Skip to content

Commit

Permalink
Improve EMV Data Object List (DOL) processing
Browse files Browse the repository at this point in the history
Allow emv_dol_build_data() to use an arbitrary number of TLV lists as
data sources.
  • Loading branch information
leonlynch committed May 12, 2024
1 parent 63f9cff commit 31777d5
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 22 deletions.
10 changes: 8 additions & 2 deletions src/emv.c
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,8 @@ int emv_initiate_application_processing(
)
{
int r;
const struct emv_tlv_list_t* sources[2];
size_t sources_count = sizeof(sources) / sizeof(sources[0]);
const struct emv_tlv_t* pdol;
uint8_t gpo_data_buf[255]; // See EMV_CAPDU_DATA_MAX
uint8_t* gpo_data;
Expand All @@ -509,6 +511,10 @@ int emv_initiate_application_processing(
emv_tlv_list_clear(&ctx->icc);
emv_tlv_list_clear(&ctx->terminal);

// Prepare ordered data source list
sources[0] = &ctx->params;
sources[1] = &ctx->config;

// Process PDOL, if available
// See EMV 4.4 Book 3, 10.1
pdol = emv_tlv_list_find_const(&ctx->selected_app->tlv_list, EMV_TAG_9F38_PDOL);
Expand Down Expand Up @@ -547,8 +553,8 @@ int emv_initiate_application_processing(
r = emv_dol_build_data(
pdol->value,
pdol->length,
&ctx->params,
&ctx->config,
sources,
sources_count,
gpo_data + gpo_data_offset,
&gpo_data_len
);
Expand Down
27 changes: 17 additions & 10 deletions src/emv_dol.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ int emv_dol_compute_data_length(const void* ptr, size_t len)
int emv_dol_build_data(
const void* ptr,
size_t len,
const struct emv_tlv_list_t* source1,
const struct emv_tlv_list_t* source2,
const struct emv_tlv_list_t** sources,
size_t sources_count,
void* data,
size_t* data_len
)
Expand All @@ -138,13 +138,18 @@ int emv_dol_build_data(
struct emv_dol_entry_t entry;
void* data_ptr = data;

if (!ptr || !len || !source1 || !data || !data_len || !*data_len) {
if (!ptr || !len || !sources || !sources_count || !data || !data_len || !*data_len) {
return -1;
}
for (size_t i = 0; i < sources_count; ++i) {
if (!sources[i]) {
return -2;
}
}

r = emv_dol_itr_init(ptr, len, &itr);
if (r) {
return -2;
return -3;
}

while ((r = emv_dol_itr_next(&itr, &entry)) > 0) {
Expand All @@ -155,10 +160,12 @@ int emv_dol_build_data(
return 1;
}

// Find TLV
tlv = emv_tlv_list_find_const(source1, entry.tag);
if (!tlv && source2) {
tlv = emv_tlv_list_find_const(source2, entry.tag);
// Find TLV in ordered list of EMV TLV lists
for (size_t i = 0; i < sources_count; ++i) {
tlv = emv_tlv_list_find_const(sources[i], entry.tag);
if (tlv) {
break;
}
}
if (!tlv) {
// If TLV is not found, zero data output
Expand Down Expand Up @@ -209,10 +216,10 @@ int emv_dol_build_data(
}

// This should never happen
return -3;
return -4;
}
if (r != 0) {
return -4;
return -5;
}

*data_len = data_ptr - data;
Expand Down
8 changes: 4 additions & 4 deletions src/emv_dol.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,17 +84,17 @@ int emv_dol_compute_data_length(const void* ptr, size_t len);
* Build concatenated data according to Data Object List (DOL)
* @param ptr Encoded EMV Data Object List (DOL)
* @param len Length of encoded EMV Data Object List (DOL) in bytes
* @param source1 EMV TLV list used as primary source. Required.
* @param source2 EMV TLV list used as secondary source. NULL to ignore.
* @param sources Ordered list of EMV TLV lists used as data sources.
* @param sources_count Number of entries in @p sources.
* @param data Concatenated data output
* @param data_len Length of concatenated data output in bytes
* @return Zero for success. Less than zero for internal error. Greater than zero if output data length too small.
*/
int emv_dol_build_data(
const void* ptr,
size_t len,
const struct emv_tlv_list_t* source1,
const struct emv_tlv_list_t* source2,
const struct emv_tlv_list_t** sources,
size_t sources_count,
void* data,
size_t* data_len
);
Expand Down
16 changes: 10 additions & 6 deletions tests/emv_dol_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,11 @@ const struct emv_tlv_t test6_source1[] = {
{ {{ EMV_TAG_5F2A_TRANSACTION_CURRENCY_CODE, 2, (uint8_t[]){ 0x09, 0x78 }, 0 }}, NULL },
{ {{ EMV_TAG_9F02_AMOUNT_AUTHORISED_NUMERIC, 6, (uint8_t[]){ 0x00, 0x01, 0x23, 0x45, 0x67, 0x89 }, 0 }}, NULL },
{ {{ EMV_TAG_9F03_AMOUNT_OTHER_NUMERIC, 6, (uint8_t[]){ 0x00, 0x09, 0x87, 0x65, 0x43, 0x21 }, 0 }}, NULL },
{ {{ EMV_TAG_9F37_UNPREDICTABLE_NUMBER, 4, (uint8_t[]){ 0xDE, 0xAD, 0xBE, 0xEF }, 0 }}, NULL },
};
const struct emv_tlv_t test6_source2[] = {
{ {{ EMV_TAG_9F1A_TERMINAL_COUNTRY_CODE, 2, (uint8_t[]){ 0x05, 0x28 }, 0 }}, NULL },
{ {{ EMV_TAG_9F37_UNPREDICTABLE_NUMBER, 4, (uint8_t[]){ 0xDE, 0xAD, 0xBE, 0xEF }, 0 }}, NULL },
{ {{ EMV_TAG_9F37_UNPREDICTABLE_NUMBER, 4, (uint8_t[]){ 0xDE, 0xAD, 0xCA, 0xFE }, 0 }}, NULL },
{ {{ EMV_TAG_95_TERMINAL_VERIFICATION_RESULTS, 5, (uint8_t[]){ 0x12, 0x34, 0x55, 0x43, 0x21 }, 0 }}, NULL },
};
const uint8_t test6_data[] = {
Expand Down Expand Up @@ -105,10 +106,11 @@ const struct emv_tlv_t test7_source1[] = {
{ {{ EMV_TAG_5F2A_TRANSACTION_CURRENCY_CODE, 2, (uint8_t[]){ 0x09, 0x78 }, 0 }}, NULL },
{ {{ EMV_TAG_9F02_AMOUNT_AUTHORISED_NUMERIC, 6, (uint8_t[]){ 0x00, 0x01, 0x23, 0x45, 0x67, 0x89 }, 0 }}, NULL },
{ {{ EMV_TAG_9F03_AMOUNT_OTHER_NUMERIC, 6, (uint8_t[]){ 0x00, 0x09, 0x87, 0x65, 0x43, 0x21 }, 0 }}, NULL },
{ {{ EMV_TAG_9F37_UNPREDICTABLE_NUMBER, 4, (uint8_t[]){ 0xDE, 0xAD, 0xBE, 0xEF }, 0 }}, NULL },
};
const struct emv_tlv_t test7_source2[] = {
{ {{ EMV_TAG_9F1A_TERMINAL_COUNTRY_CODE, 2, (uint8_t[]){ 0x05, 0x28 }, 0 }}, NULL },
{ {{ EMV_TAG_9F37_UNPREDICTABLE_NUMBER, 4, (uint8_t[]){ 0xDE, 0xAD, 0xBE, 0xEF }, 0 }}, NULL },
{ {{ EMV_TAG_9F37_UNPREDICTABLE_NUMBER, 4, (uint8_t[]){ 0xDE, 0xAD, 0xCA, 0xFE }, 0 }}, NULL },
{ {{ EMV_TAG_95_TERMINAL_VERIFICATION_RESULTS, 5, (uint8_t[]){ 0x12, 0x34, 0x55, 0x43, 0x21 }, 0 }}, NULL },
};
const uint8_t test7_data[] = {
Expand Down Expand Up @@ -150,6 +152,8 @@ int main(void)
size_t data_len;
struct emv_tlv_list_t source1 = EMV_TLV_LIST_INIT;
struct emv_tlv_list_t source2 = EMV_TLV_LIST_INIT;
const struct emv_tlv_list_t* sources[2] = { &source1, &source2 };
size_t sources_count = sizeof(sources) / sizeof(sources[0]);

printf("\nTest 1: Iterate valid DOL\n");
r = emv_dol_itr_init(test1_dol, sizeof(test1_dol), &itr);
Expand Down Expand Up @@ -258,8 +262,8 @@ int main(void)
r = emv_dol_build_data(
test6_dol,
sizeof(test6_dol),
&source1,
&source2,
sources,
sources_count,
data,
&data_len
);
Expand Down Expand Up @@ -293,8 +297,8 @@ int main(void)
r = emv_dol_build_data(
test7_dol,
sizeof(test7_dol),
&source1,
&source2,
sources,
sources_count,
data,
&data_len
);
Expand Down

0 comments on commit 31777d5

Please sign in to comment.