Skip to content

Commit

Permalink
Stringify Issuer Authentication Data (field 91)
Browse files Browse the repository at this point in the history
This field is determined by the issuer while each payment scheme may
have one or more different formats. Publically available information
about this field is also very limited. And in the absence of the
Application PAN (field 5A) and Issuer Application Data (field 9F10),
some guessing is required to partially decode this field.
  • Loading branch information
leonlynch committed Mar 26, 2024
1 parent 87b9cd2 commit ef894f4
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 3 deletions.
92 changes: 92 additions & 0 deletions src/emv_strings.c
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,13 @@ int emv_tlv_get_info(
info->format = EMV_FORMAT_B;
return 0;

case EMV_TAG_91_ISSUER_AUTHENTICATION_DATA:
info->tag_name = "Issuer Authentication Data";
info->tag_desc =
"Data sent to the ICC for online issuer authentication";
info->format = EMV_FORMAT_B;
return emv_issuer_auth_data_get_string_list(tlv->value, tlv->length, value_str, value_str_len);

case EMV_TAG_92_ISSUER_PUBLIC_KEY_REMAINDER:
info->tag_name = "Issuer Public Key Remainder";
info->tag_desc =
Expand Down Expand Up @@ -5621,3 +5628,88 @@ int emv_auth_response_code_get_string(

return 0;
}

int emv_issuer_auth_data_get_string_list(
const uint8_t* iad,
size_t iad_len,
char* str,
size_t str_len
)
{
int r;
struct str_itr_t itr;
char arc_str[3];

if (!iad || !iad_len) {
return -1;
}

if (!str || !str_len) {
// Caller didn't want the value string
return 0;
}

if (iad_len < 8 || iad_len > 32) {
// Issuer Authentication Data (field 91) must be 8 to 16 bytes.
return 1;
}

emv_str_list_init(&itr, str, str_len);

// Issuer Authentication Data (field 91) is determined by the issuer
// while each payment scheme may have one or more different formats.
// Therefore some guesing may be required to partially decode it.
if (iad_len == 10) {
r = emv_format_an_get_string(iad + 8, 2, arc_str, sizeof(arc_str));
if (r == 0) {
// Likely Visa CVN10 or Visa CVN17
// 8-byte ARPC followed by 2-character ARPC Response Code resembling Authorisation Response Code
// See Visa Contactless Payment Specification (VCPS) Supplemental Requirements, version 2.2, January 2016, Annex D
emv_str_list_add(&itr, "Authorisation Response Cryptogram (ARPC): %02X%02X%02X%02X%02X%02X%02X%02X",
iad[0], iad[1], iad[2], iad[3], iad[4], iad[5], iad[6], iad[7]
);
emv_str_list_add(&itr, "Authorisation Response Code: %s", arc_str);

return 0;

} else if ((iad[8] & 0xF0) == 0) { // Check for M/Chip RFU bits
// Likely M/Chip
// 8-byte ARPC followed by 2-byte ARPC Response code in M/Chip format
// NOTE: From unverified internet sources
emv_str_list_add(&itr, "Authorisation Response Cryptogram (ARPC): %02X%02X%02X%02X%02X%02X%02X%02X",
iad[0], iad[1], iad[2], iad[3], iad[4], iad[5], iad[6], iad[7]
);
emv_str_list_add(&itr, "M/Chip ARPC Response Code: %02X%02X", iad[8], iad[9]);

return 0;
}
}
if ((iad[4] & 0x70) == 0 && iad[6] == 0) { // Check for Visa CSU RFU bits
// Likely Visa CVN18 or Visa CVN'22'
// 4-byte ARPC followed by CSU and optional Proprietary Authentication Data
// See Visa Contactless Payment Specification (VCPS) Supplemental Requirements, version 2.2, January 2016, Annex D
emv_str_list_add(&itr, "Authorisation Response Cryptogram (ARPC): %02X%02X%02X%02X",
iad[0], iad[1], iad[2], iad[3]
);
emv_str_list_add(&itr, "Card Status Update (CSU): %02X%02X%02X%02X",
iad[4], iad[5], iad[6], iad[7]
);
if (iad_len > 8) { // If extra data after CSU
if ((iad[4] & 0x80) == 0x80) { // CSU indicates Proprietary Authentication Data
emv_str_list_add(&itr, "Proprietary Authentication Data: %zu bytes", iad_len - 8);
} else if (iad_len == 10) {
// Two extra bytes but not Proprietary Authentication Data
r = emv_format_an_get_string(iad + 8, 2, arc_str, sizeof(arc_str));
if (r == 0) {
// Likely Visa CVN18 or Visa CVN'22' "third map issuers"
// See Visa Contactless Payment Specification (VCPS) Supplemental Requirements, version 2.2, January 2016, Annex D
emv_str_list_add(&itr, "Authorisation Response Code: %s", arc_str);
}
}
}

return 0;
}

return 0;
}
16 changes: 16 additions & 0 deletions src/emv_strings.h
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,22 @@ int emv_auth_response_code_get_string(
size_t str_len
);

/**
* Stringify Issuer Authentication Data (field 91)
* @note Strings in output buffer are delimited using "\n", including the last string
* @param iad Issuer Authentication Data field. Must be 8 to 16 bytes.
* @param iad_len Length of Issuer Authentication Data field. Must be 8 to 16 bytes.
* @param str String buffer output
* @param str_len Length of string buffer in bytes
* @return Zero for success. Less than zero for internal error. Greater than zero for parse error.
*/
int emv_issuer_auth_data_get_string_list(
const uint8_t* iad,
size_t iad_len,
char* str,
size_t str_len
);

__END_DECLS

#endif
3 changes: 3 additions & 0 deletions src/emv_tags.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@ __BEGIN_DECLS
/// EMV tag 90 Issuer Public Key Certificate. Template 70 or 77.
#define EMV_TAG_90_ISSUER_PUBLIC_KEY_CERTIFICATE (0x90)

/// EMV tag 91 Issuer Authentication Data
#define EMV_TAG_91_ISSUER_AUTHENTICATION_DATA (0x91)

/// EMV tag 92 Issuer Public Key Remainder. Template 70 or 77.
#define EMV_TAG_92_ISSUER_PUBLIC_KEY_REMAINDER (0x92)

Expand Down
12 changes: 9 additions & 3 deletions tools/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -590,7 +590,9 @@ if(TARGET emv-decode AND BUILD_TESTING)
string(CONCAT emv_decode_issuer_response_test1_regex
"^89 \\| Authorisation Code : \\[6\\] 31 30 36 36 30 39 \"106609\"[\r\n]"
"8A \\| Authorisation Response Code : \\[2\\] 30 30 \"00 - Approved or completed successfully\"[\r\n]"
"91 : \\[10\\] 50 FC 62 05 03 82 00 00 30 30[\r\n]"
"91 \\| Issuer Authentication Data : \\[10\\] 50 FC 62 05 03 82 00 00 30 30[\r\n]"
" - Authorisation Response Cryptogram \\(ARPC\\): 50FC620503820000[\r\n]"
" - Authorisation Response Code: 00[\r\n]"
)
set_tests_properties(emv_decode_issuer_response_test1
PROPERTIES
Expand All @@ -607,7 +609,9 @@ if(TARGET emv-decode AND BUILD_TESTING)
"72 \\| Issuer Script Template 2 : \\[17\\][\r\n]"
" 86 \\| Issuer Script Command : \\[15\\] 04 DA 9F 6B 0A 00 00 00 05 00 00 91 98 63 52[\r\n]"
"8A \\| Authorisation Response Code : \\[2\\] 30 30 \"00 - Approved or completed successfully\"[\r\n]"
"91 : \\[8\\] A5 84 F9 49 00 82 00 00[\r\n]"
"91 \\| Issuer Authentication Data : \\[8\\] A5 84 F9 49 00 82 00 00[\r\n]"
" - Authorisation Response Cryptogram \\(ARPC\\): A584F949[\r\n]"
" - Card Status Update \\(CSU\\): 00820000[\r\n]"
)
set_tests_properties(emv_decode_issuer_response_test2
PROPERTIES
Expand All @@ -620,7 +624,9 @@ if(TARGET emv-decode AND BUILD_TESTING)
--mcc-json ${MCC_JSON_BUILD_PATH}
)
string(CONCAT emv_decode_issuer_response_test3_regex
"^91 : \\[10\\] FC 43 65 35 D6 14 F3 73 00 10[\r\n]"
"^91 \\| Issuer Authentication Data : \\[10\\] FC 43 65 35 D6 14 F3 73 00 10[\r\n]"
" - Authorisation Response Cryptogram \\(ARPC\\): FC436535D614F373[\r\n]"
" - M/Chip ARPC Response Code: 0010[\r\n]"
"8A \\| Authorisation Response Code : \\[2\\] 30 30 \"00 - Approved or completed successfully\"[\r\n]"
"89 \\| Authorisation Code : \\[6\\] 38 31 39 35 33 34 \"819534\"[\r\n]"
)
Expand Down

0 comments on commit ef894f4

Please sign in to comment.