blob: 2408b521ce40ce5f6057f39d9fde9a118592586b [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/apdu/apdu_command.h"
#include "components/apdu/apdu_response.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace apdu {
TEST(ApduTest, TestDeserializeBasic) {
uint8_t cla = 0xAA;
uint8_t ins = 0xAB;
uint8_t p1 = 0xAC;
uint8_t p2 = 0xAD;
std::vector<uint8_t> message({cla, ins, p1, p2});
const auto cmd = ApduCommand::CreateFromMessage(message);
ASSERT_TRUE(cmd);
EXPECT_EQ(0u, cmd->response_length_);
EXPECT_TRUE(cmd->data_.empty());
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.push_back(p2);
message.push_back(0);
// Set APDU command data size as maximum.
message.push_back(0xFF);
message.push_back(0xFF);
message.resize(message.size() + ApduCommand::kApduMaxDataLength);
// Set maximum response size.
message.push_back(0);
message.push_back(0);
// |message| is APDU encoded byte array with maximum data length.
EXPECT_TRUE(ApduCommand::CreateFromMessage(message));
message.push_back(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;
std::vector<uint8_t> data(
ApduCommand::kApduMaxDataLength - ApduCommand::kApduMaxHeader - 2, 0x7F);
std::vector<uint8_t> message = {cla, ins, p1, p2, 0};
message.push_back((data.size() >> 8) & 0xff);
message.push_back(data.size() & 0xff);
message.insert(message.end(), data.begin(), data.end());
// Create a message with no response expected.
const auto cmd_no_response = ApduCommand::CreateFromMessage(message);
ASSERT_TRUE(cmd_no_response);
EXPECT_EQ(0u, cmd_no_response->response_length_);
EXPECT_THAT(data, ::testing::ContainerEq(cmd_no_response->data_));
EXPECT_EQ(cla, cmd_no_response->cla_);
EXPECT_EQ(ins, cmd_no_response->ins_);
EXPECT_EQ(p1, cmd_no_response->p1_);
EXPECT_EQ(p2, cmd_no_response->p2_);
// Add response length to message.
message.push_back(0xF1);
message.push_back(0xD0);
const auto cmd = ApduCommand::CreateFromMessage(message);
ASSERT_TRUE(cmd);
EXPECT_THAT(data, ::testing::ContainerEq(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->response_length_);
}
TEST(ApduTest, TestDeserializeResponse) {
ApduResponse::Status status;
std::vector<uint8_t> test_vector;
// Invalid length.
std::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->response_status_);
EXPECT_THAT(response->data_, ::testing::ContainerEq(std::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)};
test_vector = {0x01, 0x02, 0xEF, 0xFF};
message.insert(message.begin(), test_vector.begin(), test_vector.end());
response = ApduResponse::CreateFromMessage(message);
ASSERT_TRUE(response);
EXPECT_EQ(ApduResponse::Status::SW_NO_ERROR, response->response_status_);
EXPECT_THAT(response->data_, ::testing::ContainerEq(test_vector));
}
TEST(ApduTest, TestSerializeCommand) {
ApduCommand cmd;
cmd.set_cla(0xA);
cmd.set_ins(0xB);
cmd.set_p1(0xC);
cmd.set_p2(0xD);
// No data, no response expected.
std::vector<uint8_t> expected({0xA, 0xB, 0xC, 0xD});
ASSERT_THAT(expected, ::testing::ContainerEq(cmd.GetEncodedCommand()));
auto deserialized_cmd = ApduCommand::CreateFromMessage(expected);
ASSERT_TRUE(deserialized_cmd);
EXPECT_THAT(expected,
::testing::ContainerEq(deserialized_cmd->GetEncodedCommand()));
// No data, response expected.
cmd.set_response_length(0xCAFE);
expected = {0xA, 0xB, 0xC, 0xD, 0x0, 0xCA, 0xFE};
EXPECT_THAT(expected, ::testing::ContainerEq(cmd.GetEncodedCommand()));
deserialized_cmd = ApduCommand::CreateFromMessage(expected);
ASSERT_TRUE(deserialized_cmd);
EXPECT_THAT(expected,
::testing::ContainerEq(deserialized_cmd->GetEncodedCommand()));
// Data exists, response expected.
std::vector<uint8_t> data({0x1, 0x2, 0x3, 0x4});
cmd.set_data(data);
expected = {0xA, 0xB, 0xC, 0xD, 0x0, 0x0, 0x4,
0x1, 0x2, 0x3, 0x4, 0xCA, 0xFE};
EXPECT_THAT(expected, ::testing::ContainerEq(cmd.GetEncodedCommand()));
deserialized_cmd = ApduCommand::CreateFromMessage(expected);
ASSERT_TRUE(deserialized_cmd);
EXPECT_THAT(expected,
::testing::ContainerEq(deserialized_cmd->GetEncodedCommand()));
// Data exists, no response expected.
cmd.set_response_length(0);
expected = {0xA, 0xB, 0xC, 0xD, 0x0, 0x0, 0x4, 0x1, 0x2, 0x3, 0x4};
EXPECT_THAT(expected, ::testing::ContainerEq(cmd.GetEncodedCommand()));
EXPECT_THAT(
expected,
::testing::ContainerEq(
ApduCommand::CreateFromMessage(expected)->GetEncodedCommand()));
}
TEST(ApduTest, TestSerializeEdgeCases) {
ApduCommand cmd;
cmd.set_cla(0xA);
cmd.set_ins(0xB);
cmd.set_p1(0xC);
cmd.set_p2(0xD);
// Set response length to maximum, which should serialize to 0x0000.
cmd.set_response_length(ApduCommand::kApduMaxResponseLength);
std::vector<uint8_t> expected({0xA, 0xB, 0xC, 0xD, 0x0, 0x0, 0x0});
EXPECT_THAT(expected, ::testing::ContainerEq(cmd.GetEncodedCommand()));
auto deserialized_cmd = ApduCommand::CreateFromMessage(expected);
ASSERT_TRUE(deserialized_cmd);
EXPECT_THAT(expected,
::testing::ContainerEq(deserialized_cmd->GetEncodedCommand()));
// Maximum data size.
std::vector<uint8_t> oversized(ApduCommand::kApduMaxDataLength);
cmd.set_data(oversized);
deserialized_cmd = ApduCommand::CreateFromMessage(cmd.GetEncodedCommand());
ASSERT_TRUE(deserialized_cmd);
EXPECT_THAT(cmd.GetEncodedCommand(),
::testing::ContainerEq(deserialized_cmd->GetEncodedCommand()));
}
} // namespace apdu