mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 13:53:55 -07:00
client: fix mix of spaces & tabs
This commit is contained in:
parent
112411042f
commit
0d9223a547
197 changed files with 49383 additions and 49383 deletions
|
@ -11,307 +11,307 @@
|
|||
#include "apduinfo.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)"}
|
||||
// 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)"}
|
||||
};
|
||||
const size_t APDUCodeTableLen = sizeof(APDUCodeTable)/sizeof(APDUCode);
|
||||
|
||||
int CodeCmp(const char *code1, const char *code2) {
|
||||
int xsymb = 0;
|
||||
int cmp = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (code1[i] == code2[i])
|
||||
cmp++;
|
||||
if (code1[i] == 'X' || code2[i] == 'X')
|
||||
xsymb++;
|
||||
}
|
||||
if (cmp == 4)
|
||||
return 0;
|
||||
int xsymb = 0;
|
||||
int cmp = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (code1[i] == code2[i])
|
||||
cmp++;
|
||||
if (code1[i] == 'X' || code2[i] == 'X')
|
||||
xsymb++;
|
||||
}
|
||||
if (cmp == 4)
|
||||
return 0;
|
||||
|
||||
if (cmp + xsymb == 4)
|
||||
return xsymb;
|
||||
if (cmp + xsymb == 4)
|
||||
return xsymb;
|
||||
|
||||
return -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
const APDUCode* const GetAPDUCode(uint8_t sw1, uint8_t sw2) {
|
||||
char buf[6] = {0};
|
||||
int res;
|
||||
int mineq = APDUCodeTableLen;
|
||||
int mineqindx = 0;
|
||||
char buf[6] = {0};
|
||||
int res;
|
||||
int mineq = APDUCodeTableLen;
|
||||
int mineqindx = 0;
|
||||
|
||||
sprintf(buf, "%02X%02X", sw1, sw2);
|
||||
sprintf(buf, "%02X%02X", sw1, sw2);
|
||||
|
||||
for (int i = 0; i < APDUCodeTableLen; i++) {
|
||||
res = CodeCmp(APDUCodeTable[i].ID, buf);
|
||||
for (int i = 0; i < APDUCodeTableLen; i++) {
|
||||
res = CodeCmp(APDUCodeTable[i].ID, buf);
|
||||
|
||||
// equal
|
||||
if (res == 0) {
|
||||
return &APDUCodeTable[i];
|
||||
}
|
||||
// equal
|
||||
if (res == 0) {
|
||||
return &APDUCodeTable[i];
|
||||
}
|
||||
|
||||
// with some 'X'
|
||||
if (res > 0 && mineq > res) {
|
||||
mineq = res;
|
||||
mineqindx = i;
|
||||
}
|
||||
}
|
||||
// with some 'X'
|
||||
if (res > 0 && mineq > res) {
|
||||
mineq = res;
|
||||
mineqindx = i;
|
||||
}
|
||||
}
|
||||
|
||||
// if we have not equal, but with some 'X'
|
||||
if (mineqindx < APDUCodeTableLen) {
|
||||
return &APDUCodeTable[mineqindx];
|
||||
}
|
||||
// if we have not equal, but with some 'X'
|
||||
if (mineqindx < APDUCodeTableLen) {
|
||||
return &APDUCodeTable[mineqindx];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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
|
||||
const APDUCode *cd = GetAPDUCode(sw1, sw2);
|
||||
if (cd)
|
||||
return cd->Description;
|
||||
else
|
||||
return APDUCodeTable[0].Description; //empty string
|
||||
}
|
||||
|
|
|
@ -16,16 +16,16 @@
|
|||
#include <stdlib.h>
|
||||
#include <inttypes.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;
|
||||
const char *ID;
|
||||
const uint8_t Type;
|
||||
const char *Description;
|
||||
} APDUCode;
|
||||
|
||||
extern const APDUCode* const GetAPDUCode(uint8_t sw1, uint8_t sw2);
|
||||
|
|
3298
client/emv/cmdemv.c
3298
client/emv/cmdemv.c
File diff suppressed because it is too large
Load diff
|
@ -26,154 +26,154 @@ static struct crypto_backend *crypto_backend;
|
|||
|
||||
static bool crypto_init(void)
|
||||
{
|
||||
if (crypto_backend)
|
||||
return true;
|
||||
if (crypto_backend)
|
||||
return true;
|
||||
|
||||
crypto_backend = crypto_polarssl_init();
|
||||
crypto_backend = crypto_polarssl_init();
|
||||
|
||||
if (!crypto_backend)
|
||||
return false;
|
||||
if (!crypto_backend)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct crypto_hash *crypto_hash_open(enum crypto_algo_hash hash)
|
||||
{
|
||||
struct crypto_hash *ch;
|
||||
struct crypto_hash *ch;
|
||||
|
||||
if (!crypto_init())
|
||||
return NULL;
|
||||
if (!crypto_init())
|
||||
return NULL;
|
||||
|
||||
ch = crypto_backend->hash_open(hash);
|
||||
if (ch)
|
||||
ch->algo = hash;
|
||||
ch = crypto_backend->hash_open(hash);
|
||||
if (ch)
|
||||
ch->algo = hash;
|
||||
|
||||
return ch;
|
||||
return ch;
|
||||
}
|
||||
|
||||
void crypto_hash_close(struct crypto_hash *ch)
|
||||
{
|
||||
ch->close(ch);
|
||||
ch->close(ch);
|
||||
}
|
||||
|
||||
void crypto_hash_write(struct crypto_hash *ch, const unsigned char *buf, size_t len)
|
||||
{
|
||||
ch->write(ch, buf, len);
|
||||
ch->write(ch, buf, len);
|
||||
}
|
||||
|
||||
unsigned char *crypto_hash_read(struct crypto_hash *ch)
|
||||
{
|
||||
return ch->read(ch);
|
||||
return ch->read(ch);
|
||||
}
|
||||
|
||||
size_t crypto_hash_get_size(const struct crypto_hash *ch)
|
||||
{
|
||||
return ch->get_size(ch);
|
||||
return ch->get_size(ch);
|
||||
}
|
||||
|
||||
struct crypto_pk *crypto_pk_open(enum crypto_algo_pk pk, ...)
|
||||
{
|
||||
struct crypto_pk *cp;
|
||||
va_list vl;
|
||||
struct crypto_pk *cp;
|
||||
va_list vl;
|
||||
|
||||
if (!crypto_init())
|
||||
return NULL;
|
||||
if (!crypto_init())
|
||||
return NULL;
|
||||
|
||||
va_start(vl, pk);
|
||||
cp = crypto_backend->pk_open(pk, vl);
|
||||
va_end(vl);
|
||||
va_start(vl, pk);
|
||||
cp = crypto_backend->pk_open(pk, vl);
|
||||
va_end(vl);
|
||||
|
||||
if (cp)
|
||||
cp->algo = pk;
|
||||
if (cp)
|
||||
cp->algo = pk;
|
||||
|
||||
return cp;
|
||||
return cp;
|
||||
}
|
||||
|
||||
struct crypto_pk *crypto_pk_open_priv(enum crypto_algo_pk pk, ...)
|
||||
{
|
||||
struct crypto_pk *cp;
|
||||
va_list vl;
|
||||
struct crypto_pk *cp;
|
||||
va_list vl;
|
||||
|
||||
if (!crypto_init())
|
||||
return NULL;
|
||||
if (!crypto_init())
|
||||
return NULL;
|
||||
|
||||
if (!crypto_backend->pk_open_priv)
|
||||
return NULL;
|
||||
if (!crypto_backend->pk_open_priv)
|
||||
return NULL;
|
||||
|
||||
va_start(vl, pk);
|
||||
cp = crypto_backend->pk_open_priv(pk, vl);
|
||||
va_end(vl);
|
||||
va_start(vl, pk);
|
||||
cp = crypto_backend->pk_open_priv(pk, vl);
|
||||
va_end(vl);
|
||||
|
||||
if (cp)
|
||||
cp->algo = pk;
|
||||
if (cp)
|
||||
cp->algo = pk;
|
||||
|
||||
return cp;
|
||||
return cp;
|
||||
}
|
||||
|
||||
struct crypto_pk *crypto_pk_genkey(enum crypto_algo_pk pk, ...)
|
||||
{
|
||||
struct crypto_pk *cp;
|
||||
va_list vl;
|
||||
struct crypto_pk *cp;
|
||||
va_list vl;
|
||||
|
||||
if (!crypto_init())
|
||||
return NULL;
|
||||
if (!crypto_init())
|
||||
return NULL;
|
||||
|
||||
if (!crypto_backend->pk_genkey)
|
||||
return NULL;
|
||||
if (!crypto_backend->pk_genkey)
|
||||
return NULL;
|
||||
|
||||
va_start(vl, pk);
|
||||
cp = crypto_backend->pk_genkey(pk, vl);
|
||||
va_end(vl);
|
||||
va_start(vl, pk);
|
||||
cp = crypto_backend->pk_genkey(pk, vl);
|
||||
va_end(vl);
|
||||
|
||||
if (cp)
|
||||
cp->algo = pk;
|
||||
if (cp)
|
||||
cp->algo = pk;
|
||||
|
||||
return cp;
|
||||
return cp;
|
||||
}
|
||||
|
||||
void crypto_pk_close(struct crypto_pk *cp)
|
||||
{
|
||||
cp->close(cp);
|
||||
cp->close(cp);
|
||||
}
|
||||
|
||||
unsigned char *crypto_pk_encrypt(const struct crypto_pk *cp, const unsigned char *buf, size_t len, size_t *clen)
|
||||
{
|
||||
return cp->encrypt(cp, buf, len, clen);
|
||||
return cp->encrypt(cp, buf, len, clen);
|
||||
}
|
||||
|
||||
unsigned char *crypto_pk_decrypt(const struct crypto_pk *cp, const unsigned char *buf, size_t len, size_t *clen)
|
||||
{
|
||||
if (!cp->decrypt) {
|
||||
*clen = 0;
|
||||
if (!cp->decrypt) {
|
||||
*clen = 0;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return cp->decrypt(cp, buf, len, clen);
|
||||
return cp->decrypt(cp, buf, len, clen);
|
||||
}
|
||||
|
||||
enum crypto_algo_pk crypto_pk_get_algo(const struct crypto_pk *cp)
|
||||
{
|
||||
if (!cp)
|
||||
return PK_INVALID;
|
||||
if (!cp)
|
||||
return PK_INVALID;
|
||||
|
||||
return cp->algo;
|
||||
return cp->algo;
|
||||
}
|
||||
|
||||
size_t crypto_pk_get_nbits(const struct crypto_pk *cp)
|
||||
{
|
||||
if (!cp->get_nbits)
|
||||
return 0;
|
||||
if (!cp->get_nbits)
|
||||
return 0;
|
||||
|
||||
return cp->get_nbits(cp);
|
||||
return cp->get_nbits(cp);
|
||||
}
|
||||
|
||||
unsigned char *crypto_pk_get_parameter(const struct crypto_pk *cp, unsigned param, size_t *plen)
|
||||
{
|
||||
*plen = 0;
|
||||
*plen = 0;
|
||||
|
||||
if (!cp->get_parameter)
|
||||
return NULL;
|
||||
if (!cp->get_parameter)
|
||||
return NULL;
|
||||
|
||||
return cp->get_parameter(cp, param, plen);
|
||||
return cp->get_parameter(cp, param, plen);
|
||||
}
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
#include <stddef.h>
|
||||
|
||||
enum crypto_algo_hash {
|
||||
HASH_INVALID,
|
||||
HASH_SHA_1,
|
||||
HASH_INVALID,
|
||||
HASH_SHA_1,
|
||||
};
|
||||
|
||||
struct crypto_hash *crypto_hash_open(enum crypto_algo_hash hash);
|
||||
|
@ -31,8 +31,8 @@ unsigned char *crypto_hash_read(struct crypto_hash *ch);
|
|||
size_t crypto_hash_get_size(const struct crypto_hash *ch);
|
||||
|
||||
enum crypto_algo_pk {
|
||||
PK_INVALID,
|
||||
PK_RSA,
|
||||
PK_INVALID,
|
||||
PK_RSA,
|
||||
};
|
||||
|
||||
struct crypto_pk *crypto_pk_open(enum crypto_algo_pk pk, ...);
|
||||
|
|
|
@ -22,27 +22,27 @@
|
|||
#include <stdarg.h>
|
||||
|
||||
struct crypto_hash {
|
||||
enum crypto_algo_hash algo;
|
||||
void (*write)(struct crypto_hash *ch, const unsigned char *buf, size_t len);
|
||||
unsigned char *(*read)(struct crypto_hash *ch);
|
||||
void (*close)(struct crypto_hash *ch);
|
||||
size_t (*get_size)(const struct crypto_hash *ch);
|
||||
enum crypto_algo_hash algo;
|
||||
void (*write)(struct crypto_hash *ch, const unsigned char *buf, size_t len);
|
||||
unsigned char *(*read)(struct crypto_hash *ch);
|
||||
void (*close)(struct crypto_hash *ch);
|
||||
size_t (*get_size)(const struct crypto_hash *ch);
|
||||
};
|
||||
|
||||
struct crypto_pk {
|
||||
enum crypto_algo_pk algo;
|
||||
unsigned char *(*encrypt)(const struct crypto_pk *cp, const unsigned char *buf, size_t len, size_t *clen);
|
||||
unsigned char *(*decrypt)(const struct crypto_pk *cp, const unsigned char *buf, size_t len, size_t *clen);
|
||||
unsigned char *(*get_parameter)(const struct crypto_pk *cp, unsigned param, size_t *plen);
|
||||
size_t (*get_nbits)(const struct crypto_pk *cp);
|
||||
void (*close)(struct crypto_pk *cp);
|
||||
enum crypto_algo_pk algo;
|
||||
unsigned char *(*encrypt)(const struct crypto_pk *cp, const unsigned char *buf, size_t len, size_t *clen);
|
||||
unsigned char *(*decrypt)(const struct crypto_pk *cp, const unsigned char *buf, size_t len, size_t *clen);
|
||||
unsigned char *(*get_parameter)(const struct crypto_pk *cp, unsigned param, size_t *plen);
|
||||
size_t (*get_nbits)(const struct crypto_pk *cp);
|
||||
void (*close)(struct crypto_pk *cp);
|
||||
};
|
||||
|
||||
struct crypto_backend {
|
||||
struct crypto_hash *(*hash_open)(enum crypto_algo_hash hash);
|
||||
struct crypto_pk *(*pk_open)(enum crypto_algo_pk pk, va_list vl);
|
||||
struct crypto_pk *(*pk_open_priv)(enum crypto_algo_pk pk, va_list vl);
|
||||
struct crypto_pk *(*pk_genkey)(enum crypto_algo_pk pk, va_list vl);
|
||||
struct crypto_hash *(*hash_open)(enum crypto_algo_hash hash);
|
||||
struct crypto_pk *(*pk_open)(enum crypto_algo_pk pk, va_list vl);
|
||||
struct crypto_pk *(*pk_open_priv)(enum crypto_algo_pk pk, va_list vl);
|
||||
struct crypto_pk *(*pk_genkey)(enum crypto_algo_pk pk, va_list vl);
|
||||
};
|
||||
|
||||
struct crypto_backend *crypto_polarssl_init(void);
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
|
||||
|
@ -30,132 +30,132 @@
|
|||
#include "mbedtls/sha1.h"
|
||||
|
||||
struct crypto_hash_polarssl {
|
||||
struct crypto_hash ch;
|
||||
mbedtls_sha1_context ctx;
|
||||
struct crypto_hash ch;
|
||||
mbedtls_sha1_context ctx;
|
||||
};
|
||||
|
||||
static void crypto_hash_polarssl_close(struct crypto_hash *_ch)
|
||||
{
|
||||
struct crypto_hash_polarssl *ch = (struct crypto_hash_polarssl *)_ch;
|
||||
struct crypto_hash_polarssl *ch = (struct crypto_hash_polarssl *)_ch;
|
||||
|
||||
free(ch);
|
||||
free(ch);
|
||||
}
|
||||
|
||||
static void crypto_hash_polarssl_write(struct crypto_hash *_ch, const unsigned char *buf, size_t len)
|
||||
{
|
||||
struct crypto_hash_polarssl *ch = (struct crypto_hash_polarssl *)_ch;
|
||||
struct crypto_hash_polarssl *ch = (struct crypto_hash_polarssl *)_ch;
|
||||
|
||||
mbedtls_sha1_update(&(ch->ctx), buf, len);
|
||||
mbedtls_sha1_update(&(ch->ctx), buf, len);
|
||||
}
|
||||
|
||||
static unsigned char *crypto_hash_polarssl_read(struct crypto_hash *_ch)
|
||||
{
|
||||
struct crypto_hash_polarssl *ch = (struct crypto_hash_polarssl *)_ch;
|
||||
struct crypto_hash_polarssl *ch = (struct crypto_hash_polarssl *)_ch;
|
||||
|
||||
static unsigned char sha1sum[20];
|
||||
mbedtls_sha1_finish(&(ch->ctx), sha1sum);
|
||||
return sha1sum;
|
||||
static unsigned char sha1sum[20];
|
||||
mbedtls_sha1_finish(&(ch->ctx), sha1sum);
|
||||
return sha1sum;
|
||||
}
|
||||
|
||||
static size_t crypto_hash_polarssl_get_size(const struct crypto_hash *ch)
|
||||
{
|
||||
if (ch->algo == HASH_SHA_1)
|
||||
return 20;
|
||||
else
|
||||
return 0;
|
||||
if (ch->algo == HASH_SHA_1)
|
||||
return 20;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct crypto_hash *crypto_hash_polarssl_open(enum crypto_algo_hash hash)
|
||||
{
|
||||
if (hash != HASH_SHA_1)
|
||||
return NULL;
|
||||
if (hash != HASH_SHA_1)
|
||||
return NULL;
|
||||
|
||||
struct crypto_hash_polarssl *ch = malloc(sizeof(*ch));
|
||||
struct crypto_hash_polarssl *ch = malloc(sizeof(*ch));
|
||||
|
||||
mbedtls_sha1_starts(&(ch->ctx));
|
||||
mbedtls_sha1_starts(&(ch->ctx));
|
||||
|
||||
ch->ch.write = crypto_hash_polarssl_write;
|
||||
ch->ch.read = crypto_hash_polarssl_read;
|
||||
ch->ch.close = crypto_hash_polarssl_close;
|
||||
ch->ch.get_size = crypto_hash_polarssl_get_size;
|
||||
ch->ch.write = crypto_hash_polarssl_write;
|
||||
ch->ch.read = crypto_hash_polarssl_read;
|
||||
ch->ch.close = crypto_hash_polarssl_close;
|
||||
ch->ch.get_size = crypto_hash_polarssl_get_size;
|
||||
|
||||
return &ch->ch;
|
||||
return &ch->ch;
|
||||
}
|
||||
|
||||
struct crypto_pk_polarssl {
|
||||
struct crypto_pk cp;
|
||||
mbedtls_rsa_context ctx;
|
||||
struct crypto_pk cp;
|
||||
mbedtls_rsa_context ctx;
|
||||
};
|
||||
|
||||
static struct crypto_pk *crypto_pk_polarssl_open_rsa(va_list vl)
|
||||
{
|
||||
struct crypto_pk_polarssl *cp = malloc(sizeof(*cp));
|
||||
memset(cp, 0x00, sizeof(*cp));
|
||||
struct crypto_pk_polarssl *cp = malloc(sizeof(*cp));
|
||||
memset(cp, 0x00, sizeof(*cp));
|
||||
|
||||
char *mod = va_arg(vl, char *); // N
|
||||
int modlen = va_arg(vl, size_t);
|
||||
char *exp = va_arg(vl, char *); // E
|
||||
int explen = va_arg(vl, size_t);
|
||||
char *mod = va_arg(vl, char *); // N
|
||||
int modlen = va_arg(vl, size_t);
|
||||
char *exp = va_arg(vl, char *); // E
|
||||
int explen = va_arg(vl, size_t);
|
||||
|
||||
mbedtls_rsa_init(&cp->ctx, MBEDTLS_RSA_PKCS_V15, 0);
|
||||
mbedtls_rsa_init(&cp->ctx, MBEDTLS_RSA_PKCS_V15, 0);
|
||||
|
||||
cp->ctx.len = modlen; // size(N) in bytes
|
||||
mbedtls_mpi_read_binary(&cp->ctx.N, (const unsigned char *)mod, modlen);
|
||||
mbedtls_mpi_read_binary(&cp->ctx.E, (const unsigned char *)exp, explen);
|
||||
cp->ctx.len = modlen; // size(N) in bytes
|
||||
mbedtls_mpi_read_binary(&cp->ctx.N, (const unsigned char *)mod, modlen);
|
||||
mbedtls_mpi_read_binary(&cp->ctx.E, (const unsigned char *)exp, explen);
|
||||
|
||||
int res = mbedtls_rsa_check_pubkey(&cp->ctx);
|
||||
if(res != 0) {
|
||||
fprintf(stderr, "PolarSSL public key error res=%x exp=%d mod=%d.\n", res * -1, explen, modlen);
|
||||
free(cp);
|
||||
return NULL;
|
||||
}
|
||||
int res = mbedtls_rsa_check_pubkey(&cp->ctx);
|
||||
if(res != 0) {
|
||||
fprintf(stderr, "PolarSSL public key error res=%x exp=%d mod=%d.\n", res * -1, explen, modlen);
|
||||
free(cp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &cp->cp;
|
||||
return &cp->cp;
|
||||
}
|
||||
|
||||
static struct crypto_pk *crypto_pk_polarssl_open_priv_rsa(va_list vl)
|
||||
{
|
||||
struct crypto_pk_polarssl *cp = malloc(sizeof(*cp));
|
||||
memset(cp, 0x00, sizeof(*cp));
|
||||
char *mod = va_arg(vl, char *);
|
||||
int modlen = va_arg(vl, size_t);
|
||||
char *exp = va_arg(vl, char *);
|
||||
int explen = va_arg(vl, size_t);
|
||||
char *d = va_arg(vl, char *);
|
||||
int dlen = va_arg(vl, size_t);
|
||||
char *p = va_arg(vl, char *);
|
||||
int plen = va_arg(vl, size_t);
|
||||
char *q = va_arg(vl, char *);
|
||||
int qlen = va_arg(vl, size_t);
|
||||
char *dp = va_arg(vl, char *);
|
||||
int dplen = va_arg(vl, size_t);
|
||||
char *dq = va_arg(vl, char *);
|
||||
int dqlen = va_arg(vl, size_t);
|
||||
// calc QP via Q and P
|
||||
// char *inv = va_arg(vl, char *);
|
||||
// int invlen = va_arg(vl, size_t);
|
||||
struct crypto_pk_polarssl *cp = malloc(sizeof(*cp));
|
||||
memset(cp, 0x00, sizeof(*cp));
|
||||
char *mod = va_arg(vl, char *);
|
||||
int modlen = va_arg(vl, size_t);
|
||||
char *exp = va_arg(vl, char *);
|
||||
int explen = va_arg(vl, size_t);
|
||||
char *d = va_arg(vl, char *);
|
||||
int dlen = va_arg(vl, size_t);
|
||||
char *p = va_arg(vl, char *);
|
||||
int plen = va_arg(vl, size_t);
|
||||
char *q = va_arg(vl, char *);
|
||||
int qlen = va_arg(vl, size_t);
|
||||
char *dp = va_arg(vl, char *);
|
||||
int dplen = va_arg(vl, size_t);
|
||||
char *dq = va_arg(vl, char *);
|
||||
int dqlen = va_arg(vl, size_t);
|
||||
// calc QP via Q and P
|
||||
// char *inv = va_arg(vl, char *);
|
||||
// int invlen = va_arg(vl, size_t);
|
||||
|
||||
mbedtls_rsa_init(&cp->ctx, MBEDTLS_RSA_PKCS_V15, 0);
|
||||
mbedtls_rsa_init(&cp->ctx, MBEDTLS_RSA_PKCS_V15, 0);
|
||||
|
||||
cp->ctx.len = modlen; // size(N) in bytes
|
||||
mbedtls_mpi_read_binary(&cp->ctx.N, (const unsigned char *)mod, modlen);
|
||||
mbedtls_mpi_read_binary(&cp->ctx.E, (const unsigned char *)exp, explen);
|
||||
cp->ctx.len = modlen; // size(N) in bytes
|
||||
mbedtls_mpi_read_binary(&cp->ctx.N, (const unsigned char *)mod, modlen);
|
||||
mbedtls_mpi_read_binary(&cp->ctx.E, (const unsigned char *)exp, explen);
|
||||
|
||||
mbedtls_mpi_read_binary(&cp->ctx.D, (const unsigned char *)d, dlen);
|
||||
mbedtls_mpi_read_binary(&cp->ctx.P, (const unsigned char *)p, plen);
|
||||
mbedtls_mpi_read_binary(&cp->ctx.Q, (const unsigned char *)q, qlen);
|
||||
mbedtls_mpi_read_binary(&cp->ctx.DP, (const unsigned char *)dp, dplen);
|
||||
mbedtls_mpi_read_binary(&cp->ctx.DQ, (const unsigned char *)dq, dqlen);
|
||||
mbedtls_mpi_inv_mod(&cp->ctx.QP, &cp->ctx.Q, &cp->ctx.P);
|
||||
mbedtls_mpi_read_binary(&cp->ctx.D, (const unsigned char *)d, dlen);
|
||||
mbedtls_mpi_read_binary(&cp->ctx.P, (const unsigned char *)p, plen);
|
||||
mbedtls_mpi_read_binary(&cp->ctx.Q, (const unsigned char *)q, qlen);
|
||||
mbedtls_mpi_read_binary(&cp->ctx.DP, (const unsigned char *)dp, dplen);
|
||||
mbedtls_mpi_read_binary(&cp->ctx.DQ, (const unsigned char *)dq, dqlen);
|
||||
mbedtls_mpi_inv_mod(&cp->ctx.QP, &cp->ctx.Q, &cp->ctx.P);
|
||||
|
||||
int res = mbedtls_rsa_check_privkey(&cp->ctx);
|
||||
if(res != 0) {
|
||||
fprintf(stderr, "PolarSSL private key error res=%x exp=%d mod=%d.\n", res * -1, explen, modlen);
|
||||
free(cp);
|
||||
return NULL;
|
||||
}
|
||||
int res = mbedtls_rsa_check_privkey(&cp->ctx);
|
||||
if(res != 0) {
|
||||
fprintf(stderr, "PolarSSL private key error res=%x exp=%d mod=%d.\n", res * -1, explen, modlen);
|
||||
free(cp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &cp->cp;
|
||||
return &cp->cp;
|
||||
}
|
||||
|
||||
static int myrand(void *rng_state, unsigned char *output, size_t len) {
|
||||
|
@ -173,184 +173,184 @@ static int myrand(void *rng_state, unsigned char *output, size_t len) {
|
|||
|
||||
static struct crypto_pk *crypto_pk_polarssl_genkey_rsa(va_list vl)
|
||||
{
|
||||
struct crypto_pk_polarssl *cp = malloc(sizeof(*cp));
|
||||
memset(cp, 0x00, sizeof(*cp));
|
||||
struct crypto_pk_polarssl *cp = malloc(sizeof(*cp));
|
||||
memset(cp, 0x00, sizeof(*cp));
|
||||
|
||||
int transient = va_arg(vl, int);
|
||||
unsigned int nbits = va_arg(vl, unsigned int);
|
||||
unsigned int exp = va_arg(vl, unsigned int);
|
||||
int transient = va_arg(vl, int);
|
||||
unsigned int nbits = va_arg(vl, unsigned int);
|
||||
unsigned int exp = va_arg(vl, unsigned int);
|
||||
|
||||
if (transient) {
|
||||
}
|
||||
if (transient) {
|
||||
}
|
||||
|
||||
int res = mbedtls_rsa_gen_key(&cp->ctx, &myrand, NULL, nbits, exp);
|
||||
if (res) {
|
||||
fprintf(stderr, "PolarSSL private key generation error res=%x exp=%d nbits=%d.\n", res * -1, exp, nbits);
|
||||
free(cp);
|
||||
return NULL;
|
||||
}
|
||||
int res = mbedtls_rsa_gen_key(&cp->ctx, &myrand, NULL, nbits, exp);
|
||||
if (res) {
|
||||
fprintf(stderr, "PolarSSL private key generation error res=%x exp=%d nbits=%d.\n", res * -1, exp, nbits);
|
||||
free(cp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &cp->cp;
|
||||
return &cp->cp;
|
||||
}
|
||||
|
||||
static void crypto_pk_polarssl_close(struct crypto_pk *_cp)
|
||||
{
|
||||
struct crypto_pk_polarssl *cp = (struct crypto_pk_polarssl *)_cp;
|
||||
struct crypto_pk_polarssl *cp = (struct crypto_pk_polarssl *)_cp;
|
||||
|
||||
mbedtls_rsa_free(&cp->ctx);
|
||||
free(cp);
|
||||
mbedtls_rsa_free(&cp->ctx);
|
||||
free(cp);
|
||||
}
|
||||
|
||||
static unsigned char *crypto_pk_polarssl_encrypt(const struct crypto_pk *_cp, const unsigned char *buf, size_t len, size_t *clen)
|
||||
{
|
||||
struct crypto_pk_polarssl *cp = (struct crypto_pk_polarssl *)_cp;
|
||||
int res;
|
||||
unsigned char *result;
|
||||
struct crypto_pk_polarssl *cp = (struct crypto_pk_polarssl *)_cp;
|
||||
int res;
|
||||
unsigned char *result;
|
||||
|
||||
*clen = 0;
|
||||
size_t keylen = mbedtls_mpi_size(&cp->ctx.N);
|
||||
*clen = 0;
|
||||
size_t keylen = mbedtls_mpi_size(&cp->ctx.N);
|
||||
|
||||
result = malloc(keylen);
|
||||
if (!result) {
|
||||
printf("RSA encrypt failed. Can't allocate result memory.\n");
|
||||
return NULL;
|
||||
}
|
||||
result = malloc(keylen);
|
||||
if (!result) {
|
||||
printf("RSA encrypt failed. Can't allocate result memory.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
res = mbedtls_rsa_public(&cp->ctx, buf, result);
|
||||
if(res) {
|
||||
printf("RSA encrypt failed. Error: %x data len: %zd key len: %zd\n", res * -1, len, keylen);
|
||||
free(result);
|
||||
return NULL;
|
||||
}
|
||||
res = mbedtls_rsa_public(&cp->ctx, buf, result);
|
||||
if(res) {
|
||||
printf("RSA encrypt failed. Error: %x data len: %zd key len: %zd\n", res * -1, len, keylen);
|
||||
free(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*clen = keylen;
|
||||
*clen = keylen;
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
static unsigned char *crypto_pk_polarssl_decrypt(const struct crypto_pk *_cp, const unsigned char *buf, size_t len, size_t *clen)
|
||||
{
|
||||
struct crypto_pk_polarssl *cp = (struct crypto_pk_polarssl *)_cp;
|
||||
int res;
|
||||
unsigned char *result;
|
||||
struct crypto_pk_polarssl *cp = (struct crypto_pk_polarssl *)_cp;
|
||||
int res;
|
||||
unsigned char *result;
|
||||
|
||||
*clen = 0;
|
||||
size_t keylen = mbedtls_mpi_size(&cp->ctx.N);
|
||||
*clen = 0;
|
||||
size_t keylen = mbedtls_mpi_size(&cp->ctx.N);
|
||||
|
||||
result = malloc(keylen);
|
||||
if (!result) {
|
||||
printf("RSA encrypt failed. Can't allocate result memory.\n");
|
||||
return NULL;
|
||||
}
|
||||
result = malloc(keylen);
|
||||
if (!result) {
|
||||
printf("RSA encrypt failed. Can't allocate result memory.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
res = mbedtls_rsa_private(&cp->ctx, NULL, NULL, buf, result); // CHECK???
|
||||
if(res) {
|
||||
printf("RSA decrypt failed. Error: %x data len: %zd key len: %zd\n", res * -1, len, keylen);
|
||||
free(result);
|
||||
return NULL;
|
||||
}
|
||||
res = mbedtls_rsa_private(&cp->ctx, NULL, NULL, buf, result); // CHECK???
|
||||
if(res) {
|
||||
printf("RSA decrypt failed. Error: %x data len: %zd key len: %zd\n", res * -1, len, keylen);
|
||||
free(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*clen = keylen;
|
||||
*clen = keylen;
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
static size_t crypto_pk_polarssl_get_nbits(const struct crypto_pk *_cp)
|
||||
{
|
||||
struct crypto_pk_polarssl *cp = (struct crypto_pk_polarssl *)_cp;
|
||||
struct crypto_pk_polarssl *cp = (struct crypto_pk_polarssl *)_cp;
|
||||
|
||||
return cp->ctx.len * 8;
|
||||
return cp->ctx.len * 8;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned char *crypto_pk_polarssl_get_parameter(const struct crypto_pk *_cp, unsigned param, size_t *plen)
|
||||
{
|
||||
struct crypto_pk_polarssl *cp = (struct crypto_pk_polarssl *)_cp;
|
||||
unsigned char *result = NULL;
|
||||
switch(param){
|
||||
// mod
|
||||
case 0:
|
||||
*plen = mbedtls_mpi_size(&cp->ctx.N);
|
||||
result = malloc(*plen);
|
||||
memset(result, 0x00, *plen);
|
||||
mbedtls_mpi_write_binary(&cp->ctx.N, result, *plen);
|
||||
break;
|
||||
// exp
|
||||
case 1:
|
||||
*plen = mbedtls_mpi_size(&cp->ctx.E);
|
||||
result = malloc(*plen);
|
||||
memset(result, 0x00, *plen);
|
||||
mbedtls_mpi_write_binary(&cp->ctx.E, result, *plen);
|
||||
break;
|
||||
default:
|
||||
printf("Error get parameter. Param=%d", param);
|
||||
break;
|
||||
}
|
||||
struct crypto_pk_polarssl *cp = (struct crypto_pk_polarssl *)_cp;
|
||||
unsigned char *result = NULL;
|
||||
switch(param){
|
||||
// mod
|
||||
case 0:
|
||||
*plen = mbedtls_mpi_size(&cp->ctx.N);
|
||||
result = malloc(*plen);
|
||||
memset(result, 0x00, *plen);
|
||||
mbedtls_mpi_write_binary(&cp->ctx.N, result, *plen);
|
||||
break;
|
||||
// exp
|
||||
case 1:
|
||||
*plen = mbedtls_mpi_size(&cp->ctx.E);
|
||||
result = malloc(*plen);
|
||||
memset(result, 0x00, *plen);
|
||||
mbedtls_mpi_write_binary(&cp->ctx.E, result, *plen);
|
||||
break;
|
||||
default:
|
||||
printf("Error get parameter. Param=%d", param);
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
static struct crypto_pk *crypto_pk_polarssl_open(enum crypto_algo_pk pk, va_list vl)
|
||||
{
|
||||
struct crypto_pk *cp;
|
||||
struct crypto_pk *cp;
|
||||
|
||||
if (pk == PK_RSA)
|
||||
cp = crypto_pk_polarssl_open_rsa(vl);
|
||||
else
|
||||
return NULL;
|
||||
if (pk == PK_RSA)
|
||||
cp = crypto_pk_polarssl_open_rsa(vl);
|
||||
else
|
||||
return NULL;
|
||||
|
||||
cp->close = crypto_pk_polarssl_close;
|
||||
cp->encrypt = crypto_pk_polarssl_encrypt;
|
||||
cp->get_parameter = crypto_pk_polarssl_get_parameter;
|
||||
cp->get_nbits = crypto_pk_polarssl_get_nbits;
|
||||
cp->close = crypto_pk_polarssl_close;
|
||||
cp->encrypt = crypto_pk_polarssl_encrypt;
|
||||
cp->get_parameter = crypto_pk_polarssl_get_parameter;
|
||||
cp->get_nbits = crypto_pk_polarssl_get_nbits;
|
||||
|
||||
return cp;
|
||||
return cp;
|
||||
}
|
||||
|
||||
static struct crypto_pk *crypto_pk_polarssl_open_priv(enum crypto_algo_pk pk, va_list vl)
|
||||
{
|
||||
struct crypto_pk *cp;
|
||||
struct crypto_pk *cp;
|
||||
|
||||
if (pk == PK_RSA)
|
||||
cp = crypto_pk_polarssl_open_priv_rsa(vl);
|
||||
else
|
||||
return NULL;
|
||||
if (pk == PK_RSA)
|
||||
cp = crypto_pk_polarssl_open_priv_rsa(vl);
|
||||
else
|
||||
return NULL;
|
||||
|
||||
cp->close = crypto_pk_polarssl_close;
|
||||
cp->encrypt = crypto_pk_polarssl_encrypt;
|
||||
cp->decrypt = crypto_pk_polarssl_decrypt;
|
||||
cp->get_parameter = crypto_pk_polarssl_get_parameter;
|
||||
cp->get_nbits = crypto_pk_polarssl_get_nbits;
|
||||
cp->close = crypto_pk_polarssl_close;
|
||||
cp->encrypt = crypto_pk_polarssl_encrypt;
|
||||
cp->decrypt = crypto_pk_polarssl_decrypt;
|
||||
cp->get_parameter = crypto_pk_polarssl_get_parameter;
|
||||
cp->get_nbits = crypto_pk_polarssl_get_nbits;
|
||||
|
||||
return cp;
|
||||
return cp;
|
||||
}
|
||||
|
||||
static struct crypto_pk *crypto_pk_polarssl_genkey(enum crypto_algo_pk pk, va_list vl)
|
||||
{
|
||||
struct crypto_pk *cp;
|
||||
struct crypto_pk *cp;
|
||||
|
||||
if (pk == PK_RSA)
|
||||
cp = crypto_pk_polarssl_genkey_rsa(vl);
|
||||
else
|
||||
return NULL;
|
||||
if (pk == PK_RSA)
|
||||
cp = crypto_pk_polarssl_genkey_rsa(vl);
|
||||
else
|
||||
return NULL;
|
||||
|
||||
cp->close = crypto_pk_polarssl_close;
|
||||
cp->encrypt = crypto_pk_polarssl_encrypt;
|
||||
cp->decrypt = crypto_pk_polarssl_decrypt;
|
||||
cp->get_parameter = crypto_pk_polarssl_get_parameter;
|
||||
cp->get_nbits = crypto_pk_polarssl_get_nbits;
|
||||
cp->close = crypto_pk_polarssl_close;
|
||||
cp->encrypt = crypto_pk_polarssl_encrypt;
|
||||
cp->decrypt = crypto_pk_polarssl_decrypt;
|
||||
cp->get_parameter = crypto_pk_polarssl_get_parameter;
|
||||
cp->get_nbits = crypto_pk_polarssl_get_nbits;
|
||||
|
||||
return cp;
|
||||
return cp;
|
||||
}
|
||||
|
||||
static struct crypto_backend crypto_polarssl_backend = {
|
||||
.hash_open = crypto_hash_polarssl_open,
|
||||
.pk_open = crypto_pk_polarssl_open,
|
||||
.pk_open_priv = crypto_pk_polarssl_open_priv,
|
||||
.pk_genkey = crypto_pk_polarssl_genkey,
|
||||
.hash_open = crypto_hash_polarssl_open,
|
||||
.pk_open = crypto_pk_polarssl_open,
|
||||
.pk_open_priv = crypto_pk_polarssl_open_priv,
|
||||
.pk_genkey = crypto_pk_polarssl_genkey,
|
||||
};
|
||||
|
||||
struct crypto_backend *crypto_polarssl_init(void)
|
||||
{
|
||||
return &crypto_polarssl_backend;
|
||||
return &crypto_polarssl_backend;
|
||||
}
|
||||
|
|
156
client/emv/dol.c
156
client/emv/dol.c
|
@ -25,111 +25,111 @@
|
|||
|
||||
static size_t dol_calculate_len(const struct tlv *tlv, size_t data_len)
|
||||
{
|
||||
if (!tlv)
|
||||
return 0;
|
||||
if (!tlv)
|
||||
return 0;
|
||||
|
||||
const unsigned char *buf = tlv->value;
|
||||
size_t left = tlv->len;
|
||||
size_t count = 0;
|
||||
const unsigned char *buf = tlv->value;
|
||||
size_t left = tlv->len;
|
||||
size_t count = 0;
|
||||
|
||||
while (left) {
|
||||
struct tlv tlv;
|
||||
if (!tlv_parse_tl(&buf, &left, &tlv))
|
||||
return 0;
|
||||
while (left) {
|
||||
struct tlv tlv;
|
||||
if (!tlv_parse_tl(&buf, &left, &tlv))
|
||||
return 0;
|
||||
|
||||
count += tlv.len;
|
||||
count += tlv.len;
|
||||
|
||||
/* Last tag can be of variable length */
|
||||
if (tlv.len == 0 && left == 0)
|
||||
count = data_len;
|
||||
}
|
||||
/* Last tag can be of variable length */
|
||||
if (tlv.len == 0 && left == 0)
|
||||
count = data_len;
|
||||
}
|
||||
|
||||
return count;
|
||||
return count;
|
||||
}
|
||||
|
||||
struct tlv *dol_process(const struct tlv *tlv, const struct tlvdb *tlvdb, tlv_tag_t tag)
|
||||
{
|
||||
size_t res_len;
|
||||
if (!tlv || !(res_len = dol_calculate_len(tlv, 0))) {
|
||||
struct tlv *res_tlv = malloc(sizeof(*res_tlv));
|
||||
size_t res_len;
|
||||
if (!tlv || !(res_len = dol_calculate_len(tlv, 0))) {
|
||||
struct tlv *res_tlv = malloc(sizeof(*res_tlv));
|
||||
|
||||
res_tlv->tag = tag;
|
||||
res_tlv->len = 0;
|
||||
res_tlv->value = NULL;
|
||||
res_tlv->tag = tag;
|
||||
res_tlv->len = 0;
|
||||
res_tlv->value = NULL;
|
||||
|
||||
return res_tlv;
|
||||
}
|
||||
return res_tlv;
|
||||
}
|
||||
|
||||
struct tlv *res_tlv = malloc(sizeof(*res_tlv) + res_len);
|
||||
if (!res_tlv)
|
||||
return NULL;
|
||||
struct tlv *res_tlv = malloc(sizeof(*res_tlv) + res_len);
|
||||
if (!res_tlv)
|
||||
return NULL;
|
||||
|
||||
const unsigned char *buf = tlv->value;
|
||||
size_t left = tlv->len;
|
||||
unsigned char *res = (unsigned char *)(res_tlv + 1);
|
||||
size_t pos = 0;
|
||||
const unsigned char *buf = tlv->value;
|
||||
size_t left = tlv->len;
|
||||
unsigned char *res = (unsigned char *)(res_tlv + 1);
|
||||
size_t pos = 0;
|
||||
|
||||
while (left) {
|
||||
struct tlv cur_tlv;
|
||||
if (!tlv_parse_tl(&buf, &left, &cur_tlv) || pos + cur_tlv.len > res_len) {
|
||||
free(res_tlv);
|
||||
while (left) {
|
||||
struct tlv cur_tlv;
|
||||
if (!tlv_parse_tl(&buf, &left, &cur_tlv) || pos + cur_tlv.len > res_len) {
|
||||
free(res_tlv);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct tlv *tag_tlv = tlvdb_get(tlvdb, cur_tlv.tag, NULL);
|
||||
if (!tag_tlv) {
|
||||
memset(res + pos, 0, cur_tlv.len);
|
||||
} else if (tag_tlv->len > cur_tlv.len) {
|
||||
memcpy(res + pos, tag_tlv->value, cur_tlv.len);
|
||||
} else {
|
||||
// FIXME: cn data should be padded with 0xFF !!!
|
||||
memcpy(res + pos, tag_tlv->value, tag_tlv->len);
|
||||
memset(res + pos + tag_tlv->len, 0, cur_tlv.len - tag_tlv->len);
|
||||
}
|
||||
pos += cur_tlv.len;
|
||||
}
|
||||
const struct tlv *tag_tlv = tlvdb_get(tlvdb, cur_tlv.tag, NULL);
|
||||
if (!tag_tlv) {
|
||||
memset(res + pos, 0, cur_tlv.len);
|
||||
} else if (tag_tlv->len > cur_tlv.len) {
|
||||
memcpy(res + pos, tag_tlv->value, cur_tlv.len);
|
||||
} else {
|
||||
// FIXME: cn data should be padded with 0xFF !!!
|
||||
memcpy(res + pos, tag_tlv->value, tag_tlv->len);
|
||||
memset(res + pos + tag_tlv->len, 0, cur_tlv.len - tag_tlv->len);
|
||||
}
|
||||
pos += cur_tlv.len;
|
||||
}
|
||||
|
||||
res_tlv->tag = tag;
|
||||
res_tlv->len = res_len;
|
||||
res_tlv->value = res;
|
||||
res_tlv->tag = tag;
|
||||
res_tlv->len = res_len;
|
||||
res_tlv->value = res;
|
||||
|
||||
return res_tlv;
|
||||
return res_tlv;
|
||||
}
|
||||
|
||||
struct tlvdb *dol_parse(const struct tlv *tlv, const unsigned char *data, size_t data_len)
|
||||
{
|
||||
if (!tlv)
|
||||
return NULL;
|
||||
if (!tlv)
|
||||
return NULL;
|
||||
|
||||
const unsigned char *buf = tlv->value;
|
||||
size_t left = tlv->len;
|
||||
size_t res_len = dol_calculate_len(tlv, data_len);
|
||||
size_t pos = 0;
|
||||
struct tlvdb *db = NULL;
|
||||
const unsigned char *buf = tlv->value;
|
||||
size_t left = tlv->len;
|
||||
size_t res_len = dol_calculate_len(tlv, data_len);
|
||||
size_t pos = 0;
|
||||
struct tlvdb *db = NULL;
|
||||
|
||||
if (res_len != data_len)
|
||||
return NULL;
|
||||
if (res_len != data_len)
|
||||
return NULL;
|
||||
|
||||
while (left) {
|
||||
struct tlv cur_tlv;
|
||||
if (!tlv_parse_tl(&buf, &left, &cur_tlv) || pos + cur_tlv.len > res_len) {
|
||||
tlvdb_free(db);
|
||||
return NULL;
|
||||
}
|
||||
while (left) {
|
||||
struct tlv cur_tlv;
|
||||
if (!tlv_parse_tl(&buf, &left, &cur_tlv) || pos + cur_tlv.len > res_len) {
|
||||
tlvdb_free(db);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Last tag can be of variable length */
|
||||
if (cur_tlv.len == 0 && left == 0)
|
||||
cur_tlv.len = res_len - pos;
|
||||
/* Last tag can be of variable length */
|
||||
if (cur_tlv.len == 0 && left == 0)
|
||||
cur_tlv.len = res_len - pos;
|
||||
|
||||
struct tlvdb *tag_db = tlvdb_fixed(cur_tlv.tag, cur_tlv.len, data + pos);
|
||||
if (!db)
|
||||
db = tag_db;
|
||||
else
|
||||
tlvdb_add(db, tag_db);
|
||||
struct tlvdb *tag_db = tlvdb_fixed(cur_tlv.tag, cur_tlv.len, data + pos);
|
||||
if (!db)
|
||||
db = tag_db;
|
||||
else
|
||||
tlvdb_add(db, tag_db);
|
||||
|
||||
pos += cur_tlv.len;
|
||||
}
|
||||
pos += cur_tlv.len;
|
||||
}
|
||||
|
||||
return db;
|
||||
return db;
|
||||
}
|
||||
|
|
|
@ -20,40 +20,40 @@
|
|||
#include "dump.h"
|
||||
|
||||
|
||||
#define PRINT_INDENT(level) {for (int i = 0; i < (level); i++) fprintf(f, " ");}
|
||||
#define PRINT_INDENT(level) {for (int i = 0; i < (level); i++) fprintf(f, " ");}
|
||||
|
||||
void dump_buffer_simple(const unsigned char *ptr, size_t len, FILE *f)
|
||||
{
|
||||
int i;
|
||||
int i;
|
||||
|
||||
if (!f)
|
||||
f = stdout;
|
||||
if (!f)
|
||||
f = stdout;
|
||||
|
||||
for (i = 0; i < len; i ++)
|
||||
fprintf(f, "%s%02hhX", i ? " " : "", ptr[i]);
|
||||
for (i = 0; i < len; i ++)
|
||||
fprintf(f, "%s%02hhX", i ? " " : "", ptr[i]);
|
||||
}
|
||||
|
||||
void dump_buffer(const unsigned char *ptr, size_t len, FILE *f, int level)
|
||||
{
|
||||
int i, j;
|
||||
int i, j;
|
||||
|
||||
if (!f)
|
||||
f = stdout;
|
||||
if (!f)
|
||||
f = stdout;
|
||||
|
||||
for (i = 0; i < len; i += 16) {
|
||||
PRINT_INDENT(level);
|
||||
fprintf(f, "\t%02x:", i);
|
||||
for (j = 0; j < 16; j++) {
|
||||
if (i + j < len)
|
||||
fprintf(f, " %02hhx", ptr[i + j]);
|
||||
else
|
||||
fprintf(f, " ");
|
||||
}
|
||||
fprintf(f, " |");
|
||||
for (j = 0; j < 16 && i + j < len; j++) {
|
||||
fprintf(f, "%c", (ptr[i+j] >= 0x20 && ptr[i+j] < 0x7f) ? ptr[i+j] : '.' );
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
for (i = 0; i < len; i += 16) {
|
||||
PRINT_INDENT(level);
|
||||
fprintf(f, "\t%02x:", i);
|
||||
for (j = 0; j < 16; j++) {
|
||||
if (i + j < len)
|
||||
fprintf(f, " %02hhx", ptr[i + j]);
|
||||
else
|
||||
fprintf(f, " ");
|
||||
}
|
||||
fprintf(f, " |");
|
||||
for (j = 0; j < 16 && i + j < len; j++) {
|
||||
fprintf(f, "%c", (ptr[i+j] >= 0x20 && ptr[i+j] < 0x7f) ? ptr[i+j] : '.' );
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,488 +31,488 @@
|
|||
#include <sys/types.h>
|
||||
|
||||
#define BCD(c) (((c) >= '0' && (c) <= '9') ? ((c) - '0') : \
|
||||
-1)
|
||||
-1)
|
||||
|
||||
#define HEX(c) (((c) >= '0' && (c) <= '9') ? ((c) - '0') : \
|
||||
((c) >= 'A' && (c) <= 'F') ? ((c) - 'A' + 10) : \
|
||||
((c) >= 'a' && (c) <= 'f') ? ((c) - 'a' + 10) : \
|
||||
-1)
|
||||
((c) >= 'A' && (c) <= 'F') ? ((c) - 'A' + 10) : \
|
||||
((c) >= 'a' && (c) <= 'f') ? ((c) - 'a' + 10) : \
|
||||
-1)
|
||||
|
||||
#define TOHEX(v) ((v) < 10 ? (v) + '0' : (v) - 10 + 'a')
|
||||
|
||||
static ssize_t emv_pk_read_bin(char *buf, unsigned char *bin, size_t size, size_t *read)
|
||||
{
|
||||
size_t left = size;
|
||||
char *p = buf;
|
||||
while (*p && *p == ' ')
|
||||
p++;
|
||||
size_t left = size;
|
||||
char *p = buf;
|
||||
while (*p && *p == ' ')
|
||||
p++;
|
||||
|
||||
while (left > 0) {
|
||||
int c1, c2;
|
||||
c1 = HEX(*p);
|
||||
if (c1 == -1)
|
||||
return -(p - buf);
|
||||
p++;
|
||||
c2 = HEX(*p);
|
||||
if (c2 == -1)
|
||||
return -(p - buf);
|
||||
p++;
|
||||
*bin = (c1 * 16 + c2);
|
||||
bin ++;
|
||||
left --;
|
||||
if (*p == ':')
|
||||
p++;
|
||||
else if (read) {
|
||||
*read = (size - left);
|
||||
break;
|
||||
} else if (left == 0)
|
||||
break;
|
||||
else
|
||||
return -(p - buf);
|
||||
}
|
||||
while (left > 0) {
|
||||
int c1, c2;
|
||||
c1 = HEX(*p);
|
||||
if (c1 == -1)
|
||||
return -(p - buf);
|
||||
p++;
|
||||
c2 = HEX(*p);
|
||||
if (c2 == -1)
|
||||
return -(p - buf);
|
||||
p++;
|
||||
*bin = (c1 * 16 + c2);
|
||||
bin ++;
|
||||
left --;
|
||||
if (*p == ':')
|
||||
p++;
|
||||
else if (read) {
|
||||
*read = (size - left);
|
||||
break;
|
||||
} else if (left == 0)
|
||||
break;
|
||||
else
|
||||
return -(p - buf);
|
||||
}
|
||||
|
||||
while (*p && *p == ' ')
|
||||
p++;
|
||||
while (*p && *p == ' ')
|
||||
p++;
|
||||
|
||||
p--;
|
||||
p--;
|
||||
|
||||
return (p - buf);
|
||||
return (p - buf);
|
||||
}
|
||||
|
||||
static ssize_t emv_pk_read_ymv(char *buf, unsigned *ymv)
|
||||
{
|
||||
int i;
|
||||
unsigned char temp[3];
|
||||
char *p = buf;
|
||||
int i;
|
||||
unsigned char temp[3];
|
||||
char *p = buf;
|
||||
|
||||
*ymv = 0;
|
||||
*ymv = 0;
|
||||
|
||||
while (*p && *p == ' ')
|
||||
p++;
|
||||
while (*p && *p == ' ')
|
||||
p++;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
int c1, c2;
|
||||
c1 = BCD(*p);
|
||||
if (c1 == -1)
|
||||
return -(p - buf);
|
||||
p++;
|
||||
c2 = BCD(*p);
|
||||
if (c2 == -1)
|
||||
return -(p - buf);
|
||||
p++;
|
||||
temp[i] = (c1 * 16 + c2);
|
||||
}
|
||||
for (i = 0; i < 3; i++) {
|
||||
int c1, c2;
|
||||
c1 = BCD(*p);
|
||||
if (c1 == -1)
|
||||
return -(p - buf);
|
||||
p++;
|
||||
c2 = BCD(*p);
|
||||
if (c2 == -1)
|
||||
return -(p - buf);
|
||||
p++;
|
||||
temp[i] = (c1 * 16 + c2);
|
||||
}
|
||||
|
||||
while (*p && *p == ' ')
|
||||
p++;
|
||||
while (*p && *p == ' ')
|
||||
p++;
|
||||
|
||||
p--;
|
||||
p--;
|
||||
|
||||
if (temp[1] > 0x12 || temp[2] > 0x31)
|
||||
return -(p - buf);
|
||||
if (temp[1] > 0x12 || temp[2] > 0x31)
|
||||
return -(p - buf);
|
||||
|
||||
*ymv = (temp[0] * 0x10000 + temp[1] * 0x100 + temp[2]);
|
||||
*ymv = (temp[0] * 0x10000 + temp[1] * 0x100 + temp[2]);
|
||||
|
||||
return (p - buf);
|
||||
return (p - buf);
|
||||
}
|
||||
|
||||
static ssize_t emv_pk_read_string(char *buf, char *str, size_t size)
|
||||
{
|
||||
char *p = buf;
|
||||
while (*p && *p == ' ')
|
||||
p++;
|
||||
char *p = buf;
|
||||
while (*p && *p == ' ')
|
||||
p++;
|
||||
|
||||
while (size > 1) {
|
||||
if (*p == ' ')
|
||||
break;
|
||||
else if (*p < 0x20 || *p >= 0x7f)
|
||||
return -(p - buf);
|
||||
*str = *p;
|
||||
p++;
|
||||
str ++;
|
||||
size --;
|
||||
}
|
||||
while (size > 1) {
|
||||
if (*p == ' ')
|
||||
break;
|
||||
else if (*p < 0x20 || *p >= 0x7f)
|
||||
return -(p - buf);
|
||||
*str = *p;
|
||||
p++;
|
||||
str ++;
|
||||
size --;
|
||||
}
|
||||
|
||||
*str = 0;
|
||||
*str = 0;
|
||||
|
||||
while (*p && *p == ' ')
|
||||
p++;
|
||||
while (*p && *p == ' ')
|
||||
p++;
|
||||
|
||||
p--;
|
||||
p--;
|
||||
|
||||
return (p - buf);
|
||||
return (p - buf);
|
||||
}
|
||||
|
||||
|
||||
struct emv_pk *emv_pk_parse_pk(char *buf)
|
||||
{
|
||||
struct emv_pk *r = calloc(1, sizeof(*r));
|
||||
ssize_t l;
|
||||
char temp[10];
|
||||
struct emv_pk *r = calloc(1, sizeof(*r));
|
||||
ssize_t l;
|
||||
char temp[10];
|
||||
|
||||
l = emv_pk_read_bin(buf, r->rid, 5, NULL);
|
||||
if (l <= 0)
|
||||
goto out;
|
||||
buf += l;
|
||||
l = emv_pk_read_bin(buf, r->rid, 5, NULL);
|
||||
if (l <= 0)
|
||||
goto out;
|
||||
buf += l;
|
||||
|
||||
l = emv_pk_read_bin(buf, &r->index, 1, NULL);
|
||||
if (l <= 0)
|
||||
goto out;
|
||||
buf += l;
|
||||
l = emv_pk_read_bin(buf, &r->index, 1, NULL);
|
||||
if (l <= 0)
|
||||
goto out;
|
||||
buf += l;
|
||||
|
||||
l = emv_pk_read_ymv(buf, &r->expire);
|
||||
if (l <= 0)
|
||||
goto out;
|
||||
buf += l;
|
||||
l = emv_pk_read_ymv(buf, &r->expire);
|
||||
if (l <= 0)
|
||||
goto out;
|
||||
buf += l;
|
||||
|
||||
l = emv_pk_read_string(buf, temp, sizeof(temp));
|
||||
if (l <= 0)
|
||||
goto out;
|
||||
buf += l;
|
||||
l = emv_pk_read_string(buf, temp, sizeof(temp));
|
||||
if (l <= 0)
|
||||
goto out;
|
||||
buf += l;
|
||||
|
||||
if (!strcmp(temp, "rsa"))
|
||||
r->pk_algo = PK_RSA;
|
||||
else
|
||||
goto out;
|
||||
if (!strcmp(temp, "rsa"))
|
||||
r->pk_algo = PK_RSA;
|
||||
else
|
||||
goto out;
|
||||
|
||||
l = emv_pk_read_bin(buf, r->exp, sizeof(r->exp), &r->elen);
|
||||
if (l <= 0)
|
||||
goto out;
|
||||
buf += l;
|
||||
l = emv_pk_read_bin(buf, r->exp, sizeof(r->exp), &r->elen);
|
||||
if (l <= 0)
|
||||
goto out;
|
||||
buf += l;
|
||||
|
||||
r->modulus = malloc(2048/8);
|
||||
l = emv_pk_read_bin(buf, r->modulus, 2048/8, &r->mlen);
|
||||
if (l <= 0)
|
||||
goto out2;
|
||||
buf += l;
|
||||
r->modulus = malloc(2048/8);
|
||||
l = emv_pk_read_bin(buf, r->modulus, 2048/8, &r->mlen);
|
||||
if (l <= 0)
|
||||
goto out2;
|
||||
buf += l;
|
||||
|
||||
l = emv_pk_read_string(buf, temp, sizeof(temp));
|
||||
if (l <= 0)
|
||||
goto out2;
|
||||
buf += l;
|
||||
l = emv_pk_read_string(buf, temp, sizeof(temp));
|
||||
if (l <= 0)
|
||||
goto out2;
|
||||
buf += l;
|
||||
|
||||
if (!strcmp(temp, "sha1"))
|
||||
r->hash_algo = HASH_SHA_1;
|
||||
else
|
||||
goto out2;
|
||||
if (!strcmp(temp, "sha1"))
|
||||
r->hash_algo = HASH_SHA_1;
|
||||
else
|
||||
goto out2;
|
||||
|
||||
l = emv_pk_read_bin(buf, r->hash, 20, NULL);
|
||||
if (l <= 0)
|
||||
goto out2;
|
||||
l = emv_pk_read_bin(buf, r->hash, 20, NULL);
|
||||
if (l <= 0)
|
||||
goto out2;
|
||||
|
||||
return r;
|
||||
return r;
|
||||
|
||||
out2:
|
||||
free(r->modulus);
|
||||
free(r->modulus);
|
||||
out:
|
||||
free(r);
|
||||
return NULL;
|
||||
free(r);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static size_t emv_pk_write_bin(char *out, size_t outlen, const unsigned char *buf, size_t len)
|
||||
{
|
||||
int i;
|
||||
size_t pos = 0;
|
||||
int i;
|
||||
size_t pos = 0;
|
||||
|
||||
if (len == 0)
|
||||
return 0;
|
||||
if (outlen < len * 3)
|
||||
return 0;
|
||||
if (len == 0)
|
||||
return 0;
|
||||
if (outlen < len * 3)
|
||||
return 0;
|
||||
|
||||
out[pos++] = TOHEX(buf[0] >> 4);
|
||||
out[pos++] = TOHEX(buf[0] & 0xf);
|
||||
for (i = 1; i < len; i++) {
|
||||
out[pos++] = ':';
|
||||
out[pos++] = TOHEX(buf[i] >> 4);
|
||||
out[pos++] = TOHEX(buf[i] & 0xf);
|
||||
}
|
||||
out[pos++] = ' ';
|
||||
out[pos++] = TOHEX(buf[0] >> 4);
|
||||
out[pos++] = TOHEX(buf[0] & 0xf);
|
||||
for (i = 1; i < len; i++) {
|
||||
out[pos++] = ':';
|
||||
out[pos++] = TOHEX(buf[i] >> 4);
|
||||
out[pos++] = TOHEX(buf[i] & 0xf);
|
||||
}
|
||||
out[pos++] = ' ';
|
||||
|
||||
return pos;
|
||||
return pos;
|
||||
}
|
||||
|
||||
static size_t emv_pk_write_str(char *out, size_t outlen, const char *str)
|
||||
{
|
||||
size_t len = strlen(str);
|
||||
size_t len = strlen(str);
|
||||
|
||||
if (len == 0)
|
||||
return 0;
|
||||
if (outlen < len)
|
||||
return 0;
|
||||
if (len == 0)
|
||||
return 0;
|
||||
if (outlen < len)
|
||||
return 0;
|
||||
|
||||
memcpy(out, str, len);
|
||||
memcpy(out, str, len);
|
||||
|
||||
return len;
|
||||
return len;
|
||||
}
|
||||
|
||||
char *emv_pk_dump_pk(const struct emv_pk *pk)
|
||||
{
|
||||
size_t outsize = 1024; /* should be enough */
|
||||
char *out = malloc(outsize); /* should be enough */
|
||||
size_t outpos = 0;
|
||||
size_t rc;
|
||||
size_t outsize = 1024; /* should be enough */
|
||||
char *out = malloc(outsize); /* should be enough */
|
||||
size_t outpos = 0;
|
||||
size_t rc;
|
||||
|
||||
if (!out)
|
||||
return NULL;
|
||||
if (!out)
|
||||
return NULL;
|
||||
|
||||
rc = emv_pk_write_bin(out + outpos, outsize - outpos, pk->rid, 5);
|
||||
if (rc == 0)
|
||||
goto err;
|
||||
outpos += rc;
|
||||
rc = emv_pk_write_bin(out + outpos, outsize - outpos, pk->rid, 5);
|
||||
if (rc == 0)
|
||||
goto err;
|
||||
outpos += rc;
|
||||
|
||||
rc = emv_pk_write_bin(out + outpos, outsize - outpos, &pk->index, 1);
|
||||
if (rc == 0)
|
||||
goto err;
|
||||
outpos += rc;
|
||||
rc = emv_pk_write_bin(out + outpos, outsize - outpos, &pk->index, 1);
|
||||
if (rc == 0)
|
||||
goto err;
|
||||
outpos += rc;
|
||||
|
||||
if (outpos + 7 > outsize)
|
||||
goto err;
|
||||
out[outpos++] = TOHEX((pk->expire >> 20) & 0xf);
|
||||
out[outpos++] = TOHEX((pk->expire >> 16) & 0xf);
|
||||
out[outpos++] = TOHEX((pk->expire >> 12) & 0xf);
|
||||
out[outpos++] = TOHEX((pk->expire >> 8 ) & 0xf);
|
||||
out[outpos++] = TOHEX((pk->expire >> 4 ) & 0xf);
|
||||
out[outpos++] = TOHEX((pk->expire >> 0 ) & 0xf);
|
||||
out[outpos++] = ' ';
|
||||
if (outpos + 7 > outsize)
|
||||
goto err;
|
||||
out[outpos++] = TOHEX((pk->expire >> 20) & 0xf);
|
||||
out[outpos++] = TOHEX((pk->expire >> 16) & 0xf);
|
||||
out[outpos++] = TOHEX((pk->expire >> 12) & 0xf);
|
||||
out[outpos++] = TOHEX((pk->expire >> 8 ) & 0xf);
|
||||
out[outpos++] = TOHEX((pk->expire >> 4 ) & 0xf);
|
||||
out[outpos++] = TOHEX((pk->expire >> 0 ) & 0xf);
|
||||
out[outpos++] = ' ';
|
||||
|
||||
if (pk->pk_algo == PK_RSA) {
|
||||
rc = emv_pk_write_str(out + outpos, outsize - outpos, "rsa");
|
||||
if (rc == 0)
|
||||
goto err;
|
||||
outpos += rc;
|
||||
out[outpos++] = ' ';
|
||||
} else {
|
||||
if (outpos + 4 > outsize)
|
||||
goto err;
|
||||
out[outpos++] = '?';
|
||||
out[outpos++] = '?';
|
||||
out[outpos++] = TOHEX(pk->pk_algo >> 4);
|
||||
out[outpos++] = TOHEX(pk->pk_algo & 0xf);
|
||||
}
|
||||
if (pk->pk_algo == PK_RSA) {
|
||||
rc = emv_pk_write_str(out + outpos, outsize - outpos, "rsa");
|
||||
if (rc == 0)
|
||||
goto err;
|
||||
outpos += rc;
|
||||
out[outpos++] = ' ';
|
||||
} else {
|
||||
if (outpos + 4 > outsize)
|
||||
goto err;
|
||||
out[outpos++] = '?';
|
||||
out[outpos++] = '?';
|
||||
out[outpos++] = TOHEX(pk->pk_algo >> 4);
|
||||
out[outpos++] = TOHEX(pk->pk_algo & 0xf);
|
||||
}
|
||||
|
||||
rc = emv_pk_write_bin(out + outpos, outsize - outpos, pk->exp, pk->elen);
|
||||
if (rc == 0)
|
||||
goto err;
|
||||
outpos += rc;
|
||||
rc = emv_pk_write_bin(out + outpos, outsize - outpos, pk->exp, pk->elen);
|
||||
if (rc == 0)
|
||||
goto err;
|
||||
outpos += rc;
|
||||
|
||||
rc = emv_pk_write_bin(out + outpos, outsize - outpos, pk->modulus, pk->mlen);
|
||||
if (rc == 0)
|
||||
goto err;
|
||||
outpos += rc;
|
||||
rc = emv_pk_write_bin(out + outpos, outsize - outpos, pk->modulus, pk->mlen);
|
||||
if (rc == 0)
|
||||
goto err;
|
||||
outpos += rc;
|
||||
|
||||
if (pk->hash_algo == HASH_SHA_1) {
|
||||
rc = emv_pk_write_str(out + outpos, outsize - outpos, "sha1");
|
||||
if (rc == 0)
|
||||
goto err;
|
||||
outpos += rc;
|
||||
out[outpos++] = ' ';
|
||||
} else {
|
||||
if (outpos + 4 > outsize)
|
||||
goto err;
|
||||
out[outpos++] = '?';
|
||||
out[outpos++] = '?';
|
||||
out[outpos++] = TOHEX(pk->pk_algo >> 4);
|
||||
out[outpos++] = TOHEX(pk->pk_algo & 0xf);
|
||||
}
|
||||
if (pk->hash_algo == HASH_SHA_1) {
|
||||
rc = emv_pk_write_str(out + outpos, outsize - outpos, "sha1");
|
||||
if (rc == 0)
|
||||
goto err;
|
||||
outpos += rc;
|
||||
out[outpos++] = ' ';
|
||||
} else {
|
||||
if (outpos + 4 > outsize)
|
||||
goto err;
|
||||
out[outpos++] = '?';
|
||||
out[outpos++] = '?';
|
||||
out[outpos++] = TOHEX(pk->pk_algo >> 4);
|
||||
out[outpos++] = TOHEX(pk->pk_algo & 0xf);
|
||||
}
|
||||
|
||||
|
||||
rc = emv_pk_write_bin(out + outpos, outsize - outpos, pk->hash, 20);
|
||||
if (rc == 0)
|
||||
goto err;
|
||||
outpos += rc;
|
||||
rc = emv_pk_write_bin(out + outpos, outsize - outpos, pk->hash, 20);
|
||||
if (rc == 0)
|
||||
goto err;
|
||||
outpos += rc;
|
||||
|
||||
out[outpos-1] = '\0';
|
||||
out[outpos-1] = '\0';
|
||||
|
||||
return out;
|
||||
return out;
|
||||
|
||||
err:
|
||||
free(out);
|
||||
return NULL;
|
||||
free(out);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool emv_pk_verify(const struct emv_pk *pk)
|
||||
{
|
||||
struct crypto_hash *ch = crypto_hash_open(pk->hash_algo);
|
||||
if (!ch)
|
||||
return false;
|
||||
struct crypto_hash *ch = crypto_hash_open(pk->hash_algo);
|
||||
if (!ch)
|
||||
return false;
|
||||
|
||||
crypto_hash_write(ch, pk->rid, sizeof(pk->rid));
|
||||
crypto_hash_write(ch, &pk->index, 1);
|
||||
crypto_hash_write(ch, pk->modulus, pk->mlen);
|
||||
crypto_hash_write(ch, pk->exp, pk->elen);
|
||||
crypto_hash_write(ch, pk->rid, sizeof(pk->rid));
|
||||
crypto_hash_write(ch, &pk->index, 1);
|
||||
crypto_hash_write(ch, pk->modulus, pk->mlen);
|
||||
crypto_hash_write(ch, pk->exp, pk->elen);
|
||||
|
||||
unsigned char *h = crypto_hash_read(ch);
|
||||
if (!h) {
|
||||
crypto_hash_close(ch);
|
||||
return false;
|
||||
}
|
||||
unsigned char *h = crypto_hash_read(ch);
|
||||
if (!h) {
|
||||
crypto_hash_close(ch);
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t hsize = crypto_hash_get_size(ch);
|
||||
bool r = hsize && !memcmp(h, pk->hash, hsize) ? true : false;
|
||||
size_t hsize = crypto_hash_get_size(ch);
|
||||
bool r = hsize && !memcmp(h, pk->hash, hsize) ? true : false;
|
||||
|
||||
crypto_hash_close(ch);
|
||||
crypto_hash_close(ch);
|
||||
|
||||
return r;
|
||||
return r;
|
||||
}
|
||||
|
||||
struct emv_pk *emv_pk_new(size_t modlen, size_t explen)
|
||||
{
|
||||
struct emv_pk *pk;
|
||||
struct emv_pk *pk;
|
||||
|
||||
/* Not supported ATM */
|
||||
if (explen > 3)
|
||||
return NULL;
|
||||
/* Not supported ATM */
|
||||
if (explen > 3)
|
||||
return NULL;
|
||||
|
||||
pk = calloc(1, sizeof(*pk));
|
||||
if (!pk)
|
||||
return NULL;
|
||||
pk = calloc(1, sizeof(*pk));
|
||||
if (!pk)
|
||||
return NULL;
|
||||
|
||||
pk->mlen = modlen;
|
||||
pk->elen = explen;
|
||||
pk->mlen = modlen;
|
||||
pk->elen = explen;
|
||||
|
||||
pk->modulus = calloc(modlen, 1);
|
||||
if (!pk->modulus) {
|
||||
free(pk);
|
||||
pk = NULL;
|
||||
}
|
||||
pk->modulus = calloc(modlen, 1);
|
||||
if (!pk->modulus) {
|
||||
free(pk);
|
||||
pk = NULL;
|
||||
}
|
||||
|
||||
return pk;
|
||||
return pk;
|
||||
}
|
||||
|
||||
void emv_pk_free(struct emv_pk *pk)
|
||||
{
|
||||
if (!pk)
|
||||
return;
|
||||
if (!pk)
|
||||
return;
|
||||
|
||||
free(pk->modulus);
|
||||
free(pk);
|
||||
free(pk->modulus);
|
||||
free(pk);
|
||||
}
|
||||
|
||||
static struct emv_pk *emv_pk_get_ca_pk_from_file(const char *fname,
|
||||
const unsigned char *rid,
|
||||
unsigned char idx)
|
||||
const unsigned char *rid,
|
||||
unsigned char idx)
|
||||
{
|
||||
if (!fname)
|
||||
return NULL;
|
||||
if (!fname)
|
||||
return NULL;
|
||||
|
||||
FILE *f = fopen(fname, "r");
|
||||
if (!f) {
|
||||
perror("fopen");
|
||||
return NULL;
|
||||
}
|
||||
FILE *f = fopen(fname, "r");
|
||||
if (!f) {
|
||||
perror("fopen");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (!feof(f)) {
|
||||
char buf[2048];
|
||||
if (fgets(buf, sizeof(buf), f) == NULL)
|
||||
break;
|
||||
while (!feof(f)) {
|
||||
char buf[2048];
|
||||
if (fgets(buf, sizeof(buf), f) == NULL)
|
||||
break;
|
||||
|
||||
struct emv_pk *pk = emv_pk_parse_pk(buf);
|
||||
if (!pk)
|
||||
continue;
|
||||
if (memcmp(pk->rid, rid, 5) || pk->index != idx) {
|
||||
emv_pk_free(pk);
|
||||
continue;
|
||||
}
|
||||
struct emv_pk *pk = emv_pk_parse_pk(buf);
|
||||
if (!pk)
|
||||
continue;
|
||||
if (memcmp(pk->rid, rid, 5) || pk->index != idx) {
|
||||
emv_pk_free(pk);
|
||||
continue;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
fclose(f);
|
||||
|
||||
return pk;
|
||||
}
|
||||
return pk;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
fclose(f);
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *emv_pk_get_ca_pk_file(const char *dirname, const unsigned char *rid, unsigned char idx)
|
||||
{
|
||||
if (!dirname)
|
||||
dirname = ".";//openemv_config_get_str("capk.dir", NULL);
|
||||
if (!dirname)
|
||||
dirname = ".";//openemv_config_get_str("capk.dir", NULL);
|
||||
|
||||
char *filename;
|
||||
int ret = asprintf(&filename, "%s/%02hhx%02hhx%02hhx%02hhx%02hhx_%02hhx.0",
|
||||
dirname,
|
||||
rid[0],
|
||||
rid[1],
|
||||
rid[2],
|
||||
rid[3],
|
||||
rid[4],
|
||||
idx);
|
||||
char *filename;
|
||||
int ret = asprintf(&filename, "%s/%02hhx%02hhx%02hhx%02hhx%02hhx_%02hhx.0",
|
||||
dirname,
|
||||
rid[0],
|
||||
rid[1],
|
||||
rid[2],
|
||||
rid[3],
|
||||
rid[4],
|
||||
idx);
|
||||
|
||||
if (ret <= 0)
|
||||
return NULL;
|
||||
if (ret <= 0)
|
||||
return NULL;
|
||||
|
||||
return filename;
|
||||
return filename;
|
||||
}
|
||||
|
||||
char *emv_pk_get_ca_pk_rid_file(const char *dirname, const unsigned char *rid)
|
||||
{
|
||||
if (!dirname)
|
||||
dirname = "."; //openemv_config_get_str("capk.dir", NULL);
|
||||
if (!dirname)
|
||||
dirname = "."; //openemv_config_get_str("capk.dir", NULL);
|
||||
|
||||
char *filename;
|
||||
int ret = asprintf(&filename, "%s/%02hhx%02hhx%02hhx%02hhx%02hhx.pks",
|
||||
dirname,
|
||||
rid[0],
|
||||
rid[1],
|
||||
rid[2],
|
||||
rid[3],
|
||||
rid[4]);
|
||||
char *filename;
|
||||
int ret = asprintf(&filename, "%s/%02hhx%02hhx%02hhx%02hhx%02hhx.pks",
|
||||
dirname,
|
||||
rid[0],
|
||||
rid[1],
|
||||
rid[2],
|
||||
rid[3],
|
||||
rid[4]);
|
||||
|
||||
if (ret <= 0)
|
||||
return NULL;
|
||||
if (ret <= 0)
|
||||
return NULL;
|
||||
|
||||
return filename;
|
||||
return filename;
|
||||
}
|
||||
|
||||
struct emv_pk *emv_pk_get_ca_pk(const unsigned char *rid, unsigned char idx)
|
||||
{
|
||||
struct emv_pk *pk = NULL;
|
||||
struct emv_pk *pk = NULL;
|
||||
|
||||
/* if (!pk) {
|
||||
char *fname = emv_pk_get_ca_pk_file(NULL, rid, idx);
|
||||
if (fname) {
|
||||
pk = emv_pk_get_ca_pk_from_file(fname, rid, idx);
|
||||
free(fname);
|
||||
}
|
||||
}
|
||||
/* if (!pk) {
|
||||
char *fname = emv_pk_get_ca_pk_file(NULL, rid, idx);
|
||||
if (fname) {
|
||||
pk = emv_pk_get_ca_pk_from_file(fname, rid, idx);
|
||||
free(fname);
|
||||
}
|
||||
}
|
||||
|
||||
if (!pk) {
|
||||
char *fname = emv_pk_get_ca_pk_rid_file(NULL, rid);
|
||||
if (fname) {
|
||||
pk = emv_pk_get_ca_pk_from_file(fname, rid, idx);
|
||||
free(fname);
|
||||
}
|
||||
}
|
||||
if (!pk) {
|
||||
char *fname = emv_pk_get_ca_pk_rid_file(NULL, rid);
|
||||
if (fname) {
|
||||
pk = emv_pk_get_ca_pk_from_file(fname, rid, idx);
|
||||
free(fname);
|
||||
}
|
||||
}
|
||||
*/
|
||||
if (!pk) {
|
||||
const char *relfname = "emv/capk.txt";
|
||||
if (!pk) {
|
||||
const char *relfname = "emv/capk.txt";
|
||||
|
||||
char fname[strlen(get_my_executable_directory()) + strlen(relfname) + 1];
|
||||
strcpy(fname, get_my_executable_directory());
|
||||
strcat(fname, relfname);
|
||||
char fname[strlen(get_my_executable_directory()) + strlen(relfname) + 1];
|
||||
strcpy(fname, get_my_executable_directory());
|
||||
strcat(fname, relfname);
|
||||
|
||||
pk = emv_pk_get_ca_pk_from_file(fname, rid, idx);
|
||||
}
|
||||
if (!pk)
|
||||
return NULL;
|
||||
pk = emv_pk_get_ca_pk_from_file(fname, rid, idx);
|
||||
}
|
||||
if (!pk)
|
||||
return NULL;
|
||||
|
||||
printf("Verifying CA PK for %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx %zd bits...",
|
||||
pk->rid[0],
|
||||
pk->rid[1],
|
||||
pk->rid[2],
|
||||
pk->rid[3],
|
||||
pk->rid[4],
|
||||
pk->index,
|
||||
pk->mlen * 8);
|
||||
if (emv_pk_verify(pk)) {
|
||||
printf("OK\n");
|
||||
printf("Verifying CA PK for %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx %zd bits...",
|
||||
pk->rid[0],
|
||||
pk->rid[1],
|
||||
pk->rid[2],
|
||||
pk->rid[3],
|
||||
pk->rid[4],
|
||||
pk->index,
|
||||
pk->mlen * 8);
|
||||
if (emv_pk_verify(pk)) {
|
||||
printf("OK\n");
|
||||
|
||||
return pk;
|
||||
}
|
||||
return pk;
|
||||
}
|
||||
|
||||
printf("Failed!\n");
|
||||
emv_pk_free(pk);
|
||||
printf("Failed!\n");
|
||||
emv_pk_free(pk);
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -20,21 +20,21 @@
|
|||
#include <stddef.h>
|
||||
|
||||
struct emv_pk {
|
||||
unsigned char rid[5];
|
||||
unsigned char index;
|
||||
unsigned char serial[3];
|
||||
unsigned char pan[10];
|
||||
unsigned char hash_algo;
|
||||
unsigned char pk_algo;
|
||||
unsigned char hash[20];
|
||||
unsigned char exp[3];
|
||||
size_t elen;
|
||||
size_t mlen;
|
||||
unsigned char *modulus;
|
||||
unsigned int expire;
|
||||
unsigned char rid[5];
|
||||
unsigned char index;
|
||||
unsigned char serial[3];
|
||||
unsigned char pan[10];
|
||||
unsigned char hash_algo;
|
||||
unsigned char pk_algo;
|
||||
unsigned char hash[20];
|
||||
unsigned char exp[3];
|
||||
size_t elen;
|
||||
size_t mlen;
|
||||
unsigned char *modulus;
|
||||
unsigned int expire;
|
||||
};
|
||||
|
||||
#define EXPIRE(yy, mm, dd) 0x ## yy ## mm ## dd
|
||||
#define EXPIRE(yy, mm, dd) 0x ## yy ## mm ## dd
|
||||
|
||||
struct emv_pk *emv_pk_parse_pk(char *buf);
|
||||
struct emv_pk *emv_pk_new(size_t modlen, size_t explen);
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
static bool strictExecution = true;
|
||||
void PKISetStrictExecution(bool se) {
|
||||
strictExecution = se;
|
||||
strictExecution = se;
|
||||
}
|
||||
|
||||
static const unsigned char empty_tlv_value[] = {};
|
||||
|
@ -38,551 +38,551 @@ static const struct tlv empty_tlv = {.tag = 0x0, .len = 0, .value = empty_tlv_va
|
|||
static size_t emv_pki_hash_psn[256] = { 0, 0, 11, 2, 17, 2, };
|
||||
|
||||
static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk,
|
||||
uint8_t msgtype,
|
||||
size_t *len,
|
||||
const struct tlv *cert_tlv,
|
||||
int tlv_count,
|
||||
... /* A list of tlv pointers */
|
||||
)
|
||||
uint8_t msgtype,
|
||||
size_t *len,
|
||||
const struct tlv *cert_tlv,
|
||||
int tlv_count,
|
||||
... /* A list of tlv pointers */
|
||||
)
|
||||
{
|
||||
struct crypto_pk *kcp;
|
||||
unsigned char *data;
|
||||
size_t data_len;
|
||||
va_list vl;
|
||||
struct crypto_pk *kcp;
|
||||
unsigned char *data;
|
||||
size_t data_len;
|
||||
va_list vl;
|
||||
|
||||
if (!enc_pk)
|
||||
return NULL;
|
||||
if (!enc_pk)
|
||||
return NULL;
|
||||
|
||||
if (!cert_tlv) {
|
||||
printf("ERROR: Can't find certificate\n");
|
||||
return NULL;
|
||||
}
|
||||
if (!cert_tlv) {
|
||||
printf("ERROR: Can't find certificate\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (cert_tlv->len != enc_pk->mlen) {
|
||||
printf("ERROR: Certificate length (%zu) not equal key length (%zu)\n", cert_tlv->len, enc_pk->mlen);
|
||||
return NULL;
|
||||
}
|
||||
kcp = crypto_pk_open(enc_pk->pk_algo,
|
||||
enc_pk->modulus, enc_pk->mlen,
|
||||
enc_pk->exp, enc_pk->elen);
|
||||
if (!kcp)
|
||||
return NULL;
|
||||
if (cert_tlv->len != enc_pk->mlen) {
|
||||
printf("ERROR: Certificate length (%zu) not equal key length (%zu)\n", cert_tlv->len, enc_pk->mlen);
|
||||
return NULL;
|
||||
}
|
||||
kcp = crypto_pk_open(enc_pk->pk_algo,
|
||||
enc_pk->modulus, enc_pk->mlen,
|
||||
enc_pk->exp, enc_pk->elen);
|
||||
if (!kcp)
|
||||
return NULL;
|
||||
|
||||
data = crypto_pk_encrypt(kcp, cert_tlv->value, cert_tlv->len, &data_len);
|
||||
crypto_pk_close(kcp);
|
||||
data = crypto_pk_encrypt(kcp, cert_tlv->value, cert_tlv->len, &data_len);
|
||||
crypto_pk_close(kcp);
|
||||
|
||||
/* if (true){
|
||||
printf("Recovered data:\n");
|
||||
dump_buffer(data, data_len, stdout, 0);
|
||||
}*/
|
||||
/* if (true){
|
||||
printf("Recovered data:\n");
|
||||
dump_buffer(data, data_len, stdout, 0);
|
||||
}*/
|
||||
|
||||
if (data[data_len-1] != 0xbc || data[0] != 0x6a || data[1] != msgtype) {
|
||||
printf("ERROR: Certificate format\n");
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
if (data[data_len-1] != 0xbc || data[0] != 0x6a || data[1] != msgtype) {
|
||||
printf("ERROR: Certificate format\n");
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t hash_pos = emv_pki_hash_psn[msgtype];
|
||||
if (hash_pos == 0 || hash_pos > data_len){
|
||||
printf("ERROR: Cant get hash position in the certificate\n");
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
size_t hash_pos = emv_pki_hash_psn[msgtype];
|
||||
if (hash_pos == 0 || hash_pos > data_len){
|
||||
printf("ERROR: Cant get hash position in the certificate\n");
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct crypto_hash *ch;
|
||||
ch = crypto_hash_open(data[hash_pos]);
|
||||
if (!ch) {
|
||||
printf("ERROR: Cant do hash\n");
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
struct crypto_hash *ch;
|
||||
ch = crypto_hash_open(data[hash_pos]);
|
||||
if (!ch) {
|
||||
printf("ERROR: Cant do hash\n");
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t hash_len = crypto_hash_get_size(ch);
|
||||
crypto_hash_write(ch, data + 1, data_len - 2 - hash_len);
|
||||
size_t hash_len = crypto_hash_get_size(ch);
|
||||
crypto_hash_write(ch, data + 1, data_len - 2 - hash_len);
|
||||
|
||||
va_start(vl, tlv_count);
|
||||
for (int i = 0; i < tlv_count; i++) {
|
||||
const struct tlv *add_tlv = va_arg(vl, const struct tlv *);
|
||||
if (!add_tlv)
|
||||
continue;
|
||||
va_start(vl, tlv_count);
|
||||
for (int i = 0; i < tlv_count; i++) {
|
||||
const struct tlv *add_tlv = va_arg(vl, const struct tlv *);
|
||||
if (!add_tlv)
|
||||
continue;
|
||||
|
||||
crypto_hash_write(ch, add_tlv->value, add_tlv->len);
|
||||
}
|
||||
va_end(vl);
|
||||
crypto_hash_write(ch, add_tlv->value, add_tlv->len);
|
||||
}
|
||||
va_end(vl);
|
||||
|
||||
uint8_t hash[hash_len];
|
||||
memset(hash, 0, hash_len);
|
||||
memcpy(hash, crypto_hash_read(ch), hash_len);
|
||||
if (memcmp(data + data_len - 1 - hash_len, hash, hash_len)) {
|
||||
printf("ERROR: Calculated wrong hash\n");
|
||||
printf("decoded: %s\n",sprint_hex(data + data_len - 1 - hash_len, hash_len));
|
||||
printf("calculated: %s\n",sprint_hex(hash, hash_len));
|
||||
uint8_t hash[hash_len];
|
||||
memset(hash, 0, hash_len);
|
||||
memcpy(hash, crypto_hash_read(ch), hash_len);
|
||||
if (memcmp(data + data_len - 1 - hash_len, hash, hash_len)) {
|
||||
printf("ERROR: Calculated wrong hash\n");
|
||||
printf("decoded: %s\n",sprint_hex(data + data_len - 1 - hash_len, hash_len));
|
||||
printf("calculated: %s\n",sprint_hex(hash, hash_len));
|
||||
|
||||
if (strictExecution) {
|
||||
crypto_hash_close(ch);
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (strictExecution) {
|
||||
crypto_hash_close(ch);
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
crypto_hash_close(ch);
|
||||
crypto_hash_close(ch);
|
||||
|
||||
*len = data_len - hash_len - 1;
|
||||
*len = data_len - hash_len - 1;
|
||||
|
||||
return data;
|
||||
return data;
|
||||
}
|
||||
|
||||
static unsigned emv_cn_length(const struct tlv *tlv)
|
||||
{
|
||||
int i;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < tlv->len; i++) {
|
||||
unsigned char c = tlv->value[i];
|
||||
for (i = 0; i < tlv->len; i++) {
|
||||
unsigned char c = tlv->value[i];
|
||||
|
||||
if (c >> 4 == 0xf)
|
||||
return 2 * i;
|
||||
if (c >> 4 == 0xf)
|
||||
return 2 * i;
|
||||
|
||||
if ((c & 0xf) == 0xf)
|
||||
return 2 * i + 1;
|
||||
}
|
||||
if ((c & 0xf) == 0xf)
|
||||
return 2 * i + 1;
|
||||
}
|
||||
|
||||
return 2 * tlv->len;
|
||||
return 2 * tlv->len;
|
||||
}
|
||||
|
||||
static unsigned char emv_cn_get(const struct tlv *tlv, unsigned pos)
|
||||
{
|
||||
if (pos > tlv->len * 2)
|
||||
return 0xf;
|
||||
if (pos > tlv->len * 2)
|
||||
return 0xf;
|
||||
|
||||
unsigned char c = tlv->value[pos / 2];
|
||||
unsigned char c = tlv->value[pos / 2];
|
||||
|
||||
if (pos % 2)
|
||||
return c & 0xf;
|
||||
else
|
||||
return c >> 4;
|
||||
if (pos % 2)
|
||||
return c & 0xf;
|
||||
else
|
||||
return c >> 4;
|
||||
}
|
||||
|
||||
static struct emv_pk *emv_pki_decode_key_ex(const struct emv_pk *enc_pk,
|
||||
unsigned char msgtype,
|
||||
const struct tlv *pan_tlv,
|
||||
const struct tlv *cert_tlv,
|
||||
const struct tlv *exp_tlv,
|
||||
const struct tlv *rem_tlv,
|
||||
const struct tlv *add_tlv,
|
||||
const struct tlv *sdatl_tlv,
|
||||
bool showData
|
||||
)
|
||||
unsigned char msgtype,
|
||||
const struct tlv *pan_tlv,
|
||||
const struct tlv *cert_tlv,
|
||||
const struct tlv *exp_tlv,
|
||||
const struct tlv *rem_tlv,
|
||||
const struct tlv *add_tlv,
|
||||
const struct tlv *sdatl_tlv,
|
||||
bool showData
|
||||
)
|
||||
{
|
||||
size_t pan_length;
|
||||
unsigned char *data;
|
||||
size_t data_len;
|
||||
size_t pk_len;
|
||||
size_t pan_length;
|
||||
unsigned char *data;
|
||||
size_t data_len;
|
||||
size_t pk_len;
|
||||
|
||||
if (!cert_tlv || !exp_tlv || !pan_tlv)
|
||||
return NULL;
|
||||
if (!cert_tlv || !exp_tlv || !pan_tlv)
|
||||
return NULL;
|
||||
|
||||
if (!rem_tlv)
|
||||
rem_tlv = &empty_tlv;
|
||||
if (!rem_tlv)
|
||||
rem_tlv = &empty_tlv;
|
||||
|
||||
if (msgtype == 2)
|
||||
pan_length = 4;
|
||||
else if (msgtype == 4)
|
||||
pan_length = 10;
|
||||
else {
|
||||
printf("ERROR: Message type must be 2 or 4\n");
|
||||
return NULL;
|
||||
}
|
||||
if (msgtype == 2)
|
||||
pan_length = 4;
|
||||
else if (msgtype == 4)
|
||||
pan_length = 10;
|
||||
else {
|
||||
printf("ERROR: Message type must be 2 or 4\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data = emv_pki_decode_message(enc_pk, msgtype, &data_len,
|
||||
cert_tlv,
|
||||
5,
|
||||
rem_tlv,
|
||||
exp_tlv,
|
||||
add_tlv,
|
||||
sdatl_tlv,
|
||||
NULL);
|
||||
if (!data || data_len < 11 + pan_length) {
|
||||
printf("ERROR: Can't decode message\n");
|
||||
return NULL;
|
||||
}
|
||||
data = emv_pki_decode_message(enc_pk, msgtype, &data_len,
|
||||
cert_tlv,
|
||||
5,
|
||||
rem_tlv,
|
||||
exp_tlv,
|
||||
add_tlv,
|
||||
sdatl_tlv,
|
||||
NULL);
|
||||
if (!data || data_len < 11 + pan_length) {
|
||||
printf("ERROR: Can't decode message\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (showData){
|
||||
printf("Recovered data:\n");
|
||||
dump_buffer(data, data_len, stdout, 0);
|
||||
}
|
||||
if (showData){
|
||||
printf("Recovered data:\n");
|
||||
dump_buffer(data, data_len, stdout, 0);
|
||||
}
|
||||
|
||||
/* Perform the rest of checks here */
|
||||
/* Perform the rest of checks here */
|
||||
|
||||
struct tlv pan2_tlv = {
|
||||
.tag = 0x5a,
|
||||
.len = pan_length,
|
||||
.value = &data[2],
|
||||
};
|
||||
unsigned pan_len = emv_cn_length(pan_tlv);
|
||||
unsigned pan2_len = emv_cn_length(&pan2_tlv);
|
||||
struct tlv pan2_tlv = {
|
||||
.tag = 0x5a,
|
||||
.len = pan_length,
|
||||
.value = &data[2],
|
||||
};
|
||||
unsigned pan_len = emv_cn_length(pan_tlv);
|
||||
unsigned pan2_len = emv_cn_length(&pan2_tlv);
|
||||
|
||||
if (((msgtype == 2) && (pan2_len < 4 || pan2_len > pan_len)) ||
|
||||
((msgtype == 4) && (pan2_len != pan_len))) {
|
||||
printf("ERROR: Invalid PAN lengths\n");
|
||||
free(data);
|
||||
if (((msgtype == 2) && (pan2_len < 4 || pan2_len > pan_len)) ||
|
||||
((msgtype == 4) && (pan2_len != pan_len))) {
|
||||
printf("ERROR: Invalid PAN lengths\n");
|
||||
free(data);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned i;
|
||||
for (i = 0; i < pan2_len; i++)
|
||||
if (emv_cn_get(pan_tlv, i) != emv_cn_get(&pan2_tlv, i)) {
|
||||
printf("ERROR: PAN data mismatch\n");
|
||||
printf("tlv pan=%s\n", sprint_hex(pan_tlv->value, pan_tlv->len));
|
||||
printf("cert pan=%s\n", sprint_hex(pan2_tlv.value, pan2_tlv.len));
|
||||
free(data);
|
||||
unsigned i;
|
||||
for (i = 0; i < pan2_len; i++)
|
||||
if (emv_cn_get(pan_tlv, i) != emv_cn_get(&pan2_tlv, i)) {
|
||||
printf("ERROR: PAN data mismatch\n");
|
||||
printf("tlv pan=%s\n", sprint_hex(pan_tlv->value, pan_tlv->len));
|
||||
printf("cert pan=%s\n", sprint_hex(pan2_tlv.value, pan2_tlv.len));
|
||||
free(data);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pk_len = data[9 + pan_length];
|
||||
if (pk_len > data_len - 11 - pan_length + rem_tlv->len) {
|
||||
printf("ERROR: Invalid pk length\n");
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
pk_len = data[9 + pan_length];
|
||||
if (pk_len > data_len - 11 - pan_length + rem_tlv->len) {
|
||||
printf("ERROR: Invalid pk length\n");
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (exp_tlv->len != data[10 + pan_length]) {
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
if (exp_tlv->len != data[10 + pan_length]) {
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct emv_pk *pk = emv_pk_new(pk_len, exp_tlv->len);
|
||||
struct emv_pk *pk = emv_pk_new(pk_len, exp_tlv->len);
|
||||
|
||||
memcpy(pk->rid, enc_pk->rid, 5);
|
||||
pk->index = enc_pk->index;
|
||||
memcpy(pk->rid, enc_pk->rid, 5);
|
||||
pk->index = enc_pk->index;
|
||||
|
||||
pk->hash_algo = data[7 + pan_length];
|
||||
pk->pk_algo = data[8 + pan_length];
|
||||
pk->expire = (data[3 + pan_length] << 16) | (data[2 + pan_length] << 8) | 0x31;
|
||||
memcpy(pk->serial, data + 4 + pan_length, 3);
|
||||
memcpy(pk->pan, data + 2, pan_length);
|
||||
memset(pk->pan + pan_length, 0xff, 10 - pan_length);
|
||||
pk->hash_algo = data[7 + pan_length];
|
||||
pk->pk_algo = data[8 + pan_length];
|
||||
pk->expire = (data[3 + pan_length] << 16) | (data[2 + pan_length] << 8) | 0x31;
|
||||
memcpy(pk->serial, data + 4 + pan_length, 3);
|
||||
memcpy(pk->pan, data + 2, pan_length);
|
||||
memset(pk->pan + pan_length, 0xff, 10 - pan_length);
|
||||
|
||||
memcpy(pk->modulus, data + 11 + pan_length,
|
||||
pk_len < data_len - (11 + pan_length) ?
|
||||
pk_len :
|
||||
data_len - (11 + pan_length));
|
||||
memcpy(pk->modulus + data_len - (11 + pan_length), rem_tlv->value, rem_tlv->len);
|
||||
memcpy(pk->exp, exp_tlv->value, exp_tlv->len);
|
||||
memcpy(pk->modulus, data + 11 + pan_length,
|
||||
pk_len < data_len - (11 + pan_length) ?
|
||||
pk_len :
|
||||
data_len - (11 + pan_length));
|
||||
memcpy(pk->modulus + data_len - (11 + pan_length), rem_tlv->value, rem_tlv->len);
|
||||
memcpy(pk->exp, exp_tlv->value, exp_tlv->len);
|
||||
|
||||
free(data);
|
||||
free(data);
|
||||
|
||||
return pk;
|
||||
return pk;
|
||||
}
|
||||
|
||||
static struct emv_pk *emv_pki_decode_key(const struct emv_pk *enc_pk,
|
||||
unsigned char msgtype,
|
||||
const struct tlv *pan_tlv,
|
||||
const struct tlv *cert_tlv,
|
||||
const struct tlv *exp_tlv,
|
||||
const struct tlv *rem_tlv,
|
||||
const struct tlv *add_tlv,
|
||||
const struct tlv *sdatl_tlv
|
||||
) {
|
||||
return emv_pki_decode_key_ex(enc_pk, msgtype, pan_tlv, cert_tlv, exp_tlv, rem_tlv, add_tlv, sdatl_tlv, false);
|
||||
unsigned char msgtype,
|
||||
const struct tlv *pan_tlv,
|
||||
const struct tlv *cert_tlv,
|
||||
const struct tlv *exp_tlv,
|
||||
const struct tlv *rem_tlv,
|
||||
const struct tlv *add_tlv,
|
||||
const struct tlv *sdatl_tlv
|
||||
) {
|
||||
return emv_pki_decode_key_ex(enc_pk, msgtype, pan_tlv, cert_tlv, exp_tlv, rem_tlv, add_tlv, sdatl_tlv, false);
|
||||
}
|
||||
|
||||
struct emv_pk *emv_pki_recover_issuer_cert(const struct emv_pk *pk, struct tlvdb *db)
|
||||
{
|
||||
return emv_pki_decode_key(pk, 2,
|
||||
tlvdb_get(db, 0x5a, NULL),
|
||||
tlvdb_get(db, 0x90, NULL),
|
||||
tlvdb_get(db, 0x9f32, NULL),
|
||||
tlvdb_get(db, 0x92, NULL),
|
||||
NULL,
|
||||
NULL);
|
||||
return emv_pki_decode_key(pk, 2,
|
||||
tlvdb_get(db, 0x5a, NULL),
|
||||
tlvdb_get(db, 0x90, NULL),
|
||||
tlvdb_get(db, 0x9f32, NULL),
|
||||
tlvdb_get(db, 0x92, NULL),
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
struct emv_pk *emv_pki_recover_icc_cert(const struct emv_pk *pk, struct tlvdb *db, const struct tlv *sda_tlv)
|
||||
{
|
||||
size_t sdatl_len;
|
||||
unsigned char *sdatl = emv_pki_sdatl_fill(db, &sdatl_len);
|
||||
struct tlv sda_tdata = {
|
||||
.tag = 0x00, // dummy tag
|
||||
.len = sdatl_len,
|
||||
.value = sdatl
|
||||
};
|
||||
size_t sdatl_len;
|
||||
unsigned char *sdatl = emv_pki_sdatl_fill(db, &sdatl_len);
|
||||
struct tlv sda_tdata = {
|
||||
.tag = 0x00, // dummy tag
|
||||
.len = sdatl_len,
|
||||
.value = sdatl
|
||||
};
|
||||
|
||||
struct emv_pk *res = emv_pki_decode_key(pk, 4,
|
||||
tlvdb_get(db, 0x5a, NULL),
|
||||
tlvdb_get(db, 0x9f46, NULL),
|
||||
tlvdb_get(db, 0x9f47, NULL),
|
||||
tlvdb_get(db, 0x9f48, NULL),
|
||||
sda_tlv,
|
||||
&sda_tdata);
|
||||
struct emv_pk *res = emv_pki_decode_key(pk, 4,
|
||||
tlvdb_get(db, 0x5a, NULL),
|
||||
tlvdb_get(db, 0x9f46, NULL),
|
||||
tlvdb_get(db, 0x9f47, NULL),
|
||||
tlvdb_get(db, 0x9f48, NULL),
|
||||
sda_tlv,
|
||||
&sda_tdata);
|
||||
|
||||
free(sdatl); // malloc here: emv_pki_sdatl_fill
|
||||
return res;
|
||||
free(sdatl); // malloc here: emv_pki_sdatl_fill
|
||||
return res;
|
||||
}
|
||||
|
||||
struct emv_pk *emv_pki_recover_icc_pe_cert(const struct emv_pk *pk, struct tlvdb *db)
|
||||
{
|
||||
return emv_pki_decode_key(pk, 4,
|
||||
tlvdb_get(db, 0x5a, NULL),
|
||||
tlvdb_get(db, 0x9f2d, NULL),
|
||||
tlvdb_get(db, 0x9f2e, NULL),
|
||||
tlvdb_get(db, 0x9f2f, NULL),
|
||||
NULL,
|
||||
NULL);
|
||||
return emv_pki_decode_key(pk, 4,
|
||||
tlvdb_get(db, 0x5a, NULL),
|
||||
tlvdb_get(db, 0x9f2d, NULL),
|
||||
tlvdb_get(db, 0x9f2e, NULL),
|
||||
tlvdb_get(db, 0x9f2f, NULL),
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
unsigned char *emv_pki_sdatl_fill(const struct tlvdb *db, size_t *sdatl_len) {
|
||||
uint8_t buf[2048] = {0};
|
||||
size_t len = 0;
|
||||
uint8_t buf[2048] = {0};
|
||||
size_t len = 0;
|
||||
|
||||
*sdatl_len = 0;
|
||||
*sdatl_len = 0;
|
||||
|
||||
const struct tlv *sda_tl = tlvdb_get(db, 0x9f4a, NULL);
|
||||
if (!sda_tl || sda_tl->len <= 0)
|
||||
return NULL;
|
||||
const struct tlv *sda_tl = tlvdb_get(db, 0x9f4a, NULL);
|
||||
if (!sda_tl || sda_tl->len <= 0)
|
||||
return NULL;
|
||||
|
||||
for (int i = 0; i < sda_tl->len; i++) {
|
||||
uint32_t tag = sda_tl->value[i]; // here may be multibyte, but now not
|
||||
const struct tlv *elm = tlvdb_get(db, tag, NULL);
|
||||
if (elm) {
|
||||
memcpy(&buf[len], elm->value, elm->len);
|
||||
len += elm->len;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < sda_tl->len; i++) {
|
||||
uint32_t tag = sda_tl->value[i]; // here may be multibyte, but now not
|
||||
const struct tlv *elm = tlvdb_get(db, tag, NULL);
|
||||
if (elm) {
|
||||
memcpy(&buf[len], elm->value, elm->len);
|
||||
len += elm->len;
|
||||
}
|
||||
}
|
||||
|
||||
if (len) {
|
||||
*sdatl_len = len;
|
||||
unsigned char *value = malloc(len);
|
||||
memcpy(value, buf, len);
|
||||
return value;
|
||||
}
|
||||
if (len) {
|
||||
*sdatl_len = len;
|
||||
unsigned char *value = malloc(len);
|
||||
memcpy(value, buf, len);
|
||||
return value;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
struct tlvdb *emv_pki_recover_dac_ex(const struct emv_pk *enc_pk, const struct tlvdb *db, const struct tlv *sda_tlv, bool showData)
|
||||
{
|
||||
size_t data_len;
|
||||
size_t data_len;
|
||||
|
||||
// Static Data Authentication Tag List
|
||||
size_t sdatl_len;
|
||||
unsigned char *sdatl = emv_pki_sdatl_fill(db, &sdatl_len);
|
||||
struct tlv sda_tdata = {
|
||||
.tag = 0x00, // dummy tag
|
||||
.len = sdatl_len,
|
||||
.value = sdatl
|
||||
};
|
||||
// Static Data Authentication Tag List
|
||||
size_t sdatl_len;
|
||||
unsigned char *sdatl = emv_pki_sdatl_fill(db, &sdatl_len);
|
||||
struct tlv sda_tdata = {
|
||||
.tag = 0x00, // dummy tag
|
||||
.len = sdatl_len,
|
||||
.value = sdatl
|
||||
};
|
||||
|
||||
unsigned char *data = emv_pki_decode_message(enc_pk, 3, &data_len,
|
||||
tlvdb_get(db, 0x93, NULL),
|
||||
3,
|
||||
sda_tlv,
|
||||
&sda_tdata,
|
||||
NULL);
|
||||
unsigned char *data = emv_pki_decode_message(enc_pk, 3, &data_len,
|
||||
tlvdb_get(db, 0x93, NULL),
|
||||
3,
|
||||
sda_tlv,
|
||||
&sda_tdata,
|
||||
NULL);
|
||||
|
||||
free(sdatl); // malloc here: emv_pki_sdatl_fill
|
||||
free(sdatl); // malloc here: emv_pki_sdatl_fill
|
||||
|
||||
if (!data || data_len < 5)
|
||||
return NULL;
|
||||
if (!data || data_len < 5)
|
||||
return NULL;
|
||||
|
||||
if (showData){
|
||||
printf("Recovered data:\n");
|
||||
dump_buffer(data, data_len, stdout, 0);
|
||||
}
|
||||
if (showData){
|
||||
printf("Recovered data:\n");
|
||||
dump_buffer(data, data_len, stdout, 0);
|
||||
}
|
||||
|
||||
struct tlvdb *dac_db = tlvdb_fixed(0x9f45, 2, data+3);
|
||||
struct tlvdb *dac_db = tlvdb_fixed(0x9f45, 2, data+3);
|
||||
|
||||
free(data);
|
||||
free(data);
|
||||
|
||||
return dac_db;
|
||||
return dac_db;
|
||||
}
|
||||
struct tlvdb *emv_pki_recover_dac(const struct emv_pk *enc_pk, const struct tlvdb *db, const struct tlv *sda_tlv) {
|
||||
return emv_pki_recover_dac_ex(enc_pk, db, sda_tlv, false);
|
||||
return emv_pki_recover_dac_ex(enc_pk, db, sda_tlv, false);
|
||||
}
|
||||
|
||||
struct tlvdb *emv_pki_recover_idn(const struct emv_pk *enc_pk, const struct tlvdb *db, const struct tlv *dyn_tlv) {
|
||||
return emv_pki_recover_idn_ex(enc_pk, db, dyn_tlv, false);
|
||||
return emv_pki_recover_idn_ex(enc_pk, db, dyn_tlv, false);
|
||||
}
|
||||
|
||||
struct tlvdb *emv_pki_recover_idn_ex(const struct emv_pk *enc_pk, const struct tlvdb *db, const struct tlv *dyn_tlv, bool showData)
|
||||
{
|
||||
size_t data_len;
|
||||
unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len,
|
||||
tlvdb_get(db, 0x9f4b, NULL),
|
||||
2,
|
||||
dyn_tlv,
|
||||
NULL);
|
||||
size_t data_len;
|
||||
unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len,
|
||||
tlvdb_get(db, 0x9f4b, NULL),
|
||||
2,
|
||||
dyn_tlv,
|
||||
NULL);
|
||||
|
||||
if (!data || data_len < 3)
|
||||
return NULL;
|
||||
if (!data || data_len < 3)
|
||||
return NULL;
|
||||
|
||||
if (data[3] < 2 || data[3] > data_len - 3) {
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
if (data[3] < 2 || data[3] > data_len - 3) {
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (showData){
|
||||
printf("Recovered data:\n");
|
||||
dump_buffer(data, data_len, stdout, 0);
|
||||
}
|
||||
if (showData){
|
||||
printf("Recovered data:\n");
|
||||
dump_buffer(data, data_len, stdout, 0);
|
||||
}
|
||||
|
||||
size_t idn_len = data[4];
|
||||
if (idn_len > data[3] - 1) {
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
size_t idn_len = data[4];
|
||||
if (idn_len > data[3] - 1) {
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 9f4c ICC Dynamic Number
|
||||
struct tlvdb *idn_db = tlvdb_fixed(0x9f4c, idn_len, data + 5);
|
||||
// 9f4c ICC Dynamic Number
|
||||
struct tlvdb *idn_db = tlvdb_fixed(0x9f4c, idn_len, data + 5);
|
||||
|
||||
free(data);
|
||||
free(data);
|
||||
|
||||
return idn_db;
|
||||
return idn_db;
|
||||
}
|
||||
|
||||
struct tlvdb *emv_pki_recover_atc_ex(const struct emv_pk *enc_pk, const struct tlvdb *db, bool showData)
|
||||
{
|
||||
size_t data_len;
|
||||
unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len,
|
||||
tlvdb_get(db, 0x9f4b, NULL),
|
||||
5,
|
||||
tlvdb_get(db, 0x9f37, NULL),
|
||||
tlvdb_get(db, 0x9f02, NULL),
|
||||
tlvdb_get(db, 0x5f2a, NULL),
|
||||
tlvdb_get(db, 0x9f69, NULL),
|
||||
NULL);
|
||||
size_t data_len;
|
||||
unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len,
|
||||
tlvdb_get(db, 0x9f4b, NULL),
|
||||
5,
|
||||
tlvdb_get(db, 0x9f37, NULL),
|
||||
tlvdb_get(db, 0x9f02, NULL),
|
||||
tlvdb_get(db, 0x5f2a, NULL),
|
||||
tlvdb_get(db, 0x9f69, NULL),
|
||||
NULL);
|
||||
|
||||
if (!data || data_len < 3)
|
||||
return NULL;
|
||||
if (!data || data_len < 3)
|
||||
return NULL;
|
||||
|
||||
if (data[3] < 2 || data[3] > data_len - 3) {
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
if (data[3] < 2 || data[3] > data_len - 3) {
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (showData){
|
||||
printf("Recovered data:\n");
|
||||
dump_buffer(data, data_len, stdout, 0);
|
||||
}
|
||||
if (showData){
|
||||
printf("Recovered data:\n");
|
||||
dump_buffer(data, data_len, stdout, 0);
|
||||
}
|
||||
|
||||
size_t idn_len = data[4];
|
||||
if (idn_len > data[3] - 1) {
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
size_t idn_len = data[4];
|
||||
if (idn_len > data[3] - 1) {
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 9f36 Application Transaction Counter (ATC)
|
||||
struct tlvdb *atc_db = tlvdb_fixed(0x9f36, idn_len, data + 5);
|
||||
// 9f36 Application Transaction Counter (ATC)
|
||||
struct tlvdb *atc_db = tlvdb_fixed(0x9f36, idn_len, data + 5);
|
||||
|
||||
free(data);
|
||||
free(data);
|
||||
|
||||
return atc_db;
|
||||
return atc_db;
|
||||
}
|
||||
|
||||
static bool tlv_hash(void *data, const struct tlv *tlv, int level, bool is_leaf)
|
||||
{
|
||||
struct crypto_hash *ch = data;
|
||||
size_t tag_len;
|
||||
unsigned char *tag;
|
||||
struct crypto_hash *ch = data;
|
||||
size_t tag_len;
|
||||
unsigned char *tag;
|
||||
|
||||
if (tlv_is_constructed(tlv))
|
||||
return true;
|
||||
if (tlv_is_constructed(tlv))
|
||||
return true;
|
||||
|
||||
if (tlv->tag == 0x9f4b)
|
||||
return true;
|
||||
if (tlv->tag == 0x9f4b)
|
||||
return true;
|
||||
|
||||
tag = tlv_encode(tlv, &tag_len);
|
||||
crypto_hash_write(ch, tag, tag_len);
|
||||
free(tag);
|
||||
tag = tlv_encode(tlv, &tag_len);
|
||||
crypto_hash_write(ch, tag, tag_len);
|
||||
free(tag);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct tlvdb *emv_pki_perform_cda(const struct emv_pk *enc_pk, const struct tlvdb *db,
|
||||
const struct tlvdb *this_db,
|
||||
const struct tlv *pdol_data_tlv,
|
||||
const struct tlv *crm1_tlv,
|
||||
const struct tlv *crm2_tlv)
|
||||
const struct tlvdb *this_db,
|
||||
const struct tlv *pdol_data_tlv,
|
||||
const struct tlv *crm1_tlv,
|
||||
const struct tlv *crm2_tlv)
|
||||
{
|
||||
return emv_pki_perform_cda_ex(enc_pk, db, this_db, pdol_data_tlv, crm1_tlv, crm2_tlv, false);
|
||||
return emv_pki_perform_cda_ex(enc_pk, db, this_db, pdol_data_tlv, crm1_tlv, crm2_tlv, false);
|
||||
}
|
||||
struct tlvdb *emv_pki_perform_cda_ex(const struct emv_pk *enc_pk, const struct tlvdb *db,
|
||||
const struct tlvdb *this_db, // AC TLV result
|
||||
const struct tlv *pdol_data_tlv, // PDOL
|
||||
const struct tlv *crm1_tlv, // CDOL1
|
||||
const struct tlv *crm2_tlv, // CDOL2
|
||||
bool showData)
|
||||
const struct tlvdb *this_db, // AC TLV result
|
||||
const struct tlv *pdol_data_tlv, // PDOL
|
||||
const struct tlv *crm1_tlv, // CDOL1
|
||||
const struct tlv *crm2_tlv, // CDOL2
|
||||
bool showData)
|
||||
{
|
||||
const struct tlv *un_tlv = tlvdb_get(db, 0x9f37, NULL);
|
||||
const struct tlv *cid_tlv = tlvdb_get(this_db, 0x9f27, NULL);
|
||||
const struct tlv *un_tlv = tlvdb_get(db, 0x9f37, NULL);
|
||||
const struct tlv *cid_tlv = tlvdb_get(this_db, 0x9f27, NULL);
|
||||
|
||||
if (!un_tlv || !cid_tlv)
|
||||
return NULL;
|
||||
if (!un_tlv || !cid_tlv)
|
||||
return NULL;
|
||||
|
||||
size_t data_len = 0;
|
||||
unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len,
|
||||
tlvdb_get(this_db, 0x9f4b, NULL),
|
||||
2,
|
||||
un_tlv,
|
||||
NULL);
|
||||
if (!data || data_len < 3) {
|
||||
printf("ERROR: can't decode message. len %zu\n", data_len);
|
||||
return NULL;
|
||||
}
|
||||
size_t data_len = 0;
|
||||
unsigned char *data = emv_pki_decode_message(enc_pk, 5, &data_len,
|
||||
tlvdb_get(this_db, 0x9f4b, NULL),
|
||||
2,
|
||||
un_tlv,
|
||||
NULL);
|
||||
if (!data || data_len < 3) {
|
||||
printf("ERROR: can't decode message. len %zu\n", data_len);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (showData){
|
||||
printf("Recovered data:\n");
|
||||
dump_buffer(data, data_len, stdout, 0);
|
||||
}
|
||||
if (showData){
|
||||
printf("Recovered data:\n");
|
||||
dump_buffer(data, data_len, stdout, 0);
|
||||
}
|
||||
|
||||
if (data[3] < 30 || data[3] > data_len - 4) {
|
||||
printf("ERROR: Invalid data length\n");
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
if (data[3] < 30 || data[3] > data_len - 4) {
|
||||
printf("ERROR: Invalid data length\n");
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!cid_tlv || cid_tlv->len != 1 || cid_tlv->value[0] != data[5 + data[4]]) {
|
||||
printf("ERROR: CID mismatch\n");
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
if (!cid_tlv || cid_tlv->len != 1 || cid_tlv->value[0] != data[5 + data[4]]) {
|
||||
printf("ERROR: CID mismatch\n");
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct crypto_hash *ch;
|
||||
ch = crypto_hash_open(enc_pk->hash_algo);
|
||||
if (!ch) {
|
||||
printf("ERROR: can't create hash\n");
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
struct crypto_hash *ch;
|
||||
ch = crypto_hash_open(enc_pk->hash_algo);
|
||||
if (!ch) {
|
||||
printf("ERROR: can't create hash\n");
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pdol_data_tlv)
|
||||
crypto_hash_write(ch, pdol_data_tlv->value, pdol_data_tlv->len);
|
||||
if (crm1_tlv)
|
||||
crypto_hash_write(ch, crm1_tlv->value, crm1_tlv->len);
|
||||
if (crm2_tlv)
|
||||
crypto_hash_write(ch, crm2_tlv->value, crm2_tlv->len);
|
||||
if (pdol_data_tlv)
|
||||
crypto_hash_write(ch, pdol_data_tlv->value, pdol_data_tlv->len);
|
||||
if (crm1_tlv)
|
||||
crypto_hash_write(ch, crm1_tlv->value, crm1_tlv->len);
|
||||
if (crm2_tlv)
|
||||
crypto_hash_write(ch, crm2_tlv->value, crm2_tlv->len);
|
||||
|
||||
tlvdb_visit(this_db, tlv_hash, ch, 0);
|
||||
tlvdb_visit(this_db, tlv_hash, ch, 0);
|
||||
|
||||
if (memcmp(data + 5 + data[4] + 1 + 8, crypto_hash_read(ch), 20)) {
|
||||
printf("ERROR: calculated hash error\n");
|
||||
crypto_hash_close(ch);
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
crypto_hash_close(ch);
|
||||
if (memcmp(data + 5 + data[4] + 1 + 8, crypto_hash_read(ch), 20)) {
|
||||
printf("ERROR: calculated hash error\n");
|
||||
crypto_hash_close(ch);
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
crypto_hash_close(ch);
|
||||
|
||||
size_t idn_len = data[4];
|
||||
if (idn_len > data[3] - 1) {
|
||||
printf("ERROR: Invalid IDN length\n");
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
size_t idn_len = data[4];
|
||||
if (idn_len > data[3] - 1) {
|
||||
printf("ERROR: Invalid IDN length\n");
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct tlvdb *idn_db = tlvdb_fixed(0x9f4c, idn_len, data + 5);
|
||||
free(data);
|
||||
struct tlvdb *idn_db = tlvdb_fixed(0x9f4c, idn_len, data + 5);
|
||||
free(data);
|
||||
|
||||
return idn_db;
|
||||
return idn_db;
|
||||
}
|
||||
|
|
|
@ -34,15 +34,15 @@ struct tlvdb *emv_pki_recover_idn(const struct emv_pk *pk, const struct tlvdb *d
|
|||
struct tlvdb *emv_pki_recover_idn_ex(const struct emv_pk *pk, const struct tlvdb *db, const struct tlv *dyn_tlv, bool showData);
|
||||
struct tlvdb *emv_pki_recover_atc_ex(const struct emv_pk *enc_pk, const struct tlvdb *db, bool showData);
|
||||
struct tlvdb *emv_pki_perform_cda(const struct emv_pk *enc_pk, const struct tlvdb *db,
|
||||
const struct tlvdb *this_db,
|
||||
const struct tlv *pdol_data_tlv,
|
||||
const struct tlv *crm1_tlv,
|
||||
const struct tlv *crm2_tlv);
|
||||
const struct tlvdb *this_db,
|
||||
const struct tlv *pdol_data_tlv,
|
||||
const struct tlv *crm1_tlv,
|
||||
const struct tlv *crm2_tlv);
|
||||
struct tlvdb *emv_pki_perform_cda_ex(const struct emv_pk *enc_pk, const struct tlvdb *db,
|
||||
const struct tlvdb *this_db,
|
||||
const struct tlv *pdol_data_tlv,
|
||||
const struct tlv *crm1_tlv,
|
||||
const struct tlv *crm2_tlv,
|
||||
bool showData);
|
||||
const struct tlvdb *this_db,
|
||||
const struct tlv *pdol_data_tlv,
|
||||
const struct tlv *crm1_tlv,
|
||||
const struct tlv *crm2_tlv,
|
||||
bool showData);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -25,259 +25,259 @@
|
|||
#include <stdarg.h>
|
||||
|
||||
struct emv_pk *emv_pki_make_ca(const struct crypto_pk *cp,
|
||||
const unsigned char *rid, unsigned char index,
|
||||
unsigned int expire, enum crypto_algo_hash hash_algo)
|
||||
const unsigned char *rid, unsigned char index,
|
||||
unsigned int expire, enum crypto_algo_hash hash_algo)
|
||||
{
|
||||
size_t modlen, explen;
|
||||
unsigned char *mod, *exp;
|
||||
size_t modlen, explen;
|
||||
unsigned char *mod, *exp;
|
||||
|
||||
if (!rid)
|
||||
return NULL;
|
||||
if (!rid)
|
||||
return NULL;
|
||||
|
||||
mod = crypto_pk_get_parameter(cp, 0, &modlen);
|
||||
exp = crypto_pk_get_parameter(cp, 1, &explen);
|
||||
mod = crypto_pk_get_parameter(cp, 0, &modlen);
|
||||
exp = crypto_pk_get_parameter(cp, 1, &explen);
|
||||
|
||||
if (!mod || !modlen || !exp || !explen) {
|
||||
free(mod);
|
||||
free(exp);
|
||||
if (!mod || !modlen || !exp || !explen) {
|
||||
free(mod);
|
||||
free(exp);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct emv_pk *pk = emv_pk_new(modlen, explen);
|
||||
memcpy(pk->rid, rid, 5);
|
||||
pk->index = index;
|
||||
pk->expire = expire;
|
||||
pk->pk_algo = crypto_pk_get_algo(cp);
|
||||
pk->hash_algo = hash_algo;
|
||||
memcpy(pk->modulus, mod, modlen);
|
||||
memcpy(pk->exp, exp, explen);
|
||||
struct emv_pk *pk = emv_pk_new(modlen, explen);
|
||||
memcpy(pk->rid, rid, 5);
|
||||
pk->index = index;
|
||||
pk->expire = expire;
|
||||
pk->pk_algo = crypto_pk_get_algo(cp);
|
||||
pk->hash_algo = hash_algo;
|
||||
memcpy(pk->modulus, mod, modlen);
|
||||
memcpy(pk->exp, exp, explen);
|
||||
|
||||
free(mod);
|
||||
free(exp);
|
||||
free(mod);
|
||||
free(exp);
|
||||
|
||||
struct crypto_hash *ch = crypto_hash_open(pk->hash_algo);
|
||||
if (!ch) {
|
||||
emv_pk_free(pk);
|
||||
return false;
|
||||
}
|
||||
struct crypto_hash *ch = crypto_hash_open(pk->hash_algo);
|
||||
if (!ch) {
|
||||
emv_pk_free(pk);
|
||||
return false;
|
||||
}
|
||||
|
||||
crypto_hash_write(ch, pk->rid, sizeof(pk->rid));
|
||||
crypto_hash_write(ch, &pk->index, 1);
|
||||
crypto_hash_write(ch, pk->modulus, pk->mlen);
|
||||
crypto_hash_write(ch, pk->exp, pk->elen);
|
||||
crypto_hash_write(ch, pk->rid, sizeof(pk->rid));
|
||||
crypto_hash_write(ch, &pk->index, 1);
|
||||
crypto_hash_write(ch, pk->modulus, pk->mlen);
|
||||
crypto_hash_write(ch, pk->exp, pk->elen);
|
||||
|
||||
unsigned char *h = crypto_hash_read(ch);
|
||||
if (!h) {
|
||||
crypto_hash_close(ch);
|
||||
emv_pk_free(pk);
|
||||
unsigned char *h = crypto_hash_read(ch);
|
||||
if (!h) {
|
||||
crypto_hash_close(ch);
|
||||
emv_pk_free(pk);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(pk->hash, h, crypto_hash_get_size(ch));
|
||||
crypto_hash_close(ch);
|
||||
memcpy(pk->hash, h, crypto_hash_get_size(ch));
|
||||
crypto_hash_close(ch);
|
||||
|
||||
return pk;
|
||||
return pk;
|
||||
}
|
||||
|
||||
static struct tlvdb *emv_pki_sign_message(const struct crypto_pk *cp,
|
||||
tlv_tag_t cert_tag, tlv_tag_t rem_tag,
|
||||
const unsigned char *msg, size_t msg_len,
|
||||
... /* A list of tlv pointers, end with NULL */
|
||||
)
|
||||
tlv_tag_t cert_tag, tlv_tag_t rem_tag,
|
||||
const unsigned char *msg, size_t msg_len,
|
||||
... /* A list of tlv pointers, end with NULL */
|
||||
)
|
||||
{
|
||||
size_t tmp_len = (crypto_pk_get_nbits(cp) + 7) / 8;
|
||||
unsigned char *tmp = malloc(tmp_len);
|
||||
if (!tmp)
|
||||
return NULL;
|
||||
size_t tmp_len = (crypto_pk_get_nbits(cp) + 7) / 8;
|
||||
unsigned char *tmp = malloc(tmp_len);
|
||||
if (!tmp)
|
||||
return NULL;
|
||||
|
||||
// XXX
|
||||
struct crypto_hash *ch = crypto_hash_open(HASH_SHA_1);
|
||||
if (!ch) {
|
||||
free(tmp);
|
||||
// XXX
|
||||
struct crypto_hash *ch = crypto_hash_open(HASH_SHA_1);
|
||||
if (!ch) {
|
||||
free(tmp);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tmp[0] = 0x6a;
|
||||
tmp[tmp_len - 1] = 0xbc;
|
||||
tmp[0] = 0x6a;
|
||||
tmp[tmp_len - 1] = 0xbc;
|
||||
|
||||
const unsigned char *rem;
|
||||
size_t rem_len;
|
||||
size_t hash_len = crypto_hash_get_size(ch);
|
||||
size_t part_len = tmp_len - 2 - hash_len;
|
||||
if (part_len < msg_len) {
|
||||
memcpy(tmp + 1, msg, part_len);
|
||||
rem = msg + part_len;
|
||||
rem_len = msg_len - part_len;
|
||||
} else {
|
||||
memcpy(tmp + 1, msg, msg_len);
|
||||
memset(tmp + 1 + msg_len, 0xbb, part_len - msg_len);
|
||||
rem = NULL;
|
||||
rem_len = 0;
|
||||
}
|
||||
crypto_hash_write(ch, tmp + 1, part_len);
|
||||
crypto_hash_write(ch, rem, rem_len);
|
||||
const unsigned char *rem;
|
||||
size_t rem_len;
|
||||
size_t hash_len = crypto_hash_get_size(ch);
|
||||
size_t part_len = tmp_len - 2 - hash_len;
|
||||
if (part_len < msg_len) {
|
||||
memcpy(tmp + 1, msg, part_len);
|
||||
rem = msg + part_len;
|
||||
rem_len = msg_len - part_len;
|
||||
} else {
|
||||
memcpy(tmp + 1, msg, msg_len);
|
||||
memset(tmp + 1 + msg_len, 0xbb, part_len - msg_len);
|
||||
rem = NULL;
|
||||
rem_len = 0;
|
||||
}
|
||||
crypto_hash_write(ch, tmp + 1, part_len);
|
||||
crypto_hash_write(ch, rem, rem_len);
|
||||
|
||||
va_list vl;
|
||||
va_start(vl, msg_len);
|
||||
while (true) {
|
||||
const struct tlv *add_tlv = va_arg(vl, const struct tlv *);
|
||||
if (!add_tlv)
|
||||
break;
|
||||
va_list vl;
|
||||
va_start(vl, msg_len);
|
||||
while (true) {
|
||||
const struct tlv *add_tlv = va_arg(vl, const struct tlv *);
|
||||
if (!add_tlv)
|
||||
break;
|
||||
|
||||
crypto_hash_write(ch, add_tlv->value, add_tlv->len);
|
||||
}
|
||||
va_end(vl);
|
||||
crypto_hash_write(ch, add_tlv->value, add_tlv->len);
|
||||
}
|
||||
va_end(vl);
|
||||
|
||||
unsigned char *h = crypto_hash_read(ch);
|
||||
if (!h) {
|
||||
crypto_hash_close(ch);
|
||||
free(tmp);
|
||||
unsigned char *h = crypto_hash_read(ch);
|
||||
if (!h) {
|
||||
crypto_hash_close(ch);
|
||||
free(tmp);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(tmp + 1 + part_len, h, hash_len);
|
||||
crypto_hash_close(ch);
|
||||
memcpy(tmp + 1 + part_len, h, hash_len);
|
||||
crypto_hash_close(ch);
|
||||
|
||||
size_t cert_len;
|
||||
unsigned char *cert = crypto_pk_decrypt(cp, tmp, tmp_len, &cert_len);
|
||||
free(tmp);
|
||||
size_t cert_len;
|
||||
unsigned char *cert = crypto_pk_decrypt(cp, tmp, tmp_len, &cert_len);
|
||||
free(tmp);
|
||||
|
||||
if (!cert)
|
||||
return NULL;
|
||||
if (!cert)
|
||||
return NULL;
|
||||
|
||||
struct tlvdb *db = tlvdb_fixed(cert_tag, cert_len, cert);
|
||||
free(cert);
|
||||
if (!db)
|
||||
return NULL;
|
||||
struct tlvdb *db = tlvdb_fixed(cert_tag, cert_len, cert);
|
||||
free(cert);
|
||||
if (!db)
|
||||
return NULL;
|
||||
|
||||
if (rem) {
|
||||
struct tlvdb *rdb = tlvdb_fixed(rem_tag, rem_len, rem);
|
||||
if (!rdb) {
|
||||
tlvdb_free(db);
|
||||
if (rem) {
|
||||
struct tlvdb *rdb = tlvdb_fixed(rem_tag, rem_len, rem);
|
||||
if (!rdb) {
|
||||
tlvdb_free(db);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
tlvdb_add(db, rdb);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
tlvdb_add(db, rdb);
|
||||
}
|
||||
|
||||
return db;
|
||||
return db;
|
||||
}
|
||||
|
||||
static struct tlvdb *emv_pki_sign_key(const struct crypto_pk *cp,
|
||||
struct emv_pk *ipk,
|
||||
unsigned char msgtype,
|
||||
size_t pan_len,
|
||||
tlv_tag_t cert_tag,
|
||||
tlv_tag_t exp_tag,
|
||||
tlv_tag_t rem_tag,
|
||||
const struct tlv *add_tlv
|
||||
)
|
||||
struct emv_pk *ipk,
|
||||
unsigned char msgtype,
|
||||
size_t pan_len,
|
||||
tlv_tag_t cert_tag,
|
||||
tlv_tag_t exp_tag,
|
||||
tlv_tag_t rem_tag,
|
||||
const struct tlv *add_tlv
|
||||
)
|
||||
{
|
||||
unsigned pos = 0;
|
||||
unsigned char *msg = malloc(1 + pan_len + 2 + 3 + 1 + 1 + 1 + 1 + ipk->mlen);
|
||||
unsigned pos = 0;
|
||||
unsigned char *msg = malloc(1 + pan_len + 2 + 3 + 1 + 1 + 1 + 1 + ipk->mlen);
|
||||
|
||||
if (!msg)
|
||||
return NULL;
|
||||
if (!msg)
|
||||
return NULL;
|
||||
|
||||
msg[pos++] = msgtype;
|
||||
memcpy(msg + pos, ipk->pan, pan_len); pos += pan_len;
|
||||
msg[pos++] = (ipk->expire >> 8) & 0xff;
|
||||
msg[pos++] = (ipk->expire >> 16) & 0xff;
|
||||
memcpy(msg + pos, ipk->serial, 3); pos += 3;
|
||||
msg[pos++] = ipk->hash_algo;
|
||||
msg[pos++] = ipk->pk_algo;
|
||||
msg[pos++] = ipk->mlen;
|
||||
msg[pos++] = ipk->elen;
|
||||
memcpy(msg + pos, ipk->modulus, ipk->mlen);
|
||||
pos += ipk->mlen;
|
||||
msg[pos++] = msgtype;
|
||||
memcpy(msg + pos, ipk->pan, pan_len); pos += pan_len;
|
||||
msg[pos++] = (ipk->expire >> 8) & 0xff;
|
||||
msg[pos++] = (ipk->expire >> 16) & 0xff;
|
||||
memcpy(msg + pos, ipk->serial, 3); pos += 3;
|
||||
msg[pos++] = ipk->hash_algo;
|
||||
msg[pos++] = ipk->pk_algo;
|
||||
msg[pos++] = ipk->mlen;
|
||||
msg[pos++] = ipk->elen;
|
||||
memcpy(msg + pos, ipk->modulus, ipk->mlen);
|
||||
pos += ipk->mlen;
|
||||
|
||||
struct tlvdb *exp_db = tlvdb_fixed(exp_tag, ipk->elen, ipk->exp);
|
||||
if (!exp_db) {
|
||||
free(msg);
|
||||
struct tlvdb *exp_db = tlvdb_fixed(exp_tag, ipk->elen, ipk->exp);
|
||||
if (!exp_db) {
|
||||
free(msg);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct tlvdb *db = emv_pki_sign_message(cp,
|
||||
cert_tag, rem_tag,
|
||||
msg, pos,
|
||||
tlvdb_get(exp_db, exp_tag, NULL),
|
||||
add_tlv,
|
||||
NULL);
|
||||
free(msg);
|
||||
if (!db)
|
||||
return NULL;
|
||||
struct tlvdb *db = emv_pki_sign_message(cp,
|
||||
cert_tag, rem_tag,
|
||||
msg, pos,
|
||||
tlvdb_get(exp_db, exp_tag, NULL),
|
||||
add_tlv,
|
||||
NULL);
|
||||
free(msg);
|
||||
if (!db)
|
||||
return NULL;
|
||||
|
||||
tlvdb_add(db, exp_db);
|
||||
tlvdb_add(db, exp_db);
|
||||
|
||||
return db;
|
||||
return db;
|
||||
}
|
||||
|
||||
struct tlvdb *emv_pki_sign_issuer_cert(const struct crypto_pk *cp, struct emv_pk *issuer_pk)
|
||||
{
|
||||
return emv_pki_sign_key(cp, issuer_pk, 2, 4, 0x90, 0x9f32, 0x92, NULL);
|
||||
return emv_pki_sign_key(cp, issuer_pk, 2, 4, 0x90, 0x9f32, 0x92, NULL);
|
||||
}
|
||||
|
||||
struct tlvdb *emv_pki_sign_icc_cert(const struct crypto_pk *cp, struct emv_pk *icc_pk, const struct tlv *sda_tlv)
|
||||
{
|
||||
return emv_pki_sign_key(cp, icc_pk, 4, 10, 0x9f46, 0x9f47, 0x9f48, sda_tlv);
|
||||
return emv_pki_sign_key(cp, icc_pk, 4, 10, 0x9f46, 0x9f47, 0x9f48, sda_tlv);
|
||||
}
|
||||
|
||||
struct tlvdb *emv_pki_sign_icc_pe_cert(const struct crypto_pk *cp, struct emv_pk *icc_pe_pk)
|
||||
{
|
||||
return emv_pki_sign_key(cp, icc_pe_pk, 4, 10, 0x9f2d, 0x9f2e, 0x9f2f, NULL);
|
||||
return emv_pki_sign_key(cp, icc_pe_pk, 4, 10, 0x9f2d, 0x9f2e, 0x9f2f, NULL);
|
||||
}
|
||||
|
||||
struct tlvdb *emv_pki_sign_dac(const struct crypto_pk *cp, const struct tlv *dac_tlv, const struct tlv *sda_tlv)
|
||||
{
|
||||
unsigned pos = 0;
|
||||
unsigned char *msg = malloc(1+1+dac_tlv->len);
|
||||
unsigned pos = 0;
|
||||
unsigned char *msg = malloc(1+1+dac_tlv->len);
|
||||
|
||||
if (!msg)
|
||||
return NULL;
|
||||
if (!msg)
|
||||
return NULL;
|
||||
|
||||
msg[pos++] = 3;
|
||||
msg[pos++] = HASH_SHA_1;
|
||||
memcpy(msg+pos, dac_tlv->value, dac_tlv->len);
|
||||
pos += dac_tlv->len;
|
||||
msg[pos++] = 3;
|
||||
msg[pos++] = HASH_SHA_1;
|
||||
memcpy(msg+pos, dac_tlv->value, dac_tlv->len);
|
||||
pos += dac_tlv->len;
|
||||
|
||||
struct tlvdb *db = emv_pki_sign_message(cp,
|
||||
0x93, 0,
|
||||
msg, pos,
|
||||
sda_tlv,
|
||||
NULL);
|
||||
struct tlvdb *db = emv_pki_sign_message(cp,
|
||||
0x93, 0,
|
||||
msg, pos,
|
||||
sda_tlv,
|
||||
NULL);
|
||||
|
||||
free(msg);
|
||||
free(msg);
|
||||
|
||||
return db;
|
||||
return db;
|
||||
}
|
||||
|
||||
struct tlvdb *emv_pki_sign_idn(const struct crypto_pk *cp, const struct tlv *idn_tlv, const struct tlv *dyn_tlv)
|
||||
{
|
||||
unsigned pos = 0;
|
||||
unsigned char *msg = malloc(1+1+1+1+idn_tlv->len);
|
||||
unsigned pos = 0;
|
||||
unsigned char *msg = malloc(1+1+1+1+idn_tlv->len);
|
||||
|
||||
if (!msg)
|
||||
return NULL;
|
||||
if (!msg)
|
||||
return NULL;
|
||||
|
||||
msg[pos++] = 5;
|
||||
msg[pos++] = HASH_SHA_1;
|
||||
msg[pos++] = idn_tlv->len + 1;
|
||||
msg[pos++] = idn_tlv->len;
|
||||
memcpy(msg+pos, idn_tlv->value, idn_tlv->len);
|
||||
pos += idn_tlv->len;
|
||||
msg[pos++] = 5;
|
||||
msg[pos++] = HASH_SHA_1;
|
||||
msg[pos++] = idn_tlv->len + 1;
|
||||
msg[pos++] = idn_tlv->len;
|
||||
memcpy(msg+pos, idn_tlv->value, idn_tlv->len);
|
||||
pos += idn_tlv->len;
|
||||
|
||||
struct tlvdb *db = emv_pki_sign_message(cp,
|
||||
0x9f4b, 0,
|
||||
msg, pos,
|
||||
dyn_tlv,
|
||||
NULL);
|
||||
struct tlvdb *db = emv_pki_sign_message(cp,
|
||||
0x9f4b, 0,
|
||||
msg, pos,
|
||||
dyn_tlv,
|
||||
NULL);
|
||||
|
||||
free(msg);
|
||||
free(msg);
|
||||
|
||||
return db;
|
||||
return db;
|
||||
}
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
#include <stddef.h>
|
||||
|
||||
struct emv_pk *emv_pki_make_ca(const struct crypto_pk *cp,
|
||||
const unsigned char *rid, unsigned char index,
|
||||
unsigned int expire, enum crypto_algo_hash hash_algo);
|
||||
const unsigned char *rid, unsigned char index,
|
||||
unsigned int expire, enum crypto_algo_hash hash_algo);
|
||||
struct tlvdb *emv_pki_sign_issuer_cert(const struct crypto_pk *cp, struct emv_pk *issuer_pk);
|
||||
struct tlvdb *emv_pki_sign_icc_cert(const struct crypto_pk *cp, struct emv_pk *icc_pk, const struct tlv *sda_tlv);
|
||||
struct tlvdb *emv_pki_sign_icc_pe_cert(const struct crypto_pk *cp, struct emv_pk *icc_pe_pk);
|
||||
|
|
|
@ -24,152 +24,152 @@
|
|||
#include "emv_roca.h"
|
||||
|
||||
static uint8_t g_primes[ROCA_PRINTS_LENGTH] = {
|
||||
11, 13, 17, 19, 37, 53, 61, 71, 73, 79, 97, 103, 107, 109, 127, 151, 157
|
||||
11, 13, 17, 19, 37, 53, 61, 71, 73, 79, 97, 103, 107, 109, 127, 151, 157
|
||||
};
|
||||
|
||||
mbedtls_mpi g_prints[ROCA_PRINTS_LENGTH];
|
||||
|
||||
void rocacheck_init(void) {
|
||||
|
||||
for (int i = 0; i < ROCA_PRINTS_LENGTH; i++)
|
||||
mbedtls_mpi_init(&g_prints[i]);
|
||||
for (int i = 0; i < ROCA_PRINTS_LENGTH; i++)
|
||||
mbedtls_mpi_init(&g_prints[i]);
|
||||
|
||||
mbedtls_mpi_read_string(&g_prints[0], 10, "1026");
|
||||
mbedtls_mpi_read_string(&g_prints[1], 10, "5658");
|
||||
mbedtls_mpi_read_string(&g_prints[2], 10, "107286");
|
||||
mbedtls_mpi_read_string(&g_prints[3], 10, "199410");
|
||||
mbedtls_mpi_read_string(&g_prints[4], 10, "67109890");
|
||||
mbedtls_mpi_read_string(&g_prints[5], 10, "5310023542746834");
|
||||
mbedtls_mpi_read_string(&g_prints[6], 10, "1455791217086302986");
|
||||
mbedtls_mpi_read_string(&g_prints[7], 10, "20052041432995567486");
|
||||
mbedtls_mpi_read_string(&g_prints[8], 10, "6041388139249378920330");
|
||||
mbedtls_mpi_read_string(&g_prints[9], 10, "207530445072488465666");
|
||||
mbedtls_mpi_read_string(&g_prints[10], 10, "79228162521181866724264247298");
|
||||
mbedtls_mpi_read_string(&g_prints[11], 10, "1760368345969468176824550810518");
|
||||
mbedtls_mpi_read_string(&g_prints[12], 10, "50079290986288516948354744811034");
|
||||
mbedtls_mpi_read_string(&g_prints[13], 10, "473022961816146413042658758988474");
|
||||
mbedtls_mpi_read_string(&g_prints[14], 10, "144390480366845522447407333004847678774");
|
||||
mbedtls_mpi_read_string(&g_prints[15], 10, "1800793591454480341970779146165214289059119882");
|
||||
mbedtls_mpi_read_string(&g_prints[16], 10, "126304807362733370595828809000324029340048915994");
|
||||
mbedtls_mpi_read_string(&g_prints[0], 10, "1026");
|
||||
mbedtls_mpi_read_string(&g_prints[1], 10, "5658");
|
||||
mbedtls_mpi_read_string(&g_prints[2], 10, "107286");
|
||||
mbedtls_mpi_read_string(&g_prints[3], 10, "199410");
|
||||
mbedtls_mpi_read_string(&g_prints[4], 10, "67109890");
|
||||
mbedtls_mpi_read_string(&g_prints[5], 10, "5310023542746834");
|
||||
mbedtls_mpi_read_string(&g_prints[6], 10, "1455791217086302986");
|
||||
mbedtls_mpi_read_string(&g_prints[7], 10, "20052041432995567486");
|
||||
mbedtls_mpi_read_string(&g_prints[8], 10, "6041388139249378920330");
|
||||
mbedtls_mpi_read_string(&g_prints[9], 10, "207530445072488465666");
|
||||
mbedtls_mpi_read_string(&g_prints[10], 10, "79228162521181866724264247298");
|
||||
mbedtls_mpi_read_string(&g_prints[11], 10, "1760368345969468176824550810518");
|
||||
mbedtls_mpi_read_string(&g_prints[12], 10, "50079290986288516948354744811034");
|
||||
mbedtls_mpi_read_string(&g_prints[13], 10, "473022961816146413042658758988474");
|
||||
mbedtls_mpi_read_string(&g_prints[14], 10, "144390480366845522447407333004847678774");
|
||||
mbedtls_mpi_read_string(&g_prints[15], 10, "1800793591454480341970779146165214289059119882");
|
||||
mbedtls_mpi_read_string(&g_prints[16], 10, "126304807362733370595828809000324029340048915994");
|
||||
}
|
||||
|
||||
void rocacheck_cleanup(void) {
|
||||
for (int i = 0; i < ROCA_PRINTS_LENGTH; i++)
|
||||
mbedtls_mpi_free(&g_prints[i]);
|
||||
for (int i = 0; i < ROCA_PRINTS_LENGTH; i++)
|
||||
mbedtls_mpi_free(&g_prints[i]);
|
||||
}
|
||||
|
||||
int bitand_is_zero( mbedtls_mpi* a, mbedtls_mpi* b ) {
|
||||
int bitand_is_zero( mbedtls_mpi* a, mbedtls_mpi* b ) {
|
||||
|
||||
for (int i = 0; i < mbedtls_mpi_bitlen(a); i++) {
|
||||
for (int i = 0; i < mbedtls_mpi_bitlen(a); i++) {
|
||||
|
||||
if (mbedtls_mpi_get_bit(a, i) && mbedtls_mpi_get_bit(b, i))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
if (mbedtls_mpi_get_bit(a, i) && mbedtls_mpi_get_bit(b, i))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
mbedtls_mpi_uint mpi_get_uint(const mbedtls_mpi *X) {
|
||||
|
||||
if (X->n == 1 && X->s > 0) {
|
||||
return X->p[0];
|
||||
}
|
||||
printf("ZERRRRO!!!\n");
|
||||
return 0;
|
||||
if (X->n == 1 && X->s > 0) {
|
||||
return X->p[0];
|
||||
}
|
||||
printf("ZERRRRO!!!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void print_mpi(const char *msg, int radix, const mbedtls_mpi *X) {
|
||||
|
||||
char Xchar[400] = {0};
|
||||
size_t len = 0;
|
||||
char Xchar[400] = {0};
|
||||
size_t len = 0;
|
||||
|
||||
mbedtls_mpi_write_string(X, radix, Xchar, sizeof(Xchar), &len);
|
||||
printf("%s[%d] %s\n", msg, len, Xchar);
|
||||
mbedtls_mpi_write_string(X, radix, Xchar, sizeof(Xchar), &len);
|
||||
printf("%s[%d] %s\n", msg, len, Xchar);
|
||||
}
|
||||
|
||||
bool emv_rocacheck(const unsigned char *buf, size_t buflen, bool verbose) {
|
||||
|
||||
mbedtls_mpi t_modulus;
|
||||
mbedtls_mpi_init(&t_modulus);
|
||||
mbedtls_mpi t_modulus;
|
||||
mbedtls_mpi_init(&t_modulus);
|
||||
|
||||
bool ret = false;
|
||||
bool ret = false;
|
||||
|
||||
rocacheck_init();
|
||||
rocacheck_init();
|
||||
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary(&t_modulus, buf, buflen) );
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary(&t_modulus, buf, buflen) );
|
||||
|
||||
for (int i = 0; i < ROCA_PRINTS_LENGTH; i++) {
|
||||
for (int i = 0; i < ROCA_PRINTS_LENGTH; i++) {
|
||||
|
||||
mbedtls_mpi t_temp;
|
||||
mbedtls_mpi t_prime;
|
||||
mbedtls_mpi g_one;
|
||||
mbedtls_mpi t_temp;
|
||||
mbedtls_mpi t_prime;
|
||||
mbedtls_mpi g_one;
|
||||
|
||||
mbedtls_mpi_init(&t_temp);
|
||||
mbedtls_mpi_init(&t_prime);
|
||||
mbedtls_mpi_init(&g_one);
|
||||
mbedtls_mpi_init(&t_temp);
|
||||
mbedtls_mpi_init(&t_prime);
|
||||
mbedtls_mpi_init(&g_one);
|
||||
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_read_string(&g_one, 10, "1") );
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_read_string(&g_one, 10, "1") );
|
||||
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_add_int(&t_prime, &t_prime, g_primes[i]) );
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_add_int(&t_prime, &t_prime, g_primes[i]) );
|
||||
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi(&t_temp, &t_modulus, &t_prime) );
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi(&t_temp, &t_modulus, &t_prime) );
|
||||
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l(&g_one, mpi_get_uint(&t_temp)) );
|
||||
MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l(&g_one, mpi_get_uint(&t_temp)) );
|
||||
|
||||
if (bitand_is_zero(&g_one, &g_prints[i])) {
|
||||
if (verbose)
|
||||
PrintAndLogEx(FAILED, "No fingerprint found.\n");
|
||||
goto cleanup;
|
||||
}
|
||||
if (bitand_is_zero(&g_one, &g_prints[i])) {
|
||||
if (verbose)
|
||||
PrintAndLogEx(FAILED, "No fingerprint found.\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
mbedtls_mpi_free(&g_one);
|
||||
mbedtls_mpi_free(&t_temp);
|
||||
mbedtls_mpi_free(&t_prime);
|
||||
}
|
||||
mbedtls_mpi_free(&g_one);
|
||||
mbedtls_mpi_free(&t_temp);
|
||||
mbedtls_mpi_free(&t_prime);
|
||||
}
|
||||
|
||||
ret = true;
|
||||
if (verbose)
|
||||
PrintAndLogEx(SUCCESS, "Fingerprint found!\n");
|
||||
ret = true;
|
||||
if (verbose)
|
||||
PrintAndLogEx(SUCCESS, "Fingerprint found!\n");
|
||||
|
||||
cleanup:
|
||||
mbedtls_mpi_free(&t_modulus);
|
||||
mbedtls_mpi_free(&t_modulus);
|
||||
|
||||
rocacheck_cleanup();
|
||||
return ret;
|
||||
rocacheck_cleanup();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int roca_self_test(void) {
|
||||
int ret = 0;
|
||||
int ret = 0;
|
||||
|
||||
PrintAndLogEx(INFO, "ROCA check vulnerability tests" );
|
||||
PrintAndLogEx(INFO, "ROCA check vulnerability tests" );
|
||||
|
||||
// positive
|
||||
uint8_t keyp[] = "\x94\x4e\x13\x20\x8a\x28\x0c\x37\xef\xc3\x1c\x31\x14\x48\x5e\x59"\
|
||||
"\x01\x92\xad\xbb\x8e\x11\xc8\x7c\xad\x60\xcd\xef\x00\x37\xce\x99"\
|
||||
"\x27\x83\x30\xd3\xf4\x71\xa2\x53\x8f\xa6\x67\x80\x2e\xd2\xa3\xc4"\
|
||||
"\x4a\x8b\x7d\xea\x82\x6e\x88\x8d\x0a\xa3\x41\xfd\x66\x4f\x7f\xa7";
|
||||
// positive
|
||||
uint8_t keyp[] = "\x94\x4e\x13\x20\x8a\x28\x0c\x37\xef\xc3\x1c\x31\x14\x48\x5e\x59"\
|
||||
"\x01\x92\xad\xbb\x8e\x11\xc8\x7c\xad\x60\xcd\xef\x00\x37\xce\x99"\
|
||||
"\x27\x83\x30\xd3\xf4\x71\xa2\x53\x8f\xa6\x67\x80\x2e\xd2\xa3\xc4"\
|
||||
"\x4a\x8b\x7d\xea\x82\x6e\x88\x8d\x0a\xa3\x41\xfd\x66\x4f\x7f\xa7";
|
||||
|
||||
|
||||
if (emv_rocacheck(keyp, 64, false)) {
|
||||
PrintAndLogEx(SUCCESS, "Weak modulus [ %s]", _GREEN_(PASS) );
|
||||
}
|
||||
else {
|
||||
ret++;
|
||||
PrintAndLogEx(FAILED, "Weak modulus [ %s]", _RED_(FAIL) );
|
||||
}
|
||||
if (emv_rocacheck(keyp, 64, false)) {
|
||||
PrintAndLogEx(SUCCESS, "Weak modulus [ %s]", _GREEN_(PASS) );
|
||||
}
|
||||
else {
|
||||
ret++;
|
||||
PrintAndLogEx(FAILED, "Weak modulus [ %s]", _RED_(FAIL) );
|
||||
}
|
||||
|
||||
// negative
|
||||
uint8_t keyn[] = "\x84\x4e\x13\x20\x8a\x28\x0c\x37\xef\xc3\x1c\x31\x14\x48\x5e\x59"\
|
||||
"\x01\x92\xad\xbb\x8e\x11\xc8\x7c\xad\x60\xcd\xef\x00\x37\xce\x99"\
|
||||
"\x27\x83\x30\xd3\xf4\x71\xa2\x53\x8f\xa6\x67\x80\x2e\xd2\xa3\xc4"\
|
||||
"\x4a\x8b\x7d\xea\x82\x6e\x88\x8d\x0a\xa3\x41\xfd\x66\x4f\x7f\xa7";
|
||||
// negative
|
||||
uint8_t keyn[] = "\x84\x4e\x13\x20\x8a\x28\x0c\x37\xef\xc3\x1c\x31\x14\x48\x5e\x59"\
|
||||
"\x01\x92\xad\xbb\x8e\x11\xc8\x7c\xad\x60\xcd\xef\x00\x37\xce\x99"\
|
||||
"\x27\x83\x30\xd3\xf4\x71\xa2\x53\x8f\xa6\x67\x80\x2e\xd2\xa3\xc4"\
|
||||
"\x4a\x8b\x7d\xea\x82\x6e\x88\x8d\x0a\xa3\x41\xfd\x66\x4f\x7f\xa7";
|
||||
|
||||
if (emv_rocacheck(keyn, 64, false)) {
|
||||
ret++;
|
||||
PrintAndLogEx(FAILED, "Strong modulus [ %s]", _RED_(FAIL) );
|
||||
} else {
|
||||
PrintAndLogEx(SUCCESS, "Strong modulus [ %s]", _GREEN_(PASS) );
|
||||
}
|
||||
if (emv_rocacheck(keyn, 64, false)) {
|
||||
ret++;
|
||||
PrintAndLogEx(FAILED, "Strong modulus [ %s]", _RED_(FAIL) );
|
||||
} else {
|
||||
PrintAndLogEx(SUCCESS, "Strong modulus [ %s]", _GREEN_(PASS) );
|
||||
}
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#include "mbedtls/bignum.h"
|
||||
#include "util.h"
|
||||
|
||||
#define ROCA_PRINTS_LENGTH 17
|
||||
#define ROCA_PRINTS_LENGTH 17
|
||||
|
||||
extern bool emv_rocacheck( const unsigned char *buf, size_t buflen, bool verbose );
|
||||
extern int roca_self_test( void );
|
||||
|
|
File diff suppressed because it is too large
Load diff
1612
client/emv/emvcore.c
1612
client/emv/emvcore.c
File diff suppressed because it is too large
Load diff
|
@ -33,35 +33,35 @@
|
|||
#define APDU_AID_LEN 50
|
||||
|
||||
typedef enum {
|
||||
ECC_CONTACTLESS,
|
||||
ECC_CONTACT
|
||||
ECC_CONTACTLESS,
|
||||
ECC_CONTACT
|
||||
} EMVCommandChannel;
|
||||
|
||||
enum TransactionType {
|
||||
TT_MSD,
|
||||
TT_VSDC, // contact only. not standart for contactless
|
||||
TT_QVSDCMCHIP,
|
||||
TT_CDA,
|
||||
TT_MSD,
|
||||
TT_VSDC, // contact only. not standart for contactless
|
||||
TT_QVSDCMCHIP,
|
||||
TT_CDA,
|
||||
};
|
||||
extern char *TransactionTypeStr[];
|
||||
|
||||
typedef struct {
|
||||
uint8_t CLA;
|
||||
uint8_t INS;
|
||||
uint8_t P1;
|
||||
uint8_t P2;
|
||||
uint8_t Lc;
|
||||
uint8_t *data;
|
||||
uint8_t CLA;
|
||||
uint8_t INS;
|
||||
uint8_t P1;
|
||||
uint8_t P2;
|
||||
uint8_t Lc;
|
||||
uint8_t *data;
|
||||
} sAPDU;
|
||||
|
||||
enum CardPSVendor {
|
||||
CV_NA,
|
||||
CV_VISA,
|
||||
CV_MASTERCARD,
|
||||
CV_AMERICANEXPRESS,
|
||||
CV_JCB,
|
||||
CV_CB,
|
||||
CV_OTHER,
|
||||
CV_NA,
|
||||
CV_VISA,
|
||||
CV_MASTERCARD,
|
||||
CV_AMERICANEXPRESS,
|
||||
CV_JCB,
|
||||
CV_CB,
|
||||
CV_OTHER,
|
||||
};
|
||||
extern enum CardPSVendor GetCardPSVendor(uint8_t * AID, size_t AIDlen);
|
||||
|
||||
|
|
|
@ -61,342 +61,342 @@ static const ApplicationDataElm ApplicationData[] = {
|
|||
int ApplicationDataLen = sizeof(ApplicationData) / sizeof(ApplicationDataElm);
|
||||
|
||||
char* GetApplicationDataName(tlv_tag_t tag) {
|
||||
for (int i = 0; i < ApplicationDataLen; i++)
|
||||
if (ApplicationData[i].Tag == tag)
|
||||
return ApplicationData[i].Name;
|
||||
for (int i = 0; i < ApplicationDataLen; i++)
|
||||
if (ApplicationData[i].Tag == tag)
|
||||
return ApplicationData[i].Name;
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int JsonSaveJsonObject(json_t *root, char *path, json_t *value) {
|
||||
json_error_t error;
|
||||
json_error_t error;
|
||||
|
||||
if (strlen(path) < 1)
|
||||
return 1;
|
||||
if (strlen(path) < 1)
|
||||
return 1;
|
||||
|
||||
if (path[0] == '$') {
|
||||
if (json_path_set(root, path, value, 0, &error)) {
|
||||
PrintAndLog("ERROR: can't set json path: ", error.text);
|
||||
return 2;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return json_object_set_new(root, path, value);
|
||||
}
|
||||
if (path[0] == '$') {
|
||||
if (json_path_set(root, path, value, 0, &error)) {
|
||||
PrintAndLog("ERROR: can't set json path: ", error.text);
|
||||
return 2;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return json_object_set_new(root, path, value);
|
||||
}
|
||||
}
|
||||
|
||||
int JsonSaveInt(json_t *root, char *path, int value) {
|
||||
return JsonSaveJsonObject(root, path, json_integer(value));
|
||||
return JsonSaveJsonObject(root, path, json_integer(value));
|
||||
}
|
||||
|
||||
int JsonSaveStr(json_t *root, char *path, char *value) {
|
||||
return JsonSaveJsonObject(root, path, json_string(value));
|
||||
return JsonSaveJsonObject(root, path, json_string(value));
|
||||
};
|
||||
|
||||
int JsonSaveBufAsHexCompact(json_t *elm, char *path, uint8_t *data, size_t datalen) {
|
||||
char * msg = sprint_hex_inrow(data, datalen);
|
||||
if (msg && strlen(msg) && msg[strlen(msg) - 1] == ' ')
|
||||
msg[strlen(msg) - 1] = '\0';
|
||||
char * msg = sprint_hex_inrow(data, datalen);
|
||||
if (msg && strlen(msg) && msg[strlen(msg) - 1] == ' ')
|
||||
msg[strlen(msg) - 1] = '\0';
|
||||
|
||||
return JsonSaveStr(elm, path, msg);
|
||||
return JsonSaveStr(elm, path, msg);
|
||||
}
|
||||
|
||||
int JsonSaveBufAsHex(json_t *elm, char *path, uint8_t *data, size_t datalen) {
|
||||
char * msg = sprint_hex(data, datalen);
|
||||
if (msg && strlen(msg) && msg[strlen(msg) - 1] == ' ')
|
||||
msg[strlen(msg) - 1] = '\0';
|
||||
char * msg = sprint_hex(data, datalen);
|
||||
if (msg && strlen(msg) && msg[strlen(msg) - 1] == ' ')
|
||||
msg[strlen(msg) - 1] = '\0';
|
||||
|
||||
return JsonSaveStr(elm, path, msg);
|
||||
return JsonSaveStr(elm, path, msg);
|
||||
}
|
||||
|
||||
int JsonSaveHex(json_t *elm, char *path, uint64_t data, int datalen) {
|
||||
uint8_t bdata[8] = {0};
|
||||
int len = 0;
|
||||
if (!datalen) {
|
||||
for (uint64_t u = 0xffffffffffffffff; u; u = u << 8) {
|
||||
if (!(data & u)) {
|
||||
break;
|
||||
}
|
||||
len++;
|
||||
}
|
||||
if (!len)
|
||||
len = 1;
|
||||
} else {
|
||||
len = datalen;
|
||||
}
|
||||
num_to_bytes(data, len, bdata);
|
||||
uint8_t bdata[8] = {0};
|
||||
int len = 0;
|
||||
if (!datalen) {
|
||||
for (uint64_t u = 0xffffffffffffffff; u; u = u << 8) {
|
||||
if (!(data & u)) {
|
||||
break;
|
||||
}
|
||||
len++;
|
||||
}
|
||||
if (!len)
|
||||
len = 1;
|
||||
} else {
|
||||
len = datalen;
|
||||
}
|
||||
num_to_bytes(data, len, bdata);
|
||||
|
||||
return JsonSaveBufAsHex(elm, path, bdata, len);
|
||||
return JsonSaveBufAsHex(elm, path, bdata, len);
|
||||
}
|
||||
|
||||
int JsonSaveTLVValue(json_t *root, char *path, struct tlvdb *tlvdbelm) {
|
||||
const struct tlv *tlvelm = tlvdb_get_tlv(tlvdbelm);
|
||||
if (tlvelm)
|
||||
return JsonSaveBufAsHex(root, path, (uint8_t *)tlvelm->value, tlvelm->len);
|
||||
else
|
||||
return 1;
|
||||
const struct tlv *tlvelm = tlvdb_get_tlv(tlvdbelm);
|
||||
if (tlvelm)
|
||||
return JsonSaveBufAsHex(root, path, (uint8_t *)tlvelm->value, tlvelm->len);
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
int JsonSaveTLVElm(json_t *elm, char *path, struct tlv *tlvelm, bool saveName, bool saveValue, bool saveAppDataLink) {
|
||||
json_error_t error;
|
||||
json_error_t error;
|
||||
|
||||
if (strlen(path) < 1 || !tlvelm)
|
||||
return 1;
|
||||
if (strlen(path) < 1 || !tlvelm)
|
||||
return 1;
|
||||
|
||||
if (path[0] == '$') {
|
||||
if (path[0] == '$') {
|
||||
|
||||
json_t *obj = json_path_get(elm, path);
|
||||
if (!obj) {
|
||||
obj = json_object();
|
||||
json_t *obj = json_path_get(elm, path);
|
||||
if (!obj) {
|
||||
obj = json_object();
|
||||
|
||||
if (json_is_array(elm)) {
|
||||
if (json_array_append_new(elm, obj)) {
|
||||
PrintAndLog("ERROR: can't append array: %s", path);
|
||||
return 2;
|
||||
}
|
||||
} else {
|
||||
if (json_path_set(elm, path, obj, 0, &error)) {
|
||||
PrintAndLog("ERROR: can't set json path: ", error.text);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (json_is_array(elm)) {
|
||||
if (json_array_append_new(elm, obj)) {
|
||||
PrintAndLog("ERROR: can't append array: %s", path);
|
||||
return 2;
|
||||
}
|
||||
} else {
|
||||
if (json_path_set(elm, path, obj, 0, &error)) {
|
||||
PrintAndLog("ERROR: can't set json path: ", error.text);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (saveAppDataLink) {
|
||||
char * AppDataName = GetApplicationDataName(tlvelm->tag);
|
||||
if (AppDataName)
|
||||
JsonSaveStr(obj, "appdata", AppDataName);
|
||||
} else {
|
||||
char * name = emv_get_tag_name(tlvelm);
|
||||
if (saveName && name && strlen(name) > 0 && strncmp(name, "Unknown", 7))
|
||||
JsonSaveStr(obj, "name", emv_get_tag_name(tlvelm));
|
||||
JsonSaveHex(obj, "tag", tlvelm->tag, 0);
|
||||
if (saveValue) {
|
||||
JsonSaveHex(obj, "length", tlvelm->len, 0);
|
||||
JsonSaveBufAsHex(obj, "value", (uint8_t *)tlvelm->value, tlvelm->len);
|
||||
};
|
||||
}
|
||||
}
|
||||
if (saveAppDataLink) {
|
||||
char * AppDataName = GetApplicationDataName(tlvelm->tag);
|
||||
if (AppDataName)
|
||||
JsonSaveStr(obj, "appdata", AppDataName);
|
||||
} else {
|
||||
char * name = emv_get_tag_name(tlvelm);
|
||||
if (saveName && name && strlen(name) > 0 && strncmp(name, "Unknown", 7))
|
||||
JsonSaveStr(obj, "name", emv_get_tag_name(tlvelm));
|
||||
JsonSaveHex(obj, "tag", tlvelm->tag, 0);
|
||||
if (saveValue) {
|
||||
JsonSaveHex(obj, "length", tlvelm->len, 0);
|
||||
JsonSaveBufAsHex(obj, "value", (uint8_t *)tlvelm->value, tlvelm->len);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int JsonSaveTLVTreeElm(json_t *elm, char *path, struct tlvdb *tlvdbelm, bool saveName, bool saveValue, bool saveAppDataLink) {
|
||||
return JsonSaveTLVElm(elm, path, (struct tlv *)tlvdb_get_tlv(tlvdbelm), saveName, saveValue, saveAppDataLink);
|
||||
return JsonSaveTLVElm(elm, path, (struct tlv *)tlvdb_get_tlv(tlvdbelm), saveName, saveValue, saveAppDataLink);
|
||||
}
|
||||
|
||||
int JsonSaveTLVTree(json_t *root, json_t *elm, char *path, struct tlvdb *tlvdbelm) {
|
||||
struct tlvdb *tlvp = tlvdbelm;
|
||||
while (tlvp) {
|
||||
const struct tlv * tlvpelm = tlvdb_get_tlv(tlvp);
|
||||
char * AppDataName = NULL;
|
||||
if (tlvpelm)
|
||||
AppDataName = GetApplicationDataName(tlvpelm->tag);
|
||||
struct tlvdb *tlvp = tlvdbelm;
|
||||
while (tlvp) {
|
||||
const struct tlv * tlvpelm = tlvdb_get_tlv(tlvp);
|
||||
char * AppDataName = NULL;
|
||||
if (tlvpelm)
|
||||
AppDataName = GetApplicationDataName(tlvpelm->tag);
|
||||
|
||||
if (AppDataName) {
|
||||
char appdatalink[200] = {0};
|
||||
sprintf(appdatalink, "$.ApplicationData.%s", AppDataName);
|
||||
JsonSaveBufAsHex(root, appdatalink, (uint8_t *)tlvpelm->value, tlvpelm->len);
|
||||
}
|
||||
if (AppDataName) {
|
||||
char appdatalink[200] = {0};
|
||||
sprintf(appdatalink, "$.ApplicationData.%s", AppDataName);
|
||||
JsonSaveBufAsHex(root, appdatalink, (uint8_t *)tlvpelm->value, tlvpelm->len);
|
||||
}
|
||||
|
||||
json_t *pelm = json_path_get(elm, path);
|
||||
if (pelm && json_is_array(pelm)) {
|
||||
json_t *appendelm = json_object();
|
||||
json_array_append_new(pelm, appendelm);
|
||||
JsonSaveTLVTreeElm(appendelm, "$", tlvp, !AppDataName, !tlvdb_elm_get_children(tlvp), AppDataName);
|
||||
pelm = appendelm;
|
||||
} else {
|
||||
JsonSaveTLVTreeElm(elm, path, tlvp, !AppDataName, !tlvdb_elm_get_children(tlvp), AppDataName);
|
||||
pelm = json_path_get(elm, path);
|
||||
}
|
||||
json_t *pelm = json_path_get(elm, path);
|
||||
if (pelm && json_is_array(pelm)) {
|
||||
json_t *appendelm = json_object();
|
||||
json_array_append_new(pelm, appendelm);
|
||||
JsonSaveTLVTreeElm(appendelm, "$", tlvp, !AppDataName, !tlvdb_elm_get_children(tlvp), AppDataName);
|
||||
pelm = appendelm;
|
||||
} else {
|
||||
JsonSaveTLVTreeElm(elm, path, tlvp, !AppDataName, !tlvdb_elm_get_children(tlvp), AppDataName);
|
||||
pelm = json_path_get(elm, path);
|
||||
}
|
||||
|
||||
if (tlvdb_elm_get_children(tlvp)) {
|
||||
// get path element
|
||||
if(!pelm)
|
||||
return 1;
|
||||
if (tlvdb_elm_get_children(tlvp)) {
|
||||
// get path element
|
||||
if(!pelm)
|
||||
return 1;
|
||||
|
||||
// check childs element and add it if not found
|
||||
json_t *chjson = json_path_get(pelm, "$.Childs");
|
||||
if (!chjson) {
|
||||
json_object_set_new(pelm, "Childs", json_array());
|
||||
// check childs element and add it if not found
|
||||
json_t *chjson = json_path_get(pelm, "$.Childs");
|
||||
if (!chjson) {
|
||||
json_object_set_new(pelm, "Childs", json_array());
|
||||
|
||||
chjson = json_path_get(pelm, "$.Childs");
|
||||
}
|
||||
chjson = json_path_get(pelm, "$.Childs");
|
||||
}
|
||||
|
||||
// check
|
||||
if (!json_is_array(chjson)) {
|
||||
PrintAndLog("E->Internal logic error. `$.Childs` is not an array.");
|
||||
break;
|
||||
}
|
||||
// check
|
||||
if (!json_is_array(chjson)) {
|
||||
PrintAndLog("E->Internal logic error. `$.Childs` is not an array.");
|
||||
break;
|
||||
}
|
||||
|
||||
// Recursion
|
||||
JsonSaveTLVTree(root, chjson, "$", tlvdb_elm_get_children(tlvp));
|
||||
}
|
||||
// Recursion
|
||||
JsonSaveTLVTree(root, chjson, "$", tlvdb_elm_get_children(tlvp));
|
||||
}
|
||||
|
||||
tlvp = tlvdb_elm_get_next(tlvp);
|
||||
}
|
||||
return 0;
|
||||
tlvp = tlvdb_elm_get_next(tlvp);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool HexToBuffer(const char *errormsg, const char *hexvalue, uint8_t * buffer, size_t maxbufferlen, size_t *bufferlen) {
|
||||
int buflen = 0;
|
||||
int buflen = 0;
|
||||
|
||||
switch (param_gethex_to_eol(hexvalue, 0, buffer, maxbufferlen, &buflen)) {
|
||||
case 1:
|
||||
PrintAndLog("%s Invalid HEX value.", errormsg);
|
||||
return false;
|
||||
case 2:
|
||||
PrintAndLog("%s Hex value too large.", errormsg);
|
||||
return false;
|
||||
case 3:
|
||||
PrintAndLog("%s Hex value must have even number of digits.", errormsg);
|
||||
return false;
|
||||
}
|
||||
switch (param_gethex_to_eol(hexvalue, 0, buffer, maxbufferlen, &buflen)) {
|
||||
case 1:
|
||||
PrintAndLog("%s Invalid HEX value.", errormsg);
|
||||
return false;
|
||||
case 2:
|
||||
PrintAndLog("%s Hex value too large.", errormsg);
|
||||
return false;
|
||||
case 3:
|
||||
PrintAndLog("%s Hex value must have even number of digits.", errormsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (buflen > maxbufferlen) {
|
||||
PrintAndLog("%s HEX length (%d) more than %d", errormsg, (bufferlen) ? *bufferlen : -1, maxbufferlen);
|
||||
return false;
|
||||
}
|
||||
if (buflen > maxbufferlen) {
|
||||
PrintAndLog("%s HEX length (%d) more than %d", errormsg, (bufferlen) ? *bufferlen : -1, maxbufferlen);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( bufferlen )
|
||||
*bufferlen = buflen;
|
||||
if ( bufferlen )
|
||||
*bufferlen = buflen;
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
int JsonLoadStr(json_t *root, char *path, char *value) {
|
||||
if (!value)
|
||||
return 1;
|
||||
if (!value)
|
||||
return 1;
|
||||
|
||||
json_t *jelm = json_path_get((const json_t *)root, path);
|
||||
if (!jelm || !json_is_string(jelm))
|
||||
return 2;
|
||||
json_t *jelm = json_path_get((const json_t *)root, path);
|
||||
if (!jelm || !json_is_string(jelm))
|
||||
return 2;
|
||||
|
||||
const char * strval = json_string_value(jelm);
|
||||
if (!strval)
|
||||
return 1;
|
||||
const char * strval = json_string_value(jelm);
|
||||
if (!strval)
|
||||
return 1;
|
||||
|
||||
memcpy(value, strval, strlen(strval));
|
||||
memcpy(value, strval, strlen(strval));
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int JsonLoadBufAsHex(json_t *elm, char *path, uint8_t *data, size_t maxbufferlen, size_t *datalen) {
|
||||
if (datalen)
|
||||
*datalen = 0;
|
||||
if (datalen)
|
||||
*datalen = 0;
|
||||
|
||||
json_t *jelm = json_path_get((const json_t *)elm, path);
|
||||
if (!jelm || !json_is_string(jelm))
|
||||
return 1;
|
||||
json_t *jelm = json_path_get((const json_t *)elm, path);
|
||||
if (!jelm || !json_is_string(jelm))
|
||||
return 1;
|
||||
|
||||
if (!HexToBuffer("ERROR load", json_string_value(jelm), data, maxbufferlen, datalen))
|
||||
return 2;
|
||||
if (!HexToBuffer("ERROR load", json_string_value(jelm), data, maxbufferlen, datalen))
|
||||
return 2;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
};
|
||||
|
||||
bool ParamLoadFromJson(struct tlvdb *tlv) {
|
||||
json_t *root;
|
||||
json_error_t error;
|
||||
json_t *root;
|
||||
json_error_t error;
|
||||
|
||||
if (!tlv) {
|
||||
PrintAndLog("ERROR load params: tlv tree is NULL.");
|
||||
return false;
|
||||
}
|
||||
if (!tlv) {
|
||||
PrintAndLog("ERROR load params: tlv tree is NULL.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// current path + file name
|
||||
const char *relfname = "emv/defparams.json";
|
||||
char fname[strlen(get_my_executable_directory()) + strlen(relfname) + 1];
|
||||
strcpy(fname, get_my_executable_directory());
|
||||
strcat(fname, relfname);
|
||||
// current path + file name
|
||||
const char *relfname = "emv/defparams.json";
|
||||
char fname[strlen(get_my_executable_directory()) + strlen(relfname) + 1];
|
||||
strcpy(fname, get_my_executable_directory());
|
||||
strcat(fname, relfname);
|
||||
|
||||
root = json_load_file(fname, 0, &error);
|
||||
if (!root) {
|
||||
PrintAndLog("Load params: json error on line %d: %s", error.line, error.text);
|
||||
return false;
|
||||
}
|
||||
root = json_load_file(fname, 0, &error);
|
||||
if (!root) {
|
||||
PrintAndLog("Load params: json error on line %d: %s", error.line, error.text);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!json_is_array(root)) {
|
||||
PrintAndLog("Load params: Invalid json format. root must be array.");
|
||||
return false;
|
||||
}
|
||||
if (!json_is_array(root)) {
|
||||
PrintAndLog("Load params: Invalid json format. root must be array.");
|
||||
return false;
|
||||
}
|
||||
|
||||
PrintAndLog("Load params: json(%d) OK", json_array_size(root));
|
||||
PrintAndLog("Load params: json(%d) OK", json_array_size(root));
|
||||
|
||||
for(int i = 0; i < json_array_size(root); i++) {
|
||||
json_t *data, *jtag, *jlength, *jvalue;
|
||||
for(int i = 0; i < json_array_size(root); i++) {
|
||||
json_t *data, *jtag, *jlength, *jvalue;
|
||||
|
||||
data = json_array_get(root, i);
|
||||
if(!json_is_object(data))
|
||||
{
|
||||
PrintAndLog("Load params: data [%d] is not an object", i + 1);
|
||||
json_decref(root);
|
||||
return false;
|
||||
}
|
||||
data = json_array_get(root, i);
|
||||
if(!json_is_object(data))
|
||||
{
|
||||
PrintAndLog("Load params: data [%d] is not an object", i + 1);
|
||||
json_decref(root);
|
||||
return false;
|
||||
}
|
||||
|
||||
jtag = json_object_get(data, "tag");
|
||||
if(!json_is_string(jtag))
|
||||
{
|
||||
PrintAndLog("Load params: data [%d] tag is not a string", i + 1);
|
||||
json_decref(root);
|
||||
return false;
|
||||
}
|
||||
const char *tlvTag = json_string_value(jtag);
|
||||
jtag = json_object_get(data, "tag");
|
||||
if(!json_is_string(jtag))
|
||||
{
|
||||
PrintAndLog("Load params: data [%d] tag is not a string", i + 1);
|
||||
json_decref(root);
|
||||
return false;
|
||||
}
|
||||
const char *tlvTag = json_string_value(jtag);
|
||||
|
||||
jvalue = json_object_get(data, "value");
|
||||
if(!json_is_string(jvalue))
|
||||
{
|
||||
PrintAndLog("Load params: data [%d] value is not a string", i + 1);
|
||||
json_decref(root);
|
||||
return false;
|
||||
}
|
||||
const char *tlvValue = json_string_value(jvalue);
|
||||
jvalue = json_object_get(data, "value");
|
||||
if(!json_is_string(jvalue))
|
||||
{
|
||||
PrintAndLog("Load params: data [%d] value is not a string", i + 1);
|
||||
json_decref(root);
|
||||
return false;
|
||||
}
|
||||
const char *tlvValue = json_string_value(jvalue);
|
||||
|
||||
jlength = json_object_get(data, "length");
|
||||
if(!json_is_number(jlength))
|
||||
{
|
||||
PrintAndLog("Load params: data [%d] length is not a number", i + 1);
|
||||
json_decref(root);
|
||||
return false;
|
||||
}
|
||||
jlength = json_object_get(data, "length");
|
||||
if(!json_is_number(jlength))
|
||||
{
|
||||
PrintAndLog("Load params: data [%d] length is not a number", i + 1);
|
||||
json_decref(root);
|
||||
return false;
|
||||
}
|
||||
|
||||
int tlvLength = json_integer_value(jlength);
|
||||
if (tlvLength > 250) {
|
||||
PrintAndLog("Load params: data [%d] length more than 250", i + 1);
|
||||
json_decref(root);
|
||||
return false;
|
||||
}
|
||||
int tlvLength = json_integer_value(jlength);
|
||||
if (tlvLength > 250) {
|
||||
PrintAndLog("Load params: data [%d] length more than 250", i + 1);
|
||||
json_decref(root);
|
||||
return false;
|
||||
}
|
||||
|
||||
PrintAndLog("TLV param: %s[%d]=%s", tlvTag, tlvLength, tlvValue);
|
||||
uint8_t buf[251] = {0};
|
||||
size_t buflen = 0;
|
||||
PrintAndLog("TLV param: %s[%d]=%s", tlvTag, tlvLength, tlvValue);
|
||||
uint8_t buf[251] = {0};
|
||||
size_t buflen = 0;
|
||||
|
||||
if (!HexToBuffer("TLV Error type:", tlvTag, buf, 4, &buflen)) {
|
||||
json_decref(root);
|
||||
return false;
|
||||
}
|
||||
tlv_tag_t tag = 0;
|
||||
for (int i = 0; i < buflen; i++) {
|
||||
tag = (tag << 8) | buf[i];
|
||||
}
|
||||
if (!HexToBuffer("TLV Error type:", tlvTag, buf, 4, &buflen)) {
|
||||
json_decref(root);
|
||||
return false;
|
||||
}
|
||||
tlv_tag_t tag = 0;
|
||||
for (int i = 0; i < buflen; i++) {
|
||||
tag = (tag << 8) | buf[i];
|
||||
}
|
||||
|
||||
if (!HexToBuffer("TLV Error value:", tlvValue, buf, sizeof(buf) - 1, &buflen)) {
|
||||
json_decref(root);
|
||||
return false;
|
||||
}
|
||||
if (!HexToBuffer("TLV Error value:", tlvValue, buf, sizeof(buf) - 1, &buflen)) {
|
||||
json_decref(root);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (buflen != tlvLength) {
|
||||
PrintAndLog("Load params: data [%d] length of HEX must(%d) be identical to length in TLV param(%d)", i + 1, buflen, tlvLength);
|
||||
json_decref(root);
|
||||
return false;
|
||||
}
|
||||
if (buflen != tlvLength) {
|
||||
PrintAndLog("Load params: data [%d] length of HEX must(%d) be identical to length in TLV param(%d)", i + 1, buflen, tlvLength);
|
||||
json_decref(root);
|
||||
return false;
|
||||
}
|
||||
|
||||
tlvdb_change_or_add_node(tlv, tag, tlvLength, (const unsigned char *)buf);
|
||||
}
|
||||
tlvdb_change_or_add_node(tlv, tag, tlvLength, (const unsigned char *)buf);
|
||||
}
|
||||
|
||||
json_decref(root);
|
||||
json_decref(root);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
#include "tlv.h"
|
||||
|
||||
typedef struct {
|
||||
tlv_tag_t Tag;
|
||||
char *Name;
|
||||
tlv_tag_t Tag;
|
||||
char *Name;
|
||||
} ApplicationDataElm;
|
||||
|
||||
extern char* GetApplicationDataName(tlv_tag_t tag);
|
||||
|
|
|
@ -28,415 +28,415 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
struct emv_pk c_mchip_05 = {
|
||||
.rid = { 0xa0, 0x00, 0x00, 0x00, 0x04, },
|
||||
.index = 5,
|
||||
.hash_algo = HASH_SHA_1,
|
||||
.pk_algo = PK_RSA,
|
||||
.hash = {
|
||||
0xeb, 0xfa, 0x0d, 0x5d,
|
||||
0x06, 0xd8, 0xce, 0x70,
|
||||
0x2d, 0xa3, 0xea, 0xe8,
|
||||
0x90, 0x70, 0x1d, 0x45,
|
||||
0xe2, 0x74, 0xc8, 0x45, },
|
||||
.exp = { 0x03, },
|
||||
.elen = 1,
|
||||
.mlen = 1408 / 8,
|
||||
.modulus = (unsigned char[]){
|
||||
0xb8, 0x04, 0x8a, 0xbc, 0x30, 0xc9, 0x0d, 0x97, 0x63, 0x36, 0x54, 0x3e, 0x3f, 0xd7, 0x09, 0x1c,
|
||||
0x8f, 0xe4, 0x80, 0x0d, 0xf8, 0x20, 0xed, 0x55, 0xe7, 0xe9, 0x48, 0x13, 0xed, 0x00, 0x55, 0x5b,
|
||||
0x57, 0x3f, 0xec, 0xa3, 0xd8, 0x4a, 0xf6, 0x13, 0x1a, 0x65, 0x1d, 0x66, 0xcf, 0xf4, 0x28, 0x4f,
|
||||
0xb1, 0x3b, 0x63, 0x5e, 0xdd, 0x0e, 0xe4, 0x01, 0x76, 0xd8, 0xbf, 0x04, 0xb7, 0xfd, 0x1c, 0x7b,
|
||||
0xac, 0xf9, 0xac, 0x73, 0x27, 0xdf, 0xaa, 0x8a, 0xa7, 0x2d, 0x10, 0xdb, 0x3b, 0x8e, 0x70, 0xb2,
|
||||
0xdd, 0xd8, 0x11, 0xcb, 0x41, 0x96, 0x52, 0x5e, 0xa3, 0x86, 0xac, 0xc3, 0x3c, 0x0d, 0x9d, 0x45,
|
||||
0x75, 0x91, 0x64, 0x69, 0xc4, 0xe4, 0xf5, 0x3e, 0x8e, 0x1c, 0x91, 0x2c, 0xc6, 0x18, 0xcb, 0x22,
|
||||
0xdd, 0xe7, 0xc3, 0x56, 0x8e, 0x90, 0x02, 0x2e, 0x6b, 0xba, 0x77, 0x02, 0x02, 0xe4, 0x52, 0x2a,
|
||||
0x2d, 0xd6, 0x23, 0xd1, 0x80, 0xe2, 0x15, 0xbd, 0x1d, 0x15, 0x07, 0xfe, 0x3d, 0xc9, 0x0c, 0xa3,
|
||||
0x10, 0xd2, 0x7b, 0x3e, 0xfc, 0xcd, 0x8f, 0x83, 0xde, 0x30, 0x52, 0xca, 0xd1, 0xe4, 0x89, 0x38,
|
||||
0xc6, 0x8d, 0x09, 0x5a, 0xac, 0x91, 0xb5, 0xf3, 0x7e, 0x28, 0xbb, 0x49, 0xec, 0x7e, 0xd5, 0x97,
|
||||
},
|
||||
.rid = { 0xa0, 0x00, 0x00, 0x00, 0x04, },
|
||||
.index = 5,
|
||||
.hash_algo = HASH_SHA_1,
|
||||
.pk_algo = PK_RSA,
|
||||
.hash = {
|
||||
0xeb, 0xfa, 0x0d, 0x5d,
|
||||
0x06, 0xd8, 0xce, 0x70,
|
||||
0x2d, 0xa3, 0xea, 0xe8,
|
||||
0x90, 0x70, 0x1d, 0x45,
|
||||
0xe2, 0x74, 0xc8, 0x45, },
|
||||
.exp = { 0x03, },
|
||||
.elen = 1,
|
||||
.mlen = 1408 / 8,
|
||||
.modulus = (unsigned char[]){
|
||||
0xb8, 0x04, 0x8a, 0xbc, 0x30, 0xc9, 0x0d, 0x97, 0x63, 0x36, 0x54, 0x3e, 0x3f, 0xd7, 0x09, 0x1c,
|
||||
0x8f, 0xe4, 0x80, 0x0d, 0xf8, 0x20, 0xed, 0x55, 0xe7, 0xe9, 0x48, 0x13, 0xed, 0x00, 0x55, 0x5b,
|
||||
0x57, 0x3f, 0xec, 0xa3, 0xd8, 0x4a, 0xf6, 0x13, 0x1a, 0x65, 0x1d, 0x66, 0xcf, 0xf4, 0x28, 0x4f,
|
||||
0xb1, 0x3b, 0x63, 0x5e, 0xdd, 0x0e, 0xe4, 0x01, 0x76, 0xd8, 0xbf, 0x04, 0xb7, 0xfd, 0x1c, 0x7b,
|
||||
0xac, 0xf9, 0xac, 0x73, 0x27, 0xdf, 0xaa, 0x8a, 0xa7, 0x2d, 0x10, 0xdb, 0x3b, 0x8e, 0x70, 0xb2,
|
||||
0xdd, 0xd8, 0x11, 0xcb, 0x41, 0x96, 0x52, 0x5e, 0xa3, 0x86, 0xac, 0xc3, 0x3c, 0x0d, 0x9d, 0x45,
|
||||
0x75, 0x91, 0x64, 0x69, 0xc4, 0xe4, 0xf5, 0x3e, 0x8e, 0x1c, 0x91, 0x2c, 0xc6, 0x18, 0xcb, 0x22,
|
||||
0xdd, 0xe7, 0xc3, 0x56, 0x8e, 0x90, 0x02, 0x2e, 0x6b, 0xba, 0x77, 0x02, 0x02, 0xe4, 0x52, 0x2a,
|
||||
0x2d, 0xd6, 0x23, 0xd1, 0x80, 0xe2, 0x15, 0xbd, 0x1d, 0x15, 0x07, 0xfe, 0x3d, 0xc9, 0x0c, 0xa3,
|
||||
0x10, 0xd2, 0x7b, 0x3e, 0xfc, 0xcd, 0x8f, 0x83, 0xde, 0x30, 0x52, 0xca, 0xd1, 0xe4, 0x89, 0x38,
|
||||
0xc6, 0x8d, 0x09, 0x5a, 0xac, 0x91, 0xb5, 0xf3, 0x7e, 0x28, 0xbb, 0x49, 0xec, 0x7e, 0xd5, 0x97,
|
||||
},
|
||||
};
|
||||
|
||||
const unsigned char c_issuer_cert[] = {
|
||||
0x17, 0x14, 0x28, 0x4f, 0x76, 0x3b, 0x85, 0x86, 0xee, 0x6d, 0x31, 0x99, 0x51, 0xf7, 0xe6, 0x3f,
|
||||
0xa2, 0x50, 0x76, 0xe5, 0x0d, 0xc9, 0xd3, 0x20, 0x0b, 0xa9, 0x98, 0xd3, 0xa0, 0x52, 0xad, 0xba,
|
||||
0x9a, 0xb6, 0x9a, 0xc6, 0xad, 0x6a, 0xdd, 0x3c, 0xe0, 0x9f, 0x02, 0x78, 0xf4, 0x07, 0x4e, 0xc4,
|
||||
0xee, 0x9b, 0x1d, 0x22, 0x68, 0xa3, 0xe9, 0x53, 0x57, 0x5e, 0x45, 0x4e, 0x50, 0xcd, 0x86, 0x0b,
|
||||
0xf4, 0x24, 0xc5, 0x1c, 0x59, 0x77, 0x12, 0xd2, 0xaa, 0x05, 0x70, 0x89, 0xdd, 0x86, 0x73, 0xe5,
|
||||
0x1b, 0x1e, 0x1d, 0x71, 0x88, 0x03, 0x48, 0x92, 0x07, 0x7a, 0xc1, 0x8a, 0x6a, 0xe2, 0x34, 0x88,
|
||||
0xbe, 0xa9, 0xdf, 0x3b, 0x1a, 0x83, 0xf2, 0xc0, 0x80, 0x0c, 0xd7, 0xc5, 0xcd, 0xf2, 0xfd, 0xe0,
|
||||
0x49, 0x6f, 0x7b, 0xc3, 0x9f, 0xb4, 0xbf, 0x36, 0x32, 0x99, 0xbf, 0xa6, 0x37, 0xb2, 0xec, 0x33,
|
||||
0xc5, 0x07, 0xe3, 0x68, 0x21, 0xee, 0xc2, 0x07, 0x5f, 0x0e, 0x42, 0x0d, 0x38, 0xa1, 0xc9, 0xf3,
|
||||
0x12, 0x72, 0x61, 0xba, 0x31, 0x6c, 0x98, 0x76, 0x74, 0xfa, 0xdb, 0x20, 0xea, 0x7f, 0xeb, 0x75,
|
||||
0xee, 0x45, 0x5d, 0x12, 0x14, 0x6e, 0xa6, 0xf0, 0x2e, 0x8b, 0x01, 0xec, 0x2f, 0xa7, 0xa1, 0x15,
|
||||
0x17, 0x14, 0x28, 0x4f, 0x76, 0x3b, 0x85, 0x86, 0xee, 0x6d, 0x31, 0x99, 0x51, 0xf7, 0xe6, 0x3f,
|
||||
0xa2, 0x50, 0x76, 0xe5, 0x0d, 0xc9, 0xd3, 0x20, 0x0b, 0xa9, 0x98, 0xd3, 0xa0, 0x52, 0xad, 0xba,
|
||||
0x9a, 0xb6, 0x9a, 0xc6, 0xad, 0x6a, 0xdd, 0x3c, 0xe0, 0x9f, 0x02, 0x78, 0xf4, 0x07, 0x4e, 0xc4,
|
||||
0xee, 0x9b, 0x1d, 0x22, 0x68, 0xa3, 0xe9, 0x53, 0x57, 0x5e, 0x45, 0x4e, 0x50, 0xcd, 0x86, 0x0b,
|
||||
0xf4, 0x24, 0xc5, 0x1c, 0x59, 0x77, 0x12, 0xd2, 0xaa, 0x05, 0x70, 0x89, 0xdd, 0x86, 0x73, 0xe5,
|
||||
0x1b, 0x1e, 0x1d, 0x71, 0x88, 0x03, 0x48, 0x92, 0x07, 0x7a, 0xc1, 0x8a, 0x6a, 0xe2, 0x34, 0x88,
|
||||
0xbe, 0xa9, 0xdf, 0x3b, 0x1a, 0x83, 0xf2, 0xc0, 0x80, 0x0c, 0xd7, 0xc5, 0xcd, 0xf2, 0xfd, 0xe0,
|
||||
0x49, 0x6f, 0x7b, 0xc3, 0x9f, 0xb4, 0xbf, 0x36, 0x32, 0x99, 0xbf, 0xa6, 0x37, 0xb2, 0xec, 0x33,
|
||||
0xc5, 0x07, 0xe3, 0x68, 0x21, 0xee, 0xc2, 0x07, 0x5f, 0x0e, 0x42, 0x0d, 0x38, 0xa1, 0xc9, 0xf3,
|
||||
0x12, 0x72, 0x61, 0xba, 0x31, 0x6c, 0x98, 0x76, 0x74, 0xfa, 0xdb, 0x20, 0xea, 0x7f, 0xeb, 0x75,
|
||||
0xee, 0x45, 0x5d, 0x12, 0x14, 0x6e, 0xa6, 0xf0, 0x2e, 0x8b, 0x01, 0xec, 0x2f, 0xa7, 0xa1, 0x15,
|
||||
};
|
||||
|
||||
const unsigned char c_issuer_rem[] = {
|
||||
0x6e, 0x63, 0xb7, 0xbc, 0x70, 0xab, 0xdd, 0x09, 0x34, 0x1b, 0x34, 0xc0, 0x32, 0x86, 0xba, 0x9b,
|
||||
0xd8, 0x3b, 0xa7, 0x93, 0x6c, 0x5b, 0x77, 0x98, 0xfb, 0x22, 0xc5, 0xe5, 0x3f, 0xf2, 0x40, 0xa2,
|
||||
0x6d, 0xbd, 0x64, 0x15,
|
||||
0x6e, 0x63, 0xb7, 0xbc, 0x70, 0xab, 0xdd, 0x09, 0x34, 0x1b, 0x34, 0xc0, 0x32, 0x86, 0xba, 0x9b,
|
||||
0xd8, 0x3b, 0xa7, 0x93, 0x6c, 0x5b, 0x77, 0x98, 0xfb, 0x22, 0xc5, 0xe5, 0x3f, 0xf2, 0x40, 0xa2,
|
||||
0x6d, 0xbd, 0x64, 0x15,
|
||||
};
|
||||
|
||||
const unsigned char c_issuer_exp[] = {
|
||||
0x03,
|
||||
0x03,
|
||||
};
|
||||
|
||||
const unsigned char c_icc_cert[] = {
|
||||
0xa4, 0x2f, 0xbe, 0xb1, 0x56, 0xb9, 0x8d, 0xcb, 0x05, 0x54, 0xda, 0x06, 0x2a, 0xdc, 0xa5, 0x30,
|
||||
0x9a, 0x91, 0xf0, 0x4f, 0xa2, 0xc7, 0xbd, 0x71, 0x02, 0xa8, 0xd7, 0x3f, 0x16, 0xa3, 0xcf, 0xad,
|
||||
0xe8, 0xaa, 0xdf, 0x4f, 0x3f, 0xe2, 0xa2, 0x12, 0x5c, 0xcd, 0xd7, 0x7c, 0x6b, 0x9f, 0x78, 0xb5,
|
||||
0xb4, 0x37, 0x1c, 0xe0, 0x80, 0x57, 0x25, 0xb0, 0xf9, 0xc0, 0x27, 0xaf, 0x14, 0x7d, 0x91, 0xe1,
|
||||
0xff, 0xdb, 0x20, 0x1e, 0x9c, 0x17, 0x0c, 0xe7, 0x77, 0x05, 0x3a, 0x17, 0x2a, 0xd5, 0x26, 0xdc,
|
||||
0xaf, 0xd3, 0x38, 0x95, 0xe1, 0xa9, 0x47, 0x30, 0x5c, 0x5b, 0x16, 0x7f, 0x2e, 0x7c, 0x6f, 0x99,
|
||||
0x15, 0x81, 0xa6, 0x52, 0xee, 0x47, 0x31, 0x54, 0x76, 0x0c, 0x2e, 0xd7, 0x74, 0x21, 0x4e, 0x50,
|
||||
0xdf, 0xec, 0xdd, 0x4c, 0xf2, 0x94, 0xc9, 0x74, 0xb8, 0x9e, 0xbc, 0xa2, 0x5b, 0x5a, 0xb3, 0xc0,
|
||||
0xbe, 0xb5, 0x0d, 0xfa, 0xf7, 0x82, 0xaf, 0xde, 0x14, 0x33, 0xd9, 0x0c, 0xa2, 0xa8, 0x9d, 0x65,
|
||||
0x1e, 0x75, 0xd6, 0x7e, 0xbc, 0x7c, 0x3e, 0x36, 0xf5, 0xa1, 0x65, 0xee, 0x61, 0x32, 0x61, 0x29,
|
||||
0x39, 0xc1, 0xec, 0xd3, 0x99, 0xe4, 0x60, 0x74, 0xb9, 0x96, 0xd9, 0x3a, 0x88, 0xe0, 0x1e, 0x0a,
|
||||
0xa4, 0x2f, 0xbe, 0xb1, 0x56, 0xb9, 0x8d, 0xcb, 0x05, 0x54, 0xda, 0x06, 0x2a, 0xdc, 0xa5, 0x30,
|
||||
0x9a, 0x91, 0xf0, 0x4f, 0xa2, 0xc7, 0xbd, 0x71, 0x02, 0xa8, 0xd7, 0x3f, 0x16, 0xa3, 0xcf, 0xad,
|
||||
0xe8, 0xaa, 0xdf, 0x4f, 0x3f, 0xe2, 0xa2, 0x12, 0x5c, 0xcd, 0xd7, 0x7c, 0x6b, 0x9f, 0x78, 0xb5,
|
||||
0xb4, 0x37, 0x1c, 0xe0, 0x80, 0x57, 0x25, 0xb0, 0xf9, 0xc0, 0x27, 0xaf, 0x14, 0x7d, 0x91, 0xe1,
|
||||
0xff, 0xdb, 0x20, 0x1e, 0x9c, 0x17, 0x0c, 0xe7, 0x77, 0x05, 0x3a, 0x17, 0x2a, 0xd5, 0x26, 0xdc,
|
||||
0xaf, 0xd3, 0x38, 0x95, 0xe1, 0xa9, 0x47, 0x30, 0x5c, 0x5b, 0x16, 0x7f, 0x2e, 0x7c, 0x6f, 0x99,
|
||||
0x15, 0x81, 0xa6, 0x52, 0xee, 0x47, 0x31, 0x54, 0x76, 0x0c, 0x2e, 0xd7, 0x74, 0x21, 0x4e, 0x50,
|
||||
0xdf, 0xec, 0xdd, 0x4c, 0xf2, 0x94, 0xc9, 0x74, 0xb8, 0x9e, 0xbc, 0xa2, 0x5b, 0x5a, 0xb3, 0xc0,
|
||||
0xbe, 0xb5, 0x0d, 0xfa, 0xf7, 0x82, 0xaf, 0xde, 0x14, 0x33, 0xd9, 0x0c, 0xa2, 0xa8, 0x9d, 0x65,
|
||||
0x1e, 0x75, 0xd6, 0x7e, 0xbc, 0x7c, 0x3e, 0x36, 0xf5, 0xa1, 0x65, 0xee, 0x61, 0x32, 0x61, 0x29,
|
||||
0x39, 0xc1, 0xec, 0xd3, 0x99, 0xe4, 0x60, 0x74, 0xb9, 0x96, 0xd9, 0x3a, 0x88, 0xe0, 0x1e, 0x0a,
|
||||
};
|
||||
|
||||
const unsigned char c_icc_exp[] = {
|
||||
0x03,
|
||||
0x03,
|
||||
};
|
||||
|
||||
const unsigned char c_sdad_cr[] = {
|
||||
0x1c, 0x00, 0x9f, 0xc4, 0x86, 0x79, 0x15, 0x7d, 0xbf, 0xf4, 0x5f, 0x65, 0xd3, 0x3f, 0xf7, 0x8d,
|
||||
0x4f, 0xcb, 0xf0, 0xcf, 0x5e, 0xa4, 0x20, 0x8d, 0x10, 0x7a, 0xe9, 0x5a, 0xa3, 0x8c, 0x54, 0x6d,
|
||||
0x0e, 0x5a, 0x18, 0xb8, 0x74, 0x03, 0xa1, 0x2b, 0xd4, 0x47, 0xa8, 0xbb, 0xfc, 0x1e, 0x49, 0xce,
|
||||
0x0b, 0x2e, 0x25, 0x13, 0x89, 0x20, 0x57, 0x03, 0xc9, 0xbb, 0x1a, 0x88, 0xcc, 0x79, 0xf1, 0xdd,
|
||||
0xc2, 0xf9, 0x84, 0x1e, 0xad, 0xf0, 0x7c, 0xe0, 0x7b, 0x62, 0x51, 0x1d, 0xdc, 0x93, 0xdf, 0x59,
|
||||
0xf2, 0x8f, 0x0e, 0x91, 0xf9, 0x23, 0x32, 0xd2, 0x9c, 0xde, 0xf2, 0xbc, 0xcb, 0x10, 0x08, 0x85,
|
||||
0x05, 0x00, 0xef, 0x3e, 0x47, 0x0a, 0x4c, 0xb1, 0x8c, 0xd9, 0x1a, 0xa5, 0xc1, 0xa1, 0x08, 0xf3,
|
||||
0x1c, 0x00, 0x9f, 0xc4, 0x86, 0x79, 0x15, 0x7d, 0xbf, 0xf4, 0x5f, 0x65, 0xd3, 0x3f, 0xf7, 0x8d,
|
||||
0x4f, 0xcb, 0xf0, 0xcf, 0x5e, 0xa4, 0x20, 0x8d, 0x10, 0x7a, 0xe9, 0x5a, 0xa3, 0x8c, 0x54, 0x6d,
|
||||
0x0e, 0x5a, 0x18, 0xb8, 0x74, 0x03, 0xa1, 0x2b, 0xd4, 0x47, 0xa8, 0xbb, 0xfc, 0x1e, 0x49, 0xce,
|
||||
0x0b, 0x2e, 0x25, 0x13, 0x89, 0x20, 0x57, 0x03, 0xc9, 0xbb, 0x1a, 0x88, 0xcc, 0x79, 0xf1, 0xdd,
|
||||
0xc2, 0xf9, 0x84, 0x1e, 0xad, 0xf0, 0x7c, 0xe0, 0x7b, 0x62, 0x51, 0x1d, 0xdc, 0x93, 0xdf, 0x59,
|
||||
0xf2, 0x8f, 0x0e, 0x91, 0xf9, 0x23, 0x32, 0xd2, 0x9c, 0xde, 0xf2, 0xbc, 0xcb, 0x10, 0x08, 0x85,
|
||||
0x05, 0x00, 0xef, 0x3e, 0x47, 0x0a, 0x4c, 0xb1, 0x8c, 0xd9, 0x1a, 0xa5, 0xc1, 0xa1, 0x08, 0xf3,
|
||||
|
||||
};
|
||||
|
||||
const unsigned char c_ssd1[] = {
|
||||
0x5f, 0x25, 0x03, 0x14, 0x05, 0x01, 0x5f, 0x24, 0x03, 0x15, 0x06, 0x30, 0x5a, 0x08, 0x52, 0x85,
|
||||
0x88, 0x12, 0x54, 0x34, 0x56, 0x53, 0x5f, 0x34, 0x01, 0x01, 0x8e, 0x0c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x1e, 0x03, 0x1f, 0x03, 0x9f, 0x07, 0x02, 0xff, 0x00, 0x9f, 0x0d, 0x05,
|
||||
0xbc, 0x50, 0xbc, 0x00, 0x00, 0x9f, 0x0e, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x0f, 0x05,
|
||||
0xbc, 0x70, 0xbc, 0x98, 0x00, 0x9f, 0x4a, 0x01, 0x82, 0x5f, 0x28, 0x02, 0x06, 0x43, 0x8c, 0x21,
|
||||
0x9f, 0x02, 0x06, 0x9f, 0x03, 0x06, 0x9f, 0x1a, 0x02, 0x95, 0x05, 0x5f, 0x2a, 0x02, 0x9a, 0x03,
|
||||
0x9c, 0x01, 0x9f, 0x37, 0x04, 0x9f, 0x35, 0x01, 0x9f, 0x45, 0x02, 0x9f, 0x4c, 0x08, 0x9f, 0x34,
|
||||
0x03, 0x8d, 0x0c, 0x91, 0x0a, 0x8a, 0x02, 0x95, 0x05, 0x9f, 0x37, 0x04, 0x9f, 0x4c, 0x08,
|
||||
0x39, 0x00,
|
||||
0x5f, 0x25, 0x03, 0x14, 0x05, 0x01, 0x5f, 0x24, 0x03, 0x15, 0x06, 0x30, 0x5a, 0x08, 0x52, 0x85,
|
||||
0x88, 0x12, 0x54, 0x34, 0x56, 0x53, 0x5f, 0x34, 0x01, 0x01, 0x8e, 0x0c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x1e, 0x03, 0x1f, 0x03, 0x9f, 0x07, 0x02, 0xff, 0x00, 0x9f, 0x0d, 0x05,
|
||||
0xbc, 0x50, 0xbc, 0x00, 0x00, 0x9f, 0x0e, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x0f, 0x05,
|
||||
0xbc, 0x70, 0xbc, 0x98, 0x00, 0x9f, 0x4a, 0x01, 0x82, 0x5f, 0x28, 0x02, 0x06, 0x43, 0x8c, 0x21,
|
||||
0x9f, 0x02, 0x06, 0x9f, 0x03, 0x06, 0x9f, 0x1a, 0x02, 0x95, 0x05, 0x5f, 0x2a, 0x02, 0x9a, 0x03,
|
||||
0x9c, 0x01, 0x9f, 0x37, 0x04, 0x9f, 0x35, 0x01, 0x9f, 0x45, 0x02, 0x9f, 0x4c, 0x08, 0x9f, 0x34,
|
||||
0x03, 0x8d, 0x0c, 0x91, 0x0a, 0x8a, 0x02, 0x95, 0x05, 0x9f, 0x37, 0x04, 0x9f, 0x4c, 0x08,
|
||||
0x39, 0x00,
|
||||
};
|
||||
static const struct tlv ssd1_tlv = {
|
||||
.len = sizeof(c_ssd1),
|
||||
.value = c_ssd1,
|
||||
.len = sizeof(c_ssd1),
|
||||
.value = c_ssd1,
|
||||
};
|
||||
|
||||
const unsigned char c_pan[] = {
|
||||
0x52, 0x85, 0x88, 0x12, 0x54, 0x34, 0x56, 0x53,
|
||||
0x52, 0x85, 0x88, 0x12, 0x54, 0x34, 0x56, 0x53,
|
||||
};
|
||||
|
||||
const unsigned char c_dd1[] = {
|
||||
0x12, 0x34, 0x57, 0x79,
|
||||
0x12, 0x34, 0x57, 0x79,
|
||||
};
|
||||
|
||||
const unsigned char c_dd2[] = {
|
||||
0x9f, 0x27, 0x01, 0x40, 0x9f, 0x36, 0x02, 0x00, 0x10, 0x9f, 0x10, 0x12, 0x00, 0x10, 0x90, 0x40,
|
||||
0x01, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
0x9f, 0x27, 0x01, 0x40, 0x9f, 0x36, 0x02, 0x00, 0x10, 0x9f, 0x10, 0x12, 0x00, 0x10, 0x90, 0x40,
|
||||
0x01, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
};
|
||||
|
||||
const unsigned char c_crm1[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x43, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x06, 0x43, 0x14, 0x09, 0x25, 0x50, 0x12, 0x34, 0x57, 0x79, 0x23, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x03, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x43, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x06, 0x43, 0x14, 0x09, 0x25, 0x50, 0x12, 0x34, 0x57, 0x79, 0x23, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x03, 0x00,
|
||||
};
|
||||
static const struct tlv crm1_tlv = {
|
||||
.len = sizeof(c_crm1),
|
||||
.value = c_crm1,
|
||||
.len = sizeof(c_crm1),
|
||||
.value = c_crm1,
|
||||
};
|
||||
|
||||
static int cda_test_raw(bool verbose)
|
||||
{
|
||||
const struct emv_pk *pk = &c_mchip_05;
|
||||
const struct emv_pk *pk = &c_mchip_05;
|
||||
|
||||
struct crypto_pk *kcp = crypto_pk_open(PK_RSA,
|
||||
pk->modulus, pk->mlen,
|
||||
pk->exp, pk->elen);
|
||||
if (!kcp)
|
||||
return 1;
|
||||
struct crypto_pk *kcp = crypto_pk_open(PK_RSA,
|
||||
pk->modulus, pk->mlen,
|
||||
pk->exp, pk->elen);
|
||||
if (!kcp)
|
||||
return 1;
|
||||
|
||||
unsigned char *ipk_data;
|
||||
size_t ipk_data_len;
|
||||
ipk_data = crypto_pk_encrypt(kcp, c_issuer_cert, sizeof(c_issuer_cert), &ipk_data_len);
|
||||
crypto_pk_close(kcp);
|
||||
unsigned char *ipk_data;
|
||||
size_t ipk_data_len;
|
||||
ipk_data = crypto_pk_encrypt(kcp, c_issuer_cert, sizeof(c_issuer_cert), &ipk_data_len);
|
||||
crypto_pk_close(kcp);
|
||||
|
||||
if (!ipk_data)
|
||||
return 1;
|
||||
if (!ipk_data)
|
||||
return 1;
|
||||
|
||||
if (verbose) {
|
||||
printf("issuer cert:\n");
|
||||
dump_buffer(ipk_data, ipk_data_len, stdout, 0);
|
||||
}
|
||||
if (verbose) {
|
||||
printf("issuer cert:\n");
|
||||
dump_buffer(ipk_data, ipk_data_len, stdout, 0);
|
||||
}
|
||||
|
||||
size_t ipk_pk_len = ipk_data[13];
|
||||
unsigned char *ipk_pk = malloc(ipk_pk_len);
|
||||
memcpy(ipk_pk, ipk_data + 15, ipk_data_len - 36);
|
||||
memcpy(ipk_pk + ipk_data_len - 36, c_issuer_rem, sizeof(c_issuer_rem));
|
||||
size_t ipk_pk_len = ipk_data[13];
|
||||
unsigned char *ipk_pk = malloc(ipk_pk_len);
|
||||
memcpy(ipk_pk, ipk_data + 15, ipk_data_len - 36);
|
||||
memcpy(ipk_pk + ipk_data_len - 36, c_issuer_rem, sizeof(c_issuer_rem));
|
||||
|
||||
struct crypto_hash *ch;
|
||||
ch = crypto_hash_open(HASH_SHA_1);
|
||||
if (!ch) {
|
||||
free(ipk_pk);
|
||||
free(ipk_data);
|
||||
return 1;
|
||||
}
|
||||
struct crypto_hash *ch;
|
||||
ch = crypto_hash_open(HASH_SHA_1);
|
||||
if (!ch) {
|
||||
free(ipk_pk);
|
||||
free(ipk_data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
crypto_hash_write(ch, ipk_data + 1, 14);
|
||||
crypto_hash_write(ch, ipk_pk, ipk_pk_len);
|
||||
crypto_hash_write(ch, c_issuer_exp, sizeof(c_issuer_exp));
|
||||
crypto_hash_write(ch, ipk_data + 1, 14);
|
||||
crypto_hash_write(ch, ipk_pk, ipk_pk_len);
|
||||
crypto_hash_write(ch, c_issuer_exp, sizeof(c_issuer_exp));
|
||||
|
||||
unsigned char *h = crypto_hash_read(ch);
|
||||
if (!h) {
|
||||
crypto_hash_close(ch);
|
||||
free(ipk_pk);
|
||||
free(ipk_data);
|
||||
return 1;
|
||||
}
|
||||
unsigned char *h = crypto_hash_read(ch);
|
||||
if (!h) {
|
||||
crypto_hash_close(ch);
|
||||
free(ipk_pk);
|
||||
free(ipk_data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
printf("crypto hash:\n");
|
||||
dump_buffer(h, 20, stdout, 0);
|
||||
}
|
||||
if (verbose) {
|
||||
printf("crypto hash:\n");
|
||||
dump_buffer(h, 20, stdout, 0);
|
||||
}
|
||||
|
||||
if (memcmp(ipk_data + ipk_data_len - 21, h, 20)) {
|
||||
crypto_hash_close(ch);
|
||||
free(ipk_pk);
|
||||
free(ipk_data);
|
||||
return 1;
|
||||
}
|
||||
if (memcmp(ipk_data + ipk_data_len - 21, h, 20)) {
|
||||
crypto_hash_close(ch);
|
||||
free(ipk_pk);
|
||||
free(ipk_data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
crypto_hash_close(ch);
|
||||
free(ipk_data);
|
||||
crypto_hash_close(ch);
|
||||
free(ipk_data);
|
||||
|
||||
struct crypto_pk *ikcp = crypto_pk_open(PK_RSA, ipk_pk, (int) ipk_pk_len,
|
||||
c_issuer_exp, (int) sizeof(c_issuer_exp));
|
||||
free(ipk_pk);
|
||||
if (!ikcp)
|
||||
return 1;
|
||||
struct crypto_pk *ikcp = crypto_pk_open(PK_RSA, ipk_pk, (int) ipk_pk_len,
|
||||
c_issuer_exp, (int) sizeof(c_issuer_exp));
|
||||
free(ipk_pk);
|
||||
if (!ikcp)
|
||||
return 1;
|
||||
|
||||
unsigned char *iccpk_data;
|
||||
size_t iccpk_data_len;
|
||||
iccpk_data = crypto_pk_encrypt(ikcp, c_icc_cert, sizeof(c_icc_cert), &iccpk_data_len);
|
||||
crypto_pk_close(ikcp);
|
||||
unsigned char *iccpk_data;
|
||||
size_t iccpk_data_len;
|
||||
iccpk_data = crypto_pk_encrypt(ikcp, c_icc_cert, sizeof(c_icc_cert), &iccpk_data_len);
|
||||
crypto_pk_close(ikcp);
|
||||
|
||||
if (!iccpk_data)
|
||||
return 1;
|
||||
if (!iccpk_data)
|
||||
return 1;
|
||||
|
||||
if (verbose) {
|
||||
printf("icc cert:\n");
|
||||
dump_buffer(iccpk_data, iccpk_data_len, stdout, 0);
|
||||
}
|
||||
if (verbose) {
|
||||
printf("icc cert:\n");
|
||||
dump_buffer(iccpk_data, iccpk_data_len, stdout, 0);
|
||||
}
|
||||
|
||||
size_t iccpk_pk_len = iccpk_data[19];
|
||||
unsigned char *iccpk_pk = malloc(iccpk_pk_len);
|
||||
memcpy(iccpk_pk, iccpk_data + 21, /*iccpk_data_len - 36*/iccpk_pk_len);
|
||||
/*memcpy(iccpk_pk + iccpk_data_len - 36, icc_rem, sizeof(icc_rem));*/
|
||||
size_t iccpk_pk_len = iccpk_data[19];
|
||||
unsigned char *iccpk_pk = malloc(iccpk_pk_len);
|
||||
memcpy(iccpk_pk, iccpk_data + 21, /*iccpk_data_len - 36*/iccpk_pk_len);
|
||||
/*memcpy(iccpk_pk + iccpk_data_len - 36, icc_rem, sizeof(icc_rem));*/
|
||||
|
||||
ch = crypto_hash_open(HASH_SHA_1);
|
||||
if (!ch) {
|
||||
free(iccpk_pk);
|
||||
free(iccpk_data);
|
||||
return 1;
|
||||
}
|
||||
ch = crypto_hash_open(HASH_SHA_1);
|
||||
if (!ch) {
|
||||
free(iccpk_pk);
|
||||
free(iccpk_data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
crypto_hash_write(ch, iccpk_data + 1, iccpk_data_len - 22);
|
||||
crypto_hash_write(ch, c_icc_exp, sizeof(c_icc_exp));
|
||||
crypto_hash_write(ch, c_ssd1, sizeof(c_ssd1));
|
||||
crypto_hash_write(ch, iccpk_data + 1, iccpk_data_len - 22);
|
||||
crypto_hash_write(ch, c_icc_exp, sizeof(c_icc_exp));
|
||||
crypto_hash_write(ch, c_ssd1, sizeof(c_ssd1));
|
||||
|
||||
h = crypto_hash_read(ch);
|
||||
if (!h) {
|
||||
crypto_hash_close(ch);
|
||||
free(iccpk_pk);
|
||||
free(iccpk_data);
|
||||
return 1;
|
||||
}
|
||||
h = crypto_hash_read(ch);
|
||||
if (!h) {
|
||||
crypto_hash_close(ch);
|
||||
free(iccpk_pk);
|
||||
free(iccpk_data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
printf("crypto hash1.1:\n");
|
||||
dump_buffer(h, 20, stdout, 0);
|
||||
}
|
||||
if (verbose) {
|
||||
printf("crypto hash1.1:\n");
|
||||
dump_buffer(h, 20, stdout, 0);
|
||||
}
|
||||
|
||||
if (memcmp(iccpk_data + iccpk_data_len - 21, h, 20)) {
|
||||
crypto_hash_close(ch);
|
||||
free(iccpk_pk);
|
||||
free(iccpk_data);
|
||||
return 1;
|
||||
}
|
||||
if (memcmp(iccpk_data + iccpk_data_len - 21, h, 20)) {
|
||||
crypto_hash_close(ch);
|
||||
free(iccpk_pk);
|
||||
free(iccpk_data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
crypto_hash_close(ch);
|
||||
free(iccpk_data);
|
||||
crypto_hash_close(ch);
|
||||
free(iccpk_data);
|
||||
|
||||
struct crypto_pk *icckcp = crypto_pk_open(PK_RSA, iccpk_pk, (int) iccpk_pk_len,
|
||||
c_issuer_exp, (int) sizeof(c_issuer_exp));
|
||||
free(iccpk_pk);
|
||||
if (!icckcp)
|
||||
return 1;
|
||||
struct crypto_pk *icckcp = crypto_pk_open(PK_RSA, iccpk_pk, (int) iccpk_pk_len,
|
||||
c_issuer_exp, (int) sizeof(c_issuer_exp));
|
||||
free(iccpk_pk);
|
||||
if (!icckcp)
|
||||
return 1;
|
||||
|
||||
size_t sdad_len;
|
||||
unsigned char *sdad = crypto_pk_encrypt(icckcp, c_sdad_cr, sizeof(c_sdad_cr), &sdad_len);
|
||||
crypto_pk_close(icckcp);
|
||||
if (!sdad)
|
||||
return 1;
|
||||
size_t sdad_len;
|
||||
unsigned char *sdad = crypto_pk_encrypt(icckcp, c_sdad_cr, sizeof(c_sdad_cr), &sdad_len);
|
||||
crypto_pk_close(icckcp);
|
||||
if (!sdad)
|
||||
return 1;
|
||||
|
||||
if (verbose) {
|
||||
printf("SDAD:\n");
|
||||
dump_buffer(sdad, sdad_len, stdout, 0);
|
||||
}
|
||||
if (verbose) {
|
||||
printf("SDAD:\n");
|
||||
dump_buffer(sdad, sdad_len, stdout, 0);
|
||||
}
|
||||
|
||||
ch = crypto_hash_open(HASH_SHA_1);
|
||||
if (!ch) {
|
||||
free(sdad);
|
||||
return 1;
|
||||
}
|
||||
ch = crypto_hash_open(HASH_SHA_1);
|
||||
if (!ch) {
|
||||
free(sdad);
|
||||
return 1;
|
||||
}
|
||||
|
||||
crypto_hash_write(ch, sdad + 1, sdad_len - 22);
|
||||
crypto_hash_write(ch, c_dd1, sizeof(c_dd1));
|
||||
crypto_hash_write(ch, sdad + 1, sdad_len - 22);
|
||||
crypto_hash_write(ch, c_dd1, sizeof(c_dd1));
|
||||
|
||||
unsigned char *h2 = crypto_hash_read(ch);
|
||||
if (!h2) {
|
||||
crypto_hash_close(ch);
|
||||
free(sdad);
|
||||
return 1;
|
||||
}
|
||||
unsigned char *h2 = crypto_hash_read(ch);
|
||||
if (!h2) {
|
||||
crypto_hash_close(ch);
|
||||
free(sdad);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
printf("crypto hash2:\n");
|
||||
dump_buffer(h2, 20, stdout, 0);
|
||||
}
|
||||
if (verbose) {
|
||||
printf("crypto hash2:\n");
|
||||
dump_buffer(h2, 20, stdout, 0);
|
||||
}
|
||||
|
||||
crypto_hash_close(ch);
|
||||
crypto_hash_close(ch);
|
||||
|
||||
ch = crypto_hash_open(HASH_SHA_1);
|
||||
if (!ch) {
|
||||
free(sdad);
|
||||
return 1;
|
||||
}
|
||||
ch = crypto_hash_open(HASH_SHA_1);
|
||||
if (!ch) {
|
||||
free(sdad);
|
||||
return 1;
|
||||
}
|
||||
|
||||
crypto_hash_write(ch, c_crm1, sizeof(c_crm1));
|
||||
crypto_hash_write(ch, c_dd2, sizeof(c_dd2));
|
||||
crypto_hash_write(ch, c_crm1, sizeof(c_crm1));
|
||||
crypto_hash_write(ch, c_dd2, sizeof(c_dd2));
|
||||
|
||||
h = crypto_hash_read(ch);
|
||||
if (!h) {
|
||||
crypto_hash_close(ch);
|
||||
free(sdad);
|
||||
return 1;
|
||||
}
|
||||
h = crypto_hash_read(ch);
|
||||
if (!h) {
|
||||
crypto_hash_close(ch);
|
||||
free(sdad);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
printf("crypto hash2.1:\n");
|
||||
dump_buffer(h, 20, stdout, 0);
|
||||
}
|
||||
if (verbose) {
|
||||
printf("crypto hash2.1:\n");
|
||||
dump_buffer(h, 20, stdout, 0);
|
||||
}
|
||||
|
||||
if (memcmp(sdad + 5 + 8 + 1 + 8, h, 20)) {
|
||||
crypto_hash_close(ch);
|
||||
free(sdad);
|
||||
return 1;
|
||||
}
|
||||
if (memcmp(sdad + 5 + 8 + 1 + 8, h, 20)) {
|
||||
crypto_hash_close(ch);
|
||||
free(sdad);
|
||||
return 1;
|
||||
}
|
||||
|
||||
crypto_hash_close(ch);
|
||||
crypto_hash_close(ch);
|
||||
|
||||
free(sdad);
|
||||
free(sdad);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cda_test_pk(bool verbose)
|
||||
{
|
||||
const struct emv_pk *pk = &c_mchip_05;
|
||||
struct tlvdb *db;
|
||||
const struct emv_pk *pk = &c_mchip_05;
|
||||
struct tlvdb *db;
|
||||
|
||||
db = tlvdb_external(0x90, sizeof(c_issuer_cert), c_issuer_cert);
|
||||
tlvdb_add(db, tlvdb_external(0x9f32, sizeof(c_issuer_exp), c_issuer_exp));
|
||||
tlvdb_add(db, tlvdb_external(0x92, sizeof(c_issuer_rem), c_issuer_rem));
|
||||
tlvdb_add(db, tlvdb_external(0x5a, sizeof(c_pan), c_pan));
|
||||
db = tlvdb_external(0x90, sizeof(c_issuer_cert), c_issuer_cert);
|
||||
tlvdb_add(db, tlvdb_external(0x9f32, sizeof(c_issuer_exp), c_issuer_exp));
|
||||
tlvdb_add(db, tlvdb_external(0x92, sizeof(c_issuer_rem), c_issuer_rem));
|
||||
tlvdb_add(db, tlvdb_external(0x5a, sizeof(c_pan), c_pan));
|
||||
|
||||
struct emv_pk *ipk = emv_pki_recover_issuer_cert(pk, db);
|
||||
if (!ipk) {
|
||||
fprintf(stderr, "Could not recover Issuer certificate!\n");
|
||||
tlvdb_free(db);
|
||||
return 2;
|
||||
}
|
||||
struct emv_pk *ipk = emv_pki_recover_issuer_cert(pk, db);
|
||||
if (!ipk) {
|
||||
fprintf(stderr, "Could not recover Issuer certificate!\n");
|
||||
tlvdb_free(db);
|
||||
return 2;
|
||||
}
|
||||
|
||||
tlvdb_add(db, tlvdb_external(0x9f46, sizeof(c_icc_cert), c_icc_cert));
|
||||
tlvdb_add(db, tlvdb_external(0x9f47, sizeof(c_icc_exp), c_icc_exp));
|
||||
/*tlvdb_add(db, tlvdb_external(0x9f48, sizeof(issuer_rem), issuer_rem));*/
|
||||
tlvdb_add(db, tlvdb_external(0x9f46, sizeof(c_icc_cert), c_icc_cert));
|
||||
tlvdb_add(db, tlvdb_external(0x9f47, sizeof(c_icc_exp), c_icc_exp));
|
||||
/*tlvdb_add(db, tlvdb_external(0x9f48, sizeof(issuer_rem), issuer_rem));*/
|
||||
|
||||
struct emv_pk *iccpk = emv_pki_recover_icc_cert(ipk, db, &ssd1_tlv);
|
||||
if (!iccpk) {
|
||||
fprintf(stderr, "Could not recover ICC certificate!\n");
|
||||
emv_pk_free(ipk);
|
||||
tlvdb_free(db);
|
||||
return 2;
|
||||
}
|
||||
struct emv_pk *iccpk = emv_pki_recover_icc_cert(ipk, db, &ssd1_tlv);
|
||||
if (!iccpk) {
|
||||
fprintf(stderr, "Could not recover ICC certificate!\n");
|
||||
emv_pk_free(ipk);
|
||||
tlvdb_free(db);
|
||||
return 2;
|
||||
}
|
||||
|
||||
tlvdb_add(db, tlvdb_fixed(0x9f37, sizeof(c_dd1), c_dd1));
|
||||
tlvdb_add(db, tlvdb_fixed(0x9f37, sizeof(c_dd1), c_dd1));
|
||||
|
||||
struct tlvdb *cda_db;
|
||||
cda_db = tlvdb_fixed(0x9f27, 1, (unsigned char[]){ 0x40 });
|
||||
tlvdb_add(cda_db, tlvdb_fixed(0x9f36, 2, (unsigned char[]) { 0x00, 0x10 }));
|
||||
tlvdb_add(cda_db, tlvdb_external(0x9f4b, sizeof(c_sdad_cr), c_sdad_cr));
|
||||
tlvdb_add(cda_db, tlvdb_fixed(0x9f10, 0x12,
|
||||
(unsigned char[]) { 0x00, 0x10, 0x90, 0x40, 0x01, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}));
|
||||
struct tlvdb *cda_db;
|
||||
cda_db = tlvdb_fixed(0x9f27, 1, (unsigned char[]){ 0x40 });
|
||||
tlvdb_add(cda_db, tlvdb_fixed(0x9f36, 2, (unsigned char[]) { 0x00, 0x10 }));
|
||||
tlvdb_add(cda_db, tlvdb_external(0x9f4b, sizeof(c_sdad_cr), c_sdad_cr));
|
||||
tlvdb_add(cda_db, tlvdb_fixed(0x9f10, 0x12,
|
||||
(unsigned char[]) { 0x00, 0x10, 0x90, 0x40, 0x01, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}));
|
||||
|
||||
struct tlvdb *idndb = emv_pki_perform_cda(iccpk, db, cda_db,
|
||||
NULL,
|
||||
&crm1_tlv,
|
||||
NULL);
|
||||
if (!idndb) {
|
||||
fprintf(stderr, "Could not recover IDN!\n");
|
||||
tlvdb_free(cda_db);
|
||||
emv_pk_free(iccpk);
|
||||
emv_pk_free(ipk);
|
||||
tlvdb_free(db);
|
||||
return 2;
|
||||
}
|
||||
struct tlvdb *idndb = emv_pki_perform_cda(iccpk, db, cda_db,
|
||||
NULL,
|
||||
&crm1_tlv,
|
||||
NULL);
|
||||
if (!idndb) {
|
||||
fprintf(stderr, "Could not recover IDN!\n");
|
||||
tlvdb_free(cda_db);
|
||||
emv_pk_free(iccpk);
|
||||
emv_pk_free(ipk);
|
||||
tlvdb_free(db);
|
||||
return 2;
|
||||
}
|
||||
|
||||
const struct tlv *idn = tlvdb_get(idndb, 0x9f4c, NULL);
|
||||
if (!idn) {
|
||||
fprintf(stderr, "IDN not found!\n");
|
||||
tlvdb_free(idndb);
|
||||
tlvdb_free(cda_db);
|
||||
emv_pk_free(iccpk);
|
||||
emv_pk_free(ipk);
|
||||
tlvdb_free(db);
|
||||
return 2;
|
||||
}
|
||||
const struct tlv *idn = tlvdb_get(idndb, 0x9f4c, NULL);
|
||||
if (!idn) {
|
||||
fprintf(stderr, "IDN not found!\n");
|
||||
tlvdb_free(idndb);
|
||||
tlvdb_free(cda_db);
|
||||
emv_pk_free(iccpk);
|
||||
emv_pk_free(ipk);
|
||||
tlvdb_free(db);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
printf("IDN:\n");
|
||||
dump_buffer(idn->value, idn->len, stdout, 0);
|
||||
}
|
||||
if (verbose) {
|
||||
printf("IDN:\n");
|
||||
dump_buffer(idn->value, idn->len, stdout, 0);
|
||||
}
|
||||
|
||||
tlvdb_free(idndb);
|
||||
tlvdb_free(cda_db);
|
||||
emv_pk_free(iccpk);
|
||||
emv_pk_free(ipk);
|
||||
tlvdb_free(db);
|
||||
tlvdb_free(idndb);
|
||||
tlvdb_free(cda_db);
|
||||
emv_pk_free(iccpk);
|
||||
emv_pk_free(ipk);
|
||||
tlvdb_free(db);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exec_cda_test(bool verbose)
|
||||
{
|
||||
int ret;
|
||||
fprintf(stdout, "\n");
|
||||
int ret;
|
||||
fprintf(stdout, "\n");
|
||||
|
||||
ret = cda_test_raw(verbose);
|
||||
if (ret) {
|
||||
fprintf(stderr, "CDA raw test: failed\n");
|
||||
return ret;
|
||||
}
|
||||
fprintf(stdout, "CDA raw test: passed\n");
|
||||
ret = cda_test_raw(verbose);
|
||||
if (ret) {
|
||||
fprintf(stderr, "CDA raw test: failed\n");
|
||||
return ret;
|
||||
}
|
||||
fprintf(stdout, "CDA raw test: passed\n");
|
||||
|
||||
ret = cda_test_pk(verbose);
|
||||
if (ret) {
|
||||
fprintf(stderr, "CDA test pk: failed\n");
|
||||
return ret;
|
||||
}
|
||||
fprintf(stdout, "CDA test pk: passed\n");
|
||||
ret = cda_test_pk(verbose);
|
||||
if (ret) {
|
||||
fprintf(stderr, "CDA test pk: failed\n");
|
||||
return ret;
|
||||
}
|
||||
fprintf(stdout, "CDA test pk: passed\n");
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -27,301 +27,301 @@
|
|||
|
||||
static int test_genkey(unsigned int keylength, unsigned char *msg, size_t msg_len, bool verbose)
|
||||
{
|
||||
int ret = 1;
|
||||
size_t tmp_len, tmp2_len;
|
||||
unsigned char *tmp, *tmp2;
|
||||
struct crypto_pk *pk;
|
||||
int ret = 1;
|
||||
size_t tmp_len, tmp2_len;
|
||||
unsigned char *tmp, *tmp2;
|
||||
struct crypto_pk *pk;
|
||||
|
||||
printf("Testing key length %u ", keylength);
|
||||
uint64_t ms = msclock();
|
||||
printf("Testing key length %u ", keylength);
|
||||
uint64_t ms = msclock();
|
||||
|
||||
pk = crypto_pk_genkey(PK_RSA, 1, keylength, 3);
|
||||
if (!pk) {
|
||||
fprintf(stderr, "ERROR: key generation error.\n");
|
||||
goto out;
|
||||
}
|
||||
pk = crypto_pk_genkey(PK_RSA, 1, keylength, 3);
|
||||
if (!pk) {
|
||||
fprintf(stderr, "ERROR: key generation error.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
tmp_len = crypto_pk_get_nbits(pk);
|
||||
if (tmp_len != keylength) {
|
||||
fprintf(stderr, "ERROR: crypto_pk_get_nbits.\n");
|
||||
goto close;
|
||||
}
|
||||
tmp_len = crypto_pk_get_nbits(pk);
|
||||
if (tmp_len != keylength) {
|
||||
fprintf(stderr, "ERROR: crypto_pk_get_nbits.\n");
|
||||
goto close;
|
||||
}
|
||||
|
||||
tmp = crypto_pk_decrypt(pk, msg, msg_len, &tmp_len);
|
||||
if (!tmp) {
|
||||
fprintf(stderr, "ERROR: crypto_pk_decrypt.\n");
|
||||
goto close;
|
||||
}
|
||||
tmp = crypto_pk_decrypt(pk, msg, msg_len, &tmp_len);
|
||||
if (!tmp) {
|
||||
fprintf(stderr, "ERROR: crypto_pk_decrypt.\n");
|
||||
goto close;
|
||||
}
|
||||
|
||||
tmp2 = crypto_pk_encrypt(pk, tmp, tmp_len, &tmp2_len);
|
||||
if (!tmp2) {
|
||||
fprintf(stderr, "ERROR: crypto_pk_encrypt.\n");
|
||||
goto free_tmp;
|
||||
}
|
||||
tmp2 = crypto_pk_encrypt(pk, tmp, tmp_len, &tmp2_len);
|
||||
if (!tmp2) {
|
||||
fprintf(stderr, "ERROR: crypto_pk_encrypt.\n");
|
||||
goto free_tmp;
|
||||
}
|
||||
|
||||
if (tmp2_len == msg_len && !memcmp(tmp2, msg, tmp2_len)) {
|
||||
ret = 0;
|
||||
} else {
|
||||
fprintf(stderr, "ERROR: encrypt-decrypt sequence length or data error.\n");
|
||||
}
|
||||
if (tmp2_len == msg_len && !memcmp(tmp2, msg, tmp2_len)) {
|
||||
ret = 0;
|
||||
} else {
|
||||
fprintf(stderr, "ERROR: encrypt-decrypt sequence length or data error.\n");
|
||||
}
|
||||
|
||||
free(tmp2);
|
||||
printf("passed. (%"PRIu64" ms) \n", msclock() - ms);
|
||||
free(tmp2);
|
||||
printf("passed. (%"PRIu64" ms) \n", msclock() - ms);
|
||||
free_tmp:
|
||||
free(tmp);
|
||||
free(tmp);
|
||||
close:
|
||||
crypto_pk_close(pk);
|
||||
crypto_pk_close(pk);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static unsigned char message[4096 / 8] =
|
||||
"aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb"
|
||||
"ccccccccccccccccdddddddddddddddd"
|
||||
"eeeeeeeeeeeeeeeeffffffffffffffff"
|
||||
"gggggggggggggggghhhhhhhhhhhhhhhh"
|
||||
"iiiiiiiiiiiiiiiijjjjjjjjjjjjjjjj"
|
||||
"kkkkkkkkkkkkkkkkllllllllllllllll"
|
||||
"mmmmmmmmmmmmmmmmnnnnnnnnnnnnnnnn"
|
||||
"oooooooooooooooopppppppppppppppp"
|
||||
"qqqqqqqqqqqqqqqqrrrrrrrrrrrrrrrr"
|
||||
"sssssssssssssssstttttttttttttttt"
|
||||
"uuuuuuuuuuuuuuuuvvvvvvvvvvvvvvvv"
|
||||
"wwwwwwwwwwwwwwwwxxxxxxxxxxxxxxxx"
|
||||
"yyyyyyyyyyyyyyyyzzzzzzzzzzzzzzzz"
|
||||
"aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb"
|
||||
"ccccccccccccccccdddddddddddddddd"
|
||||
"eeeeeeeeeeeeeeeeffffffffffffffff"
|
||||
;
|
||||
"aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb"
|
||||
"ccccccccccccccccdddddddddddddddd"
|
||||
"eeeeeeeeeeeeeeeeffffffffffffffff"
|
||||
"gggggggggggggggghhhhhhhhhhhhhhhh"
|
||||
"iiiiiiiiiiiiiiiijjjjjjjjjjjjjjjj"
|
||||
"kkkkkkkkkkkkkkkkllllllllllllllll"
|
||||
"mmmmmmmmmmmmmmmmnnnnnnnnnnnnnnnn"
|
||||
"oooooooooooooooopppppppppppppppp"
|
||||
"qqqqqqqqqqqqqqqqrrrrrrrrrrrrrrrr"
|
||||
"sssssssssssssssstttttttttttttttt"
|
||||
"uuuuuuuuuuuuuuuuvvvvvvvvvvvvvvvv"
|
||||
"wwwwwwwwwwwwwwwwxxxxxxxxxxxxxxxx"
|
||||
"yyyyyyyyyyyyyyyyzzzzzzzzzzzzzzzz"
|
||||
"aaaaaaaaaaaaaaaabbbbbbbbbbbbbbbb"
|
||||
"ccccccccccccccccdddddddddddddddd"
|
||||
"eeeeeeeeeeeeeeeeffffffffffffffff"
|
||||
;
|
||||
|
||||
static unsigned char pk_N[] = {
|
||||
0xdb, 0x12, 0xe4, 0xf1, 0x8d, 0x43, 0x74, 0xf0, 0xec, 0x38, 0xdc, 0xfb, 0xf9, 0x20, 0x75, 0x6d,
|
||||
0x05, 0xf4, 0x36, 0xc2, 0x21, 0xac, 0x34, 0x0d, 0x16, 0xc5, 0x23, 0xcb, 0xfc, 0x9a, 0x8a, 0xd1,
|
||||
0xe0, 0xbd, 0xda, 0xe5, 0x77, 0xd5, 0xaf, 0x65, 0x8d, 0x6b, 0x62, 0x5c, 0xcd, 0x89, 0x06, 0x8d,
|
||||
0x11, 0x19, 0x6b, 0x0e, 0x3e, 0xe2, 0x80, 0x45, 0xf6, 0x44, 0x55, 0x21, 0x9c, 0x86, 0x90, 0x00,
|
||||
0xa8, 0xaf, 0x8c, 0x94, 0xde, 0x3f, 0xe8, 0x56, 0x52, 0xfe, 0xee, 0xa5, 0x36, 0x72, 0x07, 0xf2,
|
||||
0xcf, 0x8e, 0xf0, 0xbd, 0xff, 0x36, 0xd5, 0xf2, 0xad, 0x74, 0x1d, 0x17, 0xd0, 0xb7, 0x93, 0xe2,
|
||||
0x2c, 0x8d, 0x3f, 0xb6, 0x7c, 0x65, 0x19, 0x9f, 0xa7, 0x80, 0x1f, 0x9f, 0xe5, 0x2f, 0x2d, 0x75,
|
||||
0xc9, 0xc2, 0xe9, 0x70, 0xfa, 0x1e, 0x5a, 0xc6, 0xa3, 0x82, 0xd1, 0x29, 0x5a, 0x60, 0xce, 0x1f,
|
||||
0x40, 0x2e, 0xfc, 0x2a, 0x5e, 0xde, 0xc9, 0x67, 0xfc, 0x45, 0x18, 0xce, 0xf2, 0x83, 0x94, 0x53,
|
||||
0xd6, 0x4f, 0x2e, 0xc5, 0x2d, 0xa1, 0xa5, 0x7a, 0x63, 0x26, 0x70, 0xcb, 0x76, 0xfc, 0xb5, 0x8d,
|
||||
0x0f, 0x88, 0x4c, 0x07, 0xba, 0xfa, 0x8b, 0xbc, 0xa0, 0xea, 0xea, 0x0a, 0xe6, 0xa5, 0x44, 0xa5,
|
||||
0x0d, 0x12, 0x66, 0x2b, 0xf7, 0xc4, 0x76, 0xa3, 0x82, 0xa6, 0x2b, 0xb2, 0x5a, 0x27, 0xcd, 0x11,
|
||||
0xd2, 0x9d, 0x42, 0x86, 0x8c, 0x82, 0xc8, 0xe1, 0xff, 0x7d, 0xf1, 0xd9, 0xd9, 0xa1, 0xf3, 0x3d,
|
||||
0xc3, 0x12, 0x4e, 0x47, 0xc8, 0xa2, 0xcd, 0x72, 0x5a, 0x18, 0xea, 0x89, 0x5c, 0x73, 0x28, 0x52,
|
||||
0xf8, 0xdb, 0x70, 0xdc, 0x92, 0xc9, 0xb7, 0x98, 0x10, 0x94, 0x79, 0xdc, 0x9e, 0x12, 0x6c, 0x14,
|
||||
0x78, 0xf9, 0x5a, 0xad, 0x00, 0x98, 0xc8, 0x17, 0x79, 0x8a, 0xed, 0xe7, 0xc3, 0xd3, 0xa7, 0x8b,
|
||||
0xdb, 0x12, 0xe4, 0xf1, 0x8d, 0x43, 0x74, 0xf0, 0xec, 0x38, 0xdc, 0xfb, 0xf9, 0x20, 0x75, 0x6d,
|
||||
0x05, 0xf4, 0x36, 0xc2, 0x21, 0xac, 0x34, 0x0d, 0x16, 0xc5, 0x23, 0xcb, 0xfc, 0x9a, 0x8a, 0xd1,
|
||||
0xe0, 0xbd, 0xda, 0xe5, 0x77, 0xd5, 0xaf, 0x65, 0x8d, 0x6b, 0x62, 0x5c, 0xcd, 0x89, 0x06, 0x8d,
|
||||
0x11, 0x19, 0x6b, 0x0e, 0x3e, 0xe2, 0x80, 0x45, 0xf6, 0x44, 0x55, 0x21, 0x9c, 0x86, 0x90, 0x00,
|
||||
0xa8, 0xaf, 0x8c, 0x94, 0xde, 0x3f, 0xe8, 0x56, 0x52, 0xfe, 0xee, 0xa5, 0x36, 0x72, 0x07, 0xf2,
|
||||
0xcf, 0x8e, 0xf0, 0xbd, 0xff, 0x36, 0xd5, 0xf2, 0xad, 0x74, 0x1d, 0x17, 0xd0, 0xb7, 0x93, 0xe2,
|
||||
0x2c, 0x8d, 0x3f, 0xb6, 0x7c, 0x65, 0x19, 0x9f, 0xa7, 0x80, 0x1f, 0x9f, 0xe5, 0x2f, 0x2d, 0x75,
|
||||
0xc9, 0xc2, 0xe9, 0x70, 0xfa, 0x1e, 0x5a, 0xc6, 0xa3, 0x82, 0xd1, 0x29, 0x5a, 0x60, 0xce, 0x1f,
|
||||
0x40, 0x2e, 0xfc, 0x2a, 0x5e, 0xde, 0xc9, 0x67, 0xfc, 0x45, 0x18, 0xce, 0xf2, 0x83, 0x94, 0x53,
|
||||
0xd6, 0x4f, 0x2e, 0xc5, 0x2d, 0xa1, 0xa5, 0x7a, 0x63, 0x26, 0x70, 0xcb, 0x76, 0xfc, 0xb5, 0x8d,
|
||||
0x0f, 0x88, 0x4c, 0x07, 0xba, 0xfa, 0x8b, 0xbc, 0xa0, 0xea, 0xea, 0x0a, 0xe6, 0xa5, 0x44, 0xa5,
|
||||
0x0d, 0x12, 0x66, 0x2b, 0xf7, 0xc4, 0x76, 0xa3, 0x82, 0xa6, 0x2b, 0xb2, 0x5a, 0x27, 0xcd, 0x11,
|
||||
0xd2, 0x9d, 0x42, 0x86, 0x8c, 0x82, 0xc8, 0xe1, 0xff, 0x7d, 0xf1, 0xd9, 0xd9, 0xa1, 0xf3, 0x3d,
|
||||
0xc3, 0x12, 0x4e, 0x47, 0xc8, 0xa2, 0xcd, 0x72, 0x5a, 0x18, 0xea, 0x89, 0x5c, 0x73, 0x28, 0x52,
|
||||
0xf8, 0xdb, 0x70, 0xdc, 0x92, 0xc9, 0xb7, 0x98, 0x10, 0x94, 0x79, 0xdc, 0x9e, 0x12, 0x6c, 0x14,
|
||||
0x78, 0xf9, 0x5a, 0xad, 0x00, 0x98, 0xc8, 0x17, 0x79, 0x8a, 0xed, 0xe7, 0xc3, 0xd3, 0xa7, 0x8b,
|
||||
};
|
||||
|
||||
static unsigned char pk_E[] = {
|
||||
0x01, 0x00, 0x01,
|
||||
0x01, 0x00, 0x01,
|
||||
};
|
||||
|
||||
static unsigned char pk_D[] = {
|
||||
0x01, 0x17, 0xd4, 0x0a, 0x9c, 0x80, 0xd4, 0xa9, 0x8b, 0x14, 0x31, 0x8e, 0x14, 0x4d, 0x24, 0x28,
|
||||
0xda, 0x19, 0xc0, 0xd8, 0x31, 0x20, 0xd1, 0xd5, 0xaa, 0xe2, 0x6a, 0xee, 0x4e, 0xa1, 0x5a, 0xc5,
|
||||
0xf7, 0x50, 0x1b, 0x32, 0x7f, 0xe9, 0x92, 0x09, 0x78, 0xae, 0x2b, 0x7c, 0x79, 0x0e, 0x10, 0xf9,
|
||||
0x4d, 0x37, 0x8a, 0x40, 0x34, 0xf2, 0x1e, 0x5f, 0xba, 0xfd, 0xd6, 0x4a, 0xe7, 0xa4, 0x08, 0x3d,
|
||||
0xe8, 0x99, 0x8f, 0xa3, 0x02, 0x84, 0xe1, 0x1c, 0xe5, 0x27, 0x1e, 0x7b, 0xb6, 0x8c, 0xd5, 0x1b,
|
||||
0x52, 0x0b, 0xcd, 0x89, 0xb5, 0x27, 0x49, 0xe3, 0xff, 0x17, 0x90, 0x39, 0x99, 0x32, 0x01, 0x4b,
|
||||
0xe4, 0x9b, 0x03, 0xd1, 0x5e, 0x47, 0x86, 0xdc, 0x34, 0x12, 0xc0, 0x95, 0xa4, 0xa8, 0x1a, 0x9a,
|
||||
0xf6, 0xd9, 0xc1, 0x1e, 0x6e, 0x31, 0x0e, 0x94, 0xe5, 0x25, 0xf6, 0xf3, 0x34, 0xdf, 0x3c, 0xc8,
|
||||
0x0a, 0xc5, 0x8c, 0x00, 0x5c, 0x59, 0x55, 0x06, 0xd1, 0x39, 0x84, 0x35, 0x96, 0x40, 0xe8, 0xb2,
|
||||
0xf7, 0x13, 0x83, 0x37, 0xe1, 0xe2, 0x79, 0x41, 0x90, 0x2a, 0xc3, 0x71, 0xc5, 0xcf, 0xf0, 0xaa,
|
||||
0x01, 0x2f, 0x48, 0x9c, 0x3f, 0x29, 0x7b, 0xb7, 0x5c, 0xef, 0x25, 0xde, 0x34, 0x23, 0x81, 0x7a,
|
||||
0x4c, 0x3a, 0x9b, 0xe4, 0xa7, 0x44, 0x73, 0xbf, 0xf7, 0x39, 0x43, 0xa4, 0x39, 0xa0, 0x1b, 0xf7,
|
||||
0x4f, 0x5f, 0x14, 0x49, 0x32, 0x0e, 0x66, 0xd0, 0x29, 0xb5, 0x80, 0xe0, 0xba, 0x3b, 0x88, 0x2b,
|
||||
0x14, 0xa4, 0x26, 0x00, 0x2f, 0x50, 0x20, 0x4e, 0xfa, 0xc2, 0x44, 0x72, 0x72, 0x6c, 0x2a, 0x77,
|
||||
0x85, 0x20, 0xe0, 0x1d, 0x95, 0x6a, 0x66, 0xe7, 0xb8, 0xca, 0x5b, 0xc9, 0xc3, 0xf3, 0x39, 0xef,
|
||||
0xd7, 0xd5, 0x45, 0xb6, 0x3e, 0x19, 0xea, 0x7c, 0x56, 0x20, 0x1b, 0x95, 0x86, 0x2e, 0xc7, 0x51,
|
||||
0x01, 0x17, 0xd4, 0x0a, 0x9c, 0x80, 0xd4, 0xa9, 0x8b, 0x14, 0x31, 0x8e, 0x14, 0x4d, 0x24, 0x28,
|
||||
0xda, 0x19, 0xc0, 0xd8, 0x31, 0x20, 0xd1, 0xd5, 0xaa, 0xe2, 0x6a, 0xee, 0x4e, 0xa1, 0x5a, 0xc5,
|
||||
0xf7, 0x50, 0x1b, 0x32, 0x7f, 0xe9, 0x92, 0x09, 0x78, 0xae, 0x2b, 0x7c, 0x79, 0x0e, 0x10, 0xf9,
|
||||
0x4d, 0x37, 0x8a, 0x40, 0x34, 0xf2, 0x1e, 0x5f, 0xba, 0xfd, 0xd6, 0x4a, 0xe7, 0xa4, 0x08, 0x3d,
|
||||
0xe8, 0x99, 0x8f, 0xa3, 0x02, 0x84, 0xe1, 0x1c, 0xe5, 0x27, 0x1e, 0x7b, 0xb6, 0x8c, 0xd5, 0x1b,
|
||||
0x52, 0x0b, 0xcd, 0x89, 0xb5, 0x27, 0x49, 0xe3, 0xff, 0x17, 0x90, 0x39, 0x99, 0x32, 0x01, 0x4b,
|
||||
0xe4, 0x9b, 0x03, 0xd1, 0x5e, 0x47, 0x86, 0xdc, 0x34, 0x12, 0xc0, 0x95, 0xa4, 0xa8, 0x1a, 0x9a,
|
||||
0xf6, 0xd9, 0xc1, 0x1e, 0x6e, 0x31, 0x0e, 0x94, 0xe5, 0x25, 0xf6, 0xf3, 0x34, 0xdf, 0x3c, 0xc8,
|
||||
0x0a, 0xc5, 0x8c, 0x00, 0x5c, 0x59, 0x55, 0x06, 0xd1, 0x39, 0x84, 0x35, 0x96, 0x40, 0xe8, 0xb2,
|
||||
0xf7, 0x13, 0x83, 0x37, 0xe1, 0xe2, 0x79, 0x41, 0x90, 0x2a, 0xc3, 0x71, 0xc5, 0xcf, 0xf0, 0xaa,
|
||||
0x01, 0x2f, 0x48, 0x9c, 0x3f, 0x29, 0x7b, 0xb7, 0x5c, 0xef, 0x25, 0xde, 0x34, 0x23, 0x81, 0x7a,
|
||||
0x4c, 0x3a, 0x9b, 0xe4, 0xa7, 0x44, 0x73, 0xbf, 0xf7, 0x39, 0x43, 0xa4, 0x39, 0xa0, 0x1b, 0xf7,
|
||||
0x4f, 0x5f, 0x14, 0x49, 0x32, 0x0e, 0x66, 0xd0, 0x29, 0xb5, 0x80, 0xe0, 0xba, 0x3b, 0x88, 0x2b,
|
||||
0x14, 0xa4, 0x26, 0x00, 0x2f, 0x50, 0x20, 0x4e, 0xfa, 0xc2, 0x44, 0x72, 0x72, 0x6c, 0x2a, 0x77,
|
||||
0x85, 0x20, 0xe0, 0x1d, 0x95, 0x6a, 0x66, 0xe7, 0xb8, 0xca, 0x5b, 0xc9, 0xc3, 0xf3, 0x39, 0xef,
|
||||
0xd7, 0xd5, 0x45, 0xb6, 0x3e, 0x19, 0xea, 0x7c, 0x56, 0x20, 0x1b, 0x95, 0x86, 0x2e, 0xc7, 0x51,
|
||||
};
|
||||
|
||||
static unsigned char pk_P[] = {
|
||||
0xf5, 0x93, 0x0f, 0x76, 0x00, 0xab, 0x37, 0x01, 0xb9, 0x52, 0xb6, 0x82, 0xf9, 0xf5, 0xae, 0x29,
|
||||
0x8f, 0xd5, 0x08, 0xbc, 0xf7, 0x9f, 0x84, 0xb6, 0x4c, 0x94, 0xb5, 0xfc, 0xfe, 0xe1, 0xcd, 0x6a,
|
||||
0xf4, 0x9c, 0xa7, 0x33, 0xdb, 0xd8, 0xc8, 0xc1, 0xc0, 0x8d, 0x65, 0xed, 0x29, 0x99, 0x6c, 0x5c,
|
||||
0xbe, 0x08, 0xac, 0x04, 0xe4, 0x3a, 0x18, 0xe2, 0x0f, 0x70, 0x26, 0x70, 0x9b, 0x71, 0xfc, 0x9f,
|
||||
0x22, 0xea, 0x90, 0x3b, 0xc2, 0xa5, 0x16, 0x7a, 0xcd, 0x04, 0x3e, 0xa6, 0x37, 0x49, 0xa7, 0xee,
|
||||
0xaa, 0xe4, 0x9d, 0xaa, 0x9b, 0xb0, 0xe2, 0x6a, 0x9d, 0x1e, 0xcd, 0x83, 0x4e, 0xd8, 0x59, 0x6d,
|
||||
0x03, 0xd5, 0x4c, 0x5e, 0xc5, 0x22, 0x10, 0xb7, 0xcc, 0x0c, 0x90, 0x76, 0x05, 0x21, 0xe7, 0x77,
|
||||
0x5c, 0x88, 0x5f, 0xd0, 0x5f, 0x9e, 0x2e, 0x49, 0x56, 0xf4, 0x2b, 0xa9, 0x99, 0x57, 0x74, 0x19,
|
||||
0xf5, 0x93, 0x0f, 0x76, 0x00, 0xab, 0x37, 0x01, 0xb9, 0x52, 0xb6, 0x82, 0xf9, 0xf5, 0xae, 0x29,
|
||||
0x8f, 0xd5, 0x08, 0xbc, 0xf7, 0x9f, 0x84, 0xb6, 0x4c, 0x94, 0xb5, 0xfc, 0xfe, 0xe1, 0xcd, 0x6a,
|
||||
0xf4, 0x9c, 0xa7, 0x33, 0xdb, 0xd8, 0xc8, 0xc1, 0xc0, 0x8d, 0x65, 0xed, 0x29, 0x99, 0x6c, 0x5c,
|
||||
0xbe, 0x08, 0xac, 0x04, 0xe4, 0x3a, 0x18, 0xe2, 0x0f, 0x70, 0x26, 0x70, 0x9b, 0x71, 0xfc, 0x9f,
|
||||
0x22, 0xea, 0x90, 0x3b, 0xc2, 0xa5, 0x16, 0x7a, 0xcd, 0x04, 0x3e, 0xa6, 0x37, 0x49, 0xa7, 0xee,
|
||||
0xaa, 0xe4, 0x9d, 0xaa, 0x9b, 0xb0, 0xe2, 0x6a, 0x9d, 0x1e, 0xcd, 0x83, 0x4e, 0xd8, 0x59, 0x6d,
|
||||
0x03, 0xd5, 0x4c, 0x5e, 0xc5, 0x22, 0x10, 0xb7, 0xcc, 0x0c, 0x90, 0x76, 0x05, 0x21, 0xe7, 0x77,
|
||||
0x5c, 0x88, 0x5f, 0xd0, 0x5f, 0x9e, 0x2e, 0x49, 0x56, 0xf4, 0x2b, 0xa9, 0x99, 0x57, 0x74, 0x19,
|
||||
};
|
||||
|
||||
static unsigned char pk_Q[] = {
|
||||
0xe4, 0x5f, 0xd2, 0x28, 0xbd, 0xf3, 0xdd, 0x70, 0x3d, 0xfd, 0x01, 0x23, 0xae, 0x93, 0x6a, 0x91,
|
||||
0xca, 0x68, 0xb1, 0xdb, 0x81, 0xab, 0x1e, 0x63, 0x76, 0x9b, 0x6d, 0xaa, 0x41, 0x87, 0x5a, 0x79,
|
||||
0xe7, 0xce, 0xd6, 0x84, 0x32, 0x53, 0xf5, 0xfc, 0xb7, 0x41, 0x7c, 0xcb, 0x88, 0x09, 0xcb, 0xe9,
|
||||
0x07, 0x16, 0x28, 0x55, 0x23, 0xe5, 0xf2, 0xf5, 0x23, 0xf5, 0xee, 0x2b, 0x9d, 0x91, 0x56, 0xc6,
|
||||
0x30, 0x91, 0x4d, 0x16, 0x11, 0x6c, 0x48, 0x45, 0xe8, 0x5d, 0x0e, 0x9e, 0x04, 0xc8, 0xb6, 0xdd,
|
||||
0xba, 0x0d, 0xdf, 0x53, 0x56, 0xfa, 0x0b, 0x0b, 0x99, 0x8d, 0xea, 0x5c, 0x45, 0x7d, 0xed, 0xad,
|
||||
0x1f, 0xc5, 0xc1, 0x7d, 0x63, 0x31, 0xf8, 0x32, 0xb5, 0x33, 0xb0, 0xef, 0xce, 0x2e, 0x74, 0x1e,
|
||||
0x77, 0x2a, 0x18, 0x35, 0x3d, 0x6e, 0x01, 0xba, 0xde, 0x21, 0x8e, 0x14, 0x12, 0xc3, 0x0d, 0x43,
|
||||
0xe4, 0x5f, 0xd2, 0x28, 0xbd, 0xf3, 0xdd, 0x70, 0x3d, 0xfd, 0x01, 0x23, 0xae, 0x93, 0x6a, 0x91,
|
||||
0xca, 0x68, 0xb1, 0xdb, 0x81, 0xab, 0x1e, 0x63, 0x76, 0x9b, 0x6d, 0xaa, 0x41, 0x87, 0x5a, 0x79,
|
||||
0xe7, 0xce, 0xd6, 0x84, 0x32, 0x53, 0xf5, 0xfc, 0xb7, 0x41, 0x7c, 0xcb, 0x88, 0x09, 0xcb, 0xe9,
|
||||
0x07, 0x16, 0x28, 0x55, 0x23, 0xe5, 0xf2, 0xf5, 0x23, 0xf5, 0xee, 0x2b, 0x9d, 0x91, 0x56, 0xc6,
|
||||
0x30, 0x91, 0x4d, 0x16, 0x11, 0x6c, 0x48, 0x45, 0xe8, 0x5d, 0x0e, 0x9e, 0x04, 0xc8, 0xb6, 0xdd,
|
||||
0xba, 0x0d, 0xdf, 0x53, 0x56, 0xfa, 0x0b, 0x0b, 0x99, 0x8d, 0xea, 0x5c, 0x45, 0x7d, 0xed, 0xad,
|
||||
0x1f, 0xc5, 0xc1, 0x7d, 0x63, 0x31, 0xf8, 0x32, 0xb5, 0x33, 0xb0, 0xef, 0xce, 0x2e, 0x74, 0x1e,
|
||||
0x77, 0x2a, 0x18, 0x35, 0x3d, 0x6e, 0x01, 0xba, 0xde, 0x21, 0x8e, 0x14, 0x12, 0xc3, 0x0d, 0x43,
|
||||
};
|
||||
|
||||
static unsigned char pk_dP[] = {
|
||||
0x5a, 0xc8, 0xf7, 0x1a, 0x44, 0xbd, 0x07, 0x24, 0xd8, 0x02, 0x3f, 0xfe, 0xc3, 0xb1, 0x93, 0xa5,
|
||||
0x41, 0xcb, 0x1b, 0xe3, 0xe0, 0x17, 0x54, 0xd4, 0xa0, 0x13, 0x0a, 0x04, 0x71, 0xa5, 0xc0, 0x6f,
|
||||
0x1d, 0xe7, 0x1b, 0xd9, 0x0c, 0x19, 0x64, 0x7e, 0x5c, 0x54, 0xe9, 0xad, 0x77, 0x87, 0x84, 0x8b,
|
||||
0xf4, 0xa4, 0xf8, 0x13, 0x06, 0xdc, 0x83, 0x7e, 0x6e, 0xfe, 0xa2, 0xf7, 0x56, 0x40, 0x19, 0x88,
|
||||
0x2b, 0x3c, 0x53, 0xfe, 0x03, 0xc3, 0x4c, 0x40, 0x31, 0xb2, 0xb4, 0x06, 0x76, 0xc2, 0x00, 0x17,
|
||||
0x37, 0x8e, 0x34, 0xcb, 0x71, 0xab, 0x3e, 0xc8, 0xf3, 0x35, 0x03, 0xfc, 0xdb, 0x15, 0x18, 0x5a,
|
||||
0x38, 0xe4, 0x8d, 0xcb, 0x2b, 0x4d, 0xa0, 0xa8, 0x92, 0x02, 0xc3, 0x15, 0x1e, 0x68, 0x9e, 0x4d,
|
||||
0x7e, 0x23, 0xdc, 0x68, 0x08, 0x31, 0x4e, 0x23, 0x46, 0xc6, 0x15, 0xae, 0x29, 0x46, 0x2f, 0x61,
|
||||
0x5a, 0xc8, 0xf7, 0x1a, 0x44, 0xbd, 0x07, 0x24, 0xd8, 0x02, 0x3f, 0xfe, 0xc3, 0xb1, 0x93, 0xa5,
|
||||
0x41, 0xcb, 0x1b, 0xe3, 0xe0, 0x17, 0x54, 0xd4, 0xa0, 0x13, 0x0a, 0x04, 0x71, 0xa5, 0xc0, 0x6f,
|
||||
0x1d, 0xe7, 0x1b, 0xd9, 0x0c, 0x19, 0x64, 0x7e, 0x5c, 0x54, 0xe9, 0xad, 0x77, 0x87, 0x84, 0x8b,
|
||||
0xf4, 0xa4, 0xf8, 0x13, 0x06, 0xdc, 0x83, 0x7e, 0x6e, 0xfe, 0xa2, 0xf7, 0x56, 0x40, 0x19, 0x88,
|
||||
0x2b, 0x3c, 0x53, 0xfe, 0x03, 0xc3, 0x4c, 0x40, 0x31, 0xb2, 0xb4, 0x06, 0x76, 0xc2, 0x00, 0x17,
|
||||
0x37, 0x8e, 0x34, 0xcb, 0x71, 0xab, 0x3e, 0xc8, 0xf3, 0x35, 0x03, 0xfc, 0xdb, 0x15, 0x18, 0x5a,
|
||||
0x38, 0xe4, 0x8d, 0xcb, 0x2b, 0x4d, 0xa0, 0xa8, 0x92, 0x02, 0xc3, 0x15, 0x1e, 0x68, 0x9e, 0x4d,
|
||||
0x7e, 0x23, 0xdc, 0x68, 0x08, 0x31, 0x4e, 0x23, 0x46, 0xc6, 0x15, 0xae, 0x29, 0x46, 0x2f, 0x61,
|
||||
};
|
||||
|
||||
static unsigned char pk_dQ[] = {
|
||||
0x33, 0x61, 0x9f, 0xae, 0x0c, 0xf6, 0xc6, 0x16, 0x8f, 0xcb, 0xd1, 0xaa, 0xce, 0x87, 0x5a, 0x4d,
|
||||
0xcc, 0xe5, 0x7b, 0x46, 0xb0, 0xc8, 0xe8, 0x40, 0x66, 0x9a, 0x17, 0xb5, 0x5b, 0xa2, 0xf1, 0x67,
|
||||
0x46, 0x11, 0x52, 0x50, 0x51, 0xe6, 0x74, 0x0c, 0xd4, 0xca, 0x46, 0x22, 0xa0, 0xcb, 0xdb, 0x75,
|
||||
0xe5, 0x63, 0x45, 0xd5, 0xca, 0x0a, 0xdd, 0x7b, 0xec, 0x08, 0x53, 0xfa, 0xba, 0x2b, 0xce, 0x03,
|
||||
0x2f, 0x40, 0x31, 0xc0, 0xca, 0x50, 0xbb, 0x7e, 0x07, 0x06, 0x90, 0xd8, 0x5a, 0xa9, 0x32, 0x03,
|
||||
0x76, 0xed, 0xd2, 0x16, 0x35, 0x16, 0x72, 0xcf, 0xbc, 0x4f, 0xa2, 0xaf, 0xf9, 0xee, 0x98, 0x40,
|
||||
0x00, 0x4b, 0x04, 0xfa, 0x8a, 0x0b, 0xdf, 0x14, 0xc1, 0x92, 0x0c, 0xb8, 0x17, 0x82, 0x7a, 0x1b,
|
||||
0xb4, 0xa1, 0xe2, 0xea, 0x6f, 0x94, 0xc5, 0x8c, 0xde, 0x97, 0x5c, 0x19, 0x06, 0x13, 0x9e, 0x73,
|
||||
0x33, 0x61, 0x9f, 0xae, 0x0c, 0xf6, 0xc6, 0x16, 0x8f, 0xcb, 0xd1, 0xaa, 0xce, 0x87, 0x5a, 0x4d,
|
||||
0xcc, 0xe5, 0x7b, 0x46, 0xb0, 0xc8, 0xe8, 0x40, 0x66, 0x9a, 0x17, 0xb5, 0x5b, 0xa2, 0xf1, 0x67,
|
||||
0x46, 0x11, 0x52, 0x50, 0x51, 0xe6, 0x74, 0x0c, 0xd4, 0xca, 0x46, 0x22, 0xa0, 0xcb, 0xdb, 0x75,
|
||||
0xe5, 0x63, 0x45, 0xd5, 0xca, 0x0a, 0xdd, 0x7b, 0xec, 0x08, 0x53, 0xfa, 0xba, 0x2b, 0xce, 0x03,
|
||||
0x2f, 0x40, 0x31, 0xc0, 0xca, 0x50, 0xbb, 0x7e, 0x07, 0x06, 0x90, 0xd8, 0x5a, 0xa9, 0x32, 0x03,
|
||||
0x76, 0xed, 0xd2, 0x16, 0x35, 0x16, 0x72, 0xcf, 0xbc, 0x4f, 0xa2, 0xaf, 0xf9, 0xee, 0x98, 0x40,
|
||||
0x00, 0x4b, 0x04, 0xfa, 0x8a, 0x0b, 0xdf, 0x14, 0xc1, 0x92, 0x0c, 0xb8, 0x17, 0x82, 0x7a, 0x1b,
|
||||
0xb4, 0xa1, 0xe2, 0xea, 0x6f, 0x94, 0xc5, 0x8c, 0xde, 0x97, 0x5c, 0x19, 0x06, 0x13, 0x9e, 0x73,
|
||||
};
|
||||
|
||||
static unsigned char pk_I[] = {
|
||||
0x75, 0x40, 0xc6, 0x02, 0x7e, 0x4f, 0xad, 0xdb, 0x95, 0xac, 0x07, 0x8d, 0x80, 0xb6, 0x80, 0x02,
|
||||
0x06, 0xdd, 0xb8, 0x5d, 0x92, 0x65, 0x69, 0x26, 0x86, 0x61, 0x6c, 0x87, 0x4e, 0xe5, 0x03, 0x68,
|
||||
0xc6, 0x10, 0x15, 0x8c, 0x43, 0x3a, 0x45, 0x63, 0x48, 0xb7, 0x8a, 0x8c, 0xa2, 0x2b, 0x34, 0xb6,
|
||||
0x83, 0xfe, 0xa8, 0x10, 0xa5, 0x74, 0xa5, 0xa9, 0x52, 0x42, 0x1f, 0xa0, 0x80, 0x6a, 0xc5, 0x35,
|
||||
0xe8, 0xb8, 0xc2, 0xa0, 0x3f, 0x49, 0x18, 0xcf, 0x0e, 0x54, 0x3c, 0x70, 0x11, 0x11, 0xd3, 0x85,
|
||||
0x8c, 0xb2, 0xe5, 0x74, 0xdf, 0x98, 0xea, 0x6c, 0xc0, 0x5f, 0x7f, 0xff, 0x69, 0xbf, 0x08, 0x8d,
|
||||
0x1b, 0xc4, 0x90, 0xcc, 0xa4, 0xcd, 0xcc, 0x34, 0x58, 0xe5, 0x91, 0x53, 0x3a, 0xd5, 0x39, 0xf4,
|
||||
0xd4, 0x42, 0xc9, 0x17, 0xb2, 0x2c, 0x92, 0x12, 0x37, 0x1b, 0xd3, 0xc5, 0x79, 0xd2, 0x65, 0x61,
|
||||
0x75, 0x40, 0xc6, 0x02, 0x7e, 0x4f, 0xad, 0xdb, 0x95, 0xac, 0x07, 0x8d, 0x80, 0xb6, 0x80, 0x02,
|
||||
0x06, 0xdd, 0xb8, 0x5d, 0x92, 0x65, 0x69, 0x26, 0x86, 0x61, 0x6c, 0x87, 0x4e, 0xe5, 0x03, 0x68,
|
||||
0xc6, 0x10, 0x15, 0x8c, 0x43, 0x3a, 0x45, 0x63, 0x48, 0xb7, 0x8a, 0x8c, 0xa2, 0x2b, 0x34, 0xb6,
|
||||
0x83, 0xfe, 0xa8, 0x10, 0xa5, 0x74, 0xa5, 0xa9, 0x52, 0x42, 0x1f, 0xa0, 0x80, 0x6a, 0xc5, 0x35,
|
||||
0xe8, 0xb8, 0xc2, 0xa0, 0x3f, 0x49, 0x18, 0xcf, 0x0e, 0x54, 0x3c, 0x70, 0x11, 0x11, 0xd3, 0x85,
|
||||
0x8c, 0xb2, 0xe5, 0x74, 0xdf, 0x98, 0xea, 0x6c, 0xc0, 0x5f, 0x7f, 0xff, 0x69, 0xbf, 0x08, 0x8d,
|
||||
0x1b, 0xc4, 0x90, 0xcc, 0xa4, 0xcd, 0xcc, 0x34, 0x58, 0xe5, 0x91, 0x53, 0x3a, 0xd5, 0x39, 0xf4,
|
||||
0xd4, 0x42, 0xc9, 0x17, 0xb2, 0x2c, 0x92, 0x12, 0x37, 0x1b, 0xd3, 0xc5, 0x79, 0xd2, 0x65, 0x61,
|
||||
};
|
||||
|
||||
static int test_pk(bool verbose)
|
||||
{
|
||||
int ret = 1;
|
||||
size_t tmp_len, tmp2_len;
|
||||
unsigned char *tmp, *tmp2;
|
||||
struct crypto_pk *pubk, *privk;
|
||||
unsigned char *msg = message;
|
||||
size_t msg_len = sizeof(pk_N);
|
||||
int ret = 1;
|
||||
size_t tmp_len, tmp2_len;
|
||||
unsigned char *tmp, *tmp2;
|
||||
struct crypto_pk *pubk, *privk;
|
||||
unsigned char *msg = message;
|
||||
size_t msg_len = sizeof(pk_N);
|
||||
|
||||
printf("Testing public keys interfaces\n");
|
||||
printf("Testing public keys interfaces\n");
|
||||
|
||||
pubk = crypto_pk_open(PK_RSA,
|
||||
pk_N, sizeof(pk_N),
|
||||
pk_E, sizeof(pk_E));
|
||||
if (!pubk) {
|
||||
fprintf(stderr, "ERROR: open public key.\n");
|
||||
return 1;
|
||||
}
|
||||
pubk = crypto_pk_open(PK_RSA,
|
||||
pk_N, sizeof(pk_N),
|
||||
pk_E, sizeof(pk_E));
|
||||
if (!pubk) {
|
||||
fprintf(stderr, "ERROR: open public key.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
tmp_len = crypto_pk_get_nbits(pubk);
|
||||
if (tmp_len != sizeof(pk_N) * 8) {
|
||||
fprintf(stderr, "ERROR: crypto_pk_get_nbits mismatch.\n");
|
||||
goto close_pub;
|
||||
}
|
||||
tmp_len = crypto_pk_get_nbits(pubk);
|
||||
if (tmp_len != sizeof(pk_N) * 8) {
|
||||
fprintf(stderr, "ERROR: crypto_pk_get_nbits mismatch.\n");
|
||||
goto close_pub;
|
||||
}
|
||||
|
||||
tmp = crypto_pk_get_parameter(pubk, 0, &tmp_len);
|
||||
if (tmp_len != sizeof(pk_N) || memcmp(tmp, pk_N, tmp_len)) {
|
||||
fprintf(stderr, "ERROR: crypto_pk_get_parameter(0) Modulus. param len %zu len %zu\n", tmp_len, sizeof(pk_N));
|
||||
free(tmp);
|
||||
goto close_pub;
|
||||
}
|
||||
free(tmp);
|
||||
tmp = crypto_pk_get_parameter(pubk, 0, &tmp_len);
|
||||
if (tmp_len != sizeof(pk_N) || memcmp(tmp, pk_N, tmp_len)) {
|
||||
fprintf(stderr, "ERROR: crypto_pk_get_parameter(0) Modulus. param len %zu len %zu\n", tmp_len, sizeof(pk_N));
|
||||
free(tmp);
|
||||
goto close_pub;
|
||||
}
|
||||
free(tmp);
|
||||
|
||||
tmp = crypto_pk_get_parameter(pubk, 1, &tmp_len);
|
||||
if (tmp_len != sizeof(pk_E) || memcmp(tmp, pk_E, tmp_len)) {
|
||||
fprintf(stderr, "ERROR: crypto_pk_get_parameter(1) Exponent.\n");
|
||||
free(tmp);
|
||||
goto close_pub;
|
||||
}
|
||||
free(tmp);
|
||||
tmp = crypto_pk_get_parameter(pubk, 1, &tmp_len);
|
||||
if (tmp_len != sizeof(pk_E) || memcmp(tmp, pk_E, tmp_len)) {
|
||||
fprintf(stderr, "ERROR: crypto_pk_get_parameter(1) Exponent.\n");
|
||||
free(tmp);
|
||||
goto close_pub;
|
||||
}
|
||||
free(tmp);
|
||||
|
||||
privk = crypto_pk_open_priv(PK_RSA,
|
||||
pk_N, sizeof(pk_N),
|
||||
pk_E, sizeof(pk_E),
|
||||
pk_D, sizeof(pk_D),
|
||||
pk_P, sizeof(pk_P),
|
||||
pk_Q, sizeof(pk_Q),
|
||||
pk_dP, sizeof(pk_dP),
|
||||
pk_dQ, sizeof(pk_dQ),
|
||||
pk_I, sizeof(pk_I));
|
||||
if (!privk) {
|
||||
fprintf(stderr, "ERROR: open private key.\n");
|
||||
goto close_pub;
|
||||
}
|
||||
privk = crypto_pk_open_priv(PK_RSA,
|
||||
pk_N, sizeof(pk_N),
|
||||
pk_E, sizeof(pk_E),
|
||||
pk_D, sizeof(pk_D),
|
||||
pk_P, sizeof(pk_P),
|
||||
pk_Q, sizeof(pk_Q),
|
||||
pk_dP, sizeof(pk_dP),
|
||||
pk_dQ, sizeof(pk_dQ),
|
||||
pk_I, sizeof(pk_I));
|
||||
if (!privk) {
|
||||
fprintf(stderr, "ERROR: open private key.\n");
|
||||
goto close_pub;
|
||||
}
|
||||
|
||||
|
||||
tmp_len = crypto_pk_get_nbits(privk);
|
||||
if (tmp_len != sizeof(pk_N) * 8) {
|
||||
fprintf(stderr, "ERROR: crypto_pk_get_nbits mismatch.\n");
|
||||
goto close_pub;
|
||||
}
|
||||
tmp_len = crypto_pk_get_nbits(privk);
|
||||
if (tmp_len != sizeof(pk_N) * 8) {
|
||||
fprintf(stderr, "ERROR: crypto_pk_get_nbits mismatch.\n");
|
||||
goto close_pub;
|
||||
}
|
||||
|
||||
tmp = crypto_pk_get_parameter(privk, 0, &tmp_len);
|
||||
if (tmp_len != sizeof(pk_N) || memcmp(tmp, pk_N, tmp_len)) {
|
||||
fprintf(stderr, "ERROR: crypto_pk_get_parameter(0) Modulus. param len %zu len %zu\n", tmp_len, sizeof(pk_N));
|
||||
free(tmp);
|
||||
goto close;
|
||||
}
|
||||
free(tmp);
|
||||
tmp = crypto_pk_get_parameter(privk, 0, &tmp_len);
|
||||
if (tmp_len != sizeof(pk_N) || memcmp(tmp, pk_N, tmp_len)) {
|
||||
fprintf(stderr, "ERROR: crypto_pk_get_parameter(0) Modulus. param len %zu len %zu\n", tmp_len, sizeof(pk_N));
|
||||
free(tmp);
|
||||
goto close;
|
||||
}
|
||||
free(tmp);
|
||||
|
||||
tmp = crypto_pk_get_parameter(privk, 1, &tmp_len);
|
||||
if (tmp_len != sizeof(pk_E) || memcmp(tmp, pk_E, tmp_len)) {
|
||||
fprintf(stderr, "ERROR: crypto_pk_get_parameter(1) Exponent.\n");
|
||||
free(tmp);
|
||||
goto close;
|
||||
}
|
||||
free(tmp);
|
||||
tmp = crypto_pk_get_parameter(privk, 1, &tmp_len);
|
||||
if (tmp_len != sizeof(pk_E) || memcmp(tmp, pk_E, tmp_len)) {
|
||||
fprintf(stderr, "ERROR: crypto_pk_get_parameter(1) Exponent.\n");
|
||||
free(tmp);
|
||||
goto close;
|
||||
}
|
||||
free(tmp);
|
||||
|
||||
tmp = crypto_pk_decrypt(privk, msg, msg_len, &tmp_len);
|
||||
if (!tmp) {
|
||||
fprintf(stderr, "ERROR: crypto_pk_decrypt.\n");
|
||||
goto close;
|
||||
}
|
||||
tmp = crypto_pk_decrypt(privk, msg, msg_len, &tmp_len);
|
||||
if (!tmp) {
|
||||
fprintf(stderr, "ERROR: crypto_pk_decrypt.\n");
|
||||
goto close;
|
||||
}
|
||||
|
||||
tmp2 = crypto_pk_encrypt(pubk, tmp, tmp_len, &tmp2_len);
|
||||
if (!tmp2) {
|
||||
fprintf(stderr, "ERROR: crypto_pk_encrypt.\n");
|
||||
goto free_tmp;
|
||||
}
|
||||
tmp2 = crypto_pk_encrypt(pubk, tmp, tmp_len, &tmp2_len);
|
||||
if (!tmp2) {
|
||||
fprintf(stderr, "ERROR: crypto_pk_encrypt.\n");
|
||||
goto free_tmp;
|
||||
}
|
||||
|
||||
if (tmp2_len == msg_len && !memcmp(tmp2, msg, tmp2_len)) {
|
||||
ret = 0;
|
||||
} else {
|
||||
fprintf(stderr, "ERROR: encrypt-decrypt sequence length or data error.\n");
|
||||
}
|
||||
if (tmp2_len == msg_len && !memcmp(tmp2, msg, tmp2_len)) {
|
||||
ret = 0;
|
||||
} else {
|
||||
fprintf(stderr, "ERROR: encrypt-decrypt sequence length or data error.\n");
|
||||
}
|
||||
|
||||
free(tmp2);
|
||||
free(tmp2);
|
||||
free_tmp:
|
||||
free(tmp);
|
||||
free(tmp);
|
||||
|
||||
close:
|
||||
crypto_pk_close(privk);
|
||||
crypto_pk_close(privk);
|
||||
close_pub:
|
||||
crypto_pk_close(pubk);
|
||||
crypto_pk_close(pubk);
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int exec_crypto_test(bool verbose)
|
||||
{
|
||||
unsigned int keylengths[] = {1024, 1152, 1408, 1984, 2048, 3072, 4096};
|
||||
int i;
|
||||
int ret;
|
||||
fprintf(stdout, "\n");
|
||||
unsigned int keylengths[] = {1024, 1152, 1408, 1984, 2048, 3072, 4096};
|
||||
int i;
|
||||
int ret;
|
||||
fprintf(stdout, "\n");
|
||||
|
||||
ret = test_pk(verbose);
|
||||
if (ret) {
|
||||
fprintf(stderr, "Crypto raw test: failed\n");
|
||||
return ret;
|
||||
}
|
||||
fprintf(stdout, "Crypto raw test: passed\n\n");
|
||||
ret = test_pk(verbose);
|
||||
if (ret) {
|
||||
fprintf(stderr, "Crypto raw test: failed\n");
|
||||
return ret;
|
||||
}
|
||||
fprintf(stdout, "Crypto raw test: passed\n\n");
|
||||
|
||||
for (i = 0; i < sizeof(keylengths) / sizeof(keylengths[0]); i++) {
|
||||
unsigned int kl = keylengths[i];
|
||||
ret = test_genkey(kl, message, kl / 8, verbose);
|
||||
if (ret) {
|
||||
fprintf(stderr, "Crypto generate key[%d] test: failed\n", kl);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < sizeof(keylengths) / sizeof(keylengths[0]); i++) {
|
||||
unsigned int kl = keylengths[i];
|
||||
ret = test_genkey(kl, message, kl / 8, verbose);
|
||||
if (ret) {
|
||||
fprintf(stderr, "Crypto generate key[%d] test: failed\n", kl);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -34,73 +34,73 @@
|
|||
#include "emv/emv_roca.h"
|
||||
|
||||
int ExecuteCryptoTests(bool verbose) {
|
||||
int res;
|
||||
bool TestFail = false;
|
||||
int res;
|
||||
bool TestFail = false;
|
||||
|
||||
res = mbedtls_mpi_self_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
res = mbedtls_mpi_self_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
|
||||
res = mbedtls_aes_self_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
res = mbedtls_aes_self_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
|
||||
res = mbedtls_des_self_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
res = mbedtls_des_self_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
|
||||
res = mbedtls_sha1_self_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
res = mbedtls_sha1_self_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
|
||||
res = mbedtls_md5_self_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
res = mbedtls_md5_self_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
|
||||
res = mbedtls_rsa_self_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
res = mbedtls_rsa_self_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
|
||||
res = mbedtls_entropy_self_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
res = mbedtls_entropy_self_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
|
||||
res = mbedtls_timing_self_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
res = mbedtls_timing_self_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
|
||||
res = mbedtls_ctr_drbg_self_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
res = mbedtls_ctr_drbg_self_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
|
||||
res = mbedtls_base64_self_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
res = mbedtls_base64_self_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
|
||||
res = mbedtls_cmac_self_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
res = mbedtls_cmac_self_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
|
||||
res = ecdsa_nist_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
res = ecdsa_nist_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
|
||||
res = mbedtls_ecp_self_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
res = mbedtls_ecp_self_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
|
||||
res = mbedtls_x509_self_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
res = mbedtls_x509_self_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
|
||||
res = exec_sda_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
res = exec_sda_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
|
||||
res = exec_dda_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
res = exec_dda_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
|
||||
res = exec_cda_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
res = exec_cda_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
|
||||
res = exec_crypto_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
res = exec_crypto_test(verbose);
|
||||
if (res) TestFail = true;
|
||||
|
||||
res = roca_self_test();
|
||||
if (res) TestFail = true;
|
||||
res = roca_self_test();
|
||||
if (res) TestFail = true;
|
||||
|
||||
PrintAndLog("\n--------------------------");
|
||||
PrintAndLog("\n--------------------------");
|
||||
|
||||
if (TestFail)
|
||||
PrintAndLogEx(FAILED, "\tTest(s) [ %s ]", _RED_(FAIL) );
|
||||
else
|
||||
PrintAndLogEx(SUCCESS, "\tTest(s) [ %s ]", _GREEN_(OK) );
|
||||
if (TestFail)
|
||||
PrintAndLogEx(FAILED, "\tTest(s) [ %s ]", _RED_(FAIL) );
|
||||
else
|
||||
PrintAndLogEx(SUCCESS, "\tTest(s) [ %s ]", _GREEN_(OK) );
|
||||
|
||||
return TestFail;
|
||||
return TestFail;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,361 +30,361 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
struct emv_pk mchip_05 = {
|
||||
.rid = { 0xa0, 0x00, 0x00, 0x00, 0x04, },
|
||||
.index = 5,
|
||||
.hash_algo = HASH_SHA_1,
|
||||
.pk_algo = PK_RSA,
|
||||
.hash = {
|
||||
0xeb, 0xfa, 0x0d, 0x5d,
|
||||
0x06, 0xd8, 0xce, 0x70,
|
||||
0x2d, 0xa3, 0xea, 0xe8,
|
||||
0x90, 0x70, 0x1d, 0x45,
|
||||
0xe2, 0x74, 0xc8, 0x45, },
|
||||
.exp = { 0x03, },
|
||||
.elen = 1,
|
||||
.mlen = 1408 / 8,
|
||||
.modulus = (unsigned char[]){
|
||||
0xb8, 0x04, 0x8a, 0xbc, 0x30, 0xc9, 0x0d, 0x97, 0x63, 0x36, 0x54, 0x3e, 0x3f, 0xd7, 0x09, 0x1c,
|
||||
0x8f, 0xe4, 0x80, 0x0d, 0xf8, 0x20, 0xed, 0x55, 0xe7, 0xe9, 0x48, 0x13, 0xed, 0x00, 0x55, 0x5b,
|
||||
0x57, 0x3f, 0xec, 0xa3, 0xd8, 0x4a, 0xf6, 0x13, 0x1a, 0x65, 0x1d, 0x66, 0xcf, 0xf4, 0x28, 0x4f,
|
||||
0xb1, 0x3b, 0x63, 0x5e, 0xdd, 0x0e, 0xe4, 0x01, 0x76, 0xd8, 0xbf, 0x04, 0xb7, 0xfd, 0x1c, 0x7b,
|
||||
0xac, 0xf9, 0xac, 0x73, 0x27, 0xdf, 0xaa, 0x8a, 0xa7, 0x2d, 0x10, 0xdb, 0x3b, 0x8e, 0x70, 0xb2,
|
||||
0xdd, 0xd8, 0x11, 0xcb, 0x41, 0x96, 0x52, 0x5e, 0xa3, 0x86, 0xac, 0xc3, 0x3c, 0x0d, 0x9d, 0x45,
|
||||
0x75, 0x91, 0x64, 0x69, 0xc4, 0xe4, 0xf5, 0x3e, 0x8e, 0x1c, 0x91, 0x2c, 0xc6, 0x18, 0xcb, 0x22,
|
||||
0xdd, 0xe7, 0xc3, 0x56, 0x8e, 0x90, 0x02, 0x2e, 0x6b, 0xba, 0x77, 0x02, 0x02, 0xe4, 0x52, 0x2a,
|
||||
0x2d, 0xd6, 0x23, 0xd1, 0x80, 0xe2, 0x15, 0xbd, 0x1d, 0x15, 0x07, 0xfe, 0x3d, 0xc9, 0x0c, 0xa3,
|
||||
0x10, 0xd2, 0x7b, 0x3e, 0xfc, 0xcd, 0x8f, 0x83, 0xde, 0x30, 0x52, 0xca, 0xd1, 0xe4, 0x89, 0x38,
|
||||
0xc6, 0x8d, 0x09, 0x5a, 0xac, 0x91, 0xb5, 0xf3, 0x7e, 0x28, 0xbb, 0x49, 0xec, 0x7e, 0xd5, 0x97,
|
||||
},
|
||||
.rid = { 0xa0, 0x00, 0x00, 0x00, 0x04, },
|
||||
.index = 5,
|
||||
.hash_algo = HASH_SHA_1,
|
||||
.pk_algo = PK_RSA,
|
||||
.hash = {
|
||||
0xeb, 0xfa, 0x0d, 0x5d,
|
||||
0x06, 0xd8, 0xce, 0x70,
|
||||
0x2d, 0xa3, 0xea, 0xe8,
|
||||
0x90, 0x70, 0x1d, 0x45,
|
||||
0xe2, 0x74, 0xc8, 0x45, },
|
||||
.exp = { 0x03, },
|
||||
.elen = 1,
|
||||
.mlen = 1408 / 8,
|
||||
.modulus = (unsigned char[]){
|
||||
0xb8, 0x04, 0x8a, 0xbc, 0x30, 0xc9, 0x0d, 0x97, 0x63, 0x36, 0x54, 0x3e, 0x3f, 0xd7, 0x09, 0x1c,
|
||||
0x8f, 0xe4, 0x80, 0x0d, 0xf8, 0x20, 0xed, 0x55, 0xe7, 0xe9, 0x48, 0x13, 0xed, 0x00, 0x55, 0x5b,
|
||||
0x57, 0x3f, 0xec, 0xa3, 0xd8, 0x4a, 0xf6, 0x13, 0x1a, 0x65, 0x1d, 0x66, 0xcf, 0xf4, 0x28, 0x4f,
|
||||
0xb1, 0x3b, 0x63, 0x5e, 0xdd, 0x0e, 0xe4, 0x01, 0x76, 0xd8, 0xbf, 0x04, 0xb7, 0xfd, 0x1c, 0x7b,
|
||||
0xac, 0xf9, 0xac, 0x73, 0x27, 0xdf, 0xaa, 0x8a, 0xa7, 0x2d, 0x10, 0xdb, 0x3b, 0x8e, 0x70, 0xb2,
|
||||
0xdd, 0xd8, 0x11, 0xcb, 0x41, 0x96, 0x52, 0x5e, 0xa3, 0x86, 0xac, 0xc3, 0x3c, 0x0d, 0x9d, 0x45,
|
||||
0x75, 0x91, 0x64, 0x69, 0xc4, 0xe4, 0xf5, 0x3e, 0x8e, 0x1c, 0x91, 0x2c, 0xc6, 0x18, 0xcb, 0x22,
|
||||
0xdd, 0xe7, 0xc3, 0x56, 0x8e, 0x90, 0x02, 0x2e, 0x6b, 0xba, 0x77, 0x02, 0x02, 0xe4, 0x52, 0x2a,
|
||||
0x2d, 0xd6, 0x23, 0xd1, 0x80, 0xe2, 0x15, 0xbd, 0x1d, 0x15, 0x07, 0xfe, 0x3d, 0xc9, 0x0c, 0xa3,
|
||||
0x10, 0xd2, 0x7b, 0x3e, 0xfc, 0xcd, 0x8f, 0x83, 0xde, 0x30, 0x52, 0xca, 0xd1, 0xe4, 0x89, 0x38,
|
||||
0xc6, 0x8d, 0x09, 0x5a, 0xac, 0x91, 0xb5, 0xf3, 0x7e, 0x28, 0xbb, 0x49, 0xec, 0x7e, 0xd5, 0x97,
|
||||
},
|
||||
};
|
||||
|
||||
const unsigned char d_issuer_cert[] = {
|
||||
0x17, 0x14, 0x28, 0x4f, 0x76, 0x3b, 0x85, 0x86, 0xee, 0x6d, 0x31, 0x99, 0x51, 0xf7, 0xe6, 0x3f,
|
||||
0xa2, 0x50, 0x76, 0xe5, 0x0d, 0xc9, 0xd3, 0x20, 0x0b, 0xa9, 0x98, 0xd3, 0xa0, 0x52, 0xad, 0xba,
|
||||
0x9a, 0xb6, 0x9a, 0xc6, 0xad, 0x6a, 0xdd, 0x3c, 0xe0, 0x9f, 0x02, 0x78, 0xf4, 0x07, 0x4e, 0xc4,
|
||||
0xee, 0x9b, 0x1d, 0x22, 0x68, 0xa3, 0xe9, 0x53, 0x57, 0x5e, 0x45, 0x4e, 0x50, 0xcd, 0x86, 0x0b,
|
||||
0xf4, 0x24, 0xc5, 0x1c, 0x59, 0x77, 0x12, 0xd2, 0xaa, 0x05, 0x70, 0x89, 0xdd, 0x86, 0x73, 0xe5,
|
||||
0x1b, 0x1e, 0x1d, 0x71, 0x88, 0x03, 0x48, 0x92, 0x07, 0x7a, 0xc1, 0x8a, 0x6a, 0xe2, 0x34, 0x88,
|
||||
0xbe, 0xa9, 0xdf, 0x3b, 0x1a, 0x83, 0xf2, 0xc0, 0x80, 0x0c, 0xd7, 0xc5, 0xcd, 0xf2, 0xfd, 0xe0,
|
||||
0x49, 0x6f, 0x7b, 0xc3, 0x9f, 0xb4, 0xbf, 0x36, 0x32, 0x99, 0xbf, 0xa6, 0x37, 0xb2, 0xec, 0x33,
|
||||
0xc5, 0x07, 0xe3, 0x68, 0x21, 0xee, 0xc2, 0x07, 0x5f, 0x0e, 0x42, 0x0d, 0x38, 0xa1, 0xc9, 0xf3,
|
||||
0x12, 0x72, 0x61, 0xba, 0x31, 0x6c, 0x98, 0x76, 0x74, 0xfa, 0xdb, 0x20, 0xea, 0x7f, 0xeb, 0x75,
|
||||
0xee, 0x45, 0x5d, 0x12, 0x14, 0x6e, 0xa6, 0xf0, 0x2e, 0x8b, 0x01, 0xec, 0x2f, 0xa7, 0xa1, 0x15,
|
||||
0x17, 0x14, 0x28, 0x4f, 0x76, 0x3b, 0x85, 0x86, 0xee, 0x6d, 0x31, 0x99, 0x51, 0xf7, 0xe6, 0x3f,
|
||||
0xa2, 0x50, 0x76, 0xe5, 0x0d, 0xc9, 0xd3, 0x20, 0x0b, 0xa9, 0x98, 0xd3, 0xa0, 0x52, 0xad, 0xba,
|
||||
0x9a, 0xb6, 0x9a, 0xc6, 0xad, 0x6a, 0xdd, 0x3c, 0xe0, 0x9f, 0x02, 0x78, 0xf4, 0x07, 0x4e, 0xc4,
|
||||
0xee, 0x9b, 0x1d, 0x22, 0x68, 0xa3, 0xe9, 0x53, 0x57, 0x5e, 0x45, 0x4e, 0x50, 0xcd, 0x86, 0x0b,
|
||||
0xf4, 0x24, 0xc5, 0x1c, 0x59, 0x77, 0x12, 0xd2, 0xaa, 0x05, 0x70, 0x89, 0xdd, 0x86, 0x73, 0xe5,
|
||||
0x1b, 0x1e, 0x1d, 0x71, 0x88, 0x03, 0x48, 0x92, 0x07, 0x7a, 0xc1, 0x8a, 0x6a, 0xe2, 0x34, 0x88,
|
||||
0xbe, 0xa9, 0xdf, 0x3b, 0x1a, 0x83, 0xf2, 0xc0, 0x80, 0x0c, 0xd7, 0xc5, 0xcd, 0xf2, 0xfd, 0xe0,
|
||||
0x49, 0x6f, 0x7b, 0xc3, 0x9f, 0xb4, 0xbf, 0x36, 0x32, 0x99, 0xbf, 0xa6, 0x37, 0xb2, 0xec, 0x33,
|
||||
0xc5, 0x07, 0xe3, 0x68, 0x21, 0xee, 0xc2, 0x07, 0x5f, 0x0e, 0x42, 0x0d, 0x38, 0xa1, 0xc9, 0xf3,
|
||||
0x12, 0x72, 0x61, 0xba, 0x31, 0x6c, 0x98, 0x76, 0x74, 0xfa, 0xdb, 0x20, 0xea, 0x7f, 0xeb, 0x75,
|
||||
0xee, 0x45, 0x5d, 0x12, 0x14, 0x6e, 0xa6, 0xf0, 0x2e, 0x8b, 0x01, 0xec, 0x2f, 0xa7, 0xa1, 0x15,
|
||||
};
|
||||
|
||||
const unsigned char d_issuer_rem[] = {
|
||||
0x6e, 0x63, 0xb7, 0xbc, 0x70, 0xab, 0xdd, 0x09, 0x34, 0x1b, 0x34, 0xc0, 0x32, 0x86, 0xba, 0x9b,
|
||||
0xd8, 0x3b, 0xa7, 0x93, 0x6c, 0x5b, 0x77, 0x98, 0xfb, 0x22, 0xc5, 0xe5, 0x3f, 0xf2, 0x40, 0xa2,
|
||||
0x6d, 0xbd, 0x64, 0x15,
|
||||
0x6e, 0x63, 0xb7, 0xbc, 0x70, 0xab, 0xdd, 0x09, 0x34, 0x1b, 0x34, 0xc0, 0x32, 0x86, 0xba, 0x9b,
|
||||
0xd8, 0x3b, 0xa7, 0x93, 0x6c, 0x5b, 0x77, 0x98, 0xfb, 0x22, 0xc5, 0xe5, 0x3f, 0xf2, 0x40, 0xa2,
|
||||
0x6d, 0xbd, 0x64, 0x15,
|
||||
};
|
||||
|
||||
const unsigned char d_issuer_exp[] = {
|
||||
0x03,
|
||||
0x03,
|
||||
};
|
||||
|
||||
const unsigned char d_icc_cert[] = {
|
||||
0xa4, 0x2f, 0xbe, 0xb1, 0x56, 0xb9, 0x8d, 0xcb, 0x05, 0x54, 0xda, 0x06, 0x2a, 0xdc, 0xa5, 0x30,
|
||||
0x9a, 0x91, 0xf0, 0x4f, 0xa2, 0xc7, 0xbd, 0x71, 0x02, 0xa8, 0xd7, 0x3f, 0x16, 0xa3, 0xcf, 0xad,
|
||||
0xe8, 0xaa, 0xdf, 0x4f, 0x3f, 0xe2, 0xa2, 0x12, 0x5c, 0xcd, 0xd7, 0x7c, 0x6b, 0x9f, 0x78, 0xb5,
|
||||
0xb4, 0x37, 0x1c, 0xe0, 0x80, 0x57, 0x25, 0xb0, 0xf9, 0xc0, 0x27, 0xaf, 0x14, 0x7d, 0x91, 0xe1,
|
||||
0xff, 0xdb, 0x20, 0x1e, 0x9c, 0x17, 0x0c, 0xe7, 0x77, 0x05, 0x3a, 0x17, 0x2a, 0xd5, 0x26, 0xdc,
|
||||
0xaf, 0xd3, 0x38, 0x95, 0xe1, 0xa9, 0x47, 0x30, 0x5c, 0x5b, 0x16, 0x7f, 0x2e, 0x7c, 0x6f, 0x99,
|
||||
0x15, 0x81, 0xa6, 0x52, 0xee, 0x47, 0x31, 0x54, 0x76, 0x0c, 0x2e, 0xd7, 0x74, 0x21, 0x4e, 0x50,
|
||||
0xdf, 0xec, 0xdd, 0x4c, 0xf2, 0x94, 0xc9, 0x74, 0xb8, 0x9e, 0xbc, 0xa2, 0x5b, 0x5a, 0xb3, 0xc0,
|
||||
0xbe, 0xb5, 0x0d, 0xfa, 0xf7, 0x82, 0xaf, 0xde, 0x14, 0x33, 0xd9, 0x0c, 0xa2, 0xa8, 0x9d, 0x65,
|
||||
0x1e, 0x75, 0xd6, 0x7e, 0xbc, 0x7c, 0x3e, 0x36, 0xf5, 0xa1, 0x65, 0xee, 0x61, 0x32, 0x61, 0x29,
|
||||
0x39, 0xc1, 0xec, 0xd3, 0x99, 0xe4, 0x60, 0x74, 0xb9, 0x96, 0xd9, 0x3a, 0x88, 0xe0, 0x1e, 0x0a,
|
||||
0xa4, 0x2f, 0xbe, 0xb1, 0x56, 0xb9, 0x8d, 0xcb, 0x05, 0x54, 0xda, 0x06, 0x2a, 0xdc, 0xa5, 0x30,
|
||||
0x9a, 0x91, 0xf0, 0x4f, 0xa2, 0xc7, 0xbd, 0x71, 0x02, 0xa8, 0xd7, 0x3f, 0x16, 0xa3, 0xcf, 0xad,
|
||||
0xe8, 0xaa, 0xdf, 0x4f, 0x3f, 0xe2, 0xa2, 0x12, 0x5c, 0xcd, 0xd7, 0x7c, 0x6b, 0x9f, 0x78, 0xb5,
|
||||
0xb4, 0x37, 0x1c, 0xe0, 0x80, 0x57, 0x25, 0xb0, 0xf9, 0xc0, 0x27, 0xaf, 0x14, 0x7d, 0x91, 0xe1,
|
||||
0xff, 0xdb, 0x20, 0x1e, 0x9c, 0x17, 0x0c, 0xe7, 0x77, 0x05, 0x3a, 0x17, 0x2a, 0xd5, 0x26, 0xdc,
|
||||
0xaf, 0xd3, 0x38, 0x95, 0xe1, 0xa9, 0x47, 0x30, 0x5c, 0x5b, 0x16, 0x7f, 0x2e, 0x7c, 0x6f, 0x99,
|
||||
0x15, 0x81, 0xa6, 0x52, 0xee, 0x47, 0x31, 0x54, 0x76, 0x0c, 0x2e, 0xd7, 0x74, 0x21, 0x4e, 0x50,
|
||||
0xdf, 0xec, 0xdd, 0x4c, 0xf2, 0x94, 0xc9, 0x74, 0xb8, 0x9e, 0xbc, 0xa2, 0x5b, 0x5a, 0xb3, 0xc0,
|
||||
0xbe, 0xb5, 0x0d, 0xfa, 0xf7, 0x82, 0xaf, 0xde, 0x14, 0x33, 0xd9, 0x0c, 0xa2, 0xa8, 0x9d, 0x65,
|
||||
0x1e, 0x75, 0xd6, 0x7e, 0xbc, 0x7c, 0x3e, 0x36, 0xf5, 0xa1, 0x65, 0xee, 0x61, 0x32, 0x61, 0x29,
|
||||
0x39, 0xc1, 0xec, 0xd3, 0x99, 0xe4, 0x60, 0x74, 0xb9, 0x96, 0xd9, 0x3a, 0x88, 0xe0, 0x1e, 0x0a,
|
||||
};
|
||||
|
||||
const unsigned char d_icc_exp[] = {
|
||||
0x03,
|
||||
0x03,
|
||||
};
|
||||
|
||||
const unsigned char d_sdad_cr[] = {
|
||||
0x3d, 0x87, 0xf3, 0x10, 0x56, 0x10, 0x2d, 0x25, 0x12, 0xcf, 0xde, 0x30, 0x90, 0x06, 0x27, 0xc1,
|
||||
0x26, 0x3a, 0x76, 0xd1, 0xda, 0xa8, 0x21, 0xf5, 0x08, 0x31, 0xe6, 0x06, 0xc5, 0x45, 0x44, 0xc2,
|
||||
0x58, 0x13, 0x1e, 0xae, 0xbe, 0x87, 0x4d, 0xcb, 0x1a, 0x28, 0xcf, 0x82, 0xd3, 0xff, 0x91, 0x11,
|
||||
0x82, 0x60, 0xbc, 0x91, 0x11, 0x37, 0x11, 0xd3, 0xb2, 0x89, 0xfa, 0x41, 0xbe, 0x69, 0xc7, 0xa7,
|
||||
0xb5, 0xc7, 0x83, 0xe6, 0xf8, 0xf9, 0x7f, 0xce, 0x13, 0xf0, 0x8b, 0x13, 0xfa, 0x44, 0x18, 0x3e,
|
||||
0x37, 0x18, 0xce, 0xbf, 0x0c, 0x41, 0x47, 0x3d, 0x2b, 0x0f, 0xf4, 0xde, 0x44, 0xb6, 0xa0, 0x2d,
|
||||
0x75, 0xad, 0xb6, 0xd4, 0x96, 0x23, 0x93, 0xff, 0xdf, 0x4e, 0x69, 0x02, 0x6c, 0xdf, 0x38, 0xff,
|
||||
0x3d, 0x87, 0xf3, 0x10, 0x56, 0x10, 0x2d, 0x25, 0x12, 0xcf, 0xde, 0x30, 0x90, 0x06, 0x27, 0xc1,
|
||||
0x26, 0x3a, 0x76, 0xd1, 0xda, 0xa8, 0x21, 0xf5, 0x08, 0x31, 0xe6, 0x06, 0xc5, 0x45, 0x44, 0xc2,
|
||||
0x58, 0x13, 0x1e, 0xae, 0xbe, 0x87, 0x4d, 0xcb, 0x1a, 0x28, 0xcf, 0x82, 0xd3, 0xff, 0x91, 0x11,
|
||||
0x82, 0x60, 0xbc, 0x91, 0x11, 0x37, 0x11, 0xd3, 0xb2, 0x89, 0xfa, 0x41, 0xbe, 0x69, 0xc7, 0xa7,
|
||||
0xb5, 0xc7, 0x83, 0xe6, 0xf8, 0xf9, 0x7f, 0xce, 0x13, 0xf0, 0x8b, 0x13, 0xfa, 0x44, 0x18, 0x3e,
|
||||
0x37, 0x18, 0xce, 0xbf, 0x0c, 0x41, 0x47, 0x3d, 0x2b, 0x0f, 0xf4, 0xde, 0x44, 0xb6, 0xa0, 0x2d,
|
||||
0x75, 0xad, 0xb6, 0xd4, 0x96, 0x23, 0x93, 0xff, 0xdf, 0x4e, 0x69, 0x02, 0x6c, 0xdf, 0x38, 0xff,
|
||||
};
|
||||
|
||||
const unsigned char d_ssd1[] = {
|
||||
0x5f, 0x25, 0x03, 0x14, 0x05, 0x01, 0x5f, 0x24, 0x03, 0x15, 0x06, 0x30, 0x5a, 0x08, 0x52, 0x85,
|
||||
0x88, 0x12, 0x54, 0x34, 0x56, 0x53, 0x5f, 0x34, 0x01, 0x01, 0x8e, 0x0c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x1e, 0x03, 0x1f, 0x03, 0x9f, 0x07, 0x02, 0xff, 0x00, 0x9f, 0x0d, 0x05,
|
||||
0xbc, 0x50, 0xbc, 0x00, 0x00, 0x9f, 0x0e, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x0f, 0x05,
|
||||
0xbc, 0x70, 0xbc, 0x98, 0x00, 0x9f, 0x4a, 0x01, 0x82, 0x5f, 0x28, 0x02, 0x06, 0x43, 0x8c, 0x21,
|
||||
0x9f, 0x02, 0x06, 0x9f, 0x03, 0x06, 0x9f, 0x1a, 0x02, 0x95, 0x05, 0x5f, 0x2a, 0x02, 0x9a, 0x03,
|
||||
0x9c, 0x01, 0x9f, 0x37, 0x04, 0x9f, 0x35, 0x01, 0x9f, 0x45, 0x02, 0x9f, 0x4c, 0x08, 0x9f, 0x34,
|
||||
0x03, 0x8d, 0x0c, 0x91, 0x0a, 0x8a, 0x02, 0x95, 0x05, 0x9f, 0x37, 0x04, 0x9f, 0x4c, 0x08,
|
||||
0x39, 0x00,
|
||||
0x5f, 0x25, 0x03, 0x14, 0x05, 0x01, 0x5f, 0x24, 0x03, 0x15, 0x06, 0x30, 0x5a, 0x08, 0x52, 0x85,
|
||||
0x88, 0x12, 0x54, 0x34, 0x56, 0x53, 0x5f, 0x34, 0x01, 0x01, 0x8e, 0x0c, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x1e, 0x03, 0x1f, 0x03, 0x9f, 0x07, 0x02, 0xff, 0x00, 0x9f, 0x0d, 0x05,
|
||||
0xbc, 0x50, 0xbc, 0x00, 0x00, 0x9f, 0x0e, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x0f, 0x05,
|
||||
0xbc, 0x70, 0xbc, 0x98, 0x00, 0x9f, 0x4a, 0x01, 0x82, 0x5f, 0x28, 0x02, 0x06, 0x43, 0x8c, 0x21,
|
||||
0x9f, 0x02, 0x06, 0x9f, 0x03, 0x06, 0x9f, 0x1a, 0x02, 0x95, 0x05, 0x5f, 0x2a, 0x02, 0x9a, 0x03,
|
||||
0x9c, 0x01, 0x9f, 0x37, 0x04, 0x9f, 0x35, 0x01, 0x9f, 0x45, 0x02, 0x9f, 0x4c, 0x08, 0x9f, 0x34,
|
||||
0x03, 0x8d, 0x0c, 0x91, 0x0a, 0x8a, 0x02, 0x95, 0x05, 0x9f, 0x37, 0x04, 0x9f, 0x4c, 0x08,
|
||||
0x39, 0x00,
|
||||
};
|
||||
static const struct tlv ssd1_tlv = {
|
||||
.len = sizeof(d_ssd1),
|
||||
.value = d_ssd1,
|
||||
.len = sizeof(d_ssd1),
|
||||
.value = d_ssd1,
|
||||
};
|
||||
|
||||
const unsigned char d_pan[] = {
|
||||
0x52, 0x85, 0x88, 0x12, 0x54, 0x34, 0x56, 0x53,
|
||||
0x52, 0x85, 0x88, 0x12, 0x54, 0x34, 0x56, 0x53,
|
||||
};
|
||||
|
||||
const unsigned char d_dd1[] = {
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
static const struct tlv dd1_tlv = {
|
||||
.len = sizeof(d_dd1),
|
||||
.value = d_dd1,
|
||||
.len = sizeof(d_dd1),
|
||||
.value = d_dd1,
|
||||
};
|
||||
|
||||
static int dda_test_raw(bool verbose)
|
||||
{
|
||||
const struct emv_pk *pk = &mchip_05;
|
||||
const struct emv_pk *pk = &mchip_05;
|
||||
|
||||
struct crypto_pk *kcp = crypto_pk_open(PK_RSA,
|
||||
pk->modulus, pk->mlen,
|
||||
pk->exp, pk->elen);
|
||||
if (!kcp)
|
||||
return 1;
|
||||
struct crypto_pk *kcp = crypto_pk_open(PK_RSA,
|
||||
pk->modulus, pk->mlen,
|
||||
pk->exp, pk->elen);
|
||||
if (!kcp)
|
||||
return 1;
|
||||
|
||||
unsigned char *ipk_data;
|
||||
size_t ipk_data_len;
|
||||
ipk_data = crypto_pk_encrypt(kcp, d_issuer_cert, sizeof(d_issuer_cert), &ipk_data_len);
|
||||
crypto_pk_close(kcp);
|
||||
unsigned char *ipk_data;
|
||||
size_t ipk_data_len;
|
||||
ipk_data = crypto_pk_encrypt(kcp, d_issuer_cert, sizeof(d_issuer_cert), &ipk_data_len);
|
||||
crypto_pk_close(kcp);
|
||||
|
||||
if (!ipk_data)
|
||||
return 1;
|
||||
if (!ipk_data)
|
||||
return 1;
|
||||
|
||||
if (verbose) {
|
||||
printf("issuer cert:\n");
|
||||
dump_buffer(ipk_data, ipk_data_len, stdout, 0);
|
||||
}
|
||||
if (verbose) {
|
||||
printf("issuer cert:\n");
|
||||
dump_buffer(ipk_data, ipk_data_len, stdout, 0);
|
||||
}
|
||||
|
||||
size_t ipk_pk_len = ipk_data[13];
|
||||
unsigned char *ipk_pk = malloc(ipk_pk_len);
|
||||
memcpy(ipk_pk, ipk_data + 15, ipk_data_len - 36);
|
||||
memcpy(ipk_pk + ipk_data_len - 36, d_issuer_rem, sizeof(d_issuer_rem));
|
||||
size_t ipk_pk_len = ipk_data[13];
|
||||
unsigned char *ipk_pk = malloc(ipk_pk_len);
|
||||
memcpy(ipk_pk, ipk_data + 15, ipk_data_len - 36);
|
||||
memcpy(ipk_pk + ipk_data_len - 36, d_issuer_rem, sizeof(d_issuer_rem));
|
||||
|
||||
struct crypto_hash *ch;
|
||||
ch = crypto_hash_open(HASH_SHA_1);
|
||||
if (!ch) {
|
||||
free(ipk_pk);
|
||||
free(ipk_data);
|
||||
return 1;
|
||||
}
|
||||
struct crypto_hash *ch;
|
||||
ch = crypto_hash_open(HASH_SHA_1);
|
||||
if (!ch) {
|
||||
free(ipk_pk);
|
||||
free(ipk_data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
crypto_hash_write(ch, ipk_data + 1, 14);
|
||||
crypto_hash_write(ch, ipk_pk, ipk_pk_len);
|
||||
crypto_hash_write(ch, d_issuer_exp, sizeof(d_issuer_exp));
|
||||
crypto_hash_write(ch, ipk_data + 1, 14);
|
||||
crypto_hash_write(ch, ipk_pk, ipk_pk_len);
|
||||
crypto_hash_write(ch, d_issuer_exp, sizeof(d_issuer_exp));
|
||||
|
||||
unsigned char *h = crypto_hash_read(ch);
|
||||
if (!h) {
|
||||
crypto_hash_close(ch);
|
||||
free(ipk_pk);
|
||||
free(ipk_data);
|
||||
return 1;
|
||||
}
|
||||
unsigned char *h = crypto_hash_read(ch);
|
||||
if (!h) {
|
||||
crypto_hash_close(ch);
|
||||
free(ipk_pk);
|
||||
free(ipk_data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
printf("crypto hash:\n");
|
||||
dump_buffer(h, 20, stdout, 0);
|
||||
}
|
||||
if (verbose) {
|
||||
printf("crypto hash:\n");
|
||||
dump_buffer(h, 20, stdout, 0);
|
||||
}
|
||||
|
||||
if (memcmp(ipk_data + ipk_data_len - 21, h, 20)) {
|
||||
crypto_hash_close(ch);
|
||||
free(ipk_pk);
|
||||
free(ipk_data);
|
||||
return 1;
|
||||
}
|
||||
if (memcmp(ipk_data + ipk_data_len - 21, h, 20)) {
|
||||
crypto_hash_close(ch);
|
||||
free(ipk_pk);
|
||||
free(ipk_data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
crypto_hash_close(ch);
|
||||
free(ipk_data);
|
||||
crypto_hash_close(ch);
|
||||
free(ipk_data);
|
||||
|
||||
struct crypto_pk *ikcp = crypto_pk_open(PK_RSA, ipk_pk, (int) ipk_pk_len,
|
||||
d_issuer_exp, (int) sizeof(d_issuer_exp));
|
||||
free(ipk_pk);
|
||||
if (!ikcp)
|
||||
return 1;
|
||||
struct crypto_pk *ikcp = crypto_pk_open(PK_RSA, ipk_pk, (int) ipk_pk_len,
|
||||
d_issuer_exp, (int) sizeof(d_issuer_exp));
|
||||
free(ipk_pk);
|
||||
if (!ikcp)
|
||||
return 1;
|
||||
|
||||
unsigned char *iccpk_data;
|
||||
size_t iccpk_data_len;
|
||||
iccpk_data = crypto_pk_encrypt(ikcp, d_icc_cert, sizeof(d_icc_cert), &iccpk_data_len);
|
||||
crypto_pk_close(ikcp);
|
||||
unsigned char *iccpk_data;
|
||||
size_t iccpk_data_len;
|
||||
iccpk_data = crypto_pk_encrypt(ikcp, d_icc_cert, sizeof(d_icc_cert), &iccpk_data_len);
|
||||
crypto_pk_close(ikcp);
|
||||
|
||||
if (!iccpk_data)
|
||||
return 1;
|
||||
if (!iccpk_data)
|
||||
return 1;
|
||||
|
||||
if (verbose) {
|
||||
printf("icc cert:\n");
|
||||
dump_buffer(iccpk_data, iccpk_data_len, stdout, 0);
|
||||
}
|
||||
if (verbose) {
|
||||
printf("icc cert:\n");
|
||||
dump_buffer(iccpk_data, iccpk_data_len, stdout, 0);
|
||||
}
|
||||
|
||||
size_t iccpk_pk_len = iccpk_data[19];
|
||||
unsigned char *iccpk_pk = malloc(iccpk_pk_len);
|
||||
memcpy(iccpk_pk, iccpk_data + 21, /*iccpk_data_len - 36*/iccpk_pk_len);
|
||||
/*memcpy(iccpk_pk + iccpk_data_len - 36, icc_rem, sizeof(icc_rem));*/
|
||||
size_t iccpk_pk_len = iccpk_data[19];
|
||||
unsigned char *iccpk_pk = malloc(iccpk_pk_len);
|
||||
memcpy(iccpk_pk, iccpk_data + 21, /*iccpk_data_len - 36*/iccpk_pk_len);
|
||||
/*memcpy(iccpk_pk + iccpk_data_len - 36, icc_rem, sizeof(icc_rem));*/
|
||||
|
||||
ch = crypto_hash_open(HASH_SHA_1);
|
||||
if (!ch) {
|
||||
free(iccpk_pk);
|
||||
free(iccpk_data);
|
||||
return 1;
|
||||
}
|
||||
ch = crypto_hash_open(HASH_SHA_1);
|
||||
if (!ch) {
|
||||
free(iccpk_pk);
|
||||
free(iccpk_data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
crypto_hash_write(ch, iccpk_data + 1, iccpk_data_len - 22);
|
||||
crypto_hash_write(ch, d_icc_exp, sizeof(d_icc_exp));
|
||||
crypto_hash_write(ch, d_ssd1, sizeof(d_ssd1));
|
||||
crypto_hash_write(ch, iccpk_data + 1, iccpk_data_len - 22);
|
||||
crypto_hash_write(ch, d_icc_exp, sizeof(d_icc_exp));
|
||||
crypto_hash_write(ch, d_ssd1, sizeof(d_ssd1));
|
||||
|
||||
h = crypto_hash_read(ch);
|
||||
if (!h) {
|
||||
crypto_hash_close(ch);
|
||||
free(iccpk_pk);
|
||||
free(iccpk_data);
|
||||
return 1;
|
||||
}
|
||||
h = crypto_hash_read(ch);
|
||||
if (!h) {
|
||||
crypto_hash_close(ch);
|
||||
free(iccpk_pk);
|
||||
free(iccpk_data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
printf("crypto hash1.1:\n");
|
||||
dump_buffer(h, 20, stdout, 0);
|
||||
}
|
||||
if (verbose) {
|
||||
printf("crypto hash1.1:\n");
|
||||
dump_buffer(h, 20, stdout, 0);
|
||||
}
|
||||
|
||||
if (memcmp(iccpk_data + iccpk_data_len - 21, h, 20)) {
|
||||
crypto_hash_close(ch);
|
||||
free(iccpk_pk);
|
||||
free(iccpk_data);
|
||||
return 1;
|
||||
}
|
||||
if (memcmp(iccpk_data + iccpk_data_len - 21, h, 20)) {
|
||||
crypto_hash_close(ch);
|
||||
free(iccpk_pk);
|
||||
free(iccpk_data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
crypto_hash_close(ch);
|
||||
free(iccpk_data);
|
||||
crypto_hash_close(ch);
|
||||
free(iccpk_data);
|
||||
|
||||
struct crypto_pk *icckcp = crypto_pk_open(PK_RSA, iccpk_pk, (int) iccpk_pk_len,
|
||||
d_issuer_exp, (int) sizeof(d_issuer_exp));
|
||||
free(iccpk_pk);
|
||||
if (!icckcp)
|
||||
return 1;
|
||||
struct crypto_pk *icckcp = crypto_pk_open(PK_RSA, iccpk_pk, (int) iccpk_pk_len,
|
||||
d_issuer_exp, (int) sizeof(d_issuer_exp));
|
||||
free(iccpk_pk);
|
||||
if (!icckcp)
|
||||
return 1;
|
||||
|
||||
size_t sdad_len;
|
||||
unsigned char *sdad = crypto_pk_encrypt(icckcp, d_sdad_cr, sizeof(d_sdad_cr), &sdad_len);
|
||||
crypto_pk_close(icckcp);
|
||||
if (!sdad)
|
||||
return 1;
|
||||
size_t sdad_len;
|
||||
unsigned char *sdad = crypto_pk_encrypt(icckcp, d_sdad_cr, sizeof(d_sdad_cr), &sdad_len);
|
||||
crypto_pk_close(icckcp);
|
||||
if (!sdad)
|
||||
return 1;
|
||||
|
||||
if (verbose) {
|
||||
printf("sdad:\n");
|
||||
dump_buffer(sdad, sdad_len, stdout, 0);
|
||||
}
|
||||
if (verbose) {
|
||||
printf("sdad:\n");
|
||||
dump_buffer(sdad, sdad_len, stdout, 0);
|
||||
}
|
||||
|
||||
ch = crypto_hash_open(HASH_SHA_1);
|
||||
if (!ch) {
|
||||
free(sdad);
|
||||
return 1;
|
||||
}
|
||||
ch = crypto_hash_open(HASH_SHA_1);
|
||||
if (!ch) {
|
||||
free(sdad);
|
||||
return 1;
|
||||
}
|
||||
|
||||
crypto_hash_write(ch, sdad + 1, sdad_len - 22);
|
||||
crypto_hash_write(ch, d_dd1, sizeof(d_dd1));
|
||||
crypto_hash_write(ch, sdad + 1, sdad_len - 22);
|
||||
crypto_hash_write(ch, d_dd1, sizeof(d_dd1));
|
||||
|
||||
unsigned char *h2 = crypto_hash_read(ch);
|
||||
if (!h2) {
|
||||
crypto_hash_close(ch);
|
||||
free(sdad);
|
||||
return 1;
|
||||
}
|
||||
unsigned char *h2 = crypto_hash_read(ch);
|
||||
if (!h2) {
|
||||
crypto_hash_close(ch);
|
||||
free(sdad);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
printf("crypto hash2:\n");
|
||||
dump_buffer(h2, 20, stdout, 0);
|
||||
}
|
||||
if (verbose) {
|
||||
printf("crypto hash2:\n");
|
||||
dump_buffer(h2, 20, stdout, 0);
|
||||
}
|
||||
|
||||
crypto_hash_close(ch);
|
||||
crypto_hash_close(ch);
|
||||
|
||||
free(sdad);
|
||||
free(sdad);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dda_test_pk(bool verbose)
|
||||
{
|
||||
const struct emv_pk *pk = &mchip_05;
|
||||
struct tlvdb *db;
|
||||
const struct emv_pk *pk = &mchip_05;
|
||||
struct tlvdb *db;
|
||||
|
||||
db = tlvdb_external(0x90, sizeof(d_issuer_cert), d_issuer_cert);
|
||||
tlvdb_add(db, tlvdb_external(0x9f32, sizeof(d_issuer_exp), d_issuer_exp));
|
||||
tlvdb_add(db, tlvdb_external(0x92, sizeof(d_issuer_rem), d_issuer_rem));
|
||||
tlvdb_add(db, tlvdb_external(0x5a, sizeof(d_pan), d_pan));
|
||||
db = tlvdb_external(0x90, sizeof(d_issuer_cert), d_issuer_cert);
|
||||
tlvdb_add(db, tlvdb_external(0x9f32, sizeof(d_issuer_exp), d_issuer_exp));
|
||||
tlvdb_add(db, tlvdb_external(0x92, sizeof(d_issuer_rem), d_issuer_rem));
|
||||
tlvdb_add(db, tlvdb_external(0x5a, sizeof(d_pan), d_pan));
|
||||
|
||||
struct emv_pk *ipk = emv_pki_recover_issuer_cert(pk, db);
|
||||
if (!ipk) {
|
||||
fprintf(stderr, "Could not recover Issuer certificate!\n");
|
||||
tlvdb_free(db);
|
||||
return 2;
|
||||
}
|
||||
struct emv_pk *ipk = emv_pki_recover_issuer_cert(pk, db);
|
||||
if (!ipk) {
|
||||
fprintf(stderr, "Could not recover Issuer certificate!\n");
|
||||
tlvdb_free(db);
|
||||
return 2;
|
||||
}
|
||||
|
||||
tlvdb_add(db, tlvdb_external(0x9f46, sizeof(d_icc_cert), d_icc_cert));
|
||||
tlvdb_add(db, tlvdb_external(0x9f47, sizeof(d_icc_exp), d_icc_exp));
|
||||
/*tlvdb_add(db, tlvdb_external(0x9f48, sizeof(d_issuer_rem), d_issuer_rem));*/
|
||||
tlvdb_add(db, tlvdb_external(0x9f46, sizeof(d_icc_cert), d_icc_cert));
|
||||
tlvdb_add(db, tlvdb_external(0x9f47, sizeof(d_icc_exp), d_icc_exp));
|
||||
/*tlvdb_add(db, tlvdb_external(0x9f48, sizeof(d_issuer_rem), d_issuer_rem));*/
|
||||
|
||||
struct emv_pk *iccpk = emv_pki_recover_icc_cert(ipk, db, &ssd1_tlv);
|
||||
if (!iccpk) {
|
||||
fprintf(stderr, "Could not recover ICC certificate!\n");
|
||||
emv_pk_free(ipk);
|
||||
tlvdb_free(db);
|
||||
return 2;
|
||||
}
|
||||
struct emv_pk *iccpk = emv_pki_recover_icc_cert(ipk, db, &ssd1_tlv);
|
||||
if (!iccpk) {
|
||||
fprintf(stderr, "Could not recover ICC certificate!\n");
|
||||
emv_pk_free(ipk);
|
||||
tlvdb_free(db);
|
||||
return 2;
|
||||
}
|
||||
|
||||
tlvdb_add(db, tlvdb_external(0x9f4b, sizeof(d_sdad_cr), d_sdad_cr));
|
||||
tlvdb_add(db, tlvdb_external(0x9f4b, sizeof(d_sdad_cr), d_sdad_cr));
|
||||
|
||||
struct tlvdb *idndb = emv_pki_recover_idn(iccpk, db, &dd1_tlv);
|
||||
if (!idndb) {
|
||||
fprintf(stderr, "Could not recover IDN!\n");
|
||||
emv_pk_free(iccpk);
|
||||
emv_pk_free(ipk);
|
||||
tlvdb_free(db);
|
||||
return 2;
|
||||
}
|
||||
struct tlvdb *idndb = emv_pki_recover_idn(iccpk, db, &dd1_tlv);
|
||||
if (!idndb) {
|
||||
fprintf(stderr, "Could not recover IDN!\n");
|
||||
emv_pk_free(iccpk);
|
||||
emv_pk_free(ipk);
|
||||
tlvdb_free(db);
|
||||
return 2;
|
||||
}
|
||||
|
||||
const struct tlv *idn = tlvdb_get(idndb, 0x9f4c, NULL);
|
||||
if (!idn) {
|
||||
fprintf(stderr, "IDN not found!\n");
|
||||
tlvdb_free(idndb);
|
||||
emv_pk_free(iccpk);
|
||||
emv_pk_free(ipk);
|
||||
tlvdb_free(db);
|
||||
return 2;
|
||||
}
|
||||
const struct tlv *idn = tlvdb_get(idndb, 0x9f4c, NULL);
|
||||
if (!idn) {
|
||||
fprintf(stderr, "IDN not found!\n");
|
||||
tlvdb_free(idndb);
|
||||
emv_pk_free(iccpk);
|
||||
emv_pk_free(ipk);
|
||||
tlvdb_free(db);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
printf("IDN:\n");
|
||||
dump_buffer(idn->value, idn->len, stdout, 0);
|
||||
}
|
||||
if (verbose) {
|
||||
printf("IDN:\n");
|
||||
dump_buffer(idn->value, idn->len, stdout, 0);
|
||||
}
|
||||
|
||||
tlvdb_free(idndb);
|
||||
emv_pk_free(iccpk);
|
||||
emv_pk_free(ipk);
|
||||
tlvdb_free(db);
|
||||
tlvdb_free(idndb);
|
||||
emv_pk_free(iccpk);
|
||||
emv_pk_free(ipk);
|
||||
tlvdb_free(db);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exec_dda_test(bool verbose)
|
||||
{
|
||||
int ret;
|
||||
fprintf(stdout, "\n");
|
||||
int ret;
|
||||
fprintf(stdout, "\n");
|
||||
|
||||
ret = dda_test_raw(verbose);
|
||||
if (ret) {
|
||||
fprintf(stderr, "DDA raw test: failed\n");
|
||||
return ret;
|
||||
}
|
||||
fprintf(stdout, "DDA raw test: passed\n");
|
||||
ret = dda_test_raw(verbose);
|
||||
if (ret) {
|
||||
fprintf(stderr, "DDA raw test: failed\n");
|
||||
return ret;
|
||||
}
|
||||
fprintf(stdout, "DDA raw test: passed\n");
|
||||
|
||||
ret = dda_test_pk(verbose);
|
||||
if (ret) {
|
||||
fprintf(stderr, "DDA test pk: failed\n");
|
||||
return ret;
|
||||
}
|
||||
fprintf(stdout, "DDA test pk: passed\n");
|
||||
ret = dda_test_pk(verbose);
|
||||
if (ret) {
|
||||
fprintf(stderr, "DDA test pk: failed\n");
|
||||
return ret;
|
||||
}
|
||||
fprintf(stdout, "DDA test pk: passed\n");
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -28,250 +28,250 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
struct emv_pk vsdc_01 = {
|
||||
.rid = { 0xa0, 0x00, 0x00, 0x00, 0x03, },
|
||||
.index = 1,
|
||||
.hash_algo = HASH_SHA_1,
|
||||
.pk_algo = PK_RSA,
|
||||
.hash = {
|
||||
0xd3, 0x4a, 0x6a, 0x77,
|
||||
0x60, 0x11, 0xc7, 0xe7,
|
||||
0xce, 0x3a, 0xec, 0x5f,
|
||||
0x03, 0xad, 0x2f, 0x8c,
|
||||
0xfc, 0x55, 0x03, 0xcc, },
|
||||
.exp = { 0x03, },
|
||||
.elen = 1,
|
||||
.mlen = 1024 / 8,
|
||||
.modulus = (unsigned char[]){
|
||||
0xc6, 0x96, 0x03, 0x42, 0x13, 0xd7, 0xd8, 0x54, 0x69, 0x84, 0x57, 0x9d, 0x1d, 0x0f, 0x0e, 0xa5,
|
||||
0x19, 0xcf, 0xf8, 0xde, 0xff, 0xc4, 0x29, 0x35, 0x4c, 0xf3, 0xa8, 0x71, 0xa6, 0xf7, 0x18, 0x3f,
|
||||
0x12, 0x28, 0xda, 0x5c, 0x74, 0x70, 0xc0, 0x55, 0x38, 0x71, 0x00, 0xcb, 0x93, 0x5a, 0x71, 0x2c,
|
||||
0x4e, 0x28, 0x64, 0xdf, 0x5d, 0x64, 0xba, 0x93, 0xfe, 0x7e, 0x63, 0xe7, 0x1f, 0x25, 0xb1, 0xe5,
|
||||
0xf5, 0x29, 0x85, 0x75, 0xeb, 0xe1, 0xc6, 0x3a, 0xa6, 0x17, 0x70, 0x69, 0x17, 0x91, 0x1d, 0xc2,
|
||||
0xa7, 0x5a, 0xc2, 0x8b, 0x25, 0x1c, 0x7e, 0xf4, 0x0f, 0x23, 0x65, 0x91, 0x24, 0x90, 0xb9, 0x39,
|
||||
0xbc, 0xa2, 0x12, 0x4a, 0x30, 0xa2, 0x8f, 0x54, 0x40, 0x2c, 0x34, 0xae, 0xca, 0x33, 0x1a, 0xb6,
|
||||
0x7e, 0x1e, 0x79, 0xb2, 0x85, 0xdd, 0x57, 0x71, 0xb5, 0xd9, 0xff, 0x79, 0xea, 0x63, 0x0b, 0x75,
|
||||
},
|
||||
.rid = { 0xa0, 0x00, 0x00, 0x00, 0x03, },
|
||||
.index = 1,
|
||||
.hash_algo = HASH_SHA_1,
|
||||
.pk_algo = PK_RSA,
|
||||
.hash = {
|
||||
0xd3, 0x4a, 0x6a, 0x77,
|
||||
0x60, 0x11, 0xc7, 0xe7,
|
||||
0xce, 0x3a, 0xec, 0x5f,
|
||||
0x03, 0xad, 0x2f, 0x8c,
|
||||
0xfc, 0x55, 0x03, 0xcc, },
|
||||
.exp = { 0x03, },
|
||||
.elen = 1,
|
||||
.mlen = 1024 / 8,
|
||||
.modulus = (unsigned char[]){
|
||||
0xc6, 0x96, 0x03, 0x42, 0x13, 0xd7, 0xd8, 0x54, 0x69, 0x84, 0x57, 0x9d, 0x1d, 0x0f, 0x0e, 0xa5,
|
||||
0x19, 0xcf, 0xf8, 0xde, 0xff, 0xc4, 0x29, 0x35, 0x4c, 0xf3, 0xa8, 0x71, 0xa6, 0xf7, 0x18, 0x3f,
|
||||
0x12, 0x28, 0xda, 0x5c, 0x74, 0x70, 0xc0, 0x55, 0x38, 0x71, 0x00, 0xcb, 0x93, 0x5a, 0x71, 0x2c,
|
||||
0x4e, 0x28, 0x64, 0xdf, 0x5d, 0x64, 0xba, 0x93, 0xfe, 0x7e, 0x63, 0xe7, 0x1f, 0x25, 0xb1, 0xe5,
|
||||
0xf5, 0x29, 0x85, 0x75, 0xeb, 0xe1, 0xc6, 0x3a, 0xa6, 0x17, 0x70, 0x69, 0x17, 0x91, 0x1d, 0xc2,
|
||||
0xa7, 0x5a, 0xc2, 0x8b, 0x25, 0x1c, 0x7e, 0xf4, 0x0f, 0x23, 0x65, 0x91, 0x24, 0x90, 0xb9, 0x39,
|
||||
0xbc, 0xa2, 0x12, 0x4a, 0x30, 0xa2, 0x8f, 0x54, 0x40, 0x2c, 0x34, 0xae, 0xca, 0x33, 0x1a, 0xb6,
|
||||
0x7e, 0x1e, 0x79, 0xb2, 0x85, 0xdd, 0x57, 0x71, 0xb5, 0xd9, 0xff, 0x79, 0xea, 0x63, 0x0b, 0x75,
|
||||
},
|
||||
};
|
||||
|
||||
const unsigned char issuer_cert[] = {
|
||||
0x3c, 0x5f, 0xea, 0xd4, 0xdd, 0x7b, 0xca, 0x44, 0xf9, 0x3e, 0x90, 0xc4, 0x4f, 0x76, 0xed, 0xe5,
|
||||
0x4a, 0x32, 0x88, 0xec, 0xdc, 0x78, 0x46, 0x9f, 0xcb, 0x12, 0x25, 0xc0, 0x3b, 0x2c, 0x04, 0xf2,
|
||||
0xc2, 0xf4, 0x12, 0x28, 0x1a, 0x08, 0x22, 0xdf, 0x14, 0x64, 0x92, 0x30, 0x98, 0x9f, 0xb1, 0x49,
|
||||
0x40, 0x70, 0xda, 0xf8, 0xc9, 0x53, 0x4a, 0x78, 0x81, 0x96, 0x01, 0x48, 0x61, 0x6a, 0xce, 0x58,
|
||||
0x17, 0x88, 0x12, 0x0d, 0x35, 0x06, 0xac, 0xe4, 0xce, 0xe5, 0x64, 0xfb, 0x27, 0xee, 0x53, 0x34,
|
||||
0x1c, 0x22, 0xf0, 0xb4, 0x5b, 0x31, 0x87, 0x3d, 0x05, 0xde, 0x54, 0x5e, 0xfe, 0x33, 0xbc, 0xd2,
|
||||
0x9b, 0x21, 0x85, 0xd0, 0x35, 0xa8, 0x06, 0xad, 0x08, 0xc6, 0x97, 0x6f, 0x35, 0x05, 0xa1, 0x99,
|
||||
0x99, 0x93, 0x0c, 0xa8, 0xa0, 0x3e, 0xfa, 0x32, 0x1c, 0x48, 0x60, 0x61, 0xf7, 0xdc, 0xec, 0x9f,
|
||||
0x3c, 0x5f, 0xea, 0xd4, 0xdd, 0x7b, 0xca, 0x44, 0xf9, 0x3e, 0x90, 0xc4, 0x4f, 0x76, 0xed, 0xe5,
|
||||
0x4a, 0x32, 0x88, 0xec, 0xdc, 0x78, 0x46, 0x9f, 0xcb, 0x12, 0x25, 0xc0, 0x3b, 0x2c, 0x04, 0xf2,
|
||||
0xc2, 0xf4, 0x12, 0x28, 0x1a, 0x08, 0x22, 0xdf, 0x14, 0x64, 0x92, 0x30, 0x98, 0x9f, 0xb1, 0x49,
|
||||
0x40, 0x70, 0xda, 0xf8, 0xc9, 0x53, 0x4a, 0x78, 0x81, 0x96, 0x01, 0x48, 0x61, 0x6a, 0xce, 0x58,
|
||||
0x17, 0x88, 0x12, 0x0d, 0x35, 0x06, 0xac, 0xe4, 0xce, 0xe5, 0x64, 0xfb, 0x27, 0xee, 0x53, 0x34,
|
||||
0x1c, 0x22, 0xf0, 0xb4, 0x5b, 0x31, 0x87, 0x3d, 0x05, 0xde, 0x54, 0x5e, 0xfe, 0x33, 0xbc, 0xd2,
|
||||
0x9b, 0x21, 0x85, 0xd0, 0x35, 0xa8, 0x06, 0xad, 0x08, 0xc6, 0x97, 0x6f, 0x35, 0x05, 0xa1, 0x99,
|
||||
0x99, 0x93, 0x0c, 0xa8, 0xa0, 0x3e, 0xfa, 0x32, 0x1c, 0x48, 0x60, 0x61, 0xf7, 0xdc, 0xec, 0x9f,
|
||||
};
|
||||
|
||||
const unsigned char issuer_rem[] = {
|
||||
0x1e, 0xbc, 0xa3, 0x0f, 0x00, 0xce, 0x59, 0x62, 0xa8, 0xc6, 0xe1, 0x30, 0x54, 0x4b, 0x82, 0x89,
|
||||
0x1b, 0x23, 0x6c, 0x65, 0xde, 0x29, 0x31, 0x7f, 0x36, 0x47, 0x35, 0xde, 0xe6, 0x3f, 0x65, 0x98,
|
||||
0x97, 0x58, 0x35, 0xd5
|
||||
0x1e, 0xbc, 0xa3, 0x0f, 0x00, 0xce, 0x59, 0x62, 0xa8, 0xc6, 0xe1, 0x30, 0x54, 0x4b, 0x82, 0x89,
|
||||
0x1b, 0x23, 0x6c, 0x65, 0xde, 0x29, 0x31, 0x7f, 0x36, 0x47, 0x35, 0xde, 0xe6, 0x3f, 0x65, 0x98,
|
||||
0x97, 0x58, 0x35, 0xd5
|
||||
};
|
||||
|
||||
const unsigned char issuer_exp[] = {
|
||||
0x03,
|
||||
0x03,
|
||||
};
|
||||
|
||||
const unsigned char ssad_cr[] = {
|
||||
0x99, 0xa5, 0x58, 0xb6, 0x2b, 0x67, 0x4a, 0xa5, 0xe7, 0xd2, 0xa5, 0x7e, 0x5e, 0xf6, 0xa6, 0xf2,
|
||||
0x25, 0x8e, 0x5d, 0xa0, 0x52, 0xd0, 0x5b, 0x54, 0xe5, 0xc1, 0x15, 0xff, 0x1c, 0xec, 0xf9, 0x4a,
|
||||
0xa2, 0xdf, 0x8f, 0x39, 0xa0, 0x1d, 0x71, 0xc6, 0x19, 0xeb, 0x81, 0x9d, 0xa5, 0x2e, 0xf3, 0x81,
|
||||
0xe8, 0x49, 0x79, 0x58, 0x6a, 0xea, 0x78, 0x55, 0xff, 0xbe, 0xf4, 0x0a, 0xa3, 0xa7, 0x1c, 0xd3,
|
||||
0xb0, 0x4c, 0xfd, 0xf2, 0x70, 0xae, 0xc8, 0x15, 0x8a, 0x27, 0x97, 0xf2, 0x4f, 0xd6, 0x13, 0xb7,
|
||||
0x48, 0x13, 0x46, 0x61, 0x13, 0x5c, 0xd2, 0x90, 0xe4, 0x5b, 0x04, 0xa8, 0xe0, 0xcc, 0xc7, 0x11,
|
||||
0xae, 0x04, 0x2f, 0x15, 0x9e, 0x73, 0xc8, 0x9c, 0x2a, 0x7e, 0x65, 0xa4, 0xc2, 0xfd, 0x1d, 0x61,
|
||||
0x06, 0x02, 0x4a, 0xa2, 0x71, 0x30, 0xb0, 0xec, 0xec, 0x02, 0x38, 0xf9, 0x16, 0x59, 0xde, 0x96,
|
||||
0x99, 0xa5, 0x58, 0xb6, 0x2b, 0x67, 0x4a, 0xa5, 0xe7, 0xd2, 0xa5, 0x7e, 0x5e, 0xf6, 0xa6, 0xf2,
|
||||
0x25, 0x8e, 0x5d, 0xa0, 0x52, 0xd0, 0x5b, 0x54, 0xe5, 0xc1, 0x15, 0xff, 0x1c, 0xec, 0xf9, 0x4a,
|
||||
0xa2, 0xdf, 0x8f, 0x39, 0xa0, 0x1d, 0x71, 0xc6, 0x19, 0xeb, 0x81, 0x9d, 0xa5, 0x2e, 0xf3, 0x81,
|
||||
0xe8, 0x49, 0x79, 0x58, 0x6a, 0xea, 0x78, 0x55, 0xff, 0xbe, 0xf4, 0x0a, 0xa3, 0xa7, 0x1c, 0xd3,
|
||||
0xb0, 0x4c, 0xfd, 0xf2, 0x70, 0xae, 0xc8, 0x15, 0x8a, 0x27, 0x97, 0xf2, 0x4f, 0xd6, 0x13, 0xb7,
|
||||
0x48, 0x13, 0x46, 0x61, 0x13, 0x5c, 0xd2, 0x90, 0xe4, 0x5b, 0x04, 0xa8, 0xe0, 0xcc, 0xc7, 0x11,
|
||||
0xae, 0x04, 0x2f, 0x15, 0x9e, 0x73, 0xc8, 0x9c, 0x2a, 0x7e, 0x65, 0xa4, 0xc2, 0xfd, 0x1d, 0x61,
|
||||
0x06, 0x02, 0x4a, 0xa2, 0x71, 0x30, 0xb0, 0xec, 0xec, 0x02, 0x38, 0xf9, 0x16, 0x59, 0xde, 0x96,
|
||||
};
|
||||
|
||||
const unsigned char ssd1[] = {
|
||||
0x5f, 0x24, 0x03, 0x08, 0x12, 0x31, 0x5a, 0x08, 0x42, 0x76, 0x55, 0x00, 0x13, 0x23, 0x45, 0x99, 0x5f, 0x34, 0x01, 0x01, 0x9f, 0x07, 0x02, 0xff, 0x00, 0x9f, 0x0d, 0x05, 0xd0, 0x40, 0xac, 0xa8, 0x00, 0x9f, 0x0e, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00, 0x9f, 0x0f, 0x05, 0xd0, 0x68, 0xbc, 0xf8, 0x00,
|
||||
0x5c, 0x00,
|
||||
0x5f, 0x24, 0x03, 0x08, 0x12, 0x31, 0x5a, 0x08, 0x42, 0x76, 0x55, 0x00, 0x13, 0x23, 0x45, 0x99, 0x5f, 0x34, 0x01, 0x01, 0x9f, 0x07, 0x02, 0xff, 0x00, 0x9f, 0x0d, 0x05, 0xd0, 0x40, 0xac, 0xa8, 0x00, 0x9f, 0x0e, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00, 0x9f, 0x0f, 0x05, 0xd0, 0x68, 0xbc, 0xf8, 0x00,
|
||||
0x5c, 0x00,
|
||||
};
|
||||
static const struct tlv ssd1_tlv = {
|
||||
.len = sizeof(ssd1),
|
||||
.value = ssd1,
|
||||
.len = sizeof(ssd1),
|
||||
.value = ssd1,
|
||||
};
|
||||
|
||||
const unsigned char pan[] = {
|
||||
0x42, 0x76, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x42, 0x76, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
static int sda_test_raw(bool verbose)
|
||||
{
|
||||
const struct emv_pk *pk = &vsdc_01;
|
||||
const struct emv_pk *pk = &vsdc_01;
|
||||
|
||||
struct crypto_pk *kcp = crypto_pk_open(PK_RSA,
|
||||
pk->modulus, pk->mlen,
|
||||
pk->exp, pk->elen);
|
||||
if (!kcp)
|
||||
return 1;
|
||||
struct crypto_pk *kcp = crypto_pk_open(PK_RSA,
|
||||
pk->modulus, pk->mlen,
|
||||
pk->exp, pk->elen);
|
||||
if (!kcp)
|
||||
return 1;
|
||||
|
||||
unsigned char *ipk_data;
|
||||
size_t ipk_data_len;
|
||||
ipk_data = crypto_pk_encrypt(kcp, issuer_cert, sizeof(issuer_cert), &ipk_data_len);
|
||||
crypto_pk_close(kcp);
|
||||
unsigned char *ipk_data;
|
||||
size_t ipk_data_len;
|
||||
ipk_data = crypto_pk_encrypt(kcp, issuer_cert, sizeof(issuer_cert), &ipk_data_len);
|
||||
crypto_pk_close(kcp);
|
||||
|
||||
if (!ipk_data)
|
||||
return 1;
|
||||
if (!ipk_data)
|
||||
return 1;
|
||||
|
||||
if (verbose) {
|
||||
printf("issuer cert:\n");
|
||||
dump_buffer(ipk_data, ipk_data_len, stdout, 0);
|
||||
}
|
||||
if (verbose) {
|
||||
printf("issuer cert:\n");
|
||||
dump_buffer(ipk_data, ipk_data_len, stdout, 0);
|
||||
}
|
||||
|
||||
size_t ipk_pk_len = ipk_data[13];
|
||||
unsigned char *ipk_pk = malloc(ipk_pk_len);
|
||||
memcpy(ipk_pk, ipk_data + 15, ipk_data_len - 36);
|
||||
memcpy(ipk_pk + ipk_data_len - 36, issuer_rem, sizeof(issuer_rem));
|
||||
size_t ipk_pk_len = ipk_data[13];
|
||||
unsigned char *ipk_pk = malloc(ipk_pk_len);
|
||||
memcpy(ipk_pk, ipk_data + 15, ipk_data_len - 36);
|
||||
memcpy(ipk_pk + ipk_data_len - 36, issuer_rem, sizeof(issuer_rem));
|
||||
|
||||
struct crypto_hash *ch;
|
||||
ch = crypto_hash_open(HASH_SHA_1);
|
||||
if (!ch) {
|
||||
free(ipk_pk);
|
||||
free(ipk_data);
|
||||
return 1;
|
||||
}
|
||||
struct crypto_hash *ch;
|
||||
ch = crypto_hash_open(HASH_SHA_1);
|
||||
if (!ch) {
|
||||
free(ipk_pk);
|
||||
free(ipk_data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
crypto_hash_write(ch, ipk_data + 1, 14);
|
||||
crypto_hash_write(ch, ipk_pk, ipk_pk_len);
|
||||
crypto_hash_write(ch, issuer_exp, sizeof(issuer_exp));
|
||||
crypto_hash_write(ch, ipk_data + 1, 14);
|
||||
crypto_hash_write(ch, ipk_pk, ipk_pk_len);
|
||||
crypto_hash_write(ch, issuer_exp, sizeof(issuer_exp));
|
||||
|
||||
unsigned char *h = crypto_hash_read(ch);
|
||||
if (!h) {
|
||||
crypto_hash_close(ch);
|
||||
free(ipk_pk);
|
||||
free(ipk_data);
|
||||
return 1;
|
||||
}
|
||||
unsigned char *h = crypto_hash_read(ch);
|
||||
if (!h) {
|
||||
crypto_hash_close(ch);
|
||||
free(ipk_pk);
|
||||
free(ipk_data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
printf("crypto hash:\n");
|
||||
dump_buffer(h, 20, stdout, 0);
|
||||
}
|
||||
if (verbose) {
|
||||
printf("crypto hash:\n");
|
||||
dump_buffer(h, 20, stdout, 0);
|
||||
}
|
||||
|
||||
if (memcmp(ipk_data + ipk_data_len - 21, h, 20)) {
|
||||
crypto_hash_close(ch);
|
||||
free(ipk_pk);
|
||||
free(ipk_data);
|
||||
return 1;
|
||||
}
|
||||
if (memcmp(ipk_data + ipk_data_len - 21, h, 20)) {
|
||||
crypto_hash_close(ch);
|
||||
free(ipk_pk);
|
||||
free(ipk_data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
crypto_hash_close(ch);
|
||||
free(ipk_data);
|
||||
crypto_hash_close(ch);
|
||||
free(ipk_data);
|
||||
|
||||
struct crypto_pk *ikcp = crypto_pk_open(PK_RSA, ipk_pk, (int) ipk_pk_len,
|
||||
issuer_exp, (int) sizeof(issuer_exp));
|
||||
free(ipk_pk);
|
||||
if (!ikcp)
|
||||
return 1;
|
||||
struct crypto_pk *ikcp = crypto_pk_open(PK_RSA, ipk_pk, (int) ipk_pk_len,
|
||||
issuer_exp, (int) sizeof(issuer_exp));
|
||||
free(ipk_pk);
|
||||
if (!ikcp)
|
||||
return 1;
|
||||
|
||||
size_t ssad_len;
|
||||
unsigned char *ssad = crypto_pk_encrypt(ikcp, ssad_cr, sizeof(ssad_cr), &ssad_len);
|
||||
crypto_pk_close(ikcp);
|
||||
if (!ssad)
|
||||
return 1;
|
||||
size_t ssad_len;
|
||||
unsigned char *ssad = crypto_pk_encrypt(ikcp, ssad_cr, sizeof(ssad_cr), &ssad_len);
|
||||
crypto_pk_close(ikcp);
|
||||
if (!ssad)
|
||||
return 1;
|
||||
|
||||
if (verbose) {
|
||||
printf("ssad:\n");
|
||||
dump_buffer(ssad, ssad_len, stdout, 0);
|
||||
}
|
||||
if (verbose) {
|
||||
printf("ssad:\n");
|
||||
dump_buffer(ssad, ssad_len, stdout, 0);
|
||||
}
|
||||
|
||||
ch = crypto_hash_open(HASH_SHA_1);
|
||||
if (!ch) {
|
||||
free(ssad);
|
||||
return 1;
|
||||
}
|
||||
ch = crypto_hash_open(HASH_SHA_1);
|
||||
if (!ch) {
|
||||
free(ssad);
|
||||
return 1;
|
||||
}
|
||||
|
||||
crypto_hash_write(ch, ssad + 1, ssad_len - 22);
|
||||
crypto_hash_write(ch, ssd1, sizeof(ssd1));
|
||||
crypto_hash_write(ch, ssad + 1, ssad_len - 22);
|
||||
crypto_hash_write(ch, ssd1, sizeof(ssd1));
|
||||
|
||||
unsigned char *h2 = crypto_hash_read(ch);
|
||||
if (!h2) {
|
||||
crypto_hash_close(ch);
|
||||
free(ssad);
|
||||
return 1;
|
||||
}
|
||||
unsigned char *h2 = crypto_hash_read(ch);
|
||||
if (!h2) {
|
||||
crypto_hash_close(ch);
|
||||
free(ssad);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
printf("crypto hash2:\n");
|
||||
dump_buffer(h2, 20, stdout, 0);
|
||||
}
|
||||
if (verbose) {
|
||||
printf("crypto hash2:\n");
|
||||
dump_buffer(h2, 20, stdout, 0);
|
||||
}
|
||||
|
||||
crypto_hash_close(ch);
|
||||
crypto_hash_close(ch);
|
||||
|
||||
free(ssad);
|
||||
free(ssad);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sda_test_pk(bool verbose)
|
||||
{
|
||||
const struct emv_pk *pk = &vsdc_01;
|
||||
struct tlvdb *db;
|
||||
const struct emv_pk *pk = &vsdc_01;
|
||||
struct tlvdb *db;
|
||||
|
||||
db = tlvdb_external(0x90, sizeof(issuer_cert), issuer_cert);
|
||||
tlvdb_add(db, tlvdb_external(0x9f32, sizeof(issuer_exp), issuer_exp));
|
||||
tlvdb_add(db, tlvdb_external(0x92, sizeof(issuer_rem), issuer_rem));
|
||||
tlvdb_add(db, tlvdb_external(0x5a, sizeof(pan), pan));
|
||||
db = tlvdb_external(0x90, sizeof(issuer_cert), issuer_cert);
|
||||
tlvdb_add(db, tlvdb_external(0x9f32, sizeof(issuer_exp), issuer_exp));
|
||||
tlvdb_add(db, tlvdb_external(0x92, sizeof(issuer_rem), issuer_rem));
|
||||
tlvdb_add(db, tlvdb_external(0x5a, sizeof(pan), pan));
|
||||
|
||||
struct emv_pk *ipk = emv_pki_recover_issuer_cert(pk, db);
|
||||
if (!ipk) {
|
||||
fprintf(stderr, "Could not recover Issuer certificate!\n");
|
||||
tlvdb_free(db);
|
||||
return 2;
|
||||
}
|
||||
struct emv_pk *ipk = emv_pki_recover_issuer_cert(pk, db);
|
||||
if (!ipk) {
|
||||
fprintf(stderr, "Could not recover Issuer certificate!\n");
|
||||
tlvdb_free(db);
|
||||
return 2;
|
||||
}
|
||||
|
||||
tlvdb_add(db, tlvdb_external(0x93, sizeof(ssad_cr), ssad_cr));
|
||||
tlvdb_add(db, tlvdb_external(0x93, sizeof(ssad_cr), ssad_cr));
|
||||
|
||||
struct tlvdb *dacdb = emv_pki_recover_dac(ipk, db, &ssd1_tlv);
|
||||
if (!dacdb) {
|
||||
fprintf(stderr, "Could not recover DAC!\n");
|
||||
emv_pk_free(ipk);
|
||||
tlvdb_free(db);
|
||||
return 2;
|
||||
}
|
||||
struct tlvdb *dacdb = emv_pki_recover_dac(ipk, db, &ssd1_tlv);
|
||||
if (!dacdb) {
|
||||
fprintf(stderr, "Could not recover DAC!\n");
|
||||
emv_pk_free(ipk);
|
||||
tlvdb_free(db);
|
||||
return 2;
|
||||
}
|
||||
|
||||
const struct tlv *dac = tlvdb_get(dacdb, 0x9f45, NULL);
|
||||
if (!dac) {
|
||||
fprintf(stderr, "DAC not found!\n");
|
||||
tlvdb_free(dacdb);
|
||||
emv_pk_free(ipk);
|
||||
tlvdb_free(db);
|
||||
return 2;
|
||||
}
|
||||
const struct tlv *dac = tlvdb_get(dacdb, 0x9f45, NULL);
|
||||
if (!dac) {
|
||||
fprintf(stderr, "DAC not found!\n");
|
||||
tlvdb_free(dacdb);
|
||||
emv_pk_free(ipk);
|
||||
tlvdb_free(db);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
printf("dac:\n");
|
||||
dump_buffer(dac->value, dac->len, stdout, 0);
|
||||
}
|
||||
if (verbose) {
|
||||
printf("dac:\n");
|
||||
dump_buffer(dac->value, dac->len, stdout, 0);
|
||||
}
|
||||
|
||||
tlvdb_free(dacdb);
|
||||
emv_pk_free(ipk);
|
||||
tlvdb_free(db);
|
||||
tlvdb_free(dacdb);
|
||||
emv_pk_free(ipk);
|
||||
tlvdb_free(db);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exec_sda_test(bool verbose)
|
||||
{
|
||||
int ret;
|
||||
fprintf(stdout, "\n");
|
||||
int ret;
|
||||
fprintf(stdout, "\n");
|
||||
|
||||
ret = sda_test_raw(verbose);
|
||||
if (ret) {
|
||||
fprintf(stderr, "SDA raw test: failed\n");
|
||||
return ret;
|
||||
}
|
||||
fprintf(stdout, "SDA raw test: passed\n");
|
||||
ret = sda_test_raw(verbose);
|
||||
if (ret) {
|
||||
fprintf(stderr, "SDA raw test: failed\n");
|
||||
return ret;
|
||||
}
|
||||
fprintf(stdout, "SDA raw test: passed\n");
|
||||
|
||||
ret = sda_test_pk(verbose);
|
||||
if (ret) {
|
||||
fprintf(stderr, "SDA test pk: failed\n");
|
||||
return ret;
|
||||
}
|
||||
fprintf(stdout, "SDA test pk: passed\n");
|
||||
ret = sda_test_pk(verbose);
|
||||
if (ret) {
|
||||
fprintf(stderr, "SDA test pk: failed\n");
|
||||
return ret;
|
||||
}
|
||||
fprintf(stdout, "SDA test pk: passed\n");
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
|
690
client/emv/tlv.c
690
client/emv/tlv.c
|
@ -26,574 +26,574 @@
|
|||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define TLV_TAG_CLASS_MASK 0xc0
|
||||
#define TLV_TAG_COMPLEX 0x20
|
||||
#define TLV_TAG_VALUE_MASK 0x1f
|
||||
#define TLV_TAG_VALUE_CONT 0x1f
|
||||
#define TLV_TAG_INVALID 0
|
||||
#define TLV_TAG_CLASS_MASK 0xc0
|
||||
#define TLV_TAG_COMPLEX 0x20
|
||||
#define TLV_TAG_VALUE_MASK 0x1f
|
||||
#define TLV_TAG_VALUE_CONT 0x1f
|
||||
#define TLV_TAG_INVALID 0
|
||||
|
||||
#define TLV_LEN_LONG 0x80
|
||||
#define TLV_LEN_MASK 0x7f
|
||||
#define TLV_LEN_INVALID (~0)
|
||||
#define TLV_LEN_LONG 0x80
|
||||
#define TLV_LEN_MASK 0x7f
|
||||
#define TLV_LEN_INVALID (~0)
|
||||
|
||||
// http://radek.io/2012/11/10/magical-container_of-macro/
|
||||
//#define container_of(ptr, type, member) ({
|
||||
// const typeof( ((type *)0)->member ) *__mptr = (ptr);
|
||||
// const typeof( ((type *)0)->member ) *__mptr = (ptr);
|
||||
// (type *)( (char *)__mptr - offsetof(type,member) );})
|
||||
|
||||
struct tlvdb {
|
||||
struct tlv tag;
|
||||
struct tlvdb *next;
|
||||
struct tlvdb *parent;
|
||||
struct tlvdb *children;
|
||||
struct tlv tag;
|
||||
struct tlvdb *next;
|
||||
struct tlvdb *parent;
|
||||
struct tlvdb *children;
|
||||
};
|
||||
|
||||
struct tlvdb_root {
|
||||
struct tlvdb db;
|
||||
size_t len;
|
||||
unsigned char buf[0];
|
||||
struct tlvdb db;
|
||||
size_t len;
|
||||
unsigned char buf[0];
|
||||
};
|
||||
|
||||
static tlv_tag_t tlv_parse_tag(const unsigned char **buf, size_t *len)
|
||||
{
|
||||
tlv_tag_t tag;
|
||||
tlv_tag_t tag;
|
||||
|
||||
if (*len == 0)
|
||||
return TLV_TAG_INVALID;
|
||||
tag = **buf;
|
||||
--*len;
|
||||
++*buf;
|
||||
if ((tag & TLV_TAG_VALUE_MASK) != TLV_TAG_VALUE_CONT)
|
||||
return tag;
|
||||
if (*len == 0)
|
||||
return TLV_TAG_INVALID;
|
||||
tag = **buf;
|
||||
--*len;
|
||||
++*buf;
|
||||
if ((tag & TLV_TAG_VALUE_MASK) != TLV_TAG_VALUE_CONT)
|
||||
return tag;
|
||||
|
||||
if (*len == 0)
|
||||
return TLV_TAG_INVALID;
|
||||
if (*len == 0)
|
||||
return TLV_TAG_INVALID;
|
||||
|
||||
tag <<= 8;
|
||||
tag |= **buf;
|
||||
--*len;
|
||||
++*buf;
|
||||
tag <<= 8;
|
||||
tag |= **buf;
|
||||
--*len;
|
||||
++*buf;
|
||||
|
||||
return tag;
|
||||
return tag;
|
||||
}
|
||||
|
||||
static size_t tlv_parse_len(const unsigned char **buf, size_t *len)
|
||||
{
|
||||
size_t l;
|
||||
size_t l;
|
||||
|
||||
if (*len == 0)
|
||||
return TLV_LEN_INVALID;
|
||||
if (*len == 0)
|
||||
return TLV_LEN_INVALID;
|
||||
|
||||
l = **buf;
|
||||
--*len;
|
||||
++*buf;
|
||||
l = **buf;
|
||||
--*len;
|
||||
++*buf;
|
||||
|
||||
if (!(l & TLV_LEN_LONG))
|
||||
return l;
|
||||
if (!(l & TLV_LEN_LONG))
|
||||
return l;
|
||||
|
||||
size_t ll = l &~ TLV_LEN_LONG;
|
||||
if (ll > 5)
|
||||
return TLV_LEN_INVALID;
|
||||
size_t ll = l &~ TLV_LEN_LONG;
|
||||
if (ll > 5)
|
||||
return TLV_LEN_INVALID;
|
||||
|
||||
l = 0;
|
||||
for (int i = 1; i <= ll; i++) {
|
||||
l = (l << 8) + **buf;
|
||||
--*len;
|
||||
++*buf;
|
||||
}
|
||||
l = 0;
|
||||
for (int i = 1; i <= ll; i++) {
|
||||
l = (l << 8) + **buf;
|
||||
--*len;
|
||||
++*buf;
|
||||
}
|
||||
|
||||
return l;
|
||||
return l;
|
||||
}
|
||||
|
||||
bool tlv_parse_tl(const unsigned char **buf, size_t *len, struct tlv *tlv)
|
||||
{
|
||||
tlv->value = 0;
|
||||
tlv->value = 0;
|
||||
|
||||
tlv->tag = tlv_parse_tag(buf, len);
|
||||
if (tlv->tag == TLV_TAG_INVALID)
|
||||
return false;
|
||||
tlv->tag = tlv_parse_tag(buf, len);
|
||||
if (tlv->tag == TLV_TAG_INVALID)
|
||||
return false;
|
||||
|
||||
tlv->len = tlv_parse_len(buf, len);
|
||||
if (tlv->len == TLV_LEN_INVALID)
|
||||
return false;
|
||||
tlv->len = tlv_parse_len(buf, len);
|
||||
if (tlv->len == TLV_LEN_INVALID)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct tlvdb *tlvdb_parse_children(struct tlvdb *parent);
|
||||
|
||||
static bool tlvdb_parse_one(struct tlvdb *tlvdb,
|
||||
struct tlvdb *parent,
|
||||
const unsigned char **tmp,
|
||||
size_t *left)
|
||||
struct tlvdb *parent,
|
||||
const unsigned char **tmp,
|
||||
size_t *left)
|
||||
{
|
||||
tlvdb->next = tlvdb->children = NULL;
|
||||
tlvdb->parent = parent;
|
||||
tlvdb->next = tlvdb->children = NULL;
|
||||
tlvdb->parent = parent;
|
||||
|
||||
tlvdb->tag.tag = tlv_parse_tag(tmp, left);
|
||||
if (tlvdb->tag.tag == TLV_TAG_INVALID)
|
||||
goto err;
|
||||
tlvdb->tag.tag = tlv_parse_tag(tmp, left);
|
||||
if (tlvdb->tag.tag == TLV_TAG_INVALID)
|
||||
goto err;
|
||||
|
||||
tlvdb->tag.len = tlv_parse_len(tmp, left);
|
||||
if (tlvdb->tag.len == TLV_LEN_INVALID)
|
||||
goto err;
|
||||
tlvdb->tag.len = tlv_parse_len(tmp, left);
|
||||
if (tlvdb->tag.len == TLV_LEN_INVALID)
|
||||
goto err;
|
||||
|
||||
if (tlvdb->tag.len > *left)
|
||||
goto err;
|
||||
if (tlvdb->tag.len > *left)
|
||||
goto err;
|
||||
|
||||
tlvdb->tag.value = *tmp;
|
||||
tlvdb->tag.value = *tmp;
|
||||
|
||||
*tmp += tlvdb->tag.len;
|
||||
*left -= tlvdb->tag.len;
|
||||
*tmp += tlvdb->tag.len;
|
||||
*left -= tlvdb->tag.len;
|
||||
|
||||
if (tlv_is_constructed(&tlvdb->tag) && (tlvdb->tag.len != 0)) {
|
||||
tlvdb->children = tlvdb_parse_children(tlvdb);
|
||||
if (!tlvdb->children)
|
||||
goto err;
|
||||
} else {
|
||||
tlvdb->children = NULL;
|
||||
}
|
||||
if (tlv_is_constructed(&tlvdb->tag) && (tlvdb->tag.len != 0)) {
|
||||
tlvdb->children = tlvdb_parse_children(tlvdb);
|
||||
if (!tlvdb->children)
|
||||
goto err;
|
||||
} else {
|
||||
tlvdb->children = NULL;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
|
||||
err:
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct tlvdb *tlvdb_parse_children(struct tlvdb *parent)
|
||||
{
|
||||
const unsigned char *tmp = parent->tag.value;
|
||||
size_t left = parent->tag.len;
|
||||
struct tlvdb *tlvdb, *first = NULL, *prev = NULL;
|
||||
const unsigned char *tmp = parent->tag.value;
|
||||
size_t left = parent->tag.len;
|
||||
struct tlvdb *tlvdb, *first = NULL, *prev = NULL;
|
||||
|
||||
while (left != 0) {
|
||||
tlvdb = malloc(sizeof(*tlvdb));
|
||||
if (prev)
|
||||
prev->next = tlvdb;
|
||||
else
|
||||
first = tlvdb;
|
||||
prev = tlvdb;
|
||||
while (left != 0) {
|
||||
tlvdb = malloc(sizeof(*tlvdb));
|
||||
if (prev)
|
||||
prev->next = tlvdb;
|
||||
else
|
||||
first = tlvdb;
|
||||
prev = tlvdb;
|
||||
|
||||
if (!tlvdb_parse_one(tlvdb, parent, &tmp, &left))
|
||||
goto err;
|
||||
if (!tlvdb_parse_one(tlvdb, parent, &tmp, &left))
|
||||
goto err;
|
||||
|
||||
tlvdb->parent = parent;
|
||||
}
|
||||
tlvdb->parent = parent;
|
||||
}
|
||||
|
||||
return first;
|
||||
return first;
|
||||
|
||||
err:
|
||||
tlvdb_free(first);
|
||||
tlvdb_free(first);
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct tlvdb *tlvdb_parse(const unsigned char *buf, size_t len)
|
||||
{
|
||||
struct tlvdb_root *root;
|
||||
const unsigned char *tmp;
|
||||
size_t left;
|
||||
struct tlvdb_root *root;
|
||||
const unsigned char *tmp;
|
||||
size_t left;
|
||||
|
||||
if (!len || !buf)
|
||||
return NULL;
|
||||
if (!len || !buf)
|
||||
return NULL;
|
||||
|
||||
root = malloc(sizeof(*root) + len);
|
||||
root->len = len;
|
||||
memcpy(root->buf, buf, len);
|
||||
root = malloc(sizeof(*root) + len);
|
||||
root->len = len;
|
||||
memcpy(root->buf, buf, len);
|
||||
|
||||
tmp = root->buf;
|
||||
left = len;
|
||||
tmp = root->buf;
|
||||
left = len;
|
||||
|
||||
if (!tlvdb_parse_one(&root->db, NULL, &tmp, &left))
|
||||
goto err;
|
||||
if (!tlvdb_parse_one(&root->db, NULL, &tmp, &left))
|
||||
goto err;
|
||||
|
||||
if (left)
|
||||
goto err;
|
||||
if (left)
|
||||
goto err;
|
||||
|
||||
return &root->db;
|
||||
return &root->db;
|
||||
|
||||
err:
|
||||
tlvdb_free(&root->db);
|
||||
tlvdb_free(&root->db);
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct tlvdb *tlvdb_parse_multi(const unsigned char *buf, size_t len)
|
||||
{
|
||||
struct tlvdb_root *root;
|
||||
const unsigned char *tmp;
|
||||
size_t left;
|
||||
struct tlvdb_root *root;
|
||||
const unsigned char *tmp;
|
||||
size_t left;
|
||||
|
||||
if (!len || !buf)
|
||||
return NULL;
|
||||
if (!len || !buf)
|
||||
return NULL;
|
||||
|
||||
root = malloc(sizeof(*root) + len);
|
||||
root->len = len;
|
||||
memcpy(root->buf, buf, len);
|
||||
root = malloc(sizeof(*root) + len);
|
||||
root->len = len;
|
||||
memcpy(root->buf, buf, len);
|
||||
|
||||
tmp = root->buf;
|
||||
left = len;
|
||||
tmp = root->buf;
|
||||
left = len;
|
||||
|
||||
if (!tlvdb_parse_one(&root->db, NULL, &tmp, &left))
|
||||
goto err;
|
||||
if (!tlvdb_parse_one(&root->db, NULL, &tmp, &left))
|
||||
goto err;
|
||||
|
||||
while (left != 0) {
|
||||
struct tlvdb *db = malloc(sizeof(*db));
|
||||
if (!tlvdb_parse_one(db, NULL, &tmp, &left)) {
|
||||
free (db);
|
||||
goto err;
|
||||
}
|
||||
while (left != 0) {
|
||||
struct tlvdb *db = malloc(sizeof(*db));
|
||||
if (!tlvdb_parse_one(db, NULL, &tmp, &left)) {
|
||||
free (db);
|
||||
goto err;
|
||||
}
|
||||
|
||||
tlvdb_add(&root->db, db);
|
||||
}
|
||||
tlvdb_add(&root->db, db);
|
||||
}
|
||||
|
||||
return &root->db;
|
||||
return &root->db;
|
||||
|
||||
err:
|
||||
tlvdb_free(&root->db);
|
||||
tlvdb_free(&root->db);
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct tlvdb *tlvdb_fixed(tlv_tag_t tag, size_t len, const unsigned char *value)
|
||||
{
|
||||
struct tlvdb_root *root = malloc(sizeof(*root) + len);
|
||||
struct tlvdb_root *root = malloc(sizeof(*root) + len);
|
||||
|
||||
root->len = len;
|
||||
memcpy(root->buf, value, len);
|
||||
root->len = len;
|
||||
memcpy(root->buf, value, len);
|
||||
|
||||
root->db.parent = root->db.next = root->db.children = NULL;
|
||||
root->db.tag.tag = tag;
|
||||
root->db.tag.len = len;
|
||||
root->db.tag.value = root->buf;
|
||||
root->db.parent = root->db.next = root->db.children = NULL;
|
||||
root->db.tag.tag = tag;
|
||||
root->db.tag.len = len;
|
||||
root->db.tag.value = root->buf;
|
||||
|
||||
return &root->db;
|
||||
return &root->db;
|
||||
}
|
||||
|
||||
struct tlvdb *tlvdb_external(tlv_tag_t tag, size_t len, const unsigned char *value)
|
||||
{
|
||||
struct tlvdb_root *root = malloc(sizeof(*root));
|
||||
struct tlvdb_root *root = malloc(sizeof(*root));
|
||||
|
||||
root->len = 0;
|
||||
root->len = 0;
|
||||
|
||||
root->db.parent = root->db.next = root->db.children = NULL;
|
||||
root->db.tag.tag = tag;
|
||||
root->db.tag.len = len;
|
||||
root->db.tag.value = value;
|
||||
root->db.parent = root->db.next = root->db.children = NULL;
|
||||
root->db.tag.tag = tag;
|
||||
root->db.tag.len = len;
|
||||
root->db.tag.value = value;
|
||||
|
||||
return &root->db;
|
||||
return &root->db;
|
||||
}
|
||||
|
||||
void tlvdb_free(struct tlvdb *tlvdb)
|
||||
{
|
||||
struct tlvdb *next = NULL;
|
||||
struct tlvdb *next = NULL;
|
||||
|
||||
if (!tlvdb)
|
||||
return;
|
||||
if (!tlvdb)
|
||||
return;
|
||||
|
||||
for (; tlvdb; tlvdb = next) {
|
||||
next = tlvdb->next;
|
||||
tlvdb_free(tlvdb->children);
|
||||
free(tlvdb);
|
||||
}
|
||||
for (; tlvdb; tlvdb = next) {
|
||||
next = tlvdb->next;
|
||||
tlvdb_free(tlvdb->children);
|
||||
free(tlvdb);
|
||||
}
|
||||
}
|
||||
|
||||
struct tlvdb *tlvdb_find_next(struct tlvdb *tlvdb, tlv_tag_t tag) {
|
||||
if (!tlvdb)
|
||||
return NULL;
|
||||
if (!tlvdb)
|
||||
return NULL;
|
||||
|
||||
return tlvdb_find(tlvdb->next, tag);
|
||||
return tlvdb_find(tlvdb->next, tag);
|
||||
}
|
||||
|
||||
struct tlvdb *tlvdb_find(struct tlvdb *tlvdb, tlv_tag_t tag) {
|
||||
if (!tlvdb)
|
||||
return NULL;
|
||||
if (!tlvdb)
|
||||
return NULL;
|
||||
|
||||
for (; tlvdb; tlvdb = tlvdb->next) {
|
||||
if (tlvdb->tag.tag == tag)
|
||||
return tlvdb;
|
||||
}
|
||||
for (; tlvdb; tlvdb = tlvdb->next) {
|
||||
if (tlvdb->tag.tag == tag)
|
||||
return tlvdb;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct tlvdb *tlvdb_find_full(struct tlvdb *tlvdb, tlv_tag_t tag) {
|
||||
if (!tlvdb)
|
||||
return NULL;
|
||||
if (!tlvdb)
|
||||
return NULL;
|
||||
|
||||
for (; tlvdb; tlvdb = tlvdb->next) {
|
||||
if (tlvdb->tag.tag == tag)
|
||||
return tlvdb;
|
||||
for (; tlvdb; tlvdb = tlvdb->next) {
|
||||
if (tlvdb->tag.tag == tag)
|
||||
return tlvdb;
|
||||
|
||||
if (tlvdb->children) {
|
||||
struct tlvdb * ch = tlvdb_find_full(tlvdb->children, tag);
|
||||
if (ch)
|
||||
return ch;
|
||||
}
|
||||
}
|
||||
if (tlvdb->children) {
|
||||
struct tlvdb * ch = tlvdb_find_full(tlvdb->children, tag);
|
||||
if (ch)
|
||||
return ch;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct tlvdb *tlvdb_find_path(struct tlvdb *tlvdb, tlv_tag_t tag[]) {
|
||||
int i = 0;
|
||||
struct tlvdb *tnext = tlvdb;
|
||||
int i = 0;
|
||||
struct tlvdb *tnext = tlvdb;
|
||||
|
||||
while (tnext && tag[i]) {
|
||||
tnext = tlvdb_find(tnext, tag[i]);
|
||||
i++;
|
||||
if (tag[i] && tnext) {
|
||||
tnext = tnext->children;
|
||||
}
|
||||
}
|
||||
while (tnext && tag[i]) {
|
||||
tnext = tlvdb_find(tnext, tag[i]);
|
||||
i++;
|
||||
if (tag[i] && tnext) {
|
||||
tnext = tnext->children;
|
||||
}
|
||||
}
|
||||
|
||||
return tnext;
|
||||
return tnext;
|
||||
}
|
||||
|
||||
void tlvdb_add(struct tlvdb *tlvdb, struct tlvdb *other)
|
||||
{
|
||||
if (tlvdb == other)
|
||||
return;
|
||||
if (tlvdb == other)
|
||||
return;
|
||||
|
||||
while (tlvdb->next) {
|
||||
if (tlvdb->next == other)
|
||||
return;
|
||||
while (tlvdb->next) {
|
||||
if (tlvdb->next == other)
|
||||
return;
|
||||
|
||||
tlvdb = tlvdb->next;
|
||||
}
|
||||
tlvdb = tlvdb->next;
|
||||
}
|
||||
|
||||
tlvdb->next = other;
|
||||
tlvdb->next = other;
|
||||
}
|
||||
|
||||
void tlvdb_change_or_add_node_ex(struct tlvdb *tlvdb, tlv_tag_t tag, size_t len, const unsigned char *value, struct tlvdb **tlvdb_elm)
|
||||
{
|
||||
struct tlvdb *telm = tlvdb_find_full(tlvdb, tag);
|
||||
if (telm == NULL) {
|
||||
// new tlv element
|
||||
struct tlvdb *elm = tlvdb_fixed(tag, len, value);
|
||||
tlvdb_add(tlvdb, elm);
|
||||
if (tlvdb_elm)
|
||||
*tlvdb_elm = elm;
|
||||
} else {
|
||||
// the same tlv structure
|
||||
if (telm->tag.tag == tag && telm->tag.len == len && !memcmp(telm->tag.value, value, len))
|
||||
return;
|
||||
struct tlvdb *telm = tlvdb_find_full(tlvdb, tag);
|
||||
if (telm == NULL) {
|
||||
// new tlv element
|
||||
struct tlvdb *elm = tlvdb_fixed(tag, len, value);
|
||||
tlvdb_add(tlvdb, elm);
|
||||
if (tlvdb_elm)
|
||||
*tlvdb_elm = elm;
|
||||
} else {
|
||||
// the same tlv structure
|
||||
if (telm->tag.tag == tag && telm->tag.len == len && !memcmp(telm->tag.value, value, len))
|
||||
return;
|
||||
|
||||
// replace tlv element
|
||||
struct tlvdb *tnewelm = tlvdb_fixed(tag, len, value);
|
||||
tnewelm->next = telm->next;
|
||||
tnewelm->parent = telm->parent;
|
||||
// replace tlv element
|
||||
struct tlvdb *tnewelm = tlvdb_fixed(tag, len, value);
|
||||
tnewelm->next = telm->next;
|
||||
tnewelm->parent = telm->parent;
|
||||
|
||||
// if telm stayed first in children chain
|
||||
if (telm->parent && telm->parent->children == telm) {
|
||||
telm->parent->children = tnewelm;
|
||||
}
|
||||
// if telm stayed first in children chain
|
||||
if (telm->parent && telm->parent->children == telm) {
|
||||
telm->parent->children = tnewelm;
|
||||
}
|
||||
|
||||
// if telm have previous element
|
||||
if (telm != tlvdb) {
|
||||
// elm in root
|
||||
struct tlvdb *celm = tlvdb;
|
||||
// elm in child list of node
|
||||
if (telm->parent && telm->parent->children)
|
||||
celm = telm->parent->children;
|
||||
// if telm have previous element
|
||||
if (telm != tlvdb) {
|
||||
// elm in root
|
||||
struct tlvdb *celm = tlvdb;
|
||||
// elm in child list of node
|
||||
if (telm->parent && telm->parent->children)
|
||||
celm = telm->parent->children;
|
||||
|
||||
// find previous element
|
||||
for (; celm; celm = celm->next) {
|
||||
if (celm->next == telm) {
|
||||
celm->next = tnewelm;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// find previous element
|
||||
for (; celm; celm = celm->next) {
|
||||
if (celm->next == telm) {
|
||||
celm->next = tnewelm;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// free old element with childrens
|
||||
telm->next = NULL;
|
||||
tlvdb_free(telm);
|
||||
// free old element with childrens
|
||||
telm->next = NULL;
|
||||
tlvdb_free(telm);
|
||||
|
||||
if (tlvdb_elm)
|
||||
*tlvdb_elm = tnewelm;
|
||||
}
|
||||
if (tlvdb_elm)
|
||||
*tlvdb_elm = tnewelm;
|
||||
}
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
void tlvdb_change_or_add_node(struct tlvdb *tlvdb, tlv_tag_t tag, size_t len, const unsigned char *value)
|
||||
{
|
||||
tlvdb_change_or_add_node_ex(tlvdb, tag, len, value, NULL);
|
||||
tlvdb_change_or_add_node_ex(tlvdb, tag, len, value, NULL);
|
||||
}
|
||||
|
||||
void tlvdb_visit(const struct tlvdb *tlvdb, tlv_cb cb, void *data, int level)
|
||||
{
|
||||
struct tlvdb *next = NULL;
|
||||
struct tlvdb *next = NULL;
|
||||
|
||||
if (!tlvdb)
|
||||
return;
|
||||
if (!tlvdb)
|
||||
return;
|
||||
|
||||
for (; tlvdb; tlvdb = next) {
|
||||
next = tlvdb->next;
|
||||
cb(data, &tlvdb->tag, level, (tlvdb->children == NULL));
|
||||
tlvdb_visit(tlvdb->children, cb, data, level + 1);
|
||||
}
|
||||
for (; tlvdb; tlvdb = next) {
|
||||
next = tlvdb->next;
|
||||
cb(data, &tlvdb->tag, level, (tlvdb->children == NULL));
|
||||
tlvdb_visit(tlvdb->children, cb, data, level + 1);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct tlvdb *tlvdb_next(const struct tlvdb *tlvdb)
|
||||
{
|
||||
if (tlvdb->children)
|
||||
return tlvdb->children;
|
||||
if (tlvdb->children)
|
||||
return tlvdb->children;
|
||||
|
||||
while (tlvdb) {
|
||||
if (tlvdb->next)
|
||||
return tlvdb->next;
|
||||
while (tlvdb) {
|
||||
if (tlvdb->next)
|
||||
return tlvdb->next;
|
||||
|
||||
tlvdb = tlvdb->parent;
|
||||
}
|
||||
tlvdb = tlvdb->parent;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct tlv *tlvdb_get(const struct tlvdb *tlvdb, tlv_tag_t tag, const struct tlv *prev)
|
||||
{
|
||||
if (prev) {
|
||||
// tlvdb = tlvdb_next(container_of(prev, struct tlvdb, tag));
|
||||
tlvdb = tlvdb_next((struct tlvdb *)prev);
|
||||
}
|
||||
if (prev) {
|
||||
// tlvdb = tlvdb_next(container_of(prev, struct tlvdb, tag));
|
||||
tlvdb = tlvdb_next((struct tlvdb *)prev);
|
||||
}
|
||||
|
||||
|
||||
while (tlvdb) {
|
||||
if (tlvdb->tag.tag == tag)
|
||||
return &tlvdb->tag;
|
||||
while (tlvdb) {
|
||||
if (tlvdb->tag.tag == tag)
|
||||
return &tlvdb->tag;
|
||||
|
||||
tlvdb = tlvdb_next(tlvdb);
|
||||
}
|
||||
tlvdb = tlvdb_next(tlvdb);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct tlv *tlvdb_get_inchild(const struct tlvdb *tlvdb, tlv_tag_t tag, const struct tlv *prev) {
|
||||
tlvdb = tlvdb->children;
|
||||
return tlvdb_get(tlvdb, tag, prev);
|
||||
tlvdb = tlvdb->children;
|
||||
return tlvdb_get(tlvdb, tag, prev);
|
||||
}
|
||||
|
||||
const struct tlv *tlvdb_get_tlv(const struct tlvdb *tlvdb) {
|
||||
if (tlvdb)
|
||||
return &tlvdb->tag;
|
||||
else
|
||||
return NULL;
|
||||
if (tlvdb)
|
||||
return &tlvdb->tag;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned char *tlv_encode(const struct tlv *tlv, size_t *len)
|
||||
{
|
||||
size_t size = tlv->len;
|
||||
unsigned char *data;
|
||||
size_t pos;
|
||||
size_t size = tlv->len;
|
||||
unsigned char *data;
|
||||
size_t pos;
|
||||
|
||||
if (tlv->tag > 0x100)
|
||||
size += 2;
|
||||
else
|
||||
size += 1;
|
||||
if (tlv->tag > 0x100)
|
||||
size += 2;
|
||||
else
|
||||
size += 1;
|
||||
|
||||
if (tlv->len > 0x7f)
|
||||
size += 2;
|
||||
else
|
||||
size += 1;
|
||||
if (tlv->len > 0x7f)
|
||||
size += 2;
|
||||
else
|
||||
size += 1;
|
||||
|
||||
data = malloc(size);
|
||||
if (!data) {
|
||||
*len = 0;
|
||||
return NULL;
|
||||
}
|
||||
data = malloc(size);
|
||||
if (!data) {
|
||||
*len = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
pos = 0;
|
||||
|
||||
if (tlv->tag > 0x100) {
|
||||
data[pos++] = tlv->tag >> 8;
|
||||
data[pos++] = tlv->tag & 0xff;
|
||||
} else
|
||||
data[pos++] = tlv->tag;
|
||||
if (tlv->tag > 0x100) {
|
||||
data[pos++] = tlv->tag >> 8;
|
||||
data[pos++] = tlv->tag & 0xff;
|
||||
} else
|
||||
data[pos++] = tlv->tag;
|
||||
|
||||
if (tlv->len > 0x7f) {
|
||||
data[pos++] = 0x81;
|
||||
data[pos++] = tlv->len;
|
||||
} else
|
||||
data[pos++] = tlv->len;
|
||||
if (tlv->len > 0x7f) {
|
||||
data[pos++] = 0x81;
|
||||
data[pos++] = tlv->len;
|
||||
} else
|
||||
data[pos++] = tlv->len;
|
||||
|
||||
memcpy(data + pos, tlv->value, tlv->len);
|
||||
pos += tlv->len;
|
||||
memcpy(data + pos, tlv->value, tlv->len);
|
||||
pos += tlv->len;
|
||||
|
||||
*len = pos;
|
||||
return data;
|
||||
*len = pos;
|
||||
return data;
|
||||
}
|
||||
|
||||
bool tlv_is_constructed(const struct tlv *tlv)
|
||||
{
|
||||
return (tlv->tag < 0x100 ? tlv->tag : tlv->tag >> 8) & TLV_TAG_COMPLEX;
|
||||
return (tlv->tag < 0x100 ? tlv->tag : tlv->tag >> 8) & TLV_TAG_COMPLEX;
|
||||
}
|
||||
|
||||
bool tlv_equal(const struct tlv *a, const struct tlv *b)
|
||||
{
|
||||
if (!a && !b)
|
||||
return true;
|
||||
if (!a && !b)
|
||||
return true;
|
||||
|
||||
if (!a || !b)
|
||||
return false;
|
||||
if (!a || !b)
|
||||
return false;
|
||||
|
||||
return a->tag == b->tag && a->len == b->len && !memcmp(a->value, b->value, a->len);
|
||||
return a->tag == b->tag && a->len == b->len && !memcmp(a->value, b->value, a->len);
|
||||
}
|
||||
|
||||
struct tlvdb *tlvdb_elm_get_next(struct tlvdb *tlvdb)
|
||||
{
|
||||
return tlvdb->next;
|
||||
return tlvdb->next;
|
||||
}
|
||||
|
||||
struct tlvdb *tlvdb_elm_get_children(struct tlvdb *tlvdb)
|
||||
{
|
||||
return tlvdb->children;
|
||||
return tlvdb->children;
|
||||
}
|
||||
|
||||
struct tlvdb *tlvdb_elm_get_parent(struct tlvdb *tlvdb)
|
||||
{
|
||||
return tlvdb->parent;
|
||||
return tlvdb->parent;
|
||||
}
|
||||
|
||||
bool tlvdb_get_uint8(struct tlvdb *tlvRoot, tlv_tag_t tag, uint8_t *value)
|
||||
{
|
||||
const struct tlv *tlvelm = tlvdb_get(tlvRoot, tag, NULL);
|
||||
return tlv_get_uint8(tlvelm, value);
|
||||
const struct tlv *tlvelm = tlvdb_get(tlvRoot, tag, NULL);
|
||||
return tlv_get_uint8(tlvelm, value);
|
||||
}
|
||||
|
||||
bool tlv_get_uint8(const struct tlv *etlv, uint8_t *value)
|
||||
{
|
||||
*value = 0;
|
||||
if (etlv)
|
||||
{
|
||||
if (etlv->len == 0)
|
||||
return true;
|
||||
*value = 0;
|
||||
if (etlv)
|
||||
{
|
||||
if (etlv->len == 0)
|
||||
return true;
|
||||
|
||||
if (etlv->len == 1)
|
||||
{
|
||||
*value = etlv->value[0];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
if (etlv->len == 1)
|
||||
{
|
||||
*value = etlv->value[0];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool tlv_get_int(const struct tlv *etlv, int *value)
|
||||
{
|
||||
*value = 0;
|
||||
if (etlv)
|
||||
{
|
||||
if (etlv->len == 0)
|
||||
return true;
|
||||
*value = 0;
|
||||
if (etlv)
|
||||
{
|
||||
if (etlv->len == 0)
|
||||
return true;
|
||||
|
||||
if (etlv->len <= 4)
|
||||
{
|
||||
for (int i = 0; i < etlv->len; i++)
|
||||
{
|
||||
*value += etlv->value[i] * (1 << (i * 8));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
if (etlv->len <= 4)
|
||||
{
|
||||
for (int i = 0; i < etlv->len; i++)
|
||||
{
|
||||
*value += etlv->value[i] * (1 << (i * 8));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -25,9 +25,9 @@
|
|||
typedef uint32_t tlv_tag_t;
|
||||
|
||||
struct tlv {
|
||||
tlv_tag_t tag;
|
||||
size_t len;
|
||||
const unsigned char *value;
|
||||
tlv_tag_t tag;
|
||||
size_t len;
|
||||
const unsigned char *value;
|
||||
};
|
||||
|
||||
struct tlvdb;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue