Skip to content

Commit

Permalink
Update EMV TTL tests
Browse files Browse the repository at this point in the history
* Use emv_cardreader_emul object library
* Add debug output for emv_ttl_pcsc_test
  • Loading branch information
leonlynch committed Jan 23, 2024
1 parent 87c5324 commit fad8d4a
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 183 deletions.
10 changes: 6 additions & 4 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
cmake_minimum_required(VERSION 3.16)

if (BUILD_TESTING)
add_library(emv_cardreader_emul OBJECT EXCLUDE_FROM_ALL emv_cardreader_emul.c)

add_executable(emv_debug_test emv_debug_test.c)
target_link_libraries(emv_debug_test PRIVATE print_helpers emv)
add_test(emv_debug_test emv_debug_test)
Expand All @@ -25,11 +27,11 @@ if (BUILD_TESTING)
add_test(emv_atr_parse_test emv_atr_parse_test)

add_executable(emv_ttl_tpdu_test emv_ttl_tpdu_test.c)
target_link_libraries(emv_ttl_tpdu_test PRIVATE print_helpers emv)
target_link_libraries(emv_ttl_tpdu_test PRIVATE emv_cardreader_emul print_helpers emv)
add_test(emv_ttl_tpdu_test emv_ttl_tpdu_test)

add_executable(emv_ttl_pcsc_test emv_ttl_pcsc_test.c)
target_link_libraries(emv_ttl_pcsc_test PRIVATE print_helpers emv)
target_link_libraries(emv_ttl_pcsc_test PRIVATE emv_cardreader_emul print_helpers emv)
add_test(emv_ttl_pcsc_test emv_ttl_pcsc_test)

add_executable(emv_str_parse_test emv_str_parse_test.c)
Expand All @@ -44,8 +46,8 @@ if (BUILD_TESTING)
target_link_libraries(emv_cvmlist_test PRIVATE emv)
add_test(emv_cvmlist_test emv_cvmlist_test)

add_executable(emv_build_candidate_list_test emv_build_candidate_list_test.c emv_cardreader_emul.c)
target_link_libraries(emv_build_candidate_list_test PRIVATE print_helpers emv)
add_executable(emv_build_candidate_list_test emv_build_candidate_list_test.c)
target_link_libraries(emv_build_candidate_list_test PRIVATE emv_cardreader_emul print_helpers emv)
add_test(emv_build_candidate_list_test emv_build_candidate_list_test)

add_executable(isocodes_test isocodes_test.c)
Expand Down
136 changes: 50 additions & 86 deletions tests/emv_ttl_pcsc_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @file emv_ttl_pcsc_test.c
* @brief Unit tests for EMV TTL APDU cases using typical PC/SC APDUs
*
* Copyright (c) 2021 Leon Lynch
* Copyright (c) 2021, 2024 Leon Lynch
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
Expand All @@ -20,24 +20,19 @@
*/

#include "emv_ttl.h"
#include "emv_cardreader_emul.h"

#include <stdint.h>
#include <stdio.h>
#include <string.h>

// For debug output
#include "emv_debug.h"
#include "print_helpers.h"

struct apdu_t {
size_t c_apdu_len;
const uint8_t* c_apdu;
size_t r_apdu_len;
const uint8_t* r_apdu;
};

