You've already forked M5Unit-NFC
mirror of
https://github.com/m5stack/M5Unit-NFC.git
synced 2026-05-20 11:48:34 -07:00
152 lines
4.4 KiB
C++
152 lines
4.4 KiB
C++
/*
|
|
* SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
/*
|
|
UnitTest for APDU
|
|
*/
|
|
#include <gtest/gtest.h>
|
|
#include <M5Unified.h>
|
|
#include "nfc/apdu/apdu.hpp"
|
|
#include <cstring>
|
|
|
|
using namespace m5::nfc::apdu;
|
|
|
|
namespace {
|
|
|
|
constexpr uint8_t cla_sample = 0x00;
|
|
constexpr uint8_t ins_sample = 0xA4;
|
|
|
|
} // namespace
|
|
|
|
TEST(APDU, ResponseOk)
|
|
{
|
|
EXPECT_TRUE(is_response_OK(0x9000));
|
|
EXPECT_TRUE(is_response_OK(0x6100));
|
|
EXPECT_TRUE(is_response_OK(0x61FF));
|
|
EXPECT_TRUE(is_response_OK(0x9F00));
|
|
EXPECT_TRUE(is_response_OK(0x9F10));
|
|
EXPECT_FALSE(is_response_OK(0x6A82));
|
|
|
|
const uint8_t sw_ok[2] = {0x90, 0x00};
|
|
const uint8_t sw_ng[2] = {0x6A, 0x82};
|
|
EXPECT_TRUE(is_response_OK(sw_ok));
|
|
EXPECT_FALSE(is_response_OK(sw_ng));
|
|
|
|
EXPECT_TRUE(is_response_OK(0x90, 0x00));
|
|
EXPECT_FALSE(is_response_OK(0x6A, 0x82));
|
|
}
|
|
|
|
TEST(APDU, NeedSelectFileLe)
|
|
{
|
|
EXPECT_TRUE(need_select_file_le(0x00));
|
|
EXPECT_TRUE(need_select_file_le(0x08));
|
|
EXPECT_FALSE(need_select_file_le(0x0C));
|
|
EXPECT_FALSE(need_select_file_le(0x0D));
|
|
}
|
|
|
|
TEST(APDU, MakeCommandCases)
|
|
{
|
|
// Case 1
|
|
auto c1 = make_apdu_case1(cla_sample, ins_sample, 0x01, 0x02);
|
|
ASSERT_EQ(c1.size(), 4u);
|
|
EXPECT_EQ(c1[0], cla_sample);
|
|
EXPECT_EQ(c1[1], ins_sample);
|
|
EXPECT_EQ(c1[2], 0x01);
|
|
EXPECT_EQ(c1[3], 0x02);
|
|
|
|
// Case 2 short Le
|
|
auto c2 = make_apdu_case2(cla_sample, ins_sample, 0x00, 0x00, 0x10);
|
|
ASSERT_EQ(c2.size(), 5u);
|
|
EXPECT_EQ(c2[4], 0x10);
|
|
|
|
// Case 2 extended Le (257)
|
|
auto c2e = make_apdu_case2(cla_sample, ins_sample, 0x00, 0x00, 0x101);
|
|
ASSERT_EQ(c2e.size(), 7u);
|
|
EXPECT_EQ(c2e[4], 0x00);
|
|
EXPECT_EQ(c2e[5], 0x01);
|
|
EXPECT_EQ(c2e[6], 0x01);
|
|
|
|
// Case 3 short Lc
|
|
uint8_t data3[] = {0xDE, 0xAD, 0xBE, 0xEF};
|
|
auto c3 = make_apdu_case3(cla_sample, ins_sample, 0x00, 0x00, data3, sizeof(data3));
|
|
ASSERT_EQ(c3.size(), 4u + 1u + sizeof(data3));
|
|
EXPECT_EQ(c3[4], sizeof(data3));
|
|
|
|
// Case 3 extended Lc
|
|
std::vector<uint8_t> data_long(260, 0xAA);
|
|
auto c3e = make_apdu_case3(cla_sample, ins_sample, 0x00, 0x00, data_long.data(), data_long.size());
|
|
ASSERT_EQ(c3e.size(), 4u + 3u + data_long.size());
|
|
EXPECT_EQ(c3e[4], 0x00);
|
|
EXPECT_EQ(c3e[5], 0x01);
|
|
EXPECT_EQ(c3e[6], 0x04);
|
|
|
|
// Case 4 (Lc + Le)
|
|
auto c4 = make_apdu_case4(cla_sample, ins_sample, 0x00, 0x00, data3, sizeof(data3), 0x20);
|
|
ASSERT_EQ(c4.size(), 4u + 1u + sizeof(data3) + 1u);
|
|
EXPECT_EQ(c4.back(), 0x20);
|
|
|
|
// data_len > 0 with nullptr should return empty
|
|
auto bad = make_apdu_command(cla_sample, ins_sample, 0x00, 0x00, nullptr, 1, 0);
|
|
EXPECT_TRUE(bad.empty());
|
|
}
|
|
|
|
TEST(APDU, ParseTLV)
|
|
{
|
|
// Short tag/length
|
|
const uint8_t buf1[] = {0x5A, 0x03, 0x01, 0x02, 0x03};
|
|
auto tlvs1 = parse_tlv(buf1, sizeof(buf1));
|
|
ASSERT_EQ(tlvs1.size(), 1u);
|
|
EXPECT_EQ(tlvs1[0].tag, 0x5Au);
|
|
EXPECT_EQ(tlvs1[0].len, 3u);
|
|
EXPECT_EQ(tlvs1[0].tag_len, 1u);
|
|
EXPECT_TRUE(std::memcmp(tlvs1[0].v, buf1 + 2, 3) == 0);
|
|
|
|
// Extended tag + long length
|
|
const uint8_t buf2[] = {0x1F, 0x81, 0x01, 0x81, 0x03, 0xAA, 0xBB, 0xCC};
|
|
auto tlvs2 = parse_tlv(buf2, sizeof(buf2));
|
|
ASSERT_EQ(tlvs2.size(), 1u);
|
|
EXPECT_EQ(tlvs2[0].tag, 0x1F8101u);
|
|
EXPECT_EQ(tlvs2[0].len, 3u);
|
|
EXPECT_EQ(tlvs2[0].tag_len, 3u);
|
|
EXPECT_TRUE(std::memcmp(tlvs2[0].v, buf2 + 5, 3) == 0);
|
|
}
|
|
|
|
TEST(APDU, ParseTLVInvalid)
|
|
{
|
|
// Null/empty
|
|
EXPECT_TRUE(parse_tlv(nullptr, 10).empty());
|
|
EXPECT_TRUE(parse_tlv(nullptr, 0).empty());
|
|
const uint8_t empty[] = {};
|
|
EXPECT_TRUE(parse_tlv(empty, 0).empty());
|
|
|
|
// Extended tag continuation beyond limit
|
|
const uint8_t bad_tag[] = {0x1F, 0x81, 0x80, 0x00};
|
|
EXPECT_TRUE(parse_tlv(bad_tag, sizeof(bad_tag)).empty());
|
|
|
|
// Invalid length (indefinite/too large)
|
|
const uint8_t bad_len[] = {0x5A, 0x83, 0x00, 0x01, 0x02};
|
|
EXPECT_TRUE(parse_tlv(bad_len, sizeof(bad_len)).empty());
|
|
|
|
// Length exceeds buffer
|
|
const uint8_t bad_vlen[] = {0x5A, 0x04, 0x01, 0x02, 0x03};
|
|
EXPECT_TRUE(parse_tlv(bad_vlen, sizeof(bad_vlen)).empty());
|
|
}
|
|
|
|
TEST(APDU, TLVPrimitive)
|
|
{
|
|
TLV t{};
|
|
t.tag = 0x20; // constructed bit set
|
|
EXPECT_TRUE(t.is_constructed());
|
|
EXPECT_FALSE(t.is_primitive());
|
|
}
|
|
|
|
TEST(APDU, TLVPrimitiveClear)
|
|
{
|
|
TLV t{};
|
|
t.tag = 0x1F; // constructed bit clear
|
|
EXPECT_FALSE(t.is_constructed());
|
|
EXPECT_TRUE(t.is_primitive());
|
|
}
|