mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-04-27 03:49:58 -07:00
MRTD generalize app selection
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
#include <furi_hal_random.h>
|
||||
|
||||
#include "mrtd.h"
|
||||
|
||||
#define TAG "Mrtd"
|
||||
@@ -56,6 +58,13 @@ struct EFFormat EF = {
|
||||
.DG16 = {.file_id = 0X0110, .short_id = 0X10 },
|
||||
};
|
||||
|
||||
struct AIDSet AID = {
|
||||
.eMRTDApplication = {0xA0, 0x00, 0x00, 0x02, 0x47, 0x10, 0x01},
|
||||
.TravelRecords = {0xA0, 0x00, 0x00, 0x02, 0x47, 0x20, 0x01},
|
||||
.VisaRecords = {0xA0, 0x00, 0x00, 0x02, 0x47, 0x20, 0x02},
|
||||
.AdditionalBiometrics = {0xA0, 0x00, 0x00, 0x02, 0x47, 0x20, 0x03},
|
||||
};
|
||||
|
||||
/*bool mrtd_send_apdu(MrtdApplication* app, uint8_t* buffer, size_t length) {
|
||||
FuriHalNfcTxRxContext* tx_rx = app->tx_rx;
|
||||
|
||||
@@ -114,7 +123,17 @@ bool mrtd_send_apdu(MrtdApplication* app, uint8_t cla, uint8_t ins, uint8_t p1,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool mrtd_select(MrtdApplication* app, EFFile file) {
|
||||
bool mrtd_select_app(MrtdApplication* app, AIDValue aid) {
|
||||
FURI_LOG_D(TAG, "Send select App: %02X %02X %02X %02X %02X %02X %02X",
|
||||
aid[0], aid[1], aid[2], aid[3], aid[4], aid[5], aid[6]);
|
||||
if(!mrtd_send_apdu(app, 0x00, 0xA4, 0x04, 0x0C, 0x07, aid, -1)) {
|
||||
FURI_LOG_E(TAG, "Failed select App");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mrtd_select_file(MrtdApplication* app, EFFile file) {
|
||||
uint8_t data[] = {file.file_id >> 8, file.file_id & 0xff};
|
||||
FURI_LOG_D(TAG, "Send select EF: 0x%04X", file.file_id);
|
||||
if(!mrtd_send_apdu(app, 0x00, 0xA4, 0x02, 0x0C, 0x02, data, -1)) {
|
||||
@@ -143,7 +162,7 @@ size_t mrtd_read_binary(MrtdApplication* app, uint8_t* buffer, size_t bufsize, s
|
||||
|
||||
void mrtd_read_dump(MrtdApplication* app, EFFile file, const char* descr) {
|
||||
FURI_LOG_D(TAG, "Read and dump %s:", descr);
|
||||
if(!mrtd_select(app, file)) {
|
||||
if(!mrtd_select_file(app, file)) {
|
||||
return;
|
||||
}
|
||||
uint8_t data[2048];
|
||||
@@ -174,145 +193,21 @@ void mrtd_free(MrtdApplication* app) {
|
||||
free(app);
|
||||
}
|
||||
|
||||
/*
|
||||
size_t mrtd_read_data(MrtdApplication* app, uint8_t* buffer, size_t bufsize) {
|
||||
//TODO: fill buffer with data from file
|
||||
|
||||
//TODO: use protected APDU if authenticated
|
||||
|
||||
|
||||
|
||||
return read;
|
||||
}
|
||||
*/
|
||||
|
||||
bool mrtd_select_efcardaccess(MrtdApplication* app) {
|
||||
FuriHalNfcTxRxContext* tx_rx = app->tx_rx;
|
||||
|
||||
// Chris: short: 0x6700, long: yes (0x9000)
|
||||
// Anna: short: 0x6700, long: yes (0x9000)
|
||||
|
||||
EFFile file = EF.CardAccess;
|
||||
|
||||
// ICAO 9303 p10 §3.6.2
|
||||
uint8_t select_efcardaccess_cmd[] = {
|
||||
0x00, // CLA
|
||||
0xA4, // INS
|
||||
0x02, // P1
|
||||
0x0C, // P2
|
||||
0x02, // Lc: Data length
|
||||
file.file_id >> 8 | (file.file_id & 0xFF),
|
||||
//0x01, 0x1C, // Data: EF.CardAccess File ID
|
||||
0x00, // Le
|
||||
};
|
||||
|
||||
memcpy(tx_rx->tx_data, select_efcardaccess_cmd, sizeof(select_efcardaccess_cmd));
|
||||
tx_rx->tx_bits = sizeof(select_efcardaccess_cmd) * 8;
|
||||
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
|
||||
|
||||
bool efcardaccess_success = false;
|
||||
|
||||
FURI_LOG_D(TAG, "Send select EF.CardAccess");
|
||||
if(furi_hal_nfc_tx_rx(tx_rx, 300)) {
|
||||
mrtd_trace(app);
|
||||
if(mrtd_decode_response(tx_rx->rx_data, tx_rx->rx_bits / 8) == 0x9000) {
|
||||
efcardaccess_success = true;
|
||||
} else {
|
||||
FURI_LOG_D(TAG, "Select EF.CardAccess response is not 0x9000");
|
||||
}
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Failed select EF.CardAccess");
|
||||
}
|
||||
return efcardaccess_success;
|
||||
}
|
||||
|
||||
bool mrtd_select_efdir(MrtdApplication* app) {
|
||||
FuriHalNfcTxRxContext* tx_rx = app->tx_rx;
|
||||
|
||||
// Chris: short: no, long: no (0x6A82)
|
||||
// Anna: short: no, long: yes (0x9000)
|
||||
|
||||
uint8_t select_efdir_cmd[] = {
|
||||
0x00, // CLA
|
||||
0xA4, // INS
|
||||
0x02, // P1
|
||||
0x0C, // P2
|
||||
0x02, // Lc: Data length
|
||||
0x2F, 0x00, // Data: EF.DIR File ID
|
||||
0x00, // Le
|
||||
};
|
||||
|
||||
memcpy(tx_rx->tx_data, select_efdir_cmd, sizeof(select_efdir_cmd));
|
||||
tx_rx->tx_bits = sizeof(select_efdir_cmd) * 8;
|
||||
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
|
||||
|
||||
bool efdir_success = false;
|
||||
|
||||
FURI_LOG_D(TAG, "Send select EF.DIR");
|
||||
if(furi_hal_nfc_tx_rx(tx_rx, 300)) {
|
||||
mrtd_trace(app);
|
||||
if(mrtd_decode_response(tx_rx->rx_data, tx_rx->rx_bits / 8) == 0x9000) {
|
||||
efdir_success = true;
|
||||
} else {
|
||||
FURI_LOG_D(TAG, "Select EF.DIR response is not 0x9000");
|
||||
}
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Failed select EF.DIR");
|
||||
}
|
||||
return efdir_success;
|
||||
}
|
||||
|
||||
bool mrtd_select_lds1(MrtdApplication* app) {
|
||||
FuriHalNfcTxRxContext* tx_rx = app->tx_rx;
|
||||
|
||||
uint8_t select_emrtd_cmd[] = {
|
||||
0x00, // CLA
|
||||
0xA4, // INS
|
||||
0x04, // P1
|
||||
0x0C, // P2: DF
|
||||
0x07, // Lc: Data length
|
||||
0xa0,
|
||||
0x00,
|
||||
0x00,
|
||||
0x02,
|
||||
0x47,
|
||||
0x10,
|
||||
0x01, // Data: LDS1 eMRTD Application
|
||||
0x00, // Le
|
||||
};
|
||||
|
||||
memcpy(tx_rx->tx_data, select_emrtd_cmd, sizeof(select_emrtd_cmd));
|
||||
tx_rx->tx_bits = sizeof(select_emrtd_cmd) * 8;
|
||||
tx_rx->tx_rx_type = FuriHalNfcTxRxTypeDefault;
|
||||
|
||||
bool lds1_success = false;
|
||||
|
||||
FURI_LOG_D(TAG, "Send select LDS1 eMRTD");
|
||||
if(furi_hal_nfc_tx_rx(tx_rx, 300)) {
|
||||
mrtd_trace(app);
|
||||
if(mrtd_decode_response(tx_rx->rx_data, tx_rx->rx_bits / 8) == 0x9000) {
|
||||
lds1_success = true;
|
||||
} else {
|
||||
FURI_LOG_D(TAG, "Select LDS1 eMRTD response is not 0x9000");
|
||||
}
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Failed select LDS1");
|
||||
}
|
||||
|
||||
return lds1_success;
|
||||
}
|
||||
|
||||
int mrtd_bac_keyhandshake(MrtdApplication* app) {
|
||||
bool mrtd_bac(MrtdApplication* app) {
|
||||
UNUSED(app);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool mrtd_read(MrtdApplication* app) {
|
||||
bool mrtd_read = false;
|
||||
|
||||
memset(app, 0, sizeof(MrtdApplication));
|
||||
|
||||
mrtd_read = mrtd_bac_keyhandshake(app);
|
||||
return mrtd_read;
|
||||
static bool rand_generator_inited = false;
|
||||
uint8_t rnd_ifd[8];
|
||||
uint8_t k_ifd[16];
|
||||
|
||||
if(!rand_generator_inited) {
|
||||
// TODO: should this maybe be system wide?
|
||||
srand(DWT->CYCCNT);
|
||||
rand_generator_inited = true;
|
||||
}
|
||||
|
||||
furi_hal_random_fill_buf(rnd_ifd, 8);
|
||||
furi_hal_random_fill_buf(k_ifd, 16);
|
||||
|
||||
return false; //TODO: return true
|
||||
}
|
||||
|
||||
@@ -51,18 +51,19 @@ struct EFFormat {
|
||||
|
||||
extern struct EFFormat EF;
|
||||
|
||||
typedef uint8_t AIDValue[7];
|
||||
|
||||
struct AIDSet {
|
||||
AIDValue eMRTDApplication;
|
||||
AIDValue TravelRecords;
|
||||
AIDValue VisaRecords;
|
||||
AIDValue AdditionalBiometrics;
|
||||
};
|
||||
|
||||
extern struct AIDSet AID;
|
||||
|
||||
//TODO: description
|
||||
MrtdApplication* mrtd_alloc_init(FuriHalNfcTxRxContext* tx_rx);
|
||||
bool mrtd_select(MrtdApplication* app, EFFile file);
|
||||
bool mrtd_select_efcardaccess(MrtdApplication* mrtd_app);
|
||||
bool mrtd_select_efdir(MrtdApplication* mrtd_app);
|
||||
bool mrtd_select_app(MrtdApplication* app, AIDValue aid);
|
||||
bool mrtd_select_file(MrtdApplication* app, EFFile file);
|
||||
void mrtd_test(MrtdApplication* app);
|
||||
|
||||
/** Select the LDS1 eMRTD application
|
||||
* @note Can be used to detect presence of Passport/ID-card
|
||||
*
|
||||
* @param emv_app MrtdApplication instance
|
||||
*
|
||||
* @return true on success
|
||||
*/
|
||||
bool mrtd_select_lds1(MrtdApplication* mrtd_app);
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include <mbedtls/sha1.h>
|
||||
#include <mbedtls/des.h>
|
||||
|
||||
static inline unsigned char *ucstr(const char *str) { return (unsigned char *)str; }
|
||||
|
||||
uint8_t mrtd_bac_check_digit(const uint8_t* input, const uint8_t length) {
|
||||
const uint8_t num_weights = 3;
|
||||
uint8_t weights[] = {7, 3, 1};
|
||||
@@ -75,7 +77,7 @@ bool mrtd_bac_keys(const uint8_t kseed[16], uint8_t ksenc[16], uint8_t ksmac[16]
|
||||
for(uint8_t i=1; i<=2; ++i) {
|
||||
if(mbedtls_sha1_starts(&ctx)) break;
|
||||
if(mbedtls_sha1_update(&ctx, kseed, 16)) break;
|
||||
if(mbedtls_sha1_update(&ctx, "\x00\x00\x00", 3)) break;
|
||||
if(mbedtls_sha1_update(&ctx, ucstr("\x00\x00\x00"), 3)) break;
|
||||
if(mbedtls_sha1_update(&ctx, &i, 1)) break;
|
||||
if(mbedtls_sha1_finish(&ctx, hash)) break;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user