diff --git a/src/emv.c b/src/emv.c index 2437cea..26784df 100644 --- a/src/emv.c +++ b/src/emv.c @@ -258,7 +258,7 @@ int emv_atr_parse(const void* atr, size_t atr_len) // For T=1, reject 2^CWI < (N + 1) // - if N==0xFF, consider N to be -1 // - if N==0x00, consider CWI to be 1 - // See EMV Level 1 Contact Interface v1.0, 8.3.3.1 + // See EMV Level 1 Contact Interface v1.0, 8.3.3.10 int N = (atr_info.global.N != 0xFF) ? atr_info.global.N : -1; unsigned int CWI = atr_info.global.N ? atr_info.protocol_T1.CWI : 1; unsigned int pow_2_CWI = 1 << CWI; diff --git a/src/emv_ttl.c b/src/emv_ttl.c index 6fabd38..cdefebb 100644 --- a/src/emv_ttl.c +++ b/src/emv_ttl.c @@ -64,8 +64,8 @@ int emv_ttl_trx( // Determine the APDU case // See ISO 7816-3:2006, 12.1.3, table 13 - // See EMV 4.3 Book 1, 9.3.1.1 - // See EMV 4.3 Book 1, Annex A + // See EMV Contact Interface Specification v1.0, 9.3.1.1 + // See EMV Contact Interface Specification v1.0, Annex A // APDU cases: // Case 1: CLA INS P1 P2 @@ -169,7 +169,7 @@ int emv_ttl_trx( // For APDU case 1, the R-APDU should only be SW1-SW2; no further action // See ISO 7816-3:2006, 12.2.1, table 14 - // See EMV 4.3 Book 1, 9.3.1.1.1 + // See EMV Contact Interface Specification v1.0, 9.3.1.1.1 if (apdu_case == ISO7816_APDU_CASE_1) { if (rx_len != 2) { // Unexpected response length for APDU case 1 @@ -191,7 +191,7 @@ int emv_ttl_trx( // Process response containing single procedure byte // See ISO 7816-3:2006, 10.3.3 - // See EMV 4.3 Book 1, 9.2.2.3.1, table 25 + // See EMV Contact Interface Specification v1.0, 9.2.2.3.1, table 25 if (rx_len == 1) { uint8_t procedure_byte = *((uint8_t*)rx_buf); @@ -205,7 +205,6 @@ int emv_ttl_trx( } // ACK: Send remaining data bytes - // See EMV 4.3 Book 1, Annex A if (procedure_byte == INS) { if (!c_tpdu_data) { // Unexpected procedure byte if no data available @@ -268,10 +267,11 @@ int emv_ttl_trx( // Process status bytes // See ISO 7816-3:2006, 12.2.1, table 14 // See ISO 7816-4:2005, 5.1.3, table 6 - // See EMV 4.3 Book 1, 9.2.2.3.1, table 25 - // See EMV 4.3 Book 1, 9.2.2.3.2 - // See EMV 4.3 Book 1, 9.3.1.2 - // See EMV 4.3 Book 1, Annex A for examples + // See EMV Contact Interface Specification v1.0, 9.2.2.3.1, table 25 + // See EMV Contact Interface Specification v1.0, 9.2.2.3.2 + // See EMV Contact Interface Specification v1.0, 9.3.1.1 + // See EMV Contact Interface Specification v1.0, 9.3.1.2 + // See EMV Contact Interface Specification v1.0, Annex A for examples switch (SW1) { case 0x61: // Normal processing: SW2 encodes the number of available bytes @@ -303,16 +303,19 @@ int emv_ttl_trx( default: // Terminal Application Layer (TAL) should receive the SW1-SW2 - // value of the initial command and not the subsequent - // GET RESPONSE command. - // See EMV 4.3 Book 1, Annex A7 "Case 4 Command with Warning Condition" + // value for all remaining cases, including normal completion + // and completion with a warning. Note that warning processing + // may occur before the response data is received. + // See EMV Contact Interface Specification v1.0, 9.3.1.1 if (!*sw1sw2) { // Output status bytes SW1-SW2 in host endianness *sw1sw2 = ((uint16_t)SW1 << 8) | SW2; - // For APDU case 4, warning processing is followed by GET RESPONSE - // See EMV 4.3 Book 1, Annex A7 "Case 4 Command with Warning Condition" + // For APDU case 4, if warning processing occurs without + // response data, it is followed by GET RESPONSE + // See EMV Contact Interface Specification v1.0, Annex A7 "Case 4 Command with Warning Condition" if (apdu_case == ISO7816_APDU_CASE_4S && + rx_len == 2 && iso7816_sw1sw2_is_warning(SW1, SW2) ) { tx_get_response = true; @@ -397,7 +400,7 @@ int emv_ttl_trx( // Build GET RESPONSE for next transmission // See ISO 7816-4:2005, 7.6.1 - // See EMV 4.3 Book 1, 9.3.1.3 + // See EMV Contact Interface Specification v1.0, 9.3.1.3 c_tpdu_header[0] = 0x00; // CLA c_tpdu_header[1] = 0xC0; // INS: GET RESPONSE c_tpdu_header[2] = 0x00; // P1 @@ -412,7 +415,7 @@ int emv_ttl_trx( if (tx_update_le) { // Update Le for next transmission - // See EMV 4.3 Book 1, 9.2.2.3.1, table 25 + // See EMV Contact Interface Specification v1.0, 9.2.2.3.1, table 25 memcpy(c_tpdu_header, tx_buf, 4); c_tpdu_header[4] = SW2; // P3 = Le tx_buf = c_tpdu_header; @@ -422,24 +425,15 @@ int emv_ttl_trx( continue; } - // If SW1-SW2 indicates success or error, finalise the R-APDU - // Only warning processing may proceed - if (iso7816_sw1sw2_is_success(SW1, SW2) || - iso7816_sw1sw2_is_error(SW1, SW2) - ) { - // Finalise R-APDU using initial SW1-SW2 - r_apdu_ptr[0] = *sw1sw2 >> 8; - r_apdu_ptr[1] = *sw1sw2 & 0xFF; - r_apdu_ptr += 2; - *r_apdu_len = (void*)r_apdu_ptr - r_apdu; - - // Let Terminal Application Layer (TAL) process the response - emv_debug_rapdu(r_apdu, *r_apdu_len); - return 0; - } + // Finalise R-APDU using current SW1-SW2 + r_apdu_ptr[0] = *sw1sw2 >> 8; + r_apdu_ptr[1] = *sw1sw2 & 0xFF; + r_apdu_ptr += 2; + *r_apdu_len = (void*)r_apdu_ptr - r_apdu; - // This should never happen - return -100; + // Let Terminal Application Layer (TAL) process the response + emv_debug_rapdu(r_apdu, *r_apdu_len); + return 0; } while (true); } @@ -466,19 +460,19 @@ int emv_ttl_select_by_df_name( } // For SELECT, ensure that Lc is from 0x05 to 0x10 - // See EMV 4.3 Book 1, 11.3.2, table 40 + // See EMV 4.4 Book 1, 11.3.2, table 5 if (df_name_len < 0x05 || df_name_len > 0x10) { return -3; } // Build SELECT command - c_apdu.CLA = 0x00; // See EMV 4.3 Book 3, 6.3.2 - c_apdu.INS = 0xA4; // See EMV 4.3 Book 1, 11.3.2, table 40 - c_apdu.P1 = 0x04; // See EMV 4.3 Book 1, 11.3.2, table 41 - c_apdu.P2 = 0x00; // See EMV 4.3 Book 1, 11.3.2, table 42 + c_apdu.CLA = 0x00; // See EMV 4.4 Book 3, 6.3.2 + c_apdu.INS = 0xA4; // See EMV 4.4 Book 1, 11.3.2, table 5 + c_apdu.P1 = 0x04; // See EMV 4.4 Book 1, 11.3.2, table 6 + c_apdu.P2 = 0x00; // See EMV 4.4 Book 1, 11.3.2, table 7 c_apdu.Lc = df_name_len; memcpy(c_apdu.data, df_name, c_apdu.Lc); - c_apdu.data[c_apdu.Lc] = 0x00; // See EMV 4.3 Book 1, 11.3.2, table 40 + c_apdu.data[c_apdu.Lc] = 0x00; // See EMV 4.4 Book 1, 11.3.2, table 5 r = emv_ttl_trx( ctx, @@ -527,19 +521,19 @@ int emv_ttl_select_by_df_name_next( } // For SELECT, ensure that Lc is from 0x05 to 0x10 - // See EMV 4.3 Book 1, 11.3.2, table 40 + // See EMV 4.4 Book 1, 11.3.2, table 5 if (df_name_len < 0x05 || df_name_len > 0x10) { return -3; } // Build SELECT command - c_apdu.CLA = 0x00; // See EMV 4.3 Book 3, 6.3.2 - c_apdu.INS = 0xA4; // See EMV 4.3 Book 1, 11.3.2, table 40 - c_apdu.P1 = 0x04; // See EMV 4.3 Book 1, 11.3.2, table 41 - c_apdu.P2 = 0x02; // See EMV 4.3 Book 1, 11.3.2, table 42 + c_apdu.CLA = 0x00; // See EMV 4.4 Book 3, 6.3.2 + c_apdu.INS = 0xA4; // See EMV 4.4 Book 1, 11.3.2, table 5 + c_apdu.P1 = 0x04; // See EMV 4.4 Book 1, 11.3.2, table 6 + c_apdu.P2 = 0x02; // See EMV 4.4 Book 1, 11.3.2, table 7 c_apdu.Lc = df_name_len; memcpy(c_apdu.data, df_name, c_apdu.Lc); - c_apdu.data[c_apdu.Lc] = 0x00; // See EMV 4.3 Book 1, 11.3.2, table 40 + c_apdu.data[c_apdu.Lc] = 0x00; // See EMV 4.4 Book 1, 11.3.2, table 5 r = emv_ttl_trx( ctx, diff --git a/src/emv_ttl.h b/src/emv_ttl.h index 3bd4fa7..f0ec90b 100644 --- a/src/emv_ttl.h +++ b/src/emv_ttl.h @@ -96,7 +96,7 @@ int emv_ttl_trx( /** * SELECT (0xA4) the first or only application by Dedicated File (DF) name * and provide File Control Information (FCI) template. - * @remark See EMV 4.3 Book 1, 11.3 + * @remark See EMV 4.4 Book 1, 11.3 * @remark See ISO 7816-4:2005, 7.1.1 * * @param ctx EMV Terminal Transport Layer context @@ -119,7 +119,7 @@ int emv_ttl_select_by_df_name( /** * SELECT (0xA4) the next application by Dedicated File (DF) name and * provide File Control Information (FCI) template. - * @remark See EMV 4.3 Book 1, 11.3 + * @remark See EMV 4.4 Book 1, 11.3 * @remark See ISO 7816-4:2005, 7.1.1 * * @param ctx EMV Terminal Transport Layer context diff --git a/src/iso7816.c b/src/iso7816.c index c07384a..e2c2fd0 100644 --- a/src/iso7816.c +++ b/src/iso7816.c @@ -678,7 +678,7 @@ static void iso7816_compute_wt(struct iso7816_atr_info_t* atr_info) // WT = WI x 960 x D ETU // Which is the same conclusion that EMV comes to below... - // From EMV Book 1, version 4.3 (Nov 2011), section 9.2.2.1: + // From EMV Contact Interface Specification v1.0, 9.2.2.1: // WWT = 960 x D x WI ETUs (D and WI are returned in TA1 and TC2, respectively) // And finally, after all that thinking... @@ -701,7 +701,7 @@ static void iso7816_compute_wt(struct iso7816_atr_info_t* atr_info) // BWT = 11etu + (2^BWI x 960 x 372 x D / F) // Which is the same conclusion that EMV comes to below... - // From EMV Book 1, version 4.3 (Nov 2011), section 9.2.4.2.2: + // From EMV Contact Interface Specification v1.0, 9.2.4.2.2: // BWT = (((2^BWI x 960 x 372 x D / F) + 11)etu; where D is Di and F is Fi // And finally, after all that thinking... diff --git a/src/pcsc.h b/src/pcsc.h index 28571f8..bf5cbfb 100644 --- a/src/pcsc.h +++ b/src/pcsc.h @@ -133,7 +133,7 @@ int pcsc_reader_get_atr(pcsc_reader_ctx_t reader_ctx, uint8_t* atr, size_t* atr_ * @param tx_buf Transmit buffer * @param tx_buf_len Length of transmit buffer in bytes * @param rx_buf Receive buffer - * @param rx_buf_len Length of R-APDU buffer in bytes + * @param rx_buf_len Length of receive buffer in bytes * @return Zero for success. Less than zero for error. */ int pcsc_reader_trx( diff --git a/tests/emv_ttl_pcsc_test.c b/tests/emv_ttl_pcsc_test.c index aa281c6..26232eb 100644 --- a/tests/emv_ttl_pcsc_test.c +++ b/tests/emv_ttl_pcsc_test.c @@ -31,7 +31,7 @@ #include "print_helpers.h" // PC/SC exchanges for case 1 normal processing -// See EMV 4.3 Book 1, Annex A1 +// See EMV Contact Interface Specification v1.0, Annex A1 static const struct xpdu_t test_pcsc_case_1_normal[] = { { 4, (uint8_t[]){ 0x12, 0x34, 0x56, 0x78 }, @@ -42,7 +42,7 @@ static const struct xpdu_t test_pcsc_case_1_normal[] = { 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 +// See EMV Contact Interface Specification v1.0, Annex A1 static const struct xpdu_t test_pcsc_case_1_error[] = { { 4, (uint8_t[]){ 0x12, 0x34, 0x56, 0x78 }, @@ -53,7 +53,7 @@ static const struct xpdu_t test_pcsc_case_1_error[] = { 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 +// See EMV Contact Interface Specification v1.0, Annex A2 static const struct xpdu_t test_pcsc_case_2_normal[] = { { 5, (uint8_t[]){ 0x00, 0xB2, 0x01, 0x0C, 0x00 }, // READ RECORD 1,1 @@ -70,7 +70,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 +// See EMV Contact Interface Specification v1.0, Annex A2 static const struct xpdu_t test_pcsc_case_2_error_early[] = { { 5, (uint8_t[]){ 0x00, 0xB2, 0x01, 0x0C, 0x00 }, // READ RECORD 1,1 @@ -81,7 +81,7 @@ static const struct xpdu_t test_pcsc_case_2_error_early[] = { 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 +// See EMV Contact Interface Specification v1.0, Annex A2 static const struct xpdu_t test_pcsc_case_2_error_late[] = { { 5, (uint8_t[]){ 0x00, 0xB2, 0x01, 0x0C, 0x00 }, // READ RECORD 1,1 @@ -96,7 +96,7 @@ static const struct xpdu_t test_pcsc_case_2_error_late[] = { 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 +// See EMV Contact Interface Specification v1.0, Annex A3 static const struct xpdu_t test_pcsc_case_3_normal[] = { { 9, (uint8_t[]){ 0x00, 0x82, 0x00, 0x00, 0x04, 0xde, 0xad, 0xbe, 0xef }, // EXTERNAL AUTHENTICATE @@ -107,7 +107,7 @@ static const struct xpdu_t test_pcsc_case_3_normal[] = { 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 +// See EMV Contact Interface Specification v1.0, Annex A3 static const struct xpdu_t test_pcsc_case_3_error[] = { { 9, (uint8_t[]){ 0x00, 0x82, 0x00, 0x00, 0x04, 0xde, 0xad, 0xbe, 0xef }, // EXTERNAL AUTHENTICATE @@ -117,7 +117,7 @@ static const struct xpdu_t test_pcsc_case_3_error[] = { 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 +// See EMV Contact Interface Specification v1.0, Annex A4 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 @@ -134,7 +134,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 +// See EMV Contact Interface Specification v1.0, Annex A4 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 @@ -145,7 +145,7 @@ static const struct xpdu_t test_pcsc_case_4_error_early[] = { 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 +// See EMV Contact Interface Specification v1.0, Annex A4 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 @@ -160,7 +160,7 @@ static const struct xpdu_t test_pcsc_case_4_error_late[] = { 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 +// See EMV Contact Interface Specification v1.0, Annex A5 static const struct xpdu_t test_pcsc_case_2_normal_advanced[] = { { 5, (uint8_t[]){ 0x00, 0xB2, 0x01, 0x0C, 0x00 }, // READ RECORD 1,1 @@ -187,7 +187,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 +// See EMV Contact Interface Specification v1.0, Annex A6 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 @@ -207,9 +207,9 @@ static const uint8_t test_pcsc_case_4_normal_advanced_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, }; -// PC/SC exchanges for case 4 warning processing -// See EMV 4.3 Book 1, Annex A4 -static const struct xpdu_t test_pcsc_case_4_warning[] = { +// PC/SC exchanges for case 4 warning processing ('62' then '6C') +// See EMV Contact Interface Specification v1.0, Annex A7, first example +static const struct xpdu_t test_pcsc_case_4_warning1[] = { { 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 @@ -224,7 +224,24 @@ static const struct xpdu_t test_pcsc_case_4_warning[] = { }, { 0 } }; -static const uint8_t test_pcsc_case_4_warning_data[] = { +static const uint8_t test_pcsc_case_4_warning1_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, +}; + +// PC/SC exchanges for case 4 warning processing ('61' then '62') +// See EMV Contact Interface Specification v1.0, Annex A7, second example +static const struct xpdu_t test_pcsc_case_4_warning2[] = { + { + 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 }, + }, + { + 5, (uint8_t[]){ 0x00, 0xC0, 0x00, 0x00, 0x26 }, + 0x28, (uint8_t[]){ 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, 0x62, 0x86 }, // No input available from a sensor on the card + }, + { 0 } +}; +static const uint8_t test_pcsc_case_4_warning2_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, }; @@ -648,9 +665,42 @@ int main(void) } printf("Success\n"); - // Test APDU case 4; warning processing - printf("\nTesting APDU case 4 (PC/SC mode); warning processing...\n"); - emul_ctx.xpdu_list = test_pcsc_case_4_warning; + // Test APDU case 4; warning processing ('62' then '6C') + printf("\nTesting APDU case 4 (PC/SC mode); warning processing ('62' then '6C')...\n"); + emul_ctx.xpdu_list = test_pcsc_case_4_warning1; + emul_ctx.xpdu_current = NULL; + data_len = sizeof(data); + + r = emv_ttl_select_by_df_name( + &ttl, + PSE, + sizeof(PSE) - 1, + data, + &data_len, + &sw1sw2 + ); + if (r) { + fprintf(stderr, "emv_ttl_trx() failed; r=%d\n", r); + return 1; + } + if (data_len != sizeof(test_pcsc_case_4_warning1_data)) { + fprintf(stderr, "emv_ttl_trx() failed; incorrect response data length\n"); + return 1; + } + if (memcmp(data, test_pcsc_case_4_warning1_data, data_len) != 0) { + fprintf(stderr, "emv_ttl_trx() failed; incorrect response data\n"); + print_buf("data", data, data_len); + return 1; + } + if (sw1sw2 != 0x6286) { + fprintf(stderr, "Unexpected SW1-SW2 %04X\n", sw1sw2); + return 2; + } + printf("Success\n"); + + // Test APDU case 4; warning processing ('61' then '62') + printf("\nTesting APDU case 4 (PC/SC mode); warning processing ('61' then '62')...\n"); + emul_ctx.xpdu_list = test_pcsc_case_4_warning2; emul_ctx.xpdu_current = NULL; data_len = sizeof(data); @@ -666,11 +716,11 @@ int main(void) fprintf(stderr, "emv_ttl_trx() failed; r=%d\n", r); return 1; } - if (data_len != sizeof(test_pcsc_case_4_warning_data)) { + if (data_len != sizeof(test_pcsc_case_4_warning2_data)) { fprintf(stderr, "emv_ttl_trx() failed; incorrect response data length\n"); return 1; } - if (memcmp(data, test_pcsc_case_4_warning_data, data_len) != 0) { + if (memcmp(data, test_pcsc_case_4_warning2_data, data_len) != 0) { fprintf(stderr, "emv_ttl_trx() failed; incorrect response data\n"); print_buf("data", data, data_len); return 1; diff --git a/tests/emv_ttl_tpdu_test.c b/tests/emv_ttl_tpdu_test.c index f07d8e7..c5e5c87 100644 --- a/tests/emv_ttl_tpdu_test.c +++ b/tests/emv_ttl_tpdu_test.c @@ -31,7 +31,7 @@ #include "print_helpers.h" // TPDU exchanges for case 1 normal processing -// See EMV 4.3 Book 1, Annex A1 +// See EMV Contact Interface Specification v1.0, Annex A1 static const struct xpdu_t test_tpdu_case_1_normal[] = { { 5, (uint8_t[]){ 0x12, 0x34, 0x56, 0x78, 0x00 }, @@ -42,7 +42,7 @@ static const struct xpdu_t test_tpdu_case_1_normal[] = { static const uint8_t test_tpdu_case_1_normal_data[] = { 0x90, 0x00 }; // TPDU exchanges for case 1 error processing -// See EMV 4.3 Book 1, Annex A1 +// See EMV Contact Interface Specification v1.0, Annex A1 static const struct xpdu_t test_tpdu_case_1_error[] = { { 5, (uint8_t[]){ 0x12, 0x34, 0x56, 0x78, 0x00 }, @@ -53,7 +53,7 @@ static const struct xpdu_t test_tpdu_case_1_error[] = { static const uint8_t test_tpdu_case_1_error_data[] = { 0x6A, 0x81 }; // TPDU exchanges for case 2 normal processing -// See EMV 4.3 Book 1, Annex A2 +// See EMV Contact Interface Specification v1.0, Annex A2 static const struct xpdu_t test_tpdu_case_2_normal[] = { { 5, (uint8_t[]){ 0x00, 0xB2, 0x01, 0x0C, 0x00 }, // READ RECORD 1,1 @@ -70,7 +70,7 @@ static const uint8_t test_tpdu_case_2_normal_data[] = { }; // TPDU exchanges for case 2 error processing (early) -// See EMV 4.3 Book 1, Annex A2 +// See EMV Contact Interface Specification v1.0, Annex A2 static const struct xpdu_t test_tpdu_case_2_error_early[] = { { 5, (uint8_t[]){ 0x00, 0xB2, 0x01, 0x0C, 0x00 }, // READ RECORD 1,1 @@ -81,7 +81,7 @@ static const struct xpdu_t test_tpdu_case_2_error_early[] = { static const uint8_t test_tpdu_case_2_error_early_data[] = { 0x6A, 0x81 }; // TPDU exchanges for case 2 error processing (late) -// See EMV 4.3 Book 1, Annex A2 +// See EMV Contact Interface Specification v1.0, Annex A2 static const struct xpdu_t test_tpdu_case_2_error_late[] = { { 5, (uint8_t[]){ 0x00, 0xB2, 0x01, 0x0C, 0x00 }, // READ RECORD 1,1 @@ -96,7 +96,7 @@ static const struct xpdu_t test_tpdu_case_2_error_late[] = { static const uint8_t test_tpdu_case_2_error_late_data[] = { 0x65, 0x81 }; // TPDU exchanges for case 3 normal processing -// See EMV 4.3 Book 1, Annex A3 +// See EMV Contact Interface Specification v1.0, Annex A3 static const struct xpdu_t test_tpdu_case_3_normal[] = { { 5, (uint8_t[]){ 0x00, 0x82, 0x00, 0x00, 0x04 }, // EXTERNAL AUTHENTICATE @@ -111,7 +111,7 @@ static const struct xpdu_t test_tpdu_case_3_normal[] = { static const uint8_t test_tpdu_case_3_normal_data[] = { 0x90, 0x00 }; // TPDU exchanges for case 3 error processing (early) -// See EMV 4.3 Book 1, Annex A3 +// See EMV Contact Interface Specification v1.0, Annex A3 static const struct xpdu_t test_tpdu_case_3_error_early[] = { { 5, (uint8_t[]){ 0x00, 0x82, 0x00, 0x00, 0x04 }, // EXTERNAL AUTHENTICATE @@ -121,7 +121,7 @@ static const struct xpdu_t test_tpdu_case_3_error_early[] = { static const uint8_t test_tpdu_case_3_error_early_data[] = { 0x6A, 0x81 }; // TPDU exchanges for case 3 error processing (late) -// See EMV 4.3 Book 1, Annex A3 +// See EMV Contact Interface Specification v1.0, Annex A3 static const struct xpdu_t test_tpdu_case_3_error_late[] = { { 5, (uint8_t[]){ 0x00, 0x82, 0x00, 0x00, 0x04 }, // EXTERNAL AUTHENTICATE @@ -136,7 +136,7 @@ static const struct xpdu_t test_tpdu_case_3_error_late[] = { static const uint8_t test_tpdu_case_3_error_late_data[] = { 0x65, 0x81 }; // TPDU exchanges for case 4 normal processing -// See EMV 4.3 Book 1, Annex A4 +// See EMV Contact Interface Specification v1.0, Annex A4 static const struct xpdu_t test_tpdu_case_4_normal[] = { { 5, (uint8_t[]){ 0x00, 0xA4, 0x04, 0x00, 0x0E }, // SELECT @@ -157,7 +157,7 @@ static const uint8_t test_tpdu_case_4_normal_data[] = { }; // TPDU exchanges for case 4 error processing (early) -// See EMV 4.3 Book 1, Annex A4 +// See EMV Contact Interface Specification v1.0, Annex A4 static const struct xpdu_t test_tpdu_case_4_error_early[] = { { 5, (uint8_t[]){ 0x00, 0xA4, 0x04, 0x00, 0x0E }, // SELECT @@ -168,7 +168,7 @@ static const struct xpdu_t test_tpdu_case_4_error_early[] = { static const uint8_t test_tpdu_case_4_error_early_data[] = { 0x6A, 0x81 }; // TPDU exchanges for case 4 error processing (early 2nd exchange) -// See EMV 4.3 Book 1, Annex A4 +// See EMV Contact Interface Specification v1.0, Annex A4 static const struct xpdu_t test_tpdu_case_4_error_early2[] = { { 5, (uint8_t[]){ 0x00, 0xA4, 0x04, 0x00, 0x0E }, // SELECT @@ -183,7 +183,7 @@ static const struct xpdu_t test_tpdu_case_4_error_early2[] = { static const uint8_t test_tpdu_case_4_error_early2_data[] = { 0x6A, 0x82 }; // TPDU exchanges for case 4 error processing (late) -// See EMV 4.3 Book 1, Annex A4 +// See EMV Contact Interface Specification v1.0, Annex A4 static const struct xpdu_t test_tpdu_case_4_error_late[] = { { 5, (uint8_t[]){ 0x00, 0xA4, 0x04, 0x00, 0x0E }, // SELECT @@ -202,7 +202,7 @@ static const struct xpdu_t test_tpdu_case_4_error_late[] = { static const uint8_t test_tpdu_case_4_error_late_data[] = { 0x65, 0x81 }; // TPDU exchanges for case 2 using both '61' and '6C' procedure bytes -// See EMV 4.3 Book 1, Annex A5 +// See EMV Contact Interface Specification v1.0, Annex A5 static const struct xpdu_t test_tpdu_case_2_normal_advanced[] = { { 5, (uint8_t[]){ 0x00, 0xB2, 0x01, 0x0C, 0x00 }, // READ RECORD 1,1 @@ -229,7 +229,7 @@ static const uint8_t test_tpdu_case_2_normal_advanced_data[] = { }; // TPDU exchanges for case 4 (using multiple '61' procedure bytes) -// See EMV 4.3 Book 1, Annex A6 +// See EMV Contact Interface Specification v1.0, Annex A6 static const struct xpdu_t test_tpdu_case_4_normal_advanced[] = { { 5, (uint8_t[]){ 0x00, 0xA4, 0x04, 0x00, 0x0E }, // SELECT @@ -253,9 +253,9 @@ static const uint8_t test_tpdu_case_4_normal_advanced_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, }; -// TPDU exchanges for case 4 warning processing -// See EMV 4.3 Book 1, Annex A4 -static const struct xpdu_t test_tpdu_case_4_warning[] = { +// TPDU exchanges for case 4 warning processing ('62' then '6C') +// See EMV Contact Interface Specification v1.0, Annex A7, first example +static const struct xpdu_t test_tpdu_case_4_warning1[] = { { 5, (uint8_t[]){ 0x00, 0xA4, 0x04, 0x00, 0x0E }, // SELECT 1, (uint8_t[]){ 0xA4 }, @@ -274,7 +274,28 @@ static const struct xpdu_t test_tpdu_case_4_warning[] = { }, { 0 } }; -static const uint8_t test_tpdu_case_4_warning_data[] = { +static const uint8_t test_tpdu_case_4_warning1_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, +}; + +// TPDU exchanges for case 4 warning processing ('61' then '62') +// See EMV Contact Interface Specification v1.0, Annex A7, second example +static const struct xpdu_t test_tpdu_case_4_warning2[] = { + { + 5, (uint8_t[]){ 0x00, 0xA4, 0x04, 0x00, 0x0E }, // SELECT + 1, (uint8_t[]){ 0xA4 }, + }, + { + 14, (uint8_t[]){ 0x31, 0x50, 0x41, 0x59, 0x2E, 0x53, 0x59, 0x53, 0x2E, 0x44, 0x44, 0x46, 0x30, 0x31 }, + 2, (uint8_t[]){ 0x61, 0x26 }, + }, + { + 5, (uint8_t[]){ 0x00, 0xC0, 0x00, 0x00, 0x26 }, + 0x29, (uint8_t[]){ 0xC0, 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, 0x62, 0x86 }, // No input available from a sensor on the card + }, + { 0 } +}; +static const uint8_t test_tpdu_case_4_warning2_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, }; @@ -764,9 +785,42 @@ int main(void) } printf("Success\n"); - // Test APDU case 4; warning processing - printf("\nTesting APDU case 4 (TPDU mode); warning processing...\n"); - emul_ctx.xpdu_list = test_tpdu_case_4_warning; + // Test APDU case 4; warning processing ('62' then '6C') + printf("\nTesting APDU case 4 (TPDU mode); warning processing ('62' then '6C')...\n"); + emul_ctx.xpdu_list = test_tpdu_case_4_warning1; + emul_ctx.xpdu_current = NULL; + data_len = sizeof(data); + + r = emv_ttl_select_by_df_name( + &ttl, + PSE, + sizeof(PSE) - 1, + data, + &data_len, + &sw1sw2 + ); + if (r) { + fprintf(stderr, "emv_ttl_trx() failed; r=%d\n", r); + return 1; + } + if (data_len != sizeof(test_tpdu_case_4_warning1_data)) { + fprintf(stderr, "emv_ttl_trx() failed; incorrect response data length\n"); + return 1; + } + if (memcmp(data, test_tpdu_case_4_warning1_data, data_len) != 0) { + fprintf(stderr, "emv_ttl_trx() failed; incorrect response data\n"); + print_buf("data", data, data_len); + return 1; + } + if (sw1sw2 != 0x6286) { + fprintf(stderr, "Unexpected SW1-SW2 %04X\n", sw1sw2); + return 2; + } + printf("Success\n"); + + // Test APDU case 4; warning processing ('61' then '62') + printf("\nTesting APDU case 4 (TPDU mode); warning processing ('61' then '62')...\n"); + emul_ctx.xpdu_list = test_tpdu_case_4_warning2; emul_ctx.xpdu_current = NULL; data_len = sizeof(data); @@ -782,11 +836,11 @@ int main(void) fprintf(stderr, "emv_ttl_trx() failed; r=%d\n", r); return 1; } - if (data_len != sizeof(test_tpdu_case_4_warning_data)) { + if (data_len != sizeof(test_tpdu_case_4_warning2_data)) { fprintf(stderr, "emv_ttl_trx() failed; incorrect response data length\n"); return 1; } - if (memcmp(data, test_tpdu_case_4_warning_data, data_len) != 0) { + if (memcmp(data, test_tpdu_case_4_warning2_data, data_len) != 0) { fprintf(stderr, "emv_ttl_trx() failed; incorrect response data\n"); print_buf("data", data, data_len); return 1;