X-Git-Url: http://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/881eacc8aad5d52b33d8585fdb5a93590545c558..5a1b25ac31a1436455e54e76b6525721eace24bf:/client/emv/emv_tags.c diff --git a/client/emv/emv_tags.c b/client/emv/emv_tags.c index 1aae847a..80b4c29d 100644 --- a/client/emv/emv_tags.c +++ b/client/emv/emv_tags.c @@ -21,15 +21,21 @@ #include "emv_tags.h" #include +#include + +#define PRINT_INDENT(level) {for (int i = 0; i < (level); i++) fprintf(f, "\t");} enum emv_tag_t { EMV_TAG_GENERIC, EMV_TAG_BITMASK, EMV_TAG_DOL, EMV_TAG_CVM_LIST, + EMV_TAG_AFL, EMV_TAG_STRING, EMV_TAG_NUMERIC, EMV_TAG_YYMMDD, + EMV_TAG_CVR, + EMV_TAG_CID, }; struct emv_tag { @@ -54,8 +60,8 @@ static const struct emv_tag_bit EMV_AIP[] = { { EMV_BIT(1, 4), "Terminal risk management is to be performed" }, { EMV_BIT(1, 3), "Issuer authentication is supported" }, { EMV_BIT(1, 2), "Reserved for use by the EMV Contactless Specifications" }, - { EMV_BIT(1, 1), "CDA supported" }, - { EMV_BIT(2, 8), "Reserved for use by the EMV Contactless Specifications" }, + { EMV_BIT(1, 1), "CDA supported (Combined Dynamic Data Authentication / Application Cryptogram Generation)" }, + { EMV_BIT(2, 8), "MSD is supported (Magnetic Stripe Data)" }, { EMV_BIT(2, 7), "Reserved for use by the EMV Contactless Specifications" }, { EMV_BIT(2, 6), "Reserved for use by the EMV Contactless Specifications" }, { EMV_BIT(2, 1), "Reserved for use by the EMV Contactless Specifications" }, @@ -111,8 +117,70 @@ static const struct emv_tag_bit EMV_TVR[] = { EMV_BIT_FINISH, }; +static const struct emv_tag_bit EMV_CTQ[] = { + { EMV_BIT(1, 8), "Online PIN Required" }, + { EMV_BIT(1, 7), "Signature Required" }, + { EMV_BIT(1, 6), "Go Online if Offline Data Authentication Fails and Reader is online capable" }, + { EMV_BIT(1, 5), "Switch Interface if Offline Data Authentication fails and Reader supports VIS" }, + { EMV_BIT(1, 4), "Go Online if Application Expired" }, + { EMV_BIT(1, 3), "Switch Interface for Cash Transactions" }, + { EMV_BIT(1, 2), "Switch Interface for Cashback Transactions" }, + { EMV_BIT(2, 8), "Consumer Device CVM Performed" }, + { EMV_BIT(2, 7), "Card supports Issuer Update Processing at the POS" }, + EMV_BIT_FINISH, +}; + +static const struct emv_tag_bit EMV_TTQ[] = { + { EMV_BIT(1, 8), "MSD supported" }, + { EMV_BIT(1, 7), "VSDC supported" }, + { EMV_BIT(1, 6), "qVSDC supported" }, + { EMV_BIT(1, 5), "EMV contact chip supported" }, + { EMV_BIT(1, 4), "Offline-only reader" }, + { EMV_BIT(1, 3), "Online PIN supported" }, + { EMV_BIT(1, 2), "Signature supported" }, + { EMV_BIT(1, 1), "Offline Data Authentication (ODA) for Online Authorizations supported\nWarning!!!! Readers compliant to this specification set TTQ byte 1 bit 1 (this field) to 0b" }, + { EMV_BIT(2, 8), "Online cryptogram required" }, + { EMV_BIT(2, 7), "CVM required" }, + { EMV_BIT(2, 6), "(Contact Chip) Offline PIN supported" }, + { EMV_BIT(3, 8), "Issuer Update Processing supported" }, + { EMV_BIT(3, 7), "Mobile functionality supported (Consumer Device CVM)" }, + EMV_BIT_FINISH, +}; + +static const struct emv_tag_bit EMV_CVR[] = { + // mask 0F 0F F0 0F + { EMV_BIT(1, 4), "CDA Performed" }, + { EMV_BIT(1, 3), "Offline DDA Performed" }, + { EMV_BIT(1, 2), "Issuer Authentication Not Performed" }, + { EMV_BIT(1, 1), "Issuer Authentication performed and Failed" }, + { EMV_BIT(2, 4), "Offline PIN Verification Performed" }, + { EMV_BIT(2, 3), "Offline PIN Verification Performed and PIN Not Successfully Verified" }, + { EMV_BIT(2, 2), "PIN Try Limit Exceeded" }, + { EMV_BIT(2, 1), "Last Online Transaction Not Completed" }, + { EMV_BIT(3, 8), "Lower Offline Transaction Count Limit Exceeded" }, + { EMV_BIT(3, 7), "Upper Offline Transaction Count Limit Exceeded" }, + { EMV_BIT(3, 6), "Lower Cumulative Offline Amount Limit Exceeded" }, + { EMV_BIT(3, 5), "Upper Cumulative Offline Amount Limit Exceeded" }, + { EMV_BIT(4, 4), "Issuer script processing failed on last transaction" }, + { EMV_BIT(4, 3), "Offline data authentication failed on previous transaction and transaction declined offline" }, + { EMV_BIT(4, 2), "Go Online on Next Transaction Was Set" }, + { EMV_BIT(4, 1), "Unable to go Online" }, + EMV_BIT_FINISH, +}; + +// All Data Elements by Tags used in TLV structure (according to the EMV 4.2 Standard ) +// https://www.eftlab.co.uk/index.php/site-map/knowledge-base/145-emv-nfc-tags +// http://dexterous-programmer.blogspot.in/2012/05/emv-tags.html static const struct emv_tag emv_tags[] = { + // internal { 0x00 , "Unknown ???" }, + { 0x01 , "", EMV_TAG_STRING }, // string for headers + { 0x02 , "Raw data", }, // data + { 0x20 , "Cardholder Verification Results (CVR)", EMV_TAG_CVR }, // not standard! + + // EMV + { 0x41 , "Country code and national data" }, + { 0x42 , "Issuer Identification Number (IIN)" }, { 0x4f , "Application Dedicated File (ADF) Name" }, { 0x50 , "Application Label", EMV_TAG_STRING }, { 0x56 , "Track 1 Data" }, @@ -145,14 +213,16 @@ static const struct emv_tag emv_tags[] = { { 0x91 , "Issuer Authentication Data" }, { 0x92 , "Issuer Public Key Remainder" }, { 0x93 , "Signed Static Application Data" }, - { 0x94 , "Application File Locator (AFL)" }, + { 0x94 , "Application File Locator (AFL)", EMV_TAG_AFL }, { 0x95 , "Terminal Verification Results" }, { 0x9a , "Transaction Date", EMV_TAG_YYMMDD }, { 0x9c , "Transaction Type" }, { 0x9f02, "Amount, Authorised (Numeric)", EMV_TAG_NUMERIC }, { 0x9f03, "Amount, Other (Numeric)", EMV_TAG_NUMERIC, }, + { 0x9f06, "Application Identifier (AID), Terminal. ISO 7816-5" }, { 0x9f07, "Application Usage Control", EMV_TAG_BITMASK, &EMV_AUC }, { 0x9f08, "Application Version Number" }, + { 0x9f0a, "Application Selection Registered Proprietary Data" }, // https://blog.ul-ts.com/posts/electronic-card-identifier-one-more-step-for-mif-compliance/ { 0x9f0d, "Issuer Action Code - Default", EMV_TAG_BITMASK, &EMV_TVR }, { 0x9f0e, "Issuer Action Code - Denial", EMV_TAG_BITMASK, &EMV_TVR }, { 0x9f0f, "Issuer Action Code - Online", EMV_TAG_BITMASK, &EMV_TVR }, @@ -165,7 +235,8 @@ static const struct emv_tag emv_tags[] = { { 0x9f1f, "Track 1 Discretionary Data", EMV_TAG_STRING }, { 0x9f21, "Transaction Time" }, { 0x9f26, "Application Cryptogram" }, - { 0x9f27, "Cryptogram Information Data" }, + { 0x9f27, "Cryptogram Information Data", EMV_TAG_CID }, + { 0x9f2a, "Kernel Identifier" }, { 0x9f2d, "ICC PIN Encipherment Public Key Certificate" }, { 0x9f2e, "ICC PIN Encipherment Public Key Exponent" }, { 0x9f2f, "ICC PIN Encipherment Public Key Remainder" }, @@ -187,15 +258,21 @@ static const struct emv_tag emv_tags[] = { { 0x9f4c, "ICC Dynamic Number" }, { 0x9f4d, "Log Entry" }, { 0x9f4f, "Log Format", EMV_TAG_DOL }, + { 0x9f60, "CVC3 (Track1)" }, + { 0x9f61, "CVC3 (Track2)" }, { 0x9f62, "PCVC3(Track1)" }, { 0x9f63, "PUNATC(Track1)" }, { 0x9f64, "NATC(Track1)" }, { 0x9f65, "PCVC3(Track2)" }, - { 0x9f66, "PUNATC(Track2)" }, - { 0x9f67, "NATC(Track2)" }, + { 0x9f66, "PUNATC(Track2) / Terminal Transaction Qualifiers (TTQ)", EMV_TAG_BITMASK, &EMV_TTQ }, + { 0x9f67, "NATC(Track2) / MSD Offset" }, + { 0x9f69, "Card Authentication Related Data" }, + { 0x9f6a, "Unpredictable Number", EMV_TAG_NUMERIC }, { 0x9f6b, "Track 2 Data" }, + { 0x9f6c, "Card Transaction Qualifiers (CTQ)", EMV_TAG_BITMASK, &EMV_CTQ }, { 0xa5 , "File Control Information (FCI) Proprietary Template" }, { 0xbf0c, "File Control Information (FCI) Issuer Discretionary Data" }, + { 0xdf20, "Issuer Proprietary Bitmap (IPB)" }, }; static int emv_sort_tag(tlv_tag_t tag) @@ -230,25 +307,28 @@ static const char *bitstrings[] = { "1.......", }; -static void emv_tag_dump_bitmask(const struct tlv *tlv, const struct emv_tag *tag, FILE *f) +static void emv_tag_dump_bitmask(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level) { const struct emv_tag_bit *bits = tag->data; unsigned bit, byte; for (byte = 1; byte <= tlv->len; byte ++) { unsigned char val = tlv->value[byte - 1]; + PRINT_INDENT(level); fprintf(f, "\tByte %u (%02x)\n", byte, val); for (bit = 8; bit > 0; bit--, val <<= 1) { - if (val & 0x80) + if (val & 0x80){ + PRINT_INDENT(level); fprintf(f, "\t\t%s - '%s'\n", bitstrings[bit - 1], bits->bit == EMV_BIT(byte, bit) ? bits->name : "Unknown"); + } if (bits->bit == EMV_BIT(byte, bit)) bits ++; } } } -static void emv_tag_dump_dol(const struct tlv *tlv, const struct emv_tag *tag, FILE *f) +static void emv_tag_dump_dol(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level) { const unsigned char *buf = tlv->value; size_t left = tlv->len; @@ -258,17 +338,19 @@ static void emv_tag_dump_dol(const struct tlv *tlv, const struct emv_tag *tag, F const struct emv_tag *doltag; if (!tlv_parse_tl(&buf, &left, &doltlv)) { + PRINT_INDENT(level); fprintf(f, "Invalid Tag-Len\n"); continue; } doltag = emv_get_tag(&doltlv); + PRINT_INDENT(level); fprintf(f, "\tTag %4hx len %02zx ('%s')\n", doltlv.tag, doltlv.len, doltag->name); } } -static void emv_tag_dump_string(const struct tlv *tlv, const struct emv_tag *tag, FILE *f) +static void emv_tag_dump_string(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level) { fprintf(f, "\tString value '"); fwrite(tlv->value, 1, tlv->len, f); @@ -306,13 +388,15 @@ static unsigned long emv_value_numeric(const struct tlv *tlv, unsigned start, un return ret; } -static void emv_tag_dump_numeric(const struct tlv *tlv, const struct emv_tag *tag, FILE *f) +static void emv_tag_dump_numeric(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level) { + PRINT_INDENT(level); fprintf(f, "\tNumeric value %lu\n", emv_value_numeric(tlv, 0, tlv->len * 2)); } -static void emv_tag_dump_yymmdd(const struct tlv *tlv, const struct emv_tag *tag, FILE *f) +static void emv_tag_dump_yymmdd(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level) { + PRINT_INDENT(level); fprintf(f, "\tDate: 20%02ld.%ld.%ld\n", emv_value_numeric(tlv, 0, 2), emv_value_numeric(tlv, 2, 4), @@ -324,12 +408,123 @@ static uint32_t emv_get_binary(const unsigned char *S) return (S[0] << 24) | (S[1] << 16) | (S[2] << 8) | (S[3] << 0); } -static void emv_tag_dump_cvm_list(const struct tlv *tlv, const struct emv_tag *tag, FILE *f) +// https://github.com/binaryfoo/emv-bertlv/blob/master/src/main/resources/fields/visa-cvr.txt +static void emv_tag_dump_cvr(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level) { + if (!tlv || tlv->len < 1) { + PRINT_INDENT(level); + fprintf(f, "\tINVALID!\n"); + return; + } + + if (tlv->len != tlv->value[0] + 1) { + PRINT_INDENT(level); + fprintf(f, "\tINVALID length!\n"); + return; + } + + if (tlv->len >= 2) { + // AC1 + PRINT_INDENT(level); + if ((tlv->value[1] & 0xC0) == 0x00) fprintf(f, "\tAC1: AAC (Transaction declined)\n"); + if ((tlv->value[1] & 0xC0) == 0x40) fprintf(f, "\tAC1: TC (Transaction approved)\n"); + if ((tlv->value[1] & 0xC0) == 0x80) fprintf(f, "\tAC1: ARQC (Online authorisation requested)\n"); + if ((tlv->value[1] & 0xC0) == 0xC0) fprintf(f, "\tAC1: RFU\n"); + // AC2 + PRINT_INDENT(level); + if ((tlv->value[1] & 0x30) == 0x00) fprintf(f, "\tAC2: AAC (Transaction declined)\n"); + if ((tlv->value[1] & 0x30) == 0x10) fprintf(f, "\tAC2: TC (Transaction approved)\n"); + if ((tlv->value[1] & 0x30) == 0x20) fprintf(f, "\tAC2: not requested (ARQC)\n"); + if ((tlv->value[1] & 0x30) == 0x30) fprintf(f, "\tAC2: RFU\n"); + } + if (tlv->len >= 3 && (tlv->value[2] >> 4)) { + PRINT_INDENT(level); + fprintf(f, "\tPIN try: %x\n", tlv->value[2] >> 4); + } + if (tlv->len >= 4 && (tlv->value[3] & 0x0F)) { + PRINT_INDENT(level); + fprintf(f, "\tIssuer discretionary bits: %x\n", tlv->value[3] & 0x0F); + } + if (tlv->len >= 5 && (tlv->value[4] >> 4)) { + PRINT_INDENT(level); + fprintf(f, "\tSuccessfully processed issuer script commands: %x\n", tlv->value[4] >> 4); + } + + // mask 0F 0F F0 0F + uint8_t data[20] = {0}; + memcpy(data, &tlv->value[1], tlv->len - 1); + data[0] &= 0x0F; + data[1] &= 0x0F; + data[2] &= 0xF0; + data[3] &= 0x0F; + const struct tlv bit_tlv = { + .tag = tlv->tag, + .len = tlv->len - 1, + .value = data, + }; + const struct emv_tag bit_tag = { + .tag = tag->tag, + .name = tag->name, + .type = EMV_TAG_BITMASK, + .data = EMV_CVR, + }; + + if (data[0] || data[1] || data[2] || data[3]) + emv_tag_dump_bitmask(&bit_tlv, &bit_tag, f, level); + + return; +} + +// EMV Book 3 +static void emv_tag_dump_cid(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level) { + if (!tlv || tlv->len < 1) { + PRINT_INDENT(level); + fprintf(f, "\tINVALID!\n"); + return; + } + + PRINT_INDENT(level); + if ((tlv->value[0] & 0xC0) == 0x00) fprintf(f, "\tAC1: AAC (Transaction declined)\n"); + if ((tlv->value[0] & 0xC0) == 0x40) fprintf(f, "\tAC1: TC (Transaction approved)\n"); + if ((tlv->value[0] & 0xC0) == 0x80) fprintf(f, "\tAC1: ARQC (Online authorisation requested)\n"); + if ((tlv->value[0] & 0xC0) == 0xC0) fprintf(f, "\tAC1: RFU\n"); + + if ((tlv->value[0] & 0x08) != 0x00) { + PRINT_INDENT(level); + fprintf(f, "\tAdvice required!\n"); + } + + if ((tlv->value[0] & 0x07) != 0x00) { + PRINT_INDENT(level); + fprintf(f, "\tReason/advice/referral code: "); + switch((tlv->value[0] & 0x07)) { + case 0: + fprintf(f, "No information given\n"); + break; + case 1: + fprintf(f, "Service not allowed\n"); + break; + case 2: + fprintf(f, "PIN Try Limit exceeded\n"); + break; + case 3: + fprintf(f, "Issuer authentication failed\n"); + break; + default: + fprintf(f, "\tRFU: %2x\n", (tlv->value[0] & 0x07)); + break; + } + } + + return; +} + +static void emv_tag_dump_cvm_list(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level) { uint32_t X, Y; int i; if (tlv->len < 10 || tlv->len % 2) { + PRINT_INDENT(level); fprintf(f, "\tINVALID!\n"); return; } @@ -337,7 +532,9 @@ static void emv_tag_dump_cvm_list(const struct tlv *tlv, const struct emv_tag *t X = emv_get_binary(tlv->value); Y = emv_get_binary(tlv->value + 4); + PRINT_INDENT(level); fprintf(f, "\tX: %d\n", X); + PRINT_INDENT(level); fprintf(f, "\tY: %d\n", Y); for (i = 8; i < tlv->len; i+= 2) { @@ -413,13 +610,27 @@ static void emv_tag_dump_cvm_list(const struct tlv *tlv, const struct emv_tag *t break; } + PRINT_INDENT(level); fprintf(f, "\t%02x %02x: '%s' '%s' and '%s' if this CVM is unsuccessful\n", tlv->value[i], tlv->value[i+1], method, condition, (tlv->value[i] & 0x40) ? "continue" : "fail"); } } -bool emv_tag_dump(const struct tlv *tlv, FILE *f) +static void emv_tag_dump_afl(const struct tlv *tlv, const struct emv_tag *tag, FILE *f, int level){ + if (tlv->len < 4 || tlv->len % 4) { + PRINT_INDENT(level); + fprintf(f, "\tINVALID!\n"); + return; + } + + for (int i = 0; i < tlv->len / 4; i++) { + PRINT_INDENT(level); + fprintf(f, "SFI[%02x] start:%02x end:%02x offline:%02x\n", tlv->value[i * 4 + 0] >> 3, tlv->value[i * 4 + 1], tlv->value[i * 4 + 2], tlv->value[i * 4 + 3]); + } +} + +bool emv_tag_dump(const struct tlv *tlv, FILE *f, int level) { if (!tlv) { fprintf(f, "NULL\n"); @@ -428,28 +639,45 @@ bool emv_tag_dump(const struct tlv *tlv, FILE *f) const struct emv_tag *tag = emv_get_tag(tlv); - fprintf(f, "--%2hx[%02zx] '%s':\n", tlv->tag, tlv->len, tag->name); + PRINT_INDENT(level); + fprintf(f, "--%2hx[%02zx] '%s':", tlv->tag, tlv->len, tag->name); switch (tag->type) { case EMV_TAG_GENERIC: + fprintf(f, "\n"); break; case EMV_TAG_BITMASK: - emv_tag_dump_bitmask(tlv, tag, f); + fprintf(f, "\n"); + emv_tag_dump_bitmask(tlv, tag, f, level); break; case EMV_TAG_DOL: - emv_tag_dump_dol(tlv, tag, f); + fprintf(f, "\n"); + emv_tag_dump_dol(tlv, tag, f, level); break; case EMV_TAG_CVM_LIST: - emv_tag_dump_cvm_list(tlv, tag, f); + fprintf(f, "\n"); + emv_tag_dump_cvm_list(tlv, tag, f, level); + break; + case EMV_TAG_AFL: + fprintf(f, "\n"); + emv_tag_dump_afl(tlv, tag, f, level); break; case EMV_TAG_STRING: - emv_tag_dump_string(tlv, tag, f); + emv_tag_dump_string(tlv, tag, f, level); break; case EMV_TAG_NUMERIC: - emv_tag_dump_numeric(tlv, tag, f); + emv_tag_dump_numeric(tlv, tag, f, level); break; case EMV_TAG_YYMMDD: - emv_tag_dump_yymmdd(tlv, tag, f); + emv_tag_dump_yymmdd(tlv, tag, f, level); + break; + case EMV_TAG_CVR: + fprintf(f, "\n"); + emv_tag_dump_cvr(tlv, tag, f, level); + break; + case EMV_TAG_CID: + fprintf(f, "\n"); + emv_tag_dump_cid(tlv, tag, f, level); break; };