| 1 | //----------------------------------------------------------------------------- |
| 2 | // Copyright (C) 2017 Merlok |
| 3 | // |
| 4 | // This code is licensed to you under the terms of the GNU GPL, version 2 or, |
| 5 | // at your option, any later version. See the LICENSE.txt file for the text of |
| 6 | // the license. |
| 7 | //----------------------------------------------------------------------------- |
| 8 | // APDU status bytes information |
| 9 | //----------------------------------------------------------------------------- |
| 10 | |
| 11 | #include "apduinfo.h" |
| 12 | |
| 13 | #include <stdio.h> |
| 14 | #include <string.h> |
| 15 | #include "ui.h" |
| 16 | |
| 17 | |
| 18 | const APDUCode APDUCodeTable[] = { |
| 19 | // ID Type Description |
| 20 | {"XXXX", APDUCODE_TYPE_NONE, ""}, // blank string |
| 21 | {"6---", APDUCODE_TYPE_ERROR, "Class not supported."}, |
| 22 | {"61--", APDUCODE_TYPE_INFO, "Response bytes still available"}, |
| 23 | {"61XX", APDUCODE_TYPE_INFO, "Command successfully executed; 'XX' bytes of data are available and can be requested using GET RESPONSE."}, |
| 24 | {"62--", APDUCODE_TYPE_WARNING, "State of non-volatile memory unchanged"}, |
| 25 | {"6200", APDUCODE_TYPE_WARNING, "No information given (NV-Ram not changed)"}, |
| 26 | {"6201", APDUCODE_TYPE_WARNING, "NV-Ram not changed 1."}, |
| 27 | {"6281", APDUCODE_TYPE_WARNING, "Part of returned data may be corrupted"}, |
| 28 | {"6282", APDUCODE_TYPE_WARNING, "End of file/record reached before reading Le bytes"}, |
| 29 | {"6283", APDUCODE_TYPE_WARNING, "Selected file invalidated"}, |
| 30 | {"6284", APDUCODE_TYPE_WARNING, "Selected file is not valid. FCI not formated according to ISO"}, |
| 31 | {"6285", APDUCODE_TYPE_WARNING, "No input data available from a sensor on the card. No Purse Engine enslaved for R3bc"}, |
| 32 | {"62A2", APDUCODE_TYPE_WARNING, "Wrong R-MAC"}, |
| 33 | {"62A4", APDUCODE_TYPE_WARNING, "Card locked (during reset( ))"}, |
| 34 | {"62CX", APDUCODE_TYPE_WARNING, "Counter with value x (command dependent)"}, |
| 35 | {"62F1", APDUCODE_TYPE_WARNING, "Wrong C-MAC"}, |
| 36 | {"62F3", APDUCODE_TYPE_WARNING, "Internal reset"}, |
| 37 | {"62F5", APDUCODE_TYPE_WARNING, "Default agent locked"}, |
| 38 | {"62F7", APDUCODE_TYPE_WARNING, "Cardholder locked"}, |
| 39 | {"62F8", APDUCODE_TYPE_WARNING, "Basement is current agent"}, |
| 40 | {"62F9", APDUCODE_TYPE_WARNING, "CALC Key Set not unblocked"}, |
| 41 | {"62FX", APDUCODE_TYPE_WARNING, "-"}, |
| 42 | {"62XX", APDUCODE_TYPE_WARNING, "RFU"}, |
| 43 | {"63--", APDUCODE_TYPE_WARNING, "State of non-volatile memory changed"}, |
| 44 | {"6300", APDUCODE_TYPE_WARNING, "No information given (NV-Ram changed)"}, |
| 45 | {"6381", APDUCODE_TYPE_WARNING, "File filled up by the last write. Loading/updating is not allowed."}, |
| 46 | {"6382", APDUCODE_TYPE_WARNING, "Card key not supported."}, |
| 47 | {"6383", APDUCODE_TYPE_WARNING, "Reader key not supported."}, |
| 48 | {"6384", APDUCODE_TYPE_WARNING, "Plaintext transmission not supported."}, |
| 49 | {"6385", APDUCODE_TYPE_WARNING, "Secured transmission not supported."}, |
| 50 | {"6386", APDUCODE_TYPE_WARNING, "Volatile memory is not available."}, |
| 51 | {"6387", APDUCODE_TYPE_WARNING, "Non-volatile memory is not available."}, |
| 52 | {"6388", APDUCODE_TYPE_WARNING, "Key number not valid."}, |
| 53 | {"6389", APDUCODE_TYPE_WARNING, "Key length is not correct."}, |
| 54 | {"63C0", APDUCODE_TYPE_WARNING, "Verify fail, no try left."}, |
| 55 | {"63C1", APDUCODE_TYPE_WARNING, "Verify fail, 1 try left."}, |
| 56 | {"63C2", APDUCODE_TYPE_WARNING, "Verify fail, 2 tries left."}, |
| 57 | {"63C3", APDUCODE_TYPE_WARNING, "Verify fail, 3 tries left."}, |
| 58 | {"63CX", APDUCODE_TYPE_WARNING, "The counter has reached the value 'x' (0 = x = 15) (command dependent)."}, |
| 59 | {"63F1", APDUCODE_TYPE_WARNING, "More data expected."}, |
| 60 | {"63F2", APDUCODE_TYPE_WARNING, "More data expected and proactive command pending."}, |
| 61 | {"63FX", APDUCODE_TYPE_WARNING, "-"}, |
| 62 | {"63XX", APDUCODE_TYPE_WARNING, "RFU"}, |
| 63 | {"64--", APDUCODE_TYPE_ERROR, "State of non-volatile memory unchanged"}, |
| 64 | {"6400", APDUCODE_TYPE_ERROR, "No information given (NV-Ram not changed)"}, |
| 65 | {"6401", APDUCODE_TYPE_ERROR, "Command timeout. Immediate response required by the card."}, |
| 66 | {"64XX", APDUCODE_TYPE_ERROR, "RFU"}, |
| 67 | {"65--", APDUCODE_TYPE_ERROR, "State of non-volatile memory changed"}, |
| 68 | {"6500", APDUCODE_TYPE_ERROR, "No information given"}, |
| 69 | {"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."}, |
| 70 | {"6581", APDUCODE_TYPE_ERROR, "Memory failure"}, |
| 71 | {"65FX", APDUCODE_TYPE_ERROR, "-"}, |
| 72 | {"65XX", APDUCODE_TYPE_ERROR, "RFU"}, |
| 73 | {"66--", APDUCODE_TYPE_SECURITY, " "}, |
| 74 | {"6600", APDUCODE_TYPE_SECURITY, "Error while receiving (timeout)"}, |
| 75 | {"6601", APDUCODE_TYPE_SECURITY, "Error while receiving (character parity error)"}, |
| 76 | {"6602", APDUCODE_TYPE_SECURITY, "Wrong checksum"}, |
| 77 | {"6603", APDUCODE_TYPE_SECURITY, "The current DF file without FCI"}, |
| 78 | {"6604", APDUCODE_TYPE_SECURITY, "No SF or KF under the current DF"}, |
| 79 | {"6669", APDUCODE_TYPE_SECURITY, "Incorrect Encryption/Decryption Padding"}, |
| 80 | {"66XX", APDUCODE_TYPE_SECURITY, "-"}, |
| 81 | {"67--", APDUCODE_TYPE_ERROR, " "}, |
| 82 | {"6700", APDUCODE_TYPE_ERROR, "Wrong length"}, |
| 83 | {"67XX", APDUCODE_TYPE_ERROR, "length incorrect (procedure)(ISO 7816-3)"}, |
| 84 | {"68--", APDUCODE_TYPE_ERROR, "Functions in CLA not supported"}, |
| 85 | {"6800", APDUCODE_TYPE_ERROR, "No information given (The request function is not supported by the card)"}, |
| 86 | {"6881", APDUCODE_TYPE_ERROR, "Logical channel not supported"}, |
| 87 | {"6882", APDUCODE_TYPE_ERROR, "Secure messaging not supported"}, |
| 88 | {"6883", APDUCODE_TYPE_ERROR, "Last command of the chain expected"}, |
| 89 | {"6884", APDUCODE_TYPE_ERROR, "Command chaining not supported"}, |
| 90 | {"68FX", APDUCODE_TYPE_ERROR, "-"}, |
| 91 | {"68XX", APDUCODE_TYPE_ERROR, "RFU"}, |
| 92 | {"69--", APDUCODE_TYPE_ERROR, "Command not allowed"}, |
| 93 | {"6900", APDUCODE_TYPE_ERROR, "No information given (Command not allowed)"}, |
| 94 | {"6901", APDUCODE_TYPE_ERROR, "Command not accepted (inactive state)"}, |
| 95 | {"6981", APDUCODE_TYPE_ERROR, "Command incompatible with file structure"}, |
| 96 | {"6982", APDUCODE_TYPE_ERROR, "Security condition not satisfied."}, |
| 97 | {"6983", APDUCODE_TYPE_ERROR, "Authentication method blocked"}, |
| 98 | {"6984", APDUCODE_TYPE_ERROR, "Referenced data reversibly blocked (invalidated)"}, |
| 99 | {"6985", APDUCODE_TYPE_ERROR, "Conditions of use not satisfied."}, |
| 100 | {"6986", APDUCODE_TYPE_ERROR, "Command not allowed (no current EF)"}, |
| 101 | {"6987", APDUCODE_TYPE_ERROR, "Expected secure messaging (SM) object missing"}, |
| 102 | {"6988", APDUCODE_TYPE_ERROR, "Incorrect secure messaging (SM) data object"}, |
| 103 | {"698D", APDUCODE_TYPE_NONE, "Reserved"}, |
| 104 | {"6996", APDUCODE_TYPE_ERROR, "Data must be updated again"}, |
| 105 | {"69E1", APDUCODE_TYPE_ERROR, "POL1 of the currently Enabled Profile prevents this action."}, |
| 106 | {"69F0", APDUCODE_TYPE_ERROR, "Permission Denied"}, |
| 107 | {"69F1", APDUCODE_TYPE_ERROR, "Permission Denied - Missing Privilege"}, |
| 108 | {"69FX", APDUCODE_TYPE_ERROR, "-"}, |
| 109 | {"69XX", APDUCODE_TYPE_ERROR, "RFU"}, |
| 110 | {"6A--", APDUCODE_TYPE_ERROR, "Wrong parameter(s) P1-P2"}, |
| 111 | {"6A00", APDUCODE_TYPE_ERROR, "No information given (Bytes P1 and/or P2 are incorrect)"}, |
| 112 | {"6A80", APDUCODE_TYPE_ERROR, "The parameters in the data field are incorrect."}, |
| 113 | {"6A81", APDUCODE_TYPE_ERROR, "Function not supported"}, |
| 114 | {"6A82", APDUCODE_TYPE_ERROR, "File not found"}, |
| 115 | {"6A83", APDUCODE_TYPE_ERROR, "Record not found"}, |
| 116 | {"6A84", APDUCODE_TYPE_ERROR, "There is insufficient memory space in record or file"}, |
| 117 | {"6A85", APDUCODE_TYPE_ERROR, "Lc inconsistent with TLV structure"}, |
| 118 | {"6A86", APDUCODE_TYPE_ERROR, "Incorrect P1 or P2 parameter."}, |
| 119 | {"6A87", APDUCODE_TYPE_ERROR, "Lc inconsistent with P1-P2"}, |
| 120 | {"6A88", APDUCODE_TYPE_ERROR, "Referenced data not found"}, |
| 121 | {"6A89", APDUCODE_TYPE_ERROR, "File already exists"}, |
| 122 | {"6A8A", APDUCODE_TYPE_ERROR, "DF name already exists."}, |
| 123 | {"6AF0", APDUCODE_TYPE_ERROR, "Wrong parameter value"}, |
| 124 | {"6AFX", APDUCODE_TYPE_ERROR, "-"}, |
| 125 | {"6AXX", APDUCODE_TYPE_ERROR, "RFU"}, |
| 126 | {"6B--", APDUCODE_TYPE_ERROR, " "}, |
| 127 | {"6B00", APDUCODE_TYPE_ERROR, "Wrong parameter(s) P1-P2"}, |
| 128 | {"6BXX", APDUCODE_TYPE_ERROR, "Reference incorrect (procedure byte), (ISO 7816-3)"}, |
| 129 | {"6C--", APDUCODE_TYPE_ERROR, "Wrong length Le"}, |
| 130 | {"6C00", APDUCODE_TYPE_ERROR, "Incorrect P3 length."}, |
| 131 | {"6CXX", APDUCODE_TYPE_ERROR, "Bad length value in Le; 'xx' is the correct exact Le"}, |
| 132 | {"6D--", APDUCODE_TYPE_ERROR, " "}, |
| 133 | {"6D00", APDUCODE_TYPE_ERROR, "Instruction code not supported or invalid"}, |
| 134 | {"6DXX", APDUCODE_TYPE_ERROR, "Instruction code not programmed or invalid (procedure byte), (ISO 7816-3)"}, |
| 135 | {"6E--", APDUCODE_TYPE_ERROR, " "}, |
| 136 | {"6E00", APDUCODE_TYPE_ERROR, "Class not supported"}, |
| 137 | {"6EXX", APDUCODE_TYPE_ERROR, "Instruction class not supported (procedure byte), (ISO 7816-3)"}, |
| 138 | {"6F--", APDUCODE_TYPE_ERROR, "Internal exception"}, |
| 139 | {"6F00", APDUCODE_TYPE_ERROR, "Command aborted - more exact diagnosis not possible (e.g., operating system error)."}, |
| 140 | {"6FFF", APDUCODE_TYPE_ERROR, "Card dead (overuse)"}, |
| 141 | {"6FXX", APDUCODE_TYPE_ERROR, "No precise diagnosis (procedure byte), (ISO 7816-3)"}, |
| 142 | {"9---", APDUCODE_TYPE_NONE, ""}, |
| 143 | {"9000", APDUCODE_TYPE_INFO, "Command successfully executed (OK)."}, |
| 144 | {"9004", APDUCODE_TYPE_WARNING, "PIN not successfully verified, 3 or more PIN tries left"}, |
| 145 | {"9008", APDUCODE_TYPE_NONE, "Key/file not found"}, |
| 146 | {"9080", APDUCODE_TYPE_WARNING, "Unblock Try Counter has reached zero"}, |
| 147 | {"9100", APDUCODE_TYPE_NONE, "OK"}, |
| 148 | {"9101", APDUCODE_TYPE_NONE, "States.activity, States.lock Status or States.lockable has wrong value"}, |
| 149 | {"9102", APDUCODE_TYPE_NONE, "Transaction number reached its limit"}, |
| 150 | {"910C", APDUCODE_TYPE_NONE, "No changes"}, |
| 151 | {"910E", APDUCODE_TYPE_NONE, "Insufficient NV-Memory to complete command"}, |
| 152 | {"911C", APDUCODE_TYPE_NONE, "Command code not supported"}, |
| 153 | {"911E", APDUCODE_TYPE_NONE, "CRC or MAC does not match data"}, |
| 154 | {"9140", APDUCODE_TYPE_NONE, "Invalid key number specified"}, |
| 155 | {"917E", APDUCODE_TYPE_NONE, "Length of command string invalid"}, |
| 156 | {"919D", APDUCODE_TYPE_NONE, "Not allow the requested command"}, |
| 157 | {"919E", APDUCODE_TYPE_NONE, "Value of the parameter invalid"}, |
| 158 | {"91A0", APDUCODE_TYPE_NONE, "Requested AID not present on PICC"}, |
| 159 | {"91A1", APDUCODE_TYPE_NONE, "Unrecoverable error within application"}, |
| 160 | {"91AE", APDUCODE_TYPE_NONE, "Authentication status does not allow the requested command"}, |
| 161 | {"91AF", APDUCODE_TYPE_NONE, "Additional data frame is expected to be sent"}, |
| 162 | {"91BE", APDUCODE_TYPE_NONE, "Out of boundary"}, |
| 163 | {"91C1", APDUCODE_TYPE_NONE, "Unrecoverable error within PICC"}, |
| 164 | {"91CA", APDUCODE_TYPE_NONE, "Previous Command was not fully completed"}, |
| 165 | {"91CD", APDUCODE_TYPE_NONE, "PICC was disabled by an unrecoverable error"}, |
| 166 | {"91CE", APDUCODE_TYPE_NONE, "Number of Applications limited to 28"}, |
| 167 | {"91DE", APDUCODE_TYPE_NONE, "File or application already exists"}, |
| 168 | {"91EE", APDUCODE_TYPE_NONE, "Could not complete NV-write operation due to loss of power"}, |
| 169 | {"91F0", APDUCODE_TYPE_NONE, "Specified file number does not exist"}, |
| 170 | {"91F1", APDUCODE_TYPE_NONE, "Unrecoverable error within file"}, |
| 171 | {"920x", APDUCODE_TYPE_INFO, "Writing to EEPROM successful after 'x' attempts."}, |
| 172 | {"9210", APDUCODE_TYPE_ERROR, "Insufficient memory. No more storage available."}, |
| 173 | {"9240", APDUCODE_TYPE_ERROR, "Writing to EEPROM not successful."}, |
| 174 | {"9301", APDUCODE_TYPE_NONE, "Integrity error"}, |
| 175 | {"9302", APDUCODE_TYPE_NONE, "Candidate S2 invalid"}, |
| 176 | {"9303", APDUCODE_TYPE_ERROR, "Application is permanently locked"}, |
| 177 | {"9400", APDUCODE_TYPE_ERROR, "No EF selected."}, |
| 178 | {"9401", APDUCODE_TYPE_NONE, "Candidate currency code does not match purse currency"}, |
| 179 | {"9402", APDUCODE_TYPE_NONE, "Candidate amount too high"}, |
| 180 | {"9402", APDUCODE_TYPE_ERROR, "Address range exceeded."}, |
| 181 | {"9403", APDUCODE_TYPE_NONE, "Candidate amount too low"}, |
| 182 | {"9404", APDUCODE_TYPE_ERROR, "FID not found, record not found or comparison pattern not found."}, |
| 183 | {"9405", APDUCODE_TYPE_NONE, "Problems in the data field"}, |
| 184 | {"9406", APDUCODE_TYPE_ERROR, "Required MAC unavailable"}, |
| 185 | {"9407", APDUCODE_TYPE_NONE, "Bad currency : purse engine has no slot with R3bc currency"}, |
| 186 | {"9408", APDUCODE_TYPE_NONE, "R3bc currency not supported in purse engine"}, |
| 187 | {"9408", APDUCODE_TYPE_ERROR, "Selected file type does not match command."}, |
| 188 | {"9580", APDUCODE_TYPE_NONE, "Bad sequence"}, |
| 189 | {"9681", APDUCODE_TYPE_NONE, "Slave not found"}, |
| 190 | {"9700", APDUCODE_TYPE_NONE, "PIN blocked and Unblock Try Counter is 1 or 2"}, |
| 191 | {"9702", APDUCODE_TYPE_NONE, "Main keys are blocked"}, |
| 192 | {"9704", APDUCODE_TYPE_NONE, "PIN not successfully verified, 3 or more PIN tries left"}, |
| 193 | {"9784", APDUCODE_TYPE_NONE, "Base key"}, |
| 194 | {"9785", APDUCODE_TYPE_NONE, "Limit exceeded - C-MAC key"}, |
| 195 | {"9786", APDUCODE_TYPE_NONE, "SM error - Limit exceeded - R-MAC key"}, |
| 196 | {"9787", APDUCODE_TYPE_NONE, "Limit exceeded - sequence counter"}, |
| 197 | {"9788", APDUCODE_TYPE_NONE, "Limit exceeded - R-MAC length"}, |
| 198 | {"9789", APDUCODE_TYPE_NONE, "Service not available"}, |
| 199 | {"9802", APDUCODE_TYPE_ERROR, "No PIN defined."}, |
| 200 | {"9804", APDUCODE_TYPE_ERROR, "Access conditions not satisfied, authentication failed."}, |
| 201 | {"9835", APDUCODE_TYPE_ERROR, "ASK RANDOM or GIVE RANDOM not executed."}, |
| 202 | {"9840", APDUCODE_TYPE_ERROR, "PIN verification not successful."}, |
| 203 | {"9850", APDUCODE_TYPE_ERROR, "INCREASE or DECREASE could not be executed because a limit has been reached."}, |
| 204 | {"9862", APDUCODE_TYPE_ERROR, "Authentication Error, application specific (incorrect MAC)"}, |
| 205 | {"9900", APDUCODE_TYPE_NONE, "1 PIN try left"}, |
| 206 | {"9904", APDUCODE_TYPE_NONE, "PIN not successfully verified, 1 PIN try left"}, |
| 207 | {"9985", APDUCODE_TYPE_NONE, "Wrong status - Cardholder lock"}, |
| 208 | {"9986", APDUCODE_TYPE_ERROR, "Missing privilege"}, |
| 209 | {"9987", APDUCODE_TYPE_NONE, "PIN is not installed"}, |
| 210 | {"9988", APDUCODE_TYPE_NONE, "Wrong status - R-MAC state"}, |
| 211 | {"9A00", APDUCODE_TYPE_NONE, "2 PIN try left"}, |
| 212 | {"9A04", APDUCODE_TYPE_NONE, "PIN not successfully verified, 2 PIN try left"}, |
| 213 | {"9A71", APDUCODE_TYPE_NONE, "Wrong parameter value - Double agent AID"}, |
| 214 | {"9A72", APDUCODE_TYPE_NONE, "Wrong parameter value - Double agent Type"}, |
| 215 | {"9D05", APDUCODE_TYPE_ERROR, "Incorrect certificate type"}, |
| 216 | {"9D07", APDUCODE_TYPE_ERROR, "Incorrect session data size"}, |
| 217 | {"9D08", APDUCODE_TYPE_ERROR, "Incorrect DIR file record size"}, |
| 218 | {"9D09", APDUCODE_TYPE_ERROR, "Incorrect FCI record size"}, |
| 219 | {"9D0A", APDUCODE_TYPE_ERROR, "Incorrect code size"}, |
| 220 | {"9D10", APDUCODE_TYPE_ERROR, "Insufficient memory to load application"}, |
| 221 | {"9D11", APDUCODE_TYPE_ERROR, "Invalid AID"}, |
| 222 | {"9D12", APDUCODE_TYPE_ERROR, "Duplicate AID"}, |
| 223 | {"9D13", APDUCODE_TYPE_ERROR, "Application previously loaded"}, |
| 224 | {"9D14", APDUCODE_TYPE_ERROR, "Application history list full"}, |
| 225 | {"9D15", APDUCODE_TYPE_ERROR, "Application not open"}, |
| 226 | {"9D17", APDUCODE_TYPE_ERROR, "Invalid offset"}, |
| 227 | {"9D18", APDUCODE_TYPE_ERROR, "Application already loaded"}, |
| 228 | {"9D19", APDUCODE_TYPE_ERROR, "Invalid certificate"}, |
| 229 | {"9D1A", APDUCODE_TYPE_ERROR, "Invalid signature"}, |
| 230 | {"9D1B", APDUCODE_TYPE_ERROR, "Invalid KTU"}, |
| 231 | {"9D1D", APDUCODE_TYPE_ERROR, "MSM controls not set"}, |
| 232 | {"9D1E", APDUCODE_TYPE_ERROR, "Application signature does not exist"}, |
| 233 | {"9D1F", APDUCODE_TYPE_ERROR, "KTU does not exist"}, |
| 234 | {"9D20", APDUCODE_TYPE_ERROR, "Application not loaded"}, |
| 235 | {"9D21", APDUCODE_TYPE_ERROR, "Invalid Open command data length"}, |
| 236 | {"9D30", APDUCODE_TYPE_ERROR, "Check data parameter is incorrect (invalid start address)"}, |
| 237 | {"9D31", APDUCODE_TYPE_ERROR, "Check data parameter is incorrect (invalid length)"}, |
| 238 | {"9D32", APDUCODE_TYPE_ERROR, "Check data parameter is incorrect (illegal memory check area)"}, |
| 239 | {"9D40", APDUCODE_TYPE_ERROR, "Invalid MSM Controls ciphertext"}, |
| 240 | {"9D41", APDUCODE_TYPE_ERROR, "MSM controls already set"}, |
| 241 | {"9D42", APDUCODE_TYPE_ERROR, "Set MSM Controls data length less than 2 bytes"}, |
| 242 | {"9D43", APDUCODE_TYPE_ERROR, "Invalid MSM Controls data length"}, |
| 243 | {"9D44", APDUCODE_TYPE_ERROR, "Excess MSM Controls ciphertext"}, |
| 244 | {"9D45", APDUCODE_TYPE_ERROR, "Verification of MSM Controls data failed"}, |
| 245 | {"9D50", APDUCODE_TYPE_ERROR, "Invalid MCD Issuer production ID"}, |
| 246 | {"9D51", APDUCODE_TYPE_ERROR, "Invalid MCD Issuer ID"}, |
| 247 | {"9D52", APDUCODE_TYPE_ERROR, "Invalid set MSM controls data date"}, |
| 248 | {"9D53", APDUCODE_TYPE_ERROR, "Invalid MCD number"}, |
| 249 | {"9D54", APDUCODE_TYPE_ERROR, "Reserved field error"}, |
| 250 | {"9D55", APDUCODE_TYPE_ERROR, "Reserved field error"}, |
| 251 | {"9D56", APDUCODE_TYPE_ERROR, "Reserved field error"}, |
| 252 | {"9D57", APDUCODE_TYPE_ERROR, "Reserved field error"}, |
| 253 | {"9D60", APDUCODE_TYPE_ERROR, "MAC verification failed"}, |
| 254 | {"9D61", APDUCODE_TYPE_ERROR, "Maximum number of unblocks reached"}, |
| 255 | {"9D62", APDUCODE_TYPE_ERROR, "Card was not blocked"}, |
| 256 | {"9D63", APDUCODE_TYPE_ERROR, "Crypto functions not available"}, |
| 257 | {"9D64", APDUCODE_TYPE_ERROR, "No application loaded"}, |
| 258 | {"9E00", APDUCODE_TYPE_NONE, "PIN not installed"}, |
| 259 | {"9E04", APDUCODE_TYPE_NONE, "PIN not successfully verified, PIN not installed"}, |
| 260 | {"9F00", APDUCODE_TYPE_NONE, "PIN blocked and Unblock Try Counter is 3"}, |
| 261 | {"9F04", APDUCODE_TYPE_NONE, "PIN not successfully verified, PIN blocked and Unblock Try Counter is 3"}, |
| 262 | {"9FXX", APDUCODE_TYPE_NONE, "Command successfully executed; 'xx' bytes of data are available and can be requested using GET RESPONSE."}, |
| 263 | {"9XXX", APDUCODE_TYPE_NONE, "Application related status, (ISO 7816-3)"} |
| 264 | }; |
| 265 | const size_t APDUCodeTableLen = sizeof(APDUCodeTable) / sizeof(APDUCode); |
| 266 | |
| 267 | static int CodeCmp(const char *code1, const char *code2) { |
| 268 | int xsymb = 0; |
| 269 | int cmp = 0; |
| 270 | for (int i = 0; i < 4; i++) { |
| 271 | if (code1[i] == code2[i]) |
| 272 | cmp++; |
| 273 | if (code1[i] == 'X' || code2[i] == 'X') |
| 274 | xsymb++; |
| 275 | } |
| 276 | if (cmp == 4) |
| 277 | return 0; |
| 278 | |
| 279 | if (cmp + xsymb == 4) |
| 280 | return xsymb; |
| 281 | |
| 282 | return -1; |
| 283 | } |
| 284 | |
| 285 | const APDUCode *GetAPDUCode(uint8_t sw1, uint8_t sw2) { |
| 286 | char buf[6] = {0}; |
| 287 | int mineq = APDUCodeTableLen; |
| 288 | int mineqindx = 0; |
| 289 | |
| 290 | sprintf(buf, "%02X%02X", sw1, sw2); |
| 291 | |
| 292 | for (int i = 0; i < APDUCodeTableLen; i++) { |
| 293 | int res = CodeCmp(APDUCodeTable[i].ID, buf); |
| 294 | |
| 295 | // equal |
| 296 | if (res == 0) { |
| 297 | return &APDUCodeTable[i]; |
| 298 | } |
| 299 | |
| 300 | // with some 'X' |
| 301 | if (res > 0 && mineq > res) { |
| 302 | mineq = res; |
| 303 | mineqindx = i; |
| 304 | } |
| 305 | } |
| 306 | |
| 307 | // if we have not equal, but with some 'X' |
| 308 | if (mineqindx < APDUCodeTableLen) { |
| 309 | return &APDUCodeTable[mineqindx]; |
| 310 | } |
| 311 | |
| 312 | return NULL; |
| 313 | } |
| 314 | |
| 315 | const char *GetAPDUCodeDescription(uint8_t sw1, uint8_t sw2) { |
| 316 | const APDUCode *cd = GetAPDUCode(sw1, sw2); |
| 317 | if (cd) |
| 318 | return cd->Description; |
| 319 | else |
| 320 | return APDUCodeTable[0].Description; //empty string |
| 321 | } |
| 322 | |
| 323 | int APDUDecode(uint8_t *data, int len, APDUStruct *apdu) { |
| 324 | ExtAPDUHeader *hapdu = (ExtAPDUHeader *)data; |
| 325 | |
| 326 | apdu->cla = hapdu->cla; |
| 327 | apdu->ins = hapdu->ins; |
| 328 | apdu->p1 = hapdu->p1; |
| 329 | apdu->p2 = hapdu->p2; |
| 330 | |
| 331 | apdu->lc = 0; |
| 332 | apdu->data = NULL; |
| 333 | apdu->le = 0; |
| 334 | apdu->extended_apdu = false; |
| 335 | apdu->case_type = 0x00; |
| 336 | |
| 337 | uint8_t b0 = hapdu->lc[0]; |
| 338 | |
| 339 | // case 1 |
| 340 | if (len == 4) { |
| 341 | apdu->case_type = 0x01; |
| 342 | } |
| 343 | |
| 344 | // case 2S (Le) |
| 345 | if (len == 5) { |
| 346 | apdu->case_type = 0x02; |
| 347 | apdu->le = b0; |
| 348 | if (!apdu->le) |
| 349 | apdu->le = 0x100; |
| 350 | } |
| 351 | |
| 352 | // case 3S (Lc + data) |
| 353 | if (len == 5U + b0 && b0 != 0) { |
| 354 | apdu->case_type = 0x03; |
| 355 | apdu->lc = b0; |
| 356 | } |
| 357 | |
| 358 | // case 4S (Lc + data + Le) |
| 359 | if (len == 5U + b0 + 1U && b0 != 0) { |
| 360 | apdu->case_type = 0x04; |
| 361 | apdu->lc = b0; |
| 362 | apdu->le = data[len - 1]; |
| 363 | if (!apdu->le) |
| 364 | apdu->le = 0x100; |
| 365 | } |
| 366 | |
| 367 | // extended length apdu |
| 368 | if (len >= 7 && b0 == 0) { |
| 369 | uint16_t extlen = (hapdu->lc[1] << 8) + hapdu->lc[2]; |
| 370 | |
| 371 | // case 2E (Le) - extended |
| 372 | if (len == 7) { |
| 373 | apdu->case_type = 0x12; |
| 374 | apdu->extended_apdu = true; |
| 375 | apdu->le = extlen; |
| 376 | if (!apdu->le) |
| 377 | apdu->le = 0x10000; |
| 378 | } |
| 379 | |
| 380 | // case 3E (Lc + data) - extended |
| 381 | if (len == 7U + extlen) { |
| 382 | apdu->case_type = 0x13; |
| 383 | apdu->extended_apdu = true; |
| 384 | apdu->lc = extlen; |
| 385 | } |
| 386 | |
| 387 | // case 4E (Lc + data + Le) - extended 2-byte Le |
| 388 | if (len == 7U + extlen + 2U) { |
| 389 | apdu->case_type = 0x14; |
| 390 | apdu->extended_apdu = true; |
| 391 | apdu->lc = extlen; |
| 392 | apdu->le = (data[len - 2] << 8) + data[len - 1]; |
| 393 | if (!apdu->le) |
| 394 | apdu->le = 0x10000; |
| 395 | } |
| 396 | |
| 397 | // case 4E (Lc + data + Le) - extended 3-byte Le |
| 398 | if (len == 7U + extlen + 3U && data[len - 3] == 0) { |
| 399 | apdu->case_type = 0x24; |
| 400 | apdu->extended_apdu = true; |
| 401 | apdu->lc = extlen; |
| 402 | apdu->le = (data[len - 2] << 8) + data[len - 1]; |
| 403 | if (!apdu->le) |
| 404 | apdu->le = 0x10000; |
| 405 | } |
| 406 | } |
| 407 | |
| 408 | if (!apdu->case_type) |
| 409 | return 1; |
| 410 | |
| 411 | if (apdu->lc) { |
| 412 | if (apdu->extended_apdu) { |
| 413 | apdu->data = data + 7; |
| 414 | } else { |
| 415 | apdu->data = data + 5; |
| 416 | } |
| 417 | |
| 418 | } |
| 419 | |
| 420 | return 0; |
| 421 | } |
| 422 | |
| 423 | int APDUEncode(APDUStruct *apdu, uint8_t *data, int *len) { |
| 424 | if (len) |
| 425 | *len = 0; |
| 426 | |
| 427 | if (apdu->le > 0x10000 || apdu->lc > 0xffff) |
| 428 | return 1; |
| 429 | |
| 430 | size_t dptr = 0; |
| 431 | data[dptr++] = apdu->cla; |
| 432 | data[dptr++] = apdu->ins; |
| 433 | data[dptr++] = apdu->p1; |
| 434 | data[dptr++] = apdu->p2; |
| 435 | |
| 436 | if (apdu->lc) { |
| 437 | if (apdu->extended_apdu || apdu->lc > 0xff || apdu->le > 0x100) { |
| 438 | data[dptr++] = 0x00; |
| 439 | data[dptr++] = (apdu->lc >> 8) & 0xff; |
| 440 | data[dptr++] = (apdu->lc) & 0xff; |
| 441 | memmove(&data[dptr], apdu->data, apdu->lc); |
| 442 | dptr += apdu->lc; |
| 443 | apdu->extended_apdu = true; |
| 444 | } else { |
| 445 | data[dptr++] = apdu->lc; |
| 446 | memmove(&data[dptr], apdu->data, apdu->lc); |
| 447 | dptr += apdu->lc; |
| 448 | } |
| 449 | } |
| 450 | |
| 451 | if (apdu->le) { |
| 452 | if (apdu->extended_apdu) { |
| 453 | if (apdu->le != 0x10000) { |
| 454 | data[dptr++] = 0x00; |
| 455 | data[dptr++] = (apdu->le >> 8) & 0xff; |
| 456 | data[dptr++] = (apdu->le) & 0xff; |
| 457 | } else { |
| 458 | data[dptr++] = 0x00; |
| 459 | data[dptr++] = 0x00; |
| 460 | data[dptr++] = 0x00; |
| 461 | } |
| 462 | } else { |
| 463 | if (apdu->le != 0x100) |
| 464 | data[dptr++] = apdu->le; |
| 465 | else |
| 466 | data[dptr++] = 0x00; |
| 467 | } |
| 468 | } |
| 469 | |
| 470 | if (len) |
| 471 | *len = dptr; |
| 472 | return 0; |
| 473 | } |
| 474 | |
| 475 | int APDUEncodeS(sAPDU *sapdu, bool extended, uint16_t le, uint8_t *data, int *len) { |
| 476 | if (extended && le > 0x100) |
| 477 | return 10; |
| 478 | |
| 479 | APDUStruct apdu; |
| 480 | |
| 481 | apdu.cla = sapdu->CLA; |
| 482 | apdu.ins = sapdu->INS; |
| 483 | apdu.p1 = sapdu->P1; |
| 484 | apdu.p2 = sapdu->P2; |
| 485 | |
| 486 | apdu.lc = sapdu->Lc; |
| 487 | if (sapdu->Lc) |
| 488 | apdu.data = sapdu->data; |
| 489 | else |
| 490 | apdu.data = NULL; |
| 491 | apdu.le = le; |
| 492 | |
| 493 | apdu.extended_apdu = extended; |
| 494 | apdu.case_type = 0x00; |
| 495 | |
| 496 | return APDUEncode(&apdu, data, len); |
| 497 | } |
| 498 | |
| 499 | void APDUPrint(APDUStruct apdu) { |
| 500 | APDUPrintEx(apdu, 0); |
| 501 | } |
| 502 | |
| 503 | void APDUPrintEx(APDUStruct apdu, size_t maxdatalen) { |
| 504 | 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)", |
| 505 | apdu.extended_apdu ? "[e]" : "", apdu.case_type, apdu.cla, apdu.ins, apdu.p1, apdu.p2, apdu.lc, apdu.lc, apdu.le, apdu.le); |
| 506 | if (maxdatalen > 0) |
| 507 | PrintAndLogEx(INFO, "data: %s%s", sprint_hex(apdu.data, MIN(apdu.lc, maxdatalen)), apdu.lc > maxdatalen ? "..." : ""); |
| 508 | } |