Skip to content

Commit

Permalink
Refactor PSE processing
Browse files Browse the repository at this point in the history
* Update comments to EMV 4.4
* Implement error and result enums for TAL
* Add logging for all code paths
* Build candidate list while processing PSE AEF records as recommended
  by EMV 4.4 Book 1, 12.3.2, step 3, instead of afterwards
* Ensure that emv_app_list_push() clears the next pointer of the app
  being pushed onto the back of the list
* Remove emv_app_list_filter_supported() because it is no longer needed
* Let emv_app_is_supported() take const parameters
* Fix emv_tlv_parse() recursion
  • Loading branch information
leonlynch committed Jan 16, 2024
1 parent 5b98bed commit cad512d
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 97 deletions.
55 changes: 25 additions & 30 deletions src/emv_app.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @file emv_app.c
* @brief EMV application abstraction and helper functions
*
* Copyright (c) 2021, 2022, 2023 Leon Lynch
* Copyright (c) 2021-2024 Leon Lynch
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
Expand Down Expand Up @@ -64,6 +64,10 @@ struct emv_app_t* emv_app_create_from_pse(

// Use ADF Name field for AID
app->aid = emv_tlv_list_find(&app->tlv_list, EMV_TAG_4F_APPLICATION_DF_NAME);
if (!app->aid) {
// Invalid FCI
goto error;
}

r = emv_app_extract_display_name(app, pse_tlv_list);
if (r) {
Expand Down Expand Up @@ -118,6 +122,10 @@ struct emv_app_t* emv_app_create_from_fci(const void* fci, size_t fci_len)

// Use DF Name field for AID
app->aid = emv_tlv_list_find(&app->tlv_list, EMV_TAG_84_DF_NAME);
if (!app->aid) {
// Invalid FCI
goto error;
}

r = emv_app_extract_display_name(app, NULL);
if (r) {
Expand Down Expand Up @@ -172,6 +180,10 @@ static int emv_app_extract_display_name(struct emv_app_t* app, struct emv_tlv_li
unsigned int issuer_code_table = 0;
struct emv_tlv_t* tlv;

if (!app) {
return -1;
}

/* Find Application Preferred Name and associated Issuer Code Table Index
* Both are optional fields but Issuer Code Table Index is required to
* interpret Application Preferred Name
Expand Down Expand Up @@ -262,6 +274,10 @@ static int emv_app_extract_priority_indicator(struct emv_app_t* app)
{
struct emv_tlv_t* tlv;

if (!app) {
return -1;
}

app->priority = 0;
app->confirmation_required = false;

Expand Down Expand Up @@ -295,7 +311,10 @@ int emv_app_free(struct emv_app_t* app)
return 0;
}

bool emv_app_is_supported(struct emv_app_t* app, struct emv_tlv_list_t* supported_aids)
bool emv_app_is_supported(
const struct emv_app_t* app,
const struct emv_tlv_list_t* supported_aids
)
{
struct emv_tlv_t* tlv;

Expand Down Expand Up @@ -382,6 +401,9 @@ int emv_app_list_push(struct emv_app_list_t* list, struct emv_app_t* app)
if (!emv_app_list_is_valid(list)) {
return -1;
}
if (!app) {
return -2;
}

if (list->back) {
list->back->next = app;
Expand All @@ -390,6 +412,7 @@ int emv_app_list_push(struct emv_app_list_t* list, struct emv_app_t* app)
list->front = app;
list->back = app;
}
app->next = NULL;

return 0;
}
Expand All @@ -414,31 +437,3 @@ struct emv_app_t* emv_app_list_pop(struct emv_app_list_t* list)

return app;
}

int emv_app_list_filter_supported(struct emv_app_list_t* list, struct emv_tlv_list_t* supported_aids)
{
int r;
struct emv_app_list_t supported_list = EMV_APP_LIST_INIT;
struct emv_app_t* app;

if (!emv_app_list_is_valid(list)) {
return -1;
}

while ((app = emv_app_list_pop(list))) {
if (emv_app_is_supported(app, supported_aids)) {
r = emv_app_list_push(&supported_list, app);
if (r) {
emv_app_list_clear(&supported_list);
return -1;
}
} else {
emv_app_free(app);
app = NULL;
}
}

*list = supported_list;

return 0;
}
26 changes: 11 additions & 15 deletions src/emv_app.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @file emv_app.h
* @brief EMV application abstraction and helper functions
*
* Copyright (c) 2021 Leon Lynch
* Copyright (c) 2021, 2024 Leon Lynch
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
Expand Down Expand Up @@ -38,7 +38,7 @@ struct emv_app_t {
* Application Identifier (AID) field, as provided by:
* - Application Dedicated File (ADF) Name (field 4F)
* - Dedicated File (DF) Name (field 84)
* in order of priority, if found in @c tlv_list
* if found in @c tlv_list
*/
const struct emv_tlv_t* aid;

Expand All @@ -56,14 +56,14 @@ struct emv_app_t {
* Application priority ordering, as provided by Application Priority
* Indicator (field 87), bits 1 to 4. Valid range is 1 to 15, with 1 being
* the highest priority. Zero if not available.
* See EMV 4.3 Book 1, 12.4 for usage
* See EMV 4.4 Book 1, 12.4 for usage
*/
uint8_t priority;

/**
* Boolean indicating whether application requires cardholder confirmation
* for selection, even if it is the only application.
* See EMV 4.3 Book 1, 12.4 for usage
* See EMV 4.4 Book 1, 12.4 for usage
*/
bool confirmation_required;

Expand Down Expand Up @@ -95,7 +95,7 @@ struct emv_app_list_t {
* @param pse_dir_entry PSE directory entry (content of Application Template, field 61)
* @param pse_dir_entry_len Length of PSE directory entry in bytes
* @return New EMV application object. NULL for error.
* Use @ref emv_tlv_free() to free memory.
* Use @ref emv_app_free() to free memory.
*/
struct emv_app_t* emv_app_create_from_pse(
struct emv_tlv_list_t* pse_tlv_list,
Expand All @@ -111,7 +111,7 @@ struct emv_app_t* emv_app_create_from_pse(
* @param fci FCI data provided by application selection
* @param fci_len Length of FCI data in bytes
* @return New EMV application object. NULL for error.
* Use @ref emv_tlv_free() to free memory.
* Use @ref emv_app_free() to free memory.
*/
struct emv_app_t* emv_app_create_from_fci(const void* fci, size_t fci_len);

Expand All @@ -129,13 +129,17 @@ int emv_app_free(struct emv_app_t* app);
* @param supported_aids Supported AID (field 9F06) list including ASI flags
* @return Boolean indicating whether EMV application is supported
*/
bool emv_app_is_supported(struct emv_app_t* app, struct emv_tlv_list_t* supported_aids);
bool emv_app_is_supported(
const struct emv_app_t* app,
const struct emv_tlv_list_t* supported_aids
);

/// Static initialiser for @ref emv_app_list_t
#define EMV_APP_LIST_INIT { NULL, NULL }

/**
* Determine whether EMV application list is empty
* @param list EMV application list
* @return Boolean indicating whether EMV application list is empty
*/
bool emv_app_list_is_empty(const struct emv_app_list_t* list);
Expand Down Expand Up @@ -163,14 +167,6 @@ int emv_app_list_push(struct emv_app_list_t* list, struct emv_app_t* app);
*/
struct emv_app_t* emv_app_list_pop(struct emv_app_list_t* list);

/**
* Filter EMV application list according to supported AIDs
* @param list EMV application list
* @param supported_aids Supported AID (field 9F06) list including ASI flags
* @return Zero for success. Less than zero for error.
*/
int emv_app_list_filter_supported(struct emv_app_list_t* list, struct emv_tlv_list_t* supported_aids);

__END_DECLS

#endif
Loading

0 comments on commit cad512d

Please sign in to comment.