MRTD Secure Messaging added

This commit is contained in:
Chris van Marle
2022-10-11 22:13:28 +02:00
parent ab5e564410
commit eaeb887d6f
3 changed files with 255 additions and 20 deletions
+34 -3
View File
@@ -132,11 +132,32 @@ bool mrtd_send_apdu(MrtdApplication* app, uint8_t cla, uint8_t ins, uint8_t p1,
if(furi_hal_nfc_tx_rx(tx_rx, 300)) {
mrtd_trace(app);
uint16_t ret_code = mrtd_decode_response(tx_rx->rx_data, tx_rx->rx_bits / 8);
//TODO: handle other return codes?
if(ret_code == 0x9000) {
if(app->secure_messaging) {
//TODO: decrypt and verify
app->ssc_long++;
mrtd_bac_decrypt_verify
}
return true;
} else {
FURI_LOG_I(TAG, "APDU answer is not 0x9000, but 0x%04X", ret_code);
switch(ret_code) {
case 0x6987:
FURI_LOG_I(TAG, "'expected secure messaging data objects are missing'");
app->secure_messaging = false;
break;
case 0x6988:
FURI_LOG_I(TAG, "'secure messaging data objects are incorrect'");
app->secure_messaging = false;
break;
}
return false;
}
}
@@ -358,6 +379,9 @@ bool mrtd_bac(MrtdApplication* app, MrtdAuthData* auth) {
//memcpy(rnd_ifd, "\x78\x17\x23\x86\x0C\x06\xC2\x26", 8);
//memcpy(k_ifd, "\x0B\x79\x52\x40\xCB\x70\x49\xB0\x1C\x19\xB3\x3E\x32\x80\x4F\x0B", 16);
hexdump(FuriLogLevelDebug, "rnd_ifd:", rnd_ifd, 8);
hexdump(FuriLogLevelDebug, "k_ifd:", k_ifd, 16);
uint8_t kenc[16];
uint8_t kmac[16];
@@ -375,9 +399,9 @@ bool mrtd_bac(MrtdApplication* app, MrtdAuthData* auth) {
uint8_t cmd_data[40];
uint8_t *eifd = cmd_data;
uint8_t *kifd = cmd_data+32;
uint8_t *mifd = cmd_data+32;
mrtd_bac_encrypt(S, 32, kenc, eifd);
mrtd_bac_padded_mac(eifd, 32, kmac, kifd);
mrtd_bac_padded_mac(eifd, 32, kmac, mifd);
uint8_t response[40];
if(!mrtd_external_authenticate(app, cmd_data, 40, response, 40)) {
@@ -393,19 +417,26 @@ bool mrtd_bac(MrtdApplication* app, MrtdAuthData* auth) {
uint8_t *rnd_ifd_recv = buffer + 8;
uint8_t *kic = buffer + 16;
hexdump(FuriLogLevelDebug, "kic:", kic, 16);
if(memcmp(rnd_ifd, rnd_ifd_recv, 8)) {
FURI_LOG_W(TAG, "BAC RND.IFD sent and received mismatch.");
}
uint8_t kseed[16];
for(uint8_t i=0; i<16; ++i) {
kseed[i] = kifd[i] ^ kic[i];
kseed[i] = k_ifd[i] ^ kic[i];
printf("seed %2d = %02X ^ %02X = %02X\r\n", i, k_ifd[i], kic[i], kseed[i]);
}
hexdump(FuriLogLevelDebug, "kseed:", kseed, 16);
if(!mrtd_bac_keys_from_seed(kseed, app->ksenc, app->ksmac)) {
FURI_LOG_E(TAG, "BAC error, could not derive KSenc and KSmac");
return false;
}
hexdump(FuriLogLevelDebug, "ksenc:", app->ksenc, 16);
hexdump(FuriLogLevelDebug, "ksmac:", app->ksmac, 16);
hexdump(FuriLogLevelTrace, "RND.IC:", rnd_ic, 8);
hexdump(FuriLogLevelTrace, "RND.IFS:", rnd_ifd, 8);
+62 -13
View File
@@ -146,6 +146,12 @@ bool mrtd_bac_encrypt(const uint8_t* data, size_t data_length, uint8_t* key, uin
bool mrtd_bac_decrypt(const uint8_t* data, size_t data_length, uint8_t* key, uint8_t* output) {
uint8_t IV[8] = "\x00\x00\x00\x00\x00\x00\x00\x00";
printf("Decrypt: ");
for(uint8_t i=0; i<data_length; ++i) {
printf("%02X ", data[i]);
}
printf("\n");
mbedtls_des3_context ctx;
mbedtls_des3_init(&ctx);
mbedtls_des3_set2key_dec(&ctx, key);
@@ -164,7 +170,42 @@ bool mrtd_bac_decrypt_verify(const uint8_t* data, size_t data_length, uint8_t* k
mrtd_bac_padded_mac(data, data_length - 8, key_mac, mac_calc);
if(memcmp(mac_calc, data + data_length - 8, 8)) {
printf( "MAC failed\n");
printf( "MAC failed\r\n");
for(uint8_t i=0; i<8; ++i) {
printf("%02X <=> %02X\r\n", mac_calc[i], data[data_length - 8 + i]);
}
return false;
}
return true;
}
bool mrtd_bac_decrypt_verify_sm(const uint8_t* data, size_t data_length, uint8_t* key_enc, uint8_t* key_mac, uint64_t ssc, uint8_t* output, uint16_t* ret_code) {
// Message: [DO'85 or DO'87] || [DO'99] || DO'8E
// Lengths: Var 1+1+2=4 1+1+8=10
printf("ret_code: %02X %02X\n", data[data_length - 10 - 2], data[data_length - 10 - 2 + 1]);
*ret_code = data[data_length - 10 - 2] <<8 | data[data_length - 10 - 1];
//ntohs(data + data_length - 10 - 2);
printf("set to: %04X\n", *ret_code);
if(data[0] == 0x87) {
uint8_t do87_length = data[1] - 1;
mrtd_bac_decrypt(data + 3, do87_length, key_enc, output);
}
mrtd_bac_mac_ctx ctx;
mrtd_bac_mac_init(&ctx, key_mac);
uint64_t ssc_n = htonll(ssc);
mrtd_bac_mac_update(&ctx, (uint8_t*)&ssc_n, 8);
mrtd_bac_mac_update(&ctx, data, data_length - 10); // 10 = len(DO'8E) = len(header + length + MAC) = 1 + 1 + 8
uint8_t mac_calc[8];
mrtd_bac_mac_finalize(&ctx, mac_calc);
if(memcmp(mac_calc, data + data_length - 8, 8)) {
printf( "SM MAC failed\r\n");
for(uint8_t i=0; i<8; ++i) {
printf("%02X <=> %02X\r\n", mac_calc[i], data[data_length - 8 + i]);
}
return false;
}
return true;
@@ -180,6 +221,7 @@ bool mrtd_bac_mac_init(mrtd_bac_mac_ctx* ctx, uint8_t key[16]) {
}
bool mrtd_bac_mac_update(mrtd_bac_mac_ctx* ctx, const uint8_t* data, size_t data_length) {
//printf("MAC add %d: ", data_length); print_hex(data, data_length); printf("\n");
size_t data_idx = 0;
//uint8_t* xormac = ctx->xormac;
@@ -198,7 +240,7 @@ bool mrtd_bac_mac_update(mrtd_bac_mac_ctx* ctx, const uint8_t* data, size_t data
}
mbedtls_des_crypt_ecb(&ctx->des, ctx->xormac, ctx->mac);
printf("DES1: %02X %02X %02X %02X %02X %02X %02X %02X\n",
printf("DES buf: %02X %02X %02X %02X %02X %02X %02X %02X\r\n",
ctx->buffer_in[0], ctx->buffer_in[1], ctx->buffer_in[2], ctx->buffer_in[3],
ctx->buffer_in[4], ctx->buffer_in[5], ctx->buffer_in[6], ctx->buffer_in[7]);
@@ -218,7 +260,7 @@ bool mrtd_bac_mac_update(mrtd_bac_mac_ctx* ctx, const uint8_t* data, size_t data
}
mbedtls_des_crypt_ecb(&ctx->des, ctx->xormac, ctx->mac);
printf("DES1: %02X %02X %02X %02X %02X %02X %02X %02X\n",
printf("DES add: %02X %02X %02X %02X %02X %02X %02X %02X\r\n",
data[data_idx - 8 + 0], data[data_idx - 8 + 1], data[data_idx - 8 + 2], data[data_idx - 8 + 3],
data[data_idx - 8 + 4], data[data_idx - 8 + 5], data[data_idx - 8 + 6], data[data_idx - 8 + 7]);
@@ -277,7 +319,7 @@ bool mrtd_bac_mac(const uint8_t* data, size_t data_length, uint8_t* key, uint8_t
}
mbedtls_des_crypt_ecb(&ctx, xormac, mac);
printf("DES1: %02X %02X %02X %02X %02X %02X %02X %02X\n",
printf("DES1: %02X %02X %02X %02X %02X %02X %02X %02X\r\n",
xormac[0], xormac[1], xormac[2], xormac[3],
xormac[4], xormac[5], xormac[6], xormac[7]);
}
@@ -318,6 +360,8 @@ size_t mrtd_protect_apdu(uint8_t cla, uint8_t ins, uint8_t p1, uint8_t p2, uint8
mrtd_bac_mac_ctx mac_ctx;
mrtd_bac_mac_init(&mac_ctx, key_mac);
uint64_t ssc_n = htonll(ssc);
printf("ssc: %016llx\r\n", ssc);
//printf("ssc_n: "); print_hex(ssc_n, 8); printf("\n");
mrtd_bac_mac_update(&mac_ctx, (uint8_t*)&ssc_n, 8);
// Mask cla
@@ -335,10 +379,10 @@ size_t mrtd_protect_apdu(uint8_t cla, uint8_t ins, uint8_t p1, uint8_t p2, uint8
// Build DO'87
// TODO: condition on data presence
{
// TODO: if ins is odd, use 0x85
if(lc > 0) {
size_t newlength = ((lc+8)/8)*8;
uint8_t padded[newlength];
size_t idx_do87 = idx;
output[idx++] = 0x87; // Header
output[idx++] = newlength + 1; // Length
@@ -350,26 +394,31 @@ size_t mrtd_protect_apdu(uint8_t cla, uint8_t ins, uint8_t p1, uint8_t p2, uint8
mrtd_bac_encrypt(padded, newlength, key_enc, output + idx);
idx += newlength;
mrtd_bac_mac_update(&mac_ctx, output + idx_do87, idx - idx_do87);
}
// Build DO'97
if(le >= 0) {
output[idx++] = 0x97; // Header
output[idx++] = 0x01; // Length
output[idx++] = le;
}
mrtd_bac_mac_update(&mac_ctx, output + idx_lc + 1, idx - idx_lc - 1);
// Build DO'8E
// TODO: conditions?
{
output[idx++] = 0x8E; // Header
output[idx++] = 0x08; // Length
printf("idx: %d\n", idx);
uint8_t mac[8];
mrtd_bac_mac_finalize(&mac_ctx, output + idx);
idx += 8;
printf("MAC: ");
for(uint8_t i=0; i<8; ++i) {
printf("%02X ", mac[i]);
printf("%02X ", output[idx - 8 + i]);
}
printf("\n");
printf("\r\n");
}
output[idx_lc] = idx - idx_lc - 1; // Set Lc
+159 -4
View File
@@ -1,7 +1,10 @@
#include <stdio.h>
#include <stdlib.h>
#include <mbedtls/sha1.h>
#include <mbedtls/des.h>
#include "applications/main/nfc/test_bac_creds.h" //TODO: remove
#include "lib/nfc/protocols/mrtd_helpers.h"
// gcc -o test_mrtd_helpers -Wall -Ilib/mbedtls/include -Itoolchain/x86_64-linux/arm-none-eabi/include/ lib/nfc/protocols/mrtd_helpers.c lib/mbedtls/library/sha1.c lib/mbedtls/library/des.c lib/mbedtls/library/platform_util.c test_mrtd_helpers.c
@@ -209,12 +212,58 @@ void test_mrtd_bac_mac_calls(uint8_t* data, size_t data_length, uint8_t* key, ui
}
}
void test_mrtd_bac_mac_steps(uint8_t* data, size_t data_length, uint8_t* key, uint8_t* exp_output, size_t exp_output_length) {
mrtd_bac_mac_ctx ctx;
printf("A\n");
if(!mrtd_bac_mac_init(&ctx, key)) {
printf("ERROR mrtd_bac_mac_init (steps)\n");
return;
}
if(!mrtd_bac_mac_update(&ctx, data, 8)) {
printf("ERROR mrtd_bac_mac_update 1 (steps)\n");
}
if(!mrtd_bac_mac_update(&ctx, data + 8, 4)) {
printf("ERROR mrtd_bac_mac_update 2 (steps)\n");
}
if(!mrtd_bac_mac_pad(&ctx)) {
printf("ERROR mrtd_bac_mac_pad (steps)\n");
}
if(!mrtd_bac_mac_update(&ctx, data + 16, 11)) {
printf("ERROR mrtd_bac_mac_update 3 (steps)\n");
}
uint8_t mac[8];
if(!mrtd_bac_mac_finalize(&ctx, mac)) {
printf("ERROR mrtd_bac_mac_finalize (steps)\n");
return;
}
if(memcmp(exp_output, mac, exp_output_length)) {
printf(COLOR_RED "FAILED - mrtd_bac_mac (steps), expected output:\n");
print_hex(exp_output, exp_output_length);
printf(" is:\n");
print_hex(mac, 8);
printf(COLOR_RESET "\n");
return;
} else {
printf(COLOR_GREEN "SUCCESS - mrtd_bac_mac (steps) output: ");
print_hex(mac, 8);
printf(COLOR_RESET "\n");
}
}
void test_mrtd_bac_decrypt_verify(const uint8_t* data, size_t data_length, uint8_t* key_enc, uint8_t* key_mac, uint8_t* exp_output, size_t exp_output_length, bool should_verify) {
uint8_t buffer[256];
bool result = mrtd_bac_decrypt_verify(data, data_length, key_enc, key_mac, buffer);
if(result != should_verify) {
printf(COLOR_RED "FAILED - mrtd_bac_decrypt_verify, expected verify: %d, but is: %d\n", should_verify, result);
printf(COLOR_RED "FAILED - mrtd_bac_decrypt_verify, expected verify: %d, but is: %d\n" COLOR_RESET, should_verify, result);
return;
}
@@ -223,6 +272,7 @@ void test_mrtd_bac_decrypt_verify(const uint8_t* data, size_t data_length, uint8
print_hex(exp_output, exp_output_length);
printf(" is:\n");
print_hex(buffer, 32);
printf(COLOR_RESET "\n");
return;
}
@@ -231,6 +281,35 @@ void test_mrtd_bac_decrypt_verify(const uint8_t* data, size_t data_length, uint8
printf(COLOR_RESET "\n");
}
void test_mrtd_bac_decrypt_verify_sm(const uint8_t* data, size_t data_length, uint8_t* key_enc, uint8_t* key_mac, uint64_t ssc, uint8_t* exp_output, size_t exp_output_length, bool should_verify) {
uint8_t buffer[256];
uint16_t ret_code;
bool result = mrtd_bac_decrypt_verify_sm(data, data_length, key_enc, key_mac, ssc, buffer, &ret_code);
if(result != should_verify) {
printf(COLOR_RED "FAILED - mrtd_bac_decrypt_verify_sm, expected verify: %d, but is: %d\n" COLOR_RESET, should_verify, result);
return;
}
if(ret_code != 0x9000) {
printf(COLOR_RED "FAILED - mrtd_bac_decrypt_verify_sm, expected ret_code: %04X, but is: %04X\n" COLOR_RESET, 0x9000, ret_code);
return;
}
if(memcmp(exp_output, buffer, exp_output_length)) {
printf(COLOR_RED "FAILED - mrtd_bac_decrypt_verify_sm, expected output:\n");
print_hex(exp_output, exp_output_length);
printf(" is:\n");
print_hex(buffer, 32);
printf(COLOR_RESET "\n");
return;
}
printf(COLOR_GREEN "SUCCESS - mrtd_bac_decrypt_verify_sm output: ");
print_hex(buffer, exp_output_length);
printf(COLOR_RESET "\n");
}
void test_mrtd_ssc_from_data(const uint8_t* rnd_ic, const uint8_t* rnd_ifd, uint64_t exp_ssc) {
uint64_t ssc_long = mrtd_ssc_from_data(rnd_ic, rnd_ifd);
@@ -253,10 +332,11 @@ void test_mrtd_protect_apdu(uint8_t cla, uint8_t ins, uint8_t p1, uint8_t p2, ui
}
if(memcmp(buffer, exp_output, ret)) {
printf(COLOR_RED "FAILED - mrtd_protect_apdu, expected output:\n" COLOR_RESET);
printf(COLOR_RED "FAILED - mrtd_protect_apdu, expected output:\n");
print_hex(exp_output, exp_output_length);
printf(" is:\n");
print_hex(buffer, ret);
printf("\n" COLOR_RESET);
return;
}
@@ -349,9 +429,84 @@ int main(int argc, char** argv) {
uint8_t* rnd_ic = (uint8_t*)"\x46\x08\xF9\x19\x88\x70\x22\x12";
uint8_t* rnd_ifd = (uint8_t*)"\x78\x17\x23\x86\x0C\x06\xC2\x26";
test_mrtd_ssc_from_data(rnd_ic, rnd_ifd, 0x887022120C06C226);
uint64_t ssc = 0x887022120C06C226;
test_mrtd_ssc_from_data(rnd_ic, rnd_ifd, ssc);
test_mrtd_protect_apdu(0x00, 0xA4, 0x02, 0x0C, 0x02, "\x01\x1e", -1, ks_enc, ks_mac, 0x887022120C06C227, (uint8_t*)"\x0C\xA4\x02\x0C\x15\x87\x09\x01\x63\x75\x43\x29\x08\xC0\x44\xF6\x8E\x08\xBF\x8B\x92\xD6\x35\xFF\x24\xF8\x00", 27);
ssc++;
test_mrtd_protect_apdu(0x00, 0xA4, 0x02, 0x0C, 0x02, "\x01\x1e", -1, ks_enc, ks_mac, ssc, (uint8_t*)"\x0C\xA4\x02\x0C\x15\x87\x09\x01\x63\x75\x43\x29\x08\xC0\x44\xF6\x8E\x08\xBF\x8B\x92\xD6\x35\xFF\x24\xF8\x00", 27);
ssc++; // Increment for decrypt, verify
test_mrtd_bac_decrypt_verify_sm((uint8_t*)"\x99\x02\x90\x00\x8E\x08\xFA\x85\x5A\x5D\x4C\x50\xA8\xED", 14, ks_enc, ks_mac, ssc, NULL, 0, 1);
ssc++; // Increment for encrypt, sign
test_mrtd_protect_apdu(0x00, 0xB0, 0x00, 0x00, 0x00, NULL, 0x04, ks_enc, ks_mac, ssc, (uint8_t*)"\x0C\xB0\x00\x00\x0D\x97\x01\x04\x8E\x08\xED\x67\x05\x41\x7E\x96\xBA\x55\x00", 19);
ssc++; // Increment for decrypt, verify
test_mrtd_bac_decrypt_verify_sm((uint8_t*)"\x87\x09\x01\x9F\xF0\xEC\x34\xF9\x92\x26\x51\x99\x02\x90\x00\x8E\x08\xAD\x55\xCC\x17\x14\x0B\x2D\xED", 25, ks_enc, ks_mac, ssc, (uint8_t*)"\x60\x14\x5F\x01", 4, 1);
ssc++; // Increment for encrypt, sign
test_mrtd_protect_apdu(0x00, 0xB0, 0x00, 0x04, 0x00, NULL, 0x12, ks_enc, ks_mac, ssc, (uint8_t*)"\x0C\xB0\x00\x04\x0D\x97\x01\x12\x8E\x08\x2E\xA2\x8A\x70\xF3\xC7\xB5\x35\x00", 19);
// Verify working against mrtdreader
/*
printf("=====================================\n\n");
//TODO: set auth data
MrtdAuthData auth;
auth.birth_date = TODO_REMOVE_ID_DOB;
auth.expiry_date = TODO_REMOVE_ID_DOE;
memcpy(auth.doc_number, TODO_REMOVE_ID_DOC, 9);
uint8_t kenc[16];
uint8_t kmac[16];
mrtd_bac_keys(&auth, kenc, kmac);
printf("kenc: "); print_hex(kenc, 16); printf("\n");
printf("kmac: "); print_hex(kmac, 16); printf("\n");
uint8_t buffer[32]; // RND.IC || RND.IFD || KIC
//TODO: set challenge rx
mrtd_bac_decrypt_verify((uint8_t*)"\x3F\xD4\x6B\xA9\xFF\x29\x4B\xF6\x77\x4E\x8F\x1E\xEC\xAE\x2E\x67\xDB\xE7\x70\x53\xB3\xAD\x9C\xDC\xED\x6E\xED\xD6\x04\x2E\xB7\x6B\x74\xDE\x2A\xFB\x4B\xC0\xF7\x24", 40, kenc, kmac, buffer);
//TODO: set kifd
uint8_t *kifd = "\x9F\x10\x40\xEA\x7F\xAE\xF8\xC3\x09\x6E\xAE\x07\x66\x95\x3F\xDC";
printf("buffer: "); print_hex(buffer, 32); printf("\n");
// 8F763C0B1CDF9F9D|0983F7C136155248|7A705FD193C6A6328C42264A3804002C
rnd_ic = buffer;
rnd_ifd = buffer+8;
uint8_t *kic = buffer+16;
printf("kifd: "); print_hex(kifd, 16); printf("\n");
printf("kicc: "); print_hex(kic, 16); printf("\n");
uint8_t kseed[16];
for(uint8_t i=0; i<16; ++i) {
kseed[i] = kifd[i] ^ kic[i];
printf("seed %2d = %02X ^ %02X = %02X\r\n", i, kifd[i], kic[i], kseed[i]);
}
printf("kseed: "); print_hex(kseed, 16); printf("\n");
ks_enc = malloc(16);
ks_mac = malloc(16);
mrtd_bac_keys_from_seed(kseed, ks_enc, ks_mac);
printf("ks_enc: "); print_hex(ks_enc, 16); printf("\n");
printf("ks_mac: "); print_hex(ks_mac, 16); printf("\n");
printf("rnd_ic: "); print_hex(rnd_ic, 16); printf("\n");
printf("rnd_ifd: "); print_hex(rnd_ifd, 16); printf("\n");
uint64_t ssc = mrtd_ssc_from_data(rnd_ic, rnd_ifd);
printf("ssc: %016lx", ssc);
ssc++;
//TODO: set challenge TX for verification
test_mrtd_protect_apdu(0x00, 0xA4, 0x02, 0x0C, 0x02, "\x01\x1e", -1, ks_enc, ks_mac, ssc,
(uint8_t*)"\x0C\xA4\x02\x0C\x15\x87\x09\x01\xC5\x4E\x76\x3A\xD1\x89\xF0\xFA\x8E\x08\x1F\x03\xC2\xB6\xCE\x8A\xE1\x53\x00", 27);
*/
return 0;
}