blob: 9fc3ee3b04e687e1ab375349bce0d41170f38430 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Copyright (C) 2018 Apple Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "config.h"
#if ENABLE(WEB_AUTHN)
#include <WebCore/ApduCommand.h>
#include <WebCore/ApduResponse.h>
#include <wtf/Optional.h>
namespace TestWebKitAPI {
using namespace apdu;
TEST(ApduTest, TestDeserializeBasic)
{
uint8_t cla = 0xAA;
uint8_t ins = 0xAB;
uint8_t p1 = 0xAC;
uint8_t p2 = 0xAD;
Vector<uint8_t> message({ cla, ins, p1, p2 });
auto cmd = ApduCommand::createFromMessage(message);
ASSERT_TRUE(cmd);
EXPECT_EQ(0u, cmd->responseLength());
EXPECT_TRUE(cmd->data().isEmpty());
EXPECT_EQ(cla, cmd->cla());
EXPECT_EQ(ins, cmd->ins());
EXPECT_EQ(p1, cmd->p1());
EXPECT_EQ(p2, cmd->p2());
// Invalid length.
message = { cla, ins, p1 };
EXPECT_FALSE(ApduCommand::createFromMessage(message));
message.append(p2);
message.append(0);
// Set APDU command data size as maximum.
message.append(0xFF);
message.append(0xFF);
message.resize(message.size() + ApduCommand::kApduMaxDataLength);
// Set maximum response size.
message.append(0);
message.append(0);
// |message| is APDU encoded byte array with maximum data length.
EXPECT_TRUE(ApduCommand::createFromMessage(message));
message.append(0);
// |message| encoding containing data of size maximum data length + 1.
EXPECT_FALSE(ApduCommand::createFromMessage(message));
}
TEST(ApduTest, TestDeserializeComplex)
{
uint8_t cla = 0xAA;
uint8_t ins = 0xAB;
uint8_t p1 = 0xAC;
uint8_t p2 = 0xAD;
Vector<uint8_t> data(ApduCommand::kApduMaxDataLength - ApduCommand::kApduMaxHeader - 2, 0x7F);
Vector<uint8_t> message = { cla, ins, p1, p2, 0 };
message.append((data.size() >> 8) & 0xff);
message.append(data.size() & 0xff);
message.appendVector(data);
// Create a message with no response expected.
auto cmdNoResponse = ApduCommand::createFromMessage(message);
ASSERT_TRUE(cmdNoResponse);
EXPECT_EQ(0u, cmdNoResponse->responseLength());
EXPECT_EQ(data, cmdNoResponse->data());
EXPECT_EQ(cla, cmdNoResponse->cla());
EXPECT_EQ(ins, cmdNoResponse->ins());
EXPECT_EQ(p1, cmdNoResponse->p1());
EXPECT_EQ(p2, cmdNoResponse->p2());
// Add response length to message.
message.append(0xF1);
message.append(0xD0);
auto cmd = ApduCommand::createFromMessage(message);
ASSERT_TRUE(cmd);
EXPECT_EQ(data, cmd->data());
EXPECT_EQ(cla, cmd->cla());
EXPECT_EQ(ins, cmd->ins());
EXPECT_EQ(p1, cmd->p1());
EXPECT_EQ(p2, cmd->p2());
EXPECT_EQ(static_cast<size_t>(0xF1D0), cmd->responseLength());
}
TEST(ApduTest, TestDeserializeResponse)
{
ApduResponse::Status status;
Vector<uint8_t> testVector;
// Invalid length.
Vector<uint8_t> message({ 0xAA });
EXPECT_FALSE(ApduResponse::createFromMessage(message));
// Valid length and status.
status = ApduResponse::Status::SW_CONDITIONS_NOT_SATISFIED;
message = { static_cast<uint8_t>(static_cast<uint16_t>(status) >> 8), static_cast<uint8_t>(status) };
auto response = ApduResponse::createFromMessage(message);
ASSERT_TRUE(response);
EXPECT_EQ(ApduResponse::Status::SW_CONDITIONS_NOT_SATISFIED, response->status());
EXPECT_EQ(response->data(), Vector<uint8_t>());
// Valid length and status.
status = ApduResponse::Status::SW_NO_ERROR;
message = { static_cast<uint8_t>(static_cast<uint16_t>(status) >> 8), static_cast<uint8_t>(status)};
testVector = { 0x01, 0x02, 0xEF, 0xFF };
message.insertVector(0, testVector);
response = ApduResponse::createFromMessage(message);
ASSERT_TRUE(response);
EXPECT_EQ(ApduResponse::Status::SW_NO_ERROR, response->status());
EXPECT_EQ(response->data(), testVector);
}
TEST(ApduTest, TestSerializeCommand)
{
ApduCommand cmd;
cmd.setCla(0xA);
cmd.setIns(0xB);
cmd.setP1(0xC);
cmd.setP2(0xD);
// No data, no response expected.
Vector<uint8_t> expected({ 0xA, 0xB, 0xC, 0xD });
ASSERT(expected == cmd.getEncodedCommand());
auto deserializedCmd = ApduCommand::createFromMessage(expected);
ASSERT_TRUE(deserializedCmd);
EXPECT_EQ(expected, deserializedCmd->getEncodedCommand());
// No data, response expected.
cmd.setResponseLength(0xCAFE);
expected = { 0xA, 0xB, 0xC, 0xD, 0x0, 0xCA, 0xFE };
EXPECT_EQ(expected, cmd.getEncodedCommand());
deserializedCmd = ApduCommand::createFromMessage(expected);
ASSERT_TRUE(deserializedCmd);
EXPECT_EQ(expected, deserializedCmd->getEncodedCommand());
// Data exists, response expected.
Vector<uint8_t> data({ 0x1, 0x2, 0x3, 0x4 });
cmd.setData(WTFMove(data));
expected = { 0xA, 0xB, 0xC, 0xD, 0x0, 0x0, 0x4, 0x1, 0x2, 0x3, 0x4, 0xCA, 0xFE };
EXPECT_EQ(expected, cmd.getEncodedCommand());
deserializedCmd = ApduCommand::createFromMessage(expected);
ASSERT_TRUE(deserializedCmd);
EXPECT_EQ(expected, deserializedCmd->getEncodedCommand());
// Data exists, no response expected.
cmd.setResponseLength(0);
expected = { 0xA, 0xB, 0xC, 0xD, 0x0, 0x0, 0x4, 0x1, 0x2, 0x3, 0x4 };
EXPECT_EQ(expected, cmd.getEncodedCommand());
EXPECT_EQ(expected, ApduCommand::createFromMessage(expected)->getEncodedCommand());
}
TEST(ApduTest, TestSerializeEdgeCases)
{
ApduCommand cmd;
cmd.setCla(0xA);
cmd.setIns(0xB);
cmd.setP1(0xC);
cmd.setP2(0xD);
// Set response length to maximum, which should serialize to 0x0000.
cmd.setResponseLength(ApduCommand::kApduMaxResponseLength);
Vector<uint8_t> expected({ 0xA, 0xB, 0xC, 0xD, 0x0, 0x0, 0x0 });
EXPECT_EQ(expected, cmd.getEncodedCommand());
auto deserializedCmd = ApduCommand::createFromMessage(expected);
ASSERT_TRUE(deserializedCmd);
EXPECT_EQ(expected, deserializedCmd->getEncodedCommand());
// Maximum data size.
Vector<uint8_t> oversized(ApduCommand::kApduMaxDataLength);
cmd.setData(WTFMove(oversized));
deserializedCmd = ApduCommand::createFromMessage(cmd.getEncodedCommand());
ASSERT_TRUE(deserializedCmd);
EXPECT_EQ(cmd.getEncodedCommand(), deserializedCmd->getEncodedCommand());
}
} // namespace TestWebKitAPI
#endif // ENABLE(WEB_AUTHN)