mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-03-01 21:27:22 -08:00
emrtd: Push initial code
Can only read EF_CardAccess currently, but has abstractions for selecting AIDs and reading files, which was the Hard Part so far Based heavily on mrpkey by rfidiot
This commit is contained in:
parent
0c0cdab17d
commit
bee075ad09
@ -228,6 +228,7 @@ set (TARGET_SOURCES
|
||||
${PM3_ROOT}/client/src/cmdhf15.c
|
||||
${PM3_ROOT}/client/src/cmdhfcryptorf.c
|
||||
${PM3_ROOT}/client/src/cmdhfepa.c
|
||||
${PM3_ROOT}/client/src/cmdhfemrtd.c
|
||||
${PM3_ROOT}/client/src/cmdhffelica.c
|
||||
${PM3_ROOT}/client/src/cmdhffido.c
|
||||
${PM3_ROOT}/client/src/cmdhficlass.c
|
||||
|
@ -469,6 +469,7 @@ SRCS = aiddesfire.c \
|
||||
cmdhf15.c \
|
||||
cmdhfcryptorf.c \
|
||||
cmdhfepa.c \
|
||||
cmdhfemrtd.c \
|
||||
cmdhffelica.c \
|
||||
cmdhffido.c \
|
||||
cmdhficlass.c \
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "cmdhf14b.h" // ISO14443-B
|
||||
#include "cmdhf15.h" // ISO15693
|
||||
#include "cmdhfepa.h"
|
||||
#include "cmdhfemrtd.h" // eMRTD
|
||||
#include "cmdhflegic.h" // LEGIC
|
||||
#include "cmdhficlass.h" // ICLASS
|
||||
#include "cmdhfmf.h" // CLASSIC
|
||||
@ -357,24 +358,25 @@ int CmdHFPlot(const char *Cmd) {
|
||||
static command_t CommandTable[] = {
|
||||
|
||||
{"--------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("High Frequency") " -----------------------"},
|
||||
{"14a", CmdHF14A, AlwaysAvailable, "{ ISO14443A RFIDs... }"},
|
||||
{"14b", CmdHF14B, AlwaysAvailable, "{ ISO14443B RFIDs... }"},
|
||||
{"15", CmdHF15, AlwaysAvailable, "{ ISO15693 RFIDs... }"},
|
||||
// {"cryptorf", CmdHFCryptoRF, AlwaysAvailable, "{ CryptoRF RFIDs... }"},
|
||||
{"epa", CmdHFEPA, AlwaysAvailable, "{ German Identification Card... }"},
|
||||
{"felica", CmdHFFelica, AlwaysAvailable, "{ ISO18092 / FeliCa RFIDs... }"},
|
||||
{"fido", CmdHFFido, AlwaysAvailable, "{ FIDO and FIDO2 authenticators... }"},
|
||||
{"iclass", CmdHFiClass, AlwaysAvailable, "{ ICLASS RFIDs... }"},
|
||||
{"legic", CmdHFLegic, AlwaysAvailable, "{ LEGIC RFIDs... }"},
|
||||
{"lto", CmdHFLTO, AlwaysAvailable, "{ LTO Cartridge Memory RFIDs... }"},
|
||||
{"mf", CmdHFMF, AlwaysAvailable, "{ MIFARE RFIDs... }"},
|
||||
{"mfp", CmdHFMFP, AlwaysAvailable, "{ MIFARE Plus RFIDs... }"},
|
||||
{"mfu", CmdHFMFUltra, AlwaysAvailable, "{ MIFARE Ultralight RFIDs... }"},
|
||||
{"mfdes", CmdHFMFDes, AlwaysAvailable, "{ MIFARE Desfire RFIDs... }"},
|
||||
{"st", CmdHF_ST, AlwaysAvailable, "{ ST Rothult RFIDs... }"},
|
||||
{"thinfilm", CmdHFThinfilm, AlwaysAvailable, "{ Thinfilm RFIDs... }"},
|
||||
{"topaz", CmdHFTopaz, AlwaysAvailable, "{ TOPAZ (NFC Type 1) RFIDs... }"},
|
||||
{"waveshare", CmdHFWaveshare, AlwaysAvailable, "{ Waveshare NFC ePaper... }"},
|
||||
{"14a", CmdHF14A, AlwaysAvailable, "{ ISO14443A RFIDs... }"},
|
||||
{"14b", CmdHF14B, AlwaysAvailable, "{ ISO14443B RFIDs... }"},
|
||||
{"15", CmdHF15, AlwaysAvailable, "{ ISO15693 RFIDs... }"},
|
||||
// {"cryptorf", CmdHFCryptoRF, AlwaysAvailable, "{ CryptoRF RFIDs... }"},
|
||||
{"epa", CmdHFEPA, AlwaysAvailable, "{ German Identification Card... }"},
|
||||
{"emrtd", CmdHFeMRTD, AlwaysAvailable, "{ Machine Readable Travel Document... }"},
|
||||
{"felica", CmdHFFelica, AlwaysAvailable, "{ ISO18092 / FeliCa RFIDs... }"},
|
||||
{"fido", CmdHFFido, AlwaysAvailable, "{ FIDO and FIDO2 authenticators... }"},
|
||||
{"iclass", CmdHFiClass, AlwaysAvailable, "{ ICLASS RFIDs... }"},
|
||||
{"legic", CmdHFLegic, AlwaysAvailable, "{ LEGIC RFIDs... }"},
|
||||
{"lto", CmdHFLTO, AlwaysAvailable, "{ LTO Cartridge Memory RFIDs... }"},
|
||||
{"mf", CmdHFMF, AlwaysAvailable, "{ MIFARE RFIDs... }"},
|
||||
{"mfp", CmdHFMFP, AlwaysAvailable, "{ MIFARE Plus RFIDs... }"},
|
||||
{"mfu", CmdHFMFUltra, AlwaysAvailable, "{ MIFARE Ultralight RFIDs... }"},
|
||||
{"mfdes", CmdHFMFDes, AlwaysAvailable, "{ MIFARE Desfire RFIDs... }"},
|
||||
{"st", CmdHF_ST, AlwaysAvailable, "{ ST Rothult RFIDs... }"},
|
||||
{"thinfilm", CmdHFThinfilm, AlwaysAvailable, "{ Thinfilm RFIDs... }"},
|
||||
{"topaz", CmdHFTopaz, AlwaysAvailable, "{ TOPAZ (NFC Type 1) RFIDs... }"},
|
||||
{"waveshare", CmdHFWaveshare, AlwaysAvailable, "{ Waveshare NFC ePaper... }"},
|
||||
{"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("General") " ---------------------"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"list", CmdTraceList, AlwaysAvailable, "List protocol data in trace buffer"},
|
||||
|
247
client/src/cmdhfemrtd.c
Normal file
247
client/src/cmdhfemrtd.c
Normal file
@ -0,0 +1,247 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2020 A. Ozkal
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// High frequency Electronic Machine Readable Travel Document commands
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "cmdhfemrtd.h"
|
||||
#include <ctype.h>
|
||||
#include "fileutils.h"
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h" // clearCommandBuffer
|
||||
#include "cmdtrace.h"
|
||||
#include "cliparser.h"
|
||||
#include "crc16.h"
|
||||
#include "cmdhf14a.h"
|
||||
#include "protocols.h" // definitions of ISO14A/7816 protocol
|
||||
#include "emv/apduinfo.h" // GetAPDUCodeDescription
|
||||
|
||||
#define TIMEOUT 2000
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static uint16_t get_sw(uint8_t *d, uint8_t n) {
|
||||
if (n < 2)
|
||||
return 0;
|
||||
|
||||
n -= 2;
|
||||
return d[n] * 0x0100 + d[n + 1];
|
||||
}
|
||||
|
||||
static int select_aid(const char *select_by, const char *file_id) {
|
||||
bool activate_field = true;
|
||||
bool keep_field_on = true;
|
||||
uint8_t response[PM3_CMD_DATA_SIZE];
|
||||
int resplen = 0;
|
||||
|
||||
size_t file_id_len = strlen(file_id) / 2;
|
||||
|
||||
char cmd[50];
|
||||
sprintf(cmd, "00A4%s0C%02lu%s", select_by, file_id_len, file_id);
|
||||
PrintAndLogEx(INFO, "Sending: %s", cmd);
|
||||
|
||||
uint8_t aSELECT_AID[80];
|
||||
int aSELECT_AID_n = 0;
|
||||
param_gethex_to_eol(cmd, 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n);
|
||||
int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||
if (res) {
|
||||
DropField();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (resplen < 2) {
|
||||
DropField();
|
||||
return false;
|
||||
}
|
||||
PrintAndLogEx(INFO, "Resp: %s", sprint_hex(response, resplen));
|
||||
|
||||
uint16_t sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLogEx(ERR, "Selecting Card Access aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int asn1datalength(uint8_t *datain, int datainlen) {
|
||||
char* dataintext = sprint_hex_inrow(datain, datainlen);
|
||||
|
||||
// lazy - https://stackoverflow.com/a/4214350/3286892
|
||||
char subbuff[8];
|
||||
memcpy(subbuff, &dataintext[2], 2);
|
||||
subbuff[2] = '\0';
|
||||
|
||||
int thing = (int)strtol(subbuff, NULL, 16);
|
||||
if (thing <= 0x7f) {
|
||||
return thing;
|
||||
} else if (thing == 0x81) {
|
||||
memcpy(subbuff, &dataintext[2], 3);
|
||||
subbuff[3] = '\0';
|
||||
return (int)strtol(subbuff, NULL, 16);
|
||||
} else if (thing == 0x82) {
|
||||
memcpy(subbuff, &dataintext[2], 5);
|
||||
subbuff[5] = '\0';
|
||||
return (int)strtol(subbuff, NULL, 16);
|
||||
} else if (thing == 0x83) {
|
||||
memcpy(subbuff, &dataintext[2], 7);
|
||||
subbuff[7] = '\0';
|
||||
return (int)strtol(subbuff, NULL, 16);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int asn1fieldlength(uint8_t *datain, int datainlen) {
|
||||
char* dataintext = sprint_hex_inrow(datain, datainlen);
|
||||
|
||||
// lazy - https://stackoverflow.com/a/4214350/3286892
|
||||
char subbuff[8];
|
||||
memcpy(subbuff, &dataintext[2], 2);
|
||||
subbuff[2] = '\0';
|
||||
|
||||
int thing = (int)strtol(subbuff, NULL, 16);
|
||||
if (thing <= 0x7f) {
|
||||
return 2;
|
||||
} else if (thing == 0x81) {
|
||||
return 4;
|
||||
} else if (thing == 0x82) {
|
||||
return 6;
|
||||
} else if (thing == 0x83) {
|
||||
return 8;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int _read_binary(int offset, int bytes_to_read, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
|
||||
bool activate_field = false;
|
||||
bool keep_field_on = true;
|
||||
uint8_t response[PM3_CMD_DATA_SIZE];
|
||||
int resplen = 0;
|
||||
|
||||
char cmd[50];
|
||||
sprintf(cmd, "00B0%04i%02i", offset, bytes_to_read);
|
||||
PrintAndLogEx(INFO, "Sending: %s", cmd);
|
||||
|
||||
uint8_t aREAD_BINARY[80];
|
||||
int aREAD_BINARY_n = 0;
|
||||
param_gethex_to_eol(cmd, 0, aREAD_BINARY, sizeof(aREAD_BINARY), &aREAD_BINARY_n);
|
||||
int res = ExchangeAPDU14a(aREAD_BINARY, aREAD_BINARY_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||
if (res) {
|
||||
DropField();
|
||||
return false;
|
||||
}
|
||||
PrintAndLogEx(INFO, "Resp: %s", sprint_hex(response, resplen));
|
||||
|
||||
// drop sw
|
||||
memcpy(dataout, &response, resplen - 2);
|
||||
*dataoutlen = (resplen - 2);
|
||||
|
||||
uint16_t sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLogEx(ERR, "Reading binary failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
DropField();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int read_file(uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
|
||||
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, sizeof(response), &resplen)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int datalen = asn1datalength(response, resplen);
|
||||
int readlen = datalen - (3 - asn1fieldlength(response, resplen) / 2);
|
||||
int offset = 4;
|
||||
int toread;
|
||||
|
||||
while (readlen > 0) {
|
||||
toread = readlen;
|
||||
if (readlen > 118) {
|
||||
toread = 118;
|
||||
}
|
||||
|
||||
if (!_read_binary(offset, toread, tempresponse, sizeof(tempresponse), &tempresplen)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(&response[resplen], &tempresponse, tempresplen);
|
||||
offset += toread;
|
||||
readlen -= toread;
|
||||
resplen += tempresplen;
|
||||
}
|
||||
|
||||
memcpy(dataout, &response, resplen);
|
||||
*dataoutlen = resplen;
|
||||
return true;
|
||||
}
|
||||
|
||||
int infoHF_EMRTD(void) {
|
||||
// const uint8_t *data
|
||||
if (select_aid("02", "011c")) {
|
||||
uint8_t response[PM3_CMD_DATA_SIZE];
|
||||
int resplen = 0;
|
||||
|
||||
read_file(response, sizeof(response), &resplen);
|
||||
|
||||
PrintAndLogEx(INFO, "EF_CardAccess: %s", sprint_hex(response, resplen));
|
||||
} else {
|
||||
PrintAndLogEx(INFO, "PACE unsupported. Will not read EF_CardAccess.");
|
||||
}
|
||||
|
||||
DropField();
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int cmd_hf_emrtd_info(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf emrtd info",
|
||||
"Get info about an eMRTD",
|
||||
"hf emrtd info"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
return infoHF_EMRTD();
|
||||
}
|
||||
|
||||
static int cmd_hf_emrtd_list(const char *Cmd) {
|
||||
char args[128] = {0};
|
||||
if (strlen(Cmd) == 0) {
|
||||
snprintf(args, sizeof(args), "-t 7816");
|
||||
} else {
|
||||
strncpy(args, Cmd, sizeof(args) - 1);
|
||||
}
|
||||
return CmdTraceList(args);
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"info", cmd_hf_emrtd_info, IfPm3Iso14443a, "Tag information"},
|
||||
{"list", cmd_hf_emrtd_list, AlwaysAvailable, "List ISO 14443A/7816 history"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
static int CmdHelp(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CmdsHelp(CommandTable);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int CmdHFeMRTD(const char *Cmd) {
|
||||
clearCommandBuffer();
|
||||
return CmdsParse(CommandTable, Cmd);
|
||||
}
|
19
client/src/cmdhfemrtd.h
Normal file
19
client/src/cmdhfemrtd.h
Normal file
@ -0,0 +1,19 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2020 A. Ozkal
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// High frequency Electronic Machine Readable Travel Document commands
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef CMDHFEMRTD_H__
|
||||
#define CMDHFEMRTD_H__
|
||||
|
||||
#include "common.h"
|
||||
|
||||
int CmdHFeMRTD(const char *Cmd);
|
||||
|
||||
int infoHF_EMRTD(void);
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user