emrtd: Join secure and insecure reads

This commit is contained in:
Ave 2020-12-14 17:45:53 +03:00
commit eaea632eb3

View file

@ -269,7 +269,6 @@ static void retail_mac(uint8_t *key, uint8_t *input, int inputlen, uint8_t *outp
memcpy(output, intermediate_des, 8); memcpy(output, intermediate_des, 8);
} }
static void deskey(uint8_t *seed, const uint8_t *type, int length, uint8_t *dataout) { static void deskey(uint8_t *seed, const uint8_t *type, int length, uint8_t *dataout) {
PrintAndLogEx(DEBUG, "seed: %s", sprint_hex_inrow(seed, 16)); PrintAndLogEx(DEBUG, "seed: %s", sprint_hex_inrow(seed, 16));
@ -324,42 +323,6 @@ static int _read_binary(int offset, int bytes_to_read, uint8_t *dataout, int *da
return exchange_commands(cmd, dataout, dataoutlen, false, true, use_14b); return exchange_commands(cmd, dataout, dataoutlen, false, true, use_14b);
} }
static int read_file(uint8_t *dataout, int *dataoutlen, bool use_14b) {
uint8_t response[PM3_CMD_DATA_SIZE];
int resplen = 0;
uint8_t tempresponse[PM3_CMD_DATA_SIZE];
int tempresplen = 0;
if (!_read_binary(0, 4, response, &resplen, use_14b)) {
return false;
}
int datalen = asn1datalength(response, resplen, 1);
int readlen = datalen - (3 - asn1fieldlength(response, resplen, 1));
int offset = 4;
int toread;
while (readlen > 0) {
toread = readlen;
if (readlen > 118) {
toread = 118;
}
if (!_read_binary(offset, toread, tempresponse, &tempresplen, use_14b)) {
return false;
}
memcpy(&response[resplen], &tempresponse, tempresplen);
offset += toread;
readlen -= toread;
resplen += tempresplen;
}
memcpy(dataout, &response, resplen);
*dataoutlen = resplen;
return true;
}
static void bump_ssc(uint8_t *ssc) { static void bump_ssc(uint8_t *ssc) {
PrintAndLogEx(DEBUG, "ssc-b: %s", sprint_hex_inrow(ssc, 8)); PrintAndLogEx(DEBUG, "ssc-b: %s", sprint_hex_inrow(ssc, 8));
for (int i = 7; i > 0; i--) { for (int i = 7; i > 0; i--) {
@ -553,21 +516,28 @@ static bool _secure_read_binary_decrypt(uint8_t *kenc, uint8_t *kmac, uint8_t *s
return true; return true;
} }
static int secure_read_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, uint8_t *dataout, int *dataoutlen, bool use_14b) {
// TODO: join this with regular read file static int read_file(uint8_t *dataout, int *dataoutlen, uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, bool use_14b) {
uint8_t response[25000]; uint8_t response[35000];
int resplen = 0; int resplen = 0;
uint8_t tempresponse[500]; uint8_t tempresponse[500];
int tempresplen = 0; int tempresplen = 0;
int toread = 4;
int offset = 0;
if (!_secure_read_binary_decrypt(kenc, kmac, ssc, 0, 4, response, &resplen, use_14b)) { if (kenc == NULL) {
if (_read_binary(offset, toread, response, &resplen, use_14b) == false) {
return false; return false;
} }
} else {
if (_secure_read_binary_decrypt(kenc, kmac, ssc, offset, toread, response, &resplen, use_14b) == false) {
return false;
}
}
int datalen = asn1datalength(response, resplen, 1); int datalen = asn1datalength(response, resplen, 1);
int readlen = datalen - (3 - asn1fieldlength(response, resplen, 1)); int readlen = datalen - (3 - asn1fieldlength(response, resplen, 1));
int offset = 4; offset = 4;
int toread;
while (readlen > 0) { while (readlen > 0) {
toread = readlen; toread = readlen;
@ -575,9 +545,15 @@ static int secure_read_file(uint8_t *kenc, uint8_t *kmac, uint8_t *ssc, uint8_t
toread = 118; toread = 118;
} }
if (!_secure_read_binary_decrypt(kenc, kmac, ssc, offset, toread, tempresponse, &tempresplen, use_14b)) { if (kenc == NULL) {
if (_read_binary(offset, toread, tempresponse, &tempresplen, use_14b) == false) {
return false; return false;
} }
} else {
if (_secure_read_binary_decrypt(kenc, kmac, ssc, offset, toread, tempresponse, &tempresplen, use_14b) == false) {
return false;
}
}
memcpy(response + resplen, tempresponse, tempresplen); memcpy(response + resplen, tempresponse, tempresplen);
offset += toread; offset += toread;
@ -712,7 +688,7 @@ static bool dump_file(uint8_t *ks_enc, uint8_t *ks_mac, uint8_t *ssc, const char
return false; return false;
} }
if (secure_read_file(ks_enc, ks_mac, ssc, response, &resplen, use_14b) == false) { if (read_file(response, &resplen, ks_enc, ks_mac, ssc, use_14b) == false) {
PrintAndLogEx(ERR, "Failed to read %s.", name); PrintAndLogEx(ERR, "Failed to read %s.", name);
DropField(); DropField();
return false; return false;
@ -738,7 +714,7 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) {
uint8_t kenc[50]; uint8_t kenc[50];
uint8_t kmac[50]; uint8_t kmac[50];
int resplen = 0; int resplen = 0;
// bool BAC = true; bool BAC = false;
uint8_t S[32]; uint8_t S[32];
uint8_t rnd_ifd[8], k_ifd[16]; uint8_t rnd_ifd[8], k_ifd[16];
rng(8, rnd_ifd); rng(8, rnd_ifd);
@ -775,7 +751,7 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) {
// Select and read EF_CardAccess // Select and read EF_CardAccess
if (select_file(P1_SELECT_BY_EF, EF_CARDACCESS, use_14b)) { if (select_file(P1_SELECT_BY_EF, EF_CARDACCESS, use_14b)) {
read_file(response, &resplen, use_14b); read_file(response, &resplen, NULL, NULL, NULL, use_14b);
PrintAndLogEx(INFO, "Read EF_CardAccess, len: %i.", resplen); PrintAndLogEx(INFO, "Read EF_CardAccess, len: %i.", resplen);
PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen)); PrintAndLogEx(DEBUG, "Contents (may be incomplete over 2k chars): %s", sprint_hex_inrow(response, resplen));
} else { } else {
@ -791,21 +767,23 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) {
// Select EF_COM // Select EF_COM
if (select_file(P1_SELECT_BY_EF, EF_COM, use_14b) == false) { if (select_file(P1_SELECT_BY_EF, EF_COM, use_14b) == false) {
// BAC = true; BAC = true;
PrintAndLogEx(INFO, "Basic Access Control is enforced. Will attempt external authentication."); PrintAndLogEx(INFO, "Basic Access Control is enforced. Will attempt external authentication.");
} else { } else {
// BAC = false; BAC = false;
// Select EF_DG1 // Select EF_DG1
select_file(P1_SELECT_BY_EF, EF_DG1, use_14b); select_file(P1_SELECT_BY_EF, EF_DG1, use_14b);
if (read_file(response, &resplen, use_14b) == false) { if (read_file(response, &resplen, NULL, NULL, NULL, use_14b) == false) {
// BAC = true; BAC = true;
PrintAndLogEx(INFO, "Basic Access Control is enforced. Will attempt external authentication."); PrintAndLogEx(INFO, "Basic Access Control is enforced. Will attempt external authentication.");
} else { } else {
// BAC = false; BAC = false;
PrintAndLogEx(INFO, "EF_DG1: %s", sprint_hex(response, resplen)); PrintAndLogEx(INFO, "EF_DG1: %s", sprint_hex(response, resplen));
} }
} }
if (BAC) {
// TODO: account for the case of no BAC // TODO: account for the case of no BAC
PrintAndLogEx(DEBUG, "doc: %s", documentnumber); PrintAndLogEx(DEBUG, "doc: %s", documentnumber);
PrintAndLogEx(DEBUG, "dob: %s", dob); PrintAndLogEx(DEBUG, "dob: %s", dob);
@ -819,7 +797,7 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) {
sprintf(kmrz, "%s%i%s%i%s%i", documentnumber, documentnumbercd, dob, dobcd, expiry, expirycd); sprintf(kmrz, "%s%i%s%i%s%i", documentnumber, documentnumbercd, dob, dobcd, expiry, expirycd);
PrintAndLogEx(DEBUG, "kmrz: %s", kmrz); PrintAndLogEx(DEBUG, "kmrz: %s", kmrz);
uint8_t kseed[16] = {0x00}; uint8_t kseed[16] = { 0x00 };
mbedtls_sha1((unsigned char *)kmrz, strlen(kmrz), kseed); mbedtls_sha1((unsigned char *)kmrz, strlen(kmrz), kseed);
PrintAndLogEx(DEBUG, "kseed: %s", sprint_hex_inrow(kseed, 16)); PrintAndLogEx(DEBUG, "kseed: %s", sprint_hex_inrow(kseed, 16));
@ -906,7 +884,7 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) {
return PM3_ESOFT; return PM3_ESOFT;
} }
if (secure_read_file(ks_enc, ks_mac, ssc, response, &resplen, use_14b) == false) { if (read_file(response, &resplen, ks_enc, ks_mac, ssc, use_14b) == false) {
PrintAndLogEx(ERR, "Failed to read EF_COM."); PrintAndLogEx(ERR, "Failed to read EF_COM.");
DropField(); DropField();
return PM3_ESOFT; return PM3_ESOFT;
@ -938,6 +916,7 @@ int dumpHF_EMRTD(char *documentnumber, char *dob, char *expiry) {
} }
dump_file(ks_enc, ks_mac, ssc, EF_SOD, "EF_SOD", use_14b); dump_file(ks_enc, ks_mac, ssc, EF_SOD, "EF_SOD", use_14b);
}
DropField(); DropField();
return PM3_SUCCESS; return PM3_SUCCESS;