// PC/SC exchanges for case 1 normal processing
// See EMV 4.3 Book 1, Annex A1
static const struct apdu_t test_pcsc_case_1_normal[] = {
static const struct xpdu_t test_pcsc_case_1_normal[] = {
{
4, (uint8_t[]){ 0x12, 0x34, 0x56, 0x78 },
2, (uint8_t[]){ 0x90, 0x00 },
Expand All @@ -48,7 +43,7 @@ static const uint8_t test_pcsc_case_1_normal_data[] = { 0x90, 0x00 };

// PC/SC exchanges for case 1 error processing
// See EMV 4.3 Book 1, Annex A1
static const struct apdu_t test_pcsc_case_1_error[] = {
static const struct xpdu_t test_pcsc_case_1_error[] = {
{
4, (uint8_t[]){ 0x12, 0x34, 0x56, 0x78 },
2, (uint8_t[]){ 0x6A, 0x81 }, // Function not supported
Expand All @@ -59,7 +54,7 @@ static const uint8_t test_pcsc_case_1_error_data[] = { 0x6A, 0x81 };

// PC/SC exchanges for case 2 normal processing
// See EMV 4.3 Book 1, Annex A2
static const struct apdu_t test_pcsc_case_2_normal[] = {
static const struct xpdu_t test_pcsc_case_2_normal[] = {
{
5, (uint8_t[]){ 0x00, 0xB2, 0x01, 0x0C, 0x00 }, // READ RECORD 1,1
2, (uint8_t[]){ 0x6C, 0x1C },
Expand All @@ -76,7 +71,7 @@ static const uint8_t test_pcsc_case_2_normal_data[] = {

// PC/SC exchanges for case 2 error processing (early)
// See EMV 4.3 Book 1, Annex A2
static const struct apdu_t test_pcsc_case_2_error_early[] = {
static const struct xpdu_t test_pcsc_case_2_error_early[] = {
{
5, (uint8_t[]){ 0x00, 0xB2, 0x01, 0x0C, 0x00 }, // READ RECORD 1,1
2, (uint8_t[]){ 0x6A, 0x81 }, // Function not supported
Expand All @@ -87,7 +82,7 @@ static const uint8_t test_pcsc_case_2_error_early_data[] = { 0x6A, 0x81 };

// PC/SC exchanges for case 2 error processing (late)
// See EMV 4.3 Book 1, Annex A2
static const struct apdu_t test_pcsc_case_2_error_late[] = {
static const struct xpdu_t test_pcsc_case_2_error_late[] = {
{
5, (uint8_t[]){ 0x00, 0xB2, 0x01, 0x0C, 0x00 }, // READ RECORD 1,1
2, (uint8_t[]){ 0x6C, 0x1C },
Expand All @@ -102,7 +97,7 @@ static const uint8_t test_pcsc_case_2_error_late_data[] = { 0x65, 0x81 };

// PC/SC exchanges for case 3 normal processing
// See EMV 4.3 Book 1, Annex A3
static const struct apdu_t test_pcsc_case_3_normal[] = {
static const struct xpdu_t test_pcsc_case_3_normal[] = {
{
9, (uint8_t[]){ 0x00, 0x82, 0x00, 0x00, 0x04, 0xde, 0xad, 0xbe, 0xef }, // EXTERNAL AUTHENTICATE
2, (uint8_t[]){ 0x90, 0x00 },
Expand All @@ -113,7 +108,7 @@ static const uint8_t test_pcsc_case_3_normal_data[] = { 0x90, 0x00 };

// PC/SC exchanges for case 3 error processing
// See EMV 4.3 Book 1, Annex A3
static const struct apdu_t test_pcsc_case_3_error[] = {
static const struct xpdu_t test_pcsc_case_3_error[] = {
{
9, (uint8_t[]){ 0x00, 0x82, 0x00, 0x00, 0x04, 0xde, 0xad, 0xbe, 0xef }, // EXTERNAL AUTHENTICATE
2, (uint8_t[]){ 0x6A, 0x81 }, // Function not supported
Expand All @@ -123,7 +118,7 @@ static const uint8_t test_pcsc_case_3_error_data[] = { 0x6A, 0x81 };

// PC/SC exchanges for case 4 normal processing
// See EMV 4.3 Book 1, Annex A4
static const struct apdu_t test_pcsc_case_4_normal[] = {
static const struct xpdu_t test_pcsc_case_4_normal[] = {
{
20, (uint8_t[]){ 0x00, 0xA4, 0x04, 0x00, 0x0E, 0x31, 0x50, 0x41, 0x59, 0x2E, 0x53, 0x59, 0x53, 0x2E, 0x44, 0x44, 0x46, 0x30, 0x31, 0x00 }, // SELECT
2, (uint8_t[]){ 0x61, 0x26 },
Expand All @@ -140,7 +135,7 @@ static const uint8_t test_pcsc_case_4_normal_data[] = {

// PC/SC exchanges for case 4 error processing
// See EMV 4.3 Book 1, Annex A4
static const struct apdu_t test_pcsc_case_4_error_early[] = {
static const struct xpdu_t test_pcsc_case_4_error_early[] = {
{
20, (uint8_t[]){ 0x00, 0xA4, 0x04, 0x00, 0x0E, 0x31, 0x50, 0x41, 0x59, 0x2E, 0x53, 0x59, 0x53, 0x2E, 0x44, 0x44, 0x46, 0x30, 0x31, 0x00 }, // SELECT
2, (uint8_t[]){ 0x6A, 0x82 }, // File or application not found
Expand All @@ -151,7 +146,7 @@ static const uint8_t test_pcsc_case_4_error_early_data[] = { 0x6A, 0x82 };

// PC/SC exchanges for case 4 error processing (late)
// See EMV 4.3 Book 1, Annex A4
static const struct apdu_t test_pcsc_case_4_error_late[] = {
static const struct xpdu_t test_pcsc_case_4_error_late[] = {
{
20, (uint8_t[]){ 0x00, 0xA4, 0x04, 0x00, 0x0E, 0x31, 0x50, 0x41, 0x59, 0x2E, 0x53, 0x59, 0x53, 0x2E, 0x44, 0x44, 0x46, 0x30, 0x31, 0x00 }, // SELECT
2, (uint8_t[]){ 0x61, 0x26 },
Expand All @@ -166,7 +161,7 @@ static const uint8_t test_pcsc_case_4_error_late_data[] = { 0x65, 0x81 };

// PC/SC exchanges for case 2 using both '61' and '6C' procedure bytes
// See EMV 4.3 Book 1, Annex A5
static const struct apdu_t test_pcsc_case_2_normal_advanced[] = {
static const struct xpdu_t test_pcsc_case_2_normal_advanced[] = {
{
5, (uint8_t[]){ 0x00, 0xB2, 0x01, 0x0C, 0x00 }, // READ RECORD 1,1
2, (uint8_t[]){ 0x6C, 0x1C },
Expand All @@ -193,7 +188,7 @@ static const uint8_t test_pcsc_case_2_normal_advanced_data[] = {

// PC/SC exchanges for case 4 (using multiple '61' procedure bytes)
// See EMV 4.3 Book 1, Annex A6
static const struct apdu_t test_pcsc_case_4_normal_advanced[] = {
static const struct xpdu_t test_pcsc_case_4_normal_advanced[] = {
{
20, (uint8_t[]){ 0x00, 0xA4, 0x04, 0x00, 0x0E, 0x31, 0x50, 0x41, 0x59, 0x2E, 0x53, 0x59, 0x53, 0x2E, 0x44, 0x44, 0x46, 0x30, 0x31, 0x00 }, // SELECT
2, (uint8_t[]){ 0x61, 0x26 },
Expand All @@ -214,7 +209,7 @@ static const uint8_t test_pcsc_case_4_normal_advanced_data[] = {

// PC/SC exchanges for case 4 warning processing
// See EMV 4.3 Book 1, Annex A4
static const struct apdu_t test_pcsc_case_4_warning[] = {
static const struct xpdu_t test_pcsc_case_4_warning[] = {
{
20, (uint8_t[]){ 0x00, 0xA4, 0x04, 0x00, 0x0E, 0x31, 0x50, 0x41, 0x59, 0x2E, 0x53, 0x59, 0x53, 0x2E, 0x44, 0x44, 0x46, 0x30, 0x31, 0x00 }, // SELECT
2, (uint8_t[]){ 0x62, 0x86 }, // No input available from a sensor on the card
Expand All @@ -233,50 +228,12 @@ static const uint8_t test_pcsc_case_4_warning_data[] = {
0x6F, 0x24, 0x84, 0x0E, 0x31, 0x50, 0x41, 0x59, 0x2E, 0x53, 0x59, 0x53, 0x2E, 0x44, 0x44, 0x46, 0x30, 0x31, 0xA5, 0x12, 0x88, 0x01, 0x01, 0x5F, 0x2D, 0x08, 0x65, 0x6E, 0x65, 0x73, 0x66, 0x72, 0x64, 0x65, 0x9F, 0x11, 0x01, 0x01,
};

struct emv_cardreader_ctx_t {
const struct apdu_t* apdu_list;
const struct apdu_t* apdu_current;
};

static int emv_cardreader_emul(
void* ctx,
const void* tx_buf,
size_t tx_buf_len,
void* rx_buf,
size_t* rx_buf_len
) {
struct emv_cardreader_ctx_t* emul_ctx = ctx;
const struct apdu_t* apdu;

if (!emul_ctx->apdu_current) {
emul_ctx->apdu_current = emul_ctx->apdu_list;
}
if (!emul_ctx->apdu_current->c_apdu_len) {
return -101;
}
apdu = emul_ctx->apdu_current;

if (tx_buf_len != apdu->c_apdu_len) {
return -102;
}
if (memcmp(tx_buf, apdu->c_apdu, apdu->c_apdu_len) != 0) {
return -103;
}

memcpy(rx_buf, apdu->r_apdu, apdu->r_apdu_len);
*rx_buf_len = apdu->r_apdu_len;

emul_ctx->apdu_current++;

return 0;
}

int main(void)
{
int r;

struct emv_ttl_t ttl;
struct emv_cardreader_ctx_t emul_ctx;
struct emv_cardreader_emul_ctx_t emul_ctx;
ttl.cardreader.mode = EMV_CARDREADER_MODE_APDU;
ttl.cardreader.ctx = &emul_ctx;
ttl.cardreader.trx = &emv_cardreader_emul;
Expand All @@ -287,10 +244,17 @@ int main(void)
size_t data_len;
uint16_t sw1sw2;

// Enable debug output
r = emv_debug_init(EMV_DEBUG_SOURCE_ALL, EMV_DEBUG_ALL, &print_emv_debug);
if (r) {
fprintf(stderr, "emv_debug_init() failed; r=%d\n", r);
return 1;
}

// Test APDU case 1; normal processing
printf("\nTesting APDU case 1 (PC/SC mode); normal processing...\n");
emul_ctx.apdu_list = test_pcsc_case_1_normal;
emul_ctx.apdu_current = NULL;
emul_ctx.xpdu_list = test_pcsc_case_1_normal;
emul_ctx.xpdu_current = NULL;
r_apdu_len = sizeof(r_apdu);

r = emv_ttl_trx(
Expand Down Expand Up @@ -322,8 +286,8 @@ int main(void)

// Test APDU case 1; error processing
printf("\nTesting APDU case 1 (PC/SC mode); error processing...\n");
emul_ctx.apdu_list = test_pcsc_case_1_error;
emul_ctx.apdu_current = NULL;
emul_ctx.xpdu_list = test_pcsc_case_1_error;
emul_ctx.xpdu_current = NULL;
r_apdu_len = sizeof(r_apdu);

r = emv_ttl_trx(
Expand Down Expand Up @@ -355,8 +319,8 @@ int main(void)

// Test APDU case 2; normal processing
printf("\nTesting APDU case 2 (PC/SC mode); normal processing...\n");
emul_ctx.apdu_list = test_pcsc_case_2_normal;
emul_ctx.apdu_current = NULL;
emul_ctx.xpdu_list = test_pcsc_case_2_normal;
emul_ctx.xpdu_current = NULL;
data_len = sizeof(data);

r = emv_ttl_read_record(
Expand Down Expand Up @@ -388,8 +352,8 @@ int main(void)

// Test APDU case 2; error processing (early)
printf("\nTesting APDU case 2 (PC/SC mode); error processing (early)...\n");
emul_ctx.apdu_list = test_pcsc_case_2_error_early;
emul_ctx.apdu_current = NULL;
emul_ctx.xpdu_list = test_pcsc_case_2_error_early;
emul_ctx.xpdu_current = NULL;
data_len = sizeof(data);

r = emv_ttl_read_record(
Expand Down Expand Up @@ -421,8 +385,8 @@ int main(void)

// Test APDU case 2; error processing (late)
printf("\nTesting APDU case 2 (PC/SC mode); error processing (late)...\n");
emul_ctx.apdu_list = test_pcsc_case_2_error_late;
emul_ctx.apdu_current = NULL;
emul_ctx.xpdu_list = test_pcsc_case_2_error_late;
emul_ctx.xpdu_current = NULL;
data_len = sizeof(data);

r = emv_ttl_read_record(
Expand Down Expand Up @@ -454,8 +418,8 @@ int main(void)

// Test APDU case 3; normal processing
printf("\nTesting APDU case 3 (PC/SC mode); normal processing...\n");
emul_ctx.apdu_list = test_pcsc_case_3_normal;
emul_ctx.apdu_current = NULL;
emul_ctx.xpdu_list = test_pcsc_case_3_normal;
emul_ctx.xpdu_current = NULL;
r_apdu_len = sizeof(r_apdu);

r = emv_ttl_trx(
Expand Down Expand Up @@ -487,8 +451,8 @@ int main(void)

// Test APDU case 3; error processing
printf("\nTesting APDU case 3 (PC/SC mode); error processing...\n");
emul_ctx.apdu_list = test_pcsc_case_3_error;
emul_ctx.apdu_current = NULL;
emul_ctx.xpdu_list = test_pcsc_case_3_error;
emul_ctx.xpdu_current = NULL;
r_apdu_len = sizeof(r_apdu);

r = emv_ttl_trx(
Expand Down Expand Up @@ -520,8 +484,8 @@ int main(void)

// Test APDU case 4; normal processing
printf("\nTesting APDU case 4 (PC/SC mode); normal processing...\n");
emul_ctx.apdu_list = test_pcsc_case_4_normal;
emul_ctx.apdu_current = NULL;
emul_ctx.xpdu_list = test_pcsc_case_4_normal;
emul_ctx.xpdu_current = NULL;
data_len = sizeof(data);

const uint8_t PSE[] = "1PAY.SYS.DDF01";
Expand Down Expand Up @@ -554,8 +518,8 @@ int main(void)

// Test APDU case 4; error processing (early)
printf("\nTesting APDU case 4 (PC/SC mode); error processing (early)...\n");
emul_ctx.apdu_list = test_pcsc_case_4_error_early;
emul_ctx.apdu_current = NULL;
emul_ctx.xpdu_list = test_pcsc_case_4_error_early;
emul_ctx.xpdu_current = NULL;
data_len = sizeof(data);

r = emv_ttl_select_by_df_name(
Expand Down Expand Up @@ -587,8 +551,8 @@ int main(void)

// Test APDU case 4; error processing (late)
printf("\nTesting APDU case 4 (PC/SC mode); error processing (late)...\n");
emul_ctx.apdu_list = test_pcsc_case_4_error_late;
emul_ctx.apdu_current = NULL;
emul_ctx.xpdu_list = test_pcsc_case_4_error_late;
emul_ctx.xpdu_current = NULL;
data_len = sizeof(data);

r = emv_ttl_select_by_df_name(
Expand Down Expand Up @@ -620,8 +584,8 @@ int main(void)

// Test APDU case 2; normal processing (using both '61' and '6C' procedure bytes)
printf("\nTesting APDU case 2 (PC/SC mode); normal processing (using both '61' and '6C' procedure bytes)...\n");
emul_ctx.apdu_list = test_pcsc_case_2_normal_advanced;
emul_ctx.apdu_current = NULL;
emul_ctx.xpdu_list = test_pcsc_case_2_normal_advanced;
emul_ctx.xpdu_current = NULL;
data_len = sizeof(data);

r = emv_ttl_read_record(
Expand Down Expand Up @@ -653,8 +617,8 @@ int main(void)

// Test APDU case 4; normal processing (using multiple '61' procedure bytes)
printf("\nTesting APDU case 4 (PC/SC mode); normal processing (using multiple '61' procedure bytes)...\n");
emul_ctx.apdu_list = test_pcsc_case_4_normal_advanced;
emul_ctx.apdu_current = NULL;
emul_ctx.xpdu_list = test_pcsc_case_4_normal_advanced;
emul_ctx.xpdu_current = NULL;
data_len = sizeof(data);

r = emv_ttl_select_by_df_name(
Expand Down Expand Up @@ -686,8 +650,8 @@ int main(void)

// Test APDU case 4; warning processing
printf("\nTesting APDU case 4 (PC/SC mode); warning processing...\n");
emul_ctx.apdu_list = test_pcsc_case_4_warning;
emul_ctx.apdu_current = NULL;
emul_ctx.xpdu_list = test_pcsc_case_4_warning;
emul_ctx.xpdu_current = NULL;
data_len = sizeof(data);

r = emv_ttl_select_by_df_name(
Expand Down
Loading

0 comments on commit fad8d4a

Please sign in to comment.