'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
This commit is contained in:
pwpiwi 2019-08-01 11:01:56 -04:00 committed by GitHub
parent ca24170fd4
commit 5a446cb212
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 581 additions and 281 deletions

View file

@ -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) - Fix `hf mf sim` - wrong access rights to write key B in trailer (@McEloff)
### Added ### 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 `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 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) - Added `lf em 4x05protect` to support changing protection blocks on em4x05 chips (marshmellow)

View file

@ -921,20 +921,34 @@ int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool lea
int CmdHF14AAPDU(const char *cmd) { int CmdHF14AAPDU(const char *cmd) {
uint8_t data[USB_CMD_DATA_SIZE]; uint8_t data[USB_CMD_DATA_SIZE];
int datalen = 0; int datalen = 0;
uint8_t header[5];
int headerlen = 0;
bool activateField = false; bool activateField = false;
bool leaveSignalON = false; bool leaveSignalON = false;
bool decodeTLV = false; bool decodeTLV = false;
bool decodeAPDU = false;
bool makeAPDU = false;
bool extendedAPDU = false;
int le = 0;
int res = 0;
CLIParserInit("hf 14a apdu", CLIParserInit("hf 14a apdu",
"Sends an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol (T=CL)", "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",
"Sample:\n\thf 14a apdu -st 00A404000E325041592E5359532E444446303100\n"); "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[] = { void* argtable[] = {
arg_param_begin, arg_param_begin,
arg_lit0("sS", "select", "activate field and select card"), arg_lit0("sS", "select", "activate field and select card"),
arg_lit0("kK", "keep", "leave the signal field ON after receive response"), arg_lit0("kK", "keep", "leave the signal field ON after receive response"),
arg_lit0("tT", "tlv", "executes TLV decoder if it possible"), arg_lit0("tT", "tlv", "executes TLV decoder if it possible"),
arg_strx1(NULL, NULL, "<APDU (hex)>", NULL), arg_lit0("dD", "decapdu", "decode APDU request if it possible"),
arg_str0("mM", "make", "<head (CLA INS P1 P2) hex>", "make APDU with head from this field and data from data field. Must be 4 bytes length: <CLA INS P1 P2>"),
arg_lit0("eE", "extended", "make extended length APDU (requires `-m`)"),
arg_int0("lL", "le", "<Le (int)>", "Le APDU parameter (requires `-m`)"),
arg_strx1(NULL, NULL, "<APDU (hex) | data (hex)>", "APDU (without `-m`), or data (with `-m`)"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(cmd, argtable, false); CLIExecWithReturn(cmd, argtable, false);
@ -942,15 +956,71 @@ int CmdHF14AAPDU(const char *cmd) {
activateField = arg_get_lit(1); activateField = arg_get_lit(1);
leaveSignalON = arg_get_lit(2); leaveSignalON = arg_get_lit(2);
decodeTLV = arg_get_lit(3); decodeTLV = arg_get_lit(3);
// len = data + PCB(1b) + CRC(2b) decodeAPDU = arg_get_lit(4);
CLIGetHexBLessWithReturn(4, data, &datalen, 1 + 2);
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(); CLIParserFree();
// PrintAndLog("---str [%d] %s", arg_get_str(4)->count, arg_get_str(4)->sval[0]); // 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));
int res = ExchangeAPDU14a(data, datalen, activateField, leaveSignalON, data, USB_CMD_DATA_SIZE, &datalen); if (decodeAPDU) {
APDUStruct apdu;
if (APDUDecode(data, datalen, &apdu) == 0)
APDUPrint(apdu);
else
PrintAndLogEx(WARNING, "can't decode APDU.");
}
res = ExchangeAPDU14a(data, datalen, activateField, leaveSignalON, data, USB_CMD_DATA_SIZE, &datalen);
if (res) if (res)
return res; return res;

View file

@ -10,256 +10,261 @@
#include "apduinfo.h" #include "apduinfo.h"
#include <stdio.h>
#include <string.h>
#include "ui.h"
const APDUCode APDUCodeTable[] = { const APDUCode APDUCodeTable[] = {
// ID Type Description // ID Type Description
{"XXXX", APDUCODE_TYPE_NONE, ""}, // blank string {"XXXX", APDUCODE_TYPE_NONE, ""}, // blank string
{"6---", APDUCODE_TYPE_ERROR, "Class not supported."}, {"6---", APDUCODE_TYPE_ERROR, "Class not supported."},
{"61--", APDUCODE_TYPE_INFO, "Response bytes still available"}, {"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."}, {"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"}, {"62--", APDUCODE_TYPE_WARNING, "State of non-volatile memory unchanged"},
{"6200", APDUCODE_TYPE_WARNING, "No information given (NV-Ram not changed)"}, {"6200", APDUCODE_TYPE_WARNING, "No information given (NV-Ram not changed)"},
{"6201", APDUCODE_TYPE_WARNING, "NV-Ram not changed 1."}, {"6201", APDUCODE_TYPE_WARNING, "NV-Ram not changed 1."},
{"6281", APDUCODE_TYPE_WARNING, "Part of returned data may be corrupted"}, {"6281", APDUCODE_TYPE_WARNING, "Part of returned data may be corrupted"},
{"6282", APDUCODE_TYPE_WARNING, "End of file/record reached before reading Le bytes"}, {"6282", APDUCODE_TYPE_WARNING, "End of file/record reached before reading Le bytes"},
{"6283", APDUCODE_TYPE_WARNING, "Selected file invalidated"}, {"6283", APDUCODE_TYPE_WARNING, "Selected file invalidated"},
{"6284", APDUCODE_TYPE_WARNING, "Selected file is not valid. FCI not formated according to ISO"}, {"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"}, {"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"}, {"62A2", APDUCODE_TYPE_WARNING, "Wrong R-MAC"},
{"62A4", APDUCODE_TYPE_WARNING, "Card locked (during reset( ))"}, {"62A4", APDUCODE_TYPE_WARNING, "Card locked (during reset( ))"},
{"62CX", APDUCODE_TYPE_WARNING, "Counter with value x (command dependent)"}, {"62CX", APDUCODE_TYPE_WARNING, "Counter with value x (command dependent)"},
{"62F1", APDUCODE_TYPE_WARNING, "Wrong C-MAC"}, {"62F1", APDUCODE_TYPE_WARNING, "Wrong C-MAC"},
{"62F3", APDUCODE_TYPE_WARNING, "Internal reset"}, {"62F3", APDUCODE_TYPE_WARNING, "Internal reset"},
{"62F5", APDUCODE_TYPE_WARNING, "Default agent locked"}, {"62F5", APDUCODE_TYPE_WARNING, "Default agent locked"},
{"62F7", APDUCODE_TYPE_WARNING, "Cardholder locked"}, {"62F7", APDUCODE_TYPE_WARNING, "Cardholder locked"},
{"62F8", APDUCODE_TYPE_WARNING, "Basement is current agent"}, {"62F8", APDUCODE_TYPE_WARNING, "Basement is current agent"},
{"62F9", APDUCODE_TYPE_WARNING, "CALC Key Set not unblocked"}, {"62F9", APDUCODE_TYPE_WARNING, "CALC Key Set not unblocked"},
{"62FX", APDUCODE_TYPE_WARNING, "-"}, {"62FX", APDUCODE_TYPE_WARNING, "-"},
{"62XX", APDUCODE_TYPE_WARNING, "RFU"}, {"62XX", APDUCODE_TYPE_WARNING, "RFU"},
{"63--", APDUCODE_TYPE_WARNING, "State of non-volatile memory changed"}, {"63--", APDUCODE_TYPE_WARNING, "State of non-volatile memory changed"},
{"6300", APDUCODE_TYPE_WARNING, "No information given (NV-Ram 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."}, {"6381", APDUCODE_TYPE_WARNING, "File filled up by the last write. Loading/updating is not allowed."},
{"6382", APDUCODE_TYPE_WARNING, "Card key not supported."}, {"6382", APDUCODE_TYPE_WARNING, "Card key not supported."},
{"6383", APDUCODE_TYPE_WARNING, "Reader key not supported."}, {"6383", APDUCODE_TYPE_WARNING, "Reader key not supported."},
{"6384", APDUCODE_TYPE_WARNING, "Plaintext transmission not supported."}, {"6384", APDUCODE_TYPE_WARNING, "Plaintext transmission not supported."},
{"6385", APDUCODE_TYPE_WARNING, "Secured transmission not supported."}, {"6385", APDUCODE_TYPE_WARNING, "Secured transmission not supported."},
{"6386", APDUCODE_TYPE_WARNING, "Volatile memory is not available."}, {"6386", APDUCODE_TYPE_WARNING, "Volatile memory is not available."},
{"6387", APDUCODE_TYPE_WARNING, "Non-volatile memory is not available."}, {"6387", APDUCODE_TYPE_WARNING, "Non-volatile memory is not available."},
{"6388", APDUCODE_TYPE_WARNING, "Key number not valid."}, {"6388", APDUCODE_TYPE_WARNING, "Key number not valid."},
{"6389", APDUCODE_TYPE_WARNING, "Key length is not correct."}, {"6389", APDUCODE_TYPE_WARNING, "Key length is not correct."},
{"63C0", APDUCODE_TYPE_WARNING, "Verify fail, no try left."}, {"63C0", APDUCODE_TYPE_WARNING, "Verify fail, no try left."},
{"63C1", APDUCODE_TYPE_WARNING, "Verify fail, 1 try left."}, {"63C1", APDUCODE_TYPE_WARNING, "Verify fail, 1 try left."},
{"63C2", APDUCODE_TYPE_WARNING, "Verify fail, 2 tries left."}, {"63C2", APDUCODE_TYPE_WARNING, "Verify fail, 2 tries left."},
{"63C3", APDUCODE_TYPE_WARNING, "Verify fail, 3 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)."}, {"63CX", APDUCODE_TYPE_WARNING, "The counter has reached the value 'x' (0 = x = 15) (command dependent)."},
{"63F1", APDUCODE_TYPE_WARNING, "More data expected."}, {"63F1", APDUCODE_TYPE_WARNING, "More data expected."},
{"63F2", APDUCODE_TYPE_WARNING, "More data expected and proactive command pending."}, {"63F2", APDUCODE_TYPE_WARNING, "More data expected and proactive command pending."},
{"63FX", APDUCODE_TYPE_WARNING, "-"}, {"63FX", APDUCODE_TYPE_WARNING, "-"},
{"63XX", APDUCODE_TYPE_WARNING, "RFU"}, {"63XX", APDUCODE_TYPE_WARNING, "RFU"},
{"64--", APDUCODE_TYPE_ERROR, "State of non-volatile memory unchanged"}, {"64--", APDUCODE_TYPE_ERROR, "State of non-volatile memory unchanged"},
{"6400", APDUCODE_TYPE_ERROR, "No information given (NV-Ram not changed)"}, {"6400", APDUCODE_TYPE_ERROR, "No information given (NV-Ram not changed)"},
{"6401", APDUCODE_TYPE_ERROR, "Command timeout. Immediate response required by the card."}, {"6401", APDUCODE_TYPE_ERROR, "Command timeout. Immediate response required by the card."},
{"64XX", APDUCODE_TYPE_ERROR, "RFU"}, {"64XX", APDUCODE_TYPE_ERROR, "RFU"},
{"65--", APDUCODE_TYPE_ERROR, "State of non-volatile memory changed"}, {"65--", APDUCODE_TYPE_ERROR, "State of non-volatile memory changed"},
{"6500", APDUCODE_TYPE_ERROR, "No information given"}, {"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."}, {"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"}, {"6581", APDUCODE_TYPE_ERROR, "Memory failure"},
{"65FX", APDUCODE_TYPE_ERROR, "-"}, {"65FX", APDUCODE_TYPE_ERROR, "-"},
{"65XX", APDUCODE_TYPE_ERROR, "RFU"}, {"65XX", APDUCODE_TYPE_ERROR, "RFU"},
{"66--", APDUCODE_TYPE_SECURITY, " "}, {"66--", APDUCODE_TYPE_SECURITY, " "},
{"6600", APDUCODE_TYPE_SECURITY, "Error while receiving (timeout)"}, {"6600", APDUCODE_TYPE_SECURITY, "Error while receiving (timeout)"},
{"6601", APDUCODE_TYPE_SECURITY, "Error while receiving (character parity error)"}, {"6601", APDUCODE_TYPE_SECURITY, "Error while receiving (character parity error)"},
{"6602", APDUCODE_TYPE_SECURITY, "Wrong checksum"}, {"6602", APDUCODE_TYPE_SECURITY, "Wrong checksum"},
{"6603", APDUCODE_TYPE_SECURITY, "The current DF file without FCI"}, {"6603", APDUCODE_TYPE_SECURITY, "The current DF file without FCI"},
{"6604", APDUCODE_TYPE_SECURITY, "No SF or KF under the current DF"}, {"6604", APDUCODE_TYPE_SECURITY, "No SF or KF under the current DF"},
{"6669", APDUCODE_TYPE_SECURITY, "Incorrect Encryption/Decryption Padding"}, {"6669", APDUCODE_TYPE_SECURITY, "Incorrect Encryption/Decryption Padding"},
{"66XX", APDUCODE_TYPE_SECURITY, "-"}, {"66XX", APDUCODE_TYPE_SECURITY, "-"},
{"67--", APDUCODE_TYPE_ERROR, " "}, {"67--", APDUCODE_TYPE_ERROR, " "},
{"6700", APDUCODE_TYPE_ERROR, "Wrong length"}, {"6700", APDUCODE_TYPE_ERROR, "Wrong length"},
{"67XX", APDUCODE_TYPE_ERROR, "length incorrect (procedure)(ISO 7816-3)"}, {"67XX", APDUCODE_TYPE_ERROR, "length incorrect (procedure)(ISO 7816-3)"},
{"68--", APDUCODE_TYPE_ERROR, "Functions in CLA not supported"}, {"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)"}, {"6800", APDUCODE_TYPE_ERROR, "No information given (The request function is not supported by the card)"},
{"6881", APDUCODE_TYPE_ERROR, "Logical channel not supported"}, {"6881", APDUCODE_TYPE_ERROR, "Logical channel not supported"},
{"6882", APDUCODE_TYPE_ERROR, "Secure messaging not supported"}, {"6882", APDUCODE_TYPE_ERROR, "Secure messaging not supported"},
{"6883", APDUCODE_TYPE_ERROR, "Last command of the chain expected"}, {"6883", APDUCODE_TYPE_ERROR, "Last command of the chain expected"},
{"6884", APDUCODE_TYPE_ERROR, "Command chaining not supported"}, {"6884", APDUCODE_TYPE_ERROR, "Command chaining not supported"},
{"68FX", APDUCODE_TYPE_ERROR, "-"}, {"68FX", APDUCODE_TYPE_ERROR, "-"},
{"68XX", APDUCODE_TYPE_ERROR, "RFU"}, {"68XX", APDUCODE_TYPE_ERROR, "RFU"},
{"69--", APDUCODE_TYPE_ERROR, "Command not allowed"}, {"69--", APDUCODE_TYPE_ERROR, "Command not allowed"},
{"6900", APDUCODE_TYPE_ERROR, "No information given (Command not allowed)"}, {"6900", APDUCODE_TYPE_ERROR, "No information given (Command not allowed)"},
{"6901", APDUCODE_TYPE_ERROR, "Command not accepted (inactive state)"}, {"6901", APDUCODE_TYPE_ERROR, "Command not accepted (inactive state)"},
{"6981", APDUCODE_TYPE_ERROR, "Command incompatible with file structure"}, {"6981", APDUCODE_TYPE_ERROR, "Command incompatible with file structure"},
{"6982", APDUCODE_TYPE_ERROR, "Security condition not satisfied."}, {"6982", APDUCODE_TYPE_ERROR, "Security condition not satisfied."},
{"6983", APDUCODE_TYPE_ERROR, "Authentication method blocked"}, {"6983", APDUCODE_TYPE_ERROR, "Authentication method blocked"},
{"6984", APDUCODE_TYPE_ERROR, "Referenced data reversibly blocked (invalidated)"}, {"6984", APDUCODE_TYPE_ERROR, "Referenced data reversibly blocked (invalidated)"},
{"6985", APDUCODE_TYPE_ERROR, "Conditions of use not satisfied."}, {"6985", APDUCODE_TYPE_ERROR, "Conditions of use not satisfied."},
{"6986", APDUCODE_TYPE_ERROR, "Command not allowed (no current EF)"}, {"6986", APDUCODE_TYPE_ERROR, "Command not allowed (no current EF)"},
{"6987", APDUCODE_TYPE_ERROR, "Expected secure messaging (SM) object missing"}, {"6987", APDUCODE_TYPE_ERROR, "Expected secure messaging (SM) object missing"},
{"6988", APDUCODE_TYPE_ERROR, "Incorrect secure messaging (SM) data object"}, {"6988", APDUCODE_TYPE_ERROR, "Incorrect secure messaging (SM) data object"},
{"698D", APDUCODE_TYPE_NONE, "Reserved"}, {"698D", APDUCODE_TYPE_NONE, "Reserved"},
{"6996", APDUCODE_TYPE_ERROR, "Data must be updated again"}, {"6996", APDUCODE_TYPE_ERROR, "Data must be updated again"},
{"69E1", APDUCODE_TYPE_ERROR, "POL1 of the currently Enabled Profile prevents this action."}, {"69E1", APDUCODE_TYPE_ERROR, "POL1 of the currently Enabled Profile prevents this action."},
{"69F0", APDUCODE_TYPE_ERROR, "Permission Denied"}, {"69F0", APDUCODE_TYPE_ERROR, "Permission Denied"},
{"69F1", APDUCODE_TYPE_ERROR, "Permission Denied - Missing Privilege"}, {"69F1", APDUCODE_TYPE_ERROR, "Permission Denied - Missing Privilege"},
{"69FX", APDUCODE_TYPE_ERROR, "-"}, {"69FX", APDUCODE_TYPE_ERROR, "-"},
{"69XX", APDUCODE_TYPE_ERROR, "RFU"}, {"69XX", APDUCODE_TYPE_ERROR, "RFU"},
{"6A--", APDUCODE_TYPE_ERROR, "Wrong parameter(s) P1-P2"}, {"6A--", APDUCODE_TYPE_ERROR, "Wrong parameter(s) P1-P2"},
{"6A00", APDUCODE_TYPE_ERROR, "No information given (Bytes P1 and/or P2 are incorrect)"}, {"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."}, {"6A80", APDUCODE_TYPE_ERROR, "The parameters in the data field are incorrect."},
{"6A81", APDUCODE_TYPE_ERROR, "Function not supported"}, {"6A81", APDUCODE_TYPE_ERROR, "Function not supported"},
{"6A82", APDUCODE_TYPE_ERROR, "File not found"}, {"6A82", APDUCODE_TYPE_ERROR, "File not found"},
{"6A83", APDUCODE_TYPE_ERROR, "Record not found"}, {"6A83", APDUCODE_TYPE_ERROR, "Record not found"},
{"6A84", APDUCODE_TYPE_ERROR, "There is insufficient memory space in record or file"}, {"6A84", APDUCODE_TYPE_ERROR, "There is insufficient memory space in record or file"},
{"6A85", APDUCODE_TYPE_ERROR, "Lc inconsistent with TLV structure"}, {"6A85", APDUCODE_TYPE_ERROR, "Lc inconsistent with TLV structure"},
{"6A86", APDUCODE_TYPE_ERROR, "Incorrect P1 or P2 parameter."}, {"6A86", APDUCODE_TYPE_ERROR, "Incorrect P1 or P2 parameter."},
{"6A87", APDUCODE_TYPE_ERROR, "Lc inconsistent with P1-P2"}, {"6A87", APDUCODE_TYPE_ERROR, "Lc inconsistent with P1-P2"},
{"6A88", APDUCODE_TYPE_ERROR, "Referenced data not found"}, {"6A88", APDUCODE_TYPE_ERROR, "Referenced data not found"},
{"6A89", APDUCODE_TYPE_ERROR, "File already exists"}, {"6A89", APDUCODE_TYPE_ERROR, "File already exists"},
{"6A8A", APDUCODE_TYPE_ERROR, "DF name already exists."}, {"6A8A", APDUCODE_TYPE_ERROR, "DF name already exists."},
{"6AF0", APDUCODE_TYPE_ERROR, "Wrong parameter value"}, {"6AF0", APDUCODE_TYPE_ERROR, "Wrong parameter value"},
{"6AFX", APDUCODE_TYPE_ERROR, "-"}, {"6AFX", APDUCODE_TYPE_ERROR, "-"},
{"6AXX", APDUCODE_TYPE_ERROR, "RFU"}, {"6AXX", APDUCODE_TYPE_ERROR, "RFU"},
{"6B--", APDUCODE_TYPE_ERROR, " "}, {"6B--", APDUCODE_TYPE_ERROR, " "},
{"6B00", APDUCODE_TYPE_ERROR, "Wrong parameter(s) P1-P2"}, {"6B00", APDUCODE_TYPE_ERROR, "Wrong parameter(s) P1-P2"},
{"6BXX", APDUCODE_TYPE_ERROR, "Reference incorrect (procedure byte), (ISO 7816-3)"}, {"6BXX", APDUCODE_TYPE_ERROR, "Reference incorrect (procedure byte), (ISO 7816-3)"},
{"6C--", APDUCODE_TYPE_ERROR, "Wrong length Le"}, {"6C--", APDUCODE_TYPE_ERROR, "Wrong length Le"},
{"6C00", APDUCODE_TYPE_ERROR, "Incorrect P3 length."}, {"6C00", APDUCODE_TYPE_ERROR, "Incorrect P3 length."},
{"6CXX", APDUCODE_TYPE_ERROR, "Bad length value in Le; 'xx' is the correct exact Le"}, {"6CXX", APDUCODE_TYPE_ERROR, "Bad length value in Le; 'xx' is the correct exact Le"},
{"6D--", APDUCODE_TYPE_ERROR, " "}, {"6D--", APDUCODE_TYPE_ERROR, " "},
{"6D00", APDUCODE_TYPE_ERROR, "Instruction code not supported or invalid"}, {"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)"}, {"6DXX", APDUCODE_TYPE_ERROR, "Instruction code not programmed or invalid (procedure byte), (ISO 7816-3)"},
{"6E--", APDUCODE_TYPE_ERROR, " "}, {"6E--", APDUCODE_TYPE_ERROR, " "},
{"6E00", APDUCODE_TYPE_ERROR, "Class not supported"}, {"6E00", APDUCODE_TYPE_ERROR, "Class not supported"},
{"6EXX", APDUCODE_TYPE_ERROR, "Instruction class not supported (procedure byte), (ISO 7816-3)"}, {"6EXX", APDUCODE_TYPE_ERROR, "Instruction class not supported (procedure byte), (ISO 7816-3)"},
{"6F--", APDUCODE_TYPE_ERROR, "Internal exception"}, {"6F--", APDUCODE_TYPE_ERROR, "Internal exception"},
{"6F00", APDUCODE_TYPE_ERROR, "Command aborted - more exact diagnosis not possible (e.g., operating system error)."}, {"6F00", APDUCODE_TYPE_ERROR, "Command aborted - more exact diagnosis not possible (e.g., operating system error)."},
{"6FFF", APDUCODE_TYPE_ERROR, "Card dead (overuse, ...)"}, {"6FFF", APDUCODE_TYPE_ERROR, "Card dead (overuse)"},
{"6FXX", APDUCODE_TYPE_ERROR, "No precise diagnosis (procedure byte), (ISO 7816-3)"}, {"6FXX", APDUCODE_TYPE_ERROR, "No precise diagnosis (procedure byte), (ISO 7816-3)"},
{"9---", APDUCODE_TYPE_NONE, ""}, {"9---", APDUCODE_TYPE_NONE, ""},
{"9000", APDUCODE_TYPE_INFO, "Command successfully executed (OK)."}, {"9000", APDUCODE_TYPE_INFO, "Command successfully executed (OK)."},
{"9004", APDUCODE_TYPE_WARNING, "PIN not succesfully verified, 3 or more PIN tries left"}, {"9004", APDUCODE_TYPE_WARNING, "PIN not successfully verified, 3 or more PIN tries left"},
{"9008", APDUCODE_TYPE_NONE, "Key/file not found"}, {"9008", APDUCODE_TYPE_NONE, "Key/file not found"},
{"9080", APDUCODE_TYPE_WARNING, "Unblock Try Counter has reached zero"}, {"9080", APDUCODE_TYPE_WARNING, "Unblock Try Counter has reached zero"},
{"9100", APDUCODE_TYPE_NONE, "OK"}, {"9100", APDUCODE_TYPE_NONE, "OK"},
{"9101", APDUCODE_TYPE_NONE, "States.activity, States.lock Status or States.lockable has wrong value"}, {"9101", APDUCODE_TYPE_NONE, "States.activity, States.lock Status or States.lockable has wrong value"},
{"9102", APDUCODE_TYPE_NONE, "Transaction number reached its limit"}, {"9102", APDUCODE_TYPE_NONE, "Transaction number reached its limit"},
{"910C", APDUCODE_TYPE_NONE, "No changes"}, {"910C", APDUCODE_TYPE_NONE, "No changes"},
{"910E", APDUCODE_TYPE_NONE, "Insufficient NV-Memory to complete command"}, {"910E", APDUCODE_TYPE_NONE, "Insufficient NV-Memory to complete command"},
{"911C", APDUCODE_TYPE_NONE, "Command code not supported"}, {"911C", APDUCODE_TYPE_NONE, "Command code not supported"},
{"911E", APDUCODE_TYPE_NONE, "CRC or MAC does not match data"}, {"911E", APDUCODE_TYPE_NONE, "CRC or MAC does not match data"},
{"9140", APDUCODE_TYPE_NONE, "Invalid key number specified"}, {"9140", APDUCODE_TYPE_NONE, "Invalid key number specified"},
{"917E", APDUCODE_TYPE_NONE, "Length of command string invalid"}, {"917E", APDUCODE_TYPE_NONE, "Length of command string invalid"},
{"919D", APDUCODE_TYPE_NONE, "Not allow the requested command"}, {"919D", APDUCODE_TYPE_NONE, "Not allow the requested command"},
{"919E", APDUCODE_TYPE_NONE, "Value of the parameter invalid"}, {"919E", APDUCODE_TYPE_NONE, "Value of the parameter invalid"},
{"91A0", APDUCODE_TYPE_NONE, "Requested AID not present on PICC"}, {"91A0", APDUCODE_TYPE_NONE, "Requested AID not present on PICC"},
{"91A1", APDUCODE_TYPE_NONE, "Unrecoverable error within application"}, {"91A1", APDUCODE_TYPE_NONE, "Unrecoverable error within application"},
{"91AE", APDUCODE_TYPE_NONE, "Authentication status does not allow the requested command"}, {"91AE", APDUCODE_TYPE_NONE, "Authentication status does not allow the requested command"},
{"91AF", APDUCODE_TYPE_NONE, "Additional data frame is expected to be sent"}, {"91AF", APDUCODE_TYPE_NONE, "Additional data frame is expected to be sent"},
{"91BE", APDUCODE_TYPE_NONE, "Out of boundary"}, {"91BE", APDUCODE_TYPE_NONE, "Out of boundary"},
{"91C1", APDUCODE_TYPE_NONE, "Unrecoverable error within PICC"}, {"91C1", APDUCODE_TYPE_NONE, "Unrecoverable error within PICC"},
{"91CA", APDUCODE_TYPE_NONE, "Previous Command was not fully completed"}, {"91CA", APDUCODE_TYPE_NONE, "Previous Command was not fully completed"},
{"91CD", APDUCODE_TYPE_NONE, "PICC was disabled by an unrecoverable error"}, {"91CD", APDUCODE_TYPE_NONE, "PICC was disabled by an unrecoverable error"},
{"91CE", APDUCODE_TYPE_NONE, "Number of Applications limited to 28"}, {"91CE", APDUCODE_TYPE_NONE, "Number of Applications limited to 28"},
{"91DE", APDUCODE_TYPE_NONE, "File or application already exists"}, {"91DE", APDUCODE_TYPE_NONE, "File or application already exists"},
{"91EE", APDUCODE_TYPE_NONE, "Could not complete NV-write operation due to loss of power"}, {"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"}, {"91F0", APDUCODE_TYPE_NONE, "Specified file number does not exist"},
{"91F1", APDUCODE_TYPE_NONE, "Unrecoverable error within file"}, {"91F1", APDUCODE_TYPE_NONE, "Unrecoverable error within file"},
{"920x", APDUCODE_TYPE_INFO, "Writing to EEPROM successful after 'x' attempts."}, {"920x", APDUCODE_TYPE_INFO, "Writing to EEPROM successful after 'x' attempts."},
{"9210", APDUCODE_TYPE_ERROR, "Insufficient memory. No more storage available."}, {"9210", APDUCODE_TYPE_ERROR, "Insufficient memory. No more storage available."},
{"9240", APDUCODE_TYPE_ERROR, "Writing to EEPROM not successful."}, {"9240", APDUCODE_TYPE_ERROR, "Writing to EEPROM not successful."},
{"9301", APDUCODE_TYPE_NONE, "Integrity error"}, {"9301", APDUCODE_TYPE_NONE, "Integrity error"},
{"9302", APDUCODE_TYPE_NONE, "Candidate S2 invalid"}, {"9302", APDUCODE_TYPE_NONE, "Candidate S2 invalid"},
{"9303", APDUCODE_TYPE_ERROR, "Application is permanently locked"}, {"9303", APDUCODE_TYPE_ERROR, "Application is permanently locked"},
{"9400", APDUCODE_TYPE_ERROR, "No EF selected."}, {"9400", APDUCODE_TYPE_ERROR, "No EF selected."},
{"9401", APDUCODE_TYPE_NONE, "Candidate currency code does not match purse currency"}, {"9401", APDUCODE_TYPE_NONE, "Candidate currency code does not match purse currency"},
{"9402", APDUCODE_TYPE_NONE, "Candidate amount too high"}, {"9402", APDUCODE_TYPE_NONE, "Candidate amount too high"},
{"9402", APDUCODE_TYPE_ERROR, "Address range exceeded."}, {"9402", APDUCODE_TYPE_ERROR, "Address range exceeded."},
{"9403", APDUCODE_TYPE_NONE, "Candidate amount too low"}, {"9403", APDUCODE_TYPE_NONE, "Candidate amount too low"},
{"9404", APDUCODE_TYPE_ERROR, "FID not found, record not found or comparison pattern not found."}, {"9404", APDUCODE_TYPE_ERROR, "FID not found, record not found or comparison pattern not found."},
{"9405", APDUCODE_TYPE_NONE, "Problems in the data field"}, {"9405", APDUCODE_TYPE_NONE, "Problems in the data field"},
{"9406", APDUCODE_TYPE_ERROR, "Required MAC unavailable"}, {"9406", APDUCODE_TYPE_ERROR, "Required MAC unavailable"},
{"9407", APDUCODE_TYPE_NONE, "Bad currency : purse engine has no slot with R3bc currency"}, {"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_NONE, "R3bc currency not supported in purse engine"},
{"9408", APDUCODE_TYPE_ERROR, "Selected file type does not match command."}, {"9408", APDUCODE_TYPE_ERROR, "Selected file type does not match command."},
{"9580", APDUCODE_TYPE_NONE, "Bad sequence"}, {"9580", APDUCODE_TYPE_NONE, "Bad sequence"},
{"9681", APDUCODE_TYPE_NONE, "Slave not found"}, {"9681", APDUCODE_TYPE_NONE, "Slave not found"},
{"9700", APDUCODE_TYPE_NONE, "PIN blocked and Unblock Try Counter is 1 or 2"}, {"9700", APDUCODE_TYPE_NONE, "PIN blocked and Unblock Try Counter is 1 or 2"},
{"9702", APDUCODE_TYPE_NONE, "Main keys are blocked"}, {"9702", APDUCODE_TYPE_NONE, "Main keys are blocked"},
{"9704", APDUCODE_TYPE_NONE, "PIN not succesfully verified, 3 or more PIN tries left"}, {"9704", APDUCODE_TYPE_NONE, "PIN not successfully verified, 3 or more PIN tries left"},
{"9784", APDUCODE_TYPE_NONE, "Base key"}, {"9784", APDUCODE_TYPE_NONE, "Base key"},
{"9785", APDUCODE_TYPE_NONE, "Limit exceeded - C-MAC key"}, {"9785", APDUCODE_TYPE_NONE, "Limit exceeded - C-MAC key"},
{"9786", APDUCODE_TYPE_NONE, "SM error - Limit exceeded - R-MAC key"}, {"9786", APDUCODE_TYPE_NONE, "SM error - Limit exceeded - R-MAC key"},
{"9787", APDUCODE_TYPE_NONE, "Limit exceeded - sequence counter"}, {"9787", APDUCODE_TYPE_NONE, "Limit exceeded - sequence counter"},
{"9788", APDUCODE_TYPE_NONE, "Limit exceeded - R-MAC length"}, {"9788", APDUCODE_TYPE_NONE, "Limit exceeded - R-MAC length"},
{"9789", APDUCODE_TYPE_NONE, "Service not available"}, {"9789", APDUCODE_TYPE_NONE, "Service not available"},
{"9802", APDUCODE_TYPE_ERROR, "No PIN defined."}, {"9802", APDUCODE_TYPE_ERROR, "No PIN defined."},
{"9804", APDUCODE_TYPE_ERROR, "Access conditions not satisfied, authentication failed."}, {"9804", APDUCODE_TYPE_ERROR, "Access conditions not satisfied, authentication failed."},
{"9835", APDUCODE_TYPE_ERROR, "ASK RANDOM or GIVE RANDOM not executed."}, {"9835", APDUCODE_TYPE_ERROR, "ASK RANDOM or GIVE RANDOM not executed."},
{"9840", APDUCODE_TYPE_ERROR, "PIN verification not successful."}, {"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."}, {"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)"}, {"9862", APDUCODE_TYPE_ERROR, "Authentication Error, application specific (incorrect MAC)"},
{"9900", APDUCODE_TYPE_NONE, "1 PIN try left"}, {"9900", APDUCODE_TYPE_NONE, "1 PIN try left"},
{"9904", APDUCODE_TYPE_NONE, "PIN not succesfully verified, 1 PIN try left"}, {"9904", APDUCODE_TYPE_NONE, "PIN not successfully verified, 1 PIN try left"},
{"9985", APDUCODE_TYPE_NONE, "Wrong status - Cardholder lock"}, {"9985", APDUCODE_TYPE_NONE, "Wrong status - Cardholder lock"},
{"9986", APDUCODE_TYPE_ERROR, "Missing privilege"}, {"9986", APDUCODE_TYPE_ERROR, "Missing privilege"},
{"9987", APDUCODE_TYPE_NONE, "PIN is not installed"}, {"9987", APDUCODE_TYPE_NONE, "PIN is not installed"},
{"9988", APDUCODE_TYPE_NONE, "Wrong status - R-MAC state"}, {"9988", APDUCODE_TYPE_NONE, "Wrong status - R-MAC state"},
{"9A00", APDUCODE_TYPE_NONE, "2 PIN try left"}, {"9A00", APDUCODE_TYPE_NONE, "2 PIN try left"},
{"9A04", APDUCODE_TYPE_NONE, "PIN not succesfully verified, 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"}, {"9A71", APDUCODE_TYPE_NONE, "Wrong parameter value - Double agent AID"},
{"9A72", APDUCODE_TYPE_NONE, "Wrong parameter value - Double agent Type"}, {"9A72", APDUCODE_TYPE_NONE, "Wrong parameter value - Double agent Type"},
{"9D05", APDUCODE_TYPE_ERROR, "Incorrect certificate type"}, {"9D05", APDUCODE_TYPE_ERROR, "Incorrect certificate type"},
{"9D07", APDUCODE_TYPE_ERROR, "Incorrect session data size"}, {"9D07", APDUCODE_TYPE_ERROR, "Incorrect session data size"},
{"9D08", APDUCODE_TYPE_ERROR, "Incorrect DIR file record size"}, {"9D08", APDUCODE_TYPE_ERROR, "Incorrect DIR file record size"},
{"9D09", APDUCODE_TYPE_ERROR, "Incorrect FCI record size"}, {"9D09", APDUCODE_TYPE_ERROR, "Incorrect FCI record size"},
{"9D0A", APDUCODE_TYPE_ERROR, "Incorrect code size"}, {"9D0A", APDUCODE_TYPE_ERROR, "Incorrect code size"},
{"9D10", APDUCODE_TYPE_ERROR, "Insufficient memory to load application"}, {"9D10", APDUCODE_TYPE_ERROR, "Insufficient memory to load application"},
{"9D11", APDUCODE_TYPE_ERROR, "Invalid AID"}, {"9D11", APDUCODE_TYPE_ERROR, "Invalid AID"},
{"9D12", APDUCODE_TYPE_ERROR, "Duplicate AID"}, {"9D12", APDUCODE_TYPE_ERROR, "Duplicate AID"},
{"9D13", APDUCODE_TYPE_ERROR, "Application previously loaded"}, {"9D13", APDUCODE_TYPE_ERROR, "Application previously loaded"},
{"9D14", APDUCODE_TYPE_ERROR, "Application history list full"}, {"9D14", APDUCODE_TYPE_ERROR, "Application history list full"},
{"9D15", APDUCODE_TYPE_ERROR, "Application not open"}, {"9D15", APDUCODE_TYPE_ERROR, "Application not open"},
{"9D17", APDUCODE_TYPE_ERROR, "Invalid offset"}, {"9D17", APDUCODE_TYPE_ERROR, "Invalid offset"},
{"9D18", APDUCODE_TYPE_ERROR, "Application already loaded"}, {"9D18", APDUCODE_TYPE_ERROR, "Application already loaded"},
{"9D19", APDUCODE_TYPE_ERROR, "Invalid certificate"}, {"9D19", APDUCODE_TYPE_ERROR, "Invalid certificate"},
{"9D1A", APDUCODE_TYPE_ERROR, "Invalid signature"}, {"9D1A", APDUCODE_TYPE_ERROR, "Invalid signature"},
{"9D1B", APDUCODE_TYPE_ERROR, "Invalid KTU"}, {"9D1B", APDUCODE_TYPE_ERROR, "Invalid KTU"},
{"9D1D", APDUCODE_TYPE_ERROR, "MSM controls not set"}, {"9D1D", APDUCODE_TYPE_ERROR, "MSM controls not set"},
{"9D1E", APDUCODE_TYPE_ERROR, "Application signature does not exist"}, {"9D1E", APDUCODE_TYPE_ERROR, "Application signature does not exist"},
{"9D1F", APDUCODE_TYPE_ERROR, "KTU does not exist"}, {"9D1F", APDUCODE_TYPE_ERROR, "KTU does not exist"},
{"9D20", APDUCODE_TYPE_ERROR, "Application not loaded"}, {"9D20", APDUCODE_TYPE_ERROR, "Application not loaded"},
{"9D21", APDUCODE_TYPE_ERROR, "Invalid Open command data length"}, {"9D21", APDUCODE_TYPE_ERROR, "Invalid Open command data length"},
{"9D30", APDUCODE_TYPE_ERROR, "Check data parameter is incorrect (invalid start address)"}, {"9D30", APDUCODE_TYPE_ERROR, "Check data parameter is incorrect (invalid start address)"},
{"9D31", APDUCODE_TYPE_ERROR, "Check data parameter is incorrect (invalid length)"}, {"9D31", APDUCODE_TYPE_ERROR, "Check data parameter is incorrect (invalid length)"},
{"9D32", APDUCODE_TYPE_ERROR, "Check data parameter is incorrect (illegal memory check area)"}, {"9D32", APDUCODE_TYPE_ERROR, "Check data parameter is incorrect (illegal memory check area)"},
{"9D40", APDUCODE_TYPE_ERROR, "Invalid MSM Controls ciphertext"}, {"9D40", APDUCODE_TYPE_ERROR, "Invalid MSM Controls ciphertext"},
{"9D41", APDUCODE_TYPE_ERROR, "MSM controls already set"}, {"9D41", APDUCODE_TYPE_ERROR, "MSM controls already set"},
{"9D42", APDUCODE_TYPE_ERROR, "Set MSM Controls data length less than 2 bytes"}, {"9D42", APDUCODE_TYPE_ERROR, "Set MSM Controls data length less than 2 bytes"},
{"9D43", APDUCODE_TYPE_ERROR, "Invalid MSM Controls data length"}, {"9D43", APDUCODE_TYPE_ERROR, "Invalid MSM Controls data length"},
{"9D44", APDUCODE_TYPE_ERROR, "Excess MSM Controls ciphertext"}, {"9D44", APDUCODE_TYPE_ERROR, "Excess MSM Controls ciphertext"},
{"9D45", APDUCODE_TYPE_ERROR, "Verification of MSM Controls data failed"}, {"9D45", APDUCODE_TYPE_ERROR, "Verification of MSM Controls data failed"},
{"9D50", APDUCODE_TYPE_ERROR, "Invalid MCD Issuer production ID"}, {"9D50", APDUCODE_TYPE_ERROR, "Invalid MCD Issuer production ID"},
{"9D51", APDUCODE_TYPE_ERROR, "Invalid MCD Issuer ID"}, {"9D51", APDUCODE_TYPE_ERROR, "Invalid MCD Issuer ID"},
{"9D52", APDUCODE_TYPE_ERROR, "Invalid set MSM controls data date"}, {"9D52", APDUCODE_TYPE_ERROR, "Invalid set MSM controls data date"},
{"9D53", APDUCODE_TYPE_ERROR, "Invalid MCD number"}, {"9D53", APDUCODE_TYPE_ERROR, "Invalid MCD number"},
{"9D54", APDUCODE_TYPE_ERROR, "Reserved field error"}, {"9D54", APDUCODE_TYPE_ERROR, "Reserved field error"},
{"9D55", APDUCODE_TYPE_ERROR, "Reserved field error"}, {"9D55", APDUCODE_TYPE_ERROR, "Reserved field error"},
{"9D56", APDUCODE_TYPE_ERROR, "Reserved field error"}, {"9D56", APDUCODE_TYPE_ERROR, "Reserved field error"},
{"9D57", APDUCODE_TYPE_ERROR, "Reserved field error"}, {"9D57", APDUCODE_TYPE_ERROR, "Reserved field error"},
{"9D60", APDUCODE_TYPE_ERROR, "MAC verification failed"}, {"9D60", APDUCODE_TYPE_ERROR, "MAC verification failed"},
{"9D61", APDUCODE_TYPE_ERROR, "Maximum number of unblocks reached"}, {"9D61", APDUCODE_TYPE_ERROR, "Maximum number of unblocks reached"},
{"9D62", APDUCODE_TYPE_ERROR, "Card was not blocked"}, {"9D62", APDUCODE_TYPE_ERROR, "Card was not blocked"},
{"9D63", APDUCODE_TYPE_ERROR, "Crypto functions not available"}, {"9D63", APDUCODE_TYPE_ERROR, "Crypto functions not available"},
{"9D64", APDUCODE_TYPE_ERROR, "No application loaded"}, {"9D64", APDUCODE_TYPE_ERROR, "No application loaded"},
{"9E00", APDUCODE_TYPE_NONE, "PIN not installed"}, {"9E00", APDUCODE_TYPE_NONE, "PIN not installed"},
{"9E04", APDUCODE_TYPE_NONE, "PIN not succesfully verified, 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"}, {"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"}, {"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."}, {"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)"} {"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 xsymb = 0;
int cmp = 0; int cmp = 0;
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
@ -270,29 +275,28 @@ int CodeCmp(const char *code1, const char *code2) {
} }
if (cmp == 4) if (cmp == 4)
return 0; return 0;
if (cmp + xsymb == 4) if (cmp + xsymb == 4)
return xsymb; return xsymb;
return -1; return -1;
} }
const APDUCode* const GetAPDUCode(uint8_t sw1, uint8_t sw2) { const APDUCode *GetAPDUCode(uint8_t sw1, uint8_t sw2) {
char buf[5] = {0}; char buf[6] = {0};
int res;
int mineq = APDUCodeTableLen; int mineq = APDUCodeTableLen;
int mineqindx = 0; int mineqindx = 0;
sprintf(buf, "%02X%02X", sw1, sw2); sprintf(buf, "%02X%02X", sw1, sw2);
for (int i = 0; i < APDUCodeTableLen; i++) { for (int i = 0; i < APDUCodeTableLen; i++) {
res = CodeCmp(APDUCodeTable[i].ID, buf); int res = CodeCmp(APDUCodeTable[i].ID, buf);
// equal // equal
if (res == 0) { if (res == 0) {
return &APDUCodeTable[i]; return &APDUCodeTable[i];
} }
// with some 'X' // with some 'X'
if (res > 0 && mineq > res) { if (res > 0 && mineq > res) {
mineq = res; mineq = res;
@ -304,14 +308,201 @@ const APDUCode* const GetAPDUCode(uint8_t sw1, uint8_t sw2) {
if (mineqindx < APDUCodeTableLen) { if (mineqindx < APDUCodeTableLen) {
return &APDUCodeTable[mineqindx]; return &APDUCodeTable[mineqindx];
} }
return NULL; 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); const APDUCode *cd = GetAPDUCode(sw1, sw2);
if (cd) if (cd)
return cd->Description; return cd->Description;
else else
return APDUCodeTable[0].Description; //empty string 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 ? "..." : "");
}

View file

@ -11,24 +11,56 @@
#ifndef APDUINFO_H__ #ifndef APDUINFO_H__
#define APDUINFO_H__ #define APDUINFO_H__
#include <stdio.h> #include "util.h"
#include <stdint.h>
#include <stdlib.h>
#include <inttypes.h>
#define APDUCODE_TYPE_NONE 0
#define APDUCODE_TYPE_INFO 1 #define APDUCODE_TYPE_NONE 0
#define APDUCODE_TYPE_WARNING 2 #define APDUCODE_TYPE_INFO 1
#define APDUCODE_TYPE_ERROR 3 #define APDUCODE_TYPE_WARNING 2
#define APDUCODE_TYPE_SECURITY 4 #define APDUCODE_TYPE_ERROR 3
#define APDUCODE_TYPE_SECURITY 4
typedef struct { typedef struct {
const char *ID; const char *ID;
const uint8_t Type; const uint8_t Type;
const char *Description; const char *Description;
} APDUCode; } APDUCode;
extern const APDUCode* const GetAPDUCode(uint8_t sw1, uint8_t sw2); typedef struct {
extern const char* GetAPDUCodeDescription(uint8_t sw1, uint8_t sw2); 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 #endif

View file

@ -15,6 +15,12 @@
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#ifdef _MSC_VER
#define PACKED
#else
#define PACKED __attribute__((packed))
#endif
#ifndef ROTR #ifndef ROTR
# define ROTR(x,n) (((uintmax_t)(x) >> (n)) | ((uintmax_t)(x) << ((sizeof(x) * 8) - (n)))) # define ROTR(x,n) (((uintmax_t)(x) >> (n)) | ((uintmax_t)(x) << ((sizeof(x) * 8) - (n))))
#endif #endif