From: pwpiwi Date: Thu, 1 Aug 2019 15:01:56 +0000 (-0400) Subject: 'hf 14a apdu' improvement X-Git-Url: http://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/commitdiff_plain/5a446cb212f7ff26f209da765b79b44011d41045 'hf 14a apdu' improvement (PR 249 by @merlokk on https://github.com/RfidResearchGroup/proxmark3) * add option to print APDU (if it can be decoded) * add option to cconstruct extended and normal size APDUs --- diff --git a/CHANGELOG.md b/CHANGELOG.md index 4640e72e..5210edbc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Fix `hf mf sim` - wrong access rights to write key B in trailer (@McEloff) ### Added +- Added to `hf 14a apdu` print apdu and compose apdu (@merlokk) - Added `hf 15 csetuid` - set UID on ISO-15693 Magic tags (t0m4) - Added `lf config s xxxx` option to allow skipping x samples before capture (marshmellow) - Added `lf em 4x05protect` to support changing protection blocks on em4x05 chips (marshmellow) diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 90032022..eba33947 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -921,20 +921,34 @@ int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool lea int CmdHF14AAPDU(const char *cmd) { uint8_t data[USB_CMD_DATA_SIZE]; int datalen = 0; + uint8_t header[5]; + int headerlen = 0; bool activateField = false; bool leaveSignalON = false; bool decodeTLV = false; + bool decodeAPDU = false; + bool makeAPDU = false; + bool extendedAPDU = false; + int le = 0; + int res = 0; CLIParserInit("hf 14a apdu", - "Sends an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol (T=CL)", - "Sample:\n\thf 14a apdu -st 00A404000E325041592E5359532E444446303100\n"); + "Sends an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol (T=CL). Works with all APDU types from ISO 7816-4:2013", + "Examples:\n\thf 14a apdu -st 00A404000E325041592E5359532E444446303100\n" + "\thf 14a apdu -sd 00A404000E325041592E5359532E444446303100 - decode APDU\n" + "\thf 14a apdu -sm 00A40400 325041592E5359532E4444463031 -l 256 - encode standard APDU\n" + "\thf 14a apdu -sm 00A40400 325041592E5359532E4444463031 -el 65536 - encode extended APDU\n"); void* argtable[] = { arg_param_begin, - arg_lit0("sS", "select", "activate field and select card"), - arg_lit0("kK", "keep", "leave the signal field ON after receive response"), - arg_lit0("tT", "tlv", "executes TLV decoder if it possible"), - arg_strx1(NULL, NULL, "", NULL), + arg_lit0("sS", "select", "activate field and select card"), + arg_lit0("kK", "keep", "leave the signal field ON after receive response"), + arg_lit0("tT", "tlv", "executes TLV decoder if it possible"), + arg_lit0("dD", "decapdu", "decode APDU request if it possible"), + arg_str0("mM", "make", "", "make APDU with head from this field and data from data field. Must be 4 bytes length: "), + arg_lit0("eE", "extended", "make extended length APDU (requires `-m`)"), + arg_int0("lL", "le", "", "Le APDU parameter (requires `-m`)"), + arg_strx1(NULL, NULL, "", "APDU (without `-m`), or data (with `-m`)"), arg_param_end }; CLIExecWithReturn(cmd, argtable, false); @@ -942,15 +956,71 @@ int CmdHF14AAPDU(const char *cmd) { activateField = arg_get_lit(1); leaveSignalON = arg_get_lit(2); decodeTLV = arg_get_lit(3); - // len = data + PCB(1b) + CRC(2b) - CLIGetHexBLessWithReturn(4, data, &datalen, 1 + 2); + decodeAPDU = arg_get_lit(4); + res = CLIParamHexToBuf(arg_get_str(5), header, sizeof(header), &headerlen); + makeAPDU = headerlen > 0; + if (res || (makeAPDU && headerlen != 4)) { + PrintAndLogEx(ERR, "header length must be exactly 4 bytes"); + CLIParserFree(); + return 1; + } + extendedAPDU = arg_get_lit(6); + le = arg_get_int_def(7, 0); + + if (makeAPDU) { + uint8_t apdudata[USB_CMD_DATA_SIZE] = {0}; + int apdudatalen = 0; + + CLIGetHexBLessWithReturn(8, apdudata, &apdudatalen, 1 + 2); + + APDUStruct apdu; + apdu.cla = header[0]; + apdu.ins = header[1]; + apdu.p1 = header[2]; + apdu.p2 = header[3]; + + apdu.lc = apdudatalen; + apdu.data = apdudata; + + apdu.extended_apdu = extendedAPDU; + apdu.le = le; + + if (APDUEncode(&apdu, data, &datalen)) { + PrintAndLogEx(ERR, "can't make apdu with provided parameters."); + CLIParserFree(); + return 2; + } + } else { + if (extendedAPDU) { + PrintAndLogEx(ERR, "`-e` without `-m`."); + CLIParserFree(); + return 3; + } + if (le > 0) { + PrintAndLogEx(ERR, "`-l` without `-m`."); + CLIParserFree(); + return 3; + } + + // len = data + PCB(1b) + CRC(2b) + CLIGetHexBLessWithReturn(8, data, &datalen, 1 + 2); + } CLIParserFree(); // PrintAndLog("---str [%d] %s", arg_get_str(4)->count, arg_get_str(4)->sval[0]); - PrintAndLog(">>>>[%s%s%s] %s", activateField ? "sel ": "", leaveSignalON ? "keep ": "", decodeTLV ? "TLV": "", sprint_hex(data, datalen)); + PrintAndLogEx(NORMAL, ">>>>[%s%s%s] %s", activateField ? "sel ": "", leaveSignalON ? "keep ": "", decodeTLV ? "TLV": "", sprint_hex(data, datalen)); + + if (decodeAPDU) { + APDUStruct apdu; + + if (APDUDecode(data, datalen, &apdu) == 0) + APDUPrint(apdu); + else + PrintAndLogEx(WARNING, "can't decode APDU."); + } - int res = ExchangeAPDU14a(data, datalen, activateField, leaveSignalON, data, USB_CMD_DATA_SIZE, &datalen); + res = ExchangeAPDU14a(data, datalen, activateField, leaveSignalON, data, USB_CMD_DATA_SIZE, &datalen); if (res) return res; diff --git a/client/emv/apduinfo.c b/client/emv/apduinfo.c index d14e3ff6..65d7404e 100644 --- a/client/emv/apduinfo.c +++ b/client/emv/apduinfo.c @@ -10,256 +10,261 @@ #include "apduinfo.h" +#include +#include +#include "ui.h" + + const APDUCode APDUCodeTable[] = { // ID Type Description - {"XXXX", APDUCODE_TYPE_NONE, ""}, // blank string - {"6---", APDUCODE_TYPE_ERROR, "Class not supported."}, - {"61--", APDUCODE_TYPE_INFO, "Response bytes still available"}, - {"61XX", APDUCODE_TYPE_INFO, "Command successfully executed; 'XX' bytes of data are available and can be requested using GET RESPONSE."}, - {"62--", APDUCODE_TYPE_WARNING, "State of non-volatile memory unchanged"}, - {"6200", APDUCODE_TYPE_WARNING, "No information given (NV-Ram not changed)"}, - {"6201", APDUCODE_TYPE_WARNING, "NV-Ram not changed 1."}, - {"6281", APDUCODE_TYPE_WARNING, "Part of returned data may be corrupted"}, - {"6282", APDUCODE_TYPE_WARNING, "End of file/record reached before reading Le bytes"}, - {"6283", APDUCODE_TYPE_WARNING, "Selected file invalidated"}, - {"6284", APDUCODE_TYPE_WARNING, "Selected file is not valid. FCI not formated according to ISO"}, - {"6285", APDUCODE_TYPE_WARNING, "No input data available from a sensor on the card. No Purse Engine enslaved for R3bc"}, - {"62A2", APDUCODE_TYPE_WARNING, "Wrong R-MAC"}, - {"62A4", APDUCODE_TYPE_WARNING, "Card locked (during reset( ))"}, - {"62CX", APDUCODE_TYPE_WARNING, "Counter with value x (command dependent)"}, - {"62F1", APDUCODE_TYPE_WARNING, "Wrong C-MAC"}, - {"62F3", APDUCODE_TYPE_WARNING, "Internal reset"}, - {"62F5", APDUCODE_TYPE_WARNING, "Default agent locked"}, - {"62F7", APDUCODE_TYPE_WARNING, "Cardholder locked"}, - {"62F8", APDUCODE_TYPE_WARNING, "Basement is current agent"}, - {"62F9", APDUCODE_TYPE_WARNING, "CALC Key Set not unblocked"}, - {"62FX", APDUCODE_TYPE_WARNING, "-"}, - {"62XX", APDUCODE_TYPE_WARNING, "RFU"}, - {"63--", APDUCODE_TYPE_WARNING, "State of non-volatile memory changed"}, - {"6300", APDUCODE_TYPE_WARNING, "No information given (NV-Ram changed)"}, - {"6381", APDUCODE_TYPE_WARNING, "File filled up by the last write. Loading/updating is not allowed."}, - {"6382", APDUCODE_TYPE_WARNING, "Card key not supported."}, - {"6383", APDUCODE_TYPE_WARNING, "Reader key not supported."}, - {"6384", APDUCODE_TYPE_WARNING, "Plaintext transmission not supported."}, - {"6385", APDUCODE_TYPE_WARNING, "Secured transmission not supported."}, - {"6386", APDUCODE_TYPE_WARNING, "Volatile memory is not available."}, - {"6387", APDUCODE_TYPE_WARNING, "Non-volatile memory is not available."}, - {"6388", APDUCODE_TYPE_WARNING, "Key number not valid."}, - {"6389", APDUCODE_TYPE_WARNING, "Key length is not correct."}, - {"63C0", APDUCODE_TYPE_WARNING, "Verify fail, no try left."}, - {"63C1", APDUCODE_TYPE_WARNING, "Verify fail, 1 try left."}, - {"63C2", APDUCODE_TYPE_WARNING, "Verify fail, 2 tries left."}, - {"63C3", APDUCODE_TYPE_WARNING, "Verify fail, 3 tries left."}, - {"63CX", APDUCODE_TYPE_WARNING, "The counter has reached the value 'x' (0 = x = 15) (command dependent)."}, - {"63F1", APDUCODE_TYPE_WARNING, "More data expected."}, - {"63F2", APDUCODE_TYPE_WARNING, "More data expected and proactive command pending."}, - {"63FX", APDUCODE_TYPE_WARNING, "-"}, - {"63XX", APDUCODE_TYPE_WARNING, "RFU"}, - {"64--", APDUCODE_TYPE_ERROR, "State of non-volatile memory unchanged"}, - {"6400", APDUCODE_TYPE_ERROR, "No information given (NV-Ram not changed)"}, - {"6401", APDUCODE_TYPE_ERROR, "Command timeout. Immediate response required by the card."}, - {"64XX", APDUCODE_TYPE_ERROR, "RFU"}, - {"65--", APDUCODE_TYPE_ERROR, "State of non-volatile memory changed"}, - {"6500", APDUCODE_TYPE_ERROR, "No information given"}, - {"6501", APDUCODE_TYPE_ERROR, "Write error. Memory failure. There have been problems in writing or reading the EEPROM. Other hardware problems may also bring this error."}, - {"6581", APDUCODE_TYPE_ERROR, "Memory failure"}, - {"65FX", APDUCODE_TYPE_ERROR, "-"}, - {"65XX", APDUCODE_TYPE_ERROR, "RFU"}, - {"66--", APDUCODE_TYPE_SECURITY, " "}, - {"6600", APDUCODE_TYPE_SECURITY, "Error while receiving (timeout)"}, - {"6601", APDUCODE_TYPE_SECURITY, "Error while receiving (character parity error)"}, - {"6602", APDUCODE_TYPE_SECURITY, "Wrong checksum"}, - {"6603", APDUCODE_TYPE_SECURITY, "The current DF file without FCI"}, - {"6604", APDUCODE_TYPE_SECURITY, "No SF or KF under the current DF"}, - {"6669", APDUCODE_TYPE_SECURITY, "Incorrect Encryption/Decryption Padding"}, - {"66XX", APDUCODE_TYPE_SECURITY, "-"}, - {"67--", APDUCODE_TYPE_ERROR, " "}, - {"6700", APDUCODE_TYPE_ERROR, "Wrong length"}, - {"67XX", APDUCODE_TYPE_ERROR, "length incorrect (procedure)(ISO 7816-3)"}, - {"68--", APDUCODE_TYPE_ERROR, "Functions in CLA not supported"}, - {"6800", APDUCODE_TYPE_ERROR, "No information given (The request function is not supported by the card)"}, - {"6881", APDUCODE_TYPE_ERROR, "Logical channel not supported"}, - {"6882", APDUCODE_TYPE_ERROR, "Secure messaging not supported"}, - {"6883", APDUCODE_TYPE_ERROR, "Last command of the chain expected"}, - {"6884", APDUCODE_TYPE_ERROR, "Command chaining not supported"}, - {"68FX", APDUCODE_TYPE_ERROR, "-"}, - {"68XX", APDUCODE_TYPE_ERROR, "RFU"}, - {"69--", APDUCODE_TYPE_ERROR, "Command not allowed"}, - {"6900", APDUCODE_TYPE_ERROR, "No information given (Command not allowed)"}, - {"6901", APDUCODE_TYPE_ERROR, "Command not accepted (inactive state)"}, - {"6981", APDUCODE_TYPE_ERROR, "Command incompatible with file structure"}, - {"6982", APDUCODE_TYPE_ERROR, "Security condition not satisfied."}, - {"6983", APDUCODE_TYPE_ERROR, "Authentication method blocked"}, - {"6984", APDUCODE_TYPE_ERROR, "Referenced data reversibly blocked (invalidated)"}, - {"6985", APDUCODE_TYPE_ERROR, "Conditions of use not satisfied."}, - {"6986", APDUCODE_TYPE_ERROR, "Command not allowed (no current EF)"}, - {"6987", APDUCODE_TYPE_ERROR, "Expected secure messaging (SM) object missing"}, - {"6988", APDUCODE_TYPE_ERROR, "Incorrect secure messaging (SM) data object"}, - {"698D", APDUCODE_TYPE_NONE, "Reserved"}, - {"6996", APDUCODE_TYPE_ERROR, "Data must be updated again"}, - {"69E1", APDUCODE_TYPE_ERROR, "POL1 of the currently Enabled Profile prevents this action."}, - {"69F0", APDUCODE_TYPE_ERROR, "Permission Denied"}, - {"69F1", APDUCODE_TYPE_ERROR, "Permission Denied - Missing Privilege"}, - {"69FX", APDUCODE_TYPE_ERROR, "-"}, - {"69XX", APDUCODE_TYPE_ERROR, "RFU"}, - {"6A--", APDUCODE_TYPE_ERROR, "Wrong parameter(s) P1-P2"}, - {"6A00", APDUCODE_TYPE_ERROR, "No information given (Bytes P1 and/or P2 are incorrect)"}, - {"6A80", APDUCODE_TYPE_ERROR, "The parameters in the data field are incorrect."}, - {"6A81", APDUCODE_TYPE_ERROR, "Function not supported"}, - {"6A82", APDUCODE_TYPE_ERROR, "File not found"}, - {"6A83", APDUCODE_TYPE_ERROR, "Record not found"}, - {"6A84", APDUCODE_TYPE_ERROR, "There is insufficient memory space in record or file"}, - {"6A85", APDUCODE_TYPE_ERROR, "Lc inconsistent with TLV structure"}, - {"6A86", APDUCODE_TYPE_ERROR, "Incorrect P1 or P2 parameter."}, - {"6A87", APDUCODE_TYPE_ERROR, "Lc inconsistent with P1-P2"}, - {"6A88", APDUCODE_TYPE_ERROR, "Referenced data not found"}, - {"6A89", APDUCODE_TYPE_ERROR, "File already exists"}, - {"6A8A", APDUCODE_TYPE_ERROR, "DF name already exists."}, - {"6AF0", APDUCODE_TYPE_ERROR, "Wrong parameter value"}, - {"6AFX", APDUCODE_TYPE_ERROR, "-"}, - {"6AXX", APDUCODE_TYPE_ERROR, "RFU"}, - {"6B--", APDUCODE_TYPE_ERROR, " "}, - {"6B00", APDUCODE_TYPE_ERROR, "Wrong parameter(s) P1-P2"}, - {"6BXX", APDUCODE_TYPE_ERROR, "Reference incorrect (procedure byte), (ISO 7816-3)"}, - {"6C--", APDUCODE_TYPE_ERROR, "Wrong length Le"}, - {"6C00", APDUCODE_TYPE_ERROR, "Incorrect P3 length."}, - {"6CXX", APDUCODE_TYPE_ERROR, "Bad length value in Le; 'xx' is the correct exact Le"}, - {"6D--", APDUCODE_TYPE_ERROR, " "}, - {"6D00", APDUCODE_TYPE_ERROR, "Instruction code not supported or invalid"}, - {"6DXX", APDUCODE_TYPE_ERROR, "Instruction code not programmed or invalid (procedure byte), (ISO 7816-3)"}, - {"6E--", APDUCODE_TYPE_ERROR, " "}, - {"6E00", APDUCODE_TYPE_ERROR, "Class not supported"}, - {"6EXX", APDUCODE_TYPE_ERROR, "Instruction class not supported (procedure byte), (ISO 7816-3)"}, - {"6F--", APDUCODE_TYPE_ERROR, "Internal exception"}, - {"6F00", APDUCODE_TYPE_ERROR, "Command aborted - more exact diagnosis not possible (e.g., operating system error)."}, - {"6FFF", APDUCODE_TYPE_ERROR, "Card dead (overuse, ...)"}, - {"6FXX", APDUCODE_TYPE_ERROR, "No precise diagnosis (procedure byte), (ISO 7816-3)"}, - {"9---", APDUCODE_TYPE_NONE, ""}, - {"9000", APDUCODE_TYPE_INFO, "Command successfully executed (OK)."}, - {"9004", APDUCODE_TYPE_WARNING, "PIN not succesfully verified, 3 or more PIN tries left"}, - {"9008", APDUCODE_TYPE_NONE, "Key/file not found"}, - {"9080", APDUCODE_TYPE_WARNING, "Unblock Try Counter has reached zero"}, - {"9100", APDUCODE_TYPE_NONE, "OK"}, - {"9101", APDUCODE_TYPE_NONE, "States.activity, States.lock Status or States.lockable has wrong value"}, - {"9102", APDUCODE_TYPE_NONE, "Transaction number reached its limit"}, - {"910C", APDUCODE_TYPE_NONE, "No changes"}, - {"910E", APDUCODE_TYPE_NONE, "Insufficient NV-Memory to complete command"}, - {"911C", APDUCODE_TYPE_NONE, "Command code not supported"}, - {"911E", APDUCODE_TYPE_NONE, "CRC or MAC does not match data"}, - {"9140", APDUCODE_TYPE_NONE, "Invalid key number specified"}, - {"917E", APDUCODE_TYPE_NONE, "Length of command string invalid"}, - {"919D", APDUCODE_TYPE_NONE, "Not allow the requested command"}, - {"919E", APDUCODE_TYPE_NONE, "Value of the parameter invalid"}, - {"91A0", APDUCODE_TYPE_NONE, "Requested AID not present on PICC"}, - {"91A1", APDUCODE_TYPE_NONE, "Unrecoverable error within application"}, - {"91AE", APDUCODE_TYPE_NONE, "Authentication status does not allow the requested command"}, - {"91AF", APDUCODE_TYPE_NONE, "Additional data frame is expected to be sent"}, - {"91BE", APDUCODE_TYPE_NONE, "Out of boundary"}, - {"91C1", APDUCODE_TYPE_NONE, "Unrecoverable error within PICC"}, - {"91CA", APDUCODE_TYPE_NONE, "Previous Command was not fully completed"}, - {"91CD", APDUCODE_TYPE_NONE, "PICC was disabled by an unrecoverable error"}, - {"91CE", APDUCODE_TYPE_NONE, "Number of Applications limited to 28"}, - {"91DE", APDUCODE_TYPE_NONE, "File or application already exists"}, - {"91EE", APDUCODE_TYPE_NONE, "Could not complete NV-write operation due to loss of power"}, - {"91F0", APDUCODE_TYPE_NONE, "Specified file number does not exist"}, - {"91F1", APDUCODE_TYPE_NONE, "Unrecoverable error within file"}, - {"920x", APDUCODE_TYPE_INFO, "Writing to EEPROM successful after 'x' attempts."}, - {"9210", APDUCODE_TYPE_ERROR, "Insufficient memory. No more storage available."}, - {"9240", APDUCODE_TYPE_ERROR, "Writing to EEPROM not successful."}, - {"9301", APDUCODE_TYPE_NONE, "Integrity error"}, - {"9302", APDUCODE_TYPE_NONE, "Candidate S2 invalid"}, - {"9303", APDUCODE_TYPE_ERROR, "Application is permanently locked"}, - {"9400", APDUCODE_TYPE_ERROR, "No EF selected."}, - {"9401", APDUCODE_TYPE_NONE, "Candidate currency code does not match purse currency"}, - {"9402", APDUCODE_TYPE_NONE, "Candidate amount too high"}, - {"9402", APDUCODE_TYPE_ERROR, "Address range exceeded."}, - {"9403", APDUCODE_TYPE_NONE, "Candidate amount too low"}, - {"9404", APDUCODE_TYPE_ERROR, "FID not found, record not found or comparison pattern not found."}, - {"9405", APDUCODE_TYPE_NONE, "Problems in the data field"}, - {"9406", APDUCODE_TYPE_ERROR, "Required MAC unavailable"}, - {"9407", APDUCODE_TYPE_NONE, "Bad currency : purse engine has no slot with R3bc currency"}, - {"9408", APDUCODE_TYPE_NONE, "R3bc currency not supported in purse engine"}, - {"9408", APDUCODE_TYPE_ERROR, "Selected file type does not match command."}, - {"9580", APDUCODE_TYPE_NONE, "Bad sequence"}, - {"9681", APDUCODE_TYPE_NONE, "Slave not found"}, - {"9700", APDUCODE_TYPE_NONE, "PIN blocked and Unblock Try Counter is 1 or 2"}, - {"9702", APDUCODE_TYPE_NONE, "Main keys are blocked"}, - {"9704", APDUCODE_TYPE_NONE, "PIN not succesfully verified, 3 or more PIN tries left"}, - {"9784", APDUCODE_TYPE_NONE, "Base key"}, - {"9785", APDUCODE_TYPE_NONE, "Limit exceeded - C-MAC key"}, - {"9786", APDUCODE_TYPE_NONE, "SM error - Limit exceeded - R-MAC key"}, - {"9787", APDUCODE_TYPE_NONE, "Limit exceeded - sequence counter"}, - {"9788", APDUCODE_TYPE_NONE, "Limit exceeded - R-MAC length"}, - {"9789", APDUCODE_TYPE_NONE, "Service not available"}, - {"9802", APDUCODE_TYPE_ERROR, "No PIN defined."}, - {"9804", APDUCODE_TYPE_ERROR, "Access conditions not satisfied, authentication failed."}, - {"9835", APDUCODE_TYPE_ERROR, "ASK RANDOM or GIVE RANDOM not executed."}, - {"9840", APDUCODE_TYPE_ERROR, "PIN verification not successful."}, - {"9850", APDUCODE_TYPE_ERROR, "INCREASE or DECREASE could not be executed because a limit has been reached."}, - {"9862", APDUCODE_TYPE_ERROR, "Authentication Error, application specific (incorrect MAC)"}, - {"9900", APDUCODE_TYPE_NONE, "1 PIN try left"}, - {"9904", APDUCODE_TYPE_NONE, "PIN not succesfully verified, 1 PIN try left"}, - {"9985", APDUCODE_TYPE_NONE, "Wrong status - Cardholder lock"}, - {"9986", APDUCODE_TYPE_ERROR, "Missing privilege"}, - {"9987", APDUCODE_TYPE_NONE, "PIN is not installed"}, - {"9988", APDUCODE_TYPE_NONE, "Wrong status - R-MAC state"}, - {"9A00", APDUCODE_TYPE_NONE, "2 PIN try left"}, - {"9A04", APDUCODE_TYPE_NONE, "PIN not succesfully verified, 2 PIN try left"}, - {"9A71", APDUCODE_TYPE_NONE, "Wrong parameter value - Double agent AID"}, - {"9A72", APDUCODE_TYPE_NONE, "Wrong parameter value - Double agent Type"}, - {"9D05", APDUCODE_TYPE_ERROR, "Incorrect certificate type"}, - {"9D07", APDUCODE_TYPE_ERROR, "Incorrect session data size"}, - {"9D08", APDUCODE_TYPE_ERROR, "Incorrect DIR file record size"}, - {"9D09", APDUCODE_TYPE_ERROR, "Incorrect FCI record size"}, - {"9D0A", APDUCODE_TYPE_ERROR, "Incorrect code size"}, - {"9D10", APDUCODE_TYPE_ERROR, "Insufficient memory to load application"}, - {"9D11", APDUCODE_TYPE_ERROR, "Invalid AID"}, - {"9D12", APDUCODE_TYPE_ERROR, "Duplicate AID"}, - {"9D13", APDUCODE_TYPE_ERROR, "Application previously loaded"}, - {"9D14", APDUCODE_TYPE_ERROR, "Application history list full"}, - {"9D15", APDUCODE_TYPE_ERROR, "Application not open"}, - {"9D17", APDUCODE_TYPE_ERROR, "Invalid offset"}, - {"9D18", APDUCODE_TYPE_ERROR, "Application already loaded"}, - {"9D19", APDUCODE_TYPE_ERROR, "Invalid certificate"}, - {"9D1A", APDUCODE_TYPE_ERROR, "Invalid signature"}, - {"9D1B", APDUCODE_TYPE_ERROR, "Invalid KTU"}, - {"9D1D", APDUCODE_TYPE_ERROR, "MSM controls not set"}, - {"9D1E", APDUCODE_TYPE_ERROR, "Application signature does not exist"}, - {"9D1F", APDUCODE_TYPE_ERROR, "KTU does not exist"}, - {"9D20", APDUCODE_TYPE_ERROR, "Application not loaded"}, - {"9D21", APDUCODE_TYPE_ERROR, "Invalid Open command data length"}, - {"9D30", APDUCODE_TYPE_ERROR, "Check data parameter is incorrect (invalid start address)"}, - {"9D31", APDUCODE_TYPE_ERROR, "Check data parameter is incorrect (invalid length)"}, - {"9D32", APDUCODE_TYPE_ERROR, "Check data parameter is incorrect (illegal memory check area)"}, - {"9D40", APDUCODE_TYPE_ERROR, "Invalid MSM Controls ciphertext"}, - {"9D41", APDUCODE_TYPE_ERROR, "MSM controls already set"}, - {"9D42", APDUCODE_TYPE_ERROR, "Set MSM Controls data length less than 2 bytes"}, - {"9D43", APDUCODE_TYPE_ERROR, "Invalid MSM Controls data length"}, - {"9D44", APDUCODE_TYPE_ERROR, "Excess MSM Controls ciphertext"}, - {"9D45", APDUCODE_TYPE_ERROR, "Verification of MSM Controls data failed"}, - {"9D50", APDUCODE_TYPE_ERROR, "Invalid MCD Issuer production ID"}, - {"9D51", APDUCODE_TYPE_ERROR, "Invalid MCD Issuer ID"}, - {"9D52", APDUCODE_TYPE_ERROR, "Invalid set MSM controls data date"}, - {"9D53", APDUCODE_TYPE_ERROR, "Invalid MCD number"}, - {"9D54", APDUCODE_TYPE_ERROR, "Reserved field error"}, - {"9D55", APDUCODE_TYPE_ERROR, "Reserved field error"}, - {"9D56", APDUCODE_TYPE_ERROR, "Reserved field error"}, - {"9D57", APDUCODE_TYPE_ERROR, "Reserved field error"}, - {"9D60", APDUCODE_TYPE_ERROR, "MAC verification failed"}, - {"9D61", APDUCODE_TYPE_ERROR, "Maximum number of unblocks reached"}, - {"9D62", APDUCODE_TYPE_ERROR, "Card was not blocked"}, - {"9D63", APDUCODE_TYPE_ERROR, "Crypto functions not available"}, - {"9D64", APDUCODE_TYPE_ERROR, "No application loaded"}, - {"9E00", APDUCODE_TYPE_NONE, "PIN not installed"}, - {"9E04", APDUCODE_TYPE_NONE, "PIN not succesfully verified, PIN not installed"}, - {"9F00", APDUCODE_TYPE_NONE, "PIN blocked and Unblock Try Counter is 3"}, - {"9F04", APDUCODE_TYPE_NONE, "PIN not succesfully verified, PIN blocked and Unblock Try Counter is 3"}, - {"9FXX", APDUCODE_TYPE_NONE, "Command successfully executed; 'xx' bytes of data are available and can be requested using GET RESPONSE."}, - {"9XXX", APDUCODE_TYPE_NONE, "Application related status, (ISO 7816-3)"} + {"XXXX", APDUCODE_TYPE_NONE, ""}, // blank string + {"6---", APDUCODE_TYPE_ERROR, "Class not supported."}, + {"61--", APDUCODE_TYPE_INFO, "Response bytes still available"}, + {"61XX", APDUCODE_TYPE_INFO, "Command successfully executed; 'XX' bytes of data are available and can be requested using GET RESPONSE."}, + {"62--", APDUCODE_TYPE_WARNING, "State of non-volatile memory unchanged"}, + {"6200", APDUCODE_TYPE_WARNING, "No information given (NV-Ram not changed)"}, + {"6201", APDUCODE_TYPE_WARNING, "NV-Ram not changed 1."}, + {"6281", APDUCODE_TYPE_WARNING, "Part of returned data may be corrupted"}, + {"6282", APDUCODE_TYPE_WARNING, "End of file/record reached before reading Le bytes"}, + {"6283", APDUCODE_TYPE_WARNING, "Selected file invalidated"}, + {"6284", APDUCODE_TYPE_WARNING, "Selected file is not valid. FCI not formated according to ISO"}, + {"6285", APDUCODE_TYPE_WARNING, "No input data available from a sensor on the card. No Purse Engine enslaved for R3bc"}, + {"62A2", APDUCODE_TYPE_WARNING, "Wrong R-MAC"}, + {"62A4", APDUCODE_TYPE_WARNING, "Card locked (during reset( ))"}, + {"62CX", APDUCODE_TYPE_WARNING, "Counter with value x (command dependent)"}, + {"62F1", APDUCODE_TYPE_WARNING, "Wrong C-MAC"}, + {"62F3", APDUCODE_TYPE_WARNING, "Internal reset"}, + {"62F5", APDUCODE_TYPE_WARNING, "Default agent locked"}, + {"62F7", APDUCODE_TYPE_WARNING, "Cardholder locked"}, + {"62F8", APDUCODE_TYPE_WARNING, "Basement is current agent"}, + {"62F9", APDUCODE_TYPE_WARNING, "CALC Key Set not unblocked"}, + {"62FX", APDUCODE_TYPE_WARNING, "-"}, + {"62XX", APDUCODE_TYPE_WARNING, "RFU"}, + {"63--", APDUCODE_TYPE_WARNING, "State of non-volatile memory changed"}, + {"6300", APDUCODE_TYPE_WARNING, "No information given (NV-Ram changed)"}, + {"6381", APDUCODE_TYPE_WARNING, "File filled up by the last write. Loading/updating is not allowed."}, + {"6382", APDUCODE_TYPE_WARNING, "Card key not supported."}, + {"6383", APDUCODE_TYPE_WARNING, "Reader key not supported."}, + {"6384", APDUCODE_TYPE_WARNING, "Plaintext transmission not supported."}, + {"6385", APDUCODE_TYPE_WARNING, "Secured transmission not supported."}, + {"6386", APDUCODE_TYPE_WARNING, "Volatile memory is not available."}, + {"6387", APDUCODE_TYPE_WARNING, "Non-volatile memory is not available."}, + {"6388", APDUCODE_TYPE_WARNING, "Key number not valid."}, + {"6389", APDUCODE_TYPE_WARNING, "Key length is not correct."}, + {"63C0", APDUCODE_TYPE_WARNING, "Verify fail, no try left."}, + {"63C1", APDUCODE_TYPE_WARNING, "Verify fail, 1 try left."}, + {"63C2", APDUCODE_TYPE_WARNING, "Verify fail, 2 tries left."}, + {"63C3", APDUCODE_TYPE_WARNING, "Verify fail, 3 tries left."}, + {"63CX", APDUCODE_TYPE_WARNING, "The counter has reached the value 'x' (0 = x = 15) (command dependent)."}, + {"63F1", APDUCODE_TYPE_WARNING, "More data expected."}, + {"63F2", APDUCODE_TYPE_WARNING, "More data expected and proactive command pending."}, + {"63FX", APDUCODE_TYPE_WARNING, "-"}, + {"63XX", APDUCODE_TYPE_WARNING, "RFU"}, + {"64--", APDUCODE_TYPE_ERROR, "State of non-volatile memory unchanged"}, + {"6400", APDUCODE_TYPE_ERROR, "No information given (NV-Ram not changed)"}, + {"6401", APDUCODE_TYPE_ERROR, "Command timeout. Immediate response required by the card."}, + {"64XX", APDUCODE_TYPE_ERROR, "RFU"}, + {"65--", APDUCODE_TYPE_ERROR, "State of non-volatile memory changed"}, + {"6500", APDUCODE_TYPE_ERROR, "No information given"}, + {"6501", APDUCODE_TYPE_ERROR, "Write error. Memory failure. There have been problems in writing or reading the EEPROM. Other hardware problems may also bring this error."}, + {"6581", APDUCODE_TYPE_ERROR, "Memory failure"}, + {"65FX", APDUCODE_TYPE_ERROR, "-"}, + {"65XX", APDUCODE_TYPE_ERROR, "RFU"}, + {"66--", APDUCODE_TYPE_SECURITY, " "}, + {"6600", APDUCODE_TYPE_SECURITY, "Error while receiving (timeout)"}, + {"6601", APDUCODE_TYPE_SECURITY, "Error while receiving (character parity error)"}, + {"6602", APDUCODE_TYPE_SECURITY, "Wrong checksum"}, + {"6603", APDUCODE_TYPE_SECURITY, "The current DF file without FCI"}, + {"6604", APDUCODE_TYPE_SECURITY, "No SF or KF under the current DF"}, + {"6669", APDUCODE_TYPE_SECURITY, "Incorrect Encryption/Decryption Padding"}, + {"66XX", APDUCODE_TYPE_SECURITY, "-"}, + {"67--", APDUCODE_TYPE_ERROR, " "}, + {"6700", APDUCODE_TYPE_ERROR, "Wrong length"}, + {"67XX", APDUCODE_TYPE_ERROR, "length incorrect (procedure)(ISO 7816-3)"}, + {"68--", APDUCODE_TYPE_ERROR, "Functions in CLA not supported"}, + {"6800", APDUCODE_TYPE_ERROR, "No information given (The request function is not supported by the card)"}, + {"6881", APDUCODE_TYPE_ERROR, "Logical channel not supported"}, + {"6882", APDUCODE_TYPE_ERROR, "Secure messaging not supported"}, + {"6883", APDUCODE_TYPE_ERROR, "Last command of the chain expected"}, + {"6884", APDUCODE_TYPE_ERROR, "Command chaining not supported"}, + {"68FX", APDUCODE_TYPE_ERROR, "-"}, + {"68XX", APDUCODE_TYPE_ERROR, "RFU"}, + {"69--", APDUCODE_TYPE_ERROR, "Command not allowed"}, + {"6900", APDUCODE_TYPE_ERROR, "No information given (Command not allowed)"}, + {"6901", APDUCODE_TYPE_ERROR, "Command not accepted (inactive state)"}, + {"6981", APDUCODE_TYPE_ERROR, "Command incompatible with file structure"}, + {"6982", APDUCODE_TYPE_ERROR, "Security condition not satisfied."}, + {"6983", APDUCODE_TYPE_ERROR, "Authentication method blocked"}, + {"6984", APDUCODE_TYPE_ERROR, "Referenced data reversibly blocked (invalidated)"}, + {"6985", APDUCODE_TYPE_ERROR, "Conditions of use not satisfied."}, + {"6986", APDUCODE_TYPE_ERROR, "Command not allowed (no current EF)"}, + {"6987", APDUCODE_TYPE_ERROR, "Expected secure messaging (SM) object missing"}, + {"6988", APDUCODE_TYPE_ERROR, "Incorrect secure messaging (SM) data object"}, + {"698D", APDUCODE_TYPE_NONE, "Reserved"}, + {"6996", APDUCODE_TYPE_ERROR, "Data must be updated again"}, + {"69E1", APDUCODE_TYPE_ERROR, "POL1 of the currently Enabled Profile prevents this action."}, + {"69F0", APDUCODE_TYPE_ERROR, "Permission Denied"}, + {"69F1", APDUCODE_TYPE_ERROR, "Permission Denied - Missing Privilege"}, + {"69FX", APDUCODE_TYPE_ERROR, "-"}, + {"69XX", APDUCODE_TYPE_ERROR, "RFU"}, + {"6A--", APDUCODE_TYPE_ERROR, "Wrong parameter(s) P1-P2"}, + {"6A00", APDUCODE_TYPE_ERROR, "No information given (Bytes P1 and/or P2 are incorrect)"}, + {"6A80", APDUCODE_TYPE_ERROR, "The parameters in the data field are incorrect."}, + {"6A81", APDUCODE_TYPE_ERROR, "Function not supported"}, + {"6A82", APDUCODE_TYPE_ERROR, "File not found"}, + {"6A83", APDUCODE_TYPE_ERROR, "Record not found"}, + {"6A84", APDUCODE_TYPE_ERROR, "There is insufficient memory space in record or file"}, + {"6A85", APDUCODE_TYPE_ERROR, "Lc inconsistent with TLV structure"}, + {"6A86", APDUCODE_TYPE_ERROR, "Incorrect P1 or P2 parameter."}, + {"6A87", APDUCODE_TYPE_ERROR, "Lc inconsistent with P1-P2"}, + {"6A88", APDUCODE_TYPE_ERROR, "Referenced data not found"}, + {"6A89", APDUCODE_TYPE_ERROR, "File already exists"}, + {"6A8A", APDUCODE_TYPE_ERROR, "DF name already exists."}, + {"6AF0", APDUCODE_TYPE_ERROR, "Wrong parameter value"}, + {"6AFX", APDUCODE_TYPE_ERROR, "-"}, + {"6AXX", APDUCODE_TYPE_ERROR, "RFU"}, + {"6B--", APDUCODE_TYPE_ERROR, " "}, + {"6B00", APDUCODE_TYPE_ERROR, "Wrong parameter(s) P1-P2"}, + {"6BXX", APDUCODE_TYPE_ERROR, "Reference incorrect (procedure byte), (ISO 7816-3)"}, + {"6C--", APDUCODE_TYPE_ERROR, "Wrong length Le"}, + {"6C00", APDUCODE_TYPE_ERROR, "Incorrect P3 length."}, + {"6CXX", APDUCODE_TYPE_ERROR, "Bad length value in Le; 'xx' is the correct exact Le"}, + {"6D--", APDUCODE_TYPE_ERROR, " "}, + {"6D00", APDUCODE_TYPE_ERROR, "Instruction code not supported or invalid"}, + {"6DXX", APDUCODE_TYPE_ERROR, "Instruction code not programmed or invalid (procedure byte), (ISO 7816-3)"}, + {"6E--", APDUCODE_TYPE_ERROR, " "}, + {"6E00", APDUCODE_TYPE_ERROR, "Class not supported"}, + {"6EXX", APDUCODE_TYPE_ERROR, "Instruction class not supported (procedure byte), (ISO 7816-3)"}, + {"6F--", APDUCODE_TYPE_ERROR, "Internal exception"}, + {"6F00", APDUCODE_TYPE_ERROR, "Command aborted - more exact diagnosis not possible (e.g., operating system error)."}, + {"6FFF", APDUCODE_TYPE_ERROR, "Card dead (overuse)"}, + {"6FXX", APDUCODE_TYPE_ERROR, "No precise diagnosis (procedure byte), (ISO 7816-3)"}, + {"9---", APDUCODE_TYPE_NONE, ""}, + {"9000", APDUCODE_TYPE_INFO, "Command successfully executed (OK)."}, + {"9004", APDUCODE_TYPE_WARNING, "PIN not successfully verified, 3 or more PIN tries left"}, + {"9008", APDUCODE_TYPE_NONE, "Key/file not found"}, + {"9080", APDUCODE_TYPE_WARNING, "Unblock Try Counter has reached zero"}, + {"9100", APDUCODE_TYPE_NONE, "OK"}, + {"9101", APDUCODE_TYPE_NONE, "States.activity, States.lock Status or States.lockable has wrong value"}, + {"9102", APDUCODE_TYPE_NONE, "Transaction number reached its limit"}, + {"910C", APDUCODE_TYPE_NONE, "No changes"}, + {"910E", APDUCODE_TYPE_NONE, "Insufficient NV-Memory to complete command"}, + {"911C", APDUCODE_TYPE_NONE, "Command code not supported"}, + {"911E", APDUCODE_TYPE_NONE, "CRC or MAC does not match data"}, + {"9140", APDUCODE_TYPE_NONE, "Invalid key number specified"}, + {"917E", APDUCODE_TYPE_NONE, "Length of command string invalid"}, + {"919D", APDUCODE_TYPE_NONE, "Not allow the requested command"}, + {"919E", APDUCODE_TYPE_NONE, "Value of the parameter invalid"}, + {"91A0", APDUCODE_TYPE_NONE, "Requested AID not present on PICC"}, + {"91A1", APDUCODE_TYPE_NONE, "Unrecoverable error within application"}, + {"91AE", APDUCODE_TYPE_NONE, "Authentication status does not allow the requested command"}, + {"91AF", APDUCODE_TYPE_NONE, "Additional data frame is expected to be sent"}, + {"91BE", APDUCODE_TYPE_NONE, "Out of boundary"}, + {"91C1", APDUCODE_TYPE_NONE, "Unrecoverable error within PICC"}, + {"91CA", APDUCODE_TYPE_NONE, "Previous Command was not fully completed"}, + {"91CD", APDUCODE_TYPE_NONE, "PICC was disabled by an unrecoverable error"}, + {"91CE", APDUCODE_TYPE_NONE, "Number of Applications limited to 28"}, + {"91DE", APDUCODE_TYPE_NONE, "File or application already exists"}, + {"91EE", APDUCODE_TYPE_NONE, "Could not complete NV-write operation due to loss of power"}, + {"91F0", APDUCODE_TYPE_NONE, "Specified file number does not exist"}, + {"91F1", APDUCODE_TYPE_NONE, "Unrecoverable error within file"}, + {"920x", APDUCODE_TYPE_INFO, "Writing to EEPROM successful after 'x' attempts."}, + {"9210", APDUCODE_TYPE_ERROR, "Insufficient memory. No more storage available."}, + {"9240", APDUCODE_TYPE_ERROR, "Writing to EEPROM not successful."}, + {"9301", APDUCODE_TYPE_NONE, "Integrity error"}, + {"9302", APDUCODE_TYPE_NONE, "Candidate S2 invalid"}, + {"9303", APDUCODE_TYPE_ERROR, "Application is permanently locked"}, + {"9400", APDUCODE_TYPE_ERROR, "No EF selected."}, + {"9401", APDUCODE_TYPE_NONE, "Candidate currency code does not match purse currency"}, + {"9402", APDUCODE_TYPE_NONE, "Candidate amount too high"}, + {"9402", APDUCODE_TYPE_ERROR, "Address range exceeded."}, + {"9403", APDUCODE_TYPE_NONE, "Candidate amount too low"}, + {"9404", APDUCODE_TYPE_ERROR, "FID not found, record not found or comparison pattern not found."}, + {"9405", APDUCODE_TYPE_NONE, "Problems in the data field"}, + {"9406", APDUCODE_TYPE_ERROR, "Required MAC unavailable"}, + {"9407", APDUCODE_TYPE_NONE, "Bad currency : purse engine has no slot with R3bc currency"}, + {"9408", APDUCODE_TYPE_NONE, "R3bc currency not supported in purse engine"}, + {"9408", APDUCODE_TYPE_ERROR, "Selected file type does not match command."}, + {"9580", APDUCODE_TYPE_NONE, "Bad sequence"}, + {"9681", APDUCODE_TYPE_NONE, "Slave not found"}, + {"9700", APDUCODE_TYPE_NONE, "PIN blocked and Unblock Try Counter is 1 or 2"}, + {"9702", APDUCODE_TYPE_NONE, "Main keys are blocked"}, + {"9704", APDUCODE_TYPE_NONE, "PIN not successfully verified, 3 or more PIN tries left"}, + {"9784", APDUCODE_TYPE_NONE, "Base key"}, + {"9785", APDUCODE_TYPE_NONE, "Limit exceeded - C-MAC key"}, + {"9786", APDUCODE_TYPE_NONE, "SM error - Limit exceeded - R-MAC key"}, + {"9787", APDUCODE_TYPE_NONE, "Limit exceeded - sequence counter"}, + {"9788", APDUCODE_TYPE_NONE, "Limit exceeded - R-MAC length"}, + {"9789", APDUCODE_TYPE_NONE, "Service not available"}, + {"9802", APDUCODE_TYPE_ERROR, "No PIN defined."}, + {"9804", APDUCODE_TYPE_ERROR, "Access conditions not satisfied, authentication failed."}, + {"9835", APDUCODE_TYPE_ERROR, "ASK RANDOM or GIVE RANDOM not executed."}, + {"9840", APDUCODE_TYPE_ERROR, "PIN verification not successful."}, + {"9850", APDUCODE_TYPE_ERROR, "INCREASE or DECREASE could not be executed because a limit has been reached."}, + {"9862", APDUCODE_TYPE_ERROR, "Authentication Error, application specific (incorrect MAC)"}, + {"9900", APDUCODE_TYPE_NONE, "1 PIN try left"}, + {"9904", APDUCODE_TYPE_NONE, "PIN not successfully verified, 1 PIN try left"}, + {"9985", APDUCODE_TYPE_NONE, "Wrong status - Cardholder lock"}, + {"9986", APDUCODE_TYPE_ERROR, "Missing privilege"}, + {"9987", APDUCODE_TYPE_NONE, "PIN is not installed"}, + {"9988", APDUCODE_TYPE_NONE, "Wrong status - R-MAC state"}, + {"9A00", APDUCODE_TYPE_NONE, "2 PIN try left"}, + {"9A04", APDUCODE_TYPE_NONE, "PIN not successfully verified, 2 PIN try left"}, + {"9A71", APDUCODE_TYPE_NONE, "Wrong parameter value - Double agent AID"}, + {"9A72", APDUCODE_TYPE_NONE, "Wrong parameter value - Double agent Type"}, + {"9D05", APDUCODE_TYPE_ERROR, "Incorrect certificate type"}, + {"9D07", APDUCODE_TYPE_ERROR, "Incorrect session data size"}, + {"9D08", APDUCODE_TYPE_ERROR, "Incorrect DIR file record size"}, + {"9D09", APDUCODE_TYPE_ERROR, "Incorrect FCI record size"}, + {"9D0A", APDUCODE_TYPE_ERROR, "Incorrect code size"}, + {"9D10", APDUCODE_TYPE_ERROR, "Insufficient memory to load application"}, + {"9D11", APDUCODE_TYPE_ERROR, "Invalid AID"}, + {"9D12", APDUCODE_TYPE_ERROR, "Duplicate AID"}, + {"9D13", APDUCODE_TYPE_ERROR, "Application previously loaded"}, + {"9D14", APDUCODE_TYPE_ERROR, "Application history list full"}, + {"9D15", APDUCODE_TYPE_ERROR, "Application not open"}, + {"9D17", APDUCODE_TYPE_ERROR, "Invalid offset"}, + {"9D18", APDUCODE_TYPE_ERROR, "Application already loaded"}, + {"9D19", APDUCODE_TYPE_ERROR, "Invalid certificate"}, + {"9D1A", APDUCODE_TYPE_ERROR, "Invalid signature"}, + {"9D1B", APDUCODE_TYPE_ERROR, "Invalid KTU"}, + {"9D1D", APDUCODE_TYPE_ERROR, "MSM controls not set"}, + {"9D1E", APDUCODE_TYPE_ERROR, "Application signature does not exist"}, + {"9D1F", APDUCODE_TYPE_ERROR, "KTU does not exist"}, + {"9D20", APDUCODE_TYPE_ERROR, "Application not loaded"}, + {"9D21", APDUCODE_TYPE_ERROR, "Invalid Open command data length"}, + {"9D30", APDUCODE_TYPE_ERROR, "Check data parameter is incorrect (invalid start address)"}, + {"9D31", APDUCODE_TYPE_ERROR, "Check data parameter is incorrect (invalid length)"}, + {"9D32", APDUCODE_TYPE_ERROR, "Check data parameter is incorrect (illegal memory check area)"}, + {"9D40", APDUCODE_TYPE_ERROR, "Invalid MSM Controls ciphertext"}, + {"9D41", APDUCODE_TYPE_ERROR, "MSM controls already set"}, + {"9D42", APDUCODE_TYPE_ERROR, "Set MSM Controls data length less than 2 bytes"}, + {"9D43", APDUCODE_TYPE_ERROR, "Invalid MSM Controls data length"}, + {"9D44", APDUCODE_TYPE_ERROR, "Excess MSM Controls ciphertext"}, + {"9D45", APDUCODE_TYPE_ERROR, "Verification of MSM Controls data failed"}, + {"9D50", APDUCODE_TYPE_ERROR, "Invalid MCD Issuer production ID"}, + {"9D51", APDUCODE_TYPE_ERROR, "Invalid MCD Issuer ID"}, + {"9D52", APDUCODE_TYPE_ERROR, "Invalid set MSM controls data date"}, + {"9D53", APDUCODE_TYPE_ERROR, "Invalid MCD number"}, + {"9D54", APDUCODE_TYPE_ERROR, "Reserved field error"}, + {"9D55", APDUCODE_TYPE_ERROR, "Reserved field error"}, + {"9D56", APDUCODE_TYPE_ERROR, "Reserved field error"}, + {"9D57", APDUCODE_TYPE_ERROR, "Reserved field error"}, + {"9D60", APDUCODE_TYPE_ERROR, "MAC verification failed"}, + {"9D61", APDUCODE_TYPE_ERROR, "Maximum number of unblocks reached"}, + {"9D62", APDUCODE_TYPE_ERROR, "Card was not blocked"}, + {"9D63", APDUCODE_TYPE_ERROR, "Crypto functions not available"}, + {"9D64", APDUCODE_TYPE_ERROR, "No application loaded"}, + {"9E00", APDUCODE_TYPE_NONE, "PIN not installed"}, + {"9E04", APDUCODE_TYPE_NONE, "PIN not successfully verified, PIN not installed"}, + {"9F00", APDUCODE_TYPE_NONE, "PIN blocked and Unblock Try Counter is 3"}, + {"9F04", APDUCODE_TYPE_NONE, "PIN not successfully verified, PIN blocked and Unblock Try Counter is 3"}, + {"9FXX", APDUCODE_TYPE_NONE, "Command successfully executed; 'xx' bytes of data are available and can be requested using GET RESPONSE."}, + {"9XXX", APDUCODE_TYPE_NONE, "Application related status, (ISO 7816-3)"} }; -const size_t APDUCodeTableLen = sizeof(APDUCodeTable)/sizeof(APDUCode); +const size_t APDUCodeTableLen = sizeof(APDUCodeTable) / sizeof(APDUCode); -int CodeCmp(const char *code1, const char *code2) { +static int CodeCmp(const char *code1, const char *code2) { int xsymb = 0; int cmp = 0; for (int i = 0; i < 4; i++) { @@ -270,29 +275,28 @@ int CodeCmp(const char *code1, const char *code2) { } if (cmp == 4) return 0; - + if (cmp + xsymb == 4) return xsymb; - + return -1; } -const APDUCode* const GetAPDUCode(uint8_t sw1, uint8_t sw2) { - char buf[5] = {0}; - int res; +const APDUCode *GetAPDUCode(uint8_t sw1, uint8_t sw2) { + char buf[6] = {0}; int mineq = APDUCodeTableLen; int mineqindx = 0; - + sprintf(buf, "%02X%02X", sw1, sw2); - + for (int i = 0; i < APDUCodeTableLen; i++) { - res = CodeCmp(APDUCodeTable[i].ID, buf); - + int res = CodeCmp(APDUCodeTable[i].ID, buf); + // equal - if (res == 0) { + if (res == 0) { return &APDUCodeTable[i]; } - + // with some 'X' if (res > 0 && mineq > res) { mineq = res; @@ -304,14 +308,201 @@ const APDUCode* const GetAPDUCode(uint8_t sw1, uint8_t sw2) { if (mineqindx < APDUCodeTableLen) { return &APDUCodeTable[mineqindx]; } - + return NULL; } -const char* GetAPDUCodeDescription(uint8_t sw1, uint8_t sw2) { +const char *GetAPDUCodeDescription(uint8_t sw1, uint8_t sw2) { const APDUCode *cd = GetAPDUCode(sw1, sw2); if (cd) return cd->Description; else return APDUCodeTable[0].Description; //empty string } + +int APDUDecode(uint8_t *data, int len, APDUStruct *apdu) { + ExtAPDUHeader *hapdu = (ExtAPDUHeader *)data; + + apdu->cla = hapdu->cla; + apdu->ins = hapdu->ins; + apdu->p1 = hapdu->p1; + apdu->p2 = hapdu->p2; + + apdu->lc = 0; + apdu->data = NULL; + apdu->le = 0; + apdu->extended_apdu = false; + apdu->case_type = 0x00; + + uint8_t b0 = hapdu->lc[0]; + + // case 1 + if (len == 4) { + apdu->case_type = 0x01; + } + + // case 2S (Le) + if (len == 5) { + apdu->case_type = 0x02; + apdu->le = b0; + if (!apdu->le) + apdu->le = 0x100; + } + + // case 3S (Lc + data) + if (len == 5U + b0 && b0 != 0) { + apdu->case_type = 0x03; + apdu->lc = b0; + } + + // case 4S (Lc + data + Le) + if (len == 5U + b0 + 1U && b0 != 0) { + apdu->case_type = 0x04; + apdu->lc = b0; + apdu->le = data[len - 1]; + if (!apdu->le) + apdu->le = 0x100; + } + + // extended length apdu + if (len >= 7 && b0 == 0) { + uint16_t extlen = (hapdu->lc[1] << 8) + hapdu->lc[2]; + + // case 2E (Le) - extended + if (len == 7) { + apdu->case_type = 0x12; + apdu->extended_apdu = true; + apdu->le = extlen; + if (!apdu->le) + apdu->le = 0x10000; + } + + // case 3E (Lc + data) - extended + if (len == 7U + extlen) { + apdu->case_type = 0x13; + apdu->extended_apdu = true; + apdu->lc = extlen; + } + + // case 4E (Lc + data + Le) - extended 2-byte Le + if (len == 7U + extlen + 2U) { + apdu->case_type = 0x14; + apdu->extended_apdu = true; + apdu->lc = extlen; + apdu->le = (data[len - 2] << 8) + data[len - 1]; + if (!apdu->le) + apdu->le = 0x10000; + } + + // case 4E (Lc + data + Le) - extended 3-byte Le + if (len == 7U + extlen + 3U && data[len - 3] == 0) { + apdu->case_type = 0x24; + apdu->extended_apdu = true; + apdu->lc = extlen; + apdu->le = (data[len - 2] << 8) + data[len - 1]; + if (!apdu->le) + apdu->le = 0x10000; + } + } + + if (!apdu->case_type) + return 1; + + if (apdu->lc) { + if (apdu->extended_apdu) { + apdu->data = data + 7; + } else { + apdu->data = data + 5; + } + + } + + return 0; +} + +int APDUEncode(APDUStruct *apdu, uint8_t *data, int *len) { + if (len) + *len = 0; + + if (apdu->le > 0x10000 || apdu->lc > 0xffff) + return 1; + + size_t dptr = 0; + data[dptr++] = apdu->cla; + data[dptr++] = apdu->ins; + data[dptr++] = apdu->p1; + data[dptr++] = apdu->p2; + + if (apdu->lc) { + if (apdu->extended_apdu || apdu->lc > 0xff || apdu->le > 0x100) { + data[dptr++] = 0x00; + data[dptr++] = (apdu->lc >> 8) & 0xff; + data[dptr++] = (apdu->lc) & 0xff; + memmove(&data[dptr], apdu->data, apdu->lc); + dptr += apdu->lc; + apdu->extended_apdu = true; + } else { + data[dptr++] = apdu->lc; + memmove(&data[dptr], apdu->data, apdu->lc); + dptr += apdu->lc; + } + } + + if (apdu->le) { + if (apdu->extended_apdu) { + if (apdu->le != 0x10000) { + data[dptr++] = 0x00; + data[dptr++] = (apdu->le >> 8) & 0xff; + data[dptr++] = (apdu->le) & 0xff; + } else { + data[dptr++] = 0x00; + data[dptr++] = 0x00; + data[dptr++] = 0x00; + } + } else { + if (apdu->le != 0x100) + data[dptr++] = apdu->le; + else + data[dptr++] = 0x00; + } + } + + if (len) + *len = dptr; + return 0; +} + +int APDUEncodeS(sAPDU *sapdu, bool extended, uint16_t le, uint8_t *data, int *len) { + if (extended && le > 0x100) + return 10; + + APDUStruct apdu; + + apdu.cla = sapdu->CLA; + apdu.ins = sapdu->INS; + apdu.p1 = sapdu->P1; + apdu.p2 = sapdu->P2; + + apdu.lc = sapdu->Lc; + if (sapdu->Lc) + apdu.data = sapdu->data; + else + apdu.data = NULL; + apdu.le = le; + + apdu.extended_apdu = extended; + apdu.case_type = 0x00; + + return APDUEncode(&apdu, data, len); +} + +void APDUPrint(APDUStruct apdu) { + APDUPrintEx(apdu, 0); +} + +void APDUPrintEx(APDUStruct apdu, size_t maxdatalen) { + PrintAndLogEx(INFO, "APDU: %scase=0x%02x cla=0x%02x ins=0x%02x p1=0x%02x p2=0x%02x Lc=0x%02x(%d) Le=0x%02x(%d)", + apdu.extended_apdu ? "[e]" : "", apdu.case_type, apdu.cla, apdu.ins, apdu.p1, apdu.p2, apdu.lc, apdu.lc, apdu.le, apdu.le); + if (maxdatalen > 0) + PrintAndLogEx(INFO, "data: %s%s", sprint_hex(apdu.data, MIN(apdu.lc, maxdatalen)), apdu.lc > maxdatalen ? "..." : ""); +} diff --git a/client/emv/apduinfo.h b/client/emv/apduinfo.h index a3fa2049..d407a125 100644 --- a/client/emv/apduinfo.h +++ b/client/emv/apduinfo.h @@ -11,24 +11,56 @@ #ifndef APDUINFO_H__ #define APDUINFO_H__ -#include -#include -#include -#include +#include "util.h" -#define APDUCODE_TYPE_NONE 0 -#define APDUCODE_TYPE_INFO 1 -#define APDUCODE_TYPE_WARNING 2 -#define APDUCODE_TYPE_ERROR 3 -#define APDUCODE_TYPE_SECURITY 4 + +#define APDUCODE_TYPE_NONE 0 +#define APDUCODE_TYPE_INFO 1 +#define APDUCODE_TYPE_WARNING 2 +#define APDUCODE_TYPE_ERROR 3 +#define APDUCODE_TYPE_SECURITY 4 typedef struct { const char *ID; const uint8_t Type; const char *Description; } APDUCode; - -extern const APDUCode* const GetAPDUCode(uint8_t sw1, uint8_t sw2); -extern const char* GetAPDUCodeDescription(uint8_t sw1, uint8_t sw2); + +typedef struct { + uint8_t CLA; + uint8_t INS; + uint8_t P1; + uint8_t P2; + uint8_t Lc; + uint8_t *data; +} PACKED sAPDU; + +typedef struct { + uint8_t cla; + uint8_t ins; + uint8_t p1; + uint8_t p2; + uint8_t lc[3]; +} PACKED ExtAPDUHeader; + +typedef struct { + uint8_t cla; + uint8_t ins; + uint8_t p1; + uint8_t p2; + uint16_t lc; + uint8_t *data; + uint32_t le; + bool extended_apdu; + uint8_t case_type; +} PACKED APDUStruct; + +extern const APDUCode *GetAPDUCode(uint8_t sw1, uint8_t sw2); +extern const char *GetAPDUCodeDescription(uint8_t sw1, uint8_t sw2); +extern int APDUDecode(uint8_t *data, int len, APDUStruct *apdu); +extern int APDUEncode(APDUStruct *apdu, uint8_t *data, int *len); +extern int APDUEncodeS(sAPDU *apdu, bool extended, uint16_t le, uint8_t *data, int *len); +extern void APDUPrint(APDUStruct apdu); +extern void APDUPrintEx(APDUStruct apdu, size_t maxdatalen); #endif diff --git a/client/util.h b/client/util.h index 18482dfe..5f3335ac 100644 --- a/client/util.h +++ b/client/util.h @@ -15,6 +15,12 @@ #include #include +#ifdef _MSC_VER +#define PACKED +#else +#define PACKED __attribute__((packed)) +#endif + #ifndef ROTR # define ROTR(x,n) (((uintmax_t)(x) >> (n)) | ((uintmax_t)(x) << ((sizeof(x) * 8) - (n)))) #endif