Skip to content

Commit

Permalink
Refactor emv_select_application() to use emv_ctx_t
Browse files Browse the repository at this point in the history
Note that emv_select_application() will now also free
emv_ctx_t.selected_app if it was previously populated.
  • Loading branch information
leonlynch committed May 4, 2024
1 parent dbb75c4 commit a547b17
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 25 deletions.
28 changes: 20 additions & 8 deletions src/emv.c
Original file line number Diff line number Diff line change
Expand Up @@ -395,26 +395,38 @@ int emv_build_candidate_list(
}

int emv_select_application(
struct emv_ttl_t* ttl,
struct emv_ctx_t* ctx,
struct emv_app_list_t* app_list,
unsigned int index,
struct emv_app_t** selected_app
unsigned int index
)
{
int r;
struct emv_app_t* current_app = NULL;
uint8_t current_aid[16];
size_t current_aid_len;

if (!ttl || !app_list || !selected_app) {
emv_debug_trace_msg("ttl=%p, app_list=%p, index=%u, selected_app=%p", ttl, app_list, index, selected_app);
if (!ctx || !app_list) {
emv_debug_trace_msg("ctx=%p, app_list=%p, index=%u", ctx, app_list, index);
emv_debug_error("Invalid parameter");
return EMV_ERROR_INVALID_PARAMETER;
}
*selected_app = NULL;

if (ctx->selected_app) {
// Free any previously selected app and ensure that it succeeds
r = emv_app_free(ctx->selected_app);
if (r) {
emv_debug_trace_msg("emv_app_free() failed; r=%d", r);
emv_debug_error("Internal error");
return EMV_ERROR_INTERNAL;

}
ctx->selected_app = NULL;
}

current_app = emv_app_list_remove_index(app_list, index);
if (!current_app) {
emv_debug_trace_msg("emv_app_list_remove_index() failed; index=%u", index);
emv_debug_error("Invalid parameter");
return EMV_ERROR_INVALID_PARAMETER;
}

Expand All @@ -427,10 +439,10 @@ int emv_select_application(
current_app = NULL;

r = emv_tal_select_app(
ttl,
ctx->ttl,
current_aid,
current_aid_len,
selected_app
&ctx->selected_app
);
if (r) {
emv_debug_trace_msg("emv_tal_select_app() failed; r=%d", r);
Expand Down
8 changes: 3 additions & 5 deletions src/emv.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,20 +244,18 @@ int emv_build_candidate_list(
* @remark See EMV 4.4 Book 1, 12.4
* @remark See EMV 4.4 Book 4, 11.3
*
* @param ttl EMV Terminal Transport Layer context
* @param ctx EMV processing context
* @param app_list Candidate application list
* @param index Index (starting from zero) of EMV application to select
* @param selected_app Selected EMV application output. Use @ref emv_app_free() to free memory.
*
* @return Zero for success
* @return Less than zero for errors. See @ref emv_error_t
* @return Greater than zero for EMV processing outcome. See @ref emv_outcome_t
*/
int emv_select_application(
struct emv_ttl_t* ttl,
struct emv_ctx_t* ctx,
struct emv_app_list_t* app_list,
unsigned int index,
struct emv_app_t** selected_app
unsigned int index
);

/**
Expand Down
56 changes: 46 additions & 10 deletions tests/emv_select_application_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,14 @@ static const struct xpdu_t test_select_app_success[] = {
{ 0 }
};

static const struct xpdu_t test_repeat_select_app_success[] = {
{
13, (uint8_t[]){ 0x00, 0xA4, 0x04, 0x00, 0x07, 0xA0, 0x00, 0x00, 0x00, 0x03, 0x10, 0x04, 0x00 }, // SELECT A0000000031004
32, (uint8_t[]){ 0x6F, 0x1C, 0x84, 0x07, 0xA0, 0x00, 0x00, 0x00, 0x03, 0x10, 0x04, 0xA5, 0x11, 0x50, 0x05, 0x56, 0x20, 0x50, 0x41, 0x59, 0x87, 0x01, 0x01, 0x5F, 0x2D, 0x04, 0x6E, 0x6C, 0x65, 0x6E, 0x90, 0x00 }, // FCI
},
{ 0 }
};

static bool verify_app_list_numbers(
const struct emv_app_list_t* app_list,
const unsigned int* numbers,
Expand Down Expand Up @@ -186,7 +194,6 @@ int main(void)
r = 1;
goto exit;
}
emv.selected_app = (void*)42;

// Supported applications
emv_tlv_list_push(&emv.supported_aids, EMV_TAG_9F06_AID, 6, (uint8_t[]){ 0xA0, 0x00, 0x00, 0x00, 0x03, 0x10 }, EMV_ASI_PARTIAL_MATCH); // Visa
Expand Down Expand Up @@ -244,7 +251,7 @@ int main(void)
printf("Success\n");

printf("\nTest selection of invalid application index...\n");
r = emv_select_application(emv.ttl, &app_list, 13, &emv.selected_app);
r = emv_select_application(&emv, &app_list, 13);
if (r != EMV_ERROR_INVALID_PARAMETER) {
fprintf(stderr, "Unexpected emv_select_application() result; error %d: %s\n", r, r < 0 ? emv_error_get_string(r) : emv_outcome_get_string(r));
r = 1;
Expand All @@ -268,7 +275,7 @@ int main(void)
printf("\nTest selection of first application index and application not found...\n");
emul_ctx.xpdu_list = test_select_app1;
emul_ctx.xpdu_current = NULL;
r = emv_select_application(emv.ttl, &app_list, 0, &emv.selected_app);
r = emv_select_application(&emv, &app_list, 0);
if (r != EMV_OUTCOME_TRY_AGAIN) {
fprintf(stderr, "Unexpected emv_select_application() result; error %d: %s\n", r, r < 0 ? emv_error_get_string(r) : emv_outcome_get_string(r));
r = 1;
Expand Down Expand Up @@ -297,7 +304,7 @@ int main(void)
printf("\nTest selection of last application index and application blocked...\n");
emul_ctx.xpdu_list = test_select_app7;
emul_ctx.xpdu_current = NULL;
r = emv_select_application(emv.ttl, &app_list, 5, &emv.selected_app);
r = emv_select_application(&emv, &app_list, 5);
if (r != EMV_OUTCOME_TRY_AGAIN) {
fprintf(stderr, "Unexpected emv_select_application() result; error %d: %s\n", r, r < 0 ? emv_error_get_string(r) : emv_outcome_get_string(r));
r = 1;
Expand Down Expand Up @@ -326,7 +333,7 @@ int main(void)
printf("\nTest card error during application selection...\n");
emul_ctx.xpdu_list = test_select_app4;
emul_ctx.xpdu_current = NULL;
r = emv_select_application(emv.ttl, &app_list, 2, &emv.selected_app);
r = emv_select_application(&emv, &app_list, 2);
if (r != EMV_OUTCOME_CARD_ERROR) {
fprintf(stderr, "Unexpected emv_select_application() result; error %d: %s\n", r, r < 0 ? emv_error_get_string(r) : emv_outcome_get_string(r));
r = 1;
Expand Down Expand Up @@ -355,7 +362,7 @@ int main(void)
printf("\nTest selection of application with card blocked...\n");
emul_ctx.xpdu_list = test_select_app3;
emul_ctx.xpdu_current = NULL;
r = emv_select_application(emv.ttl, &app_list, 1, &emv.selected_app);
r = emv_select_application(&emv, &app_list, 1);
if (r != EMV_OUTCOME_CARD_BLOCKED) {
fprintf(stderr, "Unexpected emv_select_application() result; error %d: %s\n", r, r < 0 ? emv_error_get_string(r) : emv_outcome_get_string(r));
r = 1;
Expand Down Expand Up @@ -384,7 +391,7 @@ int main(void)
printf("\nTest invalid FCI during application selection...\n");
emul_ctx.xpdu_list = test_select_app5;
emul_ctx.xpdu_current = NULL;
r = emv_select_application(emv.ttl, &app_list, 1, &emv.selected_app);
r = emv_select_application(&emv, &app_list, 1);
if (r != EMV_OUTCOME_TRY_AGAIN) {
fprintf(stderr, "Unexpected emv_select_application() result; error %d: %s\n", r, r < 0 ? emv_error_get_string(r) : emv_outcome_get_string(r));
r = 1;
Expand Down Expand Up @@ -413,7 +420,7 @@ int main(void)
printf("\nTest DF Name mismatch during application selection...\n");
emul_ctx.xpdu_list = test_select_app2;
emul_ctx.xpdu_current = NULL;
r = emv_select_application(emv.ttl, &app_list, 0, &emv.selected_app);
r = emv_select_application(&emv, &app_list, 0);
if (r != EMV_OUTCOME_TRY_AGAIN) {
fprintf(stderr, "Unexpected emv_select_application() result; error %d: %s\n", r, r < 0 ? emv_error_get_string(r) : emv_outcome_get_string(r));
r = 1;
Expand Down Expand Up @@ -442,7 +449,7 @@ int main(void)
printf("\nTest DF Name mismatch during application selection and expecting empty candidate application list...\n");
emul_ctx.xpdu_list = test_select_app6;
emul_ctx.xpdu_current = NULL;
r = emv_select_application(emv.ttl, &app_list, 0, &emv.selected_app);
r = emv_select_application(&emv, &app_list, 0);
if (r != EMV_OUTCOME_NOT_ACCEPTED) {
fprintf(stderr, "Unexpected emv_select_application() result; error %d: %s\n", r, r < 0 ? emv_error_get_string(r) : emv_outcome_get_string(r));
r = 1;
Expand Down Expand Up @@ -531,7 +538,7 @@ int main(void)
printf("\nTest successful application selection...\n");
emul_ctx.xpdu_list = test_select_app_success;
emul_ctx.xpdu_current = NULL;
r = emv_select_application(emv.ttl, &app_list, 2, &emv.selected_app);
r = emv_select_application(&emv, &app_list, 2);
if (r) {
fprintf(stderr, "emv_select_application() failed; error %d: %s\n", r, r < 0 ? emv_error_get_string(r) : emv_outcome_get_string(r));
r = 1;
Expand All @@ -557,6 +564,35 @@ int main(void)
}
printf("Success\n");

printf("\nTest application selection after previous successful application selection...\n");
emul_ctx.xpdu_list = test_repeat_select_app_success;
emul_ctx.xpdu_current = NULL;
r = emv_select_application(&emv, &app_list, 2);
if (r) {
fprintf(stderr, "emv_select_application() failed; error %d: %s\n", r, r < 0 ? emv_error_get_string(r) : emv_outcome_get_string(r));
r = 1;
goto exit;
}
if (emul_ctx.xpdu_current->c_xpdu_len != 0) {
fprintf(stderr, "Incomplete card interaction\n");
r = 1;
goto exit;
}
if (!emv.selected_app) {
fprintf(stderr, "emv_select_application() failed to populate selected_app\n");
r = 1;
goto exit;
}
if (!verify_app_list_numbers(&app_list, (unsigned int[]){ 1, 2, 5, 6, 7 }, 5)) {
fprintf(stderr, "Invalid remaining candidate application list\n");
for (struct emv_app_t* app = app_list.front; app != NULL; app = app->next) {
print_emv_app(app);
}
r = 1;
goto exit;
}
printf("Success\n");

// Success
r = 0;
goto exit;
Expand Down
3 changes: 1 addition & 2 deletions tools/emv-tool.c
Original file line number Diff line number Diff line change
Expand Up @@ -835,7 +835,7 @@ int main(int argc, char** argv)
index = 0;
}

r = emv_select_application(emv.ttl, &app_list, index, &emv.selected_app);
r = emv_select_application(&emv, &app_list, index);
if (r < 0) {
printf("ERROR: %s\n", emv_error_get_string(r));
goto emv_exit;
Expand Down Expand Up @@ -871,7 +871,6 @@ int main(int argc, char** argv)
if (r == EMV_OUTCOME_GPO_NOT_ACCEPTED && !emv_app_list_is_empty(&app_list)) {
// Return to cardholder application selection/confirmation
// See EMV 4.4 Book 4, 6.3.1
emv_app_free(emv.selected_app);
continue;
}
goto emv_exit;
Expand Down

0 comments on commit a547b17

Please sign in to comment.