From 7dadcc959fb7009b6e8bbde4a644aa2f7f1b7a98 Mon Sep 17 00:00:00 2001 From: Oleg Moiseenko Date: Wed, 10 Oct 2018 23:34:04 +0300 Subject: [PATCH 001/189] auth 14443-4 (#692) * AES authentication --- client/cmdhf14a.c | 89 ++++++++++++++++++++++++++++ client/cmdhf14a.h | 1 + client/cmdhfmf.c | 147 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 237 insertions(+) diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 94eb8ff3..a5de2e2a 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -648,6 +648,95 @@ void DropField() { SendCommand(&c); } +int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { + uint16_t cmdc = 0; + *dataoutlen = 0; + + if (activateField) { + UsbCommand resp; + + // Anticollision + SELECT card + UsbCommand ca = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT | ISO14A_CLEAR_TRACE, 0, 0}}; + SendCommand(&ca); + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + PrintAndLog("14aRAW ERROR: Proxmark connection timeout."); + return 1; + } + + // check result + if (resp.arg[0] == 0) { + PrintAndLog("14aRAW ERROR: No card in field."); + return 1; + } + + if (resp.arg[0] != 1 && resp.arg[0] != 2) { + PrintAndLog("14aRAW ERROR: card not in iso14443-4. res=%d.", resp.arg[0]); + return 1; + } + + if (resp.arg[0] == 2) { // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision + // get ATS + UsbCommand cr = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT, 2, 0}}; + uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0 + memcpy(cr.d.asBytes, rats, 2); + SendCommand(&cr); + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + PrintAndLog("14aRAW ERROR: Proxmark connection timeout."); + return 1; + } + + if (resp.arg[0] <= 0) { // ats_len + PrintAndLog("14aRAW ERROR: Can't get ATS."); + return 1; + } + } + } + + if (leaveSignalON) + cmdc |= ISO14A_NO_DISCONNECT; + + UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_APPEND_CRC | cmdc, (datainlen & 0xFFFF), 0}}; + memcpy(c.d.asBytes, datain, datainlen); + SendCommand(&c); + + uint8_t *recv; + UsbCommand resp; + + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + recv = resp.d.asBytes; + int iLen = resp.arg[0]; + + *dataoutlen = iLen - 2; + if (*dataoutlen < 0) + *dataoutlen = 0; + + if (maxdataoutlen && *dataoutlen > maxdataoutlen) { + PrintAndLog("14aRAW ERROR: Buffer too small(%d). Needs %d bytes", *dataoutlen, maxdataoutlen); + return 2; + } + + memcpy(dataout, recv, *dataoutlen); + + if(!iLen) { + PrintAndLog("14aRAW ERROR: No card response."); + return 1; + } + + // CRC Check + if (iLen == -1) { + PrintAndLog("14aRAW ERROR: ISO 14443A CRC error."); + return 3; + } + + + } else { + PrintAndLog("14aRAW ERROR: Reply timeout."); + return 4; + } + + return 0; +} + int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { uint16_t cmdc = 0; diff --git a/client/cmdhf14a.h b/client/cmdhf14a.h index 71007f95..bbfd9b29 100644 --- a/client/cmdhf14a.h +++ b/client/cmdhf14a.h @@ -25,6 +25,7 @@ int CmdHF14ASnoop(const char *Cmd); char* getTagInfo(uint8_t uid); extern void DropField(); +extern int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); extern int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); #endif diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index e2a4ba1e..028bbf7a 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -27,6 +27,9 @@ #include "mifare.h" #include "mfkey.h" #include "hardnested/hardnested_bf_core.h" +#include "cliparser/cliparser.h" +#include "cmdhf14a.h" +#include #define NESTED_SECTOR_RETRY 10 // how often we try mfested() until we give up @@ -2634,6 +2637,149 @@ int CmdDecryptTraceCmds(const char *Cmd){ return tryDecryptWord(param_get32ex(Cmd,0,0,16),param_get32ex(Cmd,1,0,16),param_get32ex(Cmd,2,0,16),data,len/2); } +int aes_encode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length){ + uint8_t iiv[16] = {0}; + if (iv) + memcpy(iiv, iv, 16); + + aes_context aes; + aes_init(&aes); + if (aes_setkey_enc(&aes, key, 128)) + return 1; + if (aes_crypt_cbc(&aes, AES_ENCRYPT, length, iiv, input, output)) + return 2; + aes_free(&aes); + + return 0; +} + +int aes_decode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length){ + uint8_t iiv[16] = {0}; + if (iv) + memcpy(iiv, iv, 16); + + aes_context aes; + aes_init(&aes); + if (aes_setkey_dec(&aes, key, 128)) + return 1; + if (aes_crypt_cbc(&aes, AES_DECRYPT, length, iiv, input, output)) + return 2; + aes_free(&aes); + + return 0; +} + +int CmdHF14AMfAuth4(const char *cmd) { + uint8_t keyn[20] = {0}; + int keynlen = 0; + uint8_t key[16] = {0}; + int keylen = 0; + uint8_t data[257] = {0}; + int datalen = 0; + + uint8_t Rnd1[17] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00}; + uint8_t Rnd2[17] = {0}; + + + CLIParserInit("hf mf auth4", + "Executes AES authentication command in ISO14443-4", + "Usage:\n\thf mf auth4 4000 000102030405060708090a0b0c0d0e0f -> executes authentication\n" + "\thf mf auth4 9003 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -> executes authentication\n"); + + void* argtable[] = { + arg_param_begin, + arg_str1(NULL, NULL, "", NULL), + arg_str1(NULL, NULL, "", NULL), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, true); + + CLIGetStrWithReturn(1, keyn, &keynlen); + CLIGetStrWithReturn(2, key, &keylen); + CLIParserFree(); + + if (keynlen != 2) { + PrintAndLog("ERROR: must be 2 bytes long instead of: %d", keynlen); + return 1; + } + + if (keylen != 16) { + PrintAndLog("ERROR: must be 16 bytes long instead of: %d", keylen); + return 1; + } + + uint8_t cmd1[] = {0x0a, 0x00, 0x70, keyn[1], keyn[0], 0x00}; + int res = ExchangeRAW14a(cmd1, sizeof(cmd1), true, true, data, sizeof(data), &datalen); + if (res) { + PrintAndLog("ERROR exchande raw error: %d", res); + return 2; + } + + PrintAndLog("phase2: %s", sprint_hex(cmd2, 35)); + + res = ExchangeRAW14a(cmd2, sizeof(cmd2), false, false, data, sizeof(data), &datalen); + if (res) { + PrintAndLog("ERROR exchande raw error: %d", res); + DropField(); + return 4; + } + + PrintAndLog(" Date: Thu, 11 Oct 2018 20:28:29 +0300 Subject: [PATCH 002/189] small fix in auth (#693) --- client/cmdhfmf.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 028bbf7a..5efb4a41 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -2712,6 +2712,7 @@ int CmdHF14AMfAuth4(const char *cmd) { int res = ExchangeRAW14a(cmd1, sizeof(cmd1), true, true, data, sizeof(data), &datalen); if (res) { PrintAndLog("ERROR exchande raw error: %d", res); + DropField(); return 2; } @@ -2719,21 +2720,25 @@ int CmdHF14AMfAuth4(const char *cmd) { if (datalen < 3) { PrintAndLog("ERROR: card response length: %d", datalen); + DropField(); return 3; } if (data[0] != 0x0a || data[1] != 0x00) { PrintAndLog("ERROR: card response. Framing error. :%s", sprint_hex(data, 2)); + DropField(); return 3; } if (data[2] != 0x90) { PrintAndLog("ERROR: card response error: %02x", data[2]); + DropField(); return 3; } if (datalen != 19) { PrintAndLog("ERROR: card response must be 16 bytes long instead of: %d", datalen); + DropField(); return 3; } From 54e3cfcb74fbc02f7d1d16be8cd5338529acd58e Mon Sep 17 00:00:00 2001 From: Oleg Moiseenko Date: Fri, 12 Oct 2018 15:13:58 +0300 Subject: [PATCH 003/189] small improvements in auth (#694) --- client/cmdhf14a.c | 16 +++++++++++++--- client/cmdhfmf.c | 30 +++++++++++------------------- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index a5de2e2a..63b1cda6 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -649,10 +649,12 @@ void DropField() { } int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { + static bool responseNum = false; uint16_t cmdc = 0; *dataoutlen = 0; if (activateField) { + responseNum = false; UsbCommand resp; // Anticollision + SELECT card @@ -695,8 +697,11 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav if (leaveSignalON) cmdc |= ISO14A_NO_DISCONNECT; - UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_APPEND_CRC | cmdc, (datainlen & 0xFFFF), 0}}; - memcpy(c.d.asBytes, datain, datainlen); + UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_APPEND_CRC | cmdc, (datainlen & 0xFFFF) + 2, 0}}; + uint8_t header[] = {0x0a | responseNum, 0x00}; + responseNum ^= 1; + memcpy(c.d.asBytes, header, 2); + memcpy(&c.d.asBytes[2], datain, datainlen); SendCommand(&c); uint8_t *recv; @@ -715,7 +720,12 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav return 2; } - memcpy(dataout, recv, *dataoutlen); + if (recv[0] != header[0]) { + PrintAndLog("14aRAW ERROR: iso14443-4 framing error. Card send %2x must be %2x", dataout[0], header[0]); + return 2; + } + + memcpy(dataout, &recv[2], *dataoutlen); if(!iLen) { PrintAndLog("14aRAW ERROR: No card response."); diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 5efb4a41..eb85b8c5 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -2708,7 +2708,7 @@ int CmdHF14AMfAuth4(const char *cmd) { return 1; } - uint8_t cmd1[] = {0x0a, 0x00, 0x70, keyn[1], keyn[0], 0x00}; + uint8_t cmd1[] = {0x70, keyn[1], keyn[0], 0x00}; int res = ExchangeRAW14a(cmd1, sizeof(cmd1), true, true, data, sizeof(data), &datalen); if (res) { PrintAndLog("ERROR exchande raw error: %d", res); @@ -2718,45 +2718,37 @@ int CmdHF14AMfAuth4(const char *cmd) { PrintAndLog("phase2: %s", sprint_hex(cmd2, 35)); + aes_encode(NULL, key, raw, &cmd2[1], 32); + PrintAndLog(">phase2: %s", sprint_hex(cmd2, 33)); res = ExchangeRAW14a(cmd2, sizeof(cmd2), false, false, data, sizeof(data), &datalen); if (res) { @@ -2767,7 +2759,7 @@ int CmdHF14AMfAuth4(const char *cmd) { PrintAndLog(" Date: Wed, 17 Oct 2018 21:53:34 +0300 Subject: [PATCH 004/189] Emv scan (#691) * added `hf emv scan` command and options * add tlv tag save to json * added tlv tree navigation * added kernel id and moved some parts of code in ppse * save gpo result * added read records * extract childs from tlv works * added application data list * added work with application data section * flag --extract works * refactoring: move json functions to emvjson.h/c * added path.c to jansson * refactoring: move ParamLoadFromJson * refactoring: move defparams.json to tag-name-value structure * refactoring and add key recovering * added some codes to appdata list * refactoring: process response format 1 from GPO * added save mode * added RID to app data * add file name handling and small refactoring in argtable string processing * added finalization logic to `emv scan` and option to remove hash checking in key recovery --- client/Makefile | 1 + client/cliparser/cliparser.c | 45 ++- client/cliparser/cliparser.h | 6 +- client/cmdhf14a.c | 41 ++- client/cmdhf14a.h | 3 + client/emv/cmdemv.c | 608 +++++++++++++++++++++++------------ client/emv/defparams.json | 16 +- client/emv/emv_pki.c | 14 +- client/emv/emv_pki.h | 2 + client/emv/emv_tags.c | 14 + client/emv/emv_tags.h | 1 + client/emv/emvcore.c | 68 ++++ client/emv/emvcore.h | 4 + client/emv/emvjson.c | 355 ++++++++++++++++++++ client/emv/emvjson.h | 35 ++ client/emv/tlv.c | 19 ++ client/emv/tlv.h | 5 + client/jansson/Makefile | 1 + client/jansson/jansson.h | 10 + client/jansson/path.c | 202 ++++++++++++ 20 files changed, 1209 insertions(+), 241 deletions(-) create mode 100644 client/emv/emvjson.c create mode 100644 client/emv/emvjson.h create mode 100644 client/jansson/path.c diff --git a/client/Makefile b/client/Makefile index 9e5bde30..f1007b89 100644 --- a/client/Makefile +++ b/client/Makefile @@ -140,6 +140,7 @@ CMDSRCS = $(SRC_SMARTCARD) \ emv/tlv.c\ emv/emv_tags.c\ emv/dol.c\ + emv/emvjson.c\ emv/emvcore.c\ emv/test/crypto_test.c\ emv/test/sda_test.c\ diff --git a/client/cliparser/cliparser.c b/client/cliparser/cliparser.c index 56be2ca6..931d68cd 100644 --- a/client/cliparser/cliparser.c +++ b/client/cliparser/cliparser.c @@ -153,23 +153,14 @@ void CLIParserFree() { // convertors int CLIParamHexToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen) { *datalen = 0; - if (!argstr->count) - return 0; - char buf[256] = {0}; int ibuf = 0; + uint8_t buf[256] = {0}; + int res = CLIParamStrToBuf(argstr, buf, maxdatalen, &ibuf); + if (res || !ibuf) + return res; - for (int i = 0; i < argstr->count; i++) { - int len = strlen(argstr->sval[i]); - memcpy(&buf[ibuf], argstr->sval[i], len); - ibuf += len; - } - buf[ibuf] = 0; - - if (!ibuf) - return 0; - - switch(param_gethex_to_eol(buf, 0, data, maxdatalen, datalen)) { + switch(param_gethex_to_eol((char *)buf, 0, data, maxdatalen, datalen)) { case 1: printf("Parameter error: Invalid HEX value.\n"); return 1; @@ -184,5 +175,31 @@ int CLIParamHexToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int return 0; } +int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen) { + *datalen = 0; + if (!argstr->count) + return 0; + + uint8_t buf[256] = {0}; + int ibuf = 0; + + for (int i = 0; i < argstr->count; i++) { + int len = strlen(argstr->sval[i]); + memcpy(&buf[ibuf], argstr->sval[i], len); + ibuf += len; + } + buf[ibuf] = 0; + + if (!ibuf) + return 0; + + if (ibuf > maxdatalen) + return 2; + + memcpy(data, buf, ibuf); + *datalen = ibuf; + + return 0; +} diff --git a/client/cliparser/cliparser.h b/client/cliparser/cliparser.h index 7c1ced20..2f5ac317 100644 --- a/client/cliparser/cliparser.h +++ b/client/cliparser/cliparser.h @@ -25,8 +25,9 @@ #define arg_strx0(shortopts, longopts, datatype, glossary) (arg_strn((shortopts), (longopts), (datatype), 0, 250, (glossary))) #define CLIExecWithReturn(cmd, atbl, ifempty) if (CLIParserParseString(cmd, atbl, arg_getsize(atbl), ifempty)){CLIParserFree();return 0;} -#define CLIGetStrBLessWithReturn(paramnum, data, datalen, delta) if (CLIParamHexToBuf(arg_get_str(paramnum), data, sizeof(data) - (delta), datalen)) {CLIParserFree();return 1;} -#define CLIGetStrWithReturn(paramnum, data, datalen) if (CLIParamHexToBuf(arg_get_str(paramnum), data, sizeof(data), datalen)) {CLIParserFree();return 1;} +#define CLIGetHexBLessWithReturn(paramnum, data, datalen, delta) if (CLIParamHexToBuf(arg_get_str(paramnum), data, sizeof(data) - (delta), datalen)) {CLIParserFree();return 1;} +#define CLIGetHexWithReturn(paramnum, data, datalen) if (CLIParamHexToBuf(arg_get_str(paramnum), data, sizeof(data), datalen)) {CLIParserFree();return 1;} +#define CLIGetStrWithReturn(paramnum, data, datalen) if (CLIParamStrToBuf(arg_get_str(paramnum), data, sizeof(data), datalen)) {CLIParserFree();return 1;} extern int CLIParserInit(char *vprogramName, char *vprogramHint, char *vprogramHelp); extern int CLIParserParseString(const char* str, void* argtable[], size_t vargtableLen, bool allowEmptyExec); @@ -35,3 +36,4 @@ extern int CLIParserParseArg(int argc, char **argv, void* argtable[], size_t var extern void CLIParserFree(); extern int CLIParamHexToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen); +extern int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen); diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 63b1cda6..31654188 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -136,6 +136,45 @@ int CmdHF14AList(const char *Cmd) return 0; } +int Hf14443_4aGetCardData(iso14a_card_select_t * card) { + UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT, 0, 0}}; + SendCommand(&c); + + UsbCommand resp; + WaitForResponse(CMD_ACK,&resp); + + memcpy(card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t)); + + uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision + + if(select_status == 0) { + PrintAndLog("E->iso14443a card select failed"); + return 1; + } + + if(select_status == 2) { + PrintAndLog("E->Card doesn't support iso14443-4 mode"); + return 1; + } + + if(select_status == 3) { + PrintAndLog("E->Card doesn't support standard iso14443-3 anticollision"); + PrintAndLog("\tATQA : %02x %02x", card->atqa[1], card->atqa[0]); + return 1; + } + + PrintAndLog(" UID: %s", sprint_hex(card->uid, card->uidlen)); + PrintAndLog("ATQA: %02x %02x", card->atqa[1], card->atqa[0]); + PrintAndLog(" SAK: %02x [%" PRIu64 "]", card->sak, resp.arg[0]); + if(card->ats_len < 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes + PrintAndLog("E-> Error ATS length(%d) : %s", card->ats_len, sprint_hex(card->ats, card->ats_len)); + return 1; + } + PrintAndLog(" ATS: %s", sprint_hex(card->ats, card->ats_len)); + + return 0; +} + int CmdHF14AReader(const char *Cmd) { uint32_t cm = ISO14A_CONNECT; bool leaveSignalON = false; @@ -850,7 +889,7 @@ int CmdHF14AAPDU(const char *cmd) { leaveSignalON = arg_get_lit(2); decodeTLV = arg_get_lit(3); // len = data + PCB(1b) + CRC(2b) - CLIGetStrBLessWithReturn(4, data, &datalen, 1 + 2); + CLIGetHexBLessWithReturn(4, data, &datalen, 1 + 2); CLIParserFree(); diff --git a/client/cmdhf14a.h b/client/cmdhf14a.h index bbfd9b29..d961d570 100644 --- a/client/cmdhf14a.h +++ b/client/cmdhf14a.h @@ -14,6 +14,7 @@ #include #include +#include "mifare.h" int CmdHF14A(const char *Cmd); int CmdHF14AList(const char *Cmd); @@ -25,6 +26,8 @@ int CmdHF14ASnoop(const char *Cmd); char* getTagInfo(uint8_t uid); extern void DropField(); + +extern int Hf14443_4aGetCardData(iso14a_card_select_t * card); extern int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); extern int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); diff --git a/client/emv/cmdemv.c b/client/emv/cmdemv.c index 6bac90d6..d886834d 100644 --- a/client/emv/cmdemv.c +++ b/client/emv/cmdemv.c @@ -9,36 +9,14 @@ //----------------------------------------------------------------------------- #include +#include "mifare.h" #include "cmdemv.h" +#include "emvjson.h" +#include "emv_pki.h" #include "test/cryptotest.h" #include "cliparser/cliparser.h" #include -bool HexToBuffer(const char *errormsg, const char *hexvalue, uint8_t * buffer, size_t maxbufferlen, size_t *bufferlen) { - 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; - } - - if (buflen > maxbufferlen) { - PrintAndLog("%s HEX length (%d) more than %d", errormsg, *bufferlen, maxbufferlen); - return false; - } - - *bufferlen = buflen; - - return true; -} - #define TLV_ADD(tag, value)( tlvdb_change_or_add_node(tlvRoot, tag, sizeof(value) - 1, (const unsigned char *)value) ) void ParamLoadDefaults(struct tlvdb *tlvRoot) { //9F02:(Amount, authorized (Numeric)) len:6 @@ -60,111 +38,6 @@ void ParamLoadDefaults(struct tlvdb *tlvRoot) { TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC } -bool ParamLoadFromJson(struct tlvdb *tlv) { - json_t *root; - json_error_t error; - - 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); - - 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; - } - - PrintAndLog("Load params: json OK"); - - for(int i = 0; i < json_array_size(root); i++) { - json_t *data, *jtype, *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; - } - - jtype = json_object_get(data, "type"); - if(!json_is_string(jtype)) - { - PrintAndLog("Load params: data [%d] type is not a string", i + 1); - json_decref(root); - return false; - } - const char *tlvType = json_string_value(jtype); - - 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; - } - - 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", tlvType, tlvLength, tlvValue); - uint8_t buf[251] = {0}; - size_t buflen = 0; - - // here max length must be 4, but now tlv_tag_t is 2-byte var. so let it be 2 by now... TODO: needs refactoring tlv_tag_t... - if (!HexToBuffer("TLV Error type:", tlvType, buf, 2, &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 (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); - } - - json_decref(root); - - return true; -} - int CmdHFEMVSelect(const char *cmd) { uint8_t data[APDU_AID_LEN] = {0}; int datalen = 0; @@ -188,7 +61,7 @@ int CmdHFEMVSelect(const char *cmd) { bool leaveSignalON = arg_get_lit(2); bool APDULogging = arg_get_lit(3); bool decodeTLV = arg_get_lit(4); - CLIGetStrWithReturn(5, data, &datalen); + CLIGetHexWithReturn(5, data, &datalen); CLIParserFree(); SetAPDULogging(APDULogging); @@ -333,7 +206,7 @@ int CmdHFEMVGPO(const char *cmd) { bool dataMakeFromPDOL = arg_get_lit(3); bool APDULogging = arg_get_lit(4); bool decodeTLV = arg_get_lit(5); - CLIGetStrWithReturn(6, data, &datalen); + CLIGetHexWithReturn(6, data, &datalen); CLIParserFree(); SetAPDULogging(APDULogging); @@ -422,7 +295,7 @@ int CmdHFEMVReadRecord(const char *cmd) { bool leaveSignalON = arg_get_lit(1); bool APDULogging = arg_get_lit(2); bool decodeTLV = arg_get_lit(3); - CLIGetStrWithReturn(4, data, &datalen); + CLIGetHexWithReturn(4, data, &datalen); CLIParserFree(); if (datalen != 2) { @@ -500,7 +373,7 @@ int CmdHFEMVAC(const char *cmd) { bool dataMakeFromCDOL = arg_get_lit(5); bool APDULogging = arg_get_lit(6); bool decodeTLV = arg_get_lit(7); - CLIGetStrWithReturn(8, data, &datalen); + CLIGetHexWithReturn(8, data, &datalen); CLIParserFree(); SetAPDULogging(APDULogging); @@ -629,7 +502,7 @@ int CmdHFEMVInternalAuthenticate(const char *cmd) { bool dataMakeFromDDOL = arg_get_lit(3); bool APDULogging = arg_get_lit(4); bool decodeTLV = arg_get_lit(5); - CLIGetStrWithReturn(6, data, &datalen); + CLIGetHexWithReturn(6, data, &datalen); CLIParserFree(); SetAPDULogging(APDULogging); @@ -693,6 +566,69 @@ int CmdHFEMVInternalAuthenticate(const char *cmd) { #define dreturn(n) {free(pdol_data_tlv);tlvdb_free(tlvSelect);tlvdb_free(tlvRoot);DropField();return n;} +void InitTransactionParameters(struct tlvdb *tlvRoot, bool paramLoadJSON, enum TransactionType TrType, bool GenACGPO) { + + ParamLoadDefaults(tlvRoot); + + if (paramLoadJSON) { + PrintAndLog("* * Transaction parameters loading from JSON..."); + ParamLoadFromJson(tlvRoot); + } + + //9F66:(Terminal Transaction Qualifiers (TTQ)) len:4 + char *qVSDC = "\x26\x00\x00\x00"; + if (GenACGPO) { + qVSDC = "\x26\x80\x00\x00"; + } + switch(TrType) { + case TT_MSD: + TLV_ADD(0x9F66, "\x86\x00\x00\x00"); // MSD + break; + // not standard for contactless. just for test. + case TT_VSDC: + TLV_ADD(0x9F66, "\x46\x00\x00\x00"); // VSDC + break; + case TT_QVSDCMCHIP: + TLV_ADD(0x9F66, qVSDC); // qVSDC + break; + case TT_CDA: + TLV_ADD(0x9F66, qVSDC); // qVSDC (VISA CDA not enabled) + break; + default: + break; + } +} + +void ProcessGPOResponseFormat1(struct tlvdb *tlvRoot, uint8_t *buf, size_t len, bool decodeTLV) { + if (buf[0] == 0x80) { + if (decodeTLV){ + PrintAndLog("GPO response format1:"); + TLVPrintFromBuffer(buf, len); + } + + if (len < 4 || (len - 4) % 4) { + PrintAndLog("ERROR: GPO response format1 parsing error. length=%d", len); + } else { + // AIP + struct tlvdb * f1AIP = tlvdb_fixed(0x82, 2, buf + 2); + tlvdb_add(tlvRoot, f1AIP); + if (decodeTLV){ + PrintAndLog("\n* * Decode response format 1 (0x80) AIP and AFL:"); + TLVPrintFromTLV(f1AIP); + } + + // AFL + struct tlvdb * f1AFL = tlvdb_fixed(0x94, len - 4, buf + 2 + 2); + tlvdb_add(tlvRoot, f1AFL); + if (decodeTLV) + TLVPrintFromTLV(f1AFL); + } + } else { + if (decodeTLV) + TLVPrintFromBuffer(buf, len); + } +} + int CmdHFEMVExec(const char *cmd) { uint8_t buf[APDU_RES_LEN] = {0}; size_t len = 0; @@ -805,37 +741,7 @@ int CmdHFEMVExec(const char *cmd) { PrintAndLog("* Selected."); PrintAndLog("\n* Init transaction parameters."); - - ParamLoadDefaults(tlvRoot); - - if (paramLoadJSON) { - PrintAndLog("* * Transaction parameters loading from JSON..."); - ParamLoadFromJson(tlvRoot); - } - - //9F66:(Terminal Transaction Qualifiers (TTQ)) len:4 - char *qVSDC = "\x26\x00\x00\x00"; - if (GenACGPO) { - qVSDC = "\x26\x80\x00\x00"; - } - switch(TrType) { - case TT_MSD: - TLV_ADD(0x9F66, "\x86\x00\x00\x00"); // MSD - break; - // not standard for contactless. just for test. - case TT_VSDC: - TLV_ADD(0x9F66, "\x46\x00\x00\x00"); // VSDC - break; - case TT_QVSDCMCHIP: - TLV_ADD(0x9F66, qVSDC); // qVSDC - break; - case TT_CDA: - TLV_ADD(0x9F66, qVSDC); // qVSDC (VISA CDA not enabled) - break; - default: - break; - } - + InitTransactionParameters(tlvRoot, paramLoadJSON, TrType, GenACGPO); TLVPrintFromTLV(tlvRoot); // TODO delete!!! PrintAndLog("\n* Calc PDOL."); @@ -865,33 +771,7 @@ int CmdHFEMVExec(const char *cmd) { } // process response template format 1 [id:80 2b AIP + x4b AFL] and format 2 [id:77 TLV] - if (buf[0] == 0x80) { - if (decodeTLV){ - PrintAndLog("GPO response format1:"); - TLVPrintFromBuffer(buf, len); - } - - if (len < 4 || (len - 4) % 4) { - PrintAndLog("ERROR: GPO response format1 parsing error. length=%d", len); - } else { - // AIP - struct tlvdb * f1AIP = tlvdb_fixed(0x82, 2, buf + 2); - tlvdb_add(tlvRoot, f1AIP); - if (decodeTLV){ - PrintAndLog("\n* * Decode response format 1 (0x80) AIP and AFL:"); - TLVPrintFromTLV(f1AIP); - } - - // AFL - struct tlvdb * f1AFL = tlvdb_fixed(0x94, len - 4, buf + 2 + 2); - tlvdb_add(tlvRoot, f1AFL); - if (decodeTLV) - TLVPrintFromTLV(f1AFL); - } - } else { - if (decodeTLV) - TLVPrintFromBuffer(buf, len); - } + ProcessGPOResponseFormat1(tlvRoot, buf, len, decodeTLV); // extract PAN from track2 { @@ -1191,26 +1071,328 @@ int CmdHFEMVExec(const char *cmd) { return 0; } -int UsageCmdHFEMVScan(void) { - PrintAndLog("HELP : Scan EMV card and save it contents to a file. \n"); - PrintAndLog(" It executes EMV contactless transaction and saves result to a file which can be used for emulation.\n"); - PrintAndLog("Usage: hf emv scan [-a][-t][-v][-c][-x][-g] \n"); - PrintAndLog(" Options:"); - PrintAndLog(" -a : show APDU reqests and responses\n"); - PrintAndLog(" -t : TLV decode results\n"); - PrintAndLog(" -v : transaction type - qVSDC or M/Chip.\n"); - PrintAndLog(" -c : transaction type - qVSDC or M/Chip plus CDA (SDAD generation).\n"); - PrintAndLog(" -x : transaction type - VSDC. For test only. Not a standart behavior.\n"); - PrintAndLog(" -g : VISA. generate AC from GPO\n"); - PrintAndLog("By default : transaction type - MSD.\n"); - PrintAndLog("Samples:"); - PrintAndLog(" hf emv scan -a -t -> scan MSD transaction mode"); - PrintAndLog(" hf emv scan -a -t -c -> scan CDA transaction mode"); - return 0; -} - int CmdHFEMVScan(const char *cmd) { - UsageCmdHFEMVScan(); + uint8_t AID[APDU_AID_LEN] = {0}; + size_t AIDlen = 0; + uint8_t buf[APDU_RES_LEN] = {0}; + size_t len = 0; + uint16_t sw = 0; + int res; + json_t *root; + json_error_t error; + + CLIParserInit("hf emv scan", + "Scan EMV card and save it contents to a file.", + "It executes EMV contactless transaction and saves result to a file which can be used for emulation\n" + "Usage:\n\thf emv scan -at -> scan MSD transaction mode and show APDU and TLV\n" + "\thf emv scan -c -> scan CDA transaction mode\n"); + + void* argtable[] = { + arg_param_begin, + arg_lit0("aA", "apdu", "show APDU reqests and responses."), + arg_lit0("tT", "tlv", "TLV decode results."), + arg_lit0("eE", "extract", "Extract TLV elements and fill Application Data"), + arg_lit0("jJ", "jload", "Load transaction parameters from `emv/defparams.json` file."), + arg_rem("By default:", "Transaction type - MSD"), + arg_lit0("vV", "qvsdc", "Transaction type - qVSDC or M/Chip."), + arg_lit0("cC", "qvsdccda", "Transaction type - qVSDC or M/Chip plus CDA (SDAD generation)."), + arg_lit0("xX", "vsdc", "Transaction type - VSDC. For test only. Not a standart behavior."), + arg_lit0("gG", "acgpo", "VISA. generate AC from GPO."), + arg_lit0("mM", "merge", "Merge output file with card's data. (warning: the file may be corrupted!)"), + arg_str1(NULL, NULL, "output.json", "JSON output file name"), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, true); + + bool showAPDU = arg_get_lit(1); + bool decodeTLV = arg_get_lit(2); + bool extractTLVElements = arg_get_lit(3); + bool paramLoadJSON = arg_get_lit(4); + + enum TransactionType TrType = TT_MSD; + if (arg_get_lit(6)) + TrType = TT_QVSDCMCHIP; + if (arg_get_lit(7)) + TrType = TT_CDA; + if (arg_get_lit(8)) + TrType = TT_VSDC; + + bool GenACGPO = arg_get_lit(9); + bool MergeJSON = arg_get_lit(10); + uint8_t relfname[250] ={0}; + char *crelfname = (char *)relfname; + int relfnamelen = 0; + CLIGetStrWithReturn(11, relfname, &relfnamelen); + CLIParserFree(); + + SetAPDULogging(showAPDU); + + // current path + file name + if (!strstr(crelfname, ".json")) + strcat(crelfname, ".json"); + char fname[strlen(get_my_executable_directory()) + strlen(crelfname) + 1]; + strcpy(fname, get_my_executable_directory()); + strcat(fname, crelfname); + + if (MergeJSON) { + root = json_load_file(fname, 0, &error); + if (!root) { + PrintAndLog("ERROR: json error on line %d: %s", error.line, error.text); + return 1; + } + + if (!json_is_object(root)) { + PrintAndLog("ERROR: Invalid json format. root must be an object."); + return 1; + } + } else { + root = json_object(); + } + + // drop field at start + DropField(); + + // iso 14443 select + PrintAndLog("--> GET UID, ATS."); + + iso14a_card_select_t card; + if (Hf14443_4aGetCardData(&card)) { + return 2; + } + + JsonSaveStr(root, "$.File.Created", "proxmark3 `hf emv scan`"); + + JsonSaveStr(root, "$.Card.Communication", "iso14443-4a"); + JsonSaveBufAsHex(root, "$.Card.UID", (uint8_t *)&card.uid, card.uidlen); + JsonSaveHex(root, "$.Card.ATQA", card.atqa[0] + (card.atqa[1] << 2), 2); + JsonSaveHex(root, "$.Card.SAK", card.sak, 0); + JsonSaveBufAsHex(root, "$.Card.ATS", (uint8_t *)card.ats, card.ats_len); + + // init applets list tree + const char *al = "Applets list"; + struct tlvdb *tlvSelect = tlvdb_fixed(1, strlen(al), (const unsigned char *)al); + + // EMV PPSE + PrintAndLog("--> PPSE."); + res = EMVSelectPSE(true, true, 2, buf, sizeof(buf), &len, &sw); + + if (!res && sw == 0x9000){ + if (decodeTLV) + TLVPrintFromBuffer(buf, len); + + JsonSaveBufAsHex(root, "$.PPSE.AID", (uint8_t *)"2PAY.SYS.DDF01", 14); + + struct tlvdb *fci = tlvdb_parse_multi(buf, len); + if (extractTLVElements) + JsonSaveTLVTree(root, root, "$.PPSE.FCITemplate", fci); + else + JsonSaveTLVTreeElm(root, "$.PPSE.FCITemplate", fci, true, true, false); + JsonSaveTLVValue(root, "$.Application.KernelID", tlvdb_find_full(fci, 0x9f2a)); + tlvdb_free(fci); + } + + res = EMVSearchPSE(false, true, decodeTLV, tlvSelect); + + // check PPSE and select application id + if (!res) { + TLVPrintAIDlistFromSelectTLV(tlvSelect); + } else { + // EMV SEARCH with AID list + SetAPDULogging(false); + PrintAndLog("--> AID search."); + if (EMVSearch(false, true, decodeTLV, tlvSelect)) { + PrintAndLog("E->Can't found any of EMV AID. Exit..."); + tlvdb_free(tlvSelect); + DropField(); + return 3; + } + + // check search and select application id + TLVPrintAIDlistFromSelectTLV(tlvSelect); + } + + // EMV SELECT application + SetAPDULogging(showAPDU); + EMVSelectApplication(tlvSelect, AID, &AIDlen); + + tlvdb_free(tlvSelect); + + if (!AIDlen) { + PrintAndLog("Can't select AID. EMV AID not found. Exit..."); + DropField(); + return 4; + } + + JsonSaveBufAsHex(root, "$.Application.AID", AID, AIDlen); + + // Init TLV tree + const char *alr = "Root terminal TLV tree"; + struct tlvdb *tlvRoot = tlvdb_fixed(1, strlen(alr), (const unsigned char *)alr); + + // EMV SELECT applet + + PrintAndLog("\n-->Selecting AID:%s.", sprint_hex_inrow(AID, AIDlen)); + SetAPDULogging(showAPDU); + res = EMVSelect(false, true, AID, AIDlen, buf, sizeof(buf), &len, &sw, tlvRoot); + + if (res) { + PrintAndLog("E->Can't select AID (%d). Exit...", res); + tlvdb_free(tlvRoot); + DropField(); + return 5; + } + + if (decodeTLV) + TLVPrintFromBuffer(buf, len); + + // save mode + if (tlvdb_get(tlvRoot, 0x9f38, NULL)) { + JsonSaveStr(root, "$.Application.Mode", TransactionTypeStr[TrType]); + } + + struct tlvdb *fci = tlvdb_parse_multi(buf, len); + if (extractTLVElements) + JsonSaveTLVTree(root, root, "$.Application.FCITemplate", fci); + else + JsonSaveTLVTreeElm(root, "$.Application.FCITemplate", fci, true, true, false); + tlvdb_free(fci); + + // create transaction parameters + PrintAndLog("-->Init transaction parameters."); + InitTransactionParameters(tlvRoot, paramLoadJSON, TrType, GenACGPO); + + PrintAndLog("-->Calc PDOL."); + struct tlv *pdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x9f38, NULL), tlvRoot, 0x83); + if (!pdol_data_tlv){ + PrintAndLog("E->Can't create PDOL TLV."); + tlvdb_free(tlvRoot); + DropField(); + return 6; + } + + size_t pdol_data_tlv_data_len; + unsigned char *pdol_data_tlv_data = tlv_encode(pdol_data_tlv, &pdol_data_tlv_data_len); + if (!pdol_data_tlv_data) { + PrintAndLog("E->Can't create PDOL data."); + tlvdb_free(tlvRoot); + DropField(); + return 6; + } + PrintAndLog("PDOL data[%d]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len)); + + PrintAndLog("-->GPO."); + res = EMVGPO(true, pdol_data_tlv_data, pdol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot); + + free(pdol_data_tlv_data); + free(pdol_data_tlv); + + if (res) { + PrintAndLog("GPO error(%d): %4x. Exit...", res, sw); + tlvdb_free(tlvRoot); + DropField(); + return 7; + } + ProcessGPOResponseFormat1(tlvRoot, buf, len, decodeTLV); + + struct tlvdb *gpofci = tlvdb_parse_multi(buf, len); + if (extractTLVElements) + JsonSaveTLVTree(root, root, "$.Application.GPO", gpofci); + else + JsonSaveTLVTreeElm(root, "$.Application.GPO", gpofci, true, true, false); + + JsonSaveTLVValue(root, "$.ApplicationData.AIP", tlvdb_find_full(gpofci, 0x82)); + JsonSaveTLVValue(root, "$.ApplicationData.AFL", tlvdb_find_full(gpofci, 0x94)); + + tlvdb_free(gpofci); + + PrintAndLog("-->Read records from AFL."); + const struct tlv *AFL = tlvdb_get(tlvRoot, 0x94, NULL); + + while(AFL && AFL->len) { + if (AFL->len % 4) { + PrintAndLog("E->Wrong AFL length: %d", AFL->len); + break; + } + + json_t *sfijson = json_path_get(root, "$.Application.Records"); + if (!sfijson) { + json_t *app = json_path_get(root, "$.Application"); + json_object_set_new(app, "Records", json_array()); + + sfijson = json_path_get(root, "$.Application.Records"); + } + if (!json_is_array(sfijson)) { + PrintAndLog("E->Internal logic error. `$.Application.Records` is not an array."); + break; + } + for (int i = 0; i < AFL->len / 4; i++) { + uint8_t SFI = AFL->value[i * 4 + 0] >> 3; + uint8_t SFIstart = AFL->value[i * 4 + 1]; + uint8_t SFIend = AFL->value[i * 4 + 2]; + uint8_t SFIoffline = AFL->value[i * 4 + 3]; + + PrintAndLog("--->SFI[%02x] start:%02x end:%02x offline:%02x", SFI, SFIstart, SFIend, SFIoffline); + if (SFI == 0 || SFI == 31 || SFIstart == 0 || SFIstart > SFIend) { + PrintAndLog("SFI ERROR! Skipped..."); + continue; + } + + for(int n = SFIstart; n <= SFIend; n++) { + PrintAndLog("---->SFI[%02x] %d", SFI, n); + + res = EMVReadRecord(true, SFI, n, buf, sizeof(buf), &len, &sw, tlvRoot); + if (res) { + PrintAndLog("E->SFI[%02x]. APDU error %4x", SFI, sw); + continue; + } + + if (decodeTLV) { + TLVPrintFromBuffer(buf, len); + PrintAndLog(""); + } + + json_t *jsonelm = json_object(); + json_array_append_new(sfijson, jsonelm); + + JsonSaveHex(jsonelm, "SFI", SFI, 1); + JsonSaveHex(jsonelm, "RecordNum", n, 1); + JsonSaveHex(jsonelm, "Offline", SFIoffline, 1); + + struct tlvdb *rsfi = tlvdb_parse_multi(buf, len); + if (extractTLVElements) + JsonSaveTLVTree(root, jsonelm, "$.Data", rsfi); + else + JsonSaveTLVTreeElm(jsonelm, "$.Data", rsfi, true, true, false); + tlvdb_free(rsfi); + } + } + + break; + } + + // getting certificates + if (tlvdb_get(tlvRoot, 0x90, NULL)) { + PrintAndLog("-->Recovering certificates."); + PKISetStrictExecution(false); + RecoveryCertificates(tlvRoot, root); + PKISetStrictExecution(true); + } + + // free tlv object + tlvdb_free(tlvRoot); + + // DropField + DropField(); + + res = json_dump_file(root, fname, JSON_INDENT(2)); + if (res) { + PrintAndLog("ERROR: can't save the file: %s", fname); + return 200; + } + PrintAndLog("File `%s` saved.", fname); + + // free json object + json_decref(root); return 0; } @@ -1231,7 +1413,7 @@ static command_t CommandTable[] = { {"genac", CmdHFEMVAC, 0, "Generate ApplicationCryptogram."}, {"challenge", CmdHFEMVGenerateChallenge, 0, "Generate challenge."}, {"intauth", CmdHFEMVInternalAuthenticate, 0, "Internal authentication."}, -// {"scan", CmdHFEMVScan, 0, "Scan EMV card and save it contents to json file for emulator."}, + {"scan", CmdHFEMVScan, 0, "Scan EMV card and save it contents to json file for emulator."}, {"test", CmdHFEMVTest, 0, "Crypto logic test."}, {NULL, NULL, 0, NULL} }; diff --git a/client/emv/defparams.json b/client/emv/defparams.json index 47f1c8a1..e615d323 100644 --- a/client/emv/defparams.json +++ b/client/emv/defparams.json @@ -1,56 +1,56 @@ [ { "name": "Transaction Date", - "type": "9A", + "tag": "9A", "value": "00 00 00", "length": 3, "hint": "format: YYMMDD" }, { "name": "Transaction Type", - "type": "9C", + "tag": "9C", "value": "00", "length": 1, "hint": "00: Goods and service, 01: Cash" }, { "name": "Amount, authorized", - "type": "9F 02", + "tag": "9F 02", "value": "00 00 00 00 01 00", "length": 6, "hint": "amount (numberic) in cents" }, { "name": "Transaction Currency Code", - "type": "5F 2A", + "tag": "5F 2A", "value": "09 80", "length": 2, "hint": "USD 840, EUR 978, RUB 643, RUR 810(old), UAH 980, AZN 031, n/a 999" }, { "name": "Terminal Country Code", - "type": "9F 1A", + "tag": "9F 1A", "value": "72 75", "length": 2, "hint": "ISO3166: de, en (65 6e), uk(75 6b), ru (72 75), us, ua" }, { "name": "Terminal Transaction Qualifiers (TTQ)", - "type": "9F 66", + "tag": "9F 66", "value": "26 00 00 00", "length": 4, "hint": "qVSDC 26 00 00 00, gen AC from GPO 26 80 00 00, MSD 86 00 00 00, VSDC 46 00 00 00" }, { "name": "Unpredictable Number", - "type": "9F 37", + "tag": "9F 37", "value": "01 02 03 04", "length": 4, "hint": "4 byte random number" }, { "name": "Unpredictable Number (MSD for UDOL)", - "type": "9F 6A", + "tag": "9F 6A", "value": "01 02 03 05", "length": 4, "hint": "4 byte random number" diff --git a/client/emv/emv_pki.c b/client/emv/emv_pki.c index f79e3045..da102291 100644 --- a/client/emv/emv_pki.c +++ b/client/emv/emv_pki.c @@ -27,6 +27,11 @@ #include #include +static bool strictExecution = true; +void PKISetStrictExecution(bool se) { + strictExecution = se; +} + static const unsigned char empty_tlv_value[] = {}; static const struct tlv empty_tlv = {.tag = 0x0, .len = 0, .value = empty_tlv_value}; @@ -108,9 +113,12 @@ static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk, 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(crypto_hash_read(ch), hash_len)); - crypto_hash_close(ch); - free(data); - return NULL; + + if (strictExecution) { + crypto_hash_close(ch); + free(data); + return NULL; + } } crypto_hash_close(ch); diff --git a/client/emv/emv_pki.h b/client/emv/emv_pki.h index e37e3c7d..6fa7b12e 100644 --- a/client/emv/emv_pki.h +++ b/client/emv/emv_pki.h @@ -21,6 +21,8 @@ #include +extern void PKISetStrictExecution(bool se); + struct emv_pk *emv_pki_recover_issuer_cert(const struct emv_pk *pk, struct tlvdb *db); struct emv_pk *emv_pki_recover_icc_cert(const struct emv_pk *pk, struct tlvdb *db, const struct tlv *sda_tlv); struct emv_pk *emv_pki_recover_icc_pe_cert(const struct emv_pk *pk, struct tlvdb *db); diff --git a/client/emv/emv_tags.c b/client/emv/emv_tags.c index 02b039f8..eed77e76 100644 --- a/client/emv/emv_tags.c +++ b/client/emv/emv_tags.c @@ -686,3 +686,17 @@ bool emv_tag_dump(const struct tlv *tlv, FILE *f, int level) return true; } + +char *emv_get_tag_name(const struct tlv *tlv) +{ + static char *defstr = ""; + + if (!tlv) + return defstr; + + const struct emv_tag *tag = emv_get_tag(tlv); + if (tag) + return tag->name; + + return defstr; +} diff --git a/client/emv/emv_tags.h b/client/emv/emv_tags.h index f6d44f01..246fc72d 100644 --- a/client/emv/emv_tags.h +++ b/client/emv/emv_tags.h @@ -31,5 +31,6 @@ # define EMVCID_REASON_MASK 0x07 bool emv_tag_dump(const struct tlv *tlv, FILE *f, int level); +char *emv_get_tag_name(const struct tlv *tlv); #endif diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index 36f6f8eb..f9dd0cbe 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -9,6 +9,7 @@ //----------------------------------------------------------------------------- #include "emvcore.h" +#include "emvjson.h" // Got from here. Thanks) // https://eftlab.co.uk/index.php/site-map/knowledge-base/211-emv-aid-rid-pix @@ -18,6 +19,13 @@ static const char *PSElist [] = { }; //static const size_t PSElistLen = sizeof(PSElist)/sizeof(char*); +char *TransactionTypeStr[] = { + "MSD", + "VSDC", + "qVCDCMCHIP", + "CDA" +}; + typedef struct { enum CardPSVendor vendor; const char* aid; @@ -849,3 +857,63 @@ int trCDA(struct tlvdb *tlv, struct tlvdb *ac_tlv, struct tlv *pdol_data_tlv, st emv_pk_free(icc_pk); return 0; } + +int RecoveryCertificates(struct tlvdb *tlvRoot, json_t *root) { + + struct emv_pk *pk = get_ca_pk(tlvRoot); + if (!pk) { + PrintAndLog("ERROR: Key not found. Exit."); + return 1; + } + + struct emv_pk *issuer_pk = emv_pki_recover_issuer_cert(pk, tlvRoot); + if (!issuer_pk) { + emv_pk_free(pk); + PrintAndLog("WARNING: Issuer certificate not found. Exit."); + return 2; + } + PrintAndLog("Issuer PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx", + issuer_pk->rid[0], + issuer_pk->rid[1], + issuer_pk->rid[2], + issuer_pk->rid[3], + issuer_pk->rid[4], + issuer_pk->index, + issuer_pk->serial[0], + issuer_pk->serial[1], + issuer_pk->serial[2] + ); + + JsonSaveBufAsHex(root, "$.ApplicationData.RID", issuer_pk->rid, 5); + + char *issuer_pk_c = emv_pk_dump_pk(issuer_pk); + JsonSaveStr(root, "$.ApplicationData.IssuerPublicKeyDec", issuer_pk_c); + JsonSaveBufAsHex(root, "$.ApplicationData.IssuerPublicKeyModulus", issuer_pk->modulus, issuer_pk->mlen); + free(issuer_pk_c); + + struct emv_pk *icc_pk = emv_pki_recover_icc_cert(issuer_pk, tlvRoot, NULL); + if (!icc_pk) { + emv_pk_free(pk); + emv_pk_free(issuer_pk); + PrintAndLog("WARNING: ICC certificate not found. Exit."); + return 2; + } + printf("ICC PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n", + icc_pk->rid[0], + icc_pk->rid[1], + icc_pk->rid[2], + icc_pk->rid[3], + icc_pk->rid[4], + icc_pk->index, + icc_pk->serial[0], + icc_pk->serial[1], + icc_pk->serial[2] + ); + + char *icc_pk_c = emv_pk_dump_pk(icc_pk); + JsonSaveStr(root, "$.ApplicationData.ICCPublicKeyDec", icc_pk_c); + JsonSaveBufAsHex(root, "$.ApplicationData.ICCPublicKeyModulus", icc_pk->modulus, icc_pk->mlen); + free(issuer_pk_c); + + return 0; +} diff --git a/client/emv/emvcore.h b/client/emv/emvcore.h index 94be4fcf..ece7324a 100644 --- a/client/emv/emvcore.h +++ b/client/emv/emvcore.h @@ -16,6 +16,7 @@ #include #include #include +#include #include "util.h" #include "common.h" #include "ui.h" @@ -37,6 +38,7 @@ enum TransactionType { TT_QVSDCMCHIP, TT_CDA, }; +extern char *TransactionTypeStr[]; typedef struct { uint8_t CLA; @@ -90,6 +92,8 @@ extern int trSDA(struct tlvdb *tlv); extern int trDDA(bool decodeTLV, struct tlvdb *tlv); extern int trCDA(struct tlvdb *tlv, struct tlvdb *ac_tlv, struct tlv *pdol_data_tlv, struct tlv *ac_data_tlv); +extern int RecoveryCertificates(struct tlvdb *tlvRoot, json_t *root); + #endif diff --git a/client/emv/emvjson.c b/client/emv/emvjson.c new file mode 100644 index 00000000..02297435 --- /dev/null +++ b/client/emv/emvjson.c @@ -0,0 +1,355 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2018 Merlok +// +// 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. +//----------------------------------------------------------------------------- +// EMV json logic +//----------------------------------------------------------------------------- + +#include "emvjson.h" +#include +#include +#include +#include +#include +#include "util.h" +#include "ui.h" +#include "proxmark3.h" +#include "emv_tags.h" + +static const ApplicationDataElm ApplicationData[] = { +{0x82, "AIP"}, +{0x94, "AFL"}, + +{0x5A, "PAN"}, +{0x5F34, "PANSeqNo"}, +{0x5F24, "ExpirationDate"}, +{0x5F25, "EffectiveDate"}, +{0x5F28, "IssuerCountryCode"}, + +{0x50, "ApplicationLabel"}, +{0x9F08, "VersionNumber"}, +{0x9F42, "CurrencyCode"}, +{0x5F2D, "LanguagePreference"}, +{0x87, "PriorityIndicator"}, +{0x9F36, "ATC"}, //Application Transaction Counter + +{0x5F20, "CardholderName"}, + +{0x9F38, "PDOL"}, +{0x8C, "CDOL1"}, +{0x8D, "CDOL2"}, + +{0x9F07, "AUC"}, // Application Usage Control +{0x9F6C, "CTQ"}, +{0x8E, "CVMList"}, +{0x9F0D, "IACDefault"}, +{0x9F0E, "IACDeny"}, +{0x9F0F, "IACOnline"}, + +{0x8F, "CertificationAuthorityPublicKeyIndex"}, +{0x9F32, "IssuerPublicKeyExponent"}, +{0x92, "IssuerPublicKeyRemainder"}, +{0x90, "IssuerPublicKeyCertificate"}, +{0x9F47, "ICCPublicKeyExponent"}, +{0x9F46, "ICCPublicKeyCertificate"}, + +{0x00, "end..."} +}; +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; + + return NULL; +} + +int JsonSaveStr(json_t *root, char *path, char *value) { + json_error_t error; + + if (strlen(path) < 1) + return 1; + + if (path[0] == '$') { + if (json_path_set(root, path, json_string(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, json_string(value)); + } +}; + +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'; + + 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); + + 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; +} + +int JsonSaveTLVElm(json_t *elm, char *path, struct tlv *tlvelm, bool saveName, bool saveValue, bool saveAppDataLink) { + json_error_t error; + + if (strlen(path) < 1 || !tlvelm) + return 1; + + if (path[0] == '$') { + + 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 (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; +} + +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); +} + +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); + + 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); + } + + 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()); + + chjson = json_path_get(pelm, "$.Childs"); + } + + // 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)); + } + + 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; + + 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, maxbufferlen); + return false; + } + + *bufferlen = buflen; + + return true; +} + +bool ParamLoadFromJson(struct tlvdb *tlv) { + json_t *root; + json_error_t error; + + 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); + + 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; + } + + 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; + + 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); + + 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; + } + + 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; + + // here max length must be 4, but now tlv_tag_t is 2-byte var. so let it be 2 by now... TODO: needs refactoring tlv_tag_t... + if (!HexToBuffer("TLV Error type:", tlvTag, buf, 2, &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 (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); + } + + json_decref(root); + + return true; +} + diff --git a/client/emv/emvjson.h b/client/emv/emvjson.h new file mode 100644 index 00000000..a518d7b9 --- /dev/null +++ b/client/emv/emvjson.h @@ -0,0 +1,35 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2018 Merlok +// +// 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. +//----------------------------------------------------------------------------- +// EMV json logic +//----------------------------------------------------------------------------- +#ifndef EMVJSON_H__ +#define EMVJSON_H__ + +#include +#include "tlv.h" + +typedef struct { + tlv_tag_t Tag; + char *Name; +} ApplicationDataElm; + +extern char* GetApplicationDataName(tlv_tag_t tag); + +extern int JsonSaveStr(json_t *root, char *path, char *value); +extern int JsonSaveBufAsHex(json_t *elm, char *path, uint8_t *data, size_t datalen); +extern int JsonSaveHex(json_t *elm, char *path, uint64_t data, int datalen); + +extern int JsonSaveTLVValue(json_t *root, char *path, struct tlvdb *tlvdbelm); +extern int JsonSaveTLVElm(json_t *elm, char *path, struct tlv *tlvelm, bool saveName, bool saveValue, bool saveAppDataLink); +extern int JsonSaveTLVTreeElm(json_t *elm, char *path, struct tlvdb *tlvdbelm, bool saveName, bool saveValue, bool saveAppDataLink); + +extern int JsonSaveTLVTree(json_t *root, json_t *elm, char *path, struct tlvdb *tlvdbelm); + +extern bool ParamLoadFromJson(struct tlvdb *tlv); + +#endif \ No newline at end of file diff --git a/client/emv/tlv.c b/client/emv/tlv.c index 776fdeed..540c33e4 100644 --- a/client/emv/tlv.c +++ b/client/emv/tlv.c @@ -458,6 +458,10 @@ const struct tlv *tlvdb_get_inchild(const struct tlvdb *tlvdb, tlv_tag_t tag, co return tlvdb_get(tlvdb, tag, prev); } +const struct tlv *tlvdb_get_tlv(const struct tlvdb *tlvdb) { + return &tlvdb->tag; +} + unsigned char *tlv_encode(const struct tlv *tlv, size_t *len) { size_t size = tlv->len; @@ -516,3 +520,18 @@ bool tlv_equal(const struct tlv *a, const struct tlv *b) 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; +} + +struct tlvdb *tlvdb_elm_get_children(struct tlvdb *tlvdb) +{ + return tlvdb->children; +} + +struct tlvdb *tlvdb_elm_get_parent(struct tlvdb *tlvdb) +{ + return tlvdb->parent; +} diff --git a/client/emv/tlv.h b/client/emv/tlv.h index 963abb2a..b25b51de 100644 --- a/client/emv/tlv.h +++ b/client/emv/tlv.h @@ -39,6 +39,10 @@ struct tlvdb *tlvdb_parse(const unsigned char *buf, size_t len); struct tlvdb *tlvdb_parse_multi(const unsigned char *buf, size_t len); void tlvdb_free(struct tlvdb *tlvdb); +struct tlvdb *tlvdb_elm_get_next(struct tlvdb *tlvdb); +struct tlvdb *tlvdb_elm_get_children(struct tlvdb *tlvdb); +struct tlvdb *tlvdb_elm_get_parent(struct tlvdb *tlvdb); + struct tlvdb *tlvdb_find_full(struct tlvdb *tlvdb, tlv_tag_t tag); // search also in childrens struct tlvdb *tlvdb_find(struct tlvdb *tlvdb, tlv_tag_t tag); struct tlvdb *tlvdb_find_next(struct tlvdb *tlvdb, tlv_tag_t tag); @@ -50,6 +54,7 @@ void tlvdb_change_or_add_node(struct tlvdb *tlvdb, tlv_tag_t tag, size_t len, co void tlvdb_visit(const struct tlvdb *tlvdb, tlv_cb cb, void *data, int level); const struct tlv *tlvdb_get(const struct tlvdb *tlvdb, tlv_tag_t tag, const struct tlv *prev); const struct tlv *tlvdb_get_inchild(const struct tlvdb *tlvdb, tlv_tag_t tag, const struct tlv *prev); +const struct tlv *tlvdb_get_tlv(const struct tlvdb *tlvdb); bool tlv_parse_tl(const unsigned char **buf, size_t *len, struct tlv *tlv); unsigned char *tlv_encode(const struct tlv *tlv, size_t *len); diff --git a/client/jansson/Makefile b/client/jansson/Makefile index 7a262f8b..e608d7c0 100644 --- a/client/jansson/Makefile +++ b/client/jansson/Makefile @@ -19,6 +19,7 @@ libjansson_la_SOURCES = \ strconv.c \ utf.c \ utf.h \ + path.c \ value.c libjansson_la_LDFLAGS = \ -no-undefined \ diff --git a/client/jansson/jansson.h b/client/jansson/jansson.h index 43332895..86f23d17 100644 --- a/client/jansson/jansson.h +++ b/client/jansson/jansson.h @@ -306,6 +306,16 @@ int json_equal(const json_t *value1, const json_t *value2); json_t *json_copy(json_t *value); json_t *json_deep_copy(const json_t *value); +/* path */ + +json_t *json_path_get(const json_t *json, const char *path); +int json_path_set_new(json_t *json, const char *path, json_t *value, size_t flags, json_error_t *error); + +static JSON_INLINE +int json_path_set(json_t *json, const char *path, json_t *value, size_t flags, json_error_t *error) +{ + return json_path_set_new(json, path, json_incref(value), flags, error); +} /* decoding */ diff --git a/client/jansson/path.c b/client/jansson/path.c new file mode 100644 index 00000000..08f2da9f --- /dev/null +++ b/client/jansson/path.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2012 Rogerz Zhang + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + * + * source here https://github.com/rogerz/jansson/blob/json_path/src/path.c + */ + +#include +#include + +#include +#include "jansson_private.h" + + +json_t *json_path_get(const json_t *json, const char *path) +{ + static const char root_chr = '$', array_open = '['; + static const char *path_delims = ".[", *array_close = "]"; + const json_t *cursor; + char *token, *buf, *peek, *endptr, delim = '\0'; + const char *expect; + + if (!json || !path || path[0] != root_chr) + return NULL; + else + buf = jsonp_strdup(path); + + peek = buf + 1; + cursor = json; + token = NULL; + expect = path_delims; + + while (peek && *peek && cursor) + { + char *last_peek = peek; + peek = strpbrk(peek, expect); + if (peek) { + if (!token && peek != last_peek) + goto fail; + delim = *peek; + *peek++ = '\0'; + } else if (expect != path_delims || !token) { + goto fail; + } + + if (expect == path_delims) { + if (token) { + cursor = json_object_get(cursor, token); + } + expect = (delim == array_open ? array_close : path_delims); + token = peek; + } else if (expect == array_close) { + size_t index = strtol(token, &endptr, 0); + if (*endptr) + goto fail; + cursor = json_array_get(cursor, index); + token = NULL; + expect = path_delims; + } else { + goto fail; + } + } + + jsonp_free(buf); + return (json_t *)cursor; +fail: + jsonp_free(buf); + return NULL; +} + +int json_path_set_new(json_t *json, const char *path, json_t *value, size_t flags, json_error_t *error) +{ + static const char root_chr = '$', array_open = '[', object_delim = '.'; + static const char * const path_delims = ".[", *array_close = "]"; + + json_t *cursor, *parent = NULL; + char *token, *buf = NULL, *peek, delim = '\0'; + const char *expect; + int index_saved = -1; + + jsonp_error_init(error, ""); + + if (!json || !path || flags || !value) { + jsonp_error_set(error, -1, -1, 0, json_error_invalid_argument, "invalid argument"); + goto fail; + } else { + buf = jsonp_strdup(path); + } + + if (buf[0] != root_chr) { + jsonp_error_set(error, -1, -1, 0, json_error_invalid_format, "path should start with $"); + goto fail; + } + + peek = buf + 1; + cursor = json; + token = NULL; + expect = path_delims; + + while (peek && *peek && cursor) + { + char *last_peek = peek; + peek = strpbrk(last_peek, expect); + + if (peek) { + if (!token && peek != last_peek) { + jsonp_error_set(error, -1, -1, last_peek - buf, json_error_invalid_format, "unexpected trailing chars"); + goto fail; + } + delim = *peek; + *peek++ = '\0'; + } else { // end of path + if (expect == path_delims) { + break; + } else { + jsonp_error_set(error, -1, -1, peek - buf, json_error_invalid_format, "missing ']'?"); + goto fail; + } + } + + if (expect == path_delims) { + if (token) { + if (token[0] == '\0') { + jsonp_error_set(error, -1, -1, peek - buf, json_error_invalid_format, "empty token"); + goto fail; + } + + parent = cursor; + cursor = json_object_get(parent, token); + + if (!cursor) { + if (!json_is_object(parent)) { + jsonp_error_set(error, -1, -1, peek - buf, json_error_item_not_found, "object expected"); + goto fail; + } + if (delim == object_delim) { + cursor = json_object(); + json_object_set_new(parent, token, cursor); + } else { + jsonp_error_set(error, -1, -1, peek - buf, json_error_item_not_found, "new array is not allowed"); + goto fail; + } + } + } + expect = (delim == array_open ? array_close : path_delims); + token = peek; + } else if (expect == array_close) { + char *endptr; + size_t index; + + parent = cursor; + if (!json_is_array(parent)) { + jsonp_error_set(error, -1, -1, peek - buf, json_error_item_not_found, "array expected"); + goto fail; + } + index = strtol(token, &endptr, 0); + if (*endptr) { + jsonp_error_set(error, -1, -1, peek - buf, json_error_item_not_found, "invalid array index"); + goto fail; + } + cursor = json_array_get(parent, index); + if (!cursor) { + jsonp_error_set(error, -1, -1, peek - buf, json_error_item_not_found, "array index out of bound"); + goto fail; + } + index_saved = index; + token = NULL; + expect = path_delims; + } else { + assert(1); + jsonp_error_set(error, -1, -1, peek - buf, json_error_unknown, "unexpected error in path move"); + goto fail; + } + } + + if (token) { + if (json_is_object(cursor)) { + json_object_set(cursor, token, value); + } else { + jsonp_error_set(error, -1, -1, peek - buf, json_error_item_not_found, "object expected"); + goto fail; + } + cursor = json_object_get(cursor, token); + } else if (index_saved != -1 && json_is_array(parent)) { + json_array_set(parent, index_saved, value); + cursor = json_array_get(parent, index_saved); + } else { + jsonp_error_set(error, -1, -1, peek - buf, json_error_item_not_found, "invalid path"); + goto fail; + } + + json_decref(value); + jsonp_free(buf); + return 0; + +fail: + json_decref(value); + jsonp_free(buf); + return -1; +} From dc3e2acf33a1f62b530d3a199073c1b9bfebf9b5 Mon Sep 17 00:00:00 2001 From: Oleg Moiseenko <807634+merlokk@users.noreply.github.com> Date: Wed, 17 Oct 2018 21:55:04 +0300 Subject: [PATCH 005/189] mf plus info with detect sl mode (#695) --- client/Makefile | 1 + client/cmdhf.c | 2 + client/cmdhfmfp.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++ client/cmdhfmfp.h | 18 +++++++ 4 files changed, 143 insertions(+) create mode 100644 client/cmdhfmfp.c create mode 100644 client/cmdhfmfp.h diff --git a/client/Makefile b/client/Makefile index f1007b89..c0a319a4 100644 --- a/client/Makefile +++ b/client/Makefile @@ -156,6 +156,7 @@ CMDSRCS = $(SRC_SMARTCARD) \ cmdhflegic.c \ cmdhficlass.c \ cmdhfmf.c \ + cmdhfmfp.c \ cmdhfmfu.c \ cmdhfmfhard.c \ hardnested/hardnested_bruteforce.c \ diff --git a/client/cmdhf.c b/client/cmdhf.c index b973354d..762cc791 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -28,6 +28,7 @@ #include "cmdhflegic.h" #include "cmdhficlass.h" #include "cmdhfmf.h" +#include "cmdhfmfp.h" #include "cmdhfmfu.h" #include "cmdhftopaz.h" #include "protocols.h" @@ -595,6 +596,7 @@ static command_t CommandTable[] = {"iclass", CmdHFiClass, 1, "{ ICLASS RFIDs... }"}, {"mf", CmdHFMF, 1, "{ MIFARE RFIDs... }"}, {"mfu", CmdHFMFUltra, 1, "{ MIFARE Ultralight RFIDs... }"}, + {"mfp", CmdHFMFP, 1, "{ MIFARE Plus RFIDs... }"}, {"topaz", CmdHFTopaz, 1, "{ TOPAZ (NFC Type 1) RFIDs... }"}, {"tune", CmdHFTune, 0, "Continuously measure HF antenna tuning"}, {"list", CmdHFList, 1, "List protocol data in trace buffer"}, diff --git a/client/cmdhfmfp.c b/client/cmdhfmfp.c new file mode 100644 index 00000000..34abbed0 --- /dev/null +++ b/client/cmdhfmfp.c @@ -0,0 +1,122 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2018 Merlok +// +// 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 MIFARE Plus commands +//----------------------------------------------------------------------------- + +#include "cmdhfmfp.h" + +#include +#include +#include +#include +#include +#include "comms.h" +#include "cmdmain.h" +#include "util.h" +#include "ui.h" +#include "cmdhf14a.h" +#include "mifare.h" + +static int CmdHelp(const char *Cmd); + +int CmdHFMFPInfo(const char *cmd) { + + if (cmd && strlen(cmd) > 0) + PrintAndLog("WARNING: command don't have any parameters.\n"); + + // info about 14a part + CmdHF14AInfo(""); + + // Mifare Plus info + UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0}}; + SendCommand(&c); + + UsbCommand resp; + WaitForResponse(CMD_ACK,&resp); + + iso14a_card_select_t card; + memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t)); + + uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision + + if (select_status == 1 || select_status == 2) { + PrintAndLog("----------------------------------------------"); + PrintAndLog("Mifare Plus info:"); + + // MIFARE Type Identification Procedure + // https://www.nxp.com/docs/en/application-note/AN10833.pdf + uint16_t ATQA = card.atqa[0] + (card.atqa[1] << 8); + if (ATQA == 0x0004) PrintAndLog("ATQA: Mifare Plus 2k 4bUID"); + if (ATQA == 0x0002) PrintAndLog("ATQA: Mifare Plus 4k 4bUID"); + if (ATQA == 0x0044) PrintAndLog("ATQA: Mifare Plus 2k 7bUID"); + if (ATQA == 0x0042) PrintAndLog("ATQA: Mifare Plus 4k 7bUID"); + + uint8_t SLmode = 0xff; + if (card.sak == 0x08) { + PrintAndLog("SAK: Mifare Plus 2k 7bUID"); + if (select_status == 2) SLmode = 1; + } + if (card.sak == 0x18) { + PrintAndLog("SAK: Mifare Plus 4k 7bUID"); + if (select_status == 2) SLmode = 1; + } + if (card.sak == 0x10) { + PrintAndLog("SAK: Mifare Plus 2k"); + if (select_status == 2) SLmode = 2; + } + if (card.sak == 0x11) { + PrintAndLog("SAK: Mifare Plus 4k"); + if (select_status == 2) SLmode = 2; + } + if (card.sak == 0x20) { + PrintAndLog("SAK: Mifare Plus SL0/SL3 or Mifare desfire"); + if (card.ats_len > 0) { + SLmode = 3; + + // check SL0 + uint8_t data[250] = {0}; + int datalen = 0; + // https://github.com/Proxmark/proxmark3/blob/master/client/scripts/mifarePlus.lua#L161 + uint8_t cmd[3 + 16] = {0xa8, 0x90, 0x90, 0x00}; + int res = ExchangeRAW14a(cmd, sizeof(cmd), false, false, data, sizeof(data), &datalen); + if (!res && datalen > 1 && data[0] == 0x09) { + SLmode = 0; + } + } + } + + if (SLmode != 0xff) + PrintAndLog("Mifare Plus SL mode: SL%d", SLmode); + else + PrintAndLog("Mifare Plus SL mode: unknown("); + } else { + PrintAndLog("Mifare Plus info not available."); + } + + DropField(); + + return 0; +} + +static command_t CommandTable[] = +{ + {"help", CmdHelp, 1, "This help"}, + {"info", CmdHFMFPInfo, 0, "Info about Mifare Plus tag"}, + {NULL, NULL, 0, NULL} +}; + +int CmdHFMFP(const char *Cmd) { + (void)WaitForResponseTimeout(CMD_ACK,NULL,100); + CmdsParse(CommandTable, Cmd); + return 0; +} + +int CmdHelp(const char *Cmd) { + CmdsHelp(CommandTable); + return 0; +} diff --git a/client/cmdhfmfp.h b/client/cmdhfmfp.h new file mode 100644 index 00000000..b1ac7c34 --- /dev/null +++ b/client/cmdhfmfp.h @@ -0,0 +1,18 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2018 Merlok +// +// 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 MIFARE Plus commands +//----------------------------------------------------------------------------- +#ifndef CMDHFMFP_H__ +#define CMDHFMFP_H__ + +#include "mifaredefault.h" + +extern int CmdHFMFP(const char *Cmd); + + +#endif \ No newline at end of file From 666fa6e1cfdc81acd1525ff4153c077535aa205a Mon Sep 17 00:00:00 2001 From: Oleg Moiseenko <807634+merlokk@users.noreply.github.com> Date: Mon, 22 Oct 2018 23:27:37 +0300 Subject: [PATCH 006/189] deploy in msys2 and proxspace (#702) --- CI/appveyor.yml | 42 +++++++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/CI/appveyor.yml b/CI/appveyor.yml index f5ae2c70..1c22c92e 100644 --- a/CI/appveyor.yml +++ b/CI/appveyor.yml @@ -66,9 +66,20 @@ clone_script: Write-Host "[ OK ]" -ForegroundColor Green - Write-Host "Fill msys\etc\fstab file..." -NoNewLine + Write-Host "Fill msys2\etc\fstab file..." -NoNewLine - New-Item c:\ProxSpace\msys\etc\fstab -type file -force -value "#Win32_Path Mount_Point`nc:\ProxSpace\devkitARM /devkitARM`nc:\ProxSpace\Qt\5.6 /qt `nc:\ProxSpace\pm3 /pm3`n" + New-Item c:\ProxSpace\msys2\etc\fstab -type file -force -value "# For a description of the file format, see the Users Guide`n# http://cygwin.com/cygwin-ug-net/using.html#mount-table`nnone / cygdrive binary,posix=0,noacl,user 0 0 `nC:\ProxSpace\pm3 /pm3 ntfs noacl 0 0 `nC:\ProxSpace\gcc-arm-none-eabi /gcc-arm-none-eabi ntfs noacl 0 0 `n" + + Write-Host "[ OK ]" -ForegroundColor Green + + + Write-Host "Update msys2 packages..." -NoNewLine + + $env:Path = "C:\ProxSpace\msys2\usr\bin;C:\ProxSpace\msys2\mingw32\bin;C:\ProxSpace\gcc-arm-none-eabi\bin;$env:Path" + + C:\ProxSpace\msys2\msys2_shell.cmd -mingw32 -defterm -no-start /dev/null 1> msys1.txt 2>&1 + + C:\ProxSpace\msys2\msys2_shell.cmd -mingw32 -defterm -no-start /dev/null 1> msys1.txt 2>&1 Write-Host "[ OK ]" -ForegroundColor Green install: @@ -84,12 +95,25 @@ install: } build_script: - ps: >- - $env:Path = "C:\ProxSpace\msys\bin;$env:Path" + "C:\ProxSpace\msys2\usr\bin;C:\ProxSpace\msys2\mingw32\bin;C:\ProxSpace\gcc-arm-none-eabi\bin;$env:Path" + + + $env:MINGW_HOME="C:\ProxSpace\msys2\mingw32" + + $env:MSYS_HOME="C:\ProxSpace\msys2" + + $env:MSYSTEM="MINGW32" + + $env:MINGW_PREFIX="/mingw32" + + $env:SHELL="/bin/bash" + + $env:MSYSTEM_CHOST="i686-w64-mingw32" #make - bash -lc -i "pwd;make all" + bash -c -i 'pwd;make clean;make all' #some checks @@ -268,19 +292,19 @@ test_script: #proxmark logic tests - ExecTest "proxmark help" "proxmark3 -h" {bash -lc 'cd ~/client;proxmark3 -h | grep -q Execute && echo Passed || echo Failed'} + ExecTest "proxmark help" "proxmark3 -h" {bash -lc 'cd ~/client;./proxmark3 -h | grep -q Execute && echo Passed || echo Failed'} - ExecTest "proxmark help hardnested" "proxmark3 -h" {bash -lc 'cd ~/client;proxmark3 -h | grep -q hardnested && echo Passed || echo Failed'} + ExecTest "proxmark help hardnested" "proxmark3 -h" {bash -lc 'cd ~/client;./proxmark3 -h | grep -q hardnested && echo Passed || echo Failed'} - ExecTest "hf mf offline text" "hf mf" {bash -lc "cd ~/client;proxmark3 comx -c 'hf mf'"} "at_enc" + ExecTest "hf mf offline text" "hf mf" {bash -lc "cd ~/client;./proxmark3 comx -c 'hf mf'"} "at_enc" - ExecTest "hf mf hardnested" "hf mf hardnested" {bash -lc "cd ~/client;proxmark3 comx -c 'hf mf hardnested t 1 000000000000'"} "found:" + ExecTest "hf mf hardnested" "hf mf hardnested" {bash -lc "cd ~/client;./proxmark3 comx -c 'hf mf hardnested t 1 000000000000'"} "found:" #proxmark crypto tests - ExecTest "hf emv test" "hf emv test" {bash -lc "cd ~/client;proxmark3 comx -c 'hf emv test'"} "Tests ?OK" + ExecTest "hf emv test" "hf emv test" {bash -lc "cd ~/client;./proxmark3 comx -c 'hf emv test'"} "Tests ?OK" if ($global:TestsPassed) { From 8c6cca0ba1424200dcb872eb96918281c9e62784 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Tue, 23 Oct 2018 08:22:13 +0200 Subject: [PATCH 007/189] Fix hf 15 sim (#696) * added ISO15693 coding for tag messages (CodeIso15693AsTag()) * added ISO15693 decoding for reader commands (Handle15693SampleFromReader()) * send tag inventory response in either high or low speed * some refactoring and formatting --- armsrc/iso15693.c | 1059 +++++++++++++++++++++++++--------------- armsrc/util.c | 24 +- client/cmdhf15.c | 103 ++-- common/iso15693tools.h | 64 +-- common/protocols.h | 60 ++- fpga/hi_simulate.v | 45 +- 6 files changed, 789 insertions(+), 566 deletions(-) diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 9b0ab29e..9479c3c0 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -2,33 +2,31 @@ // Jonathan Westhues, split Nov 2006 // Modified by Greg Jones, Jan 2009 // Modified by Adrian Dabrowski "atrox", Mar-Sept 2010,Oct 2011 +// Modified by piwi, Oct 2018 // // 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. //----------------------------------------------------------------------------- // Routines to support ISO 15693. This includes both the reader software and -// the `fake tag' modes, but at the moment I've implemented only the reader -// stuff, and that barely. -// Modified to perform modulation onboard in arm rather than on PC -// Also added additional reader commands (SELECT, READ etc.) +// the `fake tag' modes. //----------------------------------------------------------------------------- -// The ISO 15693 describes two transmission modes from reader to tag, and 4 -// transmission modes from tag to reader. As of Mar 2010 this code only -// supports one of each: "1of4" mode from reader to tag, and the highspeed -// variant with one subcarrier from card to reader. -// As long, as the card fully support ISO 15693 this is no problem, since the -// reader chooses both data rates, but some non-standard tags do not. Further for -// the simulation to work, we will need to support all data rates. + +// The ISO 15693 describes two transmission modes from reader to tag, and four +// transmission modes from tag to reader. As of Oct 2018 this code supports +// both reader modes and the high speed variant with one subcarrier from card to reader. +// As long as the card fully support ISO 15693 this is no problem, since the +// reader chooses both data rates, but some non-standard tags do not. +// For card simulation, the code supports both high and low speed modes with one subcarrier. // // VCD (reader) -> VICC (tag) // 1 out of 256: -// data rate: 1,66 kbit/s (fc/8192) +// data rate: 1,66 kbit/s (fc/8192) // used for long range // 1 out of 4: // data rate: 26,48 kbit/s (fc/512) // used for short range, high speed -// +// // VICC (tag) -> VCD (reader) // Modulation: // ASK / one subcarrier (423,75 khz) @@ -39,22 +37,17 @@ // high ASK: 26,48 kbit/s // high FSK: 26,69 kbit/s //----------------------------------------------------------------------------- -// added "1 out of 256" mode (for VCD->PICC) - atrox 20100911 // Random Remarks: // *) UID is always used "transmission order" (LSB), which is reverse to display order // TODO / BUGS / ISSUES: -// *) writing to tags takes longer: we miss the answer from the tag in most cases -// -> tweak the read-timeout times -// *) signal decoding from the card is still a bit shaky. -// *) signal decoding is unable to detect collissions. -// *) add anti-collission support for inventory-commands +// *) signal decoding is unable to detect collisions. +// *) add anti-collision support for inventory-commands // *) read security status of a block -// *) sniffing and simulation do only support one transmission mode. need to support -// all 8 transmission combinations -// *) remove or refactor code under "depricated" +// *) sniffing and simulation do not support two subcarrier modes. +// *) remove or refactor code under "depricated" // *) document all the functions @@ -63,6 +56,7 @@ #include "apps.h" #include "string.h" #include "iso15693tools.h" +#include "protocols.h" #include "cmd.h" #define arraylen(x) (sizeof(x)/sizeof((x)[0])) @@ -83,18 +77,25 @@ static int DEBUG = 0; #define AddCrc(data,datalen) Iso15693AddCrc(data,datalen) #define sprintUID(target,uid) Iso15693sprintUID(target,uid) -// approximate amplitude=sqrt(ci^2+cq^2) +// approximate amplitude=sqrt(ci^2+cq^2) by amplitude = max(|ci|,|cq|) + 1/2*min(|ci|,|cq|) #define AMPLITUDE(ci, cq) (MAX(ABS(ci), ABS(cq)) + MIN(ABS(ci), ABS(cq))/2) -// DMA buffer -#define ISO15693_DMA_BUFFER_SIZE 128 +// buffers +#define ISO15693_DMA_BUFFER_SIZE 128 +#define ISO15693_MAX_RESPONSE_LENGTH 36 // allows read single block with the maximum block size of 256bits. Read multiple blocks not supported yet +#define ISO15693_MAX_COMMAND_LENGTH 45 // allows write single block with the maximum block size of 256bits. Write multiple blocks not supported yet + +// timing. Delays in SSP_CLK ticks. +#define DELAY_READER_TO_ARM 8 +#define DELAY_ARM_TO_READER 1 +#define DELAY_ISO15693_VCD_TO_VICC 132 // 132/423.75kHz = 311.5us from end of EOF to start of tag response // --------------------------- -// Signal Processing +// Signal Processing // --------------------------- // prepare data using "1 out of 4" code for later transmission -// resulting data rate is 26,48 kbit/s (fc/512) +// resulting data rate is 26.48 kbit/s (fc/512) // cmd ... data // n ... length of data static void CodeIso15693AsReader(uint8_t *cmd, int n) @@ -174,12 +175,10 @@ static void CodeIso15693AsReader(uint8_t *cmd, int n) for(i = 0; i < 4; i++) { ToSendStuffBit(1); } - - ToSendMax++; } // encode data using "1 out of 256" scheme -// data rate is 1,66 kbit/s (fc/8192) +// data rate is 1,66 kbit/s (fc/8192) // is designed for more robust communication over longer distances static void CodeIso15693AsReader256(uint8_t *cmd, int n) { @@ -201,7 +200,7 @@ static void CodeIso15693AsReader256(uint8_t *cmd, int n) ToSendStuffBit(1); ToSendStuffBit(1); ToSendStuffBit(0); - + for(i = 0; i < n; i++) { for (j = 0; j<=255; j++) { if (cmd[i]==j) { @@ -210,8 +209,8 @@ static void CodeIso15693AsReader256(uint8_t *cmd, int n) } else { ToSendStuffBit(1); ToSendStuffBit(1); - } - } + } + } } // EOF ToSendStuffBit(1); @@ -219,10 +218,53 @@ static void CodeIso15693AsReader256(uint8_t *cmd, int n) ToSendStuffBit(0); ToSendStuffBit(1); - // And slack at the end, too. - for(i = 0; i < 24; i++) { + // Fill remainder of last byte with 1 + for(i = 0; i < 4; i++) { ToSendStuffBit(1); } + + ToSendMax++; +} + + +static void CodeIso15693AsTag(uint8_t *cmd, int n) +{ + ToSendReset(); + + // SOF + ToSendStuffBit(0); + ToSendStuffBit(0); + ToSendStuffBit(0); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(0); + ToSendStuffBit(1); + + // data + for(int i = 0; i < n; i++) { + for(int j = 0; j < 8; j++) { + if ((cmd[i] >> j) & 0x01) { + ToSendStuffBit(0); + ToSendStuffBit(1); + } else { + ToSendStuffBit(1); + ToSendStuffBit(0); + } + } + } + + // EOF + ToSendStuffBit(1); + ToSendStuffBit(0); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(1); + ToSendStuffBit(0); + ToSendStuffBit(0); + ToSendStuffBit(0); + + ToSendMax++; } @@ -244,29 +286,50 @@ static void TransmitTo15693Tag(const uint8_t *cmd, int len) } //----------------------------------------------------------------------------- -// Transmit the command (to the reader) that was placed in cmd[]. +// Transmit the tag response (to the reader) that was placed in cmd[]. //----------------------------------------------------------------------------- -static void TransmitTo15693Reader(const uint8_t *cmd, int len) +static void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t start_time, bool slow) { + // don't use the FPGA_HF_SIMULATOR_MODULATE_424K_8BIT minor mode. It would spoil GetCountSspClk() FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_424K); + uint8_t shift_delay = start_time & 0x00000007; + uint8_t bitmask = 0x00; + for (int i = 0; i < shift_delay; i++) { + bitmask |= (0x01 << i); + } + + while (GetCountSspClk() < (start_time & 0xfffffff8)) ; + AT91C_BASE_SSC->SSC_THR = 0x00; // clear TXRDY + LED_C_ON(); - for(int c = 0; c < len; ) { - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = cmd[c]; - c++; + uint8_t bits_to_shift = 0x00; + for(size_t c = 0; c <= len; c++) { + uint8_t bits_to_send = bits_to_shift << (8 - shift_delay) | (c==len?0x00:cmd[c]) >> shift_delay; + bits_to_shift = cmd[c] & bitmask; + for (int i = 7; i >= 0; i--) { + for (int j = 0; j < (slow?4:1); ) { + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { + if (bits_to_send >> i & 0x01) { + AT91C_BASE_SSC->SSC_THR = 0xff; + } else { + AT91C_BASE_SSC->SSC_THR = 0x00; + } + j++; + } + WDT_HIT(); + } } - WDT_HIT(); } LED_C_OFF(); } //============================================================================= -// An ISO 15693 demodulator (one subcarrier only). Uses cross correlation to -// identify the SOF, each bit, and EOF. +// An ISO 15693 decoder for tag responses (one subcarrier only). +// Uses cross correlation to identify the SOF, each bit, and EOF. // This function is called 8 times per bit (every 2 subcarrier cycles). -// Subcarrier frequency fs is 424kHz, 1/fs = 2,36us, +// Subcarrier frequency fs is 424kHz, 1/fs = 2,36us, // i.e. function is called every 4,72us // LED handling: // LED C -> ON once we have received the SOF and are expecting the rest. @@ -279,13 +342,13 @@ static void TransmitTo15693Reader(const uint8_t *cmd, int len) #define SUBCARRIER_DETECT_THRESHOLD 2 #define SOF_CORRELATOR_LEN (1<<5) -typedef struct Demod { +typedef struct DecodeTag { enum { - DEMOD_UNSYNCD, - DEMOD_AWAIT_SOF_1, - DEMOD_AWAIT_SOF_2, - DEMOD_RECEIVING_DATA, - DEMOD_AWAIT_EOF + STATE_TAG_UNSYNCD, + STATE_TAG_AWAIT_SOF_1, + STATE_TAG_AWAIT_SOF_2, + STATE_TAG_RECEIVING_DATA, + STATE_TAG_AWAIT_EOF } state; int bitCount; int posCount; @@ -305,145 +368,145 @@ typedef struct Demod { int32_t SOF_corr; int32_t SOF_corr_prev; uint8_t SOF_correlator[SOF_CORRELATOR_LEN]; -} Demod_t; +} DecodeTag_t; -static RAMFUNC int Handle15693SamplesDemod(int8_t ci, int8_t cq, Demod_t *Demod) +static int Handle15693SamplesFromTag(int8_t ci, int8_t cq, DecodeTag_t *DecodeTag) { - switch(Demod->state) { - case DEMOD_UNSYNCD: + switch(DecodeTag->state) { + case STATE_TAG_UNSYNCD: // initialize SOF correlator. We are looking for 12 samples low and 12 samples high. - Demod->SOF_low = 0; - Demod->SOF_high = 12; - Demod->SOF_last = 23; - memset(Demod->SOF_correlator, 0x00, Demod->SOF_last + 1); - Demod->SOF_correlator[Demod->SOF_last] = AMPLITUDE(ci,cq); - Demod->SOF_corr = Demod->SOF_correlator[Demod->SOF_last]; - Demod->SOF_corr_prev = Demod->SOF_corr; - // initialize Demodulator - Demod->posCount = 0; - Demod->bitCount = 0; - Demod->len = 0; - Demod->state = DEMOD_AWAIT_SOF_1; + DecodeTag->SOF_low = 0; + DecodeTag->SOF_high = 12; + DecodeTag->SOF_last = 23; + memset(DecodeTag->SOF_correlator, 0x00, DecodeTag->SOF_last + 1); + DecodeTag->SOF_correlator[DecodeTag->SOF_last] = AMPLITUDE(ci,cq); + DecodeTag->SOF_corr = DecodeTag->SOF_correlator[DecodeTag->SOF_last]; + DecodeTag->SOF_corr_prev = DecodeTag->SOF_corr; + // initialize Decoder + DecodeTag->posCount = 0; + DecodeTag->bitCount = 0; + DecodeTag->len = 0; + DecodeTag->state = STATE_TAG_AWAIT_SOF_1; break; - - case DEMOD_AWAIT_SOF_1: + + case STATE_TAG_AWAIT_SOF_1: // calculate the correlation in real time. Look at differences only. - Demod->SOF_corr += Demod->SOF_correlator[Demod->SOF_low++]; - Demod->SOF_corr -= 2*Demod->SOF_correlator[Demod->SOF_high++]; - Demod->SOF_last++; - Demod->SOF_low &= (SOF_CORRELATOR_LEN-1); - Demod->SOF_high &= (SOF_CORRELATOR_LEN-1); - Demod->SOF_last &= (SOF_CORRELATOR_LEN-1); - Demod->SOF_correlator[Demod->SOF_last] = AMPLITUDE(ci,cq); - Demod->SOF_corr += Demod->SOF_correlator[Demod->SOF_last]; + DecodeTag->SOF_corr += DecodeTag->SOF_correlator[DecodeTag->SOF_low++]; + DecodeTag->SOF_corr -= 2*DecodeTag->SOF_correlator[DecodeTag->SOF_high++]; + DecodeTag->SOF_last++; + DecodeTag->SOF_low &= (SOF_CORRELATOR_LEN-1); + DecodeTag->SOF_high &= (SOF_CORRELATOR_LEN-1); + DecodeTag->SOF_last &= (SOF_CORRELATOR_LEN-1); + DecodeTag->SOF_correlator[DecodeTag->SOF_last] = AMPLITUDE(ci,cq); + DecodeTag->SOF_corr += DecodeTag->SOF_correlator[DecodeTag->SOF_last]; // if correlation increases for 10 consecutive samples, we are close to maximum correlation - if (Demod->SOF_corr > Demod->SOF_corr_prev + SUBCARRIER_DETECT_THRESHOLD) { - Demod->posCount++; + if (DecodeTag->SOF_corr > DecodeTag->SOF_corr_prev + SUBCARRIER_DETECT_THRESHOLD) { + DecodeTag->posCount++; } else { - Demod->posCount = 0; + DecodeTag->posCount = 0; } - if (Demod->posCount == 10) { // correlation increased 10 times - Demod->state = DEMOD_AWAIT_SOF_2; + if (DecodeTag->posCount == 10) { // correlation increased 10 times + DecodeTag->state = STATE_TAG_AWAIT_SOF_2; } - - Demod->SOF_corr_prev = Demod->SOF_corr; - + + DecodeTag->SOF_corr_prev = DecodeTag->SOF_corr; + break; - case DEMOD_AWAIT_SOF_2: + case STATE_TAG_AWAIT_SOF_2: // calculate the correlation in real time. Look at differences only. - Demod->SOF_corr += Demod->SOF_correlator[Demod->SOF_low++]; - Demod->SOF_corr -= 2*Demod->SOF_correlator[Demod->SOF_high++]; - Demod->SOF_last++; - Demod->SOF_low &= (SOF_CORRELATOR_LEN-1); - Demod->SOF_high &= (SOF_CORRELATOR_LEN-1); - Demod->SOF_last &= (SOF_CORRELATOR_LEN-1); - Demod->SOF_correlator[Demod->SOF_last] = AMPLITUDE(ci,cq); - Demod->SOF_corr += Demod->SOF_correlator[Demod->SOF_last]; + DecodeTag->SOF_corr += DecodeTag->SOF_correlator[DecodeTag->SOF_low++]; + DecodeTag->SOF_corr -= 2*DecodeTag->SOF_correlator[DecodeTag->SOF_high++]; + DecodeTag->SOF_last++; + DecodeTag->SOF_low &= (SOF_CORRELATOR_LEN-1); + DecodeTag->SOF_high &= (SOF_CORRELATOR_LEN-1); + DecodeTag->SOF_last &= (SOF_CORRELATOR_LEN-1); + DecodeTag->SOF_correlator[DecodeTag->SOF_last] = AMPLITUDE(ci,cq); + DecodeTag->SOF_corr += DecodeTag->SOF_correlator[DecodeTag->SOF_last]; - if (Demod->SOF_corr >= Demod->SOF_corr_prev) { // we are looking for the maximum correlation - Demod->SOF_corr_prev = Demod->SOF_corr; + if (DecodeTag->SOF_corr >= DecodeTag->SOF_corr_prev) { // we are looking for the maximum correlation + DecodeTag->SOF_corr_prev = DecodeTag->SOF_corr; } else { - Demod->lastBit = SOF_PART1; // detected 1st part of SOF - Demod->sum1 = Demod->SOF_correlator[Demod->SOF_last]; - Demod->sum2 = 0; - Demod->posCount = 2; - Demod->state = DEMOD_RECEIVING_DATA; + DecodeTag->lastBit = SOF_PART1; // detected 1st part of SOF + DecodeTag->sum1 = DecodeTag->SOF_correlator[DecodeTag->SOF_last]; + DecodeTag->sum2 = 0; + DecodeTag->posCount = 2; + DecodeTag->state = STATE_TAG_RECEIVING_DATA; LED_C_ON(); } - + break; - case DEMOD_RECEIVING_DATA: - if (Demod->posCount == 1) { - Demod->sum1 = 0; - Demod->sum2 = 0; + case STATE_TAG_RECEIVING_DATA: + if (DecodeTag->posCount == 1) { + DecodeTag->sum1 = 0; + DecodeTag->sum2 = 0; } - if (Demod->posCount <= 4) { - Demod->sum1 += AMPLITUDE(ci, cq); + if (DecodeTag->posCount <= 4) { + DecodeTag->sum1 += AMPLITUDE(ci, cq); } else { - Demod->sum2 += AMPLITUDE(ci, cq); + DecodeTag->sum2 += AMPLITUDE(ci, cq); } - if (Demod->posCount == 8) { - int16_t corr_1 = (Demod->sum2 - Demod->sum1) / 4; - int16_t corr_0 = (Demod->sum1 - Demod->sum2) / 4; - int16_t corr_EOF = (Demod->sum1 + Demod->sum2) / 8; + if (DecodeTag->posCount == 8) { + int16_t corr_1 = (DecodeTag->sum2 - DecodeTag->sum1) / 4; + int16_t corr_0 = (DecodeTag->sum1 - DecodeTag->sum2) / 4; + int16_t corr_EOF = (DecodeTag->sum1 + DecodeTag->sum2) / 8; if (corr_EOF > corr_0 && corr_EOF > corr_1) { - Demod->state = DEMOD_AWAIT_EOF; + DecodeTag->state = STATE_TAG_AWAIT_EOF; } else if (corr_1 > corr_0) { // logic 1 - if (Demod->lastBit == SOF_PART1) { // still part of SOF - Demod->lastBit = SOF_PART2; + if (DecodeTag->lastBit == SOF_PART1) { // still part of SOF + DecodeTag->lastBit = SOF_PART2; } else { - Demod->lastBit = LOGIC1; - Demod->shiftReg >>= 1; - Demod->shiftReg |= 0x80; - Demod->bitCount++; - if (Demod->bitCount == 8) { - Demod->output[Demod->len] = Demod->shiftReg; - Demod->len++; - Demod->bitCount = 0; - Demod->shiftReg = 0; + DecodeTag->lastBit = LOGIC1; + DecodeTag->shiftReg >>= 1; + DecodeTag->shiftReg |= 0x80; + DecodeTag->bitCount++; + if (DecodeTag->bitCount == 8) { + DecodeTag->output[DecodeTag->len] = DecodeTag->shiftReg; + DecodeTag->len++; + DecodeTag->bitCount = 0; + DecodeTag->shiftReg = 0; } } } else { // logic 0 - if (Demod->lastBit == SOF_PART1) { // incomplete SOF - Demod->state = DEMOD_UNSYNCD; + if (DecodeTag->lastBit == SOF_PART1) { // incomplete SOF + DecodeTag->state = STATE_TAG_UNSYNCD; LED_C_OFF(); } else { - Demod->lastBit = LOGIC0; - Demod->shiftReg >>= 1; - Demod->bitCount++; - if (Demod->bitCount == 8) { - Demod->output[Demod->len] = Demod->shiftReg; - Demod->len++; - Demod->bitCount = 0; - Demod->shiftReg = 0; + DecodeTag->lastBit = LOGIC0; + DecodeTag->shiftReg >>= 1; + DecodeTag->bitCount++; + if (DecodeTag->bitCount == 8) { + DecodeTag->output[DecodeTag->len] = DecodeTag->shiftReg; + DecodeTag->len++; + DecodeTag->bitCount = 0; + DecodeTag->shiftReg = 0; } } } - Demod->posCount = 0; + DecodeTag->posCount = 0; } - Demod->posCount++; + DecodeTag->posCount++; break; - - case DEMOD_AWAIT_EOF: - if (Demod->lastBit == LOGIC0) { // this was already part of EOF + + case STATE_TAG_AWAIT_EOF: + if (DecodeTag->lastBit == LOGIC0) { // this was already part of EOF LED_C_OFF(); return true; } else { - Demod->state = DEMOD_UNSYNCD; + DecodeTag->state = STATE_TAG_UNSYNCD; LED_C_OFF(); } break; default: - Demod->state = DEMOD_UNSYNCD; + DecodeTag->state = STATE_TAG_UNSYNCD; LED_C_OFF(); break; } @@ -452,15 +515,14 @@ static RAMFUNC int Handle15693SamplesDemod(int8_t ci, int8_t cq, Demod_t *Demod) } -static void DemodInit(Demod_t* Demod, uint8_t* data) +static void DecodeTagInit(DecodeTag_t *DecodeTag, uint8_t *data) { - Demod->output = data; - Demod->state = DEMOD_UNSYNCD; + DecodeTag->output = data; + DecodeTag->state = STATE_TAG_UNSYNCD; } - /* - * Demodulate the samples we received from the tag, also log to tracebuffer + * Receive and decode the tag response, also log to tracebuffer */ static int GetIso15693AnswerFromTag(uint8_t* response, int timeout) { @@ -468,19 +530,12 @@ static int GetIso15693AnswerFromTag(uint8_t* response, int timeout) int lastRxCounter, samples = 0; int8_t ci, cq; bool gotFrame = false; - - // Allocate memory from BigBuf for some buffers - // free all previous allocations first - BigBuf_free(); - // The DMA buffer, used to stream samples from the FPGA - uint16_t* dmaBuf = (uint16_t*) BigBuf_malloc(ISO15693_DMA_BUFFER_SIZE * sizeof(uint16_t)); + uint16_t dmaBuf[ISO15693_DMA_BUFFER_SIZE]; - // the Demodulatur data structure - Demod_t* Demod = (Demod_t*) BigBuf_malloc(sizeof(Demod_t)); - - // Set up the demodulator for tag -> reader responses. - DemodInit(Demod, response); + // the Decoder data structure + DecodeTag_t DecodeTag; + DecodeTagInit(&DecodeTag, response); // wait for last transfer to complete while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)); @@ -491,7 +546,6 @@ static int GetIso15693AnswerFromTag(uint8_t* response, int timeout) // Setup and start DMA. FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); FpgaSetupSscDma((uint8_t*) dmaBuf, ISO15693_DMA_BUFFER_SIZE); - uint16_t *upTo = dmaBuf; lastRxCounter = ISO15693_DMA_BUFFER_SIZE; @@ -502,7 +556,7 @@ static int GetIso15693AnswerFromTag(uint8_t* response, int timeout) } if (behindBy < 1) continue; - + ci = (int8_t)(*upTo >> 8); cq = (int8_t)(*upTo & 0xff); @@ -518,156 +572,367 @@ static int GetIso15693AnswerFromTag(uint8_t* response, int timeout) } samples++; - if (Handle15693SamplesDemod(ci, cq, Demod)) { + if (Handle15693SamplesFromTag(ci, cq, &DecodeTag)) { gotFrame = true; break; } - if(samples > timeout && Demod->state < DEMOD_RECEIVING_DATA) { - Demod->len = 0; + if(samples > timeout && DecodeTag.state < STATE_TAG_RECEIVING_DATA) { + DecodeTag.len = 0; break; } + } FpgaDisableSscDma(); - if (DEBUG) Dbprintf("max behindby = %d, samples = %d, gotFrame = %d, Demod.state = %d, Demod.len = %d, Demod.bitCount = %d, Demod.posCount = %d", - maxBehindBy, samples, gotFrame, Demod->state, Demod->len, Demod->bitCount, Demod->posCount); + if (DEBUG) Dbprintf("max behindby = %d, samples = %d, gotFrame = %d, Decoder: state = %d, len = %d, bitCount = %d, posCount = %d", + maxBehindBy, samples, gotFrame, DecodeTag.state, DecodeTag.len, DecodeTag.bitCount, DecodeTag.posCount); - if (tracing && Demod->len > 0) { - uint8_t parity[MAX_PARITY_SIZE]; - LogTrace(Demod->output, Demod->len, 0, 0, parity, false); + if (tracing && DecodeTag.len > 0) { + LogTrace(DecodeTag.output, DecodeTag.len, 0, 0, NULL, false); } - return Demod->len; + return DecodeTag.len; } -// Now the GetISO15693 message from sniffing command -// TODO: fix it. This cannot work for several reasons: -// 1. Carrier is switched on during sniffing? -// 2. We most probable miss the next reader command when demodulating -static int GetIso15693AnswerFromSniff(uint8_t *receivedResponse, int maxLen, int *samples, int *elapsed) +//============================================================================= +// An ISO15693 decoder for reader commands. +// +// This function is called 4 times per bit (every 2 subcarrier cycles). +// Subcarrier frequency fs is 848kHz, 1/fs = 1,18us, i.e. function is called every 2,36us +// LED handling: +// LED B -> ON once we have received the SOF and are expecting the rest. +// LED B -> OFF once we have received EOF or are in error state or unsynced +// +// Returns: true if we received a EOF +// false if we are still waiting for some more +//============================================================================= + +typedef struct DecodeReader { + enum { + STATE_READER_UNSYNCD, + STATE_READER_AWAIT_1ST_RISING_EDGE_OF_SOF, + STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF, + STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF, + STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4, + STATE_READER_RECEIVE_DATA_1_OUT_OF_4, + STATE_READER_RECEIVE_DATA_1_OUT_OF_256 + } state; + enum { + CODING_1_OUT_OF_4, + CODING_1_OUT_OF_256 + } Coding; + uint8_t shiftReg; + uint8_t bitCount; + int byteCount; + int byteCountMax; + int posCount; + int sum1, sum2; + uint8_t *output; +} DecodeReader_t; + + +static int Handle15693SampleFromReader(uint8_t bit, DecodeReader_t* DecodeReader) { - uint8_t *dest = BigBuf_get_addr(); - -// NOW READ RESPONSE - LED_D_ON(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); - //spindelay(60); // greg - experiment to get rid of some of the 0 byte/failed reads - for(int c = 0; c < BIGBUF_SIZE; ) { - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - uint16_t iq = AT91C_BASE_SSC->SSC_RHR; - // The samples are correlations against I and Q versions of the - // tone that the tag AM-modulates. We just want power, - // so abs(I) + abs(Q) is close to what we want. - int8_t i = (int8_t)(iq >> 8); - int8_t q = (int8_t)(iq & 0xff); - uint8_t r = AMPLITUDE(i, q); - dest[c++] = r; - } - } - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); - - ////////////////////////////////////////// - /////////// DEMODULATE /////////////////// - ////////////////////////////////////////// - - int i, j; - int max = 0, maxPos=0; - - int skip = 2; - - // First, correlate for SOF - for(i = 0; i < 38000; i++) { - int corr = 0; - for(j = 0; j < arraylen(FrameSOF); j += skip) { - corr += FrameSOF[j]*dest[i+(j/skip)]; - } - if(corr > max) { - max = corr; - maxPos = i; - } - } - - if (DEBUG) Dbprintf("SOF at %d, correlation %d", maxPos,max/(arraylen(FrameSOF)/skip)); - - int k = 0; // this will be our return value - - // greg - If correlation is less than 1 then there's little point in continuing - if ((max/(arraylen(FrameSOF)/skip)) >= 1) // THIS SHOULD BE 1 - { - - i = maxPos + arraylen(FrameSOF)/skip; - - uint8_t outBuf[20]; - memset(outBuf, 0, sizeof(outBuf)); - uint8_t mask = 0x01; - for(;;) { - int corr0 = 0, corr00 = 0, corr01 = 0, corr1 = 0, corrEOF = 0; - for(j = 0; j < arraylen(Logic0); j += skip) { - corr0 += Logic0[j]*dest[i+(j/skip)]; + switch(DecodeReader->state) { + case STATE_READER_UNSYNCD: + if(!bit) { + // we went low, so this could be the beginning of a SOF + DecodeReader->state = STATE_READER_AWAIT_1ST_RISING_EDGE_OF_SOF; + DecodeReader->posCount = 1; } - corr01 = corr00 = corr0; - for(j = 0; j < arraylen(Logic0); j += skip) { - corr00 += Logic0[j]*dest[i+arraylen(Logic0)/skip+(j/skip)]; - corr01 += Logic1[j]*dest[i+arraylen(Logic0)/skip+(j/skip)]; - } - for(j = 0; j < arraylen(Logic1); j += skip) { - corr1 += Logic1[j]*dest[i+(j/skip)]; - } - for(j = 0; j < arraylen(FrameEOF); j += skip) { - corrEOF += FrameEOF[j]*dest[i+(j/skip)]; - } - // Even things out by the length of the target waveform. - corr00 *= 2; - corr01 *= 2; - corr0 *= 4; - corr1 *= 4; - - if(corrEOF > corr1 && corrEOF > corr00 && corrEOF > corr01) { - if (DEBUG) Dbprintf("EOF at %d, correlation %d (corr01: %d, corr00: %d, corr1: %d, corr0: %d)", - i, corrEOF, corr01, corr00, corr1, corr0); - break; - } else if(corr1 > corr0) { - i += arraylen(Logic1)/skip; - outBuf[k] |= mask; + break; + + case STATE_READER_AWAIT_1ST_RISING_EDGE_OF_SOF: + DecodeReader->posCount++; + if(bit) { // detected rising edge + if(DecodeReader->posCount < 4) { // rising edge too early (nominally expected at 5) + DecodeReader->state = STATE_READER_UNSYNCD; + } else { // SOF + DecodeReader->state = STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF; + } } else { - i += arraylen(Logic0)/skip; + if(DecodeReader->posCount > 5) { // stayed low for too long + DecodeReader->state = STATE_READER_UNSYNCD; + } else { + // do nothing, keep waiting + } } - mask <<= 1; - if(mask == 0) { - k++; - mask = 0x01; + break; + + case STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF: + DecodeReader->posCount++; + if(!bit) { // detected a falling edge + if (DecodeReader->posCount < 20) { // falling edge too early (nominally expected at 21 earliest) + DecodeReader->state = STATE_READER_UNSYNCD; + } else if (DecodeReader->posCount < 23) { // SOF for 1 out of 4 coding + DecodeReader->Coding = CODING_1_OUT_OF_4; + DecodeReader->state = STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF; + } else if (DecodeReader->posCount < 28) { // falling edge too early (nominally expected at 29 latest) + DecodeReader->state = STATE_READER_UNSYNCD; + } else { // SOF for 1 out of 4 coding + DecodeReader->Coding = CODING_1_OUT_OF_256; + DecodeReader->state = STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF; + } + } else { + if(DecodeReader->posCount > 29) { // stayed high for too long + DecodeReader->state = STATE_READER_UNSYNCD; + } else { + // do nothing, keep waiting + } } - if((i+(int)arraylen(FrameEOF)/skip) >= BIGBUF_SIZE) { - DbpString("ran off end!"); + break; + + case STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF: + DecodeReader->posCount++; + if (bit) { // detected rising edge + if (DecodeReader->Coding == CODING_1_OUT_OF_256) { + if (DecodeReader->posCount < 32) { // rising edge too early (nominally expected at 33) + DecodeReader->state = STATE_READER_UNSYNCD; + } else { + DecodeReader->posCount = 1; + DecodeReader->bitCount = 0; + DecodeReader->byteCount = 0; + DecodeReader->sum1 = 1; + DecodeReader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_256; + LED_B_ON(); + } + } else { // CODING_1_OUT_OF_4 + if (DecodeReader->posCount < 24) { // rising edge too early (nominally expected at 25) + DecodeReader->state = STATE_READER_UNSYNCD; + } else { + DecodeReader->state = STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4; + } + } + } else { + if (DecodeReader->Coding == CODING_1_OUT_OF_256) { + if (DecodeReader->posCount > 34) { // signal stayed low for too long + DecodeReader->state = STATE_READER_UNSYNCD; + } else { + // do nothing, keep waiting + } + } else { // CODING_1_OUT_OF_4 + if (DecodeReader->posCount > 26) { // signal stayed low for too long + DecodeReader->state = STATE_READER_UNSYNCD; + } else { + // do nothing, keep waiting + } + } + } + break; + + case STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4: + DecodeReader->posCount++; + if (bit) { + if (DecodeReader->posCount == 33) { + DecodeReader->posCount = 1; + DecodeReader->bitCount = 0; + DecodeReader->byteCount = 0; + DecodeReader->sum1 = 1; + DecodeReader->state = STATE_READER_RECEIVE_DATA_1_OUT_OF_4; + LED_B_ON(); + } else { + // do nothing, keep waiting + } + } else { // unexpected falling edge + DecodeReader->state = STATE_READER_UNSYNCD; + } + break; + + case STATE_READER_RECEIVE_DATA_1_OUT_OF_4: + DecodeReader->posCount++; + if (DecodeReader->posCount == 1) { + DecodeReader->sum1 = bit; + } else if (DecodeReader->posCount <= 4) { + DecodeReader->sum1 += bit; + } else if (DecodeReader->posCount == 5) { + DecodeReader->sum2 = bit; + } else { + DecodeReader->sum2 += bit; + } + if (DecodeReader->posCount == 8) { + DecodeReader->posCount = 0; + int corr10 = DecodeReader->sum1 - DecodeReader->sum2; + int corr01 = DecodeReader->sum2 - DecodeReader->sum1; + int corr11 = (DecodeReader->sum1 + DecodeReader->sum2) / 2; + if (corr01 > corr11 && corr01 > corr10) { // EOF + LED_B_OFF(); // Finished receiving + DecodeReader->state = STATE_READER_UNSYNCD; + if (DecodeReader->byteCount != 0) { + return true; + } + } + if (corr10 > corr11) { // detected a 2bit position + DecodeReader->shiftReg >>= 2; + DecodeReader->shiftReg |= (DecodeReader->bitCount << 6); + } + if (DecodeReader->bitCount == 15) { // we have a full byte + DecodeReader->output[DecodeReader->byteCount++] = DecodeReader->shiftReg; + if (DecodeReader->byteCount > DecodeReader->byteCountMax) { + // buffer overflow, give up + LED_B_OFF(); + DecodeReader->state = STATE_READER_UNSYNCD; + } + DecodeReader->bitCount = 0; + } else { + DecodeReader->bitCount++; + } + } + break; + + case STATE_READER_RECEIVE_DATA_1_OUT_OF_256: + DecodeReader->posCount++; + if (DecodeReader->posCount == 1) { + DecodeReader->sum1 = bit; + } else if (DecodeReader->posCount <= 4) { + DecodeReader->sum1 += bit; + } else if (DecodeReader->posCount == 5) { + DecodeReader->sum2 = bit; + } else { + DecodeReader->sum2 += bit; + } + if (DecodeReader->posCount == 8) { + DecodeReader->posCount = 0; + int corr10 = DecodeReader->sum1 - DecodeReader->sum2; + int corr01 = DecodeReader->sum2 - DecodeReader->sum1; + int corr11 = (DecodeReader->sum1 + DecodeReader->sum2) / 2; + if (corr01 > corr11 && corr01 > corr10) { // EOF + LED_B_OFF(); // Finished receiving + DecodeReader->state = STATE_READER_UNSYNCD; + if (DecodeReader->byteCount != 0) { + return true; + } + } + if (corr10 > corr11) { // detected the bit position + DecodeReader->shiftReg = DecodeReader->bitCount; + } + if (DecodeReader->bitCount == 255) { // we have a full byte + DecodeReader->output[DecodeReader->byteCount++] = DecodeReader->shiftReg; + if (DecodeReader->byteCount > DecodeReader->byteCountMax) { + // buffer overflow, give up + LED_B_OFF(); + DecodeReader->state = STATE_READER_UNSYNCD; + } + } + DecodeReader->bitCount++; + } + break; + + default: + LED_B_OFF(); + DecodeReader->state = STATE_READER_UNSYNCD; + break; + } + + return false; +} + + +static void DecodeReaderInit(uint8_t *data, uint16_t max_len, DecodeReader_t* DecodeReader) +{ + DecodeReader->output = data; + DecodeReader->byteCountMax = max_len; + DecodeReader->state = STATE_READER_UNSYNCD; + DecodeReader->byteCount = 0; + DecodeReader->bitCount = 0; + DecodeReader->shiftReg = 0; +} + + +//----------------------------------------------------------------------------- +// Receive a command (from the reader to us, where we are the simulated tag), +// and store it in the given buffer, up to the given maximum length. Keeps +// spinning, waiting for a well-framed command, until either we get one +// (returns true) or someone presses the pushbutton on the board (false). +// +// Assume that we're called with the SSC (to the FPGA) and ADC path set +// correctly. +//----------------------------------------------------------------------------- + +static int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eof_time) +{ + int maxBehindBy = 0; + int lastRxCounter, samples = 0; + bool gotFrame = false; + uint8_t b; + + uint8_t dmaBuf[ISO15693_DMA_BUFFER_SIZE]; + + // the decoder data structure + DecodeReader_t DecodeReader; + DecodeReaderInit(received, max_len, &DecodeReader); + + // wait for last transfer to complete + while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)); + + LED_D_OFF(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION); + + // clear receive register and wait for next transfer + uint32_t temp = AT91C_BASE_SSC->SSC_RHR; + (void) temp; + while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)) ; + + uint32_t bit_time = GetCountSspClk() & 0xfffffff8; + + // Setup and start DMA. + FpgaSetupSscDma(dmaBuf, ISO15693_DMA_BUFFER_SIZE); + uint8_t *upTo = dmaBuf; + lastRxCounter = ISO15693_DMA_BUFFER_SIZE; + + for(;;) { + int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & (ISO15693_DMA_BUFFER_SIZE-1); + if(behindBy > maxBehindBy) { + maxBehindBy = behindBy; + } + + if (behindBy < 1) continue; + + b = *upTo++; + lastRxCounter--; + if(upTo >= dmaBuf + ISO15693_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. + upTo = dmaBuf; // start reading the circular buffer from the beginning + lastRxCounter += ISO15693_DMA_BUFFER_SIZE; + } + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and + AT91C_BASE_PDC_SSC->PDC_RNCR = ISO15693_DMA_BUFFER_SIZE; // DMA Next Counter registers + } + + for (int i = 7; i >= 0; i--) { + if (Handle15693SampleFromReader((b >> i) & 0x01, &DecodeReader)) { + *eof_time = bit_time + samples - DELAY_READER_TO_ARM; // end of EOF + gotFrame = true; break; } + samples++; } - if(mask != 0x01) { - DbpString("sniff: error, uneven octet! (discard extra bits!)"); - /// DbpString(" mask=%02x", mask); - } - // uint8_t str1 [8]; - // itoa(k,str1); - // strncat(str1," octets read",8); - - // DbpString( str1); // DbpString("%d octets", k); - - // for(i = 0; i < k; i+=3) { - // //DbpString("# %2d: %02x ", i, outBuf[i]); - // DbpIntegers(outBuf[i],outBuf[i+1],outBuf[i+2]); - // } - - for(i = 0; i < k; i++) { - receivedResponse[i] = outBuf[i]; - } - } // "end if correlation > 0" (max/(arraylen(FrameSOF)/skip)) - return k; // return the number of bytes demodulated -/// DbpString("CRC=%04x", Iso15693Crc(outBuf, k-2)); + if (gotFrame) { + break; + } + + if (BUTTON_PRESS()) { + DecodeReader.byteCount = 0; + break; + } + + WDT_HIT(); + } + + + FpgaDisableSscDma(); + + if (DEBUG) Dbprintf("max behindby = %d, samples = %d, gotFrame = %d, Decoder: state = %d, len = %d, bitCount = %d, posCount = %d", + maxBehindBy, samples, gotFrame, DecodeReader.state, DecodeReader.byteCount, DecodeReader.bitCount, DecodeReader.posCount); + + if (tracing && DecodeReader.byteCount > 0) { + LogTrace(DecodeReader.output, DecodeReader.byteCount, 0, 0, NULL, true); + } + + return DecodeReader.byteCount; } @@ -681,7 +946,7 @@ void AcquireRawAdcSamplesIso15693(void) { LEDsoff(); LED_A_ON(); - + uint8_t *dest = BigBuf_get_addr(); FpgaDownloadAndGo(FPGA_BITSTREAM_HF); @@ -718,7 +983,7 @@ void AcquireRawAdcSamplesIso15693(void) if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { uint16_t iq = AT91C_BASE_SSC->SSC_RHR; // The samples are correlations against I and Q versions of the - // tone that the tag AM-modulates. We just want power, + // tone that the tag AM-modulates. We just want power, // so abs(I) + abs(Q) is close to what we want. int8_t i = (int8_t)(iq >> 8); int8_t q = (int8_t)(iq & 0xff); @@ -732,7 +997,7 @@ void AcquireRawAdcSamplesIso15693(void) } -// TODO: there is no trigger condition. The 14000 samples represent a time frame of 66ms. +// TODO: there is no trigger condition. The 14000 samples represent a time frame of 66ms. // It is unlikely that we get something meaningful. // TODO: Currently we only record tag answers. Add tracing of reader commands. // TODO: would we get something at all? The carrier is switched on... @@ -740,7 +1005,7 @@ void RecordRawAdcSamplesIso15693(void) { LEDsoff(); LED_A_ON(); - + uint8_t *dest = BigBuf_get_addr(); FpgaDownloadAndGo(FPGA_BITSTREAM_HF); @@ -762,7 +1027,7 @@ void RecordRawAdcSamplesIso15693(void) if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { uint16_t iq = AT91C_BASE_SSC->SSC_RHR; // The samples are correlations against I and Q versions of the - // tone that the tag AM-modulates. We just want power, + // tone that the tag AM-modulates. We just want power, // so abs(I) + abs(Q) is close to what we want. int8_t i = (int8_t)(iq >> 8); int8_t q = (int8_t)(iq & 0xff); @@ -778,7 +1043,7 @@ void RecordRawAdcSamplesIso15693(void) } -// Initialize the proxmark as iso15k reader +// Initialize the proxmark as iso15k reader // (this might produces glitches that confuse some tags static void Iso15693InitReader() { FpgaDownloadAndGo(FPGA_BITSTREAM_HF); @@ -851,7 +1116,7 @@ static void BuildReadBlockRequest(uint8_t *uid, uint8_t blockNumber ) // Block number to read cmd[10] = blockNumber;//0x00; //Now the CRC - crc = Crc(cmd, 11); // the crc needs to be calculated over 12 bytes + crc = Crc(cmd, 11); // the crc needs to be calculated over 11 bytes cmd[11] = crc & 0xff; cmd[12] = crc >> 8; @@ -860,15 +1125,13 @@ static void BuildReadBlockRequest(uint8_t *uid, uint8_t blockNumber ) // Now the VICC>VCD responses when we are simulating a tag -static void BuildInventoryResponse( uint8_t *uid) +static void BuildInventoryResponse(uint8_t *uid) { uint8_t cmd[12]; uint16_t crc; - // one sub-carrier, inventory, 1 slot, fast rate - // AFI is at bit 5 (1<<4) when doing an INVENTORY - //(1 << 2) | (1 << 5) | (1 << 1); - cmd[0] = 0; // + + cmd[0] = 0; // No error, no protocol format extension cmd[1] = 0; // DSFID (data storage format identifier). 0x00 = not supported // 64-bit UID cmd[2] = uid[7]; //0x32; @@ -884,21 +1147,21 @@ static void BuildInventoryResponse( uint8_t *uid) cmd[10] = crc & 0xff; cmd[11] = crc >> 8; - CodeIso15693AsReader(cmd, sizeof(cmd)); + CodeIso15693AsTag(cmd, sizeof(cmd)); } // Universal Method for sending to and recv bytes from a tag // init ... should we initialize the reader? -// speed ... 0 low speed, 1 hi speed +// speed ... 0 low speed, 1 hi speed // **recv will return you a pointer to the received data -// If you do not need the answer use NULL for *recv[] +// If you do not need the answer use NULL for *recv[] // return: lenght of received data int SendDataTag(uint8_t *send, int sendlen, bool init, int speed, uint8_t **recv) { LED_A_ON(); LED_B_OFF(); LED_C_OFF(); - + if (init) Iso15693InitReader(); int answerLen=0; @@ -912,22 +1175,22 @@ int SendDataTag(uint8_t *send, int sendlen, bool init, int speed, uint8_t **recv // high speed (1 out of 4) CodeIso15693AsReader(send, sendlen); } - - TransmitTo15693Tag(ToSend,ToSendMax); + + TransmitTo15693Tag(ToSend,ToSendMax); // Now wait for a response if (recv!=NULL) { - answerLen = GetIso15693AnswerFromTag(answer, 100); + answerLen = GetIso15693AnswerFromTag(answer, 100); *recv=answer; } LED_A_OFF(); - + return answerLen; } // -------------------------------------------------------------------- -// Debug Functions +// Debug Functions // -------------------------------------------------------------------- // Decodes a message from a tag and displays its metadata and content @@ -937,37 +1200,37 @@ void DbdecodeIso15693Answer(int len, uint8_t *d) { uint16_t crc; if (len>3) { - if (d[0]&(1<<3)) + if (d[0]&(1<<3)) strncat(status,"ProtExt ",DBD15STATLEN); - if (d[0]&1) { + if (d[0]&1) { // error strncat(status,"Error ",DBD15STATLEN); switch (d[1]) { - case 0x01: + case 0x01: strncat(status,"01:notSupp",DBD15STATLEN); break; - case 0x02: + case 0x02: strncat(status,"02:notRecog",DBD15STATLEN); break; - case 0x03: + case 0x03: strncat(status,"03:optNotSupp",DBD15STATLEN); break; - case 0x0f: + case 0x0f: strncat(status,"0f:noInfo",DBD15STATLEN); break; - case 0x10: + case 0x10: strncat(status,"10:dontExist",DBD15STATLEN); break; - case 0x11: + case 0x11: strncat(status,"11:lockAgain",DBD15STATLEN); break; - case 0x12: + case 0x12: strncat(status,"12:locked",DBD15STATLEN); break; - case 0x13: + case 0x13: strncat(status,"13:progErr",DBD15STATLEN); break; - case 0x14: + case 0x14: strncat(status,"14:lockErr",DBD15STATLEN); break; default: @@ -977,12 +1240,12 @@ void DbdecodeIso15693Answer(int len, uint8_t *d) { } else { strncat(status,"NoErr ",DBD15STATLEN); } - + crc=Crc(d,len-2); - if ( (( crc & 0xff ) == d[len-2]) && (( crc >> 8 ) == d[len-1]) ) + if ( (( crc & 0xff ) == d[len-2]) && (( crc >> 8 ) == d[len-1]) ) strncat(status,"CrcOK",DBD15STATLEN); else - strncat(status,"CrcFail!",DBD15STATLEN); + strncat(status,"CrcFail!",DBD15STATLEN); Dbprintf("%s",status); } @@ -1035,9 +1298,9 @@ void ReaderIso15693(uint32_t parameter) // Now send the IDENTIFY command BuildIdentifyRequest(); - + TransmitTo15693Tag(ToSend,ToSendMax); - + // Now wait for a response answerLen1 = GetIso15693AnswerFromTag(answer1, 100) ; @@ -1055,11 +1318,11 @@ void ReaderIso15693(uint32_t parameter) } Dbprintf("%d octets read from IDENTIFY request:", answerLen1); - DbdecodeIso15693Answer(answerLen1,answer1); - Dbhexdump(answerLen1,answer1,true); + DbdecodeIso15693Answer(answerLen1, answer1); + Dbhexdump(answerLen1, answer1, false); // UID is reverse - if (answerLen1 >= 12) + if (answerLen1 >= 12) Dbprintf("UID = %02hX%02hX%02hX%02hX%02hX%02hX%02hX%02hX", TagUID[7],TagUID[6],TagUID[5],TagUID[4], TagUID[3],TagUID[2],TagUID[1],TagUID[0]); @@ -1076,123 +1339,113 @@ void ReaderIso15693(uint32_t parameter) // read all pages if (answerLen1 >= 12 && DEBUG) { uint8_t *answer2 = BigBuf_get_addr() + 4100; - int i=0; - while (i<32) { // sanity check, assume max 32 pages - BuildReadBlockRequest(TagUID,i); - TransmitTo15693Tag(ToSend,ToSendMax); + int i = 0; + while (i < 32) { // sanity check, assume max 32 pages + BuildReadBlockRequest(TagUID, i); + TransmitTo15693Tag(ToSend, ToSendMax); int answerLen2 = GetIso15693AnswerFromTag(answer2, 100); - if (answerLen2>0) { - Dbprintf("READ SINGLE BLOCK %d returned %d octets:",i,answerLen2); - DbdecodeIso15693Answer(answerLen2,answer2); - Dbhexdump(answerLen2,answer2,true); - if ( *((uint32_t*) answer2) == 0x07160101 ) break; // exit on NoPageErr - } + if (answerLen2 > 0) { + Dbprintf("READ SINGLE BLOCK %d returned %d octets:", i, answerLen2); + DbdecodeIso15693Answer(answerLen2, answer2); + Dbhexdump(answerLen2, answer2, false); + if ( *((uint32_t*) answer2) == 0x07160101 ) break; // exit on NoPageErr + } i++; - } + } } - // for the time being, switch field off to protect rdv4.0 + // for the time being, switch field off to protect rdv4.0 // note: this prevents using hf 15 cmd with s option - which isn't implemented yet anyway FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_D_OFF(); - + LED_A_OFF(); } -// Simulate an ISO15693 TAG, perform anti-collision and then print any reader commands -// all demodulation performed in arm rather than host. - greg + +// Simulate an ISO15693 TAG. +// For Inventory command: print command and send Inventory Response with given UID +// TODO: interpret other reader commands and send appropriate response void SimTagIso15693(uint32_t parameter, uint8_t *uid) { LEDsoff(); LED_A_ON(); - int answerLen1 = 0; - int samples = 0; - int elapsed = 0; - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - - uint8_t *buf = BigBuf_get_addr() + 4000; - memset(buf, 0x00, 100); - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION); + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR); - // Start from off (no field generated) - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(200); + StartCountSspClk(); + + uint8_t cmd[ISO15693_MAX_COMMAND_LENGTH]; + + // Build a suitable response to the reader INVENTORY command + BuildInventoryResponse(uid); // Listen to reader - answerLen1 = GetIso15693AnswerFromSniff(buf, 100, &samples, &elapsed) ; + while (!BUTTON_PRESS()) { + uint32_t eof_time = 0, start_time = 0; + int cmd_len = GetIso15693CommandFromReader(cmd, sizeof(cmd), &eof_time); - if (answerLen1 >=1) // we should do a better check than this - { - // Build a suitable reponse to the reader INVENTORY cocmmand - // not so obsvious, but in the call to BuildInventoryResponse, the command is copied to the global ToSend buffer used below. - - BuildInventoryResponse(uid); - - TransmitTo15693Reader(ToSend,ToSendMax); + if ((cmd_len >= 5) && (cmd[0] & ISO15693_REQ_INVENTORY) && (cmd[1] == ISO15693_INVENTORY)) { // TODO: check more flags + bool slow = !(cmd[0] & ISO15693_REQ_DATARATE_HIGH); + start_time = eof_time + DELAY_ISO15693_VCD_TO_VICC - DELAY_ARM_TO_READER; + TransmitTo15693Reader(ToSend, ToSendMax, start_time, slow); + } + + Dbprintf("%d bytes read from reader:", cmd_len); + Dbhexdump(cmd_len, cmd, false); } - Dbprintf("%d octets read from reader command: %x %x %x %x %x %x %x %x %x", answerLen1, - buf[0], buf[1], buf[2], buf[3], - buf[4], buf[5], buf[6], buf[7], buf[8]); - - Dbprintf("Simulationg uid: %x %x %x %x %x %x %x %x", - uid[0], uid[1], uid[2], uid[3], - uid[4], uid[5], uid[6], uid[7]); - LEDsoff(); } // Since there is no standardized way of reading the AFI out of a tag, we will brute force it // (some manufactures offer a way to read the AFI, though) -void BruteforceIso15693Afi(uint32_t speed) -{ +void BruteforceIso15693Afi(uint32_t speed) +{ LEDsoff(); LED_A_ON(); - + uint8_t data[20]; uint8_t *recv=data; int datalen=0, recvlen=0; - + Iso15693InitReader(); - + // first without AFI - // Tags should respond wihtout AFI and with AFI=0 even when AFI is active - - data[0]=ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | - ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1; - data[1]=ISO15_CMD_INVENTORY; - data[2]=0; // mask length - datalen=AddCrc(data,3); - recvlen=SendDataTag(data, datalen, false, speed, &recv); + // Tags should respond without AFI and with AFI=0 even when AFI is active + + data[0] = ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_INVENTORY | ISO15693_REQINV_SLOT1; + data[1] = ISO15693_INVENTORY; + data[2] = 0; // mask length + datalen = AddCrc(data,3); + recvlen = SendDataTag(data, datalen, false, speed, &recv); WDT_HIT(); if (recvlen>=12) { Dbprintf("NoAFI UID=%s",sprintUID(NULL,&recv[2])); } - + // now with AFI - - data[0]=ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | - ISO15_REQ_INVENTORY | ISO15_REQINV_AFI | ISO15_REQINV_SLOT1; - data[1]=ISO15_CMD_INVENTORY; - data[2]=0; // AFI - data[3]=0; // mask length - + + data[0] = ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_INVENTORY | ISO15693_REQINV_AFI | ISO15693_REQINV_SLOT1; + data[1] = ISO15693_INVENTORY; + data[2] = 0; // AFI + data[3] = 0; // mask length + for (int i=0;i<256;i++) { data[2]=i & 0xFF; datalen=AddCrc(data,4); recvlen=SendDataTag(data, datalen, false, speed, &recv); WDT_HIT(); if (recvlen>=12) { - Dbprintf("AFI=%i UID=%s",i,sprintUID(NULL,&recv[2])); + Dbprintf("AFI=%i UID=%s", i, sprintUID(NULL,&recv[2])); } - } + } Dbprintf("AFI Bruteforcing done."); - + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); } @@ -1202,31 +1455,31 @@ void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint int recvlen=0; uint8_t *recvbuf = BigBuf_get_addr(); - + LED_A_ON(); - + if (DEBUG) { Dbprintf("SEND"); - Dbhexdump(datalen,data,true); + Dbhexdump(datalen, data, false); } - + recvlen = SendDataTag(data, datalen, true, speed, (recv?&recvbuf:NULL)); - if (recv) { + if (recv) { cmd_send(CMD_ACK, recvlen>48?48:recvlen, 0, 0, recvbuf, 48); - + if (DEBUG) { Dbprintf("RECV"); - DbdecodeIso15693Answer(recvlen,recvbuf); - Dbhexdump(recvlen,recvbuf,true); + DbdecodeIso15693Answer(recvlen,recvbuf); + Dbhexdump(recvlen, recvbuf, false); } } - // for the time being, switch field off to protect rdv4.0 + // for the time being, switch field off to protect rdv4.0 // note: this prevents using hf 15 cmd with s option - which isn't implemented yet anyway FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_D_OFF(); - + LED_A_OFF(); } diff --git a/armsrc/util.c b/armsrc/util.c index a1b0f151..fbb6d489 100644 --- a/armsrc/util.c +++ b/armsrc/util.c @@ -373,13 +373,13 @@ void StartCountSspClk() AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK // TC1 Clock = MCK(48MHz)/2 = 24MHz | AT91C_TC_CPCSTOP // Stop clock on RC compare | AT91C_TC_EEVTEDG_RISING // Trigger on rising edge of Event - | AT91C_TC_EEVT_TIOB // Event-Source: TIOB1 (= ssp_clk from FPGA = 13,56MHz/16) + | AT91C_TC_EEVT_TIOB // Event-Source: TIOB1 (= ssp_clk from FPGA = 13,56MHz/16 ... 13,56MHz/4) | AT91C_TC_ENETRG // Enable external trigger event | AT91C_TC_WAVESEL_UP // Upmode without automatic trigger on RC compare | AT91C_TC_WAVE // Waveform Mode | AT91C_TC_AEEVT_SET // Set TIOA1 on external event | AT91C_TC_ACPC_CLEAR; // Clear TIOA1 on RC Compare - AT91C_BASE_TC1->TC_RC = 0x04; // RC Compare value = 0x04 + AT91C_BASE_TC1->TC_RC = 0x02; // RC Compare value = 0x02 // use TC0 to count TIOA1 pulses AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // disable TC0 @@ -402,7 +402,7 @@ void StartCountSspClk() AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN; // enable TC2 // - // synchronize the counter with the ssp_frame signal. Note: FPGA must be in any iso14443 mode, otherwise SSC_FRAME and SSC_CLK signals would not be present + // synchronize the counter with the ssp_frame signal. Note: FPGA must be in a FPGA mode with SSC transfer, otherwise SSC_FRAME and SSC_CLK signals would not be present // while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME)); // wait for ssp_frame to go high (start of frame) while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME); // wait for ssp_frame to be low @@ -430,15 +430,15 @@ void ResetSspClk(void) { } -uint32_t RAMFUNC GetCountSspClk(){ - uint32_t tmp_count; - tmp_count = (AT91C_BASE_TC2->TC_CV << 16) | AT91C_BASE_TC0->TC_CV; - if ((tmp_count & 0x0000ffff) == 0) { //small chance that we may have missed an increment in TC2 - return (AT91C_BASE_TC2->TC_CV << 16); - } - else { - return tmp_count; - } +uint32_t GetCountSspClk(){ + uint32_t hi, lo; + + do { + hi = AT91C_BASE_TC2->TC_CV; + lo = AT91C_BASE_TC0->TC_CV; + } while(hi != AT91C_BASE_TC2->TC_CV); + + return (hi << 16) | lo; } diff --git a/client/cmdhf15.c b/client/cmdhf15.c index c116b001..e5f4af31 100644 --- a/client/cmdhf15.c +++ b/client/cmdhf15.c @@ -35,6 +35,7 @@ #include "util.h" #include "cmdparser.h" #include "iso15693tools.h" +#include "protocols.h" #include "cmdmain.h" #define FrameSOF Iso15693FrameSOF @@ -212,18 +213,17 @@ int getUID(uint8_t *buf) for (int retry=0;retry<3; retry++) { // don't give up the at the first try - req[0]= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | - ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1; - req[1]=ISO15_CMD_INVENTORY; - req[2]=0; // mask length - reqlen=AddCrc(req,3); - c.arg[0]=reqlen; + req[0] = ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_INVENTORY | ISO15693_REQINV_SLOT1; + req[1] = ISO15693_INVENTORY; + req[2] = 0; // mask length + reqlen = AddCrc(req,3); + c.arg[0] = reqlen; SendCommand(&c); if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) { recv = resp.d.asBytes; - if (resp.arg[0]>=12 && ISO15_CRC_CHECK==Crc(recv,12)) { + if (resp.arg[0]>=12 && ISO15693_CRC_CHECK==Crc(recv,12)) { memcpy(buf,&recv[2],8); return 1; } @@ -424,6 +424,7 @@ int CmdHF15Sim(const char *Cmd) PrintAndLog("Starting simulating UID %02X %02X %02X %02X %02X %02X %02X %02X", uid[0],uid[1],uid[2],uid[3],uid[4], uid[5], uid[6], uid[7]); + PrintAndLog("Press the button to stop simulation"); UsbCommand c = {CMD_SIMTAG_ISO_15693, {0, 0, 0}}; memcpy(c.d.asBytes,uid,8); @@ -462,20 +463,19 @@ int CmdHF15DumpMem(const char*Cmd) { for (int retry=0; retry<5; retry++) { - req[0]= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | - ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS; - req[1]=ISO15_CMD_READ; + req[0]= ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_ADDRESS; + req[1] = ISO15693_READBLOCK; memcpy(&req[2],uid,8); - req[10]=blocknum; - reqlen=AddCrc(req,11); - c.arg[0]=reqlen; + req[10] = blocknum; + reqlen = AddCrc(req,11); + c.arg[0] = reqlen; SendCommand(&c); if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) { recv = resp.d.asBytes; - if (ISO15_CRC_CHECK==Crc(recv,resp.arg[0])) { - if (!(recv[0] & ISO15_RES_ERROR)) { + if (ISO15693_CRC_CHECK==Crc(recv,resp.arg[0])) { + if (!(recv[0] & ISO15693_RES_ERROR)) { retry=0; *output=0; // reset outputstring sprintf(output, "Block %02x ",blocknum); @@ -499,7 +499,7 @@ int CmdHF15DumpMem(const char*Cmd) { // TODO: need fix // if (resp.arg[0]<3) // PrintAndLog("Lost Connection"); -// else if (ISO15_CRC_CHECK!=Crc(resp.d.asBytes,resp.arg[0])) +// else if (ISO15693_CRC_CHECK!=Crc(resp.d.asBytes,resp.arg[0])) // PrintAndLog("CRC Failed"); // else // PrintAndLog("Tag returned Error %i: %s",recv[1],TagErrorStr(recv[1])); @@ -547,12 +547,11 @@ int CmdHF15CmdInquiry(const char *Cmd) uint8_t *req=c.d.asBytes; int reqlen=0; - req[0]= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | - ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1; - req[1]=ISO15_CMD_INVENTORY; - req[2]=0; // mask length + req[0] = ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_INVENTORY | ISO15693_REQINV_SLOT1; + req[1] = ISO15693_INVENTORY; + req[2] = 0; // mask length reqlen=AddCrc(req,3); - c.arg[0]=reqlen; + c.arg[0] = reqlen; SendCommand(&c); @@ -706,7 +705,7 @@ int prepareHF15Cmd(char **cmd, UsbCommand *c, uint8_t iso15cmd[], int iso15cmdle while (**cmd==' ' || **cmd=='\t') (*cmd)++; if (strstr(*cmd,"-o")==*cmd) { - req[reqlen]=ISO15_REQ_OPTION; + req[reqlen]=ISO15693_REQ_OPTION; (*cmd)+=2; } @@ -721,36 +720,32 @@ int prepareHF15Cmd(char **cmd, UsbCommand *c, uint8_t iso15cmd[], int iso15cmdle case 's': case 'S': // you must have selected the tag earlier - req[reqlen++]|= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | - ISO15_REQ_NONINVENTORY | ISO15_REQ_SELECT; - memcpy(&req[reqlen],&iso15cmd[0],iso15cmdlen); - reqlen+=iso15cmdlen; + req[reqlen++] |= ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_SELECT; + memcpy(&req[reqlen],&iso15cmd[0],iso15cmdlen); + reqlen += iso15cmdlen; break; case 'u': case 'U': // unaddressed mode may not be supported by all vendors - req[reqlen++]|= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | - ISO15_REQ_NONINVENTORY; - memcpy(&req[reqlen],&iso15cmd[0],iso15cmdlen); - reqlen+=iso15cmdlen; + req[reqlen++] |= ISO15693_REQ_DATARATE_HIGH; + memcpy(&req[reqlen],&iso15cmd[0],iso15cmdlen); + reqlen += iso15cmdlen; break; case '*': // we scan for the UID ourself - req[reqlen++]|= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | - ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS; - memcpy(&req[reqlen],&iso15cmd[0],iso15cmdlen); + req[reqlen++] |= ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_ADDRESS; + memcpy(&req[reqlen],&iso15cmd[0],iso15cmdlen); reqlen+=iso15cmdlen; - if (!getUID(uid)) { - PrintAndLog("No Tag found"); - return 0; - } - memcpy(req+reqlen,uid,8); - PrintAndLog("Detected UID %s",sprintUID(NULL,uid)); - reqlen+=8; + if (!getUID(uid)) { + PrintAndLog("No Tag found"); + return 0; + } + memcpy(req+reqlen,uid,8); + PrintAndLog("Detected UID %s",sprintUID(NULL,uid)); + reqlen+=8; break; default: - req[reqlen++]|= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | - ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS; + req[reqlen++] |= ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_ADDRESS; memcpy(&req[reqlen],&iso15cmd[0],iso15cmdlen); reqlen+=iso15cmdlen; @@ -809,7 +804,7 @@ int CmdHF15CmdSysinfo(const char *Cmd) { return 0; } - prepareHF15Cmd(&cmd, &c,(uint8_t[]){ISO15_CMD_SYSINFO},1); + prepareHF15Cmd(&cmd, &c,(uint8_t[]){ISO15693_GET_SYSTEM_INFO},1); reqlen=c.arg[0]; reqlen=AddCrc(req,reqlen); @@ -819,8 +814,8 @@ int CmdHF15CmdSysinfo(const char *Cmd) { if (WaitForResponseTimeout(CMD_ACK,&resp,1000) && resp.arg[0]>2) { recv = resp.d.asBytes; - if (ISO15_CRC_CHECK==Crc(recv,resp.arg[0])) { - if (!(recv[0] & ISO15_RES_ERROR)) { + if (ISO15693_CRC_CHECK==Crc(recv,resp.arg[0])) { + if (!(recv[0] & ISO15693_RES_ERROR)) { *output=0; // reset outputstring for ( i=1; i2) { recv = resp.d.asBytes; - if (ISO15_CRC_CHECK==Crc(recv,resp.arg[0])) { - if (!(recv[0] & ISO15_RES_ERROR)) { + if (ISO15693_CRC_CHECK==Crc(recv,resp.arg[0])) { + if (!(recv[0] & ISO15693_RES_ERROR)) { *output=0; // reset outputstring for ( int i=1; i2) { recv = resp.d.asBytes; - if (ISO15_CRC_CHECK==Crc(recv,resp.arg[0])) { - if (!(recv[0] & ISO15_RES_ERROR)) { + if (ISO15693_CRC_CHECK==Crc(recv,resp.arg[0])) { + if (!(recv[0] & ISO15693_RES_ERROR)) { *output=0; // reset outputstring //sprintf(output, "Block %2i ",blocknum); for ( int i=1; i page num ; *cmd2 -> data @@ -1086,8 +1081,8 @@ int CmdHF15CmdWrite(const char *Cmd) { if (WaitForResponseTimeout(CMD_ACK,&resp,2000) && resp.arg[0]>2) { recv = resp.d.asBytes; - if (ISO15_CRC_CHECK==Crc(recv,resp.arg[0])) { - if (!(recv[0] & ISO15_RES_ERROR)) { + if (ISO15693_CRC_CHECK==Crc(recv,resp.arg[0])) { + if (!(recv[0] & ISO15693_RES_ERROR)) { PrintAndLog("OK"); } else { PrintAndLog("Tag returned Error %i: %s",recv[1],TagErrorStr(recv[1])); diff --git a/common/iso15693tools.h b/common/iso15693tools.h index ec63728f..96095fba 100644 --- a/common/iso15693tools.h +++ b/common/iso15693tools.h @@ -5,67 +5,9 @@ #define ISO15693_H__ // ISO15693 CRC -#define ISO15_CRC_PRESET (uint16_t)0xFFFF -#define ISO15_CRC_POLY (uint16_t)0x8408 -#define ISO15_CRC_CHECK ((uint16_t)(~0xF0B8 & 0xFFFF)) // use this for checking of a correct crc - -// REQUEST FLAGS - -#define ISO15_REQ_SUBCARRIER_SINGLE 0x00 // Tag should respond using one subcarrier (ASK) -#define ISO15_REQ_SUBCARRIER_TWO 0x01 // Tag should respond using two subcarriers (FSK) -#define ISO15_REQ_DATARATE_LOW 0x00 // Tag should respond using low data rate -#define ISO15_REQ_DATARATE_HIGH 0x02 // Tag should respond using high data rate -#define ISO15_REQ_NONINVENTORY 0x00 -#define ISO15_REQ_INVENTORY 0x04 // This is an inventory request - see inventory flags -#define ISO15_REQ_PROTOCOL_NONEXT 0x00 -#define ISO15_REQ_PROTOCOL_EXT 0x08 // RFU - -// REQUEST FLAGS when INVENTORY is not set - -#define ISO15_REQ_SELECT 0x10 // only selected cards response -#define ISO15_REQ_ADDRESS 0x20 // this req contains an address -#define ISO15_REQ_OPTION 0x40 // Command specific option selector - -//REQUEST FLAGS when INVENTORY is set - -#define ISO15_REQINV_AFI 0x10 // AFI Field is present -#define ISO15_REQINV_SLOT1 0x20 // 1 Slot -#define ISO15_REQINV_SLOT16 0x00 // 16 Slots -#define ISO15_REQINV_OPTION 0x40 // Command specific option selector - -//RESPONSE FLAGS -#define ISO15_RES_ERROR 0x01 -#define ISO15_RES_EXT 0x08 // Protocol Extention - -// RESPONSE ERROR CODES -#define ISO15_NOERROR 0x00 -#define ISO15_ERROR_CMD_NOT_SUP 0x01 // Command not supported -#define ISO15_ERROR_CMD_NOT_REC 0x02 // Command not recognized (eg. parameter error) -#define ISO15_ERROR_CMD_OPTION 0x03 // Command option not supported -#define ISO15_ERROR_GENERIC 0x0F // No additional Info about this error -#define ISO15_ERROR_BLOCK_UNAVAILABLE 0x10 -#define ISO15_ERROR_BLOCK_LOCKED_ALREADY 0x11 // cannot lock again -#define ISO15_ERROR_BLOCK_LOCKED 0x12 // cannot be changed -#define ISO15_ERROR_BLOCK_WRITE 0x13 // Writing was unsuccessful -#define ISO15_ERROR_BLOCL_WRITELOCK 0x14 // Locking was unsuccessful - -// COMMAND CODES -#define ISO15_CMD_INVENTORY 0x01 -#define ISO15_CMD_STAYQUIET 0x02 -#define ISO15_CMD_READ 0x20 -#define ISO15_CMD_WRITE 0x21 -#define ISO15_CMD_LOCK 0x22 -#define ISO15_CMD_READMULTI 0x23 -#define ISO15_CMD_WRITEMULTI 0x24 -#define ISO15_CMD_SELECT 0x25 -#define ISO15_CMD_RESET 0x26 -#define ISO15_CMD_WRITEAFI 0x27 -#define ISO15_CMD_LOCKAFI 0x28 -#define ISO15_CMD_WRITEDSFID 0x29 -#define ISO15_CMD_LOCKDSFID 0x2A -#define ISO15_CMD_SYSINFO 0x2B -#define ISO15_CMD_SECSTATUS 0x2C - +#define ISO15693_CRC_PRESET (uint16_t)0xFFFF +#define ISO15693_CRC_POLY (uint16_t)0x8408 +#define ISO15693_CRC_CHECK ((uint16_t)(~0xF0B8 & 0xFFFF)) // use this for checking of a correct crc uint16_t Iso15693Crc(uint8_t *v, int n); int Iso15693AddCrc(uint8_t *req, int n); diff --git a/common/protocols.h b/common/protocols.h index 9ba69d5c..06a80de1 100644 --- a/common/protocols.h +++ b/common/protocols.h @@ -167,22 +167,50 @@ NXP/Philips CUSTOM COMMANDS #define ISO14443B_COMPLETION 0x0F #define ISO14443B_AUTHENTICATE 0x0A -//First byte is 26 -#define ISO15693_INVENTORY 0x01 -#define ISO15693_STAYQUIET 0x02 -//First byte is 02 -#define ISO15693_READBLOCK 0x20 -#define ISO15693_WRITEBLOCK 0x21 -#define ISO15693_LOCKBLOCK 0x22 -#define ISO15693_READ_MULTI_BLOCK 0x23 -#define ISO15693_SELECT 0x25 -#define ISO15693_RESET_TO_READY 0x26 -#define ISO15693_WRITE_AFI 0x27 -#define ISO15693_LOCK_AFI 0x28 -#define ISO15693_WRITE_DSFID 0x29 -#define ISO15693_LOCK_DSFID 0x2A -#define ISO15693_GET_SYSTEM_INFO 0x2B -#define ISO15693_READ_MULTI_SECSTATUS 0x2C +// ISO15693 COMMANDS +#define ISO15693_INVENTORY 0x01 +#define ISO15693_STAYQUIET 0x02 +#define ISO15693_READBLOCK 0x20 +#define ISO15693_WRITEBLOCK 0x21 +#define ISO15693_LOCKBLOCK 0x22 +#define ISO15693_READ_MULTI_BLOCK 0x23 +#define ISO15693_SELECT 0x25 +#define ISO15693_RESET_TO_READY 0x26 +#define ISO15693_WRITE_AFI 0x27 +#define ISO15693_LOCK_AFI 0x28 +#define ISO15693_WRITE_DSFID 0x29 +#define ISO15693_LOCK_DSFID 0x2A +#define ISO15693_GET_SYSTEM_INFO 0x2B +#define ISO15693_READ_MULTI_SECSTATUS 0x2C + +// ISO15693 REQUEST FLAGS +#define ISO15693_REQ_SUBCARRIER_TWO (1<<0) +#define ISO15693_REQ_DATARATE_HIGH (1<<1) +#define ISO15693_REQ_INVENTORY (1<<2) +#define ISO15693_REQ_PROTOCOL_EXT (1<<3) // RFU +#define ISO15693_REQ_OPTION (1<<6) // Command specific option selector +// when REQ_INVENTORY is not set +#define ISO15693_REQ_SELECT (1<<4) // only selected cards response +#define ISO15693_REQ_ADDRESS (1<<5) // this req contains an address +// when REQ_INVENTORY is set +#define ISO15693_REQINV_AFI (1<<4) // AFI Field is present +#define ISO15693_REQINV_SLOT1 (1<<5) // 1 Slot (16 slots if not set) + +// ISO15693 RESPONSE FLAGS +#define ISO15693_RES_ERROR (1<<0) +#define ISO15693_RES_EXT (1<<3) // Protocol Extention + +// ISO15693 RESPONSE ERROR CODES +#define ISO15693_NOERROR 0x00 +#define ISO15693_ERROR_CMD_NOT_SUP 0x01 // Command not supported +#define ISO15693_ERROR_CMD_NOT_REC 0x02 // Command not recognized (eg. parameter error) +#define ISO15693_ERROR_CMD_OPTION 0x03 // Command option not supported +#define ISO15693_ERROR_GENERIC 0x0F // No additional Info about this error +#define ISO15693_ERROR_BLOCK_UNAVAILABLE 0x10 +#define ISO15693_ERROR_BLOCK_LOCKED_ALREADY 0x11 // cannot lock again +#define ISO15693_ERROR_BLOCK_LOCKED 0x12 // cannot be changed +#define ISO15693_ERROR_BLOCK_WRITE 0x13 // Writing was unsuccessful +#define ISO15693_ERROR_BLOCL_WRITELOCK 0x14 // Locking was unsuccessful // Topaz command set: diff --git a/fpga/hi_simulate.v b/fpga/hi_simulate.v index 78650c4a..8d70bb1b 100644 --- a/fpga/hi_simulate.v +++ b/fpga/hi_simulate.v @@ -16,6 +16,13 @@ // Jonathan Westhues, October 2006 //----------------------------------------------------------------------------- +// possible mod_types: +`define NO_MODULATION 3'b000 +`define MODULATE_BPSK 3'b001 +`define MODULATE_212K 3'b010 +`define MODULATE_424K 3'b100 +`define MODULATE_424K_8BIT 3'b101 + module hi_simulate( pck0, ck_1356meg, ck_1356megb, pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4, @@ -35,10 +42,6 @@ module hi_simulate( output dbg; input [2:0] mod_type; -// Power amp goes between LOW and tri-state, so pwr_hi (and pwr_lo) can -// always be low. -assign pwr_hi = 1'b0; -assign pwr_lo = 1'b0; // The comparator with hysteresis on the output from the peak detector. reg after_hysteresis; @@ -52,8 +55,8 @@ end // Divide 13.56 MHz to produce various frequencies for SSP_CLK -// and modulation. 11 bits allow for factors of up to /128. -reg [10:0] ssp_clk_divider; +// and modulation. +reg [7:0] ssp_clk_divider; always @(posedge adc_clk) ssp_clk_divider <= (ssp_clk_divider + 1); @@ -62,10 +65,10 @@ reg ssp_clk; always @(negedge adc_clk) begin - if(mod_type == 3'b101) + if(mod_type == `MODULATE_424K_8BIT) // Get bit every at 53KHz (every 8th carrier bit of 424kHz) ssp_clk <= ssp_clk_divider[7]; - else if(mod_type == 3'b010) + else if(mod_type == `MODULATE_212K) // Get next bit at 212kHz ssp_clk <= ssp_clk_divider[5]; else @@ -89,7 +92,7 @@ always @(negedge ssp_clk) reg ssp_frame; always @(ssp_frame_divider_to_arm or ssp_frame_divider_from_arm or mod_type) - if(mod_type == 3'b000) // not modulating, so listening, to ARM + if(mod_type == `NO_MODULATION) // not modulating, so listening, to ARM ssp_frame = (ssp_frame_divider_to_arm == 3'b000); else ssp_frame = (ssp_frame_divider_from_arm == 3'b000); @@ -102,27 +105,29 @@ always @(posedge ssp_clk) // Modulating carrier frequency is fc/64 (212kHz) to fc/16 (848kHz). Reuse ssp_clk divider for that. reg modulating_carrier; always @(mod_type or ssp_clk or ssp_dout) - if(mod_type == 3'b000) + if (mod_type == `NO_MODULATION) modulating_carrier <= 1'b0; // no modulation - else if(mod_type == 3'b001) + else if (mod_type == `MODULATE_BPSK) modulating_carrier <= ssp_dout ^ ssp_clk_divider[3]; // XOR means BPSK - else if(mod_type == 3'b010) + else if (mod_type == `MODULATE_212K) modulating_carrier <= ssp_dout & ssp_clk_divider[5]; // switch 212kHz subcarrier on/off - else if(mod_type == 3'b100 || mod_type == 3'b101) + else if (mod_type == `MODULATE_424K || mod_type == `MODULATE_424K_8BIT) modulating_carrier <= ssp_dout & ssp_clk_divider[4]; // switch 424kHz modulation on/off else modulating_carrier <= 1'b0; // yet unused -// This one is all LF, so doesn't matter -assign pwr_oe2 = modulating_carrier; -// Toggle only one of these, since we are already producing much deeper +// Load modulation. Toggle only one of these, since we are already producing much deeper // modulation than a real tag would. -assign pwr_oe1 = modulating_carrier; -assign pwr_oe4 = modulating_carrier; +assign pwr_hi = 1'b0; // HF antenna connected to GND +assign pwr_oe3 = 1'b0; // 10k Load +assign pwr_oe1 = modulating_carrier; // 33 Ohms Load +assign pwr_oe4 = modulating_carrier; // 33 Ohms Load + +// This is all LF and doesn't matter +assign pwr_lo = 1'b0; +assign pwr_oe2 = 1'b0; -// This one is always on, so that we can watch the carrier. -assign pwr_oe3 = 1'b0; assign dbg = ssp_din; From 3685f89cbd6c524c91b41bd41bd3db038b3f1b43 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Tue, 23 Oct 2018 19:50:37 +0200 Subject: [PATCH 008/189] small fix to please @dmaij's compiler (issue #703) --- armsrc/iso15693.c | 1 + 1 file changed, 1 insertion(+) diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 9479c3c0..50432392 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -837,6 +837,7 @@ static void DecodeReaderInit(uint8_t *data, uint16_t max_len, DecodeReader_t* De DecodeReader->state = STATE_READER_UNSYNCD; DecodeReader->byteCount = 0; DecodeReader->bitCount = 0; + DecodeReader->posCount = 0; DecodeReader->shiftReg = 0; } From ae3340a0fb04bf8f8b8c874e0859d7d0886e2db1 Mon Sep 17 00:00:00 2001 From: Oleg Moiseenko <807634+merlokk@users.noreply.github.com> Date: Wed, 24 Oct 2018 19:58:12 +0300 Subject: [PATCH 009/189] Mfp commands (#698) * add write perso from https://github.com/Proxmark/proxmark3/blob/master/client/scripts/mifarePlus.lua * commit perso from https://github.com/Proxmark/proxmark3/blob/master/client/scripts/mifarePlus.lua#L184 * added errors https://github.com/Proxmark/proxmark3/blob/master/client/scripts/mifarePlus.lua#L91 * fix bug in CLIParamHexToBuf * added init card command * auth4 refactoring * add changelog --- CHANGELOG.md | 1 + client/Makefile | 2 + client/cliparser/cliparser.c | 2 +- client/cliparser/cliparser.h | 1 + client/cmdhf14a.c | 10 +- client/cmdhfmf.c | 114 +------------ client/cmdhfmfp.c | 302 +++++++++++++++++++++++++++++++++++ client/mifare4.c | 118 ++++++++++++++ client/mifare4.h | 30 ++++ common/polarssl/libpcrypto.c | 44 +++++ common/polarssl/libpcrypto.h | 20 +++ 11 files changed, 529 insertions(+), 115 deletions(-) create mode 100644 client/mifare4.c create mode 100644 client/mifare4.h create mode 100644 common/polarssl/libpcrypto.c create mode 100644 common/polarssl/libpcrypto.h diff --git a/CHANGELOG.md b/CHANGELOG.md index fbc40cda..5f1847e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ### Fixed ### Added +- `hf mfp` group of commands (Merlok) ## [v3.1.0][2018-10-10] diff --git a/client/Makefile b/client/Makefile index c0a319a4..72d5080d 100644 --- a/client/Makefile +++ b/client/Makefile @@ -110,6 +110,7 @@ CMDSRCS = $(SRC_SMARTCARD) \ polarssl/bignum.c\ polarssl/rsa.c\ polarssl/sha1.c\ + polarssl/libpcrypto.c\ cliparser/argtable3.c\ cliparser/cliparser.c\ mfkey.c\ @@ -120,6 +121,7 @@ CMDSRCS = $(SRC_SMARTCARD) \ loclass/fileutils.c\ whereami.c\ mifarehost.c\ + mifare4.c\ parity.c\ crc.c \ crc16.c \ diff --git a/client/cliparser/cliparser.c b/client/cliparser/cliparser.c index 931d68cd..95422039 100644 --- a/client/cliparser/cliparser.c +++ b/client/cliparser/cliparser.c @@ -156,7 +156,7 @@ int CLIParamHexToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int int ibuf = 0; uint8_t buf[256] = {0}; - int res = CLIParamStrToBuf(argstr, buf, maxdatalen, &ibuf); + int res = CLIParamStrToBuf(argstr, buf, maxdatalen * 2, &ibuf); // *2 because here HEX if (res || !ibuf) return res; diff --git a/client/cliparser/cliparser.h b/client/cliparser/cliparser.h index 2f5ac317..c4bc7068 100644 --- a/client/cliparser/cliparser.h +++ b/client/cliparser/cliparser.h @@ -17,6 +17,7 @@ #define arg_getsize(a) (sizeof(a) / sizeof(a[0])) #define arg_get_lit(n)(((struct arg_lit*)argtable[n])->count) +#define arg_get_int_count(n)(((struct arg_int*)argtable[n])->count) #define arg_get_int(n)(((struct arg_int*)argtable[n])->ival[0]) #define arg_get_str(n)((struct arg_str*)argtable[n]) #define arg_get_str_len(n)(strlen(((struct arg_str*)argtable[n])->sval[0])) diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 31654188..326eaf50 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -750,6 +750,11 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav recv = resp.d.asBytes; int iLen = resp.arg[0]; + if(!iLen) { + PrintAndLog("14aRAW ERROR: No card response."); + return 1; + } + *dataoutlen = iLen - 2; if (*dataoutlen < 0) *dataoutlen = 0; @@ -766,11 +771,6 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav memcpy(dataout, &recv[2], *dataoutlen); - if(!iLen) { - PrintAndLog("14aRAW ERROR: No card response."); - return 1; - } - // CRC Check if (iLen == -1) { PrintAndLog("14aRAW ERROR: ISO 14443A CRC error."); diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index eb85b8c5..83180e7d 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -29,7 +29,7 @@ #include "hardnested/hardnested_bf_core.h" #include "cliparser/cliparser.h" #include "cmdhf14a.h" -#include +#include "mifare4.h" #define NESTED_SECTOR_RETRY 10 // how often we try mfested() until we give up @@ -2637,50 +2637,12 @@ int CmdDecryptTraceCmds(const char *Cmd){ return tryDecryptWord(param_get32ex(Cmd,0,0,16),param_get32ex(Cmd,1,0,16),param_get32ex(Cmd,2,0,16),data,len/2); } -int aes_encode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length){ - uint8_t iiv[16] = {0}; - if (iv) - memcpy(iiv, iv, 16); - - aes_context aes; - aes_init(&aes); - if (aes_setkey_enc(&aes, key, 128)) - return 1; - if (aes_crypt_cbc(&aes, AES_ENCRYPT, length, iiv, input, output)) - return 2; - aes_free(&aes); - - return 0; -} - -int aes_decode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length){ - uint8_t iiv[16] = {0}; - if (iv) - memcpy(iiv, iv, 16); - - aes_context aes; - aes_init(&aes); - if (aes_setkey_dec(&aes, key, 128)) - return 1; - if (aes_crypt_cbc(&aes, AES_DECRYPT, length, iiv, input, output)) - return 2; - aes_free(&aes); - - return 0; -} - int CmdHF14AMfAuth4(const char *cmd) { uint8_t keyn[20] = {0}; int keynlen = 0; uint8_t key[16] = {0}; int keylen = 0; - uint8_t data[257] = {0}; - int datalen = 0; - - uint8_t Rnd1[17] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00}; - uint8_t Rnd2[17] = {0}; - - + CLIParserInit("hf mf auth4", "Executes AES authentication command in ISO14443-4", "Usage:\n\thf mf auth4 4000 000102030405060708090a0b0c0d0e0f -> executes authentication\n" @@ -2694,8 +2656,8 @@ int CmdHF14AMfAuth4(const char *cmd) { }; CLIExecWithReturn(cmd, argtable, true); - CLIGetStrWithReturn(1, keyn, &keynlen); - CLIGetStrWithReturn(2, key, &keylen); + CLIGetHexWithReturn(1, keyn, &keynlen); + CLIGetHexWithReturn(2, key, &keylen); CLIParserFree(); if (keynlen != 2) { @@ -2708,73 +2670,7 @@ int CmdHF14AMfAuth4(const char *cmd) { return 1; } - uint8_t cmd1[] = {0x70, keyn[1], keyn[0], 0x00}; - int res = ExchangeRAW14a(cmd1, sizeof(cmd1), true, true, data, sizeof(data), &datalen); - if (res) { - PrintAndLog("ERROR exchande raw error: %d", res); - DropField(); - return 2; - } - - PrintAndLog("phase2: %s", sprint_hex(cmd2, 33)); - - res = ExchangeRAW14a(cmd2, sizeof(cmd2), false, false, data, sizeof(data), &datalen); - if (res) { - PrintAndLog("ERROR exchande raw error: %d", res); - DropField(); - return 4; - } - - PrintAndLog(">> %s", sprint_hex(datain, datainlen)); + + int res = ExchangeRAW14a(datain, datainlen, activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); + + if(VerboseMode) + PrintAndLog("<<< %s", sprint_hex(dataout, *dataoutlen)); + + return res; +} + +int MFPWritePerso(uint8_t *keyNum, uint8_t *key, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { + uint8_t rcmd[3 + 16] = {0xa8, keyNum[1], keyNum[0], 0x00}; + memmove(&rcmd[3], key, 16); + + return intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); +} + +int MFPCommitPerso(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { + uint8_t rcmd[1] = {0xaa}; + + return intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); +} + int CmdHFMFPInfo(const char *cmd) { if (cmd && strlen(cmd) > 0) @@ -103,10 +161,254 @@ int CmdHFMFPInfo(const char *cmd) { return 0; } +int CmdHFMFPWritePerso(const char *cmd) { + uint8_t keyNum[64] = {0}; + int keyNumLen = 0; + uint8_t key[64] = {0}; + int keyLen = 0; + + CLIParserInit("hf mfp wrp", + "Executes Write Perso command. Can be used in SL0 mode only.", + "Usage:\n\thf mfp wrp 4000 000102030405060708090a0b0c0d0e0f -> write key (00..0f) to key number 4000 \n" + "\thf mfp wrp 4000 -> write default key(0xff..0xff) to key number 4000"); + + void* argtable[] = { + arg_param_begin, + arg_lit0("vV", "verbose", "show internal data."), + arg_str1(NULL, NULL, "", NULL), + arg_strx0(NULL, NULL, "", NULL), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, true); + + bool verbose = arg_get_lit(1); + CLIGetHexWithReturn(2, keyNum, &keyNumLen); + CLIGetHexWithReturn(3, key, &keyLen); + CLIParserFree(); + + SetVerboseMode(verbose); + + if (!keyLen) { + memmove(key, DefaultKey, 16); + keyLen = 16; + } + + if (keyNumLen != 2) { + PrintAndLog("Key number length must be 2 bytes instead of: %d", keyNumLen); + return 1; + } + if (keyLen != 16) { + PrintAndLog("Key length must be 16 bytes instead of: %d", keyLen); + return 1; + } + + uint8_t data[250] = {0}; + int datalen = 0; + + int res = MFPWritePerso(keyNum, key, true, false, data, sizeof(data), &datalen); + if (res) { + PrintAndLog("Exchange error: %d", res); + return res; + } + + if (datalen != 3) { + PrintAndLog("Command must return 3 bytes instead of: %d", datalen); + return 1; + } + + if (data[0] != 0x90) { + PrintAndLog("Command error: %02x %s", data[0], GetErrorDescription(data[0])); + return 1; + } + PrintAndLog("Write OK."); + + return 0; +} + +uint16_t CardAddresses[] = {0x9000, 0x9001, 0x9002, 0x9003, 0x9004, 0xA000, 0xA001, 0xA080, 0xA081, 0xC000, 0xC001}; + +int CmdHFMFPInitPerso(const char *cmd) { + int res; + uint8_t key[256] = {0}; + int keyLen = 0; + uint8_t keyNum[2] = {0}; + uint8_t data[250] = {0}; + int datalen = 0; + + CLIParserInit("hf mfp initp", + "Executes Write Perso command for all card's keys. Can be used in SL0 mode only.", + "Usage:\n\thf mfp initp 000102030405060708090a0b0c0d0e0f -> fill all the keys with key (00..0f)\n" + "\thf mfp initp -vv -> fill all the keys with default key(0xff..0xff) and show all the data exchange"); + + void* argtable[] = { + arg_param_begin, + arg_litn("vV", "verbose", 0, 2, "show internal data."), + arg_strx0(NULL, NULL, "", NULL), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, true); + + bool verbose = arg_get_lit(1); + bool verbose2 = arg_get_lit(1) > 1; + CLIGetHexWithReturn(2, key, &keyLen); + CLIParserFree(); + + if (keyLen && keyLen != 16) { + PrintAndLog("Key length must be 16 bytes instead of: %d", keyLen); + return 1; + } + + if (!keyLen) + memmove(key, DefaultKey, 16); + + SetVerboseMode(verbose2); + for (uint16_t sn = 0x4000; sn < 0x4050; sn++) { + keyNum[0] = sn >> 8; + keyNum[1] = sn & 0xff; + res = MFPWritePerso(keyNum, key, (sn == 0x4000), true, data, sizeof(data), &datalen); + if (!res && (datalen == 3) && data[0] == 0x09) { + PrintAndLog("2k card detected."); + break; + } + if (res || (datalen != 3) || data[0] != 0x90) { + PrintAndLog("Write error on address %04x", sn); + break; + } + } + + SetVerboseMode(verbose); + for (int i = 0; i < sizeof(CardAddresses) / 2; i++) { + keyNum[0] = CardAddresses[i] >> 8; + keyNum[1] = CardAddresses[i] & 0xff; + res = MFPWritePerso(keyNum, key, false, true, data, sizeof(data), &datalen); + if (!res && (datalen == 3) && data[0] == 0x09) { + PrintAndLog("Skipped[%04x]...", CardAddresses[i]); + } else { + if (res || (datalen != 3) || data[0] != 0x90) { + PrintAndLog("Write error on address %04x", CardAddresses[i]); + break; + } + } + } + + DropField(); + + if (res) + return res; + + PrintAndLog("Done."); + + return 0; +} + +int CmdHFMFPCommitPerso(const char *cmd) { + CLIParserInit("hf mfp commitp", + "Executes Commit Perso command. Can be used in SL0 mode only.", + "Usage:\n\thf mfp commitp -> \n"); + + void* argtable[] = { + arg_param_begin, + arg_lit0("vV", "verbose", "show internal data."), + arg_int0(NULL, NULL, "SL mode", NULL), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, true); + + bool verbose = arg_get_lit(1); + CLIParserFree(); + + SetVerboseMode(verbose); + + uint8_t data[250] = {0}; + int datalen = 0; + + int res = MFPCommitPerso(true, false, data, sizeof(data), &datalen); + if (res) { + PrintAndLog("Exchange error: %d", res); + return res; + } + + if (datalen != 3) { + PrintAndLog("Command must return 3 bytes instead of: %d", datalen); + return 1; + } + + if (data[0] != 0x90) { + PrintAndLog("Command error: %02x %s", data[0], GetErrorDescription(data[0])); + return 1; + } + PrintAndLog("Switch level OK."); + + return 0; +} + +int CmdHFMFPAuth(const char *cmd) { + uint8_t keyn[250] = {0}; + int keynlen = 0; + uint8_t key[250] = {0}; + int keylen = 0; + + CLIParserInit("hf mfp auth", + "Executes AES authentication command in ISO14443-4", + "Usage:\n\thf mfp auth 4000 000102030405060708090a0b0c0d0e0f -> executes authentication\n" + "\thf mfp auth 9003 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -v -> executes authentication and shows all the system data\n"); + + void* argtable[] = { + arg_param_begin, + arg_lit0("vV", "verbose", "show internal data."), + arg_str1(NULL, NULL, "", NULL), + arg_str1(NULL, NULL, "", NULL), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, true); + + bool verbose = arg_get_lit(1); + CLIGetHexWithReturn(2, keyn, &keynlen); + CLIGetHexWithReturn(3, key, &keylen); + CLIParserFree(); + + if (keynlen != 2) { + PrintAndLog("ERROR: must be 2 bytes long instead of: %d", keynlen); + return 1; + } + + if (keylen != 16) { + PrintAndLog("ERROR: must be 16 bytes long instead of: %d", keylen); + return 1; + } + + return MifareAuth4(NULL, keyn, key, true, false, verbose); +} + +int CmdHFMFPRdbl(const char *cmd) { + //mf4Session session + //int res = MifareAuth4(&session, keyn, key, true, false, verbose); + //res = Read(); + + return 0; +} + +int CmdHFMFPRdsc(const char *cmd) { + + return 0; +} + +int CmdHFMFPWrbl(const char *cmd) { + + return 0; +} + static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"info", CmdHFMFPInfo, 0, "Info about Mifare Plus tag"}, + {"wrp", CmdHFMFPWritePerso, 0, "Write Perso command"}, + {"initp", CmdHFMFPInitPerso, 0, "Fills all the card's keys"}, + {"commitp", CmdHFMFPCommitPerso, 0, "Move card to SL1 or SL3 mode"}, + {"auth", CmdHFMFPAuth, 0, "Authentication in iso1443-4"}, +// {"rdbl", CmdHFMFPRdbl, 0, "Read blocks"}, +// {"rdsc", CmdHFMFPRdsc, 0, "Read sectors"}, +// {"wrbl", CmdHFMFPWrbl, 0, "Write blocks"}, {NULL, NULL, 0, NULL} }; diff --git a/client/mifare4.c b/client/mifare4.c new file mode 100644 index 00000000..3489c857 --- /dev/null +++ b/client/mifare4.c @@ -0,0 +1,118 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2018 Merlok +// +// 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. +//----------------------------------------------------------------------------- +// iso14443-4 mifare commands +//----------------------------------------------------------------------------- + +#include "mifare4.h" +#include +#include +#include "cmdhf14a.h" +#include "util.h" +#include "ui.h" +#include "polarssl/libpcrypto.h" + +int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool verbose) { + uint8_t data[257] = {0}; + int datalen = 0; + + uint8_t Rnd1[17] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00}; + uint8_t Rnd2[17] = {0}; + + if (session) + session->Authenticated = false; + + uint8_t cmd1[] = {0x70, keyn[1], keyn[0], 0x00}; + int res = ExchangeRAW14a(cmd1, sizeof(cmd1), activateField, true, data, sizeof(data), &datalen); + if (res) { + PrintAndLog("ERROR exchande raw error: %d", res); + DropField(); + return 2; + } + + if (verbose) + PrintAndLog("phase2: %s", sprint_hex(cmd2, 33)); + + res = ExchangeRAW14a(cmd2, sizeof(cmd2), false, false, data, sizeof(data), &datalen); + if (res) { + PrintAndLog("ERROR exchande raw error: %d", res); + DropField(); + return 4; + } + + if (verbose) + PrintAndLog("Authenticated = true; + session->KeyNum = keyn[1] + (keyn[0] << 8); + memmove(session->Rnd1, Rnd1, 16); + memmove(session->Rnd2, Rnd2, 16); + } + + PrintAndLog("Authentication OK"); + + return 0; +} + diff --git a/client/mifare4.h b/client/mifare4.h new file mode 100644 index 00000000..70711847 --- /dev/null +++ b/client/mifare4.h @@ -0,0 +1,30 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2018 Merlok +// +// 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. +//----------------------------------------------------------------------------- +// iso14443-4 mifare commands +//----------------------------------------------------------------------------- + +#ifndef MIFARE4_H +#define MIFARE4_H + +#include +#include +#include + +typedef struct { + bool Authenticated; + uint16_t KeyNum; + uint8_t Rnd1[16]; + uint8_t Rnd2[16]; + +}mf4Session; + +extern int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool verbose); + + + +#endif // mifare4.h diff --git a/common/polarssl/libpcrypto.c b/common/polarssl/libpcrypto.c new file mode 100644 index 00000000..032c3a18 --- /dev/null +++ b/common/polarssl/libpcrypto.c @@ -0,0 +1,44 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2018 Merlok +// +// 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. +//----------------------------------------------------------------------------- +// crypto commands +//----------------------------------------------------------------------------- + +#include "polarssl/libpcrypto.h" +#include + +int aes_encode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length){ + uint8_t iiv[16] = {0}; + if (iv) + memcpy(iiv, iv, 16); + + aes_context aes; + aes_init(&aes); + if (aes_setkey_enc(&aes, key, 128)) + return 1; + if (aes_crypt_cbc(&aes, AES_ENCRYPT, length, iiv, input, output)) + return 2; + aes_free(&aes); + + return 0; +} + +int aes_decode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length){ + uint8_t iiv[16] = {0}; + if (iv) + memcpy(iiv, iv, 16); + + aes_context aes; + aes_init(&aes); + if (aes_setkey_dec(&aes, key, 128)) + return 1; + if (aes_crypt_cbc(&aes, AES_DECRYPT, length, iiv, input, output)) + return 2; + aes_free(&aes); + + return 0; +} \ No newline at end of file diff --git a/common/polarssl/libpcrypto.h b/common/polarssl/libpcrypto.h new file mode 100644 index 00000000..84732cd3 --- /dev/null +++ b/common/polarssl/libpcrypto.h @@ -0,0 +1,20 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2018 Merlok +// +// 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. +//----------------------------------------------------------------------------- +// crypto commands +//----------------------------------------------------------------------------- + +#ifndef LIBPCRYPTO_H +#define LIBPCRYPTO_H + +#include +#include + +extern int aes_encode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length); +extern int aes_decode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length); + +#endif /* libpcrypto.h */ From cdc9a7562d70ec1b4c58841acc64150774e377b6 Mon Sep 17 00:00:00 2001 From: Oleg Moiseenko <807634+merlokk@users.noreply.github.com> Date: Fri, 26 Oct 2018 15:43:06 +0300 Subject: [PATCH 010/189] inc timeouts (#705) --- CI/appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CI/appveyor.yml b/CI/appveyor.yml index 1c22c92e..a38ff647 100644 --- a/CI/appveyor.yml +++ b/CI/appveyor.yml @@ -257,14 +257,14 @@ test_script: [bool]$res=$false # Wait 120 sec timeout for Job - if(Wait-Job $Job -Timeout 120){ + if(Wait-Job $Job -Timeout 150){ $Results = $Job | Receive-Job if($Results -like "true"){ $res=$true } } else { Write-host "Test [$Name] timeout" -ForegroundColor Red - Add-AppveyorTest -Name "$Name" -Framework NUnit -Filename "$File" -Outcome Failed -Duration 40000 -ErrorMessage "timeout" + Add-AppveyorTest -Name "$Name" -Framework NUnit -Filename "$File" -Outcome Failed -Duration 60000 -ErrorMessage "timeout" } Remove-Job -Force $Job From c8a0f5503172f25620670a9ba992d8c923b5df95 Mon Sep 17 00:00:00 2001 From: Oleg Moiseenko <807634+merlokk@users.noreply.github.com> Date: Fri, 26 Oct 2018 20:18:53 +0300 Subject: [PATCH 011/189] Mfp read plain (#704) * added aes-cmac-128 * aes-cmac added to cryptosystem. not works( --- client/Makefile | 1 + client/cliparser/cliparser.h | 1 + client/cmdhfmfp.c | 335 +++++++++++++++++++++++++++++++++- client/emv/test/cryptotest.c | 6 +- client/mifare4.c | 50 ++++- client/mifare4.h | 7 + common/polarssl/aes_cmac128.c | 322 ++++++++++++++++++++++++++++++++ common/polarssl/aes_cmac128.h | 81 ++++++++ common/polarssl/libpcrypto.c | 41 ++++- common/polarssl/libpcrypto.h | 2 + 10 files changed, 836 insertions(+), 10 deletions(-) create mode 100644 common/polarssl/aes_cmac128.c create mode 100644 common/polarssl/aes_cmac128.h diff --git a/client/Makefile b/client/Makefile index 72d5080d..1b211d4f 100644 --- a/client/Makefile +++ b/client/Makefile @@ -107,6 +107,7 @@ CMDSRCS = $(SRC_SMARTCARD) \ crapto1/crypto1.c\ polarssl/des.c \ polarssl/aes.c\ + polarssl/aes_cmac128.c\ polarssl/bignum.c\ polarssl/rsa.c\ polarssl/sha1.c\ diff --git a/client/cliparser/cliparser.h b/client/cliparser/cliparser.h index c4bc7068..05910ea4 100644 --- a/client/cliparser/cliparser.h +++ b/client/cliparser/cliparser.h @@ -19,6 +19,7 @@ #define arg_get_lit(n)(((struct arg_lit*)argtable[n])->count) #define arg_get_int_count(n)(((struct arg_int*)argtable[n])->count) #define arg_get_int(n)(((struct arg_int*)argtable[n])->ival[0]) +#define arg_get_int_def(n,def)(arg_get_int_count(n)?(arg_get_int(n)):(def)) #define arg_get_str(n)((struct arg_str*)argtable[n]) #define arg_get_str_len(n)(strlen(((struct arg_str*)argtable[n])->sval[0])) diff --git a/client/cmdhfmfp.c b/client/cmdhfmfp.c index a4c53f56..c5fd8eed 100644 --- a/client/cmdhfmfp.c +++ b/client/cmdhfmfp.c @@ -35,6 +35,9 @@ typedef struct { static const PlusErrorsElm PlusErrors[] = { {0xFF, ""}, {0x00, "Unknown error"}, + {0x06, "Block use error"}, + {0x07, "Command use error"}, + {0x08, "Invalid write command"}, {0x09, "Invalid block number"}, {0x0b, "Command code error"}, {0x0c, "Length error"}, @@ -82,6 +85,37 @@ int MFPCommitPerso(bool activateField, bool leaveSignalON, uint8_t *dataout, int return intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); } +int MFPReadBlock(mf4Session *session, bool plain, uint8_t blockNum, uint8_t blockCount, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) { + uint8_t rcmd[4 + 8] = {(plain?(0x37):(0x33)), blockNum, 0x00, blockCount}; + if (!plain && session) + CalculateMAC(session, rcmd, 4, &rcmd[4], VerboseMode); + + int res = intExchangeRAW14aPlus(rcmd, plain?4:sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); + if(res) + return res; + + if(session && mac) + CalculateMAC(session, dataout, *dataoutlen, mac, VerboseMode); + + return 0; +} + +int MFPWriteBlock(mf4Session *session, uint8_t blockNum, uint8_t *data, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) { + uint8_t rcmd[1 + 2 + 16 + 8] = {0xA3, blockNum, 0x00}; + memmove(&rcmd[3], data, 16); + if (session) + CalculateMAC(session, rcmd, 19, &rcmd[19], VerboseMode); + + int res = intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); + if(res) + return res; + + if(session && mac) + CalculateMAC(session, dataout, *dataoutlen, mac, VerboseMode); + + return 0; +} + int CmdHFMFPInfo(const char *cmd) { if (cmd && strlen(cmd) > 0) @@ -349,7 +383,7 @@ int CmdHFMFPAuth(const char *cmd) { int keylen = 0; CLIParserInit("hf mfp auth", - "Executes AES authentication command in ISO14443-4", + "Executes AES authentication command for Mifare Plus card", "Usage:\n\thf mfp auth 4000 000102030405060708090a0b0c0d0e0f -> executes authentication\n" "\thf mfp auth 9003 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -v -> executes authentication and shows all the system data\n"); @@ -381,20 +415,307 @@ int CmdHFMFPAuth(const char *cmd) { } int CmdHFMFPRdbl(const char *cmd) { - //mf4Session session - //int res = MifareAuth4(&session, keyn, key, true, false, verbose); - //res = Read(); + uint8_t keyn[2] = {0}; + uint8_t key[250] = {0}; + int keylen = 0; + + CLIParserInit("hf mfp rdbl", + "Reads several blocks from Mifare Plus card in plain mode.", + "Usage:\n\thf mfp rdbl 0 000102030405060708090a0b0c0d0e0f -> executes authentication and read block 0 data\n" + "\thf mfp rdbl 1 -v -> executes authentication and shows sector 1 data with default key 0xFF..0xFF and some additional data\n"); + + void* argtable[] = { + arg_param_begin, + arg_lit0("vV", "verbose", "show internal data."), + arg_int0("nN", "count", "blocks count (by default 1).", NULL), + arg_lit0("bB", "keyb", "use key B (by default keyA)."), + arg_lit0("pP", "plain", "plain communication between reader and card."), + arg_int1(NULL, NULL, "", NULL), + arg_str0(NULL, NULL, "", NULL), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, false); + + bool verbose = arg_get_lit(1); + int blocksCount = arg_get_int_def(2, 1); + bool keyB = arg_get_lit(3); + int plain = arg_get_lit(4) | true; + uint32_t blockn = arg_get_int(5); + CLIGetHexWithReturn(6, key, &keylen); + CLIParserFree(); + + SetVerboseMode(verbose); + + if (!keylen) { + memmove(key, DefaultKey, 16); + keylen = 16; + } + + if (blockn > 255) { + PrintAndLog("ERROR: must be in range [0..255] instead of: %d", blockn); + return 1; + } + + if (keylen != 16) { + PrintAndLog("ERROR: must be 16 bytes long instead of: %d", keylen); + return 1; + } + + // 3 blocks - wo iso14443-4 chaining + if (blocksCount > 3) { + PrintAndLog("ERROR: blocks count must be less than 3 instead of: %d", blocksCount); + return 1; + } + + uint8_t sectorNum = mfSectorNum(blockn & 0xff); + uint16_t uKeyNum = 0x4000 + sectorNum * 2 + (keyB ? 1 : 0); + keyn[0] = uKeyNum >> 8; + keyn[1] = uKeyNum & 0xff; + if (verbose) + PrintAndLog("--block:%d sector[%d]:%02x key:%04x", blockn, mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum); + + mf4Session session; + int res = MifareAuth4(&session, keyn, key, true, true, verbose); + if (res) { + PrintAndLog("Authentication error: %d", res); + return res; + } + + uint8_t data[250] = {0}; + int datalen = 0; + uint8_t mac[8] = {0}; + res = MFPReadBlock(&session, plain, blockn & 0xff, blocksCount, false, false, data, sizeof(data), &datalen, mac); + if (res) { + PrintAndLog("Read error: %d", res); + return res; + } + + if (datalen && data[0] != 0x90) { + PrintAndLog("Card read error: %02x %s", data[0], GetErrorDescription(data[0])); + return 6; + } + + if (datalen != 1 + blocksCount * 16 + 8 + 2) { + PrintAndLog("Error return length:%d", datalen); + return 5; + } + + int indx = blockn; + for(int i = 0; i < blocksCount; i++) { + PrintAndLog("data[%03d]: %s", indx, sprint_hex(&data[1 + i * 16], 16)); + indx++; + if (mfIsSectorTrailer(indx)){ + PrintAndLog("data[%03d]: ------------------- trailer -------------------", indx); + indx++; + } + } + + if (!memcmp(&data[blocksCount * 16 + 1], mac, 8)) { + PrintAndLog("WARNING: mac not equal..."); + PrintAndLog("MAC card: %s", sprint_hex(&data[blocksCount * 16 + 1], 8)); + PrintAndLog("MAC reader: %s", sprint_hex(mac, 8)); + } else { + if(verbose) + PrintAndLog("MAC: %s", sprint_hex(&data[blocksCount * 16 + 1], 8)); + } return 0; } int CmdHFMFPRdsc(const char *cmd) { + uint8_t keyn[2] = {0}; + uint8_t key[250] = {0}; + int keylen = 0; + + CLIParserInit("hf mfp rdsc", + "Reads one sector from Mifare Plus card in plain mode.", + "Usage:\n\thf mfp rdsc 0 000102030405060708090a0b0c0d0e0f -> executes authentication and read sector 0 data\n" + "\thf mfp rdsc 1 -v -> executes authentication and shows sector 1 data with default key 0xFF..0xFF and some additional data\n"); + + void* argtable[] = { + arg_param_begin, + arg_lit0("vV", "verbose", "show internal data."), + arg_lit0("bB", "keyb", "use key B (by default keyA)."), + arg_lit0("pP", "plain", "plain communication between reader and card."), + arg_int1(NULL, NULL, "", NULL), + arg_str0(NULL, NULL, "", NULL), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, false); + + bool verbose = arg_get_lit(1); + bool keyB = arg_get_lit(2); + bool plain = arg_get_lit(3) | true; + uint32_t sectorNum = arg_get_int(4); + CLIGetHexWithReturn(5, key, &keylen); + CLIParserFree(); + + SetVerboseMode(verbose); + + if (!keylen) { + memmove(key, DefaultKey, 16); + keylen = 16; + } + + if (sectorNum > 39) { + PrintAndLog("ERROR: must be in range [0..39] instead of: %d", sectorNum); + return 1; + } + + if (keylen != 16) { + PrintAndLog("ERROR: must be 16 bytes long instead of: %d", keylen); + return 1; + } + + uint16_t uKeyNum = 0x4000 + sectorNum * 2 + (keyB ? 1 : 0); + keyn[0] = uKeyNum >> 8; + keyn[1] = uKeyNum & 0xff; + if (verbose) + PrintAndLog("--sector[%d]:%02x key:%04x", mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum); + + mf4Session session; + int res = MifareAuth4(&session, keyn, key, true, true, verbose); + if (res) { + PrintAndLog("Authentication error: %d", res); + return res; + } + + uint8_t data[250] = {0}; + int datalen = 0; + uint8_t mac[8] = {0}; + for(int n = mfFirstBlockOfSector(sectorNum); n < mfFirstBlockOfSector(sectorNum) + mfNumBlocksPerSector(sectorNum); n++) { + res = MFPReadBlock(&session, plain, n & 0xff, 1, false, true, data, sizeof(data), &datalen, mac); + if (res) { + PrintAndLog("Read error: %d", res); + DropField(); + return res; + } + + if (datalen && data[0] != 0x90) { + PrintAndLog("Card read error: %02x %s", data[0], GetErrorDescription(data[0])); + DropField(); + return 6; + } + if (datalen != 1 + 16 + 8 + 2) { + PrintAndLog("Error return length:%d", datalen); + DropField(); + return 5; + } + + PrintAndLog("data[%03d]: %s", n, sprint_hex(&data[1], 16)); + + if (!memcmp(&data[1 + 16], mac, 8)) { + PrintAndLog("WARNING: mac on block %d not equal...", n); + PrintAndLog("MAC card: %s", sprint_hex(&data[1 + 16], 8)); + PrintAndLog("MAC reader: %s", sprint_hex(mac, 8)); + } else { + if(verbose) + PrintAndLog("MAC: %s", sprint_hex(&data[1 + 16], 8)); + } + } + DropField(); return 0; } int CmdHFMFPWrbl(const char *cmd) { + uint8_t keyn[2] = {0}; + uint8_t key[250] = {0}; + int keylen = 0; + uint8_t datain[250] = {0}; + int datainlen = 0; + CLIParserInit("hf mfp wrbl", + "Writes one block to Mifare Plus card.", + "Usage:\n\thf mfp wrbl 1 ff0000000000000000000000000000ff 000102030405060708090a0b0c0d0e0f -> writes block 1 data\n" + "\thf mfp wrbl 2 ff0000000000000000000000000000ff -v -> writes block 2 data with default key 0xFF..0xFF and some additional data\n"); + + void* argtable[] = { + arg_param_begin, + arg_lit0("vV", "verbose", "show internal data."), + arg_lit0("bB", "keyb", "use key B (by default keyA)."), + arg_int1(NULL, NULL, "", NULL), + arg_str1(NULL, NULL, "", NULL), + arg_str0(NULL, NULL, "", NULL), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, false); + + bool verbose = arg_get_lit(1); + bool keyB = arg_get_lit(2); + uint32_t blockNum = arg_get_int(3); + CLIGetHexWithReturn(4, datain, &datainlen); + CLIGetHexWithReturn(5, key, &keylen); + CLIParserFree(); + + SetVerboseMode(verbose); + + if (!keylen) { + memmove(key, DefaultKey, 16); + keylen = 16; + } + + if (blockNum > 39) { + PrintAndLog("ERROR: must be in range [0..255] instead of: %d", blockNum); + return 1; + } + + if (keylen != 16) { + PrintAndLog("ERROR: must be 16 bytes long instead of: %d", keylen); + return 1; + } + + if (datainlen != 16) { + PrintAndLog("ERROR: must be 16 bytes long instead of: %d", datainlen); + return 1; + } + + uint8_t sectorNum = mfSectorNum(blockNum & 0xff); + uint16_t uKeyNum = 0x4000 + sectorNum * 2 + (keyB ? 1 : 0); + keyn[0] = uKeyNum >> 8; + keyn[1] = uKeyNum & 0xff; + if (verbose) + PrintAndLog("--block:%d sector[%d]:%02x key:%04x", blockNum & 0xff, mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum); + + mf4Session session; + int res = MifareAuth4(&session, keyn, key, true, true, verbose); + if (res) { + PrintAndLog("Authentication error: %d", res); + return res; + } + + uint8_t data[250] = {0}; + int datalen = 0; + uint8_t mac[8] = {0}; + res = MFPWriteBlock(&session, blockNum & 0xff, datain, false, false, data, sizeof(data), &datalen, mac); + if (res) { + PrintAndLog("Write error: %d", res); + DropField(); + return res; + } + + if (datalen != 3 && (datalen != 3 + 8)) { + PrintAndLog("Error return length:%d", datalen); + DropField(); + return 5; + } + + if (datalen && data[0] != 0x90) { + PrintAndLog("Card write error: %02x %s", data[0], GetErrorDescription(data[0])); + DropField(); + return 6; + } + + if (!memcmp(&data[1], mac, 8)) { + PrintAndLog("WARNING: mac not equal..."); + PrintAndLog("MAC card: %s", sprint_hex(&data[1], 8)); + PrintAndLog("MAC reader: %s", sprint_hex(mac, 8)); + } else { + if(verbose) + PrintAndLog("MAC: %s", sprint_hex(&data[1], 8)); + } + + DropField(); return 0; } @@ -405,9 +726,9 @@ static command_t CommandTable[] = {"wrp", CmdHFMFPWritePerso, 0, "Write Perso command"}, {"initp", CmdHFMFPInitPerso, 0, "Fills all the card's keys"}, {"commitp", CmdHFMFPCommitPerso, 0, "Move card to SL1 or SL3 mode"}, - {"auth", CmdHFMFPAuth, 0, "Authentication in iso1443-4"}, -// {"rdbl", CmdHFMFPRdbl, 0, "Read blocks"}, -// {"rdsc", CmdHFMFPRdsc, 0, "Read sectors"}, + {"auth", CmdHFMFPAuth, 0, "Authentication"}, + {"rdbl", CmdHFMFPRdbl, 0, "Read blocks"}, + {"rdsc", CmdHFMFPRdsc, 0, "Read sectors"}, // {"wrbl", CmdHFMFPWrbl, 0, "Write blocks"}, {NULL, NULL, 0, NULL} }; diff --git a/client/emv/test/cryptotest.c b/client/emv/test/cryptotest.c index a6d06e68..b778d256 100644 --- a/client/emv/test/cryptotest.c +++ b/client/emv/test/cryptotest.c @@ -14,6 +14,7 @@ #include "bignum.h" #include "aes.h" +#include "aes_cmac128.h" #include "des.h" #include "rsa.h" #include "sha1.h" @@ -32,7 +33,10 @@ int ExecuteCryptoTests(bool verbose) { res = aes_self_test(verbose); if (res) TestFail = true; - + + res = aes_cmac_self_test(verbose); + if (res) TestFail = true; + res = des_self_test(verbose); if (res) TestFail = true; diff --git a/client/mifare4.c b/client/mifare4.c index 3489c857..e1021196 100644 --- a/client/mifare4.c +++ b/client/mifare4.c @@ -16,6 +16,18 @@ #include "ui.h" #include "polarssl/libpcrypto.h" +int CalculateMAC(mf4Session *session, uint8_t *data, int datalen, uint8_t *mac, bool verbose) { + if (!session || !session->Authenticated || !mac || !data || !datalen) + return 1; + + memset(mac, 0x00, 8); + + if (verbose) + PrintAndLog("MAC data[%d]: %s", datalen, sprint_hex(data, datalen)); + + return aes_cmac8(NULL, session->Key, data, mac, datalen); +} + int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool verbose) { uint8_t data[257] = {0}; int datalen = 0; @@ -71,7 +83,7 @@ int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateF if (verbose) PrintAndLog(">phase2: %s", sprint_hex(cmd2, 33)); - res = ExchangeRAW14a(cmd2, sizeof(cmd2), false, false, data, sizeof(data), &datalen); + res = ExchangeRAW14a(cmd2, sizeof(cmd2), false, true, data, sizeof(data), &datalen); if (res) { PrintAndLog("ERROR exchande raw error: %d", res); DropField(); @@ -109,6 +121,7 @@ int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateF session->KeyNum = keyn[1] + (keyn[0] << 8); memmove(session->Rnd1, Rnd1, 16); memmove(session->Rnd2, Rnd2, 16); + memmove(session->Key, key, 16); } PrintAndLog("Authentication OK"); @@ -116,3 +129,38 @@ int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateF return 0; } +// Mifare Memory Structure: up to 32 Sectors with 4 blocks each (1k and 2k cards), +// plus evtl. 8 sectors with 16 blocks each (4k cards) +uint8_t mfNumBlocksPerSector(uint8_t sectorNo) { + if (sectorNo < 32) + return 4; + else + return 16; +} + +uint8_t mfFirstBlockOfSector(uint8_t sectorNo) { + if (sectorNo < 32) + return sectorNo * 4; + else + return 32 * 4 + (sectorNo - 32) * 16; +} + +uint8_t mfSectorTrailer(uint8_t blockNo) { + if (blockNo < 32*4) { + return (blockNo | 0x03); + } else { + return (blockNo | 0x0f); + } +} + +bool mfIsSectorTrailer(uint8_t blockNo) { + return (blockNo == mfSectorTrailer(blockNo)); +} + +uint8_t mfSectorNum(uint8_t blockNo) { + if (blockNo < 32 * 4) + return blockNo / 4; + else + return 32 + (blockNo - 32 * 4) / 16; + +} diff --git a/client/mifare4.h b/client/mifare4.h index 70711847..5b789a70 100644 --- a/client/mifare4.h +++ b/client/mifare4.h @@ -17,14 +17,21 @@ typedef struct { bool Authenticated; + uint8_t Key[16]; uint16_t KeyNum; uint8_t Rnd1[16]; uint8_t Rnd2[16]; }mf4Session; +extern int CalculateMAC(mf4Session *session, uint8_t *data, int datalen, uint8_t *mac, bool verbose); extern int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool verbose); +extern uint8_t mfNumBlocksPerSector(uint8_t sectorNo); +extern uint8_t mfFirstBlockOfSector(uint8_t sectorNo); +extern uint8_t mfSectorTrailer(uint8_t blockNo); +extern bool mfIsSectorTrailer(uint8_t blockNo); +extern uint8_t mfSectorNum(uint8_t blockNo); #endif // mifare4.h diff --git a/common/polarssl/aes_cmac128.c b/common/polarssl/aes_cmac128.c new file mode 100644 index 00000000..595f89b8 --- /dev/null +++ b/common/polarssl/aes_cmac128.c @@ -0,0 +1,322 @@ +/* + * AES-CMAC from NIST Special Publication 800-38B — Recommendation for block cipher modes of operation: The CMAC mode for authentication. + * + * Copyright (C) 2006-2014, Brainspark B.V. + * Copyright (C) 2014, Anargyros Plemenos + * Tests added Merkok, 2018 + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Reference : https://polarssl.org/discussions/generic/authentication-token + * NIST Special Publication 800-38B — Recommendation for block cipher modes of operation: The CMAC mode for authentication. + * Tests here: + * https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/AES_CMAC.pdf +*/ + +#include "polarssl/aes_cmac128.h" +#include + +#define MIN(a,b) ((a)<(b)?(a):(b)) +#define _MSB(x) (((x)[0] & 0x80)?1:0) + +#if !defined(POLARSSL_CONFIG_FILE) +#include "polarssl_config.h" +#else +#include POLARSSL_CONFIG_FILE +#endif + +#if defined(POLARSSL_AES_C) +#include "aes.h" +#endif + +#if defined(POLARSSL_PLATFORM_C) +#include "polarssl/platform.h" +#else +#define polarssl_printf printf +#endif + + +/** + * zero a structure + */ +#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x)) + +/** + * zero a structure given a pointer to the structure + */ +#define ZERO_STRUCTP(x) do{ if((x) != NULL) memset((char *)(x), 0, sizeof(*(x)));} while(0) + + +/* For CMAC Calculation */ +static unsigned char const_Rb[16] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87 +}; +static unsigned char const_Zero[16] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static inline void aes_cmac_128_left_shift_1(const uint8_t in[16], uint8_t out[16]) +{ + uint8_t overflow = 0; + int8_t i; + + for (i = 15; i >= 0; i--) { + out[i] = in[i] << 1; + out[i] |= overflow; + overflow = _MSB(&in[i]); + } +} + +static inline void aes_cmac_128_xor(const uint8_t in1[16], const uint8_t in2[16], + uint8_t out[16]) +{ + uint8_t i; + + for (i = 0; i < 16; i++) { + out[i] = in1[i] ^ in2[i]; + } +} + +/* + * AES-CMAC-128 context setup + */ +void aes_cmac128_starts(aes_cmac128_context *ctx, const uint8_t K[16]) +{ + uint8_t L[16]; + + /* Zero struct of aes_context */ + ZERO_STRUCTP(ctx); + /* Initialize aes_context */ + aes_setkey_enc(&ctx->aes_key, K, 128); + + /* step 1 - generate subkeys k1 and k2 */ + aes_crypt_ecb(&ctx->aes_key, AES_ENCRYPT, const_Zero, L); + + if (_MSB(L) == 0) { + aes_cmac_128_left_shift_1(L, ctx->K1); + } else { + uint8_t tmp_block[16]; + + aes_cmac_128_left_shift_1(L, tmp_block); + aes_cmac_128_xor(tmp_block, const_Rb, ctx->K1); + ZERO_STRUCT(tmp_block); + } + + if (_MSB(ctx->K1) == 0) { + aes_cmac_128_left_shift_1(ctx->K1, ctx->K2); + } else { + uint8_t tmp_block[16]; + + aes_cmac_128_left_shift_1(ctx->K1, tmp_block); + aes_cmac_128_xor(tmp_block, const_Rb, ctx->K2); + ZERO_STRUCT(tmp_block); + } + + ZERO_STRUCT(L); +} + +/* + * AES-CMAC-128 process message + */ +void aes_cmac128_update(aes_cmac128_context *ctx, const uint8_t *_msg, size_t _msg_len) +{ + uint8_t tmp_block[16]; + uint8_t Y[16]; + const uint8_t *msg = _msg; + size_t msg_len = _msg_len; + + /* + * copy the remembered last block + */ + ZERO_STRUCT(tmp_block); + if (ctx->last_len) { + memcpy(tmp_block, ctx->last, ctx->last_len); + } + + /* + * check if we expand the block + */ + if (ctx->last_len < 16) { + size_t len = MIN(16 - ctx->last_len, msg_len); + + memcpy(&tmp_block[ctx->last_len], msg, len); + memcpy(ctx->last, tmp_block, 16); + msg += len; + msg_len -= len; + ctx->last_len += len; + } + + if (msg_len == 0) { + /* if it is still the last block, we are done */ + ZERO_STRUCT(tmp_block); + return; + } + + /* + * It is not the last block anymore + */ + ZERO_STRUCT(ctx->last); + ctx->last_len = 0; + + /* + * now checksum everything but the last block + */ + aes_cmac_128_xor(ctx->X, tmp_block, Y); + aes_crypt_ecb(&ctx->aes_key, AES_ENCRYPT, Y, ctx->X); + + while (msg_len > 16) { + memcpy(tmp_block, msg, 16); + msg += 16; + msg_len -= 16; + + aes_cmac_128_xor(ctx->X, tmp_block, Y); + aes_crypt_ecb(&ctx->aes_key, AES_ENCRYPT, Y, ctx->X); + } + + /* + * copy the last block, it will be processed in + * aes_cmac128_final(). + */ + memcpy(ctx->last, msg, msg_len); + ctx->last_len = msg_len; + + ZERO_STRUCT(tmp_block); + ZERO_STRUCT(Y); +} + +/* + * AES-CMAC-128 compute T + */ +void aes_cmac128_final(aes_cmac128_context *ctx, uint8_t T[16]) +{ + uint8_t tmp_block[16]; + uint8_t Y[16]; + + if (ctx->last_len < 16) { + ctx->last[ctx->last_len] = 0x80; + aes_cmac_128_xor(ctx->last, ctx->K2, tmp_block); + } else { + aes_cmac_128_xor(ctx->last, ctx->K1, tmp_block); + } + + aes_cmac_128_xor(tmp_block, ctx->X, Y); + aes_crypt_ecb(&ctx->aes_key, AES_ENCRYPT, Y, T); + + ZERO_STRUCT(tmp_block); + ZERO_STRUCT(Y); + ZERO_STRUCTP(ctx); +} + +/* + * Checkup routine + * + * https://csrc.nist.gov/projects/cryptographic-standards-and-guidelines/example-values + * https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/AES_CMAC.pdf + */ +int aes_cmac_self_test( int verbose ) +{ + unsigned char key[16] = {0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C}; + unsigned char mac[16] = {0}; + aes_cmac128_context ctx; + int ret; + + // check Example1: + if( verbose != 0 ) + polarssl_printf( " AES-CMAC-128 zero length data: " ); + unsigned char ex1data[16] = {0}; + aes_cmac128_starts(&ctx, key); + aes_cmac128_update(&ctx, ex1data, 0); + aes_cmac128_final(&ctx, mac); + unsigned char ex1res[16] = {0xBB, 0x1D, 0x69, 0x29, 0xE9, 0x59, 0x37, 0x28, 0x7F, 0xA3, 0x7D, 0x12, 0x9B, 0x75, 0x67, 0x46}; + if(!memcmp(mac, ex1res, 16)) { + if( verbose != 0 ) + polarssl_printf( "passed\n" ); + } else { + polarssl_printf( "failed\n" ); + ret = 1; + goto exit; + } + + // check Example2: + if( verbose != 0 ) + polarssl_printf( " AES-CMAC-128 one block data : " ); + unsigned char ex2data[16] = {0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A}; + aes_cmac128_starts(&ctx, key); + aes_cmac128_update(&ctx, ex2data, sizeof(ex2data)); + aes_cmac128_final(&ctx, mac); + unsigned char ex2res[16] = {0x07, 0x0A, 0x16, 0xB4, 0x6B, 0x4D, 0x41, 0x44, 0xF7, 0x9B, 0xDD, 0x9D, 0xD0, 0x4A, 0x28, 0x7C}; + if(!memcmp(mac, ex2res, 16)) { + if( verbose != 0 ) + polarssl_printf( "passed\n" ); + } else { + polarssl_printf( "failed\n" ); + ret = 1; + goto exit; + } + + // check Example3: + if( verbose != 0 ) + polarssl_printf( " AES-CMAC-128 20 bytes of data: " ); + unsigned char ex3data[20] = {0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A, + 0xAE, 0x2D, 0x8A, 0x57}; + aes_cmac128_starts(&ctx, key); + aes_cmac128_update(&ctx, ex3data, sizeof(ex3data)); + aes_cmac128_final(&ctx, mac); + unsigned char ex3res[16] = {0x7D, 0x85, 0x44, 0x9E, 0xA6, 0xEA, 0x19, 0xC8, 0x23, 0xA7, 0xBF, 0x78, 0x83, 0x7D, 0xFA, 0xDE}; + if(!memcmp(mac, ex3res, 16)) { + if( verbose != 0 ) + polarssl_printf( "passed\n" ); + } else { + polarssl_printf( "failed\n" ); + ret = 1; + goto exit; + } + + // check Example4: + if( verbose != 0 ) + polarssl_printf( " AES-CMAC-128 4 blocks of data: " ); + unsigned char ex4data[64] = {0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A, + 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C, 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51, + 0x30, 0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11, 0xE5, 0xFB, 0xC1, 0x19, 0x1A, 0x0A, 0x52, 0xEF, + 0xF6, 0x9F, 0x24, 0x45, 0xDF, 0x4F, 0x9B, 0x17, 0xAD, 0x2B, 0x41, 0x7B, 0xE6, 0x6C, 0x37, 0x10}; + aes_cmac128_starts(&ctx, key); + aes_cmac128_update(&ctx, ex4data, sizeof(ex4data)); + aes_cmac128_final(&ctx, mac); + unsigned char ex4res[16] = {0x51, 0xF0, 0xBE, 0xBF, 0x7E, 0x3B, 0x9D, 0x92, 0xFC, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3C, 0xFE}; + if(!memcmp(mac, ex4res, 16)) { + if( verbose != 0 ) + polarssl_printf( "passed\n" ); + } else { + polarssl_printf( "failed\n" ); + ret = 1; + goto exit; + } + + if( verbose != 0 ) + polarssl_printf( "\n" ); + + ret = 0; + +exit: + return( ret ); +} + diff --git a/common/polarssl/aes_cmac128.h b/common/polarssl/aes_cmac128.h new file mode 100644 index 00000000..b792755f --- /dev/null +++ b/common/polarssl/aes_cmac128.h @@ -0,0 +1,81 @@ +/* + * AES-CMAC from NIST Special Publication 800-38B — Recommendation for block cipher modes of operation: The CMAC mode for authentication. + * + * Copyright (C) 2006-2014, Brainspark B.V. + * Copyright (C) 2014, Anargyros Plemenos + * Tests added Merkok, 2018 + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Reference : https://polarssl.org/discussions/generic/authentication-token + * NIST Special Publication 800-38B — Recommendation for block cipher modes of operation: The CMAC mode for authentication. + * Tests here: + * https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/AES_CMAC.pdf +*/ + +#include +#include +#include "aes.h" + +typedef struct aes_cmac_128_context { + aes_context aes_key; + + uint8_t K1[16]; + uint8_t K2[16]; + + uint8_t X[16]; + + uint8_t last[16]; + size_t last_len; +} +aes_cmac128_context; + +/* + * \brief AES-CMAC-128 context setup + * + * \param ctx context to be initialized + * \param key secret key for AES-128 + */ +void aes_cmac128_starts(aes_cmac128_context *ctx, const uint8_t K[16]); + +/* + * \brief AES-CMAC-128 process message + * + * \param ctx context to be initialized + * \param _msg the given message + * \param _msg_len the length of message + */ +void aes_cmac128_update(aes_cmac128_context *ctx, const uint8_t *_msg, size_t _msg_len); + +/* + * \brief AES-CMAC-128 compute T + * + * \param ctx context to be initialized + * \param T the generated MAC which is used to validate the message + */ +void aes_cmac128_final(aes_cmac128_context *ctx, uint8_t T[16]); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int aes_cmac_self_test( int verbose ); + diff --git a/common/polarssl/libpcrypto.c b/common/polarssl/libpcrypto.c index 032c3a18..9be9fd26 100644 --- a/common/polarssl/libpcrypto.c +++ b/common/polarssl/libpcrypto.c @@ -10,7 +10,9 @@ #include "polarssl/libpcrypto.h" #include +#include +// NIST Special Publication 800-38A — Recommendation for block cipher modes of operation: methods and techniques, 2001. int aes_encode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length){ uint8_t iiv[16] = {0}; if (iv) @@ -41,4 +43,41 @@ int aes_decode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int l aes_free(&aes); return 0; -} \ No newline at end of file +} + +// NIST Special Publication 800-38B — Recommendation for block cipher modes of operation: The CMAC mode for authentication. +// https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/AES_CMAC.pdf +int aes_cmac(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, int length) { + memset(mac, 0x00, 16); + uint8_t iiv[16] = {0}; + if (iv) + memcpy(iiv, iv, 16); + + // padding: ISO/IEC 9797-1 Message Authentication Codes (MACs) - Part 1: Mechanisms using a block cipher + uint8_t data[2049] = {0}; // length + 16 + memcpy(data, input, length); + data[length] = 0x80; + int datalen = (length & 0xfffffff0) + 0x10; + + // NIST 800-38B + aes_cmac128_context ctx; + aes_cmac128_starts(&ctx, key); + aes_cmac128_update(&ctx, data, datalen); + aes_cmac128_final(&ctx, mac); + + return 0; +} + +int aes_cmac8(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, int length) { + uint8_t cmac[16] = {0}; + memset(mac, 0x00, 8); + + int res = aes_cmac(iv, key, input, cmac, length); + if (res) + return res; + + for(int i = 0; i < 8; i++) + mac[i] = cmac[i * 2 + 1]; + + return 0; +} diff --git a/common/polarssl/libpcrypto.h b/common/polarssl/libpcrypto.h index 84732cd3..1b74c143 100644 --- a/common/polarssl/libpcrypto.h +++ b/common/polarssl/libpcrypto.h @@ -16,5 +16,7 @@ extern int aes_encode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length); extern int aes_decode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length); +extern int aes_cmac(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, int length); +extern int aes_cmac8(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, int length); #endif /* libpcrypto.h */ From 4b5d696c179edc687ba0b61c7d96ea0ef54cad44 Mon Sep 17 00:00:00 2001 From: drhatson <44032553+drhatson@users.noreply.github.com> Date: Wed, 31 Oct 2018 18:46:12 +0000 Subject: [PATCH 012/189] changes to mifare plus code (#706) --- CHANGELOG.md | 1 + client/cmdhfmfp.c | 60 ++++++++++------ client/mifare4.c | 133 ++++++++++++++++++++++++++++++----- client/mifare4.h | 22 ++++-- common/polarssl/libpcrypto.c | 11 +-- 5 files changed, 175 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f1847e1..7781935e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ## [unreleased][unreleased] ### Changed +- Changed hf mfp security. Now it works in all the modes. (drHatson) ### Fixed diff --git a/client/cmdhfmfp.c b/client/cmdhfmfp.c index c5fd8eed..1ff24eb1 100644 --- a/client/cmdhfmfp.c +++ b/client/cmdhfmfp.c @@ -1,5 +1,6 @@ //----------------------------------------------------------------------------- // Copyright (C) 2018 Merlok +// Copyright (C) 2018 drHatson // // 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 @@ -34,13 +35,15 @@ typedef struct { static const PlusErrorsElm PlusErrors[] = { {0xFF, ""}, - {0x00, "Unknown error"}, - {0x06, "Block use error"}, - {0x07, "Command use error"}, - {0x08, "Invalid write command"}, - {0x09, "Invalid block number"}, - {0x0b, "Command code error"}, + {0x00, "Transfer cannot be granted within the current authentication."}, + {0x06, "Access Conditions not fulfilled. Block does not exist, block is not a value block."}, + {0x07, "Too many read or write commands in the session or in the transaction."}, + {0x08, "Invalid MAC in command or response"}, + {0x09, "Block Number is not valid"}, + {0x0a, "Invalid block number, not existing block number"}, + {0x0b, "The current command code not available at the current card state."}, {0x0c, "Length error"}, + {0x0f, "General Manipulation Error. Failure in the operation of the PICC (cannot write to the data block), etc."}, {0x90, "OK"}, }; int PlusErrorsLen = sizeof(PlusErrors) / sizeof(PlusErrorsElm); @@ -88,14 +91,17 @@ int MFPCommitPerso(bool activateField, bool leaveSignalON, uint8_t *dataout, int int MFPReadBlock(mf4Session *session, bool plain, uint8_t blockNum, uint8_t blockCount, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) { uint8_t rcmd[4 + 8] = {(plain?(0x37):(0x33)), blockNum, 0x00, blockCount}; if (!plain && session) - CalculateMAC(session, rcmd, 4, &rcmd[4], VerboseMode); + CalculateMAC(session, mtypReadCmd, blockNum, blockCount, rcmd, 4, &rcmd[4], VerboseMode); int res = intExchangeRAW14aPlus(rcmd, plain?4:sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); if(res) return res; - if(session && mac) - CalculateMAC(session, dataout, *dataoutlen, mac, VerboseMode); + if (session) + session->R_Ctr++; + + if(session && mac && *dataoutlen > 11) + CalculateMAC(session, mtypReadResp, blockNum, blockCount, dataout, *dataoutlen - 8 - 2, mac, VerboseMode); return 0; } @@ -104,14 +110,17 @@ int MFPWriteBlock(mf4Session *session, uint8_t blockNum, uint8_t *data, bool act uint8_t rcmd[1 + 2 + 16 + 8] = {0xA3, blockNum, 0x00}; memmove(&rcmd[3], data, 16); if (session) - CalculateMAC(session, rcmd, 19, &rcmd[19], VerboseMode); + CalculateMAC(session, mtypWriteCmd, blockNum, 1, rcmd, 19, &rcmd[19], VerboseMode); int res = intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); if(res) return res; - if(session && mac) - CalculateMAC(session, dataout, *dataoutlen, mac, VerboseMode); + if (session) + session->W_Ctr++; + + if(session && mac && *dataoutlen > 3) + CalculateMAC(session, mtypWriteResp, blockNum, 1, dataout, *dataoutlen, mac, VerboseMode); return 0; } @@ -420,7 +429,7 @@ int CmdHFMFPRdbl(const char *cmd) { int keylen = 0; CLIParserInit("hf mfp rdbl", - "Reads several blocks from Mifare Plus card in plain mode.", + "Reads several blocks from Mifare Plus card.", "Usage:\n\thf mfp rdbl 0 000102030405060708090a0b0c0d0e0f -> executes authentication and read block 0 data\n" "\thf mfp rdbl 1 -v -> executes authentication and shows sector 1 data with default key 0xFF..0xFF and some additional data\n"); @@ -429,7 +438,7 @@ int CmdHFMFPRdbl(const char *cmd) { arg_lit0("vV", "verbose", "show internal data."), arg_int0("nN", "count", "blocks count (by default 1).", NULL), arg_lit0("bB", "keyb", "use key B (by default keyA)."), - arg_lit0("pP", "plain", "plain communication between reader and card."), + arg_lit0("pP", "plain", "plain communication mode between reader and card."), arg_int1(NULL, NULL, "", NULL), arg_str0(NULL, NULL, "", NULL), arg_param_end @@ -439,7 +448,7 @@ int CmdHFMFPRdbl(const char *cmd) { bool verbose = arg_get_lit(1); int blocksCount = arg_get_int_def(2, 1); bool keyB = arg_get_lit(3); - int plain = arg_get_lit(4) | true; + int plain = arg_get_lit(4); uint32_t blockn = arg_get_int(5); CLIGetHexWithReturn(6, key, &keylen); CLIParserFree(); @@ -467,6 +476,10 @@ int CmdHFMFPRdbl(const char *cmd) { return 1; } + if (blocksCount > 1 && mfIsSectorTrailer(blockn)) { + PrintAndLog("WARNING: trailer!"); + } + uint8_t sectorNum = mfSectorNum(blockn & 0xff); uint16_t uKeyNum = 0x4000 + sectorNum * 2 + (keyB ? 1 : 0); keyn[0] = uKeyNum >> 8; @@ -504,13 +517,13 @@ int CmdHFMFPRdbl(const char *cmd) { for(int i = 0; i < blocksCount; i++) { PrintAndLog("data[%03d]: %s", indx, sprint_hex(&data[1 + i * 16], 16)); indx++; - if (mfIsSectorTrailer(indx)){ + if (mfIsSectorTrailer(indx) && i != blocksCount - 1){ PrintAndLog("data[%03d]: ------------------- trailer -------------------", indx); indx++; } } - if (!memcmp(&data[blocksCount * 16 + 1], mac, 8)) { + if (memcmp(&data[blocksCount * 16 + 1], mac, 8)) { PrintAndLog("WARNING: mac not equal..."); PrintAndLog("MAC card: %s", sprint_hex(&data[blocksCount * 16 + 1], 8)); PrintAndLog("MAC reader: %s", sprint_hex(mac, 8)); @@ -528,7 +541,7 @@ int CmdHFMFPRdsc(const char *cmd) { int keylen = 0; CLIParserInit("hf mfp rdsc", - "Reads one sector from Mifare Plus card in plain mode.", + "Reads one sector from Mifare Plus card.", "Usage:\n\thf mfp rdsc 0 000102030405060708090a0b0c0d0e0f -> executes authentication and read sector 0 data\n" "\thf mfp rdsc 1 -v -> executes authentication and shows sector 1 data with default key 0xFF..0xFF and some additional data\n"); @@ -536,7 +549,7 @@ int CmdHFMFPRdsc(const char *cmd) { arg_param_begin, arg_lit0("vV", "verbose", "show internal data."), arg_lit0("bB", "keyb", "use key B (by default keyA)."), - arg_lit0("pP", "plain", "plain communication between reader and card."), + arg_lit0("pP", "plain", "plain communication mode between reader and card."), arg_int1(NULL, NULL, "", NULL), arg_str0(NULL, NULL, "", NULL), arg_param_end @@ -545,7 +558,7 @@ int CmdHFMFPRdsc(const char *cmd) { bool verbose = arg_get_lit(1); bool keyB = arg_get_lit(2); - bool plain = arg_get_lit(3) | true; + bool plain = arg_get_lit(3); uint32_t sectorNum = arg_get_int(4); CLIGetHexWithReturn(5, key, &keylen); CLIParserFree(); @@ -604,7 +617,7 @@ int CmdHFMFPRdsc(const char *cmd) { PrintAndLog("data[%03d]: %s", n, sprint_hex(&data[1], 16)); - if (!memcmp(&data[1 + 16], mac, 8)) { + if (memcmp(&data[1 + 16], mac, 8)) { PrintAndLog("WARNING: mac on block %d not equal...", n); PrintAndLog("MAC card: %s", sprint_hex(&data[1 + 16], 8)); PrintAndLog("MAC reader: %s", sprint_hex(mac, 8)); @@ -706,7 +719,7 @@ int CmdHFMFPWrbl(const char *cmd) { return 6; } - if (!memcmp(&data[1], mac, 8)) { + if (memcmp(&data[1], mac, 8)) { PrintAndLog("WARNING: mac not equal..."); PrintAndLog("MAC card: %s", sprint_hex(&data[1], 8)); PrintAndLog("MAC reader: %s", sprint_hex(mac, 8)); @@ -716,6 +729,7 @@ int CmdHFMFPWrbl(const char *cmd) { } DropField(); + PrintAndLog("Write OK."); return 0; } @@ -729,7 +743,7 @@ static command_t CommandTable[] = {"auth", CmdHFMFPAuth, 0, "Authentication"}, {"rdbl", CmdHFMFPRdbl, 0, "Read blocks"}, {"rdsc", CmdHFMFPRdsc, 0, "Read sectors"}, -// {"wrbl", CmdHFMFPWrbl, 0, "Write blocks"}, + {"wrbl", CmdHFMFPWrbl, 0, "Write blocks"}, {NULL, NULL, 0, NULL} }; diff --git a/client/mifare4.c b/client/mifare4.c index e1021196..866e854f 100644 --- a/client/mifare4.c +++ b/client/mifare4.c @@ -1,5 +1,6 @@ //----------------------------------------------------------------------------- // Copyright (C) 2018 Merlok +// Copyright (C) 2018 drHatson // // 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 @@ -16,24 +17,85 @@ #include "ui.h" #include "polarssl/libpcrypto.h" -int CalculateMAC(mf4Session *session, uint8_t *data, int datalen, uint8_t *mac, bool verbose) { - if (!session || !session->Authenticated || !mac || !data || !datalen) +int CalculateEncIVCommand(mf4Session *session, uint8_t *iv, bool verbose) { + memcpy(&iv[0], session->TI, 4); + memcpy(&iv[4], &session->R_Ctr, 2); + memcpy(&iv[6], &session->W_Ctr, 2); + memcpy(&iv[8], &session->R_Ctr, 2); + memcpy(&iv[10], &session->W_Ctr, 2); + memcpy(&iv[12], &session->R_Ctr, 2); + memcpy(&iv[14], &session->W_Ctr, 2); + + return 0; +} + +int CalculateEncIVResponse(mf4Session *session, uint8_t *iv, bool verbose) { + memcpy(&iv[0], &session->R_Ctr, 2); + memcpy(&iv[2], &session->W_Ctr, 2); + memcpy(&iv[4], &session->R_Ctr, 2); + memcpy(&iv[6], &session->W_Ctr, 2); + memcpy(&iv[8], &session->R_Ctr, 2); + memcpy(&iv[10], &session->W_Ctr, 2); + memcpy(&iv[12], session->TI, 4); + + return 0; +} + + +int CalculateMAC(mf4Session *session, MACType_t mtype, uint8_t blockNum, uint8_t blockCount, uint8_t *data, int datalen, uint8_t *mac, bool verbose) { + if (!session || !session->Authenticated || !mac || !data || !datalen || datalen < 1) return 1; memset(mac, 0x00, 8); + + uint16_t ctr = session->R_Ctr; + switch(mtype) { + case mtypWriteCmd: + case mtypWriteResp: + ctr = session->W_Ctr; + break; + case mtypReadCmd: + case mtypReadResp: + break; + } + + uint8_t macdata[2049] = {data[0], (ctr & 0xFF), (ctr >> 8), 0}; + int macdatalen = datalen; + memcpy(&macdata[3], session->TI, 4); + + switch(mtype) { + case mtypReadCmd: + memcpy(&macdata[7], &data[1], datalen - 1); + macdatalen = datalen + 6; + break; + case mtypReadResp: + macdata[7] = blockNum; + macdata[8] = 0; + macdata[9] = blockCount; + memcpy(&macdata[10], &data[1], datalen - 1); + macdatalen = datalen + 9; + break; + case mtypWriteCmd: + memcpy(&macdata[7], &data[1], datalen - 1); + macdatalen = datalen + 6; + break; + case mtypWriteResp: + macdatalen = 1 + 6; + break; + } if (verbose) - PrintAndLog("MAC data[%d]: %s", datalen, sprint_hex(data, datalen)); + PrintAndLog("MAC data[%d]: %s", macdatalen, sprint_hex(macdata, macdatalen)); - return aes_cmac8(NULL, session->Key, data, mac, datalen); + return aes_cmac8(NULL, session->Kmac, macdata, mac, macdatalen); } int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool verbose) { uint8_t data[257] = {0}; int datalen = 0; - uint8_t Rnd1[17] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00}; - uint8_t Rnd2[17] = {0}; + uint8_t RndA[17] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00}; + uint8_t RndB[17] = {0}; if (session) session->Authenticated = false; @@ -67,17 +129,17 @@ int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateF return 3; } - aes_decode(NULL, key, &data[1], Rnd2, 16); - Rnd2[16] = Rnd2[0]; + aes_decode(NULL, key, &data[1], RndB, 16); + RndB[16] = RndB[0]; if (verbose) - PrintAndLog("Rnd2: %s", sprint_hex(Rnd2, 16)); + PrintAndLog("RndB: %s", sprint_hex(RndB, 16)); uint8_t cmd2[33] = {0}; cmd2[0] = 0x72; uint8_t raw[32] = {0}; - memmove(raw, Rnd1, 16); - memmove(&raw[16], &Rnd2[1], 16); + memmove(raw, RndA, 16); + memmove(&raw[16], &RndB[1], 16); aes_encode(NULL, key, raw, &cmd2[1], 32); if (verbose) @@ -97,19 +159,49 @@ int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateF if (verbose) { PrintAndLog("res: %s", sprint_hex(raw, 32)); - PrintAndLog("Rnd1`: %s", sprint_hex(&raw[4], 16)); + PrintAndLog("RndA`: %s", sprint_hex(&raw[4], 16)); } - if (memcmp(&raw[4], &Rnd1[1], 16)) { + if (memcmp(&raw[4], &RndA[1], 16)) { PrintAndLog("\nERROR: Authentication FAILED. rnd not equal"); if (verbose) { - PrintAndLog("rnd1 reader: %s", sprint_hex(&Rnd1[1], 16)); - PrintAndLog("rnd1 card: %s", sprint_hex(&raw[4], 16)); + PrintAndLog("RndA reader: %s", sprint_hex(&RndA[1], 16)); + PrintAndLog("RndA card: %s", sprint_hex(&raw[4], 16)); } DropField(); return 5; } + if (verbose) { + PrintAndLog(" TI: %s", sprint_hex(raw, 4)); + PrintAndLog("pic: %s", sprint_hex(&raw[20], 6)); + PrintAndLog("pcd: %s", sprint_hex(&raw[26], 6)); + } + + uint8_t kenc[16] = {0}; + memcpy(&kenc[0], &RndA[11], 5); + memcpy(&kenc[5], &RndB[11], 5); + for(int i = 0; i < 5; i++) + kenc[10 + i] = RndA[4 + i] ^ RndB[4 + i]; + kenc[15] = 0x11; + + aes_encode(NULL, key, kenc, kenc, 16); + if (verbose) { + PrintAndLog("kenc: %s", sprint_hex(kenc, 16)); + } + + uint8_t kmac[16] = {0}; + memcpy(&kmac[0], &RndA[7], 5); + memcpy(&kmac[5], &RndB[7], 5); + for(int i = 0; i < 5; i++) + kmac[10 + i] = RndA[0 + i] ^ RndB[0 + i]; + kmac[15] = 0x22; + + aes_encode(NULL, key, kmac, kmac, 16); + if (verbose) { + PrintAndLog("kmac: %s", sprint_hex(kmac, 16)); + } + if (!leaveSignalON) DropField(); @@ -118,10 +210,17 @@ int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateF if (session) { session->Authenticated = true; + session->R_Ctr = 0; + session->W_Ctr = 0; session->KeyNum = keyn[1] + (keyn[0] << 8); - memmove(session->Rnd1, Rnd1, 16); - memmove(session->Rnd2, Rnd2, 16); + memmove(session->RndA, RndA, 16); + memmove(session->RndB, RndB, 16); memmove(session->Key, key, 16); + memmove(session->TI, raw, 4); + memmove(session->PICCap2, &raw[20], 6); + memmove(session->PCDCap2, &raw[26], 6); + memmove(session->Kenc, kenc, 16); + memmove(session->Kmac, kmac, 16); } PrintAndLog("Authentication OK"); diff --git a/client/mifare4.h b/client/mifare4.h index 5b789a70..2453797b 100644 --- a/client/mifare4.h +++ b/client/mifare4.h @@ -1,5 +1,6 @@ //----------------------------------------------------------------------------- // Copyright (C) 2018 Merlok +// Copyright (C) 2018 drHatson // // 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 @@ -19,12 +20,25 @@ typedef struct { bool Authenticated; uint8_t Key[16]; uint16_t KeyNum; - uint8_t Rnd1[16]; - uint8_t Rnd2[16]; - + uint8_t RndA[16]; + uint8_t RndB[16]; + uint8_t TI[4]; + uint8_t PICCap2[6]; + uint8_t PCDCap2[6]; + uint8_t Kenc[16]; + uint8_t Kmac[16]; + uint16_t R_Ctr; + uint16_t W_Ctr; }mf4Session; -extern int CalculateMAC(mf4Session *session, uint8_t *data, int datalen, uint8_t *mac, bool verbose); +typedef enum { + mtypReadCmd, + mtypReadResp, + mtypWriteCmd, + mtypWriteResp, +} MACType_t; + +extern int CalculateMAC(mf4Session *session, MACType_t mtype, uint8_t blockNum, uint8_t blockCount, uint8_t *data, int datalen, uint8_t *mac, bool verbose); extern int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool verbose); extern uint8_t mfNumBlocksPerSector(uint8_t sectorNo); diff --git a/common/polarssl/libpcrypto.c b/common/polarssl/libpcrypto.c index 9be9fd26..13e37f00 100644 --- a/common/polarssl/libpcrypto.c +++ b/common/polarssl/libpcrypto.c @@ -1,5 +1,6 @@ //----------------------------------------------------------------------------- // Copyright (C) 2018 Merlok +// Copyright (C) 2018 drHatson // // 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 @@ -45,7 +46,7 @@ int aes_decode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int l return 0; } -// NIST Special Publication 800-38B — Recommendation for block cipher modes of operation: The CMAC mode for authentication. +// NIST Special Publication 800-38B — Recommendation for block cipher modes of operation: The CMAC mode for authentication. // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/AES_CMAC.pdf int aes_cmac(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, int length) { memset(mac, 0x00, 16); @@ -53,16 +54,10 @@ int aes_cmac(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, int length if (iv) memcpy(iiv, iv, 16); - // padding: ISO/IEC 9797-1 Message Authentication Codes (MACs) - Part 1: Mechanisms using a block cipher - uint8_t data[2049] = {0}; // length + 16 - memcpy(data, input, length); - data[length] = 0x80; - int datalen = (length & 0xfffffff0) + 0x10; - // NIST 800-38B aes_cmac128_context ctx; aes_cmac128_starts(&ctx, key); - aes_cmac128_update(&ctx, data, datalen); + aes_cmac128_update(&ctx, input, length); aes_cmac128_final(&ctx, mac); return 0; From 6eeb5f1c29d33848c6a71703d02c8465237c7e7e Mon Sep 17 00:00:00 2001 From: Oleg Moiseenko <807634+merlokk@users.noreply.github.com> Date: Wed, 31 Oct 2018 20:47:37 +0200 Subject: [PATCH 013/189] fix warning under linux (#709) --- armsrc/iso15693.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 50432392..04f43825 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -862,7 +862,7 @@ static int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint3 uint8_t dmaBuf[ISO15693_DMA_BUFFER_SIZE]; // the decoder data structure - DecodeReader_t DecodeReader; + DecodeReader_t DecodeReader = {0}; DecodeReaderInit(received, max_len, &DecodeReader); // wait for last transfer to complete From bdf96aae39d6df270de7f6f58dc034e35434d933 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Wed, 31 Oct 2018 22:00:36 +0100 Subject: [PATCH 014/189] fix hf 15 reader (merge error) --- armsrc/iso15693.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 04f43825..da2aab69 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -175,6 +175,8 @@ static void CodeIso15693AsReader(uint8_t *cmd, int n) for(i = 0; i < 4; i++) { ToSendStuffBit(1); } + + ToSendMax++; } // encode data using "1 out of 256" scheme From 14290308542a40adb5df5542ff035c3f3e5c5462 Mon Sep 17 00:00:00 2001 From: Oleg Moiseenko <807634+merlokk@users.noreply.github.com> Date: Sat, 17 Nov 2018 19:04:25 +0200 Subject: [PATCH 015/189] fix get length in tlv (#714) --- client/emv/tlv.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/client/emv/tlv.c b/client/emv/tlv.c index 540c33e4..35bdb5d4 100644 --- a/client/emv/tlv.c +++ b/client/emv/tlv.c @@ -92,16 +92,15 @@ static size_t tlv_parse_len(const unsigned char **buf, size_t *len) return l; size_t ll = l &~ TLV_LEN_LONG; - if (*len < ll) + if (ll > 5) return TLV_LEN_INVALID; - /* FIXME */ - if (ll != 1) - return TLV_LEN_INVALID; - - l = **buf; - --*len; - ++*buf; + l = 0; + for (int i = 1; i <= ll; i++) { + l = (l << 8) + **buf; + --*len; + ++*buf; + } return l; } From 8fa68384769d5d241bac693ac86ff03dbdc6a81d Mon Sep 17 00:00:00 2001 From: Oleg Moiseenko <807634+merlokk@users.noreply.github.com> Date: Sat, 17 Nov 2018 19:04:56 +0200 Subject: [PATCH 016/189] fix - some card cant reset so quick. (#713) --- client/emv/emvcore.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index f9dd0cbe..98ecc5b0 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -10,6 +10,7 @@ #include "emvcore.h" #include "emvjson.h" +#include "util_posix.h" // Got from here. Thanks) // https://eftlab.co.uk/index.php/site-map/knowledge-base/211-emv-aid-rid-pix @@ -236,8 +237,10 @@ int EMVExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool Includ if (sw) *sw = 0; uint16_t isw = 0; - if (ActivateField) + if (ActivateField){ DropField(); + msleep(50); + } // COMPUTE APDU memcpy(data, &apdu, 5); From 39cc1c879e3d75b3cafd79e4e139a7f6673dd349 Mon Sep 17 00:00:00 2001 From: Oleg Moiseenko <807634+merlokk@users.noreply.github.com> Date: Sat, 17 Nov 2018 20:22:21 +0200 Subject: [PATCH 017/189] FIDO U2F NFC authenticators (#697) * `hf fido` command * detects FIDO tag * add new commands for fido u2f * added changelog * added fido2 info --- CHANGELOG.md | 2 + armsrc/epa.c | 2 +- armsrc/iso14443a.c | 29 ++- armsrc/iso14443a.h | 2 +- client/Makefile | 1 + client/cmdhf.c | 2 + client/cmdhf14a.c | 64 +++-- client/cmdhffido.c | 550 +++++++++++++++++++++++++++++++++++++++++++ client/cmdhffido.h | 27 +++ client/emv/emvcore.c | 11 +- client/emv/emvcore.h | 4 + client/emv/emvjson.c | 36 ++- client/emv/emvjson.h | 5 + client/util.c | 4 +- 14 files changed, 704 insertions(+), 35 deletions(-) create mode 100644 client/cmdhffido.c create mode 100644 client/cmdhffido.h diff --git a/CHANGELOG.md b/CHANGELOG.md index 7781935e..6b134562 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,9 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ### Fixed ### Added +- Added `hf emv scan` - commands for scan EMV card and dump data to json file (Merlok) - `hf mfp` group of commands (Merlok) +- Added `hf fido` - FIDO U2F authenticator commands https://fidoalliance.org/ (Merlok) ## [v3.1.0][2018-10-10] diff --git a/armsrc/epa.c b/armsrc/epa.c index fd71430b..01aff302 100644 --- a/armsrc/epa.c +++ b/armsrc/epa.c @@ -116,7 +116,7 @@ int EPA_APDU(uint8_t *apdu, size_t length, uint8_t *response) switch(iso_type) { case 'a': - return iso14_apdu(apdu, (uint16_t) length, response); + return iso14_apdu(apdu, (uint16_t) length, response, NULL); break; case 'b': return iso14443b_apdu(apdu, length, response); diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 059db71e..7bf8f5af 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -1935,15 +1935,21 @@ b8 b7 b6 b5 b4 b3 b2 b1 b5,b6 = 00 - DESELECT 11 - WTX */ -int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data) { +int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data, uint8_t *res) { uint8_t parity[MAX_PARITY_SIZE]; uint8_t real_cmd[cmd_len + 4]; - // ISO 14443 APDU frame: PCB [CID] [NAD] APDU CRC PCB=0x02 - real_cmd[0] = 0x02; // bnr,nad,cid,chn=0; i-block(0x00) - // put block number into the PCB - real_cmd[0] |= iso14_pcb_blocknum; - memcpy(real_cmd + 1, cmd, cmd_len); + if (cmd_len) { + // ISO 14443 APDU frame: PCB [CID] [NAD] APDU CRC PCB=0x02 + real_cmd[0] = 0x02; // bnr,nad,cid,chn=0; i-block(0x00) + // put block number into the PCB + real_cmd[0] |= iso14_pcb_blocknum; + memcpy(real_cmd + 1, cmd, cmd_len); + } else { + // R-block. ACK + real_cmd[0] = 0xA2; // r-block + ACK + real_cmd[0] |= iso14_pcb_blocknum; + } AppendCrc14443a(real_cmd, cmd_len + 1); ReaderTransmit(real_cmd, cmd_len + 3, NULL); @@ -1982,9 +1988,13 @@ int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data) { { iso14_pcb_blocknum ^= 1; } + + // if we received I-block with chaining we need to send ACK and receive another block of data + if (res) + *res = data_bytes[0]; // crc check - if (len >=3 && !CheckCrc14443(CRC_14443_A, data_bytes, len)) { + if (len >= 3 && !CheckCrc14443(CRC_14443_A, data_bytes, len)) { return -1; } @@ -2050,9 +2060,10 @@ void ReaderIso14443a(UsbCommand *c) } if(param & ISO14A_APDU && !cantSELECT) { - arg0 = iso14_apdu(cmd, len, buf); + uint8_t res; + arg0 = iso14_apdu(cmd, len, buf, &res); LED_B_ON(); - cmd_send(CMD_ACK, arg0, 0, 0, buf, sizeof(buf)); + cmd_send(CMD_ACK, arg0, res, 0, buf, sizeof(buf)); LED_B_OFF(); } diff --git a/armsrc/iso14443a.h b/armsrc/iso14443a.h index 8796edf5..396b2100 100644 --- a/armsrc/iso14443a.h +++ b/armsrc/iso14443a.h @@ -49,7 +49,7 @@ extern int EmSendPrecompiledCmd(tag_response_info_t *response_info); extern bool prepare_allocated_tag_modulation(tag_response_info_t *response_info, uint8_t **buffer, size_t *buffer_size); extern void iso14443a_setup(uint8_t fpga_minor_mode); -extern int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data); +extern int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data, uint8_t *res); extern int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *resp_data, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats); extern void iso14a_set_trigger(bool enable); extern void iso14a_set_timeout(uint32_t timeout); diff --git a/client/Makefile b/client/Makefile index 1b211d4f..969eb241 100644 --- a/client/Makefile +++ b/client/Makefile @@ -164,6 +164,7 @@ CMDSRCS = $(SRC_SMARTCARD) \ cmdhfmfhard.c \ hardnested/hardnested_bruteforce.c \ cmdhftopaz.c \ + cmdhffido.c \ cmdhw.c \ cmdlf.c \ cmdlfawid.c \ diff --git a/client/cmdhf.c b/client/cmdhf.c index 762cc791..d2201800 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -34,6 +34,7 @@ #include "protocols.h" #include "emv/cmdemv.h" #include "cmdhflist.h" +#include "cmdhffido.h" static int CmdHelp(const char *Cmd); @@ -598,6 +599,7 @@ static command_t CommandTable[] = {"mfu", CmdHFMFUltra, 1, "{ MIFARE Ultralight RFIDs... }"}, {"mfp", CmdHFMFP, 1, "{ MIFARE Plus RFIDs... }"}, {"topaz", CmdHFTopaz, 1, "{ TOPAZ (NFC Type 1) RFIDs... }"}, + {"fido", CmdHFFido, 1, "{ FIDO and FIDO2 authenticators... }"}, {"tune", CmdHFTune, 0, "Continuously measure HF antenna tuning"}, {"list", CmdHFList, 1, "List protocol data in trace buffer"}, {"search", CmdHFSearch, 1, "Search for known HF tags [preliminary]"}, diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 326eaf50..922a9449 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -786,20 +786,20 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav return 0; } -int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { +int CmdExchangeAPDU(uint8_t *datain, int datainlen, bool activateField, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool *chaining) { uint16_t cmdc = 0; + + *chaining = false; if (activateField) { cmdc |= ISO14A_CONNECT | ISO14A_CLEAR_TRACE; } - if (leaveSignalON) - cmdc |= ISO14A_NO_DISCONNECT; // "Command APDU" length should be 5+255+1, but javacard's APDU buffer might be smaller - 133 bytes // https://stackoverflow.com/questions/32994936/safe-max-java-card-apdu-data-command-and-respond-size // here length USB_CMD_DATA_SIZE=512 // timeout must be authomatically set by "get ATS" - UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_APDU | cmdc, (datainlen & 0xFFFF), 0}}; + UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_APDU | ISO14A_NO_DISCONNECT | cmdc, (datainlen & 0xFFFF), 0}}; memcpy(c.d.asBytes, datain, datainlen); SendCommand(&c); @@ -813,6 +813,7 @@ int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool lea } if (resp.arg[0] != 1) { PrintAndLog("APDU ERROR: Proxmark error %d.", resp.arg[0]); + DropField(); return 1; } } @@ -820,45 +821,76 @@ int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool lea if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { recv = resp.d.asBytes; int iLen = resp.arg[0]; + uint8_t res = resp.arg[1]; - *dataoutlen = iLen - 2; - if (*dataoutlen < 0) - *dataoutlen = 0; + int dlen = iLen - 2; + if (dlen < 0) + dlen = 0; + *dataoutlen += dlen; if (maxdataoutlen && *dataoutlen > maxdataoutlen) { PrintAndLog("APDU ERROR: Buffer too small(%d). Needs %d bytes", *dataoutlen, maxdataoutlen); return 2; } - memcpy(dataout, recv, *dataoutlen); - if(!iLen) { PrintAndLog("APDU ERROR: No APDU response."); return 1; } + // check apdu length + if (iLen < 4 && iLen >= 0) { + PrintAndLog("APDU ERROR: Small APDU response. Len=%d", iLen); + return 2; + } + // check block TODO if (iLen == -2) { PrintAndLog("APDU ERROR: Block type mismatch."); return 2; } + + memcpy(dataout, recv, dlen); + + // chaining + if ((res & 0x10) != 0) { + *chaining = true; + } // CRC Check if (iLen == -1) { PrintAndLog("APDU ERROR: ISO 14443A CRC error."); return 3; } - - // check apdu length - if (iLen < 4) { - PrintAndLog("APDU ERROR: Small APDU response. Len=%d", iLen); - return 2; - } - } else { PrintAndLog("APDU ERROR: Reply timeout."); return 4; } + + return 0; +} + + +int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { + *dataoutlen = 0; + bool chaining = false; + + int res = CmdExchangeAPDU(datain, datainlen, activateField, dataout, maxdataoutlen, dataoutlen, &chaining); + + while (chaining) { + // I-block with chaining + res = CmdExchangeAPDU(NULL, 0, false, &dataout[*dataoutlen], maxdataoutlen, dataoutlen, &chaining); + + if (res) { + if (!leaveSignalON) + DropField(); + + return 100; + } + } + + if (!leaveSignalON) + DropField(); return 0; } diff --git a/client/cmdhffido.c b/client/cmdhffido.c new file mode 100644 index 00000000..fd97ace5 --- /dev/null +++ b/client/cmdhffido.c @@ -0,0 +1,550 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2018 Merlok +// +// 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 MIFARE Plus commands +//----------------------------------------------------------------------------- +// +// Documentation here: +// +// FIDO Alliance specifications +// https://fidoalliance.org/download/ +// FIDO NFC Protocol Specification v1.0 +// https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-nfc-protocol-v1.2-ps-20170411.html +// FIDO U2F Raw Message Formats +// https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html +//----------------------------------------------------------------------------- + + +#include "cmdhffido.h" + +#include +#include +#include +#include +#include +#include +#include +#include "comms.h" +#include "cmdmain.h" +#include "util.h" +#include "ui.h" +#include "proxmark3.h" +#include "cmdhf14a.h" +#include "mifare.h" +#include "emv/emvcore.h" +#include "emv/emvjson.h" +#include "emv/dump.h" +#include "cliparser/cliparser.h" + +static int CmdHelp(const char *Cmd); + +int FIDOSelect(bool ActivateField, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { + uint8_t data[] = {0xA0, 0x00, 0x00, 0x06, 0x47, 0x2F, 0x00, 0x01}; + + return EMVSelect(ActivateField, LeaveFieldON, data, sizeof(data), Result, MaxResultLen, ResultLen, sw, NULL); +} + +int FIDOExchange(sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { + int res = EMVExchange(true, apdu, Result, MaxResultLen, ResultLen, sw, NULL); + if (res == 5) // apdu result (sw) not a 0x9000 + res = 0; + // software chaining + while (!res && (*sw >> 8) == 0x61) { + size_t oldlen = *ResultLen; + res = EMVExchange(true, (sAPDU){0x00, 0xC0, 0x00, 0x00, 0x00, NULL}, &Result[oldlen], MaxResultLen - oldlen, ResultLen, sw, NULL); + if (res == 5) // apdu result (sw) not a 0x9000 + res = 0; + + *ResultLen += oldlen; + if (*ResultLen > MaxResultLen) + return 100; + } + return res; +} + +int FIDORegister(uint8_t *params, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { + return FIDOExchange((sAPDU){0x00, 0x01, 0x03, 0x00, 64, params}, Result, MaxResultLen, ResultLen, sw); +} + +int FIDOAuthentication(uint8_t *params, uint8_t paramslen, uint8_t controlb, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { + return FIDOExchange((sAPDU){0x00, 0x02, controlb, 0x00, paramslen, params}, Result, MaxResultLen, ResultLen, sw); +} + +int FIDO2GetInfo(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { + uint8_t data[] = {0x04}; + return FIDOExchange((sAPDU){0x80, 0x10, 0x00, 0x00, sizeof(data), data}, Result, MaxResultLen, ResultLen, sw); +} + +int CmdHFFidoInfo(const char *cmd) { + + if (cmd && strlen(cmd) > 0) + PrintAndLog("WARNING: command don't have any parameters.\n"); + + // info about 14a part + CmdHF14AInfo(""); + + // FIDO info + PrintAndLog("--------------------------------------------"); + SetAPDULogging(false); + + uint8_t buf[APDU_RES_LEN] = {0}; + size_t len = 0; + uint16_t sw = 0; + int res = FIDOSelect(true, true, buf, sizeof(buf), &len, &sw); + + if (res) { + DropField(); + return res; + } + + if (sw != 0x9000) { + if (sw) + PrintAndLog("Not a FIDO card! APDU response: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + else + PrintAndLog("APDU exchange error. Card returns 0x0000."); + + DropField(); + return 0; + } + + if (!strncmp((char *)buf, "U2F_V2", 7)) { + if (!strncmp((char *)buf, "FIDO_2_0", 8)) { + PrintAndLog("FIDO2 authenricator detected. Version: %.*s", len, buf); + } else { + PrintAndLog("FIDO authenricator detected (not standard U2F)."); + PrintAndLog("Non U2F authenticator version:"); + dump_buffer((const unsigned char *)buf, len, NULL, 0); + } + } else { + PrintAndLog("FIDO U2F authenricator detected. Version: %.*s", len, buf); + } + + res = FIDO2GetInfo(buf, sizeof(buf), &len, &sw); + DropField(); + if (res) { + return res; + } + if (sw != 0x9000) { + PrintAndLog("FIDO2 version not exists (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + + return 0; + } + + PrintAndLog("FIDO2 version: (%d)", len); + dump_buffer((const unsigned char *)buf, len, NULL, 0); + + return 0; +} + +json_t *OpenJson(int paramnum, char *fname, void* argtable[], bool *err) { + json_t *root = NULL; + json_error_t error; + *err = false; + + uint8_t jsonname[250] ={0}; + char *cjsonname = (char *)jsonname; + int jsonnamelen = 0; + + // CLIGetStrWithReturn(paramnum, jsonname, &jsonnamelen); + if (CLIParamStrToBuf(arg_get_str(paramnum), jsonname, sizeof(jsonname), &jsonnamelen)) { + CLIParserFree(); + return NULL; + } + + // current path + file name + if (!strstr(cjsonname, ".json")) + strcat(cjsonname, ".json"); + + if (jsonnamelen) { + strcpy(fname, get_my_executable_directory()); + strcat(fname, cjsonname); + if (access(fname, F_OK) != -1) { + root = json_load_file(fname, 0, &error); + if (!root) { + PrintAndLog("ERROR: json error on line %d: %s", error.line, error.text); + *err = true; + return NULL; + } + + if (!json_is_object(root)) { + PrintAndLog("ERROR: Invalid json format. root must be an object."); + json_decref(root); + *err = true; + return NULL; + } + + } else { + root = json_object(); + } + } + return root; +} + +int CmdHFFidoRegister(const char *cmd) { + uint8_t data[64] = {0}; + int chlen = 0; + uint8_t cdata[250] = {0}; + int applen = 0; + uint8_t adata[250] = {0}; + json_t *root = NULL; + + CLIParserInit("hf fido reg", + "Initiate a U2F token registration. Needs two 32-byte hash number. \nchallenge parameter (32b) and application parameter (32b).", + "Usage:\n\thf fido reg -> execute command with 2 parameters, filled 0x00\n" + "\thf fido reg 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f -> execute command with parameters" + "\thf fido reg -p s0 s1 -> execute command with plain parameters"); + + void* argtable[] = { + arg_param_begin, + arg_lit0("aA", "apdu", "show APDU reqests and responses"), + arg_lit0("vV", "verbose", "show technical data"), + arg_lit0("pP", "plain", "send plain ASCII to challenge and application parameters instead of HEX"), + arg_str0("jJ", "json", "fido.json", "JSON input / output file name for parameters."), + arg_str0(NULL, NULL, "", NULL), + arg_str0(NULL, NULL, "", NULL), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, true); + + bool APDULogging = arg_get_lit(1); + bool verbose = arg_get_lit(2); + bool paramsPlain = arg_get_lit(3); + + char fname[250] = {0}; + bool err; + root = OpenJson(4, fname, argtable, &err); + if(err) + return 1; + if (root) { + size_t jlen; + JsonLoadBufAsHex(root, "$.ChallengeParam", data, 32, &jlen); + JsonLoadBufAsHex(root, "$.ApplicationParam", &data[32], 32, &jlen); + } + + if (paramsPlain) { + memset(cdata, 0x00, 32); + CLIGetStrWithReturn(5, cdata, &chlen); + if (chlen && chlen > 16) { + PrintAndLog("ERROR: challenge parameter length in ASCII mode must be less than 16 chars instead of: %d", chlen); + return 1; + } + } else { + CLIGetHexWithReturn(5, cdata, &chlen); + if (chlen && chlen != 32) { + PrintAndLog("ERROR: challenge parameter length must be 32 bytes only."); + return 1; + } + } + if (chlen) + memmove(data, cdata, 32); + + + if (paramsPlain) { + memset(adata, 0x00, 32); + CLIGetStrWithReturn(6, adata, &applen); + if (applen && applen > 16) { + PrintAndLog("ERROR: application parameter length in ASCII mode must be less than 16 chars instead of: %d", applen); + return 1; + } + } else { + CLIGetHexWithReturn(6, adata, &applen); + if (applen && applen != 32) { + PrintAndLog("ERROR: application parameter length must be 32 bytes only."); + return 1; + } + } + if (applen) + memmove(&data[32], adata, 32); + + CLIParserFree(); + + SetAPDULogging(APDULogging); + + // challenge parameter [32 bytes] - The challenge parameter is the SHA-256 hash of the Client Data, a stringified JSON data structure that the FIDO Client prepares + // application parameter [32 bytes] - The application parameter is the SHA-256 hash of the UTF-8 encoding of the application identity + + uint8_t buf[2048] = {0}; + size_t len = 0; + uint16_t sw = 0; + + DropField(); + int res = FIDOSelect(true, true, buf, sizeof(buf), &len, &sw); + + if (res) { + PrintAndLog("Can't select authenticator. res=%x. Exit...", res); + DropField(); + return res; + } + + if (sw != 0x9000) { + PrintAndLog("Can't select FIDO application. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + DropField(); + return 2; + } + + res = FIDORegister(data, buf, sizeof(buf), &len, &sw); + DropField(); + if (res) { + PrintAndLog("Can't execute register command. res=%x. Exit...", res); + return res; + } + + if (sw != 0x9000) { + PrintAndLog("ERROR execute register command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + return 3; + } + + PrintAndLog(""); + if (APDULogging) + PrintAndLog("---------------------------------------------------------------"); + PrintAndLog("data len: %d", len); + if (verbose) { + PrintAndLog("--------------data----------------------"); + dump_buffer((const unsigned char *)buf, len, NULL, 0); + PrintAndLog("--------------data----------------------"); + } + + if (buf[0] != 0x05) { + PrintAndLog("ERROR: First byte must be 0x05, but it %2x", buf[0]); + return 5; + } + PrintAndLog("User public key: %s", sprint_hex(&buf[1], 65)); + + uint8_t keyHandleLen = buf[66]; + PrintAndLog("Key handle[%d]: %s", keyHandleLen, sprint_hex(&buf[67], keyHandleLen)); + + int derp = 67 + keyHandleLen; + int derLen = (buf[derp + 2] << 8) + buf[derp + 3] + 4; + // needs to decode DER certificate + if (verbose) { + PrintAndLog("DER certificate[%d]:------------------DER-------------------", derLen); + dump_buffer_simple((const unsigned char *)&buf[67 + keyHandleLen], derLen, NULL); + PrintAndLog("\n----------------DER---------------------"); + } else { + PrintAndLog("DER certificate[%d]: %s...", derLen, sprint_hex(&buf[derp], 20)); + } + + + int hashp = 1 + 65 + 1 + keyHandleLen + derLen; + PrintAndLog("Hash[%d]: %s", len - hashp, sprint_hex(&buf[hashp], len - hashp)); + + // check ANSI X9.62 format ECDSA signature (on P-256) + + PrintAndLog("\nauth command: "); + printf("hf fido auth %s%s", paramsPlain?"-p ":"", sprint_hex_inrow(&buf[67], keyHandleLen)); + if(chlen || applen) + printf(" %s", paramsPlain?(char *)cdata:sprint_hex_inrow(cdata, 32)); + if(applen) + printf(" %s", paramsPlain?(char *)adata:sprint_hex_inrow(adata, 32)); + printf("\n"); + + if (root) { + JsonSaveBufAsHex(root, "ChallengeParam", data, 32); + JsonSaveBufAsHex(root, "ApplicationParam", &data[32], 32); + JsonSaveInt(root, "KeyHandleLen", keyHandleLen); + JsonSaveBufAsHexCompact(root, "KeyHandle", &buf[67], keyHandleLen); + JsonSaveBufAsHexCompact(root, "DER", &buf[67 + keyHandleLen], derLen); + + res = json_dump_file(root, fname, JSON_INDENT(2)); + if (res) { + PrintAndLog("ERROR: can't save the file: %s", fname); + return 200; + } + PrintAndLog("File `%s` saved.", fname); + + // free json object + json_decref(root); + } + + return 0; +}; + +int CmdHFFidoAuthenticate(const char *cmd) { + uint8_t data[512] = {0}; + uint8_t hdata[250] = {0}; + int hdatalen = 0; + uint8_t keyHandleLen = 0; + json_t *root = NULL; + + CLIParserInit("hf fido auth", + "Initiate a U2F token authentication. Needs key handle and two 32-byte hash number. \nkey handle(var 0..255), challenge parameter (32b) and application parameter (32b).", + "Usage:\n\thf fido auth 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f -> execute command with 2 parameters, filled 0x00 and key handle\n" + "\thf fido auth 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f " + "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f 000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f -> execute command with parameters"); + + void* argtable[] = { + arg_param_begin, + arg_lit0("aA", "apdu", "show APDU reqests and responses"), + arg_lit0("vV", "verbose", "show technical data"), + arg_lit0("pP", "plain", "send plain ASCII to challenge and application parameters instead of HEX"), + arg_rem("default mode:", "dont-enforce-user-presence-and-sign"), + arg_lit0("uU", "user", "mode: enforce-user-presence-and-sign"), + arg_lit0("cC", "check", "mode: check-only"), + arg_str0("jJ", "json", "fido.json", "JSON input / output file name for parameters."), + arg_str0(NULL, NULL, "", NULL), + arg_str0(NULL, NULL, "", NULL), + arg_str0(NULL, NULL, "", NULL), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, true); + + bool APDULogging = arg_get_lit(1); + //bool verbose = arg_get_lit(2); + bool paramsPlain = arg_get_lit(3); + uint8_t controlByte = 0x08; + if (arg_get_lit(5)) + controlByte = 0x03; + if (arg_get_lit(6)) + controlByte = 0x07; + + char fname[250] = {0}; + bool err; + root = OpenJson(7, fname, argtable, &err); + if(err) + return 1; + if (root) { + size_t jlen; + JsonLoadBufAsHex(root, "$.ChallengeParam", data, 32, &jlen); + JsonLoadBufAsHex(root, "$.ApplicationParam", &data[32], 32, &jlen); + JsonLoadBufAsHex(root, "$.KeyHandle", &data[65], 512 - 67, &jlen); + keyHandleLen = jlen & 0xff; + data[64] = keyHandleLen; + } + + CLIGetHexWithReturn(8, hdata, &hdatalen); + if (hdatalen > 255) { + PrintAndLog("ERROR: application parameter length must be less than 255."); + return 1; + } + if (hdatalen) { + keyHandleLen = hdatalen; + data[64] = keyHandleLen; + memmove(&data[65], hdata, keyHandleLen); + } + + if (paramsPlain) { + memset(hdata, 0x00, 32); + CLIGetStrWithReturn(9, hdata, &hdatalen); + if (hdatalen && hdatalen > 16) { + PrintAndLog("ERROR: challenge parameter length in ASCII mode must be less than 16 chars instead of: %d", hdatalen); + return 1; + } + } else { + CLIGetHexWithReturn(9, hdata, &hdatalen); + if (hdatalen && hdatalen != 32) { + PrintAndLog("ERROR: challenge parameter length must be 32 bytes only."); + return 1; + } + } + if (hdatalen) + memmove(data, hdata, 32); + + if (paramsPlain) { + memset(hdata, 0x00, 32); + CLIGetStrWithReturn(10, hdata, &hdatalen); + if (hdatalen && hdatalen > 16) { + PrintAndLog("ERROR: application parameter length in ASCII mode must be less than 16 chars instead of: %d", hdatalen); + return 1; + } + } else { + CLIGetHexWithReturn(10, hdata, &hdatalen); + if (hdatalen && hdatalen != 32) { + PrintAndLog("ERROR: application parameter length must be 32 bytes only."); + return 1; + } + } + if (hdatalen) + memmove(&data[32], hdata, 32); + + CLIParserFree(); + + SetAPDULogging(APDULogging); + + // (in parameter) conrtol byte 0x07 - check only, 0x03 - user presense + cign. 0x08 - sign only + // challenge parameter [32 bytes] + // application parameter [32 bytes] + // key handle length [1b] = N + // key handle [N] + + uint8_t datalen = 32 + 32 + 1 + keyHandleLen; + + uint8_t buf[2048] = {0}; + size_t len = 0; + uint16_t sw = 0; + + DropField(); + int res = FIDOSelect(true, true, buf, sizeof(buf), &len, &sw); + + if (res) { + PrintAndLog("Can't select authenticator. res=%x. Exit...", res); + DropField(); + return res; + } + + if (sw != 0x9000) { + PrintAndLog("Can't select FIDO application. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + DropField(); + return 2; + } + + res = FIDOAuthentication(data, datalen, controlByte, buf, sizeof(buf), &len, &sw); + DropField(); + if (res) { + PrintAndLog("Can't execute authentication command. res=%x. Exit...", res); + return res; + } + + if (sw != 0x9000) { + PrintAndLog("ERROR execute authentication command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + return 3; + } + + PrintAndLog("---------------------------------------------------------------"); + PrintAndLog("User presence: %s", (buf[0]?"verified":"not verified")); + uint32_t cntr = (uint32_t)bytes_to_num(&buf[1], 4); + PrintAndLog("Counter: %d", cntr); + PrintAndLog("Hash[%d]: %s", len - 5, sprint_hex(&buf[5], len - 5)); + + if (root) { + JsonSaveBufAsHex(root, "ChallengeParam", data, 32); + JsonSaveBufAsHex(root, "ApplicationParam", &data[32], 32); + JsonSaveInt(root, "KeyHandleLen", keyHandleLen); + JsonSaveBufAsHexCompact(root, "KeyHandle", &data[65], keyHandleLen); + JsonSaveInt(root, "Counter", cntr); + + res = json_dump_file(root, fname, JSON_INDENT(2)); + if (res) { + PrintAndLog("ERROR: can't save the file: %s", fname); + return 200; + } + PrintAndLog("File `%s` saved.", fname); + + // free json object + json_decref(root); + } + return 0; +}; + +static command_t CommandTable[] = +{ + {"help", CmdHelp, 1, "This help."}, + {"info", CmdHFFidoInfo, 0, "Info about FIDO tag."}, + {"reg", CmdHFFidoRegister, 0, "FIDO U2F Registration Message."}, + {"auth", CmdHFFidoAuthenticate, 0, "FIDO U2F Authentication Message."}, + {NULL, NULL, 0, NULL} +}; + +int CmdHFFido(const char *Cmd) { + (void)WaitForResponseTimeout(CMD_ACK,NULL,100); + CmdsParse(CommandTable, Cmd); + return 0; +} + +int CmdHelp(const char *Cmd) { + CmdsHelp(CommandTable); + return 0; +} diff --git a/client/cmdhffido.h b/client/cmdhffido.h new file mode 100644 index 00000000..2460a170 --- /dev/null +++ b/client/cmdhffido.h @@ -0,0 +1,27 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2018 Merlok +// +// 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 FIDO U2F and FIDO2 contactless authenticators +//----------------------------------------------------------------------------- +// +// Documentation here: +// +// FIDO Alliance specifications +// https://fidoalliance.org/download/ +// FIDO NFC Protocol Specification v1.0 +// https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-nfc-protocol-v1.2-ps-20170411.html +// FIDO U2F Raw Message Formats +// https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html +//----------------------------------------------------------------------------- + +#ifndef CMDHFFIDO_H__ +#define CMDHFFIDO_H__ + +extern int CmdHFFido(const char *Cmd); + + +#endif \ No newline at end of file diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index 98ecc5b0..c1259114 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -266,9 +266,14 @@ int EMVExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool Includ *sw = isw; if (isw != 0x9000) { - if (APDULogging) - PrintAndLog("APDU(%02x%02x) ERROR: [%4X] %s", apdu.CLA, apdu.INS, isw, GetAPDUCodeDescription(*sw >> 8, *sw & 0xff)); - return 5; + if (APDULogging) { + if (*sw >> 8 == 0x61) { + PrintAndLog("APDU chaining len:%02x -->", *sw & 0xff); + } else { + PrintAndLog("APDU(%02x%02x) ERROR: [%4X] %s", apdu.CLA, apdu.INS, isw, GetAPDUCodeDescription(*sw >> 8, *sw & 0xff)); + return 5; + } + } } // add to tlv tree diff --git a/client/emv/emvcore.h b/client/emv/emvcore.h index ece7324a..fa7a4db8 100644 --- a/client/emv/emvcore.h +++ b/client/emv/emvcore.h @@ -70,6 +70,10 @@ extern struct tlvdb *GetdCVVRawFromTrack2(const struct tlv *track2); extern void SetAPDULogging(bool logging); +// exchange +extern int EMVExchange(bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); + + // search application extern int EMVSearchPSE(bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv); extern int EMVSearch(bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv); diff --git a/client/emv/emvjson.c b/client/emv/emvjson.c index 02297435..e56ecbb7 100644 --- a/client/emv/emvjson.c +++ b/client/emv/emvjson.c @@ -68,24 +68,40 @@ char* GetApplicationDataName(tlv_tag_t tag) { return NULL; } -int JsonSaveStr(json_t *root, char *path, char *value) { +int JsonSaveJsonObject(json_t *root, char *path, json_t *value) { json_error_t error; if (strlen(path) < 1) return 1; if (path[0] == '$') { - if (json_path_set(root, path, json_string(value), 0, &error)) { + 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, json_string(value)); + return json_object_set_new(root, path, value); } +} + +int JsonSaveInt(json_t *root, char *path, int value) { + return JsonSaveJsonObject(root, path, json_integer(value)); +} + +int JsonSaveStr(json_t *root, char *path, char *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'; + + 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] == ' ') @@ -248,6 +264,20 @@ bool HexToBuffer(const char *errormsg, const char *hexvalue, uint8_t * buffer, s return true; } +int JsonLoadBufAsHex(json_t *elm, char *path, uint8_t *data, size_t maxbufferlen, size_t *datalen) { + if (datalen) + *datalen = 0; + + 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; + + return 0; +}; + bool ParamLoadFromJson(struct tlvdb *tlv) { json_t *root; json_error_t error; diff --git a/client/emv/emvjson.h b/client/emv/emvjson.h index a518d7b9..9c6eda5e 100644 --- a/client/emv/emvjson.h +++ b/client/emv/emvjson.h @@ -20,7 +20,10 @@ typedef struct { extern char* GetApplicationDataName(tlv_tag_t tag); +extern int JsonSaveJsonObject(json_t *root, char *path, json_t *value); extern int JsonSaveStr(json_t *root, char *path, char *value); +extern int JsonSaveInt(json_t *root, char *path, int value); +extern int JsonSaveBufAsHexCompact(json_t *elm, char *path, uint8_t *data, size_t datalen); extern int JsonSaveBufAsHex(json_t *elm, char *path, uint8_t *data, size_t datalen); extern int JsonSaveHex(json_t *elm, char *path, uint64_t data, int datalen); @@ -30,6 +33,8 @@ extern int JsonSaveTLVTreeElm(json_t *elm, char *path, struct tlvdb *tlvdbelm, b extern int JsonSaveTLVTree(json_t *root, json_t *elm, char *path, struct tlvdb *tlvdbelm); +extern int JsonLoadBufAsHex(json_t *elm, char *path, uint8_t *data, size_t maxbufferlen, size_t *datalen); + extern bool ParamLoadFromJson(struct tlvdb *tlv); #endif \ No newline at end of file diff --git a/client/util.c b/client/util.c index d7c824d9..c6d5f0d6 100644 --- a/client/util.c +++ b/client/util.c @@ -139,7 +139,7 @@ void hex_to_buffer(const uint8_t *buf, const uint8_t *hex_data, const size_t hex // printing and converting functions char *sprint_hex(const uint8_t *data, const size_t len) { - static char buf[1025] = {0}; + static char buf[4097] = {0}; hex_to_buffer((uint8_t *)buf, data, len, sizeof(buf) - 1, 0, 1, false); @@ -147,7 +147,7 @@ char *sprint_hex(const uint8_t *data, const size_t len) { } char *sprint_hex_inrow_ex(const uint8_t *data, const size_t len, const size_t min_str_len) { - static char buf[1025] = {0}; + static char buf[4097] = {0}; hex_to_buffer((uint8_t *)buf, data, len, sizeof(buf) - 1, min_str_len, 0, false); From 700d8687944db0a48535f818b59b6c9859952c61 Mon Sep 17 00:00:00 2001 From: Oleg Moiseenko <807634+merlokk@users.noreply.github.com> Date: Mon, 19 Nov 2018 10:02:38 +0200 Subject: [PATCH 018/189] move from polarssl to mbedtls (#708) * update polarssl to mbedtls * fix a warning in armsrc/iso15693 * added random generator and ecdsa test * added signature check to test * move crypto lib to client directory --- .travis.yml | 55 + client/Makefile | 23 +- client/cmdhfmfp.c | 2 +- client/cmdhfmfu.c | 16 +- client/crypto/asn1utils.c | 63 + client/crypto/asn1utils.h | 21 + client/crypto/libpcrypto.c | 381 ++ .../polarssl => client/crypto}/libpcrypto.h | 10 + client/emv/crypto_polarssl.c | 63 +- client/emv/test/cryptotest.c | 56 +- client/mifare4.c | 2 +- client/obj/crypto/.dummy | 0 client/scripting.c | 38 +- common/mbedtls/Makefile | 86 + common/mbedtls/aes.c | 2125 +++++++++++ common/mbedtls/aes.h | 628 ++++ common/mbedtls/arc4.c | 203 ++ common/mbedtls/arc4.h | 143 + common/mbedtls/asn1.h | 360 ++ common/mbedtls/asn1parse.c | 391 ++ common/mbedtls/asn1write.c | 392 +++ common/mbedtls/asn1write.h | 242 ++ common/mbedtls/base64.c | 295 ++ common/mbedtls/base64.h | 91 + common/mbedtls/bignum.c | 2470 +++++++++++++ common/mbedtls/bignum.h | 774 ++++ common/mbedtls/blowfish.c | 654 ++++ common/mbedtls/blowfish.h | 246 ++ common/mbedtls/bn_mul.h | 895 +++++ common/mbedtls/camellia.c | 1070 ++++++ common/mbedtls/camellia.h | 273 ++ common/mbedtls/certs.c | 405 +++ common/mbedtls/certs.h | 102 + common/mbedtls/check_config.h | 685 ++++ common/mbedtls/cipher.c | 1108 ++++++ common/mbedtls/cipher.h | 808 +++++ common/mbedtls/cipher_internal.h | 127 + common/mbedtls/cipher_wrap.c | 2274 ++++++++++++ common/mbedtls/cmac.c | 1080 ++++++ common/mbedtls/cmac.h | 208 ++ common/mbedtls/config.h | 3129 +++++++++++++++++ common/mbedtls/ctr_drbg.c | 652 ++++ common/mbedtls/ctr_drbg.h | 332 ++ common/mbedtls/des.c | 1059 ++++++ common/mbedtls/des.h | 352 ++ common/mbedtls/ecdsa.c | 463 +++ common/mbedtls/ecdsa.h | 341 ++ common/mbedtls/ecp.c | 2209 ++++++++++++ common/mbedtls/ecp.h | 766 ++++ common/mbedtls/ecp_curves.c | 1462 ++++++++ common/mbedtls/ecp_internal.h | 295 ++ common/mbedtls/entropy.c | 723 ++++ common/mbedtls/entropy.h | 291 ++ common/mbedtls/entropy_poll.c | 277 ++ common/mbedtls/entropy_poll.h | 112 + common/mbedtls/error.c | 897 +++++ common/mbedtls/error.h | 124 + common/mbedtls/md.c | 477 +++ common/mbedtls/md.h | 468 +++ common/mbedtls/md5.c | 497 +++ common/mbedtls/md5.h | 308 ++ common/mbedtls/md_internal.h | 117 + common/mbedtls/md_wrap.c | 588 ++++ common/mbedtls/oid.c | 757 ++++ common/mbedtls/oid.h | 607 ++++ common/mbedtls/pem.c | 490 +++ common/mbedtls/pem.h | 132 + common/mbedtls/pk.c | 381 ++ common/mbedtls/pk.h | 620 ++++ common/mbedtls/pk_internal.h | 117 + common/mbedtls/pk_wrap.c | 525 +++ common/mbedtls/pkcs12.c | 363 ++ common/mbedtls/pkcs12.h | 122 + common/mbedtls/pkcs5.c | 428 +++ common/mbedtls/pkcs5.h | 97 + common/mbedtls/pkparse.c | 1449 ++++++++ common/mbedtls/platform.c | 341 ++ common/mbedtls/platform.h | 366 ++ common/mbedtls/platform_util.c | 69 + common/mbedtls/platform_util.h | 64 + common/mbedtls/rsa.c | 2400 +++++++++++++ common/mbedtls/rsa.h | 1133 ++++++ common/mbedtls/rsa_internal.c | 489 +++ common/mbedtls/rsa_internal.h | 228 ++ common/{polarssl => mbedtls}/sha1.c | 479 ++- common/mbedtls/sha1.h | 326 ++ common/mbedtls/sha256.c | 562 +++ common/mbedtls/sha256.h | 274 ++ common/mbedtls/sha512.c | 612 ++++ common/mbedtls/sha512.h | 272 ++ common/mbedtls/threading.c | 142 + common/mbedtls/threading.h | 110 + common/mbedtls/timing.c | 547 +++ common/mbedtls/timing.h | 155 + common/mbedtls/x509.c | 1073 ++++++ common/mbedtls/x509.h | 335 ++ common/mbedtls/x509_crl.c | 775 ++++ common/mbedtls/x509_crl.h | 176 + common/mbedtls/x509_crt.c | 2488 +++++++++++++ common/mbedtls/x509_crt.h | 672 ++++ common/polarssl/aes.c | 1454 -------- common/polarssl/aes.h | 256 -- common/polarssl/aes_cmac128.c | 322 -- common/polarssl/aes_cmac128.h | 81 - common/polarssl/bignum.c | 2143 ----------- common/polarssl/bignum.h | 685 ---- common/polarssl/bn_mul.h | 864 ----- common/polarssl/libpcrypto.c | 78 - common/polarssl/rsa.c | 1466 -------- common/polarssl/rsa.h | 597 ---- common/polarssl/sha1.h | 180 - travis_test_commands.scr | 3 + 112 files changed, 54624 insertions(+), 8485 deletions(-) create mode 100644 .travis.yml create mode 100644 client/crypto/asn1utils.c create mode 100644 client/crypto/asn1utils.h create mode 100644 client/crypto/libpcrypto.c rename {common/polarssl => client/crypto}/libpcrypto.h (65%) create mode 100644 client/obj/crypto/.dummy create mode 100644 common/mbedtls/Makefile create mode 100644 common/mbedtls/aes.c create mode 100644 common/mbedtls/aes.h create mode 100644 common/mbedtls/arc4.c create mode 100644 common/mbedtls/arc4.h create mode 100644 common/mbedtls/asn1.h create mode 100644 common/mbedtls/asn1parse.c create mode 100644 common/mbedtls/asn1write.c create mode 100644 common/mbedtls/asn1write.h create mode 100644 common/mbedtls/base64.c create mode 100644 common/mbedtls/base64.h create mode 100644 common/mbedtls/bignum.c create mode 100644 common/mbedtls/bignum.h create mode 100644 common/mbedtls/blowfish.c create mode 100644 common/mbedtls/blowfish.h create mode 100644 common/mbedtls/bn_mul.h create mode 100644 common/mbedtls/camellia.c create mode 100644 common/mbedtls/camellia.h create mode 100644 common/mbedtls/certs.c create mode 100644 common/mbedtls/certs.h create mode 100644 common/mbedtls/check_config.h create mode 100644 common/mbedtls/cipher.c create mode 100644 common/mbedtls/cipher.h create mode 100644 common/mbedtls/cipher_internal.h create mode 100644 common/mbedtls/cipher_wrap.c create mode 100644 common/mbedtls/cmac.c create mode 100644 common/mbedtls/cmac.h create mode 100644 common/mbedtls/config.h create mode 100644 common/mbedtls/ctr_drbg.c create mode 100644 common/mbedtls/ctr_drbg.h create mode 100644 common/mbedtls/des.c create mode 100644 common/mbedtls/des.h create mode 100644 common/mbedtls/ecdsa.c create mode 100644 common/mbedtls/ecdsa.h create mode 100644 common/mbedtls/ecp.c create mode 100644 common/mbedtls/ecp.h create mode 100644 common/mbedtls/ecp_curves.c create mode 100644 common/mbedtls/ecp_internal.h create mode 100644 common/mbedtls/entropy.c create mode 100644 common/mbedtls/entropy.h create mode 100644 common/mbedtls/entropy_poll.c create mode 100644 common/mbedtls/entropy_poll.h create mode 100644 common/mbedtls/error.c create mode 100644 common/mbedtls/error.h create mode 100644 common/mbedtls/md.c create mode 100644 common/mbedtls/md.h create mode 100644 common/mbedtls/md5.c create mode 100644 common/mbedtls/md5.h create mode 100644 common/mbedtls/md_internal.h create mode 100644 common/mbedtls/md_wrap.c create mode 100644 common/mbedtls/oid.c create mode 100644 common/mbedtls/oid.h create mode 100644 common/mbedtls/pem.c create mode 100644 common/mbedtls/pem.h create mode 100644 common/mbedtls/pk.c create mode 100644 common/mbedtls/pk.h create mode 100644 common/mbedtls/pk_internal.h create mode 100644 common/mbedtls/pk_wrap.c create mode 100644 common/mbedtls/pkcs12.c create mode 100644 common/mbedtls/pkcs12.h create mode 100644 common/mbedtls/pkcs5.c create mode 100644 common/mbedtls/pkcs5.h create mode 100644 common/mbedtls/pkparse.c create mode 100644 common/mbedtls/platform.c create mode 100644 common/mbedtls/platform.h create mode 100644 common/mbedtls/platform_util.c create mode 100644 common/mbedtls/platform_util.h create mode 100644 common/mbedtls/rsa.c create mode 100644 common/mbedtls/rsa.h create mode 100644 common/mbedtls/rsa_internal.c create mode 100644 common/mbedtls/rsa_internal.h rename common/{polarssl => mbedtls}/sha1.c (51%) create mode 100644 common/mbedtls/sha1.h create mode 100644 common/mbedtls/sha256.c create mode 100644 common/mbedtls/sha256.h create mode 100644 common/mbedtls/sha512.c create mode 100644 common/mbedtls/sha512.h create mode 100644 common/mbedtls/threading.c create mode 100644 common/mbedtls/threading.h create mode 100644 common/mbedtls/timing.c create mode 100644 common/mbedtls/timing.h create mode 100644 common/mbedtls/x509.c create mode 100644 common/mbedtls/x509.h create mode 100644 common/mbedtls/x509_crl.c create mode 100644 common/mbedtls/x509_crl.h create mode 100644 common/mbedtls/x509_crt.c create mode 100644 common/mbedtls/x509_crt.h delete mode 100644 common/polarssl/aes.c delete mode 100644 common/polarssl/aes.h delete mode 100644 common/polarssl/aes_cmac128.c delete mode 100644 common/polarssl/aes_cmac128.h delete mode 100644 common/polarssl/bignum.c delete mode 100644 common/polarssl/bignum.h delete mode 100644 common/polarssl/bn_mul.h delete mode 100644 common/polarssl/libpcrypto.c delete mode 100644 common/polarssl/rsa.c delete mode 100644 common/polarssl/rsa.h delete mode 100644 common/polarssl/sha1.h create mode 100644 travis_test_commands.scr diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..f5fed7a6 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,55 @@ +# Travis-CI config +# variable REPOSITORY_EP must be filled with repository name. as sample: "merlokk/proxmark3" +language: c + +compiler: gcc + +# Test on Linux and MacOS +matrix: + include: + - os: osx + osx_image: xcode7.3 # OS X 10.11 + - os: osx + osx_image: xcode8.3 # OS X 10.12 + - os: osx + osx_image: xcode9.4 # OS X 10.13 + - os: osx + osx_image: xcode10 # OS X 10.13 + - os: linux + dist: trusty + sudo: required + +before_install: +## Install ARM toolchain on Linux. +## add our homebrew tap for MacOS +## Note: all dependencies on MacOS should be resolved by the brew install command + echo $REPOSITORY_EP; + if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then + sudo apt-get update -qq; + sudo apt-get install -y gcc-arm-none-eabi; + elif [[ "$TRAVIS_OS_NAME" == "osx" ]]; then + brew update; + if [[ "$REPOSITORY_EP" == "" ]]; then + brew tap proxmark/proxmark3; + else + brew tap "$REPOSITORY_EP" --env=std; + fi + fi + +install: + if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then + brew info proxmark3; + brew install -v --HEAD proxmark3; + elif [[ "$TRAVIS_OS_NAME" == "linux" ]]; then + make all; + fi + +before_script: + +script: +## for the time being we are satisfied if it can be build and then successfully started + if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then + proxmark3 /dev/notexists travis_test_commands.scr ; + elif [[ "$TRAVIS_OS_NAME" == "linux" ]]; then + ./client/proxmark3 /dev/notexists travis_test_commands.scr ; + fi diff --git a/client/Makefile b/client/Makefile index 969eb241..bf884f1f 100644 --- a/client/Makefile +++ b/client/Makefile @@ -21,8 +21,10 @@ LDLIBS = -L/opt/local/lib -L/usr/local/lib -lreadline -lpthread -lm LUALIB = ../liblua/liblua.a JANSSONLIBPATH = ./jansson JANSSONLIB = $(JANSSONLIBPATH)/libjansson.a +MBEDTLSLIBPATH = ../common/mbedtls +MBEDTLSLIB = $(MBEDTLSLIBPATH)/libmbedtls.a LDFLAGS = $(ENV_LDFLAGS) -CFLAGS = $(ENV_CFLAGS) -std=c99 -D_ISOC99_SOURCE -I. -I../include -I../common -I../common/polarssl -I../zlib -I../uart -I/opt/local/include -I../liblua -I$(JANSSONLIBPATH) -Wall -g -O3 +CFLAGS = $(ENV_CFLAGS) -std=c99 -D_ISOC99_SOURCE -I. -I../include -I../common -I../common/polarssl -I../zlib -I../uart -I/opt/local/include -I../liblua -I$(JANSSONLIBPATH) -I$(MBEDTLSLIBPATH) -Wall -g -O3 CXXFLAGS = -I../include -Wall -O3 APP_CFLAGS = @@ -105,13 +107,9 @@ CORESRCS = uart_posix.c \ CMDSRCS = $(SRC_SMARTCARD) \ crapto1/crapto1.c\ crapto1/crypto1.c\ - polarssl/des.c \ - polarssl/aes.c\ - polarssl/aes_cmac128.c\ - polarssl/bignum.c\ - polarssl/rsa.c\ - polarssl/sha1.c\ - polarssl/libpcrypto.c\ + polarssl/des.c\ + crypto/libpcrypto.c\ + crypto/asn1utils.c\ cliparser/argtable3.c\ cliparser/cliparser.c\ mfkey.c\ @@ -247,12 +245,12 @@ WINBINS = $(patsubst %, %.exe, $(BINS)) CLEAN = $(BINS) $(WINBINS) $(COREOBJS) $(CMDOBJS) $(OBJCOBJS) $(ZLIBOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(OBJDIR)/*.o *.moc.cpp ui/ui_overlays.h # need to assign dependancies to build these first... -all: lua_build jansson_build $(BINS) +all: lua_build jansson_build mbedtls_build $(BINS) all-static: LDLIBS:=-static $(LDLIBS) all-static: proxmark3 flasher fpga_compress -proxmark3: LDLIBS+=$(LUALIB) $(JANSSONLIB) $(QTLDLIBS) +proxmark3: LDLIBS+=$(LUALIB) $(JANSSONLIB) $(MBEDTLSLIB) $(QTLDLIBS) proxmark3: $(OBJDIR)/proxmark3.o $(COREOBJS) $(CMDOBJS) $(OBJCOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(ZLIBOBJS) lualibs/usb_cmd.lua $(LD) $(LDFLAGS) $(OBJDIR)/proxmark3.o $(COREOBJS) $(CMDOBJS) $(OBJCOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(ZLIBOBJS) $(LDLIBS) -o $@ @@ -277,6 +275,7 @@ clean: $(RM) $(CLEAN) cd ../liblua && make clean cd ./jansson && make clean + cd $(MBEDTLSLIBPATH) && make clean tarbin: $(BINS) $(TAR) $(TARFLAGS) ../proxmark3-$(platform)-bin.tar $(BINS:%=client/%) $(WINBINS:%=client/%) @@ -288,6 +287,10 @@ lua_build: jansson_build: @echo Compiling jansson cd ./jansson && make all + +mbedtls_build: + @echo Compiling mbedtls + cd $(MBEDTLSLIBPATH) && make all .PHONY: all clean diff --git a/client/cmdhfmfp.c b/client/cmdhfmfp.c index 1ff24eb1..1e5bbe1a 100644 --- a/client/cmdhfmfp.c +++ b/client/cmdhfmfp.c @@ -24,7 +24,7 @@ #include "mifare.h" #include "mifare4.h" #include "cliparser/cliparser.h" -#include "polarssl/libpcrypto.h" +#include "crypto/libpcrypto.h" static const uint8_t DefaultKey[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; diff --git a/client/cmdhfmfu.c b/client/cmdhfmfu.c index 1077ec99..f167bae5 100644 --- a/client/cmdhfmfu.c +++ b/client/cmdhfmfu.c @@ -16,7 +16,7 @@ #include "usb_cmd.h" #include "cmdmain.h" #include "ui.h" -#include "polarssl/des.h" +#include "mbedtls/des.h" #include "cmdhfmf.h" #include "cmdhf14a.h" #include "mifare.h" @@ -1742,11 +1742,11 @@ int CmdHF14AMfuGenDiverseKeys(const char *Cmd){ mix[6] = block ^ uid[2]; mix[7] = uid[3]; - des3_context ctx = { 0x00 }; - des3_set2key_enc(&ctx, masterkey); + mbedtls_des3_context ctx = { 0x00 }; + mbedtls_des3_set2key_enc(&ctx, masterkey); - des3_crypt_cbc(&ctx // des3_context - , DES_ENCRYPT // int mode + mbedtls_des3_crypt_cbc(&ctx // des3_context + , MBEDTLS_DES_ENCRYPT // int mode , sizeof(mix) // length , iv // iv[8] , mix // input @@ -1781,10 +1781,10 @@ int CmdHF14AMfuGenDiverseKeys(const char *Cmd){ memcpy(dmkey+16, dkeyA, 8); memset(iv, 0x00, 8); - des3_set3key_enc(&ctx, dmkey); + mbedtls_des3_set3key_enc(&ctx, dmkey); - des3_crypt_cbc(&ctx // des3_context - , DES_ENCRYPT // int mode + mbedtls_des3_crypt_cbc(&ctx // des3_context + , MBEDTLS_DES_ENCRYPT // int mode , sizeof(newpwd) // length , iv // iv[8] , zeros // input diff --git a/client/crypto/asn1utils.c b/client/crypto/asn1utils.c new file mode 100644 index 00000000..2a3fe698 --- /dev/null +++ b/client/crypto/asn1utils.c @@ -0,0 +1,63 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2018 Merlok +// +// 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. +//----------------------------------------------------------------------------- +// asn.1 utils +//----------------------------------------------------------------------------- + +#include "asn1utils.h" +#include + +int ecdsa_asn1_get_signature(uint8_t *signature, size_t signaturelen, uint8_t *rval, uint8_t *sval) { + if (!signature || !signaturelen || !rval || !sval) + return 1; + + int res = 0; + unsigned char *p = signature; + const unsigned char *end = p + signaturelen; + size_t len; + mbedtls_mpi xmpi; + + if ((res = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) == 0) { + mbedtls_mpi_init(&xmpi); + res = mbedtls_asn1_get_mpi(&p, end, &xmpi); + if (res) { + mbedtls_mpi_free(&xmpi); + goto exit; + } + + res = mbedtls_mpi_write_binary(&xmpi, rval, 32); + mbedtls_mpi_free(&xmpi); + if (res) + goto exit; + + mbedtls_mpi_init(&xmpi); + res = mbedtls_asn1_get_mpi(&p, end, &xmpi); + if (res) { + mbedtls_mpi_free(&xmpi); + goto exit; + } + + res = mbedtls_mpi_write_binary(&xmpi, sval, 32); + mbedtls_mpi_free(&xmpi); + if (res) + goto exit; + + // check size + if (end != p) + return 2; + } + +exit: + return res; +} + +int asn1_print(uint8_t *asn1buf, int level) { + + return 0; +} + + diff --git a/client/crypto/asn1utils.h b/client/crypto/asn1utils.h new file mode 100644 index 00000000..2b00f450 --- /dev/null +++ b/client/crypto/asn1utils.h @@ -0,0 +1,21 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2018 Merlok +// +// 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. +//----------------------------------------------------------------------------- +// asn.1 utils +//----------------------------------------------------------------------------- + +#ifndef ASN1UTILS_H +#define ASN1UTILS_H + +#include +#include +#include + +extern int asn1_print(uint8_t *asn1buf, int level); +extern int ecdsa_asn1_get_signature(uint8_t *signature, size_t signaturelen, uint8_t *rval, uint8_t *sval); + +#endif /* asn1utils.h */ diff --git a/client/crypto/libpcrypto.c b/client/crypto/libpcrypto.c new file mode 100644 index 00000000..030be15a --- /dev/null +++ b/client/crypto/libpcrypto.c @@ -0,0 +1,381 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2018 Merlok +// Copyright (C) 2018 drHatson +// +// 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. +//----------------------------------------------------------------------------- +// crypto commands +//----------------------------------------------------------------------------- + +#include "crypto/libpcrypto.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// NIST Special Publication 800-38A — Recommendation for block cipher modes of operation: methods and techniques, 2001. +int aes_encode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length){ + uint8_t iiv[16] = {0}; + if (iv) + memcpy(iiv, iv, 16); + + mbedtls_aes_context aes; + mbedtls_aes_init(&aes); + if (mbedtls_aes_setkey_enc(&aes, key, 128)) + return 1; + if (mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, length, iiv, input, output)) + return 2; + mbedtls_aes_free(&aes); + + return 0; +} + +int aes_decode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length){ + uint8_t iiv[16] = {0}; + if (iv) + memcpy(iiv, iv, 16); + + mbedtls_aes_context aes; + mbedtls_aes_init(&aes); + if (mbedtls_aes_setkey_dec(&aes, key, 128)) + return 1; + if (mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, length, iiv, input, output)) + return 2; + mbedtls_aes_free(&aes); + + return 0; +} + +// NIST Special Publication 800-38B — Recommendation for block cipher modes of operation: The CMAC mode for authentication. +// https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/AES_CMAC.pdf +int aes_cmac(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, int length) { + memset(mac, 0x00, 16); + + // NIST 800-38B + return mbedtls_aes_cmac_prf_128(key, MBEDTLS_AES_BLOCK_SIZE, input, length, mac); +} + +int aes_cmac8(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, int length) { + uint8_t cmac[16] = {0}; + memset(mac, 0x00, 8); + + int res = aes_cmac(iv, key, input, cmac, length); + if (res) + return res; + + for(int i = 0; i < 8; i++) + mac[i] = cmac[i * 2 + 1]; + + return 0; +} + +static uint8_t fixed_rand_value[250] = {0}; +static int fixed_rand(void *rng_state, unsigned char *output, size_t len) { + if (len <= 250) { + memcpy(output, fixed_rand_value, len); + } else { + memset(output, 0x00, len); + } + + return 0; +} + +int sha256hash(uint8_t *input, int length, uint8_t *hash) { + if (!hash || !input) + return 1; + + mbedtls_sha256_context sctx; + mbedtls_sha256_init(&sctx); + mbedtls_sha256_starts(&sctx, 0); // SHA-256, not 224 + mbedtls_sha256_update(&sctx, input, length); + mbedtls_sha256_finish(&sctx, hash); + mbedtls_sha256_free(&sctx); + + return 0; +} + +int ecdsa_init_str(mbedtls_ecdsa_context *ctx, char * key_d, char *key_x, char *key_y) { + if (!ctx) + return 1; + + int res; + + mbedtls_ecdsa_init(ctx); + res = mbedtls_ecp_group_load(&ctx->grp, MBEDTLS_ECP_DP_SECP256R1); // secp256r1 + if (res) + return res; + + if (key_d) { + res = mbedtls_mpi_read_string(&ctx->d, 16, key_d); + if (res) + return res; + } + + if (key_x && key_y) { + res = mbedtls_ecp_point_read_string(&ctx->Q, 16, key_x, key_y); + if (res) + return res; + } + + return 0; +} + +int ecdsa_init(mbedtls_ecdsa_context *ctx, uint8_t * key_d, uint8_t *key_xy) { + if (!ctx) + return 1; + + int res; + + mbedtls_ecdsa_init(ctx); + res = mbedtls_ecp_group_load(&ctx->grp, MBEDTLS_ECP_DP_SECP256R1); // secp256r1 + if (res) + return res; + + if (key_d) { + res = mbedtls_mpi_read_binary(&ctx->d, key_d, 32); + if (res) + return res; + } + + if (key_xy) { + res = mbedtls_ecp_point_read_binary(&ctx->grp, &ctx->Q, key_xy, 32 * 2 + 1); + if (res) + return res; + } + + return 0; +} + +int ecdsa_key_create(uint8_t * key_d, uint8_t *key_xy) { + int res; + mbedtls_ecdsa_context ctx; + ecdsa_init(&ctx, NULL, NULL); + + + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + const char *pers = "ecdsaproxmark"; + + mbedtls_entropy_init(&entropy); + mbedtls_ctr_drbg_init(&ctr_drbg); + + res = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)pers, strlen(pers)); + if (res) + goto exit; + + res = mbedtls_ecdsa_genkey(&ctx, MBEDTLS_ECP_DP_SECP256R1, mbedtls_ctr_drbg_random, &ctr_drbg); + if (res) + goto exit; + + res = mbedtls_mpi_write_binary(&ctx.d, key_d, 32); + if (res) + goto exit; + + size_t keylen = 0; + uint8_t public_key[200] = {0}; + res = mbedtls_ecp_point_write_binary(&ctx.grp, &ctx.Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &keylen, public_key, sizeof(public_key)); + if (res) + goto exit; + + if (keylen != 65) { // 0x04 + res = 1; + goto exit; + } + memcpy(key_xy, public_key, 65); + +exit: + mbedtls_entropy_free(&entropy); + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_ecdsa_free(&ctx); + return res; +} + +char *ecdsa_get_error(int ret) { + static char retstr[300]; + memset(retstr, 0x00, sizeof(retstr)); + mbedtls_strerror(ret, retstr, sizeof(retstr)); + return retstr; +} + +int ecdsa_signature_create(uint8_t *key_d, uint8_t *key_xy, uint8_t *input, int length, uint8_t *signature, size_t *signaturelen) { + int res; + *signaturelen = 0; + + uint8_t shahash[32] = {0}; + res = sha256hash(input, length, shahash); + if (res) + return res; + + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + const char *pers = "ecdsaproxmark"; + + mbedtls_entropy_init(&entropy); + mbedtls_ctr_drbg_init(&ctr_drbg); + + res = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)pers, strlen(pers)); + if (res) + goto exit; + + mbedtls_ecdsa_context ctx; + ecdsa_init(&ctx, key_d, key_xy); + res = mbedtls_ecdsa_write_signature(&ctx, MBEDTLS_MD_SHA256, shahash, sizeof(shahash), signature, signaturelen, mbedtls_ctr_drbg_random, &ctr_drbg); + +exit: + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_ecdsa_free(&ctx); + return res; +} + +int ecdsa_signature_create_test(char * key_d, char *key_x, char *key_y, char *random, uint8_t *input, int length, uint8_t *signature, size_t *signaturelen) { + int res; + *signaturelen = 0; + + uint8_t shahash[32] = {0}; + res = sha256hash(input, length, shahash); + if (res) + return res; + + int rndlen = 0; + param_gethex_to_eol(random, 0, fixed_rand_value, sizeof(fixed_rand_value), &rndlen); + + mbedtls_ecdsa_context ctx; + ecdsa_init_str(&ctx, key_d, key_x, key_y); + res = mbedtls_ecdsa_write_signature(&ctx, MBEDTLS_MD_SHA256, shahash, sizeof(shahash), signature, signaturelen, fixed_rand, NULL); + + mbedtls_ecdsa_free(&ctx); + return res; +} + +int ecdsa_signature_verify_keystr(char *key_x, char *key_y, uint8_t *input, int length, uint8_t *signature, size_t signaturelen) { + int res; + uint8_t shahash[32] = {0}; + res = sha256hash(input, length, shahash); + if (res) + return res; + + mbedtls_ecdsa_context ctx; + ecdsa_init_str(&ctx, NULL, key_x, key_y); + res = mbedtls_ecdsa_read_signature(&ctx, shahash, sizeof(shahash), signature, signaturelen); + + mbedtls_ecdsa_free(&ctx); + return res; +} + +int ecdsa_signature_verify(uint8_t *key_xy, uint8_t *input, int length, uint8_t *signature, size_t signaturelen) { + int res; + uint8_t shahash[32] = {0}; + res = sha256hash(input, length, shahash); + if (res) + return res; + + mbedtls_ecdsa_context ctx; + ecdsa_init(&ctx, NULL, key_xy); + res = mbedtls_ecdsa_read_signature(&ctx, shahash, sizeof(shahash), signature, signaturelen); + + mbedtls_ecdsa_free(&ctx); + return res; +} + +#define T_PRIVATE_KEY "C477F9F65C22CCE20657FAA5B2D1D8122336F851A508A1ED04E479C34985BF96" +#define T_Q_X "B7E08AFDFE94BAD3F1DC8C734798BA1C62B3A0AD1E9EA2A38201CD0889BC7A19" +#define T_Q_Y "3603F747959DBF7A4BB226E41928729063ADC7AE43529E61B563BBC606CC5E09" +#define T_K "7A1A7E52797FC8CAAA435D2A4DACE39158504BF204FBE19F14DBB427FAEE50AE" +#define T_R "2B42F576D07F4165FF65D1F3B1500F81E44C316F1F0B3EF57325B69ACA46104F" +#define T_S "DC42C2122D6392CD3E3A993A89502A8198C1886FE69D262C4B329BDB6B63FAF1" + +int ecdsa_nist_test(bool verbose) { + int res; + uint8_t input[] = "Example of ECDSA with P-256"; + int length = strlen((char *)input); + uint8_t signature[300] = {0}; + size_t siglen = 0; + + // NIST ecdsa test + if (verbose) + printf(" ECDSA NIST test: "); + // make signature + res = ecdsa_signature_create_test(T_PRIVATE_KEY, T_Q_X, T_Q_Y, T_K, input, length, signature, &siglen); +// printf("res: %x signature[%x]: %s\n", (res<0)?-res:res, siglen, sprint_hex(signature, siglen)); + if (res) + goto exit; + + // check vectors + uint8_t rval[300] = {0}; + uint8_t sval[300] = {0}; + res = ecdsa_asn1_get_signature(signature, siglen, rval, sval); + if (res) + goto exit; + + int slen = 0; + uint8_t rval_s[33] = {0}; + param_gethex_to_eol(T_R, 0, rval_s, sizeof(rval_s), &slen); + uint8_t sval_s[33] = {0}; + param_gethex_to_eol(T_S, 0, sval_s, sizeof(sval_s), &slen); + if (strncmp((char *)rval, (char *)rval_s, 32) || strncmp((char *)sval, (char *)sval_s, 32)) { + printf("R or S check error\n"); + res = 100; + goto exit; + } + + // verify signature + res = ecdsa_signature_verify_keystr(T_Q_X, T_Q_Y, input, length, signature, siglen); + if (res) + goto exit; + + // verify wrong signature + input[0] ^= 0xFF; + res = ecdsa_signature_verify_keystr(T_Q_X, T_Q_Y, input, length, signature, siglen); + if (!res) { + res = 1; + goto exit; + } + if (verbose) + printf("passed\n"); + + // random ecdsa test + if (verbose) + printf(" ECDSA binary signature create/check test: "); + + uint8_t key_d[32] = {0}; + uint8_t key_xy[32 * 2 + 2] = {0}; + memset(signature, 0x00, sizeof(signature)); + siglen = 0; + + res = ecdsa_key_create(key_d, key_xy); + if (res) + goto exit; + + res = ecdsa_signature_create(key_d, key_xy, input, length, signature, &siglen); + if (res) + goto exit; + + res = ecdsa_signature_verify(key_xy, input, length, signature, siglen); + if (res) + goto exit; + + input[0] ^= 0xFF; + res = ecdsa_signature_verify(key_xy, input, length, signature, siglen); + if (!res) + goto exit; + + if (verbose) + printf("passed\n\n"); + + return 0; +exit: + if (verbose) + printf("failed\n\n"); + return res; +} diff --git a/common/polarssl/libpcrypto.h b/client/crypto/libpcrypto.h similarity index 65% rename from common/polarssl/libpcrypto.h rename to client/crypto/libpcrypto.h index 1b74c143..8d4b4a0d 100644 --- a/common/polarssl/libpcrypto.h +++ b/client/crypto/libpcrypto.h @@ -12,6 +12,7 @@ #define LIBPCRYPTO_H #include +#include #include extern int aes_encode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length); @@ -19,4 +20,13 @@ extern int aes_decode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output extern int aes_cmac(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, int length); extern int aes_cmac8(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, int length); +extern int sha256hash(uint8_t *input, int length, uint8_t *hash); + +extern int ecdsa_key_create(uint8_t * key_d, uint8_t *key_xy); +extern int ecdsa_signature_create(uint8_t *key_d, uint8_t *key_xy, uint8_t *input, int length, uint8_t *signature, size_t *signaturelen); +extern int ecdsa_signature_verify(uint8_t *key_xy, uint8_t *input, int length, uint8_t *signature, size_t signaturelen); +extern char *ecdsa_get_error(int ret); + +extern int ecdsa_nist_test(bool verbose); + #endif /* libpcrypto.h */ diff --git a/client/emv/crypto_polarssl.c b/client/emv/crypto_polarssl.c index 5a3db8ea..93853505 100644 --- a/client/emv/crypto_polarssl.c +++ b/client/emv/crypto_polarssl.c @@ -24,13 +24,14 @@ #include #include #include +#include -#include "rsa.h" -#include "sha1.h" +#include "mbedtls/rsa.h" +#include "mbedtls/sha1.h" struct crypto_hash_polarssl { struct crypto_hash ch; - sha1_context ctx; + mbedtls_sha1_context ctx; }; static void crypto_hash_polarssl_close(struct crypto_hash *_ch) @@ -44,7 +45,7 @@ static void crypto_hash_polarssl_write(struct crypto_hash *_ch, const unsigned c { struct crypto_hash_polarssl *ch = (struct crypto_hash_polarssl *)_ch; - sha1_update(&(ch->ctx), buf, len); + mbedtls_sha1_update(&(ch->ctx), buf, len); } static unsigned char *crypto_hash_polarssl_read(struct crypto_hash *_ch) @@ -52,7 +53,7 @@ static unsigned char *crypto_hash_polarssl_read(struct crypto_hash *_ch) struct crypto_hash_polarssl *ch = (struct crypto_hash_polarssl *)_ch; static unsigned char sha1sum[20]; - sha1_finish(&(ch->ctx), sha1sum); + mbedtls_sha1_finish(&(ch->ctx), sha1sum); return sha1sum; } @@ -71,7 +72,7 @@ static struct crypto_hash *crypto_hash_polarssl_open(enum crypto_algo_hash hash) struct crypto_hash_polarssl *ch = malloc(sizeof(*ch)); - sha1_starts(&(ch->ctx)); + mbedtls_sha1_starts(&(ch->ctx)); ch->ch.write = crypto_hash_polarssl_write; ch->ch.read = crypto_hash_polarssl_read; @@ -83,7 +84,7 @@ static struct crypto_hash *crypto_hash_polarssl_open(enum crypto_algo_hash hash) struct crypto_pk_polarssl { struct crypto_pk cp; - rsa_context ctx; + mbedtls_rsa_context ctx; }; static struct crypto_pk *crypto_pk_polarssl_open_rsa(va_list vl) @@ -96,13 +97,13 @@ static struct crypto_pk *crypto_pk_polarssl_open_rsa(va_list vl) char *exp = va_arg(vl, char *); // E int explen = va_arg(vl, size_t); - rsa_init(&cp->ctx, RSA_PKCS_V15, 0); + mbedtls_rsa_init(&cp->ctx, MBEDTLS_RSA_PKCS_V15, 0); cp->ctx.len = modlen; // size(N) in bytes - mpi_read_binary(&cp->ctx.N, (const unsigned char *)mod, modlen); - mpi_read_binary(&cp->ctx.E, (const unsigned char *)exp, explen); + 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 = rsa_check_pubkey(&cp->ctx); + 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); @@ -134,20 +135,20 @@ static struct crypto_pk *crypto_pk_polarssl_open_priv_rsa(va_list vl) // char *inv = va_arg(vl, char *); // int invlen = va_arg(vl, size_t); - rsa_init(&cp->ctx, RSA_PKCS_V15, 0); + mbedtls_rsa_init(&cp->ctx, MBEDTLS_RSA_PKCS_V15, 0); cp->ctx.len = modlen; // size(N) in bytes - mpi_read_binary(&cp->ctx.N, (const unsigned char *)mod, modlen); - mpi_read_binary(&cp->ctx.E, (const unsigned char *)exp, explen); + mbedtls_mpi_read_binary(&cp->ctx.N, (const unsigned char *)mod, modlen); + mbedtls_mpi_read_binary(&cp->ctx.E, (const unsigned char *)exp, explen); - mpi_read_binary(&cp->ctx.D, (const unsigned char *)d, dlen); - mpi_read_binary(&cp->ctx.P, (const unsigned char *)p, plen); - mpi_read_binary(&cp->ctx.Q, (const unsigned char *)q, qlen); - mpi_read_binary(&cp->ctx.DP, (const unsigned char *)dp, dplen); - mpi_read_binary(&cp->ctx.DQ, (const unsigned char *)dq, dqlen); - 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 = rsa_check_privkey(&cp->ctx); + 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); @@ -182,7 +183,7 @@ static struct crypto_pk *crypto_pk_polarssl_genkey_rsa(va_list vl) if (transient) { } - int res = rsa_gen_key(&cp->ctx, &myrand, NULL, nbits, exp); + 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); @@ -196,7 +197,7 @@ static void crypto_pk_polarssl_close(struct crypto_pk *_cp) { struct crypto_pk_polarssl *cp = (struct crypto_pk_polarssl *)_cp; - rsa_free(&cp->ctx); + mbedtls_rsa_free(&cp->ctx); free(cp); } @@ -207,7 +208,7 @@ static unsigned char *crypto_pk_polarssl_encrypt(const struct crypto_pk *_cp, co unsigned char *result; *clen = 0; - size_t keylen = mpi_size(&cp->ctx.N); + size_t keylen = mbedtls_mpi_size(&cp->ctx.N); result = malloc(keylen); if (!result) { @@ -215,7 +216,7 @@ static unsigned char *crypto_pk_polarssl_encrypt(const struct crypto_pk *_cp, co return NULL; } - res = rsa_public(&cp->ctx, buf, result); + 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); @@ -234,7 +235,7 @@ static unsigned char *crypto_pk_polarssl_decrypt(const struct crypto_pk *_cp, co unsigned char *result; *clen = 0; - size_t keylen = mpi_size(&cp->ctx.N); + size_t keylen = mbedtls_mpi_size(&cp->ctx.N); result = malloc(keylen); if (!result) { @@ -242,7 +243,7 @@ static unsigned char *crypto_pk_polarssl_decrypt(const struct crypto_pk *_cp, co return NULL; } - res = rsa_private(&cp->ctx, buf, result); // CHECK??? + 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); @@ -269,17 +270,17 @@ static unsigned char *crypto_pk_polarssl_get_parameter(const struct crypto_pk *_ switch(param){ // mod case 0: - *plen = mpi_size(&cp->ctx.N); + *plen = mbedtls_mpi_size(&cp->ctx.N); result = malloc(*plen); memset(result, 0x00, *plen); - mpi_write_binary(&cp->ctx.N, result, *plen); + mbedtls_mpi_write_binary(&cp->ctx.N, result, *plen); break; // exp case 1: - *plen = mpi_size(&cp->ctx.E); + *plen = mbedtls_mpi_size(&cp->ctx.E); result = malloc(*plen); memset(result, 0x00, *plen); - mpi_write_binary(&cp->ctx.E, result, *plen); + mbedtls_mpi_write_binary(&cp->ctx.E, result, *plen); break; default: printf("Error get parameter. Param=%d", param); diff --git a/client/emv/test/cryptotest.c b/client/emv/test/cryptotest.c index b778d256..1d5891fe 100644 --- a/client/emv/test/cryptotest.c +++ b/client/emv/test/cryptotest.c @@ -12,38 +12,70 @@ #include "util.h" #include "ui.h" -#include "bignum.h" -#include "aes.h" -#include "aes_cmac128.h" -#include "des.h" -#include "rsa.h" -#include "sha1.h" +#include "mbedtls/bignum.h" +#include "mbedtls/aes.h" +#include "mbedtls/cmac.h" +#include "mbedtls/des.h" +#include "mbedtls/ecp.h" +#include "mbedtls/rsa.h" +#include "mbedtls/sha1.h" +#include "mbedtls/md5.h" +#include "mbedtls/x509.h" +#include "mbedtls/base64.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/entropy.h" +#include "mbedtls/timing.h" #include "crypto_test.h" #include "sda_test.h" #include "dda_test.h" #include "cda_test.h" +#include "crypto/libpcrypto.h" int ExecuteCryptoTests(bool verbose) { int res; bool TestFail = false; - res = mpi_self_test(verbose); + res = mbedtls_mpi_self_test(verbose); if (res) TestFail = true; - res = aes_self_test(verbose); + res = mbedtls_aes_self_test(verbose); if (res) TestFail = true; - res = aes_cmac_self_test(verbose); + res = mbedtls_des_self_test(verbose); + if (res) TestFail = true; + + res = mbedtls_sha1_self_test(verbose); if (res) TestFail = true; - res = des_self_test(verbose); + res = mbedtls_md5_self_test(verbose); if (res) TestFail = true; - res = sha1_self_test(verbose); + res = mbedtls_rsa_self_test(verbose); if (res) TestFail = true; - res = rsa_self_test(verbose); + res = mbedtls_entropy_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_base64_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 = mbedtls_ecp_self_test(verbose); + if (res) TestFail = true; + + res = mbedtls_x509_self_test(verbose); if (res) TestFail = true; res = exec_sda_test(verbose); diff --git a/client/mifare4.c b/client/mifare4.c index 866e854f..069c54d4 100644 --- a/client/mifare4.c +++ b/client/mifare4.c @@ -15,7 +15,7 @@ #include "cmdhf14a.h" #include "util.h" #include "ui.h" -#include "polarssl/libpcrypto.h" +#include "crypto/libpcrypto.h" int CalculateEncIVCommand(mf4Session *session, uint8_t *iv, bool verbose) { memcpy(&iv[0], session->TI, 4); diff --git a/client/obj/crypto/.dummy b/client/obj/crypto/.dummy new file mode 100644 index 00000000..e69de29b diff --git a/client/scripting.c b/client/scripting.c index 232da889..ed7ae007 100644 --- a/client/scripting.c +++ b/client/scripting.c @@ -24,8 +24,8 @@ #include "iso14443crc.h" #include "../common/crc16.h" #include "../common/crc64.h" -#include "../common/polarssl/sha1.h" -#include "../common/polarssl/aes.h" +#include +#include /** * The following params expected: @@ -257,10 +257,10 @@ static int l_aes128decrypt_cbc(lua_State *L) sscanf(&p_key[i], "%02x", (unsigned int *)&aes_key[i / 2]); } - aes_context ctx; - aes_init(&ctx); - aes_setkey_dec(&ctx, aes_key, 128); - aes_crypt_cbc(&ctx,AES_DECRYPT,sizeof(indata), iv, indata,outdata ); + mbedtls_aes_context ctx; + mbedtls_aes_init(&ctx); + mbedtls_aes_setkey_dec(&ctx, aes_key, 128); + mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_DECRYPT, sizeof(indata), iv, indata,outdata ); //Push decrypted array as a string lua_pushlstring(L,(const char *)&outdata, sizeof(outdata)); return 1;// return 1 to signal one return value @@ -284,10 +284,10 @@ static int l_aes128decrypt_ecb(lua_State *L) sscanf(&p_encTxt[i], "%02x", (unsigned int *)&indata[i / 2]); sscanf(&p_key[i], "%02x", (unsigned int *)&aes_key[i / 2]); } - aes_context ctx; - aes_init(&ctx); - aes_setkey_dec(&ctx, aes_key, 128); - aes_crypt_ecb(&ctx, AES_DECRYPT, indata, outdata ); + mbedtls_aes_context ctx; + mbedtls_aes_init(&ctx); + mbedtls_aes_setkey_dec(&ctx, aes_key, 128); + mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_DECRYPT, indata, outdata ); //Push decrypted array as a string lua_pushlstring(L,(const char *)&outdata, sizeof(outdata)); @@ -314,10 +314,10 @@ static int l_aes128encrypt_cbc(lua_State *L) sscanf(&p_key[i], "%02x", (unsigned int *)&aes_key[i / 2]); } - aes_context ctx; - aes_init(&ctx); - aes_setkey_enc(&ctx, aes_key, 128); - aes_crypt_cbc(&ctx, AES_ENCRYPT, sizeof(indata), iv, indata, outdata ); + mbedtls_aes_context ctx; + mbedtls_aes_init(&ctx); + mbedtls_aes_setkey_enc(&ctx, aes_key, 128); + mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_ENCRYPT, sizeof(indata), iv, indata, outdata ); //Push encrypted array as a string lua_pushlstring(L,(const char *)&outdata, sizeof(outdata)); return 1;// return 1 to signal one return value @@ -341,10 +341,10 @@ static int l_aes128encrypt_ecb(lua_State *L) sscanf(&p_txt[i], "%02x", (unsigned int *)&indata[i / 2]); sscanf(&p_key[i], "%02x", (unsigned int *)&aes_key[i / 2]); } - aes_context ctx; - aes_init(&ctx); - aes_setkey_enc(&ctx, aes_key, 128); - aes_crypt_ecb(&ctx, AES_ENCRYPT, indata, outdata ); + mbedtls_aes_context ctx; + mbedtls_aes_init(&ctx); + mbedtls_aes_setkey_enc(&ctx, aes_key, 128); + mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, indata, outdata ); //Push encrypted array as a string lua_pushlstring(L,(const char *)&outdata, sizeof(outdata)); return 1;// return 1 to signal one return value @@ -387,7 +387,7 @@ static int l_sha1(lua_State *L) size_t size; const char *p_str = luaL_checklstring(L, 1, &size); unsigned char outdata[20] = {0x00}; - sha1( (uint8_t*) p_str, size, outdata); + mbedtls_sha1( (uint8_t*) p_str, size, outdata); lua_pushlstring(L,(const char *)&outdata, sizeof(outdata)); return 1; } diff --git a/common/mbedtls/Makefile b/common/mbedtls/Makefile new file mode 100644 index 00000000..3e57fdac --- /dev/null +++ b/common/mbedtls/Makefile @@ -0,0 +1,86 @@ + +LIB_A = libmbedtls.a +mbedtls_SOURCES = \ + aes.c \ + asn1parse.c \ + asn1write.c \ + base64.c \ + bignum.c \ + ctr_drbg.c \ + entropy_poll.c \ + entropy.c \ + error.c \ + timing.c \ + ecp.c \ + ecp_curves.c \ + certs.c \ + camellia.c \ + blowfish.c \ + cipher_wrap.c \ + cipher.c \ + cmac.c \ + des.c \ + ecdsa.c \ + md.c \ + md_wrap.c \ + md5.c \ + oid.c \ + pem.c \ + arc4.c \ + pk.c \ + pk_wrap.c \ + pkcs5.c \ + pkcs12.c \ + pkparse.c \ + platform.c \ + platform_util.c \ + rsa.c \ + rsa_internal.c \ + sha1.c \ + sha256.c \ + sha512.c \ + threading.c \ + x509.c \ + x509_crl.c \ + x509_crt.c +mbedtls_LDFLAGS = \ + -no-undefined \ + -export-symbols-regex '^mbedtls_' \ + -version-info 15:0:11 + + +CFILES = $(filter %.c, $(mbedtls_SOURCES)) +CMDOBJS = $(CFILES:%.c=%.o) +CLEAN = $(CMDOBJS) + +CC= gcc +CFLAGS= -O2 -Wall -Wno-unused-variable -Wno-unused-function +LDFLAGS= $(SYSLDFLAGS) $(mbedtls_LDFLAGS) +LIBS= -lm $(SYSLIBS) $(MYLIBS) +DEFAULT_INCLUDES = -I. -I.. +DEFS = -DHAVE_STDINT_H + +AR= ar rcs +RANLIB= ranlib +RM= rm -f +TST= echo + +SYSLDFLAGS= +SYSLIBS= + +MYLIBS= +MYOBJS= + +all: $(CMDOBJS) + $(AR) $(LIB_A) $(CMDOBJS) + $(RANLIB) $(LIB_A) + +clean: + $(RM) $(CLEAN) + $(RM) $(LIB_A) + +%.o: %.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(CFLAGS) -c -o $@ $< $(LIBS) + +.PHONY: all clean + diff --git a/common/mbedtls/aes.c b/common/mbedtls/aes.c new file mode 100644 index 00000000..07391ecd --- /dev/null +++ b/common/mbedtls/aes.c @@ -0,0 +1,2125 @@ +/* + * FIPS-197 compliant AES implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The AES block cipher was designed by Vincent Rijmen and Joan Daemen. + * + * http://csrc.nist.gov/encryption/aes/rijndael/Rijndael.pdf + * http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_AES_C) + +#include + +#include "mbedtls/aes.h" +#include "mbedtls/platform_util.h" +#if defined(MBEDTLS_PADLOCK_C) +#include "mbedtls/padlock.h" +#endif +#if defined(MBEDTLS_AESNI_C) +#include "mbedtls/aesni.h" +#endif + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_AES_ALT) + +/* + * 32-bit integer manipulation macros (little endian) + */ +#ifndef GET_UINT32_LE +#define GET_UINT32_LE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] ) \ + | ( (uint32_t) (b)[(i) + 1] << 8 ) \ + | ( (uint32_t) (b)[(i) + 2] << 16 ) \ + | ( (uint32_t) (b)[(i) + 3] << 24 ); \ +} +#endif + +#ifndef PUT_UINT32_LE +#define PUT_UINT32_LE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( ( (n) ) & 0xFF ); \ + (b)[(i) + 1] = (unsigned char) ( ( (n) >> 8 ) & 0xFF ); \ + (b)[(i) + 2] = (unsigned char) ( ( (n) >> 16 ) & 0xFF ); \ + (b)[(i) + 3] = (unsigned char) ( ( (n) >> 24 ) & 0xFF ); \ +} +#endif + +#if defined(MBEDTLS_PADLOCK_C) && \ + ( defined(MBEDTLS_HAVE_X86) || defined(MBEDTLS_PADLOCK_ALIGN16) ) +static int aes_padlock_ace = -1; +#endif + +#if defined(MBEDTLS_AES_ROM_TABLES) +/* + * Forward S-box + */ +static const unsigned char FSb[256] = +{ + 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, + 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, + 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, + 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, + 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, + 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, + 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, + 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, + 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, + 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, + 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, + 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, + 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, + 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, + 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, + 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, + 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, + 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, + 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, + 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, + 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, + 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, + 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, + 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, + 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, + 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, + 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, + 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, + 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, + 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, + 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, + 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 +}; + +/* + * Forward tables + */ +#define FT \ +\ + V(A5,63,63,C6), V(84,7C,7C,F8), V(99,77,77,EE), V(8D,7B,7B,F6), \ + V(0D,F2,F2,FF), V(BD,6B,6B,D6), V(B1,6F,6F,DE), V(54,C5,C5,91), \ + V(50,30,30,60), V(03,01,01,02), V(A9,67,67,CE), V(7D,2B,2B,56), \ + V(19,FE,FE,E7), V(62,D7,D7,B5), V(E6,AB,AB,4D), V(9A,76,76,EC), \ + V(45,CA,CA,8F), V(9D,82,82,1F), V(40,C9,C9,89), V(87,7D,7D,FA), \ + V(15,FA,FA,EF), V(EB,59,59,B2), V(C9,47,47,8E), V(0B,F0,F0,FB), \ + V(EC,AD,AD,41), V(67,D4,D4,B3), V(FD,A2,A2,5F), V(EA,AF,AF,45), \ + V(BF,9C,9C,23), V(F7,A4,A4,53), V(96,72,72,E4), V(5B,C0,C0,9B), \ + V(C2,B7,B7,75), V(1C,FD,FD,E1), V(AE,93,93,3D), V(6A,26,26,4C), \ + V(5A,36,36,6C), V(41,3F,3F,7E), V(02,F7,F7,F5), V(4F,CC,CC,83), \ + V(5C,34,34,68), V(F4,A5,A5,51), V(34,E5,E5,D1), V(08,F1,F1,F9), \ + V(93,71,71,E2), V(73,D8,D8,AB), V(53,31,31,62), V(3F,15,15,2A), \ + V(0C,04,04,08), V(52,C7,C7,95), V(65,23,23,46), V(5E,C3,C3,9D), \ + V(28,18,18,30), V(A1,96,96,37), V(0F,05,05,0A), V(B5,9A,9A,2F), \ + V(09,07,07,0E), V(36,12,12,24), V(9B,80,80,1B), V(3D,E2,E2,DF), \ + V(26,EB,EB,CD), V(69,27,27,4E), V(CD,B2,B2,7F), V(9F,75,75,EA), \ + V(1B,09,09,12), V(9E,83,83,1D), V(74,2C,2C,58), V(2E,1A,1A,34), \ + V(2D,1B,1B,36), V(B2,6E,6E,DC), V(EE,5A,5A,B4), V(FB,A0,A0,5B), \ + V(F6,52,52,A4), V(4D,3B,3B,76), V(61,D6,D6,B7), V(CE,B3,B3,7D), \ + V(7B,29,29,52), V(3E,E3,E3,DD), V(71,2F,2F,5E), V(97,84,84,13), \ + V(F5,53,53,A6), V(68,D1,D1,B9), V(00,00,00,00), V(2C,ED,ED,C1), \ + V(60,20,20,40), V(1F,FC,FC,E3), V(C8,B1,B1,79), V(ED,5B,5B,B6), \ + V(BE,6A,6A,D4), V(46,CB,CB,8D), V(D9,BE,BE,67), V(4B,39,39,72), \ + V(DE,4A,4A,94), V(D4,4C,4C,98), V(E8,58,58,B0), V(4A,CF,CF,85), \ + V(6B,D0,D0,BB), V(2A,EF,EF,C5), V(E5,AA,AA,4F), V(16,FB,FB,ED), \ + V(C5,43,43,86), V(D7,4D,4D,9A), V(55,33,33,66), V(94,85,85,11), \ + V(CF,45,45,8A), V(10,F9,F9,E9), V(06,02,02,04), V(81,7F,7F,FE), \ + V(F0,50,50,A0), V(44,3C,3C,78), V(BA,9F,9F,25), V(E3,A8,A8,4B), \ + V(F3,51,51,A2), V(FE,A3,A3,5D), V(C0,40,40,80), V(8A,8F,8F,05), \ + V(AD,92,92,3F), V(BC,9D,9D,21), V(48,38,38,70), V(04,F5,F5,F1), \ + V(DF,BC,BC,63), V(C1,B6,B6,77), V(75,DA,DA,AF), V(63,21,21,42), \ + V(30,10,10,20), V(1A,FF,FF,E5), V(0E,F3,F3,FD), V(6D,D2,D2,BF), \ + V(4C,CD,CD,81), V(14,0C,0C,18), V(35,13,13,26), V(2F,EC,EC,C3), \ + V(E1,5F,5F,BE), V(A2,97,97,35), V(CC,44,44,88), V(39,17,17,2E), \ + V(57,C4,C4,93), V(F2,A7,A7,55), V(82,7E,7E,FC), V(47,3D,3D,7A), \ + V(AC,64,64,C8), V(E7,5D,5D,BA), V(2B,19,19,32), V(95,73,73,E6), \ + V(A0,60,60,C0), V(98,81,81,19), V(D1,4F,4F,9E), V(7F,DC,DC,A3), \ + V(66,22,22,44), V(7E,2A,2A,54), V(AB,90,90,3B), V(83,88,88,0B), \ + V(CA,46,46,8C), V(29,EE,EE,C7), V(D3,B8,B8,6B), V(3C,14,14,28), \ + V(79,DE,DE,A7), V(E2,5E,5E,BC), V(1D,0B,0B,16), V(76,DB,DB,AD), \ + V(3B,E0,E0,DB), V(56,32,32,64), V(4E,3A,3A,74), V(1E,0A,0A,14), \ + V(DB,49,49,92), V(0A,06,06,0C), V(6C,24,24,48), V(E4,5C,5C,B8), \ + V(5D,C2,C2,9F), V(6E,D3,D3,BD), V(EF,AC,AC,43), V(A6,62,62,C4), \ + V(A8,91,91,39), V(A4,95,95,31), V(37,E4,E4,D3), V(8B,79,79,F2), \ + V(32,E7,E7,D5), V(43,C8,C8,8B), V(59,37,37,6E), V(B7,6D,6D,DA), \ + V(8C,8D,8D,01), V(64,D5,D5,B1), V(D2,4E,4E,9C), V(E0,A9,A9,49), \ + V(B4,6C,6C,D8), V(FA,56,56,AC), V(07,F4,F4,F3), V(25,EA,EA,CF), \ + V(AF,65,65,CA), V(8E,7A,7A,F4), V(E9,AE,AE,47), V(18,08,08,10), \ + V(D5,BA,BA,6F), V(88,78,78,F0), V(6F,25,25,4A), V(72,2E,2E,5C), \ + V(24,1C,1C,38), V(F1,A6,A6,57), V(C7,B4,B4,73), V(51,C6,C6,97), \ + V(23,E8,E8,CB), V(7C,DD,DD,A1), V(9C,74,74,E8), V(21,1F,1F,3E), \ + V(DD,4B,4B,96), V(DC,BD,BD,61), V(86,8B,8B,0D), V(85,8A,8A,0F), \ + V(90,70,70,E0), V(42,3E,3E,7C), V(C4,B5,B5,71), V(AA,66,66,CC), \ + V(D8,48,48,90), V(05,03,03,06), V(01,F6,F6,F7), V(12,0E,0E,1C), \ + V(A3,61,61,C2), V(5F,35,35,6A), V(F9,57,57,AE), V(D0,B9,B9,69), \ + V(91,86,86,17), V(58,C1,C1,99), V(27,1D,1D,3A), V(B9,9E,9E,27), \ + V(38,E1,E1,D9), V(13,F8,F8,EB), V(B3,98,98,2B), V(33,11,11,22), \ + V(BB,69,69,D2), V(70,D9,D9,A9), V(89,8E,8E,07), V(A7,94,94,33), \ + V(B6,9B,9B,2D), V(22,1E,1E,3C), V(92,87,87,15), V(20,E9,E9,C9), \ + V(49,CE,CE,87), V(FF,55,55,AA), V(78,28,28,50), V(7A,DF,DF,A5), \ + V(8F,8C,8C,03), V(F8,A1,A1,59), V(80,89,89,09), V(17,0D,0D,1A), \ + V(DA,BF,BF,65), V(31,E6,E6,D7), V(C6,42,42,84), V(B8,68,68,D0), \ + V(C3,41,41,82), V(B0,99,99,29), V(77,2D,2D,5A), V(11,0F,0F,1E), \ + V(CB,B0,B0,7B), V(FC,54,54,A8), V(D6,BB,BB,6D), V(3A,16,16,2C) + +#define V(a,b,c,d) 0x##a##b##c##d +static const uint32_t FT0[256] = { FT }; +#undef V + +#if !defined(MBEDTLS_AES_FEWER_TABLES) + +#define V(a,b,c,d) 0x##b##c##d##a +static const uint32_t FT1[256] = { FT }; +#undef V + +#define V(a,b,c,d) 0x##c##d##a##b +static const uint32_t FT2[256] = { FT }; +#undef V + +#define V(a,b,c,d) 0x##d##a##b##c +static const uint32_t FT3[256] = { FT }; +#undef V + +#endif /* !MBEDTLS_AES_FEWER_TABLES */ + +#undef FT + +/* + * Reverse S-box + */ +static const unsigned char RSb[256] = +{ + 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, + 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, + 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, + 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, + 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, + 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, + 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, + 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, + 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, + 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, + 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, + 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, + 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, + 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, + 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, + 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, + 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, + 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, + 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, + 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, + 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, + 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, + 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, + 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, + 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, + 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, + 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, + 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, + 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, + 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, + 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D +}; + +/* + * Reverse tables + */ +#define RT \ +\ + V(50,A7,F4,51), V(53,65,41,7E), V(C3,A4,17,1A), V(96,5E,27,3A), \ + V(CB,6B,AB,3B), V(F1,45,9D,1F), V(AB,58,FA,AC), V(93,03,E3,4B), \ + V(55,FA,30,20), V(F6,6D,76,AD), V(91,76,CC,88), V(25,4C,02,F5), \ + V(FC,D7,E5,4F), V(D7,CB,2A,C5), V(80,44,35,26), V(8F,A3,62,B5), \ + V(49,5A,B1,DE), V(67,1B,BA,25), V(98,0E,EA,45), V(E1,C0,FE,5D), \ + V(02,75,2F,C3), V(12,F0,4C,81), V(A3,97,46,8D), V(C6,F9,D3,6B), \ + V(E7,5F,8F,03), V(95,9C,92,15), V(EB,7A,6D,BF), V(DA,59,52,95), \ + V(2D,83,BE,D4), V(D3,21,74,58), V(29,69,E0,49), V(44,C8,C9,8E), \ + V(6A,89,C2,75), V(78,79,8E,F4), V(6B,3E,58,99), V(DD,71,B9,27), \ + V(B6,4F,E1,BE), V(17,AD,88,F0), V(66,AC,20,C9), V(B4,3A,CE,7D), \ + V(18,4A,DF,63), V(82,31,1A,E5), V(60,33,51,97), V(45,7F,53,62), \ + V(E0,77,64,B1), V(84,AE,6B,BB), V(1C,A0,81,FE), V(94,2B,08,F9), \ + V(58,68,48,70), V(19,FD,45,8F), V(87,6C,DE,94), V(B7,F8,7B,52), \ + V(23,D3,73,AB), V(E2,02,4B,72), V(57,8F,1F,E3), V(2A,AB,55,66), \ + V(07,28,EB,B2), V(03,C2,B5,2F), V(9A,7B,C5,86), V(A5,08,37,D3), \ + V(F2,87,28,30), V(B2,A5,BF,23), V(BA,6A,03,02), V(5C,82,16,ED), \ + V(2B,1C,CF,8A), V(92,B4,79,A7), V(F0,F2,07,F3), V(A1,E2,69,4E), \ + V(CD,F4,DA,65), V(D5,BE,05,06), V(1F,62,34,D1), V(8A,FE,A6,C4), \ + V(9D,53,2E,34), V(A0,55,F3,A2), V(32,E1,8A,05), V(75,EB,F6,A4), \ + V(39,EC,83,0B), V(AA,EF,60,40), V(06,9F,71,5E), V(51,10,6E,BD), \ + V(F9,8A,21,3E), V(3D,06,DD,96), V(AE,05,3E,DD), V(46,BD,E6,4D), \ + V(B5,8D,54,91), V(05,5D,C4,71), V(6F,D4,06,04), V(FF,15,50,60), \ + V(24,FB,98,19), V(97,E9,BD,D6), V(CC,43,40,89), V(77,9E,D9,67), \ + V(BD,42,E8,B0), V(88,8B,89,07), V(38,5B,19,E7), V(DB,EE,C8,79), \ + V(47,0A,7C,A1), V(E9,0F,42,7C), V(C9,1E,84,F8), V(00,00,00,00), \ + V(83,86,80,09), V(48,ED,2B,32), V(AC,70,11,1E), V(4E,72,5A,6C), \ + V(FB,FF,0E,FD), V(56,38,85,0F), V(1E,D5,AE,3D), V(27,39,2D,36), \ + V(64,D9,0F,0A), V(21,A6,5C,68), V(D1,54,5B,9B), V(3A,2E,36,24), \ + V(B1,67,0A,0C), V(0F,E7,57,93), V(D2,96,EE,B4), V(9E,91,9B,1B), \ + V(4F,C5,C0,80), V(A2,20,DC,61), V(69,4B,77,5A), V(16,1A,12,1C), \ + V(0A,BA,93,E2), V(E5,2A,A0,C0), V(43,E0,22,3C), V(1D,17,1B,12), \ + V(0B,0D,09,0E), V(AD,C7,8B,F2), V(B9,A8,B6,2D), V(C8,A9,1E,14), \ + V(85,19,F1,57), V(4C,07,75,AF), V(BB,DD,99,EE), V(FD,60,7F,A3), \ + V(9F,26,01,F7), V(BC,F5,72,5C), V(C5,3B,66,44), V(34,7E,FB,5B), \ + V(76,29,43,8B), V(DC,C6,23,CB), V(68,FC,ED,B6), V(63,F1,E4,B8), \ + V(CA,DC,31,D7), V(10,85,63,42), V(40,22,97,13), V(20,11,C6,84), \ + V(7D,24,4A,85), V(F8,3D,BB,D2), V(11,32,F9,AE), V(6D,A1,29,C7), \ + V(4B,2F,9E,1D), V(F3,30,B2,DC), V(EC,52,86,0D), V(D0,E3,C1,77), \ + V(6C,16,B3,2B), V(99,B9,70,A9), V(FA,48,94,11), V(22,64,E9,47), \ + V(C4,8C,FC,A8), V(1A,3F,F0,A0), V(D8,2C,7D,56), V(EF,90,33,22), \ + V(C7,4E,49,87), V(C1,D1,38,D9), V(FE,A2,CA,8C), V(36,0B,D4,98), \ + V(CF,81,F5,A6), V(28,DE,7A,A5), V(26,8E,B7,DA), V(A4,BF,AD,3F), \ + V(E4,9D,3A,2C), V(0D,92,78,50), V(9B,CC,5F,6A), V(62,46,7E,54), \ + V(C2,13,8D,F6), V(E8,B8,D8,90), V(5E,F7,39,2E), V(F5,AF,C3,82), \ + V(BE,80,5D,9F), V(7C,93,D0,69), V(A9,2D,D5,6F), V(B3,12,25,CF), \ + V(3B,99,AC,C8), V(A7,7D,18,10), V(6E,63,9C,E8), V(7B,BB,3B,DB), \ + V(09,78,26,CD), V(F4,18,59,6E), V(01,B7,9A,EC), V(A8,9A,4F,83), \ + V(65,6E,95,E6), V(7E,E6,FF,AA), V(08,CF,BC,21), V(E6,E8,15,EF), \ + V(D9,9B,E7,BA), V(CE,36,6F,4A), V(D4,09,9F,EA), V(D6,7C,B0,29), \ + V(AF,B2,A4,31), V(31,23,3F,2A), V(30,94,A5,C6), V(C0,66,A2,35), \ + V(37,BC,4E,74), V(A6,CA,82,FC), V(B0,D0,90,E0), V(15,D8,A7,33), \ + V(4A,98,04,F1), V(F7,DA,EC,41), V(0E,50,CD,7F), V(2F,F6,91,17), \ + V(8D,D6,4D,76), V(4D,B0,EF,43), V(54,4D,AA,CC), V(DF,04,96,E4), \ + V(E3,B5,D1,9E), V(1B,88,6A,4C), V(B8,1F,2C,C1), V(7F,51,65,46), \ + V(04,EA,5E,9D), V(5D,35,8C,01), V(73,74,87,FA), V(2E,41,0B,FB), \ + V(5A,1D,67,B3), V(52,D2,DB,92), V(33,56,10,E9), V(13,47,D6,6D), \ + V(8C,61,D7,9A), V(7A,0C,A1,37), V(8E,14,F8,59), V(89,3C,13,EB), \ + V(EE,27,A9,CE), V(35,C9,61,B7), V(ED,E5,1C,E1), V(3C,B1,47,7A), \ + V(59,DF,D2,9C), V(3F,73,F2,55), V(79,CE,14,18), V(BF,37,C7,73), \ + V(EA,CD,F7,53), V(5B,AA,FD,5F), V(14,6F,3D,DF), V(86,DB,44,78), \ + V(81,F3,AF,CA), V(3E,C4,68,B9), V(2C,34,24,38), V(5F,40,A3,C2), \ + V(72,C3,1D,16), V(0C,25,E2,BC), V(8B,49,3C,28), V(41,95,0D,FF), \ + V(71,01,A8,39), V(DE,B3,0C,08), V(9C,E4,B4,D8), V(90,C1,56,64), \ + V(61,84,CB,7B), V(70,B6,32,D5), V(74,5C,6C,48), V(42,57,B8,D0) + +#define V(a,b,c,d) 0x##a##b##c##d +static const uint32_t RT0[256] = { RT }; +#undef V + +#if !defined(MBEDTLS_AES_FEWER_TABLES) + +#define V(a,b,c,d) 0x##b##c##d##a +static const uint32_t RT1[256] = { RT }; +#undef V + +#define V(a,b,c,d) 0x##c##d##a##b +static const uint32_t RT2[256] = { RT }; +#undef V + +#define V(a,b,c,d) 0x##d##a##b##c +static const uint32_t RT3[256] = { RT }; +#undef V + +#endif /* !MBEDTLS_AES_FEWER_TABLES */ + +#undef RT + +/* + * Round constants + */ +static const uint32_t RCON[10] = +{ + 0x00000001, 0x00000002, 0x00000004, 0x00000008, + 0x00000010, 0x00000020, 0x00000040, 0x00000080, + 0x0000001B, 0x00000036 +}; + +#else /* MBEDTLS_AES_ROM_TABLES */ + +/* + * Forward S-box & tables + */ +static unsigned char FSb[256]; +static uint32_t FT0[256]; +#if !defined(MBEDTLS_AES_FEWER_TABLES) +static uint32_t FT1[256]; +static uint32_t FT2[256]; +static uint32_t FT3[256]; +#endif /* !MBEDTLS_AES_FEWER_TABLES */ + +/* + * Reverse S-box & tables + */ +static unsigned char RSb[256]; +static uint32_t RT0[256]; +#if !defined(MBEDTLS_AES_FEWER_TABLES) +static uint32_t RT1[256]; +static uint32_t RT2[256]; +static uint32_t RT3[256]; +#endif /* !MBEDTLS_AES_FEWER_TABLES */ + +/* + * Round constants + */ +static uint32_t RCON[10]; + +/* + * Tables generation code + */ +#define ROTL8(x) ( ( x << 8 ) & 0xFFFFFFFF ) | ( x >> 24 ) +#define XTIME(x) ( ( x << 1 ) ^ ( ( x & 0x80 ) ? 0x1B : 0x00 ) ) +#define MUL(x,y) ( ( x && y ) ? pow[(log[x]+log[y]) % 255] : 0 ) + +static int aes_init_done = 0; + +static void aes_gen_tables( void ) +{ + int i, x, y, z; + int pow[256]; + int log[256]; + + /* + * compute pow and log tables over GF(2^8) + */ + for( i = 0, x = 1; i < 256; i++ ) + { + pow[i] = x; + log[x] = i; + x = ( x ^ XTIME( x ) ) & 0xFF; + } + + /* + * calculate the round constants + */ + for( i = 0, x = 1; i < 10; i++ ) + { + RCON[i] = (uint32_t) x; + x = XTIME( x ) & 0xFF; + } + + /* + * generate the forward and reverse S-boxes + */ + FSb[0x00] = 0x63; + RSb[0x63] = 0x00; + + for( i = 1; i < 256; i++ ) + { + x = pow[255 - log[i]]; + + y = x; y = ( ( y << 1 ) | ( y >> 7 ) ) & 0xFF; + x ^= y; y = ( ( y << 1 ) | ( y >> 7 ) ) & 0xFF; + x ^= y; y = ( ( y << 1 ) | ( y >> 7 ) ) & 0xFF; + x ^= y; y = ( ( y << 1 ) | ( y >> 7 ) ) & 0xFF; + x ^= y ^ 0x63; + + FSb[i] = (unsigned char) x; + RSb[x] = (unsigned char) i; + } + + /* + * generate the forward and reverse tables + */ + for( i = 0; i < 256; i++ ) + { + x = FSb[i]; + y = XTIME( x ) & 0xFF; + z = ( y ^ x ) & 0xFF; + + FT0[i] = ( (uint32_t) y ) ^ + ( (uint32_t) x << 8 ) ^ + ( (uint32_t) x << 16 ) ^ + ( (uint32_t) z << 24 ); + +#if !defined(MBEDTLS_AES_FEWER_TABLES) + FT1[i] = ROTL8( FT0[i] ); + FT2[i] = ROTL8( FT1[i] ); + FT3[i] = ROTL8( FT2[i] ); +#endif /* !MBEDTLS_AES_FEWER_TABLES */ + + x = RSb[i]; + + RT0[i] = ( (uint32_t) MUL( 0x0E, x ) ) ^ + ( (uint32_t) MUL( 0x09, x ) << 8 ) ^ + ( (uint32_t) MUL( 0x0D, x ) << 16 ) ^ + ( (uint32_t) MUL( 0x0B, x ) << 24 ); + +#if !defined(MBEDTLS_AES_FEWER_TABLES) + RT1[i] = ROTL8( RT0[i] ); + RT2[i] = ROTL8( RT1[i] ); + RT3[i] = ROTL8( RT2[i] ); +#endif /* !MBEDTLS_AES_FEWER_TABLES */ + } +} + +#undef ROTL8 + +#endif /* MBEDTLS_AES_ROM_TABLES */ + +#if defined(MBEDTLS_AES_FEWER_TABLES) + +#define ROTL8(x) ( (uint32_t)( ( x ) << 8 ) + (uint32_t)( ( x ) >> 24 ) ) +#define ROTL16(x) ( (uint32_t)( ( x ) << 16 ) + (uint32_t)( ( x ) >> 16 ) ) +#define ROTL24(x) ( (uint32_t)( ( x ) << 24 ) + (uint32_t)( ( x ) >> 8 ) ) + +#define AES_RT0(idx) RT0[idx] +#define AES_RT1(idx) ROTL8( RT0[idx] ) +#define AES_RT2(idx) ROTL16( RT0[idx] ) +#define AES_RT3(idx) ROTL24( RT0[idx] ) + +#define AES_FT0(idx) FT0[idx] +#define AES_FT1(idx) ROTL8( FT0[idx] ) +#define AES_FT2(idx) ROTL16( FT0[idx] ) +#define AES_FT3(idx) ROTL24( FT0[idx] ) + +#else /* MBEDTLS_AES_FEWER_TABLES */ + +#define AES_RT0(idx) RT0[idx] +#define AES_RT1(idx) RT1[idx] +#define AES_RT2(idx) RT2[idx] +#define AES_RT3(idx) RT3[idx] + +#define AES_FT0(idx) FT0[idx] +#define AES_FT1(idx) FT1[idx] +#define AES_FT2(idx) FT2[idx] +#define AES_FT3(idx) FT3[idx] + +#endif /* MBEDTLS_AES_FEWER_TABLES */ + +void mbedtls_aes_init( mbedtls_aes_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_aes_context ) ); +} + +void mbedtls_aes_free( mbedtls_aes_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_aes_context ) ); +} + +#if defined(MBEDTLS_CIPHER_MODE_XTS) +void mbedtls_aes_xts_init( mbedtls_aes_xts_context *ctx ) +{ + mbedtls_aes_init( &ctx->crypt ); + mbedtls_aes_init( &ctx->tweak ); +} + +void mbedtls_aes_xts_free( mbedtls_aes_xts_context *ctx ) +{ + mbedtls_aes_free( &ctx->crypt ); + mbedtls_aes_free( &ctx->tweak ); +} +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +/* + * AES key schedule (encryption) + */ +#if !defined(MBEDTLS_AES_SETKEY_ENC_ALT) +int mbedtls_aes_setkey_enc( mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits ) +{ + unsigned int i; + uint32_t *RK; + +#if !defined(MBEDTLS_AES_ROM_TABLES) + if( aes_init_done == 0 ) + { + aes_gen_tables(); + aes_init_done = 1; + + } +#endif + + switch( keybits ) + { + case 128: ctx->nr = 10; break; + case 192: ctx->nr = 12; break; + case 256: ctx->nr = 14; break; + default : return( MBEDTLS_ERR_AES_INVALID_KEY_LENGTH ); + } + +#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_PADLOCK_ALIGN16) + if( aes_padlock_ace == -1 ) + aes_padlock_ace = mbedtls_padlock_has_support( MBEDTLS_PADLOCK_ACE ); + + if( aes_padlock_ace ) + ctx->rk = RK = MBEDTLS_PADLOCK_ALIGN16( ctx->buf ); + else +#endif + ctx->rk = RK = ctx->buf; + +#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64) + if( mbedtls_aesni_has_support( MBEDTLS_AESNI_AES ) ) + return( mbedtls_aesni_setkey_enc( (unsigned char *) ctx->rk, key, keybits ) ); +#endif + + for( i = 0; i < ( keybits >> 5 ); i++ ) + { + GET_UINT32_LE( RK[i], key, i << 2 ); + } + + switch( ctx->nr ) + { + case 10: + + for( i = 0; i < 10; i++, RK += 4 ) + { + RK[4] = RK[0] ^ RCON[i] ^ + ( (uint32_t) FSb[ ( RK[3] >> 8 ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( RK[3] >> 16 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( RK[3] >> 24 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( RK[3] ) & 0xFF ] << 24 ); + + RK[5] = RK[1] ^ RK[4]; + RK[6] = RK[2] ^ RK[5]; + RK[7] = RK[3] ^ RK[6]; + } + break; + + case 12: + + for( i = 0; i < 8; i++, RK += 6 ) + { + RK[6] = RK[0] ^ RCON[i] ^ + ( (uint32_t) FSb[ ( RK[5] >> 8 ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( RK[5] >> 16 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( RK[5] >> 24 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( RK[5] ) & 0xFF ] << 24 ); + + RK[7] = RK[1] ^ RK[6]; + RK[8] = RK[2] ^ RK[7]; + RK[9] = RK[3] ^ RK[8]; + RK[10] = RK[4] ^ RK[9]; + RK[11] = RK[5] ^ RK[10]; + } + break; + + case 14: + + for( i = 0; i < 7; i++, RK += 8 ) + { + RK[8] = RK[0] ^ RCON[i] ^ + ( (uint32_t) FSb[ ( RK[7] >> 8 ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( RK[7] >> 16 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( RK[7] >> 24 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( RK[7] ) & 0xFF ] << 24 ); + + RK[9] = RK[1] ^ RK[8]; + RK[10] = RK[2] ^ RK[9]; + RK[11] = RK[3] ^ RK[10]; + + RK[12] = RK[4] ^ + ( (uint32_t) FSb[ ( RK[11] ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( RK[11] >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( RK[11] >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( RK[11] >> 24 ) & 0xFF ] << 24 ); + + RK[13] = RK[5] ^ RK[12]; + RK[14] = RK[6] ^ RK[13]; + RK[15] = RK[7] ^ RK[14]; + } + break; + } + + return( 0 ); +} +#endif /* !MBEDTLS_AES_SETKEY_ENC_ALT */ + +/* + * AES key schedule (decryption) + */ +#if !defined(MBEDTLS_AES_SETKEY_DEC_ALT) +int mbedtls_aes_setkey_dec( mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits ) +{ + int i, j, ret; + mbedtls_aes_context cty; + uint32_t *RK; + uint32_t *SK; + + mbedtls_aes_init( &cty ); + +#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_PADLOCK_ALIGN16) + if( aes_padlock_ace == -1 ) + aes_padlock_ace = mbedtls_padlock_has_support( MBEDTLS_PADLOCK_ACE ); + + if( aes_padlock_ace ) + ctx->rk = RK = MBEDTLS_PADLOCK_ALIGN16( ctx->buf ); + else +#endif + ctx->rk = RK = ctx->buf; + + /* Also checks keybits */ + if( ( ret = mbedtls_aes_setkey_enc( &cty, key, keybits ) ) != 0 ) + goto exit; + + ctx->nr = cty.nr; + +#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64) + if( mbedtls_aesni_has_support( MBEDTLS_AESNI_AES ) ) + { + mbedtls_aesni_inverse_key( (unsigned char *) ctx->rk, + (const unsigned char *) cty.rk, ctx->nr ); + goto exit; + } +#endif + + SK = cty.rk + cty.nr * 4; + + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + + for( i = ctx->nr - 1, SK -= 8; i > 0; i--, SK -= 8 ) + { + for( j = 0; j < 4; j++, SK++ ) + { + *RK++ = AES_RT0( FSb[ ( *SK ) & 0xFF ] ) ^ + AES_RT1( FSb[ ( *SK >> 8 ) & 0xFF ] ) ^ + AES_RT2( FSb[ ( *SK >> 16 ) & 0xFF ] ) ^ + AES_RT3( FSb[ ( *SK >> 24 ) & 0xFF ] ); + } + } + + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + +exit: + mbedtls_aes_free( &cty ); + + return( ret ); +} + +#if defined(MBEDTLS_CIPHER_MODE_XTS) +static int mbedtls_aes_xts_decode_keys( const unsigned char *key, + unsigned int keybits, + const unsigned char **key1, + unsigned int *key1bits, + const unsigned char **key2, + unsigned int *key2bits ) +{ + const unsigned int half_keybits = keybits / 2; + const unsigned int half_keybytes = half_keybits / 8; + + switch( keybits ) + { + case 256: break; + case 512: break; + default : return( MBEDTLS_ERR_AES_INVALID_KEY_LENGTH ); + } + + *key1bits = half_keybits; + *key2bits = half_keybits; + *key1 = &key[0]; + *key2 = &key[half_keybytes]; + + return 0; +} + +int mbedtls_aes_xts_setkey_enc( mbedtls_aes_xts_context *ctx, + const unsigned char *key, + unsigned int keybits) +{ + int ret; + const unsigned char *key1, *key2; + unsigned int key1bits, key2bits; + + ret = mbedtls_aes_xts_decode_keys( key, keybits, &key1, &key1bits, + &key2, &key2bits ); + if( ret != 0 ) + return( ret ); + + /* Set the tweak key. Always set tweak key for the encryption mode. */ + ret = mbedtls_aes_setkey_enc( &ctx->tweak, key2, key2bits ); + if( ret != 0 ) + return( ret ); + + /* Set crypt key for encryption. */ + return mbedtls_aes_setkey_enc( &ctx->crypt, key1, key1bits ); +} + +int mbedtls_aes_xts_setkey_dec( mbedtls_aes_xts_context *ctx, + const unsigned char *key, + unsigned int keybits) +{ + int ret; + const unsigned char *key1, *key2; + unsigned int key1bits, key2bits; + + ret = mbedtls_aes_xts_decode_keys( key, keybits, &key1, &key1bits, + &key2, &key2bits ); + if( ret != 0 ) + return( ret ); + + /* Set the tweak key. Always set tweak key for encryption. */ + ret = mbedtls_aes_setkey_enc( &ctx->tweak, key2, key2bits ); + if( ret != 0 ) + return( ret ); + + /* Set crypt key for decryption. */ + return mbedtls_aes_setkey_dec( &ctx->crypt, key1, key1bits ); +} +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +#endif /* !MBEDTLS_AES_SETKEY_DEC_ALT */ + +#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ +{ \ + X0 = *RK++ ^ AES_FT0( ( Y0 ) & 0xFF ) ^ \ + AES_FT1( ( Y1 >> 8 ) & 0xFF ) ^ \ + AES_FT2( ( Y2 >> 16 ) & 0xFF ) ^ \ + AES_FT3( ( Y3 >> 24 ) & 0xFF ); \ + \ + X1 = *RK++ ^ AES_FT0( ( Y1 ) & 0xFF ) ^ \ + AES_FT1( ( Y2 >> 8 ) & 0xFF ) ^ \ + AES_FT2( ( Y3 >> 16 ) & 0xFF ) ^ \ + AES_FT3( ( Y0 >> 24 ) & 0xFF ); \ + \ + X2 = *RK++ ^ AES_FT0( ( Y2 ) & 0xFF ) ^ \ + AES_FT1( ( Y3 >> 8 ) & 0xFF ) ^ \ + AES_FT2( ( Y0 >> 16 ) & 0xFF ) ^ \ + AES_FT3( ( Y1 >> 24 ) & 0xFF ); \ + \ + X3 = *RK++ ^ AES_FT0( ( Y3 ) & 0xFF ) ^ \ + AES_FT1( ( Y0 >> 8 ) & 0xFF ) ^ \ + AES_FT2( ( Y1 >> 16 ) & 0xFF ) ^ \ + AES_FT3( ( Y2 >> 24 ) & 0xFF ); \ +} + +#define AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ +{ \ + X0 = *RK++ ^ AES_RT0( ( Y0 ) & 0xFF ) ^ \ + AES_RT1( ( Y3 >> 8 ) & 0xFF ) ^ \ + AES_RT2( ( Y2 >> 16 ) & 0xFF ) ^ \ + AES_RT3( ( Y1 >> 24 ) & 0xFF ); \ + \ + X1 = *RK++ ^ AES_RT0( ( Y1 ) & 0xFF ) ^ \ + AES_RT1( ( Y0 >> 8 ) & 0xFF ) ^ \ + AES_RT2( ( Y3 >> 16 ) & 0xFF ) ^ \ + AES_RT3( ( Y2 >> 24 ) & 0xFF ); \ + \ + X2 = *RK++ ^ AES_RT0( ( Y2 ) & 0xFF ) ^ \ + AES_RT1( ( Y1 >> 8 ) & 0xFF ) ^ \ + AES_RT2( ( Y0 >> 16 ) & 0xFF ) ^ \ + AES_RT3( ( Y3 >> 24 ) & 0xFF ); \ + \ + X3 = *RK++ ^ AES_RT0( ( Y3 ) & 0xFF ) ^ \ + AES_RT1( ( Y2 >> 8 ) & 0xFF ) ^ \ + AES_RT2( ( Y1 >> 16 ) & 0xFF ) ^ \ + AES_RT3( ( Y0 >> 24 ) & 0xFF ); \ +} + +/* + * AES-ECB block encryption + */ +#if !defined(MBEDTLS_AES_ENCRYPT_ALT) +int mbedtls_internal_aes_encrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + int i; + uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; + + RK = ctx->rk; + + GET_UINT32_LE( X0, input, 0 ); X0 ^= *RK++; + GET_UINT32_LE( X1, input, 4 ); X1 ^= *RK++; + GET_UINT32_LE( X2, input, 8 ); X2 ^= *RK++; + GET_UINT32_LE( X3, input, 12 ); X3 ^= *RK++; + + for( i = ( ctx->nr >> 1 ) - 1; i > 0; i-- ) + { + AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); + AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); + } + + AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); + + X0 = *RK++ ^ \ + ( (uint32_t) FSb[ ( Y0 ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( Y1 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( Y3 >> 24 ) & 0xFF ] << 24 ); + + X1 = *RK++ ^ \ + ( (uint32_t) FSb[ ( Y1 ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( Y2 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( Y0 >> 24 ) & 0xFF ] << 24 ); + + X2 = *RK++ ^ \ + ( (uint32_t) FSb[ ( Y2 ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( Y3 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( Y1 >> 24 ) & 0xFF ] << 24 ); + + X3 = *RK++ ^ \ + ( (uint32_t) FSb[ ( Y3 ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( Y0 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( Y2 >> 24 ) & 0xFF ] << 24 ); + + PUT_UINT32_LE( X0, output, 0 ); + PUT_UINT32_LE( X1, output, 4 ); + PUT_UINT32_LE( X2, output, 8 ); + PUT_UINT32_LE( X3, output, 12 ); + + return( 0 ); +} +#endif /* !MBEDTLS_AES_ENCRYPT_ALT */ + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_aes_encrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + mbedtls_internal_aes_encrypt( ctx, input, output ); +} +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +/* + * AES-ECB block decryption + */ +#if !defined(MBEDTLS_AES_DECRYPT_ALT) +int mbedtls_internal_aes_decrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + int i; + uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; + + RK = ctx->rk; + + GET_UINT32_LE( X0, input, 0 ); X0 ^= *RK++; + GET_UINT32_LE( X1, input, 4 ); X1 ^= *RK++; + GET_UINT32_LE( X2, input, 8 ); X2 ^= *RK++; + GET_UINT32_LE( X3, input, 12 ); X3 ^= *RK++; + + for( i = ( ctx->nr >> 1 ) - 1; i > 0; i-- ) + { + AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); + AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); + } + + AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); + + X0 = *RK++ ^ \ + ( (uint32_t) RSb[ ( Y0 ) & 0xFF ] ) ^ + ( (uint32_t) RSb[ ( Y3 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) RSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) RSb[ ( Y1 >> 24 ) & 0xFF ] << 24 ); + + X1 = *RK++ ^ \ + ( (uint32_t) RSb[ ( Y1 ) & 0xFF ] ) ^ + ( (uint32_t) RSb[ ( Y0 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) RSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) RSb[ ( Y2 >> 24 ) & 0xFF ] << 24 ); + + X2 = *RK++ ^ \ + ( (uint32_t) RSb[ ( Y2 ) & 0xFF ] ) ^ + ( (uint32_t) RSb[ ( Y1 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) RSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) RSb[ ( Y3 >> 24 ) & 0xFF ] << 24 ); + + X3 = *RK++ ^ \ + ( (uint32_t) RSb[ ( Y3 ) & 0xFF ] ) ^ + ( (uint32_t) RSb[ ( Y2 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) RSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) RSb[ ( Y0 >> 24 ) & 0xFF ] << 24 ); + + PUT_UINT32_LE( X0, output, 0 ); + PUT_UINT32_LE( X1, output, 4 ); + PUT_UINT32_LE( X2, output, 8 ); + PUT_UINT32_LE( X3, output, 12 ); + + return( 0 ); +} +#endif /* !MBEDTLS_AES_DECRYPT_ALT */ + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_aes_decrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + mbedtls_internal_aes_decrypt( ctx, input, output ); +} +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +/* + * AES-ECB block encryption/decryption + */ +int mbedtls_aes_crypt_ecb( mbedtls_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ) +{ +#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64) + if( mbedtls_aesni_has_support( MBEDTLS_AESNI_AES ) ) + return( mbedtls_aesni_crypt_ecb( ctx, mode, input, output ) ); +#endif + +#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_HAVE_X86) + if( aes_padlock_ace ) + { + if( mbedtls_padlock_xcryptecb( ctx, mode, input, output ) == 0 ) + return( 0 ); + + // If padlock data misaligned, we just fall back to + // unaccelerated mode + // + } +#endif + + if( mode == MBEDTLS_AES_ENCRYPT ) + return( mbedtls_internal_aes_encrypt( ctx, input, output ) ); + else + return( mbedtls_internal_aes_decrypt( ctx, input, output ) ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/* + * AES-CBC buffer encryption/decryption + */ +int mbedtls_aes_crypt_cbc( mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[16]; + + if( length % 16 ) + return( MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH ); + +#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_HAVE_X86) + if( aes_padlock_ace ) + { + if( mbedtls_padlock_xcryptcbc( ctx, mode, length, iv, input, output ) == 0 ) + return( 0 ); + + // If padlock data misaligned, we just fall back to + // unaccelerated mode + // + } +#endif + + if( mode == MBEDTLS_AES_DECRYPT ) + { + while( length > 0 ) + { + memcpy( temp, input, 16 ); + mbedtls_aes_crypt_ecb( ctx, mode, input, output ); + + for( i = 0; i < 16; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 16 ); + + input += 16; + output += 16; + length -= 16; + } + } + else + { + while( length > 0 ) + { + for( i = 0; i < 16; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + mbedtls_aes_crypt_ecb( ctx, mode, output, output ); + memcpy( iv, output, 16 ); + + input += 16; + output += 16; + length -= 16; + } + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_XTS) + +/* Endianess with 64 bits values */ +#ifndef GET_UINT64_LE +#define GET_UINT64_LE(n,b,i) \ +{ \ + (n) = ( (uint64_t) (b)[(i) + 7] << 56 ) \ + | ( (uint64_t) (b)[(i) + 6] << 48 ) \ + | ( (uint64_t) (b)[(i) + 5] << 40 ) \ + | ( (uint64_t) (b)[(i) + 4] << 32 ) \ + | ( (uint64_t) (b)[(i) + 3] << 24 ) \ + | ( (uint64_t) (b)[(i) + 2] << 16 ) \ + | ( (uint64_t) (b)[(i) + 1] << 8 ) \ + | ( (uint64_t) (b)[(i) ] ); \ +} +#endif + +#ifndef PUT_UINT64_LE +#define PUT_UINT64_LE(n,b,i) \ +{ \ + (b)[(i) + 7] = (unsigned char) ( (n) >> 56 ); \ + (b)[(i) + 6] = (unsigned char) ( (n) >> 48 ); \ + (b)[(i) + 5] = (unsigned char) ( (n) >> 40 ); \ + (b)[(i) + 4] = (unsigned char) ( (n) >> 32 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) ] = (unsigned char) ( (n) ); \ +} +#endif + +typedef unsigned char mbedtls_be128[16]; + +/* + * GF(2^128) multiplication function + * + * This function multiplies a field element by x in the polynomial field + * representation. It uses 64-bit word operations to gain speed but compensates + * for machine endianess and hence works correctly on both big and little + * endian machines. + */ +static void mbedtls_gf128mul_x_ble( unsigned char r[16], + const unsigned char x[16] ) +{ + uint64_t a, b, ra, rb; + + GET_UINT64_LE( a, x, 0 ); + GET_UINT64_LE( b, x, 8 ); + + ra = ( a << 1 ) ^ 0x0087 >> ( 8 - ( ( b >> 63 ) << 3 ) ); + rb = ( a >> 63 ) | ( b << 1 ); + + PUT_UINT64_LE( ra, r, 0 ); + PUT_UINT64_LE( rb, r, 8 ); +} + +/* + * AES-XTS buffer encryption/decryption + */ +int mbedtls_aes_crypt_xts( mbedtls_aes_xts_context *ctx, + int mode, + size_t length, + const unsigned char data_unit[16], + const unsigned char *input, + unsigned char *output ) +{ + int ret; + size_t blocks = length / 16; + size_t leftover = length % 16; + unsigned char tweak[16]; + unsigned char prev_tweak[16]; + unsigned char tmp[16]; + + /* Sectors must be at least 16 bytes. */ + if( length < 16 ) + return MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH; + + /* NIST SP 80-38E disallows data units larger than 2**20 blocks. */ + if( length > ( 1 << 20 ) * 16 ) + return MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH; + + /* Compute the tweak. */ + ret = mbedtls_aes_crypt_ecb( &ctx->tweak, MBEDTLS_AES_ENCRYPT, + data_unit, tweak ); + if( ret != 0 ) + return( ret ); + + while( blocks-- ) + { + size_t i; + + if( leftover && ( mode == MBEDTLS_AES_DECRYPT ) && blocks == 0 ) + { + /* We are on the last block in a decrypt operation that has + * leftover bytes, so we need to use the next tweak for this block, + * and this tweak for the lefover bytes. Save the current tweak for + * the leftovers and then update the current tweak for use on this, + * the last full block. */ + memcpy( prev_tweak, tweak, sizeof( tweak ) ); + mbedtls_gf128mul_x_ble( tweak, tweak ); + } + + for( i = 0; i < 16; i++ ) + tmp[i] = input[i] ^ tweak[i]; + + ret = mbedtls_aes_crypt_ecb( &ctx->crypt, mode, tmp, tmp ); + if( ret != 0 ) + return( ret ); + + for( i = 0; i < 16; i++ ) + output[i] = tmp[i] ^ tweak[i]; + + /* Update the tweak for the next block. */ + mbedtls_gf128mul_x_ble( tweak, tweak ); + + output += 16; + input += 16; + } + + if( leftover ) + { + /* If we are on the leftover bytes in a decrypt operation, we need to + * use the previous tweak for these bytes (as saved in prev_tweak). */ + unsigned char *t = mode == MBEDTLS_AES_DECRYPT ? prev_tweak : tweak; + + /* We are now on the final part of the data unit, which doesn't divide + * evenly by 16. It's time for ciphertext stealing. */ + size_t i; + unsigned char *prev_output = output - 16; + + /* Copy ciphertext bytes from the previous block to our output for each + * byte of cyphertext we won't steal. At the same time, copy the + * remainder of the input for this final round (since the loop bounds + * are the same). */ + for( i = 0; i < leftover; i++ ) + { + output[i] = prev_output[i]; + tmp[i] = input[i] ^ t[i]; + } + + /* Copy ciphertext bytes from the previous block for input in this + * round. */ + for( ; i < 16; i++ ) + tmp[i] = prev_output[i] ^ t[i]; + + ret = mbedtls_aes_crypt_ecb( &ctx->crypt, mode, tmp, tmp ); + if( ret != 0 ) + return ret; + + /* Write the result back to the previous block, overriding the previous + * output we copied. */ + for( i = 0; i < 16; i++ ) + prev_output[i] = tmp[i] ^ t[i]; + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/* + * AES-CFB128 buffer encryption/decryption + */ +int mbedtls_aes_crypt_cfb128( mbedtls_aes_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int c; + size_t n = *iv_off; + + if( mode == MBEDTLS_AES_DECRYPT ) + { + while( length-- ) + { + if( n == 0 ) + mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, iv, iv ); + + c = *input++; + *output++ = (unsigned char)( c ^ iv[n] ); + iv[n] = (unsigned char) c; + + n = ( n + 1 ) & 0x0F; + } + } + else + { + while( length-- ) + { + if( n == 0 ) + mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, iv, iv ); + + iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ ); + + n = ( n + 1 ) & 0x0F; + } + } + + *iv_off = n; + + return( 0 ); +} + +/* + * AES-CFB8 buffer encryption/decryption + */ +int mbedtls_aes_crypt_cfb8( mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + unsigned char c; + unsigned char ov[17]; + + while( length-- ) + { + memcpy( ov, iv, 16 ); + mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, iv, iv ); + + if( mode == MBEDTLS_AES_DECRYPT ) + ov[16] = *input; + + c = *output++ = (unsigned char)( iv[0] ^ *input++ ); + + if( mode == MBEDTLS_AES_ENCRYPT ) + ov[16] = c; + + memcpy( iv, ov + 1, 16 ); + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_OFB) +/* + * AES-OFB (Output Feedback Mode) buffer encryption/decryption + */ +int mbedtls_aes_crypt_ofb( mbedtls_aes_context *ctx, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int ret = 0; + size_t n = *iv_off; + + while( length-- ) + { + if( n == 0 ) + { + ret = mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, iv, iv ); + if( ret != 0 ) + goto exit; + } + *output++ = *input++ ^ iv[n]; + + n = ( n + 1 ) & 0x0F; + } + + *iv_off = n; + +exit: + return( ret ); +} +#endif /* MBEDTLS_CIPHER_MODE_OFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/* + * AES-CTR buffer encryption/decryption + */ +int mbedtls_aes_crypt_ctr( mbedtls_aes_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ) +{ + int c, i; + size_t n = *nc_off; + + if ( n > 0x0F ) + return( MBEDTLS_ERR_AES_BAD_INPUT_DATA ); + + while( length-- ) + { + if( n == 0 ) { + mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, nonce_counter, stream_block ); + + for( i = 16; i > 0; i-- ) + if( ++nonce_counter[i - 1] != 0 ) + break; + } + c = *input++; + *output++ = (unsigned char)( c ^ stream_block[n] ); + + n = ( n + 1 ) & 0x0F; + } + + *nc_off = n; + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#endif /* !MBEDTLS_AES_ALT */ + +#if defined(MBEDTLS_SELF_TEST) +/* + * AES test vectors from: + * + * http://csrc.nist.gov/archive/aes/rijndael/rijndael-vals.zip + */ +static const unsigned char aes_test_ecb_dec[3][16] = +{ + { 0x44, 0x41, 0x6A, 0xC2, 0xD1, 0xF5, 0x3C, 0x58, + 0x33, 0x03, 0x91, 0x7E, 0x6B, 0xE9, 0xEB, 0xE0 }, + { 0x48, 0xE3, 0x1E, 0x9E, 0x25, 0x67, 0x18, 0xF2, + 0x92, 0x29, 0x31, 0x9C, 0x19, 0xF1, 0x5B, 0xA4 }, + { 0x05, 0x8C, 0xCF, 0xFD, 0xBB, 0xCB, 0x38, 0x2D, + 0x1F, 0x6F, 0x56, 0x58, 0x5D, 0x8A, 0x4A, 0xDE } +}; + +static const unsigned char aes_test_ecb_enc[3][16] = +{ + { 0xC3, 0x4C, 0x05, 0x2C, 0xC0, 0xDA, 0x8D, 0x73, + 0x45, 0x1A, 0xFE, 0x5F, 0x03, 0xBE, 0x29, 0x7F }, + { 0xF3, 0xF6, 0x75, 0x2A, 0xE8, 0xD7, 0x83, 0x11, + 0x38, 0xF0, 0x41, 0x56, 0x06, 0x31, 0xB1, 0x14 }, + { 0x8B, 0x79, 0xEE, 0xCC, 0x93, 0xA0, 0xEE, 0x5D, + 0xFF, 0x30, 0xB4, 0xEA, 0x21, 0x63, 0x6D, 0xA4 } +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const unsigned char aes_test_cbc_dec[3][16] = +{ + { 0xFA, 0xCA, 0x37, 0xE0, 0xB0, 0xC8, 0x53, 0x73, + 0xDF, 0x70, 0x6E, 0x73, 0xF7, 0xC9, 0xAF, 0x86 }, + { 0x5D, 0xF6, 0x78, 0xDD, 0x17, 0xBA, 0x4E, 0x75, + 0xB6, 0x17, 0x68, 0xC6, 0xAD, 0xEF, 0x7C, 0x7B }, + { 0x48, 0x04, 0xE1, 0x81, 0x8F, 0xE6, 0x29, 0x75, + 0x19, 0xA3, 0xE8, 0x8C, 0x57, 0x31, 0x04, 0x13 } +}; + +static const unsigned char aes_test_cbc_enc[3][16] = +{ + { 0x8A, 0x05, 0xFC, 0x5E, 0x09, 0x5A, 0xF4, 0x84, + 0x8A, 0x08, 0xD3, 0x28, 0xD3, 0x68, 0x8E, 0x3D }, + { 0x7B, 0xD9, 0x66, 0xD5, 0x3A, 0xD8, 0xC1, 0xBB, + 0x85, 0xD2, 0xAD, 0xFA, 0xE8, 0x7B, 0xB1, 0x04 }, + { 0xFE, 0x3C, 0x53, 0x65, 0x3E, 0x2F, 0x45, 0xB5, + 0x6F, 0xCD, 0x88, 0xB2, 0xCC, 0x89, 0x8F, 0xF0 } +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/* + * AES-CFB128 test vectors from: + * + * http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + */ +static const unsigned char aes_test_cfb128_key[3][32] = +{ + { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, + 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }, + { 0x8E, 0x73, 0xB0, 0xF7, 0xDA, 0x0E, 0x64, 0x52, + 0xC8, 0x10, 0xF3, 0x2B, 0x80, 0x90, 0x79, 0xE5, + 0x62, 0xF8, 0xEA, 0xD2, 0x52, 0x2C, 0x6B, 0x7B }, + { 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE, + 0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81, + 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7, + 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4 } +}; + +static const unsigned char aes_test_cfb128_iv[16] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F +}; + +static const unsigned char aes_test_cfb128_pt[64] = +{ + 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, + 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A, + 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C, + 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51, + 0x30, 0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11, + 0xE5, 0xFB, 0xC1, 0x19, 0x1A, 0x0A, 0x52, 0xEF, + 0xF6, 0x9F, 0x24, 0x45, 0xDF, 0x4F, 0x9B, 0x17, + 0xAD, 0x2B, 0x41, 0x7B, 0xE6, 0x6C, 0x37, 0x10 +}; + +static const unsigned char aes_test_cfb128_ct[3][64] = +{ + { 0x3B, 0x3F, 0xD9, 0x2E, 0xB7, 0x2D, 0xAD, 0x20, + 0x33, 0x34, 0x49, 0xF8, 0xE8, 0x3C, 0xFB, 0x4A, + 0xC8, 0xA6, 0x45, 0x37, 0xA0, 0xB3, 0xA9, 0x3F, + 0xCD, 0xE3, 0xCD, 0xAD, 0x9F, 0x1C, 0xE5, 0x8B, + 0x26, 0x75, 0x1F, 0x67, 0xA3, 0xCB, 0xB1, 0x40, + 0xB1, 0x80, 0x8C, 0xF1, 0x87, 0xA4, 0xF4, 0xDF, + 0xC0, 0x4B, 0x05, 0x35, 0x7C, 0x5D, 0x1C, 0x0E, + 0xEA, 0xC4, 0xC6, 0x6F, 0x9F, 0xF7, 0xF2, 0xE6 }, + { 0xCD, 0xC8, 0x0D, 0x6F, 0xDD, 0xF1, 0x8C, 0xAB, + 0x34, 0xC2, 0x59, 0x09, 0xC9, 0x9A, 0x41, 0x74, + 0x67, 0xCE, 0x7F, 0x7F, 0x81, 0x17, 0x36, 0x21, + 0x96, 0x1A, 0x2B, 0x70, 0x17, 0x1D, 0x3D, 0x7A, + 0x2E, 0x1E, 0x8A, 0x1D, 0xD5, 0x9B, 0x88, 0xB1, + 0xC8, 0xE6, 0x0F, 0xED, 0x1E, 0xFA, 0xC4, 0xC9, + 0xC0, 0x5F, 0x9F, 0x9C, 0xA9, 0x83, 0x4F, 0xA0, + 0x42, 0xAE, 0x8F, 0xBA, 0x58, 0x4B, 0x09, 0xFF }, + { 0xDC, 0x7E, 0x84, 0xBF, 0xDA, 0x79, 0x16, 0x4B, + 0x7E, 0xCD, 0x84, 0x86, 0x98, 0x5D, 0x38, 0x60, + 0x39, 0xFF, 0xED, 0x14, 0x3B, 0x28, 0xB1, 0xC8, + 0x32, 0x11, 0x3C, 0x63, 0x31, 0xE5, 0x40, 0x7B, + 0xDF, 0x10, 0x13, 0x24, 0x15, 0xE5, 0x4B, 0x92, + 0xA1, 0x3E, 0xD0, 0xA8, 0x26, 0x7A, 0xE2, 0xF9, + 0x75, 0xA3, 0x85, 0x74, 0x1A, 0xB9, 0xCE, 0xF8, + 0x20, 0x31, 0x62, 0x3D, 0x55, 0xB1, 0xE4, 0x71 } +}; +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_OFB) +/* + * AES-OFB test vectors from: + * + * https://csrc.nist.gov/publications/detail/sp/800-38a/final + */ +static const unsigned char aes_test_ofb_key[3][32] = +{ + { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, + 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }, + { 0x8E, 0x73, 0xB0, 0xF7, 0xDA, 0x0E, 0x64, 0x52, + 0xC8, 0x10, 0xF3, 0x2B, 0x80, 0x90, 0x79, 0xE5, + 0x62, 0xF8, 0xEA, 0xD2, 0x52, 0x2C, 0x6B, 0x7B }, + { 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE, + 0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81, + 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7, + 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4 } +}; + +static const unsigned char aes_test_ofb_iv[16] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F +}; + +static const unsigned char aes_test_ofb_pt[64] = +{ + 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, + 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A, + 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C, + 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51, + 0x30, 0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11, + 0xE5, 0xFB, 0xC1, 0x19, 0x1A, 0x0A, 0x52, 0xEF, + 0xF6, 0x9F, 0x24, 0x45, 0xDF, 0x4F, 0x9B, 0x17, + 0xAD, 0x2B, 0x41, 0x7B, 0xE6, 0x6C, 0x37, 0x10 +}; + +static const unsigned char aes_test_ofb_ct[3][64] = +{ + { 0x3B, 0x3F, 0xD9, 0x2E, 0xB7, 0x2D, 0xAD, 0x20, + 0x33, 0x34, 0x49, 0xF8, 0xE8, 0x3C, 0xFB, 0x4A, + 0x77, 0x89, 0x50, 0x8d, 0x16, 0x91, 0x8f, 0x03, + 0xf5, 0x3c, 0x52, 0xda, 0xc5, 0x4e, 0xd8, 0x25, + 0x97, 0x40, 0x05, 0x1e, 0x9c, 0x5f, 0xec, 0xf6, + 0x43, 0x44, 0xf7, 0xa8, 0x22, 0x60, 0xed, 0xcc, + 0x30, 0x4c, 0x65, 0x28, 0xf6, 0x59, 0xc7, 0x78, + 0x66, 0xa5, 0x10, 0xd9, 0xc1, 0xd6, 0xae, 0x5e }, + { 0xCD, 0xC8, 0x0D, 0x6F, 0xDD, 0xF1, 0x8C, 0xAB, + 0x34, 0xC2, 0x59, 0x09, 0xC9, 0x9A, 0x41, 0x74, + 0xfc, 0xc2, 0x8b, 0x8d, 0x4c, 0x63, 0x83, 0x7c, + 0x09, 0xe8, 0x17, 0x00, 0xc1, 0x10, 0x04, 0x01, + 0x8d, 0x9a, 0x9a, 0xea, 0xc0, 0xf6, 0x59, 0x6f, + 0x55, 0x9c, 0x6d, 0x4d, 0xaf, 0x59, 0xa5, 0xf2, + 0x6d, 0x9f, 0x20, 0x08, 0x57, 0xca, 0x6c, 0x3e, + 0x9c, 0xac, 0x52, 0x4b, 0xd9, 0xac, 0xc9, 0x2a }, + { 0xDC, 0x7E, 0x84, 0xBF, 0xDA, 0x79, 0x16, 0x4B, + 0x7E, 0xCD, 0x84, 0x86, 0x98, 0x5D, 0x38, 0x60, + 0x4f, 0xeb, 0xdc, 0x67, 0x40, 0xd2, 0x0b, 0x3a, + 0xc8, 0x8f, 0x6a, 0xd8, 0x2a, 0x4f, 0xb0, 0x8d, + 0x71, 0xab, 0x47, 0xa0, 0x86, 0xe8, 0x6e, 0xed, + 0xf3, 0x9d, 0x1c, 0x5b, 0xba, 0x97, 0xc4, 0x08, + 0x01, 0x26, 0x14, 0x1d, 0x67, 0xf3, 0x7b, 0xe8, + 0x53, 0x8f, 0x5a, 0x8b, 0xe7, 0x40, 0xe4, 0x84 } +}; +#endif /* MBEDTLS_CIPHER_MODE_OFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/* + * AES-CTR test vectors from: + * + * http://www.faqs.org/rfcs/rfc3686.html + */ + +static const unsigned char aes_test_ctr_key[3][16] = +{ + { 0xAE, 0x68, 0x52, 0xF8, 0x12, 0x10, 0x67, 0xCC, + 0x4B, 0xF7, 0xA5, 0x76, 0x55, 0x77, 0xF3, 0x9E }, + { 0x7E, 0x24, 0x06, 0x78, 0x17, 0xFA, 0xE0, 0xD7, + 0x43, 0xD6, 0xCE, 0x1F, 0x32, 0x53, 0x91, 0x63 }, + { 0x76, 0x91, 0xBE, 0x03, 0x5E, 0x50, 0x20, 0xA8, + 0xAC, 0x6E, 0x61, 0x85, 0x29, 0xF9, 0xA0, 0xDC } +}; + +static const unsigned char aes_test_ctr_nonce_counter[3][16] = +{ + { 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, + { 0x00, 0x6C, 0xB6, 0xDB, 0xC0, 0x54, 0x3B, 0x59, + 0xDA, 0x48, 0xD9, 0x0B, 0x00, 0x00, 0x00, 0x01 }, + { 0x00, 0xE0, 0x01, 0x7B, 0x27, 0x77, 0x7F, 0x3F, + 0x4A, 0x17, 0x86, 0xF0, 0x00, 0x00, 0x00, 0x01 } +}; + +static const unsigned char aes_test_ctr_pt[3][48] = +{ + { 0x53, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x62, + 0x6C, 0x6F, 0x63, 0x6B, 0x20, 0x6D, 0x73, 0x67 }, + + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F }, + + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23 } +}; + +static const unsigned char aes_test_ctr_ct[3][48] = +{ + { 0xE4, 0x09, 0x5D, 0x4F, 0xB7, 0xA7, 0xB3, 0x79, + 0x2D, 0x61, 0x75, 0xA3, 0x26, 0x13, 0x11, 0xB8 }, + { 0x51, 0x04, 0xA1, 0x06, 0x16, 0x8A, 0x72, 0xD9, + 0x79, 0x0D, 0x41, 0xEE, 0x8E, 0xDA, 0xD3, 0x88, + 0xEB, 0x2E, 0x1E, 0xFC, 0x46, 0xDA, 0x57, 0xC8, + 0xFC, 0xE6, 0x30, 0xDF, 0x91, 0x41, 0xBE, 0x28 }, + { 0xC1, 0xCF, 0x48, 0xA8, 0x9F, 0x2F, 0xFD, 0xD9, + 0xCF, 0x46, 0x52, 0xE9, 0xEF, 0xDB, 0x72, 0xD7, + 0x45, 0x40, 0xA4, 0x2B, 0xDE, 0x6D, 0x78, 0x36, + 0xD5, 0x9A, 0x5C, 0xEA, 0xAE, 0xF3, 0x10, 0x53, + 0x25, 0xB2, 0x07, 0x2F } +}; + +static const int aes_test_ctr_len[3] = + { 16, 32, 36 }; +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_CIPHER_MODE_XTS) +/* + * AES-XTS test vectors from: + * + * IEEE P1619/D16 Annex B + * https://web.archive.org/web/20150629024421/http://grouper.ieee.org/groups/1619/email/pdf00086.pdf + * (Archived from original at http://grouper.ieee.org/groups/1619/email/pdf00086.pdf) + */ +static const unsigned char aes_test_xts_key[][32] = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 }, + { 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, + 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 }, +}; + +static const unsigned char aes_test_xts_pt32[][32] = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 }, + { 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 }, +}; + +static const unsigned char aes_test_xts_ct32[][32] = +{ + { 0x91, 0x7c, 0xf6, 0x9e, 0xbd, 0x68, 0xb2, 0xec, + 0x9b, 0x9f, 0xe9, 0xa3, 0xea, 0xdd, 0xa6, 0x92, + 0xcd, 0x43, 0xd2, 0xf5, 0x95, 0x98, 0xed, 0x85, + 0x8c, 0x02, 0xc2, 0x65, 0x2f, 0xbf, 0x92, 0x2e }, + { 0xc4, 0x54, 0x18, 0x5e, 0x6a, 0x16, 0x93, 0x6e, + 0x39, 0x33, 0x40, 0x38, 0xac, 0xef, 0x83, 0x8b, + 0xfb, 0x18, 0x6f, 0xff, 0x74, 0x80, 0xad, 0xc4, + 0x28, 0x93, 0x82, 0xec, 0xd6, 0xd3, 0x94, 0xf0 }, + { 0xaf, 0x85, 0x33, 0x6b, 0x59, 0x7a, 0xfc, 0x1a, + 0x90, 0x0b, 0x2e, 0xb2, 0x1e, 0xc9, 0x49, 0xd2, + 0x92, 0xdf, 0x4c, 0x04, 0x7e, 0x0b, 0x21, 0x53, + 0x21, 0x86, 0xa5, 0x97, 0x1a, 0x22, 0x7a, 0x89 }, +}; + +static const unsigned char aes_test_xts_data_unit[][16] = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x33, 0x33, 0x33, 0x33, 0x33, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, +}; + +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +/* + * Checkup routine + */ +int mbedtls_aes_self_test( int verbose ) +{ + int ret = 0, i, j, u, mode; + unsigned int keybits; + unsigned char key[32]; + unsigned char buf[64]; + const unsigned char *aes_tests; +#if defined(MBEDTLS_CIPHER_MODE_CBC) || defined(MBEDTLS_CIPHER_MODE_CFB) + unsigned char iv[16]; +#endif +#if defined(MBEDTLS_CIPHER_MODE_CBC) + unsigned char prv[16]; +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) || defined(MBEDTLS_CIPHER_MODE_CFB) || \ + defined(MBEDTLS_CIPHER_MODE_OFB) + size_t offset; +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) || defined(MBEDTLS_CIPHER_MODE_XTS) + int len; +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + unsigned char nonce_counter[16]; + unsigned char stream_block[16]; +#endif + mbedtls_aes_context ctx; + + memset( key, 0, 32 ); + mbedtls_aes_init( &ctx ); + + /* + * ECB mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + keybits = 128 + u * 64; + mode = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " AES-ECB-%3d (%s): ", keybits, + ( mode == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" ); + + memset( buf, 0, 16 ); + + if( mode == MBEDTLS_AES_DECRYPT ) + { + ret = mbedtls_aes_setkey_dec( &ctx, key, keybits ); + aes_tests = aes_test_ecb_dec[u]; + } + else + { + ret = mbedtls_aes_setkey_enc( &ctx, key, keybits ); + aes_tests = aes_test_ecb_enc[u]; + } + + /* + * AES-192 is an optional feature that may be unavailable when + * there is an alternative underlying implementation i.e. when + * MBEDTLS_AES_ALT is defined. + */ + if( ret == MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE && keybits == 192 ) + { + mbedtls_printf( "skipped\n" ); + continue; + } + else if( ret != 0 ) + { + goto exit; + } + + for( j = 0; j < 10000; j++ ) + { + ret = mbedtls_aes_crypt_ecb( &ctx, mode, buf, buf ); + if( ret != 0 ) + goto exit; + } + + if( memcmp( buf, aes_tests, 16 ) != 0 ) + { + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + /* + * CBC mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + keybits = 128 + u * 64; + mode = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " AES-CBC-%3d (%s): ", keybits, + ( mode == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" ); + + memset( iv , 0, 16 ); + memset( prv, 0, 16 ); + memset( buf, 0, 16 ); + + if( mode == MBEDTLS_AES_DECRYPT ) + { + ret = mbedtls_aes_setkey_dec( &ctx, key, keybits ); + aes_tests = aes_test_cbc_dec[u]; + } + else + { + ret = mbedtls_aes_setkey_enc( &ctx, key, keybits ); + aes_tests = aes_test_cbc_enc[u]; + } + + /* + * AES-192 is an optional feature that may be unavailable when + * there is an alternative underlying implementation i.e. when + * MBEDTLS_AES_ALT is defined. + */ + if( ret == MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE && keybits == 192 ) + { + mbedtls_printf( "skipped\n" ); + continue; + } + else if( ret != 0 ) + { + goto exit; + } + + for( j = 0; j < 10000; j++ ) + { + if( mode == MBEDTLS_AES_ENCRYPT ) + { + unsigned char tmp[16]; + + memcpy( tmp, prv, 16 ); + memcpy( prv, buf, 16 ); + memcpy( buf, tmp, 16 ); + } + + ret = mbedtls_aes_crypt_cbc( &ctx, mode, 16, iv, buf, buf ); + if( ret != 0 ) + goto exit; + + } + + if( memcmp( buf, aes_tests, 16 ) != 0 ) + { + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) + /* + * CFB128 mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + keybits = 128 + u * 64; + mode = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " AES-CFB128-%3d (%s): ", keybits, + ( mode == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" ); + + memcpy( iv, aes_test_cfb128_iv, 16 ); + memcpy( key, aes_test_cfb128_key[u], keybits / 8 ); + + offset = 0; + ret = mbedtls_aes_setkey_enc( &ctx, key, keybits ); + /* + * AES-192 is an optional feature that may be unavailable when + * there is an alternative underlying implementation i.e. when + * MBEDTLS_AES_ALT is defined. + */ + if( ret == MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE && keybits == 192 ) + { + mbedtls_printf( "skipped\n" ); + continue; + } + else if( ret != 0 ) + { + goto exit; + } + + if( mode == MBEDTLS_AES_DECRYPT ) + { + memcpy( buf, aes_test_cfb128_ct[u], 64 ); + aes_tests = aes_test_cfb128_pt; + } + else + { + memcpy( buf, aes_test_cfb128_pt, 64 ); + aes_tests = aes_test_cfb128_ct[u]; + } + + ret = mbedtls_aes_crypt_cfb128( &ctx, mode, 64, &offset, iv, buf, buf ); + if( ret != 0 ) + goto exit; + + if( memcmp( buf, aes_tests, 64 ) != 0 ) + { + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_OFB) + /* + * OFB mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + keybits = 128 + u * 64; + mode = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " AES-OFB-%3d (%s): ", keybits, + ( mode == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" ); + + memcpy( iv, aes_test_ofb_iv, 16 ); + memcpy( key, aes_test_ofb_key[u], keybits / 8 ); + + offset = 0; + ret = mbedtls_aes_setkey_enc( &ctx, key, keybits ); + /* + * AES-192 is an optional feature that may be unavailable when + * there is an alternative underlying implementation i.e. when + * MBEDTLS_AES_ALT is defined. + */ + if( ret == MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE && keybits == 192 ) + { + mbedtls_printf( "skipped\n" ); + continue; + } + else if( ret != 0 ) + { + goto exit; + } + + if( mode == MBEDTLS_AES_DECRYPT ) + { + memcpy( buf, aes_test_ofb_ct[u], 64 ); + aes_tests = aes_test_ofb_pt; + } + else + { + memcpy( buf, aes_test_ofb_pt, 64 ); + aes_tests = aes_test_ofb_ct[u]; + } + + ret = mbedtls_aes_crypt_ofb( &ctx, 64, &offset, iv, buf, buf ); + if( ret != 0 ) + goto exit; + + if( memcmp( buf, aes_tests, 64 ) != 0 ) + { + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); +#endif /* MBEDTLS_CIPHER_MODE_OFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) + /* + * CTR mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + mode = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " AES-CTR-128 (%s): ", + ( mode == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" ); + + memcpy( nonce_counter, aes_test_ctr_nonce_counter[u], 16 ); + memcpy( key, aes_test_ctr_key[u], 16 ); + + offset = 0; + if( ( ret = mbedtls_aes_setkey_enc( &ctx, key, 128 ) ) != 0 ) + goto exit; + + len = aes_test_ctr_len[u]; + + if( mode == MBEDTLS_AES_DECRYPT ) + { + memcpy( buf, aes_test_ctr_ct[u], len ); + aes_tests = aes_test_ctr_pt[u]; + } + else + { + memcpy( buf, aes_test_ctr_pt[u], len ); + aes_tests = aes_test_ctr_ct[u]; + } + + ret = mbedtls_aes_crypt_ctr( &ctx, len, &offset, nonce_counter, + stream_block, buf, buf ); + if( ret != 0 ) + goto exit; + + if( memcmp( buf, aes_tests, len ) != 0 ) + { + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_CIPHER_MODE_XTS) + { + static const int num_tests = + sizeof(aes_test_xts_key) / sizeof(*aes_test_xts_key); + mbedtls_aes_xts_context ctx_xts; + + /* + * XTS mode + */ + mbedtls_aes_xts_init( &ctx_xts ); + + for( i = 0; i < num_tests << 1; i++ ) + { + const unsigned char *data_unit; + u = i >> 1; + mode = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " AES-XTS-128 (%s): ", + ( mode == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" ); + + memset( key, 0, sizeof( key ) ); + memcpy( key, aes_test_xts_key[u], 32 ); + data_unit = aes_test_xts_data_unit[u]; + + len = sizeof( *aes_test_xts_ct32 ); + + if( mode == MBEDTLS_AES_DECRYPT ) + { + ret = mbedtls_aes_xts_setkey_dec( &ctx_xts, key, 256 ); + if( ret != 0) + goto exit; + memcpy( buf, aes_test_xts_ct32[u], len ); + aes_tests = aes_test_xts_pt32[u]; + } + else + { + ret = mbedtls_aes_xts_setkey_enc( &ctx_xts, key, 256 ); + if( ret != 0) + goto exit; + memcpy( buf, aes_test_xts_pt32[u], len ); + aes_tests = aes_test_xts_ct32[u]; + } + + + ret = mbedtls_aes_crypt_xts( &ctx_xts, mode, len, data_unit, + buf, buf ); + if( ret != 0 ) + goto exit; + + if( memcmp( buf, aes_tests, len ) != 0 ) + { + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + mbedtls_aes_xts_free( &ctx_xts ); + } +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + + ret = 0; + +exit: + if( ret != 0 && verbose != 0 ) + mbedtls_printf( "failed\n" ); + + mbedtls_aes_free( &ctx ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_AES_C */ diff --git a/common/mbedtls/aes.h b/common/mbedtls/aes.h new file mode 100644 index 00000000..9af6bb72 --- /dev/null +++ b/common/mbedtls/aes.h @@ -0,0 +1,628 @@ +/** + * \file aes.h + * + * \brief This file contains AES definitions and functions. + * + * The Advanced Encryption Standard (AES) specifies a FIPS-approved + * cryptographic algorithm that can be used to protect electronic + * data. + * + * The AES algorithm is a symmetric block cipher that can + * encrypt and decrypt information. For more information, see + * FIPS Publication 197: Advanced Encryption Standard and + * ISO/IEC 18033-2:2006: Information technology -- Security + * techniques -- Encryption algorithms -- Part 2: Asymmetric + * ciphers. + * + * The AES-XTS block mode is standardized by NIST SP 800-38E + * + * and described in detail by IEEE P1619 + * . + */ + +/* Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved. + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_AES_H +#define MBEDTLS_AES_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +/* padlock.c and aesni.c rely on these values! */ +#define MBEDTLS_AES_ENCRYPT 1 /**< AES encryption. */ +#define MBEDTLS_AES_DECRYPT 0 /**< AES decryption. */ + +/* Error codes in range 0x0020-0x0022 */ +#define MBEDTLS_ERR_AES_INVALID_KEY_LENGTH -0x0020 /**< Invalid key length. */ +#define MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH -0x0022 /**< Invalid data input length. */ + +/* Error codes in range 0x0021-0x0025 */ +#define MBEDTLS_ERR_AES_BAD_INPUT_DATA -0x0021 /**< Invalid input data. */ +#define MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE -0x0023 /**< Feature not available. For example, an unsupported AES key size. */ +#define MBEDTLS_ERR_AES_HW_ACCEL_FAILED -0x0025 /**< AES hardware accelerator failed. */ + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_AES_ALT) +// Regular implementation +// + +/** + * \brief The AES context-type definition. + */ +typedef struct mbedtls_aes_context +{ + int nr; /*!< The number of rounds. */ + uint32_t *rk; /*!< AES round keys. */ + uint32_t buf[68]; /*!< Unaligned data buffer. This buffer can + hold 32 extra Bytes, which can be used for + one of the following purposes: +
  • Alignment if VIA padlock is + used.
  • +
  • Simplifying key expansion in the 256-bit + case by generating an extra round key. +
*/ +} +mbedtls_aes_context; + +#if defined(MBEDTLS_CIPHER_MODE_XTS) +/** + * \brief The AES XTS context-type definition. + */ +typedef struct mbedtls_aes_xts_context +{ + mbedtls_aes_context crypt; /*!< The AES context to use for AES block + encryption or decryption. */ + mbedtls_aes_context tweak; /*!< The AES context used for tweak + computation. */ +} mbedtls_aes_xts_context; +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +#else /* MBEDTLS_AES_ALT */ +#include "aes_alt.h" +#endif /* MBEDTLS_AES_ALT */ + +/** + * \brief This function initializes the specified AES context. + * + * It must be the first API called before using + * the context. + * + * \param ctx The AES context to initialize. + */ +void mbedtls_aes_init( mbedtls_aes_context *ctx ); + +/** + * \brief This function releases and clears the specified AES context. + * + * \param ctx The AES context to clear. + */ +void mbedtls_aes_free( mbedtls_aes_context *ctx ); + +#if defined(MBEDTLS_CIPHER_MODE_XTS) +/** + * \brief This function initializes the specified AES XTS context. + * + * It must be the first API called before using + * the context. + * + * \param ctx The AES XTS context to initialize. + */ +void mbedtls_aes_xts_init( mbedtls_aes_xts_context *ctx ); + +/** + * \brief This function releases and clears the specified AES XTS context. + * + * \param ctx The AES XTS context to clear. + */ +void mbedtls_aes_xts_free( mbedtls_aes_xts_context *ctx ); +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +/** + * \brief This function sets the encryption key. + * + * \param ctx The AES context to which the key should be bound. + * \param key The encryption key. + * \param keybits The size of data passed in bits. Valid options are: + *
  • 128 bits
  • + *
  • 192 bits
  • + *
  • 256 bits
+ * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH on failure. + */ +int mbedtls_aes_setkey_enc( mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits ); + +/** + * \brief This function sets the decryption key. + * + * \param ctx The AES context to which the key should be bound. + * \param key The decryption key. + * \param keybits The size of data passed. Valid options are: + *
  • 128 bits
  • + *
  • 192 bits
  • + *
  • 256 bits
+ * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH on failure. + */ +int mbedtls_aes_setkey_dec( mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits ); + +#if defined(MBEDTLS_CIPHER_MODE_XTS) +/** + * \brief This function prepares an XTS context for encryption and + * sets the encryption key. + * + * \param ctx The AES XTS context to which the key should be bound. + * \param key The encryption key. This is comprised of the XTS key1 + * concatenated with the XTS key2. + * \param keybits The size of \p key passed in bits. Valid options are: + *
  • 256 bits (each of key1 and key2 is a 128-bit key)
  • + *
  • 512 bits (each of key1 and key2 is a 256-bit key)
+ * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH on failure. + */ +int mbedtls_aes_xts_setkey_enc( mbedtls_aes_xts_context *ctx, + const unsigned char *key, + unsigned int keybits ); + +/** + * \brief This function prepares an XTS context for decryption and + * sets the decryption key. + * + * \param ctx The AES XTS context to which the key should be bound. + * \param key The decryption key. This is comprised of the XTS key1 + * concatenated with the XTS key2. + * \param keybits The size of \p key passed in bits. Valid options are: + *
  • 256 bits (each of key1 and key2 is a 128-bit key)
  • + *
  • 512 bits (each of key1 and key2 is a 256-bit key)
+ * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_AES_INVALID_KEY_LENGTH on failure. + */ +int mbedtls_aes_xts_setkey_dec( mbedtls_aes_xts_context *ctx, + const unsigned char *key, + unsigned int keybits ); +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +/** + * \brief This function performs an AES single-block encryption or + * decryption operation. + * + * It performs the operation defined in the \p mode parameter + * (encrypt or decrypt), on the input data buffer defined in + * the \p input parameter. + * + * mbedtls_aes_init(), and either mbedtls_aes_setkey_enc() or + * mbedtls_aes_setkey_dec() must be called before the first + * call to this API with the same context. + * + * \param ctx The AES context to use for encryption or decryption. + * \param mode The AES operation: #MBEDTLS_AES_ENCRYPT or + * #MBEDTLS_AES_DECRYPT. + * \param input The 16-Byte buffer holding the input data. + * \param output The 16-Byte buffer holding the output data. + + * \return \c 0 on success. + */ +int mbedtls_aes_crypt_ecb( mbedtls_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/** + * \brief This function performs an AES-CBC encryption or decryption operation + * on full blocks. + * + * It performs the operation defined in the \p mode + * parameter (encrypt/decrypt), on the input data buffer defined in + * the \p input parameter. + * + * It can be called as many times as needed, until all the input + * data is processed. mbedtls_aes_init(), and either + * mbedtls_aes_setkey_enc() or mbedtls_aes_setkey_dec() must be called + * before the first call to this API with the same context. + * + * \note This function operates on aligned blocks, that is, the input size + * must be a multiple of the AES block size of 16 Bytes. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the same function again on the next + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If you need to retain the contents of the IV, you should + * either save it manually or use the cipher module instead. + * + * + * \param ctx The AES context to use for encryption or decryption. + * \param mode The AES operation: #MBEDTLS_AES_ENCRYPT or + * #MBEDTLS_AES_DECRYPT. + * \param length The length of the input data in Bytes. This must be a + * multiple of the block size (16 Bytes). + * \param iv Initialization vector (updated after use). + * \param input The buffer holding the input data. + * \param output The buffer holding the output data. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH + * on failure. + */ +int mbedtls_aes_crypt_cbc( mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_XTS) +/** + * \brief This function performs an AES-XTS encryption or decryption + * operation for an entire XTS data unit. + * + * AES-XTS encrypts or decrypts blocks based on their location as + * defined by a data unit number. The data unit number must be + * provided by \p data_unit. + * + * NIST SP 800-38E limits the maximum size of a data unit to 2^20 + * AES blocks. If the data unit is larger than this, this function + * returns #MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH. + * + * \param ctx The AES XTS context to use for AES XTS operations. + * \param mode The AES operation: #MBEDTLS_AES_ENCRYPT or + * #MBEDTLS_AES_DECRYPT. + * \param length The length of a data unit in bytes. This can be any + * length between 16 bytes and 2^24 bytes inclusive + * (between 1 and 2^20 block cipher blocks). + * \param data_unit The address of the data unit encoded as an array of 16 + * bytes in little-endian format. For disk encryption, this + * is typically the index of the block device sector that + * contains the data. + * \param input The buffer holding the input data (which is an entire + * data unit). This function reads \p length bytes from \p + * input. + * \param output The buffer holding the output data (which is an entire + * data unit). This function writes \p length bytes to \p + * output. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH if \p length is + * smaller than an AES block in size (16 bytes) or if \p + * length is larger than 2^20 blocks (16 MiB). + */ +int mbedtls_aes_crypt_xts( mbedtls_aes_xts_context *ctx, + int mode, + size_t length, + const unsigned char data_unit[16], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/** + * \brief This function performs an AES-CFB128 encryption or decryption + * operation. + * + * It performs the operation defined in the \p mode + * parameter (encrypt or decrypt), on the input data buffer + * defined in the \p input parameter. + * + * For CFB, you must set up the context with mbedtls_aes_setkey_enc(), + * regardless of whether you are performing an encryption or decryption + * operation, that is, regardless of the \p mode parameter. This is + * because CFB mode uses the same key schedule for encryption and + * decryption. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the same function again on the next + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If you need to retain the contents of the + * IV, you must either save it manually or use the cipher + * module instead. + * + * + * \param ctx The AES context to use for encryption or decryption. + * \param mode The AES operation: #MBEDTLS_AES_ENCRYPT or + * #MBEDTLS_AES_DECRYPT. + * \param length The length of the input data. + * \param iv_off The offset in IV (updated after use). + * \param iv The initialization vector (updated after use). + * \param input The buffer holding the input data. + * \param output The buffer holding the output data. + * + * \return \c 0 on success. + */ +int mbedtls_aes_crypt_cfb128( mbedtls_aes_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); + +/** + * \brief This function performs an AES-CFB8 encryption or decryption + * operation. + * + * It performs the operation defined in the \p mode + * parameter (encrypt/decrypt), on the input data buffer defined + * in the \p input parameter. + * + * Due to the nature of CFB, you must use the same key schedule for + * both encryption and decryption operations. Therefore, you must + * use the context initialized with mbedtls_aes_setkey_enc() for + * both #MBEDTLS_AES_ENCRYPT and #MBEDTLS_AES_DECRYPT. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the same function again on the next + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * + * \param ctx The AES context to use for encryption or decryption. + * \param mode The AES operation: #MBEDTLS_AES_ENCRYPT or + * #MBEDTLS_AES_DECRYPT + * \param length The length of the input data. + * \param iv The initialization vector (updated after use). + * \param input The buffer holding the input data. + * \param output The buffer holding the output data. + * + * \return \c 0 on success. + */ +int mbedtls_aes_crypt_cfb8( mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); +#endif /*MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_OFB) +/** + * \brief This function performs an AES-OFB (Output Feedback Mode) + * encryption or decryption operation. + * + * For OFB, you must set up the context with + * mbedtls_aes_setkey_enc(), regardless of whether you are + * performing an encryption or decryption operation. This is + * because OFB mode uses the same key schedule for encryption and + * decryption. + * + * The OFB operation is identical for encryption or decryption, + * therefore no operation mode needs to be specified. + * + * \note Upon exit, the content of iv, the Initialisation Vector, is + * updated so that you can call the same function again on the next + * block(s) of data and get the same result as if it was encrypted + * in one call. This allows a "streaming" usage, by initialising + * iv_off to 0 before the first call, and preserving its value + * between calls. + * + * For non-streaming use, the iv should be initialised on each call + * to a unique value, and iv_off set to 0 on each call. + * + * If you need to retain the contents of the initialisation vector, + * you must either save it manually or use the cipher module + * instead. + * + * \warning For the OFB mode, the initialisation vector must be unique + * every encryption operation. Reuse of an initialisation vector + * will compromise security. + * + * \param ctx The AES context to use for encryption or decryption. + * \param length The length of the input data. + * \param iv_off The offset in IV (updated after use). + * \param iv The initialization vector (updated after use). + * \param input The buffer holding the input data. + * \param output The buffer holding the output data. + * + * \return \c 0 on success. + */ +int mbedtls_aes_crypt_ofb( mbedtls_aes_context *ctx, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); + +#endif /* MBEDTLS_CIPHER_MODE_OFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/** + * \brief This function performs an AES-CTR encryption or decryption + * operation. + * + * This function performs the operation defined in the \p mode + * parameter (encrypt/decrypt), on the input data buffer + * defined in the \p input parameter. + * + * Due to the nature of CTR, you must use the same key schedule + * for both encryption and decryption operations. Therefore, you + * must use the context initialized with mbedtls_aes_setkey_enc() + * for both #MBEDTLS_AES_ENCRYPT and #MBEDTLS_AES_DECRYPT. + * + * \warning You must never reuse a nonce value with the same key. Doing so + * would void the encryption for the two messages encrypted with + * the same nonce and key. + * + * There are two common strategies for managing nonces with CTR: + * + * 1. You can handle everything as a single message processed over + * successive calls to this function. In that case, you want to + * set \p nonce_counter and \p nc_off to 0 for the first call, and + * then preserve the values of \p nonce_counter, \p nc_off and \p + * stream_block across calls to this function as they will be + * updated by this function. + * + * With this strategy, you must not encrypt more than 2**128 + * blocks of data with the same key. + * + * 2. You can encrypt separate messages by dividing the \p + * nonce_counter buffer in two areas: the first one used for a + * per-message nonce, handled by yourself, and the second one + * updated by this function internally. + * + * For example, you might reserve the first 12 bytes for the + * per-message nonce, and the last 4 bytes for internal use. In that + * case, before calling this function on a new message you need to + * set the first 12 bytes of \p nonce_counter to your chosen nonce + * value, the last 4 to 0, and \p nc_off to 0 (which will cause \p + * stream_block to be ignored). That way, you can encrypt at most + * 2**96 messages of up to 2**32 blocks each with the same key. + * + * The per-message nonce (or information sufficient to reconstruct + * it) needs to be communicated with the ciphertext and must be unique. + * The recommended way to ensure uniqueness is to use a message + * counter. An alternative is to generate random nonces, but this + * limits the number of messages that can be securely encrypted: + * for example, with 96-bit random nonces, you should not encrypt + * more than 2**32 messages with the same key. + * + * Note that for both stategies, sizes are measured in blocks and + * that an AES block is 16 bytes. + * + * \warning Upon return, \p stream_block contains sensitive data. Its + * content must not be written to insecure storage and should be + * securely discarded as soon as it's no longer needed. + * + * \param ctx The AES context to use for encryption or decryption. + * \param length The length of the input data. + * \param nc_off The offset in the current \p stream_block, for + * resuming within the current cipher stream. The + * offset pointer should be 0 at the start of a stream. + * \param nonce_counter The 128-bit nonce and counter. + * \param stream_block The saved stream block for resuming. This is + * overwritten by the function. + * \param input The buffer holding the input data. + * \param output The buffer holding the output data. + * + * \return \c 0 on success. + */ +int mbedtls_aes_crypt_ctr( mbedtls_aes_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +/** + * \brief Internal AES block encryption function. This is only + * exposed to allow overriding it using + * \c MBEDTLS_AES_ENCRYPT_ALT. + * + * \param ctx The AES context to use for encryption. + * \param input The plaintext block. + * \param output The output (ciphertext) block. + * + * \return \c 0 on success. + */ +int mbedtls_internal_aes_encrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ); + +/** + * \brief Internal AES block decryption function. This is only + * exposed to allow overriding it using see + * \c MBEDTLS_AES_DECRYPT_ALT. + * + * \param ctx The AES context to use for decryption. + * \param input The ciphertext block. + * \param output The output (plaintext) block. + * + * \return \c 0 on success. + */ +int mbedtls_internal_aes_decrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ); + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief Deprecated internal AES block encryption function + * without return value. + * + * \deprecated Superseded by mbedtls_aes_encrypt_ext() in 2.5.0. + * + * \param ctx The AES context to use for encryption. + * \param input Plaintext block. + * \param output Output (ciphertext) block. + */ +MBEDTLS_DEPRECATED void mbedtls_aes_encrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ); + +/** + * \brief Deprecated internal AES block decryption function + * without return value. + * + * \deprecated Superseded by mbedtls_aes_decrypt_ext() in 2.5.0. + * + * \param ctx The AES context to use for decryption. + * \param input Ciphertext block. + * \param output Output (plaintext) block. + */ +MBEDTLS_DEPRECATED void mbedtls_aes_decrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ); + +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +/** + * \brief Checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_aes_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* aes.h */ diff --git a/common/mbedtls/arc4.c b/common/mbedtls/arc4.c new file mode 100644 index 00000000..22992dd4 --- /dev/null +++ b/common/mbedtls/arc4.c @@ -0,0 +1,203 @@ +/* + * An implementation of the ARCFOUR algorithm + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The ARCFOUR algorithm was publicly disclosed on 94/09. + * + * http://groups.google.com/group/sci.crypt/msg/10a300c9d21afca0 + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ARC4_C) + +#include "mbedtls/arc4.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_ARC4_ALT) + +void mbedtls_arc4_init( mbedtls_arc4_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_arc4_context ) ); +} + +void mbedtls_arc4_free( mbedtls_arc4_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_arc4_context ) ); +} + +/* + * ARC4 key schedule + */ +void mbedtls_arc4_setup( mbedtls_arc4_context *ctx, const unsigned char *key, + unsigned int keylen ) +{ + int i, j, a; + unsigned int k; + unsigned char *m; + + ctx->x = 0; + ctx->y = 0; + m = ctx->m; + + for( i = 0; i < 256; i++ ) + m[i] = (unsigned char) i; + + j = k = 0; + + for( i = 0; i < 256; i++, k++ ) + { + if( k >= keylen ) k = 0; + + a = m[i]; + j = ( j + a + key[k] ) & 0xFF; + m[i] = m[j]; + m[j] = (unsigned char) a; + } +} + +/* + * ARC4 cipher function + */ +int mbedtls_arc4_crypt( mbedtls_arc4_context *ctx, size_t length, const unsigned char *input, + unsigned char *output ) +{ + int x, y, a, b; + size_t i; + unsigned char *m; + + x = ctx->x; + y = ctx->y; + m = ctx->m; + + for( i = 0; i < length; i++ ) + { + x = ( x + 1 ) & 0xFF; a = m[x]; + y = ( y + a ) & 0xFF; b = m[y]; + + m[x] = (unsigned char) b; + m[y] = (unsigned char) a; + + output[i] = (unsigned char) + ( input[i] ^ m[(unsigned char)( a + b )] ); + } + + ctx->x = x; + ctx->y = y; + + return( 0 ); +} + +#endif /* !MBEDTLS_ARC4_ALT */ + +#if defined(MBEDTLS_SELF_TEST) +/* + * ARC4 tests vectors as posted by Eric Rescorla in sep. 1994: + * + * http://groups.google.com/group/comp.security.misc/msg/10a300c9d21afca0 + */ +static const unsigned char arc4_test_key[3][8] = +{ + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }, + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } +}; + +static const unsigned char arc4_test_pt[3][8] = +{ + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } +}; + +static const unsigned char arc4_test_ct[3][8] = +{ + { 0x75, 0xB7, 0x87, 0x80, 0x99, 0xE0, 0xC5, 0x96 }, + { 0x74, 0x94, 0xC2, 0xE7, 0x10, 0x4B, 0x08, 0x79 }, + { 0xDE, 0x18, 0x89, 0x41, 0xA3, 0x37, 0x5D, 0x3A } +}; + +/* + * Checkup routine + */ +int mbedtls_arc4_self_test( int verbose ) +{ + int i, ret = 0; + unsigned char ibuf[8]; + unsigned char obuf[8]; + mbedtls_arc4_context ctx; + + mbedtls_arc4_init( &ctx ); + + for( i = 0; i < 3; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " ARC4 test #%d: ", i + 1 ); + + memcpy( ibuf, arc4_test_pt[i], 8 ); + + mbedtls_arc4_setup( &ctx, arc4_test_key[i], 8 ); + mbedtls_arc4_crypt( &ctx, 8, ibuf, obuf ); + + if( memcmp( obuf, arc4_test_ct[i], 8 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +exit: + mbedtls_arc4_free( &ctx ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_ARC4_C */ diff --git a/common/mbedtls/arc4.h b/common/mbedtls/arc4.h new file mode 100644 index 00000000..0355fb8b --- /dev/null +++ b/common/mbedtls/arc4.h @@ -0,0 +1,143 @@ +/** + * \file arc4.h + * + * \brief The ARCFOUR stream cipher + * + * \warning ARC4 is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers instead. + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + * + */ +#ifndef MBEDTLS_ARC4_H +#define MBEDTLS_ARC4_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#define MBEDTLS_ERR_ARC4_HW_ACCEL_FAILED -0x0019 /**< ARC4 hardware accelerator failed. */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_ARC4_ALT) +// Regular implementation +// + +/** + * \brief ARC4 context structure + * + * \warning ARC4 is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers instead. + * + */ +typedef struct mbedtls_arc4_context +{ + int x; /*!< permutation index */ + int y; /*!< permutation index */ + unsigned char m[256]; /*!< permutation table */ +} +mbedtls_arc4_context; + +#else /* MBEDTLS_ARC4_ALT */ +#include "arc4_alt.h" +#endif /* MBEDTLS_ARC4_ALT */ + +/** + * \brief Initialize ARC4 context + * + * \param ctx ARC4 context to be initialized + * + * \warning ARC4 is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + * + */ +void mbedtls_arc4_init( mbedtls_arc4_context *ctx ); + +/** + * \brief Clear ARC4 context + * + * \param ctx ARC4 context to be cleared + * + * \warning ARC4 is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + * + */ +void mbedtls_arc4_free( mbedtls_arc4_context *ctx ); + +/** + * \brief ARC4 key schedule + * + * \param ctx ARC4 context to be setup + * \param key the secret key + * \param keylen length of the key, in bytes + * + * \warning ARC4 is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + * + */ +void mbedtls_arc4_setup( mbedtls_arc4_context *ctx, const unsigned char *key, + unsigned int keylen ); + +/** + * \brief ARC4 cipher function + * + * \param ctx ARC4 context + * \param length length of the input data + * \param input buffer holding the input data + * \param output buffer for the output data + * + * \return 0 if successful + * + * \warning ARC4 is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + * + */ +int mbedtls_arc4_crypt( mbedtls_arc4_context *ctx, size_t length, const unsigned char *input, + unsigned char *output ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + * + * \warning ARC4 is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + * + */ +int mbedtls_arc4_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* arc4.h */ diff --git a/common/mbedtls/asn1.h b/common/mbedtls/asn1.h new file mode 100644 index 00000000..00b6f2c0 --- /dev/null +++ b/common/mbedtls/asn1.h @@ -0,0 +1,360 @@ +/** + * \file asn1.h + * + * \brief Generic ASN.1 parsing + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_ASN1_H +#define MBEDTLS_ASN1_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#if defined(MBEDTLS_BIGNUM_C) +#include "bignum.h" +#endif + +/** + * \addtogroup asn1_module + * \{ + */ + +/** + * \name ASN1 Error codes + * These error codes are OR'ed to X509 error codes for + * higher error granularity. + * ASN1 is a standard to specify data structures. + * \{ + */ +#define MBEDTLS_ERR_ASN1_OUT_OF_DATA -0x0060 /**< Out of data when parsing an ASN1 data structure. */ +#define MBEDTLS_ERR_ASN1_UNEXPECTED_TAG -0x0062 /**< ASN1 tag was of an unexpected value. */ +#define MBEDTLS_ERR_ASN1_INVALID_LENGTH -0x0064 /**< Error when trying to determine the length or invalid length. */ +#define MBEDTLS_ERR_ASN1_LENGTH_MISMATCH -0x0066 /**< Actual length differs from expected length. */ +#define MBEDTLS_ERR_ASN1_INVALID_DATA -0x0068 /**< Data is invalid. (not used) */ +#define MBEDTLS_ERR_ASN1_ALLOC_FAILED -0x006A /**< Memory allocation failed */ +#define MBEDTLS_ERR_ASN1_BUF_TOO_SMALL -0x006C /**< Buffer too small when writing ASN.1 data structure. */ + +/* \} name */ + +/** + * \name DER constants + * These constants comply with the DER encoded ASN.1 type tags. + * DER encoding uses hexadecimal representation. + * An example DER sequence is:\n + * - 0x02 -- tag indicating INTEGER + * - 0x01 -- length in octets + * - 0x05 -- value + * Such sequences are typically read into \c ::mbedtls_x509_buf. + * \{ + */ +#define MBEDTLS_ASN1_BOOLEAN 0x01 +#define MBEDTLS_ASN1_INTEGER 0x02 +#define MBEDTLS_ASN1_BIT_STRING 0x03 +#define MBEDTLS_ASN1_OCTET_STRING 0x04 +#define MBEDTLS_ASN1_NULL 0x05 +#define MBEDTLS_ASN1_OID 0x06 +#define MBEDTLS_ASN1_UTF8_STRING 0x0C +#define MBEDTLS_ASN1_SEQUENCE 0x10 +#define MBEDTLS_ASN1_SET 0x11 +#define MBEDTLS_ASN1_PRINTABLE_STRING 0x13 +#define MBEDTLS_ASN1_T61_STRING 0x14 +#define MBEDTLS_ASN1_IA5_STRING 0x16 +#define MBEDTLS_ASN1_UTC_TIME 0x17 +#define MBEDTLS_ASN1_GENERALIZED_TIME 0x18 +#define MBEDTLS_ASN1_UNIVERSAL_STRING 0x1C +#define MBEDTLS_ASN1_BMP_STRING 0x1E +#define MBEDTLS_ASN1_PRIMITIVE 0x00 +#define MBEDTLS_ASN1_CONSTRUCTED 0x20 +#define MBEDTLS_ASN1_CONTEXT_SPECIFIC 0x80 + +/* + * Bit masks for each of the components of an ASN.1 tag as specified in + * ITU X.690 (08/2015), section 8.1 "General rules for encoding", + * paragraph 8.1.2.2: + * + * Bit 8 7 6 5 1 + * +-------+-----+------------+ + * | Class | P/C | Tag number | + * +-------+-----+------------+ + */ +#define MBEDTLS_ASN1_TAG_CLASS_MASK 0xC0 +#define MBEDTLS_ASN1_TAG_PC_MASK 0x20 +#define MBEDTLS_ASN1_TAG_VALUE_MASK 0x1F + +/* \} name */ +/* \} addtogroup asn1_module */ + +/** Returns the size of the binary string, without the trailing \\0 */ +#define MBEDTLS_OID_SIZE(x) (sizeof(x) - 1) + +/** + * Compares an mbedtls_asn1_buf structure to a reference OID. + * + * Only works for 'defined' oid_str values (MBEDTLS_OID_HMAC_SHA1), you cannot use a + * 'unsigned char *oid' here! + */ +#define MBEDTLS_OID_CMP(oid_str, oid_buf) \ + ( ( MBEDTLS_OID_SIZE(oid_str) != (oid_buf)->len ) || \ + memcmp( (oid_str), (oid_buf)->p, (oid_buf)->len) != 0 ) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \name Functions to parse ASN.1 data structures + * \{ + */ + +/** + * Type-length-value structure that allows for ASN1 using DER. + */ +typedef struct mbedtls_asn1_buf +{ + int tag; /**< ASN1 type, e.g. MBEDTLS_ASN1_UTF8_STRING. */ + size_t len; /**< ASN1 length, in octets. */ + unsigned char *p; /**< ASN1 data, e.g. in ASCII. */ +} +mbedtls_asn1_buf; + +/** + * Container for ASN1 bit strings. + */ +typedef struct mbedtls_asn1_bitstring +{ + size_t len; /**< ASN1 length, in octets. */ + unsigned char unused_bits; /**< Number of unused bits at the end of the string */ + unsigned char *p; /**< Raw ASN1 data for the bit string */ +} +mbedtls_asn1_bitstring; + +/** + * Container for a sequence of ASN.1 items + */ +typedef struct mbedtls_asn1_sequence +{ + mbedtls_asn1_buf buf; /**< Buffer containing the given ASN.1 item. */ + struct mbedtls_asn1_sequence *next; /**< The next entry in the sequence. */ +} +mbedtls_asn1_sequence; + +/** + * Container for a sequence or list of 'named' ASN.1 data items + */ +typedef struct mbedtls_asn1_named_data +{ + mbedtls_asn1_buf oid; /**< The object identifier. */ + mbedtls_asn1_buf val; /**< The named value. */ + struct mbedtls_asn1_named_data *next; /**< The next entry in the sequence. */ + unsigned char next_merged; /**< Merge next item into the current one? */ +} +mbedtls_asn1_named_data; + +/** + * \brief Get the length of an ASN.1 element. + * Updates the pointer to immediately behind the length. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param len The variable that will receive the value + * + * \return 0 if successful, MBEDTLS_ERR_ASN1_OUT_OF_DATA on reaching + * end of data, MBEDTLS_ERR_ASN1_INVALID_LENGTH if length is + * unparseable. + */ +int mbedtls_asn1_get_len( unsigned char **p, + const unsigned char *end, + size_t *len ); + +/** + * \brief Get the tag and length of the tag. Check for the requested tag. + * Updates the pointer to immediately behind the tag and length. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param len The variable that will receive the length + * \param tag The expected tag + * + * \return 0 if successful, MBEDTLS_ERR_ASN1_UNEXPECTED_TAG if tag did + * not match requested tag, or another specific ASN.1 error code. + */ +int mbedtls_asn1_get_tag( unsigned char **p, + const unsigned char *end, + size_t *len, int tag ); + +/** + * \brief Retrieve a boolean ASN.1 tag and its value. + * Updates the pointer to immediately behind the full tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param val The variable that will receive the value + * + * \return 0 if successful or a specific ASN.1 error code. + */ +int mbedtls_asn1_get_bool( unsigned char **p, + const unsigned char *end, + int *val ); + +/** + * \brief Retrieve an integer ASN.1 tag and its value. + * Updates the pointer to immediately behind the full tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param val The variable that will receive the value + * + * \return 0 if successful or a specific ASN.1 error code. + */ +int mbedtls_asn1_get_int( unsigned char **p, + const unsigned char *end, + int *val ); + +/** + * \brief Retrieve a bitstring ASN.1 tag and its value. + * Updates the pointer to immediately behind the full tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param bs The variable that will receive the value + * + * \return 0 if successful or a specific ASN.1 error code. + */ +int mbedtls_asn1_get_bitstring( unsigned char **p, const unsigned char *end, + mbedtls_asn1_bitstring *bs); + +/** + * \brief Retrieve a bitstring ASN.1 tag without unused bits and its + * value. + * Updates the pointer to the beginning of the bit/octet string. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param len Length of the actual bit/octect string in bytes + * + * \return 0 if successful or a specific ASN.1 error code. + */ +int mbedtls_asn1_get_bitstring_null( unsigned char **p, const unsigned char *end, + size_t *len ); + +/** + * \brief Parses and splits an ASN.1 "SEQUENCE OF " + * Updated the pointer to immediately behind the full sequence tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param cur First variable in the chain to fill + * \param tag Type of sequence + * + * \return 0 if successful or a specific ASN.1 error code. + */ +int mbedtls_asn1_get_sequence_of( unsigned char **p, + const unsigned char *end, + mbedtls_asn1_sequence *cur, + int tag); + +#if defined(MBEDTLS_BIGNUM_C) +/** + * \brief Retrieve a MPI value from an integer ASN.1 tag. + * Updates the pointer to immediately behind the full tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param X The MPI that will receive the value + * + * \return 0 if successful or a specific ASN.1 or MPI error code. + */ +int mbedtls_asn1_get_mpi( unsigned char **p, + const unsigned char *end, + mbedtls_mpi *X ); +#endif /* MBEDTLS_BIGNUM_C */ + +/** + * \brief Retrieve an AlgorithmIdentifier ASN.1 sequence. + * Updates the pointer to immediately behind the full + * AlgorithmIdentifier. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param alg The buffer to receive the OID + * \param params The buffer to receive the params (if any) + * + * \return 0 if successful or a specific ASN.1 or MPI error code. + */ +int mbedtls_asn1_get_alg( unsigned char **p, + const unsigned char *end, + mbedtls_asn1_buf *alg, mbedtls_asn1_buf *params ); + +/** + * \brief Retrieve an AlgorithmIdentifier ASN.1 sequence with NULL or no + * params. + * Updates the pointer to immediately behind the full + * AlgorithmIdentifier. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param alg The buffer to receive the OID + * + * \return 0 if successful or a specific ASN.1 or MPI error code. + */ +int mbedtls_asn1_get_alg_null( unsigned char **p, + const unsigned char *end, + mbedtls_asn1_buf *alg ); + +/** + * \brief Find a specific named_data entry in a sequence or list based on + * the OID. + * + * \param list The list to seek through + * \param oid The OID to look for + * \param len Size of the OID + * + * \return NULL if not found, or a pointer to the existing entry. + */ +mbedtls_asn1_named_data *mbedtls_asn1_find_named_data( mbedtls_asn1_named_data *list, + const char *oid, size_t len ); + +/** + * \brief Free a mbedtls_asn1_named_data entry + * + * \param entry The named data entry to free + */ +void mbedtls_asn1_free_named_data( mbedtls_asn1_named_data *entry ); + +/** + * \brief Free all entries in a mbedtls_asn1_named_data list + * Head will be set to NULL + * + * \param head Pointer to the head of the list of named data entries to free + */ +void mbedtls_asn1_free_named_data_list( mbedtls_asn1_named_data **head ); + +#ifdef __cplusplus +} +#endif + +#endif /* asn1.h */ diff --git a/common/mbedtls/asn1parse.c b/common/mbedtls/asn1parse.c new file mode 100644 index 00000000..aeec173a --- /dev/null +++ b/common/mbedtls/asn1parse.c @@ -0,0 +1,391 @@ +/* + * Generic ASN.1 parsing + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ASN1_PARSE_C) + +#include "mbedtls/asn1.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_BIGNUM_C) +#include "mbedtls/bignum.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +/* + * ASN.1 DER decoding routines + */ +int mbedtls_asn1_get_len( unsigned char **p, + const unsigned char *end, + size_t *len ) +{ + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + if( ( **p & 0x80 ) == 0 ) + *len = *(*p)++; + else + { + switch( **p & 0x7F ) + { + case 1: + if( ( end - *p ) < 2 ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + *len = (*p)[1]; + (*p) += 2; + break; + + case 2: + if( ( end - *p ) < 3 ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + *len = ( (size_t)(*p)[1] << 8 ) | (*p)[2]; + (*p) += 3; + break; + + case 3: + if( ( end - *p ) < 4 ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + *len = ( (size_t)(*p)[1] << 16 ) | + ( (size_t)(*p)[2] << 8 ) | (*p)[3]; + (*p) += 4; + break; + + case 4: + if( ( end - *p ) < 5 ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + *len = ( (size_t)(*p)[1] << 24 ) | ( (size_t)(*p)[2] << 16 ) | + ( (size_t)(*p)[3] << 8 ) | (*p)[4]; + (*p) += 5; + break; + + default: + return( MBEDTLS_ERR_ASN1_INVALID_LENGTH ); + } + } + + if( *len > (size_t) ( end - *p ) ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + return( 0 ); +} + +int mbedtls_asn1_get_tag( unsigned char **p, + const unsigned char *end, + size_t *len, int tag ) +{ + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + if( **p != tag ) + return( MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + (*p)++; + + return( mbedtls_asn1_get_len( p, end, len ) ); +} + +int mbedtls_asn1_get_bool( unsigned char **p, + const unsigned char *end, + int *val ) +{ + int ret; + size_t len; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_BOOLEAN ) ) != 0 ) + return( ret ); + + if( len != 1 ) + return( MBEDTLS_ERR_ASN1_INVALID_LENGTH ); + + *val = ( **p != 0 ) ? 1 : 0; + (*p)++; + + return( 0 ); +} + +int mbedtls_asn1_get_int( unsigned char **p, + const unsigned char *end, + int *val ) +{ + int ret; + size_t len; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_INTEGER ) ) != 0 ) + return( ret ); + + if( len == 0 || len > sizeof( int ) || ( **p & 0x80 ) != 0 ) + return( MBEDTLS_ERR_ASN1_INVALID_LENGTH ); + + *val = 0; + + while( len-- > 0 ) + { + *val = ( *val << 8 ) | **p; + (*p)++; + } + + return( 0 ); +} + +#if defined(MBEDTLS_BIGNUM_C) +int mbedtls_asn1_get_mpi( unsigned char **p, + const unsigned char *end, + mbedtls_mpi *X ) +{ + int ret; + size_t len; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_INTEGER ) ) != 0 ) + return( ret ); + + ret = mbedtls_mpi_read_binary( X, *p, len ); + + *p += len; + + return( ret ); +} +#endif /* MBEDTLS_BIGNUM_C */ + +int mbedtls_asn1_get_bitstring( unsigned char **p, const unsigned char *end, + mbedtls_asn1_bitstring *bs) +{ + int ret; + + /* Certificate type is a single byte bitstring */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &bs->len, MBEDTLS_ASN1_BIT_STRING ) ) != 0 ) + return( ret ); + + /* Check length, subtract one for actual bit string length */ + if( bs->len < 1 ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + bs->len -= 1; + + /* Get number of unused bits, ensure unused bits <= 7 */ + bs->unused_bits = **p; + if( bs->unused_bits > 7 ) + return( MBEDTLS_ERR_ASN1_INVALID_LENGTH ); + (*p)++; + + /* Get actual bitstring */ + bs->p = *p; + *p += bs->len; + + if( *p != end ) + return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * Get a bit string without unused bits + */ +int mbedtls_asn1_get_bitstring_null( unsigned char **p, const unsigned char *end, + size_t *len ) +{ + int ret; + + if( ( ret = mbedtls_asn1_get_tag( p, end, len, MBEDTLS_ASN1_BIT_STRING ) ) != 0 ) + return( ret ); + + if( (*len)-- < 2 || *(*p)++ != 0 ) + return( MBEDTLS_ERR_ASN1_INVALID_DATA ); + + return( 0 ); +} + + + +/* + * Parses and splits an ASN.1 "SEQUENCE OF " + */ +int mbedtls_asn1_get_sequence_of( unsigned char **p, + const unsigned char *end, + mbedtls_asn1_sequence *cur, + int tag) +{ + int ret; + size_t len; + mbedtls_asn1_buf *buf; + + /* Get main sequence tag */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( ret ); + + if( *p + len != end ) + return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + while( *p < end ) + { + buf = &(cur->buf); + buf->tag = **p; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &buf->len, tag ) ) != 0 ) + return( ret ); + + buf->p = *p; + *p += buf->len; + + /* Allocate and assign next pointer */ + if( *p < end ) + { + cur->next = (mbedtls_asn1_sequence*)mbedtls_calloc( 1, + sizeof( mbedtls_asn1_sequence ) ); + + if( cur->next == NULL ) + return( MBEDTLS_ERR_ASN1_ALLOC_FAILED ); + + cur = cur->next; + } + } + + /* Set final sequence entry's next pointer to NULL */ + cur->next = NULL; + + if( *p != end ) + return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +int mbedtls_asn1_get_alg( unsigned char **p, + const unsigned char *end, + mbedtls_asn1_buf *alg, mbedtls_asn1_buf *params ) +{ + int ret; + size_t len; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( ret ); + + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + alg->tag = **p; + end = *p + len; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &alg->len, MBEDTLS_ASN1_OID ) ) != 0 ) + return( ret ); + + alg->p = *p; + *p += alg->len; + + if( *p == end ) + { + mbedtls_platform_zeroize( params, sizeof(mbedtls_asn1_buf) ); + return( 0 ); + } + + params->tag = **p; + (*p)++; + + if( ( ret = mbedtls_asn1_get_len( p, end, ¶ms->len ) ) != 0 ) + return( ret ); + + params->p = *p; + *p += params->len; + + if( *p != end ) + return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +int mbedtls_asn1_get_alg_null( unsigned char **p, + const unsigned char *end, + mbedtls_asn1_buf *alg ) +{ + int ret; + mbedtls_asn1_buf params; + + memset( ¶ms, 0, sizeof(mbedtls_asn1_buf) ); + + if( ( ret = mbedtls_asn1_get_alg( p, end, alg, ¶ms ) ) != 0 ) + return( ret ); + + if( ( params.tag != MBEDTLS_ASN1_NULL && params.tag != 0 ) || params.len != 0 ) + return( MBEDTLS_ERR_ASN1_INVALID_DATA ); + + return( 0 ); +} + +void mbedtls_asn1_free_named_data( mbedtls_asn1_named_data *cur ) +{ + if( cur == NULL ) + return; + + mbedtls_free( cur->oid.p ); + mbedtls_free( cur->val.p ); + + mbedtls_platform_zeroize( cur, sizeof( mbedtls_asn1_named_data ) ); +} + +void mbedtls_asn1_free_named_data_list( mbedtls_asn1_named_data **head ) +{ + mbedtls_asn1_named_data *cur; + + while( ( cur = *head ) != NULL ) + { + *head = cur->next; + mbedtls_asn1_free_named_data( cur ); + mbedtls_free( cur ); + } +} + +mbedtls_asn1_named_data *mbedtls_asn1_find_named_data( mbedtls_asn1_named_data *list, + const char *oid, size_t len ) +{ + while( list != NULL ) + { + if( list->oid.len == len && + memcmp( list->oid.p, oid, len ) == 0 ) + { + break; + } + + list = list->next; + } + + return( list ); +} + +#endif /* MBEDTLS_ASN1_PARSE_C */ diff --git a/common/mbedtls/asn1write.c b/common/mbedtls/asn1write.c new file mode 100644 index 00000000..f8e29dc7 --- /dev/null +++ b/common/mbedtls/asn1write.c @@ -0,0 +1,392 @@ +/* + * ASN.1 buffer writing functionality + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ASN1_WRITE_C) + +#include "mbedtls/asn1write.h" + +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +int mbedtls_asn1_write_len( unsigned char **p, unsigned char *start, size_t len ) +{ + if( len < 0x80 ) + { + if( *p - start < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = (unsigned char) len; + return( 1 ); + } + + if( len <= 0xFF ) + { + if( *p - start < 2 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = (unsigned char) len; + *--(*p) = 0x81; + return( 2 ); + } + + if( len <= 0xFFFF ) + { + if( *p - start < 3 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = ( len ) & 0xFF; + *--(*p) = ( len >> 8 ) & 0xFF; + *--(*p) = 0x82; + return( 3 ); + } + + if( len <= 0xFFFFFF ) + { + if( *p - start < 4 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = ( len ) & 0xFF; + *--(*p) = ( len >> 8 ) & 0xFF; + *--(*p) = ( len >> 16 ) & 0xFF; + *--(*p) = 0x83; + return( 4 ); + } + +#if SIZE_MAX > 0xFFFFFFFF + if( len <= 0xFFFFFFFF ) +#endif + { + if( *p - start < 5 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = ( len ) & 0xFF; + *--(*p) = ( len >> 8 ) & 0xFF; + *--(*p) = ( len >> 16 ) & 0xFF; + *--(*p) = ( len >> 24 ) & 0xFF; + *--(*p) = 0x84; + return( 5 ); + } + +#if SIZE_MAX > 0xFFFFFFFF + return( MBEDTLS_ERR_ASN1_INVALID_LENGTH ); +#endif +} + +int mbedtls_asn1_write_tag( unsigned char **p, unsigned char *start, unsigned char tag ) +{ + if( *p - start < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = tag; + + return( 1 ); +} + +int mbedtls_asn1_write_raw_buffer( unsigned char **p, unsigned char *start, + const unsigned char *buf, size_t size ) +{ + size_t len = 0; + + if( *p < start || (size_t)( *p - start ) < size ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + len = size; + (*p) -= len; + memcpy( *p, buf, len ); + + return( (int) len ); +} + +#if defined(MBEDTLS_BIGNUM_C) +int mbedtls_asn1_write_mpi( unsigned char **p, unsigned char *start, const mbedtls_mpi *X ) +{ + int ret; + size_t len = 0; + + // Write the MPI + // + len = mbedtls_mpi_size( X ); + + if( *p < start || (size_t)( *p - start ) < len ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + (*p) -= len; + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( X, *p, len ) ); + + // DER format assumes 2s complement for numbers, so the leftmost bit + // should be 0 for positive numbers and 1 for negative numbers. + // + if( X->s ==1 && **p & 0x80 ) + { + if( *p - start < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = 0x00; + len += 1; + } + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_INTEGER ) ); + + ret = (int) len; + +cleanup: + return( ret ); +} +#endif /* MBEDTLS_BIGNUM_C */ + +int mbedtls_asn1_write_null( unsigned char **p, unsigned char *start ) +{ + int ret; + size_t len = 0; + + // Write NULL + // + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, 0) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_NULL ) ); + + return( (int) len ); +} + +int mbedtls_asn1_write_oid( unsigned char **p, unsigned char *start, + const char *oid, size_t oid_len ) +{ + int ret; + size_t len = 0; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, + (const unsigned char *) oid, oid_len ) ); + MBEDTLS_ASN1_CHK_ADD( len , mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len , mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_OID ) ); + + return( (int) len ); +} + +int mbedtls_asn1_write_algorithm_identifier( unsigned char **p, unsigned char *start, + const char *oid, size_t oid_len, + size_t par_len ) +{ + int ret; + size_t len = 0; + + if( par_len == 0 ) + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_null( p, start ) ); + else + len += par_len; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_oid( p, start, oid, oid_len ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ); + + return( (int) len ); +} + +int mbedtls_asn1_write_bool( unsigned char **p, unsigned char *start, int boolean ) +{ + int ret; + size_t len = 0; + + if( *p - start < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = (boolean) ? 255 : 0; + len++; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_BOOLEAN ) ); + + return( (int) len ); +} + +int mbedtls_asn1_write_int( unsigned char **p, unsigned char *start, int val ) +{ + int ret; + size_t len = 0; + + if( *p - start < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + len += 1; + *--(*p) = val; + + if( val > 0 && **p & 0x80 ) + { + if( *p - start < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = 0x00; + len += 1; + } + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_INTEGER ) ); + + return( (int) len ); +} + +int mbedtls_asn1_write_printable_string( unsigned char **p, unsigned char *start, + const char *text, size_t text_len ) +{ + int ret; + size_t len = 0; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, + (const unsigned char *) text, text_len ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_PRINTABLE_STRING ) ); + + return( (int) len ); +} + +int mbedtls_asn1_write_ia5_string( unsigned char **p, unsigned char *start, + const char *text, size_t text_len ) +{ + int ret; + size_t len = 0; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, + (const unsigned char *) text, text_len ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_IA5_STRING ) ); + + return( (int) len ); +} + +int mbedtls_asn1_write_bitstring( unsigned char **p, unsigned char *start, + const unsigned char *buf, size_t bits ) +{ + int ret; + size_t len = 0, size; + + size = ( bits / 8 ) + ( ( bits % 8 ) ? 1 : 0 ); + + // Calculate byte length + // + if( *p < start || (size_t)( *p - start ) < size + 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + len = size + 1; + (*p) -= size; + memcpy( *p, buf, size ); + + // Write unused bits + // + *--(*p) = (unsigned char) (size * 8 - bits); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_BIT_STRING ) ); + + return( (int) len ); +} + +int mbedtls_asn1_write_octet_string( unsigned char **p, unsigned char *start, + const unsigned char *buf, size_t size ) +{ + int ret; + size_t len = 0; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, buf, size ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_OCTET_STRING ) ); + + return( (int) len ); +} + +mbedtls_asn1_named_data *mbedtls_asn1_store_named_data( mbedtls_asn1_named_data **head, + const char *oid, size_t oid_len, + const unsigned char *val, + size_t val_len ) +{ + mbedtls_asn1_named_data *cur; + + if( ( cur = mbedtls_asn1_find_named_data( *head, oid, oid_len ) ) == NULL ) + { + // Add new entry if not present yet based on OID + // + cur = (mbedtls_asn1_named_data*)mbedtls_calloc( 1, + sizeof(mbedtls_asn1_named_data) ); + if( cur == NULL ) + return( NULL ); + + cur->oid.len = oid_len; + cur->oid.p = mbedtls_calloc( 1, oid_len ); + if( cur->oid.p == NULL ) + { + mbedtls_free( cur ); + return( NULL ); + } + + memcpy( cur->oid.p, oid, oid_len ); + + cur->val.len = val_len; + cur->val.p = mbedtls_calloc( 1, val_len ); + if( cur->val.p == NULL ) + { + mbedtls_free( cur->oid.p ); + mbedtls_free( cur ); + return( NULL ); + } + + cur->next = *head; + *head = cur; + } + else if( cur->val.len < val_len ) + { + /* + * Enlarge existing value buffer if needed + * Preserve old data until the allocation succeeded, to leave list in + * a consistent state in case allocation fails. + */ + void *p = mbedtls_calloc( 1, val_len ); + if( p == NULL ) + return( NULL ); + + mbedtls_free( cur->val.p ); + cur->val.p = p; + cur->val.len = val_len; + } + + if( val != NULL ) + memcpy( cur->val.p, val, val_len ); + + return( cur ); +} +#endif /* MBEDTLS_ASN1_WRITE_C */ diff --git a/common/mbedtls/asn1write.h b/common/mbedtls/asn1write.h new file mode 100644 index 00000000..0b832e5c --- /dev/null +++ b/common/mbedtls/asn1write.h @@ -0,0 +1,242 @@ +/** + * \file asn1write.h + * + * \brief ASN.1 buffer writing functionality + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_ASN1_WRITE_H +#define MBEDTLS_ASN1_WRITE_H + +#include "asn1.h" + +#define MBEDTLS_ASN1_CHK_ADD(g, f) do { if( ( ret = f ) < 0 ) return( ret ); else \ + g += ret; } while( 0 ) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Write a length field in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param len the length to write + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_len( unsigned char **p, unsigned char *start, size_t len ); + +/** + * \brief Write a ASN.1 tag in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param tag the tag to write + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_tag( unsigned char **p, unsigned char *start, + unsigned char tag ); + +/** + * \brief Write raw buffer data + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param buf data buffer to write + * \param size length of the data buffer + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_raw_buffer( unsigned char **p, unsigned char *start, + const unsigned char *buf, size_t size ); + +#if defined(MBEDTLS_BIGNUM_C) +/** + * \brief Write a big number (MBEDTLS_ASN1_INTEGER) in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param X the MPI to write + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_mpi( unsigned char **p, unsigned char *start, const mbedtls_mpi *X ); +#endif /* MBEDTLS_BIGNUM_C */ + +/** + * \brief Write a NULL tag (MBEDTLS_ASN1_NULL) with zero data in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_null( unsigned char **p, unsigned char *start ); + +/** + * \brief Write an OID tag (MBEDTLS_ASN1_OID) and data in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param oid the OID to write + * \param oid_len length of the OID + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_oid( unsigned char **p, unsigned char *start, + const char *oid, size_t oid_len ); + +/** + * \brief Write an AlgorithmIdentifier sequence in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param oid the OID of the algorithm + * \param oid_len length of the OID + * \param par_len length of parameters, which must be already written. + * If 0, NULL parameters are added + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_algorithm_identifier( unsigned char **p, unsigned char *start, + const char *oid, size_t oid_len, + size_t par_len ); + +/** + * \brief Write a boolean tag (MBEDTLS_ASN1_BOOLEAN) and value in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param boolean 0 or 1 + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_bool( unsigned char **p, unsigned char *start, int boolean ); + +/** + * \brief Write an int tag (MBEDTLS_ASN1_INTEGER) and value in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param val the integer value + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_int( unsigned char **p, unsigned char *start, int val ); + +/** + * \brief Write a printable string tag (MBEDTLS_ASN1_PRINTABLE_STRING) and + * value in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param text the text to write + * \param text_len length of the text + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_printable_string( unsigned char **p, unsigned char *start, + const char *text, size_t text_len ); + +/** + * \brief Write an IA5 string tag (MBEDTLS_ASN1_IA5_STRING) and + * value in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param text the text to write + * \param text_len length of the text + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_ia5_string( unsigned char **p, unsigned char *start, + const char *text, size_t text_len ); + +/** + * \brief Write a bitstring tag (MBEDTLS_ASN1_BIT_STRING) and + * value in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param buf the bitstring + * \param bits the total number of bits in the bitstring + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_bitstring( unsigned char **p, unsigned char *start, + const unsigned char *buf, size_t bits ); + +/** + * \brief Write an octet string tag (MBEDTLS_ASN1_OCTET_STRING) and + * value in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param buf data buffer to write + * \param size length of the data buffer + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_octet_string( unsigned char **p, unsigned char *start, + const unsigned char *buf, size_t size ); + +/** + * \brief Create or find a specific named_data entry for writing in a + * sequence or list based on the OID. If not already in there, + * a new entry is added to the head of the list. + * Warning: Destructive behaviour for the val data! + * + * \param list Pointer to the location of the head of the list to seek + * through (will be updated in case of a new entry) + * \param oid The OID to look for + * \param oid_len Size of the OID + * \param val Data to store (can be NULL if you want to fill it by hand) + * \param val_len Minimum length of the data buffer needed + * + * \return NULL if if there was a memory allocation error, or a pointer + * to the new / existing entry. + */ +mbedtls_asn1_named_data *mbedtls_asn1_store_named_data( mbedtls_asn1_named_data **list, + const char *oid, size_t oid_len, + const unsigned char *val, + size_t val_len ); + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_ASN1_WRITE_H */ diff --git a/common/mbedtls/base64.c b/common/mbedtls/base64.c new file mode 100644 index 00000000..41200021 --- /dev/null +++ b/common/mbedtls/base64.c @@ -0,0 +1,295 @@ +/* + * RFC 1521 base64 encoding/decoding + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_BASE64_C) + +#include "mbedtls/base64.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#include +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +static const unsigned char base64_enc_map[64] = +{ + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', + 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', + 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', + 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', '+', '/' +}; + +static const unsigned char base64_dec_map[128] = +{ + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 62, 127, 127, 127, 63, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 127, 127, + 127, 64, 127, 127, 127, 0, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 127, 127, 127, 127, 127, 127, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 127, 127, 127, 127, 127 +}; + +#define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */ + +/* + * Encode a buffer into base64 format + */ +int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen, + const unsigned char *src, size_t slen ) +{ + size_t i, n; + int C1, C2, C3; + unsigned char *p; + + if( slen == 0 ) + { + *olen = 0; + return( 0 ); + } + + n = slen / 3 + ( slen % 3 != 0 ); + + if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 ) + { + *olen = BASE64_SIZE_T_MAX; + return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL ); + } + + n *= 4; + + if( ( dlen < n + 1 ) || ( NULL == dst ) ) + { + *olen = n + 1; + return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL ); + } + + n = ( slen / 3 ) * 3; + + for( i = 0, p = dst; i < n; i += 3 ) + { + C1 = *src++; + C2 = *src++; + C3 = *src++; + + *p++ = base64_enc_map[(C1 >> 2) & 0x3F]; + *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F]; + *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F]; + *p++ = base64_enc_map[C3 & 0x3F]; + } + + if( i < slen ) + { + C1 = *src++; + C2 = ( ( i + 1 ) < slen ) ? *src++ : 0; + + *p++ = base64_enc_map[(C1 >> 2) & 0x3F]; + *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F]; + + if( ( i + 1 ) < slen ) + *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F]; + else *p++ = '='; + + *p++ = '='; + } + + *olen = p - dst; + *p = 0; + + return( 0 ); +} + +/* + * Decode a base64-formatted buffer + */ +int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen, + const unsigned char *src, size_t slen ) +{ + size_t i, n; + uint32_t j, x; + unsigned char *p; + + /* First pass: check for validity and get output length */ + for( i = n = j = 0; i < slen; i++ ) + { + /* Skip spaces before checking for EOL */ + x = 0; + while( i < slen && src[i] == ' ' ) + { + ++i; + ++x; + } + + /* Spaces at end of buffer are OK */ + if( i == slen ) + break; + + if( ( slen - i ) >= 2 && + src[i] == '\r' && src[i + 1] == '\n' ) + continue; + + if( src[i] == '\n' ) + continue; + + /* Space inside a line is an error */ + if( x != 0 ) + return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); + + if( src[i] == '=' && ++j > 2 ) + return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); + + if( src[i] > 127 || base64_dec_map[src[i]] == 127 ) + return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); + + if( base64_dec_map[src[i]] < 64 && j != 0 ) + return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); + + n++; + } + + if( n == 0 ) + { + *olen = 0; + return( 0 ); + } + + /* The following expression is to calculate the following formula without + * risk of integer overflow in n: + * n = ( ( n * 6 ) + 7 ) >> 3; + */ + n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 ); + n -= j; + + if( dst == NULL || dlen < n ) + { + *olen = n; + return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL ); + } + + for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ ) + { + if( *src == '\r' || *src == '\n' || *src == ' ' ) + continue; + + j -= ( base64_dec_map[*src] == 64 ); + x = ( x << 6 ) | ( base64_dec_map[*src] & 0x3F ); + + if( ++n == 4 ) + { + n = 0; + if( j > 0 ) *p++ = (unsigned char)( x >> 16 ); + if( j > 1 ) *p++ = (unsigned char)( x >> 8 ); + if( j > 2 ) *p++ = (unsigned char)( x ); + } + } + + *olen = p - dst; + + return( 0 ); +} + +#if defined(MBEDTLS_SELF_TEST) + +static const unsigned char base64_test_dec[64] = +{ + 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD, + 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01, + 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09, + 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13, + 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31, + 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38, + 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B, + 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97 +}; + +static const unsigned char base64_test_enc[] = + "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK" + "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw=="; + +/* + * Checkup routine + */ +int mbedtls_base64_self_test( int verbose ) +{ + size_t len; + const unsigned char *src; + unsigned char buffer[128]; + + if( verbose != 0 ) + mbedtls_printf( " Base64 encoding test: " ); + + src = base64_test_dec; + + if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 || + memcmp( base64_test_enc, buffer, 88 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n Base64 decoding test: " ); + + src = base64_test_enc; + + if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 || + memcmp( base64_test_dec, buffer, 64 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_BASE64_C */ diff --git a/common/mbedtls/base64.h b/common/mbedtls/base64.h new file mode 100644 index 00000000..ce5563e1 --- /dev/null +++ b/common/mbedtls/base64.h @@ -0,0 +1,91 @@ +/** + * \file base64.h + * + * \brief RFC 1521 base64 encoding/decoding + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_BASE64_H +#define MBEDTLS_BASE64_H + +#include + +#define MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL -0x002A /**< Output buffer too small. */ +#define MBEDTLS_ERR_BASE64_INVALID_CHARACTER -0x002C /**< Invalid character in input. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Encode a buffer into base64 format + * + * \param dst destination buffer + * \param dlen size of the destination buffer + * \param olen number of bytes written + * \param src source buffer + * \param slen amount of data to be encoded + * + * \return 0 if successful, or MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL. + * *olen is always updated to reflect the amount + * of data that has (or would have) been written. + * If that length cannot be represented, then no data is + * written to the buffer and *olen is set to the maximum + * length representable as a size_t. + * + * \note Call this function with dlen = 0 to obtain the + * required buffer size in *olen + */ +int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen, + const unsigned char *src, size_t slen ); + +/** + * \brief Decode a base64-formatted buffer + * + * \param dst destination buffer (can be NULL for checking size) + * \param dlen size of the destination buffer + * \param olen number of bytes written + * \param src source buffer + * \param slen amount of data to be decoded + * + * \return 0 if successful, MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL, or + * MBEDTLS_ERR_BASE64_INVALID_CHARACTER if the input data is + * not correct. *olen is always updated to reflect the amount + * of data that has (or would have) been written. + * + * \note Call this function with *dst = NULL or dlen = 0 to obtain + * the required buffer size in *olen + */ +int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen, + const unsigned char *src, size_t slen ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_base64_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* base64.h */ diff --git a/common/mbedtls/bignum.c b/common/mbedtls/bignum.c new file mode 100644 index 00000000..2c9ecbe2 --- /dev/null +++ b/common/mbedtls/bignum.c @@ -0,0 +1,2470 @@ +/* + * Multi-precision integer library + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * The following sources were referenced in the design of this Multi-precision + * Integer library: + * + * [1] Handbook of Applied Cryptography - 1997 + * Menezes, van Oorschot and Vanstone + * + * [2] Multi-Precision Math + * Tom St Denis + * https://github.com/libtom/libtommath/blob/develop/tommath.pdf + * + * [3] GNU Multi-Precision Arithmetic Library + * https://gmplib.org/manual/index.html + * + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_BIGNUM_C) + +#include "mbedtls/bignum.h" +#include "mbedtls/bn_mul.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_printf printf +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#define ciL (sizeof(mbedtls_mpi_uint)) /* chars in limb */ +#define biL (ciL << 3) /* bits in limb */ +#define biH (ciL << 2) /* half limb size */ + +#define MPI_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */ + +/* + * Convert between bits/chars and number of limbs + * Divide first in order to avoid potential overflows + */ +#define BITS_TO_LIMBS(i) ( (i) / biL + ( (i) % biL != 0 ) ) +#define CHARS_TO_LIMBS(i) ( (i) / ciL + ( (i) % ciL != 0 ) ) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_mpi_zeroize( mbedtls_mpi_uint *v, size_t n ) +{ + mbedtls_platform_zeroize( v, ciL * n ); +} + +/* + * Initialize one MPI + */ +void mbedtls_mpi_init( mbedtls_mpi *X ) +{ + if( X == NULL ) + return; + + X->s = 1; + X->n = 0; + X->p = NULL; +} + +/* + * Unallocate one MPI + */ +void mbedtls_mpi_free( mbedtls_mpi *X ) +{ + if( X == NULL ) + return; + + if( X->p != NULL ) + { + mbedtls_mpi_zeroize( X->p, X->n ); + mbedtls_free( X->p ); + } + + X->s = 1; + X->n = 0; + X->p = NULL; +} + +/* + * Enlarge to the specified number of limbs + */ +int mbedtls_mpi_grow( mbedtls_mpi *X, size_t nblimbs ) +{ + mbedtls_mpi_uint *p; + + if( nblimbs > MBEDTLS_MPI_MAX_LIMBS ) + return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); + + if( X->n < nblimbs ) + { + if( ( p = (mbedtls_mpi_uint*)mbedtls_calloc( nblimbs, ciL ) ) == NULL ) + return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); + + if( X->p != NULL ) + { + memcpy( p, X->p, X->n * ciL ); + mbedtls_mpi_zeroize( X->p, X->n ); + mbedtls_free( X->p ); + } + + X->n = nblimbs; + X->p = p; + } + + return( 0 ); +} + +/* + * Resize down as much as possible, + * while keeping at least the specified number of limbs + */ +int mbedtls_mpi_shrink( mbedtls_mpi *X, size_t nblimbs ) +{ + mbedtls_mpi_uint *p; + size_t i; + + /* Actually resize up in this case */ + if( X->n <= nblimbs ) + return( mbedtls_mpi_grow( X, nblimbs ) ); + + for( i = X->n - 1; i > 0; i-- ) + if( X->p[i] != 0 ) + break; + i++; + + if( i < nblimbs ) + i = nblimbs; + + if( ( p = (mbedtls_mpi_uint*)mbedtls_calloc( i, ciL ) ) == NULL ) + return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); + + if( X->p != NULL ) + { + memcpy( p, X->p, i * ciL ); + mbedtls_mpi_zeroize( X->p, X->n ); + mbedtls_free( X->p ); + } + + X->n = i; + X->p = p; + + return( 0 ); +} + +/* + * Copy the contents of Y into X + */ +int mbedtls_mpi_copy( mbedtls_mpi *X, const mbedtls_mpi *Y ) +{ + int ret = 0; + size_t i; + + if( X == Y ) + return( 0 ); + + if( Y->p == NULL ) + { + mbedtls_mpi_free( X ); + return( 0 ); + } + + for( i = Y->n - 1; i > 0; i-- ) + if( Y->p[i] != 0 ) + break; + i++; + + X->s = Y->s; + + if( X->n < i ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i ) ); + } + else + { + memset( X->p + i, 0, ( X->n - i ) * ciL ); + } + + memcpy( X->p, Y->p, i * ciL ); + +cleanup: + + return( ret ); +} + +/* + * Swap the contents of X and Y + */ +void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y ) +{ + mbedtls_mpi T; + + memcpy( &T, X, sizeof( mbedtls_mpi ) ); + memcpy( X, Y, sizeof( mbedtls_mpi ) ); + memcpy( Y, &T, sizeof( mbedtls_mpi ) ); +} + +/* + * Conditionally assign X = Y, without leaking information + * about whether the assignment was made or not. + * (Leaking information about the respective sizes of X and Y is ok however.) + */ +int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned char assign ) +{ + int ret = 0; + size_t i; + + /* make sure assign is 0 or 1 in a time-constant manner */ + assign = (assign | (unsigned char)-assign) >> 7; + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) ); + + X->s = X->s * ( 1 - assign ) + Y->s * assign; + + for( i = 0; i < Y->n; i++ ) + X->p[i] = X->p[i] * ( 1 - assign ) + Y->p[i] * assign; + + for( ; i < X->n; i++ ) + X->p[i] *= ( 1 - assign ); + +cleanup: + return( ret ); +} + +/* + * Conditionally swap X and Y, without leaking information + * about whether the swap was made or not. + * Here it is not ok to simply swap the pointers, which whould lead to + * different memory access patterns when X and Y are used afterwards. + */ +int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, mbedtls_mpi *Y, unsigned char swap ) +{ + int ret, s; + size_t i; + mbedtls_mpi_uint tmp; + + if( X == Y ) + return( 0 ); + + /* make sure swap is 0 or 1 in a time-constant manner */ + swap = (swap | (unsigned char)-swap) >> 7; + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( Y, X->n ) ); + + s = X->s; + X->s = X->s * ( 1 - swap ) + Y->s * swap; + Y->s = Y->s * ( 1 - swap ) + s * swap; + + + for( i = 0; i < X->n; i++ ) + { + tmp = X->p[i]; + X->p[i] = X->p[i] * ( 1 - swap ) + Y->p[i] * swap; + Y->p[i] = Y->p[i] * ( 1 - swap ) + tmp * swap; + } + +cleanup: + return( ret ); +} + +/* + * Set value from integer + */ +int mbedtls_mpi_lset( mbedtls_mpi *X, mbedtls_mpi_sint z ) +{ + int ret; + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, 1 ) ); + memset( X->p, 0, X->n * ciL ); + + X->p[0] = ( z < 0 ) ? -z : z; + X->s = ( z < 0 ) ? -1 : 1; + +cleanup: + + return( ret ); +} + +/* + * Get a specific bit + */ +int mbedtls_mpi_get_bit( const mbedtls_mpi *X, size_t pos ) +{ + if( X->n * biL <= pos ) + return( 0 ); + + return( ( X->p[pos / biL] >> ( pos % biL ) ) & 0x01 ); +} + +/* + * Set a bit to a specific value of 0 or 1 + */ +int mbedtls_mpi_set_bit( mbedtls_mpi *X, size_t pos, unsigned char val ) +{ + int ret = 0; + size_t off = pos / biL; + size_t idx = pos % biL; + + if( val != 0 && val != 1 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + if( X->n * biL <= pos ) + { + if( val == 0 ) + return( 0 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, off + 1 ) ); + } + + X->p[off] &= ~( (mbedtls_mpi_uint) 0x01 << idx ); + X->p[off] |= (mbedtls_mpi_uint) val << idx; + +cleanup: + + return( ret ); +} + +/* + * Return the number of less significant zero-bits + */ +size_t mbedtls_mpi_lsb( const mbedtls_mpi *X ) +{ + size_t i, j, count = 0; + + for( i = 0; i < X->n; i++ ) + for( j = 0; j < biL; j++, count++ ) + if( ( ( X->p[i] >> j ) & 1 ) != 0 ) + return( count ); + + return( 0 ); +} + +/* + * Count leading zero bits in a given integer + */ +static size_t mbedtls_clz( const mbedtls_mpi_uint x ) +{ + size_t j; + mbedtls_mpi_uint mask = (mbedtls_mpi_uint) 1 << (biL - 1); + + for( j = 0; j < biL; j++ ) + { + if( x & mask ) break; + + mask >>= 1; + } + + return j; +} + +/* + * Return the number of bits + */ +size_t mbedtls_mpi_bitlen( const mbedtls_mpi *X ) +{ + size_t i, j; + + if( X->n == 0 ) + return( 0 ); + + for( i = X->n - 1; i > 0; i-- ) + if( X->p[i] != 0 ) + break; + + j = biL - mbedtls_clz( X->p[i] ); + + return( ( i * biL ) + j ); +} + +/* + * Return the total size in bytes + */ +size_t mbedtls_mpi_size( const mbedtls_mpi *X ) +{ + return( ( mbedtls_mpi_bitlen( X ) + 7 ) >> 3 ); +} + +/* + * Convert an ASCII character to digit value + */ +static int mpi_get_digit( mbedtls_mpi_uint *d, int radix, char c ) +{ + *d = 255; + + if( c >= 0x30 && c <= 0x39 ) *d = c - 0x30; + if( c >= 0x41 && c <= 0x46 ) *d = c - 0x37; + if( c >= 0x61 && c <= 0x66 ) *d = c - 0x57; + + if( *d >= (mbedtls_mpi_uint) radix ) + return( MBEDTLS_ERR_MPI_INVALID_CHARACTER ); + + return( 0 ); +} + +/* + * Import from an ASCII string + */ +int mbedtls_mpi_read_string( mbedtls_mpi *X, int radix, const char *s ) +{ + int ret; + size_t i, j, slen, n; + mbedtls_mpi_uint d; + mbedtls_mpi T; + + if( radix < 2 || radix > 16 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + mbedtls_mpi_init( &T ); + + slen = strlen( s ); + + if( radix == 16 ) + { + if( slen > MPI_SIZE_T_MAX >> 2 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + n = BITS_TO_LIMBS( slen << 2 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, n ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) ); + + for( i = slen, j = 0; i > 0; i--, j++ ) + { + if( i == 1 && s[i - 1] == '-' ) + { + X->s = -1; + break; + } + + MBEDTLS_MPI_CHK( mpi_get_digit( &d, radix, s[i - 1] ) ); + X->p[j / ( 2 * ciL )] |= d << ( ( j % ( 2 * ciL ) ) << 2 ); + } + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) ); + + for( i = 0; i < slen; i++ ) + { + if( i == 0 && s[i] == '-' ) + { + X->s = -1; + continue; + } + + MBEDTLS_MPI_CHK( mpi_get_digit( &d, radix, s[i] ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T, X, radix ) ); + + if( X->s == 1 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, &T, d ) ); + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( X, &T, d ) ); + } + } + } + +cleanup: + + mbedtls_mpi_free( &T ); + + return( ret ); +} + +/* + * Helper to write the digits high-order first + */ +static int mpi_write_hlp( mbedtls_mpi *X, int radix, char **p ) +{ + int ret; + mbedtls_mpi_uint r; + + if( radix < 2 || radix > 16 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, radix ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_div_int( X, NULL, X, radix ) ); + + if( mbedtls_mpi_cmp_int( X, 0 ) != 0 ) + MBEDTLS_MPI_CHK( mpi_write_hlp( X, radix, p ) ); + + if( r < 10 ) + *(*p)++ = (char)( r + 0x30 ); + else + *(*p)++ = (char)( r + 0x37 ); + +cleanup: + + return( ret ); +} + +/* + * Export into an ASCII string + */ +int mbedtls_mpi_write_string( const mbedtls_mpi *X, int radix, + char *buf, size_t buflen, size_t *olen ) +{ + int ret = 0; + size_t n; + char *p; + mbedtls_mpi T; + + if( radix < 2 || radix > 16 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + n = mbedtls_mpi_bitlen( X ); + if( radix >= 4 ) n >>= 1; + if( radix >= 16 ) n >>= 1; + /* + * Round up the buffer length to an even value to ensure that there is + * enough room for hexadecimal values that can be represented in an odd + * number of digits. + */ + n += 3 + ( ( n + 1 ) & 1 ); + + if( buflen < n ) + { + *olen = n; + return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL ); + } + + p = buf; + mbedtls_mpi_init( &T ); + + if( X->s == -1 ) + *p++ = '-'; + + if( radix == 16 ) + { + int c; + size_t i, j, k; + + for( i = X->n, k = 0; i > 0; i-- ) + { + for( j = ciL; j > 0; j-- ) + { + c = ( X->p[i - 1] >> ( ( j - 1 ) << 3) ) & 0xFF; + + if( c == 0 && k == 0 && ( i + j ) != 2 ) + continue; + + *(p++) = "0123456789ABCDEF" [c / 16]; + *(p++) = "0123456789ABCDEF" [c % 16]; + k = 1; + } + } + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &T, X ) ); + + if( T.s == -1 ) + T.s = 1; + + MBEDTLS_MPI_CHK( mpi_write_hlp( &T, radix, &p ) ); + } + + *p++ = '\0'; + *olen = p - buf; + +cleanup: + + mbedtls_mpi_free( &T ); + + return( ret ); +} + +#if defined(MBEDTLS_FS_IO) +/* + * Read X from an opened file + */ +int mbedtls_mpi_read_file( mbedtls_mpi *X, int radix, FILE *fin ) +{ + mbedtls_mpi_uint d; + size_t slen; + char *p; + /* + * Buffer should have space for (short) label and decimal formatted MPI, + * newline characters and '\0' + */ + char s[ MBEDTLS_MPI_RW_BUFFER_SIZE ]; + + memset( s, 0, sizeof( s ) ); + if( fgets( s, sizeof( s ) - 1, fin ) == NULL ) + return( MBEDTLS_ERR_MPI_FILE_IO_ERROR ); + + slen = strlen( s ); + if( slen == sizeof( s ) - 2 ) + return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL ); + + if( slen > 0 && s[slen - 1] == '\n' ) { slen--; s[slen] = '\0'; } + if( slen > 0 && s[slen - 1] == '\r' ) { slen--; s[slen] = '\0'; } + + p = s + slen; + while( p-- > s ) + if( mpi_get_digit( &d, radix, *p ) != 0 ) + break; + + return( mbedtls_mpi_read_string( X, radix, p + 1 ) ); +} + +/* + * Write X into an opened file (or stdout if fout == NULL) + */ +int mbedtls_mpi_write_file( const char *p, const mbedtls_mpi *X, int radix, FILE *fout ) +{ + int ret; + size_t n, slen, plen; + /* + * Buffer should have space for (short) label and decimal formatted MPI, + * newline characters and '\0' + */ + char s[ MBEDTLS_MPI_RW_BUFFER_SIZE ]; + + memset( s, 0, sizeof( s ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_write_string( X, radix, s, sizeof( s ) - 2, &n ) ); + + if( p == NULL ) p = ""; + + plen = strlen( p ); + slen = strlen( s ); + s[slen++] = '\r'; + s[slen++] = '\n'; + + if( fout != NULL ) + { + if( fwrite( p, 1, plen, fout ) != plen || + fwrite( s, 1, slen, fout ) != slen ) + return( MBEDTLS_ERR_MPI_FILE_IO_ERROR ); + } + else + mbedtls_printf( "%s%s", p, s ); + +cleanup: + + return( ret ); +} +#endif /* MBEDTLS_FS_IO */ + +/* + * Import X from unsigned binary data, big endian + */ +int mbedtls_mpi_read_binary( mbedtls_mpi *X, const unsigned char *buf, size_t buflen ) +{ + int ret; + size_t i, j; + size_t const limbs = CHARS_TO_LIMBS( buflen ); + + /* Ensure that target MPI has exactly the necessary number of limbs */ + if( X->n != limbs ) + { + mbedtls_mpi_free( X ); + mbedtls_mpi_init( X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, limbs ) ); + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) ); + + for( i = buflen, j = 0; i > 0; i--, j++ ) + X->p[j / ciL] |= ((mbedtls_mpi_uint) buf[i - 1]) << ((j % ciL) << 3); + +cleanup: + + return( ret ); +} + +/* + * Export X into unsigned binary data, big endian + */ +int mbedtls_mpi_write_binary( const mbedtls_mpi *X, unsigned char *buf, size_t buflen ) +{ + size_t i, j, n; + + n = mbedtls_mpi_size( X ); + + if( buflen < n ) + return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL ); + + memset( buf, 0, buflen ); + + for( i = buflen - 1, j = 0; n > 0; i--, j++, n-- ) + buf[i] = (unsigned char)( X->p[j / ciL] >> ((j % ciL) << 3) ); + + return( 0 ); +} + +/* + * Left-shift: X <<= count + */ +int mbedtls_mpi_shift_l( mbedtls_mpi *X, size_t count ) +{ + int ret; + size_t i, v0, t1; + mbedtls_mpi_uint r0 = 0, r1; + + v0 = count / (biL ); + t1 = count & (biL - 1); + + i = mbedtls_mpi_bitlen( X ) + count; + + if( X->n * biL < i ) + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, BITS_TO_LIMBS( i ) ) ); + + ret = 0; + + /* + * shift by count / limb_size + */ + if( v0 > 0 ) + { + for( i = X->n; i > v0; i-- ) + X->p[i - 1] = X->p[i - v0 - 1]; + + for( ; i > 0; i-- ) + X->p[i - 1] = 0; + } + + /* + * shift by count % limb_size + */ + if( t1 > 0 ) + { + for( i = v0; i < X->n; i++ ) + { + r1 = X->p[i] >> (biL - t1); + X->p[i] <<= t1; + X->p[i] |= r0; + r0 = r1; + } + } + +cleanup: + + return( ret ); +} + +/* + * Right-shift: X >>= count + */ +int mbedtls_mpi_shift_r( mbedtls_mpi *X, size_t count ) +{ + size_t i, v0, v1; + mbedtls_mpi_uint r0 = 0, r1; + + v0 = count / biL; + v1 = count & (biL - 1); + + if( v0 > X->n || ( v0 == X->n && v1 > 0 ) ) + return mbedtls_mpi_lset( X, 0 ); + + /* + * shift by count / limb_size + */ + if( v0 > 0 ) + { + for( i = 0; i < X->n - v0; i++ ) + X->p[i] = X->p[i + v0]; + + for( ; i < X->n; i++ ) + X->p[i] = 0; + } + + /* + * shift by count % limb_size + */ + if( v1 > 0 ) + { + for( i = X->n; i > 0; i-- ) + { + r1 = X->p[i - 1] << (biL - v1); + X->p[i - 1] >>= v1; + X->p[i - 1] |= r0; + r0 = r1; + } + } + + return( 0 ); +} + +/* + * Compare unsigned values + */ +int mbedtls_mpi_cmp_abs( const mbedtls_mpi *X, const mbedtls_mpi *Y ) +{ + size_t i, j; + + for( i = X->n; i > 0; i-- ) + if( X->p[i - 1] != 0 ) + break; + + for( j = Y->n; j > 0; j-- ) + if( Y->p[j - 1] != 0 ) + break; + + if( i == 0 && j == 0 ) + return( 0 ); + + if( i > j ) return( 1 ); + if( j > i ) return( -1 ); + + for( ; i > 0; i-- ) + { + if( X->p[i - 1] > Y->p[i - 1] ) return( 1 ); + if( X->p[i - 1] < Y->p[i - 1] ) return( -1 ); + } + + return( 0 ); +} + +/* + * Compare signed values + */ +int mbedtls_mpi_cmp_mpi( const mbedtls_mpi *X, const mbedtls_mpi *Y ) +{ + size_t i, j; + + for( i = X->n; i > 0; i-- ) + if( X->p[i - 1] != 0 ) + break; + + for( j = Y->n; j > 0; j-- ) + if( Y->p[j - 1] != 0 ) + break; + + if( i == 0 && j == 0 ) + return( 0 ); + + if( i > j ) return( X->s ); + if( j > i ) return( -Y->s ); + + if( X->s > 0 && Y->s < 0 ) return( 1 ); + if( Y->s > 0 && X->s < 0 ) return( -1 ); + + for( ; i > 0; i-- ) + { + if( X->p[i - 1] > Y->p[i - 1] ) return( X->s ); + if( X->p[i - 1] < Y->p[i - 1] ) return( -X->s ); + } + + return( 0 ); +} + +/* + * Compare signed values + */ +int mbedtls_mpi_cmp_int( const mbedtls_mpi *X, mbedtls_mpi_sint z ) +{ + mbedtls_mpi Y; + mbedtls_mpi_uint p[1]; + + *p = ( z < 0 ) ? -z : z; + Y.s = ( z < 0 ) ? -1 : 1; + Y.n = 1; + Y.p = p; + + return( mbedtls_mpi_cmp_mpi( X, &Y ) ); +} + +/* + * Unsigned addition: X = |A| + |B| (HAC 14.7) + */ +int mbedtls_mpi_add_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ) +{ + int ret; + size_t i, j; + mbedtls_mpi_uint *o, *p, c, tmp; + + if( X == B ) + { + const mbedtls_mpi *T = A; A = X; B = T; + } + + if( X != A ) + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, A ) ); + + /* + * X should always be positive as a result of unsigned additions. + */ + X->s = 1; + + for( j = B->n; j > 0; j-- ) + if( B->p[j - 1] != 0 ) + break; + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) ); + + o = B->p; p = X->p; c = 0; + + /* + * tmp is used because it might happen that p == o + */ + for( i = 0; i < j; i++, o++, p++ ) + { + tmp= *o; + *p += c; c = ( *p < c ); + *p += tmp; c += ( *p < tmp ); + } + + while( c != 0 ) + { + if( i >= X->n ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i + 1 ) ); + p = X->p + i; + } + + *p += c; c = ( *p < c ); i++; p++; + } + +cleanup: + + return( ret ); +} + +/* + * Helper for mbedtls_mpi subtraction + */ +static void mpi_sub_hlp( size_t n, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d ) +{ + size_t i; + mbedtls_mpi_uint c, z; + + for( i = c = 0; i < n; i++, s++, d++ ) + { + z = ( *d < c ); *d -= c; + c = ( *d < *s ) + z; *d -= *s; + } + + while( c != 0 ) + { + z = ( *d < c ); *d -= c; + c = z; d++; + } +} + +/* + * Unsigned subtraction: X = |A| - |B| (HAC 14.9) + */ +int mbedtls_mpi_sub_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ) +{ + mbedtls_mpi TB; + int ret; + size_t n; + + if( mbedtls_mpi_cmp_abs( A, B ) < 0 ) + return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE ); + + mbedtls_mpi_init( &TB ); + + if( X == B ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) ); + B = &TB; + } + + if( X != A ) + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, A ) ); + + /* + * X should always be positive as a result of unsigned subtractions. + */ + X->s = 1; + + ret = 0; + + for( n = B->n; n > 0; n-- ) + if( B->p[n - 1] != 0 ) + break; + + mpi_sub_hlp( n, B->p, X->p ); + +cleanup: + + mbedtls_mpi_free( &TB ); + + return( ret ); +} + +/* + * Signed addition: X = A + B + */ +int mbedtls_mpi_add_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ) +{ + int ret, s = A->s; + + if( A->s * B->s < 0 ) + { + if( mbedtls_mpi_cmp_abs( A, B ) >= 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, A, B ) ); + X->s = s; + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, B, A ) ); + X->s = -s; + } + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( X, A, B ) ); + X->s = s; + } + +cleanup: + + return( ret ); +} + +/* + * Signed subtraction: X = A - B + */ +int mbedtls_mpi_sub_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ) +{ + int ret, s = A->s; + + if( A->s * B->s > 0 ) + { + if( mbedtls_mpi_cmp_abs( A, B ) >= 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, A, B ) ); + X->s = s; + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, B, A ) ); + X->s = -s; + } + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( X, A, B ) ); + X->s = s; + } + +cleanup: + + return( ret ); +} + +/* + * Signed addition: X = A + b + */ +int mbedtls_mpi_add_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b ) +{ + mbedtls_mpi _B; + mbedtls_mpi_uint p[1]; + + p[0] = ( b < 0 ) ? -b : b; + _B.s = ( b < 0 ) ? -1 : 1; + _B.n = 1; + _B.p = p; + + return( mbedtls_mpi_add_mpi( X, A, &_B ) ); +} + +/* + * Signed subtraction: X = A - b + */ +int mbedtls_mpi_sub_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b ) +{ + mbedtls_mpi _B; + mbedtls_mpi_uint p[1]; + + p[0] = ( b < 0 ) ? -b : b; + _B.s = ( b < 0 ) ? -1 : 1; + _B.n = 1; + _B.p = p; + + return( mbedtls_mpi_sub_mpi( X, A, &_B ) ); +} + +/* + * Helper for mbedtls_mpi multiplication + */ +static +#if defined(__APPLE__) && defined(__arm__) +/* + * Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn) + * appears to need this to prevent bad ARM code generation at -O3. + */ +__attribute__ ((noinline)) +#endif +void mpi_mul_hlp( size_t i, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d, mbedtls_mpi_uint b ) +{ + mbedtls_mpi_uint c = 0, t = 0; + +#if defined(MULADDC_HUIT) + for( ; i >= 8; i -= 8 ) + { + MULADDC_INIT + MULADDC_HUIT + MULADDC_STOP + } + + for( ; i > 0; i-- ) + { + MULADDC_INIT + MULADDC_CORE + MULADDC_STOP + } +#else /* MULADDC_HUIT */ + for( ; i >= 16; i -= 16 ) + { + MULADDC_INIT + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_STOP + } + + for( ; i >= 8; i -= 8 ) + { + MULADDC_INIT + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_STOP + } + + for( ; i > 0; i-- ) + { + MULADDC_INIT + MULADDC_CORE + MULADDC_STOP + } +#endif /* MULADDC_HUIT */ + + t++; + + do { + *d += c; c = ( *d < c ); d++; + } + while( c != 0 ); +} + +/* + * Baseline multiplication: X = A * B (HAC 14.12) + */ +int mbedtls_mpi_mul_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ) +{ + int ret; + size_t i, j; + mbedtls_mpi TA, TB; + + mbedtls_mpi_init( &TA ); mbedtls_mpi_init( &TB ); + + if( X == A ) { MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TA, A ) ); A = &TA; } + if( X == B ) { MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) ); B = &TB; } + + for( i = A->n; i > 0; i-- ) + if( A->p[i - 1] != 0 ) + break; + + for( j = B->n; j > 0; j-- ) + if( B->p[j - 1] != 0 ) + break; + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i + j ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) ); + + for( ; j > 0; j-- ) + mpi_mul_hlp( i, A->p, X->p + j - 1, B->p[j - 1] ); + + X->s = A->s * B->s; + +cleanup: + + mbedtls_mpi_free( &TB ); mbedtls_mpi_free( &TA ); + + return( ret ); +} + +/* + * Baseline multiplication: X = A * b + */ +int mbedtls_mpi_mul_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint b ) +{ + mbedtls_mpi _B; + mbedtls_mpi_uint p[1]; + + _B.s = 1; + _B.n = 1; + _B.p = p; + p[0] = b; + + return( mbedtls_mpi_mul_mpi( X, A, &_B ) ); +} + +/* + * Unsigned integer divide - double mbedtls_mpi_uint dividend, u1/u0, and + * mbedtls_mpi_uint divisor, d + */ +static mbedtls_mpi_uint mbedtls_int_div_int( mbedtls_mpi_uint u1, + mbedtls_mpi_uint u0, mbedtls_mpi_uint d, mbedtls_mpi_uint *r ) +{ +#if defined(MBEDTLS_HAVE_UDBL) + mbedtls_t_udbl dividend, quotient; +#else + const mbedtls_mpi_uint radix = (mbedtls_mpi_uint) 1 << biH; + const mbedtls_mpi_uint uint_halfword_mask = ( (mbedtls_mpi_uint) 1 << biH ) - 1; + mbedtls_mpi_uint d0, d1, q0, q1, rAX, r0, quotient; + mbedtls_mpi_uint u0_msw, u0_lsw; + size_t s; +#endif + + /* + * Check for overflow + */ + if( 0 == d || u1 >= d ) + { + if (r != NULL) *r = ~0; + + return ( ~0 ); + } + +#if defined(MBEDTLS_HAVE_UDBL) + dividend = (mbedtls_t_udbl) u1 << biL; + dividend |= (mbedtls_t_udbl) u0; + quotient = dividend / d; + if( quotient > ( (mbedtls_t_udbl) 1 << biL ) - 1 ) + quotient = ( (mbedtls_t_udbl) 1 << biL ) - 1; + + if( r != NULL ) + *r = (mbedtls_mpi_uint)( dividend - (quotient * d ) ); + + return (mbedtls_mpi_uint) quotient; +#else + + /* + * Algorithm D, Section 4.3.1 - The Art of Computer Programming + * Vol. 2 - Seminumerical Algorithms, Knuth + */ + + /* + * Normalize the divisor, d, and dividend, u0, u1 + */ + s = mbedtls_clz( d ); + d = d << s; + + u1 = u1 << s; + u1 |= ( u0 >> ( biL - s ) ) & ( -(mbedtls_mpi_sint)s >> ( biL - 1 ) ); + u0 = u0 << s; + + d1 = d >> biH; + d0 = d & uint_halfword_mask; + + u0_msw = u0 >> biH; + u0_lsw = u0 & uint_halfword_mask; + + /* + * Find the first quotient and remainder + */ + q1 = u1 / d1; + r0 = u1 - d1 * q1; + + while( q1 >= radix || ( q1 * d0 > radix * r0 + u0_msw ) ) + { + q1 -= 1; + r0 += d1; + + if ( r0 >= radix ) break; + } + + rAX = ( u1 * radix ) + ( u0_msw - q1 * d ); + q0 = rAX / d1; + r0 = rAX - q0 * d1; + + while( q0 >= radix || ( q0 * d0 > radix * r0 + u0_lsw ) ) + { + q0 -= 1; + r0 += d1; + + if ( r0 >= radix ) break; + } + + if (r != NULL) + *r = ( rAX * radix + u0_lsw - q0 * d ) >> s; + + quotient = q1 * radix + q0; + + return quotient; +#endif +} + +/* + * Division by mbedtls_mpi: A = Q * B + R (HAC 14.20) + */ +int mbedtls_mpi_div_mpi( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B ) +{ + int ret; + size_t i, n, t, k; + mbedtls_mpi X, Y, Z, T1, T2; + + if( mbedtls_mpi_cmp_int( B, 0 ) == 0 ) + return( MBEDTLS_ERR_MPI_DIVISION_BY_ZERO ); + + mbedtls_mpi_init( &X ); mbedtls_mpi_init( &Y ); mbedtls_mpi_init( &Z ); + mbedtls_mpi_init( &T1 ); mbedtls_mpi_init( &T2 ); + + if( mbedtls_mpi_cmp_abs( A, B ) < 0 ) + { + if( Q != NULL ) MBEDTLS_MPI_CHK( mbedtls_mpi_lset( Q, 0 ) ); + if( R != NULL ) MBEDTLS_MPI_CHK( mbedtls_mpi_copy( R, A ) ); + return( 0 ); + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &X, A ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Y, B ) ); + X.s = Y.s = 1; + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &Z, A->n + 2 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &Z, 0 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T1, 2 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T2, 3 ) ); + + k = mbedtls_mpi_bitlen( &Y ) % biL; + if( k < biL - 1 ) + { + k = biL - 1 - k; + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &X, k ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &Y, k ) ); + } + else k = 0; + + n = X.n - 1; + t = Y.n - 1; + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &Y, biL * ( n - t ) ) ); + + while( mbedtls_mpi_cmp_mpi( &X, &Y ) >= 0 ) + { + Z.p[n - t]++; + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &Y ) ); + } + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &Y, biL * ( n - t ) ) ); + + for( i = n; i > t ; i-- ) + { + if( X.p[i] >= Y.p[t] ) + Z.p[i - t - 1] = ~0; + else + { + Z.p[i - t - 1] = mbedtls_int_div_int( X.p[i], X.p[i - 1], + Y.p[t], NULL); + } + + Z.p[i - t - 1]++; + do + { + Z.p[i - t - 1]--; + + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &T1, 0 ) ); + T1.p[0] = ( t < 1 ) ? 0 : Y.p[t - 1]; + T1.p[1] = Y.p[t]; + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T1, &T1, Z.p[i - t - 1] ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &T2, 0 ) ); + T2.p[0] = ( i < 2 ) ? 0 : X.p[i - 2]; + T2.p[1] = ( i < 1 ) ? 0 : X.p[i - 1]; + T2.p[2] = X.p[i]; + } + while( mbedtls_mpi_cmp_mpi( &T1, &T2 ) > 0 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T1, &Y, Z.p[i - t - 1] ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &T1, biL * ( i - t - 1 ) ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &T1 ) ); + + if( mbedtls_mpi_cmp_int( &X, 0 ) < 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &T1, &Y ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &T1, biL * ( i - t - 1 ) ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &X, &X, &T1 ) ); + Z.p[i - t - 1]--; + } + } + + if( Q != NULL ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( Q, &Z ) ); + Q->s = A->s * B->s; + } + + if( R != NULL ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &X, k ) ); + X.s = A->s; + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( R, &X ) ); + + if( mbedtls_mpi_cmp_int( R, 0 ) == 0 ) + R->s = 1; + } + +cleanup: + + mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &Z ); + mbedtls_mpi_free( &T1 ); mbedtls_mpi_free( &T2 ); + + return( ret ); +} + +/* + * Division by int: A = Q * b + R + */ +int mbedtls_mpi_div_int( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, mbedtls_mpi_sint b ) +{ + mbedtls_mpi _B; + mbedtls_mpi_uint p[1]; + + p[0] = ( b < 0 ) ? -b : b; + _B.s = ( b < 0 ) ? -1 : 1; + _B.n = 1; + _B.p = p; + + return( mbedtls_mpi_div_mpi( Q, R, A, &_B ) ); +} + +/* + * Modulo: R = A mod B + */ +int mbedtls_mpi_mod_mpi( mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B ) +{ + int ret; + + if( mbedtls_mpi_cmp_int( B, 0 ) < 0 ) + return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( NULL, R, A, B ) ); + + while( mbedtls_mpi_cmp_int( R, 0 ) < 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( R, R, B ) ); + + while( mbedtls_mpi_cmp_mpi( R, B ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( R, R, B ) ); + +cleanup: + + return( ret ); +} + +/* + * Modulo: r = A mod b + */ +int mbedtls_mpi_mod_int( mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_sint b ) +{ + size_t i; + mbedtls_mpi_uint x, y, z; + + if( b == 0 ) + return( MBEDTLS_ERR_MPI_DIVISION_BY_ZERO ); + + if( b < 0 ) + return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE ); + + /* + * handle trivial cases + */ + if( b == 1 ) + { + *r = 0; + return( 0 ); + } + + if( b == 2 ) + { + *r = A->p[0] & 1; + return( 0 ); + } + + /* + * general case + */ + for( i = A->n, y = 0; i > 0; i-- ) + { + x = A->p[i - 1]; + y = ( y << biH ) | ( x >> biH ); + z = y / b; + y -= z * b; + + x <<= biH; + y = ( y << biH ) | ( x >> biH ); + z = y / b; + y -= z * b; + } + + /* + * If A is negative, then the current y represents a negative value. + * Flipping it to the positive side. + */ + if( A->s < 0 && y != 0 ) + y = b - y; + + *r = y; + + return( 0 ); +} + +/* + * Fast Montgomery initialization (thanks to Tom St Denis) + */ +static void mpi_montg_init( mbedtls_mpi_uint *mm, const mbedtls_mpi *N ) +{ + mbedtls_mpi_uint x, m0 = N->p[0]; + unsigned int i; + + x = m0; + x += ( ( m0 + 2 ) & 4 ) << 1; + + for( i = biL; i >= 8; i /= 2 ) + x *= ( 2 - ( m0 * x ) ); + + *mm = ~x + 1; +} + +/* + * Montgomery multiplication: A = A * B * R^-1 mod N (HAC 14.36) + */ +static int mpi_montmul( mbedtls_mpi *A, const mbedtls_mpi *B, const mbedtls_mpi *N, mbedtls_mpi_uint mm, + const mbedtls_mpi *T ) +{ + size_t i, n, m; + mbedtls_mpi_uint u0, u1, *d; + + if( T->n < N->n + 1 || T->p == NULL ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + memset( T->p, 0, T->n * ciL ); + + d = T->p; + n = N->n; + m = ( B->n < n ) ? B->n : n; + + for( i = 0; i < n; i++ ) + { + /* + * T = (T + u0*B + u1*N) / 2^biL + */ + u0 = A->p[i]; + u1 = ( d[0] + u0 * B->p[0] ) * mm; + + mpi_mul_hlp( m, B->p, d, u0 ); + mpi_mul_hlp( n, N->p, d, u1 ); + + *d++ = u0; d[n + 1] = 0; + } + + memcpy( A->p, d, ( n + 1 ) * ciL ); + + if( mbedtls_mpi_cmp_abs( A, N ) >= 0 ) + mpi_sub_hlp( n, N->p, A->p ); + else + /* prevent timing attacks */ + mpi_sub_hlp( n, A->p, T->p ); + + return( 0 ); +} + +/* + * Montgomery reduction: A = A * R^-1 mod N + */ +static int mpi_montred( mbedtls_mpi *A, const mbedtls_mpi *N, mbedtls_mpi_uint mm, const mbedtls_mpi *T ) +{ + mbedtls_mpi_uint z = 1; + mbedtls_mpi U; + + U.n = U.s = (int) z; + U.p = &z; + + return( mpi_montmul( A, &U, N, mm, T ) ); +} + +/* + * Sliding-window exponentiation: X = A^E mod N (HAC 14.85) + */ +int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *E, const mbedtls_mpi *N, mbedtls_mpi *_RR ) +{ + int ret; + size_t wbits, wsize, one = 1; + size_t i, j, nblimbs; + size_t bufsize, nbits; + mbedtls_mpi_uint ei, mm, state; + mbedtls_mpi RR, T, W[ 2 << MBEDTLS_MPI_WINDOW_SIZE ], Apos; + int neg; + + if( mbedtls_mpi_cmp_int( N, 0 ) <= 0 || ( N->p[0] & 1 ) == 0 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + if( mbedtls_mpi_cmp_int( E, 0 ) < 0 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + /* + * Init temps and window size + */ + mpi_montg_init( &mm, N ); + mbedtls_mpi_init( &RR ); mbedtls_mpi_init( &T ); + mbedtls_mpi_init( &Apos ); + memset( W, 0, sizeof( W ) ); + + i = mbedtls_mpi_bitlen( E ); + + wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 : + ( i > 79 ) ? 4 : ( i > 23 ) ? 3 : 1; + + if( wsize > MBEDTLS_MPI_WINDOW_SIZE ) + wsize = MBEDTLS_MPI_WINDOW_SIZE; + + j = N->n + 1; + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[1], j ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T, j * 2 ) ); + + /* + * Compensate for negative A (and correct at the end) + */ + neg = ( A->s == -1 ); + if( neg ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Apos, A ) ); + Apos.s = 1; + A = &Apos; + } + + /* + * If 1st call, pre-compute R^2 mod N + */ + if( _RR == NULL || _RR->p == NULL ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &RR, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &RR, N->n * 2 * biL ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &RR, &RR, N ) ); + + if( _RR != NULL ) + memcpy( _RR, &RR, sizeof( mbedtls_mpi ) ); + } + else + memcpy( &RR, _RR, sizeof( mbedtls_mpi ) ); + + /* + * W[1] = A * R^2 * R^-1 mod N = A * R mod N + */ + if( mbedtls_mpi_cmp_mpi( A, N ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &W[1], A, N ) ); + else + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[1], A ) ); + + MBEDTLS_MPI_CHK( mpi_montmul( &W[1], &RR, N, mm, &T ) ); + + /* + * X = R^2 * R^-1 mod N = R mod N + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, &RR ) ); + MBEDTLS_MPI_CHK( mpi_montred( X, N, mm, &T ) ); + + if( wsize > 1 ) + { + /* + * W[1 << (wsize - 1)] = W[1] ^ (wsize - 1) + */ + j = one << ( wsize - 1 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[j], N->n + 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[j], &W[1] ) ); + + for( i = 0; i < wsize - 1; i++ ) + MBEDTLS_MPI_CHK( mpi_montmul( &W[j], &W[j], N, mm, &T ) ); + + /* + * W[i] = W[i - 1] * W[1] + */ + for( i = j + 1; i < ( one << wsize ); i++ ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[i], N->n + 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[i], &W[i - 1] ) ); + + MBEDTLS_MPI_CHK( mpi_montmul( &W[i], &W[1], N, mm, &T ) ); + } + } + + nblimbs = E->n; + bufsize = 0; + nbits = 0; + wbits = 0; + state = 0; + + while( 1 ) + { + if( bufsize == 0 ) + { + if( nblimbs == 0 ) + break; + + nblimbs--; + + bufsize = sizeof( mbedtls_mpi_uint ) << 3; + } + + bufsize--; + + ei = (E->p[nblimbs] >> bufsize) & 1; + + /* + * skip leading 0s + */ + if( ei == 0 && state == 0 ) + continue; + + if( ei == 0 && state == 1 ) + { + /* + * out of window, square X + */ + MBEDTLS_MPI_CHK( mpi_montmul( X, X, N, mm, &T ) ); + continue; + } + + /* + * add ei to current window + */ + state = 2; + + nbits++; + wbits |= ( ei << ( wsize - nbits ) ); + + if( nbits == wsize ) + { + /* + * X = X^wsize R^-1 mod N + */ + for( i = 0; i < wsize; i++ ) + MBEDTLS_MPI_CHK( mpi_montmul( X, X, N, mm, &T ) ); + + /* + * X = X * W[wbits] R^-1 mod N + */ + MBEDTLS_MPI_CHK( mpi_montmul( X, &W[wbits], N, mm, &T ) ); + + state--; + nbits = 0; + wbits = 0; + } + } + + /* + * process the remaining bits + */ + for( i = 0; i < nbits; i++ ) + { + MBEDTLS_MPI_CHK( mpi_montmul( X, X, N, mm, &T ) ); + + wbits <<= 1; + + if( ( wbits & ( one << wsize ) ) != 0 ) + MBEDTLS_MPI_CHK( mpi_montmul( X, &W[1], N, mm, &T ) ); + } + + /* + * X = A^E * R * R^-1 mod N = A^E mod N + */ + MBEDTLS_MPI_CHK( mpi_montred( X, N, mm, &T ) ); + + if( neg && E->n != 0 && ( E->p[0] & 1 ) != 0 ) + { + X->s = -1; + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( X, N, X ) ); + } + +cleanup: + + for( i = ( one << ( wsize - 1 ) ); i < ( one << wsize ); i++ ) + mbedtls_mpi_free( &W[i] ); + + mbedtls_mpi_free( &W[1] ); mbedtls_mpi_free( &T ); mbedtls_mpi_free( &Apos ); + + if( _RR == NULL || _RR->p == NULL ) + mbedtls_mpi_free( &RR ); + + return( ret ); +} + +/* + * Greatest common divisor: G = gcd(A, B) (HAC 14.54) + */ +int mbedtls_mpi_gcd( mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B ) +{ + int ret; + size_t lz, lzt; + mbedtls_mpi TG, TA, TB; + + mbedtls_mpi_init( &TG ); mbedtls_mpi_init( &TA ); mbedtls_mpi_init( &TB ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TA, A ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) ); + + lz = mbedtls_mpi_lsb( &TA ); + lzt = mbedtls_mpi_lsb( &TB ); + + if( lzt < lz ) + lz = lzt; + + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, lz ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, lz ) ); + + TA.s = TB.s = 1; + + while( mbedtls_mpi_cmp_int( &TA, 0 ) != 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, mbedtls_mpi_lsb( &TA ) ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, mbedtls_mpi_lsb( &TB ) ) ); + + if( mbedtls_mpi_cmp_mpi( &TA, &TB ) >= 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &TA, &TA, &TB ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, 1 ) ); + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &TB, &TB, &TA ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, 1 ) ); + } + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &TB, lz ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( G, &TB ) ); + +cleanup: + + mbedtls_mpi_free( &TG ); mbedtls_mpi_free( &TA ); mbedtls_mpi_free( &TB ); + + return( ret ); +} + +/* + * Fill X with size bytes of random. + * + * Use a temporary bytes representation to make sure the result is the same + * regardless of the platform endianness (useful when f_rng is actually + * deterministic, eg for tests). + */ +int mbedtls_mpi_fill_random( mbedtls_mpi *X, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; + + if( size > MBEDTLS_MPI_MAX_SIZE ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + MBEDTLS_MPI_CHK( f_rng( p_rng, buf, size ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( X, buf, size ) ); + +cleanup: + mbedtls_platform_zeroize( buf, sizeof( buf ) ); + return( ret ); +} + +/* + * Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64) + */ +int mbedtls_mpi_inv_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N ) +{ + int ret; + mbedtls_mpi G, TA, TU, U1, U2, TB, TV, V1, V2; + + if( mbedtls_mpi_cmp_int( N, 1 ) <= 0 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + mbedtls_mpi_init( &TA ); mbedtls_mpi_init( &TU ); mbedtls_mpi_init( &U1 ); mbedtls_mpi_init( &U2 ); + mbedtls_mpi_init( &G ); mbedtls_mpi_init( &TB ); mbedtls_mpi_init( &TV ); + mbedtls_mpi_init( &V1 ); mbedtls_mpi_init( &V2 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G, A, N ) ); + + if( mbedtls_mpi_cmp_int( &G, 1 ) != 0 ) + { + ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; + goto cleanup; + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &TA, A, N ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TU, &TA ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, N ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TV, N ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &U1, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &U2, 0 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &V1, 0 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &V2, 1 ) ); + + do + { + while( ( TU.p[0] & 1 ) == 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TU, 1 ) ); + + if( ( U1.p[0] & 1 ) != 0 || ( U2.p[0] & 1 ) != 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &U1, &U1, &TB ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U2, &U2, &TA ) ); + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &U1, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &U2, 1 ) ); + } + + while( ( TV.p[0] & 1 ) == 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TV, 1 ) ); + + if( ( V1.p[0] & 1 ) != 0 || ( V2.p[0] & 1 ) != 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &V1, &V1, &TB ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V2, &V2, &TA ) ); + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &V1, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &V2, 1 ) ); + } + + if( mbedtls_mpi_cmp_mpi( &TU, &TV ) >= 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &TU, &TU, &TV ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U1, &U1, &V1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U2, &U2, &V2 ) ); + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &TV, &TV, &TU ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V1, &V1, &U1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V2, &V2, &U2 ) ); + } + } + while( mbedtls_mpi_cmp_int( &TU, 0 ) != 0 ); + + while( mbedtls_mpi_cmp_int( &V1, 0 ) < 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &V1, &V1, N ) ); + + while( mbedtls_mpi_cmp_mpi( &V1, N ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V1, &V1, N ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, &V1 ) ); + +cleanup: + + mbedtls_mpi_free( &TA ); mbedtls_mpi_free( &TU ); mbedtls_mpi_free( &U1 ); mbedtls_mpi_free( &U2 ); + mbedtls_mpi_free( &G ); mbedtls_mpi_free( &TB ); mbedtls_mpi_free( &TV ); + mbedtls_mpi_free( &V1 ); mbedtls_mpi_free( &V2 ); + + return( ret ); +} + +#if defined(MBEDTLS_GENPRIME) + +static const int small_prime[] = +{ + 3, 5, 7, 11, 13, 17, 19, 23, + 29, 31, 37, 41, 43, 47, 53, 59, + 61, 67, 71, 73, 79, 83, 89, 97, + 101, 103, 107, 109, 113, 127, 131, 137, + 139, 149, 151, 157, 163, 167, 173, 179, + 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251, 257, 263, 269, + 271, 277, 281, 283, 293, 307, 311, 313, + 317, 331, 337, 347, 349, 353, 359, 367, + 373, 379, 383, 389, 397, 401, 409, 419, + 421, 431, 433, 439, 443, 449, 457, 461, + 463, 467, 479, 487, 491, 499, 503, 509, + 521, 523, 541, 547, 557, 563, 569, 571, + 577, 587, 593, 599, 601, 607, 613, 617, + 619, 631, 641, 643, 647, 653, 659, 661, + 673, 677, 683, 691, 701, 709, 719, 727, + 733, 739, 743, 751, 757, 761, 769, 773, + 787, 797, 809, 811, 821, 823, 827, 829, + 839, 853, 857, 859, 863, 877, 881, 883, + 887, 907, 911, 919, 929, 937, 941, 947, + 953, 967, 971, 977, 983, 991, 997, -103 +}; + +/* + * Small divisors test (X must be positive) + * + * Return values: + * 0: no small factor (possible prime, more tests needed) + * 1: certain prime + * MBEDTLS_ERR_MPI_NOT_ACCEPTABLE: certain non-prime + * other negative: error + */ +static int mpi_check_small_factors( const mbedtls_mpi *X ) +{ + int ret = 0; + size_t i; + mbedtls_mpi_uint r; + + if( ( X->p[0] & 1 ) == 0 ) + return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ); + + for( i = 0; small_prime[i] > 0; i++ ) + { + if( mbedtls_mpi_cmp_int( X, small_prime[i] ) <= 0 ) + return( 1 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, small_prime[i] ) ); + + if( r == 0 ) + return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ); + } + +cleanup: + return( ret ); +} + +/* + * Miller-Rabin pseudo-primality test (HAC 4.24) + */ +static int mpi_miller_rabin( const mbedtls_mpi *X, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret, count; + size_t i, j, k, n, s; + mbedtls_mpi W, R, T, A, RR; + + mbedtls_mpi_init( &W ); mbedtls_mpi_init( &R ); mbedtls_mpi_init( &T ); mbedtls_mpi_init( &A ); + mbedtls_mpi_init( &RR ); + + /* + * W = |X| - 1 + * R = W >> lsb( W ) + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &W, X, 1 ) ); + s = mbedtls_mpi_lsb( &W ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R, &W ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &R, s ) ); + + i = mbedtls_mpi_bitlen( X ); + /* + * HAC, table 4.4 + */ + n = ( ( i >= 1300 ) ? 2 : ( i >= 850 ) ? 3 : + ( i >= 650 ) ? 4 : ( i >= 350 ) ? 8 : + ( i >= 250 ) ? 12 : ( i >= 150 ) ? 18 : 27 ); + + for( i = 0; i < n; i++ ) + { + /* + * pick a random A, 1 < A < |X| - 1 + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) ); + + if( mbedtls_mpi_cmp_mpi( &A, &W ) >= 0 ) + { + j = mbedtls_mpi_bitlen( &A ) - mbedtls_mpi_bitlen( &W ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &A, j + 1 ) ); + } + A.p[0] |= 3; + + count = 0; + do { + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) ); + + j = mbedtls_mpi_bitlen( &A ); + k = mbedtls_mpi_bitlen( &W ); + if (j > k) { + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &A, j - k ) ); + } + + if (count++ > 30) { + return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; + } + + } while ( mbedtls_mpi_cmp_mpi( &A, &W ) >= 0 || + mbedtls_mpi_cmp_int( &A, 1 ) <= 0 ); + + /* + * A = A^R mod |X| + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &A, &A, &R, X, &RR ) ); + + if( mbedtls_mpi_cmp_mpi( &A, &W ) == 0 || + mbedtls_mpi_cmp_int( &A, 1 ) == 0 ) + continue; + + j = 1; + while( j < s && mbedtls_mpi_cmp_mpi( &A, &W ) != 0 ) + { + /* + * A = A * A mod |X| + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &A, &A ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &A, &T, X ) ); + + if( mbedtls_mpi_cmp_int( &A, 1 ) == 0 ) + break; + + j++; + } + + /* + * not prime if A != |X| - 1 or A == 1 + */ + if( mbedtls_mpi_cmp_mpi( &A, &W ) != 0 || + mbedtls_mpi_cmp_int( &A, 1 ) == 0 ) + { + ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; + break; + } + } + +cleanup: + mbedtls_mpi_free( &W ); mbedtls_mpi_free( &R ); mbedtls_mpi_free( &T ); mbedtls_mpi_free( &A ); + mbedtls_mpi_free( &RR ); + + return( ret ); +} + +/* + * Pseudo-primality test: small factors, then Miller-Rabin + */ +int mbedtls_mpi_is_prime( const mbedtls_mpi *X, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + mbedtls_mpi XX; + + XX.s = 1; + XX.n = X->n; + XX.p = X->p; + + if( mbedtls_mpi_cmp_int( &XX, 0 ) == 0 || + mbedtls_mpi_cmp_int( &XX, 1 ) == 0 ) + return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ); + + if( mbedtls_mpi_cmp_int( &XX, 2 ) == 0 ) + return( 0 ); + + if( ( ret = mpi_check_small_factors( &XX ) ) != 0 ) + { + if( ret == 1 ) + return( 0 ); + + return( ret ); + } + + return( mpi_miller_rabin( &XX, f_rng, p_rng ) ); +} + +/* + * Prime number generation + * + * If dh_flag is 0 and nbits is at least 1024, then the procedure + * follows the RSA probably-prime generation method of FIPS 186-4. + * NB. FIPS 186-4 only allows the specific bit lengths of 1024 and 1536. + */ +int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int dh_flag, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ +#ifdef MBEDTLS_HAVE_INT64 +// ceil(2^63.5) +#define CEIL_MAXUINT_DIV_SQRT2 0xb504f333f9de6485ULL +#else +// ceil(2^31.5) +#define CEIL_MAXUINT_DIV_SQRT2 0xb504f334U +#endif + int ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; + size_t k, n; + mbedtls_mpi_uint r; + mbedtls_mpi Y; + + if( nbits < 3 || nbits > MBEDTLS_MPI_MAX_BITS ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + mbedtls_mpi_init( &Y ); + + n = BITS_TO_LIMBS( nbits ); + + while( 1 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( X, n * ciL, f_rng, p_rng ) ); + /* make sure generated number is at least (nbits-1)+0.5 bits (FIPS 186-4 §B.3.3 steps 4.4, 5.5) */ + if( X->p[n-1] < CEIL_MAXUINT_DIV_SQRT2 ) continue; + + k = n * biL; + if( k > nbits ) MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( X, k - nbits ) ); + X->p[0] |= 1; + + if( dh_flag == 0 ) + { + ret = mbedtls_mpi_is_prime( X, f_rng, p_rng ); + + if( ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ) + goto cleanup; + } + else + { + /* + * An necessary condition for Y and X = 2Y + 1 to be prime + * is X = 2 mod 3 (which is equivalent to Y = 2 mod 3). + * Make sure it is satisfied, while keeping X = 3 mod 4 + */ + + X->p[0] |= 2; + + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, 3 ) ); + if( r == 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 8 ) ); + else if( r == 1 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 4 ) ); + + /* Set Y = (X-1) / 2, which is X / 2 because X is odd */ + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Y, X ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &Y, 1 ) ); + + while( 1 ) + { + /* + * First, check small factors for X and Y + * before doing Miller-Rabin on any of them + */ + if( ( ret = mpi_check_small_factors( X ) ) == 0 && + ( ret = mpi_check_small_factors( &Y ) ) == 0 && + ( ret = mpi_miller_rabin( X, f_rng, p_rng ) ) == 0 && + ( ret = mpi_miller_rabin( &Y, f_rng, p_rng ) ) == 0 ) + goto cleanup; + + if( ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ) + goto cleanup; + + /* + * Next candidates. We want to preserve Y = (X-1) / 2 and + * Y = 1 mod 2 and Y = 2 mod 3 (eq X = 3 mod 4 and X = 2 mod 3) + * so up Y by 6 and X by 12. + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 12 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( &Y, &Y, 6 ) ); + } + } + } + +cleanup: + + mbedtls_mpi_free( &Y ); + + return( ret ); +} + +#endif /* MBEDTLS_GENPRIME */ + +#if defined(MBEDTLS_SELF_TEST) + +#define GCD_PAIR_COUNT 3 + +static const int gcd_pairs[GCD_PAIR_COUNT][3] = +{ + { 693, 609, 21 }, + { 1764, 868, 28 }, + { 768454923, 542167814, 1 } +}; + +/* + * Checkup routine + */ +int mbedtls_mpi_self_test( int verbose ) +{ + int ret, i; + mbedtls_mpi A, E, N, X, Y, U, V; + + mbedtls_mpi_init( &A ); mbedtls_mpi_init( &E ); mbedtls_mpi_init( &N ); mbedtls_mpi_init( &X ); + mbedtls_mpi_init( &Y ); mbedtls_mpi_init( &U ); mbedtls_mpi_init( &V ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &A, 16, + "EFE021C2645FD1DC586E69184AF4A31E" \ + "D5F53E93B5F123FA41680867BA110131" \ + "944FE7952E2517337780CB0DB80E61AA" \ + "E7C8DDC6C5C6AADEB34EB38A2F40D5E6" ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &E, 16, + "B2E7EFD37075B9F03FF989C7C5051C20" \ + "34D2A323810251127E7BF8625A4F49A5" \ + "F3E27F4DA8BD59C47D6DAABA4C8127BD" \ + "5B5C25763222FEFCCFC38B832366C29E" ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &N, 16, + "0066A198186C18C10B2F5ED9B522752A" \ + "9830B69916E535C8F047518A889A43A5" \ + "94B6BED27A168D31D4A52F88925AA8F5" ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &X, &A, &N ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16, + "602AB7ECA597A3D6B56FF9829A5E8B85" \ + "9E857EA95A03512E2BAE7391688D264A" \ + "A5663B0341DB9CCFD2C4C5F421FEC814" \ + "8001B72E848A38CAE1C65F78E56ABDEF" \ + "E12D3C039B8A02D6BE593F0BBBDA56F1" \ + "ECF677152EF804370C1A305CAF3B5BF1" \ + "30879B56C61DE584A0F53A2447A51E" ) ); + + if( verbose != 0 ) + mbedtls_printf( " MPI test #1 (mul_mpi): " ); + + if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto cleanup; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( &X, &Y, &A, &N ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16, + "256567336059E52CAE22925474705F39A94" ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &V, 16, + "6613F26162223DF488E9CD48CC132C7A" \ + "0AC93C701B001B092E4E5B9F73BCD27B" \ + "9EE50D0657C77F374E903CDFA4C642" ) ); + + if( verbose != 0 ) + mbedtls_printf( " MPI test #2 (div_mpi): " ); + + if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 || + mbedtls_mpi_cmp_mpi( &Y, &V ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto cleanup; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &X, &A, &E, &N, NULL ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16, + "36E139AEA55215609D2816998ED020BB" \ + "BD96C37890F65171D948E9BC7CBAA4D9" \ + "325D24D6A3C12710F10A09FA08AB87" ) ); + + if( verbose != 0 ) + mbedtls_printf( " MPI test #3 (exp_mod): " ); + + if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto cleanup; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &X, &A, &N ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16, + "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \ + "C3DBA76456363A10869622EAC2DD84EC" \ + "C5B8A74DAC4D09E03B5E0BE779F2DF61" ) ); + + if( verbose != 0 ) + mbedtls_printf( " MPI test #4 (inv_mod): " ); + + if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto cleanup; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " MPI test #5 (simple gcd): " ); + + for( i = 0; i < GCD_PAIR_COUNT; i++ ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &X, gcd_pairs[i][0] ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &Y, gcd_pairs[i][1] ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &A, &X, &Y ) ); + + if( mbedtls_mpi_cmp_int( &A, gcd_pairs[i][2] ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed at %d\n", i ); + + ret = 1; + goto cleanup; + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + +cleanup: + + if( ret != 0 && verbose != 0 ) + mbedtls_printf( "Unexpected error, return code = %08X\n", ret ); + + mbedtls_mpi_free( &A ); mbedtls_mpi_free( &E ); mbedtls_mpi_free( &N ); mbedtls_mpi_free( &X ); + mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &U ); mbedtls_mpi_free( &V ); + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_BIGNUM_C */ diff --git a/common/mbedtls/bignum.h b/common/mbedtls/bignum.h new file mode 100644 index 00000000..00787908 --- /dev/null +++ b/common/mbedtls/bignum.h @@ -0,0 +1,774 @@ +/** + * \file bignum.h + * + * \brief Multi-precision integer library + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_BIGNUM_H +#define MBEDTLS_BIGNUM_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#if defined(MBEDTLS_FS_IO) +#include +#endif + +#define MBEDTLS_ERR_MPI_FILE_IO_ERROR -0x0002 /**< An error occurred while reading from or writing to a file. */ +#define MBEDTLS_ERR_MPI_BAD_INPUT_DATA -0x0004 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_MPI_INVALID_CHARACTER -0x0006 /**< There is an invalid character in the digit string. */ +#define MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL -0x0008 /**< The buffer is too small to write to. */ +#define MBEDTLS_ERR_MPI_NEGATIVE_VALUE -0x000A /**< The input arguments are negative or result in illegal output. */ +#define MBEDTLS_ERR_MPI_DIVISION_BY_ZERO -0x000C /**< The input argument for division is zero, which is not allowed. */ +#define MBEDTLS_ERR_MPI_NOT_ACCEPTABLE -0x000E /**< The input arguments are not acceptable. */ +#define MBEDTLS_ERR_MPI_ALLOC_FAILED -0x0010 /**< Memory allocation failed. */ + +#define MBEDTLS_MPI_CHK(f) do { if( ( ret = f ) != 0 ) goto cleanup; } while( 0 ) + +/* + * Maximum size MPIs are allowed to grow to in number of limbs. + */ +#define MBEDTLS_MPI_MAX_LIMBS 10000 + +#if !defined(MBEDTLS_MPI_WINDOW_SIZE) +/* + * Maximum window size used for modular exponentiation. Default: 6 + * Minimum value: 1. Maximum value: 6. + * + * Result is an array of ( 2 << MBEDTLS_MPI_WINDOW_SIZE ) MPIs used + * for the sliding window calculation. (So 64 by default) + * + * Reduction in size, reduces speed. + */ +#define MBEDTLS_MPI_WINDOW_SIZE 6 /**< Maximum windows size used. */ +#endif /* !MBEDTLS_MPI_WINDOW_SIZE */ + +#if !defined(MBEDTLS_MPI_MAX_SIZE) +/* + * Maximum size of MPIs allowed in bits and bytes for user-MPIs. + * ( Default: 512 bytes => 4096 bits, Maximum tested: 2048 bytes => 16384 bits ) + * + * Note: Calculations can temporarily result in larger MPIs. So the number + * of limbs required (MBEDTLS_MPI_MAX_LIMBS) is higher. + */ +#define MBEDTLS_MPI_MAX_SIZE 1024 /**< Maximum number of bytes for usable MPIs. */ +#endif /* !MBEDTLS_MPI_MAX_SIZE */ + +#define MBEDTLS_MPI_MAX_BITS ( 8 * MBEDTLS_MPI_MAX_SIZE ) /**< Maximum number of bits for usable MPIs. */ + +/* + * When reading from files with mbedtls_mpi_read_file() and writing to files with + * mbedtls_mpi_write_file() the buffer should have space + * for a (short) label, the MPI (in the provided radix), the newline + * characters and the '\0'. + * + * By default we assume at least a 10 char label, a minimum radix of 10 + * (decimal) and a maximum of 4096 bit numbers (1234 decimal chars). + * Autosized at compile time for at least a 10 char label, a minimum radix + * of 10 (decimal) for a number of MBEDTLS_MPI_MAX_BITS size. + * + * This used to be statically sized to 1250 for a maximum of 4096 bit + * numbers (1234 decimal chars). + * + * Calculate using the formula: + * MBEDTLS_MPI_RW_BUFFER_SIZE = ceil(MBEDTLS_MPI_MAX_BITS / ln(10) * ln(2)) + + * LabelSize + 6 + */ +#define MBEDTLS_MPI_MAX_BITS_SCALE100 ( 100 * MBEDTLS_MPI_MAX_BITS ) +#define MBEDTLS_LN_2_DIV_LN_10_SCALE100 332 +#define MBEDTLS_MPI_RW_BUFFER_SIZE ( ((MBEDTLS_MPI_MAX_BITS_SCALE100 + MBEDTLS_LN_2_DIV_LN_10_SCALE100 - 1) / MBEDTLS_LN_2_DIV_LN_10_SCALE100) + 10 + 6 ) + +/* + * Define the base integer type, architecture-wise. + * + * 32 or 64-bit integer types can be forced regardless of the underlying + * architecture by defining MBEDTLS_HAVE_INT32 or MBEDTLS_HAVE_INT64 + * respectively and undefining MBEDTLS_HAVE_ASM. + * + * Double-width integers (e.g. 128-bit in 64-bit architectures) can be + * disabled by defining MBEDTLS_NO_UDBL_DIVISION. + */ +#if !defined(MBEDTLS_HAVE_INT32) + #if defined(_MSC_VER) && defined(_M_AMD64) + /* Always choose 64-bit when using MSC */ + #if !defined(MBEDTLS_HAVE_INT64) + #define MBEDTLS_HAVE_INT64 + #endif /* !MBEDTLS_HAVE_INT64 */ + typedef int64_t mbedtls_mpi_sint; + typedef uint64_t mbedtls_mpi_uint; + #elif defined(__GNUC__) && ( \ + defined(__amd64__) || defined(__x86_64__) || \ + defined(__ppc64__) || defined(__powerpc64__) || \ + defined(__ia64__) || defined(__alpha__) || \ + ( defined(__sparc__) && defined(__arch64__) ) || \ + defined(__s390x__) || defined(__mips64) ) + #if !defined(MBEDTLS_HAVE_INT64) + #define MBEDTLS_HAVE_INT64 + #endif /* MBEDTLS_HAVE_INT64 */ + typedef int64_t mbedtls_mpi_sint; + typedef uint64_t mbedtls_mpi_uint; + #if !defined(MBEDTLS_NO_UDBL_DIVISION) + /* mbedtls_t_udbl defined as 128-bit unsigned int */ + typedef unsigned int mbedtls_t_udbl __attribute__((mode(TI))); + #define MBEDTLS_HAVE_UDBL + #endif /* !MBEDTLS_NO_UDBL_DIVISION */ + #elif defined(__ARMCC_VERSION) && defined(__aarch64__) + /* + * __ARMCC_VERSION is defined for both armcc and armclang and + * __aarch64__ is only defined by armclang when compiling 64-bit code + */ + #if !defined(MBEDTLS_HAVE_INT64) + #define MBEDTLS_HAVE_INT64 + #endif /* !MBEDTLS_HAVE_INT64 */ + typedef int64_t mbedtls_mpi_sint; + typedef uint64_t mbedtls_mpi_uint; + #if !defined(MBEDTLS_NO_UDBL_DIVISION) + /* mbedtls_t_udbl defined as 128-bit unsigned int */ + typedef __uint128_t mbedtls_t_udbl; + #define MBEDTLS_HAVE_UDBL + #endif /* !MBEDTLS_NO_UDBL_DIVISION */ + #elif defined(MBEDTLS_HAVE_INT64) + /* Force 64-bit integers with unknown compiler */ + typedef int64_t mbedtls_mpi_sint; + typedef uint64_t mbedtls_mpi_uint; + #endif +#endif /* !MBEDTLS_HAVE_INT32 */ + +#if !defined(MBEDTLS_HAVE_INT64) + /* Default to 32-bit compilation */ + #if !defined(MBEDTLS_HAVE_INT32) + #define MBEDTLS_HAVE_INT32 + #endif /* !MBEDTLS_HAVE_INT32 */ + typedef int32_t mbedtls_mpi_sint; + typedef uint32_t mbedtls_mpi_uint; + #if !defined(MBEDTLS_NO_UDBL_DIVISION) + typedef uint64_t mbedtls_t_udbl; + #define MBEDTLS_HAVE_UDBL + #endif /* !MBEDTLS_NO_UDBL_DIVISION */ +#endif /* !MBEDTLS_HAVE_INT64 */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MPI structure + */ +typedef struct mbedtls_mpi +{ + int s; /*!< integer sign */ + size_t n; /*!< total # of limbs */ + mbedtls_mpi_uint *p; /*!< pointer to limbs */ +} +mbedtls_mpi; + +/** + * \brief Initialize one MPI (make internal references valid) + * This just makes it ready to be set or freed, + * but does not define a value for the MPI. + * + * \param X One MPI to initialize. + */ +void mbedtls_mpi_init( mbedtls_mpi *X ); + +/** + * \brief Unallocate one MPI + * + * \param X One MPI to unallocate. + */ +void mbedtls_mpi_free( mbedtls_mpi *X ); + +/** + * \brief Enlarge to the specified number of limbs + * + * This function does nothing if the MPI is already large enough. + * + * \param X MPI to grow + * \param nblimbs The target number of limbs + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_grow( mbedtls_mpi *X, size_t nblimbs ); + +/** + * \brief Resize down, keeping at least the specified number of limbs + * + * If \c X is smaller than \c nblimbs, it is resized up + * instead. + * + * \param X MPI to shrink + * \param nblimbs The minimum number of limbs to keep + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + * (this can only happen when resizing up). + */ +int mbedtls_mpi_shrink( mbedtls_mpi *X, size_t nblimbs ); + +/** + * \brief Copy the contents of Y into X + * + * \param X Destination MPI. It is enlarged if necessary. + * \param Y Source MPI. + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_copy( mbedtls_mpi *X, const mbedtls_mpi *Y ); + +/** + * \brief Swap the contents of X and Y + * + * \param X First MPI value + * \param Y Second MPI value + */ +void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y ); + +/** + * \brief Safe conditional assignement X = Y if assign is 1 + * + * \param X MPI to conditionally assign to + * \param Y Value to be assigned + * \param assign 1: perform the assignment, 0: keep X's original value + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * + * \note This function is equivalent to + * if( assign ) mbedtls_mpi_copy( X, Y ); + * except that it avoids leaking any information about whether + * the assignment was done or not (the above code may leak + * information through branch prediction and/or memory access + * patterns analysis). + */ +int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned char assign ); + +/** + * \brief Safe conditional swap X <-> Y if swap is 1 + * + * \param X First mbedtls_mpi value + * \param Y Second mbedtls_mpi value + * \param assign 1: perform the swap, 0: keep X and Y's original values + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * + * \note This function is equivalent to + * if( assign ) mbedtls_mpi_swap( X, Y ); + * except that it avoids leaking any information about whether + * the assignment was done or not (the above code may leak + * information through branch prediction and/or memory access + * patterns analysis). + */ +int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, mbedtls_mpi *Y, unsigned char assign ); + +/** + * \brief Set value from integer + * + * \param X MPI to set + * \param z Value to use + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_lset( mbedtls_mpi *X, mbedtls_mpi_sint z ); + +/** + * \brief Get a specific bit from X + * + * \param X MPI to use + * \param pos Zero-based index of the bit in X + * + * \return Either a 0 or a 1 + */ +int mbedtls_mpi_get_bit( const mbedtls_mpi *X, size_t pos ); + +/** + * \brief Set a bit of X to a specific value of 0 or 1 + * + * \note Will grow X if necessary to set a bit to 1 in a not yet + * existing limb. Will not grow if bit should be set to 0 + * + * \param X MPI to use + * \param pos Zero-based index of the bit in X + * \param val The value to set the bit to (0 or 1) + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_BAD_INPUT_DATA if val is not 0 or 1 + */ +int mbedtls_mpi_set_bit( mbedtls_mpi *X, size_t pos, unsigned char val ); + +/** + * \brief Return the number of zero-bits before the least significant + * '1' bit + * + * Note: Thus also the zero-based index of the least significant '1' bit + * + * \param X MPI to use + */ +size_t mbedtls_mpi_lsb( const mbedtls_mpi *X ); + +/** + * \brief Return the number of bits up to and including the most + * significant '1' bit' + * + * Note: Thus also the one-based index of the most significant '1' bit + * + * \param X MPI to use + */ +size_t mbedtls_mpi_bitlen( const mbedtls_mpi *X ); + +/** + * \brief Return the total size in bytes + * + * \param X MPI to use + */ +size_t mbedtls_mpi_size( const mbedtls_mpi *X ); + +/** + * \brief Import from an ASCII string + * + * \param X Destination MPI + * \param radix Input numeric base + * \param s Null-terminated string buffer + * + * \return 0 if successful, or a MBEDTLS_ERR_MPI_XXX error code + */ +int mbedtls_mpi_read_string( mbedtls_mpi *X, int radix, const char *s ); + +/** + * \brief Export into an ASCII string + * + * \param X Source MPI + * \param radix Output numeric base + * \param buf Buffer to write the string to + * \param buflen Length of buf + * \param olen Length of the string written, including final NUL byte + * + * \return 0 if successful, or a MBEDTLS_ERR_MPI_XXX error code. + * *olen is always updated to reflect the amount + * of data that has (or would have) been written. + * + * \note Call this function with buflen = 0 to obtain the + * minimum required buffer size in *olen. + */ +int mbedtls_mpi_write_string( const mbedtls_mpi *X, int radix, + char *buf, size_t buflen, size_t *olen ); + +#if defined(MBEDTLS_FS_IO) +/** + * \brief Read MPI from a line in an opened file + * + * \param X Destination MPI + * \param radix Input numeric base + * \param fin Input file handle + * + * \return 0 if successful, MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if + * the file read buffer is too small or a + * MBEDTLS_ERR_MPI_XXX error code + * + * \note On success, this function advances the file stream + * to the end of the current line or to EOF. + * + * The function returns 0 on an empty line. + * + * Leading whitespaces are ignored, as is a + * '0x' prefix for radix 16. + * + */ +int mbedtls_mpi_read_file( mbedtls_mpi *X, int radix, FILE *fin ); + +/** + * \brief Write X into an opened file, or stdout if fout is NULL + * + * \param p Prefix, can be NULL + * \param X Source MPI + * \param radix Output numeric base + * \param fout Output file handle (can be NULL) + * + * \return 0 if successful, or a MBEDTLS_ERR_MPI_XXX error code + * + * \note Set fout == NULL to print X on the console. + */ +int mbedtls_mpi_write_file( const char *p, const mbedtls_mpi *X, int radix, FILE *fout ); +#endif /* MBEDTLS_FS_IO */ + +/** + * \brief Import X from unsigned binary data, big endian + * + * \param X Destination MPI + * \param buf Input buffer + * \param buflen Input buffer size + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_read_binary( mbedtls_mpi *X, const unsigned char *buf, size_t buflen ); + +/** + * \brief Export X into unsigned binary data, big endian. + * Always fills the whole buffer, which will start with zeros + * if the number is smaller. + * + * \param X Source MPI + * \param buf Output buffer + * \param buflen Output buffer size + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if buf isn't large enough + */ +int mbedtls_mpi_write_binary( const mbedtls_mpi *X, unsigned char *buf, size_t buflen ); + +/** + * \brief Left-shift: X <<= count + * + * \param X MPI to shift + * \param count Amount to shift + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_shift_l( mbedtls_mpi *X, size_t count ); + +/** + * \brief Right-shift: X >>= count + * + * \param X MPI to shift + * \param count Amount to shift + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_shift_r( mbedtls_mpi *X, size_t count ); + +/** + * \brief Compare unsigned values + * + * \param X Left-hand MPI + * \param Y Right-hand MPI + * + * \return 1 if |X| is greater than |Y|, + * -1 if |X| is lesser than |Y| or + * 0 if |X| is equal to |Y| + */ +int mbedtls_mpi_cmp_abs( const mbedtls_mpi *X, const mbedtls_mpi *Y ); + +/** + * \brief Compare signed values + * + * \param X Left-hand MPI + * \param Y Right-hand MPI + * + * \return 1 if X is greater than Y, + * -1 if X is lesser than Y or + * 0 if X is equal to Y + */ +int mbedtls_mpi_cmp_mpi( const mbedtls_mpi *X, const mbedtls_mpi *Y ); + +/** + * \brief Compare signed values + * + * \param X Left-hand MPI + * \param z The integer value to compare to + * + * \return 1 if X is greater than z, + * -1 if X is lesser than z or + * 0 if X is equal to z + */ +int mbedtls_mpi_cmp_int( const mbedtls_mpi *X, mbedtls_mpi_sint z ); + +/** + * \brief Unsigned addition: X = |A| + |B| + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_add_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Unsigned subtraction: X = |A| - |B| + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_NEGATIVE_VALUE if B is greater than A + */ +int mbedtls_mpi_sub_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Signed addition: X = A + B + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_add_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Signed subtraction: X = A - B + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_sub_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Signed addition: X = A + b + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param b The integer value to add + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_add_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b ); + +/** + * \brief Signed subtraction: X = A - b + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param b The integer value to subtract + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_sub_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b ); + +/** + * \brief Baseline multiplication: X = A * B + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_mul_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Baseline multiplication: X = A * b + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param b The unsigned integer value to multiply with + * + * \note b is unsigned + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_mul_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint b ); + +/** + * \brief Division by mbedtls_mpi: A = Q * B + R + * + * \param Q Destination MPI for the quotient + * \param R Destination MPI for the rest value + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if B == 0 + * + * \note Either Q or R can be NULL. + */ +int mbedtls_mpi_div_mpi( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Division by int: A = Q * b + R + * + * \param Q Destination MPI for the quotient + * \param R Destination MPI for the rest value + * \param A Left-hand MPI + * \param b Integer to divide by + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if b == 0 + * + * \note Either Q or R can be NULL. + */ +int mbedtls_mpi_div_int( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, mbedtls_mpi_sint b ); + +/** + * \brief Modulo: R = A mod B + * + * \param R Destination MPI for the rest value + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if B == 0, + * MBEDTLS_ERR_MPI_NEGATIVE_VALUE if B < 0 + */ +int mbedtls_mpi_mod_mpi( mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Modulo: r = A mod b + * + * \param r Destination mbedtls_mpi_uint + * \param A Left-hand MPI + * \param b Integer to divide by + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if b == 0, + * MBEDTLS_ERR_MPI_NEGATIVE_VALUE if b < 0 + */ +int mbedtls_mpi_mod_int( mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_sint b ); + +/** + * \brief Sliding-window exponentiation: X = A^E mod N + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param E Exponent MPI + * \param N Modular MPI + * \param _RR Speed-up MPI used for recalculations + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_BAD_INPUT_DATA if N is negative or even or + * if E is negative + * + * \note _RR is used to avoid re-computing R*R mod N across + * multiple calls, which speeds up things a bit. It can + * be set to NULL if the extra performance is unneeded. + */ +int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *E, const mbedtls_mpi *N, mbedtls_mpi *_RR ); + +/** + * \brief Fill an MPI X with size bytes of random + * + * \param X Destination MPI + * \param size Size in bytes + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + * + * \note The bytes obtained from the PRNG are interpreted + * as a big-endian representation of an MPI; this can + * be relevant in applications like deterministic ECDSA. + */ +int mbedtls_mpi_fill_random( mbedtls_mpi *X, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Greatest common divisor: G = gcd(A, B) + * + * \param G Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_gcd( mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Modular inverse: X = A^-1 mod N + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param N Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_BAD_INPUT_DATA if N is <= 1, + MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if A has no inverse mod N. + */ +int mbedtls_mpi_inv_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N ); + +/** + * \brief Miller-Rabin primality test + * + * \param X MPI to check + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful (probably prime), + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if X is not prime + */ +int mbedtls_mpi_is_prime( const mbedtls_mpi *X, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Prime number generation + * + * \param X Destination MPI + * \param nbits Required size of X in bits + * ( 3 <= nbits <= MBEDTLS_MPI_MAX_BITS ) + * \param dh_flag If 1, then (X-1)/2 will be prime too + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful (probably prime), + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_BAD_INPUT_DATA if nbits is < 3 + */ +int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int dh_flag, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_mpi_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* bignum.h */ diff --git a/common/mbedtls/blowfish.c b/common/mbedtls/blowfish.c new file mode 100644 index 00000000..404d24e1 --- /dev/null +++ b/common/mbedtls/blowfish.c @@ -0,0 +1,654 @@ +/* + * Blowfish implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The Blowfish block cipher was designed by Bruce Schneier in 1993. + * http://www.schneier.com/blowfish.html + * http://en.wikipedia.org/wiki/Blowfish_%28cipher%29 + * + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_BLOWFISH_C) + +#include "mbedtls/blowfish.h" +#include "mbedtls/platform_util.h" + +#include + +#if !defined(MBEDTLS_BLOWFISH_ALT) + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +static const uint32_t P[MBEDTLS_BLOWFISH_ROUNDS + 2] = { + 0x243F6A88L, 0x85A308D3L, 0x13198A2EL, 0x03707344L, + 0xA4093822L, 0x299F31D0L, 0x082EFA98L, 0xEC4E6C89L, + 0x452821E6L, 0x38D01377L, 0xBE5466CFL, 0x34E90C6CL, + 0xC0AC29B7L, 0xC97C50DDL, 0x3F84D5B5L, 0xB5470917L, + 0x9216D5D9L, 0x8979FB1BL +}; + +/* declarations of data at the end of this file */ +static const uint32_t S[4][256]; + +static uint32_t F( mbedtls_blowfish_context *ctx, uint32_t x ) +{ + unsigned short a, b, c, d; + uint32_t y; + + d = (unsigned short)(x & 0xFF); + x >>= 8; + c = (unsigned short)(x & 0xFF); + x >>= 8; + b = (unsigned short)(x & 0xFF); + x >>= 8; + a = (unsigned short)(x & 0xFF); + y = ctx->S[0][a] + ctx->S[1][b]; + y = y ^ ctx->S[2][c]; + y = y + ctx->S[3][d]; + + return( y ); +} + +static void blowfish_enc( mbedtls_blowfish_context *ctx, uint32_t *xl, uint32_t *xr ) +{ + uint32_t Xl, Xr, temp; + short i; + + Xl = *xl; + Xr = *xr; + + for( i = 0; i < MBEDTLS_BLOWFISH_ROUNDS; ++i ) + { + Xl = Xl ^ ctx->P[i]; + Xr = F( ctx, Xl ) ^ Xr; + + temp = Xl; + Xl = Xr; + Xr = temp; + } + + temp = Xl; + Xl = Xr; + Xr = temp; + + Xr = Xr ^ ctx->P[MBEDTLS_BLOWFISH_ROUNDS]; + Xl = Xl ^ ctx->P[MBEDTLS_BLOWFISH_ROUNDS + 1]; + + *xl = Xl; + *xr = Xr; +} + +static void blowfish_dec( mbedtls_blowfish_context *ctx, uint32_t *xl, uint32_t *xr ) +{ + uint32_t Xl, Xr, temp; + short i; + + Xl = *xl; + Xr = *xr; + + for( i = MBEDTLS_BLOWFISH_ROUNDS + 1; i > 1; --i ) + { + Xl = Xl ^ ctx->P[i]; + Xr = F( ctx, Xl ) ^ Xr; + + temp = Xl; + Xl = Xr; + Xr = temp; + } + + temp = Xl; + Xl = Xr; + Xr = temp; + + Xr = Xr ^ ctx->P[1]; + Xl = Xl ^ ctx->P[0]; + + *xl = Xl; + *xr = Xr; +} + +void mbedtls_blowfish_init( mbedtls_blowfish_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_blowfish_context ) ); +} + +void mbedtls_blowfish_free( mbedtls_blowfish_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_blowfish_context ) ); +} + +/* + * Blowfish key schedule + */ +int mbedtls_blowfish_setkey( mbedtls_blowfish_context *ctx, const unsigned char *key, + unsigned int keybits ) +{ + unsigned int i, j, k; + uint32_t data, datal, datar; + + if( keybits < MBEDTLS_BLOWFISH_MIN_KEY_BITS || keybits > MBEDTLS_BLOWFISH_MAX_KEY_BITS || + ( keybits % 8 ) ) + { + return( MBEDTLS_ERR_BLOWFISH_INVALID_KEY_LENGTH ); + } + + keybits >>= 3; + + for( i = 0; i < 4; i++ ) + { + for( j = 0; j < 256; j++ ) + ctx->S[i][j] = S[i][j]; + } + + j = 0; + for( i = 0; i < MBEDTLS_BLOWFISH_ROUNDS + 2; ++i ) + { + data = 0x00000000; + for( k = 0; k < 4; ++k ) + { + data = ( data << 8 ) | key[j++]; + if( j >= keybits ) + j = 0; + } + ctx->P[i] = P[i] ^ data; + } + + datal = 0x00000000; + datar = 0x00000000; + + for( i = 0; i < MBEDTLS_BLOWFISH_ROUNDS + 2; i += 2 ) + { + blowfish_enc( ctx, &datal, &datar ); + ctx->P[i] = datal; + ctx->P[i + 1] = datar; + } + + for( i = 0; i < 4; i++ ) + { + for( j = 0; j < 256; j += 2 ) + { + blowfish_enc( ctx, &datal, &datar ); + ctx->S[i][j] = datal; + ctx->S[i][j + 1] = datar; + } + } + return( 0 ); +} + +/* + * Blowfish-ECB block encryption/decryption + */ +int mbedtls_blowfish_crypt_ecb( mbedtls_blowfish_context *ctx, + int mode, + const unsigned char input[MBEDTLS_BLOWFISH_BLOCKSIZE], + unsigned char output[MBEDTLS_BLOWFISH_BLOCKSIZE] ) +{ + uint32_t X0, X1; + + GET_UINT32_BE( X0, input, 0 ); + GET_UINT32_BE( X1, input, 4 ); + + if( mode == MBEDTLS_BLOWFISH_DECRYPT ) + { + blowfish_dec( ctx, &X0, &X1 ); + } + else /* MBEDTLS_BLOWFISH_ENCRYPT */ + { + blowfish_enc( ctx, &X0, &X1 ); + } + + PUT_UINT32_BE( X0, output, 0 ); + PUT_UINT32_BE( X1, output, 4 ); + + return( 0 ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/* + * Blowfish-CBC buffer encryption/decryption + */ +int mbedtls_blowfish_crypt_cbc( mbedtls_blowfish_context *ctx, + int mode, + size_t length, + unsigned char iv[MBEDTLS_BLOWFISH_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[MBEDTLS_BLOWFISH_BLOCKSIZE]; + + if( length % MBEDTLS_BLOWFISH_BLOCKSIZE ) + return( MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH ); + + if( mode == MBEDTLS_BLOWFISH_DECRYPT ) + { + while( length > 0 ) + { + memcpy( temp, input, MBEDTLS_BLOWFISH_BLOCKSIZE ); + mbedtls_blowfish_crypt_ecb( ctx, mode, input, output ); + + for( i = 0; i < MBEDTLS_BLOWFISH_BLOCKSIZE;i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, MBEDTLS_BLOWFISH_BLOCKSIZE ); + + input += MBEDTLS_BLOWFISH_BLOCKSIZE; + output += MBEDTLS_BLOWFISH_BLOCKSIZE; + length -= MBEDTLS_BLOWFISH_BLOCKSIZE; + } + } + else + { + while( length > 0 ) + { + for( i = 0; i < MBEDTLS_BLOWFISH_BLOCKSIZE; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + mbedtls_blowfish_crypt_ecb( ctx, mode, output, output ); + memcpy( iv, output, MBEDTLS_BLOWFISH_BLOCKSIZE ); + + input += MBEDTLS_BLOWFISH_BLOCKSIZE; + output += MBEDTLS_BLOWFISH_BLOCKSIZE; + length -= MBEDTLS_BLOWFISH_BLOCKSIZE; + } + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/* + * Blowfish CFB buffer encryption/decryption + */ +int mbedtls_blowfish_crypt_cfb64( mbedtls_blowfish_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[MBEDTLS_BLOWFISH_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ) +{ + int c; + size_t n = *iv_off; + + if( mode == MBEDTLS_BLOWFISH_DECRYPT ) + { + while( length-- ) + { + if( n == 0 ) + mbedtls_blowfish_crypt_ecb( ctx, MBEDTLS_BLOWFISH_ENCRYPT, iv, iv ); + + c = *input++; + *output++ = (unsigned char)( c ^ iv[n] ); + iv[n] = (unsigned char) c; + + n = ( n + 1 ) % MBEDTLS_BLOWFISH_BLOCKSIZE; + } + } + else + { + while( length-- ) + { + if( n == 0 ) + mbedtls_blowfish_crypt_ecb( ctx, MBEDTLS_BLOWFISH_ENCRYPT, iv, iv ); + + iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ ); + + n = ( n + 1 ) % MBEDTLS_BLOWFISH_BLOCKSIZE; + } + } + + *iv_off = n; + + return( 0 ); +} +#endif /*MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/* + * Blowfish CTR buffer encryption/decryption + */ +int mbedtls_blowfish_crypt_ctr( mbedtls_blowfish_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[MBEDTLS_BLOWFISH_BLOCKSIZE], + unsigned char stream_block[MBEDTLS_BLOWFISH_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ) +{ + int c, i; + size_t n = *nc_off; + + while( length-- ) + { + if( n == 0 ) { + mbedtls_blowfish_crypt_ecb( ctx, MBEDTLS_BLOWFISH_ENCRYPT, nonce_counter, + stream_block ); + + for( i = MBEDTLS_BLOWFISH_BLOCKSIZE; i > 0; i-- ) + if( ++nonce_counter[i - 1] != 0 ) + break; + } + c = *input++; + *output++ = (unsigned char)( c ^ stream_block[n] ); + + n = ( n + 1 ) % MBEDTLS_BLOWFISH_BLOCKSIZE; + } + + *nc_off = n; + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +static const uint32_t S[4][256] = { + { 0xD1310BA6L, 0x98DFB5ACL, 0x2FFD72DBL, 0xD01ADFB7L, + 0xB8E1AFEDL, 0x6A267E96L, 0xBA7C9045L, 0xF12C7F99L, + 0x24A19947L, 0xB3916CF7L, 0x0801F2E2L, 0x858EFC16L, + 0x636920D8L, 0x71574E69L, 0xA458FEA3L, 0xF4933D7EL, + 0x0D95748FL, 0x728EB658L, 0x718BCD58L, 0x82154AEEL, + 0x7B54A41DL, 0xC25A59B5L, 0x9C30D539L, 0x2AF26013L, + 0xC5D1B023L, 0x286085F0L, 0xCA417918L, 0xB8DB38EFL, + 0x8E79DCB0L, 0x603A180EL, 0x6C9E0E8BL, 0xB01E8A3EL, + 0xD71577C1L, 0xBD314B27L, 0x78AF2FDAL, 0x55605C60L, + 0xE65525F3L, 0xAA55AB94L, 0x57489862L, 0x63E81440L, + 0x55CA396AL, 0x2AAB10B6L, 0xB4CC5C34L, 0x1141E8CEL, + 0xA15486AFL, 0x7C72E993L, 0xB3EE1411L, 0x636FBC2AL, + 0x2BA9C55DL, 0x741831F6L, 0xCE5C3E16L, 0x9B87931EL, + 0xAFD6BA33L, 0x6C24CF5CL, 0x7A325381L, 0x28958677L, + 0x3B8F4898L, 0x6B4BB9AFL, 0xC4BFE81BL, 0x66282193L, + 0x61D809CCL, 0xFB21A991L, 0x487CAC60L, 0x5DEC8032L, + 0xEF845D5DL, 0xE98575B1L, 0xDC262302L, 0xEB651B88L, + 0x23893E81L, 0xD396ACC5L, 0x0F6D6FF3L, 0x83F44239L, + 0x2E0B4482L, 0xA4842004L, 0x69C8F04AL, 0x9E1F9B5EL, + 0x21C66842L, 0xF6E96C9AL, 0x670C9C61L, 0xABD388F0L, + 0x6A51A0D2L, 0xD8542F68L, 0x960FA728L, 0xAB5133A3L, + 0x6EEF0B6CL, 0x137A3BE4L, 0xBA3BF050L, 0x7EFB2A98L, + 0xA1F1651DL, 0x39AF0176L, 0x66CA593EL, 0x82430E88L, + 0x8CEE8619L, 0x456F9FB4L, 0x7D84A5C3L, 0x3B8B5EBEL, + 0xE06F75D8L, 0x85C12073L, 0x401A449FL, 0x56C16AA6L, + 0x4ED3AA62L, 0x363F7706L, 0x1BFEDF72L, 0x429B023DL, + 0x37D0D724L, 0xD00A1248L, 0xDB0FEAD3L, 0x49F1C09BL, + 0x075372C9L, 0x80991B7BL, 0x25D479D8L, 0xF6E8DEF7L, + 0xE3FE501AL, 0xB6794C3BL, 0x976CE0BDL, 0x04C006BAL, + 0xC1A94FB6L, 0x409F60C4L, 0x5E5C9EC2L, 0x196A2463L, + 0x68FB6FAFL, 0x3E6C53B5L, 0x1339B2EBL, 0x3B52EC6FL, + 0x6DFC511FL, 0x9B30952CL, 0xCC814544L, 0xAF5EBD09L, + 0xBEE3D004L, 0xDE334AFDL, 0x660F2807L, 0x192E4BB3L, + 0xC0CBA857L, 0x45C8740FL, 0xD20B5F39L, 0xB9D3FBDBL, + 0x5579C0BDL, 0x1A60320AL, 0xD6A100C6L, 0x402C7279L, + 0x679F25FEL, 0xFB1FA3CCL, 0x8EA5E9F8L, 0xDB3222F8L, + 0x3C7516DFL, 0xFD616B15L, 0x2F501EC8L, 0xAD0552ABL, + 0x323DB5FAL, 0xFD238760L, 0x53317B48L, 0x3E00DF82L, + 0x9E5C57BBL, 0xCA6F8CA0L, 0x1A87562EL, 0xDF1769DBL, + 0xD542A8F6L, 0x287EFFC3L, 0xAC6732C6L, 0x8C4F5573L, + 0x695B27B0L, 0xBBCA58C8L, 0xE1FFA35DL, 0xB8F011A0L, + 0x10FA3D98L, 0xFD2183B8L, 0x4AFCB56CL, 0x2DD1D35BL, + 0x9A53E479L, 0xB6F84565L, 0xD28E49BCL, 0x4BFB9790L, + 0xE1DDF2DAL, 0xA4CB7E33L, 0x62FB1341L, 0xCEE4C6E8L, + 0xEF20CADAL, 0x36774C01L, 0xD07E9EFEL, 0x2BF11FB4L, + 0x95DBDA4DL, 0xAE909198L, 0xEAAD8E71L, 0x6B93D5A0L, + 0xD08ED1D0L, 0xAFC725E0L, 0x8E3C5B2FL, 0x8E7594B7L, + 0x8FF6E2FBL, 0xF2122B64L, 0x8888B812L, 0x900DF01CL, + 0x4FAD5EA0L, 0x688FC31CL, 0xD1CFF191L, 0xB3A8C1ADL, + 0x2F2F2218L, 0xBE0E1777L, 0xEA752DFEL, 0x8B021FA1L, + 0xE5A0CC0FL, 0xB56F74E8L, 0x18ACF3D6L, 0xCE89E299L, + 0xB4A84FE0L, 0xFD13E0B7L, 0x7CC43B81L, 0xD2ADA8D9L, + 0x165FA266L, 0x80957705L, 0x93CC7314L, 0x211A1477L, + 0xE6AD2065L, 0x77B5FA86L, 0xC75442F5L, 0xFB9D35CFL, + 0xEBCDAF0CL, 0x7B3E89A0L, 0xD6411BD3L, 0xAE1E7E49L, + 0x00250E2DL, 0x2071B35EL, 0x226800BBL, 0x57B8E0AFL, + 0x2464369BL, 0xF009B91EL, 0x5563911DL, 0x59DFA6AAL, + 0x78C14389L, 0xD95A537FL, 0x207D5BA2L, 0x02E5B9C5L, + 0x83260376L, 0x6295CFA9L, 0x11C81968L, 0x4E734A41L, + 0xB3472DCAL, 0x7B14A94AL, 0x1B510052L, 0x9A532915L, + 0xD60F573FL, 0xBC9BC6E4L, 0x2B60A476L, 0x81E67400L, + 0x08BA6FB5L, 0x571BE91FL, 0xF296EC6BL, 0x2A0DD915L, + 0xB6636521L, 0xE7B9F9B6L, 0xFF34052EL, 0xC5855664L, + 0x53B02D5DL, 0xA99F8FA1L, 0x08BA4799L, 0x6E85076AL }, + { 0x4B7A70E9L, 0xB5B32944L, 0xDB75092EL, 0xC4192623L, + 0xAD6EA6B0L, 0x49A7DF7DL, 0x9CEE60B8L, 0x8FEDB266L, + 0xECAA8C71L, 0x699A17FFL, 0x5664526CL, 0xC2B19EE1L, + 0x193602A5L, 0x75094C29L, 0xA0591340L, 0xE4183A3EL, + 0x3F54989AL, 0x5B429D65L, 0x6B8FE4D6L, 0x99F73FD6L, + 0xA1D29C07L, 0xEFE830F5L, 0x4D2D38E6L, 0xF0255DC1L, + 0x4CDD2086L, 0x8470EB26L, 0x6382E9C6L, 0x021ECC5EL, + 0x09686B3FL, 0x3EBAEFC9L, 0x3C971814L, 0x6B6A70A1L, + 0x687F3584L, 0x52A0E286L, 0xB79C5305L, 0xAA500737L, + 0x3E07841CL, 0x7FDEAE5CL, 0x8E7D44ECL, 0x5716F2B8L, + 0xB03ADA37L, 0xF0500C0DL, 0xF01C1F04L, 0x0200B3FFL, + 0xAE0CF51AL, 0x3CB574B2L, 0x25837A58L, 0xDC0921BDL, + 0xD19113F9L, 0x7CA92FF6L, 0x94324773L, 0x22F54701L, + 0x3AE5E581L, 0x37C2DADCL, 0xC8B57634L, 0x9AF3DDA7L, + 0xA9446146L, 0x0FD0030EL, 0xECC8C73EL, 0xA4751E41L, + 0xE238CD99L, 0x3BEA0E2FL, 0x3280BBA1L, 0x183EB331L, + 0x4E548B38L, 0x4F6DB908L, 0x6F420D03L, 0xF60A04BFL, + 0x2CB81290L, 0x24977C79L, 0x5679B072L, 0xBCAF89AFL, + 0xDE9A771FL, 0xD9930810L, 0xB38BAE12L, 0xDCCF3F2EL, + 0x5512721FL, 0x2E6B7124L, 0x501ADDE6L, 0x9F84CD87L, + 0x7A584718L, 0x7408DA17L, 0xBC9F9ABCL, 0xE94B7D8CL, + 0xEC7AEC3AL, 0xDB851DFAL, 0x63094366L, 0xC464C3D2L, + 0xEF1C1847L, 0x3215D908L, 0xDD433B37L, 0x24C2BA16L, + 0x12A14D43L, 0x2A65C451L, 0x50940002L, 0x133AE4DDL, + 0x71DFF89EL, 0x10314E55L, 0x81AC77D6L, 0x5F11199BL, + 0x043556F1L, 0xD7A3C76BL, 0x3C11183BL, 0x5924A509L, + 0xF28FE6EDL, 0x97F1FBFAL, 0x9EBABF2CL, 0x1E153C6EL, + 0x86E34570L, 0xEAE96FB1L, 0x860E5E0AL, 0x5A3E2AB3L, + 0x771FE71CL, 0x4E3D06FAL, 0x2965DCB9L, 0x99E71D0FL, + 0x803E89D6L, 0x5266C825L, 0x2E4CC978L, 0x9C10B36AL, + 0xC6150EBAL, 0x94E2EA78L, 0xA5FC3C53L, 0x1E0A2DF4L, + 0xF2F74EA7L, 0x361D2B3DL, 0x1939260FL, 0x19C27960L, + 0x5223A708L, 0xF71312B6L, 0xEBADFE6EL, 0xEAC31F66L, + 0xE3BC4595L, 0xA67BC883L, 0xB17F37D1L, 0x018CFF28L, + 0xC332DDEFL, 0xBE6C5AA5L, 0x65582185L, 0x68AB9802L, + 0xEECEA50FL, 0xDB2F953BL, 0x2AEF7DADL, 0x5B6E2F84L, + 0x1521B628L, 0x29076170L, 0xECDD4775L, 0x619F1510L, + 0x13CCA830L, 0xEB61BD96L, 0x0334FE1EL, 0xAA0363CFL, + 0xB5735C90L, 0x4C70A239L, 0xD59E9E0BL, 0xCBAADE14L, + 0xEECC86BCL, 0x60622CA7L, 0x9CAB5CABL, 0xB2F3846EL, + 0x648B1EAFL, 0x19BDF0CAL, 0xA02369B9L, 0x655ABB50L, + 0x40685A32L, 0x3C2AB4B3L, 0x319EE9D5L, 0xC021B8F7L, + 0x9B540B19L, 0x875FA099L, 0x95F7997EL, 0x623D7DA8L, + 0xF837889AL, 0x97E32D77L, 0x11ED935FL, 0x16681281L, + 0x0E358829L, 0xC7E61FD6L, 0x96DEDFA1L, 0x7858BA99L, + 0x57F584A5L, 0x1B227263L, 0x9B83C3FFL, 0x1AC24696L, + 0xCDB30AEBL, 0x532E3054L, 0x8FD948E4L, 0x6DBC3128L, + 0x58EBF2EFL, 0x34C6FFEAL, 0xFE28ED61L, 0xEE7C3C73L, + 0x5D4A14D9L, 0xE864B7E3L, 0x42105D14L, 0x203E13E0L, + 0x45EEE2B6L, 0xA3AAABEAL, 0xDB6C4F15L, 0xFACB4FD0L, + 0xC742F442L, 0xEF6ABBB5L, 0x654F3B1DL, 0x41CD2105L, + 0xD81E799EL, 0x86854DC7L, 0xE44B476AL, 0x3D816250L, + 0xCF62A1F2L, 0x5B8D2646L, 0xFC8883A0L, 0xC1C7B6A3L, + 0x7F1524C3L, 0x69CB7492L, 0x47848A0BL, 0x5692B285L, + 0x095BBF00L, 0xAD19489DL, 0x1462B174L, 0x23820E00L, + 0x58428D2AL, 0x0C55F5EAL, 0x1DADF43EL, 0x233F7061L, + 0x3372F092L, 0x8D937E41L, 0xD65FECF1L, 0x6C223BDBL, + 0x7CDE3759L, 0xCBEE7460L, 0x4085F2A7L, 0xCE77326EL, + 0xA6078084L, 0x19F8509EL, 0xE8EFD855L, 0x61D99735L, + 0xA969A7AAL, 0xC50C06C2L, 0x5A04ABFCL, 0x800BCADCL, + 0x9E447A2EL, 0xC3453484L, 0xFDD56705L, 0x0E1E9EC9L, + 0xDB73DBD3L, 0x105588CDL, 0x675FDA79L, 0xE3674340L, + 0xC5C43465L, 0x713E38D8L, 0x3D28F89EL, 0xF16DFF20L, + 0x153E21E7L, 0x8FB03D4AL, 0xE6E39F2BL, 0xDB83ADF7L }, + { 0xE93D5A68L, 0x948140F7L, 0xF64C261CL, 0x94692934L, + 0x411520F7L, 0x7602D4F7L, 0xBCF46B2EL, 0xD4A20068L, + 0xD4082471L, 0x3320F46AL, 0x43B7D4B7L, 0x500061AFL, + 0x1E39F62EL, 0x97244546L, 0x14214F74L, 0xBF8B8840L, + 0x4D95FC1DL, 0x96B591AFL, 0x70F4DDD3L, 0x66A02F45L, + 0xBFBC09ECL, 0x03BD9785L, 0x7FAC6DD0L, 0x31CB8504L, + 0x96EB27B3L, 0x55FD3941L, 0xDA2547E6L, 0xABCA0A9AL, + 0x28507825L, 0x530429F4L, 0x0A2C86DAL, 0xE9B66DFBL, + 0x68DC1462L, 0xD7486900L, 0x680EC0A4L, 0x27A18DEEL, + 0x4F3FFEA2L, 0xE887AD8CL, 0xB58CE006L, 0x7AF4D6B6L, + 0xAACE1E7CL, 0xD3375FECL, 0xCE78A399L, 0x406B2A42L, + 0x20FE9E35L, 0xD9F385B9L, 0xEE39D7ABL, 0x3B124E8BL, + 0x1DC9FAF7L, 0x4B6D1856L, 0x26A36631L, 0xEAE397B2L, + 0x3A6EFA74L, 0xDD5B4332L, 0x6841E7F7L, 0xCA7820FBL, + 0xFB0AF54EL, 0xD8FEB397L, 0x454056ACL, 0xBA489527L, + 0x55533A3AL, 0x20838D87L, 0xFE6BA9B7L, 0xD096954BL, + 0x55A867BCL, 0xA1159A58L, 0xCCA92963L, 0x99E1DB33L, + 0xA62A4A56L, 0x3F3125F9L, 0x5EF47E1CL, 0x9029317CL, + 0xFDF8E802L, 0x04272F70L, 0x80BB155CL, 0x05282CE3L, + 0x95C11548L, 0xE4C66D22L, 0x48C1133FL, 0xC70F86DCL, + 0x07F9C9EEL, 0x41041F0FL, 0x404779A4L, 0x5D886E17L, + 0x325F51EBL, 0xD59BC0D1L, 0xF2BCC18FL, 0x41113564L, + 0x257B7834L, 0x602A9C60L, 0xDFF8E8A3L, 0x1F636C1BL, + 0x0E12B4C2L, 0x02E1329EL, 0xAF664FD1L, 0xCAD18115L, + 0x6B2395E0L, 0x333E92E1L, 0x3B240B62L, 0xEEBEB922L, + 0x85B2A20EL, 0xE6BA0D99L, 0xDE720C8CL, 0x2DA2F728L, + 0xD0127845L, 0x95B794FDL, 0x647D0862L, 0xE7CCF5F0L, + 0x5449A36FL, 0x877D48FAL, 0xC39DFD27L, 0xF33E8D1EL, + 0x0A476341L, 0x992EFF74L, 0x3A6F6EABL, 0xF4F8FD37L, + 0xA812DC60L, 0xA1EBDDF8L, 0x991BE14CL, 0xDB6E6B0DL, + 0xC67B5510L, 0x6D672C37L, 0x2765D43BL, 0xDCD0E804L, + 0xF1290DC7L, 0xCC00FFA3L, 0xB5390F92L, 0x690FED0BL, + 0x667B9FFBL, 0xCEDB7D9CL, 0xA091CF0BL, 0xD9155EA3L, + 0xBB132F88L, 0x515BAD24L, 0x7B9479BFL, 0x763BD6EBL, + 0x37392EB3L, 0xCC115979L, 0x8026E297L, 0xF42E312DL, + 0x6842ADA7L, 0xC66A2B3BL, 0x12754CCCL, 0x782EF11CL, + 0x6A124237L, 0xB79251E7L, 0x06A1BBE6L, 0x4BFB6350L, + 0x1A6B1018L, 0x11CAEDFAL, 0x3D25BDD8L, 0xE2E1C3C9L, + 0x44421659L, 0x0A121386L, 0xD90CEC6EL, 0xD5ABEA2AL, + 0x64AF674EL, 0xDA86A85FL, 0xBEBFE988L, 0x64E4C3FEL, + 0x9DBC8057L, 0xF0F7C086L, 0x60787BF8L, 0x6003604DL, + 0xD1FD8346L, 0xF6381FB0L, 0x7745AE04L, 0xD736FCCCL, + 0x83426B33L, 0xF01EAB71L, 0xB0804187L, 0x3C005E5FL, + 0x77A057BEL, 0xBDE8AE24L, 0x55464299L, 0xBF582E61L, + 0x4E58F48FL, 0xF2DDFDA2L, 0xF474EF38L, 0x8789BDC2L, + 0x5366F9C3L, 0xC8B38E74L, 0xB475F255L, 0x46FCD9B9L, + 0x7AEB2661L, 0x8B1DDF84L, 0x846A0E79L, 0x915F95E2L, + 0x466E598EL, 0x20B45770L, 0x8CD55591L, 0xC902DE4CL, + 0xB90BACE1L, 0xBB8205D0L, 0x11A86248L, 0x7574A99EL, + 0xB77F19B6L, 0xE0A9DC09L, 0x662D09A1L, 0xC4324633L, + 0xE85A1F02L, 0x09F0BE8CL, 0x4A99A025L, 0x1D6EFE10L, + 0x1AB93D1DL, 0x0BA5A4DFL, 0xA186F20FL, 0x2868F169L, + 0xDCB7DA83L, 0x573906FEL, 0xA1E2CE9BL, 0x4FCD7F52L, + 0x50115E01L, 0xA70683FAL, 0xA002B5C4L, 0x0DE6D027L, + 0x9AF88C27L, 0x773F8641L, 0xC3604C06L, 0x61A806B5L, + 0xF0177A28L, 0xC0F586E0L, 0x006058AAL, 0x30DC7D62L, + 0x11E69ED7L, 0x2338EA63L, 0x53C2DD94L, 0xC2C21634L, + 0xBBCBEE56L, 0x90BCB6DEL, 0xEBFC7DA1L, 0xCE591D76L, + 0x6F05E409L, 0x4B7C0188L, 0x39720A3DL, 0x7C927C24L, + 0x86E3725FL, 0x724D9DB9L, 0x1AC15BB4L, 0xD39EB8FCL, + 0xED545578L, 0x08FCA5B5L, 0xD83D7CD3L, 0x4DAD0FC4L, + 0x1E50EF5EL, 0xB161E6F8L, 0xA28514D9L, 0x6C51133CL, + 0x6FD5C7E7L, 0x56E14EC4L, 0x362ABFCEL, 0xDDC6C837L, + 0xD79A3234L, 0x92638212L, 0x670EFA8EL, 0x406000E0L }, + { 0x3A39CE37L, 0xD3FAF5CFL, 0xABC27737L, 0x5AC52D1BL, + 0x5CB0679EL, 0x4FA33742L, 0xD3822740L, 0x99BC9BBEL, + 0xD5118E9DL, 0xBF0F7315L, 0xD62D1C7EL, 0xC700C47BL, + 0xB78C1B6BL, 0x21A19045L, 0xB26EB1BEL, 0x6A366EB4L, + 0x5748AB2FL, 0xBC946E79L, 0xC6A376D2L, 0x6549C2C8L, + 0x530FF8EEL, 0x468DDE7DL, 0xD5730A1DL, 0x4CD04DC6L, + 0x2939BBDBL, 0xA9BA4650L, 0xAC9526E8L, 0xBE5EE304L, + 0xA1FAD5F0L, 0x6A2D519AL, 0x63EF8CE2L, 0x9A86EE22L, + 0xC089C2B8L, 0x43242EF6L, 0xA51E03AAL, 0x9CF2D0A4L, + 0x83C061BAL, 0x9BE96A4DL, 0x8FE51550L, 0xBA645BD6L, + 0x2826A2F9L, 0xA73A3AE1L, 0x4BA99586L, 0xEF5562E9L, + 0xC72FEFD3L, 0xF752F7DAL, 0x3F046F69L, 0x77FA0A59L, + 0x80E4A915L, 0x87B08601L, 0x9B09E6ADL, 0x3B3EE593L, + 0xE990FD5AL, 0x9E34D797L, 0x2CF0B7D9L, 0x022B8B51L, + 0x96D5AC3AL, 0x017DA67DL, 0xD1CF3ED6L, 0x7C7D2D28L, + 0x1F9F25CFL, 0xADF2B89BL, 0x5AD6B472L, 0x5A88F54CL, + 0xE029AC71L, 0xE019A5E6L, 0x47B0ACFDL, 0xED93FA9BL, + 0xE8D3C48DL, 0x283B57CCL, 0xF8D56629L, 0x79132E28L, + 0x785F0191L, 0xED756055L, 0xF7960E44L, 0xE3D35E8CL, + 0x15056DD4L, 0x88F46DBAL, 0x03A16125L, 0x0564F0BDL, + 0xC3EB9E15L, 0x3C9057A2L, 0x97271AECL, 0xA93A072AL, + 0x1B3F6D9BL, 0x1E6321F5L, 0xF59C66FBL, 0x26DCF319L, + 0x7533D928L, 0xB155FDF5L, 0x03563482L, 0x8ABA3CBBL, + 0x28517711L, 0xC20AD9F8L, 0xABCC5167L, 0xCCAD925FL, + 0x4DE81751L, 0x3830DC8EL, 0x379D5862L, 0x9320F991L, + 0xEA7A90C2L, 0xFB3E7BCEL, 0x5121CE64L, 0x774FBE32L, + 0xA8B6E37EL, 0xC3293D46L, 0x48DE5369L, 0x6413E680L, + 0xA2AE0810L, 0xDD6DB224L, 0x69852DFDL, 0x09072166L, + 0xB39A460AL, 0x6445C0DDL, 0x586CDECFL, 0x1C20C8AEL, + 0x5BBEF7DDL, 0x1B588D40L, 0xCCD2017FL, 0x6BB4E3BBL, + 0xDDA26A7EL, 0x3A59FF45L, 0x3E350A44L, 0xBCB4CDD5L, + 0x72EACEA8L, 0xFA6484BBL, 0x8D6612AEL, 0xBF3C6F47L, + 0xD29BE463L, 0x542F5D9EL, 0xAEC2771BL, 0xF64E6370L, + 0x740E0D8DL, 0xE75B1357L, 0xF8721671L, 0xAF537D5DL, + 0x4040CB08L, 0x4EB4E2CCL, 0x34D2466AL, 0x0115AF84L, + 0xE1B00428L, 0x95983A1DL, 0x06B89FB4L, 0xCE6EA048L, + 0x6F3F3B82L, 0x3520AB82L, 0x011A1D4BL, 0x277227F8L, + 0x611560B1L, 0xE7933FDCL, 0xBB3A792BL, 0x344525BDL, + 0xA08839E1L, 0x51CE794BL, 0x2F32C9B7L, 0xA01FBAC9L, + 0xE01CC87EL, 0xBCC7D1F6L, 0xCF0111C3L, 0xA1E8AAC7L, + 0x1A908749L, 0xD44FBD9AL, 0xD0DADECBL, 0xD50ADA38L, + 0x0339C32AL, 0xC6913667L, 0x8DF9317CL, 0xE0B12B4FL, + 0xF79E59B7L, 0x43F5BB3AL, 0xF2D519FFL, 0x27D9459CL, + 0xBF97222CL, 0x15E6FC2AL, 0x0F91FC71L, 0x9B941525L, + 0xFAE59361L, 0xCEB69CEBL, 0xC2A86459L, 0x12BAA8D1L, + 0xB6C1075EL, 0xE3056A0CL, 0x10D25065L, 0xCB03A442L, + 0xE0EC6E0EL, 0x1698DB3BL, 0x4C98A0BEL, 0x3278E964L, + 0x9F1F9532L, 0xE0D392DFL, 0xD3A0342BL, 0x8971F21EL, + 0x1B0A7441L, 0x4BA3348CL, 0xC5BE7120L, 0xC37632D8L, + 0xDF359F8DL, 0x9B992F2EL, 0xE60B6F47L, 0x0FE3F11DL, + 0xE54CDA54L, 0x1EDAD891L, 0xCE6279CFL, 0xCD3E7E6FL, + 0x1618B166L, 0xFD2C1D05L, 0x848FD2C5L, 0xF6FB2299L, + 0xF523F357L, 0xA6327623L, 0x93A83531L, 0x56CCCD02L, + 0xACF08162L, 0x5A75EBB5L, 0x6E163697L, 0x88D273CCL, + 0xDE966292L, 0x81B949D0L, 0x4C50901BL, 0x71C65614L, + 0xE6C6C7BDL, 0x327A140AL, 0x45E1D006L, 0xC3F27B9AL, + 0xC9AA53FDL, 0x62A80F00L, 0xBB25BFE2L, 0x35BDD2F6L, + 0x71126905L, 0xB2040222L, 0xB6CBCF7CL, 0xCD769C2BL, + 0x53113EC0L, 0x1640E3D3L, 0x38ABBD60L, 0x2547ADF0L, + 0xBA38209CL, 0xF746CE76L, 0x77AFA1C5L, 0x20756060L, + 0x85CBFE4EL, 0x8AE88DD8L, 0x7AAAF9B0L, 0x4CF9AA7EL, + 0x1948C25CL, 0x02FB8A8CL, 0x01C36AE4L, 0xD6EBE1F9L, + 0x90D4F869L, 0xA65CDEA0L, 0x3F09252DL, 0xC208E69FL, + 0xB74E6132L, 0xCE77E25BL, 0x578FDFE3L, 0x3AC372E6L } +}; + +#endif /* !MBEDTLS_BLOWFISH_ALT */ +#endif /* MBEDTLS_BLOWFISH_C */ diff --git a/common/mbedtls/blowfish.h b/common/mbedtls/blowfish.h new file mode 100644 index 00000000..b63af8cd --- /dev/null +++ b/common/mbedtls/blowfish.h @@ -0,0 +1,246 @@ +/** + * \file blowfish.h + * + * \brief Blowfish block cipher + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_BLOWFISH_H +#define MBEDTLS_BLOWFISH_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#define MBEDTLS_BLOWFISH_ENCRYPT 1 +#define MBEDTLS_BLOWFISH_DECRYPT 0 +#define MBEDTLS_BLOWFISH_MAX_KEY_BITS 448 +#define MBEDTLS_BLOWFISH_MIN_KEY_BITS 32 +#define MBEDTLS_BLOWFISH_ROUNDS 16 /**< Rounds to use. When increasing this value, make sure to extend the initialisation vectors */ +#define MBEDTLS_BLOWFISH_BLOCKSIZE 8 /* Blowfish uses 64 bit blocks */ + +#define MBEDTLS_ERR_BLOWFISH_INVALID_KEY_LENGTH -0x0016 /**< Invalid key length. */ +#define MBEDTLS_ERR_BLOWFISH_HW_ACCEL_FAILED -0x0017 /**< Blowfish hardware accelerator failed. */ +#define MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH -0x0018 /**< Invalid data input length. */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_BLOWFISH_ALT) +// Regular implementation +// + +/** + * \brief Blowfish context structure + */ +typedef struct mbedtls_blowfish_context +{ + uint32_t P[MBEDTLS_BLOWFISH_ROUNDS + 2]; /*!< Blowfish round keys */ + uint32_t S[4][256]; /*!< key dependent S-boxes */ +} +mbedtls_blowfish_context; + +#else /* MBEDTLS_BLOWFISH_ALT */ +#include "blowfish_alt.h" +#endif /* MBEDTLS_BLOWFISH_ALT */ + +/** + * \brief Initialize Blowfish context + * + * \param ctx Blowfish context to be initialized + */ +void mbedtls_blowfish_init( mbedtls_blowfish_context *ctx ); + +/** + * \brief Clear Blowfish context + * + * \param ctx Blowfish context to be cleared + */ +void mbedtls_blowfish_free( mbedtls_blowfish_context *ctx ); + +/** + * \brief Blowfish key schedule + * + * \param ctx Blowfish context to be initialized + * \param key encryption key + * \param keybits must be between 32 and 448 bits + * + * \return 0 if successful, or MBEDTLS_ERR_BLOWFISH_INVALID_KEY_LENGTH + */ +int mbedtls_blowfish_setkey( mbedtls_blowfish_context *ctx, const unsigned char *key, + unsigned int keybits ); + +/** + * \brief Blowfish-ECB block encryption/decryption + * + * \param ctx Blowfish context + * \param mode MBEDTLS_BLOWFISH_ENCRYPT or MBEDTLS_BLOWFISH_DECRYPT + * \param input 8-byte input block + * \param output 8-byte output block + * + * \return 0 if successful + */ +int mbedtls_blowfish_crypt_ecb( mbedtls_blowfish_context *ctx, + int mode, + const unsigned char input[MBEDTLS_BLOWFISH_BLOCKSIZE], + unsigned char output[MBEDTLS_BLOWFISH_BLOCKSIZE] ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/** + * \brief Blowfish-CBC buffer encryption/decryption + * Length should be a multiple of the block + * size (8 bytes) + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx Blowfish context + * \param mode MBEDTLS_BLOWFISH_ENCRYPT or MBEDTLS_BLOWFISH_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful, or + * MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH + */ +int mbedtls_blowfish_crypt_cbc( mbedtls_blowfish_context *ctx, + int mode, + size_t length, + unsigned char iv[MBEDTLS_BLOWFISH_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/** + * \brief Blowfish CFB buffer encryption/decryption. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx Blowfish context + * \param mode MBEDTLS_BLOWFISH_ENCRYPT or MBEDTLS_BLOWFISH_DECRYPT + * \param length length of the input data + * \param iv_off offset in IV (updated after use) + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful + */ +int mbedtls_blowfish_crypt_cfb64( mbedtls_blowfish_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[MBEDTLS_BLOWFISH_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ); +#endif /*MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/** + * \brief Blowfish-CTR buffer encryption/decryption + * + * \warning You must never reuse a nonce value with the same key. Doing so + * would void the encryption for the two messages encrypted with + * the same nonce and key. + * + * There are two common strategies for managing nonces with CTR: + * + * 1. You can handle everything as a single message processed over + * successive calls to this function. In that case, you want to + * set \p nonce_counter and \p nc_off to 0 for the first call, and + * then preserve the values of \p nonce_counter, \p nc_off and \p + * stream_block across calls to this function as they will be + * updated by this function. + * + * With this strategy, you must not encrypt more than 2**64 + * blocks of data with the same key. + * + * 2. You can encrypt separate messages by dividing the \p + * nonce_counter buffer in two areas: the first one used for a + * per-message nonce, handled by yourself, and the second one + * updated by this function internally. + * + * For example, you might reserve the first 4 bytes for the + * per-message nonce, and the last 4 bytes for internal use. In that + * case, before calling this function on a new message you need to + * set the first 4 bytes of \p nonce_counter to your chosen nonce + * value, the last 4 to 0, and \p nc_off to 0 (which will cause \p + * stream_block to be ignored). That way, you can encrypt at most + * 2**32 messages of up to 2**32 blocks each with the same key. + * + * The per-message nonce (or information sufficient to reconstruct + * it) needs to be communicated with the ciphertext and must be unique. + * The recommended way to ensure uniqueness is to use a message + * counter. + * + * Note that for both stategies, sizes are measured in blocks and + * that a Blowfish block is 8 bytes. + * + * \warning Upon return, \p stream_block contains sensitive data. Its + * content must not be written to insecure storage and should be + * securely discarded as soon as it's no longer needed. + * + * \param ctx Blowfish context + * \param length The length of the data + * \param nc_off The offset in the current stream_block (for resuming + * within current cipher stream). The offset pointer to + * should be 0 at the start of a stream. + * \param nonce_counter The 64-bit nonce and counter. + * \param stream_block The saved stream-block for resuming. Is overwritten + * by the function. + * \param input The input data stream + * \param output The output data stream + * + * \return 0 if successful + */ +int mbedtls_blowfish_crypt_ctr( mbedtls_blowfish_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[MBEDTLS_BLOWFISH_BLOCKSIZE], + unsigned char stream_block[MBEDTLS_BLOWFISH_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#ifdef __cplusplus +} +#endif + +#endif /* blowfish.h */ diff --git a/common/mbedtls/bn_mul.h b/common/mbedtls/bn_mul.h new file mode 100644 index 00000000..ff0c9fe2 --- /dev/null +++ b/common/mbedtls/bn_mul.h @@ -0,0 +1,895 @@ +/** + * \file bn_mul.h + * + * \brief Multi-precision integer library + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * Multiply source vector [s] with b, add result + * to destination vector [d] and set carry c. + * + * Currently supports: + * + * . IA-32 (386+) . AMD64 / EM64T + * . IA-32 (SSE2) . Motorola 68000 + * . PowerPC, 32-bit . MicroBlaze + * . PowerPC, 64-bit . TriCore + * . SPARC v8 . ARM v3+ + * . Alpha . MIPS32 + * . C, longlong . C, generic + */ +#ifndef MBEDTLS_BN_MUL_H +#define MBEDTLS_BN_MUL_H + +#include "bignum.h" + +#if defined(MBEDTLS_HAVE_ASM) + +#ifndef asm +#define asm __asm +#endif + +/* armcc5 --gnu defines __GNUC__ but doesn't support GNU's extended asm */ +#if defined(__GNUC__) && \ + ( !defined(__ARMCC_VERSION) || __ARMCC_VERSION >= 6000000 ) + +/* + * Disable use of the i386 assembly code below if option -O0, to disable all + * compiler optimisations, is passed, detected with __OPTIMIZE__ + * This is done as the number of registers used in the assembly code doesn't + * work with the -O0 option. + */ +#if defined(__i386__) && defined(__OPTIMIZE__) + +#define MULADDC_INIT \ + asm( \ + "movl %%ebx, %0 \n\t" \ + "movl %5, %%esi \n\t" \ + "movl %6, %%edi \n\t" \ + "movl %7, %%ecx \n\t" \ + "movl %8, %%ebx \n\t" + +#define MULADDC_CORE \ + "lodsl \n\t" \ + "mull %%ebx \n\t" \ + "addl %%ecx, %%eax \n\t" \ + "adcl $0, %%edx \n\t" \ + "addl (%%edi), %%eax \n\t" \ + "adcl $0, %%edx \n\t" \ + "movl %%edx, %%ecx \n\t" \ + "stosl \n\t" + +#if defined(MBEDTLS_HAVE_SSE2) + +#define MULADDC_HUIT \ + "movd %%ecx, %%mm1 \n\t" \ + "movd %%ebx, %%mm0 \n\t" \ + "movd (%%edi), %%mm3 \n\t" \ + "paddq %%mm3, %%mm1 \n\t" \ + "movd (%%esi), %%mm2 \n\t" \ + "pmuludq %%mm0, %%mm2 \n\t" \ + "movd 4(%%esi), %%mm4 \n\t" \ + "pmuludq %%mm0, %%mm4 \n\t" \ + "movd 8(%%esi), %%mm6 \n\t" \ + "pmuludq %%mm0, %%mm6 \n\t" \ + "movd 12(%%esi), %%mm7 \n\t" \ + "pmuludq %%mm0, %%mm7 \n\t" \ + "paddq %%mm2, %%mm1 \n\t" \ + "movd 4(%%edi), %%mm3 \n\t" \ + "paddq %%mm4, %%mm3 \n\t" \ + "movd 8(%%edi), %%mm5 \n\t" \ + "paddq %%mm6, %%mm5 \n\t" \ + "movd 12(%%edi), %%mm4 \n\t" \ + "paddq %%mm4, %%mm7 \n\t" \ + "movd %%mm1, (%%edi) \n\t" \ + "movd 16(%%esi), %%mm2 \n\t" \ + "pmuludq %%mm0, %%mm2 \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "movd 20(%%esi), %%mm4 \n\t" \ + "pmuludq %%mm0, %%mm4 \n\t" \ + "paddq %%mm3, %%mm1 \n\t" \ + "movd 24(%%esi), %%mm6 \n\t" \ + "pmuludq %%mm0, %%mm6 \n\t" \ + "movd %%mm1, 4(%%edi) \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "movd 28(%%esi), %%mm3 \n\t" \ + "pmuludq %%mm0, %%mm3 \n\t" \ + "paddq %%mm5, %%mm1 \n\t" \ + "movd 16(%%edi), %%mm5 \n\t" \ + "paddq %%mm5, %%mm2 \n\t" \ + "movd %%mm1, 8(%%edi) \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "paddq %%mm7, %%mm1 \n\t" \ + "movd 20(%%edi), %%mm5 \n\t" \ + "paddq %%mm5, %%mm4 \n\t" \ + "movd %%mm1, 12(%%edi) \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "paddq %%mm2, %%mm1 \n\t" \ + "movd 24(%%edi), %%mm5 \n\t" \ + "paddq %%mm5, %%mm6 \n\t" \ + "movd %%mm1, 16(%%edi) \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "paddq %%mm4, %%mm1 \n\t" \ + "movd 28(%%edi), %%mm5 \n\t" \ + "paddq %%mm5, %%mm3 \n\t" \ + "movd %%mm1, 20(%%edi) \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "paddq %%mm6, %%mm1 \n\t" \ + "movd %%mm1, 24(%%edi) \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "paddq %%mm3, %%mm1 \n\t" \ + "movd %%mm1, 28(%%edi) \n\t" \ + "addl $32, %%edi \n\t" \ + "addl $32, %%esi \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "movd %%mm1, %%ecx \n\t" + +#define MULADDC_STOP \ + "emms \n\t" \ + "movl %4, %%ebx \n\t" \ + "movl %%ecx, %1 \n\t" \ + "movl %%edi, %2 \n\t" \ + "movl %%esi, %3 \n\t" \ + : "=m" (t), "=m" (c), "=m" (d), "=m" (s) \ + : "m" (t), "m" (s), "m" (d), "m" (c), "m" (b) \ + : "eax", "ebx", "ecx", "edx", "esi", "edi" \ + ); + +#else + +#define MULADDC_STOP \ + "movl %4, %%ebx \n\t" \ + "movl %%ecx, %1 \n\t" \ + "movl %%edi, %2 \n\t" \ + "movl %%esi, %3 \n\t" \ + : "=m" (t), "=m" (c), "=m" (d), "=m" (s) \ + : "m" (t), "m" (s), "m" (d), "m" (c), "m" (b) \ + : "eax", "ebx", "ecx", "edx", "esi", "edi" \ + ); +#endif /* SSE2 */ +#endif /* i386 */ + +#if defined(__amd64__) || defined (__x86_64__) + +#define MULADDC_INIT \ + asm( \ + "xorq %%r8, %%r8 \n\t" + +#define MULADDC_CORE \ + "movq (%%rsi), %%rax \n\t" \ + "mulq %%rbx \n\t" \ + "addq $8, %%rsi \n\t" \ + "addq %%rcx, %%rax \n\t" \ + "movq %%r8, %%rcx \n\t" \ + "adcq $0, %%rdx \n\t" \ + "nop \n\t" \ + "addq %%rax, (%%rdi) \n\t" \ + "adcq %%rdx, %%rcx \n\t" \ + "addq $8, %%rdi \n\t" + +#define MULADDC_STOP \ + : "+c" (c), "+D" (d), "+S" (s) \ + : "b" (b) \ + : "rax", "rdx", "r8" \ + ); + +#endif /* AMD64 */ + +#if defined(__mc68020__) || defined(__mcpu32__) + +#define MULADDC_INIT \ + asm( \ + "movl %3, %%a2 \n\t" \ + "movl %4, %%a3 \n\t" \ + "movl %5, %%d3 \n\t" \ + "movl %6, %%d2 \n\t" \ + "moveq #0, %%d0 \n\t" + +#define MULADDC_CORE \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d4:%%d1 \n\t" \ + "addl %%d3, %%d1 \n\t" \ + "addxl %%d0, %%d4 \n\t" \ + "moveq #0, %%d3 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "addxl %%d4, %%d3 \n\t" + +#define MULADDC_STOP \ + "movl %%d3, %0 \n\t" \ + "movl %%a3, %1 \n\t" \ + "movl %%a2, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "d0", "d1", "d2", "d3", "d4", "a2", "a3" \ + ); + +#define MULADDC_HUIT \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d4:%%d1 \n\t" \ + "addxl %%d3, %%d1 \n\t" \ + "addxl %%d0, %%d4 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d3:%%d1 \n\t" \ + "addxl %%d4, %%d1 \n\t" \ + "addxl %%d0, %%d3 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d4:%%d1 \n\t" \ + "addxl %%d3, %%d1 \n\t" \ + "addxl %%d0, %%d4 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d3:%%d1 \n\t" \ + "addxl %%d4, %%d1 \n\t" \ + "addxl %%d0, %%d3 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d4:%%d1 \n\t" \ + "addxl %%d3, %%d1 \n\t" \ + "addxl %%d0, %%d4 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d3:%%d1 \n\t" \ + "addxl %%d4, %%d1 \n\t" \ + "addxl %%d0, %%d3 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d4:%%d1 \n\t" \ + "addxl %%d3, %%d1 \n\t" \ + "addxl %%d0, %%d4 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d3:%%d1 \n\t" \ + "addxl %%d4, %%d1 \n\t" \ + "addxl %%d0, %%d3 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "addxl %%d0, %%d3 \n\t" + +#endif /* MC68000 */ + +#if defined(__powerpc64__) || defined(__ppc64__) + +#if defined(__MACH__) && defined(__APPLE__) + +#define MULADDC_INIT \ + asm( \ + "ld r3, %3 \n\t" \ + "ld r4, %4 \n\t" \ + "ld r5, %5 \n\t" \ + "ld r6, %6 \n\t" \ + "addi r3, r3, -8 \n\t" \ + "addi r4, r4, -8 \n\t" \ + "addic r5, r5, 0 \n\t" + +#define MULADDC_CORE \ + "ldu r7, 8(r3) \n\t" \ + "mulld r8, r7, r6 \n\t" \ + "mulhdu r9, r7, r6 \n\t" \ + "adde r8, r8, r5 \n\t" \ + "ld r7, 8(r4) \n\t" \ + "addze r5, r9 \n\t" \ + "addc r8, r8, r7 \n\t" \ + "stdu r8, 8(r4) \n\t" + +#define MULADDC_STOP \ + "addze r5, r5 \n\t" \ + "addi r4, r4, 8 \n\t" \ + "addi r3, r3, 8 \n\t" \ + "std r5, %0 \n\t" \ + "std r4, %1 \n\t" \ + "std r3, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r3", "r4", "r5", "r6", "r7", "r8", "r9" \ + ); + + +#else /* __MACH__ && __APPLE__ */ + +#define MULADDC_INIT \ + asm( \ + "ld %%r3, %3 \n\t" \ + "ld %%r4, %4 \n\t" \ + "ld %%r5, %5 \n\t" \ + "ld %%r6, %6 \n\t" \ + "addi %%r3, %%r3, -8 \n\t" \ + "addi %%r4, %%r4, -8 \n\t" \ + "addic %%r5, %%r5, 0 \n\t" + +#define MULADDC_CORE \ + "ldu %%r7, 8(%%r3) \n\t" \ + "mulld %%r8, %%r7, %%r6 \n\t" \ + "mulhdu %%r9, %%r7, %%r6 \n\t" \ + "adde %%r8, %%r8, %%r5 \n\t" \ + "ld %%r7, 8(%%r4) \n\t" \ + "addze %%r5, %%r9 \n\t" \ + "addc %%r8, %%r8, %%r7 \n\t" \ + "stdu %%r8, 8(%%r4) \n\t" + +#define MULADDC_STOP \ + "addze %%r5, %%r5 \n\t" \ + "addi %%r4, %%r4, 8 \n\t" \ + "addi %%r3, %%r3, 8 \n\t" \ + "std %%r5, %0 \n\t" \ + "std %%r4, %1 \n\t" \ + "std %%r3, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r3", "r4", "r5", "r6", "r7", "r8", "r9" \ + ); + +#endif /* __MACH__ && __APPLE__ */ + +#elif defined(__powerpc__) || defined(__ppc__) /* end PPC64/begin PPC32 */ + +#if defined(__MACH__) && defined(__APPLE__) + +#define MULADDC_INIT \ + asm( \ + "lwz r3, %3 \n\t" \ + "lwz r4, %4 \n\t" \ + "lwz r5, %5 \n\t" \ + "lwz r6, %6 \n\t" \ + "addi r3, r3, -4 \n\t" \ + "addi r4, r4, -4 \n\t" \ + "addic r5, r5, 0 \n\t" + +#define MULADDC_CORE \ + "lwzu r7, 4(r3) \n\t" \ + "mullw r8, r7, r6 \n\t" \ + "mulhwu r9, r7, r6 \n\t" \ + "adde r8, r8, r5 \n\t" \ + "lwz r7, 4(r4) \n\t" \ + "addze r5, r9 \n\t" \ + "addc r8, r8, r7 \n\t" \ + "stwu r8, 4(r4) \n\t" + +#define MULADDC_STOP \ + "addze r5, r5 \n\t" \ + "addi r4, r4, 4 \n\t" \ + "addi r3, r3, 4 \n\t" \ + "stw r5, %0 \n\t" \ + "stw r4, %1 \n\t" \ + "stw r3, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r3", "r4", "r5", "r6", "r7", "r8", "r9" \ + ); + +#else /* __MACH__ && __APPLE__ */ + +#define MULADDC_INIT \ + asm( \ + "lwz %%r3, %3 \n\t" \ + "lwz %%r4, %4 \n\t" \ + "lwz %%r5, %5 \n\t" \ + "lwz %%r6, %6 \n\t" \ + "addi %%r3, %%r3, -4 \n\t" \ + "addi %%r4, %%r4, -4 \n\t" \ + "addic %%r5, %%r5, 0 \n\t" + +#define MULADDC_CORE \ + "lwzu %%r7, 4(%%r3) \n\t" \ + "mullw %%r8, %%r7, %%r6 \n\t" \ + "mulhwu %%r9, %%r7, %%r6 \n\t" \ + "adde %%r8, %%r8, %%r5 \n\t" \ + "lwz %%r7, 4(%%r4) \n\t" \ + "addze %%r5, %%r9 \n\t" \ + "addc %%r8, %%r8, %%r7 \n\t" \ + "stwu %%r8, 4(%%r4) \n\t" + +#define MULADDC_STOP \ + "addze %%r5, %%r5 \n\t" \ + "addi %%r4, %%r4, 4 \n\t" \ + "addi %%r3, %%r3, 4 \n\t" \ + "stw %%r5, %0 \n\t" \ + "stw %%r4, %1 \n\t" \ + "stw %%r3, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r3", "r4", "r5", "r6", "r7", "r8", "r9" \ + ); + +#endif /* __MACH__ && __APPLE__ */ + +#endif /* PPC32 */ + +/* + * The Sparc(64) assembly is reported to be broken. + * Disable it for now, until we're able to fix it. + */ +#if 0 && defined(__sparc__) +#if defined(__sparc64__) + +#define MULADDC_INIT \ + asm( \ + "ldx %3, %%o0 \n\t" \ + "ldx %4, %%o1 \n\t" \ + "ld %5, %%o2 \n\t" \ + "ld %6, %%o3 \n\t" + +#define MULADDC_CORE \ + "ld [%%o0], %%o4 \n\t" \ + "inc 4, %%o0 \n\t" \ + "ld [%%o1], %%o5 \n\t" \ + "umul %%o3, %%o4, %%o4 \n\t" \ + "addcc %%o4, %%o2, %%o4 \n\t" \ + "rd %%y, %%g1 \n\t" \ + "addx %%g1, 0, %%g1 \n\t" \ + "addcc %%o4, %%o5, %%o4 \n\t" \ + "st %%o4, [%%o1] \n\t" \ + "addx %%g1, 0, %%o2 \n\t" \ + "inc 4, %%o1 \n\t" + + #define MULADDC_STOP \ + "st %%o2, %0 \n\t" \ + "stx %%o1, %1 \n\t" \ + "stx %%o0, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "g1", "o0", "o1", "o2", "o3", "o4", \ + "o5" \ + ); + +#else /* __sparc64__ */ + +#define MULADDC_INIT \ + asm( \ + "ld %3, %%o0 \n\t" \ + "ld %4, %%o1 \n\t" \ + "ld %5, %%o2 \n\t" \ + "ld %6, %%o3 \n\t" + +#define MULADDC_CORE \ + "ld [%%o0], %%o4 \n\t" \ + "inc 4, %%o0 \n\t" \ + "ld [%%o1], %%o5 \n\t" \ + "umul %%o3, %%o4, %%o4 \n\t" \ + "addcc %%o4, %%o2, %%o4 \n\t" \ + "rd %%y, %%g1 \n\t" \ + "addx %%g1, 0, %%g1 \n\t" \ + "addcc %%o4, %%o5, %%o4 \n\t" \ + "st %%o4, [%%o1] \n\t" \ + "addx %%g1, 0, %%o2 \n\t" \ + "inc 4, %%o1 \n\t" + +#define MULADDC_STOP \ + "st %%o2, %0 \n\t" \ + "st %%o1, %1 \n\t" \ + "st %%o0, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "g1", "o0", "o1", "o2", "o3", "o4", \ + "o5" \ + ); + +#endif /* __sparc64__ */ +#endif /* __sparc__ */ + +#if defined(__microblaze__) || defined(microblaze) + +#define MULADDC_INIT \ + asm( \ + "lwi r3, %3 \n\t" \ + "lwi r4, %4 \n\t" \ + "lwi r5, %5 \n\t" \ + "lwi r6, %6 \n\t" \ + "andi r7, r6, 0xffff \n\t" \ + "bsrli r6, r6, 16 \n\t" + +#define MULADDC_CORE \ + "lhui r8, r3, 0 \n\t" \ + "addi r3, r3, 2 \n\t" \ + "lhui r9, r3, 0 \n\t" \ + "addi r3, r3, 2 \n\t" \ + "mul r10, r9, r6 \n\t" \ + "mul r11, r8, r7 \n\t" \ + "mul r12, r9, r7 \n\t" \ + "mul r13, r8, r6 \n\t" \ + "bsrli r8, r10, 16 \n\t" \ + "bsrli r9, r11, 16 \n\t" \ + "add r13, r13, r8 \n\t" \ + "add r13, r13, r9 \n\t" \ + "bslli r10, r10, 16 \n\t" \ + "bslli r11, r11, 16 \n\t" \ + "add r12, r12, r10 \n\t" \ + "addc r13, r13, r0 \n\t" \ + "add r12, r12, r11 \n\t" \ + "addc r13, r13, r0 \n\t" \ + "lwi r10, r4, 0 \n\t" \ + "add r12, r12, r10 \n\t" \ + "addc r13, r13, r0 \n\t" \ + "add r12, r12, r5 \n\t" \ + "addc r5, r13, r0 \n\t" \ + "swi r12, r4, 0 \n\t" \ + "addi r4, r4, 4 \n\t" + +#define MULADDC_STOP \ + "swi r5, %0 \n\t" \ + "swi r4, %1 \n\t" \ + "swi r3, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r3", "r4", "r5", "r6", "r7", "r8", \ + "r9", "r10", "r11", "r12", "r13" \ + ); + +#endif /* MicroBlaze */ + +#if defined(__tricore__) + +#define MULADDC_INIT \ + asm( \ + "ld.a %%a2, %3 \n\t" \ + "ld.a %%a3, %4 \n\t" \ + "ld.w %%d4, %5 \n\t" \ + "ld.w %%d1, %6 \n\t" \ + "xor %%d5, %%d5 \n\t" + +#define MULADDC_CORE \ + "ld.w %%d0, [%%a2+] \n\t" \ + "madd.u %%e2, %%e4, %%d0, %%d1 \n\t" \ + "ld.w %%d0, [%%a3] \n\t" \ + "addx %%d2, %%d2, %%d0 \n\t" \ + "addc %%d3, %%d3, 0 \n\t" \ + "mov %%d4, %%d3 \n\t" \ + "st.w [%%a3+], %%d2 \n\t" + +#define MULADDC_STOP \ + "st.w %0, %%d4 \n\t" \ + "st.a %1, %%a3 \n\t" \ + "st.a %2, %%a2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "d0", "d1", "e2", "d4", "a2", "a3" \ + ); + +#endif /* TriCore */ + +/* + * gcc -O0 by default uses r7 for the frame pointer, so it complains about our + * use of r7 below, unless -fomit-frame-pointer is passed. Unfortunately, + * passing that option is not easy when building with yotta. + * + * On the other hand, -fomit-frame-pointer is implied by any -Ox options with + * x !=0, which we can detect using __OPTIMIZE__ (which is also defined by + * clang and armcc5 under the same conditions). + * + * So, only use the optimized assembly below for optimized build, which avoids + * the build error and is pretty reasonable anyway. + */ +#if defined(__GNUC__) && !defined(__OPTIMIZE__) +#define MULADDC_CANNOT_USE_R7 +#endif + +#if defined(__arm__) && !defined(MULADDC_CANNOT_USE_R7) + +#if defined(__thumb__) && !defined(__thumb2__) + +#define MULADDC_INIT \ + asm( \ + "ldr r0, %3 \n\t" \ + "ldr r1, %4 \n\t" \ + "ldr r2, %5 \n\t" \ + "ldr r3, %6 \n\t" \ + "lsr r7, r3, #16 \n\t" \ + "mov r9, r7 \n\t" \ + "lsl r7, r3, #16 \n\t" \ + "lsr r7, r7, #16 \n\t" \ + "mov r8, r7 \n\t" + +#define MULADDC_CORE \ + "ldmia r0!, {r6} \n\t" \ + "lsr r7, r6, #16 \n\t" \ + "lsl r6, r6, #16 \n\t" \ + "lsr r6, r6, #16 \n\t" \ + "mov r4, r8 \n\t" \ + "mul r4, r6 \n\t" \ + "mov r3, r9 \n\t" \ + "mul r6, r3 \n\t" \ + "mov r5, r9 \n\t" \ + "mul r5, r7 \n\t" \ + "mov r3, r8 \n\t" \ + "mul r7, r3 \n\t" \ + "lsr r3, r6, #16 \n\t" \ + "add r5, r5, r3 \n\t" \ + "lsr r3, r7, #16 \n\t" \ + "add r5, r5, r3 \n\t" \ + "add r4, r4, r2 \n\t" \ + "mov r2, #0 \n\t" \ + "adc r5, r2 \n\t" \ + "lsl r3, r6, #16 \n\t" \ + "add r4, r4, r3 \n\t" \ + "adc r5, r2 \n\t" \ + "lsl r3, r7, #16 \n\t" \ + "add r4, r4, r3 \n\t" \ + "adc r5, r2 \n\t" \ + "ldr r3, [r1] \n\t" \ + "add r4, r4, r3 \n\t" \ + "adc r2, r5 \n\t" \ + "stmia r1!, {r4} \n\t" + +#define MULADDC_STOP \ + "str r2, %0 \n\t" \ + "str r1, %1 \n\t" \ + "str r0, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r0", "r1", "r2", "r3", "r4", "r5", \ + "r6", "r7", "r8", "r9", "cc" \ + ); + +#else + +#define MULADDC_INIT \ + asm( \ + "ldr r0, %3 \n\t" \ + "ldr r1, %4 \n\t" \ + "ldr r2, %5 \n\t" \ + "ldr r3, %6 \n\t" + +#define MULADDC_CORE \ + "ldr r4, [r0], #4 \n\t" \ + "mov r5, #0 \n\t" \ + "ldr r6, [r1] \n\t" \ + "umlal r2, r5, r3, r4 \n\t" \ + "adds r7, r6, r2 \n\t" \ + "adc r2, r5, #0 \n\t" \ + "str r7, [r1], #4 \n\t" + +#define MULADDC_STOP \ + "str r2, %0 \n\t" \ + "str r1, %1 \n\t" \ + "str r0, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r0", "r1", "r2", "r3", "r4", "r5", \ + "r6", "r7", "cc" \ + ); + +#endif /* Thumb */ + +#endif /* ARMv3 */ + +#if defined(__alpha__) + +#define MULADDC_INIT \ + asm( \ + "ldq $1, %3 \n\t" \ + "ldq $2, %4 \n\t" \ + "ldq $3, %5 \n\t" \ + "ldq $4, %6 \n\t" + +#define MULADDC_CORE \ + "ldq $6, 0($1) \n\t" \ + "addq $1, 8, $1 \n\t" \ + "mulq $6, $4, $7 \n\t" \ + "umulh $6, $4, $6 \n\t" \ + "addq $7, $3, $7 \n\t" \ + "cmpult $7, $3, $3 \n\t" \ + "ldq $5, 0($2) \n\t" \ + "addq $7, $5, $7 \n\t" \ + "cmpult $7, $5, $5 \n\t" \ + "stq $7, 0($2) \n\t" \ + "addq $2, 8, $2 \n\t" \ + "addq $6, $3, $3 \n\t" \ + "addq $5, $3, $3 \n\t" + +#define MULADDC_STOP \ + "stq $3, %0 \n\t" \ + "stq $2, %1 \n\t" \ + "stq $1, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "$1", "$2", "$3", "$4", "$5", "$6", "$7" \ + ); +#endif /* Alpha */ + +#if defined(__mips__) && !defined(__mips64) + +#define MULADDC_INIT \ + asm( \ + "lw $10, %3 \n\t" \ + "lw $11, %4 \n\t" \ + "lw $12, %5 \n\t" \ + "lw $13, %6 \n\t" + +#define MULADDC_CORE \ + "lw $14, 0($10) \n\t" \ + "multu $13, $14 \n\t" \ + "addi $10, $10, 4 \n\t" \ + "mflo $14 \n\t" \ + "mfhi $9 \n\t" \ + "addu $14, $12, $14 \n\t" \ + "lw $15, 0($11) \n\t" \ + "sltu $12, $14, $12 \n\t" \ + "addu $15, $14, $15 \n\t" \ + "sltu $14, $15, $14 \n\t" \ + "addu $12, $12, $9 \n\t" \ + "sw $15, 0($11) \n\t" \ + "addu $12, $12, $14 \n\t" \ + "addi $11, $11, 4 \n\t" + +#define MULADDC_STOP \ + "sw $12, %0 \n\t" \ + "sw $11, %1 \n\t" \ + "sw $10, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "$9", "$10", "$11", "$12", "$13", "$14", "$15" \ + ); + +#endif /* MIPS */ +#endif /* GNUC */ + +#if (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__) + +#define MULADDC_INIT \ + __asm mov esi, s \ + __asm mov edi, d \ + __asm mov ecx, c \ + __asm mov ebx, b + +#define MULADDC_CORE \ + __asm lodsd \ + __asm mul ebx \ + __asm add eax, ecx \ + __asm adc edx, 0 \ + __asm add eax, [edi] \ + __asm adc edx, 0 \ + __asm mov ecx, edx \ + __asm stosd + +#if defined(MBEDTLS_HAVE_SSE2) + +#define EMIT __asm _emit + +#define MULADDC_HUIT \ + EMIT 0x0F EMIT 0x6E EMIT 0xC9 \ + EMIT 0x0F EMIT 0x6E EMIT 0xC3 \ + EMIT 0x0F EMIT 0x6E EMIT 0x1F \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ + EMIT 0x0F EMIT 0x6E EMIT 0x16 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \ + EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x04 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \ + EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x08 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \ + EMIT 0x0F EMIT 0x6E EMIT 0x7E EMIT 0x0C \ + EMIT 0x0F EMIT 0xF4 EMIT 0xF8 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCA \ + EMIT 0x0F EMIT 0x6E EMIT 0x5F EMIT 0x04 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xDC \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x08 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xEE \ + EMIT 0x0F EMIT 0x6E EMIT 0x67 EMIT 0x0C \ + EMIT 0x0F EMIT 0xD4 EMIT 0xFC \ + EMIT 0x0F EMIT 0x7E EMIT 0x0F \ + EMIT 0x0F EMIT 0x6E EMIT 0x56 EMIT 0x10 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x14 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ + EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x18 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x04 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0x6E EMIT 0x5E EMIT 0x1C \ + EMIT 0x0F EMIT 0xF4 EMIT 0xD8 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCD \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x10 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xD5 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x08 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCF \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x14 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xE5 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x0C \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCA \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x18 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xF5 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x10 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCC \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x1C \ + EMIT 0x0F EMIT 0xD4 EMIT 0xDD \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x14 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCE \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x18 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x1C \ + EMIT 0x83 EMIT 0xC7 EMIT 0x20 \ + EMIT 0x83 EMIT 0xC6 EMIT 0x20 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0x7E EMIT 0xC9 + +#define MULADDC_STOP \ + EMIT 0x0F EMIT 0x77 \ + __asm mov c, ecx \ + __asm mov d, edi \ + __asm mov s, esi \ + +#else + +#define MULADDC_STOP \ + __asm mov c, ecx \ + __asm mov d, edi \ + __asm mov s, esi \ + +#endif /* SSE2 */ +#endif /* MSVC */ + +#endif /* MBEDTLS_HAVE_ASM */ + +#if !defined(MULADDC_CORE) +#if defined(MBEDTLS_HAVE_UDBL) + +#define MULADDC_INIT \ +{ \ + mbedtls_t_udbl r; \ + mbedtls_mpi_uint r0, r1; + +#define MULADDC_CORE \ + r = *(s++) * (mbedtls_t_udbl) b; \ + r0 = (mbedtls_mpi_uint) r; \ + r1 = (mbedtls_mpi_uint)( r >> biL ); \ + r0 += c; r1 += (r0 < c); \ + r0 += *d; r1 += (r0 < *d); \ + c = r1; *(d++) = r0; + +#define MULADDC_STOP \ +} + +#else +#define MULADDC_INIT \ +{ \ + mbedtls_mpi_uint s0, s1, b0, b1; \ + mbedtls_mpi_uint r0, r1, rx, ry; \ + b0 = ( b << biH ) >> biH; \ + b1 = ( b >> biH ); + +#define MULADDC_CORE \ + s0 = ( *s << biH ) >> biH; \ + s1 = ( *s >> biH ); s++; \ + rx = s0 * b1; r0 = s0 * b0; \ + ry = s1 * b0; r1 = s1 * b1; \ + r1 += ( rx >> biH ); \ + r1 += ( ry >> biH ); \ + rx <<= biH; ry <<= biH; \ + r0 += rx; r1 += (r0 < rx); \ + r0 += ry; r1 += (r0 < ry); \ + r0 += c; r1 += (r0 < c); \ + r0 += *d; r1 += (r0 < *d); \ + c = r1; *(d++) = r0; + +#define MULADDC_STOP \ +} + +#endif /* C (generic) */ +#endif /* C (longlong) */ + +#endif /* bn_mul.h */ diff --git a/common/mbedtls/camellia.c b/common/mbedtls/camellia.c new file mode 100644 index 00000000..3d9ae72c --- /dev/null +++ b/common/mbedtls/camellia.c @@ -0,0 +1,1070 @@ +/* + * Camellia implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The Camellia block cipher was designed by NTT and Mitsubishi Electric + * Corporation. + * + * http://info.isl.ntt.co.jp/crypt/eng/camellia/dl/01espec.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_CAMELLIA_C) + +#include "mbedtls/camellia.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_CAMELLIA_ALT) + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +static const unsigned char SIGMA_CHARS[6][8] = +{ + { 0xa0, 0x9e, 0x66, 0x7f, 0x3b, 0xcc, 0x90, 0x8b }, + { 0xb6, 0x7a, 0xe8, 0x58, 0x4c, 0xaa, 0x73, 0xb2 }, + { 0xc6, 0xef, 0x37, 0x2f, 0xe9, 0x4f, 0x82, 0xbe }, + { 0x54, 0xff, 0x53, 0xa5, 0xf1, 0xd3, 0x6f, 0x1c }, + { 0x10, 0xe5, 0x27, 0xfa, 0xde, 0x68, 0x2d, 0x1d }, + { 0xb0, 0x56, 0x88, 0xc2, 0xb3, 0xe6, 0xc1, 0xfd } +}; + +#if defined(MBEDTLS_CAMELLIA_SMALL_MEMORY) + +static const unsigned char FSb[256] = +{ + 112,130, 44,236,179, 39,192,229,228,133, 87, 53,234, 12,174, 65, + 35,239,107,147, 69, 25,165, 33,237, 14, 79, 78, 29,101,146,189, + 134,184,175,143,124,235, 31,206, 62, 48,220, 95, 94,197, 11, 26, + 166,225, 57,202,213, 71, 93, 61,217, 1, 90,214, 81, 86,108, 77, + 139, 13,154,102,251,204,176, 45,116, 18, 43, 32,240,177,132,153, + 223, 76,203,194, 52,126,118, 5,109,183,169, 49,209, 23, 4,215, + 20, 88, 58, 97,222, 27, 17, 28, 50, 15,156, 22, 83, 24,242, 34, + 254, 68,207,178,195,181,122,145, 36, 8,232,168, 96,252,105, 80, + 170,208,160,125,161,137, 98,151, 84, 91, 30,149,224,255,100,210, + 16,196, 0, 72,163,247,117,219,138, 3,230,218, 9, 63,221,148, + 135, 92,131, 2,205, 74,144, 51,115,103,246,243,157,127,191,226, + 82,155,216, 38,200, 55,198, 59,129,150,111, 75, 19,190, 99, 46, + 233,121,167,140,159,110,188,142, 41,245,249,182, 47,253,180, 89, + 120,152, 6,106,231, 70,113,186,212, 37,171, 66,136,162,141,250, + 114, 7,185, 85,248,238,172, 10, 54, 73, 42,104, 60, 56,241,164, + 64, 40,211,123,187,201, 67,193, 21,227,173,244,119,199,128,158 +}; + +#define SBOX1(n) FSb[(n)] +#define SBOX2(n) (unsigned char)((FSb[(n)] >> 7 ^ FSb[(n)] << 1) & 0xff) +#define SBOX3(n) (unsigned char)((FSb[(n)] >> 1 ^ FSb[(n)] << 7) & 0xff) +#define SBOX4(n) FSb[((n) << 1 ^ (n) >> 7) &0xff] + +#else /* MBEDTLS_CAMELLIA_SMALL_MEMORY */ + +static const unsigned char FSb[256] = +{ + 112, 130, 44, 236, 179, 39, 192, 229, 228, 133, 87, 53, 234, 12, 174, 65, + 35, 239, 107, 147, 69, 25, 165, 33, 237, 14, 79, 78, 29, 101, 146, 189, + 134, 184, 175, 143, 124, 235, 31, 206, 62, 48, 220, 95, 94, 197, 11, 26, + 166, 225, 57, 202, 213, 71, 93, 61, 217, 1, 90, 214, 81, 86, 108, 77, + 139, 13, 154, 102, 251, 204, 176, 45, 116, 18, 43, 32, 240, 177, 132, 153, + 223, 76, 203, 194, 52, 126, 118, 5, 109, 183, 169, 49, 209, 23, 4, 215, + 20, 88, 58, 97, 222, 27, 17, 28, 50, 15, 156, 22, 83, 24, 242, 34, + 254, 68, 207, 178, 195, 181, 122, 145, 36, 8, 232, 168, 96, 252, 105, 80, + 170, 208, 160, 125, 161, 137, 98, 151, 84, 91, 30, 149, 224, 255, 100, 210, + 16, 196, 0, 72, 163, 247, 117, 219, 138, 3, 230, 218, 9, 63, 221, 148, + 135, 92, 131, 2, 205, 74, 144, 51, 115, 103, 246, 243, 157, 127, 191, 226, + 82, 155, 216, 38, 200, 55, 198, 59, 129, 150, 111, 75, 19, 190, 99, 46, + 233, 121, 167, 140, 159, 110, 188, 142, 41, 245, 249, 182, 47, 253, 180, 89, + 120, 152, 6, 106, 231, 70, 113, 186, 212, 37, 171, 66, 136, 162, 141, 250, + 114, 7, 185, 85, 248, 238, 172, 10, 54, 73, 42, 104, 60, 56, 241, 164, + 64, 40, 211, 123, 187, 201, 67, 193, 21, 227, 173, 244, 119, 199, 128, 158 +}; + +static const unsigned char FSb2[256] = +{ + 224, 5, 88, 217, 103, 78, 129, 203, 201, 11, 174, 106, 213, 24, 93, 130, + 70, 223, 214, 39, 138, 50, 75, 66, 219, 28, 158, 156, 58, 202, 37, 123, + 13, 113, 95, 31, 248, 215, 62, 157, 124, 96, 185, 190, 188, 139, 22, 52, + 77, 195, 114, 149, 171, 142, 186, 122, 179, 2, 180, 173, 162, 172, 216, 154, + 23, 26, 53, 204, 247, 153, 97, 90, 232, 36, 86, 64, 225, 99, 9, 51, + 191, 152, 151, 133, 104, 252, 236, 10, 218, 111, 83, 98, 163, 46, 8, 175, + 40, 176, 116, 194, 189, 54, 34, 56, 100, 30, 57, 44, 166, 48, 229, 68, + 253, 136, 159, 101, 135, 107, 244, 35, 72, 16, 209, 81, 192, 249, 210, 160, + 85, 161, 65, 250, 67, 19, 196, 47, 168, 182, 60, 43, 193, 255, 200, 165, + 32, 137, 0, 144, 71, 239, 234, 183, 21, 6, 205, 181, 18, 126, 187, 41, + 15, 184, 7, 4, 155, 148, 33, 102, 230, 206, 237, 231, 59, 254, 127, 197, + 164, 55, 177, 76, 145, 110, 141, 118, 3, 45, 222, 150, 38, 125, 198, 92, + 211, 242, 79, 25, 63, 220, 121, 29, 82, 235, 243, 109, 94, 251, 105, 178, + 240, 49, 12, 212, 207, 140, 226, 117, 169, 74, 87, 132, 17, 69, 27, 245, + 228, 14, 115, 170, 241, 221, 89, 20, 108, 146, 84, 208, 120, 112, 227, 73, + 128, 80, 167, 246, 119, 147, 134, 131, 42, 199, 91, 233, 238, 143, 1, 61 +}; + +static const unsigned char FSb3[256] = +{ + 56, 65, 22, 118, 217, 147, 96, 242, 114, 194, 171, 154, 117, 6, 87, 160, + 145, 247, 181, 201, 162, 140, 210, 144, 246, 7, 167, 39, 142, 178, 73, 222, + 67, 92, 215, 199, 62, 245, 143, 103, 31, 24, 110, 175, 47, 226, 133, 13, + 83, 240, 156, 101, 234, 163, 174, 158, 236, 128, 45, 107, 168, 43, 54, 166, + 197, 134, 77, 51, 253, 102, 88, 150, 58, 9, 149, 16, 120, 216, 66, 204, + 239, 38, 229, 97, 26, 63, 59, 130, 182, 219, 212, 152, 232, 139, 2, 235, + 10, 44, 29, 176, 111, 141, 136, 14, 25, 135, 78, 11, 169, 12, 121, 17, + 127, 34, 231, 89, 225, 218, 61, 200, 18, 4, 116, 84, 48, 126, 180, 40, + 85, 104, 80, 190, 208, 196, 49, 203, 42, 173, 15, 202, 112, 255, 50, 105, + 8, 98, 0, 36, 209, 251, 186, 237, 69, 129, 115, 109, 132, 159, 238, 74, + 195, 46, 193, 1, 230, 37, 72, 153, 185, 179, 123, 249, 206, 191, 223, 113, + 41, 205, 108, 19, 100, 155, 99, 157, 192, 75, 183, 165, 137, 95, 177, 23, + 244, 188, 211, 70, 207, 55, 94, 71, 148, 250, 252, 91, 151, 254, 90, 172, + 60, 76, 3, 53, 243, 35, 184, 93, 106, 146, 213, 33, 68, 81, 198, 125, + 57, 131, 220, 170, 124, 119, 86, 5, 27, 164, 21, 52, 30, 28, 248, 82, + 32, 20, 233, 189, 221, 228, 161, 224, 138, 241, 214, 122, 187, 227, 64, 79 +}; + +static const unsigned char FSb4[256] = +{ + 112, 44, 179, 192, 228, 87, 234, 174, 35, 107, 69, 165, 237, 79, 29, 146, + 134, 175, 124, 31, 62, 220, 94, 11, 166, 57, 213, 93, 217, 90, 81, 108, + 139, 154, 251, 176, 116, 43, 240, 132, 223, 203, 52, 118, 109, 169, 209, 4, + 20, 58, 222, 17, 50, 156, 83, 242, 254, 207, 195, 122, 36, 232, 96, 105, + 170, 160, 161, 98, 84, 30, 224, 100, 16, 0, 163, 117, 138, 230, 9, 221, + 135, 131, 205, 144, 115, 246, 157, 191, 82, 216, 200, 198, 129, 111, 19, 99, + 233, 167, 159, 188, 41, 249, 47, 180, 120, 6, 231, 113, 212, 171, 136, 141, + 114, 185, 248, 172, 54, 42, 60, 241, 64, 211, 187, 67, 21, 173, 119, 128, + 130, 236, 39, 229, 133, 53, 12, 65, 239, 147, 25, 33, 14, 78, 101, 189, + 184, 143, 235, 206, 48, 95, 197, 26, 225, 202, 71, 61, 1, 214, 86, 77, + 13, 102, 204, 45, 18, 32, 177, 153, 76, 194, 126, 5, 183, 49, 23, 215, + 88, 97, 27, 28, 15, 22, 24, 34, 68, 178, 181, 145, 8, 168, 252, 80, + 208, 125, 137, 151, 91, 149, 255, 210, 196, 72, 247, 219, 3, 218, 63, 148, + 92, 2, 74, 51, 103, 243, 127, 226, 155, 38, 55, 59, 150, 75, 190, 46, + 121, 140, 110, 142, 245, 182, 253, 89, 152, 106, 70, 186, 37, 66, 162, 250, + 7, 85, 238, 10, 73, 104, 56, 164, 40, 123, 201, 193, 227, 244, 199, 158 +}; + +#define SBOX1(n) FSb[(n)] +#define SBOX2(n) FSb2[(n)] +#define SBOX3(n) FSb3[(n)] +#define SBOX4(n) FSb4[(n)] + +#endif /* MBEDTLS_CAMELLIA_SMALL_MEMORY */ + +static const unsigned char shifts[2][4][4] = +{ + { + { 1, 1, 1, 1 }, /* KL */ + { 0, 0, 0, 0 }, /* KR */ + { 1, 1, 1, 1 }, /* KA */ + { 0, 0, 0, 0 } /* KB */ + }, + { + { 1, 0, 1, 1 }, /* KL */ + { 1, 1, 0, 1 }, /* KR */ + { 1, 1, 1, 0 }, /* KA */ + { 1, 1, 0, 1 } /* KB */ + } +}; + +static const signed char indexes[2][4][20] = +{ + { + { 0, 1, 2, 3, 8, 9, 10, 11, 38, 39, + 36, 37, 23, 20, 21, 22, 27, -1, -1, 26 }, /* KL -> RK */ + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /* KR -> RK */ + { 4, 5, 6, 7, 12, 13, 14, 15, 16, 17, + 18, 19, -1, 24, 25, -1, 31, 28, 29, 30 }, /* KA -> RK */ + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } /* KB -> RK */ + }, + { + { 0, 1, 2, 3, 61, 62, 63, 60, -1, -1, + -1, -1, 27, 24, 25, 26, 35, 32, 33, 34 }, /* KL -> RK */ + { -1, -1, -1, -1, 8, 9, 10, 11, 16, 17, + 18, 19, -1, -1, -1, -1, 39, 36, 37, 38 }, /* KR -> RK */ + { -1, -1, -1, -1, 12, 13, 14, 15, 58, 59, + 56, 57, 31, 28, 29, 30, -1, -1, -1, -1 }, /* KA -> RK */ + { 4, 5, 6, 7, 65, 66, 67, 64, 20, 21, + 22, 23, -1, -1, -1, -1, 43, 40, 41, 42 } /* KB -> RK */ + } +}; + +static const signed char transposes[2][20] = +{ + { + 21, 22, 23, 20, + -1, -1, -1, -1, + 18, 19, 16, 17, + 11, 8, 9, 10, + 15, 12, 13, 14 + }, + { + 25, 26, 27, 24, + 29, 30, 31, 28, + 18, 19, 16, 17, + -1, -1, -1, -1, + -1, -1, -1, -1 + } +}; + +/* Shift macro for 128 bit strings with rotation smaller than 32 bits (!) */ +#define ROTL(DEST, SRC, SHIFT) \ +{ \ + (DEST)[0] = (SRC)[0] << (SHIFT) ^ (SRC)[1] >> (32 - (SHIFT)); \ + (DEST)[1] = (SRC)[1] << (SHIFT) ^ (SRC)[2] >> (32 - (SHIFT)); \ + (DEST)[2] = (SRC)[2] << (SHIFT) ^ (SRC)[3] >> (32 - (SHIFT)); \ + (DEST)[3] = (SRC)[3] << (SHIFT) ^ (SRC)[0] >> (32 - (SHIFT)); \ +} + +#define FL(XL, XR, KL, KR) \ +{ \ + (XR) = ((((XL) & (KL)) << 1) | (((XL) & (KL)) >> 31)) ^ (XR); \ + (XL) = ((XR) | (KR)) ^ (XL); \ +} + +#define FLInv(YL, YR, KL, KR) \ +{ \ + (YL) = ((YR) | (KR)) ^ (YL); \ + (YR) = ((((YL) & (KL)) << 1) | (((YL) & (KL)) >> 31)) ^ (YR); \ +} + +#define SHIFT_AND_PLACE(INDEX, OFFSET) \ +{ \ + TK[0] = KC[(OFFSET) * 4 + 0]; \ + TK[1] = KC[(OFFSET) * 4 + 1]; \ + TK[2] = KC[(OFFSET) * 4 + 2]; \ + TK[3] = KC[(OFFSET) * 4 + 3]; \ + \ + for( i = 1; i <= 4; i++ ) \ + if( shifts[(INDEX)][(OFFSET)][i -1] ) \ + ROTL(TK + i * 4, TK, ( 15 * i ) % 32); \ + \ + for( i = 0; i < 20; i++ ) \ + if( indexes[(INDEX)][(OFFSET)][i] != -1 ) { \ + RK[indexes[(INDEX)][(OFFSET)][i]] = TK[ i ]; \ + } \ +} + +static void camellia_feistel( const uint32_t x[2], const uint32_t k[2], + uint32_t z[2]) +{ + uint32_t I0, I1; + I0 = x[0] ^ k[0]; + I1 = x[1] ^ k[1]; + + I0 = ((uint32_t) SBOX1((I0 >> 24) & 0xFF) << 24) | + ((uint32_t) SBOX2((I0 >> 16) & 0xFF) << 16) | + ((uint32_t) SBOX3((I0 >> 8) & 0xFF) << 8) | + ((uint32_t) SBOX4((I0 ) & 0xFF) ); + I1 = ((uint32_t) SBOX2((I1 >> 24) & 0xFF) << 24) | + ((uint32_t) SBOX3((I1 >> 16) & 0xFF) << 16) | + ((uint32_t) SBOX4((I1 >> 8) & 0xFF) << 8) | + ((uint32_t) SBOX1((I1 ) & 0xFF) ); + + I0 ^= (I1 << 8) | (I1 >> 24); + I1 ^= (I0 << 16) | (I0 >> 16); + I0 ^= (I1 >> 8) | (I1 << 24); + I1 ^= (I0 >> 8) | (I0 << 24); + + z[0] ^= I1; + z[1] ^= I0; +} + +void mbedtls_camellia_init( mbedtls_camellia_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_camellia_context ) ); +} + +void mbedtls_camellia_free( mbedtls_camellia_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_camellia_context ) ); +} + +/* + * Camellia key schedule (encryption) + */ +int mbedtls_camellia_setkey_enc( mbedtls_camellia_context *ctx, const unsigned char *key, + unsigned int keybits ) +{ + int idx; + size_t i; + uint32_t *RK; + unsigned char t[64]; + uint32_t SIGMA[6][2]; + uint32_t KC[16]; + uint32_t TK[20]; + + RK = ctx->rk; + + memset( t, 0, 64 ); + memset( RK, 0, sizeof(ctx->rk) ); + + switch( keybits ) + { + case 128: ctx->nr = 3; idx = 0; break; + case 192: + case 256: ctx->nr = 4; idx = 1; break; + default : return( MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH ); + } + + for( i = 0; i < keybits / 8; ++i ) + t[i] = key[i]; + + if( keybits == 192 ) { + for( i = 0; i < 8; i++ ) + t[24 + i] = ~t[16 + i]; + } + + /* + * Prepare SIGMA values + */ + for( i = 0; i < 6; i++ ) { + GET_UINT32_BE( SIGMA[i][0], SIGMA_CHARS[i], 0 ); + GET_UINT32_BE( SIGMA[i][1], SIGMA_CHARS[i], 4 ); + } + + /* + * Key storage in KC + * Order: KL, KR, KA, KB + */ + memset( KC, 0, sizeof(KC) ); + + /* Store KL, KR */ + for( i = 0; i < 8; i++ ) + GET_UINT32_BE( KC[i], t, i * 4 ); + + /* Generate KA */ + for( i = 0; i < 4; ++i ) + KC[8 + i] = KC[i] ^ KC[4 + i]; + + camellia_feistel( KC + 8, SIGMA[0], KC + 10 ); + camellia_feistel( KC + 10, SIGMA[1], KC + 8 ); + + for( i = 0; i < 4; ++i ) + KC[8 + i] ^= KC[i]; + + camellia_feistel( KC + 8, SIGMA[2], KC + 10 ); + camellia_feistel( KC + 10, SIGMA[3], KC + 8 ); + + if( keybits > 128 ) { + /* Generate KB */ + for( i = 0; i < 4; ++i ) + KC[12 + i] = KC[4 + i] ^ KC[8 + i]; + + camellia_feistel( KC + 12, SIGMA[4], KC + 14 ); + camellia_feistel( KC + 14, SIGMA[5], KC + 12 ); + } + + /* + * Generating subkeys + */ + + /* Manipulating KL */ + SHIFT_AND_PLACE( idx, 0 ); + + /* Manipulating KR */ + if( keybits > 128 ) { + SHIFT_AND_PLACE( idx, 1 ); + } + + /* Manipulating KA */ + SHIFT_AND_PLACE( idx, 2 ); + + /* Manipulating KB */ + if( keybits > 128 ) { + SHIFT_AND_PLACE( idx, 3 ); + } + + /* Do transpositions */ + for( i = 0; i < 20; i++ ) { + if( transposes[idx][i] != -1 ) { + RK[32 + 12 * idx + i] = RK[transposes[idx][i]]; + } + } + + return( 0 ); +} + +/* + * Camellia key schedule (decryption) + */ +int mbedtls_camellia_setkey_dec( mbedtls_camellia_context *ctx, const unsigned char *key, + unsigned int keybits ) +{ + int idx, ret; + size_t i; + mbedtls_camellia_context cty; + uint32_t *RK; + uint32_t *SK; + + mbedtls_camellia_init( &cty ); + + /* Also checks keybits */ + if( ( ret = mbedtls_camellia_setkey_enc( &cty, key, keybits ) ) != 0 ) + goto exit; + + ctx->nr = cty.nr; + idx = ( ctx->nr == 4 ); + + RK = ctx->rk; + SK = cty.rk + 24 * 2 + 8 * idx * 2; + + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + + for( i = 22 + 8 * idx, SK -= 6; i > 0; i--, SK -= 4 ) + { + *RK++ = *SK++; + *RK++ = *SK++; + } + + SK -= 2; + + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + +exit: + mbedtls_camellia_free( &cty ); + + return( ret ); +} + +/* + * Camellia-ECB block encryption/decryption + */ +int mbedtls_camellia_crypt_ecb( mbedtls_camellia_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ) +{ + int NR; + uint32_t *RK, X[4]; + + ( (void) mode ); + + NR = ctx->nr; + RK = ctx->rk; + + GET_UINT32_BE( X[0], input, 0 ); + GET_UINT32_BE( X[1], input, 4 ); + GET_UINT32_BE( X[2], input, 8 ); + GET_UINT32_BE( X[3], input, 12 ); + + X[0] ^= *RK++; + X[1] ^= *RK++; + X[2] ^= *RK++; + X[3] ^= *RK++; + + while( NR ) { + --NR; + camellia_feistel( X, RK, X + 2 ); + RK += 2; + camellia_feistel( X + 2, RK, X ); + RK += 2; + camellia_feistel( X, RK, X + 2 ); + RK += 2; + camellia_feistel( X + 2, RK, X ); + RK += 2; + camellia_feistel( X, RK, X + 2 ); + RK += 2; + camellia_feistel( X + 2, RK, X ); + RK += 2; + + if( NR ) { + FL(X[0], X[1], RK[0], RK[1]); + RK += 2; + FLInv(X[2], X[3], RK[0], RK[1]); + RK += 2; + } + } + + X[2] ^= *RK++; + X[3] ^= *RK++; + X[0] ^= *RK++; + X[1] ^= *RK++; + + PUT_UINT32_BE( X[2], output, 0 ); + PUT_UINT32_BE( X[3], output, 4 ); + PUT_UINT32_BE( X[0], output, 8 ); + PUT_UINT32_BE( X[1], output, 12 ); + + return( 0 ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/* + * Camellia-CBC buffer encryption/decryption + */ +int mbedtls_camellia_crypt_cbc( mbedtls_camellia_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[16]; + + if( length % 16 ) + return( MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH ); + + if( mode == MBEDTLS_CAMELLIA_DECRYPT ) + { + while( length > 0 ) + { + memcpy( temp, input, 16 ); + mbedtls_camellia_crypt_ecb( ctx, mode, input, output ); + + for( i = 0; i < 16; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 16 ); + + input += 16; + output += 16; + length -= 16; + } + } + else + { + while( length > 0 ) + { + for( i = 0; i < 16; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + mbedtls_camellia_crypt_ecb( ctx, mode, output, output ); + memcpy( iv, output, 16 ); + + input += 16; + output += 16; + length -= 16; + } + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/* + * Camellia-CFB128 buffer encryption/decryption + */ +int mbedtls_camellia_crypt_cfb128( mbedtls_camellia_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int c; + size_t n = *iv_off; + + if( mode == MBEDTLS_CAMELLIA_DECRYPT ) + { + while( length-- ) + { + if( n == 0 ) + mbedtls_camellia_crypt_ecb( ctx, MBEDTLS_CAMELLIA_ENCRYPT, iv, iv ); + + c = *input++; + *output++ = (unsigned char)( c ^ iv[n] ); + iv[n] = (unsigned char) c; + + n = ( n + 1 ) & 0x0F; + } + } + else + { + while( length-- ) + { + if( n == 0 ) + mbedtls_camellia_crypt_ecb( ctx, MBEDTLS_CAMELLIA_ENCRYPT, iv, iv ); + + iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ ); + + n = ( n + 1 ) & 0x0F; + } + } + + *iv_off = n; + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/* + * Camellia-CTR buffer encryption/decryption + */ +int mbedtls_camellia_crypt_ctr( mbedtls_camellia_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ) +{ + int c, i; + size_t n = *nc_off; + + while( length-- ) + { + if( n == 0 ) { + mbedtls_camellia_crypt_ecb( ctx, MBEDTLS_CAMELLIA_ENCRYPT, nonce_counter, + stream_block ); + + for( i = 16; i > 0; i-- ) + if( ++nonce_counter[i - 1] != 0 ) + break; + } + c = *input++; + *output++ = (unsigned char)( c ^ stream_block[n] ); + + n = ( n + 1 ) & 0x0F; + } + + *nc_off = n; + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ +#endif /* !MBEDTLS_CAMELLIA_ALT */ + +#if defined(MBEDTLS_SELF_TEST) + +/* + * Camellia test vectors from: + * + * http://info.isl.ntt.co.jp/crypt/eng/camellia/technology.html: + * http://info.isl.ntt.co.jp/crypt/eng/camellia/dl/cryptrec/intermediate.txt + * http://info.isl.ntt.co.jp/crypt/eng/camellia/dl/cryptrec/t_camellia.txt + * (For each bitlength: Key 0, Nr 39) + */ +#define CAMELLIA_TESTS_ECB 2 + +static const unsigned char camellia_test_ecb_key[3][CAMELLIA_TESTS_ECB][32] = +{ + { + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } + }, + { + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } + }, + { + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } + }, +}; + +static const unsigned char camellia_test_ecb_plain[CAMELLIA_TESTS_ECB][16] = +{ + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + { 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } +}; + +static const unsigned char camellia_test_ecb_cipher[3][CAMELLIA_TESTS_ECB][16] = +{ + { + { 0x67, 0x67, 0x31, 0x38, 0x54, 0x96, 0x69, 0x73, + 0x08, 0x57, 0x06, 0x56, 0x48, 0xea, 0xbe, 0x43 }, + { 0x38, 0x3C, 0x6C, 0x2A, 0xAB, 0xEF, 0x7F, 0xDE, + 0x25, 0xCD, 0x47, 0x0B, 0xF7, 0x74, 0xA3, 0x31 } + }, + { + { 0xb4, 0x99, 0x34, 0x01, 0xb3, 0xe9, 0x96, 0xf8, + 0x4e, 0xe5, 0xce, 0xe7, 0xd7, 0x9b, 0x09, 0xb9 }, + { 0xD1, 0x76, 0x3F, 0xC0, 0x19, 0xD7, 0x7C, 0xC9, + 0x30, 0xBF, 0xF2, 0xA5, 0x6F, 0x7C, 0x93, 0x64 } + }, + { + { 0x9a, 0xcc, 0x23, 0x7d, 0xff, 0x16, 0xd7, 0x6c, + 0x20, 0xef, 0x7c, 0x91, 0x9e, 0x3a, 0x75, 0x09 }, + { 0x05, 0x03, 0xFB, 0x10, 0xAB, 0x24, 0x1E, 0x7C, + 0xF4, 0x5D, 0x8C, 0xDE, 0xEE, 0x47, 0x43, 0x35 } + } +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#define CAMELLIA_TESTS_CBC 3 + +static const unsigned char camellia_test_cbc_key[3][32] = +{ + { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, + 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C } + , + { 0x8E, 0x73, 0xB0, 0xF7, 0xDA, 0x0E, 0x64, 0x52, + 0xC8, 0x10, 0xF3, 0x2B, 0x80, 0x90, 0x79, 0xE5, + 0x62, 0xF8, 0xEA, 0xD2, 0x52, 0x2C, 0x6B, 0x7B } + , + { 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE, + 0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81, + 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7, + 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4 } +}; + +static const unsigned char camellia_test_cbc_iv[16] = + + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F } +; + +static const unsigned char camellia_test_cbc_plain[CAMELLIA_TESTS_CBC][16] = +{ + { 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, + 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A }, + { 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C, + 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51 }, + { 0x30, 0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11, + 0xE5, 0xFB, 0xC1, 0x19, 0x1A, 0x0A, 0x52, 0xEF } + +}; + +static const unsigned char camellia_test_cbc_cipher[3][CAMELLIA_TESTS_CBC][16] = +{ + { + { 0x16, 0x07, 0xCF, 0x49, 0x4B, 0x36, 0xBB, 0xF0, + 0x0D, 0xAE, 0xB0, 0xB5, 0x03, 0xC8, 0x31, 0xAB }, + { 0xA2, 0xF2, 0xCF, 0x67, 0x16, 0x29, 0xEF, 0x78, + 0x40, 0xC5, 0xA5, 0xDF, 0xB5, 0x07, 0x48, 0x87 }, + { 0x0F, 0x06, 0x16, 0x50, 0x08, 0xCF, 0x8B, 0x8B, + 0x5A, 0x63, 0x58, 0x63, 0x62, 0x54, 0x3E, 0x54 } + }, + { + { 0x2A, 0x48, 0x30, 0xAB, 0x5A, 0xC4, 0xA1, 0xA2, + 0x40, 0x59, 0x55, 0xFD, 0x21, 0x95, 0xCF, 0x93 }, + { 0x5D, 0x5A, 0x86, 0x9B, 0xD1, 0x4C, 0xE5, 0x42, + 0x64, 0xF8, 0x92, 0xA6, 0xDD, 0x2E, 0xC3, 0xD5 }, + { 0x37, 0xD3, 0x59, 0xC3, 0x34, 0x98, 0x36, 0xD8, + 0x84, 0xE3, 0x10, 0xAD, 0xDF, 0x68, 0xC4, 0x49 } + }, + { + { 0xE6, 0xCF, 0xA3, 0x5F, 0xC0, 0x2B, 0x13, 0x4A, + 0x4D, 0x2C, 0x0B, 0x67, 0x37, 0xAC, 0x3E, 0xDA }, + { 0x36, 0xCB, 0xEB, 0x73, 0xBD, 0x50, 0x4B, 0x40, + 0x70, 0xB1, 0xB7, 0xDE, 0x2B, 0x21, 0xEB, 0x50 }, + { 0xE3, 0x1A, 0x60, 0x55, 0x29, 0x7D, 0x96, 0xCA, + 0x33, 0x30, 0xCD, 0xF1, 0xB1, 0x86, 0x0A, 0x83 } + } +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/* + * Camellia-CTR test vectors from: + * + * http://www.faqs.org/rfcs/rfc5528.html + */ + +static const unsigned char camellia_test_ctr_key[3][16] = +{ + { 0xAE, 0x68, 0x52, 0xF8, 0x12, 0x10, 0x67, 0xCC, + 0x4B, 0xF7, 0xA5, 0x76, 0x55, 0x77, 0xF3, 0x9E }, + { 0x7E, 0x24, 0x06, 0x78, 0x17, 0xFA, 0xE0, 0xD7, + 0x43, 0xD6, 0xCE, 0x1F, 0x32, 0x53, 0x91, 0x63 }, + { 0x76, 0x91, 0xBE, 0x03, 0x5E, 0x50, 0x20, 0xA8, + 0xAC, 0x6E, 0x61, 0x85, 0x29, 0xF9, 0xA0, 0xDC } +}; + +static const unsigned char camellia_test_ctr_nonce_counter[3][16] = +{ + { 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, + { 0x00, 0x6C, 0xB6, 0xDB, 0xC0, 0x54, 0x3B, 0x59, + 0xDA, 0x48, 0xD9, 0x0B, 0x00, 0x00, 0x00, 0x01 }, + { 0x00, 0xE0, 0x01, 0x7B, 0x27, 0x77, 0x7F, 0x3F, + 0x4A, 0x17, 0x86, 0xF0, 0x00, 0x00, 0x00, 0x01 } +}; + +static const unsigned char camellia_test_ctr_pt[3][48] = +{ + { 0x53, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x62, + 0x6C, 0x6F, 0x63, 0x6B, 0x20, 0x6D, 0x73, 0x67 }, + + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F }, + + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23 } +}; + +static const unsigned char camellia_test_ctr_ct[3][48] = +{ + { 0xD0, 0x9D, 0xC2, 0x9A, 0x82, 0x14, 0x61, 0x9A, + 0x20, 0x87, 0x7C, 0x76, 0xDB, 0x1F, 0x0B, 0x3F }, + { 0xDB, 0xF3, 0xC7, 0x8D, 0xC0, 0x83, 0x96, 0xD4, + 0xDA, 0x7C, 0x90, 0x77, 0x65, 0xBB, 0xCB, 0x44, + 0x2B, 0x8E, 0x8E, 0x0F, 0x31, 0xF0, 0xDC, 0xA7, + 0x2C, 0x74, 0x17, 0xE3, 0x53, 0x60, 0xE0, 0x48 }, + { 0xB1, 0x9D, 0x1F, 0xCD, 0xCB, 0x75, 0xEB, 0x88, + 0x2F, 0x84, 0x9C, 0xE2, 0x4D, 0x85, 0xCF, 0x73, + 0x9C, 0xE6, 0x4B, 0x2B, 0x5C, 0x9D, 0x73, 0xF1, + 0x4F, 0x2D, 0x5D, 0x9D, 0xCE, 0x98, 0x89, 0xCD, + 0xDF, 0x50, 0x86, 0x96 } +}; + +static const int camellia_test_ctr_len[3] = + { 16, 32, 36 }; +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +/* + * Checkup routine + */ +int mbedtls_camellia_self_test( int verbose ) +{ + int i, j, u, v; + unsigned char key[32]; + unsigned char buf[64]; + unsigned char src[16]; + unsigned char dst[16]; +#if defined(MBEDTLS_CIPHER_MODE_CBC) + unsigned char iv[16]; +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + size_t offset, len; + unsigned char nonce_counter[16]; + unsigned char stream_block[16]; +#endif + + mbedtls_camellia_context ctx; + + memset( key, 0, 32 ); + + for( j = 0; j < 6; j++ ) { + u = j >> 1; + v = j & 1; + + if( verbose != 0 ) + mbedtls_printf( " CAMELLIA-ECB-%3d (%s): ", 128 + u * 64, + (v == MBEDTLS_CAMELLIA_DECRYPT) ? "dec" : "enc"); + + for( i = 0; i < CAMELLIA_TESTS_ECB; i++ ) { + memcpy( key, camellia_test_ecb_key[u][i], 16 + 8 * u ); + + if( v == MBEDTLS_CAMELLIA_DECRYPT ) { + mbedtls_camellia_setkey_dec( &ctx, key, 128 + u * 64 ); + memcpy( src, camellia_test_ecb_cipher[u][i], 16 ); + memcpy( dst, camellia_test_ecb_plain[i], 16 ); + } else { /* MBEDTLS_CAMELLIA_ENCRYPT */ + mbedtls_camellia_setkey_enc( &ctx, key, 128 + u * 64 ); + memcpy( src, camellia_test_ecb_plain[i], 16 ); + memcpy( dst, camellia_test_ecb_cipher[u][i], 16 ); + } + + mbedtls_camellia_crypt_ecb( &ctx, v, src, buf ); + + if( memcmp( buf, dst, 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + /* + * CBC mode + */ + for( j = 0; j < 6; j++ ) + { + u = j >> 1; + v = j & 1; + + if( verbose != 0 ) + mbedtls_printf( " CAMELLIA-CBC-%3d (%s): ", 128 + u * 64, + ( v == MBEDTLS_CAMELLIA_DECRYPT ) ? "dec" : "enc" ); + + memcpy( src, camellia_test_cbc_iv, 16 ); + memcpy( dst, camellia_test_cbc_iv, 16 ); + memcpy( key, camellia_test_cbc_key[u], 16 + 8 * u ); + + if( v == MBEDTLS_CAMELLIA_DECRYPT ) { + mbedtls_camellia_setkey_dec( &ctx, key, 128 + u * 64 ); + } else { + mbedtls_camellia_setkey_enc( &ctx, key, 128 + u * 64 ); + } + + for( i = 0; i < CAMELLIA_TESTS_CBC; i++ ) { + + if( v == MBEDTLS_CAMELLIA_DECRYPT ) { + memcpy( iv , src, 16 ); + memcpy( src, camellia_test_cbc_cipher[u][i], 16 ); + memcpy( dst, camellia_test_cbc_plain[i], 16 ); + } else { /* MBEDTLS_CAMELLIA_ENCRYPT */ + memcpy( iv , dst, 16 ); + memcpy( src, camellia_test_cbc_plain[i], 16 ); + memcpy( dst, camellia_test_cbc_cipher[u][i], 16 ); + } + + mbedtls_camellia_crypt_cbc( &ctx, v, 16, iv, src, buf ); + + if( memcmp( buf, dst, 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +#if defined(MBEDTLS_CIPHER_MODE_CTR) + /* + * CTR mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " CAMELLIA-CTR-128 (%s): ", + ( v == MBEDTLS_CAMELLIA_DECRYPT ) ? "dec" : "enc" ); + + memcpy( nonce_counter, camellia_test_ctr_nonce_counter[u], 16 ); + memcpy( key, camellia_test_ctr_key[u], 16 ); + + offset = 0; + mbedtls_camellia_setkey_enc( &ctx, key, 128 ); + + if( v == MBEDTLS_CAMELLIA_DECRYPT ) + { + len = camellia_test_ctr_len[u]; + memcpy( buf, camellia_test_ctr_ct[u], len ); + + mbedtls_camellia_crypt_ctr( &ctx, len, &offset, nonce_counter, stream_block, + buf, buf ); + + if( memcmp( buf, camellia_test_ctr_pt[u], len ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + } + else + { + len = camellia_test_ctr_len[u]; + memcpy( buf, camellia_test_ctr_pt[u], len ); + + mbedtls_camellia_crypt_ctr( &ctx, len, &offset, nonce_counter, stream_block, + buf, buf ); + + if( memcmp( buf, camellia_test_ctr_ct[u], len ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_CAMELLIA_C */ diff --git a/common/mbedtls/camellia.h b/common/mbedtls/camellia.h new file mode 100644 index 00000000..cb36312b --- /dev/null +++ b/common/mbedtls/camellia.h @@ -0,0 +1,273 @@ +/** + * \file camellia.h + * + * \brief Camellia block cipher + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_CAMELLIA_H +#define MBEDTLS_CAMELLIA_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#define MBEDTLS_CAMELLIA_ENCRYPT 1 +#define MBEDTLS_CAMELLIA_DECRYPT 0 + +#define MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH -0x0024 /**< Invalid key length. */ +#define MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH -0x0026 /**< Invalid data input length. */ +#define MBEDTLS_ERR_CAMELLIA_HW_ACCEL_FAILED -0x0027 /**< Camellia hardware accelerator failed. */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_CAMELLIA_ALT) +// Regular implementation +// + +/** + * \brief CAMELLIA context structure + */ +typedef struct mbedtls_camellia_context +{ + int nr; /*!< number of rounds */ + uint32_t rk[68]; /*!< CAMELLIA round keys */ +} +mbedtls_camellia_context; + +#else /* MBEDTLS_CAMELLIA_ALT */ +#include "camellia_alt.h" +#endif /* MBEDTLS_CAMELLIA_ALT */ + +/** + * \brief Initialize CAMELLIA context + * + * \param ctx CAMELLIA context to be initialized + */ +void mbedtls_camellia_init( mbedtls_camellia_context *ctx ); + +/** + * \brief Clear CAMELLIA context + * + * \param ctx CAMELLIA context to be cleared + */ +void mbedtls_camellia_free( mbedtls_camellia_context *ctx ); + +/** + * \brief CAMELLIA key schedule (encryption) + * + * \param ctx CAMELLIA context to be initialized + * \param key encryption key + * \param keybits must be 128, 192 or 256 + * + * \return 0 if successful, or MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH + */ +int mbedtls_camellia_setkey_enc( mbedtls_camellia_context *ctx, const unsigned char *key, + unsigned int keybits ); + +/** + * \brief CAMELLIA key schedule (decryption) + * + * \param ctx CAMELLIA context to be initialized + * \param key decryption key + * \param keybits must be 128, 192 or 256 + * + * \return 0 if successful, or MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH + */ +int mbedtls_camellia_setkey_dec( mbedtls_camellia_context *ctx, const unsigned char *key, + unsigned int keybits ); + +/** + * \brief CAMELLIA-ECB block encryption/decryption + * + * \param ctx CAMELLIA context + * \param mode MBEDTLS_CAMELLIA_ENCRYPT or MBEDTLS_CAMELLIA_DECRYPT + * \param input 16-byte input block + * \param output 16-byte output block + * + * \return 0 if successful + */ +int mbedtls_camellia_crypt_ecb( mbedtls_camellia_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/** + * \brief CAMELLIA-CBC buffer encryption/decryption + * Length should be a multiple of the block + * size (16 bytes) + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx CAMELLIA context + * \param mode MBEDTLS_CAMELLIA_ENCRYPT or MBEDTLS_CAMELLIA_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful, or + * MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH + */ +int mbedtls_camellia_crypt_cbc( mbedtls_camellia_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/** + * \brief CAMELLIA-CFB128 buffer encryption/decryption + * + * Note: Due to the nature of CFB you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * mbedtls_camellia_setkey_enc() for both MBEDTLS_CAMELLIA_ENCRYPT and CAMELLIE_DECRYPT. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx CAMELLIA context + * \param mode MBEDTLS_CAMELLIA_ENCRYPT or MBEDTLS_CAMELLIA_DECRYPT + * \param length length of the input data + * \param iv_off offset in IV (updated after use) + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful, or + * MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH + */ +int mbedtls_camellia_crypt_cfb128( mbedtls_camellia_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/** + * \brief CAMELLIA-CTR buffer encryption/decryption + * + * Note: Due to the nature of CTR you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * mbedtls_camellia_setkey_enc() for both MBEDTLS_CAMELLIA_ENCRYPT and MBEDTLS_CAMELLIA_DECRYPT. + * + * \warning You must never reuse a nonce value with the same key. Doing so + * would void the encryption for the two messages encrypted with + * the same nonce and key. + * + * There are two common strategies for managing nonces with CTR: + * + * 1. You can handle everything as a single message processed over + * successive calls to this function. In that case, you want to + * set \p nonce_counter and \p nc_off to 0 for the first call, and + * then preserve the values of \p nonce_counter, \p nc_off and \p + * stream_block across calls to this function as they will be + * updated by this function. + * + * With this strategy, you must not encrypt more than 2**128 + * blocks of data with the same key. + * + * 2. You can encrypt separate messages by dividing the \p + * nonce_counter buffer in two areas: the first one used for a + * per-message nonce, handled by yourself, and the second one + * updated by this function internally. + * + * For example, you might reserve the first 12 bytes for the + * per-message nonce, and the last 4 bytes for internal use. In that + * case, before calling this function on a new message you need to + * set the first 12 bytes of \p nonce_counter to your chosen nonce + * value, the last 4 to 0, and \p nc_off to 0 (which will cause \p + * stream_block to be ignored). That way, you can encrypt at most + * 2**96 messages of up to 2**32 blocks each with the same key. + * + * The per-message nonce (or information sufficient to reconstruct + * it) needs to be communicated with the ciphertext and must be unique. + * The recommended way to ensure uniqueness is to use a message + * counter. An alternative is to generate random nonces, but this + * limits the number of messages that can be securely encrypted: + * for example, with 96-bit random nonces, you should not encrypt + * more than 2**32 messages with the same key. + * + * Note that for both stategies, sizes are measured in blocks and + * that a CAMELLIA block is 16 bytes. + * + * \warning Upon return, \p stream_block contains sensitive data. Its + * content must not be written to insecure storage and should be + * securely discarded as soon as it's no longer needed. + * + * \param ctx CAMELLIA context + * \param length The length of the data + * \param nc_off The offset in the current stream_block (for resuming + * within current cipher stream). The offset pointer to + * should be 0 at the start of a stream. + * \param nonce_counter The 128-bit nonce and counter. + * \param stream_block The saved stream-block for resuming. Is overwritten + * by the function. + * \param input The input data stream + * \param output The output data stream + * + * \return 0 if successful + */ +int mbedtls_camellia_crypt_ctr( mbedtls_camellia_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_camellia_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* camellia.h */ diff --git a/common/mbedtls/certs.c b/common/mbedtls/certs.c new file mode 100644 index 00000000..dd9d02ba --- /dev/null +++ b/common/mbedtls/certs.c @@ -0,0 +1,405 @@ +/* + * X.509 test certificates + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "mbedtls/certs.h" + +#if defined(MBEDTLS_CERTS_C) + +#if defined(MBEDTLS_ECDSA_C) +#define TEST_CA_CRT_EC \ +"-----BEGIN CERTIFICATE-----\r\n" \ +"MIICUjCCAdegAwIBAgIJAMFD4n5iQ8zoMAoGCCqGSM49BAMCMD4xCzAJBgNVBAYT\r\n" \ +"Ak5MMREwDwYDVQQKEwhQb2xhclNTTDEcMBoGA1UEAxMTUG9sYXJzc2wgVGVzdCBF\r\n" \ +"QyBDQTAeFw0xMzA5MjQxNTQ5NDhaFw0yMzA5MjIxNTQ5NDhaMD4xCzAJBgNVBAYT\r\n" \ +"Ak5MMREwDwYDVQQKEwhQb2xhclNTTDEcMBoGA1UEAxMTUG9sYXJzc2wgVGVzdCBF\r\n" \ +"QyBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IABMPaKzRBN1gvh1b+/Im6KUNLTuBu\r\n" \ +"ww5XUzM5WNRStJGVOQsj318XJGJI/BqVKc4sLYfCiFKAr9ZqqyHduNMcbli4yuiy\r\n" \ +"aY7zQa0pw7RfdadHb9UZKVVpmlM7ILRmFmAzHqOBoDCBnTAdBgNVHQ4EFgQUnW0g\r\n" \ +"JEkBPyvLeLUZvH4kydv7NnwwbgYDVR0jBGcwZYAUnW0gJEkBPyvLeLUZvH4kydv7\r\n" \ +"NnyhQqRAMD4xCzAJBgNVBAYTAk5MMREwDwYDVQQKEwhQb2xhclNTTDEcMBoGA1UE\r\n" \ +"AxMTUG9sYXJzc2wgVGVzdCBFQyBDQYIJAMFD4n5iQ8zoMAwGA1UdEwQFMAMBAf8w\r\n" \ +"CgYIKoZIzj0EAwIDaQAwZgIxAMO0YnNWKJUAfXgSJtJxexn4ipg+kv4znuR50v56\r\n" \ +"t4d0PCu412mUC6Nnd7izvtE2MgIxAP1nnJQjZ8BWukszFQDG48wxCCyci9qpdSMv\r\n" \ +"uCjn8pwUOkABXK8Mss90fzCfCEOtIA==\r\n" \ +"-----END CERTIFICATE-----\r\n" +const char mbedtls_test_ca_crt_ec[] = TEST_CA_CRT_EC; +const size_t mbedtls_test_ca_crt_ec_len = sizeof( mbedtls_test_ca_crt_ec ); + +const char mbedtls_test_ca_key_ec[] = +"-----BEGIN EC PRIVATE KEY-----\r\n" +"Proc-Type: 4,ENCRYPTED\r\n" +"DEK-Info: DES-EDE3-CBC,307EAB469933D64E\r\n" +"\r\n" +"IxbrRmKcAzctJqPdTQLA4SWyBYYGYJVkYEna+F7Pa5t5Yg/gKADrFKcm6B72e7DG\r\n" +"ihExtZI648s0zdYw6qSJ74vrPSuWDe5qm93BqsfVH9svtCzWHW0pm1p0KTBCFfUq\r\n" +"UsuWTITwJImcnlAs1gaRZ3sAWm7cOUidL0fo2G0fYUFNcYoCSLffCFTEHBuPnagb\r\n" +"a77x/sY1Bvii8S9/XhDTb6pTMx06wzrm\r\n" +"-----END EC PRIVATE KEY-----\r\n"; +const size_t mbedtls_test_ca_key_ec_len = sizeof( mbedtls_test_ca_key_ec ); + +const char mbedtls_test_ca_pwd_ec[] = "PolarSSLTest"; +const size_t mbedtls_test_ca_pwd_ec_len = sizeof( mbedtls_test_ca_pwd_ec ) - 1; + +const char mbedtls_test_srv_crt_ec[] = +"-----BEGIN CERTIFICATE-----\r\n" +"MIICHzCCAaWgAwIBAgIBCTAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJOTDERMA8G\r\n" +"A1UEChMIUG9sYXJTU0wxHDAaBgNVBAMTE1BvbGFyc3NsIFRlc3QgRUMgQ0EwHhcN\r\n" +"MTMwOTI0MTU1MjA0WhcNMjMwOTIyMTU1MjA0WjA0MQswCQYDVQQGEwJOTDERMA8G\r\n" +"A1UEChMIUG9sYXJTU0wxEjAQBgNVBAMTCWxvY2FsaG9zdDBZMBMGByqGSM49AgEG\r\n" +"CCqGSM49AwEHA0IABDfMVtl2CR5acj7HWS3/IG7ufPkGkXTQrRS192giWWKSTuUA\r\n" +"2CMR/+ov0jRdXRa9iojCa3cNVc2KKg76Aci07f+jgZ0wgZowCQYDVR0TBAIwADAd\r\n" +"BgNVHQ4EFgQUUGGlj9QH2deCAQzlZX+MY0anE74wbgYDVR0jBGcwZYAUnW0gJEkB\r\n" +"PyvLeLUZvH4kydv7NnyhQqRAMD4xCzAJBgNVBAYTAk5MMREwDwYDVQQKEwhQb2xh\r\n" +"clNTTDEcMBoGA1UEAxMTUG9sYXJzc2wgVGVzdCBFQyBDQYIJAMFD4n5iQ8zoMAoG\r\n" +"CCqGSM49BAMCA2gAMGUCMQCaLFzXptui5WQN8LlO3ddh1hMxx6tzgLvT03MTVK2S\r\n" +"C12r0Lz3ri/moSEpNZWqPjkCMCE2f53GXcYLqyfyJR078c/xNSUU5+Xxl7VZ414V\r\n" +"fGa5kHvHARBPc8YAIVIqDvHH1Q==\r\n" +"-----END CERTIFICATE-----\r\n"; +const size_t mbedtls_test_srv_crt_ec_len = sizeof( mbedtls_test_srv_crt_ec ); + +const char mbedtls_test_srv_key_ec[] = +"-----BEGIN EC PRIVATE KEY-----\r\n" +"MHcCAQEEIPEqEyB2AnCoPL/9U/YDHvdqXYbIogTywwyp6/UfDw6noAoGCCqGSM49\r\n" +"AwEHoUQDQgAEN8xW2XYJHlpyPsdZLf8gbu58+QaRdNCtFLX3aCJZYpJO5QDYIxH/\r\n" +"6i/SNF1dFr2KiMJrdw1VzYoqDvoByLTt/w==\r\n" +"-----END EC PRIVATE KEY-----\r\n"; +const size_t mbedtls_test_srv_key_ec_len = sizeof( mbedtls_test_srv_key_ec ); + +const char mbedtls_test_cli_crt_ec[] = +"-----BEGIN CERTIFICATE-----\r\n" +"MIICLDCCAbKgAwIBAgIBDTAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJOTDERMA8G\r\n" +"A1UEChMIUG9sYXJTU0wxHDAaBgNVBAMTE1BvbGFyc3NsIFRlc3QgRUMgQ0EwHhcN\r\n" +"MTMwOTI0MTU1MjA0WhcNMjMwOTIyMTU1MjA0WjBBMQswCQYDVQQGEwJOTDERMA8G\r\n" +"A1UEChMIUG9sYXJTU0wxHzAdBgNVBAMTFlBvbGFyU1NMIFRlc3QgQ2xpZW50IDIw\r\n" +"WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARX5a6xc9/TrLuTuIH/Eq7u5lOszlVT\r\n" +"9jQOzC7jYyUL35ji81xgNpbA1RgUcOV/n9VLRRjlsGzVXPiWj4dwo+THo4GdMIGa\r\n" +"MAkGA1UdEwQCMAAwHQYDVR0OBBYEFHoAX4Zk/OBd5REQO7LmO8QmP8/iMG4GA1Ud\r\n" +"IwRnMGWAFJ1tICRJAT8ry3i1Gbx+JMnb+zZ8oUKkQDA+MQswCQYDVQQGEwJOTDER\r\n" +"MA8GA1UEChMIUG9sYXJTU0wxHDAaBgNVBAMTE1BvbGFyc3NsIFRlc3QgRUMgQ0GC\r\n" +"CQDBQ+J+YkPM6DAKBggqhkjOPQQDAgNoADBlAjBKZQ17IIOimbmoD/yN7o89u3BM\r\n" +"lgOsjnhw3fIOoLIWy2WOGsk/LGF++DzvrRzuNiACMQCd8iem1XS4JK7haj8xocpU\r\n" +"LwjQje5PDGHfd3h9tP38Qknu5bJqws0md2KOKHyeV0U=\r\n" +"-----END CERTIFICATE-----\r\n"; +const size_t mbedtls_test_cli_crt_ec_len = sizeof( mbedtls_test_cli_crt_ec ); + +const char mbedtls_test_cli_key_ec[] = +"-----BEGIN EC PRIVATE KEY-----\r\n" +"MHcCAQEEIPb3hmTxZ3/mZI3vyk7p3U3wBf+WIop6hDhkFzJhmLcqoAoGCCqGSM49\r\n" +"AwEHoUQDQgAEV+WusXPf06y7k7iB/xKu7uZTrM5VU/Y0Dswu42MlC9+Y4vNcYDaW\r\n" +"wNUYFHDlf5/VS0UY5bBs1Vz4lo+HcKPkxw==\r\n" +"-----END EC PRIVATE KEY-----\r\n"; +const size_t mbedtls_test_cli_key_ec_len = sizeof( mbedtls_test_cli_key_ec ); +#endif /* MBEDTLS_ECDSA_C */ + +#if defined(MBEDTLS_RSA_C) + +#if defined(MBEDTLS_SHA256_C) +#define TEST_CA_CRT_RSA_SHA256 \ +"-----BEGIN CERTIFICATE-----\r\n" \ +"MIIDhzCCAm+gAwIBAgIBADANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER\r\n" \ +"MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n" \ +"MTcwNTA0MTY1NzAxWhcNMjcwNTA1MTY1NzAxWjA7MQswCQYDVQQGEwJOTDERMA8G\r\n" \ +"A1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwggEiMA0G\r\n" \ +"CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDA3zf8F7vglp0/ht6WMn1EpRagzSHx\r\n" \ +"mdTs6st8GFgIlKXsm8WL3xoemTiZhx57wI053zhdcHgH057Zk+i5clHFzqMwUqny\r\n" \ +"50BwFMtEonILwuVA+T7lpg6z+exKY8C4KQB0nFc7qKUEkHHxvYPZP9al4jwqj+8n\r\n" \ +"YMPGn8u67GB9t+aEMr5P+1gmIgNb1LTV+/Xjli5wwOQuvfwu7uJBVcA0Ln0kcmnL\r\n" \ +"R7EUQIN9Z/SG9jGr8XmksrUuEvmEF/Bibyc+E1ixVA0hmnM3oTDPb5Lc9un8rNsu\r\n" \ +"KNF+AksjoBXyOGVkCeoMbo4bF6BxyLObyavpw/LPh5aPgAIynplYb6LVAgMBAAGj\r\n" \ +"gZUwgZIwHQYDVR0OBBYEFLRa5KWz3tJS9rnVppUP6z68x/3/MGMGA1UdIwRcMFqA\r\n" \ +"FLRa5KWz3tJS9rnVppUP6z68x/3/oT+kPTA7MQswCQYDVQQGEwJOTDERMA8GA1UE\r\n" \ +"CgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0GCAQAwDAYDVR0T\r\n" \ +"BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAHK/HHrTZMnnVMpde1io+voAtql7j\r\n" \ +"4sRhLrjD7o3THtwRbDa2diCvpq0Sq23Ng2LMYoXsOxoL/RQK3iN7UKxV3MKPEr0w\r\n" \ +"XQS+kKQqiT2bsfrjnWMVHZtUOMpm6FNqcdGm/Rss3vKda2lcKl8kUnq/ylc1+QbB\r\n" \ +"G6A6tUvQcr2ZyWfVg+mM5XkhTrOOXus2OLikb4WwEtJTJRNE0f+yPODSUz0/vT57\r\n" \ +"ApH0CnB80bYJshYHPHHymOtleAB8KSYtqm75g/YNobjnjB6cm4HkW3OZRVIl6fYY\r\n" \ +"n20NRVA1Vjs6GAROr4NqW4k/+LofY9y0LLDE+p0oIEKXIsIvhPr39swxSA==\r\n" \ +"-----END CERTIFICATE-----\r\n" + +const char mbedtls_test_ca_crt_rsa[] = TEST_CA_CRT_RSA_SHA256; +const size_t mbedtls_test_ca_crt_rsa_len = sizeof( mbedtls_test_ca_crt_rsa ); +#define TEST_CA_CRT_RSA_SOME + +static const char mbedtls_test_ca_crt_rsa_sha256[] = TEST_CA_CRT_RSA_SHA256; + +#endif + +#if !defined(TEST_CA_CRT_RSA_SOME) || defined(MBEDTLS_SHA1_C) +#define TEST_CA_CRT_RSA_SHA1 \ +"-----BEGIN CERTIFICATE-----\r\n" \ +"MIIDhzCCAm+gAwIBAgIBADANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER\r\n" \ +"MA8GA1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n" \ +"MTEwMjEyMTQ0NDAwWhcNMjEwMjEyMTQ0NDAwWjA7MQswCQYDVQQGEwJOTDERMA8G\r\n" \ +"A1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3QgQ0EwggEiMA0G\r\n" \ +"CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDA3zf8F7vglp0/ht6WMn1EpRagzSHx\r\n" \ +"mdTs6st8GFgIlKXsm8WL3xoemTiZhx57wI053zhdcHgH057Zk+i5clHFzqMwUqny\r\n" \ +"50BwFMtEonILwuVA+T7lpg6z+exKY8C4KQB0nFc7qKUEkHHxvYPZP9al4jwqj+8n\r\n" \ +"YMPGn8u67GB9t+aEMr5P+1gmIgNb1LTV+/Xjli5wwOQuvfwu7uJBVcA0Ln0kcmnL\r\n" \ +"R7EUQIN9Z/SG9jGr8XmksrUuEvmEF/Bibyc+E1ixVA0hmnM3oTDPb5Lc9un8rNsu\r\n" \ +"KNF+AksjoBXyOGVkCeoMbo4bF6BxyLObyavpw/LPh5aPgAIynplYb6LVAgMBAAGj\r\n" \ +"gZUwgZIwDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQUtFrkpbPe0lL2udWmlQ/rPrzH\r\n" \ +"/f8wYwYDVR0jBFwwWoAUtFrkpbPe0lL2udWmlQ/rPrzH/f+hP6Q9MDsxCzAJBgNV\r\n" \ +"BAYTAk5MMREwDwYDVQQKEwhQb2xhclNTTDEZMBcGA1UEAxMQUG9sYXJTU0wgVGVz\r\n" \ +"dCBDQYIBADANBgkqhkiG9w0BAQUFAAOCAQEAuP1U2ABUkIslsCfdlc2i94QHHYeJ\r\n" \ +"SsR4EdgHtdciUI5I62J6Mom+Y0dT/7a+8S6MVMCZP6C5NyNyXw1GWY/YR82XTJ8H\r\n" \ +"DBJiCTok5DbZ6SzaONBzdWHXwWwmi5vg1dxn7YxrM9d0IjxM27WNKs4sDQhZBQkF\r\n" \ +"pjmfs2cb4oPl4Y9T9meTx/lvdkRYEug61Jfn6cA+qHpyPYdTH+UshITnmp5/Ztkf\r\n" \ +"m/UTSLBNFNHesiTZeH31NcxYGdHSme9Nc/gfidRa0FLOCfWxRlFqAI47zG9jAQCZ\r\n" \ +"7Z2mCGDNMhjQc+BYcdnl0lPXjdDK6V0qCg1dVewhUBcW5gZKzV7e9+DpVA==\r\n" \ +"-----END CERTIFICATE-----\r\n" + +#if !defined (TEST_CA_CRT_RSA_SOME) +const char mbedtls_test_ca_crt_rsa[] = TEST_CA_CRT_RSA_SHA1; +const size_t mbedtls_test_ca_crt_rsa_len = sizeof( mbedtls_test_ca_crt_rsa ); +#endif + +static const char mbedtls_test_ca_crt_rsa_sha1[] = TEST_CA_CRT_RSA_SHA1; + +#endif + +const char mbedtls_test_ca_key_rsa[] = +"-----BEGIN RSA PRIVATE KEY-----\r\n" +"Proc-Type: 4,ENCRYPTED\r\n" +"DEK-Info: DES-EDE3-CBC,A8A95B05D5B7206B\r\n" +"\r\n" +"9Qd9GeArejl1GDVh2lLV1bHt0cPtfbh5h/5zVpAVaFpqtSPMrElp50Rntn9et+JA\r\n" +"7VOyboR+Iy2t/HU4WvA687k3Bppe9GwKHjHhtl//8xFKwZr3Xb5yO5JUP8AUctQq\r\n" +"Nb8CLlZyuUC+52REAAthdWgsX+7dJO4yabzUcQ22Tp9JSD0hiL43BlkWYUNK3dAo\r\n" +"PZlmiptjnzVTjg1MxsBSydZinWOLBV8/JQgxSPo2yD4uEfig28qbvQ2wNIn0pnAb\r\n" +"GxnSAOazkongEGfvcjIIs+LZN9gXFhxcOh6kc4Q/c99B7QWETwLLkYgZ+z1a9VY9\r\n" +"gEU7CwCxYCD+h9hY6FPmsK0/lC4O7aeRKpYq00rPPxs6i7phiexg6ax6yTMmArQq\r\n" +"QmK3TAsJm8V/J5AWpLEV6jAFgRGymGGHnof0DXzVWZidrcZJWTNuGEX90nB3ee2w\r\n" +"PXJEFWKoD3K3aFcSLdHYr3mLGxP7H9ThQai9VsycxZKS5kwvBKQ//YMrmFfwPk8x\r\n" +"vTeY4KZMaUrveEel5tWZC94RSMKgxR6cyE1nBXyTQnDOGbfpNNgBKxyKbINWoOJU\r\n" +"WJZAwlsQn+QzCDwpri7+sV1mS3gBE6UY7aQmnmiiaC2V3Hbphxct/en5QsfDOt1X\r\n" +"JczSfpRWLlbPznZg8OQh/VgCMA58N5DjOzTIK7sJJ5r+94ZBTCpgAMbF588f0NTR\r\n" +"KCe4yrxGJR7X02M4nvD4IwOlpsQ8xQxZtOSgXv4LkxvdU9XJJKWZ/XNKJeWztxSe\r\n" +"Z1vdTc2YfsDBA2SEv33vxHx2g1vqtw8SjDRT2RaQSS0QuSaMJimdOX6mTOCBKk1J\r\n" +"9Q5mXTrER+/LnK0jEmXsBXWA5bqqVZIyahXSx4VYZ7l7w/PHiUDtDgyRhMMKi4n2\r\n" +"iQvQcWSQTjrpnlJbca1/DkpRt3YwrvJwdqb8asZU2VrNETh5x0QVefDRLFiVpif/\r\n" +"tUaeAe/P1F8OkS7OIZDs1SUbv/sD2vMbhNkUoCms3/PvNtdnvgL4F0zhaDpKCmlT\r\n" +"P8vx49E7v5CyRNmED9zZg4o3wmMqrQO93PtTug3Eu9oVx1zPQM1NVMyBa2+f29DL\r\n" +"1nuTCeXdo9+ni45xx+jAI4DCwrRdhJ9uzZyC6962H37H6D+5naNvClFR1s6li1Gb\r\n" +"nqPoiy/OBsEx9CaDGcqQBp5Wme/3XW+6z1ISOx+igwNTVCT14mHdBMbya0eIKft5\r\n" +"X+GnwtgEMyCYyyWuUct8g4RzErcY9+yW9Om5Hzpx4zOuW4NPZgPDTgK+t2RSL/Yq\r\n" +"rE1njrgeGYcVeG3f+OftH4s6fPbq7t1A5ZgUscbLMBqr9tK+OqygR4EgKBPsH6Cz\r\n" +"L6zlv/2RV0qAHvVuDJcIDIgwY5rJtINEm32rhOeFNJwZS5MNIC1czXZx5//ugX7l\r\n" +"I4sy5nbVhwSjtAk8Xg5dZbdTZ6mIrb7xqH+fdakZor1khG7bC2uIwibD3cSl2XkR\r\n" +"wN48lslbHnqqagr6Xm1nNOSVl8C/6kbJEsMpLhAezfRtGwvOucoaE+WbeUNolGde\r\n" +"P/eQiddSf0brnpiLJRh7qZrl9XuqYdpUqnoEdMAfotDOID8OtV7gt8a48ad8VPW2\r\n" +"-----END RSA PRIVATE KEY-----\r\n"; +const size_t mbedtls_test_ca_key_rsa_len = sizeof( mbedtls_test_ca_key_rsa ); + +const char mbedtls_test_ca_pwd_rsa[] = "PolarSSLTest"; +const size_t mbedtls_test_ca_pwd_rsa_len = sizeof( mbedtls_test_ca_pwd_rsa ) - 1; + +const char mbedtls_test_srv_crt_rsa[] = +"-----BEGIN CERTIFICATE-----\r\n" +"MIIDNzCCAh+gAwIBAgIBAjANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER\r\n" +"MA8GA1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n" +"MTEwMjEyMTQ0NDA2WhcNMjEwMjEyMTQ0NDA2WjA0MQswCQYDVQQGEwJOTDERMA8G\r\n" +"A1UEChMIUG9sYXJTU0wxEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcN\r\n" +"AQEBBQADggEPADCCAQoCggEBAMFNo93nzR3RBNdJcriZrA545Do8Ss86ExbQWuTN\r\n" +"owCIp+4ea5anUrSQ7y1yej4kmvy2NKwk9XfgJmSMnLAofaHa6ozmyRyWvP7BBFKz\r\n" +"NtSj+uGxdtiQwWG0ZlI2oiZTqqt0Xgd9GYLbKtgfoNkNHC1JZvdbJXNG6AuKT2kM\r\n" +"tQCQ4dqCEGZ9rlQri2V5kaHiYcPNQEkI7mgM8YuG0ka/0LiqEQMef1aoGh5EGA8P\r\n" +"hYvai0Re4hjGYi/HZo36Xdh98yeJKQHFkA4/J/EwyEoO79bex8cna8cFPXrEAjya\r\n" +"HT4P6DSYW8tzS1KW2BGiLICIaTla0w+w3lkvEcf36hIBMJcCAwEAAaNNMEswCQYD\r\n" +"VR0TBAIwADAdBgNVHQ4EFgQUpQXoZLjc32APUBJNYKhkr02LQ5MwHwYDVR0jBBgw\r\n" +"FoAUtFrkpbPe0lL2udWmlQ/rPrzH/f8wDQYJKoZIhvcNAQEFBQADggEBAJxnXClY\r\n" +"oHkbp70cqBrsGXLybA74czbO5RdLEgFs7rHVS9r+c293luS/KdliLScZqAzYVylw\r\n" +"UfRWvKMoWhHYKp3dEIS4xTXk6/5zXxhv9Rw8SGc8qn6vITHk1S1mPevtekgasY5Y\r\n" +"iWQuM3h4YVlRH3HHEMAD1TnAexfXHHDFQGe+Bd1iAbz1/sH9H8l4StwX6egvTK3M\r\n" +"wXRwkKkvjKaEDA9ATbZx0mI8LGsxSuCqe9r9dyjmttd47J1p1Rulz3CLzaRcVIuS\r\n" +"RRQfaD8neM9c1S/iJ/amTVqJxA1KOdOS5780WhPfSArA+g4qAmSjelc3p4wWpha8\r\n" +"zhuYwjVuX6JHG0c=\r\n" +"-----END CERTIFICATE-----\r\n"; +const size_t mbedtls_test_srv_crt_rsa_len = sizeof( mbedtls_test_srv_crt_rsa ); + +const char mbedtls_test_srv_key_rsa[] = +"-----BEGIN RSA PRIVATE KEY-----\r\n" +"MIIEpAIBAAKCAQEAwU2j3efNHdEE10lyuJmsDnjkOjxKzzoTFtBa5M2jAIin7h5r\r\n" +"lqdStJDvLXJ6PiSa/LY0rCT1d+AmZIycsCh9odrqjObJHJa8/sEEUrM21KP64bF2\r\n" +"2JDBYbRmUjaiJlOqq3ReB30Zgtsq2B+g2Q0cLUlm91slc0boC4pPaQy1AJDh2oIQ\r\n" +"Zn2uVCuLZXmRoeJhw81ASQjuaAzxi4bSRr/QuKoRAx5/VqgaHkQYDw+Fi9qLRF7i\r\n" +"GMZiL8dmjfpd2H3zJ4kpAcWQDj8n8TDISg7v1t7HxydrxwU9esQCPJodPg/oNJhb\r\n" +"y3NLUpbYEaIsgIhpOVrTD7DeWS8Rx/fqEgEwlwIDAQABAoIBAQCXR0S8EIHFGORZ\r\n" +"++AtOg6eENxD+xVs0f1IeGz57Tjo3QnXX7VBZNdj+p1ECvhCE/G7XnkgU5hLZX+G\r\n" +"Z0jkz/tqJOI0vRSdLBbipHnWouyBQ4e/A1yIJdlBtqXxJ1KE/ituHRbNc4j4kL8Z\r\n" +"/r6pvwnTI0PSx2Eqs048YdS92LT6qAv4flbNDxMn2uY7s4ycS4Q8w1JXnCeaAnYm\r\n" +"WYI5wxO+bvRELR2Mcz5DmVnL8jRyml6l6582bSv5oufReFIbyPZbQWlXgYnpu6He\r\n" +"GTc7E1zKYQGG/9+DQUl/1vQuCPqQwny0tQoX2w5tdYpdMdVm+zkLtbajzdTviJJa\r\n" +"TWzL6lt5AoGBAN86+SVeJDcmQJcv4Eq6UhtRr4QGMiQMz0Sod6ettYxYzMgxtw28\r\n" +"CIrgpozCc+UaZJLo7UxvC6an85r1b2nKPCLQFaggJ0H4Q0J/sZOhBIXaoBzWxveK\r\n" +"nupceKdVxGsFi8CDy86DBfiyFivfBj+47BbaQzPBj7C4rK7UlLjab2rDAoGBAN2u\r\n" +"AM2gchoFiu4v1HFL8D7lweEpi6ZnMJjnEu/dEgGQJFjwdpLnPbsj4c75odQ4Gz8g\r\n" +"sw9lao9VVzbusoRE/JGI4aTdO0pATXyG7eG1Qu+5Yc1YGXcCrliA2xM9xx+d7f+s\r\n" +"mPzN+WIEg5GJDYZDjAzHG5BNvi/FfM1C9dOtjv2dAoGAF0t5KmwbjWHBhcVqO4Ic\r\n" +"BVvN3BIlc1ue2YRXEDlxY5b0r8N4XceMgKmW18OHApZxfl8uPDauWZLXOgl4uepv\r\n" +"whZC3EuWrSyyICNhLY21Ah7hbIEBPF3L3ZsOwC+UErL+dXWLdB56Jgy3gZaBeW7b\r\n" +"vDrEnocJbqCm7IukhXHOBK8CgYEAwqdHB0hqyNSzIOGY7v9abzB6pUdA3BZiQvEs\r\n" +"3LjHVd4HPJ2x0N8CgrBIWOE0q8+0hSMmeE96WW/7jD3fPWwCR5zlXknxBQsfv0gP\r\n" +"3BC5PR0Qdypz+d+9zfMf625kyit4T/hzwhDveZUzHnk1Cf+IG7Q+TOEnLnWAWBED\r\n" +"ISOWmrUCgYAFEmRxgwAc/u+D6t0syCwAYh6POtscq9Y0i9GyWk89NzgC4NdwwbBH\r\n" +"4AgahOxIxXx2gxJnq3yfkJfIjwf0s2DyP0kY2y6Ua1OeomPeY9mrIS4tCuDQ6LrE\r\n" +"TB6l9VGoxJL4fyHnZb8L5gGvnB1bbD8cL6YPaDiOhcRseC9vBiEuVg==\r\n" +"-----END RSA PRIVATE KEY-----\r\n"; +const size_t mbedtls_test_srv_key_rsa_len = sizeof( mbedtls_test_srv_key_rsa ); + +const char mbedtls_test_cli_crt_rsa[] = +"-----BEGIN CERTIFICATE-----\r\n" +"MIIDhTCCAm2gAwIBAgIBBDANBgkqhkiG9w0BAQsFADA7MQswCQYDVQQGEwJOTDER\r\n" +"MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n" +"MTcwNTA1MTMwNzU5WhcNMjcwNTA2MTMwNzU5WjA8MQswCQYDVQQGEwJOTDERMA8G\r\n" +"A1UECgwIUG9sYXJTU0wxGjAYBgNVBAMMEVBvbGFyU1NMIENsaWVudCAyMIIBIjAN\r\n" +"BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyHTEzLn5tXnpRdkUYLB9u5Pyax6f\r\n" +"M60Nj4o8VmXl3ETZzGaFB9X4J7BKNdBjngpuG7fa8H6r7gwQk4ZJGDTzqCrSV/Uu\r\n" +"1C93KYRhTYJQj6eVSHD1bk2y1RPD0hrt5kPqQhTrdOrA7R/UV06p86jt0uDBMHEw\r\n" +"MjDV0/YI0FZPRo7yX/k9Z5GIMC5Cst99++UMd//sMcB4j7/Cf8qtbCHWjdmLao5v\r\n" +"4Jv4EFbMs44TFeY0BGbH7vk2DmqV9gmaBmf0ZXH4yqSxJeD+PIs1BGe64E92hfx/\r\n" +"/DZrtenNLQNiTrM9AM+vdqBpVoNq0qjU51Bx5rU2BXcFbXvI5MT9TNUhXwIDAQAB\r\n" +"o4GSMIGPMB0GA1UdDgQWBBRxoQBzckAvVHZeM/xSj7zx3WtGITBjBgNVHSMEXDBa\r\n" +"gBS0WuSls97SUva51aaVD+s+vMf9/6E/pD0wOzELMAkGA1UEBhMCTkwxETAPBgNV\r\n" +"BAoMCFBvbGFyU1NMMRkwFwYDVQQDDBBQb2xhclNTTCBUZXN0IENBggEAMAkGA1Ud\r\n" +"EwQCMAAwDQYJKoZIhvcNAQELBQADggEBAC7yO786NvcHpK8UovKIG9cB32oSQQom\r\n" +"LoR0eHDRzdqEkoq7yGZufHFiRAAzbMqJfogRtxlrWAeB4y/jGaMBV25IbFOIcH2W\r\n" +"iCEaMMbG+VQLKNvuC63kmw/Zewc9ThM6Pa1Hcy0axT0faf1B/U01j0FIcw/6mTfK\r\n" +"D8w48OIwc1yr0JtutCVjig5DC0yznGMt32RyseOLcUe+lfq005v2PAiCozr5X8rE\r\n" +"ofGZpiM2NqRPePgYy+Vc75Zk28xkRQq1ncprgQb3S4vTsZdScpM9hLf+eMlrgqlj\r\n" +"c5PLSkXBeLE5+fedkyfTaLxxQlgCpuoOhKBm04/R1pWNzUHyqagjO9Q=\r\n" +"-----END CERTIFICATE-----\r\n"; +const size_t mbedtls_test_cli_crt_rsa_len = sizeof( mbedtls_test_cli_crt_rsa ); + +const char mbedtls_test_cli_key_rsa[] = +"-----BEGIN RSA PRIVATE KEY-----\r\n" +"MIIEpAIBAAKCAQEAyHTEzLn5tXnpRdkUYLB9u5Pyax6fM60Nj4o8VmXl3ETZzGaF\r\n" +"B9X4J7BKNdBjngpuG7fa8H6r7gwQk4ZJGDTzqCrSV/Uu1C93KYRhTYJQj6eVSHD1\r\n" +"bk2y1RPD0hrt5kPqQhTrdOrA7R/UV06p86jt0uDBMHEwMjDV0/YI0FZPRo7yX/k9\r\n" +"Z5GIMC5Cst99++UMd//sMcB4j7/Cf8qtbCHWjdmLao5v4Jv4EFbMs44TFeY0BGbH\r\n" +"7vk2DmqV9gmaBmf0ZXH4yqSxJeD+PIs1BGe64E92hfx//DZrtenNLQNiTrM9AM+v\r\n" +"dqBpVoNq0qjU51Bx5rU2BXcFbXvI5MT9TNUhXwIDAQABAoIBAGdNtfYDiap6bzst\r\n" +"yhCiI8m9TtrhZw4MisaEaN/ll3XSjaOG2dvV6xMZCMV+5TeXDHOAZnY18Yi18vzz\r\n" +"4Ut2TnNFzizCECYNaA2fST3WgInnxUkV3YXAyP6CNxJaCmv2aA0yFr2kFVSeaKGt\r\n" +"ymvljNp2NVkvm7Th8fBQBO7I7AXhz43k0mR7XmPgewe8ApZOG3hstkOaMvbWAvWA\r\n" +"zCZupdDjZYjOJqlA4eEA4H8/w7F83r5CugeBE8LgEREjLPiyejrU5H1fubEY+h0d\r\n" +"l5HZBJ68ybTXfQ5U9o/QKA3dd0toBEhhdRUDGzWtjvwkEQfqF1reGWj/tod/gCpf\r\n" +"DFi6X0ECgYEA4wOv/pjSC3ty6TuOvKX2rOUiBrLXXv2JSxZnMoMiWI5ipLQt+RYT\r\n" +"VPafL/m7Dn6MbwjayOkcZhBwk5CNz5A6Q4lJ64Mq/lqHznRCQQ2Mc1G8eyDF/fYL\r\n" +"Ze2pLvwP9VD5jTc2miDfw+MnvJhywRRLcemDFP8k4hQVtm8PMp3ZmNECgYEA4gz7\r\n" +"wzObR4gn8ibe617uQPZjWzUj9dUHYd+in1gwBCIrtNnaRn9I9U/Q6tegRYpii4ys\r\n" +"c176NmU+umy6XmuSKV5qD9bSpZWG2nLFnslrN15Lm3fhZxoeMNhBaEDTnLT26yoi\r\n" +"33gp0mSSWy94ZEqipms+ULF6sY1ZtFW6tpGFoy8CgYAQHhnnvJflIs2ky4q10B60\r\n" +"ZcxFp3rtDpkp0JxhFLhiizFrujMtZSjYNm5U7KkgPVHhLELEUvCmOnKTt4ap/vZ0\r\n" +"BxJNe1GZH3pW6SAvGDQpl9sG7uu/vTFP+lCxukmzxB0DrrDcvorEkKMom7ZCCRvW\r\n" +"KZsZ6YeH2Z81BauRj218kQKBgQCUV/DgKP2985xDTT79N08jUo3hTP5MVYCCuj/+\r\n" +"UeEw1TvZcx3LJby7P6Xad6a1/BqveaGyFKIfEFIaBUBItk801sDDpDaYc4gL00Xc\r\n" +"7lFuBHOZkxJYlss5QrGpuOEl9ZwUt5IrFLBdYaKqNHzNVC1pCPfb/JyH6Dr2HUxq\r\n" +"gxUwAQKBgQCcU6G2L8AG9d9c0UpOyL1tMvFe5Ttw0KjlQVdsh1MP6yigYo9DYuwu\r\n" +"bHFVW2r0dBTqegP2/KTOxKzaHfC1qf0RGDsUoJCNJrd1cwoCLG8P2EF4w3OBrKqv\r\n" +"8u4ytY0F+Vlanj5lm3TaoHSVF1+NWPyOTiwevIECGKwSxvlki4fDAA==\r\n" +"-----END RSA PRIVATE KEY-----\r\n"; +const size_t mbedtls_test_cli_key_rsa_len = sizeof( mbedtls_test_cli_key_rsa ); +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_PEM_PARSE_C) +/* Concatenation of all available CA certificates */ +const char mbedtls_test_cas_pem[] = +#ifdef TEST_CA_CRT_RSA_SHA1 + TEST_CA_CRT_RSA_SHA1 +#endif +#ifdef TEST_CA_CRT_RSA_SHA256 + TEST_CA_CRT_RSA_SHA256 +#endif +#ifdef TEST_CA_CRT_EC + TEST_CA_CRT_EC +#endif + ""; +const size_t mbedtls_test_cas_pem_len = sizeof( mbedtls_test_cas_pem ); +#endif + +/* List of all available CA certificates */ +const char * mbedtls_test_cas[] = { +#if defined(TEST_CA_CRT_RSA_SHA1) + mbedtls_test_ca_crt_rsa_sha1, +#endif +#if defined(TEST_CA_CRT_RSA_SHA256) + mbedtls_test_ca_crt_rsa_sha256, +#endif +#if defined(MBEDTLS_ECDSA_C) + mbedtls_test_ca_crt_ec, +#endif + NULL +}; +const size_t mbedtls_test_cas_len[] = { +#if defined(TEST_CA_CRT_RSA_SHA1) + sizeof( mbedtls_test_ca_crt_rsa_sha1 ), +#endif +#if defined(TEST_CA_CRT_RSA_SHA256) + sizeof( mbedtls_test_ca_crt_rsa_sha256 ), +#endif +#if defined(MBEDTLS_ECDSA_C) + sizeof( mbedtls_test_ca_crt_ec ), +#endif + 0 +}; + +#if defined(MBEDTLS_RSA_C) +const char *mbedtls_test_ca_crt = mbedtls_test_ca_crt_rsa; /* SHA1 or SHA256 */ +const char *mbedtls_test_ca_key = mbedtls_test_ca_key_rsa; +const char *mbedtls_test_ca_pwd = mbedtls_test_ca_pwd_rsa; +const char *mbedtls_test_srv_crt = mbedtls_test_srv_crt_rsa; +const char *mbedtls_test_srv_key = mbedtls_test_srv_key_rsa; +const char *mbedtls_test_cli_crt = mbedtls_test_cli_crt_rsa; +const char *mbedtls_test_cli_key = mbedtls_test_cli_key_rsa; +const size_t mbedtls_test_ca_crt_len = sizeof( mbedtls_test_ca_crt_rsa ); +const size_t mbedtls_test_ca_key_len = sizeof( mbedtls_test_ca_key_rsa ); +const size_t mbedtls_test_ca_pwd_len = sizeof( mbedtls_test_ca_pwd_rsa ) - 1; +const size_t mbedtls_test_srv_crt_len = sizeof( mbedtls_test_srv_crt_rsa ); +const size_t mbedtls_test_srv_key_len = sizeof( mbedtls_test_srv_key_rsa ); +const size_t mbedtls_test_cli_crt_len = sizeof( mbedtls_test_cli_crt_rsa ); +const size_t mbedtls_test_cli_key_len = sizeof( mbedtls_test_cli_key_rsa ); +#else /* ! MBEDTLS_RSA_C, so MBEDTLS_ECDSA_C */ +const char *mbedtls_test_ca_crt = mbedtls_test_ca_crt_ec; +const char *mbedtls_test_ca_key = mbedtls_test_ca_key_ec; +const char *mbedtls_test_ca_pwd = mbedtls_test_ca_pwd_ec; +const char *mbedtls_test_srv_crt = mbedtls_test_srv_crt_ec; +const char *mbedtls_test_srv_key = mbedtls_test_srv_key_ec; +const char *mbedtls_test_cli_crt = mbedtls_test_cli_crt_ec; +const char *mbedtls_test_cli_key = mbedtls_test_cli_key_ec; +const size_t mbedtls_test_ca_crt_len = sizeof( mbedtls_test_ca_crt_ec ); +const size_t mbedtls_test_ca_key_len = sizeof( mbedtls_test_ca_key_ec ); +const size_t mbedtls_test_ca_pwd_len = sizeof( mbedtls_test_ca_pwd_ec ) - 1; +const size_t mbedtls_test_srv_crt_len = sizeof( mbedtls_test_srv_crt_ec ); +const size_t mbedtls_test_srv_key_len = sizeof( mbedtls_test_srv_key_ec ); +const size_t mbedtls_test_cli_crt_len = sizeof( mbedtls_test_cli_crt_ec ); +const size_t mbedtls_test_cli_key_len = sizeof( mbedtls_test_cli_key_ec ); +#endif /* MBEDTLS_RSA_C */ + +#endif /* MBEDTLS_CERTS_C */ diff --git a/common/mbedtls/certs.h b/common/mbedtls/certs.h new file mode 100644 index 00000000..ae0f84a3 --- /dev/null +++ b/common/mbedtls/certs.h @@ -0,0 +1,102 @@ +/** + * \file certs.h + * + * \brief Sample certificates and DHM parameters for testing + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_CERTS_H +#define MBEDTLS_CERTS_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(MBEDTLS_PEM_PARSE_C) +/* Concatenation of all CA certificates in PEM format if available */ +extern const char mbedtls_test_cas_pem[]; +extern const size_t mbedtls_test_cas_pem_len; +#endif + +/* List of all CA certificates, terminated by NULL */ +extern const char * mbedtls_test_cas[]; +extern const size_t mbedtls_test_cas_len[]; + +/* + * Convenience for users who just want a certificate: + * RSA by default, or ECDSA if RSA is not available + */ +extern const char * mbedtls_test_ca_crt; +extern const size_t mbedtls_test_ca_crt_len; +extern const char * mbedtls_test_ca_key; +extern const size_t mbedtls_test_ca_key_len; +extern const char * mbedtls_test_ca_pwd; +extern const size_t mbedtls_test_ca_pwd_len; +extern const char * mbedtls_test_srv_crt; +extern const size_t mbedtls_test_srv_crt_len; +extern const char * mbedtls_test_srv_key; +extern const size_t mbedtls_test_srv_key_len; +extern const char * mbedtls_test_cli_crt; +extern const size_t mbedtls_test_cli_crt_len; +extern const char * mbedtls_test_cli_key; +extern const size_t mbedtls_test_cli_key_len; + +#if defined(MBEDTLS_ECDSA_C) +extern const char mbedtls_test_ca_crt_ec[]; +extern const size_t mbedtls_test_ca_crt_ec_len; +extern const char mbedtls_test_ca_key_ec[]; +extern const size_t mbedtls_test_ca_key_ec_len; +extern const char mbedtls_test_ca_pwd_ec[]; +extern const size_t mbedtls_test_ca_pwd_ec_len; +extern const char mbedtls_test_srv_crt_ec[]; +extern const size_t mbedtls_test_srv_crt_ec_len; +extern const char mbedtls_test_srv_key_ec[]; +extern const size_t mbedtls_test_srv_key_ec_len; +extern const char mbedtls_test_cli_crt_ec[]; +extern const size_t mbedtls_test_cli_crt_ec_len; +extern const char mbedtls_test_cli_key_ec[]; +extern const size_t mbedtls_test_cli_key_ec_len; +#endif + +#if defined(MBEDTLS_RSA_C) +extern const char mbedtls_test_ca_crt_rsa[]; +extern const size_t mbedtls_test_ca_crt_rsa_len; +extern const char mbedtls_test_ca_key_rsa[]; +extern const size_t mbedtls_test_ca_key_rsa_len; +extern const char mbedtls_test_ca_pwd_rsa[]; +extern const size_t mbedtls_test_ca_pwd_rsa_len; +extern const char mbedtls_test_srv_crt_rsa[]; +extern const size_t mbedtls_test_srv_crt_rsa_len; +extern const char mbedtls_test_srv_key_rsa[]; +extern const size_t mbedtls_test_srv_key_rsa_len; +extern const char mbedtls_test_cli_crt_rsa[]; +extern const size_t mbedtls_test_cli_crt_rsa_len; +extern const char mbedtls_test_cli_key_rsa[]; +extern const size_t mbedtls_test_cli_key_rsa_len; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* certs.h */ diff --git a/common/mbedtls/check_config.h b/common/mbedtls/check_config.h new file mode 100644 index 00000000..a4fa7bdd --- /dev/null +++ b/common/mbedtls/check_config.h @@ -0,0 +1,685 @@ +/** + * \file check_config.h + * + * \brief Consistency checks for configuration options + */ +/* + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * It is recommended to include this file from your config.h + * in order to catch dependency issues early. + */ + +#ifndef MBEDTLS_CHECK_CONFIG_H +#define MBEDTLS_CHECK_CONFIG_H + +/* + * We assume CHAR_BIT is 8 in many places. In practice, this is true on our + * target platforms, so not an issue, but let's just be extra sure. + */ +#include +#if CHAR_BIT != 8 +#error "mbed TLS requires a platform with 8-bit chars" +#endif + +#if defined(_WIN32) +#if !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_C is required on Windows" +#endif + +/* Fix the config here. Not convenient to put an #ifdef _WIN32 in config.h as + * it would confuse config.pl. */ +#if !defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) && \ + !defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO) +#define MBEDTLS_PLATFORM_SNPRINTF_ALT +#endif +#endif /* _WIN32 */ + +#if defined(TARGET_LIKE_MBED) && \ + ( defined(MBEDTLS_NET_C) || defined(MBEDTLS_TIMING_C) ) +#error "The NET and TIMING modules are not available for mbed OS - please use the network and timing functions provided by mbed OS" +#endif + +#if defined(MBEDTLS_DEPRECATED_WARNING) && \ + !defined(__GNUC__) && !defined(__clang__) +#error "MBEDTLS_DEPRECATED_WARNING only works with GCC and Clang" +#endif + +#if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_HAVE_TIME) +#error "MBEDTLS_HAVE_TIME_DATE without MBEDTLS_HAVE_TIME does not make sense" +#endif + +#if defined(MBEDTLS_AESNI_C) && !defined(MBEDTLS_HAVE_ASM) +#error "MBEDTLS_AESNI_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_CTR_DRBG_C) && !defined(MBEDTLS_AES_C) +#error "MBEDTLS_CTR_DRBG_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_DHM_C) && !defined(MBEDTLS_BIGNUM_C) +#error "MBEDTLS_DHM_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT) && !defined(MBEDTLS_SSL_TRUNCATED_HMAC) +#error "MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_CMAC_C) && \ + !defined(MBEDTLS_AES_C) && !defined(MBEDTLS_DES_C) +#error "MBEDTLS_CMAC_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_NIST_KW_C) && \ + ( !defined(MBEDTLS_AES_C) || !defined(MBEDTLS_CIPHER_C) ) +#error "MBEDTLS_NIST_KW_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECDH_C) && !defined(MBEDTLS_ECP_C) +#error "MBEDTLS_ECDH_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECDSA_C) && \ + ( !defined(MBEDTLS_ECP_C) || \ + !defined(MBEDTLS_ASN1_PARSE_C) || \ + !defined(MBEDTLS_ASN1_WRITE_C) ) +#error "MBEDTLS_ECDSA_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECJPAKE_C) && \ + ( !defined(MBEDTLS_ECP_C) || !defined(MBEDTLS_MD_C) ) +#error "MBEDTLS_ECJPAKE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) && !defined(MBEDTLS_HMAC_DRBG_C) +#error "MBEDTLS_ECDSA_DETERMINISTIC defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECP_C) && ( !defined(MBEDTLS_BIGNUM_C) || ( \ + !defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) ) ) +#error "MBEDTLS_ECP_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ENTROPY_C) && (!defined(MBEDTLS_SHA512_C) && \ + !defined(MBEDTLS_SHA256_C)) +#error "MBEDTLS_ENTROPY_C defined, but not all prerequisites" +#endif +#if defined(MBEDTLS_ENTROPY_C) && defined(MBEDTLS_SHA512_C) && \ + defined(MBEDTLS_CTR_DRBG_ENTROPY_LEN) && (MBEDTLS_CTR_DRBG_ENTROPY_LEN > 64) +#error "MBEDTLS_CTR_DRBG_ENTROPY_LEN value too high" +#endif +#if defined(MBEDTLS_ENTROPY_C) && \ + ( !defined(MBEDTLS_SHA512_C) || defined(MBEDTLS_ENTROPY_FORCE_SHA256) ) \ + && defined(MBEDTLS_CTR_DRBG_ENTROPY_LEN) && (MBEDTLS_CTR_DRBG_ENTROPY_LEN > 32) +#error "MBEDTLS_CTR_DRBG_ENTROPY_LEN value too high" +#endif +#if defined(MBEDTLS_ENTROPY_C) && \ + defined(MBEDTLS_ENTROPY_FORCE_SHA256) && !defined(MBEDTLS_SHA256_C) +#error "MBEDTLS_ENTROPY_FORCE_SHA256 defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_TEST_NULL_ENTROPY) && \ + ( !defined(MBEDTLS_ENTROPY_C) || !defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES) ) +#error "MBEDTLS_TEST_NULL_ENTROPY defined, but not all prerequisites" +#endif +#if defined(MBEDTLS_TEST_NULL_ENTROPY) && \ + ( defined(MBEDTLS_ENTROPY_NV_SEED) || defined(MBEDTLS_ENTROPY_HARDWARE_ALT) || \ + defined(MBEDTLS_HAVEGE_C) ) +#error "MBEDTLS_TEST_NULL_ENTROPY defined, but entropy sources too" +#endif + +#if defined(MBEDTLS_GCM_C) && ( \ + !defined(MBEDTLS_AES_C) && !defined(MBEDTLS_CAMELLIA_C) ) +#error "MBEDTLS_GCM_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECP_RANDOMIZE_JAC_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT) +#error "MBEDTLS_ECP_RANDOMIZE_JAC_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECP_ADD_MIXED_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT) +#error "MBEDTLS_ECP_ADD_MIXED_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECP_DOUBLE_JAC_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT) +#error "MBEDTLS_ECP_DOUBLE_JAC_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT) +#error "MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT) +#error "MBEDTLS_ECP_NORMALIZE_JAC_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT) +#error "MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECP_RANDOMIZE_MXZ_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT) +#error "MBEDTLS_ECP_RANDOMIZE_MXZ_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECP_NORMALIZE_MXZ_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT) +#error "MBEDTLS_ECP_NORMALIZE_MXZ_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_HAVEGE_C) && !defined(MBEDTLS_TIMING_C) +#error "MBEDTLS_HAVEGE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_HKDF_C) && !defined(MBEDTLS_MD_C) +#error "MBEDTLS_HKDF_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_HMAC_DRBG_C) && !defined(MBEDTLS_MD_C) +#error "MBEDTLS_HMAC_DRBG_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) && \ + ( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) ) +#error "MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) && \ + ( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) ) +#error "MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) && !defined(MBEDTLS_DHM_C) +#error "MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) && \ + !defined(MBEDTLS_ECDH_C) +#error "MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) && \ + ( !defined(MBEDTLS_DHM_C) || !defined(MBEDTLS_RSA_C) || \ + !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_PKCS1_V15) ) +#error "MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) && \ + ( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_RSA_C) || \ + !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_PKCS1_V15) ) +#error "MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) && \ + ( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_ECDSA_C) || \ + !defined(MBEDTLS_X509_CRT_PARSE_C) ) +#error "MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) && \ + ( !defined(MBEDTLS_RSA_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) || \ + !defined(MBEDTLS_PKCS1_V15) ) +#error "MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) && \ + ( !defined(MBEDTLS_RSA_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) || \ + !defined(MBEDTLS_PKCS1_V15) ) +#error "MBEDTLS_KEY_EXCHANGE_RSA_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) && \ + ( !defined(MBEDTLS_ECJPAKE_C) || !defined(MBEDTLS_SHA256_C) || \ + !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) ) +#error "MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) && \ + ( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) ) +#error "MBEDTLS_MEMORY_BUFFER_ALLOC_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PADLOCK_C) && !defined(MBEDTLS_HAVE_ASM) +#error "MBEDTLS_PADLOCK_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PEM_PARSE_C) && !defined(MBEDTLS_BASE64_C) +#error "MBEDTLS_PEM_PARSE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PEM_WRITE_C) && !defined(MBEDTLS_BASE64_C) +#error "MBEDTLS_PEM_WRITE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PK_C) && \ + ( !defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_ECP_C) ) +#error "MBEDTLS_PK_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PK_PARSE_C) && !defined(MBEDTLS_PK_C) +#error "MBEDTLS_PK_PARSE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PK_WRITE_C) && !defined(MBEDTLS_PK_C) +#error "MBEDTLS_PK_WRITE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PKCS11_C) && !defined(MBEDTLS_PK_C) +#error "MBEDTLS_PKCS11_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_EXIT_ALT) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_EXIT_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_EXIT_MACRO) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_EXIT_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_EXIT_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_EXIT) ||\ + defined(MBEDTLS_PLATFORM_EXIT_ALT) ) +#error "MBEDTLS_PLATFORM_EXIT_MACRO and MBEDTLS_PLATFORM_STD_EXIT/MBEDTLS_PLATFORM_EXIT_ALT cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_TIME_ALT) &&\ + ( !defined(MBEDTLS_PLATFORM_C) ||\ + !defined(MBEDTLS_HAVE_TIME) ) +#error "MBEDTLS_PLATFORM_TIME_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_TIME_MACRO) &&\ + ( !defined(MBEDTLS_PLATFORM_C) ||\ + !defined(MBEDTLS_HAVE_TIME) ) +#error "MBEDTLS_PLATFORM_TIME_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_TIME_TYPE_MACRO) &&\ + ( !defined(MBEDTLS_PLATFORM_C) ||\ + !defined(MBEDTLS_HAVE_TIME) ) +#error "MBEDTLS_PLATFORM_TIME_TYPE_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_TIME_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_TIME) ||\ + defined(MBEDTLS_PLATFORM_TIME_ALT) ) +#error "MBEDTLS_PLATFORM_TIME_MACRO and MBEDTLS_PLATFORM_STD_TIME/MBEDTLS_PLATFORM_TIME_ALT cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_TIME_TYPE_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_TIME) ||\ + defined(MBEDTLS_PLATFORM_TIME_ALT) ) +#error "MBEDTLS_PLATFORM_TIME_TYPE_MACRO and MBEDTLS_PLATFORM_STD_TIME/MBEDTLS_PLATFORM_TIME_ALT cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_FPRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_FPRINTF_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_FPRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_FPRINTF_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_FPRINTF_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_FPRINTF) ||\ + defined(MBEDTLS_PLATFORM_FPRINTF_ALT) ) +#error "MBEDTLS_PLATFORM_FPRINTF_MACRO and MBEDTLS_PLATFORM_STD_FPRINTF/MBEDTLS_PLATFORM_FPRINTF_ALT cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_FREE_MACRO) &&\ + ( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) ) +#error "MBEDTLS_PLATFORM_FREE_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_FREE_MACRO) &&\ + defined(MBEDTLS_PLATFORM_STD_FREE) +#error "MBEDTLS_PLATFORM_FREE_MACRO and MBEDTLS_PLATFORM_STD_FREE cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_FREE_MACRO) && !defined(MBEDTLS_PLATFORM_CALLOC_MACRO) +#error "MBEDTLS_PLATFORM_CALLOC_MACRO must be defined if MBEDTLS_PLATFORM_FREE_MACRO is" +#endif + +#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO) &&\ + ( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) ) +#error "MBEDTLS_PLATFORM_CALLOC_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO) &&\ + defined(MBEDTLS_PLATFORM_STD_CALLOC) +#error "MBEDTLS_PLATFORM_CALLOC_MACRO and MBEDTLS_PLATFORM_STD_CALLOC cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO) && !defined(MBEDTLS_PLATFORM_FREE_MACRO) +#error "MBEDTLS_PLATFORM_FREE_MACRO must be defined if MBEDTLS_PLATFORM_CALLOC_MACRO is" +#endif + +#if defined(MBEDTLS_PLATFORM_MEMORY) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_MEMORY defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_PRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_PRINTF_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_PRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_PRINTF_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_PRINTF_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_PRINTF) ||\ + defined(MBEDTLS_PLATFORM_PRINTF_ALT) ) +#error "MBEDTLS_PLATFORM_PRINTF_MACRO and MBEDTLS_PLATFORM_STD_PRINTF/MBEDTLS_PLATFORM_PRINTF_ALT cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_SNPRINTF_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_SNPRINTF_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_SNPRINTF) ||\ + defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) ) +#error "MBEDTLS_PLATFORM_SNPRINTF_MACRO and MBEDTLS_PLATFORM_STD_SNPRINTF/MBEDTLS_PLATFORM_SNPRINTF_ALT cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_MEM_HDR) &&\ + !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS) +#error "MBEDTLS_PLATFORM_STD_MEM_HDR defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_CALLOC) && !defined(MBEDTLS_PLATFORM_MEMORY) +#error "MBEDTLS_PLATFORM_STD_CALLOC defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_CALLOC) && !defined(MBEDTLS_PLATFORM_MEMORY) +#error "MBEDTLS_PLATFORM_STD_CALLOC defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_FREE) && !defined(MBEDTLS_PLATFORM_MEMORY) +#error "MBEDTLS_PLATFORM_STD_FREE defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_EXIT) &&\ + !defined(MBEDTLS_PLATFORM_EXIT_ALT) +#error "MBEDTLS_PLATFORM_STD_EXIT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_TIME) &&\ + ( !defined(MBEDTLS_PLATFORM_TIME_ALT) ||\ + !defined(MBEDTLS_HAVE_TIME) ) +#error "MBEDTLS_PLATFORM_STD_TIME defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_FPRINTF) &&\ + !defined(MBEDTLS_PLATFORM_FPRINTF_ALT) +#error "MBEDTLS_PLATFORM_STD_FPRINTF defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_PRINTF) &&\ + !defined(MBEDTLS_PLATFORM_PRINTF_ALT) +#error "MBEDTLS_PLATFORM_STD_PRINTF defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_SNPRINTF) &&\ + !defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) +#error "MBEDTLS_PLATFORM_STD_SNPRINTF defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ENTROPY_NV_SEED) &&\ + ( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_ENTROPY_C) ) +#error "MBEDTLS_ENTROPY_NV_SEED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_NV_SEED_ALT) &&\ + !defined(MBEDTLS_ENTROPY_NV_SEED) +#error "MBEDTLS_PLATFORM_NV_SEED_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ) &&\ + !defined(MBEDTLS_PLATFORM_NV_SEED_ALT) +#error "MBEDTLS_PLATFORM_STD_NV_SEED_READ defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE) &&\ + !defined(MBEDTLS_PLATFORM_NV_SEED_ALT) +#error "MBEDTLS_PLATFORM_STD_NV_SEED_WRITE defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_NV_SEED_READ_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ) ||\ + defined(MBEDTLS_PLATFORM_NV_SEED_ALT) ) +#error "MBEDTLS_PLATFORM_NV_SEED_READ_MACRO and MBEDTLS_PLATFORM_STD_NV_SEED_READ cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE) ||\ + defined(MBEDTLS_PLATFORM_NV_SEED_ALT) ) +#error "MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO and MBEDTLS_PLATFORM_STD_NV_SEED_WRITE cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_RSA_C) && ( !defined(MBEDTLS_BIGNUM_C) || \ + !defined(MBEDTLS_OID_C) ) +#error "MBEDTLS_RSA_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_RSA_C) && ( !defined(MBEDTLS_PKCS1_V21) && \ + !defined(MBEDTLS_PKCS1_V15) ) +#error "MBEDTLS_RSA_C defined, but none of the PKCS1 versions enabled" +#endif + +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) && \ + ( !defined(MBEDTLS_RSA_C) || !defined(MBEDTLS_PKCS1_V21) ) +#error "MBEDTLS_X509_RSASSA_PSS_SUPPORT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_PROTO_SSL3) && ( !defined(MBEDTLS_MD5_C) || \ + !defined(MBEDTLS_SHA1_C) ) +#error "MBEDTLS_SSL_PROTO_SSL3 defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1) && ( !defined(MBEDTLS_MD5_C) || \ + !defined(MBEDTLS_SHA1_C) ) +#error "MBEDTLS_SSL_PROTO_TLS1 defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_1) && ( !defined(MBEDTLS_MD5_C) || \ + !defined(MBEDTLS_SHA1_C) ) +#error "MBEDTLS_SSL_PROTO_TLS1_1 defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && ( !defined(MBEDTLS_SHA1_C) && \ + !defined(MBEDTLS_SHA256_C) && !defined(MBEDTLS_SHA512_C) ) +#error "MBEDTLS_SSL_PROTO_TLS1_2 defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_PROTO_DTLS) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1_1) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1_2) +#error "MBEDTLS_SSL_PROTO_DTLS defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_CLI_C) && !defined(MBEDTLS_SSL_TLS_C) +#error "MBEDTLS_SSL_CLI_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_TLS_C) && ( !defined(MBEDTLS_CIPHER_C) || \ + !defined(MBEDTLS_MD_C) ) +#error "MBEDTLS_SSL_TLS_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_SRV_C) && !defined(MBEDTLS_SSL_TLS_C) +#error "MBEDTLS_SSL_SRV_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_TLS_C) && (!defined(MBEDTLS_SSL_PROTO_SSL3) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1) && !defined(MBEDTLS_SSL_PROTO_TLS1_1) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1_2)) +#error "MBEDTLS_SSL_TLS_C defined, but no protocols are active" +#endif + +#if defined(MBEDTLS_SSL_TLS_C) && (defined(MBEDTLS_SSL_PROTO_SSL3) && \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) && !defined(MBEDTLS_SSL_PROTO_TLS1)) +#error "Illegal protocol selection" +#endif + +#if defined(MBEDTLS_SSL_TLS_C) && (defined(MBEDTLS_SSL_PROTO_TLS1) && \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) && !defined(MBEDTLS_SSL_PROTO_TLS1_1)) +#error "Illegal protocol selection" +#endif + +#if defined(MBEDTLS_SSL_TLS_C) && (defined(MBEDTLS_SSL_PROTO_SSL3) && \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) && (!defined(MBEDTLS_SSL_PROTO_TLS1) || \ + !defined(MBEDTLS_SSL_PROTO_TLS1_1))) +#error "Illegal protocol selection" +#endif + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && !defined(MBEDTLS_SSL_PROTO_DTLS) +#error "MBEDTLS_SSL_DTLS_HELLO_VERIFY defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && \ + !defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) +#error "MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) && \ + ( !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_PROTO_DTLS) ) +#error "MBEDTLS_SSL_DTLS_ANTI_REPLAY defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT) && \ + ( !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_PROTO_DTLS) ) +#error "MBEDTLS_SSL_DTLS_BADMAC_LIMIT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1_1) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1_2) +#error "MBEDTLS_SSL_ENCRYPT_THEN_MAC defined, but not all prerequsites" +#endif + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1_1) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1_2) +#error "MBEDTLS_SSL_EXTENDED_MASTER_SECRET defined, but not all prerequsites" +#endif + +#if defined(MBEDTLS_SSL_TICKET_C) && !defined(MBEDTLS_CIPHER_C) +#error "MBEDTLS_SSL_TICKET_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) && \ + !defined(MBEDTLS_SSL_PROTO_SSL3) && !defined(MBEDTLS_SSL_PROTO_TLS1) +#error "MBEDTLS_SSL_CBC_RECORD_SPLITTING defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) && \ + !defined(MBEDTLS_X509_CRT_PARSE_C) +#error "MBEDTLS_SSL_SERVER_NAME_INDICATION defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_THREADING_PTHREAD) +#if !defined(MBEDTLS_THREADING_C) || defined(MBEDTLS_THREADING_IMPL) +#error "MBEDTLS_THREADING_PTHREAD defined, but not all prerequisites" +#endif +#define MBEDTLS_THREADING_IMPL +#endif + +#if defined(MBEDTLS_THREADING_ALT) +#if !defined(MBEDTLS_THREADING_C) || defined(MBEDTLS_THREADING_IMPL) +#error "MBEDTLS_THREADING_ALT defined, but not all prerequisites" +#endif +#define MBEDTLS_THREADING_IMPL +#endif + +#if defined(MBEDTLS_THREADING_C) && !defined(MBEDTLS_THREADING_IMPL) +#error "MBEDTLS_THREADING_C defined, single threading implementation required" +#endif +#undef MBEDTLS_THREADING_IMPL + +#if defined(MBEDTLS_VERSION_FEATURES) && !defined(MBEDTLS_VERSION_C) +#error "MBEDTLS_VERSION_FEATURES defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_X509_USE_C) && ( !defined(MBEDTLS_BIGNUM_C) || \ + !defined(MBEDTLS_OID_C) || !defined(MBEDTLS_ASN1_PARSE_C) || \ + !defined(MBEDTLS_PK_PARSE_C) ) +#error "MBEDTLS_X509_USE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_X509_CREATE_C) && ( !defined(MBEDTLS_BIGNUM_C) || \ + !defined(MBEDTLS_OID_C) || !defined(MBEDTLS_ASN1_WRITE_C) || \ + !defined(MBEDTLS_PK_WRITE_C) ) +#error "MBEDTLS_X509_CREATE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) && ( !defined(MBEDTLS_X509_USE_C) ) +#error "MBEDTLS_X509_CRT_PARSE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_X509_CRL_PARSE_C) && ( !defined(MBEDTLS_X509_USE_C) ) +#error "MBEDTLS_X509_CRL_PARSE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_X509_CSR_PARSE_C) && ( !defined(MBEDTLS_X509_USE_C) ) +#error "MBEDTLS_X509_CSR_PARSE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_X509_CRT_WRITE_C) && ( !defined(MBEDTLS_X509_CREATE_C) ) +#error "MBEDTLS_X509_CRT_WRITE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_X509_CSR_WRITE_C) && ( !defined(MBEDTLS_X509_CREATE_C) ) +#error "MBEDTLS_X509_CSR_WRITE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_HAVE_INT32) && defined(MBEDTLS_HAVE_INT64) +#error "MBEDTLS_HAVE_INT32 and MBEDTLS_HAVE_INT64 cannot be defined simultaneously" +#endif /* MBEDTLS_HAVE_INT32 && MBEDTLS_HAVE_INT64 */ + +#if ( defined(MBEDTLS_HAVE_INT32) || defined(MBEDTLS_HAVE_INT64) ) && \ + defined(MBEDTLS_HAVE_ASM) +#error "MBEDTLS_HAVE_INT32/MBEDTLS_HAVE_INT64 and MBEDTLS_HAVE_ASM cannot be defined simultaneously" +#endif /* (MBEDTLS_HAVE_INT32 || MBEDTLS_HAVE_INT64) && MBEDTLS_HAVE_ASM */ + +/* + * Avoid warning from -pedantic. This is a convenient place for this + * workaround since this is included by every single file before the + * #if defined(MBEDTLS_xxx_C) that results in emtpy translation units. + */ +typedef int mbedtls_iso_c_forbids_empty_translation_units; + +#endif /* MBEDTLS_CHECK_CONFIG_H */ diff --git a/common/mbedtls/cipher.c b/common/mbedtls/cipher.c new file mode 100644 index 00000000..de9402a2 --- /dev/null +++ b/common/mbedtls/cipher.c @@ -0,0 +1,1108 @@ +/** + * \file cipher.c + * + * \brief Generic cipher wrapper for mbed TLS + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_CIPHER_C) + +#include "mbedtls/cipher.h" +#include "mbedtls/cipher_internal.h" +#include "mbedtls/platform_util.h" + +#include +#include + +#if defined(MBEDTLS_CHACHAPOLY_C) +#include "mbedtls/chachapoly.h" +#endif + +#if defined(MBEDTLS_GCM_C) +#include "mbedtls/gcm.h" +#endif + +#if defined(MBEDTLS_CCM_C) +#include "mbedtls/ccm.h" +#endif + +#if defined(MBEDTLS_CHACHA20_C) +#include "mbedtls/chacha20.h" +#endif + +#if defined(MBEDTLS_CMAC_C) +#include "mbedtls/cmac.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) +/* Compare the contents of two buffers in constant time. + * Returns 0 if the contents are bitwise identical, otherwise returns + * a non-zero value. + * This is currently only used by GCM and ChaCha20+Poly1305. + */ +static int mbedtls_constant_time_memcmp( const void *v1, const void *v2, size_t len ) +{ + const unsigned char *p1 = (const unsigned char*) v1; + const unsigned char *p2 = (const unsigned char*) v2; + size_t i; + unsigned char diff; + + for( diff = 0, i = 0; i < len; i++ ) + diff |= p1[i] ^ p2[i]; + + return (int)diff; +} +#endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */ + +static int supported_init = 0; + +const int *mbedtls_cipher_list( void ) +{ + const mbedtls_cipher_definition_t *def; + int *type; + + if( ! supported_init ) + { + def = mbedtls_cipher_definitions; + type = mbedtls_cipher_supported; + + while( def->type != 0 ) + *type++ = (*def++).type; + + *type = 0; + + supported_init = 1; + } + + return( mbedtls_cipher_supported ); +} + +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_type( const mbedtls_cipher_type_t cipher_type ) +{ + const mbedtls_cipher_definition_t *def; + + for( def = mbedtls_cipher_definitions; def->info != NULL; def++ ) + if( def->type == cipher_type ) + return( def->info ); + + return( NULL ); +} + +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_string( const char *cipher_name ) +{ + const mbedtls_cipher_definition_t *def; + + if( NULL == cipher_name ) + return( NULL ); + + for( def = mbedtls_cipher_definitions; def->info != NULL; def++ ) + if( ! strcmp( def->info->name, cipher_name ) ) + return( def->info ); + + return( NULL ); +} + +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_values( const mbedtls_cipher_id_t cipher_id, + int key_bitlen, + const mbedtls_cipher_mode_t mode ) +{ + const mbedtls_cipher_definition_t *def; + + for( def = mbedtls_cipher_definitions; def->info != NULL; def++ ) + if( def->info->base->cipher == cipher_id && + def->info->key_bitlen == (unsigned) key_bitlen && + def->info->mode == mode ) + return( def->info ); + + return( NULL ); +} + +void mbedtls_cipher_init( mbedtls_cipher_context_t *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_cipher_context_t ) ); +} + +void mbedtls_cipher_free( mbedtls_cipher_context_t *ctx ) +{ + if( ctx == NULL ) + return; + +#if defined(MBEDTLS_CMAC_C) + if( ctx->cmac_ctx ) + { + mbedtls_platform_zeroize( ctx->cmac_ctx, + sizeof( mbedtls_cmac_context_t ) ); + mbedtls_free( ctx->cmac_ctx ); + } +#endif + + if( ctx->cipher_ctx ) + ctx->cipher_info->base->ctx_free_func( ctx->cipher_ctx ); + + mbedtls_platform_zeroize( ctx, sizeof(mbedtls_cipher_context_t) ); +} + +int mbedtls_cipher_setup( mbedtls_cipher_context_t *ctx, const mbedtls_cipher_info_t *cipher_info ) +{ + if( NULL == cipher_info || NULL == ctx ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + memset( ctx, 0, sizeof( mbedtls_cipher_context_t ) ); + + if( NULL == ( ctx->cipher_ctx = cipher_info->base->ctx_alloc_func() ) ) + return( MBEDTLS_ERR_CIPHER_ALLOC_FAILED ); + + ctx->cipher_info = cipher_info; + +#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) + /* + * Ignore possible errors caused by a cipher mode that doesn't use padding + */ +#if defined(MBEDTLS_CIPHER_PADDING_PKCS7) + (void) mbedtls_cipher_set_padding_mode( ctx, MBEDTLS_PADDING_PKCS7 ); +#else + (void) mbedtls_cipher_set_padding_mode( ctx, MBEDTLS_PADDING_NONE ); +#endif +#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ + + return( 0 ); +} + +int mbedtls_cipher_setkey( mbedtls_cipher_context_t *ctx, const unsigned char *key, + int key_bitlen, const mbedtls_operation_t operation ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + if( ( ctx->cipher_info->flags & MBEDTLS_CIPHER_VARIABLE_KEY_LEN ) == 0 && + (int) ctx->cipher_info->key_bitlen != key_bitlen ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + ctx->key_bitlen = key_bitlen; + ctx->operation = operation; + + /* + * For OFB, CFB and CTR mode always use the encryption key schedule + */ + if( MBEDTLS_ENCRYPT == operation || + MBEDTLS_MODE_CFB == ctx->cipher_info->mode || + MBEDTLS_MODE_OFB == ctx->cipher_info->mode || + MBEDTLS_MODE_CTR == ctx->cipher_info->mode ) + { + return ctx->cipher_info->base->setkey_enc_func( ctx->cipher_ctx, key, + ctx->key_bitlen ); + } + + if( MBEDTLS_DECRYPT == operation ) + return ctx->cipher_info->base->setkey_dec_func( ctx->cipher_ctx, key, + ctx->key_bitlen ); + + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); +} + +int mbedtls_cipher_set_iv( mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len ) +{ + size_t actual_iv_size; + + if( NULL == ctx || NULL == ctx->cipher_info || NULL == iv ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + /* avoid buffer overflow in ctx->iv */ + if( iv_len > MBEDTLS_MAX_IV_LENGTH ) + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); + + if( ( ctx->cipher_info->flags & MBEDTLS_CIPHER_VARIABLE_IV_LEN ) != 0 ) + actual_iv_size = iv_len; + else + { + actual_iv_size = ctx->cipher_info->iv_size; + + /* avoid reading past the end of input buffer */ + if( actual_iv_size > iv_len ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + +#if defined(MBEDTLS_CHACHA20_C) + if ( ctx->cipher_info->type == MBEDTLS_CIPHER_CHACHA20 ) + { + if ( 0 != mbedtls_chacha20_starts( (mbedtls_chacha20_context*)ctx->cipher_ctx, + iv, + 0U ) ) /* Initial counter value */ + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + } +#endif + + memcpy( ctx->iv, iv, actual_iv_size ); + ctx->iv_size = actual_iv_size; + + return( 0 ); +} + +int mbedtls_cipher_reset( mbedtls_cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + ctx->unprocessed_len = 0; + + return( 0 ); +} + +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) +int mbedtls_cipher_update_ad( mbedtls_cipher_context_t *ctx, + const unsigned char *ad, size_t ad_len ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_GCM_C) + if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) + { + return mbedtls_gcm_starts( (mbedtls_gcm_context *) ctx->cipher_ctx, ctx->operation, + ctx->iv, ctx->iv_size, ad, ad_len ); + } +#endif + +#if defined(MBEDTLS_CHACHAPOLY_C) + if (MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type ) + { + int result; + mbedtls_chachapoly_mode_t mode; + + mode = ( ctx->operation == MBEDTLS_ENCRYPT ) + ? MBEDTLS_CHACHAPOLY_ENCRYPT + : MBEDTLS_CHACHAPOLY_DECRYPT; + + result = mbedtls_chachapoly_starts( (mbedtls_chachapoly_context*) ctx->cipher_ctx, + ctx->iv, + mode ); + if ( result != 0 ) + return( result ); + + return mbedtls_chachapoly_update_aad( (mbedtls_chachapoly_context*) ctx->cipher_ctx, + ad, ad_len ); + } +#endif + + return( 0 ); +} +#endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */ + +int mbedtls_cipher_update( mbedtls_cipher_context_t *ctx, const unsigned char *input, + size_t ilen, unsigned char *output, size_t *olen ) +{ + int ret; + size_t block_size = 0; + + if( NULL == ctx || NULL == ctx->cipher_info || NULL == olen ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + *olen = 0; + block_size = mbedtls_cipher_get_block_size( ctx ); + + if( ctx->cipher_info->mode == MBEDTLS_MODE_ECB ) + { + if( ilen != block_size ) + return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED ); + + *olen = ilen; + + if( 0 != ( ret = ctx->cipher_info->base->ecb_func( ctx->cipher_ctx, + ctx->operation, input, output ) ) ) + { + return( ret ); + } + + return( 0 ); + } + +#if defined(MBEDTLS_GCM_C) + if( ctx->cipher_info->mode == MBEDTLS_MODE_GCM ) + { + *olen = ilen; + return mbedtls_gcm_update( (mbedtls_gcm_context *) ctx->cipher_ctx, ilen, input, + output ); + } +#endif + +#if defined(MBEDTLS_CHACHAPOLY_C) + if ( ctx->cipher_info->type == MBEDTLS_CIPHER_CHACHA20_POLY1305 ) + { + *olen = ilen; + return mbedtls_chachapoly_update( (mbedtls_chachapoly_context*) ctx->cipher_ctx, + ilen, input, output ); + } +#endif + + if ( 0 == block_size ) + { + return MBEDTLS_ERR_CIPHER_INVALID_CONTEXT; + } + + if( input == output && + ( ctx->unprocessed_len != 0 || ilen % block_size ) ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + if( ctx->cipher_info->mode == MBEDTLS_MODE_CBC ) + { + size_t copy_len = 0; + + /* + * If there is not enough data for a full block, cache it. + */ + if( ( ctx->operation == MBEDTLS_DECRYPT && NULL != ctx->add_padding && + ilen <= block_size - ctx->unprocessed_len ) || + ( ctx->operation == MBEDTLS_DECRYPT && NULL == ctx->add_padding && + ilen < block_size - ctx->unprocessed_len ) || + ( ctx->operation == MBEDTLS_ENCRYPT && + ilen < block_size - ctx->unprocessed_len ) ) + { + memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ), input, + ilen ); + + ctx->unprocessed_len += ilen; + return( 0 ); + } + + /* + * Process cached data first + */ + if( 0 != ctx->unprocessed_len ) + { + copy_len = block_size - ctx->unprocessed_len; + + memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ), input, + copy_len ); + + if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx, + ctx->operation, block_size, ctx->iv, + ctx->unprocessed_data, output ) ) ) + { + return( ret ); + } + + *olen += block_size; + output += block_size; + ctx->unprocessed_len = 0; + + input += copy_len; + ilen -= copy_len; + } + + /* + * Cache final, incomplete block + */ + if( 0 != ilen ) + { + if( 0 == block_size ) + { + return MBEDTLS_ERR_CIPHER_INVALID_CONTEXT; + } + + /* Encryption: only cache partial blocks + * Decryption w/ padding: always keep at least one whole block + * Decryption w/o padding: only cache partial blocks + */ + copy_len = ilen % block_size; + if( copy_len == 0 && + ctx->operation == MBEDTLS_DECRYPT && + NULL != ctx->add_padding) + { + copy_len = block_size; + } + + memcpy( ctx->unprocessed_data, &( input[ilen - copy_len] ), + copy_len ); + + ctx->unprocessed_len += copy_len; + ilen -= copy_len; + } + + /* + * Process remaining full blocks + */ + if( ilen ) + { + if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx, + ctx->operation, ilen, ctx->iv, input, output ) ) ) + { + return( ret ); + } + + *olen += ilen; + } + + return( 0 ); + } +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) + if( ctx->cipher_info->mode == MBEDTLS_MODE_CFB ) + { + if( 0 != ( ret = ctx->cipher_info->base->cfb_func( ctx->cipher_ctx, + ctx->operation, ilen, &ctx->unprocessed_len, ctx->iv, + input, output ) ) ) + { + return( ret ); + } + + *olen = ilen; + + return( 0 ); + } +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_OFB) + if( ctx->cipher_info->mode == MBEDTLS_MODE_OFB ) + { + if( 0 != ( ret = ctx->cipher_info->base->ofb_func( ctx->cipher_ctx, + ilen, &ctx->unprocessed_len, ctx->iv, input, output ) ) ) + { + return( ret ); + } + + *olen = ilen; + + return( 0 ); + } +#endif /* MBEDTLS_CIPHER_MODE_OFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) + if( ctx->cipher_info->mode == MBEDTLS_MODE_CTR ) + { + if( 0 != ( ret = ctx->cipher_info->base->ctr_func( ctx->cipher_ctx, + ilen, &ctx->unprocessed_len, ctx->iv, + ctx->unprocessed_data, input, output ) ) ) + { + return( ret ); + } + + *olen = ilen; + + return( 0 ); + } +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_CIPHER_MODE_XTS) + if( ctx->cipher_info->mode == MBEDTLS_MODE_XTS ) + { + if( ctx->unprocessed_len > 0 ) { + /* We can only process an entire data unit at a time. */ + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); + } + + ret = ctx->cipher_info->base->xts_func( ctx->cipher_ctx, + ctx->operation, ilen, ctx->iv, input, output ); + if( ret != 0 ) + { + return( ret ); + } + + *olen = ilen; + + return( 0 ); + } +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + if( ctx->cipher_info->mode == MBEDTLS_MODE_STREAM ) + { + if( 0 != ( ret = ctx->cipher_info->base->stream_func( ctx->cipher_ctx, + ilen, input, output ) ) ) + { + return( ret ); + } + + *olen = ilen; + + return( 0 ); + } +#endif /* MBEDTLS_CIPHER_MODE_STREAM */ + + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); +} + +#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) +#if defined(MBEDTLS_CIPHER_PADDING_PKCS7) +/* + * PKCS7 (and PKCS5) padding: fill with ll bytes, with ll = padding_len + */ +static void add_pkcs_padding( unsigned char *output, size_t output_len, + size_t data_len ) +{ + size_t padding_len = output_len - data_len; + unsigned char i; + + for( i = 0; i < padding_len; i++ ) + output[data_len + i] = (unsigned char) padding_len; +} + +static int get_pkcs_padding( unsigned char *input, size_t input_len, + size_t *data_len ) +{ + size_t i, pad_idx; + unsigned char padding_len, bad = 0; + + if( NULL == input || NULL == data_len ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + padding_len = input[input_len - 1]; + *data_len = input_len - padding_len; + + /* Avoid logical || since it results in a branch */ + bad |= padding_len > input_len; + bad |= padding_len == 0; + + /* The number of bytes checked must be independent of padding_len, + * so pick input_len, which is usually 8 or 16 (one block) */ + pad_idx = input_len - padding_len; + for( i = 0; i < input_len; i++ ) + bad |= ( input[i] ^ padding_len ) * ( i >= pad_idx ); + + return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) ); +} +#endif /* MBEDTLS_CIPHER_PADDING_PKCS7 */ + +#if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS) +/* + * One and zeros padding: fill with 80 00 ... 00 + */ +static void add_one_and_zeros_padding( unsigned char *output, + size_t output_len, size_t data_len ) +{ + size_t padding_len = output_len - data_len; + unsigned char i = 0; + + output[data_len] = 0x80; + for( i = 1; i < padding_len; i++ ) + output[data_len + i] = 0x00; +} + +static int get_one_and_zeros_padding( unsigned char *input, size_t input_len, + size_t *data_len ) +{ + size_t i; + unsigned char done = 0, prev_done, bad; + + if( NULL == input || NULL == data_len ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + bad = 0x80; + *data_len = 0; + for( i = input_len; i > 0; i-- ) + { + prev_done = done; + done |= ( input[i - 1] != 0 ); + *data_len |= ( i - 1 ) * ( done != prev_done ); + bad ^= input[i - 1] * ( done != prev_done ); + } + + return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) ); + +} +#endif /* MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS */ + +#if defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN) +/* + * Zeros and len padding: fill with 00 ... 00 ll, where ll is padding length + */ +static void add_zeros_and_len_padding( unsigned char *output, + size_t output_len, size_t data_len ) +{ + size_t padding_len = output_len - data_len; + unsigned char i = 0; + + for( i = 1; i < padding_len; i++ ) + output[data_len + i - 1] = 0x00; + output[output_len - 1] = (unsigned char) padding_len; +} + +static int get_zeros_and_len_padding( unsigned char *input, size_t input_len, + size_t *data_len ) +{ + size_t i, pad_idx; + unsigned char padding_len, bad = 0; + + if( NULL == input || NULL == data_len ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + padding_len = input[input_len - 1]; + *data_len = input_len - padding_len; + + /* Avoid logical || since it results in a branch */ + bad |= padding_len > input_len; + bad |= padding_len == 0; + + /* The number of bytes checked must be independent of padding_len */ + pad_idx = input_len - padding_len; + for( i = 0; i < input_len - 1; i++ ) + bad |= input[i] * ( i >= pad_idx ); + + return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) ); +} +#endif /* MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN */ + +#if defined(MBEDTLS_CIPHER_PADDING_ZEROS) +/* + * Zero padding: fill with 00 ... 00 + */ +static void add_zeros_padding( unsigned char *output, + size_t output_len, size_t data_len ) +{ + size_t i; + + for( i = data_len; i < output_len; i++ ) + output[i] = 0x00; +} + +static int get_zeros_padding( unsigned char *input, size_t input_len, + size_t *data_len ) +{ + size_t i; + unsigned char done = 0, prev_done; + + if( NULL == input || NULL == data_len ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + *data_len = 0; + for( i = input_len; i > 0; i-- ) + { + prev_done = done; + done |= ( input[i-1] != 0 ); + *data_len |= i * ( done != prev_done ); + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_PADDING_ZEROS */ + +/* + * No padding: don't pad :) + * + * There is no add_padding function (check for NULL in mbedtls_cipher_finish) + * but a trivial get_padding function + */ +static int get_no_padding( unsigned char *input, size_t input_len, + size_t *data_len ) +{ + if( NULL == input || NULL == data_len ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + *data_len = input_len; + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ + +int mbedtls_cipher_finish( mbedtls_cipher_context_t *ctx, + unsigned char *output, size_t *olen ) +{ + if( NULL == ctx || NULL == ctx->cipher_info || NULL == olen ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + *olen = 0; + + if( MBEDTLS_MODE_CFB == ctx->cipher_info->mode || + MBEDTLS_MODE_OFB == ctx->cipher_info->mode || + MBEDTLS_MODE_CTR == ctx->cipher_info->mode || + MBEDTLS_MODE_GCM == ctx->cipher_info->mode || + MBEDTLS_MODE_XTS == ctx->cipher_info->mode || + MBEDTLS_MODE_STREAM == ctx->cipher_info->mode ) + { + return( 0 ); + } + + if ( ( MBEDTLS_CIPHER_CHACHA20 == ctx->cipher_info->type ) || + ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type ) ) + { + return( 0 ); + } + + if( MBEDTLS_MODE_ECB == ctx->cipher_info->mode ) + { + if( ctx->unprocessed_len != 0 ) + return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED ); + + return( 0 ); + } + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + if( MBEDTLS_MODE_CBC == ctx->cipher_info->mode ) + { + int ret = 0; + + if( MBEDTLS_ENCRYPT == ctx->operation ) + { + /* check for 'no padding' mode */ + if( NULL == ctx->add_padding ) + { + if( 0 != ctx->unprocessed_len ) + return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED ); + + return( 0 ); + } + + ctx->add_padding( ctx->unprocessed_data, mbedtls_cipher_get_iv_size( ctx ), + ctx->unprocessed_len ); + } + else if( mbedtls_cipher_get_block_size( ctx ) != ctx->unprocessed_len ) + { + /* + * For decrypt operations, expect a full block, + * or an empty block if no padding + */ + if( NULL == ctx->add_padding && 0 == ctx->unprocessed_len ) + return( 0 ); + + return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED ); + } + + /* cipher block */ + if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx, + ctx->operation, mbedtls_cipher_get_block_size( ctx ), ctx->iv, + ctx->unprocessed_data, output ) ) ) + { + return( ret ); + } + + /* Set output size for decryption */ + if( MBEDTLS_DECRYPT == ctx->operation ) + return ctx->get_padding( output, mbedtls_cipher_get_block_size( ctx ), + olen ); + + /* Set output size for encryption */ + *olen = mbedtls_cipher_get_block_size( ctx ); + return( 0 ); + } +#else + ((void) output); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); +} + +#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) +int mbedtls_cipher_set_padding_mode( mbedtls_cipher_context_t *ctx, mbedtls_cipher_padding_t mode ) +{ + if( NULL == ctx || + MBEDTLS_MODE_CBC != ctx->cipher_info->mode ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + switch( mode ) + { +#if defined(MBEDTLS_CIPHER_PADDING_PKCS7) + case MBEDTLS_PADDING_PKCS7: + ctx->add_padding = add_pkcs_padding; + ctx->get_padding = get_pkcs_padding; + break; +#endif +#if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS) + case MBEDTLS_PADDING_ONE_AND_ZEROS: + ctx->add_padding = add_one_and_zeros_padding; + ctx->get_padding = get_one_and_zeros_padding; + break; +#endif +#if defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN) + case MBEDTLS_PADDING_ZEROS_AND_LEN: + ctx->add_padding = add_zeros_and_len_padding; + ctx->get_padding = get_zeros_and_len_padding; + break; +#endif +#if defined(MBEDTLS_CIPHER_PADDING_ZEROS) + case MBEDTLS_PADDING_ZEROS: + ctx->add_padding = add_zeros_padding; + ctx->get_padding = get_zeros_padding; + break; +#endif + case MBEDTLS_PADDING_NONE: + ctx->add_padding = NULL; + ctx->get_padding = get_no_padding; + break; + + default: + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ + +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) +int mbedtls_cipher_write_tag( mbedtls_cipher_context_t *ctx, + unsigned char *tag, size_t tag_len ) +{ + if( NULL == ctx || NULL == ctx->cipher_info || NULL == tag ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + if( MBEDTLS_ENCRYPT != ctx->operation ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_GCM_C) + if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) + return mbedtls_gcm_finish( (mbedtls_gcm_context *) ctx->cipher_ctx, tag, tag_len ); +#endif + +#if defined(MBEDTLS_CHACHAPOLY_C) + if ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type ) + { + /* Don't allow truncated MAC for Poly1305 */ + if ( tag_len != 16U ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + return mbedtls_chachapoly_finish( (mbedtls_chachapoly_context*) ctx->cipher_ctx, + tag ); + } +#endif + + return( 0 ); +} + +int mbedtls_cipher_check_tag( mbedtls_cipher_context_t *ctx, + const unsigned char *tag, size_t tag_len ) +{ + unsigned char check_tag[16]; + int ret; + + if( NULL == ctx || NULL == ctx->cipher_info || + MBEDTLS_DECRYPT != ctx->operation ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + +#if defined(MBEDTLS_GCM_C) + if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) + { + if( tag_len > sizeof( check_tag ) ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + if( 0 != ( ret = mbedtls_gcm_finish( (mbedtls_gcm_context *) ctx->cipher_ctx, + check_tag, tag_len ) ) ) + { + return( ret ); + } + + /* Check the tag in "constant-time" */ + if( mbedtls_constant_time_memcmp( tag, check_tag, tag_len ) != 0 ) + return( MBEDTLS_ERR_CIPHER_AUTH_FAILED ); + + return( 0 ); + } +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CHACHAPOLY_C) + if ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type ) + { + /* Don't allow truncated MAC for Poly1305 */ + if ( tag_len != sizeof( check_tag ) ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + ret = mbedtls_chachapoly_finish( (mbedtls_chachapoly_context*) ctx->cipher_ctx, + check_tag ); + if ( ret != 0 ) + { + return( ret ); + } + + /* Check the tag in "constant-time" */ + if( mbedtls_constant_time_memcmp( tag, check_tag, tag_len ) != 0 ) + return( MBEDTLS_ERR_CIPHER_AUTH_FAILED ); + + return( 0 ); + } +#endif /* MBEDTLS_CHACHAPOLY_C */ + + return( 0 ); +} +#endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */ + +/* + * Packet-oriented wrapper for non-AEAD modes + */ +int mbedtls_cipher_crypt( mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen ) +{ + int ret; + size_t finish_olen; + + if( ( ret = mbedtls_cipher_set_iv( ctx, iv, iv_len ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_cipher_reset( ctx ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_cipher_update( ctx, input, ilen, output, olen ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_cipher_finish( ctx, output + *olen, &finish_olen ) ) != 0 ) + return( ret ); + + *olen += finish_olen; + + return( 0 ); +} + +#if defined(MBEDTLS_CIPHER_MODE_AEAD) +/* + * Packet-oriented encryption for AEAD modes + */ +int mbedtls_cipher_auth_encrypt( mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *ad, size_t ad_len, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, + unsigned char *tag, size_t tag_len ) +{ +#if defined(MBEDTLS_GCM_C) + if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) + { + *olen = ilen; + return( mbedtls_gcm_crypt_and_tag( ctx->cipher_ctx, MBEDTLS_GCM_ENCRYPT, ilen, + iv, iv_len, ad, ad_len, input, output, + tag_len, tag ) ); + } +#endif /* MBEDTLS_GCM_C */ +#if defined(MBEDTLS_CCM_C) + if( MBEDTLS_MODE_CCM == ctx->cipher_info->mode ) + { + *olen = ilen; + return( mbedtls_ccm_encrypt_and_tag( ctx->cipher_ctx, ilen, + iv, iv_len, ad, ad_len, input, output, + tag, tag_len ) ); + } +#endif /* MBEDTLS_CCM_C */ +#if defined(MBEDTLS_CHACHAPOLY_C) + if ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type ) + { + /* ChachaPoly has fixed length nonce and MAC (tag) */ + if ( ( iv_len != ctx->cipher_info->iv_size ) || + ( tag_len != 16U ) ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + *olen = ilen; + return( mbedtls_chachapoly_encrypt_and_tag( ctx->cipher_ctx, + ilen, iv, ad, ad_len, input, output, tag ) ); + } +#endif /* MBEDTLS_CHACHAPOLY_C */ + + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); +} + +/* + * Packet-oriented decryption for AEAD modes + */ +int mbedtls_cipher_auth_decrypt( mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *ad, size_t ad_len, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, + const unsigned char *tag, size_t tag_len ) +{ +#if defined(MBEDTLS_GCM_C) + if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) + { + int ret; + + *olen = ilen; + ret = mbedtls_gcm_auth_decrypt( ctx->cipher_ctx, ilen, + iv, iv_len, ad, ad_len, + tag, tag_len, input, output ); + + if( ret == MBEDTLS_ERR_GCM_AUTH_FAILED ) + ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; + + return( ret ); + } +#endif /* MBEDTLS_GCM_C */ +#if defined(MBEDTLS_CCM_C) + if( MBEDTLS_MODE_CCM == ctx->cipher_info->mode ) + { + int ret; + + *olen = ilen; + ret = mbedtls_ccm_auth_decrypt( ctx->cipher_ctx, ilen, + iv, iv_len, ad, ad_len, + input, output, tag, tag_len ); + + if( ret == MBEDTLS_ERR_CCM_AUTH_FAILED ) + ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; + + return( ret ); + } +#endif /* MBEDTLS_CCM_C */ +#if defined(MBEDTLS_CHACHAPOLY_C) + if ( MBEDTLS_CIPHER_CHACHA20_POLY1305 == ctx->cipher_info->type ) + { + int ret; + + /* ChachaPoly has fixed length nonce and MAC (tag) */ + if ( ( iv_len != ctx->cipher_info->iv_size ) || + ( tag_len != 16U ) ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + *olen = ilen; + ret = mbedtls_chachapoly_auth_decrypt( ctx->cipher_ctx, ilen, + iv, ad, ad_len, tag, input, output ); + + if( ret == MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED ) + ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; + + return( ret ); + } +#endif /* MBEDTLS_CHACHAPOLY_C */ + + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); +} +#endif /* MBEDTLS_CIPHER_MODE_AEAD */ + +#endif /* MBEDTLS_CIPHER_C */ diff --git a/common/mbedtls/cipher.h b/common/mbedtls/cipher.h new file mode 100644 index 00000000..9e3832dd --- /dev/null +++ b/common/mbedtls/cipher.h @@ -0,0 +1,808 @@ +/** + * \file cipher.h + * + * \brief This file contains an abstraction interface for use with the cipher + * primitives provided by the library. It provides a common interface to all of + * the available cipher operations. + * + * \author Adriaan de Jong + */ +/* + * Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_CIPHER_H +#define MBEDTLS_CIPHER_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CCM_C) || defined(MBEDTLS_CHACHAPOLY_C) +#define MBEDTLS_CIPHER_MODE_AEAD +#endif + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#define MBEDTLS_CIPHER_MODE_WITH_PADDING +#endif + +#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) || \ + defined(MBEDTLS_CHACHA20_C) +#define MBEDTLS_CIPHER_MODE_STREAM +#endif + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +#define MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE -0x6080 /**< The selected feature is not available. */ +#define MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA -0x6100 /**< Bad input parameters. */ +#define MBEDTLS_ERR_CIPHER_ALLOC_FAILED -0x6180 /**< Failed to allocate memory. */ +#define MBEDTLS_ERR_CIPHER_INVALID_PADDING -0x6200 /**< Input data contains invalid padding and is rejected. */ +#define MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED -0x6280 /**< Decryption of block requires a full block. */ +#define MBEDTLS_ERR_CIPHER_AUTH_FAILED -0x6300 /**< Authentication failed (for AEAD modes). */ +#define MBEDTLS_ERR_CIPHER_INVALID_CONTEXT -0x6380 /**< The context is invalid. For example, because it was freed. */ +#define MBEDTLS_ERR_CIPHER_HW_ACCEL_FAILED -0x6400 /**< Cipher hardware accelerator failed. */ + +#define MBEDTLS_CIPHER_VARIABLE_IV_LEN 0x01 /**< Cipher accepts IVs of variable length. */ +#define MBEDTLS_CIPHER_VARIABLE_KEY_LEN 0x02 /**< Cipher accepts keys of variable length. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Supported cipher types. + * + * \warning RC4 and DES are considered weak ciphers and their use + * constitutes a security risk. Arm recommends considering stronger + * ciphers instead. + */ +typedef enum { + MBEDTLS_CIPHER_ID_NONE = 0, /**< Placeholder to mark the end of cipher ID lists. */ + MBEDTLS_CIPHER_ID_NULL, /**< The identity cipher, treated as a stream cipher. */ + MBEDTLS_CIPHER_ID_AES, /**< The AES cipher. */ + MBEDTLS_CIPHER_ID_DES, /**< The DES cipher. */ + MBEDTLS_CIPHER_ID_3DES, /**< The Triple DES cipher. */ + MBEDTLS_CIPHER_ID_CAMELLIA, /**< The Camellia cipher. */ + MBEDTLS_CIPHER_ID_BLOWFISH, /**< The Blowfish cipher. */ + MBEDTLS_CIPHER_ID_ARC4, /**< The RC4 cipher. */ + MBEDTLS_CIPHER_ID_ARIA, /**< The Aria cipher. */ + MBEDTLS_CIPHER_ID_CHACHA20, /**< The ChaCha20 cipher. */ +} mbedtls_cipher_id_t; + +/** + * \brief Supported {cipher type, cipher mode} pairs. + * + * \warning RC4 and DES are considered weak ciphers and their use + * constitutes a security risk. Arm recommends considering stronger + * ciphers instead. + */ +typedef enum { + MBEDTLS_CIPHER_NONE = 0, /**< Placeholder to mark the end of cipher-pair lists. */ + MBEDTLS_CIPHER_NULL, /**< The identity stream cipher. */ + MBEDTLS_CIPHER_AES_128_ECB, /**< AES cipher with 128-bit ECB mode. */ + MBEDTLS_CIPHER_AES_192_ECB, /**< AES cipher with 192-bit ECB mode. */ + MBEDTLS_CIPHER_AES_256_ECB, /**< AES cipher with 256-bit ECB mode. */ + MBEDTLS_CIPHER_AES_128_CBC, /**< AES cipher with 128-bit CBC mode. */ + MBEDTLS_CIPHER_AES_192_CBC, /**< AES cipher with 192-bit CBC mode. */ + MBEDTLS_CIPHER_AES_256_CBC, /**< AES cipher with 256-bit CBC mode. */ + MBEDTLS_CIPHER_AES_128_CFB128, /**< AES cipher with 128-bit CFB128 mode. */ + MBEDTLS_CIPHER_AES_192_CFB128, /**< AES cipher with 192-bit CFB128 mode. */ + MBEDTLS_CIPHER_AES_256_CFB128, /**< AES cipher with 256-bit CFB128 mode. */ + MBEDTLS_CIPHER_AES_128_CTR, /**< AES cipher with 128-bit CTR mode. */ + MBEDTLS_CIPHER_AES_192_CTR, /**< AES cipher with 192-bit CTR mode. */ + MBEDTLS_CIPHER_AES_256_CTR, /**< AES cipher with 256-bit CTR mode. */ + MBEDTLS_CIPHER_AES_128_GCM, /**< AES cipher with 128-bit GCM mode. */ + MBEDTLS_CIPHER_AES_192_GCM, /**< AES cipher with 192-bit GCM mode. */ + MBEDTLS_CIPHER_AES_256_GCM, /**< AES cipher with 256-bit GCM mode. */ + MBEDTLS_CIPHER_CAMELLIA_128_ECB, /**< Camellia cipher with 128-bit ECB mode. */ + MBEDTLS_CIPHER_CAMELLIA_192_ECB, /**< Camellia cipher with 192-bit ECB mode. */ + MBEDTLS_CIPHER_CAMELLIA_256_ECB, /**< Camellia cipher with 256-bit ECB mode. */ + MBEDTLS_CIPHER_CAMELLIA_128_CBC, /**< Camellia cipher with 128-bit CBC mode. */ + MBEDTLS_CIPHER_CAMELLIA_192_CBC, /**< Camellia cipher with 192-bit CBC mode. */ + MBEDTLS_CIPHER_CAMELLIA_256_CBC, /**< Camellia cipher with 256-bit CBC mode. */ + MBEDTLS_CIPHER_CAMELLIA_128_CFB128, /**< Camellia cipher with 128-bit CFB128 mode. */ + MBEDTLS_CIPHER_CAMELLIA_192_CFB128, /**< Camellia cipher with 192-bit CFB128 mode. */ + MBEDTLS_CIPHER_CAMELLIA_256_CFB128, /**< Camellia cipher with 256-bit CFB128 mode. */ + MBEDTLS_CIPHER_CAMELLIA_128_CTR, /**< Camellia cipher with 128-bit CTR mode. */ + MBEDTLS_CIPHER_CAMELLIA_192_CTR, /**< Camellia cipher with 192-bit CTR mode. */ + MBEDTLS_CIPHER_CAMELLIA_256_CTR, /**< Camellia cipher with 256-bit CTR mode. */ + MBEDTLS_CIPHER_CAMELLIA_128_GCM, /**< Camellia cipher with 128-bit GCM mode. */ + MBEDTLS_CIPHER_CAMELLIA_192_GCM, /**< Camellia cipher with 192-bit GCM mode. */ + MBEDTLS_CIPHER_CAMELLIA_256_GCM, /**< Camellia cipher with 256-bit GCM mode. */ + MBEDTLS_CIPHER_DES_ECB, /**< DES cipher with ECB mode. */ + MBEDTLS_CIPHER_DES_CBC, /**< DES cipher with CBC mode. */ + MBEDTLS_CIPHER_DES_EDE_ECB, /**< DES cipher with EDE ECB mode. */ + MBEDTLS_CIPHER_DES_EDE_CBC, /**< DES cipher with EDE CBC mode. */ + MBEDTLS_CIPHER_DES_EDE3_ECB, /**< DES cipher with EDE3 ECB mode. */ + MBEDTLS_CIPHER_DES_EDE3_CBC, /**< DES cipher with EDE3 CBC mode. */ + MBEDTLS_CIPHER_BLOWFISH_ECB, /**< Blowfish cipher with ECB mode. */ + MBEDTLS_CIPHER_BLOWFISH_CBC, /**< Blowfish cipher with CBC mode. */ + MBEDTLS_CIPHER_BLOWFISH_CFB64, /**< Blowfish cipher with CFB64 mode. */ + MBEDTLS_CIPHER_BLOWFISH_CTR, /**< Blowfish cipher with CTR mode. */ + MBEDTLS_CIPHER_ARC4_128, /**< RC4 cipher with 128-bit mode. */ + MBEDTLS_CIPHER_AES_128_CCM, /**< AES cipher with 128-bit CCM mode. */ + MBEDTLS_CIPHER_AES_192_CCM, /**< AES cipher with 192-bit CCM mode. */ + MBEDTLS_CIPHER_AES_256_CCM, /**< AES cipher with 256-bit CCM mode. */ + MBEDTLS_CIPHER_CAMELLIA_128_CCM, /**< Camellia cipher with 128-bit CCM mode. */ + MBEDTLS_CIPHER_CAMELLIA_192_CCM, /**< Camellia cipher with 192-bit CCM mode. */ + MBEDTLS_CIPHER_CAMELLIA_256_CCM, /**< Camellia cipher with 256-bit CCM mode. */ + MBEDTLS_CIPHER_ARIA_128_ECB, /**< Aria cipher with 128-bit key and ECB mode. */ + MBEDTLS_CIPHER_ARIA_192_ECB, /**< Aria cipher with 192-bit key and ECB mode. */ + MBEDTLS_CIPHER_ARIA_256_ECB, /**< Aria cipher with 256-bit key and ECB mode. */ + MBEDTLS_CIPHER_ARIA_128_CBC, /**< Aria cipher with 128-bit key and CBC mode. */ + MBEDTLS_CIPHER_ARIA_192_CBC, /**< Aria cipher with 192-bit key and CBC mode. */ + MBEDTLS_CIPHER_ARIA_256_CBC, /**< Aria cipher with 256-bit key and CBC mode. */ + MBEDTLS_CIPHER_ARIA_128_CFB128, /**< Aria cipher with 128-bit key and CFB-128 mode. */ + MBEDTLS_CIPHER_ARIA_192_CFB128, /**< Aria cipher with 192-bit key and CFB-128 mode. */ + MBEDTLS_CIPHER_ARIA_256_CFB128, /**< Aria cipher with 256-bit key and CFB-128 mode. */ + MBEDTLS_CIPHER_ARIA_128_CTR, /**< Aria cipher with 128-bit key and CTR mode. */ + MBEDTLS_CIPHER_ARIA_192_CTR, /**< Aria cipher with 192-bit key and CTR mode. */ + MBEDTLS_CIPHER_ARIA_256_CTR, /**< Aria cipher with 256-bit key and CTR mode. */ + MBEDTLS_CIPHER_ARIA_128_GCM, /**< Aria cipher with 128-bit key and GCM mode. */ + MBEDTLS_CIPHER_ARIA_192_GCM, /**< Aria cipher with 192-bit key and GCM mode. */ + MBEDTLS_CIPHER_ARIA_256_GCM, /**< Aria cipher with 256-bit key and GCM mode. */ + MBEDTLS_CIPHER_ARIA_128_CCM, /**< Aria cipher with 128-bit key and CCM mode. */ + MBEDTLS_CIPHER_ARIA_192_CCM, /**< Aria cipher with 192-bit key and CCM mode. */ + MBEDTLS_CIPHER_ARIA_256_CCM, /**< Aria cipher with 256-bit key and CCM mode. */ + MBEDTLS_CIPHER_AES_128_OFB, /**< AES 128-bit cipher in OFB mode. */ + MBEDTLS_CIPHER_AES_192_OFB, /**< AES 192-bit cipher in OFB mode. */ + MBEDTLS_CIPHER_AES_256_OFB, /**< AES 256-bit cipher in OFB mode. */ + MBEDTLS_CIPHER_AES_128_XTS, /**< AES 128-bit cipher in XTS block mode. */ + MBEDTLS_CIPHER_AES_256_XTS, /**< AES 256-bit cipher in XTS block mode. */ + MBEDTLS_CIPHER_CHACHA20, /**< ChaCha20 stream cipher. */ + MBEDTLS_CIPHER_CHACHA20_POLY1305, /**< ChaCha20-Poly1305 AEAD cipher. */ +} mbedtls_cipher_type_t; + +/** Supported cipher modes. */ +typedef enum { + MBEDTLS_MODE_NONE = 0, /**< None. */ + MBEDTLS_MODE_ECB, /**< The ECB cipher mode. */ + MBEDTLS_MODE_CBC, /**< The CBC cipher mode. */ + MBEDTLS_MODE_CFB, /**< The CFB cipher mode. */ + MBEDTLS_MODE_OFB, /**< The OFB cipher mode. */ + MBEDTLS_MODE_CTR, /**< The CTR cipher mode. */ + MBEDTLS_MODE_GCM, /**< The GCM cipher mode. */ + MBEDTLS_MODE_STREAM, /**< The stream cipher mode. */ + MBEDTLS_MODE_CCM, /**< The CCM cipher mode. */ + MBEDTLS_MODE_XTS, /**< The XTS cipher mode. */ + MBEDTLS_MODE_CHACHAPOLY, /**< The ChaCha-Poly cipher mode. */ +} mbedtls_cipher_mode_t; + +/** Supported cipher padding types. */ +typedef enum { + MBEDTLS_PADDING_PKCS7 = 0, /**< PKCS7 padding (default). */ + MBEDTLS_PADDING_ONE_AND_ZEROS, /**< ISO/IEC 7816-4 padding. */ + MBEDTLS_PADDING_ZEROS_AND_LEN, /**< ANSI X.923 padding. */ + MBEDTLS_PADDING_ZEROS, /**< Zero padding (not reversible). */ + MBEDTLS_PADDING_NONE, /**< Never pad (full blocks only). */ +} mbedtls_cipher_padding_t; + +/** Type of operation. */ +typedef enum { + MBEDTLS_OPERATION_NONE = -1, + MBEDTLS_DECRYPT = 0, + MBEDTLS_ENCRYPT, +} mbedtls_operation_t; + +enum { + /** Undefined key length. */ + MBEDTLS_KEY_LENGTH_NONE = 0, + /** Key length, in bits (including parity), for DES keys. */ + MBEDTLS_KEY_LENGTH_DES = 64, + /** Key length in bits, including parity, for DES in two-key EDE. */ + MBEDTLS_KEY_LENGTH_DES_EDE = 128, + /** Key length in bits, including parity, for DES in three-key EDE. */ + MBEDTLS_KEY_LENGTH_DES_EDE3 = 192, +}; + +/** Maximum length of any IV, in Bytes. */ +#define MBEDTLS_MAX_IV_LENGTH 16 +/** Maximum block size of any cipher, in Bytes. */ +#define MBEDTLS_MAX_BLOCK_LENGTH 16 + +/** + * Base cipher information (opaque struct). + */ +typedef struct mbedtls_cipher_base_t mbedtls_cipher_base_t; + +/** + * CMAC context (opaque struct). + */ +typedef struct mbedtls_cmac_context_t mbedtls_cmac_context_t; + +/** + * Cipher information. Allows calling cipher functions + * in a generic way. + */ +typedef struct mbedtls_cipher_info_t +{ + /** Full cipher identifier. For example, + * MBEDTLS_CIPHER_AES_256_CBC. + */ + mbedtls_cipher_type_t type; + + /** The cipher mode. For example, MBEDTLS_MODE_CBC. */ + mbedtls_cipher_mode_t mode; + + /** The cipher key length, in bits. This is the + * default length for variable sized ciphers. + * Includes parity bits for ciphers like DES. + */ + unsigned int key_bitlen; + + /** Name of the cipher. */ + const char * name; + + /** IV or nonce size, in Bytes. + * For ciphers that accept variable IV sizes, + * this is the recommended size. + */ + unsigned int iv_size; + + /** Bitflag comprised of MBEDTLS_CIPHER_VARIABLE_IV_LEN and + * MBEDTLS_CIPHER_VARIABLE_KEY_LEN indicating whether the + * cipher supports variable IV or variable key sizes, respectively. + */ + int flags; + + /** The block size, in Bytes. */ + unsigned int block_size; + + /** Struct for base cipher information and functions. */ + const mbedtls_cipher_base_t *base; + +} mbedtls_cipher_info_t; + +/** + * Generic cipher context. + */ +typedef struct mbedtls_cipher_context_t +{ + /** Information about the associated cipher. */ + const mbedtls_cipher_info_t *cipher_info; + + /** Key length to use. */ + int key_bitlen; + + /** Operation that the key of the context has been + * initialized for. + */ + mbedtls_operation_t operation; + +#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) + /** Padding functions to use, if relevant for + * the specific cipher mode. + */ + void (*add_padding)( unsigned char *output, size_t olen, size_t data_len ); + int (*get_padding)( unsigned char *input, size_t ilen, size_t *data_len ); +#endif + + /** Buffer for input that has not been processed yet. */ + unsigned char unprocessed_data[MBEDTLS_MAX_BLOCK_LENGTH]; + + /** Number of Bytes that have not been processed yet. */ + size_t unprocessed_len; + + /** Current IV or NONCE_COUNTER for CTR-mode, data unit (or sector) number + * for XTS-mode. */ + unsigned char iv[MBEDTLS_MAX_IV_LENGTH]; + + /** IV size in Bytes, for ciphers with variable-length IVs. */ + size_t iv_size; + + /** The cipher-specific context. */ + void *cipher_ctx; + +#if defined(MBEDTLS_CMAC_C) + /** CMAC-specific context. */ + mbedtls_cmac_context_t *cmac_ctx; +#endif +} mbedtls_cipher_context_t; + +/** + * \brief This function retrieves the list of ciphers supported by the generic + * cipher module. + * + * \return A statically-allocated array of ciphers. The last entry + * is zero. + */ +const int *mbedtls_cipher_list( void ); + +/** + * \brief This function retrieves the cipher-information + * structure associated with the given cipher name. + * + * \param cipher_name Name of the cipher to search for. + * + * \return The cipher information structure associated with the + * given \p cipher_name. + * \return NULL if the associated cipher information is not found. + */ +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_string( const char *cipher_name ); + +/** + * \brief This function retrieves the cipher-information + * structure associated with the given cipher type. + * + * \param cipher_type Type of the cipher to search for. + * + * \return The cipher information structure associated with the + * given \p cipher_type. + * \return NULL if the associated cipher information is not found. + */ +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_type( const mbedtls_cipher_type_t cipher_type ); + +/** + * \brief This function retrieves the cipher-information + * structure associated with the given cipher ID, + * key size and mode. + * + * \param cipher_id The ID of the cipher to search for. For example, + * #MBEDTLS_CIPHER_ID_AES. + * \param key_bitlen The length of the key in bits. + * \param mode The cipher mode. For example, #MBEDTLS_MODE_CBC. + * + * \return The cipher information structure associated with the + * given \p cipher_id. + * \return NULL if the associated cipher information is not found. + */ +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_values( const mbedtls_cipher_id_t cipher_id, + int key_bitlen, + const mbedtls_cipher_mode_t mode ); + +/** + * \brief This function initializes a \p cipher_context as NONE. + */ +void mbedtls_cipher_init( mbedtls_cipher_context_t *ctx ); + +/** + * \brief This function frees and clears the cipher-specific + * context of \p ctx. Freeing \p ctx itself remains the + * responsibility of the caller. + */ +void mbedtls_cipher_free( mbedtls_cipher_context_t *ctx ); + + +/** + * \brief This function initializes and fills the cipher-context + * structure with the appropriate values. It also clears + * the structure. + * + * \param ctx The context to initialize. May not be NULL. + * \param cipher_info The cipher to use. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + * \return #MBEDTLS_ERR_CIPHER_ALLOC_FAILED if allocation of the + * cipher-specific context fails. + * + * \internal Currently, the function also clears the structure. + * In future versions, the caller will be required to call + * mbedtls_cipher_init() on the structure first. + */ +int mbedtls_cipher_setup( mbedtls_cipher_context_t *ctx, const mbedtls_cipher_info_t *cipher_info ); + +/** + * \brief This function returns the block size of the given cipher. + * + * \param ctx The context of the cipher. Must be initialized. + * + * \return The size of the blocks of the cipher. + * \return 0 if \p ctx has not been initialized. + */ +static inline unsigned int mbedtls_cipher_get_block_size( const mbedtls_cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return 0; + + return ctx->cipher_info->block_size; +} + +/** + * \brief This function returns the mode of operation for + * the cipher. For example, MBEDTLS_MODE_CBC. + * + * \param ctx The context of the cipher. Must be initialized. + * + * \return The mode of operation. + * \return #MBEDTLS_MODE_NONE if \p ctx has not been initialized. + */ +static inline mbedtls_cipher_mode_t mbedtls_cipher_get_cipher_mode( const mbedtls_cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return MBEDTLS_MODE_NONE; + + return ctx->cipher_info->mode; +} + +/** + * \brief This function returns the size of the IV or nonce + * of the cipher, in Bytes. + * + * \param ctx The context of the cipher. Must be initialized. + * + * \return The recommended IV size if no IV has been set. + * \return \c 0 for ciphers not using an IV or a nonce. + * \return The actual size if an IV has been set. + */ +static inline int mbedtls_cipher_get_iv_size( const mbedtls_cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return 0; + + if( ctx->iv_size != 0 ) + return (int) ctx->iv_size; + + return (int) ctx->cipher_info->iv_size; +} + +/** + * \brief This function returns the type of the given cipher. + * + * \param ctx The context of the cipher. Must be initialized. + * + * \return The type of the cipher. + * \return #MBEDTLS_CIPHER_NONE if \p ctx has not been initialized. + */ +static inline mbedtls_cipher_type_t mbedtls_cipher_get_type( const mbedtls_cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return MBEDTLS_CIPHER_NONE; + + return ctx->cipher_info->type; +} + +/** + * \brief This function returns the name of the given cipher + * as a string. + * + * \param ctx The context of the cipher. Must be initialized. + * + * \return The name of the cipher. + * \return NULL if \p ctx has not been not initialized. + */ +static inline const char *mbedtls_cipher_get_name( const mbedtls_cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return 0; + + return ctx->cipher_info->name; +} + +/** + * \brief This function returns the key length of the cipher. + * + * \param ctx The context of the cipher. Must be initialized. + * + * \return The key length of the cipher in bits. + * \return #MBEDTLS_KEY_LENGTH_NONE if ctx \p has not been + * initialized. + */ +static inline int mbedtls_cipher_get_key_bitlen( const mbedtls_cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return MBEDTLS_KEY_LENGTH_NONE; + + return (int) ctx->cipher_info->key_bitlen; +} + +/** + * \brief This function returns the operation of the given cipher. + * + * \param ctx The context of the cipher. Must be initialized. + * + * \return The type of operation: #MBEDTLS_ENCRYPT or #MBEDTLS_DECRYPT. + * \return #MBEDTLS_OPERATION_NONE if \p ctx has not been initialized. + */ +static inline mbedtls_operation_t mbedtls_cipher_get_operation( const mbedtls_cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return MBEDTLS_OPERATION_NONE; + + return ctx->operation; +} + +/** + * \brief This function sets the key to use with the given context. + * + * \param ctx The generic cipher context. May not be NULL. Must have + * been initialized using mbedtls_cipher_info_from_type() + * or mbedtls_cipher_info_from_string(). + * \param key The key to use. + * \param key_bitlen The key length to use, in bits. + * \param operation The operation that the key will be used for: + * #MBEDTLS_ENCRYPT or #MBEDTLS_DECRYPT. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + * \return A cipher-specific error code on failure. + */ +int mbedtls_cipher_setkey( mbedtls_cipher_context_t *ctx, const unsigned char *key, + int key_bitlen, const mbedtls_operation_t operation ); + +#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) +/** + * \brief This function sets the padding mode, for cipher modes + * that use padding. + * + * The default passing mode is PKCS7 padding. + * + * \param ctx The generic cipher context. + * \param mode The padding mode. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE + * if the selected padding mode is not supported. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA if the cipher mode + * does not support padding. + */ +int mbedtls_cipher_set_padding_mode( mbedtls_cipher_context_t *ctx, mbedtls_cipher_padding_t mode ); +#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ + +/** + * \brief This function sets the initialization vector (IV) + * or nonce. + * + * \note Some ciphers do not use IVs nor nonce. For these + * ciphers, this function has no effect. + * + * \param ctx The generic cipher context. + * \param iv The IV to use, or NONCE_COUNTER for CTR-mode ciphers. + * \param iv_len The IV length for ciphers with variable-size IV. + * This parameter is discarded by ciphers with fixed-size IV. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + */ +int mbedtls_cipher_set_iv( mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len ); + +/** + * \brief This function resets the cipher state. + * + * \param ctx The generic cipher context. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + */ +int mbedtls_cipher_reset( mbedtls_cipher_context_t *ctx ); + +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) +/** + * \brief This function adds additional data for AEAD ciphers. + * Currently supported with GCM and ChaCha20+Poly1305. + * Must be called exactly once, after mbedtls_cipher_reset(). + * + * \param ctx The generic cipher context. + * \param ad The additional data to use. + * \param ad_len the Length of \p ad. + * + * \return \c 0 on success. + * \return A specific error code on failure. + */ +int mbedtls_cipher_update_ad( mbedtls_cipher_context_t *ctx, + const unsigned char *ad, size_t ad_len ); +#endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */ + +/** + * \brief The generic cipher update function. It encrypts or + * decrypts using the given cipher context. Writes as + * many block-sized blocks of data as possible to output. + * Any data that cannot be written immediately is either + * added to the next block, or flushed when + * mbedtls_cipher_finish() is called. + * Exception: For MBEDTLS_MODE_ECB, expects a single block + * in size. For example, 16 Bytes for AES. + * + * \note If the underlying cipher is used in GCM mode, all calls + * to this function, except for the last one before + * mbedtls_cipher_finish(), must have \p ilen as a + * multiple of the block size of the cipher. + * + * \param ctx The generic cipher context. + * \param input The buffer holding the input data. + * \param ilen The length of the input data. + * \param output The buffer for the output data. Must be able to hold at + * least \p ilen + block_size. Must not be the same buffer + * as input. + * \param olen The length of the output data, to be updated with the + * actual number of Bytes written. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + * \return #MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE on an + * unsupported mode for a cipher. + * \return A cipher-specific error code on failure. + */ +int mbedtls_cipher_update( mbedtls_cipher_context_t *ctx, const unsigned char *input, + size_t ilen, unsigned char *output, size_t *olen ); + +/** + * \brief The generic cipher finalization function. If data still + * needs to be flushed from an incomplete block, the data + * contained in it is padded to the size of + * the last block, and written to the \p output buffer. + * + * \param ctx The generic cipher context. + * \param output The buffer to write data to. Needs block_size available. + * \param olen The length of the data written to the \p output buffer. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + * \return #MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED on decryption + * expecting a full block but not receiving one. + * \return #MBEDTLS_ERR_CIPHER_INVALID_PADDING on invalid padding + * while decrypting. + * \return A cipher-specific error code on failure. + */ +int mbedtls_cipher_finish( mbedtls_cipher_context_t *ctx, + unsigned char *output, size_t *olen ); + +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CHACHAPOLY_C) +/** + * \brief This function writes a tag for AEAD ciphers. + * Currently supported with GCM and ChaCha20+Poly1305. + * Must be called after mbedtls_cipher_finish(). + * + * \param ctx The generic cipher context. + * \param tag The buffer to write the tag to. + * \param tag_len The length of the tag to write. + * + * \return \c 0 on success. + * \return A specific error code on failure. + */ +int mbedtls_cipher_write_tag( mbedtls_cipher_context_t *ctx, + unsigned char *tag, size_t tag_len ); + +/** + * \brief This function checks the tag for AEAD ciphers. + * Currently supported with GCM and ChaCha20+Poly1305. + * Must be called after mbedtls_cipher_finish(). + * + * \param ctx The generic cipher context. + * \param tag The buffer holding the tag. + * \param tag_len The length of the tag to check. + * + * \return \c 0 on success. + * \return A specific error code on failure. + */ +int mbedtls_cipher_check_tag( mbedtls_cipher_context_t *ctx, + const unsigned char *tag, size_t tag_len ); +#endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */ + +/** + * \brief The generic all-in-one encryption/decryption function, + * for all ciphers except AEAD constructs. + * + * \param ctx The generic cipher context. + * \param iv The IV to use, or NONCE_COUNTER for CTR-mode ciphers. + * \param iv_len The IV length for ciphers with variable-size IV. + * This parameter is discarded by ciphers with fixed-size + * IV. + * \param input The buffer holding the input data. + * \param ilen The length of the input data. + * \param output The buffer for the output data. Must be able to hold at + * least \p ilen + block_size. Must not be the same buffer + * as input. + * \param olen The length of the output data, to be updated with the + * actual number of Bytes written. + * + * \note Some ciphers do not use IVs nor nonce. For these + * ciphers, use \p iv = NULL and \p iv_len = 0. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + * \return #MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED on decryption + * expecting a full block but not receiving one. + * \return #MBEDTLS_ERR_CIPHER_INVALID_PADDING on invalid padding + * while decrypting. + * \return A cipher-specific error code on failure. + */ +int mbedtls_cipher_crypt( mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen ); + +#if defined(MBEDTLS_CIPHER_MODE_AEAD) +/** + * \brief The generic autenticated encryption (AEAD) function. + * + * \param ctx The generic cipher context. + * \param iv The IV to use, or NONCE_COUNTER for CTR-mode ciphers. + * \param iv_len The IV length for ciphers with variable-size IV. + * This parameter is discarded by ciphers with fixed-size IV. + * \param ad The additional data to authenticate. + * \param ad_len The length of \p ad. + * \param input The buffer holding the input data. + * \param ilen The length of the input data. + * \param output The buffer for the output data. + * Must be able to hold at least \p ilen. + * \param olen The length of the output data, to be updated with the + * actual number of Bytes written. + * \param tag The buffer for the authentication tag. + * \param tag_len The desired length of the authentication tag. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + * \return A cipher-specific error code on failure. + */ +int mbedtls_cipher_auth_encrypt( mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *ad, size_t ad_len, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, + unsigned char *tag, size_t tag_len ); + +/** + * \brief The generic autenticated decryption (AEAD) function. + * + * \note If the data is not authentic, then the output buffer + * is zeroed out to prevent the unauthentic plaintext being + * used, making this interface safer. + * + * \param ctx The generic cipher context. + * \param iv The IV to use, or NONCE_COUNTER for CTR-mode ciphers. + * \param iv_len The IV length for ciphers with variable-size IV. + * This parameter is discarded by ciphers with fixed-size IV. + * \param ad The additional data to be authenticated. + * \param ad_len The length of \p ad. + * \param input The buffer holding the input data. + * \param ilen The length of the input data. + * \param output The buffer for the output data. + * Must be able to hold at least \p ilen. + * \param olen The length of the output data, to be updated with the + * actual number of Bytes written. + * \param tag The buffer holding the authentication tag. + * \param tag_len The length of the authentication tag. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on + * parameter-verification failure. + * \return #MBEDTLS_ERR_CIPHER_AUTH_FAILED if data is not authentic. + * \return A cipher-specific error code on failure. + */ +int mbedtls_cipher_auth_decrypt( mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *ad, size_t ad_len, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, + const unsigned char *tag, size_t tag_len ); +#endif /* MBEDTLS_CIPHER_MODE_AEAD */ + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_CIPHER_H */ diff --git a/common/mbedtls/cipher_internal.h b/common/mbedtls/cipher_internal.h new file mode 100644 index 00000000..9f2858aa --- /dev/null +++ b/common/mbedtls/cipher_internal.h @@ -0,0 +1,127 @@ +/** + * \file cipher_internal.h + * + * \brief Cipher wrappers. + * + * \author Adriaan de Jong + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_CIPHER_WRAP_H +#define MBEDTLS_CIPHER_WRAP_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "cipher.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Base cipher information. The non-mode specific functions and values. + */ +struct mbedtls_cipher_base_t +{ + /** Base Cipher type (e.g. MBEDTLS_CIPHER_ID_AES) */ + mbedtls_cipher_id_t cipher; + + /** Encrypt using ECB */ + int (*ecb_func)( void *ctx, mbedtls_operation_t mode, + const unsigned char *input, unsigned char *output ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + /** Encrypt using CBC */ + int (*cbc_func)( void *ctx, mbedtls_operation_t mode, size_t length, + unsigned char *iv, const unsigned char *input, + unsigned char *output ); +#endif + +#if defined(MBEDTLS_CIPHER_MODE_CFB) + /** Encrypt using CFB (Full length) */ + int (*cfb_func)( void *ctx, mbedtls_operation_t mode, size_t length, size_t *iv_off, + unsigned char *iv, const unsigned char *input, + unsigned char *output ); +#endif + +#if defined(MBEDTLS_CIPHER_MODE_OFB) + /** Encrypt using OFB (Full length) */ + int (*ofb_func)( void *ctx, size_t length, size_t *iv_off, + unsigned char *iv, + const unsigned char *input, + unsigned char *output ); +#endif + +#if defined(MBEDTLS_CIPHER_MODE_CTR) + /** Encrypt using CTR */ + int (*ctr_func)( void *ctx, size_t length, size_t *nc_off, + unsigned char *nonce_counter, unsigned char *stream_block, + const unsigned char *input, unsigned char *output ); +#endif + +#if defined(MBEDTLS_CIPHER_MODE_XTS) + /** Encrypt or decrypt using XTS. */ + int (*xts_func)( void *ctx, mbedtls_operation_t mode, size_t length, + const unsigned char data_unit[16], + const unsigned char *input, unsigned char *output ); +#endif + +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + /** Encrypt using STREAM */ + int (*stream_func)( void *ctx, size_t length, + const unsigned char *input, unsigned char *output ); +#endif + + /** Set key for encryption purposes */ + int (*setkey_enc_func)( void *ctx, const unsigned char *key, + unsigned int key_bitlen ); + + /** Set key for decryption purposes */ + int (*setkey_dec_func)( void *ctx, const unsigned char *key, + unsigned int key_bitlen); + + /** Allocate a new context */ + void * (*ctx_alloc_func)( void ); + + /** Free the given context */ + void (*ctx_free_func)( void *ctx ); + +}; + +typedef struct +{ + mbedtls_cipher_type_t type; + const mbedtls_cipher_info_t *info; +} mbedtls_cipher_definition_t; + +extern const mbedtls_cipher_definition_t mbedtls_cipher_definitions[]; + +extern int mbedtls_cipher_supported[]; + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_CIPHER_WRAP_H */ diff --git a/common/mbedtls/cipher_wrap.c b/common/mbedtls/cipher_wrap.c new file mode 100644 index 00000000..3f81729c --- /dev/null +++ b/common/mbedtls/cipher_wrap.c @@ -0,0 +1,2274 @@ +/** + * \file cipher_wrap.c + * + * \brief Generic cipher wrapper for mbed TLS + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_CIPHER_C) + +#include "mbedtls/cipher_internal.h" + +#if defined(MBEDTLS_CHACHAPOLY_C) +#include "mbedtls/chachapoly.h" +#endif + +#if defined(MBEDTLS_AES_C) +#include "mbedtls/aes.h" +#endif + +#if defined(MBEDTLS_ARC4_C) +#include "mbedtls/arc4.h" +#endif + +#if defined(MBEDTLS_CAMELLIA_C) +#include "mbedtls/camellia.h" +#endif + +#if defined(MBEDTLS_ARIA_C) +#include "mbedtls/aria.h" +#endif + +#if defined(MBEDTLS_DES_C) +#include "mbedtls/des.h" +#endif + +#if defined(MBEDTLS_BLOWFISH_C) +#include "mbedtls/blowfish.h" +#endif + +#if defined(MBEDTLS_CHACHA20_C) +#include "mbedtls/chacha20.h" +#endif + +#if defined(MBEDTLS_GCM_C) +#include "mbedtls/gcm.h" +#endif + +#if defined(MBEDTLS_CCM_C) +#include "mbedtls/ccm.h" +#endif + +#if defined(MBEDTLS_CIPHER_NULL_CIPHER) +#include +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#if defined(MBEDTLS_GCM_C) +/* shared by all GCM ciphers */ +static void *gcm_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_gcm_context ) ); + + if( ctx != NULL ) + mbedtls_gcm_init( (mbedtls_gcm_context *) ctx ); + + return( ctx ); +} + +static void gcm_ctx_free( void *ctx ) +{ + mbedtls_gcm_free( ctx ); + mbedtls_free( ctx ); +} +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CCM_C) +/* shared by all CCM ciphers */ +static void *ccm_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_ccm_context ) ); + + if( ctx != NULL ) + mbedtls_ccm_init( (mbedtls_ccm_context *) ctx ); + + return( ctx ); +} + +static void ccm_ctx_free( void *ctx ) +{ + mbedtls_ccm_free( ctx ); + mbedtls_free( ctx ); +} +#endif /* MBEDTLS_CCM_C */ + +#if defined(MBEDTLS_AES_C) + +static int aes_crypt_ecb_wrap( void *ctx, mbedtls_operation_t operation, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_aes_crypt_ecb( (mbedtls_aes_context *) ctx, operation, input, output ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static int aes_crypt_cbc_wrap( void *ctx, mbedtls_operation_t operation, size_t length, + unsigned char *iv, const unsigned char *input, unsigned char *output ) +{ + return mbedtls_aes_crypt_cbc( (mbedtls_aes_context *) ctx, operation, length, iv, input, + output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static int aes_crypt_cfb128_wrap( void *ctx, mbedtls_operation_t operation, + size_t length, size_t *iv_off, unsigned char *iv, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_aes_crypt_cfb128( (mbedtls_aes_context *) ctx, operation, length, iv_off, iv, + input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_OFB) +static int aes_crypt_ofb_wrap( void *ctx, size_t length, size_t *iv_off, + unsigned char *iv, const unsigned char *input, unsigned char *output ) +{ + return mbedtls_aes_crypt_ofb( (mbedtls_aes_context *) ctx, length, iv_off, + iv, input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_OFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static int aes_crypt_ctr_wrap( void *ctx, size_t length, size_t *nc_off, + unsigned char *nonce_counter, unsigned char *stream_block, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_aes_crypt_ctr( (mbedtls_aes_context *) ctx, length, nc_off, nonce_counter, + stream_block, input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_CIPHER_MODE_XTS) +static int aes_crypt_xts_wrap( void *ctx, mbedtls_operation_t operation, + size_t length, + const unsigned char data_unit[16], + const unsigned char *input, + unsigned char *output ) +{ + mbedtls_aes_xts_context *xts_ctx = ctx; + int mode; + + switch( operation ) + { + case MBEDTLS_ENCRYPT: + mode = MBEDTLS_AES_ENCRYPT; + break; + case MBEDTLS_DECRYPT: + mode = MBEDTLS_AES_DECRYPT; + break; + default: + return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA; + } + + return mbedtls_aes_crypt_xts( xts_ctx, mode, length, + data_unit, input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +static int aes_setkey_dec_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_aes_setkey_dec( (mbedtls_aes_context *) ctx, key, key_bitlen ); +} + +static int aes_setkey_enc_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_aes_setkey_enc( (mbedtls_aes_context *) ctx, key, key_bitlen ); +} + +static void * aes_ctx_alloc( void ) +{ + mbedtls_aes_context *aes = mbedtls_calloc( 1, sizeof( mbedtls_aes_context ) ); + + if( aes == NULL ) + return( NULL ); + + mbedtls_aes_init( aes ); + + return( aes ); +} + +static void aes_ctx_free( void *ctx ) +{ + mbedtls_aes_free( (mbedtls_aes_context *) ctx ); + mbedtls_free( ctx ); +} + +static const mbedtls_cipher_base_t aes_info = { + MBEDTLS_CIPHER_ID_AES, + aes_crypt_ecb_wrap, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + aes_crypt_cbc_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + aes_crypt_cfb128_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + aes_crypt_ofb_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + aes_crypt_ctr_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + aes_setkey_enc_wrap, + aes_setkey_dec_wrap, + aes_ctx_alloc, + aes_ctx_free +}; + +static const mbedtls_cipher_info_t aes_128_ecb_info = { + MBEDTLS_CIPHER_AES_128_ECB, + MBEDTLS_MODE_ECB, + 128, + "AES-128-ECB", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_192_ecb_info = { + MBEDTLS_CIPHER_AES_192_ECB, + MBEDTLS_MODE_ECB, + 192, + "AES-192-ECB", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_256_ecb_info = { + MBEDTLS_CIPHER_AES_256_ECB, + MBEDTLS_MODE_ECB, + 256, + "AES-256-ECB", + 16, + 0, + 16, + &aes_info +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const mbedtls_cipher_info_t aes_128_cbc_info = { + MBEDTLS_CIPHER_AES_128_CBC, + MBEDTLS_MODE_CBC, + 128, + "AES-128-CBC", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_192_cbc_info = { + MBEDTLS_CIPHER_AES_192_CBC, + MBEDTLS_MODE_CBC, + 192, + "AES-192-CBC", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_256_cbc_info = { + MBEDTLS_CIPHER_AES_256_CBC, + MBEDTLS_MODE_CBC, + 256, + "AES-256-CBC", + 16, + 0, + 16, + &aes_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static const mbedtls_cipher_info_t aes_128_cfb128_info = { + MBEDTLS_CIPHER_AES_128_CFB128, + MBEDTLS_MODE_CFB, + 128, + "AES-128-CFB128", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_192_cfb128_info = { + MBEDTLS_CIPHER_AES_192_CFB128, + MBEDTLS_MODE_CFB, + 192, + "AES-192-CFB128", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_256_cfb128_info = { + MBEDTLS_CIPHER_AES_256_CFB128, + MBEDTLS_MODE_CFB, + 256, + "AES-256-CFB128", + 16, + 0, + 16, + &aes_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_OFB) +static const mbedtls_cipher_info_t aes_128_ofb_info = { + MBEDTLS_CIPHER_AES_128_OFB, + MBEDTLS_MODE_OFB, + 128, + "AES-128-OFB", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_192_ofb_info = { + MBEDTLS_CIPHER_AES_192_OFB, + MBEDTLS_MODE_OFB, + 192, + "AES-192-OFB", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_256_ofb_info = { + MBEDTLS_CIPHER_AES_256_OFB, + MBEDTLS_MODE_OFB, + 256, + "AES-256-OFB", + 16, + 0, + 16, + &aes_info +}; +#endif /* MBEDTLS_CIPHER_MODE_OFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static const mbedtls_cipher_info_t aes_128_ctr_info = { + MBEDTLS_CIPHER_AES_128_CTR, + MBEDTLS_MODE_CTR, + 128, + "AES-128-CTR", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_192_ctr_info = { + MBEDTLS_CIPHER_AES_192_CTR, + MBEDTLS_MODE_CTR, + 192, + "AES-192-CTR", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_256_ctr_info = { + MBEDTLS_CIPHER_AES_256_CTR, + MBEDTLS_MODE_CTR, + 256, + "AES-256-CTR", + 16, + 0, + 16, + &aes_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_CIPHER_MODE_XTS) +static int xts_aes_setkey_enc_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + mbedtls_aes_xts_context *xts_ctx = ctx; + return( mbedtls_aes_xts_setkey_enc( xts_ctx, key, key_bitlen ) ); +} + +static int xts_aes_setkey_dec_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + mbedtls_aes_xts_context *xts_ctx = ctx; + return( mbedtls_aes_xts_setkey_dec( xts_ctx, key, key_bitlen ) ); +} + +static void *xts_aes_ctx_alloc( void ) +{ + mbedtls_aes_xts_context *xts_ctx = mbedtls_calloc( 1, sizeof( *xts_ctx ) ); + + if( xts_ctx != NULL ) + mbedtls_aes_xts_init( xts_ctx ); + + return( xts_ctx ); +} + +static void xts_aes_ctx_free( void *ctx ) +{ + mbedtls_aes_xts_context *xts_ctx = ctx; + + if( xts_ctx == NULL ) + return; + + mbedtls_aes_xts_free( xts_ctx ); + mbedtls_free( xts_ctx ); +} + +static const mbedtls_cipher_base_t xts_aes_info = { + MBEDTLS_CIPHER_ID_AES, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + aes_crypt_xts_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + xts_aes_setkey_enc_wrap, + xts_aes_setkey_dec_wrap, + xts_aes_ctx_alloc, + xts_aes_ctx_free +}; + +static const mbedtls_cipher_info_t aes_128_xts_info = { + MBEDTLS_CIPHER_AES_128_XTS, + MBEDTLS_MODE_XTS, + 256, + "AES-128-XTS", + 16, + 0, + 16, + &xts_aes_info +}; + +static const mbedtls_cipher_info_t aes_256_xts_info = { + MBEDTLS_CIPHER_AES_256_XTS, + MBEDTLS_MODE_XTS, + 512, + "AES-256-XTS", + 16, + 0, + 16, + &xts_aes_info +}; +#endif /* MBEDTLS_CIPHER_MODE_XTS */ + +#if defined(MBEDTLS_GCM_C) +static int gcm_aes_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_gcm_setkey( (mbedtls_gcm_context *) ctx, MBEDTLS_CIPHER_ID_AES, + key, key_bitlen ); +} + +static const mbedtls_cipher_base_t gcm_aes_info = { + MBEDTLS_CIPHER_ID_AES, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + gcm_aes_setkey_wrap, + gcm_aes_setkey_wrap, + gcm_ctx_alloc, + gcm_ctx_free, +}; + +static const mbedtls_cipher_info_t aes_128_gcm_info = { + MBEDTLS_CIPHER_AES_128_GCM, + MBEDTLS_MODE_GCM, + 128, + "AES-128-GCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &gcm_aes_info +}; + +static const mbedtls_cipher_info_t aes_192_gcm_info = { + MBEDTLS_CIPHER_AES_192_GCM, + MBEDTLS_MODE_GCM, + 192, + "AES-192-GCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &gcm_aes_info +}; + +static const mbedtls_cipher_info_t aes_256_gcm_info = { + MBEDTLS_CIPHER_AES_256_GCM, + MBEDTLS_MODE_GCM, + 256, + "AES-256-GCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &gcm_aes_info +}; +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CCM_C) +static int ccm_aes_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_ccm_setkey( (mbedtls_ccm_context *) ctx, MBEDTLS_CIPHER_ID_AES, + key, key_bitlen ); +} + +static const mbedtls_cipher_base_t ccm_aes_info = { + MBEDTLS_CIPHER_ID_AES, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + ccm_aes_setkey_wrap, + ccm_aes_setkey_wrap, + ccm_ctx_alloc, + ccm_ctx_free, +}; + +static const mbedtls_cipher_info_t aes_128_ccm_info = { + MBEDTLS_CIPHER_AES_128_CCM, + MBEDTLS_MODE_CCM, + 128, + "AES-128-CCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &ccm_aes_info +}; + +static const mbedtls_cipher_info_t aes_192_ccm_info = { + MBEDTLS_CIPHER_AES_192_CCM, + MBEDTLS_MODE_CCM, + 192, + "AES-192-CCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &ccm_aes_info +}; + +static const mbedtls_cipher_info_t aes_256_ccm_info = { + MBEDTLS_CIPHER_AES_256_CCM, + MBEDTLS_MODE_CCM, + 256, + "AES-256-CCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &ccm_aes_info +}; +#endif /* MBEDTLS_CCM_C */ + +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) + +static int camellia_crypt_ecb_wrap( void *ctx, mbedtls_operation_t operation, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_camellia_crypt_ecb( (mbedtls_camellia_context *) ctx, operation, input, + output ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static int camellia_crypt_cbc_wrap( void *ctx, mbedtls_operation_t operation, + size_t length, unsigned char *iv, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_camellia_crypt_cbc( (mbedtls_camellia_context *) ctx, operation, length, iv, + input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static int camellia_crypt_cfb128_wrap( void *ctx, mbedtls_operation_t operation, + size_t length, size_t *iv_off, unsigned char *iv, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_camellia_crypt_cfb128( (mbedtls_camellia_context *) ctx, operation, length, + iv_off, iv, input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static int camellia_crypt_ctr_wrap( void *ctx, size_t length, size_t *nc_off, + unsigned char *nonce_counter, unsigned char *stream_block, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_camellia_crypt_ctr( (mbedtls_camellia_context *) ctx, length, nc_off, + nonce_counter, stream_block, input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +static int camellia_setkey_dec_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_camellia_setkey_dec( (mbedtls_camellia_context *) ctx, key, key_bitlen ); +} + +static int camellia_setkey_enc_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_camellia_setkey_enc( (mbedtls_camellia_context *) ctx, key, key_bitlen ); +} + +static void * camellia_ctx_alloc( void ) +{ + mbedtls_camellia_context *ctx; + ctx = mbedtls_calloc( 1, sizeof( mbedtls_camellia_context ) ); + + if( ctx == NULL ) + return( NULL ); + + mbedtls_camellia_init( ctx ); + + return( ctx ); +} + +static void camellia_ctx_free( void *ctx ) +{ + mbedtls_camellia_free( (mbedtls_camellia_context *) ctx ); + mbedtls_free( ctx ); +} + +static const mbedtls_cipher_base_t camellia_info = { + MBEDTLS_CIPHER_ID_CAMELLIA, + camellia_crypt_ecb_wrap, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + camellia_crypt_cbc_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + camellia_crypt_cfb128_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + camellia_crypt_ctr_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + camellia_setkey_enc_wrap, + camellia_setkey_dec_wrap, + camellia_ctx_alloc, + camellia_ctx_free +}; + +static const mbedtls_cipher_info_t camellia_128_ecb_info = { + MBEDTLS_CIPHER_CAMELLIA_128_ECB, + MBEDTLS_MODE_ECB, + 128, + "CAMELLIA-128-ECB", + 16, + 0, + 16, + &camellia_info +}; + +static const mbedtls_cipher_info_t camellia_192_ecb_info = { + MBEDTLS_CIPHER_CAMELLIA_192_ECB, + MBEDTLS_MODE_ECB, + 192, + "CAMELLIA-192-ECB", + 16, + 0, + 16, + &camellia_info +}; + +static const mbedtls_cipher_info_t camellia_256_ecb_info = { + MBEDTLS_CIPHER_CAMELLIA_256_ECB, + MBEDTLS_MODE_ECB, + 256, + "CAMELLIA-256-ECB", + 16, + 0, + 16, + &camellia_info +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const mbedtls_cipher_info_t camellia_128_cbc_info = { + MBEDTLS_CIPHER_CAMELLIA_128_CBC, + MBEDTLS_MODE_CBC, + 128, + "CAMELLIA-128-CBC", + 16, + 0, + 16, + &camellia_info +}; + +static const mbedtls_cipher_info_t camellia_192_cbc_info = { + MBEDTLS_CIPHER_CAMELLIA_192_CBC, + MBEDTLS_MODE_CBC, + 192, + "CAMELLIA-192-CBC", + 16, + 0, + 16, + &camellia_info +}; + +static const mbedtls_cipher_info_t camellia_256_cbc_info = { + MBEDTLS_CIPHER_CAMELLIA_256_CBC, + MBEDTLS_MODE_CBC, + 256, + "CAMELLIA-256-CBC", + 16, + 0, + 16, + &camellia_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static const mbedtls_cipher_info_t camellia_128_cfb128_info = { + MBEDTLS_CIPHER_CAMELLIA_128_CFB128, + MBEDTLS_MODE_CFB, + 128, + "CAMELLIA-128-CFB128", + 16, + 0, + 16, + &camellia_info +}; + +static const mbedtls_cipher_info_t camellia_192_cfb128_info = { + MBEDTLS_CIPHER_CAMELLIA_192_CFB128, + MBEDTLS_MODE_CFB, + 192, + "CAMELLIA-192-CFB128", + 16, + 0, + 16, + &camellia_info +}; + +static const mbedtls_cipher_info_t camellia_256_cfb128_info = { + MBEDTLS_CIPHER_CAMELLIA_256_CFB128, + MBEDTLS_MODE_CFB, + 256, + "CAMELLIA-256-CFB128", + 16, + 0, + 16, + &camellia_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static const mbedtls_cipher_info_t camellia_128_ctr_info = { + MBEDTLS_CIPHER_CAMELLIA_128_CTR, + MBEDTLS_MODE_CTR, + 128, + "CAMELLIA-128-CTR", + 16, + 0, + 16, + &camellia_info +}; + +static const mbedtls_cipher_info_t camellia_192_ctr_info = { + MBEDTLS_CIPHER_CAMELLIA_192_CTR, + MBEDTLS_MODE_CTR, + 192, + "CAMELLIA-192-CTR", + 16, + 0, + 16, + &camellia_info +}; + +static const mbedtls_cipher_info_t camellia_256_ctr_info = { + MBEDTLS_CIPHER_CAMELLIA_256_CTR, + MBEDTLS_MODE_CTR, + 256, + "CAMELLIA-256-CTR", + 16, + 0, + 16, + &camellia_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_GCM_C) +static int gcm_camellia_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_gcm_setkey( (mbedtls_gcm_context *) ctx, MBEDTLS_CIPHER_ID_CAMELLIA, + key, key_bitlen ); +} + +static const mbedtls_cipher_base_t gcm_camellia_info = { + MBEDTLS_CIPHER_ID_CAMELLIA, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + gcm_camellia_setkey_wrap, + gcm_camellia_setkey_wrap, + gcm_ctx_alloc, + gcm_ctx_free, +}; + +static const mbedtls_cipher_info_t camellia_128_gcm_info = { + MBEDTLS_CIPHER_CAMELLIA_128_GCM, + MBEDTLS_MODE_GCM, + 128, + "CAMELLIA-128-GCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &gcm_camellia_info +}; + +static const mbedtls_cipher_info_t camellia_192_gcm_info = { + MBEDTLS_CIPHER_CAMELLIA_192_GCM, + MBEDTLS_MODE_GCM, + 192, + "CAMELLIA-192-GCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &gcm_camellia_info +}; + +static const mbedtls_cipher_info_t camellia_256_gcm_info = { + MBEDTLS_CIPHER_CAMELLIA_256_GCM, + MBEDTLS_MODE_GCM, + 256, + "CAMELLIA-256-GCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &gcm_camellia_info +}; +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CCM_C) +static int ccm_camellia_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_ccm_setkey( (mbedtls_ccm_context *) ctx, MBEDTLS_CIPHER_ID_CAMELLIA, + key, key_bitlen ); +} + +static const mbedtls_cipher_base_t ccm_camellia_info = { + MBEDTLS_CIPHER_ID_CAMELLIA, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + ccm_camellia_setkey_wrap, + ccm_camellia_setkey_wrap, + ccm_ctx_alloc, + ccm_ctx_free, +}; + +static const mbedtls_cipher_info_t camellia_128_ccm_info = { + MBEDTLS_CIPHER_CAMELLIA_128_CCM, + MBEDTLS_MODE_CCM, + 128, + "CAMELLIA-128-CCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &ccm_camellia_info +}; + +static const mbedtls_cipher_info_t camellia_192_ccm_info = { + MBEDTLS_CIPHER_CAMELLIA_192_CCM, + MBEDTLS_MODE_CCM, + 192, + "CAMELLIA-192-CCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &ccm_camellia_info +}; + +static const mbedtls_cipher_info_t camellia_256_ccm_info = { + MBEDTLS_CIPHER_CAMELLIA_256_CCM, + MBEDTLS_MODE_CCM, + 256, + "CAMELLIA-256-CCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &ccm_camellia_info +}; +#endif /* MBEDTLS_CCM_C */ + +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_ARIA_C) + +static int aria_crypt_ecb_wrap( void *ctx, mbedtls_operation_t operation, + const unsigned char *input, unsigned char *output ) +{ + (void) operation; + return mbedtls_aria_crypt_ecb( (mbedtls_aria_context *) ctx, input, + output ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static int aria_crypt_cbc_wrap( void *ctx, mbedtls_operation_t operation, + size_t length, unsigned char *iv, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_aria_crypt_cbc( (mbedtls_aria_context *) ctx, operation, length, iv, + input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static int aria_crypt_cfb128_wrap( void *ctx, mbedtls_operation_t operation, + size_t length, size_t *iv_off, unsigned char *iv, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_aria_crypt_cfb128( (mbedtls_aria_context *) ctx, operation, length, + iv_off, iv, input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static int aria_crypt_ctr_wrap( void *ctx, size_t length, size_t *nc_off, + unsigned char *nonce_counter, unsigned char *stream_block, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_aria_crypt_ctr( (mbedtls_aria_context *) ctx, length, nc_off, + nonce_counter, stream_block, input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +static int aria_setkey_dec_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_aria_setkey_dec( (mbedtls_aria_context *) ctx, key, key_bitlen ); +} + +static int aria_setkey_enc_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_aria_setkey_enc( (mbedtls_aria_context *) ctx, key, key_bitlen ); +} + +static void * aria_ctx_alloc( void ) +{ + mbedtls_aria_context *ctx; + ctx = mbedtls_calloc( 1, sizeof( mbedtls_aria_context ) ); + + if( ctx == NULL ) + return( NULL ); + + mbedtls_aria_init( ctx ); + + return( ctx ); +} + +static void aria_ctx_free( void *ctx ) +{ + mbedtls_aria_free( (mbedtls_aria_context *) ctx ); + mbedtls_free( ctx ); +} + +static const mbedtls_cipher_base_t aria_info = { + MBEDTLS_CIPHER_ID_ARIA, + aria_crypt_ecb_wrap, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + aria_crypt_cbc_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + aria_crypt_cfb128_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + aria_crypt_ctr_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + aria_setkey_enc_wrap, + aria_setkey_dec_wrap, + aria_ctx_alloc, + aria_ctx_free +}; + +static const mbedtls_cipher_info_t aria_128_ecb_info = { + MBEDTLS_CIPHER_ARIA_128_ECB, + MBEDTLS_MODE_ECB, + 128, + "ARIA-128-ECB", + 16, + 0, + 16, + &aria_info +}; + +static const mbedtls_cipher_info_t aria_192_ecb_info = { + MBEDTLS_CIPHER_ARIA_192_ECB, + MBEDTLS_MODE_ECB, + 192, + "ARIA-192-ECB", + 16, + 0, + 16, + &aria_info +}; + +static const mbedtls_cipher_info_t aria_256_ecb_info = { + MBEDTLS_CIPHER_ARIA_256_ECB, + MBEDTLS_MODE_ECB, + 256, + "ARIA-256-ECB", + 16, + 0, + 16, + &aria_info +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const mbedtls_cipher_info_t aria_128_cbc_info = { + MBEDTLS_CIPHER_ARIA_128_CBC, + MBEDTLS_MODE_CBC, + 128, + "ARIA-128-CBC", + 16, + 0, + 16, + &aria_info +}; + +static const mbedtls_cipher_info_t aria_192_cbc_info = { + MBEDTLS_CIPHER_ARIA_192_CBC, + MBEDTLS_MODE_CBC, + 192, + "ARIA-192-CBC", + 16, + 0, + 16, + &aria_info +}; + +static const mbedtls_cipher_info_t aria_256_cbc_info = { + MBEDTLS_CIPHER_ARIA_256_CBC, + MBEDTLS_MODE_CBC, + 256, + "ARIA-256-CBC", + 16, + 0, + 16, + &aria_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static const mbedtls_cipher_info_t aria_128_cfb128_info = { + MBEDTLS_CIPHER_ARIA_128_CFB128, + MBEDTLS_MODE_CFB, + 128, + "ARIA-128-CFB128", + 16, + 0, + 16, + &aria_info +}; + +static const mbedtls_cipher_info_t aria_192_cfb128_info = { + MBEDTLS_CIPHER_ARIA_192_CFB128, + MBEDTLS_MODE_CFB, + 192, + "ARIA-192-CFB128", + 16, + 0, + 16, + &aria_info +}; + +static const mbedtls_cipher_info_t aria_256_cfb128_info = { + MBEDTLS_CIPHER_ARIA_256_CFB128, + MBEDTLS_MODE_CFB, + 256, + "ARIA-256-CFB128", + 16, + 0, + 16, + &aria_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static const mbedtls_cipher_info_t aria_128_ctr_info = { + MBEDTLS_CIPHER_ARIA_128_CTR, + MBEDTLS_MODE_CTR, + 128, + "ARIA-128-CTR", + 16, + 0, + 16, + &aria_info +}; + +static const mbedtls_cipher_info_t aria_192_ctr_info = { + MBEDTLS_CIPHER_ARIA_192_CTR, + MBEDTLS_MODE_CTR, + 192, + "ARIA-192-CTR", + 16, + 0, + 16, + &aria_info +}; + +static const mbedtls_cipher_info_t aria_256_ctr_info = { + MBEDTLS_CIPHER_ARIA_256_CTR, + MBEDTLS_MODE_CTR, + 256, + "ARIA-256-CTR", + 16, + 0, + 16, + &aria_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_GCM_C) +static int gcm_aria_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_gcm_setkey( (mbedtls_gcm_context *) ctx, MBEDTLS_CIPHER_ID_ARIA, + key, key_bitlen ); +} + +static const mbedtls_cipher_base_t gcm_aria_info = { + MBEDTLS_CIPHER_ID_ARIA, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + gcm_aria_setkey_wrap, + gcm_aria_setkey_wrap, + gcm_ctx_alloc, + gcm_ctx_free, +}; + +static const mbedtls_cipher_info_t aria_128_gcm_info = { + MBEDTLS_CIPHER_ARIA_128_GCM, + MBEDTLS_MODE_GCM, + 128, + "ARIA-128-GCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &gcm_aria_info +}; + +static const mbedtls_cipher_info_t aria_192_gcm_info = { + MBEDTLS_CIPHER_ARIA_192_GCM, + MBEDTLS_MODE_GCM, + 192, + "ARIA-192-GCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &gcm_aria_info +}; + +static const mbedtls_cipher_info_t aria_256_gcm_info = { + MBEDTLS_CIPHER_ARIA_256_GCM, + MBEDTLS_MODE_GCM, + 256, + "ARIA-256-GCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &gcm_aria_info +}; +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CCM_C) +static int ccm_aria_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_ccm_setkey( (mbedtls_ccm_context *) ctx, MBEDTLS_CIPHER_ID_ARIA, + key, key_bitlen ); +} + +static const mbedtls_cipher_base_t ccm_aria_info = { + MBEDTLS_CIPHER_ID_ARIA, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + ccm_aria_setkey_wrap, + ccm_aria_setkey_wrap, + ccm_ctx_alloc, + ccm_ctx_free, +}; + +static const mbedtls_cipher_info_t aria_128_ccm_info = { + MBEDTLS_CIPHER_ARIA_128_CCM, + MBEDTLS_MODE_CCM, + 128, + "ARIA-128-CCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &ccm_aria_info +}; + +static const mbedtls_cipher_info_t aria_192_ccm_info = { + MBEDTLS_CIPHER_ARIA_192_CCM, + MBEDTLS_MODE_CCM, + 192, + "ARIA-192-CCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &ccm_aria_info +}; + +static const mbedtls_cipher_info_t aria_256_ccm_info = { + MBEDTLS_CIPHER_ARIA_256_CCM, + MBEDTLS_MODE_CCM, + 256, + "ARIA-256-CCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &ccm_aria_info +}; +#endif /* MBEDTLS_CCM_C */ + +#endif /* MBEDTLS_ARIA_C */ + +#if defined(MBEDTLS_DES_C) + +static int des_crypt_ecb_wrap( void *ctx, mbedtls_operation_t operation, + const unsigned char *input, unsigned char *output ) +{ + ((void) operation); + return mbedtls_des_crypt_ecb( (mbedtls_des_context *) ctx, input, output ); +} + +static int des3_crypt_ecb_wrap( void *ctx, mbedtls_operation_t operation, + const unsigned char *input, unsigned char *output ) +{ + ((void) operation); + return mbedtls_des3_crypt_ecb( (mbedtls_des3_context *) ctx, input, output ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static int des_crypt_cbc_wrap( void *ctx, mbedtls_operation_t operation, size_t length, + unsigned char *iv, const unsigned char *input, unsigned char *output ) +{ + return mbedtls_des_crypt_cbc( (mbedtls_des_context *) ctx, operation, length, iv, input, + output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static int des3_crypt_cbc_wrap( void *ctx, mbedtls_operation_t operation, size_t length, + unsigned char *iv, const unsigned char *input, unsigned char *output ) +{ + return mbedtls_des3_crypt_cbc( (mbedtls_des3_context *) ctx, operation, length, iv, input, + output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +static int des_setkey_dec_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + ((void) key_bitlen); + + return mbedtls_des_setkey_dec( (mbedtls_des_context *) ctx, key ); +} + +static int des_setkey_enc_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + ((void) key_bitlen); + + return mbedtls_des_setkey_enc( (mbedtls_des_context *) ctx, key ); +} + +static int des3_set2key_dec_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + ((void) key_bitlen); + + return mbedtls_des3_set2key_dec( (mbedtls_des3_context *) ctx, key ); +} + +static int des3_set2key_enc_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + ((void) key_bitlen); + + return mbedtls_des3_set2key_enc( (mbedtls_des3_context *) ctx, key ); +} + +static int des3_set3key_dec_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + ((void) key_bitlen); + + return mbedtls_des3_set3key_dec( (mbedtls_des3_context *) ctx, key ); +} + +static int des3_set3key_enc_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + ((void) key_bitlen); + + return mbedtls_des3_set3key_enc( (mbedtls_des3_context *) ctx, key ); +} + +static void * des_ctx_alloc( void ) +{ + mbedtls_des_context *des = mbedtls_calloc( 1, sizeof( mbedtls_des_context ) ); + + if( des == NULL ) + return( NULL ); + + mbedtls_des_init( des ); + + return( des ); +} + +static void des_ctx_free( void *ctx ) +{ + mbedtls_des_free( (mbedtls_des_context *) ctx ); + mbedtls_free( ctx ); +} + +static void * des3_ctx_alloc( void ) +{ + mbedtls_des3_context *des3; + des3 = mbedtls_calloc( 1, sizeof( mbedtls_des3_context ) ); + + if( des3 == NULL ) + return( NULL ); + + mbedtls_des3_init( des3 ); + + return( des3 ); +} + +static void des3_ctx_free( void *ctx ) +{ + mbedtls_des3_free( (mbedtls_des3_context *) ctx ); + mbedtls_free( ctx ); +} + +static const mbedtls_cipher_base_t des_info = { + MBEDTLS_CIPHER_ID_DES, + des_crypt_ecb_wrap, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + des_crypt_cbc_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + des_setkey_enc_wrap, + des_setkey_dec_wrap, + des_ctx_alloc, + des_ctx_free +}; + +static const mbedtls_cipher_info_t des_ecb_info = { + MBEDTLS_CIPHER_DES_ECB, + MBEDTLS_MODE_ECB, + MBEDTLS_KEY_LENGTH_DES, + "DES-ECB", + 8, + 0, + 8, + &des_info +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const mbedtls_cipher_info_t des_cbc_info = { + MBEDTLS_CIPHER_DES_CBC, + MBEDTLS_MODE_CBC, + MBEDTLS_KEY_LENGTH_DES, + "DES-CBC", + 8, + 0, + 8, + &des_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +static const mbedtls_cipher_base_t des_ede_info = { + MBEDTLS_CIPHER_ID_DES, + des3_crypt_ecb_wrap, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + des3_crypt_cbc_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + des3_set2key_enc_wrap, + des3_set2key_dec_wrap, + des3_ctx_alloc, + des3_ctx_free +}; + +static const mbedtls_cipher_info_t des_ede_ecb_info = { + MBEDTLS_CIPHER_DES_EDE_ECB, + MBEDTLS_MODE_ECB, + MBEDTLS_KEY_LENGTH_DES_EDE, + "DES-EDE-ECB", + 8, + 0, + 8, + &des_ede_info +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const mbedtls_cipher_info_t des_ede_cbc_info = { + MBEDTLS_CIPHER_DES_EDE_CBC, + MBEDTLS_MODE_CBC, + MBEDTLS_KEY_LENGTH_DES_EDE, + "DES-EDE-CBC", + 8, + 0, + 8, + &des_ede_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +static const mbedtls_cipher_base_t des_ede3_info = { + MBEDTLS_CIPHER_ID_3DES, + des3_crypt_ecb_wrap, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + des3_crypt_cbc_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + des3_set3key_enc_wrap, + des3_set3key_dec_wrap, + des3_ctx_alloc, + des3_ctx_free +}; + +static const mbedtls_cipher_info_t des_ede3_ecb_info = { + MBEDTLS_CIPHER_DES_EDE3_ECB, + MBEDTLS_MODE_ECB, + MBEDTLS_KEY_LENGTH_DES_EDE3, + "DES-EDE3-ECB", + 8, + 0, + 8, + &des_ede3_info +}; +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const mbedtls_cipher_info_t des_ede3_cbc_info = { + MBEDTLS_CIPHER_DES_EDE3_CBC, + MBEDTLS_MODE_CBC, + MBEDTLS_KEY_LENGTH_DES_EDE3, + "DES-EDE3-CBC", + 8, + 0, + 8, + &des_ede3_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_BLOWFISH_C) + +static int blowfish_crypt_ecb_wrap( void *ctx, mbedtls_operation_t operation, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_blowfish_crypt_ecb( (mbedtls_blowfish_context *) ctx, operation, input, + output ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static int blowfish_crypt_cbc_wrap( void *ctx, mbedtls_operation_t operation, + size_t length, unsigned char *iv, const unsigned char *input, + unsigned char *output ) +{ + return mbedtls_blowfish_crypt_cbc( (mbedtls_blowfish_context *) ctx, operation, length, iv, + input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static int blowfish_crypt_cfb64_wrap( void *ctx, mbedtls_operation_t operation, + size_t length, size_t *iv_off, unsigned char *iv, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_blowfish_crypt_cfb64( (mbedtls_blowfish_context *) ctx, operation, length, + iv_off, iv, input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static int blowfish_crypt_ctr_wrap( void *ctx, size_t length, size_t *nc_off, + unsigned char *nonce_counter, unsigned char *stream_block, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_blowfish_crypt_ctr( (mbedtls_blowfish_context *) ctx, length, nc_off, + nonce_counter, stream_block, input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +static int blowfish_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_blowfish_setkey( (mbedtls_blowfish_context *) ctx, key, key_bitlen ); +} + +static void * blowfish_ctx_alloc( void ) +{ + mbedtls_blowfish_context *ctx; + ctx = mbedtls_calloc( 1, sizeof( mbedtls_blowfish_context ) ); + + if( ctx == NULL ) + return( NULL ); + + mbedtls_blowfish_init( ctx ); + + return( ctx ); +} + +static void blowfish_ctx_free( void *ctx ) +{ + mbedtls_blowfish_free( (mbedtls_blowfish_context *) ctx ); + mbedtls_free( ctx ); +} + +static const mbedtls_cipher_base_t blowfish_info = { + MBEDTLS_CIPHER_ID_BLOWFISH, + blowfish_crypt_ecb_wrap, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + blowfish_crypt_cbc_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + blowfish_crypt_cfb64_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + blowfish_crypt_ctr_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + blowfish_setkey_wrap, + blowfish_setkey_wrap, + blowfish_ctx_alloc, + blowfish_ctx_free +}; + +static const mbedtls_cipher_info_t blowfish_ecb_info = { + MBEDTLS_CIPHER_BLOWFISH_ECB, + MBEDTLS_MODE_ECB, + 128, + "BLOWFISH-ECB", + 8, + MBEDTLS_CIPHER_VARIABLE_KEY_LEN, + 8, + &blowfish_info +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const mbedtls_cipher_info_t blowfish_cbc_info = { + MBEDTLS_CIPHER_BLOWFISH_CBC, + MBEDTLS_MODE_CBC, + 128, + "BLOWFISH-CBC", + 8, + MBEDTLS_CIPHER_VARIABLE_KEY_LEN, + 8, + &blowfish_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static const mbedtls_cipher_info_t blowfish_cfb64_info = { + MBEDTLS_CIPHER_BLOWFISH_CFB64, + MBEDTLS_MODE_CFB, + 128, + "BLOWFISH-CFB64", + 8, + MBEDTLS_CIPHER_VARIABLE_KEY_LEN, + 8, + &blowfish_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static const mbedtls_cipher_info_t blowfish_ctr_info = { + MBEDTLS_CIPHER_BLOWFISH_CTR, + MBEDTLS_MODE_CTR, + 128, + "BLOWFISH-CTR", + 8, + MBEDTLS_CIPHER_VARIABLE_KEY_LEN, + 8, + &blowfish_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CTR */ +#endif /* MBEDTLS_BLOWFISH_C */ + +#if defined(MBEDTLS_ARC4_C) +static int arc4_crypt_stream_wrap( void *ctx, size_t length, + const unsigned char *input, + unsigned char *output ) +{ + return( mbedtls_arc4_crypt( (mbedtls_arc4_context *) ctx, length, input, output ) ); +} + +static int arc4_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + /* we get key_bitlen in bits, arc4 expects it in bytes */ + if( key_bitlen % 8 != 0 ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + mbedtls_arc4_setup( (mbedtls_arc4_context *) ctx, key, key_bitlen / 8 ); + return( 0 ); +} + +static void * arc4_ctx_alloc( void ) +{ + mbedtls_arc4_context *ctx; + ctx = mbedtls_calloc( 1, sizeof( mbedtls_arc4_context ) ); + + if( ctx == NULL ) + return( NULL ); + + mbedtls_arc4_init( ctx ); + + return( ctx ); +} + +static void arc4_ctx_free( void *ctx ) +{ + mbedtls_arc4_free( (mbedtls_arc4_context *) ctx ); + mbedtls_free( ctx ); +} + +static const mbedtls_cipher_base_t arc4_base_info = { + MBEDTLS_CIPHER_ID_ARC4, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + arc4_crypt_stream_wrap, +#endif + arc4_setkey_wrap, + arc4_setkey_wrap, + arc4_ctx_alloc, + arc4_ctx_free +}; + +static const mbedtls_cipher_info_t arc4_128_info = { + MBEDTLS_CIPHER_ARC4_128, + MBEDTLS_MODE_STREAM, + 128, + "ARC4-128", + 0, + 0, + 1, + &arc4_base_info +}; +#endif /* MBEDTLS_ARC4_C */ + +#if defined(MBEDTLS_CHACHA20_C) + +static int chacha20_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + if( key_bitlen != 256U ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + if ( 0 != mbedtls_chacha20_setkey( (mbedtls_chacha20_context*)ctx, key ) ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + return( 0 ); +} + +static int chacha20_stream_wrap( void *ctx, size_t length, + const unsigned char *input, + unsigned char *output ) +{ + int ret; + + ret = mbedtls_chacha20_update( ctx, length, input, output ); + if( ret == MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + return( ret ); +} + +static void * chacha20_ctx_alloc( void ) +{ + mbedtls_chacha20_context *ctx; + ctx = mbedtls_calloc( 1, sizeof( mbedtls_chacha20_context ) ); + + if( ctx == NULL ) + return( NULL ); + + mbedtls_chacha20_init( ctx ); + + return( ctx ); +} + +static void chacha20_ctx_free( void *ctx ) +{ + mbedtls_chacha20_free( (mbedtls_chacha20_context *) ctx ); + mbedtls_free( ctx ); +} + +static const mbedtls_cipher_base_t chacha20_base_info = { + MBEDTLS_CIPHER_ID_CHACHA20, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + chacha20_stream_wrap, +#endif + chacha20_setkey_wrap, + chacha20_setkey_wrap, + chacha20_ctx_alloc, + chacha20_ctx_free +}; +static const mbedtls_cipher_info_t chacha20_info = { + MBEDTLS_CIPHER_CHACHA20, + MBEDTLS_MODE_STREAM, + 256, + "CHACHA20", + 12, + 0, + 1, + &chacha20_base_info +}; +#endif /* MBEDTLS_CHACHA20_C */ + +#if defined(MBEDTLS_CHACHAPOLY_C) + +static int chachapoly_setkey_wrap( void *ctx, + const unsigned char *key, + unsigned int key_bitlen ) +{ + if( key_bitlen != 256U ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + if ( 0 != mbedtls_chachapoly_setkey( (mbedtls_chachapoly_context*)ctx, key ) ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + return( 0 ); +} + +static void * chachapoly_ctx_alloc( void ) +{ + mbedtls_chachapoly_context *ctx; + ctx = mbedtls_calloc( 1, sizeof( mbedtls_chachapoly_context ) ); + + if( ctx == NULL ) + return( NULL ); + + mbedtls_chachapoly_init( ctx ); + + return( ctx ); +} + +static void chachapoly_ctx_free( void *ctx ) +{ + mbedtls_chachapoly_free( (mbedtls_chachapoly_context *) ctx ); + mbedtls_free( ctx ); +} + +static const mbedtls_cipher_base_t chachapoly_base_info = { + MBEDTLS_CIPHER_ID_CHACHA20, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + chachapoly_setkey_wrap, + chachapoly_setkey_wrap, + chachapoly_ctx_alloc, + chachapoly_ctx_free +}; +static const mbedtls_cipher_info_t chachapoly_info = { + MBEDTLS_CIPHER_CHACHA20_POLY1305, + MBEDTLS_MODE_CHACHAPOLY, + 256, + "CHACHA20-POLY1305", + 12, + 0, + 1, + &chachapoly_base_info +}; +#endif /* MBEDTLS_CHACHAPOLY_C */ + +#if defined(MBEDTLS_CIPHER_NULL_CIPHER) +static int null_crypt_stream( void *ctx, size_t length, + const unsigned char *input, + unsigned char *output ) +{ + ((void) ctx); + memmove( output, input, length ); + return( 0 ); +} + +static int null_setkey( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + ((void) ctx); + ((void) key); + ((void) key_bitlen); + + return( 0 ); +} + +static void * null_ctx_alloc( void ) +{ + return( (void *) 1 ); +} + +static void null_ctx_free( void *ctx ) +{ + ((void) ctx); +} + +static const mbedtls_cipher_base_t null_base_info = { + MBEDTLS_CIPHER_ID_NULL, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + null_crypt_stream, +#endif + null_setkey, + null_setkey, + null_ctx_alloc, + null_ctx_free +}; + +static const mbedtls_cipher_info_t null_cipher_info = { + MBEDTLS_CIPHER_NULL, + MBEDTLS_MODE_STREAM, + 0, + "NULL", + 0, + 0, + 1, + &null_base_info +}; +#endif /* defined(MBEDTLS_CIPHER_NULL_CIPHER) */ + +const mbedtls_cipher_definition_t mbedtls_cipher_definitions[] = +{ +#if defined(MBEDTLS_AES_C) + { MBEDTLS_CIPHER_AES_128_ECB, &aes_128_ecb_info }, + { MBEDTLS_CIPHER_AES_192_ECB, &aes_192_ecb_info }, + { MBEDTLS_CIPHER_AES_256_ECB, &aes_256_ecb_info }, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_CIPHER_AES_128_CBC, &aes_128_cbc_info }, + { MBEDTLS_CIPHER_AES_192_CBC, &aes_192_cbc_info }, + { MBEDTLS_CIPHER_AES_256_CBC, &aes_256_cbc_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + { MBEDTLS_CIPHER_AES_128_CFB128, &aes_128_cfb128_info }, + { MBEDTLS_CIPHER_AES_192_CFB128, &aes_192_cfb128_info }, + { MBEDTLS_CIPHER_AES_256_CFB128, &aes_256_cfb128_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_OFB) + { MBEDTLS_CIPHER_AES_128_OFB, &aes_128_ofb_info }, + { MBEDTLS_CIPHER_AES_192_OFB, &aes_192_ofb_info }, + { MBEDTLS_CIPHER_AES_256_OFB, &aes_256_ofb_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + { MBEDTLS_CIPHER_AES_128_CTR, &aes_128_ctr_info }, + { MBEDTLS_CIPHER_AES_192_CTR, &aes_192_ctr_info }, + { MBEDTLS_CIPHER_AES_256_CTR, &aes_256_ctr_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_XTS) + { MBEDTLS_CIPHER_AES_128_XTS, &aes_128_xts_info }, + { MBEDTLS_CIPHER_AES_256_XTS, &aes_256_xts_info }, +#endif +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_CIPHER_AES_128_GCM, &aes_128_gcm_info }, + { MBEDTLS_CIPHER_AES_192_GCM, &aes_192_gcm_info }, + { MBEDTLS_CIPHER_AES_256_GCM, &aes_256_gcm_info }, +#endif +#if defined(MBEDTLS_CCM_C) + { MBEDTLS_CIPHER_AES_128_CCM, &aes_128_ccm_info }, + { MBEDTLS_CIPHER_AES_192_CCM, &aes_192_ccm_info }, + { MBEDTLS_CIPHER_AES_256_CCM, &aes_256_ccm_info }, +#endif +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_ARC4_C) + { MBEDTLS_CIPHER_ARC4_128, &arc4_128_info }, +#endif + +#if defined(MBEDTLS_BLOWFISH_C) + { MBEDTLS_CIPHER_BLOWFISH_ECB, &blowfish_ecb_info }, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_CIPHER_BLOWFISH_CBC, &blowfish_cbc_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + { MBEDTLS_CIPHER_BLOWFISH_CFB64, &blowfish_cfb64_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + { MBEDTLS_CIPHER_BLOWFISH_CTR, &blowfish_ctr_info }, +#endif +#endif /* MBEDTLS_BLOWFISH_C */ + +#if defined(MBEDTLS_CAMELLIA_C) + { MBEDTLS_CIPHER_CAMELLIA_128_ECB, &camellia_128_ecb_info }, + { MBEDTLS_CIPHER_CAMELLIA_192_ECB, &camellia_192_ecb_info }, + { MBEDTLS_CIPHER_CAMELLIA_256_ECB, &camellia_256_ecb_info }, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_CIPHER_CAMELLIA_128_CBC, &camellia_128_cbc_info }, + { MBEDTLS_CIPHER_CAMELLIA_192_CBC, &camellia_192_cbc_info }, + { MBEDTLS_CIPHER_CAMELLIA_256_CBC, &camellia_256_cbc_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + { MBEDTLS_CIPHER_CAMELLIA_128_CFB128, &camellia_128_cfb128_info }, + { MBEDTLS_CIPHER_CAMELLIA_192_CFB128, &camellia_192_cfb128_info }, + { MBEDTLS_CIPHER_CAMELLIA_256_CFB128, &camellia_256_cfb128_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + { MBEDTLS_CIPHER_CAMELLIA_128_CTR, &camellia_128_ctr_info }, + { MBEDTLS_CIPHER_CAMELLIA_192_CTR, &camellia_192_ctr_info }, + { MBEDTLS_CIPHER_CAMELLIA_256_CTR, &camellia_256_ctr_info }, +#endif +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_CIPHER_CAMELLIA_128_GCM, &camellia_128_gcm_info }, + { MBEDTLS_CIPHER_CAMELLIA_192_GCM, &camellia_192_gcm_info }, + { MBEDTLS_CIPHER_CAMELLIA_256_GCM, &camellia_256_gcm_info }, +#endif +#if defined(MBEDTLS_CCM_C) + { MBEDTLS_CIPHER_CAMELLIA_128_CCM, &camellia_128_ccm_info }, + { MBEDTLS_CIPHER_CAMELLIA_192_CCM, &camellia_192_ccm_info }, + { MBEDTLS_CIPHER_CAMELLIA_256_CCM, &camellia_256_ccm_info }, +#endif +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_ARIA_C) + { MBEDTLS_CIPHER_ARIA_128_ECB, &aria_128_ecb_info }, + { MBEDTLS_CIPHER_ARIA_192_ECB, &aria_192_ecb_info }, + { MBEDTLS_CIPHER_ARIA_256_ECB, &aria_256_ecb_info }, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_CIPHER_ARIA_128_CBC, &aria_128_cbc_info }, + { MBEDTLS_CIPHER_ARIA_192_CBC, &aria_192_cbc_info }, + { MBEDTLS_CIPHER_ARIA_256_CBC, &aria_256_cbc_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + { MBEDTLS_CIPHER_ARIA_128_CFB128, &aria_128_cfb128_info }, + { MBEDTLS_CIPHER_ARIA_192_CFB128, &aria_192_cfb128_info }, + { MBEDTLS_CIPHER_ARIA_256_CFB128, &aria_256_cfb128_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + { MBEDTLS_CIPHER_ARIA_128_CTR, &aria_128_ctr_info }, + { MBEDTLS_CIPHER_ARIA_192_CTR, &aria_192_ctr_info }, + { MBEDTLS_CIPHER_ARIA_256_CTR, &aria_256_ctr_info }, +#endif +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_CIPHER_ARIA_128_GCM, &aria_128_gcm_info }, + { MBEDTLS_CIPHER_ARIA_192_GCM, &aria_192_gcm_info }, + { MBEDTLS_CIPHER_ARIA_256_GCM, &aria_256_gcm_info }, +#endif +#if defined(MBEDTLS_CCM_C) + { MBEDTLS_CIPHER_ARIA_128_CCM, &aria_128_ccm_info }, + { MBEDTLS_CIPHER_ARIA_192_CCM, &aria_192_ccm_info }, + { MBEDTLS_CIPHER_ARIA_256_CCM, &aria_256_ccm_info }, +#endif +#endif /* MBEDTLS_ARIA_C */ + +#if defined(MBEDTLS_DES_C) + { MBEDTLS_CIPHER_DES_ECB, &des_ecb_info }, + { MBEDTLS_CIPHER_DES_EDE_ECB, &des_ede_ecb_info }, + { MBEDTLS_CIPHER_DES_EDE3_ECB, &des_ede3_ecb_info }, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_CIPHER_DES_CBC, &des_cbc_info }, + { MBEDTLS_CIPHER_DES_EDE_CBC, &des_ede_cbc_info }, + { MBEDTLS_CIPHER_DES_EDE3_CBC, &des_ede3_cbc_info }, +#endif +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_CHACHA20_C) + { MBEDTLS_CIPHER_CHACHA20, &chacha20_info }, +#endif + +#if defined(MBEDTLS_CHACHAPOLY_C) + { MBEDTLS_CIPHER_CHACHA20_POLY1305, &chachapoly_info }, +#endif + +#if defined(MBEDTLS_CIPHER_NULL_CIPHER) + { MBEDTLS_CIPHER_NULL, &null_cipher_info }, +#endif /* MBEDTLS_CIPHER_NULL_CIPHER */ + + { MBEDTLS_CIPHER_NONE, NULL } +}; + +#define NUM_CIPHERS sizeof mbedtls_cipher_definitions / sizeof mbedtls_cipher_definitions[0] +int mbedtls_cipher_supported[NUM_CIPHERS]; + +#endif /* MBEDTLS_CIPHER_C */ diff --git a/common/mbedtls/cmac.c b/common/mbedtls/cmac.c new file mode 100644 index 00000000..db4a71d7 --- /dev/null +++ b/common/mbedtls/cmac.c @@ -0,0 +1,1080 @@ +/** + * \file cmac.c + * + * \brief NIST SP800-38B compliant CMAC implementation for AES and 3DES + * + * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * References: + * + * - NIST SP 800-38B Recommendation for Block Cipher Modes of Operation: The + * CMAC Mode for Authentication + * http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38b.pdf + * + * - RFC 4493 - The AES-CMAC Algorithm + * https://tools.ietf.org/html/rfc4493 + * + * - RFC 4615 - The Advanced Encryption Standard-Cipher-based Message + * Authentication Code-Pseudo-Random Function-128 (AES-CMAC-PRF-128) + * Algorithm for the Internet Key Exchange Protocol (IKE) + * https://tools.ietf.org/html/rfc4615 + * + * Additional test vectors: ISO/IEC 9797-1 + * + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_CMAC_C) + +#include "mbedtls/cmac.h" +#include "mbedtls/platform_util.h" + +#include + + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#if defined(MBEDTLS_SELF_TEST) +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_SELF_TEST */ +#endif /* MBEDTLS_PLATFORM_C */ + +#if !defined(MBEDTLS_CMAC_ALT) || defined(MBEDTLS_SELF_TEST) + +/* + * Multiplication by u in the Galois field of GF(2^n) + * + * As explained in NIST SP 800-38B, this can be computed: + * + * If MSB(p) = 0, then p = (p << 1) + * If MSB(p) = 1, then p = (p << 1) ^ R_n + * with R_64 = 0x1B and R_128 = 0x87 + * + * Input and output MUST NOT point to the same buffer + * Block size must be 8 bytes or 16 bytes - the block sizes for DES and AES. + */ +static int cmac_multiply_by_u( unsigned char *output, + const unsigned char *input, + size_t blocksize ) +{ + const unsigned char R_128 = 0x87; + const unsigned char R_64 = 0x1B; + unsigned char R_n, mask; + unsigned char overflow = 0x00; + int i; + + if( blocksize == MBEDTLS_AES_BLOCK_SIZE ) + { + R_n = R_128; + } + else if( blocksize == MBEDTLS_DES3_BLOCK_SIZE ) + { + R_n = R_64; + } + else + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + for( i = (int)blocksize - 1; i >= 0; i-- ) + { + output[i] = input[i] << 1 | overflow; + overflow = input[i] >> 7; + } + + /* mask = ( input[0] >> 7 ) ? 0xff : 0x00 + * using bit operations to avoid branches */ + + /* MSVC has a warning about unary minus on unsigned, but this is + * well-defined and precisely what we want to do here */ +#if defined(_MSC_VER) +#pragma warning( push ) +#pragma warning( disable : 4146 ) +#endif + mask = - ( input[0] >> 7 ); +#if defined(_MSC_VER) +#pragma warning( pop ) +#endif + + output[ blocksize - 1 ] ^= R_n & mask; + + return( 0 ); +} + +/* + * Generate subkeys + * + * - as specified by RFC 4493, section 2.3 Subkey Generation Algorithm + */ +static int cmac_generate_subkeys( mbedtls_cipher_context_t *ctx, + unsigned char* K1, unsigned char* K2 ) +{ + int ret; + unsigned char L[MBEDTLS_CIPHER_BLKSIZE_MAX]; + size_t olen, block_size; + + mbedtls_platform_zeroize( L, sizeof( L ) ); + + block_size = ctx->cipher_info->block_size; + + /* Calculate Ek(0) */ + if( ( ret = mbedtls_cipher_update( ctx, L, block_size, L, &olen ) ) != 0 ) + goto exit; + + /* + * Generate K1 and K2 + */ + if( ( ret = cmac_multiply_by_u( K1, L , block_size ) ) != 0 ) + goto exit; + + if( ( ret = cmac_multiply_by_u( K2, K1 , block_size ) ) != 0 ) + goto exit; + +exit: + mbedtls_platform_zeroize( L, sizeof( L ) ); + + return( ret ); +} +#endif /* !defined(MBEDTLS_CMAC_ALT) || defined(MBEDTLS_SELF_TEST) */ + +#if !defined(MBEDTLS_CMAC_ALT) +static void cmac_xor_block( unsigned char *output, const unsigned char *input1, + const unsigned char *input2, + const size_t block_size ) +{ + size_t idx; + + for( idx = 0; idx < block_size; idx++ ) + output[ idx ] = input1[ idx ] ^ input2[ idx ]; +} + +/* + * Create padded last block from (partial) last block. + * + * We can't use the padding option from the cipher layer, as it only works for + * CBC and we use ECB mode, and anyway we need to XOR K1 or K2 in addition. + */ +static void cmac_pad( unsigned char padded_block[MBEDTLS_CIPHER_BLKSIZE_MAX], + size_t padded_block_len, + const unsigned char *last_block, + size_t last_block_len ) +{ + size_t j; + + for( j = 0; j < padded_block_len; j++ ) + { + if( j < last_block_len ) + padded_block[j] = last_block[j]; + else if( j == last_block_len ) + padded_block[j] = 0x80; + else + padded_block[j] = 0x00; + } +} + +int mbedtls_cipher_cmac_starts( mbedtls_cipher_context_t *ctx, + const unsigned char *key, size_t keybits ) +{ + mbedtls_cipher_type_t type; + mbedtls_cmac_context_t *cmac_ctx; + int retval; + + if( ctx == NULL || ctx->cipher_info == NULL || key == NULL ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + if( ( retval = mbedtls_cipher_setkey( ctx, key, (int)keybits, + MBEDTLS_ENCRYPT ) ) != 0 ) + return( retval ); + + type = ctx->cipher_info->type; + + switch( type ) + { + case MBEDTLS_CIPHER_AES_128_ECB: + case MBEDTLS_CIPHER_AES_192_ECB: + case MBEDTLS_CIPHER_AES_256_ECB: + case MBEDTLS_CIPHER_DES_EDE3_ECB: + break; + default: + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + /* Allocated and initialise in the cipher context memory for the CMAC + * context */ + cmac_ctx = mbedtls_calloc( 1, sizeof( mbedtls_cmac_context_t ) ); + if( cmac_ctx == NULL ) + return( MBEDTLS_ERR_CIPHER_ALLOC_FAILED ); + + ctx->cmac_ctx = cmac_ctx; + + mbedtls_platform_zeroize( cmac_ctx->state, sizeof( cmac_ctx->state ) ); + + return 0; +} + +int mbedtls_cipher_cmac_update( mbedtls_cipher_context_t *ctx, + const unsigned char *input, size_t ilen ) +{ + mbedtls_cmac_context_t* cmac_ctx; + unsigned char *state; + int ret = 0; + size_t n, j, olen, block_size; + + if( ctx == NULL || ctx->cipher_info == NULL || input == NULL || + ctx->cmac_ctx == NULL ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + cmac_ctx = ctx->cmac_ctx; + block_size = ctx->cipher_info->block_size; + state = ctx->cmac_ctx->state; + + /* Is there data still to process from the last call, that's greater in + * size than a block? */ + if( cmac_ctx->unprocessed_len > 0 && + ilen > block_size - cmac_ctx->unprocessed_len ) + { + memcpy( &cmac_ctx->unprocessed_block[cmac_ctx->unprocessed_len], + input, + block_size - cmac_ctx->unprocessed_len ); + + cmac_xor_block( state, cmac_ctx->unprocessed_block, state, block_size ); + + if( ( ret = mbedtls_cipher_update( ctx, state, block_size, state, + &olen ) ) != 0 ) + { + goto exit; + } + + input += block_size - cmac_ctx->unprocessed_len; + ilen -= block_size - cmac_ctx->unprocessed_len; + cmac_ctx->unprocessed_len = 0; + } + + /* n is the number of blocks including any final partial block */ + n = ( ilen + block_size - 1 ) / block_size; + + /* Iterate across the input data in block sized chunks, excluding any + * final partial or complete block */ + for( j = 1; j < n; j++ ) + { + cmac_xor_block( state, input, state, block_size ); + + if( ( ret = mbedtls_cipher_update( ctx, state, block_size, state, + &olen ) ) != 0 ) + goto exit; + + ilen -= block_size; + input += block_size; + } + + /* If there is data left over that wasn't aligned to a block */ + if( ilen > 0 ) + { + memcpy( &cmac_ctx->unprocessed_block[cmac_ctx->unprocessed_len], + input, + ilen ); + cmac_ctx->unprocessed_len += ilen; + } + +exit: + return( ret ); +} + +int mbedtls_cipher_cmac_finish( mbedtls_cipher_context_t *ctx, + unsigned char *output ) +{ + mbedtls_cmac_context_t* cmac_ctx; + unsigned char *state, *last_block; + unsigned char K1[MBEDTLS_CIPHER_BLKSIZE_MAX]; + unsigned char K2[MBEDTLS_CIPHER_BLKSIZE_MAX]; + unsigned char M_last[MBEDTLS_CIPHER_BLKSIZE_MAX]; + int ret; + size_t olen, block_size; + + if( ctx == NULL || ctx->cipher_info == NULL || ctx->cmac_ctx == NULL || + output == NULL ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + cmac_ctx = ctx->cmac_ctx; + block_size = ctx->cipher_info->block_size; + state = cmac_ctx->state; + + mbedtls_platform_zeroize( K1, sizeof( K1 ) ); + mbedtls_platform_zeroize( K2, sizeof( K2 ) ); + cmac_generate_subkeys( ctx, K1, K2 ); + + last_block = cmac_ctx->unprocessed_block; + + /* Calculate last block */ + if( cmac_ctx->unprocessed_len < block_size ) + { + cmac_pad( M_last, block_size, last_block, cmac_ctx->unprocessed_len ); + cmac_xor_block( M_last, M_last, K2, block_size ); + } + else + { + /* Last block is complete block */ + cmac_xor_block( M_last, last_block, K1, block_size ); + } + + + cmac_xor_block( state, M_last, state, block_size ); + if( ( ret = mbedtls_cipher_update( ctx, state, block_size, state, + &olen ) ) != 0 ) + { + goto exit; + } + + memcpy( output, state, block_size ); + +exit: + /* Wipe the generated keys on the stack, and any other transients to avoid + * side channel leakage */ + mbedtls_platform_zeroize( K1, sizeof( K1 ) ); + mbedtls_platform_zeroize( K2, sizeof( K2 ) ); + + cmac_ctx->unprocessed_len = 0; + mbedtls_platform_zeroize( cmac_ctx->unprocessed_block, + sizeof( cmac_ctx->unprocessed_block ) ); + + mbedtls_platform_zeroize( state, MBEDTLS_CIPHER_BLKSIZE_MAX ); + return( ret ); +} + +int mbedtls_cipher_cmac_reset( mbedtls_cipher_context_t *ctx ) +{ + mbedtls_cmac_context_t* cmac_ctx; + + if( ctx == NULL || ctx->cipher_info == NULL || ctx->cmac_ctx == NULL ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + cmac_ctx = ctx->cmac_ctx; + + /* Reset the internal state */ + cmac_ctx->unprocessed_len = 0; + mbedtls_platform_zeroize( cmac_ctx->unprocessed_block, + sizeof( cmac_ctx->unprocessed_block ) ); + mbedtls_platform_zeroize( cmac_ctx->state, + sizeof( cmac_ctx->state ) ); + + return( 0 ); +} + +int mbedtls_cipher_cmac( const mbedtls_cipher_info_t *cipher_info, + const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + mbedtls_cipher_context_t ctx; + int ret; + + if( cipher_info == NULL || key == NULL || input == NULL || output == NULL ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + mbedtls_cipher_init( &ctx ); + + if( ( ret = mbedtls_cipher_setup( &ctx, cipher_info ) ) != 0 ) + goto exit; + + ret = mbedtls_cipher_cmac_starts( &ctx, key, keylen ); + if( ret != 0 ) + goto exit; + + ret = mbedtls_cipher_cmac_update( &ctx, input, ilen ); + if( ret != 0 ) + goto exit; + + ret = mbedtls_cipher_cmac_finish( &ctx, output ); + +exit: + mbedtls_cipher_free( &ctx ); + + return( ret ); +} + +#if defined(MBEDTLS_AES_C) +/* + * Implementation of AES-CMAC-PRF-128 defined in RFC 4615 + */ +int mbedtls_aes_cmac_prf_128( const unsigned char *key, size_t key_length, + const unsigned char *input, size_t in_len, + unsigned char *output ) +{ + int ret; + const mbedtls_cipher_info_t *cipher_info; + unsigned char zero_key[MBEDTLS_AES_BLOCK_SIZE]; + unsigned char int_key[MBEDTLS_AES_BLOCK_SIZE]; + + if( key == NULL || input == NULL || output == NULL ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + cipher_info = mbedtls_cipher_info_from_type( MBEDTLS_CIPHER_AES_128_ECB ); + if( cipher_info == NULL ) + { + /* Failing at this point must be due to a build issue */ + ret = MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE; + goto exit; + } + + if( key_length == MBEDTLS_AES_BLOCK_SIZE ) + { + /* Use key as is */ + memcpy( int_key, key, MBEDTLS_AES_BLOCK_SIZE ); + } + else + { + memset( zero_key, 0, MBEDTLS_AES_BLOCK_SIZE ); + + ret = mbedtls_cipher_cmac( cipher_info, zero_key, 128, key, + key_length, int_key ); + if( ret != 0 ) + goto exit; + } + + ret = mbedtls_cipher_cmac( cipher_info, int_key, 128, input, in_len, + output ); + +exit: + mbedtls_platform_zeroize( int_key, sizeof( int_key ) ); + + return( ret ); +} +#endif /* MBEDTLS_AES_C */ + +#endif /* !MBEDTLS_CMAC_ALT */ + +#if defined(MBEDTLS_SELF_TEST) +/* + * CMAC test data for SP800-38B + * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/AES_CMAC.pdf + * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/TDES_CMAC.pdf + * + * AES-CMAC-PRF-128 test data from RFC 4615 + * https://tools.ietf.org/html/rfc4615#page-4 + */ + +#define NB_CMAC_TESTS_PER_KEY 4 +#define NB_PRF_TESTS 3 + +#if defined(MBEDTLS_AES_C) || defined(MBEDTLS_DES_C) +/* All CMAC test inputs are truncated from the same 64 byte buffer. */ +static const unsigned char test_message[] = { + /* PT */ + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 +}; +#endif /* MBEDTLS_AES_C || MBEDTLS_DES_C */ + +#if defined(MBEDTLS_AES_C) +/* Truncation point of message for AES CMAC tests */ +static const unsigned int aes_message_lengths[NB_CMAC_TESTS_PER_KEY] = { + /* Mlen */ + 0, + 16, + 20, + 64 +}; + +/* CMAC-AES128 Test Data */ +static const unsigned char aes_128_key[16] = { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c +}; +static const unsigned char aes_128_subkeys[2][MBEDTLS_AES_BLOCK_SIZE] = { + { + /* K1 */ + 0xfb, 0xee, 0xd6, 0x18, 0x35, 0x71, 0x33, 0x66, + 0x7c, 0x85, 0xe0, 0x8f, 0x72, 0x36, 0xa8, 0xde + }, + { + /* K2 */ + 0xf7, 0xdd, 0xac, 0x30, 0x6a, 0xe2, 0x66, 0xcc, + 0xf9, 0x0b, 0xc1, 0x1e, 0xe4, 0x6d, 0x51, 0x3b + } +}; +static const unsigned char aes_128_expected_result[NB_CMAC_TESTS_PER_KEY][MBEDTLS_AES_BLOCK_SIZE] = { + { + /* Example #1 */ + 0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28, + 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46 + }, + { + /* Example #2 */ + 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, + 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c + }, + { + /* Example #3 */ + 0x7d, 0x85, 0x44, 0x9e, 0xa6, 0xea, 0x19, 0xc8, + 0x23, 0xa7, 0xbf, 0x78, 0x83, 0x7d, 0xfa, 0xde + }, + { + /* Example #4 */ + 0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92, + 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe + } +}; + +/* CMAC-AES192 Test Data */ +static const unsigned char aes_192_key[24] = { + 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, + 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5, + 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b +}; +static const unsigned char aes_192_subkeys[2][MBEDTLS_AES_BLOCK_SIZE] = { + { + /* K1 */ + 0x44, 0x8a, 0x5b, 0x1c, 0x93, 0x51, 0x4b, 0x27, + 0x3e, 0xe6, 0x43, 0x9d, 0xd4, 0xda, 0xa2, 0x96 + }, + { + /* K2 */ + 0x89, 0x14, 0xb6, 0x39, 0x26, 0xa2, 0x96, 0x4e, + 0x7d, 0xcc, 0x87, 0x3b, 0xa9, 0xb5, 0x45, 0x2c + } +}; +static const unsigned char aes_192_expected_result[NB_CMAC_TESTS_PER_KEY][MBEDTLS_AES_BLOCK_SIZE] = { + { + /* Example #1 */ + 0xd1, 0x7d, 0xdf, 0x46, 0xad, 0xaa, 0xcd, 0xe5, + 0x31, 0xca, 0xc4, 0x83, 0xde, 0x7a, 0x93, 0x67 + }, + { + /* Example #2 */ + 0x9e, 0x99, 0xa7, 0xbf, 0x31, 0xe7, 0x10, 0x90, + 0x06, 0x62, 0xf6, 0x5e, 0x61, 0x7c, 0x51, 0x84 + }, + { + /* Example #3 */ + 0x3d, 0x75, 0xc1, 0x94, 0xed, 0x96, 0x07, 0x04, + 0x44, 0xa9, 0xfa, 0x7e, 0xc7, 0x40, 0xec, 0xf8 + }, + { + /* Example #4 */ + 0xa1, 0xd5, 0xdf, 0x0e, 0xed, 0x79, 0x0f, 0x79, + 0x4d, 0x77, 0x58, 0x96, 0x59, 0xf3, 0x9a, 0x11 + } +}; + +/* CMAC-AES256 Test Data */ +static const unsigned char aes_256_key[32] = { + 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, + 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, + 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, + 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4 +}; +static const unsigned char aes_256_subkeys[2][MBEDTLS_AES_BLOCK_SIZE] = { + { + /* K1 */ + 0xca, 0xd1, 0xed, 0x03, 0x29, 0x9e, 0xed, 0xac, + 0x2e, 0x9a, 0x99, 0x80, 0x86, 0x21, 0x50, 0x2f + }, + { + /* K2 */ + 0x95, 0xa3, 0xda, 0x06, 0x53, 0x3d, 0xdb, 0x58, + 0x5d, 0x35, 0x33, 0x01, 0x0c, 0x42, 0xa0, 0xd9 + } +}; +static const unsigned char aes_256_expected_result[NB_CMAC_TESTS_PER_KEY][MBEDTLS_AES_BLOCK_SIZE] = { + { + /* Example #1 */ + 0x02, 0x89, 0x62, 0xf6, 0x1b, 0x7b, 0xf8, 0x9e, + 0xfc, 0x6b, 0x55, 0x1f, 0x46, 0x67, 0xd9, 0x83 + }, + { + /* Example #2 */ + 0x28, 0xa7, 0x02, 0x3f, 0x45, 0x2e, 0x8f, 0x82, + 0xbd, 0x4b, 0xf2, 0x8d, 0x8c, 0x37, 0xc3, 0x5c + }, + { + /* Example #3 */ + 0x15, 0x67, 0x27, 0xdc, 0x08, 0x78, 0x94, 0x4a, + 0x02, 0x3c, 0x1f, 0xe0, 0x3b, 0xad, 0x6d, 0x93 + }, + { + /* Example #4 */ + 0xe1, 0x99, 0x21, 0x90, 0x54, 0x9f, 0x6e, 0xd5, + 0x69, 0x6a, 0x2c, 0x05, 0x6c, 0x31, 0x54, 0x10 + } +}; +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_DES_C) +/* Truncation point of message for 3DES CMAC tests */ +static const unsigned int des3_message_lengths[NB_CMAC_TESTS_PER_KEY] = { + 0, + 16, + 20, + 32 +}; + +/* CMAC-TDES (Generation) - 2 Key Test Data */ +static const unsigned char des3_2key_key[24] = { + /* Key1 */ + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + /* Key2 */ + 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xEF, 0x01, + /* Key3 */ + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef +}; +static const unsigned char des3_2key_subkeys[2][8] = { + { + /* K1 */ + 0x0d, 0xd2, 0xcb, 0x7a, 0x3d, 0x88, 0x88, 0xd9 + }, + { + /* K2 */ + 0x1b, 0xa5, 0x96, 0xf4, 0x7b, 0x11, 0x11, 0xb2 + } +}; +static const unsigned char des3_2key_expected_result[NB_CMAC_TESTS_PER_KEY][MBEDTLS_DES3_BLOCK_SIZE] = { + { + /* Sample #1 */ + 0x79, 0xce, 0x52, 0xa7, 0xf7, 0x86, 0xa9, 0x60 + }, + { + /* Sample #2 */ + 0xcc, 0x18, 0xa0, 0xb7, 0x9a, 0xf2, 0x41, 0x3b + }, + { + /* Sample #3 */ + 0xc0, 0x6d, 0x37, 0x7e, 0xcd, 0x10, 0x19, 0x69 + }, + { + /* Sample #4 */ + 0x9c, 0xd3, 0x35, 0x80, 0xf9, 0xb6, 0x4d, 0xfb + } +}; + +/* CMAC-TDES (Generation) - 3 Key Test Data */ +static const unsigned char des3_3key_key[24] = { + /* Key1 */ + 0x01, 0x23, 0x45, 0x67, 0x89, 0xaa, 0xcd, 0xef, + /* Key2 */ + 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, + /* Key3 */ + 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23 +}; +static const unsigned char des3_3key_subkeys[2][8] = { + { + /* K1 */ + 0x9d, 0x74, 0xe7, 0x39, 0x33, 0x17, 0x96, 0xc0 + }, + { + /* K2 */ + 0x3a, 0xe9, 0xce, 0x72, 0x66, 0x2f, 0x2d, 0x9b + } +}; +static const unsigned char des3_3key_expected_result[NB_CMAC_TESTS_PER_KEY][MBEDTLS_DES3_BLOCK_SIZE] = { + { + /* Sample #1 */ + 0x7d, 0xb0, 0xd3, 0x7d, 0xf9, 0x36, 0xc5, 0x50 + }, + { + /* Sample #2 */ + 0x30, 0x23, 0x9c, 0xf1, 0xf5, 0x2e, 0x66, 0x09 + }, + { + /* Sample #3 */ + 0x6c, 0x9f, 0x3e, 0xe4, 0x92, 0x3f, 0x6b, 0xe2 + }, + { + /* Sample #4 */ + 0x99, 0x42, 0x9b, 0xd0, 0xbF, 0x79, 0x04, 0xe5 + } +}; + +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_AES_C) +/* AES AES-CMAC-PRF-128 Test Data */ +static const unsigned char PRFK[] = { + /* Key */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0xed, 0xcb +}; + +/* Sizes in bytes */ +static const size_t PRFKlen[NB_PRF_TESTS] = { + 18, + 16, + 10 +}; + +/* Message */ +static const unsigned char PRFM[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13 +}; + +static const unsigned char PRFT[NB_PRF_TESTS][16] = { + { + 0x84, 0xa3, 0x48, 0xa4, 0xa4, 0x5d, 0x23, 0x5b, + 0xab, 0xff, 0xfc, 0x0d, 0x2b, 0x4d, 0xa0, 0x9a + }, + { + 0x98, 0x0a, 0xe8, 0x7b, 0x5f, 0x4c, 0x9c, 0x52, + 0x14, 0xf5, 0xb6, 0xa8, 0x45, 0x5e, 0x4c, 0x2d + }, + { + 0x29, 0x0d, 0x9e, 0x11, 0x2e, 0xdb, 0x09, 0xee, + 0x14, 0x1f, 0xcf, 0x64, 0xc0, 0xb7, 0x2f, 0x3d + } +}; +#endif /* MBEDTLS_AES_C */ + +static int cmac_test_subkeys( int verbose, + const char* testname, + const unsigned char* key, + int keybits, + const unsigned char* subkeys, + mbedtls_cipher_type_t cipher_type, + int block_size, + int num_tests ) +{ + int i, ret = 0; + mbedtls_cipher_context_t ctx; + const mbedtls_cipher_info_t *cipher_info; + unsigned char K1[MBEDTLS_CIPHER_BLKSIZE_MAX]; + unsigned char K2[MBEDTLS_CIPHER_BLKSIZE_MAX]; + + cipher_info = mbedtls_cipher_info_from_type( cipher_type ); + if( cipher_info == NULL ) + { + /* Failing at this point must be due to a build issue */ + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); + } + + for( i = 0; i < num_tests; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " %s CMAC subkey #%u: ", testname, i + 1 ); + + mbedtls_cipher_init( &ctx ); + + if( ( ret = mbedtls_cipher_setup( &ctx, cipher_info ) ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "test execution failed\n" ); + + goto cleanup; + } + + if( ( ret = mbedtls_cipher_setkey( &ctx, key, keybits, + MBEDTLS_ENCRYPT ) ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "test execution failed\n" ); + + goto cleanup; + } + + ret = cmac_generate_subkeys( &ctx, K1, K2 ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + goto cleanup; + } + + if( ( ret = memcmp( K1, subkeys, block_size ) ) != 0 || + ( ret = memcmp( K2, &subkeys[block_size], block_size ) ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + goto cleanup; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + mbedtls_cipher_free( &ctx ); + } + + ret = 0; + goto exit; + +cleanup: + mbedtls_cipher_free( &ctx ); + +exit: + return( ret ); +} + +static int cmac_test_wth_cipher( int verbose, + const char* testname, + const unsigned char* key, + int keybits, + const unsigned char* messages, + const unsigned int message_lengths[4], + const unsigned char* expected_result, + mbedtls_cipher_type_t cipher_type, + int block_size, + int num_tests ) +{ + const mbedtls_cipher_info_t *cipher_info; + int i, ret = 0; + unsigned char output[MBEDTLS_CIPHER_BLKSIZE_MAX]; + + cipher_info = mbedtls_cipher_info_from_type( cipher_type ); + if( cipher_info == NULL ) + { + /* Failing at this point must be due to a build issue */ + ret = MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE; + goto exit; + } + + for( i = 0; i < num_tests; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " %s CMAC #%u: ", testname, i + 1 ); + + if( ( ret = mbedtls_cipher_cmac( cipher_info, key, keybits, messages, + message_lengths[i], output ) ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + goto exit; + } + + if( ( ret = memcmp( output, &expected_result[i * block_size], block_size ) ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + ret = 0; + +exit: + return( ret ); +} + +#if defined(MBEDTLS_AES_C) +static int test_aes128_cmac_prf( int verbose ) +{ + int i; + int ret; + unsigned char output[MBEDTLS_AES_BLOCK_SIZE]; + + for( i = 0; i < NB_PRF_TESTS; i++ ) + { + mbedtls_printf( " AES CMAC 128 PRF #%u: ", i ); + ret = mbedtls_aes_cmac_prf_128( PRFK, PRFKlen[i], PRFM, 20, output ); + if( ret != 0 || + memcmp( output, PRFT[i], MBEDTLS_AES_BLOCK_SIZE ) != 0 ) + { + + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( ret ); + } + else if( verbose != 0 ) + { + mbedtls_printf( "passed\n" ); + } + } + return( ret ); +} +#endif /* MBEDTLS_AES_C */ + +int mbedtls_cmac_self_test( int verbose ) +{ + int ret; + +#if defined(MBEDTLS_AES_C) + /* AES-128 */ + if( ( ret = cmac_test_subkeys( verbose, + "AES 128", + aes_128_key, + 128, + (const unsigned char*)aes_128_subkeys, + MBEDTLS_CIPHER_AES_128_ECB, + MBEDTLS_AES_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY ) ) != 0 ) + { + return( ret ); + } + + if( ( ret = cmac_test_wth_cipher( verbose, + "AES 128", + aes_128_key, + 128, + test_message, + aes_message_lengths, + (const unsigned char*)aes_128_expected_result, + MBEDTLS_CIPHER_AES_128_ECB, + MBEDTLS_AES_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY ) ) != 0 ) + { + return( ret ); + } + + /* AES-192 */ + if( ( ret = cmac_test_subkeys( verbose, + "AES 192", + aes_192_key, + 192, + (const unsigned char*)aes_192_subkeys, + MBEDTLS_CIPHER_AES_192_ECB, + MBEDTLS_AES_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY ) ) != 0 ) + { + return( ret ); + } + + if( ( ret = cmac_test_wth_cipher( verbose, + "AES 192", + aes_192_key, + 192, + test_message, + aes_message_lengths, + (const unsigned char*)aes_192_expected_result, + MBEDTLS_CIPHER_AES_192_ECB, + MBEDTLS_AES_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY ) ) != 0 ) + { + return( ret ); + } + + /* AES-256 */ + if( ( ret = cmac_test_subkeys( verbose, + "AES 256", + aes_256_key, + 256, + (const unsigned char*)aes_256_subkeys, + MBEDTLS_CIPHER_AES_256_ECB, + MBEDTLS_AES_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY ) ) != 0 ) + { + return( ret ); + } + + if( ( ret = cmac_test_wth_cipher ( verbose, + "AES 256", + aes_256_key, + 256, + test_message, + aes_message_lengths, + (const unsigned char*)aes_256_expected_result, + MBEDTLS_CIPHER_AES_256_ECB, + MBEDTLS_AES_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY ) ) != 0 ) + { + return( ret ); + } +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_DES_C) + /* 3DES 2 key */ + if( ( ret = cmac_test_subkeys( verbose, + "3DES 2 key", + des3_2key_key, + 192, + (const unsigned char*)des3_2key_subkeys, + MBEDTLS_CIPHER_DES_EDE3_ECB, + MBEDTLS_DES3_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY ) ) != 0 ) + { + return( ret ); + } + + if( ( ret = cmac_test_wth_cipher( verbose, + "3DES 2 key", + des3_2key_key, + 192, + test_message, + des3_message_lengths, + (const unsigned char*)des3_2key_expected_result, + MBEDTLS_CIPHER_DES_EDE3_ECB, + MBEDTLS_DES3_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY ) ) != 0 ) + { + return( ret ); + } + + /* 3DES 3 key */ + if( ( ret = cmac_test_subkeys( verbose, + "3DES 3 key", + des3_3key_key, + 192, + (const unsigned char*)des3_3key_subkeys, + MBEDTLS_CIPHER_DES_EDE3_ECB, + MBEDTLS_DES3_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY ) ) != 0 ) + { + return( ret ); + } + + if( ( ret = cmac_test_wth_cipher( verbose, + "3DES 3 key", + des3_3key_key, + 192, + test_message, + des3_message_lengths, + (const unsigned char*)des3_3key_expected_result, + MBEDTLS_CIPHER_DES_EDE3_ECB, + MBEDTLS_DES3_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY ) ) != 0 ) + { + return( ret ); + } +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_AES_C) + if( ( ret = test_aes128_cmac_prf( verbose ) ) != 0 ) + return( ret ); +#endif /* MBEDTLS_AES_C */ + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_CMAC_C */ diff --git a/common/mbedtls/cmac.h b/common/mbedtls/cmac.h new file mode 100644 index 00000000..f6fc79b7 --- /dev/null +++ b/common/mbedtls/cmac.h @@ -0,0 +1,208 @@ +/** + * \file cmac.h + * + * \brief This file contains CMAC definitions and functions. + * + * The Cipher-based Message Authentication Code (CMAC) Mode for + * Authentication is defined in RFC-4493: The AES-CMAC Algorithm. + */ +/* + * Copyright (C) 2015-2018, Arm Limited (or its affiliates), All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_CMAC_H +#define MBEDTLS_CMAC_H + +#include "cipher.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MBEDTLS_ERR_CMAC_HW_ACCEL_FAILED -0x007A /**< CMAC hardware accelerator failed. */ + +#define MBEDTLS_AES_BLOCK_SIZE 16 +#define MBEDTLS_DES3_BLOCK_SIZE 8 + +#if defined(MBEDTLS_AES_C) +#define MBEDTLS_CIPHER_BLKSIZE_MAX 16 /**< The longest block used by CMAC is that of AES. */ +#else +#define MBEDTLS_CIPHER_BLKSIZE_MAX 8 /**< The longest block used by CMAC is that of 3DES. */ +#endif + +#if !defined(MBEDTLS_CMAC_ALT) + +/** + * The CMAC context structure. + */ +struct mbedtls_cmac_context_t +{ + /** The internal state of the CMAC algorithm. */ + unsigned char state[MBEDTLS_CIPHER_BLKSIZE_MAX]; + + /** Unprocessed data - either data that was not block aligned and is still + * pending processing, or the final block. */ + unsigned char unprocessed_block[MBEDTLS_CIPHER_BLKSIZE_MAX]; + + /** The length of data pending processing. */ + size_t unprocessed_len; +}; + +#else /* !MBEDTLS_CMAC_ALT */ +#include "cmac_alt.h" +#endif /* !MBEDTLS_CMAC_ALT */ + +/** + * \brief This function sets the CMAC key, and prepares to authenticate + * the input data. + * Must be called with an initialized cipher context. + * + * \param ctx The cipher context used for the CMAC operation, initialized + * as one of the following types: MBEDTLS_CIPHER_AES_128_ECB, + * MBEDTLS_CIPHER_AES_192_ECB, MBEDTLS_CIPHER_AES_256_ECB, + * or MBEDTLS_CIPHER_DES_EDE3_ECB. + * \param key The CMAC key. + * \param keybits The length of the CMAC key in bits. + * Must be supported by the cipher. + * + * \return \c 0 on success. + * \return A cipher-specific error code on failure. + */ +int mbedtls_cipher_cmac_starts( mbedtls_cipher_context_t *ctx, + const unsigned char *key, size_t keybits ); + +/** + * \brief This function feeds an input buffer into an ongoing CMAC + * computation. + * + * It is called between mbedtls_cipher_cmac_starts() or + * mbedtls_cipher_cmac_reset(), and mbedtls_cipher_cmac_finish(). + * Can be called repeatedly. + * + * \param ctx The cipher context used for the CMAC operation. + * \param input The buffer holding the input data. + * \param ilen The length of the input data. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA + * if parameter verification fails. + */ +int mbedtls_cipher_cmac_update( mbedtls_cipher_context_t *ctx, + const unsigned char *input, size_t ilen ); + +/** + * \brief This function finishes the CMAC operation, and writes + * the result to the output buffer. + * + * It is called after mbedtls_cipher_cmac_update(). + * It can be followed by mbedtls_cipher_cmac_reset() and + * mbedtls_cipher_cmac_update(), or mbedtls_cipher_free(). + * + * \param ctx The cipher context used for the CMAC operation. + * \param output The output buffer for the CMAC checksum result. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA + * if parameter verification fails. + */ +int mbedtls_cipher_cmac_finish( mbedtls_cipher_context_t *ctx, + unsigned char *output ); + +/** + * \brief This function prepares the authentication of another + * message with the same key as the previous CMAC + * operation. + * + * It is called after mbedtls_cipher_cmac_finish() + * and before mbedtls_cipher_cmac_update(). + * + * \param ctx The cipher context used for the CMAC operation. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA + * if parameter verification fails. + */ +int mbedtls_cipher_cmac_reset( mbedtls_cipher_context_t *ctx ); + +/** + * \brief This function calculates the full generic CMAC + * on the input buffer with the provided key. + * + * The function allocates the context, performs the + * calculation, and frees the context. + * + * The CMAC result is calculated as + * output = generic CMAC(cmac key, input buffer). + * + * + * \param cipher_info The cipher information. + * \param key The CMAC key. + * \param keylen The length of the CMAC key in bits. + * \param input The buffer holding the input data. + * \param ilen The length of the input data. + * \param output The buffer for the generic CMAC result. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA + * if parameter verification fails. + */ +int mbedtls_cipher_cmac( const mbedtls_cipher_info_t *cipher_info, + const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char *output ); + +#if defined(MBEDTLS_AES_C) +/** + * \brief This function implements the AES-CMAC-PRF-128 pseudorandom + * function, as defined in + * RFC-4615: The Advanced Encryption Standard-Cipher-based + * Message Authentication Code-Pseudo-Random Function-128 + * (AES-CMAC-PRF-128) Algorithm for the Internet Key + * Exchange Protocol (IKE). + * + * \param key The key to use. + * \param key_len The key length in Bytes. + * \param input The buffer holding the input data. + * \param in_len The length of the input data in Bytes. + * \param output The buffer holding the generated 16 Bytes of + * pseudorandom output. + * + * \return \c 0 on success. + */ +int mbedtls_aes_cmac_prf_128( const unsigned char *key, size_t key_len, + const unsigned char *input, size_t in_len, + unsigned char output[16] ); +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_SELF_TEST) && ( defined(MBEDTLS_AES_C) || defined(MBEDTLS_DES_C) ) +/** + * \brief The CMAC checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_cmac_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST && ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */ + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_CMAC_H */ diff --git a/common/mbedtls/config.h b/common/mbedtls/config.h new file mode 100644 index 00000000..dfda7ca4 --- /dev/null +++ b/common/mbedtls/config.h @@ -0,0 +1,3129 @@ +/** + * \file config.h + * + * \brief Configuration options (set of defines) + * + * This set of compile-time options may be used to enable + * or disable features selectively, and reduce the global + * memory footprint. + */ +/* + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_CONFIG_H +#define MBEDTLS_CONFIG_H + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif + +/** + * \name SECTION: System support + * + * This section sets system specific settings. + * \{ + */ + +/** + * \def MBEDTLS_HAVE_ASM + * + * The compiler has support for asm(). + * + * Requires support for asm() in compiler. + * + * Used in: + * library/aria.c + * library/timing.c + * include/mbedtls/bn_mul.h + * + * Required by: + * MBEDTLS_AESNI_C + * MBEDTLS_PADLOCK_C + * + * Comment to disable the use of assembly code. + */ +//#define MBEDTLS_HAVE_ASM + +/** + * \def MBEDTLS_NO_UDBL_DIVISION + * + * The platform lacks support for double-width integer division (64-bit + * division on a 32-bit platform, 128-bit division on a 64-bit platform). + * + * Used in: + * include/mbedtls/bignum.h + * library/bignum.c + * + * The bignum code uses double-width division to speed up some operations. + * Double-width division is often implemented in software that needs to + * be linked with the program. The presence of a double-width integer + * type is usually detected automatically through preprocessor macros, + * but the automatic detection cannot know whether the code needs to + * and can be linked with an implementation of division for that type. + * By default division is assumed to be usable if the type is present. + * Uncomment this option to prevent the use of double-width division. + * + * Note that division for the native integer type is always required. + * Furthermore, a 64-bit type is always required even on a 32-bit + * platform, but it need not support multiplication or division. In some + * cases it is also desirable to disable some double-width operations. For + * example, if double-width division is implemented in software, disabling + * it can reduce code size in some embedded targets. + */ +//#define MBEDTLS_NO_UDBL_DIVISION + +/** + * \def MBEDTLS_NO_64BIT_MULTIPLICATION + * + * The platform lacks support for 32x32 -> 64-bit multiplication. + * + * Used in: + * library/poly1305.c + * + * Some parts of the library may use multiplication of two unsigned 32-bit + * operands with a 64-bit result in order to speed up computations. On some + * platforms, this is not available in hardware and has to be implemented in + * software, usually in a library provided by the toolchain. + * + * Sometimes it is not desirable to have to link to that library. This option + * removes the dependency of that library on platforms that lack a hardware + * 64-bit multiplier by embedding a software implementation in Mbed TLS. + * + * Note that depending on the compiler, this may decrease performance compared + * to using the library function provided by the toolchain. + */ +//#define MBEDTLS_NO_64BIT_MULTIPLICATION + +/** + * \def MBEDTLS_HAVE_SSE2 + * + * CPU supports SSE2 instruction set. + * + * Uncomment if the CPU supports SSE2 (IA-32 specific). + */ +//#define MBEDTLS_HAVE_SSE2 + +/** + * \def MBEDTLS_HAVE_TIME + * + * System has time.h and time(). + * The time does not need to be correct, only time differences are used, + * by contrast with MBEDTLS_HAVE_TIME_DATE + * + * Defining MBEDTLS_HAVE_TIME allows you to specify MBEDTLS_PLATFORM_TIME_ALT, + * MBEDTLS_PLATFORM_TIME_MACRO, MBEDTLS_PLATFORM_TIME_TYPE_MACRO and + * MBEDTLS_PLATFORM_STD_TIME. + * + * Comment if your system does not support time functions + */ +//#define MBEDTLS_HAVE_TIME + +/** + * \def MBEDTLS_HAVE_TIME_DATE + * + * System has time.h and time(), gmtime() and the clock is correct. + * The time needs to be correct (not necesarily very accurate, but at least + * the date should be correct). This is used to verify the validity period of + * X.509 certificates. + * + * Comment if your system does not have a correct clock. + */ +//#define MBEDTLS_HAVE_TIME_DATE + +/** + * \def MBEDTLS_PLATFORM_MEMORY + * + * Enable the memory allocation layer. + * + * By default mbed TLS uses the system-provided calloc() and free(). + * This allows different allocators (self-implemented or provided) to be + * provided to the platform abstraction layer. + * + * Enabling MBEDTLS_PLATFORM_MEMORY without the + * MBEDTLS_PLATFORM_{FREE,CALLOC}_MACROs will provide + * "mbedtls_platform_set_calloc_free()" allowing you to set an alternative calloc() and + * free() function pointer at runtime. + * + * Enabling MBEDTLS_PLATFORM_MEMORY and specifying + * MBEDTLS_PLATFORM_{CALLOC,FREE}_MACROs will allow you to specify the + * alternate function at compile time. + * + * Requires: MBEDTLS_PLATFORM_C + * + * Enable this layer to allow use of alternative memory allocators. + */ +//#define MBEDTLS_PLATFORM_MEMORY + +/** + * \def MBEDTLS_PLATFORM_NO_STD_FUNCTIONS + * + * Do not assign standard functions in the platform layer (e.g. calloc() to + * MBEDTLS_PLATFORM_STD_CALLOC and printf() to MBEDTLS_PLATFORM_STD_PRINTF) + * + * This makes sure there are no linking errors on platforms that do not support + * these functions. You will HAVE to provide alternatives, either at runtime + * via the platform_set_xxx() functions or at compile time by setting + * the MBEDTLS_PLATFORM_STD_XXX defines, or enabling a + * MBEDTLS_PLATFORM_XXX_MACRO. + * + * Requires: MBEDTLS_PLATFORM_C + * + * Uncomment to prevent default assignment of standard functions in the + * platform layer. + */ +//#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS + +/** + * \def MBEDTLS_PLATFORM_EXIT_ALT + * + * MBEDTLS_PLATFORM_XXX_ALT: Uncomment a macro to let mbed TLS support the + * function in the platform abstraction layer. + * + * Example: In case you uncomment MBEDTLS_PLATFORM_PRINTF_ALT, mbed TLS will + * provide a function "mbedtls_platform_set_printf()" that allows you to set an + * alternative printf function pointer. + * + * All these define require MBEDTLS_PLATFORM_C to be defined! + * + * \note MBEDTLS_PLATFORM_SNPRINTF_ALT is required on Windows; + * it will be enabled automatically by check_config.h + * + * \warning MBEDTLS_PLATFORM_XXX_ALT cannot be defined at the same time as + * MBEDTLS_PLATFORM_XXX_MACRO! + * + * Requires: MBEDTLS_PLATFORM_TIME_ALT requires MBEDTLS_HAVE_TIME + * + * Uncomment a macro to enable alternate implementation of specific base + * platform function + */ +//#define MBEDTLS_PLATFORM_EXIT_ALT +//#define MBEDTLS_PLATFORM_TIME_ALT +//#define MBEDTLS_PLATFORM_FPRINTF_ALT +//#define MBEDTLS_PLATFORM_PRINTF_ALT +//#define MBEDTLS_PLATFORM_SNPRINTF_ALT +//#define MBEDTLS_PLATFORM_NV_SEED_ALT +//#define MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT + +/** + * \def MBEDTLS_DEPRECATED_WARNING + * + * Mark deprecated functions so that they generate a warning if used. + * Functions deprecated in one version will usually be removed in the next + * version. You can enable this to help you prepare the transition to a new + * major version by making sure your code is not using these functions. + * + * This only works with GCC and Clang. With other compilers, you may want to + * use MBEDTLS_DEPRECATED_REMOVED + * + * Uncomment to get warnings on using deprecated functions. + */ +//#define MBEDTLS_DEPRECATED_WARNING + +/** + * \def MBEDTLS_DEPRECATED_REMOVED + * + * Remove deprecated functions so that they generate an error if used. + * Functions deprecated in one version will usually be removed in the next + * version. You can enable this to help you prepare the transition to a new + * major version by making sure your code is not using these functions. + * + * Uncomment to get errors on using deprecated functions. + */ +//#define MBEDTLS_DEPRECATED_REMOVED + +/* \} name SECTION: System support */ + +/** + * \name SECTION: mbed TLS feature support + * + * This section sets support for features that are or are not needed + * within the modules that are enabled. + * \{ + */ + +/** + * \def MBEDTLS_TIMING_ALT + * + * Uncomment to provide your own alternate implementation for mbedtls_timing_hardclock(), + * mbedtls_timing_get_timer(), mbedtls_set_alarm(), mbedtls_set/get_delay() + * + * Only works if you have MBEDTLS_TIMING_C enabled. + * + * You will need to provide a header "timing_alt.h" and an implementation at + * compile time. + */ +//#define MBEDTLS_TIMING_ALT + +/** + * \def MBEDTLS_AES_ALT + * + * MBEDTLS__MODULE_NAME__ALT: Uncomment a macro to let mbed TLS use your + * alternate core implementation of a symmetric crypto, an arithmetic or hash + * module (e.g. platform specific assembly optimized implementations). Keep + * in mind that the function prototypes should remain the same. + * + * This replaces the whole module. If you only want to replace one of the + * functions, use one of the MBEDTLS__FUNCTION_NAME__ALT flags. + * + * Example: In case you uncomment MBEDTLS_AES_ALT, mbed TLS will no longer + * provide the "struct mbedtls_aes_context" definition and omit the base + * function declarations and implementations. "aes_alt.h" will be included from + * "aes.h" to include the new function definitions. + * + * Uncomment a macro to enable alternate implementation of the corresponding + * module. + * + * \warning MD2, MD4, MD5, ARC4, DES and SHA-1 are considered weak and their + * use constitutes a security risk. If possible, we recommend + * avoiding dependencies on them, and considering stronger message + * digests and ciphers instead. + * + */ +//#define MBEDTLS_AES_ALT +//#define MBEDTLS_ARC4_ALT +//#define MBEDTLS_ARIA_ALT +//#define MBEDTLS_BLOWFISH_ALT +//#define MBEDTLS_CAMELLIA_ALT +//#define MBEDTLS_CCM_ALT +//#define MBEDTLS_CHACHA20_ALT +//#define MBEDTLS_CHACHAPOLY_ALT +//#define MBEDTLS_CMAC_ALT +//#define MBEDTLS_DES_ALT +//#define MBEDTLS_DHM_ALT +//#define MBEDTLS_ECJPAKE_ALT +//#define MBEDTLS_GCM_ALT +//#define MBEDTLS_NIST_KW_ALT +//#define MBEDTLS_MD2_ALT +//#define MBEDTLS_MD4_ALT +//#define MBEDTLS_MD5_ALT +//#define MBEDTLS_POLY1305_ALT +//#define MBEDTLS_RIPEMD160_ALT +//#define MBEDTLS_RSA_ALT +//#define MBEDTLS_SHA1_ALT +//#define MBEDTLS_SHA256_ALT +//#define MBEDTLS_SHA512_ALT +//#define MBEDTLS_XTEA_ALT + +/* + * When replacing the elliptic curve module, pleace consider, that it is + * implemented with two .c files: + * - ecp.c + * - ecp_curves.c + * You can replace them very much like all the other MBEDTLS__MODULE_NAME__ALT + * macros as described above. The only difference is that you have to make sure + * that you provide functionality for both .c files. + */ +//#define MBEDTLS_ECP_ALT + +/** + * \def MBEDTLS_MD2_PROCESS_ALT + * + * MBEDTLS__FUNCTION_NAME__ALT: Uncomment a macro to let mbed TLS use you + * alternate core implementation of symmetric crypto or hash function. Keep in + * mind that function prototypes should remain the same. + * + * This replaces only one function. The header file from mbed TLS is still + * used, in contrast to the MBEDTLS__MODULE_NAME__ALT flags. + * + * Example: In case you uncomment MBEDTLS_SHA256_PROCESS_ALT, mbed TLS will + * no longer provide the mbedtls_sha1_process() function, but it will still provide + * the other function (using your mbedtls_sha1_process() function) and the definition + * of mbedtls_sha1_context, so your implementation of mbedtls_sha1_process must be compatible + * with this definition. + * + * \note Because of a signature change, the core AES encryption and decryption routines are + * currently named mbedtls_aes_internal_encrypt and mbedtls_aes_internal_decrypt, + * respectively. When setting up alternative implementations, these functions should + * be overriden, but the wrapper functions mbedtls_aes_decrypt and mbedtls_aes_encrypt + * must stay untouched. + * + * \note If you use the AES_xxx_ALT macros, then is is recommended to also set + * MBEDTLS_AES_ROM_TABLES in order to help the linker garbage-collect the AES + * tables. + * + * Uncomment a macro to enable alternate implementation of the corresponding + * function. + * + * \warning MD2, MD4, MD5, DES and SHA-1 are considered weak and their use + * constitutes a security risk. If possible, we recommend avoiding + * dependencies on them, and considering stronger message digests + * and ciphers instead. + * + */ +//#define MBEDTLS_MD2_PROCESS_ALT +//#define MBEDTLS_MD4_PROCESS_ALT +//#define MBEDTLS_MD5_PROCESS_ALT +//#define MBEDTLS_RIPEMD160_PROCESS_ALT +//#define MBEDTLS_SHA1_PROCESS_ALT +//#define MBEDTLS_SHA256_PROCESS_ALT +//#define MBEDTLS_SHA512_PROCESS_ALT +//#define MBEDTLS_DES_SETKEY_ALT +//#define MBEDTLS_DES_CRYPT_ECB_ALT +//#define MBEDTLS_DES3_CRYPT_ECB_ALT +//#define MBEDTLS_AES_SETKEY_ENC_ALT +//#define MBEDTLS_AES_SETKEY_DEC_ALT +//#define MBEDTLS_AES_ENCRYPT_ALT +//#define MBEDTLS_AES_DECRYPT_ALT +//#define MBEDTLS_ECDH_GEN_PUBLIC_ALT +//#define MBEDTLS_ECDH_COMPUTE_SHARED_ALT +//#define MBEDTLS_ECDSA_VERIFY_ALT +//#define MBEDTLS_ECDSA_SIGN_ALT +//#define MBEDTLS_ECDSA_GENKEY_ALT + +/** + * \def MBEDTLS_ECP_INTERNAL_ALT + * + * Expose a part of the internal interface of the Elliptic Curve Point module. + * + * MBEDTLS_ECP__FUNCTION_NAME__ALT: Uncomment a macro to let mbed TLS use your + * alternative core implementation of elliptic curve arithmetic. Keep in mind + * that function prototypes should remain the same. + * + * This partially replaces one function. The header file from mbed TLS is still + * used, in contrast to the MBEDTLS_ECP_ALT flag. The original implementation + * is still present and it is used for group structures not supported by the + * alternative. + * + * Any of these options become available by defining MBEDTLS_ECP_INTERNAL_ALT + * and implementing the following functions: + * unsigned char mbedtls_internal_ecp_grp_capable( + * const mbedtls_ecp_group *grp ) + * int mbedtls_internal_ecp_init( const mbedtls_ecp_group *grp ) + * void mbedtls_internal_ecp_deinit( const mbedtls_ecp_group *grp ) + * The mbedtls_internal_ecp_grp_capable function should return 1 if the + * replacement functions implement arithmetic for the given group and 0 + * otherwise. + * The functions mbedtls_internal_ecp_init and mbedtls_internal_ecp_deinit are + * called before and after each point operation and provide an opportunity to + * implement optimized set up and tear down instructions. + * + * Example: In case you uncomment MBEDTLS_ECP_INTERNAL_ALT and + * MBEDTLS_ECP_DOUBLE_JAC_ALT, mbed TLS will still provide the ecp_double_jac + * function, but will use your mbedtls_internal_ecp_double_jac if the group is + * supported (your mbedtls_internal_ecp_grp_capable function returns 1 when + * receives it as an argument). If the group is not supported then the original + * implementation is used. The other functions and the definition of + * mbedtls_ecp_group and mbedtls_ecp_point will not change, so your + * implementation of mbedtls_internal_ecp_double_jac and + * mbedtls_internal_ecp_grp_capable must be compatible with this definition. + * + * Uncomment a macro to enable alternate implementation of the corresponding + * function. + */ +/* Required for all the functions in this section */ +//#define MBEDTLS_ECP_INTERNAL_ALT +/* Support for Weierstrass curves with Jacobi representation */ +//#define MBEDTLS_ECP_RANDOMIZE_JAC_ALT +//#define MBEDTLS_ECP_ADD_MIXED_ALT +//#define MBEDTLS_ECP_DOUBLE_JAC_ALT +//#define MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT +//#define MBEDTLS_ECP_NORMALIZE_JAC_ALT +/* Support for curves with Montgomery arithmetic */ +//#define MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT +//#define MBEDTLS_ECP_RANDOMIZE_MXZ_ALT +//#define MBEDTLS_ECP_NORMALIZE_MXZ_ALT + +/** + * \def MBEDTLS_TEST_NULL_ENTROPY + * + * Enables testing and use of mbed TLS without any configured entropy sources. + * This permits use of the library on platforms before an entropy source has + * been integrated (see for example the MBEDTLS_ENTROPY_HARDWARE_ALT or the + * MBEDTLS_ENTROPY_NV_SEED switches). + * + * WARNING! This switch MUST be disabled in production builds, and is suitable + * only for development. + * Enabling the switch negates any security provided by the library. + * + * Requires MBEDTLS_ENTROPY_C, MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES + * + */ +//#define MBEDTLS_TEST_NULL_ENTROPY + +/** + * \def MBEDTLS_ENTROPY_HARDWARE_ALT + * + * Uncomment this macro to let mbed TLS use your own implementation of a + * hardware entropy collector. + * + * Your function must be called \c mbedtls_hardware_poll(), have the same + * prototype as declared in entropy_poll.h, and accept NULL as first argument. + * + * Uncomment to use your own hardware entropy collector. + */ +//#define MBEDTLS_ENTROPY_HARDWARE_ALT + +/** + * \def MBEDTLS_AES_ROM_TABLES + * + * Use precomputed AES tables stored in ROM. + * + * Uncomment this macro to use precomputed AES tables stored in ROM. + * Comment this macro to generate AES tables in RAM at runtime. + * + * Tradeoff: Using precomputed ROM tables reduces RAM usage by ~8kb + * (or ~2kb if \c MBEDTLS_AES_FEWER_TABLES is used) and reduces the + * initialization time before the first AES operation can be performed. + * It comes at the cost of additional ~8kb ROM use (resp. ~2kb if \c + * MBEDTLS_AES_FEWER_TABLES below is used), and potentially degraded + * performance if ROM access is slower than RAM access. + * + * This option is independent of \c MBEDTLS_AES_FEWER_TABLES. + * + */ +//#define MBEDTLS_AES_ROM_TABLES + +/** + * \def MBEDTLS_AES_FEWER_TABLES + * + * Use less ROM/RAM for AES tables. + * + * Uncommenting this macro omits 75% of the AES tables from + * ROM / RAM (depending on the value of \c MBEDTLS_AES_ROM_TABLES) + * by computing their values on the fly during operations + * (the tables are entry-wise rotations of one another). + * + * Tradeoff: Uncommenting this reduces the RAM / ROM footprint + * by ~6kb but at the cost of more arithmetic operations during + * runtime. Specifically, one has to compare 4 accesses within + * different tables to 4 accesses with additional arithmetic + * operations within the same table. The performance gain/loss + * depends on the system and memory details. + * + * This option is independent of \c MBEDTLS_AES_ROM_TABLES. + * + */ +//#define MBEDTLS_AES_FEWER_TABLES + +/** + * \def MBEDTLS_CAMELLIA_SMALL_MEMORY + * + * Use less ROM for the Camellia implementation (saves about 768 bytes). + * + * Uncomment this macro to use less memory for Camellia. + */ +//#define MBEDTLS_CAMELLIA_SMALL_MEMORY + +/** + * \def MBEDTLS_CIPHER_MODE_CBC + * + * Enable Cipher Block Chaining mode (CBC) for symmetric ciphers. + */ +#define MBEDTLS_CIPHER_MODE_CBC + +/** + * \def MBEDTLS_CIPHER_MODE_CFB + * + * Enable Cipher Feedback mode (CFB) for symmetric ciphers. + */ +#define MBEDTLS_CIPHER_MODE_CFB + +/** + * \def MBEDTLS_CIPHER_MODE_CTR + * + * Enable Counter Block Cipher mode (CTR) for symmetric ciphers. + */ +#define MBEDTLS_CIPHER_MODE_CTR + +/** + * \def MBEDTLS_CIPHER_MODE_OFB + * + * Enable Output Feedback mode (OFB) for symmetric ciphers. + */ +#define MBEDTLS_CIPHER_MODE_OFB + +/** + * \def MBEDTLS_CIPHER_MODE_XTS + * + * Enable Xor-encrypt-xor with ciphertext stealing mode (XTS) for AES. + */ +#define MBEDTLS_CIPHER_MODE_XTS + +/** + * \def MBEDTLS_CIPHER_NULL_CIPHER + * + * Enable NULL cipher. + * Warning: Only do so when you know what you are doing. This allows for + * encryption or channels without any security! + * + * Requires MBEDTLS_ENABLE_WEAK_CIPHERSUITES as well to enable + * the following ciphersuites: + * MBEDTLS_TLS_ECDH_ECDSA_WITH_NULL_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_NULL_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_NULL_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_NULL_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA + * MBEDTLS_TLS_RSA_WITH_NULL_SHA256 + * MBEDTLS_TLS_RSA_WITH_NULL_SHA + * MBEDTLS_TLS_RSA_WITH_NULL_MD5 + * MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA + * MBEDTLS_TLS_PSK_WITH_NULL_SHA384 + * MBEDTLS_TLS_PSK_WITH_NULL_SHA256 + * MBEDTLS_TLS_PSK_WITH_NULL_SHA + * + * Uncomment this macro to enable the NULL cipher and ciphersuites + */ +//#define MBEDTLS_CIPHER_NULL_CIPHER + +/** + * \def MBEDTLS_CIPHER_PADDING_PKCS7 + * + * MBEDTLS_CIPHER_PADDING_XXX: Uncomment or comment macros to add support for + * specific padding modes in the cipher layer with cipher modes that support + * padding (e.g. CBC) + * + * If you disable all padding modes, only full blocks can be used with CBC. + * + * Enable padding modes in the cipher layer. + */ +#define MBEDTLS_CIPHER_PADDING_PKCS7 +#define MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS +#define MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN +#define MBEDTLS_CIPHER_PADDING_ZEROS + +/** + * \def MBEDTLS_ENABLE_WEAK_CIPHERSUITES + * + * Enable weak ciphersuites in SSL / TLS. + * Warning: Only do so when you know what you are doing. This allows for + * channels with virtually no security at all! + * + * This enables the following ciphersuites: + * MBEDTLS_TLS_RSA_WITH_DES_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_DES_CBC_SHA + * + * Uncomment this macro to enable weak ciphersuites + * + * \warning DES is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers instead. + */ +//#define MBEDTLS_ENABLE_WEAK_CIPHERSUITES + +/** + * \def MBEDTLS_REMOVE_ARC4_CIPHERSUITES + * + * Remove RC4 ciphersuites by default in SSL / TLS. + * This flag removes the ciphersuites based on RC4 from the default list as + * returned by mbedtls_ssl_list_ciphersuites(). However, it is still possible to + * enable (some of) them with mbedtls_ssl_conf_ciphersuites() by including them + * explicitly. + * + * Uncomment this macro to remove RC4 ciphersuites by default. + */ +#define MBEDTLS_REMOVE_ARC4_CIPHERSUITES + +/** + * \def MBEDTLS_ECP_DP_SECP192R1_ENABLED + * + * MBEDTLS_ECP_XXXX_ENABLED: Enables specific curves within the Elliptic Curve + * module. By default all supported curves are enabled. + * + * Comment macros to disable the curve and functions for it + */ +#define MBEDTLS_ECP_DP_SECP192R1_ENABLED +#define MBEDTLS_ECP_DP_SECP224R1_ENABLED +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +#define MBEDTLS_ECP_DP_SECP384R1_ENABLED +#define MBEDTLS_ECP_DP_SECP521R1_ENABLED +#define MBEDTLS_ECP_DP_SECP192K1_ENABLED +#define MBEDTLS_ECP_DP_SECP224K1_ENABLED +#define MBEDTLS_ECP_DP_SECP256K1_ENABLED +#define MBEDTLS_ECP_DP_BP256R1_ENABLED +#define MBEDTLS_ECP_DP_BP384R1_ENABLED +#define MBEDTLS_ECP_DP_BP512R1_ENABLED +#define MBEDTLS_ECP_DP_CURVE25519_ENABLED +#define MBEDTLS_ECP_DP_CURVE448_ENABLED + +/** + * \def MBEDTLS_ECP_NIST_OPTIM + * + * Enable specific 'modulo p' routines for each NIST prime. + * Depending on the prime and architecture, makes operations 4 to 8 times + * faster on the corresponding curve. + * + * Comment this macro to disable NIST curves optimisation. + */ +#define MBEDTLS_ECP_NIST_OPTIM + +/** + * \def MBEDTLS_ECDSA_DETERMINISTIC + * + * Enable deterministic ECDSA (RFC 6979). + * Standard ECDSA is "fragile" in the sense that lack of entropy when signing + * may result in a compromise of the long-term signing key. This is avoided by + * the deterministic variant. + * + * Requires: MBEDTLS_HMAC_DRBG_C + * + * Comment this macro to disable deterministic ECDSA. + */ +//#define MBEDTLS_ECDSA_DETERMINISTIC + +/** + * \def MBEDTLS_KEY_EXCHANGE_PSK_ENABLED + * + * Enable the PSK based ciphersuite modes in SSL / TLS. + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_RC4_128_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED + * + * Enable the DHE-PSK based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_DHM_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA + * + * \warning Using DHE constitutes a security risk as it + * is not possible to validate custom DH parameters. + * If possible, it is recommended users should consider + * preferring other methods of key exchange. + * See dhm.h for more details. + * + */ +//#define MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED + * + * Enable the ECDHE-PSK based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED + * + * Enable the RSA-PSK based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_RSA_ENABLED + * + * Enable the RSA-only based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_MD5 + */ +#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED + * + * Enable the DHE-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_DHM_C, MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA + * + * \warning Using DHE constitutes a security risk as it + * is not possible to validate custom DH parameters. + * If possible, it is recommended users should consider + * preferring other methods of key exchange. + * See dhm.h for more details. + * + */ +//#define MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED + * + * Enable the ECDHE-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + * + * Enable the ECDHE-ECDSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_ECDSA_C, MBEDTLS_X509_CRT_PARSE_C, + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED + * + * Enable the ECDH-ECDSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + */ +#define MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED + * + * Enable the ECDH-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 + */ +#define MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED + * + * Enable the ECJPAKE based ciphersuite modes in SSL / TLS. + * + * \warning This is currently experimental. EC J-PAKE support is based on the + * Thread v1.0.0 specification; incompatible changes to the specification + * might still happen. For this reason, this is disabled by default. + * + * Requires: MBEDTLS_ECJPAKE_C + * MBEDTLS_SHA256_C + * MBEDTLS_ECP_DP_SECP256R1_ENABLED + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8 + */ +//#define MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED + +/** + * \def MBEDTLS_PK_PARSE_EC_EXTENDED + * + * Enhance support for reading EC keys using variants of SEC1 not allowed by + * RFC 5915 and RFC 5480. + * + * Currently this means parsing the SpecifiedECDomain choice of EC + * parameters (only known groups are supported, not arbitrary domains, to + * avoid validation issues). + * + * Disable if you only need to support RFC 5915 + 5480 key formats. + */ +#define MBEDTLS_PK_PARSE_EC_EXTENDED + +/** + * \def MBEDTLS_ERROR_STRERROR_DUMMY + * + * Enable a dummy error function to make use of mbedtls_strerror() in + * third party libraries easier when MBEDTLS_ERROR_C is disabled + * (no effect when MBEDTLS_ERROR_C is enabled). + * + * You can safely disable this if MBEDTLS_ERROR_C is enabled, or if you're + * not using mbedtls_strerror() or error_strerror() in your application. + * + * Disable if you run into name conflicts and want to really remove the + * mbedtls_strerror() + */ +#define MBEDTLS_ERROR_STRERROR_DUMMY + +/** + * \def MBEDTLS_GENPRIME + * + * Enable the prime-number generation code. + * + * Requires: MBEDTLS_BIGNUM_C + */ +#define MBEDTLS_GENPRIME + +/** + * \def MBEDTLS_FS_IO + * + * Enable functions that use the filesystem. + */ +#define MBEDTLS_FS_IO + +/** + * \def MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES + * + * Do not add default entropy sources. These are the platform specific, + * mbedtls_timing_hardclock and HAVEGE based poll functions. + * + * This is useful to have more control over the added entropy sources in an + * application. + * + * Uncomment this macro to prevent loading of default entropy functions. + */ +//#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES + +/** + * \def MBEDTLS_NO_PLATFORM_ENTROPY + * + * Do not use built-in platform entropy functions. + * This is useful if your platform does not support + * standards like the /dev/urandom or Windows CryptoAPI. + * + * Uncomment this macro to disable the built-in platform entropy functions. + */ +//#define MBEDTLS_NO_PLATFORM_ENTROPY + +/** + * \def MBEDTLS_ENTROPY_FORCE_SHA256 + * + * Force the entropy accumulator to use a SHA-256 accumulator instead of the + * default SHA-512 based one (if both are available). + * + * Requires: MBEDTLS_SHA256_C + * + * On 32-bit systems SHA-256 can be much faster than SHA-512. Use this option + * if you have performance concerns. + * + * This option is only useful if both MBEDTLS_SHA256_C and + * MBEDTLS_SHA512_C are defined. Otherwise the available hash module is used. + */ +//#define MBEDTLS_ENTROPY_FORCE_SHA256 + +/** + * \def MBEDTLS_ENTROPY_NV_SEED + * + * Enable the non-volatile (NV) seed file-based entropy source. + * (Also enables the NV seed read/write functions in the platform layer) + * + * This is crucial (if not required) on systems that do not have a + * cryptographic entropy source (in hardware or kernel) available. + * + * Requires: MBEDTLS_ENTROPY_C, MBEDTLS_PLATFORM_C + * + * \note The read/write functions that are used by the entropy source are + * determined in the platform layer, and can be modified at runtime and/or + * compile-time depending on the flags (MBEDTLS_PLATFORM_NV_SEED_*) used. + * + * \note If you use the default implementation functions that read a seedfile + * with regular fopen(), please make sure you make a seedfile with the + * proper name (defined in MBEDTLS_PLATFORM_STD_NV_SEED_FILE) and at + * least MBEDTLS_ENTROPY_BLOCK_SIZE bytes in size that can be read from + * and written to or you will get an entropy source error! The default + * implementation will only use the first MBEDTLS_ENTROPY_BLOCK_SIZE + * bytes from the file. + * + * \note The entropy collector will write to the seed file before entropy is + * given to an external source, to update it. + */ +//#define MBEDTLS_ENTROPY_NV_SEED + +/** + * \def MBEDTLS_MEMORY_DEBUG + * + * Enable debugging of buffer allocator memory issues. Automatically prints + * (to stderr) all (fatal) messages on memory allocation issues. Enables + * function for 'debug output' of allocated memory. + * + * Requires: MBEDTLS_MEMORY_BUFFER_ALLOC_C + * + * Uncomment this macro to let the buffer allocator print out error messages. + */ +//#define MBEDTLS_MEMORY_DEBUG + +/** + * \def MBEDTLS_MEMORY_BACKTRACE + * + * Include backtrace information with each allocated block. + * + * Requires: MBEDTLS_MEMORY_BUFFER_ALLOC_C + * GLIBC-compatible backtrace() an backtrace_symbols() support + * + * Uncomment this macro to include backtrace information + */ +//#define MBEDTLS_MEMORY_BACKTRACE + +/** + * \def MBEDTLS_PK_RSA_ALT_SUPPORT + * + * Support external private RSA keys (eg from a HSM) in the PK layer. + * + * Comment this macro to disable support for external private RSA keys. + */ +#define MBEDTLS_PK_RSA_ALT_SUPPORT + +/** + * \def MBEDTLS_PKCS1_V15 + * + * Enable support for PKCS#1 v1.5 encoding. + * + * Requires: MBEDTLS_RSA_C + * + * This enables support for PKCS#1 v1.5 operations. + */ +#define MBEDTLS_PKCS1_V15 + +/** + * \def MBEDTLS_PKCS1_V21 + * + * Enable support for PKCS#1 v2.1 encoding. + * + * Requires: MBEDTLS_MD_C, MBEDTLS_RSA_C + * + * This enables support for RSAES-OAEP and RSASSA-PSS operations. + */ +#define MBEDTLS_PKCS1_V21 + +/** + * \def MBEDTLS_RSA_NO_CRT + * + * Do not use the Chinese Remainder Theorem + * for the RSA private operation. + * + * Uncomment this macro to disable the use of CRT in RSA. + * + */ +//#define MBEDTLS_RSA_NO_CRT + +/** + * \def MBEDTLS_SELF_TEST + * + * Enable the checkup functions (*_self_test). + */ +#define MBEDTLS_SELF_TEST + +/** + * \def MBEDTLS_SHA256_SMALLER + * + * Enable an implementation of SHA-256 that has lower ROM footprint but also + * lower performance. + * + * The default implementation is meant to be a reasonnable compromise between + * performance and size. This version optimizes more aggressively for size at + * the expense of performance. Eg on Cortex-M4 it reduces the size of + * mbedtls_sha256_process() from ~2KB to ~0.5KB for a performance hit of about + * 30%. + * + * Uncomment to enable the smaller implementation of SHA256. + */ +//#define MBEDTLS_SHA256_SMALLER + +/** + * \def MBEDTLS_SSL_ALL_ALERT_MESSAGES + * + * Enable sending of alert messages in case of encountered errors as per RFC. + * If you choose not to send the alert messages, mbed TLS can still communicate + * with other servers, only debugging of failures is harder. + * + * The advantage of not sending alert messages, is that no information is given + * about reasons for failures thus preventing adversaries of gaining intel. + * + * Enable sending of all alert messages + */ +#define MBEDTLS_SSL_ALL_ALERT_MESSAGES + +/** + * \def MBEDTLS_SSL_ASYNC_PRIVATE + * + * Enable asynchronous external private key operations in SSL. This allows + * you to configure an SSL connection to call an external cryptographic + * module to perform private key operations instead of performing the + * operation inside the library. + * + */ +//#define MBEDTLS_SSL_ASYNC_PRIVATE + +/** + * \def MBEDTLS_SSL_DEBUG_ALL + * + * Enable the debug messages in SSL module for all issues. + * Debug messages have been disabled in some places to prevent timing + * attacks due to (unbalanced) debugging function calls. + * + * If you need all error reporting you should enable this during debugging, + * but remove this for production servers that should log as well. + * + * Uncomment this macro to report all debug messages on errors introducing + * a timing side-channel. + * + */ +//#define MBEDTLS_SSL_DEBUG_ALL + +/** \def MBEDTLS_SSL_ENCRYPT_THEN_MAC + * + * Enable support for Encrypt-then-MAC, RFC 7366. + * + * This allows peers that both support it to use a more robust protection for + * ciphersuites using CBC, providing deep resistance against timing attacks + * on the padding or underlying cipher. + * + * This only affects CBC ciphersuites, and is useless if none is defined. + * + * Requires: MBEDTLS_SSL_PROTO_TLS1 or + * MBEDTLS_SSL_PROTO_TLS1_1 or + * MBEDTLS_SSL_PROTO_TLS1_2 + * + * Comment this macro to disable support for Encrypt-then-MAC + */ +#define MBEDTLS_SSL_ENCRYPT_THEN_MAC + +/** \def MBEDTLS_SSL_EXTENDED_MASTER_SECRET + * + * Enable support for Extended Master Secret, aka Session Hash + * (draft-ietf-tls-session-hash-02). + * + * This was introduced as "the proper fix" to the Triple Handshake familiy of + * attacks, but it is recommended to always use it (even if you disable + * renegotiation), since it actually fixes a more fundamental issue in the + * original SSL/TLS design, and has implications beyond Triple Handshake. + * + * Requires: MBEDTLS_SSL_PROTO_TLS1 or + * MBEDTLS_SSL_PROTO_TLS1_1 or + * MBEDTLS_SSL_PROTO_TLS1_2 + * + * Comment this macro to disable support for Extended Master Secret. + */ +#define MBEDTLS_SSL_EXTENDED_MASTER_SECRET + +/** + * \def MBEDTLS_SSL_FALLBACK_SCSV + * + * Enable support for FALLBACK_SCSV (draft-ietf-tls-downgrade-scsv-00). + * + * For servers, it is recommended to always enable this, unless you support + * only one version of TLS, or know for sure that none of your clients + * implements a fallback strategy. + * + * For clients, you only need this if you're using a fallback strategy, which + * is not recommended in the first place, unless you absolutely need it to + * interoperate with buggy (version-intolerant) servers. + * + * Comment this macro to disable support for FALLBACK_SCSV + */ +#define MBEDTLS_SSL_FALLBACK_SCSV + +/** + * \def MBEDTLS_SSL_HW_RECORD_ACCEL + * + * Enable hooking functions in SSL module for hardware acceleration of + * individual records. + * + * Uncomment this macro to enable hooking functions. + */ +//#define MBEDTLS_SSL_HW_RECORD_ACCEL + +/** + * \def MBEDTLS_SSL_CBC_RECORD_SPLITTING + * + * Enable 1/n-1 record splitting for CBC mode in SSLv3 and TLS 1.0. + * + * This is a countermeasure to the BEAST attack, which also minimizes the risk + * of interoperability issues compared to sending 0-length records. + * + * Comment this macro to disable 1/n-1 record splitting. + */ +#define MBEDTLS_SSL_CBC_RECORD_SPLITTING + +/** + * \def MBEDTLS_SSL_RENEGOTIATION + * + * Disable support for TLS renegotiation. + * + * The two main uses of renegotiation are (1) refresh keys on long-lived + * connections and (2) client authentication after the initial handshake. + * If you don't need renegotiation, it's probably better to disable it, since + * it has been associated with security issues in the past and is easy to + * misuse/misunderstand. + * + * Comment this to disable support for renegotiation. + * + * \note Even if this option is disabled, both client and server are aware + * of the Renegotiation Indication Extension (RFC 5746) used to + * prevent the SSL renegotiation attack (see RFC 5746 Sect. 1). + * (See \c mbedtls_ssl_conf_legacy_renegotiation for the + * configuration of this extension). + * + */ +#define MBEDTLS_SSL_RENEGOTIATION + +/** + * \def MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO + * + * Enable support for receiving and parsing SSLv2 Client Hello messages for the + * SSL Server module (MBEDTLS_SSL_SRV_C). + * + * Uncomment this macro to enable support for SSLv2 Client Hello messages. + */ +//#define MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO + +/** + * \def MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE + * + * Pick the ciphersuite according to the client's preferences rather than ours + * in the SSL Server module (MBEDTLS_SSL_SRV_C). + * + * Uncomment this macro to respect client's ciphersuite order + */ +//#define MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE + +/** + * \def MBEDTLS_SSL_MAX_FRAGMENT_LENGTH + * + * Enable support for RFC 6066 max_fragment_length extension in SSL. + * + * Comment this macro to disable support for the max_fragment_length extension + */ +#define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH + +/** + * \def MBEDTLS_SSL_PROTO_SSL3 + * + * Enable support for SSL 3.0. + * + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for SSL 3.0 + */ +//#define MBEDTLS_SSL_PROTO_SSL3 + +/** + * \def MBEDTLS_SSL_PROTO_TLS1 + * + * Enable support for TLS 1.0. + * + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for TLS 1.0 + */ +#define MBEDTLS_SSL_PROTO_TLS1 + +/** + * \def MBEDTLS_SSL_PROTO_TLS1_1 + * + * Enable support for TLS 1.1 (and DTLS 1.0 if DTLS is enabled). + * + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for TLS 1.1 / DTLS 1.0 + */ +#define MBEDTLS_SSL_PROTO_TLS1_1 + +/** + * \def MBEDTLS_SSL_PROTO_TLS1_2 + * + * Enable support for TLS 1.2 (and DTLS 1.2 if DTLS is enabled). + * + * Requires: MBEDTLS_SHA1_C or MBEDTLS_SHA256_C or MBEDTLS_SHA512_C + * (Depends on ciphersuites) + * + * Comment this macro to disable support for TLS 1.2 / DTLS 1.2 + */ +#define MBEDTLS_SSL_PROTO_TLS1_2 + +/** + * \def MBEDTLS_SSL_PROTO_DTLS + * + * Enable support for DTLS (all available versions). + * + * Enable this and MBEDTLS_SSL_PROTO_TLS1_1 to enable DTLS 1.0, + * and/or this and MBEDTLS_SSL_PROTO_TLS1_2 to enable DTLS 1.2. + * + * Requires: MBEDTLS_SSL_PROTO_TLS1_1 + * or MBEDTLS_SSL_PROTO_TLS1_2 + * + * Comment this macro to disable support for DTLS + */ +#define MBEDTLS_SSL_PROTO_DTLS + +/** + * \def MBEDTLS_SSL_ALPN + * + * Enable support for RFC 7301 Application Layer Protocol Negotiation. + * + * Comment this macro to disable support for ALPN. + */ +#define MBEDTLS_SSL_ALPN + +/** + * \def MBEDTLS_SSL_DTLS_ANTI_REPLAY + * + * Enable support for the anti-replay mechanism in DTLS. + * + * Requires: MBEDTLS_SSL_TLS_C + * MBEDTLS_SSL_PROTO_DTLS + * + * \warning Disabling this is often a security risk! + * See mbedtls_ssl_conf_dtls_anti_replay() for details. + * + * Comment this to disable anti-replay in DTLS. + */ +//#define MBEDTLS_SSL_DTLS_ANTI_REPLAY + +/** + * \def MBEDTLS_SSL_DTLS_HELLO_VERIFY + * + * Enable support for HelloVerifyRequest on DTLS servers. + * + * This feature is highly recommended to prevent DTLS servers being used as + * amplifiers in DoS attacks against other hosts. It should always be enabled + * unless you know for sure amplification cannot be a problem in the + * environment in which your server operates. + * + * \warning Disabling this can ba a security risk! (see above) + * + * Requires: MBEDTLS_SSL_PROTO_DTLS + * + * Comment this to disable support for HelloVerifyRequest. + */ +#define MBEDTLS_SSL_DTLS_HELLO_VERIFY + +/** + * \def MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE + * + * Enable server-side support for clients that reconnect from the same port. + * + * Some clients unexpectedly close the connection and try to reconnect using the + * same source port. This needs special support from the server to handle the + * new connection securely, as described in section 4.2.8 of RFC 6347. This + * flag enables that support. + * + * Requires: MBEDTLS_SSL_DTLS_HELLO_VERIFY + * + * Comment this to disable support for clients reusing the source port. + */ +#define MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE + +/** + * \def MBEDTLS_SSL_DTLS_BADMAC_LIMIT + * + * Enable support for a limit of records with bad MAC. + * + * See mbedtls_ssl_conf_dtls_badmac_limit(). + * + * Requires: MBEDTLS_SSL_PROTO_DTLS + */ +//#define MBEDTLS_SSL_DTLS_BADMAC_LIMIT + +/** + * \def MBEDTLS_SSL_SESSION_TICKETS + * + * Enable support for RFC 5077 session tickets in SSL. + * Client-side, provides full support for session tickets (maintainance of a + * session store remains the responsibility of the application, though). + * Server-side, you also need to provide callbacks for writing and parsing + * tickets, including authenticated encryption and key management. Example + * callbacks are provided by MBEDTLS_SSL_TICKET_C. + * + * Comment this macro to disable support for SSL session tickets + */ +#define MBEDTLS_SSL_SESSION_TICKETS + +/** + * \def MBEDTLS_SSL_EXPORT_KEYS + * + * Enable support for exporting key block and master secret. + * This is required for certain users of TLS, e.g. EAP-TLS. + * + * Comment this macro to disable support for key export + */ +#define MBEDTLS_SSL_EXPORT_KEYS + +/** + * \def MBEDTLS_SSL_SERVER_NAME_INDICATION + * + * Enable support for RFC 6066 server name indication (SNI) in SSL. + * + * Requires: MBEDTLS_X509_CRT_PARSE_C + * + * Comment this macro to disable support for server name indication in SSL + */ +#define MBEDTLS_SSL_SERVER_NAME_INDICATION + +/** + * \def MBEDTLS_SSL_TRUNCATED_HMAC + * + * Enable support for RFC 6066 truncated HMAC in SSL. + * + * Comment this macro to disable support for truncated HMAC in SSL + */ +#define MBEDTLS_SSL_TRUNCATED_HMAC + +/** + * \def MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT + * + * Fallback to old (pre-2.7), non-conforming implementation of the truncated + * HMAC extension which also truncates the HMAC key. Note that this option is + * only meant for a transitory upgrade period and is likely to be removed in + * a future version of the library. + * + * \warning The old implementation is non-compliant and has a security weakness + * (2^80 brute force attack on the HMAC key used for a single, + * uninterrupted connection). This should only be enabled temporarily + * when (1) the use of truncated HMAC is essential in order to save + * bandwidth, and (2) the peer is an Mbed TLS stack that doesn't use + * the fixed implementation yet (pre-2.7). + * + * \deprecated This option is deprecated and will likely be removed in a + * future version of Mbed TLS. + * + * Uncomment to fallback to old, non-compliant truncated HMAC implementation. + * + * Requires: MBEDTLS_SSL_TRUNCATED_HMAC + */ +//#define MBEDTLS_SSL_TRUNCATED_HMAC_COMPAT + +/** + * \def MBEDTLS_THREADING_ALT + * + * Provide your own alternate threading implementation. + * + * Requires: MBEDTLS_THREADING_C + * + * Uncomment this to allow your own alternate threading implementation. + */ +//#define MBEDTLS_THREADING_ALT + +/** + * \def MBEDTLS_THREADING_PTHREAD + * + * Enable the pthread wrapper layer for the threading layer. + * + * Requires: MBEDTLS_THREADING_C + * + * Uncomment this to enable pthread mutexes. + */ +//#define MBEDTLS_THREADING_PTHREAD + +/** + * \def MBEDTLS_VERSION_FEATURES + * + * Allow run-time checking of compile-time enabled features. Thus allowing users + * to check at run-time if the library is for instance compiled with threading + * support via mbedtls_version_check_feature(). + * + * Requires: MBEDTLS_VERSION_C + * + * Comment this to disable run-time checking and save ROM space + */ +#define MBEDTLS_VERSION_FEATURES + +/** + * \def MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 + * + * If set, the X509 parser will not break-off when parsing an X509 certificate + * and encountering an extension in a v1 or v2 certificate. + * + * Uncomment to prevent an error. + */ +//#define MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 + +/** + * \def MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION + * + * If set, the X509 parser will not break-off when parsing an X509 certificate + * and encountering an unknown critical extension. + * + * \warning Depending on your PKI use, enabling this can be a security risk! + * + * Uncomment to prevent an error. + */ +//#define MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION + +/** + * \def MBEDTLS_X509_CHECK_KEY_USAGE + * + * Enable verification of the keyUsage extension (CA and leaf certificates). + * + * Disabling this avoids problems with mis-issued and/or misused + * (intermediate) CA and leaf certificates. + * + * \warning Depending on your PKI use, disabling this can be a security risk! + * + * Comment to skip keyUsage checking for both CA and leaf certificates. + */ +#define MBEDTLS_X509_CHECK_KEY_USAGE + +/** + * \def MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE + * + * Enable verification of the extendedKeyUsage extension (leaf certificates). + * + * Disabling this avoids problems with mis-issued and/or misused certificates. + * + * \warning Depending on your PKI use, disabling this can be a security risk! + * + * Comment to skip extendedKeyUsage checking for certificates. + */ +#define MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE + +/** + * \def MBEDTLS_X509_RSASSA_PSS_SUPPORT + * + * Enable parsing and verification of X.509 certificates, CRLs and CSRS + * signed with RSASSA-PSS (aka PKCS#1 v2.1). + * + * Comment this macro to disallow using RSASSA-PSS in certificates. + */ +#define MBEDTLS_X509_RSASSA_PSS_SUPPORT + +/** + * \def MBEDTLS_ZLIB_SUPPORT + * + * If set, the SSL/TLS module uses ZLIB to support compression and + * decompression of packet data. + * + * \warning TLS-level compression MAY REDUCE SECURITY! See for example the + * CRIME attack. Before enabling this option, you should examine with care if + * CRIME or similar exploits may be a applicable to your use case. + * + * \note Currently compression can't be used with DTLS. + * + * \deprecated This feature is deprecated and will be removed + * in the next major revision of the library. + * + * Used in: library/ssl_tls.c + * library/ssl_cli.c + * library/ssl_srv.c + * + * This feature requires zlib library and headers to be present. + * + * Uncomment to enable use of ZLIB + */ +//#define MBEDTLS_ZLIB_SUPPORT +/* \} name SECTION: mbed TLS feature support */ + +/** + * \name SECTION: mbed TLS modules + * + * This section enables or disables entire modules in mbed TLS + * \{ + */ + +/** + * \def MBEDTLS_AESNI_C + * + * Enable AES-NI support on x86-64. + * + * Module: library/aesni.c + * Caller: library/aes.c + * + * Requires: MBEDTLS_HAVE_ASM + * + * This modules adds support for the AES-NI instructions on x86-64 + */ +//#define MBEDTLS_AESNI_C + +/** + * \def MBEDTLS_AES_C + * + * Enable the AES block cipher. + * + * Module: library/aes.c + * Caller: library/cipher.c + * library/pem.c + * library/ctr_drbg.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA + * + * PEM_PARSE uses AES for decrypting encrypted keys. + */ +#define MBEDTLS_AES_C + +/** + * \def MBEDTLS_ARC4_C + * + * Enable the ARCFOUR stream cipher. + * + * Module: library/arc4.c + * Caller: library/cipher.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_MD5 + * MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA + * MBEDTLS_TLS_PSK_WITH_RC4_128_SHA + * + * \warning ARC4 is considered a weak cipher and its use constitutes a + * security risk. If possible, we recommend avoidng dependencies on + * it, and considering stronger ciphers instead. + * + */ +#define MBEDTLS_ARC4_C + +/** + * \def MBEDTLS_ASN1_PARSE_C + * + * Enable the generic ASN1 parser. + * + * Module: library/asn1.c + * Caller: library/x509.c + * library/dhm.c + * library/pkcs12.c + * library/pkcs5.c + * library/pkparse.c + */ +#define MBEDTLS_ASN1_PARSE_C + +/** + * \def MBEDTLS_ASN1_WRITE_C + * + * Enable the generic ASN1 writer. + * + * Module: library/asn1write.c + * Caller: library/ecdsa.c + * library/pkwrite.c + * library/x509_create.c + * library/x509write_crt.c + * library/x509write_csr.c + */ +#define MBEDTLS_ASN1_WRITE_C + +/** + * \def MBEDTLS_BASE64_C + * + * Enable the Base64 module. + * + * Module: library/base64.c + * Caller: library/pem.c + * + * This module is required for PEM support (required by X.509). + */ +#define MBEDTLS_BASE64_C + +/** + * \def MBEDTLS_BIGNUM_C + * + * Enable the multi-precision integer library. + * + * Module: library/bignum.c + * Caller: library/dhm.c + * library/ecp.c + * library/ecdsa.c + * library/rsa.c + * library/rsa_internal.c + * library/ssl_tls.c + * + * This module is required for RSA, DHM and ECC (ECDH, ECDSA) support. + */ +#define MBEDTLS_BIGNUM_C + +/** + * \def MBEDTLS_BLOWFISH_C + * + * Enable the Blowfish block cipher. + * + * Module: library/blowfish.c + */ +#define MBEDTLS_BLOWFISH_C + +/** + * \def MBEDTLS_CAMELLIA_C + * + * Enable the Camellia block cipher. + * + * Module: library/camellia.c + * Caller: library/cipher.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 + */ +#define MBEDTLS_CAMELLIA_C + +/** + * \def MBEDTLS_ARIA_C + * + * Enable the ARIA block cipher. + * + * Module: library/aria.c + * Caller: library/cipher.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * + * MBEDTLS_TLS_RSA_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 + */ +//#define MBEDTLS_ARIA_C + +/** + * \def MBEDTLS_CCM_C + * + * Enable the Counter with CBC-MAC (CCM) mode for 128-bit block cipher. + * + * Module: library/ccm.c + * + * Requires: MBEDTLS_AES_C or MBEDTLS_CAMELLIA_C + * + * This module enables the AES-CCM ciphersuites, if other requisites are + * enabled as well. + */ +//#define MBEDTLS_CCM_C + +/** + * \def MBEDTLS_CERTS_C + * + * Enable the test certificates. + * + * Module: library/certs.c + * Caller: + * + * This module is used for testing (ssl_client/server). + */ +#define MBEDTLS_CERTS_C + +/** + * \def MBEDTLS_CHACHA20_C + * + * Enable the ChaCha20 stream cipher. + * + * Module: library/chacha20.c + */ +//#define MBEDTLS_CHACHA20_C + +/** + * \def MBEDTLS_CHACHAPOLY_C + * + * Enable the ChaCha20-Poly1305 AEAD algorithm. + * + * Module: library/chachapoly.c + * + * This module requires: MBEDTLS_CHACHA20_C, MBEDTLS_POLY1305_C + */ +//#define MBEDTLS_CHACHAPOLY_C + +/** + * \def MBEDTLS_CIPHER_C + * + * Enable the generic cipher layer. + * + * Module: library/cipher.c + * Caller: library/ssl_tls.c + * + * Uncomment to enable generic cipher wrappers. + */ +#define MBEDTLS_CIPHER_C + +/** + * \def MBEDTLS_CMAC_C + * + * Enable the CMAC (Cipher-based Message Authentication Code) mode for block + * ciphers. + * + * Module: library/cmac.c + * + * Requires: MBEDTLS_AES_C or MBEDTLS_DES_C + * + */ +#define MBEDTLS_CMAC_C + +/** + * \def MBEDTLS_CTR_DRBG_C + * + * Enable the CTR_DRBG AES-256-based random generator. + * + * Module: library/ctr_drbg.c + * Caller: + * + * Requires: MBEDTLS_AES_C + * + * This module provides the CTR_DRBG AES-256 random number generator. + */ +#define MBEDTLS_CTR_DRBG_C + +/** + * \def MBEDTLS_DEBUG_C + * + * Enable the debug functions. + * + * Module: library/debug.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * This module provides debugging functions. + */ +#define MBEDTLS_DEBUG_C + +/** + * \def MBEDTLS_DES_C + * + * Enable the DES block cipher. + * + * Module: library/des.c + * Caller: library/pem.c + * library/cipher.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA + * + * PEM_PARSE uses DES/3DES for decrypting encrypted keys. + * + * \warning DES is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers instead. + */ +#define MBEDTLS_DES_C + +/** + * \def MBEDTLS_DHM_C + * + * Enable the Diffie-Hellman-Merkle module. + * + * Module: library/dhm.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * This module is used by the following key exchanges: + * DHE-RSA, DHE-PSK + * + * \warning Using DHE constitutes a security risk as it + * is not possible to validate custom DH parameters. + * If possible, it is recommended users should consider + * preferring other methods of key exchange. + * See dhm.h for more details. + * + */ +//#define MBEDTLS_DHM_C + +/** + * \def MBEDTLS_ECDH_C + * + * Enable the elliptic curve Diffie-Hellman library. + * + * Module: library/ecdh.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * This module is used by the following key exchanges: + * ECDHE-ECDSA, ECDHE-RSA, DHE-PSK + * + * Requires: MBEDTLS_ECP_C + */ +#define MBEDTLS_ECDH_C + +/** + * \def MBEDTLS_ECDSA_C + * + * Enable the elliptic curve DSA library. + * + * Module: library/ecdsa.c + * Caller: + * + * This module is used by the following key exchanges: + * ECDHE-ECDSA + * + * Requires: MBEDTLS_ECP_C, MBEDTLS_ASN1_WRITE_C, MBEDTLS_ASN1_PARSE_C + */ +#define MBEDTLS_ECDSA_C + +/** + * \def MBEDTLS_ECJPAKE_C + * + * Enable the elliptic curve J-PAKE library. + * + * \warning This is currently experimental. EC J-PAKE support is based on the + * Thread v1.0.0 specification; incompatible changes to the specification + * might still happen. For this reason, this is disabled by default. + * + * Module: library/ecjpake.c + * Caller: + * + * This module is used by the following key exchanges: + * ECJPAKE + * + * Requires: MBEDTLS_ECP_C, MBEDTLS_MD_C + */ +//#define MBEDTLS_ECJPAKE_C + +/** + * \def MBEDTLS_ECP_C + * + * Enable the elliptic curve over GF(p) library. + * + * Module: library/ecp.c + * Caller: library/ecdh.c + * library/ecdsa.c + * library/ecjpake.c + * + * Requires: MBEDTLS_BIGNUM_C and at least one MBEDTLS_ECP_DP_XXX_ENABLED + */ +#define MBEDTLS_ECP_C + +/** + * \def MBEDTLS_ENTROPY_C + * + * Enable the platform-specific entropy code. + * + * Module: library/entropy.c + * Caller: + * + * Requires: MBEDTLS_SHA512_C or MBEDTLS_SHA256_C + * + * This module provides a generic entropy pool + */ +#define MBEDTLS_ENTROPY_C + +/** + * \def MBEDTLS_ERROR_C + * + * Enable error code to error string conversion. + * + * Module: library/error.c + * Caller: + * + * This module enables mbedtls_strerror(). + */ +#define MBEDTLS_ERROR_C + +/** + * \def MBEDTLS_GCM_C + * + * Enable the Galois/Counter Mode (GCM) for AES. + * + * Module: library/gcm.c + * + * Requires: MBEDTLS_AES_C or MBEDTLS_CAMELLIA_C + * + * This module enables the AES-GCM and CAMELLIA-GCM ciphersuites, if other + * requisites are enabled as well. + */ +//#define MBEDTLS_GCM_C + +/** + * \def MBEDTLS_HAVEGE_C + * + * Enable the HAVEGE random generator. + * + * Warning: the HAVEGE random generator is not suitable for virtualized + * environments + * + * Warning: the HAVEGE random generator is dependent on timing and specific + * processor traits. It is therefore not advised to use HAVEGE as + * your applications primary random generator or primary entropy pool + * input. As a secondary input to your entropy pool, it IS able add + * the (limited) extra entropy it provides. + * + * Module: library/havege.c + * Caller: + * + * Requires: MBEDTLS_TIMING_C + * + * Uncomment to enable the HAVEGE random generator. + */ +//#define MBEDTLS_HAVEGE_C + +/** + * \def MBEDTLS_HKDF_C + * + * Enable the HKDF algorithm (RFC 5869). + * + * Module: library/hkdf.c + * Caller: + * + * Requires: MBEDTLS_MD_C + * + * This module adds support for the Hashed Message Authentication Code + * (HMAC)-based key derivation function (HKDF). + */ +//#define MBEDTLS_HKDF_C + +/** + * \def MBEDTLS_HMAC_DRBG_C + * + * Enable the HMAC_DRBG random generator. + * + * Module: library/hmac_drbg.c + * Caller: + * + * Requires: MBEDTLS_MD_C + * + * Uncomment to enable the HMAC_DRBG random number geerator. + */ +//#define MBEDTLS_HMAC_DRBG_C + +/** + * \def MBEDTLS_NIST_KW_C + * + * Enable the Key Wrapping mode for 128-bit block ciphers, + * as defined in NIST SP 800-38F. Only KW and KWP modes + * are supported. At the moment, only AES is approved by NIST. + * + * Module: library/nist_kw.c + * + * Requires: MBEDTLS_AES_C and MBEDTLS_CIPHER_C + */ +//#define MBEDTLS_NIST_KW_C + +/** + * \def MBEDTLS_MD_C + * + * Enable the generic message digest layer. + * + * Module: library/md.c + * Caller: + * + * Uncomment to enable generic message digest wrappers. + */ +#define MBEDTLS_MD_C + +/** + * \def MBEDTLS_MD2_C + * + * Enable the MD2 hash algorithm. + * + * Module: library/md2.c + * Caller: + * + * Uncomment to enable support for (rare) MD2-signed X.509 certs. + * + * \warning MD2 is considered a weak message digest and its use constitutes a + * security risk. If possible, we recommend avoiding dependencies on + * it, and considering stronger message digests instead. + * + */ +//#define MBEDTLS_MD2_C + +/** + * \def MBEDTLS_MD4_C + * + * Enable the MD4 hash algorithm. + * + * Module: library/md4.c + * Caller: + * + * Uncomment to enable support for (rare) MD4-signed X.509 certs. + * + * \warning MD4 is considered a weak message digest and its use constitutes a + * security risk. If possible, we recommend avoiding dependencies on + * it, and considering stronger message digests instead. + * + */ +//#define MBEDTLS_MD4_C + +/** + * \def MBEDTLS_MD5_C + * + * Enable the MD5 hash algorithm. + * + * Module: library/md5.c + * Caller: library/md.c + * library/pem.c + * library/ssl_tls.c + * + * This module is required for SSL/TLS up to version 1.1, and for TLS 1.2 + * depending on the handshake parameters. Further, it is used for checking + * MD5-signed certificates, and for PBKDF1 when decrypting PEM-encoded + * encrypted keys. + * + * \warning MD5 is considered a weak message digest and its use constitutes a + * security risk. If possible, we recommend avoiding dependencies on + * it, and considering stronger message digests instead. + * + */ +#define MBEDTLS_MD5_C + +/** + * \def MBEDTLS_MEMORY_BUFFER_ALLOC_C + * + * Enable the buffer allocator implementation that makes use of a (stack) + * based buffer to 'allocate' dynamic memory. (replaces calloc() and free() + * calls) + * + * Module: library/memory_buffer_alloc.c + * + * Requires: MBEDTLS_PLATFORM_C + * MBEDTLS_PLATFORM_MEMORY (to use it within mbed TLS) + * + * Enable this module to enable the buffer memory allocator. + */ +//#define MBEDTLS_MEMORY_BUFFER_ALLOC_C + +/** + * \def MBEDTLS_NET_C + * + * Enable the TCP and UDP over IPv6/IPv4 networking routines. + * + * \note This module only works on POSIX/Unix (including Linux, BSD and OS X) + * and Windows. For other platforms, you'll want to disable it, and write your + * own networking callbacks to be passed to \c mbedtls_ssl_set_bio(). + * + * \note See also our Knowledge Base article about porting to a new + * environment: + * https://tls.mbed.org/kb/how-to/how-do-i-port-mbed-tls-to-a-new-environment-OS + * + * Module: library/net_sockets.c + * + * This module provides networking routines. + */ +//#define MBEDTLS_NET_C + +/** + * \def MBEDTLS_OID_C + * + * Enable the OID database. + * + * Module: library/oid.c + * Caller: library/asn1write.c + * library/pkcs5.c + * library/pkparse.c + * library/pkwrite.c + * library/rsa.c + * library/x509.c + * library/x509_create.c + * library/x509_crl.c + * library/x509_crt.c + * library/x509_csr.c + * library/x509write_crt.c + * library/x509write_csr.c + * + * This modules translates between OIDs and internal values. + */ +#define MBEDTLS_OID_C + +/** + * \def MBEDTLS_PADLOCK_C + * + * Enable VIA Padlock support on x86. + * + * Module: library/padlock.c + * Caller: library/aes.c + * + * Requires: MBEDTLS_HAVE_ASM + * + * This modules adds support for the VIA PadLock on x86. + */ +//#define MBEDTLS_PADLOCK_C + +/** + * \def MBEDTLS_PEM_PARSE_C + * + * Enable PEM decoding / parsing. + * + * Module: library/pem.c + * Caller: library/dhm.c + * library/pkparse.c + * library/x509_crl.c + * library/x509_crt.c + * library/x509_csr.c + * + * Requires: MBEDTLS_BASE64_C + * + * This modules adds support for decoding / parsing PEM files. + */ +#define MBEDTLS_PEM_PARSE_C + +/** + * \def MBEDTLS_PEM_WRITE_C + * + * Enable PEM encoding / writing. + * + * Module: library/pem.c + * Caller: library/pkwrite.c + * library/x509write_crt.c + * library/x509write_csr.c + * + * Requires: MBEDTLS_BASE64_C + * + * This modules adds support for encoding / writing PEM files. + */ +#define MBEDTLS_PEM_WRITE_C + +/** + * \def MBEDTLS_PK_C + * + * Enable the generic public (asymetric) key layer. + * + * Module: library/pk.c + * Caller: library/ssl_tls.c + * library/ssl_cli.c + * library/ssl_srv.c + * + * Requires: MBEDTLS_RSA_C or MBEDTLS_ECP_C + * + * Uncomment to enable generic public key wrappers. + */ +#define MBEDTLS_PK_C + +/** + * \def MBEDTLS_PK_PARSE_C + * + * Enable the generic public (asymetric) key parser. + * + * Module: library/pkparse.c + * Caller: library/x509_crt.c + * library/x509_csr.c + * + * Requires: MBEDTLS_PK_C + * + * Uncomment to enable generic public key parse functions. + */ +#define MBEDTLS_PK_PARSE_C + +/** + * \def MBEDTLS_PK_WRITE_C + * + * Enable the generic public (asymetric) key writer. + * + * Module: library/pkwrite.c + * Caller: library/x509write.c + * + * Requires: MBEDTLS_PK_C + * + * Uncomment to enable generic public key write functions. + */ +#define MBEDTLS_PK_WRITE_C + +/** + * \def MBEDTLS_PKCS5_C + * + * Enable PKCS#5 functions. + * + * Module: library/pkcs5.c + * + * Requires: MBEDTLS_MD_C + * + * This module adds support for the PKCS#5 functions. + */ +#define MBEDTLS_PKCS5_C + +/** + * \def MBEDTLS_PKCS11_C + * + * Enable wrapper for PKCS#11 smartcard support. + * + * Module: library/pkcs11.c + * Caller: library/pk.c + * + * Requires: MBEDTLS_PK_C + * + * This module enables SSL/TLS PKCS #11 smartcard support. + * Requires the presence of the PKCS#11 helper library (libpkcs11-helper) + */ +//#define MBEDTLS_PKCS11_C + +/** + * \def MBEDTLS_PKCS12_C + * + * Enable PKCS#12 PBE functions. + * Adds algorithms for parsing PKCS#8 encrypted private keys + * + * Module: library/pkcs12.c + * Caller: library/pkparse.c + * + * Requires: MBEDTLS_ASN1_PARSE_C, MBEDTLS_CIPHER_C, MBEDTLS_MD_C + * Can use: MBEDTLS_ARC4_C + * + * This module enables PKCS#12 functions. + */ +#define MBEDTLS_PKCS12_C + +/** + * \def MBEDTLS_PLATFORM_C + * + * Enable the platform abstraction layer that allows you to re-assign + * functions like calloc(), free(), snprintf(), printf(), fprintf(), exit(). + * + * Enabling MBEDTLS_PLATFORM_C enables to use of MBEDTLS_PLATFORM_XXX_ALT + * or MBEDTLS_PLATFORM_XXX_MACRO directives, allowing the functions mentioned + * above to be specified at runtime or compile time respectively. + * + * \note This abstraction layer must be enabled on Windows (including MSYS2) + * as other module rely on it for a fixed snprintf implementation. + * + * Module: library/platform.c + * Caller: Most other .c files + * + * This module enables abstraction of common (libc) functions. + */ +#define MBEDTLS_PLATFORM_C + +/** + * \def MBEDTLS_POLY1305_C + * + * Enable the Poly1305 MAC algorithm. + * + * Module: library/poly1305.c + * Caller: library/chachapoly.c + */ +//#define MBEDTLS_POLY1305_C + +/** + * \def MBEDTLS_RIPEMD160_C + * + * Enable the RIPEMD-160 hash algorithm. + * + * Module: library/ripemd160.c + * Caller: library/md.c + * + */ +//#define MBEDTLS_RIPEMD160_C + +/** + * \def MBEDTLS_RSA_C + * + * Enable the RSA public-key cryptosystem. + * + * Module: library/rsa.c + * library/rsa_internal.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509.c + * + * This module is used by the following key exchanges: + * RSA, DHE-RSA, ECDHE-RSA, RSA-PSK + * + * Requires: MBEDTLS_BIGNUM_C, MBEDTLS_OID_C + */ +#define MBEDTLS_RSA_C + +/** + * \def MBEDTLS_SHA1_C + * + * Enable the SHA1 cryptographic hash algorithm. + * + * Module: library/sha1.c + * Caller: library/md.c + * library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509write_crt.c + * + * This module is required for SSL/TLS up to version 1.1, for TLS 1.2 + * depending on the handshake parameters, and for SHA1-signed certificates. + * + * \warning SHA-1 is considered a weak message digest and its use constitutes + * a security risk. If possible, we recommend avoiding dependencies + * on it, and considering stronger message digests instead. + * + */ +#define MBEDTLS_SHA1_C + +/** + * \def MBEDTLS_SHA256_C + * + * Enable the SHA-224 and SHA-256 cryptographic hash algorithms. + * + * Module: library/sha256.c + * Caller: library/entropy.c + * library/md.c + * library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * This module adds support for SHA-224 and SHA-256. + * This module is required for the SSL/TLS 1.2 PRF function. + */ +#define MBEDTLS_SHA256_C + +/** + * \def MBEDTLS_SHA512_C + * + * Enable the SHA-384 and SHA-512 cryptographic hash algorithms. + * + * Module: library/sha512.c + * Caller: library/entropy.c + * library/md.c + * library/ssl_cli.c + * library/ssl_srv.c + * + * This module adds support for SHA-384 and SHA-512. + */ +#define MBEDTLS_SHA512_C + +/** + * \def MBEDTLS_SSL_CACHE_C + * + * Enable simple SSL cache implementation. + * + * Module: library/ssl_cache.c + * Caller: + * + * Requires: MBEDTLS_SSL_CACHE_C + */ +#define MBEDTLS_SSL_CACHE_C + +/** + * \def MBEDTLS_SSL_COOKIE_C + * + * Enable basic implementation of DTLS cookies for hello verification. + * + * Module: library/ssl_cookie.c + * Caller: + */ +#define MBEDTLS_SSL_COOKIE_C + +/** + * \def MBEDTLS_SSL_TICKET_C + * + * Enable an implementation of TLS server-side callbacks for session tickets. + * + * Module: library/ssl_ticket.c + * Caller: + * + * Requires: MBEDTLS_CIPHER_C + */ +#define MBEDTLS_SSL_TICKET_C + +/** + * \def MBEDTLS_SSL_CLI_C + * + * Enable the SSL/TLS client code. + * + * Module: library/ssl_cli.c + * Caller: + * + * Requires: MBEDTLS_SSL_TLS_C + * + * This module is required for SSL/TLS client support. + */ +//#define MBEDTLS_SSL_CLI_C + +/** + * \def MBEDTLS_SSL_SRV_C + * + * Enable the SSL/TLS server code. + * + * Module: library/ssl_srv.c + * Caller: + * + * Requires: MBEDTLS_SSL_TLS_C + * + * This module is required for SSL/TLS server support. + */ +//#define MBEDTLS_SSL_SRV_C + +/** + * \def MBEDTLS_SSL_TLS_C + * + * Enable the generic SSL/TLS code. + * + * Module: library/ssl_tls.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * Requires: MBEDTLS_CIPHER_C, MBEDTLS_MD_C + * and at least one of the MBEDTLS_SSL_PROTO_XXX defines + * + * This module is required for SSL/TLS. + */ +//#define MBEDTLS_SSL_TLS_C + +/** + * \def MBEDTLS_THREADING_C + * + * Enable the threading abstraction layer. + * By default mbed TLS assumes it is used in a non-threaded environment or that + * contexts are not shared between threads. If you do intend to use contexts + * between threads, you will need to enable this layer to prevent race + * conditions. See also our Knowledge Base article about threading: + * https://tls.mbed.org/kb/development/thread-safety-and-multi-threading + * + * Module: library/threading.c + * + * This allows different threading implementations (self-implemented or + * provided). + * + * You will have to enable either MBEDTLS_THREADING_ALT or + * MBEDTLS_THREADING_PTHREAD. + * + * Enable this layer to allow use of mutexes within mbed TLS + */ +//#define MBEDTLS_THREADING_C + +/** + * \def MBEDTLS_TIMING_C + * + * Enable the semi-portable timing interface. + * + * \note The provided implementation only works on POSIX/Unix (including Linux, + * BSD and OS X) and Windows. On other platforms, you can either disable that + * module and provide your own implementations of the callbacks needed by + * \c mbedtls_ssl_set_timer_cb() for DTLS, or leave it enabled and provide + * your own implementation of the whole module by setting + * \c MBEDTLS_TIMING_ALT in the current file. + * + * \note See also our Knowledge Base article about porting to a new + * environment: + * https://tls.mbed.org/kb/how-to/how-do-i-port-mbed-tls-to-a-new-environment-OS + * + * Module: library/timing.c + * Caller: library/havege.c + * + * This module is used by the HAVEGE random number generator. + */ +#define MBEDTLS_TIMING_C + +/** + * \def MBEDTLS_VERSION_C + * + * Enable run-time version information. + * + * Module: library/version.c + * + * This module provides run-time version information. + */ +#define MBEDTLS_VERSION_C + +/** + * \def MBEDTLS_X509_USE_C + * + * Enable X.509 core for using certificates. + * + * Module: library/x509.c + * Caller: library/x509_crl.c + * library/x509_crt.c + * library/x509_csr.c + * + * Requires: MBEDTLS_ASN1_PARSE_C, MBEDTLS_BIGNUM_C, MBEDTLS_OID_C, + * MBEDTLS_PK_PARSE_C + * + * This module is required for the X.509 parsing modules. + */ +#define MBEDTLS_X509_USE_C + +/** + * \def MBEDTLS_X509_CRT_PARSE_C + * + * Enable X.509 certificate parsing. + * + * Module: library/x509_crt.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * Requires: MBEDTLS_X509_USE_C + * + * This module is required for X.509 certificate parsing. + */ +#define MBEDTLS_X509_CRT_PARSE_C + +/** + * \def MBEDTLS_X509_CRL_PARSE_C + * + * Enable X.509 CRL parsing. + * + * Module: library/x509_crl.c + * Caller: library/x509_crt.c + * + * Requires: MBEDTLS_X509_USE_C + * + * This module is required for X.509 CRL parsing. + */ +#define MBEDTLS_X509_CRL_PARSE_C + +/** + * \def MBEDTLS_X509_CSR_PARSE_C + * + * Enable X.509 Certificate Signing Request (CSR) parsing. + * + * Module: library/x509_csr.c + * Caller: library/x509_crt_write.c + * + * Requires: MBEDTLS_X509_USE_C + * + * This module is used for reading X.509 certificate request. + */ +#define MBEDTLS_X509_CSR_PARSE_C + +/** + * \def MBEDTLS_X509_CREATE_C + * + * Enable X.509 core for creating certificates. + * + * Module: library/x509_create.c + * + * Requires: MBEDTLS_BIGNUM_C, MBEDTLS_OID_C, MBEDTLS_PK_WRITE_C + * + * This module is the basis for creating X.509 certificates and CSRs. + */ +#define MBEDTLS_X509_CREATE_C + +/** + * \def MBEDTLS_X509_CRT_WRITE_C + * + * Enable creating X.509 certificates. + * + * Module: library/x509_crt_write.c + * + * Requires: MBEDTLS_X509_CREATE_C + * + * This module is required for X.509 certificate creation. + */ +#define MBEDTLS_X509_CRT_WRITE_C + +/** + * \def MBEDTLS_X509_CSR_WRITE_C + * + * Enable creating X.509 Certificate Signing Requests (CSR). + * + * Module: library/x509_csr_write.c + * + * Requires: MBEDTLS_X509_CREATE_C + * + * This module is required for X.509 certificate request writing. + */ +#define MBEDTLS_X509_CSR_WRITE_C + +/** + * \def MBEDTLS_XTEA_C + * + * Enable the XTEA block cipher. + * + * Module: library/xtea.c + * Caller: + */ +//#define MBEDTLS_XTEA_C + +/* \} name SECTION: mbed TLS modules */ + +/** + * \name SECTION: Module configuration options + * + * This section allows for the setting of module specific sizes and + * configuration options. The default values are already present in the + * relevant header files and should suffice for the regular use cases. + * + * Our advice is to enable options and change their values here + * only if you have a good reason and know the consequences. + * + * Please check the respective header file for documentation on these + * parameters (to prevent duplicate documentation). + * \{ + */ + +/* MPI / BIGNUM options */ +//#define MBEDTLS_MPI_WINDOW_SIZE 6 /**< Maximum windows size used. */ +//#define MBEDTLS_MPI_MAX_SIZE 1024 /**< Maximum number of bytes for usable MPIs. */ + +/* CTR_DRBG options */ +//#define MBEDTLS_CTR_DRBG_ENTROPY_LEN 48 /**< Amount of entropy used per seed by default (48 with SHA-512, 32 with SHA-256) */ +//#define MBEDTLS_CTR_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ +//#define MBEDTLS_CTR_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +//#define MBEDTLS_CTR_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +//#define MBEDTLS_CTR_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ + +/* HMAC_DRBG options */ +//#define MBEDTLS_HMAC_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ +//#define MBEDTLS_HMAC_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +//#define MBEDTLS_HMAC_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +//#define MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ + +/* ECP options */ +//#define MBEDTLS_ECP_MAX_BITS 521 /**< Maximum bit size of groups */ +//#define MBEDTLS_ECP_WINDOW_SIZE 6 /**< Maximum window size used */ +//#define MBEDTLS_ECP_FIXED_POINT_OPTIM 1 /**< Enable fixed-point speed-up */ + +/* Entropy options */ +//#define MBEDTLS_ENTROPY_MAX_SOURCES 20 /**< Maximum number of sources supported */ +//#define MBEDTLS_ENTROPY_MAX_GATHER 128 /**< Maximum amount requested from entropy sources */ +//#define MBEDTLS_ENTROPY_MIN_HARDWARE 32 /**< Default minimum number of bytes required for the hardware entropy source mbedtls_hardware_poll() before entropy is released */ + +/* Memory buffer allocator options */ +//#define MBEDTLS_MEMORY_ALIGN_MULTIPLE 4 /**< Align on multiples of this value */ + +/* Platform options */ +//#define MBEDTLS_PLATFORM_STD_MEM_HDR /**< Header to include if MBEDTLS_PLATFORM_NO_STD_FUNCTIONS is defined. Don't define if no header is needed. */ +//#define MBEDTLS_PLATFORM_STD_CALLOC calloc /**< Default allocator to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_FREE free /**< Default free to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_EXIT exit /**< Default exit to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_TIME time /**< Default time to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */ +//#define MBEDTLS_PLATFORM_STD_FPRINTF fprintf /**< Default fprintf to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_PRINTF printf /**< Default printf to use, can be undefined */ +/* Note: your snprintf must correclty zero-terminate the buffer! */ +//#define MBEDTLS_PLATFORM_STD_SNPRINTF snprintf /**< Default snprintf to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_EXIT_SUCCESS 0 /**< Default exit value to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_EXIT_FAILURE 1 /**< Default exit value to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_NV_SEED_READ mbedtls_platform_std_nv_seed_read /**< Default nv_seed_read function to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_NV_SEED_WRITE mbedtls_platform_std_nv_seed_write /**< Default nv_seed_write function to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_NV_SEED_FILE "seedfile" /**< Seed file to read/write with default implementation */ + +/* To Use Function Macros MBEDTLS_PLATFORM_C must be enabled */ +/* MBEDTLS_PLATFORM_XXX_MACRO and MBEDTLS_PLATFORM_XXX_ALT cannot both be defined */ +//#define MBEDTLS_PLATFORM_CALLOC_MACRO calloc /**< Default allocator macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_FREE_MACRO free /**< Default free macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_EXIT_MACRO exit /**< Default exit macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_TIME_MACRO time /**< Default time macro to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */ +//#define MBEDTLS_PLATFORM_TIME_TYPE_MACRO time_t /**< Default time macro to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */ +//#define MBEDTLS_PLATFORM_FPRINTF_MACRO fprintf /**< Default fprintf macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_PRINTF_MACRO printf /**< Default printf macro to use, can be undefined */ +/* Note: your snprintf must correclty zero-terminate the buffer! */ +//#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf /**< Default snprintf macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_NV_SEED_READ_MACRO mbedtls_platform_std_nv_seed_read /**< Default nv_seed_read function to use, can be undefined */ +//#define MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO mbedtls_platform_std_nv_seed_write /**< Default nv_seed_write function to use, can be undefined */ + +/* SSL Cache options */ +//#define MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT 86400 /**< 1 day */ +//#define MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES 50 /**< Maximum entries in cache */ + +/* SSL options */ + +/** \def MBEDTLS_SSL_MAX_CONTENT_LEN + * + * Maximum fragment length in bytes. + * + * Determines the size of both the incoming and outgoing TLS I/O buffers. + * + * Uncommenting MBEDTLS_SSL_IN_CONTENT_LEN and/or MBEDTLS_SSL_OUT_CONTENT_LEN + * will override this length by setting maximum incoming and/or outgoing + * fragment length, respectively. + */ +//#define MBEDTLS_SSL_MAX_CONTENT_LEN 16384 + +/** \def MBEDTLS_SSL_IN_CONTENT_LEN + * + * Maximum incoming fragment length in bytes. + * + * Uncomment to set the size of the inward TLS buffer independently of the + * outward buffer. + */ +//#define MBEDTLS_SSL_IN_CONTENT_LEN 16384 + +/** \def MBEDTLS_SSL_OUT_CONTENT_LEN + * + * Maximum outgoing fragment length in bytes. + * + * Uncomment to set the size of the outward TLS buffer independently of the + * inward buffer. + * + * It is possible to save RAM by setting a smaller outward buffer, while keeping + * the default inward 16384 byte buffer to conform to the TLS specification. + * + * The minimum required outward buffer size is determined by the handshake + * protocol's usage. Handshaking will fail if the outward buffer is too small. + * The specific size requirement depends on the configured ciphers and any + * certificate data which is sent during the handshake. + * + * For absolute minimum RAM usage, it's best to enable + * MBEDTLS_SSL_MAX_FRAGMENT_LENGTH and reduce MBEDTLS_SSL_MAX_CONTENT_LEN. This + * reduces both incoming and outgoing buffer sizes. However this is only + * guaranteed if the other end of the connection also supports the TLS + * max_fragment_len extension. Otherwise the connection may fail. + */ +//#define MBEDTLS_SSL_OUT_CONTENT_LEN 16384 + +/** \def MBEDTLS_SSL_DTLS_MAX_BUFFERING + * + * Maximum number of heap-allocated bytes for the purpose of + * DTLS handshake message reassembly and future message buffering. + * + * This should be at least 9/8 * MBEDTLSSL_IN_CONTENT_LEN + * to account for a reassembled handshake message of maximum size, + * together with its reassembly bitmap. + * + * A value of 2 * MBEDTLS_SSL_IN_CONTENT_LEN (32768 by default) + * should be sufficient for all practical situations as it allows + * to reassembly a large handshake message (such as a certificate) + * while buffering multiple smaller handshake messages. + * + */ +//#define MBEDTLS_SSL_DTLS_MAX_BUFFERING 32768 + +//#define MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME 86400 /**< Lifetime of session tickets (if enabled) */ +//#define MBEDTLS_PSK_MAX_LEN 32 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */ +//#define MBEDTLS_SSL_COOKIE_TIMEOUT 60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */ + +/** + * Complete list of ciphersuites to use, in order of preference. + * + * \warning No dependency checking is done on that field! This option can only + * be used to restrict the set of available ciphersuites. It is your + * responsibility to make sure the needed modules are active. + * + * Use this to save a few hundred bytes of ROM (default ordering of all + * available ciphersuites) and a few to a few hundred bytes of RAM. + * + * The value below is only an example, not the default. + */ +//#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + +/* X509 options */ +//#define MBEDTLS_X509_MAX_INTERMEDIATE_CA 8 /**< Maximum number of intermediate CAs in a verification chain. */ +//#define MBEDTLS_X509_MAX_FILE_PATH_LEN 512 /**< Maximum length of a path/filename string in bytes including the null terminator character ('\0'). */ + +/** + * Allow SHA-1 in the default TLS configuration for certificate signing. + * Without this build-time option, SHA-1 support must be activated explicitly + * through mbedtls_ssl_conf_cert_profile. Turning on this option is not + * recommended because of it is possible to generate SHA-1 collisions, however + * this may be safe for legacy infrastructure where additional controls apply. + * + * \warning SHA-1 is considered a weak message digest and its use constitutes + * a security risk. If possible, we recommend avoiding dependencies + * on it, and considering stronger message digests instead. + * + */ +// #define MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_CERTIFICATES + +/** + * Allow SHA-1 in the default TLS configuration for TLS 1.2 handshake + * signature and ciphersuite selection. Without this build-time option, SHA-1 + * support must be activated explicitly through mbedtls_ssl_conf_sig_hashes. + * The use of SHA-1 in TLS <= 1.1 and in HMAC-SHA-1 is always allowed by + * default. At the time of writing, there is no practical attack on the use + * of SHA-1 in handshake signatures, hence this option is turned on by default + * to preserve compatibility with existing peers, but the general + * warning applies nonetheless: + * + * \warning SHA-1 is considered a weak message digest and its use constitutes + * a security risk. If possible, we recommend avoiding dependencies + * on it, and considering stronger message digests instead. + * + */ +#define MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_KEY_EXCHANGE + +/** + * Uncomment the macro to let mbed TLS use your alternate implementation of + * mbedtls_platform_zeroize(). This replaces the default implementation in + * platform_util.c. + * + * mbedtls_platform_zeroize() is a widely used function across the library to + * zero a block of memory. The implementation is expected to be secure in the + * sense that it has been written to prevent the compiler from removing calls + * to mbedtls_platform_zeroize() as part of redundant code elimination + * optimizations. However, it is difficult to guarantee that calls to + * mbedtls_platform_zeroize() will not be optimized by the compiler as older + * versions of the C language standards do not provide a secure implementation + * of memset(). Therefore, MBEDTLS_PLATFORM_ZEROIZE_ALT enables users to + * configure their own implementation of mbedtls_platform_zeroize(), for + * example by using directives specific to their compiler, features from newer + * C standards (e.g using memset_s() in C11) or calling a secure memset() from + * their system (e.g explicit_bzero() in BSD). + */ +//#define MBEDTLS_PLATFORM_ZEROIZE_ALT + +/* \} name SECTION: Customisation configuration options */ + +/* Target and application specific configurations */ +//#define YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE "target_config.h" + +#if defined(TARGET_LIKE_MBED) && defined(YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE) +#include YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE +#endif + +/* + * Allow user to override any previous default. + * + * Use two macro names for that, as: + * - with yotta the prefix YOTTA_CFG_ is forced + * - without yotta is looks weird to have a YOTTA prefix. + */ +#if defined(YOTTA_CFG_MBEDTLS_USER_CONFIG_FILE) +#include YOTTA_CFG_MBEDTLS_USER_CONFIG_FILE +#elif defined(MBEDTLS_USER_CONFIG_FILE) +#include MBEDTLS_USER_CONFIG_FILE +#endif + +#include "check_config.h" + +#endif /* MBEDTLS_CONFIG_H */ diff --git a/common/mbedtls/ctr_drbg.c b/common/mbedtls/ctr_drbg.c new file mode 100644 index 00000000..ebbba1a7 --- /dev/null +++ b/common/mbedtls/ctr_drbg.c @@ -0,0 +1,652 @@ +/* + * CTR_DRBG implementation based on AES-256 (NIST SP 800-90) + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The NIST SP 800-90 DRBGs are described in the following publication. + * + * http://csrc.nist.gov/publications/nistpubs/800-90/SP800-90revised_March2007.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_CTR_DRBG_C) + +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_FS_IO) +#include +#endif + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +/* + * CTR_DRBG context initialization + */ +void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_ctr_drbg_context ) ); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init( &ctx->mutex ); +#endif +} + +/* + * Non-public function wrapped by mbedtls_ctr_drbg_seed(). Necessary to allow + * NIST tests to succeed (which require known length fixed entropy) + */ +int mbedtls_ctr_drbg_seed_entropy_len( + mbedtls_ctr_drbg_context *ctx, + int (*f_entropy)(void *, unsigned char *, size_t), + void *p_entropy, + const unsigned char *custom, + size_t len, + size_t entropy_len ) +{ + int ret; + unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE]; + + memset( key, 0, MBEDTLS_CTR_DRBG_KEYSIZE ); + + mbedtls_aes_init( &ctx->aes_ctx ); + + ctx->f_entropy = f_entropy; + ctx->p_entropy = p_entropy; + + ctx->entropy_len = entropy_len; + ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL; + + /* + * Initialize with an empty key + */ + if( ( ret = mbedtls_aes_setkey_enc( &ctx->aes_ctx, key, MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 ) + { + return( ret ); + } + + if( ( ret = mbedtls_ctr_drbg_reseed( ctx, custom, len ) ) != 0 ) + { + return( ret ); + } + return( 0 ); +} + +int mbedtls_ctr_drbg_seed( mbedtls_ctr_drbg_context *ctx, + int (*f_entropy)(void *, unsigned char *, size_t), + void *p_entropy, + const unsigned char *custom, + size_t len ) +{ + return( mbedtls_ctr_drbg_seed_entropy_len( ctx, f_entropy, p_entropy, custom, len, + MBEDTLS_CTR_DRBG_ENTROPY_LEN ) ); +} + +void mbedtls_ctr_drbg_free( mbedtls_ctr_drbg_context *ctx ) +{ + if( ctx == NULL ) + return; + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_free( &ctx->mutex ); +#endif + mbedtls_aes_free( &ctx->aes_ctx ); + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ctr_drbg_context ) ); +} + +void mbedtls_ctr_drbg_set_prediction_resistance( mbedtls_ctr_drbg_context *ctx, int resistance ) +{ + ctx->prediction_resistance = resistance; +} + +void mbedtls_ctr_drbg_set_entropy_len( mbedtls_ctr_drbg_context *ctx, size_t len ) +{ + ctx->entropy_len = len; +} + +void mbedtls_ctr_drbg_set_reseed_interval( mbedtls_ctr_drbg_context *ctx, int interval ) +{ + ctx->reseed_interval = interval; +} + +static int block_cipher_df( unsigned char *output, + const unsigned char *data, size_t data_len ) +{ + unsigned char buf[MBEDTLS_CTR_DRBG_MAX_SEED_INPUT + MBEDTLS_CTR_DRBG_BLOCKSIZE + 16]; + unsigned char tmp[MBEDTLS_CTR_DRBG_SEEDLEN]; + unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE]; + unsigned char chain[MBEDTLS_CTR_DRBG_BLOCKSIZE]; + unsigned char *p, *iv; + mbedtls_aes_context aes_ctx; + int ret = 0; + + int i, j; + size_t buf_len, use_len; + + if( data_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT ) + return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG ); + + memset( buf, 0, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT + MBEDTLS_CTR_DRBG_BLOCKSIZE + 16 ); + mbedtls_aes_init( &aes_ctx ); + + /* + * Construct IV (16 bytes) and S in buffer + * IV = Counter (in 32-bits) padded to 16 with zeroes + * S = Length input string (in 32-bits) || Length of output (in 32-bits) || + * data || 0x80 + * (Total is padded to a multiple of 16-bytes with zeroes) + */ + p = buf + MBEDTLS_CTR_DRBG_BLOCKSIZE; + *p++ = ( data_len >> 24 ) & 0xff; + *p++ = ( data_len >> 16 ) & 0xff; + *p++ = ( data_len >> 8 ) & 0xff; + *p++ = ( data_len ) & 0xff; + p += 3; + *p++ = MBEDTLS_CTR_DRBG_SEEDLEN; + memcpy( p, data, data_len ); + p[data_len] = 0x80; + + buf_len = MBEDTLS_CTR_DRBG_BLOCKSIZE + 8 + data_len + 1; + + for( i = 0; i < MBEDTLS_CTR_DRBG_KEYSIZE; i++ ) + key[i] = i; + + if( ( ret = mbedtls_aes_setkey_enc( &aes_ctx, key, MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 ) + { + goto exit; + } + + /* + * Reduce data to MBEDTLS_CTR_DRBG_SEEDLEN bytes of data + */ + for( j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE ) + { + p = buf; + memset( chain, 0, MBEDTLS_CTR_DRBG_BLOCKSIZE ); + use_len = buf_len; + + while( use_len > 0 ) + { + for( i = 0; i < MBEDTLS_CTR_DRBG_BLOCKSIZE; i++ ) + chain[i] ^= p[i]; + p += MBEDTLS_CTR_DRBG_BLOCKSIZE; + use_len -= ( use_len >= MBEDTLS_CTR_DRBG_BLOCKSIZE ) ? + MBEDTLS_CTR_DRBG_BLOCKSIZE : use_len; + + if( ( ret = mbedtls_aes_crypt_ecb( &aes_ctx, MBEDTLS_AES_ENCRYPT, chain, chain ) ) != 0 ) + { + goto exit; + } + } + + memcpy( tmp + j, chain, MBEDTLS_CTR_DRBG_BLOCKSIZE ); + + /* + * Update IV + */ + buf[3]++; + } + + /* + * Do final encryption with reduced data + */ + if( ( ret = mbedtls_aes_setkey_enc( &aes_ctx, tmp, MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 ) + { + goto exit; + } + iv = tmp + MBEDTLS_CTR_DRBG_KEYSIZE; + p = output; + + for( j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE ) + { + if( ( ret = mbedtls_aes_crypt_ecb( &aes_ctx, MBEDTLS_AES_ENCRYPT, iv, iv ) ) != 0 ) + { + goto exit; + } + memcpy( p, iv, MBEDTLS_CTR_DRBG_BLOCKSIZE ); + p += MBEDTLS_CTR_DRBG_BLOCKSIZE; + } +exit: + mbedtls_aes_free( &aes_ctx ); + /* + * tidy up the stack + */ + mbedtls_platform_zeroize( buf, sizeof( buf ) ); + mbedtls_platform_zeroize( tmp, sizeof( tmp ) ); + mbedtls_platform_zeroize( key, sizeof( key ) ); + mbedtls_platform_zeroize( chain, sizeof( chain ) ); + if( 0 != ret ) + { + /* + * wipe partial seed from memory + */ + mbedtls_platform_zeroize( output, MBEDTLS_CTR_DRBG_SEEDLEN ); + } + + return( ret ); +} + +static int ctr_drbg_update_internal( mbedtls_ctr_drbg_context *ctx, + const unsigned char data[MBEDTLS_CTR_DRBG_SEEDLEN] ) +{ + unsigned char tmp[MBEDTLS_CTR_DRBG_SEEDLEN]; + unsigned char *p = tmp; + int i, j; + int ret = 0; + + memset( tmp, 0, MBEDTLS_CTR_DRBG_SEEDLEN ); + + for( j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE ) + { + /* + * Increase counter + */ + for( i = MBEDTLS_CTR_DRBG_BLOCKSIZE; i > 0; i-- ) + if( ++ctx->counter[i - 1] != 0 ) + break; + + /* + * Crypt counter block + */ + if( ( ret = mbedtls_aes_crypt_ecb( &ctx->aes_ctx, MBEDTLS_AES_ENCRYPT, ctx->counter, p ) ) != 0 ) + { + return( ret ); + } + + p += MBEDTLS_CTR_DRBG_BLOCKSIZE; + } + + for( i = 0; i < MBEDTLS_CTR_DRBG_SEEDLEN; i++ ) + tmp[i] ^= data[i]; + + /* + * Update key and counter + */ + if( ( ret = mbedtls_aes_setkey_enc( &ctx->aes_ctx, tmp, MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 ) + { + return( ret ); + } + memcpy( ctx->counter, tmp + MBEDTLS_CTR_DRBG_KEYSIZE, MBEDTLS_CTR_DRBG_BLOCKSIZE ); + + return( 0 ); +} + +void mbedtls_ctr_drbg_update( mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, size_t add_len ) +{ + unsigned char add_input[MBEDTLS_CTR_DRBG_SEEDLEN]; + + if( add_len > 0 ) + { + /* MAX_INPUT would be more logical here, but we have to match + * block_cipher_df()'s limits since we can't propagate errors */ + if( add_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT ) + add_len = MBEDTLS_CTR_DRBG_MAX_SEED_INPUT; + + block_cipher_df( add_input, additional, add_len ); + ctr_drbg_update_internal( ctx, add_input ); + } +} + +int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, size_t len ) +{ + unsigned char seed[MBEDTLS_CTR_DRBG_MAX_SEED_INPUT]; + size_t seedlen = 0; + int ret; + + if( ctx->entropy_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT || + len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - ctx->entropy_len ) + return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG ); + + memset( seed, 0, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT ); + + /* + * Gather entropy_len bytes of entropy to seed state + */ + if( 0 != ctx->f_entropy( ctx->p_entropy, seed, + ctx->entropy_len ) ) + { + return( MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED ); + } + + seedlen += ctx->entropy_len; + + /* + * Add additional data + */ + if( additional && len ) + { + memcpy( seed + seedlen, additional, len ); + seedlen += len; + } + + /* + * Reduce to 384 bits + */ + if( ( ret = block_cipher_df( seed, seed, seedlen ) ) != 0 ) + { + return( ret ); + } + + /* + * Update state + */ + if( ( ret = ctr_drbg_update_internal( ctx, seed ) ) != 0 ) + { + return( ret ); + } + ctx->reseed_counter = 1; + + return( 0 ); +} + +int mbedtls_ctr_drbg_random_with_add( void *p_rng, + unsigned char *output, size_t output_len, + const unsigned char *additional, size_t add_len ) +{ + int ret = 0; + mbedtls_ctr_drbg_context *ctx = (mbedtls_ctr_drbg_context *) p_rng; + unsigned char add_input[MBEDTLS_CTR_DRBG_SEEDLEN]; + unsigned char *p = output; + unsigned char tmp[MBEDTLS_CTR_DRBG_BLOCKSIZE]; + int i; + size_t use_len; + + if( output_len > MBEDTLS_CTR_DRBG_MAX_REQUEST ) + return( MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG ); + + if( add_len > MBEDTLS_CTR_DRBG_MAX_INPUT ) + return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG ); + + memset( add_input, 0, MBEDTLS_CTR_DRBG_SEEDLEN ); + + if( ctx->reseed_counter > ctx->reseed_interval || + ctx->prediction_resistance ) + { + if( ( ret = mbedtls_ctr_drbg_reseed( ctx, additional, add_len ) ) != 0 ) + { + return( ret ); + } + add_len = 0; + } + + if( add_len > 0 ) + { + if( ( ret = block_cipher_df( add_input, additional, add_len ) ) != 0 ) + { + return( ret ); + } + if( ( ret = ctr_drbg_update_internal( ctx, add_input ) ) != 0 ) + { + return( ret ); + } + } + + while( output_len > 0 ) + { + /* + * Increase counter + */ + for( i = MBEDTLS_CTR_DRBG_BLOCKSIZE; i > 0; i-- ) + if( ++ctx->counter[i - 1] != 0 ) + break; + + /* + * Crypt counter block + */ + if( ( ret = mbedtls_aes_crypt_ecb( &ctx->aes_ctx, MBEDTLS_AES_ENCRYPT, ctx->counter, tmp ) ) != 0 ) + { + return( ret ); + } + + use_len = ( output_len > MBEDTLS_CTR_DRBG_BLOCKSIZE ) ? MBEDTLS_CTR_DRBG_BLOCKSIZE : + output_len; + /* + * Copy random block to destination + */ + memcpy( p, tmp, use_len ); + p += use_len; + output_len -= use_len; + } + + if( ( ret = ctr_drbg_update_internal( ctx, add_input ) ) != 0 ) + { + return( ret ); + } + + ctx->reseed_counter++; + + return( 0 ); +} + +int mbedtls_ctr_drbg_random( void *p_rng, unsigned char *output, size_t output_len ) +{ + int ret; + mbedtls_ctr_drbg_context *ctx = (mbedtls_ctr_drbg_context *) p_rng; + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + ret = mbedtls_ctr_drbg_random_with_add( ctx, output, output_len, NULL, 0 ); + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} + +#if defined(MBEDTLS_FS_IO) +int mbedtls_ctr_drbg_write_seed_file( mbedtls_ctr_drbg_context *ctx, const char *path ) +{ + int ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR; + FILE *f; + unsigned char buf[ MBEDTLS_CTR_DRBG_MAX_INPUT ]; + + if( ( f = fopen( path, "wb" ) ) == NULL ) + return( MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR ); + + if( ( ret = mbedtls_ctr_drbg_random( ctx, buf, MBEDTLS_CTR_DRBG_MAX_INPUT ) ) != 0 ) + goto exit; + + if( fwrite( buf, 1, MBEDTLS_CTR_DRBG_MAX_INPUT, f ) != MBEDTLS_CTR_DRBG_MAX_INPUT ) + ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR; + else + ret = 0; + +exit: + mbedtls_platform_zeroize( buf, sizeof( buf ) ); + + fclose( f ); + return( ret ); +} + +int mbedtls_ctr_drbg_update_seed_file( mbedtls_ctr_drbg_context *ctx, const char *path ) +{ + int ret = 0; + FILE *f; + size_t n; + unsigned char buf[ MBEDTLS_CTR_DRBG_MAX_INPUT ]; + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR ); + + fseek( f, 0, SEEK_END ); + n = (size_t) ftell( f ); + fseek( f, 0, SEEK_SET ); + + if( n > MBEDTLS_CTR_DRBG_MAX_INPUT ) + { + fclose( f ); + return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG ); + } + + if( fread( buf, 1, n, f ) != n ) + ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR; + else + mbedtls_ctr_drbg_update( ctx, buf, n ); + + fclose( f ); + + mbedtls_platform_zeroize( buf, sizeof( buf ) ); + + if( ret != 0 ) + return( ret ); + + return( mbedtls_ctr_drbg_write_seed_file( ctx, path ) ); +} +#endif /* MBEDTLS_FS_IO */ + +#if defined(MBEDTLS_SELF_TEST) + +static const unsigned char entropy_source_pr[96] = + { 0xc1, 0x80, 0x81, 0xa6, 0x5d, 0x44, 0x02, 0x16, + 0x19, 0xb3, 0xf1, 0x80, 0xb1, 0xc9, 0x20, 0x02, + 0x6a, 0x54, 0x6f, 0x0c, 0x70, 0x81, 0x49, 0x8b, + 0x6e, 0xa6, 0x62, 0x52, 0x6d, 0x51, 0xb1, 0xcb, + 0x58, 0x3b, 0xfa, 0xd5, 0x37, 0x5f, 0xfb, 0xc9, + 0xff, 0x46, 0xd2, 0x19, 0xc7, 0x22, 0x3e, 0x95, + 0x45, 0x9d, 0x82, 0xe1, 0xe7, 0x22, 0x9f, 0x63, + 0x31, 0x69, 0xd2, 0x6b, 0x57, 0x47, 0x4f, 0xa3, + 0x37, 0xc9, 0x98, 0x1c, 0x0b, 0xfb, 0x91, 0x31, + 0x4d, 0x55, 0xb9, 0xe9, 0x1c, 0x5a, 0x5e, 0xe4, + 0x93, 0x92, 0xcf, 0xc5, 0x23, 0x12, 0xd5, 0x56, + 0x2c, 0x4a, 0x6e, 0xff, 0xdc, 0x10, 0xd0, 0x68 }; + +static const unsigned char entropy_source_nopr[64] = + { 0x5a, 0x19, 0x4d, 0x5e, 0x2b, 0x31, 0x58, 0x14, + 0x54, 0xde, 0xf6, 0x75, 0xfb, 0x79, 0x58, 0xfe, + 0xc7, 0xdb, 0x87, 0x3e, 0x56, 0x89, 0xfc, 0x9d, + 0x03, 0x21, 0x7c, 0x68, 0xd8, 0x03, 0x38, 0x20, + 0xf9, 0xe6, 0x5e, 0x04, 0xd8, 0x56, 0xf3, 0xa9, + 0xc4, 0x4a, 0x4c, 0xbd, 0xc1, 0xd0, 0x08, 0x46, + 0xf5, 0x98, 0x3d, 0x77, 0x1c, 0x1b, 0x13, 0x7e, + 0x4e, 0x0f, 0x9d, 0x8e, 0xf4, 0x09, 0xf9, 0x2e }; + +static const unsigned char nonce_pers_pr[16] = + { 0xd2, 0x54, 0xfc, 0xff, 0x02, 0x1e, 0x69, 0xd2, + 0x29, 0xc9, 0xcf, 0xad, 0x85, 0xfa, 0x48, 0x6c }; + +static const unsigned char nonce_pers_nopr[16] = + { 0x1b, 0x54, 0xb8, 0xff, 0x06, 0x42, 0xbf, 0xf5, + 0x21, 0xf1, 0x5c, 0x1c, 0x0b, 0x66, 0x5f, 0x3f }; + +static const unsigned char result_pr[16] = + { 0x34, 0x01, 0x16, 0x56, 0xb4, 0x29, 0x00, 0x8f, + 0x35, 0x63, 0xec, 0xb5, 0xf2, 0x59, 0x07, 0x23 }; + +static const unsigned char result_nopr[16] = + { 0xa0, 0x54, 0x30, 0x3d, 0x8a, 0x7e, 0xa9, 0x88, + 0x9d, 0x90, 0x3e, 0x07, 0x7c, 0x6f, 0x21, 0x8f }; + +static size_t test_offset; +static int ctr_drbg_self_test_entropy( void *data, unsigned char *buf, + size_t len ) +{ + const unsigned char *p = data; + memcpy( buf, p + test_offset, len ); + test_offset += len; + return( 0 ); +} + +#define CHK( c ) if( (c) != 0 ) \ + { \ + if( verbose != 0 ) \ + mbedtls_printf( "failed\n" ); \ + return( 1 ); \ + } + +/* + * Checkup routine + */ +int mbedtls_ctr_drbg_self_test( int verbose ) +{ + mbedtls_ctr_drbg_context ctx; + unsigned char buf[16]; + + mbedtls_ctr_drbg_init( &ctx ); + + /* + * Based on a NIST CTR_DRBG test vector (PR = True) + */ + if( verbose != 0 ) + mbedtls_printf( " CTR_DRBG (PR = TRUE) : " ); + + test_offset = 0; + CHK( mbedtls_ctr_drbg_seed_entropy_len( &ctx, ctr_drbg_self_test_entropy, + (void *) entropy_source_pr, nonce_pers_pr, 16, 32 ) ); + mbedtls_ctr_drbg_set_prediction_resistance( &ctx, MBEDTLS_CTR_DRBG_PR_ON ); + CHK( mbedtls_ctr_drbg_random( &ctx, buf, MBEDTLS_CTR_DRBG_BLOCKSIZE ) ); + CHK( mbedtls_ctr_drbg_random( &ctx, buf, MBEDTLS_CTR_DRBG_BLOCKSIZE ) ); + CHK( memcmp( buf, result_pr, MBEDTLS_CTR_DRBG_BLOCKSIZE ) ); + + mbedtls_ctr_drbg_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + /* + * Based on a NIST CTR_DRBG test vector (PR = FALSE) + */ + if( verbose != 0 ) + mbedtls_printf( " CTR_DRBG (PR = FALSE): " ); + + mbedtls_ctr_drbg_init( &ctx ); + + test_offset = 0; + CHK( mbedtls_ctr_drbg_seed_entropy_len( &ctx, ctr_drbg_self_test_entropy, + (void *) entropy_source_nopr, nonce_pers_nopr, 16, 32 ) ); + CHK( mbedtls_ctr_drbg_random( &ctx, buf, 16 ) ); + CHK( mbedtls_ctr_drbg_reseed( &ctx, NULL, 0 ) ); + CHK( mbedtls_ctr_drbg_random( &ctx, buf, 16 ) ); + CHK( memcmp( buf, result_nopr, 16 ) ); + + mbedtls_ctr_drbg_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_CTR_DRBG_C */ diff --git a/common/mbedtls/ctr_drbg.h b/common/mbedtls/ctr_drbg.h new file mode 100644 index 00000000..5d62f9be --- /dev/null +++ b/common/mbedtls/ctr_drbg.h @@ -0,0 +1,332 @@ +/** + * \file ctr_drbg.h + * + * \brief This file contains CTR_DRBG definitions and functions. + * + * CTR_DRBG is a standardized way of building a PRNG from a block-cipher + * in counter mode operation, as defined in NIST SP 800-90A: + * Recommendation for Random Number Generation Using Deterministic Random + * Bit Generators. + * + * The Mbed TLS implementation of CTR_DRBG uses AES-256 as the underlying + * block cipher. + */ +/* + * Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_CTR_DRBG_H +#define MBEDTLS_CTR_DRBG_H + +#include "aes.h" + +#if defined(MBEDTLS_THREADING_C) +#include "threading.h" +#endif + +#define MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED -0x0034 /**< The entropy source failed. */ +#define MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG -0x0036 /**< The requested random buffer length is too big. */ +#define MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG -0x0038 /**< The input (entropy + additional data) is too large. */ +#define MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR -0x003A /**< Read or write error in file. */ + +#define MBEDTLS_CTR_DRBG_BLOCKSIZE 16 /**< The block size used by the cipher. */ +#define MBEDTLS_CTR_DRBG_KEYSIZE 32 /**< The key size used by the cipher. */ +#define MBEDTLS_CTR_DRBG_KEYBITS ( MBEDTLS_CTR_DRBG_KEYSIZE * 8 ) /**< The key size for the DRBG operation, in bits. */ +#define MBEDTLS_CTR_DRBG_SEEDLEN ( MBEDTLS_CTR_DRBG_KEYSIZE + MBEDTLS_CTR_DRBG_BLOCKSIZE ) /**< The seed length, calculated as (counter + AES key). */ + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h or define them using the compiler command + * line. + * \{ + */ + +#if !defined(MBEDTLS_CTR_DRBG_ENTROPY_LEN) +#if defined(MBEDTLS_SHA512_C) && !defined(MBEDTLS_ENTROPY_FORCE_SHA256) +#define MBEDTLS_CTR_DRBG_ENTROPY_LEN 48 +/**< The amount of entropy used per seed by default: + *
  • 48 with SHA-512.
  • + *
  • 32 with SHA-256.
+ */ +#else +#define MBEDTLS_CTR_DRBG_ENTROPY_LEN 32 +/**< Amount of entropy used per seed by default: + *
  • 48 with SHA-512.
  • + *
  • 32 with SHA-256.
+ */ +#endif +#endif + +#if !defined(MBEDTLS_CTR_DRBG_RESEED_INTERVAL) +#define MBEDTLS_CTR_DRBG_RESEED_INTERVAL 10000 +/**< The interval before reseed is performed by default. */ +#endif + +#if !defined(MBEDTLS_CTR_DRBG_MAX_INPUT) +#define MBEDTLS_CTR_DRBG_MAX_INPUT 256 +/**< The maximum number of additional input Bytes. */ +#endif + +#if !defined(MBEDTLS_CTR_DRBG_MAX_REQUEST) +#define MBEDTLS_CTR_DRBG_MAX_REQUEST 1024 +/**< The maximum number of requested Bytes per call. */ +#endif + +#if !defined(MBEDTLS_CTR_DRBG_MAX_SEED_INPUT) +#define MBEDTLS_CTR_DRBG_MAX_SEED_INPUT 384 +/**< The maximum size of seed or reseed buffer. */ +#endif + +/* \} name SECTION: Module settings */ + +#define MBEDTLS_CTR_DRBG_PR_OFF 0 +/**< Prediction resistance is disabled. */ +#define MBEDTLS_CTR_DRBG_PR_ON 1 +/**< Prediction resistance is enabled. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief The CTR_DRBG context structure. + */ +typedef struct mbedtls_ctr_drbg_context +{ + unsigned char counter[16]; /*!< The counter (V). */ + int reseed_counter; /*!< The reseed counter. */ + int prediction_resistance; /*!< This determines whether prediction + resistance is enabled, that is + whether to systematically reseed before + each random generation. */ + size_t entropy_len; /*!< The amount of entropy grabbed on each + seed or reseed operation. */ + int reseed_interval; /*!< The reseed interval. */ + + mbedtls_aes_context aes_ctx; /*!< The AES context. */ + + /* + * Callbacks (Entropy) + */ + int (*f_entropy)(void *, unsigned char *, size_t); + /*!< The entropy callback function. */ + + void *p_entropy; /*!< The context for the entropy function. */ + +#if defined(MBEDTLS_THREADING_C) + mbedtls_threading_mutex_t mutex; +#endif +} +mbedtls_ctr_drbg_context; + +/** + * \brief This function initializes the CTR_DRBG context, + * and prepares it for mbedtls_ctr_drbg_seed() + * or mbedtls_ctr_drbg_free(). + * + * \param ctx The CTR_DRBG context to initialize. + */ +void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx ); + +/** + * \brief This function seeds and sets up the CTR_DRBG + * entropy source for future reseeds. + * + * \note Personalization data can be provided in addition to the more generic + * entropy source, to make this instantiation as unique as possible. + * + * \param ctx The CTR_DRBG context to seed. + * \param f_entropy The entropy callback, taking as arguments the + * \p p_entropy context, the buffer to fill, and the + length of the buffer. + * \param p_entropy The entropy context. + * \param custom Personalization data, that is device-specific + identifiers. Can be NULL. + * \param len The length of the personalization data. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED on failure. + */ +int mbedtls_ctr_drbg_seed( mbedtls_ctr_drbg_context *ctx, + int (*f_entropy)(void *, unsigned char *, size_t), + void *p_entropy, + const unsigned char *custom, + size_t len ); + +/** + * \brief This function clears CTR_CRBG context data. + * + * \param ctx The CTR_DRBG context to clear. + */ +void mbedtls_ctr_drbg_free( mbedtls_ctr_drbg_context *ctx ); + +/** + * \brief This function turns prediction resistance on or off. + * The default value is off. + * + * \note If enabled, entropy is gathered at the beginning of + * every call to mbedtls_ctr_drbg_random_with_add(). + * Only use this if your entropy source has sufficient + * throughput. + * + * \param ctx The CTR_DRBG context. + * \param resistance #MBEDTLS_CTR_DRBG_PR_ON or #MBEDTLS_CTR_DRBG_PR_OFF. + */ +void mbedtls_ctr_drbg_set_prediction_resistance( mbedtls_ctr_drbg_context *ctx, + int resistance ); + +/** + * \brief This function sets the amount of entropy grabbed on each + * seed or reseed. The default value is + * #MBEDTLS_CTR_DRBG_ENTROPY_LEN. + * + * \param ctx The CTR_DRBG context. + * \param len The amount of entropy to grab. + */ +void mbedtls_ctr_drbg_set_entropy_len( mbedtls_ctr_drbg_context *ctx, + size_t len ); + +/** + * \brief This function sets the reseed interval. + * The default value is #MBEDTLS_CTR_DRBG_RESEED_INTERVAL. + * + * \param ctx The CTR_DRBG context. + * \param interval The reseed interval. + */ +void mbedtls_ctr_drbg_set_reseed_interval( mbedtls_ctr_drbg_context *ctx, + int interval ); + +/** + * \brief This function reseeds the CTR_DRBG context, that is + * extracts data from the entropy source. + * + * \param ctx The CTR_DRBG context. + * \param additional Additional data to add to the state. Can be NULL. + * \param len The length of the additional data. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED on failure. + */ +int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, size_t len ); + +/** + * \brief This function updates the state of the CTR_DRBG context. + * + * \note If \p add_len is greater than + * #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT, only the first + * #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT Bytes are used. + * The remaining Bytes are silently discarded. + * + * \param ctx The CTR_DRBG context. + * \param additional The data to update the state with. + * \param add_len Length of \p additional data. + * + */ +void mbedtls_ctr_drbg_update( mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, size_t add_len ); + +/** + * \brief This function updates a CTR_DRBG instance with additional + * data and uses it to generate random data. + * + * \note The function automatically reseeds if the reseed counter is exceeded. + * + * \param p_rng The CTR_DRBG context. This must be a pointer to a + * #mbedtls_ctr_drbg_context structure. + * \param output The buffer to fill. + * \param output_len The length of the buffer. + * \param additional Additional data to update. Can be NULL. + * \param add_len The length of the additional data. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED or + * #MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG on failure. + */ +int mbedtls_ctr_drbg_random_with_add( void *p_rng, + unsigned char *output, size_t output_len, + const unsigned char *additional, size_t add_len ); + +/** + * \brief This function uses CTR_DRBG to generate random data. + * + * \note The function automatically reseeds if the reseed counter is exceeded. + * + * \param p_rng The CTR_DRBG context. This must be a pointer to a + * #mbedtls_ctr_drbg_context structure. + * \param output The buffer to fill. + * \param output_len The length of the buffer. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED or + * #MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG on failure. + */ +int mbedtls_ctr_drbg_random( void *p_rng, + unsigned char *output, size_t output_len ); + +#if defined(MBEDTLS_FS_IO) +/** + * \brief This function writes a seed file. + * + * \param ctx The CTR_DRBG context. + * \param path The name of the file. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR on file error. + * \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED on + * failure. + */ +int mbedtls_ctr_drbg_write_seed_file( mbedtls_ctr_drbg_context *ctx, const char *path ); + +/** + * \brief This function reads and updates a seed file. The seed + * is added to this instance. + * + * \param ctx The CTR_DRBG context. + * \param path The name of the file. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR on file error. + * \return #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED or + * #MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG on failure. + */ +int mbedtls_ctr_drbg_update_seed_file( mbedtls_ctr_drbg_context *ctx, const char *path ); +#endif /* MBEDTLS_FS_IO */ + +/** + * \brief The CTR_DRBG checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_ctr_drbg_self_test( int verbose ); + +/* Internal functions (do not call directly) */ +int mbedtls_ctr_drbg_seed_entropy_len( mbedtls_ctr_drbg_context *, + int (*)(void *, unsigned char *, size_t), void *, + const unsigned char *, size_t, size_t ); + +#ifdef __cplusplus +} +#endif + +#endif /* ctr_drbg.h */ diff --git a/common/mbedtls/des.c b/common/mbedtls/des.c new file mode 100644 index 00000000..5c4e2cc9 --- /dev/null +++ b/common/mbedtls/des.c @@ -0,0 +1,1059 @@ +/* + * FIPS-46-3 compliant Triple-DES implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * DES, on which TDES is based, was originally designed by Horst Feistel + * at IBM in 1974, and was adopted as a standard by NIST (formerly NBS). + * + * http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_DES_C) + +#include "mbedtls/des.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_DES_ALT) + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +/* + * Expanded DES S-boxes + */ +static const uint32_t SB1[64] = +{ + 0x01010400, 0x00000000, 0x00010000, 0x01010404, + 0x01010004, 0x00010404, 0x00000004, 0x00010000, + 0x00000400, 0x01010400, 0x01010404, 0x00000400, + 0x01000404, 0x01010004, 0x01000000, 0x00000004, + 0x00000404, 0x01000400, 0x01000400, 0x00010400, + 0x00010400, 0x01010000, 0x01010000, 0x01000404, + 0x00010004, 0x01000004, 0x01000004, 0x00010004, + 0x00000000, 0x00000404, 0x00010404, 0x01000000, + 0x00010000, 0x01010404, 0x00000004, 0x01010000, + 0x01010400, 0x01000000, 0x01000000, 0x00000400, + 0x01010004, 0x00010000, 0x00010400, 0x01000004, + 0x00000400, 0x00000004, 0x01000404, 0x00010404, + 0x01010404, 0x00010004, 0x01010000, 0x01000404, + 0x01000004, 0x00000404, 0x00010404, 0x01010400, + 0x00000404, 0x01000400, 0x01000400, 0x00000000, + 0x00010004, 0x00010400, 0x00000000, 0x01010004 +}; + +static const uint32_t SB2[64] = +{ + 0x80108020, 0x80008000, 0x00008000, 0x00108020, + 0x00100000, 0x00000020, 0x80100020, 0x80008020, + 0x80000020, 0x80108020, 0x80108000, 0x80000000, + 0x80008000, 0x00100000, 0x00000020, 0x80100020, + 0x00108000, 0x00100020, 0x80008020, 0x00000000, + 0x80000000, 0x00008000, 0x00108020, 0x80100000, + 0x00100020, 0x80000020, 0x00000000, 0x00108000, + 0x00008020, 0x80108000, 0x80100000, 0x00008020, + 0x00000000, 0x00108020, 0x80100020, 0x00100000, + 0x80008020, 0x80100000, 0x80108000, 0x00008000, + 0x80100000, 0x80008000, 0x00000020, 0x80108020, + 0x00108020, 0x00000020, 0x00008000, 0x80000000, + 0x00008020, 0x80108000, 0x00100000, 0x80000020, + 0x00100020, 0x80008020, 0x80000020, 0x00100020, + 0x00108000, 0x00000000, 0x80008000, 0x00008020, + 0x80000000, 0x80100020, 0x80108020, 0x00108000 +}; + +static const uint32_t SB3[64] = +{ + 0x00000208, 0x08020200, 0x00000000, 0x08020008, + 0x08000200, 0x00000000, 0x00020208, 0x08000200, + 0x00020008, 0x08000008, 0x08000008, 0x00020000, + 0x08020208, 0x00020008, 0x08020000, 0x00000208, + 0x08000000, 0x00000008, 0x08020200, 0x00000200, + 0x00020200, 0x08020000, 0x08020008, 0x00020208, + 0x08000208, 0x00020200, 0x00020000, 0x08000208, + 0x00000008, 0x08020208, 0x00000200, 0x08000000, + 0x08020200, 0x08000000, 0x00020008, 0x00000208, + 0x00020000, 0x08020200, 0x08000200, 0x00000000, + 0x00000200, 0x00020008, 0x08020208, 0x08000200, + 0x08000008, 0x00000200, 0x00000000, 0x08020008, + 0x08000208, 0x00020000, 0x08000000, 0x08020208, + 0x00000008, 0x00020208, 0x00020200, 0x08000008, + 0x08020000, 0x08000208, 0x00000208, 0x08020000, + 0x00020208, 0x00000008, 0x08020008, 0x00020200 +}; + +static const uint32_t SB4[64] = +{ + 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802080, 0x00800081, 0x00800001, 0x00002001, + 0x00000000, 0x00802000, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00800080, 0x00800001, + 0x00000001, 0x00002000, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002001, 0x00002080, + 0x00800081, 0x00000001, 0x00002080, 0x00800080, + 0x00002000, 0x00802080, 0x00802081, 0x00000081, + 0x00800080, 0x00800001, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00000000, 0x00802000, + 0x00002080, 0x00800080, 0x00800081, 0x00000001, + 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802081, 0x00000081, 0x00000001, 0x00002000, + 0x00800001, 0x00002001, 0x00802080, 0x00800081, + 0x00002001, 0x00002080, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002000, 0x00802080 +}; + +static const uint32_t SB5[64] = +{ + 0x00000100, 0x02080100, 0x02080000, 0x42000100, + 0x00080000, 0x00000100, 0x40000000, 0x02080000, + 0x40080100, 0x00080000, 0x02000100, 0x40080100, + 0x42000100, 0x42080000, 0x00080100, 0x40000000, + 0x02000000, 0x40080000, 0x40080000, 0x00000000, + 0x40000100, 0x42080100, 0x42080100, 0x02000100, + 0x42080000, 0x40000100, 0x00000000, 0x42000000, + 0x02080100, 0x02000000, 0x42000000, 0x00080100, + 0x00080000, 0x42000100, 0x00000100, 0x02000000, + 0x40000000, 0x02080000, 0x42000100, 0x40080100, + 0x02000100, 0x40000000, 0x42080000, 0x02080100, + 0x40080100, 0x00000100, 0x02000000, 0x42080000, + 0x42080100, 0x00080100, 0x42000000, 0x42080100, + 0x02080000, 0x00000000, 0x40080000, 0x42000000, + 0x00080100, 0x02000100, 0x40000100, 0x00080000, + 0x00000000, 0x40080000, 0x02080100, 0x40000100 +}; + +static const uint32_t SB6[64] = +{ + 0x20000010, 0x20400000, 0x00004000, 0x20404010, + 0x20400000, 0x00000010, 0x20404010, 0x00400000, + 0x20004000, 0x00404010, 0x00400000, 0x20000010, + 0x00400010, 0x20004000, 0x20000000, 0x00004010, + 0x00000000, 0x00400010, 0x20004010, 0x00004000, + 0x00404000, 0x20004010, 0x00000010, 0x20400010, + 0x20400010, 0x00000000, 0x00404010, 0x20404000, + 0x00004010, 0x00404000, 0x20404000, 0x20000000, + 0x20004000, 0x00000010, 0x20400010, 0x00404000, + 0x20404010, 0x00400000, 0x00004010, 0x20000010, + 0x00400000, 0x20004000, 0x20000000, 0x00004010, + 0x20000010, 0x20404010, 0x00404000, 0x20400000, + 0x00404010, 0x20404000, 0x00000000, 0x20400010, + 0x00000010, 0x00004000, 0x20400000, 0x00404010, + 0x00004000, 0x00400010, 0x20004010, 0x00000000, + 0x20404000, 0x20000000, 0x00400010, 0x20004010 +}; + +static const uint32_t SB7[64] = +{ + 0x00200000, 0x04200002, 0x04000802, 0x00000000, + 0x00000800, 0x04000802, 0x00200802, 0x04200800, + 0x04200802, 0x00200000, 0x00000000, 0x04000002, + 0x00000002, 0x04000000, 0x04200002, 0x00000802, + 0x04000800, 0x00200802, 0x00200002, 0x04000800, + 0x04000002, 0x04200000, 0x04200800, 0x00200002, + 0x04200000, 0x00000800, 0x00000802, 0x04200802, + 0x00200800, 0x00000002, 0x04000000, 0x00200800, + 0x04000000, 0x00200800, 0x00200000, 0x04000802, + 0x04000802, 0x04200002, 0x04200002, 0x00000002, + 0x00200002, 0x04000000, 0x04000800, 0x00200000, + 0x04200800, 0x00000802, 0x00200802, 0x04200800, + 0x00000802, 0x04000002, 0x04200802, 0x04200000, + 0x00200800, 0x00000000, 0x00000002, 0x04200802, + 0x00000000, 0x00200802, 0x04200000, 0x00000800, + 0x04000002, 0x04000800, 0x00000800, 0x00200002 +}; + +static const uint32_t SB8[64] = +{ + 0x10001040, 0x00001000, 0x00040000, 0x10041040, + 0x10000000, 0x10001040, 0x00000040, 0x10000000, + 0x00040040, 0x10040000, 0x10041040, 0x00041000, + 0x10041000, 0x00041040, 0x00001000, 0x00000040, + 0x10040000, 0x10000040, 0x10001000, 0x00001040, + 0x00041000, 0x00040040, 0x10040040, 0x10041000, + 0x00001040, 0x00000000, 0x00000000, 0x10040040, + 0x10000040, 0x10001000, 0x00041040, 0x00040000, + 0x00041040, 0x00040000, 0x10041000, 0x00001000, + 0x00000040, 0x10040040, 0x00001000, 0x00041040, + 0x10001000, 0x00000040, 0x10000040, 0x10040000, + 0x10040040, 0x10000000, 0x00040000, 0x10001040, + 0x00000000, 0x10041040, 0x00040040, 0x10000040, + 0x10040000, 0x10001000, 0x10001040, 0x00000000, + 0x10041040, 0x00041000, 0x00041000, 0x00001040, + 0x00001040, 0x00040040, 0x10000000, 0x10041000 +}; + +/* + * PC1: left and right halves bit-swap + */ +static const uint32_t LHs[16] = +{ + 0x00000000, 0x00000001, 0x00000100, 0x00000101, + 0x00010000, 0x00010001, 0x00010100, 0x00010101, + 0x01000000, 0x01000001, 0x01000100, 0x01000101, + 0x01010000, 0x01010001, 0x01010100, 0x01010101 +}; + +static const uint32_t RHs[16] = +{ + 0x00000000, 0x01000000, 0x00010000, 0x01010000, + 0x00000100, 0x01000100, 0x00010100, 0x01010100, + 0x00000001, 0x01000001, 0x00010001, 0x01010001, + 0x00000101, 0x01000101, 0x00010101, 0x01010101, +}; + +/* + * Initial Permutation macro + */ +#define DES_IP(X,Y) \ +{ \ + T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \ + T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \ + T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \ + T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \ + Y = ((Y << 1) | (Y >> 31)) & 0xFFFFFFFF; \ + T = (X ^ Y) & 0xAAAAAAAA; Y ^= T; X ^= T; \ + X = ((X << 1) | (X >> 31)) & 0xFFFFFFFF; \ +} + +/* + * Final Permutation macro + */ +#define DES_FP(X,Y) \ +{ \ + X = ((X << 31) | (X >> 1)) & 0xFFFFFFFF; \ + T = (X ^ Y) & 0xAAAAAAAA; X ^= T; Y ^= T; \ + Y = ((Y << 31) | (Y >> 1)) & 0xFFFFFFFF; \ + T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \ + T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \ + T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \ + T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \ +} + +/* + * DES round macro + */ +#define DES_ROUND(X,Y) \ +{ \ + T = *SK++ ^ X; \ + Y ^= SB8[ (T ) & 0x3F ] ^ \ + SB6[ (T >> 8) & 0x3F ] ^ \ + SB4[ (T >> 16) & 0x3F ] ^ \ + SB2[ (T >> 24) & 0x3F ]; \ + \ + T = *SK++ ^ ((X << 28) | (X >> 4)); \ + Y ^= SB7[ (T ) & 0x3F ] ^ \ + SB5[ (T >> 8) & 0x3F ] ^ \ + SB3[ (T >> 16) & 0x3F ] ^ \ + SB1[ (T >> 24) & 0x3F ]; \ +} + +#define SWAP(a,b) { uint32_t t = a; a = b; b = t; t = 0; } + +void mbedtls_des_init( mbedtls_des_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_des_context ) ); +} + +void mbedtls_des_free( mbedtls_des_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_des_context ) ); +} + +void mbedtls_des3_init( mbedtls_des3_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_des3_context ) ); +} + +void mbedtls_des3_free( mbedtls_des3_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_des3_context ) ); +} + +static const unsigned char odd_parity_table[128] = { 1, 2, 4, 7, 8, + 11, 13, 14, 16, 19, 21, 22, 25, 26, 28, 31, 32, 35, 37, 38, 41, 42, 44, + 47, 49, 50, 52, 55, 56, 59, 61, 62, 64, 67, 69, 70, 73, 74, 76, 79, 81, + 82, 84, 87, 88, 91, 93, 94, 97, 98, 100, 103, 104, 107, 109, 110, 112, + 115, 117, 118, 121, 122, 124, 127, 128, 131, 133, 134, 137, 138, 140, + 143, 145, 146, 148, 151, 152, 155, 157, 158, 161, 162, 164, 167, 168, + 171, 173, 174, 176, 179, 181, 182, 185, 186, 188, 191, 193, 194, 196, + 199, 200, 203, 205, 206, 208, 211, 213, 214, 217, 218, 220, 223, 224, + 227, 229, 230, 233, 234, 236, 239, 241, 242, 244, 247, 248, 251, 253, + 254 }; + +void mbedtls_des_key_set_parity( unsigned char key[MBEDTLS_DES_KEY_SIZE] ) +{ + int i; + + for( i = 0; i < MBEDTLS_DES_KEY_SIZE; i++ ) + key[i] = odd_parity_table[key[i] / 2]; +} + +/* + * Check the given key's parity, returns 1 on failure, 0 on SUCCESS + */ +int mbedtls_des_key_check_key_parity( const unsigned char key[MBEDTLS_DES_KEY_SIZE] ) +{ + int i; + + for( i = 0; i < MBEDTLS_DES_KEY_SIZE; i++ ) + if( key[i] != odd_parity_table[key[i] / 2] ) + return( 1 ); + + return( 0 ); +} + +/* + * Table of weak and semi-weak keys + * + * Source: http://en.wikipedia.org/wiki/Weak_key + * + * Weak: + * Alternating ones + zeros (0x0101010101010101) + * Alternating 'F' + 'E' (0xFEFEFEFEFEFEFEFE) + * '0xE0E0E0E0F1F1F1F1' + * '0x1F1F1F1F0E0E0E0E' + * + * Semi-weak: + * 0x011F011F010E010E and 0x1F011F010E010E01 + * 0x01E001E001F101F1 and 0xE001E001F101F101 + * 0x01FE01FE01FE01FE and 0xFE01FE01FE01FE01 + * 0x1FE01FE00EF10EF1 and 0xE01FE01FF10EF10E + * 0x1FFE1FFE0EFE0EFE and 0xFE1FFE1FFE0EFE0E + * 0xE0FEE0FEF1FEF1FE and 0xFEE0FEE0FEF1FEF1 + * + */ + +#define WEAK_KEY_COUNT 16 + +static const unsigned char weak_key_table[WEAK_KEY_COUNT][MBEDTLS_DES_KEY_SIZE] = +{ + { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, + { 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE }, + { 0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E }, + { 0xE0, 0xE0, 0xE0, 0xE0, 0xF1, 0xF1, 0xF1, 0xF1 }, + + { 0x01, 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E }, + { 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E, 0x01 }, + { 0x01, 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1 }, + { 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1, 0x01 }, + { 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE }, + { 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01 }, + { 0x1F, 0xE0, 0x1F, 0xE0, 0x0E, 0xF1, 0x0E, 0xF1 }, + { 0xE0, 0x1F, 0xE0, 0x1F, 0xF1, 0x0E, 0xF1, 0x0E }, + { 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E, 0xFE }, + { 0xFE, 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E }, + { 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1, 0xFE }, + { 0xFE, 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1 } +}; + +int mbedtls_des_key_check_weak( const unsigned char key[MBEDTLS_DES_KEY_SIZE] ) +{ + int i; + + for( i = 0; i < WEAK_KEY_COUNT; i++ ) + if( memcmp( weak_key_table[i], key, MBEDTLS_DES_KEY_SIZE) == 0 ) + return( 1 ); + + return( 0 ); +} + +#if !defined(MBEDTLS_DES_SETKEY_ALT) +void mbedtls_des_setkey( uint32_t SK[32], const unsigned char key[MBEDTLS_DES_KEY_SIZE] ) +{ + int i; + uint32_t X, Y, T; + + GET_UINT32_BE( X, key, 0 ); + GET_UINT32_BE( Y, key, 4 ); + + /* + * Permuted Choice 1 + */ + T = ((Y >> 4) ^ X) & 0x0F0F0F0F; X ^= T; Y ^= (T << 4); + T = ((Y ) ^ X) & 0x10101010; X ^= T; Y ^= (T ); + + X = (LHs[ (X ) & 0xF] << 3) | (LHs[ (X >> 8) & 0xF ] << 2) + | (LHs[ (X >> 16) & 0xF] << 1) | (LHs[ (X >> 24) & 0xF ] ) + | (LHs[ (X >> 5) & 0xF] << 7) | (LHs[ (X >> 13) & 0xF ] << 6) + | (LHs[ (X >> 21) & 0xF] << 5) | (LHs[ (X >> 29) & 0xF ] << 4); + + Y = (RHs[ (Y >> 1) & 0xF] << 3) | (RHs[ (Y >> 9) & 0xF ] << 2) + | (RHs[ (Y >> 17) & 0xF] << 1) | (RHs[ (Y >> 25) & 0xF ] ) + | (RHs[ (Y >> 4) & 0xF] << 7) | (RHs[ (Y >> 12) & 0xF ] << 6) + | (RHs[ (Y >> 20) & 0xF] << 5) | (RHs[ (Y >> 28) & 0xF ] << 4); + + X &= 0x0FFFFFFF; + Y &= 0x0FFFFFFF; + + /* + * calculate subkeys + */ + for( i = 0; i < 16; i++ ) + { + if( i < 2 || i == 8 || i == 15 ) + { + X = ((X << 1) | (X >> 27)) & 0x0FFFFFFF; + Y = ((Y << 1) | (Y >> 27)) & 0x0FFFFFFF; + } + else + { + X = ((X << 2) | (X >> 26)) & 0x0FFFFFFF; + Y = ((Y << 2) | (Y >> 26)) & 0x0FFFFFFF; + } + + *SK++ = ((X << 4) & 0x24000000) | ((X << 28) & 0x10000000) + | ((X << 14) & 0x08000000) | ((X << 18) & 0x02080000) + | ((X << 6) & 0x01000000) | ((X << 9) & 0x00200000) + | ((X >> 1) & 0x00100000) | ((X << 10) & 0x00040000) + | ((X << 2) & 0x00020000) | ((X >> 10) & 0x00010000) + | ((Y >> 13) & 0x00002000) | ((Y >> 4) & 0x00001000) + | ((Y << 6) & 0x00000800) | ((Y >> 1) & 0x00000400) + | ((Y >> 14) & 0x00000200) | ((Y ) & 0x00000100) + | ((Y >> 5) & 0x00000020) | ((Y >> 10) & 0x00000010) + | ((Y >> 3) & 0x00000008) | ((Y >> 18) & 0x00000004) + | ((Y >> 26) & 0x00000002) | ((Y >> 24) & 0x00000001); + + *SK++ = ((X << 15) & 0x20000000) | ((X << 17) & 0x10000000) + | ((X << 10) & 0x08000000) | ((X << 22) & 0x04000000) + | ((X >> 2) & 0x02000000) | ((X << 1) & 0x01000000) + | ((X << 16) & 0x00200000) | ((X << 11) & 0x00100000) + | ((X << 3) & 0x00080000) | ((X >> 6) & 0x00040000) + | ((X << 15) & 0x00020000) | ((X >> 4) & 0x00010000) + | ((Y >> 2) & 0x00002000) | ((Y << 8) & 0x00001000) + | ((Y >> 14) & 0x00000808) | ((Y >> 9) & 0x00000400) + | ((Y ) & 0x00000200) | ((Y << 7) & 0x00000100) + | ((Y >> 7) & 0x00000020) | ((Y >> 3) & 0x00000011) + | ((Y << 2) & 0x00000004) | ((Y >> 21) & 0x00000002); + } +} +#endif /* !MBEDTLS_DES_SETKEY_ALT */ + +/* + * DES key schedule (56-bit, encryption) + */ +int mbedtls_des_setkey_enc( mbedtls_des_context *ctx, const unsigned char key[MBEDTLS_DES_KEY_SIZE] ) +{ + mbedtls_des_setkey( ctx->sk, key ); + + return( 0 ); +} + +/* + * DES key schedule (56-bit, decryption) + */ +int mbedtls_des_setkey_dec( mbedtls_des_context *ctx, const unsigned char key[MBEDTLS_DES_KEY_SIZE] ) +{ + int i; + + mbedtls_des_setkey( ctx->sk, key ); + + for( i = 0; i < 16; i += 2 ) + { + SWAP( ctx->sk[i ], ctx->sk[30 - i] ); + SWAP( ctx->sk[i + 1], ctx->sk[31 - i] ); + } + + return( 0 ); +} + +static void des3_set2key( uint32_t esk[96], + uint32_t dsk[96], + const unsigned char key[MBEDTLS_DES_KEY_SIZE*2] ) +{ + int i; + + mbedtls_des_setkey( esk, key ); + mbedtls_des_setkey( dsk + 32, key + 8 ); + + for( i = 0; i < 32; i += 2 ) + { + dsk[i ] = esk[30 - i]; + dsk[i + 1] = esk[31 - i]; + + esk[i + 32] = dsk[62 - i]; + esk[i + 33] = dsk[63 - i]; + + esk[i + 64] = esk[i ]; + esk[i + 65] = esk[i + 1]; + + dsk[i + 64] = dsk[i ]; + dsk[i + 65] = dsk[i + 1]; + } +} + +/* + * Triple-DES key schedule (112-bit, encryption) + */ +int mbedtls_des3_set2key_enc( mbedtls_des3_context *ctx, + const unsigned char key[MBEDTLS_DES_KEY_SIZE * 2] ) +{ + uint32_t sk[96]; + + des3_set2key( ctx->sk, sk, key ); + mbedtls_platform_zeroize( sk, sizeof( sk ) ); + + return( 0 ); +} + +/* + * Triple-DES key schedule (112-bit, decryption) + */ +int mbedtls_des3_set2key_dec( mbedtls_des3_context *ctx, + const unsigned char key[MBEDTLS_DES_KEY_SIZE * 2] ) +{ + uint32_t sk[96]; + + des3_set2key( sk, ctx->sk, key ); + mbedtls_platform_zeroize( sk, sizeof( sk ) ); + + return( 0 ); +} + +static void des3_set3key( uint32_t esk[96], + uint32_t dsk[96], + const unsigned char key[24] ) +{ + int i; + + mbedtls_des_setkey( esk, key ); + mbedtls_des_setkey( dsk + 32, key + 8 ); + mbedtls_des_setkey( esk + 64, key + 16 ); + + for( i = 0; i < 32; i += 2 ) + { + dsk[i ] = esk[94 - i]; + dsk[i + 1] = esk[95 - i]; + + esk[i + 32] = dsk[62 - i]; + esk[i + 33] = dsk[63 - i]; + + dsk[i + 64] = esk[30 - i]; + dsk[i + 65] = esk[31 - i]; + } +} + +/* + * Triple-DES key schedule (168-bit, encryption) + */ +int mbedtls_des3_set3key_enc( mbedtls_des3_context *ctx, + const unsigned char key[MBEDTLS_DES_KEY_SIZE * 3] ) +{ + uint32_t sk[96]; + + des3_set3key( ctx->sk, sk, key ); + mbedtls_platform_zeroize( sk, sizeof( sk ) ); + + return( 0 ); +} + +/* + * Triple-DES key schedule (168-bit, decryption) + */ +int mbedtls_des3_set3key_dec( mbedtls_des3_context *ctx, + const unsigned char key[MBEDTLS_DES_KEY_SIZE * 3] ) +{ + uint32_t sk[96]; + + des3_set3key( sk, ctx->sk, key ); + mbedtls_platform_zeroize( sk, sizeof( sk ) ); + + return( 0 ); +} + +/* + * DES-ECB block encryption/decryption + */ +#if !defined(MBEDTLS_DES_CRYPT_ECB_ALT) +int mbedtls_des_crypt_ecb( mbedtls_des_context *ctx, + const unsigned char input[8], + unsigned char output[8] ) +{ + int i; + uint32_t X, Y, T, *SK; + + SK = ctx->sk; + + GET_UINT32_BE( X, input, 0 ); + GET_UINT32_BE( Y, input, 4 ); + + DES_IP( X, Y ); + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( Y, X ); + DES_ROUND( X, Y ); + } + + DES_FP( Y, X ); + + PUT_UINT32_BE( Y, output, 0 ); + PUT_UINT32_BE( X, output, 4 ); + + return( 0 ); +} +#endif /* !MBEDTLS_DES_CRYPT_ECB_ALT */ + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/* + * DES-CBC buffer encryption/decryption + */ +int mbedtls_des_crypt_cbc( mbedtls_des_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + const unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[8]; + + if( length % 8 ) + return( MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH ); + + if( mode == MBEDTLS_DES_ENCRYPT ) + { + while( length > 0 ) + { + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + mbedtls_des_crypt_ecb( ctx, output, output ); + memcpy( iv, output, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + else /* MBEDTLS_DES_DECRYPT */ + { + while( length > 0 ) + { + memcpy( temp, input, 8 ); + mbedtls_des_crypt_ecb( ctx, input, output ); + + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +/* + * 3DES-ECB block encryption/decryption + */ +#if !defined(MBEDTLS_DES3_CRYPT_ECB_ALT) +int mbedtls_des3_crypt_ecb( mbedtls_des3_context *ctx, + const unsigned char input[8], + unsigned char output[8] ) +{ + int i; + uint32_t X, Y, T, *SK; + + SK = ctx->sk; + + GET_UINT32_BE( X, input, 0 ); + GET_UINT32_BE( Y, input, 4 ); + + DES_IP( X, Y ); + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( Y, X ); + DES_ROUND( X, Y ); + } + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( X, Y ); + DES_ROUND( Y, X ); + } + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( Y, X ); + DES_ROUND( X, Y ); + } + + DES_FP( Y, X ); + + PUT_UINT32_BE( Y, output, 0 ); + PUT_UINT32_BE( X, output, 4 ); + + return( 0 ); +} +#endif /* !MBEDTLS_DES3_CRYPT_ECB_ALT */ + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/* + * 3DES-CBC buffer encryption/decryption + */ +int mbedtls_des3_crypt_cbc( mbedtls_des3_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + const unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[8]; + + if( length % 8 ) + return( MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH ); + + if( mode == MBEDTLS_DES_ENCRYPT ) + { + while( length > 0 ) + { + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + mbedtls_des3_crypt_ecb( ctx, output, output ); + memcpy( iv, output, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + else /* MBEDTLS_DES_DECRYPT */ + { + while( length > 0 ) + { + memcpy( temp, input, 8 ); + mbedtls_des3_crypt_ecb( ctx, input, output ); + + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#endif /* !MBEDTLS_DES_ALT */ + +#if defined(MBEDTLS_SELF_TEST) +/* + * DES and 3DES test vectors from: + * + * http://csrc.nist.gov/groups/STM/cavp/documents/des/tripledes-vectors.zip + */ +static const unsigned char des3_test_keys[24] = +{ + 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, + 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, + 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23 +}; + +static const unsigned char des3_test_buf[8] = +{ + 0x4E, 0x6F, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74 +}; + +static const unsigned char des3_test_ecb_dec[3][8] = +{ + { 0xCD, 0xD6, 0x4F, 0x2F, 0x94, 0x27, 0xC1, 0x5D }, + { 0x69, 0x96, 0xC8, 0xFA, 0x47, 0xA2, 0xAB, 0xEB }, + { 0x83, 0x25, 0x39, 0x76, 0x44, 0x09, 0x1A, 0x0A } +}; + +static const unsigned char des3_test_ecb_enc[3][8] = +{ + { 0x6A, 0x2A, 0x19, 0xF4, 0x1E, 0xCA, 0x85, 0x4B }, + { 0x03, 0xE6, 0x9F, 0x5B, 0xFA, 0x58, 0xEB, 0x42 }, + { 0xDD, 0x17, 0xE8, 0xB8, 0xB4, 0x37, 0xD2, 0x32 } +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const unsigned char des3_test_iv[8] = +{ + 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, +}; + +static const unsigned char des3_test_cbc_dec[3][8] = +{ + { 0x12, 0x9F, 0x40, 0xB9, 0xD2, 0x00, 0x56, 0xB3 }, + { 0x47, 0x0E, 0xFC, 0x9A, 0x6B, 0x8E, 0xE3, 0x93 }, + { 0xC5, 0xCE, 0xCF, 0x63, 0xEC, 0xEC, 0x51, 0x4C } +}; + +static const unsigned char des3_test_cbc_enc[3][8] = +{ + { 0x54, 0xF1, 0x5A, 0xF6, 0xEB, 0xE3, 0xA4, 0xB4 }, + { 0x35, 0x76, 0x11, 0x56, 0x5F, 0xA1, 0x8E, 0x4D }, + { 0xCB, 0x19, 0x1F, 0x85, 0xD1, 0xED, 0x84, 0x39 } +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +/* + * Checkup routine + */ +int mbedtls_des_self_test( int verbose ) +{ + int i, j, u, v, ret = 0; + mbedtls_des_context ctx; + mbedtls_des3_context ctx3; + unsigned char buf[8]; +#if defined(MBEDTLS_CIPHER_MODE_CBC) + unsigned char prv[8]; + unsigned char iv[8]; +#endif + + mbedtls_des_init( &ctx ); + mbedtls_des3_init( &ctx3 ); + /* + * ECB mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " DES%c-ECB-%3d (%s): ", + ( u == 0 ) ? ' ' : '3', 56 + u * 56, + ( v == MBEDTLS_DES_DECRYPT ) ? "dec" : "enc" ); + + memcpy( buf, des3_test_buf, 8 ); + + switch( i ) + { + case 0: + mbedtls_des_setkey_dec( &ctx, des3_test_keys ); + break; + + case 1: + mbedtls_des_setkey_enc( &ctx, des3_test_keys ); + break; + + case 2: + mbedtls_des3_set2key_dec( &ctx3, des3_test_keys ); + break; + + case 3: + mbedtls_des3_set2key_enc( &ctx3, des3_test_keys ); + break; + + case 4: + mbedtls_des3_set3key_dec( &ctx3, des3_test_keys ); + break; + + case 5: + mbedtls_des3_set3key_enc( &ctx3, des3_test_keys ); + break; + + default: + return( 1 ); + } + + for( j = 0; j < 10000; j++ ) + { + if( u == 0 ) + mbedtls_des_crypt_ecb( &ctx, buf, buf ); + else + mbedtls_des3_crypt_ecb( &ctx3, buf, buf ); + } + + if( ( v == MBEDTLS_DES_DECRYPT && + memcmp( buf, des3_test_ecb_dec[u], 8 ) != 0 ) || + ( v != MBEDTLS_DES_DECRYPT && + memcmp( buf, des3_test_ecb_enc[u], 8 ) != 0 ) ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + /* + * CBC mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " DES%c-CBC-%3d (%s): ", + ( u == 0 ) ? ' ' : '3', 56 + u * 56, + ( v == MBEDTLS_DES_DECRYPT ) ? "dec" : "enc" ); + + memcpy( iv, des3_test_iv, 8 ); + memcpy( prv, des3_test_iv, 8 ); + memcpy( buf, des3_test_buf, 8 ); + + switch( i ) + { + case 0: + mbedtls_des_setkey_dec( &ctx, des3_test_keys ); + break; + + case 1: + mbedtls_des_setkey_enc( &ctx, des3_test_keys ); + break; + + case 2: + mbedtls_des3_set2key_dec( &ctx3, des3_test_keys ); + break; + + case 3: + mbedtls_des3_set2key_enc( &ctx3, des3_test_keys ); + break; + + case 4: + mbedtls_des3_set3key_dec( &ctx3, des3_test_keys ); + break; + + case 5: + mbedtls_des3_set3key_enc( &ctx3, des3_test_keys ); + break; + + default: + return( 1 ); + } + + if( v == MBEDTLS_DES_DECRYPT ) + { + for( j = 0; j < 10000; j++ ) + { + if( u == 0 ) + mbedtls_des_crypt_cbc( &ctx, v, 8, iv, buf, buf ); + else + mbedtls_des3_crypt_cbc( &ctx3, v, 8, iv, buf, buf ); + } + } + else + { + for( j = 0; j < 10000; j++ ) + { + unsigned char tmp[8]; + + if( u == 0 ) + mbedtls_des_crypt_cbc( &ctx, v, 8, iv, buf, buf ); + else + mbedtls_des3_crypt_cbc( &ctx3, v, 8, iv, buf, buf ); + + memcpy( tmp, prv, 8 ); + memcpy( prv, buf, 8 ); + memcpy( buf, tmp, 8 ); + } + + memcpy( buf, prv, 8 ); + } + + if( ( v == MBEDTLS_DES_DECRYPT && + memcmp( buf, des3_test_cbc_dec[u], 8 ) != 0 ) || + ( v != MBEDTLS_DES_DECRYPT && + memcmp( buf, des3_test_cbc_enc[u], 8 ) != 0 ) ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +exit: + mbedtls_des_free( &ctx ); + mbedtls_des3_free( &ctx3 ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_DES_C */ diff --git a/common/mbedtls/des.h b/common/mbedtls/des.h new file mode 100644 index 00000000..9406e0ae --- /dev/null +++ b/common/mbedtls/des.h @@ -0,0 +1,352 @@ +/** + * \file des.h + * + * \brief DES block cipher + * + * \warning DES is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + * + */ +#ifndef MBEDTLS_DES_H +#define MBEDTLS_DES_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#define MBEDTLS_DES_ENCRYPT 1 +#define MBEDTLS_DES_DECRYPT 0 + +#define MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH -0x0032 /**< The data input has an invalid length. */ +#define MBEDTLS_ERR_DES_HW_ACCEL_FAILED -0x0033 /**< DES hardware accelerator failed. */ + +#define MBEDTLS_DES_KEY_SIZE 8 + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_DES_ALT) +// Regular implementation +// + +/** + * \brief DES context structure + * + * \warning DES is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + */ +typedef struct mbedtls_des_context +{ + uint32_t sk[32]; /*!< DES subkeys */ +} +mbedtls_des_context; + +/** + * \brief Triple-DES context structure + */ +typedef struct mbedtls_des3_context +{ + uint32_t sk[96]; /*!< 3DES subkeys */ +} +mbedtls_des3_context; + +#else /* MBEDTLS_DES_ALT */ +#include "des_alt.h" +#endif /* MBEDTLS_DES_ALT */ + +/** + * \brief Initialize DES context + * + * \param ctx DES context to be initialized + * + * \warning DES is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + */ +void mbedtls_des_init( mbedtls_des_context *ctx ); + +/** + * \brief Clear DES context + * + * \param ctx DES context to be cleared + * + * \warning DES is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + */ +void mbedtls_des_free( mbedtls_des_context *ctx ); + +/** + * \brief Initialize Triple-DES context + * + * \param ctx DES3 context to be initialized + */ +void mbedtls_des3_init( mbedtls_des3_context *ctx ); + +/** + * \brief Clear Triple-DES context + * + * \param ctx DES3 context to be cleared + */ +void mbedtls_des3_free( mbedtls_des3_context *ctx ); + +/** + * \brief Set key parity on the given key to odd. + * + * DES keys are 56 bits long, but each byte is padded with + * a parity bit to allow verification. + * + * \param key 8-byte secret key + * + * \warning DES is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + */ +void mbedtls_des_key_set_parity( unsigned char key[MBEDTLS_DES_KEY_SIZE] ); + +/** + * \brief Check that key parity on the given key is odd. + * + * DES keys are 56 bits long, but each byte is padded with + * a parity bit to allow verification. + * + * \param key 8-byte secret key + * + * \return 0 is parity was ok, 1 if parity was not correct. + * + * \warning DES is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + */ +int mbedtls_des_key_check_key_parity( const unsigned char key[MBEDTLS_DES_KEY_SIZE] ); + +/** + * \brief Check that key is not a weak or semi-weak DES key + * + * \param key 8-byte secret key + * + * \return 0 if no weak key was found, 1 if a weak key was identified. + * + * \warning DES is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + */ +int mbedtls_des_key_check_weak( const unsigned char key[MBEDTLS_DES_KEY_SIZE] ); + +/** + * \brief DES key schedule (56-bit, encryption) + * + * \param ctx DES context to be initialized + * \param key 8-byte secret key + * + * \return 0 + * + * \warning DES is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + */ +int mbedtls_des_setkey_enc( mbedtls_des_context *ctx, const unsigned char key[MBEDTLS_DES_KEY_SIZE] ); + +/** + * \brief DES key schedule (56-bit, decryption) + * + * \param ctx DES context to be initialized + * \param key 8-byte secret key + * + * \return 0 + * + * \warning DES is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + */ +int mbedtls_des_setkey_dec( mbedtls_des_context *ctx, const unsigned char key[MBEDTLS_DES_KEY_SIZE] ); + +/** + * \brief Triple-DES key schedule (112-bit, encryption) + * + * \param ctx 3DES context to be initialized + * \param key 16-byte secret key + * + * \return 0 + */ +int mbedtls_des3_set2key_enc( mbedtls_des3_context *ctx, + const unsigned char key[MBEDTLS_DES_KEY_SIZE * 2] ); + +/** + * \brief Triple-DES key schedule (112-bit, decryption) + * + * \param ctx 3DES context to be initialized + * \param key 16-byte secret key + * + * \return 0 + */ +int mbedtls_des3_set2key_dec( mbedtls_des3_context *ctx, + const unsigned char key[MBEDTLS_DES_KEY_SIZE * 2] ); + +/** + * \brief Triple-DES key schedule (168-bit, encryption) + * + * \param ctx 3DES context to be initialized + * \param key 24-byte secret key + * + * \return 0 + */ +int mbedtls_des3_set3key_enc( mbedtls_des3_context *ctx, + const unsigned char key[MBEDTLS_DES_KEY_SIZE * 3] ); + +/** + * \brief Triple-DES key schedule (168-bit, decryption) + * + * \param ctx 3DES context to be initialized + * \param key 24-byte secret key + * + * \return 0 + */ +int mbedtls_des3_set3key_dec( mbedtls_des3_context *ctx, + const unsigned char key[MBEDTLS_DES_KEY_SIZE * 3] ); + +/** + * \brief DES-ECB block encryption/decryption + * + * \param ctx DES context + * \param input 64-bit input block + * \param output 64-bit output block + * + * \return 0 if successful + * + * \warning DES is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + */ +int mbedtls_des_crypt_ecb( mbedtls_des_context *ctx, + const unsigned char input[8], + unsigned char output[8] ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/** + * \brief DES-CBC buffer encryption/decryption + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx DES context + * \param mode MBEDTLS_DES_ENCRYPT or MBEDTLS_DES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \warning DES is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + */ +int mbedtls_des_crypt_cbc( mbedtls_des_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +/** + * \brief 3DES-ECB block encryption/decryption + * + * \param ctx 3DES context + * \param input 64-bit input block + * \param output 64-bit output block + * + * \return 0 if successful + */ +int mbedtls_des3_crypt_ecb( mbedtls_des3_context *ctx, + const unsigned char input[8], + unsigned char output[8] ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/** + * \brief 3DES-CBC buffer encryption/decryption + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx 3DES context + * \param mode MBEDTLS_DES_ENCRYPT or MBEDTLS_DES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful, or MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH + */ +int mbedtls_des3_crypt_cbc( mbedtls_des3_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +/** + * \brief Internal function for key expansion. + * (Only exposed to allow overriding it, + * see MBEDTLS_DES_SETKEY_ALT) + * + * \param SK Round keys + * \param key Base key + * + * \warning DES is considered a weak cipher and its use constitutes a + * security risk. We recommend considering stronger ciphers + * instead. + */ +void mbedtls_des_setkey( uint32_t SK[32], + const unsigned char key[MBEDTLS_DES_KEY_SIZE] ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_des_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* des.h */ diff --git a/common/mbedtls/ecdsa.c b/common/mbedtls/ecdsa.c new file mode 100644 index 00000000..e97e6cb4 --- /dev/null +++ b/common/mbedtls/ecdsa.c @@ -0,0 +1,463 @@ +/* + * Elliptic curve DSA + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * References: + * + * SEC1 http://www.secg.org/index.php?action=secg,docs_secg + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ECDSA_C) + +#include "mbedtls/ecdsa.h" +#include "mbedtls/asn1write.h" + +#include + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) +#include "mbedtls/hmac_drbg.h" +#endif + +/* + * Derive a suitable integer for group grp from a buffer of length len + * SEC1 4.1.3 step 5 aka SEC1 4.1.4 step 3 + */ +static int derive_mpi( const mbedtls_ecp_group *grp, mbedtls_mpi *x, + const unsigned char *buf, size_t blen ) +{ + int ret; + size_t n_size = ( grp->nbits + 7 ) / 8; + size_t use_size = blen > n_size ? n_size : blen; + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( x, buf, use_size ) ); + if( use_size * 8 > grp->nbits ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( x, use_size * 8 - grp->nbits ) ); + + /* While at it, reduce modulo N */ + if( mbedtls_mpi_cmp_mpi( x, &grp->N ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( x, x, &grp->N ) ); + +cleanup: + return( ret ); +} + +#if !defined(MBEDTLS_ECDSA_SIGN_ALT) +/* + * Compute ECDSA signature of a hashed message (SEC1 4.1.3) + * Obviously, compared to SEC1 4.1.3, we skip step 4 (hash message) + */ +int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, + const mbedtls_mpi *d, const unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret, key_tries, sign_tries, blind_tries; + mbedtls_ecp_point R; + mbedtls_mpi k, e, t; + + /* Fail cleanly on curves such as Curve25519 that can't be used for ECDSA */ + if( grp->N.p == NULL ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* Make sure d is in range 1..n-1 */ + if( mbedtls_mpi_cmp_int( d, 1 ) < 0 || mbedtls_mpi_cmp_mpi( d, &grp->N ) >= 0 ) + return( MBEDTLS_ERR_ECP_INVALID_KEY ); + + mbedtls_ecp_point_init( &R ); + mbedtls_mpi_init( &k ); mbedtls_mpi_init( &e ); mbedtls_mpi_init( &t ); + + sign_tries = 0; + do + { + /* + * Steps 1-3: generate a suitable ephemeral keypair + * and set r = xR mod n + */ + key_tries = 0; + do + { + MBEDTLS_MPI_CHK( mbedtls_ecp_gen_keypair( grp, &k, &R, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( r, &R.X, &grp->N ) ); + + if( key_tries++ > 10 ) + { + ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; + goto cleanup; + } + } + while( mbedtls_mpi_cmp_int( r, 0 ) == 0 ); + + /* + * Step 5: derive MPI from hashed message + */ + MBEDTLS_MPI_CHK( derive_mpi( grp, &e, buf, blen ) ); + + /* + * Generate a random value to blind inv_mod in next step, + * avoiding a potential timing leak. + */ + blind_tries = 0; + do + { + size_t n_size = ( grp->nbits + 7 ) / 8; + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &t, n_size, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &t, 8 * n_size - grp->nbits ) ); + + /* See mbedtls_ecp_gen_keypair() */ + if( ++blind_tries > 30 ) + return( MBEDTLS_ERR_ECP_RANDOM_FAILED ); + } + while( mbedtls_mpi_cmp_int( &t, 1 ) < 0 || + mbedtls_mpi_cmp_mpi( &t, &grp->N ) >= 0 ); + + /* + * Step 6: compute s = (e + r * d) / k = t (e + rd) / (kt) mod n + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, r, d ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &e, &e, s ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &e, &e, &t ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &k, &k, &t ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( s, &k, &grp->N ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, s, &e ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( s, s, &grp->N ) ); + + if( sign_tries++ > 10 ) + { + ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; + goto cleanup; + } + } + while( mbedtls_mpi_cmp_int( s, 0 ) == 0 ); + +cleanup: + mbedtls_ecp_point_free( &R ); + mbedtls_mpi_free( &k ); mbedtls_mpi_free( &e ); mbedtls_mpi_free( &t ); + + return( ret ); +} +#endif /* MBEDTLS_ECDSA_SIGN_ALT */ + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) +/* + * Deterministic signature wrapper + */ +int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, + const mbedtls_mpi *d, const unsigned char *buf, size_t blen, + mbedtls_md_type_t md_alg ) +{ + int ret; + mbedtls_hmac_drbg_context rng_ctx; + unsigned char data[2 * MBEDTLS_ECP_MAX_BYTES]; + size_t grp_len = ( grp->nbits + 7 ) / 8; + const mbedtls_md_info_t *md_info; + mbedtls_mpi h; + + if( ( md_info = mbedtls_md_info_from_type( md_alg ) ) == NULL ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + mbedtls_mpi_init( &h ); + mbedtls_hmac_drbg_init( &rng_ctx ); + + /* Use private key and message hash (reduced) to initialize HMAC_DRBG */ + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( d, data, grp_len ) ); + MBEDTLS_MPI_CHK( derive_mpi( grp, &h, buf, blen ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &h, data + grp_len, grp_len ) ); + mbedtls_hmac_drbg_seed_buf( &rng_ctx, md_info, data, 2 * grp_len ); + + ret = mbedtls_ecdsa_sign( grp, r, s, d, buf, blen, + mbedtls_hmac_drbg_random, &rng_ctx ); + +cleanup: + mbedtls_hmac_drbg_free( &rng_ctx ); + mbedtls_mpi_free( &h ); + + return( ret ); +} +#endif /* MBEDTLS_ECDSA_DETERMINISTIC */ + +#if !defined(MBEDTLS_ECDSA_VERIFY_ALT) +/* + * Verify ECDSA signature of hashed message (SEC1 4.1.4) + * Obviously, compared to SEC1 4.1.3, we skip step 2 (hash message) + */ +int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp, + const unsigned char *buf, size_t blen, + const mbedtls_ecp_point *Q, const mbedtls_mpi *r, const mbedtls_mpi *s) +{ + int ret; + mbedtls_mpi e, s_inv, u1, u2; + mbedtls_ecp_point R; + + mbedtls_ecp_point_init( &R ); + mbedtls_mpi_init( &e ); mbedtls_mpi_init( &s_inv ); mbedtls_mpi_init( &u1 ); mbedtls_mpi_init( &u2 ); + + /* Fail cleanly on curves such as Curve25519 that can't be used for ECDSA */ + if( grp->N.p == NULL ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * Step 1: make sure r and s are in range 1..n-1 + */ + if( mbedtls_mpi_cmp_int( r, 1 ) < 0 || mbedtls_mpi_cmp_mpi( r, &grp->N ) >= 0 || + mbedtls_mpi_cmp_int( s, 1 ) < 0 || mbedtls_mpi_cmp_mpi( s, &grp->N ) >= 0 ) + { + ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; + goto cleanup; + } + + /* + * Additional precaution: make sure Q is valid + */ + MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, Q ) ); + + /* + * Step 3: derive MPI from hashed message + */ + MBEDTLS_MPI_CHK( derive_mpi( grp, &e, buf, blen ) ); + + /* + * Step 4: u1 = e / s mod n, u2 = r / s mod n + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &s_inv, s, &grp->N ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &u1, &e, &s_inv ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &u1, &u1, &grp->N ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &u2, r, &s_inv ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &u2, &u2, &grp->N ) ); + + /* + * Step 5: R = u1 G + u2 Q + * + * Since we're not using any secret data, no need to pass a RNG to + * mbedtls_ecp_mul() for countermesures. + */ + MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( grp, &R, &u1, &grp->G, &u2, Q ) ); + + if( mbedtls_ecp_is_zero( &R ) ) + { + ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; + goto cleanup; + } + + /* + * Step 6: convert xR to an integer (no-op) + * Step 7: reduce xR mod n (gives v) + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &R.X, &R.X, &grp->N ) ); + + /* + * Step 8: check if v (that is, R.X) is equal to r + */ + if( mbedtls_mpi_cmp_mpi( &R.X, r ) != 0 ) + { + ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; + goto cleanup; + } + +cleanup: + mbedtls_ecp_point_free( &R ); + mbedtls_mpi_free( &e ); mbedtls_mpi_free( &s_inv ); mbedtls_mpi_free( &u1 ); mbedtls_mpi_free( &u2 ); + + return( ret ); +} +#endif /* MBEDTLS_ECDSA_VERIFY_ALT */ + +/* + * Convert a signature (given by context) to ASN.1 + */ +static int ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s, + unsigned char *sig, size_t *slen ) +{ + int ret; + unsigned char buf[MBEDTLS_ECDSA_MAX_LEN]; + unsigned char *p = buf + sizeof( buf ); + size_t len = 0; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &p, buf, s ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &p, buf, r ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &p, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &p, buf, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ); + + memcpy( sig, p, len ); + *slen = len; + + return( 0 ); +} + +/* + * Compute and write signature + */ +int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hlen, + unsigned char *sig, size_t *slen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + mbedtls_mpi r, s; + + mbedtls_mpi_init( &r ); + mbedtls_mpi_init( &s ); + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) + (void) f_rng; + (void) p_rng; + + MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign_det( &ctx->grp, &r, &s, &ctx->d, + hash, hlen, md_alg ) ); +#else + (void) md_alg; + + MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign( &ctx->grp, &r, &s, &ctx->d, + hash, hlen, f_rng, p_rng ) ); +#endif + + MBEDTLS_MPI_CHK( ecdsa_signature_to_asn1( &r, &s, sig, slen ) ); + +cleanup: + mbedtls_mpi_free( &r ); + mbedtls_mpi_free( &s ); + + return( ret ); +} + +#if ! defined(MBEDTLS_DEPRECATED_REMOVED) && \ + defined(MBEDTLS_ECDSA_DETERMINISTIC) +int mbedtls_ecdsa_write_signature_det( mbedtls_ecdsa_context *ctx, + const unsigned char *hash, size_t hlen, + unsigned char *sig, size_t *slen, + mbedtls_md_type_t md_alg ) +{ + return( mbedtls_ecdsa_write_signature( ctx, md_alg, hash, hlen, sig, slen, + NULL, NULL ) ); +} +#endif + +/* + * Read and check signature + */ +int mbedtls_ecdsa_read_signature( mbedtls_ecdsa_context *ctx, + const unsigned char *hash, size_t hlen, + const unsigned char *sig, size_t slen ) +{ + int ret; + unsigned char *p = (unsigned char *) sig; + const unsigned char *end = sig + slen; + size_t len; + mbedtls_mpi r, s; + + mbedtls_mpi_init( &r ); + mbedtls_mpi_init( &s ); + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + ret += MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + + if( p + len != end ) + { + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; + goto cleanup; + } + + if( ( ret = mbedtls_asn1_get_mpi( &p, end, &r ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( &p, end, &s ) ) != 0 ) + { + ret += MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + + if( ( ret = mbedtls_ecdsa_verify( &ctx->grp, hash, hlen, + &ctx->Q, &r, &s ) ) != 0 ) + goto cleanup; + + /* At this point we know that the buffer starts with a valid signature. + * Return 0 if the buffer just contains the signature, and a specific + * error code if the valid signature is followed by more data. */ + if( p != end ) + ret = MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH; + +cleanup: + mbedtls_mpi_free( &r ); + mbedtls_mpi_free( &s ); + + return( ret ); +} + +#if !defined(MBEDTLS_ECDSA_GENKEY_ALT) +/* + * Generate key pair + */ +int mbedtls_ecdsa_genkey( mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id gid, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + return( mbedtls_ecp_group_load( &ctx->grp, gid ) || + mbedtls_ecp_gen_keypair( &ctx->grp, &ctx->d, &ctx->Q, f_rng, p_rng ) ); +} +#endif /* MBEDTLS_ECDSA_GENKEY_ALT */ + +/* + * Set context from an mbedtls_ecp_keypair + */ +int mbedtls_ecdsa_from_keypair( mbedtls_ecdsa_context *ctx, const mbedtls_ecp_keypair *key ) +{ + int ret; + + if( ( ret = mbedtls_ecp_group_copy( &ctx->grp, &key->grp ) ) != 0 || + ( ret = mbedtls_mpi_copy( &ctx->d, &key->d ) ) != 0 || + ( ret = mbedtls_ecp_copy( &ctx->Q, &key->Q ) ) != 0 ) + { + mbedtls_ecdsa_free( ctx ); + } + + return( ret ); +} + +/* + * Initialize context + */ +void mbedtls_ecdsa_init( mbedtls_ecdsa_context *ctx ) +{ + mbedtls_ecp_keypair_init( ctx ); +} + +/* + * Free context + */ +void mbedtls_ecdsa_free( mbedtls_ecdsa_context *ctx ) +{ + mbedtls_ecp_keypair_free( ctx ); +} + +#endif /* MBEDTLS_ECDSA_C */ diff --git a/common/mbedtls/ecdsa.h b/common/mbedtls/ecdsa.h new file mode 100644 index 00000000..a56cc0a5 --- /dev/null +++ b/common/mbedtls/ecdsa.h @@ -0,0 +1,341 @@ +/** + * \file ecdsa.h + * + * \brief This file contains ECDSA definitions and functions. + * + * The Elliptic Curve Digital Signature Algorithm (ECDSA) is defined in + * Standards for Efficient Cryptography Group (SECG): + * SEC1 Elliptic Curve Cryptography. + * The use of ECDSA for TLS is defined in RFC-4492: Elliptic Curve + * Cryptography (ECC) Cipher Suites for Transport Layer Security (TLS). + * + */ +/* + * Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_ECDSA_H +#define MBEDTLS_ECDSA_H + +#include "ecp.h" +#include "md.h" + +/* + * RFC-4492 page 20: + * + * Ecdsa-Sig-Value ::= SEQUENCE { + * r INTEGER, + * s INTEGER + * } + * + * Size is at most + * 1 (tag) + 1 (len) + 1 (initial 0) + ECP_MAX_BYTES for each of r and s, + * twice that + 1 (tag) + 2 (len) for the sequence + * (assuming ECP_MAX_BYTES is less than 126 for r and s, + * and less than 124 (total len <= 255) for the sequence) + */ +#if MBEDTLS_ECP_MAX_BYTES > 124 +#error "MBEDTLS_ECP_MAX_BYTES bigger than expected, please fix MBEDTLS_ECDSA_MAX_LEN" +#endif +/** The maximal size of an ECDSA signature in Bytes. */ +#define MBEDTLS_ECDSA_MAX_LEN ( 3 + 2 * ( 3 + MBEDTLS_ECP_MAX_BYTES ) ) + +/** + * \brief The ECDSA context structure. + */ +typedef mbedtls_ecp_keypair mbedtls_ecdsa_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief This function computes the ECDSA signature of a + * previously-hashed message. + * + * \note The deterministic version is usually preferred. + * + * \note If the bitlength of the message hash is larger than the + * bitlength of the group order, then the hash is truncated + * as defined in Standards for Efficient Cryptography Group + * (SECG): SEC1 Elliptic Curve Cryptography, section + * 4.1.3, step 5. + * + * \see ecp.h + * + * \param grp The ECP group. + * \param r The first output integer. + * \param s The second output integer. + * \param d The private signing key. + * \param buf The message hash. + * \param blen The length of \p buf. + * \param f_rng The RNG function. + * \param p_rng The RNG context. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX + * or \c MBEDTLS_MPI_XXX error code on failure. + */ +int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, + const mbedtls_mpi *d, const unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) +/** + * \brief This function computes the ECDSA signature of a + * previously-hashed message, deterministic version. + * + * For more information, see RFC-6979: Deterministic + * Usage of the Digital Signature Algorithm (DSA) and Elliptic + * Curve Digital Signature Algorithm (ECDSA). + * + * \note If the bitlength of the message hash is larger than the + * bitlength of the group order, then the hash is truncated as + * defined in Standards for Efficient Cryptography Group + * (SECG): SEC1 Elliptic Curve Cryptography, section + * 4.1.3, step 5. + * + * \see ecp.h + * + * \param grp The ECP group. + * \param r The first output integer. + * \param s The second output integer. + * \param d The private signing key. + * \param buf The message hash. + * \param blen The length of \p buf. + * \param md_alg The MD algorithm used to hash the message. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX + * error code on failure. + */ +int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, + const mbedtls_mpi *d, const unsigned char *buf, size_t blen, + mbedtls_md_type_t md_alg ); +#endif /* MBEDTLS_ECDSA_DETERMINISTIC */ + +/** + * \brief This function verifies the ECDSA signature of a + * previously-hashed message. + * + * \note If the bitlength of the message hash is larger than the + * bitlength of the group order, then the hash is truncated as + * defined in Standards for Efficient Cryptography Group + * (SECG): SEC1 Elliptic Curve Cryptography, section + * 4.1.4, step 3. + * + * \see ecp.h + * + * \param grp The ECP group. + * \param buf The message hash. + * \param blen The length of \p buf. + * \param Q The public key to use for verification. + * \param r The first integer of the signature. + * \param s The second integer of the signature. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if the signature + * is invalid. + * \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX + * error code on failure for any other reason. + */ +int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp, + const unsigned char *buf, size_t blen, + const mbedtls_ecp_point *Q, const mbedtls_mpi *r, const mbedtls_mpi *s); + +/** + * \brief This function computes the ECDSA signature and writes it + * to a buffer, serialized as defined in RFC-4492: + * Elliptic Curve Cryptography (ECC) Cipher Suites for + * Transport Layer Security (TLS). + * + * \warning It is not thread-safe to use the same context in + * multiple threads. + * + * \note The deterministic version is used if + * #MBEDTLS_ECDSA_DETERMINISTIC is defined. For more + * information, see RFC-6979: Deterministic Usage + * of the Digital Signature Algorithm (DSA) and Elliptic + * Curve Digital Signature Algorithm (ECDSA). + * + * \note The \p sig buffer must be at least twice as large as the + * size of the curve used, plus 9. For example, 73 Bytes if + * a 256-bit curve is used. A buffer length of + * #MBEDTLS_ECDSA_MAX_LEN is always safe. + * + * \note If the bitlength of the message hash is larger than the + * bitlength of the group order, then the hash is truncated as + * defined in Standards for Efficient Cryptography Group + * (SECG): SEC1 Elliptic Curve Cryptography, section + * 4.1.3, step 5. + * + * \see ecp.h + * + * \param ctx The ECDSA context. + * \param md_alg The message digest that was used to hash the message. + * \param hash The message hash. + * \param hlen The length of the hash. + * \param sig The buffer that holds the signature. + * \param slen The length of the signature written. + * \param f_rng The RNG function. + * \param p_rng The RNG context. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX, \c MBEDTLS_ERR_MPI_XXX or + * \c MBEDTLS_ERR_ASN1_XXX error code on failure. + */ +int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hlen, + unsigned char *sig, size_t *slen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) +#if ! defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief This function computes an ECDSA signature and writes + * it to a buffer, serialized as defined in RFC-4492: + * Elliptic Curve Cryptography (ECC) Cipher Suites for + * Transport Layer Security (TLS). + * + * The deterministic version is defined in RFC-6979: + * Deterministic Usage of the Digital Signature Algorithm (DSA) + * and Elliptic Curve Digital Signature Algorithm (ECDSA). + * + * \warning It is not thread-safe to use the same context in + * multiple threads. + * + * \note The \p sig buffer must be at least twice as large as the + * size of the curve used, plus 9. For example, 73 Bytes if a + * 256-bit curve is used. A buffer length of + * #MBEDTLS_ECDSA_MAX_LEN is always safe. + * + * \note If the bitlength of the message hash is larger than the + * bitlength of the group order, then the hash is truncated as + * defined in Standards for Efficient Cryptography Group + * (SECG): SEC1 Elliptic Curve Cryptography, section + * 4.1.3, step 5. + * + * \see ecp.h + * + * \deprecated Superseded by mbedtls_ecdsa_write_signature() in + * Mbed TLS version 2.0 and later. + * + * \param ctx The ECDSA context. + * \param hash The message hash. + * \param hlen The length of the hash. + * \param sig The buffer that holds the signature. + * \param slen The length of the signature written. + * \param md_alg The MD algorithm used to hash the message. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX, \c MBEDTLS_ERR_MPI_XXX or + * \c MBEDTLS_ERR_ASN1_XXX error code on failure. + */ +int mbedtls_ecdsa_write_signature_det( mbedtls_ecdsa_context *ctx, + const unsigned char *hash, size_t hlen, + unsigned char *sig, size_t *slen, + mbedtls_md_type_t md_alg ) MBEDTLS_DEPRECATED; +#undef MBEDTLS_DEPRECATED +#endif /* MBEDTLS_DEPRECATED_REMOVED */ +#endif /* MBEDTLS_ECDSA_DETERMINISTIC */ + +/** + * \brief This function reads and verifies an ECDSA signature. + * + * \note If the bitlength of the message hash is larger than the + * bitlength of the group order, then the hash is truncated as + * defined in Standards for Efficient Cryptography Group + * (SECG): SEC1 Elliptic Curve Cryptography, section + * 4.1.4, step 3. + * + * \see ecp.h + * + * \param ctx The ECDSA context. + * \param hash The message hash. + * \param hlen The size of the hash. + * \param sig The signature to read and verify. + * \param slen The size of \p sig. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if signature is invalid. + * \return #MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH if there is a valid + * signature in \p sig, but its length is less than \p siglen. + * \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_ERR_MPI_XXX + * error code on failure for any other reason. + */ +int mbedtls_ecdsa_read_signature( mbedtls_ecdsa_context *ctx, + const unsigned char *hash, size_t hlen, + const unsigned char *sig, size_t slen ); + +/** + * \brief This function generates an ECDSA keypair on the given curve. + * + * \see ecp.h + * + * \param ctx The ECDSA context to store the keypair in. + * \param gid The elliptic curve to use. One of the various + * \c MBEDTLS_ECP_DP_XXX macros depending on configuration. + * \param f_rng The RNG function. + * \param p_rng The RNG context. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX code on failure. + */ +int mbedtls_ecdsa_genkey( mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id gid, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + +/** + * \brief This function sets an ECDSA context from an EC key pair. + * + * \see ecp.h + * + * \param ctx The ECDSA context to set. + * \param key The EC key to use. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX code on failure. + */ +int mbedtls_ecdsa_from_keypair( mbedtls_ecdsa_context *ctx, const mbedtls_ecp_keypair *key ); + +/** + * \brief This function initializes an ECDSA context. + * + * \param ctx The ECDSA context to initialize. + */ +void mbedtls_ecdsa_init( mbedtls_ecdsa_context *ctx ); + +/** + * \brief This function frees an ECDSA context. + * + * \param ctx The ECDSA context to free. + */ +void mbedtls_ecdsa_free( mbedtls_ecdsa_context *ctx ); + +#ifdef __cplusplus +} +#endif + +#endif /* ecdsa.h */ diff --git a/common/mbedtls/ecp.c b/common/mbedtls/ecp.c new file mode 100644 index 00000000..028c7fe3 --- /dev/null +++ b/common/mbedtls/ecp.c @@ -0,0 +1,2209 @@ +/* + * Elliptic curves over GF(p): generic functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * References: + * + * SEC1 http://www.secg.org/index.php?action=secg,docs_secg + * GECC = Guide to Elliptic Curve Cryptography - Hankerson, Menezes, Vanstone + * FIPS 186-3 http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf + * RFC 4492 for the related TLS structures and constants + * RFC 7748 for the Curve448 and Curve25519 curve definitions + * + * [Curve25519] http://cr.yp.to/ecdh/curve25519-20060209.pdf + * + * [2] CORON, Jean-S'ebastien. Resistance against differential power analysis + * for elliptic curve cryptosystems. In : Cryptographic Hardware and + * Embedded Systems. Springer Berlin Heidelberg, 1999. p. 292-302. + * + * + * [3] HEDABOU, Mustapha, PINEL, Pierre, et B'EN'ETEAU, Lucien. A comb method to + * render ECC resistant against Side Channel Attacks. IACR Cryptology + * ePrint Archive, 2004, vol. 2004, p. 342. + * + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ECP_C) + +#include "mbedtls/ecp.h" +#include "mbedtls/threading.h" +#include "mbedtls/platform_util.h" + +#include + +#if !defined(MBEDTLS_ECP_ALT) + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_printf printf +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#include "mbedtls/ecp_internal.h" + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +#if defined(MBEDTLS_SELF_TEST) +/* + * Counts of point addition and doubling, and field multiplications. + * Used to test resistance of point multiplication to simple timing attacks. + */ +static unsigned long add_count, dbl_count, mul_count; +#endif + +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) +#define ECP_SHORTWEIERSTRASS +#endif + +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) || \ + defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) +#define ECP_MONTGOMERY +#endif + +/* + * Curve types: internal for now, might be exposed later + */ +typedef enum +{ + ECP_TYPE_NONE = 0, + ECP_TYPE_SHORT_WEIERSTRASS, /* y^2 = x^3 + a x + b */ + ECP_TYPE_MONTGOMERY, /* y^2 = x^3 + a x^2 + x */ +} ecp_curve_type; + +/* + * List of supported curves: + * - internal ID + * - TLS NamedCurve ID (RFC 4492 sec. 5.1.1, RFC 7071 sec. 2) + * - size in bits + * - readable name + * + * Curves are listed in order: largest curves first, and for a given size, + * fastest curves first. This provides the default order for the SSL module. + * + * Reminder: update profiles in x509_crt.c when adding a new curves! + */ +static const mbedtls_ecp_curve_info ecp_supported_curves[] = +{ +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) + { MBEDTLS_ECP_DP_SECP521R1, 25, 521, "secp521r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) + { MBEDTLS_ECP_DP_BP512R1, 28, 512, "brainpoolP512r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) + { MBEDTLS_ECP_DP_SECP384R1, 24, 384, "secp384r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) + { MBEDTLS_ECP_DP_BP384R1, 27, 384, "brainpoolP384r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + { MBEDTLS_ECP_DP_SECP256R1, 23, 256, "secp256r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) + { MBEDTLS_ECP_DP_SECP256K1, 22, 256, "secp256k1" }, +#endif +#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) + { MBEDTLS_ECP_DP_BP256R1, 26, 256, "brainpoolP256r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) + { MBEDTLS_ECP_DP_SECP224R1, 21, 224, "secp224r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) + { MBEDTLS_ECP_DP_SECP224K1, 20, 224, "secp224k1" }, +#endif +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) + { MBEDTLS_ECP_DP_SECP192R1, 19, 192, "secp192r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) + { MBEDTLS_ECP_DP_SECP192K1, 18, 192, "secp192k1" }, +#endif + { MBEDTLS_ECP_DP_NONE, 0, 0, NULL }, +}; + +#define ECP_NB_CURVES sizeof( ecp_supported_curves ) / \ + sizeof( ecp_supported_curves[0] ) + +static mbedtls_ecp_group_id ecp_supported_grp_id[ECP_NB_CURVES]; + +/* + * List of supported curves and associated info + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_list( void ) +{ + return( ecp_supported_curves ); +} + +/* + * List of supported curves, group ID only + */ +const mbedtls_ecp_group_id *mbedtls_ecp_grp_id_list( void ) +{ + static int init_done = 0; + + if( ! init_done ) + { + size_t i = 0; + const mbedtls_ecp_curve_info *curve_info; + + for( curve_info = mbedtls_ecp_curve_list(); + curve_info->grp_id != MBEDTLS_ECP_DP_NONE; + curve_info++ ) + { + ecp_supported_grp_id[i++] = curve_info->grp_id; + } + ecp_supported_grp_id[i] = MBEDTLS_ECP_DP_NONE; + + init_done = 1; + } + + return( ecp_supported_grp_id ); +} + +/* + * Get the curve info for the internal identifier + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_grp_id( mbedtls_ecp_group_id grp_id ) +{ + const mbedtls_ecp_curve_info *curve_info; + + for( curve_info = mbedtls_ecp_curve_list(); + curve_info->grp_id != MBEDTLS_ECP_DP_NONE; + curve_info++ ) + { + if( curve_info->grp_id == grp_id ) + return( curve_info ); + } + + return( NULL ); +} + +/* + * Get the curve info from the TLS identifier + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_tls_id( uint16_t tls_id ) +{ + const mbedtls_ecp_curve_info *curve_info; + + for( curve_info = mbedtls_ecp_curve_list(); + curve_info->grp_id != MBEDTLS_ECP_DP_NONE; + curve_info++ ) + { + if( curve_info->tls_id == tls_id ) + return( curve_info ); + } + + return( NULL ); +} + +/* + * Get the curve info from the name + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_name( const char *name ) +{ + const mbedtls_ecp_curve_info *curve_info; + + for( curve_info = mbedtls_ecp_curve_list(); + curve_info->grp_id != MBEDTLS_ECP_DP_NONE; + curve_info++ ) + { + if( strcmp( curve_info->name, name ) == 0 ) + return( curve_info ); + } + + return( NULL ); +} + +/* + * Get the type of a curve + */ +static inline ecp_curve_type ecp_get_type( const mbedtls_ecp_group *grp ) +{ + if( grp->G.X.p == NULL ) + return( ECP_TYPE_NONE ); + + if( grp->G.Y.p == NULL ) + return( ECP_TYPE_MONTGOMERY ); + else + return( ECP_TYPE_SHORT_WEIERSTRASS ); +} + +/* + * Initialize (the components of) a point + */ +void mbedtls_ecp_point_init( mbedtls_ecp_point *pt ) +{ + if( pt == NULL ) + return; + + mbedtls_mpi_init( &pt->X ); + mbedtls_mpi_init( &pt->Y ); + mbedtls_mpi_init( &pt->Z ); +} + +/* + * Initialize (the components of) a group + */ +void mbedtls_ecp_group_init( mbedtls_ecp_group *grp ) +{ + if( grp == NULL ) + return; + + memset( grp, 0, sizeof( mbedtls_ecp_group ) ); +} + +/* + * Initialize (the components of) a key pair + */ +void mbedtls_ecp_keypair_init( mbedtls_ecp_keypair *key ) +{ + if( key == NULL ) + return; + + mbedtls_ecp_group_init( &key->grp ); + mbedtls_mpi_init( &key->d ); + mbedtls_ecp_point_init( &key->Q ); +} + +/* + * Unallocate (the components of) a point + */ +void mbedtls_ecp_point_free( mbedtls_ecp_point *pt ) +{ + if( pt == NULL ) + return; + + mbedtls_mpi_free( &( pt->X ) ); + mbedtls_mpi_free( &( pt->Y ) ); + mbedtls_mpi_free( &( pt->Z ) ); +} + +/* + * Unallocate (the components of) a group + */ +void mbedtls_ecp_group_free( mbedtls_ecp_group *grp ) +{ + size_t i; + + if( grp == NULL ) + return; + + if( grp->h != 1 ) + { + mbedtls_mpi_free( &grp->P ); + mbedtls_mpi_free( &grp->A ); + mbedtls_mpi_free( &grp->B ); + mbedtls_ecp_point_free( &grp->G ); + mbedtls_mpi_free( &grp->N ); + } + + if( grp->T != NULL ) + { + for( i = 0; i < grp->T_size; i++ ) + mbedtls_ecp_point_free( &grp->T[i] ); + mbedtls_free( grp->T ); + } + + mbedtls_platform_zeroize( grp, sizeof( mbedtls_ecp_group ) ); +} + +/* + * Unallocate (the components of) a key pair + */ +void mbedtls_ecp_keypair_free( mbedtls_ecp_keypair *key ) +{ + if( key == NULL ) + return; + + mbedtls_ecp_group_free( &key->grp ); + mbedtls_mpi_free( &key->d ); + mbedtls_ecp_point_free( &key->Q ); +} + +/* + * Copy the contents of a point + */ +int mbedtls_ecp_copy( mbedtls_ecp_point *P, const mbedtls_ecp_point *Q ) +{ + int ret; + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &P->X, &Q->X ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &P->Y, &Q->Y ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &P->Z, &Q->Z ) ); + +cleanup: + return( ret ); +} + +/* + * Copy the contents of a group object + */ +int mbedtls_ecp_group_copy( mbedtls_ecp_group *dst, const mbedtls_ecp_group *src ) +{ + return mbedtls_ecp_group_load( dst, src->id ); +} + +/* + * Set point to zero + */ +int mbedtls_ecp_set_zero( mbedtls_ecp_point *pt ) +{ + int ret; + + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->X , 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->Y , 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->Z , 0 ) ); + +cleanup: + return( ret ); +} + +/* + * Tell if a point is zero + */ +int mbedtls_ecp_is_zero( mbedtls_ecp_point *pt ) +{ + return( mbedtls_mpi_cmp_int( &pt->Z, 0 ) == 0 ); +} + +/* + * Compare two points lazyly + */ +int mbedtls_ecp_point_cmp( const mbedtls_ecp_point *P, + const mbedtls_ecp_point *Q ) +{ + if( mbedtls_mpi_cmp_mpi( &P->X, &Q->X ) == 0 && + mbedtls_mpi_cmp_mpi( &P->Y, &Q->Y ) == 0 && + mbedtls_mpi_cmp_mpi( &P->Z, &Q->Z ) == 0 ) + { + return( 0 ); + } + + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); +} + +/* + * Import a non-zero point from ASCII strings + */ +int mbedtls_ecp_point_read_string( mbedtls_ecp_point *P, int radix, + const char *x, const char *y ) +{ + int ret; + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &P->X, radix, x ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &P->Y, radix, y ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &P->Z, 1 ) ); + +cleanup: + return( ret ); +} + +/* + * Export a point into unsigned binary data (SEC1 2.3.3) + */ +int mbedtls_ecp_point_write_binary( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *P, + int format, size_t *olen, + unsigned char *buf, size_t buflen ) +{ + int ret = 0; + size_t plen; + + if( format != MBEDTLS_ECP_PF_UNCOMPRESSED && + format != MBEDTLS_ECP_PF_COMPRESSED ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * Common case: P == 0 + */ + if( mbedtls_mpi_cmp_int( &P->Z, 0 ) == 0 ) + { + if( buflen < 1 ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + buf[0] = 0x00; + *olen = 1; + + return( 0 ); + } + + plen = mbedtls_mpi_size( &grp->P ); + + if( format == MBEDTLS_ECP_PF_UNCOMPRESSED ) + { + *olen = 2 * plen + 1; + + if( buflen < *olen ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + buf[0] = 0x04; + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &P->X, buf + 1, plen ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &P->Y, buf + 1 + plen, plen ) ); + } + else if( format == MBEDTLS_ECP_PF_COMPRESSED ) + { + *olen = plen + 1; + + if( buflen < *olen ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + buf[0] = 0x02 + mbedtls_mpi_get_bit( &P->Y, 0 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &P->X, buf + 1, plen ) ); + } + +cleanup: + return( ret ); +} + +/* + * Import a point from unsigned binary data (SEC1 2.3.4) + */ +int mbedtls_ecp_point_read_binary( const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt, + const unsigned char *buf, size_t ilen ) +{ + int ret; + size_t plen; + + if( ilen < 1 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + if( buf[0] == 0x00 ) + { + if( ilen == 1 ) + return( mbedtls_ecp_set_zero( pt ) ); + else + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + } + + plen = mbedtls_mpi_size( &grp->P ); + + if( buf[0] != 0x04 ) + return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); + + if( ilen != 2 * plen + 1 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &pt->X, buf + 1, plen ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &pt->Y, buf + 1 + plen, plen ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->Z, 1 ) ); + +cleanup: + return( ret ); +} + +/* + * Import a point from a TLS ECPoint record (RFC 4492) + * struct { + * opaque point <1..2^8-1>; + * } ECPoint; + */ +int mbedtls_ecp_tls_read_point( const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt, + const unsigned char **buf, size_t buf_len ) +{ + unsigned char data_len; + const unsigned char *buf_start; + + /* + * We must have at least two bytes (1 for length, at least one for data) + */ + if( buf_len < 2 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + data_len = *(*buf)++; + if( data_len < 1 || data_len > buf_len - 1 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * Save buffer start for read_binary and update buf + */ + buf_start = *buf; + *buf += data_len; + + return mbedtls_ecp_point_read_binary( grp, pt, buf_start, data_len ); +} + +/* + * Export a point as a TLS ECPoint record (RFC 4492) + * struct { + * opaque point <1..2^8-1>; + * } ECPoint; + */ +int mbedtls_ecp_tls_write_point( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt, + int format, size_t *olen, + unsigned char *buf, size_t blen ) +{ + int ret; + + /* + * buffer length must be at least one, for our length byte + */ + if( blen < 1 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_ecp_point_write_binary( grp, pt, format, + olen, buf + 1, blen - 1) ) != 0 ) + return( ret ); + + /* + * write length to the first byte and update total length + */ + buf[0] = (unsigned char) *olen; + ++*olen; + + return( 0 ); +} + +/* + * Set a group from an ECParameters record (RFC 4492) + */ +int mbedtls_ecp_tls_read_group( mbedtls_ecp_group *grp, const unsigned char **buf, size_t len ) +{ + uint16_t tls_id; + const mbedtls_ecp_curve_info *curve_info; + + /* + * We expect at least three bytes (see below) + */ + if( len < 3 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * First byte is curve_type; only named_curve is handled + */ + if( *(*buf)++ != MBEDTLS_ECP_TLS_NAMED_CURVE ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * Next two bytes are the namedcurve value + */ + tls_id = *(*buf)++; + tls_id <<= 8; + tls_id |= *(*buf)++; + + if( ( curve_info = mbedtls_ecp_curve_info_from_tls_id( tls_id ) ) == NULL ) + return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); + + return mbedtls_ecp_group_load( grp, curve_info->grp_id ); +} + +/* + * Write the ECParameters record corresponding to a group (RFC 4492) + */ +int mbedtls_ecp_tls_write_group( const mbedtls_ecp_group *grp, size_t *olen, + unsigned char *buf, size_t blen ) +{ + const mbedtls_ecp_curve_info *curve_info; + + if( ( curve_info = mbedtls_ecp_curve_info_from_grp_id( grp->id ) ) == NULL ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * We are going to write 3 bytes (see below) + */ + *olen = 3; + if( blen < *olen ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + /* + * First byte is curve_type, always named_curve + */ + *buf++ = MBEDTLS_ECP_TLS_NAMED_CURVE; + + /* + * Next two bytes are the namedcurve value + */ + buf[0] = curve_info->tls_id >> 8; + buf[1] = curve_info->tls_id & 0xFF; + + return( 0 ); +} + +/* + * Wrapper around fast quasi-modp functions, with fall-back to mbedtls_mpi_mod_mpi. + * See the documentation of struct mbedtls_ecp_group. + * + * This function is in the critial loop for mbedtls_ecp_mul, so pay attention to perf. + */ +static int ecp_modp( mbedtls_mpi *N, const mbedtls_ecp_group *grp ) +{ + int ret; + + if( grp->modp == NULL ) + return( mbedtls_mpi_mod_mpi( N, N, &grp->P ) ); + + /* N->s < 0 is a much faster test, which fails only if N is 0 */ + if( ( N->s < 0 && mbedtls_mpi_cmp_int( N, 0 ) != 0 ) || + mbedtls_mpi_bitlen( N ) > 2 * grp->pbits ) + { + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + } + + MBEDTLS_MPI_CHK( grp->modp( N ) ); + + /* N->s < 0 is a much faster test, which fails only if N is 0 */ + while( N->s < 0 && mbedtls_mpi_cmp_int( N, 0 ) != 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( N, N, &grp->P ) ); + + while( mbedtls_mpi_cmp_mpi( N, &grp->P ) >= 0 ) + /* we known P, N and the result are positive */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( N, N, &grp->P ) ); + +cleanup: + return( ret ); +} + +/* + * Fast mod-p functions expect their argument to be in the 0..p^2 range. + * + * In order to guarantee that, we need to ensure that operands of + * mbedtls_mpi_mul_mpi are in the 0..p range. So, after each operation we will + * bring the result back to this range. + * + * The following macros are shortcuts for doing that. + */ + +/* + * Reduce a mbedtls_mpi mod p in-place, general case, to use after mbedtls_mpi_mul_mpi + */ +#if defined(MBEDTLS_SELF_TEST) +#define INC_MUL_COUNT mul_count++; +#else +#define INC_MUL_COUNT +#endif + +#define MOD_MUL( N ) do { MBEDTLS_MPI_CHK( ecp_modp( &N, grp ) ); INC_MUL_COUNT } \ + while( 0 ) + +/* + * Reduce a mbedtls_mpi mod p in-place, to use after mbedtls_mpi_sub_mpi + * N->s < 0 is a very fast test, which fails only if N is 0 + */ +#define MOD_SUB( N ) \ + while( N.s < 0 && mbedtls_mpi_cmp_int( &N, 0 ) != 0 ) \ + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &N, &N, &grp->P ) ) + +/* + * Reduce a mbedtls_mpi mod p in-place, to use after mbedtls_mpi_add_mpi and mbedtls_mpi_mul_int. + * We known P, N and the result are positive, so sub_abs is correct, and + * a bit faster. + */ +#define MOD_ADD( N ) \ + while( mbedtls_mpi_cmp_mpi( &N, &grp->P ) >= 0 ) \ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &N, &N, &grp->P ) ) + +#if defined(ECP_SHORTWEIERSTRASS) +/* + * For curves in short Weierstrass form, we do all the internal operations in + * Jacobian coordinates. + * + * For multiplication, we'll use a comb method with coutermeasueres against + * SPA, hence timing attacks. + */ + +/* + * Normalize jacobian coordinates so that Z == 0 || Z == 1 (GECC 3.2.1) + * Cost: 1N := 1I + 3M + 1S + */ +static int ecp_normalize_jac( const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt ) +{ + int ret; + mbedtls_mpi Zi, ZZi; + + if( mbedtls_mpi_cmp_int( &pt->Z, 0 ) == 0 ) + return( 0 ); + +#if defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT) + if ( mbedtls_internal_ecp_grp_capable( grp ) ) + { + return mbedtls_internal_ecp_normalize_jac( grp, pt ); + } +#endif /* MBEDTLS_ECP_NORMALIZE_JAC_ALT */ + mbedtls_mpi_init( &Zi ); mbedtls_mpi_init( &ZZi ); + + /* + * X = X / Z^2 mod p + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &Zi, &pt->Z, &grp->P ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ZZi, &Zi, &Zi ) ); MOD_MUL( ZZi ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &pt->X, &pt->X, &ZZi ) ); MOD_MUL( pt->X ); + + /* + * Y = Y / Z^3 mod p + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &pt->Y, &pt->Y, &ZZi ) ); MOD_MUL( pt->Y ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &pt->Y, &pt->Y, &Zi ) ); MOD_MUL( pt->Y ); + + /* + * Z = 1 + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->Z, 1 ) ); + +cleanup: + + mbedtls_mpi_free( &Zi ); mbedtls_mpi_free( &ZZi ); + + return( ret ); +} + +/* + * Normalize jacobian coordinates of an array of (pointers to) points, + * using Montgomery's trick to perform only one inversion mod P. + * (See for example Cohen's "A Course in Computational Algebraic Number + * Theory", Algorithm 10.3.4.) + * + * Warning: fails (returning an error) if one of the points is zero! + * This should never happen, see choice of w in ecp_mul_comb(). + * + * Cost: 1N(t) := 1I + (6t - 3)M + 1S + */ +static int ecp_normalize_jac_many( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *T[], size_t t_len ) +{ + int ret; + size_t i; + mbedtls_mpi *c, u, Zi, ZZi; + + if( t_len < 2 ) + return( ecp_normalize_jac( grp, *T ) ); + +#if defined(MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT) + if ( mbedtls_internal_ecp_grp_capable( grp ) ) + { + return mbedtls_internal_ecp_normalize_jac_many(grp, T, t_len); + } +#endif + + if( ( c = mbedtls_calloc( t_len, sizeof( mbedtls_mpi ) ) ) == NULL ) + return( MBEDTLS_ERR_ECP_ALLOC_FAILED ); + + mbedtls_mpi_init( &u ); mbedtls_mpi_init( &Zi ); mbedtls_mpi_init( &ZZi ); + + /* + * c[i] = Z_0 * ... * Z_i + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &c[0], &T[0]->Z ) ); + for( i = 1; i < t_len; i++ ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &c[i], &c[i-1], &T[i]->Z ) ); + MOD_MUL( c[i] ); + } + + /* + * u = 1 / (Z_0 * ... * Z_n) mod P + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &u, &c[t_len-1], &grp->P ) ); + + for( i = t_len - 1; ; i-- ) + { + /* + * Zi = 1 / Z_i mod p + * u = 1 / (Z_0 * ... * Z_i) mod P + */ + if( i == 0 ) { + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Zi, &u ) ); + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &Zi, &u, &c[i-1] ) ); MOD_MUL( Zi ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &u, &u, &T[i]->Z ) ); MOD_MUL( u ); + } + + /* + * proceed as in normalize() + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ZZi, &Zi, &Zi ) ); MOD_MUL( ZZi ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T[i]->X, &T[i]->X, &ZZi ) ); MOD_MUL( T[i]->X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T[i]->Y, &T[i]->Y, &ZZi ) ); MOD_MUL( T[i]->Y ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T[i]->Y, &T[i]->Y, &Zi ) ); MOD_MUL( T[i]->Y ); + + /* + * Post-precessing: reclaim some memory by shrinking coordinates + * - not storing Z (always 1) + * - shrinking other coordinates, but still keeping the same number of + * limbs as P, as otherwise it will too likely be regrown too fast. + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_shrink( &T[i]->X, grp->P.n ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shrink( &T[i]->Y, grp->P.n ) ); + mbedtls_mpi_free( &T[i]->Z ); + + if( i == 0 ) + break; + } + +cleanup: + + mbedtls_mpi_free( &u ); mbedtls_mpi_free( &Zi ); mbedtls_mpi_free( &ZZi ); + for( i = 0; i < t_len; i++ ) + mbedtls_mpi_free( &c[i] ); + mbedtls_free( c ); + + return( ret ); +} + +/* + * Conditional point inversion: Q -> -Q = (Q.X, -Q.Y, Q.Z) without leak. + * "inv" must be 0 (don't invert) or 1 (invert) or the result will be invalid + */ +static int ecp_safe_invert_jac( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *Q, + unsigned char inv ) +{ + int ret; + unsigned char nonzero; + mbedtls_mpi mQY; + + mbedtls_mpi_init( &mQY ); + + /* Use the fact that -Q.Y mod P = P - Q.Y unless Q.Y == 0 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &mQY, &grp->P, &Q->Y ) ); + nonzero = mbedtls_mpi_cmp_int( &Q->Y, 0 ) != 0; + MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &Q->Y, &mQY, inv & nonzero ) ); + +cleanup: + mbedtls_mpi_free( &mQY ); + + return( ret ); +} + +/* + * Point doubling R = 2 P, Jacobian coordinates + * + * Based on http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-1998-cmo-2 . + * + * We follow the variable naming fairly closely. The formula variations that trade a MUL for a SQR + * (plus a few ADDs) aren't useful as our bignum implementation doesn't distinguish squaring. + * + * Standard optimizations are applied when curve parameter A is one of { 0, -3 }. + * + * Cost: 1D := 3M + 4S (A == 0) + * 4M + 4S (A == -3) + * 3M + 6S + 1a otherwise + */ +static int ecp_double_jac( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_ecp_point *P ) +{ + int ret; + mbedtls_mpi M, S, T, U; + +#if defined(MBEDTLS_SELF_TEST) + dbl_count++; +#endif + +#if defined(MBEDTLS_ECP_DOUBLE_JAC_ALT) + if ( mbedtls_internal_ecp_grp_capable( grp ) ) + { + return mbedtls_internal_ecp_double_jac( grp, R, P ); + } +#endif /* MBEDTLS_ECP_DOUBLE_JAC_ALT */ + + mbedtls_mpi_init( &M ); mbedtls_mpi_init( &S ); mbedtls_mpi_init( &T ); mbedtls_mpi_init( &U ); + + /* Special case for A = -3 */ + if( grp->A.p == NULL ) + { + /* M = 3(X + Z^2)(X - Z^2) */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S, &P->Z, &P->Z ) ); MOD_MUL( S ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &T, &P->X, &S ) ); MOD_ADD( T ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U, &P->X, &S ) ); MOD_SUB( U ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S, &T, &U ) ); MOD_MUL( S ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &M, &S, 3 ) ); MOD_ADD( M ); + } + else + { + /* M = 3.X^2 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S, &P->X, &P->X ) ); MOD_MUL( S ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &M, &S, 3 ) ); MOD_ADD( M ); + + /* Optimize away for "koblitz" curves with A = 0 */ + if( mbedtls_mpi_cmp_int( &grp->A, 0 ) != 0 ) + { + /* M += A.Z^4 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S, &P->Z, &P->Z ) ); MOD_MUL( S ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &S, &S ) ); MOD_MUL( T ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S, &T, &grp->A ) ); MOD_MUL( S ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &M, &M, &S ) ); MOD_ADD( M ); + } + } + + /* S = 4.X.Y^2 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &P->Y, &P->Y ) ); MOD_MUL( T ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &T, 1 ) ); MOD_ADD( T ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S, &P->X, &T ) ); MOD_MUL( S ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &S, 1 ) ); MOD_ADD( S ); + + /* U = 8.Y^4 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &U, &T, &T ) ); MOD_MUL( U ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &U, 1 ) ); MOD_ADD( U ); + + /* T = M^2 - 2.S */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &M, &M ) ); MOD_MUL( T ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T, &T, &S ) ); MOD_SUB( T ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T, &T, &S ) ); MOD_SUB( T ); + + /* S = M(S - T) - U */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &S, &S, &T ) ); MOD_SUB( S ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S, &S, &M ) ); MOD_MUL( S ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &S, &S, &U ) ); MOD_SUB( S ); + + /* U = 2.Y.Z */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &U, &P->Y, &P->Z ) ); MOD_MUL( U ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &U, 1 ) ); MOD_ADD( U ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R->X, &T ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R->Y, &S ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R->Z, &U ) ); + +cleanup: + mbedtls_mpi_free( &M ); mbedtls_mpi_free( &S ); mbedtls_mpi_free( &T ); mbedtls_mpi_free( &U ); + + return( ret ); +} + +/* + * Addition: R = P + Q, mixed affine-Jacobian coordinates (GECC 3.22) + * + * The coordinates of Q must be normalized (= affine), + * but those of P don't need to. R is not normalized. + * + * Special cases: (1) P or Q is zero, (2) R is zero, (3) P == Q. + * None of these cases can happen as intermediate step in ecp_mul_comb(): + * - at each step, P, Q and R are multiples of the base point, the factor + * being less than its order, so none of them is zero; + * - Q is an odd multiple of the base point, P an even multiple, + * due to the choice of precomputed points in the modified comb method. + * So branches for these cases do not leak secret information. + * + * We accept Q->Z being unset (saving memory in tables) as meaning 1. + * + * Cost: 1A := 8M + 3S + */ +static int ecp_add_mixed( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_ecp_point *P, const mbedtls_ecp_point *Q ) +{ + int ret; + mbedtls_mpi T1, T2, T3, T4, X, Y, Z; + +#if defined(MBEDTLS_SELF_TEST) + add_count++; +#endif + +#if defined(MBEDTLS_ECP_ADD_MIXED_ALT) + if ( mbedtls_internal_ecp_grp_capable( grp ) ) + { + return mbedtls_internal_ecp_add_mixed( grp, R, P, Q ); + } +#endif /* MBEDTLS_ECP_ADD_MIXED_ALT */ + + /* + * Trivial cases: P == 0 or Q == 0 (case 1) + */ + if( mbedtls_mpi_cmp_int( &P->Z, 0 ) == 0 ) + return( mbedtls_ecp_copy( R, Q ) ); + + if( Q->Z.p != NULL && mbedtls_mpi_cmp_int( &Q->Z, 0 ) == 0 ) + return( mbedtls_ecp_copy( R, P ) ); + + /* + * Make sure Q coordinates are normalized + */ + if( Q->Z.p != NULL && mbedtls_mpi_cmp_int( &Q->Z, 1 ) != 0 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + mbedtls_mpi_init( &T1 ); mbedtls_mpi_init( &T2 ); mbedtls_mpi_init( &T3 ); mbedtls_mpi_init( &T4 ); + mbedtls_mpi_init( &X ); mbedtls_mpi_init( &Y ); mbedtls_mpi_init( &Z ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T1, &P->Z, &P->Z ) ); MOD_MUL( T1 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T2, &T1, &P->Z ) ); MOD_MUL( T2 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T1, &T1, &Q->X ) ); MOD_MUL( T1 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T2, &T2, &Q->Y ) ); MOD_MUL( T2 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T1, &T1, &P->X ) ); MOD_SUB( T1 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T2, &T2, &P->Y ) ); MOD_SUB( T2 ); + + /* Special cases (2) and (3) */ + if( mbedtls_mpi_cmp_int( &T1, 0 ) == 0 ) + { + if( mbedtls_mpi_cmp_int( &T2, 0 ) == 0 ) + { + ret = ecp_double_jac( grp, R, P ); + goto cleanup; + } + else + { + ret = mbedtls_ecp_set_zero( R ); + goto cleanup; + } + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &Z, &P->Z, &T1 ) ); MOD_MUL( Z ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T3, &T1, &T1 ) ); MOD_MUL( T3 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T4, &T3, &T1 ) ); MOD_MUL( T4 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T3, &T3, &P->X ) ); MOD_MUL( T3 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T1, &T3, 2 ) ); MOD_ADD( T1 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &X, &T2, &T2 ) ); MOD_MUL( X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &T1 ) ); MOD_SUB( X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &T4 ) ); MOD_SUB( X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T3, &T3, &X ) ); MOD_SUB( T3 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T3, &T3, &T2 ) ); MOD_MUL( T3 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T4, &T4, &P->Y ) ); MOD_MUL( T4 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &Y, &T3, &T4 ) ); MOD_SUB( Y ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R->X, &X ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R->Y, &Y ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R->Z, &Z ) ); + +cleanup: + + mbedtls_mpi_free( &T1 ); mbedtls_mpi_free( &T2 ); mbedtls_mpi_free( &T3 ); mbedtls_mpi_free( &T4 ); + mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &Z ); + + return( ret ); +} + +/* + * Randomize jacobian coordinates: + * (X, Y, Z) -> (l^2 X, l^3 Y, l Z) for random l + * This is sort of the reverse operation of ecp_normalize_jac(). + * + * This countermeasure was first suggested in [2]. + */ +static int ecp_randomize_jac( const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret; + mbedtls_mpi l, ll; + size_t p_size; + int count = 0; + +#if defined(MBEDTLS_ECP_RANDOMIZE_JAC_ALT) + if ( mbedtls_internal_ecp_grp_capable( grp ) ) + { + return mbedtls_internal_ecp_randomize_jac( grp, pt, f_rng, p_rng ); + } +#endif /* MBEDTLS_ECP_RANDOMIZE_JAC_ALT */ + + p_size = ( grp->pbits + 7 ) / 8; + mbedtls_mpi_init( &l ); mbedtls_mpi_init( &ll ); + + /* Generate l such that 1 < l < p */ + do + { + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &l, p_size, f_rng, p_rng ) ); + + while( mbedtls_mpi_cmp_mpi( &l, &grp->P ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &l, 1 ) ); + + if( count++ > 10 ) + return( MBEDTLS_ERR_ECP_RANDOM_FAILED ); + } + while( mbedtls_mpi_cmp_int( &l, 1 ) <= 0 ); + + /* Z = l * Z */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &pt->Z, &pt->Z, &l ) ); MOD_MUL( pt->Z ); + + /* X = l^2 * X */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ll, &l, &l ) ); MOD_MUL( ll ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &pt->X, &pt->X, &ll ) ); MOD_MUL( pt->X ); + + /* Y = l^3 * Y */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ll, &ll, &l ) ); MOD_MUL( ll ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &pt->Y, &pt->Y, &ll ) ); MOD_MUL( pt->Y ); + +cleanup: + mbedtls_mpi_free( &l ); mbedtls_mpi_free( &ll ); + + return( ret ); +} + +/* + * Check and define parameters used by the comb method (see below for details) + */ +#if MBEDTLS_ECP_WINDOW_SIZE < 2 || MBEDTLS_ECP_WINDOW_SIZE > 7 +#error "MBEDTLS_ECP_WINDOW_SIZE out of bounds" +#endif + +/* d = ceil( n / w ) */ +#define COMB_MAX_D ( MBEDTLS_ECP_MAX_BITS + 1 ) / 2 + +/* number of precomputed points */ +#define COMB_MAX_PRE ( 1 << ( MBEDTLS_ECP_WINDOW_SIZE - 1 ) ) + +/* + * Compute the representation of m that will be used with our comb method. + * + * The basic comb method is described in GECC 3.44 for example. We use a + * modified version that provides resistance to SPA by avoiding zero + * digits in the representation as in [3]. We modify the method further by + * requiring that all K_i be odd, which has the small cost that our + * representation uses one more K_i, due to carries. + * + * Also, for the sake of compactness, only the seven low-order bits of x[i] + * are used to represent K_i, and the msb of x[i] encodes the the sign (s_i in + * the paper): it is set if and only if if s_i == -1; + * + * Calling conventions: + * - x is an array of size d + 1 + * - w is the size, ie number of teeth, of the comb, and must be between + * 2 and 7 (in practice, between 2 and MBEDTLS_ECP_WINDOW_SIZE) + * - m is the MPI, expected to be odd and such that bitlength(m) <= w * d + * (the result will be incorrect if these assumptions are not satisfied) + */ +static void ecp_comb_fixed( unsigned char x[], size_t d, + unsigned char w, const mbedtls_mpi *m ) +{ + size_t i, j; + unsigned char c, cc, adjust; + + memset( x, 0, d+1 ); + + /* First get the classical comb values (except for x_d = 0) */ + for( i = 0; i < d; i++ ) + for( j = 0; j < w; j++ ) + x[i] |= mbedtls_mpi_get_bit( m, i + d * j ) << j; + + /* Now make sure x_1 .. x_d are odd */ + c = 0; + for( i = 1; i <= d; i++ ) + { + /* Add carry and update it */ + cc = x[i] & c; + x[i] = x[i] ^ c; + c = cc; + + /* Adjust if needed, avoiding branches */ + adjust = 1 - ( x[i] & 0x01 ); + c |= x[i] & ( x[i-1] * adjust ); + x[i] = x[i] ^ ( x[i-1] * adjust ); + x[i-1] |= adjust << 7; + } +} + +/* + * Precompute points for the comb method + * + * If i = i_{w-1} ... i_1 is the binary representation of i, then + * T[i] = i_{w-1} 2^{(w-1)d} P + ... + i_1 2^d P + P + * + * T must be able to hold 2^{w - 1} elements + * + * Cost: d(w-1) D + (2^{w-1} - 1) A + 1 N(w-1) + 1 N(2^{w-1} - 1) + */ +static int ecp_precompute_comb( const mbedtls_ecp_group *grp, + mbedtls_ecp_point T[], const mbedtls_ecp_point *P, + unsigned char w, size_t d ) +{ + int ret; + unsigned char i, k; + size_t j; + mbedtls_ecp_point *cur, *TT[COMB_MAX_PRE - 1]; + + /* + * Set T[0] = P and + * T[2^{l-1}] = 2^{dl} P for l = 1 .. w-1 (this is not the final value) + */ + MBEDTLS_MPI_CHK( mbedtls_ecp_copy( &T[0], P ) ); + + k = 0; + for( i = 1; i < ( 1U << ( w - 1 ) ); i <<= 1 ) + { + cur = T + i; + MBEDTLS_MPI_CHK( mbedtls_ecp_copy( cur, T + ( i >> 1 ) ) ); + for( j = 0; j < d; j++ ) + MBEDTLS_MPI_CHK( ecp_double_jac( grp, cur, cur ) ); + + TT[k++] = cur; + } + + MBEDTLS_MPI_CHK( ecp_normalize_jac_many( grp, TT, k ) ); + + /* + * Compute the remaining ones using the minimal number of additions + * Be careful to update T[2^l] only after using it! + */ + k = 0; + for( i = 1; i < ( 1U << ( w - 1 ) ); i <<= 1 ) + { + j = i; + while( j-- ) + { + MBEDTLS_MPI_CHK( ecp_add_mixed( grp, &T[i + j], &T[j], &T[i] ) ); + TT[k++] = &T[i + j]; + } + } + + MBEDTLS_MPI_CHK( ecp_normalize_jac_many( grp, TT, k ) ); + +cleanup: + + return( ret ); +} + +/* + * Select precomputed point: R = sign(i) * T[ abs(i) / 2 ] + */ +static int ecp_select_comb( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_ecp_point T[], unsigned char t_len, + unsigned char i ) +{ + int ret; + unsigned char ii, j; + + /* Ignore the "sign" bit and scale down */ + ii = ( i & 0x7Fu ) >> 1; + + /* Read the whole table to thwart cache-based timing attacks */ + for( j = 0; j < t_len; j++ ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &R->X, &T[j].X, j == ii ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &R->Y, &T[j].Y, j == ii ) ); + } + + /* Safely invert result if i is "negative" */ + MBEDTLS_MPI_CHK( ecp_safe_invert_jac( grp, R, i >> 7 ) ); + +cleanup: + return( ret ); +} + +/* + * Core multiplication algorithm for the (modified) comb method. + * This part is actually common with the basic comb method (GECC 3.44) + * + * Cost: d A + d D + 1 R + */ +static int ecp_mul_comb_core( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_ecp_point T[], unsigned char t_len, + const unsigned char x[], size_t d, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + mbedtls_ecp_point Txi; + size_t i; + + mbedtls_ecp_point_init( &Txi ); + + /* Start with a non-zero point and randomize its coordinates */ + i = d; + MBEDTLS_MPI_CHK( ecp_select_comb( grp, R, T, t_len, x[i] ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &R->Z, 1 ) ); + if( f_rng != 0 ) + MBEDTLS_MPI_CHK( ecp_randomize_jac( grp, R, f_rng, p_rng ) ); + + while( i-- != 0 ) + { + MBEDTLS_MPI_CHK( ecp_double_jac( grp, R, R ) ); + MBEDTLS_MPI_CHK( ecp_select_comb( grp, &Txi, T, t_len, x[i] ) ); + MBEDTLS_MPI_CHK( ecp_add_mixed( grp, R, R, &Txi ) ); + } + +cleanup: + + mbedtls_ecp_point_free( &Txi ); + + return( ret ); +} + +/* + * Multiplication using the comb method, + * for curves in short Weierstrass form + */ +static int ecp_mul_comb( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + unsigned char w, m_is_odd, p_eq_g, pre_len, i; + size_t d; + unsigned char k[COMB_MAX_D + 1]; + mbedtls_ecp_point *T; + mbedtls_mpi M, mm; + + mbedtls_mpi_init( &M ); + mbedtls_mpi_init( &mm ); + + /* we need N to be odd to trnaform m in an odd number, check now */ + if( mbedtls_mpi_get_bit( &grp->N, 0 ) != 1 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * Minimize the number of multiplications, that is minimize + * 10 * d * w + 18 * 2^(w-1) + 11 * d + 7 * w, with d = ceil( nbits / w ) + * (see costs of the various parts, with 1S = 1M) + */ + w = grp->nbits >= 384 ? 5 : 4; + + /* + * If P == G, pre-compute a bit more, since this may be re-used later. + * Just adding one avoids upping the cost of the first mul too much, + * and the memory cost too. + */ +#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1 + p_eq_g = ( mbedtls_mpi_cmp_mpi( &P->Y, &grp->G.Y ) == 0 && + mbedtls_mpi_cmp_mpi( &P->X, &grp->G.X ) == 0 ); + if( p_eq_g ) + w++; +#else + p_eq_g = 0; +#endif + + /* + * Make sure w is within bounds. + * (The last test is useful only for very small curves in the test suite.) + */ + if( w > MBEDTLS_ECP_WINDOW_SIZE ) + w = MBEDTLS_ECP_WINDOW_SIZE; + if( w >= grp->nbits ) + w = 2; + + /* Other sizes that depend on w */ + pre_len = 1U << ( w - 1 ); + d = ( grp->nbits + w - 1 ) / w; + + /* + * Prepare precomputed points: if P == G we want to + * use grp->T if already initialized, or initialize it. + */ + T = p_eq_g ? grp->T : NULL; + + if( T == NULL ) + { + T = mbedtls_calloc( pre_len, sizeof( mbedtls_ecp_point ) ); + if( T == NULL ) + { + ret = MBEDTLS_ERR_ECP_ALLOC_FAILED; + goto cleanup; + } + + MBEDTLS_MPI_CHK( ecp_precompute_comb( grp, T, P, w, d ) ); + + if( p_eq_g ) + { + grp->T = T; + grp->T_size = pre_len; + } + } + + /* + * Make sure M is odd (M = m or M = N - m, since N is odd) + * using the fact that m * P = - (N - m) * P + */ + m_is_odd = ( mbedtls_mpi_get_bit( m, 0 ) == 1 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &M, m ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &mm, &grp->N, m ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &M, &mm, ! m_is_odd ) ); + + /* + * Go for comb multiplication, R = M * P + */ + ecp_comb_fixed( k, d, w, &M ); + MBEDTLS_MPI_CHK( ecp_mul_comb_core( grp, R, T, pre_len, k, d, f_rng, p_rng ) ); + + /* + * Now get m * P from M * P and normalize it + */ + MBEDTLS_MPI_CHK( ecp_safe_invert_jac( grp, R, ! m_is_odd ) ); + MBEDTLS_MPI_CHK( ecp_normalize_jac( grp, R ) ); + +cleanup: + + /* There are two cases where T is not stored in grp: + * - P != G + * - An intermediate operation failed before setting grp->T + * In either case, T must be freed. + */ + if( T != NULL && T != grp->T ) + { + for( i = 0; i < pre_len; i++ ) + mbedtls_ecp_point_free( &T[i] ); + mbedtls_free( T ); + } + + mbedtls_mpi_free( &M ); + mbedtls_mpi_free( &mm ); + + if( ret != 0 ) + mbedtls_ecp_point_free( R ); + + return( ret ); +} + +#endif /* ECP_SHORTWEIERSTRASS */ + +#if defined(ECP_MONTGOMERY) +/* + * For Montgomery curves, we do all the internal arithmetic in projective + * coordinates. Import/export of points uses only the x coordinates, which is + * internaly represented as X / Z. + * + * For scalar multiplication, we'll use a Montgomery ladder. + */ + +/* + * Normalize Montgomery x/z coordinates: X = X/Z, Z = 1 + * Cost: 1M + 1I + */ +static int ecp_normalize_mxz( const mbedtls_ecp_group *grp, mbedtls_ecp_point *P ) +{ + int ret; + +#if defined(MBEDTLS_ECP_NORMALIZE_MXZ_ALT) + if ( mbedtls_internal_ecp_grp_capable( grp ) ) + { + return mbedtls_internal_ecp_normalize_mxz( grp, P ); + } +#endif /* MBEDTLS_ECP_NORMALIZE_MXZ_ALT */ + + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &P->Z, &P->Z, &grp->P ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &P->X, &P->X, &P->Z ) ); MOD_MUL( P->X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &P->Z, 1 ) ); + +cleanup: + return( ret ); +} + +/* + * Randomize projective x/z coordinates: + * (X, Z) -> (l X, l Z) for random l + * This is sort of the reverse operation of ecp_normalize_mxz(). + * + * This countermeasure was first suggested in [2]. + * Cost: 2M + */ +static int ecp_randomize_mxz( const mbedtls_ecp_group *grp, mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret; + mbedtls_mpi l; + size_t p_size; + int count = 0; + +#if defined(MBEDTLS_ECP_RANDOMIZE_MXZ_ALT) + if ( mbedtls_internal_ecp_grp_capable( grp ) ) + { + return mbedtls_internal_ecp_randomize_mxz( grp, P, f_rng, p_rng ); + } +#endif /* MBEDTLS_ECP_RANDOMIZE_MXZ_ALT */ + + p_size = ( grp->pbits + 7 ) / 8; + mbedtls_mpi_init( &l ); + + /* Generate l such that 1 < l < p */ + do + { + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &l, p_size, f_rng, p_rng ) ); + + while( mbedtls_mpi_cmp_mpi( &l, &grp->P ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &l, 1 ) ); + + if( count++ > 10 ) + return( MBEDTLS_ERR_ECP_RANDOM_FAILED ); + } + while( mbedtls_mpi_cmp_int( &l, 1 ) <= 0 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &P->X, &P->X, &l ) ); MOD_MUL( P->X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &P->Z, &P->Z, &l ) ); MOD_MUL( P->Z ); + +cleanup: + mbedtls_mpi_free( &l ); + + return( ret ); +} + +/* + * Double-and-add: R = 2P, S = P + Q, with d = X(P - Q), + * for Montgomery curves in x/z coordinates. + * + * http://www.hyperelliptic.org/EFD/g1p/auto-code/montgom/xz/ladder/mladd-1987-m.op3 + * with + * d = X1 + * P = (X2, Z2) + * Q = (X3, Z3) + * R = (X4, Z4) + * S = (X5, Z5) + * and eliminating temporary variables tO, ..., t4. + * + * Cost: 5M + 4S + */ +static int ecp_double_add_mxz( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *R, mbedtls_ecp_point *S, + const mbedtls_ecp_point *P, const mbedtls_ecp_point *Q, + const mbedtls_mpi *d ) +{ + int ret; + mbedtls_mpi A, AA, B, BB, E, C, D, DA, CB; + +#if defined(MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT) + if ( mbedtls_internal_ecp_grp_capable( grp ) ) + { + return mbedtls_internal_ecp_double_add_mxz( grp, R, S, P, Q, d ); + } +#endif /* MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT */ + + mbedtls_mpi_init( &A ); mbedtls_mpi_init( &AA ); mbedtls_mpi_init( &B ); + mbedtls_mpi_init( &BB ); mbedtls_mpi_init( &E ); mbedtls_mpi_init( &C ); + mbedtls_mpi_init( &D ); mbedtls_mpi_init( &DA ); mbedtls_mpi_init( &CB ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &A, &P->X, &P->Z ) ); MOD_ADD( A ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &AA, &A, &A ) ); MOD_MUL( AA ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &B, &P->X, &P->Z ) ); MOD_SUB( B ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &BB, &B, &B ) ); MOD_MUL( BB ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &E, &AA, &BB ) ); MOD_SUB( E ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &C, &Q->X, &Q->Z ) ); MOD_ADD( C ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &D, &Q->X, &Q->Z ) ); MOD_SUB( D ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &DA, &D, &A ) ); MOD_MUL( DA ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &CB, &C, &B ) ); MOD_MUL( CB ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &S->X, &DA, &CB ) ); MOD_MUL( S->X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S->X, &S->X, &S->X ) ); MOD_MUL( S->X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &S->Z, &DA, &CB ) ); MOD_SUB( S->Z ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S->Z, &S->Z, &S->Z ) ); MOD_MUL( S->Z ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S->Z, d, &S->Z ) ); MOD_MUL( S->Z ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &R->X, &AA, &BB ) ); MOD_MUL( R->X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &R->Z, &grp->A, &E ) ); MOD_MUL( R->Z ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &R->Z, &BB, &R->Z ) ); MOD_ADD( R->Z ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &R->Z, &E, &R->Z ) ); MOD_MUL( R->Z ); + +cleanup: + mbedtls_mpi_free( &A ); mbedtls_mpi_free( &AA ); mbedtls_mpi_free( &B ); + mbedtls_mpi_free( &BB ); mbedtls_mpi_free( &E ); mbedtls_mpi_free( &C ); + mbedtls_mpi_free( &D ); mbedtls_mpi_free( &DA ); mbedtls_mpi_free( &CB ); + + return( ret ); +} + +/* + * Multiplication with Montgomery ladder in x/z coordinates, + * for curves in Montgomery form + */ +static int ecp_mul_mxz( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + size_t i; + unsigned char b; + mbedtls_ecp_point RP; + mbedtls_mpi PX; + + mbedtls_ecp_point_init( &RP ); mbedtls_mpi_init( &PX ); + + /* Save PX and read from P before writing to R, in case P == R */ + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &PX, &P->X ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_copy( &RP, P ) ); + + /* Set R to zero in modified x/z coordinates */ + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &R->X, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &R->Z, 0 ) ); + mbedtls_mpi_free( &R->Y ); + + /* RP.X might be sligtly larger than P, so reduce it */ + MOD_ADD( RP.X ); + + /* Randomize coordinates of the starting point */ + if( f_rng != NULL ) + MBEDTLS_MPI_CHK( ecp_randomize_mxz( grp, &RP, f_rng, p_rng ) ); + + /* Loop invariant: R = result so far, RP = R + P */ + i = mbedtls_mpi_bitlen( m ); /* one past the (zero-based) most significant bit */ + while( i-- > 0 ) + { + b = mbedtls_mpi_get_bit( m, i ); + /* + * if (b) R = 2R + P else R = 2R, + * which is: + * if (b) double_add( RP, R, RP, R ) + * else double_add( R, RP, R, RP ) + * but using safe conditional swaps to avoid leaks + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_swap( &R->X, &RP.X, b ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_swap( &R->Z, &RP.Z, b ) ); + MBEDTLS_MPI_CHK( ecp_double_add_mxz( grp, R, &RP, R, &RP, &PX ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_swap( &R->X, &RP.X, b ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_swap( &R->Z, &RP.Z, b ) ); + } + + MBEDTLS_MPI_CHK( ecp_normalize_mxz( grp, R ) ); + +cleanup: + mbedtls_ecp_point_free( &RP ); mbedtls_mpi_free( &PX ); + + return( ret ); +} + +#endif /* ECP_MONTGOMERY */ + +/* + * Multiplication R = m * P + */ +int mbedtls_ecp_mul( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; +#if defined(MBEDTLS_ECP_INTERNAL_ALT) + char is_grp_capable = 0; +#endif + + /* Common sanity checks */ + if( mbedtls_mpi_cmp_int( &P->Z, 1 ) != 0 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_ecp_check_privkey( grp, m ) ) != 0 || + ( ret = mbedtls_ecp_check_pubkey( grp, P ) ) != 0 ) + return( ret ); + +#if defined(MBEDTLS_ECP_INTERNAL_ALT) + if ( is_grp_capable = mbedtls_internal_ecp_grp_capable( grp ) ) + { + MBEDTLS_MPI_CHK( mbedtls_internal_ecp_init( grp ) ); + } + +#endif /* MBEDTLS_ECP_INTERNAL_ALT */ +#if defined(ECP_MONTGOMERY) + if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY ) + ret = ecp_mul_mxz( grp, R, m, P, f_rng, p_rng ); + +#endif +#if defined(ECP_SHORTWEIERSTRASS) + if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS ) + ret = ecp_mul_comb( grp, R, m, P, f_rng, p_rng ); + +#endif +#if defined(MBEDTLS_ECP_INTERNAL_ALT) +cleanup: + + if ( is_grp_capable ) + { + mbedtls_internal_ecp_free( grp ); + } + +#endif /* MBEDTLS_ECP_INTERNAL_ALT */ + return( ret ); +} + +#if defined(ECP_SHORTWEIERSTRASS) +/* + * Check that an affine point is valid as a public key, + * short weierstrass curves (SEC1 3.2.3.1) + */ +static int ecp_check_pubkey_sw( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt ) +{ + int ret; + mbedtls_mpi YY, RHS; + + /* pt coordinates must be normalized for our checks */ + if( mbedtls_mpi_cmp_int( &pt->X, 0 ) < 0 || + mbedtls_mpi_cmp_int( &pt->Y, 0 ) < 0 || + mbedtls_mpi_cmp_mpi( &pt->X, &grp->P ) >= 0 || + mbedtls_mpi_cmp_mpi( &pt->Y, &grp->P ) >= 0 ) + return( MBEDTLS_ERR_ECP_INVALID_KEY ); + + mbedtls_mpi_init( &YY ); mbedtls_mpi_init( &RHS ); + + /* + * YY = Y^2 + * RHS = X (X^2 + A) + B = X^3 + A X + B + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &YY, &pt->Y, &pt->Y ) ); MOD_MUL( YY ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &RHS, &pt->X, &pt->X ) ); MOD_MUL( RHS ); + + /* Special case for A = -3 */ + if( grp->A.p == NULL ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &RHS, &RHS, 3 ) ); MOD_SUB( RHS ); + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &RHS, &RHS, &grp->A ) ); MOD_ADD( RHS ); + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &RHS, &RHS, &pt->X ) ); MOD_MUL( RHS ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &RHS, &RHS, &grp->B ) ); MOD_ADD( RHS ); + + if( mbedtls_mpi_cmp_mpi( &YY, &RHS ) != 0 ) + ret = MBEDTLS_ERR_ECP_INVALID_KEY; + +cleanup: + + mbedtls_mpi_free( &YY ); mbedtls_mpi_free( &RHS ); + + return( ret ); +} +#endif /* ECP_SHORTWEIERSTRASS */ + +/* + * R = m * P with shortcuts for m == 1 and m == -1 + * NOT constant-time - ONLY for short Weierstrass! + */ +static int mbedtls_ecp_mul_shortcuts( mbedtls_ecp_group *grp, + mbedtls_ecp_point *R, + const mbedtls_mpi *m, + const mbedtls_ecp_point *P ) +{ + int ret; + + if( mbedtls_mpi_cmp_int( m, 1 ) == 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_ecp_copy( R, P ) ); + } + else if( mbedtls_mpi_cmp_int( m, -1 ) == 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_ecp_copy( R, P ) ); + if( mbedtls_mpi_cmp_int( &R->Y, 0 ) != 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &R->Y, &grp->P, &R->Y ) ); + } + else + { + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( grp, R, m, P, NULL, NULL ) ); + } + +cleanup: + return( ret ); +} + +/* + * Linear combination + * NOT constant-time + */ +int mbedtls_ecp_muladd( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + const mbedtls_mpi *n, const mbedtls_ecp_point *Q ) +{ + int ret; + mbedtls_ecp_point mP; +#if defined(MBEDTLS_ECP_INTERNAL_ALT) + char is_grp_capable = 0; +#endif + + if( ecp_get_type( grp ) != ECP_TYPE_SHORT_WEIERSTRASS ) + return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); + + mbedtls_ecp_point_init( &mP ); + + MBEDTLS_MPI_CHK( mbedtls_ecp_mul_shortcuts( grp, &mP, m, P ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul_shortcuts( grp, R, n, Q ) ); + +#if defined(MBEDTLS_ECP_INTERNAL_ALT) + if ( is_grp_capable = mbedtls_internal_ecp_grp_capable( grp ) ) + { + MBEDTLS_MPI_CHK( mbedtls_internal_ecp_init( grp ) ); + } + +#endif /* MBEDTLS_ECP_INTERNAL_ALT */ + MBEDTLS_MPI_CHK( ecp_add_mixed( grp, R, &mP, R ) ); + MBEDTLS_MPI_CHK( ecp_normalize_jac( grp, R ) ); + +cleanup: + +#if defined(MBEDTLS_ECP_INTERNAL_ALT) + if ( is_grp_capable ) + { + mbedtls_internal_ecp_free( grp ); + } + +#endif /* MBEDTLS_ECP_INTERNAL_ALT */ + mbedtls_ecp_point_free( &mP ); + + return( ret ); +} + + +#if defined(ECP_MONTGOMERY) +/* + * Check validity of a public key for Montgomery curves with x-only schemes + */ +static int ecp_check_pubkey_mx( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt ) +{ + /* [Curve25519 p. 5] Just check X is the correct number of bytes */ + /* Allow any public value, if it's too big then we'll just reduce it mod p + * (RFC 7748 sec. 5 para. 3). */ + if( mbedtls_mpi_size( &pt->X ) > ( grp->nbits + 7 ) / 8 ) + return( MBEDTLS_ERR_ECP_INVALID_KEY ); + + return( 0 ); +} +#endif /* ECP_MONTGOMERY */ + +/* + * Check that a point is valid as a public key + */ +int mbedtls_ecp_check_pubkey( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt ) +{ + /* Must use affine coordinates */ + if( mbedtls_mpi_cmp_int( &pt->Z, 1 ) != 0 ) + return( MBEDTLS_ERR_ECP_INVALID_KEY ); + +#if defined(ECP_MONTGOMERY) + if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY ) + return( ecp_check_pubkey_mx( grp, pt ) ); +#endif +#if defined(ECP_SHORTWEIERSTRASS) + if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS ) + return( ecp_check_pubkey_sw( grp, pt ) ); +#endif + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); +} + +/* + * Check that an mbedtls_mpi is valid as a private key + */ +int mbedtls_ecp_check_privkey( const mbedtls_ecp_group *grp, const mbedtls_mpi *d ) +{ +#if defined(ECP_MONTGOMERY) + if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY ) + { + /* see RFC 7748 sec. 5 para. 5 */ + if( mbedtls_mpi_get_bit( d, 0 ) != 0 || + mbedtls_mpi_get_bit( d, 1 ) != 0 || + mbedtls_mpi_bitlen( d ) - 1 != grp->nbits ) /* mbedtls_mpi_bitlen is one-based! */ + return( MBEDTLS_ERR_ECP_INVALID_KEY ); + + /* see [Curve25519] page 5 */ + if( grp->nbits == 254 && mbedtls_mpi_get_bit( d, 2 ) != 0 ) + return( MBEDTLS_ERR_ECP_INVALID_KEY ); + + return( 0 ); + } +#endif /* ECP_MONTGOMERY */ +#if defined(ECP_SHORTWEIERSTRASS) + if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS ) + { + /* see SEC1 3.2 */ + if( mbedtls_mpi_cmp_int( d, 1 ) < 0 || + mbedtls_mpi_cmp_mpi( d, &grp->N ) >= 0 ) + return( MBEDTLS_ERR_ECP_INVALID_KEY ); + else + return( 0 ); + } +#endif /* ECP_SHORTWEIERSTRASS */ + + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); +} + +/* + * Generate a keypair with configurable base point + */ +int mbedtls_ecp_gen_keypair_base( mbedtls_ecp_group *grp, + const mbedtls_ecp_point *G, + mbedtls_mpi *d, mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + size_t n_size = ( grp->nbits + 7 ) / 8; + +#if defined(ECP_MONTGOMERY) + if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY ) + { + /* [M225] page 5 */ + size_t b; + + do { + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( d, n_size, f_rng, p_rng ) ); + } while( mbedtls_mpi_bitlen( d ) == 0); + + /* Make sure the most significant bit is nbits */ + b = mbedtls_mpi_bitlen( d ) - 1; /* mbedtls_mpi_bitlen is one-based */ + if( b > grp->nbits ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( d, b - grp->nbits ) ); + else + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, grp->nbits, 1 ) ); + + /* Make sure the last two bits are unset for Curve448, three bits for + Curve25519 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, 0, 0 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, 1, 0 ) ); + if( grp->nbits == 254 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, 2, 0 ) ); + } + } + else +#endif /* ECP_MONTGOMERY */ +#if defined(ECP_SHORTWEIERSTRASS) + if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS ) + { + /* SEC1 3.2.1: Generate d such that 1 <= n < N */ + int count = 0; + + /* + * Match the procedure given in RFC 6979 (deterministic ECDSA): + * - use the same byte ordering; + * - keep the leftmost nbits bits of the generated octet string; + * - try until result is in the desired range. + * This also avoids any biais, which is especially important for ECDSA. + */ + do + { + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( d, n_size, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( d, 8 * n_size - grp->nbits ) ); + + /* + * Each try has at worst a probability 1/2 of failing (the msb has + * a probability 1/2 of being 0, and then the result will be < N), + * so after 30 tries failure probability is a most 2**(-30). + * + * For most curves, 1 try is enough with overwhelming probability, + * since N starts with a lot of 1s in binary, but some curves + * such as secp224k1 are actually very close to the worst case. + */ + if( ++count > 30 ) + return( MBEDTLS_ERR_ECP_RANDOM_FAILED ); + } + while( mbedtls_mpi_cmp_int( d, 1 ) < 0 || + mbedtls_mpi_cmp_mpi( d, &grp->N ) >= 0 ); + } + else +#endif /* ECP_SHORTWEIERSTRASS */ + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + +cleanup: + if( ret != 0 ) + return( ret ); + + return( mbedtls_ecp_mul( grp, Q, d, G, f_rng, p_rng ) ); +} + +/* + * Generate key pair, wrapper for conventional base point + */ +int mbedtls_ecp_gen_keypair( mbedtls_ecp_group *grp, + mbedtls_mpi *d, mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + return( mbedtls_ecp_gen_keypair_base( grp, &grp->G, d, Q, f_rng, p_rng ) ); +} + +/* + * Generate a keypair, prettier wrapper + */ +int mbedtls_ecp_gen_key( mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret; + + if( ( ret = mbedtls_ecp_group_load( &key->grp, grp_id ) ) != 0 ) + return( ret ); + + return( mbedtls_ecp_gen_keypair( &key->grp, &key->d, &key->Q, f_rng, p_rng ) ); +} + +/* + * Check a public-private key pair + */ +int mbedtls_ecp_check_pub_priv( const mbedtls_ecp_keypair *pub, const mbedtls_ecp_keypair *prv ) +{ + int ret; + mbedtls_ecp_point Q; + mbedtls_ecp_group grp; + + if( pub->grp.id == MBEDTLS_ECP_DP_NONE || + pub->grp.id != prv->grp.id || + mbedtls_mpi_cmp_mpi( &pub->Q.X, &prv->Q.X ) || + mbedtls_mpi_cmp_mpi( &pub->Q.Y, &prv->Q.Y ) || + mbedtls_mpi_cmp_mpi( &pub->Q.Z, &prv->Q.Z ) ) + { + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + } + + mbedtls_ecp_point_init( &Q ); + mbedtls_ecp_group_init( &grp ); + + /* mbedtls_ecp_mul() needs a non-const group... */ + mbedtls_ecp_group_copy( &grp, &prv->grp ); + + /* Also checks d is valid */ + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &grp, &Q, &prv->d, &prv->grp.G, NULL, NULL ) ); + + if( mbedtls_mpi_cmp_mpi( &Q.X, &prv->Q.X ) || + mbedtls_mpi_cmp_mpi( &Q.Y, &prv->Q.Y ) || + mbedtls_mpi_cmp_mpi( &Q.Z, &prv->Q.Z ) ) + { + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + +cleanup: + mbedtls_ecp_point_free( &Q ); + mbedtls_ecp_group_free( &grp ); + + return( ret ); +} + +#if defined(MBEDTLS_SELF_TEST) + +/* + * Checkup routine + */ +int mbedtls_ecp_self_test( int verbose ) +{ + int ret; + size_t i; + mbedtls_ecp_group grp; + mbedtls_ecp_point R, P; + mbedtls_mpi m; + unsigned long add_c_prev, dbl_c_prev, mul_c_prev; + /* exponents especially adapted for secp192r1 */ + const char *exponents[] = + { + "000000000000000000000000000000000000000000000001", /* one */ + "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22830", /* N - 1 */ + "5EA6F389A38B8BC81E767753B15AA5569E1782E30ABE7D25", /* random */ + "400000000000000000000000000000000000000000000000", /* one and zeros */ + "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", /* all ones */ + "555555555555555555555555555555555555555555555555", /* 101010... */ + }; + + mbedtls_ecp_group_init( &grp ); + mbedtls_ecp_point_init( &R ); + mbedtls_ecp_point_init( &P ); + mbedtls_mpi_init( &m ); + + /* Use secp192r1 if available, or any available curve */ +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) + MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &grp, MBEDTLS_ECP_DP_SECP192R1 ) ); +#else + MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &grp, mbedtls_ecp_curve_list()->grp_id ) ); +#endif + + if( verbose != 0 ) + mbedtls_printf( " ECP test #1 (constant op_count, base point G): " ); + + /* Do a dummy multiplication first to trigger precomputation */ + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &m, 2 ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &grp, &P, &m, &grp.G, NULL, NULL ) ); + + add_count = 0; + dbl_count = 0; + mul_count = 0; + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &m, 16, exponents[0] ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &grp, &R, &m, &grp.G, NULL, NULL ) ); + + for( i = 1; i < sizeof( exponents ) / sizeof( exponents[0] ); i++ ) + { + add_c_prev = add_count; + dbl_c_prev = dbl_count; + mul_c_prev = mul_count; + add_count = 0; + dbl_count = 0; + mul_count = 0; + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &m, 16, exponents[i] ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &grp, &R, &m, &grp.G, NULL, NULL ) ); + + if( add_count != add_c_prev || + dbl_count != dbl_c_prev || + mul_count != mul_c_prev ) + { + if( verbose != 0 ) + mbedtls_printf( "failed (%u)\n", (unsigned int) i ); + + ret = 1; + goto cleanup; + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " ECP test #2 (constant op_count, other point): " ); + /* We computed P = 2G last time, use it */ + + add_count = 0; + dbl_count = 0; + mul_count = 0; + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &m, 16, exponents[0] ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &grp, &R, &m, &P, NULL, NULL ) ); + + for( i = 1; i < sizeof( exponents ) / sizeof( exponents[0] ); i++ ) + { + add_c_prev = add_count; + dbl_c_prev = dbl_count; + mul_c_prev = mul_count; + add_count = 0; + dbl_count = 0; + mul_count = 0; + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &m, 16, exponents[i] ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &grp, &R, &m, &P, NULL, NULL ) ); + + if( add_count != add_c_prev || + dbl_count != dbl_c_prev || + mul_count != mul_c_prev ) + { + if( verbose != 0 ) + mbedtls_printf( "failed (%u)\n", (unsigned int) i ); + + ret = 1; + goto cleanup; + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + +cleanup: + + if( ret < 0 && verbose != 0 ) + mbedtls_printf( "Unexpected error, return code = %08X\n", ret ); + + mbedtls_ecp_group_free( &grp ); + mbedtls_ecp_point_free( &R ); + mbedtls_ecp_point_free( &P ); + mbedtls_mpi_free( &m ); + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* !MBEDTLS_ECP_ALT */ + +#endif /* MBEDTLS_ECP_C */ diff --git a/common/mbedtls/ecp.h b/common/mbedtls/ecp.h new file mode 100644 index 00000000..1821a72f --- /dev/null +++ b/common/mbedtls/ecp.h @@ -0,0 +1,766 @@ +/** + * \file ecp.h + * + * \brief This file provides an API for Elliptic Curves over GF(P) (ECP). + * + * The use of ECP in cryptography and TLS is defined in + * Standards for Efficient Cryptography Group (SECG): SEC1 + * Elliptic Curve Cryptography and + * RFC-4492: Elliptic Curve Cryptography (ECC) Cipher Suites + * for Transport Layer Security (TLS). + * + * RFC-2409: The Internet Key Exchange (IKE) defines ECP + * group types. + * + */ + +/* + * Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_ECP_H +#define MBEDTLS_ECP_H + +#include "bignum.h" + +/* + * ECP error codes + */ +#define MBEDTLS_ERR_ECP_BAD_INPUT_DATA -0x4F80 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL -0x4F00 /**< The buffer is too small to write to. */ +#define MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE -0x4E80 /**< The requested feature is not available, for example, the requested curve is not supported. */ +#define MBEDTLS_ERR_ECP_VERIFY_FAILED -0x4E00 /**< The signature is not valid. */ +#define MBEDTLS_ERR_ECP_ALLOC_FAILED -0x4D80 /**< Memory allocation failed. */ +#define MBEDTLS_ERR_ECP_RANDOM_FAILED -0x4D00 /**< Generation of random value, such as ephemeral key, failed. */ +#define MBEDTLS_ERR_ECP_INVALID_KEY -0x4C80 /**< Invalid private or public key. */ +#define MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH -0x4C00 /**< The buffer contains a valid signature followed by more data. */ +#define MBEDTLS_ERR_ECP_HW_ACCEL_FAILED -0x4B80 /**< The ECP hardware accelerator failed. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Domain-parameter identifiers: curve, subgroup, and generator. + * + * \note Only curves over prime fields are supported. + * + * \warning This library does not support validation of arbitrary domain + * parameters. Therefore, only standardized domain parameters from trusted + * sources should be used. See mbedtls_ecp_group_load(). + */ +typedef enum +{ + MBEDTLS_ECP_DP_NONE = 0, /*!< Curve not defined. */ + MBEDTLS_ECP_DP_SECP192R1, /*!< Domain parameters for the 192-bit curve defined by FIPS 186-4 and SEC1. */ + MBEDTLS_ECP_DP_SECP224R1, /*!< Domain parameters for the 224-bit curve defined by FIPS 186-4 and SEC1. */ + MBEDTLS_ECP_DP_SECP256R1, /*!< Domain parameters for the 256-bit curve defined by FIPS 186-4 and SEC1. */ + MBEDTLS_ECP_DP_SECP384R1, /*!< Domain parameters for the 384-bit curve defined by FIPS 186-4 and SEC1. */ + MBEDTLS_ECP_DP_SECP521R1, /*!< Domain parameters for the 521-bit curve defined by FIPS 186-4 and SEC1. */ + MBEDTLS_ECP_DP_BP256R1, /*!< Domain parameters for 256-bit Brainpool curve. */ + MBEDTLS_ECP_DP_BP384R1, /*!< Domain parameters for 384-bit Brainpool curve. */ + MBEDTLS_ECP_DP_BP512R1, /*!< Domain parameters for 512-bit Brainpool curve. */ + MBEDTLS_ECP_DP_CURVE25519, /*!< Domain parameters for Curve25519. */ + MBEDTLS_ECP_DP_SECP192K1, /*!< Domain parameters for 192-bit "Koblitz" curve. */ + MBEDTLS_ECP_DP_SECP224K1, /*!< Domain parameters for 224-bit "Koblitz" curve. */ + MBEDTLS_ECP_DP_SECP256K1, /*!< Domain parameters for 256-bit "Koblitz" curve. */ + MBEDTLS_ECP_DP_CURVE448, /*!< Domain parameters for Curve448. */ +} mbedtls_ecp_group_id; + +/** + * The number of supported curves, plus one for #MBEDTLS_ECP_DP_NONE. + * + * \note Montgomery curves are currently excluded. + */ +#define MBEDTLS_ECP_DP_MAX 12 + +/** + * Curve information, for use by other modules. + */ +typedef struct mbedtls_ecp_curve_info +{ + mbedtls_ecp_group_id grp_id; /*!< An internal identifier. */ + uint16_t tls_id; /*!< The TLS NamedCurve identifier. */ + uint16_t bit_size; /*!< The curve size in bits. */ + const char *name; /*!< A human-friendly name. */ +} mbedtls_ecp_curve_info; + +/** + * \brief The ECP point structure, in Jacobian coordinates. + * + * \note All functions expect and return points satisfying + * the following condition: Z == 0 or + * Z == 1. Other values of \p Z are + * used only by internal functions. + * The point is zero, or "at infinity", if Z == 0. + * Otherwise, \p X and \p Y are its standard (affine) + * coordinates. + */ +typedef struct mbedtls_ecp_point +{ + mbedtls_mpi X; /*!< The X coordinate of the ECP point. */ + mbedtls_mpi Y; /*!< The Y coordinate of the ECP point. */ + mbedtls_mpi Z; /*!< The Z coordinate of the ECP point. */ +} +mbedtls_ecp_point; + +#if !defined(MBEDTLS_ECP_ALT) +/* + * default mbed TLS elliptic curve arithmetic implementation + * + * (in case MBEDTLS_ECP_ALT is defined then the developer has to provide an + * alternative implementation for the whole module and it will replace this + * one.) + */ + +/** + * \brief The ECP group structure. + * + * We consider two types of curve equations: + *
  • Short Weierstrass: y^2 = x^3 + A x + B mod P + * (SEC1 + RFC-4492)
  • + *
  • Montgomery: y^2 = x^3 + A x^2 + x mod P (Curve25519, + * Curve448)
+ * In both cases, the generator (\p G) for a prime-order subgroup is fixed. + * + * For Short Weierstrass, this subgroup is the whole curve, and its + * cardinality is denoted by \p N. Our code requires that \p N is an + * odd prime as mbedtls_ecp_mul() requires an odd number, and + * mbedtls_ecdsa_sign() requires that it is prime for blinding purposes. + * + * For Montgomery curves, we do not store \p A, but (A + 2) / 4, + * which is the quantity used in the formulas. Additionally, \p nbits is + * not the size of \p N but the required size for private keys. + * + * If \p modp is NULL, reduction modulo \p P is done using a generic algorithm. + * Otherwise, \p modp must point to a function that takes an \p mbedtls_mpi in the + * range of 0..2^(2*pbits)-1, and transforms it in-place to an integer + * which is congruent mod \p P to the given MPI, and is close enough to \p pbits + * in size, so that it may be efficiently brought in the 0..P-1 range by a few + * additions or subtractions. Therefore, it is only an approximative modular + * reduction. It must return 0 on success and non-zero on failure. + * + */ +typedef struct mbedtls_ecp_group +{ + mbedtls_ecp_group_id id; /*!< An internal group identifier. */ + mbedtls_mpi P; /*!< The prime modulus of the base field. */ + mbedtls_mpi A; /*!< For Short Weierstrass: \p A in the equation. For + Montgomery curves: (A + 2) / 4. */ + mbedtls_mpi B; /*!< For Short Weierstrass: \p B in the equation. + For Montgomery curves: unused. */ + mbedtls_ecp_point G; /*!< The generator of the subgroup used. */ + mbedtls_mpi N; /*!< The order of \p G. */ + size_t pbits; /*!< The number of bits in \p P.*/ + size_t nbits; /*!< For Short Weierstrass: The number of bits in \p P. + For Montgomery curves: the number of bits in the + private keys. */ + unsigned int h; /*!< \internal 1 if the constants are static. */ + int (*modp)(mbedtls_mpi *); /*!< The function for fast pseudo-reduction + mod \p P (see above).*/ + int (*t_pre)(mbedtls_ecp_point *, void *); /*!< Unused. */ + int (*t_post)(mbedtls_ecp_point *, void *); /*!< Unused. */ + void *t_data; /*!< Unused. */ + mbedtls_ecp_point *T; /*!< Pre-computed points for ecp_mul_comb(). */ + size_t T_size; /*!< The number of pre-computed points. */ +} +mbedtls_ecp_group; + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h, or define them using the compiler command line. + * \{ + */ + +#if !defined(MBEDTLS_ECP_MAX_BITS) +/** + * The maximum size of the groups, that is, of \c N and \c P. + */ +#define MBEDTLS_ECP_MAX_BITS 521 /**< The maximum size of groups, in bits. */ +#endif + +#define MBEDTLS_ECP_MAX_BYTES ( ( MBEDTLS_ECP_MAX_BITS + 7 ) / 8 ) +#define MBEDTLS_ECP_MAX_PT_LEN ( 2 * MBEDTLS_ECP_MAX_BYTES + 1 ) + +#if !defined(MBEDTLS_ECP_WINDOW_SIZE) +/* + * Maximum "window" size used for point multiplication. + * Default: 6. + * Minimum value: 2. Maximum value: 7. + * + * Result is an array of at most ( 1 << ( MBEDTLS_ECP_WINDOW_SIZE - 1 ) ) + * points used for point multiplication. This value is directly tied to EC + * peak memory usage, so decreasing it by one should roughly cut memory usage + * by two (if large curves are in use). + * + * Reduction in size may reduce speed, but larger curves are impacted first. + * Sample performances (in ECDHE handshakes/s, with FIXED_POINT_OPTIM = 1): + * w-size: 6 5 4 3 2 + * 521 145 141 135 120 97 + * 384 214 209 198 177 146 + * 256 320 320 303 262 226 + * 224 475 475 453 398 342 + * 192 640 640 633 587 476 + */ +#define MBEDTLS_ECP_WINDOW_SIZE 6 /**< The maximum window size used. */ +#endif /* MBEDTLS_ECP_WINDOW_SIZE */ + +#if !defined(MBEDTLS_ECP_FIXED_POINT_OPTIM) +/* + * Trade memory for speed on fixed-point multiplication. + * + * This speeds up repeated multiplication of the generator (that is, the + * multiplication in ECDSA signatures, and half of the multiplications in + * ECDSA verification and ECDHE) by a factor roughly 3 to 4. + * + * The cost is increasing EC peak memory usage by a factor roughly 2. + * + * Change this value to 0 to reduce peak memory usage. + */ +#define MBEDTLS_ECP_FIXED_POINT_OPTIM 1 /**< Enable fixed-point speed-up. */ +#endif /* MBEDTLS_ECP_FIXED_POINT_OPTIM */ + +/* \} name SECTION: Module settings */ + +#else /* MBEDTLS_ECP_ALT */ +#include "ecp_alt.h" +#endif /* MBEDTLS_ECP_ALT */ + +/** + * \brief The ECP key-pair structure. + * + * A generic key-pair that may be used for ECDSA and fixed ECDH, for example. + * + * \note Members are deliberately in the same order as in the + * ::mbedtls_ecdsa_context structure. + */ +typedef struct mbedtls_ecp_keypair +{ + mbedtls_ecp_group grp; /*!< Elliptic curve and base point */ + mbedtls_mpi d; /*!< our secret value */ + mbedtls_ecp_point Q; /*!< our public value */ +} +mbedtls_ecp_keypair; + +/* + * Point formats, from RFC 4492's enum ECPointFormat + */ +#define MBEDTLS_ECP_PF_UNCOMPRESSED 0 /**< Uncompressed point format. */ +#define MBEDTLS_ECP_PF_COMPRESSED 1 /**< Compressed point format. */ + +/* + * Some other constants from RFC 4492 + */ +#define MBEDTLS_ECP_TLS_NAMED_CURVE 3 /**< The named_curve of ECCurveType. */ + +/** + * \brief This function retrieves the information defined in + * mbedtls_ecp_curve_info() for all supported curves in order + * of preference. + * + * \return A statically allocated array. The last entry is 0. + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_list( void ); + +/** + * \brief This function retrieves the list of internal group + * identifiers of all supported curves in the order of + * preference. + * + * \return A statically allocated array, + * terminated with MBEDTLS_ECP_DP_NONE. + */ +const mbedtls_ecp_group_id *mbedtls_ecp_grp_id_list( void ); + +/** + * \brief This function retrieves curve information from an internal + * group identifier. + * + * \param grp_id An \c MBEDTLS_ECP_DP_XXX value. + * + * \return The associated curve information on success. + * \return NULL on failure. + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_grp_id( mbedtls_ecp_group_id grp_id ); + +/** + * \brief This function retrieves curve information from a TLS + * NamedCurve value. + * + * \param tls_id An \c MBEDTLS_ECP_DP_XXX value. + * + * \return The associated curve information on success. + * \return NULL on failure. + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_tls_id( uint16_t tls_id ); + +/** + * \brief This function retrieves curve information from a + * human-readable name. + * + * \param name The human-readable name. + * + * \return The associated curve information on success. + * \return NULL on failure. + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_name( const char *name ); + +/** + * \brief This function initializes a point as zero. + * + * \param pt The point to initialize. + */ +void mbedtls_ecp_point_init( mbedtls_ecp_point *pt ); + +/** + * \brief This function initializes an ECP group context + * without loading any domain parameters. + * + * \note After this function is called, domain parameters + * for various ECP groups can be loaded through the + * mbedtls_ecp_load() or mbedtls_ecp_tls_read_group() + * functions. + */ +void mbedtls_ecp_group_init( mbedtls_ecp_group *grp ); + +/** + * \brief This function initializes a key pair as an invalid one. + * + * \param key The key pair to initialize. + */ +void mbedtls_ecp_keypair_init( mbedtls_ecp_keypair *key ); + +/** + * \brief This function frees the components of a point. + * + * \param pt The point to free. + */ +void mbedtls_ecp_point_free( mbedtls_ecp_point *pt ); + +/** + * \brief This function frees the components of an ECP group. + * \param grp The group to free. + */ +void mbedtls_ecp_group_free( mbedtls_ecp_group *grp ); + +/** + * \brief This function frees the components of a key pair. + * \param key The key pair to free. + */ +void mbedtls_ecp_keypair_free( mbedtls_ecp_keypair *key ); + +/** + * \brief This function copies the contents of point \p Q into + * point \p P. + * + * \param P The destination point. + * \param Q The source point. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure. + */ +int mbedtls_ecp_copy( mbedtls_ecp_point *P, const mbedtls_ecp_point *Q ); + +/** + * \brief This function copies the contents of group \p src into + * group \p dst. + * + * \param dst The destination group. + * \param src The source group. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure. + */ +int mbedtls_ecp_group_copy( mbedtls_ecp_group *dst, const mbedtls_ecp_group *src ); + +/** + * \brief This function sets a point to zero. + * + * \param pt The point to set. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure. + */ +int mbedtls_ecp_set_zero( mbedtls_ecp_point *pt ); + +/** + * \brief This function checks if a point is zero. + * + * \param pt The point to test. + * + * \return \c 1 if the point is zero. + * \return \c 0 if the point is non-zero. + */ +int mbedtls_ecp_is_zero( mbedtls_ecp_point *pt ); + +/** + * \brief This function compares two points. + * + * \note This assumes that the points are normalized. Otherwise, + * they may compare as "not equal" even if they are. + * + * \param P The first point to compare. + * \param Q The second point to compare. + * + * \return \c 0 if the points are equal. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if the points are not equal. + */ +int mbedtls_ecp_point_cmp( const mbedtls_ecp_point *P, + const mbedtls_ecp_point *Q ); + +/** + * \brief This function imports a non-zero point from two ASCII + * strings. + * + * \param P The destination point. + * \param radix The numeric base of the input. + * \param x The first affine coordinate, as a null-terminated string. + * \param y The second affine coordinate, as a null-terminated string. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_MPI_XXX error code on failure. + */ +int mbedtls_ecp_point_read_string( mbedtls_ecp_point *P, int radix, + const char *x, const char *y ); + +/** + * \brief This function exports a point into unsigned binary data. + * + * \param grp The group to which the point should belong. + * \param P The point to export. + * \param format The point format. Should be an \c MBEDTLS_ECP_PF_XXX macro. + * \param olen The length of the output. + * \param buf The output buffer. + * \param buflen The length of the output buffer. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA + * or #MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL on failure. + */ +int mbedtls_ecp_point_write_binary( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *P, + int format, size_t *olen, + unsigned char *buf, size_t buflen ); + +/** + * \brief This function imports a point from unsigned binary data. + * + * \note This function does not check that the point actually + * belongs to the given group, see mbedtls_ecp_check_pubkey() + * for that. + * + * \param grp The group to which the point should belong. + * \param P The point to import. + * \param buf The input buffer. + * \param ilen The length of the input. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure. + * \return #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the point format + * is not implemented. + * + */ +int mbedtls_ecp_point_read_binary( const mbedtls_ecp_group *grp, mbedtls_ecp_point *P, + const unsigned char *buf, size_t ilen ); + +/** + * \brief This function imports a point from a TLS ECPoint record. + * + * \note On function return, \p buf is updated to point to immediately + * after the ECPoint record. + * + * \param grp The ECP group used. + * \param pt The destination point. + * \param buf The address of the pointer to the start of the input buffer. + * \param len The length of the buffer. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_MPI_XXX error code on initialization failure. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid. + */ +int mbedtls_ecp_tls_read_point( const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt, + const unsigned char **buf, size_t len ); + +/** + * \brief This function exports a point as a TLS ECPoint record. + * + * \param grp The ECP group used. + * \param pt The point format to export to. The point format is an + * \c MBEDTLS_ECP_PF_XXX constant. + * \param format The export format. + * \param olen The length of the data written. + * \param buf The buffer to write to. + * \param blen The length of the buffer. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA or + * #MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL on failure. + */ +int mbedtls_ecp_tls_write_point( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt, + int format, size_t *olen, + unsigned char *buf, size_t blen ); + +/** + * \brief This function sets a group using standardized domain parameters. + * + * \note The index should be a value of the NamedCurve enum, + * as defined in RFC-4492: Elliptic Curve Cryptography + * (ECC) Cipher Suites for Transport Layer Security (TLS), + * usually in the form of an \c MBEDTLS_ECP_DP_XXX macro. + * + * \param grp The destination group. + * \param id The identifier of the domain parameter set to load. + * + * \return \c 0 on success, + * \return An \c MBEDTLS_ERR_MPI_XXX error code on initialization failure. + * \return #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE for unkownn groups. + + */ +int mbedtls_ecp_group_load( mbedtls_ecp_group *grp, mbedtls_ecp_group_id id ); + +/** + * \brief This function sets a group from a TLS ECParameters record. + * + * \note \p buf is updated to point right after the ECParameters record + * on exit. + * + * \param grp The destination group. + * \param buf The address of the pointer to the start of the input buffer. + * \param len The length of the buffer. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_MPI_XXX error code on initialization failure. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid. + */ +int mbedtls_ecp_tls_read_group( mbedtls_ecp_group *grp, const unsigned char **buf, size_t len ); + +/** + * \brief This function writes the TLS ECParameters record for a group. + * + * \param grp The ECP group used. + * \param olen The number of Bytes written. + * \param buf The buffer to write to. + * \param blen The length of the buffer. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL on failure. + */ +int mbedtls_ecp_tls_write_group( const mbedtls_ecp_group *grp, size_t *olen, + unsigned char *buf, size_t blen ); + +/** + * \brief This function performs multiplication of a point by + * an integer: \p R = \p m * \p P. + * + * It is not thread-safe to use same group in multiple threads. + * + * \note To prevent timing attacks, this function + * executes the exact same sequence of base-field + * operations for any valid \p m. It avoids any if-branch or + * array index depending on the value of \p m. + * + * \note If \p f_rng is not NULL, it is used to randomize + * intermediate results to prevent potential timing attacks + * targeting these results. We recommend always providing + * a non-NULL \p f_rng. The overhead is negligible. + * + * \param grp The ECP group. + * \param R The destination point. + * \param m The integer by which to multiply. + * \param P The point to multiply. + * \param f_rng The RNG function. + * \param p_rng The RNG context. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_INVALID_KEY if \p m is not a valid private + * key, or \p P is not a valid public key. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure. + */ +int mbedtls_ecp_mul( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + +/** + * \brief This function performs multiplication and addition of two + * points by integers: \p R = \p m * \p P + \p n * \p Q + * + * It is not thread-safe to use same group in multiple threads. + * + * \note In contrast to mbedtls_ecp_mul(), this function does not + * guarantee a constant execution flow and timing. + * + * \param grp The ECP group. + * \param R The destination point. + * \param m The integer by which to multiply \p P. + * \param P The point to multiply by \p m. + * \param n The integer by which to multiply \p Q. + * \param Q The point to be multiplied by \p n. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_INVALID_KEY if \p m or \p n are not + * valid private keys, or \p P or \p Q are not valid public + * keys. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure. + */ +int mbedtls_ecp_muladd( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + const mbedtls_mpi *n, const mbedtls_ecp_point *Q ); + +/** + * \brief This function checks that a point is a valid public key + * on this curve. + * + * It only checks that the point is non-zero, has + * valid coordinates and lies on the curve. It does not verify + * that it is indeed a multiple of \p G. This additional + * check is computationally more expensive, is not required + * by standards, and should not be necessary if the group + * used has a small cofactor. In particular, it is useless for + * the NIST groups which all have a cofactor of 1. + * + * \note This function uses bare components rather than an + * ::mbedtls_ecp_keypair structure, to ease use with other + * structures, such as ::mbedtls_ecdh_context or + * ::mbedtls_ecdsa_context. + * + * \param grp The curve the point should lie on. + * \param pt The point to check. + * + * \return \c 0 if the point is a valid public key. + * \return #MBEDTLS_ERR_ECP_INVALID_KEY on failure. + */ +int mbedtls_ecp_check_pubkey( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt ); + +/** + * \brief This function checks that an \p mbedtls_mpi is a valid private + * key for this curve. + * + * \note This function uses bare components rather than an + * ::mbedtls_ecp_keypair structure to ease use with other + * structures, such as ::mbedtls_ecdh_context or + * ::mbedtls_ecdsa_context. + * + * \param grp The group used. + * \param d The integer to check. + * + * \return \c 0 if the point is a valid private key. + * \return #MBEDTLS_ERR_ECP_INVALID_KEY on failure. + */ +int mbedtls_ecp_check_privkey( const mbedtls_ecp_group *grp, const mbedtls_mpi *d ); + +/** + * \brief This function generates a keypair with a configurable base + * point. + * + * \note This function uses bare components rather than an + * ::mbedtls_ecp_keypair structure to ease use with other + * structures, such as ::mbedtls_ecdh_context or + * ::mbedtls_ecdsa_context. + * + * \param grp The ECP group. + * \param G The chosen base point. + * \param d The destination MPI (secret part). + * \param Q The destination point (public part). + * \param f_rng The RNG function. + * \param p_rng The RNG context. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX error code + * on failure. + */ +int mbedtls_ecp_gen_keypair_base( mbedtls_ecp_group *grp, + const mbedtls_ecp_point *G, + mbedtls_mpi *d, mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief This function generates an ECP keypair. + * + * \note This function uses bare components rather than an + * ::mbedtls_ecp_keypair structure to ease use with other + * structures, such as ::mbedtls_ecdh_context or + * ::mbedtls_ecdsa_context. + * + * \param grp The ECP group. + * \param d The destination MPI (secret part). + * \param Q The destination point (public part). + * \param f_rng The RNG function. + * \param p_rng The RNG context. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX error code + * on failure. + */ +int mbedtls_ecp_gen_keypair( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief This function generates an ECP key. + * + * \param grp_id The ECP group identifier. + * \param key The destination key. + * \param f_rng The RNG function. + * \param p_rng The RNG context. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_ECP_XXX or \c MBEDTLS_MPI_XXX error code + * on failure. + */ +int mbedtls_ecp_gen_key( mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + +/** + * \brief This function checks that the keypair objects + * \p pub and \p prv have the same group and the + * same public point, and that the private key in + * \p prv is consistent with the public key. + * + * \param pub The keypair structure holding the public key. + * If it contains a private key, that part is ignored. + * \param prv The keypair structure holding the full keypair. + * + * \return \c 0 on success, meaning that the keys are valid and match. + * \return #MBEDTLS_ERR_ECP_BAD_INPUT_DATA if the keys are invalid or do not match. + * \return An \c MBEDTLS_ERR_ECP_XXX or an \c MBEDTLS_ERR_MPI_XXX + * error code on calculation failure. + */ +int mbedtls_ecp_check_pub_priv( const mbedtls_ecp_keypair *pub, const mbedtls_ecp_keypair *prv ); + +#if defined(MBEDTLS_SELF_TEST) + +/** + * \brief The ECP checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_ecp_self_test( int verbose ); + +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* ecp.h */ diff --git a/common/mbedtls/ecp_curves.c b/common/mbedtls/ecp_curves.c new file mode 100644 index 00000000..01efe8ba --- /dev/null +++ b/common/mbedtls/ecp_curves.c @@ -0,0 +1,1462 @@ +/* + * Elliptic curves over GF(p): curve-specific data and functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ECP_C) + +#include "mbedtls/ecp.h" + +#include + +#if !defined(MBEDTLS_ECP_ALT) + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +/* + * Conversion macros for embedded constants: + * build lists of mbedtls_mpi_uint's from lists of unsigned char's grouped by 8, 4 or 2 + */ +#if defined(MBEDTLS_HAVE_INT32) + +#define BYTES_TO_T_UINT_4( a, b, c, d ) \ + ( (mbedtls_mpi_uint) a << 0 ) | \ + ( (mbedtls_mpi_uint) b << 8 ) | \ + ( (mbedtls_mpi_uint) c << 16 ) | \ + ( (mbedtls_mpi_uint) d << 24 ) + +#define BYTES_TO_T_UINT_2( a, b ) \ + BYTES_TO_T_UINT_4( a, b, 0, 0 ) + +#define BYTES_TO_T_UINT_8( a, b, c, d, e, f, g, h ) \ + BYTES_TO_T_UINT_4( a, b, c, d ), \ + BYTES_TO_T_UINT_4( e, f, g, h ) + +#else /* 64-bits */ + +#define BYTES_TO_T_UINT_8( a, b, c, d, e, f, g, h ) \ + ( (mbedtls_mpi_uint) a << 0 ) | \ + ( (mbedtls_mpi_uint) b << 8 ) | \ + ( (mbedtls_mpi_uint) c << 16 ) | \ + ( (mbedtls_mpi_uint) d << 24 ) | \ + ( (mbedtls_mpi_uint) e << 32 ) | \ + ( (mbedtls_mpi_uint) f << 40 ) | \ + ( (mbedtls_mpi_uint) g << 48 ) | \ + ( (mbedtls_mpi_uint) h << 56 ) + +#define BYTES_TO_T_UINT_4( a, b, c, d ) \ + BYTES_TO_T_UINT_8( a, b, c, d, 0, 0, 0, 0 ) + +#define BYTES_TO_T_UINT_2( a, b ) \ + BYTES_TO_T_UINT_8( a, b, 0, 0, 0, 0, 0, 0 ) + +#endif /* bits in mbedtls_mpi_uint */ + +/* + * Note: the constants are in little-endian order + * to be directly usable in MPIs + */ + +/* + * Domain parameters for secp192r1 + */ +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) +static const mbedtls_mpi_uint secp192r1_p[] = { + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +static const mbedtls_mpi_uint secp192r1_b[] = { + BYTES_TO_T_UINT_8( 0xB1, 0xB9, 0x46, 0xC1, 0xEC, 0xDE, 0xB8, 0xFE ), + BYTES_TO_T_UINT_8( 0x49, 0x30, 0x24, 0x72, 0xAB, 0xE9, 0xA7, 0x0F ), + BYTES_TO_T_UINT_8( 0xE7, 0x80, 0x9C, 0xE5, 0x19, 0x05, 0x21, 0x64 ), +}; +static const mbedtls_mpi_uint secp192r1_gx[] = { + BYTES_TO_T_UINT_8( 0x12, 0x10, 0xFF, 0x82, 0xFD, 0x0A, 0xFF, 0xF4 ), + BYTES_TO_T_UINT_8( 0x00, 0x88, 0xA1, 0x43, 0xEB, 0x20, 0xBF, 0x7C ), + BYTES_TO_T_UINT_8( 0xF6, 0x90, 0x30, 0xB0, 0x0E, 0xA8, 0x8D, 0x18 ), +}; +static const mbedtls_mpi_uint secp192r1_gy[] = { + BYTES_TO_T_UINT_8( 0x11, 0x48, 0x79, 0x1E, 0xA1, 0x77, 0xF9, 0x73 ), + BYTES_TO_T_UINT_8( 0xD5, 0xCD, 0x24, 0x6B, 0xED, 0x11, 0x10, 0x63 ), + BYTES_TO_T_UINT_8( 0x78, 0xDA, 0xC8, 0xFF, 0x95, 0x2B, 0x19, 0x07 ), +}; +static const mbedtls_mpi_uint secp192r1_n[] = { + BYTES_TO_T_UINT_8( 0x31, 0x28, 0xD2, 0xB4, 0xB1, 0xC9, 0x6B, 0x14 ), + BYTES_TO_T_UINT_8( 0x36, 0xF8, 0xDE, 0x99, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */ + +/* + * Domain parameters for secp224r1 + */ +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) +static const mbedtls_mpi_uint secp224r1_p[] = { + BYTES_TO_T_UINT_8( 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), + BYTES_TO_T_UINT_8( 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00 ), +}; +static const mbedtls_mpi_uint secp224r1_b[] = { + BYTES_TO_T_UINT_8( 0xB4, 0xFF, 0x55, 0x23, 0x43, 0x39, 0x0B, 0x27 ), + BYTES_TO_T_UINT_8( 0xBA, 0xD8, 0xBF, 0xD7, 0xB7, 0xB0, 0x44, 0x50 ), + BYTES_TO_T_UINT_8( 0x56, 0x32, 0x41, 0xF5, 0xAB, 0xB3, 0x04, 0x0C ), + BYTES_TO_T_UINT_4( 0x85, 0x0A, 0x05, 0xB4 ), +}; +static const mbedtls_mpi_uint secp224r1_gx[] = { + BYTES_TO_T_UINT_8( 0x21, 0x1D, 0x5C, 0x11, 0xD6, 0x80, 0x32, 0x34 ), + BYTES_TO_T_UINT_8( 0x22, 0x11, 0xC2, 0x56, 0xD3, 0xC1, 0x03, 0x4A ), + BYTES_TO_T_UINT_8( 0xB9, 0x90, 0x13, 0x32, 0x7F, 0xBF, 0xB4, 0x6B ), + BYTES_TO_T_UINT_4( 0xBD, 0x0C, 0x0E, 0xB7 ), +}; +static const mbedtls_mpi_uint secp224r1_gy[] = { + BYTES_TO_T_UINT_8( 0x34, 0x7E, 0x00, 0x85, 0x99, 0x81, 0xD5, 0x44 ), + BYTES_TO_T_UINT_8( 0x64, 0x47, 0x07, 0x5A, 0xA0, 0x75, 0x43, 0xCD ), + BYTES_TO_T_UINT_8( 0xE6, 0xDF, 0x22, 0x4C, 0xFB, 0x23, 0xF7, 0xB5 ), + BYTES_TO_T_UINT_4( 0x88, 0x63, 0x37, 0xBD ), +}; +static const mbedtls_mpi_uint secp224r1_n[] = { + BYTES_TO_T_UINT_8( 0x3D, 0x2A, 0x5C, 0x5C, 0x45, 0x29, 0xDD, 0x13 ), + BYTES_TO_T_UINT_8( 0x3E, 0xF0, 0xB8, 0xE0, 0xA2, 0x16, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_4( 0xFF, 0xFF, 0xFF, 0xFF ), +}; +#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED */ + +/* + * Domain parameters for secp256r1 + */ +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) +static const mbedtls_mpi_uint secp256r1_p[] = { + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00 ), + BYTES_TO_T_UINT_8( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), + BYTES_TO_T_UINT_8( 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +static const mbedtls_mpi_uint secp256r1_b[] = { + BYTES_TO_T_UINT_8( 0x4B, 0x60, 0xD2, 0x27, 0x3E, 0x3C, 0xCE, 0x3B ), + BYTES_TO_T_UINT_8( 0xF6, 0xB0, 0x53, 0xCC, 0xB0, 0x06, 0x1D, 0x65 ), + BYTES_TO_T_UINT_8( 0xBC, 0x86, 0x98, 0x76, 0x55, 0xBD, 0xEB, 0xB3 ), + BYTES_TO_T_UINT_8( 0xE7, 0x93, 0x3A, 0xAA, 0xD8, 0x35, 0xC6, 0x5A ), +}; +static const mbedtls_mpi_uint secp256r1_gx[] = { + BYTES_TO_T_UINT_8( 0x96, 0xC2, 0x98, 0xD8, 0x45, 0x39, 0xA1, 0xF4 ), + BYTES_TO_T_UINT_8( 0xA0, 0x33, 0xEB, 0x2D, 0x81, 0x7D, 0x03, 0x77 ), + BYTES_TO_T_UINT_8( 0xF2, 0x40, 0xA4, 0x63, 0xE5, 0xE6, 0xBC, 0xF8 ), + BYTES_TO_T_UINT_8( 0x47, 0x42, 0x2C, 0xE1, 0xF2, 0xD1, 0x17, 0x6B ), +}; +static const mbedtls_mpi_uint secp256r1_gy[] = { + BYTES_TO_T_UINT_8( 0xF5, 0x51, 0xBF, 0x37, 0x68, 0x40, 0xB6, 0xCB ), + BYTES_TO_T_UINT_8( 0xCE, 0x5E, 0x31, 0x6B, 0x57, 0x33, 0xCE, 0x2B ), + BYTES_TO_T_UINT_8( 0x16, 0x9E, 0x0F, 0x7C, 0x4A, 0xEB, 0xE7, 0x8E ), + BYTES_TO_T_UINT_8( 0x9B, 0x7F, 0x1A, 0xFE, 0xE2, 0x42, 0xE3, 0x4F ), +}; +static const mbedtls_mpi_uint secp256r1_n[] = { + BYTES_TO_T_UINT_8( 0x51, 0x25, 0x63, 0xFC, 0xC2, 0xCA, 0xB9, 0xF3 ), + BYTES_TO_T_UINT_8( 0x84, 0x9E, 0x17, 0xA7, 0xAD, 0xFA, 0xE6, 0xBC ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ + +/* + * Domain parameters for secp384r1 + */ +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) +static const mbedtls_mpi_uint secp384r1_p[] = { + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00 ), + BYTES_TO_T_UINT_8( 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +static const mbedtls_mpi_uint secp384r1_b[] = { + BYTES_TO_T_UINT_8( 0xEF, 0x2A, 0xEC, 0xD3, 0xED, 0xC8, 0x85, 0x2A ), + BYTES_TO_T_UINT_8( 0x9D, 0xD1, 0x2E, 0x8A, 0x8D, 0x39, 0x56, 0xC6 ), + BYTES_TO_T_UINT_8( 0x5A, 0x87, 0x13, 0x50, 0x8F, 0x08, 0x14, 0x03 ), + BYTES_TO_T_UINT_8( 0x12, 0x41, 0x81, 0xFE, 0x6E, 0x9C, 0x1D, 0x18 ), + BYTES_TO_T_UINT_8( 0x19, 0x2D, 0xF8, 0xE3, 0x6B, 0x05, 0x8E, 0x98 ), + BYTES_TO_T_UINT_8( 0xE4, 0xE7, 0x3E, 0xE2, 0xA7, 0x2F, 0x31, 0xB3 ), +}; +static const mbedtls_mpi_uint secp384r1_gx[] = { + BYTES_TO_T_UINT_8( 0xB7, 0x0A, 0x76, 0x72, 0x38, 0x5E, 0x54, 0x3A ), + BYTES_TO_T_UINT_8( 0x6C, 0x29, 0x55, 0xBF, 0x5D, 0xF2, 0x02, 0x55 ), + BYTES_TO_T_UINT_8( 0x38, 0x2A, 0x54, 0x82, 0xE0, 0x41, 0xF7, 0x59 ), + BYTES_TO_T_UINT_8( 0x98, 0x9B, 0xA7, 0x8B, 0x62, 0x3B, 0x1D, 0x6E ), + BYTES_TO_T_UINT_8( 0x74, 0xAD, 0x20, 0xF3, 0x1E, 0xC7, 0xB1, 0x8E ), + BYTES_TO_T_UINT_8( 0x37, 0x05, 0x8B, 0xBE, 0x22, 0xCA, 0x87, 0xAA ), +}; +static const mbedtls_mpi_uint secp384r1_gy[] = { + BYTES_TO_T_UINT_8( 0x5F, 0x0E, 0xEA, 0x90, 0x7C, 0x1D, 0x43, 0x7A ), + BYTES_TO_T_UINT_8( 0x9D, 0x81, 0x7E, 0x1D, 0xCE, 0xB1, 0x60, 0x0A ), + BYTES_TO_T_UINT_8( 0xC0, 0xB8, 0xF0, 0xB5, 0x13, 0x31, 0xDA, 0xE9 ), + BYTES_TO_T_UINT_8( 0x7C, 0x14, 0x9A, 0x28, 0xBD, 0x1D, 0xF4, 0xF8 ), + BYTES_TO_T_UINT_8( 0x29, 0xDC, 0x92, 0x92, 0xBF, 0x98, 0x9E, 0x5D ), + BYTES_TO_T_UINT_8( 0x6F, 0x2C, 0x26, 0x96, 0x4A, 0xDE, 0x17, 0x36 ), +}; +static const mbedtls_mpi_uint secp384r1_n[] = { + BYTES_TO_T_UINT_8( 0x73, 0x29, 0xC5, 0xCC, 0x6A, 0x19, 0xEC, 0xEC ), + BYTES_TO_T_UINT_8( 0x7A, 0xA7, 0xB0, 0x48, 0xB2, 0x0D, 0x1A, 0x58 ), + BYTES_TO_T_UINT_8( 0xDF, 0x2D, 0x37, 0xF4, 0x81, 0x4D, 0x63, 0xC7 ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */ + +/* + * Domain parameters for secp521r1 + */ +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) +static const mbedtls_mpi_uint secp521r1_p[] = { + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_2( 0xFF, 0x01 ), +}; +static const mbedtls_mpi_uint secp521r1_b[] = { + BYTES_TO_T_UINT_8( 0x00, 0x3F, 0x50, 0x6B, 0xD4, 0x1F, 0x45, 0xEF ), + BYTES_TO_T_UINT_8( 0xF1, 0x34, 0x2C, 0x3D, 0x88, 0xDF, 0x73, 0x35 ), + BYTES_TO_T_UINT_8( 0x07, 0xBF, 0xB1, 0x3B, 0xBD, 0xC0, 0x52, 0x16 ), + BYTES_TO_T_UINT_8( 0x7B, 0x93, 0x7E, 0xEC, 0x51, 0x39, 0x19, 0x56 ), + BYTES_TO_T_UINT_8( 0xE1, 0x09, 0xF1, 0x8E, 0x91, 0x89, 0xB4, 0xB8 ), + BYTES_TO_T_UINT_8( 0xF3, 0x15, 0xB3, 0x99, 0x5B, 0x72, 0xDA, 0xA2 ), + BYTES_TO_T_UINT_8( 0xEE, 0x40, 0x85, 0xB6, 0xA0, 0x21, 0x9A, 0x92 ), + BYTES_TO_T_UINT_8( 0x1F, 0x9A, 0x1C, 0x8E, 0x61, 0xB9, 0x3E, 0x95 ), + BYTES_TO_T_UINT_2( 0x51, 0x00 ), +}; +static const mbedtls_mpi_uint secp521r1_gx[] = { + BYTES_TO_T_UINT_8( 0x66, 0xBD, 0xE5, 0xC2, 0x31, 0x7E, 0x7E, 0xF9 ), + BYTES_TO_T_UINT_8( 0x9B, 0x42, 0x6A, 0x85, 0xC1, 0xB3, 0x48, 0x33 ), + BYTES_TO_T_UINT_8( 0xDE, 0xA8, 0xFF, 0xA2, 0x27, 0xC1, 0x1D, 0xFE ), + BYTES_TO_T_UINT_8( 0x28, 0x59, 0xE7, 0xEF, 0x77, 0x5E, 0x4B, 0xA1 ), + BYTES_TO_T_UINT_8( 0xBA, 0x3D, 0x4D, 0x6B, 0x60, 0xAF, 0x28, 0xF8 ), + BYTES_TO_T_UINT_8( 0x21, 0xB5, 0x3F, 0x05, 0x39, 0x81, 0x64, 0x9C ), + BYTES_TO_T_UINT_8( 0x42, 0xB4, 0x95, 0x23, 0x66, 0xCB, 0x3E, 0x9E ), + BYTES_TO_T_UINT_8( 0xCD, 0xE9, 0x04, 0x04, 0xB7, 0x06, 0x8E, 0x85 ), + BYTES_TO_T_UINT_2( 0xC6, 0x00 ), +}; +static const mbedtls_mpi_uint secp521r1_gy[] = { + BYTES_TO_T_UINT_8( 0x50, 0x66, 0xD1, 0x9F, 0x76, 0x94, 0xBE, 0x88 ), + BYTES_TO_T_UINT_8( 0x40, 0xC2, 0x72, 0xA2, 0x86, 0x70, 0x3C, 0x35 ), + BYTES_TO_T_UINT_8( 0x61, 0x07, 0xAD, 0x3F, 0x01, 0xB9, 0x50, 0xC5 ), + BYTES_TO_T_UINT_8( 0x40, 0x26, 0xF4, 0x5E, 0x99, 0x72, 0xEE, 0x97 ), + BYTES_TO_T_UINT_8( 0x2C, 0x66, 0x3E, 0x27, 0x17, 0xBD, 0xAF, 0x17 ), + BYTES_TO_T_UINT_8( 0x68, 0x44, 0x9B, 0x57, 0x49, 0x44, 0xF5, 0x98 ), + BYTES_TO_T_UINT_8( 0xD9, 0x1B, 0x7D, 0x2C, 0xB4, 0x5F, 0x8A, 0x5C ), + BYTES_TO_T_UINT_8( 0x04, 0xC0, 0x3B, 0x9A, 0x78, 0x6A, 0x29, 0x39 ), + BYTES_TO_T_UINT_2( 0x18, 0x01 ), +}; +static const mbedtls_mpi_uint secp521r1_n[] = { + BYTES_TO_T_UINT_8( 0x09, 0x64, 0x38, 0x91, 0x1E, 0xB7, 0x6F, 0xBB ), + BYTES_TO_T_UINT_8( 0xAE, 0x47, 0x9C, 0x89, 0xB8, 0xC9, 0xB5, 0x3B ), + BYTES_TO_T_UINT_8( 0xD0, 0xA5, 0x09, 0xF7, 0x48, 0x01, 0xCC, 0x7F ), + BYTES_TO_T_UINT_8( 0x6B, 0x96, 0x2F, 0xBF, 0x83, 0x87, 0x86, 0x51 ), + BYTES_TO_T_UINT_8( 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_2( 0xFF, 0x01 ), +}; +#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) +static const mbedtls_mpi_uint secp192k1_p[] = { + BYTES_TO_T_UINT_8( 0x37, 0xEE, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +static const mbedtls_mpi_uint secp192k1_a[] = { + BYTES_TO_T_UINT_2( 0x00, 0x00 ), +}; +static const mbedtls_mpi_uint secp192k1_b[] = { + BYTES_TO_T_UINT_2( 0x03, 0x00 ), +}; +static const mbedtls_mpi_uint secp192k1_gx[] = { + BYTES_TO_T_UINT_8( 0x7D, 0x6C, 0xE0, 0xEA, 0xB1, 0xD1, 0xA5, 0x1D ), + BYTES_TO_T_UINT_8( 0x34, 0xF4, 0xB7, 0x80, 0x02, 0x7D, 0xB0, 0x26 ), + BYTES_TO_T_UINT_8( 0xAE, 0xE9, 0x57, 0xC0, 0x0E, 0xF1, 0x4F, 0xDB ), +}; +static const mbedtls_mpi_uint secp192k1_gy[] = { + BYTES_TO_T_UINT_8( 0x9D, 0x2F, 0x5E, 0xD9, 0x88, 0xAA, 0x82, 0x40 ), + BYTES_TO_T_UINT_8( 0x34, 0x86, 0xBE, 0x15, 0xD0, 0x63, 0x41, 0x84 ), + BYTES_TO_T_UINT_8( 0xA7, 0x28, 0x56, 0x9C, 0x6D, 0x2F, 0x2F, 0x9B ), +}; +static const mbedtls_mpi_uint secp192k1_n[] = { + BYTES_TO_T_UINT_8( 0x8D, 0xFD, 0xDE, 0x74, 0x6A, 0x46, 0x69, 0x0F ), + BYTES_TO_T_UINT_8( 0x17, 0xFC, 0xF2, 0x26, 0xFE, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +#endif /* MBEDTLS_ECP_DP_SECP192K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) +static const mbedtls_mpi_uint secp224k1_p[] = { + BYTES_TO_T_UINT_8( 0x6D, 0xE5, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_4( 0xFF, 0xFF, 0xFF, 0xFF ), +}; +static const mbedtls_mpi_uint secp224k1_a[] = { + BYTES_TO_T_UINT_2( 0x00, 0x00 ), +}; +static const mbedtls_mpi_uint secp224k1_b[] = { + BYTES_TO_T_UINT_2( 0x05, 0x00 ), +}; +static const mbedtls_mpi_uint secp224k1_gx[] = { + BYTES_TO_T_UINT_8( 0x5C, 0xA4, 0xB7, 0xB6, 0x0E, 0x65, 0x7E, 0x0F ), + BYTES_TO_T_UINT_8( 0xA9, 0x75, 0x70, 0xE4, 0xE9, 0x67, 0xA4, 0x69 ), + BYTES_TO_T_UINT_8( 0xA1, 0x28, 0xFC, 0x30, 0xDF, 0x99, 0xF0, 0x4D ), + BYTES_TO_T_UINT_4( 0x33, 0x5B, 0x45, 0xA1 ), +}; +static const mbedtls_mpi_uint secp224k1_gy[] = { + BYTES_TO_T_UINT_8( 0xA5, 0x61, 0x6D, 0x55, 0xDB, 0x4B, 0xCA, 0xE2 ), + BYTES_TO_T_UINT_8( 0x59, 0xBD, 0xB0, 0xC0, 0xF7, 0x19, 0xE3, 0xF7 ), + BYTES_TO_T_UINT_8( 0xD6, 0xFB, 0xCA, 0x82, 0x42, 0x34, 0xBA, 0x7F ), + BYTES_TO_T_UINT_4( 0xED, 0x9F, 0x08, 0x7E ), +}; +static const mbedtls_mpi_uint secp224k1_n[] = { + BYTES_TO_T_UINT_8( 0xF7, 0xB1, 0x9F, 0x76, 0x71, 0xA9, 0xF0, 0xCA ), + BYTES_TO_T_UINT_8( 0x84, 0x61, 0xEC, 0xD2, 0xE8, 0xDC, 0x01, 0x00 ), + BYTES_TO_T_UINT_8( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), + BYTES_TO_T_UINT_8( 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 ), +}; +#endif /* MBEDTLS_ECP_DP_SECP224K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) +static const mbedtls_mpi_uint secp256k1_p[] = { + BYTES_TO_T_UINT_8( 0x2F, 0xFC, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +static const mbedtls_mpi_uint secp256k1_a[] = { + BYTES_TO_T_UINT_2( 0x00, 0x00 ), +}; +static const mbedtls_mpi_uint secp256k1_b[] = { + BYTES_TO_T_UINT_2( 0x07, 0x00 ), +}; +static const mbedtls_mpi_uint secp256k1_gx[] = { + BYTES_TO_T_UINT_8( 0x98, 0x17, 0xF8, 0x16, 0x5B, 0x81, 0xF2, 0x59 ), + BYTES_TO_T_UINT_8( 0xD9, 0x28, 0xCE, 0x2D, 0xDB, 0xFC, 0x9B, 0x02 ), + BYTES_TO_T_UINT_8( 0x07, 0x0B, 0x87, 0xCE, 0x95, 0x62, 0xA0, 0x55 ), + BYTES_TO_T_UINT_8( 0xAC, 0xBB, 0xDC, 0xF9, 0x7E, 0x66, 0xBE, 0x79 ), +}; +static const mbedtls_mpi_uint secp256k1_gy[] = { + BYTES_TO_T_UINT_8( 0xB8, 0xD4, 0x10, 0xFB, 0x8F, 0xD0, 0x47, 0x9C ), + BYTES_TO_T_UINT_8( 0x19, 0x54, 0x85, 0xA6, 0x48, 0xB4, 0x17, 0xFD ), + BYTES_TO_T_UINT_8( 0xA8, 0x08, 0x11, 0x0E, 0xFC, 0xFB, 0xA4, 0x5D ), + BYTES_TO_T_UINT_8( 0x65, 0xC4, 0xA3, 0x26, 0x77, 0xDA, 0x3A, 0x48 ), +}; +static const mbedtls_mpi_uint secp256k1_n[] = { + BYTES_TO_T_UINT_8( 0x41, 0x41, 0x36, 0xD0, 0x8C, 0x5E, 0xD2, 0xBF ), + BYTES_TO_T_UINT_8( 0x3B, 0xA0, 0x48, 0xAF, 0xE6, 0xDC, 0xAE, 0xBA ), + BYTES_TO_T_UINT_8( 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED */ + +/* + * Domain parameters for brainpoolP256r1 (RFC 5639 3.4) + */ +#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) +static const mbedtls_mpi_uint brainpoolP256r1_p[] = { + BYTES_TO_T_UINT_8( 0x77, 0x53, 0x6E, 0x1F, 0x1D, 0x48, 0x13, 0x20 ), + BYTES_TO_T_UINT_8( 0x28, 0x20, 0x26, 0xD5, 0x23, 0xF6, 0x3B, 0x6E ), + BYTES_TO_T_UINT_8( 0x72, 0x8D, 0x83, 0x9D, 0x90, 0x0A, 0x66, 0x3E ), + BYTES_TO_T_UINT_8( 0xBC, 0xA9, 0xEE, 0xA1, 0xDB, 0x57, 0xFB, 0xA9 ), +}; +static const mbedtls_mpi_uint brainpoolP256r1_a[] = { + BYTES_TO_T_UINT_8( 0xD9, 0xB5, 0x30, 0xF3, 0x44, 0x4B, 0x4A, 0xE9 ), + BYTES_TO_T_UINT_8( 0x6C, 0x5C, 0xDC, 0x26, 0xC1, 0x55, 0x80, 0xFB ), + BYTES_TO_T_UINT_8( 0xE7, 0xFF, 0x7A, 0x41, 0x30, 0x75, 0xF6, 0xEE ), + BYTES_TO_T_UINT_8( 0x57, 0x30, 0x2C, 0xFC, 0x75, 0x09, 0x5A, 0x7D ), +}; +static const mbedtls_mpi_uint brainpoolP256r1_b[] = { + BYTES_TO_T_UINT_8( 0xB6, 0x07, 0x8C, 0xFF, 0x18, 0xDC, 0xCC, 0x6B ), + BYTES_TO_T_UINT_8( 0xCE, 0xE1, 0xF7, 0x5C, 0x29, 0x16, 0x84, 0x95 ), + BYTES_TO_T_UINT_8( 0xBF, 0x7C, 0xD7, 0xBB, 0xD9, 0xB5, 0x30, 0xF3 ), + BYTES_TO_T_UINT_8( 0x44, 0x4B, 0x4A, 0xE9, 0x6C, 0x5C, 0xDC, 0x26 ), +}; +static const mbedtls_mpi_uint brainpoolP256r1_gx[] = { + BYTES_TO_T_UINT_8( 0x62, 0x32, 0xCE, 0x9A, 0xBD, 0x53, 0x44, 0x3A ), + BYTES_TO_T_UINT_8( 0xC2, 0x23, 0xBD, 0xE3, 0xE1, 0x27, 0xDE, 0xB9 ), + BYTES_TO_T_UINT_8( 0xAF, 0xB7, 0x81, 0xFC, 0x2F, 0x48, 0x4B, 0x2C ), + BYTES_TO_T_UINT_8( 0xCB, 0x57, 0x7E, 0xCB, 0xB9, 0xAE, 0xD2, 0x8B ), +}; +static const mbedtls_mpi_uint brainpoolP256r1_gy[] = { + BYTES_TO_T_UINT_8( 0x97, 0x69, 0x04, 0x2F, 0xC7, 0x54, 0x1D, 0x5C ), + BYTES_TO_T_UINT_8( 0x54, 0x8E, 0xED, 0x2D, 0x13, 0x45, 0x77, 0xC2 ), + BYTES_TO_T_UINT_8( 0xC9, 0x1D, 0x61, 0x14, 0x1A, 0x46, 0xF8, 0x97 ), + BYTES_TO_T_UINT_8( 0xFD, 0xC4, 0xDA, 0xC3, 0x35, 0xF8, 0x7E, 0x54 ), +}; +static const mbedtls_mpi_uint brainpoolP256r1_n[] = { + BYTES_TO_T_UINT_8( 0xA7, 0x56, 0x48, 0x97, 0x82, 0x0E, 0x1E, 0x90 ), + BYTES_TO_T_UINT_8( 0xF7, 0xA6, 0x61, 0xB5, 0xA3, 0x7A, 0x39, 0x8C ), + BYTES_TO_T_UINT_8( 0x71, 0x8D, 0x83, 0x9D, 0x90, 0x0A, 0x66, 0x3E ), + BYTES_TO_T_UINT_8( 0xBC, 0xA9, 0xEE, 0xA1, 0xDB, 0x57, 0xFB, 0xA9 ), +}; +#endif /* MBEDTLS_ECP_DP_BP256R1_ENABLED */ + +/* + * Domain parameters for brainpoolP384r1 (RFC 5639 3.6) + */ +#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) +static const mbedtls_mpi_uint brainpoolP384r1_p[] = { + BYTES_TO_T_UINT_8( 0x53, 0xEC, 0x07, 0x31, 0x13, 0x00, 0x47, 0x87 ), + BYTES_TO_T_UINT_8( 0x71, 0x1A, 0x1D, 0x90, 0x29, 0xA7, 0xD3, 0xAC ), + BYTES_TO_T_UINT_8( 0x23, 0x11, 0xB7, 0x7F, 0x19, 0xDA, 0xB1, 0x12 ), + BYTES_TO_T_UINT_8( 0xB4, 0x56, 0x54, 0xED, 0x09, 0x71, 0x2F, 0x15 ), + BYTES_TO_T_UINT_8( 0xDF, 0x41, 0xE6, 0x50, 0x7E, 0x6F, 0x5D, 0x0F ), + BYTES_TO_T_UINT_8( 0x28, 0x6D, 0x38, 0xA3, 0x82, 0x1E, 0xB9, 0x8C ), +}; +static const mbedtls_mpi_uint brainpoolP384r1_a[] = { + BYTES_TO_T_UINT_8( 0x26, 0x28, 0xCE, 0x22, 0xDD, 0xC7, 0xA8, 0x04 ), + BYTES_TO_T_UINT_8( 0xEB, 0xD4, 0x3A, 0x50, 0x4A, 0x81, 0xA5, 0x8A ), + BYTES_TO_T_UINT_8( 0x0F, 0xF9, 0x91, 0xBA, 0xEF, 0x65, 0x91, 0x13 ), + BYTES_TO_T_UINT_8( 0x87, 0x27, 0xB2, 0x4F, 0x8E, 0xA2, 0xBE, 0xC2 ), + BYTES_TO_T_UINT_8( 0xA0, 0xAF, 0x05, 0xCE, 0x0A, 0x08, 0x72, 0x3C ), + BYTES_TO_T_UINT_8( 0x0C, 0x15, 0x8C, 0x3D, 0xC6, 0x82, 0xC3, 0x7B ), +}; +static const mbedtls_mpi_uint brainpoolP384r1_b[] = { + BYTES_TO_T_UINT_8( 0x11, 0x4C, 0x50, 0xFA, 0x96, 0x86, 0xB7, 0x3A ), + BYTES_TO_T_UINT_8( 0x94, 0xC9, 0xDB, 0x95, 0x02, 0x39, 0xB4, 0x7C ), + BYTES_TO_T_UINT_8( 0xD5, 0x62, 0xEB, 0x3E, 0xA5, 0x0E, 0x88, 0x2E ), + BYTES_TO_T_UINT_8( 0xA6, 0xD2, 0xDC, 0x07, 0xE1, 0x7D, 0xB7, 0x2F ), + BYTES_TO_T_UINT_8( 0x7C, 0x44, 0xF0, 0x16, 0x54, 0xB5, 0x39, 0x8B ), + BYTES_TO_T_UINT_8( 0x26, 0x28, 0xCE, 0x22, 0xDD, 0xC7, 0xA8, 0x04 ), +}; +static const mbedtls_mpi_uint brainpoolP384r1_gx[] = { + BYTES_TO_T_UINT_8( 0x1E, 0xAF, 0xD4, 0x47, 0xE2, 0xB2, 0x87, 0xEF ), + BYTES_TO_T_UINT_8( 0xAA, 0x46, 0xD6, 0x36, 0x34, 0xE0, 0x26, 0xE8 ), + BYTES_TO_T_UINT_8( 0xE8, 0x10, 0xBD, 0x0C, 0xFE, 0xCA, 0x7F, 0xDB ), + BYTES_TO_T_UINT_8( 0xE3, 0x4F, 0xF1, 0x7E, 0xE7, 0xA3, 0x47, 0x88 ), + BYTES_TO_T_UINT_8( 0x6B, 0x3F, 0xC1, 0xB7, 0x81, 0x3A, 0xA6, 0xA2 ), + BYTES_TO_T_UINT_8( 0xFF, 0x45, 0xCF, 0x68, 0xF0, 0x64, 0x1C, 0x1D ), +}; +static const mbedtls_mpi_uint brainpoolP384r1_gy[] = { + BYTES_TO_T_UINT_8( 0x15, 0x53, 0x3C, 0x26, 0x41, 0x03, 0x82, 0x42 ), + BYTES_TO_T_UINT_8( 0x11, 0x81, 0x91, 0x77, 0x21, 0x46, 0x46, 0x0E ), + BYTES_TO_T_UINT_8( 0x28, 0x29, 0x91, 0xF9, 0x4F, 0x05, 0x9C, 0xE1 ), + BYTES_TO_T_UINT_8( 0x64, 0x58, 0xEC, 0xFE, 0x29, 0x0B, 0xB7, 0x62 ), + BYTES_TO_T_UINT_8( 0x52, 0xD5, 0xCF, 0x95, 0x8E, 0xEB, 0xB1, 0x5C ), + BYTES_TO_T_UINT_8( 0xA4, 0xC2, 0xF9, 0x20, 0x75, 0x1D, 0xBE, 0x8A ), +}; +static const mbedtls_mpi_uint brainpoolP384r1_n[] = { + BYTES_TO_T_UINT_8( 0x65, 0x65, 0x04, 0xE9, 0x02, 0x32, 0x88, 0x3B ), + BYTES_TO_T_UINT_8( 0x10, 0xC3, 0x7F, 0x6B, 0xAF, 0xB6, 0x3A, 0xCF ), + BYTES_TO_T_UINT_8( 0xA7, 0x25, 0x04, 0xAC, 0x6C, 0x6E, 0x16, 0x1F ), + BYTES_TO_T_UINT_8( 0xB3, 0x56, 0x54, 0xED, 0x09, 0x71, 0x2F, 0x15 ), + BYTES_TO_T_UINT_8( 0xDF, 0x41, 0xE6, 0x50, 0x7E, 0x6F, 0x5D, 0x0F ), + BYTES_TO_T_UINT_8( 0x28, 0x6D, 0x38, 0xA3, 0x82, 0x1E, 0xB9, 0x8C ), +}; +#endif /* MBEDTLS_ECP_DP_BP384R1_ENABLED */ + +/* + * Domain parameters for brainpoolP512r1 (RFC 5639 3.7) + */ +#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) +static const mbedtls_mpi_uint brainpoolP512r1_p[] = { + BYTES_TO_T_UINT_8( 0xF3, 0x48, 0x3A, 0x58, 0x56, 0x60, 0xAA, 0x28 ), + BYTES_TO_T_UINT_8( 0x85, 0xC6, 0x82, 0x2D, 0x2F, 0xFF, 0x81, 0x28 ), + BYTES_TO_T_UINT_8( 0xE6, 0x80, 0xA3, 0xE6, 0x2A, 0xA1, 0xCD, 0xAE ), + BYTES_TO_T_UINT_8( 0x42, 0x68, 0xC6, 0x9B, 0x00, 0x9B, 0x4D, 0x7D ), + BYTES_TO_T_UINT_8( 0x71, 0x08, 0x33, 0x70, 0xCA, 0x9C, 0x63, 0xD6 ), + BYTES_TO_T_UINT_8( 0x0E, 0xD2, 0xC9, 0xB3, 0xB3, 0x8D, 0x30, 0xCB ), + BYTES_TO_T_UINT_8( 0x07, 0xFC, 0xC9, 0x33, 0xAE, 0xE6, 0xD4, 0x3F ), + BYTES_TO_T_UINT_8( 0x8B, 0xC4, 0xE9, 0xDB, 0xB8, 0x9D, 0xDD, 0xAA ), +}; +static const mbedtls_mpi_uint brainpoolP512r1_a[] = { + BYTES_TO_T_UINT_8( 0xCA, 0x94, 0xFC, 0x77, 0x4D, 0xAC, 0xC1, 0xE7 ), + BYTES_TO_T_UINT_8( 0xB9, 0xC7, 0xF2, 0x2B, 0xA7, 0x17, 0x11, 0x7F ), + BYTES_TO_T_UINT_8( 0xB5, 0xC8, 0x9A, 0x8B, 0xC9, 0xF1, 0x2E, 0x0A ), + BYTES_TO_T_UINT_8( 0xA1, 0x3A, 0x25, 0xA8, 0x5A, 0x5D, 0xED, 0x2D ), + BYTES_TO_T_UINT_8( 0xBC, 0x63, 0x98, 0xEA, 0xCA, 0x41, 0x34, 0xA8 ), + BYTES_TO_T_UINT_8( 0x10, 0x16, 0xF9, 0x3D, 0x8D, 0xDD, 0xCB, 0x94 ), + BYTES_TO_T_UINT_8( 0xC5, 0x4C, 0x23, 0xAC, 0x45, 0x71, 0x32, 0xE2 ), + BYTES_TO_T_UINT_8( 0x89, 0x3B, 0x60, 0x8B, 0x31, 0xA3, 0x30, 0x78 ), +}; +static const mbedtls_mpi_uint brainpoolP512r1_b[] = { + BYTES_TO_T_UINT_8( 0x23, 0xF7, 0x16, 0x80, 0x63, 0xBD, 0x09, 0x28 ), + BYTES_TO_T_UINT_8( 0xDD, 0xE5, 0xBA, 0x5E, 0xB7, 0x50, 0x40, 0x98 ), + BYTES_TO_T_UINT_8( 0x67, 0x3E, 0x08, 0xDC, 0xCA, 0x94, 0xFC, 0x77 ), + BYTES_TO_T_UINT_8( 0x4D, 0xAC, 0xC1, 0xE7, 0xB9, 0xC7, 0xF2, 0x2B ), + BYTES_TO_T_UINT_8( 0xA7, 0x17, 0x11, 0x7F, 0xB5, 0xC8, 0x9A, 0x8B ), + BYTES_TO_T_UINT_8( 0xC9, 0xF1, 0x2E, 0x0A, 0xA1, 0x3A, 0x25, 0xA8 ), + BYTES_TO_T_UINT_8( 0x5A, 0x5D, 0xED, 0x2D, 0xBC, 0x63, 0x98, 0xEA ), + BYTES_TO_T_UINT_8( 0xCA, 0x41, 0x34, 0xA8, 0x10, 0x16, 0xF9, 0x3D ), +}; +static const mbedtls_mpi_uint brainpoolP512r1_gx[] = { + BYTES_TO_T_UINT_8( 0x22, 0xF8, 0xB9, 0xBC, 0x09, 0x22, 0x35, 0x8B ), + BYTES_TO_T_UINT_8( 0x68, 0x5E, 0x6A, 0x40, 0x47, 0x50, 0x6D, 0x7C ), + BYTES_TO_T_UINT_8( 0x5F, 0x7D, 0xB9, 0x93, 0x7B, 0x68, 0xD1, 0x50 ), + BYTES_TO_T_UINT_8( 0x8D, 0xD4, 0xD0, 0xE2, 0x78, 0x1F, 0x3B, 0xFF ), + BYTES_TO_T_UINT_8( 0x8E, 0x09, 0xD0, 0xF4, 0xEE, 0x62, 0x3B, 0xB4 ), + BYTES_TO_T_UINT_8( 0xC1, 0x16, 0xD9, 0xB5, 0x70, 0x9F, 0xED, 0x85 ), + BYTES_TO_T_UINT_8( 0x93, 0x6A, 0x4C, 0x9C, 0x2E, 0x32, 0x21, 0x5A ), + BYTES_TO_T_UINT_8( 0x64, 0xD9, 0x2E, 0xD8, 0xBD, 0xE4, 0xAE, 0x81 ), +}; +static const mbedtls_mpi_uint brainpoolP512r1_gy[] = { + BYTES_TO_T_UINT_8( 0x92, 0x08, 0xD8, 0x3A, 0x0F, 0x1E, 0xCD, 0x78 ), + BYTES_TO_T_UINT_8( 0x06, 0x54, 0xF0, 0xA8, 0x2F, 0x2B, 0xCA, 0xD1 ), + BYTES_TO_T_UINT_8( 0xAE, 0x63, 0x27, 0x8A, 0xD8, 0x4B, 0xCA, 0x5B ), + BYTES_TO_T_UINT_8( 0x5E, 0x48, 0x5F, 0x4A, 0x49, 0xDE, 0xDC, 0xB2 ), + BYTES_TO_T_UINT_8( 0x11, 0x81, 0x1F, 0x88, 0x5B, 0xC5, 0x00, 0xA0 ), + BYTES_TO_T_UINT_8( 0x1A, 0x7B, 0xA5, 0x24, 0x00, 0xF7, 0x09, 0xF2 ), + BYTES_TO_T_UINT_8( 0xFD, 0x22, 0x78, 0xCF, 0xA9, 0xBF, 0xEA, 0xC0 ), + BYTES_TO_T_UINT_8( 0xEC, 0x32, 0x63, 0x56, 0x5D, 0x38, 0xDE, 0x7D ), +}; +static const mbedtls_mpi_uint brainpoolP512r1_n[] = { + BYTES_TO_T_UINT_8( 0x69, 0x00, 0xA9, 0x9C, 0x82, 0x96, 0x87, 0xB5 ), + BYTES_TO_T_UINT_8( 0xDD, 0xDA, 0x5D, 0x08, 0x81, 0xD3, 0xB1, 0x1D ), + BYTES_TO_T_UINT_8( 0x47, 0x10, 0xAC, 0x7F, 0x19, 0x61, 0x86, 0x41 ), + BYTES_TO_T_UINT_8( 0x19, 0x26, 0xA9, 0x4C, 0x41, 0x5C, 0x3E, 0x55 ), + BYTES_TO_T_UINT_8( 0x70, 0x08, 0x33, 0x70, 0xCA, 0x9C, 0x63, 0xD6 ), + BYTES_TO_T_UINT_8( 0x0E, 0xD2, 0xC9, 0xB3, 0xB3, 0x8D, 0x30, 0xCB ), + BYTES_TO_T_UINT_8( 0x07, 0xFC, 0xC9, 0x33, 0xAE, 0xE6, 0xD4, 0x3F ), + BYTES_TO_T_UINT_8( 0x8B, 0xC4, 0xE9, 0xDB, 0xB8, 0x9D, 0xDD, 0xAA ), +}; +#endif /* MBEDTLS_ECP_DP_BP512R1_ENABLED */ + +/* + * Create an MPI from embedded constants + * (assumes len is an exact multiple of sizeof mbedtls_mpi_uint) + */ +static inline void ecp_mpi_load( mbedtls_mpi *X, const mbedtls_mpi_uint *p, size_t len ) +{ + X->s = 1; + X->n = len / sizeof( mbedtls_mpi_uint ); + X->p = (mbedtls_mpi_uint *) p; +} + +/* + * Set an MPI to static value 1 + */ +static inline void ecp_mpi_set1( mbedtls_mpi *X ) +{ + static mbedtls_mpi_uint one[] = { 1 }; + X->s = 1; + X->n = 1; + X->p = one; +} + +/* + * Make group available from embedded constants + */ +static int ecp_group_load( mbedtls_ecp_group *grp, + const mbedtls_mpi_uint *p, size_t plen, + const mbedtls_mpi_uint *a, size_t alen, + const mbedtls_mpi_uint *b, size_t blen, + const mbedtls_mpi_uint *gx, size_t gxlen, + const mbedtls_mpi_uint *gy, size_t gylen, + const mbedtls_mpi_uint *n, size_t nlen) +{ + ecp_mpi_load( &grp->P, p, plen ); + if( a != NULL ) + ecp_mpi_load( &grp->A, a, alen ); + ecp_mpi_load( &grp->B, b, blen ); + ecp_mpi_load( &grp->N, n, nlen ); + + ecp_mpi_load( &grp->G.X, gx, gxlen ); + ecp_mpi_load( &grp->G.Y, gy, gylen ); + ecp_mpi_set1( &grp->G.Z ); + + grp->pbits = mbedtls_mpi_bitlen( &grp->P ); + grp->nbits = mbedtls_mpi_bitlen( &grp->N ); + + grp->h = 1; + + return( 0 ); +} + +#if defined(MBEDTLS_ECP_NIST_OPTIM) +/* Forward declarations */ +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) +static int ecp_mod_p192( mbedtls_mpi * ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) +static int ecp_mod_p224( mbedtls_mpi * ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) +static int ecp_mod_p256( mbedtls_mpi * ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) +static int ecp_mod_p384( mbedtls_mpi * ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) +static int ecp_mod_p521( mbedtls_mpi * ); +#endif + +#define NIST_MODP( P ) grp->modp = ecp_mod_ ## P; +#else +#define NIST_MODP( P ) +#endif /* MBEDTLS_ECP_NIST_OPTIM */ + +/* Additional forward declarations */ +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) +static int ecp_mod_p255( mbedtls_mpi * ); +#endif +#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) +static int ecp_mod_p448( mbedtls_mpi * ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) +static int ecp_mod_p192k1( mbedtls_mpi * ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) +static int ecp_mod_p224k1( mbedtls_mpi * ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) +static int ecp_mod_p256k1( mbedtls_mpi * ); +#endif + +#define LOAD_GROUP_A( G ) ecp_group_load( grp, \ + G ## _p, sizeof( G ## _p ), \ + G ## _a, sizeof( G ## _a ), \ + G ## _b, sizeof( G ## _b ), \ + G ## _gx, sizeof( G ## _gx ), \ + G ## _gy, sizeof( G ## _gy ), \ + G ## _n, sizeof( G ## _n ) ) + +#define LOAD_GROUP( G ) ecp_group_load( grp, \ + G ## _p, sizeof( G ## _p ), \ + NULL, 0, \ + G ## _b, sizeof( G ## _b ), \ + G ## _gx, sizeof( G ## _gx ), \ + G ## _gy, sizeof( G ## _gy ), \ + G ## _n, sizeof( G ## _n ) ) + +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) +/* + * Specialized function for creating the Curve25519 group + */ +static int ecp_use_curve25519( mbedtls_ecp_group *grp ) +{ + int ret; + + /* Actually ( A + 2 ) / 4 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &grp->A, 16, "01DB42" ) ); + + /* P = 2^255 - 19 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &grp->P, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &grp->P, 255 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &grp->P, &grp->P, 19 ) ); + grp->pbits = mbedtls_mpi_bitlen( &grp->P ); + + /* N = 2^252 + 27742317777372353535851937790883648493 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &grp->N, 16, + "14DEF9DEA2F79CD65812631A5CF5D3ED" ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( &grp->N, 252, 1 ) ); + + /* Y intentionally not set, since we use x/z coordinates. + * This is used as a marker to identify Montgomery curves! */ + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &grp->G.X, 9 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &grp->G.Z, 1 ) ); + mbedtls_mpi_free( &grp->G.Y ); + + /* Actually, the required msb for private keys */ + grp->nbits = 254; + +cleanup: + if( ret != 0 ) + mbedtls_ecp_group_free( grp ); + + return( ret ); +} +#endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) +/* + * Specialized function for creating the Curve448 group + */ +static int ecp_use_curve448( mbedtls_ecp_group *grp ) +{ + mbedtls_mpi Ns; + int ret; + + mbedtls_mpi_init( &Ns ); + + /* Actually ( A + 2 ) / 4 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &grp->A, 16, "98AA" ) ); + + /* P = 2^448 - 2^224 - 1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &grp->P, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &grp->P, 224 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &grp->P, &grp->P, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &grp->P, 224 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &grp->P, &grp->P, 1 ) ); + grp->pbits = mbedtls_mpi_bitlen( &grp->P ); + + /* Y intentionally not set, since we use x/z coordinates. + * This is used as a marker to identify Montgomery curves! */ + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &grp->G.X, 5 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &grp->G.Z, 1 ) ); + mbedtls_mpi_free( &grp->G.Y ); + + /* N = 2^446 - 13818066809895115352007386748515426880336692474882178609894547503885 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( &grp->N, 446, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &Ns, 16, + "8335DC163BB124B65129C96FDE933D8D723A70AADC873D6D54A7BB0D" ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &grp->N, &grp->N, &Ns ) ); + + /* Actually, the required msb for private keys */ + grp->nbits = 447; + +cleanup: + mbedtls_mpi_free( &Ns ); + if( ret != 0 ) + mbedtls_ecp_group_free( grp ); + + return( ret ); +} +#endif /* MBEDTLS_ECP_DP_CURVE448_ENABLED */ + +/* + * Set a group using well-known domain parameters + */ +int mbedtls_ecp_group_load( mbedtls_ecp_group *grp, mbedtls_ecp_group_id id ) +{ + mbedtls_ecp_group_free( grp ); + + grp->id = id; + + switch( id ) + { +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) + case MBEDTLS_ECP_DP_SECP192R1: + NIST_MODP( p192 ); + return( LOAD_GROUP( secp192r1 ) ); +#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) + case MBEDTLS_ECP_DP_SECP224R1: + NIST_MODP( p224 ); + return( LOAD_GROUP( secp224r1 ) ); +#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + case MBEDTLS_ECP_DP_SECP256R1: + NIST_MODP( p256 ); + return( LOAD_GROUP( secp256r1 ) ); +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) + case MBEDTLS_ECP_DP_SECP384R1: + NIST_MODP( p384 ); + return( LOAD_GROUP( secp384r1 ) ); +#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) + case MBEDTLS_ECP_DP_SECP521R1: + NIST_MODP( p521 ); + return( LOAD_GROUP( secp521r1 ) ); +#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) + case MBEDTLS_ECP_DP_SECP192K1: + grp->modp = ecp_mod_p192k1; + return( LOAD_GROUP_A( secp192k1 ) ); +#endif /* MBEDTLS_ECP_DP_SECP192K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) + case MBEDTLS_ECP_DP_SECP224K1: + grp->modp = ecp_mod_p224k1; + return( LOAD_GROUP_A( secp224k1 ) ); +#endif /* MBEDTLS_ECP_DP_SECP224K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) + case MBEDTLS_ECP_DP_SECP256K1: + grp->modp = ecp_mod_p256k1; + return( LOAD_GROUP_A( secp256k1 ) ); +#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) + case MBEDTLS_ECP_DP_BP256R1: + return( LOAD_GROUP_A( brainpoolP256r1 ) ); +#endif /* MBEDTLS_ECP_DP_BP256R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) + case MBEDTLS_ECP_DP_BP384R1: + return( LOAD_GROUP_A( brainpoolP384r1 ) ); +#endif /* MBEDTLS_ECP_DP_BP384R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) + case MBEDTLS_ECP_DP_BP512R1: + return( LOAD_GROUP_A( brainpoolP512r1 ) ); +#endif /* MBEDTLS_ECP_DP_BP512R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) + case MBEDTLS_ECP_DP_CURVE25519: + grp->modp = ecp_mod_p255; + return( ecp_use_curve25519( grp ) ); +#endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) + case MBEDTLS_ECP_DP_CURVE448: + grp->modp = ecp_mod_p448; + return( ecp_use_curve448( grp ) ); +#endif /* MBEDTLS_ECP_DP_CURVE448_ENABLED */ + + default: + mbedtls_ecp_group_free( grp ); + return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); + } +} + +#if defined(MBEDTLS_ECP_NIST_OPTIM) +/* + * Fast reduction modulo the primes used by the NIST curves. + * + * These functions are critical for speed, but not needed for correct + * operations. So, we make the choice to heavily rely on the internals of our + * bignum library, which creates a tight coupling between these functions and + * our MPI implementation. However, the coupling between the ECP module and + * MPI remains loose, since these functions can be deactivated at will. + */ + +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) +/* + * Compared to the way things are presented in FIPS 186-3 D.2, + * we proceed in columns, from right (least significant chunk) to left, + * adding chunks to N in place, and keeping a carry for the next chunk. + * This avoids moving things around in memory, and uselessly adding zeros, + * compared to the more straightforward, line-oriented approach. + * + * For this prime we need to handle data in chunks of 64 bits. + * Since this is always a multiple of our basic mbedtls_mpi_uint, we can + * use a mbedtls_mpi_uint * to designate such a chunk, and small loops to handle it. + */ + +/* Add 64-bit chunks (dst += src) and update carry */ +static inline void add64( mbedtls_mpi_uint *dst, mbedtls_mpi_uint *src, mbedtls_mpi_uint *carry ) +{ + unsigned char i; + mbedtls_mpi_uint c = 0; + for( i = 0; i < 8 / sizeof( mbedtls_mpi_uint ); i++, dst++, src++ ) + { + *dst += c; c = ( *dst < c ); + *dst += *src; c += ( *dst < *src ); + } + *carry += c; +} + +/* Add carry to a 64-bit chunk and update carry */ +static inline void carry64( mbedtls_mpi_uint *dst, mbedtls_mpi_uint *carry ) +{ + unsigned char i; + for( i = 0; i < 8 / sizeof( mbedtls_mpi_uint ); i++, dst++ ) + { + *dst += *carry; + *carry = ( *dst < *carry ); + } +} + +#define WIDTH 8 / sizeof( mbedtls_mpi_uint ) +#define A( i ) N->p + i * WIDTH +#define ADD( i ) add64( p, A( i ), &c ) +#define NEXT p += WIDTH; carry64( p, &c ) +#define LAST p += WIDTH; *p = c; while( ++p < end ) *p = 0 + +/* + * Fast quasi-reduction modulo p192 (FIPS 186-3 D.2.1) + */ +static int ecp_mod_p192( mbedtls_mpi *N ) +{ + int ret; + mbedtls_mpi_uint c = 0; + mbedtls_mpi_uint *p, *end; + + /* Make sure we have enough blocks so that A(5) is legal */ + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( N, 6 * WIDTH ) ); + + p = N->p; + end = p + N->n; + + ADD( 3 ); ADD( 5 ); NEXT; // A0 += A3 + A5 + ADD( 3 ); ADD( 4 ); ADD( 5 ); NEXT; // A1 += A3 + A4 + A5 + ADD( 4 ); ADD( 5 ); LAST; // A2 += A4 + A5 + +cleanup: + return( ret ); +} + +#undef WIDTH +#undef A +#undef ADD +#undef NEXT +#undef LAST +#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) +/* + * The reader is advised to first understand ecp_mod_p192() since the same + * general structure is used here, but with additional complications: + * (1) chunks of 32 bits, and (2) subtractions. + */ + +/* + * For these primes, we need to handle data in chunks of 32 bits. + * This makes it more complicated if we use 64 bits limbs in MPI, + * which prevents us from using a uniform access method as for p192. + * + * So, we define a mini abstraction layer to access 32 bit chunks, + * load them in 'cur' for work, and store them back from 'cur' when done. + * + * While at it, also define the size of N in terms of 32-bit chunks. + */ +#define LOAD32 cur = A( i ); + +#if defined(MBEDTLS_HAVE_INT32) /* 32 bit */ + +#define MAX32 N->n +#define A( j ) N->p[j] +#define STORE32 N->p[i] = cur; + +#else /* 64-bit */ + +#define MAX32 N->n * 2 +#define A( j ) j % 2 ? (uint32_t)( N->p[j/2] >> 32 ) : (uint32_t)( N->p[j/2] ) +#define STORE32 \ + if( i % 2 ) { \ + N->p[i/2] &= 0x00000000FFFFFFFF; \ + N->p[i/2] |= ((mbedtls_mpi_uint) cur) << 32; \ + } else { \ + N->p[i/2] &= 0xFFFFFFFF00000000; \ + N->p[i/2] |= (mbedtls_mpi_uint) cur; \ + } + +#endif /* sizeof( mbedtls_mpi_uint ) */ + +/* + * Helpers for addition and subtraction of chunks, with signed carry. + */ +static inline void add32( uint32_t *dst, uint32_t src, signed char *carry ) +{ + *dst += src; + *carry += ( *dst < src ); +} + +static inline void sub32( uint32_t *dst, uint32_t src, signed char *carry ) +{ + *carry -= ( *dst < src ); + *dst -= src; +} + +#define ADD( j ) add32( &cur, A( j ), &c ); +#define SUB( j ) sub32( &cur, A( j ), &c ); + +/* + * Helpers for the main 'loop' + * (see fix_negative for the motivation of C) + */ +#define INIT( b ) \ + int ret; \ + signed char c = 0, cc; \ + uint32_t cur; \ + size_t i = 0, bits = b; \ + mbedtls_mpi C; \ + mbedtls_mpi_uint Cp[ b / 8 / sizeof( mbedtls_mpi_uint) + 1 ]; \ + \ + C.s = 1; \ + C.n = b / 8 / sizeof( mbedtls_mpi_uint) + 1; \ + C.p = Cp; \ + memset( Cp, 0, C.n * sizeof( mbedtls_mpi_uint ) ); \ + \ + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( N, b * 2 / 8 / sizeof( mbedtls_mpi_uint ) ) ); \ + LOAD32; + +#define NEXT \ + STORE32; i++; LOAD32; \ + cc = c; c = 0; \ + if( cc < 0 ) \ + sub32( &cur, -cc, &c ); \ + else \ + add32( &cur, cc, &c ); \ + +#define LAST \ + STORE32; i++; \ + cur = c > 0 ? c : 0; STORE32; \ + cur = 0; while( ++i < MAX32 ) { STORE32; } \ + if( c < 0 ) fix_negative( N, c, &C, bits ); + +/* + * If the result is negative, we get it in the form + * c * 2^(bits + 32) + N, with c negative and N positive shorter than 'bits' + */ +static inline int fix_negative( mbedtls_mpi *N, signed char c, mbedtls_mpi *C, size_t bits ) +{ + int ret; + + /* C = - c * 2^(bits + 32) */ +#if !defined(MBEDTLS_HAVE_INT64) + ((void) bits); +#else + if( bits == 224 ) + C->p[ C->n - 1 ] = ((mbedtls_mpi_uint) -c) << 32; + else +#endif + C->p[ C->n - 1 ] = (mbedtls_mpi_uint) -c; + + /* N = - ( C - N ) */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( N, C, N ) ); + N->s = -1; + +cleanup: + + return( ret ); +} + +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) +/* + * Fast quasi-reduction modulo p224 (FIPS 186-3 D.2.2) + */ +static int ecp_mod_p224( mbedtls_mpi *N ) +{ + INIT( 224 ); + + SUB( 7 ); SUB( 11 ); NEXT; // A0 += -A7 - A11 + SUB( 8 ); SUB( 12 ); NEXT; // A1 += -A8 - A12 + SUB( 9 ); SUB( 13 ); NEXT; // A2 += -A9 - A13 + SUB( 10 ); ADD( 7 ); ADD( 11 ); NEXT; // A3 += -A10 + A7 + A11 + SUB( 11 ); ADD( 8 ); ADD( 12 ); NEXT; // A4 += -A11 + A8 + A12 + SUB( 12 ); ADD( 9 ); ADD( 13 ); NEXT; // A5 += -A12 + A9 + A13 + SUB( 13 ); ADD( 10 ); LAST; // A6 += -A13 + A10 + +cleanup: + return( ret ); +} +#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) +/* + * Fast quasi-reduction modulo p256 (FIPS 186-3 D.2.3) + */ +static int ecp_mod_p256( mbedtls_mpi *N ) +{ + INIT( 256 ); + + ADD( 8 ); ADD( 9 ); + SUB( 11 ); SUB( 12 ); SUB( 13 ); SUB( 14 ); NEXT; // A0 + + ADD( 9 ); ADD( 10 ); + SUB( 12 ); SUB( 13 ); SUB( 14 ); SUB( 15 ); NEXT; // A1 + + ADD( 10 ); ADD( 11 ); + SUB( 13 ); SUB( 14 ); SUB( 15 ); NEXT; // A2 + + ADD( 11 ); ADD( 11 ); ADD( 12 ); ADD( 12 ); ADD( 13 ); + SUB( 15 ); SUB( 8 ); SUB( 9 ); NEXT; // A3 + + ADD( 12 ); ADD( 12 ); ADD( 13 ); ADD( 13 ); ADD( 14 ); + SUB( 9 ); SUB( 10 ); NEXT; // A4 + + ADD( 13 ); ADD( 13 ); ADD( 14 ); ADD( 14 ); ADD( 15 ); + SUB( 10 ); SUB( 11 ); NEXT; // A5 + + ADD( 14 ); ADD( 14 ); ADD( 15 ); ADD( 15 ); ADD( 14 ); ADD( 13 ); + SUB( 8 ); SUB( 9 ); NEXT; // A6 + + ADD( 15 ); ADD( 15 ); ADD( 15 ); ADD( 8 ); + SUB( 10 ); SUB( 11 ); SUB( 12 ); SUB( 13 ); LAST; // A7 + +cleanup: + return( ret ); +} +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) +/* + * Fast quasi-reduction modulo p384 (FIPS 186-3 D.2.4) + */ +static int ecp_mod_p384( mbedtls_mpi *N ) +{ + INIT( 384 ); + + ADD( 12 ); ADD( 21 ); ADD( 20 ); + SUB( 23 ); NEXT; // A0 + + ADD( 13 ); ADD( 22 ); ADD( 23 ); + SUB( 12 ); SUB( 20 ); NEXT; // A2 + + ADD( 14 ); ADD( 23 ); + SUB( 13 ); SUB( 21 ); NEXT; // A2 + + ADD( 15 ); ADD( 12 ); ADD( 20 ); ADD( 21 ); + SUB( 14 ); SUB( 22 ); SUB( 23 ); NEXT; // A3 + + ADD( 21 ); ADD( 21 ); ADD( 16 ); ADD( 13 ); ADD( 12 ); ADD( 20 ); ADD( 22 ); + SUB( 15 ); SUB( 23 ); SUB( 23 ); NEXT; // A4 + + ADD( 22 ); ADD( 22 ); ADD( 17 ); ADD( 14 ); ADD( 13 ); ADD( 21 ); ADD( 23 ); + SUB( 16 ); NEXT; // A5 + + ADD( 23 ); ADD( 23 ); ADD( 18 ); ADD( 15 ); ADD( 14 ); ADD( 22 ); + SUB( 17 ); NEXT; // A6 + + ADD( 19 ); ADD( 16 ); ADD( 15 ); ADD( 23 ); + SUB( 18 ); NEXT; // A7 + + ADD( 20 ); ADD( 17 ); ADD( 16 ); + SUB( 19 ); NEXT; // A8 + + ADD( 21 ); ADD( 18 ); ADD( 17 ); + SUB( 20 ); NEXT; // A9 + + ADD( 22 ); ADD( 19 ); ADD( 18 ); + SUB( 21 ); NEXT; // A10 + + ADD( 23 ); ADD( 20 ); ADD( 19 ); + SUB( 22 ); LAST; // A11 + +cleanup: + return( ret ); +} +#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */ + +#undef A +#undef LOAD32 +#undef STORE32 +#undef MAX32 +#undef INIT +#undef NEXT +#undef LAST + +#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED || + MBEDTLS_ECP_DP_SECP256R1_ENABLED || + MBEDTLS_ECP_DP_SECP384R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) +/* + * Here we have an actual Mersenne prime, so things are more straightforward. + * However, chunks are aligned on a 'weird' boundary (521 bits). + */ + +/* Size of p521 in terms of mbedtls_mpi_uint */ +#define P521_WIDTH ( 521 / 8 / sizeof( mbedtls_mpi_uint ) + 1 ) + +/* Bits to keep in the most significant mbedtls_mpi_uint */ +#define P521_MASK 0x01FF + +/* + * Fast quasi-reduction modulo p521 (FIPS 186-3 D.2.5) + * Write N as A1 + 2^521 A0, return A0 + A1 + */ +static int ecp_mod_p521( mbedtls_mpi *N ) +{ + int ret; + size_t i; + mbedtls_mpi M; + mbedtls_mpi_uint Mp[P521_WIDTH + 1]; + /* Worst case for the size of M is when mbedtls_mpi_uint is 16 bits: + * we need to hold bits 513 to 1056, which is 34 limbs, that is + * P521_WIDTH + 1. Otherwise P521_WIDTH is enough. */ + + if( N->n < P521_WIDTH ) + return( 0 ); + + /* M = A1 */ + M.s = 1; + M.n = N->n - ( P521_WIDTH - 1 ); + if( M.n > P521_WIDTH + 1 ) + M.n = P521_WIDTH + 1; + M.p = Mp; + memcpy( Mp, N->p + P521_WIDTH - 1, M.n * sizeof( mbedtls_mpi_uint ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &M, 521 % ( 8 * sizeof( mbedtls_mpi_uint ) ) ) ); + + /* N = A0 */ + N->p[P521_WIDTH - 1] &= P521_MASK; + for( i = P521_WIDTH; i < N->n; i++ ) + N->p[i] = 0; + + /* N = A0 + A1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( N, N, &M ) ); + +cleanup: + return( ret ); +} + +#undef P521_WIDTH +#undef P521_MASK +#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */ + +#endif /* MBEDTLS_ECP_NIST_OPTIM */ + +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) + +/* Size of p255 in terms of mbedtls_mpi_uint */ +#define P255_WIDTH ( 255 / 8 / sizeof( mbedtls_mpi_uint ) + 1 ) + +/* + * Fast quasi-reduction modulo p255 = 2^255 - 19 + * Write N as A0 + 2^255 A1, return A0 + 19 * A1 + */ +static int ecp_mod_p255( mbedtls_mpi *N ) +{ + int ret; + size_t i; + mbedtls_mpi M; + mbedtls_mpi_uint Mp[P255_WIDTH + 2]; + + if( N->n < P255_WIDTH ) + return( 0 ); + + /* M = A1 */ + M.s = 1; + M.n = N->n - ( P255_WIDTH - 1 ); + if( M.n > P255_WIDTH + 1 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + M.p = Mp; + memset( Mp, 0, sizeof Mp ); + memcpy( Mp, N->p + P255_WIDTH - 1, M.n * sizeof( mbedtls_mpi_uint ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &M, 255 % ( 8 * sizeof( mbedtls_mpi_uint ) ) ) ); + M.n++; /* Make room for multiplication by 19 */ + + /* N = A0 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( N, 255, 0 ) ); + for( i = P255_WIDTH; i < N->n; i++ ) + N->p[i] = 0; + + /* N = A0 + 19 * A1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &M, &M, 19 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( N, N, &M ) ); + +cleanup: + return( ret ); +} +#endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) + +/* Size of p448 in terms of mbedtls_mpi_uint */ +#define P448_WIDTH ( 448 / 8 / sizeof( mbedtls_mpi_uint ) ) + +/* Number of limbs fully occupied by 2^224 (max), and limbs used by it (min) */ +#define DIV_ROUND_UP( X, Y ) ( ( ( X ) + ( Y ) - 1 ) / ( Y ) ) +#define P224_WIDTH_MIN ( 28 / sizeof( mbedtls_mpi_uint ) ) +#define P224_WIDTH_MAX DIV_ROUND_UP( 28, sizeof( mbedtls_mpi_uint ) ) +#define P224_UNUSED_BITS ( ( P224_WIDTH_MAX * sizeof( mbedtls_mpi_uint ) * 8 ) - 224 ) + +/* + * Fast quasi-reduction modulo p448 = 2^448 - 2^224 - 1 + * Write N as A0 + 2^448 A1 and A1 as B0 + 2^224 B1, and return + * A0 + A1 + B1 + (B0 + B1) * 2^224. This is different to the reference + * implementation of Curve448, which uses its own special 56-bit limbs rather + * than a generic bignum library. We could squeeze some extra speed out on + * 32-bit machines by splitting N up into 32-bit limbs and doing the + * arithmetic using the limbs directly as we do for the NIST primes above, + * but for 64-bit targets it should use half the number of operations if we do + * the reduction with 224-bit limbs, since mpi_add_mpi will then use 64-bit adds. + */ +static int ecp_mod_p448( mbedtls_mpi *N ) +{ + int ret; + size_t i; + mbedtls_mpi M, Q; + mbedtls_mpi_uint Mp[P448_WIDTH + 1], Qp[P448_WIDTH]; + + if( N->n <= P448_WIDTH ) + return( 0 ); + + /* M = A1 */ + M.s = 1; + M.n = N->n - ( P448_WIDTH ); + if( M.n > P448_WIDTH ) + /* Shouldn't be called with N larger than 2^896! */ + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + M.p = Mp; + memset( Mp, 0, sizeof( Mp ) ); + memcpy( Mp, N->p + P448_WIDTH, M.n * sizeof( mbedtls_mpi_uint ) ); + + /* N = A0 */ + for( i = P448_WIDTH; i < N->n; i++ ) + N->p[i] = 0; + + /* N += A1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( N, N, &M ) ); + + /* Q = B1, N += B1 */ + Q = M; + Q.p = Qp; + memcpy( Qp, Mp, sizeof( Qp ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &Q, 224 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( N, N, &Q ) ); + + /* M = (B0 + B1) * 2^224, N += M */ + if( sizeof( mbedtls_mpi_uint ) > 4 ) + Mp[P224_WIDTH_MIN] &= ( (mbedtls_mpi_uint)-1 ) >> ( P224_UNUSED_BITS ); + for( i = P224_WIDTH_MAX; i < M.n; ++i ) + Mp[i] = 0; + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &M, &M, &Q ) ); + M.n = P448_WIDTH + 1; /* Make room for shifted carry bit from the addition */ + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &M, 224 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( N, N, &M ) ); + +cleanup: + return( ret ); +} +#endif /* MBEDTLS_ECP_DP_CURVE448_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) +/* + * Fast quasi-reduction modulo P = 2^s - R, + * with R about 33 bits, used by the Koblitz curves. + * + * Write N as A0 + 2^224 A1, return A0 + R * A1. + * Actually do two passes, since R is big. + */ +#define P_KOBLITZ_MAX ( 256 / 8 / sizeof( mbedtls_mpi_uint ) ) // Max limbs in P +#define P_KOBLITZ_R ( 8 / sizeof( mbedtls_mpi_uint ) ) // Limbs in R +static inline int ecp_mod_koblitz( mbedtls_mpi *N, mbedtls_mpi_uint *Rp, size_t p_limbs, + size_t adjust, size_t shift, mbedtls_mpi_uint mask ) +{ + int ret; + size_t i; + mbedtls_mpi M, R; + mbedtls_mpi_uint Mp[P_KOBLITZ_MAX + P_KOBLITZ_R + 1]; + + if( N->n < p_limbs ) + return( 0 ); + + /* Init R */ + R.s = 1; + R.p = Rp; + R.n = P_KOBLITZ_R; + + /* Common setup for M */ + M.s = 1; + M.p = Mp; + + /* M = A1 */ + M.n = N->n - ( p_limbs - adjust ); + if( M.n > p_limbs + adjust ) + M.n = p_limbs + adjust; + memset( Mp, 0, sizeof Mp ); + memcpy( Mp, N->p + p_limbs - adjust, M.n * sizeof( mbedtls_mpi_uint ) ); + if( shift != 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &M, shift ) ); + M.n += R.n; /* Make room for multiplication by R */ + + /* N = A0 */ + if( mask != 0 ) + N->p[p_limbs - 1] &= mask; + for( i = p_limbs; i < N->n; i++ ) + N->p[i] = 0; + + /* N = A0 + R * A1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &M, &M, &R ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( N, N, &M ) ); + + /* Second pass */ + + /* M = A1 */ + M.n = N->n - ( p_limbs - adjust ); + if( M.n > p_limbs + adjust ) + M.n = p_limbs + adjust; + memset( Mp, 0, sizeof Mp ); + memcpy( Mp, N->p + p_limbs - adjust, M.n * sizeof( mbedtls_mpi_uint ) ); + if( shift != 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &M, shift ) ); + M.n += R.n; /* Make room for multiplication by R */ + + /* N = A0 */ + if( mask != 0 ) + N->p[p_limbs - 1] &= mask; + for( i = p_limbs; i < N->n; i++ ) + N->p[i] = 0; + + /* N = A0 + R * A1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &M, &M, &R ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( N, N, &M ) ); + +cleanup: + return( ret ); +} +#endif /* MBEDTLS_ECP_DP_SECP192K1_ENABLED) || + MBEDTLS_ECP_DP_SECP224K1_ENABLED) || + MBEDTLS_ECP_DP_SECP256K1_ENABLED) */ + +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) +/* + * Fast quasi-reduction modulo p192k1 = 2^192 - R, + * with R = 2^32 + 2^12 + 2^8 + 2^7 + 2^6 + 2^3 + 1 = 0x0100001119 + */ +static int ecp_mod_p192k1( mbedtls_mpi *N ) +{ + static mbedtls_mpi_uint Rp[] = { + BYTES_TO_T_UINT_8( 0xC9, 0x11, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 ) }; + + return( ecp_mod_koblitz( N, Rp, 192 / 8 / sizeof( mbedtls_mpi_uint ), 0, 0, 0 ) ); +} +#endif /* MBEDTLS_ECP_DP_SECP192K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) +/* + * Fast quasi-reduction modulo p224k1 = 2^224 - R, + * with R = 2^32 + 2^12 + 2^11 + 2^9 + 2^7 + 2^4 + 2 + 1 = 0x0100001A93 + */ +static int ecp_mod_p224k1( mbedtls_mpi *N ) +{ + static mbedtls_mpi_uint Rp[] = { + BYTES_TO_T_UINT_8( 0x93, 0x1A, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 ) }; + +#if defined(MBEDTLS_HAVE_INT64) + return( ecp_mod_koblitz( N, Rp, 4, 1, 32, 0xFFFFFFFF ) ); +#else + return( ecp_mod_koblitz( N, Rp, 224 / 8 / sizeof( mbedtls_mpi_uint ), 0, 0, 0 ) ); +#endif +} + +#endif /* MBEDTLS_ECP_DP_SECP224K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) +/* + * Fast quasi-reduction modulo p256k1 = 2^256 - R, + * with R = 2^32 + 2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1 = 0x01000003D1 + */ +static int ecp_mod_p256k1( mbedtls_mpi *N ) +{ + static mbedtls_mpi_uint Rp[] = { + BYTES_TO_T_UINT_8( 0xD1, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 ) }; + return( ecp_mod_koblitz( N, Rp, 256 / 8 / sizeof( mbedtls_mpi_uint ), 0, 0, 0 ) ); +} +#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED */ + +#endif /* !MBEDTLS_ECP_ALT */ + +#endif /* MBEDTLS_ECP_C */ diff --git a/common/mbedtls/ecp_internal.h b/common/mbedtls/ecp_internal.h new file mode 100644 index 00000000..73bccd42 --- /dev/null +++ b/common/mbedtls/ecp_internal.h @@ -0,0 +1,295 @@ +/** + * \file ecp_internal.h + * + * \brief Function declarations for alternative implementation of elliptic curve + * point arithmetic. + */ +/* + * Copyright (C) 2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * References: + * + * [1] BERNSTEIN, Daniel J. Curve25519: new Diffie-Hellman speed records. + * + * + * [2] CORON, Jean-S'ebastien. Resistance against differential power analysis + * for elliptic curve cryptosystems. In : Cryptographic Hardware and + * Embedded Systems. Springer Berlin Heidelberg, 1999. p. 292-302. + * + * + * [3] HEDABOU, Mustapha, PINEL, Pierre, et B'EN'ETEAU, Lucien. A comb method to + * render ECC resistant against Side Channel Attacks. IACR Cryptology + * ePrint Archive, 2004, vol. 2004, p. 342. + * + * + * [4] Certicom Research. SEC 2: Recommended Elliptic Curve Domain Parameters. + * + * + * [5] HANKERSON, Darrel, MENEZES, Alfred J., VANSTONE, Scott. Guide to Elliptic + * Curve Cryptography. + * + * [6] Digital Signature Standard (DSS), FIPS 186-4. + * + * + * [7] Elliptic Curve Cryptography (ECC) Cipher Suites for Transport Layer + * Security (TLS), RFC 4492. + * + * + * [8] + * + * [9] COHEN, Henri. A Course in Computational Algebraic Number Theory. + * Springer Science & Business Media, 1 Aug 2000 + */ + +#ifndef MBEDTLS_ECP_INTERNAL_H +#define MBEDTLS_ECP_INTERNAL_H + +#if defined(MBEDTLS_ECP_INTERNAL_ALT) + +/** + * \brief Indicate if the Elliptic Curve Point module extension can + * handle the group. + * + * \param grp The pointer to the elliptic curve group that will be the + * basis of the cryptographic computations. + * + * \return Non-zero if successful. + */ +unsigned char mbedtls_internal_ecp_grp_capable( const mbedtls_ecp_group *grp ); + +/** + * \brief Initialise the Elliptic Curve Point module extension. + * + * If mbedtls_internal_ecp_grp_capable returns true for a + * group, this function has to be able to initialise the + * module for it. + * + * This module can be a driver to a crypto hardware + * accelerator, for which this could be an initialise function. + * + * \param grp The pointer to the group the module needs to be + * initialised for. + * + * \return 0 if successful. + */ +int mbedtls_internal_ecp_init( const mbedtls_ecp_group *grp ); + +/** + * \brief Frees and deallocates the Elliptic Curve Point module + * extension. + * + * \param grp The pointer to the group the module was initialised for. + */ +void mbedtls_internal_ecp_free( const mbedtls_ecp_group *grp ); + +#if defined(ECP_SHORTWEIERSTRASS) + +#if defined(MBEDTLS_ECP_RANDOMIZE_JAC_ALT) +/** + * \brief Randomize jacobian coordinates: + * (X, Y, Z) -> (l^2 X, l^3 Y, l Z) for random l. + * + * \param grp Pointer to the group representing the curve. + * + * \param pt The point on the curve to be randomised, given with Jacobian + * coordinates. + * + * \param f_rng A function pointer to the random number generator. + * + * \param p_rng A pointer to the random number generator state. + * + * \return 0 if successful. + */ +int mbedtls_internal_ecp_randomize_jac( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *pt, int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); +#endif + +#if defined(MBEDTLS_ECP_ADD_MIXED_ALT) +/** + * \brief Addition: R = P + Q, mixed affine-Jacobian coordinates. + * + * The coordinates of Q must be normalized (= affine), + * but those of P don't need to. R is not normalized. + * + * This function is used only as a subrutine of + * ecp_mul_comb(). + * + * Special cases: (1) P or Q is zero, (2) R is zero, + * (3) P == Q. + * None of these cases can happen as intermediate step in + * ecp_mul_comb(): + * - at each step, P, Q and R are multiples of the base + * point, the factor being less than its order, so none of + * them is zero; + * - Q is an odd multiple of the base point, P an even + * multiple, due to the choice of precomputed points in the + * modified comb method. + * So branches for these cases do not leak secret information. + * + * We accept Q->Z being unset (saving memory in tables) as + * meaning 1. + * + * Cost in field operations if done by [5] 3.22: + * 1A := 8M + 3S + * + * \param grp Pointer to the group representing the curve. + * + * \param R Pointer to a point structure to hold the result. + * + * \param P Pointer to the first summand, given with Jacobian + * coordinates + * + * \param Q Pointer to the second summand, given with affine + * coordinates. + * + * \return 0 if successful. + */ +int mbedtls_internal_ecp_add_mixed( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *R, const mbedtls_ecp_point *P, + const mbedtls_ecp_point *Q ); +#endif + +/** + * \brief Point doubling R = 2 P, Jacobian coordinates. + * + * Cost: 1D := 3M + 4S (A == 0) + * 4M + 4S (A == -3) + * 3M + 6S + 1a otherwise + * when the implementation is based on the "dbl-1998-cmo-2" + * doubling formulas in [8] and standard optimizations are + * applied when curve parameter A is one of { 0, -3 }. + * + * \param grp Pointer to the group representing the curve. + * + * \param R Pointer to a point structure to hold the result. + * + * \param P Pointer to the point that has to be doubled, given with + * Jacobian coordinates. + * + * \return 0 if successful. + */ +#if defined(MBEDTLS_ECP_DOUBLE_JAC_ALT) +int mbedtls_internal_ecp_double_jac( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *R, const mbedtls_ecp_point *P ); +#endif + +/** + * \brief Normalize jacobian coordinates of an array of (pointers to) + * points. + * + * Using Montgomery's trick to perform only one inversion mod P + * the cost is: + * 1N(t) := 1I + (6t - 3)M + 1S + * (See for example Algorithm 10.3.4. in [9]) + * + * This function is used only as a subrutine of + * ecp_mul_comb(). + * + * Warning: fails (returning an error) if one of the points is + * zero! + * This should never happen, see choice of w in ecp_mul_comb(). + * + * \param grp Pointer to the group representing the curve. + * + * \param T Array of pointers to the points to normalise. + * + * \param t_len Number of elements in the array. + * + * \return 0 if successful, + * an error if one of the points is zero. + */ +#if defined(MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT) +int mbedtls_internal_ecp_normalize_jac_many( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *T[], size_t t_len ); +#endif + +/** + * \brief Normalize jacobian coordinates so that Z == 0 || Z == 1. + * + * Cost in field operations if done by [5] 3.2.1: + * 1N := 1I + 3M + 1S + * + * \param grp Pointer to the group representing the curve. + * + * \param pt pointer to the point to be normalised. This is an + * input/output parameter. + * + * \return 0 if successful. + */ +#if defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT) +int mbedtls_internal_ecp_normalize_jac( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *pt ); +#endif + +#endif /* ECP_SHORTWEIERSTRASS */ + +#if defined(ECP_MONTGOMERY) + +#if defined(MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT) +int mbedtls_internal_ecp_double_add_mxz( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *R, mbedtls_ecp_point *S, const mbedtls_ecp_point *P, + const mbedtls_ecp_point *Q, const mbedtls_mpi *d ); +#endif + +/** + * \brief Randomize projective x/z coordinates: + * (X, Z) -> (l X, l Z) for random l + * + * \param grp pointer to the group representing the curve + * + * \param P the point on the curve to be randomised given with + * projective coordinates. This is an input/output parameter. + * + * \param f_rng a function pointer to the random number generator + * + * \param p_rng a pointer to the random number generator state + * + * \return 0 if successful + */ +#if defined(MBEDTLS_ECP_RANDOMIZE_MXZ_ALT) +int mbedtls_internal_ecp_randomize_mxz( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *P, int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); +#endif + +/** + * \brief Normalize Montgomery x/z coordinates: X = X/Z, Z = 1. + * + * \param grp pointer to the group representing the curve + * + * \param P pointer to the point to be normalised. This is an + * input/output parameter. + * + * \return 0 if successful + */ +#if defined(MBEDTLS_ECP_NORMALIZE_MXZ_ALT) +int mbedtls_internal_ecp_normalize_mxz( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *P ); +#endif + +#endif /* ECP_MONTGOMERY */ + +#endif /* MBEDTLS_ECP_INTERNAL_ALT */ + +#endif /* ecp_internal.h */ + diff --git a/common/mbedtls/entropy.c b/common/mbedtls/entropy.c new file mode 100644 index 00000000..33f92515 --- /dev/null +++ b/common/mbedtls/entropy.c @@ -0,0 +1,723 @@ +/* + * Entropy accumulator implementation + * + * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ENTROPY_C) + +#if defined(MBEDTLS_TEST_NULL_ENTROPY) +#warning "**** WARNING! MBEDTLS_TEST_NULL_ENTROPY defined! " +#warning "**** THIS BUILD HAS NO DEFINED ENTROPY SOURCES " +#warning "**** THIS BUILD IS *NOT* SUITABLE FOR PRODUCTION USE " +#endif + +#include "mbedtls/entropy.h" +#include "mbedtls/entropy_poll.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_FS_IO) +#include +#endif + +#if defined(MBEDTLS_ENTROPY_NV_SEED) +#include "mbedtls/platform.h" +#endif + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if defined(MBEDTLS_HAVEGE_C) +#include "mbedtls/havege.h" +#endif + +#define ENTROPY_MAX_LOOP 256 /**< Maximum amount to loop before error */ + +void mbedtls_entropy_init( mbedtls_entropy_context *ctx ) +{ + ctx->source_count = 0; + memset( ctx->source, 0, sizeof( ctx->source ) ); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init( &ctx->mutex ); +#endif + + ctx->accumulator_started = 0; +#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) + mbedtls_sha512_init( &ctx->accumulator ); +#else + mbedtls_sha256_init( &ctx->accumulator ); +#endif +#if defined(MBEDTLS_HAVEGE_C) + mbedtls_havege_init( &ctx->havege_data ); +#endif + + /* Reminder: Update ENTROPY_HAVE_STRONG in the test files + * when adding more strong entropy sources here. */ + +#if defined(MBEDTLS_TEST_NULL_ENTROPY) + mbedtls_entropy_add_source( ctx, mbedtls_null_entropy_poll, NULL, + 1, MBEDTLS_ENTROPY_SOURCE_STRONG ); +#endif + +#if !defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES) +#if !defined(MBEDTLS_NO_PLATFORM_ENTROPY) + mbedtls_entropy_add_source( ctx, mbedtls_platform_entropy_poll, NULL, + MBEDTLS_ENTROPY_MIN_PLATFORM, + MBEDTLS_ENTROPY_SOURCE_STRONG ); +#endif +#if defined(MBEDTLS_TIMING_C) + mbedtls_entropy_add_source( ctx, mbedtls_hardclock_poll, NULL, + MBEDTLS_ENTROPY_MIN_HARDCLOCK, + MBEDTLS_ENTROPY_SOURCE_WEAK ); +#endif +#if defined(MBEDTLS_HAVEGE_C) + mbedtls_entropy_add_source( ctx, mbedtls_havege_poll, &ctx->havege_data, + MBEDTLS_ENTROPY_MIN_HAVEGE, + MBEDTLS_ENTROPY_SOURCE_STRONG ); +#endif +#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) + mbedtls_entropy_add_source( ctx, mbedtls_hardware_poll, NULL, + MBEDTLS_ENTROPY_MIN_HARDWARE, + MBEDTLS_ENTROPY_SOURCE_STRONG ); +#endif +#if defined(MBEDTLS_ENTROPY_NV_SEED) + mbedtls_entropy_add_source( ctx, mbedtls_nv_seed_poll, NULL, + MBEDTLS_ENTROPY_BLOCK_SIZE, + MBEDTLS_ENTROPY_SOURCE_STRONG ); + ctx->initial_entropy_run = 0; +#endif +#endif /* MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES */ +} + +void mbedtls_entropy_free( mbedtls_entropy_context *ctx ) +{ +#if defined(MBEDTLS_HAVEGE_C) + mbedtls_havege_free( &ctx->havege_data ); +#endif +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_free( &ctx->mutex ); +#endif +#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) + mbedtls_sha512_free( &ctx->accumulator ); +#else + mbedtls_sha256_free( &ctx->accumulator ); +#endif +#if defined(MBEDTLS_ENTROPY_NV_SEED) + ctx->initial_entropy_run = 0; +#endif + ctx->source_count = 0; + mbedtls_platform_zeroize( ctx->source, sizeof( ctx->source ) ); + ctx->accumulator_started = 0; +} + +int mbedtls_entropy_add_source( mbedtls_entropy_context *ctx, + mbedtls_entropy_f_source_ptr f_source, void *p_source, + size_t threshold, int strong ) +{ + int idx, ret = 0; + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + idx = ctx->source_count; + if( idx >= MBEDTLS_ENTROPY_MAX_SOURCES ) + { + ret = MBEDTLS_ERR_ENTROPY_MAX_SOURCES; + goto exit; + } + + ctx->source[idx].f_source = f_source; + ctx->source[idx].p_source = p_source; + ctx->source[idx].threshold = threshold; + ctx->source[idx].strong = strong; + + ctx->source_count++; + +exit: +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} + +/* + * Entropy accumulator update + */ +static int entropy_update( mbedtls_entropy_context *ctx, unsigned char source_id, + const unsigned char *data, size_t len ) +{ + unsigned char header[2]; + unsigned char tmp[MBEDTLS_ENTROPY_BLOCK_SIZE]; + size_t use_len = len; + const unsigned char *p = data; + int ret = 0; + + if( use_len > MBEDTLS_ENTROPY_BLOCK_SIZE ) + { +#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) + if( ( ret = mbedtls_sha512_ret( data, len, tmp, 0 ) ) != 0 ) + goto cleanup; +#else + if( ( ret = mbedtls_sha256_ret( data, len, tmp, 0 ) ) != 0 ) + goto cleanup; +#endif + p = tmp; + use_len = MBEDTLS_ENTROPY_BLOCK_SIZE; + } + + header[0] = source_id; + header[1] = use_len & 0xFF; + + /* + * Start the accumulator if this has not already happened. Note that + * it is sufficient to start the accumulator here only because all calls to + * gather entropy eventually execute this code. + */ +#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) + if( ctx->accumulator_started == 0 && + ( ret = mbedtls_sha512_starts_ret( &ctx->accumulator, 0 ) ) != 0 ) + goto cleanup; + else + ctx->accumulator_started = 1; + if( ( ret = mbedtls_sha512_update_ret( &ctx->accumulator, header, 2 ) ) != 0 ) + goto cleanup; + ret = mbedtls_sha512_update_ret( &ctx->accumulator, p, use_len ); +#else + if( ctx->accumulator_started == 0 && + ( ret = mbedtls_sha256_starts_ret( &ctx->accumulator, 0 ) ) != 0 ) + goto cleanup; + else + ctx->accumulator_started = 1; + if( ( ret = mbedtls_sha256_update_ret( &ctx->accumulator, header, 2 ) ) != 0 ) + goto cleanup; + ret = mbedtls_sha256_update_ret( &ctx->accumulator, p, use_len ); +#endif + +cleanup: + mbedtls_platform_zeroize( tmp, sizeof( tmp ) ); + + return( ret ); +} + +int mbedtls_entropy_update_manual( mbedtls_entropy_context *ctx, + const unsigned char *data, size_t len ) +{ + int ret; + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + ret = entropy_update( ctx, MBEDTLS_ENTROPY_SOURCE_MANUAL, data, len ); + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} + +/* + * Run through the different sources to add entropy to our accumulator + */ +static int entropy_gather_internal( mbedtls_entropy_context *ctx ) +{ + int ret, i, have_one_strong = 0; + unsigned char buf[MBEDTLS_ENTROPY_MAX_GATHER]; + size_t olen; + + if( ctx->source_count == 0 ) + return( MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED ); + + /* + * Run through our entropy sources + */ + for( i = 0; i < ctx->source_count; i++ ) + { + if( ctx->source[i].strong == MBEDTLS_ENTROPY_SOURCE_STRONG ) + have_one_strong = 1; + + olen = 0; + if( ( ret = ctx->source[i].f_source( ctx->source[i].p_source, + buf, MBEDTLS_ENTROPY_MAX_GATHER, &olen ) ) != 0 ) + { + goto cleanup; + } + + /* + * Add if we actually gathered something + */ + if( olen > 0 ) + { + if( ( ret = entropy_update( ctx, (unsigned char) i, + buf, olen ) ) != 0 ) + return( ret ); + ctx->source[i].size += olen; + } + } + + if( have_one_strong == 0 ) + ret = MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE; + +cleanup: + mbedtls_platform_zeroize( buf, sizeof( buf ) ); + + return( ret ); +} + +/* + * Thread-safe wrapper for entropy_gather_internal() + */ +int mbedtls_entropy_gather( mbedtls_entropy_context *ctx ) +{ + int ret; + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + ret = entropy_gather_internal( ctx ); + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} + +int mbedtls_entropy_func( void *data, unsigned char *output, size_t len ) +{ + int ret, count = 0, i, done; + mbedtls_entropy_context *ctx = (mbedtls_entropy_context *) data; + unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; + + if( len > MBEDTLS_ENTROPY_BLOCK_SIZE ) + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + +#if defined(MBEDTLS_ENTROPY_NV_SEED) + /* Update the NV entropy seed before generating any entropy for outside + * use. + */ + if( ctx->initial_entropy_run == 0 ) + { + ctx->initial_entropy_run = 1; + if( ( ret = mbedtls_entropy_update_nv_seed( ctx ) ) != 0 ) + return( ret ); + } +#endif + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + /* + * Always gather extra entropy before a call + */ + do + { + if( count++ > ENTROPY_MAX_LOOP ) + { + ret = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; + goto exit; + } + + if( ( ret = entropy_gather_internal( ctx ) ) != 0 ) + goto exit; + + done = 1; + for( i = 0; i < ctx->source_count; i++ ) + if( ctx->source[i].size < ctx->source[i].threshold ) + done = 0; + } + while( ! done ); + + memset( buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE ); + +#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) + /* + * Note that at this stage it is assumed that the accumulator was started + * in a previous call to entropy_update(). If this is not guaranteed, the + * code below will fail. + */ + if( ( ret = mbedtls_sha512_finish_ret( &ctx->accumulator, buf ) ) != 0 ) + goto exit; + + /* + * Reset accumulator and counters and recycle existing entropy + */ + mbedtls_sha512_free( &ctx->accumulator ); + mbedtls_sha512_init( &ctx->accumulator ); + if( ( ret = mbedtls_sha512_starts_ret( &ctx->accumulator, 0 ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_sha512_update_ret( &ctx->accumulator, buf, + MBEDTLS_ENTROPY_BLOCK_SIZE ) ) != 0 ) + goto exit; + + /* + * Perform second SHA-512 on entropy + */ + if( ( ret = mbedtls_sha512_ret( buf, MBEDTLS_ENTROPY_BLOCK_SIZE, + buf, 0 ) ) != 0 ) + goto exit; +#else /* MBEDTLS_ENTROPY_SHA512_ACCUMULATOR */ + if( ( ret = mbedtls_sha256_finish_ret( &ctx->accumulator, buf ) ) != 0 ) + goto exit; + + /* + * Reset accumulator and counters and recycle existing entropy + */ + mbedtls_sha256_free( &ctx->accumulator ); + mbedtls_sha256_init( &ctx->accumulator ); + if( ( ret = mbedtls_sha256_starts_ret( &ctx->accumulator, 0 ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_sha256_update_ret( &ctx->accumulator, buf, + MBEDTLS_ENTROPY_BLOCK_SIZE ) ) != 0 ) + goto exit; + + /* + * Perform second SHA-256 on entropy + */ + if( ( ret = mbedtls_sha256_ret( buf, MBEDTLS_ENTROPY_BLOCK_SIZE, + buf, 0 ) ) != 0 ) + goto exit; +#endif /* MBEDTLS_ENTROPY_SHA512_ACCUMULATOR */ + + for( i = 0; i < ctx->source_count; i++ ) + ctx->source[i].size = 0; + + memcpy( output, buf, len ); + + ret = 0; + +exit: + mbedtls_platform_zeroize( buf, sizeof( buf ) ); + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} + +#if defined(MBEDTLS_ENTROPY_NV_SEED) +int mbedtls_entropy_update_nv_seed( mbedtls_entropy_context *ctx ) +{ + int ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; + unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; + + /* Read new seed and write it to NV */ + if( ( ret = mbedtls_entropy_func( ctx, buf, MBEDTLS_ENTROPY_BLOCK_SIZE ) ) != 0 ) + return( ret ); + + if( mbedtls_nv_seed_write( buf, MBEDTLS_ENTROPY_BLOCK_SIZE ) < 0 ) + return( MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR ); + + /* Manually update the remaining stream with a separator value to diverge */ + memset( buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE ); + ret = mbedtls_entropy_update_manual( ctx, buf, MBEDTLS_ENTROPY_BLOCK_SIZE ); + + return( ret ); +} +#endif /* MBEDTLS_ENTROPY_NV_SEED */ + +#if defined(MBEDTLS_FS_IO) +int mbedtls_entropy_write_seed_file( mbedtls_entropy_context *ctx, const char *path ) +{ + int ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; + FILE *f; + unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; + + if( ( f = fopen( path, "wb" ) ) == NULL ) + return( MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR ); + + if( ( ret = mbedtls_entropy_func( ctx, buf, MBEDTLS_ENTROPY_BLOCK_SIZE ) ) != 0 ) + goto exit; + + if( fwrite( buf, 1, MBEDTLS_ENTROPY_BLOCK_SIZE, f ) != MBEDTLS_ENTROPY_BLOCK_SIZE ) + { + ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; + goto exit; + } + + ret = 0; + +exit: + mbedtls_platform_zeroize( buf, sizeof( buf ) ); + + fclose( f ); + return( ret ); +} + +int mbedtls_entropy_update_seed_file( mbedtls_entropy_context *ctx, const char *path ) +{ + int ret = 0; + FILE *f; + size_t n; + unsigned char buf[ MBEDTLS_ENTROPY_MAX_SEED_SIZE ]; + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR ); + + fseek( f, 0, SEEK_END ); + n = (size_t) ftell( f ); + fseek( f, 0, SEEK_SET ); + + if( n > MBEDTLS_ENTROPY_MAX_SEED_SIZE ) + n = MBEDTLS_ENTROPY_MAX_SEED_SIZE; + + if( fread( buf, 1, n, f ) != n ) + ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; + else + ret = mbedtls_entropy_update_manual( ctx, buf, n ); + + fclose( f ); + + mbedtls_platform_zeroize( buf, sizeof( buf ) ); + + if( ret != 0 ) + return( ret ); + + return( mbedtls_entropy_write_seed_file( ctx, path ) ); +} +#endif /* MBEDTLS_FS_IO */ + +#if defined(MBEDTLS_SELF_TEST) +#if !defined(MBEDTLS_TEST_NULL_ENTROPY) +/* + * Dummy source function + */ +static int entropy_dummy_source( void *data, unsigned char *output, + size_t len, size_t *olen ) +{ + ((void) data); + + memset( output, 0x2a, len ); + *olen = len; + + return( 0 ); +} +#endif /* !MBEDTLS_TEST_NULL_ENTROPY */ + +#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) + +static int mbedtls_entropy_source_self_test_gather( unsigned char *buf, size_t buf_len ) +{ + int ret = 0; + size_t entropy_len = 0; + size_t olen = 0; + size_t attempts = buf_len; + + while( attempts > 0 && entropy_len < buf_len ) + { + if( ( ret = mbedtls_hardware_poll( NULL, buf + entropy_len, + buf_len - entropy_len, &olen ) ) != 0 ) + return( ret ); + + entropy_len += olen; + attempts--; + } + + if( entropy_len < buf_len ) + { + ret = 1; + } + + return( ret ); +} + + +static int mbedtls_entropy_source_self_test_check_bits( const unsigned char *buf, + size_t buf_len ) +{ + unsigned char set= 0xFF; + unsigned char unset = 0x00; + size_t i; + + for( i = 0; i < buf_len; i++ ) + { + set &= buf[i]; + unset |= buf[i]; + } + + return( set == 0xFF || unset == 0x00 ); +} + +/* + * A test to ensure hat the entropy sources are functioning correctly + * and there is no obvious failure. The test performs the following checks: + * - The entropy source is not providing only 0s (all bits unset) or 1s (all + * bits set). + * - The entropy source is not providing values in a pattern. Because the + * hardware could be providing data in an arbitrary length, this check polls + * the hardware entropy source twice and compares the result to ensure they + * are not equal. + * - The error code returned by the entropy source is not an error. + */ +int mbedtls_entropy_source_self_test( int verbose ) +{ + int ret = 0; + unsigned char buf0[2 * sizeof( unsigned long long int )]; + unsigned char buf1[2 * sizeof( unsigned long long int )]; + + if( verbose != 0 ) + mbedtls_printf( " ENTROPY_BIAS test: " ); + + memset( buf0, 0x00, sizeof( buf0 ) ); + memset( buf1, 0x00, sizeof( buf1 ) ); + + if( ( ret = mbedtls_entropy_source_self_test_gather( buf0, sizeof( buf0 ) ) ) != 0 ) + goto cleanup; + if( ( ret = mbedtls_entropy_source_self_test_gather( buf1, sizeof( buf1 ) ) ) != 0 ) + goto cleanup; + + /* Make sure that the returned values are not all 0 or 1 */ + if( ( ret = mbedtls_entropy_source_self_test_check_bits( buf0, sizeof( buf0 ) ) ) != 0 ) + goto cleanup; + if( ( ret = mbedtls_entropy_source_self_test_check_bits( buf1, sizeof( buf1 ) ) ) != 0 ) + goto cleanup; + + /* Make sure that the entropy source is not returning values in a + * pattern */ + ret = memcmp( buf0, buf1, sizeof( buf0 ) ) == 0; + +cleanup: + if( verbose != 0 ) + { + if( ret != 0 ) + mbedtls_printf( "failed\n" ); + else + mbedtls_printf( "passed\n" ); + + mbedtls_printf( "\n" ); + } + + return( ret != 0 ); +} + +#endif /* MBEDTLS_ENTROPY_HARDWARE_ALT */ + +/* + * The actual entropy quality is hard to test, but we can at least + * test that the functions don't cause errors and write the correct + * amount of data to buffers. + */ +int mbedtls_entropy_self_test( int verbose ) +{ + int ret = 1; +#if !defined(MBEDTLS_TEST_NULL_ENTROPY) + mbedtls_entropy_context ctx; + unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 }; + unsigned char acc[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 }; + size_t i, j; +#endif /* !MBEDTLS_TEST_NULL_ENTROPY */ + + if( verbose != 0 ) + mbedtls_printf( " ENTROPY test: " ); + +#if !defined(MBEDTLS_TEST_NULL_ENTROPY) + mbedtls_entropy_init( &ctx ); + + /* First do a gather to make sure we have default sources */ + if( ( ret = mbedtls_entropy_gather( &ctx ) ) != 0 ) + goto cleanup; + + ret = mbedtls_entropy_add_source( &ctx, entropy_dummy_source, NULL, 16, + MBEDTLS_ENTROPY_SOURCE_WEAK ); + if( ret != 0 ) + goto cleanup; + + if( ( ret = mbedtls_entropy_update_manual( &ctx, buf, sizeof buf ) ) != 0 ) + goto cleanup; + + /* + * To test that mbedtls_entropy_func writes correct number of bytes: + * - use the whole buffer and rely on ASan to detect overruns + * - collect entropy 8 times and OR the result in an accumulator: + * any byte should then be 0 with probably 2^(-64), so requiring + * each of the 32 or 64 bytes to be non-zero has a false failure rate + * of at most 2^(-58) which is acceptable. + */ + for( i = 0; i < 8; i++ ) + { + if( ( ret = mbedtls_entropy_func( &ctx, buf, sizeof( buf ) ) ) != 0 ) + goto cleanup; + + for( j = 0; j < sizeof( buf ); j++ ) + acc[j] |= buf[j]; + } + + for( j = 0; j < sizeof( buf ); j++ ) + { + if( acc[j] == 0 ) + { + ret = 1; + goto cleanup; + } + } + +#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) + if( ( ret = mbedtls_entropy_source_self_test( 0 ) ) != 0 ) + goto cleanup; +#endif + +cleanup: + mbedtls_entropy_free( &ctx ); +#endif /* !MBEDTLS_TEST_NULL_ENTROPY */ + + if( verbose != 0 ) + { + if( ret != 0 ) + mbedtls_printf( "failed\n" ); + else + mbedtls_printf( "passed\n" ); + + mbedtls_printf( "\n" ); + } + + return( ret != 0 ); +} +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_ENTROPY_C */ diff --git a/common/mbedtls/entropy.h b/common/mbedtls/entropy.h new file mode 100644 index 00000000..b1e8c4cd --- /dev/null +++ b/common/mbedtls/entropy.h @@ -0,0 +1,291 @@ +/** + * \file entropy.h + * + * \brief Entropy accumulator implementation + */ +/* + * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_ENTROPY_H +#define MBEDTLS_ENTROPY_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#if defined(MBEDTLS_SHA512_C) && !defined(MBEDTLS_ENTROPY_FORCE_SHA256) +#include "sha512.h" +#define MBEDTLS_ENTROPY_SHA512_ACCUMULATOR +#else +#if defined(MBEDTLS_SHA256_C) +#define MBEDTLS_ENTROPY_SHA256_ACCUMULATOR +#include "sha256.h" +#endif +#endif + +#if defined(MBEDTLS_THREADING_C) +#include "threading.h" +#endif + +#if defined(MBEDTLS_HAVEGE_C) +#include "havege.h" +#endif + +#define MBEDTLS_ERR_ENTROPY_SOURCE_FAILED -0x003C /**< Critical entropy source failure. */ +#define MBEDTLS_ERR_ENTROPY_MAX_SOURCES -0x003E /**< No more sources can be added. */ +#define MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED -0x0040 /**< No sources have been added to poll. */ +#define MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE -0x003D /**< No strong sources have been added to poll. */ +#define MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR -0x003F /**< Read/write error in file. */ + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h or define them on the compiler command line. + * \{ + */ + +#if !defined(MBEDTLS_ENTROPY_MAX_SOURCES) +#define MBEDTLS_ENTROPY_MAX_SOURCES 20 /**< Maximum number of sources supported */ +#endif + +#if !defined(MBEDTLS_ENTROPY_MAX_GATHER) +#define MBEDTLS_ENTROPY_MAX_GATHER 128 /**< Maximum amount requested from entropy sources */ +#endif + +/* \} name SECTION: Module settings */ + +#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) +#define MBEDTLS_ENTROPY_BLOCK_SIZE 64 /**< Block size of entropy accumulator (SHA-512) */ +#else +#define MBEDTLS_ENTROPY_BLOCK_SIZE 32 /**< Block size of entropy accumulator (SHA-256) */ +#endif + +#define MBEDTLS_ENTROPY_MAX_SEED_SIZE 1024 /**< Maximum size of seed we read from seed file */ +#define MBEDTLS_ENTROPY_SOURCE_MANUAL MBEDTLS_ENTROPY_MAX_SOURCES + +#define MBEDTLS_ENTROPY_SOURCE_STRONG 1 /**< Entropy source is strong */ +#define MBEDTLS_ENTROPY_SOURCE_WEAK 0 /**< Entropy source is weak */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Entropy poll callback pointer + * + * \param data Callback-specific data pointer + * \param output Data to fill + * \param len Maximum size to provide + * \param olen The actual amount of bytes put into the buffer (Can be 0) + * + * \return 0 if no critical failures occurred, + * MBEDTLS_ERR_ENTROPY_SOURCE_FAILED otherwise + */ +typedef int (*mbedtls_entropy_f_source_ptr)(void *data, unsigned char *output, size_t len, + size_t *olen); + +/** + * \brief Entropy source state + */ +typedef struct mbedtls_entropy_source_state +{ + mbedtls_entropy_f_source_ptr f_source; /**< The entropy source callback */ + void * p_source; /**< The callback data pointer */ + size_t size; /**< Amount received in bytes */ + size_t threshold; /**< Minimum bytes required before release */ + int strong; /**< Is the source strong? */ +} +mbedtls_entropy_source_state; + +/** + * \brief Entropy context structure + */ +typedef struct mbedtls_entropy_context +{ + int accumulator_started; +#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) + mbedtls_sha512_context accumulator; +#else + mbedtls_sha256_context accumulator; +#endif + int source_count; + mbedtls_entropy_source_state source[MBEDTLS_ENTROPY_MAX_SOURCES]; +#if defined(MBEDTLS_HAVEGE_C) + mbedtls_havege_state havege_data; +#endif +#if defined(MBEDTLS_THREADING_C) + mbedtls_threading_mutex_t mutex; /*!< mutex */ +#endif +#if defined(MBEDTLS_ENTROPY_NV_SEED) + int initial_entropy_run; +#endif +} +mbedtls_entropy_context; + +/** + * \brief Initialize the context + * + * \param ctx Entropy context to initialize + */ +void mbedtls_entropy_init( mbedtls_entropy_context *ctx ); + +/** + * \brief Free the data in the context + * + * \param ctx Entropy context to free + */ +void mbedtls_entropy_free( mbedtls_entropy_context *ctx ); + +/** + * \brief Adds an entropy source to poll + * (Thread-safe if MBEDTLS_THREADING_C is enabled) + * + * \param ctx Entropy context + * \param f_source Entropy function + * \param p_source Function data + * \param threshold Minimum required from source before entropy is released + * ( with mbedtls_entropy_func() ) (in bytes) + * \param strong MBEDTLS_ENTROPY_SOURCE_STRONG or + * MBEDTLS_ENTROPY_SOURCE_WEAK. + * At least one strong source needs to be added. + * Weaker sources (such as the cycle counter) can be used as + * a complement. + * + * \return 0 if successful or MBEDTLS_ERR_ENTROPY_MAX_SOURCES + */ +int mbedtls_entropy_add_source( mbedtls_entropy_context *ctx, + mbedtls_entropy_f_source_ptr f_source, void *p_source, + size_t threshold, int strong ); + +/** + * \brief Trigger an extra gather poll for the accumulator + * (Thread-safe if MBEDTLS_THREADING_C is enabled) + * + * \param ctx Entropy context + * + * \return 0 if successful, or MBEDTLS_ERR_ENTROPY_SOURCE_FAILED + */ +int mbedtls_entropy_gather( mbedtls_entropy_context *ctx ); + +/** + * \brief Retrieve entropy from the accumulator + * (Maximum length: MBEDTLS_ENTROPY_BLOCK_SIZE) + * (Thread-safe if MBEDTLS_THREADING_C is enabled) + * + * \param data Entropy context + * \param output Buffer to fill + * \param len Number of bytes desired, must be at most MBEDTLS_ENTROPY_BLOCK_SIZE + * + * \return 0 if successful, or MBEDTLS_ERR_ENTROPY_SOURCE_FAILED + */ +int mbedtls_entropy_func( void *data, unsigned char *output, size_t len ); + +/** + * \brief Add data to the accumulator manually + * (Thread-safe if MBEDTLS_THREADING_C is enabled) + * + * \param ctx Entropy context + * \param data Data to add + * \param len Length of data + * + * \return 0 if successful + */ +int mbedtls_entropy_update_manual( mbedtls_entropy_context *ctx, + const unsigned char *data, size_t len ); + +#if defined(MBEDTLS_ENTROPY_NV_SEED) +/** + * \brief Trigger an update of the seed file in NV by using the + * current entropy pool. + * + * \param ctx Entropy context + * + * \return 0 if successful + */ +int mbedtls_entropy_update_nv_seed( mbedtls_entropy_context *ctx ); +#endif /* MBEDTLS_ENTROPY_NV_SEED */ + +#if defined(MBEDTLS_FS_IO) +/** + * \brief Write a seed file + * + * \param ctx Entropy context + * \param path Name of the file + * + * \return 0 if successful, + * MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR on file error, or + * MBEDTLS_ERR_ENTROPY_SOURCE_FAILED + */ +int mbedtls_entropy_write_seed_file( mbedtls_entropy_context *ctx, const char *path ); + +/** + * \brief Read and update a seed file. Seed is added to this + * instance. No more than MBEDTLS_ENTROPY_MAX_SEED_SIZE bytes are + * read from the seed file. The rest is ignored. + * + * \param ctx Entropy context + * \param path Name of the file + * + * \return 0 if successful, + * MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR on file error, + * MBEDTLS_ERR_ENTROPY_SOURCE_FAILED + */ +int mbedtls_entropy_update_seed_file( mbedtls_entropy_context *ctx, const char *path ); +#endif /* MBEDTLS_FS_IO */ + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief Checkup routine + * + * This module self-test also calls the entropy self-test, + * mbedtls_entropy_source_self_test(); + * + * \return 0 if successful, or 1 if a test failed + */ +int mbedtls_entropy_self_test( int verbose ); + +#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) +/** + * \brief Checkup routine + * + * Verifies the integrity of the hardware entropy source + * provided by the function 'mbedtls_hardware_poll()'. + * + * Note this is the only hardware entropy source that is known + * at link time, and other entropy sources configured + * dynamically at runtime by the function + * mbedtls_entropy_add_source() will not be tested. + * + * \return 0 if successful, or 1 if a test failed + */ +int mbedtls_entropy_source_self_test( int verbose ); +#endif /* MBEDTLS_ENTROPY_HARDWARE_ALT */ +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* entropy.h */ diff --git a/common/mbedtls/entropy_poll.c b/common/mbedtls/entropy_poll.c new file mode 100644 index 00000000..e8b8da86 --- /dev/null +++ b/common/mbedtls/entropy_poll.c @@ -0,0 +1,277 @@ +/* + * Platform-specific and custom entropy polling functions + * + * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if defined(__linux__) +/* Ensure that syscall() is available even when compiling with -std=c99 */ +#define _GNU_SOURCE +#endif + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#if defined(MBEDTLS_ENTROPY_C) + +#include "mbedtls/entropy.h" +#include "mbedtls/entropy_poll.h" + +#if defined(MBEDTLS_TIMING_C) +#include "mbedtls/timing.h" +#endif +#if defined(MBEDTLS_HAVEGE_C) +#include "mbedtls/havege.h" +#endif +#if defined(MBEDTLS_ENTROPY_NV_SEED) +#include "mbedtls/platform.h" +#endif + +#if !defined(MBEDTLS_NO_PLATFORM_ENTROPY) + +#if !defined(unix) && !defined(__unix__) && !defined(__unix) && \ + !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \ + !defined(__HAIKU__) +#error "Platform entropy sources only work on Unix and Windows, see MBEDTLS_NO_PLATFORM_ENTROPY in config.h" +#endif + +#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) + +#if !defined(_WIN32_WINNT) +#define _WIN32_WINNT 0x0400 +#endif +#include +#include + +int mbedtls_platform_entropy_poll( void *data, unsigned char *output, size_t len, + size_t *olen ) +{ + HCRYPTPROV provider; + ((void) data); + *olen = 0; + + if( CryptAcquireContext( &provider, NULL, NULL, + PROV_RSA_FULL, CRYPT_VERIFYCONTEXT ) == FALSE ) + { + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + } + + if( CryptGenRandom( provider, (DWORD) len, output ) == FALSE ) + { + CryptReleaseContext( provider, 0 ); + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + } + + CryptReleaseContext( provider, 0 ); + *olen = len; + + return( 0 ); +} +#else /* _WIN32 && !EFIX64 && !EFI32 */ + +/* + * Test for Linux getrandom() support. + * Since there is no wrapper in the libc yet, use the generic syscall wrapper + * available in GNU libc and compatible libc's (eg uClibc). + */ +#if defined(__linux__) && defined(__GLIBC__) +#include +#include +#if defined(SYS_getrandom) +#define HAVE_GETRANDOM + +static int getrandom_wrapper( void *buf, size_t buflen, unsigned int flags ) +{ + /* MemSan cannot understand that the syscall writes to the buffer */ +#if defined(__has_feature) +#if __has_feature(memory_sanitizer) + memset( buf, 0, buflen ); +#endif +#endif + + return( syscall( SYS_getrandom, buf, buflen, flags ) ); +} + +#include +/* Check if version is at least 3.17.0 */ +static int check_version_3_17_plus( void ) +{ + int minor; + struct utsname un; + const char *ver; + + /* Get version information */ + uname(&un); + ver = un.release; + + /* Check major version; assume a single digit */ + if( ver[0] < '3' || ver[0] > '9' || ver [1] != '.' ) + return( -1 ); + + if( ver[0] - '0' > 3 ) + return( 0 ); + + /* Ok, so now we know major == 3, check minor. + * Assume 1 or 2 digits. */ + if( ver[2] < '0' || ver[2] > '9' ) + return( -1 ); + + minor = ver[2] - '0'; + + if( ver[3] >= '0' && ver[3] <= '9' ) + minor = 10 * minor + ver[3] - '0'; + else if( ver [3] != '.' ) + return( -1 ); + + if( minor < 17 ) + return( -1 ); + + return( 0 ); +} +static int has_getrandom = -1; +#endif /* SYS_getrandom */ +#endif /* __linux__ */ + +#include + +int mbedtls_platform_entropy_poll( void *data, + unsigned char *output, size_t len, size_t *olen ) +{ + FILE *file; + size_t read_len; + ((void) data); + +#if defined(HAVE_GETRANDOM) + if( has_getrandom == -1 ) + has_getrandom = ( check_version_3_17_plus() == 0 ); + + if( has_getrandom ) + { + int ret; + + if( ( ret = getrandom_wrapper( output, len, 0 ) ) < 0 ) + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + + *olen = ret; + return( 0 ); + } +#endif /* HAVE_GETRANDOM */ + + *olen = 0; + + file = fopen( "/dev/urandom", "rb" ); + if( file == NULL ) + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + + read_len = fread( output, 1, len, file ); + if( read_len != len ) + { + fclose( file ); + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + } + + fclose( file ); + *olen = len; + + return( 0 ); +} +#endif /* _WIN32 && !EFIX64 && !EFI32 */ +#endif /* !MBEDTLS_NO_PLATFORM_ENTROPY */ + +#if defined(MBEDTLS_TEST_NULL_ENTROPY) +int mbedtls_null_entropy_poll( void *data, + unsigned char *output, size_t len, size_t *olen ) +{ + ((void) data); + ((void) output); + *olen = 0; + + if( len < sizeof(unsigned char) ) + return( 0 ); + + *olen = sizeof(unsigned char); + + return( 0 ); +} +#endif + +#if defined(MBEDTLS_TIMING_C) +int mbedtls_hardclock_poll( void *data, + unsigned char *output, size_t len, size_t *olen ) +{ + unsigned long timer = mbedtls_timing_hardclock(); + ((void) data); + *olen = 0; + + if( len < sizeof(unsigned long) ) + return( 0 ); + + memcpy( output, &timer, sizeof(unsigned long) ); + *olen = sizeof(unsigned long); + + return( 0 ); +} +#endif /* MBEDTLS_TIMING_C */ + +#if defined(MBEDTLS_HAVEGE_C) +int mbedtls_havege_poll( void *data, + unsigned char *output, size_t len, size_t *olen ) +{ + mbedtls_havege_state *hs = (mbedtls_havege_state *) data; + *olen = 0; + + if( mbedtls_havege_random( hs, output, len ) != 0 ) + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + + *olen = len; + + return( 0 ); +} +#endif /* MBEDTLS_HAVEGE_C */ + +#if defined(MBEDTLS_ENTROPY_NV_SEED) +int mbedtls_nv_seed_poll( void *data, + unsigned char *output, size_t len, size_t *olen ) +{ + unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; + size_t use_len = MBEDTLS_ENTROPY_BLOCK_SIZE; + ((void) data); + + memset( buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE ); + + if( mbedtls_nv_seed_read( buf, MBEDTLS_ENTROPY_BLOCK_SIZE ) < 0 ) + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + + if( len < use_len ) + use_len = len; + + memcpy( output, buf, use_len ); + *olen = use_len; + + return( 0 ); +} +#endif /* MBEDTLS_ENTROPY_NV_SEED */ + +#endif /* MBEDTLS_ENTROPY_C */ diff --git a/common/mbedtls/entropy_poll.h b/common/mbedtls/entropy_poll.h new file mode 100644 index 00000000..d48b8555 --- /dev/null +++ b/common/mbedtls/entropy_poll.h @@ -0,0 +1,112 @@ +/** + * \file entropy_poll.h + * + * \brief Platform-specific and custom entropy polling functions + */ +/* + * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_ENTROPY_POLL_H +#define MBEDTLS_ENTROPY_POLL_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Default thresholds for built-in sources, in bytes + */ +#define MBEDTLS_ENTROPY_MIN_PLATFORM 32 /**< Minimum for platform source */ +#define MBEDTLS_ENTROPY_MIN_HAVEGE 32 /**< Minimum for HAVEGE */ +#define MBEDTLS_ENTROPY_MIN_HARDCLOCK 4 /**< Minimum for mbedtls_timing_hardclock() */ +#if !defined(MBEDTLS_ENTROPY_MIN_HARDWARE) +#define MBEDTLS_ENTROPY_MIN_HARDWARE 32 /**< Minimum for the hardware source */ +#endif + +/** + * \brief Entropy poll callback that provides 0 entropy. + */ +#if defined(MBEDTLS_TEST_NULL_ENTROPY) + int mbedtls_null_entropy_poll( void *data, + unsigned char *output, size_t len, size_t *olen ); +#endif + +#if !defined(MBEDTLS_NO_PLATFORM_ENTROPY) +/** + * \brief Platform-specific entropy poll callback + */ +int mbedtls_platform_entropy_poll( void *data, + unsigned char *output, size_t len, size_t *olen ); +#endif + +#if defined(MBEDTLS_HAVEGE_C) +/** + * \brief HAVEGE based entropy poll callback + * + * Requires an HAVEGE state as its data pointer. + */ +int mbedtls_havege_poll( void *data, + unsigned char *output, size_t len, size_t *olen ); +#endif + +#if defined(MBEDTLS_TIMING_C) +/** + * \brief mbedtls_timing_hardclock-based entropy poll callback + */ +int mbedtls_hardclock_poll( void *data, + unsigned char *output, size_t len, size_t *olen ); +#endif + +#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) +/** + * \brief Entropy poll callback for a hardware source + * + * \warning This is not provided by mbed TLS! + * See \c MBEDTLS_ENTROPY_HARDWARE_ALT in config.h. + * + * \note This must accept NULL as its first argument. + */ +int mbedtls_hardware_poll( void *data, + unsigned char *output, size_t len, size_t *olen ); +#endif + +#if defined(MBEDTLS_ENTROPY_NV_SEED) +/** + * \brief Entropy poll callback for a non-volatile seed file + * + * \note This must accept NULL as its first argument. + */ +int mbedtls_nv_seed_poll( void *data, + unsigned char *output, size_t len, size_t *olen ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* entropy_poll.h */ diff --git a/common/mbedtls/error.c b/common/mbedtls/error.c new file mode 100644 index 00000000..d8c0ddc6 --- /dev/null +++ b/common/mbedtls/error.c @@ -0,0 +1,897 @@ +/* + * Error message information + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ERROR_C) || defined(MBEDTLS_ERROR_STRERROR_DUMMY) +#include "mbedtls/error.h" +#include +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#define mbedtls_snprintf snprintf +#define mbedtls_time_t time_t +#endif + +#if defined(MBEDTLS_ERROR_C) + +#include + +#if defined(MBEDTLS_AES_C) +#include "mbedtls/aes.h" +#endif + +#if defined(MBEDTLS_ARC4_C) +#include "mbedtls/arc4.h" +#endif + +#if defined(MBEDTLS_ARIA_C) +#include "mbedtls/aria.h" +#endif + +#if defined(MBEDTLS_BASE64_C) +#include "mbedtls/base64.h" +#endif + +#if defined(MBEDTLS_BIGNUM_C) +#include "mbedtls/bignum.h" +#endif + +#if defined(MBEDTLS_BLOWFISH_C) +#include "mbedtls/blowfish.h" +#endif + +#if defined(MBEDTLS_CAMELLIA_C) +#include "mbedtls/camellia.h" +#endif + +#if defined(MBEDTLS_CCM_C) +#include "mbedtls/ccm.h" +#endif + +#if defined(MBEDTLS_CHACHA20_C) +#include "mbedtls/chacha20.h" +#endif + +#if defined(MBEDTLS_CHACHAPOLY_C) +#include "mbedtls/chachapoly.h" +#endif + +#if defined(MBEDTLS_CIPHER_C) +#include "mbedtls/cipher.h" +#endif + +#if defined(MBEDTLS_CMAC_C) +#include "mbedtls/cmac.h" +#endif + +#if defined(MBEDTLS_CTR_DRBG_C) +#include "mbedtls/ctr_drbg.h" +#endif + +#if defined(MBEDTLS_DES_C) +#include "mbedtls/des.h" +#endif + +#if defined(MBEDTLS_DHM_C) +#include "mbedtls/dhm.h" +#endif + +#if defined(MBEDTLS_ECP_C) +#include "mbedtls/ecp.h" +#endif + +#if defined(MBEDTLS_ENTROPY_C) +#include "mbedtls/entropy.h" +#endif + +#if defined(MBEDTLS_GCM_C) +#include "mbedtls/gcm.h" +#endif + +#if defined(MBEDTLS_HKDF_C) +#include "mbedtls/hkdf.h" +#endif + +#if defined(MBEDTLS_HMAC_DRBG_C) +#include "mbedtls/hmac_drbg.h" +#endif + +#if defined(MBEDTLS_MD_C) +#include "mbedtls/md.h" +#endif + +#if defined(MBEDTLS_MD2_C) +#include "mbedtls/md2.h" +#endif + +#if defined(MBEDTLS_MD4_C) +#include "mbedtls/md4.h" +#endif + +#if defined(MBEDTLS_MD5_C) +#include "mbedtls/md5.h" +#endif + +#if defined(MBEDTLS_NET_C) +#include "mbedtls/net_sockets.h" +#endif + +#if defined(MBEDTLS_OID_C) +#include "mbedtls/oid.h" +#endif + +#if defined(MBEDTLS_PADLOCK_C) +#include "mbedtls/padlock.h" +#endif + +#if defined(MBEDTLS_PEM_PARSE_C) || defined(MBEDTLS_PEM_WRITE_C) +#include "mbedtls/pem.h" +#endif + +#if defined(MBEDTLS_PK_C) +#include "mbedtls/pk.h" +#endif + +#if defined(MBEDTLS_PKCS12_C) +#include "mbedtls/pkcs12.h" +#endif + +#if defined(MBEDTLS_PKCS5_C) +#include "mbedtls/pkcs5.h" +#endif + +#if defined(MBEDTLS_POLY1305_C) +#include "mbedtls/poly1305.h" +#endif + +#if defined(MBEDTLS_RIPEMD160_C) +#include "mbedtls/ripemd160.h" +#endif + +#if defined(MBEDTLS_RSA_C) +#include "mbedtls/rsa.h" +#endif + +#if defined(MBEDTLS_SHA1_C) +#include "mbedtls/sha1.h" +#endif + +#if defined(MBEDTLS_SHA256_C) +#include "mbedtls/sha256.h" +#endif + +#if defined(MBEDTLS_SHA512_C) +#include "mbedtls/sha512.h" +#endif + +#if defined(MBEDTLS_SSL_TLS_C) +#include "mbedtls/ssl.h" +#endif + +#if defined(MBEDTLS_THREADING_C) +#include "mbedtls/threading.h" +#endif + +#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C) +#include "mbedtls/x509.h" +#endif + +#if defined(MBEDTLS_XTEA_C) +#include "mbedtls/xtea.h" +#endif + + +void mbedtls_strerror( int ret, char *buf, size_t buflen ) +{ + size_t len; + int use_ret; + + if( buflen == 0 ) + return; + + memset( buf, 0x00, buflen ); + + if( ret < 0 ) + ret = -ret; + + if( ret & 0xFF80 ) + { + use_ret = ret & 0xFF80; + + // High level error codes + // + // BEGIN generated code +#if defined(MBEDTLS_CIPHER_C) + if( use_ret == -(MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "CIPHER - The selected feature is not available" ); + if( use_ret == -(MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "CIPHER - Bad input parameters" ); + if( use_ret == -(MBEDTLS_ERR_CIPHER_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "CIPHER - Failed to allocate memory" ); + if( use_ret == -(MBEDTLS_ERR_CIPHER_INVALID_PADDING) ) + mbedtls_snprintf( buf, buflen, "CIPHER - Input data contains invalid padding and is rejected" ); + if( use_ret == -(MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED) ) + mbedtls_snprintf( buf, buflen, "CIPHER - Decryption of block requires a full block" ); + if( use_ret == -(MBEDTLS_ERR_CIPHER_AUTH_FAILED) ) + mbedtls_snprintf( buf, buflen, "CIPHER - Authentication failed (for AEAD modes)" ); + if( use_ret == -(MBEDTLS_ERR_CIPHER_INVALID_CONTEXT) ) + mbedtls_snprintf( buf, buflen, "CIPHER - The context is invalid. For example, because it was freed" ); + if( use_ret == -(MBEDTLS_ERR_CIPHER_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "CIPHER - Cipher hardware accelerator failed" ); +#endif /* MBEDTLS_CIPHER_C */ + +#if defined(MBEDTLS_DHM_C) + if( use_ret == -(MBEDTLS_ERR_DHM_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "DHM - Bad input parameters" ); + if( use_ret == -(MBEDTLS_ERR_DHM_READ_PARAMS_FAILED) ) + mbedtls_snprintf( buf, buflen, "DHM - Reading of the DHM parameters failed" ); + if( use_ret == -(MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED) ) + mbedtls_snprintf( buf, buflen, "DHM - Making of the DHM parameters failed" ); + if( use_ret == -(MBEDTLS_ERR_DHM_READ_PUBLIC_FAILED) ) + mbedtls_snprintf( buf, buflen, "DHM - Reading of the public values failed" ); + if( use_ret == -(MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED) ) + mbedtls_snprintf( buf, buflen, "DHM - Making of the public value failed" ); + if( use_ret == -(MBEDTLS_ERR_DHM_CALC_SECRET_FAILED) ) + mbedtls_snprintf( buf, buflen, "DHM - Calculation of the DHM secret failed" ); + if( use_ret == -(MBEDTLS_ERR_DHM_INVALID_FORMAT) ) + mbedtls_snprintf( buf, buflen, "DHM - The ASN.1 data is not formatted correctly" ); + if( use_ret == -(MBEDTLS_ERR_DHM_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "DHM - Allocation of memory failed" ); + if( use_ret == -(MBEDTLS_ERR_DHM_FILE_IO_ERROR) ) + mbedtls_snprintf( buf, buflen, "DHM - Read or write of file failed" ); + if( use_ret == -(MBEDTLS_ERR_DHM_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "DHM - DHM hardware accelerator failed" ); + if( use_ret == -(MBEDTLS_ERR_DHM_SET_GROUP_FAILED) ) + mbedtls_snprintf( buf, buflen, "DHM - Setting the modulus and generator failed" ); +#endif /* MBEDTLS_DHM_C */ + +#if defined(MBEDTLS_ECP_C) + if( use_ret == -(MBEDTLS_ERR_ECP_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "ECP - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "ECP - The buffer is too small to write to" ); + if( use_ret == -(MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "ECP - The requested feature is not available, for example, the requested curve is not supported" ); + if( use_ret == -(MBEDTLS_ERR_ECP_VERIFY_FAILED) ) + mbedtls_snprintf( buf, buflen, "ECP - The signature is not valid" ); + if( use_ret == -(MBEDTLS_ERR_ECP_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "ECP - Memory allocation failed" ); + if( use_ret == -(MBEDTLS_ERR_ECP_RANDOM_FAILED) ) + mbedtls_snprintf( buf, buflen, "ECP - Generation of random value, such as ephemeral key, failed" ); + if( use_ret == -(MBEDTLS_ERR_ECP_INVALID_KEY) ) + mbedtls_snprintf( buf, buflen, "ECP - Invalid private or public key" ); + if( use_ret == -(MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "ECP - The buffer contains a valid signature followed by more data" ); + if( use_ret == -(MBEDTLS_ERR_ECP_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "ECP - The ECP hardware accelerator failed" ); +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_MD_C) + if( use_ret == -(MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "MD - The selected feature is not available" ); + if( use_ret == -(MBEDTLS_ERR_MD_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "MD - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_MD_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "MD - Failed to allocate memory" ); + if( use_ret == -(MBEDTLS_ERR_MD_FILE_IO_ERROR) ) + mbedtls_snprintf( buf, buflen, "MD - Opening or reading of file failed" ); + if( use_ret == -(MBEDTLS_ERR_MD_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "MD - MD hardware accelerator failed" ); +#endif /* MBEDTLS_MD_C */ + +#if defined(MBEDTLS_PEM_PARSE_C) || defined(MBEDTLS_PEM_WRITE_C) + if( use_ret == -(MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) ) + mbedtls_snprintf( buf, buflen, "PEM - No PEM header or footer found" ); + if( use_ret == -(MBEDTLS_ERR_PEM_INVALID_DATA) ) + mbedtls_snprintf( buf, buflen, "PEM - PEM string is not as expected" ); + if( use_ret == -(MBEDTLS_ERR_PEM_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "PEM - Failed to allocate memory" ); + if( use_ret == -(MBEDTLS_ERR_PEM_INVALID_ENC_IV) ) + mbedtls_snprintf( buf, buflen, "PEM - RSA IV is not in hex-format" ); + if( use_ret == -(MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG) ) + mbedtls_snprintf( buf, buflen, "PEM - Unsupported key encryption algorithm" ); + if( use_ret == -(MBEDTLS_ERR_PEM_PASSWORD_REQUIRED) ) + mbedtls_snprintf( buf, buflen, "PEM - Private key password can't be empty" ); + if( use_ret == -(MBEDTLS_ERR_PEM_PASSWORD_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "PEM - Given private key password does not allow for correct decryption" ); + if( use_ret == -(MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "PEM - Unavailable feature, e.g. hashing/encryption combination" ); + if( use_ret == -(MBEDTLS_ERR_PEM_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "PEM - Bad input parameters to function" ); +#endif /* MBEDTLS_PEM_PARSE_C || MBEDTLS_PEM_WRITE_C */ + +#if defined(MBEDTLS_PK_C) + if( use_ret == -(MBEDTLS_ERR_PK_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "PK - Memory allocation failed" ); + if( use_ret == -(MBEDTLS_ERR_PK_TYPE_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "PK - Type mismatch, eg attempt to encrypt with an ECDSA key" ); + if( use_ret == -(MBEDTLS_ERR_PK_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "PK - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_PK_FILE_IO_ERROR) ) + mbedtls_snprintf( buf, buflen, "PK - Read/write of file failed" ); + if( use_ret == -(MBEDTLS_ERR_PK_KEY_INVALID_VERSION) ) + mbedtls_snprintf( buf, buflen, "PK - Unsupported key version" ); + if( use_ret == -(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT) ) + mbedtls_snprintf( buf, buflen, "PK - Invalid key tag or value" ); + if( use_ret == -(MBEDTLS_ERR_PK_UNKNOWN_PK_ALG) ) + mbedtls_snprintf( buf, buflen, "PK - Key algorithm is unsupported (only RSA and EC are supported)" ); + if( use_ret == -(MBEDTLS_ERR_PK_PASSWORD_REQUIRED) ) + mbedtls_snprintf( buf, buflen, "PK - Private key password can't be empty" ); + if( use_ret == -(MBEDTLS_ERR_PK_PASSWORD_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "PK - Given private key password does not allow for correct decryption" ); + if( use_ret == -(MBEDTLS_ERR_PK_INVALID_PUBKEY) ) + mbedtls_snprintf( buf, buflen, "PK - The pubkey tag or value is invalid (only RSA and EC are supported)" ); + if( use_ret == -(MBEDTLS_ERR_PK_INVALID_ALG) ) + mbedtls_snprintf( buf, buflen, "PK - The algorithm tag or value is invalid" ); + if( use_ret == -(MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE) ) + mbedtls_snprintf( buf, buflen, "PK - Elliptic curve is unsupported (only NIST curves are supported)" ); + if( use_ret == -(MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "PK - Unavailable feature, e.g. RSA disabled for RSA key" ); + if( use_ret == -(MBEDTLS_ERR_PK_SIG_LEN_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "PK - The buffer contains a valid signature followed by more data" ); + if( use_ret == -(MBEDTLS_ERR_PK_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "PK - PK hardware accelerator failed" ); +#endif /* MBEDTLS_PK_C */ + +#if defined(MBEDTLS_PKCS12_C) + if( use_ret == -(MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "PKCS12 - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "PKCS12 - Feature not available, e.g. unsupported encryption scheme" ); + if( use_ret == -(MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT) ) + mbedtls_snprintf( buf, buflen, "PKCS12 - PBE ASN.1 data not as expected" ); + if( use_ret == -(MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "PKCS12 - Given private key password does not allow for correct decryption" ); +#endif /* MBEDTLS_PKCS12_C */ + +#if defined(MBEDTLS_PKCS5_C) + if( use_ret == -(MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "PKCS5 - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_PKCS5_INVALID_FORMAT) ) + mbedtls_snprintf( buf, buflen, "PKCS5 - Unexpected ASN.1 data" ); + if( use_ret == -(MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "PKCS5 - Requested encryption or digest alg not available" ); + if( use_ret == -(MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "PKCS5 - Given private key password does not allow for correct decryption" ); +#endif /* MBEDTLS_PKCS5_C */ + +#if defined(MBEDTLS_RSA_C) + if( use_ret == -(MBEDTLS_ERR_RSA_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "RSA - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_RSA_INVALID_PADDING) ) + mbedtls_snprintf( buf, buflen, "RSA - Input data contains invalid padding and is rejected" ); + if( use_ret == -(MBEDTLS_ERR_RSA_KEY_GEN_FAILED) ) + mbedtls_snprintf( buf, buflen, "RSA - Something failed during generation of a key" ); + if( use_ret == -(MBEDTLS_ERR_RSA_KEY_CHECK_FAILED) ) + mbedtls_snprintf( buf, buflen, "RSA - Key failed to pass the validity check of the library" ); + if( use_ret == -(MBEDTLS_ERR_RSA_PUBLIC_FAILED) ) + mbedtls_snprintf( buf, buflen, "RSA - The public key operation failed" ); + if( use_ret == -(MBEDTLS_ERR_RSA_PRIVATE_FAILED) ) + mbedtls_snprintf( buf, buflen, "RSA - The private key operation failed" ); + if( use_ret == -(MBEDTLS_ERR_RSA_VERIFY_FAILED) ) + mbedtls_snprintf( buf, buflen, "RSA - The PKCS#1 verification failed" ); + if( use_ret == -(MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE) ) + mbedtls_snprintf( buf, buflen, "RSA - The output buffer for decryption is not large enough" ); + if( use_ret == -(MBEDTLS_ERR_RSA_RNG_FAILED) ) + mbedtls_snprintf( buf, buflen, "RSA - The random generator failed to generate non-zeros" ); + if( use_ret == -(MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION) ) + mbedtls_snprintf( buf, buflen, "RSA - The implementation does not offer the requested operation, for example, because of security violations or lack of functionality" ); + if( use_ret == -(MBEDTLS_ERR_RSA_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "RSA - RSA hardware accelerator failed" ); +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_SSL_TLS_C) + if( use_ret == -(MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "SSL - The requested feature is not available" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "SSL - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_SSL_INVALID_MAC) ) + mbedtls_snprintf( buf, buflen, "SSL - Verification of the message MAC failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_INVALID_RECORD) ) + mbedtls_snprintf( buf, buflen, "SSL - An invalid SSL record was received" ); + if( use_ret == -(MBEDTLS_ERR_SSL_CONN_EOF) ) + mbedtls_snprintf( buf, buflen, "SSL - The connection indicated an EOF" ); + if( use_ret == -(MBEDTLS_ERR_SSL_UNKNOWN_CIPHER) ) + mbedtls_snprintf( buf, buflen, "SSL - An unknown cipher was received" ); + if( use_ret == -(MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN) ) + mbedtls_snprintf( buf, buflen, "SSL - The server has no ciphersuites in common with the client" ); + if( use_ret == -(MBEDTLS_ERR_SSL_NO_RNG) ) + mbedtls_snprintf( buf, buflen, "SSL - No RNG was provided to the SSL module" ); + if( use_ret == -(MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE) ) + mbedtls_snprintf( buf, buflen, "SSL - No client certification received from the client, but required by the authentication mode" ); + if( use_ret == -(MBEDTLS_ERR_SSL_CERTIFICATE_TOO_LARGE) ) + mbedtls_snprintf( buf, buflen, "SSL - Our own certificate(s) is/are too large to send in an SSL message" ); + if( use_ret == -(MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED) ) + mbedtls_snprintf( buf, buflen, "SSL - The own certificate is not set, but needed by the server" ); + if( use_ret == -(MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED) ) + mbedtls_snprintf( buf, buflen, "SSL - The own private key or pre-shared key is not set, but needed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED) ) + mbedtls_snprintf( buf, buflen, "SSL - No CA Chain is set, but required to operate" ); + if( use_ret == -(MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE) ) + mbedtls_snprintf( buf, buflen, "SSL - An unexpected message was received from our peer" ); + if( use_ret == -(MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE) ) + { + mbedtls_snprintf( buf, buflen, "SSL - A fatal alert message was received from our peer" ); + return; + } + if( use_ret == -(MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED) ) + mbedtls_snprintf( buf, buflen, "SSL - Verification of our peer failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) ) + mbedtls_snprintf( buf, buflen, "SSL - The peer notified us that the connection is going to be closed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the ClientHello handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the ServerHello handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the Certificate handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the CertificateRequest handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the ServerKeyExchange handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO_DONE) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the ServerHelloDone handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the ClientKeyExchange handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the ClientKeyExchange handshake message failed in DHM / ECDH Read Public" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the ClientKeyExchange handshake message failed in DHM / ECDH Calculate Secret" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the CertificateVerify handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the ChangeCipherSpec handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_FINISHED) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the Finished handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "SSL - Memory allocation failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "SSL - Hardware acceleration function returned with error" ); + if( use_ret == -(MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH) ) + mbedtls_snprintf( buf, buflen, "SSL - Hardware acceleration function skipped / left alone data" ); + if( use_ret == -(MBEDTLS_ERR_SSL_COMPRESSION_FAILED) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the compression / decompression failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION) ) + mbedtls_snprintf( buf, buflen, "SSL - Handshake protocol not within min/max boundaries" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the NewSessionTicket handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED) ) + mbedtls_snprintf( buf, buflen, "SSL - Session ticket has expired" ); + if( use_ret == -(MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "SSL - Public key type mismatch (eg, asked for RSA key exchange and presented EC key)" ); + if( use_ret == -(MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY) ) + mbedtls_snprintf( buf, buflen, "SSL - Unknown identity received (eg, PSK identity)" ); + if( use_ret == -(MBEDTLS_ERR_SSL_INTERNAL_ERROR) ) + mbedtls_snprintf( buf, buflen, "SSL - Internal error (eg, unexpected failure in lower-level module)" ); + if( use_ret == -(MBEDTLS_ERR_SSL_COUNTER_WRAPPING) ) + mbedtls_snprintf( buf, buflen, "SSL - A counter would wrap (eg, too many messages exchanged)" ); + if( use_ret == -(MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO) ) + mbedtls_snprintf( buf, buflen, "SSL - Unexpected message at ServerHello in renegotiation" ); + if( use_ret == -(MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED) ) + mbedtls_snprintf( buf, buflen, "SSL - DTLS client must retry for hello verification" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "SSL - A buffer is too small to receive or write a message" ); + if( use_ret == -(MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE) ) + mbedtls_snprintf( buf, buflen, "SSL - None of the common ciphersuites is usable (eg, no suitable certificate, see debug messages)" ); + if( use_ret == -(MBEDTLS_ERR_SSL_WANT_READ) ) + mbedtls_snprintf( buf, buflen, "SSL - No data of requested type currently available on underlying transport" ); + if( use_ret == -(MBEDTLS_ERR_SSL_WANT_WRITE) ) + mbedtls_snprintf( buf, buflen, "SSL - Connection requires a write call" ); + if( use_ret == -(MBEDTLS_ERR_SSL_TIMEOUT) ) + mbedtls_snprintf( buf, buflen, "SSL - The operation timed out" ); + if( use_ret == -(MBEDTLS_ERR_SSL_CLIENT_RECONNECT) ) + mbedtls_snprintf( buf, buflen, "SSL - The client initiated a reconnect from the same port" ); + if( use_ret == -(MBEDTLS_ERR_SSL_UNEXPECTED_RECORD) ) + mbedtls_snprintf( buf, buflen, "SSL - Record header looks valid but is not expected" ); + if( use_ret == -(MBEDTLS_ERR_SSL_NON_FATAL) ) + mbedtls_snprintf( buf, buflen, "SSL - The alert message received indicates a non-fatal error" ); + if( use_ret == -(MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH) ) + mbedtls_snprintf( buf, buflen, "SSL - Couldn't set the hash for verifying CertificateVerify" ); + if( use_ret == -(MBEDTLS_ERR_SSL_CONTINUE_PROCESSING) ) + mbedtls_snprintf( buf, buflen, "SSL - Internal-only message signaling that further message-processing should be done" ); + if( use_ret == -(MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS) ) + mbedtls_snprintf( buf, buflen, "SSL - The asynchronous operation is not completed yet" ); + if( use_ret == -(MBEDTLS_ERR_SSL_EARLY_MESSAGE) ) + mbedtls_snprintf( buf, buflen, "SSL - Internal-only message signaling that a message arrived early" ); +#endif /* MBEDTLS_SSL_TLS_C */ + +#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C) + if( use_ret == -(MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "X509 - Unavailable feature, e.g. RSA hashing/encryption combination" ); + if( use_ret == -(MBEDTLS_ERR_X509_UNKNOWN_OID) ) + mbedtls_snprintf( buf, buflen, "X509 - Requested OID is unknown" ); + if( use_ret == -(MBEDTLS_ERR_X509_INVALID_FORMAT) ) + mbedtls_snprintf( buf, buflen, "X509 - The CRT/CRL/CSR format is invalid, e.g. different type expected" ); + if( use_ret == -(MBEDTLS_ERR_X509_INVALID_VERSION) ) + mbedtls_snprintf( buf, buflen, "X509 - The CRT/CRL/CSR version element is invalid" ); + if( use_ret == -(MBEDTLS_ERR_X509_INVALID_SERIAL) ) + mbedtls_snprintf( buf, buflen, "X509 - The serial tag or value is invalid" ); + if( use_ret == -(MBEDTLS_ERR_X509_INVALID_ALG) ) + mbedtls_snprintf( buf, buflen, "X509 - The algorithm tag or value is invalid" ); + if( use_ret == -(MBEDTLS_ERR_X509_INVALID_NAME) ) + mbedtls_snprintf( buf, buflen, "X509 - The name tag or value is invalid" ); + if( use_ret == -(MBEDTLS_ERR_X509_INVALID_DATE) ) + mbedtls_snprintf( buf, buflen, "X509 - The date tag or value is invalid" ); + if( use_ret == -(MBEDTLS_ERR_X509_INVALID_SIGNATURE) ) + mbedtls_snprintf( buf, buflen, "X509 - The signature tag or value invalid" ); + if( use_ret == -(MBEDTLS_ERR_X509_INVALID_EXTENSIONS) ) + mbedtls_snprintf( buf, buflen, "X509 - The extension tag or value is invalid" ); + if( use_ret == -(MBEDTLS_ERR_X509_UNKNOWN_VERSION) ) + mbedtls_snprintf( buf, buflen, "X509 - CRT/CRL/CSR has an unsupported version number" ); + if( use_ret == -(MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG) ) + mbedtls_snprintf( buf, buflen, "X509 - Signature algorithm (oid) is unsupported" ); + if( use_ret == -(MBEDTLS_ERR_X509_SIG_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "X509 - Signature algorithms do not match. (see \\c ::mbedtls_x509_crt sig_oid)" ); + if( use_ret == -(MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) ) + mbedtls_snprintf( buf, buflen, "X509 - Certificate verification failed, e.g. CRL, CA or signature check failed" ); + if( use_ret == -(MBEDTLS_ERR_X509_CERT_UNKNOWN_FORMAT) ) + mbedtls_snprintf( buf, buflen, "X509 - Format not recognized as DER or PEM" ); + if( use_ret == -(MBEDTLS_ERR_X509_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "X509 - Input invalid" ); + if( use_ret == -(MBEDTLS_ERR_X509_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "X509 - Allocation of memory failed" ); + if( use_ret == -(MBEDTLS_ERR_X509_FILE_IO_ERROR) ) + mbedtls_snprintf( buf, buflen, "X509 - Read/write of file failed" ); + if( use_ret == -(MBEDTLS_ERR_X509_BUFFER_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "X509 - Destination buffer is too small" ); + if( use_ret == -(MBEDTLS_ERR_X509_FATAL_ERROR) ) + mbedtls_snprintf( buf, buflen, "X509 - A fatal error occured, eg the chain is too long or the vrfy callback failed" ); +#endif /* MBEDTLS_X509_USE_C || MBEDTLS_X509_CREATE_C */ + // END generated code + + if( strlen( buf ) == 0 ) + mbedtls_snprintf( buf, buflen, "UNKNOWN ERROR CODE (%04X)", use_ret ); + } + + use_ret = ret & ~0xFF80; + + if( use_ret == 0 ) + return; + + // If high level code is present, make a concatenation between both + // error strings. + // + len = strlen( buf ); + + if( len > 0 ) + { + if( buflen - len < 5 ) + return; + + mbedtls_snprintf( buf + len, buflen - len, " : " ); + + buf += len + 3; + buflen -= len + 3; + } + + // Low level error codes + // + // BEGIN generated code +#if defined(MBEDTLS_AES_C) + if( use_ret == -(MBEDTLS_ERR_AES_INVALID_KEY_LENGTH) ) + mbedtls_snprintf( buf, buflen, "AES - Invalid key length" ); + if( use_ret == -(MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH) ) + mbedtls_snprintf( buf, buflen, "AES - Invalid data input length" ); + if( use_ret == -(MBEDTLS_ERR_AES_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "AES - Invalid input data" ); + if( use_ret == -(MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "AES - Feature not available. For example, an unsupported AES key size" ); + if( use_ret == -(MBEDTLS_ERR_AES_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "AES - AES hardware accelerator failed" ); +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_ARC4_C) + if( use_ret == -(MBEDTLS_ERR_ARC4_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "ARC4 - ARC4 hardware accelerator failed" ); +#endif /* MBEDTLS_ARC4_C */ + +#if defined(MBEDTLS_ARIA_C) + if( use_ret == -(MBEDTLS_ERR_ARIA_INVALID_KEY_LENGTH) ) + mbedtls_snprintf( buf, buflen, "ARIA - Invalid key length" ); + if( use_ret == -(MBEDTLS_ERR_ARIA_INVALID_INPUT_LENGTH) ) + mbedtls_snprintf( buf, buflen, "ARIA - Invalid data input length" ); + if( use_ret == -(MBEDTLS_ERR_ARIA_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "ARIA - Feature not available. For example, an unsupported ARIA key size" ); + if( use_ret == -(MBEDTLS_ERR_ARIA_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "ARIA - ARIA hardware accelerator failed" ); +#endif /* MBEDTLS_ARIA_C */ + +#if defined(MBEDTLS_ASN1_PARSE_C) + if( use_ret == -(MBEDTLS_ERR_ASN1_OUT_OF_DATA) ) + mbedtls_snprintf( buf, buflen, "ASN1 - Out of data when parsing an ASN1 data structure" ); + if( use_ret == -(MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) ) + mbedtls_snprintf( buf, buflen, "ASN1 - ASN1 tag was of an unexpected value" ); + if( use_ret == -(MBEDTLS_ERR_ASN1_INVALID_LENGTH) ) + mbedtls_snprintf( buf, buflen, "ASN1 - Error when trying to determine the length or invalid length" ); + if( use_ret == -(MBEDTLS_ERR_ASN1_LENGTH_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "ASN1 - Actual length differs from expected length" ); + if( use_ret == -(MBEDTLS_ERR_ASN1_INVALID_DATA) ) + mbedtls_snprintf( buf, buflen, "ASN1 - Data is invalid. (not used)" ); + if( use_ret == -(MBEDTLS_ERR_ASN1_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "ASN1 - Memory allocation failed" ); + if( use_ret == -(MBEDTLS_ERR_ASN1_BUF_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "ASN1 - Buffer too small when writing ASN.1 data structure" ); +#endif /* MBEDTLS_ASN1_PARSE_C */ + +#if defined(MBEDTLS_BASE64_C) + if( use_ret == -(MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "BASE64 - Output buffer too small" ); + if( use_ret == -(MBEDTLS_ERR_BASE64_INVALID_CHARACTER) ) + mbedtls_snprintf( buf, buflen, "BASE64 - Invalid character in input" ); +#endif /* MBEDTLS_BASE64_C */ + +#if defined(MBEDTLS_BIGNUM_C) + if( use_ret == -(MBEDTLS_ERR_MPI_FILE_IO_ERROR) ) + mbedtls_snprintf( buf, buflen, "BIGNUM - An error occurred while reading from or writing to a file" ); + if( use_ret == -(MBEDTLS_ERR_MPI_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "BIGNUM - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_MPI_INVALID_CHARACTER) ) + mbedtls_snprintf( buf, buflen, "BIGNUM - There is an invalid character in the digit string" ); + if( use_ret == -(MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "BIGNUM - The buffer is too small to write to" ); + if( use_ret == -(MBEDTLS_ERR_MPI_NEGATIVE_VALUE) ) + mbedtls_snprintf( buf, buflen, "BIGNUM - The input arguments are negative or result in illegal output" ); + if( use_ret == -(MBEDTLS_ERR_MPI_DIVISION_BY_ZERO) ) + mbedtls_snprintf( buf, buflen, "BIGNUM - The input argument for division is zero, which is not allowed" ); + if( use_ret == -(MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) ) + mbedtls_snprintf( buf, buflen, "BIGNUM - The input arguments are not acceptable" ); + if( use_ret == -(MBEDTLS_ERR_MPI_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "BIGNUM - Memory allocation failed" ); +#endif /* MBEDTLS_BIGNUM_C */ + +#if defined(MBEDTLS_BLOWFISH_C) + if( use_ret == -(MBEDTLS_ERR_BLOWFISH_INVALID_KEY_LENGTH) ) + mbedtls_snprintf( buf, buflen, "BLOWFISH - Invalid key length" ); + if( use_ret == -(MBEDTLS_ERR_BLOWFISH_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "BLOWFISH - Blowfish hardware accelerator failed" ); + if( use_ret == -(MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH) ) + mbedtls_snprintf( buf, buflen, "BLOWFISH - Invalid data input length" ); +#endif /* MBEDTLS_BLOWFISH_C */ + +#if defined(MBEDTLS_CAMELLIA_C) + if( use_ret == -(MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH) ) + mbedtls_snprintf( buf, buflen, "CAMELLIA - Invalid key length" ); + if( use_ret == -(MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH) ) + mbedtls_snprintf( buf, buflen, "CAMELLIA - Invalid data input length" ); + if( use_ret == -(MBEDTLS_ERR_CAMELLIA_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "CAMELLIA - Camellia hardware accelerator failed" ); +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_CCM_C) + if( use_ret == -(MBEDTLS_ERR_CCM_BAD_INPUT) ) + mbedtls_snprintf( buf, buflen, "CCM - Bad input parameters to the function" ); + if( use_ret == -(MBEDTLS_ERR_CCM_AUTH_FAILED) ) + mbedtls_snprintf( buf, buflen, "CCM - Authenticated decryption failed" ); + if( use_ret == -(MBEDTLS_ERR_CCM_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "CCM - CCM hardware accelerator failed" ); +#endif /* MBEDTLS_CCM_C */ + +#if defined(MBEDTLS_CHACHA20_C) + if( use_ret == -(MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "CHACHA20 - Invalid input parameter(s)" ); + if( use_ret == -(MBEDTLS_ERR_CHACHA20_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "CHACHA20 - Feature not available. For example, s part of the API is not implemented" ); + if( use_ret == -(MBEDTLS_ERR_CHACHA20_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "CHACHA20 - Chacha20 hardware accelerator failed" ); +#endif /* MBEDTLS_CHACHA20_C */ + +#if defined(MBEDTLS_CHACHAPOLY_C) + if( use_ret == -(MBEDTLS_ERR_CHACHAPOLY_BAD_STATE) ) + mbedtls_snprintf( buf, buflen, "CHACHAPOLY - The requested operation is not permitted in the current state" ); + if( use_ret == -(MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED) ) + mbedtls_snprintf( buf, buflen, "CHACHAPOLY - Authenticated decryption failed: data was not authentic" ); +#endif /* MBEDTLS_CHACHAPOLY_C */ + +#if defined(MBEDTLS_CMAC_C) + if( use_ret == -(MBEDTLS_ERR_CMAC_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "CMAC - CMAC hardware accelerator failed" ); +#endif /* MBEDTLS_CMAC_C */ + +#if defined(MBEDTLS_CTR_DRBG_C) + if( use_ret == -(MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED) ) + mbedtls_snprintf( buf, buflen, "CTR_DRBG - The entropy source failed" ); + if( use_ret == -(MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG) ) + mbedtls_snprintf( buf, buflen, "CTR_DRBG - The requested random buffer length is too big" ); + if( use_ret == -(MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG) ) + mbedtls_snprintf( buf, buflen, "CTR_DRBG - The input (entropy + additional data) is too large" ); + if( use_ret == -(MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR) ) + mbedtls_snprintf( buf, buflen, "CTR_DRBG - Read or write error in file" ); +#endif /* MBEDTLS_CTR_DRBG_C */ + +#if defined(MBEDTLS_DES_C) + if( use_ret == -(MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH) ) + mbedtls_snprintf( buf, buflen, "DES - The data input has an invalid length" ); + if( use_ret == -(MBEDTLS_ERR_DES_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "DES - DES hardware accelerator failed" ); +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_ENTROPY_C) + if( use_ret == -(MBEDTLS_ERR_ENTROPY_SOURCE_FAILED) ) + mbedtls_snprintf( buf, buflen, "ENTROPY - Critical entropy source failure" ); + if( use_ret == -(MBEDTLS_ERR_ENTROPY_MAX_SOURCES) ) + mbedtls_snprintf( buf, buflen, "ENTROPY - No more sources can be added" ); + if( use_ret == -(MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED) ) + mbedtls_snprintf( buf, buflen, "ENTROPY - No sources have been added to poll" ); + if( use_ret == -(MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE) ) + mbedtls_snprintf( buf, buflen, "ENTROPY - No strong sources have been added to poll" ); + if( use_ret == -(MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR) ) + mbedtls_snprintf( buf, buflen, "ENTROPY - Read/write error in file" ); +#endif /* MBEDTLS_ENTROPY_C */ + +#if defined(MBEDTLS_GCM_C) + if( use_ret == -(MBEDTLS_ERR_GCM_AUTH_FAILED) ) + mbedtls_snprintf( buf, buflen, "GCM - Authenticated decryption failed" ); + if( use_ret == -(MBEDTLS_ERR_GCM_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "GCM - GCM hardware accelerator failed" ); + if( use_ret == -(MBEDTLS_ERR_GCM_BAD_INPUT) ) + mbedtls_snprintf( buf, buflen, "GCM - Bad input parameters to function" ); +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_HKDF_C) + if( use_ret == -(MBEDTLS_ERR_HKDF_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "HKDF - Bad input parameters to function" ); +#endif /* MBEDTLS_HKDF_C */ + +#if defined(MBEDTLS_HMAC_DRBG_C) + if( use_ret == -(MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG) ) + mbedtls_snprintf( buf, buflen, "HMAC_DRBG - Too many random requested in single call" ); + if( use_ret == -(MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG) ) + mbedtls_snprintf( buf, buflen, "HMAC_DRBG - Input too large (Entropy + additional)" ); + if( use_ret == -(MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR) ) + mbedtls_snprintf( buf, buflen, "HMAC_DRBG - Read/write error in file" ); + if( use_ret == -(MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED) ) + mbedtls_snprintf( buf, buflen, "HMAC_DRBG - The entropy source failed" ); +#endif /* MBEDTLS_HMAC_DRBG_C */ + +#if defined(MBEDTLS_MD2_C) + if( use_ret == -(MBEDTLS_ERR_MD2_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "MD2 - MD2 hardware accelerator failed" ); +#endif /* MBEDTLS_MD2_C */ + +#if defined(MBEDTLS_MD4_C) + if( use_ret == -(MBEDTLS_ERR_MD4_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "MD4 - MD4 hardware accelerator failed" ); +#endif /* MBEDTLS_MD4_C */ + +#if defined(MBEDTLS_MD5_C) + if( use_ret == -(MBEDTLS_ERR_MD5_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "MD5 - MD5 hardware accelerator failed" ); +#endif /* MBEDTLS_MD5_C */ + +#if defined(MBEDTLS_NET_C) + if( use_ret == -(MBEDTLS_ERR_NET_SOCKET_FAILED) ) + mbedtls_snprintf( buf, buflen, "NET - Failed to open a socket" ); + if( use_ret == -(MBEDTLS_ERR_NET_CONNECT_FAILED) ) + mbedtls_snprintf( buf, buflen, "NET - The connection to the given server / port failed" ); + if( use_ret == -(MBEDTLS_ERR_NET_BIND_FAILED) ) + mbedtls_snprintf( buf, buflen, "NET - Binding of the socket failed" ); + if( use_ret == -(MBEDTLS_ERR_NET_LISTEN_FAILED) ) + mbedtls_snprintf( buf, buflen, "NET - Could not listen on the socket" ); + if( use_ret == -(MBEDTLS_ERR_NET_ACCEPT_FAILED) ) + mbedtls_snprintf( buf, buflen, "NET - Could not accept the incoming connection" ); + if( use_ret == -(MBEDTLS_ERR_NET_RECV_FAILED) ) + mbedtls_snprintf( buf, buflen, "NET - Reading information from the socket failed" ); + if( use_ret == -(MBEDTLS_ERR_NET_SEND_FAILED) ) + mbedtls_snprintf( buf, buflen, "NET - Sending information through the socket failed" ); + if( use_ret == -(MBEDTLS_ERR_NET_CONN_RESET) ) + mbedtls_snprintf( buf, buflen, "NET - Connection was reset by peer" ); + if( use_ret == -(MBEDTLS_ERR_NET_UNKNOWN_HOST) ) + mbedtls_snprintf( buf, buflen, "NET - Failed to get an IP address for the given hostname" ); + if( use_ret == -(MBEDTLS_ERR_NET_BUFFER_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "NET - Buffer is too small to hold the data" ); + if( use_ret == -(MBEDTLS_ERR_NET_INVALID_CONTEXT) ) + mbedtls_snprintf( buf, buflen, "NET - The context is invalid, eg because it was free()ed" ); + if( use_ret == -(MBEDTLS_ERR_NET_POLL_FAILED) ) + mbedtls_snprintf( buf, buflen, "NET - Polling the net context failed" ); + if( use_ret == -(MBEDTLS_ERR_NET_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "NET - Input invalid" ); +#endif /* MBEDTLS_NET_C */ + +#if defined(MBEDTLS_OID_C) + if( use_ret == -(MBEDTLS_ERR_OID_NOT_FOUND) ) + mbedtls_snprintf( buf, buflen, "OID - OID is not found" ); + if( use_ret == -(MBEDTLS_ERR_OID_BUF_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "OID - output buffer is too small" ); +#endif /* MBEDTLS_OID_C */ + +#if defined(MBEDTLS_PADLOCK_C) + if( use_ret == -(MBEDTLS_ERR_PADLOCK_DATA_MISALIGNED) ) + mbedtls_snprintf( buf, buflen, "PADLOCK - Input data should be aligned" ); +#endif /* MBEDTLS_PADLOCK_C */ + +#if defined(MBEDTLS_POLY1305_C) + if( use_ret == -(MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "POLY1305 - Invalid input parameter(s)" ); + if( use_ret == -(MBEDTLS_ERR_POLY1305_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "POLY1305 - Feature not available. For example, s part of the API is not implemented" ); + if( use_ret == -(MBEDTLS_ERR_POLY1305_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "POLY1305 - Poly1305 hardware accelerator failed" ); +#endif /* MBEDTLS_POLY1305_C */ + +#if defined(MBEDTLS_RIPEMD160_C) + if( use_ret == -(MBEDTLS_ERR_RIPEMD160_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "RIPEMD160 - RIPEMD160 hardware accelerator failed" ); +#endif /* MBEDTLS_RIPEMD160_C */ + +#if defined(MBEDTLS_SHA1_C) + if( use_ret == -(MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "SHA1 - SHA-1 hardware accelerator failed" ); +#endif /* MBEDTLS_SHA1_C */ + +#if defined(MBEDTLS_SHA256_C) + if( use_ret == -(MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "SHA256 - SHA-256 hardware accelerator failed" ); +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + if( use_ret == -(MBEDTLS_ERR_SHA512_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "SHA512 - SHA-512 hardware accelerator failed" ); +#endif /* MBEDTLS_SHA512_C */ + +#if defined(MBEDTLS_THREADING_C) + if( use_ret == -(MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "THREADING - The selected feature is not available" ); + if( use_ret == -(MBEDTLS_ERR_THREADING_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "THREADING - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_THREADING_MUTEX_ERROR) ) + mbedtls_snprintf( buf, buflen, "THREADING - Locking / unlocking / free failed with error code" ); +#endif /* MBEDTLS_THREADING_C */ + +#if defined(MBEDTLS_XTEA_C) + if( use_ret == -(MBEDTLS_ERR_XTEA_INVALID_INPUT_LENGTH) ) + mbedtls_snprintf( buf, buflen, "XTEA - The data input has an invalid length" ); + if( use_ret == -(MBEDTLS_ERR_XTEA_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "XTEA - XTEA hardware accelerator failed" ); +#endif /* MBEDTLS_XTEA_C */ + // END generated code + + if( strlen( buf ) != 0 ) + return; + + mbedtls_snprintf( buf, buflen, "UNKNOWN ERROR CODE (%04X)", use_ret ); +} + +#else /* MBEDTLS_ERROR_C */ + +#if defined(MBEDTLS_ERROR_STRERROR_DUMMY) + +/* + * Provide an non-function in case MBEDTLS_ERROR_C is not defined + */ +void mbedtls_strerror( int ret, char *buf, size_t buflen ) +{ + ((void) ret); + + if( buflen > 0 ) + buf[0] = '\0'; +} + +#endif /* MBEDTLS_ERROR_STRERROR_DUMMY */ + +#endif /* MBEDTLS_ERROR_C */ diff --git a/common/mbedtls/error.h b/common/mbedtls/error.h new file mode 100644 index 00000000..43217908 --- /dev/null +++ b/common/mbedtls/error.h @@ -0,0 +1,124 @@ +/** + * \file error.h + * + * \brief Error to string translation + */ +/* + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_ERROR_H +#define MBEDTLS_ERROR_H + +#include + +/** + * Error code layout. + * + * Currently we try to keep all error codes within the negative space of 16 + * bits signed integers to support all platforms (-0x0001 - -0x7FFF). In + * addition we'd like to give two layers of information on the error if + * possible. + * + * For that purpose the error codes are segmented in the following manner: + * + * 16 bit error code bit-segmentation + * + * 1 bit - Unused (sign bit) + * 3 bits - High level module ID + * 5 bits - Module-dependent error code + * 7 bits - Low level module errors + * + * For historical reasons, low-level error codes are divided in even and odd, + * even codes were assigned first, and -1 is reserved for other errors. + * + * Low-level module errors (0x0002-0x007E, 0x0003-0x007F) + * + * Module Nr Codes assigned + * MPI 7 0x0002-0x0010 + * GCM 3 0x0012-0x0014 0x0013-0x0013 + * BLOWFISH 3 0x0016-0x0018 0x0017-0x0017 + * THREADING 3 0x001A-0x001E + * AES 5 0x0020-0x0022 0x0021-0x0025 + * CAMELLIA 3 0x0024-0x0026 0x0027-0x0027 + * XTEA 2 0x0028-0x0028 0x0029-0x0029 + * BASE64 2 0x002A-0x002C + * OID 1 0x002E-0x002E 0x000B-0x000B + * PADLOCK 1 0x0030-0x0030 + * DES 2 0x0032-0x0032 0x0033-0x0033 + * CTR_DBRG 4 0x0034-0x003A + * ENTROPY 3 0x003C-0x0040 0x003D-0x003F + * NET 13 0x0042-0x0052 0x0043-0x0049 + * ARIA 4 0x0058-0x005E + * ASN1 7 0x0060-0x006C + * CMAC 1 0x007A-0x007A + * PBKDF2 1 0x007C-0x007C + * HMAC_DRBG 4 0x0003-0x0009 + * CCM 3 0x000D-0x0011 + * ARC4 1 0x0019-0x0019 + * MD2 1 0x002B-0x002B + * MD4 1 0x002D-0x002D + * MD5 1 0x002F-0x002F + * RIPEMD160 1 0x0031-0x0031 + * SHA1 1 0x0035-0x0035 + * SHA256 1 0x0037-0x0037 + * SHA512 1 0x0039-0x0039 + * CHACHA20 3 0x0051-0x0055 + * POLY1305 3 0x0057-0x005B + * CHACHAPOLY 2 0x0054-0x0056 + * + * High-level module nr (3 bits - 0x0...-0x7...) + * Name ID Nr of Errors + * PEM 1 9 + * PKCS#12 1 4 (Started from top) + * X509 2 20 + * PKCS5 2 4 (Started from top) + * DHM 3 11 + * PK 3 15 (Started from top) + * RSA 4 11 + * ECP 4 9 (Started from top) + * MD 5 5 + * HKDF 5 1 (Started from top) + * CIPHER 6 8 + * SSL 6 22 (Started from top) + * SSL 7 31 + * + * Module dependent error code (5 bits 0x.00.-0x.F8.) + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Translate a mbed TLS error code into a string representation, + * Result is truncated if necessary and always includes a terminating + * null byte. + * + * \param errnum error code + * \param buffer buffer to place representation in + * \param buflen length of the buffer + */ +void mbedtls_strerror( int errnum, char *buffer, size_t buflen ); + +#ifdef __cplusplus +} +#endif + +#endif /* error.h */ diff --git a/common/mbedtls/md.c b/common/mbedtls/md.c new file mode 100644 index 00000000..0530621b --- /dev/null +++ b/common/mbedtls/md.c @@ -0,0 +1,477 @@ +/** + * \file mbedtls_md.c + * + * \brief Generic message digest wrapper for mbed TLS + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_MD_C) + +#include "mbedtls/md.h" +#include "mbedtls/md_internal.h" +#include "mbedtls/platform_util.h" + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#include + +#if defined(MBEDTLS_FS_IO) +#include +#endif + +/* + * Reminder: update profiles in x509_crt.c when adding a new hash! + */ +static const int supported_digests[] = { + +#if defined(MBEDTLS_SHA512_C) + MBEDTLS_MD_SHA512, + MBEDTLS_MD_SHA384, +#endif + +#if defined(MBEDTLS_SHA256_C) + MBEDTLS_MD_SHA256, + MBEDTLS_MD_SHA224, +#endif + +#if defined(MBEDTLS_SHA1_C) + MBEDTLS_MD_SHA1, +#endif + +#if defined(MBEDTLS_RIPEMD160_C) + MBEDTLS_MD_RIPEMD160, +#endif + +#if defined(MBEDTLS_MD5_C) + MBEDTLS_MD_MD5, +#endif + +#if defined(MBEDTLS_MD4_C) + MBEDTLS_MD_MD4, +#endif + +#if defined(MBEDTLS_MD2_C) + MBEDTLS_MD_MD2, +#endif + + MBEDTLS_MD_NONE +}; + +const int *mbedtls_md_list( void ) +{ + return( supported_digests ); +} + +const mbedtls_md_info_t *mbedtls_md_info_from_string( const char *md_name ) +{ + if( NULL == md_name ) + return( NULL ); + + /* Get the appropriate digest information */ +#if defined(MBEDTLS_MD2_C) + if( !strcmp( "MD2", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_MD2 ); +#endif +#if defined(MBEDTLS_MD4_C) + if( !strcmp( "MD4", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_MD4 ); +#endif +#if defined(MBEDTLS_MD5_C) + if( !strcmp( "MD5", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_MD5 ); +#endif +#if defined(MBEDTLS_RIPEMD160_C) + if( !strcmp( "RIPEMD160", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_RIPEMD160 ); +#endif +#if defined(MBEDTLS_SHA1_C) + if( !strcmp( "SHA1", md_name ) || !strcmp( "SHA", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_SHA1 ); +#endif +#if defined(MBEDTLS_SHA256_C) + if( !strcmp( "SHA224", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_SHA224 ); + if( !strcmp( "SHA256", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 ); +#endif +#if defined(MBEDTLS_SHA512_C) + if( !strcmp( "SHA384", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_SHA384 ); + if( !strcmp( "SHA512", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_SHA512 ); +#endif + return( NULL ); +} + +const mbedtls_md_info_t *mbedtls_md_info_from_type( mbedtls_md_type_t md_type ) +{ + switch( md_type ) + { +#if defined(MBEDTLS_MD2_C) + case MBEDTLS_MD_MD2: + return( &mbedtls_md2_info ); +#endif +#if defined(MBEDTLS_MD4_C) + case MBEDTLS_MD_MD4: + return( &mbedtls_md4_info ); +#endif +#if defined(MBEDTLS_MD5_C) + case MBEDTLS_MD_MD5: + return( &mbedtls_md5_info ); +#endif +#if defined(MBEDTLS_RIPEMD160_C) + case MBEDTLS_MD_RIPEMD160: + return( &mbedtls_ripemd160_info ); +#endif +#if defined(MBEDTLS_SHA1_C) + case MBEDTLS_MD_SHA1: + return( &mbedtls_sha1_info ); +#endif +#if defined(MBEDTLS_SHA256_C) + case MBEDTLS_MD_SHA224: + return( &mbedtls_sha224_info ); + case MBEDTLS_MD_SHA256: + return( &mbedtls_sha256_info ); +#endif +#if defined(MBEDTLS_SHA512_C) + case MBEDTLS_MD_SHA384: + return( &mbedtls_sha384_info ); + case MBEDTLS_MD_SHA512: + return( &mbedtls_sha512_info ); +#endif + default: + return( NULL ); + } +} + +void mbedtls_md_init( mbedtls_md_context_t *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_md_context_t ) ); +} + +void mbedtls_md_free( mbedtls_md_context_t *ctx ) +{ + if( ctx == NULL || ctx->md_info == NULL ) + return; + + if( ctx->md_ctx != NULL ) + ctx->md_info->ctx_free_func( ctx->md_ctx ); + + if( ctx->hmac_ctx != NULL ) + { + mbedtls_platform_zeroize( ctx->hmac_ctx, + 2 * ctx->md_info->block_size ); + mbedtls_free( ctx->hmac_ctx ); + } + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_md_context_t ) ); +} + +int mbedtls_md_clone( mbedtls_md_context_t *dst, + const mbedtls_md_context_t *src ) +{ + if( dst == NULL || dst->md_info == NULL || + src == NULL || src->md_info == NULL || + dst->md_info != src->md_info ) + { + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + } + + dst->md_info->clone_func( dst->md_ctx, src->md_ctx ); + + return( 0 ); +} + +#if ! defined(MBEDTLS_DEPRECATED_REMOVED) +int mbedtls_md_init_ctx( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info ) +{ + return mbedtls_md_setup( ctx, md_info, 1 ); +} +#endif + +int mbedtls_md_setup( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info, int hmac ) +{ + if( md_info == NULL || ctx == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + if( ( ctx->md_ctx = md_info->ctx_alloc_func() ) == NULL ) + return( MBEDTLS_ERR_MD_ALLOC_FAILED ); + + if( hmac != 0 ) + { + ctx->hmac_ctx = mbedtls_calloc( 2, md_info->block_size ); + if( ctx->hmac_ctx == NULL ) + { + md_info->ctx_free_func( ctx->md_ctx ); + return( MBEDTLS_ERR_MD_ALLOC_FAILED ); + } + } + + ctx->md_info = md_info; + + return( 0 ); +} + +int mbedtls_md_starts( mbedtls_md_context_t *ctx ) +{ + if( ctx == NULL || ctx->md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + return( ctx->md_info->starts_func( ctx->md_ctx ) ); +} + +int mbedtls_md_update( mbedtls_md_context_t *ctx, const unsigned char *input, size_t ilen ) +{ + if( ctx == NULL || ctx->md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + return( ctx->md_info->update_func( ctx->md_ctx, input, ilen ) ); +} + +int mbedtls_md_finish( mbedtls_md_context_t *ctx, unsigned char *output ) +{ + if( ctx == NULL || ctx->md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + return( ctx->md_info->finish_func( ctx->md_ctx, output ) ); +} + +int mbedtls_md( const mbedtls_md_info_t *md_info, const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + if( md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + return( md_info->digest_func( input, ilen, output ) ); +} + +#if defined(MBEDTLS_FS_IO) +int mbedtls_md_file( const mbedtls_md_info_t *md_info, const char *path, unsigned char *output ) +{ + int ret; + FILE *f; + size_t n; + mbedtls_md_context_t ctx; + unsigned char buf[1024]; + + if( md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( MBEDTLS_ERR_MD_FILE_IO_ERROR ); + + mbedtls_md_init( &ctx ); + + if( ( ret = mbedtls_md_setup( &ctx, md_info, 0 ) ) != 0 ) + goto cleanup; + + if( ( ret = md_info->starts_func( ctx.md_ctx ) ) != 0 ) + goto cleanup; + + while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 ) + if( ( ret = md_info->update_func( ctx.md_ctx, buf, n ) ) != 0 ) + goto cleanup; + + if( ferror( f ) != 0 ) + ret = MBEDTLS_ERR_MD_FILE_IO_ERROR; + else + ret = md_info->finish_func( ctx.md_ctx, output ); + +cleanup: + mbedtls_platform_zeroize( buf, sizeof( buf ) ); + fclose( f ); + mbedtls_md_free( &ctx ); + + return( ret ); +} +#endif /* MBEDTLS_FS_IO */ + +int mbedtls_md_hmac_starts( mbedtls_md_context_t *ctx, const unsigned char *key, size_t keylen ) +{ + int ret; + unsigned char sum[MBEDTLS_MD_MAX_SIZE]; + unsigned char *ipad, *opad; + size_t i; + + if( ctx == NULL || ctx->md_info == NULL || ctx->hmac_ctx == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + if( keylen > (size_t) ctx->md_info->block_size ) + { + if( ( ret = ctx->md_info->starts_func( ctx->md_ctx ) ) != 0 ) + goto cleanup; + if( ( ret = ctx->md_info->update_func( ctx->md_ctx, key, keylen ) ) != 0 ) + goto cleanup; + if( ( ret = ctx->md_info->finish_func( ctx->md_ctx, sum ) ) != 0 ) + goto cleanup; + + keylen = ctx->md_info->size; + key = sum; + } + + ipad = (unsigned char *) ctx->hmac_ctx; + opad = (unsigned char *) ctx->hmac_ctx + ctx->md_info->block_size; + + memset( ipad, 0x36, ctx->md_info->block_size ); + memset( opad, 0x5C, ctx->md_info->block_size ); + + for( i = 0; i < keylen; i++ ) + { + ipad[i] = (unsigned char)( ipad[i] ^ key[i] ); + opad[i] = (unsigned char)( opad[i] ^ key[i] ); + } + + if( ( ret = ctx->md_info->starts_func( ctx->md_ctx ) ) != 0 ) + goto cleanup; + if( ( ret = ctx->md_info->update_func( ctx->md_ctx, ipad, + ctx->md_info->block_size ) ) != 0 ) + goto cleanup; + +cleanup: + mbedtls_platform_zeroize( sum, sizeof( sum ) ); + + return( ret ); +} + +int mbedtls_md_hmac_update( mbedtls_md_context_t *ctx, const unsigned char *input, size_t ilen ) +{ + if( ctx == NULL || ctx->md_info == NULL || ctx->hmac_ctx == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + return( ctx->md_info->update_func( ctx->md_ctx, input, ilen ) ); +} + +int mbedtls_md_hmac_finish( mbedtls_md_context_t *ctx, unsigned char *output ) +{ + int ret; + unsigned char tmp[MBEDTLS_MD_MAX_SIZE]; + unsigned char *opad; + + if( ctx == NULL || ctx->md_info == NULL || ctx->hmac_ctx == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + opad = (unsigned char *) ctx->hmac_ctx + ctx->md_info->block_size; + + if( ( ret = ctx->md_info->finish_func( ctx->md_ctx, tmp ) ) != 0 ) + return( ret ); + if( ( ret = ctx->md_info->starts_func( ctx->md_ctx ) ) != 0 ) + return( ret ); + if( ( ret = ctx->md_info->update_func( ctx->md_ctx, opad, + ctx->md_info->block_size ) ) != 0 ) + return( ret ); + if( ( ret = ctx->md_info->update_func( ctx->md_ctx, tmp, + ctx->md_info->size ) ) != 0 ) + return( ret ); + return( ctx->md_info->finish_func( ctx->md_ctx, output ) ); +} + +int mbedtls_md_hmac_reset( mbedtls_md_context_t *ctx ) +{ + int ret; + unsigned char *ipad; + + if( ctx == NULL || ctx->md_info == NULL || ctx->hmac_ctx == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + ipad = (unsigned char *) ctx->hmac_ctx; + + if( ( ret = ctx->md_info->starts_func( ctx->md_ctx ) ) != 0 ) + return( ret ); + return( ctx->md_info->update_func( ctx->md_ctx, ipad, + ctx->md_info->block_size ) ); +} + +int mbedtls_md_hmac( const mbedtls_md_info_t *md_info, + const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + mbedtls_md_context_t ctx; + int ret; + + if( md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + mbedtls_md_init( &ctx ); + + if( ( ret = mbedtls_md_setup( &ctx, md_info, 1 ) ) != 0 ) + goto cleanup; + + if( ( ret = mbedtls_md_hmac_starts( &ctx, key, keylen ) ) != 0 ) + goto cleanup; + if( ( ret = mbedtls_md_hmac_update( &ctx, input, ilen ) ) != 0 ) + goto cleanup; + if( ( ret = mbedtls_md_hmac_finish( &ctx, output ) ) != 0 ) + goto cleanup; + +cleanup: + mbedtls_md_free( &ctx ); + + return( ret ); +} + +int mbedtls_md_process( mbedtls_md_context_t *ctx, const unsigned char *data ) +{ + if( ctx == NULL || ctx->md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + return( ctx->md_info->process_func( ctx->md_ctx, data ) ); +} + +unsigned char mbedtls_md_get_size( const mbedtls_md_info_t *md_info ) +{ + if( md_info == NULL ) + return( 0 ); + + return md_info->size; +} + +mbedtls_md_type_t mbedtls_md_get_type( const mbedtls_md_info_t *md_info ) +{ + if( md_info == NULL ) + return( MBEDTLS_MD_NONE ); + + return md_info->type; +} + +const char *mbedtls_md_get_name( const mbedtls_md_info_t *md_info ) +{ + if( md_info == NULL ) + return( NULL ); + + return md_info->name; +} + +#endif /* MBEDTLS_MD_C */ diff --git a/common/mbedtls/md.h b/common/mbedtls/md.h new file mode 100644 index 00000000..797d5ff3 --- /dev/null +++ b/common/mbedtls/md.h @@ -0,0 +1,468 @@ + /** + * \file md.h + * + * \brief This file contains the generic message-digest wrapper. + * + * \author Adriaan de Jong + */ +/* + * Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_MD_H +#define MBEDTLS_MD_H + +#include + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#define MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE -0x5080 /**< The selected feature is not available. */ +#define MBEDTLS_ERR_MD_BAD_INPUT_DATA -0x5100 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_MD_ALLOC_FAILED -0x5180 /**< Failed to allocate memory. */ +#define MBEDTLS_ERR_MD_FILE_IO_ERROR -0x5200 /**< Opening or reading of file failed. */ +#define MBEDTLS_ERR_MD_HW_ACCEL_FAILED -0x5280 /**< MD hardware accelerator failed. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Supported message digests. + * + * \warning MD2, MD4, MD5 and SHA-1 are considered weak message digests and + * their use constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +typedef enum { + MBEDTLS_MD_NONE=0, /**< None. */ + MBEDTLS_MD_MD2, /**< The MD2 message digest. */ + MBEDTLS_MD_MD4, /**< The MD4 message digest. */ + MBEDTLS_MD_MD5, /**< The MD5 message digest. */ + MBEDTLS_MD_SHA1, /**< The SHA-1 message digest. */ + MBEDTLS_MD_SHA224, /**< The SHA-224 message digest. */ + MBEDTLS_MD_SHA256, /**< The SHA-256 message digest. */ + MBEDTLS_MD_SHA384, /**< The SHA-384 message digest. */ + MBEDTLS_MD_SHA512, /**< The SHA-512 message digest. */ + MBEDTLS_MD_RIPEMD160, /**< The RIPEMD-160 message digest. */ +} mbedtls_md_type_t; + +#if defined(MBEDTLS_SHA512_C) +#define MBEDTLS_MD_MAX_SIZE 64 /* longest known is SHA512 */ +#else +#define MBEDTLS_MD_MAX_SIZE 32 /* longest known is SHA256 or less */ +#endif + +/** + * Opaque struct defined in md_internal.h. + */ +typedef struct mbedtls_md_info_t mbedtls_md_info_t; + +/** + * The generic message-digest context. + */ +typedef struct mbedtls_md_context_t +{ + /** Information about the associated message digest. */ + const mbedtls_md_info_t *md_info; + + /** The digest-specific context. */ + void *md_ctx; + + /** The HMAC part of the context. */ + void *hmac_ctx; +} mbedtls_md_context_t; + +/** + * \brief This function returns the list of digests supported by the + * generic digest module. + * + * \return A statically allocated array of digests. Each element + * in the returned list is an integer belonging to the + * message-digest enumeration #mbedtls_md_type_t. + * The last entry is 0. + */ +const int *mbedtls_md_list( void ); + +/** + * \brief This function returns the message-digest information + * associated with the given digest name. + * + * \param md_name The name of the digest to search for. + * + * \return The message-digest information associated with \p md_name. + * \return NULL if the associated message-digest information is not found. + */ +const mbedtls_md_info_t *mbedtls_md_info_from_string( const char *md_name ); + +/** + * \brief This function returns the message-digest information + * associated with the given digest type. + * + * \param md_type The type of digest to search for. + * + * \return The message-digest information associated with \p md_type. + * \return NULL if the associated message-digest information is not found. + */ +const mbedtls_md_info_t *mbedtls_md_info_from_type( mbedtls_md_type_t md_type ); + +/** + * \brief This function initializes a message-digest context without + * binding it to a particular message-digest algorithm. + * + * This function should always be called first. It prepares the + * context for mbedtls_md_setup() for binding it to a + * message-digest algorithm. + */ +void mbedtls_md_init( mbedtls_md_context_t *ctx ); + +/** + * \brief This function clears the internal structure of \p ctx and + * frees any embedded internal structure, but does not free + * \p ctx itself. + * + * If you have called mbedtls_md_setup() on \p ctx, you must + * call mbedtls_md_free() when you are no longer using the + * context. + * Calling this function if you have previously + * called mbedtls_md_init() and nothing else is optional. + * You must not call this function if you have not called + * mbedtls_md_init(). + */ +void mbedtls_md_free( mbedtls_md_context_t *ctx ); + +#if ! defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief This function selects the message digest algorithm to use, + * and allocates internal structures. + * + * It should be called after mbedtls_md_init() or mbedtls_md_free(). + * Makes it necessary to call mbedtls_md_free() later. + * + * \deprecated Superseded by mbedtls_md_setup() in 2.0.0 + * + * \param ctx The context to set up. + * \param md_info The information structure of the message-digest algorithm + * to use. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification + * failure. + * \return #MBEDTLS_ERR_MD_ALLOC_FAILED on memory-allocation failure. + */ +int mbedtls_md_init_ctx( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info ) MBEDTLS_DEPRECATED; +#undef MBEDTLS_DEPRECATED +#endif /* MBEDTLS_DEPRECATED_REMOVED */ + +/** + * \brief This function selects the message digest algorithm to use, + * and allocates internal structures. + * + * It should be called after mbedtls_md_init() or + * mbedtls_md_free(). Makes it necessary to call + * mbedtls_md_free() later. + * + * \param ctx The context to set up. + * \param md_info The information structure of the message-digest algorithm + * to use. + * \param hmac Defines if HMAC is used. 0: HMAC is not used (saves some memory), + * or non-zero: HMAC is used with this context. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification + * failure. + * \return #MBEDTLS_ERR_MD_ALLOC_FAILED on memory-allocation failure. + */ +int mbedtls_md_setup( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info, int hmac ); + +/** + * \brief This function clones the state of an message-digest + * context. + * + * \note You must call mbedtls_md_setup() on \c dst before calling + * this function. + * + * \note The two contexts must have the same type, + * for example, both are SHA-256. + * + * \warning This function clones the message-digest state, not the + * HMAC state. + * + * \param dst The destination context. + * \param src The context to be cloned. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification failure. + */ +int mbedtls_md_clone( mbedtls_md_context_t *dst, + const mbedtls_md_context_t *src ); + +/** + * \brief This function extracts the message-digest size from the + * message-digest information structure. + * + * \param md_info The information structure of the message-digest algorithm + * to use. + * + * \return The size of the message-digest output in Bytes. + */ +unsigned char mbedtls_md_get_size( const mbedtls_md_info_t *md_info ); + +/** + * \brief This function extracts the message-digest type from the + * message-digest information structure. + * + * \param md_info The information structure of the message-digest algorithm + * to use. + * + * \return The type of the message digest. + */ +mbedtls_md_type_t mbedtls_md_get_type( const mbedtls_md_info_t *md_info ); + +/** + * \brief This function extracts the message-digest name from the + * message-digest information structure. + * + * \param md_info The information structure of the message-digest algorithm + * to use. + * + * \return The name of the message digest. + */ +const char *mbedtls_md_get_name( const mbedtls_md_info_t *md_info ); + +/** + * \brief This function starts a message-digest computation. + * + * You must call this function after setting up the context + * with mbedtls_md_setup(), and before passing data with + * mbedtls_md_update(). + * + * \param ctx The generic message-digest context. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification + * failure. + */ +int mbedtls_md_starts( mbedtls_md_context_t *ctx ); + +/** + * \brief This function feeds an input buffer into an ongoing + * message-digest computation. + * + * You must call mbedtls_md_starts() before calling this + * function. You may call this function multiple times. + * Afterwards, call mbedtls_md_finish(). + * + * \param ctx The generic message-digest context. + * \param input The buffer holding the input data. + * \param ilen The length of the input data. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification + * failure. + */ +int mbedtls_md_update( mbedtls_md_context_t *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief This function finishes the digest operation, + * and writes the result to the output buffer. + * + * Call this function after a call to mbedtls_md_starts(), + * followed by any number of calls to mbedtls_md_update(). + * Afterwards, you may either clear the context with + * mbedtls_md_free(), or call mbedtls_md_starts() to reuse + * the context for another digest operation with the same + * algorithm. + * + * \param ctx The generic message-digest context. + * \param output The buffer for the generic message-digest checksum result. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification + * failure. + */ +int mbedtls_md_finish( mbedtls_md_context_t *ctx, unsigned char *output ); + +/** + * \brief This function calculates the message-digest of a buffer, + * with respect to a configurable message-digest algorithm + * in a single call. + * + * The result is calculated as + * Output = message_digest(input buffer). + * + * \param md_info The information structure of the message-digest algorithm + * to use. + * \param input The buffer holding the data. + * \param ilen The length of the input data. + * \param output The generic message-digest checksum result. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification + * failure. + */ +int mbedtls_md( const mbedtls_md_info_t *md_info, const unsigned char *input, size_t ilen, + unsigned char *output ); + +#if defined(MBEDTLS_FS_IO) +/** + * \brief This function calculates the message-digest checksum + * result of the contents of the provided file. + * + * The result is calculated as + * Output = message_digest(file contents). + * + * \param md_info The information structure of the message-digest algorithm + * to use. + * \param path The input file name. + * \param output The generic message-digest checksum result. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_FILE_IO_ERROR on an I/O error accessing + * the file pointed by \p path. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA if \p md_info was NULL. + */ +int mbedtls_md_file( const mbedtls_md_info_t *md_info, const char *path, + unsigned char *output ); +#endif /* MBEDTLS_FS_IO */ + +/** + * \brief This function sets the HMAC key and prepares to + * authenticate a new message. + * + * Call this function after mbedtls_md_setup(), to use + * the MD context for an HMAC calculation, then call + * mbedtls_md_hmac_update() to provide the input data, and + * mbedtls_md_hmac_finish() to get the HMAC value. + * + * \param ctx The message digest context containing an embedded HMAC + * context. + * \param key The HMAC secret key. + * \param keylen The length of the HMAC key in Bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification + * failure. + */ +int mbedtls_md_hmac_starts( mbedtls_md_context_t *ctx, const unsigned char *key, + size_t keylen ); + +/** + * \brief This function feeds an input buffer into an ongoing HMAC + * computation. + * + * Call mbedtls_md_hmac_starts() or mbedtls_md_hmac_reset() + * before calling this function. + * You may call this function multiple times to pass the + * input piecewise. + * Afterwards, call mbedtls_md_hmac_finish(). + * + * \param ctx The message digest context containing an embedded HMAC + * context. + * \param input The buffer holding the input data. + * \param ilen The length of the input data. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification + * failure. + */ +int mbedtls_md_hmac_update( mbedtls_md_context_t *ctx, const unsigned char *input, + size_t ilen ); + +/** + * \brief This function finishes the HMAC operation, and writes + * the result to the output buffer. + * + * Call this function after mbedtls_md_hmac_starts() and + * mbedtls_md_hmac_update() to get the HMAC value. Afterwards + * you may either call mbedtls_md_free() to clear the context, + * or call mbedtls_md_hmac_reset() to reuse the context with + * the same HMAC key. + * + * \param ctx The message digest context containing an embedded HMAC + * context. + * \param output The generic HMAC checksum result. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification + * failure. + */ +int mbedtls_md_hmac_finish( mbedtls_md_context_t *ctx, unsigned char *output); + +/** + * \brief This function prepares to authenticate a new message with + * the same key as the previous HMAC operation. + * + * You may call this function after mbedtls_md_hmac_finish(). + * Afterwards call mbedtls_md_hmac_update() to pass the new + * input. + * + * \param ctx The message digest context containing an embedded HMAC + * context. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification + * failure. + */ +int mbedtls_md_hmac_reset( mbedtls_md_context_t *ctx ); + +/** + * \brief This function calculates the full generic HMAC + * on the input buffer with the provided key. + * + * The function allocates the context, performs the + * calculation, and frees the context. + * + * The HMAC result is calculated as + * output = generic HMAC(hmac key, input buffer). + * + * \param md_info The information structure of the message-digest algorithm + * to use. + * \param key The HMAC secret key. + * \param keylen The length of the HMAC secret key in Bytes. + * \param input The buffer holding the input data. + * \param ilen The length of the input data. + * \param output The generic HMAC result. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification + * failure. + */ +int mbedtls_md_hmac( const mbedtls_md_info_t *md_info, const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char *output ); + +/* Internal use */ +int mbedtls_md_process( mbedtls_md_context_t *ctx, const unsigned char *data ); + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_MD_H */ diff --git a/common/mbedtls/md5.c b/common/mbedtls/md5.c new file mode 100644 index 00000000..e0b4c768 --- /dev/null +++ b/common/mbedtls/md5.c @@ -0,0 +1,497 @@ +/* + * RFC 1321 compliant MD5 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The MD5 algorithm was designed by Ron Rivest in 1991. + * + * http://www.ietf.org/rfc/rfc1321.txt + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_MD5_C) + +#include "mbedtls/md5.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_MD5_ALT) + +/* + * 32-bit integer manipulation macros (little endian) + */ +#ifndef GET_UINT32_LE +#define GET_UINT32_LE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] ) \ + | ( (uint32_t) (b)[(i) + 1] << 8 ) \ + | ( (uint32_t) (b)[(i) + 2] << 16 ) \ + | ( (uint32_t) (b)[(i) + 3] << 24 ); \ +} +#endif + +#ifndef PUT_UINT32_LE +#define PUT_UINT32_LE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( ( (n) ) & 0xFF ); \ + (b)[(i) + 1] = (unsigned char) ( ( (n) >> 8 ) & 0xFF ); \ + (b)[(i) + 2] = (unsigned char) ( ( (n) >> 16 ) & 0xFF ); \ + (b)[(i) + 3] = (unsigned char) ( ( (n) >> 24 ) & 0xFF ); \ +} +#endif + +void mbedtls_md5_init( mbedtls_md5_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_md5_context ) ); +} + +void mbedtls_md5_free( mbedtls_md5_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_md5_context ) ); +} + +void mbedtls_md5_clone( mbedtls_md5_context *dst, + const mbedtls_md5_context *src ) +{ + *dst = *src; +} + +/* + * MD5 context setup + */ +int mbedtls_md5_starts_ret( mbedtls_md5_context *ctx ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_md5_starts( mbedtls_md5_context *ctx ) +{ + mbedtls_md5_starts_ret( ctx ); +} +#endif + +#if !defined(MBEDTLS_MD5_PROCESS_ALT) +int mbedtls_internal_md5_process( mbedtls_md5_context *ctx, + const unsigned char data[64] ) +{ + uint32_t X[16], A, B, C, D; + + GET_UINT32_LE( X[ 0], data, 0 ); + GET_UINT32_LE( X[ 1], data, 4 ); + GET_UINT32_LE( X[ 2], data, 8 ); + GET_UINT32_LE( X[ 3], data, 12 ); + GET_UINT32_LE( X[ 4], data, 16 ); + GET_UINT32_LE( X[ 5], data, 20 ); + GET_UINT32_LE( X[ 6], data, 24 ); + GET_UINT32_LE( X[ 7], data, 28 ); + GET_UINT32_LE( X[ 8], data, 32 ); + GET_UINT32_LE( X[ 9], data, 36 ); + GET_UINT32_LE( X[10], data, 40 ); + GET_UINT32_LE( X[11], data, 44 ); + GET_UINT32_LE( X[12], data, 48 ); + GET_UINT32_LE( X[13], data, 52 ); + GET_UINT32_LE( X[14], data, 56 ); + GET_UINT32_LE( X[15], data, 60 ); + +#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) + +#define P(a,b,c,d,k,s,t) \ +{ \ + a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \ +} + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + +#define F(x,y,z) (z ^ (x & (y ^ z))) + + P( A, B, C, D, 0, 7, 0xD76AA478 ); + P( D, A, B, C, 1, 12, 0xE8C7B756 ); + P( C, D, A, B, 2, 17, 0x242070DB ); + P( B, C, D, A, 3, 22, 0xC1BDCEEE ); + P( A, B, C, D, 4, 7, 0xF57C0FAF ); + P( D, A, B, C, 5, 12, 0x4787C62A ); + P( C, D, A, B, 6, 17, 0xA8304613 ); + P( B, C, D, A, 7, 22, 0xFD469501 ); + P( A, B, C, D, 8, 7, 0x698098D8 ); + P( D, A, B, C, 9, 12, 0x8B44F7AF ); + P( C, D, A, B, 10, 17, 0xFFFF5BB1 ); + P( B, C, D, A, 11, 22, 0x895CD7BE ); + P( A, B, C, D, 12, 7, 0x6B901122 ); + P( D, A, B, C, 13, 12, 0xFD987193 ); + P( C, D, A, B, 14, 17, 0xA679438E ); + P( B, C, D, A, 15, 22, 0x49B40821 ); + +#undef F + +#define F(x,y,z) (y ^ (z & (x ^ y))) + + P( A, B, C, D, 1, 5, 0xF61E2562 ); + P( D, A, B, C, 6, 9, 0xC040B340 ); + P( C, D, A, B, 11, 14, 0x265E5A51 ); + P( B, C, D, A, 0, 20, 0xE9B6C7AA ); + P( A, B, C, D, 5, 5, 0xD62F105D ); + P( D, A, B, C, 10, 9, 0x02441453 ); + P( C, D, A, B, 15, 14, 0xD8A1E681 ); + P( B, C, D, A, 4, 20, 0xE7D3FBC8 ); + P( A, B, C, D, 9, 5, 0x21E1CDE6 ); + P( D, A, B, C, 14, 9, 0xC33707D6 ); + P( C, D, A, B, 3, 14, 0xF4D50D87 ); + P( B, C, D, A, 8, 20, 0x455A14ED ); + P( A, B, C, D, 13, 5, 0xA9E3E905 ); + P( D, A, B, C, 2, 9, 0xFCEFA3F8 ); + P( C, D, A, B, 7, 14, 0x676F02D9 ); + P( B, C, D, A, 12, 20, 0x8D2A4C8A ); + +#undef F + +#define F(x,y,z) (x ^ y ^ z) + + P( A, B, C, D, 5, 4, 0xFFFA3942 ); + P( D, A, B, C, 8, 11, 0x8771F681 ); + P( C, D, A, B, 11, 16, 0x6D9D6122 ); + P( B, C, D, A, 14, 23, 0xFDE5380C ); + P( A, B, C, D, 1, 4, 0xA4BEEA44 ); + P( D, A, B, C, 4, 11, 0x4BDECFA9 ); + P( C, D, A, B, 7, 16, 0xF6BB4B60 ); + P( B, C, D, A, 10, 23, 0xBEBFBC70 ); + P( A, B, C, D, 13, 4, 0x289B7EC6 ); + P( D, A, B, C, 0, 11, 0xEAA127FA ); + P( C, D, A, B, 3, 16, 0xD4EF3085 ); + P( B, C, D, A, 6, 23, 0x04881D05 ); + P( A, B, C, D, 9, 4, 0xD9D4D039 ); + P( D, A, B, C, 12, 11, 0xE6DB99E5 ); + P( C, D, A, B, 15, 16, 0x1FA27CF8 ); + P( B, C, D, A, 2, 23, 0xC4AC5665 ); + +#undef F + +#define F(x,y,z) (y ^ (x | ~z)) + + P( A, B, C, D, 0, 6, 0xF4292244 ); + P( D, A, B, C, 7, 10, 0x432AFF97 ); + P( C, D, A, B, 14, 15, 0xAB9423A7 ); + P( B, C, D, A, 5, 21, 0xFC93A039 ); + P( A, B, C, D, 12, 6, 0x655B59C3 ); + P( D, A, B, C, 3, 10, 0x8F0CCC92 ); + P( C, D, A, B, 10, 15, 0xFFEFF47D ); + P( B, C, D, A, 1, 21, 0x85845DD1 ); + P( A, B, C, D, 8, 6, 0x6FA87E4F ); + P( D, A, B, C, 15, 10, 0xFE2CE6E0 ); + P( C, D, A, B, 6, 15, 0xA3014314 ); + P( B, C, D, A, 13, 21, 0x4E0811A1 ); + P( A, B, C, D, 4, 6, 0xF7537E82 ); + P( D, A, B, C, 11, 10, 0xBD3AF235 ); + P( C, D, A, B, 2, 15, 0x2AD7D2BB ); + P( B, C, D, A, 9, 21, 0xEB86D391 ); + +#undef F + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_md5_process( mbedtls_md5_context *ctx, + const unsigned char data[64] ) +{ + mbedtls_internal_md5_process( ctx, data ); +} +#endif +#endif /* !MBEDTLS_MD5_PROCESS_ALT */ + +/* + * MD5 process buffer + */ +int mbedtls_md5_update_ret( mbedtls_md5_context *ctx, + const unsigned char *input, + size_t ilen ) +{ + int ret; + size_t fill; + uint32_t left; + + if( ilen == 0 ) + return( 0 ); + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), input, fill ); + if( ( ret = mbedtls_internal_md5_process( ctx, ctx->buffer ) ) != 0 ) + return( ret ); + + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + if( ( ret = mbedtls_internal_md5_process( ctx, input ) ) != 0 ) + return( ret ); + + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + { + memcpy( (void *) (ctx->buffer + left), input, ilen ); + } + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_md5_update( mbedtls_md5_context *ctx, + const unsigned char *input, + size_t ilen ) +{ + mbedtls_md5_update_ret( ctx, input, ilen ); +} +#endif + +/* + * MD5 final digest + */ +int mbedtls_md5_finish_ret( mbedtls_md5_context *ctx, + unsigned char output[16] ) +{ + int ret; + uint32_t used; + uint32_t high, low; + + /* + * Add padding: 0x80 then 0x00 until 8 bytes remain for the length + */ + used = ctx->total[0] & 0x3F; + + ctx->buffer[used++] = 0x80; + + if( used <= 56 ) + { + /* Enough room for padding + length in current block */ + memset( ctx->buffer + used, 0, 56 - used ); + } + else + { + /* We'll need an extra block */ + memset( ctx->buffer + used, 0, 64 - used ); + + if( ( ret = mbedtls_internal_md5_process( ctx, ctx->buffer ) ) != 0 ) + return( ret ); + + memset( ctx->buffer, 0, 56 ); + } + + /* + * Add message length + */ + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT32_LE( low, ctx->buffer, 56 ); + PUT_UINT32_LE( high, ctx->buffer, 60 ); + + if( ( ret = mbedtls_internal_md5_process( ctx, ctx->buffer ) ) != 0 ) + return( ret ); + + /* + * Output final state + */ + PUT_UINT32_LE( ctx->state[0], output, 0 ); + PUT_UINT32_LE( ctx->state[1], output, 4 ); + PUT_UINT32_LE( ctx->state[2], output, 8 ); + PUT_UINT32_LE( ctx->state[3], output, 12 ); + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_md5_finish( mbedtls_md5_context *ctx, + unsigned char output[16] ) +{ + mbedtls_md5_finish_ret( ctx, output ); +} +#endif + +#endif /* !MBEDTLS_MD5_ALT */ + +/* + * output = MD5( input buffer ) + */ +int mbedtls_md5_ret( const unsigned char *input, + size_t ilen, + unsigned char output[16] ) +{ + int ret; + mbedtls_md5_context ctx; + + mbedtls_md5_init( &ctx ); + + if( ( ret = mbedtls_md5_starts_ret( &ctx ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_md5_update_ret( &ctx, input, ilen ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_md5_finish_ret( &ctx, output ) ) != 0 ) + goto exit; + +exit: + mbedtls_md5_free( &ctx ); + + return( ret ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_md5( const unsigned char *input, + size_t ilen, + unsigned char output[16] ) +{ + mbedtls_md5_ret( input, ilen, output ); +} +#endif + +#if defined(MBEDTLS_SELF_TEST) +/* + * RFC 1321 test vectors + */ +static const unsigned char md5_test_buf[7][81] = +{ + { "" }, + { "a" }, + { "abc" }, + { "message digest" }, + { "abcdefghijklmnopqrstuvwxyz" }, + { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" }, + { "12345678901234567890123456789012345678901234567890123456789012" + "345678901234567890" } +}; + +static const size_t md5_test_buflen[7] = +{ + 0, 1, 3, 14, 26, 62, 80 +}; + +static const unsigned char md5_test_sum[7][16] = +{ + { 0xD4, 0x1D, 0x8C, 0xD9, 0x8F, 0x00, 0xB2, 0x04, + 0xE9, 0x80, 0x09, 0x98, 0xEC, 0xF8, 0x42, 0x7E }, + { 0x0C, 0xC1, 0x75, 0xB9, 0xC0, 0xF1, 0xB6, 0xA8, + 0x31, 0xC3, 0x99, 0xE2, 0x69, 0x77, 0x26, 0x61 }, + { 0x90, 0x01, 0x50, 0x98, 0x3C, 0xD2, 0x4F, 0xB0, + 0xD6, 0x96, 0x3F, 0x7D, 0x28, 0xE1, 0x7F, 0x72 }, + { 0xF9, 0x6B, 0x69, 0x7D, 0x7C, 0xB7, 0x93, 0x8D, + 0x52, 0x5A, 0x2F, 0x31, 0xAA, 0xF1, 0x61, 0xD0 }, + { 0xC3, 0xFC, 0xD3, 0xD7, 0x61, 0x92, 0xE4, 0x00, + 0x7D, 0xFB, 0x49, 0x6C, 0xCA, 0x67, 0xE1, 0x3B }, + { 0xD1, 0x74, 0xAB, 0x98, 0xD2, 0x77, 0xD9, 0xF5, + 0xA5, 0x61, 0x1C, 0x2C, 0x9F, 0x41, 0x9D, 0x9F }, + { 0x57, 0xED, 0xF4, 0xA2, 0x2B, 0xE3, 0xC9, 0x55, + 0xAC, 0x49, 0xDA, 0x2E, 0x21, 0x07, 0xB6, 0x7A } +}; + +/* + * Checkup routine + */ +int mbedtls_md5_self_test( int verbose ) +{ + int i, ret = 0; + unsigned char md5sum[16]; + + for( i = 0; i < 7; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " MD5 test #%d: ", i + 1 ); + + ret = mbedtls_md5_ret( md5_test_buf[i], md5_test_buflen[i], md5sum ); + if( ret != 0 ) + goto fail; + + if( memcmp( md5sum, md5_test_sum[i], 16 ) != 0 ) + { + ret = 1; + goto fail; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); + +fail: + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_MD5_C */ diff --git a/common/mbedtls/md5.h b/common/mbedtls/md5.h new file mode 100644 index 00000000..d3af51fb --- /dev/null +++ b/common/mbedtls/md5.h @@ -0,0 +1,308 @@ +/** + * \file md5.h + * + * \brief MD5 message digest algorithm (hash function) + * + * \warning MD5 is considered a weak message digest and its use constitutes a + * security risk. We recommend considering stronger message + * digests instead. + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_MD5_H +#define MBEDTLS_MD5_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#define MBEDTLS_ERR_MD5_HW_ACCEL_FAILED -0x002F /**< MD5 hardware accelerator failed */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_MD5_ALT) +// Regular implementation +// + +/** + * \brief MD5 context structure + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +typedef struct mbedtls_md5_context +{ + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[4]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ +} +mbedtls_md5_context; + +#else /* MBEDTLS_MD5_ALT */ +#include "md5_alt.h" +#endif /* MBEDTLS_MD5_ALT */ + +/** + * \brief Initialize MD5 context + * + * \param ctx MD5 context to be initialized + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +void mbedtls_md5_init( mbedtls_md5_context *ctx ); + +/** + * \brief Clear MD5 context + * + * \param ctx MD5 context to be cleared + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +void mbedtls_md5_free( mbedtls_md5_context *ctx ); + +/** + * \brief Clone (the state of) an MD5 context + * + * \param dst The destination context + * \param src The context to be cloned + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +void mbedtls_md5_clone( mbedtls_md5_context *dst, + const mbedtls_md5_context *src ); + +/** + * \brief MD5 context setup + * + * \param ctx context to be initialized + * + * \return 0 if successful + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +int mbedtls_md5_starts_ret( mbedtls_md5_context *ctx ); + +/** + * \brief MD5 process buffer + * + * \param ctx MD5 context + * \param input buffer holding the data + * \param ilen length of the input data + * + * \return 0 if successful + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +int mbedtls_md5_update_ret( mbedtls_md5_context *ctx, + const unsigned char *input, + size_t ilen ); + +/** + * \brief MD5 final digest + * + * \param ctx MD5 context + * \param output MD5 checksum result + * + * \return 0 if successful + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +int mbedtls_md5_finish_ret( mbedtls_md5_context *ctx, + unsigned char output[16] ); + +/** + * \brief MD5 process data block (internal use only) + * + * \param ctx MD5 context + * \param data buffer holding one block of data + * + * \return 0 if successful + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +int mbedtls_internal_md5_process( mbedtls_md5_context *ctx, + const unsigned char data[64] ); + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief MD5 context setup + * + * \deprecated Superseded by mbedtls_md5_starts_ret() in 2.7.0 + * + * \param ctx context to be initialized + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +MBEDTLS_DEPRECATED void mbedtls_md5_starts( mbedtls_md5_context *ctx ); + +/** + * \brief MD5 process buffer + * + * \deprecated Superseded by mbedtls_md5_update_ret() in 2.7.0 + * + * \param ctx MD5 context + * \param input buffer holding the data + * \param ilen length of the input data + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +MBEDTLS_DEPRECATED void mbedtls_md5_update( mbedtls_md5_context *ctx, + const unsigned char *input, + size_t ilen ); + +/** + * \brief MD5 final digest + * + * \deprecated Superseded by mbedtls_md5_finish_ret() in 2.7.0 + * + * \param ctx MD5 context + * \param output MD5 checksum result + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +MBEDTLS_DEPRECATED void mbedtls_md5_finish( mbedtls_md5_context *ctx, + unsigned char output[16] ); + +/** + * \brief MD5 process data block (internal use only) + * + * \deprecated Superseded by mbedtls_internal_md5_process() in 2.7.0 + * + * \param ctx MD5 context + * \param data buffer holding one block of data + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +MBEDTLS_DEPRECATED void mbedtls_md5_process( mbedtls_md5_context *ctx, + const unsigned char data[64] ); + +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +/** + * \brief Output = MD5( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD5 checksum result + * + * \return 0 if successful + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +int mbedtls_md5_ret( const unsigned char *input, + size_t ilen, + unsigned char output[16] ); + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief Output = MD5( input buffer ) + * + * \deprecated Superseded by mbedtls_md5_ret() in 2.7.0 + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD5 checksum result + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +MBEDTLS_DEPRECATED void mbedtls_md5( const unsigned char *input, + size_t ilen, + unsigned char output[16] ); + +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + * + * \warning MD5 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +int mbedtls_md5_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_md5.h */ diff --git a/common/mbedtls/md_internal.h b/common/mbedtls/md_internal.h new file mode 100644 index 00000000..b917cf34 --- /dev/null +++ b/common/mbedtls/md_internal.h @@ -0,0 +1,117 @@ +/** + * \file md_internal.h + * + * \brief Message digest wrappers. + * + * \warning This in an internal header. Do not include directly. + * + * \author Adriaan de Jong + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_MD_WRAP_H +#define MBEDTLS_MD_WRAP_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "md.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Message digest information. + * Allows message digest functions to be called in a generic way. + */ +struct mbedtls_md_info_t +{ + /** Digest identifier */ + mbedtls_md_type_t type; + + /** Name of the message digest */ + const char * name; + + /** Output length of the digest function in bytes */ + int size; + + /** Block length of the digest function in bytes */ + int block_size; + + /** Digest initialisation function */ + int (*starts_func)( void *ctx ); + + /** Digest update function */ + int (*update_func)( void *ctx, const unsigned char *input, size_t ilen ); + + /** Digest finalisation function */ + int (*finish_func)( void *ctx, unsigned char *output ); + + /** Generic digest function */ + int (*digest_func)( const unsigned char *input, size_t ilen, + unsigned char *output ); + + /** Allocate a new context */ + void * (*ctx_alloc_func)( void ); + + /** Free the given context */ + void (*ctx_free_func)( void *ctx ); + + /** Clone state from a context */ + void (*clone_func)( void *dst, const void *src ); + + /** Internal use only */ + int (*process_func)( void *ctx, const unsigned char *input ); +}; + +#if defined(MBEDTLS_MD2_C) +extern const mbedtls_md_info_t mbedtls_md2_info; +#endif +#if defined(MBEDTLS_MD4_C) +extern const mbedtls_md_info_t mbedtls_md4_info; +#endif +#if defined(MBEDTLS_MD5_C) +extern const mbedtls_md_info_t mbedtls_md5_info; +#endif +#if defined(MBEDTLS_RIPEMD160_C) +extern const mbedtls_md_info_t mbedtls_ripemd160_info; +#endif +#if defined(MBEDTLS_SHA1_C) +extern const mbedtls_md_info_t mbedtls_sha1_info; +#endif +#if defined(MBEDTLS_SHA256_C) +extern const mbedtls_md_info_t mbedtls_sha224_info; +extern const mbedtls_md_info_t mbedtls_sha256_info; +#endif +#if defined(MBEDTLS_SHA512_C) +extern const mbedtls_md_info_t mbedtls_sha384_info; +extern const mbedtls_md_info_t mbedtls_sha512_info; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_MD_WRAP_H */ diff --git a/common/mbedtls/md_wrap.c b/common/mbedtls/md_wrap.c new file mode 100644 index 00000000..97067b04 --- /dev/null +++ b/common/mbedtls/md_wrap.c @@ -0,0 +1,588 @@ +/** + * \file md_wrap.c + * + * \brief Generic message digest wrapper for mbed TLS + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_MD_C) + +#include "mbedtls/md_internal.h" + +#if defined(MBEDTLS_MD2_C) +#include "mbedtls/md2.h" +#endif + +#if defined(MBEDTLS_MD4_C) +#include "mbedtls/md4.h" +#endif + +#if defined(MBEDTLS_MD5_C) +#include "mbedtls/md5.h" +#endif + +#if defined(MBEDTLS_RIPEMD160_C) +#include "mbedtls/ripemd160.h" +#endif + +#if defined(MBEDTLS_SHA1_C) +#include "mbedtls/sha1.h" +#endif + +#if defined(MBEDTLS_SHA256_C) +#include "mbedtls/sha256.h" +#endif + +#if defined(MBEDTLS_SHA512_C) +#include "mbedtls/sha512.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#if defined(MBEDTLS_MD2_C) + +static int md2_starts_wrap( void *ctx ) +{ + return( mbedtls_md2_starts_ret( (mbedtls_md2_context *) ctx ) ); +} + +static int md2_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + return( mbedtls_md2_update_ret( (mbedtls_md2_context *) ctx, input, ilen ) ); +} + +static int md2_finish_wrap( void *ctx, unsigned char *output ) +{ + return( mbedtls_md2_finish_ret( (mbedtls_md2_context *) ctx, output ) ); +} + +static void *md2_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_md2_context ) ); + + if( ctx != NULL ) + mbedtls_md2_init( (mbedtls_md2_context *) ctx ); + + return( ctx ); +} + +static void md2_ctx_free( void *ctx ) +{ + mbedtls_md2_free( (mbedtls_md2_context *) ctx ); + mbedtls_free( ctx ); +} + +static void md2_clone_wrap( void *dst, const void *src ) +{ + mbedtls_md2_clone( (mbedtls_md2_context *) dst, + (const mbedtls_md2_context *) src ); +} + +static int md2_process_wrap( void *ctx, const unsigned char *data ) +{ + ((void) data); + + return( mbedtls_internal_md2_process( (mbedtls_md2_context *) ctx ) ); +} + +const mbedtls_md_info_t mbedtls_md2_info = { + MBEDTLS_MD_MD2, + "MD2", + 16, + 16, + md2_starts_wrap, + md2_update_wrap, + md2_finish_wrap, + mbedtls_md2_ret, + md2_ctx_alloc, + md2_ctx_free, + md2_clone_wrap, + md2_process_wrap, +}; + +#endif /* MBEDTLS_MD2_C */ + +#if defined(MBEDTLS_MD4_C) + +static int md4_starts_wrap( void *ctx ) +{ + return( mbedtls_md4_starts_ret( (mbedtls_md4_context *) ctx ) ); +} + +static int md4_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + return( mbedtls_md4_update_ret( (mbedtls_md4_context *) ctx, input, ilen ) ); +} + +static int md4_finish_wrap( void *ctx, unsigned char *output ) +{ + return( mbedtls_md4_finish_ret( (mbedtls_md4_context *) ctx, output ) ); +} + +static void *md4_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_md4_context ) ); + + if( ctx != NULL ) + mbedtls_md4_init( (mbedtls_md4_context *) ctx ); + + return( ctx ); +} + +static void md4_ctx_free( void *ctx ) +{ + mbedtls_md4_free( (mbedtls_md4_context *) ctx ); + mbedtls_free( ctx ); +} + +static void md4_clone_wrap( void *dst, const void *src ) +{ + mbedtls_md4_clone( (mbedtls_md4_context *) dst, + (const mbedtls_md4_context *) src ); +} + +static int md4_process_wrap( void *ctx, const unsigned char *data ) +{ + return( mbedtls_internal_md4_process( (mbedtls_md4_context *) ctx, data ) ); +} + +const mbedtls_md_info_t mbedtls_md4_info = { + MBEDTLS_MD_MD4, + "MD4", + 16, + 64, + md4_starts_wrap, + md4_update_wrap, + md4_finish_wrap, + mbedtls_md4_ret, + md4_ctx_alloc, + md4_ctx_free, + md4_clone_wrap, + md4_process_wrap, +}; + +#endif /* MBEDTLS_MD4_C */ + +#if defined(MBEDTLS_MD5_C) + +static int md5_starts_wrap( void *ctx ) +{ + return( mbedtls_md5_starts_ret( (mbedtls_md5_context *) ctx ) ); +} + +static int md5_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + return( mbedtls_md5_update_ret( (mbedtls_md5_context *) ctx, input, ilen ) ); +} + +static int md5_finish_wrap( void *ctx, unsigned char *output ) +{ + return( mbedtls_md5_finish_ret( (mbedtls_md5_context *) ctx, output ) ); +} + +static void *md5_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_md5_context ) ); + + if( ctx != NULL ) + mbedtls_md5_init( (mbedtls_md5_context *) ctx ); + + return( ctx ); +} + +static void md5_ctx_free( void *ctx ) +{ + mbedtls_md5_free( (mbedtls_md5_context *) ctx ); + mbedtls_free( ctx ); +} + +static void md5_clone_wrap( void *dst, const void *src ) +{ + mbedtls_md5_clone( (mbedtls_md5_context *) dst, + (const mbedtls_md5_context *) src ); +} + +static int md5_process_wrap( void *ctx, const unsigned char *data ) +{ + return( mbedtls_internal_md5_process( (mbedtls_md5_context *) ctx, data ) ); +} + +const mbedtls_md_info_t mbedtls_md5_info = { + MBEDTLS_MD_MD5, + "MD5", + 16, + 64, + md5_starts_wrap, + md5_update_wrap, + md5_finish_wrap, + mbedtls_md5_ret, + md5_ctx_alloc, + md5_ctx_free, + md5_clone_wrap, + md5_process_wrap, +}; + +#endif /* MBEDTLS_MD5_C */ + +#if defined(MBEDTLS_RIPEMD160_C) + +static int ripemd160_starts_wrap( void *ctx ) +{ + return( mbedtls_ripemd160_starts_ret( (mbedtls_ripemd160_context *) ctx ) ); +} + +static int ripemd160_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + return( mbedtls_ripemd160_update_ret( (mbedtls_ripemd160_context *) ctx, + input, ilen ) ); +} + +static int ripemd160_finish_wrap( void *ctx, unsigned char *output ) +{ + return( mbedtls_ripemd160_finish_ret( (mbedtls_ripemd160_context *) ctx, + output ) ); +} + +static void *ripemd160_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_ripemd160_context ) ); + + if( ctx != NULL ) + mbedtls_ripemd160_init( (mbedtls_ripemd160_context *) ctx ); + + return( ctx ); +} + +static void ripemd160_ctx_free( void *ctx ) +{ + mbedtls_ripemd160_free( (mbedtls_ripemd160_context *) ctx ); + mbedtls_free( ctx ); +} + +static void ripemd160_clone_wrap( void *dst, const void *src ) +{ + mbedtls_ripemd160_clone( (mbedtls_ripemd160_context *) dst, + (const mbedtls_ripemd160_context *) src ); +} + +static int ripemd160_process_wrap( void *ctx, const unsigned char *data ) +{ + return( mbedtls_internal_ripemd160_process( + (mbedtls_ripemd160_context *) ctx, data ) ); +} + +const mbedtls_md_info_t mbedtls_ripemd160_info = { + MBEDTLS_MD_RIPEMD160, + "RIPEMD160", + 20, + 64, + ripemd160_starts_wrap, + ripemd160_update_wrap, + ripemd160_finish_wrap, + mbedtls_ripemd160_ret, + ripemd160_ctx_alloc, + ripemd160_ctx_free, + ripemd160_clone_wrap, + ripemd160_process_wrap, +}; + +#endif /* MBEDTLS_RIPEMD160_C */ + +#if defined(MBEDTLS_SHA1_C) + +static int sha1_starts_wrap( void *ctx ) +{ + return( mbedtls_sha1_starts_ret( (mbedtls_sha1_context *) ctx ) ); +} + +static int sha1_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + return( mbedtls_sha1_update_ret( (mbedtls_sha1_context *) ctx, + input, ilen ) ); +} + +static int sha1_finish_wrap( void *ctx, unsigned char *output ) +{ + return( mbedtls_sha1_finish_ret( (mbedtls_sha1_context *) ctx, output ) ); +} + +static void *sha1_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_sha1_context ) ); + + if( ctx != NULL ) + mbedtls_sha1_init( (mbedtls_sha1_context *) ctx ); + + return( ctx ); +} + +static void sha1_clone_wrap( void *dst, const void *src ) +{ + mbedtls_sha1_clone( (mbedtls_sha1_context *) dst, + (const mbedtls_sha1_context *) src ); +} + +static void sha1_ctx_free( void *ctx ) +{ + mbedtls_sha1_free( (mbedtls_sha1_context *) ctx ); + mbedtls_free( ctx ); +} + +static int sha1_process_wrap( void *ctx, const unsigned char *data ) +{ + return( mbedtls_internal_sha1_process( (mbedtls_sha1_context *) ctx, + data ) ); +} + +const mbedtls_md_info_t mbedtls_sha1_info = { + MBEDTLS_MD_SHA1, + "SHA1", + 20, + 64, + sha1_starts_wrap, + sha1_update_wrap, + sha1_finish_wrap, + mbedtls_sha1_ret, + sha1_ctx_alloc, + sha1_ctx_free, + sha1_clone_wrap, + sha1_process_wrap, +}; + +#endif /* MBEDTLS_SHA1_C */ + +/* + * Wrappers for generic message digests + */ +#if defined(MBEDTLS_SHA256_C) + +static int sha224_starts_wrap( void *ctx ) +{ + return( mbedtls_sha256_starts_ret( (mbedtls_sha256_context *) ctx, 1 ) ); +} + +static int sha224_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + return( mbedtls_sha256_update_ret( (mbedtls_sha256_context *) ctx, + input, ilen ) ); +} + +static int sha224_finish_wrap( void *ctx, unsigned char *output ) +{ + return( mbedtls_sha256_finish_ret( (mbedtls_sha256_context *) ctx, + output ) ); +} + +static int sha224_wrap( const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + return( mbedtls_sha256_ret( input, ilen, output, 1 ) ); +} + +static void *sha224_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_sha256_context ) ); + + if( ctx != NULL ) + mbedtls_sha256_init( (mbedtls_sha256_context *) ctx ); + + return( ctx ); +} + +static void sha224_ctx_free( void *ctx ) +{ + mbedtls_sha256_free( (mbedtls_sha256_context *) ctx ); + mbedtls_free( ctx ); +} + +static void sha224_clone_wrap( void *dst, const void *src ) +{ + mbedtls_sha256_clone( (mbedtls_sha256_context *) dst, + (const mbedtls_sha256_context *) src ); +} + +static int sha224_process_wrap( void *ctx, const unsigned char *data ) +{ + return( mbedtls_internal_sha256_process( (mbedtls_sha256_context *) ctx, + data ) ); +} + +const mbedtls_md_info_t mbedtls_sha224_info = { + MBEDTLS_MD_SHA224, + "SHA224", + 28, + 64, + sha224_starts_wrap, + sha224_update_wrap, + sha224_finish_wrap, + sha224_wrap, + sha224_ctx_alloc, + sha224_ctx_free, + sha224_clone_wrap, + sha224_process_wrap, +}; + +static int sha256_starts_wrap( void *ctx ) +{ + return( mbedtls_sha256_starts_ret( (mbedtls_sha256_context *) ctx, 0 ) ); +} + +static int sha256_wrap( const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + return( mbedtls_sha256_ret( input, ilen, output, 0 ) ); +} + +const mbedtls_md_info_t mbedtls_sha256_info = { + MBEDTLS_MD_SHA256, + "SHA256", + 32, + 64, + sha256_starts_wrap, + sha224_update_wrap, + sha224_finish_wrap, + sha256_wrap, + sha224_ctx_alloc, + sha224_ctx_free, + sha224_clone_wrap, + sha224_process_wrap, +}; + +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + +static int sha384_starts_wrap( void *ctx ) +{ + return( mbedtls_sha512_starts_ret( (mbedtls_sha512_context *) ctx, 1 ) ); +} + +static int sha384_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + return( mbedtls_sha512_update_ret( (mbedtls_sha512_context *) ctx, + input, ilen ) ); +} + +static int sha384_finish_wrap( void *ctx, unsigned char *output ) +{ + return( mbedtls_sha512_finish_ret( (mbedtls_sha512_context *) ctx, + output ) ); +} + +static int sha384_wrap( const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + return( mbedtls_sha512_ret( input, ilen, output, 1 ) ); +} + +static void *sha384_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_sha512_context ) ); + + if( ctx != NULL ) + mbedtls_sha512_init( (mbedtls_sha512_context *) ctx ); + + return( ctx ); +} + +static void sha384_ctx_free( void *ctx ) +{ + mbedtls_sha512_free( (mbedtls_sha512_context *) ctx ); + mbedtls_free( ctx ); +} + +static void sha384_clone_wrap( void *dst, const void *src ) +{ + mbedtls_sha512_clone( (mbedtls_sha512_context *) dst, + (const mbedtls_sha512_context *) src ); +} + +static int sha384_process_wrap( void *ctx, const unsigned char *data ) +{ + return( mbedtls_internal_sha512_process( (mbedtls_sha512_context *) ctx, + data ) ); +} + +const mbedtls_md_info_t mbedtls_sha384_info = { + MBEDTLS_MD_SHA384, + "SHA384", + 48, + 128, + sha384_starts_wrap, + sha384_update_wrap, + sha384_finish_wrap, + sha384_wrap, + sha384_ctx_alloc, + sha384_ctx_free, + sha384_clone_wrap, + sha384_process_wrap, +}; + +static int sha512_starts_wrap( void *ctx ) +{ + return( mbedtls_sha512_starts_ret( (mbedtls_sha512_context *) ctx, 0 ) ); +} + +static int sha512_wrap( const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + return( mbedtls_sha512_ret( input, ilen, output, 0 ) ); +} + +const mbedtls_md_info_t mbedtls_sha512_info = { + MBEDTLS_MD_SHA512, + "SHA512", + 64, + 128, + sha512_starts_wrap, + sha384_update_wrap, + sha384_finish_wrap, + sha512_wrap, + sha384_ctx_alloc, + sha384_ctx_free, + sha384_clone_wrap, + sha384_process_wrap, +}; + +#endif /* MBEDTLS_SHA512_C */ + +#endif /* MBEDTLS_MD_C */ diff --git a/common/mbedtls/oid.c b/common/mbedtls/oid.c new file mode 100644 index 00000000..962bd189 --- /dev/null +++ b/common/mbedtls/oid.c @@ -0,0 +1,757 @@ +/** + * \file oid.c + * + * \brief Object Identifier (OID) database + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_OID_C) + +#include "mbedtls/oid.h" +#include "mbedtls/rsa.h" + +#include +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#define mbedtls_snprintf snprintf +#endif + +#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C) +#include "mbedtls/x509.h" +#endif + +/* + * Macro to automatically add the size of #define'd OIDs + */ +#define ADD_LEN(s) s, MBEDTLS_OID_SIZE(s) + +/* + * Macro to generate an internal function for oid_XXX_from_asn1() (used by + * the other functions) + */ +#define FN_OID_TYPED_FROM_ASN1( TYPE_T, NAME, LIST ) \ +static const TYPE_T * oid_ ## NAME ## _from_asn1( const mbedtls_asn1_buf *oid ) \ +{ \ + const TYPE_T *p = LIST; \ + const mbedtls_oid_descriptor_t *cur = (const mbedtls_oid_descriptor_t *) p; \ + if( p == NULL || oid == NULL ) return( NULL ); \ + while( cur->asn1 != NULL ) { \ + if( cur->asn1_len == oid->len && \ + memcmp( cur->asn1, oid->p, oid->len ) == 0 ) { \ + return( p ); \ + } \ + p++; \ + cur = (const mbedtls_oid_descriptor_t *) p; \ + } \ + return( NULL ); \ +} + +/* + * Macro to generate a function for retrieving a single attribute from the + * descriptor of an mbedtls_oid_descriptor_t wrapper. + */ +#define FN_OID_GET_DESCRIPTOR_ATTR1(FN_NAME, TYPE_T, TYPE_NAME, ATTR1_TYPE, ATTR1) \ +int FN_NAME( const mbedtls_asn1_buf *oid, ATTR1_TYPE * ATTR1 ) \ +{ \ + const TYPE_T *data = oid_ ## TYPE_NAME ## _from_asn1( oid ); \ + if( data == NULL ) return( MBEDTLS_ERR_OID_NOT_FOUND ); \ + *ATTR1 = data->descriptor.ATTR1; \ + return( 0 ); \ +} + +/* + * Macro to generate a function for retrieving a single attribute from an + * mbedtls_oid_descriptor_t wrapper. + */ +#define FN_OID_GET_ATTR1(FN_NAME, TYPE_T, TYPE_NAME, ATTR1_TYPE, ATTR1) \ +int FN_NAME( const mbedtls_asn1_buf *oid, ATTR1_TYPE * ATTR1 ) \ +{ \ + const TYPE_T *data = oid_ ## TYPE_NAME ## _from_asn1( oid ); \ + if( data == NULL ) return( MBEDTLS_ERR_OID_NOT_FOUND ); \ + *ATTR1 = data->ATTR1; \ + return( 0 ); \ +} + +/* + * Macro to generate a function for retrieving two attributes from an + * mbedtls_oid_descriptor_t wrapper. + */ +#define FN_OID_GET_ATTR2(FN_NAME, TYPE_T, TYPE_NAME, ATTR1_TYPE, ATTR1, \ + ATTR2_TYPE, ATTR2) \ +int FN_NAME( const mbedtls_asn1_buf *oid, ATTR1_TYPE * ATTR1, ATTR2_TYPE * ATTR2 ) \ +{ \ + const TYPE_T *data = oid_ ## TYPE_NAME ## _from_asn1( oid ); \ + if( data == NULL ) return( MBEDTLS_ERR_OID_NOT_FOUND ); \ + *ATTR1 = data->ATTR1; \ + *ATTR2 = data->ATTR2; \ + return( 0 ); \ +} + +/* + * Macro to generate a function for retrieving the OID based on a single + * attribute from a mbedtls_oid_descriptor_t wrapper. + */ +#define FN_OID_GET_OID_BY_ATTR1(FN_NAME, TYPE_T, LIST, ATTR1_TYPE, ATTR1) \ +int FN_NAME( ATTR1_TYPE ATTR1, const char **oid, size_t *olen ) \ +{ \ + const TYPE_T *cur = LIST; \ + while( cur->descriptor.asn1 != NULL ) { \ + if( cur->ATTR1 == ATTR1 ) { \ + *oid = cur->descriptor.asn1; \ + *olen = cur->descriptor.asn1_len; \ + return( 0 ); \ + } \ + cur++; \ + } \ + return( MBEDTLS_ERR_OID_NOT_FOUND ); \ +} + +/* + * Macro to generate a function for retrieving the OID based on two + * attributes from a mbedtls_oid_descriptor_t wrapper. + */ +#define FN_OID_GET_OID_BY_ATTR2(FN_NAME, TYPE_T, LIST, ATTR1_TYPE, ATTR1, \ + ATTR2_TYPE, ATTR2) \ +int FN_NAME( ATTR1_TYPE ATTR1, ATTR2_TYPE ATTR2, const char **oid , \ + size_t *olen ) \ +{ \ + const TYPE_T *cur = LIST; \ + while( cur->descriptor.asn1 != NULL ) { \ + if( cur->ATTR1 == ATTR1 && cur->ATTR2 == ATTR2 ) { \ + *oid = cur->descriptor.asn1; \ + *olen = cur->descriptor.asn1_len; \ + return( 0 ); \ + } \ + cur++; \ + } \ + return( MBEDTLS_ERR_OID_NOT_FOUND ); \ +} + +#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C) +/* + * For X520 attribute types + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + const char *short_name; +} oid_x520_attr_t; + +static const oid_x520_attr_t oid_x520_attr_type[] = +{ + { + { ADD_LEN( MBEDTLS_OID_AT_CN ), "id-at-commonName", "Common Name" }, + "CN", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_COUNTRY ), "id-at-countryName", "Country" }, + "C", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_LOCALITY ), "id-at-locality", "Locality" }, + "L", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_STATE ), "id-at-state", "State" }, + "ST", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_ORGANIZATION ),"id-at-organizationName", "Organization" }, + "O", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_ORG_UNIT ), "id-at-organizationalUnitName", "Org Unit" }, + "OU", + }, + { + { ADD_LEN( MBEDTLS_OID_PKCS9_EMAIL ), "emailAddress", "E-mail address" }, + "emailAddress", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_SERIAL_NUMBER ),"id-at-serialNumber", "Serial number" }, + "serialNumber", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_POSTAL_ADDRESS ),"id-at-postalAddress", "Postal address" }, + "postalAddress", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_POSTAL_CODE ), "id-at-postalCode", "Postal code" }, + "postalCode", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_SUR_NAME ), "id-at-surName", "Surname" }, + "SN", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_GIVEN_NAME ), "id-at-givenName", "Given name" }, + "GN", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_INITIALS ), "id-at-initials", "Initials" }, + "initials", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_GENERATION_QUALIFIER ), "id-at-generationQualifier", "Generation qualifier" }, + "generationQualifier", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_TITLE ), "id-at-title", "Title" }, + "title", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_DN_QUALIFIER ),"id-at-dnQualifier", "Distinguished Name qualifier" }, + "dnQualifier", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_PSEUDONYM ), "id-at-pseudonym", "Pseudonym" }, + "pseudonym", + }, + { + { ADD_LEN( MBEDTLS_OID_DOMAIN_COMPONENT ), "id-domainComponent", "Domain component" }, + "DC", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_UNIQUE_IDENTIFIER ), "id-at-uniqueIdentifier", "Unique Identifier" }, + "uniqueIdentifier", + }, + { + { NULL, 0, NULL, NULL }, + NULL, + } +}; + +FN_OID_TYPED_FROM_ASN1(oid_x520_attr_t, x520_attr, oid_x520_attr_type) +FN_OID_GET_ATTR1(mbedtls_oid_get_attr_short_name, oid_x520_attr_t, x520_attr, const char *, short_name) + +/* + * For X509 extensions + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + int ext_type; +} oid_x509_ext_t; + +static const oid_x509_ext_t oid_x509_ext[] = +{ + { + { ADD_LEN( MBEDTLS_OID_BASIC_CONSTRAINTS ), "id-ce-basicConstraints", "Basic Constraints" }, + MBEDTLS_X509_EXT_BASIC_CONSTRAINTS, + }, + { + { ADD_LEN( MBEDTLS_OID_KEY_USAGE ), "id-ce-keyUsage", "Key Usage" }, + MBEDTLS_X509_EXT_KEY_USAGE, + }, + { + { ADD_LEN( MBEDTLS_OID_EXTENDED_KEY_USAGE ), "id-ce-extKeyUsage", "Extended Key Usage" }, + MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE, + }, + { + { ADD_LEN( MBEDTLS_OID_SUBJECT_ALT_NAME ), "id-ce-subjectAltName", "Subject Alt Name" }, + MBEDTLS_X509_EXT_SUBJECT_ALT_NAME, + }, + { + { ADD_LEN( MBEDTLS_OID_NS_CERT_TYPE ), "id-netscape-certtype", "Netscape Certificate Type" }, + MBEDTLS_X509_EXT_NS_CERT_TYPE, + }, + { + { NULL, 0, NULL, NULL }, + 0, + }, +}; + +FN_OID_TYPED_FROM_ASN1(oid_x509_ext_t, x509_ext, oid_x509_ext) +FN_OID_GET_ATTR1(mbedtls_oid_get_x509_ext_type, oid_x509_ext_t, x509_ext, int, ext_type) + +static const mbedtls_oid_descriptor_t oid_ext_key_usage[] = +{ + { ADD_LEN( MBEDTLS_OID_SERVER_AUTH ), "id-kp-serverAuth", "TLS Web Server Authentication" }, + { ADD_LEN( MBEDTLS_OID_CLIENT_AUTH ), "id-kp-clientAuth", "TLS Web Client Authentication" }, + { ADD_LEN( MBEDTLS_OID_CODE_SIGNING ), "id-kp-codeSigning", "Code Signing" }, + { ADD_LEN( MBEDTLS_OID_EMAIL_PROTECTION ), "id-kp-emailProtection", "E-mail Protection" }, + { ADD_LEN( MBEDTLS_OID_TIME_STAMPING ), "id-kp-timeStamping", "Time Stamping" }, + { ADD_LEN( MBEDTLS_OID_OCSP_SIGNING ), "id-kp-OCSPSigning", "OCSP Signing" }, + { NULL, 0, NULL, NULL }, +}; + +FN_OID_TYPED_FROM_ASN1(mbedtls_oid_descriptor_t, ext_key_usage, oid_ext_key_usage) +FN_OID_GET_ATTR1(mbedtls_oid_get_extended_key_usage, mbedtls_oid_descriptor_t, ext_key_usage, const char *, description) +#endif /* MBEDTLS_X509_USE_C || MBEDTLS_X509_CREATE_C */ + +#if defined(MBEDTLS_MD_C) +/* + * For SignatureAlgorithmIdentifier + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + mbedtls_md_type_t md_alg; + mbedtls_pk_type_t pk_alg; +} oid_sig_alg_t; + +static const oid_sig_alg_t oid_sig_alg[] = +{ +#if defined(MBEDTLS_RSA_C) +#if defined(MBEDTLS_MD2_C) + { + { ADD_LEN( MBEDTLS_OID_PKCS1_MD2 ), "md2WithRSAEncryption", "RSA with MD2" }, + MBEDTLS_MD_MD2, MBEDTLS_PK_RSA, + }, +#endif /* MBEDTLS_MD2_C */ +#if defined(MBEDTLS_MD4_C) + { + { ADD_LEN( MBEDTLS_OID_PKCS1_MD4 ), "md4WithRSAEncryption", "RSA with MD4" }, + MBEDTLS_MD_MD4, MBEDTLS_PK_RSA, + }, +#endif /* MBEDTLS_MD4_C */ +#if defined(MBEDTLS_MD5_C) + { + { ADD_LEN( MBEDTLS_OID_PKCS1_MD5 ), "md5WithRSAEncryption", "RSA with MD5" }, + MBEDTLS_MD_MD5, MBEDTLS_PK_RSA, + }, +#endif /* MBEDTLS_MD5_C */ +#if defined(MBEDTLS_SHA1_C) + { + { ADD_LEN( MBEDTLS_OID_PKCS1_SHA1 ), "sha-1WithRSAEncryption", "RSA with SHA1" }, + MBEDTLS_MD_SHA1, MBEDTLS_PK_RSA, + }, +#endif /* MBEDTLS_SHA1_C */ +#if defined(MBEDTLS_SHA256_C) + { + { ADD_LEN( MBEDTLS_OID_PKCS1_SHA224 ), "sha224WithRSAEncryption", "RSA with SHA-224" }, + MBEDTLS_MD_SHA224, MBEDTLS_PK_RSA, + }, + { + { ADD_LEN( MBEDTLS_OID_PKCS1_SHA256 ), "sha256WithRSAEncryption", "RSA with SHA-256" }, + MBEDTLS_MD_SHA256, MBEDTLS_PK_RSA, + }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { + { ADD_LEN( MBEDTLS_OID_PKCS1_SHA384 ), "sha384WithRSAEncryption", "RSA with SHA-384" }, + MBEDTLS_MD_SHA384, MBEDTLS_PK_RSA, + }, + { + { ADD_LEN( MBEDTLS_OID_PKCS1_SHA512 ), "sha512WithRSAEncryption", "RSA with SHA-512" }, + MBEDTLS_MD_SHA512, MBEDTLS_PK_RSA, + }, +#endif /* MBEDTLS_SHA512_C */ +#if defined(MBEDTLS_SHA1_C) + { + { ADD_LEN( MBEDTLS_OID_RSA_SHA_OBS ), "sha-1WithRSAEncryption", "RSA with SHA1" }, + MBEDTLS_MD_SHA1, MBEDTLS_PK_RSA, + }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_RSA_C */ +#if defined(MBEDTLS_ECDSA_C) +#if defined(MBEDTLS_SHA1_C) + { + { ADD_LEN( MBEDTLS_OID_ECDSA_SHA1 ), "ecdsa-with-SHA1", "ECDSA with SHA1" }, + MBEDTLS_MD_SHA1, MBEDTLS_PK_ECDSA, + }, +#endif /* MBEDTLS_SHA1_C */ +#if defined(MBEDTLS_SHA256_C) + { + { ADD_LEN( MBEDTLS_OID_ECDSA_SHA224 ), "ecdsa-with-SHA224", "ECDSA with SHA224" }, + MBEDTLS_MD_SHA224, MBEDTLS_PK_ECDSA, + }, + { + { ADD_LEN( MBEDTLS_OID_ECDSA_SHA256 ), "ecdsa-with-SHA256", "ECDSA with SHA256" }, + MBEDTLS_MD_SHA256, MBEDTLS_PK_ECDSA, + }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { + { ADD_LEN( MBEDTLS_OID_ECDSA_SHA384 ), "ecdsa-with-SHA384", "ECDSA with SHA384" }, + MBEDTLS_MD_SHA384, MBEDTLS_PK_ECDSA, + }, + { + { ADD_LEN( MBEDTLS_OID_ECDSA_SHA512 ), "ecdsa-with-SHA512", "ECDSA with SHA512" }, + MBEDTLS_MD_SHA512, MBEDTLS_PK_ECDSA, + }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_ECDSA_C */ +#if defined(MBEDTLS_RSA_C) + { + { ADD_LEN( MBEDTLS_OID_RSASSA_PSS ), "RSASSA-PSS", "RSASSA-PSS" }, + MBEDTLS_MD_NONE, MBEDTLS_PK_RSASSA_PSS, + }, +#endif /* MBEDTLS_RSA_C */ + { + { NULL, 0, NULL, NULL }, + MBEDTLS_MD_NONE, MBEDTLS_PK_NONE, + }, +}; + +FN_OID_TYPED_FROM_ASN1(oid_sig_alg_t, sig_alg, oid_sig_alg) +FN_OID_GET_DESCRIPTOR_ATTR1(mbedtls_oid_get_sig_alg_desc, oid_sig_alg_t, sig_alg, const char *, description) +FN_OID_GET_ATTR2(mbedtls_oid_get_sig_alg, oid_sig_alg_t, sig_alg, mbedtls_md_type_t, md_alg, mbedtls_pk_type_t, pk_alg) +FN_OID_GET_OID_BY_ATTR2(mbedtls_oid_get_oid_by_sig_alg, oid_sig_alg_t, oid_sig_alg, mbedtls_pk_type_t, pk_alg, mbedtls_md_type_t, md_alg) +#endif /* MBEDTLS_MD_C */ + +/* + * For PublicKeyInfo (PKCS1, RFC 5480) + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + mbedtls_pk_type_t pk_alg; +} oid_pk_alg_t; + +static const oid_pk_alg_t oid_pk_alg[] = +{ + { + { ADD_LEN( MBEDTLS_OID_PKCS1_RSA ), "rsaEncryption", "RSA" }, + MBEDTLS_PK_RSA, + }, + { + { ADD_LEN( MBEDTLS_OID_EC_ALG_UNRESTRICTED ), "id-ecPublicKey", "Generic EC key" }, + MBEDTLS_PK_ECKEY, + }, + { + { ADD_LEN( MBEDTLS_OID_EC_ALG_ECDH ), "id-ecDH", "EC key for ECDH" }, + MBEDTLS_PK_ECKEY_DH, + }, + { + { NULL, 0, NULL, NULL }, + MBEDTLS_PK_NONE, + }, +}; + +FN_OID_TYPED_FROM_ASN1(oid_pk_alg_t, pk_alg, oid_pk_alg) +FN_OID_GET_ATTR1(mbedtls_oid_get_pk_alg, oid_pk_alg_t, pk_alg, mbedtls_pk_type_t, pk_alg) +FN_OID_GET_OID_BY_ATTR1(mbedtls_oid_get_oid_by_pk_alg, oid_pk_alg_t, oid_pk_alg, mbedtls_pk_type_t, pk_alg) + +#if defined(MBEDTLS_ECP_C) +/* + * For namedCurve (RFC 5480) + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + mbedtls_ecp_group_id grp_id; +} oid_ecp_grp_t; + +static const oid_ecp_grp_t oid_ecp_grp[] = +{ +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP192R1 ), "secp192r1", "secp192r1" }, + MBEDTLS_ECP_DP_SECP192R1, + }, +#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP224R1 ), "secp224r1", "secp224r1" }, + MBEDTLS_ECP_DP_SECP224R1, + }, +#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP256R1 ), "secp256r1", "secp256r1" }, + MBEDTLS_ECP_DP_SECP256R1, + }, +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP384R1 ), "secp384r1", "secp384r1" }, + MBEDTLS_ECP_DP_SECP384R1, + }, +#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP521R1 ), "secp521r1", "secp521r1" }, + MBEDTLS_ECP_DP_SECP521R1, + }, +#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP192K1 ), "secp192k1", "secp192k1" }, + MBEDTLS_ECP_DP_SECP192K1, + }, +#endif /* MBEDTLS_ECP_DP_SECP192K1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP224K1 ), "secp224k1", "secp224k1" }, + MBEDTLS_ECP_DP_SECP224K1, + }, +#endif /* MBEDTLS_ECP_DP_SECP224K1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP256K1 ), "secp256k1", "secp256k1" }, + MBEDTLS_ECP_DP_SECP256K1, + }, +#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_BP256R1 ), "brainpoolP256r1","brainpool256r1" }, + MBEDTLS_ECP_DP_BP256R1, + }, +#endif /* MBEDTLS_ECP_DP_BP256R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_BP384R1 ), "brainpoolP384r1","brainpool384r1" }, + MBEDTLS_ECP_DP_BP384R1, + }, +#endif /* MBEDTLS_ECP_DP_BP384R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_BP512R1 ), "brainpoolP512r1","brainpool512r1" }, + MBEDTLS_ECP_DP_BP512R1, + }, +#endif /* MBEDTLS_ECP_DP_BP512R1_ENABLED */ + { + { NULL, 0, NULL, NULL }, + MBEDTLS_ECP_DP_NONE, + }, +}; + +FN_OID_TYPED_FROM_ASN1(oid_ecp_grp_t, grp_id, oid_ecp_grp) +FN_OID_GET_ATTR1(mbedtls_oid_get_ec_grp, oid_ecp_grp_t, grp_id, mbedtls_ecp_group_id, grp_id) +FN_OID_GET_OID_BY_ATTR1(mbedtls_oid_get_oid_by_ec_grp, oid_ecp_grp_t, oid_ecp_grp, mbedtls_ecp_group_id, grp_id) +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_CIPHER_C) +/* + * For PKCS#5 PBES2 encryption algorithm + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + mbedtls_cipher_type_t cipher_alg; +} oid_cipher_alg_t; + +static const oid_cipher_alg_t oid_cipher_alg[] = +{ + { + { ADD_LEN( MBEDTLS_OID_DES_CBC ), "desCBC", "DES-CBC" }, + MBEDTLS_CIPHER_DES_CBC, + }, + { + { ADD_LEN( MBEDTLS_OID_DES_EDE3_CBC ), "des-ede3-cbc", "DES-EDE3-CBC" }, + MBEDTLS_CIPHER_DES_EDE3_CBC, + }, + { + { NULL, 0, NULL, NULL }, + MBEDTLS_CIPHER_NONE, + }, +}; + +FN_OID_TYPED_FROM_ASN1(oid_cipher_alg_t, cipher_alg, oid_cipher_alg) +FN_OID_GET_ATTR1(mbedtls_oid_get_cipher_alg, oid_cipher_alg_t, cipher_alg, mbedtls_cipher_type_t, cipher_alg) +#endif /* MBEDTLS_CIPHER_C */ + +#if defined(MBEDTLS_MD_C) +/* + * For digestAlgorithm + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + mbedtls_md_type_t md_alg; +} oid_md_alg_t; + +static const oid_md_alg_t oid_md_alg[] = +{ +#if defined(MBEDTLS_MD2_C) + { + { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_MD2 ), "id-md2", "MD2" }, + MBEDTLS_MD_MD2, + }, +#endif /* MBEDTLS_MD2_C */ +#if defined(MBEDTLS_MD4_C) + { + { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_MD4 ), "id-md4", "MD4" }, + MBEDTLS_MD_MD4, + }, +#endif /* MBEDTLS_MD4_C */ +#if defined(MBEDTLS_MD5_C) + { + { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_MD5 ), "id-md5", "MD5" }, + MBEDTLS_MD_MD5, + }, +#endif /* MBEDTLS_MD5_C */ +#if defined(MBEDTLS_SHA1_C) + { + { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_SHA1 ), "id-sha1", "SHA-1" }, + MBEDTLS_MD_SHA1, + }, +#endif /* MBEDTLS_SHA1_C */ +#if defined(MBEDTLS_SHA256_C) + { + { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_SHA224 ), "id-sha224", "SHA-224" }, + MBEDTLS_MD_SHA224, + }, + { + { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_SHA256 ), "id-sha256", "SHA-256" }, + MBEDTLS_MD_SHA256, + }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { + { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_SHA384 ), "id-sha384", "SHA-384" }, + MBEDTLS_MD_SHA384, + }, + { + { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_SHA512 ), "id-sha512", "SHA-512" }, + MBEDTLS_MD_SHA512, + }, +#endif /* MBEDTLS_SHA512_C */ + { + { NULL, 0, NULL, NULL }, + MBEDTLS_MD_NONE, + }, +}; + +FN_OID_TYPED_FROM_ASN1(oid_md_alg_t, md_alg, oid_md_alg) +FN_OID_GET_ATTR1(mbedtls_oid_get_md_alg, oid_md_alg_t, md_alg, mbedtls_md_type_t, md_alg) +FN_OID_GET_OID_BY_ATTR1(mbedtls_oid_get_oid_by_md, oid_md_alg_t, oid_md_alg, mbedtls_md_type_t, md_alg) + +/* + * For HMAC digestAlgorithm + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + mbedtls_md_type_t md_hmac; +} oid_md_hmac_t; + +static const oid_md_hmac_t oid_md_hmac[] = +{ +#if defined(MBEDTLS_SHA1_C) + { + { ADD_LEN( MBEDTLS_OID_HMAC_SHA1 ), "hmacSHA1", "HMAC-SHA-1" }, + MBEDTLS_MD_SHA1, + }, +#endif /* MBEDTLS_SHA1_C */ +#if defined(MBEDTLS_SHA256_C) + { + { ADD_LEN( MBEDTLS_OID_HMAC_SHA224 ), "hmacSHA224", "HMAC-SHA-224" }, + MBEDTLS_MD_SHA224, + }, + { + { ADD_LEN( MBEDTLS_OID_HMAC_SHA256 ), "hmacSHA256", "HMAC-SHA-256" }, + MBEDTLS_MD_SHA256, + }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { + { ADD_LEN( MBEDTLS_OID_HMAC_SHA384 ), "hmacSHA384", "HMAC-SHA-384" }, + MBEDTLS_MD_SHA384, + }, + { + { ADD_LEN( MBEDTLS_OID_HMAC_SHA512 ), "hmacSHA512", "HMAC-SHA-512" }, + MBEDTLS_MD_SHA512, + }, +#endif /* MBEDTLS_SHA512_C */ + { + { NULL, 0, NULL, NULL }, + MBEDTLS_MD_NONE, + }, +}; + +FN_OID_TYPED_FROM_ASN1(oid_md_hmac_t, md_hmac, oid_md_hmac) +FN_OID_GET_ATTR1(mbedtls_oid_get_md_hmac, oid_md_hmac_t, md_hmac, mbedtls_md_type_t, md_hmac) +#endif /* MBEDTLS_MD_C */ + +#if defined(MBEDTLS_PKCS12_C) +/* + * For PKCS#12 PBEs + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + mbedtls_md_type_t md_alg; + mbedtls_cipher_type_t cipher_alg; +} oid_pkcs12_pbe_alg_t; + +static const oid_pkcs12_pbe_alg_t oid_pkcs12_pbe_alg[] = +{ + { + { ADD_LEN( MBEDTLS_OID_PKCS12_PBE_SHA1_DES3_EDE_CBC ), "pbeWithSHAAnd3-KeyTripleDES-CBC", "PBE with SHA1 and 3-Key 3DES" }, + MBEDTLS_MD_SHA1, MBEDTLS_CIPHER_DES_EDE3_CBC, + }, + { + { ADD_LEN( MBEDTLS_OID_PKCS12_PBE_SHA1_DES2_EDE_CBC ), "pbeWithSHAAnd2-KeyTripleDES-CBC", "PBE with SHA1 and 2-Key 3DES" }, + MBEDTLS_MD_SHA1, MBEDTLS_CIPHER_DES_EDE_CBC, + }, + { + { NULL, 0, NULL, NULL }, + MBEDTLS_MD_NONE, MBEDTLS_CIPHER_NONE, + }, +}; + +FN_OID_TYPED_FROM_ASN1(oid_pkcs12_pbe_alg_t, pkcs12_pbe_alg, oid_pkcs12_pbe_alg) +FN_OID_GET_ATTR2(mbedtls_oid_get_pkcs12_pbe_alg, oid_pkcs12_pbe_alg_t, pkcs12_pbe_alg, mbedtls_md_type_t, md_alg, mbedtls_cipher_type_t, cipher_alg) +#endif /* MBEDTLS_PKCS12_C */ + +#define OID_SAFE_SNPRINTF \ + do { \ + if( ret < 0 || (size_t) ret >= n ) \ + return( MBEDTLS_ERR_OID_BUF_TOO_SMALL ); \ + \ + n -= (size_t) ret; \ + p += (size_t) ret; \ + } while( 0 ) + +/* Return the x.y.z.... style numeric string for the given OID */ +int mbedtls_oid_get_numeric_string( char *buf, size_t size, + const mbedtls_asn1_buf *oid ) +{ + int ret; + size_t i, n; + unsigned int value; + char *p; + + p = buf; + n = size; + + /* First byte contains first two dots */ + if( oid->len > 0 ) + { + ret = mbedtls_snprintf( p, n, "%d.%d", oid->p[0] / 40, oid->p[0] % 40 ); + OID_SAFE_SNPRINTF; + } + + value = 0; + for( i = 1; i < oid->len; i++ ) + { + /* Prevent overflow in value. */ + if( ( ( value << 7 ) >> 7 ) != value ) + return( MBEDTLS_ERR_OID_BUF_TOO_SMALL ); + + value <<= 7; + value += oid->p[i] & 0x7F; + + if( !( oid->p[i] & 0x80 ) ) + { + /* Last byte */ + ret = mbedtls_snprintf( p, n, ".%d", value ); + OID_SAFE_SNPRINTF; + value = 0; + } + } + + return( (int) ( size - n ) ); +} + +#endif /* MBEDTLS_OID_C */ diff --git a/common/mbedtls/oid.h b/common/mbedtls/oid.h new file mode 100644 index 00000000..1ea4a3f1 --- /dev/null +++ b/common/mbedtls/oid.h @@ -0,0 +1,607 @@ +/** + * \file oid.h + * + * \brief Object Identifier (OID) database + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_OID_H +#define MBEDTLS_OID_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "asn1.h" +#include "pk.h" + +#include + +#if defined(MBEDTLS_CIPHER_C) +#include "cipher.h" +#endif + +#if defined(MBEDTLS_MD_C) +#include "md.h" +#endif + +#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C) +#include "x509.h" +#endif + +#define MBEDTLS_ERR_OID_NOT_FOUND -0x002E /**< OID is not found. */ +#define MBEDTLS_ERR_OID_BUF_TOO_SMALL -0x000B /**< output buffer is too small */ + +/* + * Top level OID tuples + */ +#define MBEDTLS_OID_ISO_MEMBER_BODIES "\x2a" /* {iso(1) member-body(2)} */ +#define MBEDTLS_OID_ISO_IDENTIFIED_ORG "\x2b" /* {iso(1) identified-organization(3)} */ +#define MBEDTLS_OID_ISO_CCITT_DS "\x55" /* {joint-iso-ccitt(2) ds(5)} */ +#define MBEDTLS_OID_ISO_ITU_COUNTRY "\x60" /* {joint-iso-itu-t(2) country(16)} */ + +/* + * ISO Member bodies OID parts + */ +#define MBEDTLS_OID_COUNTRY_US "\x86\x48" /* {us(840)} */ +#define MBEDTLS_OID_ORG_RSA_DATA_SECURITY "\x86\xf7\x0d" /* {rsadsi(113549)} */ +#define MBEDTLS_OID_RSA_COMPANY MBEDTLS_OID_ISO_MEMBER_BODIES MBEDTLS_OID_COUNTRY_US \ + MBEDTLS_OID_ORG_RSA_DATA_SECURITY /* {iso(1) member-body(2) us(840) rsadsi(113549)} */ +#define MBEDTLS_OID_ORG_ANSI_X9_62 "\xce\x3d" /* ansi-X9-62(10045) */ +#define MBEDTLS_OID_ANSI_X9_62 MBEDTLS_OID_ISO_MEMBER_BODIES MBEDTLS_OID_COUNTRY_US \ + MBEDTLS_OID_ORG_ANSI_X9_62 + +/* + * ISO Identified organization OID parts + */ +#define MBEDTLS_OID_ORG_DOD "\x06" /* {dod(6)} */ +#define MBEDTLS_OID_ORG_OIW "\x0e" +#define MBEDTLS_OID_OIW_SECSIG MBEDTLS_OID_ORG_OIW "\x03" +#define MBEDTLS_OID_OIW_SECSIG_ALG MBEDTLS_OID_OIW_SECSIG "\x02" +#define MBEDTLS_OID_OIW_SECSIG_SHA1 MBEDTLS_OID_OIW_SECSIG_ALG "\x1a" +#define MBEDTLS_OID_ORG_CERTICOM "\x81\x04" /* certicom(132) */ +#define MBEDTLS_OID_CERTICOM MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_ORG_CERTICOM +#define MBEDTLS_OID_ORG_TELETRUST "\x24" /* teletrust(36) */ +#define MBEDTLS_OID_TELETRUST MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_ORG_TELETRUST + +/* + * ISO ITU OID parts + */ +#define MBEDTLS_OID_ORGANIZATION "\x01" /* {organization(1)} */ +#define MBEDTLS_OID_ISO_ITU_US_ORG MBEDTLS_OID_ISO_ITU_COUNTRY MBEDTLS_OID_COUNTRY_US MBEDTLS_OID_ORGANIZATION /* {joint-iso-itu-t(2) country(16) us(840) organization(1)} */ + +#define MBEDTLS_OID_ORG_GOV "\x65" /* {gov(101)} */ +#define MBEDTLS_OID_GOV MBEDTLS_OID_ISO_ITU_US_ORG MBEDTLS_OID_ORG_GOV /* {joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101)} */ + +#define MBEDTLS_OID_ORG_NETSCAPE "\x86\xF8\x42" /* {netscape(113730)} */ +#define MBEDTLS_OID_NETSCAPE MBEDTLS_OID_ISO_ITU_US_ORG MBEDTLS_OID_ORG_NETSCAPE /* Netscape OID {joint-iso-itu-t(2) country(16) us(840) organization(1) netscape(113730)} */ + +/* ISO arc for standard certificate and CRL extensions */ +#define MBEDTLS_OID_ID_CE MBEDTLS_OID_ISO_CCITT_DS "\x1D" /**< id-ce OBJECT IDENTIFIER ::= {joint-iso-ccitt(2) ds(5) 29} */ + +#define MBEDTLS_OID_NIST_ALG MBEDTLS_OID_GOV "\x03\x04" /** { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistAlgorithm(4) */ + +/** + * Private Internet Extensions + * { iso(1) identified-organization(3) dod(6) internet(1) + * security(5) mechanisms(5) pkix(7) } + */ +#define MBEDTLS_OID_PKIX MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_ORG_DOD "\x01\x05\x05\x07" + +/* + * Arc for standard naming attributes + */ +#define MBEDTLS_OID_AT MBEDTLS_OID_ISO_CCITT_DS "\x04" /**< id-at OBJECT IDENTIFIER ::= {joint-iso-ccitt(2) ds(5) 4} */ +#define MBEDTLS_OID_AT_CN MBEDTLS_OID_AT "\x03" /**< id-at-commonName AttributeType:= {id-at 3} */ +#define MBEDTLS_OID_AT_SUR_NAME MBEDTLS_OID_AT "\x04" /**< id-at-surName AttributeType:= {id-at 4} */ +#define MBEDTLS_OID_AT_SERIAL_NUMBER MBEDTLS_OID_AT "\x05" /**< id-at-serialNumber AttributeType:= {id-at 5} */ +#define MBEDTLS_OID_AT_COUNTRY MBEDTLS_OID_AT "\x06" /**< id-at-countryName AttributeType:= {id-at 6} */ +#define MBEDTLS_OID_AT_LOCALITY MBEDTLS_OID_AT "\x07" /**< id-at-locality AttributeType:= {id-at 7} */ +#define MBEDTLS_OID_AT_STATE MBEDTLS_OID_AT "\x08" /**< id-at-state AttributeType:= {id-at 8} */ +#define MBEDTLS_OID_AT_ORGANIZATION MBEDTLS_OID_AT "\x0A" /**< id-at-organizationName AttributeType:= {id-at 10} */ +#define MBEDTLS_OID_AT_ORG_UNIT MBEDTLS_OID_AT "\x0B" /**< id-at-organizationalUnitName AttributeType:= {id-at 11} */ +#define MBEDTLS_OID_AT_TITLE MBEDTLS_OID_AT "\x0C" /**< id-at-title AttributeType:= {id-at 12} */ +#define MBEDTLS_OID_AT_POSTAL_ADDRESS MBEDTLS_OID_AT "\x10" /**< id-at-postalAddress AttributeType:= {id-at 16} */ +#define MBEDTLS_OID_AT_POSTAL_CODE MBEDTLS_OID_AT "\x11" /**< id-at-postalCode AttributeType:= {id-at 17} */ +#define MBEDTLS_OID_AT_GIVEN_NAME MBEDTLS_OID_AT "\x2A" /**< id-at-givenName AttributeType:= {id-at 42} */ +#define MBEDTLS_OID_AT_INITIALS MBEDTLS_OID_AT "\x2B" /**< id-at-initials AttributeType:= {id-at 43} */ +#define MBEDTLS_OID_AT_GENERATION_QUALIFIER MBEDTLS_OID_AT "\x2C" /**< id-at-generationQualifier AttributeType:= {id-at 44} */ +#define MBEDTLS_OID_AT_UNIQUE_IDENTIFIER MBEDTLS_OID_AT "\x2D" /**< id-at-uniqueIdentifier AttributType:= {id-at 45} */ +#define MBEDTLS_OID_AT_DN_QUALIFIER MBEDTLS_OID_AT "\x2E" /**< id-at-dnQualifier AttributeType:= {id-at 46} */ +#define MBEDTLS_OID_AT_PSEUDONYM MBEDTLS_OID_AT "\x41" /**< id-at-pseudonym AttributeType:= {id-at 65} */ + +#define MBEDTLS_OID_DOMAIN_COMPONENT "\x09\x92\x26\x89\x93\xF2\x2C\x64\x01\x19" /** id-domainComponent AttributeType:= {itu-t(0) data(9) pss(2342) ucl(19200300) pilot(100) pilotAttributeType(1) domainComponent(25)} */ + +/* + * OIDs for standard certificate extensions + */ +#define MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER MBEDTLS_OID_ID_CE "\x23" /**< id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 35 } */ +#define MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER MBEDTLS_OID_ID_CE "\x0E" /**< id-ce-subjectKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 14 } */ +#define MBEDTLS_OID_KEY_USAGE MBEDTLS_OID_ID_CE "\x0F" /**< id-ce-keyUsage OBJECT IDENTIFIER ::= { id-ce 15 } */ +#define MBEDTLS_OID_CERTIFICATE_POLICIES MBEDTLS_OID_ID_CE "\x20" /**< id-ce-certificatePolicies OBJECT IDENTIFIER ::= { id-ce 32 } */ +#define MBEDTLS_OID_POLICY_MAPPINGS MBEDTLS_OID_ID_CE "\x21" /**< id-ce-policyMappings OBJECT IDENTIFIER ::= { id-ce 33 } */ +#define MBEDTLS_OID_SUBJECT_ALT_NAME MBEDTLS_OID_ID_CE "\x11" /**< id-ce-subjectAltName OBJECT IDENTIFIER ::= { id-ce 17 } */ +#define MBEDTLS_OID_ISSUER_ALT_NAME MBEDTLS_OID_ID_CE "\x12" /**< id-ce-issuerAltName OBJECT IDENTIFIER ::= { id-ce 18 } */ +#define MBEDTLS_OID_SUBJECT_DIRECTORY_ATTRS MBEDTLS_OID_ID_CE "\x09" /**< id-ce-subjectDirectoryAttributes OBJECT IDENTIFIER ::= { id-ce 9 } */ +#define MBEDTLS_OID_BASIC_CONSTRAINTS MBEDTLS_OID_ID_CE "\x13" /**< id-ce-basicConstraints OBJECT IDENTIFIER ::= { id-ce 19 } */ +#define MBEDTLS_OID_NAME_CONSTRAINTS MBEDTLS_OID_ID_CE "\x1E" /**< id-ce-nameConstraints OBJECT IDENTIFIER ::= { id-ce 30 } */ +#define MBEDTLS_OID_POLICY_CONSTRAINTS MBEDTLS_OID_ID_CE "\x24" /**< id-ce-policyConstraints OBJECT IDENTIFIER ::= { id-ce 36 } */ +#define MBEDTLS_OID_EXTENDED_KEY_USAGE MBEDTLS_OID_ID_CE "\x25" /**< id-ce-extKeyUsage OBJECT IDENTIFIER ::= { id-ce 37 } */ +#define MBEDTLS_OID_CRL_DISTRIBUTION_POINTS MBEDTLS_OID_ID_CE "\x1F" /**< id-ce-cRLDistributionPoints OBJECT IDENTIFIER ::= { id-ce 31 } */ +#define MBEDTLS_OID_INIHIBIT_ANYPOLICY MBEDTLS_OID_ID_CE "\x36" /**< id-ce-inhibitAnyPolicy OBJECT IDENTIFIER ::= { id-ce 54 } */ +#define MBEDTLS_OID_FRESHEST_CRL MBEDTLS_OID_ID_CE "\x2E" /**< id-ce-freshestCRL OBJECT IDENTIFIER ::= { id-ce 46 } */ + +/* + * Netscape certificate extensions + */ +#define MBEDTLS_OID_NS_CERT MBEDTLS_OID_NETSCAPE "\x01" +#define MBEDTLS_OID_NS_CERT_TYPE MBEDTLS_OID_NS_CERT "\x01" +#define MBEDTLS_OID_NS_BASE_URL MBEDTLS_OID_NS_CERT "\x02" +#define MBEDTLS_OID_NS_REVOCATION_URL MBEDTLS_OID_NS_CERT "\x03" +#define MBEDTLS_OID_NS_CA_REVOCATION_URL MBEDTLS_OID_NS_CERT "\x04" +#define MBEDTLS_OID_NS_RENEWAL_URL MBEDTLS_OID_NS_CERT "\x07" +#define MBEDTLS_OID_NS_CA_POLICY_URL MBEDTLS_OID_NS_CERT "\x08" +#define MBEDTLS_OID_NS_SSL_SERVER_NAME MBEDTLS_OID_NS_CERT "\x0C" +#define MBEDTLS_OID_NS_COMMENT MBEDTLS_OID_NS_CERT "\x0D" +#define MBEDTLS_OID_NS_DATA_TYPE MBEDTLS_OID_NETSCAPE "\x02" +#define MBEDTLS_OID_NS_CERT_SEQUENCE MBEDTLS_OID_NS_DATA_TYPE "\x05" + +/* + * OIDs for CRL extensions + */ +#define MBEDTLS_OID_PRIVATE_KEY_USAGE_PERIOD MBEDTLS_OID_ID_CE "\x10" +#define MBEDTLS_OID_CRL_NUMBER MBEDTLS_OID_ID_CE "\x14" /**< id-ce-cRLNumber OBJECT IDENTIFIER ::= { id-ce 20 } */ + +/* + * X.509 v3 Extended key usage OIDs + */ +#define MBEDTLS_OID_ANY_EXTENDED_KEY_USAGE MBEDTLS_OID_EXTENDED_KEY_USAGE "\x00" /**< anyExtendedKeyUsage OBJECT IDENTIFIER ::= { id-ce-extKeyUsage 0 } */ + +#define MBEDTLS_OID_KP MBEDTLS_OID_PKIX "\x03" /**< id-kp OBJECT IDENTIFIER ::= { id-pkix 3 } */ +#define MBEDTLS_OID_SERVER_AUTH MBEDTLS_OID_KP "\x01" /**< id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 } */ +#define MBEDTLS_OID_CLIENT_AUTH MBEDTLS_OID_KP "\x02" /**< id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 } */ +#define MBEDTLS_OID_CODE_SIGNING MBEDTLS_OID_KP "\x03" /**< id-kp-codeSigning OBJECT IDENTIFIER ::= { id-kp 3 } */ +#define MBEDTLS_OID_EMAIL_PROTECTION MBEDTLS_OID_KP "\x04" /**< id-kp-emailProtection OBJECT IDENTIFIER ::= { id-kp 4 } */ +#define MBEDTLS_OID_TIME_STAMPING MBEDTLS_OID_KP "\x08" /**< id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 } */ +#define MBEDTLS_OID_OCSP_SIGNING MBEDTLS_OID_KP "\x09" /**< id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 } */ + +/* + * PKCS definition OIDs + */ + +#define MBEDTLS_OID_PKCS MBEDTLS_OID_RSA_COMPANY "\x01" /**< pkcs OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) 1 } */ +#define MBEDTLS_OID_PKCS1 MBEDTLS_OID_PKCS "\x01" /**< pkcs-1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 } */ +#define MBEDTLS_OID_PKCS5 MBEDTLS_OID_PKCS "\x05" /**< pkcs-5 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 5 } */ +#define MBEDTLS_OID_PKCS9 MBEDTLS_OID_PKCS "\x09" /**< pkcs-9 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 } */ +#define MBEDTLS_OID_PKCS12 MBEDTLS_OID_PKCS "\x0c" /**< pkcs-12 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 12 } */ + +/* + * PKCS#1 OIDs + */ +#define MBEDTLS_OID_PKCS1_RSA MBEDTLS_OID_PKCS1 "\x01" /**< rsaEncryption OBJECT IDENTIFIER ::= { pkcs-1 1 } */ +#define MBEDTLS_OID_PKCS1_MD2 MBEDTLS_OID_PKCS1 "\x02" /**< md2WithRSAEncryption ::= { pkcs-1 2 } */ +#define MBEDTLS_OID_PKCS1_MD4 MBEDTLS_OID_PKCS1 "\x03" /**< md4WithRSAEncryption ::= { pkcs-1 3 } */ +#define MBEDTLS_OID_PKCS1_MD5 MBEDTLS_OID_PKCS1 "\x04" /**< md5WithRSAEncryption ::= { pkcs-1 4 } */ +#define MBEDTLS_OID_PKCS1_SHA1 MBEDTLS_OID_PKCS1 "\x05" /**< sha1WithRSAEncryption ::= { pkcs-1 5 } */ +#define MBEDTLS_OID_PKCS1_SHA224 MBEDTLS_OID_PKCS1 "\x0e" /**< sha224WithRSAEncryption ::= { pkcs-1 14 } */ +#define MBEDTLS_OID_PKCS1_SHA256 MBEDTLS_OID_PKCS1 "\x0b" /**< sha256WithRSAEncryption ::= { pkcs-1 11 } */ +#define MBEDTLS_OID_PKCS1_SHA384 MBEDTLS_OID_PKCS1 "\x0c" /**< sha384WithRSAEncryption ::= { pkcs-1 12 } */ +#define MBEDTLS_OID_PKCS1_SHA512 MBEDTLS_OID_PKCS1 "\x0d" /**< sha512WithRSAEncryption ::= { pkcs-1 13 } */ + +#define MBEDTLS_OID_RSA_SHA_OBS "\x2B\x0E\x03\x02\x1D" + +#define MBEDTLS_OID_PKCS9_EMAIL MBEDTLS_OID_PKCS9 "\x01" /**< emailAddress AttributeType ::= { pkcs-9 1 } */ + +/* RFC 4055 */ +#define MBEDTLS_OID_RSASSA_PSS MBEDTLS_OID_PKCS1 "\x0a" /**< id-RSASSA-PSS ::= { pkcs-1 10 } */ +#define MBEDTLS_OID_MGF1 MBEDTLS_OID_PKCS1 "\x08" /**< id-mgf1 ::= { pkcs-1 8 } */ + +/* + * Digest algorithms + */ +#define MBEDTLS_OID_DIGEST_ALG_MD2 MBEDTLS_OID_RSA_COMPANY "\x02\x02" /**< id-mbedtls_md2 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 2 } */ +#define MBEDTLS_OID_DIGEST_ALG_MD4 MBEDTLS_OID_RSA_COMPANY "\x02\x04" /**< id-mbedtls_md4 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 4 } */ +#define MBEDTLS_OID_DIGEST_ALG_MD5 MBEDTLS_OID_RSA_COMPANY "\x02\x05" /**< id-mbedtls_md5 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 5 } */ +#define MBEDTLS_OID_DIGEST_ALG_SHA1 MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_OIW_SECSIG_SHA1 /**< id-mbedtls_sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 } */ +#define MBEDTLS_OID_DIGEST_ALG_SHA224 MBEDTLS_OID_NIST_ALG "\x02\x04" /**< id-sha224 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 4 } */ +#define MBEDTLS_OID_DIGEST_ALG_SHA256 MBEDTLS_OID_NIST_ALG "\x02\x01" /**< id-mbedtls_sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 1 } */ + +#define MBEDTLS_OID_DIGEST_ALG_SHA384 MBEDTLS_OID_NIST_ALG "\x02\x02" /**< id-sha384 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 2 } */ + +#define MBEDTLS_OID_DIGEST_ALG_SHA512 MBEDTLS_OID_NIST_ALG "\x02\x03" /**< id-mbedtls_sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 3 } */ + +#define MBEDTLS_OID_HMAC_SHA1 MBEDTLS_OID_RSA_COMPANY "\x02\x07" /**< id-hmacWithSHA1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 7 } */ + +#define MBEDTLS_OID_HMAC_SHA224 MBEDTLS_OID_RSA_COMPANY "\x02\x08" /**< id-hmacWithSHA224 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 8 } */ + +#define MBEDTLS_OID_HMAC_SHA256 MBEDTLS_OID_RSA_COMPANY "\x02\x09" /**< id-hmacWithSHA256 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 9 } */ + +#define MBEDTLS_OID_HMAC_SHA384 MBEDTLS_OID_RSA_COMPANY "\x02\x0A" /**< id-hmacWithSHA384 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 10 } */ + +#define MBEDTLS_OID_HMAC_SHA512 MBEDTLS_OID_RSA_COMPANY "\x02\x0B" /**< id-hmacWithSHA512 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 11 } */ + +/* + * Encryption algorithms + */ +#define MBEDTLS_OID_DES_CBC MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_OIW_SECSIG_ALG "\x07" /**< desCBC OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 7 } */ +#define MBEDTLS_OID_DES_EDE3_CBC MBEDTLS_OID_RSA_COMPANY "\x03\x07" /**< des-ede3-cbc OBJECT IDENTIFIER ::= { iso(1) member-body(2) -- us(840) rsadsi(113549) encryptionAlgorithm(3) 7 } */ +#define MBEDTLS_OID_AES MBEDTLS_OID_NIST_ALG "\x01" /** aes OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistAlgorithm(4) 1 } */ + +/* + * Key Wrapping algorithms + */ +/* + * RFC 5649 + */ +#define MBEDTLS_OID_AES128_KW MBEDTLS_OID_AES "\x05" /** id-aes128-wrap OBJECT IDENTIFIER ::= { aes 5 } */ +#define MBEDTLS_OID_AES128_KWP MBEDTLS_OID_AES "\x08" /** id-aes128-wrap-pad OBJECT IDENTIFIER ::= { aes 8 } */ +#define MBEDTLS_OID_AES192_KW MBEDTLS_OID_AES "\x19" /** id-aes192-wrap OBJECT IDENTIFIER ::= { aes 25 } */ +#define MBEDTLS_OID_AES192_KWP MBEDTLS_OID_AES "\x1c" /** id-aes192-wrap-pad OBJECT IDENTIFIER ::= { aes 28 } */ +#define MBEDTLS_OID_AES256_KW MBEDTLS_OID_AES "\x2d" /** id-aes256-wrap OBJECT IDENTIFIER ::= { aes 45 } */ +#define MBEDTLS_OID_AES256_KWP MBEDTLS_OID_AES "\x30" /** id-aes256-wrap-pad OBJECT IDENTIFIER ::= { aes 48 } */ +/* + * PKCS#5 OIDs + */ +#define MBEDTLS_OID_PKCS5_PBKDF2 MBEDTLS_OID_PKCS5 "\x0c" /**< id-PBKDF2 OBJECT IDENTIFIER ::= {pkcs-5 12} */ +#define MBEDTLS_OID_PKCS5_PBES2 MBEDTLS_OID_PKCS5 "\x0d" /**< id-PBES2 OBJECT IDENTIFIER ::= {pkcs-5 13} */ +#define MBEDTLS_OID_PKCS5_PBMAC1 MBEDTLS_OID_PKCS5 "\x0e" /**< id-PBMAC1 OBJECT IDENTIFIER ::= {pkcs-5 14} */ + +/* + * PKCS#5 PBES1 algorithms + */ +#define MBEDTLS_OID_PKCS5_PBE_MD2_DES_CBC MBEDTLS_OID_PKCS5 "\x01" /**< pbeWithMD2AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 1} */ +#define MBEDTLS_OID_PKCS5_PBE_MD2_RC2_CBC MBEDTLS_OID_PKCS5 "\x04" /**< pbeWithMD2AndRC2-CBC OBJECT IDENTIFIER ::= {pkcs-5 4} */ +#define MBEDTLS_OID_PKCS5_PBE_MD5_DES_CBC MBEDTLS_OID_PKCS5 "\x03" /**< pbeWithMD5AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 3} */ +#define MBEDTLS_OID_PKCS5_PBE_MD5_RC2_CBC MBEDTLS_OID_PKCS5 "\x06" /**< pbeWithMD5AndRC2-CBC OBJECT IDENTIFIER ::= {pkcs-5 6} */ +#define MBEDTLS_OID_PKCS5_PBE_SHA1_DES_CBC MBEDTLS_OID_PKCS5 "\x0a" /**< pbeWithSHA1AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 10} */ +#define MBEDTLS_OID_PKCS5_PBE_SHA1_RC2_CBC MBEDTLS_OID_PKCS5 "\x0b" /**< pbeWithSHA1AndRC2-CBC OBJECT IDENTIFIER ::= {pkcs-5 11} */ + +/* + * PKCS#8 OIDs + */ +#define MBEDTLS_OID_PKCS9_CSR_EXT_REQ MBEDTLS_OID_PKCS9 "\x0e" /**< extensionRequest OBJECT IDENTIFIER ::= {pkcs-9 14} */ + +/* + * PKCS#12 PBE OIDs + */ +#define MBEDTLS_OID_PKCS12_PBE MBEDTLS_OID_PKCS12 "\x01" /**< pkcs-12PbeIds OBJECT IDENTIFIER ::= {pkcs-12 1} */ + +#define MBEDTLS_OID_PKCS12_PBE_SHA1_RC4_128 MBEDTLS_OID_PKCS12_PBE "\x01" /**< pbeWithSHAAnd128BitRC4 OBJECT IDENTIFIER ::= {pkcs-12PbeIds 1} */ +#define MBEDTLS_OID_PKCS12_PBE_SHA1_RC4_40 MBEDTLS_OID_PKCS12_PBE "\x02" /**< pbeWithSHAAnd40BitRC4 OBJECT IDENTIFIER ::= {pkcs-12PbeIds 2} */ +#define MBEDTLS_OID_PKCS12_PBE_SHA1_DES3_EDE_CBC MBEDTLS_OID_PKCS12_PBE "\x03" /**< pbeWithSHAAnd3-KeyTripleDES-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 3} */ +#define MBEDTLS_OID_PKCS12_PBE_SHA1_DES2_EDE_CBC MBEDTLS_OID_PKCS12_PBE "\x04" /**< pbeWithSHAAnd2-KeyTripleDES-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 4} */ +#define MBEDTLS_OID_PKCS12_PBE_SHA1_RC2_128_CBC MBEDTLS_OID_PKCS12_PBE "\x05" /**< pbeWithSHAAnd128BitRC2-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 5} */ +#define MBEDTLS_OID_PKCS12_PBE_SHA1_RC2_40_CBC MBEDTLS_OID_PKCS12_PBE "\x06" /**< pbeWithSHAAnd40BitRC2-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 6} */ + +/* + * EC key algorithms from RFC 5480 + */ + +/* id-ecPublicKey OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 } */ +#define MBEDTLS_OID_EC_ALG_UNRESTRICTED MBEDTLS_OID_ANSI_X9_62 "\x02\01" + +/* id-ecDH OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) + * schemes(1) ecdh(12) } */ +#define MBEDTLS_OID_EC_ALG_ECDH MBEDTLS_OID_CERTICOM "\x01\x0c" + +/* + * ECParameters namedCurve identifiers, from RFC 5480, RFC 5639, and SEC2 + */ + +/* secp192r1 OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3) prime(1) 1 } */ +#define MBEDTLS_OID_EC_GRP_SECP192R1 MBEDTLS_OID_ANSI_X9_62 "\x03\x01\x01" + +/* secp224r1 OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) curve(0) 33 } */ +#define MBEDTLS_OID_EC_GRP_SECP224R1 MBEDTLS_OID_CERTICOM "\x00\x21" + +/* secp256r1 OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3) prime(1) 7 } */ +#define MBEDTLS_OID_EC_GRP_SECP256R1 MBEDTLS_OID_ANSI_X9_62 "\x03\x01\x07" + +/* secp384r1 OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) curve(0) 34 } */ +#define MBEDTLS_OID_EC_GRP_SECP384R1 MBEDTLS_OID_CERTICOM "\x00\x22" + +/* secp521r1 OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) curve(0) 35 } */ +#define MBEDTLS_OID_EC_GRP_SECP521R1 MBEDTLS_OID_CERTICOM "\x00\x23" + +/* secp192k1 OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) curve(0) 31 } */ +#define MBEDTLS_OID_EC_GRP_SECP192K1 MBEDTLS_OID_CERTICOM "\x00\x1f" + +/* secp224k1 OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) curve(0) 32 } */ +#define MBEDTLS_OID_EC_GRP_SECP224K1 MBEDTLS_OID_CERTICOM "\x00\x20" + +/* secp256k1 OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) curve(0) 10 } */ +#define MBEDTLS_OID_EC_GRP_SECP256K1 MBEDTLS_OID_CERTICOM "\x00\x0a" + +/* RFC 5639 4.1 + * ecStdCurvesAndGeneration OBJECT IDENTIFIER::= {iso(1) + * identified-organization(3) teletrust(36) algorithm(3) signature- + * algorithm(3) ecSign(2) 8} + * ellipticCurve OBJECT IDENTIFIER ::= {ecStdCurvesAndGeneration 1} + * versionOne OBJECT IDENTIFIER ::= {ellipticCurve 1} */ +#define MBEDTLS_OID_EC_BRAINPOOL_V1 MBEDTLS_OID_TELETRUST "\x03\x03\x02\x08\x01\x01" + +/* brainpoolP256r1 OBJECT IDENTIFIER ::= {versionOne 7} */ +#define MBEDTLS_OID_EC_GRP_BP256R1 MBEDTLS_OID_EC_BRAINPOOL_V1 "\x07" + +/* brainpoolP384r1 OBJECT IDENTIFIER ::= {versionOne 11} */ +#define MBEDTLS_OID_EC_GRP_BP384R1 MBEDTLS_OID_EC_BRAINPOOL_V1 "\x0B" + +/* brainpoolP512r1 OBJECT IDENTIFIER ::= {versionOne 13} */ +#define MBEDTLS_OID_EC_GRP_BP512R1 MBEDTLS_OID_EC_BRAINPOOL_V1 "\x0D" + +/* + * SEC1 C.1 + * + * prime-field OBJECT IDENTIFIER ::= { id-fieldType 1 } + * id-fieldType OBJECT IDENTIFIER ::= { ansi-X9-62 fieldType(1)} + */ +#define MBEDTLS_OID_ANSI_X9_62_FIELD_TYPE MBEDTLS_OID_ANSI_X9_62 "\x01" +#define MBEDTLS_OID_ANSI_X9_62_PRIME_FIELD MBEDTLS_OID_ANSI_X9_62_FIELD_TYPE "\x01" + +/* + * ECDSA signature identifiers, from RFC 5480 + */ +#define MBEDTLS_OID_ANSI_X9_62_SIG MBEDTLS_OID_ANSI_X9_62 "\x04" /* signatures(4) */ +#define MBEDTLS_OID_ANSI_X9_62_SIG_SHA2 MBEDTLS_OID_ANSI_X9_62_SIG "\x03" /* ecdsa-with-SHA2(3) */ + +/* ecdsa-with-SHA1 OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) 1 } */ +#define MBEDTLS_OID_ECDSA_SHA1 MBEDTLS_OID_ANSI_X9_62_SIG "\x01" + +/* ecdsa-with-SHA224 OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) + * ecdsa-with-SHA2(3) 1 } */ +#define MBEDTLS_OID_ECDSA_SHA224 MBEDTLS_OID_ANSI_X9_62_SIG_SHA2 "\x01" + +/* ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) + * ecdsa-with-SHA2(3) 2 } */ +#define MBEDTLS_OID_ECDSA_SHA256 MBEDTLS_OID_ANSI_X9_62_SIG_SHA2 "\x02" + +/* ecdsa-with-SHA384 OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) + * ecdsa-with-SHA2(3) 3 } */ +#define MBEDTLS_OID_ECDSA_SHA384 MBEDTLS_OID_ANSI_X9_62_SIG_SHA2 "\x03" + +/* ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) + * ecdsa-with-SHA2(3) 4 } */ +#define MBEDTLS_OID_ECDSA_SHA512 MBEDTLS_OID_ANSI_X9_62_SIG_SHA2 "\x04" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Base OID descriptor structure + */ +typedef struct mbedtls_oid_descriptor_t +{ + const char *asn1; /*!< OID ASN.1 representation */ + size_t asn1_len; /*!< length of asn1 */ + const char *name; /*!< official name (e.g. from RFC) */ + const char *description; /*!< human friendly description */ +} mbedtls_oid_descriptor_t; + +/** + * \brief Translate an ASN.1 OID into its numeric representation + * (e.g. "\x2A\x86\x48\x86\xF7\x0D" into "1.2.840.113549") + * + * \param buf buffer to put representation in + * \param size size of the buffer + * \param oid OID to translate + * + * \return Length of the string written (excluding final NULL) or + * MBEDTLS_ERR_OID_BUF_TOO_SMALL in case of error + */ +int mbedtls_oid_get_numeric_string( char *buf, size_t size, const mbedtls_asn1_buf *oid ); + +#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C) +/** + * \brief Translate an X.509 extension OID into local values + * + * \param oid OID to use + * \param ext_type place to store the extension type + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_x509_ext_type( const mbedtls_asn1_buf *oid, int *ext_type ); +#endif + +/** + * \brief Translate an X.509 attribute type OID into the short name + * (e.g. the OID for an X520 Common Name into "CN") + * + * \param oid OID to use + * \param short_name place to store the string pointer + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_attr_short_name( const mbedtls_asn1_buf *oid, const char **short_name ); + +/** + * \brief Translate PublicKeyAlgorithm OID into pk_type + * + * \param oid OID to use + * \param pk_alg place to store public key algorithm + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_pk_alg( const mbedtls_asn1_buf *oid, mbedtls_pk_type_t *pk_alg ); + +/** + * \brief Translate pk_type into PublicKeyAlgorithm OID + * + * \param pk_alg Public key type to look for + * \param oid place to store ASN.1 OID string pointer + * \param olen length of the OID + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_oid_by_pk_alg( mbedtls_pk_type_t pk_alg, + const char **oid, size_t *olen ); + +#if defined(MBEDTLS_ECP_C) +/** + * \brief Translate NamedCurve OID into an EC group identifier + * + * \param oid OID to use + * \param grp_id place to store group id + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_ec_grp( const mbedtls_asn1_buf *oid, mbedtls_ecp_group_id *grp_id ); + +/** + * \brief Translate EC group identifier into NamedCurve OID + * + * \param grp_id EC group identifier + * \param oid place to store ASN.1 OID string pointer + * \param olen length of the OID + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_oid_by_ec_grp( mbedtls_ecp_group_id grp_id, + const char **oid, size_t *olen ); +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_MD_C) +/** + * \brief Translate SignatureAlgorithm OID into md_type and pk_type + * + * \param oid OID to use + * \param md_alg place to store message digest algorithm + * \param pk_alg place to store public key algorithm + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_sig_alg( const mbedtls_asn1_buf *oid, + mbedtls_md_type_t *md_alg, mbedtls_pk_type_t *pk_alg ); + +/** + * \brief Translate SignatureAlgorithm OID into description + * + * \param oid OID to use + * \param desc place to store string pointer + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_sig_alg_desc( const mbedtls_asn1_buf *oid, const char **desc ); + +/** + * \brief Translate md_type and pk_type into SignatureAlgorithm OID + * + * \param md_alg message digest algorithm + * \param pk_alg public key algorithm + * \param oid place to store ASN.1 OID string pointer + * \param olen length of the OID + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_oid_by_sig_alg( mbedtls_pk_type_t pk_alg, mbedtls_md_type_t md_alg, + const char **oid, size_t *olen ); + +/** + * \brief Translate hash algorithm OID into md_type + * + * \param oid OID to use + * \param md_alg place to store message digest algorithm + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_md_alg( const mbedtls_asn1_buf *oid, mbedtls_md_type_t *md_alg ); + +/** + * \brief Translate hmac algorithm OID into md_type + * + * \param oid OID to use + * \param md_hmac place to store message hmac algorithm + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_md_hmac( const mbedtls_asn1_buf *oid, mbedtls_md_type_t *md_hmac ); +#endif /* MBEDTLS_MD_C */ + +/** + * \brief Translate Extended Key Usage OID into description + * + * \param oid OID to use + * \param desc place to store string pointer + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_extended_key_usage( const mbedtls_asn1_buf *oid, const char **desc ); + +/** + * \brief Translate md_type into hash algorithm OID + * + * \param md_alg message digest algorithm + * \param oid place to store ASN.1 OID string pointer + * \param olen length of the OID + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_oid_by_md( mbedtls_md_type_t md_alg, const char **oid, size_t *olen ); + +#if defined(MBEDTLS_CIPHER_C) +/** + * \brief Translate encryption algorithm OID into cipher_type + * + * \param oid OID to use + * \param cipher_alg place to store cipher algorithm + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_cipher_alg( const mbedtls_asn1_buf *oid, mbedtls_cipher_type_t *cipher_alg ); +#endif /* MBEDTLS_CIPHER_C */ + +#if defined(MBEDTLS_PKCS12_C) +/** + * \brief Translate PKCS#12 PBE algorithm OID into md_type and + * cipher_type + * + * \param oid OID to use + * \param md_alg place to store message digest algorithm + * \param cipher_alg place to store cipher algorithm + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_pkcs12_pbe_alg( const mbedtls_asn1_buf *oid, mbedtls_md_type_t *md_alg, + mbedtls_cipher_type_t *cipher_alg ); +#endif /* MBEDTLS_PKCS12_C */ + +#ifdef __cplusplus +} +#endif + +#endif /* oid.h */ diff --git a/common/mbedtls/pem.c b/common/mbedtls/pem.c new file mode 100644 index 00000000..3436d07e --- /dev/null +++ b/common/mbedtls/pem.c @@ -0,0 +1,490 @@ +/* + * Privacy Enhanced Mail (PEM) decoding + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PEM_PARSE_C) || defined(MBEDTLS_PEM_WRITE_C) + +#include "mbedtls/pem.h" +#include "mbedtls/base64.h" +#include "mbedtls/des.h" +#include "mbedtls/aes.h" +#include "mbedtls/md5.h" +#include "mbedtls/cipher.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#if defined(MBEDTLS_PEM_PARSE_C) +void mbedtls_pem_init( mbedtls_pem_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_pem_context ) ); +} + +#if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \ + ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) ) +/* + * Read a 16-byte hex string and convert it to binary + */ +static int pem_get_iv( const unsigned char *s, unsigned char *iv, + size_t iv_len ) +{ + size_t i, j, k; + + memset( iv, 0, iv_len ); + + for( i = 0; i < iv_len * 2; i++, s++ ) + { + if( *s >= '0' && *s <= '9' ) j = *s - '0'; else + if( *s >= 'A' && *s <= 'F' ) j = *s - '7'; else + if( *s >= 'a' && *s <= 'f' ) j = *s - 'W'; else + return( MBEDTLS_ERR_PEM_INVALID_ENC_IV ); + + k = ( ( i & 1 ) != 0 ) ? j : j << 4; + + iv[i >> 1] = (unsigned char)( iv[i >> 1] | k ); + } + + return( 0 ); +} + +static int pem_pbkdf1( unsigned char *key, size_t keylen, + unsigned char *iv, + const unsigned char *pwd, size_t pwdlen ) +{ + mbedtls_md5_context md5_ctx; + unsigned char md5sum[16]; + size_t use_len; + int ret; + + mbedtls_md5_init( &md5_ctx ); + + /* + * key[ 0..15] = MD5(pwd || IV) + */ + if( ( ret = mbedtls_md5_starts_ret( &md5_ctx ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md5_update_ret( &md5_ctx, pwd, pwdlen ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md5_update_ret( &md5_ctx, iv, 8 ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md5_finish_ret( &md5_ctx, md5sum ) ) != 0 ) + goto exit; + + if( keylen <= 16 ) + { + memcpy( key, md5sum, keylen ); + goto exit; + } + + memcpy( key, md5sum, 16 ); + + /* + * key[16..23] = MD5(key[ 0..15] || pwd || IV]) + */ + if( ( ret = mbedtls_md5_starts_ret( &md5_ctx ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md5_update_ret( &md5_ctx, md5sum, 16 ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md5_update_ret( &md5_ctx, pwd, pwdlen ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md5_update_ret( &md5_ctx, iv, 8 ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md5_finish_ret( &md5_ctx, md5sum ) ) != 0 ) + goto exit; + + use_len = 16; + if( keylen < 32 ) + use_len = keylen - 16; + + memcpy( key + 16, md5sum, use_len ); + +exit: + mbedtls_md5_free( &md5_ctx ); + mbedtls_platform_zeroize( md5sum, 16 ); + + return( ret ); +} + +#if defined(MBEDTLS_DES_C) +/* + * Decrypt with DES-CBC, using PBKDF1 for key derivation + */ +static int pem_des_decrypt( unsigned char des_iv[8], + unsigned char *buf, size_t buflen, + const unsigned char *pwd, size_t pwdlen ) +{ + mbedtls_des_context des_ctx; + unsigned char des_key[8]; + int ret; + + mbedtls_des_init( &des_ctx ); + + if( ( ret = pem_pbkdf1( des_key, 8, des_iv, pwd, pwdlen ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_des_setkey_dec( &des_ctx, des_key ) ) != 0 ) + goto exit; + ret = mbedtls_des_crypt_cbc( &des_ctx, MBEDTLS_DES_DECRYPT, buflen, + des_iv, buf, buf ); + +exit: + mbedtls_des_free( &des_ctx ); + mbedtls_platform_zeroize( des_key, 8 ); + + return( ret ); +} + +/* + * Decrypt with 3DES-CBC, using PBKDF1 for key derivation + */ +static int pem_des3_decrypt( unsigned char des3_iv[8], + unsigned char *buf, size_t buflen, + const unsigned char *pwd, size_t pwdlen ) +{ + mbedtls_des3_context des3_ctx; + unsigned char des3_key[24]; + int ret; + + mbedtls_des3_init( &des3_ctx ); + + if( ( ret = pem_pbkdf1( des3_key, 24, des3_iv, pwd, pwdlen ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_des3_set3key_dec( &des3_ctx, des3_key ) ) != 0 ) + goto exit; + ret = mbedtls_des3_crypt_cbc( &des3_ctx, MBEDTLS_DES_DECRYPT, buflen, + des3_iv, buf, buf ); + +exit: + mbedtls_des3_free( &des3_ctx ); + mbedtls_platform_zeroize( des3_key, 24 ); + + return( ret ); +} +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_AES_C) +/* + * Decrypt with AES-XXX-CBC, using PBKDF1 for key derivation + */ +static int pem_aes_decrypt( unsigned char aes_iv[16], unsigned int keylen, + unsigned char *buf, size_t buflen, + const unsigned char *pwd, size_t pwdlen ) +{ + mbedtls_aes_context aes_ctx; + unsigned char aes_key[32]; + int ret; + + mbedtls_aes_init( &aes_ctx ); + + if( ( ret = pem_pbkdf1( aes_key, keylen, aes_iv, pwd, pwdlen ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_aes_setkey_dec( &aes_ctx, aes_key, keylen * 8 ) ) != 0 ) + goto exit; + ret = mbedtls_aes_crypt_cbc( &aes_ctx, MBEDTLS_AES_DECRYPT, buflen, + aes_iv, buf, buf ); + +exit: + mbedtls_aes_free( &aes_ctx ); + mbedtls_platform_zeroize( aes_key, keylen ); + + return( ret ); +} +#endif /* MBEDTLS_AES_C */ + +#endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC && + ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */ + +int mbedtls_pem_read_buffer( mbedtls_pem_context *ctx, const char *header, const char *footer, + const unsigned char *data, const unsigned char *pwd, + size_t pwdlen, size_t *use_len ) +{ + int ret, enc; + size_t len; + unsigned char *buf; + const unsigned char *s1, *s2, *end; +#if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \ + ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) ) + unsigned char pem_iv[16]; + mbedtls_cipher_type_t enc_alg = MBEDTLS_CIPHER_NONE; +#else + ((void) pwd); + ((void) pwdlen); +#endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC && + ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */ + + if( ctx == NULL ) + return( MBEDTLS_ERR_PEM_BAD_INPUT_DATA ); + + s1 = (unsigned char *) strstr( (const char *) data, header ); + + if( s1 == NULL ) + return( MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ); + + s2 = (unsigned char *) strstr( (const char *) data, footer ); + + if( s2 == NULL || s2 <= s1 ) + return( MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ); + + s1 += strlen( header ); + if( *s1 == ' ' ) s1++; + if( *s1 == '\r' ) s1++; + if( *s1 == '\n' ) s1++; + else return( MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ); + + end = s2; + end += strlen( footer ); + if( *end == ' ' ) end++; + if( *end == '\r' ) end++; + if( *end == '\n' ) end++; + *use_len = end - data; + + enc = 0; + + if( s2 - s1 >= 22 && memcmp( s1, "Proc-Type: 4,ENCRYPTED", 22 ) == 0 ) + { +#if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \ + ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) ) + enc++; + + s1 += 22; + if( *s1 == '\r' ) s1++; + if( *s1 == '\n' ) s1++; + else return( MBEDTLS_ERR_PEM_INVALID_DATA ); + + +#if defined(MBEDTLS_DES_C) + if( s2 - s1 >= 23 && memcmp( s1, "DEK-Info: DES-EDE3-CBC,", 23 ) == 0 ) + { + enc_alg = MBEDTLS_CIPHER_DES_EDE3_CBC; + + s1 += 23; + if( s2 - s1 < 16 || pem_get_iv( s1, pem_iv, 8 ) != 0 ) + return( MBEDTLS_ERR_PEM_INVALID_ENC_IV ); + + s1 += 16; + } + else if( s2 - s1 >= 18 && memcmp( s1, "DEK-Info: DES-CBC,", 18 ) == 0 ) + { + enc_alg = MBEDTLS_CIPHER_DES_CBC; + + s1 += 18; + if( s2 - s1 < 16 || pem_get_iv( s1, pem_iv, 8) != 0 ) + return( MBEDTLS_ERR_PEM_INVALID_ENC_IV ); + + s1 += 16; + } +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_AES_C) + if( s2 - s1 >= 14 && memcmp( s1, "DEK-Info: AES-", 14 ) == 0 ) + { + if( s2 - s1 < 22 ) + return( MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG ); + else if( memcmp( s1, "DEK-Info: AES-128-CBC,", 22 ) == 0 ) + enc_alg = MBEDTLS_CIPHER_AES_128_CBC; + else if( memcmp( s1, "DEK-Info: AES-192-CBC,", 22 ) == 0 ) + enc_alg = MBEDTLS_CIPHER_AES_192_CBC; + else if( memcmp( s1, "DEK-Info: AES-256-CBC,", 22 ) == 0 ) + enc_alg = MBEDTLS_CIPHER_AES_256_CBC; + else + return( MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG ); + + s1 += 22; + if( s2 - s1 < 32 || pem_get_iv( s1, pem_iv, 16 ) != 0 ) + return( MBEDTLS_ERR_PEM_INVALID_ENC_IV ); + + s1 += 32; + } +#endif /* MBEDTLS_AES_C */ + + if( enc_alg == MBEDTLS_CIPHER_NONE ) + return( MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG ); + + if( *s1 == '\r' ) s1++; + if( *s1 == '\n' ) s1++; + else return( MBEDTLS_ERR_PEM_INVALID_DATA ); +#else + return( MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE ); +#endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC && + ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */ + } + + if( s1 >= s2 ) + return( MBEDTLS_ERR_PEM_INVALID_DATA ); + + ret = mbedtls_base64_decode( NULL, 0, &len, s1, s2 - s1 ); + + if( ret == MBEDTLS_ERR_BASE64_INVALID_CHARACTER ) + return( MBEDTLS_ERR_PEM_INVALID_DATA + ret ); + + if( ( buf = mbedtls_calloc( 1, len ) ) == NULL ) + return( MBEDTLS_ERR_PEM_ALLOC_FAILED ); + + if( ( ret = mbedtls_base64_decode( buf, len, &len, s1, s2 - s1 ) ) != 0 ) + { + mbedtls_platform_zeroize( buf, len ); + mbedtls_free( buf ); + return( MBEDTLS_ERR_PEM_INVALID_DATA + ret ); + } + + if( enc != 0 ) + { +#if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \ + ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) ) + if( pwd == NULL ) + { + mbedtls_platform_zeroize( buf, len ); + mbedtls_free( buf ); + return( MBEDTLS_ERR_PEM_PASSWORD_REQUIRED ); + } + + ret = 0; + +#if defined(MBEDTLS_DES_C) + if( enc_alg == MBEDTLS_CIPHER_DES_EDE3_CBC ) + ret = pem_des3_decrypt( pem_iv, buf, len, pwd, pwdlen ); + else if( enc_alg == MBEDTLS_CIPHER_DES_CBC ) + ret = pem_des_decrypt( pem_iv, buf, len, pwd, pwdlen ); +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_AES_C) + if( enc_alg == MBEDTLS_CIPHER_AES_128_CBC ) + ret = pem_aes_decrypt( pem_iv, 16, buf, len, pwd, pwdlen ); + else if( enc_alg == MBEDTLS_CIPHER_AES_192_CBC ) + ret = pem_aes_decrypt( pem_iv, 24, buf, len, pwd, pwdlen ); + else if( enc_alg == MBEDTLS_CIPHER_AES_256_CBC ) + ret = pem_aes_decrypt( pem_iv, 32, buf, len, pwd, pwdlen ); +#endif /* MBEDTLS_AES_C */ + + if( ret != 0 ) + { + mbedtls_free( buf ); + return( ret ); + } + + /* + * The result will be ASN.1 starting with a SEQUENCE tag, with 1 to 3 + * length bytes (allow 4 to be sure) in all known use cases. + * + * Use that as a heuristic to try to detect password mismatches. + */ + if( len <= 2 || buf[0] != 0x30 || buf[1] > 0x83 ) + { + mbedtls_platform_zeroize( buf, len ); + mbedtls_free( buf ); + return( MBEDTLS_ERR_PEM_PASSWORD_MISMATCH ); + } +#else + mbedtls_platform_zeroize( buf, len ); + mbedtls_free( buf ); + return( MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE ); +#endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC && + ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */ + } + + ctx->buf = buf; + ctx->buflen = len; + + return( 0 ); +} + +void mbedtls_pem_free( mbedtls_pem_context *ctx ) +{ + if( ctx->buf != NULL ) + mbedtls_platform_zeroize( ctx->buf, ctx->buflen ); + mbedtls_free( ctx->buf ); + mbedtls_free( ctx->info ); + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_pem_context ) ); +} +#endif /* MBEDTLS_PEM_PARSE_C */ + +#if defined(MBEDTLS_PEM_WRITE_C) +int mbedtls_pem_write_buffer( const char *header, const char *footer, + const unsigned char *der_data, size_t der_len, + unsigned char *buf, size_t buf_len, size_t *olen ) +{ + int ret; + unsigned char *encode_buf = NULL, *c, *p = buf; + size_t len = 0, use_len, add_len = 0; + + mbedtls_base64_encode( NULL, 0, &use_len, der_data, der_len ); + add_len = strlen( header ) + strlen( footer ) + ( use_len / 64 ) + 1; + + if( use_len + add_len > buf_len ) + { + *olen = use_len + add_len; + return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL ); + } + + if( use_len != 0 && + ( ( encode_buf = mbedtls_calloc( 1, use_len ) ) == NULL ) ) + return( MBEDTLS_ERR_PEM_ALLOC_FAILED ); + + if( ( ret = mbedtls_base64_encode( encode_buf, use_len, &use_len, der_data, + der_len ) ) != 0 ) + { + mbedtls_free( encode_buf ); + return( ret ); + } + + memcpy( p, header, strlen( header ) ); + p += strlen( header ); + c = encode_buf; + + while( use_len ) + { + len = ( use_len > 64 ) ? 64 : use_len; + memcpy( p, c, len ); + use_len -= len; + p += len; + c += len; + *p++ = '\n'; + } + + memcpy( p, footer, strlen( footer ) ); + p += strlen( footer ); + + *p++ = '\0'; + *olen = p - buf; + + mbedtls_free( encode_buf ); + return( 0 ); +} +#endif /* MBEDTLS_PEM_WRITE_C */ +#endif /* MBEDTLS_PEM_PARSE_C || MBEDTLS_PEM_WRITE_C */ diff --git a/common/mbedtls/pem.h b/common/mbedtls/pem.h new file mode 100644 index 00000000..c0e5e025 --- /dev/null +++ b/common/mbedtls/pem.h @@ -0,0 +1,132 @@ +/** + * \file pem.h + * + * \brief Privacy Enhanced Mail (PEM) decoding + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_PEM_H +#define MBEDTLS_PEM_H + +#include + +/** + * \name PEM Error codes + * These error codes are returned in case of errors reading the + * PEM data. + * \{ + */ +#define MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT -0x1080 /**< No PEM header or footer found. */ +#define MBEDTLS_ERR_PEM_INVALID_DATA -0x1100 /**< PEM string is not as expected. */ +#define MBEDTLS_ERR_PEM_ALLOC_FAILED -0x1180 /**< Failed to allocate memory. */ +#define MBEDTLS_ERR_PEM_INVALID_ENC_IV -0x1200 /**< RSA IV is not in hex-format. */ +#define MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG -0x1280 /**< Unsupported key encryption algorithm. */ +#define MBEDTLS_ERR_PEM_PASSWORD_REQUIRED -0x1300 /**< Private key password can't be empty. */ +#define MBEDTLS_ERR_PEM_PASSWORD_MISMATCH -0x1380 /**< Given private key password does not allow for correct decryption. */ +#define MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE -0x1400 /**< Unavailable feature, e.g. hashing/encryption combination. */ +#define MBEDTLS_ERR_PEM_BAD_INPUT_DATA -0x1480 /**< Bad input parameters to function. */ +/* \} name */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(MBEDTLS_PEM_PARSE_C) +/** + * \brief PEM context structure + */ +typedef struct mbedtls_pem_context +{ + unsigned char *buf; /*!< buffer for decoded data */ + size_t buflen; /*!< length of the buffer */ + unsigned char *info; /*!< buffer for extra header information */ +} +mbedtls_pem_context; + +/** + * \brief PEM context setup + * + * \param ctx context to be initialized + */ +void mbedtls_pem_init( mbedtls_pem_context *ctx ); + +/** + * \brief Read a buffer for PEM information and store the resulting + * data into the specified context buffers. + * + * \param ctx context to use + * \param header header string to seek and expect + * \param footer footer string to seek and expect + * \param data source data to look in (must be nul-terminated) + * \param pwd password for decryption (can be NULL) + * \param pwdlen length of password + * \param use_len destination for total length used (set after header is + * correctly read, so unless you get + * MBEDTLS_ERR_PEM_BAD_INPUT_DATA or + * MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT, use_len is + * the length to skip) + * + * \note Attempts to check password correctness by verifying if + * the decrypted text starts with an ASN.1 sequence of + * appropriate length + * + * \return 0 on success, or a specific PEM error code + */ +int mbedtls_pem_read_buffer( mbedtls_pem_context *ctx, const char *header, const char *footer, + const unsigned char *data, + const unsigned char *pwd, + size_t pwdlen, size_t *use_len ); + +/** + * \brief PEM context memory freeing + * + * \param ctx context to be freed + */ +void mbedtls_pem_free( mbedtls_pem_context *ctx ); +#endif /* MBEDTLS_PEM_PARSE_C */ + +#if defined(MBEDTLS_PEM_WRITE_C) +/** + * \brief Write a buffer of PEM information from a DER encoded + * buffer. + * + * \param header header string to write + * \param footer footer string to write + * \param der_data DER data to write + * \param der_len length of the DER data + * \param buf buffer to write to + * \param buf_len length of output buffer + * \param olen total length written / required (if buf_len is not enough) + * + * \return 0 on success, or a specific PEM or BASE64 error code. On + * MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL olen is the required + * size. + */ +int mbedtls_pem_write_buffer( const char *header, const char *footer, + const unsigned char *der_data, size_t der_len, + unsigned char *buf, size_t buf_len, size_t *olen ); +#endif /* MBEDTLS_PEM_WRITE_C */ + +#ifdef __cplusplus +} +#endif + +#endif /* pem.h */ diff --git a/common/mbedtls/pk.c b/common/mbedtls/pk.c new file mode 100644 index 00000000..784b6696 --- /dev/null +++ b/common/mbedtls/pk.c @@ -0,0 +1,381 @@ +/* + * Public Key abstraction layer + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PK_C) +#include "mbedtls/pk.h" +#include "mbedtls/pk_internal.h" + +#include "mbedtls/platform_util.h" + +#if defined(MBEDTLS_RSA_C) +#include "mbedtls/rsa.h" +#endif +#if defined(MBEDTLS_ECP_C) +#include "mbedtls/ecp.h" +#endif +#if defined(MBEDTLS_ECDSA_C) +#include "mbedtls/ecdsa.h" +#endif + +#include +#include + +/* + * Initialise a mbedtls_pk_context + */ +void mbedtls_pk_init( mbedtls_pk_context *ctx ) +{ + if( ctx == NULL ) + return; + + ctx->pk_info = NULL; + ctx->pk_ctx = NULL; +} + +/* + * Free (the components of) a mbedtls_pk_context + */ +void mbedtls_pk_free( mbedtls_pk_context *ctx ) +{ + if( ctx == NULL || ctx->pk_info == NULL ) + return; + + ctx->pk_info->ctx_free_func( ctx->pk_ctx ); + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_pk_context ) ); +} + +/* + * Get pk_info structure from type + */ +const mbedtls_pk_info_t * mbedtls_pk_info_from_type( mbedtls_pk_type_t pk_type ) +{ + switch( pk_type ) { +#if defined(MBEDTLS_RSA_C) + case MBEDTLS_PK_RSA: + return( &mbedtls_rsa_info ); +#endif +#if defined(MBEDTLS_ECP_C) + case MBEDTLS_PK_ECKEY: + return( &mbedtls_eckey_info ); + case MBEDTLS_PK_ECKEY_DH: + return( &mbedtls_eckeydh_info ); +#endif +#if defined(MBEDTLS_ECDSA_C) + case MBEDTLS_PK_ECDSA: + return( &mbedtls_ecdsa_info ); +#endif + /* MBEDTLS_PK_RSA_ALT omitted on purpose */ + default: + return( NULL ); + } +} + +/* + * Initialise context + */ +int mbedtls_pk_setup( mbedtls_pk_context *ctx, const mbedtls_pk_info_t *info ) +{ + if( ctx == NULL || info == NULL || ctx->pk_info != NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ( ctx->pk_ctx = info->ctx_alloc_func() ) == NULL ) + return( MBEDTLS_ERR_PK_ALLOC_FAILED ); + + ctx->pk_info = info; + + return( 0 ); +} + +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) +/* + * Initialize an RSA-alt context + */ +int mbedtls_pk_setup_rsa_alt( mbedtls_pk_context *ctx, void * key, + mbedtls_pk_rsa_alt_decrypt_func decrypt_func, + mbedtls_pk_rsa_alt_sign_func sign_func, + mbedtls_pk_rsa_alt_key_len_func key_len_func ) +{ + mbedtls_rsa_alt_context *rsa_alt; + const mbedtls_pk_info_t *info = &mbedtls_rsa_alt_info; + + if( ctx == NULL || ctx->pk_info != NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ( ctx->pk_ctx = info->ctx_alloc_func() ) == NULL ) + return( MBEDTLS_ERR_PK_ALLOC_FAILED ); + + ctx->pk_info = info; + + rsa_alt = (mbedtls_rsa_alt_context *) ctx->pk_ctx; + + rsa_alt->key = key; + rsa_alt->decrypt_func = decrypt_func; + rsa_alt->sign_func = sign_func; + rsa_alt->key_len_func = key_len_func; + + return( 0 ); +} +#endif /* MBEDTLS_PK_RSA_ALT_SUPPORT */ + +/* + * Tell if a PK can do the operations of the given type + */ +int mbedtls_pk_can_do( const mbedtls_pk_context *ctx, mbedtls_pk_type_t type ) +{ + /* null or NONE context can't do anything */ + if( ctx == NULL || ctx->pk_info == NULL ) + return( 0 ); + + return( ctx->pk_info->can_do( type ) ); +} + +/* + * Helper for mbedtls_pk_sign and mbedtls_pk_verify + */ +static inline int pk_hashlen_helper( mbedtls_md_type_t md_alg, size_t *hash_len ) +{ + const mbedtls_md_info_t *md_info; + + if( *hash_len != 0 ) + return( 0 ); + + if( ( md_info = mbedtls_md_info_from_type( md_alg ) ) == NULL ) + return( -1 ); + + *hash_len = mbedtls_md_get_size( md_info ); + return( 0 ); +} + +/* + * Verify a signature + */ +int mbedtls_pk_verify( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ) +{ + if( ctx == NULL || ctx->pk_info == NULL || + pk_hashlen_helper( md_alg, &hash_len ) != 0 ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ctx->pk_info->verify_func == NULL ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + + return( ctx->pk_info->verify_func( ctx->pk_ctx, md_alg, hash, hash_len, + sig, sig_len ) ); +} + +/* + * Verify a signature with options + */ +int mbedtls_pk_verify_ext( mbedtls_pk_type_t type, const void *options, + mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ) +{ + if( ctx == NULL || ctx->pk_info == NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ! mbedtls_pk_can_do( ctx, type ) ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + + if( type == MBEDTLS_PK_RSASSA_PSS ) + { +#if defined(MBEDTLS_RSA_C) && defined(MBEDTLS_PKCS1_V21) + int ret; + const mbedtls_pk_rsassa_pss_options *pss_opts; + +#if SIZE_MAX > UINT_MAX + if( md_alg == MBEDTLS_MD_NONE && UINT_MAX < hash_len ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); +#endif /* SIZE_MAX > UINT_MAX */ + + if( options == NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + pss_opts = (const mbedtls_pk_rsassa_pss_options *) options; + + if( sig_len < mbedtls_pk_get_len( ctx ) ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + ret = mbedtls_rsa_rsassa_pss_verify_ext( mbedtls_pk_rsa( *ctx ), + NULL, NULL, MBEDTLS_RSA_PUBLIC, + md_alg, (unsigned int) hash_len, hash, + pss_opts->mgf1_hash_id, + pss_opts->expected_salt_len, + sig ); + if( ret != 0 ) + return( ret ); + + if( sig_len > mbedtls_pk_get_len( ctx ) ) + return( MBEDTLS_ERR_PK_SIG_LEN_MISMATCH ); + + return( 0 ); +#else + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); +#endif /* MBEDTLS_RSA_C && MBEDTLS_PKCS1_V21 */ + } + + /* General case: no options */ + if( options != NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + return( mbedtls_pk_verify( ctx, md_alg, hash, hash_len, sig, sig_len ) ); +} + +/* + * Make a signature + */ +int mbedtls_pk_sign( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + if( ctx == NULL || ctx->pk_info == NULL || + pk_hashlen_helper( md_alg, &hash_len ) != 0 ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ctx->pk_info->sign_func == NULL ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + + return( ctx->pk_info->sign_func( ctx->pk_ctx, md_alg, hash, hash_len, + sig, sig_len, f_rng, p_rng ) ); +} + +/* + * Decrypt message + */ +int mbedtls_pk_decrypt( mbedtls_pk_context *ctx, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + if( ctx == NULL || ctx->pk_info == NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ctx->pk_info->decrypt_func == NULL ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + + return( ctx->pk_info->decrypt_func( ctx->pk_ctx, input, ilen, + output, olen, osize, f_rng, p_rng ) ); +} + +/* + * Encrypt message + */ +int mbedtls_pk_encrypt( mbedtls_pk_context *ctx, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + if( ctx == NULL || ctx->pk_info == NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ctx->pk_info->encrypt_func == NULL ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + + return( ctx->pk_info->encrypt_func( ctx->pk_ctx, input, ilen, + output, olen, osize, f_rng, p_rng ) ); +} + +/* + * Check public-private key pair + */ +int mbedtls_pk_check_pair( const mbedtls_pk_context *pub, const mbedtls_pk_context *prv ) +{ + if( pub == NULL || pub->pk_info == NULL || + prv == NULL || prv->pk_info == NULL || + prv->pk_info->check_pair_func == NULL ) + { + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + } + + if( prv->pk_info->type == MBEDTLS_PK_RSA_ALT ) + { + if( pub->pk_info->type != MBEDTLS_PK_RSA ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + } + else + { + if( pub->pk_info != prv->pk_info ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + } + + return( prv->pk_info->check_pair_func( pub->pk_ctx, prv->pk_ctx ) ); +} + +/* + * Get key size in bits + */ +size_t mbedtls_pk_get_bitlen( const mbedtls_pk_context *ctx ) +{ + if( ctx == NULL || ctx->pk_info == NULL ) + return( 0 ); + + return( ctx->pk_info->get_bitlen( ctx->pk_ctx ) ); +} + +/* + * Export debug information + */ +int mbedtls_pk_debug( const mbedtls_pk_context *ctx, mbedtls_pk_debug_item *items ) +{ + if( ctx == NULL || ctx->pk_info == NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ctx->pk_info->debug_func == NULL ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + + ctx->pk_info->debug_func( ctx->pk_ctx, items ); + return( 0 ); +} + +/* + * Access the PK type name + */ +const char *mbedtls_pk_get_name( const mbedtls_pk_context *ctx ) +{ + if( ctx == NULL || ctx->pk_info == NULL ) + return( "invalid PK" ); + + return( ctx->pk_info->name ); +} + +/* + * Access the PK type + */ +mbedtls_pk_type_t mbedtls_pk_get_type( const mbedtls_pk_context *ctx ) +{ + if( ctx == NULL || ctx->pk_info == NULL ) + return( MBEDTLS_PK_NONE ); + + return( ctx->pk_info->type ); +} + +#endif /* MBEDTLS_PK_C */ diff --git a/common/mbedtls/pk.h b/common/mbedtls/pk.h new file mode 100644 index 00000000..f75dc2f8 --- /dev/null +++ b/common/mbedtls/pk.h @@ -0,0 +1,620 @@ +/** + * \file pk.h + * + * \brief Public Key abstraction layer + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_PK_H +#define MBEDTLS_PK_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "md.h" + +#if defined(MBEDTLS_RSA_C) +#include "rsa.h" +#endif + +#if defined(MBEDTLS_ECP_C) +#include "ecp.h" +#endif + +#if defined(MBEDTLS_ECDSA_C) +#include "ecdsa.h" +#endif + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +#define MBEDTLS_ERR_PK_ALLOC_FAILED -0x3F80 /**< Memory allocation failed. */ +#define MBEDTLS_ERR_PK_TYPE_MISMATCH -0x3F00 /**< Type mismatch, eg attempt to encrypt with an ECDSA key */ +#define MBEDTLS_ERR_PK_BAD_INPUT_DATA -0x3E80 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_PK_FILE_IO_ERROR -0x3E00 /**< Read/write of file failed. */ +#define MBEDTLS_ERR_PK_KEY_INVALID_VERSION -0x3D80 /**< Unsupported key version */ +#define MBEDTLS_ERR_PK_KEY_INVALID_FORMAT -0x3D00 /**< Invalid key tag or value. */ +#define MBEDTLS_ERR_PK_UNKNOWN_PK_ALG -0x3C80 /**< Key algorithm is unsupported (only RSA and EC are supported). */ +#define MBEDTLS_ERR_PK_PASSWORD_REQUIRED -0x3C00 /**< Private key password can't be empty. */ +#define MBEDTLS_ERR_PK_PASSWORD_MISMATCH -0x3B80 /**< Given private key password does not allow for correct decryption. */ +#define MBEDTLS_ERR_PK_INVALID_PUBKEY -0x3B00 /**< The pubkey tag or value is invalid (only RSA and EC are supported). */ +#define MBEDTLS_ERR_PK_INVALID_ALG -0x3A80 /**< The algorithm tag or value is invalid. */ +#define MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE -0x3A00 /**< Elliptic curve is unsupported (only NIST curves are supported). */ +#define MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE -0x3980 /**< Unavailable feature, e.g. RSA disabled for RSA key. */ +#define MBEDTLS_ERR_PK_SIG_LEN_MISMATCH -0x3900 /**< The buffer contains a valid signature followed by more data. */ +#define MBEDTLS_ERR_PK_HW_ACCEL_FAILED -0x3880 /**< PK hardware accelerator failed. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Public key types + */ +typedef enum { + MBEDTLS_PK_NONE=0, + MBEDTLS_PK_RSA, + MBEDTLS_PK_ECKEY, + MBEDTLS_PK_ECKEY_DH, + MBEDTLS_PK_ECDSA, + MBEDTLS_PK_RSA_ALT, + MBEDTLS_PK_RSASSA_PSS, +} mbedtls_pk_type_t; + +/** + * \brief Options for RSASSA-PSS signature verification. + * See \c mbedtls_rsa_rsassa_pss_verify_ext() + */ +typedef struct mbedtls_pk_rsassa_pss_options +{ + mbedtls_md_type_t mgf1_hash_id; + int expected_salt_len; + +} mbedtls_pk_rsassa_pss_options; + +/** + * \brief Types for interfacing with the debug module + */ +typedef enum +{ + MBEDTLS_PK_DEBUG_NONE = 0, + MBEDTLS_PK_DEBUG_MPI, + MBEDTLS_PK_DEBUG_ECP, +} mbedtls_pk_debug_type; + +/** + * \brief Item to send to the debug module + */ +typedef struct mbedtls_pk_debug_item +{ + mbedtls_pk_debug_type type; + const char *name; + void *value; +} mbedtls_pk_debug_item; + +/** Maximum number of item send for debugging, plus 1 */ +#define MBEDTLS_PK_DEBUG_MAX_ITEMS 3 + +/** + * \brief Public key information and operations + */ +typedef struct mbedtls_pk_info_t mbedtls_pk_info_t; + +/** + * \brief Public key container + */ +typedef struct mbedtls_pk_context +{ + const mbedtls_pk_info_t * pk_info; /**< Public key informations */ + void * pk_ctx; /**< Underlying public key context */ +} mbedtls_pk_context; + +#if defined(MBEDTLS_RSA_C) +/** + * Quick access to an RSA context inside a PK context. + * + * \warning You must make sure the PK context actually holds an RSA context + * before using this function! + */ +static inline mbedtls_rsa_context *mbedtls_pk_rsa( const mbedtls_pk_context pk ) +{ + return( (mbedtls_rsa_context *) (pk).pk_ctx ); +} +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_ECP_C) +/** + * Quick access to an EC context inside a PK context. + * + * \warning You must make sure the PK context actually holds an EC context + * before using this function! + */ +static inline mbedtls_ecp_keypair *mbedtls_pk_ec( const mbedtls_pk_context pk ) +{ + return( (mbedtls_ecp_keypair *) (pk).pk_ctx ); +} +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) +/** + * \brief Types for RSA-alt abstraction + */ +typedef int (*mbedtls_pk_rsa_alt_decrypt_func)( void *ctx, int mode, size_t *olen, + const unsigned char *input, unsigned char *output, + size_t output_max_len ); +typedef int (*mbedtls_pk_rsa_alt_sign_func)( void *ctx, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + int mode, mbedtls_md_type_t md_alg, unsigned int hashlen, + const unsigned char *hash, unsigned char *sig ); +typedef size_t (*mbedtls_pk_rsa_alt_key_len_func)( void *ctx ); +#endif /* MBEDTLS_PK_RSA_ALT_SUPPORT */ + +/** + * \brief Return information associated with the given PK type + * + * \param pk_type PK type to search for. + * + * \return The PK info associated with the type or NULL if not found. + */ +const mbedtls_pk_info_t *mbedtls_pk_info_from_type( mbedtls_pk_type_t pk_type ); + +/** + * \brief Initialize a mbedtls_pk_context (as NONE) + */ +void mbedtls_pk_init( mbedtls_pk_context *ctx ); + +/** + * \brief Free a mbedtls_pk_context + */ +void mbedtls_pk_free( mbedtls_pk_context *ctx ); + +/** + * \brief Initialize a PK context with the information given + * and allocates the type-specific PK subcontext. + * + * \param ctx Context to initialize. Must be empty (type NONE). + * \param info Information to use + * + * \return 0 on success, + * MBEDTLS_ERR_PK_BAD_INPUT_DATA on invalid input, + * MBEDTLS_ERR_PK_ALLOC_FAILED on allocation failure. + * + * \note For contexts holding an RSA-alt key, use + * \c mbedtls_pk_setup_rsa_alt() instead. + */ +int mbedtls_pk_setup( mbedtls_pk_context *ctx, const mbedtls_pk_info_t *info ); + +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) +/** + * \brief Initialize an RSA-alt context + * + * \param ctx Context to initialize. Must be empty (type NONE). + * \param key RSA key pointer + * \param decrypt_func Decryption function + * \param sign_func Signing function + * \param key_len_func Function returning key length in bytes + * + * \return 0 on success, or MBEDTLS_ERR_PK_BAD_INPUT_DATA if the + * context wasn't already initialized as RSA_ALT. + * + * \note This function replaces \c mbedtls_pk_setup() for RSA-alt. + */ +int mbedtls_pk_setup_rsa_alt( mbedtls_pk_context *ctx, void * key, + mbedtls_pk_rsa_alt_decrypt_func decrypt_func, + mbedtls_pk_rsa_alt_sign_func sign_func, + mbedtls_pk_rsa_alt_key_len_func key_len_func ); +#endif /* MBEDTLS_PK_RSA_ALT_SUPPORT */ + +/** + * \brief Get the size in bits of the underlying key + * + * \param ctx Context to use + * + * \return Key size in bits, or 0 on error + */ +size_t mbedtls_pk_get_bitlen( const mbedtls_pk_context *ctx ); + +/** + * \brief Get the length in bytes of the underlying key + * \param ctx Context to use + * + * \return Key length in bytes, or 0 on error + */ +static inline size_t mbedtls_pk_get_len( const mbedtls_pk_context *ctx ) +{ + return( ( mbedtls_pk_get_bitlen( ctx ) + 7 ) / 8 ); +} + +/** + * \brief Tell if a context can do the operation given by type + * + * \param ctx Context to test + * \param type Target type + * + * \return 0 if context can't do the operations, + * 1 otherwise. + */ +int mbedtls_pk_can_do( const mbedtls_pk_context *ctx, mbedtls_pk_type_t type ); + +/** + * \brief Verify signature (including padding if relevant). + * + * \param ctx PK context to use + * \param md_alg Hash algorithm used (see notes) + * \param hash Hash of the message to sign + * \param hash_len Hash length or 0 (see notes) + * \param sig Signature to verify + * \param sig_len Signature length + * + * \return 0 on success (signature is valid), + * #MBEDTLS_ERR_PK_SIG_LEN_MISMATCH if there is a valid + * signature in sig but its length is less than \p siglen, + * or a specific error code. + * + * \note For RSA keys, the default padding type is PKCS#1 v1.5. + * Use \c mbedtls_pk_verify_ext( MBEDTLS_PK_RSASSA_PSS, ... ) + * to verify RSASSA_PSS signatures. + * + * \note If hash_len is 0, then the length associated with md_alg + * is used instead, or an error returned if it is invalid. + * + * \note md_alg may be MBEDTLS_MD_NONE, only if hash_len != 0 + */ +int mbedtls_pk_verify( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ); + +/** + * \brief Verify signature, with options. + * (Includes verification of the padding depending on type.) + * + * \param type Signature type (inc. possible padding type) to verify + * \param options Pointer to type-specific options, or NULL + * \param ctx PK context to use + * \param md_alg Hash algorithm used (see notes) + * \param hash Hash of the message to sign + * \param hash_len Hash length or 0 (see notes) + * \param sig Signature to verify + * \param sig_len Signature length + * + * \return 0 on success (signature is valid), + * #MBEDTLS_ERR_PK_TYPE_MISMATCH if the PK context can't be + * used for this type of signatures, + * #MBEDTLS_ERR_PK_SIG_LEN_MISMATCH if there is a valid + * signature in sig but its length is less than \p siglen, + * or a specific error code. + * + * \note If hash_len is 0, then the length associated with md_alg + * is used instead, or an error returned if it is invalid. + * + * \note md_alg may be MBEDTLS_MD_NONE, only if hash_len != 0 + * + * \note If type is MBEDTLS_PK_RSASSA_PSS, then options must point + * to a mbedtls_pk_rsassa_pss_options structure, + * otherwise it must be NULL. + */ +int mbedtls_pk_verify_ext( mbedtls_pk_type_t type, const void *options, + mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ); + +/** + * \brief Make signature, including padding if relevant. + * + * \param ctx PK context to use - must hold a private key + * \param md_alg Hash algorithm used (see notes) + * \param hash Hash of the message to sign + * \param hash_len Hash length or 0 (see notes) + * \param sig Place to write the signature + * \param sig_len Number of bytes written + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 on success, or a specific error code. + * + * \note For RSA keys, the default padding type is PKCS#1 v1.5. + * There is no interface in the PK module to make RSASSA-PSS + * signatures yet. + * + * \note If hash_len is 0, then the length associated with md_alg + * is used instead, or an error returned if it is invalid. + * + * \note For RSA, md_alg may be MBEDTLS_MD_NONE if hash_len != 0. + * For ECDSA, md_alg may never be MBEDTLS_MD_NONE. + */ +int mbedtls_pk_sign( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + +/** + * \brief Decrypt message (including padding if relevant). + * + * \param ctx PK context to use - must hold a private key + * \param input Input to decrypt + * \param ilen Input size + * \param output Decrypted output + * \param olen Decrypted message length + * \param osize Size of the output buffer + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \note For RSA keys, the default padding type is PKCS#1 v1.5. + * + * \return 0 on success, or a specific error code. + */ +int mbedtls_pk_decrypt( mbedtls_pk_context *ctx, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + +/** + * \brief Encrypt message (including padding if relevant). + * + * \param ctx PK context to use + * \param input Message to encrypt + * \param ilen Message size + * \param output Encrypted output + * \param olen Encrypted output length + * \param osize Size of the output buffer + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \note For RSA keys, the default padding type is PKCS#1 v1.5. + * + * \return 0 on success, or a specific error code. + */ +int mbedtls_pk_encrypt( mbedtls_pk_context *ctx, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + +/** + * \brief Check if a public-private pair of keys matches. + * + * \param pub Context holding a public key. + * \param prv Context holding a private (and public) key. + * + * \return 0 on success or MBEDTLS_ERR_PK_BAD_INPUT_DATA + */ +int mbedtls_pk_check_pair( const mbedtls_pk_context *pub, const mbedtls_pk_context *prv ); + +/** + * \brief Export debug information + * + * \param ctx Context to use + * \param items Place to write debug items + * + * \return 0 on success or MBEDTLS_ERR_PK_BAD_INPUT_DATA + */ +int mbedtls_pk_debug( const mbedtls_pk_context *ctx, mbedtls_pk_debug_item *items ); + +/** + * \brief Access the type name + * + * \param ctx Context to use + * + * \return Type name on success, or "invalid PK" + */ +const char * mbedtls_pk_get_name( const mbedtls_pk_context *ctx ); + +/** + * \brief Get the key type + * + * \param ctx Context to use + * + * \return Type on success, or MBEDTLS_PK_NONE + */ +mbedtls_pk_type_t mbedtls_pk_get_type( const mbedtls_pk_context *ctx ); + +#if defined(MBEDTLS_PK_PARSE_C) +/** \ingroup pk_module */ +/** + * \brief Parse a private key in PEM or DER format + * + * \param ctx key to be initialized + * \param key input buffer + * \param keylen size of the buffer + * (including the terminating null byte for PEM data) + * \param pwd password for decryption (optional) + * \param pwdlen size of the password + * + * \note On entry, ctx must be empty, either freshly initialised + * with mbedtls_pk_init() or reset with mbedtls_pk_free(). If you need a + * specific key type, check the result with mbedtls_pk_can_do(). + * + * \note The key is also checked for correctness. + * + * \return 0 if successful, or a specific PK or PEM error code + */ +int mbedtls_pk_parse_key( mbedtls_pk_context *ctx, + const unsigned char *key, size_t keylen, + const unsigned char *pwd, size_t pwdlen ); + +/** \ingroup pk_module */ +/** + * \brief Parse a public key in PEM or DER format + * + * \param ctx key to be initialized + * \param key input buffer + * \param keylen size of the buffer + * (including the terminating null byte for PEM data) + * + * \note On entry, ctx must be empty, either freshly initialised + * with mbedtls_pk_init() or reset with mbedtls_pk_free(). If you need a + * specific key type, check the result with mbedtls_pk_can_do(). + * + * \note The key is also checked for correctness. + * + * \return 0 if successful, or a specific PK or PEM error code + */ +int mbedtls_pk_parse_public_key( mbedtls_pk_context *ctx, + const unsigned char *key, size_t keylen ); + +#if defined(MBEDTLS_FS_IO) +/** \ingroup pk_module */ +/** + * \brief Load and parse a private key + * + * \param ctx key to be initialized + * \param path filename to read the private key from + * \param password password to decrypt the file (can be NULL) + * + * \note On entry, ctx must be empty, either freshly initialised + * with mbedtls_pk_init() or reset with mbedtls_pk_free(). If you need a + * specific key type, check the result with mbedtls_pk_can_do(). + * + * \note The key is also checked for correctness. + * + * \return 0 if successful, or a specific PK or PEM error code + */ +int mbedtls_pk_parse_keyfile( mbedtls_pk_context *ctx, + const char *path, const char *password ); + +/** \ingroup pk_module */ +/** + * \brief Load and parse a public key + * + * \param ctx key to be initialized + * \param path filename to read the public key from + * + * \note On entry, ctx must be empty, either freshly initialised + * with mbedtls_pk_init() or reset with mbedtls_pk_free(). If + * you need a specific key type, check the result with + * mbedtls_pk_can_do(). + * + * \note The key is also checked for correctness. + * + * \return 0 if successful, or a specific PK or PEM error code + */ +int mbedtls_pk_parse_public_keyfile( mbedtls_pk_context *ctx, const char *path ); +#endif /* MBEDTLS_FS_IO */ +#endif /* MBEDTLS_PK_PARSE_C */ + +#if defined(MBEDTLS_PK_WRITE_C) +/** + * \brief Write a private key to a PKCS#1 or SEC1 DER structure + * Note: data is written at the end of the buffer! Use the + * return value to determine where you should start + * using the buffer + * + * \param ctx private to write away + * \param buf buffer to write to + * \param size size of the buffer + * + * \return length of data written if successful, or a specific + * error code + */ +int mbedtls_pk_write_key_der( mbedtls_pk_context *ctx, unsigned char *buf, size_t size ); + +/** + * \brief Write a public key to a SubjectPublicKeyInfo DER structure + * Note: data is written at the end of the buffer! Use the + * return value to determine where you should start + * using the buffer + * + * \param ctx public key to write away + * \param buf buffer to write to + * \param size size of the buffer + * + * \return length of data written if successful, or a specific + * error code + */ +int mbedtls_pk_write_pubkey_der( mbedtls_pk_context *ctx, unsigned char *buf, size_t size ); + +#if defined(MBEDTLS_PEM_WRITE_C) +/** + * \brief Write a public key to a PEM string + * + * \param ctx public key to write away + * \param buf buffer to write to + * \param size size of the buffer + * + * \return 0 if successful, or a specific error code + */ +int mbedtls_pk_write_pubkey_pem( mbedtls_pk_context *ctx, unsigned char *buf, size_t size ); + +/** + * \brief Write a private key to a PKCS#1 or SEC1 PEM string + * + * \param ctx private to write away + * \param buf buffer to write to + * \param size size of the buffer + * + * \return 0 if successful, or a specific error code + */ +int mbedtls_pk_write_key_pem( mbedtls_pk_context *ctx, unsigned char *buf, size_t size ); +#endif /* MBEDTLS_PEM_WRITE_C */ +#endif /* MBEDTLS_PK_WRITE_C */ + +/* + * WARNING: Low-level functions. You probably do not want to use these unless + * you are certain you do ;) + */ + +#if defined(MBEDTLS_PK_PARSE_C) +/** + * \brief Parse a SubjectPublicKeyInfo DER structure + * + * \param p the position in the ASN.1 data + * \param end end of the buffer + * \param pk the key to fill + * + * \return 0 if successful, or a specific PK error code + */ +int mbedtls_pk_parse_subpubkey( unsigned char **p, const unsigned char *end, + mbedtls_pk_context *pk ); +#endif /* MBEDTLS_PK_PARSE_C */ + +#if defined(MBEDTLS_PK_WRITE_C) +/** + * \brief Write a subjectPublicKey to ASN.1 data + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param key public key to write away + * + * \return the length written or a negative error code + */ +int mbedtls_pk_write_pubkey( unsigned char **p, unsigned char *start, + const mbedtls_pk_context *key ); +#endif /* MBEDTLS_PK_WRITE_C */ + +/* + * Internal module functions. You probably do not want to use these unless you + * know you do. + */ +#if defined(MBEDTLS_FS_IO) +int mbedtls_pk_load_file( const char *path, unsigned char **buf, size_t *n ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_PK_H */ diff --git a/common/mbedtls/pk_internal.h b/common/mbedtls/pk_internal.h new file mode 100644 index 00000000..685cd575 --- /dev/null +++ b/common/mbedtls/pk_internal.h @@ -0,0 +1,117 @@ +/** + * \file pk_internal.h + * + * \brief Public Key abstraction layer: wrapper functions + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_PK_WRAP_H +#define MBEDTLS_PK_WRAP_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "pk.h" + +struct mbedtls_pk_info_t +{ + /** Public key type */ + mbedtls_pk_type_t type; + + /** Type name */ + const char *name; + + /** Get key size in bits */ + size_t (*get_bitlen)( const void * ); + + /** Tell if the context implements this type (e.g. ECKEY can do ECDSA) */ + int (*can_do)( mbedtls_pk_type_t type ); + + /** Verify signature */ + int (*verify_func)( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ); + + /** Make signature */ + int (*sign_func)( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + + /** Decrypt message */ + int (*decrypt_func)( void *ctx, const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + + /** Encrypt message */ + int (*encrypt_func)( void *ctx, const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + + /** Check public-private key pair */ + int (*check_pair_func)( const void *pub, const void *prv ); + + /** Allocate a new context */ + void * (*ctx_alloc_func)( void ); + + /** Free the given context */ + void (*ctx_free_func)( void *ctx ); + + /** Interface with the debug module */ + void (*debug_func)( const void *ctx, mbedtls_pk_debug_item *items ); + +}; +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) +/* Container for RSA-alt */ +typedef struct +{ + void *key; + mbedtls_pk_rsa_alt_decrypt_func decrypt_func; + mbedtls_pk_rsa_alt_sign_func sign_func; + mbedtls_pk_rsa_alt_key_len_func key_len_func; +} mbedtls_rsa_alt_context; +#endif + +#if defined(MBEDTLS_RSA_C) +extern const mbedtls_pk_info_t mbedtls_rsa_info; +#endif + +#if defined(MBEDTLS_ECP_C) +extern const mbedtls_pk_info_t mbedtls_eckey_info; +extern const mbedtls_pk_info_t mbedtls_eckeydh_info; +#endif + +#if defined(MBEDTLS_ECDSA_C) +extern const mbedtls_pk_info_t mbedtls_ecdsa_info; +#endif + +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) +extern const mbedtls_pk_info_t mbedtls_rsa_alt_info; +#endif + +#endif /* MBEDTLS_PK_WRAP_H */ diff --git a/common/mbedtls/pk_wrap.c b/common/mbedtls/pk_wrap.c new file mode 100644 index 00000000..7c4275ec --- /dev/null +++ b/common/mbedtls/pk_wrap.c @@ -0,0 +1,525 @@ +/* + * Public Key abstraction layer: wrapper functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PK_C) +#include "mbedtls/pk_internal.h" + +/* Even if RSA not activated, for the sake of RSA-alt */ +#include "mbedtls/rsa.h" + +#include + +#if defined(MBEDTLS_ECP_C) +#include "mbedtls/ecp.h" +#endif + +#if defined(MBEDTLS_ECDSA_C) +#include "mbedtls/ecdsa.h" +#endif + +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) +#include "mbedtls/platform_util.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#include +#include + +#if defined(MBEDTLS_RSA_C) +static int rsa_can_do( mbedtls_pk_type_t type ) +{ + return( type == MBEDTLS_PK_RSA || + type == MBEDTLS_PK_RSASSA_PSS ); +} + +static size_t rsa_get_bitlen( const void *ctx ) +{ + const mbedtls_rsa_context * rsa = (const mbedtls_rsa_context *) ctx; + return( 8 * mbedtls_rsa_get_len( rsa ) ); +} + +static int rsa_verify_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ) +{ + int ret; + mbedtls_rsa_context * rsa = (mbedtls_rsa_context *) ctx; + size_t rsa_len = mbedtls_rsa_get_len( rsa ); + +#if SIZE_MAX > UINT_MAX + if( md_alg == MBEDTLS_MD_NONE && UINT_MAX < hash_len ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); +#endif /* SIZE_MAX > UINT_MAX */ + + if( sig_len < rsa_len ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + if( ( ret = mbedtls_rsa_pkcs1_verify( rsa, NULL, NULL, + MBEDTLS_RSA_PUBLIC, md_alg, + (unsigned int) hash_len, hash, sig ) ) != 0 ) + return( ret ); + + /* The buffer contains a valid signature followed by extra data. + * We have a special error code for that so that so that callers can + * use mbedtls_pk_verify() to check "Does the buffer start with a + * valid signature?" and not just "Does the buffer contain a valid + * signature?". */ + if( sig_len > rsa_len ) + return( MBEDTLS_ERR_PK_SIG_LEN_MISMATCH ); + + return( 0 ); +} + +static int rsa_sign_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + mbedtls_rsa_context * rsa = (mbedtls_rsa_context *) ctx; + +#if SIZE_MAX > UINT_MAX + if( md_alg == MBEDTLS_MD_NONE && UINT_MAX < hash_len ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); +#endif /* SIZE_MAX > UINT_MAX */ + + *sig_len = mbedtls_rsa_get_len( rsa ); + + return( mbedtls_rsa_pkcs1_sign( rsa, f_rng, p_rng, MBEDTLS_RSA_PRIVATE, + md_alg, (unsigned int) hash_len, hash, sig ) ); +} + +static int rsa_decrypt_wrap( void *ctx, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + mbedtls_rsa_context * rsa = (mbedtls_rsa_context *) ctx; + + if( ilen != mbedtls_rsa_get_len( rsa ) ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + return( mbedtls_rsa_pkcs1_decrypt( rsa, f_rng, p_rng, + MBEDTLS_RSA_PRIVATE, olen, input, output, osize ) ); +} + +static int rsa_encrypt_wrap( void *ctx, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + mbedtls_rsa_context * rsa = (mbedtls_rsa_context *) ctx; + *olen = mbedtls_rsa_get_len( rsa ); + + if( *olen > osize ) + return( MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE ); + + return( mbedtls_rsa_pkcs1_encrypt( rsa, f_rng, p_rng, MBEDTLS_RSA_PUBLIC, + ilen, input, output ) ); +} + +static int rsa_check_pair_wrap( const void *pub, const void *prv ) +{ + return( mbedtls_rsa_check_pub_priv( (const mbedtls_rsa_context *) pub, + (const mbedtls_rsa_context *) prv ) ); +} + +static void *rsa_alloc_wrap( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_rsa_context ) ); + + if( ctx != NULL ) + mbedtls_rsa_init( (mbedtls_rsa_context *) ctx, 0, 0 ); + + return( ctx ); +} + +static void rsa_free_wrap( void *ctx ) +{ + mbedtls_rsa_free( (mbedtls_rsa_context *) ctx ); + mbedtls_free( ctx ); +} + +static void rsa_debug( const void *ctx, mbedtls_pk_debug_item *items ) +{ + items->type = MBEDTLS_PK_DEBUG_MPI; + items->name = "rsa.N"; + items->value = &( ((mbedtls_rsa_context *) ctx)->N ); + + items++; + + items->type = MBEDTLS_PK_DEBUG_MPI; + items->name = "rsa.E"; + items->value = &( ((mbedtls_rsa_context *) ctx)->E ); +} + +const mbedtls_pk_info_t mbedtls_rsa_info = { + MBEDTLS_PK_RSA, + "RSA", + rsa_get_bitlen, + rsa_can_do, + rsa_verify_wrap, + rsa_sign_wrap, + rsa_decrypt_wrap, + rsa_encrypt_wrap, + rsa_check_pair_wrap, + rsa_alloc_wrap, + rsa_free_wrap, + rsa_debug, +}; +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_ECP_C) +/* + * Generic EC key + */ +static int eckey_can_do( mbedtls_pk_type_t type ) +{ + return( type == MBEDTLS_PK_ECKEY || + type == MBEDTLS_PK_ECKEY_DH || + type == MBEDTLS_PK_ECDSA ); +} + +static size_t eckey_get_bitlen( const void *ctx ) +{ + return( ((mbedtls_ecp_keypair *) ctx)->grp.pbits ); +} + +#if defined(MBEDTLS_ECDSA_C) +/* Forward declarations */ +static int ecdsa_verify_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ); + +static int ecdsa_sign_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + +static int eckey_verify_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ) +{ + int ret; + mbedtls_ecdsa_context ecdsa; + + mbedtls_ecdsa_init( &ecdsa ); + + if( ( ret = mbedtls_ecdsa_from_keypair( &ecdsa, ctx ) ) == 0 ) + ret = ecdsa_verify_wrap( &ecdsa, md_alg, hash, hash_len, sig, sig_len ); + + mbedtls_ecdsa_free( &ecdsa ); + + return( ret ); +} + +static int eckey_sign_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret; + mbedtls_ecdsa_context ecdsa; + + mbedtls_ecdsa_init( &ecdsa ); + + if( ( ret = mbedtls_ecdsa_from_keypair( &ecdsa, ctx ) ) == 0 ) + ret = ecdsa_sign_wrap( &ecdsa, md_alg, hash, hash_len, sig, sig_len, + f_rng, p_rng ); + + mbedtls_ecdsa_free( &ecdsa ); + + return( ret ); +} + +#endif /* MBEDTLS_ECDSA_C */ + +static int eckey_check_pair( const void *pub, const void *prv ) +{ + return( mbedtls_ecp_check_pub_priv( (const mbedtls_ecp_keypair *) pub, + (const mbedtls_ecp_keypair *) prv ) ); +} + +static void *eckey_alloc_wrap( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_ecp_keypair ) ); + + if( ctx != NULL ) + mbedtls_ecp_keypair_init( ctx ); + + return( ctx ); +} + +static void eckey_free_wrap( void *ctx ) +{ + mbedtls_ecp_keypair_free( (mbedtls_ecp_keypair *) ctx ); + mbedtls_free( ctx ); +} + +static void eckey_debug( const void *ctx, mbedtls_pk_debug_item *items ) +{ + items->type = MBEDTLS_PK_DEBUG_ECP; + items->name = "eckey.Q"; + items->value = &( ((mbedtls_ecp_keypair *) ctx)->Q ); +} + +const mbedtls_pk_info_t mbedtls_eckey_info = { + MBEDTLS_PK_ECKEY, + "EC", + eckey_get_bitlen, + eckey_can_do, +#if defined(MBEDTLS_ECDSA_C) + eckey_verify_wrap, + eckey_sign_wrap, +#else + NULL, + NULL, +#endif + NULL, + NULL, + eckey_check_pair, + eckey_alloc_wrap, + eckey_free_wrap, + eckey_debug, +}; + +/* + * EC key restricted to ECDH + */ +static int eckeydh_can_do( mbedtls_pk_type_t type ) +{ + return( type == MBEDTLS_PK_ECKEY || + type == MBEDTLS_PK_ECKEY_DH ); +} + +const mbedtls_pk_info_t mbedtls_eckeydh_info = { + MBEDTLS_PK_ECKEY_DH, + "EC_DH", + eckey_get_bitlen, /* Same underlying key structure */ + eckeydh_can_do, + NULL, + NULL, + NULL, + NULL, + eckey_check_pair, + eckey_alloc_wrap, /* Same underlying key structure */ + eckey_free_wrap, /* Same underlying key structure */ + eckey_debug, /* Same underlying key structure */ +}; +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_ECDSA_C) +static int ecdsa_can_do( mbedtls_pk_type_t type ) +{ + return( type == MBEDTLS_PK_ECDSA ); +} + +static int ecdsa_verify_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ) +{ + int ret; + ((void) md_alg); + + ret = mbedtls_ecdsa_read_signature( (mbedtls_ecdsa_context *) ctx, + hash, hash_len, sig, sig_len ); + + if( ret == MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH ) + return( MBEDTLS_ERR_PK_SIG_LEN_MISMATCH ); + + return( ret ); +} + +static int ecdsa_sign_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + return( mbedtls_ecdsa_write_signature( (mbedtls_ecdsa_context *) ctx, + md_alg, hash, hash_len, sig, sig_len, f_rng, p_rng ) ); +} + +static void *ecdsa_alloc_wrap( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_ecdsa_context ) ); + + if( ctx != NULL ) + mbedtls_ecdsa_init( (mbedtls_ecdsa_context *) ctx ); + + return( ctx ); +} + +static void ecdsa_free_wrap( void *ctx ) +{ + mbedtls_ecdsa_free( (mbedtls_ecdsa_context *) ctx ); + mbedtls_free( ctx ); +} + +const mbedtls_pk_info_t mbedtls_ecdsa_info = { + MBEDTLS_PK_ECDSA, + "ECDSA", + eckey_get_bitlen, /* Compatible key structures */ + ecdsa_can_do, + ecdsa_verify_wrap, + ecdsa_sign_wrap, + NULL, + NULL, + eckey_check_pair, /* Compatible key structures */ + ecdsa_alloc_wrap, + ecdsa_free_wrap, + eckey_debug, /* Compatible key structures */ +}; +#endif /* MBEDTLS_ECDSA_C */ + +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) +/* + * Support for alternative RSA-private implementations + */ + +static int rsa_alt_can_do( mbedtls_pk_type_t type ) +{ + return( type == MBEDTLS_PK_RSA ); +} + +static size_t rsa_alt_get_bitlen( const void *ctx ) +{ + const mbedtls_rsa_alt_context *rsa_alt = (const mbedtls_rsa_alt_context *) ctx; + + return( 8 * rsa_alt->key_len_func( rsa_alt->key ) ); +} + +static int rsa_alt_sign_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + mbedtls_rsa_alt_context *rsa_alt = (mbedtls_rsa_alt_context *) ctx; + +#if SIZE_MAX > UINT_MAX + if( UINT_MAX < hash_len ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); +#endif /* SIZE_MAX > UINT_MAX */ + + *sig_len = rsa_alt->key_len_func( rsa_alt->key ); + + return( rsa_alt->sign_func( rsa_alt->key, f_rng, p_rng, MBEDTLS_RSA_PRIVATE, + md_alg, (unsigned int) hash_len, hash, sig ) ); +} + +static int rsa_alt_decrypt_wrap( void *ctx, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + mbedtls_rsa_alt_context *rsa_alt = (mbedtls_rsa_alt_context *) ctx; + + ((void) f_rng); + ((void) p_rng); + + if( ilen != rsa_alt->key_len_func( rsa_alt->key ) ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + return( rsa_alt->decrypt_func( rsa_alt->key, + MBEDTLS_RSA_PRIVATE, olen, input, output, osize ) ); +} + +#if defined(MBEDTLS_RSA_C) +static int rsa_alt_check_pair( const void *pub, const void *prv ) +{ + unsigned char sig[MBEDTLS_MPI_MAX_SIZE]; + unsigned char hash[32]; + size_t sig_len = 0; + int ret; + + if( rsa_alt_get_bitlen( prv ) != rsa_get_bitlen( pub ) ) + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + + memset( hash, 0x2a, sizeof( hash ) ); + + if( ( ret = rsa_alt_sign_wrap( (void *) prv, MBEDTLS_MD_NONE, + hash, sizeof( hash ), + sig, &sig_len, NULL, NULL ) ) != 0 ) + { + return( ret ); + } + + if( rsa_verify_wrap( (void *) pub, MBEDTLS_MD_NONE, + hash, sizeof( hash ), sig, sig_len ) != 0 ) + { + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + } + + return( 0 ); +} +#endif /* MBEDTLS_RSA_C */ + +static void *rsa_alt_alloc_wrap( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_rsa_alt_context ) ); + + if( ctx != NULL ) + memset( ctx, 0, sizeof( mbedtls_rsa_alt_context ) ); + + return( ctx ); +} + +static void rsa_alt_free_wrap( void *ctx ) +{ + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_rsa_alt_context ) ); + mbedtls_free( ctx ); +} + +const mbedtls_pk_info_t mbedtls_rsa_alt_info = { + MBEDTLS_PK_RSA_ALT, + "RSA-alt", + rsa_alt_get_bitlen, + rsa_alt_can_do, + NULL, + rsa_alt_sign_wrap, + rsa_alt_decrypt_wrap, + NULL, +#if defined(MBEDTLS_RSA_C) + rsa_alt_check_pair, +#else + NULL, +#endif + rsa_alt_alloc_wrap, + rsa_alt_free_wrap, + NULL, +}; + +#endif /* MBEDTLS_PK_RSA_ALT_SUPPORT */ + +#endif /* MBEDTLS_PK_C */ diff --git a/common/mbedtls/pkcs12.c b/common/mbedtls/pkcs12.c new file mode 100644 index 00000000..3d93bfe9 --- /dev/null +++ b/common/mbedtls/pkcs12.c @@ -0,0 +1,363 @@ +/* + * PKCS#12 Personal Information Exchange Syntax + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The PKCS #12 Personal Information Exchange Syntax Standard v1.1 + * + * http://www.rsa.com/rsalabs/pkcs/files/h11301-wp-pkcs-12v1-1-personal-information-exchange-syntax.pdf + * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12v1-1.asn + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PKCS12_C) + +#include "mbedtls/pkcs12.h" +#include "mbedtls/asn1.h" +#include "mbedtls/cipher.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_ARC4_C) +#include "mbedtls/arc4.h" +#endif + +#if defined(MBEDTLS_DES_C) +#include "mbedtls/des.h" +#endif + +static int pkcs12_parse_pbe_params( mbedtls_asn1_buf *params, + mbedtls_asn1_buf *salt, int *iterations ) +{ + int ret; + unsigned char **p = ¶ms->p; + const unsigned char *end = params->p + params->len; + + /* + * pkcs-12PbeParams ::= SEQUENCE { + * salt OCTET STRING, + * iterations INTEGER + * } + * + */ + if( params->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) + return( MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + if( ( ret = mbedtls_asn1_get_tag( p, end, &salt->len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT + ret ); + + salt->p = *p; + *p += salt->len; + + if( ( ret = mbedtls_asn1_get_int( p, end, iterations ) ) != 0 ) + return( MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT + ret ); + + if( *p != end ) + return( MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +#define PKCS12_MAX_PWDLEN 128 + +static int pkcs12_pbe_derive_key_iv( mbedtls_asn1_buf *pbe_params, mbedtls_md_type_t md_type, + const unsigned char *pwd, size_t pwdlen, + unsigned char *key, size_t keylen, + unsigned char *iv, size_t ivlen ) +{ + int ret, iterations = 0; + mbedtls_asn1_buf salt; + size_t i; + unsigned char unipwd[PKCS12_MAX_PWDLEN * 2 + 2]; + + if( pwdlen > PKCS12_MAX_PWDLEN ) + return( MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA ); + + memset( &salt, 0, sizeof(mbedtls_asn1_buf) ); + memset( &unipwd, 0, sizeof(unipwd) ); + + if( ( ret = pkcs12_parse_pbe_params( pbe_params, &salt, + &iterations ) ) != 0 ) + return( ret ); + + for( i = 0; i < pwdlen; i++ ) + unipwd[i * 2 + 1] = pwd[i]; + + if( ( ret = mbedtls_pkcs12_derivation( key, keylen, unipwd, pwdlen * 2 + 2, + salt.p, salt.len, md_type, + MBEDTLS_PKCS12_DERIVE_KEY, iterations ) ) != 0 ) + { + return( ret ); + } + + if( iv == NULL || ivlen == 0 ) + return( 0 ); + + if( ( ret = mbedtls_pkcs12_derivation( iv, ivlen, unipwd, pwdlen * 2 + 2, + salt.p, salt.len, md_type, + MBEDTLS_PKCS12_DERIVE_IV, iterations ) ) != 0 ) + { + return( ret ); + } + return( 0 ); +} + +#undef PKCS12_MAX_PWDLEN + +int mbedtls_pkcs12_pbe_sha1_rc4_128( mbedtls_asn1_buf *pbe_params, int mode, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *data, size_t len, + unsigned char *output ) +{ +#if !defined(MBEDTLS_ARC4_C) + ((void) pbe_params); + ((void) mode); + ((void) pwd); + ((void) pwdlen); + ((void) data); + ((void) len); + ((void) output); + return( MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE ); +#else + int ret; + unsigned char key[16]; + mbedtls_arc4_context ctx; + ((void) mode); + + mbedtls_arc4_init( &ctx ); + + if( ( ret = pkcs12_pbe_derive_key_iv( pbe_params, MBEDTLS_MD_SHA1, + pwd, pwdlen, + key, 16, NULL, 0 ) ) != 0 ) + { + return( ret ); + } + + mbedtls_arc4_setup( &ctx, key, 16 ); + if( ( ret = mbedtls_arc4_crypt( &ctx, len, data, output ) ) != 0 ) + goto exit; + +exit: + mbedtls_platform_zeroize( key, sizeof( key ) ); + mbedtls_arc4_free( &ctx ); + + return( ret ); +#endif /* MBEDTLS_ARC4_C */ +} + +int mbedtls_pkcs12_pbe( mbedtls_asn1_buf *pbe_params, int mode, + mbedtls_cipher_type_t cipher_type, mbedtls_md_type_t md_type, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *data, size_t len, + unsigned char *output ) +{ + int ret, keylen = 0; + unsigned char key[32]; + unsigned char iv[16]; + const mbedtls_cipher_info_t *cipher_info; + mbedtls_cipher_context_t cipher_ctx; + size_t olen = 0; + + cipher_info = mbedtls_cipher_info_from_type( cipher_type ); + if( cipher_info == NULL ) + return( MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE ); + + keylen = cipher_info->key_bitlen / 8; + + if( ( ret = pkcs12_pbe_derive_key_iv( pbe_params, md_type, pwd, pwdlen, + key, keylen, + iv, cipher_info->iv_size ) ) != 0 ) + { + return( ret ); + } + + mbedtls_cipher_init( &cipher_ctx ); + + if( ( ret = mbedtls_cipher_setup( &cipher_ctx, cipher_info ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_cipher_setkey( &cipher_ctx, key, 8 * keylen, (mbedtls_operation_t) mode ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_cipher_set_iv( &cipher_ctx, iv, cipher_info->iv_size ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_cipher_reset( &cipher_ctx ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_cipher_update( &cipher_ctx, data, len, + output, &olen ) ) != 0 ) + { + goto exit; + } + + if( ( ret = mbedtls_cipher_finish( &cipher_ctx, output + olen, &olen ) ) != 0 ) + ret = MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH; + +exit: + mbedtls_platform_zeroize( key, sizeof( key ) ); + mbedtls_platform_zeroize( iv, sizeof( iv ) ); + mbedtls_cipher_free( &cipher_ctx ); + + return( ret ); +} + +static void pkcs12_fill_buffer( unsigned char *data, size_t data_len, + const unsigned char *filler, size_t fill_len ) +{ + unsigned char *p = data; + size_t use_len; + + while( data_len > 0 ) + { + use_len = ( data_len > fill_len ) ? fill_len : data_len; + memcpy( p, filler, use_len ); + p += use_len; + data_len -= use_len; + } +} + +int mbedtls_pkcs12_derivation( unsigned char *data, size_t datalen, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *salt, size_t saltlen, + mbedtls_md_type_t md_type, int id, int iterations ) +{ + int ret; + unsigned int j; + + unsigned char diversifier[128]; + unsigned char salt_block[128], pwd_block[128], hash_block[128]; + unsigned char hash_output[MBEDTLS_MD_MAX_SIZE]; + unsigned char *p; + unsigned char c; + + size_t hlen, use_len, v, i; + + const mbedtls_md_info_t *md_info; + mbedtls_md_context_t md_ctx; + + // This version only allows max of 64 bytes of password or salt + if( datalen > 128 || pwdlen > 64 || saltlen > 64 ) + return( MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA ); + + md_info = mbedtls_md_info_from_type( md_type ); + if( md_info == NULL ) + return( MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE ); + + mbedtls_md_init( &md_ctx ); + + if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 0 ) ) != 0 ) + return( ret ); + hlen = mbedtls_md_get_size( md_info ); + + if( hlen <= 32 ) + v = 64; + else + v = 128; + + memset( diversifier, (unsigned char) id, v ); + + pkcs12_fill_buffer( salt_block, v, salt, saltlen ); + pkcs12_fill_buffer( pwd_block, v, pwd, pwdlen ); + + p = data; + while( datalen > 0 ) + { + // Calculate hash( diversifier || salt_block || pwd_block ) + if( ( ret = mbedtls_md_starts( &md_ctx ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_md_update( &md_ctx, diversifier, v ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_md_update( &md_ctx, salt_block, v ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_md_update( &md_ctx, pwd_block, v ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_md_finish( &md_ctx, hash_output ) ) != 0 ) + goto exit; + + // Perform remaining ( iterations - 1 ) recursive hash calculations + for( i = 1; i < (size_t) iterations; i++ ) + { + if( ( ret = mbedtls_md( md_info, hash_output, hlen, hash_output ) ) != 0 ) + goto exit; + } + + use_len = ( datalen > hlen ) ? hlen : datalen; + memcpy( p, hash_output, use_len ); + datalen -= use_len; + p += use_len; + + if( datalen == 0 ) + break; + + // Concatenating copies of hash_output into hash_block (B) + pkcs12_fill_buffer( hash_block, v, hash_output, hlen ); + + // B += 1 + for( i = v; i > 0; i-- ) + if( ++hash_block[i - 1] != 0 ) + break; + + // salt_block += B + c = 0; + for( i = v; i > 0; i-- ) + { + j = salt_block[i - 1] + hash_block[i - 1] + c; + c = (unsigned char) (j >> 8); + salt_block[i - 1] = j & 0xFF; + } + + // pwd_block += B + c = 0; + for( i = v; i > 0; i-- ) + { + j = pwd_block[i - 1] + hash_block[i - 1] + c; + c = (unsigned char) (j >> 8); + pwd_block[i - 1] = j & 0xFF; + } + } + + ret = 0; + +exit: + mbedtls_platform_zeroize( salt_block, sizeof( salt_block ) ); + mbedtls_platform_zeroize( pwd_block, sizeof( pwd_block ) ); + mbedtls_platform_zeroize( hash_block, sizeof( hash_block ) ); + mbedtls_platform_zeroize( hash_output, sizeof( hash_output ) ); + + mbedtls_md_free( &md_ctx ); + + return( ret ); +} + +#endif /* MBEDTLS_PKCS12_C */ diff --git a/common/mbedtls/pkcs12.h b/common/mbedtls/pkcs12.h new file mode 100644 index 00000000..f2230fa9 --- /dev/null +++ b/common/mbedtls/pkcs12.h @@ -0,0 +1,122 @@ +/** + * \file pkcs12.h + * + * \brief PKCS#12 Personal Information Exchange Syntax + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_PKCS12_H +#define MBEDTLS_PKCS12_H + +#include "md.h" +#include "cipher.h" +#include "asn1.h" + +#include + +#define MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA -0x1F80 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE -0x1F00 /**< Feature not available, e.g. unsupported encryption scheme. */ +#define MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT -0x1E80 /**< PBE ASN.1 data not as expected. */ +#define MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH -0x1E00 /**< Given private key password does not allow for correct decryption. */ + +#define MBEDTLS_PKCS12_DERIVE_KEY 1 /**< encryption/decryption key */ +#define MBEDTLS_PKCS12_DERIVE_IV 2 /**< initialization vector */ +#define MBEDTLS_PKCS12_DERIVE_MAC_KEY 3 /**< integrity / MAC key */ + +#define MBEDTLS_PKCS12_PBE_DECRYPT 0 +#define MBEDTLS_PKCS12_PBE_ENCRYPT 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief PKCS12 Password Based function (encryption / decryption) + * for pbeWithSHAAnd128BitRC4 + * + * \param pbe_params an ASN1 buffer containing the pkcs-12PbeParams structure + * \param mode either MBEDTLS_PKCS12_PBE_ENCRYPT or MBEDTLS_PKCS12_PBE_DECRYPT + * \param pwd the password used (may be NULL if no password is used) + * \param pwdlen length of the password (may be 0) + * \param input the input data + * \param len data length + * \param output the output buffer + * + * \return 0 if successful, or a MBEDTLS_ERR_XXX code + */ +int mbedtls_pkcs12_pbe_sha1_rc4_128( mbedtls_asn1_buf *pbe_params, int mode, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *input, size_t len, + unsigned char *output ); + +/** + * \brief PKCS12 Password Based function (encryption / decryption) + * for cipher-based and mbedtls_md-based PBE's + * + * \param pbe_params an ASN1 buffer containing the pkcs-12PbeParams structure + * \param mode either MBEDTLS_PKCS12_PBE_ENCRYPT or MBEDTLS_PKCS12_PBE_DECRYPT + * \param cipher_type the cipher used + * \param md_type the mbedtls_md used + * \param pwd the password used (may be NULL if no password is used) + * \param pwdlen length of the password (may be 0) + * \param input the input data + * \param len data length + * \param output the output buffer + * + * \return 0 if successful, or a MBEDTLS_ERR_XXX code + */ +int mbedtls_pkcs12_pbe( mbedtls_asn1_buf *pbe_params, int mode, + mbedtls_cipher_type_t cipher_type, mbedtls_md_type_t md_type, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *input, size_t len, + unsigned char *output ); + +/** + * \brief The PKCS#12 derivation function uses a password and a salt + * to produce pseudo-random bits for a particular "purpose". + * + * Depending on the given id, this function can produce an + * encryption/decryption key, an nitialization vector or an + * integrity key. + * + * \param data buffer to store the derived data in + * \param datalen length to fill + * \param pwd password to use (may be NULL if no password is used) + * \param pwdlen length of the password (may be 0) + * \param salt salt buffer to use + * \param saltlen length of the salt + * \param mbedtls_md mbedtls_md type to use during the derivation + * \param id id that describes the purpose (can be MBEDTLS_PKCS12_DERIVE_KEY, + * MBEDTLS_PKCS12_DERIVE_IV or MBEDTLS_PKCS12_DERIVE_MAC_KEY) + * \param iterations number of iterations + * + * \return 0 if successful, or a MD, BIGNUM type error. + */ +int mbedtls_pkcs12_derivation( unsigned char *data, size_t datalen, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *salt, size_t saltlen, + mbedtls_md_type_t mbedtls_md, int id, int iterations ); + +#ifdef __cplusplus +} +#endif + +#endif /* pkcs12.h */ diff --git a/common/mbedtls/pkcs5.c b/common/mbedtls/pkcs5.c new file mode 100644 index 00000000..e62d663d --- /dev/null +++ b/common/mbedtls/pkcs5.c @@ -0,0 +1,428 @@ +/** + * \file pkcs5.c + * + * \brief PKCS#5 functions + * + * \author Mathias Olsson + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * PKCS#5 includes PBKDF2 and more + * + * http://tools.ietf.org/html/rfc2898 (Specification) + * http://tools.ietf.org/html/rfc6070 (Test vectors) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PKCS5_C) + +#include "mbedtls/pkcs5.h" + +#if defined(MBEDTLS_ASN1_PARSE_C) +#include "mbedtls/asn1.h" +#include "mbedtls/cipher.h" +#include "mbedtls/oid.h" +#endif /* MBEDTLS_ASN1_PARSE_C */ + +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif + +#if !defined(MBEDTLS_ASN1_PARSE_C) +int mbedtls_pkcs5_pbes2( const mbedtls_asn1_buf *pbe_params, int mode, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *data, size_t datalen, + unsigned char *output ) +{ + ((void) pbe_params); + ((void) mode); + ((void) pwd); + ((void) pwdlen); + ((void) data); + ((void) datalen); + ((void) output); + return( MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE ); +} +#else +static int pkcs5_parse_pbkdf2_params( const mbedtls_asn1_buf *params, + mbedtls_asn1_buf *salt, int *iterations, + int *keylen, mbedtls_md_type_t *md_type ) +{ + int ret; + mbedtls_asn1_buf prf_alg_oid; + unsigned char *p = params->p; + const unsigned char *end = params->p + params->len; + + if( params->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + /* + * PBKDF2-params ::= SEQUENCE { + * salt OCTET STRING, + * iterationCount INTEGER, + * keyLength INTEGER OPTIONAL + * prf AlgorithmIdentifier DEFAULT algid-hmacWithSHA1 + * } + * + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &salt->len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret ); + + salt->p = p; + p += salt->len; + + if( ( ret = mbedtls_asn1_get_int( &p, end, iterations ) ) != 0 ) + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret ); + + if( p == end ) + return( 0 ); + + if( ( ret = mbedtls_asn1_get_int( &p, end, keylen ) ) != 0 ) + { + if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret ); + } + + if( p == end ) + return( 0 ); + + if( ( ret = mbedtls_asn1_get_alg_null( &p, end, &prf_alg_oid ) ) != 0 ) + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret ); + + if( mbedtls_oid_get_md_hmac( &prf_alg_oid, md_type ) != 0 ) + return( MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE ); + + if( p != end ) + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +int mbedtls_pkcs5_pbes2( const mbedtls_asn1_buf *pbe_params, int mode, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *data, size_t datalen, + unsigned char *output ) +{ + int ret, iterations = 0, keylen = 0; + unsigned char *p, *end; + mbedtls_asn1_buf kdf_alg_oid, enc_scheme_oid, kdf_alg_params, enc_scheme_params; + mbedtls_asn1_buf salt; + mbedtls_md_type_t md_type = MBEDTLS_MD_SHA1; + unsigned char key[32], iv[32]; + size_t olen = 0; + const mbedtls_md_info_t *md_info; + const mbedtls_cipher_info_t *cipher_info; + mbedtls_md_context_t md_ctx; + mbedtls_cipher_type_t cipher_alg; + mbedtls_cipher_context_t cipher_ctx; + + p = pbe_params->p; + end = p + pbe_params->len; + + /* + * PBES2-params ::= SEQUENCE { + * keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}}, + * encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} + * } + */ + if( pbe_params->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + if( ( ret = mbedtls_asn1_get_alg( &p, end, &kdf_alg_oid, &kdf_alg_params ) ) != 0 ) + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret ); + + // Only PBKDF2 supported at the moment + // + if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS5_PBKDF2, &kdf_alg_oid ) != 0 ) + return( MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE ); + + if( ( ret = pkcs5_parse_pbkdf2_params( &kdf_alg_params, + &salt, &iterations, &keylen, + &md_type ) ) != 0 ) + { + return( ret ); + } + + md_info = mbedtls_md_info_from_type( md_type ); + if( md_info == NULL ) + return( MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE ); + + if( ( ret = mbedtls_asn1_get_alg( &p, end, &enc_scheme_oid, + &enc_scheme_params ) ) != 0 ) + { + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret ); + } + + if( mbedtls_oid_get_cipher_alg( &enc_scheme_oid, &cipher_alg ) != 0 ) + return( MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE ); + + cipher_info = mbedtls_cipher_info_from_type( cipher_alg ); + if( cipher_info == NULL ) + return( MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE ); + + /* + * The value of keylen from pkcs5_parse_pbkdf2_params() is ignored + * since it is optional and we don't know if it was set or not + */ + keylen = cipher_info->key_bitlen / 8; + + if( enc_scheme_params.tag != MBEDTLS_ASN1_OCTET_STRING || + enc_scheme_params.len != cipher_info->iv_size ) + { + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT ); + } + + mbedtls_md_init( &md_ctx ); + mbedtls_cipher_init( &cipher_ctx ); + + memcpy( iv, enc_scheme_params.p, enc_scheme_params.len ); + + if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 1 ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_pkcs5_pbkdf2_hmac( &md_ctx, pwd, pwdlen, salt.p, salt.len, + iterations, keylen, key ) ) != 0 ) + { + goto exit; + } + + if( ( ret = mbedtls_cipher_setup( &cipher_ctx, cipher_info ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_cipher_setkey( &cipher_ctx, key, 8 * keylen, (mbedtls_operation_t) mode ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_cipher_crypt( &cipher_ctx, iv, enc_scheme_params.len, + data, datalen, output, &olen ) ) != 0 ) + ret = MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH; + +exit: + mbedtls_md_free( &md_ctx ); + mbedtls_cipher_free( &cipher_ctx ); + + return( ret ); +} +#endif /* MBEDTLS_ASN1_PARSE_C */ + +int mbedtls_pkcs5_pbkdf2_hmac( mbedtls_md_context_t *ctx, const unsigned char *password, + size_t plen, const unsigned char *salt, size_t slen, + unsigned int iteration_count, + uint32_t key_length, unsigned char *output ) +{ + int ret, j; + unsigned int i; + unsigned char md1[MBEDTLS_MD_MAX_SIZE]; + unsigned char work[MBEDTLS_MD_MAX_SIZE]; + unsigned char md_size = mbedtls_md_get_size( ctx->md_info ); + size_t use_len; + unsigned char *out_p = output; + unsigned char counter[4]; + + memset( counter, 0, 4 ); + counter[3] = 1; + +#if UINT_MAX > 0xFFFFFFFF + if( iteration_count > 0xFFFFFFFF ) + return( MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA ); +#endif + + while( key_length ) + { + // U1 ends up in work + // + if( ( ret = mbedtls_md_hmac_starts( ctx, password, plen ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_md_hmac_update( ctx, salt, slen ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_md_hmac_update( ctx, counter, 4 ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_md_hmac_finish( ctx, work ) ) != 0 ) + return( ret ); + + memcpy( md1, work, md_size ); + + for( i = 1; i < iteration_count; i++ ) + { + // U2 ends up in md1 + // + if( ( ret = mbedtls_md_hmac_starts( ctx, password, plen ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_md_hmac_update( ctx, md1, md_size ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_md_hmac_finish( ctx, md1 ) ) != 0 ) + return( ret ); + + // U1 xor U2 + // + for( j = 0; j < md_size; j++ ) + work[j] ^= md1[j]; + } + + use_len = ( key_length < md_size ) ? key_length : md_size; + memcpy( out_p, work, use_len ); + + key_length -= (uint32_t) use_len; + out_p += use_len; + + for( i = 4; i > 0; i-- ) + if( ++counter[i - 1] != 0 ) + break; + } + + return( 0 ); +} + +#if defined(MBEDTLS_SELF_TEST) + +#if !defined(MBEDTLS_SHA1_C) +int mbedtls_pkcs5_self_test( int verbose ) +{ + if( verbose != 0 ) + mbedtls_printf( " PBKDF2 (SHA1): skipped\n\n" ); + + return( 0 ); +} +#else + +#define MAX_TESTS 6 + +static const size_t plen[MAX_TESTS] = + { 8, 8, 8, 24, 9 }; + +static const unsigned char password[MAX_TESTS][32] = +{ + "password", + "password", + "password", + "passwordPASSWORDpassword", + "pass\0word", +}; + +static const size_t slen[MAX_TESTS] = + { 4, 4, 4, 36, 5 }; + +static const unsigned char salt[MAX_TESTS][40] = +{ + "salt", + "salt", + "salt", + "saltSALTsaltSALTsaltSALTsaltSALTsalt", + "sa\0lt", +}; + +static const uint32_t it_cnt[MAX_TESTS] = + { 1, 2, 4096, 4096, 4096 }; + +static const uint32_t key_len[MAX_TESTS] = + { 20, 20, 20, 25, 16 }; + +static const unsigned char result_key[MAX_TESTS][32] = +{ + { 0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e, 0x71, + 0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60, 0x12, 0x06, + 0x2f, 0xe0, 0x37, 0xa6 }, + { 0xea, 0x6c, 0x01, 0x4d, 0xc7, 0x2d, 0x6f, 0x8c, + 0xcd, 0x1e, 0xd9, 0x2a, 0xce, 0x1d, 0x41, 0xf0, + 0xd8, 0xde, 0x89, 0x57 }, + { 0x4b, 0x00, 0x79, 0x01, 0xb7, 0x65, 0x48, 0x9a, + 0xbe, 0xad, 0x49, 0xd9, 0x26, 0xf7, 0x21, 0xd0, + 0x65, 0xa4, 0x29, 0xc1 }, + { 0x3d, 0x2e, 0xec, 0x4f, 0xe4, 0x1c, 0x84, 0x9b, + 0x80, 0xc8, 0xd8, 0x36, 0x62, 0xc0, 0xe4, 0x4a, + 0x8b, 0x29, 0x1a, 0x96, 0x4c, 0xf2, 0xf0, 0x70, + 0x38 }, + { 0x56, 0xfa, 0x6a, 0xa7, 0x55, 0x48, 0x09, 0x9d, + 0xcc, 0x37, 0xd7, 0xf0, 0x34, 0x25, 0xe0, 0xc3 }, +}; + +int mbedtls_pkcs5_self_test( int verbose ) +{ + mbedtls_md_context_t sha1_ctx; + const mbedtls_md_info_t *info_sha1; + int ret, i; + unsigned char key[64]; + + mbedtls_md_init( &sha1_ctx ); + + info_sha1 = mbedtls_md_info_from_type( MBEDTLS_MD_SHA1 ); + if( info_sha1 == NULL ) + { + ret = 1; + goto exit; + } + + if( ( ret = mbedtls_md_setup( &sha1_ctx, info_sha1, 1 ) ) != 0 ) + { + ret = 1; + goto exit; + } + + for( i = 0; i < MAX_TESTS; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " PBKDF2 (SHA1) #%d: ", i ); + + ret = mbedtls_pkcs5_pbkdf2_hmac( &sha1_ctx, password[i], plen[i], salt[i], + slen[i], it_cnt[i], key_len[i], key ); + if( ret != 0 || + memcmp( result_key[i], key, key_len[i] ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +exit: + mbedtls_md_free( &sha1_ctx ); + + return( ret ); +} +#endif /* MBEDTLS_SHA1_C */ + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_PKCS5_C */ diff --git a/common/mbedtls/pkcs5.h b/common/mbedtls/pkcs5.h new file mode 100644 index 00000000..7b6acf58 --- /dev/null +++ b/common/mbedtls/pkcs5.h @@ -0,0 +1,97 @@ +/** + * \file pkcs5.h + * + * \brief PKCS#5 functions + * + * \author Mathias Olsson + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_PKCS5_H +#define MBEDTLS_PKCS5_H + +#include "asn1.h" +#include "md.h" + +#include +#include + +#define MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA -0x2f80 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_PKCS5_INVALID_FORMAT -0x2f00 /**< Unexpected ASN.1 data. */ +#define MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE -0x2e80 /**< Requested encryption or digest alg not available. */ +#define MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH -0x2e00 /**< Given private key password does not allow for correct decryption. */ + +#define MBEDTLS_PKCS5_DECRYPT 0 +#define MBEDTLS_PKCS5_ENCRYPT 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief PKCS#5 PBES2 function + * + * \param pbe_params the ASN.1 algorithm parameters + * \param mode either MBEDTLS_PKCS5_DECRYPT or MBEDTLS_PKCS5_ENCRYPT + * \param pwd password to use when generating key + * \param pwdlen length of password + * \param data data to process + * \param datalen length of data + * \param output output buffer + * + * \returns 0 on success, or a MBEDTLS_ERR_XXX code if verification fails. + */ +int mbedtls_pkcs5_pbes2( const mbedtls_asn1_buf *pbe_params, int mode, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *data, size_t datalen, + unsigned char *output ); + +/** + * \brief PKCS#5 PBKDF2 using HMAC + * + * \param ctx Generic HMAC context + * \param password Password to use when generating key + * \param plen Length of password + * \param salt Salt to use when generating key + * \param slen Length of salt + * \param iteration_count Iteration count + * \param key_length Length of generated key in bytes + * \param output Generated key. Must be at least as big as key_length + * + * \returns 0 on success, or a MBEDTLS_ERR_XXX code if verification fails. + */ +int mbedtls_pkcs5_pbkdf2_hmac( mbedtls_md_context_t *ctx, const unsigned char *password, + size_t plen, const unsigned char *salt, size_t slen, + unsigned int iteration_count, + uint32_t key_length, unsigned char *output ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_pkcs5_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* pkcs5.h */ diff --git a/common/mbedtls/pkparse.c b/common/mbedtls/pkparse.c new file mode 100644 index 00000000..a687076b --- /dev/null +++ b/common/mbedtls/pkparse.c @@ -0,0 +1,1449 @@ +/* + * Public Key layer for parsing key files and structures + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PK_PARSE_C) + +#include "mbedtls/pk.h" +#include "mbedtls/asn1.h" +#include "mbedtls/oid.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_RSA_C) +#include "mbedtls/rsa.h" +#endif +#if defined(MBEDTLS_ECP_C) +#include "mbedtls/ecp.h" +#endif +#if defined(MBEDTLS_ECDSA_C) +#include "mbedtls/ecdsa.h" +#endif +#if defined(MBEDTLS_PEM_PARSE_C) +#include "mbedtls/pem.h" +#endif +#if defined(MBEDTLS_PKCS5_C) +#include "mbedtls/pkcs5.h" +#endif +#if defined(MBEDTLS_PKCS12_C) +#include "mbedtls/pkcs12.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#if defined(MBEDTLS_FS_IO) +/* + * Load all data from a file into a given buffer. + * + * The file is expected to contain either PEM or DER encoded data. + * A terminating null byte is always appended. It is included in the announced + * length only if the data looks like it is PEM encoded. + */ +int mbedtls_pk_load_file( const char *path, unsigned char **buf, size_t *n ) +{ + FILE *f; + long size; + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( MBEDTLS_ERR_PK_FILE_IO_ERROR ); + + fseek( f, 0, SEEK_END ); + if( ( size = ftell( f ) ) == -1 ) + { + fclose( f ); + return( MBEDTLS_ERR_PK_FILE_IO_ERROR ); + } + fseek( f, 0, SEEK_SET ); + + *n = (size_t) size; + + if( *n + 1 == 0 || + ( *buf = mbedtls_calloc( 1, *n + 1 ) ) == NULL ) + { + fclose( f ); + return( MBEDTLS_ERR_PK_ALLOC_FAILED ); + } + + if( fread( *buf, 1, *n, f ) != *n ) + { + fclose( f ); + + mbedtls_platform_zeroize( *buf, *n ); + mbedtls_free( *buf ); + + return( MBEDTLS_ERR_PK_FILE_IO_ERROR ); + } + + fclose( f ); + + (*buf)[*n] = '\0'; + + if( strstr( (const char *) *buf, "-----BEGIN " ) != NULL ) + ++*n; + + return( 0 ); +} + +/* + * Load and parse a private key + */ +int mbedtls_pk_parse_keyfile( mbedtls_pk_context *ctx, + const char *path, const char *pwd ) +{ + int ret; + size_t n; + unsigned char *buf; + + if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + if( pwd == NULL ) + ret = mbedtls_pk_parse_key( ctx, buf, n, NULL, 0 ); + else + ret = mbedtls_pk_parse_key( ctx, buf, n, + (const unsigned char *) pwd, strlen( pwd ) ); + + mbedtls_platform_zeroize( buf, n ); + mbedtls_free( buf ); + + return( ret ); +} + +/* + * Load and parse a public key + */ +int mbedtls_pk_parse_public_keyfile( mbedtls_pk_context *ctx, const char *path ) +{ + int ret; + size_t n; + unsigned char *buf; + + if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + ret = mbedtls_pk_parse_public_key( ctx, buf, n ); + + mbedtls_platform_zeroize( buf, n ); + mbedtls_free( buf ); + + return( ret ); +} +#endif /* MBEDTLS_FS_IO */ + +#if defined(MBEDTLS_ECP_C) +/* Minimally parse an ECParameters buffer to and mbedtls_asn1_buf + * + * ECParameters ::= CHOICE { + * namedCurve OBJECT IDENTIFIER + * specifiedCurve SpecifiedECDomain -- = SEQUENCE { ... } + * -- implicitCurve NULL + * } + */ +static int pk_get_ecparams( unsigned char **p, const unsigned char *end, + mbedtls_asn1_buf *params ) +{ + int ret; + + if ( end - *p < 1 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + /* Tag may be either OID or SEQUENCE */ + params->tag = **p; + if( params->tag != MBEDTLS_ASN1_OID +#if defined(MBEDTLS_PK_PARSE_EC_EXTENDED) + && params->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) +#endif + ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + } + + if( ( ret = mbedtls_asn1_get_tag( p, end, ¶ms->len, params->tag ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + params->p = *p; + *p += params->len; + + if( *p != end ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +#if defined(MBEDTLS_PK_PARSE_EC_EXTENDED) +/* + * Parse a SpecifiedECDomain (SEC 1 C.2) and (mostly) fill the group with it. + * WARNING: the resulting group should only be used with + * pk_group_id_from_specified(), since its base point may not be set correctly + * if it was encoded compressed. + * + * SpecifiedECDomain ::= SEQUENCE { + * version SpecifiedECDomainVersion(ecdpVer1 | ecdpVer2 | ecdpVer3, ...), + * fieldID FieldID {{FieldTypes}}, + * curve Curve, + * base ECPoint, + * order INTEGER, + * cofactor INTEGER OPTIONAL, + * hash HashAlgorithm OPTIONAL, + * ... + * } + * + * We only support prime-field as field type, and ignore hash and cofactor. + */ +static int pk_group_from_specified( const mbedtls_asn1_buf *params, mbedtls_ecp_group *grp ) +{ + int ret; + unsigned char *p = params->p; + const unsigned char * const end = params->p + params->len; + const unsigned char *end_field, *end_curve; + size_t len; + int ver; + + /* SpecifiedECDomainVersion ::= INTEGER { 1, 2, 3 } */ + if( ( ret = mbedtls_asn1_get_int( &p, end, &ver ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( ver < 1 || ver > 3 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); + + /* + * FieldID { FIELD-ID:IOSet } ::= SEQUENCE { -- Finite field + * fieldType FIELD-ID.&id({IOSet}), + * parameters FIELD-ID.&Type({IOSet}{@fieldType}) + * } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( ret ); + + end_field = p + len; + + /* + * FIELD-ID ::= TYPE-IDENTIFIER + * FieldTypes FIELD-ID ::= { + * { Prime-p IDENTIFIED BY prime-field } | + * { Characteristic-two IDENTIFIED BY characteristic-two-field } + * } + * prime-field OBJECT IDENTIFIER ::= { id-fieldType 1 } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end_field, &len, MBEDTLS_ASN1_OID ) ) != 0 ) + return( ret ); + + if( len != MBEDTLS_OID_SIZE( MBEDTLS_OID_ANSI_X9_62_PRIME_FIELD ) || + memcmp( p, MBEDTLS_OID_ANSI_X9_62_PRIME_FIELD, len ) != 0 ) + { + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); + } + + p += len; + + /* Prime-p ::= INTEGER -- Field of size p. */ + if( ( ret = mbedtls_asn1_get_mpi( &p, end_field, &grp->P ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + grp->pbits = mbedtls_mpi_bitlen( &grp->P ); + + if( p != end_field ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + /* + * Curve ::= SEQUENCE { + * a FieldElement, + * b FieldElement, + * seed BIT STRING OPTIONAL + * -- Shall be present if used in SpecifiedECDomain + * -- with version equal to ecdpVer2 or ecdpVer3 + * } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( ret ); + + end_curve = p + len; + + /* + * FieldElement ::= OCTET STRING + * containing an integer in the case of a prime field + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end_curve, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 || + ( ret = mbedtls_mpi_read_binary( &grp->A, p, len ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + p += len; + + if( ( ret = mbedtls_asn1_get_tag( &p, end_curve, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 || + ( ret = mbedtls_mpi_read_binary( &grp->B, p, len ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + p += len; + + /* Ignore seed BIT STRING OPTIONAL */ + if( ( ret = mbedtls_asn1_get_tag( &p, end_curve, &len, MBEDTLS_ASN1_BIT_STRING ) ) == 0 ) + p += len; + + if( p != end_curve ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + /* + * ECPoint ::= OCTET STRING + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( ( ret = mbedtls_ecp_point_read_binary( grp, &grp->G, + ( const unsigned char *) p, len ) ) != 0 ) + { + /* + * If we can't read the point because it's compressed, cheat by + * reading only the X coordinate and the parity bit of Y. + */ + if( ret != MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE || + ( p[0] != 0x02 && p[0] != 0x03 ) || + len != mbedtls_mpi_size( &grp->P ) + 1 || + mbedtls_mpi_read_binary( &grp->G.X, p + 1, len - 1 ) != 0 || + mbedtls_mpi_lset( &grp->G.Y, p[0] - 2 ) != 0 || + mbedtls_mpi_lset( &grp->G.Z, 1 ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); + } + } + + p += len; + + /* + * order INTEGER + */ + if( ( ret = mbedtls_asn1_get_mpi( &p, end, &grp->N ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + grp->nbits = mbedtls_mpi_bitlen( &grp->N ); + + /* + * Allow optional elements by purposefully not enforcing p == end here. + */ + + return( 0 ); +} + +/* + * Find the group id associated with an (almost filled) group as generated by + * pk_group_from_specified(), or return an error if unknown. + */ +static int pk_group_id_from_group( const mbedtls_ecp_group *grp, mbedtls_ecp_group_id *grp_id ) +{ + int ret = 0; + mbedtls_ecp_group ref; + const mbedtls_ecp_group_id *id; + + mbedtls_ecp_group_init( &ref ); + + for( id = mbedtls_ecp_grp_id_list(); *id != MBEDTLS_ECP_DP_NONE; id++ ) + { + /* Load the group associated to that id */ + mbedtls_ecp_group_free( &ref ); + MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &ref, *id ) ); + + /* Compare to the group we were given, starting with easy tests */ + if( grp->pbits == ref.pbits && grp->nbits == ref.nbits && + mbedtls_mpi_cmp_mpi( &grp->P, &ref.P ) == 0 && + mbedtls_mpi_cmp_mpi( &grp->A, &ref.A ) == 0 && + mbedtls_mpi_cmp_mpi( &grp->B, &ref.B ) == 0 && + mbedtls_mpi_cmp_mpi( &grp->N, &ref.N ) == 0 && + mbedtls_mpi_cmp_mpi( &grp->G.X, &ref.G.X ) == 0 && + mbedtls_mpi_cmp_mpi( &grp->G.Z, &ref.G.Z ) == 0 && + /* For Y we may only know the parity bit, so compare only that */ + mbedtls_mpi_get_bit( &grp->G.Y, 0 ) == mbedtls_mpi_get_bit( &ref.G.Y, 0 ) ) + { + break; + } + + } + +cleanup: + mbedtls_ecp_group_free( &ref ); + + *grp_id = *id; + + if( ret == 0 && *id == MBEDTLS_ECP_DP_NONE ) + ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; + + return( ret ); +} + +/* + * Parse a SpecifiedECDomain (SEC 1 C.2) and find the associated group ID + */ +static int pk_group_id_from_specified( const mbedtls_asn1_buf *params, + mbedtls_ecp_group_id *grp_id ) +{ + int ret; + mbedtls_ecp_group grp; + + mbedtls_ecp_group_init( &grp ); + + if( ( ret = pk_group_from_specified( params, &grp ) ) != 0 ) + goto cleanup; + + ret = pk_group_id_from_group( &grp, grp_id ); + +cleanup: + mbedtls_ecp_group_free( &grp ); + + return( ret ); +} +#endif /* MBEDTLS_PK_PARSE_EC_EXTENDED */ + +/* + * Use EC parameters to initialise an EC group + * + * ECParameters ::= CHOICE { + * namedCurve OBJECT IDENTIFIER + * specifiedCurve SpecifiedECDomain -- = SEQUENCE { ... } + * -- implicitCurve NULL + */ +static int pk_use_ecparams( const mbedtls_asn1_buf *params, mbedtls_ecp_group *grp ) +{ + int ret; + mbedtls_ecp_group_id grp_id; + + if( params->tag == MBEDTLS_ASN1_OID ) + { + if( mbedtls_oid_get_ec_grp( params, &grp_id ) != 0 ) + return( MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE ); + } + else + { +#if defined(MBEDTLS_PK_PARSE_EC_EXTENDED) + if( ( ret = pk_group_id_from_specified( params, &grp_id ) ) != 0 ) + return( ret ); +#else + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); +#endif + } + + /* + * grp may already be initilialized; if so, make sure IDs match + */ + if( grp->id != MBEDTLS_ECP_DP_NONE && grp->id != grp_id ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); + + if( ( ret = mbedtls_ecp_group_load( grp, grp_id ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +/* + * EC public key is an EC point + * + * The caller is responsible for clearing the structure upon failure if + * desired. Take care to pass along the possible ECP_FEATURE_UNAVAILABLE + * return code of mbedtls_ecp_point_read_binary() and leave p in a usable state. + */ +static int pk_get_ecpubkey( unsigned char **p, const unsigned char *end, + mbedtls_ecp_keypair *key ) +{ + int ret; + + if( ( ret = mbedtls_ecp_point_read_binary( &key->grp, &key->Q, + (const unsigned char *) *p, end - *p ) ) == 0 ) + { + ret = mbedtls_ecp_check_pubkey( &key->grp, &key->Q ); + } + + /* + * We know mbedtls_ecp_point_read_binary consumed all bytes or failed + */ + *p = (unsigned char *) end; + + return( ret ); +} +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_RSA_C) +/* + * RSAPublicKey ::= SEQUENCE { + * modulus INTEGER, -- n + * publicExponent INTEGER -- e + * } + */ +static int pk_get_rsapubkey( unsigned char **p, + const unsigned char *end, + mbedtls_rsa_context *rsa ) +{ + int ret; + size_t len; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY + ret ); + + if( *p + len != end ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + /* Import N */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_INTEGER ) ) != 0 ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY + ret ); + + if( ( ret = mbedtls_rsa_import_raw( rsa, *p, len, NULL, 0, NULL, 0, + NULL, 0, NULL, 0 ) ) != 0 ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY ); + + *p += len; + + /* Import E */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_INTEGER ) ) != 0 ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY + ret ); + + if( ( ret = mbedtls_rsa_import_raw( rsa, NULL, 0, NULL, 0, NULL, 0, + NULL, 0, *p, len ) ) != 0 ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY ); + + *p += len; + + if( mbedtls_rsa_complete( rsa ) != 0 || + mbedtls_rsa_check_pubkey( rsa ) != 0 ) + { + return( MBEDTLS_ERR_PK_INVALID_PUBKEY ); + } + + if( *p != end ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} +#endif /* MBEDTLS_RSA_C */ + +/* Get a PK algorithm identifier + * + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL } + */ +static int pk_get_pk_alg( unsigned char **p, + const unsigned char *end, + mbedtls_pk_type_t *pk_alg, mbedtls_asn1_buf *params ) +{ + int ret; + mbedtls_asn1_buf alg_oid; + + memset( params, 0, sizeof(mbedtls_asn1_buf) ); + + if( ( ret = mbedtls_asn1_get_alg( p, end, &alg_oid, params ) ) != 0 ) + return( MBEDTLS_ERR_PK_INVALID_ALG + ret ); + + if( mbedtls_oid_get_pk_alg( &alg_oid, pk_alg ) != 0 ) + return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); + + /* + * No parameters with RSA (only for EC) + */ + if( *pk_alg == MBEDTLS_PK_RSA && + ( ( params->tag != MBEDTLS_ASN1_NULL && params->tag != 0 ) || + params->len != 0 ) ) + { + return( MBEDTLS_ERR_PK_INVALID_ALG ); + } + + return( 0 ); +} + +/* + * SubjectPublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * subjectPublicKey BIT STRING } + */ +int mbedtls_pk_parse_subpubkey( unsigned char **p, const unsigned char *end, + mbedtls_pk_context *pk ) +{ + int ret; + size_t len; + mbedtls_asn1_buf alg_params; + mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE; + const mbedtls_pk_info_t *pk_info; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + end = *p + len; + + if( ( ret = pk_get_pk_alg( p, end, &pk_alg, &alg_params ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_asn1_get_bitstring_null( p, end, &len ) ) != 0 ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY + ret ); + + if( *p + len != end ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + if( ( pk_info = mbedtls_pk_info_from_type( pk_alg ) ) == NULL ) + return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); + + if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 ) + return( ret ); + +#if defined(MBEDTLS_RSA_C) + if( pk_alg == MBEDTLS_PK_RSA ) + { + ret = pk_get_rsapubkey( p, end, mbedtls_pk_rsa( *pk ) ); + } else +#endif /* MBEDTLS_RSA_C */ +#if defined(MBEDTLS_ECP_C) + if( pk_alg == MBEDTLS_PK_ECKEY_DH || pk_alg == MBEDTLS_PK_ECKEY ) + { + ret = pk_use_ecparams( &alg_params, &mbedtls_pk_ec( *pk )->grp ); + if( ret == 0 ) + ret = pk_get_ecpubkey( p, end, mbedtls_pk_ec( *pk ) ); + } else +#endif /* MBEDTLS_ECP_C */ + ret = MBEDTLS_ERR_PK_UNKNOWN_PK_ALG; + + if( ret == 0 && *p != end ) + ret = MBEDTLS_ERR_PK_INVALID_PUBKEY + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; + + if( ret != 0 ) + mbedtls_pk_free( pk ); + + return( ret ); +} + +#if defined(MBEDTLS_RSA_C) +/* + * Parse a PKCS#1 encoded private RSA key + */ +static int pk_parse_key_pkcs1_der( mbedtls_rsa_context *rsa, + const unsigned char *key, + size_t keylen ) +{ + int ret, version; + size_t len; + unsigned char *p, *end; + + mbedtls_mpi T; + mbedtls_mpi_init( &T ); + + p = (unsigned char *) key; + end = p + keylen; + + /* + * This function parses the RSAPrivateKey (PKCS#1) + * + * RSAPrivateKey ::= SEQUENCE { + * version Version, + * modulus INTEGER, -- n + * publicExponent INTEGER, -- e + * privateExponent INTEGER, -- d + * prime1 INTEGER, -- p + * prime2 INTEGER, -- q + * exponent1 INTEGER, -- d mod (p-1) + * exponent2 INTEGER, -- d mod (q-1) + * coefficient INTEGER, -- (inverse of q) mod p + * otherPrimeInfos OtherPrimeInfos OPTIONAL + * } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + end = p + len; + + if( ( ret = mbedtls_asn1_get_int( &p, end, &version ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + if( version != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_VERSION ); + } + + /* Import N */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_INTEGER ) ) != 0 || + ( ret = mbedtls_rsa_import_raw( rsa, p, len, NULL, 0, NULL, 0, + NULL, 0, NULL, 0 ) ) != 0 ) + goto cleanup; + p += len; + + /* Import E */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_INTEGER ) ) != 0 || + ( ret = mbedtls_rsa_import_raw( rsa, NULL, 0, NULL, 0, NULL, 0, + NULL, 0, p, len ) ) != 0 ) + goto cleanup; + p += len; + + /* Import D */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_INTEGER ) ) != 0 || + ( ret = mbedtls_rsa_import_raw( rsa, NULL, 0, NULL, 0, NULL, 0, + p, len, NULL, 0 ) ) != 0 ) + goto cleanup; + p += len; + + /* Import P */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_INTEGER ) ) != 0 || + ( ret = mbedtls_rsa_import_raw( rsa, NULL, 0, p, len, NULL, 0, + NULL, 0, NULL, 0 ) ) != 0 ) + goto cleanup; + p += len; + + /* Import Q */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_INTEGER ) ) != 0 || + ( ret = mbedtls_rsa_import_raw( rsa, NULL, 0, NULL, 0, p, len, + NULL, 0, NULL, 0 ) ) != 0 ) + goto cleanup; + p += len; + + /* Complete the RSA private key */ + if( ( ret = mbedtls_rsa_complete( rsa ) ) != 0 ) + goto cleanup; + + /* Check optional parameters */ + if( ( ret = mbedtls_asn1_get_mpi( &p, end, &T ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( &p, end, &T ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( &p, end, &T ) ) != 0 ) + goto cleanup; + + if( p != end ) + { + ret = MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ; + } + +cleanup: + + mbedtls_mpi_free( &T ); + + if( ret != 0 ) + { + /* Wrap error code if it's coming from a lower level */ + if( ( ret & 0xff80 ) == 0 ) + ret = MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret; + else + ret = MBEDTLS_ERR_PK_KEY_INVALID_FORMAT; + + mbedtls_rsa_free( rsa ); + } + + return( ret ); +} +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_ECP_C) +/* + * Parse a SEC1 encoded private EC key + */ +static int pk_parse_key_sec1_der( mbedtls_ecp_keypair *eck, + const unsigned char *key, + size_t keylen ) +{ + int ret; + int version, pubkey_done; + size_t len; + mbedtls_asn1_buf params; + unsigned char *p = (unsigned char *) key; + unsigned char *end = p + keylen; + unsigned char *end2; + + /* + * RFC 5915, or SEC1 Appendix C.4 + * + * ECPrivateKey ::= SEQUENCE { + * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), + * privateKey OCTET STRING, + * parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, + * publicKey [1] BIT STRING OPTIONAL + * } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + end = p + len; + + if( ( ret = mbedtls_asn1_get_int( &p, end, &version ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( version != 1 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_VERSION ); + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( ( ret = mbedtls_mpi_read_binary( &eck->d, p, len ) ) != 0 ) + { + mbedtls_ecp_keypair_free( eck ); + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + p += len; + + pubkey_done = 0; + if( p != end ) + { + /* + * Is 'parameters' present? + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0 ) ) == 0 ) + { + if( ( ret = pk_get_ecparams( &p, p + len, ¶ms) ) != 0 || + ( ret = pk_use_ecparams( ¶ms, &eck->grp ) ) != 0 ) + { + mbedtls_ecp_keypair_free( eck ); + return( ret ); + } + } + else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + { + mbedtls_ecp_keypair_free( eck ); + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + } + + if( p != end ) + { + /* + * Is 'publickey' present? If not, or if we can't read it (eg because it + * is compressed), create it from the private key. + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 1 ) ) == 0 ) + { + end2 = p + len; + + if( ( ret = mbedtls_asn1_get_bitstring_null( &p, end2, &len ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( p + len != end2 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + if( ( ret = pk_get_ecpubkey( &p, end2, eck ) ) == 0 ) + pubkey_done = 1; + else + { + /* + * The only acceptable failure mode of pk_get_ecpubkey() above + * is if the point format is not recognized. + */ + if( ret != MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); + } + } + else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + { + mbedtls_ecp_keypair_free( eck ); + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + } + + if( ! pubkey_done && + ( ret = mbedtls_ecp_mul( &eck->grp, &eck->Q, &eck->d, &eck->grp.G, + NULL, NULL ) ) != 0 ) + { + mbedtls_ecp_keypair_free( eck ); + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + if( ( ret = mbedtls_ecp_check_privkey( &eck->grp, &eck->d ) ) != 0 ) + { + mbedtls_ecp_keypair_free( eck ); + return( ret ); + } + + return( 0 ); +} +#endif /* MBEDTLS_ECP_C */ + +/* + * Parse an unencrypted PKCS#8 encoded private key + * + * Notes: + * + * - This function does not own the key buffer. It is the + * responsibility of the caller to take care of zeroizing + * and freeing it after use. + * + * - The function is responsible for freeing the provided + * PK context on failure. + * + */ +static int pk_parse_key_pkcs8_unencrypted_der( + mbedtls_pk_context *pk, + const unsigned char* key, + size_t keylen ) +{ + int ret, version; + size_t len; + mbedtls_asn1_buf params; + unsigned char *p = (unsigned char *) key; + unsigned char *end = p + keylen; + mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE; + const mbedtls_pk_info_t *pk_info; + + /* + * This function parses the PrivateKeyInfo object (PKCS#8 v1.2 = RFC 5208) + * + * PrivateKeyInfo ::= SEQUENCE { + * version Version, + * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, + * privateKey PrivateKey, + * attributes [0] IMPLICIT Attributes OPTIONAL } + * + * Version ::= INTEGER + * PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier + * PrivateKey ::= OCTET STRING + * + * The PrivateKey OCTET STRING is a SEC1 ECPrivateKey + */ + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + end = p + len; + + if( ( ret = mbedtls_asn1_get_int( &p, end, &version ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( version != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_VERSION + ret ); + + if( ( ret = pk_get_pk_alg( &p, end, &pk_alg, ¶ms ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( len < 1 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + if( ( pk_info = mbedtls_pk_info_from_type( pk_alg ) ) == NULL ) + return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); + + if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 ) + return( ret ); + +#if defined(MBEDTLS_RSA_C) + if( pk_alg == MBEDTLS_PK_RSA ) + { + if( ( ret = pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ), p, len ) ) != 0 ) + { + mbedtls_pk_free( pk ); + return( ret ); + } + } else +#endif /* MBEDTLS_RSA_C */ +#if defined(MBEDTLS_ECP_C) + if( pk_alg == MBEDTLS_PK_ECKEY || pk_alg == MBEDTLS_PK_ECKEY_DH ) + { + if( ( ret = pk_use_ecparams( ¶ms, &mbedtls_pk_ec( *pk )->grp ) ) != 0 || + ( ret = pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ), p, len ) ) != 0 ) + { + mbedtls_pk_free( pk ); + return( ret ); + } + } else +#endif /* MBEDTLS_ECP_C */ + return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); + + return( 0 ); +} + +/* + * Parse an encrypted PKCS#8 encoded private key + * + * To save space, the decryption happens in-place on the given key buffer. + * Also, while this function may modify the keybuffer, it doesn't own it, + * and instead it is the responsibility of the caller to zeroize and properly + * free it after use. + * + */ +#if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C) +static int pk_parse_key_pkcs8_encrypted_der( + mbedtls_pk_context *pk, + unsigned char *key, size_t keylen, + const unsigned char *pwd, size_t pwdlen ) +{ + int ret, decrypted = 0; + size_t len; + unsigned char *buf; + unsigned char *p, *end; + mbedtls_asn1_buf pbe_alg_oid, pbe_params; +#if defined(MBEDTLS_PKCS12_C) + mbedtls_cipher_type_t cipher_alg; + mbedtls_md_type_t md_alg; +#endif + + p = key; + end = p + keylen; + + if( pwdlen == 0 ) + return( MBEDTLS_ERR_PK_PASSWORD_REQUIRED ); + + /* + * This function parses the EncryptedPrivateKeyInfo object (PKCS#8) + * + * EncryptedPrivateKeyInfo ::= SEQUENCE { + * encryptionAlgorithm EncryptionAlgorithmIdentifier, + * encryptedData EncryptedData + * } + * + * EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier + * + * EncryptedData ::= OCTET STRING + * + * The EncryptedData OCTET STRING is a PKCS#8 PrivateKeyInfo + * + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + end = p + len; + + if( ( ret = mbedtls_asn1_get_alg( &p, end, &pbe_alg_oid, &pbe_params ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + buf = p; + + /* + * Decrypt EncryptedData with appropriate PBE + */ +#if defined(MBEDTLS_PKCS12_C) + if( mbedtls_oid_get_pkcs12_pbe_alg( &pbe_alg_oid, &md_alg, &cipher_alg ) == 0 ) + { + if( ( ret = mbedtls_pkcs12_pbe( &pbe_params, MBEDTLS_PKCS12_PBE_DECRYPT, + cipher_alg, md_alg, + pwd, pwdlen, p, len, buf ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH ) + return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); + + return( ret ); + } + + decrypted = 1; + } + else if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS12_PBE_SHA1_RC4_128, &pbe_alg_oid ) == 0 ) + { + if( ( ret = mbedtls_pkcs12_pbe_sha1_rc4_128( &pbe_params, + MBEDTLS_PKCS12_PBE_DECRYPT, + pwd, pwdlen, + p, len, buf ) ) != 0 ) + { + return( ret ); + } + + // Best guess for password mismatch when using RC4. If first tag is + // not MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE + // + if( *buf != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) + return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); + + decrypted = 1; + } + else +#endif /* MBEDTLS_PKCS12_C */ +#if defined(MBEDTLS_PKCS5_C) + if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS5_PBES2, &pbe_alg_oid ) == 0 ) + { + if( ( ret = mbedtls_pkcs5_pbes2( &pbe_params, MBEDTLS_PKCS5_DECRYPT, pwd, pwdlen, + p, len, buf ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH ) + return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); + + return( ret ); + } + + decrypted = 1; + } + else +#endif /* MBEDTLS_PKCS5_C */ + { + ((void) pwd); + } + + if( decrypted == 0 ) + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); + + return( pk_parse_key_pkcs8_unencrypted_der( pk, buf, len ) ); +} +#endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */ + +/* + * Parse a private key + */ +int mbedtls_pk_parse_key( mbedtls_pk_context *pk, + const unsigned char *key, size_t keylen, + const unsigned char *pwd, size_t pwdlen ) +{ + int ret; + const mbedtls_pk_info_t *pk_info; + +#if defined(MBEDTLS_PEM_PARSE_C) + size_t len; + mbedtls_pem_context pem; + + mbedtls_pem_init( &pem ); + +#if defined(MBEDTLS_RSA_C) + /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ + if( keylen == 0 || key[keylen - 1] != '\0' ) + ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; + else + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN RSA PRIVATE KEY-----", + "-----END RSA PRIVATE KEY-----", + key, pwd, pwdlen, &len ); + + if( ret == 0 ) + { + pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ); + if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 || + ( ret = pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ), + pem.buf, pem.buflen ) ) != 0 ) + { + mbedtls_pk_free( pk ); + } + + mbedtls_pem_free( &pem ); + return( ret ); + } + else if( ret == MBEDTLS_ERR_PEM_PASSWORD_MISMATCH ) + return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); + else if( ret == MBEDTLS_ERR_PEM_PASSWORD_REQUIRED ) + return( MBEDTLS_ERR_PK_PASSWORD_REQUIRED ); + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + return( ret ); +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_ECP_C) + /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ + if( keylen == 0 || key[keylen - 1] != '\0' ) + ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; + else + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN EC PRIVATE KEY-----", + "-----END EC PRIVATE KEY-----", + key, pwd, pwdlen, &len ); + if( ret == 0 ) + { + pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_ECKEY ); + + if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 || + ( ret = pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ), + pem.buf, pem.buflen ) ) != 0 ) + { + mbedtls_pk_free( pk ); + } + + mbedtls_pem_free( &pem ); + return( ret ); + } + else if( ret == MBEDTLS_ERR_PEM_PASSWORD_MISMATCH ) + return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); + else if( ret == MBEDTLS_ERR_PEM_PASSWORD_REQUIRED ) + return( MBEDTLS_ERR_PK_PASSWORD_REQUIRED ); + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + return( ret ); +#endif /* MBEDTLS_ECP_C */ + + /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ + if( keylen == 0 || key[keylen - 1] != '\0' ) + ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; + else + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN PRIVATE KEY-----", + "-----END PRIVATE KEY-----", + key, NULL, 0, &len ); + if( ret == 0 ) + { + if( ( ret = pk_parse_key_pkcs8_unencrypted_der( pk, + pem.buf, pem.buflen ) ) != 0 ) + { + mbedtls_pk_free( pk ); + } + + mbedtls_pem_free( &pem ); + return( ret ); + } + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + return( ret ); + +#if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C) + /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ + if( keylen == 0 || key[keylen - 1] != '\0' ) + ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; + else + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN ENCRYPTED PRIVATE KEY-----", + "-----END ENCRYPTED PRIVATE KEY-----", + key, NULL, 0, &len ); + if( ret == 0 ) + { + if( ( ret = pk_parse_key_pkcs8_encrypted_der( pk, + pem.buf, pem.buflen, + pwd, pwdlen ) ) != 0 ) + { + mbedtls_pk_free( pk ); + } + + mbedtls_pem_free( &pem ); + return( ret ); + } + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + return( ret ); +#endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */ +#else + ((void) pwd); + ((void) pwdlen); +#endif /* MBEDTLS_PEM_PARSE_C */ + + /* + * At this point we only know it's not a PEM formatted key. Could be any + * of the known DER encoded private key formats + * + * We try the different DER format parsers to see if one passes without + * error + */ +#if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C) + { + unsigned char *key_copy; + + if( keylen == 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); + + if( ( key_copy = mbedtls_calloc( 1, keylen ) ) == NULL ) + return( MBEDTLS_ERR_PK_ALLOC_FAILED ); + + memcpy( key_copy, key, keylen ); + + ret = pk_parse_key_pkcs8_encrypted_der( pk, key_copy, keylen, + pwd, pwdlen ); + + mbedtls_platform_zeroize( key_copy, keylen ); + mbedtls_free( key_copy ); + } + + if( ret == 0 ) + return( 0 ); + + mbedtls_pk_free( pk ); + + if( ret == MBEDTLS_ERR_PK_PASSWORD_MISMATCH ) + { + return( ret ); + } +#endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */ + + if( ( ret = pk_parse_key_pkcs8_unencrypted_der( pk, key, keylen ) ) == 0 ) + return( 0 ); + + mbedtls_pk_free( pk ); + +#if defined(MBEDTLS_RSA_C) + + pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ); + if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 || + ( ret = pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ), + key, keylen ) ) != 0 ) + { + mbedtls_pk_free( pk ); + } + else + { + return( 0 ); + } + +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_ECP_C) + + pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_ECKEY ); + if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 || + ( ret = pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ), + key, keylen ) ) != 0 ) + { + mbedtls_pk_free( pk ); + } + else + { + return( 0 ); + } + +#endif /* MBEDTLS_ECP_C */ + + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); +} + +/* + * Parse a public key + */ +int mbedtls_pk_parse_public_key( mbedtls_pk_context *ctx, + const unsigned char *key, size_t keylen ) +{ + int ret; + unsigned char *p; +#if defined(MBEDTLS_RSA_C) + const mbedtls_pk_info_t *pk_info; +#endif +#if defined(MBEDTLS_PEM_PARSE_C) + size_t len; + mbedtls_pem_context pem; + + mbedtls_pem_init( &pem ); +#if defined(MBEDTLS_RSA_C) + /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ + if( keylen == 0 || key[keylen - 1] != '\0' ) + ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; + else + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN RSA PUBLIC KEY-----", + "-----END RSA PUBLIC KEY-----", + key, NULL, 0, &len ); + + if( ret == 0 ) + { + p = pem.buf; + if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == NULL ) + return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); + + if( ( ret = mbedtls_pk_setup( ctx, pk_info ) ) != 0 ) + return( ret ); + + if ( ( ret = pk_get_rsapubkey( &p, p + pem.buflen, mbedtls_pk_rsa( *ctx ) ) ) != 0 ) + mbedtls_pk_free( ctx ); + + mbedtls_pem_free( &pem ); + return( ret ); + } + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + { + mbedtls_pem_free( &pem ); + return( ret ); + } +#endif /* MBEDTLS_RSA_C */ + + /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ + if( keylen == 0 || key[keylen - 1] != '\0' ) + ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; + else + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN PUBLIC KEY-----", + "-----END PUBLIC KEY-----", + key, NULL, 0, &len ); + + if( ret == 0 ) + { + /* + * Was PEM encoded + */ + p = pem.buf; + + ret = mbedtls_pk_parse_subpubkey( &p, p + pem.buflen, ctx ); + mbedtls_pem_free( &pem ); + return( ret ); + } + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + { + mbedtls_pem_free( &pem ); + return( ret ); + } + mbedtls_pem_free( &pem ); +#endif /* MBEDTLS_PEM_PARSE_C */ + +#if defined(MBEDTLS_RSA_C) + if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == NULL ) + return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); + + if( ( ret = mbedtls_pk_setup( ctx, pk_info ) ) != 0 ) + return( ret ); + + p = (unsigned char *)key; + ret = pk_get_rsapubkey( &p, p + keylen, mbedtls_pk_rsa( *ctx ) ); + if( ret == 0 ) + { + return( ret ); + } + mbedtls_pk_free( ctx ); + if( ret != ( MBEDTLS_ERR_PK_INVALID_PUBKEY + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) ) + { + return( ret ); + } +#endif /* MBEDTLS_RSA_C */ + p = (unsigned char *) key; + + ret = mbedtls_pk_parse_subpubkey( &p, p + keylen, ctx ); + + return( ret ); +} + +#endif /* MBEDTLS_PK_PARSE_C */ diff --git a/common/mbedtls/platform.c b/common/mbedtls/platform.c new file mode 100644 index 00000000..3ddb7f7a --- /dev/null +++ b/common/mbedtls/platform.c @@ -0,0 +1,341 @@ +/* + * Platform abstraction layer + * + * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PLATFORM_C) + +#include "mbedtls/platform.h" +#include "mbedtls/platform_util.h" + +#if defined(MBEDTLS_PLATFORM_MEMORY) +#if !defined(MBEDTLS_PLATFORM_STD_CALLOC) +static void *platform_calloc_uninit( size_t n, size_t size ) +{ + ((void) n); + ((void) size); + return( NULL ); +} + +#define MBEDTLS_PLATFORM_STD_CALLOC platform_calloc_uninit +#endif /* !MBEDTLS_PLATFORM_STD_CALLOC */ + +#if !defined(MBEDTLS_PLATFORM_STD_FREE) +static void platform_free_uninit( void *ptr ) +{ + ((void) ptr); +} + +#define MBEDTLS_PLATFORM_STD_FREE platform_free_uninit +#endif /* !MBEDTLS_PLATFORM_STD_FREE */ + +static void * (*mbedtls_calloc_func)( size_t, size_t ) = MBEDTLS_PLATFORM_STD_CALLOC; +static void (*mbedtls_free_func)( void * ) = MBEDTLS_PLATFORM_STD_FREE; + +void * mbedtls_calloc( size_t nmemb, size_t size ) +{ + return (*mbedtls_calloc_func)( nmemb, size ); +} + +void mbedtls_free( void * ptr ) +{ + (*mbedtls_free_func)( ptr ); +} + +int mbedtls_platform_set_calloc_free( void * (*calloc_func)( size_t, size_t ), + void (*free_func)( void * ) ) +{ + mbedtls_calloc_func = calloc_func; + mbedtls_free_func = free_func; + return( 0 ); +} +#endif /* MBEDTLS_PLATFORM_MEMORY */ + +#if defined(_WIN32) +#include +int mbedtls_platform_win32_snprintf( char *s, size_t n, const char *fmt, ... ) +{ + int ret; + va_list argp; + + /* Avoid calling the invalid parameter handler by checking ourselves */ + if( s == NULL || n == 0 || fmt == NULL ) + return( -1 ); + + va_start( argp, fmt ); +#if defined(_TRUNCATE) && !defined(__MINGW32__) + ret = _vsnprintf_s( s, n, _TRUNCATE, fmt, argp ); +#else + ret = _vsnprintf( s, n, fmt, argp ); + if( ret < 0 || (size_t) ret == n ) + { + s[n-1] = '\0'; + ret = -1; + } +#endif + va_end( argp ); + + return( ret ); +} +#endif + +#if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) +#if !defined(MBEDTLS_PLATFORM_STD_SNPRINTF) +/* + * Make dummy function to prevent NULL pointer dereferences + */ +static int platform_snprintf_uninit( char * s, size_t n, + const char * format, ... ) +{ + ((void) s); + ((void) n); + ((void) format); + return( 0 ); +} + +#define MBEDTLS_PLATFORM_STD_SNPRINTF platform_snprintf_uninit +#endif /* !MBEDTLS_PLATFORM_STD_SNPRINTF */ + +int (*mbedtls_snprintf)( char * s, size_t n, + const char * format, + ... ) = MBEDTLS_PLATFORM_STD_SNPRINTF; + +int mbedtls_platform_set_snprintf( int (*snprintf_func)( char * s, size_t n, + const char * format, + ... ) ) +{ + mbedtls_snprintf = snprintf_func; + return( 0 ); +} +#endif /* MBEDTLS_PLATFORM_SNPRINTF_ALT */ + +#if defined(MBEDTLS_PLATFORM_PRINTF_ALT) +#if !defined(MBEDTLS_PLATFORM_STD_PRINTF) +/* + * Make dummy function to prevent NULL pointer dereferences + */ +static int platform_printf_uninit( const char *format, ... ) +{ + ((void) format); + return( 0 ); +} + +#define MBEDTLS_PLATFORM_STD_PRINTF platform_printf_uninit +#endif /* !MBEDTLS_PLATFORM_STD_PRINTF */ + +int (*mbedtls_printf)( const char *, ... ) = MBEDTLS_PLATFORM_STD_PRINTF; + +int mbedtls_platform_set_printf( int (*printf_func)( const char *, ... ) ) +{ + mbedtls_printf = printf_func; + return( 0 ); +} +#endif /* MBEDTLS_PLATFORM_PRINTF_ALT */ + +#if defined(MBEDTLS_PLATFORM_FPRINTF_ALT) +#if !defined(MBEDTLS_PLATFORM_STD_FPRINTF) +/* + * Make dummy function to prevent NULL pointer dereferences + */ +static int platform_fprintf_uninit( FILE *stream, const char *format, ... ) +{ + ((void) stream); + ((void) format); + return( 0 ); +} + +#define MBEDTLS_PLATFORM_STD_FPRINTF platform_fprintf_uninit +#endif /* !MBEDTLS_PLATFORM_STD_FPRINTF */ + +int (*mbedtls_fprintf)( FILE *, const char *, ... ) = + MBEDTLS_PLATFORM_STD_FPRINTF; + +int mbedtls_platform_set_fprintf( int (*fprintf_func)( FILE *, const char *, ... ) ) +{ + mbedtls_fprintf = fprintf_func; + return( 0 ); +} +#endif /* MBEDTLS_PLATFORM_FPRINTF_ALT */ + +#if defined(MBEDTLS_PLATFORM_EXIT_ALT) +#if !defined(MBEDTLS_PLATFORM_STD_EXIT) +/* + * Make dummy function to prevent NULL pointer dereferences + */ +static void platform_exit_uninit( int status ) +{ + ((void) status); +} + +#define MBEDTLS_PLATFORM_STD_EXIT platform_exit_uninit +#endif /* !MBEDTLS_PLATFORM_STD_EXIT */ + +void (*mbedtls_exit)( int status ) = MBEDTLS_PLATFORM_STD_EXIT; + +int mbedtls_platform_set_exit( void (*exit_func)( int status ) ) +{ + mbedtls_exit = exit_func; + return( 0 ); +} +#endif /* MBEDTLS_PLATFORM_EXIT_ALT */ + +#if defined(MBEDTLS_HAVE_TIME) + +#if defined(MBEDTLS_PLATFORM_TIME_ALT) +#if !defined(MBEDTLS_PLATFORM_STD_TIME) +/* + * Make dummy function to prevent NULL pointer dereferences + */ +static mbedtls_time_t platform_time_uninit( mbedtls_time_t* timer ) +{ + ((void) timer); + return( 0 ); +} + +#define MBEDTLS_PLATFORM_STD_TIME platform_time_uninit +#endif /* !MBEDTLS_PLATFORM_STD_TIME */ + +mbedtls_time_t (*mbedtls_time)( mbedtls_time_t* timer ) = MBEDTLS_PLATFORM_STD_TIME; + +int mbedtls_platform_set_time( mbedtls_time_t (*time_func)( mbedtls_time_t* timer ) ) +{ + mbedtls_time = time_func; + return( 0 ); +} +#endif /* MBEDTLS_PLATFORM_TIME_ALT */ + +#endif /* MBEDTLS_HAVE_TIME */ + +#if defined(MBEDTLS_ENTROPY_NV_SEED) +#if !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS) && defined(MBEDTLS_FS_IO) +/* Default implementations for the platform independent seed functions use + * standard libc file functions to read from and write to a pre-defined filename + */ +int mbedtls_platform_std_nv_seed_read( unsigned char *buf, size_t buf_len ) +{ + FILE *file; + size_t n; + + if( ( file = fopen( MBEDTLS_PLATFORM_STD_NV_SEED_FILE, "rb" ) ) == NULL ) + return( -1 ); + + if( ( n = fread( buf, 1, buf_len, file ) ) != buf_len ) + { + fclose( file ); + mbedtls_platform_zeroize( buf, buf_len ); + return( -1 ); + } + + fclose( file ); + return( (int)n ); +} + +int mbedtls_platform_std_nv_seed_write( unsigned char *buf, size_t buf_len ) +{ + FILE *file; + size_t n; + + if( ( file = fopen( MBEDTLS_PLATFORM_STD_NV_SEED_FILE, "w" ) ) == NULL ) + return -1; + + if( ( n = fwrite( buf, 1, buf_len, file ) ) != buf_len ) + { + fclose( file ); + return -1; + } + + fclose( file ); + return( (int)n ); +} +#endif /* MBEDTLS_PLATFORM_NO_STD_FUNCTIONS */ + +#if defined(MBEDTLS_PLATFORM_NV_SEED_ALT) +#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ) +/* + * Make dummy function to prevent NULL pointer dereferences + */ +static int platform_nv_seed_read_uninit( unsigned char *buf, size_t buf_len ) +{ + ((void) buf); + ((void) buf_len); + return( -1 ); +} + +#define MBEDTLS_PLATFORM_STD_NV_SEED_READ platform_nv_seed_read_uninit +#endif /* !MBEDTLS_PLATFORM_STD_NV_SEED_READ */ + +#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE) +/* + * Make dummy function to prevent NULL pointer dereferences + */ +static int platform_nv_seed_write_uninit( unsigned char *buf, size_t buf_len ) +{ + ((void) buf); + ((void) buf_len); + return( -1 ); +} + +#define MBEDTLS_PLATFORM_STD_NV_SEED_WRITE platform_nv_seed_write_uninit +#endif /* !MBEDTLS_PLATFORM_STD_NV_SEED_WRITE */ + +int (*mbedtls_nv_seed_read)( unsigned char *buf, size_t buf_len ) = + MBEDTLS_PLATFORM_STD_NV_SEED_READ; +int (*mbedtls_nv_seed_write)( unsigned char *buf, size_t buf_len ) = + MBEDTLS_PLATFORM_STD_NV_SEED_WRITE; + +int mbedtls_platform_set_nv_seed( + int (*nv_seed_read_func)( unsigned char *buf, size_t buf_len ), + int (*nv_seed_write_func)( unsigned char *buf, size_t buf_len ) ) +{ + mbedtls_nv_seed_read = nv_seed_read_func; + mbedtls_nv_seed_write = nv_seed_write_func; + return( 0 ); +} +#endif /* MBEDTLS_PLATFORM_NV_SEED_ALT */ +#endif /* MBEDTLS_ENTROPY_NV_SEED */ + +#if !defined(MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT) +/* + * Placeholder platform setup that does nothing by default + */ +int mbedtls_platform_setup( mbedtls_platform_context *ctx ) +{ + (void)ctx; + + return( 0 ); +} + +/* + * Placeholder platform teardown that does nothing by default + */ +void mbedtls_platform_teardown( mbedtls_platform_context *ctx ) +{ + (void)ctx; +} +#endif /* MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT */ + +#endif /* MBEDTLS_PLATFORM_C */ diff --git a/common/mbedtls/platform.h b/common/mbedtls/platform.h new file mode 100644 index 00000000..818f44d4 --- /dev/null +++ b/common/mbedtls/platform.h @@ -0,0 +1,366 @@ +/** + * \file platform.h + * + * \brief This file contains the definitions and functions of the + * Mbed TLS platform abstraction layer. + * + * The platform abstraction layer removes the need for the library + * to directly link to standard C library functions or operating + * system services, making the library easier to port and embed. + * Application developers and users of the library can provide their own + * implementations of these functions, or implementations specific to + * their platform, which can be statically linked to the library or + * dynamically configured at runtime. + */ +/* + * Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_PLATFORM_H +#define MBEDTLS_PLATFORM_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_HAVE_TIME) +#include "platform_time.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h or define them on the compiler command line. + * \{ + */ + +#if !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS) +#include +#include +#include +#if !defined(MBEDTLS_PLATFORM_STD_SNPRINTF) +#if defined(_WIN32) +#define MBEDTLS_PLATFORM_STD_SNPRINTF mbedtls_platform_win32_snprintf /**< The default \c snprintf function to use. */ +#else +#define MBEDTLS_PLATFORM_STD_SNPRINTF snprintf /**< The default \c snprintf function to use. */ +#endif +#endif +#if !defined(MBEDTLS_PLATFORM_STD_PRINTF) +#define MBEDTLS_PLATFORM_STD_PRINTF printf /**< The default \c printf function to use. */ +#endif +#if !defined(MBEDTLS_PLATFORM_STD_FPRINTF) +#define MBEDTLS_PLATFORM_STD_FPRINTF fprintf /**< The default \c fprintf function to use. */ +#endif +#if !defined(MBEDTLS_PLATFORM_STD_CALLOC) +#define MBEDTLS_PLATFORM_STD_CALLOC calloc /**< The default \c calloc function to use. */ +#endif +#if !defined(MBEDTLS_PLATFORM_STD_FREE) +#define MBEDTLS_PLATFORM_STD_FREE free /**< The default \c free function to use. */ +#endif +#if !defined(MBEDTLS_PLATFORM_STD_EXIT) +#define MBEDTLS_PLATFORM_STD_EXIT exit /**< The default \c exit function to use. */ +#endif +#if !defined(MBEDTLS_PLATFORM_STD_TIME) +#define MBEDTLS_PLATFORM_STD_TIME time /**< The default \c time function to use. */ +#endif +#if !defined(MBEDTLS_PLATFORM_STD_EXIT_SUCCESS) +#define MBEDTLS_PLATFORM_STD_EXIT_SUCCESS EXIT_SUCCESS /**< The default exit value to use. */ +#endif +#if !defined(MBEDTLS_PLATFORM_STD_EXIT_FAILURE) +#define MBEDTLS_PLATFORM_STD_EXIT_FAILURE EXIT_FAILURE /**< The default exit value to use. */ +#endif +#if defined(MBEDTLS_FS_IO) +#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ) +#define MBEDTLS_PLATFORM_STD_NV_SEED_READ mbedtls_platform_std_nv_seed_read +#endif +#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE) +#define MBEDTLS_PLATFORM_STD_NV_SEED_WRITE mbedtls_platform_std_nv_seed_write +#endif +#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_FILE) +#define MBEDTLS_PLATFORM_STD_NV_SEED_FILE "seedfile" +#endif +#endif /* MBEDTLS_FS_IO */ +#else /* MBEDTLS_PLATFORM_NO_STD_FUNCTIONS */ +#if defined(MBEDTLS_PLATFORM_STD_MEM_HDR) +#include MBEDTLS_PLATFORM_STD_MEM_HDR +#endif +#endif /* MBEDTLS_PLATFORM_NO_STD_FUNCTIONS */ + + +/* \} name SECTION: Module settings */ + +/* + * The function pointers for calloc and free. + */ +#if defined(MBEDTLS_PLATFORM_MEMORY) +#if defined(MBEDTLS_PLATFORM_FREE_MACRO) && \ + defined(MBEDTLS_PLATFORM_CALLOC_MACRO) +#define mbedtls_free MBEDTLS_PLATFORM_FREE_MACRO +#define mbedtls_calloc MBEDTLS_PLATFORM_CALLOC_MACRO +#else +/* For size_t */ +#include +extern void *mbedtls_calloc( size_t n, size_t size ); +extern void mbedtls_free( void *ptr ); + +/** + * \brief This function dynamically sets the memory-management + * functions used by the library, during runtime. + * + * \param calloc_func The \c calloc function implementation. + * \param free_func The \c free function implementation. + * + * \return \c 0. + */ +int mbedtls_platform_set_calloc_free( void * (*calloc_func)( size_t, size_t ), + void (*free_func)( void * ) ); +#endif /* MBEDTLS_PLATFORM_FREE_MACRO && MBEDTLS_PLATFORM_CALLOC_MACRO */ +#else /* !MBEDTLS_PLATFORM_MEMORY */ +#define mbedtls_free free +#define mbedtls_calloc calloc +#endif /* MBEDTLS_PLATFORM_MEMORY && !MBEDTLS_PLATFORM_{FREE,CALLOC}_MACRO */ + +/* + * The function pointers for fprintf + */ +#if defined(MBEDTLS_PLATFORM_FPRINTF_ALT) +/* We need FILE * */ +#include +extern int (*mbedtls_fprintf)( FILE *stream, const char *format, ... ); + +/** + * \brief This function dynamically configures the fprintf + * function that is called when the + * mbedtls_fprintf() function is invoked by the library. + * + * \param fprintf_func The \c fprintf function implementation. + * + * \return \c 0. + */ +int mbedtls_platform_set_fprintf( int (*fprintf_func)( FILE *stream, const char *, + ... ) ); +#else +#if defined(MBEDTLS_PLATFORM_FPRINTF_MACRO) +#define mbedtls_fprintf MBEDTLS_PLATFORM_FPRINTF_MACRO +#else +#define mbedtls_fprintf fprintf +#endif /* MBEDTLS_PLATFORM_FPRINTF_MACRO */ +#endif /* MBEDTLS_PLATFORM_FPRINTF_ALT */ + +/* + * The function pointers for printf + */ +#if defined(MBEDTLS_PLATFORM_PRINTF_ALT) +extern int (*mbedtls_printf)( const char *format, ... ); + +/** + * \brief This function dynamically configures the snprintf + * function that is called when the mbedtls_snprintf() + * function is invoked by the library. + * + * \param printf_func The \c printf function implementation. + * + * \return \c 0 on success. + */ +int mbedtls_platform_set_printf( int (*printf_func)( const char *, ... ) ); +#else /* !MBEDTLS_PLATFORM_PRINTF_ALT */ +#if defined(MBEDTLS_PLATFORM_PRINTF_MACRO) +#define mbedtls_printf MBEDTLS_PLATFORM_PRINTF_MACRO +#else +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_PRINTF_MACRO */ +#endif /* MBEDTLS_PLATFORM_PRINTF_ALT */ + +/* + * The function pointers for snprintf + * + * The snprintf implementation should conform to C99: + * - it *must* always correctly zero-terminate the buffer + * (except when n == 0, then it must leave the buffer untouched) + * - however it is acceptable to return -1 instead of the required length when + * the destination buffer is too short. + */ +#if defined(_WIN32) +/* For Windows (inc. MSYS2), we provide our own fixed implementation */ +int mbedtls_platform_win32_snprintf( char *s, size_t n, const char *fmt, ... ); +#endif + +#if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) +extern int (*mbedtls_snprintf)( char * s, size_t n, const char * format, ... ); + +/** + * \brief This function allows configuring a custom + * \c snprintf function pointer. + * + * \param snprintf_func The \c snprintf function implementation. + * + * \return \c 0 on success. + */ +int mbedtls_platform_set_snprintf( int (*snprintf_func)( char * s, size_t n, + const char * format, ... ) ); +#else /* MBEDTLS_PLATFORM_SNPRINTF_ALT */ +#if defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO) +#define mbedtls_snprintf MBEDTLS_PLATFORM_SNPRINTF_MACRO +#else +#define mbedtls_snprintf MBEDTLS_PLATFORM_STD_SNPRINTF +#endif /* MBEDTLS_PLATFORM_SNPRINTF_MACRO */ +#endif /* MBEDTLS_PLATFORM_SNPRINTF_ALT */ + +/* + * The function pointers for exit + */ +#if defined(MBEDTLS_PLATFORM_EXIT_ALT) +extern void (*mbedtls_exit)( int status ); + +/** + * \brief This function dynamically configures the exit + * function that is called when the mbedtls_exit() + * function is invoked by the library. + * + * \param exit_func The \c exit function implementation. + * + * \return \c 0 on success. + */ +int mbedtls_platform_set_exit( void (*exit_func)( int status ) ); +#else +#if defined(MBEDTLS_PLATFORM_EXIT_MACRO) +#define mbedtls_exit MBEDTLS_PLATFORM_EXIT_MACRO +#else +#define mbedtls_exit exit +#endif /* MBEDTLS_PLATFORM_EXIT_MACRO */ +#endif /* MBEDTLS_PLATFORM_EXIT_ALT */ + +/* + * The default exit values + */ +#if defined(MBEDTLS_PLATFORM_STD_EXIT_SUCCESS) +#define MBEDTLS_EXIT_SUCCESS MBEDTLS_PLATFORM_STD_EXIT_SUCCESS +#else +#define MBEDTLS_EXIT_SUCCESS 0 +#endif +#if defined(MBEDTLS_PLATFORM_STD_EXIT_FAILURE) +#define MBEDTLS_EXIT_FAILURE MBEDTLS_PLATFORM_STD_EXIT_FAILURE +#else +#define MBEDTLS_EXIT_FAILURE 1 +#endif + +/* + * The function pointers for reading from and writing a seed file to + * Non-Volatile storage (NV) in a platform-independent way + * + * Only enabled when the NV seed entropy source is enabled + */ +#if defined(MBEDTLS_ENTROPY_NV_SEED) +#if !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS) && defined(MBEDTLS_FS_IO) +/* Internal standard platform definitions */ +int mbedtls_platform_std_nv_seed_read( unsigned char *buf, size_t buf_len ); +int mbedtls_platform_std_nv_seed_write( unsigned char *buf, size_t buf_len ); +#endif + +#if defined(MBEDTLS_PLATFORM_NV_SEED_ALT) +extern int (*mbedtls_nv_seed_read)( unsigned char *buf, size_t buf_len ); +extern int (*mbedtls_nv_seed_write)( unsigned char *buf, size_t buf_len ); + +/** + * \brief This function allows configuring custom seed file writing and + * reading functions. + * + * \param nv_seed_read_func The seed reading function implementation. + * \param nv_seed_write_func The seed writing function implementation. + * + * \return \c 0 on success. + */ +int mbedtls_platform_set_nv_seed( + int (*nv_seed_read_func)( unsigned char *buf, size_t buf_len ), + int (*nv_seed_write_func)( unsigned char *buf, size_t buf_len ) + ); +#else +#if defined(MBEDTLS_PLATFORM_NV_SEED_READ_MACRO) && \ + defined(MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO) +#define mbedtls_nv_seed_read MBEDTLS_PLATFORM_NV_SEED_READ_MACRO +#define mbedtls_nv_seed_write MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO +#else +#define mbedtls_nv_seed_read mbedtls_platform_std_nv_seed_read +#define mbedtls_nv_seed_write mbedtls_platform_std_nv_seed_write +#endif +#endif /* MBEDTLS_PLATFORM_NV_SEED_ALT */ +#endif /* MBEDTLS_ENTROPY_NV_SEED */ + +#if !defined(MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT) + +/** + * \brief The platform context structure. + * + * \note This structure may be used to assist platform-specific + * setup or teardown operations. + */ +typedef struct mbedtls_platform_context +{ + char dummy; /**< A placeholder member, as empty structs are not portable. */ +} +mbedtls_platform_context; + +#else +#include "platform_alt.h" +#endif /* !MBEDTLS_PLATFORM_SETUP_TEARDOWN_ALT */ + +/** + * \brief This function performs any platform-specific initialization + * operations. + * + * \note This function should be called before any other library functions. + * + * Its implementation is platform-specific, and unless + * platform-specific code is provided, it does nothing. + * + * \note The usage and necessity of this function is dependent on the platform. + * + * \param ctx The platform context. + * + * \return \c 0 on success. + */ +int mbedtls_platform_setup( mbedtls_platform_context *ctx ); +/** + * \brief This function performs any platform teardown operations. + * + * \note This function should be called after every other Mbed TLS module + * has been correctly freed using the appropriate free function. + * + * Its implementation is platform-specific, and unless + * platform-specific code is provided, it does nothing. + * + * \note The usage and necessity of this function is dependent on the platform. + * + * \param ctx The platform context. + * + */ +void mbedtls_platform_teardown( mbedtls_platform_context *ctx ); + +#ifdef __cplusplus +} +#endif + +#endif /* platform.h */ diff --git a/common/mbedtls/platform_util.c b/common/mbedtls/platform_util.c new file mode 100644 index 00000000..0be18aca --- /dev/null +++ b/common/mbedtls/platform_util.c @@ -0,0 +1,69 @@ +/* + * Common and shared functions used by multiple modules in the Mbed TLS + * library. + * + * Copyright (C) 2018, Arm Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "mbedtls/platform_util.h" + +#include +#include + +#if !defined(MBEDTLS_PLATFORM_ZEROIZE_ALT) +/* + * This implementation should never be optimized out by the compiler + * + * This implementation for mbedtls_platform_zeroize() was inspired from Colin + * Percival's blog article at: + * + * http://www.daemonology.net/blog/2014-09-04-how-to-zero-a-buffer.html + * + * It uses a volatile function pointer to the standard memset(). Because the + * pointer is volatile the compiler expects it to change at + * any time and will not optimize out the call that could potentially perform + * other operations on the input buffer instead of just setting it to 0. + * Nevertheless, as pointed out by davidtgoldblatt on Hacker News + * (refer to http://www.daemonology.net/blog/2014-09-05-erratum.html for + * details), optimizations of the following form are still possible: + * + * if( memset_func != memset ) + * memset_func( buf, 0, len ); + * + * Note that it is extremely difficult to guarantee that + * mbedtls_platform_zeroize() will not be optimized out by aggressive compilers + * in a portable way. For this reason, Mbed TLS also provides the configuration + * option MBEDTLS_PLATFORM_ZEROIZE_ALT, which allows users to configure + * mbedtls_platform_zeroize() to use a suitable implementation for their + * platform and needs. + */ +static void * (* const volatile memset_func)( void *, int, size_t ) = memset; + +void mbedtls_platform_zeroize( void *buf, size_t len ) +{ + memset_func( buf, 0, len ); +} +#endif /* MBEDTLS_PLATFORM_ZEROIZE_ALT */ diff --git a/common/mbedtls/platform_util.h b/common/mbedtls/platform_util.h new file mode 100644 index 00000000..79404ce6 --- /dev/null +++ b/common/mbedtls/platform_util.h @@ -0,0 +1,64 @@ +/** + * \file platform_util.h + * + * \brief Common and shared functions used by multiple modules in the Mbed TLS + * library. + */ +/* + * Copyright (C) 2018, Arm Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_PLATFORM_UTIL_H +#define MBEDTLS_PLATFORM_UTIL_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Securely zeroize a buffer + * + * The function is meant to wipe the data contained in a buffer so + * that it can no longer be recovered even if the program memory + * is later compromised. Call this function on sensitive data + * stored on the stack before returning from a function, and on + * sensitive data stored on the heap before freeing the heap + * object. + * + * It is extremely difficult to guarantee that calls to + * mbedtls_platform_zeroize() are not removed by aggressive + * compiler optimizations in a portable way. For this reason, Mbed + * TLS provides the configuration option + * MBEDTLS_PLATFORM_ZEROIZE_ALT, which allows users to configure + * mbedtls_platform_zeroize() to use a suitable implementation for + * their platform and needs + * + * \param buf Buffer to be zeroized + * \param len Length of the buffer in bytes + * + */ +void mbedtls_platform_zeroize( void *buf, size_t len ); + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_PLATFORM_UTIL_H */ diff --git a/common/mbedtls/rsa.c b/common/mbedtls/rsa.c new file mode 100644 index 00000000..f26cf6a8 --- /dev/null +++ b/common/mbedtls/rsa.c @@ -0,0 +1,2400 @@ +/* + * The RSA public-key cryptosystem + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * The following sources were referenced in the design of this implementation + * of the RSA algorithm: + * + * [1] A method for obtaining digital signatures and public-key cryptosystems + * R Rivest, A Shamir, and L Adleman + * http://people.csail.mit.edu/rivest/pubs.html#RSA78 + * + * [2] Handbook of Applied Cryptography - 1997, Chapter 8 + * Menezes, van Oorschot and Vanstone + * + * [3] Malware Guard Extension: Using SGX to Conceal Cache Attacks + * Michael Schwarz, Samuel Weiser, Daniel Gruss, Clémentine Maurice and + * Stefan Mangard + * https://arxiv.org/abs/1702.08719v2 + * + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_RSA_C) + +#include "mbedtls/rsa.h" +#include "mbedtls/rsa_internal.h" +#include "mbedtls/oid.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_PKCS1_V21) +#include "mbedtls/md.h" +#endif + +#if defined(MBEDTLS_PKCS1_V15) && !defined(__OpenBSD__) +#include +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#if !defined(MBEDTLS_RSA_ALT) + +#if defined(MBEDTLS_PKCS1_V15) +/* constant-time buffer comparison */ +static inline int mbedtls_safer_memcmp( const void *a, const void *b, size_t n ) +{ + size_t i; + const unsigned char *A = (const unsigned char *) a; + const unsigned char *B = (const unsigned char *) b; + unsigned char diff = 0; + + for( i = 0; i < n; i++ ) + diff |= A[i] ^ B[i]; + + return( diff ); +} +#endif /* MBEDTLS_PKCS1_V15 */ + +int mbedtls_rsa_import( mbedtls_rsa_context *ctx, + const mbedtls_mpi *N, + const mbedtls_mpi *P, const mbedtls_mpi *Q, + const mbedtls_mpi *D, const mbedtls_mpi *E ) +{ + int ret; + + if( ( N != NULL && ( ret = mbedtls_mpi_copy( &ctx->N, N ) ) != 0 ) || + ( P != NULL && ( ret = mbedtls_mpi_copy( &ctx->P, P ) ) != 0 ) || + ( Q != NULL && ( ret = mbedtls_mpi_copy( &ctx->Q, Q ) ) != 0 ) || + ( D != NULL && ( ret = mbedtls_mpi_copy( &ctx->D, D ) ) != 0 ) || + ( E != NULL && ( ret = mbedtls_mpi_copy( &ctx->E, E ) ) != 0 ) ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA + ret ); + } + + if( N != NULL ) + ctx->len = mbedtls_mpi_size( &ctx->N ); + + return( 0 ); +} + +int mbedtls_rsa_import_raw( mbedtls_rsa_context *ctx, + unsigned char const *N, size_t N_len, + unsigned char const *P, size_t P_len, + unsigned char const *Q, size_t Q_len, + unsigned char const *D, size_t D_len, + unsigned char const *E, size_t E_len ) +{ + int ret = 0; + + if( N != NULL ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &ctx->N, N, N_len ) ); + ctx->len = mbedtls_mpi_size( &ctx->N ); + } + + if( P != NULL ) + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &ctx->P, P, P_len ) ); + + if( Q != NULL ) + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &ctx->Q, Q, Q_len ) ); + + if( D != NULL ) + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &ctx->D, D, D_len ) ); + + if( E != NULL ) + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &ctx->E, E, E_len ) ); + +cleanup: + + if( ret != 0 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA + ret ); + + return( 0 ); +} + +/* + * Checks whether the context fields are set in such a way + * that the RSA primitives will be able to execute without error. + * It does *not* make guarantees for consistency of the parameters. + */ +static int rsa_check_context( mbedtls_rsa_context const *ctx, int is_priv, + int blinding_needed ) +{ +#if !defined(MBEDTLS_RSA_NO_CRT) + /* blinding_needed is only used for NO_CRT to decide whether + * P,Q need to be present or not. */ + ((void) blinding_needed); +#endif + + if( ctx->len != mbedtls_mpi_size( &ctx->N ) || + ctx->len > MBEDTLS_MPI_MAX_SIZE ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + } + + /* + * 1. Modular exponentiation needs positive, odd moduli. + */ + + /* Modular exponentiation wrt. N is always used for + * RSA public key operations. */ + if( mbedtls_mpi_cmp_int( &ctx->N, 0 ) <= 0 || + mbedtls_mpi_get_bit( &ctx->N, 0 ) == 0 ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + } + +#if !defined(MBEDTLS_RSA_NO_CRT) + /* Modular exponentiation for P and Q is only + * used for private key operations and if CRT + * is used. */ + if( is_priv && + ( mbedtls_mpi_cmp_int( &ctx->P, 0 ) <= 0 || + mbedtls_mpi_get_bit( &ctx->P, 0 ) == 0 || + mbedtls_mpi_cmp_int( &ctx->Q, 0 ) <= 0 || + mbedtls_mpi_get_bit( &ctx->Q, 0 ) == 0 ) ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + } +#endif /* !MBEDTLS_RSA_NO_CRT */ + + /* + * 2. Exponents must be positive + */ + + /* Always need E for public key operations */ + if( mbedtls_mpi_cmp_int( &ctx->E, 0 ) <= 0 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_RSA_NO_CRT) + /* For private key operations, use D or DP & DQ + * as (unblinded) exponents. */ + if( is_priv && mbedtls_mpi_cmp_int( &ctx->D, 0 ) <= 0 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); +#else + if( is_priv && + ( mbedtls_mpi_cmp_int( &ctx->DP, 0 ) <= 0 || + mbedtls_mpi_cmp_int( &ctx->DQ, 0 ) <= 0 ) ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + } +#endif /* MBEDTLS_RSA_NO_CRT */ + + /* Blinding shouldn't make exponents negative either, + * so check that P, Q >= 1 if that hasn't yet been + * done as part of 1. */ +#if defined(MBEDTLS_RSA_NO_CRT) + if( is_priv && blinding_needed && + ( mbedtls_mpi_cmp_int( &ctx->P, 0 ) <= 0 || + mbedtls_mpi_cmp_int( &ctx->Q, 0 ) <= 0 ) ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + } +#endif + + /* It wouldn't lead to an error if it wasn't satisfied, + * but check for QP >= 1 nonetheless. */ +#if !defined(MBEDTLS_RSA_NO_CRT) + if( is_priv && + mbedtls_mpi_cmp_int( &ctx->QP, 0 ) <= 0 ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + } +#endif + + return( 0 ); +} + +int mbedtls_rsa_complete( mbedtls_rsa_context *ctx ) +{ + int ret = 0; + + const int have_N = ( mbedtls_mpi_cmp_int( &ctx->N, 0 ) != 0 ); + const int have_P = ( mbedtls_mpi_cmp_int( &ctx->P, 0 ) != 0 ); + const int have_Q = ( mbedtls_mpi_cmp_int( &ctx->Q, 0 ) != 0 ); + const int have_D = ( mbedtls_mpi_cmp_int( &ctx->D, 0 ) != 0 ); + const int have_E = ( mbedtls_mpi_cmp_int( &ctx->E, 0 ) != 0 ); + + /* + * Check whether provided parameters are enough + * to deduce all others. The following incomplete + * parameter sets for private keys are supported: + * + * (1) P, Q missing. + * (2) D and potentially N missing. + * + */ + + const int n_missing = have_P && have_Q && have_D && have_E; + const int pq_missing = have_N && !have_P && !have_Q && have_D && have_E; + const int d_missing = have_P && have_Q && !have_D && have_E; + const int is_pub = have_N && !have_P && !have_Q && !have_D && have_E; + + /* These three alternatives are mutually exclusive */ + const int is_priv = n_missing || pq_missing || d_missing; + + if( !is_priv && !is_pub ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + /* + * Step 1: Deduce N if P, Q are provided. + */ + + if( !have_N && have_P && have_Q ) + { + if( ( ret = mbedtls_mpi_mul_mpi( &ctx->N, &ctx->P, + &ctx->Q ) ) != 0 ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA + ret ); + } + + ctx->len = mbedtls_mpi_size( &ctx->N ); + } + + /* + * Step 2: Deduce and verify all remaining core parameters. + */ + + if( pq_missing ) + { + ret = mbedtls_rsa_deduce_primes( &ctx->N, &ctx->E, &ctx->D, + &ctx->P, &ctx->Q ); + if( ret != 0 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA + ret ); + + } + else if( d_missing ) + { + if( ( ret = mbedtls_rsa_deduce_private_exponent( &ctx->P, + &ctx->Q, + &ctx->E, + &ctx->D ) ) != 0 ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA + ret ); + } + } + + /* + * Step 3: Deduce all additional parameters specific + * to our current RSA implementation. + */ + +#if !defined(MBEDTLS_RSA_NO_CRT) + if( is_priv ) + { + ret = mbedtls_rsa_deduce_crt( &ctx->P, &ctx->Q, &ctx->D, + &ctx->DP, &ctx->DQ, &ctx->QP ); + if( ret != 0 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA + ret ); + } +#endif /* MBEDTLS_RSA_NO_CRT */ + + /* + * Step 3: Basic sanity checks + */ + + return( rsa_check_context( ctx, is_priv, 1 ) ); +} + +int mbedtls_rsa_export_raw( const mbedtls_rsa_context *ctx, + unsigned char *N, size_t N_len, + unsigned char *P, size_t P_len, + unsigned char *Q, size_t Q_len, + unsigned char *D, size_t D_len, + unsigned char *E, size_t E_len ) +{ + int ret = 0; + + /* Check if key is private or public */ + const int is_priv = + mbedtls_mpi_cmp_int( &ctx->N, 0 ) != 0 && + mbedtls_mpi_cmp_int( &ctx->P, 0 ) != 0 && + mbedtls_mpi_cmp_int( &ctx->Q, 0 ) != 0 && + mbedtls_mpi_cmp_int( &ctx->D, 0 ) != 0 && + mbedtls_mpi_cmp_int( &ctx->E, 0 ) != 0; + + if( !is_priv ) + { + /* If we're trying to export private parameters for a public key, + * something must be wrong. */ + if( P != NULL || Q != NULL || D != NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + } + + if( N != NULL ) + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->N, N, N_len ) ); + + if( P != NULL ) + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->P, P, P_len ) ); + + if( Q != NULL ) + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->Q, Q, Q_len ) ); + + if( D != NULL ) + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->D, D, D_len ) ); + + if( E != NULL ) + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->E, E, E_len ) ); + +cleanup: + + return( ret ); +} + +int mbedtls_rsa_export( const mbedtls_rsa_context *ctx, + mbedtls_mpi *N, mbedtls_mpi *P, mbedtls_mpi *Q, + mbedtls_mpi *D, mbedtls_mpi *E ) +{ + int ret; + + /* Check if key is private or public */ + int is_priv = + mbedtls_mpi_cmp_int( &ctx->N, 0 ) != 0 && + mbedtls_mpi_cmp_int( &ctx->P, 0 ) != 0 && + mbedtls_mpi_cmp_int( &ctx->Q, 0 ) != 0 && + mbedtls_mpi_cmp_int( &ctx->D, 0 ) != 0 && + mbedtls_mpi_cmp_int( &ctx->E, 0 ) != 0; + + if( !is_priv ) + { + /* If we're trying to export private parameters for a public key, + * something must be wrong. */ + if( P != NULL || Q != NULL || D != NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + } + + /* Export all requested core parameters. */ + + if( ( N != NULL && ( ret = mbedtls_mpi_copy( N, &ctx->N ) ) != 0 ) || + ( P != NULL && ( ret = mbedtls_mpi_copy( P, &ctx->P ) ) != 0 ) || + ( Q != NULL && ( ret = mbedtls_mpi_copy( Q, &ctx->Q ) ) != 0 ) || + ( D != NULL && ( ret = mbedtls_mpi_copy( D, &ctx->D ) ) != 0 ) || + ( E != NULL && ( ret = mbedtls_mpi_copy( E, &ctx->E ) ) != 0 ) ) + { + return( ret ); + } + + return( 0 ); +} + +/* + * Export CRT parameters + * This must also be implemented if CRT is not used, for being able to + * write DER encoded RSA keys. The helper function mbedtls_rsa_deduce_crt + * can be used in this case. + */ +int mbedtls_rsa_export_crt( const mbedtls_rsa_context *ctx, + mbedtls_mpi *DP, mbedtls_mpi *DQ, mbedtls_mpi *QP ) +{ + int ret; + + /* Check if key is private or public */ + int is_priv = + mbedtls_mpi_cmp_int( &ctx->N, 0 ) != 0 && + mbedtls_mpi_cmp_int( &ctx->P, 0 ) != 0 && + mbedtls_mpi_cmp_int( &ctx->Q, 0 ) != 0 && + mbedtls_mpi_cmp_int( &ctx->D, 0 ) != 0 && + mbedtls_mpi_cmp_int( &ctx->E, 0 ) != 0; + + if( !is_priv ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + +#if !defined(MBEDTLS_RSA_NO_CRT) + /* Export all requested blinding parameters. */ + if( ( DP != NULL && ( ret = mbedtls_mpi_copy( DP, &ctx->DP ) ) != 0 ) || + ( DQ != NULL && ( ret = mbedtls_mpi_copy( DQ, &ctx->DQ ) ) != 0 ) || + ( QP != NULL && ( ret = mbedtls_mpi_copy( QP, &ctx->QP ) ) != 0 ) ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA + ret ); + } +#else + if( ( ret = mbedtls_rsa_deduce_crt( &ctx->P, &ctx->Q, &ctx->D, + DP, DQ, QP ) ) != 0 ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA + ret ); + } +#endif + + return( 0 ); +} + +/* + * Initialize an RSA context + */ +void mbedtls_rsa_init( mbedtls_rsa_context *ctx, + int padding, + int hash_id ) +{ + memset( ctx, 0, sizeof( mbedtls_rsa_context ) ); + + mbedtls_rsa_set_padding( ctx, padding, hash_id ); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init( &ctx->mutex ); +#endif +} + +/* + * Set padding for an existing RSA context + */ +void mbedtls_rsa_set_padding( mbedtls_rsa_context *ctx, int padding, int hash_id ) +{ + ctx->padding = padding; + ctx->hash_id = hash_id; +} + +/* + * Get length in bytes of RSA modulus + */ + +size_t mbedtls_rsa_get_len( const mbedtls_rsa_context *ctx ) +{ + return( ctx->len ); +} + + +#if defined(MBEDTLS_GENPRIME) + +/* + * Generate an RSA keypair + * + * This generation method follows the RSA key pair generation procedure of + * FIPS 186-4 if 2^16 < exponent < 2^256 and nbits = 2048 or nbits = 3072. + */ +int mbedtls_rsa_gen_key( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + unsigned int nbits, int exponent ) +{ + int ret; + mbedtls_mpi H, G, L; + + if( f_rng == NULL || nbits < 128 || exponent < 3 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + if( nbits % 2 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + mbedtls_mpi_init( &H ); + mbedtls_mpi_init( &G ); + mbedtls_mpi_init( &L ); + + /* + * find primes P and Q with Q < P so that: + * 1. |P-Q| > 2^( nbits / 2 - 100 ) + * 2. GCD( E, (P-1)*(Q-1) ) == 1 + * 3. E^-1 mod LCM(P-1, Q-1) > 2^( nbits / 2 ) + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->E, exponent ) ); + + do + { + MBEDTLS_MPI_CHK( mbedtls_mpi_gen_prime( &ctx->P, nbits >> 1, 0, + f_rng, p_rng ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_gen_prime( &ctx->Q, nbits >> 1, 0, + f_rng, p_rng ) ); + + /* make sure the difference between p and q is not too small (FIPS 186-4 §B.3.3 step 5.4) */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &H, &ctx->P, &ctx->Q ) ); + if( mbedtls_mpi_bitlen( &H ) <= ( ( nbits >= 200 ) ? ( ( nbits >> 1 ) - 99 ) : 0 ) ) + continue; + + /* not required by any standards, but some users rely on the fact that P > Q */ + if( H.s < 0 ) + mbedtls_mpi_swap( &ctx->P, &ctx->Q ); + + /* Temporarily replace P,Q by P-1, Q-1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &ctx->P, &ctx->P, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &ctx->Q, &ctx->Q, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &H, &ctx->P, &ctx->Q ) ); + + /* check GCD( E, (P-1)*(Q-1) ) == 1 (FIPS 186-4 §B.3.1 criterion 2(a)) */ + MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G, &ctx->E, &H ) ); + if( mbedtls_mpi_cmp_int( &G, 1 ) != 0 ) + continue; + + /* compute smallest possible D = E^-1 mod LCM(P-1, Q-1) (FIPS 186-4 §B.3.1 criterion 3(b)) */ + MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G, &ctx->P, &ctx->Q ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( &L, NULL, &H, &G ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->D, &ctx->E, &L ) ); + + if( mbedtls_mpi_bitlen( &ctx->D ) <= ( ( nbits + 1 ) / 2 ) ) // (FIPS 186-4 §B.3.1 criterion 3(a)) + continue; + + break; + } + while( 1 ); + + /* Restore P,Q */ + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( &ctx->P, &ctx->P, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( &ctx->Q, &ctx->Q, 1 ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->N, &ctx->P, &ctx->Q ) ); + + ctx->len = mbedtls_mpi_size( &ctx->N ); + +#if !defined(MBEDTLS_RSA_NO_CRT) + /* + * DP = D mod (P - 1) + * DQ = D mod (Q - 1) + * QP = Q^-1 mod P + */ + MBEDTLS_MPI_CHK( mbedtls_rsa_deduce_crt( &ctx->P, &ctx->Q, &ctx->D, + &ctx->DP, &ctx->DQ, &ctx->QP ) ); +#endif /* MBEDTLS_RSA_NO_CRT */ + + /* Double-check */ + MBEDTLS_MPI_CHK( mbedtls_rsa_check_privkey( ctx ) ); + +cleanup: + + mbedtls_mpi_free( &H ); + mbedtls_mpi_free( &G ); + mbedtls_mpi_free( &L ); + + if( ret != 0 ) + { + mbedtls_rsa_free( ctx ); + return( MBEDTLS_ERR_RSA_KEY_GEN_FAILED + ret ); + } + + return( 0 ); +} + +#endif /* MBEDTLS_GENPRIME */ + +/* + * Check a public RSA key + */ +int mbedtls_rsa_check_pubkey( const mbedtls_rsa_context *ctx ) +{ + if( rsa_check_context( ctx, 0 /* public */, 0 /* no blinding */ ) != 0 ) + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + + if( mbedtls_mpi_bitlen( &ctx->N ) < 128 ) + { + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + } + + if( mbedtls_mpi_get_bit( &ctx->E, 0 ) == 0 || + mbedtls_mpi_bitlen( &ctx->E ) < 2 || + mbedtls_mpi_cmp_mpi( &ctx->E, &ctx->N ) >= 0 ) + { + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + } + + return( 0 ); +} + +/* + * Check for the consistency of all fields in an RSA private key context + */ +int mbedtls_rsa_check_privkey( const mbedtls_rsa_context *ctx ) +{ + if( mbedtls_rsa_check_pubkey( ctx ) != 0 || + rsa_check_context( ctx, 1 /* private */, 1 /* blinding */ ) != 0 ) + { + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + } + + if( mbedtls_rsa_validate_params( &ctx->N, &ctx->P, &ctx->Q, + &ctx->D, &ctx->E, NULL, NULL ) != 0 ) + { + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + } + +#if !defined(MBEDTLS_RSA_NO_CRT) + else if( mbedtls_rsa_validate_crt( &ctx->P, &ctx->Q, &ctx->D, + &ctx->DP, &ctx->DQ, &ctx->QP ) != 0 ) + { + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + } +#endif + + return( 0 ); +} + +/* + * Check if contexts holding a public and private key match + */ +int mbedtls_rsa_check_pub_priv( const mbedtls_rsa_context *pub, + const mbedtls_rsa_context *prv ) +{ + if( mbedtls_rsa_check_pubkey( pub ) != 0 || + mbedtls_rsa_check_privkey( prv ) != 0 ) + { + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + } + + if( mbedtls_mpi_cmp_mpi( &pub->N, &prv->N ) != 0 || + mbedtls_mpi_cmp_mpi( &pub->E, &prv->E ) != 0 ) + { + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + } + + return( 0 ); +} + +/* + * Do an RSA public key operation + */ +int mbedtls_rsa_public( mbedtls_rsa_context *ctx, + const unsigned char *input, + unsigned char *output ) +{ + int ret; + size_t olen; + mbedtls_mpi T; + + if( rsa_check_context( ctx, 0 /* public */, 0 /* no blinding */ ) ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + mbedtls_mpi_init( &T ); + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &T, input, ctx->len ) ); + + if( mbedtls_mpi_cmp_mpi( &T, &ctx->N ) >= 0 ) + { + ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + goto cleanup; + } + + olen = ctx->len; + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &T, &T, &ctx->E, &ctx->N, &ctx->RN ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &T, output, olen ) ); + +cleanup: +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + mbedtls_mpi_free( &T ); + + if( ret != 0 ) + return( MBEDTLS_ERR_RSA_PUBLIC_FAILED + ret ); + + return( 0 ); +} + +/* + * Generate or update blinding values, see section 10 of: + * KOCHER, Paul C. Timing attacks on implementations of Diffie-Hellman, RSA, + * DSS, and other systems. In : Advances in Cryptology-CRYPTO'96. Springer + * Berlin Heidelberg, 1996. p. 104-113. + */ +static int rsa_prepare_blinding( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret, count = 0; + + if( ctx->Vf.p != NULL ) + { + /* We already have blinding values, just update them by squaring */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vi, &ctx->Vi, &ctx->Vi ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vi, &ctx->Vi, &ctx->N ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vf, &ctx->Vf, &ctx->Vf ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vf, &ctx->Vf, &ctx->N ) ); + + goto cleanup; + } + + /* Unblinding value: Vf = random number, invertible mod N */ + do { + if( count++ > 10 ) + return( MBEDTLS_ERR_RSA_RNG_FAILED ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->Vf, ctx->len - 1, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &ctx->Vi, &ctx->Vf, &ctx->N ) ); + } while( mbedtls_mpi_cmp_int( &ctx->Vi, 1 ) != 0 ); + + /* Blinding value: Vi = Vf^(-e) mod N */ + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->Vi, &ctx->Vf, &ctx->N ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->Vi, &ctx->Vi, &ctx->E, &ctx->N, &ctx->RN ) ); + + +cleanup: + return( ret ); +} + +/* + * Exponent blinding supposed to prevent side-channel attacks using multiple + * traces of measurements to recover the RSA key. The more collisions are there, + * the more bits of the key can be recovered. See [3]. + * + * Collecting n collisions with m bit long blinding value requires 2^(m-m/n) + * observations on avarage. + * + * For example with 28 byte blinding to achieve 2 collisions the adversary has + * to make 2^112 observations on avarage. + * + * (With the currently (as of 2017 April) known best algorithms breaking 2048 + * bit RSA requires approximately as much time as trying out 2^112 random keys. + * Thus in this sense with 28 byte blinding the security is not reduced by + * side-channel attacks like the one in [3]) + * + * This countermeasure does not help if the key recovery is possible with a + * single trace. + */ +#define RSA_EXPONENT_BLINDING 28 + +/* + * Do an RSA private key operation + */ +int mbedtls_rsa_private( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + const unsigned char *input, + unsigned char *output ) +{ + int ret; + size_t olen; + + /* Temporary holding the result */ + mbedtls_mpi T; + + /* Temporaries holding P-1, Q-1 and the + * exponent blinding factor, respectively. */ + mbedtls_mpi P1, Q1, R; + +#if !defined(MBEDTLS_RSA_NO_CRT) + /* Temporaries holding the results mod p resp. mod q. */ + mbedtls_mpi TP, TQ; + + /* Temporaries holding the blinded exponents for + * the mod p resp. mod q computation (if used). */ + mbedtls_mpi DP_blind, DQ_blind; + + /* Pointers to actual exponents to be used - either the unblinded + * or the blinded ones, depending on the presence of a PRNG. */ + mbedtls_mpi *DP = &ctx->DP; + mbedtls_mpi *DQ = &ctx->DQ; +#else + /* Temporary holding the blinded exponent (if used). */ + mbedtls_mpi D_blind; + + /* Pointer to actual exponent to be used - either the unblinded + * or the blinded one, depending on the presence of a PRNG. */ + mbedtls_mpi *D = &ctx->D; +#endif /* MBEDTLS_RSA_NO_CRT */ + + /* Temporaries holding the initial input and the double + * checked result; should be the same in the end. */ + mbedtls_mpi I, C; + + if( rsa_check_context( ctx, 1 /* private key checks */, + f_rng != NULL /* blinding y/n */ ) != 0 ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + } + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + /* MPI Initialization */ + mbedtls_mpi_init( &T ); + + mbedtls_mpi_init( &P1 ); + mbedtls_mpi_init( &Q1 ); + mbedtls_mpi_init( &R ); + + if( f_rng != NULL ) + { +#if defined(MBEDTLS_RSA_NO_CRT) + mbedtls_mpi_init( &D_blind ); +#else + mbedtls_mpi_init( &DP_blind ); + mbedtls_mpi_init( &DQ_blind ); +#endif + } + +#if !defined(MBEDTLS_RSA_NO_CRT) + mbedtls_mpi_init( &TP ); mbedtls_mpi_init( &TQ ); +#endif + + mbedtls_mpi_init( &I ); + mbedtls_mpi_init( &C ); + + /* End of MPI initialization */ + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &T, input, ctx->len ) ); + if( mbedtls_mpi_cmp_mpi( &T, &ctx->N ) >= 0 ) + { + ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + goto cleanup; + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &I, &T ) ); + + if( f_rng != NULL ) + { + /* + * Blinding + * T = T * Vi mod N + */ + MBEDTLS_MPI_CHK( rsa_prepare_blinding( ctx, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &T, &ctx->Vi ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &T, &T, &ctx->N ) ); + + /* + * Exponent blinding + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &P1, &ctx->P, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &Q1, &ctx->Q, 1 ) ); + +#if defined(MBEDTLS_RSA_NO_CRT) + /* + * D_blind = ( P - 1 ) * ( Q - 1 ) * R + D + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &R, RSA_EXPONENT_BLINDING, + f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &D_blind, &P1, &Q1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &D_blind, &D_blind, &R ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &D_blind, &D_blind, &ctx->D ) ); + + D = &D_blind; +#else + /* + * DP_blind = ( P - 1 ) * R + DP + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &R, RSA_EXPONENT_BLINDING, + f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &DP_blind, &P1, &R ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &DP_blind, &DP_blind, + &ctx->DP ) ); + + DP = &DP_blind; + + /* + * DQ_blind = ( Q - 1 ) * R + DQ + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &R, RSA_EXPONENT_BLINDING, + f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &DQ_blind, &Q1, &R ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &DQ_blind, &DQ_blind, + &ctx->DQ ) ); + + DQ = &DQ_blind; +#endif /* MBEDTLS_RSA_NO_CRT */ + } + +#if defined(MBEDTLS_RSA_NO_CRT) + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &T, &T, D, &ctx->N, &ctx->RN ) ); +#else + /* + * Faster decryption using the CRT + * + * TP = input ^ dP mod P + * TQ = input ^ dQ mod Q + */ + + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &TP, &T, DP, &ctx->P, &ctx->RP ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &TQ, &T, DQ, &ctx->Q, &ctx->RQ ) ); + + /* + * T = (TP - TQ) * (Q^-1 mod P) mod P + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T, &TP, &TQ ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &TP, &T, &ctx->QP ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &T, &TP, &ctx->P ) ); + + /* + * T = TQ + T * Q + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &TP, &T, &ctx->Q ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &T, &TQ, &TP ) ); +#endif /* MBEDTLS_RSA_NO_CRT */ + + if( f_rng != NULL ) + { + /* + * Unblind + * T = T * Vf mod N + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &T, &ctx->Vf ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &T, &T, &ctx->N ) ); + } + + /* Verify the result to prevent glitching attacks. */ + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &C, &T, &ctx->E, + &ctx->N, &ctx->RN ) ); + if( mbedtls_mpi_cmp_mpi( &C, &I ) != 0 ) + { + ret = MBEDTLS_ERR_RSA_VERIFY_FAILED; + goto cleanup; + } + + olen = ctx->len; + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &T, output, olen ) ); + +cleanup: +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + mbedtls_mpi_free( &P1 ); + mbedtls_mpi_free( &Q1 ); + mbedtls_mpi_free( &R ); + + if( f_rng != NULL ) + { +#if defined(MBEDTLS_RSA_NO_CRT) + mbedtls_mpi_free( &D_blind ); +#else + mbedtls_mpi_free( &DP_blind ); + mbedtls_mpi_free( &DQ_blind ); +#endif + } + + mbedtls_mpi_free( &T ); + +#if !defined(MBEDTLS_RSA_NO_CRT) + mbedtls_mpi_free( &TP ); mbedtls_mpi_free( &TQ ); +#endif + + mbedtls_mpi_free( &C ); + mbedtls_mpi_free( &I ); + + if( ret != 0 ) + return( MBEDTLS_ERR_RSA_PRIVATE_FAILED + ret ); + + return( 0 ); +} + +#if defined(MBEDTLS_PKCS1_V21) +/** + * Generate and apply the MGF1 operation (from PKCS#1 v2.1) to a buffer. + * + * \param dst buffer to mask + * \param dlen length of destination buffer + * \param src source of the mask generation + * \param slen length of the source buffer + * \param md_ctx message digest context to use + */ +static int mgf_mask( unsigned char *dst, size_t dlen, unsigned char *src, + size_t slen, mbedtls_md_context_t *md_ctx ) +{ + unsigned char mask[MBEDTLS_MD_MAX_SIZE]; + unsigned char counter[4]; + unsigned char *p; + unsigned int hlen; + size_t i, use_len; + int ret = 0; + + memset( mask, 0, MBEDTLS_MD_MAX_SIZE ); + memset( counter, 0, 4 ); + + hlen = mbedtls_md_get_size( md_ctx->md_info ); + + /* Generate and apply dbMask */ + p = dst; + + while( dlen > 0 ) + { + use_len = hlen; + if( dlen < hlen ) + use_len = dlen; + + if( ( ret = mbedtls_md_starts( md_ctx ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md_update( md_ctx, src, slen ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md_update( md_ctx, counter, 4 ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md_finish( md_ctx, mask ) ) != 0 ) + goto exit; + + for( i = 0; i < use_len; ++i ) + *p++ ^= mask[i]; + + counter[3]++; + + dlen -= use_len; + } + +exit: + mbedtls_platform_zeroize( mask, sizeof( mask ) ); + + return( ret ); +} +#endif /* MBEDTLS_PKCS1_V21 */ + +#if defined(MBEDTLS_PKCS1_V21) +/* + * Implementation of the PKCS#1 v2.1 RSAES-OAEP-ENCRYPT function + */ +int mbedtls_rsa_rsaes_oaep_encrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + const unsigned char *label, size_t label_len, + size_t ilen, + const unsigned char *input, + unsigned char *output ) +{ + size_t olen; + int ret; + unsigned char *p = output; + unsigned int hlen; + const mbedtls_md_info_t *md_info; + mbedtls_md_context_t md_ctx; + + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V21 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + if( f_rng == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + md_info = mbedtls_md_info_from_type( (mbedtls_md_type_t) ctx->hash_id ); + if( md_info == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + olen = ctx->len; + hlen = mbedtls_md_get_size( md_info ); + + /* first comparison checks for overflow */ + if( ilen + 2 * hlen + 2 < ilen || olen < ilen + 2 * hlen + 2 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + memset( output, 0, olen ); + + *p++ = 0; + + /* Generate a random octet string seed */ + if( ( ret = f_rng( p_rng, p, hlen ) ) != 0 ) + return( MBEDTLS_ERR_RSA_RNG_FAILED + ret ); + + p += hlen; + + /* Construct DB */ + if( ( ret = mbedtls_md( md_info, label, label_len, p ) ) != 0 ) + return( ret ); + p += hlen; + p += olen - 2 * hlen - 2 - ilen; + *p++ = 1; + memcpy( p, input, ilen ); + + mbedtls_md_init( &md_ctx ); + if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 0 ) ) != 0 ) + goto exit; + + /* maskedDB: Apply dbMask to DB */ + if( ( ret = mgf_mask( output + hlen + 1, olen - hlen - 1, output + 1, hlen, + &md_ctx ) ) != 0 ) + goto exit; + + /* maskedSeed: Apply seedMask to seed */ + if( ( ret = mgf_mask( output + 1, hlen, output + hlen + 1, olen - hlen - 1, + &md_ctx ) ) != 0 ) + goto exit; + +exit: + mbedtls_md_free( &md_ctx ); + + if( ret != 0 ) + return( ret ); + + return( ( mode == MBEDTLS_RSA_PUBLIC ) + ? mbedtls_rsa_public( ctx, output, output ) + : mbedtls_rsa_private( ctx, f_rng, p_rng, output, output ) ); +} +#endif /* MBEDTLS_PKCS1_V21 */ + +#if defined(MBEDTLS_PKCS1_V15) +/* + * Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-ENCRYPT function + */ +int mbedtls_rsa_rsaes_pkcs1_v15_encrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t ilen, + const unsigned char *input, + unsigned char *output ) +{ + size_t nb_pad, olen; + int ret; + unsigned char *p = output; + + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + // We don't check p_rng because it won't be dereferenced here + if( f_rng == NULL || input == NULL || output == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + olen = ctx->len; + + /* first comparison checks for overflow */ + if( ilen + 11 < ilen || olen < ilen + 11 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + nb_pad = olen - 3 - ilen; + + *p++ = 0; + if( mode == MBEDTLS_RSA_PUBLIC ) + { + *p++ = MBEDTLS_RSA_CRYPT; + + while( nb_pad-- > 0 ) + { + int rng_dl = 100; + + do { + ret = f_rng( p_rng, p, 1 ); + } while( *p == 0 && --rng_dl && ret == 0 ); + + /* Check if RNG failed to generate data */ + if( rng_dl == 0 || ret != 0 ) + return( MBEDTLS_ERR_RSA_RNG_FAILED + ret ); + + p++; + } + } + else + { + *p++ = MBEDTLS_RSA_SIGN; + + while( nb_pad-- > 0 ) + *p++ = 0xFF; + } + + *p++ = 0; + memcpy( p, input, ilen ); + + return( ( mode == MBEDTLS_RSA_PUBLIC ) + ? mbedtls_rsa_public( ctx, output, output ) + : mbedtls_rsa_private( ctx, f_rng, p_rng, output, output ) ); +} +#endif /* MBEDTLS_PKCS1_V15 */ + +/* + * Add the message padding, then do an RSA operation + */ +int mbedtls_rsa_pkcs1_encrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t ilen, + const unsigned char *input, + unsigned char *output ) +{ + switch( ctx->padding ) + { +#if defined(MBEDTLS_PKCS1_V15) + case MBEDTLS_RSA_PKCS_V15: + return mbedtls_rsa_rsaes_pkcs1_v15_encrypt( ctx, f_rng, p_rng, mode, ilen, + input, output ); +#endif + +#if defined(MBEDTLS_PKCS1_V21) + case MBEDTLS_RSA_PKCS_V21: + return mbedtls_rsa_rsaes_oaep_encrypt( ctx, f_rng, p_rng, mode, NULL, 0, + ilen, input, output ); +#endif + + default: + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + } +} + +#if defined(MBEDTLS_PKCS1_V21) +/* + * Implementation of the PKCS#1 v2.1 RSAES-OAEP-DECRYPT function + */ +int mbedtls_rsa_rsaes_oaep_decrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + const unsigned char *label, size_t label_len, + size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len ) +{ + int ret; + size_t ilen, i, pad_len; + unsigned char *p, bad, pad_done; + unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; + unsigned char lhash[MBEDTLS_MD_MAX_SIZE]; + unsigned int hlen; + const mbedtls_md_info_t *md_info; + mbedtls_md_context_t md_ctx; + + /* + * Parameters sanity checks + */ + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V21 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + ilen = ctx->len; + + if( ilen < 16 || ilen > sizeof( buf ) ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + md_info = mbedtls_md_info_from_type( (mbedtls_md_type_t) ctx->hash_id ); + if( md_info == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + hlen = mbedtls_md_get_size( md_info ); + + // checking for integer underflow + if( 2 * hlen + 2 > ilen ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + /* + * RSA operation + */ + ret = ( mode == MBEDTLS_RSA_PUBLIC ) + ? mbedtls_rsa_public( ctx, input, buf ) + : mbedtls_rsa_private( ctx, f_rng, p_rng, input, buf ); + + if( ret != 0 ) + goto cleanup; + + /* + * Unmask data and generate lHash + */ + mbedtls_md_init( &md_ctx ); + if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 0 ) ) != 0 ) + { + mbedtls_md_free( &md_ctx ); + goto cleanup; + } + + /* seed: Apply seedMask to maskedSeed */ + if( ( ret = mgf_mask( buf + 1, hlen, buf + hlen + 1, ilen - hlen - 1, + &md_ctx ) ) != 0 || + /* DB: Apply dbMask to maskedDB */ + ( ret = mgf_mask( buf + hlen + 1, ilen - hlen - 1, buf + 1, hlen, + &md_ctx ) ) != 0 ) + { + mbedtls_md_free( &md_ctx ); + goto cleanup; + } + + mbedtls_md_free( &md_ctx ); + + /* Generate lHash */ + if( ( ret = mbedtls_md( md_info, label, label_len, lhash ) ) != 0 ) + goto cleanup; + + /* + * Check contents, in "constant-time" + */ + p = buf; + bad = 0; + + bad |= *p++; /* First byte must be 0 */ + + p += hlen; /* Skip seed */ + + /* Check lHash */ + for( i = 0; i < hlen; i++ ) + bad |= lhash[i] ^ *p++; + + /* Get zero-padding len, but always read till end of buffer + * (minus one, for the 01 byte) */ + pad_len = 0; + pad_done = 0; + for( i = 0; i < ilen - 2 * hlen - 2; i++ ) + { + pad_done |= p[i]; + pad_len += ((pad_done | (unsigned char)-pad_done) >> 7) ^ 1; + } + + p += pad_len; + bad |= *p++ ^ 0x01; + + /* + * The only information "leaked" is whether the padding was correct or not + * (eg, no data is copied if it was not correct). This meets the + * recommendations in PKCS#1 v2.2: an opponent cannot distinguish between + * the different error conditions. + */ + if( bad != 0 ) + { + ret = MBEDTLS_ERR_RSA_INVALID_PADDING; + goto cleanup; + } + + if( ilen - ( p - buf ) > output_max_len ) + { + ret = MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE; + goto cleanup; + } + + *olen = ilen - (p - buf); + memcpy( output, p, *olen ); + ret = 0; + +cleanup: + mbedtls_platform_zeroize( buf, sizeof( buf ) ); + mbedtls_platform_zeroize( lhash, sizeof( lhash ) ); + + return( ret ); +} +#endif /* MBEDTLS_PKCS1_V21 */ + +#if defined(MBEDTLS_PKCS1_V15) +/* + * Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-DECRYPT function + */ +int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len) +{ + int ret; + size_t ilen, pad_count = 0, i; + unsigned char *p, bad, pad_done = 0; + unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; + + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + ilen = ctx->len; + + if( ilen < 16 || ilen > sizeof( buf ) ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + ret = ( mode == MBEDTLS_RSA_PUBLIC ) + ? mbedtls_rsa_public( ctx, input, buf ) + : mbedtls_rsa_private( ctx, f_rng, p_rng, input, buf ); + + if( ret != 0 ) + goto cleanup; + + p = buf; + bad = 0; + + /* + * Check and get padding len in "constant-time" + */ + bad |= *p++; /* First byte must be 0 */ + + /* This test does not depend on secret data */ + if( mode == MBEDTLS_RSA_PRIVATE ) + { + bad |= *p++ ^ MBEDTLS_RSA_CRYPT; + + /* Get padding len, but always read till end of buffer + * (minus one, for the 00 byte) */ + for( i = 0; i < ilen - 3; i++ ) + { + pad_done |= ((p[i] | (unsigned char)-p[i]) >> 7) ^ 1; + pad_count += ((pad_done | (unsigned char)-pad_done) >> 7) ^ 1; + } + + p += pad_count; + bad |= *p++; /* Must be zero */ + } + else + { + bad |= *p++ ^ MBEDTLS_RSA_SIGN; + + /* Get padding len, but always read till end of buffer + * (minus one, for the 00 byte) */ + for( i = 0; i < ilen - 3; i++ ) + { + pad_done |= ( p[i] != 0xFF ); + pad_count += ( pad_done == 0 ); + } + + p += pad_count; + bad |= *p++; /* Must be zero */ + } + + bad |= ( pad_count < 8 ); + + if( bad ) + { + ret = MBEDTLS_ERR_RSA_INVALID_PADDING; + goto cleanup; + } + + if( ilen - ( p - buf ) > output_max_len ) + { + ret = MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE; + goto cleanup; + } + + *olen = ilen - (p - buf); + memcpy( output, p, *olen ); + ret = 0; + +cleanup: + mbedtls_platform_zeroize( buf, sizeof( buf ) ); + + return( ret ); +} +#endif /* MBEDTLS_PKCS1_V15 */ + +/* + * Do an RSA operation, then remove the message padding + */ +int mbedtls_rsa_pkcs1_decrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len) +{ + switch( ctx->padding ) + { +#if defined(MBEDTLS_PKCS1_V15) + case MBEDTLS_RSA_PKCS_V15: + return mbedtls_rsa_rsaes_pkcs1_v15_decrypt( ctx, f_rng, p_rng, mode, olen, + input, output, output_max_len ); +#endif + +#if defined(MBEDTLS_PKCS1_V21) + case MBEDTLS_RSA_PKCS_V21: + return mbedtls_rsa_rsaes_oaep_decrypt( ctx, f_rng, p_rng, mode, NULL, 0, + olen, input, output, + output_max_len ); +#endif + + default: + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + } +} + +#if defined(MBEDTLS_PKCS1_V21) +/* + * Implementation of the PKCS#1 v2.1 RSASSA-PSS-SIGN function + */ +int mbedtls_rsa_rsassa_pss_sign( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ) +{ + size_t olen; + unsigned char *p = sig; + unsigned char salt[MBEDTLS_MD_MAX_SIZE]; + unsigned int slen, hlen, offset = 0; + int ret; + size_t msb; + const mbedtls_md_info_t *md_info; + mbedtls_md_context_t md_ctx; + + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V21 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + if( f_rng == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + olen = ctx->len; + + if( md_alg != MBEDTLS_MD_NONE ) + { + /* Gather length of hash to sign */ + md_info = mbedtls_md_info_from_type( md_alg ); + if( md_info == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + hashlen = mbedtls_md_get_size( md_info ); + } + + md_info = mbedtls_md_info_from_type( (mbedtls_md_type_t) ctx->hash_id ); + if( md_info == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + hlen = mbedtls_md_get_size( md_info ); + slen = hlen; + + if( olen < hlen + slen + 2 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + memset( sig, 0, olen ); + + /* Generate salt of length slen */ + if( ( ret = f_rng( p_rng, salt, slen ) ) != 0 ) + return( MBEDTLS_ERR_RSA_RNG_FAILED + ret ); + + /* Note: EMSA-PSS encoding is over the length of N - 1 bits */ + msb = mbedtls_mpi_bitlen( &ctx->N ) - 1; + p += olen - hlen * 2 - 2; + *p++ = 0x01; + memcpy( p, salt, slen ); + p += slen; + + mbedtls_md_init( &md_ctx ); + if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 0 ) ) != 0 ) + goto exit; + + /* Generate H = Hash( M' ) */ + if( ( ret = mbedtls_md_starts( &md_ctx ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md_update( &md_ctx, p, 8 ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md_update( &md_ctx, hash, hashlen ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md_update( &md_ctx, salt, slen ) ) != 0 ) + goto exit; + if( ( ret = mbedtls_md_finish( &md_ctx, p ) ) != 0 ) + goto exit; + + /* Compensate for boundary condition when applying mask */ + if( msb % 8 == 0 ) + offset = 1; + + /* maskedDB: Apply dbMask to DB */ + if( ( ret = mgf_mask( sig + offset, olen - hlen - 1 - offset, p, hlen, + &md_ctx ) ) != 0 ) + goto exit; + + msb = mbedtls_mpi_bitlen( &ctx->N ) - 1; + sig[0] &= 0xFF >> ( olen * 8 - msb ); + + p += hlen; + *p++ = 0xBC; + + mbedtls_platform_zeroize( salt, sizeof( salt ) ); + +exit: + mbedtls_md_free( &md_ctx ); + + if( ret != 0 ) + return( ret ); + + return( ( mode == MBEDTLS_RSA_PUBLIC ) + ? mbedtls_rsa_public( ctx, sig, sig ) + : mbedtls_rsa_private( ctx, f_rng, p_rng, sig, sig ) ); +} +#endif /* MBEDTLS_PKCS1_V21 */ + +#if defined(MBEDTLS_PKCS1_V15) +/* + * Implementation of the PKCS#1 v2.1 RSASSA-PKCS1-V1_5-SIGN function + */ + +/* Construct a PKCS v1.5 encoding of a hashed message + * + * This is used both for signature generation and verification. + * + * Parameters: + * - md_alg: Identifies the hash algorithm used to generate the given hash; + * MBEDTLS_MD_NONE if raw data is signed. + * - hashlen: Length of hash in case hashlen is MBEDTLS_MD_NONE. + * - hash: Buffer containing the hashed message or the raw data. + * - dst_len: Length of the encoded message. + * - dst: Buffer to hold the encoded message. + * + * Assumptions: + * - hash has size hashlen if md_alg == MBEDTLS_MD_NONE. + * - hash has size corresponding to md_alg if md_alg != MBEDTLS_MD_NONE. + * - dst points to a buffer of size at least dst_len. + * + */ +static int rsa_rsassa_pkcs1_v15_encode( mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + size_t dst_len, + unsigned char *dst ) +{ + size_t oid_size = 0; + size_t nb_pad = dst_len; + unsigned char *p = dst; + const char *oid = NULL; + + /* Are we signing hashed or raw data? */ + if( md_alg != MBEDTLS_MD_NONE ) + { + const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( md_alg ); + if( md_info == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + if( mbedtls_oid_get_oid_by_md( md_alg, &oid, &oid_size ) != 0 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + hashlen = mbedtls_md_get_size( md_info ); + + /* Double-check that 8 + hashlen + oid_size can be used as a + * 1-byte ASN.1 length encoding and that there's no overflow. */ + if( 8 + hashlen + oid_size >= 0x80 || + 10 + hashlen < hashlen || + 10 + hashlen + oid_size < 10 + hashlen ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + /* + * Static bounds check: + * - Need 10 bytes for five tag-length pairs. + * (Insist on 1-byte length encodings to protect against variants of + * Bleichenbacher's forgery attack against lax PKCS#1v1.5 verification) + * - Need hashlen bytes for hash + * - Need oid_size bytes for hash alg OID. + */ + if( nb_pad < 10 + hashlen + oid_size ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + nb_pad -= 10 + hashlen + oid_size; + } + else + { + if( nb_pad < hashlen ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + nb_pad -= hashlen; + } + + /* Need space for signature header and padding delimiter (3 bytes), + * and 8 bytes for the minimal padding */ + if( nb_pad < 3 + 8 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + nb_pad -= 3; + + /* Now nb_pad is the amount of memory to be filled + * with padding, and at least 8 bytes long. */ + + /* Write signature header and padding */ + *p++ = 0; + *p++ = MBEDTLS_RSA_SIGN; + memset( p, 0xFF, nb_pad ); + p += nb_pad; + *p++ = 0; + + /* Are we signing raw data? */ + if( md_alg == MBEDTLS_MD_NONE ) + { + memcpy( p, hash, hashlen ); + return( 0 ); + } + + /* Signing hashed data, add corresponding ASN.1 structure + * + * DigestInfo ::= SEQUENCE { + * digestAlgorithm DigestAlgorithmIdentifier, + * digest Digest } + * DigestAlgorithmIdentifier ::= AlgorithmIdentifier + * Digest ::= OCTET STRING + * + * Schematic: + * TAG-SEQ + LEN [ TAG-SEQ + LEN [ TAG-OID + LEN [ OID ] + * TAG-NULL + LEN [ NULL ] ] + * TAG-OCTET + LEN [ HASH ] ] + */ + *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED; + *p++ = (unsigned char)( 0x08 + oid_size + hashlen ); + *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED; + *p++ = (unsigned char)( 0x04 + oid_size ); + *p++ = MBEDTLS_ASN1_OID; + *p++ = (unsigned char) oid_size; + memcpy( p, oid, oid_size ); + p += oid_size; + *p++ = MBEDTLS_ASN1_NULL; + *p++ = 0x00; + *p++ = MBEDTLS_ASN1_OCTET_STRING; + *p++ = (unsigned char) hashlen; + memcpy( p, hash, hashlen ); + p += hashlen; + + /* Just a sanity-check, should be automatic + * after the initial bounds check. */ + if( p != dst + dst_len ) + { + mbedtls_platform_zeroize( dst, dst_len ); + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + } + + return( 0 ); +} + +/* + * Do an RSA operation to sign the message digest + */ +int mbedtls_rsa_rsassa_pkcs1_v15_sign( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ) +{ + int ret; + unsigned char *sig_try = NULL, *verif = NULL; + + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + /* + * Prepare PKCS1-v1.5 encoding (padding and hash identifier) + */ + + if( ( ret = rsa_rsassa_pkcs1_v15_encode( md_alg, hashlen, hash, + ctx->len, sig ) ) != 0 ) + return( ret ); + + /* + * Call respective RSA primitive + */ + + if( mode == MBEDTLS_RSA_PUBLIC ) + { + /* Skip verification on a public key operation */ + return( mbedtls_rsa_public( ctx, sig, sig ) ); + } + + /* Private key operation + * + * In order to prevent Lenstra's attack, make the signature in a + * temporary buffer and check it before returning it. + */ + + sig_try = mbedtls_calloc( 1, ctx->len ); + if( sig_try == NULL ) + return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); + + verif = mbedtls_calloc( 1, ctx->len ); + if( verif == NULL ) + { + mbedtls_free( sig_try ); + return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); + } + + MBEDTLS_MPI_CHK( mbedtls_rsa_private( ctx, f_rng, p_rng, sig, sig_try ) ); + MBEDTLS_MPI_CHK( mbedtls_rsa_public( ctx, sig_try, verif ) ); + + if( mbedtls_safer_memcmp( verif, sig, ctx->len ) != 0 ) + { + ret = MBEDTLS_ERR_RSA_PRIVATE_FAILED; + goto cleanup; + } + + memcpy( sig, sig_try, ctx->len ); + +cleanup: + mbedtls_free( sig_try ); + mbedtls_free( verif ); + + return( ret ); +} +#endif /* MBEDTLS_PKCS1_V15 */ + +/* + * Do an RSA operation to sign the message digest + */ +int mbedtls_rsa_pkcs1_sign( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ) +{ + switch( ctx->padding ) + { +#if defined(MBEDTLS_PKCS1_V15) + case MBEDTLS_RSA_PKCS_V15: + return mbedtls_rsa_rsassa_pkcs1_v15_sign( ctx, f_rng, p_rng, mode, md_alg, + hashlen, hash, sig ); +#endif + +#if defined(MBEDTLS_PKCS1_V21) + case MBEDTLS_RSA_PKCS_V21: + return mbedtls_rsa_rsassa_pss_sign( ctx, f_rng, p_rng, mode, md_alg, + hashlen, hash, sig ); +#endif + + default: + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + } +} + +#if defined(MBEDTLS_PKCS1_V21) +/* + * Implementation of the PKCS#1 v2.1 RSASSA-PSS-VERIFY function + */ +int mbedtls_rsa_rsassa_pss_verify_ext( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + mbedtls_md_type_t mgf1_hash_id, + int expected_salt_len, + const unsigned char *sig ) +{ + int ret; + size_t siglen; + unsigned char *p; + unsigned char *hash_start; + unsigned char result[MBEDTLS_MD_MAX_SIZE]; + unsigned char zeros[8]; + unsigned int hlen; + size_t observed_salt_len, msb; + const mbedtls_md_info_t *md_info; + mbedtls_md_context_t md_ctx; + unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; + + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V21 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + siglen = ctx->len; + + if( siglen < 16 || siglen > sizeof( buf ) ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + ret = ( mode == MBEDTLS_RSA_PUBLIC ) + ? mbedtls_rsa_public( ctx, sig, buf ) + : mbedtls_rsa_private( ctx, f_rng, p_rng, sig, buf ); + + if( ret != 0 ) + return( ret ); + + p = buf; + + if( buf[siglen - 1] != 0xBC ) + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + + if( md_alg != MBEDTLS_MD_NONE ) + { + /* Gather length of hash to sign */ + md_info = mbedtls_md_info_from_type( md_alg ); + if( md_info == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + hashlen = mbedtls_md_get_size( md_info ); + } + + md_info = mbedtls_md_info_from_type( mgf1_hash_id ); + if( md_info == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + hlen = mbedtls_md_get_size( md_info ); + + memset( zeros, 0, 8 ); + + /* + * Note: EMSA-PSS verification is over the length of N - 1 bits + */ + msb = mbedtls_mpi_bitlen( &ctx->N ) - 1; + + if( buf[0] >> ( 8 - siglen * 8 + msb ) ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + /* Compensate for boundary condition when applying mask */ + if( msb % 8 == 0 ) + { + p++; + siglen -= 1; + } + + if( siglen < hlen + 2 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + hash_start = p + siglen - hlen - 1; + + mbedtls_md_init( &md_ctx ); + if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 0 ) ) != 0 ) + goto exit; + + ret = mgf_mask( p, siglen - hlen - 1, hash_start, hlen, &md_ctx ); + if( ret != 0 ) + goto exit; + + buf[0] &= 0xFF >> ( siglen * 8 - msb ); + + while( p < hash_start - 1 && *p == 0 ) + p++; + + if( *p++ != 0x01 ) + { + ret = MBEDTLS_ERR_RSA_INVALID_PADDING; + goto exit; + } + + observed_salt_len = hash_start - p; + + if( expected_salt_len != MBEDTLS_RSA_SALT_LEN_ANY && + observed_salt_len != (size_t) expected_salt_len ) + { + ret = MBEDTLS_ERR_RSA_INVALID_PADDING; + goto exit; + } + + /* + * Generate H = Hash( M' ) + */ + ret = mbedtls_md_starts( &md_ctx ); + if ( ret != 0 ) + goto exit; + ret = mbedtls_md_update( &md_ctx, zeros, 8 ); + if ( ret != 0 ) + goto exit; + ret = mbedtls_md_update( &md_ctx, hash, hashlen ); + if ( ret != 0 ) + goto exit; + ret = mbedtls_md_update( &md_ctx, p, observed_salt_len ); + if ( ret != 0 ) + goto exit; + ret = mbedtls_md_finish( &md_ctx, result ); + if ( ret != 0 ) + goto exit; + + if( memcmp( hash_start, result, hlen ) != 0 ) + { + ret = MBEDTLS_ERR_RSA_VERIFY_FAILED; + goto exit; + } + +exit: + mbedtls_md_free( &md_ctx ); + + return( ret ); +} + +/* + * Simplified PKCS#1 v2.1 RSASSA-PSS-VERIFY function + */ +int mbedtls_rsa_rsassa_pss_verify( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + const unsigned char *sig ) +{ + mbedtls_md_type_t mgf1_hash_id = ( ctx->hash_id != MBEDTLS_MD_NONE ) + ? (mbedtls_md_type_t) ctx->hash_id + : md_alg; + + return( mbedtls_rsa_rsassa_pss_verify_ext( ctx, f_rng, p_rng, mode, + md_alg, hashlen, hash, + mgf1_hash_id, MBEDTLS_RSA_SALT_LEN_ANY, + sig ) ); + +} +#endif /* MBEDTLS_PKCS1_V21 */ + +#if defined(MBEDTLS_PKCS1_V15) +/* + * Implementation of the PKCS#1 v2.1 RSASSA-PKCS1-v1_5-VERIFY function + */ +int mbedtls_rsa_rsassa_pkcs1_v15_verify( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + const unsigned char *sig ) +{ + int ret = 0; + const size_t sig_len = ctx->len; + unsigned char *encoded = NULL, *encoded_expected = NULL; + + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + /* + * Prepare expected PKCS1 v1.5 encoding of hash. + */ + + if( ( encoded = mbedtls_calloc( 1, sig_len ) ) == NULL || + ( encoded_expected = mbedtls_calloc( 1, sig_len ) ) == NULL ) + { + ret = MBEDTLS_ERR_MPI_ALLOC_FAILED; + goto cleanup; + } + + if( ( ret = rsa_rsassa_pkcs1_v15_encode( md_alg, hashlen, hash, sig_len, + encoded_expected ) ) != 0 ) + goto cleanup; + + /* + * Apply RSA primitive to get what should be PKCS1 encoded hash. + */ + + ret = ( mode == MBEDTLS_RSA_PUBLIC ) + ? mbedtls_rsa_public( ctx, sig, encoded ) + : mbedtls_rsa_private( ctx, f_rng, p_rng, sig, encoded ); + if( ret != 0 ) + goto cleanup; + + /* + * Compare + */ + + if( ( ret = mbedtls_safer_memcmp( encoded, encoded_expected, + sig_len ) ) != 0 ) + { + ret = MBEDTLS_ERR_RSA_VERIFY_FAILED; + goto cleanup; + } + +cleanup: + + if( encoded != NULL ) + { + mbedtls_platform_zeroize( encoded, sig_len ); + mbedtls_free( encoded ); + } + + if( encoded_expected != NULL ) + { + mbedtls_platform_zeroize( encoded_expected, sig_len ); + mbedtls_free( encoded_expected ); + } + + return( ret ); +} +#endif /* MBEDTLS_PKCS1_V15 */ + +/* + * Do an RSA operation and check the message digest + */ +int mbedtls_rsa_pkcs1_verify( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + const unsigned char *sig ) +{ + switch( ctx->padding ) + { +#if defined(MBEDTLS_PKCS1_V15) + case MBEDTLS_RSA_PKCS_V15: + return mbedtls_rsa_rsassa_pkcs1_v15_verify( ctx, f_rng, p_rng, mode, md_alg, + hashlen, hash, sig ); +#endif + +#if defined(MBEDTLS_PKCS1_V21) + case MBEDTLS_RSA_PKCS_V21: + return mbedtls_rsa_rsassa_pss_verify( ctx, f_rng, p_rng, mode, md_alg, + hashlen, hash, sig ); +#endif + + default: + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + } +} + +/* + * Copy the components of an RSA key + */ +int mbedtls_rsa_copy( mbedtls_rsa_context *dst, const mbedtls_rsa_context *src ) +{ + int ret; + + dst->ver = src->ver; + dst->len = src->len; + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->N, &src->N ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->E, &src->E ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->D, &src->D ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->P, &src->P ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->Q, &src->Q ) ); + +#if !defined(MBEDTLS_RSA_NO_CRT) + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->DP, &src->DP ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->DQ, &src->DQ ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->QP, &src->QP ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->RP, &src->RP ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->RQ, &src->RQ ) ); +#endif + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->RN, &src->RN ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->Vi, &src->Vi ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->Vf, &src->Vf ) ); + + dst->padding = src->padding; + dst->hash_id = src->hash_id; + +cleanup: + if( ret != 0 ) + mbedtls_rsa_free( dst ); + + return( ret ); +} + +/* + * Free the components of an RSA key + */ +void mbedtls_rsa_free( mbedtls_rsa_context *ctx ) +{ + mbedtls_mpi_free( &ctx->Vi ); mbedtls_mpi_free( &ctx->Vf ); + mbedtls_mpi_free( &ctx->RN ); mbedtls_mpi_free( &ctx->D ); + mbedtls_mpi_free( &ctx->Q ); mbedtls_mpi_free( &ctx->P ); + mbedtls_mpi_free( &ctx->E ); mbedtls_mpi_free( &ctx->N ); + +#if !defined(MBEDTLS_RSA_NO_CRT) + mbedtls_mpi_free( &ctx->RQ ); mbedtls_mpi_free( &ctx->RP ); + mbedtls_mpi_free( &ctx->QP ); mbedtls_mpi_free( &ctx->DQ ); + mbedtls_mpi_free( &ctx->DP ); +#endif /* MBEDTLS_RSA_NO_CRT */ + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_free( &ctx->mutex ); +#endif +} + +#endif /* !MBEDTLS_RSA_ALT */ + +#if defined(MBEDTLS_SELF_TEST) + +#include "mbedtls/sha1.h" + +/* + * Example RSA-1024 keypair, for test purposes + */ +#define KEY_LEN 128 + +#define RSA_N "9292758453063D803DD603D5E777D788" \ + "8ED1D5BF35786190FA2F23EBC0848AEA" \ + "DDA92CA6C3D80B32C4D109BE0F36D6AE" \ + "7130B9CED7ACDF54CFC7555AC14EEBAB" \ + "93A89813FBF3C4F8066D2D800F7C38A8" \ + "1AE31942917403FF4946B0A83D3D3E05" \ + "EE57C6F5F5606FB5D4BC6CD34EE0801A" \ + "5E94BB77B07507233A0BC7BAC8F90F79" + +#define RSA_E "10001" + +#define RSA_D "24BF6185468786FDD303083D25E64EFC" \ + "66CA472BC44D253102F8B4A9D3BFA750" \ + "91386C0077937FE33FA3252D28855837" \ + "AE1B484A8A9A45F7EE8C0C634F99E8CD" \ + "DF79C5CE07EE72C7F123142198164234" \ + "CABB724CF78B8173B9F880FC86322407" \ + "AF1FEDFDDE2BEB674CA15F3E81A1521E" \ + "071513A1E85B5DFA031F21ECAE91A34D" + +#define RSA_P "C36D0EB7FCD285223CFB5AABA5BDA3D8" \ + "2C01CAD19EA484A87EA4377637E75500" \ + "FCB2005C5C7DD6EC4AC023CDA285D796" \ + "C3D9E75E1EFC42488BB4F1D13AC30A57" + +#define RSA_Q "C000DF51A7C77AE8D7C7370C1FF55B69" \ + "E211C2B9E5DB1ED0BF61D0D9899620F4" \ + "910E4168387E3C30AA1E00C339A79508" \ + "8452DD96A9A5EA5D9DCA68DA636032AF" + +#define PT_LEN 24 +#define RSA_PT "\xAA\xBB\xCC\x03\x02\x01\x00\xFF\xFF\xFF\xFF\xFF" \ + "\x11\x22\x33\x0A\x0B\x0C\xCC\xDD\xDD\xDD\xDD\xDD" + +#if defined(MBEDTLS_PKCS1_V15) +static int myrand( void *rng_state, unsigned char *output, size_t len ) +{ +#if !defined(__OpenBSD__) + size_t i; + + if( rng_state != NULL ) + rng_state = NULL; + + for( i = 0; i < len; ++i ) + output[i] = rand(); +#else + if( rng_state != NULL ) + rng_state = NULL; + + arc4random_buf( output, len ); +#endif /* !OpenBSD */ + + return( 0 ); +} +#endif /* MBEDTLS_PKCS1_V15 */ + +/* + * Checkup routine + */ +int mbedtls_rsa_self_test( int verbose ) +{ + int ret = 0; +#if defined(MBEDTLS_PKCS1_V15) + size_t len; + mbedtls_rsa_context rsa; + unsigned char rsa_plaintext[PT_LEN]; + unsigned char rsa_decrypted[PT_LEN]; + unsigned char rsa_ciphertext[KEY_LEN]; +#if defined(MBEDTLS_SHA1_C) + unsigned char sha1sum[20]; +#endif + + mbedtls_mpi K; + + mbedtls_mpi_init( &K ); + mbedtls_rsa_init( &rsa, MBEDTLS_RSA_PKCS_V15, 0 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &K, 16, RSA_N ) ); + MBEDTLS_MPI_CHK( mbedtls_rsa_import( &rsa, &K, NULL, NULL, NULL, NULL ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &K, 16, RSA_P ) ); + MBEDTLS_MPI_CHK( mbedtls_rsa_import( &rsa, NULL, &K, NULL, NULL, NULL ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &K, 16, RSA_Q ) ); + MBEDTLS_MPI_CHK( mbedtls_rsa_import( &rsa, NULL, NULL, &K, NULL, NULL ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &K, 16, RSA_D ) ); + MBEDTLS_MPI_CHK( mbedtls_rsa_import( &rsa, NULL, NULL, NULL, &K, NULL ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &K, 16, RSA_E ) ); + MBEDTLS_MPI_CHK( mbedtls_rsa_import( &rsa, NULL, NULL, NULL, NULL, &K ) ); + + MBEDTLS_MPI_CHK( mbedtls_rsa_complete( &rsa ) ); + + if( verbose != 0 ) + mbedtls_printf( " RSA key validation: " ); + + if( mbedtls_rsa_check_pubkey( &rsa ) != 0 || + mbedtls_rsa_check_privkey( &rsa ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto cleanup; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n PKCS#1 encryption : " ); + + memcpy( rsa_plaintext, RSA_PT, PT_LEN ); + + if( mbedtls_rsa_pkcs1_encrypt( &rsa, myrand, NULL, MBEDTLS_RSA_PUBLIC, + PT_LEN, rsa_plaintext, + rsa_ciphertext ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto cleanup; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n PKCS#1 decryption : " ); + + if( mbedtls_rsa_pkcs1_decrypt( &rsa, myrand, NULL, MBEDTLS_RSA_PRIVATE, + &len, rsa_ciphertext, rsa_decrypted, + sizeof(rsa_decrypted) ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto cleanup; + } + + if( memcmp( rsa_decrypted, rsa_plaintext, len ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto cleanup; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + +#if defined(MBEDTLS_SHA1_C) + if( verbose != 0 ) + mbedtls_printf( " PKCS#1 data sign : " ); + + if( mbedtls_sha1_ret( rsa_plaintext, PT_LEN, sha1sum ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( mbedtls_rsa_pkcs1_sign( &rsa, myrand, NULL, + MBEDTLS_RSA_PRIVATE, MBEDTLS_MD_SHA1, 0, + sha1sum, rsa_ciphertext ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto cleanup; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n PKCS#1 sig. verify: " ); + + if( mbedtls_rsa_pkcs1_verify( &rsa, NULL, NULL, + MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA1, 0, + sha1sum, rsa_ciphertext ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto cleanup; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); +#endif /* MBEDTLS_SHA1_C */ + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +cleanup: + mbedtls_mpi_free( &K ); + mbedtls_rsa_free( &rsa ); +#else /* MBEDTLS_PKCS1_V15 */ + ((void) verbose); +#endif /* MBEDTLS_PKCS1_V15 */ + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_RSA_C */ diff --git a/common/mbedtls/rsa.h b/common/mbedtls/rsa.h new file mode 100644 index 00000000..7be7863c --- /dev/null +++ b/common/mbedtls/rsa.h @@ -0,0 +1,1133 @@ +/** + * \file rsa.h + * + * \brief This file provides an API for the RSA public-key cryptosystem. + * + * The RSA public-key cryptosystem is defined in Public-Key + * Cryptography Standards (PKCS) #1 v1.5: RSA Encryption + * and Public-Key Cryptography Standards (PKCS) #1 v2.1: + * RSA Cryptography Specifications. + * + */ +/* + * Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_RSA_H +#define MBEDTLS_RSA_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "bignum.h" +#include "md.h" + +#if defined(MBEDTLS_THREADING_C) +#include "threading.h" +#endif + +/* + * RSA Error codes + */ +#define MBEDTLS_ERR_RSA_BAD_INPUT_DATA -0x4080 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_RSA_INVALID_PADDING -0x4100 /**< Input data contains invalid padding and is rejected. */ +#define MBEDTLS_ERR_RSA_KEY_GEN_FAILED -0x4180 /**< Something failed during generation of a key. */ +#define MBEDTLS_ERR_RSA_KEY_CHECK_FAILED -0x4200 /**< Key failed to pass the validity check of the library. */ +#define MBEDTLS_ERR_RSA_PUBLIC_FAILED -0x4280 /**< The public key operation failed. */ +#define MBEDTLS_ERR_RSA_PRIVATE_FAILED -0x4300 /**< The private key operation failed. */ +#define MBEDTLS_ERR_RSA_VERIFY_FAILED -0x4380 /**< The PKCS#1 verification failed. */ +#define MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE -0x4400 /**< The output buffer for decryption is not large enough. */ +#define MBEDTLS_ERR_RSA_RNG_FAILED -0x4480 /**< The random generator failed to generate non-zeros. */ +#define MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION -0x4500 /**< The implementation does not offer the requested operation, for example, because of security violations or lack of functionality. */ +#define MBEDTLS_ERR_RSA_HW_ACCEL_FAILED -0x4580 /**< RSA hardware accelerator failed. */ + +/* + * RSA constants + */ +#define MBEDTLS_RSA_PUBLIC 0 /**< Request private key operation. */ +#define MBEDTLS_RSA_PRIVATE 1 /**< Request public key operation. */ + +#define MBEDTLS_RSA_PKCS_V15 0 /**< Use PKCS#1 v1.5 encoding. */ +#define MBEDTLS_RSA_PKCS_V21 1 /**< Use PKCS#1 v2.1 encoding. */ + +#define MBEDTLS_RSA_SIGN 1 /**< Identifier for RSA signature operations. */ +#define MBEDTLS_RSA_CRYPT 2 /**< Identifier for RSA encryption and decryption operations. */ + +#define MBEDTLS_RSA_SALT_LEN_ANY -1 + +/* + * The above constants may be used even if the RSA module is compile out, + * eg for alternative (PKCS#11) RSA implemenations in the PK layers. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_RSA_ALT) +// Regular implementation +// + +/** + * \brief The RSA context structure. + * + * \note Direct manipulation of the members of this structure + * is deprecated. All manipulation should instead be done through + * the public interface functions. + */ +typedef struct mbedtls_rsa_context +{ + int ver; /*!< Always 0.*/ + size_t len; /*!< The size of \p N in Bytes. */ + + mbedtls_mpi N; /*!< The public modulus. */ + mbedtls_mpi E; /*!< The public exponent. */ + + mbedtls_mpi D; /*!< The private exponent. */ + mbedtls_mpi P; /*!< The first prime factor. */ + mbedtls_mpi Q; /*!< The second prime factor. */ + + mbedtls_mpi DP; /*!< D % (P - 1). */ + mbedtls_mpi DQ; /*!< D % (Q - 1). */ + mbedtls_mpi QP; /*!< 1 / (Q % P). */ + + mbedtls_mpi RN; /*!< cached R^2 mod N. */ + + mbedtls_mpi RP; /*!< cached R^2 mod P. */ + mbedtls_mpi RQ; /*!< cached R^2 mod Q. */ + + mbedtls_mpi Vi; /*!< The cached blinding value. */ + mbedtls_mpi Vf; /*!< The cached un-blinding value. */ + + int padding; /*!< Selects padding mode: + #MBEDTLS_RSA_PKCS_V15 for 1.5 padding and + #MBEDTLS_RSA_PKCS_V21 for OAEP or PSS. */ + int hash_id; /*!< Hash identifier of mbedtls_md_type_t type, + as specified in md.h for use in the MGF + mask generating function used in the + EME-OAEP and EMSA-PSS encodings. */ +#if defined(MBEDTLS_THREADING_C) + mbedtls_threading_mutex_t mutex; /*!< Thread-safety mutex. */ +#endif +} +mbedtls_rsa_context; + +#else /* MBEDTLS_RSA_ALT */ +#include "rsa_alt.h" +#endif /* MBEDTLS_RSA_ALT */ + +/** + * \brief This function initializes an RSA context. + * + * \note Set padding to #MBEDTLS_RSA_PKCS_V21 for the RSAES-OAEP + * encryption scheme and the RSASSA-PSS signature scheme. + * + * \note The \p hash_id parameter is ignored when using + * #MBEDTLS_RSA_PKCS_V15 padding. + * + * \note The choice of padding mode is strictly enforced for private key + * operations, since there might be security concerns in + * mixing padding modes. For public key operations it is + * a default value, which can be overriden by calling specific + * \c rsa_rsaes_xxx or \c rsa_rsassa_xxx functions. + * + * \note The hash selected in \p hash_id is always used for OEAP + * encryption. For PSS signatures, it is always used for + * making signatures, but can be overriden for verifying them. + * If set to #MBEDTLS_MD_NONE, it is always overriden. + * + * \param ctx The RSA context to initialize. + * \param padding Selects padding mode: #MBEDTLS_RSA_PKCS_V15 or + * #MBEDTLS_RSA_PKCS_V21. + * \param hash_id The hash identifier of #mbedtls_md_type_t type, if + * \p padding is #MBEDTLS_RSA_PKCS_V21. + */ +void mbedtls_rsa_init( mbedtls_rsa_context *ctx, + int padding, + int hash_id); + +/** + * \brief This function imports a set of core parameters into an + * RSA context. + * + * \note This function can be called multiple times for successive + * imports, if the parameters are not simultaneously present. + * + * Any sequence of calls to this function should be followed + * by a call to mbedtls_rsa_complete(), which checks and + * completes the provided information to a ready-for-use + * public or private RSA key. + * + * \note See mbedtls_rsa_complete() for more information on which + * parameters are necessary to set up a private or public + * RSA key. + * + * \note The imported parameters are copied and need not be preserved + * for the lifetime of the RSA context being set up. + * + * \param ctx The initialized RSA context to store the parameters in. + * \param N The RSA modulus, or NULL. + * \param P The first prime factor of \p N, or NULL. + * \param Q The second prime factor of \p N, or NULL. + * \param D The private exponent, or NULL. + * \param E The public exponent, or NULL. + * + * \return \c 0 on success. + * \return A non-zero error code on failure. + */ +int mbedtls_rsa_import( mbedtls_rsa_context *ctx, + const mbedtls_mpi *N, + const mbedtls_mpi *P, const mbedtls_mpi *Q, + const mbedtls_mpi *D, const mbedtls_mpi *E ); + +/** + * \brief This function imports core RSA parameters, in raw big-endian + * binary format, into an RSA context. + * + * \note This function can be called multiple times for successive + * imports, if the parameters are not simultaneously present. + * + * Any sequence of calls to this function should be followed + * by a call to mbedtls_rsa_complete(), which checks and + * completes the provided information to a ready-for-use + * public or private RSA key. + * + * \note See mbedtls_rsa_complete() for more information on which + * parameters are necessary to set up a private or public + * RSA key. + * + * \note The imported parameters are copied and need not be preserved + * for the lifetime of the RSA context being set up. + * + * \param ctx The initialized RSA context to store the parameters in. + * \param N The RSA modulus, or NULL. + * \param N_len The Byte length of \p N, ignored if \p N == NULL. + * \param P The first prime factor of \p N, or NULL. + * \param P_len The Byte length of \p P, ignored if \p P == NULL. + * \param Q The second prime factor of \p N, or NULL. + * \param Q_len The Byte length of \p Q, ignored if \p Q == NULL. + * \param D The private exponent, or NULL. + * \param D_len The Byte length of \p D, ignored if \p D == NULL. + * \param E The public exponent, or NULL. + * \param E_len The Byte length of \p E, ignored if \p E == NULL. + * + * \return \c 0 on success. + * \return A non-zero error code on failure. + */ +int mbedtls_rsa_import_raw( mbedtls_rsa_context *ctx, + unsigned char const *N, size_t N_len, + unsigned char const *P, size_t P_len, + unsigned char const *Q, size_t Q_len, + unsigned char const *D, size_t D_len, + unsigned char const *E, size_t E_len ); + +/** + * \brief This function completes an RSA context from + * a set of imported core parameters. + * + * To setup an RSA public key, precisely \p N and \p E + * must have been imported. + * + * To setup an RSA private key, sufficient information must + * be present for the other parameters to be derivable. + * + * The default implementation supports the following: + *
  • Derive \p P, \p Q from \p N, \p D, \p E.
  • + *
  • Derive \p N, \p D from \p P, \p Q, \p E.
+ * Alternative implementations need not support these. + * + * If this function runs successfully, it guarantees that + * the RSA context can be used for RSA operations without + * the risk of failure or crash. + * + * \warning This function need not perform consistency checks + * for the imported parameters. In particular, parameters that + * are not needed by the implementation might be silently + * discarded and left unchecked. To check the consistency + * of the key material, see mbedtls_rsa_check_privkey(). + * + * \param ctx The initialized RSA context holding imported parameters. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_RSA_BAD_INPUT_DATA if the attempted derivations + * failed. + * + */ +int mbedtls_rsa_complete( mbedtls_rsa_context *ctx ); + +/** + * \brief This function exports the core parameters of an RSA key. + * + * If this function runs successfully, the non-NULL buffers + * pointed to by \p N, \p P, \p Q, \p D, and \p E are fully + * written, with additional unused space filled leading by + * zero Bytes. + * + * Possible reasons for returning + * #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION:
    + *
  • An alternative RSA implementation is in use, which + * stores the key externally, and either cannot or should + * not export it into RAM.
  • + *
  • A SW or HW implementation might not support a certain + * deduction. For example, \p P, \p Q from \p N, \p D, + * and \p E if the former are not part of the + * implementation.
+ * + * If the function fails due to an unsupported operation, + * the RSA context stays intact and remains usable. + * + * \param ctx The initialized RSA context. + * \param N The MPI to hold the RSA modulus, or NULL. + * \param P The MPI to hold the first prime factor of \p N, or NULL. + * \param Q The MPI to hold the second prime factor of \p N, or NULL. + * \param D The MPI to hold the private exponent, or NULL. + * \param E The MPI to hold the public exponent, or NULL. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION if exporting the + * requested parameters cannot be done due to missing + * functionality or because of security policies. + * \return A non-zero return code on any other failure. + * + */ +int mbedtls_rsa_export( const mbedtls_rsa_context *ctx, + mbedtls_mpi *N, mbedtls_mpi *P, mbedtls_mpi *Q, + mbedtls_mpi *D, mbedtls_mpi *E ); + +/** + * \brief This function exports core parameters of an RSA key + * in raw big-endian binary format. + * + * If this function runs successfully, the non-NULL buffers + * pointed to by \p N, \p P, \p Q, \p D, and \p E are fully + * written, with additional unused space filled leading by + * zero Bytes. + * + * Possible reasons for returning + * #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION:
    + *
  • An alternative RSA implementation is in use, which + * stores the key externally, and either cannot or should + * not export it into RAM.
  • + *
  • A SW or HW implementation might not support a certain + * deduction. For example, \p P, \p Q from \p N, \p D, + * and \p E if the former are not part of the + * implementation.
+ * If the function fails due to an unsupported operation, + * the RSA context stays intact and remains usable. + * + * \note The length parameters are ignored if the corresponding + * buffer pointers are NULL. + * + * \param ctx The initialized RSA context. + * \param N The Byte array to store the RSA modulus, or NULL. + * \param N_len The size of the buffer for the modulus. + * \param P The Byte array to hold the first prime factor of \p N, or + * NULL. + * \param P_len The size of the buffer for the first prime factor. + * \param Q The Byte array to hold the second prime factor of \p N, or + * NULL. + * \param Q_len The size of the buffer for the second prime factor. + * \param D The Byte array to hold the private exponent, or NULL. + * \param D_len The size of the buffer for the private exponent. + * \param E The Byte array to hold the public exponent, or NULL. + * \param E_len The size of the buffer for the public exponent. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION if exporting the + * requested parameters cannot be done due to missing + * functionality or because of security policies. + * \return A non-zero return code on any other failure. + */ +int mbedtls_rsa_export_raw( const mbedtls_rsa_context *ctx, + unsigned char *N, size_t N_len, + unsigned char *P, size_t P_len, + unsigned char *Q, size_t Q_len, + unsigned char *D, size_t D_len, + unsigned char *E, size_t E_len ); + +/** + * \brief This function exports CRT parameters of a private RSA key. + * + * \note Alternative RSA implementations not using CRT-parameters + * internally can implement this function based on + * mbedtls_rsa_deduce_opt(). + * + * \param ctx The initialized RSA context. + * \param DP The MPI to hold D modulo P-1, or NULL. + * \param DQ The MPI to hold D modulo Q-1, or NULL. + * \param QP The MPI to hold modular inverse of Q modulo P, or NULL. + * + * \return \c 0 on success. + * \return A non-zero error code on failure. + * + */ +int mbedtls_rsa_export_crt( const mbedtls_rsa_context *ctx, + mbedtls_mpi *DP, mbedtls_mpi *DQ, mbedtls_mpi *QP ); + +/** + * \brief This function sets padding for an already initialized RSA + * context. See mbedtls_rsa_init() for details. + * + * \param ctx The RSA context to be set. + * \param padding Selects padding mode: #MBEDTLS_RSA_PKCS_V15 or + * #MBEDTLS_RSA_PKCS_V21. + * \param hash_id The #MBEDTLS_RSA_PKCS_V21 hash identifier. + */ +void mbedtls_rsa_set_padding( mbedtls_rsa_context *ctx, int padding, + int hash_id); + +/** + * \brief This function retrieves the length of RSA modulus in Bytes. + * + * \param ctx The initialized RSA context. + * + * \return The length of the RSA modulus in Bytes. + * + */ +size_t mbedtls_rsa_get_len( const mbedtls_rsa_context *ctx ); + +/** + * \brief This function generates an RSA keypair. + * + * \note mbedtls_rsa_init() must be called before this function, + * to set up the RSA context. + * + * \param ctx The RSA context used to hold the key. + * \param f_rng The RNG function. + * \param p_rng The RNG context. + * \param nbits The size of the public key in bits. + * \param exponent The public exponent. For example, 65537. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_gen_key( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + unsigned int nbits, int exponent ); + +/** + * \brief This function checks if a context contains at least an RSA + * public key. + * + * If the function runs successfully, it is guaranteed that + * enough information is present to perform an RSA public key + * operation using mbedtls_rsa_public(). + * + * \param ctx The RSA context to check. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + * + */ +int mbedtls_rsa_check_pubkey( const mbedtls_rsa_context *ctx ); + +/** + * \brief This function checks if a context contains an RSA private key + * and perform basic consistency checks. + * + * \note The consistency checks performed by this function not only + * ensure that mbedtls_rsa_private() can be called successfully + * on the given context, but that the various parameters are + * mutually consistent with high probability, in the sense that + * mbedtls_rsa_public() and mbedtls_rsa_private() are inverses. + * + * \warning This function should catch accidental misconfigurations + * like swapping of parameters, but it cannot establish full + * trust in neither the quality nor the consistency of the key + * material that was used to setup the given RSA context: + *
  • Consistency: Imported parameters that are irrelevant + * for the implementation might be silently dropped. If dropped, + * the current function does not have access to them, + * and therefore cannot check them. See mbedtls_rsa_complete(). + * If you want to check the consistency of the entire + * content of an PKCS1-encoded RSA private key, for example, you + * should use mbedtls_rsa_validate_params() before setting + * up the RSA context. + * Additionally, if the implementation performs empirical checks, + * these checks substantiate but do not guarantee consistency.
  • + *
  • Quality: This function is not expected to perform + * extended quality assessments like checking that the prime + * factors are safe. Additionally, it is the responsibility of the + * user to ensure the trustworthiness of the source of his RSA + * parameters, which goes beyond what is effectively checkable + * by the library.
+ * + * \param ctx The RSA context to check. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_check_privkey( const mbedtls_rsa_context *ctx ); + +/** + * \brief This function checks a public-private RSA key pair. + * + * It checks each of the contexts, and makes sure they match. + * + * \param pub The RSA context holding the public key. + * \param prv The RSA context holding the private key. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_check_pub_priv( const mbedtls_rsa_context *pub, + const mbedtls_rsa_context *prv ); + +/** + * \brief This function performs an RSA public key operation. + * + * \note This function does not handle message padding. + * + * \note Make sure to set \p input[0] = 0 or ensure that + * input is smaller than \p N. + * + * \note The input and output buffers must be large + * enough. For example, 128 Bytes if RSA-1024 is used. + * + * \param ctx The RSA context. + * \param input The input buffer. + * \param output The output buffer. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_public( mbedtls_rsa_context *ctx, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief This function performs an RSA private key operation. + * + * \note The input and output buffers must be large + * enough. For example, 128 Bytes if RSA-1024 is used. + * + * \note Blinding is used if and only if a PRNG is provided. + * + * \note If blinding is used, both the base of exponentation + * and the exponent are blinded, providing protection + * against some side-channel attacks. + * + * \warning It is deprecated and a security risk to not provide + * a PRNG here and thereby prevent the use of blinding. + * Future versions of the library may enforce the presence + * of a PRNG. + * + * \param ctx The RSA context. + * \param f_rng The RNG function. Needed for blinding. + * \param p_rng The RNG context. + * \param input The input buffer. + * \param output The output buffer. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + * + */ +int mbedtls_rsa_private( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief This function adds the message padding, then performs an RSA + * operation. + * + * It is the generic wrapper for performing a PKCS#1 encryption + * operation using the \p mode from the context. + * + * \note The input and output buffers must be as large as the size + * of \p ctx->N. For example, 128 Bytes if RSA-1024 is used. + * + * \deprecated It is deprecated and discouraged to call this function + * in #MBEDTLS_RSA_PRIVATE mode. Future versions of the library + * are likely to remove the \p mode argument and have it + * implicitly set to #MBEDTLS_RSA_PUBLIC. + * + * \note Alternative implementations of RSA need not support + * mode being set to #MBEDTLS_RSA_PRIVATE and might instead + * return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION. + * + * \param ctx The RSA context. + * \param f_rng The RNG function. Needed for padding, PKCS#1 v2.1 + * encoding, and #MBEDTLS_RSA_PRIVATE. + * \param p_rng The RNG context. + * \param mode #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE. + * \param ilen The length of the plaintext. + * \param input The buffer holding the data to encrypt. + * \param output The buffer used to hold the ciphertext. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_pkcs1_encrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t ilen, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief This function performs a PKCS#1 v1.5 encryption operation + * (RSAES-PKCS1-v1_5-ENCRYPT). + * + * \note The output buffer must be as large as the size + * of \p ctx->N. For example, 128 Bytes if RSA-1024 is used. + * + * \deprecated It is deprecated and discouraged to call this function + * in #MBEDTLS_RSA_PRIVATE mode. Future versions of the library + * are likely to remove the \p mode argument and have it + * implicitly set to #MBEDTLS_RSA_PUBLIC. + * + * \note Alternative implementations of RSA need not support + * mode being set to #MBEDTLS_RSA_PRIVATE and might instead + * return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION. + * + * \param ctx The RSA context. + * \param f_rng The RNG function. Needed for padding and + * #MBEDTLS_RSA_PRIVATE. + * \param p_rng The RNG context. + * \param mode #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE. + * \param ilen The length of the plaintext. + * \param input The buffer holding the data to encrypt. + * \param output The buffer used to hold the ciphertext. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_rsaes_pkcs1_v15_encrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t ilen, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief This function performs a PKCS#1 v2.1 OAEP encryption + * operation (RSAES-OAEP-ENCRYPT). + * + * \note The output buffer must be as large as the size + * of ctx->N. For example, 128 Bytes if RSA-1024 is used. + * + * \deprecated It is deprecated and discouraged to call this function + * in #MBEDTLS_RSA_PRIVATE mode. Future versions of the library + * are likely to remove the \p mode argument and have it + * implicitly set to #MBEDTLS_RSA_PUBLIC. + * + * \note Alternative implementations of RSA need not support + * mode being set to #MBEDTLS_RSA_PRIVATE and might instead + * return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION. + * + * \param ctx The RSA context. + * \param f_rng The RNG function. Needed for padding and PKCS#1 v2.1 + * encoding and #MBEDTLS_RSA_PRIVATE. + * \param p_rng The RNG context. + * \param mode #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE. + * \param label The buffer holding the custom label to use. + * \param label_len The length of the label. + * \param ilen The length of the plaintext. + * \param input The buffer holding the data to encrypt. + * \param output The buffer used to hold the ciphertext. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_rsaes_oaep_encrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + const unsigned char *label, size_t label_len, + size_t ilen, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief This function performs an RSA operation, then removes the + * message padding. + * + * It is the generic wrapper for performing a PKCS#1 decryption + * operation using the \p mode from the context. + * + * \note The output buffer length \c output_max_len should be + * as large as the size \p ctx->len of \p ctx->N (for example, + * 128 Bytes if RSA-1024 is used) to be able to hold an + * arbitrary decrypted message. If it is not large enough to + * hold the decryption of the particular ciphertext provided, + * the function returns \c MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE. + * + * \note The input buffer must be as large as the size + * of \p ctx->N. For example, 128 Bytes if RSA-1024 is used. + * + * \deprecated It is deprecated and discouraged to call this function + * in #MBEDTLS_RSA_PUBLIC mode. Future versions of the library + * are likely to remove the \p mode argument and have it + * implicitly set to #MBEDTLS_RSA_PRIVATE. + * + * \note Alternative implementations of RSA need not support + * mode being set to #MBEDTLS_RSA_PUBLIC and might instead + * return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION. + * + * \param ctx The RSA context. + * \param f_rng The RNG function. Only needed for #MBEDTLS_RSA_PRIVATE. + * \param p_rng The RNG context. + * \param mode #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE. + * \param olen The length of the plaintext. + * \param input The buffer holding the encrypted data. + * \param output The buffer used to hold the plaintext. + * \param output_max_len The maximum length of the output buffer. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_pkcs1_decrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len ); + +/** + * \brief This function performs a PKCS#1 v1.5 decryption + * operation (RSAES-PKCS1-v1_5-DECRYPT). + * + * \note The output buffer length \c output_max_len should be + * as large as the size \p ctx->len of \p ctx->N, for example, + * 128 Bytes if RSA-1024 is used, to be able to hold an + * arbitrary decrypted message. If it is not large enough to + * hold the decryption of the particular ciphertext provided, + * the function returns #MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE. + * + * \note The input buffer must be as large as the size + * of \p ctx->N. For example, 128 Bytes if RSA-1024 is used. + * + * \deprecated It is deprecated and discouraged to call this function + * in #MBEDTLS_RSA_PUBLIC mode. Future versions of the library + * are likely to remove the \p mode argument and have it + * implicitly set to #MBEDTLS_RSA_PRIVATE. + * + * \note Alternative implementations of RSA need not support + * mode being set to #MBEDTLS_RSA_PUBLIC and might instead + * return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION. + * + * \param ctx The RSA context. + * \param f_rng The RNG function. Only needed for #MBEDTLS_RSA_PRIVATE. + * \param p_rng The RNG context. + * \param mode #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE. + * \param olen The length of the plaintext. + * \param input The buffer holding the encrypted data. + * \param output The buffer to hold the plaintext. + * \param output_max_len The maximum length of the output buffer. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + * + */ +int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len ); + +/** + * \brief This function performs a PKCS#1 v2.1 OAEP decryption + * operation (RSAES-OAEP-DECRYPT). + * + * \note The output buffer length \c output_max_len should be + * as large as the size \p ctx->len of \p ctx->N, for + * example, 128 Bytes if RSA-1024 is used, to be able to + * hold an arbitrary decrypted message. If it is not + * large enough to hold the decryption of the particular + * ciphertext provided, the function returns + * #MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE. + * + * \note The input buffer must be as large as the size + * of \p ctx->N. For example, 128 Bytes if RSA-1024 is used. + * + * \deprecated It is deprecated and discouraged to call this function + * in #MBEDTLS_RSA_PUBLIC mode. Future versions of the library + * are likely to remove the \p mode argument and have it + * implicitly set to #MBEDTLS_RSA_PRIVATE. + * + * \note Alternative implementations of RSA need not support + * mode being set to #MBEDTLS_RSA_PUBLIC and might instead + * return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION. + * + * \param ctx The RSA context. + * \param f_rng The RNG function. Only needed for #MBEDTLS_RSA_PRIVATE. + * \param p_rng The RNG context. + * \param mode #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE. + * \param label The buffer holding the custom label to use. + * \param label_len The length of the label. + * \param olen The length of the plaintext. + * \param input The buffer holding the encrypted data. + * \param output The buffer to hold the plaintext. + * \param output_max_len The maximum length of the output buffer. + * + * \return \c 0 on success. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_rsaes_oaep_decrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + const unsigned char *label, size_t label_len, + size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len ); + +/** + * \brief This function performs a private RSA operation to sign + * a message digest using PKCS#1. + * + * It is the generic wrapper for performing a PKCS#1 + * signature using the \p mode from the context. + * + * \note The \p sig buffer must be as large as the size + * of \p ctx->N. For example, 128 Bytes if RSA-1024 is used. + * + * \note For PKCS#1 v2.1 encoding, see comments on + * mbedtls_rsa_rsassa_pss_sign() for details on + * \p md_alg and \p hash_id. + * + * \deprecated It is deprecated and discouraged to call this function + * in #MBEDTLS_RSA_PUBLIC mode. Future versions of the library + * are likely to remove the \p mode argument and have it + * implicitly set to #MBEDTLS_RSA_PRIVATE. + * + * \note Alternative implementations of RSA need not support + * mode being set to #MBEDTLS_RSA_PUBLIC and might instead + * return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION. + * + * \param ctx The RSA context. + * \param f_rng The RNG function. Needed for PKCS#1 v2.1 encoding and for + * #MBEDTLS_RSA_PRIVATE. + * \param p_rng The RNG context. + * \param mode #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE. + * \param md_alg The message-digest algorithm used to hash the original data. + * Use #MBEDTLS_MD_NONE for signing raw data. + * \param hashlen The length of the message digest. Only used if \p md_alg is #MBEDTLS_MD_NONE. + * \param hash The buffer holding the message digest. + * \param sig The buffer to hold the ciphertext. + * + * \return \c 0 if the signing operation was successful. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_pkcs1_sign( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ); + +/** + * \brief This function performs a PKCS#1 v1.5 signature + * operation (RSASSA-PKCS1-v1_5-SIGN). + * + * \note The \p sig buffer must be as large as the size + * of \p ctx->N. For example, 128 Bytes if RSA-1024 is used. + * + * \deprecated It is deprecated and discouraged to call this function + * in #MBEDTLS_RSA_PUBLIC mode. Future versions of the library + * are likely to remove the \p mode argument and have it + * implicitly set to #MBEDTLS_RSA_PRIVATE. + * + * \note Alternative implementations of RSA need not support + * mode being set to #MBEDTLS_RSA_PUBLIC and might instead + * return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION. + * + * \param ctx The RSA context. + * \param f_rng The RNG function. Only needed for #MBEDTLS_RSA_PRIVATE. + * \param p_rng The RNG context. + * \param mode #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE. + * \param md_alg The message-digest algorithm used to hash the original data. + * Use #MBEDTLS_MD_NONE for signing raw data. + * \param hashlen The length of the message digest. Only used if \p md_alg is #MBEDTLS_MD_NONE. + * \param hash The buffer holding the message digest. + * \param sig The buffer to hold the ciphertext. + * + * \return \c 0 if the signing operation was successful. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_rsassa_pkcs1_v15_sign( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ); + +/** + * \brief This function performs a PKCS#1 v2.1 PSS signature + * operation (RSASSA-PSS-SIGN). + * + * \note The \p sig buffer must be as large as the size + * of \p ctx->N. For example, 128 Bytes if RSA-1024 is used. + * + * \note The \p hash_id in the RSA context is the one used for the + * encoding. \p md_alg in the function call is the type of hash + * that is encoded. According to RFC-3447: Public-Key + * Cryptography Standards (PKCS) #1 v2.1: RSA Cryptography + * Specifications it is advised to keep both hashes the + * same. + * + * \deprecated It is deprecated and discouraged to call this function + * in #MBEDTLS_RSA_PUBLIC mode. Future versions of the library + * are likely to remove the \p mode argument and have it + * implicitly set to #MBEDTLS_RSA_PRIVATE. + * + * \note Alternative implementations of RSA need not support + * mode being set to #MBEDTLS_RSA_PUBLIC and might instead + * return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION. + * + * \param ctx The RSA context. + * \param f_rng The RNG function. Needed for PKCS#1 v2.1 encoding and for + * #MBEDTLS_RSA_PRIVATE. + * \param p_rng The RNG context. + * \param mode #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE. + * \param md_alg The message-digest algorithm used to hash the original data. + * Use #MBEDTLS_MD_NONE for signing raw data. + * \param hashlen The length of the message digest. Only used if \p md_alg is #MBEDTLS_MD_NONE. + * \param hash The buffer holding the message digest. + * \param sig The buffer to hold the ciphertext. + * + * \return \c 0 if the signing operation was successful. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_rsassa_pss_sign( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ); + +/** + * \brief This function performs a public RSA operation and checks + * the message digest. + * + * This is the generic wrapper for performing a PKCS#1 + * verification using the mode from the context. + * + * \note The \p sig buffer must be as large as the size + * of \p ctx->N. For example, 128 Bytes if RSA-1024 is used. + * + * \note For PKCS#1 v2.1 encoding, see comments on + * mbedtls_rsa_rsassa_pss_verify() about \p md_alg and + * \p hash_id. + * + * \deprecated It is deprecated and discouraged to call this function + * in #MBEDTLS_RSA_PRIVATE mode. Future versions of the library + * are likely to remove the \p mode argument and have it + * set to #MBEDTLS_RSA_PUBLIC. + * + * \note Alternative implementations of RSA need not support + * mode being set to #MBEDTLS_RSA_PRIVATE and might instead + * return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION. + * + * \param ctx The RSA public key context. + * \param f_rng The RNG function. Only needed for #MBEDTLS_RSA_PRIVATE. + * \param p_rng The RNG context. + * \param mode #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE. + * \param md_alg The message-digest algorithm used to hash the original data. + * Use #MBEDTLS_MD_NONE for signing raw data. + * \param hashlen The length of the message digest. Only used if \p md_alg is #MBEDTLS_MD_NONE. + * \param hash The buffer holding the message digest. + * \param sig The buffer holding the ciphertext. + * + * \return \c 0 if the verify operation was successful. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_pkcs1_verify( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + const unsigned char *sig ); + +/** + * \brief This function performs a PKCS#1 v1.5 verification + * operation (RSASSA-PKCS1-v1_5-VERIFY). + * + * \note The \p sig buffer must be as large as the size + * of \p ctx->N. For example, 128 Bytes if RSA-1024 is used. + * + * \deprecated It is deprecated and discouraged to call this function + * in #MBEDTLS_RSA_PRIVATE mode. Future versions of the library + * are likely to remove the \p mode argument and have it + * set to #MBEDTLS_RSA_PUBLIC. + * + * \note Alternative implementations of RSA need not support + * mode being set to #MBEDTLS_RSA_PRIVATE and might instead + * return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION. + * + * \param ctx The RSA public key context. + * \param f_rng The RNG function. Only needed for #MBEDTLS_RSA_PRIVATE. + * \param p_rng The RNG context. + * \param mode #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE. + * \param md_alg The message-digest algorithm used to hash the original data. + * Use #MBEDTLS_MD_NONE for signing raw data. + * \param hashlen The length of the message digest. Only used if \p md_alg is #MBEDTLS_MD_NONE. + * \param hash The buffer holding the message digest. + * \param sig The buffer holding the ciphertext. + * + * \return \c 0 if the verify operation was successful. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_rsassa_pkcs1_v15_verify( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + const unsigned char *sig ); + +/** + * \brief This function performs a PKCS#1 v2.1 PSS verification + * operation (RSASSA-PSS-VERIFY). + * + * The hash function for the MGF mask generating function + * is that specified in the RSA context. + * + * \note The \p sig buffer must be as large as the size + * of \p ctx->N. For example, 128 Bytes if RSA-1024 is used. + * + * \note The \p hash_id in the RSA context is the one used for the + * verification. \p md_alg in the function call is the type of + * hash that is verified. According to RFC-3447: Public-Key + * Cryptography Standards (PKCS) #1 v2.1: RSA Cryptography + * Specifications it is advised to keep both hashes the + * same. If \p hash_id in the RSA context is unset, + * the \p md_alg from the function call is used. + * + * \deprecated It is deprecated and discouraged to call this function + * in #MBEDTLS_RSA_PRIVATE mode. Future versions of the library + * are likely to remove the \p mode argument and have it + * implicitly set to #MBEDTLS_RSA_PUBLIC. + * + * \note Alternative implementations of RSA need not support + * mode being set to #MBEDTLS_RSA_PRIVATE and might instead + * return #MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION. + * + * \param ctx The RSA public key context. + * \param f_rng The RNG function. Only needed for #MBEDTLS_RSA_PRIVATE. + * \param p_rng The RNG context. + * \param mode #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE. + * \param md_alg The message-digest algorithm used to hash the original data. + * Use #MBEDTLS_MD_NONE for signing raw data. + * \param hashlen The length of the message digest. Only used if \p md_alg is #MBEDTLS_MD_NONE. + * \param hash The buffer holding the message digest. + * \param sig The buffer holding the ciphertext. + * + * \return \c 0 if the verify operation was successful. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_rsassa_pss_verify( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + const unsigned char *sig ); + +/** + * \brief This function performs a PKCS#1 v2.1 PSS verification + * operation (RSASSA-PSS-VERIFY). + * + * The hash function for the MGF mask generating function + * is that specified in \p mgf1_hash_id. + * + * \note The \p sig buffer must be as large as the size + * of \p ctx->N. For example, 128 Bytes if RSA-1024 is used. + * + * \note The \p hash_id in the RSA context is ignored. + * + * \param ctx The RSA public key context. + * \param f_rng The RNG function. Only needed for #MBEDTLS_RSA_PRIVATE. + * \param p_rng The RNG context. + * \param mode #MBEDTLS_RSA_PUBLIC or #MBEDTLS_RSA_PRIVATE. + * \param md_alg The message-digest algorithm used to hash the original data. + * Use #MBEDTLS_MD_NONE for signing raw data. + * \param hashlen The length of the message digest. Only used if \p md_alg is + * #MBEDTLS_MD_NONE. + * \param hash The buffer holding the message digest. + * \param mgf1_hash_id The message digest used for mask generation. + * \param expected_salt_len The length of the salt used in padding. Use + * #MBEDTLS_RSA_SALT_LEN_ANY to accept any salt length. + * \param sig The buffer holding the ciphertext. + * + * \return \c 0 if the verify operation was successful. + * \return An \c MBEDTLS_ERR_RSA_XXX error code on failure. + */ +int mbedtls_rsa_rsassa_pss_verify_ext( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + mbedtls_md_type_t mgf1_hash_id, + int expected_salt_len, + const unsigned char *sig ); + +/** + * \brief This function copies the components of an RSA context. + * + * \param dst The destination context. + * \param src The source context. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory allocation failure. + */ +int mbedtls_rsa_copy( mbedtls_rsa_context *dst, const mbedtls_rsa_context *src ); + +/** + * \brief This function frees the components of an RSA key. + * + * \param ctx The RSA Context to free. + */ +void mbedtls_rsa_free( mbedtls_rsa_context *ctx ); + +/** + * \brief The RSA checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_rsa_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* rsa.h */ diff --git a/common/mbedtls/rsa_internal.c b/common/mbedtls/rsa_internal.c new file mode 100644 index 00000000..36c37f89 --- /dev/null +++ b/common/mbedtls/rsa_internal.c @@ -0,0 +1,489 @@ +/* + * Helper functions for the RSA module + * + * Copyright (C) 2006-2017, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + * + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_RSA_C) + +#include "mbedtls/rsa.h" +#include "mbedtls/bignum.h" +#include "mbedtls/rsa_internal.h" + +/* + * Compute RSA prime factors from public and private exponents + * + * Summary of algorithm: + * Setting F := lcm(P-1,Q-1), the idea is as follows: + * + * (a) For any 1 <= X < N with gcd(X,N)=1, we have X^F = 1 modulo N, so X^(F/2) + * is a square root of 1 in Z/NZ. Since Z/NZ ~= Z/PZ x Z/QZ by CRT and the + * square roots of 1 in Z/PZ and Z/QZ are +1 and -1, this leaves the four + * possibilities X^(F/2) = (+-1, +-1). If it happens that X^(F/2) = (-1,+1) + * or (+1,-1), then gcd(X^(F/2) + 1, N) will be equal to one of the prime + * factors of N. + * + * (b) If we don't know F/2 but (F/2) * K for some odd (!) K, then the same + * construction still applies since (-)^K is the identity on the set of + * roots of 1 in Z/NZ. + * + * The public and private key primitives (-)^E and (-)^D are mutually inverse + * bijections on Z/NZ if and only if (-)^(DE) is the identity on Z/NZ, i.e. + * if and only if DE - 1 is a multiple of F, say DE - 1 = F * L. + * Splitting L = 2^t * K with K odd, we have + * + * DE - 1 = FL = (F/2) * (2^(t+1)) * K, + * + * so (F / 2) * K is among the numbers + * + * (DE - 1) >> 1, (DE - 1) >> 2, ..., (DE - 1) >> ord + * + * where ord is the order of 2 in (DE - 1). + * We can therefore iterate through these numbers apply the construction + * of (a) and (b) above to attempt to factor N. + * + */ +int mbedtls_rsa_deduce_primes( mbedtls_mpi const *N, + mbedtls_mpi const *E, mbedtls_mpi const *D, + mbedtls_mpi *P, mbedtls_mpi *Q ) +{ + int ret = 0; + + uint16_t attempt; /* Number of current attempt */ + uint16_t iter; /* Number of squares computed in the current attempt */ + + uint16_t order; /* Order of 2 in DE - 1 */ + + mbedtls_mpi T; /* Holds largest odd divisor of DE - 1 */ + mbedtls_mpi K; /* Temporary holding the current candidate */ + + const unsigned char primes[] = { 2, + 3, 5, 7, 11, 13, 17, 19, 23, + 29, 31, 37, 41, 43, 47, 53, 59, + 61, 67, 71, 73, 79, 83, 89, 97, + 101, 103, 107, 109, 113, 127, 131, 137, + 139, 149, 151, 157, 163, 167, 173, 179, + 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251 + }; + + const size_t num_primes = sizeof( primes ) / sizeof( *primes ); + + if( P == NULL || Q == NULL || P->p != NULL || Q->p != NULL ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + if( mbedtls_mpi_cmp_int( N, 0 ) <= 0 || + mbedtls_mpi_cmp_int( D, 1 ) <= 0 || + mbedtls_mpi_cmp_mpi( D, N ) >= 0 || + mbedtls_mpi_cmp_int( E, 1 ) <= 0 || + mbedtls_mpi_cmp_mpi( E, N ) >= 0 ) + { + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + } + + /* + * Initializations and temporary changes + */ + + mbedtls_mpi_init( &K ); + mbedtls_mpi_init( &T ); + + /* T := DE - 1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, D, E ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &T, &T, 1 ) ); + + if( ( order = (uint16_t) mbedtls_mpi_lsb( &T ) ) == 0 ) + { + ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + goto cleanup; + } + + /* After this operation, T holds the largest odd divisor of DE - 1. */ + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &T, order ) ); + + /* + * Actual work + */ + + /* Skip trying 2 if N == 1 mod 8 */ + attempt = 0; + if( N->p[0] % 8 == 1 ) + attempt = 1; + + for( ; attempt < num_primes; ++attempt ) + { + mbedtls_mpi_lset( &K, primes[attempt] ); + + /* Check if gcd(K,N) = 1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( P, &K, N ) ); + if( mbedtls_mpi_cmp_int( P, 1 ) != 0 ) + continue; + + /* Go through K^T + 1, K^(2T) + 1, K^(4T) + 1, ... + * and check whether they have nontrivial GCD with N. */ + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &K, &K, &T, N, + Q /* temporarily use Q for storing Montgomery + * multiplication helper values */ ) ); + + for( iter = 1; iter <= order; ++iter ) + { + /* If we reach 1 prematurely, there's no point + * in continuing to square K */ + if( mbedtls_mpi_cmp_int( &K, 1 ) == 0 ) + break; + + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( &K, &K, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( P, &K, N ) ); + + if( mbedtls_mpi_cmp_int( P, 1 ) == 1 && + mbedtls_mpi_cmp_mpi( P, N ) == -1 ) + { + /* + * Have found a nontrivial divisor P of N. + * Set Q := N / P. + */ + + MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( Q, NULL, N, P ) ); + goto cleanup; + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, &K, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &K, &K, &K ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &K, &K, N ) ); + } + + /* + * If we get here, then either we prematurely aborted the loop because + * we reached 1, or K holds primes[attempt]^(DE - 1) mod N, which must + * be 1 if D,E,N were consistent. + * Check if that's the case and abort if not, to avoid very long, + * yet eventually failing, computations if N,D,E were not sane. + */ + if( mbedtls_mpi_cmp_int( &K, 1 ) != 0 ) + { + break; + } + } + + ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + +cleanup: + + mbedtls_mpi_free( &K ); + mbedtls_mpi_free( &T ); + return( ret ); +} + +/* + * Given P, Q and the public exponent E, deduce D. + * This is essentially a modular inversion. + */ +int mbedtls_rsa_deduce_private_exponent( mbedtls_mpi const *P, + mbedtls_mpi const *Q, + mbedtls_mpi const *E, + mbedtls_mpi *D ) +{ + int ret = 0; + mbedtls_mpi K, L; + + if( D == NULL || mbedtls_mpi_cmp_int( D, 0 ) != 0 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + if( mbedtls_mpi_cmp_int( P, 1 ) <= 0 || + mbedtls_mpi_cmp_int( Q, 1 ) <= 0 || + mbedtls_mpi_cmp_int( E, 0 ) == 0 ) + { + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + } + + mbedtls_mpi_init( &K ); + mbedtls_mpi_init( &L ); + + /* Temporarily put K := P-1 and L := Q-1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, P, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &L, Q, 1 ) ); + + /* Temporarily put D := gcd(P-1, Q-1) */ + MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( D, &K, &L ) ); + + /* K := LCM(P-1, Q-1) */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &K, &K, &L ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( &K, NULL, &K, D ) ); + + /* Compute modular inverse of E in LCM(P-1, Q-1) */ + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( D, E, &K ) ); + +cleanup: + + mbedtls_mpi_free( &K ); + mbedtls_mpi_free( &L ); + + return( ret ); +} + +/* + * Check that RSA CRT parameters are in accordance with core parameters. + */ +int mbedtls_rsa_validate_crt( const mbedtls_mpi *P, const mbedtls_mpi *Q, + const mbedtls_mpi *D, const mbedtls_mpi *DP, + const mbedtls_mpi *DQ, const mbedtls_mpi *QP ) +{ + int ret = 0; + + mbedtls_mpi K, L; + mbedtls_mpi_init( &K ); + mbedtls_mpi_init( &L ); + + /* Check that DP - D == 0 mod P - 1 */ + if( DP != NULL ) + { + if( P == NULL ) + { + ret = MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + goto cleanup; + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, P, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &L, DP, D ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &L, &L, &K ) ); + + if( mbedtls_mpi_cmp_int( &L, 0 ) != 0 ) + { + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + goto cleanup; + } + } + + /* Check that DQ - D == 0 mod Q - 1 */ + if( DQ != NULL ) + { + if( Q == NULL ) + { + ret = MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + goto cleanup; + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, Q, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &L, DQ, D ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &L, &L, &K ) ); + + if( mbedtls_mpi_cmp_int( &L, 0 ) != 0 ) + { + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + goto cleanup; + } + } + + /* Check that QP * Q - 1 == 0 mod P */ + if( QP != NULL ) + { + if( P == NULL || Q == NULL ) + { + ret = MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + goto cleanup; + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &K, QP, Q ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, &K, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &K, &K, P ) ); + if( mbedtls_mpi_cmp_int( &K, 0 ) != 0 ) + { + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + goto cleanup; + } + } + +cleanup: + + /* Wrap MPI error codes by RSA check failure error code */ + if( ret != 0 && + ret != MBEDTLS_ERR_RSA_KEY_CHECK_FAILED && + ret != MBEDTLS_ERR_RSA_BAD_INPUT_DATA ) + { + ret += MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + } + + mbedtls_mpi_free( &K ); + mbedtls_mpi_free( &L ); + + return( ret ); +} + +/* + * Check that core RSA parameters are sane. + */ +int mbedtls_rsa_validate_params( const mbedtls_mpi *N, const mbedtls_mpi *P, + const mbedtls_mpi *Q, const mbedtls_mpi *D, + const mbedtls_mpi *E, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret = 0; + mbedtls_mpi K, L; + + mbedtls_mpi_init( &K ); + mbedtls_mpi_init( &L ); + + /* + * Step 1: If PRNG provided, check that P and Q are prime + */ + +#if defined(MBEDTLS_GENPRIME) + if( f_rng != NULL && P != NULL && + ( ret = mbedtls_mpi_is_prime( P, f_rng, p_rng ) ) != 0 ) + { + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + goto cleanup; + } + + if( f_rng != NULL && Q != NULL && + ( ret = mbedtls_mpi_is_prime( Q, f_rng, p_rng ) ) != 0 ) + { + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + goto cleanup; + } +#else + ((void) f_rng); + ((void) p_rng); +#endif /* MBEDTLS_GENPRIME */ + + /* + * Step 2: Check that 1 < N = P * Q + */ + + if( P != NULL && Q != NULL && N != NULL ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &K, P, Q ) ); + if( mbedtls_mpi_cmp_int( N, 1 ) <= 0 || + mbedtls_mpi_cmp_mpi( &K, N ) != 0 ) + { + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + goto cleanup; + } + } + + /* + * Step 3: Check and 1 < D, E < N if present. + */ + + if( N != NULL && D != NULL && E != NULL ) + { + if ( mbedtls_mpi_cmp_int( D, 1 ) <= 0 || + mbedtls_mpi_cmp_int( E, 1 ) <= 0 || + mbedtls_mpi_cmp_mpi( D, N ) >= 0 || + mbedtls_mpi_cmp_mpi( E, N ) >= 0 ) + { + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + goto cleanup; + } + } + + /* + * Step 4: Check that D, E are inverse modulo P-1 and Q-1 + */ + + if( P != NULL && Q != NULL && D != NULL && E != NULL ) + { + if( mbedtls_mpi_cmp_int( P, 1 ) <= 0 || + mbedtls_mpi_cmp_int( Q, 1 ) <= 0 ) + { + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + goto cleanup; + } + + /* Compute DE-1 mod P-1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &K, D, E ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, &K, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &L, P, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &K, &K, &L ) ); + if( mbedtls_mpi_cmp_int( &K, 0 ) != 0 ) + { + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + goto cleanup; + } + + /* Compute DE-1 mod Q-1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &K, D, E ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, &K, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &L, Q, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &K, &K, &L ) ); + if( mbedtls_mpi_cmp_int( &K, 0 ) != 0 ) + { + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + goto cleanup; + } + } + +cleanup: + + mbedtls_mpi_free( &K ); + mbedtls_mpi_free( &L ); + + /* Wrap MPI error codes by RSA check failure error code */ + if( ret != 0 && ret != MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ) + { + ret += MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + } + + return( ret ); +} + +int mbedtls_rsa_deduce_crt( const mbedtls_mpi *P, const mbedtls_mpi *Q, + const mbedtls_mpi *D, mbedtls_mpi *DP, + mbedtls_mpi *DQ, mbedtls_mpi *QP ) +{ + int ret = 0; + mbedtls_mpi K; + mbedtls_mpi_init( &K ); + + /* DP = D mod P-1 */ + if( DP != NULL ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, P, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( DP, D, &K ) ); + } + + /* DQ = D mod Q-1 */ + if( DQ != NULL ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &K, Q, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( DQ, D, &K ) ); + } + + /* QP = Q^{-1} mod P */ + if( QP != NULL ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( QP, Q, P ) ); + } + +cleanup: + mbedtls_mpi_free( &K ); + + return( ret ); +} + +#endif /* MBEDTLS_RSA_C */ diff --git a/common/mbedtls/rsa_internal.h b/common/mbedtls/rsa_internal.h new file mode 100644 index 00000000..8ee0bfe3 --- /dev/null +++ b/common/mbedtls/rsa_internal.h @@ -0,0 +1,228 @@ +/** + * \file rsa_internal.h + * + * \brief Context-independent RSA helper functions + * + * This module declares some RSA-related helper functions useful when + * implementing the RSA interface. These functions are provided in a separate + * compilation unit in order to make it easy for designers of alternative RSA + * implementations to use them in their own code, as it is conceived that the + * functionality they provide will be necessary for most complete + * implementations. + * + * End-users of Mbed TLS who are not providing their own alternative RSA + * implementations should not use these functions directly, and should instead + * use only the functions declared in rsa.h. + * + * The interface provided by this module will be maintained through LTS (Long + * Term Support) branches of Mbed TLS, but may otherwise be subject to change, + * and must be considered an internal interface of the library. + * + * There are two classes of helper functions: + * + * (1) Parameter-generating helpers. These are: + * - mbedtls_rsa_deduce_primes + * - mbedtls_rsa_deduce_private_exponent + * - mbedtls_rsa_deduce_crt + * Each of these functions takes a set of core RSA parameters and + * generates some other, or CRT related parameters. + * + * (2) Parameter-checking helpers. These are: + * - mbedtls_rsa_validate_params + * - mbedtls_rsa_validate_crt + * They take a set of core or CRT related RSA parameters and check their + * validity. + * + */ +/* + * Copyright (C) 2006-2017, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + * + */ + +#ifndef MBEDTLS_RSA_INTERNAL_H +#define MBEDTLS_RSA_INTERNAL_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "bignum.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * \brief Compute RSA prime moduli P, Q from public modulus N=PQ + * and a pair of private and public key. + * + * \note This is a 'static' helper function not operating on + * an RSA context. Alternative implementations need not + * overwrite it. + * + * \param N RSA modulus N = PQ, with P, Q to be found + * \param E RSA public exponent + * \param D RSA private exponent + * \param P Pointer to MPI holding first prime factor of N on success + * \param Q Pointer to MPI holding second prime factor of N on success + * + * \return + * - 0 if successful. In this case, P and Q constitute a + * factorization of N. + * - A non-zero error code otherwise. + * + * \note It is neither checked that P, Q are prime nor that + * D, E are modular inverses wrt. P-1 and Q-1. For that, + * use the helper function \c mbedtls_rsa_validate_params. + * + */ +int mbedtls_rsa_deduce_primes( mbedtls_mpi const *N, mbedtls_mpi const *E, + mbedtls_mpi const *D, + mbedtls_mpi *P, mbedtls_mpi *Q ); + +/** + * \brief Compute RSA private exponent from + * prime moduli and public key. + * + * \note This is a 'static' helper function not operating on + * an RSA context. Alternative implementations need not + * overwrite it. + * + * \param P First prime factor of RSA modulus + * \param Q Second prime factor of RSA modulus + * \param E RSA public exponent + * \param D Pointer to MPI holding the private exponent on success. + * + * \return + * - 0 if successful. In this case, D is set to a simultaneous + * modular inverse of E modulo both P-1 and Q-1. + * - A non-zero error code otherwise. + * + * \note This function does not check whether P and Q are primes. + * + */ +int mbedtls_rsa_deduce_private_exponent( mbedtls_mpi const *P, + mbedtls_mpi const *Q, + mbedtls_mpi const *E, + mbedtls_mpi *D ); + + +/** + * \brief Generate RSA-CRT parameters + * + * \note This is a 'static' helper function not operating on + * an RSA context. Alternative implementations need not + * overwrite it. + * + * \param P First prime factor of N + * \param Q Second prime factor of N + * \param D RSA private exponent + * \param DP Output variable for D modulo P-1 + * \param DQ Output variable for D modulo Q-1 + * \param QP Output variable for the modular inverse of Q modulo P. + * + * \return 0 on success, non-zero error code otherwise. + * + * \note This function does not check whether P, Q are + * prime and whether D is a valid private exponent. + * + */ +int mbedtls_rsa_deduce_crt( const mbedtls_mpi *P, const mbedtls_mpi *Q, + const mbedtls_mpi *D, mbedtls_mpi *DP, + mbedtls_mpi *DQ, mbedtls_mpi *QP ); + + +/** + * \brief Check validity of core RSA parameters + * + * \note This is a 'static' helper function not operating on + * an RSA context. Alternative implementations need not + * overwrite it. + * + * \param N RSA modulus N = PQ + * \param P First prime factor of N + * \param Q Second prime factor of N + * \param D RSA private exponent + * \param E RSA public exponent + * \param f_rng PRNG to be used for primality check, or NULL + * \param p_rng PRNG context for f_rng, or NULL + * + * \return + * - 0 if the following conditions are satisfied + * if all relevant parameters are provided: + * - P prime if f_rng != NULL (%) + * - Q prime if f_rng != NULL (%) + * - 1 < N = P * Q + * - 1 < D, E < N + * - D and E are modular inverses modulo P-1 and Q-1 + * (%) This is only done if MBEDTLS_GENPRIME is defined. + * - A non-zero error code otherwise. + * + * \note The function can be used with a restricted set of arguments + * to perform specific checks only. E.g., calling it with + * (-,P,-,-,-) and a PRNG amounts to a primality check for P. + */ +int mbedtls_rsa_validate_params( const mbedtls_mpi *N, const mbedtls_mpi *P, + const mbedtls_mpi *Q, const mbedtls_mpi *D, + const mbedtls_mpi *E, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Check validity of RSA CRT parameters + * + * \note This is a 'static' helper function not operating on + * an RSA context. Alternative implementations need not + * overwrite it. + * + * \param P First prime factor of RSA modulus + * \param Q Second prime factor of RSA modulus + * \param D RSA private exponent + * \param DP MPI to check for D modulo P-1 + * \param DQ MPI to check for D modulo P-1 + * \param QP MPI to check for the modular inverse of Q modulo P. + * + * \return + * - 0 if the following conditions are satisfied: + * - D = DP mod P-1 if P, D, DP != NULL + * - Q = DQ mod P-1 if P, D, DQ != NULL + * - QP = Q^-1 mod P if P, Q, QP != NULL + * - \c MBEDTLS_ERR_RSA_KEY_CHECK_FAILED if check failed, + * potentially including \c MBEDTLS_ERR_MPI_XXX if some + * MPI calculations failed. + * - \c MBEDTLS_ERR_RSA_BAD_INPUT_DATA if insufficient + * data was provided to check DP, DQ or QP. + * + * \note The function can be used with a restricted set of arguments + * to perform specific checks only. E.g., calling it with the + * parameters (P, -, D, DP, -, -) will check DP = D mod P-1. + */ +int mbedtls_rsa_validate_crt( const mbedtls_mpi *P, const mbedtls_mpi *Q, + const mbedtls_mpi *D, const mbedtls_mpi *DP, + const mbedtls_mpi *DQ, const mbedtls_mpi *QP ); + +#ifdef __cplusplus +} +#endif + +#endif /* rsa_internal.h */ diff --git a/common/polarssl/sha1.c b/common/mbedtls/sha1.c similarity index 51% rename from common/polarssl/sha1.c rename to common/mbedtls/sha1.c index 28bcd4e3..9981c5a9 100644 --- a/common/polarssl/sha1.c +++ b/common/mbedtls/sha1.c @@ -1,12 +1,8 @@ /* * FIPS-180-1 compliant SHA-1 implementation * - * Copyright (C) 2006-2013, Brainspark B.V. - * - * This file is part of PolarSSL (http://www.polarssl.org) - * Lead Maintainer: Paul Bakker - * - * All rights reserved. + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,6 +17,8 @@ * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) */ /* * The SHA-1 standard was published by NIST in 1993. @@ -28,17 +26,29 @@ * http://www.itl.nist.gov/fipspubs/fip180-1.htm */ -#include "polarssl_config.h" - -#if defined(POLARSSL_SHA1_C) - -#include "sha1.h" - -#if defined(POLARSSL_FS_IO) || defined(POLARSSL_SELF_TEST) -#include +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE #endif -#if !defined(POLARSSL_SHA1_ALT) +#if defined(MBEDTLS_SHA1_C) + +#include "mbedtls/sha1.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_SHA1_ALT) /* * 32-bit integer manipulation macros (big endian) @@ -63,10 +73,29 @@ } #endif +void mbedtls_sha1_init( mbedtls_sha1_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_sha1_context ) ); +} + +void mbedtls_sha1_free( mbedtls_sha1_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_sha1_context ) ); +} + +void mbedtls_sha1_clone( mbedtls_sha1_context *dst, + const mbedtls_sha1_context *src ) +{ + *dst = *src; +} + /* * SHA-1 context setup */ -void sha1_starts( sha1_context *ctx ) +int mbedtls_sha1_starts_ret( mbedtls_sha1_context *ctx ) { ctx->total[0] = 0; ctx->total[1] = 0; @@ -76,9 +105,20 @@ void sha1_starts( sha1_context *ctx ) ctx->state[2] = 0x98BADCFE; ctx->state[3] = 0x10325476; ctx->state[4] = 0xC3D2E1F0; + + return( 0 ); } -void sha1_process( sha1_context *ctx, const unsigned char data[64] ) +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_sha1_starts( mbedtls_sha1_context *ctx ) +{ + mbedtls_sha1_starts_ret( ctx ); +} +#endif + +#if !defined(MBEDTLS_SHA1_PROCESS_ALT) +int mbedtls_internal_sha1_process( mbedtls_sha1_context *ctx, + const unsigned char data[64] ) { uint32_t temp, W[16], A, B, C, D, E; @@ -103,8 +143,8 @@ void sha1_process( sha1_context *ctx, const unsigned char data[64] ) #define R(t) \ ( \ - temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ \ - W[(t - 14) & 0x0F] ^ W[ t & 0x0F], \ + temp = W[( t - 3 ) & 0x0F] ^ W[( t - 8 ) & 0x0F] ^ \ + W[( t - 14 ) & 0x0F] ^ W[ t & 0x0F], \ ( W[t & 0x0F] = S(temp,1) ) \ ) @@ -232,18 +272,32 @@ void sha1_process( sha1_context *ctx, const unsigned char data[64] ) ctx->state[2] += C; ctx->state[3] += D; ctx->state[4] += E; + + return( 0 ); } +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_sha1_process( mbedtls_sha1_context *ctx, + const unsigned char data[64] ) +{ + mbedtls_internal_sha1_process( ctx, data ); +} +#endif +#endif /* !MBEDTLS_SHA1_PROCESS_ALT */ + /* * SHA-1 process buffer */ -void sha1_update( sha1_context *ctx, const unsigned char *input, size_t ilen ) +int mbedtls_sha1_update_ret( mbedtls_sha1_context *ctx, + const unsigned char *input, + size_t ilen ) { + int ret; size_t fill; uint32_t left; - if( ilen <= 0 ) - return; + if( ilen == 0 ) + return( 0 ); left = ctx->total[0] & 0x3F; fill = 64 - left; @@ -257,7 +311,10 @@ void sha1_update( sha1_context *ctx, const unsigned char *input, size_t ilen ) if( left && ilen >= fill ) { memcpy( (void *) (ctx->buffer + left), input, fill ); - sha1_process( ctx, ctx->buffer ); + + if( ( ret = mbedtls_internal_sha1_process( ctx, ctx->buffer ) ) != 0 ) + return( ret ); + input += fill; ilen -= fill; left = 0; @@ -265,193 +322,144 @@ void sha1_update( sha1_context *ctx, const unsigned char *input, size_t ilen ) while( ilen >= 64 ) { - sha1_process( ctx, input ); + if( ( ret = mbedtls_internal_sha1_process( ctx, input ) ) != 0 ) + return( ret ); + input += 64; ilen -= 64; } if( ilen > 0 ) memcpy( (void *) (ctx->buffer + left), input, ilen ); + + return( 0 ); } -static const unsigned char sha1_padding[64] = +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_sha1_update( mbedtls_sha1_context *ctx, + const unsigned char *input, + size_t ilen ) { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; + mbedtls_sha1_update_ret( ctx, input, ilen ); +} +#endif /* * SHA-1 final digest */ -void sha1_finish( sha1_context *ctx, unsigned char output[20] ) +int mbedtls_sha1_finish_ret( mbedtls_sha1_context *ctx, + unsigned char output[20] ) { - uint32_t last, padn; + int ret; + uint32_t used; uint32_t high, low; - unsigned char msglen[8]; + /* + * Add padding: 0x80 then 0x00 until 8 bytes remain for the length + */ + used = ctx->total[0] & 0x3F; + + ctx->buffer[used++] = 0x80; + + if( used <= 56 ) + { + /* Enough room for padding + length in current block */ + memset( ctx->buffer + used, 0, 56 - used ); + } + else + { + /* We'll need an extra block */ + memset( ctx->buffer + used, 0, 64 - used ); + + if( ( ret = mbedtls_internal_sha1_process( ctx, ctx->buffer ) ) != 0 ) + return( ret ); + + memset( ctx->buffer, 0, 56 ); + } + + /* + * Add message length + */ high = ( ctx->total[0] >> 29 ) | ( ctx->total[1] << 3 ); low = ( ctx->total[0] << 3 ); - PUT_UINT32_BE( high, msglen, 0 ); - PUT_UINT32_BE( low, msglen, 4 ); + PUT_UINT32_BE( high, ctx->buffer, 56 ); + PUT_UINT32_BE( low, ctx->buffer, 60 ); - last = ctx->total[0] & 0x3F; - padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); - - sha1_update( ctx, sha1_padding, padn ); - sha1_update( ctx, msglen, 8 ); + if( ( ret = mbedtls_internal_sha1_process( ctx, ctx->buffer ) ) != 0 ) + return( ret ); + /* + * Output final state + */ PUT_UINT32_BE( ctx->state[0], output, 0 ); PUT_UINT32_BE( ctx->state[1], output, 4 ); PUT_UINT32_BE( ctx->state[2], output, 8 ); PUT_UINT32_BE( ctx->state[3], output, 12 ); PUT_UINT32_BE( ctx->state[4], output, 16 ); + + return( 0 ); } -#endif /* !POLARSSL_SHA1_ALT */ +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_sha1_finish( mbedtls_sha1_context *ctx, + unsigned char output[20] ) +{ + mbedtls_sha1_finish_ret( ctx, output ); +} +#endif + +#endif /* !MBEDTLS_SHA1_ALT */ /* * output = SHA-1( input buffer ) */ -void sha1( const unsigned char *input, size_t ilen, unsigned char output[20] ) +int mbedtls_sha1_ret( const unsigned char *input, + size_t ilen, + unsigned char output[20] ) { - sha1_context ctx; + int ret; + mbedtls_sha1_context ctx; - sha1_starts( &ctx ); - sha1_update( &ctx, input, ilen ); - sha1_finish( &ctx, output ); + mbedtls_sha1_init( &ctx ); - memset( &ctx, 0, sizeof( sha1_context ) ); + if( ( ret = mbedtls_sha1_starts_ret( &ctx ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_sha1_update_ret( &ctx, input, ilen ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_sha1_finish_ret( &ctx, output ) ) != 0 ) + goto exit; + +exit: + mbedtls_sha1_free( &ctx ); + + return( ret ); } -#if defined(POLARSSL_FS_IO) -/* - * output = SHA-1( file contents ) - */ -int sha1_file( const char *path, unsigned char output[20] ) +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_sha1( const unsigned char *input, + size_t ilen, + unsigned char output[20] ) { - FILE *f; - size_t n; - sha1_context ctx; - unsigned char buf[1024]; - - if( ( f = fopen( path, "rb" ) ) == NULL ) - return( POLARSSL_ERR_SHA1_FILE_IO_ERROR ); - - sha1_starts( &ctx ); - - while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 ) - sha1_update( &ctx, buf, n ); - - sha1_finish( &ctx, output ); - - memset( &ctx, 0, sizeof( sha1_context ) ); - - if( ferror( f ) != 0 ) - { - fclose( f ); - return( POLARSSL_ERR_SHA1_FILE_IO_ERROR ); - } - - fclose( f ); - return( 0 ); + mbedtls_sha1_ret( input, ilen, output ); } -#endif /* POLARSSL_FS_IO */ +#endif -/* - * SHA-1 HMAC context setup - */ -void sha1_hmac_starts( sha1_context *ctx, const unsigned char *key, size_t keylen ) -{ - size_t i; - unsigned char sum[20]; - - if( keylen > 64 ) - { - sha1( key, keylen, sum ); - keylen = 20; - key = sum; - } - - memset( ctx->ipad, 0x36, 64 ); - memset( ctx->opad, 0x5C, 64 ); - - for( i = 0; i < keylen; i++ ) - { - ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] ); - ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] ); - } - - sha1_starts( ctx ); - sha1_update( ctx, ctx->ipad, 64 ); - - memset( sum, 0, sizeof( sum ) ); -} - -/* - * SHA-1 HMAC process buffer - */ -void sha1_hmac_update( sha1_context *ctx, const unsigned char *input, size_t ilen ) -{ - sha1_update( ctx, input, ilen ); -} - -/* - * SHA-1 HMAC final digest - */ -void sha1_hmac_finish( sha1_context *ctx, unsigned char output[20] ) -{ - unsigned char tmpbuf[20]; - - sha1_finish( ctx, tmpbuf ); - sha1_starts( ctx ); - sha1_update( ctx, ctx->opad, 64 ); - sha1_update( ctx, tmpbuf, 20 ); - sha1_finish( ctx, output ); - - memset( tmpbuf, 0, sizeof( tmpbuf ) ); -} - -/* - * SHA1 HMAC context reset - */ -void sha1_hmac_reset( sha1_context *ctx ) -{ - sha1_starts( ctx ); - sha1_update( ctx, ctx->ipad, 64 ); -} - -/* - * output = HMAC-SHA-1( hmac key, input buffer ) - */ -void sha1_hmac( const unsigned char *key, size_t keylen, - const unsigned char *input, size_t ilen, - unsigned char output[20] ) -{ - sha1_context ctx; - - sha1_hmac_starts( &ctx, key, keylen ); - sha1_hmac_update( &ctx, input, ilen ); - sha1_hmac_finish( &ctx, output ); - - memset( &ctx, 0, sizeof( sha1_context ) ); -} - -#if defined(POLARSSL_SELF_TEST) +#if defined(MBEDTLS_SELF_TEST) /* * FIPS-180-1 test vectors */ -static unsigned char sha1_test_buf[3][57] = +static const unsigned char sha1_test_buf[3][57] = { { "abc" }, { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" }, { "" } }; -static const int sha1_test_buflen[3] = +static const size_t sha1_test_buflen[3] = { 3, 56, 1000 }; @@ -466,81 +474,17 @@ static const unsigned char sha1_test_sum[3][20] = 0xEB, 0x2B, 0xDB, 0xAD, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6F } }; -/* - * RFC 2202 test vectors - */ -static unsigned char sha1_hmac_test_key[7][26] = -{ - { "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B" - "\x0B\x0B\x0B\x0B" }, - { "Jefe" }, - { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" - "\xAA\xAA\xAA\xAA" }, - { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10" - "\x11\x12\x13\x14\x15\x16\x17\x18\x19" }, - { "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C" - "\x0C\x0C\x0C\x0C" }, - { "" }, /* 0xAA 80 times */ - { "" } -}; - -static const int sha1_hmac_test_keylen[7] = -{ - 20, 4, 20, 25, 20, 80, 80 -}; - -static unsigned char sha1_hmac_test_buf[7][74] = -{ - { "Hi There" }, - { "what do ya want for nothing?" }, - { "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" - "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" - "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" - "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" - "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" }, - { "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" - "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" - "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" - "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" - "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" }, - { "Test With Truncation" }, - { "Test Using Larger Than Block-Size Key - Hash Key First" }, - { "Test Using Larger Than Block-Size Key and Larger" - " Than One Block-Size Data" } -}; - -static const int sha1_hmac_test_buflen[7] = -{ - 8, 28, 50, 50, 20, 54, 73 -}; - -static const unsigned char sha1_hmac_test_sum[7][20] = -{ - { 0xB6, 0x17, 0x31, 0x86, 0x55, 0x05, 0x72, 0x64, 0xE2, 0x8B, - 0xC0, 0xB6, 0xFB, 0x37, 0x8C, 0x8E, 0xF1, 0x46, 0xBE, 0x00 }, - { 0xEF, 0xFC, 0xDF, 0x6A, 0xE5, 0xEB, 0x2F, 0xA2, 0xD2, 0x74, - 0x16, 0xD5, 0xF1, 0x84, 0xDF, 0x9C, 0x25, 0x9A, 0x7C, 0x79 }, - { 0x12, 0x5D, 0x73, 0x42, 0xB9, 0xAC, 0x11, 0xCD, 0x91, 0xA3, - 0x9A, 0xF4, 0x8A, 0xA1, 0x7B, 0x4F, 0x63, 0xF1, 0x75, 0xD3 }, - { 0x4C, 0x90, 0x07, 0xF4, 0x02, 0x62, 0x50, 0xC6, 0xBC, 0x84, - 0x14, 0xF9, 0xBF, 0x50, 0xC8, 0x6C, 0x2D, 0x72, 0x35, 0xDA }, - { 0x4C, 0x1A, 0x03, 0x42, 0x4B, 0x55, 0xE0, 0x7F, 0xE7, 0xF2, - 0x7B, 0xE1 }, - { 0xAA, 0x4A, 0xE5, 0xE1, 0x52, 0x72, 0xD0, 0x0E, 0x95, 0x70, - 0x56, 0x37, 0xCE, 0x8A, 0x3B, 0x55, 0xED, 0x40, 0x21, 0x12 }, - { 0xE8, 0xE9, 0x9D, 0x0F, 0x45, 0x23, 0x7D, 0x78, 0x6D, 0x6B, - 0xBA, 0xA7, 0x96, 0x5C, 0x78, 0x08, 0xBB, 0xFF, 0x1A, 0x91 } -}; - /* * Checkup routine */ -int sha1_self_test( int verbose ) +int mbedtls_sha1_self_test( int verbose ) { - int i, j, buflen; + int i, j, buflen, ret = 0; unsigned char buf[1024]; unsigned char sha1sum[20]; - sha1_context ctx; + mbedtls_sha1_context ctx; + + mbedtls_sha1_init( &ctx ); /* * SHA-1 @@ -548,77 +492,58 @@ int sha1_self_test( int verbose ) for( i = 0; i < 3; i++ ) { if( verbose != 0 ) - printf( " SHA-1 test #%d: ", i + 1 ); + mbedtls_printf( " SHA-1 test #%d: ", i + 1 ); - sha1_starts( &ctx ); + if( ( ret = mbedtls_sha1_starts_ret( &ctx ) ) != 0 ) + goto fail; if( i == 2 ) { memset( buf, 'a', buflen = 1000 ); for( j = 0; j < 1000; j++ ) - sha1_update( &ctx, buf, buflen ); + { + ret = mbedtls_sha1_update_ret( &ctx, buf, buflen ); + if( ret != 0 ) + goto fail; + } } else - sha1_update( &ctx, sha1_test_buf[i], - sha1_test_buflen[i] ); + { + ret = mbedtls_sha1_update_ret( &ctx, sha1_test_buf[i], + sha1_test_buflen[i] ); + if( ret != 0 ) + goto fail; + } - sha1_finish( &ctx, sha1sum ); + if( ( ret = mbedtls_sha1_finish_ret( &ctx, sha1sum ) ) != 0 ) + goto fail; if( memcmp( sha1sum, sha1_test_sum[i], 20 ) != 0 ) { - if( verbose != 0 ) - printf( "failed\n" ); - - return( 1 ); + ret = 1; + goto fail; } if( verbose != 0 ) - printf( "passed\n" ); + mbedtls_printf( "passed\n" ); } if( verbose != 0 ) - printf( "\n" ); + mbedtls_printf( "\n" ); - for( i = 0; i < 7; i++ ) - { - if( verbose != 0 ) - printf( " HMAC-SHA-1 test #%d: ", i + 1 ); - - if( i == 5 || i == 6 ) - { - memset( buf, '\xAA', buflen = 80 ); - sha1_hmac_starts( &ctx, buf, buflen ); - } - else - sha1_hmac_starts( &ctx, sha1_hmac_test_key[i], - sha1_hmac_test_keylen[i] ); - - sha1_hmac_update( &ctx, sha1_hmac_test_buf[i], - sha1_hmac_test_buflen[i] ); - - sha1_hmac_finish( &ctx, sha1sum ); - - buflen = ( i == 4 ) ? 12 : 20; - - if( memcmp( sha1sum, sha1_hmac_test_sum[i], buflen ) != 0 ) - { - if( verbose != 0 ) - printf( "failed\n" ); - - return( 1 ); - } - - if( verbose != 0 ) - printf( "passed\n" ); - } + goto exit; +fail: if( verbose != 0 ) - printf( "\n" ); + mbedtls_printf( "failed\n" ); - return( 0 ); +exit: + mbedtls_sha1_free( &ctx ); + + return( ret ); } -#endif +#endif /* MBEDTLS_SELF_TEST */ -#endif +#endif /* MBEDTLS_SHA1_C */ diff --git a/common/mbedtls/sha1.h b/common/mbedtls/sha1.h new file mode 100644 index 00000000..872fe1b0 --- /dev/null +++ b/common/mbedtls/sha1.h @@ -0,0 +1,326 @@ +/** + * \file sha1.h + * + * \brief This file contains SHA-1 definitions and functions. + * + * The Secure Hash Algorithm 1 (SHA-1) cryptographic hash function is defined in + * FIPS 180-4: Secure Hash Standard (SHS). + * + * \warning SHA-1 is considered a weak message digest and its use constitutes + * a security risk. We recommend considering stronger message + * digests instead. + */ +/* + * Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_SHA1_H +#define MBEDTLS_SHA1_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#define MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED -0x0035 /**< SHA-1 hardware accelerator failed */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_SHA1_ALT) +// Regular implementation +// + +/** + * \brief The SHA-1 context structure. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + */ +typedef struct mbedtls_sha1_context +{ + uint32_t total[2]; /*!< The number of Bytes processed. */ + uint32_t state[5]; /*!< The intermediate digest state. */ + unsigned char buffer[64]; /*!< The data block being processed. */ +} +mbedtls_sha1_context; + +#else /* MBEDTLS_SHA1_ALT */ +#include "sha1_alt.h" +#endif /* MBEDTLS_SHA1_ALT */ + +/** + * \brief This function initializes a SHA-1 context. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \param ctx The SHA-1 context to initialize. + * + */ +void mbedtls_sha1_init( mbedtls_sha1_context *ctx ); + +/** + * \brief This function clears a SHA-1 context. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \param ctx The SHA-1 context to clear. + * + */ +void mbedtls_sha1_free( mbedtls_sha1_context *ctx ); + +/** + * \brief This function clones the state of a SHA-1 context. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \param dst The SHA-1 context to clone to. + * \param src The SHA-1 context to clone from. + * + */ +void mbedtls_sha1_clone( mbedtls_sha1_context *dst, + const mbedtls_sha1_context *src ); + +/** + * \brief This function starts a SHA-1 checksum calculation. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \param ctx The SHA-1 context to initialize. + * + * \return \c 0 on success. + * + */ +int mbedtls_sha1_starts_ret( mbedtls_sha1_context *ctx ); + +/** + * \brief This function feeds an input buffer into an ongoing SHA-1 + * checksum calculation. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \param ctx The SHA-1 context. + * \param input The buffer holding the input data. + * \param ilen The length of the input data. + * + * \return \c 0 on success. + */ +int mbedtls_sha1_update_ret( mbedtls_sha1_context *ctx, + const unsigned char *input, + size_t ilen ); + +/** + * \brief This function finishes the SHA-1 operation, and writes + * the result to the output buffer. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \param ctx The SHA-1 context. + * \param output The SHA-1 checksum result. + * + * \return \c 0 on success. + */ +int mbedtls_sha1_finish_ret( mbedtls_sha1_context *ctx, + unsigned char output[20] ); + +/** + * \brief SHA-1 process data block (internal use only). + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \param ctx The SHA-1 context. + * \param data The data block being processed. + * + * \return \c 0 on success. + * + */ +int mbedtls_internal_sha1_process( mbedtls_sha1_context *ctx, + const unsigned char data[64] ); + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief This function starts a SHA-1 checksum calculation. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \deprecated Superseded by mbedtls_sha1_starts_ret() in 2.7.0. + * + * \param ctx The SHA-1 context to initialize. + * + */ +MBEDTLS_DEPRECATED void mbedtls_sha1_starts( mbedtls_sha1_context *ctx ); + +/** + * \brief This function feeds an input buffer into an ongoing SHA-1 + * checksum calculation. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \deprecated Superseded by mbedtls_sha1_update_ret() in 2.7.0. + * + * \param ctx The SHA-1 context. + * \param input The buffer holding the input data. + * \param ilen The length of the input data. + * + */ +MBEDTLS_DEPRECATED void mbedtls_sha1_update( mbedtls_sha1_context *ctx, + const unsigned char *input, + size_t ilen ); + +/** + * \brief This function finishes the SHA-1 operation, and writes + * the result to the output buffer. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \deprecated Superseded by mbedtls_sha1_finish_ret() in 2.7.0. + * + * \param ctx The SHA-1 context. + * \param output The SHA-1 checksum result. + * + */ +MBEDTLS_DEPRECATED void mbedtls_sha1_finish( mbedtls_sha1_context *ctx, + unsigned char output[20] ); + +/** + * \brief SHA-1 process data block (internal use only). + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \deprecated Superseded by mbedtls_internal_sha1_process() in 2.7.0. + * + * \param ctx The SHA-1 context. + * \param data The data block being processed. + * + */ +MBEDTLS_DEPRECATED void mbedtls_sha1_process( mbedtls_sha1_context *ctx, + const unsigned char data[64] ); + +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +/** + * \brief This function calculates the SHA-1 checksum of a buffer. + * + * The function allocates the context, performs the + * calculation, and frees the context. + * + * The SHA-1 result is calculated as + * output = SHA-1(input buffer). + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \param input The buffer holding the input data. + * \param ilen The length of the input data. + * \param output The SHA-1 checksum result. + * + * \return \c 0 on success. + * + */ +int mbedtls_sha1_ret( const unsigned char *input, + size_t ilen, + unsigned char output[20] ); + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief This function calculates the SHA-1 checksum of a buffer. + * + * The function allocates the context, performs the + * calculation, and frees the context. + * + * The SHA-1 result is calculated as + * output = SHA-1(input buffer). + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \deprecated Superseded by mbedtls_sha1_ret() in 2.7.0 + * + * \param input The buffer holding the input data. + * \param ilen The length of the input data. + * \param output The SHA-1 checksum result. + * + */ +MBEDTLS_DEPRECATED void mbedtls_sha1( const unsigned char *input, + size_t ilen, + unsigned char output[20] ); + +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +/** + * \brief The SHA-1 checkup routine. + * + * \warning SHA-1 is considered a weak message digest and its use + * constitutes a security risk. We recommend considering + * stronger message digests instead. + * + * \return \c 0 on success. + * \return \c 1 on failure. + * + */ +int mbedtls_sha1_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_sha1.h */ diff --git a/common/mbedtls/sha256.c b/common/mbedtls/sha256.c new file mode 100644 index 00000000..06b5f7a7 --- /dev/null +++ b/common/mbedtls/sha256.c @@ -0,0 +1,562 @@ +/* + * FIPS-180-2 compliant SHA-256 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The SHA-256 Secure Hash Standard was published by NIST in 2002. + * + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SHA256_C) + +#include "mbedtls/sha256.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_printf printf +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_SHA256_ALT) + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +do { \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} while( 0 ) +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +do { \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} while( 0 ) +#endif + +void mbedtls_sha256_init( mbedtls_sha256_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_sha256_context ) ); +} + +void mbedtls_sha256_free( mbedtls_sha256_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_sha256_context ) ); +} + +void mbedtls_sha256_clone( mbedtls_sha256_context *dst, + const mbedtls_sha256_context *src ) +{ + *dst = *src; +} + +/* + * SHA-256 context setup + */ +int mbedtls_sha256_starts_ret( mbedtls_sha256_context *ctx, int is224 ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + if( is224 == 0 ) + { + /* SHA-256 */ + ctx->state[0] = 0x6A09E667; + ctx->state[1] = 0xBB67AE85; + ctx->state[2] = 0x3C6EF372; + ctx->state[3] = 0xA54FF53A; + ctx->state[4] = 0x510E527F; + ctx->state[5] = 0x9B05688C; + ctx->state[6] = 0x1F83D9AB; + ctx->state[7] = 0x5BE0CD19; + } + else + { + /* SHA-224 */ + ctx->state[0] = 0xC1059ED8; + ctx->state[1] = 0x367CD507; + ctx->state[2] = 0x3070DD17; + ctx->state[3] = 0xF70E5939; + ctx->state[4] = 0xFFC00B31; + ctx->state[5] = 0x68581511; + ctx->state[6] = 0x64F98FA7; + ctx->state[7] = 0xBEFA4FA4; + } + + ctx->is224 = is224; + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_sha256_starts( mbedtls_sha256_context *ctx, + int is224 ) +{ + mbedtls_sha256_starts_ret( ctx, is224 ); +} +#endif + +#if !defined(MBEDTLS_SHA256_PROCESS_ALT) +static const uint32_t K[] = +{ + 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, + 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, + 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, + 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, + 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, + 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, + 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, + 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, + 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, + 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, + 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, + 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, + 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, + 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, + 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, + 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2, +}; + +#define SHR(x,n) ((x & 0xFFFFFFFF) >> n) +#define ROTR(x,n) (SHR(x,n) | (x << (32 - n))) + +#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3)) +#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10)) + +#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22)) +#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25)) + +#define F0(x,y,z) ((x & y) | (z & (x | y))) +#define F1(x,y,z) (z ^ (x & (y ^ z))) + +#define R(t) \ +( \ + W[t] = S1(W[t - 2]) + W[t - 7] + \ + S0(W[t - 15]) + W[t - 16] \ +) + +#define P(a,b,c,d,e,f,g,h,x,K) \ +{ \ + temp1 = h + S3(e) + F1(e,f,g) + K + x; \ + temp2 = S2(a) + F0(a,b,c); \ + d += temp1; h = temp1 + temp2; \ +} + +int mbedtls_internal_sha256_process( mbedtls_sha256_context *ctx, + const unsigned char data[64] ) +{ + uint32_t temp1, temp2, W[64]; + uint32_t A[8]; + unsigned int i; + + for( i = 0; i < 8; i++ ) + A[i] = ctx->state[i]; + +#if defined(MBEDTLS_SHA256_SMALLER) + for( i = 0; i < 64; i++ ) + { + if( i < 16 ) + GET_UINT32_BE( W[i], data, 4 * i ); + else + R( i ); + + P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i], K[i] ); + + temp1 = A[7]; A[7] = A[6]; A[6] = A[5]; A[5] = A[4]; A[4] = A[3]; + A[3] = A[2]; A[2] = A[1]; A[1] = A[0]; A[0] = temp1; + } +#else /* MBEDTLS_SHA256_SMALLER */ + for( i = 0; i < 16; i++ ) + GET_UINT32_BE( W[i], data, 4 * i ); + + for( i = 0; i < 16; i += 8 ) + { + P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i+0], K[i+0] ); + P( A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[i+1], K[i+1] ); + P( A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[i+2], K[i+2] ); + P( A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[i+3], K[i+3] ); + P( A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[i+4], K[i+4] ); + P( A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[i+5], K[i+5] ); + P( A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[i+6], K[i+6] ); + P( A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[i+7], K[i+7] ); + } + + for( i = 16; i < 64; i += 8 ) + { + P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(i+0), K[i+0] ); + P( A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(i+1), K[i+1] ); + P( A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(i+2), K[i+2] ); + P( A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(i+3), K[i+3] ); + P( A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(i+4), K[i+4] ); + P( A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(i+5), K[i+5] ); + P( A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(i+6), K[i+6] ); + P( A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(i+7), K[i+7] ); + } +#endif /* MBEDTLS_SHA256_SMALLER */ + + for( i = 0; i < 8; i++ ) + ctx->state[i] += A[i]; + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_sha256_process( mbedtls_sha256_context *ctx, + const unsigned char data[64] ) +{ + mbedtls_internal_sha256_process( ctx, data ); +} +#endif +#endif /* !MBEDTLS_SHA256_PROCESS_ALT */ + +/* + * SHA-256 process buffer + */ +int mbedtls_sha256_update_ret( mbedtls_sha256_context *ctx, + const unsigned char *input, + size_t ilen ) +{ + int ret; + size_t fill; + uint32_t left; + + if( ilen == 0 ) + return( 0 ); + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), input, fill ); + + if( ( ret = mbedtls_internal_sha256_process( ctx, ctx->buffer ) ) != 0 ) + return( ret ); + + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + if( ( ret = mbedtls_internal_sha256_process( ctx, input ) ) != 0 ) + return( ret ); + + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + memcpy( (void *) (ctx->buffer + left), input, ilen ); + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_sha256_update( mbedtls_sha256_context *ctx, + const unsigned char *input, + size_t ilen ) +{ + mbedtls_sha256_update_ret( ctx, input, ilen ); +} +#endif + +/* + * SHA-256 final digest + */ +int mbedtls_sha256_finish_ret( mbedtls_sha256_context *ctx, + unsigned char output[32] ) +{ + int ret; + uint32_t used; + uint32_t high, low; + + /* + * Add padding: 0x80 then 0x00 until 8 bytes remain for the length + */ + used = ctx->total[0] & 0x3F; + + ctx->buffer[used++] = 0x80; + + if( used <= 56 ) + { + /* Enough room for padding + length in current block */ + memset( ctx->buffer + used, 0, 56 - used ); + } + else + { + /* We'll need an extra block */ + memset( ctx->buffer + used, 0, 64 - used ); + + if( ( ret = mbedtls_internal_sha256_process( ctx, ctx->buffer ) ) != 0 ) + return( ret ); + + memset( ctx->buffer, 0, 56 ); + } + + /* + * Add message length + */ + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT32_BE( high, ctx->buffer, 56 ); + PUT_UINT32_BE( low, ctx->buffer, 60 ); + + if( ( ret = mbedtls_internal_sha256_process( ctx, ctx->buffer ) ) != 0 ) + return( ret ); + + /* + * Output final state + */ + PUT_UINT32_BE( ctx->state[0], output, 0 ); + PUT_UINT32_BE( ctx->state[1], output, 4 ); + PUT_UINT32_BE( ctx->state[2], output, 8 ); + PUT_UINT32_BE( ctx->state[3], output, 12 ); + PUT_UINT32_BE( ctx->state[4], output, 16 ); + PUT_UINT32_BE( ctx->state[5], output, 20 ); + PUT_UINT32_BE( ctx->state[6], output, 24 ); + + if( ctx->is224 == 0 ) + PUT_UINT32_BE( ctx->state[7], output, 28 ); + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_sha256_finish( mbedtls_sha256_context *ctx, + unsigned char output[32] ) +{ + mbedtls_sha256_finish_ret( ctx, output ); +} +#endif + +#endif /* !MBEDTLS_SHA256_ALT */ + +/* + * output = SHA-256( input buffer ) + */ +int mbedtls_sha256_ret( const unsigned char *input, + size_t ilen, + unsigned char output[32], + int is224 ) +{ + int ret; + mbedtls_sha256_context ctx; + + mbedtls_sha256_init( &ctx ); + + if( ( ret = mbedtls_sha256_starts_ret( &ctx, is224 ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_sha256_update_ret( &ctx, input, ilen ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_sha256_finish_ret( &ctx, output ) ) != 0 ) + goto exit; + +exit: + mbedtls_sha256_free( &ctx ); + + return( ret ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_sha256( const unsigned char *input, + size_t ilen, + unsigned char output[32], + int is224 ) +{ + mbedtls_sha256_ret( input, ilen, output, is224 ); +} +#endif + +#if defined(MBEDTLS_SELF_TEST) +/* + * FIPS-180-2 test vectors + */ +static const unsigned char sha256_test_buf[3][57] = +{ + { "abc" }, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" }, + { "" } +}; + +static const size_t sha256_test_buflen[3] = +{ + 3, 56, 1000 +}; + +static const unsigned char sha256_test_sum[6][32] = +{ + /* + * SHA-224 test vectors + */ + { 0x23, 0x09, 0x7D, 0x22, 0x34, 0x05, 0xD8, 0x22, + 0x86, 0x42, 0xA4, 0x77, 0xBD, 0xA2, 0x55, 0xB3, + 0x2A, 0xAD, 0xBC, 0xE4, 0xBD, 0xA0, 0xB3, 0xF7, + 0xE3, 0x6C, 0x9D, 0xA7 }, + { 0x75, 0x38, 0x8B, 0x16, 0x51, 0x27, 0x76, 0xCC, + 0x5D, 0xBA, 0x5D, 0xA1, 0xFD, 0x89, 0x01, 0x50, + 0xB0, 0xC6, 0x45, 0x5C, 0xB4, 0xF5, 0x8B, 0x19, + 0x52, 0x52, 0x25, 0x25 }, + { 0x20, 0x79, 0x46, 0x55, 0x98, 0x0C, 0x91, 0xD8, + 0xBB, 0xB4, 0xC1, 0xEA, 0x97, 0x61, 0x8A, 0x4B, + 0xF0, 0x3F, 0x42, 0x58, 0x19, 0x48, 0xB2, 0xEE, + 0x4E, 0xE7, 0xAD, 0x67 }, + + /* + * SHA-256 test vectors + */ + { 0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA, + 0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23, + 0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C, + 0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD }, + { 0x24, 0x8D, 0x6A, 0x61, 0xD2, 0x06, 0x38, 0xB8, + 0xE5, 0xC0, 0x26, 0x93, 0x0C, 0x3E, 0x60, 0x39, + 0xA3, 0x3C, 0xE4, 0x59, 0x64, 0xFF, 0x21, 0x67, + 0xF6, 0xEC, 0xED, 0xD4, 0x19, 0xDB, 0x06, 0xC1 }, + { 0xCD, 0xC7, 0x6E, 0x5C, 0x99, 0x14, 0xFB, 0x92, + 0x81, 0xA1, 0xC7, 0xE2, 0x84, 0xD7, 0x3E, 0x67, + 0xF1, 0x80, 0x9A, 0x48, 0xA4, 0x97, 0x20, 0x0E, + 0x04, 0x6D, 0x39, 0xCC, 0xC7, 0x11, 0x2C, 0xD0 } +}; + +/* + * Checkup routine + */ +int mbedtls_sha256_self_test( int verbose ) +{ + int i, j, k, buflen, ret = 0; + unsigned char *buf; + unsigned char sha256sum[32]; + mbedtls_sha256_context ctx; + + buf = mbedtls_calloc( 1024, sizeof(unsigned char) ); + if( NULL == buf ) + { + if( verbose != 0 ) + mbedtls_printf( "Buffer allocation failed\n" ); + + return( 1 ); + } + + mbedtls_sha256_init( &ctx ); + + for( i = 0; i < 6; i++ ) + { + j = i % 3; + k = i < 3; + + if( verbose != 0 ) + mbedtls_printf( " SHA-%d test #%d: ", 256 - k * 32, j + 1 ); + + if( ( ret = mbedtls_sha256_starts_ret( &ctx, k ) ) != 0 ) + goto fail; + + if( j == 2 ) + { + memset( buf, 'a', buflen = 1000 ); + + for( j = 0; j < 1000; j++ ) + { + ret = mbedtls_sha256_update_ret( &ctx, buf, buflen ); + if( ret != 0 ) + goto fail; + } + + } + else + { + ret = mbedtls_sha256_update_ret( &ctx, sha256_test_buf[j], + sha256_test_buflen[j] ); + if( ret != 0 ) + goto fail; + } + + if( ( ret = mbedtls_sha256_finish_ret( &ctx, sha256sum ) ) != 0 ) + goto fail; + + + if( memcmp( sha256sum, sha256_test_sum[i], 32 - k * 4 ) != 0 ) + { + ret = 1; + goto fail; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + goto exit; + +fail: + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + +exit: + mbedtls_sha256_free( &ctx ); + mbedtls_free( buf ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_SHA256_C */ diff --git a/common/mbedtls/sha256.h b/common/mbedtls/sha256.h new file mode 100644 index 00000000..0aebdde2 --- /dev/null +++ b/common/mbedtls/sha256.h @@ -0,0 +1,274 @@ +/** + * \file sha256.h + * + * \brief This file contains SHA-224 and SHA-256 definitions and functions. + * + * The Secure Hash Algorithms 224 and 256 (SHA-224 and SHA-256) cryptographic + * hash functions are defined in FIPS 180-4: Secure Hash Standard (SHS). + */ +/* + * Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_SHA256_H +#define MBEDTLS_SHA256_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#define MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED -0x0037 /**< SHA-256 hardware accelerator failed */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_SHA256_ALT) +// Regular implementation +// + +/** + * \brief The SHA-256 context structure. + * + * The structure is used both for SHA-256 and for SHA-224 + * checksum calculations. The choice between these two is + * made in the call to mbedtls_sha256_starts_ret(). + */ +typedef struct mbedtls_sha256_context +{ + uint32_t total[2]; /*!< The number of Bytes processed. */ + uint32_t state[8]; /*!< The intermediate digest state. */ + unsigned char buffer[64]; /*!< The data block being processed. */ + int is224; /*!< Determines which function to use: + 0: Use SHA-256, or 1: Use SHA-224. */ +} +mbedtls_sha256_context; + +#else /* MBEDTLS_SHA256_ALT */ +#include "sha256_alt.h" +#endif /* MBEDTLS_SHA256_ALT */ + +/** + * \brief This function initializes a SHA-256 context. + * + * \param ctx The SHA-256 context to initialize. + */ +void mbedtls_sha256_init( mbedtls_sha256_context *ctx ); + +/** + * \brief This function clears a SHA-256 context. + * + * \param ctx The SHA-256 context to clear. + */ +void mbedtls_sha256_free( mbedtls_sha256_context *ctx ); + +/** + * \brief This function clones the state of a SHA-256 context. + * + * \param dst The destination context. + * \param src The context to clone. + */ +void mbedtls_sha256_clone( mbedtls_sha256_context *dst, + const mbedtls_sha256_context *src ); + +/** + * \brief This function starts a SHA-224 or SHA-256 checksum + * calculation. + * + * \param ctx The context to initialize. + * \param is224 Determines which function to use: + * 0: Use SHA-256, or 1: Use SHA-224. + * + * \return \c 0 on success. + */ +int mbedtls_sha256_starts_ret( mbedtls_sha256_context *ctx, int is224 ); + +/** + * \brief This function feeds an input buffer into an ongoing + * SHA-256 checksum calculation. + * + * \param ctx The SHA-256 context. + * \param input The buffer holding the data. + * \param ilen The length of the input data. + * + * \return \c 0 on success. + */ +int mbedtls_sha256_update_ret( mbedtls_sha256_context *ctx, + const unsigned char *input, + size_t ilen ); + +/** + * \brief This function finishes the SHA-256 operation, and writes + * the result to the output buffer. + * + * \param ctx The SHA-256 context. + * \param output The SHA-224 or SHA-256 checksum result. + * + * \return \c 0 on success. + */ +int mbedtls_sha256_finish_ret( mbedtls_sha256_context *ctx, + unsigned char output[32] ); + +/** + * \brief This function processes a single data block within + * the ongoing SHA-256 computation. This function is for + * internal use only. + * + * \param ctx The SHA-256 context. + * \param data The buffer holding one block of data. + * + * \return \c 0 on success. + */ +int mbedtls_internal_sha256_process( mbedtls_sha256_context *ctx, + const unsigned char data[64] ); + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief This function starts a SHA-224 or SHA-256 checksum + * calculation. + * + * + * \deprecated Superseded by mbedtls_sha256_starts_ret() in 2.7.0. + * + * \param ctx The context to initialize. + * \param is224 Determines which function to use: + * 0: Use SHA-256, or 1: Use SHA-224. + */ +MBEDTLS_DEPRECATED void mbedtls_sha256_starts( mbedtls_sha256_context *ctx, + int is224 ); + +/** + * \brief This function feeds an input buffer into an ongoing + * SHA-256 checksum calculation. + * + * \deprecated Superseded by mbedtls_sha256_update_ret() in 2.7.0. + * + * \param ctx The SHA-256 context to initialize. + * \param input The buffer holding the data. + * \param ilen The length of the input data. + */ +MBEDTLS_DEPRECATED void mbedtls_sha256_update( mbedtls_sha256_context *ctx, + const unsigned char *input, + size_t ilen ); + +/** + * \brief This function finishes the SHA-256 operation, and writes + * the result to the output buffer. + * + * \deprecated Superseded by mbedtls_sha256_finish_ret() in 2.7.0. + * + * \param ctx The SHA-256 context. + * \param output The SHA-224 or SHA-256 checksum result. + */ +MBEDTLS_DEPRECATED void mbedtls_sha256_finish( mbedtls_sha256_context *ctx, + unsigned char output[32] ); + +/** + * \brief This function processes a single data block within + * the ongoing SHA-256 computation. This function is for + * internal use only. + * + * \deprecated Superseded by mbedtls_internal_sha256_process() in 2.7.0. + * + * \param ctx The SHA-256 context. + * \param data The buffer holding one block of data. + */ +MBEDTLS_DEPRECATED void mbedtls_sha256_process( mbedtls_sha256_context *ctx, + const unsigned char data[64] ); + +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +/** + * \brief This function calculates the SHA-224 or SHA-256 + * checksum of a buffer. + * + * The function allocates the context, performs the + * calculation, and frees the context. + * + * The SHA-256 result is calculated as + * output = SHA-256(input buffer). + * + * \param input The buffer holding the input data. + * \param ilen The length of the input data. + * \param output The SHA-224 or SHA-256 checksum result. + * \param is224 Determines which function to use: + * 0: Use SHA-256, or 1: Use SHA-224. + */ +int mbedtls_sha256_ret( const unsigned char *input, + size_t ilen, + unsigned char output[32], + int is224 ); + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif + +/** + * \brief This function calculates the SHA-224 or SHA-256 checksum + * of a buffer. + * + * The function allocates the context, performs the + * calculation, and frees the context. + * + * The SHA-256 result is calculated as + * output = SHA-256(input buffer). + * + * \deprecated Superseded by mbedtls_sha256_ret() in 2.7.0. + * + * \param input The buffer holding the data. + * \param ilen The length of the input data. + * \param output The SHA-224 or SHA-256 checksum result. + * \param is224 Determines which function to use: + * 0: Use SHA-256, or 1: Use SHA-224. + */ +MBEDTLS_DEPRECATED void mbedtls_sha256( const unsigned char *input, + size_t ilen, + unsigned char output[32], + int is224 ); + +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +/** + * \brief The SHA-224 and SHA-256 checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_sha256_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_sha256.h */ diff --git a/common/mbedtls/sha512.c b/common/mbedtls/sha512.c new file mode 100644 index 00000000..331965da --- /dev/null +++ b/common/mbedtls/sha512.c @@ -0,0 +1,612 @@ +/* + * FIPS-180-2 compliant SHA-384/512 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The SHA-512 Secure Hash Standard was published by NIST in 2002. + * + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SHA512_C) + +#include "mbedtls/sha512.h" +#include "mbedtls/platform_util.h" + +#if defined(_MSC_VER) || defined(__WATCOMC__) + #define UL64(x) x##ui64 +#else + #define UL64(x) x##ULL +#endif + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_printf printf +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_SHA512_ALT) + +/* + * 64-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT64_BE +#define GET_UINT64_BE(n,b,i) \ +{ \ + (n) = ( (uint64_t) (b)[(i) ] << 56 ) \ + | ( (uint64_t) (b)[(i) + 1] << 48 ) \ + | ( (uint64_t) (b)[(i) + 2] << 40 ) \ + | ( (uint64_t) (b)[(i) + 3] << 32 ) \ + | ( (uint64_t) (b)[(i) + 4] << 24 ) \ + | ( (uint64_t) (b)[(i) + 5] << 16 ) \ + | ( (uint64_t) (b)[(i) + 6] << 8 ) \ + | ( (uint64_t) (b)[(i) + 7] ); \ +} +#endif /* GET_UINT64_BE */ + +#ifndef PUT_UINT64_BE +#define PUT_UINT64_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 56 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 48 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 40 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) >> 32 ); \ + (b)[(i) + 4] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 5] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 6] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 7] = (unsigned char) ( (n) ); \ +} +#endif /* PUT_UINT64_BE */ + +void mbedtls_sha512_init( mbedtls_sha512_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_sha512_context ) ); +} + +void mbedtls_sha512_free( mbedtls_sha512_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_platform_zeroize( ctx, sizeof( mbedtls_sha512_context ) ); +} + +void mbedtls_sha512_clone( mbedtls_sha512_context *dst, + const mbedtls_sha512_context *src ) +{ + *dst = *src; +} + +/* + * SHA-512 context setup + */ +int mbedtls_sha512_starts_ret( mbedtls_sha512_context *ctx, int is384 ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + if( is384 == 0 ) + { + /* SHA-512 */ + ctx->state[0] = UL64(0x6A09E667F3BCC908); + ctx->state[1] = UL64(0xBB67AE8584CAA73B); + ctx->state[2] = UL64(0x3C6EF372FE94F82B); + ctx->state[3] = UL64(0xA54FF53A5F1D36F1); + ctx->state[4] = UL64(0x510E527FADE682D1); + ctx->state[5] = UL64(0x9B05688C2B3E6C1F); + ctx->state[6] = UL64(0x1F83D9ABFB41BD6B); + ctx->state[7] = UL64(0x5BE0CD19137E2179); + } + else + { + /* SHA-384 */ + ctx->state[0] = UL64(0xCBBB9D5DC1059ED8); + ctx->state[1] = UL64(0x629A292A367CD507); + ctx->state[2] = UL64(0x9159015A3070DD17); + ctx->state[3] = UL64(0x152FECD8F70E5939); + ctx->state[4] = UL64(0x67332667FFC00B31); + ctx->state[5] = UL64(0x8EB44A8768581511); + ctx->state[6] = UL64(0xDB0C2E0D64F98FA7); + ctx->state[7] = UL64(0x47B5481DBEFA4FA4); + } + + ctx->is384 = is384; + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_sha512_starts( mbedtls_sha512_context *ctx, + int is384 ) +{ + mbedtls_sha512_starts_ret( ctx, is384 ); +} +#endif + +#if !defined(MBEDTLS_SHA512_PROCESS_ALT) + +/* + * Round constants + */ +static const uint64_t K[80] = +{ + UL64(0x428A2F98D728AE22), UL64(0x7137449123EF65CD), + UL64(0xB5C0FBCFEC4D3B2F), UL64(0xE9B5DBA58189DBBC), + UL64(0x3956C25BF348B538), UL64(0x59F111F1B605D019), + UL64(0x923F82A4AF194F9B), UL64(0xAB1C5ED5DA6D8118), + UL64(0xD807AA98A3030242), UL64(0x12835B0145706FBE), + UL64(0x243185BE4EE4B28C), UL64(0x550C7DC3D5FFB4E2), + UL64(0x72BE5D74F27B896F), UL64(0x80DEB1FE3B1696B1), + UL64(0x9BDC06A725C71235), UL64(0xC19BF174CF692694), + UL64(0xE49B69C19EF14AD2), UL64(0xEFBE4786384F25E3), + UL64(0x0FC19DC68B8CD5B5), UL64(0x240CA1CC77AC9C65), + UL64(0x2DE92C6F592B0275), UL64(0x4A7484AA6EA6E483), + UL64(0x5CB0A9DCBD41FBD4), UL64(0x76F988DA831153B5), + UL64(0x983E5152EE66DFAB), UL64(0xA831C66D2DB43210), + UL64(0xB00327C898FB213F), UL64(0xBF597FC7BEEF0EE4), + UL64(0xC6E00BF33DA88FC2), UL64(0xD5A79147930AA725), + UL64(0x06CA6351E003826F), UL64(0x142929670A0E6E70), + UL64(0x27B70A8546D22FFC), UL64(0x2E1B21385C26C926), + UL64(0x4D2C6DFC5AC42AED), UL64(0x53380D139D95B3DF), + UL64(0x650A73548BAF63DE), UL64(0x766A0ABB3C77B2A8), + UL64(0x81C2C92E47EDAEE6), UL64(0x92722C851482353B), + UL64(0xA2BFE8A14CF10364), UL64(0xA81A664BBC423001), + UL64(0xC24B8B70D0F89791), UL64(0xC76C51A30654BE30), + UL64(0xD192E819D6EF5218), UL64(0xD69906245565A910), + UL64(0xF40E35855771202A), UL64(0x106AA07032BBD1B8), + UL64(0x19A4C116B8D2D0C8), UL64(0x1E376C085141AB53), + UL64(0x2748774CDF8EEB99), UL64(0x34B0BCB5E19B48A8), + UL64(0x391C0CB3C5C95A63), UL64(0x4ED8AA4AE3418ACB), + UL64(0x5B9CCA4F7763E373), UL64(0x682E6FF3D6B2B8A3), + UL64(0x748F82EE5DEFB2FC), UL64(0x78A5636F43172F60), + UL64(0x84C87814A1F0AB72), UL64(0x8CC702081A6439EC), + UL64(0x90BEFFFA23631E28), UL64(0xA4506CEBDE82BDE9), + UL64(0xBEF9A3F7B2C67915), UL64(0xC67178F2E372532B), + UL64(0xCA273ECEEA26619C), UL64(0xD186B8C721C0C207), + UL64(0xEADA7DD6CDE0EB1E), UL64(0xF57D4F7FEE6ED178), + UL64(0x06F067AA72176FBA), UL64(0x0A637DC5A2C898A6), + UL64(0x113F9804BEF90DAE), UL64(0x1B710B35131C471B), + UL64(0x28DB77F523047D84), UL64(0x32CAAB7B40C72493), + UL64(0x3C9EBE0A15C9BEBC), UL64(0x431D67C49C100D4C), + UL64(0x4CC5D4BECB3E42B6), UL64(0x597F299CFC657E2A), + UL64(0x5FCB6FAB3AD6FAEC), UL64(0x6C44198C4A475817) +}; + +int mbedtls_internal_sha512_process( mbedtls_sha512_context *ctx, + const unsigned char data[128] ) +{ + int i; + uint64_t temp1, temp2, W[80]; + uint64_t A, B, C, D, E, F, G, H; + +#define SHR(x,n) (x >> n) +#define ROTR(x,n) (SHR(x,n) | (x << (64 - n))) + +#define S0(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHR(x, 7)) +#define S1(x) (ROTR(x,19) ^ ROTR(x,61) ^ SHR(x, 6)) + +#define S2(x) (ROTR(x,28) ^ ROTR(x,34) ^ ROTR(x,39)) +#define S3(x) (ROTR(x,14) ^ ROTR(x,18) ^ ROTR(x,41)) + +#define F0(x,y,z) ((x & y) | (z & (x | y))) +#define F1(x,y,z) (z ^ (x & (y ^ z))) + +#define P(a,b,c,d,e,f,g,h,x,K) \ +{ \ + temp1 = h + S3(e) + F1(e,f,g) + K + x; \ + temp2 = S2(a) + F0(a,b,c); \ + d += temp1; h = temp1 + temp2; \ +} + + for( i = 0; i < 16; i++ ) + { + GET_UINT64_BE( W[i], data, i << 3 ); + } + + for( ; i < 80; i++ ) + { + W[i] = S1(W[i - 2]) + W[i - 7] + + S0(W[i - 15]) + W[i - 16]; + } + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + F = ctx->state[5]; + G = ctx->state[6]; + H = ctx->state[7]; + i = 0; + + do + { + P( A, B, C, D, E, F, G, H, W[i], K[i] ); i++; + P( H, A, B, C, D, E, F, G, W[i], K[i] ); i++; + P( G, H, A, B, C, D, E, F, W[i], K[i] ); i++; + P( F, G, H, A, B, C, D, E, W[i], K[i] ); i++; + P( E, F, G, H, A, B, C, D, W[i], K[i] ); i++; + P( D, E, F, G, H, A, B, C, W[i], K[i] ); i++; + P( C, D, E, F, G, H, A, B, W[i], K[i] ); i++; + P( B, C, D, E, F, G, H, A, W[i], K[i] ); i++; + } + while( i < 80 ); + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; + ctx->state[5] += F; + ctx->state[6] += G; + ctx->state[7] += H; + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_sha512_process( mbedtls_sha512_context *ctx, + const unsigned char data[128] ) +{ + mbedtls_internal_sha512_process( ctx, data ); +} +#endif +#endif /* !MBEDTLS_SHA512_PROCESS_ALT */ + +/* + * SHA-512 process buffer + */ +int mbedtls_sha512_update_ret( mbedtls_sha512_context *ctx, + const unsigned char *input, + size_t ilen ) +{ + int ret; + size_t fill; + unsigned int left; + + if( ilen == 0 ) + return( 0 ); + + left = (unsigned int) (ctx->total[0] & 0x7F); + fill = 128 - left; + + ctx->total[0] += (uint64_t) ilen; + + if( ctx->total[0] < (uint64_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), input, fill ); + + if( ( ret = mbedtls_internal_sha512_process( ctx, ctx->buffer ) ) != 0 ) + return( ret ); + + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 128 ) + { + if( ( ret = mbedtls_internal_sha512_process( ctx, input ) ) != 0 ) + return( ret ); + + input += 128; + ilen -= 128; + } + + if( ilen > 0 ) + memcpy( (void *) (ctx->buffer + left), input, ilen ); + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_sha512_update( mbedtls_sha512_context *ctx, + const unsigned char *input, + size_t ilen ) +{ + mbedtls_sha512_update_ret( ctx, input, ilen ); +} +#endif + +/* + * SHA-512 final digest + */ +int mbedtls_sha512_finish_ret( mbedtls_sha512_context *ctx, + unsigned char output[64] ) +{ + int ret; + unsigned used; + uint64_t high, low; + + /* + * Add padding: 0x80 then 0x00 until 16 bytes remain for the length + */ + used = ctx->total[0] & 0x7F; + + ctx->buffer[used++] = 0x80; + + if( used <= 112 ) + { + /* Enough room for padding + length in current block */ + memset( ctx->buffer + used, 0, 112 - used ); + } + else + { + /* We'll need an extra block */ + memset( ctx->buffer + used, 0, 128 - used ); + + if( ( ret = mbedtls_internal_sha512_process( ctx, ctx->buffer ) ) != 0 ) + return( ret ); + + memset( ctx->buffer, 0, 112 ); + } + + /* + * Add message length + */ + high = ( ctx->total[0] >> 61 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT64_BE( high, ctx->buffer, 112 ); + PUT_UINT64_BE( low, ctx->buffer, 120 ); + + if( ( ret = mbedtls_internal_sha512_process( ctx, ctx->buffer ) ) != 0 ) + return( ret ); + + /* + * Output final state + */ + PUT_UINT64_BE( ctx->state[0], output, 0 ); + PUT_UINT64_BE( ctx->state[1], output, 8 ); + PUT_UINT64_BE( ctx->state[2], output, 16 ); + PUT_UINT64_BE( ctx->state[3], output, 24 ); + PUT_UINT64_BE( ctx->state[4], output, 32 ); + PUT_UINT64_BE( ctx->state[5], output, 40 ); + + if( ctx->is384 == 0 ) + { + PUT_UINT64_BE( ctx->state[6], output, 48 ); + PUT_UINT64_BE( ctx->state[7], output, 56 ); + } + + return( 0 ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_sha512_finish( mbedtls_sha512_context *ctx, + unsigned char output[64] ) +{ + mbedtls_sha512_finish_ret( ctx, output ); +} +#endif + +#endif /* !MBEDTLS_SHA512_ALT */ + +/* + * output = SHA-512( input buffer ) + */ +int mbedtls_sha512_ret( const unsigned char *input, + size_t ilen, + unsigned char output[64], + int is384 ) +{ + int ret; + mbedtls_sha512_context ctx; + + mbedtls_sha512_init( &ctx ); + + if( ( ret = mbedtls_sha512_starts_ret( &ctx, is384 ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_sha512_update_ret( &ctx, input, ilen ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_sha512_finish_ret( &ctx, output ) ) != 0 ) + goto exit; + +exit: + mbedtls_sha512_free( &ctx ); + + return( ret ); +} + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +void mbedtls_sha512( const unsigned char *input, + size_t ilen, + unsigned char output[64], + int is384 ) +{ + mbedtls_sha512_ret( input, ilen, output, is384 ); +} +#endif + +#if defined(MBEDTLS_SELF_TEST) + +/* + * FIPS-180-2 test vectors + */ +static const unsigned char sha512_test_buf[3][113] = +{ + { "abc" }, + { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" + "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" }, + { "" } +}; + +static const size_t sha512_test_buflen[3] = +{ + 3, 112, 1000 +}; + +static const unsigned char sha512_test_sum[6][64] = +{ + /* + * SHA-384 test vectors + */ + { 0xCB, 0x00, 0x75, 0x3F, 0x45, 0xA3, 0x5E, 0x8B, + 0xB5, 0xA0, 0x3D, 0x69, 0x9A, 0xC6, 0x50, 0x07, + 0x27, 0x2C, 0x32, 0xAB, 0x0E, 0xDE, 0xD1, 0x63, + 0x1A, 0x8B, 0x60, 0x5A, 0x43, 0xFF, 0x5B, 0xED, + 0x80, 0x86, 0x07, 0x2B, 0xA1, 0xE7, 0xCC, 0x23, + 0x58, 0xBA, 0xEC, 0xA1, 0x34, 0xC8, 0x25, 0xA7 }, + { 0x09, 0x33, 0x0C, 0x33, 0xF7, 0x11, 0x47, 0xE8, + 0x3D, 0x19, 0x2F, 0xC7, 0x82, 0xCD, 0x1B, 0x47, + 0x53, 0x11, 0x1B, 0x17, 0x3B, 0x3B, 0x05, 0xD2, + 0x2F, 0xA0, 0x80, 0x86, 0xE3, 0xB0, 0xF7, 0x12, + 0xFC, 0xC7, 0xC7, 0x1A, 0x55, 0x7E, 0x2D, 0xB9, + 0x66, 0xC3, 0xE9, 0xFA, 0x91, 0x74, 0x60, 0x39 }, + { 0x9D, 0x0E, 0x18, 0x09, 0x71, 0x64, 0x74, 0xCB, + 0x08, 0x6E, 0x83, 0x4E, 0x31, 0x0A, 0x4A, 0x1C, + 0xED, 0x14, 0x9E, 0x9C, 0x00, 0xF2, 0x48, 0x52, + 0x79, 0x72, 0xCE, 0xC5, 0x70, 0x4C, 0x2A, 0x5B, + 0x07, 0xB8, 0xB3, 0xDC, 0x38, 0xEC, 0xC4, 0xEB, + 0xAE, 0x97, 0xDD, 0xD8, 0x7F, 0x3D, 0x89, 0x85 }, + + /* + * SHA-512 test vectors + */ + { 0xDD, 0xAF, 0x35, 0xA1, 0x93, 0x61, 0x7A, 0xBA, + 0xCC, 0x41, 0x73, 0x49, 0xAE, 0x20, 0x41, 0x31, + 0x12, 0xE6, 0xFA, 0x4E, 0x89, 0xA9, 0x7E, 0xA2, + 0x0A, 0x9E, 0xEE, 0xE6, 0x4B, 0x55, 0xD3, 0x9A, + 0x21, 0x92, 0x99, 0x2A, 0x27, 0x4F, 0xC1, 0xA8, + 0x36, 0xBA, 0x3C, 0x23, 0xA3, 0xFE, 0xEB, 0xBD, + 0x45, 0x4D, 0x44, 0x23, 0x64, 0x3C, 0xE8, 0x0E, + 0x2A, 0x9A, 0xC9, 0x4F, 0xA5, 0x4C, 0xA4, 0x9F }, + { 0x8E, 0x95, 0x9B, 0x75, 0xDA, 0xE3, 0x13, 0xDA, + 0x8C, 0xF4, 0xF7, 0x28, 0x14, 0xFC, 0x14, 0x3F, + 0x8F, 0x77, 0x79, 0xC6, 0xEB, 0x9F, 0x7F, 0xA1, + 0x72, 0x99, 0xAE, 0xAD, 0xB6, 0x88, 0x90, 0x18, + 0x50, 0x1D, 0x28, 0x9E, 0x49, 0x00, 0xF7, 0xE4, + 0x33, 0x1B, 0x99, 0xDE, 0xC4, 0xB5, 0x43, 0x3A, + 0xC7, 0xD3, 0x29, 0xEE, 0xB6, 0xDD, 0x26, 0x54, + 0x5E, 0x96, 0xE5, 0x5B, 0x87, 0x4B, 0xE9, 0x09 }, + { 0xE7, 0x18, 0x48, 0x3D, 0x0C, 0xE7, 0x69, 0x64, + 0x4E, 0x2E, 0x42, 0xC7, 0xBC, 0x15, 0xB4, 0x63, + 0x8E, 0x1F, 0x98, 0xB1, 0x3B, 0x20, 0x44, 0x28, + 0x56, 0x32, 0xA8, 0x03, 0xAF, 0xA9, 0x73, 0xEB, + 0xDE, 0x0F, 0xF2, 0x44, 0x87, 0x7E, 0xA6, 0x0A, + 0x4C, 0xB0, 0x43, 0x2C, 0xE5, 0x77, 0xC3, 0x1B, + 0xEB, 0x00, 0x9C, 0x5C, 0x2C, 0x49, 0xAA, 0x2E, + 0x4E, 0xAD, 0xB2, 0x17, 0xAD, 0x8C, 0xC0, 0x9B } +}; + +/* + * Checkup routine + */ +int mbedtls_sha512_self_test( int verbose ) +{ + int i, j, k, buflen, ret = 0; + unsigned char *buf; + unsigned char sha512sum[64]; + mbedtls_sha512_context ctx; + + buf = mbedtls_calloc( 1024, sizeof(unsigned char) ); + if( NULL == buf ) + { + if( verbose != 0 ) + mbedtls_printf( "Buffer allocation failed\n" ); + + return( 1 ); + } + + mbedtls_sha512_init( &ctx ); + + for( i = 0; i < 6; i++ ) + { + j = i % 3; + k = i < 3; + + if( verbose != 0 ) + mbedtls_printf( " SHA-%d test #%d: ", 512 - k * 128, j + 1 ); + + if( ( ret = mbedtls_sha512_starts_ret( &ctx, k ) ) != 0 ) + goto fail; + + if( j == 2 ) + { + memset( buf, 'a', buflen = 1000 ); + + for( j = 0; j < 1000; j++ ) + { + ret = mbedtls_sha512_update_ret( &ctx, buf, buflen ); + if( ret != 0 ) + goto fail; + } + } + else + { + ret = mbedtls_sha512_update_ret( &ctx, sha512_test_buf[j], + sha512_test_buflen[j] ); + if( ret != 0 ) + goto fail; + } + + if( ( ret = mbedtls_sha512_finish_ret( &ctx, sha512sum ) ) != 0 ) + goto fail; + + if( memcmp( sha512sum, sha512_test_sum[i], 64 - k * 16 ) != 0 ) + { + ret = 1; + goto fail; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + goto exit; + +fail: + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + +exit: + mbedtls_sha512_free( &ctx ); + mbedtls_free( buf ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_SHA512_C */ diff --git a/common/mbedtls/sha512.h b/common/mbedtls/sha512.h new file mode 100644 index 00000000..18f6a180 --- /dev/null +++ b/common/mbedtls/sha512.h @@ -0,0 +1,272 @@ +/** + * \file sha512.h + * \brief This file contains SHA-384 and SHA-512 definitions and functions. + * + * The Secure Hash Algorithms 384 and 512 (SHA-384 and SHA-512) cryptographic + * hash functions are defined in FIPS 180-4: Secure Hash Standard (SHS). + */ +/* + * Copyright (C) 2006-2018, Arm Limited (or its affiliates), All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_SHA512_H +#define MBEDTLS_SHA512_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#define MBEDTLS_ERR_SHA512_HW_ACCEL_FAILED -0x0039 /**< SHA-512 hardware accelerator failed */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_SHA512_ALT) +// Regular implementation +// + +/** + * \brief The SHA-512 context structure. + * + * The structure is used both for SHA-384 and for SHA-512 + * checksum calculations. The choice between these two is + * made in the call to mbedtls_sha512_starts_ret(). + */ +typedef struct mbedtls_sha512_context +{ + uint64_t total[2]; /*!< The number of Bytes processed. */ + uint64_t state[8]; /*!< The intermediate digest state. */ + unsigned char buffer[128]; /*!< The data block being processed. */ + int is384; /*!< Determines which function to use: + 0: Use SHA-512, or 1: Use SHA-384. */ +} +mbedtls_sha512_context; + +#else /* MBEDTLS_SHA512_ALT */ +#include "sha512_alt.h" +#endif /* MBEDTLS_SHA512_ALT */ + +/** + * \brief This function initializes a SHA-512 context. + * + * \param ctx The SHA-512 context to initialize. + */ +void mbedtls_sha512_init( mbedtls_sha512_context *ctx ); + +/** + * \brief This function clears a SHA-512 context. + * + * \param ctx The SHA-512 context to clear. + */ +void mbedtls_sha512_free( mbedtls_sha512_context *ctx ); + +/** + * \brief This function clones the state of a SHA-512 context. + * + * \param dst The destination context. + * \param src The context to clone. + */ +void mbedtls_sha512_clone( mbedtls_sha512_context *dst, + const mbedtls_sha512_context *src ); + +/** + * \brief This function starts a SHA-384 or SHA-512 checksum + * calculation. + * + * \param ctx The SHA-512 context to initialize. + * \param is384 Determines which function to use: + * 0: Use SHA-512, or 1: Use SHA-384. + * + * \return \c 0 on success. + */ +int mbedtls_sha512_starts_ret( mbedtls_sha512_context *ctx, int is384 ); + +/** + * \brief This function feeds an input buffer into an ongoing + * SHA-512 checksum calculation. + * + * \param ctx The SHA-512 context. + * \param input The buffer holding the input data. + * \param ilen The length of the input data. + * + * \return \c 0 on success. + */ +int mbedtls_sha512_update_ret( mbedtls_sha512_context *ctx, + const unsigned char *input, + size_t ilen ); + +/** + * \brief This function finishes the SHA-512 operation, and writes + * the result to the output buffer. This function is for + * internal use only. + * + * \param ctx The SHA-512 context. + * \param output The SHA-384 or SHA-512 checksum result. + * + * \return \c 0 on success. + */ +int mbedtls_sha512_finish_ret( mbedtls_sha512_context *ctx, + unsigned char output[64] ); + +/** + * \brief This function processes a single data block within + * the ongoing SHA-512 computation. + * + * \param ctx The SHA-512 context. + * \param data The buffer holding one block of data. + * + * \return \c 0 on success. + */ +int mbedtls_internal_sha512_process( mbedtls_sha512_context *ctx, + const unsigned char data[128] ); +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief This function starts a SHA-384 or SHA-512 checksum + * calculation. + * + * \deprecated Superseded by mbedtls_sha512_starts_ret() in 2.7.0 + * + * \param ctx The SHA-512 context to initialize. + * \param is384 Determines which function to use: + * 0: Use SHA-512, or 1: Use SHA-384. + */ +MBEDTLS_DEPRECATED void mbedtls_sha512_starts( mbedtls_sha512_context *ctx, + int is384 ); + +/** + * \brief This function feeds an input buffer into an ongoing + * SHA-512 checksum calculation. + * + * \deprecated Superseded by mbedtls_sha512_update_ret() in 2.7.0. + * + * \param ctx The SHA-512 context. + * \param input The buffer holding the data. + * \param ilen The length of the input data. + */ +MBEDTLS_DEPRECATED void mbedtls_sha512_update( mbedtls_sha512_context *ctx, + const unsigned char *input, + size_t ilen ); + +/** + * \brief This function finishes the SHA-512 operation, and writes + * the result to the output buffer. + * + * \deprecated Superseded by mbedtls_sha512_finish_ret() in 2.7.0. + * + * \param ctx The SHA-512 context. + * \param output The SHA-384 or SHA-512 checksum result. + */ +MBEDTLS_DEPRECATED void mbedtls_sha512_finish( mbedtls_sha512_context *ctx, + unsigned char output[64] ); + +/** + * \brief This function processes a single data block within + * the ongoing SHA-512 computation. This function is for + * internal use only. + * + * \deprecated Superseded by mbedtls_internal_sha512_process() in 2.7.0. + * + * \param ctx The SHA-512 context. + * \param data The buffer holding one block of data. + */ +MBEDTLS_DEPRECATED void mbedtls_sha512_process( + mbedtls_sha512_context *ctx, + const unsigned char data[128] ); + +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + +/** + * \brief This function calculates the SHA-512 or SHA-384 + * checksum of a buffer. + * + * The function allocates the context, performs the + * calculation, and frees the context. + * + * The SHA-512 result is calculated as + * output = SHA-512(input buffer). + * + * \param input The buffer holding the input data. + * \param ilen The length of the input data. + * \param output The SHA-384 or SHA-512 checksum result. + * \param is384 Determines which function to use: + * 0: Use SHA-512, or 1: Use SHA-384. + * + * \return \c 0 on success. + */ +int mbedtls_sha512_ret( const unsigned char *input, + size_t ilen, + unsigned char output[64], + int is384 ); + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief This function calculates the SHA-512 or SHA-384 + * checksum of a buffer. + * + * The function allocates the context, performs the + * calculation, and frees the context. + * + * The SHA-512 result is calculated as + * output = SHA-512(input buffer). + * + * \deprecated Superseded by mbedtls_sha512_ret() in 2.7.0 + * + * \param input The buffer holding the data. + * \param ilen The length of the input data. + * \param output The SHA-384 or SHA-512 checksum result. + * \param is384 Determines which function to use: + * 0: Use SHA-512, or 1: Use SHA-384. + */ +MBEDTLS_DEPRECATED void mbedtls_sha512( const unsigned char *input, + size_t ilen, + unsigned char output[64], + int is384 ); + +#undef MBEDTLS_DEPRECATED +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ + /** + * \brief The SHA-384 or SHA-512 checkup routine. + * + * \return \c 0 on success. + * \return \c 1 on failure. + */ +int mbedtls_sha512_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_sha512.h */ diff --git a/common/mbedtls/threading.c b/common/mbedtls/threading.c new file mode 100644 index 00000000..f7997ac9 --- /dev/null +++ b/common/mbedtls/threading.c @@ -0,0 +1,142 @@ +/* + * Threading abstraction layer + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_THREADING_C) + +#include "mbedtls/threading.h" + +#if defined(MBEDTLS_THREADING_PTHREAD) +static void threading_mutex_init_pthread( mbedtls_threading_mutex_t *mutex ) +{ + if( mutex == NULL ) + return; + + mutex->is_valid = pthread_mutex_init( &mutex->mutex, NULL ) == 0; +} + +static void threading_mutex_free_pthread( mbedtls_threading_mutex_t *mutex ) +{ + if( mutex == NULL || !mutex->is_valid ) + return; + + (void) pthread_mutex_destroy( &mutex->mutex ); + mutex->is_valid = 0; +} + +static int threading_mutex_lock_pthread( mbedtls_threading_mutex_t *mutex ) +{ + if( mutex == NULL || ! mutex->is_valid ) + return( MBEDTLS_ERR_THREADING_BAD_INPUT_DATA ); + + if( pthread_mutex_lock( &mutex->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); + + return( 0 ); +} + +static int threading_mutex_unlock_pthread( mbedtls_threading_mutex_t *mutex ) +{ + if( mutex == NULL || ! mutex->is_valid ) + return( MBEDTLS_ERR_THREADING_BAD_INPUT_DATA ); + + if( pthread_mutex_unlock( &mutex->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); + + return( 0 ); +} + +void (*mbedtls_mutex_init)( mbedtls_threading_mutex_t * ) = threading_mutex_init_pthread; +void (*mbedtls_mutex_free)( mbedtls_threading_mutex_t * ) = threading_mutex_free_pthread; +int (*mbedtls_mutex_lock)( mbedtls_threading_mutex_t * ) = threading_mutex_lock_pthread; +int (*mbedtls_mutex_unlock)( mbedtls_threading_mutex_t * ) = threading_mutex_unlock_pthread; + +/* + * With phtreads we can statically initialize mutexes + */ +#define MUTEX_INIT = { PTHREAD_MUTEX_INITIALIZER, 1 } + +#endif /* MBEDTLS_THREADING_PTHREAD */ + +#if defined(MBEDTLS_THREADING_ALT) +static int threading_mutex_fail( mbedtls_threading_mutex_t *mutex ) +{ + ((void) mutex ); + return( MBEDTLS_ERR_THREADING_BAD_INPUT_DATA ); +} +static void threading_mutex_dummy( mbedtls_threading_mutex_t *mutex ) +{ + ((void) mutex ); + return; +} + +void (*mbedtls_mutex_init)( mbedtls_threading_mutex_t * ) = threading_mutex_dummy; +void (*mbedtls_mutex_free)( mbedtls_threading_mutex_t * ) = threading_mutex_dummy; +int (*mbedtls_mutex_lock)( mbedtls_threading_mutex_t * ) = threading_mutex_fail; +int (*mbedtls_mutex_unlock)( mbedtls_threading_mutex_t * ) = threading_mutex_fail; + +/* + * Set functions pointers and initialize global mutexes + */ +void mbedtls_threading_set_alt( void (*mutex_init)( mbedtls_threading_mutex_t * ), + void (*mutex_free)( mbedtls_threading_mutex_t * ), + int (*mutex_lock)( mbedtls_threading_mutex_t * ), + int (*mutex_unlock)( mbedtls_threading_mutex_t * ) ) +{ + mbedtls_mutex_init = mutex_init; + mbedtls_mutex_free = mutex_free; + mbedtls_mutex_lock = mutex_lock; + mbedtls_mutex_unlock = mutex_unlock; + +#if defined(MBEDTLS_FS_IO) + mbedtls_mutex_init( &mbedtls_threading_readdir_mutex ); +#endif +} + +/* + * Free global mutexes + */ +void mbedtls_threading_free_alt( void ) +{ +#if defined(MBEDTLS_FS_IO) + mbedtls_mutex_free( &mbedtls_threading_readdir_mutex ); +#endif +} +#endif /* MBEDTLS_THREADING_ALT */ + +/* + * Define global mutexes + */ +#ifndef MUTEX_INIT +#define MUTEX_INIT +#endif +#if defined(MBEDTLS_FS_IO) +mbedtls_threading_mutex_t mbedtls_threading_readdir_mutex MUTEX_INIT; +#endif + +#endif /* MBEDTLS_THREADING_C */ diff --git a/common/mbedtls/threading.h b/common/mbedtls/threading.h new file mode 100644 index 00000000..bd68d5aa --- /dev/null +++ b/common/mbedtls/threading.h @@ -0,0 +1,110 @@ +/** + * \file threading.h + * + * \brief Threading abstraction layer + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_THREADING_H +#define MBEDTLS_THREADING_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE -0x001A /**< The selected feature is not available. */ +#define MBEDTLS_ERR_THREADING_BAD_INPUT_DATA -0x001C /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_THREADING_MUTEX_ERROR -0x001E /**< Locking / unlocking / free failed with error code. */ + +#if defined(MBEDTLS_THREADING_PTHREAD) +#include +typedef struct mbedtls_threading_mutex_t +{ + pthread_mutex_t mutex; + char is_valid; +} mbedtls_threading_mutex_t; +#endif + +#if defined(MBEDTLS_THREADING_ALT) +/* You should define the mbedtls_threading_mutex_t type in your header */ +#include "threading_alt.h" + +/** + * \brief Set your alternate threading implementation function + * pointers and initialize global mutexes. If used, this + * function must be called once in the main thread before any + * other mbed TLS function is called, and + * mbedtls_threading_free_alt() must be called once in the main + * thread after all other mbed TLS functions. + * + * \note mutex_init() and mutex_free() don't return a status code. + * If mutex_init() fails, it should leave its argument (the + * mutex) in a state such that mutex_lock() will fail when + * called with this argument. + * + * \param mutex_init the init function implementation + * \param mutex_free the free function implementation + * \param mutex_lock the lock function implementation + * \param mutex_unlock the unlock function implementation + */ +void mbedtls_threading_set_alt( void (*mutex_init)( mbedtls_threading_mutex_t * ), + void (*mutex_free)( mbedtls_threading_mutex_t * ), + int (*mutex_lock)( mbedtls_threading_mutex_t * ), + int (*mutex_unlock)( mbedtls_threading_mutex_t * ) ); + +/** + * \brief Free global mutexes. + */ +void mbedtls_threading_free_alt( void ); +#endif /* MBEDTLS_THREADING_ALT */ + +#if defined(MBEDTLS_THREADING_C) +/* + * The function pointers for mutex_init, mutex_free, mutex_ and mutex_unlock + * + * All these functions are expected to work or the result will be undefined. + */ +extern void (*mbedtls_mutex_init)( mbedtls_threading_mutex_t *mutex ); +extern void (*mbedtls_mutex_free)( mbedtls_threading_mutex_t *mutex ); +extern int (*mbedtls_mutex_lock)( mbedtls_threading_mutex_t *mutex ); +extern int (*mbedtls_mutex_unlock)( mbedtls_threading_mutex_t *mutex ); + +/* + * Global mutexes + */ +#if defined(MBEDTLS_FS_IO) +extern mbedtls_threading_mutex_t mbedtls_threading_readdir_mutex; +#endif +#endif /* MBEDTLS_THREADING_C */ + +#ifdef __cplusplus +} +#endif + +#endif /* threading.h */ diff --git a/common/mbedtls/timing.c b/common/mbedtls/timing.c new file mode 100644 index 00000000..fb251918 --- /dev/null +++ b/common/mbedtls/timing.c @@ -0,0 +1,547 @@ +/* + * Portable interface to the CPU cycle counter + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif + +#if defined(MBEDTLS_TIMING_C) + +#include "mbedtls/timing.h" + +#if !defined(MBEDTLS_TIMING_ALT) + +#if !defined(unix) && !defined(__unix__) && !defined(__unix) && \ + !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \ + !defined(__HAIKU__) +#error "This module only works on Unix and Windows, see MBEDTLS_TIMING_C in config.h" +#endif + +#ifndef asm +#define asm __asm +#endif + +#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) + +#include +#include + +struct _hr_time +{ + LARGE_INTEGER start; +}; + +#else + +#include +#include +#include +#include +#include + +struct _hr_time +{ + struct timeval start; +}; + +#endif /* _WIN32 && !EFIX64 && !EFI32 */ + +#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ + ( defined(_MSC_VER) && defined(_M_IX86) ) || defined(__WATCOMC__) + +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + unsigned long tsc; + __asm rdtsc + __asm mov [tsc], eax + return( tsc ); +} +#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && + ( _MSC_VER && _M_IX86 ) || __WATCOMC__ */ + +/* some versions of mingw-64 have 32-bit longs even on x84_64 */ +#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ + defined(__GNUC__) && ( defined(__i386__) || ( \ + ( defined(__amd64__) || defined( __x86_64__) ) && __SIZEOF_LONG__ == 4 ) ) + +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + unsigned long lo, hi; + asm volatile( "rdtsc" : "=a" (lo), "=d" (hi) ); + return( lo ); +} +#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && + __GNUC__ && __i386__ */ + +#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ + defined(__GNUC__) && ( defined(__amd64__) || defined(__x86_64__) ) + +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + unsigned long lo, hi; + asm volatile( "rdtsc" : "=a" (lo), "=d" (hi) ); + return( lo | ( hi << 32 ) ); +} +#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && + __GNUC__ && ( __amd64__ || __x86_64__ ) */ + +#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ + defined(__GNUC__) && ( defined(__powerpc__) || defined(__ppc__) ) + +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + unsigned long tbl, tbu0, tbu1; + + do + { + asm volatile( "mftbu %0" : "=r" (tbu0) ); + asm volatile( "mftb %0" : "=r" (tbl ) ); + asm volatile( "mftbu %0" : "=r" (tbu1) ); + } + while( tbu0 != tbu1 ); + + return( tbl ); +} +#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && + __GNUC__ && ( __powerpc__ || __ppc__ ) */ + +#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ + defined(__GNUC__) && defined(__sparc64__) + +#if defined(__OpenBSD__) +#warning OpenBSD does not allow access to tick register using software version instead +#else +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + unsigned long tick; + asm volatile( "rdpr %%tick, %0;" : "=&r" (tick) ); + return( tick ); +} +#endif /* __OpenBSD__ */ +#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && + __GNUC__ && __sparc64__ */ + +#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ + defined(__GNUC__) && defined(__sparc__) && !defined(__sparc64__) + +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + unsigned long tick; + asm volatile( ".byte 0x83, 0x41, 0x00, 0x00" ); + asm volatile( "mov %%g1, %0" : "=r" (tick) ); + return( tick ); +} +#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && + __GNUC__ && __sparc__ && !__sparc64__ */ + +#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ + defined(__GNUC__) && defined(__alpha__) + +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + unsigned long cc; + asm volatile( "rpcc %0" : "=r" (cc) ); + return( cc & 0xFFFFFFFF ); +} +#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && + __GNUC__ && __alpha__ */ + +#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ + defined(__GNUC__) && defined(__ia64__) + +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + unsigned long itc; + asm volatile( "mov %0 = ar.itc" : "=r" (itc) ); + return( itc ); +} +#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && + __GNUC__ && __ia64__ */ + +#if !defined(HAVE_HARDCLOCK) && defined(_MSC_VER) && \ + !defined(EFIX64) && !defined(EFI32) + +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + LARGE_INTEGER offset; + + QueryPerformanceCounter( &offset ); + + return( (unsigned long)( offset.QuadPart ) ); +} +#endif /* !HAVE_HARDCLOCK && _MSC_VER && !EFIX64 && !EFI32 */ + +#if !defined(HAVE_HARDCLOCK) + +#define HAVE_HARDCLOCK + +static int hardclock_init = 0; +static struct timeval tv_init; + +unsigned long mbedtls_timing_hardclock( void ) +{ + struct timeval tv_cur; + + if( hardclock_init == 0 ) + { +#ifdef __MINGW32__ + mingw_gettimeofday( &tv_init, NULL ); +#else + gettimeofday( &tv_init, NULL ); +#endif + hardclock_init = 1; + } + +#ifdef __MINGW32__ + mingw_gettimeofday( &tv_cur, NULL ); +#else + gettimeofday( &tv_cur, NULL ); +#endif + return( ( tv_cur.tv_sec - tv_init.tv_sec ) * 1000000 + + ( tv_cur.tv_usec - tv_init.tv_usec ) ); +} +#endif /* !HAVE_HARDCLOCK */ + +volatile int mbedtls_timing_alarmed = 0; + +#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) + +unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset ) +{ + struct _hr_time *t = (struct _hr_time *) val; + + if( reset ) + { + QueryPerformanceCounter( &t->start ); + return( 0 ); + } + else + { + unsigned long delta; + LARGE_INTEGER now, hfreq; + QueryPerformanceCounter( &now ); + QueryPerformanceFrequency( &hfreq ); + delta = (unsigned long)( ( now.QuadPart - t->start.QuadPart ) * 1000ul + / hfreq.QuadPart ); + return( delta ); + } +} + +/* It's OK to use a global because alarm() is supposed to be global anyway */ +static DWORD alarmMs; + +static DWORD WINAPI TimerProc( LPVOID TimerContext ) +{ + ((void) TimerContext); + Sleep( alarmMs ); + mbedtls_timing_alarmed = 1; + return( TRUE ); +} + +void mbedtls_set_alarm( int seconds ) +{ + DWORD ThreadId; + + if( seconds == 0 ) + { + /* No need to create a thread for this simple case. + * Also, this shorcut is more reliable at least on MinGW32 */ + mbedtls_timing_alarmed = 1; + return; + } + + mbedtls_timing_alarmed = 0; + alarmMs = seconds * 1000; + CloseHandle( CreateThread( NULL, 0, TimerProc, NULL, 0, &ThreadId ) ); +} + +#else /* _WIN32 && !EFIX64 && !EFI32 */ + +unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset ) +{ + struct _hr_time *t = (struct _hr_time *) val; + + if( reset ) + { + gettimeofday( &t->start, NULL ); + return( 0 ); + } + else + { + unsigned long delta; + struct timeval now; + gettimeofday( &now, NULL ); + delta = ( now.tv_sec - t->start.tv_sec ) * 1000ul + + ( now.tv_usec - t->start.tv_usec ) / 1000; + return( delta ); + } +} + +static void sighandler( int signum ) +{ + mbedtls_timing_alarmed = 1; + signal( signum, sighandler ); +} + +void mbedtls_set_alarm( int seconds ) +{ + mbedtls_timing_alarmed = 0; + signal( SIGALRM, sighandler ); + alarm( seconds ); + if( seconds == 0 ) + { + /* alarm(0) cancelled any previous pending alarm, but the + handler won't fire, so raise the flag straight away. */ + mbedtls_timing_alarmed = 1; + } +} + +#endif /* _WIN32 && !EFIX64 && !EFI32 */ + +/* + * Set delays to watch + */ +void mbedtls_timing_set_delay( void *data, uint32_t int_ms, uint32_t fin_ms ) +{ + mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data; + + ctx->int_ms = int_ms; + ctx->fin_ms = fin_ms; + + if( fin_ms != 0 ) + (void) mbedtls_timing_get_timer( &ctx->timer, 1 ); +} + +/* + * Get number of delays expired + */ +int mbedtls_timing_get_delay( void *data ) +{ + mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data; + unsigned long elapsed_ms; + + if( ctx->fin_ms == 0 ) + return( -1 ); + + elapsed_ms = mbedtls_timing_get_timer( &ctx->timer, 0 ); + + if( elapsed_ms >= ctx->fin_ms ) + return( 2 ); + + if( elapsed_ms >= ctx->int_ms ) + return( 1 ); + + return( 0 ); +} + +#endif /* !MBEDTLS_TIMING_ALT */ + +#if defined(MBEDTLS_SELF_TEST) + +/* + * Busy-waits for the given number of milliseconds. + * Used for testing mbedtls_timing_hardclock. + */ +static void busy_msleep( unsigned long msec ) +{ + struct mbedtls_timing_hr_time hires; + unsigned long i = 0; /* for busy-waiting */ + volatile unsigned long j; /* to prevent optimisation */ + + (void) mbedtls_timing_get_timer( &hires, 1 ); + + while( mbedtls_timing_get_timer( &hires, 0 ) < msec ) + i++; + + j = i; + (void) j; +} + +#define FAIL do \ + { \ + if( verbose != 0 ) \ + { \ + mbedtls_printf( "failed at line %d\n", __LINE__ ); \ + mbedtls_printf( " cycles=%lu ratio=%lu millisecs=%lu secs=%lu hardfail=%d a=%lu b=%lu\n", \ + cycles, ratio, millisecs, secs, hardfail, \ + (unsigned long) a, (unsigned long) b ); \ + mbedtls_printf( " elapsed(hires)=%lu elapsed(ctx)=%lu status(ctx)=%d\n", \ + mbedtls_timing_get_timer( &hires, 0 ), \ + mbedtls_timing_get_timer( &ctx.timer, 0 ), \ + mbedtls_timing_get_delay( &ctx ) ); \ + } \ + return( 1 ); \ + } while( 0 ) + +/* + * Checkup routine + * + * Warning: this is work in progress, some tests may not be reliable enough + * yet! False positives may happen. + */ +int mbedtls_timing_self_test( int verbose ) +{ + unsigned long cycles = 0, ratio = 0; + unsigned long millisecs = 0, secs = 0; + int hardfail = 0; + struct mbedtls_timing_hr_time hires; + uint32_t a = 0, b = 0; + mbedtls_timing_delay_context ctx; + + if( verbose != 0 ) + mbedtls_printf( " TIMING tests note: will take some time!\n" ); + + if( verbose != 0 ) + mbedtls_printf( " TIMING test #1 (set_alarm / get_timer): " ); + + { + secs = 1; + + (void) mbedtls_timing_get_timer( &hires, 1 ); + + mbedtls_set_alarm( (int) secs ); + while( !mbedtls_timing_alarmed ) + ; + + millisecs = mbedtls_timing_get_timer( &hires, 0 ); + + /* For some reason on Windows it looks like alarm has an extra delay + * (maybe related to creating a new thread). Allow some room here. */ + if( millisecs < 800 * secs || millisecs > 1200 * secs + 300 ) + FAIL; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " TIMING test #2 (set/get_delay ): " ); + + { + a = 800; + b = 400; + mbedtls_timing_set_delay( &ctx, a, a + b ); /* T = 0 */ + + busy_msleep( a - a / 4 ); /* T = a - a/4 */ + if( mbedtls_timing_get_delay( &ctx ) != 0 ) + FAIL; + + busy_msleep( a / 4 + b / 4 ); /* T = a + b/4 */ + if( mbedtls_timing_get_delay( &ctx ) != 1 ) + FAIL; + + busy_msleep( b ); /* T = a + b + b/4 */ + if( mbedtls_timing_get_delay( &ctx ) != 2 ) + FAIL; + } + + mbedtls_timing_set_delay( &ctx, 0, 0 ); + busy_msleep( 200 ); + if( mbedtls_timing_get_delay( &ctx ) != -1 ) + FAIL; + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " TIMING test #3 (hardclock / get_timer): " ); + + /* + * Allow one failure for possible counter wrapping. + * On a 4Ghz 32-bit machine the cycle counter wraps about once per second; + * since the whole test is about 10ms, it shouldn't happen twice in a row. + */ + +hard_test: + if( hardfail > 1 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed (ignored)\n" ); + + goto hard_test_done; + } + + /* Get a reference ratio cycles/ms */ + millisecs = 1; + cycles = mbedtls_timing_hardclock(); + busy_msleep( millisecs ); + cycles = mbedtls_timing_hardclock() - cycles; + ratio = cycles / millisecs; + + /* Check that the ratio is mostly constant */ + for( millisecs = 2; millisecs <= 4; millisecs++ ) + { + cycles = mbedtls_timing_hardclock(); + busy_msleep( millisecs ); + cycles = mbedtls_timing_hardclock() - cycles; + + /* Allow variation up to 20% */ + if( cycles / millisecs < ratio - ratio / 5 || + cycles / millisecs > ratio + ratio / 5 ) + { + hardfail++; + goto hard_test; + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + +hard_test_done: + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_TIMING_C */ diff --git a/common/mbedtls/timing.h b/common/mbedtls/timing.h new file mode 100644 index 00000000..74b5f710 --- /dev/null +++ b/common/mbedtls/timing.h @@ -0,0 +1,155 @@ +/** + * \file timing.h + * + * \brief Portable interface to timeouts and to the CPU cycle counter + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_TIMING_H +#define MBEDTLS_TIMING_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(MBEDTLS_TIMING_ALT) +// Regular implementation +// + +/** + * \brief timer structure + */ +struct mbedtls_timing_hr_time +{ + unsigned char opaque[32]; +}; + +/** + * \brief Context for mbedtls_timing_set/get_delay() + */ +typedef struct mbedtls_timing_delay_context +{ + struct mbedtls_timing_hr_time timer; + uint32_t int_ms; + uint32_t fin_ms; +} mbedtls_timing_delay_context; + +#else /* MBEDTLS_TIMING_ALT */ +#include "timing_alt.h" +#endif /* MBEDTLS_TIMING_ALT */ + +extern volatile int mbedtls_timing_alarmed; + +/** + * \brief Return the CPU cycle counter value + * + * \warning This is only a best effort! Do not rely on this! + * In particular, it is known to be unreliable on virtual + * machines. + * + * \note This value starts at an unspecified origin and + * may wrap around. + */ +unsigned long mbedtls_timing_hardclock( void ); + +/** + * \brief Return the elapsed time in milliseconds + * + * \param val points to a timer structure + * \param reset If 0, query the elapsed time. Otherwise (re)start the timer. + * + * \return Elapsed time since the previous reset in ms. When + * restarting, this is always 0. + * + * \note To initialize a timer, call this function with reset=1. + * + * Determining the elapsed time and resetting the timer is not + * atomic on all platforms, so after the sequence + * `{ get_timer(1); ...; time1 = get_timer(1); ...; time2 = + * get_timer(0) }` the value time1+time2 is only approximately + * the delay since the first reset. + */ +unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset ); + +/** + * \brief Setup an alarm clock + * + * \param seconds delay before the "mbedtls_timing_alarmed" flag is set + * (must be >=0) + * + * \warning Only one alarm at a time is supported. In a threaded + * context, this means one for the whole process, not one per + * thread. + */ +void mbedtls_set_alarm( int seconds ); + +/** + * \brief Set a pair of delays to watch + * (See \c mbedtls_timing_get_delay().) + * + * \param data Pointer to timing data. + * Must point to a valid \c mbedtls_timing_delay_context struct. + * \param int_ms First (intermediate) delay in milliseconds. + * The effect if int_ms > fin_ms is unspecified. + * \param fin_ms Second (final) delay in milliseconds. + * Pass 0 to cancel the current delay. + * + * \note To set a single delay, either use \c mbedtls_timing_set_timer + * directly or use this function with int_ms == fin_ms. + */ +void mbedtls_timing_set_delay( void *data, uint32_t int_ms, uint32_t fin_ms ); + +/** + * \brief Get the status of delays + * (Memory helper: number of delays passed.) + * + * \param data Pointer to timing data + * Must point to a valid \c mbedtls_timing_delay_context struct. + * + * \return -1 if cancelled (fin_ms = 0), + * 0 if none of the delays are passed, + * 1 if only the intermediate delay is passed, + * 2 if the final delay is passed. + */ +int mbedtls_timing_get_delay( void *data ); + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if a test failed + */ +int mbedtls_timing_self_test( int verbose ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* timing.h */ diff --git a/common/mbedtls/x509.c b/common/mbedtls/x509.c new file mode 100644 index 00000000..c2f72a52 --- /dev/null +++ b/common/mbedtls/x509.c @@ -0,0 +1,1073 @@ +/* + * X.509 common functions for parsing and verification + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The ITU-T X.509 standard defines a certificate format for PKI. + * + * http://www.ietf.org/rfc/rfc5280.txt (Certificates and CRLs) + * http://www.ietf.org/rfc/rfc3279.txt (Alg IDs for CRLs) + * http://www.ietf.org/rfc/rfc2986.txt (CSRs, aka PKCS#10) + * + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf + */ + +/* Ensure gmtime_r is available even with -std=c99; must be included before + * config.h, which pulls in glibc's features.h. Harmless on other platforms. */ +#define _POSIX_C_SOURCE 200112L + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_X509_USE_C) + +#include "mbedtls/x509.h" +#include "mbedtls/asn1.h" +#include "mbedtls/oid.h" + +#include +#include + +#if defined(MBEDTLS_PEM_PARSE_C) +#include "mbedtls/pem.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_free free +#define mbedtls_calloc calloc +#define mbedtls_printf printf +#define mbedtls_snprintf snprintf +#endif + +#if defined(MBEDTLS_HAVE_TIME) +#include "mbedtls/platform_time.h" +#endif +#if defined(MBEDTLS_HAVE_TIME_DATE) +#include +#endif + +#define CHECK(code) if( ( ret = code ) != 0 ){ return( ret ); } +#define CHECK_RANGE(min, max, val) if( val < min || val > max ){ return( ret ); } + +/* + * CertificateSerialNumber ::= INTEGER + */ +int mbedtls_x509_get_serial( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *serial ) +{ + int ret; + + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_X509_INVALID_SERIAL + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + if( **p != ( MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_PRIMITIVE | 2 ) && + **p != MBEDTLS_ASN1_INTEGER ) + return( MBEDTLS_ERR_X509_INVALID_SERIAL + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + serial->tag = *(*p)++; + + if( ( ret = mbedtls_asn1_get_len( p, end, &serial->len ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_SERIAL + ret ); + + serial->p = *p; + *p += serial->len; + + return( 0 ); +} + +/* Get an algorithm identifier without parameters (eg for signatures) + * + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL } + */ +int mbedtls_x509_get_alg_null( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *alg ) +{ + int ret; + + if( ( ret = mbedtls_asn1_get_alg_null( p, end, alg ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + return( 0 ); +} + +/* + * Parse an algorithm identifier with (optional) paramaters + */ +int mbedtls_x509_get_alg( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *alg, mbedtls_x509_buf *params ) +{ + int ret; + + if( ( ret = mbedtls_asn1_get_alg( p, end, alg, params ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + return( 0 ); +} + +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) +/* + * HashAlgorithm ::= AlgorithmIdentifier + * + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL } + * + * For HashAlgorithm, parameters MUST be NULL or absent. + */ +static int x509_get_hash_alg( const mbedtls_x509_buf *alg, mbedtls_md_type_t *md_alg ) +{ + int ret; + unsigned char *p; + const unsigned char *end; + mbedtls_x509_buf md_oid; + size_t len; + + /* Make sure we got a SEQUENCE and setup bounds */ + if( alg->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + p = (unsigned char *) alg->p; + end = p + alg->len; + + if( p >= end ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + /* Parse md_oid */ + md_oid.tag = *p; + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &md_oid.len, MBEDTLS_ASN1_OID ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + md_oid.p = p; + p += md_oid.len; + + /* Get md_alg from md_oid */ + if( ( ret = mbedtls_oid_get_md_alg( &md_oid, md_alg ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + /* Make sure params is absent of NULL */ + if( p == end ) + return( 0 ); + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_NULL ) ) != 0 || len != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + if( p != end ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * RSASSA-PSS-params ::= SEQUENCE { + * hashAlgorithm [0] HashAlgorithm DEFAULT sha1Identifier, + * maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1Identifier, + * saltLength [2] INTEGER DEFAULT 20, + * trailerField [3] INTEGER DEFAULT 1 } + * -- Note that the tags in this Sequence are explicit. + * + * RFC 4055 (which defines use of RSASSA-PSS in PKIX) states that the value + * of trailerField MUST be 1, and PKCS#1 v2.2 doesn't even define any other + * option. Enfore this at parsing time. + */ +int mbedtls_x509_get_rsassa_pss_params( const mbedtls_x509_buf *params, + mbedtls_md_type_t *md_alg, mbedtls_md_type_t *mgf_md, + int *salt_len ) +{ + int ret; + unsigned char *p; + const unsigned char *end, *end2; + size_t len; + mbedtls_x509_buf alg_id, alg_params; + + /* First set everything to defaults */ + *md_alg = MBEDTLS_MD_SHA1; + *mgf_md = MBEDTLS_MD_SHA1; + *salt_len = 20; + + /* Make sure params is a SEQUENCE and setup bounds */ + if( params->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + p = (unsigned char *) params->p; + end = p + params->len; + + if( p == end ) + return( 0 ); + + /* + * HashAlgorithm + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0 ) ) == 0 ) + { + end2 = p + len; + + /* HashAlgorithm ::= AlgorithmIdentifier (without parameters) */ + if( ( ret = mbedtls_x509_get_alg_null( &p, end2, &alg_id ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_oid_get_md_alg( &alg_id, md_alg ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + if( p != end2 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + if( p == end ) + return( 0 ); + + /* + * MaskGenAlgorithm + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 1 ) ) == 0 ) + { + end2 = p + len; + + /* MaskGenAlgorithm ::= AlgorithmIdentifier (params = HashAlgorithm) */ + if( ( ret = mbedtls_x509_get_alg( &p, end2, &alg_id, &alg_params ) ) != 0 ) + return( ret ); + + /* Only MFG1 is recognised for now */ + if( MBEDTLS_OID_CMP( MBEDTLS_OID_MGF1, &alg_id ) != 0 ) + return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE + + MBEDTLS_ERR_OID_NOT_FOUND ); + + /* Parse HashAlgorithm */ + if( ( ret = x509_get_hash_alg( &alg_params, mgf_md ) ) != 0 ) + return( ret ); + + if( p != end2 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + if( p == end ) + return( 0 ); + + /* + * salt_len + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 2 ) ) == 0 ) + { + end2 = p + len; + + if( ( ret = mbedtls_asn1_get_int( &p, end2, salt_len ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + if( p != end2 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + if( p == end ) + return( 0 ); + + /* + * trailer_field (if present, must be 1) + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 3 ) ) == 0 ) + { + int trailer_field; + + end2 = p + len; + + if( ( ret = mbedtls_asn1_get_int( &p, end2, &trailer_field ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + if( p != end2 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + if( trailer_field != 1 ) + return( MBEDTLS_ERR_X509_INVALID_ALG ); + } + else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + if( p != end ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} +#endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ + +/* + * AttributeTypeAndValue ::= SEQUENCE { + * type AttributeType, + * value AttributeValue } + * + * AttributeType ::= OBJECT IDENTIFIER + * + * AttributeValue ::= ANY DEFINED BY AttributeType + */ +static int x509_get_attr_type_value( unsigned char **p, + const unsigned char *end, + mbedtls_x509_name *cur ) +{ + int ret; + size_t len; + mbedtls_x509_buf *oid; + mbedtls_x509_buf *val; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_NAME + ret ); + + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_X509_INVALID_NAME + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + oid = &cur->oid; + oid->tag = **p; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &oid->len, MBEDTLS_ASN1_OID ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_NAME + ret ); + + oid->p = *p; + *p += oid->len; + + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_X509_INVALID_NAME + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + if( **p != MBEDTLS_ASN1_BMP_STRING && **p != MBEDTLS_ASN1_UTF8_STRING && + **p != MBEDTLS_ASN1_T61_STRING && **p != MBEDTLS_ASN1_PRINTABLE_STRING && + **p != MBEDTLS_ASN1_IA5_STRING && **p != MBEDTLS_ASN1_UNIVERSAL_STRING && + **p != MBEDTLS_ASN1_BIT_STRING ) + return( MBEDTLS_ERR_X509_INVALID_NAME + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + val = &cur->val; + val->tag = *(*p)++; + + if( ( ret = mbedtls_asn1_get_len( p, end, &val->len ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_NAME + ret ); + + val->p = *p; + *p += val->len; + + cur->next = NULL; + + return( 0 ); +} + +/* + * Name ::= CHOICE { -- only one possibility for now -- + * rdnSequence RDNSequence } + * + * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName + * + * RelativeDistinguishedName ::= + * SET OF AttributeTypeAndValue + * + * AttributeTypeAndValue ::= SEQUENCE { + * type AttributeType, + * value AttributeValue } + * + * AttributeType ::= OBJECT IDENTIFIER + * + * AttributeValue ::= ANY DEFINED BY AttributeType + * + * The data structure is optimized for the common case where each RDN has only + * one element, which is represented as a list of AttributeTypeAndValue. + * For the general case we still use a flat list, but we mark elements of the + * same set so that they are "merged" together in the functions that consume + * this list, eg mbedtls_x509_dn_gets(). + */ +int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end, + mbedtls_x509_name *cur ) +{ + int ret; + size_t set_len; + const unsigned char *end_set; + + /* don't use recursion, we'd risk stack overflow if not optimized */ + while( 1 ) + { + /* + * parse SET + */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &set_len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_NAME + ret ); + + end_set = *p + set_len; + + while( 1 ) + { + if( ( ret = x509_get_attr_type_value( p, end_set, cur ) ) != 0 ) + return( ret ); + + if( *p == end_set ) + break; + + /* Mark this item as being no the only one in a set */ + cur->next_merged = 1; + + cur->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_name ) ); + + if( cur->next == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + cur = cur->next; + } + + /* + * continue until end of SEQUENCE is reached + */ + if( *p == end ) + return( 0 ); + + cur->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_name ) ); + + if( cur->next == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + cur = cur->next; + } +} + +static int x509_parse_int( unsigned char **p, size_t n, int *res ) +{ + *res = 0; + + for( ; n > 0; --n ) + { + if( ( **p < '0') || ( **p > '9' ) ) + return ( MBEDTLS_ERR_X509_INVALID_DATE ); + + *res *= 10; + *res += ( *(*p)++ - '0' ); + } + + return( 0 ); +} + +static int x509_date_is_valid(const mbedtls_x509_time *t ) +{ + int ret = MBEDTLS_ERR_X509_INVALID_DATE; + int month_len; + + CHECK_RANGE( 0, 9999, t->year ); + CHECK_RANGE( 0, 23, t->hour ); + CHECK_RANGE( 0, 59, t->min ); + CHECK_RANGE( 0, 59, t->sec ); + + switch( t->mon ) + { + case 1: case 3: case 5: case 7: case 8: case 10: case 12: + month_len = 31; + break; + case 4: case 6: case 9: case 11: + month_len = 30; + break; + case 2: + if( ( !( t->year % 4 ) && t->year % 100 ) || + !( t->year % 400 ) ) + month_len = 29; + else + month_len = 28; + break; + default: + return( ret ); + } + CHECK_RANGE( 1, month_len, t->day ); + + return( 0 ); +} + +/* + * Parse an ASN1_UTC_TIME (yearlen=2) or ASN1_GENERALIZED_TIME (yearlen=4) + * field. + */ +static int x509_parse_time( unsigned char **p, size_t len, size_t yearlen, + mbedtls_x509_time *tm ) +{ + int ret; + + /* + * Minimum length is 10 or 12 depending on yearlen + */ + if ( len < yearlen + 8 ) + return ( MBEDTLS_ERR_X509_INVALID_DATE ); + len -= yearlen + 8; + + /* + * Parse year, month, day, hour, minute + */ + CHECK( x509_parse_int( p, yearlen, &tm->year ) ); + if ( 2 == yearlen ) + { + if ( tm->year < 50 ) + tm->year += 100; + + tm->year += 1900; + } + + CHECK( x509_parse_int( p, 2, &tm->mon ) ); + CHECK( x509_parse_int( p, 2, &tm->day ) ); + CHECK( x509_parse_int( p, 2, &tm->hour ) ); + CHECK( x509_parse_int( p, 2, &tm->min ) ); + + /* + * Parse seconds if present + */ + if ( len >= 2 ) + { + CHECK( x509_parse_int( p, 2, &tm->sec ) ); + len -= 2; + } + else + return ( MBEDTLS_ERR_X509_INVALID_DATE ); + + /* + * Parse trailing 'Z' if present + */ + if ( 1 == len && 'Z' == **p ) + { + (*p)++; + len--; + } + + /* + * We should have parsed all characters at this point + */ + if ( 0 != len ) + return ( MBEDTLS_ERR_X509_INVALID_DATE ); + + CHECK( x509_date_is_valid( tm ) ); + + return ( 0 ); +} + +/* + * Time ::= CHOICE { + * utcTime UTCTime, + * generalTime GeneralizedTime } + */ +int mbedtls_x509_get_time( unsigned char **p, const unsigned char *end, + mbedtls_x509_time *tm ) +{ + int ret; + size_t len, year_len; + unsigned char tag; + + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_X509_INVALID_DATE + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + tag = **p; + + if( tag == MBEDTLS_ASN1_UTC_TIME ) + year_len = 2; + else if( tag == MBEDTLS_ASN1_GENERALIZED_TIME ) + year_len = 4; + else + return( MBEDTLS_ERR_X509_INVALID_DATE + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + (*p)++; + ret = mbedtls_asn1_get_len( p, end, &len ); + + if( ret != 0 ) + return( MBEDTLS_ERR_X509_INVALID_DATE + ret ); + + return x509_parse_time( p, len, year_len, tm ); +} + +int mbedtls_x509_get_sig( unsigned char **p, const unsigned char *end, mbedtls_x509_buf *sig ) +{ + int ret; + size_t len; + int tag_type; + + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_X509_INVALID_SIGNATURE + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + tag_type = **p; + + if( ( ret = mbedtls_asn1_get_bitstring_null( p, end, &len ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_SIGNATURE + ret ); + + sig->tag = tag_type; + sig->len = len; + sig->p = *p; + + *p += len; + + return( 0 ); +} + +/* + * Get signature algorithm from alg OID and optional parameters + */ +int mbedtls_x509_get_sig_alg( const mbedtls_x509_buf *sig_oid, const mbedtls_x509_buf *sig_params, + mbedtls_md_type_t *md_alg, mbedtls_pk_type_t *pk_alg, + void **sig_opts ) +{ + int ret; + + if( *sig_opts != NULL ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_oid_get_sig_alg( sig_oid, md_alg, pk_alg ) ) != 0 ) + return( MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG + ret ); + +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + if( *pk_alg == MBEDTLS_PK_RSASSA_PSS ) + { + mbedtls_pk_rsassa_pss_options *pss_opts; + + pss_opts = mbedtls_calloc( 1, sizeof( mbedtls_pk_rsassa_pss_options ) ); + if( pss_opts == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + ret = mbedtls_x509_get_rsassa_pss_params( sig_params, + md_alg, + &pss_opts->mgf1_hash_id, + &pss_opts->expected_salt_len ); + if( ret != 0 ) + { + mbedtls_free( pss_opts ); + return( ret ); + } + + *sig_opts = (void *) pss_opts; + } + else +#endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ + { + /* Make sure parameters are absent or NULL */ + if( ( sig_params->tag != MBEDTLS_ASN1_NULL && sig_params->tag != 0 ) || + sig_params->len != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG ); + } + + return( 0 ); +} + +/* + * X.509 Extensions (No parsing of extensions, pointer should + * be either manually updated or extensions should be parsed!) + */ +int mbedtls_x509_get_ext( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *ext, int tag ) +{ + int ret; + size_t len; + + if( *p == end ) + return( 0 ); + + ext->tag = **p; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &ext->len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | tag ) ) != 0 ) + return( ret ); + + ext->p = *p; + end = *p + ext->len; + + /* + * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension + * + * Extension ::= SEQUENCE { + * extnID OBJECT IDENTIFIER, + * critical BOOLEAN DEFAULT FALSE, + * extnValue OCTET STRING } + */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( end != *p + len ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * Store the name in printable form into buf; no more + * than size characters will be written + */ +int mbedtls_x509_dn_gets( char *buf, size_t size, const mbedtls_x509_name *dn ) +{ + int ret; + size_t i, n; + unsigned char c, merge = 0; + const mbedtls_x509_name *name; + const char *short_name = NULL; + char s[MBEDTLS_X509_MAX_DN_NAME_SIZE], *p; + + memset( s, 0, sizeof( s ) ); + + name = dn; + p = buf; + n = size; + + while( name != NULL ) + { + if( !name->oid.p ) + { + name = name->next; + continue; + } + + if( name != dn ) + { + ret = mbedtls_snprintf( p, n, merge ? " + " : ", " ); + MBEDTLS_X509_SAFE_SNPRINTF; + } + + ret = mbedtls_oid_get_attr_short_name( &name->oid, &short_name ); + + if( ret == 0 ) + ret = mbedtls_snprintf( p, n, "%s=", short_name ); + else + ret = mbedtls_snprintf( p, n, "\?\?=" ); + MBEDTLS_X509_SAFE_SNPRINTF; + + for( i = 0; i < name->val.len; i++ ) + { + if( i >= sizeof( s ) - 1 ) + break; + + c = name->val.p[i]; + if( c < 32 || c == 127 || ( c > 128 && c < 160 ) ) + s[i] = '?'; + else s[i] = c; + } + s[i] = '\0'; + ret = mbedtls_snprintf( p, n, "%s", s ); + MBEDTLS_X509_SAFE_SNPRINTF; + + merge = name->next_merged; + name = name->next; + } + + return( (int) ( size - n ) ); +} + +/* + * Store the serial in printable form into buf; no more + * than size characters will be written + */ +int mbedtls_x509_serial_gets( char *buf, size_t size, const mbedtls_x509_buf *serial ) +{ + int ret; + size_t i, n, nr; + char *p; + + p = buf; + n = size; + + nr = ( serial->len <= 32 ) + ? serial->len : 28; + + for( i = 0; i < nr; i++ ) + { + if( i == 0 && nr > 1 && serial->p[i] == 0x0 ) + continue; + + ret = mbedtls_snprintf( p, n, "%02X%s", + serial->p[i], ( i < nr - 1 ) ? ":" : "" ); + MBEDTLS_X509_SAFE_SNPRINTF; + } + + if( nr != serial->len ) + { + ret = mbedtls_snprintf( p, n, "...." ); + MBEDTLS_X509_SAFE_SNPRINTF; + } + + return( (int) ( size - n ) ); +} + +/* + * Helper for writing signature algorithms + */ +int mbedtls_x509_sig_alg_gets( char *buf, size_t size, const mbedtls_x509_buf *sig_oid, + mbedtls_pk_type_t pk_alg, mbedtls_md_type_t md_alg, + const void *sig_opts ) +{ + int ret; + char *p = buf; + size_t n = size; + const char *desc = NULL; + + ret = mbedtls_oid_get_sig_alg_desc( sig_oid, &desc ); + if( ret != 0 ) + ret = mbedtls_snprintf( p, n, "???" ); + else + ret = mbedtls_snprintf( p, n, "%s", desc ); + MBEDTLS_X509_SAFE_SNPRINTF; + +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + if( pk_alg == MBEDTLS_PK_RSASSA_PSS ) + { + const mbedtls_pk_rsassa_pss_options *pss_opts; + const mbedtls_md_info_t *md_info, *mgf_md_info; + + pss_opts = (const mbedtls_pk_rsassa_pss_options *) sig_opts; + + md_info = mbedtls_md_info_from_type( md_alg ); + mgf_md_info = mbedtls_md_info_from_type( pss_opts->mgf1_hash_id ); + + ret = mbedtls_snprintf( p, n, " (%s, MGF1-%s, 0x%02X)", + md_info ? mbedtls_md_get_name( md_info ) : "???", + mgf_md_info ? mbedtls_md_get_name( mgf_md_info ) : "???", + pss_opts->expected_salt_len ); + MBEDTLS_X509_SAFE_SNPRINTF; + } +#else + ((void) pk_alg); + ((void) md_alg); + ((void) sig_opts); +#endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ + + return( (int)( size - n ) ); +} + +/* + * Helper for writing "RSA key size", "EC key size", etc + */ +int mbedtls_x509_key_size_helper( char *buf, size_t buf_size, const char *name ) +{ + char *p = buf; + size_t n = buf_size; + int ret; + + ret = mbedtls_snprintf( p, n, "%s key size", name ); + MBEDTLS_X509_SAFE_SNPRINTF; + + return( 0 ); +} + +#if defined(MBEDTLS_HAVE_TIME_DATE) +/* + * Set the time structure to the current time. + * Return 0 on success, non-zero on failure. + */ +static int x509_get_current_time( mbedtls_x509_time *now ) +{ + struct tm *lt, tm_buf; + mbedtls_time_t tt; + int ret = 0; + + tt = mbedtls_time( NULL ); +#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) + lt = gmtime_s( &tm_buf, &tt ) == 0 ? &tm_buf : NULL; +#else + lt = gmtime_r( &tt, &tm_buf ); +#endif + + if( lt == NULL ) + ret = -1; + else + { + now->year = lt->tm_year + 1900; + now->mon = lt->tm_mon + 1; + now->day = lt->tm_mday; + now->hour = lt->tm_hour; + now->min = lt->tm_min; + now->sec = lt->tm_sec; + } + + return( ret ); +} + +/* + * Return 0 if before <= after, 1 otherwise + */ +static int x509_check_time( const mbedtls_x509_time *before, const mbedtls_x509_time *after ) +{ + if( before->year > after->year ) + return( 1 ); + + if( before->year == after->year && + before->mon > after->mon ) + return( 1 ); + + if( before->year == after->year && + before->mon == after->mon && + before->day > after->day ) + return( 1 ); + + if( before->year == after->year && + before->mon == after->mon && + before->day == after->day && + before->hour > after->hour ) + return( 1 ); + + if( before->year == after->year && + before->mon == after->mon && + before->day == after->day && + before->hour == after->hour && + before->min > after->min ) + return( 1 ); + + if( before->year == after->year && + before->mon == after->mon && + before->day == after->day && + before->hour == after->hour && + before->min == after->min && + before->sec > after->sec ) + return( 1 ); + + return( 0 ); +} + +int mbedtls_x509_time_is_past( const mbedtls_x509_time *to ) +{ + mbedtls_x509_time now; + + if( x509_get_current_time( &now ) != 0 ) + return( 1 ); + + return( x509_check_time( &now, to ) ); +} + +int mbedtls_x509_time_is_future( const mbedtls_x509_time *from ) +{ + mbedtls_x509_time now; + + if( x509_get_current_time( &now ) != 0 ) + return( 1 ); + + return( x509_check_time( from, &now ) ); +} + +#else /* MBEDTLS_HAVE_TIME_DATE */ + +int mbedtls_x509_time_is_past( const mbedtls_x509_time *to ) +{ + ((void) to); + return( 0 ); +} + +int mbedtls_x509_time_is_future( const mbedtls_x509_time *from ) +{ + ((void) from); + return( 0 ); +} +#endif /* MBEDTLS_HAVE_TIME_DATE */ + +#if defined(MBEDTLS_SELF_TEST) + +#include "mbedtls/x509_crt.h" +#include "mbedtls/certs.h" + +/* + * Checkup routine + */ +int mbedtls_x509_self_test( int verbose ) +{ +#if defined(MBEDTLS_CERTS_C) && defined(MBEDTLS_SHA256_C) + int ret; + uint32_t flags; + mbedtls_x509_crt cacert; + mbedtls_x509_crt clicert; + + if( verbose != 0 ) + mbedtls_printf( " X.509 certificate load: " ); + + mbedtls_x509_crt_init( &clicert ); + + ret = mbedtls_x509_crt_parse( &clicert, (const unsigned char *) mbedtls_test_cli_crt, + mbedtls_test_cli_crt_len ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( ret ); + } + + mbedtls_x509_crt_init( &cacert ); + + ret = mbedtls_x509_crt_parse( &cacert, (const unsigned char *) mbedtls_test_ca_crt, + mbedtls_test_ca_crt_len ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( ret ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n X.509 signature verify: "); + + ret = mbedtls_x509_crt_verify( &clicert, &cacert, NULL, NULL, &flags, NULL, NULL ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( ret ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n\n"); + + mbedtls_x509_crt_free( &cacert ); + mbedtls_x509_crt_free( &clicert ); + + return( 0 ); +#else + ((void) verbose); + return( 0 ); +#endif /* MBEDTLS_CERTS_C && MBEDTLS_SHA1_C */ +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_X509_USE_C */ diff --git a/common/mbedtls/x509.h b/common/mbedtls/x509.h new file mode 100644 index 00000000..0f0ef2ee --- /dev/null +++ b/common/mbedtls/x509.h @@ -0,0 +1,335 @@ +/** + * \file x509.h + * + * \brief X.509 generic defines and structures + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_X509_H +#define MBEDTLS_X509_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "asn1.h" +#include "pk.h" + +#if defined(MBEDTLS_RSA_C) +#include "rsa.h" +#endif + +/** + * \addtogroup x509_module + * \{ + */ + +#if !defined(MBEDTLS_X509_MAX_INTERMEDIATE_CA) +/** + * Maximum number of intermediate CAs in a verification chain. + * That is, maximum length of the chain, excluding the end-entity certificate + * and the trusted root certificate. + * + * Set this to a low value to prevent an adversary from making you waste + * resources verifying an overlong certificate chain. + */ +#define MBEDTLS_X509_MAX_INTERMEDIATE_CA 8 +#endif + +/** + * \name X509 Error codes + * \{ + */ +#define MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE -0x2080 /**< Unavailable feature, e.g. RSA hashing/encryption combination. */ +#define MBEDTLS_ERR_X509_UNKNOWN_OID -0x2100 /**< Requested OID is unknown. */ +#define MBEDTLS_ERR_X509_INVALID_FORMAT -0x2180 /**< The CRT/CRL/CSR format is invalid, e.g. different type expected. */ +#define MBEDTLS_ERR_X509_INVALID_VERSION -0x2200 /**< The CRT/CRL/CSR version element is invalid. */ +#define MBEDTLS_ERR_X509_INVALID_SERIAL -0x2280 /**< The serial tag or value is invalid. */ +#define MBEDTLS_ERR_X509_INVALID_ALG -0x2300 /**< The algorithm tag or value is invalid. */ +#define MBEDTLS_ERR_X509_INVALID_NAME -0x2380 /**< The name tag or value is invalid. */ +#define MBEDTLS_ERR_X509_INVALID_DATE -0x2400 /**< The date tag or value is invalid. */ +#define MBEDTLS_ERR_X509_INVALID_SIGNATURE -0x2480 /**< The signature tag or value invalid. */ +#define MBEDTLS_ERR_X509_INVALID_EXTENSIONS -0x2500 /**< The extension tag or value is invalid. */ +#define MBEDTLS_ERR_X509_UNKNOWN_VERSION -0x2580 /**< CRT/CRL/CSR has an unsupported version number. */ +#define MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG -0x2600 /**< Signature algorithm (oid) is unsupported. */ +#define MBEDTLS_ERR_X509_SIG_MISMATCH -0x2680 /**< Signature algorithms do not match. (see \c ::mbedtls_x509_crt sig_oid) */ +#define MBEDTLS_ERR_X509_CERT_VERIFY_FAILED -0x2700 /**< Certificate verification failed, e.g. CRL, CA or signature check failed. */ +#define MBEDTLS_ERR_X509_CERT_UNKNOWN_FORMAT -0x2780 /**< Format not recognized as DER or PEM. */ +#define MBEDTLS_ERR_X509_BAD_INPUT_DATA -0x2800 /**< Input invalid. */ +#define MBEDTLS_ERR_X509_ALLOC_FAILED -0x2880 /**< Allocation of memory failed. */ +#define MBEDTLS_ERR_X509_FILE_IO_ERROR -0x2900 /**< Read/write of file failed. */ +#define MBEDTLS_ERR_X509_BUFFER_TOO_SMALL -0x2980 /**< Destination buffer is too small. */ +#define MBEDTLS_ERR_X509_FATAL_ERROR -0x3000 /**< A fatal error occured, eg the chain is too long or the vrfy callback failed. */ +/* \} name */ + +/** + * \name X509 Verify codes + * \{ + */ +/* Reminder: update x509_crt_verify_strings[] in library/x509_crt.c */ +#define MBEDTLS_X509_BADCERT_EXPIRED 0x01 /**< The certificate validity has expired. */ +#define MBEDTLS_X509_BADCERT_REVOKED 0x02 /**< The certificate has been revoked (is on a CRL). */ +#define MBEDTLS_X509_BADCERT_CN_MISMATCH 0x04 /**< The certificate Common Name (CN) does not match with the expected CN. */ +#define MBEDTLS_X509_BADCERT_NOT_TRUSTED 0x08 /**< The certificate is not correctly signed by the trusted CA. */ +#define MBEDTLS_X509_BADCRL_NOT_TRUSTED 0x10 /**< The CRL is not correctly signed by the trusted CA. */ +#define MBEDTLS_X509_BADCRL_EXPIRED 0x20 /**< The CRL is expired. */ +#define MBEDTLS_X509_BADCERT_MISSING 0x40 /**< Certificate was missing. */ +#define MBEDTLS_X509_BADCERT_SKIP_VERIFY 0x80 /**< Certificate verification was skipped. */ +#define MBEDTLS_X509_BADCERT_OTHER 0x0100 /**< Other reason (can be used by verify callback) */ +#define MBEDTLS_X509_BADCERT_FUTURE 0x0200 /**< The certificate validity starts in the future. */ +#define MBEDTLS_X509_BADCRL_FUTURE 0x0400 /**< The CRL is from the future */ +#define MBEDTLS_X509_BADCERT_KEY_USAGE 0x0800 /**< Usage does not match the keyUsage extension. */ +#define MBEDTLS_X509_BADCERT_EXT_KEY_USAGE 0x1000 /**< Usage does not match the extendedKeyUsage extension. */ +#define MBEDTLS_X509_BADCERT_NS_CERT_TYPE 0x2000 /**< Usage does not match the nsCertType extension. */ +#define MBEDTLS_X509_BADCERT_BAD_MD 0x4000 /**< The certificate is signed with an unacceptable hash. */ +#define MBEDTLS_X509_BADCERT_BAD_PK 0x8000 /**< The certificate is signed with an unacceptable PK alg (eg RSA vs ECDSA). */ +#define MBEDTLS_X509_BADCERT_BAD_KEY 0x010000 /**< The certificate is signed with an unacceptable key (eg bad curve, RSA too short). */ +#define MBEDTLS_X509_BADCRL_BAD_MD 0x020000 /**< The CRL is signed with an unacceptable hash. */ +#define MBEDTLS_X509_BADCRL_BAD_PK 0x040000 /**< The CRL is signed with an unacceptable PK alg (eg RSA vs ECDSA). */ +#define MBEDTLS_X509_BADCRL_BAD_KEY 0x080000 /**< The CRL is signed with an unacceptable key (eg bad curve, RSA too short). */ + +/* \} name */ +/* \} addtogroup x509_module */ + +/* + * X.509 v3 Key Usage Extension flags + * Reminder: update x509_info_key_usage() when adding new flags. + */ +#define MBEDTLS_X509_KU_DIGITAL_SIGNATURE (0x80) /* bit 0 */ +#define MBEDTLS_X509_KU_NON_REPUDIATION (0x40) /* bit 1 */ +#define MBEDTLS_X509_KU_KEY_ENCIPHERMENT (0x20) /* bit 2 */ +#define MBEDTLS_X509_KU_DATA_ENCIPHERMENT (0x10) /* bit 3 */ +#define MBEDTLS_X509_KU_KEY_AGREEMENT (0x08) /* bit 4 */ +#define MBEDTLS_X509_KU_KEY_CERT_SIGN (0x04) /* bit 5 */ +#define MBEDTLS_X509_KU_CRL_SIGN (0x02) /* bit 6 */ +#define MBEDTLS_X509_KU_ENCIPHER_ONLY (0x01) /* bit 7 */ +#define MBEDTLS_X509_KU_DECIPHER_ONLY (0x8000) /* bit 8 */ + +/* + * Netscape certificate types + * (http://www.mozilla.org/projects/security/pki/nss/tech-notes/tn3.html) + */ + +#define MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT (0x80) /* bit 0 */ +#define MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER (0x40) /* bit 1 */ +#define MBEDTLS_X509_NS_CERT_TYPE_EMAIL (0x20) /* bit 2 */ +#define MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING (0x10) /* bit 3 */ +#define MBEDTLS_X509_NS_CERT_TYPE_RESERVED (0x08) /* bit 4 */ +#define MBEDTLS_X509_NS_CERT_TYPE_SSL_CA (0x04) /* bit 5 */ +#define MBEDTLS_X509_NS_CERT_TYPE_EMAIL_CA (0x02) /* bit 6 */ +#define MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING_CA (0x01) /* bit 7 */ + +/* + * X.509 extension types + * + * Comments refer to the status for using certificates. Status can be + * different for writing certificates or reading CRLs or CSRs. + */ +#define MBEDTLS_X509_EXT_AUTHORITY_KEY_IDENTIFIER (1 << 0) +#define MBEDTLS_X509_EXT_SUBJECT_KEY_IDENTIFIER (1 << 1) +#define MBEDTLS_X509_EXT_KEY_USAGE (1 << 2) +#define MBEDTLS_X509_EXT_CERTIFICATE_POLICIES (1 << 3) +#define MBEDTLS_X509_EXT_POLICY_MAPPINGS (1 << 4) +#define MBEDTLS_X509_EXT_SUBJECT_ALT_NAME (1 << 5) /* Supported (DNS) */ +#define MBEDTLS_X509_EXT_ISSUER_ALT_NAME (1 << 6) +#define MBEDTLS_X509_EXT_SUBJECT_DIRECTORY_ATTRS (1 << 7) +#define MBEDTLS_X509_EXT_BASIC_CONSTRAINTS (1 << 8) /* Supported */ +#define MBEDTLS_X509_EXT_NAME_CONSTRAINTS (1 << 9) +#define MBEDTLS_X509_EXT_POLICY_CONSTRAINTS (1 << 10) +#define MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE (1 << 11) +#define MBEDTLS_X509_EXT_CRL_DISTRIBUTION_POINTS (1 << 12) +#define MBEDTLS_X509_EXT_INIHIBIT_ANYPOLICY (1 << 13) +#define MBEDTLS_X509_EXT_FRESHEST_CRL (1 << 14) + +#define MBEDTLS_X509_EXT_NS_CERT_TYPE (1 << 16) + +/* + * Storage format identifiers + * Recognized formats: PEM and DER + */ +#define MBEDTLS_X509_FORMAT_DER 1 +#define MBEDTLS_X509_FORMAT_PEM 2 + +#define MBEDTLS_X509_MAX_DN_NAME_SIZE 256 /**< Maximum value size of a DN entry */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup x509_module + * \{ */ + +/** + * \name Structures for parsing X.509 certificates, CRLs and CSRs + * \{ + */ + +/** + * Type-length-value structure that allows for ASN1 using DER. + */ +typedef mbedtls_asn1_buf mbedtls_x509_buf; + +/** + * Container for ASN1 bit strings. + */ +typedef mbedtls_asn1_bitstring mbedtls_x509_bitstring; + +/** + * Container for ASN1 named information objects. + * It allows for Relative Distinguished Names (e.g. cn=localhost,ou=code,etc.). + */ +typedef mbedtls_asn1_named_data mbedtls_x509_name; + +/** + * Container for a sequence of ASN.1 items + */ +typedef mbedtls_asn1_sequence mbedtls_x509_sequence; + +/** Container for date and time (precision in seconds). */ +typedef struct mbedtls_x509_time +{ + int year, mon, day; /**< Date. */ + int hour, min, sec; /**< Time. */ +} +mbedtls_x509_time; + +/** \} name Structures for parsing X.509 certificates, CRLs and CSRs */ +/** \} addtogroup x509_module */ + +/** + * \brief Store the certificate DN in printable form into buf; + * no more than size characters will be written. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param dn The X509 name to represent + * + * \return The length of the string written (not including the + * terminated nul byte), or a negative error code. + */ +int mbedtls_x509_dn_gets( char *buf, size_t size, const mbedtls_x509_name *dn ); + +/** + * \brief Store the certificate serial in printable form into buf; + * no more than size characters will be written. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param serial The X509 serial to represent + * + * \return The length of the string written (not including the + * terminated nul byte), or a negative error code. + */ +int mbedtls_x509_serial_gets( char *buf, size_t size, const mbedtls_x509_buf *serial ); + +/** + * \brief Check a given mbedtls_x509_time against the system time + * and tell if it's in the past. + * + * \note Intended usage is "if( is_past( valid_to ) ) ERROR". + * Hence the return value of 1 if on internal errors. + * + * \param to mbedtls_x509_time to check + * + * \return 1 if the given time is in the past or an error occured, + * 0 otherwise. + */ +int mbedtls_x509_time_is_past( const mbedtls_x509_time *to ); + +/** + * \brief Check a given mbedtls_x509_time against the system time + * and tell if it's in the future. + * + * \note Intended usage is "if( is_future( valid_from ) ) ERROR". + * Hence the return value of 1 if on internal errors. + * + * \param from mbedtls_x509_time to check + * + * \return 1 if the given time is in the future or an error occured, + * 0 otherwise. + */ +int mbedtls_x509_time_is_future( const mbedtls_x509_time *from ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_x509_self_test( int verbose ); + +/* + * Internal module functions. You probably do not want to use these unless you + * know you do. + */ +int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end, + mbedtls_x509_name *cur ); +int mbedtls_x509_get_alg_null( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *alg ); +int mbedtls_x509_get_alg( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *alg, mbedtls_x509_buf *params ); +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) +int mbedtls_x509_get_rsassa_pss_params( const mbedtls_x509_buf *params, + mbedtls_md_type_t *md_alg, mbedtls_md_type_t *mgf_md, + int *salt_len ); +#endif +int mbedtls_x509_get_sig( unsigned char **p, const unsigned char *end, mbedtls_x509_buf *sig ); +int mbedtls_x509_get_sig_alg( const mbedtls_x509_buf *sig_oid, const mbedtls_x509_buf *sig_params, + mbedtls_md_type_t *md_alg, mbedtls_pk_type_t *pk_alg, + void **sig_opts ); +int mbedtls_x509_get_time( unsigned char **p, const unsigned char *end, + mbedtls_x509_time *t ); +int mbedtls_x509_get_serial( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *serial ); +int mbedtls_x509_get_ext( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *ext, int tag ); +int mbedtls_x509_sig_alg_gets( char *buf, size_t size, const mbedtls_x509_buf *sig_oid, + mbedtls_pk_type_t pk_alg, mbedtls_md_type_t md_alg, + const void *sig_opts ); +int mbedtls_x509_key_size_helper( char *buf, size_t buf_size, const char *name ); +int mbedtls_x509_string_to_names( mbedtls_asn1_named_data **head, const char *name ); +int mbedtls_x509_set_extension( mbedtls_asn1_named_data **head, const char *oid, size_t oid_len, + int critical, const unsigned char *val, + size_t val_len ); +int mbedtls_x509_write_extensions( unsigned char **p, unsigned char *start, + mbedtls_asn1_named_data *first ); +int mbedtls_x509_write_names( unsigned char **p, unsigned char *start, + mbedtls_asn1_named_data *first ); +int mbedtls_x509_write_sig( unsigned char **p, unsigned char *start, + const char *oid, size_t oid_len, + unsigned char *sig, size_t size ); + +#define MBEDTLS_X509_SAFE_SNPRINTF \ + do { \ + if( ret < 0 || (size_t) ret >= n ) \ + return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); \ + \ + n -= (size_t) ret; \ + p += (size_t) ret; \ + } while( 0 ) + +#ifdef __cplusplus +} +#endif + +#endif /* x509.h */ diff --git a/common/mbedtls/x509_crl.c b/common/mbedtls/x509_crl.c new file mode 100644 index 00000000..12e196a3 --- /dev/null +++ b/common/mbedtls/x509_crl.c @@ -0,0 +1,775 @@ +/* + * X.509 Certidicate Revocation List (CRL) parsing + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The ITU-T X.509 standard defines a certificate format for PKI. + * + * http://www.ietf.org/rfc/rfc5280.txt (Certificates and CRLs) + * http://www.ietf.org/rfc/rfc3279.txt (Alg IDs for CRLs) + * http://www.ietf.org/rfc/rfc2986.txt (CSRs, aka PKCS#10) + * + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_X509_CRL_PARSE_C) + +#include "mbedtls/x509_crl.h" +#include "mbedtls/oid.h" +#include "mbedtls/platform_util.h" + +#include + +#if defined(MBEDTLS_PEM_PARSE_C) +#include "mbedtls/pem.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_free free +#define mbedtls_calloc calloc +#define mbedtls_snprintf snprintf +#endif + +#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) +#include +#else +#include +#endif + +#if defined(MBEDTLS_FS_IO) || defined(EFIX64) || defined(EFI32) +#include +#endif + +/* + * Version ::= INTEGER { v1(0), v2(1) } + */ +static int x509_crl_get_version( unsigned char **p, + const unsigned char *end, + int *ver ) +{ + int ret; + + if( ( ret = mbedtls_asn1_get_int( p, end, ver ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + { + *ver = 0; + return( 0 ); + } + + return( MBEDTLS_ERR_X509_INVALID_VERSION + ret ); + } + + return( 0 ); +} + +/* + * X.509 CRL v2 extensions + * + * We currently don't parse any extension's content, but we do check that the + * list of extensions is well-formed and abort on critical extensions (that + * are unsupported as we don't support any extension so far) + */ +static int x509_get_crl_ext( unsigned char **p, + const unsigned char *end, + mbedtls_x509_buf *ext ) +{ + int ret; + + /* + * crlExtensions [0] EXPLICIT Extensions OPTIONAL + * -- if present, version MUST be v2 + */ + if( ( ret = mbedtls_x509_get_ext( p, end, ext, 0 ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( 0 ); + + return( ret ); + } + + while( *p < end ) + { + /* + * Extension ::= SEQUENCE { + * extnID OBJECT IDENTIFIER, + * critical BOOLEAN DEFAULT FALSE, + * extnValue OCTET STRING } + */ + int is_critical = 0; + const unsigned char *end_ext_data; + size_t len; + + /* Get enclosing sequence tag */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + end_ext_data = *p + len; + + /* Get OID (currently ignored) */ + if( ( ret = mbedtls_asn1_get_tag( p, end_ext_data, &len, + MBEDTLS_ASN1_OID ) ) != 0 ) + { + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + } + *p += len; + + /* Get optional critical */ + if( ( ret = mbedtls_asn1_get_bool( p, end_ext_data, + &is_critical ) ) != 0 && + ( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) ) + { + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + } + + /* Data should be octet string type */ + if( ( ret = mbedtls_asn1_get_tag( p, end_ext_data, &len, + MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + /* Ignore data so far and just check its length */ + *p += len; + if( *p != end_ext_data ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + /* Abort on (unsupported) critical extensions */ + if( is_critical ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + } + + if( *p != end ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * X.509 CRL v2 entry extensions (no extensions parsed yet.) + */ +static int x509_get_crl_entry_ext( unsigned char **p, + const unsigned char *end, + mbedtls_x509_buf *ext ) +{ + int ret; + size_t len = 0; + + /* OPTIONAL */ + if( end <= *p ) + return( 0 ); + + ext->tag = **p; + ext->p = *p; + + /* + * Get CRL-entry extension sequence header + * crlEntryExtensions Extensions OPTIONAL -- if present, MUST be v2 + */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &ext->len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + { + ext->p = NULL; + return( 0 ); + } + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + } + + end = *p + ext->len; + + if( end != *p + ext->len ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + while( *p < end ) + { + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + *p += len; + } + + if( *p != end ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * X.509 CRL Entries + */ +static int x509_get_entries( unsigned char **p, + const unsigned char *end, + mbedtls_x509_crl_entry *entry ) +{ + int ret; + size_t entry_len; + mbedtls_x509_crl_entry *cur_entry = entry; + + if( *p == end ) + return( 0 ); + + if( ( ret = mbedtls_asn1_get_tag( p, end, &entry_len, + MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( 0 ); + + return( ret ); + } + + end = *p + entry_len; + + while( *p < end ) + { + size_t len2; + const unsigned char *end2; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len2, + MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED ) ) != 0 ) + { + return( ret ); + } + + cur_entry->raw.tag = **p; + cur_entry->raw.p = *p; + cur_entry->raw.len = len2; + end2 = *p + len2; + + if( ( ret = mbedtls_x509_get_serial( p, end2, &cur_entry->serial ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_x509_get_time( p, end2, + &cur_entry->revocation_date ) ) != 0 ) + return( ret ); + + if( ( ret = x509_get_crl_entry_ext( p, end2, + &cur_entry->entry_ext ) ) != 0 ) + return( ret ); + + if( *p < end ) + { + cur_entry->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_crl_entry ) ); + + if( cur_entry->next == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + cur_entry = cur_entry->next; + } + } + + return( 0 ); +} + +/* + * Parse one CRLs in DER format and append it to the chained list + */ +int mbedtls_x509_crl_parse_der( mbedtls_x509_crl *chain, + const unsigned char *buf, size_t buflen ) +{ + int ret; + size_t len; + unsigned char *p = NULL, *end = NULL; + mbedtls_x509_buf sig_params1, sig_params2, sig_oid2; + mbedtls_x509_crl *crl = chain; + + /* + * Check for valid input + */ + if( crl == NULL || buf == NULL ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + memset( &sig_params1, 0, sizeof( mbedtls_x509_buf ) ); + memset( &sig_params2, 0, sizeof( mbedtls_x509_buf ) ); + memset( &sig_oid2, 0, sizeof( mbedtls_x509_buf ) ); + + /* + * Add new CRL on the end of the chain if needed. + */ + while( crl->version != 0 && crl->next != NULL ) + crl = crl->next; + + if( crl->version != 0 && crl->next == NULL ) + { + crl->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_crl ) ); + + if( crl->next == NULL ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + } + + mbedtls_x509_crl_init( crl->next ); + crl = crl->next; + } + + /* + * Copy raw DER-encoded CRL + */ + if( buflen == 0 ) + return( MBEDTLS_ERR_X509_INVALID_FORMAT ); + + p = mbedtls_calloc( 1, buflen ); + if( p == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + memcpy( p, buf, buflen ); + + crl->raw.p = p; + crl->raw.len = buflen; + + end = p + buflen; + + /* + * CertificateList ::= SEQUENCE { + * tbsCertList TBSCertList, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT ); + } + + if( len != (size_t) ( end - p ) ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + /* + * TBSCertList ::= SEQUENCE { + */ + crl->tbs.p = p; + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); + } + + end = p + len; + crl->tbs.len = end - crl->tbs.p; + + /* + * Version ::= INTEGER OPTIONAL { v1(0), v2(1) } + * -- if present, MUST be v2 + * + * signature AlgorithmIdentifier + */ + if( ( ret = x509_crl_get_version( &p, end, &crl->version ) ) != 0 || + ( ret = mbedtls_x509_get_alg( &p, end, &crl->sig_oid, &sig_params1 ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( ret ); + } + + if( crl->version < 0 || crl->version > 1 ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_UNKNOWN_VERSION ); + } + + crl->version++; + + if( ( ret = mbedtls_x509_get_sig_alg( &crl->sig_oid, &sig_params1, + &crl->sig_md, &crl->sig_pk, + &crl->sig_opts ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG ); + } + + /* + * issuer Name + */ + crl->issuer_raw.p = p; + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); + } + + if( ( ret = mbedtls_x509_get_name( &p, p + len, &crl->issuer ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( ret ); + } + + crl->issuer_raw.len = p - crl->issuer_raw.p; + + /* + * thisUpdate Time + * nextUpdate Time OPTIONAL + */ + if( ( ret = mbedtls_x509_get_time( &p, end, &crl->this_update ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( ret ); + } + + if( ( ret = mbedtls_x509_get_time( &p, end, &crl->next_update ) ) != 0 ) + { + if( ret != ( MBEDTLS_ERR_X509_INVALID_DATE + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) && + ret != ( MBEDTLS_ERR_X509_INVALID_DATE + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ) ) + { + mbedtls_x509_crl_free( crl ); + return( ret ); + } + } + + /* + * revokedCertificates SEQUENCE OF SEQUENCE { + * userCertificate CertificateSerialNumber, + * revocationDate Time, + * crlEntryExtensions Extensions OPTIONAL + * -- if present, MUST be v2 + * } OPTIONAL + */ + if( ( ret = x509_get_entries( &p, end, &crl->entry ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( ret ); + } + + /* + * crlExtensions EXPLICIT Extensions OPTIONAL + * -- if present, MUST be v2 + */ + if( crl->version == 2 ) + { + ret = x509_get_crl_ext( &p, end, &crl->crl_ext ); + + if( ret != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( ret ); + } + } + + if( p != end ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + end = crl->raw.p + crl->raw.len; + + /* + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING + */ + if( ( ret = mbedtls_x509_get_alg( &p, end, &sig_oid2, &sig_params2 ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( ret ); + } + + if( crl->sig_oid.len != sig_oid2.len || + memcmp( crl->sig_oid.p, sig_oid2.p, crl->sig_oid.len ) != 0 || + sig_params1.len != sig_params2.len || + ( sig_params1.len != 0 && + memcmp( sig_params1.p, sig_params2.p, sig_params1.len ) != 0 ) ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_SIG_MISMATCH ); + } + + if( ( ret = mbedtls_x509_get_sig( &p, end, &crl->sig ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( ret ); + } + + if( p != end ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + return( 0 ); +} + +/* + * Parse one or more CRLs and add them to the chained list + */ +int mbedtls_x509_crl_parse( mbedtls_x509_crl *chain, const unsigned char *buf, size_t buflen ) +{ +#if defined(MBEDTLS_PEM_PARSE_C) + int ret; + size_t use_len; + mbedtls_pem_context pem; + int is_pem = 0; + + if( chain == NULL || buf == NULL ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + do + { + mbedtls_pem_init( &pem ); + + // Avoid calling mbedtls_pem_read_buffer() on non-null-terminated + // string + if( buflen == 0 || buf[buflen - 1] != '\0' ) + ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; + else + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN X509 CRL-----", + "-----END X509 CRL-----", + buf, NULL, 0, &use_len ); + + if( ret == 0 ) + { + /* + * Was PEM encoded + */ + is_pem = 1; + + buflen -= use_len; + buf += use_len; + + if( ( ret = mbedtls_x509_crl_parse_der( chain, + pem.buf, pem.buflen ) ) != 0 ) + { + mbedtls_pem_free( &pem ); + return( ret ); + } + } + else if( is_pem ) + { + mbedtls_pem_free( &pem ); + return( ret ); + } + + mbedtls_pem_free( &pem ); + } + /* In the PEM case, buflen is 1 at the end, for the terminated NULL byte. + * And a valid CRL cannot be less than 1 byte anyway. */ + while( is_pem && buflen > 1 ); + + if( is_pem ) + return( 0 ); + else +#endif /* MBEDTLS_PEM_PARSE_C */ + return( mbedtls_x509_crl_parse_der( chain, buf, buflen ) ); +} + +#if defined(MBEDTLS_FS_IO) +/* + * Load one or more CRLs and add them to the chained list + */ +int mbedtls_x509_crl_parse_file( mbedtls_x509_crl *chain, const char *path ) +{ + int ret; + size_t n; + unsigned char *buf; + + if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + ret = mbedtls_x509_crl_parse( chain, buf, n ); + + mbedtls_platform_zeroize( buf, n ); + mbedtls_free( buf ); + + return( ret ); +} +#endif /* MBEDTLS_FS_IO */ + +/* + * Return an informational string about the certificate. + */ +#define BEFORE_COLON 14 +#define BC "14" +/* + * Return an informational string about the CRL. + */ +int mbedtls_x509_crl_info( char *buf, size_t size, const char *prefix, + const mbedtls_x509_crl *crl ) +{ + int ret; + size_t n; + char *p; + const mbedtls_x509_crl_entry *entry; + + p = buf; + n = size; + + ret = mbedtls_snprintf( p, n, "%sCRL version : %d", + prefix, crl->version ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%sissuer name : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + ret = mbedtls_x509_dn_gets( p, n, &crl->issuer ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%sthis update : " \ + "%04d-%02d-%02d %02d:%02d:%02d", prefix, + crl->this_update.year, crl->this_update.mon, + crl->this_update.day, crl->this_update.hour, + crl->this_update.min, crl->this_update.sec ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%snext update : " \ + "%04d-%02d-%02d %02d:%02d:%02d", prefix, + crl->next_update.year, crl->next_update.mon, + crl->next_update.day, crl->next_update.hour, + crl->next_update.min, crl->next_update.sec ); + MBEDTLS_X509_SAFE_SNPRINTF; + + entry = &crl->entry; + + ret = mbedtls_snprintf( p, n, "\n%sRevoked certificates:", + prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + while( entry != NULL && entry->raw.len != 0 ) + { + ret = mbedtls_snprintf( p, n, "\n%sserial number: ", + prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_x509_serial_gets( p, n, &entry->serial ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, " revocation date: " \ + "%04d-%02d-%02d %02d:%02d:%02d", + entry->revocation_date.year, entry->revocation_date.mon, + entry->revocation_date.day, entry->revocation_date.hour, + entry->revocation_date.min, entry->revocation_date.sec ); + MBEDTLS_X509_SAFE_SNPRINTF; + + entry = entry->next; + } + + ret = mbedtls_snprintf( p, n, "\n%ssigned using : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_x509_sig_alg_gets( p, n, &crl->sig_oid, crl->sig_pk, crl->sig_md, + crl->sig_opts ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n" ); + MBEDTLS_X509_SAFE_SNPRINTF; + + return( (int) ( size - n ) ); +} + +/* + * Initialize a CRL chain + */ +void mbedtls_x509_crl_init( mbedtls_x509_crl *crl ) +{ + memset( crl, 0, sizeof(mbedtls_x509_crl) ); +} + +/* + * Unallocate all CRL data + */ +void mbedtls_x509_crl_free( mbedtls_x509_crl *crl ) +{ + mbedtls_x509_crl *crl_cur = crl; + mbedtls_x509_crl *crl_prv; + mbedtls_x509_name *name_cur; + mbedtls_x509_name *name_prv; + mbedtls_x509_crl_entry *entry_cur; + mbedtls_x509_crl_entry *entry_prv; + + if( crl == NULL ) + return; + + do + { +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + mbedtls_free( crl_cur->sig_opts ); +#endif + + name_cur = crl_cur->issuer.next; + while( name_cur != NULL ) + { + name_prv = name_cur; + name_cur = name_cur->next; + mbedtls_platform_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); + mbedtls_free( name_prv ); + } + + entry_cur = crl_cur->entry.next; + while( entry_cur != NULL ) + { + entry_prv = entry_cur; + entry_cur = entry_cur->next; + mbedtls_platform_zeroize( entry_prv, + sizeof( mbedtls_x509_crl_entry ) ); + mbedtls_free( entry_prv ); + } + + if( crl_cur->raw.p != NULL ) + { + mbedtls_platform_zeroize( crl_cur->raw.p, crl_cur->raw.len ); + mbedtls_free( crl_cur->raw.p ); + } + + crl_cur = crl_cur->next; + } + while( crl_cur != NULL ); + + crl_cur = crl; + do + { + crl_prv = crl_cur; + crl_cur = crl_cur->next; + + mbedtls_platform_zeroize( crl_prv, sizeof( mbedtls_x509_crl ) ); + if( crl_prv != crl ) + mbedtls_free( crl_prv ); + } + while( crl_cur != NULL ); +} + +#endif /* MBEDTLS_X509_CRL_PARSE_C */ diff --git a/common/mbedtls/x509_crl.h b/common/mbedtls/x509_crl.h new file mode 100644 index 00000000..99f6e712 --- /dev/null +++ b/common/mbedtls/x509_crl.h @@ -0,0 +1,176 @@ +/** + * \file x509_crl.h + * + * \brief X.509 certificate revocation list parsing + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_X509_CRL_H +#define MBEDTLS_X509_CRL_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "x509.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup x509_module + * \{ */ + +/** + * \name Structures and functions for parsing CRLs + * \{ + */ + +/** + * Certificate revocation list entry. + * Contains the CA-specific serial numbers and revocation dates. + */ +typedef struct mbedtls_x509_crl_entry +{ + mbedtls_x509_buf raw; + + mbedtls_x509_buf serial; + + mbedtls_x509_time revocation_date; + + mbedtls_x509_buf entry_ext; + + struct mbedtls_x509_crl_entry *next; +} +mbedtls_x509_crl_entry; + +/** + * Certificate revocation list structure. + * Every CRL may have multiple entries. + */ +typedef struct mbedtls_x509_crl +{ + mbedtls_x509_buf raw; /**< The raw certificate data (DER). */ + mbedtls_x509_buf tbs; /**< The raw certificate body (DER). The part that is To Be Signed. */ + + int version; /**< CRL version (1=v1, 2=v2) */ + mbedtls_x509_buf sig_oid; /**< CRL signature type identifier */ + + mbedtls_x509_buf issuer_raw; /**< The raw issuer data (DER). */ + + mbedtls_x509_name issuer; /**< The parsed issuer data (named information object). */ + + mbedtls_x509_time this_update; + mbedtls_x509_time next_update; + + mbedtls_x509_crl_entry entry; /**< The CRL entries containing the certificate revocation times for this CA. */ + + mbedtls_x509_buf crl_ext; + + mbedtls_x509_buf sig_oid2; + mbedtls_x509_buf sig; + mbedtls_md_type_t sig_md; /**< Internal representation of the MD algorithm of the signature algorithm, e.g. MBEDTLS_MD_SHA256 */ + mbedtls_pk_type_t sig_pk; /**< Internal representation of the Public Key algorithm of the signature algorithm, e.g. MBEDTLS_PK_RSA */ + void *sig_opts; /**< Signature options to be passed to mbedtls_pk_verify_ext(), e.g. for RSASSA-PSS */ + + struct mbedtls_x509_crl *next; +} +mbedtls_x509_crl; + +/** + * \brief Parse a DER-encoded CRL and append it to the chained list + * + * \param chain points to the start of the chain + * \param buf buffer holding the CRL data in DER format + * \param buflen size of the buffer + * (including the terminating null byte for PEM data) + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int mbedtls_x509_crl_parse_der( mbedtls_x509_crl *chain, + const unsigned char *buf, size_t buflen ); +/** + * \brief Parse one or more CRLs and append them to the chained list + * + * \note Mutliple CRLs are accepted only if using PEM format + * + * \param chain points to the start of the chain + * \param buf buffer holding the CRL data in PEM or DER format + * \param buflen size of the buffer + * (including the terminating null byte for PEM data) + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int mbedtls_x509_crl_parse( mbedtls_x509_crl *chain, const unsigned char *buf, size_t buflen ); + +#if defined(MBEDTLS_FS_IO) +/** + * \brief Load one or more CRLs and append them to the chained list + * + * \note Mutliple CRLs are accepted only if using PEM format + * + * \param chain points to the start of the chain + * \param path filename to read the CRLs from (in PEM or DER encoding) + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int mbedtls_x509_crl_parse_file( mbedtls_x509_crl *chain, const char *path ); +#endif /* MBEDTLS_FS_IO */ + +/** + * \brief Returns an informational string about the CRL. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param prefix A line prefix + * \param crl The X509 CRL to represent + * + * \return The length of the string written (not including the + * terminated nul byte), or a negative error code. + */ +int mbedtls_x509_crl_info( char *buf, size_t size, const char *prefix, + const mbedtls_x509_crl *crl ); + +/** + * \brief Initialize a CRL (chain) + * + * \param crl CRL chain to initialize + */ +void mbedtls_x509_crl_init( mbedtls_x509_crl *crl ); + +/** + * \brief Unallocate all CRL data + * + * \param crl CRL chain to free + */ +void mbedtls_x509_crl_free( mbedtls_x509_crl *crl ); + +/* \} name */ +/* \} addtogroup x509_module */ + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_x509_crl.h */ diff --git a/common/mbedtls/x509_crt.c b/common/mbedtls/x509_crt.c new file mode 100644 index 00000000..925bddf1 --- /dev/null +++ b/common/mbedtls/x509_crt.c @@ -0,0 +1,2488 @@ +/* + * X.509 certificate parsing and verification + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The ITU-T X.509 standard defines a certificate format for PKI. + * + * http://www.ietf.org/rfc/rfc5280.txt (Certificates and CRLs) + * http://www.ietf.org/rfc/rfc3279.txt (Alg IDs for CRLs) + * http://www.ietf.org/rfc/rfc2986.txt (CSRs, aka PKCS#10) + * + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf + * + * [SIRO] https://cabforum.org/wp-content/uploads/Chunghwatelecom201503cabforumV4.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + +#include "mbedtls/x509_crt.h" +#include "mbedtls/oid.h" +#include "mbedtls/platform_util.h" + +#include +#include + +#if defined(MBEDTLS_PEM_PARSE_C) +#include "mbedtls/pem.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_free free +#define mbedtls_calloc calloc +#define mbedtls_snprintf snprintf +#endif + +#if defined(MBEDTLS_THREADING_C) +#include "mbedtls/threading.h" +#endif + +#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) +#include +#else +#include +#endif + +#if defined(MBEDTLS_FS_IO) +#include +#if !defined(_WIN32) || defined(EFIX64) || defined(EFI32) +#include +#include +#include +#endif /* !_WIN32 || EFIX64 || EFI32 */ +#endif + +/* + * Item in a verification chain: cert and flags for it + */ +typedef struct { + mbedtls_x509_crt *crt; + uint32_t flags; +} x509_crt_verify_chain_item; + +/* + * Max size of verification chain: end-entity + intermediates + trusted root + */ +#define X509_MAX_VERIFY_CHAIN_SIZE ( MBEDTLS_X509_MAX_INTERMEDIATE_CA + 2 ) + +/* + * Default profile + */ +const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_default = +{ +#if defined(MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_CERTIFICATES) + /* Allow SHA-1 (weak, but still safe in controlled environments) */ + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA1 ) | +#endif + /* Only SHA-2 hashes */ + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA224 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ), + 0xFFFFFFF, /* Any PK alg */ + 0xFFFFFFF, /* Any curve */ + 2048, +}; + +/* + * Next-default profile + */ +const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_next = +{ + /* Hashes from SHA-256 and above */ + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ), + 0xFFFFFFF, /* Any PK alg */ +#if defined(MBEDTLS_ECP_C) + /* Curves at or above 128-bit security level */ + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP256R1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP384R1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP521R1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_BP256R1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_BP384R1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_BP512R1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP256K1 ), +#else + 0, +#endif + 2048, +}; + +/* + * NSA Suite B Profile + */ +const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_suiteb = +{ + /* Only SHA-256 and 384 */ + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ), + /* Only ECDSA */ + MBEDTLS_X509_ID_FLAG( MBEDTLS_PK_ECDSA ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_PK_ECKEY ), +#if defined(MBEDTLS_ECP_C) + /* Only NIST P-256 and P-384 */ + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP256R1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP384R1 ), +#else + 0, +#endif + 0, +}; + +/* + * Check md_alg against profile + * Return 0 if md_alg is acceptable for this profile, -1 otherwise + */ +static int x509_profile_check_md_alg( const mbedtls_x509_crt_profile *profile, + mbedtls_md_type_t md_alg ) +{ + if( md_alg == MBEDTLS_MD_NONE ) + return( -1 ); + + if( ( profile->allowed_mds & MBEDTLS_X509_ID_FLAG( md_alg ) ) != 0 ) + return( 0 ); + + return( -1 ); +} + +/* + * Check pk_alg against profile + * Return 0 if pk_alg is acceptable for this profile, -1 otherwise + */ +static int x509_profile_check_pk_alg( const mbedtls_x509_crt_profile *profile, + mbedtls_pk_type_t pk_alg ) +{ + if( pk_alg == MBEDTLS_PK_NONE ) + return( -1 ); + + if( ( profile->allowed_pks & MBEDTLS_X509_ID_FLAG( pk_alg ) ) != 0 ) + return( 0 ); + + return( -1 ); +} + +/* + * Check key against profile + * Return 0 if pk is acceptable for this profile, -1 otherwise + */ +static int x509_profile_check_key( const mbedtls_x509_crt_profile *profile, + const mbedtls_pk_context *pk ) +{ + const mbedtls_pk_type_t pk_alg = mbedtls_pk_get_type( pk ); + +#if defined(MBEDTLS_RSA_C) + if( pk_alg == MBEDTLS_PK_RSA || pk_alg == MBEDTLS_PK_RSASSA_PSS ) + { + if( mbedtls_pk_get_bitlen( pk ) >= profile->rsa_min_bitlen ) + return( 0 ); + + return( -1 ); + } +#endif + +#if defined(MBEDTLS_ECP_C) + if( pk_alg == MBEDTLS_PK_ECDSA || + pk_alg == MBEDTLS_PK_ECKEY || + pk_alg == MBEDTLS_PK_ECKEY_DH ) + { + const mbedtls_ecp_group_id gid = mbedtls_pk_ec( *pk )->grp.id; + + if( gid == MBEDTLS_ECP_DP_NONE ) + return( -1 ); + + if( ( profile->allowed_curves & MBEDTLS_X509_ID_FLAG( gid ) ) != 0 ) + return( 0 ); + + return( -1 ); + } +#endif + + return( -1 ); +} + +/* + * Version ::= INTEGER { v1(0), v2(1), v3(2) } + */ +static int x509_get_version( unsigned char **p, + const unsigned char *end, + int *ver ) +{ + int ret; + size_t len; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0 ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + { + *ver = 0; + return( 0 ); + } + + return( ret ); + } + + end = *p + len; + + if( ( ret = mbedtls_asn1_get_int( p, end, ver ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_VERSION + ret ); + + if( *p != end ) + return( MBEDTLS_ERR_X509_INVALID_VERSION + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * Validity ::= SEQUENCE { + * notBefore Time, + * notAfter Time } + */ +static int x509_get_dates( unsigned char **p, + const unsigned char *end, + mbedtls_x509_time *from, + mbedtls_x509_time *to ) +{ + int ret; + size_t len; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_DATE + ret ); + + end = *p + len; + + if( ( ret = mbedtls_x509_get_time( p, end, from ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_x509_get_time( p, end, to ) ) != 0 ) + return( ret ); + + if( *p != end ) + return( MBEDTLS_ERR_X509_INVALID_DATE + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * X.509 v2/v3 unique identifier (not parsed) + */ +static int x509_get_uid( unsigned char **p, + const unsigned char *end, + mbedtls_x509_buf *uid, int n ) +{ + int ret; + + if( *p == end ) + return( 0 ); + + uid->tag = **p; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &uid->len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | n ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( 0 ); + + return( ret ); + } + + uid->p = *p; + *p += uid->len; + + return( 0 ); +} + +static int x509_get_basic_constraints( unsigned char **p, + const unsigned char *end, + int *ca_istrue, + int *max_pathlen ) +{ + int ret; + size_t len; + + /* + * BasicConstraints ::= SEQUENCE { + * cA BOOLEAN DEFAULT FALSE, + * pathLenConstraint INTEGER (0..MAX) OPTIONAL } + */ + *ca_istrue = 0; /* DEFAULT FALSE */ + *max_pathlen = 0; /* endless */ + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( *p == end ) + return( 0 ); + + if( ( ret = mbedtls_asn1_get_bool( p, end, ca_istrue ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + ret = mbedtls_asn1_get_int( p, end, ca_istrue ); + + if( ret != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( *ca_istrue != 0 ) + *ca_istrue = 1; + } + + if( *p == end ) + return( 0 ); + + if( ( ret = mbedtls_asn1_get_int( p, end, max_pathlen ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( *p != end ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + (*max_pathlen)++; + + return( 0 ); +} + +static int x509_get_ns_cert_type( unsigned char **p, + const unsigned char *end, + unsigned char *ns_cert_type) +{ + int ret; + mbedtls_x509_bitstring bs = { 0, 0, NULL }; + + if( ( ret = mbedtls_asn1_get_bitstring( p, end, &bs ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( bs.len != 1 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_INVALID_LENGTH ); + + /* Get actual bitstring */ + *ns_cert_type = *bs.p; + return( 0 ); +} + +static int x509_get_key_usage( unsigned char **p, + const unsigned char *end, + unsigned int *key_usage) +{ + int ret; + size_t i; + mbedtls_x509_bitstring bs = { 0, 0, NULL }; + + if( ( ret = mbedtls_asn1_get_bitstring( p, end, &bs ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( bs.len < 1 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_INVALID_LENGTH ); + + /* Get actual bitstring */ + *key_usage = 0; + for( i = 0; i < bs.len && i < sizeof( unsigned int ); i++ ) + { + *key_usage |= (unsigned int) bs.p[i] << (8*i); + } + + return( 0 ); +} + +/* + * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId + * + * KeyPurposeId ::= OBJECT IDENTIFIER + */ +static int x509_get_ext_key_usage( unsigned char **p, + const unsigned char *end, + mbedtls_x509_sequence *ext_key_usage) +{ + int ret; + + if( ( ret = mbedtls_asn1_get_sequence_of( p, end, ext_key_usage, MBEDTLS_ASN1_OID ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + /* Sequence length must be >= 1 */ + if( ext_key_usage->buf.p == NULL ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_INVALID_LENGTH ); + + return( 0 ); +} + +/* + * SubjectAltName ::= GeneralNames + * + * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName + * + * GeneralName ::= CHOICE { + * otherName [0] OtherName, + * rfc822Name [1] IA5String, + * dNSName [2] IA5String, + * x400Address [3] ORAddress, + * directoryName [4] Name, + * ediPartyName [5] EDIPartyName, + * uniformResourceIdentifier [6] IA5String, + * iPAddress [7] OCTET STRING, + * registeredID [8] OBJECT IDENTIFIER } + * + * OtherName ::= SEQUENCE { + * type-id OBJECT IDENTIFIER, + * value [0] EXPLICIT ANY DEFINED BY type-id } + * + * EDIPartyName ::= SEQUENCE { + * nameAssigner [0] DirectoryString OPTIONAL, + * partyName [1] DirectoryString } + * + * NOTE: we only parse and use dNSName at this point. + */ +static int x509_get_subject_alt_name( unsigned char **p, + const unsigned char *end, + mbedtls_x509_sequence *subject_alt_name ) +{ + int ret; + size_t len, tag_len; + mbedtls_asn1_buf *buf; + unsigned char tag; + mbedtls_asn1_sequence *cur = subject_alt_name; + + /* Get main sequence tag */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( *p + len != end ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + while( *p < end ) + { + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + tag = **p; + (*p)++; + if( ( ret = mbedtls_asn1_get_len( p, end, &tag_len ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( ( tag & MBEDTLS_ASN1_TAG_CLASS_MASK ) != + MBEDTLS_ASN1_CONTEXT_SPECIFIC ) + { + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + } + + /* Skip everything but DNS name */ + if( tag != ( MBEDTLS_ASN1_CONTEXT_SPECIFIC | 2 ) ) + { + *p += tag_len; + continue; + } + + /* Allocate and assign next pointer */ + if( cur->buf.p != NULL ) + { + if( cur->next != NULL ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS ); + + cur->next = mbedtls_calloc( 1, sizeof( mbedtls_asn1_sequence ) ); + + if( cur->next == NULL ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_ALLOC_FAILED ); + + cur = cur->next; + } + + buf = &(cur->buf); + buf->tag = tag; + buf->p = *p; + buf->len = tag_len; + *p += buf->len; + } + + /* Set final sequence entry's next pointer to NULL */ + cur->next = NULL; + + if( *p != end ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * X.509 v3 extensions + * + */ +static int x509_get_crt_ext( unsigned char **p, + const unsigned char *end, + mbedtls_x509_crt *crt ) +{ + int ret; + size_t len; + unsigned char *end_ext_data, *end_ext_octet; + + if( ( ret = mbedtls_x509_get_ext( p, end, &crt->v3_ext, 3 ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( 0 ); + + return( ret ); + } + + while( *p < end ) + { + /* + * Extension ::= SEQUENCE { + * extnID OBJECT IDENTIFIER, + * critical BOOLEAN DEFAULT FALSE, + * extnValue OCTET STRING } + */ + mbedtls_x509_buf extn_oid = {0, 0, NULL}; + int is_critical = 0; /* DEFAULT FALSE */ + int ext_type = 0; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + end_ext_data = *p + len; + + /* Get extension ID */ + if( ( ret = mbedtls_asn1_get_tag( p, end_ext_data, &extn_oid.len, + MBEDTLS_ASN1_OID ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + extn_oid.tag = MBEDTLS_ASN1_OID; + extn_oid.p = *p; + *p += extn_oid.len; + + /* Get optional critical */ + if( ( ret = mbedtls_asn1_get_bool( p, end_ext_data, &is_critical ) ) != 0 && + ( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + /* Data should be octet string type */ + if( ( ret = mbedtls_asn1_get_tag( p, end_ext_data, &len, + MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + end_ext_octet = *p + len; + + if( end_ext_octet != end_ext_data ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + /* + * Detect supported extensions + */ + ret = mbedtls_oid_get_x509_ext_type( &extn_oid, &ext_type ); + + if( ret != 0 ) + { + /* No parser found, skip extension */ + *p = end_ext_octet; + +#if !defined(MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION) + if( is_critical ) + { + /* Data is marked as critical: fail */ + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + } +#endif + continue; + } + + /* Forbid repeated extensions */ + if( ( crt->ext_types & ext_type ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS ); + + crt->ext_types |= ext_type; + + switch( ext_type ) + { + case MBEDTLS_X509_EXT_BASIC_CONSTRAINTS: + /* Parse basic constraints */ + if( ( ret = x509_get_basic_constraints( p, end_ext_octet, + &crt->ca_istrue, &crt->max_pathlen ) ) != 0 ) + return( ret ); + break; + + case MBEDTLS_X509_EXT_KEY_USAGE: + /* Parse key usage */ + if( ( ret = x509_get_key_usage( p, end_ext_octet, + &crt->key_usage ) ) != 0 ) + return( ret ); + break; + + case MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE: + /* Parse extended key usage */ + if( ( ret = x509_get_ext_key_usage( p, end_ext_octet, + &crt->ext_key_usage ) ) != 0 ) + return( ret ); + break; + + case MBEDTLS_X509_EXT_SUBJECT_ALT_NAME: + /* Parse subject alt name */ + if( ( ret = x509_get_subject_alt_name( p, end_ext_octet, + &crt->subject_alt_names ) ) != 0 ) + return( ret ); + break; + + case MBEDTLS_X509_EXT_NS_CERT_TYPE: + /* Parse netscape certificate type */ + if( ( ret = x509_get_ns_cert_type( p, end_ext_octet, + &crt->ns_cert_type ) ) != 0 ) + return( ret ); + break; + + default: + return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ); + } + } + + if( *p != end ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * Parse and fill a single X.509 certificate in DER format + */ +static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, const unsigned char *buf, + size_t buflen ) +{ + int ret; + size_t len; + unsigned char *p, *end, *crt_end; + mbedtls_x509_buf sig_params1, sig_params2, sig_oid2; + + memset( &sig_params1, 0, sizeof( mbedtls_x509_buf ) ); + memset( &sig_params2, 0, sizeof( mbedtls_x509_buf ) ); + memset( &sig_oid2, 0, sizeof( mbedtls_x509_buf ) ); + + /* + * Check for valid input + */ + if( crt == NULL || buf == NULL ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + // Use the original buffer until we figure out actual length + p = (unsigned char*) buf; + len = buflen; + end = p + len; + + /* + * Certificate ::= SEQUENCE { + * tbsCertificate TBSCertificate, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT ); + } + + if( len > (size_t) ( end - p ) ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + crt_end = p + len; + + // Create and populate a new buffer for the raw field + crt->raw.len = crt_end - buf; + crt->raw.p = p = mbedtls_calloc( 1, crt->raw.len ); + if( p == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + memcpy( p, buf, crt->raw.len ); + + // Direct pointers to the new buffer + p += crt->raw.len - len; + end = crt_end = p + len; + + /* + * TBSCertificate ::= SEQUENCE { + */ + crt->tbs.p = p; + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); + } + + end = p + len; + crt->tbs.len = end - crt->tbs.p; + + /* + * Version ::= INTEGER { v1(0), v2(1), v3(2) } + * + * CertificateSerialNumber ::= INTEGER + * + * signature AlgorithmIdentifier + */ + if( ( ret = x509_get_version( &p, end, &crt->version ) ) != 0 || + ( ret = mbedtls_x509_get_serial( &p, end, &crt->serial ) ) != 0 || + ( ret = mbedtls_x509_get_alg( &p, end, &crt->sig_oid, + &sig_params1 ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + + if( crt->version < 0 || crt->version > 2 ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_UNKNOWN_VERSION ); + } + + crt->version++; + + if( ( ret = mbedtls_x509_get_sig_alg( &crt->sig_oid, &sig_params1, + &crt->sig_md, &crt->sig_pk, + &crt->sig_opts ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + + /* + * issuer Name + */ + crt->issuer_raw.p = p; + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); + } + + if( ( ret = mbedtls_x509_get_name( &p, p + len, &crt->issuer ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + + crt->issuer_raw.len = p - crt->issuer_raw.p; + + /* + * Validity ::= SEQUENCE { + * notBefore Time, + * notAfter Time } + * + */ + if( ( ret = x509_get_dates( &p, end, &crt->valid_from, + &crt->valid_to ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + + /* + * subject Name + */ + crt->subject_raw.p = p; + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); + } + + if( len && ( ret = mbedtls_x509_get_name( &p, p + len, &crt->subject ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + + crt->subject_raw.len = p - crt->subject_raw.p; + + /* + * SubjectPublicKeyInfo + */ + if( ( ret = mbedtls_pk_parse_subpubkey( &p, end, &crt->pk ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + + /* + * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, + * -- If present, version shall be v2 or v3 + * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, + * -- If present, version shall be v2 or v3 + * extensions [3] EXPLICIT Extensions OPTIONAL + * -- If present, version shall be v3 + */ + if( crt->version == 2 || crt->version == 3 ) + { + ret = x509_get_uid( &p, end, &crt->issuer_id, 1 ); + if( ret != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + } + + if( crt->version == 2 || crt->version == 3 ) + { + ret = x509_get_uid( &p, end, &crt->subject_id, 2 ); + if( ret != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + } + +#if !defined(MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3) + if( crt->version == 3 ) +#endif + { + ret = x509_get_crt_ext( &p, end, crt ); + if( ret != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + } + + if( p != end ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + end = crt_end; + + /* + * } + * -- end of TBSCertificate + * + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING + */ + if( ( ret = mbedtls_x509_get_alg( &p, end, &sig_oid2, &sig_params2 ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + + if( crt->sig_oid.len != sig_oid2.len || + memcmp( crt->sig_oid.p, sig_oid2.p, crt->sig_oid.len ) != 0 || + sig_params1.len != sig_params2.len || + ( sig_params1.len != 0 && + memcmp( sig_params1.p, sig_params2.p, sig_params1.len ) != 0 ) ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_SIG_MISMATCH ); + } + + if( ( ret = mbedtls_x509_get_sig( &p, end, &crt->sig ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + + if( p != end ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + return( 0 ); +} + +/* + * Parse one X.509 certificate in DER format from a buffer and add them to a + * chained list + */ +int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain, const unsigned char *buf, + size_t buflen ) +{ + int ret; + mbedtls_x509_crt *crt = chain, *prev = NULL; + + /* + * Check for valid input + */ + if( crt == NULL || buf == NULL ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + while( crt->version != 0 && crt->next != NULL ) + { + prev = crt; + crt = crt->next; + } + + /* + * Add new certificate on the end of the chain if needed. + */ + if( crt->version != 0 && crt->next == NULL ) + { + crt->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) ); + + if( crt->next == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + prev = crt; + mbedtls_x509_crt_init( crt->next ); + crt = crt->next; + } + + if( ( ret = x509_crt_parse_der_core( crt, buf, buflen ) ) != 0 ) + { + if( prev ) + prev->next = NULL; + + if( crt != chain ) + mbedtls_free( crt ); + + return( ret ); + } + + return( 0 ); +} + +/* + * Parse one or more PEM certificates from a buffer and add them to the chained + * list + */ +int mbedtls_x509_crt_parse( mbedtls_x509_crt *chain, const unsigned char *buf, size_t buflen ) +{ +#if defined(MBEDTLS_PEM_PARSE_C) + int success = 0, first_error = 0, total_failed = 0; + int buf_format = MBEDTLS_X509_FORMAT_DER; +#endif + + /* + * Check for valid input + */ + if( chain == NULL || buf == NULL ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + /* + * Determine buffer content. Buffer contains either one DER certificate or + * one or more PEM certificates. + */ +#if defined(MBEDTLS_PEM_PARSE_C) + if( buflen != 0 && buf[buflen - 1] == '\0' && + strstr( (const char *) buf, "-----BEGIN CERTIFICATE-----" ) != NULL ) + { + buf_format = MBEDTLS_X509_FORMAT_PEM; + } + + if( buf_format == MBEDTLS_X509_FORMAT_DER ) + return mbedtls_x509_crt_parse_der( chain, buf, buflen ); +#else + return mbedtls_x509_crt_parse_der( chain, buf, buflen ); +#endif + +#if defined(MBEDTLS_PEM_PARSE_C) + if( buf_format == MBEDTLS_X509_FORMAT_PEM ) + { + int ret; + mbedtls_pem_context pem; + + /* 1 rather than 0 since the terminating NULL byte is counted in */ + while( buflen > 1 ) + { + size_t use_len; + mbedtls_pem_init( &pem ); + + /* If we get there, we know the string is null-terminated */ + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN CERTIFICATE-----", + "-----END CERTIFICATE-----", + buf, NULL, 0, &use_len ); + + if( ret == 0 ) + { + /* + * Was PEM encoded + */ + buflen -= use_len; + buf += use_len; + } + else if( ret == MBEDTLS_ERR_PEM_BAD_INPUT_DATA ) + { + return( ret ); + } + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + { + mbedtls_pem_free( &pem ); + + /* + * PEM header and footer were found + */ + buflen -= use_len; + buf += use_len; + + if( first_error == 0 ) + first_error = ret; + + total_failed++; + continue; + } + else + break; + + ret = mbedtls_x509_crt_parse_der( chain, pem.buf, pem.buflen ); + + mbedtls_pem_free( &pem ); + + if( ret != 0 ) + { + /* + * Quit parsing on a memory error + */ + if( ret == MBEDTLS_ERR_X509_ALLOC_FAILED ) + return( ret ); + + if( first_error == 0 ) + first_error = ret; + + total_failed++; + continue; + } + + success = 1; + } + } + + if( success ) + return( total_failed ); + else if( first_error ) + return( first_error ); + else + return( MBEDTLS_ERR_X509_CERT_UNKNOWN_FORMAT ); +#endif /* MBEDTLS_PEM_PARSE_C */ +} + +#if defined(MBEDTLS_FS_IO) +/* + * Load one or more certificates and add them to the chained list + */ +int mbedtls_x509_crt_parse_file( mbedtls_x509_crt *chain, const char *path ) +{ + int ret; + size_t n; + unsigned char *buf; + + if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + ret = mbedtls_x509_crt_parse( chain, buf, n ); + + mbedtls_platform_zeroize( buf, n ); + mbedtls_free( buf ); + + return( ret ); +} + +int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path ) +{ + int ret = 0; +#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) + int w_ret; + WCHAR szDir[MAX_PATH]; + char filename[MAX_PATH]; + char *p; + size_t len = strlen( path ); + + WIN32_FIND_DATAW file_data; + HANDLE hFind; + + if( len > MAX_PATH - 3 ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + memset( szDir, 0, sizeof(szDir) ); + memset( filename, 0, MAX_PATH ); + memcpy( filename, path, len ); + filename[len++] = '\\'; + p = filename + len; + filename[len++] = '*'; + + w_ret = MultiByteToWideChar( CP_ACP, 0, filename, (int)len, szDir, + MAX_PATH - 3 ); + if( w_ret == 0 ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + hFind = FindFirstFileW( szDir, &file_data ); + if( hFind == INVALID_HANDLE_VALUE ) + return( MBEDTLS_ERR_X509_FILE_IO_ERROR ); + + len = MAX_PATH - len; + do + { + memset( p, 0, len ); + + if( file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) + continue; + + w_ret = WideCharToMultiByte( CP_ACP, 0, file_data.cFileName, + lstrlenW( file_data.cFileName ), + p, (int) len - 1, + NULL, NULL ); + if( w_ret == 0 ) + { + ret = MBEDTLS_ERR_X509_FILE_IO_ERROR; + goto cleanup; + } + + w_ret = mbedtls_x509_crt_parse_file( chain, filename ); + if( w_ret < 0 ) + ret++; + else + ret += w_ret; + } + while( FindNextFileW( hFind, &file_data ) != 0 ); + + if( GetLastError() != ERROR_NO_MORE_FILES ) + ret = MBEDTLS_ERR_X509_FILE_IO_ERROR; + +cleanup: + FindClose( hFind ); +#else /* _WIN32 */ + int t_ret; + int snp_ret; + struct stat sb; + struct dirent *entry; + char entry_name[MBEDTLS_X509_MAX_FILE_PATH_LEN]; + DIR *dir = opendir( path ); + + if( dir == NULL ) + return( MBEDTLS_ERR_X509_FILE_IO_ERROR ); + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &mbedtls_threading_readdir_mutex ) ) != 0 ) + { + closedir( dir ); + return( ret ); + } +#endif /* MBEDTLS_THREADING_C */ + + while( ( entry = readdir( dir ) ) != NULL ) + { + snp_ret = mbedtls_snprintf( entry_name, sizeof entry_name, + "%s/%s", path, entry->d_name ); + + if( snp_ret < 0 || (size_t)snp_ret >= sizeof entry_name ) + { + ret = MBEDTLS_ERR_X509_BUFFER_TOO_SMALL; + goto cleanup; + } + else if( stat( entry_name, &sb ) == -1 ) + { + ret = MBEDTLS_ERR_X509_FILE_IO_ERROR; + goto cleanup; + } + + if( !S_ISREG( sb.st_mode ) ) + continue; + + // Ignore parse errors + // + t_ret = mbedtls_x509_crt_parse_file( chain, entry_name ); + if( t_ret < 0 ) + ret++; + else + ret += t_ret; + } + +cleanup: + closedir( dir ); + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &mbedtls_threading_readdir_mutex ) != 0 ) + ret = MBEDTLS_ERR_THREADING_MUTEX_ERROR; +#endif /* MBEDTLS_THREADING_C */ + +#endif /* _WIN32 */ + + return( ret ); +} +#endif /* MBEDTLS_FS_IO */ + +static int x509_info_subject_alt_name( char **buf, size_t *size, + const mbedtls_x509_sequence *subject_alt_name ) +{ + size_t i; + size_t n = *size; + char *p = *buf; + const mbedtls_x509_sequence *cur = subject_alt_name; + const char *sep = ""; + size_t sep_len = 0; + + while( cur != NULL ) + { + if( cur->buf.len + sep_len >= n ) + { + *p = '\0'; + return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); + } + + n -= cur->buf.len + sep_len; + for( i = 0; i < sep_len; i++ ) + *p++ = sep[i]; + for( i = 0; i < cur->buf.len; i++ ) + *p++ = cur->buf.p[i]; + + sep = ", "; + sep_len = 2; + + cur = cur->next; + } + + *p = '\0'; + + *size = n; + *buf = p; + + return( 0 ); +} + +#define PRINT_ITEM(i) \ + { \ + ret = mbedtls_snprintf( p, n, "%s" i, sep ); \ + MBEDTLS_X509_SAFE_SNPRINTF; \ + sep = ", "; \ + } + +#define CERT_TYPE(type,name) \ + if( ns_cert_type & type ) \ + PRINT_ITEM( name ); + +static int x509_info_cert_type( char **buf, size_t *size, + unsigned char ns_cert_type ) +{ + int ret; + size_t n = *size; + char *p = *buf; + const char *sep = ""; + + CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT, "SSL Client" ); + CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER, "SSL Server" ); + CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_EMAIL, "Email" ); + CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING, "Object Signing" ); + CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_RESERVED, "Reserved" ); + CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_SSL_CA, "SSL CA" ); + CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_EMAIL_CA, "Email CA" ); + CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING_CA, "Object Signing CA" ); + + *size = n; + *buf = p; + + return( 0 ); +} + +#define KEY_USAGE(code,name) \ + if( key_usage & code ) \ + PRINT_ITEM( name ); + +static int x509_info_key_usage( char **buf, size_t *size, + unsigned int key_usage ) +{ + int ret; + size_t n = *size; + char *p = *buf; + const char *sep = ""; + + KEY_USAGE( MBEDTLS_X509_KU_DIGITAL_SIGNATURE, "Digital Signature" ); + KEY_USAGE( MBEDTLS_X509_KU_NON_REPUDIATION, "Non Repudiation" ); + KEY_USAGE( MBEDTLS_X509_KU_KEY_ENCIPHERMENT, "Key Encipherment" ); + KEY_USAGE( MBEDTLS_X509_KU_DATA_ENCIPHERMENT, "Data Encipherment" ); + KEY_USAGE( MBEDTLS_X509_KU_KEY_AGREEMENT, "Key Agreement" ); + KEY_USAGE( MBEDTLS_X509_KU_KEY_CERT_SIGN, "Key Cert Sign" ); + KEY_USAGE( MBEDTLS_X509_KU_CRL_SIGN, "CRL Sign" ); + KEY_USAGE( MBEDTLS_X509_KU_ENCIPHER_ONLY, "Encipher Only" ); + KEY_USAGE( MBEDTLS_X509_KU_DECIPHER_ONLY, "Decipher Only" ); + + *size = n; + *buf = p; + + return( 0 ); +} + +static int x509_info_ext_key_usage( char **buf, size_t *size, + const mbedtls_x509_sequence *extended_key_usage ) +{ + int ret; + const char *desc; + size_t n = *size; + char *p = *buf; + const mbedtls_x509_sequence *cur = extended_key_usage; + const char *sep = ""; + + while( cur != NULL ) + { + if( mbedtls_oid_get_extended_key_usage( &cur->buf, &desc ) != 0 ) + desc = "???"; + + ret = mbedtls_snprintf( p, n, "%s%s", sep, desc ); + MBEDTLS_X509_SAFE_SNPRINTF; + + sep = ", "; + + cur = cur->next; + } + + *size = n; + *buf = p; + + return( 0 ); +} + +/* + * Return an informational string about the certificate. + */ +#define BEFORE_COLON 18 +#define BC "18" +int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, + const mbedtls_x509_crt *crt ) +{ + int ret; + size_t n; + char *p; + char key_size_str[BEFORE_COLON]; + + p = buf; + n = size; + + if( NULL == crt ) + { + ret = mbedtls_snprintf( p, n, "\nCertificate is uninitialised!\n" ); + MBEDTLS_X509_SAFE_SNPRINTF; + + return( (int) ( size - n ) ); + } + + ret = mbedtls_snprintf( p, n, "%scert. version : %d\n", + prefix, crt->version ); + MBEDTLS_X509_SAFE_SNPRINTF; + ret = mbedtls_snprintf( p, n, "%sserial number : ", + prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_x509_serial_gets( p, n, &crt->serial ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%sissuer name : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + ret = mbedtls_x509_dn_gets( p, n, &crt->issuer ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%ssubject name : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + ret = mbedtls_x509_dn_gets( p, n, &crt->subject ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%sissued on : " \ + "%04d-%02d-%02d %02d:%02d:%02d", prefix, + crt->valid_from.year, crt->valid_from.mon, + crt->valid_from.day, crt->valid_from.hour, + crt->valid_from.min, crt->valid_from.sec ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%sexpires on : " \ + "%04d-%02d-%02d %02d:%02d:%02d", prefix, + crt->valid_to.year, crt->valid_to.mon, + crt->valid_to.day, crt->valid_to.hour, + crt->valid_to.min, crt->valid_to.sec ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%ssigned using : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_x509_sig_alg_gets( p, n, &crt->sig_oid, crt->sig_pk, + crt->sig_md, crt->sig_opts ); + MBEDTLS_X509_SAFE_SNPRINTF; + + /* Key size */ + if( ( ret = mbedtls_x509_key_size_helper( key_size_str, BEFORE_COLON, + mbedtls_pk_get_name( &crt->pk ) ) ) != 0 ) + { + return( ret ); + } + + ret = mbedtls_snprintf( p, n, "\n%s%-" BC "s: %d bits", prefix, key_size_str, + (int) mbedtls_pk_get_bitlen( &crt->pk ) ); + MBEDTLS_X509_SAFE_SNPRINTF; + + /* + * Optional extensions + */ + + if( crt->ext_types & MBEDTLS_X509_EXT_BASIC_CONSTRAINTS ) + { + ret = mbedtls_snprintf( p, n, "\n%sbasic constraints : CA=%s", prefix, + crt->ca_istrue ? "true" : "false" ); + MBEDTLS_X509_SAFE_SNPRINTF; + + if( crt->max_pathlen > 0 ) + { + ret = mbedtls_snprintf( p, n, ", max_pathlen=%d", crt->max_pathlen - 1 ); + MBEDTLS_X509_SAFE_SNPRINTF; + } + } + + if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) + { + ret = mbedtls_snprintf( p, n, "\n%ssubject alt name : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + if( ( ret = x509_info_subject_alt_name( &p, &n, + &crt->subject_alt_names ) ) != 0 ) + return( ret ); + } + + if( crt->ext_types & MBEDTLS_X509_EXT_NS_CERT_TYPE ) + { + ret = mbedtls_snprintf( p, n, "\n%scert. type : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + if( ( ret = x509_info_cert_type( &p, &n, crt->ns_cert_type ) ) != 0 ) + return( ret ); + } + + if( crt->ext_types & MBEDTLS_X509_EXT_KEY_USAGE ) + { + ret = mbedtls_snprintf( p, n, "\n%skey usage : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + if( ( ret = x509_info_key_usage( &p, &n, crt->key_usage ) ) != 0 ) + return( ret ); + } + + if( crt->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE ) + { + ret = mbedtls_snprintf( p, n, "\n%sext key usage : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + if( ( ret = x509_info_ext_key_usage( &p, &n, + &crt->ext_key_usage ) ) != 0 ) + return( ret ); + } + + ret = mbedtls_snprintf( p, n, "\n" ); + MBEDTLS_X509_SAFE_SNPRINTF; + + return( (int) ( size - n ) ); +} + +struct x509_crt_verify_string { + int code; + const char *string; +}; + +static const struct x509_crt_verify_string x509_crt_verify_strings[] = { + { MBEDTLS_X509_BADCERT_EXPIRED, "The certificate validity has expired" }, + { MBEDTLS_X509_BADCERT_REVOKED, "The certificate has been revoked (is on a CRL)" }, + { MBEDTLS_X509_BADCERT_CN_MISMATCH, "The certificate Common Name (CN) does not match with the expected CN" }, + { MBEDTLS_X509_BADCERT_NOT_TRUSTED, "The certificate is not correctly signed by the trusted CA" }, + { MBEDTLS_X509_BADCRL_NOT_TRUSTED, "The CRL is not correctly signed by the trusted CA" }, + { MBEDTLS_X509_BADCRL_EXPIRED, "The CRL is expired" }, + { MBEDTLS_X509_BADCERT_MISSING, "Certificate was missing" }, + { MBEDTLS_X509_BADCERT_SKIP_VERIFY, "Certificate verification was skipped" }, + { MBEDTLS_X509_BADCERT_OTHER, "Other reason (can be used by verify callback)" }, + { MBEDTLS_X509_BADCERT_FUTURE, "The certificate validity starts in the future" }, + { MBEDTLS_X509_BADCRL_FUTURE, "The CRL is from the future" }, + { MBEDTLS_X509_BADCERT_KEY_USAGE, "Usage does not match the keyUsage extension" }, + { MBEDTLS_X509_BADCERT_EXT_KEY_USAGE, "Usage does not match the extendedKeyUsage extension" }, + { MBEDTLS_X509_BADCERT_NS_CERT_TYPE, "Usage does not match the nsCertType extension" }, + { MBEDTLS_X509_BADCERT_BAD_MD, "The certificate is signed with an unacceptable hash." }, + { MBEDTLS_X509_BADCERT_BAD_PK, "The certificate is signed with an unacceptable PK alg (eg RSA vs ECDSA)." }, + { MBEDTLS_X509_BADCERT_BAD_KEY, "The certificate is signed with an unacceptable key (eg bad curve, RSA too short)." }, + { MBEDTLS_X509_BADCRL_BAD_MD, "The CRL is signed with an unacceptable hash." }, + { MBEDTLS_X509_BADCRL_BAD_PK, "The CRL is signed with an unacceptable PK alg (eg RSA vs ECDSA)." }, + { MBEDTLS_X509_BADCRL_BAD_KEY, "The CRL is signed with an unacceptable key (eg bad curve, RSA too short)." }, + { 0, NULL } +}; + +int mbedtls_x509_crt_verify_info( char *buf, size_t size, const char *prefix, + uint32_t flags ) +{ + int ret; + const struct x509_crt_verify_string *cur; + char *p = buf; + size_t n = size; + + for( cur = x509_crt_verify_strings; cur->string != NULL ; cur++ ) + { + if( ( flags & cur->code ) == 0 ) + continue; + + ret = mbedtls_snprintf( p, n, "%s%s\n", prefix, cur->string ); + MBEDTLS_X509_SAFE_SNPRINTF; + flags ^= cur->code; + } + + if( flags != 0 ) + { + ret = mbedtls_snprintf( p, n, "%sUnknown reason " + "(this should not happen)\n", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + } + + return( (int) ( size - n ) ); +} + +#if defined(MBEDTLS_X509_CHECK_KEY_USAGE) +int mbedtls_x509_crt_check_key_usage( const mbedtls_x509_crt *crt, + unsigned int usage ) +{ + unsigned int usage_must, usage_may; + unsigned int may_mask = MBEDTLS_X509_KU_ENCIPHER_ONLY + | MBEDTLS_X509_KU_DECIPHER_ONLY; + + if( ( crt->ext_types & MBEDTLS_X509_EXT_KEY_USAGE ) == 0 ) + return( 0 ); + + usage_must = usage & ~may_mask; + + if( ( ( crt->key_usage & ~may_mask ) & usage_must ) != usage_must ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + usage_may = usage & may_mask; + + if( ( ( crt->key_usage & may_mask ) | usage_may ) != usage_may ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + return( 0 ); +} +#endif + +#if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) +int mbedtls_x509_crt_check_extended_key_usage( const mbedtls_x509_crt *crt, + const char *usage_oid, + size_t usage_len ) +{ + const mbedtls_x509_sequence *cur; + + /* Extension is not mandatory, absent means no restriction */ + if( ( crt->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE ) == 0 ) + return( 0 ); + + /* + * Look for the requested usage (or wildcard ANY) in our list + */ + for( cur = &crt->ext_key_usage; cur != NULL; cur = cur->next ) + { + const mbedtls_x509_buf *cur_oid = &cur->buf; + + if( cur_oid->len == usage_len && + memcmp( cur_oid->p, usage_oid, usage_len ) == 0 ) + { + return( 0 ); + } + + if( MBEDTLS_OID_CMP( MBEDTLS_OID_ANY_EXTENDED_KEY_USAGE, cur_oid ) == 0 ) + return( 0 ); + } + + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); +} +#endif /* MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE */ + +#if defined(MBEDTLS_X509_CRL_PARSE_C) +/* + * Return 1 if the certificate is revoked, or 0 otherwise. + */ +int mbedtls_x509_crt_is_revoked( const mbedtls_x509_crt *crt, const mbedtls_x509_crl *crl ) +{ + const mbedtls_x509_crl_entry *cur = &crl->entry; + + while( cur != NULL && cur->serial.len != 0 ) + { + if( crt->serial.len == cur->serial.len && + memcmp( crt->serial.p, cur->serial.p, crt->serial.len ) == 0 ) + { + if( mbedtls_x509_time_is_past( &cur->revocation_date ) ) + return( 1 ); + } + + cur = cur->next; + } + + return( 0 ); +} + +/* + * Check that the given certificate is not revoked according to the CRL. + * Skip validation if no CRL for the given CA is present. + */ +static int x509_crt_verifycrl( mbedtls_x509_crt *crt, mbedtls_x509_crt *ca, + mbedtls_x509_crl *crl_list, + const mbedtls_x509_crt_profile *profile ) +{ + int flags = 0; + unsigned char hash[MBEDTLS_MD_MAX_SIZE]; + const mbedtls_md_info_t *md_info; + + if( ca == NULL ) + return( flags ); + + while( crl_list != NULL ) + { + if( crl_list->version == 0 || + crl_list->issuer_raw.len != ca->subject_raw.len || + memcmp( crl_list->issuer_raw.p, ca->subject_raw.p, + crl_list->issuer_raw.len ) != 0 ) + { + crl_list = crl_list->next; + continue; + } + + /* + * Check if the CA is configured to sign CRLs + */ +#if defined(MBEDTLS_X509_CHECK_KEY_USAGE) + if( mbedtls_x509_crt_check_key_usage( ca, MBEDTLS_X509_KU_CRL_SIGN ) != 0 ) + { + flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED; + break; + } +#endif + + /* + * Check if CRL is correctly signed by the trusted CA + */ + if( x509_profile_check_md_alg( profile, crl_list->sig_md ) != 0 ) + flags |= MBEDTLS_X509_BADCRL_BAD_MD; + + if( x509_profile_check_pk_alg( profile, crl_list->sig_pk ) != 0 ) + flags |= MBEDTLS_X509_BADCRL_BAD_PK; + + md_info = mbedtls_md_info_from_type( crl_list->sig_md ); + if( mbedtls_md( md_info, crl_list->tbs.p, crl_list->tbs.len, hash ) != 0 ) + { + /* Note: this can't happen except after an internal error */ + flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED; + break; + } + + if( x509_profile_check_key( profile, &ca->pk ) != 0 ) + flags |= MBEDTLS_X509_BADCERT_BAD_KEY; + + if( mbedtls_pk_verify_ext( crl_list->sig_pk, crl_list->sig_opts, &ca->pk, + crl_list->sig_md, hash, mbedtls_md_get_size( md_info ), + crl_list->sig.p, crl_list->sig.len ) != 0 ) + { + flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED; + break; + } + + /* + * Check for validity of CRL (Do not drop out) + */ + if( mbedtls_x509_time_is_past( &crl_list->next_update ) ) + flags |= MBEDTLS_X509_BADCRL_EXPIRED; + + if( mbedtls_x509_time_is_future( &crl_list->this_update ) ) + flags |= MBEDTLS_X509_BADCRL_FUTURE; + + /* + * Check if certificate is revoked + */ + if( mbedtls_x509_crt_is_revoked( crt, crl_list ) ) + { + flags |= MBEDTLS_X509_BADCERT_REVOKED; + break; + } + + crl_list = crl_list->next; + } + + return( flags ); +} +#endif /* MBEDTLS_X509_CRL_PARSE_C */ + +/* + * Like memcmp, but case-insensitive and always returns -1 if different + */ +static int x509_memcasecmp( const void *s1, const void *s2, size_t len ) +{ + size_t i; + unsigned char diff; + const unsigned char *n1 = s1, *n2 = s2; + + for( i = 0; i < len; i++ ) + { + diff = n1[i] ^ n2[i]; + + if( diff == 0 ) + continue; + + if( diff == 32 && + ( ( n1[i] >= 'a' && n1[i] <= 'z' ) || + ( n1[i] >= 'A' && n1[i] <= 'Z' ) ) ) + { + continue; + } + + return( -1 ); + } + + return( 0 ); +} + +/* + * Return 0 if name matches wildcard, -1 otherwise + */ +static int x509_check_wildcard( const char *cn, const mbedtls_x509_buf *name ) +{ + size_t i; + size_t cn_idx = 0, cn_len = strlen( cn ); + + /* We can't have a match if there is no wildcard to match */ + if( name->len < 3 || name->p[0] != '*' || name->p[1] != '.' ) + return( -1 ); + + for( i = 0; i < cn_len; ++i ) + { + if( cn[i] == '.' ) + { + cn_idx = i; + break; + } + } + + if( cn_idx == 0 ) + return( -1 ); + + if( cn_len - cn_idx == name->len - 1 && + x509_memcasecmp( name->p + 1, cn + cn_idx, name->len - 1 ) == 0 ) + { + return( 0 ); + } + + return( -1 ); +} + +/* + * Compare two X.509 strings, case-insensitive, and allowing for some encoding + * variations (but not all). + * + * Return 0 if equal, -1 otherwise. + */ +static int x509_string_cmp( const mbedtls_x509_buf *a, const mbedtls_x509_buf *b ) +{ + if( a->tag == b->tag && + a->len == b->len && + memcmp( a->p, b->p, b->len ) == 0 ) + { + return( 0 ); + } + + if( ( a->tag == MBEDTLS_ASN1_UTF8_STRING || a->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) && + ( b->tag == MBEDTLS_ASN1_UTF8_STRING || b->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) && + a->len == b->len && + x509_memcasecmp( a->p, b->p, b->len ) == 0 ) + { + return( 0 ); + } + + return( -1 ); +} + +/* + * Compare two X.509 Names (aka rdnSequence). + * + * See RFC 5280 section 7.1, though we don't implement the whole algorithm: + * we sometimes return unequal when the full algorithm would return equal, + * but never the other way. (In particular, we don't do Unicode normalisation + * or space folding.) + * + * Return 0 if equal, -1 otherwise. + */ +static int x509_name_cmp( const mbedtls_x509_name *a, const mbedtls_x509_name *b ) +{ + /* Avoid recursion, it might not be optimised by the compiler */ + while( a != NULL || b != NULL ) + { + if( a == NULL || b == NULL ) + return( -1 ); + + /* type */ + if( a->oid.tag != b->oid.tag || + a->oid.len != b->oid.len || + memcmp( a->oid.p, b->oid.p, b->oid.len ) != 0 ) + { + return( -1 ); + } + + /* value */ + if( x509_string_cmp( &a->val, &b->val ) != 0 ) + return( -1 ); + + /* structure of the list of sets */ + if( a->next_merged != b->next_merged ) + return( -1 ); + + a = a->next; + b = b->next; + } + + /* a == NULL == b */ + return( 0 ); +} + +/* + * Check the signature of a certificate by its parent + */ +static int x509_crt_check_signature( const mbedtls_x509_crt *child, + mbedtls_x509_crt *parent ) +{ + const mbedtls_md_info_t *md_info; + unsigned char hash[MBEDTLS_MD_MAX_SIZE]; + + md_info = mbedtls_md_info_from_type( child->sig_md ); + if( mbedtls_md( md_info, child->tbs.p, child->tbs.len, hash ) != 0 ) + { + /* Note: this can't happen except after an internal error */ + return( -1 ); + } + + if( mbedtls_pk_verify_ext( child->sig_pk, child->sig_opts, &parent->pk, + child->sig_md, hash, mbedtls_md_get_size( md_info ), + child->sig.p, child->sig.len ) != 0 ) + { + return( -1 ); + } + + return( 0 ); +} + +/* + * Check if 'parent' is a suitable parent (signing CA) for 'child'. + * Return 0 if yes, -1 if not. + * + * top means parent is a locally-trusted certificate + */ +static int x509_crt_check_parent( const mbedtls_x509_crt *child, + const mbedtls_x509_crt *parent, + int top ) +{ + int need_ca_bit; + + /* Parent must be the issuer */ + if( x509_name_cmp( &child->issuer, &parent->subject ) != 0 ) + return( -1 ); + + /* Parent must have the basicConstraints CA bit set as a general rule */ + need_ca_bit = 1; + + /* Exception: v1/v2 certificates that are locally trusted. */ + if( top && parent->version < 3 ) + need_ca_bit = 0; + + if( need_ca_bit && ! parent->ca_istrue ) + return( -1 ); + +#if defined(MBEDTLS_X509_CHECK_KEY_USAGE) + if( need_ca_bit && + mbedtls_x509_crt_check_key_usage( parent, MBEDTLS_X509_KU_KEY_CERT_SIGN ) != 0 ) + { + return( -1 ); + } +#endif + + return( 0 ); +} + +/* + * Find a suitable parent for child in candidates, or return NULL. + * + * Here suitable is defined as: + * 1. subject name matches child's issuer + * 2. if necessary, the CA bit is set and key usage allows signing certs + * 3. for trusted roots, the signature is correct + * 4. pathlen constraints are satisfied + * + * If there's a suitable candidate which is also time-valid, return the first + * such. Otherwise, return the first suitable candidate (or NULL if there is + * none). + * + * The rationale for this rule is that someone could have a list of trusted + * roots with two versions on the same root with different validity periods. + * (At least one user reported having such a list and wanted it to just work.) + * The reason we don't just require time-validity is that generally there is + * only one version, and if it's expired we want the flags to state that + * rather than NOT_TRUSTED, as would be the case if we required it here. + * + * The rationale for rule 3 (signature for trusted roots) is that users might + * have two versions of the same CA with different keys in their list, and the + * way we select the correct one is by checking the signature (as we don't + * rely on key identifier extensions). (This is one way users might choose to + * handle key rollover, another relies on self-issued certs, see [SIRO].) + * + * Arguments: + * - [in] child: certificate for which we're looking for a parent + * - [in] candidates: chained list of potential parents + * - [in] top: 1 if candidates consists of trusted roots, ie we're at the top + * of the chain, 0 otherwise + * - [in] path_cnt: number of intermediates seen so far + * - [in] self_cnt: number of self-signed intermediates seen so far + * (will never be greater than path_cnt) + * + * Return value: + * - the first suitable parent found (see above regarding time-validity) + * - NULL if no suitable parent was found + */ +static mbedtls_x509_crt *x509_crt_find_parent_in( mbedtls_x509_crt *child, + mbedtls_x509_crt *candidates, + int top, + size_t path_cnt, + size_t self_cnt ) +{ + mbedtls_x509_crt *parent, *badtime_parent = NULL; + + for( parent = candidates; parent != NULL; parent = parent->next ) + { + /* basic parenting skills (name, CA bit, key usage) */ + if( x509_crt_check_parent( child, parent, top ) != 0 ) + continue; + + /* +1 because stored max_pathlen is 1 higher that the actual value */ + if( parent->max_pathlen > 0 && + (size_t) parent->max_pathlen < 1 + path_cnt - self_cnt ) + { + continue; + } + + /* Signature */ + if( top && x509_crt_check_signature( child, parent ) != 0 ) + { + continue; + } + + /* optional time check */ + if( mbedtls_x509_time_is_past( &parent->valid_to ) || + mbedtls_x509_time_is_future( &parent->valid_from ) ) + { + if( badtime_parent == NULL ) + badtime_parent = parent; + + continue; + } + + break; + } + + if( parent == NULL ) + parent = badtime_parent; + + return( parent ); +} + +/* + * Find a parent in trusted CAs or the provided chain, or return NULL. + * + * Searches in trusted CAs first, and return the first suitable parent found + * (see find_parent_in() for definition of suitable). + * + * Arguments: + * - [in] child: certificate for which we're looking for a parent, followed + * by a chain of possible intermediates + * - [in] trust_ca: locally trusted CAs + * - [out] 1 if parent was found in trust_ca, 0 if found in provided chain + * - [in] path_cnt: number of intermediates seen so far + * - [in] self_cnt: number of self-signed intermediates seen so far + * (will always be no greater than path_cnt) + * + * Return value: + * - the first suitable parent found (see find_parent_in() for "suitable") + * - NULL if no suitable parent was found + */ +static mbedtls_x509_crt *x509_crt_find_parent( mbedtls_x509_crt *child, + mbedtls_x509_crt *trust_ca, + int *parent_is_trusted, + size_t path_cnt, + size_t self_cnt ) +{ + mbedtls_x509_crt *parent; + + /* Look for a parent in trusted CAs */ + *parent_is_trusted = 1; + parent = x509_crt_find_parent_in( child, trust_ca, 1, path_cnt, self_cnt ); + + if( parent != NULL ) + return( parent ); + + /* Look for a parent upwards the chain */ + *parent_is_trusted = 0; + return( x509_crt_find_parent_in( child, child->next, 0, path_cnt, self_cnt ) ); +} + +/* + * Check if an end-entity certificate is locally trusted + * + * Currently we require such certificates to be self-signed (actually only + * check for self-issued as self-signatures are not checked) + */ +static int x509_crt_check_ee_locally_trusted( + mbedtls_x509_crt *crt, + mbedtls_x509_crt *trust_ca ) +{ + mbedtls_x509_crt *cur; + + /* must be self-issued */ + if( x509_name_cmp( &crt->issuer, &crt->subject ) != 0 ) + return( -1 ); + + /* look for an exact match with trusted cert */ + for( cur = trust_ca; cur != NULL; cur = cur->next ) + { + if( crt->raw.len == cur->raw.len && + memcmp( crt->raw.p, cur->raw.p, crt->raw.len ) == 0 ) + { + return( 0 ); + } + } + + /* too bad */ + return( -1 ); +} + +/* + * Build and verify a certificate chain + * + * Given a peer-provided list of certificates EE, C1, ..., Cn and + * a list of trusted certs R1, ... Rp, try to build and verify a chain + * EE, Ci1, ... Ciq [, Rj] + * such that every cert in the chain is a child of the next one, + * jumping to a trusted root as early as possible. + * + * Verify that chain and return it with flags for all issues found. + * + * Special cases: + * - EE == Rj -> return a one-element list containing it + * - EE, Ci1, ..., Ciq cannot be continued with a trusted root + * -> return that chain with NOT_TRUSTED set on Ciq + * + * Arguments: + * - [in] crt: the cert list EE, C1, ..., Cn + * - [in] trust_ca: the trusted list R1, ..., Rp + * - [in] ca_crl, profile: as in verify_with_profile() + * - [out] ver_chain, chain_len: the built and verified chain + * + * Return value: + * - non-zero if the chain could not be fully built and examined + * - 0 is the chain was successfully built and examined, + * even if it was found to be invalid + */ +static int x509_crt_verify_chain( + mbedtls_x509_crt *crt, + mbedtls_x509_crt *trust_ca, + mbedtls_x509_crl *ca_crl, + const mbedtls_x509_crt_profile *profile, + x509_crt_verify_chain_item ver_chain[X509_MAX_VERIFY_CHAIN_SIZE], + size_t *chain_len ) +{ + uint32_t *flags; + mbedtls_x509_crt *child; + mbedtls_x509_crt *parent; + int parent_is_trusted = 0; + int child_is_trusted = 0; + size_t self_cnt = 0; + + child = crt; + *chain_len = 0; + + while( 1 ) { + /* Add certificate to the verification chain */ + ver_chain[*chain_len].crt = child; + flags = &ver_chain[*chain_len].flags; + ++*chain_len; + + /* Check time-validity (all certificates) */ + if( mbedtls_x509_time_is_past( &child->valid_to ) ) + *flags |= MBEDTLS_X509_BADCERT_EXPIRED; + + if( mbedtls_x509_time_is_future( &child->valid_from ) ) + *flags |= MBEDTLS_X509_BADCERT_FUTURE; + + /* Stop here for trusted roots (but not for trusted EE certs) */ + if( child_is_trusted ) + return( 0 ); + + /* Check signature algorithm: MD & PK algs */ + if( x509_profile_check_md_alg( profile, child->sig_md ) != 0 ) + *flags |= MBEDTLS_X509_BADCERT_BAD_MD; + + if( x509_profile_check_pk_alg( profile, child->sig_pk ) != 0 ) + *flags |= MBEDTLS_X509_BADCERT_BAD_PK; + + /* Special case: EE certs that are locally trusted */ + if( *chain_len == 1 && + x509_crt_check_ee_locally_trusted( child, trust_ca ) == 0 ) + { + return( 0 ); + } + + /* Look for a parent in trusted CAs or up the chain */ + parent = x509_crt_find_parent( child, trust_ca, &parent_is_trusted, + *chain_len - 1, self_cnt ); + + /* No parent? We're done here */ + if( parent == NULL ) + { + *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; + return( 0 ); + } + + /* Count intermediate self-issued (not necessarily self-signed) certs. + * These can occur with some strategies for key rollover, see [SIRO], + * and should be excluded from max_pathlen checks. */ + if( *chain_len != 1 && + x509_name_cmp( &child->issuer, &child->subject ) == 0 ) + { + self_cnt++; + } + + /* path_cnt is 0 for the first intermediate CA, + * and if parent is trusted it's not an intermediate CA */ + if( ! parent_is_trusted && + *chain_len > MBEDTLS_X509_MAX_INTERMEDIATE_CA ) + { + /* return immediately to avoid overflow the chain array */ + return( MBEDTLS_ERR_X509_FATAL_ERROR ); + } + + /* if parent is trusted, the signature was checked by find_parent() */ + if( ! parent_is_trusted && x509_crt_check_signature( child, parent ) != 0 ) + *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; + + /* check size of signing key */ + if( x509_profile_check_key( profile, &parent->pk ) != 0 ) + *flags |= MBEDTLS_X509_BADCERT_BAD_KEY; + +#if defined(MBEDTLS_X509_CRL_PARSE_C) + /* Check trusted CA's CRL for the given crt */ + *flags |= x509_crt_verifycrl( child, parent, ca_crl, profile ); +#else + (void) ca_crl; +#endif + + /* prepare for next iteration */ + child = parent; + parent = NULL; + child_is_trusted = parent_is_trusted; + } +} + +/* + * Check for CN match + */ +static int x509_crt_check_cn( const mbedtls_x509_buf *name, + const char *cn, size_t cn_len ) +{ + /* try exact match */ + if( name->len == cn_len && + x509_memcasecmp( cn, name->p, cn_len ) == 0 ) + { + return( 0 ); + } + + /* try wildcard match */ + if( x509_check_wildcard( cn, name ) == 0 ) + { + return( 0 ); + } + + return( -1 ); +} + +/* + * Verify the requested CN - only call this if cn is not NULL! + */ +static void x509_crt_verify_name( const mbedtls_x509_crt *crt, + const char *cn, + uint32_t *flags ) +{ + const mbedtls_x509_name *name; + const mbedtls_x509_sequence *cur; + size_t cn_len = strlen( cn ); + + if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) + { + for( cur = &crt->subject_alt_names; cur != NULL; cur = cur->next ) + { + if( x509_crt_check_cn( &cur->buf, cn, cn_len ) == 0 ) + break; + } + + if( cur == NULL ) + *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; + } + else + { + for( name = &crt->subject; name != NULL; name = name->next ) + { + if( MBEDTLS_OID_CMP( MBEDTLS_OID_AT_CN, &name->oid ) == 0 && + x509_crt_check_cn( &name->val, cn, cn_len ) == 0 ) + { + break; + } + } + + if( name == NULL ) + *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; + } +} + +/* + * Merge the flags for all certs in the chain, after calling callback + */ +static int x509_crt_merge_flags_with_cb( + uint32_t *flags, + x509_crt_verify_chain_item ver_chain[X509_MAX_VERIFY_CHAIN_SIZE], + size_t chain_len, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ) +{ + int ret; + size_t i; + uint32_t cur_flags; + + for( i = chain_len; i != 0; --i ) + { + cur_flags = ver_chain[i-1].flags; + + if( NULL != f_vrfy ) + if( ( ret = f_vrfy( p_vrfy, ver_chain[i-1].crt, (int) i-1, &cur_flags ) ) != 0 ) + return( ret ); + + *flags |= cur_flags; + } + + return( 0 ); +} + +/* + * Verify the certificate validity + */ +int mbedtls_x509_crt_verify( mbedtls_x509_crt *crt, + mbedtls_x509_crt *trust_ca, + mbedtls_x509_crl *ca_crl, + const char *cn, uint32_t *flags, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ) +{ + return( mbedtls_x509_crt_verify_with_profile( crt, trust_ca, ca_crl, + &mbedtls_x509_crt_profile_default, cn, flags, f_vrfy, p_vrfy ) ); +} + +/* + * Verify the certificate validity, with profile + * + * This function: + * - checks the requested CN (if any) + * - checks the type and size of the EE cert's key, + * as that isn't done as part of chain building/verification currently + * - builds and verifies the chain + * - then calls the callback and merges the flags + */ +int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt, + mbedtls_x509_crt *trust_ca, + mbedtls_x509_crl *ca_crl, + const mbedtls_x509_crt_profile *profile, + const char *cn, uint32_t *flags, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ) +{ + int ret; + mbedtls_pk_type_t pk_type; + x509_crt_verify_chain_item ver_chain[X509_MAX_VERIFY_CHAIN_SIZE]; + size_t chain_len; + uint32_t *ee_flags = &ver_chain[0].flags; + + *flags = 0; + memset( ver_chain, 0, sizeof( ver_chain ) ); + chain_len = 0; + + if( profile == NULL ) + { + ret = MBEDTLS_ERR_X509_BAD_INPUT_DATA; + goto exit; + } + + /* check name if requested */ + if( cn != NULL ) + x509_crt_verify_name( crt, cn, ee_flags ); + + /* Check the type and size of the key */ + pk_type = mbedtls_pk_get_type( &crt->pk ); + + if( x509_profile_check_pk_alg( profile, pk_type ) != 0 ) + *ee_flags |= MBEDTLS_X509_BADCERT_BAD_PK; + + if( x509_profile_check_key( profile, &crt->pk ) != 0 ) + *ee_flags |= MBEDTLS_X509_BADCERT_BAD_KEY; + + /* Check the chain */ + ret = x509_crt_verify_chain( crt, trust_ca, ca_crl, profile, + ver_chain, &chain_len ); + if( ret != 0 ) + goto exit; + + /* Build final flags, calling callback on the way if any */ + ret = x509_crt_merge_flags_with_cb( flags, + ver_chain, chain_len, f_vrfy, p_vrfy ); + +exit: + /* prevent misuse of the vrfy callback - VERIFY_FAILED would be ignored by + * the SSL module for authmode optional, but non-zero return from the + * callback means a fatal error so it shouldn't be ignored */ + if( ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED ) + ret = MBEDTLS_ERR_X509_FATAL_ERROR; + + if( ret != 0 ) + { + *flags = (uint32_t) -1; + return( ret ); + } + + if( *flags != 0 ) + return( MBEDTLS_ERR_X509_CERT_VERIFY_FAILED ); + + return( 0 ); +} + +/* + * Initialize a certificate chain + */ +void mbedtls_x509_crt_init( mbedtls_x509_crt *crt ) +{ + memset( crt, 0, sizeof(mbedtls_x509_crt) ); +} + +/* + * Unallocate all certificate data + */ +void mbedtls_x509_crt_free( mbedtls_x509_crt *crt ) +{ + mbedtls_x509_crt *cert_cur = crt; + mbedtls_x509_crt *cert_prv; + mbedtls_x509_name *name_cur; + mbedtls_x509_name *name_prv; + mbedtls_x509_sequence *seq_cur; + mbedtls_x509_sequence *seq_prv; + + if( crt == NULL ) + return; + + do + { + mbedtls_pk_free( &cert_cur->pk ); + +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + mbedtls_free( cert_cur->sig_opts ); +#endif + + name_cur = cert_cur->issuer.next; + while( name_cur != NULL ) + { + name_prv = name_cur; + name_cur = name_cur->next; + mbedtls_platform_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); + mbedtls_free( name_prv ); + } + + name_cur = cert_cur->subject.next; + while( name_cur != NULL ) + { + name_prv = name_cur; + name_cur = name_cur->next; + mbedtls_platform_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); + mbedtls_free( name_prv ); + } + + seq_cur = cert_cur->ext_key_usage.next; + while( seq_cur != NULL ) + { + seq_prv = seq_cur; + seq_cur = seq_cur->next; + mbedtls_platform_zeroize( seq_prv, + sizeof( mbedtls_x509_sequence ) ); + mbedtls_free( seq_prv ); + } + + seq_cur = cert_cur->subject_alt_names.next; + while( seq_cur != NULL ) + { + seq_prv = seq_cur; + seq_cur = seq_cur->next; + mbedtls_platform_zeroize( seq_prv, + sizeof( mbedtls_x509_sequence ) ); + mbedtls_free( seq_prv ); + } + + if( cert_cur->raw.p != NULL ) + { + mbedtls_platform_zeroize( cert_cur->raw.p, cert_cur->raw.len ); + mbedtls_free( cert_cur->raw.p ); + } + + cert_cur = cert_cur->next; + } + while( cert_cur != NULL ); + + cert_cur = crt; + do + { + cert_prv = cert_cur; + cert_cur = cert_cur->next; + + mbedtls_platform_zeroize( cert_prv, sizeof( mbedtls_x509_crt ) ); + if( cert_prv != crt ) + mbedtls_free( cert_prv ); + } + while( cert_cur != NULL ); +} + +#endif /* MBEDTLS_X509_CRT_PARSE_C */ diff --git a/common/mbedtls/x509_crt.h b/common/mbedtls/x509_crt.h new file mode 100644 index 00000000..4f7f7afb --- /dev/null +++ b/common/mbedtls/x509_crt.h @@ -0,0 +1,672 @@ +/** + * \file x509_crt.h + * + * \brief X.509 certificate parsing and writing + */ +/* + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_X509_CRT_H +#define MBEDTLS_X509_CRT_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "x509.h" +#include "x509_crl.h" + +/** + * \addtogroup x509_module + * \{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \name Structures and functions for parsing and writing X.509 certificates + * \{ + */ + +/** + * Container for an X.509 certificate. The certificate may be chained. + */ +typedef struct mbedtls_x509_crt +{ + mbedtls_x509_buf raw; /**< The raw certificate data (DER). */ + mbedtls_x509_buf tbs; /**< The raw certificate body (DER). The part that is To Be Signed. */ + + int version; /**< The X.509 version. (1=v1, 2=v2, 3=v3) */ + mbedtls_x509_buf serial; /**< Unique id for certificate issued by a specific CA. */ + mbedtls_x509_buf sig_oid; /**< Signature algorithm, e.g. sha1RSA */ + + mbedtls_x509_buf issuer_raw; /**< The raw issuer data (DER). Used for quick comparison. */ + mbedtls_x509_buf subject_raw; /**< The raw subject data (DER). Used for quick comparison. */ + + mbedtls_x509_name issuer; /**< The parsed issuer data (named information object). */ + mbedtls_x509_name subject; /**< The parsed subject data (named information object). */ + + mbedtls_x509_time valid_from; /**< Start time of certificate validity. */ + mbedtls_x509_time valid_to; /**< End time of certificate validity. */ + + mbedtls_pk_context pk; /**< Container for the public key context. */ + + mbedtls_x509_buf issuer_id; /**< Optional X.509 v2/v3 issuer unique identifier. */ + mbedtls_x509_buf subject_id; /**< Optional X.509 v2/v3 subject unique identifier. */ + mbedtls_x509_buf v3_ext; /**< Optional X.509 v3 extensions. */ + mbedtls_x509_sequence subject_alt_names; /**< Optional list of Subject Alternative Names (Only dNSName supported). */ + + int ext_types; /**< Bit string containing detected and parsed extensions */ + int ca_istrue; /**< Optional Basic Constraint extension value: 1 if this certificate belongs to a CA, 0 otherwise. */ + int max_pathlen; /**< Optional Basic Constraint extension value: The maximum path length to the root certificate. Path length is 1 higher than RFC 5280 'meaning', so 1+ */ + + unsigned int key_usage; /**< Optional key usage extension value: See the values in x509.h */ + + mbedtls_x509_sequence ext_key_usage; /**< Optional list of extended key usage OIDs. */ + + unsigned char ns_cert_type; /**< Optional Netscape certificate type extension value: See the values in x509.h */ + + mbedtls_x509_buf sig; /**< Signature: hash of the tbs part signed with the private key. */ + mbedtls_md_type_t sig_md; /**< Internal representation of the MD algorithm of the signature algorithm, e.g. MBEDTLS_MD_SHA256 */ + mbedtls_pk_type_t sig_pk; /**< Internal representation of the Public Key algorithm of the signature algorithm, e.g. MBEDTLS_PK_RSA */ + void *sig_opts; /**< Signature options to be passed to mbedtls_pk_verify_ext(), e.g. for RSASSA-PSS */ + + struct mbedtls_x509_crt *next; /**< Next certificate in the CA-chain. */ +} +mbedtls_x509_crt; + +/** + * Build flag from an algorithm/curve identifier (pk, md, ecp) + * Since 0 is always XXX_NONE, ignore it. + */ +#define MBEDTLS_X509_ID_FLAG( id ) ( 1 << ( id - 1 ) ) + +/** + * Security profile for certificate verification. + * + * All lists are bitfields, built by ORing flags from MBEDTLS_X509_ID_FLAG(). + */ +typedef struct mbedtls_x509_crt_profile +{ + uint32_t allowed_mds; /**< MDs for signatures */ + uint32_t allowed_pks; /**< PK algs for signatures */ + uint32_t allowed_curves; /**< Elliptic curves for ECDSA */ + uint32_t rsa_min_bitlen; /**< Minimum size for RSA keys */ +} +mbedtls_x509_crt_profile; + +#define MBEDTLS_X509_CRT_VERSION_1 0 +#define MBEDTLS_X509_CRT_VERSION_2 1 +#define MBEDTLS_X509_CRT_VERSION_3 2 + +#define MBEDTLS_X509_RFC5280_MAX_SERIAL_LEN 32 +#define MBEDTLS_X509_RFC5280_UTC_TIME_LEN 15 + +#if !defined( MBEDTLS_X509_MAX_FILE_PATH_LEN ) +#define MBEDTLS_X509_MAX_FILE_PATH_LEN 512 +#endif + +/** + * Container for writing a certificate (CRT) + */ +typedef struct mbedtls_x509write_cert +{ + int version; + mbedtls_mpi serial; + mbedtls_pk_context *subject_key; + mbedtls_pk_context *issuer_key; + mbedtls_asn1_named_data *subject; + mbedtls_asn1_named_data *issuer; + mbedtls_md_type_t md_alg; + char not_before[MBEDTLS_X509_RFC5280_UTC_TIME_LEN + 1]; + char not_after[MBEDTLS_X509_RFC5280_UTC_TIME_LEN + 1]; + mbedtls_asn1_named_data *extensions; +} +mbedtls_x509write_cert; + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +/** + * Default security profile. Should provide a good balance between security + * and compatibility with current deployments. + */ +extern const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_default; + +/** + * Expected next default profile. Recommended for new deployments. + * Currently targets a 128-bit security level, except for RSA-2048. + */ +extern const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_next; + +/** + * NSA Suite B profile. + */ +extern const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_suiteb; + +/** + * \brief Parse a single DER formatted certificate and add it + * to the chained list. + * + * \param chain points to the start of the chain + * \param buf buffer holding the certificate DER data + * \param buflen size of the buffer + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain, const unsigned char *buf, + size_t buflen ); + +/** + * \brief Parse one or more certificates and add them + * to the chained list. Parses permissively. If some + * certificates can be parsed, the result is the number + * of failed certificates it encountered. If none complete + * correctly, the first error is returned. + * + * \param chain points to the start of the chain + * \param buf buffer holding the certificate data in PEM or DER format + * \param buflen size of the buffer + * (including the terminating null byte for PEM data) + * + * \return 0 if all certificates parsed successfully, a positive number + * if partly successful or a specific X509 or PEM error code + */ +int mbedtls_x509_crt_parse( mbedtls_x509_crt *chain, const unsigned char *buf, size_t buflen ); + +#if defined(MBEDTLS_FS_IO) +/** + * \brief Load one or more certificates and add them + * to the chained list. Parses permissively. If some + * certificates can be parsed, the result is the number + * of failed certificates it encountered. If none complete + * correctly, the first error is returned. + * + * \param chain points to the start of the chain + * \param path filename to read the certificates from + * + * \return 0 if all certificates parsed successfully, a positive number + * if partly successful or a specific X509 or PEM error code + */ +int mbedtls_x509_crt_parse_file( mbedtls_x509_crt *chain, const char *path ); + +/** + * \brief Load one or more certificate files from a path and add them + * to the chained list. Parses permissively. If some + * certificates can be parsed, the result is the number + * of failed certificates it encountered. If none complete + * correctly, the first error is returned. + * + * \param chain points to the start of the chain + * \param path directory / folder to read the certificate files from + * + * \return 0 if all certificates parsed successfully, a positive number + * if partly successful or a specific X509 or PEM error code + */ +int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path ); +#endif /* MBEDTLS_FS_IO */ + +/** + * \brief Returns an informational string about the + * certificate. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param prefix A line prefix + * \param crt The X509 certificate to represent + * + * \return The length of the string written (not including the + * terminated nul byte), or a negative error code. + */ +int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, + const mbedtls_x509_crt *crt ); + +/** + * \brief Returns an informational string about the + * verification status of a certificate. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param prefix A line prefix + * \param flags Verification flags created by mbedtls_x509_crt_verify() + * + * \return The length of the string written (not including the + * terminated nul byte), or a negative error code. + */ +int mbedtls_x509_crt_verify_info( char *buf, size_t size, const char *prefix, + uint32_t flags ); + +/** + * \brief Verify the certificate signature + * + * The verify callback is a user-supplied callback that + * can clear / modify / add flags for a certificate. If set, + * the verification callback is called for each + * certificate in the chain (from the trust-ca down to the + * presented crt). The parameters for the callback are: + * (void *parameter, mbedtls_x509_crt *crt, int certificate_depth, + * int *flags). With the flags representing current flags for + * that specific certificate and the certificate depth from + * the bottom (Peer cert depth = 0). + * + * All flags left after returning from the callback + * are also returned to the application. The function should + * return 0 for anything (including invalid certificates) + * other than fatal error, as a non-zero return code + * immediately aborts the verification process. For fatal + * errors, a specific error code should be used (different + * from MBEDTLS_ERR_X509_CERT_VERIFY_FAILED which should not + * be returned at this point), or MBEDTLS_ERR_X509_FATAL_ERROR + * can be used if no better code is available. + * + * \note In case verification failed, the results can be displayed + * using \c mbedtls_x509_crt_verify_info() + * + * \note Same as \c mbedtls_x509_crt_verify_with_profile() with the + * default security profile. + * + * \note It is your responsibility to provide up-to-date CRLs for + * all trusted CAs. If no CRL is provided for the CA that was + * used to sign the certificate, CRL verification is skipped + * silently, that is *without* setting any flag. + * + * \note The \c trust_ca list can contain two types of certificates: + * (1) those of trusted root CAs, so that certificates + * chaining up to those CAs will be trusted, and (2) + * self-signed end-entity certificates to be trusted (for + * specific peers you know) - in that case, the self-signed + * certificate doesn't need to have the CA bit set. + * + * \param crt a certificate (chain) to be verified + * \param trust_ca the list of trusted CAs (see note above) + * \param ca_crl the list of CRLs for trusted CAs (see note above) + * \param cn expected Common Name (can be set to + * NULL if the CN must not be verified) + * \param flags result of the verification + * \param f_vrfy verification function + * \param p_vrfy verification parameter + * + * \return 0 (and flags set to 0) if the chain was verified and valid, + * MBEDTLS_ERR_X509_CERT_VERIFY_FAILED if the chain was verified + * but found to be invalid, in which case *flags will have one + * or more MBEDTLS_X509_BADCERT_XXX or MBEDTLS_X509_BADCRL_XXX + * flags set, or another error (and flags set to 0xffffffff) + * in case of a fatal error encountered during the + * verification process. + */ +int mbedtls_x509_crt_verify( mbedtls_x509_crt *crt, + mbedtls_x509_crt *trust_ca, + mbedtls_x509_crl *ca_crl, + const char *cn, uint32_t *flags, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ); + +/** + * \brief Verify the certificate signature according to profile + * + * \note Same as \c mbedtls_x509_crt_verify(), but with explicit + * security profile. + * + * \note The restrictions on keys (RSA minimum size, allowed curves + * for ECDSA) apply to all certificates: trusted root, + * intermediate CAs if any, and end entity certificate. + * + * \param crt a certificate (chain) to be verified + * \param trust_ca the list of trusted CAs + * \param ca_crl the list of CRLs for trusted CAs + * \param profile security profile for verification + * \param cn expected Common Name (can be set to + * NULL if the CN must not be verified) + * \param flags result of the verification + * \param f_vrfy verification function + * \param p_vrfy verification parameter + * + * \return 0 if successful or MBEDTLS_ERR_X509_CERT_VERIFY_FAILED + * in which case *flags will have one or more + * MBEDTLS_X509_BADCERT_XXX or MBEDTLS_X509_BADCRL_XXX flags + * set, + * or another error in case of a fatal error encountered + * during the verification process. + */ +int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt, + mbedtls_x509_crt *trust_ca, + mbedtls_x509_crl *ca_crl, + const mbedtls_x509_crt_profile *profile, + const char *cn, uint32_t *flags, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ); + +#if defined(MBEDTLS_X509_CHECK_KEY_USAGE) +/** + * \brief Check usage of certificate against keyUsage extension. + * + * \param crt Leaf certificate used. + * \param usage Intended usage(s) (eg MBEDTLS_X509_KU_KEY_ENCIPHERMENT + * before using the certificate to perform an RSA key + * exchange). + * + * \note Except for decipherOnly and encipherOnly, a bit set in the + * usage argument means this bit MUST be set in the + * certificate. For decipherOnly and encipherOnly, it means + * that bit MAY be set. + * + * \return 0 is these uses of the certificate are allowed, + * MBEDTLS_ERR_X509_BAD_INPUT_DATA if the keyUsage extension + * is present but does not match the usage argument. + * + * \note You should only call this function on leaf certificates, on + * (intermediate) CAs the keyUsage extension is automatically + * checked by \c mbedtls_x509_crt_verify(). + */ +int mbedtls_x509_crt_check_key_usage( const mbedtls_x509_crt *crt, + unsigned int usage ); +#endif /* MBEDTLS_X509_CHECK_KEY_USAGE) */ + +#if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) +/** + * \brief Check usage of certificate against extendedKeyUsage. + * + * \param crt Leaf certificate used. + * \param usage_oid Intended usage (eg MBEDTLS_OID_SERVER_AUTH or + * MBEDTLS_OID_CLIENT_AUTH). + * \param usage_len Length of usage_oid (eg given by MBEDTLS_OID_SIZE()). + * + * \return 0 if this use of the certificate is allowed, + * MBEDTLS_ERR_X509_BAD_INPUT_DATA if not. + * + * \note Usually only makes sense on leaf certificates. + */ +int mbedtls_x509_crt_check_extended_key_usage( const mbedtls_x509_crt *crt, + const char *usage_oid, + size_t usage_len ); +#endif /* MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE */ + +#if defined(MBEDTLS_X509_CRL_PARSE_C) +/** + * \brief Verify the certificate revocation status + * + * \param crt a certificate to be verified + * \param crl the CRL to verify against + * + * \return 1 if the certificate is revoked, 0 otherwise + * + */ +int mbedtls_x509_crt_is_revoked( const mbedtls_x509_crt *crt, const mbedtls_x509_crl *crl ); +#endif /* MBEDTLS_X509_CRL_PARSE_C */ + +/** + * \brief Initialize a certificate (chain) + * + * \param crt Certificate chain to initialize + */ +void mbedtls_x509_crt_init( mbedtls_x509_crt *crt ); + +/** + * \brief Unallocate all certificate data + * + * \param crt Certificate chain to free + */ +void mbedtls_x509_crt_free( mbedtls_x509_crt *crt ); +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +/* \} name */ +/* \} addtogroup x509_module */ + +#if defined(MBEDTLS_X509_CRT_WRITE_C) +/** + * \brief Initialize a CRT writing context + * + * \param ctx CRT context to initialize + */ +void mbedtls_x509write_crt_init( mbedtls_x509write_cert *ctx ); + +/** + * \brief Set the verion for a Certificate + * Default: MBEDTLS_X509_CRT_VERSION_3 + * + * \param ctx CRT context to use + * \param version version to set (MBEDTLS_X509_CRT_VERSION_1, MBEDTLS_X509_CRT_VERSION_2 or + * MBEDTLS_X509_CRT_VERSION_3) + */ +void mbedtls_x509write_crt_set_version( mbedtls_x509write_cert *ctx, int version ); + +/** + * \brief Set the serial number for a Certificate. + * + * \param ctx CRT context to use + * \param serial serial number to set + * + * \return 0 if successful + */ +int mbedtls_x509write_crt_set_serial( mbedtls_x509write_cert *ctx, const mbedtls_mpi *serial ); + +/** + * \brief Set the validity period for a Certificate + * Timestamps should be in string format for UTC timezone + * i.e. "YYYYMMDDhhmmss" + * e.g. "20131231235959" for December 31st 2013 + * at 23:59:59 + * + * \param ctx CRT context to use + * \param not_before not_before timestamp + * \param not_after not_after timestamp + * + * \return 0 if timestamp was parsed successfully, or + * a specific error code + */ +int mbedtls_x509write_crt_set_validity( mbedtls_x509write_cert *ctx, const char *not_before, + const char *not_after ); + +/** + * \brief Set the issuer name for a Certificate + * Issuer names should contain a comma-separated list + * of OID types and values: + * e.g. "C=UK,O=ARM,CN=mbed TLS CA" + * + * \param ctx CRT context to use + * \param issuer_name issuer name to set + * + * \return 0 if issuer name was parsed successfully, or + * a specific error code + */ +int mbedtls_x509write_crt_set_issuer_name( mbedtls_x509write_cert *ctx, + const char *issuer_name ); + +/** + * \brief Set the subject name for a Certificate + * Subject names should contain a comma-separated list + * of OID types and values: + * e.g. "C=UK,O=ARM,CN=mbed TLS Server 1" + * + * \param ctx CRT context to use + * \param subject_name subject name to set + * + * \return 0 if subject name was parsed successfully, or + * a specific error code + */ +int mbedtls_x509write_crt_set_subject_name( mbedtls_x509write_cert *ctx, + const char *subject_name ); + +/** + * \brief Set the subject public key for the certificate + * + * \param ctx CRT context to use + * \param key public key to include + */ +void mbedtls_x509write_crt_set_subject_key( mbedtls_x509write_cert *ctx, mbedtls_pk_context *key ); + +/** + * \brief Set the issuer key used for signing the certificate + * + * \param ctx CRT context to use + * \param key private key to sign with + */ +void mbedtls_x509write_crt_set_issuer_key( mbedtls_x509write_cert *ctx, mbedtls_pk_context *key ); + +/** + * \brief Set the MD algorithm to use for the signature + * (e.g. MBEDTLS_MD_SHA1) + * + * \param ctx CRT context to use + * \param md_alg MD algorithm to use + */ +void mbedtls_x509write_crt_set_md_alg( mbedtls_x509write_cert *ctx, mbedtls_md_type_t md_alg ); + +/** + * \brief Generic function to add to or replace an extension in the + * CRT + * + * \param ctx CRT context to use + * \param oid OID of the extension + * \param oid_len length of the OID + * \param critical if the extension is critical (per the RFC's definition) + * \param val value of the extension OCTET STRING + * \param val_len length of the value data + * + * \return 0 if successful, or a MBEDTLS_ERR_X509_ALLOC_FAILED + */ +int mbedtls_x509write_crt_set_extension( mbedtls_x509write_cert *ctx, + const char *oid, size_t oid_len, + int critical, + const unsigned char *val, size_t val_len ); + +/** + * \brief Set the basicConstraints extension for a CRT + * + * \param ctx CRT context to use + * \param is_ca is this a CA certificate + * \param max_pathlen maximum length of certificate chains below this + * certificate (only for CA certificates, -1 is + * inlimited) + * + * \return 0 if successful, or a MBEDTLS_ERR_X509_ALLOC_FAILED + */ +int mbedtls_x509write_crt_set_basic_constraints( mbedtls_x509write_cert *ctx, + int is_ca, int max_pathlen ); + +#if defined(MBEDTLS_SHA1_C) +/** + * \brief Set the subjectKeyIdentifier extension for a CRT + * Requires that mbedtls_x509write_crt_set_subject_key() has been + * called before + * + * \param ctx CRT context to use + * + * \return 0 if successful, or a MBEDTLS_ERR_X509_ALLOC_FAILED + */ +int mbedtls_x509write_crt_set_subject_key_identifier( mbedtls_x509write_cert *ctx ); + +/** + * \brief Set the authorityKeyIdentifier extension for a CRT + * Requires that mbedtls_x509write_crt_set_issuer_key() has been + * called before + * + * \param ctx CRT context to use + * + * \return 0 if successful, or a MBEDTLS_ERR_X509_ALLOC_FAILED + */ +int mbedtls_x509write_crt_set_authority_key_identifier( mbedtls_x509write_cert *ctx ); +#endif /* MBEDTLS_SHA1_C */ + +/** + * \brief Set the Key Usage Extension flags + * (e.g. MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_KEY_CERT_SIGN) + * + * \param ctx CRT context to use + * \param key_usage key usage flags to set + * + * \return 0 if successful, or MBEDTLS_ERR_X509_ALLOC_FAILED + */ +int mbedtls_x509write_crt_set_key_usage( mbedtls_x509write_cert *ctx, + unsigned int key_usage ); + +/** + * \brief Set the Netscape Cert Type flags + * (e.g. MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT | MBEDTLS_X509_NS_CERT_TYPE_EMAIL) + * + * \param ctx CRT context to use + * \param ns_cert_type Netscape Cert Type flags to set + * + * \return 0 if successful, or MBEDTLS_ERR_X509_ALLOC_FAILED + */ +int mbedtls_x509write_crt_set_ns_cert_type( mbedtls_x509write_cert *ctx, + unsigned char ns_cert_type ); + +/** + * \brief Free the contents of a CRT write context + * + * \param ctx CRT context to free + */ +void mbedtls_x509write_crt_free( mbedtls_x509write_cert *ctx ); + +/** + * \brief Write a built up certificate to a X509 DER structure + * Note: data is written at the end of the buffer! Use the + * return value to determine where you should start + * using the buffer + * + * \param ctx certificate to write away + * \param buf buffer to write to + * \param size size of the buffer + * \param f_rng RNG function (for signature, see note) + * \param p_rng RNG parameter + * + * \return length of data written if successful, or a specific + * error code + * + * \note f_rng may be NULL if RSA is used for signature and the + * signature is made offline (otherwise f_rng is desirable + * for countermeasures against timing attacks). + * ECDSA signatures always require a non-NULL f_rng. + */ +int mbedtls_x509write_crt_der( mbedtls_x509write_cert *ctx, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +#if defined(MBEDTLS_PEM_WRITE_C) +/** + * \brief Write a built up certificate to a X509 PEM string + * + * \param ctx certificate to write away + * \param buf buffer to write to + * \param size size of the buffer + * \param f_rng RNG function (for signature, see note) + * \param p_rng RNG parameter + * + * \return 0 if successful, or a specific error code + * + * \note f_rng may be NULL if RSA is used for signature and the + * signature is made offline (otherwise f_rng is desirable + * for countermeasures against timing attacks). + * ECDSA signatures always require a non-NULL f_rng. + */ +int mbedtls_x509write_crt_pem( mbedtls_x509write_cert *ctx, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); +#endif /* MBEDTLS_PEM_WRITE_C */ +#endif /* MBEDTLS_X509_CRT_WRITE_C */ + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_x509_crt.h */ diff --git a/common/polarssl/aes.c b/common/polarssl/aes.c deleted file mode 100644 index 36f735d4..00000000 --- a/common/polarssl/aes.c +++ /dev/null @@ -1,1454 +0,0 @@ -/* - * FIPS-197 compliant AES implementation - * - * Copyright (C) 2006-2014, Brainspark B.V. - * - * This file is part of PolarSSL (http://www.polarssl.org) - * Lead Maintainer: Paul Bakker - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/* - * The AES block cipher was designed by Vincent Rijmen and Joan Daemen. - * - * http://csrc.nist.gov/encryption/aes/rijndael/Rijndael.pdf - * http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf - */ - -#if !defined(POLARSSL_CONFIG_FILE) -#include "polarssl_config.h" -#else -#include POLARSSL_CONFIG_FILE -#endif - -#if defined(POLARSSL_AES_C) - -#include "aes.h" -#if defined(POLARSSL_PADLOCK_C) -#include "polarssl/padlock.h" -#endif -#if defined(POLARSSL_AESNI_C) -#include "polarssl/aesni.h" -#endif - -#if defined(POLARSSL_PLATFORM_C) -#include "polarssl/platform.h" -#else -#define polarssl_printf printf -#endif - -#if !defined(POLARSSL_AES_ALT) - -/* Implementation that should never be optimized out by the compiler */ -static void polarssl_zeroize( void *v, size_t n ) { - volatile unsigned char *p = v; while( n-- ) *p++ = 0; -} - -/* - * 32-bit integer manipulation macros (little endian) - */ -#ifndef GET_UINT32_LE -#define GET_UINT32_LE(n,b,i) \ -{ \ - (n) = ( (uint32_t) (b)[(i) ] ) \ - | ( (uint32_t) (b)[(i) + 1] << 8 ) \ - | ( (uint32_t) (b)[(i) + 2] << 16 ) \ - | ( (uint32_t) (b)[(i) + 3] << 24 ); \ -} -#endif - -#ifndef PUT_UINT32_LE -#define PUT_UINT32_LE(n,b,i) \ -{ \ - (b)[(i) ] = (unsigned char) ( (n) ); \ - (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \ - (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \ - (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \ -} -#endif - -#if defined(POLARSSL_PADLOCK_C) && \ - ( defined(POLARSSL_HAVE_X86) || defined(PADLOCK_ALIGN16) ) -static int aes_padlock_ace = -1; -#endif - -#if defined(POLARSSL_AES_ROM_TABLES) -/* - * Forward S-box - */ -static const unsigned char FSb[256] = -{ - 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, - 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, - 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, - 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, - 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, - 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, - 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, - 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, - 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, - 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, - 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, - 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, - 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, - 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, - 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, - 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, - 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, - 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, - 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, - 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, - 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, - 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, - 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, - 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, - 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, - 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, - 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, - 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, - 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, - 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, - 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, - 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 -}; - -/* - * Forward tables - */ -#define FT \ -\ - V(A5,63,63,C6), V(84,7C,7C,F8), V(99,77,77,EE), V(8D,7B,7B,F6), \ - V(0D,F2,F2,FF), V(BD,6B,6B,D6), V(B1,6F,6F,DE), V(54,C5,C5,91), \ - V(50,30,30,60), V(03,01,01,02), V(A9,67,67,CE), V(7D,2B,2B,56), \ - V(19,FE,FE,E7), V(62,D7,D7,B5), V(E6,AB,AB,4D), V(9A,76,76,EC), \ - V(45,CA,CA,8F), V(9D,82,82,1F), V(40,C9,C9,89), V(87,7D,7D,FA), \ - V(15,FA,FA,EF), V(EB,59,59,B2), V(C9,47,47,8E), V(0B,F0,F0,FB), \ - V(EC,AD,AD,41), V(67,D4,D4,B3), V(FD,A2,A2,5F), V(EA,AF,AF,45), \ - V(BF,9C,9C,23), V(F7,A4,A4,53), V(96,72,72,E4), V(5B,C0,C0,9B), \ - V(C2,B7,B7,75), V(1C,FD,FD,E1), V(AE,93,93,3D), V(6A,26,26,4C), \ - V(5A,36,36,6C), V(41,3F,3F,7E), V(02,F7,F7,F5), V(4F,CC,CC,83), \ - V(5C,34,34,68), V(F4,A5,A5,51), V(34,E5,E5,D1), V(08,F1,F1,F9), \ - V(93,71,71,E2), V(73,D8,D8,AB), V(53,31,31,62), V(3F,15,15,2A), \ - V(0C,04,04,08), V(52,C7,C7,95), V(65,23,23,46), V(5E,C3,C3,9D), \ - V(28,18,18,30), V(A1,96,96,37), V(0F,05,05,0A), V(B5,9A,9A,2F), \ - V(09,07,07,0E), V(36,12,12,24), V(9B,80,80,1B), V(3D,E2,E2,DF), \ - V(26,EB,EB,CD), V(69,27,27,4E), V(CD,B2,B2,7F), V(9F,75,75,EA), \ - V(1B,09,09,12), V(9E,83,83,1D), V(74,2C,2C,58), V(2E,1A,1A,34), \ - V(2D,1B,1B,36), V(B2,6E,6E,DC), V(EE,5A,5A,B4), V(FB,A0,A0,5B), \ - V(F6,52,52,A4), V(4D,3B,3B,76), V(61,D6,D6,B7), V(CE,B3,B3,7D), \ - V(7B,29,29,52), V(3E,E3,E3,DD), V(71,2F,2F,5E), V(97,84,84,13), \ - V(F5,53,53,A6), V(68,D1,D1,B9), V(00,00,00,00), V(2C,ED,ED,C1), \ - V(60,20,20,40), V(1F,FC,FC,E3), V(C8,B1,B1,79), V(ED,5B,5B,B6), \ - V(BE,6A,6A,D4), V(46,CB,CB,8D), V(D9,BE,BE,67), V(4B,39,39,72), \ - V(DE,4A,4A,94), V(D4,4C,4C,98), V(E8,58,58,B0), V(4A,CF,CF,85), \ - V(6B,D0,D0,BB), V(2A,EF,EF,C5), V(E5,AA,AA,4F), V(16,FB,FB,ED), \ - V(C5,43,43,86), V(D7,4D,4D,9A), V(55,33,33,66), V(94,85,85,11), \ - V(CF,45,45,8A), V(10,F9,F9,E9), V(06,02,02,04), V(81,7F,7F,FE), \ - V(F0,50,50,A0), V(44,3C,3C,78), V(BA,9F,9F,25), V(E3,A8,A8,4B), \ - V(F3,51,51,A2), V(FE,A3,A3,5D), V(C0,40,40,80), V(8A,8F,8F,05), \ - V(AD,92,92,3F), V(BC,9D,9D,21), V(48,38,38,70), V(04,F5,F5,F1), \ - V(DF,BC,BC,63), V(C1,B6,B6,77), V(75,DA,DA,AF), V(63,21,21,42), \ - V(30,10,10,20), V(1A,FF,FF,E5), V(0E,F3,F3,FD), V(6D,D2,D2,BF), \ - V(4C,CD,CD,81), V(14,0C,0C,18), V(35,13,13,26), V(2F,EC,EC,C3), \ - V(E1,5F,5F,BE), V(A2,97,97,35), V(CC,44,44,88), V(39,17,17,2E), \ - V(57,C4,C4,93), V(F2,A7,A7,55), V(82,7E,7E,FC), V(47,3D,3D,7A), \ - V(AC,64,64,C8), V(E7,5D,5D,BA), V(2B,19,19,32), V(95,73,73,E6), \ - V(A0,60,60,C0), V(98,81,81,19), V(D1,4F,4F,9E), V(7F,DC,DC,A3), \ - V(66,22,22,44), V(7E,2A,2A,54), V(AB,90,90,3B), V(83,88,88,0B), \ - V(CA,46,46,8C), V(29,EE,EE,C7), V(D3,B8,B8,6B), V(3C,14,14,28), \ - V(79,DE,DE,A7), V(E2,5E,5E,BC), V(1D,0B,0B,16), V(76,DB,DB,AD), \ - V(3B,E0,E0,DB), V(56,32,32,64), V(4E,3A,3A,74), V(1E,0A,0A,14), \ - V(DB,49,49,92), V(0A,06,06,0C), V(6C,24,24,48), V(E4,5C,5C,B8), \ - V(5D,C2,C2,9F), V(6E,D3,D3,BD), V(EF,AC,AC,43), V(A6,62,62,C4), \ - V(A8,91,91,39), V(A4,95,95,31), V(37,E4,E4,D3), V(8B,79,79,F2), \ - V(32,E7,E7,D5), V(43,C8,C8,8B), V(59,37,37,6E), V(B7,6D,6D,DA), \ - V(8C,8D,8D,01), V(64,D5,D5,B1), V(D2,4E,4E,9C), V(E0,A9,A9,49), \ - V(B4,6C,6C,D8), V(FA,56,56,AC), V(07,F4,F4,F3), V(25,EA,EA,CF), \ - V(AF,65,65,CA), V(8E,7A,7A,F4), V(E9,AE,AE,47), V(18,08,08,10), \ - V(D5,BA,BA,6F), V(88,78,78,F0), V(6F,25,25,4A), V(72,2E,2E,5C), \ - V(24,1C,1C,38), V(F1,A6,A6,57), V(C7,B4,B4,73), V(51,C6,C6,97), \ - V(23,E8,E8,CB), V(7C,DD,DD,A1), V(9C,74,74,E8), V(21,1F,1F,3E), \ - V(DD,4B,4B,96), V(DC,BD,BD,61), V(86,8B,8B,0D), V(85,8A,8A,0F), \ - V(90,70,70,E0), V(42,3E,3E,7C), V(C4,B5,B5,71), V(AA,66,66,CC), \ - V(D8,48,48,90), V(05,03,03,06), V(01,F6,F6,F7), V(12,0E,0E,1C), \ - V(A3,61,61,C2), V(5F,35,35,6A), V(F9,57,57,AE), V(D0,B9,B9,69), \ - V(91,86,86,17), V(58,C1,C1,99), V(27,1D,1D,3A), V(B9,9E,9E,27), \ - V(38,E1,E1,D9), V(13,F8,F8,EB), V(B3,98,98,2B), V(33,11,11,22), \ - V(BB,69,69,D2), V(70,D9,D9,A9), V(89,8E,8E,07), V(A7,94,94,33), \ - V(B6,9B,9B,2D), V(22,1E,1E,3C), V(92,87,87,15), V(20,E9,E9,C9), \ - V(49,CE,CE,87), V(FF,55,55,AA), V(78,28,28,50), V(7A,DF,DF,A5), \ - V(8F,8C,8C,03), V(F8,A1,A1,59), V(80,89,89,09), V(17,0D,0D,1A), \ - V(DA,BF,BF,65), V(31,E6,E6,D7), V(C6,42,42,84), V(B8,68,68,D0), \ - V(C3,41,41,82), V(B0,99,99,29), V(77,2D,2D,5A), V(11,0F,0F,1E), \ - V(CB,B0,B0,7B), V(FC,54,54,A8), V(D6,BB,BB,6D), V(3A,16,16,2C) - -#define V(a,b,c,d) 0x##a##b##c##d -static const uint32_t FT0[256] = { FT }; -#undef V - -#define V(a,b,c,d) 0x##b##c##d##a -static const uint32_t FT1[256] = { FT }; -#undef V - -#define V(a,b,c,d) 0x##c##d##a##b -static const uint32_t FT2[256] = { FT }; -#undef V - -#define V(a,b,c,d) 0x##d##a##b##c -static const uint32_t FT3[256] = { FT }; -#undef V - -#undef FT - -/* - * Reverse S-box - */ -static const unsigned char RSb[256] = -{ - 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, - 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, - 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, - 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, - 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, - 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, - 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, - 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, - 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, - 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, - 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, - 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, - 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, - 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, - 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, - 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, - 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, - 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, - 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, - 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, - 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, - 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, - 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, - 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, - 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, - 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, - 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, - 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, - 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, - 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, - 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, - 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D -}; - -/* - * Reverse tables - */ -#define RT \ -\ - V(50,A7,F4,51), V(53,65,41,7E), V(C3,A4,17,1A), V(96,5E,27,3A), \ - V(CB,6B,AB,3B), V(F1,45,9D,1F), V(AB,58,FA,AC), V(93,03,E3,4B), \ - V(55,FA,30,20), V(F6,6D,76,AD), V(91,76,CC,88), V(25,4C,02,F5), \ - V(FC,D7,E5,4F), V(D7,CB,2A,C5), V(80,44,35,26), V(8F,A3,62,B5), \ - V(49,5A,B1,DE), V(67,1B,BA,25), V(98,0E,EA,45), V(E1,C0,FE,5D), \ - V(02,75,2F,C3), V(12,F0,4C,81), V(A3,97,46,8D), V(C6,F9,D3,6B), \ - V(E7,5F,8F,03), V(95,9C,92,15), V(EB,7A,6D,BF), V(DA,59,52,95), \ - V(2D,83,BE,D4), V(D3,21,74,58), V(29,69,E0,49), V(44,C8,C9,8E), \ - V(6A,89,C2,75), V(78,79,8E,F4), V(6B,3E,58,99), V(DD,71,B9,27), \ - V(B6,4F,E1,BE), V(17,AD,88,F0), V(66,AC,20,C9), V(B4,3A,CE,7D), \ - V(18,4A,DF,63), V(82,31,1A,E5), V(60,33,51,97), V(45,7F,53,62), \ - V(E0,77,64,B1), V(84,AE,6B,BB), V(1C,A0,81,FE), V(94,2B,08,F9), \ - V(58,68,48,70), V(19,FD,45,8F), V(87,6C,DE,94), V(B7,F8,7B,52), \ - V(23,D3,73,AB), V(E2,02,4B,72), V(57,8F,1F,E3), V(2A,AB,55,66), \ - V(07,28,EB,B2), V(03,C2,B5,2F), V(9A,7B,C5,86), V(A5,08,37,D3), \ - V(F2,87,28,30), V(B2,A5,BF,23), V(BA,6A,03,02), V(5C,82,16,ED), \ - V(2B,1C,CF,8A), V(92,B4,79,A7), V(F0,F2,07,F3), V(A1,E2,69,4E), \ - V(CD,F4,DA,65), V(D5,BE,05,06), V(1F,62,34,D1), V(8A,FE,A6,C4), \ - V(9D,53,2E,34), V(A0,55,F3,A2), V(32,E1,8A,05), V(75,EB,F6,A4), \ - V(39,EC,83,0B), V(AA,EF,60,40), V(06,9F,71,5E), V(51,10,6E,BD), \ - V(F9,8A,21,3E), V(3D,06,DD,96), V(AE,05,3E,DD), V(46,BD,E6,4D), \ - V(B5,8D,54,91), V(05,5D,C4,71), V(6F,D4,06,04), V(FF,15,50,60), \ - V(24,FB,98,19), V(97,E9,BD,D6), V(CC,43,40,89), V(77,9E,D9,67), \ - V(BD,42,E8,B0), V(88,8B,89,07), V(38,5B,19,E7), V(DB,EE,C8,79), \ - V(47,0A,7C,A1), V(E9,0F,42,7C), V(C9,1E,84,F8), V(00,00,00,00), \ - V(83,86,80,09), V(48,ED,2B,32), V(AC,70,11,1E), V(4E,72,5A,6C), \ - V(FB,FF,0E,FD), V(56,38,85,0F), V(1E,D5,AE,3D), V(27,39,2D,36), \ - V(64,D9,0F,0A), V(21,A6,5C,68), V(D1,54,5B,9B), V(3A,2E,36,24), \ - V(B1,67,0A,0C), V(0F,E7,57,93), V(D2,96,EE,B4), V(9E,91,9B,1B), \ - V(4F,C5,C0,80), V(A2,20,DC,61), V(69,4B,77,5A), V(16,1A,12,1C), \ - V(0A,BA,93,E2), V(E5,2A,A0,C0), V(43,E0,22,3C), V(1D,17,1B,12), \ - V(0B,0D,09,0E), V(AD,C7,8B,F2), V(B9,A8,B6,2D), V(C8,A9,1E,14), \ - V(85,19,F1,57), V(4C,07,75,AF), V(BB,DD,99,EE), V(FD,60,7F,A3), \ - V(9F,26,01,F7), V(BC,F5,72,5C), V(C5,3B,66,44), V(34,7E,FB,5B), \ - V(76,29,43,8B), V(DC,C6,23,CB), V(68,FC,ED,B6), V(63,F1,E4,B8), \ - V(CA,DC,31,D7), V(10,85,63,42), V(40,22,97,13), V(20,11,C6,84), \ - V(7D,24,4A,85), V(F8,3D,BB,D2), V(11,32,F9,AE), V(6D,A1,29,C7), \ - V(4B,2F,9E,1D), V(F3,30,B2,DC), V(EC,52,86,0D), V(D0,E3,C1,77), \ - V(6C,16,B3,2B), V(99,B9,70,A9), V(FA,48,94,11), V(22,64,E9,47), \ - V(C4,8C,FC,A8), V(1A,3F,F0,A0), V(D8,2C,7D,56), V(EF,90,33,22), \ - V(C7,4E,49,87), V(C1,D1,38,D9), V(FE,A2,CA,8C), V(36,0B,D4,98), \ - V(CF,81,F5,A6), V(28,DE,7A,A5), V(26,8E,B7,DA), V(A4,BF,AD,3F), \ - V(E4,9D,3A,2C), V(0D,92,78,50), V(9B,CC,5F,6A), V(62,46,7E,54), \ - V(C2,13,8D,F6), V(E8,B8,D8,90), V(5E,F7,39,2E), V(F5,AF,C3,82), \ - V(BE,80,5D,9F), V(7C,93,D0,69), V(A9,2D,D5,6F), V(B3,12,25,CF), \ - V(3B,99,AC,C8), V(A7,7D,18,10), V(6E,63,9C,E8), V(7B,BB,3B,DB), \ - V(09,78,26,CD), V(F4,18,59,6E), V(01,B7,9A,EC), V(A8,9A,4F,83), \ - V(65,6E,95,E6), V(7E,E6,FF,AA), V(08,CF,BC,21), V(E6,E8,15,EF), \ - V(D9,9B,E7,BA), V(CE,36,6F,4A), V(D4,09,9F,EA), V(D6,7C,B0,29), \ - V(AF,B2,A4,31), V(31,23,3F,2A), V(30,94,A5,C6), V(C0,66,A2,35), \ - V(37,BC,4E,74), V(A6,CA,82,FC), V(B0,D0,90,E0), V(15,D8,A7,33), \ - V(4A,98,04,F1), V(F7,DA,EC,41), V(0E,50,CD,7F), V(2F,F6,91,17), \ - V(8D,D6,4D,76), V(4D,B0,EF,43), V(54,4D,AA,CC), V(DF,04,96,E4), \ - V(E3,B5,D1,9E), V(1B,88,6A,4C), V(B8,1F,2C,C1), V(7F,51,65,46), \ - V(04,EA,5E,9D), V(5D,35,8C,01), V(73,74,87,FA), V(2E,41,0B,FB), \ - V(5A,1D,67,B3), V(52,D2,DB,92), V(33,56,10,E9), V(13,47,D6,6D), \ - V(8C,61,D7,9A), V(7A,0C,A1,37), V(8E,14,F8,59), V(89,3C,13,EB), \ - V(EE,27,A9,CE), V(35,C9,61,B7), V(ED,E5,1C,E1), V(3C,B1,47,7A), \ - V(59,DF,D2,9C), V(3F,73,F2,55), V(79,CE,14,18), V(BF,37,C7,73), \ - V(EA,CD,F7,53), V(5B,AA,FD,5F), V(14,6F,3D,DF), V(86,DB,44,78), \ - V(81,F3,AF,CA), V(3E,C4,68,B9), V(2C,34,24,38), V(5F,40,A3,C2), \ - V(72,C3,1D,16), V(0C,25,E2,BC), V(8B,49,3C,28), V(41,95,0D,FF), \ - V(71,01,A8,39), V(DE,B3,0C,08), V(9C,E4,B4,D8), V(90,C1,56,64), \ - V(61,84,CB,7B), V(70,B6,32,D5), V(74,5C,6C,48), V(42,57,B8,D0) - -#define V(a,b,c,d) 0x##a##b##c##d -static const uint32_t RT0[256] = { RT }; -#undef V - -#define V(a,b,c,d) 0x##b##c##d##a -static const uint32_t RT1[256] = { RT }; -#undef V - -#define V(a,b,c,d) 0x##c##d##a##b -static const uint32_t RT2[256] = { RT }; -#undef V - -#define V(a,b,c,d) 0x##d##a##b##c -static const uint32_t RT3[256] = { RT }; -#undef V - -#undef RT - -/* - * Round constants - */ -static const uint32_t RCON[10] = -{ - 0x00000001, 0x00000002, 0x00000004, 0x00000008, - 0x00000010, 0x00000020, 0x00000040, 0x00000080, - 0x0000001B, 0x00000036 -}; - -#else /* POLARSSL_AES_ROM_TABLES */ - -/* - * Forward S-box & tables - */ -static unsigned char FSb[256]; -static uint32_t FT0[256]; -static uint32_t FT1[256]; -static uint32_t FT2[256]; -static uint32_t FT3[256]; - -/* - * Reverse S-box & tables - */ -static unsigned char RSb[256]; -static uint32_t RT0[256]; -static uint32_t RT1[256]; -static uint32_t RT2[256]; -static uint32_t RT3[256]; - -/* - * Round constants - */ -static uint32_t RCON[10]; - -/* - * Tables generation code - */ -#define ROTL8(x) ( ( x << 8 ) & 0xFFFFFFFF ) | ( x >> 24 ) -#define XTIME(x) ( ( x << 1 ) ^ ( ( x & 0x80 ) ? 0x1B : 0x00 ) ) -#define MUL(x,y) ( ( x && y ) ? pow[(log[x]+log[y]) % 255] : 0 ) - -static int aes_init_done = 0; - -static void aes_gen_tables( void ) -{ - int i, x, y, z; - int pow[256]; - int log[256]; - - /* - * compute pow and log tables over GF(2^8) - */ - for( i = 0, x = 1; i < 256; i++ ) - { - pow[i] = x; - log[x] = i; - x = ( x ^ XTIME( x ) ) & 0xFF; - } - - /* - * calculate the round constants - */ - for( i = 0, x = 1; i < 10; i++ ) - { - RCON[i] = (uint32_t) x; - x = XTIME( x ) & 0xFF; - } - - /* - * generate the forward and reverse S-boxes - */ - FSb[0x00] = 0x63; - RSb[0x63] = 0x00; - - for( i = 1; i < 256; i++ ) - { - x = pow[255 - log[i]]; - - y = x; y = ( ( y << 1 ) | ( y >> 7 ) ) & 0xFF; - x ^= y; y = ( ( y << 1 ) | ( y >> 7 ) ) & 0xFF; - x ^= y; y = ( ( y << 1 ) | ( y >> 7 ) ) & 0xFF; - x ^= y; y = ( ( y << 1 ) | ( y >> 7 ) ) & 0xFF; - x ^= y ^ 0x63; - - FSb[i] = (unsigned char) x; - RSb[x] = (unsigned char) i; - } - - /* - * generate the forward and reverse tables - */ - for( i = 0; i < 256; i++ ) - { - x = FSb[i]; - y = XTIME( x ) & 0xFF; - z = ( y ^ x ) & 0xFF; - - FT0[i] = ( (uint32_t) y ) ^ - ( (uint32_t) x << 8 ) ^ - ( (uint32_t) x << 16 ) ^ - ( (uint32_t) z << 24 ); - - FT1[i] = ROTL8( FT0[i] ); - FT2[i] = ROTL8( FT1[i] ); - FT3[i] = ROTL8( FT2[i] ); - - x = RSb[i]; - - RT0[i] = ( (uint32_t) MUL( 0x0E, x ) ) ^ - ( (uint32_t) MUL( 0x09, x ) << 8 ) ^ - ( (uint32_t) MUL( 0x0D, x ) << 16 ) ^ - ( (uint32_t) MUL( 0x0B, x ) << 24 ); - - RT1[i] = ROTL8( RT0[i] ); - RT2[i] = ROTL8( RT1[i] ); - RT3[i] = ROTL8( RT2[i] ); - } -} - -#endif /* POLARSSL_AES_ROM_TABLES */ - -void aes_init( aes_context *ctx ) -{ - memset( ctx, 0, sizeof( aes_context ) ); -} - -void aes_free( aes_context *ctx ) -{ - if( ctx == NULL ) - return; - - polarssl_zeroize( ctx, sizeof( aes_context ) ); -} - -/* - * AES key schedule (encryption) - */ -int aes_setkey_enc( aes_context *ctx, const unsigned char *key, - unsigned int keysize ) -{ - unsigned int i; - uint32_t *RK; - -#if !defined(POLARSSL_AES_ROM_TABLES) - if( aes_init_done == 0 ) - { - aes_gen_tables(); - aes_init_done = 1; - - } -#endif - - switch( keysize ) - { - case 128: ctx->nr = 10; break; - case 192: ctx->nr = 12; break; - case 256: ctx->nr = 14; break; - default : return( POLARSSL_ERR_AES_INVALID_KEY_LENGTH ); - } - -#if defined(POLARSSL_PADLOCK_C) && defined(PADLOCK_ALIGN16) - if( aes_padlock_ace == -1 ) - aes_padlock_ace = padlock_supports( PADLOCK_ACE ); - - if( aes_padlock_ace ) - ctx->rk = RK = PADLOCK_ALIGN16( ctx->buf ); - else -#endif - ctx->rk = RK = ctx->buf; - -#if defined(POLARSSL_AESNI_C) && defined(POLARSSL_HAVE_X86_64) - if( aesni_supports( POLARSSL_AESNI_AES ) ) - return( aesni_setkey_enc( (unsigned char *) ctx->rk, key, keysize ) ); -#endif - - for( i = 0; i < ( keysize >> 5 ); i++ ) - { - GET_UINT32_LE( RK[i], key, i << 2 ); - } - - switch( ctx->nr ) - { - case 10: - - for( i = 0; i < 10; i++, RK += 4 ) - { - RK[4] = RK[0] ^ RCON[i] ^ - ( (uint32_t) FSb[ ( RK[3] >> 8 ) & 0xFF ] ) ^ - ( (uint32_t) FSb[ ( RK[3] >> 16 ) & 0xFF ] << 8 ) ^ - ( (uint32_t) FSb[ ( RK[3] >> 24 ) & 0xFF ] << 16 ) ^ - ( (uint32_t) FSb[ ( RK[3] ) & 0xFF ] << 24 ); - - RK[5] = RK[1] ^ RK[4]; - RK[6] = RK[2] ^ RK[5]; - RK[7] = RK[3] ^ RK[6]; - } - break; - - case 12: - - for( i = 0; i < 8; i++, RK += 6 ) - { - RK[6] = RK[0] ^ RCON[i] ^ - ( (uint32_t) FSb[ ( RK[5] >> 8 ) & 0xFF ] ) ^ - ( (uint32_t) FSb[ ( RK[5] >> 16 ) & 0xFF ] << 8 ) ^ - ( (uint32_t) FSb[ ( RK[5] >> 24 ) & 0xFF ] << 16 ) ^ - ( (uint32_t) FSb[ ( RK[5] ) & 0xFF ] << 24 ); - - RK[7] = RK[1] ^ RK[6]; - RK[8] = RK[2] ^ RK[7]; - RK[9] = RK[3] ^ RK[8]; - RK[10] = RK[4] ^ RK[9]; - RK[11] = RK[5] ^ RK[10]; - } - break; - - case 14: - - for( i = 0; i < 7; i++, RK += 8 ) - { - RK[8] = RK[0] ^ RCON[i] ^ - ( (uint32_t) FSb[ ( RK[7] >> 8 ) & 0xFF ] ) ^ - ( (uint32_t) FSb[ ( RK[7] >> 16 ) & 0xFF ] << 8 ) ^ - ( (uint32_t) FSb[ ( RK[7] >> 24 ) & 0xFF ] << 16 ) ^ - ( (uint32_t) FSb[ ( RK[7] ) & 0xFF ] << 24 ); - - RK[9] = RK[1] ^ RK[8]; - RK[10] = RK[2] ^ RK[9]; - RK[11] = RK[3] ^ RK[10]; - - RK[12] = RK[4] ^ - ( (uint32_t) FSb[ ( RK[11] ) & 0xFF ] ) ^ - ( (uint32_t) FSb[ ( RK[11] >> 8 ) & 0xFF ] << 8 ) ^ - ( (uint32_t) FSb[ ( RK[11] >> 16 ) & 0xFF ] << 16 ) ^ - ( (uint32_t) FSb[ ( RK[11] >> 24 ) & 0xFF ] << 24 ); - - RK[13] = RK[5] ^ RK[12]; - RK[14] = RK[6] ^ RK[13]; - RK[15] = RK[7] ^ RK[14]; - } - break; - } - - return( 0 ); -} - -/* - * AES key schedule (decryption) - */ -int aes_setkey_dec( aes_context *ctx, const unsigned char *key, - unsigned int keysize ) -{ - int i, j, ret; - aes_context cty; - uint32_t *RK; - uint32_t *SK; - - aes_init( &cty ); - -#if defined(POLARSSL_PADLOCK_C) && defined(PADLOCK_ALIGN16) - if( aes_padlock_ace == -1 ) - aes_padlock_ace = padlock_supports( PADLOCK_ACE ); - - if( aes_padlock_ace ) - ctx->rk = RK = PADLOCK_ALIGN16( ctx->buf ); - else -#endif - ctx->rk = RK = ctx->buf; - - /* Also checks keysize */ - if( ( ret = aes_setkey_enc( &cty, key, keysize ) ) != 0 ) - goto exit; - - ctx->nr = cty.nr; - -#if defined(POLARSSL_AESNI_C) && defined(POLARSSL_HAVE_X86_64) - if( aesni_supports( POLARSSL_AESNI_AES ) ) - { - aesni_inverse_key( (unsigned char *) ctx->rk, - (const unsigned char *) cty.rk, ctx->nr ); - goto exit; - } -#endif - - SK = cty.rk + cty.nr * 4; - - *RK++ = *SK++; - *RK++ = *SK++; - *RK++ = *SK++; - *RK++ = *SK++; - - for( i = ctx->nr - 1, SK -= 8; i > 0; i--, SK -= 8 ) - { - for( j = 0; j < 4; j++, SK++ ) - { - *RK++ = RT0[ FSb[ ( *SK ) & 0xFF ] ] ^ - RT1[ FSb[ ( *SK >> 8 ) & 0xFF ] ] ^ - RT2[ FSb[ ( *SK >> 16 ) & 0xFF ] ] ^ - RT3[ FSb[ ( *SK >> 24 ) & 0xFF ] ]; - } - } - - *RK++ = *SK++; - *RK++ = *SK++; - *RK++ = *SK++; - *RK++ = *SK++; - -exit: - aes_free( &cty ); - - return( ret ); -} - -#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ -{ \ - X0 = *RK++ ^ FT0[ ( Y0 ) & 0xFF ] ^ \ - FT1[ ( Y1 >> 8 ) & 0xFF ] ^ \ - FT2[ ( Y2 >> 16 ) & 0xFF ] ^ \ - FT3[ ( Y3 >> 24 ) & 0xFF ]; \ - \ - X1 = *RK++ ^ FT0[ ( Y1 ) & 0xFF ] ^ \ - FT1[ ( Y2 >> 8 ) & 0xFF ] ^ \ - FT2[ ( Y3 >> 16 ) & 0xFF ] ^ \ - FT3[ ( Y0 >> 24 ) & 0xFF ]; \ - \ - X2 = *RK++ ^ FT0[ ( Y2 ) & 0xFF ] ^ \ - FT1[ ( Y3 >> 8 ) & 0xFF ] ^ \ - FT2[ ( Y0 >> 16 ) & 0xFF ] ^ \ - FT3[ ( Y1 >> 24 ) & 0xFF ]; \ - \ - X3 = *RK++ ^ FT0[ ( Y3 ) & 0xFF ] ^ \ - FT1[ ( Y0 >> 8 ) & 0xFF ] ^ \ - FT2[ ( Y1 >> 16 ) & 0xFF ] ^ \ - FT3[ ( Y2 >> 24 ) & 0xFF ]; \ -} - -#define AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ -{ \ - X0 = *RK++ ^ RT0[ ( Y0 ) & 0xFF ] ^ \ - RT1[ ( Y3 >> 8 ) & 0xFF ] ^ \ - RT2[ ( Y2 >> 16 ) & 0xFF ] ^ \ - RT3[ ( Y1 >> 24 ) & 0xFF ]; \ - \ - X1 = *RK++ ^ RT0[ ( Y1 ) & 0xFF ] ^ \ - RT1[ ( Y0 >> 8 ) & 0xFF ] ^ \ - RT2[ ( Y3 >> 16 ) & 0xFF ] ^ \ - RT3[ ( Y2 >> 24 ) & 0xFF ]; \ - \ - X2 = *RK++ ^ RT0[ ( Y2 ) & 0xFF ] ^ \ - RT1[ ( Y1 >> 8 ) & 0xFF ] ^ \ - RT2[ ( Y0 >> 16 ) & 0xFF ] ^ \ - RT3[ ( Y3 >> 24 ) & 0xFF ]; \ - \ - X3 = *RK++ ^ RT0[ ( Y3 ) & 0xFF ] ^ \ - RT1[ ( Y2 >> 8 ) & 0xFF ] ^ \ - RT2[ ( Y1 >> 16 ) & 0xFF ] ^ \ - RT3[ ( Y0 >> 24 ) & 0xFF ]; \ -} - -/* - * AES-ECB block encryption/decryption - */ -int aes_crypt_ecb( aes_context *ctx, - int mode, - const unsigned char input[16], - unsigned char output[16] ) -{ - int i; - uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; - -#if defined(POLARSSL_AESNI_C) && defined(POLARSSL_HAVE_X86_64) - if( aesni_supports( POLARSSL_AESNI_AES ) ) - return( aesni_crypt_ecb( ctx, mode, input, output ) ); -#endif - -#if defined(POLARSSL_PADLOCK_C) && defined(POLARSSL_HAVE_X86) - if( aes_padlock_ace ) - { - if( padlock_xcryptecb( ctx, mode, input, output ) == 0 ) - return( 0 ); - - // If padlock data misaligned, we just fall back to - // unaccelerated mode - // - } -#endif - - RK = ctx->rk; - - GET_UINT32_LE( X0, input, 0 ); X0 ^= *RK++; - GET_UINT32_LE( X1, input, 4 ); X1 ^= *RK++; - GET_UINT32_LE( X2, input, 8 ); X2 ^= *RK++; - GET_UINT32_LE( X3, input, 12 ); X3 ^= *RK++; - - if( mode == AES_DECRYPT ) - { - for( i = ( ctx->nr >> 1 ) - 1; i > 0; i-- ) - { - AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); - AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); - } - - AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); - - X0 = *RK++ ^ \ - ( (uint32_t) RSb[ ( Y0 ) & 0xFF ] ) ^ - ( (uint32_t) RSb[ ( Y3 >> 8 ) & 0xFF ] << 8 ) ^ - ( (uint32_t) RSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^ - ( (uint32_t) RSb[ ( Y1 >> 24 ) & 0xFF ] << 24 ); - - X1 = *RK++ ^ \ - ( (uint32_t) RSb[ ( Y1 ) & 0xFF ] ) ^ - ( (uint32_t) RSb[ ( Y0 >> 8 ) & 0xFF ] << 8 ) ^ - ( (uint32_t) RSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^ - ( (uint32_t) RSb[ ( Y2 >> 24 ) & 0xFF ] << 24 ); - - X2 = *RK++ ^ \ - ( (uint32_t) RSb[ ( Y2 ) & 0xFF ] ) ^ - ( (uint32_t) RSb[ ( Y1 >> 8 ) & 0xFF ] << 8 ) ^ - ( (uint32_t) RSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^ - ( (uint32_t) RSb[ ( Y3 >> 24 ) & 0xFF ] << 24 ); - - X3 = *RK++ ^ \ - ( (uint32_t) RSb[ ( Y3 ) & 0xFF ] ) ^ - ( (uint32_t) RSb[ ( Y2 >> 8 ) & 0xFF ] << 8 ) ^ - ( (uint32_t) RSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^ - ( (uint32_t) RSb[ ( Y0 >> 24 ) & 0xFF ] << 24 ); - } - else /* AES_ENCRYPT */ - { - for( i = ( ctx->nr >> 1 ) - 1; i > 0; i-- ) - { - AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); - AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); - } - - AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); - - X0 = *RK++ ^ \ - ( (uint32_t) FSb[ ( Y0 ) & 0xFF ] ) ^ - ( (uint32_t) FSb[ ( Y1 >> 8 ) & 0xFF ] << 8 ) ^ - ( (uint32_t) FSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^ - ( (uint32_t) FSb[ ( Y3 >> 24 ) & 0xFF ] << 24 ); - - X1 = *RK++ ^ \ - ( (uint32_t) FSb[ ( Y1 ) & 0xFF ] ) ^ - ( (uint32_t) FSb[ ( Y2 >> 8 ) & 0xFF ] << 8 ) ^ - ( (uint32_t) FSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^ - ( (uint32_t) FSb[ ( Y0 >> 24 ) & 0xFF ] << 24 ); - - X2 = *RK++ ^ \ - ( (uint32_t) FSb[ ( Y2 ) & 0xFF ] ) ^ - ( (uint32_t) FSb[ ( Y3 >> 8 ) & 0xFF ] << 8 ) ^ - ( (uint32_t) FSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^ - ( (uint32_t) FSb[ ( Y1 >> 24 ) & 0xFF ] << 24 ); - - X3 = *RK++ ^ \ - ( (uint32_t) FSb[ ( Y3 ) & 0xFF ] ) ^ - ( (uint32_t) FSb[ ( Y0 >> 8 ) & 0xFF ] << 8 ) ^ - ( (uint32_t) FSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^ - ( (uint32_t) FSb[ ( Y2 >> 24 ) & 0xFF ] << 24 ); - } - - PUT_UINT32_LE( X0, output, 0 ); - PUT_UINT32_LE( X1, output, 4 ); - PUT_UINT32_LE( X2, output, 8 ); - PUT_UINT32_LE( X3, output, 12 ); - - return( 0 ); -} - -#if defined(POLARSSL_CIPHER_MODE_CBC) -/* - * AES-CBC buffer encryption/decryption - */ -int aes_crypt_cbc( aes_context *ctx, - int mode, - size_t length, - unsigned char iv[16], - const unsigned char *input, - unsigned char *output ) -{ - int i; - unsigned char temp[16]; - - if( length % 16 ) - return( POLARSSL_ERR_AES_INVALID_INPUT_LENGTH ); - -#if defined(POLARSSL_PADLOCK_C) && defined(POLARSSL_HAVE_X86) - if( aes_padlock_ace ) - { - if( padlock_xcryptcbc( ctx, mode, length, iv, input, output ) == 0 ) - return( 0 ); - - // If padlock data misaligned, we just fall back to - // unaccelerated mode - // - } -#endif - - if( mode == AES_DECRYPT ) - { - while( length > 0 ) - { - memcpy( temp, input, 16 ); - aes_crypt_ecb( ctx, mode, input, output ); - - for( i = 0; i < 16; i++ ) - output[i] = (unsigned char)( output[i] ^ iv[i] ); - - memcpy( iv, temp, 16 ); - - input += 16; - output += 16; - length -= 16; - } - } - else - { - while( length > 0 ) - { - for( i = 0; i < 16; i++ ) - output[i] = (unsigned char)( input[i] ^ iv[i] ); - - aes_crypt_ecb( ctx, mode, output, output ); - memcpy( iv, output, 16 ); - - input += 16; - output += 16; - length -= 16; - } - } - - return( 0 ); -} -#endif /* POLARSSL_CIPHER_MODE_CBC */ - -#if defined(POLARSSL_CIPHER_MODE_CFB) -/* - * AES-CFB128 buffer encryption/decryption - */ -int aes_crypt_cfb128( aes_context *ctx, - int mode, - size_t length, - size_t *iv_off, - unsigned char iv[16], - const unsigned char *input, - unsigned char *output ) -{ - int c; - size_t n = *iv_off; - - if( mode == AES_DECRYPT ) - { - while( length-- ) - { - if( n == 0 ) - aes_crypt_ecb( ctx, AES_ENCRYPT, iv, iv ); - - c = *input++; - *output++ = (unsigned char)( c ^ iv[n] ); - iv[n] = (unsigned char) c; - - n = ( n + 1 ) & 0x0F; - } - } - else - { - while( length-- ) - { - if( n == 0 ) - aes_crypt_ecb( ctx, AES_ENCRYPT, iv, iv ); - - iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ ); - - n = ( n + 1 ) & 0x0F; - } - } - - *iv_off = n; - - return( 0 ); -} - -/* - * AES-CFB8 buffer encryption/decryption - */ -#include -int aes_crypt_cfb8( aes_context *ctx, - int mode, - size_t length, - unsigned char iv[16], - const unsigned char *input, - unsigned char *output ) -{ - unsigned char c; - unsigned char ov[17]; - - while( length-- ) - { - memcpy( ov, iv, 16 ); - aes_crypt_ecb( ctx, AES_ENCRYPT, iv, iv ); - - if( mode == AES_DECRYPT ) - ov[16] = *input; - - c = *output++ = (unsigned char)( iv[0] ^ *input++ ); - - if( mode == AES_ENCRYPT ) - ov[16] = c; - - memcpy( iv, ov + 1, 16 ); - } - - return( 0 ); -} -#endif /*POLARSSL_CIPHER_MODE_CFB */ - -#if defined(POLARSSL_CIPHER_MODE_CTR) -/* - * AES-CTR buffer encryption/decryption - */ -int aes_crypt_ctr( aes_context *ctx, - size_t length, - size_t *nc_off, - unsigned char nonce_counter[16], - unsigned char stream_block[16], - const unsigned char *input, - unsigned char *output ) -{ - int c, i; - size_t n = *nc_off; - - while( length-- ) - { - if( n == 0 ) { - aes_crypt_ecb( ctx, AES_ENCRYPT, nonce_counter, stream_block ); - - for( i = 16; i > 0; i-- ) - if( ++nonce_counter[i - 1] != 0 ) - break; - } - c = *input++; - *output++ = (unsigned char)( c ^ stream_block[n] ); - - n = ( n + 1 ) & 0x0F; - } - - *nc_off = n; - - return( 0 ); -} -#endif /* POLARSSL_CIPHER_MODE_CTR */ - -#endif /* !POLARSSL_AES_ALT */ - -#if defined(POLARSSL_SELF_TEST) - -#include - -/* - * AES test vectors from: - * - * http://csrc.nist.gov/archive/aes/rijndael/rijndael-vals.zip - */ -static const unsigned char aes_test_ecb_dec[3][16] = -{ - { 0x44, 0x41, 0x6A, 0xC2, 0xD1, 0xF5, 0x3C, 0x58, - 0x33, 0x03, 0x91, 0x7E, 0x6B, 0xE9, 0xEB, 0xE0 }, - { 0x48, 0xE3, 0x1E, 0x9E, 0x25, 0x67, 0x18, 0xF2, - 0x92, 0x29, 0x31, 0x9C, 0x19, 0xF1, 0x5B, 0xA4 }, - { 0x05, 0x8C, 0xCF, 0xFD, 0xBB, 0xCB, 0x38, 0x2D, - 0x1F, 0x6F, 0x56, 0x58, 0x5D, 0x8A, 0x4A, 0xDE } -}; - -static const unsigned char aes_test_ecb_enc[3][16] = -{ - { 0xC3, 0x4C, 0x05, 0x2C, 0xC0, 0xDA, 0x8D, 0x73, - 0x45, 0x1A, 0xFE, 0x5F, 0x03, 0xBE, 0x29, 0x7F }, - { 0xF3, 0xF6, 0x75, 0x2A, 0xE8, 0xD7, 0x83, 0x11, - 0x38, 0xF0, 0x41, 0x56, 0x06, 0x31, 0xB1, 0x14 }, - { 0x8B, 0x79, 0xEE, 0xCC, 0x93, 0xA0, 0xEE, 0x5D, - 0xFF, 0x30, 0xB4, 0xEA, 0x21, 0x63, 0x6D, 0xA4 } -}; - -#if defined(POLARSSL_CIPHER_MODE_CBC) -static const unsigned char aes_test_cbc_dec[3][16] = -{ - { 0xFA, 0xCA, 0x37, 0xE0, 0xB0, 0xC8, 0x53, 0x73, - 0xDF, 0x70, 0x6E, 0x73, 0xF7, 0xC9, 0xAF, 0x86 }, - { 0x5D, 0xF6, 0x78, 0xDD, 0x17, 0xBA, 0x4E, 0x75, - 0xB6, 0x17, 0x68, 0xC6, 0xAD, 0xEF, 0x7C, 0x7B }, - { 0x48, 0x04, 0xE1, 0x81, 0x8F, 0xE6, 0x29, 0x75, - 0x19, 0xA3, 0xE8, 0x8C, 0x57, 0x31, 0x04, 0x13 } -}; - -static const unsigned char aes_test_cbc_enc[3][16] = -{ - { 0x8A, 0x05, 0xFC, 0x5E, 0x09, 0x5A, 0xF4, 0x84, - 0x8A, 0x08, 0xD3, 0x28, 0xD3, 0x68, 0x8E, 0x3D }, - { 0x7B, 0xD9, 0x66, 0xD5, 0x3A, 0xD8, 0xC1, 0xBB, - 0x85, 0xD2, 0xAD, 0xFA, 0xE8, 0x7B, 0xB1, 0x04 }, - { 0xFE, 0x3C, 0x53, 0x65, 0x3E, 0x2F, 0x45, 0xB5, - 0x6F, 0xCD, 0x88, 0xB2, 0xCC, 0x89, 0x8F, 0xF0 } -}; -#endif /* POLARSSL_CIPHER_MODE_CBC */ - -#if defined(POLARSSL_CIPHER_MODE_CFB) -/* - * AES-CFB128 test vectors from: - * - * http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf - */ -static const unsigned char aes_test_cfb128_key[3][32] = -{ - { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, - 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }, - { 0x8E, 0x73, 0xB0, 0xF7, 0xDA, 0x0E, 0x64, 0x52, - 0xC8, 0x10, 0xF3, 0x2B, 0x80, 0x90, 0x79, 0xE5, - 0x62, 0xF8, 0xEA, 0xD2, 0x52, 0x2C, 0x6B, 0x7B }, - { 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE, - 0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81, - 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7, - 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4 } -}; - -static const unsigned char aes_test_cfb128_iv[16] = -{ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F -}; - -static const unsigned char aes_test_cfb128_pt[64] = -{ - 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, - 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A, - 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C, - 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51, - 0x30, 0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11, - 0xE5, 0xFB, 0xC1, 0x19, 0x1A, 0x0A, 0x52, 0xEF, - 0xF6, 0x9F, 0x24, 0x45, 0xDF, 0x4F, 0x9B, 0x17, - 0xAD, 0x2B, 0x41, 0x7B, 0xE6, 0x6C, 0x37, 0x10 -}; - -static const unsigned char aes_test_cfb128_ct[3][64] = -{ - { 0x3B, 0x3F, 0xD9, 0x2E, 0xB7, 0x2D, 0xAD, 0x20, - 0x33, 0x34, 0x49, 0xF8, 0xE8, 0x3C, 0xFB, 0x4A, - 0xC8, 0xA6, 0x45, 0x37, 0xA0, 0xB3, 0xA9, 0x3F, - 0xCD, 0xE3, 0xCD, 0xAD, 0x9F, 0x1C, 0xE5, 0x8B, - 0x26, 0x75, 0x1F, 0x67, 0xA3, 0xCB, 0xB1, 0x40, - 0xB1, 0x80, 0x8C, 0xF1, 0x87, 0xA4, 0xF4, 0xDF, - 0xC0, 0x4B, 0x05, 0x35, 0x7C, 0x5D, 0x1C, 0x0E, - 0xEA, 0xC4, 0xC6, 0x6F, 0x9F, 0xF7, 0xF2, 0xE6 }, - { 0xCD, 0xC8, 0x0D, 0x6F, 0xDD, 0xF1, 0x8C, 0xAB, - 0x34, 0xC2, 0x59, 0x09, 0xC9, 0x9A, 0x41, 0x74, - 0x67, 0xCE, 0x7F, 0x7F, 0x81, 0x17, 0x36, 0x21, - 0x96, 0x1A, 0x2B, 0x70, 0x17, 0x1D, 0x3D, 0x7A, - 0x2E, 0x1E, 0x8A, 0x1D, 0xD5, 0x9B, 0x88, 0xB1, - 0xC8, 0xE6, 0x0F, 0xED, 0x1E, 0xFA, 0xC4, 0xC9, - 0xC0, 0x5F, 0x9F, 0x9C, 0xA9, 0x83, 0x4F, 0xA0, - 0x42, 0xAE, 0x8F, 0xBA, 0x58, 0x4B, 0x09, 0xFF }, - { 0xDC, 0x7E, 0x84, 0xBF, 0xDA, 0x79, 0x16, 0x4B, - 0x7E, 0xCD, 0x84, 0x86, 0x98, 0x5D, 0x38, 0x60, - 0x39, 0xFF, 0xED, 0x14, 0x3B, 0x28, 0xB1, 0xC8, - 0x32, 0x11, 0x3C, 0x63, 0x31, 0xE5, 0x40, 0x7B, - 0xDF, 0x10, 0x13, 0x24, 0x15, 0xE5, 0x4B, 0x92, - 0xA1, 0x3E, 0xD0, 0xA8, 0x26, 0x7A, 0xE2, 0xF9, - 0x75, 0xA3, 0x85, 0x74, 0x1A, 0xB9, 0xCE, 0xF8, - 0x20, 0x31, 0x62, 0x3D, 0x55, 0xB1, 0xE4, 0x71 } -}; -#endif /* POLARSSL_CIPHER_MODE_CFB */ - -#if defined(POLARSSL_CIPHER_MODE_CTR) -/* - * AES-CTR test vectors from: - * - * http://www.faqs.org/rfcs/rfc3686.html - */ - -static const unsigned char aes_test_ctr_key[3][16] = -{ - { 0xAE, 0x68, 0x52, 0xF8, 0x12, 0x10, 0x67, 0xCC, - 0x4B, 0xF7, 0xA5, 0x76, 0x55, 0x77, 0xF3, 0x9E }, - { 0x7E, 0x24, 0x06, 0x78, 0x17, 0xFA, 0xE0, 0xD7, - 0x43, 0xD6, 0xCE, 0x1F, 0x32, 0x53, 0x91, 0x63 }, - { 0x76, 0x91, 0xBE, 0x03, 0x5E, 0x50, 0x20, 0xA8, - 0xAC, 0x6E, 0x61, 0x85, 0x29, 0xF9, 0xA0, 0xDC } -}; - -static const unsigned char aes_test_ctr_nonce_counter[3][16] = -{ - { 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, - { 0x00, 0x6C, 0xB6, 0xDB, 0xC0, 0x54, 0x3B, 0x59, - 0xDA, 0x48, 0xD9, 0x0B, 0x00, 0x00, 0x00, 0x01 }, - { 0x00, 0xE0, 0x01, 0x7B, 0x27, 0x77, 0x7F, 0x3F, - 0x4A, 0x17, 0x86, 0xF0, 0x00, 0x00, 0x00, 0x01 } -}; - -static const unsigned char aes_test_ctr_pt[3][48] = -{ - { 0x53, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x62, - 0x6C, 0x6F, 0x63, 0x6B, 0x20, 0x6D, 0x73, 0x67 }, - - { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F }, - - { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, - 0x20, 0x21, 0x22, 0x23 } -}; - -static const unsigned char aes_test_ctr_ct[3][48] = -{ - { 0xE4, 0x09, 0x5D, 0x4F, 0xB7, 0xA7, 0xB3, 0x79, - 0x2D, 0x61, 0x75, 0xA3, 0x26, 0x13, 0x11, 0xB8 }, - { 0x51, 0x04, 0xA1, 0x06, 0x16, 0x8A, 0x72, 0xD9, - 0x79, 0x0D, 0x41, 0xEE, 0x8E, 0xDA, 0xD3, 0x88, - 0xEB, 0x2E, 0x1E, 0xFC, 0x46, 0xDA, 0x57, 0xC8, - 0xFC, 0xE6, 0x30, 0xDF, 0x91, 0x41, 0xBE, 0x28 }, - { 0xC1, 0xCF, 0x48, 0xA8, 0x9F, 0x2F, 0xFD, 0xD9, - 0xCF, 0x46, 0x52, 0xE9, 0xEF, 0xDB, 0x72, 0xD7, - 0x45, 0x40, 0xA4, 0x2B, 0xDE, 0x6D, 0x78, 0x36, - 0xD5, 0x9A, 0x5C, 0xEA, 0xAE, 0xF3, 0x10, 0x53, - 0x25, 0xB2, 0x07, 0x2F } -}; - -static const int aes_test_ctr_len[3] = - { 16, 32, 36 }; -#endif /* POLARSSL_CIPHER_MODE_CTR */ - -/* - * Checkup routine - */ -int aes_self_test( int verbose ) -{ - int ret = 0, i, j, u, v; - unsigned char key[32]; - unsigned char buf[64]; - unsigned char iv[16]; -#if defined(POLARSSL_CIPHER_MODE_CBC) - unsigned char prv[16]; -#endif -#if defined(POLARSSL_CIPHER_MODE_CTR) || defined(POLARSSL_CIPHER_MODE_CFB) - size_t offset; -#endif -#if defined(POLARSSL_CIPHER_MODE_CTR) - int len; - unsigned char nonce_counter[16]; - unsigned char stream_block[16]; -#endif - aes_context ctx; - - memset( key, 0, 32 ); - aes_init( &ctx ); - - /* - * ECB mode - */ - for( i = 0; i < 6; i++ ) - { - u = i >> 1; - v = i & 1; - - if( verbose != 0 ) - polarssl_printf( " AES-ECB-%3d (%s): ", 128 + u * 64, - ( v == AES_DECRYPT ) ? "dec" : "enc" ); - - memset( buf, 0, 16 ); - - if( v == AES_DECRYPT ) - { - aes_setkey_dec( &ctx, key, 128 + u * 64 ); - - for( j = 0; j < 10000; j++ ) - aes_crypt_ecb( &ctx, v, buf, buf ); - - if( memcmp( buf, aes_test_ecb_dec[u], 16 ) != 0 ) - { - if( verbose != 0 ) - polarssl_printf( "failed\n" ); - - ret = 1; - goto exit; - } - } - else - { - aes_setkey_enc( &ctx, key, 128 + u * 64 ); - - for( j = 0; j < 10000; j++ ) - aes_crypt_ecb( &ctx, v, buf, buf ); - - if( memcmp( buf, aes_test_ecb_enc[u], 16 ) != 0 ) - { - if( verbose != 0 ) - polarssl_printf( "failed\n" ); - - ret = 1; - goto exit; - } - } - - if( verbose != 0 ) - polarssl_printf( "passed\n" ); - } - - if( verbose != 0 ) - polarssl_printf( "\n" ); - -#if defined(POLARSSL_CIPHER_MODE_CBC) - /* - * CBC mode - */ - for( i = 0; i < 6; i++ ) - { - u = i >> 1; - v = i & 1; - - if( verbose != 0 ) - polarssl_printf( " AES-CBC-%3d (%s): ", 128 + u * 64, - ( v == AES_DECRYPT ) ? "dec" : "enc" ); - - memset( iv , 0, 16 ); - memset( prv, 0, 16 ); - memset( buf, 0, 16 ); - - if( v == AES_DECRYPT ) - { - aes_setkey_dec( &ctx, key, 128 + u * 64 ); - - for( j = 0; j < 10000; j++ ) - aes_crypt_cbc( &ctx, v, 16, iv, buf, buf ); - - if( memcmp( buf, aes_test_cbc_dec[u], 16 ) != 0 ) - { - if( verbose != 0 ) - polarssl_printf( "failed\n" ); - - ret = 1; - goto exit; - } - } - else - { - aes_setkey_enc( &ctx, key, 128 + u * 64 ); - - for( j = 0; j < 10000; j++ ) - { - unsigned char tmp[16]; - - aes_crypt_cbc( &ctx, v, 16, iv, buf, buf ); - - memcpy( tmp, prv, 16 ); - memcpy( prv, buf, 16 ); - memcpy( buf, tmp, 16 ); - } - - if( memcmp( prv, aes_test_cbc_enc[u], 16 ) != 0 ) - { - if( verbose != 0 ) - polarssl_printf( "failed\n" ); - - ret = 1; - goto exit; - } - } - - if( verbose != 0 ) - polarssl_printf( "passed\n" ); - } - - if( verbose != 0 ) - polarssl_printf( "\n" ); -#endif /* POLARSSL_CIPHER_MODE_CBC */ - -#if defined(POLARSSL_CIPHER_MODE_CFB) - /* - * CFB128 mode - */ - for( i = 0; i < 6; i++ ) - { - u = i >> 1; - v = i & 1; - - if( verbose != 0 ) - polarssl_printf( " AES-CFB128-%3d (%s): ", 128 + u * 64, - ( v == AES_DECRYPT ) ? "dec" : "enc" ); - - memcpy( iv, aes_test_cfb128_iv, 16 ); - memcpy( key, aes_test_cfb128_key[u], 16 + u * 8 ); - - offset = 0; - aes_setkey_enc( &ctx, key, 128 + u * 64 ); - - if( v == AES_DECRYPT ) - { - memcpy( buf, aes_test_cfb128_ct[u], 64 ); - aes_crypt_cfb128( &ctx, v, 64, &offset, iv, buf, buf ); - - if( memcmp( buf, aes_test_cfb128_pt, 64 ) != 0 ) - { - if( verbose != 0 ) - polarssl_printf( "failed\n" ); - - ret = 1; - goto exit; - } - } - else - { - memcpy( buf, aes_test_cfb128_pt, 64 ); - aes_crypt_cfb128( &ctx, v, 64, &offset, iv, buf, buf ); - - if( memcmp( buf, aes_test_cfb128_ct[u], 64 ) != 0 ) - { - if( verbose != 0 ) - polarssl_printf( "failed\n" ); - - ret = 1; - goto exit; - } - } - - if( verbose != 0 ) - polarssl_printf( "passed\n" ); - } - - if( verbose != 0 ) - polarssl_printf( "\n" ); -#endif /* POLARSSL_CIPHER_MODE_CFB */ - -#if defined(POLARSSL_CIPHER_MODE_CTR) - /* - * CTR mode - */ - for( i = 0; i < 6; i++ ) - { - u = i >> 1; - v = i & 1; - - if( verbose != 0 ) - polarssl_printf( " AES-CTR-128 (%s): ", - ( v == AES_DECRYPT ) ? "dec" : "enc" ); - - memcpy( nonce_counter, aes_test_ctr_nonce_counter[u], 16 ); - memcpy( key, aes_test_ctr_key[u], 16 ); - - offset = 0; - aes_setkey_enc( &ctx, key, 128 ); - - if( v == AES_DECRYPT ) - { - len = aes_test_ctr_len[u]; - memcpy( buf, aes_test_ctr_ct[u], len ); - - aes_crypt_ctr( &ctx, len, &offset, nonce_counter, stream_block, - buf, buf ); - - if( memcmp( buf, aes_test_ctr_pt[u], len ) != 0 ) - { - if( verbose != 0 ) - polarssl_printf( "failed\n" ); - - ret = 1; - goto exit; - } - } - else - { - len = aes_test_ctr_len[u]; - memcpy( buf, aes_test_ctr_pt[u], len ); - - aes_crypt_ctr( &ctx, len, &offset, nonce_counter, stream_block, - buf, buf ); - - if( memcmp( buf, aes_test_ctr_ct[u], len ) != 0 ) - { - if( verbose != 0 ) - polarssl_printf( "failed\n" ); - - ret = 1; - goto exit; - } - } - - if( verbose != 0 ) - polarssl_printf( "passed\n" ); - } - - if( verbose != 0 ) - polarssl_printf( "\n" ); -#endif /* POLARSSL_CIPHER_MODE_CTR */ - - ret = 0; - -exit: - aes_free( &ctx ); - - return( ret ); -} - -#endif /* POLARSSL_SELF_TEST */ - -#endif /* POLARSSL_AES_C */ diff --git a/common/polarssl/aes.h b/common/polarssl/aes.h deleted file mode 100644 index 299cb4cd..00000000 --- a/common/polarssl/aes.h +++ /dev/null @@ -1,256 +0,0 @@ -/** - * \file aes.h - * - * \brief AES block cipher - * - * Copyright (C) 2006-2014, Brainspark B.V. - * - * This file is part of PolarSSL (http://www.polarssl.org) - * Lead Maintainer: Paul Bakker - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -#ifndef POLARSSL_AES_H -#define POLARSSL_AES_H - -#if !defined(POLARSSL_CONFIG_FILE) -#include "polarssl_config.h" -#else -#include POLARSSL_CONFIG_FILE -#endif - -#include - -#if defined(_MSC_VER) && !defined(EFIX64) && !defined(EFI32) -#include -typedef UINT32 uint32_t; -#else -#include -#endif - -/* padlock.c and aesni.c rely on these values! */ -#define AES_ENCRYPT 1 -#define AES_DECRYPT 0 - -#define POLARSSL_ERR_AES_INVALID_KEY_LENGTH -0x0020 /**< Invalid key length. */ -#define POLARSSL_ERR_AES_INVALID_INPUT_LENGTH -0x0022 /**< Invalid data input length. */ - -#if !defined(POLARSSL_AES_ALT) -// Regular implementation -// - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief AES context structure - * - * \note buf is able to hold 32 extra bytes, which can be used: - * - for alignment purposes if VIA padlock is used, and/or - * - to simplify key expansion in the 256-bit case by - * generating an extra round key - */ -typedef struct -{ - int nr; /*!< number of rounds */ - uint32_t *rk; /*!< AES round keys */ - uint32_t buf[68]; /*!< unaligned data */ -} -aes_context; - -/** - * \brief Initialize AES context - * - * \param ctx AES context to be initialized - */ -void aes_init( aes_context *ctx ); - -/** - * \brief Clear AES context - * - * \param ctx AES context to be cleared - */ -void aes_free( aes_context *ctx ); - -/** - * \brief AES key schedule (encryption) - * - * \param ctx AES context to be initialized - * \param key encryption key - * \param keysize must be 128, 192 or 256 - * - * \return 0 if successful, or POLARSSL_ERR_AES_INVALID_KEY_LENGTH - */ -int aes_setkey_enc( aes_context *ctx, const unsigned char *key, - unsigned int keysize ); - -/** - * \brief AES key schedule (decryption) - * - * \param ctx AES context to be initialized - * \param key decryption key - * \param keysize must be 128, 192 or 256 - * - * \return 0 if successful, or POLARSSL_ERR_AES_INVALID_KEY_LENGTH - */ -int aes_setkey_dec( aes_context *ctx, const unsigned char *key, - unsigned int keysize ); - -/** - * \brief AES-ECB block encryption/decryption - * - * \param ctx AES context - * \param mode AES_ENCRYPT or AES_DECRYPT - * \param input 16-byte input block - * \param output 16-byte output block - * - * \return 0 if successful - */ -int aes_crypt_ecb( aes_context *ctx, - int mode, - const unsigned char input[16], - unsigned char output[16] ); -#if defined(POLARSSL_CIPHER_MODE_CBC) -/** - * \brief AES-CBC buffer encryption/decryption - * Length should be a multiple of the block - * size (16 bytes) - * - * \param ctx AES context - * \param mode AES_ENCRYPT or AES_DECRYPT - * \param length length of the input data - * \param iv initialization vector (updated after use) - * \param input buffer holding the input data - * \param output buffer holding the output data - * - * \return 0 if successful, or POLARSSL_ERR_AES_INVALID_INPUT_LENGTH - */ -int aes_crypt_cbc( aes_context *ctx, - int mode, - size_t length, - unsigned char iv[16], - const unsigned char *input, - unsigned char *output ); -#endif /* POLARSSL_CIPHER_MODE_CBC */ - -#if defined(POLARSSL_CIPHER_MODE_CFB) -/** - * \brief AES-CFB128 buffer encryption/decryption. - * - * Note: Due to the nature of CFB you should use the same key schedule for - * both encryption and decryption. So a context initialized with - * aes_setkey_enc() for both AES_ENCRYPT and AES_DECRYPT. - * - * \param ctx AES context - * \param mode AES_ENCRYPT or AES_DECRYPT - * \param length length of the input data - * \param iv_off offset in IV (updated after use) - * \param iv initialization vector (updated after use) - * \param input buffer holding the input data - * \param output buffer holding the output data - * - * \return 0 if successful - */ -int aes_crypt_cfb128( aes_context *ctx, - int mode, - size_t length, - size_t *iv_off, - unsigned char iv[16], - const unsigned char *input, - unsigned char *output ); - -/** - * \brief AES-CFB8 buffer encryption/decryption. - * - * Note: Due to the nature of CFB you should use the same key schedule for - * both encryption and decryption. So a context initialized with - * aes_setkey_enc() for both AES_ENCRYPT and AES_DECRYPT. - * - * \param ctx AES context - * \param mode AES_ENCRYPT or AES_DECRYPT - * \param length length of the input data - * \param iv initialization vector (updated after use) - * \param input buffer holding the input data - * \param output buffer holding the output data - * - * \return 0 if successful - */ -int aes_crypt_cfb8( aes_context *ctx, - int mode, - size_t length, - unsigned char iv[16], - const unsigned char *input, - unsigned char *output ); -#endif /*POLARSSL_CIPHER_MODE_CFB */ - -#if defined(POLARSSL_CIPHER_MODE_CTR) -/** - * \brief AES-CTR buffer encryption/decryption - * - * Warning: You have to keep the maximum use of your counter in mind! - * - * Note: Due to the nature of CTR you should use the same key schedule for - * both encryption and decryption. So a context initialized with - * aes_setkey_enc() for both AES_ENCRYPT and AES_DECRYPT. - * - * \param ctx AES context - * \param length The length of the data - * \param nc_off The offset in the current stream_block (for resuming - * within current cipher stream). The offset pointer to - * should be 0 at the start of a stream. - * \param nonce_counter The 128-bit nonce and counter. - * \param stream_block The saved stream-block for resuming. Is overwritten - * by the function. - * \param input The input data stream - * \param output The output data stream - * - * \return 0 if successful - */ -int aes_crypt_ctr( aes_context *ctx, - size_t length, - size_t *nc_off, - unsigned char nonce_counter[16], - unsigned char stream_block[16], - const unsigned char *input, - unsigned char *output ); -#endif /* POLARSSL_CIPHER_MODE_CTR */ - -#ifdef __cplusplus -} -#endif - -#else /* POLARSSL_AES_ALT */ -#include "aes_alt.h" -#endif /* POLARSSL_AES_ALT */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief Checkup routine - * - * \return 0 if successful, or 1 if the test failed - */ -int aes_self_test( int verbose ); - -#ifdef __cplusplus -} -#endif - -#endif /* aes.h */ diff --git a/common/polarssl/aes_cmac128.c b/common/polarssl/aes_cmac128.c deleted file mode 100644 index 595f89b8..00000000 --- a/common/polarssl/aes_cmac128.c +++ /dev/null @@ -1,322 +0,0 @@ -/* - * AES-CMAC from NIST Special Publication 800-38B — Recommendation for block cipher modes of operation: The CMAC mode for authentication. - * - * Copyright (C) 2006-2014, Brainspark B.V. - * Copyright (C) 2014, Anargyros Plemenos - * Tests added Merkok, 2018 - * - * This file is part of PolarSSL (http://www.polarssl.org) - * Lead Maintainer: Paul Bakker - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Reference : https://polarssl.org/discussions/generic/authentication-token - * NIST Special Publication 800-38B — Recommendation for block cipher modes of operation: The CMAC mode for authentication. - * Tests here: - * https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/AES_CMAC.pdf -*/ - -#include "polarssl/aes_cmac128.h" -#include - -#define MIN(a,b) ((a)<(b)?(a):(b)) -#define _MSB(x) (((x)[0] & 0x80)?1:0) - -#if !defined(POLARSSL_CONFIG_FILE) -#include "polarssl_config.h" -#else -#include POLARSSL_CONFIG_FILE -#endif - -#if defined(POLARSSL_AES_C) -#include "aes.h" -#endif - -#if defined(POLARSSL_PLATFORM_C) -#include "polarssl/platform.h" -#else -#define polarssl_printf printf -#endif - - -/** - * zero a structure - */ -#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x)) - -/** - * zero a structure given a pointer to the structure - */ -#define ZERO_STRUCTP(x) do{ if((x) != NULL) memset((char *)(x), 0, sizeof(*(x)));} while(0) - - -/* For CMAC Calculation */ -static unsigned char const_Rb[16] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87 -}; -static unsigned char const_Zero[16] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static inline void aes_cmac_128_left_shift_1(const uint8_t in[16], uint8_t out[16]) -{ - uint8_t overflow = 0; - int8_t i; - - for (i = 15; i >= 0; i--) { - out[i] = in[i] << 1; - out[i] |= overflow; - overflow = _MSB(&in[i]); - } -} - -static inline void aes_cmac_128_xor(const uint8_t in1[16], const uint8_t in2[16], - uint8_t out[16]) -{ - uint8_t i; - - for (i = 0; i < 16; i++) { - out[i] = in1[i] ^ in2[i]; - } -} - -/* - * AES-CMAC-128 context setup - */ -void aes_cmac128_starts(aes_cmac128_context *ctx, const uint8_t K[16]) -{ - uint8_t L[16]; - - /* Zero struct of aes_context */ - ZERO_STRUCTP(ctx); - /* Initialize aes_context */ - aes_setkey_enc(&ctx->aes_key, K, 128); - - /* step 1 - generate subkeys k1 and k2 */ - aes_crypt_ecb(&ctx->aes_key, AES_ENCRYPT, const_Zero, L); - - if (_MSB(L) == 0) { - aes_cmac_128_left_shift_1(L, ctx->K1); - } else { - uint8_t tmp_block[16]; - - aes_cmac_128_left_shift_1(L, tmp_block); - aes_cmac_128_xor(tmp_block, const_Rb, ctx->K1); - ZERO_STRUCT(tmp_block); - } - - if (_MSB(ctx->K1) == 0) { - aes_cmac_128_left_shift_1(ctx->K1, ctx->K2); - } else { - uint8_t tmp_block[16]; - - aes_cmac_128_left_shift_1(ctx->K1, tmp_block); - aes_cmac_128_xor(tmp_block, const_Rb, ctx->K2); - ZERO_STRUCT(tmp_block); - } - - ZERO_STRUCT(L); -} - -/* - * AES-CMAC-128 process message - */ -void aes_cmac128_update(aes_cmac128_context *ctx, const uint8_t *_msg, size_t _msg_len) -{ - uint8_t tmp_block[16]; - uint8_t Y[16]; - const uint8_t *msg = _msg; - size_t msg_len = _msg_len; - - /* - * copy the remembered last block - */ - ZERO_STRUCT(tmp_block); - if (ctx->last_len) { - memcpy(tmp_block, ctx->last, ctx->last_len); - } - - /* - * check if we expand the block - */ - if (ctx->last_len < 16) { - size_t len = MIN(16 - ctx->last_len, msg_len); - - memcpy(&tmp_block[ctx->last_len], msg, len); - memcpy(ctx->last, tmp_block, 16); - msg += len; - msg_len -= len; - ctx->last_len += len; - } - - if (msg_len == 0) { - /* if it is still the last block, we are done */ - ZERO_STRUCT(tmp_block); - return; - } - - /* - * It is not the last block anymore - */ - ZERO_STRUCT(ctx->last); - ctx->last_len = 0; - - /* - * now checksum everything but the last block - */ - aes_cmac_128_xor(ctx->X, tmp_block, Y); - aes_crypt_ecb(&ctx->aes_key, AES_ENCRYPT, Y, ctx->X); - - while (msg_len > 16) { - memcpy(tmp_block, msg, 16); - msg += 16; - msg_len -= 16; - - aes_cmac_128_xor(ctx->X, tmp_block, Y); - aes_crypt_ecb(&ctx->aes_key, AES_ENCRYPT, Y, ctx->X); - } - - /* - * copy the last block, it will be processed in - * aes_cmac128_final(). - */ - memcpy(ctx->last, msg, msg_len); - ctx->last_len = msg_len; - - ZERO_STRUCT(tmp_block); - ZERO_STRUCT(Y); -} - -/* - * AES-CMAC-128 compute T - */ -void aes_cmac128_final(aes_cmac128_context *ctx, uint8_t T[16]) -{ - uint8_t tmp_block[16]; - uint8_t Y[16]; - - if (ctx->last_len < 16) { - ctx->last[ctx->last_len] = 0x80; - aes_cmac_128_xor(ctx->last, ctx->K2, tmp_block); - } else { - aes_cmac_128_xor(ctx->last, ctx->K1, tmp_block); - } - - aes_cmac_128_xor(tmp_block, ctx->X, Y); - aes_crypt_ecb(&ctx->aes_key, AES_ENCRYPT, Y, T); - - ZERO_STRUCT(tmp_block); - ZERO_STRUCT(Y); - ZERO_STRUCTP(ctx); -} - -/* - * Checkup routine - * - * https://csrc.nist.gov/projects/cryptographic-standards-and-guidelines/example-values - * https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/AES_CMAC.pdf - */ -int aes_cmac_self_test( int verbose ) -{ - unsigned char key[16] = {0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C}; - unsigned char mac[16] = {0}; - aes_cmac128_context ctx; - int ret; - - // check Example1: - if( verbose != 0 ) - polarssl_printf( " AES-CMAC-128 zero length data: " ); - unsigned char ex1data[16] = {0}; - aes_cmac128_starts(&ctx, key); - aes_cmac128_update(&ctx, ex1data, 0); - aes_cmac128_final(&ctx, mac); - unsigned char ex1res[16] = {0xBB, 0x1D, 0x69, 0x29, 0xE9, 0x59, 0x37, 0x28, 0x7F, 0xA3, 0x7D, 0x12, 0x9B, 0x75, 0x67, 0x46}; - if(!memcmp(mac, ex1res, 16)) { - if( verbose != 0 ) - polarssl_printf( "passed\n" ); - } else { - polarssl_printf( "failed\n" ); - ret = 1; - goto exit; - } - - // check Example2: - if( verbose != 0 ) - polarssl_printf( " AES-CMAC-128 one block data : " ); - unsigned char ex2data[16] = {0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A}; - aes_cmac128_starts(&ctx, key); - aes_cmac128_update(&ctx, ex2data, sizeof(ex2data)); - aes_cmac128_final(&ctx, mac); - unsigned char ex2res[16] = {0x07, 0x0A, 0x16, 0xB4, 0x6B, 0x4D, 0x41, 0x44, 0xF7, 0x9B, 0xDD, 0x9D, 0xD0, 0x4A, 0x28, 0x7C}; - if(!memcmp(mac, ex2res, 16)) { - if( verbose != 0 ) - polarssl_printf( "passed\n" ); - } else { - polarssl_printf( "failed\n" ); - ret = 1; - goto exit; - } - - // check Example3: - if( verbose != 0 ) - polarssl_printf( " AES-CMAC-128 20 bytes of data: " ); - unsigned char ex3data[20] = {0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A, - 0xAE, 0x2D, 0x8A, 0x57}; - aes_cmac128_starts(&ctx, key); - aes_cmac128_update(&ctx, ex3data, sizeof(ex3data)); - aes_cmac128_final(&ctx, mac); - unsigned char ex3res[16] = {0x7D, 0x85, 0x44, 0x9E, 0xA6, 0xEA, 0x19, 0xC8, 0x23, 0xA7, 0xBF, 0x78, 0x83, 0x7D, 0xFA, 0xDE}; - if(!memcmp(mac, ex3res, 16)) { - if( verbose != 0 ) - polarssl_printf( "passed\n" ); - } else { - polarssl_printf( "failed\n" ); - ret = 1; - goto exit; - } - - // check Example4: - if( verbose != 0 ) - polarssl_printf( " AES-CMAC-128 4 blocks of data: " ); - unsigned char ex4data[64] = {0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A, - 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C, 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51, - 0x30, 0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11, 0xE5, 0xFB, 0xC1, 0x19, 0x1A, 0x0A, 0x52, 0xEF, - 0xF6, 0x9F, 0x24, 0x45, 0xDF, 0x4F, 0x9B, 0x17, 0xAD, 0x2B, 0x41, 0x7B, 0xE6, 0x6C, 0x37, 0x10}; - aes_cmac128_starts(&ctx, key); - aes_cmac128_update(&ctx, ex4data, sizeof(ex4data)); - aes_cmac128_final(&ctx, mac); - unsigned char ex4res[16] = {0x51, 0xF0, 0xBE, 0xBF, 0x7E, 0x3B, 0x9D, 0x92, 0xFC, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3C, 0xFE}; - if(!memcmp(mac, ex4res, 16)) { - if( verbose != 0 ) - polarssl_printf( "passed\n" ); - } else { - polarssl_printf( "failed\n" ); - ret = 1; - goto exit; - } - - if( verbose != 0 ) - polarssl_printf( "\n" ); - - ret = 0; - -exit: - return( ret ); -} - diff --git a/common/polarssl/aes_cmac128.h b/common/polarssl/aes_cmac128.h deleted file mode 100644 index b792755f..00000000 --- a/common/polarssl/aes_cmac128.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * AES-CMAC from NIST Special Publication 800-38B — Recommendation for block cipher modes of operation: The CMAC mode for authentication. - * - * Copyright (C) 2006-2014, Brainspark B.V. - * Copyright (C) 2014, Anargyros Plemenos - * Tests added Merkok, 2018 - * - * This file is part of PolarSSL (http://www.polarssl.org) - * Lead Maintainer: Paul Bakker - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Reference : https://polarssl.org/discussions/generic/authentication-token - * NIST Special Publication 800-38B — Recommendation for block cipher modes of operation: The CMAC mode for authentication. - * Tests here: - * https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/AES_CMAC.pdf -*/ - -#include -#include -#include "aes.h" - -typedef struct aes_cmac_128_context { - aes_context aes_key; - - uint8_t K1[16]; - uint8_t K2[16]; - - uint8_t X[16]; - - uint8_t last[16]; - size_t last_len; -} -aes_cmac128_context; - -/* - * \brief AES-CMAC-128 context setup - * - * \param ctx context to be initialized - * \param key secret key for AES-128 - */ -void aes_cmac128_starts(aes_cmac128_context *ctx, const uint8_t K[16]); - -/* - * \brief AES-CMAC-128 process message - * - * \param ctx context to be initialized - * \param _msg the given message - * \param _msg_len the length of message - */ -void aes_cmac128_update(aes_cmac128_context *ctx, const uint8_t *_msg, size_t _msg_len); - -/* - * \brief AES-CMAC-128 compute T - * - * \param ctx context to be initialized - * \param T the generated MAC which is used to validate the message - */ -void aes_cmac128_final(aes_cmac128_context *ctx, uint8_t T[16]); - -/** - * \brief Checkup routine - * - * \return 0 if successful, or 1 if the test failed - */ -int aes_cmac_self_test( int verbose ); - diff --git a/common/polarssl/bignum.c b/common/polarssl/bignum.c deleted file mode 100644 index d22dd5c7..00000000 --- a/common/polarssl/bignum.c +++ /dev/null @@ -1,2143 +0,0 @@ -/* - * Multi-precision integer library - * - * Copyright (C) 2006-2010, Brainspark B.V. - * - * This file is part of PolarSSL (http://www.polarssl.org) - * Lead Maintainer: Paul Bakker - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/* - * This MPI implementation is based on: - * - * http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf - * http://www.stillhq.com/extracted/gnupg-api/mpi/ - * http://math.libtomcrypt.com/files/tommath.pdf - */ - -#include "polarssl_config.h" - -#if defined(POLARSSL_BIGNUM_C) - -#include "bignum.h" -#include "bn_mul.h" - -#include - -#define ciL (sizeof(t_uint)) /* chars in limb */ -#define biL (ciL << 3) /* bits in limb */ -#define biH (ciL << 2) /* half limb size */ - -/* - * Convert between bits/chars and number of limbs - */ -#define BITS_TO_LIMBS(i) (((i) + biL - 1) / biL) -#define CHARS_TO_LIMBS(i) (((i) + ciL - 1) / ciL) - -/* - * Initialize one MPI - */ -void mpi_init( mpi *X ) -{ - if( X == NULL ) - return; - - X->s = 1; - X->n = 0; - X->p = NULL; -} - -/* - * Unallocate one MPI - */ -void mpi_free( mpi *X ) -{ - if( X == NULL ) - return; - - if( X->p != NULL ) - { - memset( X->p, 0, X->n * ciL ); - free( X->p ); - } - - X->s = 1; - X->n = 0; - X->p = NULL; -} - -/* - * Enlarge to the specified number of limbs - */ -int mpi_grow( mpi *X, size_t nblimbs ) -{ - t_uint *p; - - if( nblimbs > POLARSSL_MPI_MAX_LIMBS ) - return( POLARSSL_ERR_MPI_MALLOC_FAILED ); - - if( X->n < nblimbs ) - { - if( ( p = (t_uint *) malloc( nblimbs * ciL ) ) == NULL ) - return( POLARSSL_ERR_MPI_MALLOC_FAILED ); - - memset( p, 0, nblimbs * ciL ); - - if( X->p != NULL ) - { - memcpy( p, X->p, X->n * ciL ); - memset( X->p, 0, X->n * ciL ); - free( X->p ); - } - - X->n = nblimbs; - X->p = p; - } - - return( 0 ); -} - -/* - * Copy the contents of Y into X - */ -int mpi_copy( mpi *X, const mpi *Y ) -{ - int ret; - size_t i; - - if( X == Y ) - return( 0 ); - - for( i = Y->n - 1; i > 0; i-- ) - if( Y->p[i] != 0 ) - break; - i++; - - X->s = Y->s; - - MPI_CHK( mpi_grow( X, i ) ); - - memset( X->p, 0, X->n * ciL ); - memcpy( X->p, Y->p, i * ciL ); - -cleanup: - - return( ret ); -} - -/* - * Swap the contents of X and Y - */ -void mpi_swap( mpi *X, mpi *Y ) -{ - mpi T; - - memcpy( &T, X, sizeof( mpi ) ); - memcpy( X, Y, sizeof( mpi ) ); - memcpy( Y, &T, sizeof( mpi ) ); -} - -/* - * Set value from integer - */ -int mpi_lset( mpi *X, t_sint z ) -{ - int ret; - - MPI_CHK( mpi_grow( X, 1 ) ); - memset( X->p, 0, X->n * ciL ); - - X->p[0] = ( z < 0 ) ? -z : z; - X->s = ( z < 0 ) ? -1 : 1; - -cleanup: - - return( ret ); -} - -/* - * Get a specific bit - */ -int mpi_get_bit( const mpi *X, size_t pos ) -{ - if( X->n * biL <= pos ) - return( 0 ); - - return ( X->p[pos / biL] >> ( pos % biL ) ) & 0x01; -} - -/* - * Set a bit to a specific value of 0 or 1 - */ -int mpi_set_bit( mpi *X, size_t pos, unsigned char val ) -{ - int ret = 0; - size_t off = pos / biL; - size_t idx = pos % biL; - - if( val != 0 && val != 1 ) - return POLARSSL_ERR_MPI_BAD_INPUT_DATA; - - if( X->n * biL <= pos ) - { - if( val == 0 ) - return ( 0 ); - - MPI_CHK( mpi_grow( X, off + 1 ) ); - } - - X->p[off] = ( X->p[off] & ~( 0x01 << idx ) ) | ( val << idx ); - -cleanup: - - return( ret ); -} - -/* - * Return the number of least significant bits - */ -size_t mpi_lsb( const mpi *X ) -{ - size_t i, j, count = 0; - - for( i = 0; i < X->n; i++ ) - for( j = 0; j < biL; j++, count++ ) - if( ( ( X->p[i] >> j ) & 1 ) != 0 ) - return( count ); - - return( 0 ); -} - -/* - * Return the number of most significant bits - */ -size_t mpi_msb( const mpi *X ) -{ - size_t i, j; - - for( i = X->n - 1; i > 0; i-- ) - if( X->p[i] != 0 ) - break; - - for( j = biL; j > 0; j-- ) - if( ( ( X->p[i] >> ( j - 1 ) ) & 1 ) != 0 ) - break; - - return( ( i * biL ) + j ); -} - -/* - * Return the total size in bytes - */ -size_t mpi_size( const mpi *X ) -{ - return( ( mpi_msb( X ) + 7 ) >> 3 ); -} - -/* - * Convert an ASCII character to digit value - */ -static int mpi_get_digit( t_uint *d, int radix, char c ) -{ - *d = 255; - - if( c >= 0x30 && c <= 0x39 ) *d = c - 0x30; - if( c >= 0x41 && c <= 0x46 ) *d = c - 0x37; - if( c >= 0x61 && c <= 0x66 ) *d = c - 0x57; - - if( *d >= (t_uint) radix ) - return( POLARSSL_ERR_MPI_INVALID_CHARACTER ); - - return( 0 ); -} - -/* - * Import from an ASCII string - */ -int mpi_read_string( mpi *X, int radix, const char *s ) -{ - int ret; - size_t i, j, slen, n; - t_uint d; - mpi T; - - if( radix < 2 || radix > 16 ) - return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); - - mpi_init( &T ); - - slen = strlen( s ); - - if( radix == 16 ) - { - n = BITS_TO_LIMBS( slen << 2 ); - - MPI_CHK( mpi_grow( X, n ) ); - MPI_CHK( mpi_lset( X, 0 ) ); - - for( i = slen, j = 0; i > 0; i--, j++ ) - { - if( i == 1 && s[i - 1] == '-' ) - { - X->s = -1; - break; - } - - MPI_CHK( mpi_get_digit( &d, radix, s[i - 1] ) ); - X->p[j / (2 * ciL)] |= d << ( (j % (2 * ciL)) << 2 ); - } - } - else - { - MPI_CHK( mpi_lset( X, 0 ) ); - - for( i = 0; i < slen; i++ ) - { - if( i == 0 && s[i] == '-' ) - { - X->s = -1; - continue; - } - - MPI_CHK( mpi_get_digit( &d, radix, s[i] ) ); - MPI_CHK( mpi_mul_int( &T, X, radix ) ); - - if( X->s == 1 ) - { - MPI_CHK( mpi_add_int( X, &T, d ) ); - } - else - { - MPI_CHK( mpi_sub_int( X, &T, d ) ); - } - } - } - -cleanup: - - mpi_free( &T ); - - return( ret ); -} - -/* - * Helper to write the digits high-order first - */ -static int mpi_write_hlp( mpi *X, int radix, char **p ) -{ - int ret; - t_uint r; - - if( radix < 2 || radix > 16 ) - return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); - - MPI_CHK( mpi_mod_int( &r, X, radix ) ); - MPI_CHK( mpi_div_int( X, NULL, X, radix ) ); - - if( mpi_cmp_int( X, 0 ) != 0 ) - MPI_CHK( mpi_write_hlp( X, radix, p ) ); - - if( r < 10 ) - *(*p)++ = (char)( r + 0x30 ); - else - *(*p)++ = (char)( r + 0x37 ); - -cleanup: - - return( ret ); -} - -/* - * Export into an ASCII string - */ -int mpi_write_string( const mpi *X, int radix, char *s, size_t *slen ) -{ - int ret = 0; - size_t n; - char *p; - mpi T; - - if( radix < 2 || radix > 16 ) - return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); - - n = mpi_msb( X ); - if( radix >= 4 ) n >>= 1; - if( radix >= 16 ) n >>= 1; - n += 3; - - if( *slen < n ) - { - *slen = n; - return( POLARSSL_ERR_MPI_BUFFER_TOO_SMALL ); - } - - p = s; - mpi_init( &T ); - - if( X->s == -1 ) - *p++ = '-'; - - if( radix == 16 ) - { - int c; - size_t i, j, k; - - for( i = X->n, k = 0; i > 0; i-- ) - { - for( j = ciL; j > 0; j-- ) - { - c = ( X->p[i - 1] >> ( ( j - 1 ) << 3) ) & 0xFF; - - if( c == 0 && k == 0 && ( i + j + 3 ) != 0 ) - continue; - - *(p++) = "0123456789ABCDEF" [c / 16]; - *(p++) = "0123456789ABCDEF" [c % 16]; - k = 1; - } - } - } - else - { - MPI_CHK( mpi_copy( &T, X ) ); - - if( T.s == -1 ) - T.s = 1; - - MPI_CHK( mpi_write_hlp( &T, radix, &p ) ); - } - - *p++ = '\0'; - *slen = p - s; - -cleanup: - - mpi_free( &T ); - - return( ret ); -} - -#if defined(POLARSSL_FS_IO) -/* - * Read X from an opened file - */ -int mpi_read_file( mpi *X, int radix, FILE *fin ) -{ - t_uint d; - size_t slen; - char *p; - /* - * Buffer should have space for (short) label and decimal formatted MPI, - * newline characters and '\0' - */ - char s[ POLARSSL_MPI_RW_BUFFER_SIZE ]; - - memset( s, 0, sizeof( s ) ); - if( fgets( s, sizeof( s ) - 1, fin ) == NULL ) - return( POLARSSL_ERR_MPI_FILE_IO_ERROR ); - - slen = strlen( s ); - if( slen == sizeof( s ) - 2 ) - return( POLARSSL_ERR_MPI_BUFFER_TOO_SMALL ); - - if( s[slen - 1] == '\n' ) { slen--; s[slen] = '\0'; } - if( s[slen - 1] == '\r' ) { slen--; s[slen] = '\0'; } - - p = s + slen; - while( --p >= s ) - if( mpi_get_digit( &d, radix, *p ) != 0 ) - break; - - return( mpi_read_string( X, radix, p + 1 ) ); -} - -/* - * Write X into an opened file (or stdout if fout == NULL) - */ -int mpi_write_file( const char *p, const mpi *X, int radix, FILE *fout ) -{ - int ret; - size_t n, slen, plen; - /* - * Buffer should have space for (short) label and decimal formatted MPI, - * newline characters and '\0' - */ - char s[ POLARSSL_MPI_RW_BUFFER_SIZE ]; - - n = sizeof( s ); - memset( s, 0, n ); - n -= 2; - - MPI_CHK( mpi_write_string( X, radix, s, (size_t *) &n ) ); - - if( p == NULL ) p = ""; - - plen = strlen( p ); - slen = strlen( s ); - s[slen++] = '\r'; - s[slen++] = '\n'; - - if( fout != NULL ) - { - if( fwrite( p, 1, plen, fout ) != plen || - fwrite( s, 1, slen, fout ) != slen ) - return( POLARSSL_ERR_MPI_FILE_IO_ERROR ); - } - else - printf( "%s%s", p, s ); - -cleanup: - - return( ret ); -} -#endif /* POLARSSL_FS_IO */ - -/* - * Import X from unsigned binary data, big endian - */ -int mpi_read_binary( mpi *X, const unsigned char *buf, size_t buflen ) -{ - int ret; - size_t i, j, n; - - for( n = 0; n < buflen; n++ ) - if( buf[n] != 0 ) - break; - - MPI_CHK( mpi_grow( X, CHARS_TO_LIMBS( buflen - n ) ) ); - MPI_CHK( mpi_lset( X, 0 ) ); - - for( i = buflen, j = 0; i > n; i--, j++ ) - X->p[j / ciL] |= ((t_uint) buf[i - 1]) << ((j % ciL) << 3); - -cleanup: - - return( ret ); -} - -/* - * Export X into unsigned binary data, big endian - */ -int mpi_write_binary( const mpi *X, unsigned char *buf, size_t buflen ) -{ - size_t i, j, n; - - n = mpi_size( X ); - - if( buflen < n ) - return( POLARSSL_ERR_MPI_BUFFER_TOO_SMALL ); - - memset( buf, 0, buflen ); - - for( i = buflen - 1, j = 0; n > 0; i--, j++, n-- ) - buf[i] = (unsigned char)( X->p[j / ciL] >> ((j % ciL) << 3) ); - - return( 0 ); -} - -/* - * Left-shift: X <<= count - */ -int mpi_shift_l( mpi *X, size_t count ) -{ - int ret; - size_t i, v0, t1; - t_uint r0 = 0, r1; - - v0 = count / (biL ); - t1 = count & (biL - 1); - - i = mpi_msb( X ) + count; - - if( X->n * biL < i ) - MPI_CHK( mpi_grow( X, BITS_TO_LIMBS( i ) ) ); - - ret = 0; - - /* - * shift by count / limb_size - */ - if( v0 > 0 ) - { - for( i = X->n; i > v0; i-- ) - X->p[i - 1] = X->p[i - v0 - 1]; - - for( ; i > 0; i-- ) - X->p[i - 1] = 0; - } - - /* - * shift by count % limb_size - */ - if( t1 > 0 ) - { - for( i = v0; i < X->n; i++ ) - { - r1 = X->p[i] >> (biL - t1); - X->p[i] <<= t1; - X->p[i] |= r0; - r0 = r1; - } - } - -cleanup: - - return( ret ); -} - -/* - * Right-shift: X >>= count - */ -int mpi_shift_r( mpi *X, size_t count ) -{ - size_t i, v0, v1; - t_uint r0 = 0, r1; - - v0 = count / biL; - v1 = count & (biL - 1); - - if( v0 > X->n || ( v0 == X->n && v1 > 0 ) ) - return mpi_lset( X, 0 ); - - /* - * shift by count / limb_size - */ - if( v0 > 0 ) - { - for( i = 0; i < X->n - v0; i++ ) - X->p[i] = X->p[i + v0]; - - for( ; i < X->n; i++ ) - X->p[i] = 0; - } - - /* - * shift by count % limb_size - */ - if( v1 > 0 ) - { - for( i = X->n; i > 0; i-- ) - { - r1 = X->p[i - 1] << (biL - v1); - X->p[i - 1] >>= v1; - X->p[i - 1] |= r0; - r0 = r1; - } - } - - return( 0 ); -} - -/* - * Compare unsigned values - */ -int mpi_cmp_abs( const mpi *X, const mpi *Y ) -{ - size_t i, j; - - for( i = X->n; i > 0; i-- ) - if( X->p[i - 1] != 0 ) - break; - - for( j = Y->n; j > 0; j-- ) - if( Y->p[j - 1] != 0 ) - break; - - if( i == 0 && j == 0 ) - return( 0 ); - - if( i > j ) return( 1 ); - if( j > i ) return( -1 ); - - for( ; i > 0; i-- ) - { - if( X->p[i - 1] > Y->p[i - 1] ) return( 1 ); - if( X->p[i - 1] < Y->p[i - 1] ) return( -1 ); - } - - return( 0 ); -} - -/* - * Compare signed values - */ -int mpi_cmp_mpi( const mpi *X, const mpi *Y ) -{ - size_t i, j; - - for( i = X->n; i > 0; i-- ) - if( X->p[i - 1] != 0 ) - break; - - for( j = Y->n; j > 0; j-- ) - if( Y->p[j - 1] != 0 ) - break; - - if( i == 0 && j == 0 ) - return( 0 ); - - if( i > j ) return( X->s ); - if( j > i ) return( -Y->s ); - - if( X->s > 0 && Y->s < 0 ) return( 1 ); - if( Y->s > 0 && X->s < 0 ) return( -1 ); - - for( ; i > 0; i-- ) - { - if( X->p[i - 1] > Y->p[i - 1] ) return( X->s ); - if( X->p[i - 1] < Y->p[i - 1] ) return( -X->s ); - } - - return( 0 ); -} - -/* - * Compare signed values - */ -int mpi_cmp_int( const mpi *X, t_sint z ) -{ - mpi Y; - t_uint p[1]; - - *p = ( z < 0 ) ? -z : z; - Y.s = ( z < 0 ) ? -1 : 1; - Y.n = 1; - Y.p = p; - - return( mpi_cmp_mpi( X, &Y ) ); -} - -/* - * Unsigned addition: X = |A| + |B| (HAC 14.7) - */ -int mpi_add_abs( mpi *X, const mpi *A, const mpi *B ) -{ - int ret; - size_t i, j; - t_uint *o, *p, c; - - if( X == B ) - { - const mpi *T = A; A = X; B = T; - } - - if( X != A ) - MPI_CHK( mpi_copy( X, A ) ); - - /* - * X should always be positive as a result of unsigned additions. - */ - X->s = 1; - - for( j = B->n; j > 0; j-- ) - if( B->p[j - 1] != 0 ) - break; - - MPI_CHK( mpi_grow( X, j ) ); - - o = B->p; p = X->p; c = 0; - - for( i = 0; i < j; i++, o++, p++ ) - { - *p += c; c = ( *p < c ); - *p += *o; c += ( *p < *o ); - } - - while( c != 0 ) - { - if( i >= X->n ) - { - MPI_CHK( mpi_grow( X, i + 1 ) ); - p = X->p + i; - } - - *p += c; c = ( *p < c ); i++; p++; - } - -cleanup: - - return( ret ); -} - -/* - * Helper for mpi substraction - */ -static void mpi_sub_hlp( size_t n, t_uint *s, t_uint *d ) -{ - size_t i; - t_uint c, z; - - for( i = c = 0; i < n; i++, s++, d++ ) - { - z = ( *d < c ); *d -= c; - c = ( *d < *s ) + z; *d -= *s; - } - - while( c != 0 ) - { - z = ( *d < c ); *d -= c; - c = z; i++; d++; - } -} - -/* - * Unsigned substraction: X = |A| - |B| (HAC 14.9) - */ -int mpi_sub_abs( mpi *X, const mpi *A, const mpi *B ) -{ - mpi TB; - int ret; - size_t n; - - if( mpi_cmp_abs( A, B ) < 0 ) - return( POLARSSL_ERR_MPI_NEGATIVE_VALUE ); - - mpi_init( &TB ); - - if( X == B ) - { - MPI_CHK( mpi_copy( &TB, B ) ); - B = &TB; - } - - if( X != A ) - MPI_CHK( mpi_copy( X, A ) ); - - /* - * X should always be positive as a result of unsigned substractions. - */ - X->s = 1; - - ret = 0; - - for( n = B->n; n > 0; n-- ) - if( B->p[n - 1] != 0 ) - break; - - mpi_sub_hlp( n, B->p, X->p ); - -cleanup: - - mpi_free( &TB ); - - return( ret ); -} - -/* - * Signed addition: X = A + B - */ -int mpi_add_mpi( mpi *X, const mpi *A, const mpi *B ) -{ - int ret, s = A->s; - - if( A->s * B->s < 0 ) - { - if( mpi_cmp_abs( A, B ) >= 0 ) - { - MPI_CHK( mpi_sub_abs( X, A, B ) ); - X->s = s; - } - else - { - MPI_CHK( mpi_sub_abs( X, B, A ) ); - X->s = -s; - } - } - else - { - MPI_CHK( mpi_add_abs( X, A, B ) ); - X->s = s; - } - -cleanup: - - return( ret ); -} - -/* - * Signed substraction: X = A - B - */ -int mpi_sub_mpi( mpi *X, const mpi *A, const mpi *B ) -{ - int ret, s = A->s; - - if( A->s * B->s > 0 ) - { - if( mpi_cmp_abs( A, B ) >= 0 ) - { - MPI_CHK( mpi_sub_abs( X, A, B ) ); - X->s = s; - } - else - { - MPI_CHK( mpi_sub_abs( X, B, A ) ); - X->s = -s; - } - } - else - { - MPI_CHK( mpi_add_abs( X, A, B ) ); - X->s = s; - } - -cleanup: - - return( ret ); -} - -/* - * Signed addition: X = A + b - */ -int mpi_add_int( mpi *X, const mpi *A, t_sint b ) -{ - mpi _B; - t_uint p[1]; - - p[0] = ( b < 0 ) ? -b : b; - _B.s = ( b < 0 ) ? -1 : 1; - _B.n = 1; - _B.p = p; - - return( mpi_add_mpi( X, A, &_B ) ); -} - -/* - * Signed substraction: X = A - b - */ -int mpi_sub_int( mpi *X, const mpi *A, t_sint b ) -{ - mpi _B; - t_uint p[1]; - - p[0] = ( b < 0 ) ? -b : b; - _B.s = ( b < 0 ) ? -1 : 1; - _B.n = 1; - _B.p = p; - - return( mpi_sub_mpi( X, A, &_B ) ); -} - -/* - * Helper for mpi multiplication - */ -static -#if defined(__APPLE__) && defined(__arm__) -/* - * Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn) - * appears to need this to prevent bad ARM code generation at -O3. - */ -__attribute__ ((noinline)) -#endif -void mpi_mul_hlp( size_t i, t_uint *s, t_uint *d, t_uint b ) -{ - t_uint c = 0, t = 0; - -#if defined(MULADDC_HUIT) - for( ; i >= 8; i -= 8 ) - { - MULADDC_INIT - MULADDC_HUIT - MULADDC_STOP - } - - for( ; i > 0; i-- ) - { - MULADDC_INIT - MULADDC_CORE - MULADDC_STOP - } -#else - for( ; i >= 16; i -= 16 ) - { - MULADDC_INIT - MULADDC_CORE MULADDC_CORE - MULADDC_CORE MULADDC_CORE - MULADDC_CORE MULADDC_CORE - MULADDC_CORE MULADDC_CORE - - MULADDC_CORE MULADDC_CORE - MULADDC_CORE MULADDC_CORE - MULADDC_CORE MULADDC_CORE - MULADDC_CORE MULADDC_CORE - MULADDC_STOP - } - - for( ; i >= 8; i -= 8 ) - { - MULADDC_INIT - MULADDC_CORE MULADDC_CORE - MULADDC_CORE MULADDC_CORE - - MULADDC_CORE MULADDC_CORE - MULADDC_CORE MULADDC_CORE - MULADDC_STOP - } - - for( ; i > 0; i-- ) - { - MULADDC_INIT - MULADDC_CORE - MULADDC_STOP - } -#endif - - t++; - - do { - *d += c; c = ( *d < c ); d++; - } - while( c != 0 ); -} - -/* - * Baseline multiplication: X = A * B (HAC 14.12) - */ -int mpi_mul_mpi( mpi *X, const mpi *A, const mpi *B ) -{ - int ret; - size_t i, j; - mpi TA, TB; - - mpi_init( &TA ); mpi_init( &TB ); - - if( X == A ) { MPI_CHK( mpi_copy( &TA, A ) ); A = &TA; } - if( X == B ) { MPI_CHK( mpi_copy( &TB, B ) ); B = &TB; } - - for( i = A->n; i > 0; i-- ) - if( A->p[i - 1] != 0 ) - break; - - for( j = B->n; j > 0; j-- ) - if( B->p[j - 1] != 0 ) - break; - - MPI_CHK( mpi_grow( X, i + j ) ); - MPI_CHK( mpi_lset( X, 0 ) ); - - for( i++; j > 0; j-- ) - mpi_mul_hlp( i - 1, A->p, X->p + j - 1, B->p[j - 1] ); - - X->s = A->s * B->s; - -cleanup: - - mpi_free( &TB ); mpi_free( &TA ); - - return( ret ); -} - -/* - * Baseline multiplication: X = A * b - */ -int mpi_mul_int( mpi *X, const mpi *A, t_sint b ) -{ - mpi _B; - t_uint p[1]; - - _B.s = 1; - _B.n = 1; - _B.p = p; - p[0] = b; - - return( mpi_mul_mpi( X, A, &_B ) ); -} - -/* - * Division by mpi: A = Q * B + R (HAC 14.20) - */ -int mpi_div_mpi( mpi *Q, mpi *R, const mpi *A, const mpi *B ) -{ - int ret; - size_t i, n, t, k; - mpi X, Y, Z, T1, T2; - - if( mpi_cmp_int( B, 0 ) == 0 ) - return( POLARSSL_ERR_MPI_DIVISION_BY_ZERO ); - - mpi_init( &X ); mpi_init( &Y ); mpi_init( &Z ); - mpi_init( &T1 ); mpi_init( &T2 ); - - if( mpi_cmp_abs( A, B ) < 0 ) - { - if( Q != NULL ) MPI_CHK( mpi_lset( Q, 0 ) ); - if( R != NULL ) MPI_CHK( mpi_copy( R, A ) ); - return( 0 ); - } - - MPI_CHK( mpi_copy( &X, A ) ); - MPI_CHK( mpi_copy( &Y, B ) ); - X.s = Y.s = 1; - - MPI_CHK( mpi_grow( &Z, A->n + 2 ) ); - MPI_CHK( mpi_lset( &Z, 0 ) ); - MPI_CHK( mpi_grow( &T1, 2 ) ); - MPI_CHK( mpi_grow( &T2, 3 ) ); - - k = mpi_msb( &Y ) % biL; - if( k < biL - 1 ) - { - k = biL - 1 - k; - MPI_CHK( mpi_shift_l( &X, k ) ); - MPI_CHK( mpi_shift_l( &Y, k ) ); - } - else k = 0; - - n = X.n - 1; - t = Y.n - 1; - MPI_CHK( mpi_shift_l( &Y, biL * (n - t) ) ); - - while( mpi_cmp_mpi( &X, &Y ) >= 0 ) - { - Z.p[n - t]++; - mpi_sub_mpi( &X, &X, &Y ); - } - mpi_shift_r( &Y, biL * (n - t) ); - - for( i = n; i > t ; i-- ) - { - if( X.p[i] >= Y.p[t] ) - Z.p[i - t - 1] = ~0; - else - { -#if defined(POLARSSL_HAVE_UDBL) - t_udbl r; - - r = (t_udbl) X.p[i] << biL; - r |= (t_udbl) X.p[i - 1]; - r /= Y.p[t]; - if( r > ((t_udbl) 1 << biL) - 1) - r = ((t_udbl) 1 << biL) - 1; - - Z.p[i - t - 1] = (t_uint) r; -#else - /* - * __udiv_qrnnd_c, from gmp/longlong.h - */ - t_uint q0, q1, r0, r1; - t_uint d0, d1, d, m; - - d = Y.p[t]; - d0 = ( d << biH ) >> biH; - d1 = ( d >> biH ); - - q1 = X.p[i] / d1; - r1 = X.p[i] - d1 * q1; - r1 <<= biH; - r1 |= ( X.p[i - 1] >> biH ); - - m = q1 * d0; - if( r1 < m ) - { - q1--, r1 += d; - while( r1 >= d && r1 < m ) - q1--, r1 += d; - } - r1 -= m; - - q0 = r1 / d1; - r0 = r1 - d1 * q0; - r0 <<= biH; - r0 |= ( X.p[i - 1] << biH ) >> biH; - - m = q0 * d0; - if( r0 < m ) - { - q0--, r0 += d; - while( r0 >= d && r0 < m ) - q0--, r0 += d; - } - r0 -= m; - - Z.p[i - t - 1] = ( q1 << biH ) | q0; -#endif - } - - Z.p[i - t - 1]++; - do - { - Z.p[i - t - 1]--; - - MPI_CHK( mpi_lset( &T1, 0 ) ); - T1.p[0] = (t < 1) ? 0 : Y.p[t - 1]; - T1.p[1] = Y.p[t]; - MPI_CHK( mpi_mul_int( &T1, &T1, Z.p[i - t - 1] ) ); - - MPI_CHK( mpi_lset( &T2, 0 ) ); - T2.p[0] = (i < 2) ? 0 : X.p[i - 2]; - T2.p[1] = (i < 1) ? 0 : X.p[i - 1]; - T2.p[2] = X.p[i]; - } - while( mpi_cmp_mpi( &T1, &T2 ) > 0 ); - - MPI_CHK( mpi_mul_int( &T1, &Y, Z.p[i - t - 1] ) ); - MPI_CHK( mpi_shift_l( &T1, biL * (i - t - 1) ) ); - MPI_CHK( mpi_sub_mpi( &X, &X, &T1 ) ); - - if( mpi_cmp_int( &X, 0 ) < 0 ) - { - MPI_CHK( mpi_copy( &T1, &Y ) ); - MPI_CHK( mpi_shift_l( &T1, biL * (i - t - 1) ) ); - MPI_CHK( mpi_add_mpi( &X, &X, &T1 ) ); - Z.p[i - t - 1]--; - } - } - - if( Q != NULL ) - { - mpi_copy( Q, &Z ); - Q->s = A->s * B->s; - } - - if( R != NULL ) - { - mpi_shift_r( &X, k ); - X.s = A->s; - mpi_copy( R, &X ); - - if( mpi_cmp_int( R, 0 ) == 0 ) - R->s = 1; - } - -cleanup: - - mpi_free( &X ); mpi_free( &Y ); mpi_free( &Z ); - mpi_free( &T1 ); mpi_free( &T2 ); - - return( ret ); -} - -/* - * Division by int: A = Q * b + R - */ -int mpi_div_int( mpi *Q, mpi *R, const mpi *A, t_sint b ) -{ - mpi _B; - t_uint p[1]; - - p[0] = ( b < 0 ) ? -b : b; - _B.s = ( b < 0 ) ? -1 : 1; - _B.n = 1; - _B.p = p; - - return( mpi_div_mpi( Q, R, A, &_B ) ); -} - -/* - * Modulo: R = A mod B - */ -int mpi_mod_mpi( mpi *R, const mpi *A, const mpi *B ) -{ - int ret; - - if( mpi_cmp_int( B, 0 ) < 0 ) - return POLARSSL_ERR_MPI_NEGATIVE_VALUE; - - MPI_CHK( mpi_div_mpi( NULL, R, A, B ) ); - - while( mpi_cmp_int( R, 0 ) < 0 ) - MPI_CHK( mpi_add_mpi( R, R, B ) ); - - while( mpi_cmp_mpi( R, B ) >= 0 ) - MPI_CHK( mpi_sub_mpi( R, R, B ) ); - -cleanup: - - return( ret ); -} - -/* - * Modulo: r = A mod b - */ -int mpi_mod_int( t_uint *r, const mpi *A, t_sint b ) -{ - size_t i; - t_uint x, y, z; - - if( b == 0 ) - return( POLARSSL_ERR_MPI_DIVISION_BY_ZERO ); - - if( b < 0 ) - return POLARSSL_ERR_MPI_NEGATIVE_VALUE; - - /* - * handle trivial cases - */ - if( b == 1 ) - { - *r = 0; - return( 0 ); - } - - if( b == 2 ) - { - *r = A->p[0] & 1; - return( 0 ); - } - - /* - * general case - */ - for( i = A->n, y = 0; i > 0; i-- ) - { - x = A->p[i - 1]; - y = ( y << biH ) | ( x >> biH ); - z = y / b; - y -= z * b; - - x <<= biH; - y = ( y << biH ) | ( x >> biH ); - z = y / b; - y -= z * b; - } - - /* - * If A is negative, then the current y represents a negative value. - * Flipping it to the positive side. - */ - if( A->s < 0 && y != 0 ) - y = b - y; - - *r = y; - - return( 0 ); -} - -/* - * Fast Montgomery initialization (thanks to Tom St Denis) - */ -static void mpi_montg_init( t_uint *mm, const mpi *N ) -{ - t_uint x, m0 = N->p[0]; - - x = m0; - x += ( ( m0 + 2 ) & 4 ) << 1; - x *= ( 2 - ( m0 * x ) ); - - if( biL >= 16 ) x *= ( 2 - ( m0 * x ) ); - if( biL >= 32 ) x *= ( 2 - ( m0 * x ) ); - if( biL >= 64 ) x *= ( 2 - ( m0 * x ) ); - - *mm = ~x + 1; -} - -/* - * Montgomery multiplication: A = A * B * R^-1 mod N (HAC 14.36) - */ -static void mpi_montmul( mpi *A, const mpi *B, const mpi *N, t_uint mm, const mpi *T ) -{ - size_t i, n, m; - t_uint u0, u1, *d; - - memset( T->p, 0, T->n * ciL ); - - d = T->p; - n = N->n; - m = ( B->n < n ) ? B->n : n; - - for( i = 0; i < n; i++ ) - { - /* - * T = (T + u0*B + u1*N) / 2^biL - */ - u0 = A->p[i]; - u1 = ( d[0] + u0 * B->p[0] ) * mm; - - mpi_mul_hlp( m, B->p, d, u0 ); - mpi_mul_hlp( n, N->p, d, u1 ); - - *d++ = u0; d[n + 1] = 0; - } - - memcpy( A->p, d, (n + 1) * ciL ); - - if( mpi_cmp_abs( A, N ) >= 0 ) - mpi_sub_hlp( n, N->p, A->p ); - else - /* prevent timing attacks */ - mpi_sub_hlp( n, A->p, T->p ); -} - -/* - * Montgomery reduction: A = A * R^-1 mod N - */ -static void mpi_montred( mpi *A, const mpi *N, t_uint mm, const mpi *T ) -{ - t_uint z = 1; - mpi U; - - U.n = U.s = (int) z; - U.p = &z; - - mpi_montmul( A, &U, N, mm, T ); -} - -/* - * Sliding-window exponentiation: X = A^E mod N (HAC 14.85) - */ -int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR ) -{ - int ret; - size_t wbits, wsize, one = 1; - size_t i, j, nblimbs; - size_t bufsize, nbits; - t_uint ei, mm, state; - mpi RR, T, W[ 2 << POLARSSL_MPI_WINDOW_SIZE ], Apos; - int neg; - - if( mpi_cmp_int( N, 0 ) < 0 || ( N->p[0] & 1 ) == 0 ) - return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); - - if( mpi_cmp_int( E, 0 ) < 0 ) - return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); - - /* - * Init temps and window size - */ - mpi_montg_init( &mm, N ); - mpi_init( &RR ); mpi_init( &T ); - memset( W, 0, sizeof( W ) ); - - i = mpi_msb( E ); - - wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 : - ( i > 79 ) ? 4 : ( i > 23 ) ? 3 : 1; - - if( wsize > POLARSSL_MPI_WINDOW_SIZE ) - wsize = POLARSSL_MPI_WINDOW_SIZE; - - j = N->n + 1; - MPI_CHK( mpi_grow( X, j ) ); - MPI_CHK( mpi_grow( &W[1], j ) ); - MPI_CHK( mpi_grow( &T, j * 2 ) ); - - /* - * Compensate for negative A (and correct at the end) - */ - neg = ( A->s == -1 ); - - mpi_init( &Apos ); - if( neg ) - { - MPI_CHK( mpi_copy( &Apos, A ) ); - Apos.s = 1; - A = &Apos; - } - - /* - * If 1st call, pre-compute R^2 mod N - */ - if( _RR == NULL || _RR->p == NULL ) - { - MPI_CHK( mpi_lset( &RR, 1 ) ); - MPI_CHK( mpi_shift_l( &RR, N->n * 2 * biL ) ); - MPI_CHK( mpi_mod_mpi( &RR, &RR, N ) ); - - if( _RR != NULL ) - memcpy( _RR, &RR, sizeof( mpi ) ); - } - else - memcpy( &RR, _RR, sizeof( mpi ) ); - - /* - * W[1] = A * R^2 * R^-1 mod N = A * R mod N - */ - if( mpi_cmp_mpi( A, N ) >= 0 ) - mpi_mod_mpi( &W[1], A, N ); - else mpi_copy( &W[1], A ); - - mpi_montmul( &W[1], &RR, N, mm, &T ); - - /* - * X = R^2 * R^-1 mod N = R mod N - */ - MPI_CHK( mpi_copy( X, &RR ) ); - mpi_montred( X, N, mm, &T ); - - if( wsize > 1 ) - { - /* - * W[1 << (wsize - 1)] = W[1] ^ (wsize - 1) - */ - j = one << (wsize - 1); - - MPI_CHK( mpi_grow( &W[j], N->n + 1 ) ); - MPI_CHK( mpi_copy( &W[j], &W[1] ) ); - - for( i = 0; i < wsize - 1; i++ ) - mpi_montmul( &W[j], &W[j], N, mm, &T ); - - /* - * W[i] = W[i - 1] * W[1] - */ - for( i = j + 1; i < (one << wsize); i++ ) - { - MPI_CHK( mpi_grow( &W[i], N->n + 1 ) ); - MPI_CHK( mpi_copy( &W[i], &W[i - 1] ) ); - - mpi_montmul( &W[i], &W[1], N, mm, &T ); - } - } - - nblimbs = E->n; - bufsize = 0; - nbits = 0; - wbits = 0; - state = 0; - - while( 1 ) - { - if( bufsize == 0 ) - { - if( nblimbs-- == 0 ) - break; - - bufsize = sizeof( t_uint ) << 3; - } - - bufsize--; - - ei = (E->p[nblimbs] >> bufsize) & 1; - - /* - * skip leading 0s - */ - if( ei == 0 && state == 0 ) - continue; - - if( ei == 0 && state == 1 ) - { - /* - * out of window, square X - */ - mpi_montmul( X, X, N, mm, &T ); - continue; - } - - /* - * add ei to current window - */ - state = 2; - - nbits++; - wbits |= (ei << (wsize - nbits)); - - if( nbits == wsize ) - { - /* - * X = X^wsize R^-1 mod N - */ - for( i = 0; i < wsize; i++ ) - mpi_montmul( X, X, N, mm, &T ); - - /* - * X = X * W[wbits] R^-1 mod N - */ - mpi_montmul( X, &W[wbits], N, mm, &T ); - - state--; - nbits = 0; - wbits = 0; - } - } - - /* - * process the remaining bits - */ - for( i = 0; i < nbits; i++ ) - { - mpi_montmul( X, X, N, mm, &T ); - - wbits <<= 1; - - if( (wbits & (one << wsize)) != 0 ) - mpi_montmul( X, &W[1], N, mm, &T ); - } - - /* - * X = A^E * R * R^-1 mod N = A^E mod N - */ - mpi_montred( X, N, mm, &T ); - - if( neg ) - { - X->s = -1; - mpi_add_mpi( X, N, X ); - } - -cleanup: - - for( i = (one << (wsize - 1)); i < (one << wsize); i++ ) - mpi_free( &W[i] ); - - mpi_free( &W[1] ); mpi_free( &T ); mpi_free( &Apos ); - - if( _RR == NULL ) - mpi_free( &RR ); - - return( ret ); -} - -/* - * Greatest common divisor: G = gcd(A, B) (HAC 14.54) - */ -int mpi_gcd( mpi *G, const mpi *A, const mpi *B ) -{ - int ret; - size_t lz, lzt; - mpi TG, TA, TB; - - mpi_init( &TG ); mpi_init( &TA ); mpi_init( &TB ); - - MPI_CHK( mpi_copy( &TA, A ) ); - MPI_CHK( mpi_copy( &TB, B ) ); - - lz = mpi_lsb( &TA ); - lzt = mpi_lsb( &TB ); - - if ( lzt < lz ) - lz = lzt; - - MPI_CHK( mpi_shift_r( &TA, lz ) ); - MPI_CHK( mpi_shift_r( &TB, lz ) ); - - TA.s = TB.s = 1; - - while( mpi_cmp_int( &TA, 0 ) != 0 ) - { - MPI_CHK( mpi_shift_r( &TA, mpi_lsb( &TA ) ) ); - MPI_CHK( mpi_shift_r( &TB, mpi_lsb( &TB ) ) ); - - if( mpi_cmp_mpi( &TA, &TB ) >= 0 ) - { - MPI_CHK( mpi_sub_abs( &TA, &TA, &TB ) ); - MPI_CHK( mpi_shift_r( &TA, 1 ) ); - } - else - { - MPI_CHK( mpi_sub_abs( &TB, &TB, &TA ) ); - MPI_CHK( mpi_shift_r( &TB, 1 ) ); - } - } - - MPI_CHK( mpi_shift_l( &TB, lz ) ); - MPI_CHK( mpi_copy( G, &TB ) ); - -cleanup: - - mpi_free( &TG ); mpi_free( &TA ); mpi_free( &TB ); - - return( ret ); -} - -int mpi_fill_random( mpi *X, size_t size, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng ) -{ - int ret; - - MPI_CHK( mpi_grow( X, CHARS_TO_LIMBS( size ) ) ); - MPI_CHK( mpi_lset( X, 0 ) ); - - MPI_CHK( f_rng( p_rng, (unsigned char *) X->p, size ) ); - -cleanup: - return( ret ); -} - -/* - * Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64) - */ -int mpi_inv_mod( mpi *X, const mpi *A, const mpi *N ) -{ - int ret; - mpi G, TA, TU, U1, U2, TB, TV, V1, V2; - - if( mpi_cmp_int( N, 0 ) <= 0 ) - return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); - - mpi_init( &TA ); mpi_init( &TU ); mpi_init( &U1 ); mpi_init( &U2 ); - mpi_init( &G ); mpi_init( &TB ); mpi_init( &TV ); - mpi_init( &V1 ); mpi_init( &V2 ); - - MPI_CHK( mpi_gcd( &G, A, N ) ); - - if( mpi_cmp_int( &G, 1 ) != 0 ) - { - ret = POLARSSL_ERR_MPI_NOT_ACCEPTABLE; - goto cleanup; - } - - MPI_CHK( mpi_mod_mpi( &TA, A, N ) ); - MPI_CHK( mpi_copy( &TU, &TA ) ); - MPI_CHK( mpi_copy( &TB, N ) ); - MPI_CHK( mpi_copy( &TV, N ) ); - - MPI_CHK( mpi_lset( &U1, 1 ) ); - MPI_CHK( mpi_lset( &U2, 0 ) ); - MPI_CHK( mpi_lset( &V1, 0 ) ); - MPI_CHK( mpi_lset( &V2, 1 ) ); - - do - { - while( ( TU.p[0] & 1 ) == 0 ) - { - MPI_CHK( mpi_shift_r( &TU, 1 ) ); - - if( ( U1.p[0] & 1 ) != 0 || ( U2.p[0] & 1 ) != 0 ) - { - MPI_CHK( mpi_add_mpi( &U1, &U1, &TB ) ); - MPI_CHK( mpi_sub_mpi( &U2, &U2, &TA ) ); - } - - MPI_CHK( mpi_shift_r( &U1, 1 ) ); - MPI_CHK( mpi_shift_r( &U2, 1 ) ); - } - - while( ( TV.p[0] & 1 ) == 0 ) - { - MPI_CHK( mpi_shift_r( &TV, 1 ) ); - - if( ( V1.p[0] & 1 ) != 0 || ( V2.p[0] & 1 ) != 0 ) - { - MPI_CHK( mpi_add_mpi( &V1, &V1, &TB ) ); - MPI_CHK( mpi_sub_mpi( &V2, &V2, &TA ) ); - } - - MPI_CHK( mpi_shift_r( &V1, 1 ) ); - MPI_CHK( mpi_shift_r( &V2, 1 ) ); - } - - if( mpi_cmp_mpi( &TU, &TV ) >= 0 ) - { - MPI_CHK( mpi_sub_mpi( &TU, &TU, &TV ) ); - MPI_CHK( mpi_sub_mpi( &U1, &U1, &V1 ) ); - MPI_CHK( mpi_sub_mpi( &U2, &U2, &V2 ) ); - } - else - { - MPI_CHK( mpi_sub_mpi( &TV, &TV, &TU ) ); - MPI_CHK( mpi_sub_mpi( &V1, &V1, &U1 ) ); - MPI_CHK( mpi_sub_mpi( &V2, &V2, &U2 ) ); - } - } - while( mpi_cmp_int( &TU, 0 ) != 0 ); - - while( mpi_cmp_int( &V1, 0 ) < 0 ) - MPI_CHK( mpi_add_mpi( &V1, &V1, N ) ); - - while( mpi_cmp_mpi( &V1, N ) >= 0 ) - MPI_CHK( mpi_sub_mpi( &V1, &V1, N ) ); - - MPI_CHK( mpi_copy( X, &V1 ) ); - -cleanup: - - mpi_free( &TA ); mpi_free( &TU ); mpi_free( &U1 ); mpi_free( &U2 ); - mpi_free( &G ); mpi_free( &TB ); mpi_free( &TV ); - mpi_free( &V1 ); mpi_free( &V2 ); - - return( ret ); -} - -#if defined(POLARSSL_GENPRIME) - -static const int small_prime[] = -{ - 3, 5, 7, 11, 13, 17, 19, 23, - 29, 31, 37, 41, 43, 47, 53, 59, - 61, 67, 71, 73, 79, 83, 89, 97, - 101, 103, 107, 109, 113, 127, 131, 137, - 139, 149, 151, 157, 163, 167, 173, 179, - 181, 191, 193, 197, 199, 211, 223, 227, - 229, 233, 239, 241, 251, 257, 263, 269, - 271, 277, 281, 283, 293, 307, 311, 313, - 317, 331, 337, 347, 349, 353, 359, 367, - 373, 379, 383, 389, 397, 401, 409, 419, - 421, 431, 433, 439, 443, 449, 457, 461, - 463, 467, 479, 487, 491, 499, 503, 509, - 521, 523, 541, 547, 557, 563, 569, 571, - 577, 587, 593, 599, 601, 607, 613, 617, - 619, 631, 641, 643, 647, 653, 659, 661, - 673, 677, 683, 691, 701, 709, 719, 727, - 733, 739, 743, 751, 757, 761, 769, 773, - 787, 797, 809, 811, 821, 823, 827, 829, - 839, 853, 857, 859, 863, 877, 881, 883, - 887, 907, 911, 919, 929, 937, 941, 947, - 953, 967, 971, 977, 983, 991, 997, -103 -}; - -/* - * Miller-Rabin primality test (HAC 4.24) - */ -int mpi_is_prime( mpi *X, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng ) -{ - int ret, xs; - size_t i, j, n, s; - mpi W, R, T, A, RR; - - if( mpi_cmp_int( X, 0 ) == 0 || - mpi_cmp_int( X, 1 ) == 0 ) - return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE ); - - if( mpi_cmp_int( X, 2 ) == 0 ) - return( 0 ); - - mpi_init( &W ); mpi_init( &R ); mpi_init( &T ); mpi_init( &A ); - mpi_init( &RR ); - - xs = X->s; X->s = 1; - - /* - * test trivial factors first - */ - if( ( X->p[0] & 1 ) == 0 ) - return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE ); - - for( i = 0; small_prime[i] > 0; i++ ) - { - t_uint r; - - if( mpi_cmp_int( X, small_prime[i] ) <= 0 ) - return( 0 ); - - MPI_CHK( mpi_mod_int( &r, X, small_prime[i] ) ); - - if( r == 0 ) - return( POLARSSL_ERR_MPI_NOT_ACCEPTABLE ); - } - - /* - * W = |X| - 1 - * R = W >> lsb( W ) - */ - MPI_CHK( mpi_sub_int( &W, X, 1 ) ); - s = mpi_lsb( &W ); - MPI_CHK( mpi_copy( &R, &W ) ); - MPI_CHK( mpi_shift_r( &R, s ) ); - - i = mpi_msb( X ); - /* - * HAC, table 4.4 - */ - n = ( ( i >= 1300 ) ? 2 : ( i >= 850 ) ? 3 : - ( i >= 650 ) ? 4 : ( i >= 350 ) ? 8 : - ( i >= 250 ) ? 12 : ( i >= 150 ) ? 18 : 27 ); - - for( i = 0; i < n; i++ ) - { - /* - * pick a random A, 1 < A < |X| - 1 - */ - MPI_CHK( mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) ); - - if( mpi_cmp_mpi( &A, &W ) >= 0 ) - { - j = mpi_msb( &A ) - mpi_msb( &W ); - MPI_CHK( mpi_shift_r( &A, j + 1 ) ); - } - A.p[0] |= 3; - - /* - * A = A^R mod |X| - */ - MPI_CHK( mpi_exp_mod( &A, &A, &R, X, &RR ) ); - - if( mpi_cmp_mpi( &A, &W ) == 0 || - mpi_cmp_int( &A, 1 ) == 0 ) - continue; - - j = 1; - while( j < s && mpi_cmp_mpi( &A, &W ) != 0 ) - { - /* - * A = A * A mod |X| - */ - MPI_CHK( mpi_mul_mpi( &T, &A, &A ) ); - MPI_CHK( mpi_mod_mpi( &A, &T, X ) ); - - if( mpi_cmp_int( &A, 1 ) == 0 ) - break; - - j++; - } - - /* - * not prime if A != |X| - 1 or A == 1 - */ - if( mpi_cmp_mpi( &A, &W ) != 0 || - mpi_cmp_int( &A, 1 ) == 0 ) - { - ret = POLARSSL_ERR_MPI_NOT_ACCEPTABLE; - break; - } - } - -cleanup: - - X->s = xs; - - mpi_free( &W ); mpi_free( &R ); mpi_free( &T ); mpi_free( &A ); - mpi_free( &RR ); - - return( ret ); -} - -/* - * Prime number generation - */ -int mpi_gen_prime( mpi *X, size_t nbits, int dh_flag, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng ) -{ - int ret; - size_t k, n; - mpi Y; - - if( nbits < 3 || nbits > POLARSSL_MPI_MAX_BITS ) - return( POLARSSL_ERR_MPI_BAD_INPUT_DATA ); - - mpi_init( &Y ); - - n = BITS_TO_LIMBS( nbits ); - - MPI_CHK( mpi_fill_random( X, n * ciL, f_rng, p_rng ) ); - - k = mpi_msb( X ); - if( k < nbits ) MPI_CHK( mpi_shift_l( X, nbits - k ) ); - if( k > nbits ) MPI_CHK( mpi_shift_r( X, k - nbits ) ); - - X->p[0] |= 3; - - if( dh_flag == 0 ) - { - while( ( ret = mpi_is_prime( X, f_rng, p_rng ) ) != 0 ) - { - if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE ) - goto cleanup; - - MPI_CHK( mpi_add_int( X, X, 2 ) ); - } - } - else - { - MPI_CHK( mpi_sub_int( &Y, X, 1 ) ); - MPI_CHK( mpi_shift_r( &Y, 1 ) ); - - while( 1 ) - { - if( ( ret = mpi_is_prime( X, f_rng, p_rng ) ) == 0 ) - { - if( ( ret = mpi_is_prime( &Y, f_rng, p_rng ) ) == 0 ) - break; - - if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE ) - goto cleanup; - } - - if( ret != POLARSSL_ERR_MPI_NOT_ACCEPTABLE ) - goto cleanup; - - MPI_CHK( mpi_add_int( &Y, X, 1 ) ); - MPI_CHK( mpi_add_int( X, X, 2 ) ); - MPI_CHK( mpi_shift_r( &Y, 1 ) ); - } - } - -cleanup: - - mpi_free( &Y ); - - return( ret ); -} - -#endif - -#if defined(POLARSSL_SELF_TEST) - -#define GCD_PAIR_COUNT 3 - -static const int gcd_pairs[GCD_PAIR_COUNT][3] = -{ - { 693, 609, 21 }, - { 1764, 868, 28 }, - { 768454923, 542167814, 1 } -}; - -/* - * Checkup routine - */ -int mpi_self_test( int verbose ) -{ - int ret, i; - mpi A, E, N, X, Y, U, V; - - mpi_init( &A ); mpi_init( &E ); mpi_init( &N ); mpi_init( &X ); - mpi_init( &Y ); mpi_init( &U ); mpi_init( &V ); - - MPI_CHK( mpi_read_string( &A, 16, - "EFE021C2645FD1DC586E69184AF4A31E" \ - "D5F53E93B5F123FA41680867BA110131" \ - "944FE7952E2517337780CB0DB80E61AA" \ - "E7C8DDC6C5C6AADEB34EB38A2F40D5E6" ) ); - - MPI_CHK( mpi_read_string( &E, 16, - "B2E7EFD37075B9F03FF989C7C5051C20" \ - "34D2A323810251127E7BF8625A4F49A5" \ - "F3E27F4DA8BD59C47D6DAABA4C8127BD" \ - "5B5C25763222FEFCCFC38B832366C29E" ) ); - - MPI_CHK( mpi_read_string( &N, 16, - "0066A198186C18C10B2F5ED9B522752A" \ - "9830B69916E535C8F047518A889A43A5" \ - "94B6BED27A168D31D4A52F88925AA8F5" ) ); - - MPI_CHK( mpi_mul_mpi( &X, &A, &N ) ); - - MPI_CHK( mpi_read_string( &U, 16, - "602AB7ECA597A3D6B56FF9829A5E8B85" \ - "9E857EA95A03512E2BAE7391688D264A" \ - "A5663B0341DB9CCFD2C4C5F421FEC814" \ - "8001B72E848A38CAE1C65F78E56ABDEF" \ - "E12D3C039B8A02D6BE593F0BBBDA56F1" \ - "ECF677152EF804370C1A305CAF3B5BF1" \ - "30879B56C61DE584A0F53A2447A51E" ) ); - - if( verbose != 0 ) - printf( " MPI test #1 (mul_mpi): " ); - - if( mpi_cmp_mpi( &X, &U ) != 0 ) - { - if( verbose != 0 ) - printf( "failed\n" ); - - return( 1 ); - } - - if( verbose != 0 ) - printf( "passed\n" ); - - MPI_CHK( mpi_div_mpi( &X, &Y, &A, &N ) ); - - MPI_CHK( mpi_read_string( &U, 16, - "256567336059E52CAE22925474705F39A94" ) ); - - MPI_CHK( mpi_read_string( &V, 16, - "6613F26162223DF488E9CD48CC132C7A" \ - "0AC93C701B001B092E4E5B9F73BCD27B" \ - "9EE50D0657C77F374E903CDFA4C642" ) ); - - if( verbose != 0 ) - printf( " MPI test #2 (div_mpi): " ); - - if( mpi_cmp_mpi( &X, &U ) != 0 || - mpi_cmp_mpi( &Y, &V ) != 0 ) - { - if( verbose != 0 ) - printf( "failed\n" ); - - return( 1 ); - } - - if( verbose != 0 ) - printf( "passed\n" ); - - MPI_CHK( mpi_exp_mod( &X, &A, &E, &N, NULL ) ); - - MPI_CHK( mpi_read_string( &U, 16, - "36E139AEA55215609D2816998ED020BB" \ - "BD96C37890F65171D948E9BC7CBAA4D9" \ - "325D24D6A3C12710F10A09FA08AB87" ) ); - - if( verbose != 0 ) - printf( " MPI test #3 (exp_mod): " ); - - if( mpi_cmp_mpi( &X, &U ) != 0 ) - { - if( verbose != 0 ) - printf( "failed\n" ); - - return( 1 ); - } - - if( verbose != 0 ) - printf( "passed\n" ); - -#if defined(POLARSSL_GENPRIME) - MPI_CHK( mpi_inv_mod( &X, &A, &N ) ); - - MPI_CHK( mpi_read_string( &U, 16, - "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \ - "C3DBA76456363A10869622EAC2DD84EC" \ - "C5B8A74DAC4D09E03B5E0BE779F2DF61" ) ); - - if( verbose != 0 ) - printf( " MPI test #4 (inv_mod): " ); - - if( mpi_cmp_mpi( &X, &U ) != 0 ) - { - if( verbose != 0 ) - printf( "failed\n" ); - - return( 1 ); - } - - if( verbose != 0 ) - printf( "passed\n" ); -#endif - - if( verbose != 0 ) - printf( " MPI test #5 (simple gcd): " ); - - for ( i = 0; i < GCD_PAIR_COUNT; i++) - { - MPI_CHK( mpi_lset( &X, gcd_pairs[i][0] ) ); - MPI_CHK( mpi_lset( &Y, gcd_pairs[i][1] ) ); - - MPI_CHK( mpi_gcd( &A, &X, &Y ) ); - - if( mpi_cmp_int( &A, gcd_pairs[i][2] ) != 0 ) - { - if( verbose != 0 ) - printf( "failed at %d\n", i ); - - return( 1 ); - } - } - - if( verbose != 0 ) - printf( "passed\n" ); - -cleanup: - - if( ret != 0 && verbose != 0 ) - printf( "Unexpected error, return code = %08X\n", ret ); - - mpi_free( &A ); mpi_free( &E ); mpi_free( &N ); mpi_free( &X ); - mpi_free( &Y ); mpi_free( &U ); mpi_free( &V ); - - if( verbose != 0 ) - printf( "\n" ); - - return( ret ); -} - -#endif - -#endif diff --git a/common/polarssl/bignum.h b/common/polarssl/bignum.h deleted file mode 100644 index 5eaf1a57..00000000 --- a/common/polarssl/bignum.h +++ /dev/null @@ -1,685 +0,0 @@ -/** - * \file bignum.h - * - * \brief Multi-precision integer library - * - * Copyright (C) 2006-2013, Brainspark B.V. - * - * This file is part of PolarSSL (http://www.polarssl.org) - * Lead Maintainer: Paul Bakker - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -#ifndef POLARSSL_BIGNUM_H -#define POLARSSL_BIGNUM_H - -#include -#include - -#include "polarssl_config.h" - -#ifdef _MSC_VER -#include -#if (_MSC_VER <= 1200) -typedef signed short int16_t; -typedef unsigned short uint16_t; -#else -typedef INT16 int16_t; -typedef UINT16 uint16_t; -#endif -typedef INT32 int32_t; -typedef INT64 int64_t; -typedef UINT32 uint32_t; -typedef UINT64 uint64_t; -#else -#include -#endif - -#define POLARSSL_ERR_MPI_FILE_IO_ERROR -0x0002 /**< An error occurred while reading from or writing to a file. */ -#define POLARSSL_ERR_MPI_BAD_INPUT_DATA -0x0004 /**< Bad input parameters to function. */ -#define POLARSSL_ERR_MPI_INVALID_CHARACTER -0x0006 /**< There is an invalid character in the digit string. */ -#define POLARSSL_ERR_MPI_BUFFER_TOO_SMALL -0x0008 /**< The buffer is too small to write to. */ -#define POLARSSL_ERR_MPI_NEGATIVE_VALUE -0x000A /**< The input arguments are negative or result in illegal output. */ -#define POLARSSL_ERR_MPI_DIVISION_BY_ZERO -0x000C /**< The input argument for division is zero, which is not allowed. */ -#define POLARSSL_ERR_MPI_NOT_ACCEPTABLE -0x000E /**< The input arguments are not acceptable. */ -#define POLARSSL_ERR_MPI_MALLOC_FAILED -0x0010 /**< Memory allocation failed. */ - -#define MPI_CHK(f) if( ( ret = f ) != 0 ) goto cleanup - -/* - * Maximum size MPIs are allowed to grow to in number of limbs. - */ -#define POLARSSL_MPI_MAX_LIMBS 10000 - -#if !defined(POLARSSL_CONFIG_OPTIONS) -/* - * Maximum window size used for modular exponentiation. Default: 6 - * Minimum value: 1. Maximum value: 6. - * - * Result is an array of ( 2 << POLARSSL_MPI_WINDOW_SIZE ) MPIs used - * for the sliding window calculation. (So 64 by default) - * - * Reduction in size, reduces speed. - */ -#define POLARSSL_MPI_WINDOW_SIZE 6 /**< Maximum windows size used. */ - -/* - * Maximum size of MPIs allowed in bits and bytes for user-MPIs. - * ( Default: 512 bytes => 4096 bits, Maximum tested: 2048 bytes => 16384 bits ) - * - * Note: Calculations can results temporarily in larger MPIs. So the number - * of limbs required (POLARSSL_MPI_MAX_LIMBS) is higher. - */ -#define POLARSSL_MPI_MAX_SIZE 512 /**< Maximum number of bytes for usable MPIs. */ - -#endif /* !POLARSSL_CONFIG_OPTIONS */ - -#define POLARSSL_MPI_MAX_BITS ( 8 * POLARSSL_MPI_MAX_SIZE ) /**< Maximum number of bits for usable MPIs. */ - -/* - * When reading from files with mpi_read_file() and writing to files with - * mpi_write_file() the buffer should have space - * for a (short) label, the MPI (in the provided radix), the newline - * characters and the '\0'. - * - * By default we assume at least a 10 char label, a minimum radix of 10 - * (decimal) and a maximum of 4096 bit numbers (1234 decimal chars). - * Autosized at compile time for at least a 10 char label, a minimum radix - * of 10 (decimal) for a number of POLARSSL_MPI_MAX_BITS size. - * - * This used to be statically sized to 1250 for a maximum of 4096 bit - * numbers (1234 decimal chars). - * - * Calculate using the formula: - * POLARSSL_MPI_RW_BUFFER_SIZE = ceil(POLARSSL_MPI_MAX_BITS / ln(10) * ln(2)) + - * LabelSize + 6 - */ -#define POLARSSL_MPI_MAX_BITS_SCALE100 ( 100 * POLARSSL_MPI_MAX_BITS ) -#define LN_2_DIV_LN_10_SCALE100 332 -#define POLARSSL_MPI_RW_BUFFER_SIZE ( ((POLARSSL_MPI_MAX_BITS_SCALE100 + LN_2_DIV_LN_10_SCALE100 - 1) / LN_2_DIV_LN_10_SCALE100) + 10 + 6 ) - -/* - * Define the base integer type, architecture-wise - */ -#if defined(POLARSSL_HAVE_INT8) -typedef signed char t_sint; -typedef unsigned char t_uint; -typedef uint16_t t_udbl; -#define POLARSSL_HAVE_UDBL -#else -#if defined(POLARSSL_HAVE_INT16) -typedef int16_t t_sint; -typedef uint16_t t_uint; -typedef uint32_t t_udbl; -#define POLARSSL_HAVE_UDBL -#else - #if ( defined(_MSC_VER) && defined(_M_AMD64) ) - typedef int64_t t_sint; - typedef uint64_t t_uint; - #else - #if ( defined(__GNUC__) && ( \ - defined(__amd64__) || defined(__x86_64__) || \ - defined(__ppc64__) || defined(__powerpc64__) || \ - defined(__ia64__) || defined(__alpha__) || \ - (defined(__sparc__) && defined(__arch64__)) || \ - defined(__s390x__) ) ) - typedef int64_t t_sint; - typedef uint64_t t_uint; - typedef unsigned int t_udbl __attribute__((mode(TI))); - #define POLARSSL_HAVE_UDBL - #else - typedef int32_t t_sint; - typedef uint32_t t_uint; - #if ( defined(_MSC_VER) && defined(_M_IX86) ) - typedef uint64_t t_udbl; - #define POLARSSL_HAVE_UDBL - #else - #if defined( POLARSSL_HAVE_LONGLONG ) - typedef unsigned long long t_udbl; - #define POLARSSL_HAVE_UDBL - #endif - #endif - #endif - #endif -#endif /* POLARSSL_HAVE_INT16 */ -#endif /* POLARSSL_HAVE_INT8 */ - -/** - * \brief MPI structure - */ -typedef struct -{ - int s; /*!< integer sign */ - size_t n; /*!< total # of limbs */ - t_uint *p; /*!< pointer to limbs */ -} -mpi; - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief Initialize one MPI - * - * \param X One MPI to initialize. - */ -void mpi_init( mpi *X ); - -/** - * \brief Unallocate one MPI - * - * \param X One MPI to unallocate. - */ -void mpi_free( mpi *X ); - -/** - * \brief Enlarge to the specified number of limbs - * - * \param X MPI to grow - * \param nblimbs The target number of limbs - * - * \return 0 if successful, - * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed - */ -int mpi_grow( mpi *X, size_t nblimbs ); - -/** - * \brief Copy the contents of Y into X - * - * \param X Destination MPI - * \param Y Source MPI - * - * \return 0 if successful, - * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed - */ -int mpi_copy( mpi *X, const mpi *Y ); - -/** - * \brief Swap the contents of X and Y - * - * \param X First MPI value - * \param Y Second MPI value - */ -void mpi_swap( mpi *X, mpi *Y ); - -/** - * \brief Set value from integer - * - * \param X MPI to set - * \param z Value to use - * - * \return 0 if successful, - * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed - */ -int mpi_lset( mpi *X, t_sint z ); - -/** - * \brief Get a specific bit from X - * - * \param X MPI to use - * \param pos Zero-based index of the bit in X - * - * \return Either a 0 or a 1 - */ -int mpi_get_bit( const mpi *X, size_t pos ); - -/** - * \brief Set a bit of X to a specific value of 0 or 1 - * - * \note Will grow X if necessary to set a bit to 1 in a not yet - * existing limb. Will not grow if bit should be set to 0 - * - * \param X MPI to use - * \param pos Zero-based index of the bit in X - * \param val The value to set the bit to (0 or 1) - * - * \return 0 if successful, - * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, - * POLARSSL_ERR_MPI_BAD_INPUT_DATA if val is not 0 or 1 - */ -int mpi_set_bit( mpi *X, size_t pos, unsigned char val ); - -/** - * \brief Return the number of zero-bits before the least significant - * '1' bit - * - * Note: Thus also the zero-based index of the least significant '1' bit - * - * \param X MPI to use - */ -size_t mpi_lsb( const mpi *X ); - -/** - * \brief Return the number of bits up to and including the most - * significant '1' bit' - * - * Note: Thus also the one-based index of the most significant '1' bit - * - * \param X MPI to use - */ -size_t mpi_msb( const mpi *X ); - -/** - * \brief Return the total size in bytes - * - * \param X MPI to use - */ -size_t mpi_size( const mpi *X ); - -/** - * \brief Import from an ASCII string - * - * \param X Destination MPI - * \param radix Input numeric base - * \param s Null-terminated string buffer - * - * \return 0 if successful, or a POLARSSL_ERR_MPI_XXX error code - */ -int mpi_read_string( mpi *X, int radix, const char *s ); - -/** - * \brief Export into an ASCII string - * - * \param X Source MPI - * \param radix Output numeric base - * \param s String buffer - * \param slen String buffer size - * - * \return 0 if successful, or a POLARSSL_ERR_MPI_XXX error code. - * *slen is always updated to reflect the amount - * of data that has (or would have) been written. - * - * \note Call this function with *slen = 0 to obtain the - * minimum required buffer size in *slen. - */ -int mpi_write_string( const mpi *X, int radix, char *s, size_t *slen ); - -#if defined(POLARSSL_FS_IO) -/** - * \brief Read X from an opened file - * - * \param X Destination MPI - * \param radix Input numeric base - * \param fin Input file handle - * - * \return 0 if successful, POLARSSL_ERR_MPI_BUFFER_TOO_SMALL if - * the file read buffer is too small or a - * POLARSSL_ERR_MPI_XXX error code - */ -int mpi_read_file( mpi *X, int radix, FILE *fin ); - -/** - * \brief Write X into an opened file, or stdout if fout is NULL - * - * \param p Prefix, can be NULL - * \param X Source MPI - * \param radix Output numeric base - * \param fout Output file handle (can be NULL) - * - * \return 0 if successful, or a POLARSSL_ERR_MPI_XXX error code - * - * \note Set fout == NULL to print X on the console. - */ -int mpi_write_file( const char *p, const mpi *X, int radix, FILE *fout ); -#endif /* POLARSSL_FS_IO */ - -/** - * \brief Import X from unsigned binary data, big endian - * - * \param X Destination MPI - * \param buf Input buffer - * \param buflen Input buffer size - * - * \return 0 if successful, - * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed - */ -int mpi_read_binary( mpi *X, const unsigned char *buf, size_t buflen ); - -/** - * \brief Export X into unsigned binary data, big endian - * - * \param X Source MPI - * \param buf Output buffer - * \param buflen Output buffer size - * - * \return 0 if successful, - * POLARSSL_ERR_MPI_BUFFER_TOO_SMALL if buf isn't large enough - */ -int mpi_write_binary( const mpi *X, unsigned char *buf, size_t buflen ); - -/** - * \brief Left-shift: X <<= count - * - * \param X MPI to shift - * \param count Amount to shift - * - * \return 0 if successful, - * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed - */ -int mpi_shift_l( mpi *X, size_t count ); - -/** - * \brief Right-shift: X >>= count - * - * \param X MPI to shift - * \param count Amount to shift - * - * \return 0 if successful, - * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed - */ -int mpi_shift_r( mpi *X, size_t count ); - -/** - * \brief Compare unsigned values - * - * \param X Left-hand MPI - * \param Y Right-hand MPI - * - * \return 1 if |X| is greater than |Y|, - * -1 if |X| is lesser than |Y| or - * 0 if |X| is equal to |Y| - */ -int mpi_cmp_abs( const mpi *X, const mpi *Y ); - -/** - * \brief Compare signed values - * - * \param X Left-hand MPI - * \param Y Right-hand MPI - * - * \return 1 if X is greater than Y, - * -1 if X is lesser than Y or - * 0 if X is equal to Y - */ -int mpi_cmp_mpi( const mpi *X, const mpi *Y ); - -/** - * \brief Compare signed values - * - * \param X Left-hand MPI - * \param z The integer value to compare to - * - * \return 1 if X is greater than z, - * -1 if X is lesser than z or - * 0 if X is equal to z - */ -int mpi_cmp_int( const mpi *X, t_sint z ); - -/** - * \brief Unsigned addition: X = |A| + |B| - * - * \param X Destination MPI - * \param A Left-hand MPI - * \param B Right-hand MPI - * - * \return 0 if successful, - * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed - */ -int mpi_add_abs( mpi *X, const mpi *A, const mpi *B ); - -/** - * \brief Unsigned substraction: X = |A| - |B| - * - * \param X Destination MPI - * \param A Left-hand MPI - * \param B Right-hand MPI - * - * \return 0 if successful, - * POLARSSL_ERR_MPI_NEGATIVE_VALUE if B is greater than A - */ -int mpi_sub_abs( mpi *X, const mpi *A, const mpi *B ); - -/** - * \brief Signed addition: X = A + B - * - * \param X Destination MPI - * \param A Left-hand MPI - * \param B Right-hand MPI - * - * \return 0 if successful, - * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed - */ -int mpi_add_mpi( mpi *X, const mpi *A, const mpi *B ); - -/** - * \brief Signed substraction: X = A - B - * - * \param X Destination MPI - * \param A Left-hand MPI - * \param B Right-hand MPI - * - * \return 0 if successful, - * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed - */ -int mpi_sub_mpi( mpi *X, const mpi *A, const mpi *B ); - -/** - * \brief Signed addition: X = A + b - * - * \param X Destination MPI - * \param A Left-hand MPI - * \param b The integer value to add - * - * \return 0 if successful, - * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed - */ -int mpi_add_int( mpi *X, const mpi *A, t_sint b ); - -/** - * \brief Signed substraction: X = A - b - * - * \param X Destination MPI - * \param A Left-hand MPI - * \param b The integer value to subtract - * - * \return 0 if successful, - * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed - */ -int mpi_sub_int( mpi *X, const mpi *A, t_sint b ); - -/** - * \brief Baseline multiplication: X = A * B - * - * \param X Destination MPI - * \param A Left-hand MPI - * \param B Right-hand MPI - * - * \return 0 if successful, - * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed - */ -int mpi_mul_mpi( mpi *X, const mpi *A, const mpi *B ); - -/** - * \brief Baseline multiplication: X = A * b - * Note: b is an unsigned integer type, thus - * Negative values of b are ignored. - * - * \param X Destination MPI - * \param A Left-hand MPI - * \param b The integer value to multiply with - * - * \return 0 if successful, - * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed - */ -int mpi_mul_int( mpi *X, const mpi *A, t_sint b ); - -/** - * \brief Division by mpi: A = Q * B + R - * - * \param Q Destination MPI for the quotient - * \param R Destination MPI for the rest value - * \param A Left-hand MPI - * \param B Right-hand MPI - * - * \return 0 if successful, - * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, - * POLARSSL_ERR_MPI_DIVISION_BY_ZERO if B == 0 - * - * \note Either Q or R can be NULL. - */ -int mpi_div_mpi( mpi *Q, mpi *R, const mpi *A, const mpi *B ); - -/** - * \brief Division by int: A = Q * b + R - * - * \param Q Destination MPI for the quotient - * \param R Destination MPI for the rest value - * \param A Left-hand MPI - * \param b Integer to divide by - * - * \return 0 if successful, - * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, - * POLARSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0 - * - * \note Either Q or R can be NULL. - */ -int mpi_div_int( mpi *Q, mpi *R, const mpi *A, t_sint b ); - -/** - * \brief Modulo: R = A mod B - * - * \param R Destination MPI for the rest value - * \param A Left-hand MPI - * \param B Right-hand MPI - * - * \return 0 if successful, - * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, - * POLARSSL_ERR_MPI_DIVISION_BY_ZERO if B == 0, - * POLARSSL_ERR_MPI_NEGATIVE_VALUE if B < 0 - */ -int mpi_mod_mpi( mpi *R, const mpi *A, const mpi *B ); - -/** - * \brief Modulo: r = A mod b - * - * \param r Destination t_uint - * \param A Left-hand MPI - * \param b Integer to divide by - * - * \return 0 if successful, - * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, - * POLARSSL_ERR_MPI_DIVISION_BY_ZERO if b == 0, - * POLARSSL_ERR_MPI_NEGATIVE_VALUE if b < 0 - */ -int mpi_mod_int( t_uint *r, const mpi *A, t_sint b ); - -/** - * \brief Sliding-window exponentiation: X = A^E mod N - * - * \param X Destination MPI - * \param A Left-hand MPI - * \param E Exponent MPI - * \param N Modular MPI - * \param _RR Speed-up MPI used for recalculations - * - * \return 0 if successful, - * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, - * POLARSSL_ERR_MPI_BAD_INPUT_DATA if N is negative or even or if - * E is negative - * - * \note _RR is used to avoid re-computing R*R mod N across - * multiple calls, which speeds up things a bit. It can - * be set to NULL if the extra performance is unneeded. - */ -int mpi_exp_mod( mpi *X, const mpi *A, const mpi *E, const mpi *N, mpi *_RR ); - -/** - * \brief Fill an MPI X with size bytes of random - * - * \param X Destination MPI - * \param size Size in bytes - * \param f_rng RNG function - * \param p_rng RNG parameter - * - * \return 0 if successful, - * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed - */ -int mpi_fill_random( mpi *X, size_t size, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng ); - -/** - * \brief Greatest common divisor: G = gcd(A, B) - * - * \param G Destination MPI - * \param A Left-hand MPI - * \param B Right-hand MPI - * - * \return 0 if successful, - * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed - */ -int mpi_gcd( mpi *G, const mpi *A, const mpi *B ); - -/** - * \brief Modular inverse: X = A^-1 mod N - * - * \param X Destination MPI - * \param A Left-hand MPI - * \param N Right-hand MPI - * - * \return 0 if successful, - * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, - * POLARSSL_ERR_MPI_BAD_INPUT_DATA if N is negative or nil - POLARSSL_ERR_MPI_NOT_ACCEPTABLE if A has no inverse mod N - */ -int mpi_inv_mod( mpi *X, const mpi *A, const mpi *N ); - -/** - * \brief Miller-Rabin primality test - * - * \param X MPI to check - * \param f_rng RNG function - * \param p_rng RNG parameter - * - * \return 0 if successful (probably prime), - * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, - * POLARSSL_ERR_MPI_NOT_ACCEPTABLE if X is not prime - */ -int mpi_is_prime( mpi *X, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng ); - -/** - * \brief Prime number generation - * - * \param X Destination MPI - * \param nbits Required size of X in bits ( 3 <= nbits <= POLARSSL_MPI_MAX_BITS ) - * \param dh_flag If 1, then (X-1)/2 will be prime too - * \param f_rng RNG function - * \param p_rng RNG parameter - * - * \return 0 if successful (probably prime), - * POLARSSL_ERR_MPI_MALLOC_FAILED if memory allocation failed, - * POLARSSL_ERR_MPI_BAD_INPUT_DATA if nbits is < 3 - */ -int mpi_gen_prime( mpi *X, size_t nbits, int dh_flag, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng ); - -/** - * \brief Checkup routine - * - * \return 0 if successful, or 1 if the test failed - */ -int mpi_self_test( int verbose ); - -#ifdef __cplusplus -} -#endif - -#endif /* bignum.h */ diff --git a/common/polarssl/bn_mul.h b/common/polarssl/bn_mul.h deleted file mode 100644 index 1c2da136..00000000 --- a/common/polarssl/bn_mul.h +++ /dev/null @@ -1,864 +0,0 @@ -/** - * \file bn_mul.h - * - * \brief Multi-precision integer library - * - * Copyright (C) 2006-2010, Brainspark B.V. - * - * This file is part of PolarSSL (http://www.polarssl.org) - * Lead Maintainer: Paul Bakker - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/* - * Multiply source vector [s] with b, add result - * to destination vector [d] and set carry c. - * - * Currently supports: - * - * . IA-32 (386+) . AMD64 / EM64T - * . IA-32 (SSE2) . Motorola 68000 - * . PowerPC, 32-bit . MicroBlaze - * . PowerPC, 64-bit . TriCore - * . SPARC v8 . ARM v3+ - * . Alpha . MIPS32 - * . C, longlong . C, generic - */ -#ifndef POLARSSL_BN_MUL_H -#define POLARSSL_BN_MUL_H - -#include "bignum.h" - -#if defined(POLARSSL_HAVE_ASM) - -#if defined(__GNUC__) -#if defined(__i386__) - -#define MULADDC_INIT \ - asm( " \ - movl %%ebx, %0; \ - movl %5, %%esi; \ - movl %6, %%edi; \ - movl %7, %%ecx; \ - movl %8, %%ebx; \ - " - -#define MULADDC_CORE \ - " \ - lodsl; \ - mull %%ebx; \ - addl %%ecx, %%eax; \ - adcl $0, %%edx; \ - addl (%%edi), %%eax; \ - adcl $0, %%edx; \ - movl %%edx, %%ecx; \ - stosl; \ - " - -#if defined(POLARSSL_HAVE_SSE2) - -#define MULADDC_HUIT \ - " \ - movd %%ecx, %%mm1; \ - movd %%ebx, %%mm0; \ - movd (%%edi), %%mm3; \ - paddq %%mm3, %%mm1; \ - movd (%%esi), %%mm2; \ - pmuludq %%mm0, %%mm2; \ - movd 4(%%esi), %%mm4; \ - pmuludq %%mm0, %%mm4; \ - movd 8(%%esi), %%mm6; \ - pmuludq %%mm0, %%mm6; \ - movd 12(%%esi), %%mm7; \ - pmuludq %%mm0, %%mm7; \ - paddq %%mm2, %%mm1; \ - movd 4(%%edi), %%mm3; \ - paddq %%mm4, %%mm3; \ - movd 8(%%edi), %%mm5; \ - paddq %%mm6, %%mm5; \ - movd 12(%%edi), %%mm4; \ - paddq %%mm4, %%mm7; \ - movd %%mm1, (%%edi); \ - movd 16(%%esi), %%mm2; \ - pmuludq %%mm0, %%mm2; \ - psrlq $32, %%mm1; \ - movd 20(%%esi), %%mm4; \ - pmuludq %%mm0, %%mm4; \ - paddq %%mm3, %%mm1; \ - movd 24(%%esi), %%mm6; \ - pmuludq %%mm0, %%mm6; \ - movd %%mm1, 4(%%edi); \ - psrlq $32, %%mm1; \ - movd 28(%%esi), %%mm3; \ - pmuludq %%mm0, %%mm3; \ - paddq %%mm5, %%mm1; \ - movd 16(%%edi), %%mm5; \ - paddq %%mm5, %%mm2; \ - movd %%mm1, 8(%%edi); \ - psrlq $32, %%mm1; \ - paddq %%mm7, %%mm1; \ - movd 20(%%edi), %%mm5; \ - paddq %%mm5, %%mm4; \ - movd %%mm1, 12(%%edi); \ - psrlq $32, %%mm1; \ - paddq %%mm2, %%mm1; \ - movd 24(%%edi), %%mm5; \ - paddq %%mm5, %%mm6; \ - movd %%mm1, 16(%%edi); \ - psrlq $32, %%mm1; \ - paddq %%mm4, %%mm1; \ - movd 28(%%edi), %%mm5; \ - paddq %%mm5, %%mm3; \ - movd %%mm1, 20(%%edi); \ - psrlq $32, %%mm1; \ - paddq %%mm6, %%mm1; \ - movd %%mm1, 24(%%edi); \ - psrlq $32, %%mm1; \ - paddq %%mm3, %%mm1; \ - movd %%mm1, 28(%%edi); \ - addl $32, %%edi; \ - addl $32, %%esi; \ - psrlq $32, %%mm1; \ - movd %%mm1, %%ecx; \ - " - -#define MULADDC_STOP \ - " \ - emms; \ - movl %4, %%ebx; \ - movl %%ecx, %1; \ - movl %%edi, %2; \ - movl %%esi, %3; \ - " \ - : "=m" (t), "=m" (c), "=m" (d), "=m" (s) \ - : "m" (t), "m" (s), "m" (d), "m" (c), "m" (b) \ - : "eax", "ecx", "edx", "esi", "edi" \ - ); - -#else - -#define MULADDC_STOP \ - " \ - movl %4, %%ebx; \ - movl %%ecx, %1; \ - movl %%edi, %2; \ - movl %%esi, %3; \ - " \ - : "=m" (t), "=m" (c), "=m" (d), "=m" (s) \ - : "m" (t), "m" (s), "m" (d), "m" (c), "m" (b) \ - : "eax", "ecx", "edx", "esi", "edi" \ - ); -#endif /* SSE2 */ -#endif /* i386 */ - -#if defined(__amd64__) || defined (__x86_64__) - -#define MULADDC_INIT \ - asm( "movq %0, %%rsi " :: "m" (s)); \ - asm( "movq %0, %%rdi " :: "m" (d)); \ - asm( "movq %0, %%rcx " :: "m" (c)); \ - asm( "movq %0, %%rbx " :: "m" (b)); \ - asm( "xorq %r8, %r8 " ); - -#define MULADDC_CORE \ - asm( "movq (%rsi),%rax " ); \ - asm( "mulq %rbx " ); \ - asm( "addq $8, %rsi " ); \ - asm( "addq %rcx, %rax " ); \ - asm( "movq %r8, %rcx " ); \ - asm( "adcq $0, %rdx " ); \ - asm( "nop " ); \ - asm( "addq %rax, (%rdi) " ); \ - asm( "adcq %rdx, %rcx " ); \ - asm( "addq $8, %rdi " ); - -#define MULADDC_STOP \ - asm( "movq %%rcx, %0 " : "=m" (c)); \ - asm( "movq %%rdi, %0 " : "=m" (d)); \ - asm( "movq %%rsi, %0 " : "=m" (s) :: \ - "rax", "rcx", "rdx", "rbx", "rsi", "rdi", "r8" ); - -#endif /* AMD64 */ - -#if defined(__mc68020__) || defined(__mcpu32__) - -#define MULADDC_INIT \ - asm( "movl %0, %%a2 " :: "m" (s)); \ - asm( "movl %0, %%a3 " :: "m" (d)); \ - asm( "movl %0, %%d3 " :: "m" (c)); \ - asm( "movl %0, %%d2 " :: "m" (b)); \ - asm( "moveq #0, %d0 " ); - -#define MULADDC_CORE \ - asm( "movel %a2@+, %d1 " ); \ - asm( "mulul %d2, %d4:%d1 " ); \ - asm( "addl %d3, %d1 " ); \ - asm( "addxl %d0, %d4 " ); \ - asm( "moveq #0, %d3 " ); \ - asm( "addl %d1, %a3@+ " ); \ - asm( "addxl %d4, %d3 " ); - -#define MULADDC_STOP \ - asm( "movl %%d3, %0 " : "=m" (c)); \ - asm( "movl %%a3, %0 " : "=m" (d)); \ - asm( "movl %%a2, %0 " : "=m" (s) :: \ - "d0", "d1", "d2", "d3", "d4", "a2", "a3" ); - -#define MULADDC_HUIT \ - asm( "movel %a2@+, %d1 " ); \ - asm( "mulul %d2, %d4:%d1 " ); \ - asm( "addxl %d3, %d1 " ); \ - asm( "addxl %d0, %d4 " ); \ - asm( "addl %d1, %a3@+ " ); \ - asm( "movel %a2@+, %d1 " ); \ - asm( "mulul %d2, %d3:%d1 " ); \ - asm( "addxl %d4, %d1 " ); \ - asm( "addxl %d0, %d3 " ); \ - asm( "addl %d1, %a3@+ " ); \ - asm( "movel %a2@+, %d1 " ); \ - asm( "mulul %d2, %d4:%d1 " ); \ - asm( "addxl %d3, %d1 " ); \ - asm( "addxl %d0, %d4 " ); \ - asm( "addl %d1, %a3@+ " ); \ - asm( "movel %a2@+, %d1 " ); \ - asm( "mulul %d2, %d3:%d1 " ); \ - asm( "addxl %d4, %d1 " ); \ - asm( "addxl %d0, %d3 " ); \ - asm( "addl %d1, %a3@+ " ); \ - asm( "movel %a2@+, %d1 " ); \ - asm( "mulul %d2, %d4:%d1 " ); \ - asm( "addxl %d3, %d1 " ); \ - asm( "addxl %d0, %d4 " ); \ - asm( "addl %d1, %a3@+ " ); \ - asm( "movel %a2@+, %d1 " ); \ - asm( "mulul %d2, %d3:%d1 " ); \ - asm( "addxl %d4, %d1 " ); \ - asm( "addxl %d0, %d3 " ); \ - asm( "addl %d1, %a3@+ " ); \ - asm( "movel %a2@+, %d1 " ); \ - asm( "mulul %d2, %d4:%d1 " ); \ - asm( "addxl %d3, %d1 " ); \ - asm( "addxl %d0, %d4 " ); \ - asm( "addl %d1, %a3@+ " ); \ - asm( "movel %a2@+, %d1 " ); \ - asm( "mulul %d2, %d3:%d1 " ); \ - asm( "addxl %d4, %d1 " ); \ - asm( "addxl %d0, %d3 " ); \ - asm( "addl %d1, %a3@+ " ); \ - asm( "addxl %d0, %d3 " ); - -#endif /* MC68000 */ - -#if defined(__powerpc__) || defined(__ppc__) -#if defined(__powerpc64__) || defined(__ppc64__) - -#if defined(__MACH__) && defined(__APPLE__) - -#define MULADDC_INIT \ - asm( "ld r3, %0 " :: "m" (s)); \ - asm( "ld r4, %0 " :: "m" (d)); \ - asm( "ld r5, %0 " :: "m" (c)); \ - asm( "ld r6, %0 " :: "m" (b)); \ - asm( "addi r3, r3, -8 " ); \ - asm( "addi r4, r4, -8 " ); \ - asm( "addic r5, r5, 0 " ); - -#define MULADDC_CORE \ - asm( "ldu r7, 8(r3) " ); \ - asm( "mulld r8, r7, r6 " ); \ - asm( "mulhdu r9, r7, r6 " ); \ - asm( "adde r8, r8, r5 " ); \ - asm( "ld r7, 8(r4) " ); \ - asm( "addze r5, r9 " ); \ - asm( "addc r8, r8, r7 " ); \ - asm( "stdu r8, 8(r4) " ); - -#define MULADDC_STOP \ - asm( "addze r5, r5 " ); \ - asm( "addi r4, r4, 8 " ); \ - asm( "addi r3, r3, 8 " ); \ - asm( "std r5, %0 " : "=m" (c)); \ - asm( "std r4, %0 " : "=m" (d)); \ - asm( "std r3, %0 " : "=m" (s) :: \ - "r3", "r4", "r5", "r6", "r7", "r8", "r9" ); - -#else - -#define MULADDC_INIT \ - asm( "ld %%r3, %0 " :: "m" (s)); \ - asm( "ld %%r4, %0 " :: "m" (d)); \ - asm( "ld %%r5, %0 " :: "m" (c)); \ - asm( "ld %%r6, %0 " :: "m" (b)); \ - asm( "addi %r3, %r3, -8 " ); \ - asm( "addi %r4, %r4, -8 " ); \ - asm( "addic %r5, %r5, 0 " ); - -#define MULADDC_CORE \ - asm( "ldu %r7, 8(%r3) " ); \ - asm( "mulld %r8, %r7, %r6 " ); \ - asm( "mulhdu %r9, %r7, %r6 " ); \ - asm( "adde %r8, %r8, %r5 " ); \ - asm( "ld %r7, 8(%r4) " ); \ - asm( "addze %r5, %r9 " ); \ - asm( "addc %r8, %r8, %r7 " ); \ - asm( "stdu %r8, 8(%r4) " ); - -#define MULADDC_STOP \ - asm( "addze %r5, %r5 " ); \ - asm( "addi %r4, %r4, 8 " ); \ - asm( "addi %r3, %r3, 8 " ); \ - asm( "std %%r5, %0 " : "=m" (c)); \ - asm( "std %%r4, %0 " : "=m" (d)); \ - asm( "std %%r3, %0 " : "=m" (s) :: \ - "r3", "r4", "r5", "r6", "r7", "r8", "r9" ); - -#endif - -#else /* PPC32 */ - -#if defined(__MACH__) && defined(__APPLE__) - -#define MULADDC_INIT \ - asm( "lwz r3, %0 " :: "m" (s)); \ - asm( "lwz r4, %0 " :: "m" (d)); \ - asm( "lwz r5, %0 " :: "m" (c)); \ - asm( "lwz r6, %0 " :: "m" (b)); \ - asm( "addi r3, r3, -4 " ); \ - asm( "addi r4, r4, -4 " ); \ - asm( "addic r5, r5, 0 " ); - -#define MULADDC_CORE \ - asm( "lwzu r7, 4(r3) " ); \ - asm( "mullw r8, r7, r6 " ); \ - asm( "mulhwu r9, r7, r6 " ); \ - asm( "adde r8, r8, r5 " ); \ - asm( "lwz r7, 4(r4) " ); \ - asm( "addze r5, r9 " ); \ - asm( "addc r8, r8, r7 " ); \ - asm( "stwu r8, 4(r4) " ); - -#define MULADDC_STOP \ - asm( "addze r5, r5 " ); \ - asm( "addi r4, r4, 4 " ); \ - asm( "addi r3, r3, 4 " ); \ - asm( "stw r5, %0 " : "=m" (c)); \ - asm( "stw r4, %0 " : "=m" (d)); \ - asm( "stw r3, %0 " : "=m" (s) :: \ - "r3", "r4", "r5", "r6", "r7", "r8", "r9" ); - -#else - -#define MULADDC_INIT \ - asm( "lwz %%r3, %0 " :: "m" (s)); \ - asm( "lwz %%r4, %0 " :: "m" (d)); \ - asm( "lwz %%r5, %0 " :: "m" (c)); \ - asm( "lwz %%r6, %0 " :: "m" (b)); \ - asm( "addi %r3, %r3, -4 " ); \ - asm( "addi %r4, %r4, -4 " ); \ - asm( "addic %r5, %r5, 0 " ); - -#define MULADDC_CORE \ - asm( "lwzu %r7, 4(%r3) " ); \ - asm( "mullw %r8, %r7, %r6 " ); \ - asm( "mulhwu %r9, %r7, %r6 " ); \ - asm( "adde %r8, %r8, %r5 " ); \ - asm( "lwz %r7, 4(%r4) " ); \ - asm( "addze %r5, %r9 " ); \ - asm( "addc %r8, %r8, %r7 " ); \ - asm( "stwu %r8, 4(%r4) " ); - -#define MULADDC_STOP \ - asm( "addze %r5, %r5 " ); \ - asm( "addi %r4, %r4, 4 " ); \ - asm( "addi %r3, %r3, 4 " ); \ - asm( "stw %%r5, %0 " : "=m" (c)); \ - asm( "stw %%r4, %0 " : "=m" (d)); \ - asm( "stw %%r3, %0 " : "=m" (s) :: \ - "r3", "r4", "r5", "r6", "r7", "r8", "r9" ); - -#endif - -#endif /* PPC32 */ -#endif /* PPC64 */ - -#if defined(__sparc__) && defined(__sparc64__) - -#define MULADDC_INIT \ - asm( \ - " \ - ldx %3, %%o0; \ - ldx %4, %%o1; \ - ld %5, %%o2; \ - ld %6, %%o3; \ - " - -#define MULADDC_CORE \ - " \ - ld [%%o0], %%o4; \ - inc 4, %%o0; \ - ld [%%o1], %%o5; \ - umul %%o3, %%o4, %%o4; \ - addcc %%o4, %%o2, %%o4; \ - rd %%y, %%g1; \ - addx %%g1, 0, %%g1; \ - addcc %%o4, %%o5, %%o4; \ - st %%o4, [%%o1]; \ - addx %%g1, 0, %%o2; \ - inc 4, %%o1; \ - " - -#define MULADDC_STOP \ - " \ - st %%o2, %0; \ - stx %%o1, %1; \ - stx %%o0, %2; \ - " \ - : "=m" (c), "=m" (d), "=m" (s) \ - : "m" (s), "m" (d), "m" (c), "m" (b) \ - : "g1", "o0", "o1", "o2", "o3", "o4", \ - "o5" \ - ); -#endif /* SPARCv9 */ - -#if defined(__sparc__) && !defined(__sparc64__) - -#define MULADDC_INIT \ - asm( \ - " \ - ld %3, %%o0; \ - ld %4, %%o1; \ - ld %5, %%o2; \ - ld %6, %%o3; \ - " - -#define MULADDC_CORE \ - " \ - ld [%%o0], %%o4; \ - inc 4, %%o0; \ - ld [%%o1], %%o5; \ - umul %%o3, %%o4, %%o4; \ - addcc %%o4, %%o2, %%o4; \ - rd %%y, %%g1; \ - addx %%g1, 0, %%g1; \ - addcc %%o4, %%o5, %%o4; \ - st %%o4, [%%o1]; \ - addx %%g1, 0, %%o2; \ - inc 4, %%o1; \ - " - -#define MULADDC_STOP \ - " \ - st %%o2, %0; \ - st %%o1, %1; \ - st %%o0, %2; \ - " \ - : "=m" (c), "=m" (d), "=m" (s) \ - : "m" (s), "m" (d), "m" (c), "m" (b) \ - : "g1", "o0", "o1", "o2", "o3", "o4", \ - "o5" \ - ); - -#endif /* SPARCv8 */ - -#if defined(__microblaze__) || defined(microblaze) - -#define MULADDC_INIT \ - asm( "lwi r3, %0 " :: "m" (s)); \ - asm( "lwi r4, %0 " :: "m" (d)); \ - asm( "lwi r5, %0 " :: "m" (c)); \ - asm( "lwi r6, %0 " :: "m" (b)); \ - asm( "andi r7, r6, 0xffff" ); \ - asm( "bsrli r6, r6, 16 " ); - -#define MULADDC_CORE \ - asm( "lhui r8, r3, 0 " ); \ - asm( "addi r3, r3, 2 " ); \ - asm( "lhui r9, r3, 0 " ); \ - asm( "addi r3, r3, 2 " ); \ - asm( "mul r10, r9, r6 " ); \ - asm( "mul r11, r8, r7 " ); \ - asm( "mul r12, r9, r7 " ); \ - asm( "mul r13, r8, r6 " ); \ - asm( "bsrli r8, r10, 16 " ); \ - asm( "bsrli r9, r11, 16 " ); \ - asm( "add r13, r13, r8 " ); \ - asm( "add r13, r13, r9 " ); \ - asm( "bslli r10, r10, 16 " ); \ - asm( "bslli r11, r11, 16 " ); \ - asm( "add r12, r12, r10 " ); \ - asm( "addc r13, r13, r0 " ); \ - asm( "add r12, r12, r11 " ); \ - asm( "addc r13, r13, r0 " ); \ - asm( "lwi r10, r4, 0 " ); \ - asm( "add r12, r12, r10 " ); \ - asm( "addc r13, r13, r0 " ); \ - asm( "add r12, r12, r5 " ); \ - asm( "addc r5, r13, r0 " ); \ - asm( "swi r12, r4, 0 " ); \ - asm( "addi r4, r4, 4 " ); - -#define MULADDC_STOP \ - asm( "swi r5, %0 " : "=m" (c)); \ - asm( "swi r4, %0 " : "=m" (d)); \ - asm( "swi r3, %0 " : "=m" (s) :: \ - "r3", "r4" , "r5" , "r6" , "r7" , "r8" , \ - "r9", "r10", "r11", "r12", "r13" ); - -#endif /* MicroBlaze */ - -#if defined(__tricore__) - -#define MULADDC_INIT \ - asm( "ld.a %%a2, %0 " :: "m" (s)); \ - asm( "ld.a %%a3, %0 " :: "m" (d)); \ - asm( "ld.w %%d4, %0 " :: "m" (c)); \ - asm( "ld.w %%d1, %0 " :: "m" (b)); \ - asm( "xor %d5, %d5 " ); - -#define MULADDC_CORE \ - asm( "ld.w %d0, [%a2+] " ); \ - asm( "madd.u %e2, %e4, %d0, %d1 " ); \ - asm( "ld.w %d0, [%a3] " ); \ - asm( "addx %d2, %d2, %d0 " ); \ - asm( "addc %d3, %d3, 0 " ); \ - asm( "mov %d4, %d3 " ); \ - asm( "st.w [%a3+], %d2 " ); - -#define MULADDC_STOP \ - asm( "st.w %0, %%d4 " : "=m" (c)); \ - asm( "st.a %0, %%a3 " : "=m" (d)); \ - asm( "st.a %0, %%a2 " : "=m" (s) :: \ - "d0", "d1", "e2", "d4", "a2", "a3" ); - -#endif /* TriCore */ - -#if defined(__arm__) - -#if defined(__thumb__) && !defined(__thumb2__) - -#define MULADDC_INIT \ - asm( \ - " \ - ldr r0, %3; \ - ldr r1, %4; \ - ldr r2, %5; \ - ldr r3, %6; \ - lsr r7, r3, #16; \ - mov r9, r7; \ - lsl r7, r3, #16; \ - lsr r7, r7, #16; \ - mov r8, r7; \ - " - -#define MULADDC_CORE \ - " \ - ldmia r0!, {r6}; \ - lsr r7, r6, #16; \ - lsl r6, r6, #16; \ - lsr r6, r6, #16; \ - mov r4, r8; \ - mul r4, r6; \ - mov r3, r9; \ - mul r6, r3; \ - mov r5, r9; \ - mul r5, r7; \ - mov r3, r8; \ - mul r7, r3; \ - lsr r3, r6, #16; \ - add r5, r5, r3; \ - lsr r3, r7, #16; \ - add r5, r5, r3; \ - add r4, r4, r2; \ - mov r2, #0; \ - adc r5, r2; \ - lsl r3, r6, #16; \ - add r4, r4, r3; \ - adc r5, r2; \ - lsl r3, r7, #16; \ - add r4, r4, r3; \ - adc r5, r2; \ - ldr r3, [r1]; \ - add r4, r4, r3; \ - adc r2, r5; \ - stmia r1!, {r4}; \ - " - -#define MULADDC_STOP \ - " \ - str r2, %0; \ - str r1, %1; \ - str r0, %2; \ - " \ - : "=m" (c), "=m" (d), "=m" (s) \ - : "m" (s), "m" (d), "m" (c), "m" (b) \ - : "r0", "r1", "r2", "r3", "r4", "r5", \ - "r6", "r7", "r8", "r9", "cc" \ - ); - -#else - -#define MULADDC_INIT \ - asm( \ - " \ - ldr r0, %3; \ - ldr r1, %4; \ - ldr r2, %5; \ - ldr r3, %6; \ - " - -#define MULADDC_CORE \ - " \ - ldr r4, [r0], #4; \ - mov r5, #0; \ - ldr r6, [r1]; \ - umlal r2, r5, r3, r4; \ - adds r7, r6, r2; \ - adc r2, r5, #0; \ - str r7, [r1], #4; \ - " - -#define MULADDC_STOP \ - " \ - str r2, %0; \ - str r1, %1; \ - str r0, %2; \ - " \ - : "=m" (c), "=m" (d), "=m" (s) \ - : "m" (s), "m" (d), "m" (c), "m" (b) \ - : "r0", "r1", "r2", "r3", "r4", "r5", \ - "r6", "r7", "cc" \ - ); - -#endif /* Thumb */ - -#endif /* ARMv3 */ - -#if defined(__alpha__) - -#define MULADDC_INIT \ - asm( "ldq $1, %0 " :: "m" (s)); \ - asm( "ldq $2, %0 " :: "m" (d)); \ - asm( "ldq $3, %0 " :: "m" (c)); \ - asm( "ldq $4, %0 " :: "m" (b)); - -#define MULADDC_CORE \ - asm( "ldq $6, 0($1) " ); \ - asm( "addq $1, 8, $1 " ); \ - asm( "mulq $6, $4, $7 " ); \ - asm( "umulh $6, $4, $6 " ); \ - asm( "addq $7, $3, $7 " ); \ - asm( "cmpult $7, $3, $3 " ); \ - asm( "ldq $5, 0($2) " ); \ - asm( "addq $7, $5, $7 " ); \ - asm( "cmpult $7, $5, $5 " ); \ - asm( "stq $7, 0($2) " ); \ - asm( "addq $2, 8, $2 " ); \ - asm( "addq $6, $3, $3 " ); \ - asm( "addq $5, $3, $3 " ); - -#define MULADDC_STOP \ - asm( "stq $3, %0 " : "=m" (c)); \ - asm( "stq $2, %0 " : "=m" (d)); \ - asm( "stq $1, %0 " : "=m" (s) :: \ - "$1", "$2", "$3", "$4", "$5", "$6", "$7" ); - -#endif /* Alpha */ - -#if defined(__mips__) - -#define MULADDC_INIT \ - asm( "lw $10, %0 " :: "m" (s)); \ - asm( "lw $11, %0 " :: "m" (d)); \ - asm( "lw $12, %0 " :: "m" (c)); \ - asm( "lw $13, %0 " :: "m" (b)); - -#define MULADDC_CORE \ - asm( "lw $14, 0($10) " ); \ - asm( "multu $13, $14 " ); \ - asm( "addi $10, $10, 4 " ); \ - asm( "mflo $14 " ); \ - asm( "mfhi $9 " ); \ - asm( "addu $14, $12, $14 " ); \ - asm( "lw $15, 0($11) " ); \ - asm( "sltu $12, $14, $12 " ); \ - asm( "addu $15, $14, $15 " ); \ - asm( "sltu $14, $15, $14 " ); \ - asm( "addu $12, $12, $9 " ); \ - asm( "sw $15, 0($11) " ); \ - asm( "addu $12, $12, $14 " ); \ - asm( "addi $11, $11, 4 " ); - -#define MULADDC_STOP \ - asm( "sw $12, %0 " : "=m" (c)); \ - asm( "sw $11, %0 " : "=m" (d)); \ - asm( "sw $10, %0 " : "=m" (s) :: \ - "$9", "$10", "$11", "$12", "$13", "$14", "$15" ); - -#endif /* MIPS */ -#endif /* GNUC */ - -#if (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__) - -#define MULADDC_INIT \ - __asm mov esi, s \ - __asm mov edi, d \ - __asm mov ecx, c \ - __asm mov ebx, b - -#define MULADDC_CORE \ - __asm lodsd \ - __asm mul ebx \ - __asm add eax, ecx \ - __asm adc edx, 0 \ - __asm add eax, [edi] \ - __asm adc edx, 0 \ - __asm mov ecx, edx \ - __asm stosd - -#if defined(POLARSSL_HAVE_SSE2) - -#define EMIT __asm _emit - -#define MULADDC_HUIT \ - EMIT 0x0F EMIT 0x6E EMIT 0xC9 \ - EMIT 0x0F EMIT 0x6E EMIT 0xC3 \ - EMIT 0x0F EMIT 0x6E EMIT 0x1F \ - EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ - EMIT 0x0F EMIT 0x6E EMIT 0x16 \ - EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \ - EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x04 \ - EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \ - EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x08 \ - EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \ - EMIT 0x0F EMIT 0x6E EMIT 0x7E EMIT 0x0C \ - EMIT 0x0F EMIT 0xF4 EMIT 0xF8 \ - EMIT 0x0F EMIT 0xD4 EMIT 0xCA \ - EMIT 0x0F EMIT 0x6E EMIT 0x5F EMIT 0x04 \ - EMIT 0x0F EMIT 0xD4 EMIT 0xDC \ - EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x08 \ - EMIT 0x0F EMIT 0xD4 EMIT 0xEE \ - EMIT 0x0F EMIT 0x6E EMIT 0x67 EMIT 0x0C \ - EMIT 0x0F EMIT 0xD4 EMIT 0xFC \ - EMIT 0x0F EMIT 0x7E EMIT 0x0F \ - EMIT 0x0F EMIT 0x6E EMIT 0x56 EMIT 0x10 \ - EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \ - EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ - EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x14 \ - EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \ - EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ - EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x18 \ - EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \ - EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x04 \ - EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ - EMIT 0x0F EMIT 0x6E EMIT 0x5E EMIT 0x1C \ - EMIT 0x0F EMIT 0xF4 EMIT 0xD8 \ - EMIT 0x0F EMIT 0xD4 EMIT 0xCD \ - EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x10 \ - EMIT 0x0F EMIT 0xD4 EMIT 0xD5 \ - EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x08 \ - EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ - EMIT 0x0F EMIT 0xD4 EMIT 0xCF \ - EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x14 \ - EMIT 0x0F EMIT 0xD4 EMIT 0xE5 \ - EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x0C \ - EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ - EMIT 0x0F EMIT 0xD4 EMIT 0xCA \ - EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x18 \ - EMIT 0x0F EMIT 0xD4 EMIT 0xF5 \ - EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x10 \ - EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ - EMIT 0x0F EMIT 0xD4 EMIT 0xCC \ - EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x1C \ - EMIT 0x0F EMIT 0xD4 EMIT 0xDD \ - EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x14 \ - EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ - EMIT 0x0F EMIT 0xD4 EMIT 0xCE \ - EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x18 \ - EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ - EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ - EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x1C \ - EMIT 0x83 EMIT 0xC7 EMIT 0x20 \ - EMIT 0x83 EMIT 0xC6 EMIT 0x20 \ - EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ - EMIT 0x0F EMIT 0x7E EMIT 0xC9 - -#define MULADDC_STOP \ - EMIT 0x0F EMIT 0x77 \ - __asm mov c, ecx \ - __asm mov d, edi \ - __asm mov s, esi \ - -#else - -#define MULADDC_STOP \ - __asm mov c, ecx \ - __asm mov d, edi \ - __asm mov s, esi \ - -#endif /* SSE2 */ -#endif /* MSVC */ - -#endif /* POLARSSL_HAVE_ASM */ - -#if !defined(MULADDC_CORE) -#if defined(POLARSSL_HAVE_UDBL) - -#define MULADDC_INIT \ -{ \ - t_udbl r; \ - t_uint r0, r1; - -#define MULADDC_CORE \ - r = *(s++) * (t_udbl) b; \ - r0 = r; \ - r1 = r >> biL; \ - r0 += c; r1 += (r0 < c); \ - r0 += *d; r1 += (r0 < *d); \ - c = r1; *(d++) = r0; - -#define MULADDC_STOP \ -} - -#else -#define MULADDC_INIT \ -{ \ - t_uint s0, s1, b0, b1; \ - t_uint r0, r1, rx, ry; \ - b0 = ( b << biH ) >> biH; \ - b1 = ( b >> biH ); - -#define MULADDC_CORE \ - s0 = ( *s << biH ) >> biH; \ - s1 = ( *s >> biH ); s++; \ - rx = s0 * b1; r0 = s0 * b0; \ - ry = s1 * b0; r1 = s1 * b1; \ - r1 += ( rx >> biH ); \ - r1 += ( ry >> biH ); \ - rx <<= biH; ry <<= biH; \ - r0 += rx; r1 += (r0 < rx); \ - r0 += ry; r1 += (r0 < ry); \ - r0 += c; r1 += (r0 < c); \ - r0 += *d; r1 += (r0 < *d); \ - c = r1; *(d++) = r0; - -#define MULADDC_STOP \ -} - -#endif /* C (generic) */ -#endif /* C (longlong) */ - -#endif /* bn_mul.h */ diff --git a/common/polarssl/libpcrypto.c b/common/polarssl/libpcrypto.c deleted file mode 100644 index 13e37f00..00000000 --- a/common/polarssl/libpcrypto.c +++ /dev/null @@ -1,78 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (C) 2018 Merlok -// Copyright (C) 2018 drHatson -// -// 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. -//----------------------------------------------------------------------------- -// crypto commands -//----------------------------------------------------------------------------- - -#include "polarssl/libpcrypto.h" -#include -#include - -// NIST Special Publication 800-38A — Recommendation for block cipher modes of operation: methods and techniques, 2001. -int aes_encode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length){ - uint8_t iiv[16] = {0}; - if (iv) - memcpy(iiv, iv, 16); - - aes_context aes; - aes_init(&aes); - if (aes_setkey_enc(&aes, key, 128)) - return 1; - if (aes_crypt_cbc(&aes, AES_ENCRYPT, length, iiv, input, output)) - return 2; - aes_free(&aes); - - return 0; -} - -int aes_decode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length){ - uint8_t iiv[16] = {0}; - if (iv) - memcpy(iiv, iv, 16); - - aes_context aes; - aes_init(&aes); - if (aes_setkey_dec(&aes, key, 128)) - return 1; - if (aes_crypt_cbc(&aes, AES_DECRYPT, length, iiv, input, output)) - return 2; - aes_free(&aes); - - return 0; -} - -// NIST Special Publication 800-38B — Recommendation for block cipher modes of operation: The CMAC mode for authentication. -// https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/AES_CMAC.pdf -int aes_cmac(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, int length) { - memset(mac, 0x00, 16); - uint8_t iiv[16] = {0}; - if (iv) - memcpy(iiv, iv, 16); - - // NIST 800-38B - aes_cmac128_context ctx; - aes_cmac128_starts(&ctx, key); - aes_cmac128_update(&ctx, input, length); - aes_cmac128_final(&ctx, mac); - - return 0; -} - -int aes_cmac8(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, int length) { - uint8_t cmac[16] = {0}; - memset(mac, 0x00, 8); - - int res = aes_cmac(iv, key, input, cmac, length); - if (res) - return res; - - for(int i = 0; i < 8; i++) - mac[i] = cmac[i * 2 + 1]; - - return 0; -} diff --git a/common/polarssl/rsa.c b/common/polarssl/rsa.c deleted file mode 100644 index 9872274b..00000000 --- a/common/polarssl/rsa.c +++ /dev/null @@ -1,1466 +0,0 @@ -/* - * The RSA public-key cryptosystem - * - * Copyright (C) 2006-2011, Brainspark B.V. - * - * This file is part of PolarSSL (http://www.polarssl.org) - * Lead Maintainer: Paul Bakker - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/* - * RSA was designed by Ron Rivest, Adi Shamir and Len Adleman. - * - * http://theory.lcs.mit.edu/~rivest/rsapaper.pdf - * http://www.cacr.math.uwaterloo.ca/hac/about/chap8.pdf - */ - -#include "polarssl_config.h" - -#if defined(POLARSSL_RSA_C) - -#include "rsa.h" - -#if defined(POLARSSL_PKCS1_V21) -#include "md.h" -#endif - -#include -#include - -/* - * Initialize an RSA context - */ -void rsa_init( rsa_context *ctx, - int padding, - int hash_id ) -{ - memset( ctx, 0, sizeof( rsa_context ) ); - - ctx->padding = padding; - ctx->hash_id = hash_id; -} - -#if defined(POLARSSL_GENPRIME) - -/* - * Generate an RSA keypair - */ -int rsa_gen_key( rsa_context *ctx, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng, - unsigned int nbits, int exponent ) -{ - int ret; - mpi P1, Q1, H, G; - - if( f_rng == NULL || nbits < 128 || exponent < 3 ) - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - - mpi_init( &P1 ); mpi_init( &Q1 ); mpi_init( &H ); mpi_init( &G ); - - /* - * find primes P and Q with Q < P so that: - * GCD( E, (P-1)*(Q-1) ) == 1 - */ - MPI_CHK( mpi_lset( &ctx->E, exponent ) ); - - do - { - MPI_CHK( mpi_gen_prime( &ctx->P, ( nbits + 1 ) >> 1, 0, - f_rng, p_rng ) ); - - MPI_CHK( mpi_gen_prime( &ctx->Q, ( nbits + 1 ) >> 1, 0, - f_rng, p_rng ) ); - - if( mpi_cmp_mpi( &ctx->P, &ctx->Q ) < 0 ) - mpi_swap( &ctx->P, &ctx->Q ); - - if( mpi_cmp_mpi( &ctx->P, &ctx->Q ) == 0 ) - continue; - - MPI_CHK( mpi_mul_mpi( &ctx->N, &ctx->P, &ctx->Q ) ); - if( mpi_msb( &ctx->N ) != nbits ) - continue; - - MPI_CHK( mpi_sub_int( &P1, &ctx->P, 1 ) ); - MPI_CHK( mpi_sub_int( &Q1, &ctx->Q, 1 ) ); - MPI_CHK( mpi_mul_mpi( &H, &P1, &Q1 ) ); - MPI_CHK( mpi_gcd( &G, &ctx->E, &H ) ); - } - while( mpi_cmp_int( &G, 1 ) != 0 ); - - /* - * D = E^-1 mod ((P-1)*(Q-1)) - * DP = D mod (P - 1) - * DQ = D mod (Q - 1) - * QP = Q^-1 mod P - */ - MPI_CHK( mpi_inv_mod( &ctx->D , &ctx->E, &H ) ); - MPI_CHK( mpi_mod_mpi( &ctx->DP, &ctx->D, &P1 ) ); - MPI_CHK( mpi_mod_mpi( &ctx->DQ, &ctx->D, &Q1 ) ); - MPI_CHK( mpi_inv_mod( &ctx->QP, &ctx->Q, &ctx->P ) ); - - ctx->len = ( mpi_msb( &ctx->N ) + 7 ) >> 3; - -cleanup: - - mpi_free( &P1 ); mpi_free( &Q1 ); mpi_free( &H ); mpi_free( &G ); - - if( ret != 0 ) - { - rsa_free( ctx ); - return( POLARSSL_ERR_RSA_KEY_GEN_FAILED + ret ); - } - - return( 0 ); -} - -#endif - -/* - * Check a public RSA key - */ -int rsa_check_pubkey( const rsa_context *ctx ) -{ - if( !ctx->N.p || !ctx->E.p ) - return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED ); - - if( ( ctx->N.p[0] & 1 ) == 0 || - ( ctx->E.p[0] & 1 ) == 0 ) - return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED ); - - if( mpi_msb( &ctx->N ) < 128 || - mpi_msb( &ctx->N ) > POLARSSL_MPI_MAX_BITS ) - return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED ); - - if( mpi_msb( &ctx->E ) < 2 || - mpi_msb( &ctx->E ) > 64 ) - return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED ); - - return( 0 ); -} - -/* - * Check a private RSA key - */ -int rsa_check_privkey( const rsa_context *ctx ) -{ - int ret; - mpi PQ, DE, P1, Q1, H, I, G, G2, L1, L2, DP, DQ, QP; - - if( ( ret = rsa_check_pubkey( ctx ) ) != 0 ) - return( ret ); - - if( !ctx->P.p || !ctx->Q.p || !ctx->D.p ) - return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED ); - - mpi_init( &PQ ); mpi_init( &DE ); mpi_init( &P1 ); mpi_init( &Q1 ); - mpi_init( &H ); mpi_init( &I ); mpi_init( &G ); mpi_init( &G2 ); - mpi_init( &L1 ); mpi_init( &L2 ); mpi_init( &DP ); mpi_init( &DQ ); - mpi_init( &QP ); - - MPI_CHK( mpi_mul_mpi( &PQ, &ctx->P, &ctx->Q ) ); - MPI_CHK( mpi_mul_mpi( &DE, &ctx->D, &ctx->E ) ); - MPI_CHK( mpi_sub_int( &P1, &ctx->P, 1 ) ); - MPI_CHK( mpi_sub_int( &Q1, &ctx->Q, 1 ) ); - MPI_CHK( mpi_mul_mpi( &H, &P1, &Q1 ) ); - MPI_CHK( mpi_gcd( &G, &ctx->E, &H ) ); - - MPI_CHK( mpi_gcd( &G2, &P1, &Q1 ) ); - MPI_CHK( mpi_div_mpi( &L1, &L2, &H, &G2 ) ); - MPI_CHK( mpi_mod_mpi( &I, &DE, &L1 ) ); - - MPI_CHK( mpi_mod_mpi( &DP, &ctx->D, &P1 ) ); - MPI_CHK( mpi_mod_mpi( &DQ, &ctx->D, &Q1 ) ); - MPI_CHK( mpi_inv_mod( &QP, &ctx->Q, &ctx->P ) ); - /* - * Check for a valid PKCS1v2 private key - */ - if( mpi_cmp_mpi( &PQ, &ctx->N ) != 0 || - mpi_cmp_mpi( &DP, &ctx->DP ) != 0 || - mpi_cmp_mpi( &DQ, &ctx->DQ ) != 0 || - mpi_cmp_mpi( &QP, &ctx->QP ) != 0 || - mpi_cmp_int( &L2, 0 ) != 0 || - mpi_cmp_int( &I, 1 ) != 0 || - mpi_cmp_int( &G, 1 ) != 0 ) - { - ret = POLARSSL_ERR_RSA_KEY_CHECK_FAILED; - } - -cleanup: - mpi_free( &PQ ); mpi_free( &DE ); mpi_free( &P1 ); mpi_free( &Q1 ); - mpi_free( &H ); mpi_free( &I ); mpi_free( &G ); mpi_free( &G2 ); - mpi_free( &L1 ); mpi_free( &L2 ); mpi_free( &DP ); mpi_free( &DQ ); - mpi_free( &QP ); - - if( ret == POLARSSL_ERR_RSA_KEY_CHECK_FAILED ) - return( ret ); - - if( ret != 0 ) - return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED + ret ); - - return( 0 ); -} - -/* - * Do an RSA public key operation - */ -int rsa_public( rsa_context *ctx, - const unsigned char *input, - unsigned char *output ) -{ - int ret; - size_t olen; - mpi T; - - mpi_init( &T ); - - MPI_CHK( mpi_read_binary( &T, input, ctx->len ) ); - - if( mpi_cmp_mpi( &T, &ctx->N ) >= 0 ) - { - mpi_free( &T ); - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - } - - olen = ctx->len; - MPI_CHK( mpi_exp_mod( &T, &T, &ctx->E, &ctx->N, &ctx->RN ) ); - MPI_CHK( mpi_write_binary( &T, output, olen ) ); - -cleanup: - - mpi_free( &T ); - - if( ret != 0 ) - return( POLARSSL_ERR_RSA_PUBLIC_FAILED + ret ); - - return( 0 ); -} - -/* - * Do an RSA private key operation - */ -int rsa_private( rsa_context *ctx, - const unsigned char *input, - unsigned char *output ) -{ - int ret; - size_t olen; - mpi T, T1, T2; - - mpi_init( &T ); mpi_init( &T1 ); mpi_init( &T2 ); - - MPI_CHK( mpi_read_binary( &T, input, ctx->len ) ); - - if( mpi_cmp_mpi( &T, &ctx->N ) >= 0 ) - { - mpi_free( &T ); - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - } - -#if defined(POLARSSL_RSA_NO_CRT) - MPI_CHK( mpi_exp_mod( &T, &T, &ctx->D, &ctx->N, &ctx->RN ) ); -#else - /* - * faster decryption using the CRT - * - * T1 = input ^ dP mod P - * T2 = input ^ dQ mod Q - */ - MPI_CHK( mpi_exp_mod( &T1, &T, &ctx->DP, &ctx->P, &ctx->RP ) ); - MPI_CHK( mpi_exp_mod( &T2, &T, &ctx->DQ, &ctx->Q, &ctx->RQ ) ); - - /* - * T = (T1 - T2) * (Q^-1 mod P) mod P - */ - MPI_CHK( mpi_sub_mpi( &T, &T1, &T2 ) ); - MPI_CHK( mpi_mul_mpi( &T1, &T, &ctx->QP ) ); - MPI_CHK( mpi_mod_mpi( &T, &T1, &ctx->P ) ); - - /* - * output = T2 + T * Q - */ - MPI_CHK( mpi_mul_mpi( &T1, &T, &ctx->Q ) ); - MPI_CHK( mpi_add_mpi( &T, &T2, &T1 ) ); -#endif - - olen = ctx->len; - MPI_CHK( mpi_write_binary( &T, output, olen ) ); - -cleanup: - - mpi_free( &T ); mpi_free( &T1 ); mpi_free( &T2 ); - - if( ret != 0 ) - return( POLARSSL_ERR_RSA_PRIVATE_FAILED + ret ); - - return( 0 ); -} - -#if defined(POLARSSL_PKCS1_V21) -/** - * Generate and apply the MGF1 operation (from PKCS#1 v2.1) to a buffer. - * - * \param dst buffer to mask - * \param dlen length of destination buffer - * \param src source of the mask generation - * \param slen length of the source buffer - * \param md_ctx message digest context to use - */ -static void mgf_mask( unsigned char *dst, size_t dlen, unsigned char *src, size_t slen, - md_context_t *md_ctx ) -{ - unsigned char mask[POLARSSL_MD_MAX_SIZE]; - unsigned char counter[4]; - unsigned char *p; - unsigned int hlen; - size_t i, use_len; - - memset( mask, 0, POLARSSL_MD_MAX_SIZE ); - memset( counter, 0, 4 ); - - hlen = md_ctx->md_info->size; - - // Generate and apply dbMask - // - p = dst; - - while( dlen > 0 ) - { - use_len = hlen; - if( dlen < hlen ) - use_len = dlen; - - md_starts( md_ctx ); - md_update( md_ctx, src, slen ); - md_update( md_ctx, counter, 4 ); - md_finish( md_ctx, mask ); - - for( i = 0; i < use_len; ++i ) - *p++ ^= mask[i]; - - counter[3]++; - - dlen -= use_len; - } -} -#endif - -#if defined(POLARSSL_PKCS1_V21) -/* - * Implementation of the PKCS#1 v2.1 RSAES-OAEP-ENCRYPT function - */ -int rsa_rsaes_oaep_encrypt( rsa_context *ctx, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng, - int mode, - const unsigned char *label, size_t label_len, - size_t ilen, - const unsigned char *input, - unsigned char *output ) -{ - size_t olen; - int ret; - unsigned char *p = output; - unsigned int hlen; - const md_info_t *md_info; - md_context_t md_ctx; - - if( ctx->padding != RSA_PKCS_V21 || f_rng == NULL ) - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - - md_info = md_info_from_type( ctx->hash_id ); - - if( md_info == NULL ) - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - - olen = ctx->len; - hlen = md_get_size( md_info ); - - if( olen < ilen + 2 * hlen + 2 || f_rng == NULL ) - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - - memset( output, 0, olen ); - - *p++ = 0; - - // Generate a random octet string seed - // - if( ( ret = f_rng( p_rng, p, hlen ) ) != 0 ) - return( POLARSSL_ERR_RSA_RNG_FAILED + ret ); - - p += hlen; - - // Construct DB - // - md( md_info, label, label_len, p ); - p += hlen; - p += olen - 2 * hlen - 2 - ilen; - *p++ = 1; - memcpy( p, input, ilen ); - - md_init_ctx( &md_ctx, md_info ); - - // maskedDB: Apply dbMask to DB - // - mgf_mask( output + hlen + 1, olen - hlen - 1, output + 1, hlen, - &md_ctx ); - - // maskedSeed: Apply seedMask to seed - // - mgf_mask( output + 1, hlen, output + hlen + 1, olen - hlen - 1, - &md_ctx ); - - md_free_ctx( &md_ctx ); - - return( ( mode == RSA_PUBLIC ) - ? rsa_public( ctx, output, output ) - : rsa_private( ctx, output, output ) ); -} -#endif /* POLARSSL_PKCS1_V21 */ - -/* - * Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-ENCRYPT function - */ -int rsa_rsaes_pkcs1_v15_encrypt( rsa_context *ctx, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng, - int mode, size_t ilen, - const unsigned char *input, - unsigned char *output ) -{ - size_t nb_pad, olen; - int ret; - unsigned char *p = output; - - if( ctx->padding != RSA_PKCS_V15 || f_rng == NULL ) - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - - olen = ctx->len; - - if( olen < ilen + 11 ) - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - - nb_pad = olen - 3 - ilen; - - *p++ = 0; - if( mode == RSA_PUBLIC ) - { - *p++ = RSA_CRYPT; - - while( nb_pad-- > 0 ) - { - int rng_dl = 100; - - do { - ret = f_rng( p_rng, p, 1 ); - } while( *p == 0 && --rng_dl && ret == 0 ); - - // Check if RNG failed to generate data - // - if( rng_dl == 0 || ret != 0) - return POLARSSL_ERR_RSA_RNG_FAILED + ret; - - p++; - } - } - else - { - *p++ = RSA_SIGN; - - while( nb_pad-- > 0 ) - *p++ = 0xFF; - } - - *p++ = 0; - memcpy( p, input, ilen ); - - return( ( mode == RSA_PUBLIC ) - ? rsa_public( ctx, output, output ) - : rsa_private( ctx, output, output ) ); -} - -/* - * Add the message padding, then do an RSA operation - */ -int rsa_pkcs1_encrypt( rsa_context *ctx, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng, - int mode, size_t ilen, - const unsigned char *input, - unsigned char *output ) -{ - switch( ctx->padding ) - { - case RSA_PKCS_V15: - return rsa_rsaes_pkcs1_v15_encrypt( ctx, f_rng, p_rng, mode, ilen, - input, output ); - -#if defined(POLARSSL_PKCS1_V21) - case RSA_PKCS_V21: - return rsa_rsaes_oaep_encrypt( ctx, f_rng, p_rng, mode, NULL, 0, - ilen, input, output ); -#endif - - default: - return( POLARSSL_ERR_RSA_INVALID_PADDING ); - } -} - -#if defined(POLARSSL_PKCS1_V21) -/* - * Implementation of the PKCS#1 v2.1 RSAES-OAEP-DECRYPT function - */ -int rsa_rsaes_oaep_decrypt( rsa_context *ctx, - int mode, - const unsigned char *label, size_t label_len, - size_t *olen, - const unsigned char *input, - unsigned char *output, - size_t output_max_len ) -{ - int ret; - size_t ilen; - unsigned char *p; - unsigned char buf[POLARSSL_MPI_MAX_SIZE]; - unsigned char lhash[POLARSSL_MD_MAX_SIZE]; - unsigned int hlen; - const md_info_t *md_info; - md_context_t md_ctx; - - if( ctx->padding != RSA_PKCS_V21 ) - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - - ilen = ctx->len; - - if( ilen < 16 || ilen > sizeof( buf ) ) - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - - ret = ( mode == RSA_PUBLIC ) - ? rsa_public( ctx, input, buf ) - : rsa_private( ctx, input, buf ); - - if( ret != 0 ) - return( ret ); - - p = buf; - - if( *p++ != 0 ) - return( POLARSSL_ERR_RSA_INVALID_PADDING ); - - md_info = md_info_from_type( ctx->hash_id ); - if( md_info == NULL ) - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - - hlen = md_get_size( md_info ); - - md_init_ctx( &md_ctx, md_info ); - - // Generate lHash - // - md( md_info, label, label_len, lhash ); - - // seed: Apply seedMask to maskedSeed - // - mgf_mask( buf + 1, hlen, buf + hlen + 1, ilen - hlen - 1, - &md_ctx ); - - // DB: Apply dbMask to maskedDB - // - mgf_mask( buf + hlen + 1, ilen - hlen - 1, buf + 1, hlen, - &md_ctx ); - - p += hlen; - md_free_ctx( &md_ctx ); - - // Check validity - // - if( memcmp( lhash, p, hlen ) != 0 ) - return( POLARSSL_ERR_RSA_INVALID_PADDING ); - - p += hlen; - - while( *p == 0 && p < buf + ilen ) - p++; - - if( p == buf + ilen ) - return( POLARSSL_ERR_RSA_INVALID_PADDING ); - - if( *p++ != 0x01 ) - return( POLARSSL_ERR_RSA_INVALID_PADDING ); - - if (ilen - (p - buf) > output_max_len) - return( POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE ); - - *olen = ilen - (p - buf); - memcpy( output, p, *olen ); - - return( 0 ); -} -#endif /* POLARSSL_PKCS1_V21 */ - -/* - * Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-DECRYPT function - */ -int rsa_rsaes_pkcs1_v15_decrypt( rsa_context *ctx, - int mode, size_t *olen, - const unsigned char *input, - unsigned char *output, - size_t output_max_len) -{ - int ret, correct = 1; - size_t ilen, pad_count = 0; - unsigned char *p, *q; - unsigned char bt; - unsigned char buf[POLARSSL_MPI_MAX_SIZE]; - - if( ctx->padding != RSA_PKCS_V15 ) - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - - ilen = ctx->len; - - if( ilen < 16 || ilen > sizeof( buf ) ) - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - - ret = ( mode == RSA_PUBLIC ) - ? rsa_public( ctx, input, buf ) - : rsa_private( ctx, input, buf ); - - if( ret != 0 ) - return( ret ); - - p = buf; - - if( *p++ != 0 ) - correct = 0; - - bt = *p++; - if( ( bt != RSA_CRYPT && mode == RSA_PRIVATE ) || - ( bt != RSA_SIGN && mode == RSA_PUBLIC ) ) - { - correct = 0; - } - - if( bt == RSA_CRYPT ) - { - while( *p != 0 && p < buf + ilen - 1 ) - pad_count += ( *p++ != 0 ); - - correct &= ( *p == 0 && p < buf + ilen - 1 ); - - q = p; - - // Also pass over all other bytes to reduce timing differences - // - while ( q < buf + ilen - 1 ) - pad_count += ( *q++ != 0 ); - - // Prevent compiler optimization of pad_count - // - correct |= pad_count & 0x100000; /* Always 0 unless 1M bit keys */ - p++; - } - else - { - while( *p == 0xFF && p < buf + ilen - 1 ) - pad_count += ( *p++ == 0xFF ); - - correct &= ( *p == 0 && p < buf + ilen - 1 ); - - q = p; - - // Also pass over all other bytes to reduce timing differences - // - while ( q < buf + ilen - 1 ) - pad_count += ( *q++ != 0 ); - - // Prevent compiler optimization of pad_count - // - correct |= pad_count & 0x100000; /* Always 0 unless 1M bit keys */ - p++; - } - - if( correct == 0 ) - return( POLARSSL_ERR_RSA_INVALID_PADDING ); - - if (ilen - (p - buf) > output_max_len) - return( POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE ); - - *olen = ilen - (p - buf); - memcpy( output, p, *olen ); - - return( 0 ); -} - -/* - * Do an RSA operation, then remove the message padding - */ -int rsa_pkcs1_decrypt( rsa_context *ctx, - int mode, size_t *olen, - const unsigned char *input, - unsigned char *output, - size_t output_max_len) -{ - switch( ctx->padding ) - { - case RSA_PKCS_V15: - return rsa_rsaes_pkcs1_v15_decrypt( ctx, mode, olen, input, output, - output_max_len ); - -#if defined(POLARSSL_PKCS1_V21) - case RSA_PKCS_V21: - return rsa_rsaes_oaep_decrypt( ctx, mode, NULL, 0, olen, input, - output, output_max_len ); -#endif - - default: - return( POLARSSL_ERR_RSA_INVALID_PADDING ); - } -} - -#if defined(POLARSSL_PKCS1_V21) -/* - * Implementation of the PKCS#1 v2.1 RSASSA-PSS-SIGN function - */ -int rsa_rsassa_pss_sign( rsa_context *ctx, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng, - int mode, - int hash_id, - unsigned int hashlen, - const unsigned char *hash, - unsigned char *sig ) -{ - size_t olen; - unsigned char *p = sig; - unsigned char salt[POLARSSL_MD_MAX_SIZE]; - unsigned int slen, hlen, offset = 0; - int ret; - size_t msb; - const md_info_t *md_info; - md_context_t md_ctx; - - if( ctx->padding != RSA_PKCS_V21 || f_rng == NULL ) - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - - olen = ctx->len; - - switch( hash_id ) - { - case SIG_RSA_MD2: - case SIG_RSA_MD4: - case SIG_RSA_MD5: - hashlen = 16; - break; - - case SIG_RSA_SHA1: - hashlen = 20; - break; - - case SIG_RSA_SHA224: - hashlen = 28; - break; - - case SIG_RSA_SHA256: - hashlen = 32; - break; - - case SIG_RSA_SHA384: - hashlen = 48; - break; - - case SIG_RSA_SHA512: - hashlen = 64; - break; - - default: - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - } - - md_info = md_info_from_type( ctx->hash_id ); - if( md_info == NULL ) - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - - hlen = md_get_size( md_info ); - slen = hlen; - - if( olen < hlen + slen + 2 ) - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - - memset( sig, 0, olen ); - - msb = mpi_msb( &ctx->N ) - 1; - - // Generate salt of length slen - // - if( ( ret = f_rng( p_rng, salt, slen ) ) != 0 ) - return( POLARSSL_ERR_RSA_RNG_FAILED + ret ); - - // Note: EMSA-PSS encoding is over the length of N - 1 bits - // - msb = mpi_msb( &ctx->N ) - 1; - p += olen - hlen * 2 - 2; - *p++ = 0x01; - memcpy( p, salt, slen ); - p += slen; - - md_init_ctx( &md_ctx, md_info ); - - // Generate H = Hash( M' ) - // - md_starts( &md_ctx ); - md_update( &md_ctx, p, 8 ); - md_update( &md_ctx, hash, hashlen ); - md_update( &md_ctx, salt, slen ); - md_finish( &md_ctx, p ); - - // Compensate for boundary condition when applying mask - // - if( msb % 8 == 0 ) - offset = 1; - - // maskedDB: Apply dbMask to DB - // - mgf_mask( sig + offset, olen - hlen - 1 - offset, p, hlen, &md_ctx ); - - md_free_ctx( &md_ctx ); - - msb = mpi_msb( &ctx->N ) - 1; - sig[0] &= 0xFF >> ( olen * 8 - msb ); - - p += hlen; - *p++ = 0xBC; - - return( ( mode == RSA_PUBLIC ) - ? rsa_public( ctx, sig, sig ) - : rsa_private( ctx, sig, sig ) ); -} -#endif /* POLARSSL_PKCS1_V21 */ - -/* - * Implementation of the PKCS#1 v2.1 RSASSA-PKCS1-V1_5-SIGN function - */ -/* - * Do an RSA operation to sign the message digest - */ -int rsa_rsassa_pkcs1_v15_sign( rsa_context *ctx, - int mode, - int hash_id, - unsigned int hashlen, - const unsigned char *hash, - unsigned char *sig ) -{ - size_t nb_pad, olen; - unsigned char *p = sig; - - if( ctx->padding != RSA_PKCS_V15 ) - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - - olen = ctx->len; - - switch( hash_id ) - { - case SIG_RSA_RAW: - nb_pad = olen - 3 - hashlen; - break; - - case SIG_RSA_MD2: - case SIG_RSA_MD4: - case SIG_RSA_MD5: - nb_pad = olen - 3 - 34; - break; - - case SIG_RSA_SHA1: - nb_pad = olen - 3 - 35; - break; - - case SIG_RSA_SHA224: - nb_pad = olen - 3 - 47; - break; - - case SIG_RSA_SHA256: - nb_pad = olen - 3 - 51; - break; - - case SIG_RSA_SHA384: - nb_pad = olen - 3 - 67; - break; - - case SIG_RSA_SHA512: - nb_pad = olen - 3 - 83; - break; - - - default: - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - } - - if( ( nb_pad < 8 ) || ( nb_pad > olen ) ) - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - - *p++ = 0; - *p++ = RSA_SIGN; - memset( p, 0xFF, nb_pad ); - p += nb_pad; - *p++ = 0; - - switch( hash_id ) - { - case SIG_RSA_RAW: - memcpy( p, hash, hashlen ); - break; - - case SIG_RSA_MD2: - memcpy( p, ASN1_HASH_MDX, 18 ); - memcpy( p + 18, hash, 16 ); - p[13] = 2; break; - - case SIG_RSA_MD4: - memcpy( p, ASN1_HASH_MDX, 18 ); - memcpy( p + 18, hash, 16 ); - p[13] = 4; break; - - case SIG_RSA_MD5: - memcpy( p, ASN1_HASH_MDX, 18 ); - memcpy( p + 18, hash, 16 ); - p[13] = 5; break; - - case SIG_RSA_SHA1: - memcpy( p, ASN1_HASH_SHA1, 15 ); - memcpy( p + 15, hash, 20 ); - break; - - case SIG_RSA_SHA224: - memcpy( p, ASN1_HASH_SHA2X, 19 ); - memcpy( p + 19, hash, 28 ); - p[1] += 28; p[14] = 4; p[18] += 28; break; - - case SIG_RSA_SHA256: - memcpy( p, ASN1_HASH_SHA2X, 19 ); - memcpy( p + 19, hash, 32 ); - p[1] += 32; p[14] = 1; p[18] += 32; break; - - case SIG_RSA_SHA384: - memcpy( p, ASN1_HASH_SHA2X, 19 ); - memcpy( p + 19, hash, 48 ); - p[1] += 48; p[14] = 2; p[18] += 48; break; - - case SIG_RSA_SHA512: - memcpy( p, ASN1_HASH_SHA2X, 19 ); - memcpy( p + 19, hash, 64 ); - p[1] += 64; p[14] = 3; p[18] += 64; break; - - default: - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - } - - return( ( mode == RSA_PUBLIC ) - ? rsa_public( ctx, sig, sig ) - : rsa_private( ctx, sig, sig ) ); -} - -/* - * Do an RSA operation to sign the message digest - */ -int rsa_pkcs1_sign( rsa_context *ctx, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng, - int mode, - int hash_id, - unsigned int hashlen, - const unsigned char *hash, - unsigned char *sig ) -{ - switch( ctx->padding ) - { - case RSA_PKCS_V15: - return rsa_rsassa_pkcs1_v15_sign( ctx, mode, hash_id, - hashlen, hash, sig ); - -#if defined(POLARSSL_PKCS1_V21) - case RSA_PKCS_V21: - return rsa_rsassa_pss_sign( ctx, f_rng, p_rng, mode, hash_id, - hashlen, hash, sig ); -#endif - - default: - return( POLARSSL_ERR_RSA_INVALID_PADDING ); - } -} - -#if defined(POLARSSL_PKCS1_V21) -/* - * Implementation of the PKCS#1 v2.1 RSASSA-PSS-VERIFY function - */ -int rsa_rsassa_pss_verify( rsa_context *ctx, - int mode, - int hash_id, - unsigned int hashlen, - const unsigned char *hash, - unsigned char *sig ) -{ - int ret; - size_t siglen; - unsigned char *p; - unsigned char buf[POLARSSL_MPI_MAX_SIZE]; - unsigned char result[POLARSSL_MD_MAX_SIZE]; - unsigned char zeros[8]; - unsigned int hlen; - size_t slen, msb; - const md_info_t *md_info; - md_context_t md_ctx; - - if( ctx->padding != RSA_PKCS_V21 ) - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - - siglen = ctx->len; - - if( siglen < 16 || siglen > sizeof( buf ) ) - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - - ret = ( mode == RSA_PUBLIC ) - ? rsa_public( ctx, sig, buf ) - : rsa_private( ctx, sig, buf ); - - if( ret != 0 ) - return( ret ); - - p = buf; - - if( buf[siglen - 1] != 0xBC ) - return( POLARSSL_ERR_RSA_INVALID_PADDING ); - - switch( hash_id ) - { - case SIG_RSA_MD2: - case SIG_RSA_MD4: - case SIG_RSA_MD5: - hashlen = 16; - break; - - case SIG_RSA_SHA1: - hashlen = 20; - break; - - case SIG_RSA_SHA224: - hashlen = 28; - break; - - case SIG_RSA_SHA256: - hashlen = 32; - break; - - case SIG_RSA_SHA384: - hashlen = 48; - break; - - case SIG_RSA_SHA512: - hashlen = 64; - break; - - default: - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - } - - md_info = md_info_from_type( ctx->hash_id ); - if( md_info == NULL ) - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - - hlen = md_get_size( md_info ); - slen = siglen - hlen - 1; - - memset( zeros, 0, 8 ); - - // Note: EMSA-PSS verification is over the length of N - 1 bits - // - msb = mpi_msb( &ctx->N ) - 1; - - // Compensate for boundary condition when applying mask - // - if( msb % 8 == 0 ) - { - p++; - siglen -= 1; - } - if( buf[0] >> ( 8 - siglen * 8 + msb ) ) - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - - md_init_ctx( &md_ctx, md_info ); - - mgf_mask( p, siglen - hlen - 1, p + siglen - hlen - 1, hlen, &md_ctx ); - - buf[0] &= 0xFF >> ( siglen * 8 - msb ); - - while( *p == 0 && p < buf + siglen ) - p++; - - if( p == buf + siglen || - *p++ != 0x01 ) - { - md_free_ctx( &md_ctx ); - return( POLARSSL_ERR_RSA_INVALID_PADDING ); - } - - slen -= p - buf; - - // Generate H = Hash( M' ) - // - md_starts( &md_ctx ); - md_update( &md_ctx, zeros, 8 ); - md_update( &md_ctx, hash, hashlen ); - md_update( &md_ctx, p, slen ); - md_finish( &md_ctx, result ); - - md_free_ctx( &md_ctx ); - - if( memcmp( p + slen, result, hlen ) == 0 ) - return( 0 ); - else - return( POLARSSL_ERR_RSA_VERIFY_FAILED ); -} -#endif /* POLARSSL_PKCS1_V21 */ - -/* - * Implementation of the PKCS#1 v2.1 RSASSA-PKCS1-v1_5-VERIFY function - */ -int rsa_rsassa_pkcs1_v15_verify( rsa_context *ctx, - int mode, - int hash_id, - unsigned int hashlen, - const unsigned char *hash, - unsigned char *sig ) -{ - int ret; - size_t len, siglen; - unsigned char *p, c; - unsigned char buf[POLARSSL_MPI_MAX_SIZE]; - - if( ctx->padding != RSA_PKCS_V15 ) - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - - siglen = ctx->len; - - if( siglen < 16 || siglen > sizeof( buf ) ) - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - - ret = ( mode == RSA_PUBLIC ) - ? rsa_public( ctx, sig, buf ) - : rsa_private( ctx, sig, buf ); - - if( ret != 0 ) - return( ret ); - - p = buf; - - if( *p++ != 0 || *p++ != RSA_SIGN ) - return( POLARSSL_ERR_RSA_INVALID_PADDING ); - - while( *p != 0 ) - { - if( p >= buf + siglen - 1 || *p != 0xFF ) - return( POLARSSL_ERR_RSA_INVALID_PADDING ); - p++; - } - p++; - - len = siglen - ( p - buf ); - - if( len == 33 && hash_id == SIG_RSA_SHA1 ) - { - if( memcmp( p, ASN1_HASH_SHA1_ALT, 13 ) == 0 && - memcmp( p + 13, hash, 20 ) == 0 ) - return( 0 ); - else - return( POLARSSL_ERR_RSA_VERIFY_FAILED ); - } - if( len == 34 ) - { - c = p[13]; - p[13] = 0; - - if( memcmp( p, ASN1_HASH_MDX, 18 ) != 0 ) - return( POLARSSL_ERR_RSA_VERIFY_FAILED ); - - if( ( c == 2 && hash_id == SIG_RSA_MD2 ) || - ( c == 4 && hash_id == SIG_RSA_MD4 ) || - ( c == 5 && hash_id == SIG_RSA_MD5 ) ) - { - if( memcmp( p + 18, hash, 16 ) == 0 ) - return( 0 ); - else - return( POLARSSL_ERR_RSA_VERIFY_FAILED ); - } - } - - if( len == 35 && hash_id == SIG_RSA_SHA1 ) - { - if( memcmp( p, ASN1_HASH_SHA1, 15 ) == 0 && - memcmp( p + 15, hash, 20 ) == 0 ) - return( 0 ); - else - return( POLARSSL_ERR_RSA_VERIFY_FAILED ); - } - if( ( len == 19 + 28 && p[14] == 4 && hash_id == SIG_RSA_SHA224 ) || - ( len == 19 + 32 && p[14] == 1 && hash_id == SIG_RSA_SHA256 ) || - ( len == 19 + 48 && p[14] == 2 && hash_id == SIG_RSA_SHA384 ) || - ( len == 19 + 64 && p[14] == 3 && hash_id == SIG_RSA_SHA512 ) ) - { - c = p[1] - 17; - p[1] = 17; - p[14] = 0; - - if( p[18] == c && - memcmp( p, ASN1_HASH_SHA2X, 18 ) == 0 && - memcmp( p + 19, hash, c ) == 0 ) - return( 0 ); - else - return( POLARSSL_ERR_RSA_VERIFY_FAILED ); - } - - if( len == hashlen && hash_id == SIG_RSA_RAW ) - { - if( memcmp( p, hash, hashlen ) == 0 ) - return( 0 ); - else - return( POLARSSL_ERR_RSA_VERIFY_FAILED ); - } - - return( POLARSSL_ERR_RSA_INVALID_PADDING ); -} - -/* - * Do an RSA operation and check the message digest - */ -int rsa_pkcs1_verify( rsa_context *ctx, - int mode, - int hash_id, - unsigned int hashlen, - const unsigned char *hash, - unsigned char *sig ) -{ - switch( ctx->padding ) - { - case RSA_PKCS_V15: - return rsa_rsassa_pkcs1_v15_verify( ctx, mode, hash_id, - hashlen, hash, sig ); - -#if defined(POLARSSL_PKCS1_V21) - case RSA_PKCS_V21: - return rsa_rsassa_pss_verify( ctx, mode, hash_id, - hashlen, hash, sig ); -#endif - - default: - return( POLARSSL_ERR_RSA_INVALID_PADDING ); - } -} - -/* - * Free the components of an RSA key - */ -void rsa_free( rsa_context *ctx ) -{ - mpi_free( &ctx->RQ ); mpi_free( &ctx->RP ); mpi_free( &ctx->RN ); - mpi_free( &ctx->QP ); mpi_free( &ctx->DQ ); mpi_free( &ctx->DP ); - mpi_free( &ctx->Q ); mpi_free( &ctx->P ); mpi_free( &ctx->D ); - mpi_free( &ctx->E ); mpi_free( &ctx->N ); -} - -#if defined(POLARSSL_SELF_TEST) - -#include "polarssl/sha1.h" - -/* - * Example RSA-1024 keypair, for test purposes - */ -#define KEY_LEN 128 - -#define RSA_N "9292758453063D803DD603D5E777D788" \ - "8ED1D5BF35786190FA2F23EBC0848AEA" \ - "DDA92CA6C3D80B32C4D109BE0F36D6AE" \ - "7130B9CED7ACDF54CFC7555AC14EEBAB" \ - "93A89813FBF3C4F8066D2D800F7C38A8" \ - "1AE31942917403FF4946B0A83D3D3E05" \ - "EE57C6F5F5606FB5D4BC6CD34EE0801A" \ - "5E94BB77B07507233A0BC7BAC8F90F79" - -#define RSA_E "10001" - -#define RSA_D "24BF6185468786FDD303083D25E64EFC" \ - "66CA472BC44D253102F8B4A9D3BFA750" \ - "91386C0077937FE33FA3252D28855837" \ - "AE1B484A8A9A45F7EE8C0C634F99E8CD" \ - "DF79C5CE07EE72C7F123142198164234" \ - "CABB724CF78B8173B9F880FC86322407" \ - "AF1FEDFDDE2BEB674CA15F3E81A1521E" \ - "071513A1E85B5DFA031F21ECAE91A34D" - -#define RSA_P "C36D0EB7FCD285223CFB5AABA5BDA3D8" \ - "2C01CAD19EA484A87EA4377637E75500" \ - "FCB2005C5C7DD6EC4AC023CDA285D796" \ - "C3D9E75E1EFC42488BB4F1D13AC30A57" - -#define RSA_Q "C000DF51A7C77AE8D7C7370C1FF55B69" \ - "E211C2B9E5DB1ED0BF61D0D9899620F4" \ - "910E4168387E3C30AA1E00C339A79508" \ - "8452DD96A9A5EA5D9DCA68DA636032AF" - -#define RSA_DP "C1ACF567564274FB07A0BBAD5D26E298" \ - "3C94D22288ACD763FD8E5600ED4A702D" \ - "F84198A5F06C2E72236AE490C93F07F8" \ - "3CC559CD27BC2D1CA488811730BB5725" - -#define RSA_DQ "4959CBF6F8FEF750AEE6977C155579C7" \ - "D8AAEA56749EA28623272E4F7D0592AF" \ - "7C1F1313CAC9471B5C523BFE592F517B" \ - "407A1BD76C164B93DA2D32A383E58357" - -#define RSA_QP "9AE7FBC99546432DF71896FC239EADAE" \ - "F38D18D2B2F0E2DD275AA977E2BF4411" \ - "F5A3B2A5D33605AEBBCCBA7FEB9F2D2F" \ - "A74206CEC169D74BF5A8C50D6F48EA08" - -#define PT_LEN 24 -#define RSA_PT "\xAA\xBB\xCC\x03\x02\x01\x00\xFF\xFF\xFF\xFF\xFF" \ - "\x11\x22\x33\x0A\x0B\x0C\xCC\xDD\xDD\xDD\xDD\xDD" - -static int myrand( void *rng_state, unsigned char *output, size_t len ) -{ - size_t i; - - if( rng_state != NULL ) - rng_state = NULL; - - for( i = 0; i < len; ++i ) - output[i] = rand(); - - return( 0 ); -} - -/* - * Checkup routine - */ -int rsa_self_test( int verbose ) -{ - size_t len; - rsa_context rsa; - unsigned char rsa_plaintext[PT_LEN]; - unsigned char rsa_decrypted[PT_LEN]; - unsigned char rsa_ciphertext[KEY_LEN]; -#if defined(POLARSSL_SHA1_C) - unsigned char sha1sum[20]; -#endif - - rsa_init( &rsa, RSA_PKCS_V15, 0 ); - - rsa.len = KEY_LEN; - mpi_read_string( &rsa.N , 16, RSA_N ); - mpi_read_string( &rsa.E , 16, RSA_E ); - mpi_read_string( &rsa.D , 16, RSA_D ); - mpi_read_string( &rsa.P , 16, RSA_P ); - mpi_read_string( &rsa.Q , 16, RSA_Q ); - mpi_read_string( &rsa.DP, 16, RSA_DP ); - mpi_read_string( &rsa.DQ, 16, RSA_DQ ); - mpi_read_string( &rsa.QP, 16, RSA_QP ); - - if( verbose != 0 ) - printf( " RSA key validation: " ); - - if( rsa_check_pubkey( &rsa ) != 0 || - rsa_check_privkey( &rsa ) != 0 ) - { - if( verbose != 0 ) - printf( "failed\n" ); - - return( 1 ); - } - - if( verbose != 0 ) - printf( "passed\n PKCS#1 encryption : " ); - - memcpy( rsa_plaintext, RSA_PT, PT_LEN ); - - if( rsa_pkcs1_encrypt( &rsa, &myrand, NULL, RSA_PUBLIC, PT_LEN, - rsa_plaintext, rsa_ciphertext ) != 0 ) - { - if( verbose != 0 ) - printf( "failed\n" ); - - return( 1 ); - } - - if( verbose != 0 ) - printf( "passed\n PKCS#1 decryption : " ); - - if( rsa_pkcs1_decrypt( &rsa, RSA_PRIVATE, &len, - rsa_ciphertext, rsa_decrypted, - sizeof(rsa_decrypted) ) != 0 ) - { - if( verbose != 0 ) - printf( "failed\n" ); - - return( 1 ); - } - - if( memcmp( rsa_decrypted, rsa_plaintext, len ) != 0 ) - { - if( verbose != 0 ) - printf( "failed\n" ); - - return( 1 ); - } - -#if defined(POLARSSL_SHA1_C) - if( verbose != 0 ) - printf( "passed\n PKCS#1 data sign : " ); - - sha1( rsa_plaintext, PT_LEN, sha1sum ); - - if( rsa_pkcs1_sign( &rsa, NULL, NULL, RSA_PRIVATE, SIG_RSA_SHA1, 20, - sha1sum, rsa_ciphertext ) != 0 ) - { - if( verbose != 0 ) - printf( "failed\n" ); - - return( 1 ); - } - - if( verbose != 0 ) - printf( "passed\n PKCS#1 sig. verify: " ); - - if( rsa_pkcs1_verify( &rsa, RSA_PUBLIC, SIG_RSA_SHA1, 20, - sha1sum, rsa_ciphertext ) != 0 ) - { - if( verbose != 0 ) - printf( "failed\n" ); - - return( 1 ); - } - - if( verbose != 0 ) - printf( "passed\n\n" ); -#endif /* POLARSSL_SHA1_C */ - - rsa_free( &rsa ); - - return( 0 ); -} - -#endif - -#endif diff --git a/common/polarssl/rsa.h b/common/polarssl/rsa.h deleted file mode 100644 index f9a02202..00000000 --- a/common/polarssl/rsa.h +++ /dev/null @@ -1,597 +0,0 @@ -/** - * \file rsa.h - * - * \brief The RSA public-key cryptosystem - * - * Copyright (C) 2006-2010, Brainspark B.V. - * - * This file is part of PolarSSL (http://www.polarssl.org) - * Lead Maintainer: Paul Bakker - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -#ifndef POLARSSL_RSA_H -#define POLARSSL_RSA_H - -#include "bignum.h" - -/* - * RSA Error codes - */ -#define POLARSSL_ERR_RSA_BAD_INPUT_DATA -0x4080 /**< Bad input parameters to function. */ -#define POLARSSL_ERR_RSA_INVALID_PADDING -0x4100 /**< Input data contains invalid padding and is rejected. */ -#define POLARSSL_ERR_RSA_KEY_GEN_FAILED -0x4180 /**< Something failed during generation of a key. */ -#define POLARSSL_ERR_RSA_KEY_CHECK_FAILED -0x4200 /**< Key failed to pass the libraries validity check. */ -#define POLARSSL_ERR_RSA_PUBLIC_FAILED -0x4280 /**< The public key operation failed. */ -#define POLARSSL_ERR_RSA_PRIVATE_FAILED -0x4300 /**< The private key operation failed. */ -#define POLARSSL_ERR_RSA_VERIFY_FAILED -0x4380 /**< The PKCS#1 verification failed. */ -#define POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE -0x4400 /**< The output buffer for decryption is not large enough. */ -#define POLARSSL_ERR_RSA_RNG_FAILED -0x4480 /**< The random generator failed to generate non-zeros. */ - -/* - * PKCS#1 constants - */ -#define SIG_RSA_RAW 0 -#define SIG_RSA_MD2 2 -#define SIG_RSA_MD4 3 -#define SIG_RSA_MD5 4 -#define SIG_RSA_SHA1 5 -#define SIG_RSA_SHA224 14 -#define SIG_RSA_SHA256 11 -#define SIG_RSA_SHA384 12 -#define SIG_RSA_SHA512 13 - -#define RSA_PUBLIC 0 -#define RSA_PRIVATE 1 - -#define RSA_PKCS_V15 0 -#define RSA_PKCS_V21 1 - -#define RSA_SIGN 1 -#define RSA_CRYPT 2 - -#define ASN1_STR_CONSTRUCTED_SEQUENCE "\x30" -#define ASN1_STR_NULL "\x05" -#define ASN1_STR_OID "\x06" -#define ASN1_STR_OCTET_STRING "\x04" - -#define OID_DIGEST_ALG_MDX "\x2A\x86\x48\x86\xF7\x0D\x02\x00" -#define OID_HASH_ALG_SHA1 "\x2b\x0e\x03\x02\x1a" -#define OID_HASH_ALG_SHA2X "\x60\x86\x48\x01\x65\x03\x04\x02\x00" - -#define OID_ISO_MEMBER_BODIES "\x2a" -#define OID_ISO_IDENTIFIED_ORG "\x2b" - -/* - * ISO Member bodies OID parts - */ -#define OID_COUNTRY_US "\x86\x48" -#define OID_RSA_DATA_SECURITY "\x86\xf7\x0d" - -/* - * ISO Identified organization OID parts - */ -#define OID_OIW_SECSIG_SHA1 "\x0e\x03\x02\x1a" - -/* - * DigestInfo ::= SEQUENCE { - * digestAlgorithm DigestAlgorithmIdentifier, - * digest Digest } - * - * DigestAlgorithmIdentifier ::= AlgorithmIdentifier - * - * Digest ::= OCTET STRING - */ -#define ASN1_HASH_MDX \ -( \ - ASN1_STR_CONSTRUCTED_SEQUENCE "\x20" \ - ASN1_STR_CONSTRUCTED_SEQUENCE "\x0C" \ - ASN1_STR_OID "\x08" \ - OID_DIGEST_ALG_MDX \ - ASN1_STR_NULL "\x00" \ - ASN1_STR_OCTET_STRING "\x10" \ -) - -#define ASN1_HASH_SHA1 \ - ASN1_STR_CONSTRUCTED_SEQUENCE "\x21" \ - ASN1_STR_CONSTRUCTED_SEQUENCE "\x09" \ - ASN1_STR_OID "\x05" \ - OID_HASH_ALG_SHA1 \ - ASN1_STR_NULL "\x00" \ - ASN1_STR_OCTET_STRING "\x14" - -#define ASN1_HASH_SHA1_ALT \ - ASN1_STR_CONSTRUCTED_SEQUENCE "\x1F" \ - ASN1_STR_CONSTRUCTED_SEQUENCE "\x07" \ - ASN1_STR_OID "\x05" \ - OID_HASH_ALG_SHA1 \ - ASN1_STR_OCTET_STRING "\x14" - -#define ASN1_HASH_SHA2X \ - ASN1_STR_CONSTRUCTED_SEQUENCE "\x11" \ - ASN1_STR_CONSTRUCTED_SEQUENCE "\x0d" \ - ASN1_STR_OID "\x09" \ - OID_HASH_ALG_SHA2X \ - ASN1_STR_NULL "\x00" \ - ASN1_STR_OCTET_STRING "\x00" - -/** - * \brief RSA context structure - */ -typedef struct -{ - int ver; /*!< always 0 */ - size_t len; /*!< size(N) in chars */ - - mpi N; /*!< public modulus */ - mpi E; /*!< public exponent */ - - mpi D; /*!< private exponent */ - mpi P; /*!< 1st prime factor */ - mpi Q; /*!< 2nd prime factor */ - mpi DP; /*!< D % (P - 1) */ - mpi DQ; /*!< D % (Q - 1) */ - mpi QP; /*!< 1 / (Q % P) */ - - mpi RN; /*!< cached R^2 mod N */ - mpi RP; /*!< cached R^2 mod P */ - mpi RQ; /*!< cached R^2 mod Q */ - - int padding; /*!< RSA_PKCS_V15 for 1.5 padding and - RSA_PKCS_v21 for OAEP/PSS */ - int hash_id; /*!< Hash identifier of md_type_t as - specified in the md.h header file - for the EME-OAEP and EMSA-PSS - encoding */ -} -rsa_context; - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief Initialize an RSA context - * - * Note: Set padding to RSA_PKCS_V21 for the RSAES-OAEP - * encryption scheme and the RSASSA-PSS signature scheme. - * - * \param ctx RSA context to be initialized - * \param padding RSA_PKCS_V15 or RSA_PKCS_V21 - * \param hash_id RSA_PKCS_V21 hash identifier - * - * \note The hash_id parameter is actually ignored - * when using RSA_PKCS_V15 padding. - */ -void rsa_init( rsa_context *ctx, - int padding, - int hash_id); - -/** - * \brief Generate an RSA keypair - * - * \param ctx RSA context that will hold the key - * \param f_rng RNG function - * \param p_rng RNG parameter - * \param nbits size of the public key in bits - * \param exponent public exponent (e.g., 65537) - * - * \note rsa_init() must be called beforehand to setup - * the RSA context. - * - * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code - */ -int rsa_gen_key( rsa_context *ctx, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng, - unsigned int nbits, int exponent ); - -/** - * \brief Check a public RSA key - * - * \param ctx RSA context to be checked - * - * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code - */ -int rsa_check_pubkey( const rsa_context *ctx ); - -/** - * \brief Check a private RSA key - * - * \param ctx RSA context to be checked - * - * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code - */ -int rsa_check_privkey( const rsa_context *ctx ); - -/** - * \brief Do an RSA public key operation - * - * \param ctx RSA context - * \param input input buffer - * \param output output buffer - * - * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code - * - * \note This function does NOT take care of message - * padding. Also, be sure to set input[0] = 0 or assure that - * input is smaller than N. - * - * \note The input and output buffers must be large - * enough (eg. 128 bytes if RSA-1024 is used). - */ -int rsa_public( rsa_context *ctx, - const unsigned char *input, - unsigned char *output ); - -/** - * \brief Do an RSA private key operation - * - * \param ctx RSA context - * \param input input buffer - * \param output output buffer - * - * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code - * - * \note The input and output buffers must be large - * enough (eg. 128 bytes if RSA-1024 is used). - */ -int rsa_private( rsa_context *ctx, - const unsigned char *input, - unsigned char *output ); - -/** - * \brief Generic wrapper to perform a PKCS#1 encryption using the - * mode from the context. Add the message padding, then do an - * RSA operation. - * - * \param ctx RSA context - * \param f_rng RNG function (Needed for padding and PKCS#1 v2.1 encoding) - * \param p_rng RNG parameter - * \param mode RSA_PUBLIC or RSA_PRIVATE - * \param ilen contains the plaintext length - * \param input buffer holding the data to be encrypted - * \param output buffer that will hold the ciphertext - * - * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code - * - * \note The output buffer must be as large as the size - * of ctx->N (eg. 128 bytes if RSA-1024 is used). - */ -int rsa_pkcs1_encrypt( rsa_context *ctx, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng, - int mode, size_t ilen, - const unsigned char *input, - unsigned char *output ); - -/** - * \brief Perform a PKCS#1 v1.5 encryption (RSAES-PKCS1-v1_5-ENCRYPT) - * - * \param ctx RSA context - * \param f_rng RNG function (Needed for padding) - * \param p_rng RNG parameter - * \param mode RSA_PUBLIC or RSA_PRIVATE - * \param ilen contains the plaintext length - * \param input buffer holding the data to be encrypted - * \param output buffer that will hold the ciphertext - * - * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code - * - * \note The output buffer must be as large as the size - * of ctx->N (eg. 128 bytes if RSA-1024 is used). - */ -int rsa_rsaes_pkcs1_v15_encrypt( rsa_context *ctx, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng, - int mode, size_t ilen, - const unsigned char *input, - unsigned char *output ); - -/** - * \brief Perform a PKCS#1 v2.1 OAEP encryption (RSAES-OAEP-ENCRYPT) - * - * \param ctx RSA context - * \param f_rng RNG function (Needed for padding and PKCS#1 v2.1 encoding) - * \param p_rng RNG parameter - * \param mode RSA_PUBLIC or RSA_PRIVATE - * \param label buffer holding the custom label to use - * \param label_len contains the label length - * \param ilen contains the plaintext length - * \param input buffer holding the data to be encrypted - * \param output buffer that will hold the ciphertext - * - * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code - * - * \note The output buffer must be as large as the size - * of ctx->N (eg. 128 bytes if RSA-1024 is used). - */ -int rsa_rsaes_oaep_encrypt( rsa_context *ctx, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng, - int mode, - const unsigned char *label, size_t label_len, - size_t ilen, - const unsigned char *input, - unsigned char *output ); - -/** - * \brief Generic wrapper to perform a PKCS#1 decryption using the - * mode from the context. Do an RSA operation, then remove - * the message padding - * - * \param ctx RSA context - * \param mode RSA_PUBLIC or RSA_PRIVATE - * \param olen will contain the plaintext length - * \param input buffer holding the encrypted data - * \param output buffer that will hold the plaintext - * \param output_max_len maximum length of the output buffer - * - * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code - * - * \note The output buffer must be as large as the size - * of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise - * an error is thrown. - */ -int rsa_pkcs1_decrypt( rsa_context *ctx, - int mode, size_t *olen, - const unsigned char *input, - unsigned char *output, - size_t output_max_len ); - -/** - * \brief Perform a PKCS#1 v1.5 decryption (RSAES-PKCS1-v1_5-DECRYPT) - * - * \param ctx RSA context - * \param mode RSA_PUBLIC or RSA_PRIVATE - * \param olen will contain the plaintext length - * \param input buffer holding the encrypted data - * \param output buffer that will hold the plaintext - * \param output_max_len maximum length of the output buffer - * - * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code - * - * \note The output buffer must be as large as the size - * of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise - * an error is thrown. - */ -int rsa_rsaes_pkcs1_v15_decrypt( rsa_context *ctx, - int mode, size_t *olen, - const unsigned char *input, - unsigned char *output, - size_t output_max_len ); - -/** - * \brief Perform a PKCS#1 v2.1 OAEP decryption (RSAES-OAEP-DECRYPT) - * - * \param ctx RSA context - * \param mode RSA_PUBLIC or RSA_PRIVATE - * \param label buffer holding the custom label to use - * \param label_len contains the label length - * \param olen will contain the plaintext length - * \param input buffer holding the encrypted data - * \param output buffer that will hold the plaintext - * \param output_max_len maximum length of the output buffer - * - * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code - * - * \note The output buffer must be as large as the size - * of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise - * an error is thrown. - */ -int rsa_rsaes_oaep_decrypt( rsa_context *ctx, - int mode, - const unsigned char *label, size_t label_len, - size_t *olen, - const unsigned char *input, - unsigned char *output, - size_t output_max_len ); - -/** - * \brief Generic wrapper to perform a PKCS#1 signature using the - * mode from the context. Do a private RSA operation to sign - * a message digest - * - * \param ctx RSA context - * \param f_rng RNG function (Needed for PKCS#1 v2.1 encoding) - * \param p_rng RNG parameter - * \param mode RSA_PUBLIC or RSA_PRIVATE - * \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512} - * \param hashlen message digest length (for SIG_RSA_RAW only) - * \param hash buffer holding the message digest - * \param sig buffer that will hold the ciphertext - * - * \return 0 if the signing operation was successful, - * or an POLARSSL_ERR_RSA_XXX error code - * - * \note The "sig" buffer must be as large as the size - * of ctx->N (eg. 128 bytes if RSA-1024 is used). - * - * \note In case of PKCS#1 v2.1 encoding keep in mind that - * the hash_id in the RSA context is the one used for the - * encoding. hash_id in the function call is the type of hash - * that is encoded. According to RFC 3447 it is advised to - * keep both hashes the same. - */ -int rsa_pkcs1_sign( rsa_context *ctx, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng, - int mode, - int hash_id, - unsigned int hashlen, - const unsigned char *hash, - unsigned char *sig ); - -/** - * \brief Perform a PKCS#1 v1.5 signature (RSASSA-PKCS1-v1_5-SIGN) - * - * \param ctx RSA context - * \param mode RSA_PUBLIC or RSA_PRIVATE - * \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512} - * \param hashlen message digest length (for SIG_RSA_RAW only) - * \param hash buffer holding the message digest - * \param sig buffer that will hold the ciphertext - * - * \return 0 if the signing operation was successful, - * or an POLARSSL_ERR_RSA_XXX error code - * - * \note The "sig" buffer must be as large as the size - * of ctx->N (eg. 128 bytes if RSA-1024 is used). - */ -int rsa_rsassa_pkcs1_v15_sign( rsa_context *ctx, - int mode, - int hash_id, - unsigned int hashlen, - const unsigned char *hash, - unsigned char *sig ); - -/** - * \brief Perform a PKCS#1 v2.1 PSS signature (RSASSA-PSS-SIGN) - * - * \param ctx RSA context - * \param f_rng RNG function (Needed for PKCS#1 v2.1 encoding) - * \param p_rng RNG parameter - * \param mode RSA_PUBLIC or RSA_PRIVATE - * \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512} - * \param hashlen message digest length (for SIG_RSA_RAW only) - * \param hash buffer holding the message digest - * \param sig buffer that will hold the ciphertext - * - * \return 0 if the signing operation was successful, - * or an POLARSSL_ERR_RSA_XXX error code - * - * \note The "sig" buffer must be as large as the size - * of ctx->N (eg. 128 bytes if RSA-1024 is used). - * - * \note In case of PKCS#1 v2.1 encoding keep in mind that - * the hash_id in the RSA context is the one used for the - * encoding. hash_id in the function call is the type of hash - * that is encoded. According to RFC 3447 it is advised to - * keep both hashes the same. - */ -int rsa_rsassa_pss_sign( rsa_context *ctx, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng, - int mode, - int hash_id, - unsigned int hashlen, - const unsigned char *hash, - unsigned char *sig ); - -/** - * \brief Generic wrapper to perform a PKCS#1 verification using the - * mode from the context. Do a public RSA operation and check - * the message digest - * - * \param ctx points to an RSA public key - * \param mode RSA_PUBLIC or RSA_PRIVATE - * \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512} - * \param hashlen message digest length (for SIG_RSA_RAW only) - * \param hash buffer holding the message digest - * \param sig buffer holding the ciphertext - * - * \return 0 if the verify operation was successful, - * or an POLARSSL_ERR_RSA_XXX error code - * - * \note The "sig" buffer must be as large as the size - * of ctx->N (eg. 128 bytes if RSA-1024 is used). - * - * \note In case of PKCS#1 v2.1 encoding keep in mind that - * the hash_id in the RSA context is the one used for the - * verification. hash_id in the function call is the type of hash - * that is verified. According to RFC 3447 it is advised to - * keep both hashes the same. - */ -int rsa_pkcs1_verify( rsa_context *ctx, - int mode, - int hash_id, - unsigned int hashlen, - const unsigned char *hash, - unsigned char *sig ); - -/** - * \brief Perform a PKCS#1 v1.5 verification (RSASSA-PKCS1-v1_5-VERIFY) - * - * \param ctx points to an RSA public key - * \param mode RSA_PUBLIC or RSA_PRIVATE - * \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512} - * \param hashlen message digest length (for SIG_RSA_RAW only) - * \param hash buffer holding the message digest - * \param sig buffer holding the ciphertext - * - * \return 0 if the verify operation was successful, - * or an POLARSSL_ERR_RSA_XXX error code - * - * \note The "sig" buffer must be as large as the size - * of ctx->N (eg. 128 bytes if RSA-1024 is used). - */ -int rsa_rsassa_pkcs1_v15_verify( rsa_context *ctx, - int mode, - int hash_id, - unsigned int hashlen, - const unsigned char *hash, - unsigned char *sig ); - -/** - * \brief Perform a PKCS#1 v2.1 PSS verification (RSASSA-PSS-VERIFY) - * \brief Do a public RSA and check the message digest - * - * \param ctx points to an RSA public key - * \param mode RSA_PUBLIC or RSA_PRIVATE - * \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512} - * \param hashlen message digest length (for SIG_RSA_RAW only) - * \param hash buffer holding the message digest - * \param sig buffer holding the ciphertext - * - * \return 0 if the verify operation was successful, - * or an POLARSSL_ERR_RSA_XXX error code - * - * \note The "sig" buffer must be as large as the size - * of ctx->N (eg. 128 bytes if RSA-1024 is used). - * - * \note In case of PKCS#1 v2.1 encoding keep in mind that - * the hash_id in the RSA context is the one used for the - * verification. hash_id in the function call is the type of hash - * that is verified. According to RFC 3447 it is advised to - * keep both hashes the same. - */ -int rsa_rsassa_pss_verify( rsa_context *ctx, - int mode, - int hash_id, - unsigned int hashlen, - const unsigned char *hash, - unsigned char *sig ); - -/** - * \brief Free the components of an RSA key - * - * \param ctx RSA Context to free - */ -void rsa_free( rsa_context *ctx ); - -/** - * \brief Checkup routine - * - * \return 0 if successful, or 1 if the test failed - */ -int rsa_self_test( int verbose ); - -#ifdef __cplusplus -} -#endif - -#endif /* rsa.h */ diff --git a/common/polarssl/sha1.h b/common/polarssl/sha1.h deleted file mode 100644 index 01cb69b7..00000000 --- a/common/polarssl/sha1.h +++ /dev/null @@ -1,180 +0,0 @@ -/** - * \file sha1.h - * - * \brief SHA-1 cryptographic hash function - * - * Copyright (C) 2006-2013, Brainspark B.V. - * - * This file is part of PolarSSL (http://www.polarssl.org) - * Lead Maintainer: Paul Bakker - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -#ifndef POLARSSL_SHA1_H -#define POLARSSL_SHA1_H - -#include "polarssl_config.h" - -#include - -#ifdef _MSC_VER -#include -typedef UINT32 uint32_t; -#else -#include -#endif - -#define POLARSSL_ERR_SHA1_FILE_IO_ERROR -0x0076 /**< Read/write error in file. */ - -#if !defined(POLARSSL_SHA1_ALT) -// Regular implementation -// - -/** - * \brief SHA-1 context structure - */ -typedef struct -{ - uint32_t total[2]; /*!< number of bytes processed */ - uint32_t state[5]; /*!< intermediate digest state */ - unsigned char buffer[64]; /*!< data block being processed */ - - unsigned char ipad[64]; /*!< HMAC: inner padding */ - unsigned char opad[64]; /*!< HMAC: outer padding */ -} -sha1_context; - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief SHA-1 context setup - * - * \param ctx context to be initialized - */ -void sha1_starts( sha1_context *ctx ); - -/** - * \brief SHA-1 process buffer - * - * \param ctx SHA-1 context - * \param input buffer holding the data - * \param ilen length of the input data - */ -void sha1_update( sha1_context *ctx, const unsigned char *input, size_t ilen ); - -/** - * \brief SHA-1 final digest - * - * \param ctx SHA-1 context - * \param output SHA-1 checksum result - */ -void sha1_finish( sha1_context *ctx, unsigned char output[20] ); - -/* Internal use */ -void sha1_process( sha1_context *ctx, const unsigned char data[64] ); - -#ifdef __cplusplus -} -#endif - -#else /* POLARSSL_SHA1_ALT */ -#include "sha1_alt.h" -#endif /* POLARSSL_SHA1_ALT */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief Output = SHA-1( input buffer ) - * - * \param input buffer holding the data - * \param ilen length of the input data - * \param output SHA-1 checksum result - */ -void sha1( const unsigned char *input, size_t ilen, unsigned char output[20] ); - -/** - * \brief Output = SHA-1( file contents ) - * - * \param path input file name - * \param output SHA-1 checksum result - * - * \return 0 if successful, or POLARSSL_ERR_SHA1_FILE_IO_ERROR - */ -int sha1_file( const char *path, unsigned char output[20] ); - -/** - * \brief SHA-1 HMAC context setup - * - * \param ctx HMAC context to be initialized - * \param key HMAC secret key - * \param keylen length of the HMAC key - */ -void sha1_hmac_starts( sha1_context *ctx, const unsigned char *key, size_t keylen ); - -/** - * \brief SHA-1 HMAC process buffer - * - * \param ctx HMAC context - * \param input buffer holding the data - * \param ilen length of the input data - */ -void sha1_hmac_update( sha1_context *ctx, const unsigned char *input, size_t ilen ); - -/** - * \brief SHA-1 HMAC final digest - * - * \param ctx HMAC context - * \param output SHA-1 HMAC checksum result - */ -void sha1_hmac_finish( sha1_context *ctx, unsigned char output[20] ); - -/** - * \brief SHA-1 HMAC context reset - * - * \param ctx HMAC context to be reset - */ -void sha1_hmac_reset( sha1_context *ctx ); - -/** - * \brief Output = HMAC-SHA-1( hmac key, input buffer ) - * - * \param key HMAC secret key - * \param keylen length of the HMAC key - * \param input buffer holding the data - * \param ilen length of the input data - * \param output HMAC-SHA-1 result - */ -void sha1_hmac( const unsigned char *key, size_t keylen, - const unsigned char *input, size_t ilen, - unsigned char output[20] ); - -/** - * \brief Checkup routine - * - * \return 0 if successful, or 1 if the test failed - */ -int sha1_self_test( int verbose ); - -#ifdef __cplusplus -} -#endif - -#endif /* sha1.h */ diff --git a/travis_test_commands.scr b/travis_test_commands.scr new file mode 100644 index 00000000..4f5b025c --- /dev/null +++ b/travis_test_commands.scr @@ -0,0 +1,3 @@ +hf mf hardnested t 1 000000000000 +hf emv test +exit From e0991f6aa7bf7b193080855bb818ce193542c6dc Mon Sep 17 00:00:00 2001 From: Oleg Moiseenko <807634+merlokk@users.noreply.github.com> Date: Fri, 23 Nov 2018 20:03:46 +0200 Subject: [PATCH 019/189] Get rid of polarssl (#717) --- armsrc/Makefile | 4 +- armsrc/mifareutil.c | 22 +- client/Makefile | 1 - client/cmdhficlass.c | 14 +- client/loclass/elite_crack.c | 24 +- client/loclass/ikeys.c | 24 +- client/obj/polarssl/.dummy | 0 common/Makefile.common | 2 +- common/mbedtls/platform_util_arm.c | 68 + common/mbedtls/platform_util_arm.h | 64 + common/polarssl/des.c | 1014 ------------- common/polarssl/des.h | 281 ---- common/polarssl/polarssl_config.h | 2179 ---------------------------- 13 files changed, 178 insertions(+), 3519 deletions(-) delete mode 100644 client/obj/polarssl/.dummy create mode 100644 common/mbedtls/platform_util_arm.c create mode 100644 common/mbedtls/platform_util_arm.h delete mode 100644 common/polarssl/des.c delete mode 100644 common/polarssl/des.h delete mode 100644 common/polarssl/polarssl_config.h diff --git a/armsrc/Makefile b/armsrc/Makefile index d230cda1..7348fda6 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -24,7 +24,8 @@ SRC_LF = lfops.c hitag2.c hitagS.c lfsampling.c pcf7931.c lfdemod.c protocols.c SRC_ISO15693 = iso15693.c iso15693tools.c SRC_ISO14443a = epa.c iso14443a.c mifareutil.c mifarecmd.c mifaresniff.c mifaresim.c SRC_ISO14443b = iso14443b.c -SRC_CRAPTO1 = crypto1.c des.c +SRC_CRAPTO1 = crypto1.c +SRC_DES = platform_util_arm.c des.c SRC_CRC = iso14443crc.c crc.c crc16.c crc32.c parity.c SRC_SMARTCARD = i2c.c @@ -61,6 +62,7 @@ ARMSRC = fpgaloader.c \ $(SRC_ISO14443a) \ $(SRC_ISO14443b) \ $(SRC_CRAPTO1) \ + $(SRC_DES) \ $(SRC_CRC) \ iclass.c \ BigBuf.c \ diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index 684b5e36..4b1f16f3 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -21,7 +21,7 @@ #include "iso14443crc.h" #include "iso14443a.h" #include "crapto1/crapto1.h" -#include "polarssl/des.h" +#include "mbedtls/des.h" int MF_DBGLEVEL = MF_DBG_ALL; @@ -296,7 +296,7 @@ int mifare_ultra_auth(uint8_t *keybytes){ /// 3des2k - des3_context ctx = { 0x00 }; + mbedtls_des3_context ctx = { 0x00 }; uint8_t random_a[8] = {1,1,1,1,1,1,1,1}; uint8_t random_b[8] = {0x00}; uint8_t enc_random_b[8] = {0x00}; @@ -321,9 +321,9 @@ int mifare_ultra_auth(uint8_t *keybytes){ // decrypt nonce. // tdes_2key_dec(random_b, enc_random_b, sizeof(random_b), key, IV ); - des3_set2key_dec(&ctx, key); - des3_crypt_cbc(&ctx // des3_context - , DES_DECRYPT // int mode + mbedtls_des3_set2key_dec(&ctx, key); + mbedtls_des3_crypt_cbc(&ctx // des3_context + , MBEDTLS_DES_DECRYPT // int mode , sizeof(random_b) // length , IV // iv[8] , enc_random_b // input @@ -350,9 +350,9 @@ int mifare_ultra_auth(uint8_t *keybytes){ // encrypt out, in, length, key, iv //tdes_2key_enc(rnd_ab, rnd_ab, sizeof(rnd_ab), key, enc_random_b); - des3_set2key_enc(&ctx, key); - des3_crypt_cbc(&ctx // des3_context - , DES_ENCRYPT // int mode + mbedtls_des3_set2key_enc(&ctx, key); + mbedtls_des3_crypt_cbc(&ctx // des3_context + , MBEDTLS_DES_ENCRYPT // int mode , sizeof(rnd_ab) // length , enc_random_b // iv[8] , rnd_ab // input @@ -372,9 +372,9 @@ int mifare_ultra_auth(uint8_t *keybytes){ // decrypt out, in, length, key, iv // tdes_2key_dec(resp_random_a, enc_resp, 8, key, enc_random_b); - des3_set2key_dec(&ctx, key); - des3_crypt_cbc(&ctx // des3_context - , DES_DECRYPT // int mode + mbedtls_des3_set2key_dec(&ctx, key); + mbedtls_des3_crypt_cbc(&ctx // des3_context + , MBEDTLS_DES_DECRYPT // int mode , 8 // length , enc_random_b // iv[8] , enc_resp // input diff --git a/client/Makefile b/client/Makefile index bf884f1f..a049ae5a 100644 --- a/client/Makefile +++ b/client/Makefile @@ -107,7 +107,6 @@ CORESRCS = uart_posix.c \ CMDSRCS = $(SRC_SMARTCARD) \ crapto1/crapto1.c\ crapto1/crypto1.c\ - polarssl/des.c\ crypto/libpcrypto.c\ crypto/asn1utils.c\ cliparser/argtable3.c\ diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index 499f7aae..c97e433c 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -23,7 +23,7 @@ #include "common.h" #include "util.h" #include "cmdmain.h" -#include "polarssl/des.h" +#include "mbedtls/des.h" #include "loclass/cipherutils.h" #include "loclass/cipher.h" #include "loclass/ikeys.h" @@ -414,8 +414,8 @@ int CmdHFiClassDecrypt(const char *Cmd) { fseek(f, 0, SEEK_SET); uint8_t enc_dump[8] = {0}; uint8_t *decrypted = malloc(fsize); - des3_context ctx = { DES_DECRYPT ,{ 0 } }; - des3_set2key_dec( &ctx, key); + mbedtls_des3_context ctx = { 0 }; + mbedtls_des3_set2key_dec( &ctx, key); size_t bytes_read = fread(enc_dump, 1, 8, f); //Use the first block (CSN) for filename @@ -431,7 +431,7 @@ int CmdHFiClassDecrypt(const char *Cmd) { { memcpy(decrypted+(blocknum*8), enc_dump, 8); }else{ - des3_crypt_ecb(&ctx, enc_dump,decrypted +(blocknum*8) ); + mbedtls_des3_crypt_ecb(&ctx, enc_dump,decrypted +(blocknum*8) ); } printvar("decrypted block", decrypted +(blocknum*8), 8); bytes_read = fread(enc_dump, 1, 8, f); @@ -466,10 +466,10 @@ static int iClassEncryptBlkData(uint8_t *blkData) { uint8_t encryptedData[16]; uint8_t *encrypted = encryptedData; - des3_context ctx = { DES_DECRYPT ,{ 0 } }; - des3_set2key_enc( &ctx, key); + mbedtls_des3_context ctx = { 0 }; + mbedtls_des3_set2key_enc( &ctx, key); - des3_crypt_ecb(&ctx, blkData,encrypted); + mbedtls_des3_crypt_ecb(&ctx, blkData,encrypted); //printvar("decrypted block", decrypted, 8); memcpy(blkData,encrypted,8); diff --git a/client/loclass/elite_crack.c b/client/loclass/elite_crack.c index fe9bf7d1..f45c55b5 100644 --- a/client/loclass/elite_crack.c +++ b/client/loclass/elite_crack.c @@ -46,7 +46,7 @@ #include "ikeys.h" #include "elite_crack.h" #include "fileutils.h" -#include "polarssl/des.h" +#include "mbedtls/des.h" /** * @brief Permutes a key from standard NIST format to Iclass specific format @@ -179,22 +179,22 @@ void rk(uint8_t *key, uint8_t n, uint8_t *outp_key) return; } -static des_context ctx_enc = {DES_ENCRYPT,{0}}; -static des_context ctx_dec = {DES_DECRYPT,{0}}; +static mbedtls_des_context ctx_enc = {0}; +static mbedtls_des_context ctx_dec = {0}; void desdecrypt_iclass(uint8_t *iclass_key, uint8_t *input, uint8_t *output) { uint8_t key_std_format[8] = {0}; permutekey_rev(iclass_key, key_std_format); - des_setkey_dec( &ctx_dec, key_std_format); - des_crypt_ecb(&ctx_dec,input,output); + mbedtls_des_setkey_dec( &ctx_dec, key_std_format); + mbedtls_des_crypt_ecb(&ctx_dec,input,output); } void desencrypt_iclass(uint8_t *iclass_key, uint8_t *input, uint8_t *output) { uint8_t key_std_format[8] = {0}; permutekey_rev(iclass_key, key_std_format); - des_setkey_enc( &ctx_enc, key_std_format); - des_crypt_ecb(&ctx_enc,input,output); + mbedtls_des_setkey_enc( &ctx_enc, key_std_format); + mbedtls_des_crypt_ecb(&ctx_enc,input,output); } /** @@ -449,7 +449,7 @@ int bruteforceItem(dumpdata item, uint16_t keytable[]) */ int calculateMasterKey(uint8_t first16bytes[], uint64_t master_key[] ) { - des_context ctx_e = {DES_ENCRYPT,{0}}; + mbedtls_des_context ctx_e = {0}; uint8_t z_0[8] = {0}; uint8_t y_0[8] = {0}; @@ -468,8 +468,8 @@ int calculateMasterKey(uint8_t first16bytes[], uint64_t master_key[] ) permutekey_rev(z_0, z_0_rev); // ~K_cus = DESenc(z[0], y[0]) - des_setkey_enc( &ctx_e, z_0_rev ); - des_crypt_ecb(&ctx_e, y_0, key64_negated); + mbedtls_des_setkey_enc( &ctx_e, z_0_rev ); + mbedtls_des_crypt_ecb(&ctx_e, y_0, key64_negated); int i; for(i = 0; i < 8 ; i++) @@ -482,8 +482,8 @@ int calculateMasterKey(uint8_t first16bytes[], uint64_t master_key[] ) uint8_t key64_stdformat[8] = {0}; permutekey_rev(key64, key64_stdformat); - des_setkey_enc( &ctx_e, key64_stdformat ); - des_crypt_ecb(&ctx_e, key64_negated, result); + mbedtls_des_setkey_enc( &ctx_e, key64_stdformat ); + mbedtls_des_crypt_ecb(&ctx_e, key64_negated, result); prnlog("\nHigh security custom key (Kcus):"); printvar("Std format ", key64_stdformat,8); printvar("Iclass format", key64,8); diff --git a/client/loclass/ikeys.c b/client/loclass/ikeys.c index 2a6a0010..3f90d6ee 100644 --- a/client/loclass/ikeys.c +++ b/client/loclass/ikeys.c @@ -68,12 +68,12 @@ From "Dismantling iclass": #include #include "fileutils.h" #include "cipherutils.h" -#include "polarssl/des.h" +#include "mbedtls/des.h" uint8_t pi[35] = {0x0F,0x17,0x1B,0x1D,0x1E,0x27,0x2B,0x2D,0x2E,0x33,0x35,0x39,0x36,0x3A,0x3C,0x47,0x4B,0x4D,0x4E,0x53,0x55,0x56,0x59,0x5A,0x5C,0x63,0x65,0x66,0x69,0x6A,0x6C,0x71,0x72,0x74,0x78}; -static des_context ctx_enc = {DES_ENCRYPT,{0}}; -static des_context ctx_dec = {DES_DECRYPT,{0}}; +static mbedtls_des_context ctx_enc = {0}; +static mbedtls_des_context ctx_dec = {0}; static int debug_print = 0; @@ -393,12 +393,12 @@ void diversifyKey(uint8_t csn[8], uint8_t key[8], uint8_t div_key[8]) { // Prepare the DES key - des_setkey_enc( &ctx_enc, key); + mbedtls_des_setkey_enc( &ctx_enc, key); uint8_t crypted_csn[8] = {0}; // Calculate DES(CSN, KEY) - des_crypt_ecb(&ctx_enc,csn, crypted_csn); + mbedtls_des_crypt_ecb(&ctx_enc,csn, crypted_csn); //Calculate HASH0(DES)) uint64_t crypt_csn = x_bytes_to_num(crypted_csn, 8); @@ -466,13 +466,13 @@ typedef struct } Testcase; -int testDES(Testcase testcase, des_context ctx_enc, des_context ctx_dec) +int testDES(Testcase testcase, mbedtls_des_context ctx_enc, mbedtls_des_context ctx_dec) { uint8_t des_encrypted_csn[8] = {0}; uint8_t decrypted[8] = {0}; uint8_t div_key[8] = {0}; - int retval = des_crypt_ecb(&ctx_enc,testcase.uid,des_encrypted_csn); - retval |= des_crypt_ecb(&ctx_dec,des_encrypted_csn,decrypted); + int retval = mbedtls_des_crypt_ecb(&ctx_enc,testcase.uid,des_encrypted_csn); + retval |= mbedtls_des_crypt_ecb(&ctx_dec,des_encrypted_csn,decrypted); if(memcmp(testcase.uid,decrypted,8) != 0) { @@ -678,7 +678,7 @@ int testDES2(uint64_t csn, uint64_t expected) print64bits(" csn ", csn); x_num_to_bytes(csn, 8,input); - des_crypt_ecb(&ctx_enc,input, result); + mbedtls_des_crypt_ecb(&ctx_enc,input, result); uint64_t crypt_csn = x_bytes_to_num(result, 8); print64bits(" {csn} ", crypt_csn ); @@ -709,7 +709,7 @@ int doTestsWithKnownInputs() prnlog("[+] Testing foo"); uint8_t key[8] = {0x6c,0x8d,0x44,0xf9,0x2a,0x2d,0x01,0xbf}; - des_setkey_enc( &ctx_enc, key); + mbedtls_des_setkey_enc( &ctx_enc, key); testDES2(0xbbbbaaaabbbbeeee,0xd6ad3ca619659e6b); prnlog("[+] Testing hashing algorithm"); @@ -776,8 +776,8 @@ int doKeyTests(uint8_t debuglevel) prnlog("[+] Checking key parity..."); des_checkParity(key); - des_setkey_enc( &ctx_enc, key); - des_setkey_dec( &ctx_dec, key); + mbedtls_des_setkey_enc( &ctx_enc, key); + mbedtls_des_setkey_dec( &ctx_dec, key); // Test hashing functions prnlog("[+] The following tests require the correct 8-byte master key"); testKeyDiversificationWithMasterkeyTestcases(); diff --git a/client/obj/polarssl/.dummy b/client/obj/polarssl/.dummy deleted file mode 100644 index e69de29b..00000000 diff --git a/common/Makefile.common b/common/Makefile.common index 0ab89b3d..952a5b9a 100644 --- a/common/Makefile.common +++ b/common/Makefile.common @@ -63,7 +63,7 @@ endif # Also search prerequisites in the common directory (for usb.c), the fpga directory (for fpga.bit), and the zlib directory -VPATH = . ../common ../common/crapto1 ../common/polarssl ../fpga ../zlib +VPATH = . ../common ../common/crapto1 ../common/mbedtls ../fpga ../zlib INCLUDES = ../include/proxmark3.h ../include/at91sam7s512.h ../include/config_gpio.h ../include/usb_cmd.h $(APP_INCLUDES) diff --git a/common/mbedtls/platform_util_arm.c b/common/mbedtls/platform_util_arm.c new file mode 100644 index 00000000..13f3be00 --- /dev/null +++ b/common/mbedtls/platform_util_arm.c @@ -0,0 +1,68 @@ +/* + * Common and shared functions used by multiple modules in the Mbed TLS + * library. + * + * Copyright (C) 2018, Arm Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "mbedtls/platform_util.h" + +#include +#include + +#if !defined(MBEDTLS_PLATFORM_ZEROIZE_ALT) +/* + * This implementation should never be optimized out by the compiler + * + * This implementation for mbedtls_platform_zeroize() was inspired from Colin + * Percival's blog article at: + * + * http://www.daemonology.net/blog/2014-09-04-how-to-zero-a-buffer.html + * + * It uses a volatile function pointer to the standard memset(). Because the + * pointer is volatile the compiler expects it to change at + * any time and will not optimize out the call that could potentially perform + * other operations on the input buffer instead of just setting it to 0. + * Nevertheless, as pointed out by davidtgoldblatt on Hacker News + * (refer to http://www.daemonology.net/blog/2014-09-05-erratum.html for + * details), optimizations of the following form are still possible: + * + * if( memset_func != memset ) + * memset_func( buf, 0, len ); + * + * Note that it is extremely difficult to guarantee that + * mbedtls_platform_zeroize() will not be optimized out by aggressive compilers + * in a portable way. For this reason, Mbed TLS also provides the configuration + * option MBEDTLS_PLATFORM_ZEROIZE_ALT, which allows users to configure + * mbedtls_platform_zeroize() to use a suitable implementation for their + * platform and needs. + */ + +void mbedtls_platform_zeroize( void *buf, size_t len ) +{ + memset( buf, 0, len ); +} +#endif /* MBEDTLS_PLATFORM_ZEROIZE_ALT */ diff --git a/common/mbedtls/platform_util_arm.h b/common/mbedtls/platform_util_arm.h new file mode 100644 index 00000000..79404ce6 --- /dev/null +++ b/common/mbedtls/platform_util_arm.h @@ -0,0 +1,64 @@ +/** + * \file platform_util.h + * + * \brief Common and shared functions used by multiple modules in the Mbed TLS + * library. + */ +/* + * Copyright (C) 2018, Arm Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of Mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_PLATFORM_UTIL_H +#define MBEDTLS_PLATFORM_UTIL_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Securely zeroize a buffer + * + * The function is meant to wipe the data contained in a buffer so + * that it can no longer be recovered even if the program memory + * is later compromised. Call this function on sensitive data + * stored on the stack before returning from a function, and on + * sensitive data stored on the heap before freeing the heap + * object. + * + * It is extremely difficult to guarantee that calls to + * mbedtls_platform_zeroize() are not removed by aggressive + * compiler optimizations in a portable way. For this reason, Mbed + * TLS provides the configuration option + * MBEDTLS_PLATFORM_ZEROIZE_ALT, which allows users to configure + * mbedtls_platform_zeroize() to use a suitable implementation for + * their platform and needs + * + * \param buf Buffer to be zeroized + * \param len Length of the buffer in bytes + * + */ +void mbedtls_platform_zeroize( void *buf, size_t len ); + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_PLATFORM_UTIL_H */ diff --git a/common/polarssl/des.c b/common/polarssl/des.c deleted file mode 100644 index b33deb6c..00000000 --- a/common/polarssl/des.c +++ /dev/null @@ -1,1014 +0,0 @@ -/* - * FIPS-46-3 compliant Triple-DES implementation - * - * Copyright (C) 2006-2014, Brainspark B.V. - * - * This file is part of PolarSSL (http://www.polarssl.org) - * Lead Maintainer: Paul Bakker - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/* - * DES, on which TDES is based, was originally designed by Horst Feistel - * at IBM in 1974, and was adopted as a standard by NIST (formerly NBS). - * - * http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf - */ - -#include "polarssl_config.h" -#define POLARSSL_DES_C - -#if defined(POLARSSL_DES_C) - -#include "des.h" - -#if defined(POLARSSL_PLATFORM_C) -#include "polarssl/platform.h" -#else -#define polarssl_printf printf -#endif - -#if !defined(POLARSSL_DES_ALT) - -/* - * 32-bit integer manipulation macros (big endian) - */ -#ifndef GET_UINT32_BE -#define GET_UINT32_BE(n,b,i) \ -{ \ - (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ - | ( (uint32_t) (b)[(i) + 1] << 16 ) \ - | ( (uint32_t) (b)[(i) + 2] << 8 ) \ - | ( (uint32_t) (b)[(i) + 3] ); \ -} -#endif - -#ifndef PUT_UINT32_BE -#define PUT_UINT32_BE(n,b,i) \ -{ \ - (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ - (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ - (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ - (b)[(i) + 3] = (unsigned char) ( (n) ); \ -} -#endif - -/* - * Expanded DES S-boxes - */ -static const uint32_t SB1[64] = -{ - 0x01010400, 0x00000000, 0x00010000, 0x01010404, - 0x01010004, 0x00010404, 0x00000004, 0x00010000, - 0x00000400, 0x01010400, 0x01010404, 0x00000400, - 0x01000404, 0x01010004, 0x01000000, 0x00000004, - 0x00000404, 0x01000400, 0x01000400, 0x00010400, - 0x00010400, 0x01010000, 0x01010000, 0x01000404, - 0x00010004, 0x01000004, 0x01000004, 0x00010004, - 0x00000000, 0x00000404, 0x00010404, 0x01000000, - 0x00010000, 0x01010404, 0x00000004, 0x01010000, - 0x01010400, 0x01000000, 0x01000000, 0x00000400, - 0x01010004, 0x00010000, 0x00010400, 0x01000004, - 0x00000400, 0x00000004, 0x01000404, 0x00010404, - 0x01010404, 0x00010004, 0x01010000, 0x01000404, - 0x01000004, 0x00000404, 0x00010404, 0x01010400, - 0x00000404, 0x01000400, 0x01000400, 0x00000000, - 0x00010004, 0x00010400, 0x00000000, 0x01010004 -}; - -static const uint32_t SB2[64] = -{ - 0x80108020, 0x80008000, 0x00008000, 0x00108020, - 0x00100000, 0x00000020, 0x80100020, 0x80008020, - 0x80000020, 0x80108020, 0x80108000, 0x80000000, - 0x80008000, 0x00100000, 0x00000020, 0x80100020, - 0x00108000, 0x00100020, 0x80008020, 0x00000000, - 0x80000000, 0x00008000, 0x00108020, 0x80100000, - 0x00100020, 0x80000020, 0x00000000, 0x00108000, - 0x00008020, 0x80108000, 0x80100000, 0x00008020, - 0x00000000, 0x00108020, 0x80100020, 0x00100000, - 0x80008020, 0x80100000, 0x80108000, 0x00008000, - 0x80100000, 0x80008000, 0x00000020, 0x80108020, - 0x00108020, 0x00000020, 0x00008000, 0x80000000, - 0x00008020, 0x80108000, 0x00100000, 0x80000020, - 0x00100020, 0x80008020, 0x80000020, 0x00100020, - 0x00108000, 0x00000000, 0x80008000, 0x00008020, - 0x80000000, 0x80100020, 0x80108020, 0x00108000 -}; - -static const uint32_t SB3[64] = -{ - 0x00000208, 0x08020200, 0x00000000, 0x08020008, - 0x08000200, 0x00000000, 0x00020208, 0x08000200, - 0x00020008, 0x08000008, 0x08000008, 0x00020000, - 0x08020208, 0x00020008, 0x08020000, 0x00000208, - 0x08000000, 0x00000008, 0x08020200, 0x00000200, - 0x00020200, 0x08020000, 0x08020008, 0x00020208, - 0x08000208, 0x00020200, 0x00020000, 0x08000208, - 0x00000008, 0x08020208, 0x00000200, 0x08000000, - 0x08020200, 0x08000000, 0x00020008, 0x00000208, - 0x00020000, 0x08020200, 0x08000200, 0x00000000, - 0x00000200, 0x00020008, 0x08020208, 0x08000200, - 0x08000008, 0x00000200, 0x00000000, 0x08020008, - 0x08000208, 0x00020000, 0x08000000, 0x08020208, - 0x00000008, 0x00020208, 0x00020200, 0x08000008, - 0x08020000, 0x08000208, 0x00000208, 0x08020000, - 0x00020208, 0x00000008, 0x08020008, 0x00020200 -}; - -static const uint32_t SB4[64] = -{ - 0x00802001, 0x00002081, 0x00002081, 0x00000080, - 0x00802080, 0x00800081, 0x00800001, 0x00002001, - 0x00000000, 0x00802000, 0x00802000, 0x00802081, - 0x00000081, 0x00000000, 0x00800080, 0x00800001, - 0x00000001, 0x00002000, 0x00800000, 0x00802001, - 0x00000080, 0x00800000, 0x00002001, 0x00002080, - 0x00800081, 0x00000001, 0x00002080, 0x00800080, - 0x00002000, 0x00802080, 0x00802081, 0x00000081, - 0x00800080, 0x00800001, 0x00802000, 0x00802081, - 0x00000081, 0x00000000, 0x00000000, 0x00802000, - 0x00002080, 0x00800080, 0x00800081, 0x00000001, - 0x00802001, 0x00002081, 0x00002081, 0x00000080, - 0x00802081, 0x00000081, 0x00000001, 0x00002000, - 0x00800001, 0x00002001, 0x00802080, 0x00800081, - 0x00002001, 0x00002080, 0x00800000, 0x00802001, - 0x00000080, 0x00800000, 0x00002000, 0x00802080 -}; - -static const uint32_t SB5[64] = -{ - 0x00000100, 0x02080100, 0x02080000, 0x42000100, - 0x00080000, 0x00000100, 0x40000000, 0x02080000, - 0x40080100, 0x00080000, 0x02000100, 0x40080100, - 0x42000100, 0x42080000, 0x00080100, 0x40000000, - 0x02000000, 0x40080000, 0x40080000, 0x00000000, - 0x40000100, 0x42080100, 0x42080100, 0x02000100, - 0x42080000, 0x40000100, 0x00000000, 0x42000000, - 0x02080100, 0x02000000, 0x42000000, 0x00080100, - 0x00080000, 0x42000100, 0x00000100, 0x02000000, - 0x40000000, 0x02080000, 0x42000100, 0x40080100, - 0x02000100, 0x40000000, 0x42080000, 0x02080100, - 0x40080100, 0x00000100, 0x02000000, 0x42080000, - 0x42080100, 0x00080100, 0x42000000, 0x42080100, - 0x02080000, 0x00000000, 0x40080000, 0x42000000, - 0x00080100, 0x02000100, 0x40000100, 0x00080000, - 0x00000000, 0x40080000, 0x02080100, 0x40000100 -}; - -static const uint32_t SB6[64] = -{ - 0x20000010, 0x20400000, 0x00004000, 0x20404010, - 0x20400000, 0x00000010, 0x20404010, 0x00400000, - 0x20004000, 0x00404010, 0x00400000, 0x20000010, - 0x00400010, 0x20004000, 0x20000000, 0x00004010, - 0x00000000, 0x00400010, 0x20004010, 0x00004000, - 0x00404000, 0x20004010, 0x00000010, 0x20400010, - 0x20400010, 0x00000000, 0x00404010, 0x20404000, - 0x00004010, 0x00404000, 0x20404000, 0x20000000, - 0x20004000, 0x00000010, 0x20400010, 0x00404000, - 0x20404010, 0x00400000, 0x00004010, 0x20000010, - 0x00400000, 0x20004000, 0x20000000, 0x00004010, - 0x20000010, 0x20404010, 0x00404000, 0x20400000, - 0x00404010, 0x20404000, 0x00000000, 0x20400010, - 0x00000010, 0x00004000, 0x20400000, 0x00404010, - 0x00004000, 0x00400010, 0x20004010, 0x00000000, - 0x20404000, 0x20000000, 0x00400010, 0x20004010 -}; - -static const uint32_t SB7[64] = -{ - 0x00200000, 0x04200002, 0x04000802, 0x00000000, - 0x00000800, 0x04000802, 0x00200802, 0x04200800, - 0x04200802, 0x00200000, 0x00000000, 0x04000002, - 0x00000002, 0x04000000, 0x04200002, 0x00000802, - 0x04000800, 0x00200802, 0x00200002, 0x04000800, - 0x04000002, 0x04200000, 0x04200800, 0x00200002, - 0x04200000, 0x00000800, 0x00000802, 0x04200802, - 0x00200800, 0x00000002, 0x04000000, 0x00200800, - 0x04000000, 0x00200800, 0x00200000, 0x04000802, - 0x04000802, 0x04200002, 0x04200002, 0x00000002, - 0x00200002, 0x04000000, 0x04000800, 0x00200000, - 0x04200800, 0x00000802, 0x00200802, 0x04200800, - 0x00000802, 0x04000002, 0x04200802, 0x04200000, - 0x00200800, 0x00000000, 0x00000002, 0x04200802, - 0x00000000, 0x00200802, 0x04200000, 0x00000800, - 0x04000002, 0x04000800, 0x00000800, 0x00200002 -}; - -static const uint32_t SB8[64] = -{ - 0x10001040, 0x00001000, 0x00040000, 0x10041040, - 0x10000000, 0x10001040, 0x00000040, 0x10000000, - 0x00040040, 0x10040000, 0x10041040, 0x00041000, - 0x10041000, 0x00041040, 0x00001000, 0x00000040, - 0x10040000, 0x10000040, 0x10001000, 0x00001040, - 0x00041000, 0x00040040, 0x10040040, 0x10041000, - 0x00001040, 0x00000000, 0x00000000, 0x10040040, - 0x10000040, 0x10001000, 0x00041040, 0x00040000, - 0x00041040, 0x00040000, 0x10041000, 0x00001000, - 0x00000040, 0x10040040, 0x00001000, 0x00041040, - 0x10001000, 0x00000040, 0x10000040, 0x10040000, - 0x10040040, 0x10000000, 0x00040000, 0x10001040, - 0x00000000, 0x10041040, 0x00040040, 0x10000040, - 0x10040000, 0x10001000, 0x10001040, 0x00000000, - 0x10041040, 0x00041000, 0x00041000, 0x00001040, - 0x00001040, 0x00040040, 0x10000000, 0x10041000 -}; - -/* - * PC1: left and right halves bit-swap - */ -static const uint32_t LHs[16] = -{ - 0x00000000, 0x00000001, 0x00000100, 0x00000101, - 0x00010000, 0x00010001, 0x00010100, 0x00010101, - 0x01000000, 0x01000001, 0x01000100, 0x01000101, - 0x01010000, 0x01010001, 0x01010100, 0x01010101 -}; - -static const uint32_t RHs[16] = -{ - 0x00000000, 0x01000000, 0x00010000, 0x01010000, - 0x00000100, 0x01000100, 0x00010100, 0x01010100, - 0x00000001, 0x01000001, 0x00010001, 0x01010001, - 0x00000101, 0x01000101, 0x00010101, 0x01010101, -}; - -/* - * Initial Permutation macro - */ -#define DES_IP(X,Y) \ -{ \ - T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \ - T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \ - T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \ - T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \ - Y = ((Y << 1) | (Y >> 31)) & 0xFFFFFFFF; \ - T = (X ^ Y) & 0xAAAAAAAA; Y ^= T; X ^= T; \ - X = ((X << 1) | (X >> 31)) & 0xFFFFFFFF; \ -} - -/* - * Final Permutation macro - */ -#define DES_FP(X,Y) \ -{ \ - X = ((X << 31) | (X >> 1)) & 0xFFFFFFFF; \ - T = (X ^ Y) & 0xAAAAAAAA; X ^= T; Y ^= T; \ - Y = ((Y << 31) | (Y >> 1)) & 0xFFFFFFFF; \ - T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \ - T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \ - T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \ - T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \ -} - -/* - * DES round macro - */ -#define DES_ROUND(X,Y) \ -{ \ - T = *SK++ ^ X; \ - Y ^= SB8[ (T ) & 0x3F ] ^ \ - SB6[ (T >> 8) & 0x3F ] ^ \ - SB4[ (T >> 16) & 0x3F ] ^ \ - SB2[ (T >> 24) & 0x3F ]; \ - \ - T = *SK++ ^ ((X << 28) | (X >> 4)); \ - Y ^= SB7[ (T ) & 0x3F ] ^ \ - SB5[ (T >> 8) & 0x3F ] ^ \ - SB3[ (T >> 16) & 0x3F ] ^ \ - SB1[ (T >> 24) & 0x3F ]; \ -} - -#define SWAP(a,b) { uint32_t t = a; a = b; b = t; t = 0; } - -static const unsigned char odd_parity_table[128] = { 1, 2, 4, 7, 8, - 11, 13, 14, 16, 19, 21, 22, 25, 26, 28, 31, 32, 35, 37, 38, 41, 42, 44, - 47, 49, 50, 52, 55, 56, 59, 61, 62, 64, 67, 69, 70, 73, 74, 76, 79, 81, - 82, 84, 87, 88, 91, 93, 94, 97, 98, 100, 103, 104, 107, 109, 110, 112, - 115, 117, 118, 121, 122, 124, 127, 128, 131, 133, 134, 137, 138, 140, - 143, 145, 146, 148, 151, 152, 155, 157, 158, 161, 162, 164, 167, 168, - 171, 173, 174, 176, 179, 181, 182, 185, 186, 188, 191, 193, 194, 196, - 199, 200, 203, 205, 206, 208, 211, 213, 214, 217, 218, 220, 223, 224, - 227, 229, 230, 233, 234, 236, 239, 241, 242, 244, 247, 248, 251, 253, - 254 }; - -void des_key_set_parity( unsigned char key[DES_KEY_SIZE] ) -{ - int i; - - for( i = 0; i < DES_KEY_SIZE; i++ ) - key[i] = odd_parity_table[key[i] / 2]; -} - -/* - * Check the given key's parity, returns 1 on failure, 0 on SUCCESS - */ -int des_key_check_key_parity( const unsigned char key[DES_KEY_SIZE] ) -{ - int i; - - for( i = 0; i < DES_KEY_SIZE; i++ ) - if ( key[i] != odd_parity_table[key[i] / 2] ) - return( 1 ); - - return( 0 ); -} - -/* - * Table of weak and semi-weak keys - * - * Source: http://en.wikipedia.org/wiki/Weak_key - * - * Weak: - * Alternating ones + zeros (0x0101010101010101) - * Alternating 'F' + 'E' (0xFEFEFEFEFEFEFEFE) - * '0xE0E0E0E0F1F1F1F1' - * '0x1F1F1F1F0E0E0E0E' - * - * Semi-weak: - * 0x011F011F010E010E and 0x1F011F010E010E01 - * 0x01E001E001F101F1 and 0xE001E001F101F101 - * 0x01FE01FE01FE01FE and 0xFE01FE01FE01FE01 - * 0x1FE01FE00EF10EF1 and 0xE01FE01FF10EF10E - * 0x1FFE1FFE0EFE0EFE and 0xFE1FFE1FFE0EFE0E - * 0xE0FEE0FEF1FEF1FE and 0xFEE0FEE0FEF1FEF1 - * - */ - -#define WEAK_KEY_COUNT 16 - -static const unsigned char weak_key_table[WEAK_KEY_COUNT][DES_KEY_SIZE] = -{ - { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, - { 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE }, - { 0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E }, - { 0xE0, 0xE0, 0xE0, 0xE0, 0xF1, 0xF1, 0xF1, 0xF1 }, - - { 0x01, 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E }, - { 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E, 0x01 }, - { 0x01, 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1 }, - { 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1, 0x01 }, - { 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE }, - { 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01 }, - { 0x1F, 0xE0, 0x1F, 0xE0, 0x0E, 0xF1, 0x0E, 0xF1 }, - { 0xE0, 0x1F, 0xE0, 0x1F, 0xF1, 0x0E, 0xF1, 0x0E }, - { 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E, 0xFE }, - { 0xFE, 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E }, - { 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1, 0xFE }, - { 0xFE, 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1 } -}; - -int des_key_check_weak( const unsigned char key[DES_KEY_SIZE] ) -{ - int i; - - for( i = 0; i < WEAK_KEY_COUNT; i++ ) - if( memcmp( weak_key_table[i], key, DES_KEY_SIZE) == 0) - return( 1 ); - - return( 0 ); -} - -static void des_setkey( uint32_t SK[32], const unsigned char key[DES_KEY_SIZE] ) -{ - int i; - uint32_t X, Y, T; - - GET_UINT32_BE( X, key, 0 ); - GET_UINT32_BE( Y, key, 4 ); - - /* - * Permuted Choice 1 - */ - T = ((Y >> 4) ^ X) & 0x0F0F0F0F; X ^= T; Y ^= (T << 4); - T = ((Y ) ^ X) & 0x10101010; X ^= T; Y ^= (T ); - - X = (LHs[ (X ) & 0xF] << 3) | (LHs[ (X >> 8) & 0xF ] << 2) - | (LHs[ (X >> 16) & 0xF] << 1) | (LHs[ (X >> 24) & 0xF ] ) - | (LHs[ (X >> 5) & 0xF] << 7) | (LHs[ (X >> 13) & 0xF ] << 6) - | (LHs[ (X >> 21) & 0xF] << 5) | (LHs[ (X >> 29) & 0xF ] << 4); - - Y = (RHs[ (Y >> 1) & 0xF] << 3) | (RHs[ (Y >> 9) & 0xF ] << 2) - | (RHs[ (Y >> 17) & 0xF] << 1) | (RHs[ (Y >> 25) & 0xF ] ) - | (RHs[ (Y >> 4) & 0xF] << 7) | (RHs[ (Y >> 12) & 0xF ] << 6) - | (RHs[ (Y >> 20) & 0xF] << 5) | (RHs[ (Y >> 28) & 0xF ] << 4); - - X &= 0x0FFFFFFF; - Y &= 0x0FFFFFFF; - - /* - * calculate subkeys - */ - for( i = 0; i < 16; i++ ) - { - if( i < 2 || i == 8 || i == 15 ) - { - X = ((X << 1) | (X >> 27)) & 0x0FFFFFFF; - Y = ((Y << 1) | (Y >> 27)) & 0x0FFFFFFF; - } - else - { - X = ((X << 2) | (X >> 26)) & 0x0FFFFFFF; - Y = ((Y << 2) | (Y >> 26)) & 0x0FFFFFFF; - } - - *SK++ = ((X << 4) & 0x24000000) | ((X << 28) & 0x10000000) - | ((X << 14) & 0x08000000) | ((X << 18) & 0x02080000) - | ((X << 6) & 0x01000000) | ((X << 9) & 0x00200000) - | ((X >> 1) & 0x00100000) | ((X << 10) & 0x00040000) - | ((X << 2) & 0x00020000) | ((X >> 10) & 0x00010000) - | ((Y >> 13) & 0x00002000) | ((Y >> 4) & 0x00001000) - | ((Y << 6) & 0x00000800) | ((Y >> 1) & 0x00000400) - | ((Y >> 14) & 0x00000200) | ((Y ) & 0x00000100) - | ((Y >> 5) & 0x00000020) | ((Y >> 10) & 0x00000010) - | ((Y >> 3) & 0x00000008) | ((Y >> 18) & 0x00000004) - | ((Y >> 26) & 0x00000002) | ((Y >> 24) & 0x00000001); - - *SK++ = ((X << 15) & 0x20000000) | ((X << 17) & 0x10000000) - | ((X << 10) & 0x08000000) | ((X << 22) & 0x04000000) - | ((X >> 2) & 0x02000000) | ((X << 1) & 0x01000000) - | ((X << 16) & 0x00200000) | ((X << 11) & 0x00100000) - | ((X << 3) & 0x00080000) | ((X >> 6) & 0x00040000) - | ((X << 15) & 0x00020000) | ((X >> 4) & 0x00010000) - | ((Y >> 2) & 0x00002000) | ((Y << 8) & 0x00001000) - | ((Y >> 14) & 0x00000808) | ((Y >> 9) & 0x00000400) - | ((Y ) & 0x00000200) | ((Y << 7) & 0x00000100) - | ((Y >> 7) & 0x00000020) | ((Y >> 3) & 0x00000011) - | ((Y << 2) & 0x00000004) | ((Y >> 21) & 0x00000002); - } -} - -/* - * DES key schedule (56-bit, encryption) - */ -int des_setkey_enc( des_context *ctx, const unsigned char key[DES_KEY_SIZE] ) -{ - des_setkey( ctx->sk, key ); - - return( 0 ); -} - -/* - * DES key schedule (56-bit, decryption) - */ -int des_setkey_dec( des_context *ctx, const unsigned char key[DES_KEY_SIZE] ) -{ - int i; - - des_setkey( ctx->sk, key ); - - for( i = 0; i < 16; i += 2 ) - { - SWAP( ctx->sk[i ], ctx->sk[30 - i] ); - SWAP( ctx->sk[i + 1], ctx->sk[31 - i] ); - } - - return( 0 ); -} - -static void des3_set2key( uint32_t esk[96], - uint32_t dsk[96], - const unsigned char key[DES_KEY_SIZE*2] ) -{ - int i; - - des_setkey( esk, key ); - des_setkey( dsk + 32, key + 8 ); - - for( i = 0; i < 32; i += 2 ) - { - dsk[i ] = esk[30 - i]; - dsk[i + 1] = esk[31 - i]; - - esk[i + 32] = dsk[62 - i]; - esk[i + 33] = dsk[63 - i]; - - esk[i + 64] = esk[i ]; - esk[i + 65] = esk[i + 1]; - - dsk[i + 64] = dsk[i ]; - dsk[i + 65] = dsk[i + 1]; - } -} - -/* - * Triple-DES key schedule (112-bit, encryption) - */ -int des3_set2key_enc( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 2] ) -{ - uint32_t sk[96]; - - des3_set2key( ctx->sk, sk, key ); - memset( sk, 0, sizeof( sk ) ); - - return( 0 ); -} - -/* - * Triple-DES key schedule (112-bit, decryption) - */ -int des3_set2key_dec( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 2] ) -{ - uint32_t sk[96]; - - des3_set2key( sk, ctx->sk, key ); - memset( sk, 0, sizeof( sk ) ); - - return( 0 ); -} - -static void des3_set3key( uint32_t esk[96], - uint32_t dsk[96], - const unsigned char key[24] ) -{ - int i; - - des_setkey( esk, key ); - des_setkey( dsk + 32, key + 8 ); - des_setkey( esk + 64, key + 16 ); - - for( i = 0; i < 32; i += 2 ) - { - dsk[i ] = esk[94 - i]; - dsk[i + 1] = esk[95 - i]; - - esk[i + 32] = dsk[62 - i]; - esk[i + 33] = dsk[63 - i]; - - dsk[i + 64] = esk[30 - i]; - dsk[i + 65] = esk[31 - i]; - } -} - -/* - * Triple-DES key schedule (168-bit, encryption) - */ -int des3_set3key_enc( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 3] ) -{ - uint32_t sk[96]; - - des3_set3key( ctx->sk, sk, key ); - memset( sk, 0, sizeof( sk ) ); - - return( 0 ); -} - -/* - * Triple-DES key schedule (168-bit, decryption) - */ -int des3_set3key_dec( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 3] ) -{ - uint32_t sk[96]; - - des3_set3key( sk, ctx->sk, key ); - memset( sk, 0, sizeof( sk ) ); - - return( 0 ); -} - -/* - * DES-ECB block encryption/decryption - */ -int des_crypt_ecb( des_context *ctx, - const unsigned char input[8], - unsigned char output[8] ) -{ - int i; - uint32_t X, Y, T, *SK; - - SK = ctx->sk; - - GET_UINT32_BE( X, input, 0 ); - GET_UINT32_BE( Y, input, 4 ); - - DES_IP( X, Y ); - - for( i = 0; i < 8; i++ ) - { - DES_ROUND( Y, X ); - DES_ROUND( X, Y ); - } - - DES_FP( Y, X ); - - PUT_UINT32_BE( Y, output, 0 ); - PUT_UINT32_BE( X, output, 4 ); - - return( 0 ); -} - -#if defined(POLARSSL_CIPHER_MODE_CBC) -/* - * DES-CBC buffer encryption/decryption - */ -int des_crypt_cbc( des_context *ctx, - int mode, - size_t length, - unsigned char iv[8], - const unsigned char *input, - unsigned char *output ) -{ - int i; - unsigned char temp[8]; - - if( length % 8 ) - return( POLARSSL_ERR_DES_INVALID_INPUT_LENGTH ); - - if( mode == DES_ENCRYPT ) - { - while( length > 0 ) - { - for( i = 0; i < 8; i++ ) - output[i] = (unsigned char)( input[i] ^ iv[i] ); - - des_crypt_ecb( ctx, output, output ); - memcpy( iv, output, 8 ); - - input += 8; - output += 8; - length -= 8; - } - } - else /* DES_DECRYPT */ - { - while( length > 0 ) - { - memcpy( temp, input, 8 ); - des_crypt_ecb( ctx, input, output ); - - for( i = 0; i < 8; i++ ) - output[i] = (unsigned char)( output[i] ^ iv[i] ); - - memcpy( iv, temp, 8 ); - - input += 8; - output += 8; - length -= 8; - } - } - - return( 0 ); -} -#endif /* POLARSSL_CIPHER_MODE_CBC */ - -/* - * 3DES-ECB block encryption/decryption - */ -int des3_crypt_ecb( des3_context *ctx, - const unsigned char input[8], - unsigned char output[8] ) -{ - int i; - uint32_t X, Y, T, *SK; - - SK = ctx->sk; - - GET_UINT32_BE( X, input, 0 ); - GET_UINT32_BE( Y, input, 4 ); - - DES_IP( X, Y ); - - for( i = 0; i < 8; i++ ) - { - DES_ROUND( Y, X ); - DES_ROUND( X, Y ); - } - - for( i = 0; i < 8; i++ ) - { - DES_ROUND( X, Y ); - DES_ROUND( Y, X ); - } - - for( i = 0; i < 8; i++ ) - { - DES_ROUND( Y, X ); - DES_ROUND( X, Y ); - } - - DES_FP( Y, X ); - - PUT_UINT32_BE( Y, output, 0 ); - PUT_UINT32_BE( X, output, 4 ); - - return( 0 ); -} - -#if defined(POLARSSL_CIPHER_MODE_CBC) -/* - * 3DES-CBC buffer encryption/decryption - */ -int des3_crypt_cbc( des3_context *ctx, - int mode, - size_t length, - unsigned char iv[8], - const unsigned char *input, - unsigned char *output ) -{ - int i; - unsigned char temp[8]; - - if( length % 8 ) - return( POLARSSL_ERR_DES_INVALID_INPUT_LENGTH ); - - if( mode == DES_ENCRYPT ) - { - while( length > 0 ) - { - for( i = 0; i < 8; i++ ) - output[i] = (unsigned char)( input[i] ^ iv[i] ); - - des3_crypt_ecb( ctx, output, output ); - memcpy( iv, output, 8 ); - - input += 8; - output += 8; - length -= 8; - } - } - else /* DES_DECRYPT */ - { - while( length > 0 ) - { - memcpy( temp, input, 8 ); - des3_crypt_ecb( ctx, input, output ); - - for( i = 0; i < 8; i++ ) - output[i] = (unsigned char)( output[i] ^ iv[i] ); - - memcpy( iv, temp, 8 ); - - input += 8; - output += 8; - length -= 8; - } - } - - return( 0 ); -} -#endif /* POLARSSL_CIPHER_MODE_CBC */ - -#endif /* !POLARSSL_DES_ALT */ - -#if defined(POLARSSL_SELF_TEST) - -#include - -/* - * DES and 3DES test vectors from: - * - * http://csrc.nist.gov/groups/STM/cavp/documents/des/tripledes-vectors.zip - */ -static const unsigned char des3_test_keys[24] = -{ - 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, - 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, - 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23 -}; - -static const unsigned char des3_test_buf[8] = -{ - 0x4E, 0x6F, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74 -}; - -static const unsigned char des3_test_ecb_dec[3][8] = -{ - { 0xCD, 0xD6, 0x4F, 0x2F, 0x94, 0x27, 0xC1, 0x5D }, - { 0x69, 0x96, 0xC8, 0xFA, 0x47, 0xA2, 0xAB, 0xEB }, - { 0x83, 0x25, 0x39, 0x76, 0x44, 0x09, 0x1A, 0x0A } -}; - -static const unsigned char des3_test_ecb_enc[3][8] = -{ - { 0x6A, 0x2A, 0x19, 0xF4, 0x1E, 0xCA, 0x85, 0x4B }, - { 0x03, 0xE6, 0x9F, 0x5B, 0xFA, 0x58, 0xEB, 0x42 }, - { 0xDD, 0x17, 0xE8, 0xB8, 0xB4, 0x37, 0xD2, 0x32 } -}; - -#if defined(POLARSSL_CIPHER_MODE_CBC) -static const unsigned char des3_test_iv[8] = -{ - 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, -}; - -static const unsigned char des3_test_cbc_dec[3][8] = -{ - { 0x12, 0x9F, 0x40, 0xB9, 0xD2, 0x00, 0x56, 0xB3 }, - { 0x47, 0x0E, 0xFC, 0x9A, 0x6B, 0x8E, 0xE3, 0x93 }, - { 0xC5, 0xCE, 0xCF, 0x63, 0xEC, 0xEC, 0x51, 0x4C } -}; - -static const unsigned char des3_test_cbc_enc[3][8] = -{ - { 0x54, 0xF1, 0x5A, 0xF6, 0xEB, 0xE3, 0xA4, 0xB4 }, - { 0x35, 0x76, 0x11, 0x56, 0x5F, 0xA1, 0x8E, 0x4D }, - { 0xCB, 0x19, 0x1F, 0x85, 0xD1, 0xED, 0x84, 0x39 } -}; -#endif /* POLARSSL_CIPHER_MODE_CBC */ - -/* - * Checkup routine - */ -int des_self_test( int verbose ) -{ - int i, j, u, v; - des_context ctx; - des3_context ctx3; - unsigned char key[24]; - unsigned char buf[8]; -#if defined(POLARSSL_CIPHER_MODE_CBC) - unsigned char prv[8]; - unsigned char iv[8]; -#endif - - memset( key, 0, 24 ); - - /* - * ECB mode - */ - for( i = 0; i < 6; i++ ) - { - u = i >> 1; - v = i & 1; - - if( verbose != 0 ) - polarssl_printf( " DES%c-ECB-%3d (%s): ", - ( u == 0 ) ? ' ' : '3', 56 + u * 56, - ( v == DES_DECRYPT ) ? "dec" : "enc" ); - - memcpy( buf, des3_test_buf, 8 ); - - switch( i ) - { - case 0: - des_setkey_dec( &ctx, des3_test_keys ); - break; - - case 1: - des_setkey_enc( &ctx, des3_test_keys ); - break; - - case 2: - des3_set2key_dec( &ctx3, des3_test_keys ); - break; - - case 3: - des3_set2key_enc( &ctx3, des3_test_keys ); - break; - - case 4: - des3_set3key_dec( &ctx3, des3_test_keys ); - break; - - case 5: - des3_set3key_enc( &ctx3, des3_test_keys ); - break; - - default: - return( 1 ); - } - - for( j = 0; j < 10000; j++ ) - { - if( u == 0 ) - des_crypt_ecb( &ctx, buf, buf ); - else - des3_crypt_ecb( &ctx3, buf, buf ); - } - - if( ( v == DES_DECRYPT && - memcmp( buf, des3_test_ecb_dec[u], 8 ) != 0 ) || - ( v != DES_DECRYPT && - memcmp( buf, des3_test_ecb_enc[u], 8 ) != 0 ) ) - { - if( verbose != 0 ) - polarssl_printf( "failed\n" ); - - return( 1 ); - } - - if( verbose != 0 ) - polarssl_printf( "passed\n" ); - } - - if( verbose != 0 ) - polarssl_printf( "\n" ); - -#if defined(POLARSSL_CIPHER_MODE_CBC) - /* - * CBC mode - */ - for( i = 0; i < 6; i++ ) - { - u = i >> 1; - v = i & 1; - - if( verbose != 0 ) - polarssl_printf( " DES%c-CBC-%3d (%s): ", - ( u == 0 ) ? ' ' : '3', 56 + u * 56, - ( v == DES_DECRYPT ) ? "dec" : "enc" ); - - memcpy( iv, des3_test_iv, 8 ); - memcpy( prv, des3_test_iv, 8 ); - memcpy( buf, des3_test_buf, 8 ); - - switch( i ) - { - case 0: - des_setkey_dec( &ctx, des3_test_keys ); - break; - - case 1: - des_setkey_enc( &ctx, des3_test_keys ); - break; - - case 2: - des3_set2key_dec( &ctx3, des3_test_keys ); - break; - - case 3: - des3_set2key_enc( &ctx3, des3_test_keys ); - break; - - case 4: - des3_set3key_dec( &ctx3, des3_test_keys ); - break; - - case 5: - des3_set3key_enc( &ctx3, des3_test_keys ); - break; - - default: - return( 1 ); - } - - if( v == DES_DECRYPT ) - { - for( j = 0; j < 10000; j++ ) - { - if( u == 0 ) - des_crypt_cbc( &ctx, v, 8, iv, buf, buf ); - else - des3_crypt_cbc( &ctx3, v, 8, iv, buf, buf ); - } - } - else - { - for( j = 0; j < 10000; j++ ) - { - unsigned char tmp[8]; - - if( u == 0 ) - des_crypt_cbc( &ctx, v, 8, iv, buf, buf ); - else - des3_crypt_cbc( &ctx3, v, 8, iv, buf, buf ); - - memcpy( tmp, prv, 8 ); - memcpy( prv, buf, 8 ); - memcpy( buf, tmp, 8 ); - } - - memcpy( buf, prv, 8 ); - } - - if( ( v == DES_DECRYPT && - memcmp( buf, des3_test_cbc_dec[u], 8 ) != 0 ) || - ( v != DES_DECRYPT && - memcmp( buf, des3_test_cbc_enc[u], 8 ) != 0 ) ) - { - if( verbose != 0 ) - polarssl_printf( "failed\n" ); - - return( 1 ); - } - - if( verbose != 0 ) - polarssl_printf( "passed\n" ); - } -#endif /* POLARSSL_CIPHER_MODE_CBC */ - - if( verbose != 0 ) - polarssl_printf( "\n" ); - - return( 0 ); -} - -#endif - -#endif diff --git a/common/polarssl/des.h b/common/polarssl/des.h deleted file mode 100644 index 460beaf0..00000000 --- a/common/polarssl/des.h +++ /dev/null @@ -1,281 +0,0 @@ -/** - * \file des.h - * - * \brief DES block cipher - * - * Copyright (C) 2006-2013, Brainspark B.V. - * - * This file is part of PolarSSL (http://www.polarssl.org) - * Lead Maintainer: Paul Bakker - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -#ifndef POLARSSL_DES_H -#define POLARSSL_DES_H - -//#include "config.h" -/** - * \def POLARSSL_CIPHER_MODE_CBC - * - * Enable Cipher Block Chaining mode (CBC) for symmetric ciphers. - */ -#define POLARSSL_CIPHER_MODE_CBC - -#include - -#if defined(_MSC_VER) && !defined(EFIX64) && !defined(EFI32) -#include -typedef UINT32 uint32_t; -#else -#include -#endif - -#define DES_ENCRYPT 1 -#define DES_DECRYPT 0 - -#define POLARSSL_ERR_DES_INVALID_INPUT_LENGTH -0x0032 /**< The data input has an invalid length. */ - -#define DES_KEY_SIZE 8 - -#if !defined(POLARSSL_DES_ALT) -// Regular implementation -// - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief DES context structure - */ -typedef struct -{ - int mode; /*!< encrypt/decrypt */ - uint32_t sk[32]; /*!< DES subkeys */ -} -des_context; - -/** - * \brief Triple-DES context structure - */ -typedef struct -{ - int mode; /*!< encrypt/decrypt */ - uint32_t sk[96]; /*!< 3DES subkeys */ -} -des3_context; -/* - * Triple-DES key schedule (112-bit, encryption) - */ -int des3_set2key_enc( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 2] ); - -/* - * Triple-DES key schedule (112-bit, decryption) - */ -int des3_set2key_dec( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 2] ); - -/* - * Triple-DES key schedule (168-bit, encryption) - */ -int des3_set3key_enc( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 3] ); - -/* - * Triple-DES key schedule (168-bit, decryption) - */ -int des3_set3key_dec( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 3] ); - -/** - * \brief Set key parity on the given key to odd. - * - * DES keys are 56 bits long, but each byte is padded with - * a parity bit to allow verification. - * - * \param key 8-byte secret key - */ -void des_key_set_parity( unsigned char key[DES_KEY_SIZE] ); - -/** - * \brief Check that key parity on the given key is odd. - * - * DES keys are 56 bits long, but each byte is padded with - * a parity bit to allow verification. - * - * \param key 8-byte secret key - * - * \return 0 is parity was ok, 1 if parity was not correct. - */ -int des_key_check_key_parity( const unsigned char key[DES_KEY_SIZE] ); - -/** - * \brief Check that key is not a weak or semi-weak DES key - * - * \param key 8-byte secret key - * - * \return 0 if no weak key was found, 1 if a weak key was identified. - */ -int des_key_check_weak( const unsigned char key[DES_KEY_SIZE] ); - -/** - * \brief DES key schedule (56-bit, encryption) - * - * \param ctx DES context to be initialized - * \param key 8-byte secret key - * - * \return 0 - */ -int des_setkey_enc( des_context *ctx, const unsigned char key[DES_KEY_SIZE] ); - -/** - * \brief DES key schedule (56-bit, decryption) - * - * \param ctx DES context to be initialized - * \param key 8-byte secret key - * - * \return 0 - */ -int des_setkey_dec( des_context *ctx, const unsigned char key[DES_KEY_SIZE] ); - -/** - * \brief Triple-DES key schedule (112-bit, encryption) - * - * \param ctx 3DES context to be initialized - * \param key 16-byte secret key - * - * \return 0 - */ -int des3_set2key_enc( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 2] ); - -/** - * \brief Triple-DES key schedule (112-bit, decryption) - * - * \param ctx 3DES context to be initialized - * \param key 16-byte secret key - * - * \return 0 - */ -int des3_set2key_dec( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 2] ); - -/** - * \brief Triple-DES key schedule (168-bit, encryption) - * - * \param ctx 3DES context to be initialized - * \param key 24-byte secret key - * - * \return 0 - */ -int des3_set3key_enc( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 3] ); - -/** - * \brief Triple-DES key schedule (168-bit, decryption) - * - * \param ctx 3DES context to be initialized - * \param key 24-byte secret key - * - * \return 0 - */ -int des3_set3key_dec( des3_context *ctx, const unsigned char key[DES_KEY_SIZE * 3] ); - -/** - * \brief DES-ECB block encryption/decryption - * - * \param ctx DES context - * \param input 64-bit input block - * \param output 64-bit output block - * - * \return 0 if successful - */ -int des_crypt_ecb( des_context *ctx, - const unsigned char input[8], - unsigned char output[8] ); - -#if defined(POLARSSL_CIPHER_MODE_CBC) -/** - * \brief DES-CBC buffer encryption/decryption - * - * \param ctx DES context - * \param mode DES_ENCRYPT or DES_DECRYPT - * \param length length of the input data - * \param iv initialization vector (updated after use) - * \param input buffer holding the input data - * \param output buffer holding the output data - */ -int des_crypt_cbc( des_context *ctx, - int mode, - size_t length, - unsigned char iv[8], - const unsigned char *input, - unsigned char *output ); -#endif /* POLARSSL_CIPHER_MODE_CBC */ - -/** - * \brief 3DES-ECB block encryption/decryption - * - * \param ctx 3DES context - * \param input 64-bit input block - * \param output 64-bit output block - * - * \return 0 if successful - */ -int des3_crypt_ecb( des3_context *ctx, - const unsigned char input[8], - unsigned char output[8] ); - -#if defined(POLARSSL_CIPHER_MODE_CBC) -/** - * \brief 3DES-CBC buffer encryption/decryption - * - * \param ctx 3DES context - * \param mode DES_ENCRYPT or DES_DECRYPT - * \param length length of the input data - * \param iv initialization vector (updated after use) - * \param input buffer holding the input data - * \param output buffer holding the output data - * - * \return 0 if successful, or POLARSSL_ERR_DES_INVALID_INPUT_LENGTH - */ -int des3_crypt_cbc( des3_context *ctx, - int mode, - size_t length, - unsigned char iv[8], - const unsigned char *input, - unsigned char *output ); -#endif /* POLARSSL_CIPHER_MODE_CBC */ - -#ifdef __cplusplus -} -#endif - -#else /* POLARSSL_DES_ALT */ -#include "des_alt.h" -#endif /* POLARSSL_DES_ALT */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \brief Checkup routine - * - * \return 0 if successful, or 1 if the test failed - */ -int des_self_test( int verbose ); - -#ifdef __cplusplus -} -#endif - -#endif /* des.h */ diff --git a/common/polarssl/polarssl_config.h b/common/polarssl/polarssl_config.h deleted file mode 100644 index 3d9a2f67..00000000 --- a/common/polarssl/polarssl_config.h +++ /dev/null @@ -1,2179 +0,0 @@ -/** - * \file config.h - * - * \brief Configuration options (set of defines) - * - * Copyright (C) 2006-2014, Brainspark B.V. - * - * This file is part of PolarSSL (http://www.polarssl.org) - * Lead Maintainer: Paul Bakker - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * This set of compile-time options may be used to enable - * or disable features selectively, and reduce the global - * memory footprint. - */ -#ifndef POLARSSL_CONFIG_H -#define POLARSSL_CONFIG_H - -#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) -#define _CRT_SECURE_NO_DEPRECATE 1 -#endif - -/** - * \name SECTION: System support - * - * This section sets system specific settings. - * \{ - */ - -/** - * \def POLARSSL_HAVE_INT8 - * - * The system uses 8-bit wide native integers. - * - * Uncomment if native integers are 8-bit wide. - */ -//#define POLARSSL_HAVE_INT8 - -/** - * \def POLARSSL_HAVE_INT16 - * - * The system uses 16-bit wide native integers. - * - * Uncomment if native integers are 16-bit wide. - */ -//#define POLARSSL_HAVE_INT16 - -/** - * \def POLARSSL_HAVE_LONGLONG - * - * The compiler supports the 'long long' type. - * (Only used on 32-bit platforms) - */ -#define POLARSSL_HAVE_LONGLONG - -/** - * \def POLARSSL_HAVE_ASM - * - * The compiler has support for asm(). - * - * Requires support for asm() in compiler. - * - * Used in: - * library/timing.c - * library/padlock.c - * include/polarssl/bn_mul.h - * - * Comment to disable the use of assembly code. - */ -//#define POLARSSL_HAVE_ASM - -/** - * \def POLARSSL_HAVE_SSE2 - * - * CPU supports SSE2 instruction set. - * - * Uncomment if the CPU supports SSE2 (IA-32 specific). - */ -//#define POLARSSL_HAVE_SSE2 - -/** - * \def POLARSSL_HAVE_TIME - * - * System has time.h and time() / localtime() / gettimeofday(). - * - * Comment if your system does not support time functions - */ -#define POLARSSL_HAVE_TIME - -/** - * \def POLARSSL_HAVE_IPV6 - * - * System supports the basic socket interface for IPv6 (RFC 3493), - * specifically getaddrinfo(), freeaddrinfo() and struct sockaddr_storage. - * - * Note: on Windows/MingW, XP or higher is required. - * - * Comment if your system does not support the IPv6 socket interface - */ -#define POLARSSL_HAVE_IPV6 - -/** - * \def POLARSSL_PLATFORM_MEMORY - * - * Enable the memory allocation layer. - * - * By default PolarSSL uses the system-provided malloc() and free(). - * This allows different allocators (self-implemented or provided) to be - * provided to the platform abstraction layer. - * - * Enabling POLARSSL_PLATFORM_MEMORY will provide "platform_set_malloc_free()" - * to allow you to set an alternative malloc() and free() function pointer. - * - * Requires: POLARSSL_PLATFORM_C - * - * Enable this layer to allow use of alternative memory allocators. - */ -//#define POLARSSL_PLATFORM_MEMORY - -/** - * \def POLARSSL_PLATFORM_NO_STD_FUNCTIONS - * - * Do not assign standard functions in the platform layer (e.g. malloc() to - * POLARSSL_PLATFORM_STD_MALLOC and printf() to POLARSSL_PLATFORM_STD_PRINTF) - * - * This makes sure there are no linking errors on platforms that do not support - * these functions. You will HAVE to provide alternatives, either at runtime - * via the platform_set_xxx() functions or at compile time by setting - * the POLARSSL_PLATFORM_STD_XXX defines. - * - * Requires: POLARSSL_PLATFORM_C - * - * Uncomment to prevent default assignment of standard functions in the - * platform layer. - */ -//#define POLARSSL_PLATFORM_NO_STD_FUNCTIONS - -/** - * \def POLARSSL_PLATFORM_XXX_ALT - * - * Uncomment a macro to let PolarSSL support the function in the platform - * abstraction layer. - * - * Example: In case you uncomment POLARSSL_PLATFORM_PRINTF_ALT, PolarSSL will - * provide a function "platform_set_printf()" that allows you to set an - * alternative printf function pointer. - * - * All these define require POLARSSL_PLATFORM_C to be defined! - * - * Uncomment a macro to enable alternate implementation of specific base - * platform function - */ -//#define POLARSSL_PLATFORM_PRINTF_ALT -//#define POLARSSL_PLATFORM_FPRINTF_ALT -/* \} name SECTION: System support */ - -/** - * \name SECTION: PolarSSL feature support - * - * This section sets support for features that are or are not needed - * within the modules that are enabled. - * \{ - */ - -/** - * \def POLARSSL_TIMING_ALT - * - * Uncomment to provide your own alternate implementation for hardclock(), - * get_timer(), set_alarm() and m_sleep(). - * - * Only works if you have POLARSSL_TIMING_C enabled. - * - * You will need to provide a header "timing_alt.h" and an implementation at - * compile time. - */ -//#define POLARSSL_TIMING_ALT - -/** - * \def POLARSSL_XXX_ALT - * - * Uncomment a macro to let PolarSSL use your alternate core implementation of - * a symmetric or hash algorithm (e.g. platform specific assembly optimized - * implementations). Keep in mind that the function prototypes should remain - * the same. - * - * Example: In case you uncomment POLARSSL_AES_ALT, PolarSSL will no longer - * provide the "struct aes_context" definition and omit the base function - * declarations and implementations. "aes_alt.h" will be included from - * "aes.h" to include the new function definitions. - * - * Uncomment a macro to enable alternate implementation for core algorithm - * functions - */ -//#define POLARSSL_AES_ALT -//#define POLARSSL_ARC4_ALT -//#define POLARSSL_BLOWFISH_ALT -//#define POLARSSL_CAMELLIA_ALT -//#define POLARSSL_DES_ALT -//#define POLARSSL_XTEA_ALT -//#define POLARSSL_MD2_ALT -//#define POLARSSL_MD4_ALT -//#define POLARSSL_MD5_ALT -//#define POLARSSL_RIPEMD160_ALT -//#define POLARSSL_SHA1_ALT -//#define POLARSSL_SHA256_ALT -//#define POLARSSL_SHA512_ALT - -/** - * \def POLARSSL_AES_ROM_TABLES - * - * Store the AES tables in ROM. - * - * Uncomment this macro to store the AES tables in ROM. - * - */ -//#define POLARSSL_AES_ROM_TABLES - -/** - * \def POLARSSL_CIPHER_MODE_CBC - * - * Enable Cipher Block Chaining mode (CBC) for symmetric ciphers. - */ -#define POLARSSL_CIPHER_MODE_CBC - -/** - * \def POLARSSL_CIPHER_MODE_CFB - * - * Enable Cipher Feedback mode (CFB) for symmetric ciphers. - */ -#define POLARSSL_CIPHER_MODE_CFB - -/** - * \def POLARSSL_CIPHER_MODE_CTR - * - * Enable Counter Block Cipher mode (CTR) for symmetric ciphers. - */ -#define POLARSSL_CIPHER_MODE_CTR - -/** - * \def POLARSSL_CIPHER_NULL_CIPHER - * - * Enable NULL cipher. - * Warning: Only do so when you know what you are doing. This allows for - * encryption or channels without any security! - * - * Requires POLARSSL_ENABLE_WEAK_CIPHERSUITES as well to enable - * the following ciphersuites: - * TLS_ECDH_ECDSA_WITH_NULL_SHA - * TLS_ECDH_RSA_WITH_NULL_SHA - * TLS_ECDHE_ECDSA_WITH_NULL_SHA - * TLS_ECDHE_RSA_WITH_NULL_SHA - * TLS_ECDHE_PSK_WITH_NULL_SHA384 - * TLS_ECDHE_PSK_WITH_NULL_SHA256 - * TLS_ECDHE_PSK_WITH_NULL_SHA - * TLS_DHE_PSK_WITH_NULL_SHA384 - * TLS_DHE_PSK_WITH_NULL_SHA256 - * TLS_DHE_PSK_WITH_NULL_SHA - * TLS_RSA_WITH_NULL_SHA256 - * TLS_RSA_WITH_NULL_SHA - * TLS_RSA_WITH_NULL_MD5 - * TLS_RSA_PSK_WITH_NULL_SHA384 - * TLS_RSA_PSK_WITH_NULL_SHA256 - * TLS_RSA_PSK_WITH_NULL_SHA - * TLS_PSK_WITH_NULL_SHA384 - * TLS_PSK_WITH_NULL_SHA256 - * TLS_PSK_WITH_NULL_SHA - * - * Uncomment this macro to enable the NULL cipher and ciphersuites - */ -//#define POLARSSL_CIPHER_NULL_CIPHER - -/** - * \def POLARSSL_CIPHER_PADDING_XXX - * - * Uncomment or comment macros to add support for specific padding modes - * in the cipher layer with cipher modes that support padding (e.g. CBC) - * - * If you disable all padding modes, only full blocks can be used with CBC. - * - * Enable padding modes in the cipher layer. - */ -#define POLARSSL_CIPHER_PADDING_PKCS7 -#define POLARSSL_CIPHER_PADDING_ONE_AND_ZEROS -#define POLARSSL_CIPHER_PADDING_ZEROS_AND_LEN -#define POLARSSL_CIPHER_PADDING_ZEROS - -/** - * \def POLARSSL_ENABLE_WEAK_CIPHERSUITES - * - * Enable weak ciphersuites in SSL / TLS. - * Warning: Only do so when you know what you are doing. This allows for - * channels with virtually no security at all! - * - * This enables the following ciphersuites: - * TLS_RSA_WITH_DES_CBC_SHA - * TLS_DHE_RSA_WITH_DES_CBC_SHA - * - * Uncomment this macro to enable weak ciphersuites - */ -//#define POLARSSL_ENABLE_WEAK_CIPHERSUITES - -/** - * \def POLARSSL_REMOVE_ARC4_CIPHERSUITES - * - * Remove RC4 ciphersuites by default in SSL / TLS. - * This flag removes the ciphersuites based on RC4 from the default list as - * returned by ssl_list_ciphersuites(). However, it is still possible to - * enable (some of) them with ssl_set_ciphersuites() by including them - * explicitly. - * - * Uncomment this macro to remove RC4 ciphersuites by default. - */ -//#define POLARSSL_REMOVE_ARC4_CIPHERSUITES - -/** - * \def POLARSSL_ECP_XXXX_ENABLED - * - * Enables specific curves within the Elliptic Curve module. - * By default all supported curves are enabled. - * - * Comment macros to disable the curve and functions for it - */ -#define POLARSSL_ECP_DP_SECP192R1_ENABLED -#define POLARSSL_ECP_DP_SECP224R1_ENABLED -#define POLARSSL_ECP_DP_SECP256R1_ENABLED -#define POLARSSL_ECP_DP_SECP384R1_ENABLED -#define POLARSSL_ECP_DP_SECP521R1_ENABLED -#define POLARSSL_ECP_DP_SECP192K1_ENABLED -#define POLARSSL_ECP_DP_SECP224K1_ENABLED -#define POLARSSL_ECP_DP_SECP256K1_ENABLED -#define POLARSSL_ECP_DP_BP256R1_ENABLED -#define POLARSSL_ECP_DP_BP384R1_ENABLED -#define POLARSSL_ECP_DP_BP512R1_ENABLED -//#define POLARSSL_ECP_DP_M221_ENABLED // Not implemented yet! -#define POLARSSL_ECP_DP_M255_ENABLED -//#define POLARSSL_ECP_DP_M383_ENABLED // Not implemented yet! -//#define POLARSSL_ECP_DP_M511_ENABLED // Not implemented yet! - -/** - * \def POLARSSL_ECP_NIST_OPTIM - * - * Enable specific 'modulo p' routines for each NIST prime. - * Depending on the prime and architecture, makes operations 4 to 8 times - * faster on the corresponding curve. - * - * Comment this macro to disable NIST curves optimisation. - */ -#define POLARSSL_ECP_NIST_OPTIM - -/** - * \def POLARSSL_ECDSA_DETERMINISTIC - * - * Enable deterministic ECDSA (RFC 6979). - * Standard ECDSA is "fragile" in the sense that lack of entropy when signing - * may result in a compromise of the long-term signing key. This is avoided by - * the deterministic variant. - * - * Requires: POLARSSL_HMAC_DRBG_C - * - * Comment this macro to disable deterministic ECDSA. - */ -#define POLARSSL_ECDSA_DETERMINISTIC - -/** - * \def POLARSSL_KEY_EXCHANGE_PSK_ENABLED - * - * Enable the PSK based ciphersuite modes in SSL / TLS. - * - * This enables the following ciphersuites (if other requisites are - * enabled as well): - * TLS_PSK_WITH_AES_256_GCM_SHA384 - * TLS_PSK_WITH_AES_256_CBC_SHA384 - * TLS_PSK_WITH_AES_256_CBC_SHA - * TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 - * TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 - * TLS_PSK_WITH_AES_128_GCM_SHA256 - * TLS_PSK_WITH_AES_128_CBC_SHA256 - * TLS_PSK_WITH_AES_128_CBC_SHA - * TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 - * TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 - * TLS_PSK_WITH_3DES_EDE_CBC_SHA - * TLS_PSK_WITH_RC4_128_SHA - */ -#define POLARSSL_KEY_EXCHANGE_PSK_ENABLED - -/** - * \def POLARSSL_KEY_EXCHANGE_DHE_PSK_ENABLED - * - * Enable the DHE-PSK based ciphersuite modes in SSL / TLS. - * - * Requires: POLARSSL_DHM_C - * - * This enables the following ciphersuites (if other requisites are - * enabled as well): - * TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 - * TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 - * TLS_DHE_PSK_WITH_AES_256_CBC_SHA - * TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 - * TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 - * TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 - * TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 - * TLS_DHE_PSK_WITH_AES_128_CBC_SHA - * TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 - * TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 - * TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA - * TLS_DHE_PSK_WITH_RC4_128_SHA - */ -#define POLARSSL_KEY_EXCHANGE_DHE_PSK_ENABLED - -/** - * \def POLARSSL_KEY_EXCHANGE_ECDHE_PSK_ENABLED - * - * Enable the ECDHE-PSK based ciphersuite modes in SSL / TLS. - * - * Requires: POLARSSL_ECDH_C - * - * This enables the following ciphersuites (if other requisites are - * enabled as well): - * TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 - * TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA - * TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 - * TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 - * TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA - * TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 - * TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA - * TLS_ECDHE_PSK_WITH_RC4_128_SHA - */ -#define POLARSSL_KEY_EXCHANGE_ECDHE_PSK_ENABLED - -/** - * \def POLARSSL_KEY_EXCHANGE_RSA_PSK_ENABLED - * - * Enable the RSA-PSK based ciphersuite modes in SSL / TLS. - * - * Requires: POLARSSL_RSA_C, POLARSSL_PKCS1_V15, - * POLARSSL_X509_CRT_PARSE_C - * - * This enables the following ciphersuites (if other requisites are - * enabled as well): - * TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 - * TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 - * TLS_RSA_PSK_WITH_AES_256_CBC_SHA - * TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 - * TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 - * TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 - * TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 - * TLS_RSA_PSK_WITH_AES_128_CBC_SHA - * TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 - * TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 - * TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA - * TLS_RSA_PSK_WITH_RC4_128_SHA - */ -#define POLARSSL_KEY_EXCHANGE_RSA_PSK_ENABLED - -/** - * \def POLARSSL_KEY_EXCHANGE_RSA_ENABLED - * - * Enable the RSA-only based ciphersuite modes in SSL / TLS. - * - * Requires: POLARSSL_RSA_C, POLARSSL_PKCS1_V15, - * POLARSSL_X509_CRT_PARSE_C - * - * This enables the following ciphersuites (if other requisites are - * enabled as well): - * TLS_RSA_WITH_AES_256_GCM_SHA384 - * TLS_RSA_WITH_AES_256_CBC_SHA256 - * TLS_RSA_WITH_AES_256_CBC_SHA - * TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 - * TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 - * TLS_RSA_WITH_CAMELLIA_256_CBC_SHA - * TLS_RSA_WITH_AES_128_GCM_SHA256 - * TLS_RSA_WITH_AES_128_CBC_SHA256 - * TLS_RSA_WITH_AES_128_CBC_SHA - * TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 - * TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 - * TLS_RSA_WITH_CAMELLIA_128_CBC_SHA - * TLS_RSA_WITH_3DES_EDE_CBC_SHA - * TLS_RSA_WITH_RC4_128_SHA - * TLS_RSA_WITH_RC4_128_MD5 - */ -#define POLARSSL_KEY_EXCHANGE_RSA_ENABLED - -/** - * \def POLARSSL_KEY_EXCHANGE_DHE_RSA_ENABLED - * - * Enable the DHE-RSA based ciphersuite modes in SSL / TLS. - * - * Requires: POLARSSL_DHM_C, POLARSSL_RSA_C, POLARSSL_PKCS1_V15, - * POLARSSL_X509_CRT_PARSE_C - * - * This enables the following ciphersuites (if other requisites are - * enabled as well): - * TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 - * TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 - * TLS_DHE_RSA_WITH_AES_256_CBC_SHA - * TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 - * TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 - * TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA - * TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 - * TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 - * TLS_DHE_RSA_WITH_AES_128_CBC_SHA - * TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 - * TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 - * TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA - * TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA - */ -#define POLARSSL_KEY_EXCHANGE_DHE_RSA_ENABLED - -/** - * \def POLARSSL_KEY_EXCHANGE_ECDHE_RSA_ENABLED - * - * Enable the ECDHE-RSA based ciphersuite modes in SSL / TLS. - * - * Requires: POLARSSL_ECDH_C, POLARSSL_RSA_C, POLARSSL_PKCS1_V15, - * POLARSSL_X509_CRT_PARSE_C - * - * This enables the following ciphersuites (if other requisites are - * enabled as well): - * TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - * TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 - * TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA - * TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 - * TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 - * TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - * TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 - * TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA - * TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 - * TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 - * TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA - * TLS_ECDHE_RSA_WITH_RC4_128_SHA - */ -#define POLARSSL_KEY_EXCHANGE_ECDHE_RSA_ENABLED - -/** - * \def POLARSSL_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED - * - * Enable the ECDHE-ECDSA based ciphersuite modes in SSL / TLS. - * - * Requires: POLARSSL_ECDH_C, POLARSSL_ECDSA_C, POLARSSL_X509_CRT_PARSE_C, - * - * This enables the following ciphersuites (if other requisites are - * enabled as well): - * TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 - * TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 - * TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA - * TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 - * TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 - * TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 - * TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 - * TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA - * TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 - * TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 - * TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA - * TLS_ECDHE_ECDSA_WITH_RC4_128_SHA - */ -#define POLARSSL_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED - -/** - * \def POLARSSL_KEY_EXCHANGE_ECDH_ECDSA_ENABLED - * - * Enable the ECDH-ECDSA based ciphersuite modes in SSL / TLS. - * - * Requires: POLARSSL_ECDH_C, POLARSSL_X509_CRT_PARSE_C - * - * This enables the following ciphersuites (if other requisites are - * enabled as well): - * TLS_ECDH_ECDSA_WITH_RC4_128_SHA - * TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA - * TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA - * TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA - * TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 - * TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 - * TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 - * TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 - * TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 - * TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 - * TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 - * TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 - */ -#define POLARSSL_KEY_EXCHANGE_ECDH_ECDSA_ENABLED - -/** - * \def POLARSSL_KEY_EXCHANGE_ECDH_RSA_ENABLED - * - * Enable the ECDH-RSA based ciphersuite modes in SSL / TLS. - * - * Requires: POLARSSL_ECDH_C, POLARSSL_X509_CRT_PARSE_C - * - * This enables the following ciphersuites (if other requisites are - * enabled as well): - * TLS_ECDH_RSA_WITH_RC4_128_SHA - * TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA - * TLS_ECDH_RSA_WITH_AES_128_CBC_SHA - * TLS_ECDH_RSA_WITH_AES_256_CBC_SHA - * TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 - * TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 - * TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 - * TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 - * TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 - * TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 - * TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 - * TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 - */ -#define POLARSSL_KEY_EXCHANGE_ECDH_RSA_ENABLED - -/** - * \def POLARSSL_PK_PARSE_EC_EXTENDED - * - * Enhance support for reading EC keys using variants of SEC1 not allowed by - * RFC 5915 and RFC 5480. - * - * Currently this means parsing the SpecifiedECDomain choice of EC - * parameters (only known groups are supported, not arbitrary domains, to - * avoid validation issues). - * - * Disable if you only need to support RFC 5915 + 5480 key formats. - */ -#define POLARSSL_PK_PARSE_EC_EXTENDED - -/** - * \def POLARSSL_ERROR_STRERROR_BC - * - * Make available the backward compatible error_strerror() next to the - * current polarssl_strerror(). - * - * For new code, it is recommended to use polarssl_strerror() instead and - * disable this. - * - * Disable if you run into name conflicts and want to really remove the - * error_strerror() - */ -#define POLARSSL_ERROR_STRERROR_BC - -/** - * \def POLARSSL_ERROR_STRERROR_DUMMY - * - * Enable a dummy error function to make use of polarssl_strerror() in - * third party libraries easier when POLARSSL_ERROR_C is disabled - * (no effect when POLARSSL_ERROR_C is enabled). - * - * You can safely disable this if POLARSSL_ERROR_C is enabled, or if you're - * not using polarssl_strerror() or error_strerror() in your application. - * - * Disable if you run into name conflicts and want to really remove the - * polarssl_strerror() - */ -#define POLARSSL_ERROR_STRERROR_DUMMY - -/** - * \def POLARSSL_GENPRIME - * - * Enable the prime-number generation code. - * - * Requires: POLARSSL_BIGNUM_C - */ -#define POLARSSL_GENPRIME - -/** - * \def POLARSSL_FS_IO - * - * Enable functions that use the filesystem. - */ -#define POLARSSL_FS_IO - -/** - * \def POLARSSL_NO_DEFAULT_ENTROPY_SOURCES - * - * Do not add default entropy sources. These are the platform specific, - * hardclock and HAVEGE based poll functions. - * - * This is useful to have more control over the added entropy sources in an - * application. - * - * Uncomment this macro to prevent loading of default entropy functions. - */ -//#define POLARSSL_NO_DEFAULT_ENTROPY_SOURCES - -/** - * \def POLARSSL_NO_PLATFORM_ENTROPY - * - * Do not use built-in platform entropy functions. - * This is useful if your platform does not support - * standards like the /dev/urandom or Windows CryptoAPI. - * - * Uncomment this macro to disable the built-in platform entropy functions. - */ -//#define POLARSSL_NO_PLATFORM_ENTROPY - -/** - * \def POLARSSL_ENTROPY_FORCE_SHA256 - * - * Force the entropy accumulator to use a SHA-256 accumulator instead of the - * default SHA-512 based one (if both are available). - * - * Requires: POLARSSL_SHA256_C - * - * On 32-bit systems SHA-256 can be much faster than SHA-512. Use this option - * if you have performance concerns. - * - * This option is only useful if both POLARSSL_SHA256_C and - * POLARSSL_SHA512_C are defined. Otherwise the available hash module is used. - */ -//#define POLARSSL_ENTROPY_FORCE_SHA256 - -/** - * \def POLARSSL_MEMORY_DEBUG - * - * Enable debugging of buffer allocator memory issues. Automatically prints - * (to stderr) all (fatal) messages on memory allocation issues. Enables - * function for 'debug output' of allocated memory. - * - * Requires: POLARSSL_MEMORY_BUFFER_ALLOC_C - * - * Uncomment this macro to let the buffer allocator print out error messages. - */ -//#define POLARSSL_MEMORY_DEBUG - -/** - * \def POLARSSL_MEMORY_BACKTRACE - * - * Include backtrace information with each allocated block. - * - * Requires: POLARSSL_MEMORY_BUFFER_ALLOC_C - * GLIBC-compatible backtrace() an backtrace_symbols() support - * - * Uncomment this macro to include backtrace information - */ -//#define POLARSSL_MEMORY_BACKTRACE - -/** - * \def POLARSSL_PKCS1_V15 - * - * Enable support for PKCS#1 v1.5 encoding. - * - * Requires: POLARSSL_RSA_C - * - * This enables support for PKCS#1 v1.5 operations. - */ -#define POLARSSL_PKCS1_V15 - -/** - * \def POLARSSL_PKCS1_V21 - * - * Enable support for PKCS#1 v2.1 encoding. - * - * Requires: POLARSSL_MD_C, POLARSSL_RSA_C - * - * This enables support for RSAES-OAEP and RSASSA-PSS operations. - */ -//#define POLARSSL_PKCS1_V21 - -/** - * \def POLARSSL_RSA_NO_CRT - * - * Do not use the Chinese Remainder Theorem for the RSA private operation. - * - * Uncomment this macro to disable the use of CRT in RSA. - * - */ -//#define POLARSSL_RSA_NO_CRT - -/** - * \def POLARSSL_SELF_TEST - * - * Enable the checkup functions (*_self_test). - */ -#define POLARSSL_SELF_TEST - -/** - * \def POLARSSL_SSL_ALL_ALERT_MESSAGES - * - * Enable sending of alert messages in case of encountered errors as per RFC. - * If you choose not to send the alert messages, PolarSSL can still communicate - * with other servers, only debugging of failures is harder. - * - * The advantage of not sending alert messages, is that no information is given - * about reasons for failures thus preventing adversaries of gaining intel. - * - * Enable sending of all alert messages - */ -#define POLARSSL_SSL_ALERT_MESSAGES - -/** - * \def POLARSSL_SSL_DEBUG_ALL - * - * Enable the debug messages in SSL module for all issues. - * Debug messages have been disabled in some places to prevent timing - * attacks due to (unbalanced) debugging function calls. - * - * If you need all error reporting you should enable this during debugging, - * but remove this for production servers that should log as well. - * - * Uncomment this macro to report all debug messages on errors introducing - * a timing side-channel. - * - */ -//#define POLARSSL_SSL_DEBUG_ALL - -/** - * \def POLARSSL_SSL_HW_RECORD_ACCEL - * - * Enable hooking functions in SSL module for hardware acceleration of - * individual records. - * - * Uncomment this macro to enable hooking functions. - */ -//#define POLARSSL_SSL_HW_RECORD_ACCEL - -/** - * \def POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO - * - * Enable support for receiving and parsing SSLv2 Client Hello messages for the - * SSL Server module (POLARSSL_SSL_SRV_C). - * - * Comment this macro to disable support for SSLv2 Client Hello messages. - */ -#define POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO - -/** - * \def POLARSSL_SSL_SRV_RESPECT_CLIENT_PREFERENCE - * - * Pick the ciphersuite according to the client's preferences rather than ours - * in the SSL Server module (POLARSSL_SSL_SRV_C). - * - * Uncomment this macro to respect client's ciphersuite order - */ -//#define POLARSSL_SSL_SRV_RESPECT_CLIENT_PREFERENCE - -/** - * \def POLARSSL_SSL_MAX_FRAGMENT_LENGTH - * - * Enable support for RFC 6066 max_fragment_length extension in SSL. - * - * Comment this macro to disable support for the max_fragment_length extension - */ -#define POLARSSL_SSL_MAX_FRAGMENT_LENGTH - -/** - * \def POLARSSL_SSL_PROTO_SSL3 - * - * Enable support for SSL 3.0. - * - * Requires: POLARSSL_MD5_C - * POLARSSL_SHA1_C - * - * Comment this macro to disable support for SSL 3.0 - */ -#define POLARSSL_SSL_PROTO_SSL3 - -/** - * \def POLARSSL_SSL_PROTO_TLS1 - * - * Enable support for TLS 1.0. - * - * Requires: POLARSSL_MD5_C - * POLARSSL_SHA1_C - * - * Comment this macro to disable support for TLS 1.0 - */ -#define POLARSSL_SSL_PROTO_TLS1 - -/** - * \def POLARSSL_SSL_PROTO_TLS1_1 - * - * Enable support for TLS 1.1. - * - * Requires: POLARSSL_MD5_C - * POLARSSL_SHA1_C - * - * Comment this macro to disable support for TLS 1.1 - */ -#define POLARSSL_SSL_PROTO_TLS1_1 - -/** - * \def POLARSSL_SSL_PROTO_TLS1_2 - * - * Enable support for TLS 1.2. - * - * Requires: POLARSSL_SHA1_C or POLARSSL_SHA256_C or POLARSSL_SHA512_C - * (Depends on ciphersuites) - * - * Comment this macro to disable support for TLS 1.2 - */ -#define POLARSSL_SSL_PROTO_TLS1_2 - -/** - * \def POLARSSL_SSL_ALPN - * - * Enable support for Application Layer Protocol Negotiation. - * draft-ietf-tls-applayerprotoneg-05 - * - * Comment this macro to disable support for ALPN. - */ -#define POLARSSL_SSL_ALPN - -/** - * \def POLARSSL_SSL_SESSION_TICKETS - * - * Enable support for RFC 5077 session tickets in SSL. - * - * Requires: POLARSSL_AES_C - * POLARSSL_SHA256_C - * POLARSSL_CIPHER_MODE_CBC - * - * Comment this macro to disable support for SSL session tickets - */ -#define POLARSSL_SSL_SESSION_TICKETS - -/** - * \def POLARSSL_SSL_SERVER_NAME_INDICATION - * - * Enable support for RFC 6066 server name indication (SNI) in SSL. - * - * Comment this macro to disable support for server name indication in SSL - */ -#define POLARSSL_SSL_SERVER_NAME_INDICATION - -/** - * \def POLARSSL_SSL_TRUNCATED_HMAC - * - * Enable support for RFC 6066 truncated HMAC in SSL. - * - * Comment this macro to disable support for truncated HMAC in SSL - */ -#define POLARSSL_SSL_TRUNCATED_HMAC - -/** - * \def POLARSSL_SSL_SET_CURVES - * - * Enable ssl_set_curves(). - * - * This is disabled by default since it breaks binary compatibility with the - * 1.3.x line. If you choose to enable it, you will need to rebuild your - * application against the new header files, relinking will not be enough. - * It will be enabled by default, or no longer an option, in the 1.4 branch. - * - * Uncomment to make ssl_set_curves() available. - */ -//#define POLARSSL_SSL_SET_CURVES - -/** - * \def POLARSSL_THREADING_ALT - * - * Provide your own alternate threading implementation. - * - * Requires: POLARSSL_THREADING_C - * - * Uncomment this to allow your own alternate threading implementation. - */ -//#define POLARSSL_THREADING_ALT - -/** - * \def POLARSSL_THREADING_PTHREAD - * - * Enable the pthread wrapper layer for the threading layer. - * - * Requires: POLARSSL_THREADING_C - * - * Uncomment this to enable pthread mutexes. - */ -//#define POLARSSL_THREADING_PTHREAD - -/** - * \def POLARSSL_VERSION_FEATURES - * - * Allow run-time checking of compile-time enabled features. Thus allowing users - * to check at run-time if the library is for instance compiled with threading - * support via version_check_feature(). - * - * Requires: POLARSSL_VERSION_C - * - * Comment this to disable run-time checking and save ROM space - */ -#define POLARSSL_VERSION_FEATURES - -/** - * \def POLARSSL_X509_ALLOW_EXTENSIONS_NON_V3 - * - * If set, the X509 parser will not break-off when parsing an X509 certificate - * and encountering an extension in a v1 or v2 certificate. - * - * Uncomment to prevent an error. - */ -//#define POLARSSL_X509_ALLOW_EXTENSIONS_NON_V3 - -/** - * \def POLARSSL_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION - * - * If set, the X509 parser will not break-off when parsing an X509 certificate - * and encountering an unknown critical extension. - * - * Uncomment to prevent an error. - */ -//#define POLARSSL_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION - -/** - * \def POLARSSL_X509_CHECK_KEY_USAGE - * - * Enable verification of the keyUsage extension (CA and leaf certificates). - * - * Disabling this avoids problems with mis-issued and/or misused - * (intermediate) CA and leaf certificates. - * - * \warning Depending on your PKI use, disabling this can be a security risk! - * - * Comment to skip keyUsage checking for both CA and leaf certificates. - */ -#define POLARSSL_X509_CHECK_KEY_USAGE - -/** - * \def POLARSSL_X509_CHECK_EXTENDED_KEY_USAGE - * - * Enable verification of the extendedKeyUsage extension (leaf certificates). - * - * Disabling this avoids problems with mis-issued and/or misused certificates. - * - * \warning Depending on your PKI use, disabling this can be a security risk! - * - * Comment to skip extendedKeyUsage checking for certificates. - */ -#define POLARSSL_X509_CHECK_EXTENDED_KEY_USAGE - -/** - * \def POLARSSL_X509_RSASSA_PSS_SUPPORT - * - * Enable parsing and verification of X.509 certificates, CRLs and CSRS - * signed with RSASSA-PSS (aka PKCS#1 v2.1). - * - * Comment this macro to disallow using RSASSA-PSS in certificates. - */ -#define POLARSSL_X509_RSASSA_PSS_SUPPORT - -/** - * \def POLARSSL_ZLIB_SUPPORT - * - * If set, the SSL/TLS module uses ZLIB to support compression and - * decompression of packet data. - * - * \warning TLS-level compression MAY REDUCE SECURITY! See for example the - * CRIME attack. Before enabling this option, you should examine with care if - * CRIME or similar exploits may be a applicable to your use case. - * - * Used in: library/ssl_tls.c - * library/ssl_cli.c - * library/ssl_srv.c - * - * This feature requires zlib library and headers to be present. - * - * Uncomment to enable use of ZLIB - */ -//#define POLARSSL_ZLIB_SUPPORT -/* \} name SECTION: PolarSSL feature support */ - -/** - * \name SECTION: PolarSSL modules - * - * This section enables or disables entire modules in PolarSSL - * \{ - */ - -/** - * \def POLARSSL_AESNI_C - * - * Enable AES-NI support on x86-64. - * - * Module: library/aesni.c - * Caller: library/aes.c - * - * Requires: POLARSSL_HAVE_ASM - * - * This modules adds support for the AES-NI instructions on x86-64 - */ -//#define POLARSSL_AESNI_C - -/** - * \def POLARSSL_AES_C - * - * Enable the AES block cipher. - * - * Module: library/aes.c - * Caller: library/ssl_tls.c - * library/pem.c - * library/ctr_drbg.c - * - * This module enables the following ciphersuites (if other requisites are - * enabled as well): - * TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA - * TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA - * TLS_ECDH_RSA_WITH_AES_128_CBC_SHA - * TLS_ECDH_RSA_WITH_AES_256_CBC_SHA - * TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 - * TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 - * TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 - * TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 - * TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 - * TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 - * TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 - * TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 - * TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 - * TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - * TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 - * TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 - * TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 - * TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 - * TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA - * TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA - * TLS_DHE_RSA_WITH_AES_256_CBC_SHA - * TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 - * TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - * TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 - * TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 - * TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 - * TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 - * TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA - * TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA - * TLS_DHE_RSA_WITH_AES_128_CBC_SHA - * TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 - * TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 - * TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 - * TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA - * TLS_DHE_PSK_WITH_AES_256_CBC_SHA - * TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 - * TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 - * TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 - * TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA - * TLS_DHE_PSK_WITH_AES_128_CBC_SHA - * TLS_RSA_WITH_AES_256_GCM_SHA384 - * TLS_RSA_WITH_AES_256_CBC_SHA256 - * TLS_RSA_WITH_AES_256_CBC_SHA - * TLS_RSA_WITH_AES_128_GCM_SHA256 - * TLS_RSA_WITH_AES_128_CBC_SHA256 - * TLS_RSA_WITH_AES_128_CBC_SHA - * TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 - * TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 - * TLS_RSA_PSK_WITH_AES_256_CBC_SHA - * TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 - * TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 - * TLS_RSA_PSK_WITH_AES_128_CBC_SHA - * TLS_PSK_WITH_AES_256_GCM_SHA384 - * TLS_PSK_WITH_AES_256_CBC_SHA384 - * TLS_PSK_WITH_AES_256_CBC_SHA - * TLS_PSK_WITH_AES_128_GCM_SHA256 - * TLS_PSK_WITH_AES_128_CBC_SHA256 - * TLS_PSK_WITH_AES_128_CBC_SHA - * - * PEM_PARSE uses AES for decrypting encrypted keys. - */ -#define POLARSSL_AES_C - -/** - * \def POLARSSL_ARC4_C - * - * Enable the ARCFOUR stream cipher. - * - * Module: library/arc4.c - * Caller: library/ssl_tls.c - * - * This module enables the following ciphersuites (if other requisites are - * enabled as well): - * TLS_ECDH_ECDSA_WITH_RC4_128_SHA - * TLS_ECDH_RSA_WITH_RC4_128_SHA - * TLS_ECDHE_ECDSA_WITH_RC4_128_SHA - * TLS_ECDHE_RSA_WITH_RC4_128_SHA - * TLS_ECDHE_PSK_WITH_RC4_128_SHA - * TLS_DHE_PSK_WITH_RC4_128_SHA - * TLS_RSA_WITH_RC4_128_SHA - * TLS_RSA_WITH_RC4_128_MD5 - * TLS_RSA_PSK_WITH_RC4_128_SHA - * TLS_PSK_WITH_RC4_128_SHA - */ -#define POLARSSL_ARC4_C - -/** - * \def POLARSSL_ASN1_PARSE_C - * - * Enable the generic ASN1 parser. - * - * Module: library/asn1.c - * Caller: library/x509.c - * library/dhm.c - * library/pkcs12.c - * library/pkcs5.c - * library/pkparse.c - */ -#define POLARSSL_ASN1_PARSE_C - -/** - * \def POLARSSL_ASN1_WRITE_C - * - * Enable the generic ASN1 writer. - * - * Module: library/asn1write.c - * Caller: library/ecdsa.c - * library/pkwrite.c - * library/x509_create.c - * library/x509write_crt.c - * library/x509write_csr.c - */ -#define POLARSSL_ASN1_WRITE_C - -/** - * \def POLARSSL_BASE64_C - * - * Enable the Base64 module. - * - * Module: library/base64.c - * Caller: library/pem.c - * - * This module is required for PEM support (required by X.509). - */ -#define POLARSSL_BASE64_C - -/** - * \def POLARSSL_BIGNUM_C - * - * Enable the multi-precision integer library. - * - * Module: library/bignum.c - * Caller: library/dhm.c - * library/ecp.c - * library/ecdsa.c - * library/rsa.c - * library/ssl_tls.c - * - * This module is required for RSA, DHM and ECC (ECDH, ECDSA) support. - */ -#define POLARSSL_BIGNUM_C - -/** - * \def POLARSSL_BLOWFISH_C - * - * Enable the Blowfish block cipher. - * - * Module: library/blowfish.c - */ -#define POLARSSL_BLOWFISH_C - -/** - * \def POLARSSL_CAMELLIA_C - * - * Enable the Camellia block cipher. - * - * Module: library/camellia.c - * Caller: library/ssl_tls.c - * - * This module enables the following ciphersuites (if other requisites are - * enabled as well): - * TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 - * TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 - * TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 - * TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 - * TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 - * TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 - * TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 - * TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 - * TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 - * TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 - * TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 - * TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 - * TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 - * TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 - * TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA - * TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 - * TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 - * TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 - * TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 - * TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 - * TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 - * TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA - * TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 - * TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 - * TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 - * TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 - * TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 - * TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 - * TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 - * TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 - * TLS_RSA_WITH_CAMELLIA_256_CBC_SHA - * TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 - * TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 - * TLS_RSA_WITH_CAMELLIA_128_CBC_SHA - * TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 - * TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 - * TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 - * TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 - * TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 - * TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 - * TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 - * TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 - */ -#define POLARSSL_CAMELLIA_C - -/** - * \def POLARSSL_CCM_C - * - * Enable the Counter with CBC-MAC (CCM) mode for 128-bit block cipher. - * - * Module: library/ccm.c - * - * Requires: POLARSSL_AES_C or POLARSSL_CAMELLIA_C - * - * This module enables the AES-CCM ciphersuites, if other requisites are - * enabled as well. - */ -#define POLARSSL_CCM_C - -/** - * \def POLARSSL_CERTS_C - * - * Enable the test certificates. - * - * Module: library/certs.c - * Caller: - * - * Requires: POLARSSL_PEM_PARSE_C - * - * This module is used for testing (ssl_client/server). - */ -#define POLARSSL_CERTS_C - -/** - * \def POLARSSL_CIPHER_C - * - * Enable the generic cipher layer. - * - * Module: library/cipher.c - * Caller: library/ssl_tls.c - * - * Uncomment to enable generic cipher wrappers. - */ -#define POLARSSL_CIPHER_C - -/** - * \def POLARSSL_CTR_DRBG_C - * - * Enable the CTR_DRBG AES-256-based random generator. - * - * Module: library/ctr_drbg.c - * Caller: - * - * Requires: POLARSSL_AES_C - * - * This module provides the CTR_DRBG AES-256 random number generator. - */ -#define POLARSSL_CTR_DRBG_C - -/** - * \def POLARSSL_DEBUG_C - * - * Enable the debug functions. - * - * Module: library/debug.c - * Caller: library/ssl_cli.c - * library/ssl_srv.c - * library/ssl_tls.c - * - * This module provides debugging functions. - */ -#define POLARSSL_DEBUG_C - -/** - * \def POLARSSL_DES_C - * - * Enable the DES block cipher. - * - * Module: library/des.c - * Caller: library/pem.c - * library/ssl_tls.c - * - * This module enables the following ciphersuites (if other requisites are - * enabled as well): - * TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA - * TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA - * TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA - * TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA - * TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA - * TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA - * TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA - * TLS_RSA_WITH_3DES_EDE_CBC_SHA - * TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA - * TLS_PSK_WITH_3DES_EDE_CBC_SHA - * - * PEM_PARSE uses DES/3DES for decrypting encrypted keys. - */ -#define POLARSSL_DES_C - -/** - * \def POLARSSL_DHM_C - * - * Enable the Diffie-Hellman-Merkle module. - * - * Module: library/dhm.c - * Caller: library/ssl_cli.c - * library/ssl_srv.c - * - * This module is used by the following key exchanges: - * DHE-RSA, DHE-PSK - */ -#define POLARSSL_DHM_C - -/** - * \def POLARSSL_ECDH_C - * - * Enable the elliptic curve Diffie-Hellman library. - * - * Module: library/ecdh.c - * Caller: library/ssl_cli.c - * library/ssl_srv.c - * - * This module is used by the following key exchanges: - * ECDHE-ECDSA, ECDHE-RSA, DHE-PSK - * - * Requires: POLARSSL_ECP_C - */ -#define POLARSSL_ECDH_C - -/** - * \def POLARSSL_ECDSA_C - * - * Enable the elliptic curve DSA library. - * - * Module: library/ecdsa.c - * Caller: - * - * This module is used by the following key exchanges: - * ECDHE-ECDSA - * - * Requires: POLARSSL_ECP_C, POLARSSL_ASN1_WRITE_C, POLARSSL_ASN1_PARSE_C - */ -#define POLARSSL_ECDSA_C - -/** - * \def POLARSSL_ECP_C - * - * Enable the elliptic curve over GF(p) library. - * - * Module: library/ecp.c - * Caller: library/ecdh.c - * library/ecdsa.c - * - * Requires: POLARSSL_BIGNUM_C and at least one POLARSSL_ECP_DP_XXX_ENABLED - */ -#define POLARSSL_ECP_C - -/** - * \def POLARSSL_ENTROPY_C - * - * Enable the platform-specific entropy code. - * - * Module: library/entropy.c - * Caller: - * - * Requires: POLARSSL_SHA512_C or POLARSSL_SHA256_C - * - * This module provides a generic entropy pool - */ -#define POLARSSL_ENTROPY_C - -/** - * \def POLARSSL_ERROR_C - * - * Enable error code to error string conversion. - * - * Module: library/error.c - * Caller: - * - * This module enables polarssl_strerror(). - */ -#define POLARSSL_ERROR_C - -/** - * \def POLARSSL_GCM_C - * - * Enable the Galois/Counter Mode (GCM) for AES. - * - * Module: library/gcm.c - * - * Requires: POLARSSL_AES_C or POLARSSL_CAMELLIA_C - * - * This module enables the AES-GCM and CAMELLIA-GCM ciphersuites, if other - * requisites are enabled as well. - */ -#define POLARSSL_GCM_C - -/** - * \def POLARSSL_HAVEGE_C - * - * Enable the HAVEGE random generator. - * - * Warning: the HAVEGE random generator is not suitable for virtualized - * environments - * - * Warning: the HAVEGE random generator is dependent on timing and specific - * processor traits. It is therefore not advised to use HAVEGE as - * your applications primary random generator or primary entropy pool - * input. As a secondary input to your entropy pool, it IS able add - * the (limited) extra entropy it provides. - * - * Module: library/havege.c - * Caller: - * - * Requires: POLARSSL_TIMING_C - * - * Uncomment to enable the HAVEGE random generator. - */ -//#define POLARSSL_HAVEGE_C - -/** - * \def POLARSSL_HMAC_DRBG_C - * - * Enable the HMAC_DRBG random generator. - * - * Module: library/hmac_drbg.c - * Caller: - * - * Requires: POLARSSL_MD_C - * - * Uncomment to enable the HMAC_DRBG random number geerator. - */ -#define POLARSSL_HMAC_DRBG_C - -/** - * \def POLARSSL_MD_C - * - * Enable the generic message digest layer. - * - * Module: library/md.c - * Caller: - * - * Uncomment to enable generic message digest wrappers. - */ -#define POLARSSL_MD_C - -/** - * \def POLARSSL_MD2_C - * - * Enable the MD2 hash algorithm. - * - * Module: library/md2.c - * Caller: - * - * Uncomment to enable support for (rare) MD2-signed X.509 certs. - */ -//#define POLARSSL_MD2_C - -/** - * \def POLARSSL_MD4_C - * - * Enable the MD4 hash algorithm. - * - * Module: library/md4.c - * Caller: - * - * Uncomment to enable support for (rare) MD4-signed X.509 certs. - */ -//#define POLARSSL_MD4_C - -/** - * \def POLARSSL_MD5_C - * - * Enable the MD5 hash algorithm. - * - * Module: library/md5.c - * Caller: library/md.c - * library/pem.c - * library/ssl_tls.c - * - * This module is required for SSL/TLS and X.509. - * PEM_PARSE uses MD5 for decrypting encrypted keys. - */ -#define POLARSSL_MD5_C - -/** - * \def POLARSSL_MEMORY_C - * Deprecated since 1.3.5. Please use POLARSSL_PLATFORM_MEMORY instead. - */ -//#define POLARSSL_MEMORY_C - -/** - * \def POLARSSL_MEMORY_BUFFER_ALLOC_C - * - * Enable the buffer allocator implementation that makes use of a (stack) - * based buffer to 'allocate' dynamic memory. (replaces malloc() and free() - * calls) - * - * Module: library/memory_buffer_alloc.c - * - * Requires: POLARSSL_PLATFORM_C - * POLARSSL_PLATFORM_MEMORY (to use it within PolarSSL) - * - * Enable this module to enable the buffer memory allocator. - */ -//#define POLARSSL_MEMORY_BUFFER_ALLOC_C - -/** - * \def POLARSSL_NET_C - * - * Enable the TCP/IP networking routines. - * - * Module: library/net.c - * - * This module provides TCP/IP networking routines. - */ -#define POLARSSL_NET_C - -/** - * \def POLARSSL_OID_C - * - * Enable the OID database. - * - * Module: library/oid.c - * Caller: library/asn1write.c - * library/pkcs5.c - * library/pkparse.c - * library/pkwrite.c - * library/rsa.c - * library/x509.c - * library/x509_create.c - * library/x509_crl.c - * library/x509_crt.c - * library/x509_csr.c - * library/x509write_crt.c - * library/x509write_csr.c - * - * This modules translates between OIDs and internal values. - */ -#define POLARSSL_OID_C - -/** - * \def POLARSSL_PADLOCK_C - * - * Enable VIA Padlock support on x86. - * - * Module: library/padlock.c - * Caller: library/aes.c - * - * Requires: POLARSSL_HAVE_ASM - * - * This modules adds support for the VIA PadLock on x86. - */ -//#define POLARSSL_PADLOCK_C - -/** - * \def POLARSSL_PBKDF2_C - * - * Enable PKCS#5 PBKDF2 key derivation function. - * DEPRECATED: Use POLARSSL_PKCS5_C instead - * - * Module: library/pbkdf2.c - * - * Requires: POLARSSL_PKCS5_C - * - * This module adds support for the PKCS#5 PBKDF2 key derivation function. - */ -#define POLARSSL_PBKDF2_C - -/** - * \def POLARSSL_PEM_PARSE_C - * - * Enable PEM decoding / parsing. - * - * Module: library/pem.c - * Caller: library/dhm.c - * library/pkparse.c - * library/x509_crl.c - * library/x509_crt.c - * library/x509_csr.c - * - * Requires: POLARSSL_BASE64_C - * - * This modules adds support for decoding / parsing PEM files. - */ -#define POLARSSL_PEM_PARSE_C - -/** - * \def POLARSSL_PEM_WRITE_C - * - * Enable PEM encoding / writing. - * - * Module: library/pem.c - * Caller: library/pkwrite.c - * library/x509write_crt.c - * library/x509write_csr.c - * - * Requires: POLARSSL_BASE64_C - * - * This modules adds support for encoding / writing PEM files. - */ -#define POLARSSL_PEM_WRITE_C - -/** - * \def POLARSSL_PK_C - * - * Enable the generic public (asymetric) key layer. - * - * Module: library/pk.c - * Caller: library/ssl_tls.c - * library/ssl_cli.c - * library/ssl_srv.c - * - * Requires: POLARSSL_RSA_C or POLARSSL_ECP_C - * - * Uncomment to enable generic public key wrappers. - */ -#define POLARSSL_PK_C - -/** - * \def POLARSSL_PK_PARSE_C - * - * Enable the generic public (asymetric) key parser. - * - * Module: library/pkparse.c - * Caller: library/x509_crt.c - * library/x509_csr.c - * - * Requires: POLARSSL_PK_C - * - * Uncomment to enable generic public key parse functions. - */ -#define POLARSSL_PK_PARSE_C - -/** - * \def POLARSSL_PK_WRITE_C - * - * Enable the generic public (asymetric) key writer. - * - * Module: library/pkwrite.c - * Caller: library/x509write.c - * - * Requires: POLARSSL_PK_C - * - * Uncomment to enable generic public key write functions. - */ -#define POLARSSL_PK_WRITE_C - -/** - * \def POLARSSL_PKCS5_C - * - * Enable PKCS#5 functions. - * - * Module: library/pkcs5.c - * - * Requires: POLARSSL_MD_C - * - * This module adds support for the PKCS#5 functions. - */ -#define POLARSSL_PKCS5_C - -/** - * \def POLARSSL_PKCS11_C - * - * Enable wrapper for PKCS#11 smartcard support. - * - * Module: library/pkcs11.c - * Caller: library/pk.c - * - * Requires: POLARSSL_PK_C - * - * This module enables SSL/TLS PKCS #11 smartcard support. - * Requires the presence of the PKCS#11 helper library (libpkcs11-helper) - */ -//#define POLARSSL_PKCS11_C - -/** - * \def POLARSSL_PKCS12_C - * - * Enable PKCS#12 PBE functions. - * Adds algorithms for parsing PKCS#8 encrypted private keys - * - * Module: library/pkcs12.c - * Caller: library/pkparse.c - * - * Requires: POLARSSL_ASN1_PARSE_C, POLARSSL_CIPHER_C, POLARSSL_MD_C - * Can use: POLARSSL_ARC4_C - * - * This module enables PKCS#12 functions. - */ -#define POLARSSL_PKCS12_C - -/** - * \def POLARSSL_PLATFORM_C - * - * Enable the platform abstraction layer that allows you to re-assign - * functions like malloc(), free(), printf(), fprintf() - * - * Module: library/platform.c - * Caller: Most other .c files - * - * This module enables abstraction of common (libc) functions. - */ -//#define POLARSSL_PLATFORM_C - -/** - * \def POLARSSL_RIPEMD160_C - * - * Enable the RIPEMD-160 hash algorithm. - * - * Module: library/ripemd160.c - * Caller: library/md.c - * - */ -#define POLARSSL_RIPEMD160_C - -/** - * \def POLARSSL_RSA_C - * - * Enable the RSA public-key cryptosystem. - * - * Module: library/rsa.c - * Caller: library/ssl_cli.c - * library/ssl_srv.c - * library/ssl_tls.c - * library/x509.c - * - * This module is used by the following key exchanges: - * RSA, DHE-RSA, ECDHE-RSA, RSA-PSK - * - * Requires: POLARSSL_BIGNUM_C, POLARSSL_OID_C - */ -#define POLARSSL_RSA_C - -/** - * \def POLARSSL_SHA1_C - * - * Enable the SHA1 cryptographic hash algorithm. - * - * Module: library/sha1.c - * Caller: library/md.c - * library/ssl_cli.c - * library/ssl_srv.c - * library/ssl_tls.c - * library/x509write_crt.c - * - * This module is required for SSL/TLS and SHA1-signed certificates. - */ -#define POLARSSL_SHA1_C - -/** - * \def POLARSSL_SHA256_C - * - * Enable the SHA-224 and SHA-256 cryptographic hash algorithms. - * (Used to be POLARSSL_SHA2_C) - * - * Module: library/sha256.c - * Caller: library/entropy.c - * library/md.c - * library/ssl_cli.c - * library/ssl_srv.c - * library/ssl_tls.c - * - * This module adds support for SHA-224 and SHA-256. - * This module is required for the SSL/TLS 1.2 PRF function. - */ -#define POLARSSL_SHA256_C - -/** - * \def POLARSSL_SHA512_C - * - * Enable the SHA-384 and SHA-512 cryptographic hash algorithms. - * (Used to be POLARSSL_SHA4_C) - * - * Module: library/sha512.c - * Caller: library/entropy.c - * library/md.c - * library/ssl_cli.c - * library/ssl_srv.c - * - * This module adds support for SHA-384 and SHA-512. - */ -#define POLARSSL_SHA512_C - -/** - * \def POLARSSL_SSL_CACHE_C - * - * Enable simple SSL cache implementation. - * - * Module: library/ssl_cache.c - * Caller: - * - * Requires: POLARSSL_SSL_CACHE_C - */ -#define POLARSSL_SSL_CACHE_C - -/** - * \def POLARSSL_SSL_CLI_C - * - * Enable the SSL/TLS client code. - * - * Module: library/ssl_cli.c - * Caller: - * - * Requires: POLARSSL_SSL_TLS_C - * - * This module is required for SSL/TLS client support. - */ -#define POLARSSL_SSL_CLI_C - -/** - * \def POLARSSL_SSL_SRV_C - * - * Enable the SSL/TLS server code. - * - * Module: library/ssl_srv.c - * Caller: - * - * Requires: POLARSSL_SSL_TLS_C - * - * This module is required for SSL/TLS server support. - */ -#define POLARSSL_SSL_SRV_C - -/** - * \def POLARSSL_SSL_TLS_C - * - * Enable the generic SSL/TLS code. - * - * Module: library/ssl_tls.c - * Caller: library/ssl_cli.c - * library/ssl_srv.c - * - * Requires: POLARSSL_CIPHER_C, POLARSSL_MD_C - * and at least one of the POLARSSL_SSL_PROTO_* defines - * - * This module is required for SSL/TLS. - */ -#define POLARSSL_SSL_TLS_C - -/** - * \def POLARSSL_THREADING_C - * - * Enable the threading abstraction layer. - * By default PolarSSL assumes it is used in a non-threaded environment or that - * contexts are not shared between threads. If you do intend to use contexts - * between threads, you will need to enable this layer to prevent race - * conditions. - * - * Module: library/threading.c - * - * This allows different threading implementations (self-implemented or - * provided). - * - * You will have to enable either POLARSSL_THREADING_ALT or - * POLARSSL_THREADING_PTHREAD. - * - * Enable this layer to allow use of mutexes within PolarSSL - */ -//#define POLARSSL_THREADING_C - -/** - * \def POLARSSL_TIMING_C - * - * Enable the portable timing interface. - * - * Module: library/timing.c - * Caller: library/havege.c - * - * This module is used by the HAVEGE random number generator. - */ -#define POLARSSL_TIMING_C - -/** - * \def POLARSSL_VERSION_C - * - * Enable run-time version information. - * - * Module: library/version.c - * - * This module provides run-time version information. - */ -#define POLARSSL_VERSION_C - -/** - * \def POLARSSL_X509_USE_C - * - * Enable X.509 core for using certificates. - * - * Module: library/x509.c - * Caller: library/x509_crl.c - * library/x509_crt.c - * library/x509_csr.c - * - * Requires: POLARSSL_ASN1_PARSE_C, POLARSSL_BIGNUM_C, POLARSSL_OID_C, - * POLARSSL_PK_PARSE_C - * - * This module is required for the X.509 parsing modules. - */ -#define POLARSSL_X509_USE_C - -/** - * \def POLARSSL_X509_CRT_PARSE_C - * - * Enable X.509 certificate parsing. - * - * Module: library/x509_crt.c - * Caller: library/ssl_cli.c - * library/ssl_srv.c - * library/ssl_tls.c - * - * Requires: POLARSSL_X509_USE_C - * - * This module is required for X.509 certificate parsing. - */ -#define POLARSSL_X509_CRT_PARSE_C - -/** - * \def POLARSSL_X509_CRL_PARSE_C - * - * Enable X.509 CRL parsing. - * - * Module: library/x509_crl.c - * Caller: library/x509_crt.c - * - * Requires: POLARSSL_X509_USE_C - * - * This module is required for X.509 CRL parsing. - */ -#define POLARSSL_X509_CRL_PARSE_C - -/** - * \def POLARSSL_X509_CSR_PARSE_C - * - * Enable X.509 Certificate Signing Request (CSR) parsing. - * - * Module: library/x509_csr.c - * Caller: library/x509_crt_write.c - * - * Requires: POLARSSL_X509_USE_C - * - * This module is used for reading X.509 certificate request. - */ -#define POLARSSL_X509_CSR_PARSE_C - -/** - * \def POLARSSL_X509_CREATE_C - * - * Enable X.509 core for creating certificates. - * - * Module: library/x509_create.c - * - * Requires: POLARSSL_BIGNUM_C, POLARSSL_OID_C, POLARSSL_PK_WRITE_C - * - * This module is the basis for creating X.509 certificates and CSRs. - */ -#define POLARSSL_X509_CREATE_C - -/** - * \def POLARSSL_X509_CRT_WRITE_C - * - * Enable creating X.509 certificates. - * - * Module: library/x509_crt_write.c - * - * Requires: POLARSSL_CREATE_C - * - * This module is required for X.509 certificate creation. - */ -#define POLARSSL_X509_CRT_WRITE_C - -/** - * \def POLARSSL_X509_CSR_WRITE_C - * - * Enable creating X.509 Certificate Signing Requests (CSR). - * - * Module: library/x509_csr_write.c - * - * Requires: POLARSSL_CREATE_C - * - * This module is required for X.509 certificate request writing. - */ -#define POLARSSL_X509_CSR_WRITE_C - -/** - * \def POLARSSL_XTEA_C - * - * Enable the XTEA block cipher. - * - * Module: library/xtea.c - * Caller: - */ -#define POLARSSL_XTEA_C - -/* \} name SECTION: PolarSSL modules */ - -/** - * \name SECTION: Module configuration options - * - * This section allows for the setting of module specific sizes and - * configuration options. The default values are already present in the - * relevant header files and should suffice for the regular use cases. - * - * Our advice is to enable options and change their values here - * only if you have a good reason and know the consequences. - * - * Please check the respective header file for documentation on these - * parameters (to prevent duplicate documentation). - * \{ - */ - -/* MPI / BIGNUM options */ -//#define POLARSSL_MPI_WINDOW_SIZE 6 /**< Maximum windows size used. */ -//#define POLARSSL_MPI_MAX_SIZE 1024 /**< Maximum number of bytes for usable MPIs. */ - -/* CTR_DRBG options */ -//#define CTR_DRBG_ENTROPY_LEN 48 /**< Amount of entropy used per seed by default (48 with SHA-512, 32 with SHA-256) */ -//#define CTR_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ -//#define CTR_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ -//#define CTR_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ -//#define CTR_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ - -/* HMAC_DRBG options */ -//#define POLARSSL_HMAC_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ -//#define POLARSSL_HMAC_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ -//#define POLARSSL_HMAC_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ -//#define POLARSSL_HMAC_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ - -/* ECP options */ -//#define POLARSSL_ECP_MAX_BITS 521 /**< Maximum bit size of groups */ -//#define POLARSSL_ECP_WINDOW_SIZE 6 /**< Maximum window size used */ -//#define POLARSSL_ECP_FIXED_POINT_OPTIM 1 /**< Enable fixed-point speed-up */ - -/* Entropy options */ -//#define ENTROPY_MAX_SOURCES 20 /**< Maximum number of sources supported */ -//#define ENTROPY_MAX_GATHER 128 /**< Maximum amount requested from entropy sources */ - -/* Memory buffer allocator options */ -//#define POLARSSL_MEMORY_ALIGN_MULTIPLE 4 /**< Align on multiples of this value */ - -/* Platform options */ -//#define POLARSSL_PLATFORM_STD_MEM_HDR /**< Header to include if POLARSSL_PLATFORM_NO_STD_FUNCTIONS is defined. Don't define if no header is needed. */ -//#define POLARSSL_PLATFORM_STD_MALLOC malloc /**< Default allocator to use, can be undefined */ -//#define POLARSSL_PLATFORM_STD_FREE free /**< Default free to use, can be undefined */ -//#define POLARSSL_PLATFORM_STD_PRINTF printf /**< Default printf to use, can be undefined */ -//#define POLARSSL_PLATFORM_STD_FPRINTF fprintf /**< Default fprintf to use, can be undefined */ - -/* SSL Cache options */ -//#define SSL_CACHE_DEFAULT_TIMEOUT 86400 /**< 1 day */ -//#define SSL_CACHE_DEFAULT_MAX_ENTRIES 50 /**< Maximum entries in cache */ - -/* SSL options */ -//#define SSL_MAX_CONTENT_LEN 16384 /**< Size of the input / output buffer */ -//#define SSL_DEFAULT_TICKET_LIFETIME 86400 /**< Lifetime of session tickets (if enabled) */ -//#define POLARSSL_PSK_MAX_LEN 32 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */ - -/** - * Complete list of ciphersuites to use, in order of preference. - * - * \warning No dependency checking is done on that field! This option can only - * be used to restrict the set of available ciphersuites. It is your - * responsibility to make sure the needed modules are active. - * - * Use this to save a few hundred bytes of ROM (default ordering of all - * available ciphersuites) and a few to a few hundred bytes of RAM. - * - * The value below is only an example, not the default. - */ -//#define SSL_CIPHERSUITES TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 - -/* Debug options */ -//#define POLARSSL_DEBUG_DFL_MODE POLARSSL_DEBUG_LOG_FULL /**< Default log: Full or Raw */ - -/* \} name SECTION: Module configuration options */ - - -#endif /* POLARSSL_CONFIG_H */ From 6b882a3918590b9c0f45643323adae9862eedde5 Mon Sep 17 00:00:00 2001 From: Oleg Moiseenko <807634+merlokk@users.noreply.github.com> Date: Sun, 25 Nov 2018 17:56:12 +0200 Subject: [PATCH 020/189] Fido U2F complete (#716) * add pkwrite * asn1print * asn1dump and CA * added PrintAndLogEx for merge commits between repo easier than now * changelog --- CHANGELOG.md | 1 + client/Makefile | 2 + client/cmdhffido.c | 191 ++- client/crypto/asn1dump.c | 353 ++++++ client/crypto/asn1dump.h | 21 + client/crypto/asn1utils.c | 29 +- client/crypto/asn1utils.h | 2 +- client/crypto/libpcrypto.c | 26 + client/crypto/libpcrypto.h | 2 + client/crypto/oids.json | 2325 +++++++++++++++++++++++++++++++++++ client/emv/emvjson.c | 17 + client/emv/emvjson.h | 1 + client/fido/additional_ca.c | 63 + client/fido/additional_ca.h | 21 + client/obj/fido/.dummy | 0 client/ui.c | 72 ++ client/ui.h | 4 + client/util.c | 29 + client/util.h | 43 + common/mbedtls/Makefile | 1 + common/mbedtls/pkwrite.c | 517 ++++++++ 21 files changed, 3703 insertions(+), 17 deletions(-) create mode 100644 client/crypto/asn1dump.c create mode 100644 client/crypto/asn1dump.h create mode 100644 client/crypto/oids.json create mode 100644 client/fido/additional_ca.c create mode 100644 client/fido/additional_ca.h create mode 100644 client/obj/fido/.dummy create mode 100644 common/mbedtls/pkwrite.c diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b134562..b0073f34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ### Changed - Changed hf mfp security. Now it works in all the modes. (drHatson) +- `hf fido` - show/check DER certificate and signatures (Merlok) ### Fixed diff --git a/client/Makefile b/client/Makefile index a049ae5a..5ed4ea49 100644 --- a/client/Makefile +++ b/client/Makefile @@ -109,8 +109,10 @@ CMDSRCS = $(SRC_SMARTCARD) \ crapto1/crypto1.c\ crypto/libpcrypto.c\ crypto/asn1utils.c\ + crypto/asn1dump.c\ cliparser/argtable3.c\ cliparser/cliparser.c\ + fido/additional_ca.c \ mfkey.c\ loclass/cipher.c \ loclass/cipherutils.c \ diff --git a/client/cmdhffido.c b/client/cmdhffido.c index fd97ace5..e2d6c091 100644 --- a/client/cmdhffido.c +++ b/client/cmdhffido.c @@ -39,6 +39,12 @@ #include "emv/emvjson.h" #include "emv/dump.h" #include "cliparser/cliparser.h" +#include "crypto/asn1utils.h" +#include "crypto/libpcrypto.h" +#include "fido/additional_ca.h" +#include "mbedtls/x509_crt.h" +#include "mbedtls/x509.h" +#include "mbedtls/pk.h" static int CmdHelp(const char *Cmd); @@ -201,8 +207,9 @@ int CmdHFFidoRegister(const char *cmd) { void* argtable[] = { arg_param_begin, arg_lit0("aA", "apdu", "show APDU reqests and responses"), - arg_lit0("vV", "verbose", "show technical data"), + arg_litn("vV", "verbose", 0, 2, "show technical data. vv - show full certificates data"), arg_lit0("pP", "plain", "send plain ASCII to challenge and application parameters instead of HEX"), + arg_lit0("tT", "tlv", "Show DER certificate contents in TLV representation"), arg_str0("jJ", "json", "fido.json", "JSON input / output file name for parameters."), arg_str0(NULL, NULL, "", NULL), arg_str0(NULL, NULL, "", NULL), @@ -212,11 +219,13 @@ int CmdHFFidoRegister(const char *cmd) { bool APDULogging = arg_get_lit(1); bool verbose = arg_get_lit(2); + bool verbose2 = arg_get_lit(2) > 1; bool paramsPlain = arg_get_lit(3); + bool showDERTLV = arg_get_lit(4); char fname[250] = {0}; bool err; - root = OpenJson(4, fname, argtable, &err); + root = OpenJson(5, fname, argtable, &err); if(err) return 1; if (root) { @@ -227,13 +236,13 @@ int CmdHFFidoRegister(const char *cmd) { if (paramsPlain) { memset(cdata, 0x00, 32); - CLIGetStrWithReturn(5, cdata, &chlen); + CLIGetStrWithReturn(6, cdata, &chlen); if (chlen && chlen > 16) { PrintAndLog("ERROR: challenge parameter length in ASCII mode must be less than 16 chars instead of: %d", chlen); return 1; } } else { - CLIGetHexWithReturn(5, cdata, &chlen); + CLIGetHexWithReturn(6, cdata, &chlen); if (chlen && chlen != 32) { PrintAndLog("ERROR: challenge parameter length must be 32 bytes only."); return 1; @@ -245,13 +254,13 @@ int CmdHFFidoRegister(const char *cmd) { if (paramsPlain) { memset(adata, 0x00, 32); - CLIGetStrWithReturn(6, adata, &applen); + CLIGetStrWithReturn(7, adata, &applen); if (applen && applen > 16) { PrintAndLog("ERROR: application parameter length in ASCII mode must be less than 16 chars instead of: %d", applen); return 1; } } else { - CLIGetHexWithReturn(6, adata, &applen); + CLIGetHexWithReturn(7, adata, &applen); if (applen && applen != 32) { PrintAndLog("ERROR: application parameter length must be 32 bytes only."); return 1; @@ -302,7 +311,7 @@ int CmdHFFidoRegister(const char *cmd) { if (APDULogging) PrintAndLog("---------------------------------------------------------------"); PrintAndLog("data len: %d", len); - if (verbose) { + if (verbose2) { PrintAndLog("--------------data----------------------"); dump_buffer((const unsigned char *)buf, len, NULL, 0); PrintAndLog("--------------data----------------------"); @@ -319,20 +328,119 @@ int CmdHFFidoRegister(const char *cmd) { int derp = 67 + keyHandleLen; int derLen = (buf[derp + 2] << 8) + buf[derp + 3] + 4; - // needs to decode DER certificate - if (verbose) { - PrintAndLog("DER certificate[%d]:------------------DER-------------------", derLen); - dump_buffer_simple((const unsigned char *)&buf[67 + keyHandleLen], derLen, NULL); + if (verbose2) { + PrintAndLog("DER certificate[%d]:\n------------------DER-------------------", derLen); + dump_buffer_simple((const unsigned char *)&buf[derp], derLen, NULL); PrintAndLog("\n----------------DER---------------------"); } else { + if (verbose) + PrintAndLog("------------------DER-------------------"); PrintAndLog("DER certificate[%d]: %s...", derLen, sprint_hex(&buf[derp], 20)); } + // check and print DER certificate + uint8_t public_key[65] = {0}; + // print DER certificate in TLV view + if (showDERTLV) { + PrintAndLog("----------------DER TLV-----------------"); + asn1_print(&buf[derp], derLen, " "); + PrintAndLog("----------------DER TLV-----------------"); + } + + // load CA's + mbedtls_x509_crt cacert; + mbedtls_x509_crt_init(&cacert); + res = mbedtls_x509_crt_parse(&cacert, (const unsigned char *) additional_ca_pem, additional_ca_pem_len); + if (res < 0) { + PrintAndLog("ERROR: CA parse certificate returned -0x%x - %s", -res, ecdsa_get_error(res)); + } + if (verbose) + PrintAndLog("CA load OK. %d skipped", res); + + // load DER certificate from authenticator's data + mbedtls_x509_crt cert; + mbedtls_x509_crt_init(&cert); + res = mbedtls_x509_crt_parse_der(&cert, &buf[derp], derLen); + if (res) { + PrintAndLog("ERROR: DER parse returned 0x%x - %s", (res<0)?-res:res, ecdsa_get_error(res)); + } + + // get certificate info + char linfo[300] = {0}; + if (verbose) { + mbedtls_x509_crt_info(linfo, sizeof(linfo), " ", &cert); + PrintAndLog("DER certificate info:\n%s", linfo); + } + + // verify certificate + uint32_t verifyflags = 0; + res = mbedtls_x509_crt_verify(&cert, &cacert, NULL, NULL, &verifyflags, NULL, NULL); + if (res) { + PrintAndLog("ERROR: DER verify returned 0x%x - %s", (res<0)?-res:res, ecdsa_get_error(res)); + } else { + PrintAndLog("Certificate OK."); + } + + if (verbose) { + memset(linfo, 0x00, sizeof(linfo)); + mbedtls_x509_crt_verify_info(linfo, sizeof(linfo), " ", verifyflags); + PrintAndLog("Verification info:\n%s", linfo); + } + + // get public key + res = ecdsa_public_key_from_pk(&cert.pk, public_key, sizeof(public_key)); + if (res) { + PrintAndLog("ERROR: getting public key from certificate 0x%x - %s", (res<0)?-res:res, ecdsa_get_error(res)); + } else { + if (verbose) + PrintAndLog("Got a public key from certificate:\n%s", sprint_hex_inrow(public_key, 65)); + } + + if (verbose) + PrintAndLog("------------------DER-------------------"); + + mbedtls_x509_crt_free(&cert); + mbedtls_x509_crt_free(&cacert); + + // get hash int hashp = 1 + 65 + 1 + keyHandleLen + derLen; PrintAndLog("Hash[%d]: %s", len - hashp, sprint_hex(&buf[hashp], len - hashp)); - + // check ANSI X9.62 format ECDSA signature (on P-256) + uint8_t rval[300] = {0}; + uint8_t sval[300] = {0}; + res = ecdsa_asn1_get_signature(&buf[hashp], len - hashp, rval, sval); + if (!res) { + if (verbose) { + PrintAndLog(" r: %s", sprint_hex(rval, 32)); + PrintAndLog(" s: %s", sprint_hex(sval, 32)); + } + + uint8_t xbuf[4096] = {0}; + size_t xbuflen = 0; + res = FillBuffer(xbuf, sizeof(xbuf), &xbuflen, + "\x00", 1, + &data[32], 32, // application parameter + &data[0], 32, // challenge parameter + &buf[67], keyHandleLen, // keyHandle + &buf[1], 65, // user public key + NULL, 0); + //PrintAndLog("--xbuf(%d)[%d]: %s", res, xbuflen, sprint_hex(xbuf, xbuflen)); + res = ecdsa_signature_verify(public_key, xbuf, xbuflen, &buf[hashp], len - hashp); + if (res) { + if (res == -0x4e00) { + PrintAndLog("Signature is NOT VALID."); + } else { + PrintAndLog("Other signature check error: %x %s", (res<0)?-res:res, ecdsa_get_error(res)); + } + } else { + PrintAndLog("Signature is OK."); + } + + } else { + PrintAndLog("Invalid signature. res=%d.", res); + } PrintAndLog("\nauth command: "); printf("hf fido auth %s%s", paramsPlain?"-p ":"", sprint_hex_inrow(&buf[67], keyHandleLen)); @@ -345,6 +453,7 @@ int CmdHFFidoRegister(const char *cmd) { if (root) { JsonSaveBufAsHex(root, "ChallengeParam", data, 32); JsonSaveBufAsHex(root, "ApplicationParam", &data[32], 32); + JsonSaveBufAsHexCompact(root, "PublicKey", &buf[1], 65); JsonSaveInt(root, "KeyHandleLen", keyHandleLen); JsonSaveBufAsHexCompact(root, "KeyHandle", &buf[67], keyHandleLen); JsonSaveBufAsHexCompact(root, "DER", &buf[67 + keyHandleLen], derLen); @@ -366,6 +475,8 @@ int CmdHFFidoRegister(const char *cmd) { int CmdHFFidoAuthenticate(const char *cmd) { uint8_t data[512] = {0}; uint8_t hdata[250] = {0}; + bool public_key_loaded = false; + uint8_t public_key[65] = {0}; int hdatalen = 0; uint8_t keyHandleLen = 0; json_t *root = NULL; @@ -385,6 +496,7 @@ int CmdHFFidoAuthenticate(const char *cmd) { arg_lit0("uU", "user", "mode: enforce-user-presence-and-sign"), arg_lit0("cC", "check", "mode: check-only"), arg_str0("jJ", "json", "fido.json", "JSON input / output file name for parameters."), + arg_str0("kK", "key", "public key to verify signature", NULL), arg_str0(NULL, NULL, "", NULL), arg_str0(NULL, NULL, "", NULL), arg_str0(NULL, NULL, "", NULL), @@ -393,7 +505,7 @@ int CmdHFFidoAuthenticate(const char *cmd) { CLIExecWithReturn(cmd, argtable, true); bool APDULogging = arg_get_lit(1); - //bool verbose = arg_get_lit(2); + bool verbose = arg_get_lit(2); bool paramsPlain = arg_get_lit(3); uint8_t controlByte = 0x08; if (arg_get_lit(5)) @@ -413,9 +525,22 @@ int CmdHFFidoAuthenticate(const char *cmd) { JsonLoadBufAsHex(root, "$.KeyHandle", &data[65], 512 - 67, &jlen); keyHandleLen = jlen & 0xff; data[64] = keyHandleLen; + JsonLoadBufAsHex(root, "$.PublicKey", public_key, 65, &jlen); + public_key_loaded = (jlen > 0); } + // public key CLIGetHexWithReturn(8, hdata, &hdatalen); + if (hdatalen && hdatalen != 130) { + PrintAndLog("ERROR: public key length must be 65 bytes only."); + return 1; + } + if (hdatalen) { + memmove(public_key, hdata, hdatalen); + public_key_loaded = true; + } + + CLIGetHexWithReturn(9, hdata, &hdatalen); if (hdatalen > 255) { PrintAndLog("ERROR: application parameter length must be less than 255."); return 1; @@ -434,7 +559,7 @@ int CmdHFFidoAuthenticate(const char *cmd) { return 1; } } else { - CLIGetHexWithReturn(9, hdata, &hdatalen); + CLIGetHexWithReturn(10, hdata, &hdatalen); if (hdatalen && hdatalen != 32) { PrintAndLog("ERROR: challenge parameter length must be 32 bytes only."); return 1; @@ -445,7 +570,7 @@ int CmdHFFidoAuthenticate(const char *cmd) { if (paramsPlain) { memset(hdata, 0x00, 32); - CLIGetStrWithReturn(10, hdata, &hdatalen); + CLIGetStrWithReturn(11, hdata, &hdatalen); if (hdatalen && hdatalen > 16) { PrintAndLog("ERROR: application parameter length in ASCII mode must be less than 16 chars instead of: %d", hdatalen); return 1; @@ -509,6 +634,42 @@ int CmdHFFidoAuthenticate(const char *cmd) { PrintAndLog("Counter: %d", cntr); PrintAndLog("Hash[%d]: %s", len - 5, sprint_hex(&buf[5], len - 5)); + // check ANSI X9.62 format ECDSA signature (on P-256) + uint8_t rval[300] = {0}; + uint8_t sval[300] = {0}; + res = ecdsa_asn1_get_signature(&buf[5], len - 5, rval, sval); + if (!res) { + if (verbose) { + PrintAndLog(" r: %s", sprint_hex(rval, 32)); + PrintAndLog(" s: %s", sprint_hex(sval, 32)); + } + if (public_key_loaded) { + uint8_t xbuf[4096] = {0}; + size_t xbuflen = 0; + res = FillBuffer(xbuf, sizeof(xbuf), &xbuflen, + &data[32], 32, // application parameter + &buf[0], 1, // user presence + &buf[1], 4, // counter + data, 32, // challenge parameter + NULL, 0); + //PrintAndLog("--xbuf(%d)[%d]: %s", res, xbuflen, sprint_hex(xbuf, xbuflen)); + res = ecdsa_signature_verify(public_key, xbuf, xbuflen, &buf[5], len - 5); + if (res) { + if (res == -0x4e00) { + PrintAndLog("Signature is NOT VALID."); + } else { + PrintAndLog("Other signature check error: %x %s", (res<0)?-res:res, ecdsa_get_error(res)); + } + } else { + PrintAndLog("Signature is OK."); + } + } else { + PrintAndLog("No public key provided. can't check signature."); + } + } else { + PrintAndLog("Invalid signature. res=%d.", res); + } + if (root) { JsonSaveBufAsHex(root, "ChallengeParam", data, 32); JsonSaveBufAsHex(root, "ApplicationParam", &data[32], 32); diff --git a/client/crypto/asn1dump.c b/client/crypto/asn1dump.c new file mode 100644 index 00000000..60799fc8 --- /dev/null +++ b/client/crypto/asn1dump.c @@ -0,0 +1,353 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2018 Merlok +// +// 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. +//----------------------------------------------------------------------------- +// asn.1 dumping +//----------------------------------------------------------------------------- + +#include "asn1dump.h" +#include +#include +#include +#include +#include +#include +#include +#include "emv/emv_tags.h" +#include "emv/dump.h" +#include "emv/emvjson.h" +#include "util.h" +#include "proxmark3.h" + +#define PRINT_INDENT(level) {for (int i = 0; i < (level); i++) fprintf(f, " ");} + +enum asn1_tag_t { + ASN1_TAG_GENERIC, + ASN1_TAG_BOOLEAN, + ASN1_TAG_INTEGER, + ASN1_TAG_STRING, + ASN1_TAG_OCTET_STRING, + ASN1_TAG_UTC_TIME, + ASN1_TAG_STR_TIME, + ASN1_TAG_OBJECT_ID, +}; + +struct asn1_tag { + tlv_tag_t tag; + char *name; + enum asn1_tag_t type; + const void *data; +}; + +static const struct asn1_tag asn1_tags[] = { + // internal + { 0x00 , "Unknown ???" }, + + // ASN.1 + { 0x01, "BOOLEAN", ASN1_TAG_BOOLEAN }, + { 0x02, "INTEGER", ASN1_TAG_INTEGER }, + { 0x03, "BIT STRING" }, + { 0x04, "OCTET STRING", ASN1_TAG_OCTET_STRING}, + { 0x05, "NULL" }, + { 0x06, "OBJECT IDENTIFIER", ASN1_TAG_OBJECT_ID }, + { 0x07, "OBJECT DESCRIPTOR" }, + { 0x08, "EXTERNAL" }, + { 0x09, "REAL" }, + { 0x0A, "ENUMERATED" }, + { 0x0B, "EMBEDDED_PDV" }, + { 0x0C, "UTF8String", ASN1_TAG_STRING }, + { 0x10, "SEQUENCE" }, + { 0x11, "SET" }, + { 0x12, "NumericString", ASN1_TAG_STRING }, + { 0x13, "PrintableString", ASN1_TAG_STRING }, + { 0x14, "T61String" }, + { 0x15, "VideotexString" }, + { 0x16, "IA5String" }, + { 0x17, "UTCTime", ASN1_TAG_UTC_TIME }, + { 0x18, "GeneralizedTime", ASN1_TAG_STR_TIME }, + { 0x19, "GraphicString" }, + { 0x1A, "VisibleString", ASN1_TAG_STRING }, + { 0x1B, "GeneralString", ASN1_TAG_STRING }, + { 0x1C, "UniversalString", ASN1_TAG_STRING }, + { 0x1E, "BMPString" }, + { 0x30, "SEQUENCE" }, + { 0x31, "SET" }, + { 0xa0, "[0]" }, + { 0xa1, "[1]" }, + { 0xa2, "[2]" }, + { 0xa3, "[3]" }, + { 0xa4, "[4]" }, + { 0xa5, "[5]" }, +}; + +static int asn1_sort_tag(tlv_tag_t tag) { + return (int)(tag >= 0x100 ? tag : tag << 8); +} + +static int asn1_tlv_compare(const void *a, const void *b) { + const struct tlv *tlv = a; + const struct asn1_tag *tag = b; + + return asn1_sort_tag(tlv->tag) - (asn1_sort_tag(tag->tag)); +} + +static const struct asn1_tag *asn1_get_tag(const struct tlv *tlv) { + struct asn1_tag *tag = bsearch(tlv, asn1_tags, sizeof(asn1_tags) / sizeof(asn1_tags[0]), + sizeof(asn1_tags[0]), asn1_tlv_compare); + + return tag ? tag : &asn1_tags[0]; +} + +static void asn1_tag_dump_str_time(const struct tlv *tlv, const struct asn1_tag *tag, FILE *f, int level, bool longyear, bool *needdump){ + int len = tlv->len; + *needdump = false; + + int startindx = longyear ? 4 : 2; + + if (len > 4) { + fprintf(f, "\tvalue: '"); + while (true) { + // year + if (!longyear) + fprintf(f, "20"); + fwrite(tlv->value, 1, longyear ? 4 : 2, f); + fprintf(f, "-"); + if (len < startindx + 2) + break; + // month + fwrite(&tlv->value[startindx], 1, 2, f); + fprintf(f, "-"); + if (len < startindx + 4) + break; + // day + fwrite(&tlv->value[startindx + 2], 1, 2, f); + fprintf(f, " "); + if (len < startindx + 6) + break; + // hour + fwrite(&tlv->value[startindx + 4], 1, 2, f); + fprintf(f, ":"); + if (len < startindx + 8) + break; + // min + fwrite(&tlv->value[startindx + 6], 1, 2, f); + fprintf(f, ":"); + if (len < startindx + 10) + break; + // sec + fwrite(&tlv->value[startindx + 8], 1, 2, f); + if (len < startindx + 11) + break; + // time zone + fprintf(f, " zone: %.*s", len - 10 - (longyear ? 4 : 2), &tlv->value[startindx + 10]); + + break; + } + fprintf(f, "'\n"); + } else { + fprintf(f, "\n"); + *needdump = true; + } +} + +static void asn1_tag_dump_string(const struct tlv *tlv, const struct asn1_tag *tag, FILE *f, int level){ + fprintf(f, "\tvalue: '"); + fwrite(tlv->value, 1, tlv->len, f); + fprintf(f, "'\n"); +} + +static void asn1_tag_dump_octet_string(const struct tlv *tlv, const struct asn1_tag *tag, FILE *f, int level, bool *needdump){ + *needdump = false; + for (int i = 0; i < tlv->len; i++) + if (!isspace(tlv->value[i]) && !isprint(tlv->value[i])){ + *needdump = true; + break; + } + + if (*needdump) { + fprintf(f, "'\n"); + } else { + fprintf(f, "\t\t"); + asn1_tag_dump_string(tlv, tag, f, level); + } +} + +static unsigned long asn1_value_integer(const struct tlv *tlv, unsigned start, unsigned end) { + unsigned long ret = 0; + int i; + + if (end > tlv->len * 2) + return ret; + if (start >= end) + return ret; + + if (start & 1) { + ret += tlv->value[start/2] & 0xf; + i = start + 1; + } else + i = start; + + for (; i < end - 1; i += 2) { + ret *= 10; + ret += tlv->value[i/2] >> 4; + ret *= 10; + ret += tlv->value[i/2] & 0xf; + } + + if (end & 1) { + ret *= 10; + ret += tlv->value[end/2] >> 4; + } + + return ret; +} + +static void asn1_tag_dump_boolean(const struct tlv *tlv, const struct asn1_tag *tag, FILE *f, int level) { + PRINT_INDENT(level); + if (tlv->len > 0) { + fprintf(f, "\tvalue: %s\n", tlv->value[0]?"true":"false"); + } else { + fprintf(f, "n/a\n"); + } +} + +static void asn1_tag_dump_integer(const struct tlv *tlv, const struct asn1_tag *tag, FILE *f, int level) { + PRINT_INDENT(level); + if (tlv->len == 4) { + int32_t val = 0; + for (int i = 0; i < tlv->len; i++) + val = (val << 8) + tlv->value[i]; + fprintf(f, "\tvalue4b: %d\n", val); + return; + } + fprintf(f, "\tvalue: %lu\n", asn1_value_integer(tlv, 0, tlv->len * 2)); +} + +static char *asn1_oid_description(const char *oid, bool with_group_desc) { + json_error_t error; + json_t *root = NULL; + char fname[300] = {0}; + static char res[300]; + memset(res, 0x00, sizeof(res)); + + strcpy(fname, get_my_executable_directory()); + strcat(fname, "crypto/oids.json"); + if (access(fname, F_OK) < 0) { + strcpy(fname, get_my_executable_directory()); + strcat(fname, "oids.json"); + if (access(fname, F_OK) < 0) { + goto error; // file not found + } + } + + // load `oids.json` + root = json_load_file(fname, 0, &error); + + if (!root || !json_is_object(root)) { + goto error; + } + + json_t *elm = json_object_get(root, oid); + if (!elm) { + goto error; + } + + if (JsonLoadStr(elm, "$.d", res)) + goto error; + + char strext[300] = {0}; + if (!JsonLoadStr(elm, "$.c", strext)) { + strcat(res, " ("); + strcat(res, strext); + strcat(res, ")"); + } + + json_decref(root); + return res; + +error: + if (root) + json_decref(root); + return NULL; +} + +static void asn1_tag_dump_object_id(const struct tlv *tlv, const struct asn1_tag *tag, FILE *f, int level) { + PRINT_INDENT(level); + mbedtls_asn1_buf asn1_buf; + asn1_buf.len = tlv->len; + asn1_buf.p = (uint8_t *)tlv->value; + char pstr[300]; + mbedtls_oid_get_numeric_string(pstr, sizeof(pstr), &asn1_buf); + fprintf(f, " %s", pstr); + + char *jsondesc = asn1_oid_description(pstr, true); + if (jsondesc) { + fprintf(f, " - %s", jsondesc); + } else { + const char *ppstr; + mbedtls_oid_get_attr_short_name(&asn1_buf, &ppstr); + if (ppstr && strnlen(ppstr, 1)) { + fprintf(f, " (%s)\n", ppstr); + return; + } + mbedtls_oid_get_sig_alg_desc(&asn1_buf, &ppstr); + if (ppstr && strnlen(ppstr, 1)) { + fprintf(f, " (%s)\n", ppstr); + return; + } + mbedtls_oid_get_extended_key_usage(&asn1_buf, &ppstr); + if (ppstr && strnlen(ppstr, 1)) { + fprintf(f, " (%s)\n", ppstr); + return; + } + } + fprintf(f, "\n"); +} + +bool asn1_tag_dump(const struct tlv *tlv, FILE *f, int level, bool *candump) { + if (!tlv) { + fprintf(f, "NULL\n"); + return false; + } + + const struct asn1_tag *tag = asn1_get_tag(tlv); + + PRINT_INDENT(level); + fprintf(f, "--%2hx[%02zx] '%s':", tlv->tag, tlv->len, tag->name); + + switch (tag->type) { + case ASN1_TAG_GENERIC: + fprintf(f, "\n"); + break; + case ASN1_TAG_STRING: + asn1_tag_dump_string(tlv, tag, f, level); + *candump = false; + break; + case ASN1_TAG_OCTET_STRING: + asn1_tag_dump_octet_string(tlv, tag, f, level, candump); + break; + case ASN1_TAG_BOOLEAN: + asn1_tag_dump_boolean(tlv, tag, f, level); + *candump = false; + break; + case ASN1_TAG_INTEGER: + asn1_tag_dump_integer(tlv, tag, f, level); + *candump = false; + break; + case ASN1_TAG_UTC_TIME: + asn1_tag_dump_str_time(tlv, tag, f, level, false, candump); + break; + case ASN1_TAG_STR_TIME: + asn1_tag_dump_str_time(tlv, tag, f, level, true, candump); + break; + case ASN1_TAG_OBJECT_ID: + asn1_tag_dump_object_id(tlv, tag, f, level); + *candump = false; + break; + }; + + return true; +} diff --git a/client/crypto/asn1dump.h b/client/crypto/asn1dump.h new file mode 100644 index 00000000..1aadf487 --- /dev/null +++ b/client/crypto/asn1dump.h @@ -0,0 +1,21 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2018 Merlok +// +// 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. +//----------------------------------------------------------------------------- +// asn.1 dumping +//----------------------------------------------------------------------------- +#ifndef ASN1DUMP_H +#define ASN1DUMP_H + +#include +#include +#include +#include +#include "emv/tlv.h" + +extern bool asn1_tag_dump(const struct tlv *tlv, FILE *f, int level, bool *candump); + +#endif /* asn1utils.h */ diff --git a/client/crypto/asn1utils.c b/client/crypto/asn1utils.c index 2a3fe698..f48c2e12 100644 --- a/client/crypto/asn1utils.c +++ b/client/crypto/asn1utils.c @@ -9,7 +9,14 @@ //----------------------------------------------------------------------------- #include "asn1utils.h" +#include +#include #include +#include "emv/tlv.h" +#include "emv/dump.h" +#include "asn1dump.h" +#include "util.h" +#include "ui.h" // PrintAndLog int ecdsa_asn1_get_signature(uint8_t *signature, size_t signaturelen, uint8_t *rval, uint8_t *sval) { if (!signature || !signaturelen || !rval || !sval) @@ -55,7 +62,27 @@ exit: return res; } -int asn1_print(uint8_t *asn1buf, int level) { +static bool print_cb(void *data, const struct tlv *tlv, int level, bool is_leaf) { + bool candump = true; + asn1_tag_dump(tlv, stdout, level, &candump); + if (is_leaf && candump) { + dump_buffer(tlv->value, tlv->len, stdout, level); + } + + return true; +} + +int asn1_print(uint8_t *asn1buf, size_t asn1buflen, char *indent) { + + struct tlvdb *t = NULL; + t = tlvdb_parse_multi(asn1buf, asn1buflen); + if (t) { + tlvdb_visit(t, print_cb, NULL, 0); + tlvdb_free(t); + } else { + PrintAndLogEx(ERR, "Can't parse data as TLV tree."); + return 1; + } return 0; } diff --git a/client/crypto/asn1utils.h b/client/crypto/asn1utils.h index 2b00f450..19f8ded7 100644 --- a/client/crypto/asn1utils.h +++ b/client/crypto/asn1utils.h @@ -15,7 +15,7 @@ #include #include -extern int asn1_print(uint8_t *asn1buf, int level); +extern int asn1_print(uint8_t *asn1buf, size_t asn1buflen, char *indent); extern int ecdsa_asn1_get_signature(uint8_t *signature, size_t signaturelen, uint8_t *rval, uint8_t *sval); #endif /* asn1utils.h */ diff --git a/client/crypto/libpcrypto.c b/client/crypto/libpcrypto.c index 030be15a..896048bf 100644 --- a/client/crypto/libpcrypto.c +++ b/client/crypto/libpcrypto.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -208,6 +209,31 @@ char *ecdsa_get_error(int ret) { return retstr; } +int ecdsa_public_key_from_pk(mbedtls_pk_context *pk, uint8_t *key, size_t keylen) { + int res = 0; + size_t realkeylen = 0; + if (keylen < 65) + return 1; + + mbedtls_ecdsa_context ctx; + mbedtls_ecdsa_init(&ctx); + + res = mbedtls_ecp_group_load(&ctx.grp, MBEDTLS_ECP_DP_SECP256R1); // secp256r1 + if (res) + goto exit; + + res = mbedtls_ecdsa_from_keypair(&ctx, mbedtls_pk_ec(*pk) ); + if (res) + goto exit; + + res = mbedtls_ecp_point_write_binary(&ctx.grp, &ctx.Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &realkeylen, key, keylen); + if (realkeylen != 65) + res = 2; +exit: + mbedtls_ecdsa_free(&ctx); + return res; +} + int ecdsa_signature_create(uint8_t *key_d, uint8_t *key_xy, uint8_t *input, int length, uint8_t *signature, size_t *signaturelen) { int res; *signaturelen = 0; diff --git a/client/crypto/libpcrypto.h b/client/crypto/libpcrypto.h index 8d4b4a0d..7ac6c3b0 100644 --- a/client/crypto/libpcrypto.h +++ b/client/crypto/libpcrypto.h @@ -14,6 +14,7 @@ #include #include #include +#include extern int aes_encode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length); extern int aes_decode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length); @@ -23,6 +24,7 @@ extern int aes_cmac8(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, in extern int sha256hash(uint8_t *input, int length, uint8_t *hash); extern int ecdsa_key_create(uint8_t * key_d, uint8_t *key_xy); +extern int ecdsa_public_key_from_pk(mbedtls_pk_context *pk, uint8_t *key, size_t keylen); extern int ecdsa_signature_create(uint8_t *key_d, uint8_t *key_xy, uint8_t *input, int length, uint8_t *signature, size_t *signaturelen); extern int ecdsa_signature_verify(uint8_t *key_xy, uint8_t *input, int length, uint8_t *signature, size_t signaturelen); extern char *ecdsa_get_error(int ret); diff --git a/client/crypto/oids.json b/client/crypto/oids.json new file mode 100644 index 00000000..75d963d3 --- /dev/null +++ b/client/crypto/oids.json @@ -0,0 +1,2325 @@ +{ +"copyright": "https://www.cs.auckland.ac.nz/~pgut001/dumpasn1.cfg", + +"1.3.6.1.4.1.41482": { "d": "Yubico", "c": "FIDO Alliance" }, +"1.3.6.1.4.1.45724": { "d": "FIDO Alliance, Inc.", "c": "FIDO Alliance" }, +"1.3.6.1.4.1.41482.2": { "d": "Device ID", "c": "Yubico" }, +"1.3.6.1.4.1.45724.2.1.1": { "d": "FIDO U2F Transports", "c": "FIDO Alliance" }, +"1.3.6.1.4.1.45724.1.1.4": { "d": "Authenticator Attestation GUID", "c": "FIDO Alliance" }, + +"0.2.262.1.10": { "d": "Telesec", "c": "Deutsche Telekom" }, +"0.2.262.1.10.0": { "d": "extension", "c": "Telesec" }, +"0.2.262.1.10.1": { "d": "mechanism", "c": "Telesec" }, +"0.2.262.1.10.1.0": { "d": "authentication", "c": "Telesec mechanism" }, +"0.2.262.1.10.1.0.1": { "d": "passwordAuthentication", "c": "Telesec authentication" }, +"0.2.262.1.10.1.0.2": { "d": "protectedPasswordAuthentication", "c": "Telesec authentication" }, +"0.2.262.1.10.1.0.3": { "d": "oneWayX509Authentication", "c": "Telesec authentication" }, +"0.2.262.1.10.1.0.4": { "d": "twoWayX509Authentication", "c": "Telesec authentication" }, +"0.2.262.1.10.1.0.5": { "d": "threeWayX509Authentication", "c": "Telesec authentication" }, +"0.2.262.1.10.1.0.6": { "d": "oneWayISO9798Authentication", "c": "Telesec authentication" }, +"0.2.262.1.10.1.0.7": { "d": "twoWayISO9798Authentication", "c": "Telesec authentication" }, +"0.2.262.1.10.1.0.8": { "d": "telekomAuthentication", "c": "Telesec authentication" }, +"0.2.262.1.10.1.1": { "d": "signature", "c": "Telesec mechanism" }, +"0.2.262.1.10.1.1.1": { "d": "md4WithRSAAndISO9697", "c": "Telesec mechanism" }, +"0.2.262.1.10.1.1.2": { "d": "md4WithRSAAndTelesecSignatureStandard", "c": "Telesec mechanism" }, +"0.2.262.1.10.1.1.3": { "d": "md5WithRSAAndISO9697", "c": "Telesec mechanism" }, +"0.2.262.1.10.1.1.4": { "d": "md5WithRSAAndTelesecSignatureStandard", "c": "Telesec mechanism" }, +"0.2.262.1.10.1.1.5": { "d": "ripemd160WithRSAAndTelekomSignatureStandard", "c": "Telesec mechanism" }, +"0.2.262.1.10.1.1.9": { "d": "hbciRsaSignature", "c": "Telesec signature" }, +"0.2.262.1.10.1.2": { "d": "encryption", "c": "Telesec mechanism" }, +"0.2.262.1.10.1.2.0": { "d": "none", "c": "Telesec encryption" }, +"0.2.262.1.10.1.2.1": { "d": "rsaTelesec", "c": "Telesec encryption" }, +"0.2.262.1.10.1.2.2": { "d": "des", "c": "Telesec encryption" }, +"0.2.262.1.10.1.2.2.1": { "d": "desECB", "c": "Telesec encryption" }, +"0.2.262.1.10.1.2.2.2": { "d": "desCBC", "c": "Telesec encryption" }, +"0.2.262.1.10.1.2.2.3": { "d": "desOFB", "c": "Telesec encryption" }, +"0.2.262.1.10.1.2.2.4": { "d": "desCFB8", "c": "Telesec encryption" }, +"0.2.262.1.10.1.2.2.5": { "d": "desCFB64", "c": "Telesec encryption" }, +"0.2.262.1.10.1.2.3": { "d": "des3", "c": "Telesec encryption" }, +"0.2.262.1.10.1.2.3.1": { "d": "des3ECB", "c": "Telesec encryption" }, +"0.2.262.1.10.1.2.3.2": { "d": "des3CBC", "c": "Telesec encryption" }, +"0.2.262.1.10.1.2.3.3": { "d": "des3OFB", "c": "Telesec encryption" }, +"0.2.262.1.10.1.2.3.4": { "d": "des3CFB8", "c": "Telesec encryption" }, +"0.2.262.1.10.1.2.3.5": { "d": "des3CFB64", "c": "Telesec encryption" }, +"0.2.262.1.10.1.2.4": { "d": "magenta", "c": "Telesec encryption" }, +"0.2.262.1.10.1.2.5": { "d": "idea", "c": "Telesec encryption" }, +"0.2.262.1.10.1.2.5.1": { "d": "ideaECB", "c": "Telesec encryption" }, +"0.2.262.1.10.1.2.5.2": { "d": "ideaCBC", "c": "Telesec encryption" }, +"0.2.262.1.10.1.2.5.3": { "d": "ideaOFB", "c": "Telesec encryption" }, +"0.2.262.1.10.1.2.5.4": { "d": "ideaCFB8", "c": "Telesec encryption" }, +"0.2.262.1.10.1.2.5.5": { "d": "ideaCFB64", "c": "Telesec encryption" }, +"0.2.262.1.10.1.3": { "d": "oneWayFunction", "c": "Telesec mechanism" }, +"0.2.262.1.10.1.3.1": { "d": "md4", "c": "Telesec one-way function" }, +"0.2.262.1.10.1.3.2": { "d": "md5", "c": "Telesec one-way function" }, +"0.2.262.1.10.1.3.3": { "d": "sqModNX509", "c": "Telesec one-way function" }, +"0.2.262.1.10.1.3.4": { "d": "sqModNISO", "c": "Telesec one-way function" }, +"0.2.262.1.10.1.3.5": { "d": "ripemd128", "c": "Telesec one-way function" }, +"0.2.262.1.10.1.3.6": { "d": "hashUsingBlockCipher", "c": "Telesec one-way function" }, +"0.2.262.1.10.1.3.7": { "d": "mac", "c": "Telesec one-way function" }, +"0.2.262.1.10.1.3.8": { "d": "ripemd160", "c": "Telesec one-way function" }, +"0.2.262.1.10.1.4": { "d": "fecFunction", "c": "Telesec mechanism" }, +"0.2.262.1.10.1.4.1": { "d": "reedSolomon", "c": "Telesec mechanism" }, +"0.2.262.1.10.2": { "d": "module", "c": "Telesec" }, +"0.2.262.1.10.2.0": { "d": "algorithms", "c": "Telesec module" }, +"0.2.262.1.10.2.1": { "d": "attributeTypes", "c": "Telesec module" }, +"0.2.262.1.10.2.2": { "d": "certificateTypes", "c": "Telesec module" }, +"0.2.262.1.10.2.3": { "d": "messageTypes", "c": "Telesec module" }, +"0.2.262.1.10.2.4": { "d": "plProtocol", "c": "Telesec module" }, +"0.2.262.1.10.2.5": { "d": "smeAndComponentsOfSme", "c": "Telesec module" }, +"0.2.262.1.10.2.6": { "d": "fec", "c": "Telesec module" }, +"0.2.262.1.10.2.7": { "d": "usefulDefinitions", "c": "Telesec module" }, +"0.2.262.1.10.2.8": { "d": "stefiles", "c": "Telesec module" }, +"0.2.262.1.10.2.9": { "d": "sadmib", "c": "Telesec module" }, +"0.2.262.1.10.2.10": { "d": "electronicOrder", "c": "Telesec module" }, +"0.2.262.1.10.2.11": { "d": "telesecTtpAsymmetricApplication", "c": "Telesec module" }, +"0.2.262.1.10.2.12": { "d": "telesecTtpBasisApplication", "c": "Telesec module" }, +"0.2.262.1.10.2.13": { "d": "telesecTtpMessages", "c": "Telesec module" }, +"0.2.262.1.10.2.14": { "d": "telesecTtpTimeStampApplication", "c": "Telesec module" }, +"0.2.262.1.10.3": { "d": "objectClass", "c": "Telesec" }, +"0.2.262.1.10.3.0": { "d": "telesecOtherName", "c": "Telesec object class" }, +"0.2.262.1.10.3.1": { "d": "directory", "c": "Telesec object class" }, +"0.2.262.1.10.3.2": { "d": "directoryType", "c": "Telesec object class" }, +"0.2.262.1.10.3.3": { "d": "directoryGroup", "c": "Telesec object class" }, +"0.2.262.1.10.3.4": { "d": "directoryUser", "c": "Telesec object class" }, +"0.2.262.1.10.3.5": { "d": "symmetricKeyEntry", "c": "Telesec object class" }, +"0.2.262.1.10.4": { "d": "package", "c": "Telesec" }, +"0.2.262.1.10.5": { "d": "parameter", "c": "Telesec" }, +"0.2.262.1.10.6": { "d": "nameBinding", "c": "Telesec" }, +"0.2.262.1.10.7": { "d": "attribute", "c": "Telesec" }, +"0.2.262.1.10.7.0": { "d": "applicationGroupIdentifier", "c": "Telesec attribute" }, +"0.2.262.1.10.7.1": { "d": "certificateType", "c": "Telesec attribute" }, +"0.2.262.1.10.7.2": { "d": "telesecCertificate", "c": "Telesec attribute" }, +"0.2.262.1.10.7.3": { "d": "certificateNumber", "c": "Telesec attribute" }, +"0.2.262.1.10.7.4": { "d": "certificateRevocationList", "c": "Telesec attribute" }, +"0.2.262.1.10.7.5": { "d": "creationDate", "c": "Telesec attribute" }, +"0.2.262.1.10.7.6": { "d": "issuer", "c": "Telesec attribute" }, +"0.2.262.1.10.7.7": { "d": "namingAuthority", "c": "Telesec attribute" }, +"0.2.262.1.10.7.8": { "d": "publicKeyDirectory", "c": "Telesec attribute" }, +"0.2.262.1.10.7.9": { "d": "securityDomain", "c": "Telesec attribute" }, +"0.2.262.1.10.7.10": { "d": "subject", "c": "Telesec attribute" }, +"0.2.262.1.10.7.11": { "d": "timeOfRevocation", "c": "Telesec attribute" }, +"0.2.262.1.10.7.12": { "d": "userGroupReference", "c": "Telesec attribute" }, +"0.2.262.1.10.7.13": { "d": "validity", "c": "Telesec attribute" }, +"0.2.262.1.10.7.14": { "d": "zert93", "c": "Telesec attribute" }, +"0.2.262.1.10.7.15": { "d": "securityMessEnv", "c": "Telesec attribute" }, +"0.2.262.1.10.7.16": { "d": "anonymizedPublicKeyDirectory", "c": "Telesec attribute" }, +"0.2.262.1.10.7.17": { "d": "telesecGivenName", "c": "Telesec attribute" }, +"0.2.262.1.10.7.18": { "d": "nameAdditions", "c": "Telesec attribute" }, +"0.2.262.1.10.7.19": { "d": "telesecPostalCode", "c": "Telesec attribute" }, +"0.2.262.1.10.7.20": { "d": "nameDistinguisher", "c": "Telesec attribute" }, +"0.2.262.1.10.7.21": { "d": "telesecCertificateList", "c": "Telesec attribute" }, +"0.2.262.1.10.7.22": { "d": "teletrustCertificateList", "c": "Telesec attribute" }, +"0.2.262.1.10.7.23": { "d": "x509CertificateList", "c": "Telesec attribute" }, +"0.2.262.1.10.7.24": { "d": "timeOfIssue", "c": "Telesec attribute" }, +"0.2.262.1.10.7.25": { "d": "physicalCardNumber", "c": "Telesec attribute" }, +"0.2.262.1.10.7.26": { "d": "fileType", "c": "Telesec attribute" }, +"0.2.262.1.10.7.27": { "d": "ctlFileIsArchive", "c": "Telesec attribute" }, +"0.2.262.1.10.7.28": { "d": "emailAddress", "c": "Telesec attribute" }, +"0.2.262.1.10.7.29": { "d": "certificateTemplateList", "c": "Telesec attribute" }, +"0.2.262.1.10.7.30": { "d": "directoryName", "c": "Telesec attribute" }, +"0.2.262.1.10.7.31": { "d": "directoryTypeName", "c": "Telesec attribute" }, +"0.2.262.1.10.7.32": { "d": "directoryGroupName", "c": "Telesec attribute" }, +"0.2.262.1.10.7.33": { "d": "directoryUserName", "c": "Telesec attribute" }, +"0.2.262.1.10.7.34": { "d": "revocationFlag", "c": "Telesec attribute" }, +"0.2.262.1.10.7.35": { "d": "symmetricKeyEntryName", "c": "Telesec attribute" }, +"0.2.262.1.10.7.36": { "d": "glNumber", "c": "Telesec attribute" }, +"0.2.262.1.10.7.37": { "d": "goNumber", "c": "Telesec attribute" }, +"0.2.262.1.10.7.38": { "d": "gKeyData", "c": "Telesec attribute" }, +"0.2.262.1.10.7.39": { "d": "zKeyData", "c": "Telesec attribute" }, +"0.2.262.1.10.7.40": { "d": "ktKeyData", "c": "Telesec attribute" }, +"0.2.262.1.10.7.41": { "d": "ktKeyNumber", "c": "Telesec attribute" }, +"0.2.262.1.10.7.51": { "d": "timeOfRevocationGen", "c": "Telesec attribute" }, +"0.2.262.1.10.7.52": { "d": "liabilityText", "c": "Telesec attribute" }, +"0.2.262.1.10.8": { "d": "attributeGroup", "c": "Telesec" }, +"0.2.262.1.10.9": { "d": "action", "c": "Telesec" }, +"0.2.262.1.10.10": { "d": "notification", "c": "Telesec" }, +"0.2.262.1.10.11": { "d": "snmp-mibs", "c": "Telesec" }, +"0.2.262.1.10.11.1": { "d": "securityApplication", "c": "Telesec SNMP MIBs" }, +"0.2.262.1.10.12": { "d": "certAndCrlExtensionDefinitions", "c": "Telesec" }, +"0.2.262.1.10.12.0": { "d": "liabilityLimitationFlag", "c": "Telesec cert/CRL extension" }, +"0.2.262.1.10.12.1": { "d": "telesecCertIdExt", "c": "Telesec cert/CRL extension" }, +"0.2.262.1.10.12.2": { "d": "Telesec policyIdentifier", "c": "Telesec cert/CRL extension" }, +"0.2.262.1.10.12.3": { "d": "telesecPolicyQualifierID", "c": "Telesec cert/CRL extension" }, +"0.2.262.1.10.12.4": { "d": "telesecCRLFilteredExt", "c": "Telesec cert/CRL extension" }, +"0.2.262.1.10.12.5": { "d": "telesecCRLFilterExt", "c": "Telesec cert/CRL extension" }, +"0.2.262.1.10.12.6": { "d": "telesecNamingAuthorityExt", "c": "Telesec cert/CRL extension" }, +"0.4.0.127.0.7": { "d": "bsi", "c": "BSI TR-03110/TR-03111" }, +"0.4.0.127.0.7.1": { "d": "bsiEcc", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1": { "d": "bsifieldType", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.1": { "d": "bsiPrimeField", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.2": { "d": "bsiCharacteristicTwoField", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.2.2": { "d": "bsiECTLVKeyFormat", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.2.2.1": { "d": "bsiECTLVPublicKey", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.2.3": { "d": "bsiCharacteristicTwoBasis", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.2.3.1": { "d": "bsiGnBasis", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.2.3.2": { "d": "bsiTpBasis", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.2.3.3": { "d": "bsiPpBasis", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.4.1": { "d": "bsiEcdsaSignatures", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.4.1.1": { "d": "bsiEcdsaWithSHA1", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.4.1.2": { "d": "bsiEcdsaWithSHA224", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.4.1.3": { "d": "bsiEcdsaWithSHA256", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.4.1.4": { "d": "bsiEcdsaWithSHA384", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.4.1.5": { "d": "bsiEcdsaWithSHA512", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.4.1.6": { "d": "bsiEcdsaWithRIPEMD160", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.5.1.1": { "d": "bsiEckaEgX963KDF", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.5.1.1.1": { "d": "bsiEckaEgX963KDFWithSHA1", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.5.1.1.2": { "d": "bsiEckaEgX963KDFWithSHA224", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.5.1.1.3": { "d": "bsiEckaEgX963KDFWithSHA256", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.5.1.1.4": { "d": "bsiEckaEgX963KDFWithSHA384", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.5.1.1.5": { "d": "bsiEckaEgX963KDFWithSHA512", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.5.1.1.6": { "d": "bsiEckaEgX963KDFWithRIPEMD160", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.5.1.2": { "d": "bsiEckaEgSessionKDF", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.5.1.2.1": { "d": "bsiEckaEgSessionKDFWith3DES", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.5.1.2.2": { "d": "bsiEckaEgSessionKDFWithAES128", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.5.1.2.3": { "d": "bsiEckaEgSessionKDFWithAES192", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.5.1.2.4": { "d": "bsiEckaEgSessionKDFWithAES256", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.5.2": { "d": "bsiEckaDH", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.5.2.1": { "d": "bsiEckaDHX963KDF", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.5.2.1.1": { "d": "bsiEckaDHX963KDFWithSHA1", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.5.2.1.2": { "d": "bsiEckaDHX963KDFWithSHA224", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.5.2.1.3": { "d": "bsiEckaDHX963KDFWithSHA256", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.5.2.1.4": { "d": "bsiEckaDHX963KDFWithSHA384", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.5.2.1.5": { "d": "bsiEckaDHX963KDFWithSHA512", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.5.2.1.6": { "d": "bsiEckaDHX963KDFWithRIPEMD160", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.5.2.2": { "d": "bsiEckaDHSessionKDF", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.5.2.2.1": { "d": "bsiEckaDHSessionKDFWith3DES", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.5.2.2.2": { "d": "bsiEckaDHSessionKDFWithAES128", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.5.2.2.3": { "d": "bsiEckaDHSessionKDFWithAES192", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.1.5.2.2.4": { "d": "bsiEckaDHSessionKDFWithAES256", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.2": { "d": "bsiEcKeyType", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.2.1": { "d": "bsiEcPublicKey", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.5.1": { "d": "bsiKaeg", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.5.1.1": { "d": "bsiKaegWithX963KDF", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.1.5.1.2": { "d": "bsiKaegWith3DESKDF", "c": "BSI TR-03111" }, +"0.4.0.127.0.7.2.2.1": { "d": "bsiPK", "c": "BSI TR-03110. Formerly known as bsiCA, now moved to ...2.2.3.x" }, +"0.4.0.127.0.7.2.2.1.1": { "d": "bsiPK_DH", "c": "BSI TR-03110. Formerly known as bsiCA_DH, now moved to ...2.2.3.x" }, +"0.4.0.127.0.7.2.2.1.2": { "d": "bsiPK_ECDH", "c": "BSI TR-03110. Formerly known as bsiCA_ECDH, now moved to ...2.2.3.x" }, +"0.4.0.127.0.7.2.2.2": { "d": "bsiTA", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.2.1": { "d": "bsiTA_RSA", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.2.1.1": { "d": "bsiTA_RSAv1_5_SHA1", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.2.1.2": { "d": "bsiTA_RSAv1_5_SHA256", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.2.1.3": { "d": "bsiTA_RSAPSS_SHA1", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.2.1.4": { "d": "bsiTA_RSAPSS_SHA256", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.2.1.5": { "d": "bsiTA_RSAv1_5_SHA512", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.2.1.6": { "d": "bsiTA_RSAPSS_SHA512", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.2.2": { "d": "bsiTA_ECDSA", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.2.2.1": { "d": "bsiTA_ECDSA_SHA1", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.2.2.2": { "d": "bsiTA_ECDSA_SHA224", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.2.2.3": { "d": "bsiTA_ECDSA_SHA256", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.2.2.4": { "d": "bsiTA_ECDSA_SHA384", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.2.2.5": { "d": "bsiTA_ECDSA_SHA512", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.3": { "d": "bsiCA", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.3.1": { "d": "bsiCA_DH", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.3.1.1": { "d": "bsiCA_DH_3DES_CBC_CBC", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.3.1.2": { "d": "bsiCA_DH_AES_CBC_CMAC_128", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.3.1.3": { "d": "bsiCA_DH_AES_CBC_CMAC_192", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.3.1.4": { "d": "bsiCA_DH_AES_CBC_CMAC_256", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.3.2": { "d": "bsiCA_ECDH", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.3.2.1": { "d": "bsiCA_ECDH_3DES_CBC_CBC", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.3.2.2": { "d": "bsiCA_ECDH_AES_CBC_CMAC_128", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.3.2.3": { "d": "bsiCA_ECDH_AES_CBC_CMAC_192", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.3.2.4": { "d": "bsiCA_ECDH_AES_CBC_CMAC_256", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.4": { "d": "bsiPACE", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.4.1": { "d": "bsiPACE_DH_GM", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.4.1.1": { "d": "bsiPACE_DH_GM_3DES_CBC_CBC", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.4.1.2": { "d": "bsiPACE_DH_GM_AES_CBC_CMAC_128", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.4.1.3": { "d": "bsiPACE_DH_GM_AES_CBC_CMAC_192", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.4.1.4": { "d": "bsiPACE_DH_GM_AES_CBC_CMAC_256", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.4.2": { "d": "bsiPACE_ECDH_GM", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.4.2.1": { "d": "bsiPACE_ECDH_GM_3DES_CBC_CBC", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.4.2.2": { "d": "bsiPACE_ECDH_GM_AES_CBC_CMAC_128", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.4.2.3": { "d": "bsiPACE_ECDH_GM_AES_CBC_CMAC_192", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.4.2.4": { "d": "bsiPACE_ECDH_GM_AES_CBC_CMAC_256", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.4.3": { "d": "bsiPACE_DH_IM", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.4.3.1": { "d": "bsiPACE_DH_IM_3DES_CBC_CBC", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.4.3.2": { "d": "bsiPACE_DH_IM_AES_CBC_CMAC_128", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.4.3.3": { "d": "bsiPACE_DH_IM_AES_CBC_CMAC_192", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.4.3.4": { "d": "bsiPACE_DH_IM_AES_CBC_CMAC_256", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.4.4": { "d": "bsiPACE_ECDH_IM", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.4.4.1": { "d": "bsiPACE_ECDH_IM_3DES_CBC_CBC", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.4.4.2": { "d": "bsiPACE_ECDH_IM_AES_CBC_CMAC_128", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.4.4.3": { "d": "bsiPACE_ECDH_IM_AES_CBC_CMAC_192", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.4.4.4": { "d": "bsiPACE_ECDH_IM_AES_CBC_CMAC_256", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.5": { "d": "bsiRI", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.5.1": { "d": "bsiRI_DH", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.5.1.1": { "d": "bsiRI_DH_SHA1", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.5.1.2": { "d": "bsiRI_DH_SHA224", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.5.1.3": { "d": "bsiRI_DH_SHA256", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.5.1.4": { "d": "bsiRI_DH_SHA384", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.5.1.5": { "d": "bsiRI_DH_SHA512", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.5.2": { "d": "bsiRI_ECDH", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.5.2.1": { "d": "bsiRI_ECDH_SHA1", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.5.2.2": { "d": "bsiRI_ECDH_SHA224", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.5.2.3": { "d": "bsiRI_ECDH_SHA256", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.5.2.4": { "d": "bsiRI_ECDH_SHA384", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.5.2.5": { "d": "bsiRI_ECDH_SHA512", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.6": { "d": "bsiCardInfo", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.7": { "d": "bsiEidSecurity", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.2.2.8": { "d": "bsiPT", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.1.2": { "d": "bsiEACRoles", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.1.2.1": { "d": "bsiEACRolesIS", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.1.2.2": { "d": "bsiEACRolesAT", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.1.2.3": { "d": "bsiEACRolesST", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.1.3": { "d": "bsiTAv2ce", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.1.3.1": { "d": "bsiTAv2ceDescription", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.1.3.1.1": { "d": "bsiTAv2ceDescriptionPlainText", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.1.3.1.2": { "d": "bsiTAv2ceDescriptionIA5String", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.1.3.1.3": { "d": "bsiTAv2ceDescriptionOctetString", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.1.3.2": { "d": "bsiTAv2ceTerminalSector", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.1.4": { "d": "bsiAuxData", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.1.4.1": { "d": "bsiAuxDataBirthday", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.1.4.2": { "d": "bsiAuxDataExpireDate", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.1.4.3": { "d": "bsiAuxDataCommunityID", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.1.5": { "d": "bsiDefectList", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.1.5.1": { "d": "bsiDefectAuthDefect", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.1.5.1.1": { "d": "bsiDefectCertRevoked", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.1.5.1.2": { "d": "bsiDefectCertReplaced", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.1.5.1.3": { "d": "bsiDefectChipAuthKeyRevoked", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.1.5.1.4": { "d": "bsiDefectActiveAuthKeyRevoked", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.1.5.2": { "d": "bsiDefectEPassportDefect", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.1.5.2.1": { "d": "bsiDefectEPassportDGMalformed", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.1.5.2.2": { "d": "bsiDefectSODInvalid", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.1.5.3": { "d": "bsiDefectEIDDefect", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.1.5.3.1": { "d": "bsiDefectEIDDGMalformed", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.1.5.3.2": { "d": "bsiDefectEIDIntegrity", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.1.5.4": { "d": "bsiDefectDocumentDefect", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.1.5.4.1": { "d": "bsiDefectCardSecurityMalformed", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.1.5.4.2": { "d": "bsiDefectChipSecurityMalformed", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.1.5.4.3": { "d": "bsiDefectPowerDownReq", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.1.6": { "d": "bsiListContentDescription", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.2.1": { "d": "bsiSecurityObject", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.2.2": { "d": "bsiBlackList", "c": "BSI TR-03110" }, +"0.4.0.127.0.7.3.4.2.2": { "d": "bsiSignedUpdateDeviceAdmin", "c": "BSI TR-03109" }, +"0.4.0.127.0.7.4.1.1.1": { "d": "bsiCertReqMsgs", "c": "BSI TR-03109" }, +"0.4.0.127.0.7.4.1.1.2": { "d": "bsiCertReqMsgswithOuterSignature", "c": "BSI TR-03109" }, +"0.4.0.127.0.7.4.1.1.3": { "d": "bsiAuthorizedCertReqMsgs", "c": "BSI TR-03109" }, +"0.4.0.127.0.7.4.1.2.2": { "d": "bsiSignedRevReqs", "c": "BSI TR-03109" }, +"0.4.0.1862": { "d": "etsiQcsProfile", "c": "ETSI TS 101 862 qualified certificates" }, +"0.4.0.1862.1": { "d": "etsiQcs", "c": "ETSI TS 101 862 qualified certificates" }, +"0.4.0.1862.1.1": { "d": "etsiQcsCompliance", "c": "ETSI TS 101 862 qualified certificates" }, +"0.4.0.1862.1.2": { "d": "etsiQcsLimitValue", "c": "ETSI TS 101 862 qualified certificates" }, +"0.4.0.1862.1.3": { "d": "etsiQcsRetentionPeriod", "c": "ETSI TS 101 862 qualified certificates" }, +"0.4.0.1862.1.4": { "d": "etsiQcsQcSSCD", "c": "ETSI TS 101 862 qualified certificates" }, +"0.9.2342.19200300.100.1.1": { "d": "userID", "c": "Some oddball X.500 attribute collection" }, +"0.9.2342.19200300.100.1.3": { "d": "rfc822Mailbox", "c": "Some oddball X.500 attribute collection" }, +"0.9.2342.19200300.100.1.25": { "d": "domainComponent", "c": "Men are from Mars, this OID is from Pluto" }, +"1.0.10118.3.0.49": { "d": "ripemd160", "c": "ISO 10118-3 hash function" }, +"1.0.10118.3.0.50": { "d": "ripemd128", "c": "ISO 10118-3 hash function" }, +"1.0.10118.3.0.55": { "d": "whirlpool", "c": "ISO 10118-3 hash function" }, +"1.2.36.1.3.1.1.1": { "d": "qgpki", "c": "Queensland Government PKI" }, +"1.2.36.1.3.1.1.1.1": { "d": "qgpkiPolicies", "c": "QGPKI policies" }, +"1.2.36.1.3.1.1.1.1.1": { "d": "qgpkiMedIntermedCA", "c": "QGPKI policy" }, +"1.2.36.1.3.1.1.1.1.1.1": { "d": "qgpkiMedIntermedIndividual", "c": "QGPKI policy" }, +"1.2.36.1.3.1.1.1.1.1.2": { "d": "qgpkiMedIntermedDeviceControl", "c": "QGPKI policy" }, +"1.2.36.1.3.1.1.1.1.1.3": { "d": "qgpkiMedIntermedDevice", "c": "QGPKI policy" }, +"1.2.36.1.3.1.1.1.1.1.4": { "d": "qgpkiMedIntermedAuthorisedParty", "c": "QGPKI policy" }, +"1.2.36.1.3.1.1.1.1.1.5": { "d": "qgpkiMedIntermedDeviceSystem", "c": "QGPKI policy" }, +"1.2.36.1.3.1.1.1.1.2": { "d": "qgpkiMedIssuingCA", "c": "QGPKI policy" }, +"1.2.36.1.3.1.1.1.1.2.1": { "d": "qgpkiMedIssuingIndividual", "c": "QGPKI policy" }, +"1.2.36.1.3.1.1.1.1.2.2": { "d": "qgpkiMedIssuingDeviceControl", "c": "QGPKI policy" }, +"1.2.36.1.3.1.1.1.1.2.3": { "d": "qgpkiMedIssuingDevice", "c": "QGPKI policy" }, +"1.2.36.1.3.1.1.1.1.2.4": { "d": "qgpkiMedIssuingAuthorisedParty", "c": "QGPKI policy" }, +"1.2.36.1.3.1.1.1.1.2.5": { "d": "qgpkiMedIssuingClientAuth", "c": "QGPKI policy" }, +"1.2.36.1.3.1.1.1.1.2.6": { "d": "qgpkiMedIssuingServerAuth", "c": "QGPKI policy" }, +"1.2.36.1.3.1.1.1.1.2.7": { "d": "qgpkiMedIssuingDataProt", "c": "QGPKI policy" }, +"1.2.36.1.3.1.1.1.1.2.8": { "d": "qgpkiMedIssuingTokenAuth", "c": "QGPKI policy" }, +"1.2.36.1.3.1.1.1.1.3": { "d": "qgpkiBasicIntermedCA", "c": "QGPKI policy" }, +"1.2.36.1.3.1.1.1.1.3.1": { "d": "qgpkiBasicIntermedDeviceSystem", "c": "QGPKI policy" }, +"1.2.36.1.3.1.1.1.1.4": { "d": "qgpkiBasicIssuingCA", "c": "QGPKI policy" }, +"1.2.36.1.3.1.1.1.1.4.1": { "d": "qgpkiBasicIssuingClientAuth", "c": "QGPKI policy" }, +"1.2.36.1.3.1.1.1.1.4.2": { "d": "qgpkiBasicIssuingServerAuth", "c": "QGPKI policy" }, +"1.2.36.1.3.1.1.1.1.4.3": { "d": "qgpkiBasicIssuingDataSigning", "c": "QGPKI policy" }, +"1.2.36.1.3.1.1.1.2": { "d": "qgpkiAssuranceLevel", "c": "QGPKI assurance level" }, +"1.2.36.1.3.1.1.1.2.1": { "d": "qgpkiAssuranceRudimentary", "c": "QGPKI assurance level" }, +"1.2.36.1.3.1.1.1.2.2": { "d": "qgpkiAssuranceBasic", "c": "QGPKI assurance level" }, +"1.2.36.1.3.1.1.1.2.3": { "d": "qgpkiAssuranceMedium", "c": "QGPKI assurance level" }, +"1.2.36.1.3.1.1.1.2.4": { "d": "qgpkiAssuranceHigh", "c": "QGPKI assurance level" }, +"1.2.36.1.3.1.1.1.3": { "d": "qgpkiCertFunction", "c": "QGPKI policies" }, +"1.2.36.1.3.1.1.1.3.1": { "d": "qgpkiFunctionIndividual", "c": "QGPKI policies" }, +"1.2.36.1.3.1.1.1.3.2": { "d": "qgpkiFunctionDevice", "c": "QGPKI policies" }, +"1.2.36.1.3.1.1.1.3.3": { "d": "qgpkiFunctionAuthorisedParty", "c": "QGPKI policies" }, +"1.2.36.1.3.1.1.1.3.4": { "d": "qgpkiFunctionDeviceControl", "c": "QGPKI policies" }, +"1.2.36.1.3.1.2": { "d": "qpspki", "c": "Queensland Police PKI" }, +"1.2.36.1.3.1.2.1": { "d": "qpspkiPolicies", "c": "Queensland Police PKI" }, +"1.2.36.1.3.1.2.1.2": { "d": "qpspkiPolicyBasic", "c": "Queensland Police PKI" }, +"1.2.36.1.3.1.2.1.3": { "d": "qpspkiPolicyMedium", "c": "Queensland Police PKI" }, +"1.2.36.1.3.1.2.1.4": { "d": "qpspkiPolicyHigh", "c": "Queensland Police PKI" }, +"1.2.36.1.3.1.3.2": { "d": "qtmrpki", "c": "Queensland Transport PKI" }, +"1.2.36.1.3.1.3.2.1": { "d": "qtmrpkiPolicies", "c": "Queensland Transport PKI" }, +"1.2.36.1.3.1.3.2.2": { "d": "qtmrpkiPurpose", "c": "Queensland Transport PKI" }, +"1.2.36.1.3.1.3.2.2.1": { "d": "qtmrpkiIndividual", "c": "Queensland Transport PKI purpose" }, +"1.2.36.1.3.1.3.2.2.2": { "d": "qtmrpkiDeviceControl", "c": "Queensland Transport PKI purpose" }, +"1.2.36.1.3.1.3.2.2.3": { "d": "qtmrpkiDevice", "c": "Queensland Transport PKI purpose" }, +"1.2.36.1.3.1.3.2.2.4": { "d": "qtmrpkiAuthorisedParty", "c": "Queensland Transport PKI purpose" }, +"1.2.36.1.3.1.3.2.2.5": { "d": "qtmrpkiDeviceSystem", "c": "Queensland Transport PKI purpose" }, +"1.2.36.1.3.1.3.2.3": { "d": "qtmrpkiDevice", "c": "Queensland Transport PKI" }, +"1.2.36.1.3.1.3.2.3.1": { "d": "qtmrpkiDriverLicense", "c": "Queensland Transport PKI device" }, +"1.2.36.1.3.1.3.2.3.2": { "d": "qtmrpkiIndustryAuthority", "c": "Queensland Transport PKI device" }, +"1.2.36.1.3.1.3.2.3.3": { "d": "qtmrpkiMarineLicense", "c": "Queensland Transport PKI device" }, +"1.2.36.1.3.1.3.2.3.4": { "d": "qtmrpkiAdultProofOfAge", "c": "Queensland Transport PKI device" }, +"1.2.36.1.3.1.3.2.3.5": { "d": "qtmrpkiSam", "c": "Queensland Transport PKI device" }, +"1.2.36.1.3.1.3.2.4": { "d": "qtmrpkiAuthorisedParty", "c": "Queensland Transport PKI" }, +"1.2.36.1.3.1.3.2.4.1": { "d": "qtmrpkiTransportInspector", "c": "Queensland Transport PKI authorised party" }, +"1.2.36.1.3.1.3.2.4.2": { "d": "qtmrpkiPoliceOfficer", "c": "Queensland Transport PKI authorised party" }, +"1.2.36.1.3.1.3.2.4.3": { "d": "qtmrpkiSystem", "c": "Queensland Transport PKI authorised party" }, +"1.2.36.1.3.1.3.2.4.4": { "d": "qtmrpkiLiquorLicensingInspector", "c": "Queensland Transport PKI authorised party" }, +"1.2.36.1.3.1.3.2.4.5": { "d": "qtmrpkiMarineEnforcementOfficer", "c": "Queensland Transport PKI authorised party" }, +"1.2.36.1.333.1": { "d": "australianBusinessNumber", "c": "Australian Government corporate taxpayer ID" }, +"1.2.36.68980861.1.1.2": { "d": "signetPersonal", "c": "Signet CA" }, +"1.2.36.68980861.1.1.3": { "d": "signetBusiness", "c": "Signet CA" }, +"1.2.36.68980861.1.1.4": { "d": "signetLegal", "c": "Signet CA" }, +"1.2.36.68980861.1.1.10": { "d": "signetPilot", "c": "Signet CA" }, +"1.2.36.68980861.1.1.11": { "d": "signetIntraNet", "c": "Signet CA" }, +"1.2.36.68980861.1.1.20": { "d": "signetPolicy", "c": "Signet CA" }, +"1.2.36.75878867.1.100.1.1": { "d": "certificatesAustraliaPolicy", "c": "Certificates Australia CA" }, +"1.2.156.10197.1": { "d": "gmtCryptographicAlgorithm", "c": "China GM Standards Committee" }, +"1.2.156.10197.1.100": { "d": "gmtBlockCipher", "c": "China GM Standards Committee" }, +"1.2.156.10197.1.102": { "d": "sm1Cipher", "c": "China GM Standards Committee" }, +"1.2.156.10197.1.103": { "d": "ssf33Cipher", "c": "China GM Standards Committee" }, +"1.2.156.10197.1.104": { "d": "sm4Cipher", "c": "China GM Standards Committee" }, +"1.2.156.10197.1.200": { "d": "gmtStreamCipher", "c": "China GM Standards Committee" }, +"1.2.156.10197.1.201": { "d": "zucCipher", "c": "China GM Standards Committee" }, +"1.2.156.10197.1.300": { "d": "gmtPublicKeyCryptography", "c": "China GM Standards Committee" }, +"1.2.156.10197.1.301": { "d": "sm2ECC", "c": "China GM Standards Committee" }, +"1.2.156.10197.1.301.1": { "d": "sm2-1DigitalSignature", "c": "China GM Standards Committee" }, +"1.2.156.10197.1.301.2": { "d": "sm2-2KeyExchange", "c": "China GM Standards Committee" }, +"1.2.156.10197.1.301.3": { "d": "sm2-3PublicKeyEncryption", "c": "China GM Standards Committee" }, +"1.2.156.10197.1.302": { "d": "gmtSM9IBE", "c": "China GM Standards Committee" }, +"1.2.156.10197.1.302.1": { "d": "sm9-1DigitalSignature", "c": "China GM Standards Committee" }, +"1.2.156.10197.1.302.2": { "d": "sm9-2KeyExchange", "c": "China GM Standards Committee" }, +"1.2.156.10197.1.302.3": { "d": "sm9-3PublicKeyEncryption", "c": "China GM Standards Committee" }, +"1.2.156.10197.1.400": { "d": "gmtHashAlgorithm", "c": "China GM Standards Committee" }, +"1.2.156.10197.1.401": { "d": "sm3Hash", "c": "China GM Standards Committee" }, +"1.2.156.10197.1.401.1": { "d": "sm3HashWithoutKey", "c": "China GM Standards Committee" }, +"1.2.156.10197.1.401.2": { "d": "sm3HashWithKey", "c": "China GM Standards Committee" }, +"1.2.156.10197.1.500": { "d": "gmtDigestSigning", "c": "China GM Standards Committee" }, +"1.2.156.10197.1.501": { "d": "sm2withSM3", "c": "China GM Standards Committee" }, +"1.2.156.10197.1.504": { "d": "rsaWithSM3", "c": "China GM Standards Committee" }, +"1.2.156.10197.4.3": { "d": "gmtCertificateAuthority", "c": "China GM Standards Committee" }, +"1.2.156.10197.6": { "d": "gmtStandardClass", "c": "China GM Standards Committee" }, +"1.2.156.10197.6.1": { "d": "gmtFoundationClass", "c": "China GM Standards Committee" }, +"1.2.156.10197.6.1.1": { "d": "gmtAlgorithmClass", "c": "China GM Standards Committee" }, +"1.2.156.10197.6.1.1.1": { "d": "zucStandard", "c": "China GM Standards Committee" }, +"1.2.156.10197.6.1.1.2": { "d": "sm4Standard", "c": "China GM Standards Committee" }, +"1.2.156.10197.6.1.1.3": { "d": "sm2Standard", "c": "China GM Standards Committee" }, +"1.2.156.10197.6.1.1.4": { "d": "sm3Standard", "c": "China GM Standards Committee" }, +"1.2.156.10197.6.1.2": { "d": "gmtIDClass", "c": "China GM Standards Committee" }, +"1.2.156.10197.6.1.2.1": { "d": "gmtCryptoID", "c": "China GM Standards Committee" }, +"1.2.156.10197.6.1.3": { "d": "gmtOperationModes", "c": "China GM Standards Committee" }, +"1.2.156.10197.6.1.4": { "d": "gmtSecurityMechanism", "c": "China GM Standards Committee" }, +"1.2.156.10197.6.1.4.1": { "d": "gmtSM2Specification", "c": "China GM Standards Committee" }, +"1.2.156.10197.6.1.4.2": { "d": "gmtSM2CryptographicMessageSyntax", "c": "China GM Standards Committee" }, +"1.2.156.10197.6.2": { "d": "gmtDeviceClass", "c": "China GM Standards Committee" }, +"1.2.156.10197.6.3": { "d": "gmtServiceClass", "c": "China GM Standards Committee" }, +"1.2.156.10197.6.4": { "d": "gmtInfrastructure", "c": "China GM Standards Committee" }, +"1.2.156.10197.6.5": { "d": "gmtTestingClass", "c": "China GM Standards Committee" }, +"1.2.156.10197.6.5.1": { "d": "gmtRandomTestingClass", "c": "China GM Standards Committee" }, +"1.2.156.10197.6.6": { "d": "gmtManagementClass", "c": "China GM Standards Committee" }, +"1.2.392.200011.61.1.1.1": { "d": "mitsubishiSecurityAlgorithm", "c": "Mitsubishi security algorithm" }, +"1.2.392.200011.61.1.1.1.1": { "d": "misty1-cbc", "c": "Mitsubishi security algorithm" }, +"1.2.410.200004.1": { "d": "kisaAlgorithm", "c": "KISA algorithm" }, +"1.2.410.200004.1.1": { "d": "kcdsa", "c": "Korean DSA" }, +"1.2.410.200004.1.2": { "d": "has160", "c": "Korean hash algorithm" }, +"1.2.410.200004.1.3": { "d": "seedECB", "c": "Korean SEED algorithm, ECB mode" }, +"1.2.410.200004.1.4": { "d": "seedCBC", "c": "Korean SEED algorithm, CBC mode" }, +"1.2.410.200004.1.5": { "d": "seedOFB", "c": "Korean SEED algorithm, OFB mode" }, +"1.2.410.200004.1.6": { "d": "seedCFB", "c": "Korean SEED algorithm, CFB mode" }, +"1.2.410.200004.1.7": { "d": "seedMAC", "c": "Korean SEED algorithm, MAC mode" }, +"1.2.410.200004.1.8": { "d": "kcdsaWithHAS160", "c": "Korean signature algorithm" }, +"1.2.410.200004.1.9": { "d": "kcdsaWithSHA1", "c": "Korean signature algorithm" }, +"1.2.410.200004.1.10": { "d": "pbeWithHAS160AndSEED-ECB", "c": "Korean SEED algorithm, PBE key derivation" }, +"1.2.410.200004.1.11": { "d": "pbeWithHAS160AndSEED-CBC", "c": "Korean SEED algorithm, PBE key derivation" }, +"1.2.410.200004.1.12": { "d": "pbeWithHAS160AndSEED-CFB", "c": "Korean SEED algorithm, PBE key derivation" }, +"1.2.410.200004.1.13": { "d": "pbeWithHAS160AndSEED-OFB", "c": "Korean SEED algorithm, PBE key derivation" }, +"1.2.410.200004.1.14": { "d": "pbeWithSHA1AndSEED-ECB", "c": "Korean SEED algorithm, PBE key derivation" }, +"1.2.410.200004.1.15": { "d": "pbeWithSHA1AndSEED-CBC", "c": "Korean SEED algorithm, PBE key derivation" }, +"1.2.410.200004.1.16": { "d": "pbeWithSHA1AndSEED-CFB", "c": "Korean SEED algorithm, PBE key derivation" }, +"1.2.410.200004.1.17": { "d": "pbeWithSHA1AndSEED-OFB", "c": "Korean SEED algorithm, PBE key derivation" }, +"1.2.410.200004.1.20": { "d": "rsaWithHAS160", "c": "Korean signature algorithm" }, +"1.2.410.200004.1.21": { "d": "kcdsa1", "c": "Korean DSA" }, +"1.2.410.200004.2": { "d": "npkiCP", "c": "KISA NPKI certificate policies" }, +"1.2.410.200004.2.1": { "d": "npkiSignaturePolicy", "c": "KISA NPKI certificate policies" }, +"1.2.410.200004.3": { "d": "npkiKP", "c": "KISA NPKI key usage" }, +"1.2.410.200004.4": { "d": "npkiAT", "c": "KISA NPKI attribute" }, +"1.2.410.200004.5": { "d": "npkiLCA", "c": "KISA NPKI licensed CA" }, +"1.2.410.200004.5.1": { "d": "npkiSignKorea", "c": "KISA NPKI licensed CA" }, +"1.2.410.200004.5.2": { "d": "npkiSignGate", "c": "KISA NPKI licensed CA" }, +"1.2.410.200004.5.3": { "d": "npkiNcaSign", "c": "KISA NPKI licensed CA" }, +"1.2.410.200004.6": { "d": "npkiON", "c": "KISA NPKI otherName" }, +"1.2.410.200004.7": { "d": "npkiAPP", "c": "KISA NPKI application" }, +"1.2.410.200004.7.1": { "d": "npkiSMIME", "c": "KISA NPKI application" }, +"1.2.410.200004.7.1.1": { "d": "npkiSMIMEAlgo", "c": "KISA NPKI application" }, +"1.2.410.200004.7.1.1.1": { "d": "npkiCmsSEEDWrap", "c": "KISA NPKI application" }, +"1.2.410.200004.10": { "d": "npki", "c": "KISA NPKI" }, +"1.2.410.200004.10.1": { "d": "npkiAttribute", "c": "KISA NPKI attribute" }, +"1.2.410.200004.10.1.1": { "d": "npkiIdentifyData", "c": "KISA NPKI attribute" }, +"1.2.410.200004.10.1.1.1": { "d": "npkiVID", "c": "KISA NPKI attribute" }, +"1.2.410.200004.10.1.1.2": { "d": "npkiEncryptedVID", "c": "KISA NPKI attribute" }, +"1.2.410.200004.10.1.1.3": { "d": "npkiRandomNum", "c": "KISA NPKI attribute" }, +"1.2.410.200004.10.1.1.4": { "d": "npkiVID", "c": "KISA NPKI attribute" }, +"1.2.410.200046.1.1": { "d": "aria1AlgorithmModes", "c": "ARIA algorithm modes" }, +"1.2.410.200046.1.1.1": { "d": "aria128-ecb", "c": "ARIA algorithm modes" }, +"1.2.410.200046.1.1.2": { "d": "aria128-cbc", "c": "ARIA algorithm modes" }, +"1.2.410.200046.1.1.3": { "d": "aria128-cfb", "c": "ARIA algorithm modes" }, +"1.2.410.200046.1.1.4": { "d": "aria128-ofb", "c": "ARIA algorithm modes" }, +"1.2.410.200046.1.1.5": { "d": "aria128-ctr", "c": "ARIA algorithm modes" }, +"1.2.410.200046.1.1.6": { "d": "aria192-ecb", "c": "ARIA algorithm modes" }, +"1.2.410.200046.1.1.7": { "d": "aria192-cbc", "c": "ARIA algorithm modes" }, +"1.2.410.200046.1.1.8": { "d": "aria192-cfb", "c": "ARIA algorithm modes" }, +"1.2.410.200046.1.1.9": { "d": "aria192-ofb", "c": "ARIA algorithm modes" }, +"1.2.410.200046.1.1.10": { "d": "aria192-ctr", "c": "ARIA algorithm modes" }, +"1.2.410.200046.1.1.11": { "d": "aria256-ecb", "c": "ARIA algorithm modes" }, +"1.2.410.200046.1.1.12": { "d": "aria256-cbc", "c": "ARIA algorithm modes" }, +"1.2.410.200046.1.1.13": { "d": "aria256-cfb", "c": "ARIA algorithm modes" }, +"1.2.410.200046.1.1.14": { "d": "aria256-ofb", "c": "ARIA algorithm modes" }, +"1.2.410.200046.1.1.15": { "d": "aria256-ctr", "c": "ARIA algorithm modes" }, +"1.2.410.200046.1.1.21": { "d": "aria128-cmac", "c": "ARIA algorithm modes" }, +"1.2.410.200046.1.1.22": { "d": "aria192-cmac", "c": "ARIA algorithm modes" }, +"1.2.410.200046.1.1.23": { "d": "aria256-cmac", "c": "ARIA algorithm modes" }, +"1.2.410.200046.1.1.31": { "d": "aria128-ocb2", "c": "ARIA algorithm modes" }, +"1.2.410.200046.1.1.32": { "d": "aria192-ocb2", "c": "ARIA algorithm modes" }, +"1.2.410.200046.1.1.33": { "d": "aria256-ocb2", "c": "ARIA algorithm modes" }, +"1.2.410.200046.1.1.34": { "d": "aria128-gcm", "c": "ARIA algorithm modes" }, +"1.2.410.200046.1.1.35": { "d": "aria192-gcm", "c": "ARIA algorithm modes" }, +"1.2.410.200046.1.1.36": { "d": "aria256-gcm", "c": "ARIA algorithm modes" }, +"1.2.410.200046.1.1.37": { "d": "aria128-ccm", "c": "ARIA algorithm modes" }, +"1.2.410.200046.1.1.38": { "d": "aria192-ccm", "c": "ARIA algorithm modes" }, +"1.2.410.200046.1.1.39": { "d": "aria256-ccm", "c": "ARIA algorithm modes" }, +"1.2.410.200046.1.1.40": { "d": "aria128-keywrap", "c": "ARIA algorithm modes" }, +"1.2.410.200046.1.1.41": { "d": "aria192-keywrap", "c": "ARIA algorithm modes" }, +"1.2.410.200046.1.1.42": { "d": "aria256-keywrap", "c": "ARIA algorithm modes" }, +"1.2.410.200046.1.1.43": { "d": "aria128-keywrapWithPad", "c": "ARIA algorithm modes" }, +"1.2.410.200046.1.1.44": { "d": "aria192-keywrapWithPad", "c": "ARIA algorithm modes" }, +"1.2.410.200046.1.1.45": { "d": "aria256-keywrapWithPad", "c": "ARIA algorithm modes" }, +"1.2.643.2.2.3": { "d": "gostSignature", "c": "GOST R 34.10-2001 + GOST R 34.11-94 signature" }, +"1.2.643.2.2.4": { "d": "gost94Signature", "c": "GOST R 34.10-94 + GOST R 34.11-94 signature. Obsoleted by GOST R 34.10-2001", "w": true }, +"1.2.643.2.2.19": { "d": "gostPublicKey", "c": "GOST R 34.10-2001 (ECC) public key" }, +"1.2.643.2.2.20": { "d": "gost94PublicKey", "c": "GOST R 34.10-94 public key. Obsoleted by GOST R 34.10-2001", "w": true }, +"1.2.643.2.2.21": { "d": "gostCipher", "c": "GOST 28147-89 (symmetric key block cipher)" }, +"1.2.643.2.2.31.0": { "d": "testCipherParams", "c": "Test params for GOST 28147-89" }, +"1.2.643.2.2.31.1": { "d": "cryptoProCipherA", "c": "CryptoPro params A (default, variant 'Verba-O') for GOST 28147-89" }, +"1.2.643.2.2.31.2": { "d": "cryptoProCipherB", "c": "CryptoPro params B (variant 1) for GOST 28147-89" }, +"1.2.643.2.2.31.3": { "d": "cryptoProCipherC", "c": "CryptoPro params C (variant 2) for GOST 28147-89" }, +"1.2.643.2.2.31.4": { "d": "cryptoProCipherD", "c": "CryptoPro params D (variant 3) for GOST 28147-89" }, +"1.2.643.2.2.31.5": { "d": "oscar11Cipher", "c": "Oscar-1.1 params for GOST 28147-89" }, +"1.2.643.2.2.31.6": { "d": "oscar10Cipher", "c": "Oscar-1.0 params for GOST 28147-89" }, +"1.2.643.2.2.31.7": { "d": "ric1Cipher", "c": "RIC-1 params for GOST 28147-89" }, +"1.2.643.2.2.31.12": { "d": "tc26CipherA", "c": "TC26 params 2 for GOST 28147-89" }, +"1.2.643.2.2.31.13": { "d": "tc26CipherB", "c": "TC26 params 1 for GOST 28147-89" }, +"1.2.643.2.2.31.14": { "d": "tc26CipherC", "c": "TC26 params 3 for GOST 28147-89" }, +"1.2.643.2.2.31.15": { "d": "tc26CipherD", "c": "TC26 params 4 for GOST 28147-89" }, +"1.2.643.2.2.31.16": { "d": "tc26CipherE", "c": "TC26 params 5 for GOST 28147-89" }, +"1.2.643.2.2.31.17": { "d": "tc26CipherF", "c": "TC26 params 6 for GOST 28147-89" }, +"1.2.643.7.1.2.5.1.1": { "d": "tc26CipherZ", "c": "TC26 params Z for GOST 28147-89" }, +"1.2.643.2.2.9": { "d": "gostDigest", "c": "GOST R 34.11-94 digest" }, +"1.2.643.2.2.30.0": { "d": "testDigestParams", "c": "Test params for GOST R 34.11-94" }, +"1.2.643.2.2.30.1": { "d": "cryptoProDigestA", "c": "CryptoPro digest params A (default, variant 'Verba-O') for GOST R 34.11-94" }, +"1.2.643.2.2.30.2": { "d": "cryptoProDigestB", "c": "CryptoPro digest params B (variant 1) for GOST R 34.11-94" }, +"1.2.643.2.2.30.3": { "d": "cryptoProDigestC", "c": "CryptoPro digest params C (variant 2) for GOST R 34.11-94" }, +"1.2.643.2.2.30.4": { "d": "cryptoProDigestD", "c": "CryptoPro digest params D (variant 3) for GOST R 34.11-94" }, +"1.2.643.2.2.32.2": { "d": "cryptoPro94SignA", "c": "CryptoPro sign params A (default, variant 'Verba-O') for GOST R 34.10-94" }, +"1.2.643.2.2.32.3": { "d": "cryptoPro94SignB", "c": "CryptoPro sign params B (variant 1) for GOST R 34.10-94" }, +"1.2.643.2.2.32.4": { "d": "cryptoPro94SignC", "c": "CryptoPro sign params C (variant 2) for GOST R 34.10-94" }, +"1.2.643.2.2.32.5": { "d": "cryptoPro94SignD", "c": "CryptoPro sign params D (variant 3) for GOST R 34.10-94" }, +"1.2.643.2.2.33.1": { "d": "cryptoPro94SignXA", "c": "CryptoPro sign params XA (variant 1) for GOST R 34.10-94" }, +"1.2.643.2.2.33.2": { "d": "cryptoPro94SignXB", "c": "CryptoPro sign params XB (variant 2) for GOST R 34.10-94" }, +"1.2.643.2.2.33.3": { "d": "cryptoPro94SignXC", "c": "CryptoPro sign params XC (variant 3) for GOST R 34.10-94" }, +"1.2.643.2.2.35.0": { "d": "testSignParams", "c": "Test elliptic curve for GOST R 34.10-2001" }, +"1.2.643.2.2.35.1": { "d": "cryptoProSignA", "c": "CryptoPro ell.curve A for GOST R 34.10-2001" }, +"1.2.643.2.2.35.2": { "d": "cryptoProSignB", "c": "CryptoPro ell.curve B for GOST R 34.10-2001" }, +"1.2.643.2.2.35.3": { "d": "cryptoProSignC", "c": "CryptoPro ell.curve C for GOST R 34.10-2001" }, +"1.2.643.2.2.36.0": { "d": "cryptoProSignXA", "c": "CryptoPro ell.curve XA for GOST R 34.10-2001" }, +"1.2.643.2.2.36.1": { "d": "cryptoProSignXB", "c": "CryptoPro ell.curve XB for GOST R 34.10-2001" }, +"1.2.643.7.1.2.1.1.1": { "d": "cryptoPro2012Sign256A", "c": "CryptoPro ell.curve A for GOST R 34.10-2012 256 bit" }, +"1.2.643.7.1.2.1.2.1": { "d": "cryptoPro2012Sign512A", "c": "CryptoPro ell.curve A (default) for GOST R 34.10-2012 512 bit" }, +"1.2.643.7.1.2.1.2.2": { "d": "cryptoPro2012Sign512B", "c": "CryptoPro ell.curve B for GOST R 34.10-2012 512 bit" }, +"1.2.643.7.1.2.1.2.3": { "d": "cryptoPro2012Sign512C", "c": "CryptoPro ell.curve C for GOST R 34.10-2012 512 bit" }, +"1.2.643.2.2.14.0": { "d": "nullMeshing", "c": "Do not mesh state of GOST 28147-89 cipher" }, +"1.2.643.2.2.14.1": { "d": "cryptoProMeshing", "c": "CryptoPro meshing of state of GOST 28147-89 cipher" }, +"1.2.643.2.2.10": { "d": "hmacGost", "c": "HMAC with GOST R 34.11-94" }, +"1.2.643.2.2.13.0": { "d": "gostWrap", "c": "Wrap key using GOST 28147-89 key" }, +"1.2.643.2.2.13.1": { "d": "cryptoProWrap", "c": "Wrap key using diversified GOST 28147-89 key" }, +"1.2.643.2.2.96": { "d": "cryptoProECDHWrap", "c": "Wrap key using ECC DH on GOST R 34.10-2001 keys (VKO)" }, +"1.2.643.7.1.1.1.1": { "d": "gost2012PublicKey256", "c": "GOST R 34.10-2012 256 bit public key" }, +"1.2.643.7.1.1.1.2": { "d": "gost2012PublicKey512", "c": "GOST R 34.10-2012 512 bit public key" }, +"1.2.643.7.1.1.2.2": { "d": "gost2012Digest256", "c": "GOST R 34.11-2012 256 bit digest" }, +"1.2.643.7.1.1.2.3": { "d": "gost2012Digest512", "c": "GOST R 34.11-2012 512 bit digest" }, +"1.2.643.7.1.1.3.2": { "d": "gost2012Signature256", "c": "GOST R 34.10-2012 256 bit signature" }, +"1.2.643.7.1.1.3.3": { "d": "gost2012Signature512", "c": "GOST R 34.10-2012 512 bit signature" }, +"1.2.643.7.1.1.6.1": { "d": "cryptoProECDH256", "c": "CryptoPro ECC DH algorithm for GOST R 34.10-2012 256 bit key" }, +"1.2.643.7.1.1.6.2": { "d": "cryptoProECDH512", "c": "CryptoPro ECC DH algorithm for GOST R 34.10-2012 512 bit key" }, +"1.2.752.34.1": { "d": "seis-cp", "c": "SEIS Project" }, +"1.2.752.34.1.1": { "d": "SEIS high-assurance policyIdentifier", "c": "SEIS Project certificate policies" }, +"1.2.752.34.1.2": { "d": "SEIS GAK policyIdentifier", "c": "SEIS Project certificate policies" }, +"1.2.752.34.2": { "d": "SEIS pe", "c": "SEIS Project" }, +"1.2.752.34.3": { "d": "SEIS at", "c": "SEIS Project" }, +"1.2.752.34.3.1": { "d": "SEIS at-personalIdentifier", "c": "SEIS Project attribute" }, +"1.2.840.10040.1": { "d": "module", "c": "ANSI X9.57" }, +"1.2.840.10040.1.1": { "d": "x9f1-cert-mgmt", "c": "ANSI X9.57 module" }, +"1.2.840.10040.2": { "d": "holdinstruction", "c": "ANSI X9.57" }, +"1.2.840.10040.2.1": { "d": "holdinstruction-none", "c": "ANSI X9.57 hold instruction" }, +"1.2.840.10040.2.2": { "d": "callissuer", "c": "ANSI X9.57 hold instruction" }, +"1.2.840.10040.2.3": { "d": "reject", "c": "ANSI X9.57 hold instruction" }, +"1.2.840.10040.2.4": { "d": "pickupToken", "c": "ANSI X9.57 hold instruction" }, +"1.2.840.10040.3": { "d": "attribute", "c": "ANSI X9.57" }, +"1.2.840.10040.3.1": { "d": "countersignature", "c": "ANSI X9.57 attribute" }, +"1.2.840.10040.3.2": { "d": "attribute-cert", "c": "ANSI X9.57 attribute" }, +"1.2.840.10040.4": { "d": "algorithm", "c": "ANSI X9.57" }, +"1.2.840.10040.4.1": { "d": "dsa", "c": "ANSI X9.57 algorithm" }, +"1.2.840.10040.4.2": { "d": "dsa-match", "c": "ANSI X9.57 algorithm" }, +"1.2.840.10040.4.3": { "d": "dsaWithSha1", "c": "ANSI X9.57 algorithm" }, +"1.2.840.10045.1": { "d": "fieldType", "c": "ANSI X9.62. This OID is also assigned as ecdsa-with-SHA1" }, +"1.2.840.10045.1.1": { "d": "prime-field", "c": "ANSI X9.62 field type" }, +"1.2.840.10045.1.2": { "d": "characteristic-two-field", "c": "ANSI X9.62 field type" }, +"1.2.840.10045.1.2.3": { "d": "characteristic-two-basis", "c": "ANSI X9.62 field type" }, +"1.2.840.10045.1.2.3.1": { "d": "onBasis", "c": "ANSI X9.62 field basis" }, +"1.2.840.10045.1.2.3.2": { "d": "tpBasis", "c": "ANSI X9.62 field basis" }, +"1.2.840.10045.1.2.3.3": { "d": "ppBasis", "c": "ANSI X9.62 field basis" }, +"1.2.840.10045.2": { "d": "publicKeyType", "c": "ANSI X9.62" }, +"1.2.840.10045.2.1": { "d": "ecPublicKey", "c": "ANSI X9.62 public key type" }, +"1.2.840.10045.3.0.1": { "d": "c2pnb163v1", "c": "ANSI X9.62 named elliptic curve" }, +"1.2.840.10045.3.0.2": { "d": "c2pnb163v2", "c": "ANSI X9.62 named elliptic curve" }, +"1.2.840.10045.3.0.3": { "d": "c2pnb163v3", "c": "ANSI X9.62 named elliptic curve" }, +"1.2.840.10045.3.0.5": { "d": "c2tnb191v1", "c": "ANSI X9.62 named elliptic curve" }, +"1.2.840.10045.3.0.6": { "d": "c2tnb191v2", "c": "ANSI X9.62 named elliptic curve" }, +"1.2.840.10045.3.0.7": { "d": "c2tnb191v3", "c": "ANSI X9.62 named elliptic curve" }, +"1.2.840.10045.3.0.10": { "d": "c2pnb208w1", "c": "ANSI X9.62 named elliptic curve" }, +"1.2.840.10045.3.0.11": { "d": "c2tnb239v1", "c": "ANSI X9.62 named elliptic curve" }, +"1.2.840.10045.3.0.12": { "d": "c2tnb239v2", "c": "ANSI X9.62 named elliptic curve" }, +"1.2.840.10045.3.0.13": { "d": "c2tnb239v3", "c": "ANSI X9.62 named elliptic curve" }, +"1.2.840.10045.3.0.16": { "d": "c2pnb272w1", "c": "ANSI X9.62 named elliptic curve" }, +"1.2.840.10045.3.0.18": { "d": "c2tnb359v1", "c": "ANSI X9.62 named elliptic curve" }, +"1.2.840.10045.3.0.19": { "d": "c2pnb368w1", "c": "ANSI X9.62 named elliptic curve" }, +"1.2.840.10045.3.0.20": { "d": "c2tnb431r1", "c": "ANSI X9.62 named elliptic curve" }, +"1.2.840.10045.3.1.1": { "d": "prime192v1", "c": "ANSI X9.62 named elliptic curve" }, +"1.2.840.10045.3.1.2": { "d": "prime192v2", "c": "ANSI X9.62 named elliptic curve" }, +"1.2.840.10045.3.1.3": { "d": "prime192v3", "c": "ANSI X9.62 named elliptic curve" }, +"1.2.840.10045.3.1.4": { "d": "prime239v1", "c": "ANSI X9.62 named elliptic curve" }, +"1.2.840.10045.3.1.5": { "d": "prime239v2", "c": "ANSI X9.62 named elliptic curve" }, +"1.2.840.10045.3.1.6": { "d": "prime239v3", "c": "ANSI X9.62 named elliptic curve" }, +"1.2.840.10045.3.1.7": { "d": "prime256v1", "c": "ANSI X9.62 named elliptic curve" }, +"1.2.840.10045.4.1": { "d": "ecdsaWithSHA1", "c": "ANSI X9.62 ECDSA algorithm with SHA1" }, +"1.2.840.10045.4.2": { "d": "ecdsaWithRecommended", "c": "ANSI X9.62 ECDSA algorithm with Recommended" }, +"1.2.840.10045.4.3": { "d": "ecdsaWithSpecified", "c": "ANSI X9.62 ECDSA algorithm with Specified" }, +"1.2.840.10045.4.3.1": { "d": "ecdsaWithSHA224", "c": "ANSI X9.62 ECDSA algorithm with SHA224" }, +"1.2.840.10045.4.3.2": { "d": "ecdsaWithSHA256", "c": "ANSI X9.62 ECDSA algorithm with SHA256" }, +"1.2.840.10045.4.3.3": { "d": "ecdsaWithSHA384", "c": "ANSI X9.62 ECDSA algorithm with SHA384" }, +"1.2.840.10045.4.3.4": { "d": "ecdsaWithSHA512", "c": "ANSI X9.62 ECDSA algorithm with SHA512" }, +"1.2.840.10046.1": { "d": "fieldType", "c": "ANSI X9.42" }, +"1.2.840.10046.1.1": { "d": "gf-prime", "c": "ANSI X9.42 field type" }, +"1.2.840.10046.2": { "d": "numberType", "c": "ANSI X9.42" }, +"1.2.840.10046.2.1": { "d": "dhPublicKey", "c": "ANSI X9.42 number type" }, +"1.2.840.10046.3": { "d": "scheme", "c": "ANSI X9.42" }, +"1.2.840.10046.3.1": { "d": "dhStatic", "c": "ANSI X9.42 scheme" }, +"1.2.840.10046.3.2": { "d": "dhEphem", "c": "ANSI X9.42 scheme" }, +"1.2.840.10046.3.3": { "d": "dhHybrid1", "c": "ANSI X9.42 scheme" }, +"1.2.840.10046.3.4": { "d": "dhHybrid2", "c": "ANSI X9.42 scheme" }, +"1.2.840.10046.3.5": { "d": "mqv2", "c": "ANSI X9.42 scheme" }, +"1.2.840.10046.3.6": { "d": "mqv1", "c": "ANSI X9.42 scheme" }, +"1.2.840.10065.2.2": { "d": "?", "c": "ASTM 31.20" }, +"1.2.840.10065.2.3": { "d": "healthcareLicense", "c": "ASTM 31.20" }, +"1.2.840.10065.2.3.1.1": { "d": "license?", "c": "ASTM 31.20 healthcare license type" }, +"1.2.840.10070": { "d": "iec62351", "c": "IEC 62351" }, +"1.2.840.10070.8": { "d": "iec62351_8", "c": "IEC 62351-8" }, +"1.2.840.10070.8.1": { "d": "iecUserRoles", "c": "IEC 62351-8" }, +"1.2.840.113533.7": { "d": "nsn", "c": "" }, +"1.2.840.113533.7.65": { "d": "nsn-ce", "c": "" }, +"1.2.840.113533.7.65.0": { "d": "entrustVersInfo", "c": "Nortel Secure Networks ce" }, +"1.2.840.113533.7.66": { "d": "nsn-alg", "c": "" }, +"1.2.840.113533.7.66.3": { "d": "cast3CBC", "c": "Nortel Secure Networks alg" }, +"1.2.840.113533.7.66.10": { "d": "cast5CBC", "c": "Nortel Secure Networks alg" }, +"1.2.840.113533.7.66.11": { "d": "cast5MAC", "c": "Nortel Secure Networks alg" }, +"1.2.840.113533.7.66.12": { "d": "pbeWithMD5AndCAST5-CBC", "c": "Nortel Secure Networks alg" }, +"1.2.840.113533.7.66.13": { "d": "passwordBasedMac", "c": "Nortel Secure Networks alg" }, +"1.2.840.113533.7.67": { "d": "nsn-oc", "c": "" }, +"1.2.840.113533.7.67.0": { "d": "entrustUser", "c": "Nortel Secure Networks oc" }, +"1.2.840.113533.7.68": { "d": "nsn-at", "c": "" }, +"1.2.840.113533.7.68.0": { "d": "entrustCAInfo", "c": "Nortel Secure Networks at" }, +"1.2.840.113533.7.68.10": { "d": "attributeCertificate", "c": "Nortel Secure Networks at" }, +"1.2.840.113549.1.1": { "d": "pkcs-1", "c": "" }, +"1.2.840.113549.1.1.1": { "d": "rsaEncryption", "c": "PKCS #1" }, +"1.2.840.113549.1.1.2": { "d": "md2WithRSAEncryption", "c": "PKCS #1" }, +"1.2.840.113549.1.1.3": { "d": "md4WithRSAEncryption", "c": "PKCS #1" }, +"1.2.840.113549.1.1.4": { "d": "md5WithRSAEncryption", "c": "PKCS #1" }, +"1.2.840.113549.1.1.5": { "d": "sha1WithRSAEncryption", "c": "PKCS #1" }, +"1.2.840.113549.1.1.7": { "d": "rsaOAEP", "c": "PKCS #1" }, +"1.2.840.113549.1.1.8": { "d": "pkcs1-MGF", "c": "PKCS #1" }, +"1.2.840.113549.1.1.9": { "d": "rsaOAEP-pSpecified", "c": "PKCS #1" }, +"1.2.840.113549.1.1.10": { "d": "rsaPSS", "c": "PKCS #1" }, +"1.2.840.113549.1.1.11": { "d": "sha256WithRSAEncryption", "c": "PKCS #1" }, +"1.2.840.113549.1.1.12": { "d": "sha384WithRSAEncryption", "c": "PKCS #1" }, +"1.2.840.113549.1.1.13": { "d": "sha512WithRSAEncryption", "c": "PKCS #1" }, +"1.2.840.113549.1.1.14": { "d": "sha224WithRSAEncryption", "c": "PKCS #1" }, +"1.2.840.113549.1.1.6": { "d": "rsaOAEPEncryptionSET", "c": "PKCS #1. This OID may also be assigned as ripemd160WithRSAEncryption" }, +"1.2.840.113549.1.2": { "d": "bsafeRsaEncr", "c": "Obsolete BSAFE OID", "w": true }, +"1.2.840.113549.1.3": { "d": "pkcs-3", "c": "" }, +"1.2.840.113549.1.3.1": { "d": "dhKeyAgreement", "c": "PKCS #3" }, +"1.2.840.113549.1.5": { "d": "pkcs-5", "c": "" }, +"1.2.840.113549.1.5.1": { "d": "pbeWithMD2AndDES-CBC", "c": "PKCS #5" }, +"1.2.840.113549.1.5.3": { "d": "pbeWithMD5AndDES-CBC", "c": "PKCS #5" }, +"1.2.840.113549.1.5.4": { "d": "pbeWithMD2AndRC2-CBC", "c": "PKCS #5" }, +"1.2.840.113549.1.5.6": { "d": "pbeWithMD5AndRC2-CBC", "c": "PKCS #5" }, +"1.2.840.113549.1.5.9": { "d": "pbeWithMD5AndXOR", "c": "PKCS #5, used in BSAFE only", "w": true }, +"1.2.840.113549.1.5.10": { "d": "pbeWithSHAAndDES-CBC", "c": "PKCS #5" }, +"1.2.840.113549.1.5.12": { "d": "pkcs5PBKDF2", "c": "PKCS #5 v2.0" }, +"1.2.840.113549.1.5.13": { "d": "pkcs5PBES2", "c": "PKCS #5 v2.0" }, +"1.2.840.113549.1.5.14": { "d": "pkcs5PBMAC1", "c": "PKCS #5 v2.0" }, +"1.2.840.113549.1.7": { "d": "pkcs-7", "c": "" }, +"1.2.840.113549.1.7.1": { "d": "data", "c": "PKCS #7" }, +"1.2.840.113549.1.7.2": { "d": "signedData", "c": "PKCS #7" }, +"1.2.840.113549.1.7.3": { "d": "envelopedData", "c": "PKCS #7" }, +"1.2.840.113549.1.7.4": { "d": "signedAndEnvelopedData", "c": "PKCS #7" }, +"1.2.840.113549.1.7.5": { "d": "digestedData", "c": "PKCS #7" }, +"1.2.840.113549.1.7.6": { "d": "encryptedData", "c": "PKCS #7" }, +"1.2.840.113549.1.7.7": { "d": "dataWithAttributes", "c": "PKCS #7 experimental", "w": true }, +"1.2.840.113549.1.7.8": { "d": "encryptedPrivateKeyInfo", "c": "PKCS #7 experimental", "w": true }, +"1.2.840.113549.1.9": { "d": "pkcs-9", "c": "" }, +"1.2.840.113549.1.9.1": { "d": "emailAddress", "c": "PKCS #9. Deprecated, use an altName extension instead" }, +"1.2.840.113549.1.9.2": { "d": "unstructuredName", "c": "PKCS #9" }, +"1.2.840.113549.1.9.3": { "d": "contentType", "c": "PKCS #9" }, +"1.2.840.113549.1.9.4": { "d": "messageDigest", "c": "PKCS #9" }, +"1.2.840.113549.1.9.5": { "d": "signingTime", "c": "PKCS #9" }, +"1.2.840.113549.1.9.6": { "d": "countersignature", "c": "PKCS #9" }, +"1.2.840.113549.1.9.7": { "d": "challengePassword", "c": "PKCS #9" }, +"1.2.840.113549.1.9.8": { "d": "unstructuredAddress", "c": "PKCS #9" }, +"1.2.840.113549.1.9.9": { "d": "extendedCertificateAttributes", "c": "PKCS #9" }, +"1.2.840.113549.1.9.10": { "d": "issuerAndSerialNumber", "c": "PKCS #9 experimental", "w": true }, +"1.2.840.113549.1.9.11": { "d": "passwordCheck", "c": "PKCS #9 experimental", "w": true }, +"1.2.840.113549.1.9.12": { "d": "publicKey", "c": "PKCS #9 experimental", "w": true }, +"1.2.840.113549.1.9.13": { "d": "signingDescription", "c": "PKCS #9" }, +"1.2.840.113549.1.9.14": { "d": "extensionRequest", "c": "PKCS #9 via CRMF" }, +"1.2.840.113549.1.9.15": { "d": "sMIMECapabilities", "c": "PKCS #9. This OID was formerly assigned as symmetricCapabilities, then reassigned as SMIMECapabilities, then renamed to the current name" }, +"1.2.840.113549.1.9.15.1": { "d": "preferSignedData", "c": "sMIMECapabilities" }, +"1.2.840.113549.1.9.15.2": { "d": "canNotDecryptAny", "c": "sMIMECapabilities" }, +"1.2.840.113549.1.9.15.3": { "d": "receiptRequest", "c": "sMIMECapabilities. Deprecated, use (1 2 840 113549 1 9 16 2 1) instead", "w": true }, +"1.2.840.113549.1.9.15.4": { "d": "receipt", "c": "sMIMECapabilities. Deprecated, use (1 2 840 113549 1 9 16 1 1) instead", "w": true }, +"1.2.840.113549.1.9.15.5": { "d": "contentHints", "c": "sMIMECapabilities. Deprecated, use (1 2 840 113549 1 9 16 2 4) instead", "w": true }, +"1.2.840.113549.1.9.15.6": { "d": "mlExpansionHistory", "c": "sMIMECapabilities. Deprecated, use (1 2 840 113549 1 9 16 2 3) instead", "w": true }, +"1.2.840.113549.1.9.16": { "d": "id-sMIME", "c": "PKCS #9" }, +"1.2.840.113549.1.9.16.0": { "d": "id-mod", "c": "id-sMIME" }, +"1.2.840.113549.1.9.16.0.1": { "d": "id-mod-cms", "c": "S/MIME Modules" }, +"1.2.840.113549.1.9.16.0.2": { "d": "id-mod-ess", "c": "S/MIME Modules" }, +"1.2.840.113549.1.9.16.0.3": { "d": "id-mod-oid", "c": "S/MIME Modules" }, +"1.2.840.113549.1.9.16.0.4": { "d": "id-mod-msg-v3", "c": "S/MIME Modules" }, +"1.2.840.113549.1.9.16.0.5": { "d": "id-mod-ets-eSignature-88", "c": "S/MIME Modules" }, +"1.2.840.113549.1.9.16.0.6": { "d": "id-mod-ets-eSignature-97", "c": "S/MIME Modules" }, +"1.2.840.113549.1.9.16.0.7": { "d": "id-mod-ets-eSigPolicy-88", "c": "S/MIME Modules" }, +"1.2.840.113549.1.9.16.0.8": { "d": "id-mod-ets-eSigPolicy-88", "c": "S/MIME Modules" }, +"1.2.840.113549.1.9.16.1": { "d": "contentType", "c": "S/MIME" }, +"1.2.840.113549.1.9.16.1.1": { "d": "receipt", "c": "S/MIME Content Types" }, +"1.2.840.113549.1.9.16.1.2": { "d": "authData", "c": "S/MIME Content Types" }, +"1.2.840.113549.1.9.16.1.3": { "d": "publishCert", "c": "S/MIME Content Types" }, +"1.2.840.113549.1.9.16.1.4": { "d": "tSTInfo", "c": "S/MIME Content Types" }, +"1.2.840.113549.1.9.16.1.5": { "d": "tDTInfo", "c": "S/MIME Content Types" }, +"1.2.840.113549.1.9.16.1.6": { "d": "contentInfo", "c": "S/MIME Content Types" }, +"1.2.840.113549.1.9.16.1.7": { "d": "dVCSRequestData", "c": "S/MIME Content Types" }, +"1.2.840.113549.1.9.16.1.8": { "d": "dVCSResponseData", "c": "S/MIME Content Types" }, +"1.2.840.113549.1.9.16.1.9": { "d": "compressedData", "c": "S/MIME Content Types" }, +"1.2.840.113549.1.9.16.1.10": { "d": "scvpCertValRequest", "c": "S/MIME Content Types" }, +"1.2.840.113549.1.9.16.1.11": { "d": "scvpCertValResponse", "c": "S/MIME Content Types" }, +"1.2.840.113549.1.9.16.1.12": { "d": "scvpValPolRequest", "c": "S/MIME Content Types" }, +"1.2.840.113549.1.9.16.1.13": { "d": "scvpValPolResponse", "c": "S/MIME Content Types" }, +"1.2.840.113549.1.9.16.1.14": { "d": "attrCertEncAttrs", "c": "S/MIME Content Types" }, +"1.2.840.113549.1.9.16.1.15": { "d": "tSReq", "c": "S/MIME Content Types" }, +"1.2.840.113549.1.9.16.1.16": { "d": "firmwarePackage", "c": "S/MIME Content Types" }, +"1.2.840.113549.1.9.16.1.17": { "d": "firmwareLoadReceipt", "c": "S/MIME Content Types" }, +"1.2.840.113549.1.9.16.1.18": { "d": "firmwareLoadError", "c": "S/MIME Content Types" }, +"1.2.840.113549.1.9.16.1.19": { "d": "contentCollection", "c": "S/MIME Content Types" }, +"1.2.840.113549.1.9.16.1.20": { "d": "contentWithAttrs", "c": "S/MIME Content Types" }, +"1.2.840.113549.1.9.16.1.21": { "d": "encKeyWithID", "c": "S/MIME Content Types" }, +"1.2.840.113549.1.9.16.1.22": { "d": "encPEPSI", "c": "S/MIME Content Types" }, +"1.2.840.113549.1.9.16.1.23": { "d": "authEnvelopedData", "c": "S/MIME Content Types" }, +"1.2.840.113549.1.9.16.1.24": { "d": "routeOriginAttest", "c": "S/MIME Content Types" }, +"1.2.840.113549.1.9.16.1.25": { "d": "symmetricKeyPackage", "c": "S/MIME Content Types" }, +"1.2.840.113549.1.9.16.1.26": { "d": "rpkiManifest", "c": "S/MIME Content Types" }, +"1.2.840.113549.1.9.16.1.27": { "d": "asciiTextWithCRLF", "c": "S/MIME Content Types" }, +"1.2.840.113549.1.9.16.1.28": { "d": "xml", "c": "S/MIME Content Types" }, +"1.2.840.113549.1.9.16.1.29": { "d": "pdf", "c": "S/MIME Content Types" }, +"1.2.840.113549.1.9.16.1.30": { "d": "postscript", "c": "S/MIME Content Types" }, +"1.2.840.113549.1.9.16.1.31": { "d": "timestampedData", "c": "S/MIME Content Types" }, +"1.2.840.113549.1.9.16.1.32": { "d": "asAdjacencyAttest", "c": "S/MIME Content Types", "w": true }, +"1.2.840.113549.1.9.16.1.33": { "d": "rpkiTrustAnchor", "c": "S/MIME Content Types" }, +"1.2.840.113549.1.9.16.1.34": { "d": "trustAnchorList", "c": "S/MIME Content Types" }, +"1.2.840.113549.1.9.16.2": { "d": "authenticatedAttributes", "c": "S/MIME" }, +"1.2.840.113549.1.9.16.2.1": { "d": "receiptRequest", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.2": { "d": "securityLabel", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.3": { "d": "mlExpandHistory", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.4": { "d": "contentHint", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.5": { "d": "msgSigDigest", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.6": { "d": "encapContentType", "c": "S/MIME Authenticated Attributes. Obsolete", "w": true }, +"1.2.840.113549.1.9.16.2.7": { "d": "contentIdentifier", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.8": { "d": "macValue", "c": "S/MIME Authenticated Attributes. Obsolete", "w": true }, +"1.2.840.113549.1.9.16.2.9": { "d": "equivalentLabels", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.10": { "d": "contentReference", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.11": { "d": "encrypKeyPref", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.12": { "d": "signingCertificate", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.13": { "d": "smimeEncryptCerts", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.14": { "d": "timeStampToken", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.15": { "d": "sigPolicyId", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.16": { "d": "commitmentType", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.17": { "d": "signerLocation", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.18": { "d": "signerAttr", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.19": { "d": "otherSigCert", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.20": { "d": "contentTimestamp", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.21": { "d": "certificateRefs", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.22": { "d": "revocationRefs", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.23": { "d": "certValues", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.24": { "d": "revocationValues", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.25": { "d": "escTimeStamp", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.26": { "d": "certCRLTimestamp", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.27": { "d": "archiveTimeStamp", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.28": { "d": "signatureType", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.29": { "d": "dvcsDvc", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.30": { "d": "cekReference", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.31": { "d": "maxCEKDecrypts", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.32": { "d": "kekDerivationAlg", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.33": { "d": "intendedRecipients", "c": "S/MIME Authenticated Attributes. Obsolete", "w": true }, +"1.2.840.113549.1.9.16.2.34": { "d": "cmcUnsignedData", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.35": { "d": "fwPackageID", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.36": { "d": "fwTargetHardwareIDs", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.37": { "d": "fwDecryptKeyID", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.38": { "d": "fwImplCryptAlgs", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.39": { "d": "fwWrappedFirmwareKey", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.40": { "d": "fwCommunityIdentifiers", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.41": { "d": "fwPkgMessageDigest", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.42": { "d": "fwPackageInfo", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.43": { "d": "fwImplCompressAlgs", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.44": { "d": "etsAttrCertificateRefs", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.45": { "d": "etsAttrRevocationRefs", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.46": { "d": "binarySigningTime", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.47": { "d": "signingCertificateV2", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.48": { "d": "etsArchiveTimeStampV2", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.49": { "d": "erInternal", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.50": { "d": "erExternal", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.2.51": { "d": "multipleSignatures", "c": "S/MIME Authenticated Attributes" }, +"1.2.840.113549.1.9.16.3.1": { "d": "esDHwith3DES", "c": "S/MIME Algorithms. Obsolete", "w": true }, +"1.2.840.113549.1.9.16.3.2": { "d": "esDHwithRC2", "c": "S/MIME Algorithms. Obsolete", "w": true }, +"1.2.840.113549.1.9.16.3.3": { "d": "3desWrap", "c": "S/MIME Algorithms. Obsolete", "w": true }, +"1.2.840.113549.1.9.16.3.4": { "d": "rc2Wrap", "c": "S/MIME Algorithms. Obsolete", "w": true }, +"1.2.840.113549.1.9.16.3.5": { "d": "esDH", "c": "S/MIME Algorithms" }, +"1.2.840.113549.1.9.16.3.6": { "d": "cms3DESwrap", "c": "S/MIME Algorithms" }, +"1.2.840.113549.1.9.16.3.7": { "d": "cmsRC2wrap", "c": "S/MIME Algorithms" }, +"1.2.840.113549.1.9.16.3.8": { "d": "zlib", "c": "S/MIME Algorithms" }, +"1.2.840.113549.1.9.16.3.9": { "d": "pwriKEK", "c": "S/MIME Algorithms" }, +"1.2.840.113549.1.9.16.3.10": { "d": "ssDH", "c": "S/MIME Algorithms" }, +"1.2.840.113549.1.9.16.3.11": { "d": "hmacWith3DESwrap", "c": "S/MIME Algorithms" }, +"1.2.840.113549.1.9.16.3.12": { "d": "hmacWithAESwrap", "c": "S/MIME Algorithms" }, +"1.2.840.113549.1.9.16.3.13": { "d": "md5XorExperiment", "c": "S/MIME Algorithms. Experimental", "w": true }, +"1.2.840.113549.1.9.16.3.14": { "d": "rsaKEM", "c": "S/MIME Algorithms" }, +"1.2.840.113549.1.9.16.3.15": { "d": "authEnc128", "c": "S/MIME Algorithms" }, +"1.2.840.113549.1.9.16.3.16": { "d": "authEnc256", "c": "S/MIME Algorithms" }, +"1.2.840.113549.1.9.16.3.19": { "d": "ecdhHKDF-SHA256", "c": "S/MIME Algorithms" }, +"1.2.840.113549.1.9.16.3.20": { "d": "ecdhHKDF-SHA384", "c": "S/MIME Algorithms" }, +"1.2.840.113549.1.9.16.3.21": { "d": "ecdhHKDF-SHA512", "c": "S/MIME Algorithms" }, +"1.2.840.113549.1.9.16.4.1": { "d": "certDist-ldap", "c": "S/MIME Certificate Distribution" }, +"1.2.840.113549.1.9.16.5.1": { "d": "sigPolicyQualifier-spuri x", "c": "S/MIME Signature Policy Qualifiers" }, +"1.2.840.113549.1.9.16.5.2": { "d": "sigPolicyQualifier-spUserNotice", "c": "S/MIME Signature Policy Qualifiers" }, +"1.2.840.113549.1.9.16.6.1": { "d": "proofOfOrigin", "c": "S/MIME Commitment Type Identifiers" }, +"1.2.840.113549.1.9.16.6.2": { "d": "proofOfReceipt", "c": "S/MIME Commitment Type Identifiers" }, +"1.2.840.113549.1.9.16.6.3": { "d": "proofOfDelivery", "c": "S/MIME Commitment Type Identifiers" }, +"1.2.840.113549.1.9.16.6.4": { "d": "proofOfSender", "c": "S/MIME Commitment Type Identifiers" }, +"1.2.840.113549.1.9.16.6.5": { "d": "proofOfApproval", "c": "S/MIME Commitment Type Identifiers" }, +"1.2.840.113549.1.9.16.6.6": { "d": "proofOfCreation", "c": "S/MIME Commitment Type Identifiers" }, +"1.2.840.113549.1.9.16.8.1": { "d": "glUseKEK", "c": "S/MIME Symmetric Key Distribution Attributes" }, +"1.2.840.113549.1.9.16.8.2": { "d": "glDelete", "c": "S/MIME Symmetric Key Distribution Attributes" }, +"1.2.840.113549.1.9.16.8.3": { "d": "glAddMember", "c": "S/MIME Symmetric Key Distribution Attributes" }, +"1.2.840.113549.1.9.16.8.4": { "d": "glDeleteMember", "c": "S/MIME Symmetric Key Distribution Attributes" }, +"1.2.840.113549.1.9.16.8.5": { "d": "glRekey", "c": "S/MIME Symmetric Key Distribution Attributes" }, +"1.2.840.113549.1.9.16.8.6": { "d": "glAddOwner", "c": "S/MIME Symmetric Key Distribution Attributes" }, +"1.2.840.113549.1.9.16.8.7": { "d": "glRemoveOwner", "c": "S/MIME Symmetric Key Distribution Attributes" }, +"1.2.840.113549.1.9.16.8.8": { "d": "glkCompromise", "c": "S/MIME Symmetric Key Distribution Attributes" }, +"1.2.840.113549.1.9.16.8.9": { "d": "glkRefresh", "c": "S/MIME Symmetric Key Distribution Attributes" }, +"1.2.840.113549.1.9.16.8.10": { "d": "glFailInfo", "c": "S/MIME Symmetric Key Distribution Attributes. Obsolete", "w": true }, +"1.2.840.113549.1.9.16.8.11": { "d": "glaQueryRequest", "c": "S/MIME Symmetric Key Distribution Attributes" }, +"1.2.840.113549.1.9.16.8.12": { "d": "glaQueryResponse", "c": "S/MIME Symmetric Key Distribution Attributes" }, +"1.2.840.113549.1.9.16.8.13": { "d": "glProvideCert", "c": "S/MIME Symmetric Key Distribution Attributes" }, +"1.2.840.113549.1.9.16.8.14": { "d": "glUpdateCert", "c": "S/MIME Symmetric Key Distribution Attributes" }, +"1.2.840.113549.1.9.16.8.15": { "d": "glKey", "c": "S/MIME Symmetric Key Distribution Attributes" }, +"1.2.840.113549.1.9.16.9": { "d": "signatureTypeIdentifier", "c": "S/MIME" }, +"1.2.840.113549.1.9.16.9.1": { "d": "originatorSig", "c": "S/MIME Signature Type Identifier" }, +"1.2.840.113549.1.9.16.9.2": { "d": "domainSig", "c": "S/MIME Signature Type Identifier" }, +"1.2.840.113549.1.9.16.9.3": { "d": "additionalAttributesSig", "c": "S/MIME Signature Type Identifier" }, +"1.2.840.113549.1.9.16.9.4": { "d": "reviewSig", "c": "S/MIME Signature Type Identifier" }, +"1.2.840.113549.1.9.16.11": { "d": "capabilities", "c": "S/MIME" }, +"1.2.840.113549.1.9.16.11.1": { "d": "preferBinaryInside", "c": "S/MIME Capability" }, +"1.2.840.113549.1.9.20": { "d": "friendlyName (for PKCS #12)", "c": "PKCS #9 via PKCS #12" }, +"1.2.840.113549.1.9.21": { "d": "localKeyID (for PKCS #12)", "c": "PKCS #9 via PKCS #12" }, +"1.2.840.113549.1.9.22": { "d": "certTypes (for PKCS #12)", "c": "PKCS #9 via PKCS #12" }, +"1.2.840.113549.1.9.22.1": { "d": "x509Certificate (for PKCS #12)", "c": "PKCS #9 via PKCS #12" }, +"1.2.840.113549.1.9.22.2": { "d": "sdsiCertificate (for PKCS #12)", "c": "PKCS #9 via PKCS #12" }, +"1.2.840.113549.1.9.23": { "d": "crlTypes (for PKCS #12)", "c": "PKCS #9 via PKCS #12" }, +"1.2.840.113549.1.9.23.1": { "d": "x509Crl (for PKCS #12)", "c": "PKCS #9 via PKCS #12" }, +"1.2.840.113549.1.9.24": { "d": "pkcs9objectClass", "c": "PKCS #9/RFC 2985" }, +"1.2.840.113549.1.9.25": { "d": "pkcs9attributes", "c": "PKCS #9/RFC 2985" }, +"1.2.840.113549.1.9.25.1": { "d": "pkcs15Token", "c": "PKCS #9/RFC 2985 attribute" }, +"1.2.840.113549.1.9.25.2": { "d": "encryptedPrivateKeyInfo", "c": "PKCS #9/RFC 2985 attribute" }, +"1.2.840.113549.1.9.25.3": { "d": "randomNonce", "c": "PKCS #9/RFC 2985 attribute" }, +"1.2.840.113549.1.9.25.4": { "d": "sequenceNumber", "c": "PKCS #9/RFC 2985 attribute" }, +"1.2.840.113549.1.9.25.5": { "d": "pkcs7PDU", "c": "PKCS #9/RFC 2985 attribute" }, +"1.2.840.113549.1.9.26": { "d": "pkcs9syntax", "c": "PKCS #9/RFC 2985" }, +"1.2.840.113549.1.9.27": { "d": "pkcs9matchingRules", "c": "PKCS #9/RFC 2985" }, +"1.2.840.113549.1.9.52": { "d": "cmsAlgorithmProtection", "c": "RFC 6211" }, +"1.2.840.113549.1.12": { "d": "pkcs-12", "c": "" }, +"1.2.840.113549.1.12.1": { "d": "pkcs-12-PbeIds", "c": "This OID was formerly assigned as PKCS #12 modeID" }, +"1.2.840.113549.1.12.1.1": { "d": "pbeWithSHAAnd128BitRC4", "c": "PKCS #12 PbeIds. This OID was formerly assigned as pkcs-12-OfflineTransportMode" }, +"1.2.840.113549.1.12.1.2": { "d": "pbeWithSHAAnd40BitRC4", "c": "PKCS #12 PbeIds. This OID was formerly assigned as pkcs-12-OnlineTransportMode" }, +"1.2.840.113549.1.12.1.3": { "d": "pbeWithSHAAnd3-KeyTripleDES-CBC", "c": "PKCS #12 PbeIds" }, +"1.2.840.113549.1.12.1.4": { "d": "pbeWithSHAAnd2-KeyTripleDES-CBC", "c": "PKCS #12 PbeIds" }, +"1.2.840.113549.1.12.1.5": { "d": "pbeWithSHAAnd128BitRC2-CBC", "c": "PKCS #12 PbeIds" }, +"1.2.840.113549.1.12.1.6": { "d": "pbeWithSHAAnd40BitRC2-CBC", "c": "PKCS #12 PbeIds" }, +"1.2.840.113549.1.12.2": { "d": "pkcs-12-ESPVKID", "c": "Deprecated", "w": true }, +"1.2.840.113549.1.12.2.1": { "d": "pkcs-12-PKCS8KeyShrouding", "c": "PKCS #12 ESPVKID. Deprecated, use (1 2 840 113549 1 12 3 5) instead", "w": true }, +"1.2.840.113549.1.12.3": { "d": "pkcs-12-BagIds", "c": "" }, +"1.2.840.113549.1.12.3.1": { "d": "pkcs-12-keyBagId", "c": "PKCS #12 BagIds" }, +"1.2.840.113549.1.12.3.2": { "d": "pkcs-12-certAndCRLBagId", "c": "PKCS #12 BagIds" }, +"1.2.840.113549.1.12.3.3": { "d": "pkcs-12-secretBagId", "c": "PKCS #12 BagIds" }, +"1.2.840.113549.1.12.3.4": { "d": "pkcs-12-safeContentsId", "c": "PKCS #12 BagIds" }, +"1.2.840.113549.1.12.3.5": { "d": "pkcs-12-pkcs-8ShroudedKeyBagId", "c": "PKCS #12 BagIds" }, +"1.2.840.113549.1.12.4": { "d": "pkcs-12-CertBagID", "c": "Deprecated", "w": true }, +"1.2.840.113549.1.12.4.1": { "d": "pkcs-12-X509CertCRLBagID", "c": "PKCS #12 CertBagID. This OID was formerly assigned as pkcs-12-X509CertCRLBag" }, +"1.2.840.113549.1.12.4.2": { "d": "pkcs-12-SDSICertBagID", "c": "PKCS #12 CertBagID. This OID was formerly assigned as pkcs-12-SDSICertBag" }, +"1.2.840.113549.1.12.5": { "d": "pkcs-12-OID", "c": "", "w": true }, +"1.2.840.113549.1.12.5.1": { "d": "pkcs-12-PBEID", "c": "PKCS #12 OID. Deprecated, use the partially compatible (1 2 840 113549 1 12 1) OIDs instead", "w": true }, +"1.2.840.113549.1.12.5.1.1": { "d": "pkcs-12-PBEWithSha1And128BitRC4", "c": "PKCS #12 OID PBEID. Deprecated, use (1 2 840 113549 1 12 1 1) instead", "w": true }, +"1.2.840.113549.1.12.5.1.2": { "d": "pkcs-12-PBEWithSha1And40BitRC4", "c": "PKCS #12 OID PBEID. Deprecated, use (1 2 840 113549 1 12 1 2) instead", "w": true }, +"1.2.840.113549.1.12.5.1.3": { "d": "pkcs-12-PBEWithSha1AndTripleDESCBC", "c": "PKCS #12 OID PBEID. Deprecated, use the incompatible but similar (1 2 840 113549 1 12 1 3) or (1 2 840 113549 1 12 1 4) instead", "w": true }, +"1.2.840.113549.1.12.5.1.4": { "d": "pkcs-12-PBEWithSha1And128BitRC2CBC", "c": "PKCS #12 OID PBEID. Deprecated, use (1 2 840 113549 1 12 1 5) instead", "w": true }, +"1.2.840.113549.1.12.5.1.5": { "d": "pkcs-12-PBEWithSha1And40BitRC2CBC", "c": "PKCS #12 OID PBEID. Deprecated, use (1 2 840 113549 1 12 1 6) instead", "w": true }, +"1.2.840.113549.1.12.5.1.6": { "d": "pkcs-12-PBEWithSha1AndRC4", "c": "PKCS #12 OID PBEID. Deprecated, use the incompatible but similar (1 2 840 113549 1 12 1 1) or (1 2 840 113549 1 12 1 2) instead", "w": true }, +"1.2.840.113549.1.12.5.1.7": { "d": "pkcs-12-PBEWithSha1AndRC2CBC", "c": "PKCS #12 OID PBEID. Deprecated, use the incompatible but similar (1 2 840 113549 1 12 1 5) or (1 2 840 113549 1 12 1 6) instead", "w": true }, +"1.2.840.113549.1.12.5.2": { "d": "pkcs-12-EnvelopingID", "c": "PKCS #12 OID. Deprecated, use the conventional PKCS #1 OIDs instead" }, +"1.2.840.113549.1.12.5.2.1": { "d": "pkcs-12-RSAEncryptionWith128BitRC4", "c": "PKCS #12 OID EnvelopingID. Deprecated, use the conventional PKCS #1 OIDs instead", "w": true }, +"1.2.840.113549.1.12.5.2.2": { "d": "pkcs-12-RSAEncryptionWith40BitRC4", "c": "PKCS #12 OID EnvelopingID. Deprecated, use the conventional PKCS #1 OIDs instead", "w": true }, +"1.2.840.113549.1.12.5.2.3": { "d": "pkcs-12-RSAEncryptionWithTripleDES", "c": "PKCS #12 OID EnvelopingID. Deprecated, use the conventional PKCS #1 OIDs instead", "w": true }, +"1.2.840.113549.1.12.5.3": { "d": "pkcs-12-SignatureID", "c": "PKCS #12 OID EnvelopingID. Deprecated, use the conventional PKCS #1 OIDs instead", "w": true }, +"1.2.840.113549.1.12.5.3.1": { "d": "pkcs-12-RSASignatureWithSHA1Digest", "c": "PKCS #12 OID SignatureID. Deprecated, use the conventional PKCS #1 OIDs instead", "w": true }, +"1.2.840.113549.1.12.10": { "d": "pkcs-12Version1", "c": "" }, +"1.2.840.113549.1.12.10.1": { "d": "pkcs-12BadIds", "c": "" }, +"1.2.840.113549.1.12.10.1.1": { "d": "pkcs-12-keyBag", "c": "PKCS #12 BagIds" }, +"1.2.840.113549.1.12.10.1.2": { "d": "pkcs-12-pkcs-8ShroudedKeyBag", "c": "PKCS #12 BagIds" }, +"1.2.840.113549.1.12.10.1.3": { "d": "pkcs-12-certBag", "c": "PKCS #12 BagIds" }, +"1.2.840.113549.1.12.10.1.4": { "d": "pkcs-12-crlBag", "c": "PKCS #12 BagIds" }, +"1.2.840.113549.1.12.10.1.5": { "d": "pkcs-12-secretBag", "c": "PKCS #12 BagIds" }, +"1.2.840.113549.1.12.10.1.6": { "d": "pkcs-12-safeContentsBag", "c": "PKCS #12 BagIds" }, +"1.2.840.113549.1.15.1": { "d": "pkcs15modules", "c": "PKCS #15" }, +"1.2.840.113549.1.15.2": { "d": "pkcs15attributes", "c": "PKCS #15" }, +"1.2.840.113549.1.15.3": { "d": "pkcs15contentType", "c": "PKCS #15" }, +"1.2.840.113549.1.15.3.1": { "d": "pkcs15content", "c": "PKCS #15 content type" }, +"1.2.840.113549.2": { "d": "digestAlgorithm", "c": "" }, +"1.2.840.113549.2.2": { "d": "md2", "c": "RSADSI digestAlgorithm" }, +"1.2.840.113549.2.4": { "d": "md4", "c": "RSADSI digestAlgorithm" }, +"1.2.840.113549.2.5": { "d": "md5", "c": "RSADSI digestAlgorithm" }, +"1.2.840.113549.2.7": { "d": "hmacWithSHA1", "c": "RSADSI digestAlgorithm" }, +"1.2.840.113549.2.8": { "d": "hmacWithSHA224", "c": "RSADSI digestAlgorithm" }, +"1.2.840.113549.2.9": { "d": "hmacWithSHA256", "c": "RSADSI digestAlgorithm" }, +"1.2.840.113549.2.10": { "d": "hmacWithSHA384", "c": "RSADSI digestAlgorithm" }, +"1.2.840.113549.2.11": { "d": "hmacWithSHA512", "c": "RSADSI digestAlgorithm" }, +"1.2.840.113549.3": { "d": "encryptionAlgorithm", "c": "" }, +"1.2.840.113549.3.2": { "d": "rc2CBC", "c": "RSADSI encryptionAlgorithm" }, +"1.2.840.113549.3.3": { "d": "rc2ECB", "c": "RSADSI encryptionAlgorithm" }, +"1.2.840.113549.3.4": { "d": "rc4", "c": "RSADSI encryptionAlgorithm" }, +"1.2.840.113549.3.5": { "d": "rc4WithMAC", "c": "RSADSI encryptionAlgorithm" }, +"1.2.840.113549.3.6": { "d": "desx-CBC", "c": "RSADSI encryptionAlgorithm" }, +"1.2.840.113549.3.7": { "d": "des-EDE3-CBC", "c": "RSADSI encryptionAlgorithm" }, +"1.2.840.113549.3.8": { "d": "rc5CBC", "c": "RSADSI encryptionAlgorithm" }, +"1.2.840.113549.3.9": { "d": "rc5-CBCPad", "c": "RSADSI encryptionAlgorithm" }, +"1.2.840.113549.3.10": { "d": "desCDMF", "c": "RSADSI encryptionAlgorithm. Formerly called CDMFCBCPad" }, +"1.2.840.114021.1.6.1": { "d": "Identrus unknown policyIdentifier", "c": "Identrus" }, +"1.2.840.114021.4.1": { "d": "identrusOCSP", "c": "Identrus" }, +"1.2.840.113556.1.2.241": { "d": "deliveryMechanism", "c": "Microsoft Exchange Server - attribute" }, +"1.2.840.113556.1.2.281": { "d": "ntSecurityDescriptor", "c": "Microsoft Cert Template - attribute" }, +"1.2.840.113556.1.3.0": { "d": "site-Addressing", "c": "Microsoft Exchange Server - object class" }, +"1.2.840.113556.1.3.13": { "d": "classSchema", "c": "Microsoft Exchange Server - object class" }, +"1.2.840.113556.1.3.14": { "d": "attributeSchema", "c": "Microsoft Exchange Server - object class" }, +"1.2.840.113556.1.3.17": { "d": "mailbox-Agent", "c": "Microsoft Exchange Server - object class" }, +"1.2.840.113556.1.3.22": { "d": "mailbox", "c": "Microsoft Exchange Server - object class" }, +"1.2.840.113556.1.3.23": { "d": "container", "c": "Microsoft Exchange Server - object class" }, +"1.2.840.113556.1.3.46": { "d": "mailRecipient", "c": "Microsoft Exchange Server - object class" }, +"1.2.840.113556.1.4.145": { "d": "revision", "c": "Microsoft Cert Template - attribute" }, +"1.2.840.113556.1.4.1327": { "d": "pKIDefaultKeySpec", "c": "Microsoft Cert Template - attribute" }, +"1.2.840.113556.1.4.1328": { "d": "pKIKeyUsage", "c": "Microsoft Cert Template - attribute" }, +"1.2.840.113556.1.4.1329": { "d": "pKIMaxIssuingDepth", "c": "Microsoft Cert Template - attribute" }, +"1.2.840.113556.1.4.1330": { "d": "pKICriticalExtensions", "c": "Microsoft Cert Template - attribute" }, +"1.2.840.113556.1.4.1331": { "d": "pKIExpirationPeriod", "c": "Microsoft Cert Template - attribute" }, +"1.2.840.113556.1.4.1332": { "d": "pKIOverlapPeriod", "c": "Microsoft Cert Template - attribute" }, +"1.2.840.113556.1.4.1333": { "d": "pKIExtendedKeyUsage", "c": "Microsoft Cert Template - attribute" }, +"1.2.840.113556.1.4.1334": { "d": "pKIDefaultCSPs", "c": "Microsoft Cert Template - attribute" }, +"1.2.840.113556.1.4.1335": { "d": "pKIEnrollmentAccess", "c": "Microsoft Cert Template - attribute" }, +"1.2.840.113556.1.4.1429": { "d": "msPKI-RA-Signature", "c": "Microsoft Cert Template - attribute" }, +"1.2.840.113556.1.4.1430": { "d": "msPKI-Enrollment-Flag", "c": "Microsoft Cert Template - attribute" }, +"1.2.840.113556.1.4.1431": { "d": "msPKI-Private-Key-Flag", "c": "Microsoft Cert Template - attribute" }, +"1.2.840.113556.1.4.1432": { "d": "msPKI-Certificate-Name-Flag", "c": "Microsoft Cert Template - attribute" }, +"1.2.840.113556.1.4.1433": { "d": "msPKI-Minimal-Key-Size", "c": "Microsoft Cert Template - attribute" }, +"1.2.840.113556.1.4.1434": { "d": "msPKI-Template-Schema-Version", "c": "Microsoft Cert Template - attribute" }, +"1.2.840.113556.1.4.1435": { "d": "msPKI-Template-Minor-Revision", "c": "Microsoft Cert Template - attribute" }, +"1.2.840.113556.1.4.1436": { "d": "msPKI-Cert-Template-OID", "c": "Microsoft Cert Template - attribute" }, +"1.2.840.113556.1.4.1437": { "d": "msPKI-Supersede-Templates", "c": "Microsoft Cert Template - attribute" }, +"1.2.840.113556.1.4.1438": { "d": "msPKI-RA-Policies", "c": "Microsoft Cert Template - attribute" }, +"1.2.840.113556.1.4.1439": { "d": "msPKI-Certificate-Policy", "c": "Microsoft Cert Template - attribute" }, +"1.2.840.113556.1.4.1674": { "d": "msPKI-Certificate-Application-Policy", "c": "Microsoft Cert Template - attribute" }, +"1.2.840.113556.1.4.1675": { "d": "msPKI-RA-Application-Policies", "c": "Microsoft Cert Template - attribute" }, +"1.2.840.113556.4.3": { "d": "microsoftExcel", "c": "Microsoft" }, +"1.2.840.113556.4.4": { "d": "titledWithOID", "c": "Microsoft" }, +"1.2.840.113556.4.5": { "d": "microsoftPowerPoint", "c": "Microsoft" }, +"1.2.840.113583.1": { "d": "adobeAcrobat", "c": "Adobe Acrobat" }, +"1.2.840.113583.1.1": { "d": "acrobatSecurity", "c": "Adobe Acrobat security" }, +"1.2.840.113583.1.1.1": { "d": "pdfPassword", "c": "Adobe Acrobat security" }, +"1.2.840.113583.1.1.2": { "d": "pdfDefaultSigningCredential", "c": "Adobe Acrobat security" }, +"1.2.840.113583.1.1.3": { "d": "pdfDefaultEncryptionCredential", "c": "Adobe Acrobat security" }, +"1.2.840.113583.1.1.4": { "d": "pdfPasswordTimeout", "c": "Adobe Acrobat security" }, +"1.2.840.113583.1.1.5": { "d": "pdfAuthenticDocumentsTrust", "c": "Adobe Acrobat security" }, +"1.2.840.113583.1.1.6": { "d": "pdfDynamicContentTrust", "c": "Adobe Acrobat security", "w": true }, +"1.2.840.113583.1.1.7": { "d": "pdfUbiquityTrust", "c": "Adobe Acrobat security" }, +"1.2.840.113583.1.1.8": { "d": "pdfRevocationInfoArchival", "c": "Adobe Acrobat security" }, +"1.2.840.113583.1.1.9": { "d": "pdfX509Extension", "c": "Adobe Acrobat security" }, +"1.2.840.113583.1.1.9.1": { "d": "pdfTimeStamp", "c": "Adobe Acrobat security" }, +"1.2.840.113583.1.1.9.2": { "d": "pdfArchiveRevInfo", "c": "Adobe Acrobat security" }, +"1.2.840.113583.1.1.10": { "d": "pdfPPLKLiteCredential", "c": "Adobe Acrobat security" }, +"1.2.840.113583.1.2": { "d": "acrobatCPS", "c": "Adobe Acrobat CPS" }, +"1.2.840.113583.1.2.1": { "d": "pdfAuthenticDocumentsCPS", "c": "Adobe Acrobat CPS" }, +"1.2.840.113583.1.2.2": { "d": "pdfTestCPS", "c": "Adobe Acrobat CPS" }, +"1.2.840.113583.1.2.3": { "d": "pdfUbiquityCPS", "c": "Adobe Acrobat CPS" }, +"1.2.840.113583.1.2.4": { "d": "pdfAdhocCPS", "c": "Adobe Acrobat CPS" }, +"1.2.840.113583.1.7": { "d": "acrobatUbiquity", "c": "Adobe Acrobat ubiquity" }, +"1.2.840.113583.1.7.1": { "d": "pdfUbiquitySubRights", "c": "Adobe Acrobat ubiquity" }, +"1.2.840.113583.1.9": { "d": "acrobatExtension", "c": "Adobe Acrobat X.509 extension" }, +"1.2.840.113628.114.1.7": { "d": "adobePKCS7", "c": "Adobe" }, +"1.2.840.113635.100": { "d": "appleDataSecurity", "c": "Apple" }, +"1.2.840.113635.100.1": { "d": "appleTrustPolicy", "c": "Apple" }, +"1.2.840.113635.100.1.1": { "d": "appleISignTP", "c": "Apple trust policy" }, +"1.2.840.113635.100.1.2": { "d": "appleX509Basic", "c": "Apple trust policy" }, +"1.2.840.113635.100.1.3": { "d": "appleSSLPolicy", "c": "Apple trust policy" }, +"1.2.840.113635.100.1.4": { "d": "appleLocalCertGenPolicy", "c": "Apple trust policy" }, +"1.2.840.113635.100.1.5": { "d": "appleCSRGenPolicy", "c": "Apple trust policy" }, +"1.2.840.113635.100.1.6": { "d": "appleCRLPolicy", "c": "Apple trust policy" }, +"1.2.840.113635.100.1.7": { "d": "appleOCSPPolicy", "c": "Apple trust policy" }, +"1.2.840.113635.100.1.8": { "d": "appleSMIMEPolicy", "c": "Apple trust policy" }, +"1.2.840.113635.100.1.9": { "d": "appleEAPPolicy", "c": "Apple trust policy" }, +"1.2.840.113635.100.1.10": { "d": "appleSWUpdateSigningPolicy", "c": "Apple trust policy" }, +"1.2.840.113635.100.1.11": { "d": "appleIPSecPolicy", "c": "Apple trust policy" }, +"1.2.840.113635.100.1.12": { "d": "appleIChatPolicy", "c": "Apple trust policy" }, +"1.2.840.113635.100.1.13": { "d": "appleResourceSignPolicy", "c": "Apple trust policy" }, +"1.2.840.113635.100.1.14": { "d": "applePKINITClientPolicy", "c": "Apple trust policy" }, +"1.2.840.113635.100.1.15": { "d": "applePKINITServerPolicy", "c": "Apple trust policy" }, +"1.2.840.113635.100.1.16": { "d": "appleCodeSigningPolicy", "c": "Apple trust policy" }, +"1.2.840.113635.100.1.17": { "d": "applePackageSigningPolicy", "c": "Apple trust policy" }, +"1.2.840.113635.100.2": { "d": "appleSecurityAlgorithm", "c": "Apple" }, +"1.2.840.113635.100.2.1": { "d": "appleFEE", "c": "Apple security algorithm" }, +"1.2.840.113635.100.2.2": { "d": "appleASC", "c": "Apple security algorithm" }, +"1.2.840.113635.100.2.3": { "d": "appleFEE_MD5", "c": "Apple security algorithm" }, +"1.2.840.113635.100.2.4": { "d": "appleFEE_SHA1", "c": "Apple security algorithm" }, +"1.2.840.113635.100.2.5": { "d": "appleFEED", "c": "Apple security algorithm" }, +"1.2.840.113635.100.2.6": { "d": "appleFEEDEXP", "c": "Apple security algorithm" }, +"1.2.840.113635.100.2.7": { "d": "appleECDSA", "c": "Apple security algorithm" }, +"1.2.840.113635.100.3": { "d": "appleDotMacCertificate", "c": "Apple" }, +"1.2.840.113635.100.3.1": { "d": "appleDotMacCertificateRequest", "c": "Apple dotMac certificate" }, +"1.2.840.113635.100.3.2": { "d": "appleDotMacCertificateExtension", "c": "Apple dotMac certificate" }, +"1.2.840.113635.100.3.3": { "d": "appleDotMacCertificateRequestValues", "c": "Apple dotMac certificate" }, +"1.2.840.113635.100.4": { "d": "appleExtendedKeyUsage", "c": "Apple" }, +"1.2.840.113635.100.4.1": { "d": "appleCodeSigning", "c": "Apple extended key usage" }, +"1.2.840.113635.100.4.1.1": { "d": "appleCodeSigningDevelopment", "c": "Apple extended key usage" }, +"1.2.840.113635.100.4.1.2": { "d": "appleSoftwareUpdateSigning", "c": "Apple extended key usage" }, +"1.2.840.113635.100.4.1.3": { "d": "appleCodeSigningThirdParty", "c": "Apple extended key usage" }, +"1.2.840.113635.100.4.1.4": { "d": "appleResourceSigning", "c": "Apple extended key usage" }, +"1.2.840.113635.100.4.2": { "d": "appleIChatSigning", "c": "Apple extended key usage" }, +"1.2.840.113635.100.4.3": { "d": "appleIChatEncryption", "c": "Apple extended key usage" }, +"1.2.840.113635.100.4.4": { "d": "appleSystemIdentity", "c": "Apple extended key usage" }, +"1.2.840.113635.100.4.5": { "d": "appleCryptoEnv", "c": "Apple extended key usage" }, +"1.2.840.113635.100.4.5.1": { "d": "appleCryptoProductionEnv", "c": "Apple extended key usage" }, +"1.2.840.113635.100.4.5.2": { "d": "appleCryptoMaintenanceEnv", "c": "Apple extended key usage" }, +"1.2.840.113635.100.4.5.3": { "d": "appleCryptoTestEnv", "c": "Apple extended key usage" }, +"1.2.840.113635.100.4.5.4": { "d": "appleCryptoDevelopmentEnv", "c": "Apple extended key usage" }, +"1.2.840.113635.100.4.6": { "d": "appleCryptoQoS", "c": "Apple extended key usage" }, +"1.2.840.113635.100.4.6.1": { "d": "appleCryptoTier0QoS", "c": "Apple extended key usage" }, +"1.2.840.113635.100.4.6.2": { "d": "appleCryptoTier1QoS", "c": "Apple extended key usage" }, +"1.2.840.113635.100.4.6.3": { "d": "appleCryptoTier2QoS", "c": "Apple extended key usage" }, +"1.2.840.113635.100.4.6.4": { "d": "appleCryptoTier3QoS", "c": "Apple extended key usage" }, +"1.2.840.113635.100.5": { "d": "appleCertificatePolicies", "c": "Apple" }, +"1.2.840.113635.100.5.1": { "d": "appleCertificatePolicyID", "c": "Apple" }, +"1.2.840.113635.100.5.2": { "d": "appleDotMacCertificatePolicyID", "c": "Apple" }, +"1.2.840.113635.100.5.3": { "d": "appleADCCertificatePolicyID", "c": "Apple" }, +"1.2.840.113635.100.6": { "d": "appleCertificateExtensions", "c": "Apple" }, +"1.2.840.113635.100.6.1": { "d": "appleCertificateExtensionCodeSigning", "c": "Apple certificate extension" }, +"1.2.840.113635.100.6.1.1": { "d": "appleCertificateExtensionAppleSigning", "c": "Apple certificate extension" }, +"1.2.840.113635.100.6.1.2": { "d": "appleCertificateExtensionADCDeveloperSigning", "c": "Apple certificate extension" }, +"1.2.840.113635.100.6.1.3": { "d": "appleCertificateExtensionADCAppleSigning", "c": "Apple certificate extension" }, +"1.3.6.1.4.1.311.2.1.4": { "d": "spcIndirectDataContext", "c": "Microsoft code signing" }, +"1.3.6.1.4.1.311.2.1.10": { "d": "spcAgencyInfo", "c": "Microsoft code signing. Also known as policyLink" }, +"1.3.6.1.4.1.311.2.1.11": { "d": "spcStatementType", "c": "Microsoft code signing" }, +"1.3.6.1.4.1.311.2.1.12": { "d": "spcSpOpusInfo", "c": "Microsoft code signing" }, +"1.3.6.1.4.1.311.2.1.14": { "d": "certReqExtensions", "c": "Microsoft" }, +"1.3.6.1.4.1.311.2.1.15": { "d": "spcPEImageData", "c": "Microsoft code signing" }, +"1.3.6.1.4.1.311.2.1.18": { "d": "spcRawFileData", "c": "Microsoft code signing" }, +"1.3.6.1.4.1.311.2.1.19": { "d": "spcStructuredStorageData", "c": "Microsoft code signing" }, +"1.3.6.1.4.1.311.2.1.20": { "d": "spcJavaClassData (type 1)", "c": "Microsoft code signing. Formerly \"link extension\" aka \"glue extension\"" }, +"1.3.6.1.4.1.311.2.1.21": { "d": "individualCodeSigning", "c": "Microsoft" }, +"1.3.6.1.4.1.311.2.1.22": { "d": "commercialCodeSigning", "c": "Microsoft" }, +"1.3.6.1.4.1.311.2.1.25": { "d": "spcLink (type 2)", "c": "Microsoft code signing. Also known as \"glue extension\"" }, +"1.3.6.1.4.1.311.2.1.26": { "d": "spcMinimalCriteriaInfo", "c": "Microsoft code signing" }, +"1.3.6.1.4.1.311.2.1.27": { "d": "spcFinancialCriteriaInfo", "c": "Microsoft code signing" }, +"1.3.6.1.4.1.311.2.1.28": { "d": "spcLink (type 3)", "c": "Microsoft code signing. Also known as \"glue extension\"" }, +"1.3.6.1.4.1.311.2.1.29": { "d": "spcHashInfoObjID", "c": "Microsoft code signing" }, +"1.3.6.1.4.1.311.2.1.30": { "d": "spcSipInfoObjID", "c": "Microsoft code signing" }, +"1.3.6.1.4.1.311.2.2": { "d": "ctl", "c": "Microsoft CTL" }, +"1.3.6.1.4.1.311.2.2.1": { "d": "ctlTrustedCodesigningCAList", "c": "Microsoft CTL" }, +"1.3.6.1.4.1.311.2.2.2": { "d": "ctlTrustedClientAuthCAList", "c": "Microsoft CTL" }, +"1.3.6.1.4.1.311.2.2.3": { "d": "ctlTrustedServerAuthCAList", "c": "Microsoft CTL" }, +"1.3.6.1.4.1.311.3.2.1": { "d": "timestampRequest", "c": "Microsoft code signing" }, +"1.3.6.1.4.1.311.10.1": { "d": "certTrustList", "c": "Microsoft contentType" }, +"1.3.6.1.4.1.311.10.1.1": { "d": "sortedCtl", "c": "Microsoft contentType" }, +"1.3.6.1.4.1.311.10.2": { "d": "nextUpdateLocation", "c": "Microsoft" }, +"1.3.6.1.4.1.311.10.3.1": { "d": "certTrustListSigning", "c": "Microsoft enhanced key usage" }, +"1.3.6.1.4.1.311.10.3.2": { "d": "timeStampSigning", "c": "Microsoft enhanced key usage" }, +"1.3.6.1.4.1.311.10.3.3": { "d": "serverGatedCrypto", "c": "Microsoft enhanced key usage" }, +"1.3.6.1.4.1.311.10.3.3.1": { "d": "serialized", "c": "Microsoft" }, +"1.3.6.1.4.1.311.10.3.4": { "d": "encryptedFileSystem", "c": "Microsoft enhanced key usage" }, +"1.3.6.1.4.1.311.10.3.5": { "d": "whqlCrypto", "c": "Microsoft enhanced key usage" }, +"1.3.6.1.4.1.311.10.3.6": { "d": "nt5Crypto", "c": "Microsoft enhanced key usage" }, +"1.3.6.1.4.1.311.10.3.7": { "d": "oemWHQLCrypto", "c": "Microsoft enhanced key usage" }, +"1.3.6.1.4.1.311.10.3.8": { "d": "embeddedNTCrypto", "c": "Microsoft enhanced key usage" }, +"1.3.6.1.4.1.311.10.3.9": { "d": "rootListSigner", "c": "Microsoft enhanced key usage" }, +"1.3.6.1.4.1.311.10.3.10": { "d": "qualifiedSubordination", "c": "Microsoft enhanced key usage" }, +"1.3.6.1.4.1.311.10.3.11": { "d": "keyRecovery", "c": "Microsoft enhanced key usage" }, +"1.3.6.1.4.1.311.10.3.12": { "d": "documentSigning", "c": "Microsoft enhanced key usage" }, +"1.3.6.1.4.1.311.10.3.13": { "d": "lifetimeSigning", "c": "Microsoft enhanced key usage" }, +"1.3.6.1.4.1.311.10.3.14": { "d": "mobileDeviceSoftware", "c": "Microsoft enhanced key usage" }, +"1.3.6.1.4.1.311.10.3.15": { "d": "smartDisplay", "c": "Microsoft enhanced key usage" }, +"1.3.6.1.4.1.311.10.3.16": { "d": "cspSignature", "c": "Microsoft enhanced key usage" }, +"1.3.6.1.4.1.311.10.3.4.1": { "d": "efsRecovery", "c": "Microsoft enhanced key usage" }, +"1.3.6.1.4.1.311.10.4.1": { "d": "yesnoTrustAttr", "c": "Microsoft attribute" }, +"1.3.6.1.4.1.311.10.5.1": { "d": "drm", "c": "Microsoft enhanced key usage" }, +"1.3.6.1.4.1.311.10.5.2": { "d": "drmIndividualization", "c": "Microsoft enhanced key usage" }, +"1.3.6.1.4.1.311.10.6.1": { "d": "licenses", "c": "Microsoft enhanced key usage" }, +"1.3.6.1.4.1.311.10.6.2": { "d": "licenseServer", "c": "Microsoft enhanced key usage" }, +"1.3.6.1.4.1.311.10.7.1": { "d": "keyidRdn", "c": "Microsoft attribute" }, +"1.3.6.1.4.1.311.10.8.1": { "d": "removeCertificate", "c": "Microsoft attribute" }, +"1.3.6.1.4.1.311.10.9.1": { "d": "crossCertDistPoints", "c": "Microsoft attribute" }, +"1.3.6.1.4.1.311.10.10.1": { "d": "cmcAddAttributes", "c": "Microsoft" }, +"1.3.6.1.4.1.311.10.11": { "d": "certPropIdPrefix", "c": "Microsoft" }, +"1.3.6.1.4.1.311.10.11.4": { "d": "certMd5HashPropId", "c": "Microsoft" }, +"1.3.6.1.4.1.311.10.11.20": { "d": "certKeyIdentifierPropId", "c": "Microsoft" }, +"1.3.6.1.4.1.311.10.11.28": { "d": "certIssuerSerialNumberMd5HashPropId", "c": "Microsoft" }, +"1.3.6.1.4.1.311.10.11.29": { "d": "certSubjectNameMd5HashPropId", "c": "Microsoft" }, +"1.3.6.1.4.1.311.10.12.1": { "d": "anyApplicationPolicy", "c": "Microsoft attribute" }, +"1.3.6.1.4.1.311.12": { "d": "catalog", "c": "Microsoft attribute" }, +"1.3.6.1.4.1.311.12.1.1": { "d": "catalogList", "c": "Microsoft attribute" }, +"1.3.6.1.4.1.311.12.1.2": { "d": "catalogListMember", "c": "Microsoft attribute" }, +"1.3.6.1.4.1.311.12.2.1": { "d": "catalogNameValueObjID", "c": "Microsoft attribute" }, +"1.3.6.1.4.1.311.12.2.2": { "d": "catalogMemberInfoObjID", "c": "Microsoft attribute" }, +"1.3.6.1.4.1.311.13.1": { "d": "renewalCertificate", "c": "Microsoft attribute" }, +"1.3.6.1.4.1.311.13.2.1": { "d": "enrolmentNameValuePair", "c": "Microsoft attribute" }, +"1.3.6.1.4.1.311.13.2.2": { "d": "enrolmentCSP", "c": "Microsoft attribute" }, +"1.3.6.1.4.1.311.13.2.3": { "d": "osVersion", "c": "Microsoft attribute" }, +"1.3.6.1.4.1.311.16.4": { "d": "microsoftRecipientInfo", "c": "Microsoft attribute" }, +"1.3.6.1.4.1.311.17.1": { "d": "pkcs12KeyProviderNameAttr", "c": "Microsoft attribute" }, +"1.3.6.1.4.1.311.17.2": { "d": "localMachineKeyset", "c": "Microsoft attribute" }, +"1.3.6.1.4.1.311.17.3": { "d": "pkcs12ExtendedAttributes", "c": "Microsoft attribute" }, +"1.3.6.1.4.1.311.20.1": { "d": "autoEnrollCtlUsage", "c": "Microsoft" }, +"1.3.6.1.4.1.311.20.2": { "d": "enrollCerttypeExtension", "c": "Microsoft CAPICOM certificate template, V1" }, +"1.3.6.1.4.1.311.20.2.1": { "d": "enrollmentAgent", "c": "Microsoft enhanced key usage" }, +"1.3.6.1.4.1.311.20.2.2": { "d": "smartcardLogon", "c": "Microsoft enhanced key usage" }, +"1.3.6.1.4.1.311.20.2.3": { "d": "universalPrincipalName", "c": "Microsoft UPN" }, +"1.3.6.1.4.1.311.20.3": { "d": "certManifold", "c": "Microsoft" }, +"1.3.6.1.4.1.311.21.1": { "d": "cAKeyCertIndexPair", "c": "Microsoft attribute. Also known as certsrvCaVersion" }, +"1.3.6.1.4.1.311.21.2": { "d": "certSrvPreviousCertHash", "c": "Microsoft" }, +"1.3.6.1.4.1.311.21.3": { "d": "crlVirtualBase", "c": "Microsoft" }, +"1.3.6.1.4.1.311.21.4": { "d": "crlNextPublish", "c": "Microsoft" }, +"1.3.6.1.4.1.311.21.5": { "d": "caExchange", "c": "Microsoft extended key usage", "w": true }, +"1.3.6.1.4.1.311.21.6": { "d": "keyRecovery", "c": "Microsoft extended key usage", "w": true }, +"1.3.6.1.4.1.311.21.7": { "d": "certificateTemplate", "c": "Microsoft CAPICOM certificate template, V2" }, +"1.3.6.1.4.1.311.21.9": { "d": "rdnDummySigner", "c": "Microsoft" }, +"1.3.6.1.4.1.311.21.10": { "d": "applicationCertPolicies", "c": "Microsoft" }, +"1.3.6.1.4.1.311.21.11": { "d": "applicationPolicyMappings", "c": "Microsoft" }, +"1.3.6.1.4.1.311.21.12": { "d": "applicationPolicyConstraints", "c": "Microsoft" }, +"1.3.6.1.4.1.311.21.13": { "d": "archivedKey", "c": "Microsoft attribute" }, +"1.3.6.1.4.1.311.21.14": { "d": "crlSelfCDP", "c": "Microsoft" }, +"1.3.6.1.4.1.311.21.15": { "d": "requireCertChainPolicy", "c": "Microsoft" }, +"1.3.6.1.4.1.311.21.16": { "d": "archivedKeyCertHash", "c": "Microsoft" }, +"1.3.6.1.4.1.311.21.17": { "d": "issuedCertHash", "c": "Microsoft" }, +"1.3.6.1.4.1.311.21.19": { "d": "dsEmailReplication", "c": "Microsoft" }, +"1.3.6.1.4.1.311.21.20": { "d": "requestClientInfo", "c": "Microsoft attribute" }, +"1.3.6.1.4.1.311.21.21": { "d": "encryptedKeyHash", "c": "Microsoft attribute" }, +"1.3.6.1.4.1.311.21.22": { "d": "certsrvCrossCaVersion", "c": "Microsoft" }, +"1.3.6.1.4.1.311.25.1": { "d": "ntdsReplication", "c": "Microsoft" }, +"1.3.6.1.4.1.311.31.1": { "d": "productUpdate", "c": "Microsoft attribute" }, +"1.3.6.1.4.1.311.47.1.1": { "d": "systemHealth", "c": "Microsoft extended key usage" }, +"1.3.6.1.4.1.311.47.1.3": { "d": "systemHealthLoophole", "c": "Microsoft extended key usage" }, +"1.3.6.1.4.1.311.60.1.1": { "d": "rootProgramFlags", "c": "Microsoft policy attribute" }, +"1.3.6.1.4.1.311.61.1.1": { "d": "kernelModeCodeSigning", "c": "Microsoft enhanced key usage" }, +"1.3.6.1.4.1.311.60.2.1.1": { "d": "jurisdictionOfIncorporationL", "c": "Microsoft (???)" }, +"1.3.6.1.4.1.311.60.2.1.2": { "d": "jurisdictionOfIncorporationSP", "c": "Microsoft (???)" }, +"1.3.6.1.4.1.311.60.2.1.3": { "d": "jurisdictionOfIncorporationC", "c": "Microsoft (???)" }, +"1.3.6.1.4.1.311.88": { "d": "capiCom", "c": "Microsoft attribute" }, +"1.3.6.1.4.1.311.88.1": { "d": "capiComVersion", "c": "Microsoft attribute" }, +"1.3.6.1.4.1.311.88.2": { "d": "capiComAttribute", "c": "Microsoft attribute" }, +"1.3.6.1.4.1.311.88.2.1": { "d": "capiComDocumentName", "c": "Microsoft attribute" }, +"1.3.6.1.4.1.311.88.2.2": { "d": "capiComDocumentDescription", "c": "Microsoft attribute" }, +"1.3.6.1.4.1.311.88.3": { "d": "capiComEncryptedData", "c": "Microsoft attribute" }, +"1.3.6.1.4.1.311.88.3.1": { "d": "capiComEncryptedContent", "c": "Microsoft attribute" }, +"1.3.6.1.4.1.188.7.1.1": { "d": "ascom", "c": "Ascom Systech" }, +"1.3.6.1.4.1.188.7.1.1.1": { "d": "ideaECB", "c": "Ascom Systech" }, +"1.3.6.1.4.1.188.7.1.1.2": { "d": "ideaCBC", "c": "Ascom Systech" }, +"1.3.6.1.4.1.188.7.1.1.3": { "d": "ideaCFB", "c": "Ascom Systech" }, +"1.3.6.1.4.1.188.7.1.1.4": { "d": "ideaOFB", "c": "Ascom Systech" }, +"1.3.6.1.4.1.2428.10.1.1": { "d": "UNINETT policyIdentifier", "c": "UNINETT PCA" }, +"1.3.6.1.4.1.2712.10": { "d": "ICE-TEL policyIdentifier", "c": "ICE-TEL CA" }, +"1.3.6.1.4.1.2786.1.1.1": { "d": "ICE-TEL Italian policyIdentifier", "c": "ICE-TEL CA policy" }, +"1.3.6.1.4.1.3029.1.1.1": { "d": "blowfishECB", "c": "cryptlib encryption algorithm" }, +"1.3.6.1.4.1.3029.1.1.2": { "d": "blowfishCBC", "c": "cryptlib encryption algorithm" }, +"1.3.6.1.4.1.3029.1.1.3": { "d": "blowfishCFB", "c": "cryptlib encryption algorithm" }, +"1.3.6.1.4.1.3029.1.1.4": { "d": "blowfishOFB", "c": "cryptlib encryption algorithm" }, +"1.3.6.1.4.1.3029.1.2.1": { "d": "elgamal", "c": "cryptlib public-key algorithm" }, +"1.3.6.1.4.1.3029.1.2.1.1": { "d": "elgamalWithSHA-1", "c": "cryptlib public-key algorithm" }, +"1.3.6.1.4.1.3029.1.2.1.2": { "d": "elgamalWithRIPEMD-160", "c": "cryptlib public-key algorithm" }, +"1.3.6.1.4.1.3029.3.1.1": { "d": "cryptlibPresenceCheck", "c": "cryptlib attribute type" }, +"1.3.6.1.4.1.3029.3.1.2": { "d": "pkiBoot", "c": "cryptlib attribute type" }, +"1.3.6.1.4.1.3029.3.1.4": { "d": "crlExtReason", "c": "cryptlib attribute type" }, +"1.3.6.1.4.1.3029.3.1.5": { "d": "keyFeatures", "c": "cryptlib attribute type" }, +"1.3.6.1.4.1.3029.4.1": { "d": "cryptlibContent", "c": "cryptlib" }, +"1.3.6.1.4.1.3029.4.1.1": { "d": "cryptlibConfigData", "c": "cryptlib content type" }, +"1.3.6.1.4.1.3029.4.1.2": { "d": "cryptlibUserIndex", "c": "cryptlib content type" }, +"1.3.6.1.4.1.3029.4.1.3": { "d": "cryptlibUserInfo", "c": "cryptlib content type" }, +"1.3.6.1.4.1.3029.4.1.4": { "d": "rtcsRequest", "c": "cryptlib content type" }, +"1.3.6.1.4.1.3029.4.1.5": { "d": "rtcsResponse", "c": "cryptlib content type" }, +"1.3.6.1.4.1.3029.4.1.6": { "d": "rtcsResponseExt", "c": "cryptlib content type" }, +"1.3.6.1.4.1.3029.42.11172.1": { "d": "mpeg-1", "c": "cryptlib special MPEG-of-cat OID" }, +"1.3.6.1.4.1.3029.54.11940.54": { "d": "TSA policy \"Anything that arrives, we sign\"", "c": "cryptlib TSA policy" }, +"1.3.6.1.4.1.3029.88.89.90.90.89": { "d": "xYZZY policyIdentifier", "c": "cryptlib certificate policy" }, +"1.3.6.1.4.1.3401.8.1.1": { "d": "pgpExtension", "c": "PGP key information" }, +"1.3.6.1.4.1.3576.7": { "d": "eciaAscX12Edi", "c": "TMN EDI for Interactive Agents" }, +"1.3.6.1.4.1.3576.7.1": { "d": "plainEDImessage", "c": "TMN EDI for Interactive Agents" }, +"1.3.6.1.4.1.3576.7.2": { "d": "signedEDImessage", "c": "TMN EDI for Interactive Agents" }, +"1.3.6.1.4.1.3576.7.5": { "d": "integrityEDImessage", "c": "TMN EDI for Interactive Agents" }, +"1.3.6.1.4.1.3576.7.65": { "d": "iaReceiptMessage", "c": "TMN EDI for Interactive Agents" }, +"1.3.6.1.4.1.3576.7.97": { "d": "iaStatusMessage", "c": "TMN EDI for Interactive Agents" }, +"1.3.6.1.4.1.3576.8": { "d": "eciaEdifact", "c": "TMN EDI for Interactive Agents" }, +"1.3.6.1.4.1.3576.9": { "d": "eciaNonEdi", "c": "TMN EDI for Interactive Agents" }, +"1.3.6.1.4.1.4146": { "d": "Globalsign", "c": "Globalsign" }, +"1.3.6.1.4.1.4146.1": { "d": "globalsignPolicy", "c": "Globalsign" }, +"1.3.6.1.4.1.4146.1.10": { "d": "globalsignDVPolicy", "c": "Globalsign policy" }, +"1.3.6.1.4.1.4146.1.20": { "d": "globalsignOVPolicy", "c": "Globalsign policy" }, +"1.3.6.1.4.1.4146.1.30": { "d": "globalsignTSAPolicy", "c": "Globalsign policy" }, +"1.3.6.1.4.1.4146.1.40": { "d": "globalsignClientCertPolicy", "c": "Globalsign policy" }, +"1.3.6.1.4.1.4146.1.50": { "d": "globalsignCodeSignPolicy", "c": "Globalsign policy" }, +"1.3.6.1.4.1.4146.1.60": { "d": "globalsignRootSignPolicy", "c": "Globalsign policy" }, +"1.3.6.1.4.1.4146.1.70": { "d": "globalsignTrustedRootPolicy", "c": "Globalsign policy" }, +"1.3.6.1.4.1.4146.1.80": { "d": "globalsignEDIClientPolicy", "c": "Globalsign policy" }, +"1.3.6.1.4.1.4146.1.81": { "d": "globalsignEDIServerPolicy", "c": "Globalsign policy" }, +"1.3.6.1.4.1.4146.1.90": { "d": "globalsignTPMRootPolicy", "c": "Globalsign policy" }, +"1.3.6.1.4.1.4146.1.95": { "d": "globalsignOCSPPolicy", "c": "Globalsign policy" }, +"1.3.6.1.4.1.5309.1": { "d": "edelWebPolicy", "c": "EdelWeb policy" }, +"1.3.6.1.4.1.5309.1.2": { "d": "edelWebCustomerPolicy", "c": "EdelWeb policy" }, +"1.3.6.1.4.1.5309.1.2.1": { "d": "edelWebClepsydrePolicy", "c": "EdelWeb policy" }, +"1.3.6.1.4.1.5309.1.2.2": { "d": "edelWebExperimentalTSAPolicy", "c": "EdelWeb policy" }, +"1.3.6.1.4.1.5309.1.2.3": { "d": "edelWebOpenEvidenceTSAPolicy", "c": "EdelWeb policy" }, +"1.3.6.1.4.1.5472": { "d": "timeproof", "c": "enterprise" }, +"1.3.6.1.4.1.5472.1": { "d": "tss", "c": "timeproof" }, +"1.3.6.1.4.1.5472.1.1": { "d": "tss80", "c": "timeproof TSS" }, +"1.3.6.1.4.1.5472.1.2": { "d": "tss380", "c": "timeproof TSS" }, +"1.3.6.1.4.1.5472.1.3": { "d": "tss400", "c": "timeproof TSS" }, +"1.3.6.1.4.1.5770.0.3": { "d": "secondaryPractices", "c": "MEDePass" }, +"1.3.6.1.4.1.5770.0.4": { "d": "physicianIdentifiers", "c": "MEDePass" }, +"1.3.6.1.4.1.6449.1.2.1.3.1": { "d": "comodoPolicy", "c": "Comodo CA" }, +"1.3.6.1.4.1.6449.1.2.2.15": { "d": "wotrustPolicy", "c": "WoTrust (Comodo) CA" }, +"1.3.6.1.4.1.6449.1.3.5.2": { "d": "comodoCertifiedDeliveryService", "c": "Comodo CA" }, +"1.3.6.1.4.1.6449.2.1.1": { "d": "comodoTimestampingPolicy", "c": "Comodo CA" }, +"1.3.6.1.4.1.8301.3.5.1": { "d": "validityModelChain", "c": "TU Darmstadt ValidityModel" }, +"1.3.6.1.4.1.8301.3.5.2": { "d": "validityModelShell", "c": "ValidityModel" }, +"1.3.6.1.4.1.8231.1": { "d": "rolUnicoNacional", "c": "Chilean Government national unique roll number" }, +"1.3.6.1.4.1.11591": { "d": "gnu", "c": "GNU Project (see http://www.gnupg.org/oids.html)" }, +"1.3.6.1.4.1.11591.1": { "d": "gnuRadius", "c": "GNU Radius" }, +"1.3.6.1.4.1.11591.3": { "d": "gnuRadar", "c": "GNU Radar" }, +"1.3.6.1.4.1.11591.12": { "d": "gnuDigestAlgorithm", "c": "GNU digest algorithm" }, +"1.3.6.1.4.1.11591.12.2": { "d": "tiger", "c": "GNU digest algorithm" }, +"1.3.6.1.4.1.11591.13": { "d": "gnuEncryptionAlgorithm", "c": "GNU encryption algorithm" }, +"1.3.6.1.4.1.11591.13.2": { "d": "serpent", "c": "GNU encryption algorithm" }, +"1.3.6.1.4.1.11591.13.2.1": { "d": "serpent128_ECB", "c": "GNU encryption algorithm" }, +"1.3.6.1.4.1.11591.13.2.2": { "d": "serpent128_CBC", "c": "GNU encryption algorithm" }, +"1.3.6.1.4.1.11591.13.2.3": { "d": "serpent128_OFB", "c": "GNU encryption algorithm" }, +"1.3.6.1.4.1.11591.13.2.4": { "d": "serpent128_CFB", "c": "GNU encryption algorithm" }, +"1.3.6.1.4.1.11591.13.2.21": { "d": "serpent192_ECB", "c": "GNU encryption algorithm" }, +"1.3.6.1.4.1.11591.13.2.22": { "d": "serpent192_CBC", "c": "GNU encryption algorithm" }, +"1.3.6.1.4.1.11591.13.2.23": { "d": "serpent192_OFB", "c": "GNU encryption algorithm" }, +"1.3.6.1.4.1.11591.13.2.24": { "d": "serpent192_CFB", "c": "GNU encryption algorithm" }, +"1.3.6.1.4.1.11591.13.2.41": { "d": "serpent256_ECB", "c": "GNU encryption algorithm" }, +"1.3.6.1.4.1.11591.13.2.42": { "d": "serpent256_CBC", "c": "GNU encryption algorithm" }, +"1.3.6.1.4.1.11591.13.2.43": { "d": "serpent256_OFB", "c": "GNU encryption algorithm" }, +"1.3.6.1.4.1.11591.13.2.44": { "d": "serpent256_CFB", "c": "GNU encryption algorithm" }, +"1.3.6.1.4.1.11591.15.1": { "d": "curve25519", "c": "GNU encryption algorithm" }, +"1.3.6.1.4.1.11591.15.2": { "d": "curve448", "c": "GNU encryption algorithm" }, +"1.3.6.1.4.1.11591.15.3": { "d": "curve25519ph", "c": "GNU encryption algorithm" }, +"1.3.6.1.4.1.11591.15.4": { "d": "curve448ph", "c": "GNU encryption algorithm" }, +"1.3.6.1.4.1.16334.509.1.1": { "d": "Northrop Grumman extKeyUsage?", "c": "Northrop Grumman extended key usage" }, +"1.3.6.1.4.1.16334.509.2.1": { "d": "ngcClass1", "c": "Northrop Grumman policy" }, +"1.3.6.1.4.1.16334.509.2.2": { "d": "ngcClass2", "c": "Northrop Grumman policy" }, +"1.3.6.1.4.1.16334.509.2.3": { "d": "ngcClass3", "c": "Northrop Grumman policy" }, +"1.3.6.1.4.1.23629.1.4.2.1.1": { "d": "safenetUsageLimit", "c": "SafeNet" }, +"1.3.6.1.4.1.23629.1.4.2.1.2": { "d": "safenetEndDate", "c": "SafeNet" }, +"1.3.6.1.4.1.23629.1.4.2.1.3": { "d": "safenetStartDate", "c": "SafeNet" }, +"1.3.6.1.4.1.23629.1.4.2.1.4": { "d": "safenetAdminCert", "c": "SafeNet" }, +"1.3.6.1.4.1.23629.1.4.2.2.1": { "d": "safenetKeyDigest", "c": "SafeNet" }, +"1.3.6.1.5.5.7": { "d": "pkix", "c": "" }, +"1.3.6.1.5.5.7.0.12": { "d": "attributeCert", "c": "PKIX" }, +"1.3.6.1.5.5.7.1": { "d": "privateExtension", "c": "PKIX" }, +"1.3.6.1.5.5.7.1.1": { "d": "authorityInfoAccess", "c": "PKIX private extension" }, +"1.3.6.1.5.5.7.1.2": { "d": "biometricInfo", "c": "PKIX private extension" }, +"1.3.6.1.5.5.7.1.3": { "d": "qcStatements", "c": "PKIX private extension" }, +"1.3.6.1.5.5.7.1.4": { "d": "acAuditIdentity", "c": "PKIX private extension" }, +"1.3.6.1.5.5.7.1.5": { "d": "acTargeting", "c": "PKIX private extension" }, +"1.3.6.1.5.5.7.1.6": { "d": "acAaControls", "c": "PKIX private extension" }, +"1.3.6.1.5.5.7.1.7": { "d": "ipAddrBlocks", "c": "PKIX private extension" }, +"1.3.6.1.5.5.7.1.8": { "d": "autonomousSysIds", "c": "PKIX private extension" }, +"1.3.6.1.5.5.7.1.9": { "d": "routerIdentifier", "c": "PKIX private extension" }, +"1.3.6.1.5.5.7.1.10": { "d": "acProxying", "c": "PKIX private extension" }, +"1.3.6.1.5.5.7.1.11": { "d": "subjectInfoAccess", "c": "PKIX private extension" }, +"1.3.6.1.5.5.7.1.12": { "d": "logoType", "c": "PKIX private extension" }, +"1.3.6.1.5.5.7.1.13": { "d": "wlanSSID", "c": "PKIX private extension" }, +"1.3.6.1.5.5.7.2": { "d": "policyQualifierIds", "c": "PKIX" }, +"1.3.6.1.5.5.7.2.1": { "d": "cps", "c": "PKIX policy qualifier" }, +"1.3.6.1.5.5.7.2.2": { "d": "unotice", "c": "PKIX policy qualifier" }, +"1.3.6.1.5.5.7.2.3": { "d": "textNotice", "c": "PKIX policy qualifier" }, +"1.3.6.1.5.5.7.3": { "d": "keyPurpose", "c": "PKIX" }, +"1.3.6.1.5.5.7.3.1": { "d": "serverAuth", "c": "PKIX key purpose" }, +"1.3.6.1.5.5.7.3.2": { "d": "clientAuth", "c": "PKIX key purpose" }, +"1.3.6.1.5.5.7.3.3": { "d": "codeSigning", "c": "PKIX key purpose" }, +"1.3.6.1.5.5.7.3.4": { "d": "emailProtection", "c": "PKIX key purpose" }, +"1.3.6.1.5.5.7.3.5": { "d": "ipsecEndSystem", "c": "PKIX key purpose" }, +"1.3.6.1.5.5.7.3.6": { "d": "ipsecTunnel", "c": "PKIX key purpose" }, +"1.3.6.1.5.5.7.3.7": { "d": "ipsecUser", "c": "PKIX key purpose" }, +"1.3.6.1.5.5.7.3.8": { "d": "timeStamping", "c": "PKIX key purpose" }, +"1.3.6.1.5.5.7.3.9": { "d": "ocspSigning", "c": "PKIX key purpose" }, +"1.3.6.1.5.5.7.3.10": { "d": "dvcs", "c": "PKIX key purpose" }, +"1.3.6.1.5.5.7.3.11": { "d": "sbgpCertAAServerAuth", "c": "PKIX key purpose" }, +"1.3.6.1.5.5.7.3.13": { "d": "eapOverPPP", "c": "PKIX key purpose" }, +"1.3.6.1.5.5.7.3.14": { "d": "eapOverLAN", "c": "PKIX key purpose" }, +"1.3.6.1.5.5.7.4": { "d": "cmpInformationTypes", "c": "PKIX" }, +"1.3.6.1.5.5.7.4.1": { "d": "caProtEncCert", "c": "PKIX CMP information" }, +"1.3.6.1.5.5.7.4.2": { "d": "signKeyPairTypes", "c": "PKIX CMP information" }, +"1.3.6.1.5.5.7.4.3": { "d": "encKeyPairTypes", "c": "PKIX CMP information" }, +"1.3.6.1.5.5.7.4.4": { "d": "preferredSymmAlg", "c": "PKIX CMP information" }, +"1.3.6.1.5.5.7.4.5": { "d": "caKeyUpdateInfo", "c": "PKIX CMP information" }, +"1.3.6.1.5.5.7.4.6": { "d": "currentCRL", "c": "PKIX CMP information" }, +"1.3.6.1.5.5.7.4.7": { "d": "unsupportedOIDs", "c": "PKIX CMP information" }, +"1.3.6.1.5.5.7.4.10": { "d": "keyPairParamReq", "c": "PKIX CMP information" }, +"1.3.6.1.5.5.7.4.11": { "d": "keyPairParamRep", "c": "PKIX CMP information" }, +"1.3.6.1.5.5.7.4.12": { "d": "revPassphrase", "c": "PKIX CMP information" }, +"1.3.6.1.5.5.7.4.13": { "d": "implicitConfirm", "c": "PKIX CMP information" }, +"1.3.6.1.5.5.7.4.14": { "d": "confirmWaitTime", "c": "PKIX CMP information" }, +"1.3.6.1.5.5.7.4.15": { "d": "origPKIMessage", "c": "PKIX CMP information" }, +"1.3.6.1.5.5.7.4.16": { "d": "suppLangTags", "c": "PKIX CMP information" }, +"1.3.6.1.5.5.7.5": { "d": "crmfRegistration", "c": "PKIX" }, +"1.3.6.1.5.5.7.5.1": { "d": "regCtrl", "c": "PKIX CRMF registration" }, +"1.3.6.1.5.5.7.5.1.1": { "d": "regToken", "c": "PKIX CRMF registration control" }, +"1.3.6.1.5.5.7.5.1.2": { "d": "authenticator", "c": "PKIX CRMF registration control" }, +"1.3.6.1.5.5.7.5.1.3": { "d": "pkiPublicationInfo", "c": "PKIX CRMF registration control" }, +"1.3.6.1.5.5.7.5.1.4": { "d": "pkiArchiveOptions", "c": "PKIX CRMF registration control" }, +"1.3.6.1.5.5.7.5.1.5": { "d": "oldCertID", "c": "PKIX CRMF registration control" }, +"1.3.6.1.5.5.7.5.1.6": { "d": "protocolEncrKey", "c": "PKIX CRMF registration control" }, +"1.3.6.1.5.5.7.5.1.7": { "d": "altCertTemplate", "c": "PKIX CRMF registration control" }, +"1.3.6.1.5.5.7.5.1.8": { "d": "wtlsTemplate", "c": "PKIX CRMF registration control" }, +"1.3.6.1.5.5.7.5.2": { "d": "utf8Pairs", "c": "PKIX CRMF registration" }, +"1.3.6.1.5.5.7.5.2.1": { "d": "utf8Pairs", "c": "PKIX CRMF registration control" }, +"1.3.6.1.5.5.7.5.2.2": { "d": "certReq", "c": "PKIX CRMF registration control" }, +"1.3.6.1.5.5.7.6": { "d": "algorithms", "c": "PKIX" }, +"1.3.6.1.5.5.7.6.1": { "d": "des40", "c": "PKIX algorithm" }, +"1.3.6.1.5.5.7.6.2": { "d": "noSignature", "c": "PKIX algorithm" }, +"1.3.6.1.5.5.7.6.3": { "d": "dh-sig-hmac-sha1", "c": "PKIX algorithm" }, +"1.3.6.1.5.5.7.6.4": { "d": "dh-pop", "c": "PKIX algorithm" }, +"1.3.6.1.5.5.7.7": { "d": "cmcControls", "c": "PKIX" }, +"1.3.6.1.5.5.7.8": { "d": "otherNames", "c": "PKIX" }, +"1.3.6.1.5.5.7.8.1": { "d": "personalData", "c": "PKIX other name" }, +"1.3.6.1.5.5.7.8.2": { "d": "userGroup", "c": "PKIX other name" }, +"1.3.6.1.5.5.7.8.5": { "d": "xmppAddr", "c": "PKIX other name" }, +"1.3.6.1.5.5.7.9": { "d": "personalData", "c": "PKIX qualified certificates" }, +"1.3.6.1.5.5.7.9.1": { "d": "dateOfBirth", "c": "PKIX personal data" }, +"1.3.6.1.5.5.7.9.2": { "d": "placeOfBirth", "c": "PKIX personal data" }, +"1.3.6.1.5.5.7.9.3": { "d": "gender", "c": "PKIX personal data" }, +"1.3.6.1.5.5.7.9.4": { "d": "countryOfCitizenship", "c": "PKIX personal data" }, +"1.3.6.1.5.5.7.9.5": { "d": "countryOfResidence", "c": "PKIX personal data" }, +"1.3.6.1.5.5.7.10": { "d": "attributeCertificate", "c": "PKIX" }, +"1.3.6.1.5.5.7.10.1": { "d": "authenticationInfo", "c": "PKIX attribute certificate extension" }, +"1.3.6.1.5.5.7.10.2": { "d": "accessIdentity", "c": "PKIX attribute certificate extension" }, +"1.3.6.1.5.5.7.10.3": { "d": "chargingIdentity", "c": "PKIX attribute certificate extension" }, +"1.3.6.1.5.5.7.10.4": { "d": "group", "c": "PKIX attribute certificate extension" }, +"1.3.6.1.5.5.7.10.5": { "d": "role", "c": "PKIX attribute certificate extension" }, +"1.3.6.1.5.5.7.10.6": { "d": "wlanSSID", "c": "PKIX attribute-certificate extension" }, +"1.3.6.1.5.5.7.11": { "d": "personalData", "c": "PKIX qualified certificates" }, +"1.3.6.1.5.5.7.11.1": { "d": "pkixQCSyntax-v1", "c": "PKIX qualified certificates" }, +"1.3.6.1.5.5.7.14.2": { "d": "resourceCertificatePolicy", "c": "PKIX policies" }, +"1.3.6.1.5.5.7.20": { "d": "logo", "c": "PKIX qualified certificates" }, +"1.3.6.1.5.5.7.20.1": { "d": "logoLoyalty", "c": "PKIX" }, +"1.3.6.1.5.5.7.20.2": { "d": "logoBackground", "c": "PKIX" }, +"1.3.6.1.5.5.7.48.1": { "d": "ocsp", "c": "PKIX" }, +"1.3.6.1.5.5.7.48.1.1": { "d": "ocspBasic", "c": "OCSP" }, +"1.3.6.1.5.5.7.48.1.2": { "d": "ocspNonce", "c": "OCSP" }, +"1.3.6.1.5.5.7.48.1.3": { "d": "ocspCRL", "c": "OCSP" }, +"1.3.6.1.5.5.7.48.1.4": { "d": "ocspResponse", "c": "OCSP" }, +"1.3.6.1.5.5.7.48.1.5": { "d": "ocspNoCheck", "c": "OCSP" }, +"1.3.6.1.5.5.7.48.1.6": { "d": "ocspArchiveCutoff", "c": "OCSP" }, +"1.3.6.1.5.5.7.48.1.7": { "d": "ocspServiceLocator", "c": "OCSP" }, +"1.3.6.1.5.5.7.48.2": { "d": "caIssuers", "c": "PKIX subject/authority info access descriptor" }, +"1.3.6.1.5.5.7.48.3": { "d": "timeStamping", "c": "PKIX subject/authority info access descriptor" }, +"1.3.6.1.5.5.7.48.4": { "d": "dvcs", "c": "PKIX subject/authority info access descriptor" }, +"1.3.6.1.5.5.7.48.5": { "d": "caRepository", "c": "PKIX subject/authority info access descriptor" }, +"1.3.6.1.5.5.7.48.7": { "d": "signedObjectRepository", "c": "PKIX subject/authority info access descriptor" }, +"1.3.6.1.5.5.7.48.10": { "d": "rpkiManifest", "c": "PKIX subject/authority info access descriptor" }, +"1.3.6.1.5.5.7.48.11": { "d": "signedObject", "c": "PKIX subject/authority info access descriptor" }, +"1.3.6.1.5.5.8.1.1": { "d": "hmacMD5", "c": "ISAKMP HMAC algorithm" }, +"1.3.6.1.5.5.8.1.2": { "d": "hmacSHA", "c": "ISAKMP HMAC algorithm" }, +"1.3.6.1.5.5.8.1.3": { "d": "hmacTiger", "c": "ISAKMP HMAC algorithm" }, +"1.3.6.1.5.5.8.2.2": { "d": "iKEIntermediate", "c": "IKE ???" }, +"1.3.12.2.1011.7.1": { "d": "decEncryptionAlgorithm", "c": "DASS algorithm" }, +"1.3.12.2.1011.7.1.2": { "d": "decDEA", "c": "DASS encryption algorithm" }, +"1.3.12.2.1011.7.2": { "d": "decHashAlgorithm", "c": "DASS algorithm" }, +"1.3.12.2.1011.7.2.1": { "d": "decMD2", "c": "DASS hash algorithm" }, +"1.3.12.2.1011.7.2.2": { "d": "decMD4", "c": "DASS hash algorithm" }, +"1.3.12.2.1011.7.3": { "d": "decSignatureAlgorithm", "c": "DASS algorithm" }, +"1.3.12.2.1011.7.3.1": { "d": "decMD2withRSA", "c": "DASS signature algorithm" }, +"1.3.12.2.1011.7.3.2": { "d": "decMD4withRSA", "c": "DASS signature algorithm" }, +"1.3.12.2.1011.7.3.3": { "d": "decDEAMAC", "c": "DASS signature algorithm" }, +"1.3.14.2.26.5": { "d": "sha", "c": "Unsure about this OID" }, +"1.3.14.3.2.1.1": { "d": "rsa", "c": "X.509. Unsure about this OID" }, +"1.3.14.3.2.2": { "d": "md4WitRSA", "c": "Oddball OIW OID" }, +"1.3.14.3.2.3": { "d": "md5WithRSA", "c": "Oddball OIW OID" }, +"1.3.14.3.2.4": { "d": "md4WithRSAEncryption", "c": "Oddball OIW OID" }, +"1.3.14.3.2.2.1": { "d": "sqmod-N", "c": "X.509. Deprecated", "w": true }, +"1.3.14.3.2.3.1": { "d": "sqmod-NwithRSA", "c": "X.509. Deprecated", "w": true }, +"1.3.14.3.2.6": { "d": "desECB", "c": "" }, +"1.3.14.3.2.7": { "d": "desCBC", "c": "" }, +"1.3.14.3.2.8": { "d": "desOFB", "c": "" }, +"1.3.14.3.2.9": { "d": "desCFB", "c": "" }, +"1.3.14.3.2.10": { "d": "desMAC", "c": "" }, +"1.3.14.3.2.11": { "d": "rsaSignature", "c": "ISO 9796-2, also X9.31 Part 1" }, +"1.3.14.3.2.12": { "d": "dsa", "c": "OIW?, supposedly from an incomplete version of SDN.701 (doesn't match final SDN.701)", "w": true }, +"1.3.14.3.2.13": { "d": "dsaWithSHA", "c": "Oddball OIW OID. Incorrectly used by JDK 1.1 in place of (1 3 14 3 2 27)", "w": true }, +"1.3.14.3.2.14": { "d": "mdc2WithRSASignature", "c": "Oddball OIW OID using 9796-2 padding rules" }, +"1.3.14.3.2.15": { "d": "shaWithRSASignature", "c": "Oddball OIW OID using 9796-2 padding rules" }, +"1.3.14.3.2.16": { "d": "dhWithCommonModulus", "c": "Oddball OIW OID. Deprecated, use a plain DH OID instead", "w": true }, +"1.3.14.3.2.17": { "d": "desEDE", "c": "Oddball OIW OID. Mode is ECB" }, +"1.3.14.3.2.18": { "d": "sha", "c": "Oddball OIW OID" }, +"1.3.14.3.2.19": { "d": "mdc-2", "c": "Oddball OIW OID, DES-based hash, planned for X9.31 Part 2" }, +"1.3.14.3.2.20": { "d": "dsaCommon", "c": "Oddball OIW OID. Deprecated, use a plain DSA OID instead", "w": true }, +"1.3.14.3.2.21": { "d": "dsaCommonWithSHA", "c": "Oddball OIW OID. Deprecated, use a plain dsaWithSHA OID instead", "w": true }, +"1.3.14.3.2.22": { "d": "rsaKeyTransport", "c": "Oddball OIW OID" }, +"1.3.14.3.2.23": { "d": "keyed-hash-seal", "c": "Oddball OIW OID" }, +"1.3.14.3.2.24": { "d": "md2WithRSASignature", "c": "Oddball OIW OID using 9796-2 padding rules" }, +"1.3.14.3.2.25": { "d": "md5WithRSASignature", "c": "Oddball OIW OID using 9796-2 padding rules" }, +"1.3.14.3.2.26": { "d": "sha1", "c": "OIW" }, +"1.3.14.3.2.27": { "d": "dsaWithSHA1", "c": "OIW. This OID may also be assigned as ripemd-160" }, +"1.3.14.3.2.28": { "d": "dsaWithCommonSHA1", "c": "OIW" }, +"1.3.14.3.2.29": { "d": "sha-1WithRSAEncryption", "c": "Oddball OIW OID" }, +"1.3.14.3.3.1": { "d": "simple-strong-auth-mechanism", "c": "Oddball OIW OID" }, +"1.3.14.7.2.1.1": { "d": "ElGamal", "c": "Unsure about this OID" }, +"1.3.14.7.2.3.1": { "d": "md2WithRSA", "c": "Unsure about this OID" }, +"1.3.14.7.2.3.2": { "d": "md2WithElGamal", "c": "Unsure about this OID" }, +"1.3.36.1": { "d": "document", "c": "Teletrust document" }, +"1.3.36.1.1": { "d": "finalVersion", "c": "Teletrust document" }, +"1.3.36.1.2": { "d": "draft", "c": "Teletrust document" }, +"1.3.36.2": { "d": "sio", "c": "Teletrust sio" }, +"1.3.36.2.1": { "d": "sedu", "c": "Teletrust sio" }, +"1.3.36.3": { "d": "algorithm", "c": "Teletrust algorithm" }, +"1.3.36.3.1": { "d": "encryptionAlgorithm", "c": "Teletrust algorithm" }, +"1.3.36.3.1.1": { "d": "des", "c": "Teletrust encryption algorithm" }, +"1.3.36.3.1.1.1": { "d": "desECB_pad", "c": "Teletrust encryption algorithm" }, +"1.3.36.3.1.1.1.1": { "d": "desECB_ISOpad", "c": "Teletrust encryption algorithm" }, +"1.3.36.3.1.1.2.1": { "d": "desCBC_pad", "c": "Teletrust encryption algorithm" }, +"1.3.36.3.1.1.2.1.1": { "d": "desCBC_ISOpad", "c": "Teletrust encryption algorithm" }, +"1.3.36.3.1.3": { "d": "des_3", "c": "Teletrust encryption algorithm" }, +"1.3.36.3.1.3.1.1": { "d": "des_3ECB_pad", "c": "Teletrust encryption algorithm. EDE triple DES" }, +"1.3.36.3.1.3.1.1.1": { "d": "des_3ECB_ISOpad", "c": "Teletrust encryption algorithm. EDE triple DES" }, +"1.3.36.3.1.3.2.1": { "d": "des_3CBC_pad", "c": "Teletrust encryption algorithm. EDE triple DES" }, +"1.3.36.3.1.3.2.1.1": { "d": "des_3CBC_ISOpad", "c": "Teletrust encryption algorithm. EDE triple DES" }, +"1.3.36.3.1.2": { "d": "idea", "c": "Teletrust encryption algorithm" }, +"1.3.36.3.1.2.1": { "d": "ideaECB", "c": "Teletrust encryption algorithm" }, +"1.3.36.3.1.2.1.1": { "d": "ideaECB_pad", "c": "Teletrust encryption algorithm" }, +"1.3.36.3.1.2.1.1.1": { "d": "ideaECB_ISOpad", "c": "Teletrust encryption algorithm" }, +"1.3.36.3.1.2.2": { "d": "ideaCBC", "c": "Teletrust encryption algorithm" }, +"1.3.36.3.1.2.2.1": { "d": "ideaCBC_pad", "c": "Teletrust encryption algorithm" }, +"1.3.36.3.1.2.2.1.1": { "d": "ideaCBC_ISOpad", "c": "Teletrust encryption algorithm" }, +"1.3.36.3.1.2.3": { "d": "ideaOFB", "c": "Teletrust encryption algorithm" }, +"1.3.36.3.1.2.4": { "d": "ideaCFB", "c": "Teletrust encryption algorithm" }, +"1.3.36.3.1.4": { "d": "rsaEncryption", "c": "Teletrust encryption algorithm" }, +"1.3.36.3.1.4.512.17": { "d": "rsaEncryptionWithlmod512expe17", "c": "Teletrust encryption algorithm" }, +"1.3.36.3.1.5": { "d": "bsi-1", "c": "Teletrust encryption algorithm" }, +"1.3.36.3.1.5.1": { "d": "bsi_1ECB_pad", "c": "Teletrust encryption algorithm" }, +"1.3.36.3.1.5.2": { "d": "bsi_1CBC_pad", "c": "Teletrust encryption algorithm" }, +"1.3.36.3.1.5.2.1": { "d": "bsi_1CBC_PEMpad", "c": "Teletrust encryption algorithm" }, +"1.3.36.3.2": { "d": "hashAlgorithm", "c": "Teletrust algorithm" }, +"1.3.36.3.2.1": { "d": "ripemd160", "c": "Teletrust hash algorithm" }, +"1.3.36.3.2.2": { "d": "ripemd128", "c": "Teletrust hash algorithm" }, +"1.3.36.3.2.3": { "d": "ripemd256", "c": "Teletrust hash algorithm" }, +"1.3.36.3.2.4": { "d": "mdc2singleLength", "c": "Teletrust hash algorithm" }, +"1.3.36.3.2.5": { "d": "mdc2doubleLength", "c": "Teletrust hash algorithm" }, +"1.3.36.3.3": { "d": "signatureAlgorithm", "c": "Teletrust algorithm" }, +"1.3.36.3.3.1": { "d": "rsaSignature", "c": "Teletrust signature algorithm" }, +"1.3.36.3.3.1.1": { "d": "rsaSignatureWithsha1", "c": "Teletrust signature algorithm" }, +"1.3.36.3.3.1.1.1024.11": { "d": "rsaSignatureWithsha1_l1024_l11", "c": "Teletrust signature algorithm" }, +"1.3.36.3.3.1.2": { "d": "rsaSignatureWithripemd160", "c": "Teletrust signature algorithm" }, +"1.3.36.3.3.1.2.1024.11": { "d": "rsaSignatureWithripemd160_l1024_l11", "c": "Teletrust signature algorithm" }, +"1.3.36.3.3.1.3": { "d": "rsaSignatureWithrimpemd128", "c": "Teletrust signature algorithm" }, +"1.3.36.3.3.1.4": { "d": "rsaSignatureWithrimpemd256", "c": "Teletrust signature algorithm" }, +"1.3.36.3.3.2": { "d": "ecsieSign", "c": "Teletrust signature algorithm" }, +"1.3.36.3.3.2.1": { "d": "ecsieSignWithsha1", "c": "Teletrust signature algorithm" }, +"1.3.36.3.3.2.2": { "d": "ecsieSignWithripemd160", "c": "Teletrust signature algorithm" }, +"1.3.36.3.3.2.3": { "d": "ecsieSignWithmd2", "c": "Teletrust signature algorithm" }, +"1.3.36.3.3.2.4": { "d": "ecsieSignWithmd5", "c": "Teletrust signature algorithm" }, +"1.3.36.3.3.2.8.1.1.1": { "d": "brainpoolP160r1", "c": "ECC Brainpool Standard Curves and Curve Generation" }, +"1.3.36.3.3.2.8.1.1.2": { "d": "brainpoolP160t1", "c": "ECC Brainpool Standard Curves and Curve Generation" }, +"1.3.36.3.3.2.8.1.1.3": { "d": "brainpoolP192r1", "c": "ECC Brainpool Standard Curves and Curve Generation" }, +"1.3.36.3.3.2.8.1.1.4": { "d": "brainpoolP192t1", "c": "ECC Brainpool Standard Curves and Curve Generation" }, +"1.3.36.3.3.2.8.1.1.5": { "d": "brainpoolP224r1", "c": "ECC Brainpool Standard Curves and Curve Generation" }, +"1.3.36.3.3.2.8.1.1.6": { "d": "brainpoolP224t1", "c": "ECC Brainpool Standard Curves and Curve Generation" }, +"1.3.36.3.3.2.8.1.1.7": { "d": "brainpoolP256r1", "c": "ECC Brainpool Standard Curves and Curve Generation" }, +"1.3.36.3.3.2.8.1.1.8": { "d": "brainpoolP256t1", "c": "ECC Brainpool Standard Curves and Curve Generation" }, +"1.3.36.3.3.2.8.1.1.9": { "d": "brainpoolP320r1", "c": "ECC Brainpool Standard Curves and Curve Generation" }, +"1.3.36.3.3.2.8.1.1.10": { "d": "brainpoolP320t1", "c": "ECC Brainpool Standard Curves and Curve Generation" }, +"1.3.36.3.3.2.8.1.1.11": { "d": "brainpoolP384r1", "c": "ECC Brainpool Standard Curves and Curve Generation" }, +"1.3.36.3.3.2.8.1.1.12": { "d": "brainpoolP384t1", "c": "ECC Brainpool Standard Curves and Curve Generation" }, +"1.3.36.3.3.2.8.1.1.13": { "d": "brainpoolP512r1", "c": "ECC Brainpool Standard Curves and Curve Generation" }, +"1.3.36.3.3.2.8.1.1.14": { "d": "brainpoolP512t1", "c": "ECC Brainpool Standard Curves and Curve Generation" }, +"1.3.36.3.4": { "d": "signatureScheme", "c": "Teletrust algorithm" }, +"1.3.36.3.4.1": { "d": "sigS_ISO9796-1", "c": "Teletrust signature scheme" }, +"1.3.36.3.4.2": { "d": "sigS_ISO9796-2", "c": "Teletrust signature scheme" }, +"1.3.36.3.4.2.1": { "d": "sigS_ISO9796-2Withred", "c": "Teletrust signature scheme. Unsure what this is supposed to be" }, +"1.3.36.3.4.2.2": { "d": "sigS_ISO9796-2Withrsa", "c": "Teletrust signature scheme. Unsure what this is supposed to be" }, +"1.3.36.3.4.2.3": { "d": "sigS_ISO9796-2Withrnd", "c": "Teletrust signature scheme. 9796-2 with random number in padding field" }, +"1.3.36.4": { "d": "attribute", "c": "Teletrust attribute" }, +"1.3.36.5": { "d": "policy", "c": "Teletrust policy" }, +"1.3.36.6": { "d": "api", "c": "Teletrust API" }, +"1.3.36.6.1": { "d": "manufacturer-specific_api", "c": "Teletrust API" }, +"1.3.36.6.1.1": { "d": "utimaco-api", "c": "Teletrust API" }, +"1.3.36.6.2": { "d": "functionality-specific_api", "c": "Teletrust API" }, +"1.3.36.7": { "d": "keymgmnt", "c": "Teletrust key management" }, +"1.3.36.7.1": { "d": "keyagree", "c": "Teletrust key management" }, +"1.3.36.7.1.1": { "d": "bsiPKE", "c": "Teletrust key management" }, +"1.3.36.7.2": { "d": "keytrans", "c": "Teletrust key management" }, +"1.3.36.7.2.1": { "d": "encISO9796-2Withrsa", "c": "Teletrust key management. 9796-2 with key stored in hash field" }, +"1.3.36.8.1.1": { "d": "Teletrust SigGConform policyIdentifier", "c": "Teletrust policy" }, +"1.3.36.8.2.1": { "d": "directoryService", "c": "Teletrust extended key usage" }, +"1.3.36.8.3.1": { "d": "dateOfCertGen", "c": "Teletrust attribute" }, +"1.3.36.8.3.2": { "d": "procuration", "c": "Teletrust attribute" }, +"1.3.36.8.3.3": { "d": "admission", "c": "Teletrust attribute" }, +"1.3.36.8.3.4": { "d": "monetaryLimit", "c": "Teletrust attribute" }, +"1.3.36.8.3.5": { "d": "declarationOfMajority", "c": "Teletrust attribute" }, +"1.3.36.8.3.6": { "d": "integratedCircuitCardSerialNumber", "c": "Teletrust attribute" }, +"1.3.36.8.3.7": { "d": "pKReference", "c": "Teletrust attribute" }, +"1.3.36.8.3.8": { "d": "restriction", "c": "Teletrust attribute" }, +"1.3.36.8.3.9": { "d": "retrieveIfAllowed", "c": "Teletrust attribute" }, +"1.3.36.8.3.10": { "d": "requestedCertificate", "c": "Teletrust attribute" }, +"1.3.36.8.3.11": { "d": "namingAuthorities", "c": "Teletrust attribute" }, +"1.3.36.8.3.11.1": { "d": "rechtWirtschaftSteuern", "c": "Teletrust naming authorities" }, +"1.3.36.8.3.11.1.1": { "d": "rechtsanwaeltin", "c": "Teletrust ProfessionInfo" }, +"1.3.36.8.3.11.1.2": { "d": "rechtsanwalt", "c": "Teletrust ProfessionInfo" }, +"1.3.36.8.3.11.1.3": { "d": "rechtsBeistand", "c": "Teletrust ProfessionInfo" }, +"1.3.36.8.3.11.1.4": { "d": "steuerBeraterin", "c": "Teletrust ProfessionInfo" }, +"1.3.36.8.3.11.1.5": { "d": "steuerBerater", "c": "Teletrust ProfessionInfo" }, +"1.3.36.8.3.11.1.6": { "d": "steuerBevollmaechtigte", "c": "Teletrust ProfessionInfo" }, +"1.3.36.8.3.11.1.7": { "d": "steuerBevollmaechtigter", "c": "Teletrust ProfessionInfo" }, +"1.3.36.8.3.11.1.8": { "d": "notarin", "c": "Teletrust ProfessionInfo" }, +"1.3.36.8.3.11.1.9": { "d": "notar", "c": "Teletrust ProfessionInfo" }, +"1.3.36.8.3.11.1.10": { "d": "notarVertreterin", "c": "Teletrust ProfessionInfo" }, +"1.3.36.8.3.11.1.11": { "d": "notarVertreter", "c": "Teletrust ProfessionInfo" }, +"1.3.36.8.3.11.1.12": { "d": "notariatsVerwalterin", "c": "Teletrust ProfessionInfo" }, +"1.3.36.8.3.11.1.13": { "d": "notariatsVerwalter", "c": "Teletrust ProfessionInfo" }, +"1.3.36.8.3.11.1.14": { "d": "wirtschaftsPrueferin", "c": "Teletrust ProfessionInfo" }, +"1.3.36.8.3.11.1.15": { "d": "wirtschaftsPruefer", "c": "Teletrust ProfessionInfo" }, +"1.3.36.8.3.11.1.16": { "d": "vereidigteBuchprueferin", "c": "Teletrust ProfessionInfo" }, +"1.3.36.8.3.11.1.17": { "d": "vereidigterBuchpruefer", "c": "Teletrust ProfessionInfo" }, +"1.3.36.8.3.11.1.18": { "d": "patentAnwaeltin", "c": "Teletrust ProfessionInfo" }, +"1.3.36.8.3.11.1.19": { "d": "patentAnwalt", "c": "Teletrust ProfessionInfo" }, +"1.3.36.8.3.12": { "d": "certInDirSince", "c": "Teletrust OCSP attribute (obsolete)", "w": true }, +"1.3.36.8.3.13": { "d": "certHash", "c": "Teletrust OCSP attribute" }, +"1.3.36.8.3.14": { "d": "nameAtBirth", "c": "Teletrust attribute" }, +"1.3.36.8.3.15": { "d": "additionalInformation", "c": "Teletrust attribute" }, +"1.3.36.8.4.1": { "d": "personalData", "c": "Teletrust OtherName attribute" }, +"1.3.36.8.4.8": { "d": "restriction", "c": "Teletrust attribute certificate attribute" }, +"1.3.36.8.5.1.1.1": { "d": "rsaIndicateSHA1", "c": "Teletrust signature algorithm" }, +"1.3.36.8.5.1.1.2": { "d": "rsaIndicateRIPEMD160", "c": "Teletrust signature algorithm" }, +"1.3.36.8.5.1.1.3": { "d": "rsaWithSHA1", "c": "Teletrust signature algorithm" }, +"1.3.36.8.5.1.1.4": { "d": "rsaWithRIPEMD160", "c": "Teletrust signature algorithm" }, +"1.3.36.8.5.1.2.1": { "d": "dsaExtended", "c": "Teletrust signature algorithm" }, +"1.3.36.8.5.1.2.2": { "d": "dsaWithRIPEMD160", "c": "Teletrust signature algorithm" }, +"1.3.36.8.6.1": { "d": "cert", "c": "Teletrust signature attributes" }, +"1.3.36.8.6.2": { "d": "certRef", "c": "Teletrust signature attributes" }, +"1.3.36.8.6.3": { "d": "attrCert", "c": "Teletrust signature attributes" }, +"1.3.36.8.6.4": { "d": "attrRef", "c": "Teletrust signature attributes" }, +"1.3.36.8.6.5": { "d": "fileName", "c": "Teletrust signature attributes" }, +"1.3.36.8.6.6": { "d": "storageTime", "c": "Teletrust signature attributes" }, +"1.3.36.8.6.7": { "d": "fileSize", "c": "Teletrust signature attributes" }, +"1.3.36.8.6.8": { "d": "location", "c": "Teletrust signature attributes" }, +"1.3.36.8.6.9": { "d": "sigNumber", "c": "Teletrust signature attributes" }, +"1.3.36.8.6.10": { "d": "autoGen", "c": "Teletrust signature attributes" }, +"1.3.36.8.7.1.1": { "d": "ptAdobeILL", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.2": { "d": "ptAmiPro", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.3": { "d": "ptAutoCAD", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.4": { "d": "ptBinary", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.5": { "d": "ptBMP", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.6": { "d": "ptCGM", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.7": { "d": "ptCorelCRT", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.8": { "d": "ptCorelDRW", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.9": { "d": "ptCorelEXC", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.10": { "d": "ptCorelPHT", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.11": { "d": "ptDraw", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.12": { "d": "ptDVI", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.13": { "d": "ptEPS", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.14": { "d": "ptExcel", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.15": { "d": "ptGEM", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.16": { "d": "ptGIF", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.17": { "d": "ptHPGL", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.18": { "d": "ptJPEG", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.19": { "d": "ptKodak", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.20": { "d": "ptLaTeX", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.21": { "d": "ptLotus", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.22": { "d": "ptLotusPIC", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.23": { "d": "ptMacPICT", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.24": { "d": "ptMacWord", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.25": { "d": "ptMSWfD", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.26": { "d": "ptMSWord", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.27": { "d": "ptMSWord2", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.28": { "d": "ptMSWord6", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.29": { "d": "ptMSWord8", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.30": { "d": "ptPDF", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.31": { "d": "ptPIF", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.32": { "d": "ptPostscript", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.33": { "d": "ptRTF", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.34": { "d": "ptSCITEX", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.35": { "d": "ptTAR", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.36": { "d": "ptTarga", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.37": { "d": "ptTeX", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.38": { "d": "ptText", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.39": { "d": "ptTIFF", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.40": { "d": "ptTIFF-FC", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.41": { "d": "ptUID", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.42": { "d": "ptUUEncode", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.43": { "d": "ptWMF", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.44": { "d": "ptWordPerfect", "c": "Teletrust presentation types" }, +"1.3.36.8.7.1.45": { "d": "ptWPGrph", "c": "Teletrust presentation types" }, +"1.3.101.1.4": { "d": "thawte-ce", "c": "Thawte" }, +"1.3.101.1.4.1": { "d": "strongExtranet", "c": "Thawte certificate extension" }, +"1.3.101.110": { "d": "curveX25519", "c": "ECDH 25519 key agreement algorithm" }, +"1.3.101.111": { "d": "curveX448", "c": "ECDH 448 key agreement algorithm" }, +"1.3.101.112": { "d": "curveEd25519", "c": "EdDSA 25519 signature algorithm" }, +"1.3.101.113": { "d": "curveEd448", "c": "EdDSA 448 signature algorithm" }, +"1.3.101.114": { "d": "curveEd25519ph", "c": "EdDSA 25519 pre-hash signature algorithm" }, +"1.3.101.115": { "d": "curveEd448ph", "c": "EdDSA 448 pre-hash signature algorithm" }, +"1.3.132.0.1": { "d": "sect163k1", "c": "SECG (Certicom) named elliptic curve" }, +"1.3.132.0.2": { "d": "sect163r1", "c": "SECG (Certicom) named elliptic curve" }, +"1.3.132.0.3": { "d": "sect239k1", "c": "SECG (Certicom) named elliptic curve" }, +"1.3.132.0.4": { "d": "sect113r1", "c": "SECG (Certicom) named elliptic curve" }, +"1.3.132.0.5": { "d": "sect113r2", "c": "SECG (Certicom) named elliptic curve" }, +"1.3.132.0.6": { "d": "secp112r1", "c": "SECG (Certicom) named elliptic curve" }, +"1.3.132.0.7": { "d": "secp112r2", "c": "SECG (Certicom) named elliptic curve" }, +"1.3.132.0.8": { "d": "secp160r1", "c": "SECG (Certicom) named elliptic curve" }, +"1.3.132.0.9": { "d": "secp160k1", "c": "SECG (Certicom) named elliptic curve" }, +"1.3.132.0.10": { "d": "secp256k1", "c": "SECG (Certicom) named elliptic curve" }, +"1.3.132.0.15": { "d": "sect163r2", "c": "SECG (Certicom) named elliptic curve" }, +"1.3.132.0.16": { "d": "sect283k1", "c": "SECG (Certicom) named elliptic curve" }, +"1.3.132.0.17": { "d": "sect283r1", "c": "SECG (Certicom) named elliptic curve" }, +"1.3.132.0.22": { "d": "sect131r1", "c": "SECG (Certicom) named elliptic curve" }, +"1.3.132.0.23": { "d": "sect131r2", "c": "SECG (Certicom) named elliptic curve" }, +"1.3.132.0.24": { "d": "sect193r1", "c": "SECG (Certicom) named elliptic curve" }, +"1.3.132.0.25": { "d": "sect193r2", "c": "SECG (Certicom) named elliptic curve" }, +"1.3.132.0.26": { "d": "sect233k1", "c": "SECG (Certicom) named elliptic curve" }, +"1.3.132.0.27": { "d": "sect233r1", "c": "SECG (Certicom) named elliptic curve" }, +"1.3.132.0.28": { "d": "secp128r1", "c": "SECG (Certicom) named elliptic curve" }, +"1.3.132.0.29": { "d": "secp128r2", "c": "SECG (Certicom) named elliptic curve" }, +"1.3.132.0.30": { "d": "secp160r2", "c": "SECG (Certicom) named elliptic curve" }, +"1.3.132.0.31": { "d": "secp192k1", "c": "SECG (Certicom) named elliptic curve" }, +"1.3.132.0.32": { "d": "secp224k1", "c": "SECG (Certicom) named elliptic curve" }, +"1.3.132.0.33": { "d": "secp224r1", "c": "SECG (Certicom) named elliptic curve" }, +"1.3.132.0.34": { "d": "secp384r1", "c": "SECG (Certicom) named elliptic curve" }, +"1.3.132.0.35": { "d": "secp521r1", "c": "SECG (Certicom) named elliptic curve" }, +"1.3.132.0.36": { "d": "sect409k1", "c": "SECG (Certicom) named elliptic curve" }, +"1.3.132.0.37": { "d": "sect409r1", "c": "SECG (Certicom) named elliptic curve" }, +"1.3.132.0.38": { "d": "sect571k1", "c": "SECG (Certicom) named elliptic curve" }, +"1.3.132.0.39": { "d": "sect571r1", "c": "SECG (Certicom) named elliptic curve" }, +"1.3.132.1.11.1": { "d": "ecdhX963KDF-SHA256", "c": "SECG (Certicom) elliptic curve key agreement" }, +"1.3.132.1.11.2": { "d": "ecdhX963KDF-SHA384", "c": "SECG (Certicom) elliptic curve key agreement" }, +"1.3.132.1.11.3": { "d": "ecdhX963KDF-SHA512", "c": "SECG (Certicom) elliptic curve key agreement" }, +"1.3.133.16.840.9.84": { "d": "x984", "c": "X9.84" }, +"1.3.133.16.840.9.84.0": { "d": "x984Module", "c": "X9.84" }, +"1.3.133.16.840.9.84.0.1": { "d": "x984Biometrics", "c": "X9.84 Module" }, +"1.3.133.16.840.9.84.0.2": { "d": "x984CMS", "c": "X9.84 Module" }, +"1.3.133.16.840.9.84.0.3": { "d": "x984Identifiers", "c": "X9.84 Module" }, +"1.3.133.16.840.9.84.1": { "d": "x984Biometric", "c": "X9.84" }, +"1.3.133.16.840.9.84.1.0": { "d": "biometricUnknownType", "c": "X9.84 Biometric" }, +"1.3.133.16.840.9.84.1.1": { "d": "biometricBodyOdor", "c": "X9.84 Biometric" }, +"1.3.133.16.840.9.84.1.2": { "d": "biometricDNA", "c": "X9.84 Biometric" }, +"1.3.133.16.840.9.84.1.3": { "d": "biometricEarShape", "c": "X9.84 Biometric" }, +"1.3.133.16.840.9.84.1.4": { "d": "biometricFacialFeatures", "c": "X9.84 Biometric" }, +"1.3.133.16.840.9.84.1.5": { "d": "biometricFingerImage", "c": "X9.84 Biometric" }, +"1.3.133.16.840.9.84.1.6": { "d": "biometricFingerGeometry", "c": "X9.84 Biometric" }, +"1.3.133.16.840.9.84.1.7": { "d": "biometricHandGeometry", "c": "X9.84 Biometric" }, +"1.3.133.16.840.9.84.1.8": { "d": "biometricIrisFeatures", "c": "X9.84 Biometric" }, +"1.3.133.16.840.9.84.1.9": { "d": "biometricKeystrokeDynamics", "c": "X9.84 Biometric" }, +"1.3.133.16.840.9.84.1.10": { "d": "biometricPalm", "c": "X9.84 Biometric" }, +"1.3.133.16.840.9.84.1.11": { "d": "biometricRetina", "c": "X9.84 Biometric" }, +"1.3.133.16.840.9.84.1.12": { "d": "biometricSignature", "c": "X9.84 Biometric" }, +"1.3.133.16.840.9.84.1.13": { "d": "biometricSpeechPattern", "c": "X9.84 Biometric" }, +"1.3.133.16.840.9.84.1.14": { "d": "biometricThermalImage", "c": "X9.84 Biometric" }, +"1.3.133.16.840.9.84.1.15": { "d": "biometricVeinPattern", "c": "X9.84 Biometric" }, +"1.3.133.16.840.9.84.1.16": { "d": "biometricThermalFaceImage", "c": "X9.84 Biometric" }, +"1.3.133.16.840.9.84.1.17": { "d": "biometricThermalHandImage", "c": "X9.84 Biometric" }, +"1.3.133.16.840.9.84.1.18": { "d": "biometricLipMovement", "c": "X9.84 Biometric" }, +"1.3.133.16.840.9.84.1.19": { "d": "biometricGait", "c": "X9.84 Biometric" }, +"1.3.133.16.840.9.84.3": { "d": "x984MatchingMethod", "c": "X9.84" }, +"1.3.133.16.840.9.84.4": { "d": "x984FormatOwner", "c": "X9.84" }, +"1.3.133.16.840.9.84.4.0": { "d": "x984CbeffOwner", "c": "X9.84 Format Owner" }, +"1.3.133.16.840.9.84.4.1": { "d": "x984IbiaOwner", "c": "X9.84 Format Owner" }, +"1.3.133.16.840.9.84.4.1.1": { "d": "ibiaOwnerSAFLINK", "c": "X9.84 IBIA Format Owner" }, +"1.3.133.16.840.9.84.4.1.2": { "d": "ibiaOwnerBioscrypt", "c": "X9.84 IBIA Format Owner" }, +"1.3.133.16.840.9.84.4.1.3": { "d": "ibiaOwnerVisionics", "c": "X9.84 IBIA Format Owner" }, +"1.3.133.16.840.9.84.4.1.4": { "d": "ibiaOwnerInfineonTechnologiesAG", "c": "X9.84 IBIA Format Owner" }, +"1.3.133.16.840.9.84.4.1.5": { "d": "ibiaOwnerIridianTechnologies", "c": "X9.84 IBIA Format Owner" }, +"1.3.133.16.840.9.84.4.1.6": { "d": "ibiaOwnerVeridicom", "c": "X9.84 IBIA Format Owner" }, +"1.3.133.16.840.9.84.4.1.7": { "d": "ibiaOwnerCyberSIGN", "c": "X9.84 IBIA Format Owner" }, +"1.3.133.16.840.9.84.4.1.8": { "d": "ibiaOwnereCryp", "c": "X9.84 IBIA Format Owner" }, +"1.3.133.16.840.9.84.4.1.9": { "d": "ibiaOwnerFingerprintCardsAB", "c": "X9.84 IBIA Format Owner" }, +"1.3.133.16.840.9.84.4.1.10": { "d": "ibiaOwnerSecuGen", "c": "X9.84 IBIA Format Owner" }, +"1.3.133.16.840.9.84.4.1.11": { "d": "ibiaOwnerPreciseBiometric", "c": "X9.84 IBIA Format Owner" }, +"1.3.133.16.840.9.84.4.1.12": { "d": "ibiaOwnerIdentix", "c": "X9.84 IBIA Format Owner" }, +"1.3.133.16.840.9.84.4.1.13": { "d": "ibiaOwnerDERMALOG", "c": "X9.84 IBIA Format Owner" }, +"1.3.133.16.840.9.84.4.1.14": { "d": "ibiaOwnerLOGICO", "c": "X9.84 IBIA Format Owner" }, +"1.3.133.16.840.9.84.4.1.15": { "d": "ibiaOwnerNIST", "c": "X9.84 IBIA Format Owner" }, +"1.3.133.16.840.9.84.4.1.16": { "d": "ibiaOwnerA3Vision", "c": "X9.84 IBIA Format Owner" }, +"1.3.133.16.840.9.84.4.1.17": { "d": "ibiaOwnerNEC", "c": "X9.84 IBIA Format Owner" }, +"1.3.133.16.840.9.84.4.1.18": { "d": "ibiaOwnerSTMicroelectronics", "c": "X9.84 IBIA Format Owner" }, +"2.5.4.0": { "d": "objectClass", "c": "X.520 DN component" }, +"2.5.4.1": { "d": "aliasedEntryName", "c": "X.520 DN component" }, +"2.5.4.2": { "d": "knowledgeInformation", "c": "X.520 DN component" }, +"2.5.4.3": { "d": "commonName", "c": "X.520 DN component" }, +"2.5.4.4": { "d": "surname", "c": "X.520 DN component" }, +"2.5.4.5": { "d": "serialNumber", "c": "X.520 DN component" }, +"2.5.4.6": { "d": "countryName", "c": "X.520 DN component" }, +"2.5.4.7": { "d": "localityName", "c": "X.520 DN component" }, +"2.5.4.7.1": { "d": "collectiveLocalityName", "c": "X.520 DN component" }, +"2.5.4.8": { "d": "stateOrProvinceName", "c": "X.520 DN component" }, +"2.5.4.8.1": { "d": "collectiveStateOrProvinceName", "c": "X.520 DN component" }, +"2.5.4.9": { "d": "streetAddress", "c": "X.520 DN component" }, +"2.5.4.9.1": { "d": "collectiveStreetAddress", "c": "X.520 DN component" }, +"2.5.4.10": { "d": "organizationName", "c": "X.520 DN component" }, +"2.5.4.10.1": { "d": "collectiveOrganizationName", "c": "X.520 DN component" }, +"2.5.4.11": { "d": "organizationalUnitName", "c": "X.520 DN component" }, +"2.5.4.11.1": { "d": "collectiveOrganizationalUnitName", "c": "X.520 DN component" }, +"2.5.4.12": { "d": "title", "c": "X.520 DN component" }, +"2.5.4.13": { "d": "description", "c": "X.520 DN component" }, +"2.5.4.14": { "d": "searchGuide", "c": "X.520 DN component" }, +"2.5.4.15": { "d": "businessCategory", "c": "X.520 DN component" }, +"2.5.4.16": { "d": "postalAddress", "c": "X.520 DN component" }, +"2.5.4.16.1": { "d": "collectivePostalAddress", "c": "X.520 DN component" }, +"2.5.4.17": { "d": "postalCode", "c": "X.520 DN component" }, +"2.5.4.17.1": { "d": "collectivePostalCode", "c": "X.520 DN component" }, +"2.5.4.18": { "d": "postOfficeBox", "c": "X.520 DN component" }, +"2.5.4.18.1": { "d": "collectivePostOfficeBox", "c": "X.520 DN component" }, +"2.5.4.19": { "d": "physicalDeliveryOfficeName", "c": "X.520 DN component" }, +"2.5.4.19.1": { "d": "collectivePhysicalDeliveryOfficeName", "c": "X.520 DN component" }, +"2.5.4.20": { "d": "telephoneNumber", "c": "X.520 DN component" }, +"2.5.4.20.1": { "d": "collectiveTelephoneNumber", "c": "X.520 DN component" }, +"2.5.4.21": { "d": "telexNumber", "c": "X.520 DN component" }, +"2.5.4.21.1": { "d": "collectiveTelexNumber", "c": "X.520 DN component" }, +"2.5.4.22": { "d": "teletexTerminalIdentifier", "c": "X.520 DN component" }, +"2.5.4.22.1": { "d": "collectiveTeletexTerminalIdentifier", "c": "X.520 DN component" }, +"2.5.4.23": { "d": "facsimileTelephoneNumber", "c": "X.520 DN component" }, +"2.5.4.23.1": { "d": "collectiveFacsimileTelephoneNumber", "c": "X.520 DN component" }, +"2.5.4.24": { "d": "x121Address", "c": "X.520 DN component" }, +"2.5.4.25": { "d": "internationalISDNNumber", "c": "X.520 DN component" }, +"2.5.4.25.1": { "d": "collectiveInternationalISDNNumber", "c": "X.520 DN component" }, +"2.5.4.26": { "d": "registeredAddress", "c": "X.520 DN component" }, +"2.5.4.27": { "d": "destinationIndicator", "c": "X.520 DN component" }, +"2.5.4.28": { "d": "preferredDeliveryMehtod", "c": "X.520 DN component" }, +"2.5.4.29": { "d": "presentationAddress", "c": "X.520 DN component" }, +"2.5.4.30": { "d": "supportedApplicationContext", "c": "X.520 DN component" }, +"2.5.4.31": { "d": "member", "c": "X.520 DN component" }, +"2.5.4.32": { "d": "owner", "c": "X.520 DN component" }, +"2.5.4.33": { "d": "roleOccupant", "c": "X.520 DN component" }, +"2.5.4.34": { "d": "seeAlso", "c": "X.520 DN component" }, +"2.5.4.35": { "d": "userPassword", "c": "X.520 DN component" }, +"2.5.4.36": { "d": "userCertificate", "c": "X.520 DN component" }, +"2.5.4.37": { "d": "caCertificate", "c": "X.520 DN component" }, +"2.5.4.38": { "d": "authorityRevocationList", "c": "X.520 DN component" }, +"2.5.4.39": { "d": "certificateRevocationList", "c": "X.520 DN component" }, +"2.5.4.40": { "d": "crossCertificatePair", "c": "X.520 DN component" }, +"2.5.4.41": { "d": "name", "c": "X.520 DN component" }, +"2.5.4.42": { "d": "givenName", "c": "X.520 DN component" }, +"2.5.4.43": { "d": "initials", "c": "X.520 DN component" }, +"2.5.4.44": { "d": "generationQualifier", "c": "X.520 DN component" }, +"2.5.4.45": { "d": "uniqueIdentifier", "c": "X.520 DN component" }, +"2.5.4.46": { "d": "dnQualifier", "c": "X.520 DN component" }, +"2.5.4.47": { "d": "enhancedSearchGuide", "c": "X.520 DN component" }, +"2.5.4.48": { "d": "protocolInformation", "c": "X.520 DN component" }, +"2.5.4.49": { "d": "distinguishedName", "c": "X.520 DN component" }, +"2.5.4.50": { "d": "uniqueMember", "c": "X.520 DN component" }, +"2.5.4.51": { "d": "houseIdentifier", "c": "X.520 DN component" }, +"2.5.4.52": { "d": "supportedAlgorithms", "c": "X.520 DN component" }, +"2.5.4.53": { "d": "deltaRevocationList", "c": "X.520 DN component" }, +"2.5.4.54": { "d": "dmdName", "c": "X.520 DN component" }, +"2.5.4.55": { "d": "clearance", "c": "X.520 DN component" }, +"2.5.4.56": { "d": "defaultDirQop", "c": "X.520 DN component" }, +"2.5.4.57": { "d": "attributeIntegrityInfo", "c": "X.520 DN component" }, +"2.5.4.58": { "d": "attributeCertificate", "c": "X.520 DN component" }, +"2.5.4.59": { "d": "attributeCertificateRevocationList", "c": "X.520 DN component" }, +"2.5.4.60": { "d": "confKeyInfo", "c": "X.520 DN component" }, +"2.5.4.61": { "d": "aACertificate", "c": "X.520 DN component" }, +"2.5.4.62": { "d": "attributeDescriptorCertificate", "c": "X.520 DN component" }, +"2.5.4.63": { "d": "attributeAuthorityRevocationList", "c": "X.520 DN component" }, +"2.5.4.64": { "d": "familyInformation", "c": "X.520 DN component" }, +"2.5.4.65": { "d": "pseudonym", "c": "X.520 DN component" }, +"2.5.4.66": { "d": "communicationsService", "c": "X.520 DN component" }, +"2.5.4.67": { "d": "communicationsNetwork", "c": "X.520 DN component" }, +"2.5.4.68": { "d": "certificationPracticeStmt", "c": "X.520 DN component" }, +"2.5.4.69": { "d": "certificatePolicy", "c": "X.520 DN component" }, +"2.5.4.70": { "d": "pkiPath", "c": "X.520 DN component" }, +"2.5.4.71": { "d": "privPolicy", "c": "X.520 DN component" }, +"2.5.4.72": { "d": "role", "c": "X.520 DN component" }, +"2.5.4.73": { "d": "delegationPath", "c": "X.520 DN component" }, +"2.5.4.74": { "d": "protPrivPolicy", "c": "X.520 DN component" }, +"2.5.4.75": { "d": "xMLPrivilegeInfo", "c": "X.520 DN component" }, +"2.5.4.76": { "d": "xmlPrivPolicy", "c": "X.520 DN component" }, +"2.5.4.82": { "d": "permission", "c": "X.520 DN component" }, +"2.5.6.0": { "d": "top", "c": "X.520 objectClass" }, +"2.5.6.1": { "d": "alias", "c": "X.520 objectClass" }, +"2.5.6.2": { "d": "country", "c": "X.520 objectClass" }, +"2.5.6.3": { "d": "locality", "c": "X.520 objectClass" }, +"2.5.6.4": { "d": "organization", "c": "X.520 objectClass" }, +"2.5.6.5": { "d": "organizationalUnit", "c": "X.520 objectClass" }, +"2.5.6.6": { "d": "person", "c": "X.520 objectClass" }, +"2.5.6.7": { "d": "organizationalPerson", "c": "X.520 objectClass" }, +"2.5.6.8": { "d": "organizationalRole", "c": "X.520 objectClass" }, +"2.5.6.9": { "d": "groupOfNames", "c": "X.520 objectClass" }, +"2.5.6.10": { "d": "residentialPerson", "c": "X.520 objectClass" }, +"2.5.6.11": { "d": "applicationProcess", "c": "X.520 objectClass" }, +"2.5.6.12": { "d": "applicationEntity", "c": "X.520 objectClass" }, +"2.5.6.13": { "d": "dSA", "c": "X.520 objectClass" }, +"2.5.6.14": { "d": "device", "c": "X.520 objectClass" }, +"2.5.6.15": { "d": "strongAuthenticationUser", "c": "X.520 objectClass" }, +"2.5.6.16": { "d": "certificateAuthority", "c": "X.520 objectClass" }, +"2.5.6.17": { "d": "groupOfUniqueNames", "c": "X.520 objectClass" }, +"2.5.6.21": { "d": "pkiUser", "c": "X.520 objectClass" }, +"2.5.6.22": { "d": "pkiCA", "c": "X.520 objectClass" }, +"2.5.8.1.1": { "d": "rsa", "c": "X.500 algorithms. Ambiguous, since no padding rules specified", "w": true }, +"2.5.29.1": { "d": "authorityKeyIdentifier", "c": "X.509 extension. Deprecated, use 2 5 29 35 instead", "w": true }, +"2.5.29.2": { "d": "keyAttributes", "c": "X.509 extension. Obsolete, use keyUsage/extKeyUsage instead", "w": true }, +"2.5.29.3": { "d": "certificatePolicies", "c": "X.509 extension. Deprecated, use 2 5 29 32 instead", "w": true }, +"2.5.29.4": { "d": "keyUsageRestriction", "c": "X.509 extension. Obsolete, use keyUsage/extKeyUsage instead", "w": true }, +"2.5.29.5": { "d": "policyMapping", "c": "X.509 extension. Deprecated, use 2 5 29 33 instead", "w": true }, +"2.5.29.6": { "d": "subtreesConstraint", "c": "X.509 extension. Obsolete, use nameConstraints instead", "w": true }, +"2.5.29.7": { "d": "subjectAltName", "c": "X.509 extension. Deprecated, use 2 5 29 17 instead", "w": true }, +"2.5.29.8": { "d": "issuerAltName", "c": "X.509 extension. Deprecated, use 2 5 29 18 instead", "w": true }, +"2.5.29.9": { "d": "subjectDirectoryAttributes", "c": "X.509 extension" }, +"2.5.29.10": { "d": "basicConstraints", "c": "X.509 extension. Deprecated, use 2 5 29 19 instead", "w": true }, +"2.5.29.11": { "d": "nameConstraints", "c": "X.509 extension. Deprecated, use 2 5 29 30 instead", "w": true }, +"2.5.29.12": { "d": "policyConstraints", "c": "X.509 extension. Deprecated, use 2 5 29 36 instead", "w": true }, +"2.5.29.13": { "d": "basicConstraints", "c": "X.509 extension. Deprecated, use 2 5 29 19 instead", "w": true }, +"2.5.29.14": { "d": "subjectKeyIdentifier", "c": "X.509 extension" }, +"2.5.29.15": { "d": "keyUsage", "c": "X.509 extension" }, +"2.5.29.16": { "d": "privateKeyUsagePeriod", "c": "X.509 extension" }, +"2.5.29.17": { "d": "subjectAltName", "c": "X.509 extension" }, +"2.5.29.18": { "d": "issuerAltName", "c": "X.509 extension" }, +"2.5.29.19": { "d": "basicConstraints", "c": "X.509 extension" }, +"2.5.29.20": { "d": "cRLNumber", "c": "X.509 extension" }, +"2.5.29.21": { "d": "cRLReason", "c": "X.509 extension" }, +"2.5.29.22": { "d": "expirationDate", "c": "X.509 extension. Deprecated, alternative OID uncertain", "w": true }, +"2.5.29.23": { "d": "instructionCode", "c": "X.509 extension" }, +"2.5.29.24": { "d": "invalidityDate", "c": "X.509 extension" }, +"2.5.29.25": { "d": "cRLDistributionPoints", "c": "X.509 extension. Deprecated, use 2 5 29 31 instead", "w": true }, +"2.5.29.26": { "d": "issuingDistributionPoint", "c": "X.509 extension. Deprecated, use 2 5 29 28 instead", "w": true }, +"2.5.29.27": { "d": "deltaCRLIndicator", "c": "X.509 extension" }, +"2.5.29.28": { "d": "issuingDistributionPoint", "c": "X.509 extension" }, +"2.5.29.29": { "d": "certificateIssuer", "c": "X.509 extension" }, +"2.5.29.30": { "d": "nameConstraints", "c": "X.509 extension" }, +"2.5.29.31": { "d": "cRLDistributionPoints", "c": "X.509 extension" }, +"2.5.29.32": { "d": "certificatePolicies", "c": "X.509 extension" }, +"2.5.29.32.0": { "d": "anyPolicy", "c": "X.509 certificate policy" }, +"2.5.29.33": { "d": "policyMappings", "c": "X.509 extension" }, +"2.5.29.34": { "d": "policyConstraints", "c": "X.509 extension. Deprecated, use 2 5 29 36 instead", "w": true }, +"2.5.29.35": { "d": "authorityKeyIdentifier", "c": "X.509 extension" }, +"2.5.29.36": { "d": "policyConstraints", "c": "X.509 extension" }, +"2.5.29.37": { "d": "extKeyUsage", "c": "X.509 extension" }, +"2.5.29.37.0": { "d": "anyExtendedKeyUsage", "c": "X.509 extended key usage" }, +"2.5.29.38": { "d": "authorityAttributeIdentifier", "c": "X.509 extension" }, +"2.5.29.39": { "d": "roleSpecCertIdentifier", "c": "X.509 extension" }, +"2.5.29.40": { "d": "cRLStreamIdentifier", "c": "X.509 extension" }, +"2.5.29.41": { "d": "basicAttConstraints", "c": "X.509 extension" }, +"2.5.29.42": { "d": "delegatedNameConstraints", "c": "X.509 extension" }, +"2.5.29.43": { "d": "timeSpecification", "c": "X.509 extension" }, +"2.5.29.44": { "d": "cRLScope", "c": "X.509 extension" }, +"2.5.29.45": { "d": "statusReferrals", "c": "X.509 extension" }, +"2.5.29.46": { "d": "freshestCRL", "c": "X.509 extension" }, +"2.5.29.47": { "d": "orderedList", "c": "X.509 extension" }, +"2.5.29.48": { "d": "attributeDescriptor", "c": "X.509 extension" }, +"2.5.29.49": { "d": "userNotice", "c": "X.509 extension" }, +"2.5.29.50": { "d": "sOAIdentifier", "c": "X.509 extension" }, +"2.5.29.51": { "d": "baseUpdateTime", "c": "X.509 extension" }, +"2.5.29.52": { "d": "acceptableCertPolicies", "c": "X.509 extension" }, +"2.5.29.53": { "d": "deltaInfo", "c": "X.509 extension" }, +"2.5.29.54": { "d": "inhibitAnyPolicy", "c": "X.509 extension" }, +"2.5.29.55": { "d": "targetInformation", "c": "X.509 extension" }, +"2.5.29.56": { "d": "noRevAvail", "c": "X.509 extension" }, +"2.5.29.57": { "d": "acceptablePrivilegePolicies", "c": "X.509 extension" }, +"2.5.29.58": { "d": "toBeRevoked", "c": "X.509 extension" }, +"2.5.29.59": { "d": "revokedGroups", "c": "X.509 extension" }, +"2.5.29.60": { "d": "expiredCertsOnCRL", "c": "X.509 extension" }, +"2.5.29.61": { "d": "indirectIssuer", "c": "X.509 extension" }, +"2.5.29.62": { "d": "noAssertion", "c": "X.509 extension" }, +"2.5.29.63": { "d": "aAissuingDistributionPoint", "c": "X.509 extension" }, +"2.5.29.64": { "d": "issuedOnBehalfOf", "c": "X.509 extension" }, +"2.5.29.65": { "d": "singleUse", "c": "X.509 extension" }, +"2.5.29.66": { "d": "groupAC", "c": "X.509 extension" }, +"2.5.29.67": { "d": "allowedAttAss", "c": "X.509 extension" }, +"2.5.29.68": { "d": "attributeMappings", "c": "X.509 extension" }, +"2.5.29.69": { "d": "holderNameConstraints", "c": "X.509 extension" }, +"2.16.724.1.2.2.4.1": { "d": "personalDataInfo", "c": "Spanish Government PKI?" }, +"2.16.840.1.101.2.1.1.1": { "d": "sdnsSignatureAlgorithm", "c": "SDN.700 INFOSEC algorithms" }, +"2.16.840.1.101.2.1.1.2": { "d": "fortezzaSignatureAlgorithm", "c": "SDN.700 INFOSEC algorithms. Formerly known as mosaicSignatureAlgorithm, this OID is better known as dsaWithSHA-1." }, +"2.16.840.1.101.2.1.1.3": { "d": "sdnsConfidentialityAlgorithm", "c": "SDN.700 INFOSEC algorithms" }, +"2.16.840.1.101.2.1.1.4": { "d": "fortezzaConfidentialityAlgorithm", "c": "SDN.700 INFOSEC algorithms. Formerly known as mosaicConfidentialityAlgorithm" }, +"2.16.840.1.101.2.1.1.5": { "d": "sdnsIntegrityAlgorithm", "c": "SDN.700 INFOSEC algorithms" }, +"2.16.840.1.101.2.1.1.6": { "d": "fortezzaIntegrityAlgorithm", "c": "SDN.700 INFOSEC algorithms. Formerly known as mosaicIntegrityAlgorithm" }, +"2.16.840.1.101.2.1.1.7": { "d": "sdnsTokenProtectionAlgorithm", "c": "SDN.700 INFOSEC algorithms" }, +"2.16.840.1.101.2.1.1.8": { "d": "fortezzaTokenProtectionAlgorithm", "c": "SDN.700 INFOSEC algorithms. Formerly know as mosaicTokenProtectionAlgorithm" }, +"2.16.840.1.101.2.1.1.9": { "d": "sdnsKeyManagementAlgorithm", "c": "SDN.700 INFOSEC algorithms" }, +"2.16.840.1.101.2.1.1.10": { "d": "fortezzaKeyManagementAlgorithm", "c": "SDN.700 INFOSEC algorithms. Formerly known as mosaicKeyManagementAlgorithm" }, +"2.16.840.1.101.2.1.1.11": { "d": "sdnsKMandSigAlgorithm", "c": "SDN.700 INFOSEC algorithms" }, +"2.16.840.1.101.2.1.1.12": { "d": "fortezzaKMandSigAlgorithm", "c": "SDN.700 INFOSEC algorithms. Formerly known as mosaicKMandSigAlgorithm" }, +"2.16.840.1.101.2.1.1.13": { "d": "suiteASignatureAlgorithm", "c": "SDN.700 INFOSEC algorithms" }, +"2.16.840.1.101.2.1.1.14": { "d": "suiteAConfidentialityAlgorithm", "c": "SDN.700 INFOSEC algorithms" }, +"2.16.840.1.101.2.1.1.15": { "d": "suiteAIntegrityAlgorithm", "c": "SDN.700 INFOSEC algorithms" }, +"2.16.840.1.101.2.1.1.16": { "d": "suiteATokenProtectionAlgorithm", "c": "SDN.700 INFOSEC algorithms" }, +"2.16.840.1.101.2.1.1.17": { "d": "suiteAKeyManagementAlgorithm", "c": "SDN.700 INFOSEC algorithms" }, +"2.16.840.1.101.2.1.1.18": { "d": "suiteAKMandSigAlgorithm", "c": "SDN.700 INFOSEC algorithms" }, +"2.16.840.1.101.2.1.1.19": { "d": "fortezzaUpdatedSigAlgorithm", "c": "SDN.700 INFOSEC algorithms. Formerly known as mosaicUpdatedSigAlgorithm" }, +"2.16.840.1.101.2.1.1.20": { "d": "fortezzaKMandUpdSigAlgorithms", "c": "SDN.700 INFOSEC algorithms. Formerly known as mosaicKMandUpdSigAlgorithms" }, +"2.16.840.1.101.2.1.1.21": { "d": "fortezzaUpdatedIntegAlgorithm", "c": "SDN.700 INFOSEC algorithms. Formerly known as mosaicUpdatedIntegAlgorithm" }, +"2.16.840.1.101.2.1.1.22": { "d": "keyExchangeAlgorithm", "c": "SDN.700 INFOSEC algorithms. Formerly known as mosaicKeyEncryptionAlgorithm" }, +"2.16.840.1.101.2.1.1.23": { "d": "fortezzaWrap80Algorithm", "c": "SDN.700 INFOSEC algorithms" }, +"2.16.840.1.101.2.1.1.24": { "d": "kEAKeyEncryptionAlgorithm", "c": "SDN.700 INFOSEC algorithms" }, +"2.16.840.1.101.2.1.2.1": { "d": "rfc822MessageFormat", "c": "SDN.700 INFOSEC format" }, +"2.16.840.1.101.2.1.2.2": { "d": "emptyContent", "c": "SDN.700 INFOSEC format" }, +"2.16.840.1.101.2.1.2.3": { "d": "cspContentType", "c": "SDN.700 INFOSEC format" }, +"2.16.840.1.101.2.1.2.42": { "d": "mspRev3ContentType", "c": "SDN.700 INFOSEC format" }, +"2.16.840.1.101.2.1.2.48": { "d": "mspContentType", "c": "SDN.700 INFOSEC format" }, +"2.16.840.1.101.2.1.2.49": { "d": "mspRekeyAgentProtocol", "c": "SDN.700 INFOSEC format" }, +"2.16.840.1.101.2.1.2.50": { "d": "mspMMP", "c": "SDN.700 INFOSEC format" }, +"2.16.840.1.101.2.1.2.66": { "d": "mspRev3-1ContentType", "c": "SDN.700 INFOSEC format" }, +"2.16.840.1.101.2.1.2.72": { "d": "forwardedMSPMessageBodyPart", "c": "SDN.700 INFOSEC format" }, +"2.16.840.1.101.2.1.2.73": { "d": "mspForwardedMessageParameters", "c": "SDN.700 INFOSEC format" }, +"2.16.840.1.101.2.1.2.74": { "d": "forwardedCSPMsgBodyPart", "c": "SDN.700 INFOSEC format" }, +"2.16.840.1.101.2.1.2.75": { "d": "cspForwardedMessageParameters", "c": "SDN.700 INFOSEC format" }, +"2.16.840.1.101.2.1.2.76": { "d": "mspMMP2", "c": "SDN.700 INFOSEC format" }, +"2.16.840.1.101.2.1.3.1": { "d": "sdnsSecurityPolicy", "c": "SDN.700 INFOSEC policy" }, +"2.16.840.1.101.2.1.3.2": { "d": "sdnsPRBAC", "c": "SDN.700 INFOSEC policy" }, +"2.16.840.1.101.2.1.3.3": { "d": "mosaicPRBAC", "c": "SDN.700 INFOSEC policy" }, +"2.16.840.1.101.2.1.3.10": { "d": "siSecurityPolicy", "c": "SDN.700 INFOSEC policy" }, +"2.16.840.1.101.2.1.3.10.0": { "d": "siNASP", "c": "SDN.700 INFOSEC policy (obsolete)", "w": true }, +"2.16.840.1.101.2.1.3.10.1": { "d": "siELCO", "c": "SDN.700 INFOSEC policy (obsolete)", "w": true }, +"2.16.840.1.101.2.1.3.10.2": { "d": "siTK", "c": "SDN.700 INFOSEC policy (obsolete)", "w": true }, +"2.16.840.1.101.2.1.3.10.3": { "d": "siDSAP", "c": "SDN.700 INFOSEC policy (obsolete)", "w": true }, +"2.16.840.1.101.2.1.3.10.4": { "d": "siSSSS", "c": "SDN.700 INFOSEC policy (obsolete)", "w": true }, +"2.16.840.1.101.2.1.3.10.5": { "d": "siDNASP", "c": "SDN.700 INFOSEC policy (obsolete)", "w": true }, +"2.16.840.1.101.2.1.3.10.6": { "d": "siBYEMAN", "c": "SDN.700 INFOSEC policy (obsolete)", "w": true }, +"2.16.840.1.101.2.1.3.10.7": { "d": "siREL-US", "c": "SDN.700 INFOSEC policy (obsolete)", "w": true }, +"2.16.840.1.101.2.1.3.10.8": { "d": "siREL-AUS", "c": "SDN.700 INFOSEC policy (obsolete)", "w": true }, +"2.16.840.1.101.2.1.3.10.9": { "d": "siREL-CAN", "c": "SDN.700 INFOSEC policy (obsolete)", "w": true }, +"2.16.840.1.101.2.1.3.10.10": { "d": "siREL_UK", "c": "SDN.700 INFOSEC policy (obsolete)", "w": true }, +"2.16.840.1.101.2.1.3.10.11": { "d": "siREL-NZ", "c": "SDN.700 INFOSEC policy (obsolete)", "w": true }, +"2.16.840.1.101.2.1.3.10.12": { "d": "siGeneric", "c": "SDN.700 INFOSEC policy (obsolete)", "w": true }, +"2.16.840.1.101.2.1.3.11": { "d": "genser", "c": "SDN.700 INFOSEC policy" }, +"2.16.840.1.101.2.1.3.11.0": { "d": "genserNations", "c": "SDN.700 INFOSEC policy (obsolete)", "w": true }, +"2.16.840.1.101.2.1.3.11.1": { "d": "genserComsec", "c": "SDN.700 INFOSEC policy (obsolete)", "w": true }, +"2.16.840.1.101.2.1.3.11.2": { "d": "genserAcquisition", "c": "SDN.700 INFOSEC policy (obsolete)", "w": true }, +"2.16.840.1.101.2.1.3.11.3": { "d": "genserSecurityCategories", "c": "SDN.700 INFOSEC policy" }, +"2.16.840.1.101.2.1.3.11.3.0": { "d": "genserTagSetName", "c": "SDN.700 INFOSEC GENSER policy" }, +"2.16.840.1.101.2.1.3.12": { "d": "defaultSecurityPolicy", "c": "SDN.700 INFOSEC policy" }, +"2.16.840.1.101.2.1.3.13": { "d": "capcoMarkings", "c": "SDN.700 INFOSEC policy" }, +"2.16.840.1.101.2.1.3.13.0": { "d": "capcoSecurityCategories", "c": "SDN.700 INFOSEC policy CAPCO markings" }, +"2.16.840.1.101.2.1.3.13.0.1": { "d": "capcoTagSetName1", "c": "SDN.700 INFOSEC policy CAPCO markings" }, +"2.16.840.1.101.2.1.3.13.0.2": { "d": "capcoTagSetName2", "c": "SDN.700 INFOSEC policy CAPCO markings" }, +"2.16.840.1.101.2.1.3.13.0.3": { "d": "capcoTagSetName3", "c": "SDN.700 INFOSEC policy CAPCO markings" }, +"2.16.840.1.101.2.1.3.13.0.4": { "d": "capcoTagSetName4", "c": "SDN.700 INFOSEC policy CAPCO markings" }, +"2.16.840.1.101.2.1.5.1": { "d": "sdnsKeyManagementCertificate", "c": "SDN.700 INFOSEC attributes (superseded)", "w": true }, +"2.16.840.1.101.2.1.5.2": { "d": "sdnsUserSignatureCertificate", "c": "SDN.700 INFOSEC attributes (superseded)", "w": true }, +"2.16.840.1.101.2.1.5.3": { "d": "sdnsKMandSigCertificate", "c": "SDN.700 INFOSEC attributes (superseded)", "w": true }, +"2.16.840.1.101.2.1.5.4": { "d": "fortezzaKeyManagementCertificate", "c": "SDN.700 INFOSEC attributes (superseded)", "w": true }, +"2.16.840.1.101.2.1.5.5": { "d": "fortezzaKMandSigCertificate", "c": "SDN.700 INFOSEC attributes (superseded)", "w": true }, +"2.16.840.1.101.2.1.5.6": { "d": "fortezzaUserSignatureCertificate", "c": "SDN.700 INFOSEC attributes (superseded)", "w": true }, +"2.16.840.1.101.2.1.5.7": { "d": "fortezzaCASignatureCertificate", "c": "SDN.700 INFOSEC attributes (superseded)", "w": true }, +"2.16.840.1.101.2.1.5.8": { "d": "sdnsCASignatureCertificate", "c": "SDN.700 INFOSEC attributes (superseded)", "w": true }, +"2.16.840.1.101.2.1.5.10": { "d": "auxiliaryVector", "c": "SDN.700 INFOSEC attributes (superseded)", "w": true }, +"2.16.840.1.101.2.1.5.11": { "d": "mlReceiptPolicy", "c": "SDN.700 INFOSEC attributes" }, +"2.16.840.1.101.2.1.5.12": { "d": "mlMembership", "c": "SDN.700 INFOSEC attributes" }, +"2.16.840.1.101.2.1.5.13": { "d": "mlAdministrators", "c": "SDN.700 INFOSEC attributes" }, +"2.16.840.1.101.2.1.5.14": { "d": "alid", "c": "SDN.700 INFOSEC attributes" }, +"2.16.840.1.101.2.1.5.20": { "d": "janUKMs", "c": "SDN.700 INFOSEC attributes" }, +"2.16.840.1.101.2.1.5.21": { "d": "febUKMs", "c": "SDN.700 INFOSEC attributes" }, +"2.16.840.1.101.2.1.5.22": { "d": "marUKMs", "c": "SDN.700 INFOSEC attributes" }, +"2.16.840.1.101.2.1.5.23": { "d": "aprUKMs", "c": "SDN.700 INFOSEC attributes" }, +"2.16.840.1.101.2.1.5.24": { "d": "mayUKMs", "c": "SDN.700 INFOSEC attributes" }, +"2.16.840.1.101.2.1.5.25": { "d": "junUKMs", "c": "SDN.700 INFOSEC attributes" }, +"2.16.840.1.101.2.1.5.26": { "d": "julUKMs", "c": "SDN.700 INFOSEC attributes" }, +"2.16.840.1.101.2.1.5.27": { "d": "augUKMs", "c": "SDN.700 INFOSEC attributes" }, +"2.16.840.1.101.2.1.5.28": { "d": "sepUKMs", "c": "SDN.700 INFOSEC attributes" }, +"2.16.840.1.101.2.1.5.29": { "d": "octUKMs", "c": "SDN.700 INFOSEC attributes" }, +"2.16.840.1.101.2.1.5.30": { "d": "novUKMs", "c": "SDN.700 INFOSEC attributes" }, +"2.16.840.1.101.2.1.5.31": { "d": "decUKMs", "c": "SDN.700 INFOSEC attributes" }, +"2.16.840.1.101.2.1.5.40": { "d": "metaSDNSckl", "c": "SDN.700 INFOSEC attributes" }, +"2.16.840.1.101.2.1.5.41": { "d": "sdnsCKL", "c": "SDN.700 INFOSEC attributes" }, +"2.16.840.1.101.2.1.5.42": { "d": "metaSDNSsignatureCKL", "c": "SDN.700 INFOSEC attributes" }, +"2.16.840.1.101.2.1.5.43": { "d": "sdnsSignatureCKL", "c": "SDN.700 INFOSEC attributes" }, +"2.16.840.1.101.2.1.5.44": { "d": "sdnsCertificateRevocationList", "c": "SDN.700 INFOSEC attributes" }, +"2.16.840.1.101.2.1.5.45": { "d": "fortezzaCertificateRevocationList", "c": "SDN.700 INFOSEC attributes (superseded)", "w": true }, +"2.16.840.1.101.2.1.5.46": { "d": "fortezzaCKL", "c": "SDN.700 INFOSEC attributes" }, +"2.16.840.1.101.2.1.5.47": { "d": "alExemptedAddressProcessor", "c": "SDN.700 INFOSEC attributes" }, +"2.16.840.1.101.2.1.5.48": { "d": "guard", "c": "SDN.700 INFOSEC attributes (obsolete)", "w": true }, +"2.16.840.1.101.2.1.5.49": { "d": "algorithmsSupported", "c": "SDN.700 INFOSEC attributes (obsolete)", "w": true }, +"2.16.840.1.101.2.1.5.50": { "d": "suiteAKeyManagementCertificate", "c": "SDN.700 INFOSEC attributes (obsolete)", "w": true }, +"2.16.840.1.101.2.1.5.51": { "d": "suiteAKMandSigCertificate", "c": "SDN.700 INFOSEC attributes (obsolete)", "w": true }, +"2.16.840.1.101.2.1.5.52": { "d": "suiteAUserSignatureCertificate", "c": "SDN.700 INFOSEC attributes (obsolete)", "w": true }, +"2.16.840.1.101.2.1.5.53": { "d": "prbacInfo", "c": "SDN.700 INFOSEC attributes" }, +"2.16.840.1.101.2.1.5.54": { "d": "prbacCAConstraints", "c": "SDN.700 INFOSEC attributes" }, +"2.16.840.1.101.2.1.5.55": { "d": "sigOrKMPrivileges", "c": "SDN.700 INFOSEC attributes" }, +"2.16.840.1.101.2.1.5.56": { "d": "commPrivileges", "c": "SDN.700 INFOSEC attributes" }, +"2.16.840.1.101.2.1.5.57": { "d": "labeledAttribute", "c": "SDN.700 INFOSEC attributes" }, +"2.16.840.1.101.2.1.5.58": { "d": "policyInformationFile", "c": "SDN.700 INFOSEC attributes (obsolete)", "w": true }, +"2.16.840.1.101.2.1.5.59": { "d": "secPolicyInformationFile", "c": "SDN.700 INFOSEC attributes" }, +"2.16.840.1.101.2.1.5.60": { "d": "cAClearanceConstraint", "c": "SDN.700 INFOSEC attributes" }, +"2.16.840.1.101.2.1.7.1": { "d": "cspExtns", "c": "SDN.700 INFOSEC extensions" }, +"2.16.840.1.101.2.1.7.1.0": { "d": "cspCsExtn", "c": "SDN.700 INFOSEC extensions" }, +"2.16.840.1.101.2.1.8.1": { "d": "mISSISecurityCategories", "c": "SDN.700 INFOSEC security category" }, +"2.16.840.1.101.2.1.8.2": { "d": "standardSecurityLabelPrivileges", "c": "SDN.700 INFOSEC security category" }, +"2.16.840.1.101.2.1.10.1": { "d": "sigPrivileges", "c": "SDN.700 INFOSEC privileges" }, +"2.16.840.1.101.2.1.10.2": { "d": "kmPrivileges", "c": "SDN.700 INFOSEC privileges" }, +"2.16.840.1.101.2.1.10.3": { "d": "namedTagSetPrivilege", "c": "SDN.700 INFOSEC privileges" }, +"2.16.840.1.101.2.1.11.1": { "d": "ukDemo", "c": "SDN.700 INFOSEC certificate policy" }, +"2.16.840.1.101.2.1.11.2": { "d": "usDODClass2", "c": "SDN.700 INFOSEC certificate policy" }, +"2.16.840.1.101.2.1.11.3": { "d": "usMediumPilot", "c": "SDN.700 INFOSEC certificate policy" }, +"2.16.840.1.101.2.1.11.4": { "d": "usDODClass4", "c": "SDN.700 INFOSEC certificate policy" }, +"2.16.840.1.101.2.1.11.5": { "d": "usDODClass3", "c": "SDN.700 INFOSEC certificate policy" }, +"2.16.840.1.101.2.1.11.6": { "d": "usDODClass5", "c": "SDN.700 INFOSEC certificate policy" }, +"2.16.840.1.101.2.1.12.0": { "d": "testSecurityPolicy", "c": "SDN.700 INFOSEC test objects" }, +"2.16.840.1.101.2.1.12.0.1": { "d": "tsp1", "c": "SDN.700 INFOSEC test objects" }, +"2.16.840.1.101.2.1.12.0.1.0": { "d": "tsp1SecurityCategories", "c": "SDN.700 INFOSEC test objects" }, +"2.16.840.1.101.2.1.12.0.1.0.0": { "d": "tsp1TagSetZero", "c": "SDN.700 INFOSEC test objects" }, +"2.16.840.1.101.2.1.12.0.1.0.1": { "d": "tsp1TagSetOne", "c": "SDN.700 INFOSEC test objects" }, +"2.16.840.1.101.2.1.12.0.1.0.2": { "d": "tsp1TagSetTwo", "c": "SDN.700 INFOSEC test objects" }, +"2.16.840.1.101.2.1.12.0.2": { "d": "tsp2", "c": "SDN.700 INFOSEC test objects" }, +"2.16.840.1.101.2.1.12.0.2.0": { "d": "tsp2SecurityCategories", "c": "SDN.700 INFOSEC test objects" }, +"2.16.840.1.101.2.1.12.0.2.0.0": { "d": "tsp2TagSetZero", "c": "SDN.700 INFOSEC test objects" }, +"2.16.840.1.101.2.1.12.0.2.0.1": { "d": "tsp2TagSetOne", "c": "SDN.700 INFOSEC test objects" }, +"2.16.840.1.101.2.1.12.0.2.0.2": { "d": "tsp2TagSetTwo", "c": "SDN.700 INFOSEC test objects" }, +"2.16.840.1.101.2.1.12.0.3": { "d": "kafka", "c": "SDN.700 INFOSEC test objects" }, +"2.16.840.1.101.2.1.12.0.3.0": { "d": "kafkaSecurityCategories", "c": "SDN.700 INFOSEC test objects" }, +"2.16.840.1.101.2.1.12.0.3.0.1": { "d": "kafkaTagSetName1", "c": "SDN.700 INFOSEC test objects" }, +"2.16.840.1.101.2.1.12.0.3.0.2": { "d": "kafkaTagSetName2", "c": "SDN.700 INFOSEC test objects" }, +"2.16.840.1.101.2.1.12.0.3.0.3": { "d": "kafkaTagSetName3", "c": "SDN.700 INFOSEC test objects" }, +"2.16.840.1.101.2.1.12.1.1": { "d": "tcp1", "c": "SDN.700 INFOSEC test objects" }, +"2.16.840.1.101.3.1": { "d": "slabel", "c": "CSOR GAK", "w": true }, +"2.16.840.1.101.3.2": { "d": "pki", "c": "NIST", "w": true }, +"2.16.840.1.101.3.2.1": { "d": "NIST policyIdentifier", "c": "NIST policies", "w": true }, +"2.16.840.1.101.3.2.1.3.1": { "d": "fbcaRudimentaryPolicy", "c": "Federal Bridge CA Policy" }, +"2.16.840.1.101.3.2.1.3.2": { "d": "fbcaBasicPolicy", "c": "Federal Bridge CA Policy" }, +"2.16.840.1.101.3.2.1.3.3": { "d": "fbcaMediumPolicy", "c": "Federal Bridge CA Policy" }, +"2.16.840.1.101.3.2.1.3.4": { "d": "fbcaHighPolicy", "c": "Federal Bridge CA Policy" }, +"2.16.840.1.101.3.2.1.48.1": { "d": "nistTestPolicy1", "c": "NIST PKITS policies" }, +"2.16.840.1.101.3.2.1.48.2": { "d": "nistTestPolicy2", "c": "NIST PKITS policies" }, +"2.16.840.1.101.3.2.1.48.3": { "d": "nistTestPolicy3", "c": "NIST PKITS policies" }, +"2.16.840.1.101.3.2.1.48.4": { "d": "nistTestPolicy4", "c": "NIST PKITS policies" }, +"2.16.840.1.101.3.2.1.48.5": { "d": "nistTestPolicy5", "c": "NIST PKITS policies" }, +"2.16.840.1.101.3.2.1.48.6": { "d": "nistTestPolicy6", "c": "NIST PKITS policies" }, +"2.16.840.1.101.3.2.2": { "d": "gak", "c": "CSOR GAK extended key usage", "w": true }, +"2.16.840.1.101.3.2.2.1": { "d": "kRAKey", "c": "CSOR GAK extended key usage", "w": true }, +"2.16.840.1.101.3.2.3": { "d": "extensions", "c": "CSOR GAK extensions", "w": true }, +"2.16.840.1.101.3.2.3.1": { "d": "kRTechnique", "c": "CSOR GAK extensions", "w": true }, +"2.16.840.1.101.3.2.3.2": { "d": "kRecoveryCapable", "c": "CSOR GAK extensions", "w": true }, +"2.16.840.1.101.3.2.3.3": { "d": "kR", "c": "CSOR GAK extensions", "w": true }, +"2.16.840.1.101.3.2.4": { "d": "keyRecoverySchemes", "c": "CSOR GAK", "w": true }, +"2.16.840.1.101.3.2.5": { "d": "krapola", "c": "CSOR GAK", "w": true }, +"2.16.840.1.101.3.3": { "d": "arpa", "c": "CSOR GAK", "w": true }, +"2.16.840.1.101.3.4": { "d": "nistAlgorithm", "c": "NIST Algorithm" }, +"2.16.840.1.101.3.4.1": { "d": "aes", "c": "NIST Algorithm" }, +"2.16.840.1.101.3.4.1.1": { "d": "aes128-ECB", "c": "NIST Algorithm" }, +"2.16.840.1.101.3.4.1.2": { "d": "aes128-CBC", "c": "NIST Algorithm" }, +"2.16.840.1.101.3.4.1.3": { "d": "aes128-OFB", "c": "NIST Algorithm" }, +"2.16.840.1.101.3.4.1.4": { "d": "aes128-CFB", "c": "NIST Algorithm" }, +"2.16.840.1.101.3.4.1.5": { "d": "aes128-wrap", "c": "NIST Algorithm" }, +"2.16.840.1.101.3.4.1.6": { "d": "aes128-GCM", "c": "NIST Algorithm" }, +"2.16.840.1.101.3.4.1.7": { "d": "aes128-CCM", "c": "NIST Algorithm" }, +"2.16.840.1.101.3.4.1.8": { "d": "aes128-wrap-pad", "c": "NIST Algorithm" }, +"2.16.840.1.101.3.4.1.21": { "d": "aes192-ECB", "c": "NIST Algorithm" }, +"2.16.840.1.101.3.4.1.22": { "d": "aes192-CBC", "c": "NIST Algorithm" }, +"2.16.840.1.101.3.4.1.23": { "d": "aes192-OFB", "c": "NIST Algorithm" }, +"2.16.840.1.101.3.4.1.24": { "d": "aes192-CFB", "c": "NIST Algorithm" }, +"2.16.840.1.101.3.4.1.25": { "d": "aes192-wrap", "c": "NIST Algorithm" }, +"2.16.840.1.101.3.4.1.26": { "d": "aes192-GCM", "c": "NIST Algorithm" }, +"2.16.840.1.101.3.4.1.27": { "d": "aes192-CCM", "c": "NIST Algorithm" }, +"2.16.840.1.101.3.4.1.28": { "d": "aes192-wrap-pad", "c": "NIST Algorithm" }, +"2.16.840.1.101.3.4.1.41": { "d": "aes256-ECB", "c": "NIST Algorithm" }, +"2.16.840.1.101.3.4.1.42": { "d": "aes256-CBC", "c": "NIST Algorithm" }, +"2.16.840.1.101.3.4.1.43": { "d": "aes256-OFB", "c": "NIST Algorithm" }, +"2.16.840.1.101.3.4.1.44": { "d": "aes256-CFB", "c": "NIST Algorithm" }, +"2.16.840.1.101.3.4.1.45": { "d": "aes256-wrap", "c": "NIST Algorithm" }, +"2.16.840.1.101.3.4.1.46": { "d": "aes256-GCM", "c": "NIST Algorithm" }, +"2.16.840.1.101.3.4.1.47": { "d": "aes256-CCM", "c": "NIST Algorithm" }, +"2.16.840.1.101.3.4.1.48": { "d": "aes256-wrap-pad", "c": "NIST Algorithm" }, +"2.16.840.1.101.3.4.2": { "d": "hashAlgos", "c": "NIST Algorithm" }, +"2.16.840.1.101.3.4.2.1": { "d": "sha-256", "c": "NIST Algorithm" }, +"2.16.840.1.101.3.4.2.2": { "d": "sha-384", "c": "NIST Algorithm" }, +"2.16.840.1.101.3.4.2.3": { "d": "sha-512", "c": "NIST Algorithm" }, +"2.16.840.1.101.3.4.2.4": { "d": "sha-224", "c": "NIST Algorithm" }, +"2.16.840.1.101.3.4.3.1": { "d": "dsaWithSha224", "c": "NIST Algorithm" }, +"2.16.840.1.101.3.4.3.2": { "d": "dsaWithSha256", "c": "NIST Algorithm" }, +"2.16.840.1.113719.1.2.8": { "d": "novellAlgorithm", "c": "Novell" }, +"2.16.840.1.113719.1.2.8.22": { "d": "desCbcIV8", "c": "Novell encryption algorithm" }, +"2.16.840.1.113719.1.2.8.23": { "d": "desCbcPadIV8", "c": "Novell encryption algorithm" }, +"2.16.840.1.113719.1.2.8.24": { "d": "desEDE2CbcIV8", "c": "Novell encryption algorithm" }, +"2.16.840.1.113719.1.2.8.25": { "d": "desEDE2CbcPadIV8", "c": "Novell encryption algorithm" }, +"2.16.840.1.113719.1.2.8.26": { "d": "desEDE3CbcIV8", "c": "Novell encryption algorithm" }, +"2.16.840.1.113719.1.2.8.27": { "d": "desEDE3CbcPadIV8", "c": "Novell encryption algorithm" }, +"2.16.840.1.113719.1.2.8.28": { "d": "rc5CbcPad", "c": "Novell encryption algorithm" }, +"2.16.840.1.113719.1.2.8.29": { "d": "md2WithRSAEncryptionBSafe1", "c": "Novell signature algorithm" }, +"2.16.840.1.113719.1.2.8.30": { "d": "md5WithRSAEncryptionBSafe1", "c": "Novell signature algorithm" }, +"2.16.840.1.113719.1.2.8.31": { "d": "sha1WithRSAEncryptionBSafe1", "c": "Novell signature algorithm" }, +"2.16.840.1.113719.1.2.8.32": { "d": "lmDigest", "c": "Novell digest algorithm" }, +"2.16.840.1.113719.1.2.8.40": { "d": "md2", "c": "Novell digest algorithm" }, +"2.16.840.1.113719.1.2.8.50": { "d": "md5", "c": "Novell digest algorithm" }, +"2.16.840.1.113719.1.2.8.51": { "d": "ikeHmacWithSHA1-RSA", "c": "Novell signature algorithm" }, +"2.16.840.1.113719.1.2.8.52": { "d": "ikeHmacWithMD5-RSA", "c": "Novell signature algorithm" }, +"2.16.840.1.113719.1.2.8.69": { "d": "rc2CbcPad", "c": "Novell encryption algorithm" }, +"2.16.840.1.113719.1.2.8.82": { "d": "sha-1", "c": "Novell digest algorithm" }, +"2.16.840.1.113719.1.2.8.92": { "d": "rc2BSafe1Cbc", "c": "Novell encryption algorithm" }, +"2.16.840.1.113719.1.2.8.95": { "d": "md4", "c": "Novell digest algorithm" }, +"2.16.840.1.113719.1.2.8.130": { "d": "md4Packet", "c": "Novell keyed hash" }, +"2.16.840.1.113719.1.2.8.131": { "d": "rsaEncryptionBsafe1", "c": "Novell encryption algorithm" }, +"2.16.840.1.113719.1.2.8.132": { "d": "nwPassword", "c": "Novell encryption algorithm" }, +"2.16.840.1.113719.1.2.8.133": { "d": "novellObfuscate-1", "c": "Novell encryption algorithm" }, +"2.16.840.1.113719.1.9": { "d": "pki", "c": "Novell" }, +"2.16.840.1.113719.1.9.4": { "d": "pkiAttributeType", "c": "Novell PKI" }, +"2.16.840.1.113719.1.9.4.1": { "d": "securityAttributes", "c": "Novell PKI attribute type" }, +"2.16.840.1.113719.1.9.4.2": { "d": "relianceLimit", "c": "Novell PKI attribute type" }, +"2.16.840.1.113730.1": { "d": "cert-extension", "c": "Netscape" }, +"2.16.840.1.113730.1.1": { "d": "netscape-cert-type", "c": "Netscape certificate extension" }, +"2.16.840.1.113730.1.2": { "d": "netscape-base-url", "c": "Netscape certificate extension" }, +"2.16.840.1.113730.1.3": { "d": "netscape-revocation-url", "c": "Netscape certificate extension" }, +"2.16.840.1.113730.1.4": { "d": "netscape-ca-revocation-url", "c": "Netscape certificate extension" }, +"2.16.840.1.113730.1.7": { "d": "netscape-cert-renewal-url", "c": "Netscape certificate extension" }, +"2.16.840.1.113730.1.8": { "d": "netscape-ca-policy-url", "c": "Netscape certificate extension" }, +"2.16.840.1.113730.1.9": { "d": "HomePage-url", "c": "Netscape certificate extension" }, +"2.16.840.1.113730.1.10": { "d": "EntityLogo", "c": "Netscape certificate extension" }, +"2.16.840.1.113730.1.11": { "d": "UserPicture", "c": "Netscape certificate extension" }, +"2.16.840.1.113730.1.12": { "d": "netscape-ssl-server-name", "c": "Netscape certificate extension" }, +"2.16.840.1.113730.1.13": { "d": "netscape-comment", "c": "Netscape certificate extension" }, +"2.16.840.1.113730.2": { "d": "data-type", "c": "Netscape" }, +"2.16.840.1.113730.2.1": { "d": "dataGIF", "c": "Netscape data type" }, +"2.16.840.1.113730.2.2": { "d": "dataJPEG", "c": "Netscape data type" }, +"2.16.840.1.113730.2.3": { "d": "dataURL", "c": "Netscape data type" }, +"2.16.840.1.113730.2.4": { "d": "dataHTML", "c": "Netscape data type" }, +"2.16.840.1.113730.2.5": { "d": "certSequence", "c": "Netscape data type" }, +"2.16.840.1.113730.2.6": { "d": "certURL", "c": "Netscape certificate extension" }, +"2.16.840.1.113730.3": { "d": "directory", "c": "Netscape" }, +"2.16.840.1.113730.3.1": { "d": "ldapDefinitions", "c": "Netscape directory" }, +"2.16.840.1.113730.3.1.1": { "d": "carLicense", "c": "Netscape LDAP definitions" }, +"2.16.840.1.113730.3.1.2": { "d": "departmentNumber", "c": "Netscape LDAP definitions" }, +"2.16.840.1.113730.3.1.3": { "d": "employeeNumber", "c": "Netscape LDAP definitions" }, +"2.16.840.1.113730.3.1.4": { "d": "employeeType", "c": "Netscape LDAP definitions" }, +"2.16.840.1.113730.3.2.2": { "d": "inetOrgPerson", "c": "Netscape LDAP definitions" }, +"2.16.840.1.113730.4.1": { "d": "serverGatedCrypto", "c": "Netscape" }, +"2.16.840.1.113733.1.6.3": { "d": "verisignCZAG", "c": "Verisign extension" }, +"2.16.840.1.113733.1.6.6": { "d": "verisignInBox", "c": "Verisign extension" }, +"2.16.840.1.113733.1.6.11": { "d": "verisignOnsiteJurisdictionHash", "c": "Verisign extension" }, +"2.16.840.1.113733.1.6.13": { "d": "Unknown Verisign VPN extension", "c": "Verisign extension" }, +"2.16.840.1.113733.1.6.15": { "d": "verisignServerID", "c": "Verisign extension" }, +"2.16.840.1.113733.1.7.1.1": { "d": "verisignCertPolicies95Qualifier1", "c": "Verisign policy" }, +"2.16.840.1.113733.1.7.1.1.1": { "d": "verisignCPSv1notice", "c": "Verisign policy (obsolete)" }, +"2.16.840.1.113733.1.7.1.1.2": { "d": "verisignCPSv1nsi", "c": "Verisign policy (obsolete)" }, +"2.16.840.1.113733.1.8.1": { "d": "verisignISSStrongCrypto", "c": "Verisign" }, +"2.16.840.1.113733.1": { "d": "pki", "c": "Verisign extension" }, +"2.16.840.1.113733.1.9": { "d": "pkcs7Attribute", "c": "Verisign PKI extension" }, +"2.16.840.1.113733.1.9.2": { "d": "messageType", "c": "Verisign PKCS #7 attribute" }, +"2.16.840.1.113733.1.9.3": { "d": "pkiStatus", "c": "Verisign PKCS #7 attribute" }, +"2.16.840.1.113733.1.9.4": { "d": "failInfo", "c": "Verisign PKCS #7 attribute" }, +"2.16.840.1.113733.1.9.5": { "d": "senderNonce", "c": "Verisign PKCS #7 attribute" }, +"2.16.840.1.113733.1.9.6": { "d": "recipientNonce", "c": "Verisign PKCS #7 attribute" }, +"2.16.840.1.113733.1.9.7": { "d": "transID", "c": "Verisign PKCS #7 attribute" }, +"2.16.840.1.113733.1.9.8": { "d": "extensionReq", "c": "Verisign PKCS #7 attribute. Use PKCS #9 extensionRequest instead", "w": true }, +"2.16.840.1.113741.2": { "d": "intelCDSA", "c": "Intel CDSA" }, +"2.16.840.1.114412.1": { "d": "digiCertNonEVCerts", "c": "Digicert CA policy" }, +"2.16.840.1.114412.1.1": { "d": "digiCertOVCert", "c": "Digicert CA policy" }, +"2.16.840.1.114412.1.2": { "d": "digiCertDVCert", "c": "Digicert CA policy" }, +"2.16.840.1.114412.1.11": { "d": "digiCertFederatedDeviceCert", "c": "Digicert CA policy" }, +"2.16.840.1.114412.1.3.0.1": { "d": "digiCertGlobalCAPolicy", "c": "Digicert CA policy" }, +"2.16.840.1.114412.1.3.0.2": { "d": "digiCertHighAssuranceEVCAPolicy", "c": "Digicert CA policy" }, +"2.16.840.1.114412.1.3.0.3": { "d": "digiCertGlobalRootCAPolicy", "c": "Digicert CA policy" }, +"2.16.840.1.114412.1.3.0.4": { "d": "digiCertAssuredIDRootCAPolicy", "c": "Digicert CA policy" }, +"2.16.840.1.114412.2.2": { "d": "digiCertEVCert", "c": "Digicert CA policy" }, +"2.16.840.1.114412.2.3": { "d": "digiCertObjectSigningCert", "c": "Digicert CA policy" }, +"2.16.840.1.114412.2.3.1": { "d": "digiCertCodeSigningCert", "c": "Digicert CA policy" }, +"2.16.840.1.114412.2.3.2": { "d": "digiCertEVCodeSigningCert", "c": "Digicert CA policy" }, +"2.16.840.1.114412.2.3.11": { "d": "digiCertKernelCodeSigningCert", "c": "Digicert CA policy" }, +"2.16.840.1.114412.2.3.21": { "d": "digiCertDocumentSigningCert", "c": "Digicert CA policy" }, +"2.16.840.1.114412.2.4": { "d": "digiCertClientCert", "c": "Digicert CA policy" }, +"2.16.840.1.114412.2.4.1.1": { "d": "digiCertLevel1PersonalClientCert", "c": "Digicert CA policy" }, +"2.16.840.1.114412.2.4.1.2": { "d": "digiCertLevel1EnterpriseClientCert", "c": "Digicert CA policy" }, +"2.16.840.1.114412.2.4.2": { "d": "digiCertLevel2ClientCert", "c": "Digicert CA policy" }, +"2.16.840.1.114412.2.4.3.1": { "d": "digiCertLevel3USClientCert", "c": "Digicert CA policy" }, +"2.16.840.1.114412.2.4.3.2": { "d": "digiCertLevel3CBPClientCert", "c": "Digicert CA policy" }, +"2.16.840.1.114412.2.4.4.1": { "d": "digiCertLevel4USClientCert", "c": "Digicert CA policy" }, +"2.16.840.1.114412.2.4.4.2": { "d": "digiCertLevel4CBPClientCert", "c": "Digicert CA policy" }, +"2.16.840.1.114412.2.4.5.1": { "d": "digiCertPIVHardwareCert", "c": "Digicert CA policy" }, +"2.16.840.1.114412.2.4.5.2": { "d": "digiCertPIVCardAuthCert", "c": "Digicert CA policy" }, +"2.16.840.1.114412.2.4.5.3": { "d": "digiCertPIVContentSigningCert", "c": "Digicert CA policy" }, +"2.16.840.1.114412.4.31": { "d": "digiCertGridClassicCert", "c": "Digicert CA policy" }, +"2.16.840.1.114412.4.31.5": { "d": "digiCertGridIntegratedCert", "c": "Digicert CA policy" }, +"2.16.840.1.114412.31.4.31.1": { "d": "digiCertGridHostCert", "c": "Digicert CA policy" }, +"2.23.42.0": { "d": "contentType", "c": "SET" }, +"2.23.42.0.0": { "d": "panData", "c": "SET contentType" }, +"2.23.42.0.1": { "d": "panToken", "c": "SET contentType" }, +"2.23.42.0.2": { "d": "panOnly", "c": "SET contentType" }, +"2.23.42.1": { "d": "msgExt", "c": "SET" }, +"2.23.42.2": { "d": "field", "c": "SET" }, +"2.23.42.2.0": { "d": "fullName", "c": "SET field" }, +"2.23.42.2.1": { "d": "givenName", "c": "SET field" }, +"2.23.42.2.2": { "d": "familyName", "c": "SET field" }, +"2.23.42.2.3": { "d": "birthFamilyName", "c": "SET field" }, +"2.23.42.2.4": { "d": "placeName", "c": "SET field" }, +"2.23.42.2.5": { "d": "identificationNumber", "c": "SET field" }, +"2.23.42.2.6": { "d": "month", "c": "SET field" }, +"2.23.42.2.7": { "d": "date", "c": "SET field" }, +"2.23.42.2.8": { "d": "address", "c": "SET field" }, +"2.23.42.2.9": { "d": "telephone", "c": "SET field" }, +"2.23.42.2.10": { "d": "amount", "c": "SET field" }, +"2.23.42.2.11": { "d": "accountNumber", "c": "SET field" }, +"2.23.42.2.12": { "d": "passPhrase", "c": "SET field" }, +"2.23.42.3": { "d": "attribute", "c": "SET" }, +"2.23.42.3.0": { "d": "cert", "c": "SET attribute" }, +"2.23.42.3.0.0": { "d": "rootKeyThumb", "c": "SET cert attribute" }, +"2.23.42.3.0.1": { "d": "additionalPolicy", "c": "SET cert attribute" }, +"2.23.42.4": { "d": "algorithm", "c": "SET" }, +"2.23.42.5": { "d": "policy", "c": "SET" }, +"2.23.42.5.0": { "d": "root", "c": "SET policy" }, +"2.23.42.6": { "d": "module", "c": "SET" }, +"2.23.42.7": { "d": "certExt", "c": "SET" }, +"2.23.42.7.0": { "d": "hashedRootKey", "c": "SET cert extension" }, +"2.23.42.7.1": { "d": "certificateType", "c": "SET cert extension" }, +"2.23.42.7.2": { "d": "merchantData", "c": "SET cert extension" }, +"2.23.42.7.3": { "d": "cardCertRequired", "c": "SET cert extension" }, +"2.23.42.7.4": { "d": "tunneling", "c": "SET cert extension" }, +"2.23.42.7.5": { "d": "setExtensions", "c": "SET cert extension" }, +"2.23.42.7.6": { "d": "setQualifier", "c": "SET cert extension" }, +"2.23.42.8": { "d": "brand", "c": "SET" }, +"2.23.42.8.1": { "d": "IATA-ATA", "c": "SET brand" }, +"2.23.42.8.4": { "d": "VISA", "c": "SET brand" }, +"2.23.42.8.5": { "d": "MasterCard", "c": "SET brand" }, +"2.23.42.8.30": { "d": "Diners", "c": "SET brand" }, +"2.23.42.8.34": { "d": "AmericanExpress", "c": "SET brand" }, +"2.23.42.8.6011": { "d": "Novus", "c": "SET brand" }, +"2.23.42.9": { "d": "vendor", "c": "SET" }, +"2.23.42.9.0": { "d": "GlobeSet", "c": "SET vendor" }, +"2.23.42.9.1": { "d": "IBM", "c": "SET vendor" }, +"2.23.42.9.2": { "d": "CyberCash", "c": "SET vendor" }, +"2.23.42.9.3": { "d": "Terisa", "c": "SET vendor" }, +"2.23.42.9.4": { "d": "RSADSI", "c": "SET vendor" }, +"2.23.42.9.5": { "d": "VeriFone", "c": "SET vendor" }, +"2.23.42.9.6": { "d": "TrinTech", "c": "SET vendor" }, +"2.23.42.9.7": { "d": "BankGate", "c": "SET vendor" }, +"2.23.42.9.8": { "d": "GTE", "c": "SET vendor" }, +"2.23.42.9.9": { "d": "CompuSource", "c": "SET vendor" }, +"2.23.42.9.10": { "d": "Griffin", "c": "SET vendor" }, +"2.23.42.9.11": { "d": "Certicom", "c": "SET vendor" }, +"2.23.42.9.12": { "d": "OSS", "c": "SET vendor" }, +"2.23.42.9.13": { "d": "TenthMountain", "c": "SET vendor" }, +"2.23.42.9.14": { "d": "Antares", "c": "SET vendor" }, +"2.23.42.9.15": { "d": "ECC", "c": "SET vendor" }, +"2.23.42.9.16": { "d": "Maithean", "c": "SET vendor" }, +"2.23.42.9.17": { "d": "Netscape", "c": "SET vendor" }, +"2.23.42.9.18": { "d": "Verisign", "c": "SET vendor" }, +"2.23.42.9.19": { "d": "BlueMoney", "c": "SET vendor" }, +"2.23.42.9.20": { "d": "Lacerte", "c": "SET vendor" }, +"2.23.42.9.21": { "d": "Fujitsu", "c": "SET vendor" }, +"2.23.42.9.22": { "d": "eLab", "c": "SET vendor" }, +"2.23.42.9.23": { "d": "Entrust", "c": "SET vendor" }, +"2.23.42.9.24": { "d": "VIAnet", "c": "SET vendor" }, +"2.23.42.9.25": { "d": "III", "c": "SET vendor" }, +"2.23.42.9.26": { "d": "OpenMarket", "c": "SET vendor" }, +"2.23.42.9.27": { "d": "Lexem", "c": "SET vendor" }, +"2.23.42.9.28": { "d": "Intertrader", "c": "SET vendor" }, +"2.23.42.9.29": { "d": "Persimmon", "c": "SET vendor" }, +"2.23.42.9.30": { "d": "NABLE", "c": "SET vendor" }, +"2.23.42.9.31": { "d": "espace-net", "c": "SET vendor" }, +"2.23.42.9.32": { "d": "Hitachi", "c": "SET vendor" }, +"2.23.42.9.33": { "d": "Microsoft", "c": "SET vendor" }, +"2.23.42.9.34": { "d": "NEC", "c": "SET vendor" }, +"2.23.42.9.35": { "d": "Mitsubishi", "c": "SET vendor" }, +"2.23.42.9.36": { "d": "NCR", "c": "SET vendor" }, +"2.23.42.9.37": { "d": "e-COMM", "c": "SET vendor" }, +"2.23.42.9.38": { "d": "Gemplus", "c": "SET vendor" }, +"2.23.42.10": { "d": "national", "c": "SET" }, +"2.23.42.10.392": { "d": "Japan", "c": "SET national" }, +"2.23.43.1.4": { "d": "wTLS-ECC", "c": "WAP WTLS" }, +"2.23.43.1.4.1": { "d": "wTLS-ECC-curve1", "c": "WAP WTLS" }, +"2.23.43.1.4.6": { "d": "wTLS-ECC-curve6", "c": "WAP WTLS" }, +"2.23.43.1.4.8": { "d": "wTLS-ECC-curve8", "c": "WAP WTLS" }, +"2.23.43.1.4.9": { "d": "wTLS-ECC-curve9", "c": "WAP WTLS" }, +"2.23.133": { "d": "tCPA", "c": "TCPA" }, +"2.23.133.1": { "d": "tcpaSpecVersion", "c": "TCPA" }, +"2.23.133.2": { "d": "tcpaAttribute", "c": "TCPA" }, +"2.23.133.2.1": { "d": "tcpaTpmManufacturer", "c": "TCPA Attribute" }, +"2.23.133.2.2": { "d": "tcpaTpmModel", "c": "TCPA Attribute" }, +"2.23.133.2.3": { "d": "tcpaTpmVersion", "c": "TCPA Attribute" }, +"2.23.133.2.4": { "d": "tcpaPlatformManufacturer", "c": "TCPA Attribute" }, +"2.23.133.2.5": { "d": "tcpaPlatformModel", "c": "TCPA Attribute" }, +"2.23.133.2.6": { "d": "tcpaPlatformVersion", "c": "TCPA Attribute" }, +"2.23.133.2.7": { "d": "tcpaComponentManufacturer", "c": "TCPA Attribute" }, +"2.23.133.2.8": { "d": "tcpaComponentModel", "c": "TCPA Attribute" }, +"2.23.133.2.9": { "d": "tcpaComponentVersion", "c": "TCPA Attribute" }, +"2.23.133.2.10": { "d": "tcpaSecurityQualities", "c": "TCPA Attribute" }, +"2.23.133.2.11": { "d": "tcpaTpmProtectionProfile", "c": "TCPA Attribute" }, +"2.23.133.2.12": { "d": "tcpaTpmSecurityTarget", "c": "TCPA Attribute" }, +"2.23.133.2.13": { "d": "tcpaFoundationProtectionProfile", "c": "TCPA Attribute" }, +"2.23.133.2.14": { "d": "tcpaFoundationSecurityTarget", "c": "TCPA Attribute" }, +"2.23.133.2.15": { "d": "tcpaTpmIdLabel", "c": "TCPA Attribute" }, +"2.23.133.3": { "d": "tcpaProtocol", "c": "TCPA" }, +"2.23.133.3.1": { "d": "tcpaPrttTpmIdProtocol", "c": "TCPA Protocol" }, +"2.23.134.1.4.2.1": { "d": "postSignumRootQCA", "c": "PostSignum CA" }, +"2.23.134.1.2.2.3": { "d": "postSignumPublicCA", "c": "PostSignum CA" }, +"2.23.134.1.2.1.8.210": { "d": "postSignumCommercialServerPolicy", "c": "PostSignum CA" }, +"2.23.136.1.1.1": { "d": "mRTDSignatureData", "c": "ICAO MRTD" }, +"2.54.1775.2": { "d": "hashedRootKey", "c": "SET. Deprecated, use (2 23 42 7 0) instead", "w": true }, +"2.54.1775.3": { "d": "certificateType", "c": "SET. Deprecated, use (2 23 42 7 0) instead", "w": true }, +"2.54.1775.4": { "d": "merchantData", "c": "SET. Deprecated, use (2 23 42 7 0) instead", "w": true }, +"2.54.1775.5": { "d": "cardCertRequired", "c": "SET. Deprecated, use (2 23 42 7 0) instead", "w": true }, +"2.54.1775.6": { "d": "tunneling", "c": "SET. Deprecated, use (2 23 42 7 0) instead", "w": true }, +"2.54.1775.7": { "d": "setQualifier", "c": "SET. Deprecated, use (2 23 42 7 0) instead", "w": true }, +"2.54.1775.99": { "d": "setData", "c": "SET. Deprecated, use (2 23 42 7 0) instead", "w": true }, +"1.2.40.0.17.1.22": { "d": "A-Trust EV policy", "c": "A-Trust CA Root" }, +"1.3.6.1.4.1.34697.2.1": { "d": "AffirmTrust EV policy", "c": "AffirmTrust Commercial" }, +"1.3.6.1.4.1.34697.2.2": { "d": "AffirmTrust EV policy", "c": "AffirmTrust Networking" }, +"1.3.6.1.4.1.34697.2.3": { "d": "AffirmTrust EV policy", "c": "AffirmTrust Premium" }, +"1.3.6.1.4.1.34697.2.4": { "d": "AffirmTrust EV policy", "c": "AffirmTrust Premium ECC" }, +"2.16.578.1.26.1.3.3": { "d": "BuyPass EV policy", "c": "BuyPass Class 3 EV" }, +"1.3.6.1.4.1.17326.10.14.2.1.2": { "d": "Camerfirma EV policy", "c": "Camerfirma CA Root" }, +"1.3.6.1.4.1.17326.10.8.12.1.2": { "d": "Camerfirma EV policy", "c": "Camerfirma CA Root" }, +"1.3.6.1.4.1.22234.2.5.2.3.1": { "d": "CertPlus EV policy", "c": "CertPlus Class 2 Primary CA (formerly Keynectis)" }, +"1.3.6.1.4.1.6449.1.2.1.5.1": { "d": "Comodo EV policy", "c": "COMODO Certification Authority" }, +"1.3.6.1.4.1.6334.1.100.1": { "d": "Cybertrust EV policy", "c": "Cybertrust Global Root (now Verizon Business)" }, +"1.3.6.1.4.1.4788.2.202.1": { "d": "D-TRUST EV policy", "c": "D-TRUST Root Class 3 CA 2 EV 2009" }, +"2.16.840.1.114412.2.1": { "d": "DigiCert EV policy", "c": "DigiCert High Assurance EV Root CA" }, +"2.16.528.1.1001.1.1.1.12.6.1.1.1": { "d": "DigiNotar EV policy", "c": "DigiNotar Root CA" }, +"2.16.840.1.114028.10.1.2": { "d": "Entrust EV policy", "c": "Entrust Root Certification Authority" }, +"1.3.6.1.4.1.14370.1.6": { "d": "GeoTrust EV policy", "c": "GeoTrust Primary Certification Authority (formerly Equifax)" }, +"1.3.6.1.4.1.4146.1.1": { "d": "GlobalSign EV policy", "c": "GlobalSign" }, +"2.16.840.1.114413.1.7.23.3": { "d": "GoDaddy EV policy", "c": "GoDaddy Class 2 Certification Authority (formerly ValiCert)" }, +"1.3.6.1.4.1.14777.6.1.1": { "d": "Izenpe EV policy", "c": "Certificado de Servidor Seguro SSL EV" }, +"1.3.6.1.4.1.14777.6.1.2": { "d": "Izenpe EV policy", "c": "Certificado de Sede Electronica EV" }, +"1.3.6.1.4.1.782.1.2.1.8.1": { "d": "Network Solutions EV policy", "c": "Network Solutions Certificate Authority" }, +"1.3.6.1.4.1.8024.0.2.100.1.2": { "d": "QuoVadis EV policy", "c": "QuoVadis Root CA 2" }, +"1.2.392.200091.100.721.1": { "d": "Security Communication (SECOM) EV policy", "c": "Security Communication RootCA1" }, +"2.16.840.1.114414.1.7.23.3": { "d": "Starfield EV policy", "c": "Starfield Class 2 Certification Authority" }, +"1.3.6.1.4.1.23223.1.1.1": { "d": "StartCom EV policy", "c": "StartCom Certification Authority" }, +"2.16.756.1.89.1.2.1.1": { "d": "SwissSign EV policy", "c": "SwissSign Gold CA - G2" }, +"1.3.6.1.4.1.7879.13.24.1": { "d": "T-TeleSec EV policy", "c": "T-TeleSec GlobalRoot Class 3" }, +"2.16.840.1.113733.1.7.48.1": { "d": "Thawte EV policy", "c": "Thawte Premium Server CA" }, +"2.16.840.1.114404.1.1.2.4.1": { "d": "TrustWave EV policy", "c": "TrustWave CA, formerly SecureTrust, before that XRamp" }, +"1.3.6.1.4.1.40869.1.1.22.3": { "d": "TWCA EV policy", "c": "TWCA Root Certification Authority" }, +"2.16.840.1.113733.1.7.23.6": { "d": "VeriSign EV policy", "c": "VeriSign Class 3 Public Primary Certification Authority" }, +"2.16.840.1.114171.500.9": { "d": "Wells Fargo EV policy", "c": "Wells Fargo WellsSecure Public Root Certificate Authority" }, +"END": "" +} \ No newline at end of file diff --git a/client/emv/emvjson.c b/client/emv/emvjson.c index e56ecbb7..116e16da 100644 --- a/client/emv/emvjson.c +++ b/client/emv/emvjson.c @@ -264,6 +264,23 @@ bool HexToBuffer(const char *errormsg, const char *hexvalue, uint8_t * buffer, s return true; } +int JsonLoadStr(json_t *root, char *path, char *value) { + if (!value) + return 1; + + 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; + + memcpy(value, strval, strlen(strval)); + + return 0; +} + int JsonLoadBufAsHex(json_t *elm, char *path, uint8_t *data, size_t maxbufferlen, size_t *datalen) { if (datalen) *datalen = 0; diff --git a/client/emv/emvjson.h b/client/emv/emvjson.h index 9c6eda5e..996b611d 100644 --- a/client/emv/emvjson.h +++ b/client/emv/emvjson.h @@ -33,6 +33,7 @@ extern int JsonSaveTLVTreeElm(json_t *elm, char *path, struct tlvdb *tlvdbelm, b extern int JsonSaveTLVTree(json_t *root, json_t *elm, char *path, struct tlvdb *tlvdbelm); +extern int JsonLoadStr(json_t *root, char *path, char *value); extern int JsonLoadBufAsHex(json_t *elm, char *path, uint8_t *data, size_t maxbufferlen, size_t *datalen); extern bool ParamLoadFromJson(struct tlvdb *tlv); diff --git a/client/fido/additional_ca.c b/client/fido/additional_ca.c new file mode 100644 index 00000000..f529e99b --- /dev/null +++ b/client/fido/additional_ca.c @@ -0,0 +1,63 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2018 Merlok +// +// 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. +//----------------------------------------------------------------------------- +// CA PEM certificates +//----------------------------------------------------------------------------- +// + +#include "additional_ca.h" +#include "mbedtls/certs.h" + +#define GLOBALSIGN_CA \ +"-----BEGIN CERTIFICATE-----\r\n" \ +"MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG\r\n" \ +"A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv\r\n" \ +"b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw\r\n" \ +"MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i\r\n" \ +"YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT\r\n" \ +"aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ\r\n" \ +"jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp\r\n" \ +"xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp\r\n" \ +"1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG\r\n" \ +"snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ\r\n" \ +"U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8\r\n" \ +"9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E\r\n" \ +"BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B\r\n" \ +"AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz\r\n" \ +"yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE\r\n" \ +"38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP\r\n" \ +"AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad\r\n" \ +"DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME\r\n" \ +"HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\r\n" \ +"-----END CERTIFICATE-----\r\n" + +// Name: Yubico U2F Root CA Serial 457200631 +// Issued: 2014-08-01 +#define YUBICO_CA \ +"-----BEGIN CERTIFICATE-----\r\n" \ +"MIIDHjCCAgagAwIBAgIEG0BT9zANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNZ\r\n" \ +"dWJpY28gVTJGIFJvb3QgQ0EgU2VyaWFsIDQ1NzIwMDYzMTAgFw0xNDA4MDEwMDAw\r\n" \ +"MDBaGA8yMDUwMDkwNDAwMDAwMFowLjEsMCoGA1UEAxMjWXViaWNvIFUyRiBSb290\r\n" \ +"IENBIFNlcmlhbCA0NTcyMDA2MzEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\r\n" \ +"AoIBAQC/jwYuhBVlqaiYWEMsrWFisgJ+PtM91eSrpI4TK7U53mwCIawSDHy8vUmk\r\n" \ +"5N2KAj9abvT9NP5SMS1hQi3usxoYGonXQgfO6ZXyUA9a+KAkqdFnBnlyugSeCOep\r\n" \ +"8EdZFfsaRFtMjkwz5Gcz2Py4vIYvCdMHPtwaz0bVuzneueIEz6TnQjE63Rdt2zbw\r\n" \ +"nebwTG5ZybeWSwbzy+BJ34ZHcUhPAY89yJQXuE0IzMZFcEBbPNRbWECRKgjq//qT\r\n" \ +"9nmDOFVlSRCt2wiqPSzluwn+v+suQEBsUjTGMEd25tKXXTkNW21wIWbxeSyUoTXw\r\n" \ +"LvGS6xlwQSgNpk2qXYwf8iXg7VWZAgMBAAGjQjBAMB0GA1UdDgQWBBQgIvz0bNGJ\r\n" \ +"hjgpToksyKpP9xv9oDAPBgNVHRMECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAN\r\n" \ +"BgkqhkiG9w0BAQsFAAOCAQEAjvjuOMDSa+JXFCLyBKsycXtBVZsJ4Ue3LbaEsPY4\r\n" \ +"MYN/hIQ5ZM5p7EjfcnMG4CtYkNsfNHc0AhBLdq45rnT87q/6O3vUEtNMafbhU6kt\r\n" \ +"hX7Y+9XFN9NpmYxr+ekVY5xOxi8h9JDIgoMP4VB1uS0aunL1IGqrNooL9mmFnL2k\r\n" \ +"LVVee6/VR6C5+KSTCMCWppMuJIZII2v9o4dkoZ8Y7QRjQlLfYzd3qGtKbw7xaF1U\r\n" \ +"sG/5xUb/Btwb2X2g4InpiB/yt/3CpQXpiWX/K4mBvUKiGn05ZsqeY1gx4g0xLBqc\r\n" \ +"U9psmyPzK+Vsgw2jeRQ5JlKDyqE0hebfC1tvFu0CCrJFcw==\r\n" \ +"-----END CERTIFICATE-----\r\n" + +/* Concatenation of all additional CA certificates in PEM format if available */ +const char additional_ca_pem[] = GLOBALSIGN_CA YUBICO_CA; +const size_t additional_ca_pem_len = sizeof(additional_ca_pem); diff --git a/client/fido/additional_ca.h b/client/fido/additional_ca.h new file mode 100644 index 00000000..85658303 --- /dev/null +++ b/client/fido/additional_ca.h @@ -0,0 +1,21 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2018 Merlok +// +// 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. +//----------------------------------------------------------------------------- +// CA PEM certificates +//----------------------------------------------------------------------------- +// + +#ifndef __ADDITIONAL_CA_H__ +#define __ADDITIONAL_CA_H__ + +#include + +// Concatenation of all CA certificates in PEM format if available +extern const char additional_ca_pem[]; +extern const size_t additional_ca_pem_len; + +#endif /* __ADDITIONAL_CA_H__ */ diff --git a/client/obj/fido/.dummy b/client/obj/fido/.dummy new file mode 100644 index 00000000..e69de29b diff --git a/client/ui.c b/client/ui.c index 50a6ec7d..3a1e42c5 100644 --- a/client/ui.c +++ b/client/ui.c @@ -16,6 +16,7 @@ #include #include #include +#include "util.h" #endif #include "ui.h" @@ -32,6 +33,77 @@ static char *logfilename = "proxmark3.log"; #ifndef EXTERNAL_PRINTANDLOG static pthread_mutex_t print_lock = PTHREAD_MUTEX_INITIALIZER; +void PrintAndLogEx(logLevel_t level, char *fmt, ...) { + + // skip debug messages if client debugging is turned off i.e. 'DATA SETDEBUG 0' +// if (g_debugMode == 0 && level == DEBUG) +// return; + + char buffer[MAX_PRINT_BUFFER] = {0}; + char buffer2[MAX_PRINT_BUFFER] = {0}; + char prefix[20] = {0}; + char *token = NULL; + int size = 0; + // {NORMAL, SUCCESS, INFO, FAILED, WARNING, ERR, DEBUG} + static char *prefixes[7] = { "", "", "INFO: ", "FAILED: ", "WARNING: ", "ERROR: ", "#: "}; + + switch( level ) { + case FAILED: + strncpy(prefix,_RED_(FAILED: ), sizeof(prefix)-1); + break; + case DEBUG: + strncpy(prefix,_BLUE_(#: ), sizeof(prefix)-1); + break; + case SUCCESS: + strncpy(prefix,_GREEN_( ), sizeof(prefix)-1); + break; + case WARNING: + strncpy(prefix,_CYAN_(WARNING: ), sizeof(prefix)-1); + break; + default: + strncpy(prefix, prefixes[level], sizeof(prefix)-1); + break; + } + + va_list args; + va_start(args, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, args); + va_end(args); + + // no prefixes for normal + if ( level == NORMAL ) { + PrintAndLog(buffer); + return; + } + + if (strchr(buffer, '\n')) { + + const char delim[2] = "\n"; + + // line starts with newline + if (buffer[0] == '\n') + PrintAndLog(""); + + token = strtok(buffer, delim); + + while (token != NULL) { + + size = strlen(buffer2); + + if (strlen(token)) + snprintf(buffer2+size, sizeof(buffer2)-size, "%s%s\n", prefix, token); + else + snprintf(buffer2+size, sizeof(buffer2)-size, "\n"); + + token = strtok(NULL, delim); + } + PrintAndLog(buffer2); + } else { + snprintf(buffer2, sizeof(buffer2), "%s%s", prefix, buffer); + PrintAndLog(buffer2); + } +} + void PrintAndLog(char *fmt, ...) { char *saved_line; diff --git a/client/ui.h b/client/ui.h index 1273fe9e..0ea738b7 100644 --- a/client/ui.h +++ b/client/ui.h @@ -14,11 +14,15 @@ #include #include +#define MAX_PRINT_BUFFER 2048 +typedef enum logLevel {NORMAL, SUCCESS, INFO, FAILED, WARNING, ERR, DEBUG} logLevel_t; + void ShowGui(void); void HideGraphWindow(void); void ShowGraphWindow(void); void RepaintGraphWindow(void); void PrintAndLog(char *fmt, ...); +void PrintAndLogEx(logLevel_t level, char *fmt, ...); void SetLogFilename(char *fn); void SetFlushAfterWrite(bool flush_after_write); diff --git a/client/util.c b/client/util.c index c6d5f0d6..242a8a28 100644 --- a/client/util.c +++ b/client/util.c @@ -110,6 +110,35 @@ void FillFileNameByUID(char *fileName, uint8_t * uid, char *ext, int byteCount) sprintf(fnameptr, "%s", ext); } +// fill buffer from structure [{uint8_t data, size_t length},...] +int FillBuffer(uint8_t *data, size_t maxDataLength, size_t *dataLength, ...) { + *dataLength = 0; + va_list valist; + va_start(valist, dataLength); + + uint8_t *vdata = NULL; + size_t vlength = 0; + do{ + vdata = va_arg(valist, uint8_t *); + if (!vdata) + break; + + vlength = va_arg(valist, size_t); + if (*dataLength + vlength > maxDataLength) { + va_end(valist); + return 1; + } + + memcpy(&data[*dataLength], vdata, vlength); + *dataLength += vlength; + + } while (vdata); + + va_end(valist); + + return 0; +} + void hex_to_buffer(const uint8_t *buf, const uint8_t *hex_data, const size_t hex_len, const size_t hex_max_len, const size_t min_str_len, const size_t spaces_between, bool uppercase) { diff --git a/client/util.h b/client/util.h index 31ad29fb..1867519e 100644 --- a/client/util.h +++ b/client/util.h @@ -35,6 +35,46 @@ #define FILE_PATH_SIZE 2000 #endif +#ifndef ARRAYLEN +# define ARRAYLEN(x) (sizeof(x)/sizeof((x)[0])) +#endif + +#if defined(__linux__) || (__APPLE__) +# define _BLUE_(s) "\x1b[34m" #s "\x1b[0m " +#else +# define _BLUE_(s) #s " " +#endif + +#if defined(__linux__) || (__APPLE__) +# define _RED_(s) "\x1b[31m" #s "\x1b[0m " +#else +# define _RED_(s) #s " " +#endif + +#if defined(__linux__) || (__APPLE__) +# define _GREEN_(s) "\x1b[32m" #s "\x1b[0m " +#else +# define _GREEN_(s) #s " " +#endif + +#if defined(__linux__) || (__APPLE__) +# define _YELLOW_(s) "\x1b[33m" #s "\x1b[0m " +#else +# define _YELLOW_(s) #s " " +#endif + +#if defined(__linux__) || (__APPLE__) +# define _MAGENTA_(s) "\x1b[35m" #s "\x1b[0m " +#else +# define _MAGENTA_(s) #s " " +#endif + +#if defined(__linux__) || (__APPLE__) +# define _CYAN_(s) "\x1b[36m" #s "\x1b[0m " +#else +# define _CYAN_(s) #s " " +#endif + extern int ukbhit(void); extern void AddLogLine(char *fileName, char *extData, char *c); @@ -43,6 +83,9 @@ extern void AddLogUint64(char *fileName, char *extData, const uint64_t data); extern void AddLogCurrentDT(char *fileName); extern void FillFileNameByUID(char *fileName, uint8_t * uid, char *ext, int byteCount); +// fill buffer from structure [{uint8_t data, size_t length},...] +extern int FillBuffer(uint8_t *data, size_t maxDataLength, size_t *dataLength, ...); + extern void hex_to_buffer(const uint8_t *buf, const uint8_t *hex_data, const size_t hex_len, const size_t hex_max_len, const size_t min_str_len, const size_t spaces_between, bool uppercase); diff --git a/common/mbedtls/Makefile b/common/mbedtls/Makefile index 3e57fdac..a9a85098 100644 --- a/common/mbedtls/Makefile +++ b/common/mbedtls/Makefile @@ -29,6 +29,7 @@ mbedtls_SOURCES = \ arc4.c \ pk.c \ pk_wrap.c \ + pkwrite.c \ pkcs5.c \ pkcs12.c \ pkparse.c \ diff --git a/common/mbedtls/pkwrite.c b/common/mbedtls/pkwrite.c new file mode 100644 index 00000000..8e0bb2e6 --- /dev/null +++ b/common/mbedtls/pkwrite.c @@ -0,0 +1,517 @@ +/* + * Public Key layer for writing key files and structures + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PK_WRITE_C) + +#include "mbedtls/pk.h" +#include "mbedtls/asn1write.h" +#include "mbedtls/oid.h" + +#include + +#if defined(MBEDTLS_RSA_C) +#include "mbedtls/rsa.h" +#endif +#if defined(MBEDTLS_ECP_C) +#include "mbedtls/ecp.h" +#endif +#if defined(MBEDTLS_ECDSA_C) +#include "mbedtls/ecdsa.h" +#endif +#if defined(MBEDTLS_PEM_WRITE_C) +#include "mbedtls/pem.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#if defined(MBEDTLS_RSA_C) +/* + * RSAPublicKey ::= SEQUENCE { + * modulus INTEGER, -- n + * publicExponent INTEGER -- e + * } + */ +static int pk_write_rsa_pubkey( unsigned char **p, unsigned char *start, + mbedtls_rsa_context *rsa ) +{ + int ret; + size_t len = 0; + mbedtls_mpi T; + + mbedtls_mpi_init( &T ); + + /* Export E */ + if ( ( ret = mbedtls_rsa_export( rsa, NULL, NULL, NULL, NULL, &T ) ) != 0 || + ( ret = mbedtls_asn1_write_mpi( p, start, &T ) ) < 0 ) + goto end_of_export; + len += ret; + + /* Export N */ + if ( ( ret = mbedtls_rsa_export( rsa, &T, NULL, NULL, NULL, NULL ) ) != 0 || + ( ret = mbedtls_asn1_write_mpi( p, start, &T ) ) < 0 ) + goto end_of_export; + len += ret; + +end_of_export: + + mbedtls_mpi_free( &T ); + if( ret < 0 ) + return( ret ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + return( (int) len ); +} +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_ECP_C) +/* + * EC public key is an EC point + */ +static int pk_write_ec_pubkey( unsigned char **p, unsigned char *start, + mbedtls_ecp_keypair *ec ) +{ + int ret; + size_t len = 0; + unsigned char buf[MBEDTLS_ECP_MAX_PT_LEN]; + + if( ( ret = mbedtls_ecp_point_write_binary( &ec->grp, &ec->Q, + MBEDTLS_ECP_PF_UNCOMPRESSED, + &len, buf, sizeof( buf ) ) ) != 0 ) + { + return( ret ); + } + + if( *p < start || (size_t)( *p - start ) < len ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *p -= len; + memcpy( *p, buf, len ); + + return( (int) len ); +} + +/* + * ECParameters ::= CHOICE { + * namedCurve OBJECT IDENTIFIER + * } + */ +static int pk_write_ec_param( unsigned char **p, unsigned char *start, + mbedtls_ecp_keypair *ec ) +{ + int ret; + size_t len = 0; + const char *oid; + size_t oid_len; + + if( ( ret = mbedtls_oid_get_oid_by_ec_grp( ec->grp.id, &oid, &oid_len ) ) != 0 ) + return( ret ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_oid( p, start, oid, oid_len ) ); + + return( (int) len ); +} +#endif /* MBEDTLS_ECP_C */ + +int mbedtls_pk_write_pubkey( unsigned char **p, unsigned char *start, + const mbedtls_pk_context *key ) +{ + int ret; + size_t len = 0; + +#if defined(MBEDTLS_RSA_C) + if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_RSA ) + MBEDTLS_ASN1_CHK_ADD( len, pk_write_rsa_pubkey( p, start, mbedtls_pk_rsa( *key ) ) ); + else +#endif +#if defined(MBEDTLS_ECP_C) + if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_ECKEY ) + MBEDTLS_ASN1_CHK_ADD( len, pk_write_ec_pubkey( p, start, mbedtls_pk_ec( *key ) ) ); + else +#endif + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); + + return( (int) len ); +} + +int mbedtls_pk_write_pubkey_der( mbedtls_pk_context *key, unsigned char *buf, size_t size ) +{ + int ret; + unsigned char *c; + size_t len = 0, par_len = 0, oid_len; + const char *oid; + + c = buf + size; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_pk_write_pubkey( &c, buf, key ) ); + + if( c - buf < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + /* + * SubjectPublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * subjectPublicKey BIT STRING } + */ + *--c = 0; + len += 1; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_BIT_STRING ) ); + + if( ( ret = mbedtls_oid_get_oid_by_pk_alg( mbedtls_pk_get_type( key ), + &oid, &oid_len ) ) != 0 ) + { + return( ret ); + } + +#if defined(MBEDTLS_ECP_C) + if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_ECKEY ) + { + MBEDTLS_ASN1_CHK_ADD( par_len, pk_write_ec_param( &c, buf, mbedtls_pk_ec( *key ) ) ); + } +#endif + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_algorithm_identifier( &c, buf, oid, oid_len, + par_len ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + return( (int) len ); +} + +int mbedtls_pk_write_key_der( mbedtls_pk_context *key, unsigned char *buf, size_t size ) +{ + int ret; + unsigned char *c = buf + size; + size_t len = 0; + +#if defined(MBEDTLS_RSA_C) + if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_RSA ) + { + mbedtls_mpi T; /* Temporary holding the exported parameters */ + mbedtls_rsa_context *rsa = mbedtls_pk_rsa( *key ); + + /* + * Export the parameters one after another to avoid simultaneous copies. + */ + + mbedtls_mpi_init( &T ); + + /* Export QP */ + if( ( ret = mbedtls_rsa_export_crt( rsa, NULL, NULL, &T ) ) != 0 || + ( ret = mbedtls_asn1_write_mpi( &c, buf, &T ) ) < 0 ) + goto end_of_export; + len += ret; + + /* Export DQ */ + if( ( ret = mbedtls_rsa_export_crt( rsa, NULL, &T, NULL ) ) != 0 || + ( ret = mbedtls_asn1_write_mpi( &c, buf, &T ) ) < 0 ) + goto end_of_export; + len += ret; + + /* Export DP */ + if( ( ret = mbedtls_rsa_export_crt( rsa, &T, NULL, NULL ) ) != 0 || + ( ret = mbedtls_asn1_write_mpi( &c, buf, &T ) ) < 0 ) + goto end_of_export; + len += ret; + + /* Export Q */ + if ( ( ret = mbedtls_rsa_export( rsa, NULL, NULL, + &T, NULL, NULL ) ) != 0 || + ( ret = mbedtls_asn1_write_mpi( &c, buf, &T ) ) < 0 ) + goto end_of_export; + len += ret; + + /* Export P */ + if ( ( ret = mbedtls_rsa_export( rsa, NULL, &T, + NULL, NULL, NULL ) ) != 0 || + ( ret = mbedtls_asn1_write_mpi( &c, buf, &T ) ) < 0 ) + goto end_of_export; + len += ret; + + /* Export D */ + if ( ( ret = mbedtls_rsa_export( rsa, NULL, NULL, + NULL, &T, NULL ) ) != 0 || + ( ret = mbedtls_asn1_write_mpi( &c, buf, &T ) ) < 0 ) + goto end_of_export; + len += ret; + + /* Export E */ + if ( ( ret = mbedtls_rsa_export( rsa, NULL, NULL, + NULL, NULL, &T ) ) != 0 || + ( ret = mbedtls_asn1_write_mpi( &c, buf, &T ) ) < 0 ) + goto end_of_export; + len += ret; + + /* Export N */ + if ( ( ret = mbedtls_rsa_export( rsa, &T, NULL, + NULL, NULL, NULL ) ) != 0 || + ( ret = mbedtls_asn1_write_mpi( &c, buf, &T ) ) < 0 ) + goto end_of_export; + len += ret; + + end_of_export: + + mbedtls_mpi_free( &T ); + if( ret < 0 ) + return( ret ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, buf, 0 ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, + buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + } + else +#endif /* MBEDTLS_RSA_C */ +#if defined(MBEDTLS_ECP_C) + if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_ECKEY ) + { + mbedtls_ecp_keypair *ec = mbedtls_pk_ec( *key ); + size_t pub_len = 0, par_len = 0; + + /* + * RFC 5915, or SEC1 Appendix C.4 + * + * ECPrivateKey ::= SEQUENCE { + * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), + * privateKey OCTET STRING, + * parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, + * publicKey [1] BIT STRING OPTIONAL + * } + */ + + /* publicKey */ + MBEDTLS_ASN1_CHK_ADD( pub_len, pk_write_ec_pubkey( &c, buf, ec ) ); + + if( c - buf < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + *--c = 0; + pub_len += 1; + + MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_asn1_write_len( &c, buf, pub_len ) ); + MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_BIT_STRING ) ); + + MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_asn1_write_len( &c, buf, pub_len ) ); + MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_asn1_write_tag( &c, buf, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 1 ) ); + len += pub_len; + + /* parameters */ + MBEDTLS_ASN1_CHK_ADD( par_len, pk_write_ec_param( &c, buf, ec ) ); + + MBEDTLS_ASN1_CHK_ADD( par_len, mbedtls_asn1_write_len( &c, buf, par_len ) ); + MBEDTLS_ASN1_CHK_ADD( par_len, mbedtls_asn1_write_tag( &c, buf, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0 ) ); + len += par_len; + + /* privateKey: write as MPI then fix tag */ + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf, &ec->d ) ); + *c = MBEDTLS_ASN1_OCTET_STRING; + + /* version */ + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, buf, 1 ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + } + else +#endif /* MBEDTLS_ECP_C */ + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); + + return( (int) len ); +} + +#if defined(MBEDTLS_PEM_WRITE_C) + +#define PEM_BEGIN_PUBLIC_KEY "-----BEGIN PUBLIC KEY-----\n" +#define PEM_END_PUBLIC_KEY "-----END PUBLIC KEY-----\n" + +#define PEM_BEGIN_PRIVATE_KEY_RSA "-----BEGIN RSA PRIVATE KEY-----\n" +#define PEM_END_PRIVATE_KEY_RSA "-----END RSA PRIVATE KEY-----\n" +#define PEM_BEGIN_PRIVATE_KEY_EC "-----BEGIN EC PRIVATE KEY-----\n" +#define PEM_END_PRIVATE_KEY_EC "-----END EC PRIVATE KEY-----\n" + +/* + * Max sizes of key per types. Shown as tag + len (+ content). + */ + +#if defined(MBEDTLS_RSA_C) +/* + * RSA public keys: + * SubjectPublicKeyInfo ::= SEQUENCE { 1 + 3 + * algorithm AlgorithmIdentifier, 1 + 1 (sequence) + * + 1 + 1 + 9 (rsa oid) + * + 1 + 1 (params null) + * subjectPublicKey BIT STRING } 1 + 3 + (1 + below) + * RSAPublicKey ::= SEQUENCE { 1 + 3 + * modulus INTEGER, -- n 1 + 3 + MPI_MAX + 1 + * publicExponent INTEGER -- e 1 + 3 + MPI_MAX + 1 + * } + */ +#define RSA_PUB_DER_MAX_BYTES 38 + 2 * MBEDTLS_MPI_MAX_SIZE + +/* + * RSA private keys: + * RSAPrivateKey ::= SEQUENCE { 1 + 3 + * version Version, 1 + 1 + 1 + * modulus INTEGER, 1 + 3 + MPI_MAX + 1 + * publicExponent INTEGER, 1 + 3 + MPI_MAX + 1 + * privateExponent INTEGER, 1 + 3 + MPI_MAX + 1 + * prime1 INTEGER, 1 + 3 + MPI_MAX / 2 + 1 + * prime2 INTEGER, 1 + 3 + MPI_MAX / 2 + 1 + * exponent1 INTEGER, 1 + 3 + MPI_MAX / 2 + 1 + * exponent2 INTEGER, 1 + 3 + MPI_MAX / 2 + 1 + * coefficient INTEGER, 1 + 3 + MPI_MAX / 2 + 1 + * otherPrimeInfos OtherPrimeInfos OPTIONAL 0 (not supported) + * } + */ +#define MPI_MAX_SIZE_2 MBEDTLS_MPI_MAX_SIZE / 2 + \ + MBEDTLS_MPI_MAX_SIZE % 2 +#define RSA_PRV_DER_MAX_BYTES 47 + 3 * MBEDTLS_MPI_MAX_SIZE \ + + 5 * MPI_MAX_SIZE_2 + +#else /* MBEDTLS_RSA_C */ + +#define RSA_PUB_DER_MAX_BYTES 0 +#define RSA_PRV_DER_MAX_BYTES 0 + +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_ECP_C) +/* + * EC public keys: + * SubjectPublicKeyInfo ::= SEQUENCE { 1 + 2 + * algorithm AlgorithmIdentifier, 1 + 1 (sequence) + * + 1 + 1 + 7 (ec oid) + * + 1 + 1 + 9 (namedCurve oid) + * subjectPublicKey BIT STRING 1 + 2 + 1 [1] + * + 1 (point format) [1] + * + 2 * ECP_MAX (coords) [1] + * } + */ +#define ECP_PUB_DER_MAX_BYTES 30 + 2 * MBEDTLS_ECP_MAX_BYTES + +/* + * EC private keys: + * ECPrivateKey ::= SEQUENCE { 1 + 2 + * version INTEGER , 1 + 1 + 1 + * privateKey OCTET STRING, 1 + 1 + ECP_MAX + * parameters [0] ECParameters OPTIONAL, 1 + 1 + (1 + 1 + 9) + * publicKey [1] BIT STRING OPTIONAL 1 + 2 + [1] above + * } + */ +#define ECP_PRV_DER_MAX_BYTES 29 + 3 * MBEDTLS_ECP_MAX_BYTES + +#else /* MBEDTLS_ECP_C */ + +#define ECP_PUB_DER_MAX_BYTES 0 +#define ECP_PRV_DER_MAX_BYTES 0 + +#endif /* MBEDTLS_ECP_C */ + +#define PUB_DER_MAX_BYTES RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \ + RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES +#define PRV_DER_MAX_BYTES RSA_PRV_DER_MAX_BYTES > ECP_PRV_DER_MAX_BYTES ? \ + RSA_PRV_DER_MAX_BYTES : ECP_PRV_DER_MAX_BYTES + +int mbedtls_pk_write_pubkey_pem( mbedtls_pk_context *key, unsigned char *buf, size_t size ) +{ + int ret; + unsigned char output_buf[PUB_DER_MAX_BYTES]; + size_t olen = 0; + + if( ( ret = mbedtls_pk_write_pubkey_der( key, output_buf, + sizeof(output_buf) ) ) < 0 ) + { + return( ret ); + } + + if( ( ret = mbedtls_pem_write_buffer( PEM_BEGIN_PUBLIC_KEY, PEM_END_PUBLIC_KEY, + output_buf + sizeof(output_buf) - ret, + ret, buf, size, &olen ) ) != 0 ) + { + return( ret ); + } + + return( 0 ); +} + +int mbedtls_pk_write_key_pem( mbedtls_pk_context *key, unsigned char *buf, size_t size ) +{ + int ret; + unsigned char output_buf[PRV_DER_MAX_BYTES]; + const char *begin, *end; + size_t olen = 0; + + if( ( ret = mbedtls_pk_write_key_der( key, output_buf, sizeof(output_buf) ) ) < 0 ) + return( ret ); + +#if defined(MBEDTLS_RSA_C) + if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_RSA ) + { + begin = PEM_BEGIN_PRIVATE_KEY_RSA; + end = PEM_END_PRIVATE_KEY_RSA; + } + else +#endif +#if defined(MBEDTLS_ECP_C) + if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_ECKEY ) + { + begin = PEM_BEGIN_PRIVATE_KEY_EC; + end = PEM_END_PRIVATE_KEY_EC; + } + else +#endif + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); + + if( ( ret = mbedtls_pem_write_buffer( begin, end, + output_buf + sizeof(output_buf) - ret, + ret, buf, size, &olen ) ) != 0 ) + { + return( ret ); + } + + return( 0 ); +} +#endif /* MBEDTLS_PEM_WRITE_C */ + +#endif /* MBEDTLS_PK_WRITE_C */ From 03439be30ff87187899944775a1c9aa3954baf72 Mon Sep 17 00:00:00 2001 From: Fl0-0 Date: Mon, 26 Nov 2018 08:11:11 +0100 Subject: [PATCH 021/189] =?UTF-8?q?Fix=20util.c:116:2:=20error:=20unknown?= =?UTF-8?q?=20type=20name=20=E2=80=98va=5Flist=E2=80=99=20(#722)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/util.c | 1 + 1 file changed, 1 insertion(+) diff --git a/client/util.c b/client/util.c index 242a8a28..423d14a0 100644 --- a/client/util.c +++ b/client/util.c @@ -16,6 +16,7 @@ #include #include #include +#include #ifdef _WIN32 #include From 5594c6215e9df0d8e9b77acc389be7ccdadd23e0 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Fri, 30 Nov 2018 07:45:01 +0100 Subject: [PATCH 022/189] fix "hf mf chk" flags (based on PR #700) (#718) --- client/cmdhfmf.c | 50 +++++++++++++++--------------------------------- 1 file changed, 15 insertions(+), 35 deletions(-) diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 83180e7d..c382664b 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -534,7 +534,7 @@ int CmdHF14AMfRestore(const char *Cmd) //---------------------------------------------- static void parseParamTDS(const char *Cmd, const uint8_t indx, bool *paramT, bool *paramD, uint8_t *timeout) { - char ctmp3[3] = {0}; + char ctmp3[4] = {0}; int len = param_getlength(Cmd, indx); if (len > 0 && len < 4){ param_getstr(Cmd, indx, ctmp3, sizeof(ctmp3)); @@ -1018,10 +1018,10 @@ int CmdHF14AMfChk(const char *Cmd) PrintAndLog("Usage: hf mf chk |<*card memory> [t|d|s|ss] [] []"); PrintAndLog(" * - all sectors"); PrintAndLog("card memory - 0 - MINI(320 bytes), 1 - 1K, 2 - 2K, 4 - 4K, - 1K"); - PrintAndLog("d - write keys to binary file\n"); - PrintAndLog("t - write keys to emulator memory"); - PrintAndLog("s - slow execute. timeout 1ms"); - PrintAndLog("ss- very slow execute. timeout 5ms"); + PrintAndLog("d - write keys to binary file\n"); + PrintAndLog("t - write keys to emulator memory"); + PrintAndLog("s - slow execute. timeout 1ms"); + PrintAndLog("ss - very slow execute. timeout 5ms"); PrintAndLog(" sample: hf mf chk 0 A 1234567890ab keys.dic"); PrintAndLog(" hf mf chk *1 ? t"); PrintAndLog(" hf mf chk *1 ? d"); @@ -1040,16 +1040,16 @@ int CmdHF14AMfChk(const char *Cmd) int keycnt = 0; char ctmp = 0x00; int clen = 0; - char ctmp3[3] = {0x00}; uint8_t blockNo = 0; uint8_t SectorsCnt = 0; uint8_t keyType = 0; uint64_t key64 = 0; - uint32_t timeout14a = 0; // timeout in us + // timeout in units. (ms * 106)/10 or us*0.0106 + uint8_t btimeout14a = MF_CHKKEYS_DEFTIMEOUT; // fast by default bool param3InUse = false; - int transferToEml = 0; - int createDumpFile = 0; + bool transferToEml = 0; + bool createDumpFile = 0; sector_t *e_sector = NULL; @@ -1087,33 +1087,13 @@ int CmdHF14AMfChk(const char *Cmd) }; } - // transfer to emulator & create dump file - ctmp = param_getchar(Cmd, 2); - clen = param_getlength(Cmd, 2); - if (clen == 1 && (ctmp == 't' || ctmp == 'T')) transferToEml = 1; - if (clen == 1 && (ctmp == 'd' || ctmp == 'D')) createDumpFile = 1; + parseParamTDS(Cmd, 2, &transferToEml, &createDumpFile, &btimeout14a); - param3InUse = transferToEml | createDumpFile; - - timeout14a = 500; // fast by default - // double parameters - ts, ds - clen = param_getlength(Cmd, 2); - if (clen == 2 || clen == 3){ - param_getstr(Cmd, 2, ctmp3, sizeof(ctmp3)); - ctmp = ctmp3[1]; - } - //parse - if (ctmp == 's' || ctmp == 'S') { - timeout14a = 1000; // slow - if (!param3InUse && clen == 2 && (ctmp3[1] == 's' || ctmp3[1] == 'S')) { - timeout14a = 5000; // very slow - } - if (param3InUse && clen == 3 && (ctmp3[2] == 's' || ctmp3[2] == 'S')) { - timeout14a = 5000; // very slow - } - param3InUse = true; - } + param3InUse = transferToEml | createDumpFile | (btimeout14a != MF_CHKKEYS_DEFTIMEOUT); + PrintAndLog("--chk keys. sectors:%2d, block no:%3d, key type:%c, eml:%c, dmp=%c checktimeout=%d us", + SectorsCnt, blockNo, keyType?'B':'A', transferToEml?'y':'n', createDumpFile?'y':'n', ((int)btimeout14a * 10000) / 106); + for (i = param3InUse; param_getchar(Cmd, 2 + i); i++) { if (!param_gethex(Cmd, 2 + i, keyBlock + 6 * keycnt, 12)) { if ( stKeyBlock - keycnt < 2) { @@ -1210,7 +1190,7 @@ int CmdHF14AMfChk(const char *Cmd) for (uint32_t c = 0; c < keycnt; c += max_keys) { uint32_t size = keycnt-c > max_keys ? max_keys : keycnt-c; - res = mfCheckKeysSec(SectorsCnt, keyType, timeout14a * 1.06 / 100, true, size, &keyBlock[6 * c], e_sector); // timeout is (ms * 106)/10 or us*0.0106 + res = mfCheckKeysSec(SectorsCnt, keyType, btimeout14a, true, size, &keyBlock[6 * c], e_sector); // timeout is (ms * 106)/10 or us*0.0106 if (res != 1) { if (!res) { From 6a2bd857195a0fb99342d93859f21150f666a089 Mon Sep 17 00:00:00 2001 From: Oleg Moiseenko <807634+merlokk@users.noreply.github.com> Date: Fri, 30 Nov 2018 09:43:46 +0200 Subject: [PATCH 023/189] jansson update. 2.11 to 2.12 (#724) --- client/jansson/dump.c | 12 +- client/jansson/hashtable.h | 2 +- client/jansson/hashtable_seed.c | 2 +- client/jansson/jansson.h | 45 +++--- client/jansson/jansson_private.h | 8 +- client/jansson/load.c | 8 +- client/jansson/pack_unpack.c | 231 ++++++++++++++++++------------- client/jansson/path.c | 1 - client/jansson/strbuffer.h | 2 +- client/jansson/value.c | 30 ++-- 10 files changed, 190 insertions(+), 151 deletions(-) diff --git a/client/jansson/dump.c b/client/jansson/dump.c index 8e725c93..89802c65 100644 --- a/client/jansson/dump.c +++ b/client/jansson/dump.c @@ -61,8 +61,8 @@ static int dump_to_file(const char *buffer, size_t size, void *data) static int dump_to_fd(const char *buffer, size_t size, void *data) { - int *dest = (int *)data; #ifdef HAVE_UNISTD_H + int *dest = (int *)data; if(write(*dest, buffer, size) == (ssize_t)size) return 0; #endif @@ -101,7 +101,7 @@ static int dump_indent(size_t flags, int depth, int space, json_dump_callback_t static int dump_string(const char *str, size_t len, json_dump_callback_t dump, void *data, size_t flags) { const char *pos, *end, *lim; - int32_t codepoint; + int32_t codepoint = 0; if(dump("\"", 1, data)) return -1; @@ -306,7 +306,7 @@ static int do_dump(const json_t *json, size_t flags, int depth, const char *separator; int separator_length; /* Space for "0x", double the sizeof a pointer for the hex and a terminator. */ - char key[2 + (sizeof(json) * 2) + 1]; + char loop_key[2 + (sizeof(json) * 2) + 1]; if(flags & JSON_COMPACT) { separator = ":"; @@ -318,7 +318,7 @@ static int do_dump(const json_t *json, size_t flags, int depth, } /* detect circular references */ - if (loop_check(parents, json, key, sizeof(key))) + if (loop_check(parents, json, loop_key, sizeof(loop_key))) return -1; iter = json_object_iter((json_t *)json); @@ -326,7 +326,7 @@ static int do_dump(const json_t *json, size_t flags, int depth, if(!embed && dump("{", 1, data)) return -1; if(!iter) { - hashtable_del(parents, key); + hashtable_del(parents, loop_key); return embed ? 0 : dump("}", 1, data); } if(dump_indent(flags, depth + 1, 0, dump, data)) @@ -422,7 +422,7 @@ static int do_dump(const json_t *json, size_t flags, int depth, } } - hashtable_del(parents, key); + hashtable_del(parents, loop_key); return embed ? 0 : dump("}", 1, data); } diff --git a/client/jansson/hashtable.h b/client/jansson/hashtable.h index d4c32ae0..c1128340 100644 --- a/client/jansson/hashtable.h +++ b/client/jansson/hashtable.h @@ -55,7 +55,7 @@ typedef struct hashtable { * * Returns 0 on success, -1 on error (out of memory). */ -int hashtable_init(hashtable_t *hashtable); +int hashtable_init(hashtable_t *hashtable) JANSSON_ATTRS(warn_unused_result); /** * hashtable_close - Release all resources used by a hashtable object diff --git a/client/jansson/hashtable_seed.c b/client/jansson/hashtable_seed.c index 8aed5406..540358ad 100644 --- a/client/jansson/hashtable_seed.c +++ b/client/jansson/hashtable_seed.c @@ -164,7 +164,7 @@ static int seed_from_timestamp_and_pid(uint32_t *seed) { } static uint32_t generate_seed() { - uint32_t seed; + uint32_t seed = 0; int done = 0; #if !defined(_WIN32) && defined(USE_URANDOM) diff --git a/client/jansson/jansson.h b/client/jansson/jansson.h index 86f23d17..12f638bc 100644 --- a/client/jansson/jansson.h +++ b/client/jansson/jansson.h @@ -9,7 +9,6 @@ #define JANSSON_H #include -#include #include /* for size_t */ #include @@ -22,11 +21,11 @@ extern "C" { /* version */ #define JANSSON_MAJOR_VERSION 2 -#define JANSSON_MINOR_VERSION 11 +#define JANSSON_MINOR_VERSION 12 #define JANSSON_MICRO_VERSION 0 /* Micro version is omitted if it's 0 */ -#define JANSSON_VERSION "2.11" +#define JANSSON_VERSION "2.12" /* Version as a 3-byte hex number, e.g. 0x010201 == 1.2.1. Use this for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */ @@ -40,6 +39,12 @@ extern "C" { #define JANSSON_THREAD_SAFE_REFCOUNT 1 #endif +#if defined(__GNUC__) || defined(__clang__) +#define JANSSON_ATTRS(...) __attribute__((__VA_ARGS__)) +#else +#define JANSSON_ATTRS(...) +#endif + /* types */ typedef enum { @@ -186,7 +191,7 @@ static JSON_INLINE enum json_error_code json_error_code(const json_error_t *e) { void json_object_seed(size_t seed); size_t json_object_size(const json_t *object); -json_t *json_object_get(const json_t *object, const char *key); +json_t *json_object_get(const json_t *object, const char *key) JANSSON_ATTRS(warn_unused_result); int json_object_set_new(json_t *object, const char *key, json_t *value); int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value); int json_object_del(json_t *object, const char *key); @@ -238,7 +243,7 @@ int json_object_iter_set(json_t *object, void *iter, json_t *value) } size_t json_array_size(const json_t *array); -json_t *json_array_get(const json_t *array, size_t index); +json_t *json_array_get(const json_t *array, size_t index) JANSSON_ATTRS(warn_unused_result); int json_array_set_new(json_t *array, size_t index, json_t *value); int json_array_append_new(json_t *array, json_t *value); int json_array_insert_new(json_t *array, size_t index, json_t *value); @@ -279,9 +284,9 @@ int json_real_set(json_t *real, double value); /* pack, unpack */ -json_t *json_pack(const char *fmt, ...); -json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...); -json_t *json_vpack_ex(json_error_t *error, size_t flags, const char *fmt, va_list ap); +json_t *json_pack(const char *fmt, ...) JANSSON_ATTRS(warn_unused_result); +json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...) JANSSON_ATTRS(warn_unused_result); +json_t *json_vpack_ex(json_error_t *error, size_t flags, const char *fmt, va_list ap) JANSSON_ATTRS(warn_unused_result); #define JSON_VALIDATE_ONLY 0x1 #define JSON_STRICT 0x2 @@ -292,8 +297,8 @@ int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, const char /* sprintf */ -json_t *json_sprintf(const char *fmt, ...); -json_t *json_vsprintf(const char *fmt, va_list ap); +json_t *json_sprintf(const char *fmt, ...) JANSSON_ATTRS(warn_unused_result, format(printf, 1, 2)); +json_t *json_vsprintf(const char *fmt, va_list ap) JANSSON_ATTRS(warn_unused_result, format(printf, 1, 0)); /* equality */ @@ -303,10 +308,8 @@ int json_equal(const json_t *value1, const json_t *value2); /* copying */ -json_t *json_copy(json_t *value); -json_t *json_deep_copy(const json_t *value); - -/* path */ +json_t *json_copy(json_t *value) JANSSON_ATTRS(warn_unused_result); +json_t *json_deep_copy(const json_t *value) JANSSON_ATTRS(warn_unused_result); json_t *json_path_get(const json_t *json, const char *path); int json_path_set_new(json_t *json, const char *path, json_t *value, size_t flags, json_error_t *error); @@ -327,12 +330,12 @@ int json_path_set(json_t *json, const char *path, json_t *value, size_t flags, j typedef size_t (*json_load_callback_t)(void *buffer, size_t buflen, void *data); -json_t *json_loads(const char *input, size_t flags, json_error_t *error); -json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error); -json_t *json_loadf(FILE *input, size_t flags, json_error_t *error); -json_t *json_loadfd(int input, size_t flags, json_error_t *error); -json_t *json_load_file(const char *path, size_t flags, json_error_t *error); -json_t *json_load_callback(json_load_callback_t callback, void *data, size_t flags, json_error_t *error); +json_t *json_loads(const char *input, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result); +json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result); +json_t *json_loadf(FILE *input, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result); +json_t *json_loadfd(int input, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result); +json_t *json_load_file(const char *path, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result); +json_t *json_load_callback(json_load_callback_t callback, void *data, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result); /* encoding */ @@ -350,7 +353,7 @@ json_t *json_load_callback(json_load_callback_t callback, void *data, size_t fla typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data); -char *json_dumps(const json_t *json, size_t flags); +char *json_dumps(const json_t *json, size_t flags) JANSSON_ATTRS(warn_unused_result); size_t json_dumpb(const json_t *json, char *buffer, size_t size, size_t flags); int json_dumpf(const json_t *json, FILE *output, size_t flags); int json_dumpfd(const json_t *json, int output, size_t flags); diff --git a/client/jansson/jansson_private.h b/client/jansson/jansson_private.h index 7b0985aa..083604b4 100644 --- a/client/jansson/jansson_private.h +++ b/client/jansson/jansson_private.h @@ -87,11 +87,11 @@ int jsonp_strtod(strbuffer_t *strbuffer, double *out); int jsonp_dtostr(char *buffer, size_t size, double value, int prec); /* Wrappers for custom memory functions */ -void* jsonp_malloc(size_t size); +void* jsonp_malloc(size_t size) JANSSON_ATTRS(warn_unused_result); void jsonp_free(void *ptr); -char *jsonp_strndup(const char *str, size_t length); -char *jsonp_strdup(const char *str); -char *jsonp_strndup(const char *str, size_t len); +char *jsonp_strndup(const char *str, size_t length) JANSSON_ATTRS(warn_unused_result); +char *jsonp_strdup(const char *str) JANSSON_ATTRS(warn_unused_result); +char *jsonp_strndup(const char *str, size_t len) JANSSON_ATTRS(warn_unused_result); /* Windows compatibility */ diff --git a/client/jansson/load.c b/client/jansson/load.c index 4cf3855a..7ed0e377 100644 --- a/client/jansson/load.c +++ b/client/jansson/load.c @@ -829,10 +829,8 @@ static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error) } json = jsonp_stringn_nocheck_own(value, len); - if(json) { - lex->value.string.val = NULL; - lex->value.string.len = 0; - } + lex->value.string.val = NULL; + lex->value.string.len = 0; break; } @@ -1036,8 +1034,8 @@ json_t *json_loadf(FILE *input, size_t flags, json_error_t *error) static int fd_get_func(int *fd) { - uint8_t c; #ifdef HAVE_UNISTD_H + uint8_t c; if (read(*fd, &c, 1) == 1) return c; #endif diff --git a/client/jansson/pack_unpack.c b/client/jansson/pack_unpack.c index 153f64d1..3b997766 100644 --- a/client/jansson/pack_unpack.c +++ b/client/jansson/pack_unpack.c @@ -75,6 +75,9 @@ static void next_token(scanner_t *s) return; } + if (!token(s) && !*s->fmt) + return; + t = s->fmt; s->column++; s->pos++; @@ -97,7 +100,7 @@ static void next_token(scanner_t *s) s->token.column = s->column; s->token.pos = s->pos; - t++; + if (*t) t++; s->fmt = t; } @@ -127,7 +130,7 @@ static json_t *pack(scanner_t *s, va_list *ap); /* ours will be set to 1 if jsonp_free() must be called for the result afterwards */ static char *read_string(scanner_t *s, va_list *ap, - const char *purpose, size_t *out_len, int *ours) + const char *purpose, size_t *out_len, int *ours, int optional) { char t; strbuffer_t strbuff; @@ -144,7 +147,10 @@ static char *read_string(scanner_t *s, va_list *ap, str = va_arg(*ap, const char *); if(!str) { - set_error(s, "", json_error_null_value, "NULL string argument"); + if (!optional) { + set_error(s, "", json_error_null_value, "NULL %s", purpose); + s->has_error = 1; + } return NULL; } @@ -152,19 +158,28 @@ static char *read_string(scanner_t *s, va_list *ap, if(!utf8_check_string(str, length)) { set_error(s, "", json_error_invalid_utf8, "Invalid UTF-8 %s", purpose); + s->has_error = 1; return NULL; } *out_len = length; return (char *)str; + } else if (optional) { + set_error(s, "", json_error_invalid_format, "Cannot use '%c' on optional strings", t); + s->has_error = 1; + + return NULL; } - strbuffer_init(&strbuff); + if(strbuffer_init(&strbuff)) { + set_error(s, "", json_error_out_of_memory, "Out of memory"); + s->has_error = 1; + } while(1) { str = va_arg(*ap, const char *); if(!str) { - set_error(s, "", json_error_null_value, "NULL string argument"); + set_error(s, "", json_error_null_value, "NULL %s", purpose); s->has_error = 1; } @@ -220,6 +235,7 @@ static json_t *pack_object(scanner_t *s, va_list *ap) size_t len; int ours; json_t *value; + char valueOptional; if(!token(s)) { set_error(s, "", json_error_invalid_format, "Unexpected end of format string"); @@ -231,20 +247,21 @@ static json_t *pack_object(scanner_t *s, va_list *ap) goto error; } - key = read_string(s, ap, "object key", &len, &ours); - if (!key) - s->has_error = 1; + key = read_string(s, ap, "object key", &len, &ours, 0); next_token(s); + next_token(s); + valueOptional = token(s); + prev_token(s); + value = pack(s, ap); if(!value) { if(ours) jsonp_free(key); - if(strchr("soO", token(s)) && s->next_token.token == '*') { - next_token(s); - } else { + if(valueOptional != '*') { + set_error(s, "", json_error_null_value, "NULL object value"); s->has_error = 1; } @@ -263,8 +280,6 @@ static json_t *pack_object(scanner_t *s, va_list *ap) if(ours) jsonp_free(key); - if(strchr("soO", token(s)) && s->next_token.token == '*') - next_token(s); next_token(s); } @@ -283,6 +298,7 @@ static json_t *pack_array(scanner_t *s, va_list *ap) while(token(s) != ']') { json_t *value; + char valueOptional; if(!token(s)) { set_error(s, "", json_error_invalid_format, "Unexpected end of format string"); @@ -290,11 +306,13 @@ static json_t *pack_array(scanner_t *s, va_list *ap) goto error; } + next_token(s); + valueOptional = token(s); + prev_token(s); + value = pack(s, ap); if(!value) { - if(strchr("soO", token(s)) && s->next_token.token == '*') { - next_token(s); - } else { + if(valueOptional != '*') { s->has_error = 1; } @@ -310,8 +328,6 @@ static json_t *pack_array(scanner_t *s, va_list *ap) s->has_error = 1; } - if(strchr("soO", token(s)) && s->next_token.token == '*') - next_token(s); next_token(s); } @@ -326,23 +342,97 @@ error: static json_t *pack_string(scanner_t *s, va_list *ap) { char *str; + char t; size_t len; int ours; - int nullable; + int optional; next_token(s); - nullable = token(s) == '?'; - if (!nullable) + t = token(s); + optional = t == '?' || t == '*'; + if (!optional) prev_token(s); - str = read_string(s, ap, "string", &len, &ours); - if (!str) { - return nullable ? json_null() : NULL; - } else if (ours) { - return jsonp_stringn_nocheck_own(str, len); - } else { - return json_stringn_nocheck(str, len); + str = read_string(s, ap, "string", &len, &ours, optional); + + if (!str) + return t == '?' && !s->has_error ? json_null() : NULL; + + if (s->has_error) { + /* It's impossible to reach this point if ours != 0, do not free str. */ + return NULL; } + + if (ours) + return jsonp_stringn_nocheck_own(str, len); + + return json_stringn_nocheck(str, len); +} + +static json_t *pack_object_inter(scanner_t *s, va_list *ap, int need_incref) +{ + json_t *json; + char ntoken; + + next_token(s); + ntoken = token(s); + + if (ntoken != '?' && ntoken != '*') + prev_token(s); + + json = va_arg(*ap, json_t *); + + if (json) + return need_incref ? json_incref(json) : json; + + switch (ntoken) { + case '?': + return json_null(); + case '*': + return NULL; + default: + break; + } + + set_error(s, "", json_error_null_value, "NULL object"); + s->has_error = 1; + return NULL; +} + +static json_t *pack_integer(scanner_t *s, json_int_t value) +{ + json_t *json = json_integer(value); + + if (!json) { + set_error(s, "", json_error_out_of_memory, "Out of memory"); + s->has_error = 1; + } + + return json; +} + +static json_t *pack_real(scanner_t *s, double value) +{ + /* Allocate without setting value so we can identify OOM error. */ + json_t *json = json_real(0.0); + + if (!json) { + set_error(s, "", json_error_out_of_memory, "Out of memory"); + s->has_error = 1; + + return NULL; + } + + if (json_real_set(json, value)) { + json_decref(json); + + set_error(s, "", json_error_numeric_overflow, "Invalid floating point value"); + s->has_error = 1; + + return NULL; + } + + return json; } static json_t *pack(scanner_t *s, va_list *ap) @@ -364,49 +454,19 @@ static json_t *pack(scanner_t *s, va_list *ap) return va_arg(*ap, int) ? json_true() : json_false(); case 'i': /* integer from int */ - return json_integer(va_arg(*ap, int)); + return pack_integer(s, va_arg(*ap, int)); case 'I': /* integer from json_int_t */ - return json_integer(va_arg(*ap, json_int_t)); + return pack_integer(s, va_arg(*ap, json_int_t)); case 'f': /* real */ - return json_real(va_arg(*ap, double)); + return pack_real(s, va_arg(*ap, double)); case 'O': /* a json_t object; increments refcount */ - { - int nullable; - json_t *json; - - next_token(s); - nullable = token(s) == '?'; - if (!nullable) - prev_token(s); - - json = va_arg(*ap, json_t *); - if (!json && nullable) { - return json_null(); - } else { - return json_incref(json); - } - } + return pack_object_inter(s, ap, 1); case 'o': /* a json_t object; doesn't increment refcount */ - { - int nullable; - json_t *json; - - next_token(s); - nullable = token(s) == '?'; - if (!nullable) - prev_token(s); - - json = va_arg(*ap, json_t *); - if (!json && nullable) { - return json_null(); - } else { - return json; - } - } + return pack_object_inter(s, ap, 0); default: set_error(s, "", json_error_invalid_format, "Unexpected format character '%c'", @@ -508,48 +568,34 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) if(root && strict == 1) { /* We need to check that all non optional items have been parsed */ const char *key; - int have_unrecognized_keys = 0; + /* keys_res is 1 for uninitialized, 0 for success, -1 for error. */ + int keys_res = 1; strbuffer_t unrecognized_keys; json_t *value; long unpacked = 0; - if (gotopt) { - /* We have optional keys, we need to iter on each key */ + + if (gotopt || json_object_size(root) != key_set.size) { json_object_foreach(root, key, value) { if(!hashtable_get(&key_set, key)) { unpacked++; /* Save unrecognized keys for the error message */ - if (!have_unrecognized_keys) { - strbuffer_init(&unrecognized_keys); - have_unrecognized_keys = 1; - } else { - strbuffer_append_bytes(&unrecognized_keys, ", ", 2); + if (keys_res == 1) { + keys_res = strbuffer_init(&unrecognized_keys); + } else if (!keys_res) { + keys_res = strbuffer_append_bytes(&unrecognized_keys, ", ", 2); } - strbuffer_append_bytes(&unrecognized_keys, key, strlen(key)); + + if (!keys_res) + keys_res = strbuffer_append_bytes(&unrecognized_keys, key, strlen(key)); } } - } else { - /* No optional keys, we can just compare the number of items */ - unpacked = (long)json_object_size(root) - (long)key_set.size; } if (unpacked) { - if (!gotopt) { - /* Save unrecognized keys for the error message */ - json_object_foreach(root, key, value) { - if(!hashtable_get(&key_set, key)) { - if (!have_unrecognized_keys) { - strbuffer_init(&unrecognized_keys); - have_unrecognized_keys = 1; - } else { - strbuffer_append_bytes(&unrecognized_keys, ", ", 2); - } - strbuffer_append_bytes(&unrecognized_keys, key, strlen(key)); - } - } - } set_error(s, "", json_error_end_of_input_expected, "%li object item(s) left unpacked: %s", - unpacked, strbuffer_value(&unrecognized_keys)); + unpacked, + keys_res ? "" : strbuffer_value(&unrecognized_keys)); strbuffer_close(&unrecognized_keys); goto out; } @@ -805,6 +851,7 @@ json_t *json_vpack_ex(json_error_t *error, size_t flags, value = pack(&s, &ap_copy); va_end(ap_copy); + /* This will cover all situations where s.has_error is true */ if(!value) return NULL; @@ -814,10 +861,6 @@ json_t *json_vpack_ex(json_error_t *error, size_t flags, set_error(&s, "", json_error_invalid_format, "Garbage after format string"); return NULL; } - if(s.has_error) { - json_decref(value); - return NULL; - } return value; } diff --git a/client/jansson/path.c b/client/jansson/path.c index 08f2da9f..e3098f5f 100644 --- a/client/jansson/path.c +++ b/client/jansson/path.c @@ -13,7 +13,6 @@ #include #include "jansson_private.h" - json_t *json_path_get(const json_t *json, const char *path) { static const char root_chr = '$', array_open = '['; diff --git a/client/jansson/strbuffer.h b/client/jansson/strbuffer.h index 615b7f5f..a0276d4b 100644 --- a/client/jansson/strbuffer.h +++ b/client/jansson/strbuffer.h @@ -16,7 +16,7 @@ typedef struct { size_t size; /* bytes allocated */ } strbuffer_t; -int strbuffer_init(strbuffer_t *strbuff); +int strbuffer_init(strbuffer_t *strbuff) JANSSON_ATTRS(warn_unused_result); void strbuffer_close(strbuffer_t *strbuff); void strbuffer_clear(strbuffer_t *strbuff); diff --git a/client/jansson/value.c b/client/jansson/value.c index b3b31412..3f964a04 100644 --- a/client/jansson/value.c +++ b/client/jansson/value.c @@ -652,8 +652,7 @@ static json_t *string_create(const char *value, size_t len, int own) string = jsonp_malloc(sizeof(json_string_t)); if(!string) { - if(!own) - jsonp_free(v); + jsonp_free(v); return NULL; } json_init(&string->json, JSON_STRING); @@ -768,9 +767,6 @@ static int json_string_equal(const json_t *string1, const json_t *string2) { json_string_t *s1, *s2; - if(!json_is_string(string1) || !json_is_string(string2)) - return 0; - s1 = json_to_string(string1); s2 = json_to_string(string2); return s1->length == s2->length && !memcmp(s1->value, s2->value, s1->length); @@ -780,34 +776,38 @@ static json_t *json_string_copy(const json_t *string) { json_string_t *s; - if(!json_is_string(string)) - return NULL; - s = json_to_string(string); return json_stringn_nocheck(s->value, s->length); } json_t *json_vsprintf(const char *fmt, va_list ap) { + json_t *json = NULL; int length; char *buf; va_list aq; va_copy(aq, ap); length = vsnprintf(NULL, 0, fmt, ap); - if (length == 0) - return json_string(""); + if (length == 0) { + json = json_string(""); + goto out; + } buf = jsonp_malloc(length + 1); if (!buf) - return NULL; + goto out; vsnprintf(buf, length + 1, fmt, aq); if (!utf8_check_string(buf, length)) { jsonp_free(buf); - return NULL; + goto out; } - return jsonp_stringn_nocheck_own(buf, length); + json = jsonp_stringn_nocheck_own(buf, length); + +out: + va_end(aq); + return json; } json_t *json_sprintf(const char *fmt, ...) { @@ -1044,8 +1044,6 @@ json_t *json_copy(json_t *json) default: return NULL; } - - return NULL; } json_t *json_deep_copy(const json_t *json) @@ -1073,6 +1071,4 @@ json_t *json_deep_copy(const json_t *json) default: return NULL; } - - return NULL; } From 994f21fe017fd0f2373399ff7cfb9843bfd303df Mon Sep 17 00:00:00 2001 From: Fl0-0 Date: Fri, 30 Nov 2018 09:03:44 +0100 Subject: [PATCH 024/189] Fix format-truncation warning, missing string.h inclusion and strnlen warning (#723) * Fix format-truncation warning, missing string.h inclusion and strnlen warning * Dynamic string width field --- client/crypto/asn1dump.c | 3 +++ client/ui.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/client/crypto/asn1dump.c b/client/crypto/asn1dump.c index 60799fc8..9570be20 100644 --- a/client/crypto/asn1dump.c +++ b/client/crypto/asn1dump.c @@ -8,11 +8,14 @@ // asn.1 dumping //----------------------------------------------------------------------------- +#define _POSIX_C_SOURCE 200809L // need for strnlen() + #include "asn1dump.h" #include #include #include #include +#include #include #include #include diff --git a/client/ui.c b/client/ui.c index 3a1e42c5..5c9d7424 100644 --- a/client/ui.c +++ b/client/ui.c @@ -99,7 +99,7 @@ void PrintAndLogEx(logLevel_t level, char *fmt, ...) { } PrintAndLog(buffer2); } else { - snprintf(buffer2, sizeof(buffer2), "%s%s", prefix, buffer); + snprintf(buffer2, sizeof(buffer2), "%s%.*s", prefix, MAX_PRINT_BUFFER - 20, buffer); PrintAndLog(buffer2); } } From 7b6e32053373740516833b1a228a0ad01bb14bd2 Mon Sep 17 00:00:00 2001 From: florianrock <45316656+florianrock@users.noreply.github.com> Date: Fri, 30 Nov 2018 17:42:22 +0100 Subject: [PATCH 025/189] HitagS Improvements (#721) * support of HITAG S standard communication mode * fixed wrong AC (Anti Collision) decoding * support of block read mode * fixed wrong uid send when using simulation * support of communication mode parameter (client is backward compatible) * support of start-page parameter (important for some weird tags) (client is backward compatible) * also expect pages if tag memory size in con0 is 11 (we got some tags) * corrected hitagS reader cmd help --- CHANGELOG.md | 7 + armsrc/BigBuf.c | 7 +- armsrc/appmain.c | 7 +- armsrc/apps.h | 5 +- armsrc/hitagS.c | 1713 +++++++++++++++++++++++++------------------ client/cmdlfhitag.c | 63 +- include/hitagS.h | 4 +- include/usb_cmd.h | 1 + 8 files changed, 1074 insertions(+), 733 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b0073f34..7d8993dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,13 +7,20 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ### Changed - Changed hf mfp security. Now it works in all the modes. (drHatson) - `hf fido` - show/check DER certificate and signatures (Merlok) +- Changed `lf hitag reader 0x ... ` - to select first page to read and tagmode (0=STANDARD, 1=ADVANCED, 2=FAST_ADVANCED) +- Accept hitagS con0 tags with memory bits set to 11 and handle like 2048 tag ### Fixed +- AC-Mode decoding for HitagS +- Wrong UID at HitagS simulation ### Added +- Support Standard Communication Mode in HITAG S - Added `hf emv scan` - commands for scan EMV card and dump data to json file (Merlok) - `hf mfp` group of commands (Merlok) - Added `hf fido` - FIDO U2F authenticator commands https://fidoalliance.org/ (Merlok) +- Added `lf hitag reader 03` - read block (instead of pages) +- Added `lf hitag reader 04` - read block (instead of pages) ## [v3.1.0][2018-10-10] diff --git a/armsrc/BigBuf.c b/armsrc/BigBuf.c index 4fe97b46..4b1264b6 100644 --- a/armsrc/BigBuf.c +++ b/armsrc/BigBuf.c @@ -229,8 +229,11 @@ int LogTraceHitag(const uint8_t * btBytes, int iBits, int iSamples, uint32_t dwP uint8_t *trace = BigBuf_get_addr(); uint16_t iLen = nbytes(iBits); + // Return when trace is full - if (traceLen + sizeof(rsamples) + sizeof(dwParity) + sizeof(iBits) + iLen > BigBuf_max_traceLen()) return false; + if (traceLen + sizeof(rsamples) + sizeof(dwParity) + sizeof(iBits) + iLen > BigBuf_max_traceLen()) { + return false; + } //Hitag traces appear to use this traceformat: // 32 bits timestamp (little endian,Highest Bit used as readerToTag flag) @@ -238,6 +241,8 @@ int LogTraceHitag(const uint8_t * btBytes, int iBits, int iSamples, uint32_t dwP // 8 bits size (number of bits in the trace entry, not number of bytes) // y Bytes data + + rsamples += iSamples; trace[traceLen++] = ((rsamples >> 0) & 0xff); trace[traceLen++] = ((rsamples >> 8) & 0xff); diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 573a3a71..35c9e5bf 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1086,10 +1086,13 @@ void UsbPacketReceived(uint8_t *packet, int len) SimulateHitagSTag((bool)c->arg[0],(byte_t*)c->d.asBytes); break; case CMD_TEST_HITAGS_TRACES:// Tests every challenge within the given file - check_challenges((bool)c->arg[0],(byte_t*)c->d.asBytes); + check_challenges_cmd((bool)c->arg[0], (byte_t*)c->d.asBytes, (uint8_t)c->arg[1]); break; case CMD_READ_HITAG_S://Reader for only Hitag S tags, args = key or challenge - ReadHitagS((hitag_function)c->arg[0],(hitag_data*)c->d.asBytes); + ReadHitagSCmd((hitag_function)c->arg[0], (hitag_data*)c->d.asBytes, (uint8_t)c->arg[1], (uint8_t)c->arg[2], false); + break; + case CMD_READ_HITAG_S_BLK: + ReadHitagSCmd((hitag_function)c->arg[0], (hitag_data*)c->d.asBytes, (uint8_t)c->arg[1], (uint8_t)c->arg[2], true); break; case CMD_WR_HITAG_S://writer for Hitag tags args=data to write,page and key or challenge if ((hitag_function)c->arg[0] < 10) { diff --git a/armsrc/apps.h b/armsrc/apps.h index 6f728c61..6af22b57 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -180,10 +180,11 @@ void ReaderHitag(hitag_function htf, hitag_data* htd); void WriterHitag(hitag_function htf, hitag_data* htd, int page); //hitagS.h +void ReadHitagSCmd(hitag_function htf, hitag_data* htd, uint64_t startPage, uint64_t tagMode, bool readBlock); void SimulateHitagSTag(bool tag_mem_supplied, byte_t* data); -void ReadHitagS(hitag_function htf, hitag_data* htd); void WritePageHitagS(hitag_function htf, hitag_data* htd,int page); -void check_challenges(bool file_given, byte_t* data); +void check_challenges_cmd(bool file_given, byte_t* data, uint64_t tagMode); + // cmd.h diff --git a/armsrc/hitagS.c b/armsrc/hitagS.c index f6ba0c6b..5fa6a9a1 100644 --- a/armsrc/hitagS.c +++ b/armsrc/hitagS.c @@ -156,112 +156,112 @@ void calc_crc(unsigned char * crc, unsigned char data, unsigned char Bitcount) { } while (--Bitcount); } + static void hitag_send_bit(int bit) { LED_A_ON(); // Reset clock for the next bit AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; switch (m) { - case AC2K: - if (bit == 0) { - // AC Coding --__ - HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 32) - ; - LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 64) - ; - } else { - // AC coding -_-_ - HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 16) - ; - LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 32) - ; - HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 48) - ; - LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 64) - ;; - } - LED_A_OFF(); - break; - case AC4K: - if (bit == 0) { - // AC Coding --__ - HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * HITAG_T_TAG_HALF_PERIOD) - ; - LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * HITAG_T_TAG_FULL_PERIOD) - ; - } else { - // AC coding -_-_ - HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 8) - ; - LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 16) - ; - HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 24) - ; - LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 32) - ; - } - LED_A_OFF(); - break; - case MC4K: - if (bit == 0) { - // Manchester: Unloaded, then loaded |__--| - LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 16) - ; - HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 32) - ; - } else { - // Manchester: Loaded, then unloaded |--__| - HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 16) - ; - LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 32) - ; - } - LED_A_OFF(); - break; - case MC8K: - if (bit == 0) { - // Manchester: Unloaded, then loaded |__--| - LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 8) - ; - HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 16) - ; - } else { - // Manchester: Loaded, then unloaded |--__| - HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 8) - ; - LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * 16) - ; - } - LED_A_OFF(); - break; - default: - break; + case AC2K: + if (bit == 0) { + // AC Coding --__ + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 32) + ; + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 64) + ; + } else { + // AC coding -_-_ + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 16) + ; + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 32) + ; + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 48) + ; + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 64) + ;; + } + LED_A_OFF(); + break; + case AC4K: + if (bit == 0) { + // AC Coding --__ + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * HITAG_T_TAG_HALF_PERIOD) + ; + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * HITAG_T_TAG_FULL_PERIOD) + ; + } else { + // AC coding -_-_ + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 8) + ; + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 16) + ; + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 24) + ; + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 32) + ; + } + LED_A_OFF(); + break; + case MC4K: + if (bit == 0) { + // Manchester: Unloaded, then loaded |__--| + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 16) + ; + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 32) + ; + } else { + // Manchester: Loaded, then unloaded |--__| + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 16) + ; + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 32) + ; + } + LED_A_OFF(); + break; + case MC8K: + if (bit == 0) { + // Manchester: Unloaded, then loaded |__--| + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 8) + ; + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 16) + ; + } else { + // Manchester: Loaded, then unloaded |--__| + HIGH(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 8) + ; + LOW(GPIO_SSC_DOUT); + while (AT91C_BASE_TC0->TC_CV < T0 * 16) + ; + } + LED_A_OFF(); + break; + default: + break; } } -static void hitag_send_frame(const byte_t* frame, size_t frame_len) { +static void hitag_tag_send_frame(const byte_t* frame, size_t frame_len) { // Send start of frame - for (size_t i = 0; i < sof_bits; i++) { hitag_send_bit(1); } @@ -331,12 +331,12 @@ static void hitag_reader_send_bit(int bit) { } static void hitag_reader_send_frame(const byte_t* frame, size_t frame_len) { -// Send the content of the frame + // Send the content of the frame for (size_t i = 0; i < frame_len; i++) { if (frame[0] == 0xf8) { //Dbprintf("BIT: %d",(frame[i / 8] >> (7 - (i % 8))) & 1); } - hitag_reader_send_bit((frame[i / 8] >> (7 - (i % 8))) & 1); + hitag_reader_send_bit(((frame[i / 8] >> (7 - (i % 8))) & 1)); } // Send EOF AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; @@ -349,6 +349,485 @@ static void hitag_reader_send_frame(const byte_t* frame, size_t frame_len) { LOW(GPIO_SSC_DOUT); } +static void hitag_decode_frame_MC(int bitRate, int sofBits, byte_t* rx, size_t* rxlenOrg, int* response, int rawMod[], int rawLen) { + size_t rxlen = 0; + bool bSkip = true; + int lastbit = 1; + int tag_sof = 0; + int timing = 1; + if (bitRate == 8) { + timing = 2; + } + + for (int i=0; i < rawLen; i++) { + int ra = rawMod[i]; + if (ra >= HITAG_T_EOF) { + if (rxlen != 0) { + //DbpString("wierd1?"); + } + tag_sof = sofBits; + + // Capture the T0 periods that have passed since last communication or field drop (reset) + // We always recieve a 'one' first, which has the falling edge after a half period |-_| + *response = ra - HITAG_T_TAG_HALF_PERIOD; + } else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF / timing) { + tag_sof=0; + // Manchester coding example |-_|_-|-_| (101) + rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); + rxlen++; + rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); + rxlen++; + } else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF / timing) { + tag_sof=0; + // Manchester coding example |_-|...|_-|-_| (0...01) + rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); + rxlen++; + // We have to skip this half period at start and add the 'one' the second time + if (!bSkip) { + rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); + rxlen++; + } + lastbit = !lastbit; + bSkip = !bSkip; + } else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF / timing) { + // Manchester coding example |_-|_-| (00) or |-_|-_| (11) + if (tag_sof) { + // Ignore bits that are transmitted during SOF + tag_sof--; + } else { + // bit is same as last bit + rx[rxlen / 8] |= lastbit << (7 - (rxlen % 8)); + rxlen++; + } + } else { + // Ignore wierd value, is to small to mean anything + } + } + *rxlenOrg = rxlen; +} + +/* +static void hitag_decode_frame_AC2K_rising(byte_t* rx, size_t* rxlenOrg, int* response, int rawMod[], int rawLen) { + int tag_sof = 1; //skip start of frame + size_t rxlen = 0; + + for (int i=0; i < rawLen; i++) { + int ra = rawMod[i]; + if (ra >= HITAG_T_EOF) { + if (rxlen != 0) { + //DbpString("wierd1?"); + } + // Capture the T0 periods that have passed since last communication or field drop (reset) + // We always recieve a 'one' first, which has the falling edge after a half period |-_| + tag_sof = 1; + *response = ra - HITAG_T_TAG_HALF_PERIOD; + } else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { + // AC coding example |--__|--__| means 0 + rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); + rxlen++; + if (rawMod[i+1] == 0) { //TODO: this is weird - may we miss one capture with current configuration + rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); + rxlen++; + i++; //drop next capture + } + } else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { + if (tag_sof) { + // Ignore bits that are transmitted during SOF + tag_sof--; + } else { + // AC coding example |-_-_|-_-_| which means 1 + //check if another high is coming (only -_-_ = 1) except end of the frame (support 0) + if (rawMod[i+1] == 0 || rawMod[i+1] >= HITAG_T_TAG_CAPTURE_TWO_HALF) { + rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); + rxlen++; + i++; //drop next capture + } else { + Dbprintf("got weird high - %d,%d", ra, rawMod[i+1]); + } + } + } else { + // Ignore wierd value, is to small to mean anything + } + } + *rxlenOrg = rxlen; +} +*/ + +static void hitag_decode_frame_AC(int bitRate, int sofBits, byte_t* rx, size_t* rxlenOrg, int* response, int rawMod[], int rawLen) { + int tag_sof = 1; + size_t rxlen = 0; + int timing = 1; + if (bitRate == 4) { + timing = 2; + } + + + for (int i=0; i < rawLen; i++) { + int ra = rawMod[i]; + if (ra >= HITAG_T_EOF) { + if (rxlen != 0) { + //DbpString("wierd1?"); + } + + // Capture the T0 periods that have passed since last communication or field drop (reset) + // We always recieve a 'one' first, which has the falling edge after a half period |-_| + tag_sof = sofBits; + *response = ra - HITAG_T_TAG_HALF_PERIOD; + } else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF / timing) { + tag_sof=0; + + // AC coding example |--__|--__| means 0 + rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); + rxlen++; + } else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF / timing) { + tag_sof=0; + + if (rawMod[i-1] >= HITAG_T_TAG_CAPTURE_THREE_HALF / timing) { + //treat like HITAG_T_TAG_CAPTURE_TWO_HALF + if (rawMod[i+1] >= HITAG_T_TAG_CAPTURE_TWO_HALF / timing) { + rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); + rxlen++; + i++; //drop next capture + } else { + Dbprintf("got weird value - %d,%d", ra, rawMod[i+1]); + } + } else { + //treat like HITAG_T_TAG_CAPTURE_FOUR_HALF + rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); + rxlen++; + } + } else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF / timing) { + if (tag_sof) { + // Ignore bits that are transmitted during SOF + tag_sof--; + } else { + // AC coding example |-_-_|-_-_| which means 1 + //check if another high is coming (only -_-_ = 1) except end of the frame (support 0) + if (rawMod[i+1] == 0 || rawMod[i+1] >= HITAG_T_TAG_CAPTURE_TWO_HALF / timing) { + rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); + rxlen++; + i++; //drop next capture + } else { + Dbprintf("got weird value - %d,%d", ra, rawMod[i+1]); + } + } + } else { + // Ignore wierd value, is to small to mean anything + } + } + *rxlenOrg = rxlen; +} + +static void hitag_receive_frame(byte_t* rx, size_t* rxlen, int* response) { + int rawMod[200] = {0}; + int rawLen = 0; + int i = 0; + int sofBits = 0; + + m = MC4K; + if (tag.pstate == READY) { + switch (tag.mode) { + case STANDARD: + m = AC2K; + sofBits = 1; + break; + case ADVANCED: + m = AC2K; + sofBits = 5; //3 sof bits but 5 captures + break; + case FAST_ADVANCED: + m = AC4K; + sofBits = 5; //3 sof bits but 5 captures + break; + default: + break; + } + } else { + switch (tag.mode) { + case STANDARD: + m = MC4K; + sofBits = 0; //in theory 1 + break; + case ADVANCED: + m = MC4K; + sofBits = 5; //in theory 6 + break; + case FAST_ADVANCED: + m = MC8K; + sofBits = 5; //in theory 6 + break; + default: + break; + } + } + + //rising AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_RISING | AT91C_TC_ABETRG | AT91C_TC_LDRA_RISING; + AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_FALLING | AT91C_TC_ABETRG | AT91C_TC_LDRA_FALLING; + + + //first capture timing values + while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_WAIT_MAX ) { + // Check if rising edge in modulation is detected + if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { + // Retrieve the new timing values + int ra = (AT91C_BASE_TC1->TC_RA / T0); + + LED_B_ON(); + // Reset timer every frame, we have to capture the last edge for timing + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + //AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + + if (rawLen >= 200) { //avoid exception + break; + } + rawMod[rawLen] = ra; + rawLen++; + + // We can break this loop if we received the last bit from a frame + if (AT91C_BASE_TC1->TC_CV > T0 * HITAG_T_EOF) { + if (rawLen > 2) { + if (DEBUG >= 2) { Dbprintf("AT91C_BASE_TC1->TC_CV > T0 * HITAG_T_EOF breaking (%d)", rawLen); } + break; + } + } + } + } + + if (DEBUG >= 2) { + for (i=0; i < rawLen; i+=20) { + Dbprintf("raw modulation: - %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", + rawMod[i],rawMod[i+1],rawMod[i+2],rawMod[i+3], rawMod[i+4],rawMod[i+5],rawMod[i+6],rawMod[i+7], + rawMod[i+8],rawMod[i+9],rawMod[i+10],rawMod[i+11], rawMod[i+12],rawMod[i+13],rawMod[i+14],rawMod[i+15], + rawMod[i+16],rawMod[i+17],rawMod[i+18],rawMod[i+19] + ); + } + } + + switch (m) { + // DATA | 1 | 0 | 1 | 1 | 0 | + // Manchester |--__|__--|--__|--__|__--| + // Anti Collision |-_-_|--__|-_-_|-_-_|--__| + // |<-->| + // | T | + case AC2K: + if (DEBUG >= 2) { Dbprintf("decoding frame with modulation AC2K"); } + hitag_decode_frame_AC(2, sofBits, rx, rxlen, response, rawMod, rawLen); + break; + case AC4K: + if (DEBUG >= 2) { Dbprintf("decoding frame with modulation AC4K"); } + hitag_decode_frame_AC(4, sofBits, rx, rxlen, response, rawMod, rawLen); + break; + case MC4K: + if (DEBUG >= 2) { Dbprintf("decoding frame with modulation MC4K"); } + hitag_decode_frame_MC(4, sofBits, rx, rxlen, response, rawMod, rawLen); + break; + case MC8K: + if (DEBUG >= 2) { Dbprintf("decoding frame with modulation MC8K"); } + hitag_decode_frame_MC(8, sofBits, rx, rxlen, response, rawMod, rawLen); + break; + } + + LED_B_OFF(); + if (DEBUG >= 2) { + int rb[200] = {0}; int z = 0; + for (i = 0; i < 16; i++) { for (int j = 0; j < 8; j++) { + rb[z] = 0; + if ((rx[i] & ((1 << 7) >> j)) != 0) { rb[z] = 1; } + z++; + } } + for (i=0; i < z; i+=8) { + Dbprintf("raw bit: - %d%d%d%d%d%d%d%d", rb[i],rb[i+1],rb[i+2],rb[i+3],rb[i+4],rb[i+5],rb[i+6],rb[i+7] ); + } + } +} + +static void hitag_start_auth(byte_t* tx, size_t* txlen) { + *txlen = 5; + switch (tag.mode) { + case STANDARD: + //00110 - 0x30 - STANDARD MODE + memcpy(tx, "\x30", nbytes(*txlen)); + break; + case ADVANCED: + //11000 - 0xc0 - Advance Mode + memcpy(tx, "\xc0", nbytes(*txlen)); + break; + case FAST_ADVANCED: + //TODO! + break; + default: //STANDARD MODE + memcpy(tx, "\x30", nbytes(*txlen)); + break; + } + tag.pstate = READY; + tag.tstate = NO_OP; +} + +static int hitag_read_page(hitag_function htf, uint64_t key, byte_t* rx, size_t* rxlen, byte_t* tx, size_t* txlen, int pageNum) { + int i, j, z; + int response_bit[200]; + unsigned char mask = 1; + unsigned char crc; + unsigned char pageData[32]; + + if (pageNum >= tag.max_page) { + return -1; + } + if (tag.pstate == SELECTED && tag.tstate == NO_OP && *rxlen > 0) { + //send read request + tag.tstate = READING_PAGE; + *txlen = 20; + crc = CRC_PRESET; + tx[0] = 0xc0 + (pageNum / 16); + calc_crc(&crc, tx[0], 8); + calc_crc(&crc, 0x00 + ((pageNum % 16) * 16), 4); + tx[1] = 0x00 + ((pageNum % 16) * 16) + (crc / 16); + tx[2] = 0x00 + (crc % 16) * 16; + } else if (tag.pstate == SELECTED && tag.tstate == READING_PAGE && *rxlen > 0) { + //save received data + z = 0; + for (i = 0; i < 4; i++) { + for (j = 0; j < 8; j++) { + response_bit[z] = 0; + if ((rx[i] & ((mask << 7) >> j)) != 0) { + response_bit[z] = 1; + } + if (z < 32) { + pageData[z] = response_bit[z]; + } + + z++; + } + } + for (i = 0; i < 4; i++) { + tag.pages[pageNum][i] = 0x0; + } + for (i = 0; i < 4; i++) { + tag.pages[pageNum][i] += ((pageData[i * 8] << 7) | (pageData[1 + (i * 8)] << 6) | + (pageData[2 + (i * 8)] << 5) | (pageData[3 + (i * 8)] << 4) | + (pageData[4 + (i * 8)] << 3) | (pageData[5 + (i * 8)] << 2) | + (pageData[6 + (i * 8)] + << 1) | pageData[7 + (i * 8)]); + } + if (tag.auth && tag.LKP && pageNum == 1) { + Dbprintf("Page[%2d]: %02X %02X %02X %02X", pageNum, pwdh0, + tag.pages[pageNum][2], tag.pages[pageNum][1], tag.pages[pageNum][0]); + } else { + Dbprintf("Page[%2d]: %02X %02X %02X %02X", pageNum, + tag.pages[pageNum][3], tag.pages[pageNum][2], + tag.pages[pageNum][1], tag.pages[pageNum][0]); + } + + + //display key and password if possible + if (pageNum == 1 && tag.auth == 1 && tag.LKP) { + if (htf == 02) { //RHTS_KEY + Dbprintf("Page[ 2]: %02X %02X %02X %02X", + (byte_t)(key >> 8) & 0xff, + (byte_t) key & 0xff, pwdl1, pwdl0); + Dbprintf("Page[ 3]: %02X %02X %02X %02X", + (byte_t)(key >> 40) & 0xff, + (byte_t)(key >> 32) & 0xff, + (byte_t)(key >> 24) & 0xff, + (byte_t)(key >> 16) & 0xff); + } else { + //if the authentication is done with a challenge the key and password are unknown + Dbprintf("Page[ 2]: __ __ __ __"); + Dbprintf("Page[ 3]: __ __ __ __"); + } + } + + *txlen = 20; + crc = CRC_PRESET; + tx[0] = 0xc0 + ((pageNum+1) / 16); + calc_crc(&crc, tx[0], 8); + calc_crc(&crc, 0x00 + (((pageNum+1) % 16) * 16), 4); + tx[1] = 0x00 + (((pageNum+1) % 16) * 16) + (crc / 16); + tx[2] = 0x00 + (crc % 16) * 16; + + return 1; + } + return 0; +} + +static int hitag_read_block(hitag_function htf, uint64_t key, byte_t* rx, size_t* rxlen, byte_t* tx, size_t* txlen, int blockNum) { + int i, j, z; + int response_bit[200]; + unsigned char mask = 1; + unsigned char crc; + unsigned char blockData[128]; + + if (blockNum+4 >= tag.max_page) { //block always = 4 pages + return -1; + } + + if (tag.pstate == SELECTED && tag.tstate == NO_OP && *rxlen > 0) { + //send read request + tag.tstate = READING_BLOCK; + *txlen = 20; + crc = CRC_PRESET; + tx[0] = 0xd0 + (blockNum / 16); + calc_crc(&crc, tx[0], 8); + calc_crc(&crc, 0x00 + ((blockNum % 16) * 16), 4); + tx[1] = 0x00 + ((blockNum % 16) * 16) + (crc / 16); + tx[2] = 0x00 + (crc % 16) * 16; + } else if (tag.pstate == SELECTED && tag.tstate == READING_BLOCK && *rxlen > 0) { + //save received data + z = 0; + for (i = 0; i < 16; i++) { + for (j = 0; j < 8; j++) { + response_bit[z] = 0; + if ((rx[i] & ((mask << 7) >> j)) != 0) { + response_bit[z] = 1; + } + if (z < 128) { + blockData[z] = response_bit[z]; + } + z++; + } + } + + for (z = 0; z < 4; z++) { //4 pages + for (i = 0; i < 4; i++) { + tag.pages[blockNum+z][i] = 0x0; + } + } + for (z = 0; z < 4; z++) { //4 pages + for (i = 0; i < 4; i++) { + j = (i * 8) + (z*32); //bit in page + pageStart + tag.pages[blockNum+z][i] = ((blockData[j] << 7) | (blockData[1 + j] << 6) | + (blockData[2 + j] << 5) | (blockData[3 + j] << 4) | + (blockData[4 + j] << 3) | (blockData[5 + j] << 2) | + (blockData[6 + j] << 1) | blockData[7 + j]); + } + } + if (DEBUG) { + for (z = 0; z < 4; z++) { + Dbprintf("Page[%2d]: %02X %02X %02X %02X", blockNum+z, + tag.pages[blockNum+z][3], tag.pages[blockNum+z][2], + tag.pages[blockNum+z][1], tag.pages[blockNum+z][0]); + } + } + Dbprintf("Block[%2d]: %02X %02X %02X %02X - %02X %02X %02X %02X - %02X %02X %02X %02X - %02X %02X %02X %02X", blockNum, + tag.pages[blockNum][3], tag.pages[blockNum][2], tag.pages[blockNum][1], tag.pages[blockNum][0], + tag.pages[blockNum+1][3], tag.pages[blockNum+1][2], tag.pages[blockNum+1][1], tag.pages[blockNum+1][0], + tag.pages[blockNum+2][3], tag.pages[blockNum+2][2], tag.pages[blockNum+2][1], tag.pages[blockNum+2][0], + tag.pages[blockNum+3][3], tag.pages[blockNum+3][2], tag.pages[blockNum+3][1], tag.pages[blockNum+3][0]); + + *txlen = 20; + crc = CRC_PRESET; + tx[0] = 0xd0 + ((blockNum+4) / 16); + calc_crc(&crc, tx[0], 8); + calc_crc(&crc, 0x00 + (((blockNum+4) % 16) * 16), 4); + tx[1] = 0x00 + (((blockNum+4) % 16) * 16) + (crc / 16); + tx[2] = 0x00 + (crc % 16) * 16; + + return 1; + } + return 0; +} + + /* * to check if the right uid was selected */ @@ -380,44 +859,83 @@ static void hitagS_handle_reader_command(byte_t* rx, const size_t rxlen, u64 state; unsigned char crc; -// Copy the (original) received frame how it is send over the air + // Copy the (original) received frame how it is send over the air memcpy(rx_air, rx, nbytes(rxlen)); -// Reset the transmission frame length + // Reset the transmission frame length *txlen = 0; -// Try to find out which command was send by selecting on length (in bits) + // Try to find out which command was send by selecting on length (in bits) switch (rxlen) { - case 5: { - //UID request with a selected response protocol mode - tag.pstate = READY; - tag.tstate = NO_OP; - if ((rx[0] & 0xf0) == 0x30) { - tag.mode = STANDARD; - sof_bits = 1; - m = AC2K; - } - if ((rx[0] & 0xf0) == 0xc0) { - tag.mode = ADVANCED; - sof_bits = 3; - m = AC2K; - } - - if ((rx[0] & 0xf0) == 0xd0) { - tag.mode = FAST_ADVANCED; - sof_bits = 3; - m = AC4K; - } - //send uid as a response - *txlen = 32; - for (i = 0; i < 4; i++) - tx[i] = (tag.uid >> (24 - (i * 8))) & 0xff; - } - break; - case 45: { - //select command from reader received - if (check_select(rx, tag.uid) == 1) { - //if the right tag was selected + case 5: { + //UID request with a selected response protocol mode + tag.pstate = READY; + tag.tstate = NO_OP; + if ((rx[0] & 0xf0) == 0x30) { + Dbprintf("recieved uid request in Standard Mode"); + tag.mode = STANDARD; + sof_bits = 1; + m = AC2K; + } + if ((rx[0] & 0xf0) == 0xc0) { + Dbprintf("recieved uid request in ADVANCE Mode"); + tag.mode = ADVANCED; + sof_bits = 3; + m = AC2K; + } + if ((rx[0] & 0xf0) == 0xd0) { + Dbprintf("recieved uid request in FAST_ADVANCE Mode"); + tag.mode = FAST_ADVANCED; + sof_bits = 3; + m = AC4K; + } + //send uid as a response *txlen = 32; - switch (tag.mode) { + for (i = 0; i < 4; i++) { + tx[i] = (tag.uid >> (24 - (i * 8))) & 0xff; + } + } + break; + case 45: { + //select command from reader received + if (check_select(rx, tag.uid) == 1) { + //if the right tag was selected + *txlen = 32; + switch (tag.mode) { + case STANDARD: + Dbprintf("uid selected in Standard Mode"); + sof_bits = 1; + m = MC4K; + break; + case ADVANCED: + Dbprintf("uid selected in ADVANCE Mode"); + sof_bits = 6; + m = MC4K; + break; + case FAST_ADVANCED: + Dbprintf("uid selected in FAST_ADVANCE Mode"); + sof_bits = 6; + m = MC8K; + break; + default: + break; + } + + //send configuration + tx[0] = tag.pages[1][3]; + tx[1] = tag.pages[1][2]; + tx[2] = tag.pages[1][1]; + tx[3] = 0xff; + if (tag.mode != STANDARD) { + *txlen = 40; + crc = CRC_PRESET; + for (i = 0; i < 4; i++) + calc_crc(&crc, tx[i], 8); + tx[4] = crc; + } + } + } + break; + case 64: { + switch (tag.mode) { case STANDARD: sof_bits = 1; m = MC4K; @@ -432,53 +950,23 @@ static void hitagS_handle_reader_command(byte_t* rx, const size_t rxlen, break; default: break; - } - - //send configuration - for (i = 0; i < 4; i++) - tx[i] = (tag.pages[0][1] >> (i * 8)) & 0xff; - tx[3] = 0xff; - if (tag.mode != STANDARD) { - *txlen = 40; - crc = CRC_PRESET; - for (i = 0; i < 4; i++) - calc_crc(&crc, tx[i], 8); - tx[4] = crc; - } } - } - break; - case 64: { //challenge message received Dbprintf("Challenge for UID: %X", temp_uid); temp2++; - *txlen = 32; state = hitag2_init(rev64(tag.key), rev32(tag.pages[0][0]), rev32(((rx[3] << 24) + (rx[2] << 16) + (rx[1] << 8) + rx[0]))); Dbprintf( ",{0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X}", rx[0], rx[1], rx[2], rx[3], rx[4], rx[5], rx[6], rx[7]); - switch (tag.mode) { - case STANDARD: - sof_bits = 1; - m = MC4K; - break; - case ADVANCED: - sof_bits = 6; - m = MC4K; - break; - case FAST_ADVANCED: - sof_bits = 6; - m = MC8K; - break; - default: - break; + + for (i = 0; i < 4; i++) { + hitag2_byte(&state); } - for (i = 0; i < 4; i++) - hitag2_byte(&state); + *txlen = 32; //send con2,pwdh0,pwdl0,pwdl1 encrypted as a response - tx[0] = hitag2_byte(&state) ^ ((tag.pages[0][1] >> 16) & 0xff); + tx[0] = hitag2_byte(&state) ^ tag.pages[1][1]; tx[1] = hitag2_byte(&state) ^ tag.pwdh0; tx[2] = hitag2_byte(&state) ^ tag.pwdl0; tx[3] = hitag2_byte(&state) ^ tag.pwdl1; @@ -486,33 +974,22 @@ static void hitagS_handle_reader_command(byte_t* rx, const size_t rxlen, //add crc8 *txlen = 40; crc = CRC_PRESET; - calc_crc(&crc, ((tag.pages[0][1] >> 16) & 0xff), 8); + calc_crc(&crc, tag.pages[1][1], 8); calc_crc(&crc, tag.pwdh0, 8); calc_crc(&crc, tag.pwdl0, 8); calc_crc(&crc, tag.pwdl1, 8); tx[4] = (crc ^ hitag2_byte(&state)); } - /* - * some readers do not allow to authenticate multiple times in a row with the same tag. - * use this to change the uid between authentications. - */ - - /* - if (temp2 % 2 == 0) { - tag.uid = 0x11223344; - tag.pages[0][0] = 0x44332211; - } else { - tag.uid = 0x55667788; - tag.pages[0][0] = 0x88776655; - } - */ } case 40: //data received to be written if (tag.tstate == WRITING_PAGE_DATA) { tag.tstate = NO_OP; - tag.pages[page_to_be_written / 4][page_to_be_written % 4] = (rx[0] - << 0) + (rx[1] << 8) + (rx[2] << 16) + (rx[3] << 24); + tag.pages[page_to_be_written][0] = rx[3]; + tag.pages[page_to_be_written][1] = rx[2]; + tag.pages[page_to_be_written][2] = rx[1]; + tag.pages[page_to_be_written][3] = rx[0]; + //send ack *txlen = 2; tx[0] = 0x40; @@ -534,8 +1011,11 @@ static void hitagS_handle_reader_command(byte_t* rx, const size_t rxlen, break; } } else if (tag.tstate == WRITING_BLOCK_DATA) { - tag.pages[page_to_be_written / 4][page_to_be_written % 4] = (rx[0] - << 24) + (rx[1] << 16) + (rx[2] << 8) + rx[3]; + tag.pages[page_to_be_written][0] = rx[0]; + tag.pages[page_to_be_written][1] = rx[1]; + tag.pages[page_to_be_written][2] = rx[2]; + tag.pages[page_to_be_written][3] = rx[3]; + //send ack *txlen = 2; tx[0] = 0x40; @@ -565,15 +1045,16 @@ static void hitagS_handle_reader_command(byte_t* rx, const size_t rxlen, break; case 20: { //write page, write block, read page or read block command received - if ((rx[0] & 0xf0) == 0xc0) //read page - { + if ((rx[0] & 0xf0) == 0xc0) { //read page //send page data page = ((rx[0] & 0x0f) * 16) + ((rx[1] & 0xf0) / 16); + Dbprintf("reading page %d", page); *txlen = 32; - tx[0] = (tag.pages[page / 4][page % 4]) & 0xff; - tx[1] = (tag.pages[page / 4][page % 4] >> 8) & 0xff; - tx[2] = (tag.pages[page / 4][page % 4] >> 16) & 0xff; - tx[3] = (tag.pages[page / 4][page % 4] >> 24) & 0xff; + tx[0] = tag.pages[page][0]; + tx[1] = tag.pages[page][1]; + tx[2] = tag.pages[page][2]; + tx[3] = tag.pages[page][3]; + if (tag.LKP && page == 1) tx[3] = 0xff; @@ -608,34 +1089,34 @@ static void hitagS_handle_reader_command(byte_t* rx, const size_t rxlen, sof_bits = 0; *txlen = 0; } - } else if ((rx[0] & 0xf0) == 0xd0) //read block - { + } else if ((rx[0] & 0xf0) == 0xd0) { //read block page = ((rx[0] & 0x0f) * 16) + ((rx[1] & 0xf0) / 16); + Dbprintf("reading block %d", page); *txlen = 32 * 4; //send page,...,page+3 data for (i = 0; i < 4; i++) { - tx[0 + i * 4] = (tag.pages[page / 4][page % 4]) & 0xff; - tx[1 + i * 4] = (tag.pages[page / 4][page % 4] >> 8) & 0xff; - tx[2 + i * 4] = (tag.pages[page / 4][page % 4] >> 16) & 0xff; - tx[3 + i * 4] = (tag.pages[page / 4][page % 4] >> 24) & 0xff; + tx[0 + (i * 4)] = tag.pages[page][0]; + tx[1 + (i * 4)] = tag.pages[page][1]; + tx[2 + (i * 4)] = tag.pages[page][2]; + tx[3 + (i * 4)] = tag.pages[page][3]; page++; } switch (tag.mode) { - case STANDARD: - sof_bits = 1; - m = MC4K; - break; - case ADVANCED: - sof_bits = 6; - m = MC4K; - break; - case FAST_ADVANCED: - sof_bits = 6; - m = MC8K; - break; - default: - break; + case STANDARD: + sof_bits = 1; + m = MC4K; + break; + case ADVANCED: + sof_bits = 6; + m = MC4K; + break; + case FAST_ADVANCED: + sof_bits = 6; + m = MC8K; + break; + default: + break; } if (tag.mode != STANDARD) { @@ -651,8 +1132,7 @@ static void hitagS_handle_reader_command(byte_t* rx, const size_t rxlen, sof_bits = 0; *txlen = 0; } - } else if ((rx[0] & 0xf0) == 0x80) //write page - { + } else if ((rx[0] & 0xf0) == 0x80) { //write page page = ((rx[0] & 0x0f) * 16) + ((rx[1] & 0xf0) / 16); switch (tag.mode) { @@ -683,8 +1163,7 @@ static void hitagS_handle_reader_command(byte_t* rx, const size_t rxlen, tag.tstate = WRITING_PAGE_DATA; } - } else if ((rx[0] & 0xf0) == 0x90) //write block - { + } else if ((rx[0] & 0xf0) == 0x90) { //write block page = ((rx[0] & 0x0f) * 6) + ((rx[1] & 0xf0) / 16); switch (tag.mode) { case STANDARD: @@ -722,13 +1201,14 @@ static void hitagS_handle_reader_command(byte_t* rx, const size_t rxlen, } } + /* * to autenticate to a tag with the given key or challenge */ -static int hitagS_handle_tag_auth(hitag_function htf,uint64_t key, uint64_t NrAr, byte_t* rx, const size_t rxlen, byte_t* tx, - size_t* txlen) { +static int hitagS_handle_tag_auth(hitag_function htf,uint64_t key, uint64_t NrAr, byte_t* rx, + const size_t rxlen, byte_t* tx, size_t* txlen) { byte_t rx_air[HITAG_FRAME_LEN]; - int response_bit[200]; + int response_bit[200] = {0}; int i, j, z, k; unsigned char mask = 1; unsigned char uid[32]; @@ -740,7 +1220,11 @@ static int hitagS_handle_tag_auth(hitag_function htf,uint64_t key, uint64_t NrAr memcpy(rx_air, rx, nbytes(rxlen)); *txlen = 0; - if (tag.pstate == READY && rxlen >= 67) { + if (DEBUG) { + Dbprintf("START hitagS_handle_tag_auth - rxlen: %d, tagstate=%d", rxlen, (int)tag.pstate); + } + + if (tag.pstate == READY && rxlen >= 32) { //received uid if(end==true) { Dbprintf("authentication failed!"); @@ -755,13 +1239,10 @@ static int hitagS_handle_tag_auth(hitag_function htf,uint64_t key, uint64_t NrAr z++; } } - k = 0; - for (i = 5; i < z; i += 2) { - uid[k] = response_bit[i]; - k++; - if (k > 31) - break; + for (i = 0; i < 32; i++) { + uid[i] = response_bit[i]; } + uid1 = (uid[0] << 7) | (uid[1] << 6) | (uid[2] << 5) | (uid[3] << 4) | (uid[4] << 3) | (uid[5] << 2) | (uid[6] << 1) | uid[7]; uid2 = (uid[8] << 7) | (uid[9] << 6) | (uid[10] << 5) | (uid[11] << 4) @@ -769,34 +1250,36 @@ static int hitagS_handle_tag_auth(hitag_function htf,uint64_t key, uint64_t NrAr uid3 = (uid[16] << 7) | (uid[17] << 6) | (uid[18] << 5) | (uid[19] << 4) | (uid[20] << 3) | (uid[21] << 2) | (uid[22] << 1) | uid[23]; uid4 = (uid[24] << 7) | (uid[25] << 6) | (uid[26] << 5) | (uid[27] << 4) - | (uid[28] << 3) | (uid[29] << 2) | (uid[30] << 1) | uid[31]; - if (DEBUG) - Dbprintf("UID: %02X %02X %02X %02X", uid1, uid2, uid3, uid4); + | (uid[28] << 3) | (uid[29] << 2) | (uid[30] << 1) | uid[31]; + Dbprintf("UID: %02X %02X %02X %02X", uid1, uid2, uid3, uid4); tag.uid = (uid4 << 24 | uid3 << 16 | uid2 << 8 | uid1); //select uid - *txlen = 45; crc = CRC_PRESET; calc_crc(&crc, 0x00, 5); calc_crc(&crc, uid1, 8); calc_crc(&crc, uid2, 8); calc_crc(&crc, uid3, 8); calc_crc(&crc, uid4, 8); + Dbprintf("crc: %02X", crc); + + //resetting response bit for (i = 0; i < 100; i++) { response_bit[i] = 0; } - for (i = 0; i < 5; i++) { - response_bit[i] = 0; - } + + //skip the first 5 for (i = 5; i < 37; i++) { response_bit[i] = uid[i - 5]; } + //add crc value for (j = 0; j < 8; j++) { response_bit[i] = 0; if ((crc & ((mask << 7) >> j)) != 0) response_bit[i] = 1; i++; } + k = 0; for (i = 0; i < 6; i++) { tx[i] = (response_bit[k] << 7) | (response_bit[k + 1] << 6) @@ -805,63 +1288,78 @@ static int hitagS_handle_tag_auth(hitag_function htf,uint64_t key, uint64_t NrAr | (response_bit[k + 6] << 1) | response_bit[k + 7]; k += 8; } + *txlen = 45; tag.pstate = INIT; - } else if (tag.pstate == INIT && rxlen == 44) { + } else if (tag.pstate == INIT && rxlen > 24) { // received configuration after select command z = 0; - for (i = 0; i < 6; i++) { + for (i = 0; i < 4; i++) { for (j = 0; j < 8; j++) { response_bit[z] = 0; - if ((rx[i] & ((mask << 7) >> j)) != 0) + if ((rx[i] & ((mask << 7) >> j)) != 0) { response_bit[z] = 1; + } z++; } } - conf_pages[0] = ((response_bit[4] << 7) | (response_bit[5] << 6) - | (response_bit[6] << 5) | (response_bit[7] << 4) - | (response_bit[8] << 3) | (response_bit[9] << 2) - | (response_bit[10] << 1) | response_bit[11]); - //check wich memorysize this tag has - if (response_bit[10] == 0 && response_bit[11] == 0) - tag.max_page = 32 / 32; - if (response_bit[10] == 0 && response_bit[11] == 1) - tag.max_page = 256 / 32; - if (response_bit[10] == 1 && response_bit[11] == 0) - tag.max_page = 2048 / 32; - conf_pages[1] = ((response_bit[12] << 7) | (response_bit[13] << 6) - | (response_bit[14] << 5) | (response_bit[15] << 4) - | (response_bit[16] << 3) | (response_bit[17] << 2) - | (response_bit[18] << 1) | response_bit[19]); - tag.auth = response_bit[12]; - tag.TTFC = response_bit[13]; - //tag.TTFDR in response_bit[14] and response_bit[15] - //tag.TTFM in response_bit[16] and response_bit[17] - tag.LCON = response_bit[18]; - tag.LKP = response_bit[19]; - conf_pages[2] = ((response_bit[20] << 7) | (response_bit[21] << 6) - | (response_bit[22] << 5) | (response_bit[23] << 4) - | (response_bit[24] << 3) | (response_bit[25] << 2) - | (response_bit[26] << 1) | response_bit[27]); - tag.LCK7 = response_bit[20]; - tag.LCK6 = response_bit[21]; - tag.LCK5 = response_bit[22]; - tag.LCK4 = response_bit[23]; - tag.LCK3 = response_bit[24]; - tag.LCK2 = response_bit[25]; - tag.LCK1 = response_bit[26]; - tag.LCK0 = response_bit[27]; - if (DEBUG) - Dbprintf("conf0: %02X conf1: %02X conf2: %02X", conf_pages[0], - conf_pages[1], conf_pages[2]); + //check wich memorysize this tag has + //CON0 + if (response_bit[6] == 0 && response_bit[7] == 0) + tag.max_page = 32 / 32; + if (response_bit[6] == 0 && response_bit[7] == 1) + tag.max_page = 256 / 32; + if (response_bit[6] == 1 && response_bit[7] == 0) + tag.max_page = 2048 / 32; + if (response_bit[6] == 1 && response_bit[7] == 1) //reserved but some tags got this setting + tag.max_page = 2048 / 32; + + //CON1 + tag.auth = response_bit[8]; + tag.TTFC = response_bit[9]; + //tag.TTFDR in response_bit[10] and response_bit[11] + //tag.TTFM in response_bit[12] and response_bit[13] + tag.LCON = response_bit[14]; + tag.LKP = response_bit[15]; + + //CON2 + tag.LCK7 = response_bit[16]; + tag.LCK6 = response_bit[17]; + tag.LCK5 = response_bit[18]; + tag.LCK4 = response_bit[19]; + tag.LCK3 = response_bit[20]; + tag.LCK2 = response_bit[21]; + tag.LCK1 = response_bit[22]; + tag.LCK0 = response_bit[23]; + + if (DEBUG) { + conf_pages[0] = ((response_bit[0] << 7) | (response_bit[1] << 6) + | (response_bit[2] << 5) | (response_bit[3] << 4) + | (response_bit[4] << 3) | (response_bit[5] << 2) + | (response_bit[6] << 1) | response_bit[7]); + conf_pages[1] = ((response_bit[8] << 7) | (response_bit[9] << 6) + | (response_bit[10] << 5) | (response_bit[11] << 4) + | (response_bit[12] << 3) | (response_bit[13] << 2) + | (response_bit[14] << 1) | response_bit[15]); + conf_pages[2] = ((response_bit[16] << 7) | (response_bit[17] << 6) + | (response_bit[18] << 5) | (response_bit[19] << 4) + | (response_bit[20] << 3) | (response_bit[21] << 2) + | (response_bit[22] << 1) | response_bit[23]); + Dbprintf("conf0: %02X conf1: %02X conf2: %02X", conf_pages[0], conf_pages[1], conf_pages[2]); + Dbprintf("tag.max_page: %d, tag.auth: %d", tag.max_page, tag.auth); + } + if (tag.auth == 1) { //if the tag is in authentication mode try the key or challenge *txlen = 64; if(end!=true){ if(htf==02||htf==04){ //RHTS_KEY //WHTS_KEY - state = hitag2_init(rev64(key), rev32(tag.uid), - rev32(rnd)); - + state = hitag2_init(rev64(key), rev32(tag.uid), rev32(rnd)); + /* + Dbprintf("key: %02X %02X\n\n", key, rev64(key)); + Dbprintf("tag.uid: %02X %02X\n\n", tag.uid, rev32(tag.uid)); + Dbprintf("rnd: %02X %02X\n\n", rnd, rev32(rnd)); + */ for (i = 0; i < 4; i++) { auth_ks[i] = hitag2_byte(&state) ^ 0xff; } @@ -892,14 +1390,8 @@ static int hitagS_handle_tag_auth(hitag_function htf,uint64_t key, uint64_t NrAr tag.pstate = SELECTED; } - } else if (tag.pstate == AUTHENTICATE && rxlen == 44) { + } else if (tag.pstate == AUTHENTICATE && rxlen >= 32) { //encrypted con2,password received. - crc = CRC_PRESET; - calc_crc(&crc, 0x80, 1); - calc_crc(&crc, ((rx[0] & 0x0f) * 16 + ((rx[1] & 0xf0) / 16)), 8); - calc_crc(&crc, ((rx[1] & 0x0f) * 16 + ((rx[2] & 0xf0) / 16)), 8); - calc_crc(&crc, ((rx[2] & 0x0f) * 16 + ((rx[3] & 0xf0) / 16)), 8); - calc_crc(&crc, ((rx[3] & 0x0f) * 16 + ((rx[4] & 0xf0) / 16)), 8); if (DEBUG) { Dbprintf("UID:::%X", tag.uid); Dbprintf("RND:::%X", rnd); @@ -909,30 +1401,26 @@ static int hitagS_handle_tag_auth(hitag_function htf,uint64_t key, uint64_t NrAr pwdh0=0; pwdl0=0; pwdl1=0; - if(htf==02 || htf==04){ //RHTS_KEY //WHTS_KEY - { + if(htf==02 || htf==04) { //RHTS_KEY //WHTS_KEY state = hitag2_init(rev64(key), rev32(tag.uid), rev32(rnd)); - for (i = 0; i < 5; i++) + for (i = 0; i < 5; i++) { hitag2_byte(&state); - pwdh0 = ((rx[1] & 0x0f) * 16 + ((rx[2] & 0xf0) / 16)) - ^ hitag2_byte(&state); - pwdl0 = ((rx[2] & 0x0f) * 16 + ((rx[3] & 0xf0) / 16)) - ^ hitag2_byte(&state); - pwdl1 = ((rx[3] & 0x0f) * 16 + ((rx[4] & 0xf0) / 16)) - ^ hitag2_byte(&state); + } + pwdh0 = ((rx[1] & 0x0f) * 16 + ((rx[2] & 0xf0) / 16)) ^ hitag2_byte(&state); + pwdl0 = ((rx[2] & 0x0f) * 16 + ((rx[3] & 0xf0) / 16)) ^ hitag2_byte(&state); + pwdl1 = ((rx[3] & 0x0f) * 16 + ((rx[4] & 0xf0) / 16)) ^ hitag2_byte(&state); + if (DEBUG) { + Dbprintf("pwdh0 %02X pwdl0 %02X pwdl1 %02X", pwdh0, pwdl0, pwdl1); + } } - - if (DEBUG) - Dbprintf("pwdh0 %02X pwdl0 %02X pwdl1 %02X", pwdh0, pwdl0, pwdl1); - - - //Dbprintf("%X %02X", rnd, ((rx[4] & 0x0f) * 16) + ((rx[5] & 0xf0) / 16)); - //rnd += 1; - } tag.pstate = SELECTED; //tag is now ready for read/write commands } + + if (DEBUG) { + Dbprintf("END hitagS_handle_tag_auth - tagstate=%d", (int)tag.pstate); + } + return 0; - } /* @@ -949,6 +1437,7 @@ void SimulateHitagSTag(bool tag_mem_supplied, byte_t* data) { byte_t txbuf[HITAG_FRAME_LEN]; byte_t* tx = txbuf; size_t txlen = 0; + uint8_t con0, con1, con2; BigBuf_free(); // Clean up trace and prepare it for storing frames @@ -960,102 +1449,104 @@ void SimulateHitagSTag(bool tag_mem_supplied, byte_t* data) { tag.pstate = READY; tag.tstate = NO_OP; - for (i = 0; i < 16; i++) - for (j = 0; j < 4; j++) - tag.pages[i][j] = 0x0; //read tag data into memory if (tag_mem_supplied) { DbpString("Loading hitagS memory..."); - memcpy((byte_t*)tag.pages,data,4*64); - } - tag.uid=(uint32_t)tag.pages[0]; - Dbprintf("Hitag S simulation started"); - tag.key=(intptr_t)tag.pages[3]; - tag.key<<=16; - tag.key+=((tag.pages[2][0])<<8)+tag.pages[2][1]; - tag.pwdl0=tag.pages[2][3]; - tag.pwdl1=tag.pages[2][2]; - tag.pwdh0=tag.pages[1][0]; - //con0 - tag.max_page=64; - if((tag.pages[1][3]&0x2)==0 && (tag.pages[1][3]&0x1)==1) - tag.max_page=8; - if((tag.pages[1][3]&0x2)==0 && (tag.pages[1][3]&0x1)==0) - tag.max_page=0; - //con1 - tag.auth=0; - if (tag.pages[1][2]&0x80) - tag.auth=1; - tag.LCON=0; - if (tag.pages[1][2]&0x2) - tag.LCON=1; - tag.LKP=0; - if (tag.pages[1][2]&0x1) - tag.LKP=1; - //con2 - //0=read write 1=read only - tag.LCK7=0; - if (tag.pages[1][1]&0x80) - tag.LCK7=1; - tag.LCK6=0; - if (tag.pages[1][1]&0x40) - tag.LCK6=1; - tag.LCK5=0; - if (tag.pages[1][1]&0x20) - tag.LCK5=1; - tag.LCK4=0; - if (tag.pages[1][1]&0x10) - tag.LCK4=1; - tag.LCK3=0; - if (tag.pages[1][1]&0x8) - tag.LCK3=1; - tag.LCK2=0; - if (tag.pages[1][1]&0x4) - tag.LCK2=1; - tag.LCK1=0; - if (tag.pages[1][1]&0x2) - tag.LCK1=1; - tag.LCK0=0; - if (tag.pages[1][1]&0x1) - tag.LCK0=1; + for (i = 0; i < 64; i++) { + for (j = 0; j < 4; j++) { + tag.pages[i][j] = 0x0; + } + } -// Set up simulator mode, frequency divisor which will drive the FPGA -// and analog mux selection. + for (i = 0; i < 64; i++) { + for (j = 0; j < 4; j++) { + tag.pages[i][j] = data[(i*4)+j]; + } + } + } + tag.uid = (tag.pages[0][3] << 24 | tag.pages[0][2] << 16 | tag.pages[0][1] << 8 | tag.pages[0][0]); + con0 = tag.pages[1][3]; + con1 = tag.pages[1][2]; + con2 = tag.pages[1][1]; + Dbprintf("UID: %X", tag.uid); + Dbprintf("Hitag S simulation started"); + + //0x01 plain mode - Reserved, CON2, CON1, CON0 + //0x01 auth mode - PWDH 0, CON2, CON1, CON0 + //0x02 auth mode - KEYH 1, KEYH 0, PWDL 1, PWDL 0 + //0x03 auth mode - KEYL 3, KEYL 2, KEYL 1, KEYL 0 + + //con0 + tag.max_page = 2048 / 32; + if ((con0 & 0x2) == 0 && (con0 & 0x1) == 1) + tag.max_page = 256 / 32; + if ((con0 & 0x2) == 0 && (con0 & 0x1) == 0) + tag.max_page = 32 / 32; + + //CON1 + tag.auth = ((con1 & 0x80) == 0x80) ? 1 : 0; + tag.TTFC = ((con1 & 0x40) == 0x40) ? 1 : 0; + //tag.TTFDR in response_bit[10] and response_bit[11] + //tag.TTFM in response_bit[12] and response_bit[13] + tag.LCON = ((con1 & 0x2) == 0x2) ? 1 : 0; + tag.LKP = ((con1 & 0x2) == 0x1) ? 1 : 0; + + //CON2 + tag.LCK7 = ((con2 & 0x80) == 0x80) ? 1 : 0; + tag.LCK6 = ((con2 & 0x40) == 0x40) ? 1 : 0; + tag.LCK5 = ((con2 & 0x20) == 0x20) ? 1 : 0; + tag.LCK4 = ((con2 & 0x10) == 0x10) ? 1 : 0; + tag.LCK3 = ((con2 & 0x8) == 0x8) ? 1 : 0; + tag.LCK2 = ((con2 & 0x4) == 0x4) ? 1 : 0; + tag.LCK1 = ((con2 & 0x2) == 0x2) ? 1 : 0; + tag.LCK0 = ((con2 & 0x1) == 0x1) ? 1 : 0; + + if (tag.auth == 1) { + //TODO check if this working :D + tag.key=(intptr_t)tag.pages[3]; + tag.key<<=16; + tag.key+=((tag.pages[2][0])<<8)+tag.pages[2][1]; + tag.pwdl0=tag.pages[2][3]; + tag.pwdl1=tag.pages[2][2]; + tag.pwdh0=tag.pages[1][0]; + } + + // Set up simulator mode, frequency divisor which will drive the FPGA + // and analog mux selection. FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz SetAdcMuxFor(GPIO_MUXSEL_LOPKD); RELAY_OFF(); -// Configure output pin that is connected to the FPGA (for modulating) + // Configure output pin that is connected to the FPGA (for modulating) AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; -// Disable modulation at default, which means release resistance + // Disable modulation at default, which means release resistance LOW(GPIO_SSC_DOUT); -// Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering + // Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0); -// Enable Peripheral Clock for TIMER_CLOCK1, used to capture edges of the reader frames + // Enable Peripheral Clock for TIMER_CLOCK1, used to capture edges of the reader frames AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; -// Disable timer during configuration + // Disable timer during configuration AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; -// Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, -// external trigger rising edge, load RA on rising edge of TIOA. - AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK - | AT91C_TC_ETRGEDG_RISING | AT91C_TC_ABETRG | AT91C_TC_LDRA_RISING; + // Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, + // external trigger rising edge, load RA on rising edge of TIOA. + AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_RISING | AT91C_TC_ABETRG | AT91C_TC_LDRA_RISING; -// Reset the received frame, frame count and timing info + // Reset the received frame, frame count and timing info memset(rx, 0x00, sizeof(rx)); frame_count = 0; response = 0; overflow = 0; -// Enable and reset counter + // Enable and reset counter AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; while (!BUTTON_PRESS()) { @@ -1063,6 +1554,7 @@ void SimulateHitagSTag(bool tag_mem_supplied, byte_t* data) { WDT_HIT(); // Receive frame, watch for at most T0*EOF periods + //HITAG_T_WAIT_MAX while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_EOF) { // Check if rising edge in modulation is detected if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { @@ -1117,13 +1609,13 @@ void SimulateHitagSTag(bool tag_mem_supplied, byte_t* data) { // with respect to the falling edge, we need to wait actually (T_Wait1 - T_Low) // periods. The gap time T_Low varies (4..10). All timer values are in // terms of T0 units - while (AT91C_BASE_TC0->TC_CV < T0 * (HITAG_T_WAIT_1 - HITAG_T_LOW)) - ; + while (AT91C_BASE_TC0->TC_CV < T0 * (HITAG_T_WAIT_1 - HITAG_T_LOW)) { } // Send and store the tag answer (if there is any) if (txlen > 0) { // Transmit the tag frame - hitag_send_frame(tx, txlen); + hitag_tag_send_frame(tx, txlen); + // Store the frame in the trace if (!bQuiet) { if (!LogTraceHitag(tx, txlen, 0, 0, false)) { @@ -1133,12 +1625,13 @@ void SimulateHitagSTag(bool tag_mem_supplied, byte_t* data) { } } + // Enable and reset external trigger in timer for capturing future frames + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + // Reset the received frame and response timing info memset(rx, 0x00, sizeof(rx)); response = 0; - // Enable and reset external trigger in timer for capturing future frames - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; LED_B_OFF(); } // Reset the frame length @@ -1148,6 +1641,7 @@ void SimulateHitagSTag(bool tag_mem_supplied, byte_t* data) { // Reset the timer to restart while-loop that receives frames AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; } + Dbprintf("Hitag S simulation stopped"); LED_B_OFF(); LED_D_OFF(); AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; @@ -1160,10 +1654,16 @@ void SimulateHitagSTag(bool tag_mem_supplied, byte_t* data) { * If the key was given the password will be decrypted. * Reads every page of a hitag S transpoder. */ -void ReadHitagS(hitag_function htf, hitag_data* htd) { - int i, j, z, k; +void ReadHitagSintern(hitag_function htf, hitag_data* htd, stype tagMode, int startPage, bool readBlock) { int frame_count; - int response_bit[200]; + int i; + int sendNum = startPage; + tag.mode = tagMode; + + //int i, j, z; + //int response_bit[200]; + //unsigned char mask = 1; + int response; byte_t rx[HITAG_FRAME_LEN]; size_t rxlen = 0; @@ -1171,16 +1671,10 @@ void ReadHitagS(hitag_function htf, hitag_data* htd) { byte_t* tx = txbuf; size_t txlen = 0; int lastbit; - bool bSkip; - int reset_sof; - int tag_sof; int t_wait = HITAG_T_WAIT_MAX; bool bStop; bool bQuitTraceFull = false; - int sendNum = 0; - unsigned char mask = 1; - unsigned char crc; - unsigned char pageData[32]; + page_to_be_written = 0; //read given key/challenge @@ -1189,14 +1683,16 @@ void ReadHitagS(hitag_function htf, hitag_data* htd) { uint64_t NrAr=0; byte_t key_[6]; switch(htf) { - case 01: { //RHTS_CHALLENGE + case 01: + case 03: { //RHTS_CHALLENGE DbpString("Authenticating using nr,ar pair:"); memcpy(NrAr_,htd->auth.NrAr,8); Dbhexdump(8,NrAr_,false); NrAr=NrAr_[7] | ((uint64_t)NrAr_[6]) << 8 | ((uint64_t)NrAr_[5]) << 16 | ((uint64_t)NrAr_[4]) << 24 | ((uint64_t)NrAr_[3]) << 32 | ((uint64_t)NrAr_[2]) << 40| ((uint64_t)NrAr_[1]) << 48 | ((uint64_t)NrAr_[0]) << 56; } break; - case 02: { //RHTS_KEY + case 02: + case 04: { //RHTS_KEY DbpString("Authenticating using key:"); memcpy(key_,htd->crypto.key,6); Dbhexdump(6,key_,false); @@ -1219,7 +1715,6 @@ void ReadHitagS(hitag_function htf, hitag_data* htd) { clear_trace(); bQuiet = false; - bQuitTraceFull = true; LED_D_ON(); @@ -1228,8 +1723,7 @@ void ReadHitagS(hitag_function htf, hitag_data* htd) { AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; // Set fpga in edge detect with reader field, we can modulate as reader now - FpgaWriteConfWord( - FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD); // Set Frequency divisor which will drive the FPGA and analog mux selection FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz @@ -1254,9 +1748,7 @@ void ReadHitagS(hitag_function htf, hitag_data* htd) { // Capture mode, defaul timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, // external trigger rising edge, load RA on falling edge of TIOA. - AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK - - | AT91C_TC_ETRGEDG_FALLING | AT91C_TC_ABETRG | AT91C_TC_LDRA_FALLING; + AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_FALLING | AT91C_TC_ABETRG | AT91C_TC_LDRA_FALLING; // Enable and reset counters AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; @@ -1267,14 +1759,34 @@ void ReadHitagS(hitag_function htf, hitag_data* htd) { response = 0; lastbit = 1; bStop = false; - - reset_sof = 1; t_wait = 200; while (!bStop && !BUTTON_PRESS()) { // Watchdog hit WDT_HIT(); + + // Add transmitted frame to total count + if (txlen > 0) { + frame_count++; + + if (tag.pstate == READY && rxlen < 1) { + //skip logging starting auths if no response + } else { + if (!bQuiet) { + // Store the frame in the trace + if (!LogTraceHitag(tx, txlen, HITAG_T_WAIT_2, 0, true)) { + if (bQuitTraceFull) { + DbpString("Trace full"); + break; + } else { + bQuiet = true; + } + } + } + } + } + // Check if frame was captured and store it if (rxlen > 0) { frame_count++; @@ -1294,94 +1806,31 @@ void ReadHitagS(hitag_function htf, hitag_data* htd) { tx = txbuf; txlen = 0; + if (DEBUG >= 2) { + Dbprintf("FRO %d rxlen: %d, pstate=%d, tstate=%d", frame_count, rxlen, (int)tag.pstate, (int)tag.tstate); + } + if (rxlen == 0) { //start authentication - txlen = 5; - memcpy(tx, "\xc0", nbytes(txlen)); - tag.pstate = READY; - tag.tstate = NO_OP; + hitag_start_auth(tx, &txlen); } else if (tag.pstate != SELECTED) { - if (hitagS_handle_tag_auth(htf, key,NrAr,rx, rxlen, tx, &txlen) == -1) + if (hitagS_handle_tag_auth(htf, key,NrAr,rx, rxlen, tx, &txlen) == -1) { + Dbprintf("hitagS_handle_tag_auth - bStop = !false"); bStop = !false; + } } - if (tag.pstate == SELECTED && tag.tstate == NO_OP && rxlen > 0) { - //send read request - tag.tstate = READING_PAGE; - txlen = 20; - crc = CRC_PRESET; - tx[0] = 0xc0 + (sendNum / 16); - calc_crc(&crc, tx[0], 8); - calc_crc(&crc, 0x00 + ((sendNum % 16) * 16), 4); - tx[1] = 0x00 + ((sendNum % 16) * 16) + (crc / 16); - tx[2] = 0x00 + (crc % 16) * 16; - } else if (tag.pstate == SELECTED && tag.tstate == READING_PAGE - && rxlen > 0) { - //save received data - z = 0; - for (i = 0; i < 5; i++) { - for (j = 0; j < 8; j++) { - response_bit[z] = 0; - if ((rx[i] & ((mask << 7) >> j)) != 0) - response_bit[z] = 1; - z++; - } - } - k = 0; - for (i = 4; i < 36; i++) { - pageData[k] = response_bit[i]; - k++; - } - for (i = 0; i < 4; i++) - tag.pages[sendNum / 4][sendNum % 4] = 0x0; - for (i = 0; i < 4; i++) { - tag.pages[sendNum / 4][sendNum % 4] += ((pageData[i * 8] << 7) - | (pageData[1 + (i * 8)] << 6) - | (pageData[2 + (i * 8)] << 5) - | (pageData[3 + (i * 8)] << 4) - | (pageData[4 + (i * 8)] << 3) - | (pageData[5 + (i * 8)] << 2) - | (pageData[6 + (i * 8)] << 1) | pageData[7 + (i * 8)]) - << (i * 8); - } - if (tag.auth && tag.LKP && sendNum == 1) { - Dbprintf("Page[%2d]: %02X %02X %02X %02X", sendNum, pwdh0, - (tag.pages[sendNum / 4][sendNum % 4] >> 16) & 0xff, - (tag.pages[sendNum / 4][sendNum % 4] >> 8) & 0xff, - tag.pages[sendNum / 4][sendNum % 4] & 0xff); - } else { - Dbprintf("Page[%2d]: %02X %02X %02X %02X", sendNum, - (tag.pages[sendNum / 4][sendNum % 4] >> 24) & 0xff, - (tag.pages[sendNum / 4][sendNum % 4] >> 16) & 0xff, - (tag.pages[sendNum / 4][sendNum % 4] >> 8) & 0xff, - tag.pages[sendNum / 4][sendNum % 4] & 0xff); - } - sendNum++; - //display key and password if possible - if (sendNum == 2 && tag.auth == 1 && tag.LKP) { - if (htf == 02) { //RHTS_KEY - Dbprintf("Page[ 2]: %02X %02X %02X %02X", - (byte_t)(key >> 8) & 0xff, - (byte_t) key & 0xff, pwdl1, pwdl0); - Dbprintf("Page[ 3]: %02X %02X %02X %02X", - (byte_t)(key >> 40) & 0xff, - (byte_t)(key >> 32) & 0xff, - (byte_t)(key >> 24) & 0xff, - (byte_t)(key >> 16) & 0xff); - } else { - //if the authentication is done with a challenge the key and password are unknown - Dbprintf("Page[ 2]: __ __ __ __"); - Dbprintf("Page[ 3]: __ __ __ __"); - } - } - txlen = 20; - crc = CRC_PRESET; - tx[0] = 0xc0 + (sendNum / 16); - calc_crc(&crc, tx[0], 8); - calc_crc(&crc, 0x00 + ((sendNum % 16) * 16), 4); - tx[1] = 0x00 + ((sendNum % 16) * 16) + (crc / 16); - tx[2] = 0x00 + (crc % 16) * 16; + + if (readBlock && tag.pstate == SELECTED && (tag.tstate == READING_BLOCK || tag.tstate == NO_OP) && rxlen > 0) { + i = hitag_read_block(htf, key, rx, &rxlen, tx, &txlen, sendNum); + if (i > 0) { sendNum+=4; } + if (sendNum+4 >= tag.max_page) { + bStop = !false; + } + } else if (!readBlock && tag.pstate == SELECTED && (tag.tstate == READING_PAGE || tag.tstate == NO_OP) && rxlen > 0) { + i = hitag_read_page(htf, key, rx, &rxlen, tx, &txlen, sendNum); + if (i > 0) { sendNum++; } if (sendNum >= tag.max_page) { bStop = !false; } @@ -1397,98 +1846,24 @@ void ReadHitagS(hitag_function htf, hitag_data* htd) { // we need to wait (T_Wait2 + half_tag_period) when the last was a 'one'. // All timer values are in terms of T0 units - while (AT91C_BASE_TC0->TC_CV - < T0 * (t_wait + (HITAG_T_TAG_HALF_PERIOD * lastbit))) - ; + while (AT91C_BASE_TC0->TC_CV < T0 * (t_wait + (HITAG_T_TAG_HALF_PERIOD * lastbit))) { } // Transmit the reader frame hitag_reader_send_frame(tx, txlen); + // Enable and reset external trigger in timer for capturing future frames AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - // Add transmitted frame to total count - if (txlen > 0) { - frame_count++; - if (!bQuiet) { - // Store the frame in the trace - if (!LogTraceHitag(tx, txlen, HITAG_T_WAIT_2, 0, true)) { - if (bQuitTraceFull) { - DbpString("Trace full"); - break; - } else { - bQuiet = true; - } - } - } - } // Reset values for receiving frames memset(rx, 0x00, sizeof(rx)); rxlen = 0; lastbit = 1; - bSkip = true; - tag_sof = reset_sof; response = 0; - // Receive frame, watch for at most T0*EOF periods - while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_WAIT_MAX) { - // Check if falling edge in tag modulation is detected - if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { - // Retrieve the new timing values - int ra = (AT91C_BASE_TC1->TC_RA / T0); - - // Reset timer every frame, we have to capture the last edge for timing - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - - LED_B_ON(); - - // Capture tag frame (manchester decoding using only falling edges) - if (ra >= HITAG_T_EOF) { - if (rxlen != 0) { - //DbpString("wierd1?"); - } - // Capture the T0 periods that have passed since last communication or field drop (reset) - // We always recieve a 'one' first, which has the falling edge after a half period |-_| - response = ra - HITAG_T_TAG_HALF_PERIOD; - } else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { - // Manchester coding example |-_|_-|-_| (101) - rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); - rxlen++; - rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); - rxlen++; - } else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { - // Manchester coding example |_-|...|_-|-_| (0...01) - rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); - rxlen++; - // We have to skip this half period at start and add the 'one' the second time - if (!bSkip) { - rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); - rxlen++; - } - lastbit = !lastbit; - bSkip = !bSkip; - } else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { - // Manchester coding example |_-|_-| (00) or |-_|-_| (11) - if (tag_sof) { - // Ignore bits that are transmitted during SOF - tag_sof--; - } else { - // bit is same as last bit - rx[rxlen / 8] |= lastbit << (7 - (rxlen % 8)); - rxlen++; - } - } else { - // Ignore wierd value, is to small to mean anything - } - } - - // We can break this loop if we received the last bit from a frame - if (AT91C_BASE_TC1->TC_CV > T0 * HITAG_T_EOF) { - if (rxlen > 0) - break; - } - } + // get tag id in anti-collision mode (proprietary data format, so switch off manchester and read at double the data rate, for 4 x the data bits) + hitag_receive_frame(rx, &rxlen, &response); } end=false; LED_B_OFF(); @@ -1499,6 +1874,21 @@ void ReadHitagS(hitag_function htf, hitag_data* htd) { cmd_send(CMD_ACK, bSuccessful, 0, 0, 0, 0); } +void ReadHitagSCmd(hitag_function htf, hitag_data* htd, uint64_t startPage, uint64_t tagMode, bool readBlock) { + if (tagMode == 1) { + Dbprintf("ReadHitagS in mode=ADVANCED, blockRead=%d, startPage=%d", readBlock, startPage); + ReadHitagSintern(htf, htd, ADVANCED, (int)startPage, readBlock); + } else if (tagMode == 2) { + Dbprintf("ReadHitagS in mode=FAST_ADVANCED, blockRead=%d, startPage=%d", readBlock, startPage); + ReadHitagSintern(htf, htd, FAST_ADVANCED, (int)startPage, readBlock); + } else { + Dbprintf("ReadHitagS in mode=STANDARD, blockRead=%d, startPage=%d", readBlock, startPage); + ReadHitagSintern(htf, htd, STANDARD, (int)startPage, readBlock); + } +} + + + /* * Authenticates to the Tag with the given Key or Challenge. * Writes the given 32Bit data into page_ @@ -1512,9 +1902,6 @@ void WritePageHitagS(hitag_function htf, hitag_data* htd,int page_) { byte_t* tx = txbuf; size_t txlen = 0; int lastbit; - bool bSkip; - int reset_sof; - int tag_sof; int t_wait = HITAG_T_WAIT_MAX; bool bStop; bool bQuitTraceFull = false; @@ -1563,7 +1950,6 @@ void WritePageHitagS(hitag_function htf, hitag_data* htd,int page_) { clear_trace(); bQuiet = false; - bQuitTraceFull = true; LED_D_ON(); @@ -1572,8 +1958,7 @@ void WritePageHitagS(hitag_function htf, hitag_data* htd,int page_) { AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; // Set fpga in edge detect with reader field, we can modulate as reader now - FpgaWriteConfWord( - FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD); // Set Frequency divisor which will drive the FPGA and analog mux selection FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz @@ -1611,8 +1996,6 @@ void WritePageHitagS(hitag_function htf, hitag_data* htd,int page_) { response = 0; lastbit = 1; bStop = false; - - reset_sof = 1; t_wait = 200; while (!bStop && !BUTTON_PRESS()) { @@ -1635,11 +2018,12 @@ void WritePageHitagS(hitag_function htf, hitag_data* htd,int page_) { } //check for valid input + /* if (page == 0) { - Dbprintf( - "usage: lf hitag writer [03 | 04] [CHALLENGE | KEY] [page] [byte0] [byte1] [byte2] [byte3]"); + Dbprintf("usage: lf hitag writer [03 | 04] [CHALLENGE | KEY] [page] [byte0] [byte1] [byte2] [byte3]"); bStop = !false; - } + }*/ + // By default reset the transmission buffer tx = txbuf; @@ -1651,15 +2035,18 @@ void WritePageHitagS(hitag_function htf, hitag_data* htd,int page_) { bStop = !false; } else if (rxlen == 0 && tag.tstate != WRITING_PAGE_DATA) { //start the authetication - txlen = 5; - memcpy(tx, "\xc0", nbytes(txlen)); - tag.pstate = READY; - tag.tstate = NO_OP; + //tag.mode = ADVANCED; + tag.mode = STANDARD; + hitag_start_auth(tx, &txlen); + m = AC2K; } else if (tag.pstate != SELECTED) { //try to authenticate with the given key or challenge - if (hitagS_handle_tag_auth(htf,key,NrAr,rx, rxlen, tx, &txlen) == -1) + if (hitagS_handle_tag_auth(htf,key,NrAr,rx, rxlen, tx, &txlen) == -1) { bStop = !false; + } + m = MC4K; } + if (tag.pstate == SELECTED && tag.tstate == NO_OP && rxlen > 0) { //check if the given page exists if (page > tag.max_page) { @@ -1676,7 +2063,7 @@ void WritePageHitagS(hitag_function htf, hitag_data* htd,int page_) { tx[1] = 0x00 + ((page % 16) * 16) + (crc / 16); tx[2] = 0x00 + (crc % 16) * 16; } else if (tag.pstate == SELECTED && tag.tstate == WRITING_PAGE_ACK - && rxlen == 6 && rx[0] == 0xf4) { + && rxlen == 2 && rx[0] == 0x40) { //ACK recieved to write the page. send data tag.tstate = WRITING_PAGE_DATA; txlen = 40; @@ -1691,7 +2078,7 @@ void WritePageHitagS(hitag_function htf, hitag_data* htd,int page_) { tx[3] = data[0]; tx[4] = crc; } else if (tag.pstate == SELECTED && tag.tstate == WRITING_PAGE_DATA - && rxlen == 6 && rx[0] == 0xf4) { + && rxlen == 2 && rx[0] == 0x40) { //received ACK Dbprintf("Successful!"); bStop = !false; @@ -1737,68 +2124,9 @@ void WritePageHitagS(hitag_function htf, hitag_data* htd,int page_) { memset(rx, 0x00, sizeof(rx)); rxlen = 0; lastbit = 1; - bSkip = true; - tag_sof = reset_sof; response = 0; - // Receive frame, watch for at most T0*EOF periods - while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_WAIT_MAX) { - // Check if falling edge in tag modulation is detected - if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { - // Retrieve the new timing values - int ra = (AT91C_BASE_TC1->TC_RA / T0); - - // Reset timer every frame, we have to capture the last edge for timing - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - - LED_B_ON(); - - // Capture tag frame (manchester decoding using only falling edges) - if (ra >= HITAG_T_EOF) { - if (rxlen != 0) { - //DbpString("wierd1?"); - } - // Capture the T0 periods that have passed since last communication or field drop (reset) - // We always recieve a 'one' first, which has the falling edge after a half period |-_| - response = ra - HITAG_T_TAG_HALF_PERIOD; - } else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { - // Manchester coding example |-_|_-|-_| (101) - rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); - rxlen++; - rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); - rxlen++; - } else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { - // Manchester coding example |_-|...|_-|-_| (0...01) - rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); - rxlen++; - // We have to skip this half period at start and add the 'one' the second time - if (!bSkip) { - rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); - rxlen++; - } - lastbit = !lastbit; - bSkip = !bSkip; - } else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { - // Manchester coding example |_-|_-| (00) or |-_|-_| (11) - if (tag_sof) { - // Ignore bits that are transmitted during SOF - tag_sof--; - } else { - // bit is same as last bit - rx[rxlen / 8] |= lastbit << (7 - (rxlen % 8)); - rxlen++; - } - } else { - // Ignore wierd value, is to small to mean anything - } - } - - // We can break this loop if we received the last bit from a frame - if (AT91C_BASE_TC1->TC_CV > T0 * HITAG_T_EOF) { - if (rxlen > 0) - break; - } - } + hitag_receive_frame(rx, &rxlen, &response); } end=false; LED_B_OFF(); @@ -1809,6 +2137,7 @@ void WritePageHitagS(hitag_function htf, hitag_data* htd,int page_) { cmd_send(CMD_ACK, bSuccessful, 0, 0, 0, 0); } + /* * Tries to authenticate to a Hitag S Transponder with the given challenges from a .cc file. * Displays all Challenges that failed. @@ -1816,7 +2145,7 @@ void WritePageHitagS(hitag_function htf, hitag_data* htd,int page_) { * is not received correctly due to Antenna problems. This function * detects these challenges. */ -void check_challenges(bool file_given, byte_t* data) { +void check_challenges_cmd(bool file_given, byte_t* data, uint64_t tagMode) { int i, j, z, k; byte_t uid_byte[4]; int frame_count; @@ -1829,9 +2158,6 @@ void check_challenges(bool file_given, byte_t* data) { byte_t* tx = txbuf; size_t txlen = 0; int lastbit; - bool bSkip; - int reset_sof; - int tag_sof; int t_wait = HITAG_T_WAIT_MAX; int STATE = 0; bool bStop; @@ -1841,6 +2167,18 @@ void check_challenges(bool file_given, byte_t* data) { unsigned char uid[32]; unsigned char crc; + if (tagMode == 1) { + Dbprintf("check_challenges in mode=ADVANCED"); + tag.mode = ADVANCED; + } else if (tagMode == 2) { + Dbprintf("check_challenges in mode=FAST_ADVANCED"); + tag.mode = FAST_ADVANCED; + } else { + Dbprintf("check_challenges in mode=STANDARD"); + tag.mode = STANDARD; + } + + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); // Reset the return status bSuccessful = false; @@ -1850,7 +2188,6 @@ void check_challenges(bool file_given, byte_t* data) { clear_trace(); bQuiet = false; - bQuitTraceFull = true; LED_D_ON(); @@ -1885,9 +2222,7 @@ void check_challenges(bool file_given, byte_t* data) { // Capture mode, defaul timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, // external trigger rising edge, load RA on falling edge of TIOA. - AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK - - | AT91C_TC_ETRGEDG_FALLING | AT91C_TC_ABETRG | AT91C_TC_LDRA_FALLING; + AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_FALLING | AT91C_TC_ABETRG | AT91C_TC_LDRA_FALLING; // Enable and reset counters AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; @@ -1899,7 +2234,6 @@ void check_challenges(bool file_given, byte_t* data) { lastbit = 1; bStop = false; - reset_sof = 1; t_wait = 200; if (file_given) { @@ -1929,18 +2263,17 @@ void check_challenges(bool file_given, byte_t* data) { tx = txbuf; txlen = 0; if (rxlen == 0) { - if (STATE == 2) + if (STATE == 2) { // challenge failed Dbprintf("Challenge failed: %02X %02X %02X %02X %02X %02X %02X %02X", unlocker[u1 - 1][0], unlocker[u1 - 1][1], unlocker[u1 - 1][2], unlocker[u1 - 1][3], unlocker[u1 - 1][4], unlocker[u1 - 1][5], unlocker[u1 - 1][6], unlocker[u1 - 1][7]); + } STATE = 0; - txlen = 5; - //start new authentication - memcpy(tx, "\xc0", nbytes(txlen)); - } else if (rxlen >= 67 && STATE == 0) { + hitag_start_auth(tx, &txlen); + } else if (rxlen >= 32 && STATE == 0) { //received uid z = 0; for (i = 0; i < 10; i++) { @@ -1951,13 +2284,10 @@ void check_challenges(bool file_given, byte_t* data) { z++; } } - k = 0; - for (i = 5; i < z; i += 2) { - uid[k] = response_bit[i]; - k++; - if (k > 31) - break; + for (i = 0; i < 32; i++) { + uid[i] = response_bit[i]; } + uid_byte[0] = (uid[0] << 7) | (uid[1] << 6) | (uid[2] << 5) | (uid[3] << 4) | (uid[4] << 3) | (uid[5] << 2) | (uid[6] << 1) | uid[7]; @@ -2005,7 +2335,9 @@ void check_challenges(bool file_given, byte_t* data) { k += 8; } - } else if (STATE == 1 && rxlen == 44) { + + tag.pstate = INIT; + } else if (STATE == 1 && rxlen > 24) { //received configuration STATE = 2; z = 0; @@ -2025,7 +2357,8 @@ void check_challenges(bool file_given, byte_t* data) { tx[i] = unlocker[u1][i]; u1++; - } else if (STATE == 2 && rxlen >= 44) { + tag.pstate = SELECTED; + } else if (STATE == 2 && rxlen >= 32) { STATE = 0; } @@ -2038,10 +2371,7 @@ void check_challenges(bool file_given, byte_t* data) { // falling edge occured halfway the period. with respect to this falling edge, // we need to wait (T_Wait2 + half_tag_period) when the last was a 'one'. // All timer values are in terms of T0 units - - while (AT91C_BASE_TC0->TC_CV - < T0 * (t_wait + (HITAG_T_TAG_HALF_PERIOD * lastbit))) - ; + while (AT91C_BASE_TC0->TC_CV < T0 * (t_wait + (HITAG_T_TAG_HALF_PERIOD * lastbit))) { } // Transmit the reader frame hitag_reader_send_frame(tx, txlen); @@ -2069,68 +2399,9 @@ void check_challenges(bool file_given, byte_t* data) { memset(rx, 0x00, sizeof(rx)); rxlen = 0; lastbit = 1; - bSkip = true; - tag_sof = reset_sof; response = 0; - // Receive frame, watch for at most T0*EOF periods - while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_WAIT_MAX) { - // Check if falling edge in tag modulation is detected - if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { - // Retrieve the new timing values - int ra = (AT91C_BASE_TC1->TC_RA / T0); - - // Reset timer every frame, we have to capture the last edge for timing - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - - LED_B_ON(); - - // Capture tag frame (manchester decoding using only falling edges) - if (ra >= HITAG_T_EOF) { - if (rxlen != 0) { - //DbpString("wierd1?"); - } - // Capture the T0 periods that have passed since last communication or field drop (reset) - // We always recieve a 'one' first, which has the falling edge after a half period |-_| - response = ra - HITAG_T_TAG_HALF_PERIOD; - } else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { - // Manchester coding example |-_|_-|-_| (101) - rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); - rxlen++; - rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); - rxlen++; - } else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { - // Manchester coding example |_-|...|_-|-_| (0...01) - rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); - rxlen++; - // We have to skip this half period at start and add the 'one' the second time - if (!bSkip) { - rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); - rxlen++; - } - lastbit = !lastbit; - bSkip = !bSkip; - } else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { - // Manchester coding example |_-|_-| (00) or |-_|-_| (11) - if (tag_sof) { - // Ignore bits that are transmitted during SOF - tag_sof--; - } else { - // bit is same as last bit - rx[rxlen / 8] |= lastbit << (7 - (rxlen % 8)); - rxlen++; - } - } else { - // Ignore wierd value, is to small to mean anything - } - } - - // We can break this loop if we received the last bit from a frame - if (AT91C_BASE_TC1->TC_CV > T0 * HITAG_T_EOF) { - if (rxlen > 0) - break; - } - } + hitag_receive_frame(rx, &rxlen, &response); } LED_B_OFF(); LED_D_OFF(); @@ -2140,5 +2411,13 @@ void check_challenges(bool file_given, byte_t* data) { cmd_send(CMD_ACK, bSuccessful, 0, 0, 0, 0); } +/** +Backward compatibility +*/ +void check_challenges(bool file_given, byte_t* data) { + check_challenges_cmd(file_given, data, 1); +} - +void ReadHitagS(hitag_function htf, hitag_data* htd) { + ReadHitagSintern(htf, htd, ADVANCED, 0, false); +} diff --git a/client/cmdlfhitag.c b/client/cmdlfhitag.c index 8eef2359..84fb5458 100644 --- a/client/cmdlfhitag.c +++ b/client/cmdlfhitag.c @@ -32,7 +32,6 @@ size_t nbytes(size_t nbits) { int CmdLFHitagList(const char *Cmd) { uint8_t *got = malloc(USB_CMD_DATA_SIZE); - // Query for the actual size of the trace UsbCommand response; GetFromBigBuf(got, USB_CMD_DATA_SIZE, 0, &response, -1, false); @@ -52,6 +51,7 @@ int CmdLFHitagList(const char *Cmd) PrintAndLog(" ETU :nbits: who bytes"); PrintAndLog("---------+-----+----+-----------"); + int j; int i = 0; int prev = -1; int len = strlen(Cmd); @@ -93,7 +93,7 @@ int CmdLFHitagList(const char *Cmd) // or each half bit period in 256 levels. int bits = got[i+8]; - int len = nbytes(got[i+8]); + int len = nbytes(bits); if (len > 100) { break; @@ -101,19 +101,43 @@ int CmdLFHitagList(const char *Cmd) if (i + len > traceLen) { break;} uint8_t *frame = (got+i+9); +/* + int fillupBits = 8 - (bits % 8); + byte_t framefilled[bits+fillupBits]; + byte_t* ff = framefilled; + + int response_bit[200] = {0}; + int z = 0; + for (int y = 0; y < len; y++) { + for (j = 0; j < 8; j++) { + response_bit[z] = 0; + if ((frame[y] & ((mask << 7) >> j)) != 0) + response_bit[z] = 1; + z++; + } + } + z = 0; + for (int y = 0; y < len; y++) { + ff[y] = (response_bit[z] << 7) | (response_bit[z + 1] << 6) + | (response_bit[z + 2] << 5) | (response_bit[z + 3] << 4) + | (response_bit[z + 4] << 3) | (response_bit[z + 5] << 2) + | (response_bit[z + 6] << 1) | response_bit[z + 7]; + z += 8; + } +*/ + + + // Break and stick with current result if buffer was not completely full if (frame[0] == 0x44 && frame[1] == 0x44 && frame[3] == 0x44) { break; } char line[1000] = ""; - int j; for (j = 0; j < len; j++) { - //if((parityBits >> (len - j - 1)) & 0x01) { if (isResponse && (oddparity8(frame[j]) != ((parityBits >> (len - j - 1)) & 0x01))) { sprintf(line+(j*4), "%02x! ", frame[j]); - } - else { + } else { sprintf(line+(j*4), "%02x ", frame[j]); } } @@ -194,10 +218,27 @@ int CmdLFHitagReader(const char *Cmd) { c = (UsbCommand){ CMD_READ_HITAG_S }; num_to_bytes(param_get32ex(Cmd,1,0,16),4,htd->auth.NrAr); num_to_bytes(param_get32ex(Cmd,2,0,16),4,htd->auth.NrAr+4); + c.arg[1] = param_get64ex(Cmd,3,0,0); //firstpage + c.arg[2] = param_get64ex(Cmd,4,0,0); //tag mode } break; case 02: { //RHTSF_KEY c = (UsbCommand){ CMD_READ_HITAG_S }; num_to_bytes(param_get64ex(Cmd,1,0,16),6,htd->crypto.key); + c.arg[1] = param_get64ex(Cmd,2,0,0); //firstpage + c.arg[2] = param_get64ex(Cmd,3,0,0); //tag mode + } break; + case 03: { //RHTSF_CHALLENGE BLOCK + c = (UsbCommand){ CMD_READ_HITAG_S_BLK }; + num_to_bytes(param_get32ex(Cmd,1,0,16),4,htd->auth.NrAr); + num_to_bytes(param_get32ex(Cmd,2,0,16),4,htd->auth.NrAr+4); + c.arg[1] = param_get64ex(Cmd,3,0,0); //firstpage + c.arg[2] = param_get64ex(Cmd,4,0,0); //tag mode + } break; + case 04: { //RHTSF_KEY BLOCK + c = (UsbCommand){ CMD_READ_HITAG_S_BLK }; + num_to_bytes(param_get64ex(Cmd,1,0,16),6,htd->crypto.key); + c.arg[1] = param_get64ex(Cmd,2,0,0); //firstpage + c.arg[2] = param_get64ex(Cmd,3,0,0); //tag mode } break; case RHT2F_PASSWORD: { num_to_bytes(param_get32ex(Cmd,1,0,16),4,htd->pwd.password); @@ -222,8 +263,11 @@ int CmdLFHitagReader(const char *Cmd) { PrintAndLog("Usage: hitag reader "); PrintAndLog("Reader Functions:"); PrintAndLog(" HitagS (0*)"); - PrintAndLog(" 01 (Challenge) read all pages from a Hitag S tag"); - PrintAndLog(" 02 (set to 0 if no authentication is needed) read all pages from a Hitag S tag"); + PrintAndLog(" 01 (Challenge) read all pages from a Hitag S tag"); + PrintAndLog(" 02 (set to 0 if no authentication is needed) read all pages from a Hitag S tag"); + PrintAndLog(" 03 (Challenge) read all blocks from a Hitag S tag"); + PrintAndLog(" 04 (set to 0 if no authentication is needed) read all blocks from a Hitag S tag"); + PrintAndLog(" Valid tagmodes are 0=STANDARD, 1=ADVANCED, 2=FAST_ADVANCED (default is ADVANCED)"); PrintAndLog(" Hitag1 (1*)"); PrintAndLog(" Hitag2 (2*)"); PrintAndLog(" 21 (password mode)"); @@ -334,6 +378,7 @@ int CmdLFHitagCheckChallenges(const char *Cmd) { //file with all the challenges to try c.arg[0] = (uint32_t)file_given; + c.arg[1] = param_get64ex(Cmd,2,0,0); //get mode SendCommand(&c); return 0; @@ -394,7 +439,7 @@ static command_t CommandTable[] = {"snoop", CmdLFHitagSnoop, 1, "Eavesdrop Hitag communication"}, {"writer", CmdLFHitagWP, 1, "Act like a Hitag Writer" }, {"simS", CmdLFHitagSimS, 1, " Simulate HitagS transponder" }, - {"checkChallenges", CmdLFHitagCheckChallenges, 1, " test all challenges" }, { + {"checkChallenges", CmdLFHitagCheckChallenges, 1, " test all challenges" }, { NULL,NULL, 0, NULL } }; diff --git a/include/hitagS.h b/include/hitagS.h index e447714b..6fd31841 100644 --- a/include/hitagS.h +++ b/include/hitagS.h @@ -16,14 +16,14 @@ #include "hitag2.h" typedef enum PROTO_STATE {READY=0,INIT,AUTHENTICATE,SELECTED,QUIET,TTF,FAIL} PSTATE; //protocol-state -typedef enum TAG_STATE {NO_OP=0,READING_PAGE,WRITING_PAGE_ACK,WRITING_PAGE_DATA,WRITING_BLOCK_DATA} TSATE; //tag-state +typedef enum TAG_STATE {NO_OP=0,READING_PAGE,READING_BLOCK,WRITING_PAGE_ACK,WRITING_PAGE_DATA,WRITING_BLOCK_DATA} TSATE; //tag-state typedef enum SOF_TYPE {STANDARD=0,ADVANCED,FAST_ADVANCED,ONE,NO_BITS} stype; //number of start-of-frame bits struct hitagS_tag { PSTATE pstate; //protocol-state TSATE tstate; //tag-state uint32_t uid; - uint32_t pages[16][4]; + uint8_t pages[64][4]; uint64_t key; byte_t pwdl0,pwdl1,pwdh0; //con0 diff --git a/include/usb_cmd.h b/include/usb_cmd.h index bdff7261..fa66634f 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -137,6 +137,7 @@ typedef struct{ #define CMD_SIMULATE_HITAG_S 0x0368 #define CMD_TEST_HITAGS_TRACES 0x0367 #define CMD_READ_HITAG_S 0x0373 +#define CMD_READ_HITAG_S_BLK 0x0374 #define CMD_WR_HITAG_S 0x0375 #define CMD_EMU_HITAG_S 0x0376 From 9c87879e360c31b521310ff7be11efb3d27e3f8f Mon Sep 17 00:00:00 2001 From: Fl0-0 Date: Fri, 30 Nov 2018 18:44:52 +0100 Subject: [PATCH 026/189] Fix public key lenght to 65 bytes (#725) --- client/cmdhffido.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/cmdhffido.c b/client/cmdhffido.c index e2d6c091..357e265c 100644 --- a/client/cmdhffido.c +++ b/client/cmdhffido.c @@ -531,7 +531,7 @@ int CmdHFFidoAuthenticate(const char *cmd) { // public key CLIGetHexWithReturn(8, hdata, &hdatalen); - if (hdatalen && hdatalen != 130) { + if (hdatalen && hdatalen != 65) { PrintAndLog("ERROR: public key length must be 65 bytes only."); return 1; } From 383f4e2479f45df77d44078618454d1ddbf52290 Mon Sep 17 00:00:00 2001 From: florianrock <45316656+florianrock@users.noreply.github.com> Date: Mon, 3 Dec 2018 08:23:53 +0100 Subject: [PATCH 027/189] Update hitagS.c (#729) Bugfix for #605 - wrong compare for tag.LKP --- armsrc/hitagS.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armsrc/hitagS.c b/armsrc/hitagS.c index 5fa6a9a1..3c247d55 100644 --- a/armsrc/hitagS.c +++ b/armsrc/hitagS.c @@ -1489,7 +1489,7 @@ void SimulateHitagSTag(bool tag_mem_supplied, byte_t* data) { //tag.TTFDR in response_bit[10] and response_bit[11] //tag.TTFM in response_bit[12] and response_bit[13] tag.LCON = ((con1 & 0x2) == 0x2) ? 1 : 0; - tag.LKP = ((con1 & 0x2) == 0x1) ? 1 : 0; + tag.LKP = ((con1 & 0x1) == 0x1) ? 1 : 0; //CON2 tag.LCK7 = ((con2 & 0x80) == 0x80) ? 1 : 0; From ac4ecfe35327f827aeaf8426af2662c656affd2c Mon Sep 17 00:00:00 2001 From: Oleg Moiseenko <807634+merlokk@users.noreply.github.com> Date: Mon, 3 Dec 2018 09:29:13 +0200 Subject: [PATCH 028/189] added mifare trailer block decoding (#726) --- client/cmdhfmf.c | 32 ++++++++++++++++++++++++++++++-- client/mifare4.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ client/mifare4.h | 7 +++++++ 3 files changed, 83 insertions(+), 2 deletions(-) diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index c382664b..fa952cb9 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -141,12 +141,26 @@ int CmdHF14AMfRdBl(const char *Cmd) uint8_t isOK = resp.arg[0] & 0xff; uint8_t *data = resp.d.asBytes; - if (isOK) + if (isOK) { PrintAndLog("isOk:%02x data:%s", isOK, sprint_hex(data, 16)); - else + } else { PrintAndLog("isOk:%02x", isOK); + return 1; + } + + if (mfIsSectorTrailer(blockNo) && (data[6] || data[7] || data[8])) { + PrintAndLogEx(NORMAL, "Trailer decoded:"); + int bln = mfFirstBlockOfSector(mfSectorNum(blockNo)); + int blinc = (mfNumBlocksPerSector(mfSectorNum(blockNo)) > 4) ? 5 : 1; + for (int i = 0; i < 4; i++) { + PrintAndLogEx(NORMAL, "Access block %d%s: %s", bln, ((blinc > 1) && (i < 3) ? "+" : "") , mfGetAccessConditionsDesc(i, &data[6])); + bln += blinc; + } + PrintAndLogEx(NORMAL, "UserData: %s", sprint_hex_inrow(&data[9], 1)); + } } else { PrintAndLog("Command execute timeout"); + return 2; } return 0; @@ -2272,6 +2286,20 @@ int CmdHF14AMfCGetBlk(const char *Cmd) { } PrintAndLog("block data:%s", sprint_hex(memBlock, 16)); + + if (mfIsSectorTrailer(blockNo)) { + PrintAndLogEx(NORMAL, "Trailer decoded:"); + PrintAndLogEx(NORMAL, "Key A: %s", sprint_hex_inrow(memBlock, 6)); + PrintAndLogEx(NORMAL, "Key B: %s", sprint_hex_inrow(&memBlock[10], 6)); + int bln = mfFirstBlockOfSector(mfSectorNum(blockNo)); + int blinc = (mfNumBlocksPerSector(mfSectorNum(blockNo)) > 4) ? 5 : 1; + for (int i = 0; i < 4; i++) { + PrintAndLogEx(NORMAL, "Access block %d%s: %s", bln, ((blinc > 1) && (i < 3) ? "+" : "") , mfGetAccessConditionsDesc(i, &memBlock[6])); + bln += blinc; + } + PrintAndLogEx(NORMAL, "UserData: %s", sprint_hex_inrow(&memBlock[9], 1)); + } + return 0; } diff --git a/client/mifare4.c b/client/mifare4.c index 069c54d4..419e9b23 100644 --- a/client/mifare4.c +++ b/client/mifare4.c @@ -17,6 +17,52 @@ #include "ui.h" #include "crypto/libpcrypto.h" +AccessConditions_t MFAccessConditions[] = { + {0x00, "read AB; write AB; increment AB; decrement transfer restore AB"}, + {0x01, "read AB; decrement transfer restore AB"}, + {0x02, "read AB"}, + {0x03, "read B; write B"}, + {0x04, "read AB; writeB"}, + {0x05, "read B"}, + {0x06, "read AB; write B; increment B; decrement transfer restore AB"}, + {0x07, "none"} +}; + +AccessConditions_t MFAccessConditionsTrailer[] = { + {0x00, "read A by A; read ACCESS by A; read B by A; write B by A"}, + {0x01, "write A by A; read ACCESS by A write ACCESS by A; read B by A; write B by A"}, + {0x02, "read ACCESS by A; read B by A"}, + {0x03, "write A by B; read ACCESS by AB; write ACCESS by B; write B by B"}, + {0x04, "write A by B; read ACCESS by AB; write B by B"}, + {0x05, "read ACCESS by AB; write ACCESS by B"}, + {0x06, "read ACCESS by AB"}, + {0x07, "read ACCESS by AB"} +}; + +char *mfGetAccessConditionsDesc(uint8_t blockn, uint8_t *data) { + static char StaticNone[] = "none"; + + uint8_t data1 = ((data[1] >> 4) & 0x0f) >> blockn; + uint8_t data2 = ((data[2]) & 0x0f) >> blockn; + uint8_t data3 = ((data[2] >> 4) & 0x0f) >> blockn; + + uint8_t cond = (data1 & 0x01) << 2 | (data2 & 0x01) << 1 | (data3 & 0x01); + + if (blockn == 3) { + for (int i = 0; i < ARRAYLEN(MFAccessConditionsTrailer); i++) + if (MFAccessConditionsTrailer[i].cond == cond) { + return MFAccessConditionsTrailer[i].description; + } + } else { + for (int i = 0; i < ARRAYLEN(MFAccessConditions); i++) + if (MFAccessConditions[i].cond == cond) { + return MFAccessConditions[i].description; + } + }; + + return StaticNone; +}; + int CalculateEncIVCommand(mf4Session *session, uint8_t *iv, bool verbose) { memcpy(&iv[0], session->TI, 4); memcpy(&iv[4], &session->R_Ctr, 2); diff --git a/client/mifare4.h b/client/mifare4.h index 2453797b..5d9735da 100644 --- a/client/mifare4.h +++ b/client/mifare4.h @@ -38,9 +38,16 @@ typedef enum { mtypWriteResp, } MACType_t; +typedef struct { + uint8_t cond; + char *description; +} AccessConditions_t; + extern int CalculateMAC(mf4Session *session, MACType_t mtype, uint8_t blockNum, uint8_t blockCount, uint8_t *data, int datalen, uint8_t *mac, bool verbose); extern int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool verbose); +extern char *mfGetAccessConditionsDesc(uint8_t blockn, uint8_t *data); + extern uint8_t mfNumBlocksPerSector(uint8_t sectorNo); extern uint8_t mfFirstBlockOfSector(uint8_t sectorNo); extern uint8_t mfSectorTrailer(uint8_t blockNo); From d664113aeed50a5d28a4f2235f226df62b8c2820 Mon Sep 17 00:00:00 2001 From: Vladimir Serbinenko Date: Mon, 3 Dec 2018 08:53:26 +0100 Subject: [PATCH 029/189] Support TCP ports for proxmark (#720) On ChromeOS Linux apps can't access serial port but they can connect to TCP, so I wrote a simple app to forward TCP to serial. I suppose this can have other uses as well. --- uart/uart_posix.c | 64 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 3 deletions(-) diff --git a/uart/uart_posix.c b/uart/uart_posix.c index 0e7f7f47..e3113e86 100644 --- a/uart/uart_posix.c +++ b/uart/uart_posix.c @@ -2,6 +2,7 @@ * Generic uart / rs232/ serial port library * * Copyright (c) 2013, Roel Verdult + * Copyright (c) 2018 Google * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,10 +33,12 @@ * proxmark3 project. */ -#include "uart.h" - // Test if we are dealing with posix operating systems #ifndef _WIN32 +#define _DEFAULT_SOURCE + +#include "uart.h" + #include #include #include @@ -45,6 +48,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include typedef struct termios term_info; typedef struct { @@ -56,7 +65,7 @@ typedef struct { // Set time-out on 30 miliseconds const struct timeval timeout = { .tv_sec = 0, // 0 second - .tv_usec = 30000 // 30000 micro seconds + .tv_usec = 300000 // 300000 micro seconds }; serial_port uart_open(const char* pcPortName) @@ -64,6 +73,55 @@ serial_port uart_open(const char* pcPortName) serial_port_unix* sp = malloc(sizeof(serial_port_unix)); if (sp == 0) return INVALID_SERIAL_PORT; + if (memcmp(pcPortName, "tcp:", 4) == 0) { + struct addrinfo *addr, *rp; + char *addrstr = strdup(pcPortName + 4); + if (addrstr == NULL) { + printf("Error: strdup\n"); + return INVALID_SERIAL_PORT; + } + char *colon = strrchr(addrstr, ':'); + char *portstr; + if (colon) { + portstr = colon + 1; + *colon = '\0'; + } else + portstr = "7901"; + + int s = getaddrinfo(addrstr, portstr, NULL, &addr); + if (s != 0) { + printf("Error: getaddrinfo: %s\n", gai_strerror(s)); + return INVALID_SERIAL_PORT; + } + + int sfd; + for (rp = addr; rp != NULL; rp = rp->ai_next) { + sfd = socket(rp->ai_family, rp->ai_socktype, + rp->ai_protocol); + if (sfd == -1) + continue; + + if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1) + break; + + close(sfd); + } + + if (rp == NULL) { /* No address succeeded */ + printf("Error: Could not connect\n"); + return INVALID_SERIAL_PORT; + } + + freeaddrinfo(addr); + free(addrstr); + + sp->fd = sfd; + + int one = 1; + setsockopt(sp->fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one)); + return sp; + } + sp->fd = open(pcPortName, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK); if(sp->fd == -1) { uart_close(sp); From a015ef37330ddd44c9a2d820e1def6545d4dea8d Mon Sep 17 00:00:00 2001 From: Jean-Michel Picod Date: Tue, 4 Dec 2018 08:12:05 +0100 Subject: [PATCH 030/189] Fix compilation error on OS X (#730) --- uart/uart_posix.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/uart/uart_posix.c b/uart/uart_posix.c index e3113e86..1db375b2 100644 --- a/uart/uart_posix.c +++ b/uart/uart_posix.c @@ -55,6 +55,12 @@ #include #include +// Fix missing definition on OS X. +// Taken from https://github.com/unbit/uwsgi/commit/b608eb1772641d525bfde268fe9d6d8d0d5efde7 +#ifndef SOL_TCP +#define SOL_TCP IPPROTO_TCP +#endif + typedef struct termios term_info; typedef struct { int fd; // Serial port file descriptor From aa0b1c431f5f1562041a27c06d61f54c14fe4b02 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Thu, 6 Dec 2018 07:53:25 +0100 Subject: [PATCH 031/189] Change mbedtls initializers to be compatible with older versions of gcc (#732) * fix issue #731 --- armsrc/mifareutil.c | 2 +- client/cmdhficlass.c | 4 ++-- client/cmdhfmfu.c | 2 +- client/loclass/elite_crack.c | 6 +++--- client/loclass/ikeys.c | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index 4b1f16f3..ab04aee4 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -296,7 +296,7 @@ int mifare_ultra_auth(uint8_t *keybytes){ /// 3des2k - mbedtls_des3_context ctx = { 0x00 }; + mbedtls_des3_context ctx = { {0} }; uint8_t random_a[8] = {1,1,1,1,1,1,1,1}; uint8_t random_b[8] = {0x00}; uint8_t enc_random_b[8] = {0x00}; diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index c97e433c..55804cf8 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -414,7 +414,7 @@ int CmdHFiClassDecrypt(const char *Cmd) { fseek(f, 0, SEEK_SET); uint8_t enc_dump[8] = {0}; uint8_t *decrypted = malloc(fsize); - mbedtls_des3_context ctx = { 0 }; + mbedtls_des3_context ctx = { {0} }; mbedtls_des3_set2key_dec( &ctx, key); size_t bytes_read = fread(enc_dump, 1, 8, f); @@ -466,7 +466,7 @@ static int iClassEncryptBlkData(uint8_t *blkData) { uint8_t encryptedData[16]; uint8_t *encrypted = encryptedData; - mbedtls_des3_context ctx = { 0 }; + mbedtls_des3_context ctx = { {0} }; mbedtls_des3_set2key_enc( &ctx, key); mbedtls_des3_crypt_ecb(&ctx, blkData,encrypted); diff --git a/client/cmdhfmfu.c b/client/cmdhfmfu.c index f167bae5..c3442ee3 100644 --- a/client/cmdhfmfu.c +++ b/client/cmdhfmfu.c @@ -1742,7 +1742,7 @@ int CmdHF14AMfuGenDiverseKeys(const char *Cmd){ mix[6] = block ^ uid[2]; mix[7] = uid[3]; - mbedtls_des3_context ctx = { 0x00 }; + mbedtls_des3_context ctx = { {0} }; mbedtls_des3_set2key_enc(&ctx, masterkey); mbedtls_des3_crypt_cbc(&ctx // des3_context diff --git a/client/loclass/elite_crack.c b/client/loclass/elite_crack.c index f45c55b5..0cd00830 100644 --- a/client/loclass/elite_crack.c +++ b/client/loclass/elite_crack.c @@ -179,8 +179,8 @@ void rk(uint8_t *key, uint8_t n, uint8_t *outp_key) return; } -static mbedtls_des_context ctx_enc = {0}; -static mbedtls_des_context ctx_dec = {0}; +static mbedtls_des_context ctx_enc = { {0} }; +static mbedtls_des_context ctx_dec = { {0} }; void desdecrypt_iclass(uint8_t *iclass_key, uint8_t *input, uint8_t *output) { @@ -449,7 +449,7 @@ int bruteforceItem(dumpdata item, uint16_t keytable[]) */ int calculateMasterKey(uint8_t first16bytes[], uint64_t master_key[] ) { - mbedtls_des_context ctx_e = {0}; + mbedtls_des_context ctx_e = { {0} }; uint8_t z_0[8] = {0}; uint8_t y_0[8] = {0}; diff --git a/client/loclass/ikeys.c b/client/loclass/ikeys.c index 3f90d6ee..a40d563a 100644 --- a/client/loclass/ikeys.c +++ b/client/loclass/ikeys.c @@ -72,8 +72,8 @@ From "Dismantling iclass": uint8_t pi[35] = {0x0F,0x17,0x1B,0x1D,0x1E,0x27,0x2B,0x2D,0x2E,0x33,0x35,0x39,0x36,0x3A,0x3C,0x47,0x4B,0x4D,0x4E,0x53,0x55,0x56,0x59,0x5A,0x5C,0x63,0x65,0x66,0x69,0x6A,0x6C,0x71,0x72,0x74,0x78}; -static mbedtls_des_context ctx_enc = {0}; -static mbedtls_des_context ctx_dec = {0}; +static mbedtls_des_context ctx_enc = { {0} }; +static mbedtls_des_context ctx_dec = { {0} }; static int debug_print = 0; From daccbcdc8d57d451323e19842aa7cf877a65829c Mon Sep 17 00:00:00 2001 From: Fl0-0 Date: Fri, 7 Dec 2018 14:09:41 +0100 Subject: [PATCH 032/189] Added mifare trailer block decoding for sector commands (#734) --- client/cmdhfmf.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index fa952cb9..b5c1b006 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -215,6 +215,15 @@ int CmdHF14AMfRdSc(const char *Cmd) PrintAndLog("data : %s", sprint_hex(data + i * 16, 16)); } PrintAndLog("trailer: %s", sprint_hex(data + (sectorNo<32?3:15) * 16, 16)); + + PrintAndLogEx(NORMAL, "Trailer decoded:"); + int bln = mfFirstBlockOfSector(sectorNo); + int blinc = (mfNumBlocksPerSector(sectorNo) > 4) ? 5 : 1; + for (i = 0; i < 4; i++) { + PrintAndLogEx(NORMAL, "Access block %d%s: %s", bln, ((blinc > 1) && (i < 3) ? "+" : "") , mfGetAccessConditionsDesc(i, &(data + (sectorNo<32?3:15) * 16)[6])); + bln += blinc; + } + PrintAndLogEx(NORMAL, "UserData: %s", sprint_hex_inrow(&(data + (sectorNo<32?3:15) * 16)[9], 1)); } } else { PrintAndLog("Command execute timeout"); @@ -2350,6 +2359,19 @@ int CmdHF14AMfCGetSc(const char *Cmd) { } PrintAndLog("block %3d data:%s", baseblock + i, sprint_hex(memBlock, 16)); + + if (mfIsSectorTrailer(baseblock + i)) { + PrintAndLogEx(NORMAL, "Trailer decoded:"); + PrintAndLogEx(NORMAL, "Key A: %s", sprint_hex_inrow(memBlock, 6)); + PrintAndLogEx(NORMAL, "Key B: %s", sprint_hex_inrow(&memBlock[10], 6)); + int bln = baseblock; + int blinc = (mfNumBlocksPerSector(sectorNo) > 4) ? 5 : 1; + for (int i = 0; i < 4; i++) { + PrintAndLogEx(NORMAL, "Access block %d%s: %s", bln, ((blinc > 1) && (i < 3) ? "+" : "") , mfGetAccessConditionsDesc(i, &memBlock[6])); + bln += blinc; + } + PrintAndLogEx(NORMAL, "UserData: %s", sprint_hex_inrow(&memBlock[9], 1)); + } } return 0; } From 27d06e044795c0b0ea4d34b10bccfa41d57f77fc Mon Sep 17 00:00:00 2001 From: ralik Date: Sat, 8 Dec 2018 00:10:08 +1100 Subject: [PATCH 033/189] Update default_pwd.dic (#735) --- client/default_pwd.dic | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/default_pwd.dic b/client/default_pwd.dic index 5edb83ef..754f3526 100644 --- a/client/default_pwd.dic +++ b/client/default_pwd.dic @@ -72,4 +72,5 @@ AABBCCDD, BBCCDDEE, CCDDEEFF, 0CB7E7FC, //rfidler? -FABADA11, //china? \ No newline at end of file +FABADA11, //china? +65857569, //chinese "handheld RFID writer" blue cloner from circa 2013 (also sold by xfpga.com) From 0bb514502a1d80e9b023d0e8a379f3559798eec2 Mon Sep 17 00:00:00 2001 From: Oleg Moiseenko <807634+merlokk@users.noreply.github.com> Date: Fri, 7 Dec 2018 17:42:37 +0200 Subject: [PATCH 034/189] Fido2 (#727) * add tinycbor * add client/fido * add test file with options for fido2 * hf fido commands * add changelog --- CHANGELOG.md | 1 + client/Makefile | 24 +- client/cmdhffido.c | 410 +++-- client/fido/cbortools.c | 491 ++++++ client/fido/cbortools.h | 38 + client/fido/cose.c | 240 +++ client/fido/cose.h | 27 + client/fido/fido2.json | 33 + client/fido/fidocore.c | 805 ++++++++++ client/fido/fidocore.h | 58 + client/tinycbor/Makefile | 46 + client/tinycbor/cbor.h | 606 +++++++ client/tinycbor/cborencoder.c | 645 ++++++++ .../cborencoder_close_container_checked.c | 57 + client/tinycbor/cborerrorstrings.c | 182 +++ client/tinycbor/cborinternal_p.h | 161 ++ client/tinycbor/cborjson.h | 62 + client/tinycbor/cborparser.c | 1430 +++++++++++++++++ client/tinycbor/cborparser_dup_string.c | 119 ++ client/tinycbor/cborpretty.c | 578 +++++++ client/tinycbor/cborpretty_stdio.c | 87 + client/tinycbor/cbortojson.c | 699 ++++++++ client/tinycbor/cborvalidation.c | 666 ++++++++ client/tinycbor/compilersupport_p.h | 205 +++ client/tinycbor/open_memstream.c | 114 ++ client/tinycbor/tinycbor-version.h | 3 + client/tinycbor/utf8_p.h | 104 ++ client/util.c | 11 + client/util.h | 1 + 29 files changed, 7799 insertions(+), 104 deletions(-) create mode 100644 client/fido/cbortools.c create mode 100644 client/fido/cbortools.h create mode 100644 client/fido/cose.c create mode 100644 client/fido/cose.h create mode 100644 client/fido/fido2.json create mode 100644 client/fido/fidocore.c create mode 100644 client/fido/fidocore.h create mode 100644 client/tinycbor/Makefile create mode 100644 client/tinycbor/cbor.h create mode 100644 client/tinycbor/cborencoder.c create mode 100644 client/tinycbor/cborencoder_close_container_checked.c create mode 100644 client/tinycbor/cborerrorstrings.c create mode 100644 client/tinycbor/cborinternal_p.h create mode 100644 client/tinycbor/cborjson.h create mode 100644 client/tinycbor/cborparser.c create mode 100644 client/tinycbor/cborparser_dup_string.c create mode 100644 client/tinycbor/cborpretty.c create mode 100644 client/tinycbor/cborpretty_stdio.c create mode 100644 client/tinycbor/cbortojson.c create mode 100644 client/tinycbor/cborvalidation.c create mode 100644 client/tinycbor/compilersupport_p.h create mode 100644 client/tinycbor/open_memstream.c create mode 100644 client/tinycbor/tinycbor-version.h create mode 100644 client/tinycbor/utf8_p.h diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d8993dc..e2ed8878 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added `hf fido` - FIDO U2F authenticator commands https://fidoalliance.org/ (Merlok) - Added `lf hitag reader 03` - read block (instead of pages) - Added `lf hitag reader 04` - read block (instead of pages) +- Added `hf fido` `assert` and `make` commands from fido2 protocol (authenticatorMakeCredential and authenticatorGetAssertion) (Merlok) ## [v3.1.0][2018-10-10] diff --git a/client/Makefile b/client/Makefile index 5ed4ea49..9ad8efdd 100644 --- a/client/Makefile +++ b/client/Makefile @@ -23,8 +23,12 @@ JANSSONLIBPATH = ./jansson JANSSONLIB = $(JANSSONLIBPATH)/libjansson.a MBEDTLSLIBPATH = ../common/mbedtls MBEDTLSLIB = $(MBEDTLSLIBPATH)/libmbedtls.a +CBORLIBPATH = ./tinycbor +CBORLIB = $(CBORLIBPATH)/tinycbor.a +LIBINCLUDES = -I../zlib -I../uart -I../liblua -I$(MBEDTLSLIBPATH) -I$(JANSSONLIBPATH) -I$(CBORLIBPATH) +INCLUDES_CLIENT = -I. -I../include -I../common -I/opt/local/include $(LIBINCLUDES) LDFLAGS = $(ENV_LDFLAGS) -CFLAGS = $(ENV_CFLAGS) -std=c99 -D_ISOC99_SOURCE -I. -I../include -I../common -I../common/polarssl -I../zlib -I../uart -I/opt/local/include -I../liblua -I$(JANSSONLIBPATH) -I$(MBEDTLSLIBPATH) -Wall -g -O3 +CFLAGS = $(ENV_CFLAGS) -std=c99 -D_ISOC99_SOURCE $(INCLUDES_CLIENT) -Wall -g -O3 CXXFLAGS = -I../include -Wall -O3 APP_CFLAGS = @@ -113,7 +117,10 @@ CMDSRCS = $(SRC_SMARTCARD) \ cliparser/argtable3.c\ cliparser/cliparser.c\ fido/additional_ca.c \ - mfkey.c\ + fido/cose.c \ + fido/cbortools.c \ + fido/fidocore.c \ + mfkey.c \ loclass/cipher.c \ loclass/cipherutils.c \ loclass/ikeys.c \ @@ -246,12 +253,12 @@ WINBINS = $(patsubst %, %.exe, $(BINS)) CLEAN = $(BINS) $(WINBINS) $(COREOBJS) $(CMDOBJS) $(OBJCOBJS) $(ZLIBOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(OBJDIR)/*.o *.moc.cpp ui/ui_overlays.h # need to assign dependancies to build these first... -all: lua_build jansson_build mbedtls_build $(BINS) +all: lua_build jansson_build mbedtls_build cbor_build $(BINS) all-static: LDLIBS:=-static $(LDLIBS) all-static: proxmark3 flasher fpga_compress -proxmark3: LDLIBS+=$(LUALIB) $(JANSSONLIB) $(MBEDTLSLIB) $(QTLDLIBS) +proxmark3: LDLIBS+=$(LUALIB) $(JANSSONLIB) $(MBEDTLSLIB) $(CBORLIB) $(QTLDLIBS) proxmark3: $(OBJDIR)/proxmark3.o $(COREOBJS) $(CMDOBJS) $(OBJCOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(ZLIBOBJS) lualibs/usb_cmd.lua $(LD) $(LDFLAGS) $(OBJDIR)/proxmark3.o $(COREOBJS) $(CMDOBJS) $(OBJCOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(ZLIBOBJS) $(LDLIBS) -o $@ @@ -275,8 +282,9 @@ lualibs/usb_cmd.lua: ../include/usb_cmd.h clean: $(RM) $(CLEAN) cd ../liblua && make clean - cd ./jansson && make clean + cd $(JANSSONLIBPATH) && make clean cd $(MBEDTLSLIBPATH) && make clean + cd $(CBORLIBPATH) && make clean tarbin: $(BINS) $(TAR) $(TARFLAGS) ../proxmark3-$(platform)-bin.tar $(BINS:%=client/%) $(WINBINS:%=client/%) @@ -292,7 +300,11 @@ jansson_build: mbedtls_build: @echo Compiling mbedtls cd $(MBEDTLSLIBPATH) && make all - + +cbor_build: + @echo Compiling tinycbor + cd $(CBORLIBPATH) && make all + .PHONY: all clean $(OBJDIR)/%_NOSIMD.o : %.c $(OBJDIR)/%.d diff --git a/client/cmdhffido.c b/client/cmdhffido.c index 357e265c..9c812860 100644 --- a/client/cmdhffido.c +++ b/client/cmdhffido.c @@ -28,12 +28,14 @@ #include #include #include +#include +#include +#include #include "comms.h" #include "cmdmain.h" #include "util.h" #include "ui.h" #include "proxmark3.h" -#include "cmdhf14a.h" #include "mifare.h" #include "emv/emvcore.h" #include "emv/emvjson.h" @@ -41,50 +43,12 @@ #include "cliparser/cliparser.h" #include "crypto/asn1utils.h" #include "crypto/libpcrypto.h" -#include "fido/additional_ca.h" -#include "mbedtls/x509_crt.h" -#include "mbedtls/x509.h" -#include "mbedtls/pk.h" +#include "fido/cbortools.h" +#include "fido/fidocore.h" +#include "fido/cose.h" static int CmdHelp(const char *Cmd); -int FIDOSelect(bool ActivateField, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { - uint8_t data[] = {0xA0, 0x00, 0x00, 0x06, 0x47, 0x2F, 0x00, 0x01}; - - return EMVSelect(ActivateField, LeaveFieldON, data, sizeof(data), Result, MaxResultLen, ResultLen, sw, NULL); -} - -int FIDOExchange(sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { - int res = EMVExchange(true, apdu, Result, MaxResultLen, ResultLen, sw, NULL); - if (res == 5) // apdu result (sw) not a 0x9000 - res = 0; - // software chaining - while (!res && (*sw >> 8) == 0x61) { - size_t oldlen = *ResultLen; - res = EMVExchange(true, (sAPDU){0x00, 0xC0, 0x00, 0x00, 0x00, NULL}, &Result[oldlen], MaxResultLen - oldlen, ResultLen, sw, NULL); - if (res == 5) // apdu result (sw) not a 0x9000 - res = 0; - - *ResultLen += oldlen; - if (*ResultLen > MaxResultLen) - return 100; - } - return res; -} - -int FIDORegister(uint8_t *params, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { - return FIDOExchange((sAPDU){0x00, 0x01, 0x03, 0x00, 64, params}, Result, MaxResultLen, ResultLen, sw); -} - -int FIDOAuthentication(uint8_t *params, uint8_t paramslen, uint8_t controlb, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { - return FIDOExchange((sAPDU){0x00, 0x02, controlb, 0x00, paramslen, params}, Result, MaxResultLen, ResultLen, sw); -} - -int FIDO2GetInfo(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { - uint8_t data[] = {0x04}; - return FIDOExchange((sAPDU){0x80, 0x10, 0x00, 0x00, sizeof(data), data}, Result, MaxResultLen, ResultLen, sw); -} - int CmdHFFidoInfo(const char *cmd) { if (cmd && strlen(cmd) > 0) @@ -139,9 +103,23 @@ int CmdHFFidoInfo(const char *cmd) { return 0; } + + if(buf[0]) { + PrintAndLog("FIDO2 ger version error: %d - %s", buf[0], fido2GetCmdErrorDescription(buf[0])); + return 0; + } - PrintAndLog("FIDO2 version: (%d)", len); - dump_buffer((const unsigned char *)buf, len, NULL, 0); + if (len > 1) { +// if (false) { +// PrintAndLog("FIDO2 version: (len=%d)", len); +// dump_buffer((const unsigned char *)buf, len, NULL, 0); +// } + + PrintAndLog("FIDO2 version CBOR decoded:"); + TinyCborPrintFIDOPackage(fido2CmdGetInfo, true, &buf[1], len - 1); + } else { + PrintAndLog("FIDO2 version length error"); + } return 0; } @@ -348,60 +326,7 @@ int CmdHFFidoRegister(const char *cmd) { PrintAndLog("----------------DER TLV-----------------"); } - // load CA's - mbedtls_x509_crt cacert; - mbedtls_x509_crt_init(&cacert); - res = mbedtls_x509_crt_parse(&cacert, (const unsigned char *) additional_ca_pem, additional_ca_pem_len); - if (res < 0) { - PrintAndLog("ERROR: CA parse certificate returned -0x%x - %s", -res, ecdsa_get_error(res)); - } - if (verbose) - PrintAndLog("CA load OK. %d skipped", res); - - // load DER certificate from authenticator's data - mbedtls_x509_crt cert; - mbedtls_x509_crt_init(&cert); - res = mbedtls_x509_crt_parse_der(&cert, &buf[derp], derLen); - if (res) { - PrintAndLog("ERROR: DER parse returned 0x%x - %s", (res<0)?-res:res, ecdsa_get_error(res)); - } - - // get certificate info - char linfo[300] = {0}; - if (verbose) { - mbedtls_x509_crt_info(linfo, sizeof(linfo), " ", &cert); - PrintAndLog("DER certificate info:\n%s", linfo); - } - - // verify certificate - uint32_t verifyflags = 0; - res = mbedtls_x509_crt_verify(&cert, &cacert, NULL, NULL, &verifyflags, NULL, NULL); - if (res) { - PrintAndLog("ERROR: DER verify returned 0x%x - %s", (res<0)?-res:res, ecdsa_get_error(res)); - } else { - PrintAndLog("Certificate OK."); - } - - if (verbose) { - memset(linfo, 0x00, sizeof(linfo)); - mbedtls_x509_crt_verify_info(linfo, sizeof(linfo), " ", verifyflags); - PrintAndLog("Verification info:\n%s", linfo); - } - - // get public key - res = ecdsa_public_key_from_pk(&cert.pk, public_key, sizeof(public_key)); - if (res) { - PrintAndLog("ERROR: getting public key from certificate 0x%x - %s", (res<0)?-res:res, ecdsa_get_error(res)); - } else { - if (verbose) - PrintAndLog("Got a public key from certificate:\n%s", sprint_hex_inrow(public_key, 65)); - } - - if (verbose) - PrintAndLog("------------------DER-------------------"); - - mbedtls_x509_crt_free(&cert); - mbedtls_x509_crt_free(&cacert); + FIDOCheckDERAndGetKey(&buf[derp], derLen, verbose, public_key, sizeof(public_key)); // get hash int hashp = 1 + 65 + 1 + keyHandleLen + derLen; @@ -690,12 +615,301 @@ int CmdHFFidoAuthenticate(const char *cmd) { return 0; }; +void CheckSlash(char *fileName) { + if ((fileName[strlen(fileName) - 1] != '/') && + (fileName[strlen(fileName) - 1] != '\\')) + strcat(fileName, "/"); +} + +int GetExistsFileNameJson(char *prefixDir, char *reqestedFileName, char *fileName) { + fileName[0] = 0x00; + strcpy(fileName, get_my_executable_directory()); + CheckSlash(fileName); + + strcat(fileName, prefixDir); + CheckSlash(fileName); + + strcat(fileName, reqestedFileName); + if (!strstr(fileName, ".json")) + strcat(fileName, ".json"); + + if (access(fileName, F_OK) < 0) { + strcpy(fileName, get_my_executable_directory()); + CheckSlash(fileName); + + strcat(fileName, reqestedFileName); + if (!strstr(fileName, ".json")) + strcat(fileName, ".json"); + + if (access(fileName, F_OK) < 0) { + return 1; // file not found + } + } + return 0; +} + +int CmdHFFido2MakeCredential(const char *cmd) { + json_error_t error; + json_t *root = NULL; + char fname[300] = {0}; + + CLIParserInit("hf fido make", + "Execute a FIDO2 Make Credentional command. Needs json file with parameters. Sample file `fido2.json`. File can be placed in proxmark directory or in `proxmark/fido` directory.", + "Usage:\n\thf fido make -> execute command default parameters file `fido2.json`\n" + "\thf fido make test.json -> execute command with parameters file `text.json`"); + + void* argtable[] = { + arg_param_begin, + arg_lit0("aA", "apdu", "show APDU reqests and responses"), + arg_litn("vV", "verbose", 0, 2, "show technical data. vv - show full certificates data"), + arg_lit0("tT", "tlv", "Show DER certificate contents in TLV representation"), + arg_lit0("cC", "cbor", "show CBOR decoded data"), + arg_str0(NULL, NULL, "", "JSON input / output file name for parameters. Default `fido2.json`"), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, true); + + bool APDULogging = arg_get_lit(1); + bool verbose = arg_get_lit(2); + bool verbose2 = arg_get_lit(2) > 1; + bool showDERTLV = arg_get_lit(3); + bool showCBOR = arg_get_lit(4); + + uint8_t jsonname[250] ={0}; + char *cjsonname = (char *)jsonname; + int jsonnamelen = 0; + CLIGetStrWithReturn(5, jsonname, &jsonnamelen); + + if (!jsonnamelen) { + strcat(cjsonname, "fido2"); + jsonnamelen = strlen(cjsonname); + } + + CLIParserFree(); + + SetAPDULogging(APDULogging); + + int res = GetExistsFileNameJson("fido", cjsonname, fname); + if(res) { + PrintAndLog("ERROR: Can't found the json file."); + return res; + } + PrintAndLog("fname: %s\n", fname); + root = json_load_file(fname, 0, &error); + if (!root) { + PrintAndLog("ERROR: json error on line %d: %s", error.line, error.text); + return 1; + } + + uint8_t data[2048] = {0}; + size_t datalen = 0; + uint8_t buf[2048] = {0}; + size_t len = 0; + uint16_t sw = 0; + + DropField(); + res = FIDOSelect(true, true, buf, sizeof(buf), &len, &sw); + + if (res) { + PrintAndLog("Can't select authenticator. res=%x. Exit...", res); + DropField(); + return res; + } + + if (sw != 0x9000) { + PrintAndLog("Can't select FIDO application. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + DropField(); + return 2; + } + + res = FIDO2CreateMakeCredentionalReq(root, data, sizeof(data), &datalen); + if (res) + return res; + + if (showCBOR) { + PrintAndLog("CBOR make credentional request:"); + PrintAndLog("---------------- CBOR ------------------"); + TinyCborPrintFIDOPackage(fido2CmdMakeCredential, false, data, datalen); + PrintAndLog("---------------- CBOR ------------------"); + } + + res = FIDO2MakeCredential(data, datalen, buf, sizeof(buf), &len, &sw); + DropField(); + if (res) { + PrintAndLog("Can't execute make credential command. res=%x. Exit...", res); + return res; + } + + if (sw != 0x9000) { + PrintAndLog("ERROR execute make credential command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + return 3; + } + + if(buf[0]) { + PrintAndLog("FIDO2 make credential error: %d - %s", buf[0], fido2GetCmdErrorDescription(buf[0])); + return 0; + } + + PrintAndLog("MakeCredential result (%d b) OK.", len); + if (showCBOR) { + PrintAndLog("CBOR make credentional response:"); + PrintAndLog("---------------- CBOR ------------------"); + TinyCborPrintFIDOPackage(fido2CmdMakeCredential, true, &buf[1], len - 1); + PrintAndLog("---------------- CBOR ------------------"); + } + + // parse returned cbor + FIDO2MakeCredentionalParseRes(root, &buf[1], len - 1, verbose, verbose2, showCBOR, showDERTLV); + + if (root) { + res = json_dump_file(root, fname, JSON_INDENT(2)); + if (res) { + PrintAndLog("ERROR: can't save the file: %s", fname); + return 200; + } + PrintAndLog("File `%s` saved.", fname); + } + + json_decref(root); + + return 0; +}; + +int CmdHFFido2GetAssertion(const char *cmd) { + json_error_t error; + json_t *root = NULL; + char fname[300] = {0}; + + CLIParserInit("hf fido assert", + "Execute a FIDO2 Get Assertion command. Needs json file with parameters. Sample file `fido2.json`. File can be placed in proxmark directory or in `proxmark/fido` directory.", + "Usage:\n\thf fido assert -> execute command default parameters file `fido2.json`\n" + "\thf fido assert test.json -l -> execute command with parameters file `text.json` and add to request CredentialId"); + + void* argtable[] = { + arg_param_begin, + arg_lit0("aA", "apdu", "show APDU reqests and responses"), + arg_litn("vV", "verbose", 0, 2, "show technical data. vv - show full certificates data"), + arg_lit0("cC", "cbor", "show CBOR decoded data"), + arg_lit0("lL", "list", "add CredentialId from json to allowList. Needs if `rk` option is `false` (authenticator don't store credential to its memory)"), + arg_str0(NULL, NULL, "", "JSON input / output file name for parameters. Default `fido2.json`"), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, true); + + bool APDULogging = arg_get_lit(1); + bool verbose = arg_get_lit(2); + bool verbose2 = arg_get_lit(2) > 1; + bool showCBOR = arg_get_lit(3); + bool createAllowList = arg_get_lit(4); + + uint8_t jsonname[250] ={0}; + char *cjsonname = (char *)jsonname; + int jsonnamelen = 0; + CLIGetStrWithReturn(5, jsonname, &jsonnamelen); + + if (!jsonnamelen) { + strcat(cjsonname, "fido2"); + jsonnamelen = strlen(cjsonname); + } + + CLIParserFree(); + + SetAPDULogging(APDULogging); + + int res = GetExistsFileNameJson("fido", "fido2", fname); + if(res) { + PrintAndLog("ERROR: Can't found the json file."); + return res; + } + PrintAndLog("fname: %s\n", fname); + root = json_load_file(fname, 0, &error); + if (!root) { + PrintAndLog("ERROR: json error on line %d: %s", error.line, error.text); + return 1; + } + + uint8_t data[2048] = {0}; + size_t datalen = 0; + uint8_t buf[2048] = {0}; + size_t len = 0; + uint16_t sw = 0; + + DropField(); + res = FIDOSelect(true, true, buf, sizeof(buf), &len, &sw); + + if (res) { + PrintAndLog("Can't select authenticator. res=%x. Exit...", res); + DropField(); + return res; + } + + if (sw != 0x9000) { + PrintAndLog("Can't select FIDO application. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + DropField(); + return 2; + } + + res = FIDO2CreateGetAssertionReq(root, data, sizeof(data), &datalen, createAllowList); + if (res) + return res; + + if (showCBOR) { + PrintAndLog("CBOR get assertion request:"); + PrintAndLog("---------------- CBOR ------------------"); + TinyCborPrintFIDOPackage(fido2CmdGetAssertion, false, data, datalen); + PrintAndLog("---------------- CBOR ------------------"); + } + + res = FIDO2GetAssertion(data, datalen, buf, sizeof(buf), &len, &sw); + DropField(); + if (res) { + PrintAndLog("Can't execute get assertion command. res=%x. Exit...", res); + return res; + } + + if (sw != 0x9000) { + PrintAndLog("ERROR execute get assertion command. APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + return 3; + } + + if(buf[0]) { + PrintAndLog("FIDO2 get assertion error: %d - %s", buf[0], fido2GetCmdErrorDescription(buf[0])); + return 0; + } + + PrintAndLog("GetAssertion result (%d b) OK.", len); + if (showCBOR) { + PrintAndLog("CBOR get assertion response:"); + PrintAndLog("---------------- CBOR ------------------"); + TinyCborPrintFIDOPackage(fido2CmdGetAssertion, true, &buf[1], len - 1); + PrintAndLog("---------------- CBOR ------------------"); + } + + // parse returned cbor + FIDO2GetAssertionParseRes(root, &buf[1], len - 1, verbose, verbose2, showCBOR); + + if (root) { + res = json_dump_file(root, fname, JSON_INDENT(2)); + if (res) { + PrintAndLog("ERROR: can't save the file: %s", fname); + return 200; + } + PrintAndLog("File `%s` saved.", fname); + } + + json_decref(root); + + return 0; +}; + static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help."}, {"info", CmdHFFidoInfo, 0, "Info about FIDO tag."}, {"reg", CmdHFFidoRegister, 0, "FIDO U2F Registration Message."}, {"auth", CmdHFFidoAuthenticate, 0, "FIDO U2F Authentication Message."}, + {"make", CmdHFFido2MakeCredential, 0, "FIDO2 MakeCredential command."}, + {"assert", CmdHFFido2GetAssertion, 0, "FIDO2 GetAssertion command."}, {NULL, NULL, 0, NULL} }; diff --git a/client/fido/cbortools.c b/client/fido/cbortools.c new file mode 100644 index 00000000..01691dad --- /dev/null +++ b/client/fido/cbortools.c @@ -0,0 +1,491 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2018 Merlok +// +// 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. +//----------------------------------------------------------------------------- +// Tools for work with CBOR format http://cbor.io/spec.html +// via Intel tinycbor (https://github.com/intel/tinycbor) library +//----------------------------------------------------------------------------- +// + +#include "cbortools.h" +#include +#include "emv/emvjson.h" +#include "util.h" +#include "fidocore.h" + +static void indent(int nestingLevel) { + while (nestingLevel--) + printf(" "); +} + +static CborError dumpelm(CborValue *it, bool *got_next, int nestingLevel) { + CborError err; + *got_next = false; + + CborType type = cbor_value_get_type(it); + indent(nestingLevel); + switch (type) { + case CborMapType: + case CborArrayType: { + printf(type == CborArrayType ? "Array[" : "Map["); + break; + } + + case CborIntegerType: { + int64_t val; + cbor_value_get_int64(it, &val); // can't fail + printf("%lld", (long long)val); + break; + } + + case CborByteStringType: { + uint8_t *buf; + size_t n; + err = cbor_value_dup_byte_string(it, &buf, &n, it); + *got_next = true; + if (err) + return err; // parse error + printf("%s", sprint_hex(buf, n)); + free(buf); + break; + } + + case CborTextStringType: { + char *buf; + size_t n; + err = cbor_value_dup_text_string(it, &buf, &n, it); + *got_next = true; + if (err) + return err; // parse error + printf("%s", buf); + free(buf); + break; + } + + case CborTagType: { + CborTag tag; + cbor_value_get_tag(it, &tag); + printf("Tag(%lld)", (long long)tag); + break; + } + + case CborSimpleType: { + uint8_t type; + cbor_value_get_simple_type(it, &type); + printf("simple(%u)", type); + break; + } + + case CborNullType: + printf("null"); + break; + + case CborUndefinedType: + printf("undefined"); + break; + + case CborBooleanType: { + bool val; + cbor_value_get_boolean(it, &val); // can't fail + printf("%s", val ? "true" : "false"); + break; + } + + case CborDoubleType: { + double val; + if (false) { + float f; + case CborFloatType: + cbor_value_get_float(it, &f); + val = f; + } else { + cbor_value_get_double(it, &val); + } + printf("%g", val); + break; + } + case CborHalfFloatType: { + uint16_t val; + cbor_value_get_half_float(it, &val); + printf("__f16(%04x)", val); + break; + } + + case CborInvalidType: + printf("CborInvalidType!!!"); + break; + } + + return CborNoError; +} + +static CborError dumprecursive(uint8_t cmdCode, bool isResponse, CborValue *it, bool isMapType, int nestingLevel) { + int elmCount = 0; + while (!cbor_value_at_end(it)) { + CborError err; + CborType type = cbor_value_get_type(it); +//printf("^%x^", type); + bool got_next; + + switch (type) { + case CborMapType: + case CborArrayType: { + // recursive type + CborValue recursed; + assert(cbor_value_is_container(it)); + if (!(isMapType && (elmCount % 2))) + indent(nestingLevel); + printf(type == CborArrayType ? "Array[\n" : "Map[\n"); + err = cbor_value_enter_container(it, &recursed); + if (err) + return err; // parse error + err = dumprecursive(cmdCode, isResponse, &recursed, (type == CborMapType), nestingLevel + 1); + if (err) + return err; // parse error + err = cbor_value_leave_container(it, &recursed); + if (err) + return err; // parse error + indent(nestingLevel); + printf("]"); + got_next = true; + break; + } + + default: { + err = dumpelm(it, &got_next, (isMapType && (elmCount % 2)) ? 0 : nestingLevel); + if (err) + return err; + if (cmdCode > 0 && nestingLevel == 1 && isMapType && !(elmCount % 2)) { + int64_t val; + cbor_value_get_int64(it, &val); + char *desc = fido2GetCmdMemberDescription(cmdCode, isResponse, val); + if (desc) + printf(" (%s)", desc); + } + break; + } + } + + if (!got_next) { + err = cbor_value_advance_fixed(it); + if (err) + return err; + } + if (isMapType && !(elmCount % 2)) { + printf(": "); + } else { + printf("\n"); + } + elmCount++; + } + return CborNoError; +} + +int TinyCborInit(uint8_t *data, size_t length, CborValue *cb) { + CborParser parser; + CborError err = cbor_parser_init(data, length, 0, &parser, cb); + if (err) + return err; + + return 0; +} + +int TinyCborPrintFIDOPackage(uint8_t cmdCode, bool isResponse, uint8_t *data, size_t length) { + CborValue cb; + int res; + res = TinyCborInit(data, length, &cb); + if (res) + return res; + + CborError err = dumprecursive(cmdCode, isResponse, &cb, false, 0); + + if (err) { + fprintf(stderr, +#if __WORDSIZE == 64 + "CBOR parsing failure at offset %" PRId64 " : %s\n", +#else + "CBOR parsing failure at offset %" PRId32 " : %s\n", +#endif + cb.ptr - data, cbor_error_string(err)); + return 1; + } + + return 0; +} + +int JsonObjElmCount(json_t *elm) { + int res = 0; + const char *key; + json_t *value; + + if (!json_is_object(elm)) + return 0; + + json_object_foreach(elm, key, value) { + if (strlen(key) > 0 && key[0] != '.') + res++; + } + + return res; +} + +int JsonToCbor(json_t *elm, CborEncoder *encoder) { + if (!elm || !encoder) + return 1; + + int res; + + // CBOR map == JSON object + if (json_is_object(elm)) { + CborEncoder map; + const char *key; + json_t *value; + + res = cbor_encoder_create_map(encoder, &map, JsonObjElmCount(elm)); + cbor_check(res); + + json_object_foreach(elm, key, value) { + if (strlen(key) > 0 && key[0] != '.') { + res = cbor_encode_text_stringz(&map, key); + cbor_check(res); + + // RECURSION! + JsonToCbor(value, &map); + } + } + + res = cbor_encoder_close_container(encoder, &map); + cbor_check(res); + } + + // CBOR array == JSON array + if (json_is_array(elm)) { + size_t index; + json_t *value; + CborEncoder array; + + res = cbor_encoder_create_array(encoder, &array, json_array_size(elm)); + cbor_check(res); + + json_array_foreach(elm, index, value) { + // RECURSION! + JsonToCbor(value, &array); + } + + res = cbor_encoder_close_container(encoder, &array); + cbor_check(res); + } + + if (json_is_boolean(elm)) { + res = cbor_encode_boolean(encoder, json_is_true(elm)); + cbor_check(res); + } + + if (json_is_integer(elm)) { + res = cbor_encode_int(encoder, json_integer_value(elm)); + cbor_check(res); + } + + if (json_is_real(elm)) { + res = cbor_encode_float(encoder, json_real_value(elm)); + cbor_check(res); + } + + if (json_is_string(elm)) { + const char * val = json_string_value(elm); + if (CheckStringIsHEXValue(val)) { + size_t datalen = 0; + uint8_t data[4096] = {0}; + res = JsonLoadBufAsHex(elm, "$", data, sizeof(data), &datalen); + if (res) + return 100; + + res = cbor_encode_byte_string(encoder, data, datalen); + cbor_check(res); + } else { + res = cbor_encode_text_stringz(encoder, val); + cbor_check(res); + } + } + + + + return 0; +} + +int CborMapGetKeyById(CborParser *parser, CborValue *map, uint8_t *data, size_t dataLen, int key) { + CborValue cb; + + CborError err = cbor_parser_init(data, dataLen, 0, parser, &cb); + cbor_check(err); + + if (cbor_value_get_type(&cb) != CborMapType) + return 1; + + err = cbor_value_enter_container(&cb, map); + cbor_check(err); + + int64_t indx; + while (!cbor_value_at_end(map)) { + // check number + if (cbor_value_get_type(map) != CborIntegerType) + return 1; + + cbor_value_get_int64(map, &indx); + + err = cbor_value_advance(map); + cbor_check(err); + + if (indx == key) + return 0; + + // pass value + err = cbor_value_advance(map); + cbor_check(err); + } + + err = cbor_value_leave_container(&cb, map); + cbor_check(err); + + return 2; +} + +CborError CborGetArrayBinStringValue(CborValue *elm, uint8_t *data, size_t maxdatalen, size_t *datalen) { + return CborGetArrayBinStringValueEx(elm, data, maxdatalen, datalen, NULL, 0); +} + +CborError CborGetArrayBinStringValueEx(CborValue *elm, uint8_t *data, size_t maxdatalen, size_t *datalen, uint8_t *delimeter, size_t delimeterlen) { + CborValue array; + if (datalen) + *datalen = 0; + + size_t slen = maxdatalen; + size_t totallen = 0; + + CborError res = cbor_value_enter_container(elm, &array); + cbor_check(res); + + while (!cbor_value_at_end(&array)) { + res = cbor_value_copy_byte_string(&array, &data[totallen], &slen, &array); + cbor_check(res); + + totallen += slen; + if (delimeter) { + memcpy(&data[totallen], delimeter, delimeterlen); + totallen += delimeterlen; + } + slen = maxdatalen - totallen; + } + + res = cbor_value_leave_container(elm, &array); + cbor_check(res); + + if (datalen) + *datalen = totallen; + + return CborNoError; +}; + +CborError CborGetBinStringValue(CborValue *elm, uint8_t *data, size_t maxdatalen, size_t *datalen) { + if (datalen) + *datalen = 0; + + size_t slen = maxdatalen; + + CborError res = cbor_value_copy_byte_string(elm, data, &slen, elm); + cbor_check(res); + + if (datalen) + *datalen = slen; + + return CborNoError; +}; + +CborError CborGetArrayStringValue(CborValue *elm, char *data, size_t maxdatalen, size_t *datalen, char *delimeter) { + CborValue array; + if (datalen) + *datalen = 0; + + size_t slen = maxdatalen; + size_t totallen = 0; + + CborError res = cbor_value_enter_container(elm, &array); + cbor_check(res); + + while (!cbor_value_at_end(&array)) { + res = cbor_value_copy_text_string(&array, &data[totallen], &slen, &array); + cbor_check(res); + + totallen += slen; + if (delimeter) { + strcat(data, delimeter); + totallen += strlen(delimeter); + } + slen = maxdatalen - totallen; + data[totallen] = 0x00; + } + + res = cbor_value_leave_container(elm, &array); + cbor_check(res); + + if (datalen) + *datalen = totallen; + + return CborNoError; +}; + +CborError CborGetStringValue(CborValue *elm, char *data, size_t maxdatalen, size_t *datalen) { + if (datalen) + *datalen = 0; + + size_t slen = maxdatalen; + + CborError res = cbor_value_copy_text_string(elm, data, &slen, elm); + cbor_check(res); + + if (datalen) + *datalen = slen; + + return CborNoError; +}; + +CborError CborGetStringValueBuf(CborValue *elm) { + static char stringBuf[2048]; + memset(stringBuf, 0x00, sizeof(stringBuf)); + + return CborGetStringValue(elm, stringBuf, sizeof(stringBuf), NULL); +}; + +int CBOREncodeElm(json_t *root, char *rootElmId, CborEncoder *encoder) { + json_t *elm = NULL; + if (rootElmId && strlen(rootElmId) && rootElmId[0] == '$') + elm = json_path_get(root, rootElmId); + else + elm = json_object_get(root, rootElmId); + + if (!elm) + return 1; + + int res = JsonToCbor(elm, encoder); + + return res; +} + +CborError CBOREncodeClientDataHash(json_t *root, CborEncoder *encoder) { + uint8_t buf[100] = {0}; + size_t jlen; + + JsonLoadBufAsHex(root, "$.ClientDataHash", buf, sizeof(buf), &jlen); + + // fill with 0x00 if not found + if (!jlen) + jlen = 32; + + int res = cbor_encode_byte_string(encoder, buf, jlen); + cbor_check(res); + + return 0; +} diff --git a/client/fido/cbortools.h b/client/fido/cbortools.h new file mode 100644 index 00000000..1e3fa8c0 --- /dev/null +++ b/client/fido/cbortools.h @@ -0,0 +1,38 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2018 Merlok +// +// 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. +//----------------------------------------------------------------------------- +// Tools for work with CBOR format http://cbor.io/spec.html +// via Intel tinycbor (https://github.com/intel/tinycbor) library +//----------------------------------------------------------------------------- +// + +#ifndef __CBORTOOLS_H__ +#define __CBORTOOLS_H__ + +#include +#include +#include +#include + +#define cbor_check_if(r) if ((r) != CborNoError) {return r;} else +#define cbor_check(r) if ((r) != CborNoError) return r; + +extern int TinyCborPrintFIDOPackage(uint8_t cmdCode, bool isResponse, uint8_t *data, size_t length); +extern int JsonToCbor(json_t *elm, CborEncoder *encoder); + +extern int CborMapGetKeyById(CborParser *parser, CborValue *map, uint8_t *data, size_t dataLen, int key); +extern CborError CborGetArrayBinStringValue(CborValue *elm, uint8_t *data, size_t maxdatalen, size_t *datalen); +extern CborError CborGetArrayBinStringValueEx(CborValue *elm, uint8_t *data, size_t maxdatalen, size_t *datalen, uint8_t *delimeter, size_t delimeterlen); +extern CborError CborGetBinStringValue(CborValue *elm, uint8_t *data, size_t maxdatalen, size_t *datalen); +extern CborError CborGetArrayStringValue(CborValue *elm, char *data, size_t maxdatalen, size_t *datalen, char *delimeter); +extern CborError CborGetStringValue(CborValue *elm, char *data, size_t maxdatalen, size_t *datalen); +extern CborError CborGetStringValueBuf(CborValue *elm); + +extern int CBOREncodeElm(json_t *root, char *rootElmId, CborEncoder *encoder); +extern CborError CBOREncodeClientDataHash(json_t *root, CborEncoder *encoder); + +#endif /* __CBORTOOLS_H__ */ diff --git a/client/fido/cose.c b/client/fido/cose.c new file mode 100644 index 00000000..1184250f --- /dev/null +++ b/client/fido/cose.c @@ -0,0 +1,240 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2018 Merlok +// +// 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. +//----------------------------------------------------------------------------- +// Tools for work with COSE (CBOR Object Signing and Encryption) rfc8152 +// https://tools.ietf.org/html/rfc8152 +//----------------------------------------------------------------------------- +// + +#include "cose.h" +#include +#include "cbortools.h" +#include "util.h" +#include "ui.h" + +static const char COSEEmptyStr[] = ""; + +typedef struct { + int Value; + char *Name; + char *Description; +} COSEValueNameDesc_t; + +typedef struct { + int Value; + char *Type; + char *Name; + char *Description; +} COSEValueTypeNameDesc_t; + +// kty - Key Type Values +COSEValueNameDesc_t COSEKeyTypeValueDesc[] = { + {0, "Reserved", "Reserved"}, + {1, "OKP", "Octet Key Pair"}, + {2, "EC2", "Elliptic Curve Key w/ x- and y-coordinate pair"}, + {4, "Symmetric", "Symmetric Key"}, +}; + +COSEValueNameDesc_t *GetCOSEktyElm(int id) { + for (int i = 0; i < ARRAYLEN(COSEKeyTypeValueDesc); i++) + if (COSEKeyTypeValueDesc[i].Value == id) + return &COSEKeyTypeValueDesc[i]; + return NULL; +} + +const char *GetCOSEktyDescription(int id) { + COSEValueNameDesc_t *elm = GetCOSEktyElm(id); + if (elm) + return elm->Description; + return COSEEmptyStr; +} + +// keys +COSEValueTypeNameDesc_t COSECurvesDesc[] = { + {1, "EC2", "P-256", "NIST P-256 also known as secp256r1"}, + {2, "EC2", "P-384", "NIST P-384 also known as secp384r1"}, + {3, "EC2", "P-521", "NIST P-521 also known as secp521r1"}, + {4, "OKP", "X25519", "X25519 for use w/ ECDH only"}, + {5, "OKP", "X448", "X448 for use w/ ECDH only"}, + {6, "OKP", "Ed25519", "Ed25519 for use w/ EdDSA only"}, + {7, "OKP", "Ed448", "Ed448 for use w/ EdDSA only"}, +}; + +COSEValueTypeNameDesc_t *GetCOSECurveElm(int id) { + for (int i = 0; i < ARRAYLEN(COSECurvesDesc); i++) + if (COSECurvesDesc[i].Value == id) + return &COSECurvesDesc[i]; + return NULL; +} + +const char *GetCOSECurveDescription(int id) { + COSEValueTypeNameDesc_t *elm = GetCOSECurveElm(id); + if (elm) + return elm->Description; + return COSEEmptyStr; +} + +// RFC8152 https://www.iana.org/assignments/cose/cose.xhtml#algorithms +COSEValueNameDesc_t COSEAlg[] = { + {-65536, "Unassigned", "Unassigned"}, + {-65535, "RS1", "RSASSA-PKCS1-v1_5 w/ SHA-1"}, + {-259, "RS512", "RSASSA-PKCS1-v1_5 w/ SHA-512"}, + {-258, "RS384", "RSASSA-PKCS1-v1_5 w/ SHA-384"}, + {-257, "RS256", "RSASSA-PKCS1-v1_5 w/ SHA-256"}, + {-42, "RSAES-OAEP w/ SHA-512", "RSAES-OAEP w/ SHA-512"}, + {-41, "RSAES-OAEP w/ SHA-256", "RSAES-OAEP w/ SHA-256"}, + {-40, "RSAES-OAEP w/ RFC 8017 def param", "RSAES-OAEP w/ SHA-1"}, + {-39, "PS512", "RSASSA-PSS w/ SHA-512"}, + {-38, "PS384", "RSASSA-PSS w/ SHA-384"}, + {-37, "PS256", "RSASSA-PSS w/ SHA-256"}, + {-36, "ES512", "ECDSA w/ SHA-512"}, + {-35, "ES384", "ECDSA w/ SHA-384"}, + {-34, "ECDH-SS + A256KW", "ECDH SS w/ Concat KDF and AES Key Wrap w/ 256-bit key"}, + {-33, "ECDH-SS + A192KW", "ECDH SS w/ Concat KDF and AES Key Wrap w/ 192-bit key"}, + {-32, "ECDH-SS + A128KW", "ECDH SS w/ Concat KDF and AES Key Wrap w/ 128-bit key"}, + {-31, "ECDH-ES + A256KW", "ECDH ES w/ Concat KDF and AES Key Wrap w/ 256-bit key"}, + {-30, "ECDH-ES + A192KW", "ECDH ES w/ Concat KDF and AES Key Wrap w/ 192-bit key"}, + {-29, "ECDH-ES + A128KW", "ECDH ES w/ Concat KDF and AES Key Wrap w/ 128-bit key"}, + {-28, "ECDH-SS + HKDF-512", "ECDH SS w/ HKDF - generate key directly"}, + {-27, "ECDH-SS + HKDF-256", "ECDH SS w/ HKDF - generate key directly"}, + {-26, "ECDH-ES + HKDF-512", "ECDH ES w/ HKDF - generate key directly"}, + {-25, "ECDH-ES + HKDF-256", "ECDH ES w/ HKDF - generate key directly"}, + {-13, "direct+HKDF-AES-256", "Shared secret w/ AES-MAC 256-bit key"}, + {-12, "direct+HKDF-AES-128", "Shared secret w/ AES-MAC 128-bit key"}, + {-11, "direct+HKDF-SHA-512", "Shared secret w/ HKDF and SHA-512"}, + {-10, "direct+HKDF-SHA-256", "Shared secret w/ HKDF and SHA-256"}, + {-8, "EdDSA", "EdDSA"}, + {-7, "ES256", "ECDSA w/ SHA-256"}, + {-6, "direct", "Direct use of CEK"}, + {-5, "A256KW", "AES Key Wrap w/ 256-bit key"}, + {-4, "A192KW", "AES Key Wrap w/ 192-bit key"}, + {-3, "A128KW", "AES Key Wrap w/ 128-bit key"}, + {0, "Reserved", "Reserved"}, + {1, "A128GCM", "AES-GCM mode w/ 128-bit key, 128-bit tag"}, + {2, "A192GCM", "AES-GCM mode w/ 192-bit key, 128-bit tag"}, + {3, "A256GCM", "AES-GCM mode w/ 256-bit key, 128-bit tag"}, + {4, "HMAC 256/64", "HMAC w/ SHA-256 truncated to 64 bits"}, + {5, "HMAC 256/256", "HMAC w/ SHA-256"}, + {6, "HMAC 384/384", "HMAC w/ SHA-384"}, + {7, "HMAC 512/512", "HMAC w/ SHA-512"}, + {10, "AES-CCM-16-64-128", "AES-CCM mode 128-bit key, 64-bit tag, 13-byte nonce"}, + {11, "AES-CCM-16-64-256", "AES-CCM mode 256-bit key, 64-bit tag, 13-byte nonce"}, + {12, "AES-CCM-64-64-128", "AES-CCM mode 128-bit key, 64-bit tag, 7-byte nonce"}, + {13, "AES-CCM-64-64-256", "AES-CCM mode 256-bit key, 64-bit tag, 7-byte nonce"}, + {14, "AES-MAC 128/64", "AES-MAC 128-bit key, 64-bit tag"}, + {15, "AES-MAC 256/64", "AES-MAC 256-bit key, 64-bit tag"}, + {24, "ChaCha20/Poly1305", "ChaCha20/Poly1305 w/ 256-bit key, 128-bit tag"}, + {25, "AES-MAC 128/128", "AES-MAC 128-bit key, 128-bit tag"}, + {26, "AES-MAC 256/128", "AES-MAC 256-bit key, 128-bit tag"}, + {30, "AES-CCM-16-128-128", "AES-CCM mode 128-bit key, 128-bit tag, 13-byte nonce"}, + {31, "AES-CCM-16-128-256", "AES-CCM mode 256-bit key, 128-bit tag, 13-byte nonce"}, + {32, "AES-CCM-64-128-128", "AES-CCM mode 128-bit key, 128-bit tag, 7-byte nonce"}, + {33, "AES-CCM-64-128-256", "AES-CCM mode 256-bit key, 128-bit tag, 7-byte nonce"} +}; + +COSEValueNameDesc_t *GetCOSEAlgElm(int id) { + for (int i = 0; i < ARRAYLEN(COSEAlg); i++) + if (COSEAlg[i].Value == id) + return &COSEAlg[i]; + return NULL; +} + +const char *GetCOSEAlgName(int id) { + COSEValueNameDesc_t *elm = GetCOSEAlgElm(id); + if (elm) + return elm->Name; + return COSEEmptyStr; +} + +const char *GetCOSEAlgDescription(int id) { + COSEValueNameDesc_t *elm = GetCOSEAlgElm(id); + if (elm) + return elm->Description; + return COSEEmptyStr; +} + +int COSEGetECDSAKey(uint8_t *data, size_t datalen, bool verbose, uint8_t *public_key) { + CborParser parser; + CborValue map; + int64_t i64; + size_t len; + + if(verbose) + PrintAndLog("----------- CBOR decode ----------------"); + + // kty + int res = CborMapGetKeyById(&parser, &map, data, datalen, 1); + if(!res) { + cbor_value_get_int64(&map, &i64); + if(verbose) + PrintAndLog("kty [%lld] %s", (long long)i64, GetCOSEktyDescription(i64)); + if (i64 != 2) + PrintAndLog("ERROR: kty must be 2."); + } + + // algorithm + res = CborMapGetKeyById(&parser, &map, data, datalen, 3); + if(!res) { + cbor_value_get_int64(&map, &i64); + if(verbose) + PrintAndLog("algorithm [%lld] %s", (long long)i64, GetCOSEAlgDescription(i64)); + if (i64 != -7) + PrintAndLog("ERROR: algorithm must be -7."); + } + + // curve + res = CborMapGetKeyById(&parser, &map, data, datalen, -1); + if(!res) { + cbor_value_get_int64(&map, &i64); + if(verbose) + PrintAndLog("curve [%lld] %s", (long long)i64, GetCOSECurveDescription(i64)); + if (i64 != 1) + PrintAndLog("ERROR: curve must be 1."); + } + + // plain key + public_key[0] = 0x04; + + // x - coordinate + res = CborMapGetKeyById(&parser, &map, data, datalen, -2); + if(!res) { + res = CborGetBinStringValue(&map, &public_key[1], 32, &len); + cbor_check(res); + if(verbose) + PrintAndLog("x - coordinate [%d]: %s", len, sprint_hex(&public_key[1], 32)); + if (len != 32) + PrintAndLog("ERROR: x - coordinate length must be 32."); + } + + // y - coordinate + res = CborMapGetKeyById(&parser, &map, data, datalen, -3); + if(!res) { + res = CborGetBinStringValue(&map, &public_key[33], 32, &len); + cbor_check(res); + if(verbose) + PrintAndLog("y - coordinate [%d]: %s", len, sprint_hex(&public_key[33], 32)); + if (len != 32) + PrintAndLog("ERROR: y - coordinate length must be 32."); + } + + // d - private key + uint8_t private_key[128] = {0}; + res = CborMapGetKeyById(&parser, &map, data, datalen, -4); + if(!res) { + res = CborGetBinStringValue(&map, private_key, sizeof(private_key), &len); + cbor_check(res); + if(verbose) + PrintAndLog("d - private key [%d]: %s", len, sprint_hex(private_key, len)); + } + + if(verbose) + PrintAndLog("----------- CBOR decode ----------------"); + + return 0; +} + + diff --git a/client/fido/cose.h b/client/fido/cose.h new file mode 100644 index 00000000..850652fc --- /dev/null +++ b/client/fido/cose.h @@ -0,0 +1,27 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2018 Merlok +// +// 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. +//----------------------------------------------------------------------------- +// Tools for work with COSE (CBOR Object Signing and Encryption) rfc8152 +// https://tools.ietf.org/html/rfc8152 +//----------------------------------------------------------------------------- +// + +#ifndef __COSE_H__ +#define __COSE_H__ + +#include +#include +#include + +extern const char *GetCOSEAlgName(int id); +extern const char *GetCOSEAlgDescription(int id); +extern const char *GetCOSEktyDescription(int id); +extern const char *GetCOSECurveDescription(int id); + +extern int COSEGetECDSAKey(uint8_t *data, size_t datalen, bool verbose, uint8_t *public_key); + +#endif /* __COSE_H__ */ diff --git a/client/fido/fido2.json b/client/fido/fido2.json new file mode 100644 index 00000000..abbfae5d --- /dev/null +++ b/client/fido/fido2.json @@ -0,0 +1,33 @@ +{ + "ClientDataHash": "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f", + "RelyingPartyEntity": { + "id": "acme.com", + "name": "Acme" + }, + "UserEntity": { + "id": "00000000000000000000000000000001", + "icon": "https://pics.acme.com/00/p/aBjjjpqPb.png", + "name": "johnpsmith@acme.com", + "displayName": "John P. Smith" + }, + "pubKeyCredParams": [ + { + "type": "public-key", + "alg": -7, + ".name": "ES256" + }, + { + "type": "public-key", + "alg": -257, + ".name": "RS256" + } + ], + "MakeCredentialOptions": { + "uv": false, + "rk": true + }, + "GetAssertionOptions": { + "up": true, + "uv": false + } +} diff --git a/client/fido/fidocore.c b/client/fido/fidocore.c new file mode 100644 index 00000000..39c2052f --- /dev/null +++ b/client/fido/fidocore.c @@ -0,0 +1,805 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2018 Merlok +// +// 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. +//----------------------------------------------------------------------------- +// FIDO2 authenticators core data and commands +// https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html +//----------------------------------------------------------------------------- +// + +#include "fidocore.h" +#include "emv/emvcore.h" +#include "emv/emvjson.h" +#include +#include "cbortools.h" +#include +#include +#include +#include "crypto/asn1utils.h" +#include "crypto/libpcrypto.h" +#include "fido/additional_ca.h" +#include "fido/cose.h" + +typedef struct { + uint8_t ErrorCode; + char *ShortDescription; + char *Description; +} fido2Error_t; + +fido2Error_t fido2Errors[] = { + {0xFF, "n/a", "n/a"}, + {0x00, "CTAP1_ERR_SUCCESS", "Indicates successful response."}, + {0x01, "CTAP1_ERR_INVALID_COMMAND", "The command is not a valid CTAP command."}, + {0x02, "CTAP1_ERR_INVALID_PARAMETER", "The command included an invalid parameter."}, + {0x03, "CTAP1_ERR_INVALID_LENGTH", "Invalid message or item length."}, + {0x04, "CTAP1_ERR_INVALID_SEQ", "Invalid message sequencing."}, + {0x05, "CTAP1_ERR_TIMEOUT", "Message timed out."}, + {0x06, "CTAP1_ERR_CHANNEL_BUSY", "Channel busy."}, + {0x0A, "CTAP1_ERR_LOCK_REQUIRED", "Command requires channel lock."}, + {0x0B, "CTAP1_ERR_INVALID_CHANNEL", "Command not allowed on this cid."}, + {0x10, "CTAP2_ERR_CBOR_PARSING", "Error while parsing CBOR."}, + {0x11, "CTAP2_ERR_CBOR_UNEXPECTED_TYPE", "Invalid/unexpected CBOR error."}, + {0x12, "CTAP2_ERR_INVALID_CBOR", "Error when parsing CBOR."}, + {0x13, "CTAP2_ERR_INVALID_CBOR_TYPE", "Invalid or unexpected CBOR type."}, + {0x14, "CTAP2_ERR_MISSING_PARAMETER", "Missing non-optional parameter."}, + {0x15, "CTAP2_ERR_LIMIT_EXCEEDED", "Limit for number of items exceeded."}, + {0x16, "CTAP2_ERR_UNSUPPORTED_EXTENSION", "Unsupported extension."}, + {0x17, "CTAP2_ERR_TOO_MANY_ELEMENTS", "Limit for number of items exceeded."}, + {0x18, "CTAP2_ERR_EXTENSION_NOT_SUPPORTED", "Unsupported extension."}, + {0x19, "CTAP2_ERR_CREDENTIAL_EXCLUDED", "Valid credential found in the exludeList."}, + {0x20, "CTAP2_ERR_CREDENTIAL_NOT_VALID", "Credential not valid for authenticator."}, + {0x21, "CTAP2_ERR_PROCESSING", "Processing (Lengthy operation is in progress)."}, + {0x22, "CTAP2_ERR_INVALID_CREDENTIAL", "Credential not valid for the authenticator."}, + {0x23, "CTAP2_ERR_USER_ACTION_PENDING", "Authentication is waiting for user interaction."}, + {0x24, "CTAP2_ERR_OPERATION_PENDING", "Processing, lengthy operation is in progress."}, + {0x25, "CTAP2_ERR_NO_OPERATIONS", "No request is pending."}, + {0x26, "CTAP2_ERR_UNSUPPORTED_ALGORITHM", "Authenticator does not support requested algorithm."}, + {0x27, "CTAP2_ERR_OPERATION_DENIED", "Not authorized for requested operation."}, + {0x28, "CTAP2_ERR_KEY_STORE_FULL", "Internal key storage is full."}, + {0x29, "CTAP2_ERR_NOT_BUSY", "Authenticator cannot cancel as it is not busy."}, + {0x2A, "CTAP2_ERR_NO_OPERATION_PENDING", "No outstanding operations."}, + {0x2B, "CTAP2_ERR_UNSUPPORTED_OPTION", "Unsupported option."}, + {0x2C, "CTAP2_ERR_INVALID_OPTION", "Unsupported option."}, + {0x2D, "CTAP2_ERR_KEEPALIVE_CANCEL", "Pending keep alive was cancelled."}, + {0x2E, "CTAP2_ERR_NO_CREDENTIALS", "No valid credentials provided."}, + {0x2F, "CTAP2_ERR_USER_ACTION_TIMEOUT", "Timeout waiting for user interaction."}, + {0x30, "CTAP2_ERR_NOT_ALLOWED", "Continuation command, such as, authenticatorGetNextAssertion not allowed."}, + {0x31, "CTAP2_ERR_PIN_INVALID", "PIN Blocked."}, + {0x32, "CTAP2_ERR_PIN_BLOCKED", "PIN Blocked."}, + {0x33, "CTAP2_ERR_PIN_AUTH_INVALID", "PIN authentication,pinAuth, verification failed."}, + {0x34, "CTAP2_ERR_PIN_AUTH_BLOCKED", "PIN authentication,pinAuth, blocked. Requires power recycle to reset."}, + {0x35, "CTAP2_ERR_PIN_NOT_SET", "No PIN has been set."}, + {0x36, "CTAP2_ERR_PIN_REQUIRED", "PIN is required for the selected operation."}, + {0x37, "CTAP2_ERR_PIN_POLICY_VIOLATION", "PIN policy violation. Currently only enforces minimum length."}, + {0x38, "CTAP2_ERR_PIN_TOKEN_EXPIRED", "pinToken expired on authenticator."}, + {0x39, "CTAP2_ERR_REQUEST_TOO_LARGE", "Authenticator cannot handle this request due to memory constraints."}, + {0x7F, "CTAP1_ERR_OTHER", "Other unspecified error."}, + {0xDF, "CTAP2_ERR_SPEC_LAST", "CTAP 2 spec last error."}, +}; + +typedef struct { + fido2Commands Command; + fido2PacketType PckType; + int MemberNumber; + char *Description; +} fido2Desc_t; + +fido2Desc_t fido2CmdGetInfoRespDesc[] = { + {fido2CmdMakeCredential, ptResponse, 0x01, "fmt"}, + {fido2CmdMakeCredential, ptResponse, 0x02, "authData"}, + {fido2CmdMakeCredential, ptResponse, 0x03, "attStmt"}, + + {fido2CmdMakeCredential, ptQuery, 0x01, "clientDataHash"}, + {fido2CmdMakeCredential, ptQuery, 0x02, "rp"}, + {fido2CmdMakeCredential, ptQuery, 0x03, "user"}, + {fido2CmdMakeCredential, ptQuery, 0x04, "pubKeyCredParams"}, + {fido2CmdMakeCredential, ptQuery, 0x05, "excludeList"}, + {fido2CmdMakeCredential, ptQuery, 0x06, "extensions"}, + {fido2CmdMakeCredential, ptQuery, 0x07, "options"}, + {fido2CmdMakeCredential, ptQuery, 0x08, "pinAuth"}, + {fido2CmdMakeCredential, ptQuery, 0x09, "pinProtocol"}, + + {fido2CmdGetAssertion, ptResponse, 0x01, "credential"}, + {fido2CmdGetAssertion, ptResponse, 0x02, "authData"}, + {fido2CmdGetAssertion, ptResponse, 0x03, "signature"}, + {fido2CmdGetAssertion, ptResponse, 0x04, "publicKeyCredentialUserEntity"}, + {fido2CmdGetAssertion, ptResponse, 0x05, "numberOfCredentials"}, + + {fido2CmdGetAssertion, ptQuery, 0x01, "rpId"}, + {fido2CmdGetAssertion, ptQuery, 0x02, "clientDataHash"}, + {fido2CmdGetAssertion, ptQuery, 0x03, "allowList"}, + {fido2CmdGetAssertion, ptQuery, 0x04, "extensions"}, + {fido2CmdGetAssertion, ptQuery, 0x05, "options"}, + {fido2CmdGetAssertion, ptQuery, 0x06, "pinAuth"}, + {fido2CmdGetAssertion, ptQuery, 0x07, "pinProtocol"}, + + {fido2CmdGetNextAssertion, ptResponse, 0x01, "credential"}, + {fido2CmdGetNextAssertion, ptResponse, 0x02, "authData"}, + {fido2CmdGetNextAssertion, ptResponse, 0x03, "signature"}, + {fido2CmdGetNextAssertion, ptResponse, 0x04, "publicKeyCredentialUserEntity"}, + + {fido2CmdGetInfo, ptResponse, 0x01, "versions"}, + {fido2CmdGetInfo, ptResponse, 0x02, "extensions"}, + {fido2CmdGetInfo, ptResponse, 0x03, "aaguid"}, + {fido2CmdGetInfo, ptResponse, 0x04, "options"}, + {fido2CmdGetInfo, ptResponse, 0x05, "maxMsgSize"}, + {fido2CmdGetInfo, ptResponse, 0x06, "pinProtocols"}, + + {fido2CmdClientPIN, ptResponse, 0x01, "keyAgreement"}, + {fido2CmdClientPIN, ptResponse, 0x02, "pinToken"}, + {fido2CmdClientPIN, ptResponse, 0x03, "retries"}, + + {fido2CmdClientPIN, ptQuery, 0x01, "pinProtocol"}, + {fido2CmdClientPIN, ptQuery, 0x02, "subCommand"}, + {fido2CmdClientPIN, ptQuery, 0x03, "keyAgreement"}, + {fido2CmdClientPIN, ptQuery, 0x04, "pinAuth"}, + {fido2CmdClientPIN, ptQuery, 0x05, "newPinEnc"}, + {fido2CmdClientPIN, ptQuery, 0x06, "pinHashEnc"}, + {fido2CmdClientPIN, ptQuery, 0x07, "getKeyAgreement"}, + {fido2CmdClientPIN, ptQuery, 0x08, "getRetries"}, + + {fido2COSEKey, ptResponse, 0x01, "kty"}, + {fido2COSEKey, ptResponse, 0x03, "alg"}, + {fido2COSEKey, ptResponse, -1, "crv"}, + {fido2COSEKey, ptResponse, -2, "x - coordinate"}, + {fido2COSEKey, ptResponse, -3, "y - coordinate"}, + {fido2COSEKey, ptResponse, -4, "d - private key"}, +}; + +char *fido2GetCmdErrorDescription(uint8_t errorCode) { + for (int i = 0; i < sizeof(fido2Errors) / sizeof(fido2Error_t); i++) + if (fido2Errors[i].ErrorCode == errorCode) + return fido2Errors[i].Description; + + return fido2Errors[0].Description; +} + +char *fido2GetCmdMemberDescription(uint8_t cmdCode, bool isResponse, int memberNum) { + for (int i = 0; i < sizeof(fido2CmdGetInfoRespDesc) / sizeof(fido2Desc_t); i++) + if (fido2CmdGetInfoRespDesc[i].Command == cmdCode && + fido2CmdGetInfoRespDesc[i].PckType == (isResponse ? ptResponse : ptQuery) && + fido2CmdGetInfoRespDesc[i].MemberNumber == memberNum ) + return fido2CmdGetInfoRespDesc[i].Description; + + return NULL; +} + +int FIDOSelect(bool ActivateField, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { + uint8_t data[] = {0xA0, 0x00, 0x00, 0x06, 0x47, 0x2F, 0x00, 0x01}; + + return EMVSelect(ActivateField, LeaveFieldON, data, sizeof(data), Result, MaxResultLen, ResultLen, sw, NULL); +} + +int FIDOExchange(sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { + int res = EMVExchange(true, apdu, Result, MaxResultLen, ResultLen, sw, NULL); + if (res == 5) // apdu result (sw) not a 0x9000 + res = 0; + // software chaining + while (!res && (*sw >> 8) == 0x61) { + size_t oldlen = *ResultLen; + res = EMVExchange(true, (sAPDU){0x00, 0xC0, 0x00, 0x00, 0x00, NULL}, &Result[oldlen], MaxResultLen - oldlen, ResultLen, sw, NULL); + if (res == 5) // apdu result (sw) not a 0x9000 + res = 0; + + *ResultLen += oldlen; + if (*ResultLen > MaxResultLen) + return 100; + } + return res; +} + +int FIDORegister(uint8_t *params, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { + return FIDOExchange((sAPDU){0x00, 0x01, 0x03, 0x00, 64, params}, Result, MaxResultLen, ResultLen, sw); +} + +int FIDOAuthentication(uint8_t *params, uint8_t paramslen, uint8_t controlb, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { + return FIDOExchange((sAPDU){0x00, 0x02, controlb, 0x00, paramslen, params}, Result, MaxResultLen, ResultLen, sw); +} + +int FIDO2GetInfo(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { + uint8_t data[] = {fido2CmdGetInfo}; + return FIDOExchange((sAPDU){0x80, 0x10, 0x00, 0x00, sizeof(data), data}, Result, MaxResultLen, ResultLen, sw); +} + +int FIDO2MakeCredential(uint8_t *params, uint8_t paramslen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { + uint8_t data[paramslen + 1]; + data[0] = fido2CmdMakeCredential; + memcpy(&data[1], params, paramslen); + return FIDOExchange((sAPDU){0x80, 0x10, 0x00, 0x00, sizeof(data), data}, Result, MaxResultLen, ResultLen, sw); +} + +int FIDO2GetAssertion(uint8_t *params, uint8_t paramslen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { + uint8_t data[paramslen + 1]; + data[0] = fido2CmdGetAssertion; + memcpy(&data[1], params, paramslen); + return FIDOExchange((sAPDU){0x80, 0x10, 0x00, 0x00, sizeof(data), data}, Result, MaxResultLen, ResultLen, sw); +} + +int FIDOCheckDERAndGetKey(uint8_t *der, size_t derLen, bool verbose, uint8_t *publicKey, size_t publicKeyMaxLen) { + int res; + + // load CA's + mbedtls_x509_crt cacert; + mbedtls_x509_crt_init(&cacert); + res = mbedtls_x509_crt_parse(&cacert, (const unsigned char *) additional_ca_pem, additional_ca_pem_len); + if (res < 0) { + PrintAndLog("ERROR: CA parse certificate returned -0x%x - %s", -res, ecdsa_get_error(res)); + } + if (verbose) + PrintAndLog("CA load OK. %d skipped", res); + + // load DER certificate from authenticator's data + mbedtls_x509_crt cert; + mbedtls_x509_crt_init(&cert); + res = mbedtls_x509_crt_parse_der(&cert, der, derLen); + if (res) { + PrintAndLog("ERROR: DER parse returned 0x%x - %s", (res<0)?-res:res, ecdsa_get_error(res)); + } + + // get certificate info + char linfo[300] = {0}; + if (verbose) { + mbedtls_x509_crt_info(linfo, sizeof(linfo), " ", &cert); + PrintAndLog("DER certificate info:\n%s", linfo); + } + + // verify certificate + uint32_t verifyflags = 0; + res = mbedtls_x509_crt_verify(&cert, &cacert, NULL, NULL, &verifyflags, NULL, NULL); + if (res) { + PrintAndLog("ERROR: DER verify returned 0x%x - %s", (res<0)?-res:res, ecdsa_get_error(res)); + } else { + PrintAndLog("Certificate OK."); + } + + if (verbose) { + memset(linfo, 0x00, sizeof(linfo)); + mbedtls_x509_crt_verify_info(linfo, sizeof(linfo), " ", verifyflags); + PrintAndLog("Verification info:\n%s", linfo); + } + + // get public key + res = ecdsa_public_key_from_pk(&cert.pk, publicKey, publicKeyMaxLen); + if (res) { + PrintAndLog("ERROR: getting public key from certificate 0x%x - %s", (res<0)?-res:res, ecdsa_get_error(res)); + } else { + if (verbose) + PrintAndLog("Got a public key from certificate:\n%s", sprint_hex_inrow(publicKey, 65)); + } + + if (verbose) + PrintAndLog("------------------DER-------------------"); + + mbedtls_x509_crt_free(&cert); + mbedtls_x509_crt_free(&cacert); + + return 0; +} + +#define fido_check_if(r) if ((r) != CborNoError) {return r;} else +#define fido_check(r) if ((r) != CborNoError) return r; + +int FIDO2CreateMakeCredentionalReq(json_t *root, uint8_t *data, size_t maxdatalen, size_t *datalen) { + if (datalen) + *datalen = 0; + if (!root || !data || !maxdatalen) + return 1; + + int res; + CborEncoder encoder; + CborEncoder map; + + cbor_encoder_init(&encoder, data, maxdatalen, 0); + + // create main map + res = cbor_encoder_create_map(&encoder, &map, 5); + fido_check_if(res) { + // clientDataHash + res = cbor_encode_uint(&map, 1); + fido_check_if(res) { + res = CBOREncodeClientDataHash(root, &map); + fido_check(res); + } + + // rp + res = cbor_encode_uint(&map, 2); + fido_check_if(res) { + res = CBOREncodeElm(root, "RelyingPartyEntity", &map); + fido_check(res); + } + + // user + res = cbor_encode_uint(&map, 3); + fido_check_if(res) { + res = CBOREncodeElm(root, "UserEntity", &map); + fido_check(res); + } + + // pubKeyCredParams + res = cbor_encode_uint(&map, 4); + fido_check_if(res) { + res = CBOREncodeElm(root, "pubKeyCredParams", &map); + fido_check(res); + } + + // options + res = cbor_encode_uint(&map, 7); + fido_check_if(res) { + res = CBOREncodeElm(root, "MakeCredentialOptions", &map); + fido_check(res); + } + } + res = cbor_encoder_close_container(&encoder, &map); + fido_check(res); + + size_t len = cbor_encoder_get_buffer_size(&encoder, data); + if (datalen) + *datalen = len; + + return 0; +} + +bool CheckrpIdHash(json_t *json, uint8_t *hash) { + char hashval[300] = {0}; + uint8_t hash2[32] = {0}; + + JsonLoadStr(json, "$.RelyingPartyEntity.id", hashval); + sha256hash((uint8_t *)hashval, strlen(hashval), hash2); + + return !memcmp(hash, hash2, 32); +} + +// check ANSI X9.62 format ECDSA signature (on P-256) +int FIDO2CheckSignature(json_t *root, uint8_t *publickey, uint8_t *sign, size_t signLen, uint8_t *authData, size_t authDataLen, bool verbose) { + int res; + uint8_t rval[300] = {0}; + uint8_t sval[300] = {0}; + res = ecdsa_asn1_get_signature(sign, signLen, rval, sval); + if (!res) { + if (verbose) { + PrintAndLog(" r: %s", sprint_hex(rval, 32)); + PrintAndLog(" s: %s", sprint_hex(sval, 32)); + } + + uint8_t clientDataHash[32] = {0}; + size_t clientDataHashLen = 0; + res = JsonLoadBufAsHex(root, "$.ClientDataHash", clientDataHash, sizeof(clientDataHash), &clientDataHashLen); + if (res || clientDataHashLen != 32) { + PrintAndLog("ERROR: Can't get clientDataHash from json!"); + return 2; + } + + uint8_t xbuf[4096] = {0}; + size_t xbuflen = 0; + res = FillBuffer(xbuf, sizeof(xbuf), &xbuflen, + authData, authDataLen, // rpIdHash[32] + flags[1] + signCount[4] + clientDataHash, 32, // Hash of the serialized client data. "$.ClientDataHash" from json + NULL, 0); + //PrintAndLog("--xbuf(%d)[%d]: %s", res, xbuflen, sprint_hex(xbuf, xbuflen)); + res = ecdsa_signature_verify(publickey, xbuf, xbuflen, sign, signLen); + if (res) { + if (res == -0x4e00) { + PrintAndLog("Signature is NOT VALID."); + } else { + PrintAndLog("Other signature check error: %x %s", (res<0)?-res:res, ecdsa_get_error(res)); + } + return res; + } else { + PrintAndLog("Signature is OK."); + } + } else { + PrintAndLog("Invalid signature. res=%d.", res); + return res; + } + + return 0; +} + +int FIDO2MakeCredentionalParseRes(json_t *root, uint8_t *data, size_t dataLen, bool verbose, bool verbose2, bool showCBOR, bool showDERTLV) { + CborParser parser; + CborValue map, mapsmt; + int res; + char *buf; + uint8_t *ubuf; + size_t n; + + // fmt + res = CborMapGetKeyById(&parser, &map, data, dataLen, 1); + if (res) + return res; + + res = cbor_value_dup_text_string(&map, &buf, &n, &map); + cbor_check(res); + PrintAndLog("format: %s", buf); + free(buf); + + // authData + uint8_t authData[400] = {0}; + size_t authDataLen = 0; + res = CborMapGetKeyById(&parser, &map, data, dataLen, 2); + if (res) + return res; + res = cbor_value_dup_byte_string(&map, &ubuf, &n, &map); + cbor_check(res); + + authDataLen = n; + memcpy(authData, ubuf, authDataLen); + + if (verbose2) { + PrintAndLog("authData[%d]: %s", n, sprint_hex_inrow(authData, authDataLen)); + } else { + PrintAndLog("authData[%d]: %s...", n, sprint_hex(authData, MIN(authDataLen, 16))); + } + + PrintAndLog("RP ID Hash: %s", sprint_hex(ubuf, 32)); + + // check RP ID Hash + if (CheckrpIdHash(root, ubuf)) { + PrintAndLog("rpIdHash OK."); + } else { + PrintAndLog("rpIdHash ERROR!"); + } + + PrintAndLog("Flags 0x%02x:", ubuf[32]); + if (!ubuf[32]) + PrintAndLog("none"); + if (ubuf[32] & 0x01) + PrintAndLog("up - user presence result"); + if (ubuf[32] & 0x04) + PrintAndLog("uv - user verification (fingerprint scan or a PIN or ...) result"); + if (ubuf[32] & 0x40) + PrintAndLog("at - attested credential data included"); + if (ubuf[32] & 0x80) + PrintAndLog("ed - extension data included"); + + uint32_t cntr = (uint32_t)bytes_to_num(&ubuf[33], 4); + PrintAndLog("Counter: %d", cntr); + JsonSaveInt(root, "$.AppData.Counter", cntr); + + // attestation data + PrintAndLog("AAGUID: %s", sprint_hex(&ubuf[37], 16)); + JsonSaveBufAsHexCompact(root, "$.AppData.AAGUID", &ubuf[37], 16); + + // Credential ID + uint8_t cridlen = (uint16_t)bytes_to_num(&ubuf[53], 2); + PrintAndLog("Credential id[%d]: %s", cridlen, sprint_hex_inrow(&ubuf[55], cridlen)); + JsonSaveInt(root, "$.AppData.CredentialIdLen", cridlen); + JsonSaveBufAsHexCompact(root, "$.AppData.CredentialId", &ubuf[55], cridlen); + + //Credentional public key (COSE_KEY) + uint8_t coseKey[65] = {0}; + uint16_t cplen = n - 55 - cridlen; + if (verbose2) { + PrintAndLog("Credentional public key (COSE_KEY)[%d]: %s", cplen, sprint_hex_inrow(&ubuf[55 + cridlen], cplen)); + } else { + PrintAndLog("Credentional public key (COSE_KEY)[%d]: %s...", cplen, sprint_hex(&ubuf[55 + cridlen], MIN(cplen, 16))); + } + JsonSaveBufAsHexCompact(root, "$.AppData.COSE_KEY", &ubuf[55 + cridlen], cplen); + + if (showCBOR) { + PrintAndLog("COSE structure:"); + PrintAndLog("---------------- CBOR ------------------"); + TinyCborPrintFIDOPackage(fido2COSEKey, true, &ubuf[55 + cridlen], cplen); + PrintAndLog("---------------- CBOR ------------------"); + } + + res = COSEGetECDSAKey(&ubuf[55 + cridlen], cplen, verbose, coseKey); + if (res) { + PrintAndLog("ERROR: Can't get COSE_KEY."); + } else { + PrintAndLog("COSE public key: %s", sprint_hex_inrow(coseKey, sizeof(coseKey))); + JsonSaveBufAsHexCompact(root, "$.AppData.COSEPublicKey", coseKey, sizeof(coseKey)); + } + + free(ubuf); + + // attStmt - we are check only as DER certificate + int64_t alg = 0; + uint8_t sign[128] = {0}; + size_t signLen = 0; + uint8_t der[4097] = {0}; + size_t derLen = 0; + + res = CborMapGetKeyById(&parser, &map, data, dataLen, 3); + if (res) + return res; + + res = cbor_value_enter_container(&map, &mapsmt); + cbor_check(res); + + while (!cbor_value_at_end(&mapsmt)) { + char key[100] = {0}; + res = CborGetStringValue(&mapsmt, key, sizeof(key), &n); + cbor_check(res); + if (!strcmp(key, "alg")) { + cbor_value_get_int64(&mapsmt, &alg); + PrintAndLog("Alg [%lld] %s", (long long)alg, GetCOSEAlgDescription(alg)); + res = cbor_value_advance_fixed(&mapsmt); + cbor_check(res); + } + + if (!strcmp(key, "sig")) { + res = CborGetBinStringValue(&mapsmt, sign, sizeof(sign), &signLen); + cbor_check(res); + if (verbose2) { + PrintAndLog("signature [%d]: %s", signLen, sprint_hex_inrow(sign, signLen)); + } else { + PrintAndLog("signature [%d]: %s...", signLen, sprint_hex(sign, MIN(signLen, 16))); + } + } + + if (!strcmp(key, "x5c")) { + res = CborGetArrayBinStringValue(&mapsmt, der, sizeof(der), &derLen); + cbor_check(res); + if (verbose2) { + PrintAndLog("DER certificate[%d]:\n------------------DER-------------------", derLen); + dump_buffer_simple((const unsigned char *)der, derLen, NULL); + PrintAndLog("\n----------------DER---------------------"); + } else { + PrintAndLog("DER [%d]: %s...", derLen, sprint_hex(der, MIN(derLen, 16))); + } + JsonSaveBufAsHexCompact(root, "$.AppData.DER", der, derLen); + } + } + res = cbor_value_leave_container(&map, &mapsmt); + cbor_check(res); + + uint8_t public_key[65] = {0}; + + // print DER certificate in TLV view + if (showDERTLV) { + PrintAndLog("----------------DER TLV-----------------"); + asn1_print(der, derLen, " "); + PrintAndLog("----------------DER TLV-----------------"); + } + FIDOCheckDERAndGetKey(der, derLen, verbose, public_key, sizeof(public_key)); + JsonSaveBufAsHexCompact(root, "$.AppData.DERPublicKey", public_key, sizeof(public_key)); + + // check ANSI X9.62 format ECDSA signature (on P-256) + FIDO2CheckSignature(root, public_key, sign, signLen, authData, authDataLen, verbose); + + return 0; +} + +int FIDO2CreateGetAssertionReq(json_t *root, uint8_t *data, size_t maxdatalen, size_t *datalen, bool createAllowList) { + if (datalen) + *datalen = 0; + if (!root || !data || !maxdatalen) + return 1; + + int res; + CborEncoder encoder; + CborEncoder map, array, mapint; + + cbor_encoder_init(&encoder, data, maxdatalen, 0); + + // create main map + res = cbor_encoder_create_map(&encoder, &map, createAllowList ? 4 : 3); + fido_check_if(res) { + // rpId + res = cbor_encode_uint(&map, 1); + fido_check_if(res) { + res = CBOREncodeElm(root, "$.RelyingPartyEntity.id", &map); + fido_check(res); + } + + // clientDataHash + res = cbor_encode_uint(&map, 2); + fido_check_if(res) { + res = CBOREncodeClientDataHash(root, &map); + fido_check(res); + } + + // allowList + if (createAllowList) { + res = cbor_encode_uint(&map, 3); + fido_check_if(res) { + res = cbor_encoder_create_array(&map, &array, 1); + fido_check_if(res) { + res = cbor_encoder_create_map(&array, &mapint, 2); + fido_check_if(res) { + res = cbor_encode_text_stringz(&mapint, "type"); + fido_check(res); + + res = cbor_encode_text_stringz(&mapint, "public-key"); + fido_check(res); + + res = cbor_encode_text_stringz(&mapint, "id"); + fido_check(res); + + res = CBOREncodeElm(root, "$.AppData.CredentialId", &mapint); + fido_check(res); + } + res = cbor_encoder_close_container(&array, &mapint); + fido_check(res); + } + res = cbor_encoder_close_container(&map, &array); + fido_check(res); + } + } + + // options + res = cbor_encode_uint(&map, 5); + fido_check_if(res) { + res = CBOREncodeElm(root, "GetAssertionOptions", &map); + fido_check(res); + } + } + res = cbor_encoder_close_container(&encoder, &map); + fido_check(res); + + size_t len = cbor_encoder_get_buffer_size(&encoder, data); + if (datalen) + *datalen = len; + + return 0; +} + +int FIDO2GetAssertionParseRes(json_t *root, uint8_t *data, size_t dataLen, bool verbose, bool verbose2, bool showCBOR) { + CborParser parser; + CborValue map, mapint; + int res; + uint8_t *ubuf; + size_t n; + + // credential + res = CborMapGetKeyById(&parser, &map, data, dataLen, 1); + if (res) + return res; + + res = cbor_value_enter_container(&map, &mapint); + cbor_check(res); + + while (!cbor_value_at_end(&mapint)) { + char key[100] = {0}; + res = CborGetStringValue(&mapint, key, sizeof(key), &n); + cbor_check(res); + + if (!strcmp(key, "type")) { + char ctype[200] = {0}; + res = CborGetStringValue(&mapint, ctype, sizeof(ctype), &n); + cbor_check(res); + PrintAndLog("credential type: %s", ctype); + } + + if (!strcmp(key, "id")) { + uint8_t cid[200] = {0}; + res = CborGetBinStringValue(&mapint, cid, sizeof(cid), &n); + cbor_check(res); + PrintAndLog("credential id [%d]: %s", n, sprint_hex(cid, n)); + } + } + res = cbor_value_leave_container(&map, &mapint); + cbor_check(res); + + // authData + uint8_t authData[400] = {0}; + size_t authDataLen = 0; + res = CborMapGetKeyById(&parser, &map, data, dataLen, 2); + if (res) + return res; + res = cbor_value_dup_byte_string(&map, &ubuf, &n, &map); + cbor_check(res); + + authDataLen = n; + memcpy(authData, ubuf, authDataLen); + + if (verbose2) { + PrintAndLog("authData[%d]: %s", n, sprint_hex_inrow(authData, authDataLen)); + } else { + PrintAndLog("authData[%d]: %s...", n, sprint_hex(authData, MIN(authDataLen, 16))); + } + + PrintAndLog("RP ID Hash: %s", sprint_hex(ubuf, 32)); + + // check RP ID Hash + if (CheckrpIdHash(root, ubuf)) { + PrintAndLog("rpIdHash OK."); + } else { + PrintAndLog("rpIdHash ERROR!"); + } + + PrintAndLog("Flags 0x%02x:", ubuf[32]); + if (!ubuf[32]) + PrintAndLog("none"); + if (ubuf[32] & 0x01) + PrintAndLog("up - user presence result"); + if (ubuf[32] & 0x04) + PrintAndLog("uv - user verification (fingerprint scan or a PIN or ...) result"); + if (ubuf[32] & 0x40) + PrintAndLog("at - attested credential data included"); + if (ubuf[32] & 0x80) + PrintAndLog("ed - extension data included"); + + uint32_t cntr = (uint32_t)bytes_to_num(&ubuf[33], 4); + PrintAndLog("Counter: %d", cntr); + JsonSaveInt(root, "$.AppData.Counter", cntr); + + free(ubuf); + + // publicKeyCredentialUserEntity + res = CborMapGetKeyById(&parser, &map, data, dataLen, 4); + if (res) { + PrintAndLog("UserEntity n/a"); + } else { + res = cbor_value_enter_container(&map, &mapint); + cbor_check(res); + + while (!cbor_value_at_end(&mapint)) { + char key[100] = {0}; + res = CborGetStringValue(&mapint, key, sizeof(key), &n); + cbor_check(res); + + if (!strcmp(key, "name") || !strcmp(key, "displayName")) { + char cname[200] = {0}; + res = CborGetStringValue(&mapint, cname, sizeof(cname), &n); + cbor_check(res); + PrintAndLog("UserEntity %s: %s", key, cname); + } + + if (!strcmp(key, "id")) { + uint8_t cid[200] = {0}; + res = CborGetBinStringValue(&mapint, cid, sizeof(cid), &n); + cbor_check(res); + PrintAndLog("UserEntity id [%d]: %s", n, sprint_hex(cid, n)); + + // check + uint8_t idbuf[100] = {0}; + size_t idbuflen; + + JsonLoadBufAsHex(root, "$.UserEntity.id", idbuf, sizeof(idbuf), &idbuflen); + + if (idbuflen == n && !memcmp(idbuf, cid, idbuflen)) { + PrintAndLog("UserEntity id OK."); + } else { + PrintAndLog("ERROR: Wrong UserEntity id (from json: %s)", sprint_hex(idbuf, idbuflen)); + } + } + } + res = cbor_value_leave_container(&map, &mapint); + cbor_check(res); + } + + + // signature + res = CborMapGetKeyById(&parser, &map, data, dataLen, 3); + if (res) + return res; + res = cbor_value_dup_byte_string(&map, &ubuf, &n, &map); + cbor_check(res); + + uint8_t *sign = ubuf; + size_t signLen = n; + + cbor_check(res); + if (verbose2) { + PrintAndLog("signature [%d]: %s", signLen, sprint_hex_inrow(sign, signLen)); + } else { + PrintAndLog("signature [%d]: %s...", signLen, sprint_hex(sign, MIN(signLen, 16))); + } + + // get public key from json + uint8_t PublicKey[65] = {0}; + size_t PublicKeyLen = 0; + JsonLoadBufAsHex(root, "$.AppData.COSEPublicKey", PublicKey, 65, &PublicKeyLen); + + // check ANSI X9.62 format ECDSA signature (on P-256) + FIDO2CheckSignature(root, PublicKey, sign, signLen, authData, authDataLen, verbose); + + free(ubuf); + + // numberOfCredentials + res = CborMapGetKeyById(&parser, &map, data, dataLen, 5); + if (res) { + PrintAndLog("numberOfCredentials: 1 by default"); + } else { + int64_t numberOfCredentials = 0; + cbor_value_get_int64(&map, &numberOfCredentials); + PrintAndLog("numberOfCredentials: %lld", (long long)numberOfCredentials); + } + + return 0; +} diff --git a/client/fido/fidocore.h b/client/fido/fidocore.h new file mode 100644 index 00000000..a1bcf876 --- /dev/null +++ b/client/fido/fidocore.h @@ -0,0 +1,58 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2018 Merlok +// +// 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. +//----------------------------------------------------------------------------- +// FIDO2 authenticators core data and commands +// https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html +//----------------------------------------------------------------------------- +// +#ifndef __FIDOCORE_H__ +#define __FIDOCORE_H__ + +#include +#include +#include +#include "cmdhf14a.h" +#include "emv/emvcore.h" + +typedef enum { + fido2CmdMakeCredential = 0x01, + fido2CmdGetAssertion = 0x02, + fido2CmdCancel = 0x03, + fido2CmdGetInfo = 0x04, + fido2CmdClientPIN = 0x06, + fido2CmdReset = 0x07, + fido2CmdGetNextAssertion = 0x08, + + // another data + fido2COSEKey = 0xF0 +} fido2Commands; + +typedef enum { + ptQuery, + ptResponse, +} fido2PacketType; + +extern int FIDOSelect(bool ActivateField, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); +extern int FIDOExchange(sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); +extern int FIDORegister(uint8_t *params, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); +extern int FIDOAuthentication(uint8_t *params, uint8_t paramslen, uint8_t controlb, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); +extern int FIDO2GetInfo(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); +extern int FIDO2MakeCredential(uint8_t *params, uint8_t paramslen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); +extern int FIDO2GetAssertion(uint8_t *params, uint8_t paramslen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); + +extern int FIDOCheckDERAndGetKey(uint8_t *der, size_t derLen, bool verbose, uint8_t *publicKey, size_t publicKeyMaxLen); + +extern char *fido2GetCmdMemberDescription(uint8_t cmdCode, bool isResponse, int memberNum); +extern char *fido2GetCmdErrorDescription(uint8_t errorCode); + +extern bool CheckrpIdHash(json_t *json, uint8_t *hash); +extern int FIDO2CreateMakeCredentionalReq(json_t *root, uint8_t *data, size_t maxdatalen, size_t *datalen); +extern int FIDO2MakeCredentionalParseRes(json_t *root, uint8_t *data, size_t dataLen, bool verbose, bool verbose2, bool showCBOR, bool showDERTLV); +extern int FIDO2CreateGetAssertionReq(json_t *root, uint8_t *data, size_t maxdatalen, size_t *datalen, bool createAllowList); +extern int FIDO2GetAssertionParseRes(json_t *root, uint8_t *data, size_t dataLen, bool verbose, bool verbose2, bool showCBOR); + +#endif /* __FIDOCORE_H__ */ diff --git a/client/tinycbor/Makefile b/client/tinycbor/Makefile new file mode 100644 index 00000000..78ef64dc --- /dev/null +++ b/client/tinycbor/Makefile @@ -0,0 +1,46 @@ + +LIB_A = tinycbor.a +tinycbor_SOURCES = \ + cborencoder.c \ + cborencoder_close_container_checked.c \ + cborerrorstrings.c \ + cborparser.c \ + cborparser_dup_string.c \ + cborpretty.c \ + cbortojson.c \ + cborvalidation.c \ + +CFILES = $(filter %.c, $(tinycbor_SOURCES)) +CMDOBJS = $(CFILES:%.c=%.o) +CLEAN = $(CMDOBJS) + +CC= gcc +CFLAGS= -O2 -Wall -Wno-unused-variable -Wno-unused-function +LIBS= $(SYSLIBS) $(MYLIBS) +DEFAULT_INCLUDES = -I. -I.. +DEFS = -DHAVE_STDINT_H + +AR= ar rcs +RANLIB= ranlib +RM= rm -f +TST= echo + +SYSLDFLAGS= +SYSLIBS= + +MYLIBS= +MYOBJS= + +all: $(CMDOBJS) + $(AR) $(LIB_A) $(CMDOBJS) + $(RANLIB) $(LIB_A) + +clean: + $(RM) $(CLEAN) + $(RM) $(LIB_A) + +%.o: %.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(CFLAGS) -c -o $@ $< $(LIBS) + +.PHONY: all clean + diff --git a/client/tinycbor/cbor.h b/client/tinycbor/cbor.h new file mode 100644 index 00000000..fd145be2 --- /dev/null +++ b/client/tinycbor/cbor.h @@ -0,0 +1,606 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Intel Corporation +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +** copies of the Software, and to permit persons to whom the Software is +** furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +** THE SOFTWARE. +** +****************************************************************************/ + +#ifndef CBOR_H +#define CBOR_H + +#ifndef assert +#include +#endif +#include +#include +#include +#include +#include + +#include "tinycbor-version.h" + +#define TINYCBOR_VERSION ((TINYCBOR_VERSION_MAJOR << 16) | (TINYCBOR_VERSION_MINOR << 8) | TINYCBOR_VERSION_PATCH) + +#ifdef __cplusplus +extern "C" { +#else +#include +#endif + +#ifndef SIZE_MAX +/* Some systems fail to define SIZE_MAX in , even though C99 requires it... + * Conversion from signed to unsigned is defined in 6.3.1.3 (Signed and unsigned integers) p2, + * which says: "the value is converted by repeatedly adding or subtracting one more than the + * maximum value that can be represented in the new type until the value is in the range of the + * new type." + * So -1 gets converted to size_t by adding SIZE_MAX + 1, which results in SIZE_MAX. + */ +# define SIZE_MAX ((size_t)-1) +#endif + +#ifndef CBOR_API +# define CBOR_API +#endif +#ifndef CBOR_PRIVATE_API +# define CBOR_PRIVATE_API +#endif +#ifndef CBOR_INLINE_API +# if defined(__cplusplus) +# define CBOR_INLINE inline +# define CBOR_INLINE_API inline +# else +# define CBOR_INLINE_API static CBOR_INLINE +# if defined(_MSC_VER) +# define CBOR_INLINE __inline +# elif defined(__GNUC__) +# define CBOR_INLINE __inline__ +# elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +# define CBOR_INLINE inline +# else +# define CBOR_INLINE +# endif +# endif +#endif + +typedef enum CborType { + CborIntegerType = 0x00, + CborByteStringType = 0x40, + CborTextStringType = 0x60, + CborArrayType = 0x80, + CborMapType = 0xa0, + CborTagType = 0xc0, + CborSimpleType = 0xe0, + CborBooleanType = 0xf5, + CborNullType = 0xf6, + CborUndefinedType = 0xf7, + CborHalfFloatType = 0xf9, + CborFloatType = 0xfa, + CborDoubleType = 0xfb, + + CborInvalidType = 0xff /* equivalent to the break byte, so it will never be used */ +} CborType; + +typedef uint64_t CborTag; +typedef enum CborKnownTags { + CborDateTimeStringTag = 0, + CborUnixTime_tTag = 1, + CborPositiveBignumTag = 2, + CborNegativeBignumTag = 3, + CborDecimalTag = 4, + CborBigfloatTag = 5, + CborCOSE_Encrypt0Tag = 16, + CborCOSE_Mac0Tag = 17, + CborCOSE_Sign1Tag = 18, + CborExpectedBase64urlTag = 21, + CborExpectedBase64Tag = 22, + CborExpectedBase16Tag = 23, + CborEncodedCborTag = 24, + CborUrlTag = 32, + CborBase64urlTag = 33, + CborBase64Tag = 34, + CborRegularExpressionTag = 35, + CborMimeMessageTag = 36, + CborCOSE_EncryptTag = 96, + CborCOSE_MacTag = 97, + CborCOSE_SignTag = 98, + CborSignatureTag = 55799 +} CborKnownTags; + +/* #define the constants so we can check with #ifdef */ +#define CborDateTimeStringTag CborDateTimeStringTag +#define CborUnixTime_tTag CborUnixTime_tTag +#define CborPositiveBignumTag CborPositiveBignumTag +#define CborNegativeBignumTag CborNegativeBignumTag +#define CborDecimalTag CborDecimalTag +#define CborBigfloatTag CborBigfloatTag +#define CborCOSE_Encrypt0Tag CborCOSE_Encrypt0Tag +#define CborCOSE_Mac0Tag CborCOSE_Mac0Tag +#define CborCOSE_Sign1Tag CborCOSE_Sign1Tag +#define CborExpectedBase64urlTag CborExpectedBase64urlTag +#define CborExpectedBase64Tag CborExpectedBase64Tag +#define CborExpectedBase16Tag CborExpectedBase16Tag +#define CborEncodedCborTag CborEncodedCborTag +#define CborUrlTag CborUrlTag +#define CborBase64urlTag CborBase64urlTag +#define CborBase64Tag CborBase64Tag +#define CborRegularExpressionTag CborRegularExpressionTag +#define CborMimeMessageTag CborMimeMessageTag +#define CborCOSE_EncryptTag CborCOSE_EncryptTag +#define CborCOSE_MacTag CborCOSE_MacTag +#define CborCOSE_SignTag CborCOSE_SignTag +#define CborSignatureTag CborSignatureTag + +/* Error API */ + +typedef enum CborError { + CborNoError = 0, + + /* errors in all modes */ + CborUnknownError, + CborErrorUnknownLength, /* request for length in array, map, or string with indeterminate length */ + CborErrorAdvancePastEOF, + CborErrorIO, + + /* parser errors streaming errors */ + CborErrorGarbageAtEnd = 256, + CborErrorUnexpectedEOF, + CborErrorUnexpectedBreak, + CborErrorUnknownType, /* can only happen in major type 7 */ + CborErrorIllegalType, /* type not allowed here */ + CborErrorIllegalNumber, + CborErrorIllegalSimpleType, /* types of value less than 32 encoded in two bytes */ + + /* parser errors in strict mode parsing only */ + CborErrorUnknownSimpleType = 512, + CborErrorUnknownTag, + CborErrorInappropriateTagForType, + CborErrorDuplicateObjectKeys, + CborErrorInvalidUtf8TextString, + CborErrorExcludedType, + CborErrorExcludedValue, + CborErrorImproperValue, + CborErrorOverlongEncoding, + CborErrorMapKeyNotString, + CborErrorMapNotSorted, + CborErrorMapKeysNotUnique, + + /* encoder errors */ + CborErrorTooManyItems = 768, + CborErrorTooFewItems, + + /* internal implementation errors */ + CborErrorDataTooLarge = 1024, + CborErrorNestingTooDeep, + CborErrorUnsupportedType, + + /* errors in converting to JSON */ + CborErrorJsonObjectKeyIsAggregate = 1280, + CborErrorJsonObjectKeyNotString, + CborErrorJsonNotImplemented, + + CborErrorOutOfMemory = (int) (~0U / 2 + 1), + CborErrorInternalError = (int) (~0U / 2) /* INT_MAX on two's complement machines */ +} CborError; + +CBOR_API const char *cbor_error_string(CborError error); + +/* Encoder API */ +struct CborEncoder +{ + union { + uint8_t *ptr; + ptrdiff_t bytes_needed; + } data; + const uint8_t *end; + size_t remaining; + int flags; +}; +typedef struct CborEncoder CborEncoder; + +static const size_t CborIndefiniteLength = SIZE_MAX; + +CBOR_API void cbor_encoder_init(CborEncoder *encoder, uint8_t *buffer, size_t size, int flags); +CBOR_API CborError cbor_encode_uint(CborEncoder *encoder, uint64_t value); +CBOR_API CborError cbor_encode_int(CborEncoder *encoder, int64_t value); +CBOR_API CborError cbor_encode_negative_int(CborEncoder *encoder, uint64_t absolute_value); +CBOR_API CborError cbor_encode_simple_value(CborEncoder *encoder, uint8_t value); +CBOR_API CborError cbor_encode_tag(CborEncoder *encoder, CborTag tag); +CBOR_API CborError cbor_encode_text_string(CborEncoder *encoder, const char *string, size_t length); +CBOR_INLINE_API CborError cbor_encode_text_stringz(CborEncoder *encoder, const char *string) +{ return cbor_encode_text_string(encoder, string, strlen(string)); } +CBOR_API CborError cbor_encode_byte_string(CborEncoder *encoder, const uint8_t *string, size_t length); +CBOR_API CborError cbor_encode_floating_point(CborEncoder *encoder, CborType fpType, const void *value); + +CBOR_INLINE_API CborError cbor_encode_boolean(CborEncoder *encoder, bool value) +{ return cbor_encode_simple_value(encoder, (int)value - 1 + (CborBooleanType & 0x1f)); } +CBOR_INLINE_API CborError cbor_encode_null(CborEncoder *encoder) +{ return cbor_encode_simple_value(encoder, CborNullType & 0x1f); } +CBOR_INLINE_API CborError cbor_encode_undefined(CborEncoder *encoder) +{ return cbor_encode_simple_value(encoder, CborUndefinedType & 0x1f); } + +CBOR_INLINE_API CborError cbor_encode_half_float(CborEncoder *encoder, const void *value) +{ return cbor_encode_floating_point(encoder, CborHalfFloatType, value); } +CBOR_INLINE_API CborError cbor_encode_float(CborEncoder *encoder, float value) +{ return cbor_encode_floating_point(encoder, CborFloatType, &value); } +CBOR_INLINE_API CborError cbor_encode_double(CborEncoder *encoder, double value) +{ return cbor_encode_floating_point(encoder, CborDoubleType, &value); } + +CBOR_API CborError cbor_encoder_create_array(CborEncoder *encoder, CborEncoder *arrayEncoder, size_t length); +CBOR_API CborError cbor_encoder_create_map(CborEncoder *encoder, CborEncoder *mapEncoder, size_t length); +CBOR_API CborError cbor_encoder_close_container(CborEncoder *encoder, const CborEncoder *containerEncoder); +CBOR_API CborError cbor_encoder_close_container_checked(CborEncoder *encoder, const CborEncoder *containerEncoder); + +CBOR_INLINE_API uint8_t *_cbor_encoder_get_buffer_pointer(const CborEncoder *encoder) +{ + return encoder->data.ptr; +} + +CBOR_INLINE_API size_t cbor_encoder_get_buffer_size(const CborEncoder *encoder, const uint8_t *buffer) +{ + return (size_t)(encoder->data.ptr - buffer); +} + +CBOR_INLINE_API size_t cbor_encoder_get_extra_bytes_needed(const CborEncoder *encoder) +{ + return encoder->end ? 0 : (size_t)encoder->data.bytes_needed; +} + +/* Parser API */ + +enum CborParserIteratorFlags +{ + CborIteratorFlag_IntegerValueTooLarge = 0x01, + CborIteratorFlag_NegativeInteger = 0x02, + CborIteratorFlag_IteratingStringChunks = 0x02, + CborIteratorFlag_UnknownLength = 0x04, + CborIteratorFlag_ContainerIsMap = 0x20 +}; + +struct CborParser +{ + const uint8_t *end; + uint32_t flags; +}; +typedef struct CborParser CborParser; + +struct CborValue +{ + const CborParser *parser; + const uint8_t *ptr; + uint32_t remaining; + uint16_t extra; + uint8_t type; + uint8_t flags; +}; +typedef struct CborValue CborValue; + +CBOR_API CborError cbor_parser_init(const uint8_t *buffer, size_t size, uint32_t flags, CborParser *parser, CborValue *it); + +CBOR_API CborError cbor_value_validate_basic(const CborValue *it); + +CBOR_INLINE_API bool cbor_value_at_end(const CborValue *it) +{ return it->remaining == 0; } +CBOR_INLINE_API const uint8_t *cbor_value_get_next_byte(const CborValue *it) +{ return it->ptr; } +CBOR_API CborError cbor_value_advance_fixed(CborValue *it); +CBOR_API CborError cbor_value_advance(CborValue *it); +CBOR_INLINE_API bool cbor_value_is_container(const CborValue *it) +{ return it->type == CborArrayType || it->type == CborMapType; } +CBOR_API CborError cbor_value_enter_container(const CborValue *it, CborValue *recursed); +CBOR_API CborError cbor_value_leave_container(CborValue *it, const CborValue *recursed); + +CBOR_PRIVATE_API uint64_t _cbor_value_decode_int64_internal(const CborValue *value); +CBOR_INLINE_API uint64_t _cbor_value_extract_int64_helper(const CborValue *value) +{ + return value->flags & CborIteratorFlag_IntegerValueTooLarge ? + _cbor_value_decode_int64_internal(value) : value->extra; +} + +CBOR_INLINE_API bool cbor_value_is_valid(const CborValue *value) +{ return value && value->type != CborInvalidType; } +CBOR_INLINE_API CborType cbor_value_get_type(const CborValue *value) +{ return (CborType)value->type; } + +/* Null & undefined type */ +CBOR_INLINE_API bool cbor_value_is_null(const CborValue *value) +{ return value->type == CborNullType; } +CBOR_INLINE_API bool cbor_value_is_undefined(const CborValue *value) +{ return value->type == CborUndefinedType; } + +/* Booleans */ +CBOR_INLINE_API bool cbor_value_is_boolean(const CborValue *value) +{ return value->type == CborBooleanType; } +CBOR_INLINE_API CborError cbor_value_get_boolean(const CborValue *value, bool *result) +{ + assert(cbor_value_is_boolean(value)); + *result = !!value->extra; + return CborNoError; +} + +/* Simple types */ +CBOR_INLINE_API bool cbor_value_is_simple_type(const CborValue *value) +{ return value->type == CborSimpleType; } +CBOR_INLINE_API CborError cbor_value_get_simple_type(const CborValue *value, uint8_t *result) +{ + assert(cbor_value_is_simple_type(value)); + *result = (uint8_t)value->extra; + return CborNoError; +} + +/* Integers */ +CBOR_INLINE_API bool cbor_value_is_integer(const CborValue *value) +{ return value->type == CborIntegerType; } +CBOR_INLINE_API bool cbor_value_is_unsigned_integer(const CborValue *value) +{ return cbor_value_is_integer(value) && (value->flags & CborIteratorFlag_NegativeInteger) == 0; } +CBOR_INLINE_API bool cbor_value_is_negative_integer(const CborValue *value) +{ return cbor_value_is_integer(value) && (value->flags & CborIteratorFlag_NegativeInteger); } + +CBOR_INLINE_API CborError cbor_value_get_raw_integer(const CborValue *value, uint64_t *result) +{ + assert(cbor_value_is_integer(value)); + *result = _cbor_value_extract_int64_helper(value); + return CborNoError; +} + +CBOR_INLINE_API CborError cbor_value_get_uint64(const CborValue *value, uint64_t *result) +{ + assert(cbor_value_is_unsigned_integer(value)); + *result = _cbor_value_extract_int64_helper(value); + return CborNoError; +} + +CBOR_INLINE_API CborError cbor_value_get_int64(const CborValue *value, int64_t *result) +{ + assert(cbor_value_is_integer(value)); + *result = (int64_t) _cbor_value_extract_int64_helper(value); + if (value->flags & CborIteratorFlag_NegativeInteger) + *result = -*result - 1; + return CborNoError; +} + +CBOR_INLINE_API CborError cbor_value_get_int(const CborValue *value, int *result) +{ + assert(cbor_value_is_integer(value)); + *result = (int) _cbor_value_extract_int64_helper(value); + if (value->flags & CborIteratorFlag_NegativeInteger) + *result = -*result - 1; + return CborNoError; +} + +CBOR_API CborError cbor_value_get_int64_checked(const CborValue *value, int64_t *result); +CBOR_API CborError cbor_value_get_int_checked(const CborValue *value, int *result); + +CBOR_INLINE_API bool cbor_value_is_length_known(const CborValue *value) +{ return (value->flags & CborIteratorFlag_UnknownLength) == 0; } + +/* Tags */ +CBOR_INLINE_API bool cbor_value_is_tag(const CborValue *value) +{ return value->type == CborTagType; } +CBOR_INLINE_API CborError cbor_value_get_tag(const CborValue *value, CborTag *result) +{ + assert(cbor_value_is_tag(value)); + *result = _cbor_value_extract_int64_helper(value); + return CborNoError; +} +CBOR_API CborError cbor_value_skip_tag(CborValue *it); + +/* Strings */ +CBOR_INLINE_API bool cbor_value_is_byte_string(const CborValue *value) +{ return value->type == CborByteStringType; } +CBOR_INLINE_API bool cbor_value_is_text_string(const CborValue *value) +{ return value->type == CborTextStringType; } + +CBOR_INLINE_API CborError cbor_value_get_string_length(const CborValue *value, size_t *length) +{ + uint64_t v; + assert(cbor_value_is_byte_string(value) || cbor_value_is_text_string(value)); + if (!cbor_value_is_length_known(value)) + return CborErrorUnknownLength; + v = _cbor_value_extract_int64_helper(value); + *length = (size_t)v; + if (*length != v) + return CborErrorDataTooLarge; + return CborNoError; +} + +CBOR_PRIVATE_API CborError _cbor_value_copy_string(const CborValue *value, void *buffer, + size_t *buflen, CborValue *next); +CBOR_PRIVATE_API CborError _cbor_value_dup_string(const CborValue *value, void **buffer, + size_t *buflen, CborValue *next); + +CBOR_API CborError cbor_value_calculate_string_length(const CborValue *value, size_t *length); + +CBOR_INLINE_API CborError cbor_value_copy_text_string(const CborValue *value, char *buffer, + size_t *buflen, CborValue *next) +{ + assert(cbor_value_is_text_string(value)); + return _cbor_value_copy_string(value, buffer, buflen, next); +} +CBOR_INLINE_API CborError cbor_value_copy_byte_string(const CborValue *value, uint8_t *buffer, + size_t *buflen, CborValue *next) +{ + assert(cbor_value_is_byte_string(value)); + return _cbor_value_copy_string(value, buffer, buflen, next); +} + +CBOR_INLINE_API CborError cbor_value_dup_text_string(const CborValue *value, char **buffer, + size_t *buflen, CborValue *next) +{ + assert(cbor_value_is_text_string(value)); + return _cbor_value_dup_string(value, (void **)buffer, buflen, next); +} +CBOR_INLINE_API CborError cbor_value_dup_byte_string(const CborValue *value, uint8_t **buffer, + size_t *buflen, CborValue *next) +{ + assert(cbor_value_is_byte_string(value)); + return _cbor_value_dup_string(value, (void **)buffer, buflen, next); +} + +CBOR_API CborError cbor_value_text_string_equals(const CborValue *value, const char *string, bool *result); + +/* Maps and arrays */ +CBOR_INLINE_API bool cbor_value_is_array(const CborValue *value) +{ return value->type == CborArrayType; } +CBOR_INLINE_API bool cbor_value_is_map(const CborValue *value) +{ return value->type == CborMapType; } + +CBOR_INLINE_API CborError cbor_value_get_array_length(const CborValue *value, size_t *length) +{ + uint64_t v; + assert(cbor_value_is_array(value)); + if (!cbor_value_is_length_known(value)) + return CborErrorUnknownLength; + v = _cbor_value_extract_int64_helper(value); + *length = (size_t)v; + if (*length != v) + return CborErrorDataTooLarge; + return CborNoError; +} + +CBOR_INLINE_API CborError cbor_value_get_map_length(const CborValue *value, size_t *length) +{ + uint64_t v; + assert(cbor_value_is_map(value)); + if (!cbor_value_is_length_known(value)) + return CborErrorUnknownLength; + v = _cbor_value_extract_int64_helper(value); + *length = (size_t)v; + if (*length != v) + return CborErrorDataTooLarge; + return CborNoError; +} + +CBOR_API CborError cbor_value_map_find_value(const CborValue *map, const char *string, CborValue *element); + +/* Floating point */ +CBOR_INLINE_API bool cbor_value_is_half_float(const CborValue *value) +{ return value->type == CborHalfFloatType; } +CBOR_API CborError cbor_value_get_half_float(const CborValue *value, void *result); + +CBOR_INLINE_API bool cbor_value_is_float(const CborValue *value) +{ return value->type == CborFloatType; } +CBOR_INLINE_API CborError cbor_value_get_float(const CborValue *value, float *result) +{ + uint32_t data; + assert(cbor_value_is_float(value)); + assert(value->flags & CborIteratorFlag_IntegerValueTooLarge); + data = (uint32_t)_cbor_value_decode_int64_internal(value); + memcpy(result, &data, sizeof(*result)); + return CborNoError; +} + +CBOR_INLINE_API bool cbor_value_is_double(const CborValue *value) +{ return value->type == CborDoubleType; } +CBOR_INLINE_API CborError cbor_value_get_double(const CborValue *value, double *result) +{ + uint64_t data; + assert(cbor_value_is_double(value)); + assert(value->flags & CborIteratorFlag_IntegerValueTooLarge); + data = _cbor_value_decode_int64_internal(value); + memcpy(result, &data, sizeof(*result)); + return CborNoError; +} + +/* Validation API */ + +enum CborValidationFlags { + /* Bit mapping: + * bits 0-7 (8 bits): canonical format + * bits 8-11 (4 bits): canonical format & strict mode + * bits 12-20 (8 bits): strict mode + * bits 21-31 (10 bits): other + */ + + CborValidateShortestIntegrals = 0x0001, + CborValidateShortestFloatingPoint = 0x0002, + CborValidateShortestNumbers = CborValidateShortestIntegrals | CborValidateShortestFloatingPoint, + CborValidateNoIndeterminateLength = 0x0100, + CborValidateMapIsSorted = 0x0200 | CborValidateNoIndeterminateLength, + + CborValidateCanonicalFormat = 0x0fff, + + CborValidateMapKeysAreUnique = 0x1000 | CborValidateMapIsSorted, + CborValidateTagUse = 0x2000, + CborValidateUtf8 = 0x4000, + + CborValidateStrictMode = 0xfff00, + + CborValidateMapKeysAreString = 0x100000, + CborValidateNoUndefined = 0x200000, + CborValidateNoTags = 0x400000, + CborValidateFiniteFloatingPoint = 0x800000, + /* unused = 0x1000000, */ + /* unused = 0x2000000, */ + + CborValidateNoUnknownSimpleTypesSA = 0x4000000, + CborValidateNoUnknownSimpleTypes = 0x8000000 | CborValidateNoUnknownSimpleTypesSA, + CborValidateNoUnknownTagsSA = 0x10000000, + CborValidateNoUnknownTagsSR = 0x20000000 | CborValidateNoUnknownTagsSA, + CborValidateNoUnknownTags = 0x40000000 | CborValidateNoUnknownTagsSR, + + CborValidateCompleteData = (int)0x80000000, + + CborValidateStrictest = (int)~0U, + CborValidateBasic = 0 +}; + +CBOR_API CborError cbor_value_validate(const CborValue *it, uint32_t flags); + +/* Human-readable (dump) API */ + +enum CborPrettyFlags { + CborPrettyNumericEncodingIndicators = 0x01, + CborPrettyTextualEncodingIndicators = 0, + + CborPrettyIndicateIndeterminateLength = 0x02, + CborPrettyIndicateIndetermineLength = CborPrettyIndicateIndeterminateLength, /* deprecated */ + CborPrettyIndicateOverlongNumbers = 0x04, + + CborPrettyShowStringFragments = 0x100, + CborPrettyMergeStringFragments = 0, + + CborPrettyDefaultFlags = CborPrettyIndicateIndeterminateLength +}; + +typedef CborError (*CborStreamFunction)(void *token, const char *fmt, ...) +#ifdef __GNUC__ + __attribute__((__format__(printf, 2, 3))) +#endif +; + +CBOR_API CborError cbor_value_to_pretty_stream(CborStreamFunction streamFunction, void *token, CborValue *value, int flags); + +/* The following API requires a hosted C implementation (uses FILE*) */ +#if !defined(__STDC_HOSTED__) || __STDC_HOSTED__-0 == 1 +CBOR_API CborError cbor_value_to_pretty_advance_flags(FILE *out, CborValue *value, int flags); +CBOR_API CborError cbor_value_to_pretty_advance(FILE *out, CborValue *value); +CBOR_INLINE_API CborError cbor_value_to_pretty(FILE *out, const CborValue *value) +{ + CborValue copy = *value; + return cbor_value_to_pretty_advance_flags(out, ©, CborPrettyDefaultFlags); +} +#endif /* __STDC_HOSTED__ check */ + +#ifdef __cplusplus +} +#endif + +#endif /* CBOR_H */ + diff --git a/client/tinycbor/cborencoder.c b/client/tinycbor/cborencoder.c new file mode 100644 index 00000000..adb92fd8 --- /dev/null +++ b/client/tinycbor/cborencoder.c @@ -0,0 +1,645 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Intel Corporation +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +** copies of the Software, and to permit persons to whom the Software is +** furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +** THE SOFTWARE. +** +****************************************************************************/ + +#ifndef _BSD_SOURCE +#define _BSD_SOURCE 1 +#endif +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE 1 +#endif +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS 1 +#endif + +#include "cbor.h" +#include "cborinternal_p.h" +#include "compilersupport_p.h" + +#include +#include + +/** + * \defgroup CborEncoding Encoding to CBOR + * \brief Group of functions used to encode data to CBOR. + * + * CborEncoder is used to encode data into a CBOR stream. The outermost + * CborEncoder is initialized by calling cbor_encoder_init(), with the buffer + * where the CBOR stream will be stored. The outermost CborEncoder is usually + * used to encode exactly one item, most often an array or map. It is possible + * to encode more than one item, but care must then be taken on the decoder + * side to ensure the state is reset after each item was decoded. + * + * Nested CborEncoder objects are created using cbor_encoder_create_array() and + * cbor_encoder_create_map(), later closed with cbor_encoder_close_container() + * or cbor_encoder_close_container_checked(). The pairs of creation and closing + * must be exactly matched and their parameters are always the same. + * + * CborEncoder writes directly to the user-supplied buffer, without extra + * buffering. CborEncoder does not allocate memory and CborEncoder objects are + * usually created on the stack of the encoding functions. + * + * The example below initializes a CborEncoder object with a buffer and encodes + * a single integer. + * + * \code + * uint8_t buf[16]; + * CborEncoder encoder; + * cbor_encoder_init(&encoder, &buf, sizeof(buf), 0); + * cbor_encode_int(&encoder, some_value); + * \endcode + * + * As explained before, usually the outermost CborEncoder object is used to add + * one array or map, which in turn contains multiple elements. The example + * below creates a CBOR map with one element: a key "foo" and a boolean value. + * + * \code + * uint8_t buf[16]; + * CborEncoder encoder, mapEncoder; + * cbor_encoder_init(&encoder, &buf, sizeof(buf), 0); + * cbor_encoder_create_map(&encoder, &mapEncoder, 1); + * cbor_encode_text_stringz(&mapEncoder, "foo"); + * cbor_encode_boolean(&mapEncoder, some_value); + * cbor_encoder_close_container(&encoder, &mapEncoder); + * \endcode + * + *

Error checking and buffer size

+ * + * All functions operating on CborEncoder return a condition of type CborError. + * If the encoding was successful, they return CborNoError. Some functions do + * extra checking on the input provided and may return some other error + * conditions (for example, cbor_encode_simple_value() checks that the type is + * of the correct type). + * + * In addition, all functions check whether the buffer has enough bytes to + * encode the item being appended. If that is not possible, they return + * CborErrorOutOfMemory. + * + * It is possible to continue with the encoding of data past the first function + * that returns CborErrorOutOfMemory. CborEncoder functions will not overrun + * the buffer, but will instead count how many more bytes are needed to + * complete the encoding. At the end, you can obtain that count by calling + * cbor_encoder_get_extra_bytes_needed(). + * + * \section1 Finalizing the encoding + * + * Once all items have been appended and the containers have all been properly + * closed, the user-supplied buffer will contain the CBOR stream and may be + * immediately used. To obtain the size of the buffer, call + * cbor_encoder_get_buffer_size() with the original buffer pointer. + * + * The example below illustrates how one can encode an item with error checking + * and then pass on the buffer for network sending. + * + * \code + * uint8_t buf[16]; + * CborError err; + * CborEncoder encoder, mapEncoder; + * cbor_encoder_init(&encoder, &buf, sizeof(buf), 0); + * err = cbor_encoder_create_map(&encoder, &mapEncoder, 1); + * if (!err) + * return err; + * err = cbor_encode_text_stringz(&mapEncoder, "foo"); + * if (!err) + * return err; + * err = cbor_encode_boolean(&mapEncoder, some_value); + * if (!err) + * return err; + * err = cbor_encoder_close_container_checked(&encoder, &mapEncoder); + * if (!err) + * return err; + * + * size_t len = cbor_encoder_get_buffer_size(&encoder, buf); + * send_payload(buf, len); + * return CborNoError; + * \endcode + * + * Finally, the example below expands on the one above and also + * deals with dynamically growing the buffer if the initial allocation wasn't + * big enough. Note the two places where the error checking was replaced with + * an cbor_assertion, showing where the author assumes no error can occur. + * + * \code + * uint8_t *encode_string_array(const char **strings, int n, size_t *bufsize) + * { + * CborError err; + * CborEncoder encoder, arrayEncoder; + * size_t size = 256; + * uint8_t *buf = NULL; + * + * while (1) { + * int i; + * size_t more_bytes; + * uint8_t *nbuf = realloc(buf, size); + * if (nbuf == NULL) + * goto error; + * buf = nbuf; + * + * cbor_encoder_init(&encoder, &buf, size, 0); + * err = cbor_encoder_create_array(&encoder, &arrayEncoder, n); + * cbor_assert(err); // can't fail, the buffer is always big enough + * + * for (i = 0; i < n; ++i) { + * err = cbor_encode_text_stringz(&arrayEncoder, strings[i]); + * if (err && err != CborErrorOutOfMemory) + * goto error; + * } + * + * err = cbor_encoder_close_container_checked(&encoder, &arrayEncoder); + * cbor_assert(err); // shouldn't fail! + * + * more_bytes = cbor_encoder_get_extra_bytes_needed(encoder); + * if (more_size) { + * // buffer wasn't big enough, try again + * size += more_bytes; + * continue; + * } + * + * *bufsize = cbor_encoder_get_buffer_size(encoder, buf); + * return buf; + * } + * error: + * free(buf); + * return NULL; + * } + * \endcode + */ + +/** + * \addtogroup CborEncoding + * @{ + */ + +/** + * \struct CborEncoder + * Structure used to encode to CBOR. + */ + +/** + * Initializes a CborEncoder structure \a encoder by pointing it to buffer \a + * buffer of size \a size. The \a flags field is currently unused and must be + * zero. + */ +void cbor_encoder_init(CborEncoder *encoder, uint8_t *buffer, size_t size, int flags) +{ + encoder->data.ptr = buffer; + encoder->end = buffer + size; + encoder->remaining = 2; + encoder->flags = flags; +} + +static inline void put16(void *where, uint16_t v) +{ + v = cbor_htons(v); + memcpy(where, &v, sizeof(v)); +} + +/* Note: Since this is currently only used in situations where OOM is the only + * valid error, we KNOW this to be true. Thus, this function now returns just 'true', + * but if in the future, any function starts returning a non-OOM error, this will need + * to be changed to the test. At the moment, this is done to prevent more branches + * being created in the tinycbor output */ +static inline bool isOomError(CborError err) +{ + (void) err; + return true; +} + +static inline void put32(void *where, uint32_t v) +{ + v = cbor_htonl(v); + memcpy(where, &v, sizeof(v)); +} + +static inline void put64(void *where, uint64_t v) +{ + v = cbor_htonll(v); + memcpy(where, &v, sizeof(v)); +} + +static inline bool would_overflow(CborEncoder *encoder, size_t len) +{ + ptrdiff_t remaining = (ptrdiff_t)encoder->end; + remaining -= remaining ? (ptrdiff_t)encoder->data.ptr : encoder->data.bytes_needed; + remaining -= (ptrdiff_t)len; + return unlikely(remaining < 0); +} + +static inline void advance_ptr(CborEncoder *encoder, size_t n) +{ + if (encoder->end) + encoder->data.ptr += n; + else + encoder->data.bytes_needed += n; +} + +static inline CborError append_to_buffer(CborEncoder *encoder, const void *data, size_t len) +{ + if (would_overflow(encoder, len)) { + if (encoder->end != NULL) { + len -= encoder->end - encoder->data.ptr; + encoder->end = NULL; + encoder->data.bytes_needed = 0; + } + + advance_ptr(encoder, len); + return CborErrorOutOfMemory; + } + + memcpy(encoder->data.ptr, data, len); + encoder->data.ptr += len; + return CborNoError; +} + +static inline CborError append_byte_to_buffer(CborEncoder *encoder, uint8_t byte) +{ + return append_to_buffer(encoder, &byte, 1); +} + +static inline CborError encode_number_no_update(CborEncoder *encoder, uint64_t ui, uint8_t shiftedMajorType) +{ + /* Little-endian would have been so much more convenient here: + * We could just write at the beginning of buf but append_to_buffer + * only the necessary bytes. + * Since it has to be big endian, do it the other way around: + * write from the end. */ + uint64_t buf[2]; + uint8_t *const bufend = (uint8_t *)buf + sizeof(buf); + uint8_t *bufstart = bufend - 1; + put64(buf + 1, ui); /* we probably have a bunch of zeros in the beginning */ + + if (ui < Value8Bit) { + *bufstart += shiftedMajorType; + } else { + uint8_t more = 0; + if (ui > 0xffU) + ++more; + if (ui > 0xffffU) + ++more; + if (ui > 0xffffffffU) + ++more; + bufstart -= (size_t)1 << more; + *bufstart = shiftedMajorType + Value8Bit + more; + } + + return append_to_buffer(encoder, bufstart, bufend - bufstart); +} + +static inline void saturated_decrement(CborEncoder *encoder) +{ + if (encoder->remaining) + --encoder->remaining; +} + +static inline CborError encode_number(CborEncoder *encoder, uint64_t ui, uint8_t shiftedMajorType) +{ + saturated_decrement(encoder); + return encode_number_no_update(encoder, ui, shiftedMajorType); +} + +/** + * Appends the unsigned 64-bit integer \a value to the CBOR stream provided by + * \a encoder. + * + * \sa cbor_encode_negative_int, cbor_encode_int + */ +CborError cbor_encode_uint(CborEncoder *encoder, uint64_t value) +{ + return encode_number(encoder, value, UnsignedIntegerType << MajorTypeShift); +} + +/** + * Appends the negative 64-bit integer whose absolute value is \a + * absolute_value to the CBOR stream provided by \a encoder. + * + * If the value \a absolute_value is zero, this function encodes -2^64. + * + * \sa cbor_encode_uint, cbor_encode_int + */ +CborError cbor_encode_negative_int(CborEncoder *encoder, uint64_t absolute_value) +{ + return encode_number(encoder, absolute_value - 1, NegativeIntegerType << MajorTypeShift); +} + +/** + * Appends the signed 64-bit integer \a value to the CBOR stream provided by + * \a encoder. + * + * \sa cbor_encode_negative_int, cbor_encode_uint + */ +CborError cbor_encode_int(CborEncoder *encoder, int64_t value) +{ + /* adapted from code in RFC 7049 appendix C (pseudocode) */ + uint64_t ui = value >> 63; /* extend sign to whole length */ + uint8_t majorType = ui & 0x20; /* extract major type */ + ui ^= value; /* complement negatives */ + return encode_number(encoder, ui, majorType); +} + +/** + * Appends the CBOR Simple Type of value \a value to the CBOR stream provided by + * \a encoder. + * + * This function may return error CborErrorIllegalSimpleType if the \a value + * variable contains a number that is not a valid simple type. + */ +CborError cbor_encode_simple_value(CborEncoder *encoder, uint8_t value) +{ +#ifndef CBOR_ENCODER_NO_CHECK_USER + /* check if this is a valid simple type */ + if (value >= HalfPrecisionFloat && value <= Break) + return CborErrorIllegalSimpleType; +#endif + return encode_number(encoder, value, SimpleTypesType << MajorTypeShift); +} + +/** + * Appends the floating-point value of type \a fpType and pointed to by \a + * value to the CBOR stream provided by \a encoder. The value of \a fpType must + * be one of CborHalfFloatType, CborFloatType or CborDoubleType, otherwise the + * behavior of this function is undefined. + * + * This function is useful for code that needs to pass through floating point + * values but does not wish to have the actual floating-point code. + * + * \sa cbor_encode_half_float, cbor_encode_float, cbor_encode_double + */ +CborError cbor_encode_floating_point(CborEncoder *encoder, CborType fpType, const void *value) +{ + unsigned size; + uint8_t buf[1 + sizeof(uint64_t)]; + cbor_assert(fpType == CborHalfFloatType || fpType == CborFloatType || fpType == CborDoubleType); + buf[0] = fpType; + + size = 2U << (fpType - CborHalfFloatType); + if (size == 8) + put64(buf + 1, *(const uint64_t*)value); + else if (size == 4) + put32(buf + 1, *(const uint32_t*)value); + else + put16(buf + 1, *(const uint16_t*)value); + saturated_decrement(encoder); + return append_to_buffer(encoder, buf, size + 1); +} + +/** + * Appends the CBOR tag \a tag to the CBOR stream provided by \a encoder. + * + * \sa CborTag + */ +CborError cbor_encode_tag(CborEncoder *encoder, CborTag tag) +{ + /* tags don't count towards the number of elements in an array or map */ + return encode_number_no_update(encoder, tag, TagType << MajorTypeShift); +} + +static CborError encode_string(CborEncoder *encoder, size_t length, uint8_t shiftedMajorType, const void *string) +{ + CborError err = encode_number(encoder, length, shiftedMajorType); + if (err && !isOomError(err)) + return err; + return append_to_buffer(encoder, string, length); +} + +/** + * \fn CborError cbor_encode_text_stringz(CborEncoder *encoder, const char *string) + * + * Appends the null-terminated text string \a string to the CBOR stream + * provided by \a encoder. CBOR requires that \a string be valid UTF-8, but + * TinyCBOR makes no verification of correctness. The terminating null is not + * included in the stream. + * + * \sa cbor_encode_text_string, cbor_encode_byte_string + */ + +/** + * Appends the text string \a string of length \a length to the CBOR stream + * provided by \a encoder. CBOR requires that \a string be valid UTF-8, but + * TinyCBOR makes no verification of correctness. + * + * \sa CborError cbor_encode_text_stringz, cbor_encode_byte_string + */ +CborError cbor_encode_byte_string(CborEncoder *encoder, const uint8_t *string, size_t length) +{ + return encode_string(encoder, length, ByteStringType << MajorTypeShift, string); +} + +/** + * Appends the byte string \a string of length \a length to the CBOR stream + * provided by \a encoder. CBOR byte strings are arbitrary raw data. + * + * \sa cbor_encode_text_stringz, cbor_encode_text_string + */ +CborError cbor_encode_text_string(CborEncoder *encoder, const char *string, size_t length) +{ + return encode_string(encoder, length, TextStringType << MajorTypeShift, string); +} + +#ifdef __GNUC__ +__attribute__((noinline)) +#endif +static CborError create_container(CborEncoder *encoder, CborEncoder *container, size_t length, uint8_t shiftedMajorType) +{ + CborError err; + container->data.ptr = encoder->data.ptr; + container->end = encoder->end; + saturated_decrement(encoder); + container->remaining = length + 1; /* overflow ok on CborIndefiniteLength */ + + cbor_static_assert(((MapType << MajorTypeShift) & CborIteratorFlag_ContainerIsMap) == CborIteratorFlag_ContainerIsMap); + cbor_static_assert(((ArrayType << MajorTypeShift) & CborIteratorFlag_ContainerIsMap) == 0); + container->flags = shiftedMajorType & CborIteratorFlag_ContainerIsMap; + + if (length == CborIndefiniteLength) { + container->flags |= CborIteratorFlag_UnknownLength; + err = append_byte_to_buffer(container, shiftedMajorType + IndefiniteLength); + } else { + if (shiftedMajorType & CborIteratorFlag_ContainerIsMap) + container->remaining += length; + err = encode_number_no_update(container, length, shiftedMajorType); + } + return err; +} + +/** + * Creates a CBOR array in the CBOR stream provided by \a encoder and + * initializes \a arrayEncoder so that items can be added to the array using + * the CborEncoder functions. The array must be terminated by calling either + * cbor_encoder_close_container() or cbor_encoder_close_container_checked() + * with the same \a encoder and \a arrayEncoder parameters. + * + * The number of items inserted into the array must be exactly \a length items, + * otherwise the stream is invalid. If the number of items is not known when + * creating the array, the constant \ref CborIndefiniteLength may be passed as + * length instead. + * + * \sa cbor_encoder_create_map + */ +CborError cbor_encoder_create_array(CborEncoder *encoder, CborEncoder *arrayEncoder, size_t length) +{ + return create_container(encoder, arrayEncoder, length, ArrayType << MajorTypeShift); +} + +/** + * Creates a CBOR map in the CBOR stream provided by \a encoder and + * initializes \a mapEncoder so that items can be added to the map using + * the CborEncoder functions. The map must be terminated by calling either + * cbor_encoder_close_container() or cbor_encoder_close_container_checked() + * with the same \a encoder and \a mapEncoder parameters. + * + * The number of pair of items inserted into the map must be exactly \a length + * items, otherwise the stream is invalid. If the number is not known + * when creating the map, the constant \ref CborIndefiniteLength may be passed as + * length instead. + * + * \b{Implementation limitation:} TinyCBOR cannot encode more than SIZE_MAX/2 + * key-value pairs in the stream. If the length \a length is larger than this + * value (and is not \ref CborIndefiniteLength), this function returns error + * CborErrorDataTooLarge. + * + * \sa cbor_encoder_create_array + */ +CborError cbor_encoder_create_map(CborEncoder *encoder, CborEncoder *mapEncoder, size_t length) +{ + if (length != CborIndefiniteLength && length > SIZE_MAX / 2) + return CborErrorDataTooLarge; + return create_container(encoder, mapEncoder, length, MapType << MajorTypeShift); +} + +/** + * Closes the CBOR container (array or map) provided by \a containerEncoder and + * updates the CBOR stream provided by \a encoder. Both parameters must be the + * same as were passed to cbor_encoder_create_array() or + * cbor_encoder_create_map(). + * + * Since version 0.5, this function verifies that the number of items (or pairs + * of items, in the case of a map) was correct. It is no longer necessary to call + * cbor_encoder_close_container_checked() instead. + * + * \sa cbor_encoder_create_array(), cbor_encoder_create_map() + */ +CborError cbor_encoder_close_container(CborEncoder *encoder, const CborEncoder *containerEncoder) +{ + if (encoder->end) + encoder->data.ptr = containerEncoder->data.ptr; + else + encoder->data.bytes_needed = containerEncoder->data.bytes_needed; + encoder->end = containerEncoder->end; + if (containerEncoder->flags & CborIteratorFlag_UnknownLength) + return append_byte_to_buffer(encoder, BreakByte); + + if (containerEncoder->remaining != 1) + return containerEncoder->remaining == 0 ? CborErrorTooManyItems : CborErrorTooFewItems; + + if (!encoder->end) + return CborErrorOutOfMemory; /* keep the state */ + return CborNoError; +} + +/** + * \fn CborError cbor_encode_boolean(CborEncoder *encoder, bool value) + * + * Appends the boolean value \a value to the CBOR stream provided by \a encoder. + */ + +/** + * \fn CborError cbor_encode_null(CborEncoder *encoder) + * + * Appends the CBOR type representing a null value to the CBOR stream provided + * by \a encoder. + * + * \sa cbor_encode_undefined() + */ + +/** + * \fn CborError cbor_encode_undefined(CborEncoder *encoder) + * + * Appends the CBOR type representing an undefined value to the CBOR stream + * provided by \a encoder. + * + * \sa cbor_encode_null() + */ + +/** + * \fn CborError cbor_encode_half_float(CborEncoder *encoder, const void *value) + * + * Appends the IEEE 754 half-precision (16-bit) floating point value pointed to + * by \a value to the CBOR stream provided by \a encoder. + * + * \sa cbor_encode_floating_point(), cbor_encode_float(), cbor_encode_double() + */ + +/** + * \fn CborError cbor_encode_float(CborEncoder *encoder, float value) + * + * Appends the IEEE 754 single-precision (32-bit) floating point value \a value + * to the CBOR stream provided by \a encoder. + * + * \sa cbor_encode_floating_point(), cbor_encode_half_float(), cbor_encode_double() + */ + +/** + * \fn CborError cbor_encode_double(CborEncoder *encoder, double value) + * + * Appends the IEEE 754 double-precision (64-bit) floating point value \a value + * to the CBOR stream provided by \a encoder. + * + * \sa cbor_encode_floating_point(), cbor_encode_half_float(), cbor_encode_float() + */ + +/** + * \fn size_t cbor_encoder_get_buffer_size(const CborEncoder *encoder, const uint8_t *buffer) + * + * Returns the total size of the buffer starting at \a buffer after the + * encoding finished without errors. The \a encoder and \a buffer arguments + * must be the same as supplied to cbor_encoder_init(). + * + * If the encoding process had errors, the return value of this function is + * meaningless. If the only errors were CborErrorOutOfMemory, instead use + * cbor_encoder_get_extra_bytes_needed() to find out by how much to grow the + * buffer before encoding again. + * + * See \ref CborEncoding for an example of using this function. + * + * \sa cbor_encoder_init(), cbor_encoder_get_extra_bytes_needed(), CborEncoding + */ + +/** + * \fn size_t cbor_encoder_get_extra_bytes_needed(const CborEncoder *encoder) + * + * Returns how many more bytes the original buffer supplied to + * cbor_encoder_init() needs to be extended by so that no CborErrorOutOfMemory + * condition will happen for the encoding. If the buffer was big enough, this + * function returns 0. The \a encoder must be the original argument as passed + * to cbor_encoder_init(). + * + * This function is usually called after an encoding sequence ended with one or + * more CborErrorOutOfMemory errors, but no other error. If any other error + * happened, the return value of this function is meaningless. + * + * See \ref CborEncoding for an example of using this function. + * + * \sa cbor_encoder_init(), cbor_encoder_get_buffer_size(), CborEncoding + */ + +/** @} */ diff --git a/client/tinycbor/cborencoder_close_container_checked.c b/client/tinycbor/cborencoder_close_container_checked.c new file mode 100644 index 00000000..5661e4d5 --- /dev/null +++ b/client/tinycbor/cborencoder_close_container_checked.c @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Intel Corporation +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +** copies of the Software, and to permit persons to whom the Software is +** furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +** THE SOFTWARE. +** +****************************************************************************/ + +#define _BSD_SOURCE 1 +#define _DEFAULT_SOURCE 1 +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS 1 +#endif + +#include "cbor.h" + +/** + * \addtogroup CborEncoding + * @{ + */ + +/** + * @deprecated + * + * Closes the CBOR container (array or map) provided by \a containerEncoder and + * updates the CBOR stream provided by \a encoder. Both parameters must be the + * same as were passed to cbor_encoder_create_array() or + * cbor_encoder_create_map(). + * + * Prior to version 0.5, cbor_encoder_close_container() did not check the + * number of items added. Since that version, it does and now + * cbor_encoder_close_container_checked() is no longer needed. + * + * \sa cbor_encoder_create_array(), cbor_encoder_create_map() + */ +CborError cbor_encoder_close_container_checked(CborEncoder *encoder, const CborEncoder *containerEncoder) +{ + return cbor_encoder_close_container(encoder, containerEncoder); +} + +/** @} */ diff --git a/client/tinycbor/cborerrorstrings.c b/client/tinycbor/cborerrorstrings.c new file mode 100644 index 00000000..3fe3a982 --- /dev/null +++ b/client/tinycbor/cborerrorstrings.c @@ -0,0 +1,182 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Intel Corporation +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +** copies of the Software, and to permit persons to whom the Software is +** furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +** THE SOFTWARE. +** +****************************************************************************/ + +#include "cbor.h" + +#ifndef _ +# define _(msg) msg +#endif + +/** + * \enum CborError + * \ingroup CborGlobals + * The CborError enum contains the possible error values used by the CBOR encoder and decoder. + * + * TinyCBOR functions report success by returning CborNoError, or one error + * condition by returning one of the values below. One exception is the + * out-of-memory condition (CborErrorOutOfMemory), which the functions for \ref + * CborEncoding may report in bit-wise OR with other conditions. + * + * This technique allows code to determine whether the only error condition was + * a lack of buffer space, which may not be a fatal condition if the buffer can + * be resized. Additionally, the functions for \ref CborEncoding may continue + * to be used even after CborErrorOutOfMemory is returned, and instead they + * will simply calculate the extra space needed. + * + * \value CborNoError No error occurred + * \omitvalue CborUnknownError + * \value CborErrorUnknownLength Request for the length of an array, map or string whose length is not provided in the CBOR stream + * \value CborErrorAdvancePastEOF Not enough data in the stream to decode item (decoding would advance past end of stream) + * \value CborErrorIO An I/O error occurred, probably due to an out-of-memory situation + * \value CborErrorGarbageAtEnd Bytes exist past the end of the CBOR stream + * \value CborErrorUnexpectedEOF End of stream reached unexpectedly + * \value CborErrorUnexpectedBreak A CBOR break byte was found where not expected + * \value CborErrorUnknownType An unknown type (future extension to CBOR) was found in the stream + * \value CborErrorIllegalType An invalid type was found while parsing a chunked CBOR string + * \value CborErrorIllegalNumber An illegal initial byte (encoding unspecified additional information) was found + * \value CborErrorIllegalSimpleType An illegal encoding of a CBOR Simple Type of value less than 32 was found + * \omitvalue CborErrorUnknownSimpleType + * \omitvalue CborErrorUnknownTag + * \omitvalue CborErrorInappropriateTagForType + * \omitvalue CborErrorDuplicateObjectKeys + * \value CborErrorInvalidUtf8TextString Illegal UTF-8 encoding found while parsing CBOR Text String + * \value CborErrorTooManyItems Too many items were added to CBOR map or array of pre-determined length + * \value CborErrorTooFewItems Too few items were added to CBOR map or array of pre-determined length + * \value CborErrorDataTooLarge Data item size exceeds TinyCBOR's implementation limits + * \value CborErrorNestingTooDeep Data item nesting exceeds TinyCBOR's implementation limits + * \omitvalue CborErrorUnsupportedType + * \value CborErrorJsonObjectKeyIsAggregate Conversion to JSON failed because the key in a map is a CBOR map or array + * \value CborErrorJsonObjectKeyNotString Conversion to JSON failed because the key in a map is not a text string + * \value CborErrorOutOfMemory During CBOR encoding, the buffer provided is insufficient for encoding the data item; + * in other situations, TinyCBOR failed to allocate memory + * \value CborErrorInternalError An internal error occurred in TinyCBOR + */ + +/** + * \ingroup CborGlobals + * Returns the error string corresponding to the CBOR error condition \a error. + */ +const char *cbor_error_string(CborError error) +{ + switch (error) { + case CborNoError: + return ""; + + case CborUnknownError: + return _("unknown error"); + + case CborErrorOutOfMemory: + return _("out of memory/need more memory"); + + case CborErrorUnknownLength: + return _("unknown length (attempted to get the length of a map/array/string of indeterminate length"); + + case CborErrorAdvancePastEOF: + return _("attempted to advance past EOF"); + + case CborErrorIO: + return _("I/O error"); + + case CborErrorGarbageAtEnd: + return _("garbage after the end of the content"); + + case CborErrorUnexpectedEOF: + return _("unexpected end of data"); + + case CborErrorUnexpectedBreak: + return _("unexpected 'break' byte"); + + case CborErrorUnknownType: + return _("illegal byte (encodes future extension type)"); + + case CborErrorIllegalType: + return _("mismatched string type in chunked string"); + + case CborErrorIllegalNumber: + return _("illegal initial byte (encodes unspecified additional information)"); + + case CborErrorIllegalSimpleType: + return _("illegal encoding of simple type smaller than 32"); + + case CborErrorUnknownSimpleType: + return _("unknown simple type"); + + case CborErrorUnknownTag: + return _("unknown tag"); + + case CborErrorInappropriateTagForType: + return _("inappropriate tag for type"); + + case CborErrorDuplicateObjectKeys: + return _("duplicate keys in object"); + + case CborErrorInvalidUtf8TextString: + return _("invalid UTF-8 content in string"); + + case CborErrorExcludedType: + return _("excluded type found"); + + case CborErrorExcludedValue: + return _("excluded value found"); + + case CborErrorImproperValue: + case CborErrorOverlongEncoding: + return _("value encoded in non-canonical form"); + + case CborErrorMapKeyNotString: + case CborErrorJsonObjectKeyNotString: + return _("key in map is not a string"); + + case CborErrorMapNotSorted: + return _("map is not sorted"); + + case CborErrorMapKeysNotUnique: + return _("map keys are not unique"); + + case CborErrorTooManyItems: + return _("too many items added to encoder"); + + case CborErrorTooFewItems: + return _("too few items added to encoder"); + + case CborErrorDataTooLarge: + return _("internal error: data too large"); + + case CborErrorNestingTooDeep: + return _("internal error: too many nested containers found in recursive function"); + + case CborErrorUnsupportedType: + return _("unsupported type"); + + case CborErrorJsonObjectKeyIsAggregate: + return _("conversion to JSON failed: key in object is an array or map"); + + case CborErrorJsonNotImplemented: + return _("conversion to JSON failed: open_memstream unavailable"); + + case CborErrorInternalError: + return _("internal error"); + } + return cbor_error_string(CborUnknownError); +} diff --git a/client/tinycbor/cborinternal_p.h b/client/tinycbor/cborinternal_p.h new file mode 100644 index 00000000..a85a9297 --- /dev/null +++ b/client/tinycbor/cborinternal_p.h @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Intel Corporation +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +** copies of the Software, and to permit persons to whom the Software is +** furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +** THE SOFTWARE. +** +****************************************************************************/ + +#ifndef CBORINTERNAL_P_H +#define CBORINTERNAL_P_H + +#include "compilersupport_p.h" + +#ifndef CBOR_NO_FLOATING_POINT +# include +# include +#else +# ifndef CBOR_NO_HALF_FLOAT_TYPE +# define CBOR_NO_HALF_FLOAT_TYPE 1 +# endif +#endif + +#ifndef CBOR_NO_HALF_FLOAT_TYPE +# ifdef __F16C__ +# include +static inline unsigned short encode_half(double val) +{ + return _cvtss_sh((float)val, 3); +} +static inline double decode_half(unsigned short half) +{ + return _cvtsh_ss(half); +} +# else +/* software implementation of float-to-fp16 conversions */ +static inline unsigned short encode_half(double val) +{ + uint64_t v; + int sign, exp, mant; + memcpy(&v, &val, sizeof(v)); + sign = v >> 63 << 15; + exp = (v >> 52) & 0x7ff; + mant = v << 12 >> 12 >> (53-11); /* keep only the 11 most significant bits of the mantissa */ + exp -= 1023; + if (exp == 1024) { + /* infinity or NaN */ + exp = 16; + mant >>= 1; + } else if (exp >= 16) { + /* overflow, as largest number */ + exp = 15; + mant = 1023; + } else if (exp >= -14) { + /* regular normal */ + } else if (exp >= -24) { + /* subnormal */ + mant |= 1024; + mant >>= -(exp + 14); + exp = -15; + } else { + /* underflow, make zero */ + return 0; + } + + /* safe cast here as bit operations above guarantee not to overflow */ + return (unsigned short)(sign | ((exp + 15) << 10) | mant); +} + +/* this function was copied & adapted from RFC 7049 Appendix D */ +static inline double decode_half(unsigned short half) +{ + int exp = (half >> 10) & 0x1f; + int mant = half & 0x3ff; + double val; + if (exp == 0) val = ldexp(mant, -24); + else if (exp != 31) val = ldexp(mant + 1024, exp - 25); + else val = mant == 0 ? INFINITY : NAN; + return half & 0x8000 ? -val : val; +} +# endif +#endif /* CBOR_NO_HALF_FLOAT_TYPE */ + +#ifndef CBOR_INTERNAL_API +# define CBOR_INTERNAL_API +#endif + +#ifndef CBOR_PARSER_MAX_RECURSIONS +# define CBOR_PARSER_MAX_RECURSIONS 1024 +#endif + +/* + * CBOR Major types + * Encoded in the high 3 bits of the descriptor byte + * See http://tools.ietf.org/html/rfc7049#section-2.1 + */ +typedef enum CborMajorTypes { + UnsignedIntegerType = 0U, + NegativeIntegerType = 1U, + ByteStringType = 2U, + TextStringType = 3U, + ArrayType = 4U, + MapType = 5U, /* a.k.a. object */ + TagType = 6U, + SimpleTypesType = 7U +} CborMajorTypes; + +/* + * CBOR simple and floating point types + * Encoded in the low 8 bits of the descriptor byte when the + * Major Type is 7. + */ +typedef enum CborSimpleTypes { + FalseValue = 20, + TrueValue = 21, + NullValue = 22, + UndefinedValue = 23, + SimpleTypeInNextByte = 24, /* not really a simple type */ + HalfPrecisionFloat = 25, /* ditto */ + SinglePrecisionFloat = 26, /* ditto */ + DoublePrecisionFloat = 27, /* ditto */ + Break = 31 +} CborSimpleTypes; + +enum { + SmallValueBitLength = 5U, + SmallValueMask = (1U << SmallValueBitLength) - 1, /* 31 */ + Value8Bit = 24U, + Value16Bit = 25U, + Value32Bit = 26U, + Value64Bit = 27U, + IndefiniteLength = 31U, + + MajorTypeShift = SmallValueBitLength, + MajorTypeMask = (int) (~0U << MajorTypeShift), + + BreakByte = (unsigned)Break | (SimpleTypesType << MajorTypeShift) +}; + +CBOR_INTERNAL_API CborError CBOR_INTERNAL_API_CC _cbor_value_extract_number(const uint8_t **ptr, const uint8_t *end, uint64_t *len); +CBOR_INTERNAL_API CborError CBOR_INTERNAL_API_CC _cbor_value_prepare_string_iteration(CborValue *it); +CBOR_INTERNAL_API CborError CBOR_INTERNAL_API_CC _cbor_value_get_string_chunk(const CborValue *value, const void **bufferptr, + size_t *len, CborValue *next); + + +#endif /* CBORINTERNAL_P_H */ diff --git a/client/tinycbor/cborjson.h b/client/tinycbor/cborjson.h new file mode 100644 index 00000000..8ff27b92 --- /dev/null +++ b/client/tinycbor/cborjson.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Intel Corporation +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +** copies of the Software, and to permit persons to whom the Software is +** furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +** THE SOFTWARE. +** +****************************************************************************/ + +#ifndef CBORJSON_H +#define CBORJSON_H + +#include "cbor.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Conversion to JSON */ +enum CborToJsonFlags +{ + CborConvertAddMetadata = 1, + CborConvertTagsToObjects = 2, + CborConvertIgnoreTags = 0, + + CborConvertObeyByteStringTags = 0, + CborConvertByteStringsToBase64Url = 4, + + CborConvertRequireMapStringKeys = 0, + CborConvertStringifyMapKeys = 8, + + CborConvertDefaultFlags = 0 +}; + +CBOR_API CborError cbor_value_to_json_advance(FILE *out, CborValue *value, int flags); +CBOR_INLINE_API CborError cbor_value_to_json(FILE *out, const CborValue *value, int flags) +{ + CborValue copy = *value; + return cbor_value_to_json_advance(out, ©, flags); +} + +#ifdef __cplusplus +} +#endif + +#endif /* CBORJSON_H */ + diff --git a/client/tinycbor/cborparser.c b/client/tinycbor/cborparser.c new file mode 100644 index 00000000..45de2226 --- /dev/null +++ b/client/tinycbor/cborparser.c @@ -0,0 +1,1430 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Intel Corporation +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +** copies of the Software, and to permit persons to whom the Software is +** furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +** THE SOFTWARE. +** +****************************************************************************/ + +#ifndef _BSD_SOURCE +#define _BSD_SOURCE 1 +#endif +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE 1 +#endif +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS 1 +#endif + +#include "cbor.h" +#include "cborinternal_p.h" +#include "compilersupport_p.h" + +#include + +/** + * \defgroup CborParsing Parsing CBOR streams + * \brief Group of functions used to parse CBOR streams. + * + * TinyCBOR provides functions for pull-based stream parsing of a CBOR-encoded + * payload. The main data type for the parsing is a CborValue, which behaves + * like an iterator and can be used to extract the encoded data. It is first + * initialized with a call to cbor_parser_init() and is usually used to extract + * exactly one item, most often an array or map. + * + * Nested CborValue objects can be parsed using cbor_value_enter_container(). + * Each call to cbor_value_enter_container() must be matched by a call to + * cbor_value_leave_container(), with the exact same parameters. + * + * The example below initializes a CborParser object, begins the parsing with a + * CborValue and decodes a single integer: + * + * \code + * int extract_int(const uint8_t *buffer, size_t len) + * { + * CborParser parser; + * CborValue value; + * int result; + * cbor_parser_init(buffer, len, 0, &parser, &value); + * cbor_value_get_int(&value, &result); + * return result; + * } + * \endcode + * + * The code above does no error checking, which means it assumes the data comes + * from a source trusted to send one properly-encoded integer. The following + * example does the exact same operation, but includes error checking and + * returns 0 on parsing failure: + * + * \code + * int extract_int(const uint8_t *buffer, size_t len) + * { + * CborParser parser; + * CborValue value; + * int result; + * if (cbor_parser_init(buffer, len, 0, &parser, &value) != CborNoError) + * return 0; + * if (!cbor_value_is_integer(&value) || + * cbor_value_get_int(&value, &result) != CborNoError) + * return 0; + * return result; + * } + * \endcode + * + * Note, in the example above, that one can't distinguish a parsing failure + * from an encoded value of zero. Reporting a parsing error is left as an + * exercise to the reader. + * + * The code above does not execute a range-check either: it is possible that + * the value decoded from the CBOR stream encodes a number larger than what can + * be represented in a variable of type \c{int}. If detecting that case is + * important, the code should call cbor_value_get_int_checked() instead. + * + *

Memory and parsing constraints

+ * + * TinyCBOR is designed to run with little memory and with minimal overhead. + * Except where otherwise noted, the parser functions always run on constant + * time (O(1)), do not recurse and never allocate memory (thus, stack usage is + * bounded and is O(1)). + * + *

Error handling and preconditions

+ * + * All functions operating on a CborValue return a CborError condition, with + * CborNoError standing for the normal situation in which no parsing error + * occurred. All functions may return parsing errors in case the stream cannot + * be decoded properly, be it due to corrupted data or due to reaching the end + * of the input buffer. + * + * Error conditions must not be ignored. All decoder functions have undefined + * behavior if called after an error has been reported, and may crash. + * + * Some functions are also documented to have preconditions, like + * cbor_value_get_int() requiring that the input be an integral value. + * Violation of preconditions also results in undefined behavior and the + * program may crash. + */ + +/** + * \addtogroup CborParsing + * @{ + */ + +/** + * \struct CborValue + * + * This type contains one value parsed from the CBOR stream. Each CborValue + * behaves as an iterator in a StAX-style parser. + * + * \if privatedocs + * Implementation details: the CborValue contains these fields: + * \list + * \li ptr: pointer to the actual data + * \li flags: flags from the decoder + * \li extra: partially decoded integer value (0, 1 or 2 bytes) + * \li remaining: remaining items in this collection after this item or UINT32_MAX if length is unknown + * \endlist + * \endif + */ + +static inline uint16_t get16(const uint8_t *ptr) +{ + uint16_t result; + memcpy(&result, ptr, sizeof(result)); + return cbor_ntohs(result); +} + +static inline uint32_t get32(const uint8_t *ptr) +{ + uint32_t result; + memcpy(&result, ptr, sizeof(result)); + return cbor_ntohl(result); +} + +static inline uint64_t get64(const uint8_t *ptr) +{ + uint64_t result; + memcpy(&result, ptr, sizeof(result)); + return cbor_ntohll(result); +} + +CborError CBOR_INTERNAL_API_CC _cbor_value_extract_number(const uint8_t **ptr, const uint8_t *end, uint64_t *len) +{ + size_t bytesNeeded; + uint8_t additional_information = **ptr & SmallValueMask; + ++*ptr; + if (additional_information < Value8Bit) { + *len = additional_information; + return CborNoError; + } + if (unlikely(additional_information > Value64Bit)) + return CborErrorIllegalNumber; + + bytesNeeded = (size_t)(1 << (additional_information - Value8Bit)); + if (unlikely(bytesNeeded > (size_t)(end - *ptr))) { + return CborErrorUnexpectedEOF; + } else if (bytesNeeded == 1) { + *len = (uint8_t)(*ptr)[0]; + } else if (bytesNeeded == 2) { + *len = get16(*ptr); + } else if (bytesNeeded == 4) { + *len = get32(*ptr); + } else { + *len = get64(*ptr); + } + *ptr += bytesNeeded; + return CborNoError; +} + +static CborError extract_length(const CborParser *parser, const uint8_t **ptr, size_t *len) +{ + uint64_t v; + CborError err = _cbor_value_extract_number(ptr, parser->end, &v); + if (err) { + *len = 0; + return err; + } + + *len = (size_t)v; + if (v != *len) + return CborErrorDataTooLarge; + return CborNoError; +} + +static bool is_fixed_type(uint8_t type) +{ + return type != CborTextStringType && type != CborByteStringType && type != CborArrayType && + type != CborMapType; +} + +static CborError preparse_value(CborValue *it) +{ + const CborParser *parser = it->parser; + it->type = CborInvalidType; + + /* are we at the end? */ + if (it->ptr == parser->end) + return CborErrorUnexpectedEOF; + + uint8_t descriptor = *it->ptr; + uint8_t type = descriptor & MajorTypeMask; + it->type = type; + it->flags = 0; + it->extra = (descriptor &= SmallValueMask); + + if (descriptor > Value64Bit) { + if (unlikely(descriptor != IndefiniteLength)) + return type == CborSimpleType ? CborErrorUnknownType : CborErrorIllegalNumber; + if (likely(!is_fixed_type(type))) { + /* special case */ + it->flags |= CborIteratorFlag_UnknownLength; + it->type = type; + return CborNoError; + } + return type == CborSimpleType ? CborErrorUnexpectedBreak : CborErrorIllegalNumber; + } + + size_t bytesNeeded = descriptor < Value8Bit ? 0 : (1 << (descriptor - Value8Bit)); + if (bytesNeeded + 1 > (size_t)(parser->end - it->ptr)) + return CborErrorUnexpectedEOF; + + uint8_t majortype = type >> MajorTypeShift; + if (majortype == NegativeIntegerType) { + it->flags |= CborIteratorFlag_NegativeInteger; + it->type = CborIntegerType; + } else if (majortype == SimpleTypesType) { + switch (descriptor) { + case FalseValue: + it->extra = false; + it->type = CborBooleanType; + break; + + case SinglePrecisionFloat: + case DoublePrecisionFloat: + it->flags |= CborIteratorFlag_IntegerValueTooLarge; + /* fall through */ + case TrueValue: + case NullValue: + case UndefinedValue: + case HalfPrecisionFloat: + it->type = *it->ptr; + break; + + case SimpleTypeInNextByte: + it->extra = (uint8_t)it->ptr[1]; +#ifndef CBOR_PARSER_NO_STRICT_CHECKS + if (unlikely(it->extra < 32)) { + it->type = CborInvalidType; + return CborErrorIllegalSimpleType; + } +#endif + break; + + case 28: + case 29: + case 30: + case Break: + cbor_assert(false); /* these conditions can't be reached */ + return CborErrorUnexpectedBreak; + } + return CborNoError; + } + + /* try to decode up to 16 bits */ + if (descriptor < Value8Bit) + return CborNoError; + + if (descriptor == Value8Bit) + it->extra = (uint8_t)it->ptr[1]; + else if (descriptor == Value16Bit) + it->extra = get16(it->ptr + 1); + else + it->flags |= CborIteratorFlag_IntegerValueTooLarge; /* Value32Bit or Value64Bit */ + return CborNoError; +} + +static CborError preparse_next_value_nodecrement(CborValue *it) +{ + if (it->remaining == UINT32_MAX && it->ptr != it->parser->end && *it->ptr == (uint8_t)BreakByte) { + /* end of map or array */ + ++it->ptr; + it->type = CborInvalidType; + it->remaining = 0; + return CborNoError; + } + + return preparse_value(it); +} + +static CborError preparse_next_value(CborValue *it) +{ + if (it->remaining != UINT32_MAX) { + /* don't decrement the item count if the current item is tag: they don't count */ + if (it->type != CborTagType && --it->remaining == 0) { + it->type = CborInvalidType; + return CborNoError; + } + } + return preparse_next_value_nodecrement(it); +} + +static CborError advance_internal(CborValue *it) +{ + uint64_t length; + CborError err = _cbor_value_extract_number(&it->ptr, it->parser->end, &length); + cbor_assert(err == CborNoError); + + if (it->type == CborByteStringType || it->type == CborTextStringType) { + cbor_assert(length == (size_t)length); + cbor_assert((it->flags & CborIteratorFlag_UnknownLength) == 0); + it->ptr += length; + } + + return preparse_next_value(it); +} + +/** \internal + * + * Decodes the CBOR integer value when it is larger than the 16 bits available + * in value->extra. This function requires that value->flags have the + * CborIteratorFlag_IntegerValueTooLarge flag set. + * + * This function is also used to extract single- and double-precision floating + * point values (SinglePrecisionFloat == Value32Bit and DoublePrecisionFloat == + * Value64Bit). + */ +uint64_t _cbor_value_decode_int64_internal(const CborValue *value) +{ + cbor_assert(value->flags & CborIteratorFlag_IntegerValueTooLarge || + value->type == CborFloatType || value->type == CborDoubleType); + + /* since the additional information can only be Value32Bit or Value64Bit, + * we just need to test for the one bit those two options differ */ + cbor_assert((*value->ptr & SmallValueMask) == Value32Bit || (*value->ptr & SmallValueMask) == Value64Bit); + if ((*value->ptr & 1) == (Value32Bit & 1)) + return get32(value->ptr + 1); + + cbor_assert((*value->ptr & SmallValueMask) == Value64Bit); + return get64(value->ptr + 1); +} + +/** + * Initializes the CBOR parser for parsing \a size bytes beginning at \a + * buffer. Parsing will use flags set in \a flags. The iterator to the first + * element is returned in \a it. + * + * The \a parser structure needs to remain valid throughout the decoding + * process. It is not thread-safe to share one CborParser among multiple + * threads iterating at the same time, but the object can be copied so multiple + * threads can iterate. + */ +CborError cbor_parser_init(const uint8_t *buffer, size_t size, uint32_t flags, CborParser *parser, CborValue *it) +{ + memset(parser, 0, sizeof(*parser)); + parser->end = buffer + size; + parser->flags = flags; + it->parser = parser; + it->ptr = buffer; + it->remaining = 1; /* there's one type altogether, usually an array or map */ + return preparse_value(it); +} + +/** + * \fn bool cbor_value_at_end(const CborValue *it) + * + * Returns true if \a it has reached the end of the iteration, usually when + * advancing after the last item in an array or map. + * + * In the case of the outermost CborValue object, this function returns true + * after decoding a single element. A pointer to the first byte of the + * remaining data (if any) can be obtained with cbor_value_get_next_byte(). + * + * \sa cbor_value_advance(), cbor_value_is_valid(), cbor_value_get_next_byte() + */ + +/** + * \fn const uint8_t *cbor_value_get_next_byte(const CborValue *it) + * + * Returns a pointer to the next byte that would be decoded if this CborValue + * object were advanced. + * + * This function is useful if cbor_value_at_end() returns true for the + * outermost CborValue: the pointer returned is the first byte of the data + * remaining in the buffer, if any. Code can decide whether to begin decoding a + * new CBOR data stream from this point, or parse some other data appended to + * the same buffer. + * + * This function may be used even after a parsing error. If that occurred, + * then this function returns a pointer to where the parsing error occurred. + * Note that the error recovery is not precise and the pointer may not indicate + * the exact byte containing bad data. + * + * \sa cbor_value_at_end() + */ + +/** + * \fn bool cbor_value_is_valid(const CborValue *it) + * + * Returns true if the iterator \a it contains a valid value. Invalid iterators + * happen when iteration reaches the end of a container (see \ref + * cbor_value_at_end()) or when a search function resulted in no matches. + * + * \sa cbor_value_advance(), cbor_value_at_end(), cbor_value_get_type() + */ + +/** + * Performs a basic validation of the CBOR stream pointed by \a it and returns + * the error it found. If no error was found, it returns CborNoError and the + * application can iterate over the items with certainty that no other errors + * will appear during parsing. + * + * A basic validation checks for: + * \list + * \li absence of undefined additional information bytes; + * \li well-formedness of all numbers, lengths, and simple values; + * \li string contents match reported sizes; + * \li arrays and maps contain the number of elements they are reported to have; + * \endlist + * + * For further checks, see cbor_value_validate(). + * + * This function has the same timing and memory requirements as + * cbor_value_advance(). + * + * \sa cbor_value_validate(), cbor_value_advance() + */ +CborError cbor_value_validate_basic(const CborValue *it) +{ + CborValue value = *it; + return cbor_value_advance(&value); +} + +/** + * Advances the CBOR value \a it by one fixed-size position. Fixed-size types + * are: integers, tags, simple types (including boolean, null and undefined + * values) and floating point types. + * + * If the type is not of fixed size, this function has undefined behavior. Code + * must be sure that the current type is one of the fixed-size types before + * calling this function. This function is provided because it can guarantee + * that it runs in constant time (O(1)). + * + * If the caller is not able to determine whether the type is fixed or not, code + * can use the cbor_value_advance() function instead. + * + * \sa cbor_value_at_end(), cbor_value_advance(), cbor_value_enter_container(), cbor_value_leave_container() + */ +CborError cbor_value_advance_fixed(CborValue *it) +{ + cbor_assert(it->type != CborInvalidType); + cbor_assert(is_fixed_type(it->type)); + if (!it->remaining) + return CborErrorAdvancePastEOF; + return advance_internal(it); +} + +static CborError advance_recursive(CborValue *it, int nestingLevel) +{ + CborError err; + CborValue recursed; + + if (is_fixed_type(it->type)) + return advance_internal(it); + + if (!cbor_value_is_container(it)) { + size_t len = SIZE_MAX; + return _cbor_value_copy_string(it, NULL, &len, it); + } + + /* map or array */ + if (nestingLevel == 0) + return CborErrorNestingTooDeep; + + err = cbor_value_enter_container(it, &recursed); + if (err) + return err; + while (!cbor_value_at_end(&recursed)) { + err = advance_recursive(&recursed, nestingLevel - 1); + if (err) + return err; + } + return cbor_value_leave_container(it, &recursed); +} + + +/** + * Advances the CBOR value \a it by one element, skipping over containers. + * Unlike cbor_value_advance_fixed(), this function can be called on a CBOR + * value of any type. However, if the type is a container (map or array) or a + * string with a chunked payload, this function will not run in constant time + * and will recurse into itself (it will run on O(n) time for the number of + * elements or chunks and will use O(n) memory for the number of nested + * containers). + * + * The number of recursions can be limited at compile time to avoid stack + * exhaustion in constrained systems. + * + * \sa cbor_value_at_end(), cbor_value_advance_fixed(), cbor_value_enter_container(), cbor_value_leave_container() + */ +CborError cbor_value_advance(CborValue *it) +{ + cbor_assert(it->type != CborInvalidType); + if (!it->remaining) + return CborErrorAdvancePastEOF; + return advance_recursive(it, CBOR_PARSER_MAX_RECURSIONS); +} + +/** + * \fn bool cbor_value_is_tag(const CborValue *value) + * + * Returns true if the iterator \a value is valid and points to a CBOR tag. + * + * \sa cbor_value_get_tag(), cbor_value_skip_tag() + */ + +/** + * \fn CborError cbor_value_get_tag(const CborValue *value, CborTag *result) + * + * Retrieves the CBOR tag value that \a value points to and stores it in \a + * result. If the iterator \a value does not point to a CBOR tag value, the + * behavior is undefined, so checking with \ref cbor_value_get_type or with + * \ref cbor_value_is_tag is recommended. + * + * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_tag() + */ + +/** + * Advances the CBOR value \a it until it no longer points to a tag. If \a it is + * already not pointing to a tag, then this function returns it unchanged. + * + * This function does not run in constant time: it will run on O(n) for n being + * the number of tags. It does use constant memory (O(1) memory requirements). + * + * \sa cbor_value_advance_fixed(), cbor_value_advance() + */ +CborError cbor_value_skip_tag(CborValue *it) +{ + while (cbor_value_is_tag(it)) { + CborError err = cbor_value_advance_fixed(it); + if (err) + return err; + } + return CborNoError; +} + +/** + * \fn bool cbor_value_is_container(const CborValue *it) + * + * Returns true if the \a it value is a container and requires recursion in + * order to decode (maps and arrays), false otherwise. + */ + +/** + * Creates a CborValue iterator pointing to the first element of the container + * represented by \a it and saves it in \a recursed. The \a it container object + * needs to be kept and passed again to cbor_value_leave_container() in order + * to continue iterating past this container. + * + * The \a it CborValue iterator must point to a container. + * + * \sa cbor_value_is_container(), cbor_value_leave_container(), cbor_value_advance() + */ +CborError cbor_value_enter_container(const CborValue *it, CborValue *recursed) +{ + cbor_assert(cbor_value_is_container(it)); + *recursed = *it; + + if (it->flags & CborIteratorFlag_UnknownLength) { + recursed->remaining = UINT32_MAX; + ++recursed->ptr; + } else { + uint64_t len; + CborError err = _cbor_value_extract_number(&recursed->ptr, recursed->parser->end, &len); + cbor_assert(err == CborNoError); + + recursed->remaining = (uint32_t)len; + if (recursed->remaining != len || len == UINT32_MAX) { + /* back track the pointer to indicate where the error occurred */ + recursed->ptr = it->ptr; + return CborErrorDataTooLarge; + } + if (recursed->type == CborMapType) { + /* maps have keys and values, so we need to multiply by 2 */ + if (recursed->remaining > UINT32_MAX / 2) { + /* back track the pointer to indicate where the error occurred */ + recursed->ptr = it->ptr; + return CborErrorDataTooLarge; + } + recursed->remaining *= 2; + } + if (len == 0) { + /* the case of the empty container */ + recursed->type = CborInvalidType; + return CborNoError; + } + } + return preparse_next_value_nodecrement(recursed); +} + +/** + * Updates \a it to point to the next element after the container. The \a + * recursed object needs to point to the element obtained either by advancing + * the last element of the container (via cbor_value_advance(), + * cbor_value_advance_fixed(), a nested cbor_value_leave_container(), or the \c + * next pointer from cbor_value_copy_string() or cbor_value_dup_string()). + * + * The \a it and \a recursed parameters must be the exact same as passed to + * cbor_value_enter_container(). + * + * \sa cbor_value_enter_container(), cbor_value_at_end() + */ +CborError cbor_value_leave_container(CborValue *it, const CborValue *recursed) +{ + cbor_assert(cbor_value_is_container(it)); + cbor_assert(recursed->type == CborInvalidType); + it->ptr = recursed->ptr; + return preparse_next_value(it); +} + + +/** + * \fn CborType cbor_value_get_type(const CborValue *value) + * + * Returns the type of the CBOR value that the iterator \a value points to. If + * \a value does not point to a valid value, this function returns \ref + * CborInvalidType. + * + * TinyCBOR also provides functions to test directly if a given CborValue object + * is of a given type, like cbor_value_is_text_string() and cbor_value_is_null(). + * + * \sa cbor_value_is_valid() + */ + +/** + * \fn bool cbor_value_is_null(const CborValue *value) + * + * Returns true if the iterator \a value is valid and points to a CBOR null type. + * + * \sa cbor_value_is_valid(), cbor_value_is_undefined() + */ + +/** + * \fn bool cbor_value_is_undefined(const CborValue *value) + * + * Returns true if the iterator \a value is valid and points to a CBOR undefined type. + * + * \sa cbor_value_is_valid(), cbor_value_is_null() + */ + +/** + * \fn bool cbor_value_is_boolean(const CborValue *value) + * + * Returns true if the iterator \a value is valid and points to a CBOR boolean + * type (true or false). + * + * \sa cbor_value_is_valid(), cbor_value_get_boolean() + */ + +/** + * \fn CborError cbor_value_get_boolean(const CborValue *value, bool *result) + * + * Retrieves the boolean value that \a value points to and stores it in \a + * result. If the iterator \a value does not point to a boolean value, the + * behavior is undefined, so checking with \ref cbor_value_get_type or with + * \ref cbor_value_is_boolean is recommended. + * + * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_boolean() + */ + +/** + * \fn bool cbor_value_is_simple_type(const CborValue *value) + * + * Returns true if the iterator \a value is valid and points to a CBOR Simple Type + * type (other than true, false, null and undefined). + * + * \sa cbor_value_is_valid(), cbor_value_get_simple_type() + */ + +/** + * \fn CborError cbor_value_get_simple_type(const CborValue *value, uint8_t *result) + * + * Retrieves the CBOR Simple Type value that \a value points to and stores it + * in \a result. If the iterator \a value does not point to a simple_type + * value, the behavior is undefined, so checking with \ref cbor_value_get_type + * or with \ref cbor_value_is_simple_type is recommended. + * + * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_simple_type() + */ + +/** + * \fn bool cbor_value_is_integer(const CborValue *value) + * + * Returns true if the iterator \a value is valid and points to a CBOR integer + * type. + * + * \sa cbor_value_is_valid(), cbor_value_get_int, cbor_value_get_int64, cbor_value_get_uint64, cbor_value_get_raw_integer + */ + +/** + * \fn bool cbor_value_is_unsigned_integer(const CborValue *value) + * + * Returns true if the iterator \a value is valid and points to a CBOR unsigned + * integer type (positive values or zero). + * + * \sa cbor_value_is_valid(), cbor_value_get_uint64() + */ + +/** + * \fn bool cbor_value_is_negative_integer(const CborValue *value) + * + * Returns true if the iterator \a value is valid and points to a CBOR negative + * integer type. + * + * \sa cbor_value_is_valid(), cbor_value_get_int, cbor_value_get_int64, cbor_value_get_raw_integer + */ + +/** + * \fn CborError cbor_value_get_int(const CborValue *value, int *result) + * + * Retrieves the CBOR integer value that \a value points to and stores it in \a + * result. If the iterator \a value does not point to an integer value, the + * behavior is undefined, so checking with \ref cbor_value_get_type or with + * \ref cbor_value_is_integer is recommended. + * + * Note that this function does not do range-checking: integral values that do + * not fit in a variable of type \c{int} are silently truncated to fit. Use + * cbor_value_get_int_checked() if that is not acceptable. + * + * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_integer() + */ + +/** + * \fn CborError cbor_value_get_int64(const CborValue *value, int64_t *result) + * + * Retrieves the CBOR integer value that \a value points to and stores it in \a + * result. If the iterator \a value does not point to an integer value, the + * behavior is undefined, so checking with \ref cbor_value_get_type or with + * \ref cbor_value_is_integer is recommended. + * + * Note that this function does not do range-checking: integral values that do + * not fit in a variable of type \c{int64_t} are silently truncated to fit. Use + * cbor_value_get_int64_checked() that is not acceptable. + * + * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_integer() + */ + +/** + * \fn CborError cbor_value_get_uint64(const CborValue *value, uint64_t *result) + * + * Retrieves the CBOR integer value that \a value points to and stores it in \a + * result. If the iterator \a value does not point to an unsigned integer + * value, the behavior is undefined, so checking with \ref cbor_value_get_type + * or with \ref cbor_value_is_unsigned_integer is recommended. + * + * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_unsigned_integer() + */ + +/** + * \fn CborError cbor_value_get_raw_integer(const CborValue *value, uint64_t *result) + * + * Retrieves the CBOR integer value that \a value points to and stores it in \a + * result. If the iterator \a value does not point to an integer value, the + * behavior is undefined, so checking with \ref cbor_value_get_type or with + * \ref cbor_value_is_integer is recommended. + * + * This function is provided because CBOR negative integers can assume values + * that cannot be represented with normal 64-bit integer variables. + * + * If the integer is unsigned (that is, if cbor_value_is_unsigned_integer() + * returns true), then \a result will contain the actual value. If the integer + * is negative, then \a result will contain the absolute value of that integer, + * minus one. That is, \c {actual = -result - 1}. On architectures using two's + * complement for representation of negative integers, it is equivalent to say + * that \a result will contain the bitwise negation of the actual value. + * + * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_integer() + */ + +/** + * Retrieves the CBOR integer value that \a value points to and stores it in \a + * result. If the iterator \a value does not point to an integer value, the + * behavior is undefined, so checking with \ref cbor_value_get_type or with + * \ref cbor_value_is_integer is recommended. + * + * Unlike \ref cbor_value_get_int64(), this function performs a check to see if the + * stored integer fits in \a result without data loss. If the number is outside + * the valid range for the data type, this function returns the recoverable + * error CborErrorDataTooLarge. In that case, use either + * cbor_value_get_uint64() (if the number is positive) or + * cbor_value_get_raw_integer(). + * + * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_integer(), cbor_value_get_int64() + */ +CborError cbor_value_get_int64_checked(const CborValue *value, int64_t *result) +{ + uint64_t v; + cbor_assert(cbor_value_is_integer(value)); + v = _cbor_value_extract_int64_helper(value); + + /* Check before converting, as the standard says (C11 6.3.1.3 paragraph 3): + * "[if] the new type is signed and the value cannot be represented in it; either the + * result is implementation-defined or an implementation-defined signal is raised." + * + * The range for int64_t is -2^63 to 2^63-1 (int64_t is required to be + * two's complement, C11 7.20.1.1 paragraph 3), which in CBOR is + * represented the same way, differing only on the "sign bit" (the major + * type). + */ + + if (unlikely(v > (uint64_t)INT64_MAX)) + return CborErrorDataTooLarge; + + *result = v; + if (value->flags & CborIteratorFlag_NegativeInteger) + *result = -*result - 1; + return CborNoError; +} + +/** + * Retrieves the CBOR integer value that \a value points to and stores it in \a + * result. If the iterator \a value does not point to an integer value, the + * behavior is undefined, so checking with \ref cbor_value_get_type or with + * \ref cbor_value_is_integer is recommended. + * + * Unlike \ref cbor_value_get_int(), this function performs a check to see if the + * stored integer fits in \a result without data loss. If the number is outside + * the valid range for the data type, this function returns the recoverable + * error CborErrorDataTooLarge. In that case, use one of the other integer + * functions to obtain the value. + * + * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_integer(), cbor_value_get_int64(), + * cbor_value_get_uint64(), cbor_value_get_int64_checked(), cbor_value_get_raw_integer() + */ +CborError cbor_value_get_int_checked(const CborValue *value, int *result) +{ + uint64_t v; + cbor_assert(cbor_value_is_integer(value)); + v = _cbor_value_extract_int64_helper(value); + + /* Check before converting, as the standard says (C11 6.3.1.3 paragraph 3): + * "[if] the new type is signed and the value cannot be represented in it; either the + * result is implementation-defined or an implementation-defined signal is raised." + * + * But we can convert from signed to unsigned without fault (paragraph 2). + * + * The range for int is implementation-defined and int is not guaranteed to use + * two's complement representation (although int32_t is). + */ + + if (value->flags & CborIteratorFlag_NegativeInteger) { + if (unlikely(v > (unsigned) -(INT_MIN + 1))) + return CborErrorDataTooLarge; + + *result = (int)v; + *result = -*result - 1; + } else { + if (unlikely(v > (uint64_t)INT_MAX)) + return CborErrorDataTooLarge; + + *result = (int)v; + } + return CborNoError; + +} + +/** + * \fn bool cbor_value_is_length_known(const CborValue *value) + * + * Returns true if the length of this type is known without calculation. That + * is, if the length of this CBOR string, map or array is encoded in the data + * stream, this function returns true. If the length is not encoded, it returns + * false. + * + * If the length is known, code can call cbor_value_get_string_length(), + * cbor_value_get_array_length() or cbor_value_get_map_length() to obtain the + * length. If the length is not known but is necessary, code can use the + * cbor_value_calculate_string_length() function (no equivalent function is + * provided for maps and arrays). + */ + +/** + * \fn bool cbor_value_is_text_string(const CborValue *value) + * + * Returns true if the iterator \a value is valid and points to a CBOR text + * string. CBOR text strings are UTF-8 encoded and usually contain + * human-readable text. + * + * \sa cbor_value_is_valid(), cbor_value_get_string_length(), cbor_value_calculate_string_length(), + * cbor_value_copy_text_string(), cbor_value_dup_text_string() + */ + +/** + * \fn bool cbor_value_is_byte_string(const CborValue *value) + * + * Returns true if the iterator \a value is valid and points to a CBOR text + * string. CBOR byte strings are binary data with no specified encoding or + * format. + * + * \sa cbor_value_is_valid(), cbor_value_get_string_length(), cbor_value_calculate_string_length(), + * cbor_value_copy_byte_string(), cbor_value_dup_byte_string() + */ + +/** + * \fn CborError cbor_value_get_string_length(const CborValue *value, size_t *length) + * + * Extracts the length of the byte or text string that \a value points to and + * stores it in \a result. If the iterator \a value does not point to a text + * string or a byte string, the behaviour is undefined, so checking with \ref + * cbor_value_get_type, with \ref cbor_value_is_text_string or \ref + * cbor_value_is_byte_string is recommended. + * + * If the length of this string is not encoded in the CBOR data stream, this + * function will return the recoverable error CborErrorUnknownLength. You may + * also check whether that is the case by using cbor_value_is_length_known(). + * + * If the length of the string is required but the length was not encoded, use + * cbor_value_calculate_string_length(), but note that that function does not + * run in constant time. + * + * \note On 32-bit platforms, this function will return error condition of \ref + * CborErrorDataTooLarge if the stream indicates a length that is too big to + * fit in 32-bit. + * + * \sa cbor_value_is_valid(), cbor_value_is_length_known(), cbor_value_calculate_string_length() + */ + +/** + * Calculates the length of the byte or text string that \a value points to and + * stores it in \a len. If the iterator \a value does not point to a text + * string or a byte string, the behaviour is undefined, so checking with \ref + * cbor_value_get_type, with \ref cbor_value_is_text_string or \ref + * cbor_value_is_byte_string is recommended. + * + * This function is different from cbor_value_get_string_length() in that it + * calculates the length even for strings sent in chunks. For that reason, this + * function may not run in constant time (it will run in O(n) time on the + * number of chunks). It does use constant memory (O(1)). + * + * \note On 32-bit platforms, this function will return error condition of \ref + * CborErrorDataTooLarge if the stream indicates a length that is too big to + * fit in 32-bit. + * + * \sa cbor_value_get_string_length(), cbor_value_copy_text_string(), cbor_value_copy_byte_string(), cbor_value_is_length_known() + */ +CborError cbor_value_calculate_string_length(const CborValue *value, size_t *len) +{ + *len = SIZE_MAX; + return _cbor_value_copy_string(value, NULL, len, NULL); +} + +static inline void prepare_string_iteration(CborValue *it) +{ + if (!cbor_value_is_length_known(it)) { + /* chunked string: we're before the first chunk; + * advance to the first chunk */ + ++it->ptr; + it->flags |= CborIteratorFlag_IteratingStringChunks; + } +} + +CborError CBOR_INTERNAL_API_CC _cbor_value_prepare_string_iteration(CborValue *it) +{ + cbor_assert((it->flags & CborIteratorFlag_IteratingStringChunks) == 0); + prepare_string_iteration(it); + + /* are we at the end? */ + if (it->ptr == it->parser->end) + return CborErrorUnexpectedEOF; + return CborNoError; +} + +static CborError get_string_chunk(CborValue *it, const void **bufferptr, size_t *len) +{ + CborError err; + + /* Possible states: + * length known | iterating | meaning + * no | no | before the first chunk of a chunked string + * yes | no | at a non-chunked string + * no | yes | second or later chunk + * yes | yes | after a non-chunked string + */ + if (it->flags & CborIteratorFlag_IteratingStringChunks) { + /* already iterating */ + if (cbor_value_is_length_known(it)) { + /* if the length was known, it wasn't chunked, so finish iteration */ + goto last_chunk; + } + } else { + prepare_string_iteration(it); + } + + /* are we at the end? */ + if (it->ptr == it->parser->end) + return CborErrorUnexpectedEOF; + + if (*it->ptr == BreakByte) { + /* last chunk */ + ++it->ptr; +last_chunk: + *bufferptr = NULL; + *len = 0; + return preparse_next_value(it); + } else if ((uint8_t)(*it->ptr & MajorTypeMask) == it->type) { + err = extract_length(it->parser, &it->ptr, len); + if (err) + return err; + if (*len > (size_t)(it->parser->end - it->ptr)) + return CborErrorUnexpectedEOF; + + *bufferptr = it->ptr; + it->ptr += *len; + } else { + return CborErrorIllegalType; + } + + it->flags |= CborIteratorFlag_IteratingStringChunks; + return CborNoError; +} + +CborError CBOR_INTERNAL_API_CC +_cbor_value_get_string_chunk(const CborValue *value, const void **bufferptr, + size_t *len, CborValue *next) +{ + CborValue tmp; + if (!next) + next = &tmp; + *next = *value; + return get_string_chunk(next, bufferptr, len); +} + +/* We return uintptr_t so that we can pass memcpy directly as the iteration + * function. The choice is to optimize for memcpy, which is used in the base + * parser API (cbor_value_copy_string), while memcmp is used in convenience API + * only. */ +typedef uintptr_t (*IterateFunction)(char *, const uint8_t *, size_t); + +static uintptr_t iterate_noop(char *dest, const uint8_t *src, size_t len) +{ + (void)dest; + (void)src; + (void)len; + return true; +} + +static uintptr_t iterate_memcmp(char *s1, const uint8_t *s2, size_t len) +{ + return memcmp(s1, (const char *)s2, len) == 0; +} + +static uintptr_t iterate_memcpy(char *dest, const uint8_t *src, size_t len) +{ + return (uintptr_t)memcpy(dest, src, len); +} + +static CborError iterate_string_chunks(const CborValue *value, char *buffer, size_t *buflen, + bool *result, CborValue *next, IterateFunction func) +{ + CborError err; + CborValue tmp; + size_t total = 0; + const void *ptr; + + cbor_assert(cbor_value_is_byte_string(value) || cbor_value_is_text_string(value)); + if (!next) + next = &tmp; + *next = *value; + *result = true; + + while (1) { + size_t newTotal; + size_t chunkLen; + err = get_string_chunk(next, &ptr, &chunkLen); + if (err) + return err; + if (!ptr) + break; + + if (unlikely(add_check_overflow(total, chunkLen, &newTotal))) + return CborErrorDataTooLarge; + + if (*result && *buflen >= newTotal) + *result = !!func(buffer + total, (const uint8_t *)ptr, chunkLen); + else + *result = false; + + total = newTotal; + } + + /* is there enough room for the ending NUL byte? */ + if (*result && *buflen > total) { + uint8_t nul[] = { 0 }; + *result = !!func(buffer + total, nul, 1); + } + *buflen = total; + return CborNoError; +} + +/** + * \fn CborError cbor_value_copy_text_string(const CborValue *value, char *buffer, size_t *buflen, CborValue *next) + * + * Copies the string pointed to by \a value into the buffer provided at \a buffer + * of \a buflen bytes. If \a buffer is a NULL pointer, this function will not + * copy anything and will only update the \a next value. + * + * If the iterator \a value does not point to a text string, the behaviour is + * undefined, so checking with \ref cbor_value_get_type or \ref + * cbor_value_is_text_string is recommended. + * + * If the provided buffer length was too small, this function returns an error + * condition of \ref CborErrorOutOfMemory. If you need to calculate the length + * of the string in order to preallocate a buffer, use + * cbor_value_calculate_string_length(). + * + * On success, this function sets the number of bytes copied to \c{*buflen}. If + * the buffer is large enough, this function will insert a null byte after the + * last copied byte, to facilitate manipulation of text strings. That byte is + * not included in the returned value of \c{*buflen}. If there was no space for + * the terminating null, no error is returned, so callers must check the value + * of *buflen after the call, before relying on the '\0'; if it has not been + * changed by the call, there is no '\0'-termination on the buffer's contents. + * + * The \a next pointer, if not null, will be updated to point to the next item + * after this string. If \a value points to the last item, then \a next will be + * invalid. + * + * This function may not run in constant time (it will run in O(n) time on the + * number of chunks). It requires constant memory (O(1)). + * + * \note This function does not perform UTF-8 validation on the incoming text + * string. + * + * \sa cbor_value_get_text_string_chunk() cbor_value_dup_text_string(), cbor_value_copy_byte_string(), cbor_value_get_string_length(), cbor_value_calculate_string_length() + */ + +/** + * \fn CborError cbor_value_copy_byte_string(const CborValue *value, uint8_t *buffer, size_t *buflen, CborValue *next) + * + * Copies the string pointed by \a value into the buffer provided at \a buffer + * of \a buflen bytes. If \a buffer is a NULL pointer, this function will not + * copy anything and will only update the \a next value. + * + * If the iterator \a value does not point to a byte string, the behaviour is + * undefined, so checking with \ref cbor_value_get_type or \ref + * cbor_value_is_byte_string is recommended. + * + * If the provided buffer length was too small, this function returns an error + * condition of \ref CborErrorOutOfMemory. If you need to calculate the length + * of the string in order to preallocate a buffer, use + * cbor_value_calculate_string_length(). + * + * On success, this function sets the number of bytes copied to \c{*buflen}. If + * the buffer is large enough, this function will insert a null byte after the + * last copied byte, to facilitate manipulation of null-terminated strings. + * That byte is not included in the returned value of \c{*buflen}. + * + * The \a next pointer, if not null, will be updated to point to the next item + * after this string. If \a value points to the last item, then \a next will be + * invalid. + * + * This function may not run in constant time (it will run in O(n) time on the + * number of chunks). It requires constant memory (O(1)). + * + * \sa cbor_value_get_byte_string_chunk(), cbor_value_dup_text_string(), cbor_value_copy_text_string(), cbor_value_get_string_length(), cbor_value_calculate_string_length() + */ + +CborError _cbor_value_copy_string(const CborValue *value, void *buffer, + size_t *buflen, CborValue *next) +{ + bool copied_all; + CborError err = iterate_string_chunks(value, (char*)buffer, buflen, &copied_all, next, + buffer ? iterate_memcpy : iterate_noop); + return err ? err : + copied_all ? CborNoError : CborErrorOutOfMemory; +} + +/** + * Compares the entry \a value with the string \a string and stores the result + * in \a result. If the value is different from \a string \a result will + * contain \c false. + * + * The entry at \a value may be a tagged string. If \a value is not a string or + * a tagged string, the comparison result will be false. + * + * CBOR requires text strings to be encoded in UTF-8, but this function does + * not validate either the strings in the stream or the string \a string to be + * matched. Moreover, comparison is done on strict codepoint comparison, + * without any Unicode normalization. + * + * This function may not run in constant time (it will run in O(n) time on the + * number of chunks). It requires constant memory (O(1)). + * + * \sa cbor_value_skip_tag(), cbor_value_copy_text_string() + */ +CborError cbor_value_text_string_equals(const CborValue *value, const char *string, bool *result) +{ + size_t len; + CborValue copy = *value; + CborError err = cbor_value_skip_tag(©); + if (err) + return err; + if (!cbor_value_is_text_string(©)) { + *result = false; + return CborNoError; + } + + len = strlen(string); + return iterate_string_chunks(©, CONST_CAST(char *, string), &len, result, NULL, iterate_memcmp); +} + +/** + * \fn bool cbor_value_is_array(const CborValue *value) + * + * Returns true if the iterator \a value is valid and points to a CBOR array. + * + * \sa cbor_value_is_valid(), cbor_value_is_map() + */ + +/** + * \fn CborError cbor_value_get_array_length(const CborValue *value, size_t *length) + * + * Extracts the length of the CBOR array that \a value points to and stores it + * in \a result. If the iterator \a value does not point to a CBOR array, the + * behaviour is undefined, so checking with \ref cbor_value_get_type or \ref + * cbor_value_is_array is recommended. + * + * If the length of this array is not encoded in the CBOR data stream, this + * function will return the recoverable error CborErrorUnknownLength. You may + * also check whether that is the case by using cbor_value_is_length_known(). + * + * \note On 32-bit platforms, this function will return error condition of \ref + * CborErrorDataTooLarge if the stream indicates a length that is too big to + * fit in 32-bit. + * + * \sa cbor_value_is_valid(), cbor_value_is_length_known() + */ + +/** + * \fn bool cbor_value_is_map(const CborValue *value) + * + * Returns true if the iterator \a value is valid and points to a CBOR map. + * + * \sa cbor_value_is_valid(), cbor_value_is_array() + */ + +/** + * \fn CborError cbor_value_get_map_length(const CborValue *value, size_t *length) + * + * Extracts the length of the CBOR map that \a value points to and stores it in + * \a result. If the iterator \a value does not point to a CBOR map, the + * behaviour is undefined, so checking with \ref cbor_value_get_type or \ref + * cbor_value_is_map is recommended. + * + * If the length of this map is not encoded in the CBOR data stream, this + * function will return the recoverable error CborErrorUnknownLength. You may + * also check whether that is the case by using cbor_value_is_length_known(). + * + * \note On 32-bit platforms, this function will return error condition of \ref + * CborErrorDataTooLarge if the stream indicates a length that is too big to + * fit in 32-bit. + * + * \sa cbor_value_is_valid(), cbor_value_is_length_known() + */ + +/** + * Attempts to find the value in map \a map that corresponds to the text string + * entry \a string. If the iterator \a value does not point to a CBOR map, the + * behaviour is undefined, so checking with \ref cbor_value_get_type or \ref + * cbor_value_is_map is recommended. + * + * If the item is found, it is stored in \a result. If no item is found + * matching the key, then \a result will contain an element of type \ref + * CborInvalidType. Matching is performed using + * cbor_value_text_string_equals(), so tagged strings will also match. + * + * This function has a time complexity of O(n) where n is the number of + * elements in the map to be searched. In addition, this function is has O(n) + * memory requirement based on the number of nested containers (maps or arrays) + * found as elements of this map. + * + * \sa cbor_value_is_valid(), cbor_value_text_string_equals(), cbor_value_advance() + */ +CborError cbor_value_map_find_value(const CborValue *map, const char *string, CborValue *element) +{ + CborError err; + size_t len = strlen(string); + cbor_assert(cbor_value_is_map(map)); + err = cbor_value_enter_container(map, element); + if (err) + goto error; + + while (!cbor_value_at_end(element)) { + /* find the non-tag so we can compare */ + err = cbor_value_skip_tag(element); + if (err) + goto error; + if (cbor_value_is_text_string(element)) { + bool equals; + size_t dummyLen = len; + err = iterate_string_chunks(element, CONST_CAST(char *, string), &dummyLen, + &equals, element, iterate_memcmp); + if (err) + goto error; + if (equals) + return preparse_value(element); + } else { + /* skip this key */ + err = cbor_value_advance(element); + if (err) + goto error; + } + + /* skip this value */ + err = cbor_value_skip_tag(element); + if (err) + goto error; + err = cbor_value_advance(element); + if (err) + goto error; + } + + /* not found */ + element->type = CborInvalidType; + return CborNoError; + +error: + element->type = CborInvalidType; + return err; +} + +/** + * \fn bool cbor_value_is_float(const CborValue *value) + * + * Returns true if the iterator \a value is valid and points to a CBOR + * single-precision floating point (32-bit). + * + * \sa cbor_value_is_valid(), cbor_value_is_double(), cbor_value_is_half_float() + */ + +/** + * \fn CborError cbor_value_get_float(const CborValue *value, float *result) + * + * Retrieves the CBOR single-precision floating point (32-bit) value that \a + * value points to and stores it in \a result. If the iterator \a value does + * not point to a single-precision floating point value, the behavior is + * undefined, so checking with \ref cbor_value_get_type or with \ref + * cbor_value_is_float is recommended. + * + * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_float(), cbor_value_get_double() + */ + +/** + * \fn bool cbor_value_is_double(const CborValue *value) + * + * Returns true if the iterator \a value is valid and points to a CBOR + * double-precision floating point (64-bit). + * + * \sa cbor_value_is_valid(), cbor_value_is_float(), cbor_value_is_half_float() + */ + +/** + * \fn CborError cbor_value_get_double(const CborValue *value, float *result) + * + * Retrieves the CBOR double-precision floating point (64-bit) value that \a + * value points to and stores it in \a result. If the iterator \a value does + * not point to a double-precision floating point value, the behavior is + * undefined, so checking with \ref cbor_value_get_type or with \ref + * cbor_value_is_double is recommended. + * + * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_double(), cbor_value_get_float() + */ + +/** + * \fn bool cbor_value_is_half_float(const CborValue *value) + * + * Returns true if the iterator \a value is valid and points to a CBOR + * single-precision floating point (16-bit). + * + * \sa cbor_value_is_valid(), cbor_value_is_double(), cbor_value_is_float() + */ + +/** + * Retrieves the CBOR half-precision floating point (16-bit) value that \a + * value points to and stores it in \a result. If the iterator \a value does + * not point to a half-precision floating point value, the behavior is + * undefined, so checking with \ref cbor_value_get_type or with \ref + * cbor_value_is_half_float is recommended. + * + * Note: since the C language does not have a standard type for half-precision + * floating point, this function takes a \c{void *} as a parameter for the + * storage area, which must be at least 16 bits wide. + * + * \sa cbor_value_get_type(), cbor_value_is_valid(), cbor_value_is_half_float(), cbor_value_get_float() + */ +CborError cbor_value_get_half_float(const CborValue *value, void *result) +{ + uint16_t v; + cbor_assert(cbor_value_is_half_float(value)); + + /* size has been computed already */ + v = get16(value->ptr + 1); + memcpy(result, &v, sizeof(v)); + return CborNoError; +} + +/** @} */ diff --git a/client/tinycbor/cborparser_dup_string.c b/client/tinycbor/cborparser_dup_string.c new file mode 100644 index 00000000..061c5ac7 --- /dev/null +++ b/client/tinycbor/cborparser_dup_string.c @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Intel Corporation +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +** copies of the Software, and to permit persons to whom the Software is +** furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +** THE SOFTWARE. +** +****************************************************************************/ + +#ifndef _BSD_SOURCE +#define _BSD_SOURCE 1 +#endif +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE 1 +#endif +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS 1 +#endif + +#include "cbor.h" +#include "compilersupport_p.h" +#include + +/** + * \fn CborError cbor_value_dup_text_string(const CborValue *value, char **buffer, size_t *buflen, CborValue *next) + * + * Allocates memory for the string pointed by \a value and copies it into this + * buffer. The pointer to the buffer is stored in \a buffer and the number of + * bytes copied is stored in \a buflen (those variables must not be NULL). + * + * If the iterator \a value does not point to a text string, the behaviour is + * undefined, so checking with \ref cbor_value_get_type or \ref + * cbor_value_is_text_string is recommended. + * + * If \c malloc returns a NULL pointer, this function will return error + * condition \ref CborErrorOutOfMemory. + * + * On success, \c{*buffer} will contain a valid pointer that must be freed by + * calling \c{free()}. This is the case even for zero-length strings. + * + * The \a next pointer, if not null, will be updated to point to the next item + * after this string. If \a value points to the last item, then \a next will be + * invalid. + * + * This function may not run in constant time (it will run in O(n) time on the + * number of chunks). It requires constant memory (O(1)) in addition to the + * malloc'ed block. + * + * \note This function does not perform UTF-8 validation on the incoming text + * string. + * + * \sa cbor_value_get_text_string_chunk(), cbor_value_copy_text_string(), cbor_value_dup_byte_string() + */ + +/** + * \fn CborError cbor_value_dup_byte_string(const CborValue *value, uint8_t **buffer, size_t *buflen, CborValue *next) + * + * Allocates memory for the string pointed by \a value and copies it into this + * buffer. The pointer to the buffer is stored in \a buffer and the number of + * bytes copied is stored in \a buflen (those variables must not be NULL). + * + * If the iterator \a value does not point to a byte string, the behaviour is + * undefined, so checking with \ref cbor_value_get_type or \ref + * cbor_value_is_byte_string is recommended. + * + * If \c malloc returns a NULL pointer, this function will return error + * condition \ref CborErrorOutOfMemory. + * + * On success, \c{*buffer} will contain a valid pointer that must be freed by + * calling \c{free()}. This is the case even for zero-length strings. + * + * The \a next pointer, if not null, will be updated to point to the next item + * after this string. If \a value points to the last item, then \a next will be + * invalid. + * + * This function may not run in constant time (it will run in O(n) time on the + * number of chunks). It requires constant memory (O(1)) in addition to the + * malloc'ed block. + * + * \sa cbor_value_get_text_string_chunk(), cbor_value_copy_byte_string(), cbor_value_dup_text_string() + */ +CborError _cbor_value_dup_string(const CborValue *value, void **buffer, size_t *buflen, CborValue *next) +{ + CborError err; + cbor_assert(buffer); + cbor_assert(buflen); + *buflen = SIZE_MAX; + err = _cbor_value_copy_string(value, NULL, buflen, NULL); + if (err) + return err; + + ++*buflen; + *buffer = malloc(*buflen); + if (!*buffer) { + /* out of memory */ + return CborErrorOutOfMemory; + } + err = _cbor_value_copy_string(value, *buffer, buflen, next); + if (err) { + free(*buffer); + return err; + } + return CborNoError; +} diff --git a/client/tinycbor/cborpretty.c b/client/tinycbor/cborpretty.c new file mode 100644 index 00000000..b8825dee --- /dev/null +++ b/client/tinycbor/cborpretty.c @@ -0,0 +1,578 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Intel Corporation +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +** copies of the Software, and to permit persons to whom the Software is +** furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +** THE SOFTWARE. +** +****************************************************************************/ + +#define _BSD_SOURCE 1 +#define _DEFAULT_SOURCE 1 +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS 1 +#endif + +#include "cbor.h" +#include "cborinternal_p.h" +#include "compilersupport_p.h" +#include "utf8_p.h" + +#include +#include + +/** + * \defgroup CborPretty Converting CBOR to text + * \brief Group of functions used to convert CBOR to text form. + * + * This group contains two functions that can be used to convert a \ref + * CborValue object to a text representation. This module attempts to follow + * the recommendations from RFC 7049 section 6 "Diagnostic Notation", though it + * has a few differences. They are noted below. + * + * TinyCBOR does not provide a way to convert from the text representation back + * to encoded form. To produce a text form meant to be parsed, CborToJson is + * recommended instead. + * + * Either of the functions in this section will attempt to convert exactly one + * CborValue object to text. Those functions may return any error documented + * for the functions for CborParsing. In addition, if the C standard library + * stream functions return with error, the text conversion will return with + * error CborErrorIO. + * + * These functions also perform UTF-8 validation in CBOR text strings. If they + * encounter a sequence of bytes that is not permitted in UTF-8, they will return + * CborErrorInvalidUtf8TextString. That includes encoding of surrogate points + * in UTF-8. + * + * \warning The output type produced by these functions is not guaranteed to + * remain stable. A future update of TinyCBOR may produce different output for + * the same input and parsers may be unable to handle it. + * + * \sa CborParsing, CborToJson, cbor_parser_init() + */ + +/** + * \addtogroup CborPretty + * @{ + *

Text format

+ * + * As described in RFC 7049 section 6 "Diagnostic Notation", the format is + * largely borrowed from JSON, but modified to suit CBOR's different data + * types. TinyCBOR makes further modifications to distinguish different, but + * similar values. + * + * CBOR values are currently encoded as follows: + * \par Integrals (unsigned and negative) + * Base-10 (decimal) text representation of the value + * \par Byte strings: + * "h'" followed by the Base16 (hex) representation of the binary data, followed by an ending quote (') + * \par Text strings: + * C-style escaped string in quotes, with C11/C++11 escaping of Unicode codepoints above U+007F. + * \par Tags: + * Tag value, with the tagged value in parentheses. No special encoding of the tagged value is performed. + * \par Simple types: + * "simple(nn)" where \c nn is the simple value + * \par Null: + * \c null + * \par Undefined: + * \c undefined + * \par Booleans: + * \c true or \c false + * \par Floating point: + * If NaN or infinite, the actual words \c NaN or \c infinite. + * Otherwise, the decimal representation with as many digits as necessary to ensure no loss of information. + * By default, float values are suffixed by "f" and half-float values suffixed by "f16" (doubles have no suffix). + * If the CborPrettyNumericEncodingIndicators flag is active, the values instead are encoded following the + * Section 6 recommended encoding indicators: float values are suffixed with "_2" and half-float with "_1". + * A decimal point is always present. + * \par Arrays: + * Comma-separated list of elements, enclosed in square brackets ("[" and "]"). + * \par Maps: + * Comma-separated list of key-value pairs, with the key and value separated + * by a colon (":"), enclosed in curly braces ("{" and "}"). + * + * The CborPrettyFlags enumerator contains flags to control some aspects of the + * encoding: + * \par String fragmentation + * When the CborPrettyShowStringFragments option is active, text and byte + * strings that are transmitted in fragments are shown instead inside + * parentheses ("(" and ")") with no preceding number and each fragment is + * displayed individually. If a tag precedes the string, then the output + * will contain a double set of parentheses. If the option is not active, + * the fragments are merged together and the display will not show any + * difference from a string transmitted with determinate length. + * \par Encoding indicators + * Numbers and lengths in CBOR can be encoded in multiple representations. + * If the CborPrettyIndicateOverlongNumbers option is active, numbers + * and lengths that are transmitted in a longer encoding than necessary + * will be indicated, by appending an underscore ("_") to either the + * number or the opening bracket or brace, followed by a number + * indicating the CBOR additional information: 0 for 1 byte, 1 for 2 + * bytes, 2 for 4 bytes and 3 for 8 bytes. + * If the CborPrettyIndicateIndeterminateLength option is active, maps, + * arrays and strings encoded with indeterminate length will be marked by + * an underscore after the opening bracket or brace or the string (if not + * showing fragments), without a number after it. + */ + +/** + * \enum CborPrettyFlags + * The CborPrettyFlags enum contains flags that control the conversion of CBOR to text format. + * + * \value CborPrettyNumericEncodingIndicators Use numeric encoding indicators instead of textual for float and half-float. + * \value CborPrettyTextualEncodingIndicators Use textual encoding indicators for float ("f") and half-float ("f16"). + * \value CborPrettyIndicateIndeterminateLength (default) Indicate when a map or array has indeterminate length. + * \value CborPrettyIndicateOverlongNumbers Indicate when a number or length was encoded with more bytes than needed. + * \value CborPrettyShowStringFragments If the byte or text string is transmitted in chunks, show each individually. + * \value CborPrettyMergeStringFragment Merge all chunked byte or text strings and display them in a single entry. + * \value CborPrettyDefaultFlags Default conversion flags. + */ + +#ifndef CBOR_NO_FLOATING_POINT +static inline bool convertToUint64(double v, uint64_t *absolute) +{ + double supremum; + v = fabs(v); + + /* C11 standard section 6.3.1.4 "Real floating and integer" says: + * + * 1 When a finite value of real floating type is converted to an integer + * type other than _Bool, the fractional part is discarded (i.e., the + * value is truncated toward zero). If the value of the integral part + * cannot be represented by the integer type, the behavior is undefined. + * + * So we must perform a range check that v <= UINT64_MAX, but we can't use + * UINT64_MAX + 1.0 because the standard continues: + * + * 2 When a value of integer type is converted to a real floating type, if + * the value being converted can be represented exactly in the new type, + * it is unchanged. If the value being converted is in the range of + * values that can be represented but cannot be represented exactly, the + * result is either the nearest higher or nearest lower representable + * value, chosen in an implementation-defined manner. + */ + supremum = -2.0 * INT64_MIN; /* -2 * (- 2^63) == 2^64 */ + if (v >= supremum) + return false; + + /* Now we can convert, these two conversions cannot be UB */ + *absolute = v; + return *absolute == v; +} +#endif + +static void printRecursionLimit(CborStreamFunction stream, void *out) +{ + stream(out, ""); +} + +static CborError hexDump(CborStreamFunction stream, void *out, const void *ptr, size_t n) +{ + const uint8_t *buffer = (const uint8_t *)ptr; + CborError err = CborNoError; + while (n-- && !err) + err = stream(out, "%02" PRIx8, *buffer++); + + return err; +} + +/* This function decodes buffer as UTF-8 and prints as escaped UTF-16. + * On UTF-8 decoding error, it returns CborErrorInvalidUtf8TextString */ +static CborError utf8EscapedDump(CborStreamFunction stream, void *out, const void *ptr, size_t n) +{ + const uint8_t *buffer = (const uint8_t *)ptr; + const uint8_t * const end = buffer + n; + CborError err = CborNoError; + + while (buffer < end && !err) { + uint32_t uc = get_utf8(&buffer, end); + if (uc == ~0U) + return CborErrorInvalidUtf8TextString; + + if (uc < 0x80) { + /* single-byte UTF-8 */ + unsigned char escaped = (unsigned char)uc; + if (uc < 0x7f && uc >= 0x20 && uc != '\\' && uc != '"') { + err = stream(out, "%c", (char)uc); + continue; + } + + /* print as an escape sequence */ + switch (uc) { + case '"': + case '\\': + break; + case '\b': + escaped = 'b'; + break; + case '\f': + escaped = 'f'; + break; + case '\n': + escaped = 'n'; + break; + case '\r': + escaped = 'r'; + break; + case '\t': + escaped = 't'; + break; + default: + goto print_utf16; + } + err = stream(out, "\\%c", escaped); + continue; + } + + /* now print the sequence */ + if (uc > 0xffffU) { + /* needs surrogate pairs */ + err = stream(out, "\\u%04" PRIX32 "\\u%04" PRIX32, + (uc >> 10) + 0xd7c0, /* high surrogate */ + (uc % 0x0400) + 0xdc00); + } else { +print_utf16: + /* no surrogate pair needed */ + err = stream(out, "\\u%04" PRIX32, uc); + } + } + return err; +} + +static const char *resolve_indicator(const uint8_t *ptr, const uint8_t *end, int flags) +{ + static const char indicators[8][3] = { + "_0", "_1", "_2", "_3", + "", "", "", /* these are not possible */ + "_" + }; + const char *no_indicator = indicators[5]; /* empty string */ + uint8_t additional_information; + uint8_t expected_information; + uint64_t value; + CborError err; + + if (ptr == end) + return NULL; /* CborErrorUnexpectedEOF */ + + additional_information = (*ptr & SmallValueMask); + if (additional_information < Value8Bit) + return no_indicator; + + /* determine whether to show anything */ + if ((flags & CborPrettyIndicateIndeterminateLength) && + additional_information == IndefiniteLength) + return indicators[IndefiniteLength - Value8Bit]; + if ((flags & CborPrettyIndicateOverlongNumbers) == 0) + return no_indicator; + + err = _cbor_value_extract_number(&ptr, end, &value); + if (err) + return NULL; /* CborErrorUnexpectedEOF */ + + expected_information = Value8Bit - 1; + if (value >= Value8Bit) + ++expected_information; + if (value > 0xffU) + ++expected_information; + if (value > 0xffffU) + ++expected_information; + if (value > 0xffffffffU) + ++expected_information; + return expected_information == additional_information ? + no_indicator : + indicators[additional_information - Value8Bit]; +} + +static const char *get_indicator(const CborValue *it, int flags) +{ + return resolve_indicator(it->ptr, it->parser->end, flags); +} + +static CborError value_to_pretty(CborStreamFunction stream, void *out, CborValue *it, int flags, int recursionsLeft); +static CborError container_to_pretty(CborStreamFunction stream, void *out, CborValue *it, CborType containerType, + int flags, int recursionsLeft) +{ + const char *comma = ""; + CborError err = CborNoError; + + if (!recursionsLeft) { + printRecursionLimit(stream, out); + return err; /* do allow the dumping to continue */ + } + + while (!cbor_value_at_end(it) && !err) { + err = stream(out, "%s", comma); + comma = ", "; + + if (!err) + err = value_to_pretty(stream, out, it, flags, recursionsLeft); + + if (containerType == CborArrayType) + continue; + + /* map: that was the key, so get the value */ + if (!err) + err = stream(out, ": "); + if (!err) + err = value_to_pretty(stream, out, it, flags, recursionsLeft); + } + return err; +} + +static CborError value_to_pretty(CborStreamFunction stream, void *out, CborValue *it, int flags, int recursionsLeft) +{ + CborError err = CborNoError; + CborType type = cbor_value_get_type(it); + switch (type) { + case CborArrayType: + case CborMapType: { + /* recursive type */ + CborValue recursed; + const char *indicator = get_indicator(it, flags); + const char *space = *indicator ? " " : indicator; + + err = stream(out, "%c%s%s", type == CborArrayType ? '[' : '{', indicator, space); + if (err) + return err; + + err = cbor_value_enter_container(it, &recursed); + if (err) { + it->ptr = recursed.ptr; + return err; /* parse error */ + } + err = container_to_pretty(stream, out, &recursed, type, flags, recursionsLeft - 1); + if (err) { + it->ptr = recursed.ptr; + return err; /* parse error */ + } + err = cbor_value_leave_container(it, &recursed); + if (err) + return err; /* parse error */ + + return stream(out, type == CborArrayType ? "]" : "}"); + } + + case CborIntegerType: { + uint64_t val; + cbor_value_get_raw_integer(it, &val); /* can't fail */ + + if (cbor_value_is_unsigned_integer(it)) { + err = stream(out, "%" PRIu64, val); + } else { + /* CBOR stores the negative number X as -1 - X + * (that is, -1 is stored as 0, -2 as 1 and so forth) */ + if (++val) { /* unsigned overflow may happen */ + err = stream(out, "-%" PRIu64, val); + } else { + /* overflown + * 0xffff`ffff`ffff`ffff + 1 = + * 0x1`0000`0000`0000`0000 = 18446744073709551616 (2^64) */ + err = stream(out, "-18446744073709551616"); + } + } + if (!err) + err = stream(out, "%s", get_indicator(it, flags)); + break; + } + + case CborByteStringType: + case CborTextStringType: { + size_t n = 0; + const void *ptr; + bool showingFragments = (flags & CborPrettyShowStringFragments) && !cbor_value_is_length_known(it); + const char *separator = ""; + char close = '\''; + char open[3] = "h'"; + const char *indicator = NULL; + + if (type == CborTextStringType) { + close = open[0] = '"'; + open[1] = '\0'; + } + + if (showingFragments) { + err = stream(out, "(_ "); + if (!err) + err = _cbor_value_prepare_string_iteration(it); + } else { + err = stream(out, "%s", open); + } + + while (!err) { + if (showingFragments || indicator == NULL) { + /* any iteration, except the second for a non-chunked string */ + indicator = resolve_indicator(it->ptr, it->parser->end, flags); + } + + err = _cbor_value_get_string_chunk(it, &ptr, &n, it); + if (!ptr) + break; + + if (!err && showingFragments) + err = stream(out, "%s%s", separator, open); + if (!err) + err = (type == CborByteStringType ? + hexDump(stream, out, ptr, n) : + utf8EscapedDump(stream, out, ptr, n)); + if (!err && showingFragments) { + err = stream(out, "%c%s", close, indicator); + separator = ", "; + } + } + + if (!err) { + if (showingFragments) + err = stream(out, ")"); + else + err = stream(out, "%c%s", close, indicator); + } + return err; + } + + case CborTagType: { + CborTag tag; + cbor_value_get_tag(it, &tag); /* can't fail */ + err = stream(out, "%" PRIu64 "%s(", tag, get_indicator(it, flags)); + if (!err) + err = cbor_value_advance_fixed(it); + if (!err && recursionsLeft) + err = value_to_pretty(stream, out, it, flags, recursionsLeft - 1); + else if (!err) + printRecursionLimit(stream, out); + if (!err) + err = stream(out, ")"); + return err; + } + + case CborSimpleType: { + /* simple types can't fail and can't have overlong encoding */ + uint8_t simple_type; + cbor_value_get_simple_type(it, &simple_type); + err = stream(out, "simple(%" PRIu8 ")", simple_type); + break; + } + + case CborNullType: + err = stream(out, "null"); + break; + + case CborUndefinedType: + err = stream(out, "undefined"); + break; + + case CborBooleanType: { + bool val; + cbor_value_get_boolean(it, &val); /* can't fail */ + err = stream(out, val ? "true" : "false"); + break; + } + +#ifndef CBOR_NO_FLOATING_POINT + case CborDoubleType: { + const char *suffix; + double val; + int r; + uint64_t ival; + + if (false) { + float f; + case CborFloatType: + cbor_value_get_float(it, &f); + val = f; + suffix = flags & CborPrettyNumericEncodingIndicators ? "_2" : "f"; + } else if (false) { + uint16_t f16; + case CborHalfFloatType: +#ifndef CBOR_NO_HALF_FLOAT_TYPE + cbor_value_get_half_float(it, &f16); + val = decode_half(f16); + suffix = flags & CborPrettyNumericEncodingIndicators ? "_1" : "f16"; +#else + (void)f16; + err = CborErrorUnsupportedType; + break; +#endif + } else { + cbor_value_get_double(it, &val); + suffix = ""; + } + + if ((flags & CborPrettyNumericEncodingIndicators) == 0) { + r = fpclassify(val); + if (r == FP_NAN || r == FP_INFINITE) + suffix = ""; + } + + if (convertToUint64(val, &ival)) { + /* this double value fits in a 64-bit integer, so show it as such + * (followed by a floating point suffix, to disambiguate) */ + err = stream(out, "%s%" PRIu64 ".%s", val < 0 ? "-" : "", ival, suffix); + } else { + /* this number is definitely not a 64-bit integer */ + err = stream(out, "%." DBL_DECIMAL_DIG_STR "g%s", val, suffix); + } + break; + } +#else + case CborDoubleType: + case CborFloatType: + case CborHalfFloatType: + err = CborErrorUnsupportedType; + break; +#endif /* !CBOR_NO_FLOATING_POINT */ + + case CborInvalidType: + err = stream(out, "invalid"); + if (err) + return err; + return CborErrorUnknownType; + } + + if (!err) + err = cbor_value_advance_fixed(it); + return err; +} + +/** + * Converts the current CBOR type pointed by \a value to its textual + * representation and writes it to the stream by calling the \a streamFunction. + * If an error occurs, this function returns an error code similar to + * \ref CborParsing. + * + * The textual representation can be controlled by the \a flags parameter (see + * \ref CborPrettyFlags for more information). + * + * If no error ocurred, this function advances \a value to the next element. + * Often, concatenating the text representation of multiple elements can be + * done by appending a comma to the output stream in between calls to this + * function. + * + * The \a streamFunction function will be called with the \a token value as the + * first parameter and a printf-style format string as the second, with a variable + * number of further parameters. + * + * \sa cbor_value_to_pretty(), cbor_value_to_json_advance() + */ +CborError cbor_value_to_pretty_stream(CborStreamFunction streamFunction, void *token, CborValue *value, int flags) +{ + return value_to_pretty(streamFunction, token, value, flags, CBOR_PARSER_MAX_RECURSIONS); +} + +/** @} */ diff --git a/client/tinycbor/cborpretty_stdio.c b/client/tinycbor/cborpretty_stdio.c new file mode 100644 index 00000000..20131850 --- /dev/null +++ b/client/tinycbor/cborpretty_stdio.c @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Intel Corporation +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +** copies of the Software, and to permit persons to whom the Software is +** furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +** THE SOFTWARE. +** +****************************************************************************/ + +#include "cbor.h" +#include +#include + +static CborError cbor_fprintf(void *out, const char *fmt, ...) +{ + int n; + + va_list list; + va_start(list, fmt); + n = vfprintf((FILE *)out, fmt, list); + va_end(list); + + return n < 0 ? CborErrorIO : CborNoError; +} + +/** + * \fn CborError cbor_value_to_pretty(FILE *out, const CborValue *value) + * + * Converts the current CBOR type pointed to by \a value to its textual + * representation and writes it to the \a out stream. If an error occurs, this + * function returns an error code similar to CborParsing. + * + * \sa cbor_value_to_pretty_advance(), cbor_value_to_json_advance() + */ + +/** + * Converts the current CBOR type pointed to by \a value to its textual + * representation and writes it to the \a out stream. If an error occurs, this + * function returns an error code similar to CborParsing. + * + * If no error ocurred, this function advances \a value to the next element. + * Often, concatenating the text representation of multiple elements can be + * done by appending a comma to the output stream in between calls to this + * function. + * + * \sa cbor_value_to_pretty(), cbor_value_to_pretty_stream(), cbor_value_to_json_advance() + */ +CborError cbor_value_to_pretty_advance(FILE *out, CborValue *value) +{ + return cbor_value_to_pretty_stream(cbor_fprintf, out, value, CborPrettyDefaultFlags); +} + +/** + * Converts the current CBOR type pointed to by \a value to its textual + * representation and writes it to the \a out stream. If an error occurs, this + * function returns an error code similar to CborParsing. + * + * The textual representation can be controlled by the \a flags parameter (see + * CborPrettyFlags for more information). + * + * If no error ocurred, this function advances \a value to the next element. + * Often, concatenating the text representation of multiple elements can be + * done by appending a comma to the output stream in between calls to this + * function. + * + * \sa cbor_value_to_pretty_stream(), cbor_value_to_pretty(), cbor_value_to_json_advance() + */ +CborError cbor_value_to_pretty_advance_flags(FILE *out, CborValue *value, int flags) +{ + return cbor_value_to_pretty_stream(cbor_fprintf, out, value, flags); +} + diff --git a/client/tinycbor/cbortojson.c b/client/tinycbor/cbortojson.c new file mode 100644 index 00000000..5a1a2e5d --- /dev/null +++ b/client/tinycbor/cbortojson.c @@ -0,0 +1,699 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Intel Corporation +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +** copies of the Software, and to permit persons to whom the Software is +** furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +** THE SOFTWARE. +** +****************************************************************************/ + +#define _BSD_SOURCE 1 +#define _DEFAULT_SOURCE 1 +#define _GNU_SOURCE 1 +#define _POSIX_C_SOURCE 200809L +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS 1 +#endif + +#include "cbor.h" +#include "cborjson.h" +#include "cborinternal_p.h" +#include "compilersupport_p.h" + +#include +#include +#include +#include + +/** + * \defgroup CborToJson Converting CBOR to JSON + * \brief Group of functions used to convert CBOR to JSON. + * + * This group contains two functions that can be used to convert a \ref + * CborValue object to an equivalent JSON representation. This module attempts + * to follow the recommendations from RFC 7049 section 4.1 "Converting from + * CBOR to JSON", though it has a few differences. They are noted below. + * + * These functions produce a "minified" JSON output, with no spacing, + * indentation or line breaks. If those are necessary, they need to be applied + * in a post-processing phase. + * + * Note that JSON cannot support all CBOR types with fidelity, so the + * conversion is usually lossy. For that reason, TinyCBOR supports adding a set + * of metadata JSON values that can be used by a JSON-to-CBOR converter to + * restore the original data types. + * + * The TinyCBOR library does not provide a way to convert from JSON + * representation back to encoded form. However, it provides a tool called + * \c json2cbor which can be used for that purpose. That tool supports the + * metadata format that these functions may produce. + * + * Either of the functions in this section will attempt to convert exactly one + * CborValue object to JSON. Those functions may return any error documented + * for the functions for CborParsing. In addition, if the C standard library + * stream functions return with error, the text conversion will return with + * error CborErrorIO. + * + * These functions also perform UTF-8 validation in CBOR text strings. If they + * encounter a sequence of bytes that is not permitted in UTF-8, they will return + * CborErrorInvalidUtf8TextString. That includes encoding of surrogate points + * in UTF-8. + * + * \warning The metadata produced by these functions is not guaranteed to + * remain stable. A future update of TinyCBOR may produce different output for + * the same input and parsers may be unable to handle it. + * + * \sa CborParsing, CborPretty, cbor_parser_init() + */ + +/** + * \addtogroup CborToJson + * @{ + *

Conversion limitations

+ * + * When converting from CBOR to JSON, there may be information loss. This + * section lists the possible scenarios. + * + * \par Number precision: + * ALL JSON numbers, due to its JavaScript heritage, are IEEE 754 + * double-precision floating point. This means JSON is not capable of + * representing all integers numbers outside the range [-(253)+1, + * 253-1] and is not capable of representing NaN or infinite. If the + * CBOR data contains a number outside the valid range, the conversion will + * lose precision. If the input was NaN or infinite, the result of the + * conversion will be the JSON null value. In addition, the distinction between + * half-, single- and double-precision is lost. + * + * \par + * If enabled, the original value and original type are stored in the metadata. + * + * \par Non-native types: + * CBOR's type system is richer than JSON's, which means some data values + * cannot be represented when converted to JSON. The conversion silently turns + * them into strings: CBOR simple types become "simple(nn)" where \c nn is the + * simple type's value, with the exception of CBOR undefined, which becomes + * "undefined", while CBOR byte strings are converted to an Base16, Base64, or + * Base64url encoding + * + * \par + * If enabled, the original type is stored in the metadata. + * + * \par Presence of tags: + * JSON has no support for tagged values, so by default tags are dropped when + * converting to JSON. However, if the CborConvertObeyByteStringTags option is + * active (default), then certain known tags are honored and are used to format + * the conversion of the tagged byte string to JSON. + * + * \par + * If the CborConvertTagsToObjects option is active, then the tag and the + * tagged value are converted to a JSON object. Otherwise, if enabled, the + * last (innermost) tag is stored in the metadata. + * + * \par Non-string keys in maps: + * JSON requires all Object keys to be strings, while CBOR does not. By + * default, if a non-string key is found, the conversion fails with error + * CborErrorJsonObjectKeyNotString. If the CborConvertStringifyMapKeys option + * is active, then the conversion attempts to create a string representation + * using CborPretty. Note that the \c json2cbor tool is not able to parse this + * back to the original form. + * + * \par Duplicate keys in maps: + * Neither JSON nor CBOR allow duplicated keys, but current TinyCBOR does not + * validate that this is the case. If there are duplicated keys in the input, + * they will be repeated in the output, which many JSON tools may flag as + * invalid. In addition to that, if the CborConvertStringifyMapKeys option is + * active, it is possible that a non-string key in a CBOR map will be converted + * to a string form that is identical to another key. + * + * \par + * When metadata support is active, the conversion will add extra key-value + * pairs to the JSON output so it can store the metadata. It is possible that + * the keys for the metadata clash with existing keys in the JSON map. + */ + +extern FILE *open_memstream(char **bufptr, size_t *sizeptr); + +enum ConversionStatusFlags { + TypeWasNotNative = 0x100, /* anything but strings, boolean, null, arrays and maps */ + TypeWasTagged = 0x200, + NumberPrecisionWasLost = 0x400, + NumberWasNaN = 0x800, + NumberWasInfinite = 0x1000, + NumberWasNegative = 0x2000, /* only used with NumberWasInifite or NumberWasTooBig */ + + FinalTypeMask = 0xff +}; + +typedef struct ConversionStatus { + CborTag lastTag; + uint64_t originalNumber; + int flags; +} ConversionStatus; + +static CborError value_to_json(FILE *out, CborValue *it, int flags, CborType type, ConversionStatus *status); + +static CborError dump_bytestring_base16(char **result, CborValue *it) +{ + static const char characters[] = "0123456789abcdef"; + size_t i; + size_t n = 0; + uint8_t *buffer; + CborError err = cbor_value_calculate_string_length(it, &n); + if (err) + return err; + + /* a Base16 (hex) output is twice as big as our buffer */ + buffer = (uint8_t *)malloc(n * 2 + 1); + *result = (char *)buffer; + + /* let cbor_value_copy_byte_string know we have an extra byte for the terminating NUL */ + ++n; + err = cbor_value_copy_byte_string(it, buffer + n - 1, &n, it); + cbor_assert(err == CborNoError); + + for (i = 0; i < n; ++i) { + uint8_t byte = buffer[n + i]; + buffer[2*i] = characters[byte >> 4]; + buffer[2*i + 1] = characters[byte & 0xf]; + } + return CborNoError; +} + +static CborError generic_dump_base64(char **result, CborValue *it, const char alphabet[65]) +{ + size_t n = 0, i; + uint8_t *buffer, *out, *in; + CborError err = cbor_value_calculate_string_length(it, &n); + if (err) + return err; + + /* a Base64 output (untruncated) has 4 bytes for every 3 in the input */ + size_t len = (n + 5) / 3 * 4; + out = buffer = (uint8_t *)malloc(len + 1); + *result = (char *)buffer; + + /* we read our byte string at the tail end of the buffer + * so we can do an in-place conversion while iterating forwards */ + in = buffer + len - n; + + /* let cbor_value_copy_byte_string know we have an extra byte for the terminating NUL */ + ++n; + err = cbor_value_copy_byte_string(it, in, &n, it); + cbor_assert(err == CborNoError); + + uint_least32_t val = 0; + for (i = 0; n - i >= 3; i += 3) { + /* read 3 bytes x 8 bits = 24 bits */ + if (false) { +#ifdef __GNUC__ + } else if (i) { + __builtin_memcpy(&val, in + i - 1, sizeof(val)); + val = cbor_ntohl(val); +#endif + } else { + val = (in[i] << 16) | (in[i + 1] << 8) | in[i + 2]; + } + + /* write 4 chars x 6 bits = 24 bits */ + *out++ = alphabet[(val >> 18) & 0x3f]; + *out++ = alphabet[(val >> 12) & 0x3f]; + *out++ = alphabet[(val >> 6) & 0x3f]; + *out++ = alphabet[val & 0x3f]; + } + + /* maybe 1 or 2 bytes left */ + if (n - i) { + /* we can read in[i + 1] even if it's past the end of the string because + * we know (by construction) that it's a NUL byte */ +#ifdef __GNUC__ + uint16_t val16; + __builtin_memcpy(&val16, in + i, sizeof(val16)); + val = cbor_ntohs(val16); +#else + val = (in[i] << 8) | in[i + 1]; +#endif + val <<= 8; + + /* the 65th character in the alphabet is our filler: either '=' or '\0' */ + out[4] = '\0'; + out[3] = alphabet[64]; + if (n - i == 2) { + /* write the third char in 3 chars x 6 bits = 18 bits */ + out[2] = alphabet[(val >> 6) & 0x3f]; + } else { + out[2] = alphabet[64]; /* filler */ + } + out[1] = alphabet[(val >> 12) & 0x3f]; + out[0] = alphabet[(val >> 18) & 0x3f]; + } else { + out[0] = '\0'; + } + + return CborNoError; +} + +static CborError dump_bytestring_base64(char **result, CborValue *it) +{ + static const char alphabet[] = "ABCDEFGH" "IJKLMNOP" "QRSTUVWX" "YZabcdef" + "ghijklmn" "opqrstuv" "wxyz0123" "456789+/" "="; + return generic_dump_base64(result, it, alphabet); +} + +static CborError dump_bytestring_base64url(char **result, CborValue *it) +{ + static const char alphabet[] = "ABCDEFGH" "IJKLMNOP" "QRSTUVWX" "YZabcdef" + "ghijklmn" "opqrstuv" "wxyz0123" "456789-_"; + return generic_dump_base64(result, it, alphabet); +} + +static CborError add_value_metadata(FILE *out, CborType type, const ConversionStatus *status) +{ + int flags = status->flags; + if (flags & TypeWasTagged) { + /* extract the tagged type, which may be JSON native */ + type = flags & FinalTypeMask; + flags &= ~(FinalTypeMask | TypeWasTagged); + + if (fprintf(out, "\"tag\":\"%" PRIu64 "\"%s", status->lastTag, + flags & ~TypeWasTagged ? "," : "") < 0) + return CborErrorIO; + } + + if (!flags) + return CborNoError; + + /* print at least the type */ + if (fprintf(out, "\"t\":%d", type) < 0) + return CborErrorIO; + + if (flags & NumberWasNaN) + if (fprintf(out, ",\"v\":\"nan\"") < 0) + return CborErrorIO; + if (flags & NumberWasInfinite) + if (fprintf(out, ",\"v\":\"%sinf\"", flags & NumberWasNegative ? "-" : "") < 0) + return CborErrorIO; + if (flags & NumberPrecisionWasLost) + if (fprintf(out, ",\"v\":\"%c%" PRIx64 "\"", flags & NumberWasNegative ? '-' : '+', + status->originalNumber) < 0) + return CborErrorIO; + if (type == CborSimpleType) + if (fprintf(out, ",\"v\":%d", (int)status->originalNumber) < 0) + return CborErrorIO; + return CborNoError; +} + +static CborError find_tagged_type(CborValue *it, CborTag *tag, CborType *type) +{ + CborError err = CborNoError; + *type = cbor_value_get_type(it); + while (*type == CborTagType) { + cbor_value_get_tag(it, tag); /* can't fail */ + err = cbor_value_advance_fixed(it); + if (err) + return err; + + *type = cbor_value_get_type(it); + } + return err; +} + +static CborError tagged_value_to_json(FILE *out, CborValue *it, int flags, ConversionStatus *status) +{ + CborTag tag; + CborError err; + + if (flags & CborConvertTagsToObjects) { + cbor_value_get_tag(it, &tag); /* can't fail */ + err = cbor_value_advance_fixed(it); + if (err) + return err; + + if (fprintf(out, "{\"tag%" PRIu64 "\":", tag) < 0) + return CborErrorIO; + + CborType type = cbor_value_get_type(it); + err = value_to_json(out, it, flags, type, status); + if (err) + return err; + if (flags & CborConvertAddMetadata && status->flags) { + if (fprintf(out, ",\"tag%" PRIu64 "$cbor\":{", tag) < 0 || + add_value_metadata(out, type, status) != CborNoError || + fputc('}', out) < 0) + return CborErrorIO; + } + if (fputc('}', out) < 0) + return CborErrorIO; + status->flags = TypeWasNotNative | CborTagType; + return CborNoError; + } + + CborType type; + err = find_tagged_type(it, &status->lastTag, &type); + if (err) + return err; + tag = status->lastTag; + + /* special handling of byte strings? */ + if (type == CborByteStringType && (flags & CborConvertByteStringsToBase64Url) == 0 && + (tag == CborNegativeBignumTag || tag == CborExpectedBase16Tag || tag == CborExpectedBase64Tag)) { + char *str; + char *pre = ""; + + if (tag == CborNegativeBignumTag) { + pre = "~"; + err = dump_bytestring_base64url(&str, it); + } else if (tag == CborExpectedBase64Tag) { + err = dump_bytestring_base64(&str, it); + } else { /* tag == CborExpectedBase16Tag */ + err = dump_bytestring_base16(&str, it); + } + if (err) + return err; + err = fprintf(out, "\"%s%s\"", pre, str) < 0 ? CborErrorIO : CborNoError; + free(str); + status->flags = TypeWasNotNative | TypeWasTagged | CborByteStringType; + return err; + } + + /* no special handling */ + err = value_to_json(out, it, flags, type, status); + status->flags |= TypeWasTagged | type; + return err; +} + +static CborError stringify_map_key(char **key, CborValue *it, int flags, CborType type) +{ + (void)flags; /* unused */ + (void)type; /* unused */ +#ifdef WITHOUT_OPEN_MEMSTREAM + (void)key; /* unused */ + (void)it; /* unused */ + return CborErrorJsonNotImplemented; +#else + size_t size; + + FILE *memstream = open_memstream(key, &size); + if (memstream == NULL) + return CborErrorOutOfMemory; /* could also be EMFILE, but it's unlikely */ + CborError err = cbor_value_to_pretty_advance(memstream, it); + + if (unlikely(fclose(memstream) < 0 || *key == NULL)) + return CborErrorInternalError; + return err; +#endif +} + +static CborError array_to_json(FILE *out, CborValue *it, int flags, ConversionStatus *status) +{ + const char *comma = ""; + while (!cbor_value_at_end(it)) { + if (fprintf(out, "%s", comma) < 0) + return CborErrorIO; + comma = ","; + + CborError err = value_to_json(out, it, flags, cbor_value_get_type(it), status); + if (err) + return err; + } + return CborNoError; +} + +static CborError map_to_json(FILE *out, CborValue *it, int flags, ConversionStatus *status) +{ + const char *comma = ""; + CborError err; + while (!cbor_value_at_end(it)) { + char *key; + if (fprintf(out, "%s", comma) < 0) + return CborErrorIO; + comma = ","; + + CborType keyType = cbor_value_get_type(it); + if (likely(keyType == CborTextStringType)) { + size_t n = 0; + err = cbor_value_dup_text_string(it, &key, &n, it); + } else if (flags & CborConvertStringifyMapKeys) { + err = stringify_map_key(&key, it, flags, keyType); + } else { + return CborErrorJsonObjectKeyNotString; + } + if (err) + return err; + + /* first, print the key */ + if (fprintf(out, "\"%s\":", key) < 0) { + free(key); + return CborErrorIO; + } + + /* then, print the value */ + CborType valueType = cbor_value_get_type(it); + err = value_to_json(out, it, flags, valueType, status); + + /* finally, print any metadata we may have */ + if (flags & CborConvertAddMetadata) { + if (!err && keyType != CborTextStringType) { + if (fprintf(out, ",\"%s$keycbordump\":true", key) < 0) + err = CborErrorIO; + } + if (!err && status->flags) { + if (fprintf(out, ",\"%s$cbor\":{", key) < 0 || + add_value_metadata(out, valueType, status) != CborNoError || + fputc('}', out) < 0) + err = CborErrorIO; + } + } + + free(key); + if (err) + return err; + } + return CborNoError; +} + +static CborError value_to_json(FILE *out, CborValue *it, int flags, CborType type, ConversionStatus *status) +{ + CborError err; + status->flags = 0; + + switch (type) { + case CborArrayType: + case CborMapType: { + /* recursive type */ + CborValue recursed; + err = cbor_value_enter_container(it, &recursed); + if (err) { + it->ptr = recursed.ptr; + return err; /* parse error */ + } + if (fputc(type == CborArrayType ? '[' : '{', out) < 0) + return CborErrorIO; + + err = (type == CborArrayType) ? + array_to_json(out, &recursed, flags, status) : + map_to_json(out, &recursed, flags, status); + if (err) { + it->ptr = recursed.ptr; + return err; /* parse error */ + } + + if (fputc(type == CborArrayType ? ']' : '}', out) < 0) + return CborErrorIO; + err = cbor_value_leave_container(it, &recursed); + if (err) + return err; /* parse error */ + + status->flags = 0; /* reset, there are never conversion errors for us */ + return CborNoError; + } + + case CborIntegerType: { + double num; /* JS numbers are IEEE double precision */ + uint64_t val; + cbor_value_get_raw_integer(it, &val); /* can't fail */ + num = (double)val; + + if (cbor_value_is_negative_integer(it)) { + num = -num - 1; /* convert to negative */ + if ((uint64_t)(-num - 1) != val) { + status->flags = NumberPrecisionWasLost | NumberWasNegative; + status->originalNumber = val; + } + } else { + if ((uint64_t)num != val) { + status->flags = NumberPrecisionWasLost; + status->originalNumber = val; + } + } + if (fprintf(out, "%.0f", num) < 0) /* this number has no fraction, so no decimal points please */ + return CborErrorIO; + break; + } + + case CborByteStringType: + case CborTextStringType: { + char *str; + if (type == CborByteStringType) { + err = dump_bytestring_base64url(&str, it); + status->flags = TypeWasNotNative; + } else { + size_t n = 0; + err = cbor_value_dup_text_string(it, &str, &n, it); + } + if (err) + return err; + err = (fprintf(out, "\"%s\"", str) < 0) ? CborErrorIO : CborNoError; + free(str); + return err; + } + + case CborTagType: + return tagged_value_to_json(out, it, flags, status); + + case CborSimpleType: { + uint8_t simple_type; + cbor_value_get_simple_type(it, &simple_type); /* can't fail */ + status->flags = TypeWasNotNative; + status->originalNumber = simple_type; + if (fprintf(out, "\"simple(%" PRIu8 ")\"", simple_type) < 0) + return CborErrorIO; + break; + } + + case CborNullType: + if (fprintf(out, "null") < 0) + return CborErrorIO; + break; + + case CborUndefinedType: + status->flags = TypeWasNotNative; + if (fprintf(out, "\"undefined\"") < 0) + return CborErrorIO; + break; + + case CborBooleanType: { + bool val; + cbor_value_get_boolean(it, &val); /* can't fail */ + if (fprintf(out, val ? "true" : "false") < 0) + return CborErrorIO; + break; + } + +#ifndef CBOR_NO_FLOATING_POINT + case CborDoubleType: { + double val; + if (false) { + float f; + case CborFloatType: + status->flags = TypeWasNotNative; + cbor_value_get_float(it, &f); + val = f; + } else if (false) { + uint16_t f16; + case CborHalfFloatType: +# ifndef CBOR_NO_HALF_FLOAT_TYPE + status->flags = TypeWasNotNative; + cbor_value_get_half_float(it, &f16); + val = decode_half(f16); +# else + (void)f16; + err = CborErrorUnsupportedType; + break; +# endif + } else { + cbor_value_get_double(it, &val); + } + + int r = fpclassify(val); + if (r == FP_NAN || r == FP_INFINITE) { + if (fprintf(out, "null") < 0) + return CborErrorIO; + status->flags |= r == FP_NAN ? NumberWasNaN : + NumberWasInfinite | (val < 0 ? NumberWasNegative : 0); + } else { + uint64_t ival = (uint64_t)fabs(val); + if ((double)ival == fabs(val)) { + /* print as integer so we get the full precision */ + r = fprintf(out, "%s%" PRIu64, val < 0 ? "-" : "", ival); + status->flags |= TypeWasNotNative; /* mark this integer number as a double */ + } else { + /* this number is definitely not a 64-bit integer */ + r = fprintf(out, "%." DBL_DECIMAL_DIG_STR "g", val); + } + if (r < 0) + return CborErrorIO; + } + break; + } +#else + case CborDoubleType: + case CborFloatType: + case CborHalfFloatType: + err = CborErrorUnsupportedType; + break; +#endif /* !CBOR_NO_FLOATING_POINT */ + + case CborInvalidType: + return CborErrorUnknownType; + } + + return cbor_value_advance_fixed(it); +} + +/** + * \enum CborToJsonFlags + * The CborToJsonFlags enum contains flags that control the conversion of CBOR to JSON. + * + * \value CborConvertAddMetadata Adds metadata to facilitate restoration of the original CBOR data. + * \value CborConvertTagsToObjects Converts CBOR tags to JSON objects + * \value CborConvertIgnoreTags (default) Ignore CBOR tags, except for byte strings + * \value CborConvertObeyByteStringTags (default) Honor formatting of CBOR byte strings if so tagged + * \value CborConvertByteStringsToBase64Url Force the conversion of all CBOR byte strings to Base64url encoding, despite any tags + * \value CborConvertRequireMapStringKeys (default) Require CBOR map keys to be strings, failing the conversion if they are not + * \value CborConvertStringifyMapKeys Convert non-string keys in CBOR maps to a string form + * \value CborConvertDefaultFlags Default conversion flags. + */ + +/** + * \fn CborError cbor_value_to_json(FILE *out, const CborValue *value, int flags) + * + * Converts the current CBOR type pointed to by \a value to JSON and writes that + * to the \a out stream. If an error occurs, this function returns an error + * code similar to CborParsing. The \a flags parameter indicates one or more of + * the flags from CborToJsonFlags that control the conversion. + * + * \sa cbor_value_to_json_advance(), cbor_value_to_pretty() + */ + +/** + * Converts the current CBOR type pointed to by \a value to JSON and writes that + * to the \a out stream. If an error occurs, this function returns an error + * code similar to CborParsing. The \a flags parameter indicates one or more of + * the flags from CborToJsonFlags that control the conversion. + * + * If no error ocurred, this function advances \a value to the next element. + * + * \sa cbor_value_to_json(), cbor_value_to_pretty_advance() + */ +CborError cbor_value_to_json_advance(FILE *out, CborValue *value, int flags) +{ + ConversionStatus status; + return value_to_json(out, value, flags, cbor_value_get_type(value), &status); +} + +/** @} */ diff --git a/client/tinycbor/cborvalidation.c b/client/tinycbor/cborvalidation.c new file mode 100644 index 00000000..08c35117 --- /dev/null +++ b/client/tinycbor/cborvalidation.c @@ -0,0 +1,666 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Intel Corporation +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +** copies of the Software, and to permit persons to whom the Software is +** furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +** THE SOFTWARE. +** +****************************************************************************/ + +#define _BSD_SOURCE 1 +#define _DEFAULT_SOURCE 1 +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS 1 +#endif + +#include "cbor.h" +#include "cborinternal_p.h" +#include "compilersupport_p.h" +#include "utf8_p.h" + +#include + +#ifndef CBOR_NO_FLOATING_POINT +# include +# include +#endif + + +#ifndef CBOR_PARSER_MAX_RECURSIONS +# define CBOR_PARSER_MAX_RECURSIONS 1024 +#endif + +/** + * \addtogroup CborParsing + * @{ + */ + +/** + * \enum CborValidationFlags + * The CborValidationFlags enum contains flags that control the validation of a + * CBOR stream. + * + * \value CborValidateBasic Validates only the syntactic correctedness of the stream. + * \value CborValidateCanonical Validates that the stream is in canonical format, according to + * RFC 7049 section 3.9. + * \value CborValidateStrictMode Performs strict validation, according to RFC 7049 section 3.10. + * \value CborValidateStrictest Attempt to perform the strictest validation we know of. + * + * \value CborValidateShortestIntegrals (Canonical) Validate that integral numbers and lengths are + * enconded in their shortest form possible. + * \value CborValidateShortestFloatingPoint (Canonical) Validate that floating-point numbers are encoded + * in their shortest form possible. + * \value CborValidateShortestNumbers (Canonical) Validate both integral and floating-point numbers + * are in their shortest form possible. + * \value CborValidateNoIndeterminateLength (Canonical) Validate that no string, array or map uses + * indeterminate length encoding. + * \value CborValidateMapIsSorted (Canonical & Strict mode) Validate that map keys appear in + * sorted order. + * \value CborValidateMapKeysAreUnique (Strict mode) Validate that map keys are unique. + * \value CborValidateTagUse (Strict mode) Validate that known tags are used with the + * correct types. This does not validate that the content of + * those types is syntactically correct. For example, this + * option validates that tag 1 (DateTimeString) is used with + * a Text String, but it does not validate that the string is + * a valid date/time representation. + * \value CborValidateUtf8 (Strict mode) Validate that text strings are appropriately + * encoded in UTF-8. + * \value CborValidateMapKeysAreString Validate that all map keys are text strings. + * \value CborValidateNoUndefined Validate that no elements of type "undefined" are present. + * \value CborValidateNoTags Validate that no tags are used. + * \value CborValidateFiniteFloatingPoint Validate that all floating point numbers are finite (no NaN or + * infinities are allowed). + * \value CborValidateCompleteData Validate that the stream is complete and there is no more data + * in the buffer. + * \value CborValidateNoUnknownSimpleTypesSA Validate that all Standards Action simple types are registered + * with IANA. + * \value CborValidateNoUnknownSimpleTypes Validate that all simple types used are registered with IANA. + * \value CborValidateNoUnknownTagsSA Validate that all Standard Actions tags are registered with IANA. + * \value CborValidateNoUnknownTagsSR Validate that all Standard Actions and Specification Required tags + * are registered with IANA (see below for limitations). + * \value CborValidateNoUnkonwnTags Validate that all tags are registered with IANA + * (see below for limitations). + * + * \par Simple type registry + * The CBOR specification requires that registration for use of the first 19 + * simple types must be done by way of Standards Action. The rest of the simple + * types only require a specification. The official list can be obtained from + * https://www.iana.org/assignments/cbor-simple-values/cbor-simple-values.xhtml. + * + * \par + * There are no registered simple types recognized by this release of TinyCBOR + * (beyond those defined by RFC 7049). + * + * \par Tag registry + * The CBOR specification requires that registration for use of the first 23 + * tags must be done by way of Standards Action. The next up to tag 255 only + * require a specification. Finally, all other tags can be registered on a + * first-come-first-serve basis. The official list can be ontained from + * https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml. + * + * \par + * Given the variability of this list, TinyCBOR cannot recognize all tags + * registered with IANA. Instead, the implementation only recognizes tags + * that are backed by an RFC. + * + * \par + * These are the tags known to the current TinyCBOR release: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TagData ItemSemantics
0UTF-8 text stringStandard date/time string
1integerEpoch-based date/time
2byte stringPositive bignum
3byte stringNegative bignum
4arrayDecimal fraction
5arrayBigfloat
16arrayCOSE Single Recipient Encrypted Data Object (RFC 8152)
17arrayCOSE Mac w/o Recipients Object (RFC 8152)
18arrayCOSE Single Signer Data Object (RFC 8162)
21byte string, array, mapExpected conversion to base64url encoding
22byte string, array, mapExpected conversion to base64 encoding
23byte string, array, mapExpected conversion to base16 encoding
24byte stringEncoded CBOR data item
32UTF-8 text stringURI
33UTF-8 text stringbase64url
34UTF-8 text stringbase64
35UTF-8 text stringRegular expression
36UTF-8 text stringMIME message
96arrayCOSE Encrypted Data Object (RFC 8152)
97arrayCOSE MACed Data Object (RFC 8152)
98arrayCOSE Signed Data Object (RFC 8152)
55799anySelf-describe CBOR
+ */ + +struct KnownTagData { uint32_t tag; uint32_t types; }; +static const struct KnownTagData knownTagData[] = { + { 0, (uint32_t)CborTextStringType }, + { 1, (uint32_t)(CborIntegerType+1) }, + { 2, (uint32_t)CborByteStringType }, + { 3, (uint32_t)CborByteStringType }, + { 4, (uint32_t)CborArrayType }, + { 5, (uint32_t)CborArrayType }, + { 16, (uint32_t)CborArrayType }, + { 17, (uint32_t)CborArrayType }, + { 18, (uint32_t)CborArrayType }, + { 21, (uint32_t)CborByteStringType | ((uint32_t)CborArrayType << 8) | ((uint32_t)CborMapType << 16) }, + { 22, (uint32_t)CborByteStringType | ((uint32_t)CborArrayType << 8) | ((uint32_t)CborMapType << 16) }, + { 23, (uint32_t)CborByteStringType | ((uint32_t)CborArrayType << 8) | ((uint32_t)CborMapType << 16) }, + { 24, (uint32_t)CborByteStringType }, + { 32, (uint32_t)CborTextStringType }, + { 33, (uint32_t)CborTextStringType }, + { 34, (uint32_t)CborTextStringType }, + { 35, (uint32_t)CborTextStringType }, + { 36, (uint32_t)CborTextStringType }, + { 96, (uint32_t)CborArrayType }, + { 97, (uint32_t)CborArrayType }, + { 98, (uint32_t)CborArrayType }, + { 55799, 0U } +}; + +static CborError validate_value(CborValue *it, uint32_t flags, int recursionLeft); + +static inline CborError validate_utf8_string(const void *ptr, size_t n) +{ + const uint8_t *buffer = (const uint8_t *)ptr; + const uint8_t * const end = buffer + n; + while (buffer < end) { + uint32_t uc = get_utf8(&buffer, end); + if (uc == ~0U) + return CborErrorInvalidUtf8TextString; + } + return CborNoError; +} + +static inline CborError validate_simple_type(uint8_t simple_type, uint32_t flags) +{ + /* At current time, all known simple types are those from RFC 7049, + * which are parsed by the parser into different CBOR types. + * That means that if we've got here, the type is unknown */ + if (simple_type < 32) + return (flags & CborValidateNoUnknownSimpleTypesSA) ? CborErrorUnknownSimpleType : CborNoError; + return (flags & CborValidateNoUnknownSimpleTypes) == CborValidateNoUnknownSimpleTypes ? + CborErrorUnknownSimpleType : CborNoError; +} + +static inline CborError validate_number(const CborValue *it, CborType type, uint32_t flags) +{ + CborError err = CborNoError; + const uint8_t *ptr = it->ptr; + size_t bytesUsed, bytesNeeded; + uint64_t value; + + if ((flags & CborValidateShortestIntegrals) == 0) + return err; + if (type >= CborHalfFloatType && type <= CborDoubleType) + return err; /* checked elsewhere */ + + err = _cbor_value_extract_number(&ptr, it->parser->end, &value); + if (err) + return err; + + bytesUsed = (size_t)(ptr - it->ptr - 1); + bytesNeeded = 0; + if (value >= Value8Bit) + ++bytesNeeded; + if (value > 0xffU) + ++bytesNeeded; + if (value > 0xffffU) + bytesNeeded += 2; + if (value > 0xffffffffU) + bytesNeeded += 4; + if (bytesNeeded < bytesUsed) + return CborErrorOverlongEncoding; + return CborNoError; +} + +static inline CborError validate_tag(CborValue *it, CborTag tag, uint32_t flags, int recursionLeft) +{ + CborType type = cbor_value_get_type(it); + const size_t knownTagCount = sizeof(knownTagData) / sizeof(knownTagData[0]); + const struct KnownTagData *tagData = knownTagData; + const struct KnownTagData * const knownTagDataEnd = knownTagData + knownTagCount; + + if (!recursionLeft) + return CborErrorNestingTooDeep; + if (flags & CborValidateNoTags) + return CborErrorExcludedType; + + /* find the tag data, if any */ + for ( ; tagData != knownTagDataEnd; ++tagData) { + if (tagData->tag < tag) + continue; + if (tagData->tag > tag) + tagData = NULL; + break; + } + if (tagData == knownTagDataEnd) + tagData = NULL; + + if (flags & CborValidateNoUnknownTags && !tagData) { + /* tag not found */ + if (flags & CborValidateNoUnknownTagsSA && tag < 24) + return CborErrorUnknownTag; + if ((flags & CborValidateNoUnknownTagsSR) == CborValidateNoUnknownTagsSR && tag < 256) + return CborErrorUnknownTag; + if ((flags & CborValidateNoUnknownTags) == CborValidateNoUnknownTags) + return CborErrorUnknownTag; + } + + if (flags & CborValidateTagUse && tagData && tagData->types) { + uint32_t allowedTypes = tagData->types; + + /* correct Integer so it's not zero */ + if (type == CborIntegerType) + type = (CborType)(type + 1); + + while (allowedTypes) { + if ((uint8_t)(allowedTypes & 0xff) == type) + break; + allowedTypes >>= 8; + } + if (!allowedTypes) + return CborErrorInappropriateTagForType; + } + + return validate_value(it, flags, recursionLeft); +} + +#ifndef CBOR_NO_FLOATING_POINT +static inline CborError validate_floating_point(CborValue *it, CborType type, uint32_t flags) +{ + CborError err; + int r; + double val; + float valf; + uint16_t valf16; + + if (type != CborDoubleType) { + if (type == CborFloatType) { + err = cbor_value_get_float(it, &valf); + val = valf; + } else { +# ifdef CBOR_NO_HALF_FLOAT_TYPE + (void)valf16; + return CborErrorUnsupportedType; +# else + err = cbor_value_get_half_float(it, &valf16); + val = decode_half(valf16); +# endif + } + } else { + err = cbor_value_get_double(it, &val); + } + cbor_assert(err == CborNoError); /* can't fail */ + + r = fpclassify(val); + if (r == FP_NAN || r == FP_INFINITE) { + if (flags & CborValidateFiniteFloatingPoint) + return CborErrorExcludedValue; + if (flags & CborValidateShortestFloatingPoint) { + if (type == CborDoubleType) + return CborErrorOverlongEncoding; +# ifndef CBOR_NO_HALF_FLOAT_TYPE + if (type == CborFloatType) + return CborErrorOverlongEncoding; + if (r == FP_NAN && valf16 != 0x7e00) + return CborErrorImproperValue; + if (r == FP_INFINITE && valf16 != 0x7c00 && valf16 != 0xfc00) + return CborErrorImproperValue; +# endif + } + } + + if (flags & CborValidateShortestFloatingPoint && type > CborHalfFloatType) { + if (type == CborDoubleType) { + valf = (float)val; + if ((double)valf == val) + return CborErrorOverlongEncoding; + } +# ifndef CBOR_NO_HALF_FLOAT_TYPE + if (type == CborFloatType) { + valf16 = encode_half(valf); + if (valf == decode_half(valf16)) + return CborErrorOverlongEncoding; + } +# endif + } + + return CborNoError; +} +#endif + +static CborError validate_container(CborValue *it, int containerType, uint32_t flags, int recursionLeft) +{ + CborError err; + const uint8_t *previous = NULL; + const uint8_t *previous_end = NULL; + + if (!recursionLeft) + return CborErrorNestingTooDeep; + + while (!cbor_value_at_end(it)) { + const uint8_t *current = cbor_value_get_next_byte(it); + + if (containerType == CborMapType) { + if (flags & CborValidateMapKeysAreString) { + CborType type = cbor_value_get_type(it); + if (type == CborTagType) { + /* skip the tags */ + CborValue copy = *it; + err = cbor_value_skip_tag(©); + if (err) + return err; + type = cbor_value_get_type(©); + } + if (type != CborTextStringType) + return CborErrorMapKeyNotString; + } + } + + err = validate_value(it, flags, recursionLeft); + if (err) + return err; + + if (containerType != CborMapType) + continue; + + if (flags & CborValidateMapIsSorted) { + if (previous) { + uint64_t len1, len2; + const uint8_t *ptr; + + /* extract the two lengths */ + ptr = previous; + _cbor_value_extract_number(&ptr, it->parser->end, &len1); + ptr = current; + _cbor_value_extract_number(&ptr, it->parser->end, &len2); + + if (len1 > len2) + return CborErrorMapNotSorted; + if (len1 == len2) { + size_t bytelen1 = (size_t)(previous_end - previous); + size_t bytelen2 = (size_t)(it->ptr - current); + int r = memcmp(previous, current, bytelen1 <= bytelen2 ? bytelen1 : bytelen2); + + if (r == 0 && bytelen1 != bytelen2) + r = bytelen1 < bytelen2 ? -1 : +1; + if (r > 0) + return CborErrorMapNotSorted; + if (r == 0 && (flags & CborValidateMapKeysAreUnique) == CborValidateMapKeysAreUnique) + return CborErrorMapKeysNotUnique; + } + } + + previous = current; + previous_end = it->ptr; + } + + /* map: that was the key, so get the value */ + err = validate_value(it, flags, recursionLeft); + if (err) + return err; + } + return CborNoError; +} + +static CborError validate_value(CborValue *it, uint32_t flags, int recursionLeft) +{ + CborError err; + CborType type = cbor_value_get_type(it); + + if (cbor_value_is_length_known(it)) { + err = validate_number(it, type, flags); + if (err) + return err; + } else { + if (flags & CborValidateNoIndeterminateLength) + return CborErrorUnknownLength; + } + + switch (type) { + case CborArrayType: + case CborMapType: { + /* recursive type */ + CborValue recursed; + err = cbor_value_enter_container(it, &recursed); + if (!err) + err = validate_container(&recursed, type, flags, recursionLeft - 1); + if (err) { + it->ptr = recursed.ptr; + return err; + } + err = cbor_value_leave_container(it, &recursed); + if (err) + return err; + return CborNoError; + } + + case CborIntegerType: { + uint64_t val; + err = cbor_value_get_raw_integer(it, &val); + cbor_assert(err == CborNoError); /* can't fail */ + + break; + } + + case CborByteStringType: + case CborTextStringType: { + size_t n = 0; + const void *ptr; + + err = _cbor_value_prepare_string_iteration(it); + if (err) + return err; + + while (1) { + err = validate_number(it, type, flags); + if (err) + return err; + + err = _cbor_value_get_string_chunk(it, &ptr, &n, it); + if (err) + return err; + if (!ptr) + break; + + if (type == CborTextStringType && flags & CborValidateUtf8) { + err = validate_utf8_string(ptr, n); + if (err) + return err; + } + } + + return CborNoError; + } + + case CborTagType: { + CborTag tag; + err = cbor_value_get_tag(it, &tag); + cbor_assert(err == CborNoError); /* can't fail */ + + err = cbor_value_advance_fixed(it); + if (err) + return err; + err = validate_tag(it, tag, flags, recursionLeft - 1); + if (err) + return err; + + return CborNoError; + } + + case CborSimpleType: { + uint8_t simple_type; + err = cbor_value_get_simple_type(it, &simple_type); + cbor_assert(err == CborNoError); /* can't fail */ + err = validate_simple_type(simple_type, flags); + if (err) + return err; + break; + } + + case CborNullType: + case CborBooleanType: + break; + + case CborUndefinedType: + if (flags & CborValidateNoUndefined) + return CborErrorExcludedType; + break; + + case CborHalfFloatType: + case CborFloatType: + case CborDoubleType: { +#ifdef CBOR_NO_FLOATING_POINT + return CborErrorUnsupportedType; +#else + err = validate_floating_point(it, type, flags); + if (err) + return err; + break; +#endif /* !CBOR_NO_FLOATING_POINT */ + } + + case CborInvalidType: + return CborErrorUnknownType; + } + + err = cbor_value_advance_fixed(it); + return err; +} + +/** + * Performs a full validation, controlled by the \a flags options, of the CBOR + * stream pointed by \a it and returns the error it found. If no error was + * found, it returns CborNoError and the application can iterate over the items + * with certainty that no errors will appear during parsing. + * + * If \a flags is CborValidateBasic, the result should be the same as + * cbor_value_validate_basic(). + * + * This function has the same timing and memory requirements as + * cbor_value_advance() and cbor_value_validate_basic(). + * + * \sa CborValidationFlags, cbor_value_validate_basic(), cbor_value_advance() + */ +CborError cbor_value_validate(const CborValue *it, uint32_t flags) +{ + CborValue value = *it; + CborError err = validate_value(&value, flags, CBOR_PARSER_MAX_RECURSIONS); + if (err) + return err; + if (flags & CborValidateCompleteData && it->ptr != it->parser->end) + return CborErrorGarbageAtEnd; + return CborNoError; +} + +/** + * @} + */ diff --git a/client/tinycbor/compilersupport_p.h b/client/tinycbor/compilersupport_p.h new file mode 100644 index 00000000..bd10efc9 --- /dev/null +++ b/client/tinycbor/compilersupport_p.h @@ -0,0 +1,205 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Intel Corporation +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +** copies of the Software, and to permit persons to whom the Software is +** furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +** THE SOFTWARE. +** +****************************************************************************/ + +#ifndef COMPILERSUPPORT_H +#define COMPILERSUPPORT_H + +#include "cbor.h" + +#ifndef _BSD_SOURCE +# define _BSD_SOURCE +#endif +#ifndef _DEFAULT_SOURCE +# define _DEFAULT_SOURCE +#endif +#ifndef assert +# include +#endif +#include +#include +#include + +#ifndef __cplusplus +# include +#endif + +#if __STDC_VERSION__ >= 201112L || __cplusplus >= 201103L || __cpp_static_assert >= 200410 +# define cbor_static_assert(x) static_assert(x, #x) +#elif !defined(__cplusplus) && defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 406) && (__STDC_VERSION__ > 199901L) +# define cbor_static_assert(x) _Static_assert(x, #x) +#else +# define cbor_static_assert(x) ((void)sizeof(char[2*!!(x) - 1])) +#endif +#if __STDC_VERSION__ >= 199901L || defined(__cplusplus) +/* inline is a keyword */ +#else +/* use the definition from cbor.h */ +# define inline CBOR_INLINE +#endif + +#ifdef NDEBUG +# define cbor_assert(cond) do { if (!(cond)) unreachable(); } while (0) +#else +# define cbor_assert(cond) assert(cond) +#endif + +#ifndef STRINGIFY +#define STRINGIFY(x) STRINGIFY2(x) +#endif +#define STRINGIFY2(x) #x + +#if !defined(UINT32_MAX) || !defined(INT64_MAX) +/* C89? We can define UINT32_MAX portably, but not INT64_MAX */ +# error "Your system has stdint.h but that doesn't define UINT32_MAX or INT64_MAX" +#endif + +#ifndef DBL_DECIMAL_DIG +/* DBL_DECIMAL_DIG is C11 */ +# define DBL_DECIMAL_DIG 17 +#endif +#define DBL_DECIMAL_DIG_STR STRINGIFY(DBL_DECIMAL_DIG) + +#if defined(__GNUC__) && defined(__i386__) && !defined(__iamcu__) +# define CBOR_INTERNAL_API_CC __attribute__((regparm(3))) +#elif defined(_MSC_VER) && defined(_M_IX86) +# define CBOR_INTERNAL_API_CC __fastcall +#else +# define CBOR_INTERNAL_API_CC +#endif + +#ifndef __has_builtin +# define __has_builtin(x) 0 +#endif + +#if (defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)) || \ + (__has_builtin(__builtin_bswap64) && __has_builtin(__builtin_bswap32)) +# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define cbor_ntohll __builtin_bswap64 +# define cbor_htonll __builtin_bswap64 +# define cbor_ntohl __builtin_bswap32 +# define cbor_htonl __builtin_bswap32 +# ifdef __INTEL_COMPILER +# define cbor_ntohs _bswap16 +# define cbor_htons _bswap16 +# elif (__GNUC__ * 100 + __GNUC_MINOR__ >= 608) || __has_builtin(__builtin_bswap16) +# define cbor_ntohs __builtin_bswap16 +# define cbor_htons __builtin_bswap16 +# else +# define cbor_ntohs(x) (((uint16_t)(x) >> 8) | ((uint16_t)(x) << 8)) +# define cbor_htons cbor_ntohs +# endif +# else +# define cbor_ntohll +# define cbor_htonll +# define cbor_ntohl +# define cbor_htonl +# define cbor_ntohs +# define cbor_htons +# endif +#elif defined(__sun) +# include +#elif defined(_MSC_VER) +/* MSVC, which implies Windows, which implies little-endian and sizeof(long) == 4 */ +# include +# define cbor_ntohll _byteswap_uint64 +# define cbor_htonll _byteswap_uint64 +# define cbor_ntohl _byteswap_ulong +# define cbor_htonl _byteswap_ulong +# define cbor_ntohs _byteswap_ushort +# define cbor_htons _byteswap_ushort +#endif +#ifndef cbor_ntohs +# include +# define cbor_ntohs ntohs +# define cbor_htons htons +#endif +#ifndef cbor_ntohl +# include +# define cbor_ntohl ntohl +# define cbor_htonl htonl +#endif +#ifndef cbor_ntohll +# define cbor_ntohll ntohll +# define cbor_htonll htonll +/* ntohll isn't usually defined */ +# ifndef ntohll +# if (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || \ + (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && __BYTE_ORDER == __BIG_ENDIAN) || \ + (defined(BYTE_ORDER) && defined(BIG_ENDIAN) && BYTE_ORDER == BIG_ENDIAN) || \ + (defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)) || (defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__)) || \ + defined(__ARMEB__) || defined(__MIPSEB__) || defined(__s390__) || defined(__sparc__) +# define ntohll +# define htonll +# elif (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \ + (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN) || \ + (defined(BYTE_ORDER) && defined(LITTLE_ENDIAN) && BYTE_ORDER == LITTLE_ENDIAN) || \ + defined(_LITTLE_ENDIAN) || defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || defined(__MIPSEL__) || \ + defined(__i386) || defined(__i386__) || defined(__x86_64) || defined(__x86_64__) || defined(__amd64) +# define ntohll(x) ((ntohl((uint32_t)(x)) * UINT64_C(0x100000000)) + (ntohl((x) >> 32))) +# define htonll ntohll +# else +# error "Unable to determine byte order!" +# endif +# endif +#endif + + +#ifdef __cplusplus +# define CONST_CAST(t, v) const_cast(v) +#else +/* C-style const_cast without triggering a warning with -Wcast-qual */ +# define CONST_CAST(t, v) (t)(uintptr_t)(v) +#endif + +#ifdef __GNUC__ +#ifndef likely +# define likely(x) __builtin_expect(!!(x), 1) +#endif +#ifndef unlikely +# define unlikely(x) __builtin_expect(!!(x), 0) +#endif +# define unreachable() __builtin_unreachable() +#elif defined(_MSC_VER) +# define likely(x) (x) +# define unlikely(x) (x) +# define unreachable() __assume(0) +#else +# define likely(x) (x) +# define unlikely(x) (x) +# define unreachable() do {} while (0) +#endif + +static inline bool add_check_overflow(size_t v1, size_t v2, size_t *r) +{ +#if ((defined(__GNUC__) && (__GNUC__ >= 5)) && !defined(__INTEL_COMPILER)) || __has_builtin(__builtin_add_overflow) + return __builtin_add_overflow(v1, v2, r); +#else + /* unsigned additions are well-defined */ + *r = v1 + v2; + return v1 > v1 + v2; +#endif +} + +#endif /* COMPILERSUPPORT_H */ + diff --git a/client/tinycbor/open_memstream.c b/client/tinycbor/open_memstream.c new file mode 100644 index 00000000..18f3de8b --- /dev/null +++ b/client/tinycbor/open_memstream.c @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Intel Corporation +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +** copies of the Software, and to permit persons to whom the Software is +** furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +** THE SOFTWARE. +** +****************************************************************************/ + +#define _BSD_SOURCE 1 +#define _DEFAULT_SOURCE 1 +#define _GNU_SOURCE 1 + +#include +#include +#include +#include +#include + +#if defined(__unix__) || defined(__APPLE__) +# include +#endif +#ifdef __APPLE__ +typedef int RetType; +typedef int LenType; +#elif __GLIBC__ +typedef ssize_t RetType; +typedef size_t LenType; +#else +# error "Cannot implement open_memstream!" +#endif + +#include "compilersupport_p.h" + +struct Buffer +{ + char **ptr; + size_t *len; + size_t alloc; +}; + +static RetType write_to_buffer(void *cookie, const char *data, LenType len) +{ + struct Buffer *b = (struct Buffer *)cookie; + char *ptr = *b->ptr; + size_t newsize; + + errno = EFBIG; + if (unlikely(add_check_overflow(*b->len, len, &newsize))) + return -1; + + if (newsize >= b->alloc) { // NB! one extra byte is needed to avoid buffer overflow at close_buffer + // make room + size_t newalloc = newsize + newsize / 2 + 1; // give 50% more room + ptr = realloc(ptr, newalloc); + if (ptr == NULL) + return -1; + b->alloc = newalloc; + *b->ptr = ptr; + } + + memcpy(ptr + *b->len, data, len); + *b->len = newsize; + return len; +} + +static int close_buffer(void *cookie) +{ + struct Buffer *b = (struct Buffer *)cookie; + if (*b->ptr) + (*b->ptr)[*b->len] = '\0'; + free(b); + return 0; +} + +FILE *open_memstream(char **bufptr, size_t *lenptr) +{ + struct Buffer *b = (struct Buffer *)malloc(sizeof(struct Buffer)); + if (b == NULL) + return NULL; + b->alloc = 0; + b->len = lenptr; + b->ptr = bufptr; + *bufptr = NULL; + *lenptr = 0; + +#ifdef __APPLE__ + return funopen(b, NULL, write_to_buffer, NULL, close_buffer); +#elif __GLIBC__ + static const cookie_io_functions_t vtable = { + NULL, + write_to_buffer, + NULL, + close_buffer + }; + return fopencookie(b, "w", vtable); +#endif +} + diff --git a/client/tinycbor/tinycbor-version.h b/client/tinycbor/tinycbor-version.h new file mode 100644 index 00000000..29967d02 --- /dev/null +++ b/client/tinycbor/tinycbor-version.h @@ -0,0 +1,3 @@ +#define TINYCBOR_VERSION_MAJOR 0 +#define TINYCBOR_VERSION_MINOR 5 +#define TINYCBOR_VERSION_PATCH 3 diff --git a/client/tinycbor/utf8_p.h b/client/tinycbor/utf8_p.h new file mode 100644 index 00000000..ca438350 --- /dev/null +++ b/client/tinycbor/utf8_p.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2017 Intel Corporation +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +** copies of the Software, and to permit persons to whom the Software is +** furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +** THE SOFTWARE. +** +****************************************************************************/ + +#ifndef CBOR_UTF8_H +#define CBOR_UTF8_H + +#include "compilersupport_p.h" + +#include + +static inline uint32_t get_utf8(const uint8_t **buffer, const uint8_t *end) +{ + int charsNeeded; + uint32_t uc, min_uc; + uint8_t b; + ptrdiff_t n = end - *buffer; + if (n == 0) + return ~0U; + + uc = *(*buffer)++; + if (uc < 0x80) { + /* single-byte UTF-8 */ + return uc; + } + + /* multi-byte UTF-8, decode it */ + if (unlikely(uc <= 0xC1)) + return ~0U; + if (uc < 0xE0) { + /* two-byte UTF-8 */ + charsNeeded = 2; + min_uc = 0x80; + uc &= 0x1f; + } else if (uc < 0xF0) { + /* three-byte UTF-8 */ + charsNeeded = 3; + min_uc = 0x800; + uc &= 0x0f; + } else if (uc < 0xF5) { + /* four-byte UTF-8 */ + charsNeeded = 4; + min_uc = 0x10000; + uc &= 0x07; + } else { + return ~0U; + } + + if (n < charsNeeded) + return ~0U; + + /* first continuation character */ + b = *(*buffer)++; + if ((b & 0xc0) != 0x80) + return ~0U; + uc <<= 6; + uc |= b & 0x3f; + + if (charsNeeded > 2) { + /* second continuation character */ + b = *(*buffer)++; + if ((b & 0xc0) != 0x80) + return ~0U; + uc <<= 6; + uc |= b & 0x3f; + + if (charsNeeded > 3) { + /* third continuation character */ + b = *(*buffer)++; + if ((b & 0xc0) != 0x80) + return ~0U; + uc <<= 6; + uc |= b & 0x3f; + } + } + + /* overlong sequence? surrogate pair? out or range? */ + if (uc < min_uc || uc - 0xd800U < 2048U || uc > 0x10ffff) + return ~0U; + + return uc; +} + +#endif /* CBOR_UTF8_H */ diff --git a/client/util.c b/client/util.c index 423d14a0..dec7c5a1 100644 --- a/client/util.c +++ b/client/util.c @@ -140,6 +140,17 @@ int FillBuffer(uint8_t *data, size_t maxDataLength, size_t *dataLength, ...) { return 0; } +bool CheckStringIsHEXValue(const char *value) { + for (int i = 0; i < strlen(value); i++) + if (!isxdigit(value[i])) + return false; + + if (strlen(value) % 2) + return false; + + return true; +} + void hex_to_buffer(const uint8_t *buf, const uint8_t *hex_data, const size_t hex_len, const size_t hex_max_len, const size_t min_str_len, const size_t spaces_between, bool uppercase) { diff --git a/client/util.h b/client/util.h index 1867519e..e3549c02 100644 --- a/client/util.h +++ b/client/util.h @@ -86,6 +86,7 @@ extern void FillFileNameByUID(char *fileName, uint8_t * uid, char *ext, int byte // fill buffer from structure [{uint8_t data, size_t length},...] extern int FillBuffer(uint8_t *data, size_t maxDataLength, size_t *dataLength, ...); +extern bool CheckStringIsHEXValue(const char *value); extern void hex_to_buffer(const uint8_t *buf, const uint8_t *hex_data, const size_t hex_len, const size_t hex_max_len, const size_t min_str_len, const size_t spaces_between, bool uppercase); From 0d5545cee00f3caf7245bf8068c8546a693812be Mon Sep 17 00:00:00 2001 From: Oleg Moiseenko <807634+merlokk@users.noreply.github.com> Date: Fri, 7 Dec 2018 19:55:35 +0200 Subject: [PATCH 035/189] delete travis. it plaed in folder `CI` (#736) --- .travis.yml | 55 ---------------------------------------- travis_test_commands.scr | 3 --- 2 files changed, 58 deletions(-) delete mode 100644 .travis.yml delete mode 100644 travis_test_commands.scr diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index f5fed7a6..00000000 --- a/.travis.yml +++ /dev/null @@ -1,55 +0,0 @@ -# Travis-CI config -# variable REPOSITORY_EP must be filled with repository name. as sample: "merlokk/proxmark3" -language: c - -compiler: gcc - -# Test on Linux and MacOS -matrix: - include: - - os: osx - osx_image: xcode7.3 # OS X 10.11 - - os: osx - osx_image: xcode8.3 # OS X 10.12 - - os: osx - osx_image: xcode9.4 # OS X 10.13 - - os: osx - osx_image: xcode10 # OS X 10.13 - - os: linux - dist: trusty - sudo: required - -before_install: -## Install ARM toolchain on Linux. -## add our homebrew tap for MacOS -## Note: all dependencies on MacOS should be resolved by the brew install command - echo $REPOSITORY_EP; - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then - sudo apt-get update -qq; - sudo apt-get install -y gcc-arm-none-eabi; - elif [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - brew update; - if [[ "$REPOSITORY_EP" == "" ]]; then - brew tap proxmark/proxmark3; - else - brew tap "$REPOSITORY_EP" --env=std; - fi - fi - -install: - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - brew info proxmark3; - brew install -v --HEAD proxmark3; - elif [[ "$TRAVIS_OS_NAME" == "linux" ]]; then - make all; - fi - -before_script: - -script: -## for the time being we are satisfied if it can be build and then successfully started - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - proxmark3 /dev/notexists travis_test_commands.scr ; - elif [[ "$TRAVIS_OS_NAME" == "linux" ]]; then - ./client/proxmark3 /dev/notexists travis_test_commands.scr ; - fi diff --git a/travis_test_commands.scr b/travis_test_commands.scr deleted file mode 100644 index 4f5b025c..00000000 --- a/travis_test_commands.scr +++ /dev/null @@ -1,3 +0,0 @@ -hf mf hardnested t 1 000000000000 -hf emv test -exit From 968ad672808c4bd4ae0d413bbe877f263e3f8228 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Fri, 4 Jan 2019 08:53:30 +0100 Subject: [PATCH 036/189] avoid compiler warning in client/cliparser/argtable3.c (#746) --- client/cliparser/argtable3.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/cliparser/argtable3.c b/client/cliparser/argtable3.c index f70f68c7..c661d26f 100644 --- a/client/cliparser/argtable3.c +++ b/client/cliparser/argtable3.c @@ -389,7 +389,9 @@ static void warnx(const char *fmt, ...) #endif va_end(ap); +#if defined(_MSC_VER) #pragma warning(suppress: 6053) +#endif fprintf(stderr, "%s\n", opterrmsg); } From 8d7d7b618777fddcde8897945f2ec42eb85095e2 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Sat, 5 Jan 2019 09:47:12 +0100 Subject: [PATCH 037/189] Emv commands work with smartcard interface (RfidResearchGroup PR67 by @Merlokk) (#743) * replace 'hf emv' commands by 'emv' commands * Enable smartcard commands by default (-DWITH_SMARTCARD) * update i2c.c from RfidResearchGroup repository * update smartcard.c from RfidResearchGroup repository --- CHANGELOG.md | 1 + armsrc/i2c.c | 122 ++--- client/cmdhf.c | 3 +- client/cmdmain.c | 24 +- client/cmdsmartcard.c | 670 +++++++++++-------------- client/cmdsmartcard.h | 21 +- client/emv/cmdemv.c | 573 ++++++++++++--------- client/emv/cmdemv.h | 10 +- client/emv/emvcore.c | 98 ++-- client/emv/emvcore.h | 29 +- client/fido/fidocore.c | 6 +- common/Makefile_Enabled_Options.common | 1 + common/protocols.h | 1 + include/smartcard.h | 2 +- 14 files changed, 811 insertions(+), 750 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2ed8878..8b856ec1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added `lf hitag reader 03` - read block (instead of pages) - Added `lf hitag reader 04` - read block (instead of pages) - Added `hf fido` `assert` and `make` commands from fido2 protocol (authenticatorMakeCredential and authenticatorGetAssertion) (Merlok) +- Added `emv` commmands working for both contactless and smart cards (Merlok) ## [v3.1.0][2018-10-10] diff --git a/armsrc/i2c.c b/armsrc/i2c.c index 7efb1fd3..bd22e19a 100644 --- a/armsrc/i2c.c +++ b/armsrc/i2c.c @@ -24,7 +24,6 @@ #endif -// ¶¨ÒåÁ¬½ÓÒý½Å #define GPIO_RST AT91C_PIO_PA1 #define GPIO_SCL AT91C_PIO_PA5 #define GPIO_SDA AT91C_PIO_PA7 @@ -49,14 +48,41 @@ static void __attribute__((optimize("O0"))) I2CSpinDelayClk(uint16_t delay) { for (c = delay * 2; c; c--) {}; } -// ͨѶÑÓ³Ùº¯Êý communication delay function +// communication delay functions #define I2C_DELAY_1CLK I2CSpinDelayClk(1) #define I2C_DELAY_2CLK I2CSpinDelayClk(2) #define I2C_DELAY_XCLK(x) I2CSpinDelayClk((x)) - #define ISO7618_MAX_FRAME 255 +// try i2c bus recovery at 100kHz = 5uS high, 5uS low +static void I2C_recovery(void) { + + DbpString("Performing i2c bus recovery"); + + // reset I2C + SDA_H; SCL_H; + + //9nth cycle acts as NACK + for (int i = 0; i < 10; i++) { + SCL_H; WaitUS(5); + SCL_L; WaitUS(5); + } + + //a STOP signal (SDA from low to high while CLK is high) + SDA_L; WaitUS(5); + SCL_H; WaitUS(2); + SDA_H; WaitUS(2); + + bool isok = (SCL_read && SDA_read); + if (!SDA_read) + DbpString("I2C bus recovery error: SDA still LOW"); + if (!SCL_read) + DbpString("I2C bus recovery error: SCL still LOW"); + if (isok) + DbpString("I2C bus recovery complete"); +} + static void I2C_init(void) { // Configure reset pin AT91C_BASE_PIOA->PIO_PPUDR = GPIO_RST; // disable pull up resistor @@ -72,10 +98,13 @@ static void I2C_init(void) { // configure all three pins as output, controlled by PIOA AT91C_BASE_PIOA->PIO_OER |= (GPIO_SCL | GPIO_SDA | GPIO_RST); AT91C_BASE_PIOA->PIO_PER |= (GPIO_SCL | GPIO_SDA | GPIO_RST); + + bool isok = (SCL_read && SDA_read); + if ( !isok ) + I2C_recovery(); + } - -// ÉèÖø´Î»×´Ì¬ // set the reset state static void I2C_SetResetStatus(uint8_t LineRST, uint8_t LineSCK, uint8_t LineSDA) { if (LineRST) @@ -94,19 +123,19 @@ static void I2C_SetResetStatus(uint8_t LineRST, uint8_t LineSCK, uint8_t LineSDA LOW(GPIO_SDA); } -// ¸´Î»½øÈëÖ÷³ÌÐò // Reset the SIM_Adapter, then enter the main program // Note: the SIM_Adapter will not enter the main program after power up. Please run this function before use SIM_Adapter. static void I2C_Reset_EnterMainProgram(void) { - I2C_SetResetStatus(0, 0, 0); // À­µÍ¸´Î»Ïß - SpinDelay(30); - I2C_SetResetStatus(1, 0, 0); // ½â³ý¸´Î» - SpinDelay(30); - I2C_SetResetStatus(1, 1, 1); // À­¸ßÊý¾ÝÏß - SpinDelay(10); + StartTicks(); + I2C_init(); + I2C_SetResetStatus(0, 0, 0); + WaitMS(30); + I2C_SetResetStatus(1, 0, 0); + WaitMS(30); + I2C_SetResetStatus(1, 1, 1); + WaitMS(10); } -// µÈ´ýʱÖÓ±ä¸ß // Wait for the clock to go High. static bool WaitSCL_H_delay(uint32_t delay) { while (delay--) { @@ -184,7 +213,8 @@ static void I2C_SendByte(uint8_t data) { uint8_t bits = 8; while (bits--) { - SCL_L; I2C_DELAY_1CLK; + SCL_L; + I2C_DELAY_1CLK; if (data & 0x80) SDA_H; @@ -205,7 +235,6 @@ static void I2C_SendByte(uint8_t data) { } bool I2C_is_available(void) { - I2C_init(); I2C_Reset_EnterMainProgram(); if (!I2C_Start()) // some other device is active on the bus return true; @@ -219,14 +248,13 @@ bool I2C_is_available(void) { } #ifdef WITH_SMARTCARD -// ¸´Î»½øÈëÒýµ¼Ä£Ê½ // Reset the SIM_Adapter, then enter the bootloader program // Reserve£ºFor firmware update. static void I2C_Reset_EnterBootloader(void) { - I2C_SetResetStatus(0, 1, 1); // À­µÍ¸´Î»Ïß - SpinDelay(100); - I2C_SetResetStatus(1, 1, 1); // ½â³ý¸´Î» - SpinDelay(10); + I2C_SetResetStatus(0, 1, 1); + WaitMS(100); + I2C_SetResetStatus(1, 1, 1); + WaitMS(10); } // Wait max 300ms or until SCL goes LOW. @@ -238,7 +266,7 @@ static bool WaitSCL_L_300ms(void) { if (!SCL_read) return true; - SpinDelay(1); + WaitMS(1); } return (delay == 0); } @@ -303,7 +331,7 @@ static bool I2C_WriteCmd(uint8_t device_cmd, uint8_t device_address) { do { if (!I2C_Start()) return false; - //[C0] + I2C_SendByte(device_address & 0xFE); if (!I2C_WaitAck()) break; @@ -323,7 +351,6 @@ static bool I2C_WriteCmd(uint8_t device_cmd, uint8_t device_address) { return true; } -// дÈë1×Ö½ÚÊý¾Ý £¨´ýдÈëÊý¾Ý£¬´ýдÈëµØÖ·£¬Æ÷¼þÀàÐÍ£© // Sends 1 byte data (Data to be written, command to be written , SlaveDevice address ). static bool I2C_WriteByte(uint8_t data, uint8_t device_cmd, uint8_t device_address) { bool bBreak = true; @@ -354,7 +381,6 @@ static bool I2C_WriteByte(uint8_t data, uint8_t device_cmd, uint8_t device_addre return true; } -// дÈë1´®Êý¾Ý£¨´ýдÈëÊý×鵨ַ£¬´ýдÈ볤¶È£¬´ýдÈëµØÖ·£¬Æ÷¼þÀàÐÍ£© //Sends a string of data (Array, length, command to be written , SlaveDevice address ). // len = uint8 (max buffer to write 256bytes) static bool I2C_BufferWrite(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t device_address) { @@ -393,7 +419,6 @@ static bool I2C_BufferWrite(uint8_t *data, uint8_t len, uint8_t device_cmd, uint return true; } -// ¶Á³ö1´®Êý¾Ý£¨´æ·Å¶Á³öÊý¾Ý£¬´ý¶Á³ö³¤¶È£¬´ø¶Á³öµØÖ·£¬Æ÷¼þÀàÐÍ£© // read 1 strings of data (Data array, Readout length, command to be written , SlaveDevice address ). // len = uint8 (max buffer to read 256bytes) static int16_t I2C_BufferRead(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t device_address) { @@ -403,7 +428,7 @@ static int16_t I2C_BufferRead(uint8_t *data, uint8_t len, uint8_t device_cmd, ui // extra wait 500us (514us measured) // 200us (xx measured) - SpinDelayUs(600); + WaitUS(600); bool bBreak = true; uint16_t readcount = 0; @@ -462,6 +487,7 @@ static int16_t I2C_BufferRead(uint8_t *data, uint8_t len, uint8_t device_cmd, ui } I2C_Stop(); + // return bytecount - first byte (which is length byte) return --readcount; } @@ -481,12 +507,10 @@ static int16_t I2C_ReadFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, if (!I2C_WaitAck()) break; - // msb I2C_SendByte(msb); if (!I2C_WaitAck()) break; - // lsb I2C_SendByte(lsb); if (!I2C_WaitAck()) break; @@ -543,12 +567,10 @@ static bool I2C_WriteFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, ui if (!I2C_WaitAck()) break; - // msb I2C_SendByte(msb); if (!I2C_WaitAck()) break; - // lsb I2C_SendByte(lsb); if (!I2C_WaitAck()) break; @@ -577,7 +599,6 @@ static bool I2C_WriteFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, ui void I2C_print_status(void) { DbpString("Smart card module (ISO 7816)"); uint8_t resp[] = {0,0,0,0}; - I2C_init(); I2C_Reset_EnterMainProgram(); uint8_t len = I2C_BufferRead(resp, sizeof(resp), I2C_DEVICE_CMD_GETVERSION, I2C_DEVICE_ADDRESS_MAIN); if ( len > 0 ) @@ -624,8 +645,6 @@ static bool GetATR(smart_card_atr_t *card_ptr) { // Send ATR // start [C0 01] stop start C1 len aa bb cc stop] I2C_WriteCmd(I2C_DEVICE_CMD_GENERATE_ATR, I2C_DEVICE_ADDRESS_MAIN); - uint8_t cmd[1] = {1}; - LogTrace(cmd, 1, 0, 0, NULL, true); // wait for sim card to answer. // 1byte = 1ms, max frame 256bytes. Should wait 256ms at least just in case. @@ -659,19 +678,6 @@ static bool GetATR(smart_card_atr_t *card_ptr) { } } - // for some reason we only get first byte of atr, if that is so, send dummy command to retrieve the rest of the atr - if (len == 1) { - - uint8_t data[1] = {0}; - I2C_BufferWrite(data, len, I2C_DEVICE_CMD_SEND, I2C_DEVICE_ADDRESS_MAIN); - - if ( !I2C_WaitForSim() ) - return false; - - uint8_t len2 = I2C_BufferRead(card_ptr->atr + len, sizeof(card_ptr->atr) - len, I2C_DEVICE_CMD_READ, I2C_DEVICE_ADDRESS_MAIN); - len = len + len2; - } - card_ptr->atr_len = len; LogTrace(card_ptr->atr, card_ptr->atr_len, 0, 0, NULL, false); @@ -683,7 +689,6 @@ void SmartCardAtr(void) { LED_D_ON(); clear_trace(); set_tracing(true); - I2C_init(); I2C_Reset_EnterMainProgram(); bool isOK = GetATR( &card ); cmd_send(CMD_ACK, isOK, sizeof(smart_card_atr_t), 0, &card, sizeof(smart_card_atr_t)); @@ -706,10 +711,9 @@ void SmartCardRaw( uint64_t arg0, uint64_t arg1, uint8_t *data ) { if ((flags & SC_CONNECT)) { - I2C_init(); I2C_Reset_EnterMainProgram(); - if ( !(flags & SC_NO_SELECT) ) { + if (flags & SC_SELECT) { smart_card_atr_t card; bool gotATR = GetATR( &card ); //cmd_send(CMD_ACK, gotATR, sizeof(smart_card_atr_t), 0, &card, sizeof(smart_card_atr_t)); @@ -725,18 +729,21 @@ void SmartCardRaw( uint64_t arg0, uint64_t arg1, uint8_t *data ) { // Send raw bytes // asBytes = A0 A4 00 00 02 // arg1 = len 5 - I2C_BufferWrite(data, arg1, I2C_DEVICE_CMD_SEND, I2C_DEVICE_ADDRESS_MAIN); - - if ( !I2C_WaitForSim() ) - goto OUT; + bool res = I2C_BufferWrite(data, arg1, I2C_DEVICE_CMD_SEND, I2C_DEVICE_ADDRESS_MAIN); + if ( !res && MF_DBGLEVEL > 3 ) DbpString(I2C_ERROR); // read bytes from module len = ISO7618_MAX_FRAME; - sc_rx_bytes(resp, &len); - LogTrace(resp, len, 0, 0, NULL, false); + res = sc_rx_bytes(resp, &len); + if ( res ) { + LogTrace(resp, len, 0, 0, NULL, false); + } else { + len = 0; + } } OUT: cmd_send(CMD_ACK, len, 0, 0, resp, len); + BigBuf_free(); set_tracing(false); LEDsoff(); } @@ -749,7 +756,6 @@ void SmartCardUpgrade(uint64_t arg0) { // write. Sector0, with 11,22,33,44 // erase is 128bytes, and takes 50ms to execute - I2C_init(); I2C_Reset_EnterBootloader(); bool isOK = true; @@ -777,7 +783,7 @@ void SmartCardUpgrade(uint64_t arg0) { } // writing takes time. - SpinDelay(50); + WaitMS(50); // read res = I2C_ReadFW(verfiydata, size, msb, lsb, I2C_DEVICE_ADDRESS_BOOT); @@ -799,6 +805,7 @@ void SmartCardUpgrade(uint64_t arg0) { } cmd_send(CMD_ACK, isOK, pos, 0, 0, 0); LED_C_OFF(); + BigBuf_free(); } // unfinished (or not needed?) @@ -808,7 +815,6 @@ void SmartCardUpgrade(uint64_t arg0) { void SmartCardSetClock(uint64_t arg0) { LED_D_ON(); set_tracing(true); - I2C_init(); I2C_Reset_EnterMainProgram(); // Send SIM CLC diff --git a/client/cmdhf.c b/client/cmdhf.c index d2201800..56b1cb3d 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -415,6 +415,8 @@ int CmdHFList(const char *Cmd) protocol = ISO_14443B; } else if(strcmp(type,"topaz") == 0) { protocol = TOPAZ; + } else if(strcmp(type, "7816") == 0) { + protocol = ISO_7816_4; } else if(strcmp(type,"raw") == 0) { protocol = -1; //No crc, no annotations } else if (strcmp(type, "save") == 0) { @@ -592,7 +594,6 @@ static command_t CommandTable[] = {"14b", CmdHF14B, 1, "{ ISO14443B RFIDs... }"}, {"15", CmdHF15, 1, "{ ISO15693 RFIDs... }"}, {"epa", CmdHFEPA, 1, "{ German Identification Card... }"}, - {"emv", CmdHFEMV, 1, "{ EMV cards... }"}, {"legic", CmdHFLegic, 0, "{ LEGIC RFIDs... }"}, {"iclass", CmdHFiClass, 1, "{ ICLASS RFIDs... }"}, {"mf", CmdHFMF, 1, "{ MIFARE RFIDs... }"}, diff --git a/client/cmdmain.c b/client/cmdmain.c index f503021a..dbaef70e 100644 --- a/client/cmdmain.c +++ b/client/cmdmain.c @@ -26,6 +26,7 @@ #include "util.h" #include "util_posix.h" #include "cmdscript.h" +#include "emv/cmdemv.h" // EMV #ifdef WITH_SMARTCARD #include "cmdsmartcard.h" #endif @@ -36,18 +37,21 @@ static int CmdQuit(const char *Cmd); static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help. Use ' help' for details of a particular command."}, - {"data", CmdData, 1, "{ Plot window / data buffer manipulation... }"}, - {"hf", CmdHF, 1, "{ High Frequency commands... }"}, - {"hw", CmdHW, 1, "{ Hardware commands... }"}, - {"lf", CmdLF, 1, "{ Low Frequency commands... }"}, + {"help", CmdHelp, 1, "This help. Use ' help' for details of a particular command."}, + {"data", CmdData, 1, "{ Plot window / data buffer manipulation... }"}, + {"hf", CmdHF, 1, "{ High Frequency commands... }"}, + {"hw", CmdHW, 1, "{ Hardware commands... }"}, + {"lf", CmdLF, 1, "{ Low Frequency commands... }"}, #ifdef WITH_SMARTCARD - {"sc", CmdSmartcard,1,"{ Smartcard commands... }"}, + {"emv", CmdEMV, 1, "{ EMV iso14443 and iso7816... }"}, + {"sc", CmdSmartcard,1,"{ Smartcard commands... }"}, +#else + {"emv", CmdEMV, 1, "{ EMV iso14443 }"}, #endif - {"script",CmdScript,1, "{ Scripting commands }"}, - {"quit", CmdQuit, 1, "Exit program"}, - {"exit", CmdQuit, 1, "Exit program"}, - {NULL, NULL, 0, NULL} + {"script",CmdScript,1, "{ Scripting commands }"}, + {"quit", CmdQuit, 1, "Exit program"}, + {"exit", CmdQuit, 1, "Exit program"}, + {NULL, NULL, 0, NULL} }; command_t* getTopLevelCommandTable() diff --git a/client/cmdsmartcard.c b/client/cmdsmartcard.c index b2a5705d..4258989c 100644 --- a/client/cmdsmartcard.c +++ b/client/cmdsmartcard.c @@ -8,66 +8,161 @@ // Proxmark3 RDV40 Smartcard module commands //----------------------------------------------------------------------------- #include "cmdsmartcard.h" + +#include + +#include "ui.h" +#include "cmdparser.h" +#include "util.h" #include "smartcard.h" #include "comms.h" #include "protocols.h" +#include "cmdhf.h" // CmdHFlist +#include "emv/apduinfo.h" // APDUcode description +#include "emv/emvcore.h" // decodeTVL static int CmdHelp(const char *Cmd); -int usage_sm_raw(void) { - PrintAndLog("Usage: sc raw [h|r|c] d <0A 0B 0C ... hex>"); - PrintAndLog(" h : this help"); - PrintAndLog(" r : do not read response"); - PrintAndLog(" a : active signal field ON without select"); - PrintAndLog(" s : active signal field ON with select"); - PrintAndLog(" t : executes TLV decoder if it is possible"); - PrintAndLog(" d : bytes to send"); - PrintAndLog(""); - PrintAndLog("Examples:"); - PrintAndLog(" sc raw d 11223344"); +static int usage_sm_raw(void) { + PrintAndLogEx(NORMAL, "Usage: sc raw [h|r|c] d <0A 0B 0C ... hex>"); + PrintAndLogEx(NORMAL, " h : this help"); + PrintAndLogEx(NORMAL, " r : do not read response"); + PrintAndLogEx(NORMAL, " a : active smartcard without select"); + PrintAndLogEx(NORMAL, " s : active smartcard with select"); + PrintAndLogEx(NORMAL, " t : executes TLV decoder if it possible"); + PrintAndLogEx(NORMAL, " d : bytes to send"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " sc raw d 00a404000e315041592e5359532e444446303100 - `1PAY.SYS.DDF01` PPSE directory"); + PrintAndLogEx(NORMAL, " sc raw d 00a404000e325041592e5359532e444446303100 - `2PAY.SYS.DDF01` PPSE directory"); return 0; } -int usage_sm_reader(void) { - PrintAndLog("Usage: sc reader [h|s]"); - PrintAndLog(" h : this help"); - PrintAndLog(" s : silent (no messages)"); - PrintAndLog(""); - PrintAndLog("Examples:"); - PrintAndLog(" sc reader"); + +static int usage_sm_reader(void) { + PrintAndLogEx(NORMAL, "Usage: sc reader [h|s]"); + PrintAndLogEx(NORMAL, " h : this help"); + PrintAndLogEx(NORMAL, " s : silent (no messages)"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " sc reader"); return 0; } -int usage_sm_info(void) { - PrintAndLog("Usage: sc info [h|s]"); - PrintAndLog(" h : this help"); - PrintAndLog(" s : silent (no messages)"); - PrintAndLog(""); - PrintAndLog("Examples:"); - PrintAndLog(" sc info"); + +static int usage_sm_info(void) { + PrintAndLogEx(NORMAL, "Usage: s info [h|s]"); + PrintAndLogEx(NORMAL, " h : this help"); + PrintAndLogEx(NORMAL, " s : silent (no messages)"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " sc info"); return 0; } -int usage_sm_upgrade(void) { - PrintAndLog("Upgrade firmware"); - PrintAndLog("Usage: sc upgrade f "); - PrintAndLog(" h : this help"); - PrintAndLog(" f : firmware file name"); - PrintAndLog(""); - PrintAndLog("Examples:"); - PrintAndLog(" sc upgrade f myfile"); - PrintAndLog(""); - PrintAndLog("WARNING - Dangerous command, do wrong and you will brick the smart card socket"); + +static int usage_sm_upgrade(void) { + PrintAndLogEx(NORMAL, "Upgrade firmware"); + PrintAndLogEx(NORMAL, "Usage: sc upgrade f "); + PrintAndLogEx(NORMAL, " h : this help"); + PrintAndLogEx(NORMAL, " f : firmware file name"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " sc upgrade f myfile"); return 0; } -int usage_sm_setclock(void) { - PrintAndLog("Usage: sc setclock [h] c "); - PrintAndLog(" h : this help"); - PrintAndLog(" c <> : clockspeed (0 = 16mhz, 1=8mhz, 2=4mhz) "); - PrintAndLog(""); - PrintAndLog("Examples:"); - PrintAndLog(" sc setclock c 2"); + +static int usage_sm_setclock(void) { + PrintAndLogEx(NORMAL, "Usage: sc setclock [h] c "); + PrintAndLogEx(NORMAL, " h : this help"); + PrintAndLogEx(NORMAL, " c <> : clockspeed (0 = 16mhz, 1=8mhz, 2=4mhz) "); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " sc setclock c 2"); return 0; } +static int usage_sm_brute(void) { + PrintAndLogEx(NORMAL, "Tries to bruteforce SFI, "); + PrintAndLogEx(NORMAL, "Usage: sc brute [h]"); + PrintAndLogEx(NORMAL, " h : this help"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " sc brute"); + return 0; +} + +static bool smart_select(bool silent) { + UsbCommand c = {CMD_SMART_ATR, {0, 0, 0}}; + clearCommandBuffer(); + SendCommand(&c); + UsbCommand resp; + if ( !WaitForResponseTimeout(CMD_ACK, &resp, 2500) ) { + if (!silent) PrintAndLogEx(WARNING, "smart card select failed"); + return false; + } + + uint8_t isok = resp.arg[0] & 0xFF; + if (!isok) { + if (!silent) PrintAndLogEx(WARNING, "smart card select failed"); + return false; + } + + if (!silent) { + smart_card_atr_t card; + memcpy(&card, (smart_card_atr_t *)resp.d.asBytes, sizeof(smart_card_atr_t)); + + PrintAndLogEx(INFO, "ISO7816-3 ATR : %s", sprint_hex(card.atr, card.atr_len)); + } + + return true; +} + +static int smart_wait(uint8_t *data) { + UsbCommand resp; + if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) { + PrintAndLogEx(WARNING, "smart card response failed"); + return -1; + } + + uint32_t len = resp.arg[0]; + if ( !len ) { + PrintAndLogEx(WARNING, "smart card response failed"); + return -2; + } + memcpy(data, resp.d.asBytes, len); + PrintAndLogEx(SUCCESS, " %d | %s", len, sprint_hex_inrow_ex(data, len, 32)); + + if (len >= 2) { + PrintAndLogEx(SUCCESS, "%02X%02X | %s", data[len - 2], data[len - 1], GetAPDUCodeDescription(data[len - 2], data[len - 1])); + } + return len; +} + +static int smart_response(uint8_t *data) { + + int len = -1; + int datalen = smart_wait(data); + + if ( data[datalen - 2] == 0x61 || data[datalen - 2] == 0x9F ) { + len = data[datalen - 1]; + } + + if (len == -1 ) { + goto out; + } + + PrintAndLogEx(INFO, "Requesting response. len=0x%x", len); + uint8_t getstatus[] = {ISO7816_GETSTATUS, 0x00, 0x00, len}; + UsbCommand cStatus = {CMD_SMART_RAW, {SC_RAW, sizeof(getstatus), 0}}; + memcpy(cStatus.d.asBytes, getstatus, sizeof(getstatus) ); + clearCommandBuffer(); + SendCommand(&cStatus); + + datalen = smart_wait(data); +out: + + return datalen; +} + int CmdSmartRaw(const char *Cmd) { int hexlen = 0; @@ -99,13 +194,13 @@ int CmdSmartRaw(const char *Cmd) { case 'd': { switch (param_gethex_to_eol(Cmd, cmdp+1, data, sizeof(data), &hexlen)) { case 1: - PrintAndLog("Invalid HEX value."); + PrintAndLogEx(WARNING, "Invalid HEX value."); return 1; case 2: - PrintAndLog("Too many bytes. Max %d bytes", sizeof(data)); + PrintAndLogEx(WARNING, "Too many bytes. Max %d bytes", sizeof(data)); return 1; case 3: - PrintAndLog("Hex must have an even number of digits."); + PrintAndLogEx(WARNING, "Hex must have even number of digits."); return 1; } cmdp++; @@ -113,7 +208,7 @@ int CmdSmartRaw(const char *Cmd) { break; } default: - PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; break; } @@ -130,13 +225,13 @@ int CmdSmartRaw(const char *Cmd) { UsbCommand c = {CMD_SMART_RAW, {0, hexlen, 0}}; if (active || active_select) { - c.arg[0] |= SC_CONNECT; - if (active) - c.arg[0] |= SC_NO_SELECT; - } + c.arg[0] |= SC_CONNECT; + if (active_select) + c.arg[0] |= SC_SELECT; + } if (hexlen > 0) { - c.arg[0] |= SC_RAW; + c.arg[0] |= SC_RAW; } memcpy(c.d.asBytes, data, hexlen ); @@ -145,45 +240,67 @@ int CmdSmartRaw(const char *Cmd) { // reading response from smart card if ( reply ) { - UsbCommand resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) { - PrintAndLog("smart card response failed"); - return 1; - } - uint32_t datalen = resp.arg[0]; - if ( !datalen ) { - PrintAndLog("smart card response failed"); - return 1; - } - - PrintAndLog("received %i bytes", datalen); - - if (!datalen) + uint8_t* buf = calloc(USB_CMD_DATA_SIZE, sizeof(uint8_t)); + if ( !buf ) return 1; - uint8_t *data = resp.d.asBytes; - - // TLV decoder - if (decodeTLV ) { - - if (datalen >= 2) { - PrintAndLog("%02x %02x | %s", data[datalen - 2], data[datalen - 1], GetAPDUCodeDescription(data[datalen - 2], data[datalen - 1])); - } - if (datalen > 4) { - TLVPrintFromBuffer(data, datalen - 2); - } - } else { - PrintAndLog("%s", sprint_hex(data, datalen)); + int len = smart_response(buf); + if ( len < 0 ) { + free(buf); + return 2; } + + if ( buf[0] == 0x6C ) { + data[4] = buf[1]; + + memcpy(c.d.asBytes, data, sizeof(data) ); + clearCommandBuffer(); + SendCommand(&c); + len = smart_response(buf); + + data[4] = 0; + } + + if (decodeTLV && len > 4) + TLVPrintFromBuffer(buf+1, len-3); + + free(buf); } return 0; } +int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { + *dataoutlen = 0; + + if (activateCard) + smart_select(false); + printf("* APDU SC\n"); + + UsbCommand c = {CMD_SMART_RAW, {SC_RAW | SC_CONNECT, datainlen, 0}}; + if (activateCard) { + c.arg[0] |= SC_SELECT; + } + memcpy(c.d.asBytes, datain, datainlen); + clearCommandBuffer(); + SendCommand(&c); + + int len = smart_response(dataout); + + if ( len < 0 ) { + return 2; + } + + *dataoutlen = len; + + return 0; +} + + int CmdSmartUpgrade(const char *Cmd) { - PrintAndLog("WARNING - Smartcard socket firmware upgrade."); - PrintAndLog("Dangerous command, do wrong and you will brick the smart card socket"); + PrintAndLogEx(WARNING, "WARNING - Smartcard socket firmware upgrade."); + PrintAndLogEx(WARNING, "A dangerous command, do wrong and you will brick the smart card socket"); FILE *f; char filename[FILE_PATH_SIZE] = {0}; @@ -195,7 +312,7 @@ int CmdSmartUpgrade(const char *Cmd) { case 'f': //File handling and reading if ( param_getstr(Cmd, cmdp+1, filename, FILE_PATH_SIZE) >= FILE_PATH_SIZE ) { - PrintAndLog("Filename too long"); + PrintAndLogEx(FAILED, "Filename too long"); errors = true; break; } @@ -204,7 +321,7 @@ int CmdSmartUpgrade(const char *Cmd) { case 'h': return usage_sm_upgrade(); default: - PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; break; } @@ -215,8 +332,8 @@ int CmdSmartUpgrade(const char *Cmd) { // load file f = fopen(filename, "rb"); - if ( !f ) { - PrintAndLog("File: %s: not found or locked.", filename); + if ( !f ){ + PrintAndLogEx(FAILED, "File: %s: not found or locked.", filename); return 1; } @@ -225,15 +342,15 @@ int CmdSmartUpgrade(const char *Cmd) { long fsize = ftell(f); fseek(f, 0, SEEK_SET); - if (fsize < 0) { - PrintAndLog("error, when getting filesize"); + if (fsize < 0) { + PrintAndLogEx(WARNING, "error, when getting filesize"); fclose(f); return 1; } - + uint8_t *dump = calloc(fsize, sizeof(uint8_t)); if (!dump) { - PrintAndLog("error, cannot allocate memory "); + PrintAndLogEx(WARNING, "error, cannot allocate memory "); fclose(f); return 1; } @@ -242,7 +359,7 @@ int CmdSmartUpgrade(const char *Cmd) { if (f) fclose(f); - PrintAndLog("Smartcard socket firmware uploading to PM3"); + PrintAndLogEx(SUCCESS, "Smartcard socket firmware uploading to PM3"); //Send to device uint32_t index = 0; uint32_t bytes_sent = 0; @@ -258,7 +375,7 @@ int CmdSmartUpgrade(const char *Cmd) { clearCommandBuffer(); SendCommand(&c); if ( !WaitForResponseTimeout(CMD_ACK, NULL, 2000) ) { - PrintAndLog("timeout while waiting for reply."); + PrintAndLogEx(WARNING, "timeout while waiting for reply."); free(dump); return 1; } @@ -269,7 +386,7 @@ int CmdSmartUpgrade(const char *Cmd) { } free(dump); printf("\n"); - PrintAndLog("Smartcard socket firmware updating, don\'t turn off your PM3!"); + PrintAndLogEx(SUCCESS, "Smartcard socket firmware updating, don\'t turn off your PM3!"); // trigger the firmware upgrade UsbCommand c = {CMD_SMART_UPGRADE, {bytes_read, 0, 0}}; @@ -277,13 +394,13 @@ int CmdSmartUpgrade(const char *Cmd) { SendCommand(&c); UsbCommand resp; if ( !WaitForResponseTimeout(CMD_ACK, &resp, 2500) ) { - PrintAndLog("timeout while waiting for reply."); + PrintAndLogEx(WARNING, "timeout while waiting for reply."); return 1; } - if ( (resp.arg[0] && 0xFF ) ) - PrintAndLog("Smartcard socket firmware upgraded successful"); + if ( (resp.arg[0] & 0xFF ) ) + PrintAndLogEx(SUCCESS, "Smartcard socket firmware upgraded successful"); else - PrintAndLog("Smartcard socket firmware updating failed"); + PrintAndLogEx(FAILED, "Smartcard socket firmware updating failed"); return 0; } @@ -294,11 +411,11 @@ int CmdSmartInfo(const char *Cmd){ while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch (tolower(param_getchar(Cmd, cmdp))) { case 'h': return usage_sm_info(); - case 's': + case 's': silent = true; break; default: - PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; break; } @@ -313,13 +430,13 @@ int CmdSmartInfo(const char *Cmd){ SendCommand(&c); UsbCommand resp; if ( !WaitForResponseTimeout(CMD_ACK, &resp, 2500) ) { - if (!silent) PrintAndLog("smart card select failed"); + if (!silent) PrintAndLogEx(WARNING, "smart card select failed"); return 1; } uint8_t isok = resp.arg[0] & 0xFF; if (!isok) { - if (!silent) PrintAndLog("smart card select failed"); + if (!silent) PrintAndLogEx(WARNING, "smart card select failed"); return 1; } @@ -327,11 +444,11 @@ int CmdSmartInfo(const char *Cmd){ memcpy(&card, (smart_card_atr_t *)resp.d.asBytes, sizeof(smart_card_atr_t)); // print header - PrintAndLog("\n--- Smartcard Information ---------"); - PrintAndLog("-------------------------------------------------------------"); - PrintAndLog("ISO76183 ATR : %s", sprint_hex(card.atr, card.atr_len)); - PrintAndLog("look up ATR"); - PrintAndLog("http://smartcard-atr.appspot.com/parse?ATR=%s", sprint_hex_inrow(card.atr, card.atr_len) ); + PrintAndLogEx(INFO, "\n--- Smartcard Information ---------"); + PrintAndLogEx(INFO, "-------------------------------------------------------------"); + PrintAndLogEx(INFO, "ISO76183 ATR : %s", sprint_hex(card.atr, card.atr_len)); + PrintAndLogEx(INFO, "look up ATR"); + PrintAndLogEx(INFO, "http://smartcard-atr.appspot.com/parse?ATR=%s", sprint_hex_inrow(card.atr, card.atr_len) ); return 0; } @@ -342,11 +459,11 @@ int CmdSmartReader(const char *Cmd){ while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch (tolower(param_getchar(Cmd, cmdp))) { case 'h': return usage_sm_reader(); - case 's': + case 's': silent = true; break; default: - PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; break; } @@ -361,18 +478,19 @@ int CmdSmartReader(const char *Cmd){ SendCommand(&c); UsbCommand resp; if ( !WaitForResponseTimeout(CMD_ACK, &resp, 2500) ) { - if (!silent) PrintAndLog("smart card select failed"); + if (!silent) PrintAndLogEx(WARNING, "smart card select failed"); return 1; } uint8_t isok = resp.arg[0] & 0xFF; if (!isok) { - if (!silent) PrintAndLog("smart card select failed"); + if (!silent) PrintAndLogEx(WARNING, "smart card select failed"); return 1; } smart_card_atr_t card; memcpy(&card, (smart_card_atr_t *)resp.d.asBytes, sizeof(smart_card_atr_t)); - PrintAndLog("ISO7816-3 ATR : %s", sprint_hex(card.atr, card.atr_len)); + + PrintAndLogEx(INFO, "ISO7816-3 ATR : %s", sprint_hex(card.atr, card.atr_len)); return 0; } @@ -383,15 +501,15 @@ int CmdSmartSetClock(const char *Cmd){ while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch (tolower(param_getchar(Cmd, cmdp))) { case 'h': return usage_sm_setclock(); - case 'c': + case 'c': clock = param_get8ex(Cmd, cmdp+1, 2, 10); if ( clock > 2) errors = true; - + cmdp += 2; break; default: - PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; break; } @@ -405,25 +523,25 @@ int CmdSmartSetClock(const char *Cmd){ SendCommand(&c); UsbCommand resp; if ( !WaitForResponseTimeout(CMD_ACK, &resp, 2500) ) { - PrintAndLog("smart card select failed"); + PrintAndLogEx(WARNING, "smart card select failed"); return 1; } uint8_t isok = resp.arg[0] & 0xFF; if (!isok) { - PrintAndLog("smart card set clock failed"); + PrintAndLogEx(WARNING, "smart card set clock failed"); return 1; } switch (clock) { case 0: - PrintAndLog("Clock changed to 16mhz giving 10800 baudrate"); + PrintAndLogEx(SUCCESS, "Clock changed to 16mhz giving 10800 baudrate"); break; case 1: - PrintAndLog("Clock changed to 8mhz giving 21600 baudrate"); + PrintAndLogEx(SUCCESS, "Clock changed to 8mhz giving 21600 baudrate"); break; case 2: - PrintAndLog("Clock changed to 4mhz giving 86400 baudrate"); + PrintAndLogEx(SUCCESS, "Clock changed to 4mhz giving 86400 baudrate"); break; default: break; @@ -431,267 +549,77 @@ int CmdSmartSetClock(const char *Cmd){ return 0; } - -// iso 7816-3 -void annotateIso7816(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize){ - // S-block - if ( (cmd[0] & 0xC0) && (cmdsize == 3) ) { - switch ( (cmd[0] & 0x3f) ) { - case 0x00 : snprintf(exp, size, "S-block RESYNCH req"); break; - case 0x20 : snprintf(exp, size, "S-block RESYNCH resp"); break; - case 0x01 : snprintf(exp, size, "S-block IFS req"); break; - case 0x21 : snprintf(exp, size, "S-block IFS resp"); break; - case 0x02 : snprintf(exp, size, "S-block ABORT req"); break; - case 0x22 : snprintf(exp, size, "S-block ABORT resp"); break; - case 0x03 : snprintf(exp, size, "S-block WTX reqt"); break; - case 0x23 : snprintf(exp, size, "S-block WTX resp"); break; - default : snprintf(exp, size, "S-block"); break; - } - } - // R-block (ack) - else if ( ((cmd[0] & 0xD0) == 0x80) && ( cmdsize > 2) ) { - if ( (cmd[0] & 0x10) == 0 ) - snprintf(exp, size, "R-block ACK"); - else - snprintf(exp, size, "R-block NACK"); - } - // I-block - else { - - int pos = (cmd[0] == 2 || cmd[0] == 3) ? 2 : 3; - switch ( cmd[pos] ) { - case ISO7816_READ_BINARY :snprintf(exp, size, "READ BIN");break; - case ISO7816_WRITE_BINARY :snprintf(exp, size, "WRITE BIN");break; - case ISO7816_UPDATE_BINARY :snprintf(exp, size, "UPDATE BIN");break; - case ISO7816_ERASE_BINARY :snprintf(exp, size, "ERASE BIN");break; - case ISO7816_READ_RECORDS :snprintf(exp, size, "READ RECORDS");break; - case ISO7816_WRITE_RECORDS :snprintf(exp, size, "WRITE RECORDS");break; - case ISO7816_APPEND_RECORD :snprintf(exp, size, "APPEND RECORD");break; - case ISO7816_UPDATE_RECORD :snprintf(exp, size, "UPDATE RECORD");break; - case ISO7816_GET_DATA :snprintf(exp, size, "GET DATA");break; - case ISO7816_PUT_DATA :snprintf(exp, size, "PUT DATA");break; - case ISO7816_SELECT_FILE :snprintf(exp, size, "SELECT FILE");break; - case ISO7816_VERIFY :snprintf(exp, size, "VERIFY");break; - case ISO7816_INTERNAL_AUTHENTICATION :snprintf(exp, size, "INTERNAL AUTH");break; - case ISO7816_EXTERNAL_AUTHENTICATION :snprintf(exp, size, "EXTERNAL AUTH");break; - case ISO7816_GET_CHALLENGE :snprintf(exp, size, "GET CHALLENGE");break; - case ISO7816_MANAGE_CHANNEL :snprintf(exp, size, "MANAGE CHANNEL");break; - default :snprintf(exp, size, "?"); break; - } - } -} - - -uint16_t printScTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace) { - // sanity check - if (tracepos + sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t) > traceLen) return traceLen; - - bool isResponse; - uint16_t data_len, parity_len; - uint32_t duration, timestamp, first_timestamp, EndOfTransmissionTimestamp; - char explanation[30] = {0}; - - first_timestamp = *((uint32_t *)(trace)); - timestamp = *((uint32_t *)(trace + tracepos)); - tracepos += 4; - - duration = *((uint16_t *)(trace + tracepos)); - tracepos += 2; - - data_len = *((uint16_t *)(trace + tracepos)); - tracepos += 2; - - if (data_len & 0x8000) { - data_len &= 0x7fff; - isResponse = true; - } else { - isResponse = false; - } - - parity_len = (data_len-1)/8 + 1; - if (tracepos + data_len + parity_len > traceLen) { - return traceLen; - } - uint8_t *frame = trace + tracepos; - tracepos += data_len; - //uint8_t *parityBytes = trace + tracepos; - tracepos += parity_len; - - //--- Draw the data column - char line[18][110]; - - if (data_len == 0 ) { - sprintf(line[0],""); - return tracepos; - } - - for (int j = 0; j < data_len && j/18 < 18; j++) { - snprintf(line[j/18]+(( j % 18) * 4),110, "%02x ", frame[j]); - } - - EndOfTransmissionTimestamp = timestamp + duration; - - annotateIso7816(explanation,sizeof(explanation),frame,data_len); - - int num_lines = MIN((data_len - 1)/18 + 1, 18); - for (int j = 0; j < num_lines ; j++) { - if (j == 0) { - PrintAndLog(" %10u | %10u | %s |%-72s | %s| %s", - (timestamp - first_timestamp), - (EndOfTransmissionTimestamp - first_timestamp), - (isResponse ? "Tag" : "Rdr"), - line[j], - " ", - (j == num_lines-1) ? explanation : ""); - } else { - PrintAndLog(" | | |%-72s | %s| %s", - line[j], - " ", - (j == num_lines-1) ? explanation : ""); - } - } - - // if is last record - if (tracepos + sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t) >= traceLen) return traceLen; - - return tracepos; -} - -int ScTraceList(const char *Cmd) { - bool loadFromFile = false; - bool saveToFile = false; - char type[5] = {0}; - char filename[FILE_PATH_SIZE] = {0}; - - // parse command line - param_getstr(Cmd, 0, type, sizeof(type)); - param_getstr(Cmd, 1, filename, sizeof(filename)); - - bool errors = false; - if(type[0] == 'h') { - errors = true; - } - - if(!errors) { - if (strcmp(type, "s") == 0) { - saveToFile = true; - } else if (strcmp(type,"l") == 0) { - loadFromFile = true; - } - } - - if ((loadFromFile || saveToFile) && strlen(filename) == 0) { - errors = true; - } - - if (loadFromFile && saveToFile) { - errors = true; - } - - if (errors) { - PrintAndLog("List or save protocol data."); - PrintAndLog("Usage: sc list [l ]"); - PrintAndLog(" sc list [s ]"); - PrintAndLog(" l - load data from file instead of trace buffer"); - PrintAndLog(" s - save data to file"); - PrintAndLog(""); - PrintAndLog("example: sc list"); - PrintAndLog("example: sc list save myCardTrace.trc"); - PrintAndLog("example: sc list l myCardTrace.trc"); - return 0; - } - - uint8_t *trace; - uint32_t tracepos = 0; - uint32_t traceLen = 0; - - if (loadFromFile) { - #define TRACE_CHUNK_SIZE (1<<16) // 64K to start with. Will be enough for BigBuf and some room for future extensions - FILE *tracefile = NULL; - size_t bytes_read; - trace = malloc(TRACE_CHUNK_SIZE); - if (trace == NULL) { - PrintAndLog("Cannot allocate memory for trace"); - return 2; - } - if ((tracefile = fopen(filename,"rb")) == NULL) { - PrintAndLog("Could not open file %s", filename); - free(trace); - return 0; - } - while (!feof(tracefile)) { - bytes_read = fread(trace+traceLen, 1, TRACE_CHUNK_SIZE, tracefile); - traceLen += bytes_read; - if (!feof(tracefile)) { - uint8_t *p = realloc(trace, traceLen + TRACE_CHUNK_SIZE); - if (p == NULL) { - PrintAndLog("Cannot allocate memory for trace"); - free(trace); - fclose(tracefile); - return 2; - } - trace = p; - } - } - fclose(tracefile); - } else { - trace = malloc(USB_CMD_DATA_SIZE); - // Query for the size of the trace - UsbCommand response; - GetFromBigBuf(trace, USB_CMD_DATA_SIZE, 0, &response, -1, false); - traceLen = response.arg[2]; - if (traceLen > USB_CMD_DATA_SIZE) { - uint8_t *p = realloc(trace, traceLen); - if (p == NULL) { - PrintAndLog("Cannot allocate memory for trace"); - free(trace); - return 2; - } - trace = p; - GetFromBigBuf(trace, traceLen, 0, NULL, -1, false); - } - } - - if (saveToFile) { - FILE *tracefile = NULL; - if ((tracefile = fopen(filename,"wb")) == NULL) { - PrintAndLog("Could not create file %s", filename); - return 1; - } - fwrite(trace, 1, traceLen, tracefile); - PrintAndLog("Recorded Activity (TraceLen = %d bytes) written to file %s", traceLen, filename); - fclose(tracefile); - } else { - PrintAndLog("Recorded Activity (TraceLen = %d bytes)", traceLen); - PrintAndLog(""); - PrintAndLog("Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer"); - PrintAndLog(""); - PrintAndLog(" Start | End | Src | Data (! denotes parity error) | CRC | Annotation |"); - PrintAndLog("------------|------------|-----|-------------------------------------------------------------------------|-----|--------------------|"); - - while(tracepos < traceLen) - { - tracepos = printScTraceLine(tracepos, traceLen, trace); - } - } - - free(trace); +int CmdSmartList(const char *Cmd) { + CmdHFList("7816"); return 0; } -int CmdSmartList(const char *Cmd) { - ScTraceList(Cmd); +int CmdSmartBruteforceSFI(const char *Cmd) { + + char ctmp = tolower(param_getchar(Cmd, 0)); + if (ctmp == 'h') return usage_sm_brute(); + + uint8_t data[5] = {0x00, 0xB2, 0x00, 0x00, 0x00}; + + PrintAndLogEx(INFO, "Selecting card"); + if ( !smart_select(false) ) { + return 1; + } + + PrintAndLogEx(INFO, "Selecting PPSE aid"); + CmdSmartRaw("d 00a404000e325041592e5359532e444446303100"); + CmdSmartRaw("d 00a4040007a000000004101000"); + + PrintAndLogEx(INFO, "starting"); + + UsbCommand c = {CMD_SMART_RAW, {SC_RAW, sizeof(data), 0}}; + uint8_t* buf = malloc(USB_CMD_DATA_SIZE); + if ( !buf ) + return 1; + + for (uint8_t i=1; i < 4; i++) { + for (int p1=1; p1 < 5; p1++) { + + data[2] = p1; + data[3] = (i << 3) + 4; + + memcpy(c.d.asBytes, data, sizeof(data) ); + clearCommandBuffer(); + SendCommand(&c); + + smart_response(buf); + + // if 0x6C + if ( buf[0] == 0x6C ) { + data[4] = buf[1]; + + memcpy(c.d.asBytes, data, sizeof(data) ); + clearCommandBuffer(); + SendCommand(&c); + uint8_t len = smart_response(buf); + + // TLV decoder + if (len > 4) + TLVPrintFromBuffer(buf+1, len-3); + + data[4] = 0; + } + memset(buf, 0x00, USB_CMD_DATA_SIZE); + } + } + free(buf); return 0; } static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help"}, - {"list", CmdSmartList, 0, "List ISO 7816 history"}, - {"info", CmdSmartInfo, 1, "Tag information [rdv40]"}, - {"reader", CmdSmartReader, 1, "Act like an IS07816 reader [rdv40]"}, - {"raw", CmdSmartRaw, 1, "Send raw hex data to tag [rdv40]"}, - {"upgrade", CmdSmartUpgrade, 1, "Upgrade firmware [rdv40]"}, - {"setclock",CmdSmartSetClock, 1, "Set clock speed"}, + {"help", CmdHelp, 1, "This help"}, + {"list", CmdSmartList, 0, "List ISO 7816 history"}, + {"info", CmdSmartInfo, 1, "Tag information"}, + {"reader", CmdSmartReader, 1, "Act like an IS07816 reader"}, + {"raw", CmdSmartRaw, 1, "Send raw hex data to tag"}, + {"upgrade", CmdSmartUpgrade, 1, "Upgrade firmware"}, + {"setclock", CmdSmartSetClock, 1, "Set clock speed"}, + {"brute", CmdSmartBruteforceSFI, 1, "Bruteforce SFI"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdsmartcard.h b/client/cmdsmartcard.h index caa06f4f..3a4c7956 100644 --- a/client/cmdsmartcard.h +++ b/client/cmdsmartcard.h @@ -11,19 +11,8 @@ #ifndef CMDSMARTCARD_H__ #define CMDSMARTCARD_H__ -#include -#include -#include -#include -#include "proxmark3.h" -#include "ui.h" -#include "cmdparser.h" -#include "common.h" -#include "util.h" -#include "loclass/fileutils.h" // saveFile -#include "cmdmain.h" // getfromdevice -#include "emv/emvcore.h" // decodeTVL -#include "emv/apduinfo.h" // APDUcode description +#include +#include extern int CmdSmartcard(const char *Cmd); @@ -32,8 +21,6 @@ extern int CmdSmartUpgrade(const char* cmd); extern int CmdSmartInfo(const char* cmd); extern int CmdSmartReader(const char *Cmd); -extern int usage_sm_raw(void); -extern int usage_sm_reader(void); -extern int usage_sm_info(void); -extern int usage_sm_upgrade(void); +extern int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); + #endif diff --git a/client/emv/cmdemv.c b/client/emv/cmdemv.c index d886834d..cb42e8f7 100644 --- a/client/emv/cmdemv.c +++ b/client/emv/cmdemv.c @@ -38,13 +38,13 @@ void ParamLoadDefaults(struct tlvdb *tlvRoot) { TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC } -int CmdHFEMVSelect(const char *cmd) { +int CmdEMVSelect(const char *cmd) { uint8_t data[APDU_AID_LEN] = {0}; int datalen = 0; - CLIParserInit("hf emv select", + CLIParserInit("emv select", "Executes select applet command", - "Usage:\n\thf emv select -s a00000000101 -> select card, select applet\n\thf emv select -st a00000000101 -> select card, select applet, show result in TLV\n"); + "Usage:\n\temv select -s a00000000101 -> select card, select applet\n\temv select -st a00000000101 -> select card, select applet, show result in TLV\n"); void* argtable[] = { arg_param_begin, @@ -52,6 +52,9 @@ int CmdHFEMVSelect(const char *cmd) { arg_lit0("kK", "keep", "keep field for next command"), arg_lit0("aA", "apdu", "show APDU reqests and responses"), arg_lit0("tT", "tlv", "TLV decode results"), +#ifdef WITH_SMARTCARD + arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."), +#endif arg_strx0(NULL, NULL, "", NULL), arg_param_end }; @@ -61,7 +64,14 @@ int CmdHFEMVSelect(const char *cmd) { bool leaveSignalON = arg_get_lit(2); bool APDULogging = arg_get_lit(3); bool decodeTLV = arg_get_lit(4); + EMVCommandChannel channel = ECC_CONTACTLESS; +#ifdef WITH_SMARTCARD + if (arg_get_lit(5)) + channel = ECC_CONTACT; + CLIGetHexWithReturn(6, data, &datalen); +#else CLIGetHexWithReturn(5, data, &datalen); +#endif CLIParserFree(); SetAPDULogging(APDULogging); @@ -70,10 +80,10 @@ int CmdHFEMVSelect(const char *cmd) { uint8_t buf[APDU_RES_LEN] = {0}; size_t len = 0; uint16_t sw = 0; - int res = EMVSelect(activateField, leaveSignalON, data, datalen, buf, sizeof(buf), &len, &sw, NULL); + int res = EMVSelect(channel, activateField, leaveSignalON, data, datalen, buf, sizeof(buf), &len, &sw, NULL); if (sw) - PrintAndLog("APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + PrintAndLogEx(INFO, "APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); if (res) return res; @@ -84,11 +94,11 @@ int CmdHFEMVSelect(const char *cmd) { return 0; } -int CmdHFEMVSearch(const char *cmd) { +int CmdEMVSearch(const char *cmd) { - CLIParserInit("hf emv search", + CLIParserInit("emv search", "Tries to select all applets from applet list:\n", - "Usage:\n\thf emv search -s -> select card and search\n\thf emv search -st -> select card, search and show result in TLV\n"); + "Usage:\n\temv search -s -> select card and search\n\temv search -st -> select card, search and show result in TLV\n"); void* argtable[] = { arg_param_begin, @@ -96,6 +106,9 @@ int CmdHFEMVSearch(const char *cmd) { arg_lit0("kK", "keep", "keep field ON for next command"), arg_lit0("aA", "apdu", "show APDU reqests and responses"), arg_lit0("tT", "tlv", "TLV decode results of selected applets"), +#ifdef WITH_SMARTCARD + arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."), +#endif arg_param_end }; CLIExecWithReturn(cmd, argtable, true); @@ -104,6 +117,11 @@ int CmdHFEMVSearch(const char *cmd) { bool leaveSignalON = arg_get_lit(2); bool APDULogging = arg_get_lit(3); bool decodeTLV = arg_get_lit(4); + EMVCommandChannel channel = ECC_CONTACTLESS; +#ifdef WITH_SMARTCARD + if (arg_get_lit(5)) + channel = ECC_CONTACT; +#endif CLIParserFree(); SetAPDULogging(APDULogging); @@ -112,12 +130,12 @@ int CmdHFEMVSearch(const char *cmd) { const char *al = "Applets list"; t = tlvdb_fixed(1, strlen(al), (const unsigned char *)al); - if (EMVSearch(activateField, leaveSignalON, decodeTLV, t)) { + if (EMVSearch(channel, activateField, leaveSignalON, decodeTLV, t)) { tlvdb_free(t); return 2; } - PrintAndLog("Search completed."); + PrintAndLogEx(SUCCESS, "Search completed."); // print list here if (!decodeTLV) { @@ -129,11 +147,11 @@ int CmdHFEMVSearch(const char *cmd) { return 0; } -int CmdHFEMVPPSE(const char *cmd) { +int CmdEMVPPSE(const char *cmd) { - CLIParserInit("hf emv pse", + CLIParserInit("emv pse", "Executes PSE/PPSE select command. It returns list of applet on the card:\n", - "Usage:\n\thf emv pse -s1 -> select, get pse\n\thf emv pse -st2 -> select, get ppse, show result in TLV\n"); + "Usage:\n\temv pse -s1 -> select, get pse\n\temv pse -st2 -> select, get ppse, show result in TLV\n"); void* argtable[] = { arg_param_begin, @@ -143,6 +161,9 @@ int CmdHFEMVPPSE(const char *cmd) { arg_lit0("2", "ppse", "ppse (2PAY.SYS.DDF01) mode (default mode)"), arg_lit0("aA", "apdu", "show APDU reqests and responses"), arg_lit0("tT", "tlv", "TLV decode results of selected applets"), +#ifdef WITH_SMARTCARD + arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."), +#endif arg_param_end }; CLIExecWithReturn(cmd, argtable, true); @@ -156,7 +177,12 @@ int CmdHFEMVPPSE(const char *cmd) { PSENum = 2; bool APDULogging = arg_get_lit(5); bool decodeTLV = arg_get_lit(6); - CLIParserFree(); + EMVCommandChannel channel = ECC_CONTACTLESS; +#ifdef WITH_SMARTCARD + if (arg_get_lit(7)) + channel = ECC_CONTACT; +#endif + CLIParserFree(); SetAPDULogging(APDULogging); @@ -164,10 +190,10 @@ int CmdHFEMVPPSE(const char *cmd) { uint8_t buf[APDU_RES_LEN] = {0}; size_t len = 0; uint16_t sw = 0; - int res = EMVSelectPSE(activateField, leaveSignalON, PSENum, buf, sizeof(buf), &len, &sw); + int res = EMVSelectPSE(channel, activateField, leaveSignalON, PSENum, buf, sizeof(buf), &len, &sw); if (sw) - PrintAndLog("APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + PrintAndLogEx(INFO, "APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); if (res) return res; @@ -179,15 +205,15 @@ int CmdHFEMVPPSE(const char *cmd) { return 0; } -int CmdHFEMVGPO(const char *cmd) { +int CmdEMVGPO(const char *cmd) { uint8_t data[APDU_RES_LEN] = {0}; int datalen = 0; - CLIParserInit("hf emv gpo", + CLIParserInit("emv gpo", "Executes Get Processing Options command. It returns data in TLV format (0x77 - format2) or plain format (0x80 - format1).\nNeeds a EMV applet to be selected.", - "Usage:\n\thf emv gpo -k -> execute GPO\n" - "\thf emv gpo -t 01020304 -> execute GPO with 4-byte PDOL data, show result in TLV\n" - "\thf emv gpo -pmt 9F 37 04 -> load params from file, make PDOL data from PDOL, execute GPO with PDOL, show result in TLV\n"); + "Usage:\n\temv gpo -k -> execute GPO\n" + "\temv gpo -t 01020304 -> execute GPO with 4-byte PDOL data, show result in TLV\n" + "\temv gpo -pmt 9F 37 04 -> load params from file, make PDOL data from PDOL, execute GPO with PDOL, show result in TLV\n"); void* argtable[] = { arg_param_begin, @@ -196,6 +222,9 @@ int CmdHFEMVGPO(const char *cmd) { arg_lit0("mM", "make", "make PDOLdata from PDOL (tag 9F38) and parameters (by default uses default parameters)"), arg_lit0("aA", "apdu", "show APDU reqests and responses"), arg_lit0("tT", "tlv", "TLV decode results of selected applets"), +#ifdef WITH_SMARTCARD + arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."), +#endif arg_strx0(NULL, NULL, "", NULL), arg_param_end }; @@ -206,8 +235,15 @@ int CmdHFEMVGPO(const char *cmd) { bool dataMakeFromPDOL = arg_get_lit(3); bool APDULogging = arg_get_lit(4); bool decodeTLV = arg_get_lit(5); + EMVCommandChannel channel = ECC_CONTACTLESS; +#ifdef WITH_SMARTCARD + if (arg_get_lit(6)) + channel = ECC_CONTACT; + CLIGetHexWithReturn(7, data, &datalen); +#else CLIGetHexWithReturn(6, data, &datalen); - CLIParserFree(); +#endif + CLIParserFree(); SetAPDULogging(APDULogging); @@ -226,19 +262,19 @@ int CmdHFEMVGPO(const char *cmd) { ParamLoadDefaults(tlvRoot); if (paramsLoadFromFile) { - PrintAndLog("Params loading from file..."); + PrintAndLogEx(INFO, "Params loading from file..."); ParamLoadFromJson(tlvRoot); }; pdol_data_tlv = dol_process((const struct tlv *)tlvdb_external(0x9f38, datalen, data), tlvRoot, 0x83); if (!pdol_data_tlv){ - PrintAndLog("ERROR: can't create PDOL TLV."); + PrintAndLogEx(ERR, "Can't create PDOL TLV."); tlvdb_free(tlvRoot); return 4; } } else { if (paramsLoadFromFile) { - PrintAndLog("WARNING: don't need to load parameters. Sending plain PDOL data..."); + PrintAndLogEx(WARNING, "Don't need to load parameters. Sending plain PDOL data..."); } pdol_data_tlv = &data_tlv; } @@ -246,24 +282,24 @@ int CmdHFEMVGPO(const char *cmd) { size_t pdol_data_tlv_data_len = 0; unsigned char *pdol_data_tlv_data = tlv_encode(pdol_data_tlv, &pdol_data_tlv_data_len); if (!pdol_data_tlv_data) { - PrintAndLog("ERROR: can't create PDOL data."); + PrintAndLogEx(ERR, "Can't create PDOL data."); tlvdb_free(tlvRoot); return 4; } - PrintAndLog("PDOL data[%d]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len)); + PrintAndLogEx(INFO, "PDOL data[%d]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len)); // exec uint8_t buf[APDU_RES_LEN] = {0}; size_t len = 0; uint16_t sw = 0; - int res = EMVGPO(leaveSignalON, pdol_data_tlv_data, pdol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot); + int res = EMVGPO(channel, leaveSignalON, pdol_data_tlv_data, pdol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot); if (pdol_data_tlv != &data_tlv) free(pdol_data_tlv); tlvdb_free(tlvRoot); if (sw) - PrintAndLog("APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + PrintAndLogEx(INFO, "APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); if (res) return res; @@ -274,19 +310,22 @@ int CmdHFEMVGPO(const char *cmd) { return 0; } -int CmdHFEMVReadRecord(const char *cmd) { +int CmdEMVReadRecord(const char *cmd) { uint8_t data[APDU_RES_LEN] = {0}; int datalen = 0; - CLIParserInit("hf emv readrec", + CLIParserInit("emv readrec", "Executes Read Record command. It returns data in TLV format.\nNeeds a bank applet to be selected and sometimes needs GPO to be executed.", - "Usage:\n\thf emv readrec -k 0101 -> read file SFI=01, SFIrec=01\n\thf emv readrec -kt 0201-> read file 0201 and show result in TLV\n"); + "Usage:\n\temv readrec -k 0101 -> read file SFI=01, SFIrec=01\n\temv readrec -kt 0201-> read file 0201 and show result in TLV\n"); void* argtable[] = { arg_param_begin, arg_lit0("kK", "keep", "keep field ON for next command"), arg_lit0("aA", "apdu", "show APDU reqests and responses"), arg_lit0("tT", "tlv", "TLV decode results of selected applets"), +#ifdef WITH_SMARTCARD + arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."), +#endif arg_strx1(NULL, NULL, "", NULL), arg_param_end }; @@ -295,11 +334,18 @@ int CmdHFEMVReadRecord(const char *cmd) { bool leaveSignalON = arg_get_lit(1); bool APDULogging = arg_get_lit(2); bool decodeTLV = arg_get_lit(3); + EMVCommandChannel channel = ECC_CONTACTLESS; +#ifdef WITH_SMARTCARD + if (arg_get_lit(4)) + channel = ECC_CONTACT; + CLIGetHexWithReturn(5, data, &datalen); +#else CLIGetHexWithReturn(4, data, &datalen); +#endif CLIParserFree(); if (datalen != 2) { - PrintAndLog("ERROR: Command needs to have 2 bytes of data"); + PrintAndLogEx(ERROR, "Command needs to have 2 bytes of data"); return 1; } @@ -309,10 +355,10 @@ int CmdHFEMVReadRecord(const char *cmd) { uint8_t buf[APDU_RES_LEN] = {0}; size_t len = 0; uint16_t sw = 0; - int res = EMVReadRecord(leaveSignalON, data[0], data[1], buf, sizeof(buf), &len, &sw, NULL); + int res = EMVReadRecord(channel, leaveSignalON, data[0], data[1], buf, sizeof(buf), &len, &sw, NULL); if (sw) - PrintAndLog("APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + PrintAndLogEx(INFO, "APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); if (res) return res; @@ -324,16 +370,16 @@ int CmdHFEMVReadRecord(const char *cmd) { return 0; } -int CmdHFEMVAC(const char *cmd) { +int CmdEMVAC(const char *cmd) { uint8_t data[APDU_RES_LEN] = {0}; int datalen = 0; - CLIParserInit("hf emv genac", + CLIParserInit("emv genac", "Generate Application Cryptogram command. It returns data in TLV format .\nNeeds a EMV applet to be selected and GPO to be executed.", - "Usage:\n\thf emv genac -k 0102 -> generate AC with 2-byte CDOLdata and keep field ON after command\n" - "\thf emv genac -t 01020304 -> generate AC with 4-byte CDOL data, show result in TLV\n" - "\thf emv genac -Daac 01020304 -> generate AC with 4-byte CDOL data and terminal decision 'declined'\n" - "\thf emv genac -pmt 9F 37 04 -> load params from file, make CDOL data from CDOL, generate AC with CDOL, show result in TLV"); + "Usage:\n\temv genac -k 0102 -> generate AC with 2-byte CDOLdata and keep field ON after command\n" + "\temv genac -t 01020304 -> generate AC with 4-byte CDOL data, show result in TLV\n" + "\temv genac -Daac 01020304 -> generate AC with 4-byte CDOL data and terminal decision 'declined'\n" + "\temv genac -pmt 9F 37 04 -> load params from file, make CDOL data from CDOL, generate AC with CDOL, show result in TLV"); void* argtable[] = { arg_param_begin, @@ -344,6 +390,9 @@ int CmdHFEMVAC(const char *cmd) { arg_lit0("mM", "make", "make CDOLdata from CDOL (tag 8C and 8D) and parameters (by default uses default parameters)"), arg_lit0("aA", "apdu", "show APDU reqests and responses"), arg_lit0("tT", "tlv", "TLV decode results of selected applets"), +#ifdef WITH_SMARTCARD + arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."), +#endif arg_strx1(NULL, NULL, "", NULL), arg_param_end }; @@ -373,8 +422,15 @@ int CmdHFEMVAC(const char *cmd) { bool dataMakeFromCDOL = arg_get_lit(5); bool APDULogging = arg_get_lit(6); bool decodeTLV = arg_get_lit(7); + EMVCommandChannel channel = ECC_CONTACTLESS; +#ifdef WITH_SMARTCARD + if (arg_get_lit(8)) + channel = ECC_CONTACT; + CLIGetHexWithReturn(9, data, &datalen); +#else CLIGetHexWithReturn(8, data, &datalen); - CLIParserFree(); +#endif + CLIParserFree(); SetAPDULogging(APDULogging); @@ -394,37 +450,37 @@ int CmdHFEMVAC(const char *cmd) { ParamLoadDefaults(tlvRoot); if (paramsLoadFromFile) { - PrintAndLog("Params loading from file..."); + PrintAndLogEx(INFO, "Params loading from file..."); ParamLoadFromJson(tlvRoot); }; cdol_data_tlv = dol_process((const struct tlv *)tlvdb_external(0x8c, datalen, data), tlvRoot, 0x01); // 0x01 - dummy tag if (!cdol_data_tlv){ - PrintAndLog("ERROR: can't create CDOL TLV."); + PrintAndLogEx(ERR, "Can't create CDOL TLV."); tlvdb_free(tlvRoot); return 4; } } else { if (paramsLoadFromFile) { - PrintAndLog("WARNING: don't need to load parameters. Sending plain CDOL data..."); + PrintAndLogEx(WARNING, "Don't need to load parameters. Sending plain CDOL data..."); } cdol_data_tlv = &data_tlv; } - PrintAndLog("CDOL data[%d]: %s", cdol_data_tlv->len, sprint_hex(cdol_data_tlv->value, cdol_data_tlv->len)); + PrintAndLogEx(INFO, "CDOL data[%d]: %s", cdol_data_tlv->len, sprint_hex(cdol_data_tlv->value, cdol_data_tlv->len)); // exec uint8_t buf[APDU_RES_LEN] = {0}; size_t len = 0; uint16_t sw = 0; - int res = EMVAC(leaveSignalON, termDecision, (uint8_t *)cdol_data_tlv->value, cdol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot); + int res = EMVAC(channel, leaveSignalON, termDecision, (uint8_t *)cdol_data_tlv->value, cdol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot); if (cdol_data_tlv != &data_tlv) free(cdol_data_tlv); tlvdb_free(tlvRoot); if (sw) - PrintAndLog("APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + PrintAndLogEx(INFO, "APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); if (res) return res; @@ -432,26 +488,34 @@ int CmdHFEMVAC(const char *cmd) { if (decodeTLV) TLVPrintFromBuffer(buf, len); - return 0; + return 0; } -int CmdHFEMVGenerateChallenge(const char *cmd) { +int CmdEMVGenerateChallenge(const char *cmd) { - CLIParserInit("hf emv challenge", + CLIParserInit("emv challenge", "Executes Generate Challenge command. It returns 4 or 8-byte random number from card.\nNeeds a EMV applet to be selected and GPO to be executed.", - "Usage:\n\thf emv challenge -> get challenge\n\thf emv challenge -k -> get challenge, keep fileld ON\n"); + "Usage:\n\temv challenge -> get challenge\n\temv challenge -k -> get challenge, keep fileld ON\n"); void* argtable[] = { arg_param_begin, arg_lit0("kK", "keep", "keep field ON for next command"), arg_lit0("aA", "apdu", "show APDU reqests and responses"), +#ifdef WITH_SMARTCARD + arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."), +#endif arg_param_end }; CLIExecWithReturn(cmd, argtable, true); bool leaveSignalON = arg_get_lit(1); bool APDULogging = arg_get_lit(2); - CLIParserFree(); + EMVCommandChannel channel = ECC_CONTACTLESS; +#ifdef WITH_SMARTCARD + if (arg_get_lit(3)) + channel = ECC_CONTACT; +#endif + CLIParserFree(); SetAPDULogging(APDULogging); @@ -459,31 +523,31 @@ int CmdHFEMVGenerateChallenge(const char *cmd) { uint8_t buf[APDU_RES_LEN] = {0}; size_t len = 0; uint16_t sw = 0; - int res = EMVGenerateChallenge(leaveSignalON, buf, sizeof(buf), &len, &sw, NULL); + int res = EMVGenerateChallenge(channel, leaveSignalON, buf, sizeof(buf), &len, &sw, NULL); if (sw) - PrintAndLog("APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + PrintAndLogEx(INFO, "APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); if (res) return res; - PrintAndLog("Challenge: %s", sprint_hex(buf, len)); + PrintAndLogEx(SUCCESS, "Challenge: %s", sprint_hex(buf, len)); if (len != 4 && len != 8) - PrintAndLog("WARNING: length of challenge must be 4 or 8, but it %d", len); + PrintAndLogEx(WARNING, "Length of challenge must be 4 or 8, but it %d", len); return 0; } -int CmdHFEMVInternalAuthenticate(const char *cmd) { +int CmdEMVInternalAuthenticate(const char *cmd) { uint8_t data[APDU_RES_LEN] = {0}; int datalen = 0; - CLIParserInit("hf emv intauth", + CLIParserInit("emv intauth", "Generate Internal Authenticate command. Usually needs 4-byte random number. It returns data in TLV format .\nNeeds a EMV applet to be selected and GPO to be executed.", - "Usage:\n\thf emv intauth -k 01020304 -> execute Internal Authenticate with 4-byte DDOLdata and keep field ON after command\n" - "\thf emv intauth -t 01020304 -> execute Internal Authenticate with 4-byte DDOL data, show result in TLV\n" - "\thf emv intauth -pmt 9F 37 04 -> load params from file, make DDOL data from DDOL, Internal Authenticate with DDOL, show result in TLV"); + "Usage:\n\temv intauth -k 01020304 -> execute Internal Authenticate with 4-byte DDOLdata and keep field ON after command\n" + "\temv intauth -t 01020304 -> execute Internal Authenticate with 4-byte DDOL data, show result in TLV\n" + "\temv intauth -pmt 9F 37 04 -> load params from file, make DDOL data from DDOL, Internal Authenticate with DDOL, show result in TLV"); void* argtable[] = { arg_param_begin, @@ -492,6 +556,9 @@ int CmdHFEMVInternalAuthenticate(const char *cmd) { arg_lit0("mM", "make", "make DDOLdata from DDOL (tag 9F49) and parameters (by default uses default parameters)"), arg_lit0("aA", "apdu", "show APDU reqests and responses"), arg_lit0("tT", "tlv", "TLV decode results of selected applets"), +#ifdef WITH_SMARTCARD + arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."), +#endif arg_strx1(NULL, NULL, "", NULL), arg_param_end }; @@ -502,8 +569,15 @@ int CmdHFEMVInternalAuthenticate(const char *cmd) { bool dataMakeFromDDOL = arg_get_lit(3); bool APDULogging = arg_get_lit(4); bool decodeTLV = arg_get_lit(5); + EMVCommandChannel channel = ECC_CONTACTLESS; +#ifdef WITH_SMARTCARD + if (arg_get_lit(6)) + channel = ECC_CONTACT; + CLIGetHexWithReturn(7, data, &datalen); +#else CLIGetHexWithReturn(6, data, &datalen); - CLIParserFree(); +#endif + CLIParserFree(); SetAPDULogging(APDULogging); @@ -523,37 +597,37 @@ int CmdHFEMVInternalAuthenticate(const char *cmd) { ParamLoadDefaults(tlvRoot); if (paramsLoadFromFile) { - PrintAndLog("Params loading from file..."); + PrintAndLogEx(INFO, "Params loading from file..."); ParamLoadFromJson(tlvRoot); }; ddol_data_tlv = dol_process((const struct tlv *)tlvdb_external(0x9f49, datalen, data), tlvRoot, 0x01); // 0x01 - dummy tag if (!ddol_data_tlv){ - PrintAndLog("ERROR: can't create DDOL TLV."); + PrintAndLogEx(ERR, "Can't create DDOL TLV."); tlvdb_free(tlvRoot); return 4; } } else { if (paramsLoadFromFile) { - PrintAndLog("WARNING: don't need to load parameters. Sending plain DDOL data..."); + PrintAndLogEx(WARNING, "Don't need to load parameters. Sending plain DDOL data..."); } ddol_data_tlv = &data_tlv; } - PrintAndLog("DDOL data[%d]: %s", ddol_data_tlv->len, sprint_hex(ddol_data_tlv->value, ddol_data_tlv->len)); + PrintAndLogEx(INFO, "DDOL data[%d]: %s", ddol_data_tlv->len, sprint_hex(ddol_data_tlv->value, ddol_data_tlv->len)); // exec uint8_t buf[APDU_RES_LEN] = {0}; size_t len = 0; uint16_t sw = 0; - int res = EMVInternalAuthenticate(leaveSignalON, data, datalen, buf, sizeof(buf), &len, &sw, NULL); + int res = EMVInternalAuthenticate(channel, leaveSignalON, data, datalen, buf, sizeof(buf), &len, &sw, NULL); if (ddol_data_tlv != &data_tlv) free(ddol_data_tlv); - tlvdb_free(tlvRoot); + tlvdb_free(tlvRoot); if (sw) - PrintAndLog("APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + PrintAndLogEx(INFO, "APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); if (res) return res; @@ -561,7 +635,7 @@ int CmdHFEMVInternalAuthenticate(const char *cmd) { if (decodeTLV) TLVPrintFromBuffer(buf, len); - return 0; + return 0; } #define dreturn(n) {free(pdol_data_tlv);tlvdb_free(tlvSelect);tlvdb_free(tlvRoot);DropField();return n;} @@ -607,13 +681,13 @@ void ProcessGPOResponseFormat1(struct tlvdb *tlvRoot, uint8_t *buf, size_t len, } if (len < 4 || (len - 4) % 4) { - PrintAndLog("ERROR: GPO response format1 parsing error. length=%d", len); + PrintAndLogEx(ERR, "GPO response format1 parsing error. length=%d", len); } else { // AIP struct tlvdb * f1AIP = tlvdb_fixed(0x82, 2, buf + 2); tlvdb_add(tlvRoot, f1AIP); if (decodeTLV){ - PrintAndLog("\n* * Decode response format 1 (0x80) AIP and AFL:"); + PrintAndLogEx(INFO, "\n* * Decode response format 1 (0x80) AIP and AFL:"); TLVPrintFromTLV(f1AIP); } @@ -622,14 +696,14 @@ void ProcessGPOResponseFormat1(struct tlvdb *tlvRoot, uint8_t *buf, size_t len, tlvdb_add(tlvRoot, f1AFL); if (decodeTLV) TLVPrintFromTLV(f1AFL); - } + } } else { if (decodeTLV) TLVPrintFromBuffer(buf, len); } } -int CmdHFEMVExec(const char *cmd) { +int CmdEMVExec(const char *cmd) { uint8_t buf[APDU_RES_LEN] = {0}; size_t len = 0; uint16_t sw = 0; @@ -644,10 +718,10 @@ int CmdHFEMVExec(const char *cmd) { struct tlvdb *tlvRoot = NULL; struct tlv *pdol_data_tlv = NULL; - CLIParserInit("hf emv exec", + CLIParserInit("emv exec", "Executes EMV contactless transaction", - "Usage:\n\thf emv exec -sat -> select card, execute MSD transaction, show APDU and TLV\n" - "\thf emv exec -satc -> select card, execute CDA transaction, show APDU and TLV\n"); + "Usage:\n\temv exec -sat -> select card, execute MSD transaction, show APDU and TLV\n" + "\temv exec -satc -> select card, execute CDA transaction, show APDU and TLV\n"); void* argtable[] = { arg_param_begin, @@ -661,6 +735,9 @@ int CmdHFEMVExec(const char *cmd) { arg_lit0("cC", "qvsdccda", "Transaction type - qVSDC or M/Chip plus CDA (SDAD generation)."), arg_lit0("xX", "vsdc", "Transaction type - VSDC. For test only. Not a standart behavior."), arg_lit0("gG", "acgpo", "VISA. generate AC from GPO."), +#ifdef WITH_SMARTCARD + arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."), +#endif arg_param_end }; CLIExecWithReturn(cmd, argtable, true); @@ -672,14 +749,19 @@ int CmdHFEMVExec(const char *cmd) { bool forceSearch = arg_get_lit(5); enum TransactionType TrType = TT_MSD; - if (arg_get_lit(6)) - TrType = TT_QVSDCMCHIP; if (arg_get_lit(7)) - TrType = TT_CDA; + TrType = TT_QVSDCMCHIP; if (arg_get_lit(8)) + TrType = TT_CDA; + if (arg_get_lit(9)) TrType = TT_VSDC; - bool GenACGPO = arg_get_lit(9); + bool GenACGPO = arg_get_lit(10); + EMVCommandChannel channel = ECC_CONTACTLESS; +#ifdef WITH_SMARTCARD + if (arg_get_lit(11)) + channel = ECC_CONTACT; +#endif CLIParserFree(); SetAPDULogging(showAPDU); @@ -692,12 +774,12 @@ int CmdHFEMVExec(const char *cmd) { // https://www.openscdp.org/scripts/tutorial/emv/applicationselection.html if (!forceSearch) { // PPSE - PrintAndLog("\n* PPSE."); + PrintAndLogEx(NORMAL, "\n* PPSE."); SetAPDULogging(showAPDU); - res = EMVSearchPSE(activateField, true, decodeTLV, tlvSelect); + res = EMVSearchPSE(channel, activateField, true, decodeTLV, tlvSelect); // check PPSE and select application id - if (!res) { + if (!res) { TLVPrintAIDlistFromSelectTLV(tlvSelect); EMVSelectApplication(tlvSelect, AID, &AIDlen); } @@ -705,9 +787,9 @@ int CmdHFEMVExec(const char *cmd) { // Search if (!AIDlen) { - PrintAndLog("\n* Search AID in list."); + PrintAndLogEx(NORMAL, "\n* Search AID in list."); SetAPDULogging(false); - if (EMVSearch(activateField, true, decodeTLV, tlvSelect)) { + if (EMVSearch(channel, activateField, true, decodeTLV, tlvSelect)) { dreturn(2); } @@ -722,51 +804,51 @@ int CmdHFEMVExec(const char *cmd) { // check if we found EMV application on card if (!AIDlen) { - PrintAndLog("Can't select AID. EMV AID not found"); + PrintAndLogEx(WARNING, "Can't select AID. EMV AID not found"); dreturn(2); } // Select - PrintAndLog("\n* Selecting AID:%s", sprint_hex_inrow(AID, AIDlen)); + PrintAndLogEx(NORMAL, "\n* Selecting AID:%s", sprint_hex_inrow(AID, AIDlen)); SetAPDULogging(showAPDU); - res = EMVSelect(false, true, AID, AIDlen, buf, sizeof(buf), &len, &sw, tlvRoot); + res = EMVSelect(channel, false, true, AID, AIDlen, buf, sizeof(buf), &len, &sw, tlvRoot); - if (res) { - PrintAndLog("Can't select AID (%d). Exit...", res); + if (res) { + PrintAndLogEx(WARNING, "Can't select AID (%d). Exit...", res); dreturn(3); } if (decodeTLV) TLVPrintFromBuffer(buf, len); - PrintAndLog("* Selected."); + PrintAndLogEx(INFO, "* Selected."); - PrintAndLog("\n* Init transaction parameters."); + PrintAndLogEx(INFO, "\n* Init transaction parameters."); InitTransactionParameters(tlvRoot, paramLoadJSON, TrType, GenACGPO); TLVPrintFromTLV(tlvRoot); // TODO delete!!! - PrintAndLog("\n* Calc PDOL."); + PrintAndLogEx(NORMAL, "\n* Calc PDOL."); pdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x9f38, NULL), tlvRoot, 0x83); if (!pdol_data_tlv){ - PrintAndLog("ERROR: can't create PDOL TLV."); + PrintAndLogEx(WARNING, "Error: can't create PDOL TLV."); dreturn(4); } size_t pdol_data_tlv_data_len; unsigned char *pdol_data_tlv_data = tlv_encode(pdol_data_tlv, &pdol_data_tlv_data_len); if (!pdol_data_tlv_data) { - PrintAndLog("ERROR: can't create PDOL data."); + PrintAndLogEx(WARNING, "Error: can't create PDOL data."); dreturn(4); } - PrintAndLog("PDOL data[%d]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len)); + PrintAndLogEx(NORMAL, "PDOL data[%d]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len)); - PrintAndLog("\n* GPO."); - res = EMVGPO(true, pdol_data_tlv_data, pdol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot); + PrintAndLogEx(NORMAL, "\n* GPO."); + res = EMVGPO(channel, true, pdol_data_tlv_data, pdol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot); free(pdol_data_tlv_data); //free(pdol_data_tlv); --- free on exit. - if (res) { - PrintAndLog("GPO error(%d): %4x. Exit...", res, sw); + if (res) { + PrintAndLogEx(NORMAL, "GPO error(%d): %4x. Exit...", res, sw); dreturn(5); } @@ -781,23 +863,23 @@ int CmdHFEMVExec(const char *cmd) { if (pan) { tlvdb_add(tlvRoot, pan); - const struct tlv *pantlv = tlvdb_get(tlvRoot, 0x5a, NULL); - PrintAndLog("\n* * Extracted PAN from track2: %s", sprint_hex(pantlv->value, pantlv->len)); + const struct tlv *pantlv = tlvdb_get(tlvRoot, 0x5a, NULL); + PrintAndLogEx(NORMAL, "\n* * Extracted PAN from track2: %s", sprint_hex(pantlv->value, pantlv->len)); } else { - PrintAndLog("\n* * WARNING: Can't extract PAN from track2."); + PrintAndLogEx(NORMAL, "\n* * WARNING: Can't extract PAN from track2."); } } } - PrintAndLog("\n* Read records from AFL."); + PrintAndLogEx(NORMAL, "\n* Read records from AFL."); const struct tlv *AFL = tlvdb_get(tlvRoot, 0x94, NULL); if (!AFL || !AFL->len) { - PrintAndLog("WARNING: AFL not found."); + PrintAndLogEx(WARNING, "AFL not found."); } while(AFL && AFL->len) { if (AFL->len % 4) { - PrintAndLog("ERROR: Wrong AFL length: %d", AFL->len); + PrintAndLogEx(WARNING, "Error: Wrong AFL length: %d", AFL->len); break; } @@ -807,24 +889,24 @@ int CmdHFEMVExec(const char *cmd) { uint8_t SFIend = AFL->value[i * 4 + 2]; uint8_t SFIoffline = AFL->value[i * 4 + 3]; - PrintAndLog("* * SFI[%02x] start:%02x end:%02x offline:%02x", SFI, SFIstart, SFIend, SFIoffline); + PrintAndLogEx(NORMAL, "* * SFI[%02x] start:%02x end:%02x offline:%02x", SFI, SFIstart, SFIend, SFIoffline); if (SFI == 0 || SFI == 31 || SFIstart == 0 || SFIstart > SFIend) { - PrintAndLog("SFI ERROR! Skipped..."); + PrintAndLogEx(NORMAL, "SFI ERROR! Skipped..."); continue; } for(int n = SFIstart; n <= SFIend; n++) { - PrintAndLog("* * * SFI[%02x] %d", SFI, n); + PrintAndLogEx(NORMAL, "* * * SFI[%02x] %d", SFI, n); - res = EMVReadRecord(true, SFI, n, buf, sizeof(buf), &len, &sw, tlvRoot); + res = EMVReadRecord(channel, true, SFI, n, buf, sizeof(buf), &len, &sw, tlvRoot); if (res) { - PrintAndLog("ERROR SFI[%02x]. APDU error %4x", SFI, sw); + PrintAndLogEx(WARNING, "Error SFI[%02x]. APDU error %4x", SFI, sw); continue; } if (decodeTLV) { TLVPrintFromBuffer(buf, len); - PrintAndLog(""); + PrintAndLogEx(NORMAL, ""); } // Build Input list for Offline Data Authentication @@ -838,7 +920,7 @@ int CmdHFEMVExec(const char *cmd) { memcpy(&ODAiList[ODAiListLen], &buf[len - elmlen], elmlen); ODAiListLen += elmlen; } else { - PrintAndLog("ERROR SFI[%02x]. Creating input list for Offline Data Authentication error.", SFI); + PrintAndLogEx(WARNING, "Error SFI[%02x]. Creating input list for Offline Data Authentication error.", SFI); } } else { memcpy(&ODAiList[ODAiListLen], buf, len); @@ -849,31 +931,36 @@ int CmdHFEMVExec(const char *cmd) { } break; - } + } // copy Input list for Offline Data Authentication if (ODAiListLen) { struct tlvdb *oda = tlvdb_fixed(0x21, ODAiListLen, ODAiList); // not a standard tag tlvdb_add(tlvRoot, oda); - PrintAndLog("* Input list for Offline Data Authentication added to TLV. len=%d \n", ODAiListLen); + PrintAndLogEx(NORMAL, "* Input list for Offline Data Authentication added to TLV. len=%d \n", ODAiListLen); } // get AIP - const struct tlv *AIPtlv = tlvdb_get(tlvRoot, 0x82, NULL); - uint16_t AIP = AIPtlv->value[0] + AIPtlv->value[1] * 0x100; - PrintAndLog("* * AIP=%04x", AIP); + uint16_t AIP = 0; + const struct tlv *AIPtlv = tlvdb_get(tlvRoot, 0x82, NULL); + if (AIPtlv) { + AIP = AIPtlv->value[0] + AIPtlv->value[1] * 0x100; + PrintAndLogEx(NORMAL, "* * AIP=%04x", AIP); + } else { + PrintAndLogEx(ERR, "Can't found AIP."); + } // SDA if (AIP & 0x0040) { - PrintAndLog("\n* SDA"); + PrintAndLogEx(NORMAL, "\n* SDA"); trSDA(tlvRoot); } // DDA if (AIP & 0x0020) { - PrintAndLog("\n* DDA"); - trDDA(decodeTLV, tlvRoot); - } + PrintAndLogEx(NORMAL, "\n* DDA"); + trDDA(channel, decodeTLV, tlvRoot); + } // transaction check @@ -882,8 +969,8 @@ int CmdHFEMVExec(const char *cmd) { // 9F26: Application Cryptogram const struct tlv *AC = tlvdb_get(tlvRoot, 0x9F26, NULL); if (AC) { - PrintAndLog("\n--> qVSDC transaction."); - PrintAndLog("* AC path"); + PrintAndLogEx(NORMAL, "\n--> qVSDC transaction."); + PrintAndLogEx(NORMAL, "* AC path"); // 9F36: Application Transaction Counter (ATC) const struct tlv *ATC = tlvdb_get(tlvRoot, 0x9F36, NULL); @@ -893,24 +980,24 @@ int CmdHFEMVExec(const char *cmd) { const struct tlv *IAD = tlvdb_get(tlvRoot, 0x9F10, NULL); // print AC data - PrintAndLog("ATC: %s", sprint_hex(ATC->value, ATC->len)); - PrintAndLog("AC: %s", sprint_hex(AC->value, AC->len)); + PrintAndLogEx(NORMAL, "ATC: %s", sprint_hex(ATC->value, ATC->len)); + PrintAndLogEx(NORMAL, "AC: %s", sprint_hex(AC->value, AC->len)); if (IAD){ - PrintAndLog("IAD: %s", sprint_hex(IAD->value, IAD->len)); + PrintAndLogEx(NORMAL, "IAD: %s", sprint_hex(IAD->value, IAD->len)); if (IAD->len >= IAD->value[0] + 1) { - PrintAndLog("\tKey index: 0x%02x", IAD->value[1]); - PrintAndLog("\tCrypto ver: 0x%02x(%03d)", IAD->value[2], IAD->value[2]); - PrintAndLog("\tCVR:", sprint_hex(&IAD->value[3], IAD->value[0] - 2)); + PrintAndLogEx(NORMAL, "\tKey index: 0x%02x", IAD->value[1]); + PrintAndLogEx(NORMAL, "\tCrypto ver: 0x%02x(%03d)", IAD->value[2], IAD->value[2]); + PrintAndLogEx(NORMAL, "\tCVR:", sprint_hex(&IAD->value[3], IAD->value[0] - 2)); struct tlvdb * cvr = tlvdb_fixed(0x20, IAD->value[0] - 2, &IAD->value[3]); TLVPrintFromTLVLev(cvr, 1); } } else { - PrintAndLog("WARNING: IAD not found."); + PrintAndLogEx(WARNING, "IAD not found."); } } else { - PrintAndLog("ERROR AC: Application Transaction Counter (ATC) not found."); + PrintAndLogEx(ERROR, "AC: Application Transaction Counter (ATC) not found."); } } } @@ -919,16 +1006,16 @@ int CmdHFEMVExec(const char *cmd) { if (GetCardPSVendor(AID, AIDlen) == CV_MASTERCARD && (TrType == TT_QVSDCMCHIP || TrType == TT_CDA)){ const struct tlv *CDOL1 = tlvdb_get(tlvRoot, 0x8c, NULL); if (CDOL1 && GetCardPSVendor(AID, AIDlen) == CV_MASTERCARD) { // and m/chip transaction flag - PrintAndLog("\n--> Mastercard M/Chip transaction."); + PrintAndLogEx(NORMAL, "\n--> Mastercard M/Chip transaction."); - PrintAndLog("* * Generate challenge"); - res = EMVGenerateChallenge(true, buf, sizeof(buf), &len, &sw, tlvRoot); + PrintAndLogEx(NORMAL, "* * Generate challenge"); + res = EMVGenerateChallenge(channel, true, buf, sizeof(buf), &len, &sw, tlvRoot); if (res) { - PrintAndLog("ERROR GetChallenge. APDU error %4x", sw); + PrintAndLogEx(WARNING, "GetChallenge. APDU error %4x", sw); dreturn(6); } if (len < 4) { - PrintAndLog("ERROR GetChallenge. Wrong challenge length %d", len); + PrintAndLogEx(WARNING, "GetChallenge. Wrong challenge length %d", len); dreturn(6); } @@ -936,24 +1023,24 @@ int CmdHFEMVExec(const char *cmd) { struct tlvdb * ICCDynN = tlvdb_fixed(0x9f4c, len, buf); tlvdb_add(tlvRoot, ICCDynN); if (decodeTLV){ - PrintAndLog("\n* * ICC Dynamic Number:"); + PrintAndLogEx(NORMAL, "\n* * ICC Dynamic Number:"); TLVPrintFromTLV(ICCDynN); } - PrintAndLog("* * Calc CDOL1"); + PrintAndLogEx(NORMAL, "* * Calc CDOL1"); struct tlv *cdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x8c, NULL), tlvRoot, 0x01); // 0x01 - dummy tag if (!cdol_data_tlv){ - PrintAndLog("ERROR: can't create CDOL1 TLV."); + PrintAndLogEx(WARNING, "Error: can't create CDOL1 TLV."); dreturn(6); } - PrintAndLog("CDOL1 data[%d]: %s", cdol_data_tlv->len, sprint_hex(cdol_data_tlv->value, cdol_data_tlv->len)); + PrintAndLogEx(NORMAL, "CDOL1 data[%d]: %s", cdol_data_tlv->len, sprint_hex(cdol_data_tlv->value, cdol_data_tlv->len)); - PrintAndLog("* * AC1"); + PrintAndLogEx(NORMAL, "* * AC1"); // EMVAC_TC + EMVAC_CDAREQ --- to get SDAD - res = EMVAC(true, (TrType == TT_CDA) ? EMVAC_TC + EMVAC_CDAREQ : EMVAC_TC, (uint8_t *)cdol_data_tlv->value, cdol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot); + res = EMVAC(channel, true, (TrType == TT_CDA) ? EMVAC_TC + EMVAC_CDAREQ : EMVAC_TC, (uint8_t *)cdol_data_tlv->value, cdol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot); - if (res) { - PrintAndLog("AC1 error(%d): %4x. Exit...", res, sw); + if (res) { + PrintAndLogEx(NORMAL, "AC1 error(%d): %4x. Exit...", res, sw); dreturn(7); } @@ -961,41 +1048,41 @@ int CmdHFEMVExec(const char *cmd) { TLVPrintFromBuffer(buf, len); // CDA - PrintAndLog("\n* CDA:"); + PrintAndLogEx(NORMAL, "\n* CDA:"); struct tlvdb *ac_tlv = tlvdb_parse_multi(buf, len); res = trCDA(tlvRoot, ac_tlv, pdol_data_tlv, cdol_data_tlv); - if (res) { - PrintAndLog("CDA error (%d)", res); + if (res) { + PrintAndLogEx(NORMAL, "CDA error (%d)", res); } free(ac_tlv); free(cdol_data_tlv); - PrintAndLog("\n* M/Chip transaction result:"); + PrintAndLogEx(NORMAL, "\n* M/Chip transaction result:"); // 9F27: Cryptogram Information Data (CID) const struct tlv *CID = tlvdb_get(tlvRoot, 0x9F27, NULL); if (CID) { emv_tag_dump(CID, stdout, 0); - PrintAndLog("------------------------------"); + PrintAndLogEx(NORMAL, "------------------------------"); if (CID->len > 0) { switch(CID->value[0] & EMVAC_AC_MASK){ case EMVAC_AAC: - PrintAndLog("Transaction DECLINED."); + PrintAndLogEx(NORMAL, "Transaction DECLINED."); break; case EMVAC_TC: - PrintAndLog("Transaction approved OFFLINE."); + PrintAndLogEx(NORMAL, "Transaction approved OFFLINE."); break; case EMVAC_ARQC: - PrintAndLog("Transaction approved ONLINE."); + PrintAndLogEx(NORMAL, "Transaction approved ONLINE."); break; default: - PrintAndLog("ERROR: CID transaction code error %2x", CID->value[0] & EMVAC_AC_MASK); + PrintAndLogEx(WARNING, "Error: CID transaction code error %2x", CID->value[0] & EMVAC_AC_MASK); break; } } else { - PrintAndLog("ERROR: Wrong CID length %d", CID->len); + PrintAndLogEx(WARNING, "Wrong CID length %d", CID->len); } } else { - PrintAndLog("ERROR: CID(9F27) not found."); + PrintAndLogEx(WARNING, "CID(9F27) not found."); } } @@ -1003,20 +1090,20 @@ int CmdHFEMVExec(const char *cmd) { // MSD if (AIP & 0x8000 && TrType == TT_MSD) { - PrintAndLog("\n--> MSD transaction."); + PrintAndLogEx(NORMAL, "\n--> MSD transaction."); - PrintAndLog("* MSD dCVV path. Check dCVV"); + PrintAndLogEx(NORMAL, "* MSD dCVV path. Check dCVV"); const struct tlv *track2 = tlvdb_get(tlvRoot, 0x57, NULL); if (track2) { - PrintAndLog("Track2: %s", sprint_hex(track2->value, track2->len)); + PrintAndLogEx(NORMAL, "Track2: %s", sprint_hex(track2->value, track2->len)); struct tlvdb *dCVV = GetdCVVRawFromTrack2(track2); - PrintAndLog("dCVV raw data:"); + PrintAndLogEx(NORMAL, "dCVV raw data:"); TLVPrintFromTLV(dCVV); if (GetCardPSVendor(AID, AIDlen) == CV_MASTERCARD) { - PrintAndLog("\n* Mastercard calculate UDOL"); + PrintAndLogEx(NORMAL, "\n* Mastercard calculate UDOL"); // UDOL (9F69) const struct tlv *UDOL = tlvdb_get(tlvRoot, 0x9F69, NULL); @@ -1027,38 +1114,37 @@ int CmdHFEMVExec(const char *cmd) { .value = (uint8_t *)"\x9f\x6a\x04", }; if (!UDOL) - PrintAndLog("Use default UDOL."); + PrintAndLogEx(NORMAL, "Use default UDOL."); struct tlv *udol_data_tlv = dol_process(UDOL ? UDOL : &defUDOL, tlvRoot, 0x01); // 0x01 - dummy tag if (!udol_data_tlv){ - PrintAndLog("ERROR: can't create UDOL TLV."); + PrintAndLogEx(WARNING, "can't create UDOL TLV."); dreturn(8); } - PrintAndLog("UDOL data[%d]: %s", udol_data_tlv->len, sprint_hex(udol_data_tlv->value, udol_data_tlv->len)); + PrintAndLogEx(NORMAL, "UDOL data[%d]: %s", udol_data_tlv->len, sprint_hex(udol_data_tlv->value, udol_data_tlv->len)); - PrintAndLog("\n* Mastercard compute cryptographic checksum(UDOL)"); + PrintAndLogEx(NORMAL, "\n* Mastercard compute cryptographic checksum(UDOL)"); - res = MSCComputeCryptoChecksum(true, (uint8_t *)udol_data_tlv->value, udol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot); + res = MSCComputeCryptoChecksum(channel, true, (uint8_t *)udol_data_tlv->value, udol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot); if (res) { - PrintAndLog("ERROR Compute Crypto Checksum. APDU error %4x", sw); + PrintAndLogEx(WARNING, "Compute Crypto Checksum. APDU error %4x", sw); free(udol_data_tlv); dreturn(9); } - if (decodeTLV) { - TLVPrintFromBuffer(buf, len); - PrintAndLog(""); - } + // Mastercard compute cryptographic checksum result + TLVPrintFromBuffer(buf, len); + PrintAndLogEx(NORMAL, ""); + free(udol_data_tlv); } } else { - PrintAndLog("ERROR MSD: Track2 data not found."); + PrintAndLogEx(WARNING, "MSD: Track2 data not found."); } } - // DropField DropField(); // Destroy TLV's @@ -1066,12 +1152,11 @@ int CmdHFEMVExec(const char *cmd) { tlvdb_free(tlvSelect); tlvdb_free(tlvRoot); - PrintAndLog("\n* Transaction completed."); - + PrintAndLogEx(NORMAL, "\n* Transaction completed."); return 0; } -int CmdHFEMVScan(const char *cmd) { +int CmdEMVScan(const char *cmd) { uint8_t AID[APDU_AID_LEN] = {0}; size_t AIDlen = 0; uint8_t buf[APDU_RES_LEN] = {0}; @@ -1081,11 +1166,11 @@ int CmdHFEMVScan(const char *cmd) { json_t *root; json_error_t error; - CLIParserInit("hf emv scan", + CLIParserInit("emv scan", "Scan EMV card and save it contents to a file.", "It executes EMV contactless transaction and saves result to a file which can be used for emulation\n" - "Usage:\n\thf emv scan -at -> scan MSD transaction mode and show APDU and TLV\n" - "\thf emv scan -c -> scan CDA transaction mode\n"); + "Usage:\n\temv scan -at -> scan MSD transaction mode and show APDU and TLV\n" + "\temv scan -c -> scan CDA transaction mode\n"); void* argtable[] = { arg_param_begin, @@ -1099,7 +1184,10 @@ int CmdHFEMVScan(const char *cmd) { arg_lit0("xX", "vsdc", "Transaction type - VSDC. For test only. Not a standart behavior."), arg_lit0("gG", "acgpo", "VISA. generate AC from GPO."), arg_lit0("mM", "merge", "Merge output file with card's data. (warning: the file may be corrupted!)"), - arg_str1(NULL, NULL, "output.json", "JSON output file name"), +#ifdef WITH_SMARTCARD + arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."), +#endif + arg_str1(NULL, NULL, "output.json", "JSON output file name"), arg_param_end }; CLIExecWithReturn(cmd, argtable, true); @@ -1119,14 +1207,27 @@ int CmdHFEMVScan(const char *cmd) { bool GenACGPO = arg_get_lit(9); bool MergeJSON = arg_get_lit(10); - uint8_t relfname[250] ={0}; + EMVCommandChannel channel = ECC_CONTACTLESS; + uint8_t relfname[250] = {0}; char *crelfname = (char *)relfname; int relfnamelen = 0; +#ifdef WITH_SMARTCARD + if (arg_get_lit(11)) + channel = ECC_CONTACT; + CLIGetStrWithReturn(12, relfname, &relfnamelen); +#else CLIGetStrWithReturn(11, relfname, &relfnamelen); +#endif CLIParserFree(); SetAPDULogging(showAPDU); + // TODO + if (channel == ECC_CONTACT) { + PrintAndLogEx(ERR, "Do not use contact interface. Exit."); + return 1; + } + // current path + file name if (!strstr(crelfname, ".json")) strcat(crelfname, ".json"); @@ -1137,12 +1238,12 @@ int CmdHFEMVScan(const char *cmd) { if (MergeJSON) { root = json_load_file(fname, 0, &error); if (!root) { - PrintAndLog("ERROR: json error on line %d: %s", error.line, error.text); + PrintAndLogEx(ERROR, "json error on line %d: %s", error.line, error.text); return 1; } if (!json_is_object(root)) { - PrintAndLog("ERROR: Invalid json format. root must be an object."); + PrintAndLogEx(ERROR, "Invalid json format. root must be an object."); return 1; } } else { @@ -1153,14 +1254,14 @@ int CmdHFEMVScan(const char *cmd) { DropField(); // iso 14443 select - PrintAndLog("--> GET UID, ATS."); + PrintAndLogEx(NORMAL, "--> GET UID, ATS."); iso14a_card_select_t card; if (Hf14443_4aGetCardData(&card)) { return 2; } - JsonSaveStr(root, "$.File.Created", "proxmark3 `hf emv scan`"); + JsonSaveStr(root, "$.File.Created", "proxmark3 `emv scan`"); JsonSaveStr(root, "$.Card.Communication", "iso14443-4a"); JsonSaveBufAsHex(root, "$.Card.UID", (uint8_t *)&card.uid, card.uidlen); @@ -1173,8 +1274,8 @@ int CmdHFEMVScan(const char *cmd) { struct tlvdb *tlvSelect = tlvdb_fixed(1, strlen(al), (const unsigned char *)al); // EMV PPSE - PrintAndLog("--> PPSE."); - res = EMVSelectPSE(true, true, 2, buf, sizeof(buf), &len, &sw); + PrintAndLogEx(NORMAL, "--> PPSE."); + res = EMVSelectPSE(channel, true, true, 2, buf, sizeof(buf), &len, &sw); if (!res && sw == 0x9000){ if (decodeTLV) @@ -1191,17 +1292,17 @@ int CmdHFEMVScan(const char *cmd) { tlvdb_free(fci); } - res = EMVSearchPSE(false, true, decodeTLV, tlvSelect); + res = EMVSearchPSE(channel, false, true, decodeTLV, tlvSelect); // check PPSE and select application id - if (!res) { - TLVPrintAIDlistFromSelectTLV(tlvSelect); + if (!res) { + TLVPrintAIDlistFromSelectTLV(tlvSelect); } else { // EMV SEARCH with AID list SetAPDULogging(false); - PrintAndLog("--> AID search."); - if (EMVSearch(false, true, decodeTLV, tlvSelect)) { - PrintAndLog("E->Can't found any of EMV AID. Exit..."); + PrintAndLogEx(NORMAL, "--> AID search."); + if (EMVSearch(channel, false, true, decodeTLV, tlvSelect)) { + PrintAndLogEx(ERROR, "Can't found any of EMV AID. Exit..."); tlvdb_free(tlvSelect); DropField(); return 3; @@ -1218,7 +1319,7 @@ int CmdHFEMVScan(const char *cmd) { tlvdb_free(tlvSelect); if (!AIDlen) { - PrintAndLog("Can't select AID. EMV AID not found. Exit..."); + PrintAndLogEx(INFO, "Can't select AID. EMV AID not found. Exit..."); DropField(); return 4; } @@ -1231,12 +1332,12 @@ int CmdHFEMVScan(const char *cmd) { // EMV SELECT applet - PrintAndLog("\n-->Selecting AID:%s.", sprint_hex_inrow(AID, AIDlen)); + PrintAndLogEx(NORMAL, "\n-->Selecting AID:%s.", sprint_hex_inrow(AID, AIDlen)); SetAPDULogging(showAPDU); - res = EMVSelect(false, true, AID, AIDlen, buf, sizeof(buf), &len, &sw, tlvRoot); + res = EMVSelect(channel, false, true, AID, AIDlen, buf, sizeof(buf), &len, &sw, tlvRoot); - if (res) { - PrintAndLog("E->Can't select AID (%d). Exit...", res); + if (res) { + PrintAndLogEx(ERROR, "Can't select AID (%d). Exit...", res); tlvdb_free(tlvRoot); DropField(); return 5; @@ -1258,13 +1359,13 @@ int CmdHFEMVScan(const char *cmd) { tlvdb_free(fci); // create transaction parameters - PrintAndLog("-->Init transaction parameters."); + PrintAndLogEx(NORMAL, "-->Init transaction parameters."); InitTransactionParameters(tlvRoot, paramLoadJSON, TrType, GenACGPO); - PrintAndLog("-->Calc PDOL."); + PrintAndLogEx(NORMAL, "-->Calc PDOL."); struct tlv *pdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x9f38, NULL), tlvRoot, 0x83); if (!pdol_data_tlv){ - PrintAndLog("E->Can't create PDOL TLV."); + PrintAndLogEx(ERROR, "Can't create PDOL TLV."); tlvdb_free(tlvRoot); DropField(); return 6; @@ -1273,21 +1374,21 @@ int CmdHFEMVScan(const char *cmd) { size_t pdol_data_tlv_data_len; unsigned char *pdol_data_tlv_data = tlv_encode(pdol_data_tlv, &pdol_data_tlv_data_len); if (!pdol_data_tlv_data) { - PrintAndLog("E->Can't create PDOL data."); + PrintAndLogEx(ERROR, "Can't create PDOL data."); tlvdb_free(tlvRoot); DropField(); return 6; } - PrintAndLog("PDOL data[%d]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len)); + PrintAndLogEx(INFO, "PDOL data[%d]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len)); - PrintAndLog("-->GPO."); - res = EMVGPO(true, pdol_data_tlv_data, pdol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot); + PrintAndLogEx(INFO, "-->GPO."); + res = EMVGPO(channel, true, pdol_data_tlv_data, pdol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot); free(pdol_data_tlv_data); free(pdol_data_tlv); - if (res) { - PrintAndLog("GPO error(%d): %4x. Exit...", res, sw); + if (res) { + PrintAndLogEx(ERROR, "GPO error(%d): %4x. Exit...", res, sw); tlvdb_free(tlvRoot); DropField(); return 7; @@ -1305,12 +1406,12 @@ int CmdHFEMVScan(const char *cmd) { tlvdb_free(gpofci); - PrintAndLog("-->Read records from AFL."); + PrintAndLogEx(INFO, "-->Read records from AFL."); const struct tlv *AFL = tlvdb_get(tlvRoot, 0x94, NULL); while(AFL && AFL->len) { if (AFL->len % 4) { - PrintAndLog("E->Wrong AFL length: %d", AFL->len); + PrintAndLogEx(ERROR, "Wrong AFL length: %d", AFL->len); break; } @@ -1322,7 +1423,7 @@ int CmdHFEMVScan(const char *cmd) { sfijson = json_path_get(root, "$.Application.Records"); } if (!json_is_array(sfijson)) { - PrintAndLog("E->Internal logic error. `$.Application.Records` is not an array."); + PrintAndLogEx(ERROR, "Internal logic error. `$.Application.Records` is not an array."); break; } for (int i = 0; i < AFL->len / 4; i++) { @@ -1331,24 +1432,24 @@ int CmdHFEMVScan(const char *cmd) { uint8_t SFIend = AFL->value[i * 4 + 2]; uint8_t SFIoffline = AFL->value[i * 4 + 3]; - PrintAndLog("--->SFI[%02x] start:%02x end:%02x offline:%02x", SFI, SFIstart, SFIend, SFIoffline); + PrintAndLogEx(INFO, "--->SFI[%02x] start:%02x end:%02x offline:%02x", SFI, SFIstart, SFIend, SFIoffline); if (SFI == 0 || SFI == 31 || SFIstart == 0 || SFIstart > SFIend) { - PrintAndLog("SFI ERROR! Skipped..."); + PrintAndLogEx(ERROR, "SFI ERROR! Skipped..."); continue; } for(int n = SFIstart; n <= SFIend; n++) { - PrintAndLog("---->SFI[%02x] %d", SFI, n); + PrintAndLogEx(INFO, "---->SFI[%02x] %d", SFI, n); - res = EMVReadRecord(true, SFI, n, buf, sizeof(buf), &len, &sw, tlvRoot); + res = EMVReadRecord(channel, true, SFI, n, buf, sizeof(buf), &len, &sw, tlvRoot); if (res) { - PrintAndLog("E->SFI[%02x]. APDU error %4x", SFI, sw); + PrintAndLogEx(ERROR, "SFI[%02x]. APDU error %4x", SFI, sw); continue; } if (decodeTLV) { TLVPrintFromBuffer(buf, len); - PrintAndLog(""); + PrintAndLogEx(NORMAL, ""); } json_t *jsonelm = json_object(); @@ -1372,7 +1473,7 @@ int CmdHFEMVScan(const char *cmd) { // getting certificates if (tlvdb_get(tlvRoot, 0x90, NULL)) { - PrintAndLog("-->Recovering certificates."); + PrintAndLogEx(INFO, "-->Recovering certificates."); PKISetStrictExecution(false); RecoveryCertificates(tlvRoot, root); PKISetStrictExecution(true); @@ -1386,10 +1487,10 @@ int CmdHFEMVScan(const char *cmd) { res = json_dump_file(root, fname, JSON_INDENT(2)); if (res) { - PrintAndLog("ERROR: can't save the file: %s", fname); + PrintAndLogEx(ERROR, "Can't save the file: %s", fname); return 200; } - PrintAndLog("File `%s` saved.", fname); + PrintAndLogEx(SUCCESS, "File `%s` saved.", fname); // free json object json_decref(root); @@ -1397,28 +1498,28 @@ int CmdHFEMVScan(const char *cmd) { return 0; } -int CmdHFEMVTest(const char *cmd) { +int CmdEMVTest(const char *cmd) { return ExecuteCryptoTests(true); } int CmdHelp(const char *Cmd); static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help"}, - {"exec", CmdHFEMVExec, 0, "Executes EMV contactless transaction."}, - {"pse", CmdHFEMVPPSE, 0, "Execute PPSE. It selects 2PAY.SYS.DDF01 or 1PAY.SYS.DDF01 directory."}, - {"search", CmdHFEMVSearch, 0, "Try to select all applets from applets list and print installed applets."}, - {"select", CmdHFEMVSelect, 0, "Select applet."}, - {"gpo", CmdHFEMVGPO, 0, "Execute GetProcessingOptions."}, - {"readrec", CmdHFEMVReadRecord, 0, "Read files from card."}, - {"genac", CmdHFEMVAC, 0, "Generate ApplicationCryptogram."}, - {"challenge", CmdHFEMVGenerateChallenge, 0, "Generate challenge."}, - {"intauth", CmdHFEMVInternalAuthenticate, 0, "Internal authentication."}, - {"scan", CmdHFEMVScan, 0, "Scan EMV card and save it contents to json file for emulator."}, - {"test", CmdHFEMVTest, 0, "Crypto logic test."}, - {NULL, NULL, 0, NULL} + {"help", CmdHelp, 1, "This help"}, + {"exec", CmdEMVExec, 0, "Executes EMV contactless transaction."}, + {"pse", CmdEMVPPSE, 0, "Execute PPSE. It selects 2PAY.SYS.DDF01 or 1PAY.SYS.DDF01 directory."}, + {"search", CmdEMVSearch, 0, "Try to select all applets from applets list and print installed applets."}, + {"select", CmdEMVSelect, 0, "Select applet."}, + {"gpo", CmdEMVGPO, 0, "Execute GetProcessingOptions."}, + {"readrec", CmdEMVReadRecord, 0, "Read files from card."}, + {"genac", CmdEMVAC, 0, "Generate ApplicationCryptogram."}, + {"challenge", CmdEMVGenerateChallenge, 0, "Generate challenge."}, + {"intauth", CmdEMVInternalAuthenticate, 0, "Internal authentication."}, + {"scan", CmdEMVScan, 0, "Scan EMV card and save it contents to json file for emulator."}, + {"test", CmdEMVTest, 0, "Crypto logic test."}, + {NULL, NULL, 0, NULL} }; -int CmdHFEMV(const char *Cmd) { +int CmdEMV(const char *Cmd) { CmdsParse(CommandTable, Cmd); return 0; } diff --git a/client/emv/cmdemv.h b/client/emv/cmdemv.h index b3f76508..3dc76fa9 100644 --- a/client/emv/cmdemv.h +++ b/client/emv/cmdemv.h @@ -26,7 +26,13 @@ #include "emvcore.h" #include "apduinfo.h" -int CmdHFEMV(const char *Cmd); +int CmdEMV(const char *Cmd); +extern int CmdEMVSelect(const char *cmd); +extern int CmdEMVSearch(const char *cmd); +extern int CmdEMVPPSE(const char *cmd); +extern int CmdEMVExec(const char *cmd); +extern int CmdEMVGetrng(const char *Cmd); +extern int CmdEMVList(const char *Cmd); -#endif \ No newline at end of file +#endif diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index c1259114..04d8f44c 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -11,6 +11,9 @@ #include "emvcore.h" #include "emvjson.h" #include "util_posix.h" +#ifdef WITH_SMARTCARD +#include "cmdsmartcard.h" +#endif // Got from here. Thanks) // https://eftlab.co.uk/index.php/site-map/knowledge-base/211-emv-aid-rid-pix @@ -230,12 +233,13 @@ struct tlvdb *GetdCVVRawFromTrack2(const struct tlv *track2) { return tlvdb_fixed(0x02, dCVVlen, dCVV); } -int EMVExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool IncludeLe, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { +int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool IncludeLe, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { uint8_t data[APDU_RES_LEN] = {0}; *ResultLen = 0; if (sw) *sw = 0; uint16_t isw = 0; + int res = 0; if (ActivateField){ DropField(); @@ -250,16 +254,32 @@ int EMVExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool Includ if (APDULogging) PrintAndLog(">>>> %s", sprint_hex(data, (IncludeLe?6:5) + apdu.Lc)); - // 6 byes + data = INS + CLA + P1 + P2 + Lc + + Le(?IncludeLe) - int res = ExchangeAPDU14a(data, (IncludeLe?6:5) + apdu.Lc, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); - - if (res) { - return res; + switch(channel) { + case ECC_CONTACTLESS: + // 6 byes + data = INS + CLA + P1 + P2 + Lc + + Le(?IncludeLe) + res = ExchangeAPDU14a(data, (IncludeLe?6:5) + apdu.Lc, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); + if (res) { + return res; + } + break; + case ECC_CONTACT: + //int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); +#ifdef WITH_SMARTCARD + res = ExchangeAPDUSC(data, (IncludeLe?6:5) + apdu.Lc, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); + if (res) { + return res; + } +#endif + break; } if (APDULogging) PrintAndLog("<<<< %s", sprint_hex(Result, *ResultLen)); + if (*ResultLen < 2) { + return 200; + } + *ResultLen -= 2; isw = Result[*ResultLen] * 0x0100 + Result[*ResultLen + 1]; if (sw) @@ -285,15 +305,15 @@ int EMVExchangeEx(bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool Includ return 0; } -int EMVExchange(bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - return EMVExchangeEx(false, LeaveFieldON, apdu, true, Result, MaxResultLen, ResultLen, sw, tlv); +int EMVExchange(EMVCommandChannel channel, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { + return EMVExchangeEx(channel, false, LeaveFieldON, apdu, true, Result, MaxResultLen, ResultLen, sw, tlv); } -int EMVSelect(bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - return EMVExchangeEx(ActivateField, LeaveFieldON, (sAPDU){0x00, 0xa4, 0x04, 0x00, AIDLen, AID}, true, Result, MaxResultLen, ResultLen, sw, tlv); +int EMVSelect(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { + return EMVExchangeEx(channel, ActivateField, LeaveFieldON, (sAPDU){0x00, 0xa4, 0x04, 0x00, AIDLen, AID}, true, Result, MaxResultLen, ResultLen, sw, tlv); } -int EMVSelectPSE(bool ActivateField, bool LeaveFieldON, uint8_t PSENum, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { +int EMVSelectPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { uint8_t buf[APDU_AID_LEN] = {0}; *ResultLen = 0; int len = 0; @@ -310,19 +330,19 @@ int EMVSelectPSE(bool ActivateField, bool LeaveFieldON, uint8_t PSENum, uint8_t } // select - res = EMVSelect(ActivateField, LeaveFieldON, buf, len, Result, MaxResultLen, ResultLen, sw, NULL); + res = EMVSelect(channel, ActivateField, LeaveFieldON, buf, len, Result, MaxResultLen, ResultLen, sw, NULL); return res; } -int EMVSearchPSE(bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv) { +int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv) { uint8_t data[APDU_RES_LEN] = {0}; size_t datalen = 0; uint16_t sw = 0; int res; // select PPSE - res = EMVSelectPSE(ActivateField, true, 2, data, sizeof(data), &datalen, &sw); + res = EMVSelectPSE(channel, ActivateField, true, 2, data, sizeof(data), &datalen, &sw); if (!res){ struct tlvdb *t = NULL; @@ -336,7 +356,7 @@ int EMVSearchPSE(bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct t while (ttmp) { const struct tlv *tgAID = tlvdb_get_inchild(ttmp, 0x4f, NULL); if (tgAID) { - res = EMVSelect(false, true, (uint8_t *)tgAID->value, tgAID->len, data, sizeof(data), &datalen, &sw, tlv); + res = EMVSelect(channel, false, true, (uint8_t *)tgAID->value, tgAID->len, data, sizeof(data), &datalen, &sw, tlv); // retry if error and not returned sw error if (res && res != 5) { @@ -383,7 +403,7 @@ int EMVSearchPSE(bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct t return res; } -int EMVSearch(bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv) { +int EMVSearch(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv) { uint8_t aidbuf[APDU_AID_LEN] = {0}; int aidlen = 0; uint8_t data[APDU_RES_LEN] = {0}; @@ -394,15 +414,15 @@ int EMVSearch(bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvd int retrycnt = 0; for(int i = 0; i < AIDlistLen; i ++) { param_gethex_to_eol(AIDlist[i].aid, 0, aidbuf, sizeof(aidbuf), &aidlen); - res = EMVSelect((i == 0) ? ActivateField : false, (i == AIDlistLen - 1) ? LeaveFieldON : true, aidbuf, aidlen, data, sizeof(data), &datalen, &sw, tlv); + res = EMVSelect(channel, (i == 0) ? ActivateField : false, (i == AIDlistLen - 1) ? LeaveFieldON : true, aidbuf, aidlen, data, sizeof(data), &datalen, &sw, tlv); // retry if error and not returned sw error if (res && res != 5) { if (++retrycnt < 3){ i--; } else { - // card select error, proxmark error - if (res == 1) { - PrintAndLog("Exit..."); + // (1) - card select error, proxmark error OR (200) - result length = 0 + if (res == 1 || res == 200) { + PrintAndLogEx(WARNING, "Exit..."); return 1; } @@ -464,38 +484,38 @@ int EMVSelectApplication(struct tlvdb *tlv, uint8_t *AID, size_t *AIDlen) { return 0; } -int EMVGPO(bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - return EMVExchange(LeaveFieldON, (sAPDU){0x80, 0xa8, 0x00, 0x00, PDOLLen, PDOL}, Result, MaxResultLen, ResultLen, sw, tlv); +int EMVGPO(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { + return EMVExchange(channel, LeaveFieldON, (sAPDU){0x80, 0xa8, 0x00, 0x00, PDOLLen, PDOL}, Result, MaxResultLen, ResultLen, sw, tlv); } -int EMVReadRecord(bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - int res = EMVExchange(LeaveFieldON, (sAPDU){0x00, 0xb2, SFIrec, (SFI << 3) | 0x04, 0, NULL}, Result, MaxResultLen, ResultLen, sw, tlv); +int EMVReadRecord(EMVCommandChannel channel, bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { + int res = EMVExchange(channel, LeaveFieldON, (sAPDU){0x00, 0xb2, SFIrec, (SFI << 3) | 0x04, 0, NULL}, Result, MaxResultLen, ResultLen, sw, tlv); if (*sw == 0x6700) { - PrintAndLog(">>> trying to reissue command withouth Le..."); - res = EMVExchangeEx(false, LeaveFieldON, (sAPDU){0x00, 0xb2, SFIrec, (SFI << 3) | 0x04, 0, NULL}, false, Result, MaxResultLen, ResultLen, sw, tlv); + PrintAndLogEx(INFO, ">>> trying to reissue command withouth Le..."); + res = EMVExchangeEx(channel, false, LeaveFieldON, (sAPDU){0x00, 0xb2, SFIrec, (SFI << 3) | 0x04, 0, NULL}, false, Result, MaxResultLen, ResultLen, sw, tlv); } return res; } -int EMVAC(bool LeaveFieldON, uint8_t RefControl, uint8_t *CDOL, size_t CDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - return EMVExchange(LeaveFieldON, (sAPDU){0x80, 0xae, RefControl, 0x00, CDOLLen, CDOL}, Result, MaxResultLen, ResultLen, sw, tlv); +int EMVAC(EMVCommandChannel channel, bool LeaveFieldON, uint8_t RefControl, uint8_t *CDOL, size_t CDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { + return EMVExchange(channel, LeaveFieldON, (sAPDU){0x80, 0xae, RefControl, 0x00, CDOLLen, CDOL}, Result, MaxResultLen, ResultLen, sw, tlv); } -int EMVGenerateChallenge(bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - int res = EMVExchange(LeaveFieldON, (sAPDU){0x00, 0x84, 0x00, 0x00, 0x00, NULL}, Result, MaxResultLen, ResultLen, sw, tlv); +int EMVGenerateChallenge(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { + int res = EMVExchange(channel, LeaveFieldON, (sAPDU){0x00, 0x84, 0x00, 0x00, 0x00, NULL}, Result, MaxResultLen, ResultLen, sw, tlv); if (*sw == 0x6700) { - PrintAndLog(">>> trying to reissue command withouth Le..."); - res = EMVExchangeEx(false, LeaveFieldON, (sAPDU){0x00, 0x84, 0x00, 0x00, 0x00, NULL}, false, Result, MaxResultLen, ResultLen, sw, tlv); + PrintAndLogEx(INFO, ">>> trying to reissue command withouth Le..."); + res = EMVExchangeEx(channel, false, LeaveFieldON, (sAPDU){0x00, 0x84, 0x00, 0x00, 0x00, NULL}, false, Result, MaxResultLen, ResultLen, sw, tlv); } return res; } -int EMVInternalAuthenticate(bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - return EMVExchange(LeaveFieldON, (sAPDU){0x00, 0x88, 0x00, 0x00, DDOLLen, DDOL}, Result, MaxResultLen, ResultLen, sw, tlv); +int EMVInternalAuthenticate(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { + return EMVExchange(channel, LeaveFieldON, (sAPDU){0x00, 0x88, 0x00, 0x00, DDOLLen, DDOL}, Result, MaxResultLen, ResultLen, sw, tlv); } -int MSCComputeCryptoChecksum(bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - return EMVExchange(LeaveFieldON, (sAPDU){0x80, 0x2a, 0x8e, 0x80, UDOLlen, UDOL}, Result, MaxResultLen, ResultLen, sw, tlv); +int MSCComputeCryptoChecksum(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { + return EMVExchange(channel, LeaveFieldON, (sAPDU){0x80, 0x2a, 0x8e, 0x80, UDOLlen, UDOL}, Result, MaxResultLen, ResultLen, sw, tlv); } // Authentication @@ -565,7 +585,7 @@ int trSDA(struct tlvdb *tlv) { static const unsigned char default_ddol_value[] = {0x9f, 0x37, 0x04}; static struct tlv default_ddol_tlv = {.tag = 0x9f49, .len = 3, .value = default_ddol_value }; -int trDDA(bool decodeTLV, struct tlvdb *tlv) { +int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { uint8_t buf[APDU_RES_LEN] = {0}; size_t len = 0; uint16_t sw = 0; @@ -705,9 +725,9 @@ int trDDA(bool decodeTLV, struct tlvdb *tlv) { PrintAndLog("DDOL data[%d]: %s", ddol_data_tlv->len, sprint_hex(ddol_data_tlv->value, ddol_data_tlv->len)); PrintAndLog("\n* Internal Authenticate"); - int res = EMVInternalAuthenticate(true, (uint8_t *)ddol_data_tlv->value, ddol_data_tlv->len, buf, sizeof(buf), &len, &sw, NULL); + int res = EMVInternalAuthenticate(channel, true, (uint8_t *)ddol_data_tlv->value, ddol_data_tlv->len, buf, sizeof(buf), &len, &sw, NULL); if (res) { - PrintAndLog("Internal Authenticate error(%d): %4x. Exit...", res, sw); + PrintAndLogEx(WARNING, "Internal Authenticate error(%d): %4x. Exit...", res, sw); free(ddol_data_tlv); emv_pk_free(pk); emv_pk_free(issuer_pk); diff --git a/client/emv/emvcore.h b/client/emv/emvcore.h index fa7a4db8..d8b6a5c7 100644 --- a/client/emv/emvcore.h +++ b/client/emv/emvcore.h @@ -32,6 +32,11 @@ #define APDU_RES_LEN 260 #define APDU_AID_LEN 50 +typedef enum { + ECC_CONTACTLESS, + ECC_CONTACT +} EMVCommandChannel; + enum TransactionType { TT_MSD, TT_VSDC, // not standart for contactless!!!! @@ -71,29 +76,29 @@ extern struct tlvdb *GetdCVVRawFromTrack2(const struct tlv *track2); extern void SetAPDULogging(bool logging); // exchange -extern int EMVExchange(bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); +extern int EMVExchange(EMVCommandChannel channel, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); // search application -extern int EMVSearchPSE(bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv); -extern int EMVSearch(bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv); -extern int EMVSelectPSE(bool ActivateField, bool LeaveFieldON, uint8_t PSENum, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); -extern int EMVSelect(bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); +extern int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv); +extern int EMVSearch(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv); +extern int EMVSelectPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); +extern int EMVSelect(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); // select application extern int EMVSelectApplication(struct tlvdb *tlv, uint8_t *AID, size_t *AIDlen); // Get Processing Options -extern int EMVGPO(bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); -extern int EMVReadRecord(bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); +extern int EMVGPO(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); +extern int EMVReadRecord(EMVCommandChannel channel, bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); // AC -extern int EMVGenerateChallenge(bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); -extern int EMVAC(bool LeaveFieldON, uint8_t RefControl, uint8_t *CDOL, size_t CDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); +extern int EMVGenerateChallenge(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); +extern int EMVAC(EMVCommandChannel channel, bool LeaveFieldON, uint8_t RefControl, uint8_t *CDOL, size_t CDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); // DDA -extern int EMVInternalAuthenticate(bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); +extern int EMVInternalAuthenticate(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); // Mastercard -int MSCComputeCryptoChecksum(bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); +int MSCComputeCryptoChecksum(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); // Auth extern int trSDA(struct tlvdb *tlv); -extern int trDDA(bool decodeTLV, struct tlvdb *tlv); +extern int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv); extern int trCDA(struct tlvdb *tlv, struct tlvdb *ac_tlv, struct tlv *pdol_data_tlv, struct tlv *ac_data_tlv); extern int RecoveryCertificates(struct tlvdb *tlvRoot, json_t *root); diff --git a/client/fido/fidocore.c b/client/fido/fidocore.c index 39c2052f..ee39fbbe 100644 --- a/client/fido/fidocore.c +++ b/client/fido/fidocore.c @@ -170,17 +170,17 @@ char *fido2GetCmdMemberDescription(uint8_t cmdCode, bool isResponse, int memberN int FIDOSelect(bool ActivateField, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { uint8_t data[] = {0xA0, 0x00, 0x00, 0x06, 0x47, 0x2F, 0x00, 0x01}; - return EMVSelect(ActivateField, LeaveFieldON, data, sizeof(data), Result, MaxResultLen, ResultLen, sw, NULL); + return EMVSelect(ECC_CONTACTLESS, ActivateField, LeaveFieldON, data, sizeof(data), Result, MaxResultLen, ResultLen, sw, NULL); } int FIDOExchange(sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { - int res = EMVExchange(true, apdu, Result, MaxResultLen, ResultLen, sw, NULL); + int res = EMVExchange(ECC_CONTACTLESS, true, apdu, Result, MaxResultLen, ResultLen, sw, NULL); if (res == 5) // apdu result (sw) not a 0x9000 res = 0; // software chaining while (!res && (*sw >> 8) == 0x61) { size_t oldlen = *ResultLen; - res = EMVExchange(true, (sAPDU){0x00, 0xC0, 0x00, 0x00, 0x00, NULL}, &Result[oldlen], MaxResultLen - oldlen, ResultLen, sw, NULL); + res = EMVExchange(ECC_CONTACTLESS, true, (sAPDU){0x00, 0xC0, 0x00, 0x00, 0x00, NULL}, &Result[oldlen], MaxResultLen - oldlen, ResultLen, sw, NULL); if (res == 5) // apdu result (sw) not a 0x9000 res = 0; diff --git a/common/Makefile_Enabled_Options.common b/common/Makefile_Enabled_Options.common index 8774946e..d9f6d3b9 100644 --- a/common/Makefile_Enabled_Options.common +++ b/common/Makefile_Enabled_Options.common @@ -13,6 +13,7 @@ APP_CFLAGS += -DWITH_ISO14443a_StandAlone \ -DWITH_HITAG \ -DWITH_CRC \ -DWITH_HFSNOOP \ + -DWITH_SMARTCARD \ -DWITH_GUI #END diff --git a/common/protocols.h b/common/protocols.h index 06a80de1..79d8e083 100644 --- a/common/protocols.h +++ b/common/protocols.h @@ -262,6 +262,7 @@ NXP/Philips CUSTOM COMMANDS #define ISO7816_EXTERNAL_AUTHENTICATION 0x82 #define ISO7816_GET_CHALLENGE 0xB4 #define ISO7816_MANAGE_CHANNEL 0x70 +#define ISO7816_GETSTATUS 0xC0 // ISO7816-4 For response APDU's #define ISO7816_OK 0x9000 // 6x xx = ERROR diff --git a/include/smartcard.h b/include/smartcard.h index 9bed8c9d..2f6e286c 100644 --- a/include/smartcard.h +++ b/include/smartcard.h @@ -22,7 +22,7 @@ typedef enum SMARTCARD_COMMAND { SC_CONNECT = (1 << 0), SC_NO_DISCONNECT = (1 << 1), SC_RAW = (1 << 2), - SC_NO_SELECT = (1 << 3) + SC_SELECT = (1 << 3) } smartcard_command_t; From 5f84531b82309c5cbb72ea5bdaaee3a1be734eb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=98=83=20Stephen=20Shkardoon=20=E2=98=83?= Date: Sat, 5 Jan 2019 21:48:59 +1300 Subject: [PATCH 038/189] Paradox clone functionality implemented (#747) This involves a refactor to the arm HID code to allow for arbitrary preambles (such as HID Proximity and Paradox). The client also borrows from the HID code, but is not shared, so could use a significant refactor in the future. --- CHANGELOG.md | 2 ++ armsrc/appmain.c | 8 +++++-- armsrc/apps.h | 2 +- armsrc/lfops.c | 12 +++++------ client/cmdlfhid.c | 8 +++---- client/cmdlfhid.h | 2 ++ client/cmdlfparadox.c | 42 +++++++++++++++++++++++++++++++++++-- client/hidcardformatutils.c | 2 +- include/usb_cmd.h | 2 ++ 9 files changed, 64 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b856ec1..19db5195 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,8 +22,10 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added `lf hitag reader 03` - read block (instead of pages) - Added `lf hitag reader 04` - read block (instead of pages) - Added `hf fido` `assert` and `make` commands from fido2 protocol (authenticatorMakeCredential and authenticatorGetAssertion) (Merlok) +- Added `lf paradox clone` to clone a Paradox card - Added `emv` commmands working for both contactless and smart cards (Merlok) + ## [v3.1.0][2018-10-10] ### Changed diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 35c9e5bf..c5c17867 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -744,7 +744,7 @@ void SamyRun() /* need this delay to prevent catching some weird data */ SpinDelay(500); - CopyHIDtoT55x7(tops[selected] & 0x000FFFFF, high[selected], low[selected], (tops[selected] != 0 && ((high[selected]& 0xFFFFFFC0) != 0))); + CopyHIDtoT55x7(tops[selected] & 0x000FFFFF, high[selected], low[selected], (tops[selected] != 0 && ((high[selected]& 0xFFFFFFC0) != 0)), 0x1D); if (tops[selected] > 0) Dbprintf("Cloned %x %x%08x%08x", selected, tops[selected], high[selected], low[selected]); else @@ -1003,7 +1003,11 @@ void UsbPacketReceived(uint8_t *packet, int len) CmdPSKsimTag(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); break; case CMD_HID_CLONE_TAG: - CopyHIDtoT55x7(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes[0]); + CopyHIDtoT55x7(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes[0], 0x1D); + break; + case CMD_PARADOX_CLONE_TAG: + // Paradox cards are the same as HID, with a different preamble, so we can reuse the same function + CopyHIDtoT55x7(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes[0], 0x0F); break; case CMD_IO_DEMOD_FSK: CmdIOdemodFSK(c->arg[0], 0, 0, 1); diff --git a/armsrc/apps.h b/armsrc/apps.h index 6af22b57..b9b1f3de 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -78,7 +78,7 @@ void CmdAWIDdemodFSK(int findone, int *high, int *low, int ledcontrol); // Realt void CmdEM410xdemod(int findone, int *high, int *low, int ledcontrol); void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol); void CopyIOtoT55x7(uint32_t hi, uint32_t lo); // Clone an ioProx card to T5557/T5567 -void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT); // Clone an HID card to T5557/T5567 +void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT, uint8_t preamble); // Clone an HID-like card to T5557/T5567 void CopyVikingtoT55xx(uint32_t block1, uint32_t block2, uint8_t Q5); void WriteEM410x(uint32_t card, uint32_t id_hi, uint32_t id_lo); void CopyIndala64toT55x7(uint32_t hi, uint32_t lo); // Clone Indala 64-bit tag by UID to T55x7 diff --git a/armsrc/lfops.c b/armsrc/lfops.c index b56c3f51..1816bdca 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1417,8 +1417,8 @@ void WriteT55xx(uint32_t *blockdata, uint8_t startblock, uint8_t numblocks) { } } -// Copy HID id to card and setup block 0 config -void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT) { +// Copy a HID-like card (e.g. HID Proximity, Paradox) to a T55x7 compatible card +void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT, uint8_t preamble) { uint32_t data[] = {0,0,0,0,0,0,0}; uint8_t last_block = 0; @@ -1430,15 +1430,15 @@ void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT) { } // Build the 6 data blocks for supplied 84bit ID last_block = 6; - // load preamble (1D) & long format identifier (9E manchester encoded) - data[1] = 0x1D96A900 | (manchesterEncode2Bytes((hi2 >> 16) & 0xF) & 0xFF); + // load preamble & long format identifier (9E manchester encoded) + data[1] = (preamble << 24) | 0x96A900 | (manchesterEncode2Bytes((hi2 >> 16) & 0xF) & 0xFF); // load raw id from hi2, hi, lo to data blocks (manchester encoded) data[2] = manchesterEncode2Bytes(hi2 & 0xFFFF); data[3] = manchesterEncode2Bytes(hi >> 16); data[4] = manchesterEncode2Bytes(hi & 0xFFFF); data[5] = manchesterEncode2Bytes(lo >> 16); data[6] = manchesterEncode2Bytes(lo & 0xFFFF); - } else { + } else { // Ensure no more than 44 bits supplied if (hi>0xFFF) { DbpString("Tags can only have 44 bits."); @@ -1447,7 +1447,7 @@ void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT) { // Build the 3 data blocks for supplied 44bit ID last_block = 3; // load preamble - data[1] = 0x1D000000 | (manchesterEncode2Bytes(hi) & 0xFFFFFF); + data[1] = (preamble << 24) | (manchesterEncode2Bytes(hi) & 0xFFFFFF); data[2] = manchesterEncode2Bytes(lo >> 16); data[3] = manchesterEncode2Bytes(lo & 0xFFFF); } diff --git a/client/cmdlfhid.c b/client/cmdlfhid.c index 38e7073c..14340082 100644 --- a/client/cmdlfhid.c +++ b/client/cmdlfhid.c @@ -39,7 +39,7 @@ * * Returns the number of nibbles (4 bits) entered. */ -int hexstring_to_int96(/* out */ uint32_t* hi2,/* out */ uint32_t* hi, /* out */ uint32_t* lo, const char* str) { +int hid_hexstring_to_int96(/* out */ uint32_t* hi2,/* out */ uint32_t* hi, /* out */ uint32_t* lo, const char* str) { // TODO: Replace this with param_gethex when it supports arbitrary length // inputs. int n = 0, i = 0; @@ -201,7 +201,7 @@ int CmdHIDReadFSK(const char *Cmd) int CmdHIDSim(const char *Cmd) { uint32_t hi2 = 0, hi = 0, lo = 0; - hexstring_to_int96(&hi2, &hi, &lo, Cmd); + hid_hexstring_to_int96(&hi2, &hi, &lo, Cmd); if (hi2 != 0) { PrintAndLog("Emulating tag with ID %x%08x%08x", hi2, hi, lo); } else { @@ -218,7 +218,7 @@ int CmdHIDSim(const char *Cmd) int CmdHIDClone(const char *Cmd) { unsigned int top = 0, mid = 0, bot = 0; - hexstring_to_int96(&top, &mid, &bot, Cmd); + hid_hexstring_to_int96(&top, &mid, &bot, Cmd); hidproxmessage_t packed = initialize_proxmessage_object(top, mid, bot); Write(&packed); return 0; @@ -234,7 +234,7 @@ int CmdHIDDecode(const char *Cmd){ uint32_t top = 0, mid = 0, bot = 0; bool ignoreParity = false; - hexstring_to_int96(&top, &mid, &bot, Cmd); + hid_hexstring_to_int96(&top, &mid, &bot, Cmd); hidproxmessage_t packed = initialize_proxmessage_object(top, mid, bot); char opt = param_getchar(Cmd, 1); diff --git a/client/cmdlfhid.h b/client/cmdlfhid.h index ef907f67..353805db 100644 --- a/client/cmdlfhid.h +++ b/client/cmdlfhid.h @@ -22,4 +22,6 @@ int CmdHIDClone(const char *Cmd); int CmdHIDDecode(const char *Cmd); int CmdHIDEncode(const char *Cmd); int CmdHIDWrite(const char *Cmd); +// This is used by the Paradox code +int hid_hexstring_to_int96(/* out */ uint32_t* hi2,/* out */ uint32_t* hi, /* out */ uint32_t* lo, const char* str); #endif diff --git a/client/cmdlfparadox.c b/client/cmdlfparadox.c index e918c7fe..d6710219 100644 --- a/client/cmdlfparadox.c +++ b/client/cmdlfparadox.c @@ -19,7 +19,14 @@ #include "cmddata.h" #include "cmdlf.h" #include "lfdemod.h" +#include "comms.h" +// This card type is similar to HID, so we include the utils from there +#include "cmdlfhid.h" +#include "hidcardformats.h" +#include "hidcardformatutils.h" + static int CmdHelp(const char *Cmd); +void ParadoxWrite(hidproxmessage_t *packed); //by marshmellow //Paradox Prox demod - FSK RF/50 with preamble of 00001111 (then manchester encoded) @@ -55,14 +62,24 @@ int CmdFSKdemodParadox(const char *Cmd) if (g_debugMode) PrintAndLog("DEBUG: Error - no value found"); return 0; } + uint32_t fc = ((hi & 0x3)<<6) | (lo>>26); uint32_t cardnum = (lo>>10)&0xFFFF; uint32_t rawLo = bytebits_to_byte(BitStream+idx+64,32); uint32_t rawHi = bytebits_to_byte(BitStream+idx+32,32); uint32_t rawHi2 = bytebits_to_byte(BitStream+idx,32); - PrintAndLog("Paradox TAG ID: %x%08x - FC: %d - Card: %d - Checksum: %02x - RAW: %08x%08x%08x", - hi>>10, (hi & 0x3)<<26 | (lo>>10), fc, cardnum, (lo>>2) & 0xFF, rawHi2, rawHi, rawLo); + // Steal the HID parsing to output a "full" ID we can send to the HID cloning function + hidproxmessage_t packed = initialize_proxmessage_object(hi2, hi, lo); + + if (packed.top != 0) { + PrintAndLog("Paradox TAG ID: %x%08x (Full ID: %x%08x%08x) - FC: %d - Card: %d - Checksum: %02x - RAW: %08x%08x%08x", + hi>>10, (hi & 0x3)<<26 | (lo>>10), (uint32_t)packed.top, (uint32_t)packed.mid, (uint32_t)packed.bot, fc, cardnum, (lo>>2) & 0xFF, rawHi2, rawHi, rawLo); + } else { + PrintAndLog("Paradox TAG ID: %x%08x (Full ID: %x%08x) - FC: %d - Card: %d - Checksum: %02x - RAW: %08x%08x%08x", + hi>>10, (hi & 0x3)<<26 | (lo>>10), (uint32_t)packed.mid, (uint32_t)packed.bot, fc, cardnum, (lo>>2) & 0xFF, rawHi2, rawHi, rawLo); + + } setDemodBuf(BitStream,BitLen,idx); setClockGrid(50, waveIdx + (idx*50)); if (g_debugMode){ @@ -80,10 +97,31 @@ int CmdParadoxRead(const char *Cmd) { return CmdFSKdemodParadox(Cmd); } +int CmdParadoxClone(const char *Cmd) +{ + unsigned int top = 0, mid = 0, bot = 0; + hid_hexstring_to_int96(&top, &mid, &bot, Cmd); + hidproxmessage_t packed = initialize_proxmessage_object(top, mid, bot); + ParadoxWrite(&packed); + return 0; +} + +void ParadoxWrite(hidproxmessage_t *packed){ + UsbCommand c; + c.d.asBytes[0] = (packed->top != 0 && ((packed->mid & 0xFFFFFFC0) != 0)) + ? 1 : 0; // Writing long format? + c.cmd = CMD_PARADOX_CLONE_TAG; + c.arg[0] = (packed->top & 0x000FFFFF); + c.arg[1] = packed->mid; + c.arg[2] = packed->bot; + SendCommand(&c); +} + static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"demod", CmdFSKdemodParadox, 1, "Demodulate a Paradox FSK tag from the GraphBuffer"}, {"read", CmdParadoxRead, 0, "Attempt to read and Extract tag data from the antenna"}, + {"clone", CmdParadoxClone, 0, " -- Clone Paradox to T55x7 (tag must be in antenna)"}, {NULL, NULL, 0, NULL} }; diff --git a/client/hidcardformatutils.c b/client/hidcardformatutils.c index 3abee223..e4fb6349 100644 --- a/client/hidcardformatutils.c +++ b/client/hidcardformatutils.c @@ -169,4 +169,4 @@ bool add_HID_header(/* inout */hidproxmessage_t* data){ data->bot |= 1 << data->Length; // leading 1: start bit } return true; -} \ No newline at end of file +} diff --git a/include/usb_cmd.h b/include/usb_cmd.h index fa66634f..306c52bf 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -111,6 +111,8 @@ typedef struct{ #define CMD_VIKING_CLONE_TAG 0x0223 #define CMD_T55XX_WAKEUP 0x0224 #define CMD_COTAG 0x0225 +// misc extra +#define CMD_PARADOX_CLONE_TAG 0x0226 /* CMD_SET_ADC_MUX: ext1 is 0 for lopkd, 1 for loraw, 2 for hipkd, 3 for hiraw */ From 5a28b51036943af40b8036ce4f1e4afe42ad8106 Mon Sep 17 00:00:00 2001 From: Fl0-0 Date: Sat, 5 Jan 2019 18:41:51 +0100 Subject: [PATCH 039/189] Fix PrintAndLogEx ERR (#748) --- client/emv/cmdemv.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/client/emv/cmdemv.c b/client/emv/cmdemv.c index cb42e8f7..d9a43cb9 100644 --- a/client/emv/cmdemv.c +++ b/client/emv/cmdemv.c @@ -345,7 +345,7 @@ int CmdEMVReadRecord(const char *cmd) { CLIParserFree(); if (datalen != 2) { - PrintAndLogEx(ERROR, "Command needs to have 2 bytes of data"); + PrintAndLogEx(ERR, "Command needs to have 2 bytes of data"); return 1; } @@ -997,7 +997,7 @@ int CmdEMVExec(const char *cmd) { } } else { - PrintAndLogEx(ERROR, "AC: Application Transaction Counter (ATC) not found."); + PrintAndLogEx(ERR, "AC: Application Transaction Counter (ATC) not found."); } } } @@ -1238,12 +1238,12 @@ int CmdEMVScan(const char *cmd) { if (MergeJSON) { root = json_load_file(fname, 0, &error); if (!root) { - PrintAndLogEx(ERROR, "json error on line %d: %s", error.line, error.text); + PrintAndLogEx(ERR, "json error on line %d: %s", error.line, error.text); return 1; } if (!json_is_object(root)) { - PrintAndLogEx(ERROR, "Invalid json format. root must be an object."); + PrintAndLogEx(ERR, "Invalid json format. root must be an object."); return 1; } } else { @@ -1302,7 +1302,7 @@ int CmdEMVScan(const char *cmd) { SetAPDULogging(false); PrintAndLogEx(NORMAL, "--> AID search."); if (EMVSearch(channel, false, true, decodeTLV, tlvSelect)) { - PrintAndLogEx(ERROR, "Can't found any of EMV AID. Exit..."); + PrintAndLogEx(ERR, "Can't found any of EMV AID. Exit..."); tlvdb_free(tlvSelect); DropField(); return 3; @@ -1337,7 +1337,7 @@ int CmdEMVScan(const char *cmd) { res = EMVSelect(channel, false, true, AID, AIDlen, buf, sizeof(buf), &len, &sw, tlvRoot); if (res) { - PrintAndLogEx(ERROR, "Can't select AID (%d). Exit...", res); + PrintAndLogEx(ERR, "Can't select AID (%d). Exit...", res); tlvdb_free(tlvRoot); DropField(); return 5; @@ -1365,7 +1365,7 @@ int CmdEMVScan(const char *cmd) { PrintAndLogEx(NORMAL, "-->Calc PDOL."); struct tlv *pdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x9f38, NULL), tlvRoot, 0x83); if (!pdol_data_tlv){ - PrintAndLogEx(ERROR, "Can't create PDOL TLV."); + PrintAndLogEx(ERR, "Can't create PDOL TLV."); tlvdb_free(tlvRoot); DropField(); return 6; @@ -1374,7 +1374,7 @@ int CmdEMVScan(const char *cmd) { size_t pdol_data_tlv_data_len; unsigned char *pdol_data_tlv_data = tlv_encode(pdol_data_tlv, &pdol_data_tlv_data_len); if (!pdol_data_tlv_data) { - PrintAndLogEx(ERROR, "Can't create PDOL data."); + PrintAndLogEx(ERR, "Can't create PDOL data."); tlvdb_free(tlvRoot); DropField(); return 6; @@ -1388,7 +1388,7 @@ int CmdEMVScan(const char *cmd) { free(pdol_data_tlv); if (res) { - PrintAndLogEx(ERROR, "GPO error(%d): %4x. Exit...", res, sw); + PrintAndLogEx(ERR, "GPO error(%d): %4x. Exit...", res, sw); tlvdb_free(tlvRoot); DropField(); return 7; @@ -1411,7 +1411,7 @@ int CmdEMVScan(const char *cmd) { while(AFL && AFL->len) { if (AFL->len % 4) { - PrintAndLogEx(ERROR, "Wrong AFL length: %d", AFL->len); + PrintAndLogEx(ERR, "Wrong AFL length: %d", AFL->len); break; } @@ -1423,7 +1423,7 @@ int CmdEMVScan(const char *cmd) { sfijson = json_path_get(root, "$.Application.Records"); } if (!json_is_array(sfijson)) { - PrintAndLogEx(ERROR, "Internal logic error. `$.Application.Records` is not an array."); + PrintAndLogEx(ERR, "Internal logic error. `$.Application.Records` is not an array."); break; } for (int i = 0; i < AFL->len / 4; i++) { @@ -1434,7 +1434,7 @@ int CmdEMVScan(const char *cmd) { PrintAndLogEx(INFO, "--->SFI[%02x] start:%02x end:%02x offline:%02x", SFI, SFIstart, SFIend, SFIoffline); if (SFI == 0 || SFI == 31 || SFIstart == 0 || SFIstart > SFIend) { - PrintAndLogEx(ERROR, "SFI ERROR! Skipped..."); + PrintAndLogEx(ERR, "SFI ERROR! Skipped..."); continue; } @@ -1443,7 +1443,7 @@ int CmdEMVScan(const char *cmd) { res = EMVReadRecord(channel, true, SFI, n, buf, sizeof(buf), &len, &sw, tlvRoot); if (res) { - PrintAndLogEx(ERROR, "SFI[%02x]. APDU error %4x", SFI, sw); + PrintAndLogEx(ERR, "SFI[%02x]. APDU error %4x", SFI, sw); continue; } @@ -1487,7 +1487,7 @@ int CmdEMVScan(const char *cmd) { res = json_dump_file(root, fname, JSON_INDENT(2)); if (res) { - PrintAndLogEx(ERROR, "Can't save the file: %s", fname); + PrintAndLogEx(ERR, "Can't save the file: %s", fname); return 200; } PrintAndLogEx(SUCCESS, "File `%s` saved.", fname); From 818e15b0c815d25fdfb914cd826baf14b48fa19d Mon Sep 17 00:00:00 2001 From: Samuele Date: Sun, 6 Jan 2019 18:33:06 +0100 Subject: [PATCH 040/189] PCF7931: improved read code and implemented a simple password bruteforce (#745) * Improved PCF 7931 read code and implemented a simple PCF7931 password bruteforce * Warning on the PCF7931 bruteforce command --- armsrc/appmain.c | 3 + armsrc/pcf7931.c | 521 +++++++++++++++++++++++------------------- armsrc/pcf7931.h | 7 +- client/cmdlfpcf7931.c | 51 +++++ client/cmdlfpcf7931.h | 3 + include/usb_cmd.h | 1 + 6 files changed, 349 insertions(+), 237 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index c5c17867..58c979db 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1059,6 +1059,9 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_PCF7931_WRITE: WritePCF7931(c->d.asBytes[0],c->d.asBytes[1],c->d.asBytes[2],c->d.asBytes[3],c->d.asBytes[4],c->d.asBytes[5],c->d.asBytes[6], c->d.asBytes[9], c->d.asBytes[7]-128,c->d.asBytes[8]-128, c->arg[0], c->arg[1], c->arg[2]); break; + case CMD_PCF7931_BRUTEFORCE: + BruteForcePCF7931(c->arg[0], (c->arg[1] & 0xFF), c->d.asBytes[9], c->d.asBytes[7]-128,c->d.asBytes[8]-128); + break; case CMD_EM4X_READ_WORD: EM4xReadWord(c->arg[0], c->arg[1],c->arg[2]); break; diff --git a/armsrc/pcf7931.c b/armsrc/pcf7931.c index e4ba1da5..16b7912d 100644 --- a/armsrc/pcf7931.c +++ b/armsrc/pcf7931.c @@ -8,23 +8,21 @@ #define T0_PCF 8 //period for the pcf7931 in us #define ALLOC 16 -int DemodPCF7931(uint8_t **outBlocks) { - - uint8_t bits[256] = {0x00}; +size_t DemodPCF7931(uint8_t **outBlocks) { + uint8_t bits[256] = {0x00}; uint8_t blocks[8][16]; - uint8_t *dest = BigBuf_get_addr(); + uint8_t *dest = BigBuf_get_addr(); int GraphTraceLen = BigBuf_max_traceLen(); - if ( GraphTraceLen > 18000 ) + if (GraphTraceLen > 18000) GraphTraceLen = 18000; - int i, j, lastval, bitidx, half_switch; int clock = 64; int tolerance = clock / 8; int pmc, block_done; int lc, warnings = 0; - int num_blocks = 0; + size_t num_blocks = 0; int lmin=128, lmax=128; uint8_t dir; //clear read buffer @@ -39,17 +37,16 @@ int DemodPCF7931(uint8_t **outBlocks) { i = 2; /* Find first local max/min */ - if(dest[1] > dest[0]) { + if(dest[1] > dest[0]) { while(i < GraphTraceLen) { - if( !(dest[i] > dest[i-1]) && dest[i] > lmax) + if( !(dest[i] > dest[i-1]) && dest[i] > lmax) break; i++; } dir = 0; - } - else { + } else { while(i < GraphTraceLen) { - if( !(dest[i] < dest[i-1]) && dest[i] < lmin) + if( !(dest[i] < dest[i-1]) && dest[i] < lmin) break; i++; } @@ -61,10 +58,8 @@ int DemodPCF7931(uint8_t **outBlocks) { pmc = 0; block_done = 0; - for (bitidx = 0; i < GraphTraceLen; i++) - { - if ( (dest[i-1] > dest[i] && dir == 1 && dest[i] > lmax) || (dest[i-1] < dest[i] && dir == 0 && dest[i] < lmin)) - { + for (bitidx = 0; i < GraphTraceLen; i++) { + if ((dest[i-1] > dest[i] && dir == 1 && dest[i] > lmax) || (dest[i-1] < dest[i] && dir == 0 && dest[i] < lmin)) { lc = i - lastval; lastval = i; @@ -78,8 +73,7 @@ int DemodPCF7931(uint8_t **outBlocks) { lastval = i; pmc = 0; block_done = 1; - } - else { + } else { pmc = i; } } else if (ABS(lc-clock/2) < tolerance) { @@ -90,21 +84,18 @@ int DemodPCF7931(uint8_t **outBlocks) { lastval = i; pmc = 0; block_done = 1; - } - else if(half_switch == 1) { - bits[bitidx++] = 0; + } else if(half_switch == 1) { + bits[bitidx++] = 0; half_switch = 0; } else half_switch++; } else if (ABS(lc-clock) < tolerance) { // 64TO - bits[bitidx++] = 1; + bits[bitidx++] = 1; } else { // Error - warnings++; - if (warnings > 10) - { + if (++warnings > 10) { Dbprintf("Error: too many detection errors, aborting."); return 0; } @@ -112,16 +103,17 @@ int DemodPCF7931(uint8_t **outBlocks) { if(block_done == 1) { if(bitidx == 128) { - for(j=0; j<16; j++) { - blocks[num_blocks][j] = 128*bits[j*8+7]+ - 64*bits[j*8+6]+ - 32*bits[j*8+5]+ - 16*bits[j*8+4]+ - 8*bits[j*8+3]+ - 4*bits[j*8+2]+ - 2*bits[j*8+1]+ - bits[j*8]; - + for(j = 0; j < 16; ++j) { + blocks[num_blocks][j] = + 128 * bits[j*8 + 7]+ + 64 * bits[j*8 + 6] + + 32 * bits[j*8 + 5] + + 16 * bits[j*8 + 4] + + 8 * bits[j*8 + 3] + + 4 * bits[j*8 + 2] + + 2 * bits[j*8 + 1] + + bits[j*8] + ; } num_blocks++; } @@ -130,272 +122,349 @@ int DemodPCF7931(uint8_t **outBlocks) { half_switch = 0; } if(i < GraphTraceLen) - dir =(dest[i-1] > dest[i]) ? 0 : 1; + dir = (dest[i-1] > dest[i]) ? 0 : 1; } if(bitidx==255) bitidx=0; warnings = 0; if(num_blocks == 4) break; } - memcpy(outBlocks, blocks, 16*num_blocks); + memcpy(outBlocks, blocks, 16 * num_blocks); return num_blocks; } -int IsBlock0PCF7931(uint8_t *Block) { - // Assume RFU means 0 :) - if((memcmp(Block, "\x00\x00\x00\x00\x00\x00\x00\x01", 8) == 0) && memcmp(Block+9, "\x00\x00\x00\x00\x00\x00\x00", 7) == 0) // PAC enabled - return 1; - if((memcmp(Block+9, "\x00\x00\x00\x00\x00\x00\x00", 7) == 0) && Block[7] == 0) // PAC disabled, can it *really* happen ? - return 1; - return 0; +bool IsBlock0PCF7931(uint8_t *block) { + // assuming all RFU bits are set to 0 + // if PAC is enabled password is set to 0 + if (block[7] == 0x01) + { + if (!memcmp(block, "\x00\x00\x00\x00\x00\x00\x00", 7) && !memcmp(block+9, "\x00\x00\x00\x00\x00\x00\x00", 7)) + return true; + } + else if (block[7] == 0x00) + { + if (!memcmp(block+9, "\x00\x00\x00\x00\x00\x00\x00", 7)) + return true; + } + return false; } -int IsBlock1PCF7931(uint8_t *Block) { - // Assume RFU means 0 :) - if(Block[10] == 0 && Block[11] == 0 && Block[12] == 0 && Block[13] == 0) - if((Block[14] & 0x7f) <= 9 && Block[15] <= 9) - return 1; +bool IsBlock1PCF7931(uint8_t *block) { + // assuming all RFU bits are set to 0 + if (block[10] == 0 && block[11] == 0 && block[12] == 0 && block[13] == 0) + if((block[14] & 0x7f) <= 9 && block[15] <= 9) + return true; - return 0; + return false; } void ReadPCF7931() { - uint8_t Blocks[8][17]; - uint8_t tmpBlocks[4][16]; - int i, j, ind, ind2, n; - int num_blocks = 0; - int max_blocks = 8; - int ident = 0; - int error = 0; - int tries = 0; + int found_blocks = 0; // successfully read blocks + int max_blocks = 8; // readable blocks + uint8_t memory_blocks[8][17]; // PCF content + + uint8_t single_blocks[8][17]; // PFC blocks with unknown position + int single_blocks_cnt = 0; - memset(Blocks, 0, 8*17*sizeof(uint8_t)); + size_t n = 0; // transmitted blocks + uint8_t tmp_blocks[4][16]; // temporary read buffer + + uint8_t found_0_1 = 0; // flag: blocks 0 and 1 were found + int errors = 0; // error counter + int tries = 0; // tries counter + + memset(memory_blocks, 0, 8*17*sizeof(uint8_t)); + memset(single_blocks, 0, 8*17*sizeof(uint8_t)); + + int i = 0, j = 0; do { - memset(tmpBlocks, 0, 4*16*sizeof(uint8_t)); - n = DemodPCF7931((uint8_t**)tmpBlocks); + i = 0; + + memset(tmp_blocks, 0, 4*16*sizeof(uint8_t)); + n = DemodPCF7931((uint8_t**)tmp_blocks); if(!n) - error++; - if(error==10 && num_blocks == 0) { + ++errors; + + // exit if no block is received + if (errors >= 10 && found_blocks == 0 && single_blocks_cnt == 0) { Dbprintf("Error, no tag or bad tag"); return; } - else if (tries==20 || error==10) { + // exit if too many errors during reading + if (tries > 50 && (2*errors > tries)) { Dbprintf("Error reading the tag"); Dbprintf("Here is the partial content"); goto end; } + + // our logic breaks if we don't get at least two blocks + if (n < 2) { + if (n == 0 || !memcmp(tmp_blocks[0], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)) + continue; - for(i=0; i= 0; ind--,ind2--) { - if(ind2 < 0) - ind2 = max_blocks; - if(!Blocks[ind2][ALLOC]) { // Block ind2 not already found - // Dbprintf("Tmp %d -> Block %d", ind, ind2); - memcpy(Blocks[ind2], tmpBlocks[ind], 16); - Blocks[ind2][ALLOC] = 1; - num_blocks++; - if(num_blocks == max_blocks) goto end; - } - } - for(ind=i+1,ind2=j+1; ind < n; ind++,ind2++) { - if(ind2 > max_blocks) - ind2 = 0; - if(!Blocks[ind2][ALLOC]) { // Block ind2 not already found - // Dbprintf("Tmp %d -> Block %d", ind, ind2); - memcpy(Blocks[ind2], tmpBlocks[ind], 16); - Blocks[ind2][ALLOC] = 1; - num_blocks++; - if(num_blocks == max_blocks) goto end; - } - } + ++tries; + continue; + } + + Dbprintf("(dbg) got %d blocks (%d/%d found) (%d tries, %d errors)", n, found_blocks, (max_blocks == 0 ? found_blocks : max_blocks), tries, errors); + + i = 0; + if(!found_0_1) { + while (i < n - 1) { + if (IsBlock0PCF7931(tmp_blocks[i]) && IsBlock1PCF7931(tmp_blocks[i+1])) { + found_0_1 = 1; + memcpy(memory_blocks[0], tmp_blocks[i], 16); + memcpy(memory_blocks[1], tmp_blocks[i+1], 16); + memory_blocks[0][ALLOC] = memory_blocks[1][ALLOC] = 1; + // block 1 tells how many blocks are going to be sent + max_blocks = MAX((memory_blocks[1][14] & 0x7f), memory_blocks[1][15]) + 1; + found_blocks = 2; + + Dbprintf("Found blocks 0 and 1. PCF is transmitting %d blocks.", max_blocks); + + // handle the following blocks + for (j = i + 2; j < n; ++j) { + memcpy(memory_blocks[found_blocks], tmp_blocks[j], 16); + memory_blocks[found_blocks][ALLOC] = 1; + ++found_blocks; + } + break; + } + ++i; + } + } else { + // Trying to re-order blocks + // Look for identical block in memory blocks + while (i < n-1) { + // skip all zeroes blocks + if (memcmp(tmp_blocks[i], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)) { + for (j = 1; j < max_blocks - 1; ++j) { + if (!memcmp(tmp_blocks[i], memory_blocks[j], 16) && !memory_blocks[j+1][ALLOC]) { + memcpy(memory_blocks[j+1], tmp_blocks[i+1], 16); + memory_blocks[j+1][ALLOC] = 1; + if (++found_blocks >= max_blocks) goto end; } } } + if (memcmp(tmp_blocks[i+1], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)) { + for (j = 0; j < max_blocks; ++j) { + if (!memcmp(tmp_blocks[i+1], memory_blocks[j], 16) && !memory_blocks[(j == 0 ? max_blocks : j) -1][ALLOC]) { + if (j == 0) { + memcpy(memory_blocks[max_blocks - 1], tmp_blocks[i], 16); + memory_blocks[max_blocks - 1][ALLOC] = 1; + } else { + memcpy(memory_blocks[j-1], tmp_blocks[i], 16); + memory_blocks[j-1][ALLOC] = 1; + } + if (++found_blocks >= max_blocks) goto end; + } + } + } + ++i; } } - tries++; - if (BUTTON_PRESS()) return; - } while (num_blocks != max_blocks); + ++tries; + if (BUTTON_PRESS()) { + Dbprintf("Button pressed, stopping."); + goto end; + } + } + while (found_blocks != max_blocks); + end: Dbprintf("-----------------------------------------"); Dbprintf("Memory content:"); Dbprintf("-----------------------------------------"); - for(i=0; i", i); } Dbprintf("-----------------------------------------"); - + + if (found_blocks < max_blocks) { + Dbprintf("-----------------------------------------"); + Dbprintf("Blocks with unknown position:"); + Dbprintf("-----------------------------------------"); + for (i = 0; i < single_blocks_cnt; ++i) + print_result("Block", single_blocks[i], 16); + + Dbprintf("-----------------------------------------"); + } cmd_send(CMD_ACK,0,0,0,0,0); } - -/* Write on a byte of a PCF7931 tag - * @param address : address of the block to write - @param byte : address of the byte to write - @param data : data to write - */ -void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, uint8_t pass5, uint8_t pass6, uint8_t pass7, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data) -{ - +static void RealWritePCF7931(uint8_t *pass, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data) { uint32_t tab[1024]={0}; // data times frame uint32_t u = 0; uint8_t parity = 0; bool comp = 0; //BUILD OF THE DATA FRAME - //alimentation of the tag (time for initializing) AddPatternPCF7931(init_delay, 0, 8192/2*T0_PCF, tab); - - //PMC - Dbprintf("Initialization delay : %d us", init_delay); AddPatternPCF7931(8192/2*T0_PCF + 319*T0_PCF+70, 3*T0_PCF, 29*T0_PCF, tab); - - Dbprintf("Offsets : %d us on the low pulses width, %d us on the low pulses positions", l, p); - //password indication bit AddBitPCF7931(1, tab, l, p); - - - //password (on 56 bits) - Dbprintf("Password (LSB first on each byte) : %02x %02x %02x %02x %02x %02x %02x", pass1,pass2,pass3,pass4,pass5,pass6,pass7); - AddBytePCF7931(pass1, tab, l, p); - AddBytePCF7931(pass2, tab, l, p); - AddBytePCF7931(pass3, tab, l, p); - AddBytePCF7931(pass4, tab, l, p); - AddBytePCF7931(pass5, tab, l, p); - AddBytePCF7931(pass6, tab, l, p); - AddBytePCF7931(pass7, tab, l, p); - + // password (on 56 bits) + AddBytePCF7931(pass[0], tab, l, p); + AddBytePCF7931(pass[1], tab, l, p); + AddBytePCF7931(pass[2], tab, l, p); + AddBytePCF7931(pass[3], tab, l, p); + AddBytePCF7931(pass[4], tab, l, p); + AddBytePCF7931(pass[5], tab, l, p); + AddBytePCF7931(pass[6], tab, l, p); //programming mode (0 or 1) AddBitPCF7931(0, tab, l, p); - + //block adress on 6 bits - Dbprintf("Block address : %02x", address); - for (u=0; u<6; u++) - { - if (address&(1< 0xFFFF){ + for (u = 0; tab[u] != 0; ++u) + if(tab[u] > 0xFFFF) { tab[u] -= 0xFFFF; comp = 0; } - } } SendCmdPCF7931(tab); } +void BruteForcePCF7931(uint64_t password, uint8_t tries, uint16_t init_delay, int32_t l, int32_t p) { + uint8_t i = 0; + uint8_t pass_array[7]; + + while (password < 0x00FFFFFFFFFFFFFF) { + if (BUTTON_PRESS()) { + Dbprintf("Button pressed, stopping bruteforce ..."); + return; + } + + pass_array[0] = password & 0xFF; + pass_array[1] = (password >> 8) & 0xFF; + pass_array[2] = (password >> 16) & 0xFF; + pass_array[3] = (password >> 24) & 0xFF; + pass_array[4] = (password >> 32) & 0xFF; + pass_array[5] = (password >> 40) & 0xFF; + pass_array[6] = (password >> 48) & 0xFF; + + Dbprintf("Trying: %02x %02x %02x %02x %02x %02x %02x ...", + pass_array[0], + pass_array[1], + pass_array[2], + pass_array[3], + pass_array[4], + pass_array[5], + pass_array[6]); + + for (i = 0; i < tries; ++i) + RealWritePCF7931 + ( + pass_array, + init_delay, + l, + p, + 0, + 7, + 0x01 + ); + + ++password; + } +} + +/* Write on a byte of a PCF7931 tag + * @param address : address of the block to write + @param byte : address of the byte to write + @param data : data to write + */ +void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, uint8_t pass5, uint8_t pass6, uint8_t pass7, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data) { + Dbprintf("Initialization delay : %d us", init_delay); + Dbprintf("Offsets : %d us on the low pulses width, %d us on the low pulses positions", l, p); + Dbprintf("Password (LSB first on each byte): %02x %02x %02x %02x %02x %02x %02x", pass1, pass2, pass3, pass4, pass5, pass6, pass7); + Dbprintf("Block address : %02x", address); + Dbprintf("Byte address : %02x", byte); + Dbprintf("Data : %02x", data); + + uint8_t password[7] = {pass1, pass2, pass3, pass4, pass5, pass6, pass7}; + + RealWritePCF7931 (password, init_delay, l, p, address, byte, data); +} + /* Send a trame to a PCF7931 tags * @param tab : array of the data frame */ -void SendCmdPCF7931(uint32_t * tab){ +void SendCmdPCF7931(uint32_t * tab) { uint16_t u=0; uint16_t tempo=0; - Dbprintf("SENDING DATA FRAME..."); + Dbprintf("Sending data frame ..."); FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU ); LED_A_ON(); @@ -412,41 +481,30 @@ void SendCmdPCF7931(uint32_t * tab){ AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN; AT91C_BASE_TCB->TCB_BCR = 1; - tempo = AT91C_BASE_TC0->TC_CV; - for(u=0;tab[u]!= 0;u+=3){ - - + for (u = 0; tab[u] != 0; u += 3) { // modulate antenna HIGH(GPIO_SSC_DOUT); - while(tempo != tab[u]){ + while(tempo != tab[u]) tempo = AT91C_BASE_TC0->TC_CV; - } - + // stop modulating antenna LOW(GPIO_SSC_DOUT); - while(tempo != tab[u+1]){ + while(tempo != tab[u+1]) tempo = AT91C_BASE_TC0->TC_CV; - } - // modulate antenna HIGH(GPIO_SSC_DOUT); - while(tempo != tab[u+2]){ + while(tempo != tab[u+2]) tempo = AT91C_BASE_TC0->TC_CV; - } - - } LED_A_OFF(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); SpinDelay(200); - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable - DbpString("FINISH !"); - DbpString("(Could be usefull to send the same trame many times)"); + DbpString("Data frame sent (multiple sends may be needed)"); LED(0xFFFF, 1000); } @@ -457,15 +515,12 @@ void SendCmdPCF7931(uint32_t * tab){ * @param l : offset on low pulse width * @param p : offset on low pulse positioning */ - -bool AddBytePCF7931(uint8_t byte, uint32_t * tab, int32_t l, int32_t p){ - +bool AddBytePCF7931(uint8_t byte, uint32_t * tab, int32_t l, int32_t p) { uint32_t u; - for (u=0; u<8; u++) - { - if (byte&(1< // 2015 Dake +// 2018 sguerrini97 // 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 @@ -76,6 +77,21 @@ int usage_pcf7931_write(){ return 0; } +int usage_pcf7931_bruteforce() +{ + PrintAndLog("Usage: lf pcf7931 bruteforce [h] "); + PrintAndLog("This command tries to disable PAC of a PCF7931 transponder by bruteforcing the password."); + PrintAndLog("!! THIS IS NOT INTENDED TO RECOVER THE FULL PASSWORD !!"); + PrintAndLog("!! DO NOT USE UNLESS THE FIRST 5 BYTES OF THE PASSWORD ARE KNOWN !!"); + PrintAndLog("Options:"); + PrintAndLog(" h This help"); + PrintAndLog(" start password hex password to start from"); + PrintAndLog(" tries How many times to send the same data frame"); + PrintAndLog("Examples:"); + PrintAndLog(" lf pcf7931 bruteforce 00000000123456 3"); + return 0; +} + int usage_pcf7931_config(){ PrintAndLog("Usage: lf pcf7931 config [h] [r] "); PrintAndLog("This command tries to set the configuration used with PCF7931 commands"); @@ -159,12 +175,47 @@ int CmdLFPCF7931Write(const char *Cmd){ return 0; } +int CmdLFPCF7931BruteForce(const char *Cmd){ + + uint8_t ctmp = param_getchar(Cmd, 0); + if (strlen(Cmd) < 1 || ctmp == 'h' || ctmp == 'H') return usage_pcf7931_bruteforce(); + + uint64_t start_password = 0; + uint8_t tries = 3; + + if (param_gethex(Cmd, 0, (uint8_t*)(&start_password), 14)) return usage_pcf7931_bruteforce(); + if (param_getdec(Cmd, 1, &tries)) return usage_pcf7931_bruteforce(); + + PrintAndLog("Bruteforcing from password: %02x %02x %02x %02x %02x %02x %02x", + start_password & 0xFF, + (start_password >> 8) & 0xFF, + (start_password >> 16) & 0xFF, + (start_password >> 24) & 0xFF, + (start_password >> 32) & 0xFF, + (start_password >> 48) & 0xFF, + (start_password >> 56) & 0xFF); + + PrintAndLog("Trying each password %d times", tries); + + UsbCommand c = {CMD_PCF7931_BRUTEFORCE, {start_password, tries} }; + + c.d.asDwords[7] = (configPcf.OffsetWidth + 128); + c.d.asDwords[8] = (configPcf.OffsetPosition + 128); + c.d.asDwords[9] = configPcf.InitDelay; + + clearCommandBuffer(); + SendCommand(&c); + //no ack? + return 0; +} + static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"read", CmdLFPCF7931Read, 0, "Read content of a PCF7931 transponder"}, {"write", CmdLFPCF7931Write, 0, "Write data on a PCF7931 transponder."}, {"config", CmdLFPCF7931Config, 1, "Configure the password, the tags initialization delay and time offsets (optional)"}, + {"bruteforce", CmdLFPCF7931BruteForce, 0, "Bruteforce a PCF7931 transponder password."}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdlfpcf7931.h b/client/cmdlfpcf7931.h index 8b24f03a..32f8491e 100644 --- a/client/cmdlfpcf7931.h +++ b/client/cmdlfpcf7931.h @@ -1,6 +1,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 2012 Chalk // 2015 Dake +// 2018 sguerrini97 // 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 @@ -26,12 +27,14 @@ int pcf7931_printConfig(); int usage_pcf7931_read(); int usage_pcf7931_write(); +int usage_pcf7931_bruteforce(); int usage_pcf7931_config(); int CmdLFPCF7931(const char *Cmd); int CmdLFPCF7931Read(const char *Cmd); int CmdLFPCF7931Write(const char *Cmd); +int CmdLFPCF7931BruteForce(const char *Cmd); int CmdLFPCF7931Config(const char *Cmd); #endif diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 306c52bf..32296ba3 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -97,6 +97,7 @@ typedef struct{ #define CMD_T55XX_RESET_READ 0x0216 #define CMD_PCF7931_READ 0x0217 #define CMD_PCF7931_WRITE 0x0222 +#define CMD_PCF7931_BRUTEFORCE 0x0226 #define CMD_EM4X_READ_WORD 0x0218 #define CMD_EM4X_WRITE_WORD 0x0219 #define CMD_IO_DEMOD_FSK 0x021A From 786ad91c85238557ea60144971ee6aea271315e8 Mon Sep 17 00:00:00 2001 From: Fl0-0 Date: Mon, 7 Jan 2019 08:55:04 +0100 Subject: [PATCH 041/189] Fix CMD_PCF7931_BRUTEFORCE duplicate case value (#750) --- include/usb_cmd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 32296ba3..e73aa2a7 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -97,7 +97,7 @@ typedef struct{ #define CMD_T55XX_RESET_READ 0x0216 #define CMD_PCF7931_READ 0x0217 #define CMD_PCF7931_WRITE 0x0222 -#define CMD_PCF7931_BRUTEFORCE 0x0226 +#define CMD_PCF7931_BRUTEFORCE 0x0227 #define CMD_EM4X_READ_WORD 0x0218 #define CMD_EM4X_WRITE_WORD 0x0219 #define CMD_IO_DEMOD_FSK 0x021A From 6b6c3be6b9a452af629c6b4f06d44f3ab2fd40c6 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Sat, 12 Jan 2019 13:24:22 +0100 Subject: [PATCH 042/189] Added ATR decoding (RfidResearchGroup PRs 67/68 by @merlokk) (#749) ... and fixed merge errors in cmdsmartcard.c --- client/cmdsmartcard.c | 303 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 278 insertions(+), 25 deletions(-) diff --git a/client/cmdsmartcard.c b/client/cmdsmartcard.c index 4258989c..c6f08aa4 100644 --- a/client/cmdsmartcard.c +++ b/client/cmdsmartcard.c @@ -20,6 +20,7 @@ #include "cmdhf.h" // CmdHFlist #include "emv/apduinfo.h" // APDUcode description #include "emv/emvcore.h" // decodeTVL +#include "emv/dump.h" // dump_buffer static int CmdHelp(const char *Cmd); @@ -90,6 +91,193 @@ static int usage_sm_brute(void) { return 0; } +uint8_t GetATRTA1(uint8_t *atr, size_t atrlen) { + if (atrlen > 2) { + uint8_t T0 = atr[1]; + if (T0 & 0x10) + return atr[2]; + } + + return 0x11; // default value is 0x11, corresponding to fmax=5 MHz, Fi=372, Di=1. +} + +int DiArray[] = { + 0, // b0000 RFU + 1, // b0001 + 2, + 4, + 8, + 16, + 32, // b0110 + 64, // b0111. This was RFU in ISO/IEC 7816-3:1997 and former. Some card readers or drivers may erroneously reject cards using this value + 12, + 20, + 0, // b1010 RFU + 0, + 0, // ... + 0, + 0, + 0 // b1111 RFU +}; + +int FiArray[] = { + 372, // b0000 Historical note: in ISO/IEC 7816-3:1989, this was assigned to cards with internal clock + 372, // b0001 + 558, // b0010 + 744, // b0011 + 1116, // b0100 + 1488, // b0101 + 1860, // b0110 + 0, // b0111 RFU + 0, // b1000 RFU + 512, // b1001 + 768, // b1010 + 1024, // b1011 + 1536, // b1100 + 2048, // b1101 + 0, // b1110 RFU + 0 // b1111 RFU +}; + +float FArray[] = { + 4, // b0000 Historical note: in ISO/IEC 7816-3:1989, this was assigned to cards with internal clock + 5, // b0001 + 6, // b0010 + 8, // b0011 + 12, // b0100 + 16, // b0101 + 20, // b0110 + 0, // b0111 RFU + 0, // b1000 RFU + 5, // b1001 + 7.5, // b1010 + 10, // b1011 + 15, // b1100 + 20, // b1101 + 0, // b1110 RFU + 0 // b1111 RFU +}; + +int GetATRDi(uint8_t *atr, size_t atrlen) { + uint8_t TA1 = GetATRTA1(atr, atrlen); + + return DiArray[TA1 & 0x0f]; // The 4 low-order bits of TA1 (4th MSbit to 1st LSbit) encode Di +} + +int GetATRFi(uint8_t *atr, size_t atrlen) { + uint8_t TA1 = GetATRTA1(atr, atrlen); + + return FiArray[TA1 >> 4]; // The 4 high-order bits of TA1 (8th MSbit to 5th LSbit) encode fmax and Fi +} + +float GetATRF(uint8_t *atr, size_t atrlen) { + uint8_t TA1 = GetATRTA1(atr, atrlen); + + return FArray[TA1 >> 4]; // The 4 high-order bits of TA1 (8th MSbit to 5th LSbit) encode fmax and Fi +} + +static int PrintATR(uint8_t *atr, size_t atrlen) { + uint8_t vxor = 0; + for (int i = 1; i < atrlen; i++) + vxor ^= atr[i]; + + if (vxor) + PrintAndLogEx(WARNING, "Check summ error. Must be 0 but: 0x%02x", vxor); + else + PrintAndLogEx(INFO, "Check summ OK."); + + if (atr[0] != 0x3b) + PrintAndLogEx(WARNING, "Not a direct convention: 0x%02x", atr[0]); + + uint8_t T0 = atr[1]; + uint8_t K = T0 & 0x0F; + uint8_t TD1 = 0; + + uint8_t T1len = 0; + uint8_t TD1len = 0; + uint8_t TDilen = 0; + + if (T0 & 0x10) { + PrintAndLog("TA1 (Maximum clock frequency, proposed bit duration): 0x%02x", atr[2 + T1len]); + T1len++; + } + if (T0 & 0x20) { + PrintAndLog("TB1 (Deprecated: VPP requirements): 0x%02x", atr[2 + T1len]); + T1len++; + } + if (T0 & 0x40) { + PrintAndLog("TC1 (Extra delay between bytes required by card): 0x%02x", atr[2 + T1len]); + T1len++; + } + if (T0 & 0x80) { + TD1 = atr[2 + T1len]; + PrintAndLog("TD1 (First offered transmission protocol, presence of TA2..TD2): 0x%02x. Protocol T=%d", TD1, TD1 & 0x0f); + T1len++; + + if (TD1 & 0x10) { + PrintAndLog("TA2 (Specific protocol and parameters to be used after the ATR): 0x%02x", atr[2 + T1len + TD1len]); + TD1len++; + } + if (TD1 & 0x20) { + PrintAndLog("TB2 (Deprecated: VPP precise voltage requirement): 0x%02x", atr[2 + T1len + TD1len]); + TD1len++; + } + if (TD1 & 0x40) { + PrintAndLog("TC2 (Maximum waiting time for protocol T=0): 0x%02x", atr[2 + T1len + TD1len]); + TD1len++; + } + if (TD1 & 0x80) { + uint8_t TDi = atr[2 + T1len + TD1len]; + PrintAndLog("TD2 (A supported protocol or more global parameters, presence of TA3..TD3): 0x%02x. Protocol T=%d", TDi, TDi & 0x0f); + TD1len++; + + bool nextCycle = true; + uint8_t vi = 3; + while (nextCycle) { + nextCycle = false; + if (TDi & 0x10) { + PrintAndLog("TA%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]); + TDilen++; + } + if (TDi & 0x20) { + PrintAndLog("TB%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]); + TDilen++; + } + if (TDi & 0x40) { + PrintAndLog("TC%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]); + TDilen++; + } + if (TDi & 0x80) { + TDi = atr[2 + T1len + TD1len + TDilen]; + PrintAndLog("TD%d: 0x%02x. Protocol T=%d", vi, TDi, TDi & 0x0f); + TDilen++; + + nextCycle = true; + vi++; + } + } + } + } + + uint8_t calen = 2 + T1len + TD1len + TDilen + K; + + if (atrlen != calen && atrlen != calen + 1) // may be CRC + PrintAndLogEx(ERR, "ATR length error. len: %d, T1len: %d, TD1len: %d, TDilen: %d, K: %d", atrlen, T1len, TD1len, TDilen, K); + else + PrintAndLogEx(INFO, "ATR length OK."); + + PrintAndLog("Historical bytes len: 0x%02x", K); + if (K > 0) + PrintAndLog("The format of historical bytes: %02x", atr[2 + T1len + TD1len + TDilen]); + if (K > 1) { + PrintAndLog("Historical bytes:"); + dump_buffer(&atr[2 + T1len + TD1len + TDilen], K, NULL, 1); + } + + return 0; +} + + static bool smart_select(bool silent) { UsbCommand c = {CMD_SMART_ATR, {0, 0, 0}}; clearCommandBuffer(); @@ -137,29 +325,55 @@ static int smart_wait(uint8_t *data) { return len; } -static int smart_response(uint8_t *data) { +static int smart_response(uint8_t apduINS, uint8_t *data) { - int len = -1; int datalen = smart_wait(data); + bool needGetData = false; - if ( data[datalen - 2] == 0x61 || data[datalen - 2] == 0x9F ) { - len = data[datalen - 1]; - } - - if (len == -1 ) { + if (datalen < 2 ) { goto out; } - PrintAndLogEx(INFO, "Requesting response. len=0x%x", len); - uint8_t getstatus[] = {ISO7816_GETSTATUS, 0x00, 0x00, len}; - UsbCommand cStatus = {CMD_SMART_RAW, {SC_RAW, sizeof(getstatus), 0}}; - memcpy(cStatus.d.asBytes, getstatus, sizeof(getstatus) ); - clearCommandBuffer(); - SendCommand(&cStatus); + if (datalen > 2 && data[0] != apduINS) { + PrintAndLogEx(ERR, "Card ACK error. len=0x%x data[0]=%02x", datalen, data[0]); + datalen = 0; + goto out; + } - datalen = smart_wait(data); -out: + if ( data[datalen - 2] == 0x61 || data[datalen - 2] == 0x9F ) { + needGetData = true; + } + if (needGetData) { + int len = data[datalen - 1]; + PrintAndLogEx(INFO, "Requesting response. len=0x%x", len); + uint8_t getstatus[] = {ISO7816_GETSTATUS, 0x00, 0x00, len}; + UsbCommand cStatus = {CMD_SMART_RAW, {SC_RAW, sizeof(getstatus), 0}}; + memcpy(cStatus.d.asBytes, getstatus, sizeof(getstatus) ); + clearCommandBuffer(); + SendCommand(&cStatus); + + datalen = smart_wait(data); + + if (datalen < 2 ) { + goto out; + } + if (datalen > 2 && data[0] != ISO7816_GETSTATUS) { + PrintAndLogEx(ERR, "GetResponse ACK error. len=0x%x data[0]=%02x", len, data[0]); + datalen = 0; + goto out; + } + + if (datalen != len + 2 + 1) { // 2 - response, 1 - ACK + PrintAndLogEx(WARNING, "GetResponse wrong length. Must be: 0x%02x but: 0x%02x", len, datalen - 3); + } + } + + if (datalen > 2) { + datalen--; + memmove(data, &data[1], datalen); + } + out: return datalen; } @@ -225,13 +439,13 @@ int CmdSmartRaw(const char *Cmd) { UsbCommand c = {CMD_SMART_RAW, {0, hexlen, 0}}; if (active || active_select) { - c.arg[0] |= SC_CONNECT; - if (active_select) - c.arg[0] |= SC_SELECT; - } + c.arg[0] |= SC_CONNECT; + if (active_select) + c.arg[0] |= SC_SELECT; + } if (hexlen > 0) { - c.arg[0] |= SC_RAW; + c.arg[0] |= SC_RAW; } memcpy(c.d.asBytes, data, hexlen ); @@ -245,7 +459,7 @@ int CmdSmartRaw(const char *Cmd) { if ( !buf ) return 1; - int len = smart_response(buf); + int len = smart_response(data[1], buf); if ( len < 0 ) { free(buf); return 2; @@ -257,7 +471,7 @@ int CmdSmartRaw(const char *Cmd) { memcpy(c.d.asBytes, data, sizeof(data) ); clearCommandBuffer(); SendCommand(&c); - len = smart_response(buf); + len = smart_response(data[1], buf); data[4] = 0; } @@ -285,12 +499,29 @@ int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leave clearCommandBuffer(); SendCommand(&c); - int len = smart_response(dataout); + int len = smart_response(datain[1], dataout); if ( len < 0 ) { return 2; } + + // retry + if (len > 1 && dataout[len - 2] == 0x6c && datainlen > 4) { + UsbCommand c2 = {CMD_SMART_RAW, {SC_RAW, datainlen, 0}}; + memcpy(c2.d.asBytes, datain, datainlen); + + int vlen = 5 + datain[4]; + if (datainlen == vlen) + datainlen++; + + c2.d.asBytes[vlen] = dataout[len - 1]; + + clearCommandBuffer(); + SendCommand(&c2); + + len = smart_response(datain[1], dataout); + } *dataoutlen = len; return 0; @@ -449,6 +680,28 @@ int CmdSmartInfo(const char *Cmd){ PrintAndLogEx(INFO, "ISO76183 ATR : %s", sprint_hex(card.atr, card.atr_len)); PrintAndLogEx(INFO, "look up ATR"); PrintAndLogEx(INFO, "http://smartcard-atr.appspot.com/parse?ATR=%s", sprint_hex_inrow(card.atr, card.atr_len) ); + + // print ATR + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "* ATR:"); + PrintATR(card.atr, card.atr_len); + + // print D/F (brom byte TA1 or defaults) + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "* D/F (TA1):"); + int Di = GetATRDi(card.atr, card.atr_len); + int Fi = GetATRFi(card.atr, card.atr_len); + float F = GetATRF(card.atr, card.atr_len); + if (GetATRTA1(card.atr, card.atr_len) == 0x11) + PrintAndLogEx(INFO, "Using default values..."); + + PrintAndLogEx(NORMAL, "Di=%d", Di); + PrintAndLogEx(NORMAL, "Fi=%d", Fi); + PrintAndLogEx(NORMAL, "F=%.1f MHz", F); + PrintAndLogEx(NORMAL, "Cycles/ETU=%d", Fi/Di); + PrintAndLogEx(NORMAL, "%.1f bits/sec at 4MHz", (float)4000000 / (Fi/Di)); + PrintAndLogEx(NORMAL, "%.1f bits/sec at Fmax=%.1fMHz", (F * 1000000) / (Fi/Di), F); + return 0; } @@ -587,7 +840,7 @@ int CmdSmartBruteforceSFI(const char *Cmd) { clearCommandBuffer(); SendCommand(&c); - smart_response(buf); + smart_response(data[1], buf); // if 0x6C if ( buf[0] == 0x6C ) { @@ -596,7 +849,7 @@ int CmdSmartBruteforceSFI(const char *Cmd) { memcpy(c.d.asBytes, data, sizeof(data) ); clearCommandBuffer(); SendCommand(&c); - uint8_t len = smart_response(buf); + uint8_t len = smart_response(data[1], buf); // TLV decoder if (len > 4) From 9f596ec7ac317c7e0e6d60610a20fb1f3feba194 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Sat, 12 Jan 2019 13:26:53 +0100 Subject: [PATCH 043/189] RDV4.0 Smartcard Slot Firmware Upgrade (#751) * RDV4.0 Smartcard Slot Firmware Upgrade * new firmware in client/sc_upgrade_firmware directory * improved sc upgrade: * check SHA-512 of firmware file * search and find firmware file in predefined directory * more sanity checks * fixed offline indicators of sc commands --- .gitignore | 1 + client/cmdsmartcard.c | 153 +++++++++++++++---- client/crypto/libpcrypto.c | 15 ++ client/crypto/libpcrypto.h | 1 + client/sc_upgrade_firmware/SIM010.BIN | Bin 0 -> 719 bytes client/sc_upgrade_firmware/SIM010.md5.txt | 1 + client/sc_upgrade_firmware/SIM010.sha512.txt | 1 + client/sc_upgrade_firmware/readme.txt | 36 +++++ 8 files changed, 180 insertions(+), 28 deletions(-) create mode 100644 client/sc_upgrade_firmware/SIM010.BIN create mode 100644 client/sc_upgrade_firmware/SIM010.md5.txt create mode 100644 client/sc_upgrade_firmware/SIM010.sha512.txt create mode 100644 client/sc_upgrade_firmware/readme.txt diff --git a/.gitignore b/.gitignore index c551f7a2..852056a7 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ *.map *.bin !client/hardnested/*.bin +!client/sc_upgrade_firmware/*.bin *.dll *.moc.cpp *.z diff --git a/client/cmdsmartcard.c b/client/cmdsmartcard.c index c6f08aa4..80cbec46 100644 --- a/client/cmdsmartcard.c +++ b/client/cmdsmartcard.c @@ -13,6 +13,7 @@ #include "ui.h" #include "cmdparser.h" +#include "proxmark3.h" #include "util.h" #include "smartcard.h" #include "comms.h" @@ -20,8 +21,10 @@ #include "cmdhf.h" // CmdHFlist #include "emv/apduinfo.h" // APDUcode description #include "emv/emvcore.h" // decodeTVL +#include "crypto/libpcrypto.h" // sha512hash #include "emv/dump.h" // dump_buffer +#define SC_UPGRADE_FILES_DIRECTORY "sc_upgrade_firmware/" static int CmdHelp(const char *Cmd); @@ -61,13 +64,13 @@ static int usage_sm_info(void) { } static int usage_sm_upgrade(void) { - PrintAndLogEx(NORMAL, "Upgrade firmware"); + PrintAndLogEx(NORMAL, "Upgrade RDV4.0 Smartcard Socket Firmware"); PrintAndLogEx(NORMAL, "Usage: sc upgrade f "); PrintAndLogEx(NORMAL, " h : this help"); PrintAndLogEx(NORMAL, " f : firmware file name"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " sc upgrade f myfile"); + PrintAndLogEx(NORMAL, " sc upgrade f SIM010.BIN"); return 0; } @@ -466,7 +469,7 @@ int CmdSmartRaw(const char *Cmd) { } if ( buf[0] == 0x6C ) { - data[4] = buf[1]; + data[4] = buf[1]; memcpy(c.d.asBytes, data, sizeof(data) ); clearCommandBuffer(); @@ -530,8 +533,10 @@ int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leave int CmdSmartUpgrade(const char *Cmd) { - PrintAndLogEx(WARNING, "WARNING - Smartcard socket firmware upgrade."); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(WARNING, "WARNING - RDV4.0 Smartcard Socket Firmware upgrade."); PrintAndLogEx(WARNING, "A dangerous command, do wrong and you will brick the smart card socket"); + PrintAndLogEx(NORMAL, ""); FILE *f; char filename[FILE_PATH_SIZE] = {0}; @@ -547,6 +552,7 @@ int CmdSmartUpgrade(const char *Cmd) { errors = true; break; } + cmdp += 2; break; case 'h': @@ -561,40 +567,131 @@ int CmdSmartUpgrade(const char *Cmd) { //Validations if (errors || cmdp == 0 ) return usage_sm_upgrade(); - // load file - f = fopen(filename, "rb"); + if (strchr(filename, '\\') || strchr(filename, '/')) { + PrintAndLogEx(FAILED, "Filename must not contain \\ or /. Firmware file will be found in client/sc_upgrade_firmware directory."); + return 1; + } + + char sc_upgrade_file_path[strlen(get_my_executable_directory()) + strlen(SC_UPGRADE_FILES_DIRECTORY) + strlen(filename) + 1]; + strcpy(sc_upgrade_file_path, get_my_executable_directory()); + strcat(sc_upgrade_file_path, SC_UPGRADE_FILES_DIRECTORY); + strcat(sc_upgrade_file_path, filename); + if (strlen(sc_upgrade_file_path) >= FILE_PATH_SIZE ) { + PrintAndLogEx(FAILED, "Filename too long"); + return 1; + } + + char sha512filename[FILE_PATH_SIZE]; + char *bin_extension = filename; + char *dot_position = NULL; + while ((dot_position = strchr(bin_extension, '.')) != NULL) { + bin_extension = dot_position + 1; + } + if (!strcmp(bin_extension, "BIN") +#ifdef _WIN32 + || !strcmp(bin_extension, "bin") +#endif + ) { + strncpy(sha512filename, filename, strlen(filename) - strlen("bin")); + strcat(sha512filename, "sha512.txt"); + } else { + PrintAndLogEx(FAILED, "Filename extension of Firmware Upgrade File must be .BIN"); + return 1; + } + + PrintAndLogEx(INFO, "Checking integrity using SHA512 File %s ...", sha512filename); + char sc_upgrade_sha512file_path[strlen(get_my_executable_directory()) + strlen(SC_UPGRADE_FILES_DIRECTORY) + strlen(sha512filename) + 1]; + strcpy(sc_upgrade_sha512file_path, get_my_executable_directory()); + strcat(sc_upgrade_sha512file_path, SC_UPGRADE_FILES_DIRECTORY); + strcat(sc_upgrade_sha512file_path, sha512filename); + if (strlen(sc_upgrade_sha512file_path) >= FILE_PATH_SIZE ) { + PrintAndLogEx(FAILED, "Filename too long"); + return 1; + } + + // load firmware file + f = fopen(sc_upgrade_file_path, "rb"); if ( !f ){ - PrintAndLogEx(FAILED, "File: %s: not found or locked.", filename); + PrintAndLogEx(FAILED, "Firmware file not found or locked."); return 1; } // get filesize in order to malloc memory fseek(f, 0, SEEK_END); - long fsize = ftell(f); + size_t fsize = ftell(f); fseek(f, 0, SEEK_SET); - if (fsize < 0) { - PrintAndLogEx(WARNING, "error, when getting filesize"); + if (fsize < 0) { + PrintAndLogEx(FAILED, "Could not determine size of firmware file"); fclose(f); return 1; } uint8_t *dump = calloc(fsize, sizeof(uint8_t)); if (!dump) { - PrintAndLogEx(WARNING, "error, cannot allocate memory "); + PrintAndLogEx(FAILED, "Could not allocate memory for firmware"); fclose(f); return 1; } - size_t bytes_read = fread(dump, 1, fsize, f); + size_t firmware_size = fread(dump, 1, fsize, f); if (f) fclose(f); - PrintAndLogEx(SUCCESS, "Smartcard socket firmware uploading to PM3"); + // load sha512 file + f = fopen(sc_upgrade_sha512file_path, "rb"); + if ( !f ){ + PrintAndLogEx(FAILED, "SHA-512 file not found or locked."); + return 1; + } + + // get filesize in order to malloc memory + fseek(f, 0, SEEK_END); + fsize = ftell(f); + fseek(f, 0, SEEK_SET); + + if (fsize < 0) { + PrintAndLogEx(FAILED, "Could not determine size of SHA-512 file"); + fclose(f); + return 1; + } + + if (fsize < 128) { + PrintAndLogEx(FAILED, "SHA-512 file too short"); + fclose(f); + return 1; + } + + char hashstring[129]; + size_t bytes_read = fread(hashstring, 1, 128, f); + hashstring[128] = '\0'; + + if (f) + fclose(f); + + uint8_t hash1[64]; + if (bytes_read != 128 || param_gethex(hashstring, 0, hash1, 128)) { + PrintAndLogEx(FAILED, "Couldn't read SHA-512 file"); + return 1; + } + + uint8_t hash2[64]; + if (sha512hash(dump, firmware_size, hash2)) { + PrintAndLogEx(FAILED, "Couldn't calculate SHA-512 of Firmware"); + return 1; + } + + if (memcmp(hash1, hash2, 64)) { + PrintAndLogEx(FAILED, "Couldn't verify integrity of Firmware file (wrong SHA-512)"); + return 1; + } + + PrintAndLogEx(SUCCESS, "RDV4.0 Smartcard Socket Firmware uploading to PM3"); + //Send to device uint32_t index = 0; uint32_t bytes_sent = 0; - uint32_t bytes_remaining = bytes_read; + uint32_t bytes_remaining = firmware_size; while (bytes_remaining > 0){ uint32_t bytes_in_packet = MIN(USB_CMD_DATA_SIZE, bytes_remaining); @@ -617,10 +714,10 @@ int CmdSmartUpgrade(const char *Cmd) { } free(dump); printf("\n"); - PrintAndLogEx(SUCCESS, "Smartcard socket firmware updating, don\'t turn off your PM3!"); + PrintAndLogEx(SUCCESS, "RDV4.0 Smartcard Socket Firmware updating, don\'t turn off your PM3!"); // trigger the firmware upgrade - UsbCommand c = {CMD_SMART_UPGRADE, {bytes_read, 0, 0}}; + UsbCommand c = {CMD_SMART_UPGRADE, {firmware_size, 0, 0}}; clearCommandBuffer(); SendCommand(&c); UsbCommand resp; @@ -629,9 +726,9 @@ int CmdSmartUpgrade(const char *Cmd) { return 1; } if ( (resp.arg[0] & 0xFF ) ) - PrintAndLogEx(SUCCESS, "Smartcard socket firmware upgraded successful"); + PrintAndLogEx(SUCCESS, "RDV4.0 Smartcard Socket Firmware upgraded successful"); else - PrintAndLogEx(FAILED, "Smartcard socket firmware updating failed"); + PrintAndLogEx(FAILED, "RDV4.0 Smartcard Socket Firmware Upgrade failed"); return 0; } @@ -844,7 +941,7 @@ int CmdSmartBruteforceSFI(const char *Cmd) { // if 0x6C if ( buf[0] == 0x6C ) { - data[4] = buf[1]; + data[4] = buf[1]; memcpy(c.d.asBytes, data, sizeof(data) ); clearCommandBuffer(); @@ -865,15 +962,15 @@ int CmdSmartBruteforceSFI(const char *Cmd) { } static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help"}, - {"list", CmdSmartList, 0, "List ISO 7816 history"}, - {"info", CmdSmartInfo, 1, "Tag information"}, - {"reader", CmdSmartReader, 1, "Act like an IS07816 reader"}, - {"raw", CmdSmartRaw, 1, "Send raw hex data to tag"}, - {"upgrade", CmdSmartUpgrade, 1, "Upgrade firmware"}, - {"setclock", CmdSmartSetClock, 1, "Set clock speed"}, - {"brute", CmdSmartBruteforceSFI, 1, "Bruteforce SFI"}, - {NULL, NULL, 0, NULL} + {"help", CmdHelp, 1, "This help"}, + {"list", CmdSmartList, 0, "List ISO 7816 history"}, + {"info", CmdSmartInfo, 0, "Tag information"}, + {"reader", CmdSmartReader, 0, "Act like an IS07816 reader"}, + {"raw", CmdSmartRaw, 0, "Send raw hex data to tag"}, + {"upgrade", CmdSmartUpgrade, 0, "Upgrade firmware"}, + {"setclock", CmdSmartSetClock, 0, "Set clock speed"}, + {"brute", CmdSmartBruteforceSFI, 0, "Bruteforce SFI"}, + {NULL, NULL, 0, NULL} }; int CmdSmartcard(const char *Cmd) { diff --git a/client/crypto/libpcrypto.c b/client/crypto/libpcrypto.c index 896048bf..ebc1e987 100644 --- a/client/crypto/libpcrypto.c +++ b/client/crypto/libpcrypto.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -106,6 +107,20 @@ int sha256hash(uint8_t *input, int length, uint8_t *hash) { return 0; } +int sha512hash(uint8_t *input, int length, uint8_t *hash) { + if (!hash || !input) + return 1; + + mbedtls_sha512_context sctx; + mbedtls_sha512_init(&sctx); + mbedtls_sha512_starts(&sctx, 0); //SHA-512, not 384 + mbedtls_sha512_update(&sctx, input, length); + mbedtls_sha512_finish(&sctx, hash); + mbedtls_sha512_free(&sctx); + + return 0; +} + int ecdsa_init_str(mbedtls_ecdsa_context *ctx, char * key_d, char *key_x, char *key_y) { if (!ctx) return 1; diff --git a/client/crypto/libpcrypto.h b/client/crypto/libpcrypto.h index 7ac6c3b0..7e70cbfc 100644 --- a/client/crypto/libpcrypto.h +++ b/client/crypto/libpcrypto.h @@ -22,6 +22,7 @@ extern int aes_cmac(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, int extern int aes_cmac8(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, int length); extern int sha256hash(uint8_t *input, int length, uint8_t *hash); +extern int sha512hash(uint8_t *input, int length, uint8_t *hash); extern int ecdsa_key_create(uint8_t * key_d, uint8_t *key_xy); extern int ecdsa_public_key_from_pk(mbedtls_pk_context *pk, uint8_t *key, size_t keylen); diff --git a/client/sc_upgrade_firmware/SIM010.BIN b/client/sc_upgrade_firmware/SIM010.BIN new file mode 100644 index 0000000000000000000000000000000000000000..dea57a7d8608a34020f7d9e5e40a5b6e915be6fa GIT binary patch literal 719 zcmbVJO=uHA6rS1L$-l5DLa~?K$zPi&EQ<%hi&CM-7^G)Cc=O`ri3c%jCH{bwbYmf* z2XzZliW1uHp@&G~bZdKD268JV2XpY2OEJ|ZaaU8USKl1o_kF{A?|VD}ucL7&IpOTI zGD})h0x#>wDni)!i+zOG{^kG6Sf3s0az&D>s?L!joojZ8)vXrkJUqrdLW$*eSQ(}+ zl9bMadb87X!JVjmY@jfA*tX&f)Jo%)%uI%v$OsFt5DTkj!?>s59LL?d9h7*~Ahr-= zQAi?AAc0iV#;3RdDFhTj+~)y7eQisz`&mdM$VlAlVUuG@e5#rXi78=0HQ&`kB(0iU z^qkg<3C}6&kp!_w(i{9{lABssVqqT9#7j)%(upyRRlyJ&TdEc!PwFABV<5-_#Z+B2 ziB*jID|Zg+Bu*^0!yL|B*IRyD_e^C1kQLy(2p1yUtAj^-uyF;}M_}KC%`NzV;Qa`m zQ+R=3;Tt@ggWWaQots(2uqpq+Hx`G`yvASgGJI-6#f7H^^sj>xf}QX1c?3%WC sc upgrade -h +pm3 --> sc upgrade f ../tools/simmodule/SIM010.bin + + + +Even its a quite fast command you should be warned. You may brick it if you interrupt it. + + + +Run hw status command to verify that the upgrade went well. + +pm3 --> hw status + + + +If you didn't download this file from the RRG Repo be aware that it might be corrupt or faulty. + +You find to hash text files in this folder. They were generated with the following linux commands. + + +md5sum -b SIM010.bin > SIM010.md5.txt +sha512sum -b SIM010.bin > SIM010.sha512.txt + + +You should validate the SIM010.bin file against these hash files in order to be sure the file is not corrupt or faulty. \ No newline at end of file From d9de20fa4bb0a36052927b55c4185caa204c5c4d Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Sat, 12 Jan 2019 13:28:26 +0100 Subject: [PATCH 044/189] Fix 15 snoop (#752) * fixing hf 15: implement hf 15 snoop * rename hf 15 record to hf 15 snoop * speedup sampling / decoding: * new FPGA mode FPGA_HF_READER_RX_XCORR_AMPLITUDE implements amplitude(ci, cq) on FPGA * inlining the decoders in iso15693.c * inlining memcpy/memset in LogTrace() * giving up the moving correlator for SOF in Handle15693SamplesFromTag * decode more of EOF in Handle15693SamplesFromTag() * some refactoring --- CHANGELOG.md | 4 +- armsrc/BigBuf.c | 31 +- armsrc/appmain.c | 6 +- armsrc/apps.h | 11 - armsrc/fpgaloader.h | 63 ++-- armsrc/iclass.c | 60 ++-- armsrc/iso14443a.c | 14 +- armsrc/iso14443b.c | 36 +- armsrc/iso15693.c | 746 +++++++++++++++++++++++----------------- armsrc/iso15693.h | 24 ++ client/cmdhf.c | 11 +- client/cmdhf15.c | 88 +++-- common/iso15693tools.h | 53 --- fpga/fpga_hf.bit | Bin 42175 -> 42175 bytes fpga/fpga_hf.v | 4 +- fpga/hi_read_rx_xcorr.v | 136 +++++--- include/usb_cmd.h | 2 +- 17 files changed, 715 insertions(+), 574 deletions(-) create mode 100644 armsrc/iso15693.h diff --git a/CHANGELOG.md b/CHANGELOG.md index 19db5195..f2c285b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ### Fixed - AC-Mode decoding for HitagS -- Wrong UID at HitagS simulation +- Wrong UID at HitagS simulation +- 'hf 15 sim' now works as expected (piwi) ### Added - Support Standard Communication Mode in HITAG S @@ -24,6 +25,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added `hf fido` `assert` and `make` commands from fido2 protocol (authenticatorMakeCredential and authenticatorGetAssertion) (Merlok) - Added `lf paradox clone` to clone a Paradox card - Added `emv` commmands working for both contactless and smart cards (Merlok) +- Added 'hf 15 snoop' (piwi) ## [v3.1.0][2018-10-10] diff --git a/armsrc/BigBuf.c b/armsrc/BigBuf.c index 4b1264b6..e2f51311 100644 --- a/armsrc/BigBuf.c +++ b/armsrc/BigBuf.c @@ -36,8 +36,8 @@ static uint16_t BigBuf_hi = BIGBUF_SIZE; static uint8_t *emulator_memory = NULL; // trace related variables -static uint16_t traceLen = 0; -int tracing = 1; //Last global one.. todo static? +static uint32_t traceLen = 0; +static bool tracing = true; // get the address of BigBuf uint8_t *BigBuf_get_addr(void) @@ -66,7 +66,7 @@ void BigBuf_Clear(void) // clear ALL of BigBuf void BigBuf_Clear_ext(bool verbose) { - memset(BigBuf,0,BIGBUF_SIZE); + memset(BigBuf, 0, BIGBUF_SIZE); if (verbose) Dbprintf("Buffer cleared (%i bytes)",BIGBUF_SIZE); } @@ -76,7 +76,7 @@ void BigBuf_Clear_EM(void){ void BigBuf_Clear_keep_EM(void) { - memset(BigBuf,0,BigBuf_hi); + memset(BigBuf, 0, BigBuf_hi); } // allocate a chunk of memory from BigBuf. We allocate high memory first. The unallocated memory @@ -162,8 +162,8 @@ bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_ uint8_t *trace = BigBuf_get_addr(); - uint16_t num_paritybytes = (iLen-1)/8 + 1; // number of valid paritybytes in *parity - uint16_t duration = timestamp_end - timestamp_start; + uint32_t num_paritybytes = (iLen-1)/8 + 1; // number of valid paritybytes in *parity + uint32_t duration = timestamp_end - timestamp_start; // Return when trace is full uint16_t max_traceLen = BigBuf_max_traceLen(); @@ -200,19 +200,23 @@ bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_ // data bytes if (btBytes != NULL && iLen != 0) { - memcpy(trace + traceLen, btBytes, iLen); + for (int i = 0; i < iLen; i++) { + trace[traceLen++] = *btBytes++; + } } - traceLen += iLen; // parity bytes if (num_paritybytes != 0) { if (parity != NULL) { - memcpy(trace + traceLen, parity, num_paritybytes); + for (int i = 0; i < num_paritybytes; i++) { + trace[traceLen++] = *parity++; + } } else { - memset(trace + traceLen, 0x00, num_paritybytes); + for (int i = 0; i < num_paritybytes; i++) { + trace[traceLen++] = 0x00; + } } } - traceLen += num_paritybytes; return true; } @@ -259,8 +263,9 @@ int LogTraceHitag(const uint8_t * btBytes, int iBits, int iSamples, uint32_t dwP trace[traceLen++] = ((dwParity >> 24) & 0xff); trace[traceLen++] = iBits; - memcpy(trace + traceLen, btBytes, iLen); - traceLen += iLen; + for (int i = 0; i < iLen; i++) { + trace[traceLen++] = *btBytes++; + } return true; } diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 58c979db..1348ef04 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -24,6 +24,7 @@ #include "legicrfsim.h" #include "hitag2.h" #include "hitagS.h" +#include "iso15693.h" #include "lfsampling.h" #include "BigBuf.h" #include "mifareutil.h" @@ -1115,8 +1116,9 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693: AcquireRawAdcSamplesIso15693(); break; - case CMD_RECORD_RAW_ADC_SAMPLES_ISO_15693: - RecordRawAdcSamplesIso15693(); + + case CMD_SNOOP_ISO_15693: + SnoopIso15693(); break; case CMD_ISO_15693_COMMAND: diff --git a/armsrc/apps.h b/armsrc/apps.h index b9b1f3de..fad9e6eb 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -25,7 +25,6 @@ extern const uint8_t OddByteParity[256]; extern int rsamples; // = 0; -extern int tracing; // = TRUE; extern uint8_t trigger; // This may be used (sparingly) to declare a function to be copied to @@ -101,7 +100,6 @@ void RAMFUNC SnoopIso14443b(void); void SendRawCommand14443B(uint32_t, uint32_t, uint8_t, uint8_t[]); // Also used in iclass.c -bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t len, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag); void GetParity(const uint8_t *pbtCmd, uint16_t len, uint8_t *parity); void RAMFUNC SniffMifare(uint8_t param); @@ -150,15 +148,6 @@ void OnSuccess(); void OnError(uint8_t reason); -/// iso15693.h -void RecordRawAdcSamplesIso15693(void); -void AcquireRawAdcSamplesIso15693(void); -void ReaderIso15693(uint32_t parameter); // Simulate an ISO15693 reader - greg -void SimTagIso15693(uint32_t parameter, uint8_t *uid); // simulate an ISO15693 tag - greg -void BruteforceIso15693Afi(uint32_t speed); // find an AFI of a tag - atrox -void DirectTag15693Command(uint32_t datalen,uint32_t speed, uint32_t recv, uint8_t data[]); // send arbitrary commands from CLI - atrox -void SetDebugIso15693(uint32_t flag); - /// iclass.h void RAMFUNC SnoopIClass(void); void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); diff --git a/armsrc/fpgaloader.h b/armsrc/fpgaloader.h index 5aff6505..0600067e 100644 --- a/armsrc/fpgaloader.h +++ b/armsrc/fpgaloader.h @@ -24,7 +24,7 @@ void SetupSpi(int mode); bool FpgaSetupSscDma(uint8_t *buf, uint16_t sample_count); void Fpga_print_status(); int FpgaGetCurrent(); -#define FpgaDisableSscDma(void) AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; +#define FpgaDisableSscDma(void) AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; #define FpgaEnableSscDma(void) AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN; void SetAdcMuxFor(uint32_t whichGpio); @@ -33,46 +33,47 @@ void SetAdcMuxFor(uint32_t whichGpio); #define FPGA_BITSTREAM_HF 2 // Definitions for the FPGA commands. -#define FPGA_CMD_SET_CONFREG (1<<12) -#define FPGA_CMD_SET_DIVISOR (2<<12) -#define FPGA_CMD_SET_USER_BYTE1 (3<<12) +#define FPGA_CMD_SET_CONFREG (1<<12) +#define FPGA_CMD_SET_DIVISOR (2<<12) +#define FPGA_CMD_SET_USER_BYTE1 (3<<12) // Definitions for the FPGA configuration word. // LF -#define FPGA_MAJOR_MODE_LF_ADC (0<<5) -#define FPGA_MAJOR_MODE_LF_EDGE_DETECT (1<<5) -#define FPGA_MAJOR_MODE_LF_PASSTHRU (2<<5) +#define FPGA_MAJOR_MODE_LF_ADC (0<<5) +#define FPGA_MAJOR_MODE_LF_EDGE_DETECT (1<<5) +#define FPGA_MAJOR_MODE_LF_PASSTHRU (2<<5) // HF -#define FPGA_MAJOR_MODE_HF_READER_TX (0<<5) -#define FPGA_MAJOR_MODE_HF_READER_RX_XCORR (1<<5) -#define FPGA_MAJOR_MODE_HF_SIMULATOR (2<<5) -#define FPGA_MAJOR_MODE_HF_ISO14443A (3<<5) -#define FPGA_MAJOR_MODE_HF_SNOOP (4<<5) +#define FPGA_MAJOR_MODE_HF_READER_TX (0<<5) +#define FPGA_MAJOR_MODE_HF_READER_RX_XCORR (1<<5) +#define FPGA_MAJOR_MODE_HF_SIMULATOR (2<<5) +#define FPGA_MAJOR_MODE_HF_ISO14443A (3<<5) +#define FPGA_MAJOR_MODE_HF_SNOOP (4<<5) // BOTH -#define FPGA_MAJOR_MODE_OFF (7<<5) +#define FPGA_MAJOR_MODE_OFF (7<<5) // Options for LF_ADC -#define FPGA_LF_ADC_READER_FIELD (1<<0) +#define FPGA_LF_ADC_READER_FIELD (1<<0) // Options for LF_EDGE_DETECT -#define FPGA_CMD_SET_EDGE_DETECT_THRESHOLD FPGA_CMD_SET_USER_BYTE1 -#define FPGA_LF_EDGE_DETECT_READER_FIELD (1<<0) -#define FPGA_LF_EDGE_DETECT_TOGGLE_MODE (1<<1) +#define FPGA_CMD_SET_EDGE_DETECT_THRESHOLD FPGA_CMD_SET_USER_BYTE1 +#define FPGA_LF_EDGE_DETECT_READER_FIELD (1<<0) +#define FPGA_LF_EDGE_DETECT_TOGGLE_MODE (1<<1) // Options for the HF reader, tx to tag -#define FPGA_HF_READER_TX_SHALLOW_MOD (1<<0) +#define FPGA_HF_READER_TX_SHALLOW_MOD (1<<0) // Options for the HF reader, correlating against rx from tag -#define FPGA_HF_READER_RX_XCORR_848_KHZ (1<<0) -#define FPGA_HF_READER_RX_XCORR_SNOOP (1<<1) -#define FPGA_HF_READER_RX_XCORR_QUARTER_FREQ (1<<2) +#define FPGA_HF_READER_RX_XCORR_848_KHZ (1<<0) +#define FPGA_HF_READER_RX_XCORR_SNOOP (1<<1) +#define FPGA_HF_READER_RX_XCORR_QUARTER_FREQ (1<<2) +#define FPGA_HF_READER_RX_XCORR_AMPLITUDE (1<<3) // Options for the HF simulated tag, how to modulate -#define FPGA_HF_SIMULATOR_NO_MODULATION (0<<0) -#define FPGA_HF_SIMULATOR_MODULATE_BPSK (1<<0) -#define FPGA_HF_SIMULATOR_MODULATE_212K (2<<0) -#define FPGA_HF_SIMULATOR_MODULATE_424K (4<<0) -#define FPGA_HF_SIMULATOR_MODULATE_424K_8BIT 0x5//101 +#define FPGA_HF_SIMULATOR_NO_MODULATION (0<<0) +#define FPGA_HF_SIMULATOR_MODULATE_BPSK (1<<0) +#define FPGA_HF_SIMULATOR_MODULATE_212K (2<<0) +#define FPGA_HF_SIMULATOR_MODULATE_424K (4<<0) +#define FPGA_HF_SIMULATOR_MODULATE_424K_8BIT 0x5//101 // Options for ISO14443A -#define FPGA_HF_ISO14443A_SNIFFER (0<<0) -#define FPGA_HF_ISO14443A_TAGSIM_LISTEN (1<<0) -#define FPGA_HF_ISO14443A_TAGSIM_MOD (2<<0) -#define FPGA_HF_ISO14443A_READER_LISTEN (3<<0) -#define FPGA_HF_ISO14443A_READER_MOD (4<<0) +#define FPGA_HF_ISO14443A_SNIFFER (0<<0) +#define FPGA_HF_ISO14443A_TAGSIM_LISTEN (1<<0) +#define FPGA_HF_ISO14443A_TAGSIM_MOD (2<<0) +#define FPGA_HF_ISO14443A_READER_LISTEN (3<<0) +#define FPGA_HF_ISO14443A_READER_MOD (4<<0) #endif diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 1591a062..d27fc1c6 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -751,12 +751,9 @@ void RAMFUNC SnoopIClass(void) //if(!LogTrace(Uart.output,Uart.byteCnt, rsamples, Uart.parityBits,true)) break; //if(!LogTrace(NULL, 0, Uart.endTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, 0, true)) break; - if(tracing) { - uint8_t parity[MAX_PARITY_SIZE]; - GetParity(Uart.output, Uart.byteCnt, parity); - LogTrace(Uart.output,Uart.byteCnt, time_start, time_stop, parity, true); - } - + uint8_t parity[MAX_PARITY_SIZE]; + GetParity(Uart.output, Uart.byteCnt, parity); + LogTrace(Uart.output,Uart.byteCnt, time_start, time_stop, parity, true); /* And ready to receive another command. */ Uart.state = STATE_UNSYNCD; @@ -779,11 +776,9 @@ void RAMFUNC SnoopIClass(void) rsamples = samples - Demod.samples; LED_B_ON(); - if(tracing) { - uint8_t parity[MAX_PARITY_SIZE]; - GetParity(Demod.output, Demod.len, parity); - LogTrace(Demod.output, Demod.len, time_start, time_stop, parity, false); - } + uint8_t parity[MAX_PARITY_SIZE]; + GetParity(Demod.output, Demod.len, parity); + LogTrace(Demod.output, Demod.len, time_start, time_stop, parity, false); // And ready to receive another response. memset(&Demod, 0, sizeof(Demod)); @@ -1322,20 +1317,17 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf) t2r_time = GetCountSspClk(); } - if (tracing) { - uint8_t parity[MAX_PARITY_SIZE]; - GetParity(receivedCmd, len, parity); - LogTrace(receivedCmd,len, (r2t_time-time_0)<< 4, (r2t_time-time_0) << 4, parity, true); - - if (trace_data != NULL) { - GetParity(trace_data, trace_data_size, parity); - LogTrace(trace_data, trace_data_size, (t2r_time-time_0) << 4, (t2r_time-time_0) << 4, parity, false); - } - if(!tracing) { - DbpString("Trace full"); - //break; - } + uint8_t parity[MAX_PARITY_SIZE]; + GetParity(receivedCmd, len, parity); + LogTrace(receivedCmd,len, (r2t_time-time_0)<< 4, (r2t_time-time_0) << 4, parity, true); + if (trace_data != NULL) { + GetParity(trace_data, trace_data_size, parity); + LogTrace(trace_data, trace_data_size, (t2r_time-time_0) << 4, (t2r_time-time_0) << 4, parity, false); + } + if(!get_tracing()) { + DbpString("Trace full"); + //break; } } @@ -1509,11 +1501,9 @@ void ReaderTransmitIClass(uint8_t* frame, int len) LED_A_ON(); // Store reader command in buffer - if (tracing) { - uint8_t par[MAX_PARITY_SIZE]; - GetParity(frame, len, par); - LogTrace(frame, len, rsamples, rsamples, par, true); - } + uint8_t par[MAX_PARITY_SIZE]; + GetParity(frame, len, par); + LogTrace(frame, len, rsamples, rsamples, par, true); } //----------------------------------------------------------------------------- @@ -1569,11 +1559,9 @@ int ReaderReceiveIClass(uint8_t* receivedAnswer) int samples = 0; if (!GetIClassAnswer(receivedAnswer,160,&samples,0)) return false; rsamples += samples; - if (tracing) { - uint8_t parity[MAX_PARITY_SIZE]; - GetParity(receivedAnswer, Demod.len, parity); - LogTrace(receivedAnswer,Demod.len,rsamples,rsamples,parity,false); - } + uint8_t parity[MAX_PARITY_SIZE]; + GetParity(receivedAnswer, Demod.len, parity); + LogTrace(receivedAnswer,Demod.len,rsamples,rsamples,parity,false); if(samples == 0) return false; return Demod.len; } @@ -1715,7 +1703,7 @@ void ReaderIClass(uint8_t arg0) { // if only looking for one card try 2 times if we missed it the first time if (try_once && tryCnt > 2) break; tryCnt++; - if(!tracing) { + if(!get_tracing()) { DbpString("Trace full"); break; } @@ -1828,7 +1816,7 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { WDT_HIT(); - if(!tracing) { + if(!get_tracing()) { DbpString("Trace full"); break; } diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 7bf8f5af..f5fcc91c 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -1220,7 +1220,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) EmSendPrecompiledCmd(p_response); } - if (!tracing) { + if (!get_tracing()) { Dbprintf("Trace Full. Simulation stopped."); break; } @@ -1619,9 +1619,7 @@ void ReaderTransmitBitsPar(uint8_t* frame, uint16_t bits, uint8_t *par, uint32_t LED_A_ON(); // Log reader command in trace buffer - if (tracing) { - LogTrace(frame, nbytes(bits), LastTimeProxToAirStart*16 + DELAY_ARM2AIR_AS_READER, (LastTimeProxToAirStart + LastProxToAirDuration)*16 + DELAY_ARM2AIR_AS_READER, par, true); - } + LogTrace(frame, nbytes(bits), LastTimeProxToAirStart*16 + DELAY_ARM2AIR_AS_READER, (LastTimeProxToAirStart + LastProxToAirDuration)*16 + DELAY_ARM2AIR_AS_READER, par, true); } @@ -1652,9 +1650,7 @@ void ReaderTransmit(uint8_t* frame, uint16_t len, uint32_t *timing) static int ReaderReceiveOffset(uint8_t* receivedAnswer, uint16_t offset, uint8_t *parity) { if (!GetIso14443aAnswerFromTag(receivedAnswer, parity, offset)) return false; - if (tracing) { - LogTrace(receivedAnswer, Demod.len, Demod.startTime*16 - DELAY_AIR2ARM_AS_READER, Demod.endTime*16 - DELAY_AIR2ARM_AS_READER, parity, false); - } + LogTrace(receivedAnswer, Demod.len, Demod.startTime*16 - DELAY_AIR2ARM_AS_READER, Demod.endTime*16 - DELAY_AIR2ARM_AS_READER, parity, false); return Demod.len; } @@ -1662,9 +1658,7 @@ static int ReaderReceiveOffset(uint8_t* receivedAnswer, uint16_t offset, uint8_t int ReaderReceive(uint8_t *receivedAnswer, uint8_t *parity) { if (!GetIso14443aAnswerFromTag(receivedAnswer, parity, 0)) return false; - if (tracing) { - LogTrace(receivedAnswer, Demod.len, Demod.startTime*16 - DELAY_AIR2ARM_AS_READER, Demod.endTime*16 - DELAY_AIR2ARM_AS_READER, parity, false); - } + LogTrace(receivedAnswer, Demod.len, Demod.startTime*16 - DELAY_AIR2ARM_AS_READER, Demod.endTime*16 - DELAY_AIR2ARM_AS_READER, parity, false); return Demod.len; } diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index cb8567fa..76d7a075 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -386,10 +386,7 @@ void SimulateIso14443bTag(void) break; } - if (tracing) { - uint8_t parity[MAX_PARITY_SIZE]; - LogTrace(receivedCmd, len, 0, 0, parity, true); - } + LogTrace(receivedCmd, len, 0, 0, NULL, true); // Good, look at the command now. if ( (len == sizeof(cmd1) && memcmp(receivedCmd, cmd1, len) == 0) @@ -463,10 +460,7 @@ void SimulateIso14443bTag(void) } // trace the response: - if (tracing) { - uint8_t parity[MAX_PARITY_SIZE]; - LogTrace(resp, respLen, 0, 0, parity, false); - } + LogTrace(resp, respLen, 0, 0, NULL, false); } } @@ -763,9 +757,8 @@ static void GetSamplesFor14443bDemod(int n, bool quiet) if (!quiet) Dbprintf("max behindby = %d, samples = %d, gotFrame = %d, Demod.len = %d, Demod.sumI = %d, Demod.sumQ = %d", maxBehindBy, samples, gotFrame, Demod.len, Demod.sumI, Demod.sumQ); //Tracing - if (tracing && Demod.len > 0) { - uint8_t parity[MAX_PARITY_SIZE]; - LogTrace(Demod.output, Demod.len, 0, 0, parity, false); + if (Demod.len > 0) { + LogTrace(Demod.output, Demod.len, 0, 0, NULL, false); } } @@ -858,10 +851,7 @@ static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len) { CodeIso14443bAsReader(cmd, len); TransmitFor14443b(); - if (tracing) { - uint8_t parity[MAX_PARITY_SIZE]; - LogTrace(cmd,len, 0, 0, parity, true); - } + LogTrace(cmd,len, 0, 0, NULL, true); } /* Sends an APDU to the tag @@ -1153,7 +1143,6 @@ void RAMFUNC SnoopIso14443b(void) upTo = dmaBuf; lastRxCounter = ISO14443B_DMA_BUFFER_SIZE; FpgaSetupSscDma((uint8_t*) dmaBuf, ISO14443B_DMA_BUFFER_SIZE); - uint8_t parity[MAX_PARITY_SIZE]; bool TagIsActive = false; bool ReaderIsActive = false; @@ -1198,9 +1187,7 @@ void RAMFUNC SnoopIso14443b(void) if (!TagIsActive) { // no need to try decoding reader data if the tag is sending if(Handle14443bUartBit(ci & 0x01)) { triggered = true; - if(tracing) { - LogTrace(Uart.output, Uart.byteCnt, samples, samples, parity, true); - } + LogTrace(Uart.output, Uart.byteCnt, samples, samples, NULL, true); /* And ready to receive another command. */ UartReset(); /* And also reset the demod code, which might have been */ @@ -1209,9 +1196,7 @@ void RAMFUNC SnoopIso14443b(void) } if(Handle14443bUartBit(cq & 0x01)) { triggered = true; - if(tracing) { - LogTrace(Uart.output, Uart.byteCnt, samples, samples, parity, true); - } + LogTrace(Uart.output, Uart.byteCnt, samples, samples, NULL, true); /* And ready to receive another command. */ UartReset(); /* And also reset the demod code, which might have been */ @@ -1223,13 +1208,8 @@ void RAMFUNC SnoopIso14443b(void) if(!ReaderIsActive && triggered) { // no need to try decoding tag data if the reader is sending or not yet triggered if(Handle14443bSamplesDemod(ci/2, cq/2)) { - //Use samples as a time measurement - if(tracing) - { - uint8_t parity[MAX_PARITY_SIZE]; - LogTrace(Demod.output, Demod.len, samples, samples, parity, false); - } + LogTrace(Demod.output, Demod.len, samples, samples, NULL, false); // And ready to receive another response. DemodReset(); } diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index da2aab69..f6868297 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -47,9 +47,10 @@ // *) add anti-collision support for inventory-commands // *) read security status of a block // *) sniffing and simulation do not support two subcarrier modes. -// *) remove or refactor code under "depricated" +// *) remove or refactor code under "deprecated" // *) document all the functions +#include "iso15693.h" #include "proxmark3.h" #include "util.h" @@ -58,6 +59,7 @@ #include "iso15693tools.h" #include "protocols.h" #include "cmd.h" +#include "BigBuf.h" #define arraylen(x) (sizeof(x)/sizeof((x)[0])) @@ -68,27 +70,20 @@ static int DEBUG = 0; // This section basicly contains transmission and receiving of bits /////////////////////////////////////////////////////////////////////// -#define FrameSOF Iso15693FrameSOF -#define Logic0 Iso15693Logic0 -#define Logic1 Iso15693Logic1 -#define FrameEOF Iso15693FrameEOF - #define Crc(data,datalen) Iso15693Crc(data,datalen) #define AddCrc(data,datalen) Iso15693AddCrc(data,datalen) #define sprintUID(target,uid) Iso15693sprintUID(target,uid) -// approximate amplitude=sqrt(ci^2+cq^2) by amplitude = max(|ci|,|cq|) + 1/2*min(|ci|,|cq|) -#define AMPLITUDE(ci, cq) (MAX(ABS(ci), ABS(cq)) + MIN(ABS(ci), ABS(cq))/2) - // buffers -#define ISO15693_DMA_BUFFER_SIZE 128 -#define ISO15693_MAX_RESPONSE_LENGTH 36 // allows read single block with the maximum block size of 256bits. Read multiple blocks not supported yet -#define ISO15693_MAX_COMMAND_LENGTH 45 // allows write single block with the maximum block size of 256bits. Write multiple blocks not supported yet +#define ISO15693_DMA_BUFFER_SIZE 2048 // must be a power of 2 +#define ISO15693_MAX_RESPONSE_LENGTH 36 // allows read single block with the maximum block size of 256bits. Read multiple blocks not supported yet +#define ISO15693_MAX_COMMAND_LENGTH 45 // allows write single block with the maximum block size of 256bits. Write multiple blocks not supported yet // timing. Delays in SSP_CLK ticks. #define DELAY_READER_TO_ARM 8 #define DELAY_ARM_TO_READER 1 #define DELAY_ISO15693_VCD_TO_VICC 132 // 132/423.75kHz = 311.5us from end of EOF to start of tag response +#define DELAY_ISO15693_VICC_TO_VCD 1017 // 1017/3.39MHz = 300us between end of tag response and next reader command // --------------------------- // Signal Processing @@ -271,11 +266,13 @@ static void CodeIso15693AsTag(uint8_t *cmd, int n) // Transmit the command (to the tag) that was placed in cmd[]. -static void TransmitTo15693Tag(const uint8_t *cmd, int len) +static void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t start_time) { FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_TX); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX); + while (GetCountSspClk() < start_time); + LED_B_ON(); for(int c = 0; c < len; ) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { @@ -302,6 +299,7 @@ static void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t start } while (GetCountSspClk() < (start_time & 0xfffffff8)) ; + AT91C_BASE_SSC->SSC_THR = 0x00; // clear TXRDY LED_C_ON(); @@ -329,7 +327,7 @@ static void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t start //============================================================================= // An ISO 15693 decoder for tag responses (one subcarrier only). -// Uses cross correlation to identify the SOF, each bit, and EOF. +// Uses cross correlation to identify each bit and EOF. // This function is called 8 times per bit (every 2 subcarrier cycles). // Subcarrier frequency fs is 424kHz, 1/fs = 2,36us, // i.e. function is called every 4,72us @@ -341,16 +339,15 @@ static void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t start // false if we are still waiting for some more //============================================================================= -#define SUBCARRIER_DETECT_THRESHOLD 2 -#define SOF_CORRELATOR_LEN (1<<5) +#define NOISE_THRESHOLD 30 // don't try to correlate noise typedef struct DecodeTag { enum { - STATE_TAG_UNSYNCD, - STATE_TAG_AWAIT_SOF_1, - STATE_TAG_AWAIT_SOF_2, + STATE_TAG_SOF_LOW, + STATE_TAG_SOF_HIGH, + STATE_TAG_SOF_HIGH_END, STATE_TAG_RECEIVING_DATA, - STATE_TAG_AWAIT_EOF + STATE_TAG_EOF } state; int bitCount; int posCount; @@ -361,84 +358,68 @@ typedef struct DecodeTag { SOF_PART2 } lastBit; uint16_t shiftReg; + uint16_t max_len; uint8_t *output; int len; int sum1, sum2; - uint8_t SOF_low; - uint8_t SOF_high; - uint8_t SOF_last; - int32_t SOF_corr; - int32_t SOF_corr_prev; - uint8_t SOF_correlator[SOF_CORRELATOR_LEN]; } DecodeTag_t; -static int Handle15693SamplesFromTag(int8_t ci, int8_t cq, DecodeTag_t *DecodeTag) + +static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint16_t amplitude, DecodeTag_t *DecodeTag) { switch(DecodeTag->state) { - case STATE_TAG_UNSYNCD: - // initialize SOF correlator. We are looking for 12 samples low and 12 samples high. - DecodeTag->SOF_low = 0; - DecodeTag->SOF_high = 12; - DecodeTag->SOF_last = 23; - memset(DecodeTag->SOF_correlator, 0x00, DecodeTag->SOF_last + 1); - DecodeTag->SOF_correlator[DecodeTag->SOF_last] = AMPLITUDE(ci,cq); - DecodeTag->SOF_corr = DecodeTag->SOF_correlator[DecodeTag->SOF_last]; - DecodeTag->SOF_corr_prev = DecodeTag->SOF_corr; - // initialize Decoder - DecodeTag->posCount = 0; - DecodeTag->bitCount = 0; - DecodeTag->len = 0; - DecodeTag->state = STATE_TAG_AWAIT_SOF_1; - break; - - case STATE_TAG_AWAIT_SOF_1: - // calculate the correlation in real time. Look at differences only. - DecodeTag->SOF_corr += DecodeTag->SOF_correlator[DecodeTag->SOF_low++]; - DecodeTag->SOF_corr -= 2*DecodeTag->SOF_correlator[DecodeTag->SOF_high++]; - DecodeTag->SOF_last++; - DecodeTag->SOF_low &= (SOF_CORRELATOR_LEN-1); - DecodeTag->SOF_high &= (SOF_CORRELATOR_LEN-1); - DecodeTag->SOF_last &= (SOF_CORRELATOR_LEN-1); - DecodeTag->SOF_correlator[DecodeTag->SOF_last] = AMPLITUDE(ci,cq); - DecodeTag->SOF_corr += DecodeTag->SOF_correlator[DecodeTag->SOF_last]; - - // if correlation increases for 10 consecutive samples, we are close to maximum correlation - if (DecodeTag->SOF_corr > DecodeTag->SOF_corr_prev + SUBCARRIER_DETECT_THRESHOLD) { + case STATE_TAG_SOF_LOW: + // waiting for 12 times low (11 times low is accepted as well) + if (amplitude < NOISE_THRESHOLD) { DecodeTag->posCount++; } else { - DecodeTag->posCount = 0; + if (DecodeTag->posCount > 10) { + DecodeTag->posCount = 1; + DecodeTag->sum1 = 0; + DecodeTag->state = STATE_TAG_SOF_HIGH; + } else { + DecodeTag->posCount = 0; + } } - - if (DecodeTag->posCount == 10) { // correlation increased 10 times - DecodeTag->state = STATE_TAG_AWAIT_SOF_2; + break; + + case STATE_TAG_SOF_HIGH: + // waiting for 10 times high. Take average over the last 8 + if (amplitude > NOISE_THRESHOLD) { + DecodeTag->posCount++; + if (DecodeTag->posCount > 2) { + DecodeTag->sum1 += amplitude; // keep track of average high value + } + if (DecodeTag->posCount == 10) { + DecodeTag->sum1 >>= 4; // calculate half of average high value (8 samples) + DecodeTag->state = STATE_TAG_SOF_HIGH_END; + } + } else { // high phase was too short + DecodeTag->posCount = 1; + DecodeTag->state = STATE_TAG_SOF_LOW; } - - DecodeTag->SOF_corr_prev = DecodeTag->SOF_corr; - break; - case STATE_TAG_AWAIT_SOF_2: - // calculate the correlation in real time. Look at differences only. - DecodeTag->SOF_corr += DecodeTag->SOF_correlator[DecodeTag->SOF_low++]; - DecodeTag->SOF_corr -= 2*DecodeTag->SOF_correlator[DecodeTag->SOF_high++]; - DecodeTag->SOF_last++; - DecodeTag->SOF_low &= (SOF_CORRELATOR_LEN-1); - DecodeTag->SOF_high &= (SOF_CORRELATOR_LEN-1); - DecodeTag->SOF_last &= (SOF_CORRELATOR_LEN-1); - DecodeTag->SOF_correlator[DecodeTag->SOF_last] = AMPLITUDE(ci,cq); - DecodeTag->SOF_corr += DecodeTag->SOF_correlator[DecodeTag->SOF_last]; - - if (DecodeTag->SOF_corr >= DecodeTag->SOF_corr_prev) { // we are looking for the maximum correlation - DecodeTag->SOF_corr_prev = DecodeTag->SOF_corr; - } else { - DecodeTag->lastBit = SOF_PART1; // detected 1st part of SOF - DecodeTag->sum1 = DecodeTag->SOF_correlator[DecodeTag->SOF_last]; + case STATE_TAG_SOF_HIGH_END: + // waiting for a falling edge + if (amplitude < DecodeTag->sum1) { // signal drops below 50% average high: a falling edge + DecodeTag->lastBit = SOF_PART1; // detected 1st part of SOF (12 samples low and 12 samples high) + DecodeTag->shiftReg = 0; + DecodeTag->bitCount = 0; + DecodeTag->len = 0; + DecodeTag->sum1 = amplitude; DecodeTag->sum2 = 0; DecodeTag->posCount = 2; DecodeTag->state = STATE_TAG_RECEIVING_DATA; LED_C_ON(); + } else { + DecodeTag->posCount++; + if (DecodeTag->posCount > 13) { // high phase too long + DecodeTag->posCount = 0; + DecodeTag->state = STATE_TAG_SOF_LOW; + LED_C_OFF(); + } } - break; case STATE_TAG_RECEIVING_DATA: @@ -446,23 +427,27 @@ static int Handle15693SamplesFromTag(int8_t ci, int8_t cq, DecodeTag_t *DecodeTa DecodeTag->sum1 = 0; DecodeTag->sum2 = 0; } - if (DecodeTag->posCount <= 4) { - DecodeTag->sum1 += AMPLITUDE(ci, cq); + DecodeTag->sum1 += amplitude; } else { - DecodeTag->sum2 += AMPLITUDE(ci, cq); + DecodeTag->sum2 += amplitude; } - if (DecodeTag->posCount == 8) { - int16_t corr_1 = (DecodeTag->sum2 - DecodeTag->sum1) / 4; - int16_t corr_0 = (DecodeTag->sum1 - DecodeTag->sum2) / 4; - int16_t corr_EOF = (DecodeTag->sum1 + DecodeTag->sum2) / 8; + int32_t corr_1 = DecodeTag->sum2 - DecodeTag->sum1; + int32_t corr_0 = -corr_1; + int32_t corr_EOF = (DecodeTag->sum1 + DecodeTag->sum2) / 2; if (corr_EOF > corr_0 && corr_EOF > corr_1) { - DecodeTag->state = STATE_TAG_AWAIT_EOF; + if (DecodeTag->lastBit == LOGIC0) { // this was already part of EOF + DecodeTag->state = STATE_TAG_EOF; + } else { + DecodeTag->posCount = 0; + DecodeTag->state = STATE_TAG_SOF_LOW; + LED_C_OFF(); + } } else if (corr_1 > corr_0) { // logic 1 if (DecodeTag->lastBit == SOF_PART1) { // still part of SOF - DecodeTag->lastBit = SOF_PART2; + DecodeTag->lastBit = SOF_PART2; // SOF completed } else { DecodeTag->lastBit = LOGIC1; DecodeTag->shiftReg >>= 1; @@ -471,6 +456,12 @@ static int Handle15693SamplesFromTag(int8_t ci, int8_t cq, DecodeTag_t *DecodeTa if (DecodeTag->bitCount == 8) { DecodeTag->output[DecodeTag->len] = DecodeTag->shiftReg; DecodeTag->len++; + if (DecodeTag->len > DecodeTag->max_len) { + // buffer overflow, give up + DecodeTag->posCount = 0; + DecodeTag->state = STATE_TAG_SOF_LOW; + LED_C_OFF(); + } DecodeTag->bitCount = 0; DecodeTag->shiftReg = 0; } @@ -478,7 +469,8 @@ static int Handle15693SamplesFromTag(int8_t ci, int8_t cq, DecodeTag_t *DecodeTa } else { // logic 0 if (DecodeTag->lastBit == SOF_PART1) { // incomplete SOF - DecodeTag->state = STATE_TAG_UNSYNCD; + DecodeTag->posCount = 0; + DecodeTag->state = STATE_TAG_SOF_LOW; LED_C_OFF(); } else { DecodeTag->lastBit = LOGIC0; @@ -487,6 +479,12 @@ static int Handle15693SamplesFromTag(int8_t ci, int8_t cq, DecodeTag_t *DecodeTa if (DecodeTag->bitCount == 8) { DecodeTag->output[DecodeTag->len] = DecodeTag->shiftReg; DecodeTag->len++; + if (DecodeTag->len > DecodeTag->max_len) { + // buffer overflow, give up + DecodeTag->posCount = 0; + DecodeTag->state = STATE_TAG_SOF_LOW; + LED_C_OFF(); + } DecodeTag->bitCount = 0; DecodeTag->shiftReg = 0; } @@ -497,89 +495,106 @@ static int Handle15693SamplesFromTag(int8_t ci, int8_t cq, DecodeTag_t *DecodeTa DecodeTag->posCount++; break; - case STATE_TAG_AWAIT_EOF: - if (DecodeTag->lastBit == LOGIC0) { // this was already part of EOF - LED_C_OFF(); - return true; - } else { - DecodeTag->state = STATE_TAG_UNSYNCD; - LED_C_OFF(); + case STATE_TAG_EOF: + if (DecodeTag->posCount == 1) { + DecodeTag->sum1 = 0; + DecodeTag->sum2 = 0; } + if (DecodeTag->posCount <= 4) { + DecodeTag->sum1 += amplitude; + } else { + DecodeTag->sum2 += amplitude; + } + if (DecodeTag->posCount == 8) { + int32_t corr_1 = DecodeTag->sum2 - DecodeTag->sum1; + int32_t corr_0 = -corr_1; + int32_t corr_EOF = (DecodeTag->sum1 + DecodeTag->sum2) / 2; + if (corr_EOF > corr_0 || corr_1 > corr_0) { + DecodeTag->posCount = 0; + DecodeTag->state = STATE_TAG_SOF_LOW; + LED_C_OFF(); + } else { + LED_C_OFF(); + return true; + } + } + DecodeTag->posCount++; break; - default: - DecodeTag->state = STATE_TAG_UNSYNCD; - LED_C_OFF(); - break; } return false; } -static void DecodeTagInit(DecodeTag_t *DecodeTag, uint8_t *data) +static void DecodeTagInit(DecodeTag_t *DecodeTag, uint8_t *data, uint16_t max_len) { + DecodeTag->posCount = 0; + DecodeTag->state = STATE_TAG_SOF_LOW; DecodeTag->output = data; - DecodeTag->state = STATE_TAG_UNSYNCD; + DecodeTag->max_len = max_len; } + +static void DecodeTagReset(DecodeTag_t *DecodeTag) +{ + DecodeTag->posCount = 0; + DecodeTag->state = STATE_TAG_SOF_LOW; +} + + /* * Receive and decode the tag response, also log to tracebuffer */ -static int GetIso15693AnswerFromTag(uint8_t* response, int timeout) +static int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, int timeout) { - int maxBehindBy = 0; - int lastRxCounter, samples = 0; - int8_t ci, cq; + int samples = 0; bool gotFrame = false; - uint16_t dmaBuf[ISO15693_DMA_BUFFER_SIZE]; - + uint16_t *dmaBuf = (uint16_t*)BigBuf_malloc(ISO15693_DMA_BUFFER_SIZE*sizeof(uint16_t)); + // the Decoder data structure - DecodeTag_t DecodeTag; - DecodeTagInit(&DecodeTag, response); + DecodeTag_t DecodeTag = { 0 }; + DecodeTagInit(&DecodeTag, response, max_len); // wait for last transfer to complete while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)); // And put the FPGA in the appropriate mode - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_AMPLITUDE); // Setup and start DMA. FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); FpgaSetupSscDma((uint8_t*) dmaBuf, ISO15693_DMA_BUFFER_SIZE); uint16_t *upTo = dmaBuf; - lastRxCounter = ISO15693_DMA_BUFFER_SIZE; for(;;) { - int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & (ISO15693_DMA_BUFFER_SIZE-1); - if(behindBy > maxBehindBy) { - maxBehindBy = behindBy; - } + uint16_t behindBy = ((uint16_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (ISO15693_DMA_BUFFER_SIZE-1); - if (behindBy < 1) continue; + if (behindBy == 0) continue; - ci = (int8_t)(*upTo >> 8); - cq = (int8_t)(*upTo & 0xff); + uint16_t tagdata = *upTo++; - upTo++; - lastRxCounter--; if(upTo >= dmaBuf + ISO15693_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. upTo = dmaBuf; // start reading the circular buffer from the beginning - lastRxCounter += ISO15693_DMA_BUFFER_SIZE; + if(behindBy > (9*ISO15693_DMA_BUFFER_SIZE/10)) { + Dbprintf("About to blow circular buffer - aborted! behindBy=%d", behindBy); + break; + } } if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and AT91C_BASE_PDC_SSC->PDC_RNCR = ISO15693_DMA_BUFFER_SIZE; // DMA Next Counter registers } + samples++; - if (Handle15693SamplesFromTag(ci, cq, &DecodeTag)) { + if (Handle15693SamplesFromTag(tagdata, &DecodeTag)) { gotFrame = true; break; } - if(samples > timeout && DecodeTag.state < STATE_TAG_RECEIVING_DATA) { + if (samples > timeout && DecodeTag.state < STATE_TAG_RECEIVING_DATA) { DecodeTag.len = 0; break; } @@ -587,11 +602,12 @@ static int GetIso15693AnswerFromTag(uint8_t* response, int timeout) } FpgaDisableSscDma(); + BigBuf_free(); + + if (DEBUG) Dbprintf("samples = %d, gotFrame = %d, Decoder: state = %d, len = %d, bitCount = %d, posCount = %d", + samples, gotFrame, DecodeTag.state, DecodeTag.len, DecodeTag.bitCount, DecodeTag.posCount); - if (DEBUG) Dbprintf("max behindby = %d, samples = %d, gotFrame = %d, Decoder: state = %d, len = %d, bitCount = %d, posCount = %d", - maxBehindBy, samples, gotFrame, DecodeTag.state, DecodeTag.len, DecodeTag.bitCount, DecodeTag.posCount); - - if (tracing && DecodeTag.len > 0) { + if (DecodeTag.len > 0) { LogTrace(DecodeTag.output, DecodeTag.len, 0, 0, NULL, false); } @@ -636,14 +652,32 @@ typedef struct DecodeReader { } DecodeReader_t; -static int Handle15693SampleFromReader(uint8_t bit, DecodeReader_t* DecodeReader) +static void DecodeReaderInit(DecodeReader_t* DecodeReader, uint8_t *data, uint16_t max_len) +{ + DecodeReader->output = data; + DecodeReader->byteCountMax = max_len; + DecodeReader->state = STATE_READER_UNSYNCD; + DecodeReader->byteCount = 0; + DecodeReader->bitCount = 0; + DecodeReader->posCount = 1; + DecodeReader->shiftReg = 0; +} + + +static void DecodeReaderReset(DecodeReader_t* DecodeReader) +{ + DecodeReader->state = STATE_READER_UNSYNCD; +} + + +static int inline __attribute__((always_inline)) Handle15693SampleFromReader(uint8_t bit, DecodeReader_t *restrict DecodeReader) { switch(DecodeReader->state) { case STATE_READER_UNSYNCD: if(!bit) { // we went low, so this could be the beginning of a SOF - DecodeReader->state = STATE_READER_AWAIT_1ST_RISING_EDGE_OF_SOF; DecodeReader->posCount = 1; + DecodeReader->state = STATE_READER_AWAIT_1ST_RISING_EDGE_OF_SOF; } break; @@ -651,13 +685,13 @@ static int Handle15693SampleFromReader(uint8_t bit, DecodeReader_t* DecodeReader DecodeReader->posCount++; if(bit) { // detected rising edge if(DecodeReader->posCount < 4) { // rising edge too early (nominally expected at 5) - DecodeReader->state = STATE_READER_UNSYNCD; + DecodeReaderReset(DecodeReader); } else { // SOF DecodeReader->state = STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF; } } else { if(DecodeReader->posCount > 5) { // stayed low for too long - DecodeReader->state = STATE_READER_UNSYNCD; + DecodeReaderReset(DecodeReader); } else { // do nothing, keep waiting } @@ -668,19 +702,19 @@ static int Handle15693SampleFromReader(uint8_t bit, DecodeReader_t* DecodeReader DecodeReader->posCount++; if(!bit) { // detected a falling edge if (DecodeReader->posCount < 20) { // falling edge too early (nominally expected at 21 earliest) - DecodeReader->state = STATE_READER_UNSYNCD; + DecodeReaderReset(DecodeReader); } else if (DecodeReader->posCount < 23) { // SOF for 1 out of 4 coding DecodeReader->Coding = CODING_1_OUT_OF_4; DecodeReader->state = STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF; } else if (DecodeReader->posCount < 28) { // falling edge too early (nominally expected at 29 latest) - DecodeReader->state = STATE_READER_UNSYNCD; + DecodeReaderReset(DecodeReader); } else { // SOF for 1 out of 4 coding DecodeReader->Coding = CODING_1_OUT_OF_256; DecodeReader->state = STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF; } } else { if(DecodeReader->posCount > 29) { // stayed high for too long - DecodeReader->state = STATE_READER_UNSYNCD; + DecodeReaderReset(DecodeReader); } else { // do nothing, keep waiting } @@ -692,7 +726,7 @@ static int Handle15693SampleFromReader(uint8_t bit, DecodeReader_t* DecodeReader if (bit) { // detected rising edge if (DecodeReader->Coding == CODING_1_OUT_OF_256) { if (DecodeReader->posCount < 32) { // rising edge too early (nominally expected at 33) - DecodeReader->state = STATE_READER_UNSYNCD; + DecodeReaderReset(DecodeReader); } else { DecodeReader->posCount = 1; DecodeReader->bitCount = 0; @@ -703,7 +737,7 @@ static int Handle15693SampleFromReader(uint8_t bit, DecodeReader_t* DecodeReader } } else { // CODING_1_OUT_OF_4 if (DecodeReader->posCount < 24) { // rising edge too early (nominally expected at 25) - DecodeReader->state = STATE_READER_UNSYNCD; + DecodeReaderReset(DecodeReader); } else { DecodeReader->state = STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4; } @@ -711,13 +745,13 @@ static int Handle15693SampleFromReader(uint8_t bit, DecodeReader_t* DecodeReader } else { if (DecodeReader->Coding == CODING_1_OUT_OF_256) { if (DecodeReader->posCount > 34) { // signal stayed low for too long - DecodeReader->state = STATE_READER_UNSYNCD; + DecodeReaderReset(DecodeReader); } else { // do nothing, keep waiting } } else { // CODING_1_OUT_OF_4 if (DecodeReader->posCount > 26) { // signal stayed low for too long - DecodeReader->state = STATE_READER_UNSYNCD; + DecodeReaderReset(DecodeReader); } else { // do nothing, keep waiting } @@ -739,7 +773,7 @@ static int Handle15693SampleFromReader(uint8_t bit, DecodeReader_t* DecodeReader // do nothing, keep waiting } } else { // unexpected falling edge - DecodeReader->state = STATE_READER_UNSYNCD; + DecodeReaderReset(DecodeReader); } break; @@ -761,7 +795,7 @@ static int Handle15693SampleFromReader(uint8_t bit, DecodeReader_t* DecodeReader int corr11 = (DecodeReader->sum1 + DecodeReader->sum2) / 2; if (corr01 > corr11 && corr01 > corr10) { // EOF LED_B_OFF(); // Finished receiving - DecodeReader->state = STATE_READER_UNSYNCD; + DecodeReaderReset(DecodeReader); if (DecodeReader->byteCount != 0) { return true; } @@ -775,9 +809,10 @@ static int Handle15693SampleFromReader(uint8_t bit, DecodeReader_t* DecodeReader if (DecodeReader->byteCount > DecodeReader->byteCountMax) { // buffer overflow, give up LED_B_OFF(); - DecodeReader->state = STATE_READER_UNSYNCD; + DecodeReaderReset(DecodeReader); } DecodeReader->bitCount = 0; + DecodeReader->shiftReg = 0; } else { DecodeReader->bitCount++; } @@ -802,7 +837,7 @@ static int Handle15693SampleFromReader(uint8_t bit, DecodeReader_t* DecodeReader int corr11 = (DecodeReader->sum1 + DecodeReader->sum2) / 2; if (corr01 > corr11 && corr01 > corr10) { // EOF LED_B_OFF(); // Finished receiving - DecodeReader->state = STATE_READER_UNSYNCD; + DecodeReaderReset(DecodeReader); if (DecodeReader->byteCount != 0) { return true; } @@ -815,7 +850,7 @@ static int Handle15693SampleFromReader(uint8_t bit, DecodeReader_t* DecodeReader if (DecodeReader->byteCount > DecodeReader->byteCountMax) { // buffer overflow, give up LED_B_OFF(); - DecodeReader->state = STATE_READER_UNSYNCD; + DecodeReaderReset(DecodeReader); } } DecodeReader->bitCount++; @@ -824,7 +859,7 @@ static int Handle15693SampleFromReader(uint8_t bit, DecodeReader_t* DecodeReader default: LED_B_OFF(); - DecodeReader->state = STATE_READER_UNSYNCD; + DecodeReaderReset(DecodeReader); break; } @@ -832,18 +867,6 @@ static int Handle15693SampleFromReader(uint8_t bit, DecodeReader_t* DecodeReader } -static void DecodeReaderInit(uint8_t *data, uint16_t max_len, DecodeReader_t* DecodeReader) -{ - DecodeReader->output = data; - DecodeReader->byteCountMax = max_len; - DecodeReader->state = STATE_READER_UNSYNCD; - DecodeReader->byteCount = 0; - DecodeReader->bitCount = 0; - DecodeReader->posCount = 0; - DecodeReader->shiftReg = 0; -} - - //----------------------------------------------------------------------------- // Receive a command (from the reader to us, where we are the simulated tag), // and store it in the given buffer, up to the given maximum length. Keeps @@ -856,16 +879,15 @@ static void DecodeReaderInit(uint8_t *data, uint16_t max_len, DecodeReader_t* De static int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eof_time) { - int maxBehindBy = 0; - int lastRxCounter, samples = 0; + int samples = 0; bool gotFrame = false; uint8_t b; - uint8_t dmaBuf[ISO15693_DMA_BUFFER_SIZE]; + uint8_t *dmaBuf = BigBuf_malloc(ISO15693_DMA_BUFFER_SIZE); // the decoder data structure DecodeReader_t DecodeReader = {0}; - DecodeReaderInit(received, max_len, &DecodeReader); + DecodeReaderInit(&DecodeReader, received, max_len); // wait for last transfer to complete while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)); @@ -883,21 +905,19 @@ static int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint3 // Setup and start DMA. FpgaSetupSscDma(dmaBuf, ISO15693_DMA_BUFFER_SIZE); uint8_t *upTo = dmaBuf; - lastRxCounter = ISO15693_DMA_BUFFER_SIZE; for(;;) { - int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & (ISO15693_DMA_BUFFER_SIZE-1); - if(behindBy > maxBehindBy) { - maxBehindBy = behindBy; - } + uint16_t behindBy = ((uint8_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (ISO15693_DMA_BUFFER_SIZE-1); - if (behindBy < 1) continue; + if (behindBy == 0) continue; b = *upTo++; - lastRxCounter--; if(upTo >= dmaBuf + ISO15693_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. upTo = dmaBuf; // start reading the circular buffer from the beginning - lastRxCounter += ISO15693_DMA_BUFFER_SIZE; + if(behindBy > (9*ISO15693_DMA_BUFFER_SIZE/10)) { + Dbprintf("About to blow circular buffer - aborted! behindBy=%d", behindBy); + break; + } } if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and @@ -927,11 +947,12 @@ static int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint3 FpgaDisableSscDma(); + BigBuf_free_keep_EM(); + + if (DEBUG) Dbprintf("samples = %d, gotFrame = %d, Decoder: state = %d, len = %d, bitCount = %d, posCount = %d", + samples, gotFrame, DecodeReader.state, DecodeReader.byteCount, DecodeReader.bitCount, DecodeReader.posCount); - if (DEBUG) Dbprintf("max behindby = %d, samples = %d, gotFrame = %d, Decoder: state = %d, len = %d, bitCount = %d, posCount = %d", - maxBehindBy, samples, gotFrame, DecodeReader.state, DecodeReader.byteCount, DecodeReader.bitCount, DecodeReader.posCount); - - if (tracing && DecodeReader.byteCount > 0) { + if (DecodeReader.byteCount > 0) { LogTrace(DecodeReader.output, DecodeReader.byteCount, 0, 0, NULL, true); } @@ -939,7 +960,29 @@ static int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint3 } -static void BuildIdentifyRequest(void); +// Encode (into the ToSend buffers) an identify request, which is the first +// thing that you must send to a tag to get a response. +static void BuildIdentifyRequest(void) +{ + uint8_t cmd[5]; + + uint16_t crc; + // one sub-carrier, inventory, 1 slot, fast rate + // AFI is at bit 5 (1<<4) when doing an INVENTORY + cmd[0] = (1 << 2) | (1 << 5) | (1 << 1); + // inventory command code + cmd[1] = 0x01; + // no mask + cmd[2] = 0x00; + //Now the CRC + crc = Crc(cmd, 3); + cmd[3] = crc & 0xff; + cmd[4] = crc >> 8; + + CodeIso15693AsReader(cmd, sizeof(cmd)); +} + + //----------------------------------------------------------------------------- // Start to read an ISO 15693 tag. We send an identify request, then wait // for the response. The response is not demodulated, just left in the buffer @@ -980,18 +1023,12 @@ void AcquireRawAdcSamplesIso15693(void) while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_AMPLITUDE); for(int c = 0; c < 4000; ) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - uint16_t iq = AT91C_BASE_SSC->SSC_RHR; - // The samples are correlations against I and Q versions of the - // tone that the tag AM-modulates. We just want power, - // so abs(I) + abs(Q) is close to what we want. - int8_t i = (int8_t)(iq >> 8); - int8_t q = (int8_t)(iq & 0xff); - uint8_t r = AMPLITUDE(i, q); - dest[c++] = r; + uint16_t r = AT91C_BASE_SSC->SSC_RHR; + dest[c++] = r >> 5; } } @@ -1000,49 +1037,139 @@ void AcquireRawAdcSamplesIso15693(void) } -// TODO: there is no trigger condition. The 14000 samples represent a time frame of 66ms. -// It is unlikely that we get something meaningful. -// TODO: Currently we only record tag answers. Add tracing of reader commands. -// TODO: would we get something at all? The carrier is switched on... -void RecordRawAdcSamplesIso15693(void) +void SnoopIso15693(void) { - LEDsoff(); - LED_A_ON(); - - uint8_t *dest = BigBuf_get_addr(); - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - // Setup SSC - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + BigBuf_free(); - // Start from off (no field generated) - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(200); + clear_trace(); + set_tracing(true); + + // The DMA buffer, used to stream samples from the FPGA + uint16_t* dmaBuf = (uint16_t*)BigBuf_malloc(ISO15693_DMA_BUFFER_SIZE*sizeof(uint16_t)); + uint16_t *upTo; + + // Count of samples received so far, so that we can include timing + // information in the trace buffer. + int samples = 0; + + DecodeTag_t DecodeTag = {0}; + uint8_t response[ISO15693_MAX_RESPONSE_LENGTH]; + DecodeTagInit(&DecodeTag, response, sizeof(response)); + + DecodeReader_t DecodeReader = {0};; + uint8_t cmd[ISO15693_MAX_COMMAND_LENGTH]; + DecodeReaderInit(&DecodeReader, cmd, sizeof(cmd)); + + // Print some debug information about the buffer sizes + if (DEBUG) { + Dbprintf("Snooping buffers initialized:"); + Dbprintf(" Trace: %i bytes", BigBuf_max_traceLen()); + Dbprintf(" Reader -> tag: %i bytes", ISO15693_MAX_COMMAND_LENGTH); + Dbprintf(" tag -> Reader: %i bytes", ISO15693_MAX_RESPONSE_LENGTH); + Dbprintf(" DMA: %i bytes", ISO15693_DMA_BUFFER_SIZE * sizeof(uint16_t)); + } + Dbprintf("Snoop started. Press button to stop."); + + // Signal field is off, no reader signal, no tag signal + LEDsoff(); + // And put the FPGA in the appropriate mode + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_SNOOP | FPGA_HF_READER_RX_XCORR_AMPLITUDE); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - SpinDelay(100); + // Setup for the DMA. + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + upTo = dmaBuf; + FpgaSetupSscDma((uint8_t*) dmaBuf, ISO15693_DMA_BUFFER_SIZE); - LED_D_ON(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + bool TagIsActive = false; + bool ReaderIsActive = false; + bool ExpectTagAnswer = false; - for(int c = 0; c < 14000;) { - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - uint16_t iq = AT91C_BASE_SSC->SSC_RHR; - // The samples are correlations against I and Q versions of the - // tone that the tag AM-modulates. We just want power, - // so abs(I) + abs(Q) is close to what we want. - int8_t i = (int8_t)(iq >> 8); - int8_t q = (int8_t)(iq & 0xff); - uint8_t r = AMPLITUDE(i, q); - dest[c++] = r; + // And now we loop, receiving samples. + for(;;) { + uint16_t behindBy = ((uint16_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (ISO15693_DMA_BUFFER_SIZE-1); + + if (behindBy == 0) continue; + + uint16_t snoopdata = *upTo++; + + if(upTo >= dmaBuf + ISO15693_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. + upTo = dmaBuf; // start reading the circular buffer from the beginning + if(behindBy > (9*ISO15693_DMA_BUFFER_SIZE/10)) { + Dbprintf("About to blow circular buffer - aborted! behindBy=%d, samples=%d", behindBy, samples); + break; + } + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and + AT91C_BASE_PDC_SSC->PDC_RNCR = ISO15693_DMA_BUFFER_SIZE; // DMA Next Counter registers + WDT_HIT(); + if(BUTTON_PRESS()) { + DbpString("Snoop stopped."); + break; + } + } } + samples++; + + if (!TagIsActive) { // no need to try decoding reader data if the tag is sending + if (Handle15693SampleFromReader(snoopdata & 0x02, &DecodeReader)) { + FpgaDisableSscDma(); + ExpectTagAnswer = true; + LogTrace(DecodeReader.output, DecodeReader.byteCount, samples, samples, NULL, true); + /* And ready to receive another command. */ + DecodeReaderReset(&DecodeReader); + /* And also reset the demod code, which might have been */ + /* false-triggered by the commands from the reader. */ + DecodeTagReset(&DecodeTag); + upTo = dmaBuf; + FpgaSetupSscDma((uint8_t*) dmaBuf, ISO15693_DMA_BUFFER_SIZE); + } + if (Handle15693SampleFromReader(snoopdata & 0x01, &DecodeReader)) { + FpgaDisableSscDma(); + ExpectTagAnswer = true; + LogTrace(DecodeReader.output, DecodeReader.byteCount, samples, samples, NULL, true); + /* And ready to receive another command. */ + DecodeReaderReset(&DecodeReader); + /* And also reset the demod code, which might have been */ + /* false-triggered by the commands from the reader. */ + DecodeTagReset(&DecodeTag); + upTo = dmaBuf; + FpgaSetupSscDma((uint8_t*) dmaBuf, ISO15693_DMA_BUFFER_SIZE); + } + ReaderIsActive = (DecodeReader.state >= STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF); + } + + if (!ReaderIsActive && ExpectTagAnswer) { // no need to try decoding tag data if the reader is currently sending or no answer expected yet + if (Handle15693SamplesFromTag(snoopdata >> 2, &DecodeTag)) { + FpgaDisableSscDma(); + //Use samples as a time measurement + LogTrace(DecodeTag.output, DecodeTag.len, samples, samples, NULL, false); + // And ready to receive another response. + DecodeTagReset(&DecodeTag); + DecodeReaderReset(&DecodeReader); + ExpectTagAnswer = false; + upTo = dmaBuf; + FpgaSetupSscDma((uint8_t*) dmaBuf, ISO15693_DMA_BUFFER_SIZE); + } + TagIsActive = (DecodeTag.state >= STATE_TAG_RECEIVING_DATA); + } + } - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_D_OFF(); - Dbprintf("finished recording"); - LED_A_OFF(); + FpgaDisableSscDma(); + BigBuf_free(); + + LEDsoff(); + + DbpString("Snoop statistics:"); + Dbprintf(" ExpectTagAnswer: %d", ExpectTagAnswer); + Dbprintf(" DecodeTag State: %d", DecodeTag.state); + Dbprintf(" DecodeTag byteCnt: %d", DecodeTag.len); + Dbprintf(" DecodeReader State: %d", DecodeReader.state); + Dbprintf(" DecodeReader byteCnt: %d", DecodeReader.byteCount); + Dbprintf(" Trace length: %d", BigBuf_get_traceLen()); } @@ -1072,27 +1199,6 @@ static void Iso15693InitReader() { // This section basically contains transmission and receiving of bits /////////////////////////////////////////////////////////////////////// -// Encode (into the ToSend buffers) an identify request, which is the first -// thing that you must send to a tag to get a response. -static void BuildIdentifyRequest(void) -{ - uint8_t cmd[5]; - - uint16_t crc; - // one sub-carrier, inventory, 1 slot, fast rate - // AFI is at bit 5 (1<<4) when doing an INVENTORY - cmd[0] = (1 << 2) | (1 << 5) | (1 << 1); - // inventory command code - cmd[1] = 0x01; - // no mask - cmd[2] = 0x00; - //Now the CRC - crc = Crc(cmd, 3); - cmd[3] = crc & 0xff; - cmd[4] = crc >> 8; - - CodeIso15693AsReader(cmd, sizeof(cmd)); -} // uid is in transmission order (which is reverse of display order) static void BuildReadBlockRequest(uint8_t *uid, uint8_t blockNumber ) @@ -1100,12 +1206,11 @@ static void BuildReadBlockRequest(uint8_t *uid, uint8_t blockNumber ) uint8_t cmd[13]; uint16_t crc; - // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block - // followed by teh block data - // one sub-carrier, inventory, 1 slot, fast rate - cmd[0] = (1 << 6)| (1 << 5) | (1 << 1); // no SELECT bit, ADDR bit, OPTION bit + // If we set the Option_Flag in this request, the VICC will respond with the security status of the block + // followed by the block data + cmd[0] = ISO15693_REQ_OPTION | ISO15693_REQ_ADDRESS | ISO15693_REQ_DATARATE_HIGH; // READ BLOCK command code - cmd[1] = 0x20; + cmd[1] = ISO15693_READBLOCK; // UID may be optionally specified here // 64-bit UID cmd[2] = uid[0]; @@ -1117,7 +1222,7 @@ static void BuildReadBlockRequest(uint8_t *uid, uint8_t blockNumber ) cmd[8] = uid[6]; cmd[9] = uid[7]; // 0xe0; // always e0 (not exactly unique) // Block number to read - cmd[10] = blockNumber;//0x00; + cmd[10] = blockNumber; //Now the CRC crc = Crc(cmd, 11); // the crc needs to be calculated over 11 bytes cmd[11] = crc & 0xff; @@ -1156,10 +1261,9 @@ static void BuildInventoryResponse(uint8_t *uid) // Universal Method for sending to and recv bytes from a tag // init ... should we initialize the reader? // speed ... 0 low speed, 1 hi speed -// **recv will return you a pointer to the received data -// If you do not need the answer use NULL for *recv[] +// *recv will contain the tag's answer // return: lenght of received data -int SendDataTag(uint8_t *send, int sendlen, bool init, int speed, uint8_t **recv) { +int SendDataTag(uint8_t *send, int sendlen, bool init, int speed, uint8_t *recv, uint16_t max_recv_len, uint32_t start_time) { LED_A_ON(); LED_B_OFF(); @@ -1168,8 +1272,6 @@ int SendDataTag(uint8_t *send, int sendlen, bool init, int speed, uint8_t **recv if (init) Iso15693InitReader(); int answerLen=0; - uint8_t *answer = BigBuf_get_addr() + 4000; - if (recv != NULL) memset(answer, 0, 100); if (!speed) { // low speed (1 out of 256) @@ -1179,11 +1281,11 @@ int SendDataTag(uint8_t *send, int sendlen, bool init, int speed, uint8_t **recv CodeIso15693AsReader(send, sendlen); } - TransmitTo15693Tag(ToSend,ToSendMax); + TransmitTo15693Tag(ToSend, ToSendMax, start_time); + // Now wait for a response - if (recv!=NULL) { - answerLen = GetIso15693AnswerFromTag(answer, 100); - *recv=answer; + if (recv != NULL) { + answerLen = GetIso15693AnswerFromTag(recv, max_recv_len, DELAY_ISO15693_VCD_TO_VICC * 2); } LED_A_OFF(); @@ -1202,46 +1304,46 @@ void DbdecodeIso15693Answer(int len, uint8_t *d) { char status[DBD15STATLEN+1]={0}; uint16_t crc; - if (len>3) { - if (d[0]&(1<<3)) - strncat(status,"ProtExt ",DBD15STATLEN); - if (d[0]&1) { + if (len > 3) { + if (d[0] & ISO15693_RES_EXT) + strncat(status,"ProtExt ", DBD15STATLEN); + if (d[0] & ISO15693_RES_ERROR) { // error - strncat(status,"Error ",DBD15STATLEN); + strncat(status,"Error ", DBD15STATLEN); switch (d[1]) { case 0x01: - strncat(status,"01:notSupp",DBD15STATLEN); + strncat(status,"01:notSupp", DBD15STATLEN); break; case 0x02: - strncat(status,"02:notRecog",DBD15STATLEN); + strncat(status,"02:notRecog", DBD15STATLEN); break; case 0x03: - strncat(status,"03:optNotSupp",DBD15STATLEN); + strncat(status,"03:optNotSupp", DBD15STATLEN); break; case 0x0f: - strncat(status,"0f:noInfo",DBD15STATLEN); + strncat(status,"0f:noInfo", DBD15STATLEN); break; case 0x10: - strncat(status,"10:dontExist",DBD15STATLEN); + strncat(status,"10:doesn'tExist", DBD15STATLEN); break; case 0x11: - strncat(status,"11:lockAgain",DBD15STATLEN); + strncat(status,"11:lockAgain", DBD15STATLEN); break; case 0x12: - strncat(status,"12:locked",DBD15STATLEN); + strncat(status,"12:locked", DBD15STATLEN); break; case 0x13: - strncat(status,"13:progErr",DBD15STATLEN); + strncat(status,"13:progErr", DBD15STATLEN); break; case 0x14: - strncat(status,"14:lockErr",DBD15STATLEN); + strncat(status,"14:lockErr", DBD15STATLEN); break; default: - strncat(status,"unknownErr",DBD15STATLEN); + strncat(status,"unknownErr", DBD15STATLEN); } - strncat(status," ",DBD15STATLEN); + strncat(status," ", DBD15STATLEN); } else { - strncat(status,"NoErr ",DBD15STATLEN); + strncat(status,"NoErr ", DBD15STATLEN); } crc=Crc(d,len-2); @@ -1266,6 +1368,7 @@ void SetDebugIso15693(uint32_t debug) { return; } + //----------------------------------------------------------------------------- // Simulate an ISO15693 reader, perform anti-collision and then attempt to read a sector // all demodulation performed in arm rather than host. - greg @@ -1275,13 +1378,14 @@ void ReaderIso15693(uint32_t parameter) LEDsoff(); LED_A_ON(); - int answerLen1 = 0; + set_tracing(true); + + int answerLen = 0; uint8_t TagUID[8] = {0x00}; FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - uint8_t *answer1 = BigBuf_get_addr() + 4000; - memset(answer1, 0x00, 200); + uint8_t answer[ISO15693_MAX_RESPONSE_LENGTH]; SetAdcMuxFor(GPIO_MUXSEL_HIPKD); // Setup SSC @@ -1295,37 +1399,39 @@ void ReaderIso15693(uint32_t parameter) LED_D_ON(); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); SpinDelay(200); + StartCountSspClk(); + // FIRST WE RUN AN INVENTORY TO GET THE TAG UID // THIS MEANS WE CAN PRE-BUILD REQUESTS TO SAVE CPU TIME // Now send the IDENTIFY command BuildIdentifyRequest(); - - TransmitTo15693Tag(ToSend,ToSendMax); + TransmitTo15693Tag(ToSend, ToSendMax, 0); // Now wait for a response - answerLen1 = GetIso15693AnswerFromTag(answer1, 100) ; + answerLen = GetIso15693AnswerFromTag(answer, sizeof(answer), DELAY_ISO15693_VCD_TO_VICC * 2) ; + uint32_t start_time = GetCountSspClk() + DELAY_ISO15693_VICC_TO_VCD; - if (answerLen1 >=12) // we should do a better check than this + if (answerLen >=12) // we should do a better check than this { - TagUID[0] = answer1[2]; - TagUID[1] = answer1[3]; - TagUID[2] = answer1[4]; - TagUID[3] = answer1[5]; - TagUID[4] = answer1[6]; - TagUID[5] = answer1[7]; - TagUID[6] = answer1[8]; // IC Manufacturer code - TagUID[7] = answer1[9]; // always E0 + TagUID[0] = answer[2]; + TagUID[1] = answer[3]; + TagUID[2] = answer[4]; + TagUID[3] = answer[5]; + TagUID[4] = answer[6]; + TagUID[5] = answer[7]; + TagUID[6] = answer[8]; // IC Manufacturer code + TagUID[7] = answer[9]; // always E0 } - Dbprintf("%d octets read from IDENTIFY request:", answerLen1); - DbdecodeIso15693Answer(answerLen1, answer1); - Dbhexdump(answerLen1, answer1, false); + Dbprintf("%d octets read from IDENTIFY request:", answerLen); + DbdecodeIso15693Answer(answerLen, answer); + Dbhexdump(answerLen, answer, false); // UID is reverse - if (answerLen1 >= 12) + if (answerLen >= 12) Dbprintf("UID = %02hX%02hX%02hX%02hX%02hX%02hX%02hX%02hX", TagUID[7],TagUID[6],TagUID[5],TagUID[4], TagUID[3],TagUID[2],TagUID[1],TagUID[0]); @@ -1340,18 +1446,21 @@ void ReaderIso15693(uint32_t parameter) // Dbhexdump(answerLen3,answer3,true); // read all pages - if (answerLen1 >= 12 && DEBUG) { - uint8_t *answer2 = BigBuf_get_addr() + 4100; + if (answerLen >= 12 && DEBUG) { + + // debugptr = BigBuf_get_addr(); + int i = 0; while (i < 32) { // sanity check, assume max 32 pages BuildReadBlockRequest(TagUID, i); - TransmitTo15693Tag(ToSend, ToSendMax); - int answerLen2 = GetIso15693AnswerFromTag(answer2, 100); - if (answerLen2 > 0) { - Dbprintf("READ SINGLE BLOCK %d returned %d octets:", i, answerLen2); - DbdecodeIso15693Answer(answerLen2, answer2); - Dbhexdump(answerLen2, answer2, false); - if ( *((uint32_t*) answer2) == 0x07160101 ) break; // exit on NoPageErr + TransmitTo15693Tag(ToSend, ToSendMax, start_time); + int answerLen = GetIso15693AnswerFromTag(answer, sizeof(answer), DELAY_ISO15693_VCD_TO_VICC * 2); + start_time = GetCountSspClk() + DELAY_ISO15693_VICC_TO_VCD; + if (answerLen > 0) { + Dbprintf("READ SINGLE BLOCK %d returned %d octets:", i, answerLen); + DbdecodeIso15693Answer(answerLen, answer); + Dbhexdump(answerLen, answer, false); + if ( *((uint32_t*) answer) == 0x07160101 ) break; // exit on NoPageErr } i++; } @@ -1412,12 +1521,14 @@ void BruteforceIso15693Afi(uint32_t speed) LEDsoff(); LED_A_ON(); - uint8_t data[20]; - uint8_t *recv=data; + uint8_t data[6]; + uint8_t recv[ISO15693_MAX_RESPONSE_LENGTH]; + int datalen=0, recvlen=0; Iso15693InitReader(); - + StartCountSspClk(); + // first without AFI // Tags should respond without AFI and with AFI=0 even when AFI is active @@ -1425,10 +1536,11 @@ void BruteforceIso15693Afi(uint32_t speed) data[1] = ISO15693_INVENTORY; data[2] = 0; // mask length datalen = AddCrc(data,3); - recvlen = SendDataTag(data, datalen, false, speed, &recv); + recvlen = SendDataTag(data, datalen, false, speed, recv, sizeof(recv), 0); + uint32_t start_time = GetCountSspClk() + DELAY_ISO15693_VCD_TO_VICC; WDT_HIT(); if (recvlen>=12) { - Dbprintf("NoAFI UID=%s",sprintUID(NULL,&recv[2])); + Dbprintf("NoAFI UID=%s", sprintUID(NULL, &recv[2])); } // now with AFI @@ -1438,13 +1550,14 @@ void BruteforceIso15693Afi(uint32_t speed) data[2] = 0; // AFI data[3] = 0; // mask length - for (int i=0;i<256;i++) { - data[2]=i & 0xFF; - datalen=AddCrc(data,4); - recvlen=SendDataTag(data, datalen, false, speed, &recv); + for (int i = 0; i < 256; i++) { + data[2] = i & 0xFF; + datalen = AddCrc(data,4); + recvlen = SendDataTag(data, datalen, false, speed, recv, sizeof(recv), start_time); + start_time = GetCountSspClk() + DELAY_ISO15693_VCD_TO_VICC; WDT_HIT(); - if (recvlen>=12) { - Dbprintf("AFI=%i UID=%s", i, sprintUID(NULL,&recv[2])); + if (recvlen >= 12) { + Dbprintf("AFI=%i UID=%s", i, sprintUID(NULL, &recv[2])); } } Dbprintf("AFI Bruteforcing done."); @@ -1456,26 +1569,27 @@ void BruteforceIso15693Afi(uint32_t speed) // Allows to directly send commands to the tag via the client void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint8_t data[]) { - int recvlen=0; - uint8_t *recvbuf = BigBuf_get_addr(); + int recvlen = 0; + uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; LED_A_ON(); if (DEBUG) { - Dbprintf("SEND"); + Dbprintf("SEND:"); Dbhexdump(datalen, data, false); } - recvlen = SendDataTag(data, datalen, true, speed, (recv?&recvbuf:NULL)); + recvlen = SendDataTag(data, datalen, true, speed, (recv?recvbuf:NULL), sizeof(recvbuf), 0); if (recv) { - cmd_send(CMD_ACK, recvlen>48?48:recvlen, 0, 0, recvbuf, 48); - if (DEBUG) { - Dbprintf("RECV"); - DbdecodeIso15693Answer(recvlen,recvbuf); + Dbprintf("RECV:"); Dbhexdump(recvlen, recvbuf, false); + DbdecodeIso15693Answer(recvlen, recvbuf); } + + cmd_send(CMD_ACK, recvlen>ISO15693_MAX_RESPONSE_LENGTH?ISO15693_MAX_RESPONSE_LENGTH:recvlen, 0, 0, recvbuf, ISO15693_MAX_RESPONSE_LENGTH); + } // for the time being, switch field off to protect rdv4.0 diff --git a/armsrc/iso15693.h b/armsrc/iso15693.h new file mode 100644 index 00000000..e5b78a8a --- /dev/null +++ b/armsrc/iso15693.h @@ -0,0 +1,24 @@ +//----------------------------------------------------------------------------- +// Piwi - October 2018 +// +// 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. +//----------------------------------------------------------------------------- +// Routines to support ISO 15693. +//----------------------------------------------------------------------------- + +#ifndef __ISO15693_H +#define __ISO15693_H + +#include + +void SnoopIso15693(void); +void AcquireRawAdcSamplesIso15693(void); +void ReaderIso15693(uint32_t parameter); +void SimTagIso15693(uint32_t parameter, uint8_t *uid); +void BruteforceIso15693Afi(uint32_t speed); +void DirectTag15693Command(uint32_t datalen,uint32_t speed, uint32_t recv, uint8_t data[]); +void SetDebugIso15693(uint32_t flag); + +#endif diff --git a/client/cmdhf.c b/client/cmdhf.c index 56b1cb3d..744a95d2 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -264,7 +264,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui uint8_t parityBits = parityBytes[j>>3]; if (protocol != ISO_14443B && (isResponse || protocol == ISO_14443A) && (oddparity8(frame[j]) != ((parityBits >> (7-(j&0x0007))) & 0x01))) { - snprintf(line[j/16]+(( j % 16) * 4),110, "%02x! ", frame[j]); + snprintf(line[j/16]+(( j % 16) * 4), 110, " %02x!", frame[j]); } else { snprintf(line[j/16]+(( j % 16) * 4), 110, " %02x ", frame[j]); } @@ -281,14 +281,11 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui } } - if(data_len == 0) - { - if(data_len == 0){ - sprintf(line[0],""); - } + if (data_len == 0) { + sprintf(line[0]," "); } - //--- Draw the CRC column + //--- Draw the CRC column char *crc = (crcStatus == 0 ? "!crc" : (crcStatus == 1 ? " ok " : " ")); EndOfTransmissionTimestamp = timestamp + duration; diff --git a/client/cmdhf15.c b/client/cmdhf15.c index e5f4af31..da83ccaf 100644 --- a/client/cmdhf15.c +++ b/client/cmdhf15.c @@ -38,15 +38,54 @@ #include "protocols.h" #include "cmdmain.h" -#define FrameSOF Iso15693FrameSOF -#define Logic0 Iso15693Logic0 -#define Logic1 Iso15693Logic1 -#define FrameEOF Iso15693FrameEOF - #define Crc(data,datalen) Iso15693Crc(data,datalen) #define AddCrc(data,datalen) Iso15693AddCrc(data,datalen) #define sprintUID(target,uid) Iso15693sprintUID(target,uid) +// SOF defined as +// 1) Unmodulated time of 56.64us +// 2) 24 pulses of 423.75khz +// 3) logic '1' (unmodulated for 18.88us followed by 8 pulses of 423.75khz) + +static const int Iso15693FrameSOF[] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + -1, -1, -1, -1, + -1, -1, -1, -1, + 1, 1, 1, 1, + 1, 1, 1, 1 +}; +static const int Iso15693Logic0[] = { + 1, 1, 1, 1, + 1, 1, 1, 1, + -1, -1, -1, -1, + -1, -1, -1, -1 +}; +static const int Iso15693Logic1[] = { + -1, -1, -1, -1, + -1, -1, -1, -1, + 1, 1, 1, 1, + 1, 1, 1, 1 +}; + +// EOF defined as +// 1) logic '0' (8 pulses of 423.75khz followed by unmodulated for 18.88us) +// 2) 24 pulses of 423.75khz +// 3) Unmodulated time of 56.64us + +static const int Iso15693FrameEOF[] = { + 1, 1, 1, 1, + 1, 1, 1, 1, + -1, -1, -1, -1, + -1, -1, -1, -1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; + // structure and database for uid -> tagtype lookups typedef struct { uint64_t uid; @@ -293,8 +332,8 @@ int CmdHF15Demod(const char *Cmd) // First, correlate for SOF for (i = 0; i < 200; i++) { int corr = 0; - for (j = 0; j < arraylen(FrameSOF); j += skip) { - corr += FrameSOF[j] * GraphBuffer[i + (j / skip)]; + for (j = 0; j < arraylen(Iso15693FrameSOF); j += skip) { + corr += Iso15693FrameSOF[j] * GraphBuffer[i + (j / skip)]; } if (corr > max) { max = corr; @@ -302,28 +341,28 @@ int CmdHF15Demod(const char *Cmd) } } PrintAndLog("SOF at %d, correlation %d", maxPos, - max / (arraylen(FrameSOF) / skip)); + max / (arraylen(Iso15693FrameSOF) / skip)); - i = maxPos + arraylen(FrameSOF) / skip; + i = maxPos + arraylen(Iso15693FrameSOF) / skip; int k = 0; uint8_t outBuf[20]; memset(outBuf, 0, sizeof(outBuf)); uint8_t mask = 0x01; for (;;) { int corr0 = 0, corr00 = 0, corr01 = 0, corr1 = 0, corrEOF = 0; - for(j = 0; j < arraylen(Logic0); j += skip) { - corr0 += Logic0[j]*GraphBuffer[i+(j/skip)]; + for(j = 0; j < arraylen(Iso15693Logic0); j += skip) { + corr0 += Iso15693Logic0[j]*GraphBuffer[i+(j/skip)]; } corr01 = corr00 = corr0; - for(j = 0; j < arraylen(Logic0); j += skip) { - corr00 += Logic0[j]*GraphBuffer[i+arraylen(Logic0)/skip+(j/skip)]; - corr01 += Logic1[j]*GraphBuffer[i+arraylen(Logic0)/skip+(j/skip)]; + for(j = 0; j < arraylen(Iso15693Logic0); j += skip) { + corr00 += Iso15693Logic0[j]*GraphBuffer[i+arraylen(Iso15693Logic0)/skip+(j/skip)]; + corr01 += Iso15693Logic1[j]*GraphBuffer[i+arraylen(Iso15693Logic0)/skip+(j/skip)]; } - for(j = 0; j < arraylen(Logic1); j += skip) { - corr1 += Logic1[j]*GraphBuffer[i+(j/skip)]; + for(j = 0; j < arraylen(Iso15693Logic1); j += skip) { + corr1 += Iso15693Logic1[j]*GraphBuffer[i+(j/skip)]; } - for(j = 0; j < arraylen(FrameEOF); j += skip) { - corrEOF += FrameEOF[j]*GraphBuffer[i+(j/skip)]; + for(j = 0; j < arraylen(Iso15693FrameEOF); j += skip) { + corrEOF += Iso15693FrameEOF[j]*GraphBuffer[i+(j/skip)]; } // Even things out by the length of the target waveform. corr00 *= 2; @@ -335,17 +374,17 @@ int CmdHF15Demod(const char *Cmd) PrintAndLog("EOF at %d", i); break; } else if (corr1 > corr0) { - i += arraylen(Logic1) / skip; + i += arraylen(Iso15693Logic1) / skip; outBuf[k] |= mask; } else { - i += arraylen(Logic0) / skip; + i += arraylen(Iso15693Logic0) / skip; } mask <<= 1; if (mask == 0) { k++; mask = 0x01; } - if ((i + (int)arraylen(FrameEOF)) >= GraphTraceLen) { + if ((i + (int)arraylen(Iso15693FrameEOF)) >= GraphTraceLen) { PrintAndLog("ran off end!"); break; } @@ -374,10 +413,9 @@ int CmdHF15Read(const char *Cmd) } // Record Activity without enabling carrier -// TODO: currently it DOES enable the carrier -int CmdHF15Record(const char *Cmd) +int CmdHF15Snoop(const char *Cmd) { - UsbCommand c = {CMD_RECORD_RAW_ADC_SAMPLES_ISO_15693}; + UsbCommand c = {CMD_SNOOP_ISO_15693}; SendCommand(&c); return 0; } @@ -514,7 +552,7 @@ static command_t CommandTable15[] = {"help", CmdHF15Help, 1, "This help"}, {"demod", CmdHF15Demod, 1, "Demodulate ISO15693 from tag"}, {"read", CmdHF15Read, 0, "Read HF tag (ISO 15693)"}, - {"record", CmdHF15Record, 0, "Record Samples (ISO 15693)"}, // atrox + {"snoop", CmdHF15Snoop, 0, "Eavesdrop ISO 15693 communications"}, {"reader", CmdHF15Reader, 0, "Act like an ISO15693 reader"}, {"sim", CmdHF15Sim, 0, "Fake an ISO15693 tag"}, {"cmd", CmdHF15Cmd, 0, "Send direct commands to ISO15693 tag"}, diff --git a/common/iso15693tools.h b/common/iso15693tools.h index 96095fba..d9f59cc6 100644 --- a/common/iso15693tools.h +++ b/common/iso15693tools.h @@ -14,57 +14,4 @@ int Iso15693AddCrc(uint8_t *req, int n); char* Iso15693sprintUID(char *target,uint8_t *uid); unsigned short iclass_crc16(char *data_p, unsigned short length); -//----------------------------------------------------------------------------- -// Map a sequence of octets (~layer 2 command) into the set of bits to feed -// to the FPGA, to transmit that command to the tag. -// Mode: highspeed && one subcarrier (ASK) -//----------------------------------------------------------------------------- - - // The sampling rate is 106.353 ksps/s, for T = 18.8 us - - // SOF defined as - // 1) Unmodulated time of 56.64us - // 2) 24 pulses of 423.75khz - // 3) logic '1' (unmodulated for 18.88us followed by 8 pulses of 423.75khz) - - static const int Iso15693FrameSOF[] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - -1, -1, -1, -1, - -1, -1, -1, -1, - 1, 1, 1, 1, - 1, 1, 1, 1 - }; - static const int Iso15693Logic0[] = { - 1, 1, 1, 1, - 1, 1, 1, 1, - -1, -1, -1, -1, - -1, -1, -1, -1 - }; - static const int Iso15693Logic1[] = { - -1, -1, -1, -1, - -1, -1, -1, -1, - 1, 1, 1, 1, - 1, 1, 1, 1 - }; - - // EOF defined as - // 1) logic '0' (8 pulses of 423.75khz followed by unmodulated for 18.88us) - // 2) 24 pulses of 423.75khz - // 3) Unmodulated time of 56.64us - - static const int Iso15693FrameEOF[] = { - 1, 1, 1, 1, - 1, 1, 1, 1, - -1, -1, -1, -1, - -1, -1, -1, -1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 - }; - - #endif diff --git a/fpga/fpga_hf.bit b/fpga/fpga_hf.bit index bd296174f0978d3214bae003d25a7063bff60021..f16fd0614fbd2614e713a29da5f47a29094953e5 100644 GIT binary patch literal 42175 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 literal 42175 zcmeIb4RBmnl`gvaoR)Ij-BKUPaz>EE9JQ3tF)gVr2gf){Yg=}LNIYXr2uy~e=5~UI z@lb(L80ucbo5yUm{}Dy*q`99Q_=`LL z%bHKN58Qp{C;ohO$7epVn(m@l*IzHn{?~gJX0!AOig#rfF6qpEpmSjtt)@8(-@kO> zlBL%zravdzK5zk_Z-4D0pUjes5Yc7XNS^;SvJopnvZp;u4*xfKKcAB&JfHdRNR|Zk zQ`;w~(d5U!QIZ$>QYqehC# zhz;R#ib%@S6;$g)NXo!Hk~(Bq+KGsIkJIo7 z?JsU~@SgGhjfYah##Sw3ZX}K0Q;p{NJv8qWopZWY$IJRD?U>jp>$k?YMZZsFCt>Ro zQT3imtKIp>rZ95_k_Cqnu2X^ieuT zT~5;0&8Wp~#%eOOi#i+w<1&Ao?~q1GJ7w%A^l-b@g$;yHrDmnvMRyB>$Fz(Aw@rl|zf7eJ2=7+j4u6T!b zOm<;ht!X-@VO%5n0(ZUo8Xlm>sl_p>S~m?-i!=tbCB}V`7AIcO8r^wz2z@TL+=Z^r zr~72O@_KJ>vtk>24lM0#qp5~gUda|HtrcI4DILG>9 z{MJ+MS{Tu&7&NUFv4&Vw>}aU(PdCMCXi!-FMw50}nGxDkcPBZbY}OC!EmRdbN=Q9L z4(+6j)L+-tx^KPe)xz6$&ziay^f%?(_KkNY@6dluZ_6ImrdMkRRDb4STxM1zw&-mF z1ME+j`qgx#i3h0Hy6d&XJRytrHY>d$meMwj*y(gpTc8yOI~Jsm#_HX%8#T|_>#UYr zjN7y(f*_3Bz6>GK{vqSGg68U1^SohNC-_I)hVsJbhwvq8XQ9?z3p=`9^XB;)I-+&u zHcd9${;Q1poR$e=HC`xqp3_E7ds^n7t%wP)m` zc4Dpm1w7ehXQtu{G;Tu1RU`BQOaUywB$Q~WOqTT#dW)Zw^~0`yiJCXDf{XHX$MrX1 z7-0tQ&==DW2Y20>9Mj2NuaSllJxbT}tUgD(>3z5K^%t6qb!Ll*3vGcr&qQ130JV@I zvbLMu827e_3V+b zkV}kbXb}r(Iu9XQjnfL%W-z*zz6>pm=e1_qOxMf!YM8i#)GA>~EMf9{WDRtXI>fCd ztqn#$CE~Ks2FsrkF{xSZS{P_INEs35tyQEpw24JAK#SXGu6~iR8oMP&NjcZz4GBTF zXbSq(Vd~`Sm;J7)c7}Q=>CCOte<%Tv#82ub^vT)*?vKJRu}Di)^&4qi_EhR8_5Vsg zk&7ycsTurwo%Ri+o;CJp37R82DiE$A#xDpye$|Wv3+^(EY-3`Wv#Dma`xm z#;<*5>M-ykgK+^k?uXG+?e{lH6z%Q&$7{3ZVBiMD* z#LL7^v|vul`e*29pHe*_nwE3$ zPTwqMY~u#)&uCb-+kmZ?=<&h!O7mK+N*4Er@oU$Sj@?GKHeuKka9N_-DDBcRPCASC zs6Eg4^&0ddW9w_^Xr$-wl9PoOEVc>oH{No;OW{{Er(=r(ztH*Q@X*WHt2q--Lih!Z z6N&rd+anNGB>z!oL{oO&$1k|Kd!ajqsjrSe7>NJ9b`si@>CKd|a7w?LYuflnVogcg z9%Uh3s^vELtx^cTXotx38)ob#Y+5Lqi8h1k$qatwu@7@rqNr~h*~2DIUN(uvR6rKs z*Gc$Vodd}&`m3<>STEj(XJvQ3z7*hB%}M-dr$|ib*T}aqoMZ{(I@^1r0A4)h<5$Jp zLn$((20KR`6o*?#d+ZK=^0Yh8M$M?Q0EVdnb5);v`AJ5kP4rpma`U|H%7^S@+wwJs z$By~IBse^FcP(t->Dm4+ktxO7&{gzjtNyAyOYp2p`lN?nk?rU+V9P{Tf5c|+z|iYx zqdM>7mud3~Qbxut8Z&Z6a(KB~Qv%Q*b@eMGlu(zbTg z)r&OrYd>Wif`tg0rZa=!@j6GbNb8G5xdj3=AXeq2uG%1M~#7a(}L*$IKSUEe`;MX=l?dJa0(b!VWa_70I@C)0Ic?!BJjdbA_8p0^%WD6-*zZ|RuM#}u_ z6brKWAU5_!Yk`9SX5F=5{K6<4%={_y9IMrceit2+`<%Kmc$3mo#lKv%;sN%Uos&b= z-V1WElRO>5FTCfA>OE`^`;rfW`20#+;$VJESHGBlh5JMCNA%A)`>`|Y%CQ;##ls24 z)gRy9SQFhvh6DYY#lPAsfUTDzk4uGLAEn1-OJ&Yl&2ZP$m$^2^BL%oTQJZH>aru`!KRi)=cuyL;w`&YD7RE22ReV5uQK@-+K)=I$ zy#HHA@g#&_=&I^7x{5xpDS(mLEvMoi*TVP}8hbWwXe+J#SW~QE2)`Ju(2Yrg@K|zE zUz(n>yCjq-j9+Xe6n=R^6I;L8_~lth7+Br_OvI+BOC(Ei&D~?nzg$Ri&GLVZUs?DD zo-AfVZ3Xx>tBttgD@?=)j$%ox_4SLr!HkHT8X!Q+h%2^e>u86y{bP9I`GlwfO<8k}3}V*K*^>~|iVv2V^r_!WXJg(j9)GisXpJ9+@k%Ij>s3 zqgJnNgx|X+>+>%czuf%{{Q}KdqkY^Oq6f!}w|xGk@C*AnxmJIPek~WKun%+e1A9?* zz$f;O<@_ zd!tz8?arLCuV0K`?pi1;fWAweq8FmvpSaJz6n=Sq{s|j=2b9XQkRkk&JEri0@oQf{v#prwyp7=Ac5KLNocJvMwIgE*!)Q#D*x=uqy}3v`(Rr+n zA3p?s?KD$P8ezi*Oq75b91-e0&>l9H0v40FaGtDFtEzbPed)AXT~r1hXY2b7vnkvQe1{% zgrZgJXY(&3vDy5~=ynnm z$5I;I5X!@hVW}jbiJI|IrMt;7PRacG~&}(Ne;u4fC&3&x6KV zeLhrgVI{dne}ND`thCSKUvF7C*;&5g7ee_+wmznGXY(xng$S?>w$;N?DGdldQ=;$M$a`>@fVb;t0d!wAZmG)(PzbUwttc3O8! zqZ_tmJ++O+Ee#Pmc1~vTFPJYYabRP&0s3Eof@CyKh(HMQFPY2!b4h<4!+{%L#y-Sv zahni+AynlgCx@mH?_K01E6b;R+Y;hmd#sLZ{2(x8y+j(tbvzW~2=TA|R)-zm*@%3K zOgXUOisKW6imzWVl`t3aZ11=>1Xl#ZQLzF%@%4-G3#Pz952xAfagr9giYEe3Li`J~ zi!O6oUj+X`=PST32mCTT+B4B{JEDa%L@c^* zr1cFvv3x8Tr!r<9CXV@qf~|4dX<4Iql8R*6CNTeE|2gLJuX<-A3p+7DV7JG=R)BxK z1?bOsOTYuro|APPXM>%0C*dH^#z2^Vy%pv88Sk#PVG`-0KoP}S|L6O{}dk)MV z06oU_Y+b;=##H{RT|k?zWd7wS;W4r%jL!jg1dm}WGP zekjnNlIqWVq2~EC`jZLx*P6(7Sif#j=eA)WL*pqr$U>NZNyVTocYfT7;zZcR@k6}= zmV^N^eoZn`BmdPH!Y||$op=|v)*@v$8pq9D(sI(X@C(~`EPl7QpEq(~;R*5b*lhed zBX6uG*TfM>lsCc+VkEz3%_;?sGi>@eoyTKAZy4<4`^Zh;vrizwuOzS(yy_o$$LZP zzXU9R-O7FL;66VB1G0n2_Anm8ueaz$xvLHMH9(_sk${_#Q=ot+WuJeIS)80RsIU#V zoU#D59UM`-DF0P3tYUN5f1f_0Ae**mKTQ))|aqXTM z?2F7u^qChWC7@pc|GJ`P*lGEk@rUp3rD1uk9Uo9Y){Dah|TnxYTBQ!hta1`p+XZWArn&esa!xtq*ZAu>_X`Q?p`i?&D!jswjYe?A6$nFBl z8wRWicBpvl6-+|FzlxwIT{83V+y#wK$?Ml8?d2Ru?6QGqZ@KHG@?Sk{^VBJ zc_hN_hMf=a>kR!!t{C4`)=)*qMah$A8SJyQmXe>BmprAE_QqTt7$v^ zNUE&jHS#n&3@%7@<*RNCc8|mDdWa&F6i)XEU{n%RDk-hEiL*t|FdZo>W;5LJn z%H@`v5=+fw0g15Vc!K%4#d}Y5j@%%DR@=1?7zZK5xA!uTwc2&eztjiy8`_XaRo>U# zXwa_m8YiBuUCDWK8+OCXe_0XGoMOx2H1n^==}re*^yAovEr;g}Xk)HVl1BdP>A^*I z=hP6#Kt6y#;?SSbzsZGp;MXmh`Yz6Yv5VFD_i?V@fX#duSO7s_fPVePyz^jNiz@YF zx6U`mg}6MjoQeZ{dR=J-H{u^*2rpJZg-2-sGas6QC*q+?@CM`6Agn{u=8 z3&V*ZoBXhT(o(##xB~t)rH#v7{h6wcBt>7rfk~OBzje7xz`xegrbsIpqZ_U< zb~pej&#@OU_yPY~DK=Vd6GkcZ9dkb|aN;{$AnWHg)Xx)bM1d64CQ-S^j$+!0o0DuYgz3FW5TQ9x8u6;9t|? z855{Crgsq>4@qZ6He;5^+eFlp>sD244`L0KY`T8G1(Snn-+UZo75%cy1?#6O1c} zAMVl4L{OJfg;F7G$lFh?1rIQ&Ka{{hxWwi7XXsodS4A7OR~-lwu6~Wxw2KY>9a~^7 zJ|XtV4h#M1hJLC31o*X*3L3KAS#2d$Ci5(WO`JX9aRvCLEnimx|N2nxZM1v1-MWGc zIXoif=~tg&5MYav5q%|_0*SEUCg2x*q!51X)|9_-k6tw}uKxE-=xC{eovevQk2bBS1hU-tuQTP&kb zYlP5lDg5G^lQ4cEl0(WHOj<+vOhxU(e{{zl;Ma(Cv=(KMmj1rsqas&OIfbW>GZCA~ zf5E>HPner|AA5?$ zTVQ|zetp6oo9tr#wJbU%dQ1coPk?C5jvu~SIJ^DenpHq6dDcd(`#Jp;dRwZ_2l(}> zePjgaFri>y;s{Q8ZXMjHpCV9xj8?MdAS+VN9742?ScBXNBrd z5I=;be7XBXXQ>r%Y#kJx_cJcr;FTf%B_(IOIPJwkBVeoIAzGM!akeYITKj~NC4%}>JdL*SP^5nrO!X+w9|6L1Sv0W<4YP`{C&d#MH6xS+zJ{RaDo|16b17Q_$V zEu7NAZL8MCmqwnJi@0p#Y5IXgATbm_{I0fEbg=4GxMqN$GNBYBEm37C*){RO~|{ znD0Oc_}9}k=(HJzm1-edWK0ZsJo?p9Wn0F4{MtrG#~!OD(t4-d@8qg+^ttH=p1!+2 ziKHj3x9(apk^F}Kik!;l?m%z`HZz-Z-V?&Fs&o*2!amH=Gj2#{9Ks@JRkbz1ufL!o zZJRJ2&|1auiH;_ilD3|TEwNl)3%ogtNQ%w)yCrR;?Hf|qy3CFY=Qf|6&b|+!?W@0 zbzrVVyaZE?ZdVoNa-ReI`X5HI>0!FHtW6plnrHBx$L{ejG4Cll`e2v6xjgr*^@6ig zBp(1avA==M7U0)z3s5_etj;~IoiC#P@JGB4u_$vw`1J@)iLS$d^^@W?kvp+!cdII- zci&_2JR|>Q?o>0MdW{Oh3bv-P78m2!PR%wqX0>D1HdC34KZ1Wa8^7j@1G43l@wJUF zhI z>29_FzfRFntvd}j>~3uAcjpt$@f_A&%};<|515Fw3#j?WwE}2YUqA5F)13gnz8)Da zwj;t>`%&b--d8auxsBWBAb$A62&$o~@CN_ND)d>S=_S1h1hm!I1N_=cPf_k$30q%l z9ZfB@6R%-I0$69^SEVpzaN3J1wNvaU20^({{o$+hBfIOws#5E#=FiO>3Uu|8a<6OW z1N>T1SYJ?R^;3|Djz9JAOW9{1zankoYqYJ8e`J4)I`ZK*0e-as0`iA8nzc`A&@YAn z<}w}@@YYcIujAAO+SPi3UK>=U{)}HRdZGB?b71SJ(<|x!7Uhz{yF}jUm>oqt3Wos`BucE`puNqWHG9;m^mY4qu_1VR*hKIHF zpk45dPZ}t>?DLXpF{X{R_6Nt8B1_KdFQE_V|0Up73w^N9`>Ka^e|aVCB!cgai?u=ScY zRLC4+1Hz6X+l>If%%;a{K26xqFIvC?h5$Ek2O)%Czn0xrV(r|Qv{8xrL&Og)4kU*0 zOI76&!xo3HnV$SYdbTCNuV?9}g&W#dPPM*3<69P0E}LQ?le6*bD|BCT%O>>a-^IP! z`zO#1CWh$PJu~^QviOEbi{bzxM3O@vRliLLznttK+0D?eaVk{WDj0IYAA5jb4O zl%Vgwq_H_&CzAW(8Q&fT@xzx5td7}P)?dX;vngmrWvpux0{%5E-!33KiIQgRZt59H zREJ)a9*_n2^%-b^oksNOZ>czp0$s*0&mQ{tRb$cKmXu|b8(*i9B0_NCHZB)7qC|T^ z5wNB!8@FL8d4Rs%2=MD}>?lN=8MY=Ps+=;g&pv)#H64AMdLj&4a9Dc8<^f=V=g$ZD zRh6R_#^u02RBp!4^j}4RXik`aouKs#QhC%>K1@I6Ld2c$=QpHVSqSRqpCnnf;7p(v zLYcS}+6*H970(uY{A$>y6-l|5BlO<^6B~K#>xIJZ0KZ<5M@n7J%5UizOPOU`JJov> z@!n+l69ImeIev&Z_M-E`9nL4tgRsnZFw%g3t%Ej|CDuKo%zM4PJj0BPdH00RzbryD z-Y(h&gMN(u=v>&p9&s)aiXX0|{e5;mZ6XH2<3eUVqoIDD7bW0d?*`jyxvTgwoElTG zwa3GP+4-+GtSli~NQCoWqxF_v2gZSlju8LaLtl*C7)?IAe8RW@H-i^WylwV8heTL_ zU(h%!`z-vHgc=uUj@r*JLKzph{s!WQVpk(a+7aLQrmOEtzs8_wjjqqe_4AL(78^ah zp6(lNuiUz(_UrVhZ2uX^V;PPJKB|76tjTmX7LgCJNvR^xp}1#RyWjN>xqkjFksV2# zjNjnH)_0_r2;1j=S0BOhTL&pg8+{WO%UcH&7HGGT$G_k);uPD;Qaq}8bp>t8X09sf zn)_W`f4IZhCeo-6H@PGp*wn^E9)fNK{EPNpyG`_c1wZoITu0w?8`t{!6{Q^}V*!q( zC@i>Ln-_Uh0Kc02`lvm1ciB^uI~OE245jQb>Okl571PM1ucG)&{bBT+T`!XTC?EPf z!`9aLt8`8R(YERj*SeSj-1!ftU0J=2YtaSp0>EJ+F1lrge^sy#7X!aysNcYMp{DBu zNxP#78W-Rfqm{J`HbMEcBHpNtO76VDIXjILH z=LCGMovi_WarPhYc{@JeSjDh4J=8;}KeQ9mL!tV^$He=O7ylZN6zJDC4UBXkTz|M5 zeHNcXNXK&>uY{o5kZEy$tfn7Qxvz~WXM&V|?bh1mcZ4MY3WmGqk^d6sMAz+!1HQhW z!9k~IR&+@q(E^`;okC_Gum##>d9Za#{Fu5WY{CqFAyl=i55M&{9{(EZre7NBJ+wmU zAlJ|DJY-eZWDy@@*t(SukZuNFHmX7WVGTlO5;lCNb~ldhb~snC&5U!KS@nlyvL!5} ziv?KI1dJ!fmG$+@t>0k$ntQjV?EFCMmGsjHG7$s8`7hKTo}u^1%>!|Ut@kK<$oM5; z7=8STJWu0<^*XIr?H|hP31Qx82Z^u>+GKtH^*X1$ZcSIUmy5_--GV^k+l0t=1qLlt zKM(#jW-QX4w${_bI0y#k7STcn`!MC|7wR`+8!f~)${NZ<;YdR`$?xGHYSvu~F>jp4 zZvoFOw^r!L@bx2E4)0J z{ybcqd%?&M$;tZoHJ090%2cp|^|Vu1m6&oA4+F>+&YWNV@A9qNayDRefjlo4-H-lE zYG7nCIdbv&<)n-wZqt?1a8Tvtrl~$<^n&`0SLm42B@!m;MbAdEqQ0cpz~4YbaZ4D# z1_idw7OgF^Bho6;*JuG^VHfbUJS}zd0D8;UB=G0GYOKlsJ5v*;?O#M9bFLheE z2Ji==RJ*QmkkYg8D^Fu!4>-P&0=RTp9a7go2oNzV&fwP>?X2j@Cm+y$%8uedvV{71 zY)Dc6Vwis&f#px2-Vd~^>r?F|{d)N%+9Y3`IlnxqV5^TbBe91TEH$M53F!ja%=u;T zFCeU80>Aj8fNM({&Se9?6z2N)rL9Msw25=0d&L6wpI6BBmIC@(SHJlD*AYkc=e=}x zxJ%Ssj*cA>3Y*fdex)PdrE^wJY%c4kif6?^jB6<1Xkq*k98Dc+(Z*;g)qzvXu|5@1 zjJf)iu89GyQgY5VZGkMXiL(H;S9_m|N8Zu|9TVn)l)%W zD!{K2-52@9sByb?oFQoxxveUn|8nC0qJPSrXQHw-MAsfJ=CyJ0e>Gq2823O20c4}` zehttClK}iWLPLiUpXWM+|vJAv%`7!GU-2OZl&b$0stoak0bq zi_rJ-%=zVtbuN!5yY)lSpBuTu5XRW|V+$GJ*Bf-9@oyc(Mc-2HuqgpKJ{q4dI`*J+7F{tI~rDq4%j=BPqM z^pIno?mUmxpxThqFxNop5z9J^C2$B8i57$tQmq&8%iI^;7Db%o8XA$;NTknHK_l1U zS6$s9)E`b+OY>k!mr;JWOTs2VcQn|;lJ3ml*BLsP$LgG+f5&j@DnqIkRA5{o{CbPB zq9dhWeRxb_y-J@rDb9kZZZ3hxss6b2^RS1HU|e(LVkDYVuR-IW@3t1of5Gn^j9nSi z$YF6An5n z%kgicp0;ZclK|$zdo>%6xq89%hwHFg;0+p7L+^KREx-irMi73EfCaGlJzRgdOMbV4 z`uVR@qS#VV`7bYL=jj*oFJ#gk<612#zDigxUQ>>1&5<$hJ&J!(?kg*8eP8Tpf%UTI zPO>)$L0{_XGS_cRYTepjIdfmeRRPF6^=p3Ajd_8e1@-odN%96?ihk zzao!P%L=0(c4NP2>3?@Wru$I{ut-`Bzs9YfA6dLK@!HS{o6}zPtY|DG9DRm=v6bNZ z!@r^bkSOF(dldrws1xp9-CBba&9sz9aUGTt_iv~+TxT_**Sc*~{d^64S{o>gfIu3G zUxl!Z(lS<0S?&+lA9C4-hhN+J(D~=^gjuB4==z6l{UIugO10O}UNhBO1@2 z_2)-aeQ%4CUZ(h0=NJ_2-<8J*!Q(_GJwUs-#zSaz#(i45Gt%$HJkiF}uQkvwR6{w& z66RkbGf`YpK*fJCGnrnpq1neT?kb=2-Pj&I*4Q(FJ0E@_FXVfUCq4`QHNcZtqEoOf zIcL?w`Y-4l?tIw1n*|;z<5!;BNORh_KuevKAJe-9m-*FCC_#Y&t*}%Z@UQ)m1&54s zZwKv~Xyy71)aki)-V$mKWlaW8wlT(Kvik*~%`7|;v~m3n_xu;*axaHNZRgf94l;Xd z3inHWmpcE2c#Di@Ob)zYYjK^P+aFDRm(AzD5QYN(3QGN%h^aPStefxOI4@CM^CLY+ zs2^Ls=|{Ta%c~PpxV1ygk2?P)JB+&fwTx99?&#|)BVD`R!rf5i0+Kr1A3nc~yFawP z#@eWc;uFSP9BMGE4;fvTzv1c^@GFAZu;y_5r&!F4rT1W5>&dQSHiGyeSIZ-g{ndCP ze^f5++w{Ot`(4XuXC+fw9>TBlr5@UhR2{&#C%=ko{$b}2B}4H;Rck~r7a4i9(B*8h zhd6%NHGwKqGiq_48NZgo8Y8;WK}DfCb>9ZzMFs&2S6EDf+qm`f8MKN0VQ(P#QZ(UMY>#i5yAGKSyTgDyQpY?8XTCF)#vHA23`CuhJrG3$T57!@-5u-+b?iPnN z;8#|UMt>H`qM|;28+J54?)@7*)OlJz(2Ii)!^wNFaQ|-h3?~QlQf;2w@cHF8Bv`hI zicq8&m=G|2NiBX{O|#ew@5?4uHycv6;K&2TBU7D2J(&^V`_}3`LZi`r>7PXiv8WV-4(l?A20U*2I)i3}4jRlt@#J&EmHF-ex z?eZH0T)s`acLu*s_jUExmw;b~#6FQ|LVte7__akJaqS`Ehm6ajZma%Nn8C#&`85F9 zk4g%^KIZOc#;-~2=M2Jz7RL`W!@#ex$WC+R=*8!k$=1%MIDQC#UO*ct#X`(`5Acga zXD}C&Q~(M>s7I*7s`TOd23NlV{Nk|TeQ??V3RhYnJ`*$dM=^f=RQ8-md~xVJA%18h zkhnBDT39se{wM`o)d*`!^(Di_>0DISVTpKL3UIVIEG` zEc{Zp*<|THE{PY7*P&xA0*<1GUj+Q(j2JX-D{ZFMzc)@7Oeo{kTKqWtD2w-)dww}H zhVx&WsF1fM9D7~J(lsVHbr`=y&&0~HuXOlQ4yoAOhiy-KhtIO*C4NPyms=bA) z|2k!}qb)%x&_jqH`u?GdUy8Y$r1fc)|3Z92yGx++mb<1der24ES*?OV2ig#V`8bm< z(y~kAk>jKA>qZBb4RJQmlXMySg$ffw2EoEiA)MJxBJkfcD@xB#rPU!S~8VUttC zh_+~yU1HO#Kg4<`7$=melvAm&N* zP{ig9>F2-Z+5H?(Kw9~f1vh>;UcRNRu^3J1X?fVgFPe7&oDtV^l|UN%|wlYll<@ZyL0NIeb9 z2d#LY_ADWVl)rVY_U;wC2NkI?+%@epB6JA%;K5fPm#9Bv*T}HI$TTEY8r?+&exa_j zN3N=1IOokIB~Qnv%`^1GC=NADxcW6xQ^7S&If*dc32fusK<2S{Cdvi`mNvkzO+YKe zn&9%8!_oGF@!3Lil!Nenq5K!u9|Cjxw0~tG6+5fFdye-ch#!vA5Zpq*)(_>->ddpT zY%k*2mCPYjnTGHS*L)3wfBigqRODp6ts8XM>6T#L0srFqLtY)NYVh`p$oT16T=2;2 z74WZ7`WMRL{wV#`=Ch;f^1W*$?EFRewf-*9t}Tr?w(NBD$FC~9w*Y?wjKkM2=3oD$ zx2|C7A-;!Va)g4fqc71zD-5<9g7w0PqKvJnWwr6AH$N{P-O|1qp~d&pI?>v1yy(a0 zIsbM1wXUVe?;Jw?;f-8>2#<%dG9g0vrJ?L_4X(O+byx`>NB--qL}UP$GSw>m+FJ9f z^)uO(2ZO#Y%JqjyXL%O=;f!-@?F@bu`%_ID*#fXy-D;##NPVTOVo|GiZ42KY^-#nT z8_mYy1}@|P7q;MQEg;wpEx<2CX%H!ep)?1LRPU{&7$*uBFq((rhm2Oq(%kLZ5z)oP zC(*(o+9Oc@7Q_#?Yv)P_Pj0?{<7(pi!_A~uth2Nj{>D%cKa^Coz(y6mi!L)!Sl)v9 z;fP{5|E17sQhtEGe0%FAV?34xemz9-vBFIKhBma!ei=E|P0m;Q?P|KaH>pA6s_{_$ z2G<{2cVRzop}(V+yz$?(EA9JQT8@H$O}cB!_;t9n!%9rf-KV`I7uku=>pk`}g@sk{ zFF*fPr+iuy<~>h8i{zHMXKDt%cz6cCM9q2al*Ii}s%)dwa}s3$Ir`wJvWG$Z@Bs^M z;bG&R!j*FOlJ>;0&oZ7GEzhU_qcFq2#CB6Y)>***Ui@UN#yPFN$x zuy!Yvc>%JGn;V7%DgbxKg8bJ%)6Yd}VABEpGxD61n?hH=OV5QYV5#<6#QL`UmPto%-UgW zNQAh{u?(*%V}TaoCM1DhKceg8N^AKDr#~bL+Y;(@_Xj5Eid6 zz|Vhyf2r!4YP_4CUe{wHJd&li%|(@P{f2vO6!5EqHd-ANld-!92XJQ9&odWBCOc9hQYB0eDMxkG8 zYrhUq_;f{|b^nG}Eg$VYW+3mt_4BBxcd&5JYTO+!e)t|IS&g0P$3?y?uwH*7__8tx z0e-o@7G~pBgo|^$+#T2en4dji{srIfP<%ieg+lL1m%Wrlw- zM~k5i|LAt`6x45+s?AfrekuO7EZ)#tYwZx%a@ep5@k4+@5TEz&kE$;YrQo6?U`*f_ z(-2^vU)TG2z1;hwxT-vkFt5xFpjH+a-a6nZrjK9EHSV~QTZeG}hIo%il=LS0AtT6y z9@NiQNL3qtxd8ksbXaMeu~a}7s-Fjbc@>hVIk7UgfLB6bAmctOtn|(=Gh~B%S{;CO zOoBqRQ2mD2pOSu!#&t5F?QIZt@;rMn8J~Z#uVv#pM}aLm3TN^lw+ZkI^&4shnRYRd z6?6!f;Fnizi2Dy^Yq`!w%9s%?UeRXo%d;DrMnl5dX z_c|@woPk2Kh6;8ko)6>K&= z>yvbrPc+*X^DhNkZ!!)}CY$k|9=s<$gI|hU#jB`~dX!pCBVXGr*Kz(Ue=+}p4qhn^ zaxkP{YZj`IBd-avuzh^~1>2$}u(1IXNPyCM2UgUY$$xo$t|HztRZ-VC;J$9of7yPn zO;TVJPGKVf3z}LdUHr0jn-qR2{^fF+9E~SHyGG&|mw~#t%1r+2Zr46nwS@6Vp|u?Q znwEx-1p92y*23cpZ4?+kS}J|l00m4ZTm zOBswsu79ZRKTM~V!%Eaxuw!N8ds?U1IDsnNM>X5^57qsLmKBYs3nR`DM-$48ZP9NL z`+k&i^^5PH-xURqvoxDfyCTyP^Yd*p#_@!*8{cs6KkRxInzBP2<30<$kxt4Fu-|LC z@r_Ev!>@_>7kGdYsm$}@C&Sl^X%!8n5h7^UQ1z3B}a5fQrf~SU4&nm?fN-+l*eUb zO%K!35zPD--0xE7mqo4x-aDs|09y`-^E67gYC`-=*;TeJC@_F+$&~bOXg`zN*x(o3 zJ?7nisA}V(RtOTlON(mjOjwY`a#&f=ZsPIeVmL|VEbV38YwGu`B+cYVcT8XjN{}IA3mw){l<{f2+ zTUuYC(_(QyfNWO$P}NJkiE;IODzSCwn$(Yq*}D>3^$`DJ`~s8uxj@;5X+$xcqSi`j zJIucrzc5m_em;FiY%#}s^D(ZO4B^+^PMXW2Fm?xHXYSc5VrH0sp{so>9~gQ?Q~1U4 z!+#Mw`5fd7|DtnI*p{6`9@z0+%A5$RE5$FyuVLud7$ML))|w?;Ohk#{cu>EA)5kwC$q!;Vz`T;@9<_BGez|(^(kvp@=n#&_pPHh_ZPBEcl<;&p0Mr zX#`2Y{NRS_w7aIvzuuHL+N;(emW%jdK5<99k(@yU0H^f@8gC7*Kjh5p$C8f?y#gQu zE=$xxoQoW!VU@x!|lv+h4cHhIO68_#SXPT!-M0*q|9 zcn<=kdG%$8AEM2mp4Xn|K1*N|{;rCdSp#MC_!q|y%XD`?Jp5A{>zC22)z_ka!#27% z1pJHftD}@$r@vlM{^|j}&ic8NyFYPe$m4nnzXZ0QiDiP(n@B#SSLE7kst?)})NgQ{ zt*3xETQ^_=H3KMk0C4P*E5UbGD2!9_LknSz61ENQi<>~7nOj+RzygH$7yLts`!_fw z*zx2X8*RYRh&h_O7T{kvVh`G7B0Yq0@rG3X81p!fe=&YxA4)7i6Y;p}r0)7ZiK7-K)-;n%!PO&bdxQTzxX zE)?xLMH@t##}&$d!Ccsw`Apwb|57$+r(oxm;}P($M>OOeDuAtEIHxq!eet+v_?I?j z;a(%WhmP7yoy}!^oW{iL`uT39<_M}Xy zpgYe7_$BY1=sXoe{h{>_QqiuLi+)5PlsY zH7?G7<(91~Eq4Jr5jwwIAr2dYZCRQsJCqm>3qZ6`{rq}TU1i#Z_&oO+8Yh5gGyF?~ zx6HEkB_9-H38`y-WM4gn;v3$VK){Wy0r|#aWAw zeGOHN7npXjZJ83e7a#=qbpdGAQ&s%y?b4!3@(lpu1xIDX99O?a8V(?y*)HSN)Rh1! z71nss&vw1$>KEs~&}V_Jn)E%olaGd>M#yM)&}YZhFRSSkNs%$)Swz3fTUA&C%z@O{ z$6WmynRh@NGZC_=>TQHSET#G!Jtupd4D{XoE{}ipgC=vylQ%9@5pd%We!sP1o|U)VNPw$HG=?pna;Z7PTOmo}|=VZ$>~4nwsn zA_gJAFYqt?y_*5B<3C_Gqk*dwwo4 zVPMVM!dk9OQ09q-U1rx0N z1g<}P0uW$K#=aN<|Ek9SMtdJYcmo$@PrL6?{EM!0ko`~4|IJ&A`4PCT!@;qQ6oU!5nA|C%4Y524QZ|DnCajLb%#D>L}DOLkQ7mze6^v1he0DogB4 z)J)Fc*Bj{J%1_0cEfvRR{CZ2E&y|_`H(=RJb#1SA1emb3rkb%cXWw61AfXb_XOrg#fBy?Md>h)JhFrDTipJlQoq1$kL->Un z`~Ecl9We!DrgpiB+g3#wzw*#8gvCfF3_6E1S?~|1I2zCRrM?S)|BKGbcCOYq&(0)D z{pT`IfiR)JdRdP8C~sfd=9}Y2opj5VZ$(NX3H4bT&c!>t6O`CB;Z7de`$Q%Jm&e6 z=$PN1V(vCfxW~Uxe@LA6>O@yH45!zvpD!ul1(#oN{f4T>l=?zUR1YDY=iQdzg!5mV z?=~#3k{75$_9^^=fc+D~FWh!mK@DCEI>;O!<{h?<;?x`9S2H~>RJFzu>mR7I0tire z!4dKRzvj~gxeMhM2pj%DcH8*#h0iNS7LFf|xN2qVW3Ipyw@cHWJ$ z!!8E03Kkdj*rgs`Wz)y6t@NnbzQPb%Rsf_V)C&D+ZZ8}Q;)fuDbU}-N^h)*?9>exRGPBc7VT&>kluOi$)Vut^9{9d&U#+ zHw^E*xrbkf9~w{eKlmKj*0|gwJ6|;3=DPPn$Hn=t7Hez-^u$6}*+m~GFMAU3uSbAZ zDjRsp*vD-c-@S}jh=1{4nFO0q^&9MFxW;@{d3nIU4!E!d7lO{aepEojLinX_7vx`u zp5i?-=hj2`rEcBiZYbIXBIfre#J{{7H9@;X#wjXXM(5!%hVx&AmXm#;U1FVVuNa@# zkP(A`jM&%=ew{@QcUwgaa318tFXHF22840d$yu(K-CJ z6g59btlU^~pNsFj?g9ULfFAE_c|oZ;j-@;oza9on-477vU-Ydck6+h%Z1f~Vq zrGS6ssVciH_z4a>iWVw&f<6cQ3rOU+Y>Q!Q07umVYzpx&uR1;WQJaf#v-lU=1lX|( zj04OUh!_Om*DU_!Rl)~d#V80YGR(h%vHK<^!1t$IzeUy0(@uAu*>tahpWyc=;9u&t zLl0`1c9}Ed3h^%wzuakIw^57|@> z3Tu|l9CI;6{rxXKZBfQ?tq%#5Tln^n_1*VHgHeD^_I0x<2%d!a*EzWQU|X=6mM3_& z#aWSMEO6@&6_Wz(s(6BDpM(21Tnnj8H&kzy4X?Pij_Wtr@~d$%?NWk=1)hF!{1AW1 zOO1=BaJDNvu1oS?=rjIor811ZJ@oL4o?NC6h!@T4qjiS@p=My2dg3hPVG%vKqUN5+ z$HkwR^IYLJbKYppJ*1vE3l&z9)FPJbvl6yf(=B=~*qi>4xm>_sBM7i83OpGd#W zEj7J^{r2tYc`;wmYQ$iF`S#2_^2e2ke3(As%*)oSbcF#3e?r1($VNplE)sD6qZA=u zFwiml)l;HnmI(oKm`5tCKo)zWfsl@D;MDFi@4KE9HTlS&s`*jEN5wpO+3H9ieU#<} zeHMBi2W}Qqo%Dp7VkED-PyBK9MzeznYq?><@&|(4#83P=ltfv@E|3Zfgf4dsjz#K& zHO-$ZHd{9v4TTxuy1_Zt&3z3)n|#e3k&n_xpq$1cx!Rf&H6p^#r*Znbx$eb4ZQDFwrY(?K?!QZdQYU^=iaC_XyC$Av!DdEaNd*P zyLwrhtlN!wO0BXVNzBtC!nxgQGHS>lmmcYNZqLq3)GQAP@^)*UQ6nP4?KDmjk*U;| z1zJH7g9J766V@^Q+|;X)l$K=}8Vk0SW?@i0@xSXP)~`FDO*JyY_J`H#GWW?me_T%r z-PbR)Ij)ou>5s7pYaG7E{Y0~o1T7~Mx}$`C2T)?TPy9BlR(Ty1!Pl<|YC{|K#A{O% zStwTa&uxl683;8EB*a`Z>iDl|tyy#EV*?-EH18o6vJmjZQG)c_5O%FW8o|OskeWp$ zYQr3$oj^C!Wx$h}+;qazAJt1*tt0|nu?C_=*zX|nRSasoFFPypX_N7A5 z=JydYKaMZ{{x8bA?q=ce55q$6>x;TqJ~Q`MqvNNQuqZ49ZEpDDAN}O3kDvU-Sr+cU z{^Xa=-mtdssku8&p89;yCZY|92h8_I=NuwmaGx~Iar{P6AD2fX9zX+^U8D}$Xfx)* z1L%VPMEdU`x&%huC(S@u?_)$6jz4HMj9nr)ew*L=9tywbVqA6sTI5aXzh^=8mcd4Q z#Yn@Yg4e`w67*qea%!?LT^9?&gl`H{!Aj(2i>l1=`4ATq^Xs-_-|i zZJ9Ll(dNjdg8Lfk1IEq5vQC0 z?H>6+{=Lm}o`SH&7t|B4O@A1dJy;Kb{;op6P1AvC$e;3wk7A^+>4Z&}NeJBP^YX$ze*Chh^IRI!D{O^j0K$|WVy!ZSr{gVE7<)cd?^|V}?l}iL~ z4*Ln3FA}C6Me_b)!SUWhHMCG9`cawjWGn_yol_gm}+o zSu7{N(EliRPaOtizpuDR#lavTAm)93>kjllkDD2;+c@(cH=gFc2m97*GkY&D3hnNo zO>9_ukVeD;^HL#bbMd%lsF*)4pz)>C;y>}Af;PWHmxDIHzb=PWI8f@}pv%4~2;S^{S6G)rD(hn|2IokgttkSdO!5rTfOs>cV^(78F*&~-kE`SX5gI}cxMLw z^Ui?sm*6nLUlRX$XW^ZZzcT~x%)mP{@XidpGXw9;z<<^mKsX abs_cq) + begin + max_ci_cq <= abs_ci; + min_ci_cq <= abs_cq; + end + else + begin + max_ci_cq <= abs_cq; + min_ci_cq <= abs_ci; + end + + corr_amplitude <= max_ci_cq + min_ci_cq/2; + +end + + // The subcarrier reference signals reg subcarrier_I; reg subcarrier_Q; @@ -110,52 +145,75 @@ begin subcarrier_Q = ~(corr_i_cnt[4] ^ corr_i_cnt[3]); end end - + + // ADC data appears on the rising edge, so sample it on the falling edge always @(negedge adc_clk) begin // These are the correlators: we correlate against in-phase and quadrature - // versions of our reference signal, and keep the (signed) result to - // send out later over the SSP. + // versions of our reference signal, and keep the (signed) results or the + // resulting amplitude to send out later over the SSP. if(corr_i_cnt == 6'd0) begin if(snoop) begin - // Send 7 most significant bits of tag signal (signed), plus 1 bit reader signal - if (corr_i_accum[13:11] == 3'b000 || corr_i_accum[13:11] == 3'b111) - corr_i_out <= {corr_i_accum[11:5], after_hysteresis_prev_prev}; - else // truncate to maximum value - if (corr_i_accum[13] == 1'b0) - corr_i_out <= {7'b0111111, after_hysteresis_prev_prev}; - else - corr_i_out <= {7'b1000000, after_hysteresis_prev_prev}; - if (corr_q_accum[13:11] == 3'b000 || corr_q_accum[13:11] == 3'b111) - corr_q_out <= {corr_q_accum[11:5], after_hysteresis_prev}; - else // truncate to maximum value - if (corr_q_accum[13] == 1'b0) - corr_q_out <= {7'b0111111, after_hysteresis_prev}; - else - corr_q_out <= {7'b1000000, after_hysteresis_prev}; - after_hysteresis_prev_prev <= after_hysteresis; + if (hi_read_rx_xcorr_amplitude) + begin + // send amplitude plus 2 bits reader signal + corr_i_out <= corr_amplitude[13:6]; + corr_q_out <= {corr_amplitude[5:0], after_hysteresis_prev_prev, after_hysteresis_prev}; + end + else + begin + // Send 7 most significant bits of in phase tag signal (signed), plus 1 bit reader signal + if (corr_i_accum[13:11] == 3'b000 || corr_i_accum[13:11] == 3'b111) + corr_i_out <= {corr_i_accum[11:5], after_hysteresis_prev_prev}; + else // truncate to maximum value + if (corr_i_accum[13] == 1'b0) + corr_i_out <= {7'b0111111, after_hysteresis_prev_prev}; + else + corr_i_out <= {7'b1000000, after_hysteresis_prev_prev}; + // Send 7 most significant bits of quadrature phase tag signal (signed), plus 1 bit reader signal + if (corr_q_accum[13:11] == 3'b000 || corr_q_accum[13:11] == 3'b111) + corr_q_out <= {corr_q_accum[11:5], after_hysteresis_prev}; + else // truncate to maximum value + if (corr_q_accum[13] == 1'b0) + corr_q_out <= {7'b0111111, after_hysteresis_prev}; + else + corr_q_out <= {7'b1000000, after_hysteresis_prev}; + end end else begin - // Send 8 bits of tag signal - if (corr_i_accum[13:11] == 3'b000 || corr_i_accum[13:11] == 3'b111) - corr_i_out <= corr_i_accum[11:4]; - else // truncate to maximum value - if (corr_i_accum[13] == 1'b0) - corr_i_out <= 8'b01111111; - else - corr_i_out <= 8'b10000000; - if (corr_q_accum[13:11] == 3'b000 || corr_q_accum[13:11] == 3'b111) - corr_q_out <= corr_q_accum[11:4]; - else // truncate to maximum value - if (corr_q_accum[13] == 1'b0) - corr_q_out <= 8'b01111111; - else - corr_q_out <= 8'b10000000; + if (hi_read_rx_xcorr_amplitude) + begin + // send amplitude + corr_i_out <= {2'b00, corr_amplitude[13:8]}; + corr_q_out <= corr_amplitude[7:0]; + end + else + begin + // Send 8 bits of in phase tag signal + if (corr_i_accum[13:11] == 3'b000 || corr_i_accum[13:11] == 3'b111) + corr_i_out <= corr_i_accum[11:4]; + else // truncate to maximum value + if (corr_i_accum[13] == 1'b0) + corr_i_out <= 8'b01111111; + else + corr_i_out <= 8'b10000000; + // Send 8 bits of quadrature phase tag signal + if (corr_q_accum[13:11] == 3'b000 || corr_q_accum[13:11] == 3'b111) + corr_q_out <= corr_q_accum[11:4]; + else // truncate to maximum value + if (corr_q_accum[13] == 1'b0) + corr_q_out <= 8'b01111111; + else + corr_q_out <= 8'b10000000; + end end + + // for each Q/I pair report two reader signal samples when sniffing. Store the 1st. + after_hysteresis_prev_prev <= after_hysteresis; // Initialize next correlation. // Both I and Q reference signals are high when corr_i_nct == 0. Therefore need to accumulate. corr_i_accum <= $signed({1'b0,adc_d}); @@ -172,16 +230,16 @@ begin corr_q_accum <= corr_q_accum + $signed({1'b0,adc_d}); else corr_q_accum <= corr_q_accum - $signed({1'b0,adc_d}); - end - // for each Q/I pair report two reader signal samples when sniffing + // for each Q/I pair report two reader signal samples when sniffing. Store the 2nd. if(corr_i_cnt == 6'd32) after_hysteresis_prev <= after_hysteresis; // Then the result from last time is serialized and send out to the ARM. // We get one report each cycle, and each report is 16 bits, so the - // ssp_clk should be the adc_clk divided by 64/16 = 4. + // ssp_clk should be the adc_clk divided by 64/16 = 4. + // ssp_clk frequency = 13,56MHz / 4 = 3.39MHz if(corr_i_cnt[1:0] == 2'b10) ssp_clk <= 1'b0; diff --git a/include/usb_cmd.h b/include/usb_cmd.h index e73aa2a7..785435f0 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -125,7 +125,7 @@ typedef struct{ #define CMD_ISO_14443B_COMMAND 0x0305 #define CMD_READER_ISO_15693 0x0310 #define CMD_SIMTAG_ISO_15693 0x0311 -#define CMD_RECORD_RAW_ADC_SAMPLES_ISO_15693 0x0312 +#define CMD_SNOOP_ISO_15693 0x0312 #define CMD_ISO_15693_COMMAND 0x0313 #define CMD_ISO_15693_COMMAND_DONE 0x0314 #define CMD_ISO_15693_FIND_AFI 0x0315 From e59481c119ded9068958d080e678ddd5c7fcdd48 Mon Sep 17 00:00:00 2001 From: Fl0-0 Date: Sun, 13 Jan 2019 16:53:09 +0100 Subject: [PATCH 045/189] Fix CmdSmartUpgrade GCC8 strncpy specified bound depends on the length of the source argument warning (#755) --- client/cmdsmartcard.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/cmdsmartcard.c b/client/cmdsmartcard.c index 80cbec46..8f3d8d2e 100644 --- a/client/cmdsmartcard.c +++ b/client/cmdsmartcard.c @@ -581,7 +581,7 @@ int CmdSmartUpgrade(const char *Cmd) { return 1; } - char sha512filename[FILE_PATH_SIZE]; + char sha512filename[FILE_PATH_SIZE] = {'\0'}; char *bin_extension = filename; char *dot_position = NULL; while ((dot_position = strchr(bin_extension, '.')) != NULL) { @@ -592,7 +592,7 @@ int CmdSmartUpgrade(const char *Cmd) { || !strcmp(bin_extension, "bin") #endif ) { - strncpy(sha512filename, filename, strlen(filename) - strlen("bin")); + memcpy(sha512filename, filename, strlen(filename) - strlen("bin")); strcat(sha512filename, "sha512.txt"); } else { PrintAndLogEx(FAILED, "Filename extension of Firmware Upgrade File must be .BIN"); From d04516a6526bbd9f7ea5ae5e6c3530c13b5ad7d4 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Wed, 16 Jan 2019 09:40:35 +0100 Subject: [PATCH 046/189] adjust CI testscript for new emv commands (#758) --- CI/travis_test_commands.scr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CI/travis_test_commands.scr b/CI/travis_test_commands.scr index 4f5b025c..2f81c885 100644 --- a/CI/travis_test_commands.scr +++ b/CI/travis_test_commands.scr @@ -1,3 +1,3 @@ hf mf hardnested t 1 000000000000 -hf emv test +emv test exit From 4309ef8feed5876379c72a458538a7b21c5a2df5 Mon Sep 17 00:00:00 2001 From: Michael Farrell Date: Wed, 16 Jan 2019 21:51:55 +1300 Subject: [PATCH 047/189] Allow skipping or trying different keys in hf mf dump (#759) --- client/cmdhfmf.c | 89 ++++++++++++++++++++++++++---------------------- 1 file changed, 49 insertions(+), 40 deletions(-) diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index b5c1b006..5bf3324a 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -276,8 +276,7 @@ int CmdHF14AMfDump(const char *Cmd) { uint8_t sectorNo, blockNo; - uint8_t keyA[40][6]; - uint8_t keyB[40][6]; + uint8_t keys[2][40][6]; uint8_t rights[40][4]; uint8_t carddata[256][16]; uint8_t numSectors = 16; @@ -290,38 +289,39 @@ int CmdHF14AMfDump(const char *Cmd) char cmdp = param_getchar(Cmd, 0); numSectors = ParamCardSizeSectors(cmdp); - if (strlen(Cmd) > 1 || cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: hf mf dump [card memory]"); + if (strlen(Cmd) > 3 || cmdp == 'h' || cmdp == 'H') { + PrintAndLog("Usage: hf mf dump [card memory] [k|m]"); PrintAndLog(" [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K"); + PrintAndLog(" k: Always try using both Key A and Key B for each sector, even if access bits would prohibit it"); + PrintAndLog(" m: When missing access bits or keys, replace that block with NULL"); PrintAndLog(""); PrintAndLog("Samples: hf mf dump"); PrintAndLog(" hf mf dump 4"); + PrintAndLog(" hf mf dump 4 m"); return 0; } + char opts = param_getchar(Cmd, 1); + bool useBothKeysAlways = false; + if (opts == 'k' || opts == 'K') useBothKeysAlways = true; + bool nullMissingKeys = false; + if (opts == 'm' || opts == 'M') nullMissingKeys = true; + if ((fin = fopen("dumpkeys.bin","rb")) == NULL) { PrintAndLog("Could not find file dumpkeys.bin"); return 1; } - // Read keys A from file - for (sectorNo=0; sectorNo Date: Wed, 16 Jan 2019 09:52:20 +0100 Subject: [PATCH 048/189] Increase threshold to 160, fix for issue 756 (#760) --- armsrc/iso15693.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index f6868297..9dc4bf18 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -339,7 +339,7 @@ static void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t start // false if we are still waiting for some more //============================================================================= -#define NOISE_THRESHOLD 30 // don't try to correlate noise +#define NOISE_THRESHOLD 160 // don't try to correlate noise typedef struct DecodeTag { enum { From 0d2624a0cc13dbe34392da1f8495af6c64a84ddb Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Wed, 16 Jan 2019 09:54:19 +0100 Subject: [PATCH 049/189] Add hf list 15 (#754) and refactoring: move all of hf list code to cmdhflist.c --- client/cmdhf.c | 513 +---------------------------- client/cmdhf.h | 2 +- client/cmdhflist.c | 736 ++++++++++++++++++++++++++++++++++++------ client/cmdhflist.h | 37 +-- client/cmdsmartcard.c | 2 +- common/protocols.h | 2 + 6 files changed, 641 insertions(+), 651 deletions(-) diff --git a/client/cmdhf.c b/client/cmdhf.c index 744a95d2..f11c5b65 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -11,15 +11,9 @@ #include "cmdhf.h" -#include -#include -#include +#include "usb_cmd.h" #include "comms.h" -#include "util.h" #include "ui.h" -#include "iso14443crc.h" -#include "parity.h" -#include "cmdmain.h" #include "cmdparser.h" #include "cmdhf14a.h" #include "cmdhf14b.h" @@ -31,8 +25,6 @@ #include "cmdhfmfp.h" #include "cmdhfmfu.h" #include "cmdhftopaz.h" -#include "protocols.h" -#include "emv/cmdemv.h" #include "cmdhflist.h" #include "cmdhffido.h" @@ -45,509 +37,6 @@ int CmdHFTune(const char *Cmd) return 0; } -/** - * @brief iso14443B_CRC_check Checks CRC in command or response - * @param isResponse - * @param data - * @param len - * @return 0 : CRC-command, CRC not ok - * 1 : CRC-command, CRC ok - * 2 : Not crc-command - */ - -uint8_t iso14443B_CRC_check(bool isResponse, uint8_t* data, uint8_t len) -{ - uint8_t b1,b2; - - if(len <= 2) return 2; - - ComputeCrc14443(CRC_14443_B, data, len-2, &b1, &b2); - if(b1 != data[len-2] || b2 != data[len-1]) { - return 0; - } else { - return 1; - } -} - -/** - * @brief iclass_CRC_Ok Checks CRC in command or response - * @param isResponse - * @param data - * @param len - * @return 0 : CRC-command, CRC not ok - * 1 : CRC-command, CRC ok - * 2 : Not crc-command - */ -uint8_t iclass_CRC_check(bool isResponse, uint8_t* data, uint8_t len) -{ - if(len < 4) return 2;//CRC commands (and responses) are all at least 4 bytes - - uint8_t b1, b2; - - if(!isResponse)//Commands to tag - { - /** - These commands should have CRC. Total length leftmost - 4 READ - 4 READ4 - 12 UPDATE - unsecured, ends with CRC16 - 14 UPDATE - secured, ends with signature instead - 4 PAGESEL - **/ - if(len == 4 || len == 12)//Covers three of them - { - //Don't include the command byte - ComputeCrc14443(CRC_ICLASS, (data+1), len-3, &b1, &b2); - return b1 == data[len -2] && b2 == data[len-1]; - } - return 2; - }else{ - /** - These tag responses should have CRC. Total length leftmost - - 10 READ data[8] crc[2] - 34 READ4 data[32]crc[2] - 10 UPDATE data[8] crc[2] - 10 SELECT csn[8] crc[2] - 10 IDENTIFY asnb[8] crc[2] - 10 PAGESEL block1[8] crc[2] - 10 DETECT csn[8] crc[2] - - These should not - - 4 CHECK chip_response[4] - 8 READCHECK data[8] - 1 ACTALL sof[1] - 1 ACT sof[1] - - In conclusion, without looking at the command; any response - of length 10 or 34 should have CRC - **/ - if(len != 10 && len != 34) return true; - - ComputeCrc14443(CRC_ICLASS, data, len-2, &b1, &b2); - return b1 == data[len -2] && b2 == data[len-1]; - } -} - - -bool is_last_record(uint16_t tracepos, uint8_t *trace, uint16_t traceLen) -{ - return(tracepos + sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t) >= traceLen); -} - - -bool next_record_is_response(uint16_t tracepos, uint8_t *trace) -{ - uint16_t next_records_datalen = *((uint16_t *)(trace + tracepos + sizeof(uint32_t) + sizeof(uint16_t))); - - return(next_records_datalen & 0x8000); -} - - -bool merge_topaz_reader_frames(uint32_t timestamp, uint32_t *duration, uint16_t *tracepos, uint16_t traceLen, uint8_t *trace, uint8_t *frame, uint8_t *topaz_reader_command, uint16_t *data_len) -{ - -#define MAX_TOPAZ_READER_CMD_LEN 16 - - uint32_t last_timestamp = timestamp + *duration; - - if ((*data_len != 1) || (frame[0] == TOPAZ_WUPA) || (frame[0] == TOPAZ_REQA)) return false; - - memcpy(topaz_reader_command, frame, *data_len); - - while (!is_last_record(*tracepos, trace, traceLen) && !next_record_is_response(*tracepos, trace)) { - uint32_t next_timestamp = *((uint32_t *)(trace + *tracepos)); - *tracepos += sizeof(uint32_t); - uint16_t next_duration = *((uint16_t *)(trace + *tracepos)); - *tracepos += sizeof(uint16_t); - uint16_t next_data_len = *((uint16_t *)(trace + *tracepos)) & 0x7FFF; - *tracepos += sizeof(uint16_t); - uint8_t *next_frame = (trace + *tracepos); - *tracepos += next_data_len; - if ((next_data_len == 1) && (*data_len + next_data_len <= MAX_TOPAZ_READER_CMD_LEN)) { - memcpy(topaz_reader_command + *data_len, next_frame, next_data_len); - *data_len += next_data_len; - last_timestamp = next_timestamp + next_duration; - } else { - // rewind and exit - *tracepos = *tracepos - next_data_len - sizeof(uint16_t) - sizeof(uint16_t) - sizeof(uint32_t); - break; - } - uint16_t next_parity_len = (next_data_len-1)/8 + 1; - *tracepos += next_parity_len; - } - - *duration = last_timestamp - timestamp; - - return true; -} - - -uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, uint8_t protocol, bool showWaitCycles, bool markCRCBytes) -{ - bool isResponse; - uint16_t data_len, parity_len; - uint32_t duration; - uint8_t topaz_reader_command[9]; - uint32_t timestamp, first_timestamp, EndOfTransmissionTimestamp; - char explanation[30] = {0}; - uint8_t mfData[32] = {0}; - size_t mfDataLen = 0; - - if (tracepos + sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t) > traceLen) return traceLen; - - first_timestamp = *((uint32_t *)(trace)); - timestamp = *((uint32_t *)(trace + tracepos)); - - tracepos += 4; - duration = *((uint16_t *)(trace + tracepos)); - tracepos += 2; - data_len = *((uint16_t *)(trace + tracepos)); - tracepos += 2; - - if (data_len & 0x8000) { - data_len &= 0x7fff; - isResponse = true; - } else { - isResponse = false; - } - parity_len = (data_len-1)/8 + 1; - - if (tracepos + data_len + parity_len > traceLen) { - return traceLen; - } - uint8_t *frame = trace + tracepos; - tracepos += data_len; - uint8_t *parityBytes = trace + tracepos; - tracepos += parity_len; - - if (protocol == TOPAZ && !isResponse) { - // topaz reader commands come in 1 or 9 separate frames with 7 or 8 Bits each. - // merge them: - if (merge_topaz_reader_frames(timestamp, &duration, &tracepos, traceLen, trace, frame, topaz_reader_command, &data_len)) { - frame = topaz_reader_command; - } - } - - //Check the CRC status - uint8_t crcStatus = 2; - - if (data_len > 2) { - switch (protocol) { - case ICLASS: - crcStatus = iclass_CRC_check(isResponse, frame, data_len); - break; - case ISO_14443B: - case TOPAZ: - crcStatus = iso14443B_CRC_check(isResponse, frame, data_len); - break; - case PROTO_MIFARE: - crcStatus = mifare_CRC_check(isResponse, frame, data_len); - break; - case ISO_14443A: - crcStatus = iso14443A_CRC_check(isResponse, frame, data_len); - break; - default: - break; - } - } - //0 CRC-command, CRC not ok - //1 CRC-command, CRC ok - //2 Not crc-command - - //--- Draw the data column - //char line[16][110]; - char line[16][110]; - - for (int j = 0; j < data_len && j/16 < 16; j++) { - - uint8_t parityBits = parityBytes[j>>3]; - if (protocol != ISO_14443B && (isResponse || protocol == ISO_14443A) && (oddparity8(frame[j]) != ((parityBits >> (7-(j&0x0007))) & 0x01))) { - snprintf(line[j/16]+(( j % 16) * 4), 110, " %02x!", frame[j]); - } else { - snprintf(line[j/16]+(( j % 16) * 4), 110, " %02x ", frame[j]); - } - - } - - if (markCRCBytes) { - if(crcStatus == 0 || crcStatus == 1) - {//CRC-command - char *pos1 = line[(data_len-2)/16]+(((data_len-2) % 16) * 4); - (*pos1) = '['; - char *pos2 = line[(data_len)/16]+(((data_len) % 16) * 4); - sprintf(pos2, "%c", ']'); - } - } - - if (data_len == 0) { - sprintf(line[0]," "); - } - - //--- Draw the CRC column - char *crc = (crcStatus == 0 ? "!crc" : (crcStatus == 1 ? " ok " : " ")); - - EndOfTransmissionTimestamp = timestamp + duration; - - if (protocol == PROTO_MIFARE) - annotateMifare(explanation, sizeof(explanation), frame, data_len, parityBytes, parity_len, isResponse); - - if(!isResponse) - { - switch(protocol) { - case ICLASS: annotateIclass(explanation,sizeof(explanation),frame,data_len); break; - case ISO_14443A: annotateIso14443a(explanation,sizeof(explanation),frame,data_len); break; - case ISO_14443B: annotateIso14443b(explanation,sizeof(explanation),frame,data_len); break; - case TOPAZ: annotateTopaz(explanation,sizeof(explanation),frame,data_len); break; - default: break; - } - } - - int num_lines = MIN((data_len - 1)/16 + 1, 16); - for (int j = 0; j < num_lines ; j++) { - if (j == 0) { - PrintAndLog(" %10d | %10d | %s |%-64s | %s| %s", - (timestamp - first_timestamp), - (EndOfTransmissionTimestamp - first_timestamp), - (isResponse ? "Tag" : "Rdr"), - line[j], - (j == num_lines-1) ? crc : " ", - (j == num_lines-1) ? explanation : ""); - } else { - PrintAndLog(" | | |%-64s | %s| %s", - line[j], - (j == num_lines-1) ? crc : " ", - (j == num_lines-1) ? explanation : ""); - } - } - - if (DecodeMifareData(frame, data_len, parityBytes, isResponse, mfData, &mfDataLen)) { - memset(explanation, 0x00, sizeof(explanation)); - if (!isResponse) { - explanation[0] = '>'; - annotateIso14443a(&explanation[1], sizeof(explanation) - 1, mfData, mfDataLen); - } - uint8_t crcc = iso14443A_CRC_check(isResponse, mfData, mfDataLen); - PrintAndLog(" | * | dec |%-64s | %-4s| %s", - sprint_hex(mfData, mfDataLen), - (crcc == 0 ? "!crc" : (crcc == 1 ? " ok " : " ")), - (true) ? explanation : ""); - }; - - if (is_last_record(tracepos, trace, traceLen)) return traceLen; - - if (showWaitCycles && !isResponse && next_record_is_response(tracepos, trace)) { - uint32_t next_timestamp = *((uint32_t *)(trace + tracepos)); - PrintAndLog(" %10d | %10d | %s | fdt (Frame Delay Time): %d", - (EndOfTransmissionTimestamp - first_timestamp), - (next_timestamp - first_timestamp), - " ", - (next_timestamp - EndOfTransmissionTimestamp)); - } - - return tracepos; -} - - -int CmdHFList(const char *Cmd) -{ - #ifdef WITH_SMARTCARD - PrintAndLog("TEST_WITH_SMARTCARD"); - #endif - #ifdef WITH_TEST - PrintAndLog("TEST_WITH_TEST"); - #endif - bool showWaitCycles = false; - bool markCRCBytes = false; - bool loadFromFile = false; - bool saveToFile = false; - char param1 = '\0'; - char param2 = '\0'; - char param3 = '\0'; - char type[40] = {0}; - char filename[FILE_PATH_SIZE] = {0}; - uint8_t protocol = 0; - - // parse command line - int tlen = param_getstr(Cmd, 0, type, sizeof(type)); - if (param_getlength(Cmd, 1) == 1) { - param1 = param_getchar(Cmd, 1); - } else { - param_getstr(Cmd, 1, filename, sizeof(filename)); - } - if (param_getlength(Cmd, 2) == 1) { - param2 = param_getchar(Cmd, 2); - } else if (strlen(filename) == 0) { - param_getstr(Cmd, 2, filename, sizeof(filename)); - } - if (param_getlength(Cmd, 3) == 1) { - param3 = param_getchar(Cmd, 3); - } else if (strlen(filename) == 0) { - param_getstr(Cmd, 3, filename, sizeof(filename)); - } - - // Validate param1 - bool errors = false; - - if(tlen == 0) { - errors = true; - } - - if(param1 == 'h' - || (param1 != 0 && param1 != 'f' && param1 != 'c' && param1 != 'l') - || (param2 != 0 && param2 != 'f' && param2 != 'c' && param2 != 'l') - || (param3 != 0 && param3 != 'f' && param3 != 'c' && param3 != 'l')) { - errors = true; - } - - if(!errors) { - if(strcmp(type, "iclass") == 0) { - protocol = ICLASS; - } else if(strcmp(type, "mf") == 0) { - protocol = PROTO_MIFARE; - } else if(strcmp(type, "14a") == 0) { - protocol = ISO_14443A; - } else if(strcmp(type, "14b") == 0) { - protocol = ISO_14443B; - } else if(strcmp(type,"topaz") == 0) { - protocol = TOPAZ; - } else if(strcmp(type, "7816") == 0) { - protocol = ISO_7816_4; - } else if(strcmp(type,"raw") == 0) { - protocol = -1; //No crc, no annotations - } else if (strcmp(type, "save") == 0) { - saveToFile = true; - } else { - errors = true; - } - } - - if (param1 == 'f' || param2 == 'f' || param3 == 'f') { - showWaitCycles = true; - } - - if (param1 == 'c' || param2 == 'c' || param3 == 'c') { - markCRCBytes = true; - } - - if (param1 == 'l' || param2 == 'l' || param3 == 'l') { - loadFromFile = true; - } - - if ((loadFromFile || saveToFile) && strlen(filename) == 0) { - errors = true; - } - - if (loadFromFile && saveToFile) { - errors = true; - } - - if (errors) { - PrintAndLog("List or save protocol data."); - PrintAndLog("Usage: hf list [f] [c] [l ]"); - PrintAndLog(" hf list save "); - PrintAndLog(" f - show frame delay times as well"); - PrintAndLog(" c - mark CRC bytes"); - PrintAndLog(" l - load data from file instead of trace buffer"); - PrintAndLog(" save - save data to file"); - PrintAndLog("Supported values:"); - PrintAndLog(" raw - just show raw data without annotations"); - PrintAndLog(" 14a - interpret data as iso14443a communications"); - PrintAndLog(" mf - interpret data as iso14443a communications and decrypt crypto1 stream"); - PrintAndLog(" 14b - interpret data as iso14443b communications"); - PrintAndLog(" iclass - interpret data as iclass communications"); - PrintAndLog(" topaz - interpret data as topaz communications"); - PrintAndLog(""); - PrintAndLog("example: hf list 14a f"); - PrintAndLog("example: hf list iclass"); - PrintAndLog("example: hf list save myCardTrace.trc"); - PrintAndLog("example: hf list 14a l myCardTrace.trc"); - return 0; - } - - - uint8_t *trace; - uint32_t tracepos = 0; - uint32_t traceLen = 0; - - if (loadFromFile) { - #define TRACE_CHUNK_SIZE (1<<16) // 64K to start with. Will be enough for BigBuf and some room for future extensions - FILE *tracefile = NULL; - size_t bytes_read; - trace = malloc(TRACE_CHUNK_SIZE); - if (trace == NULL) { - PrintAndLog("Cannot allocate memory for trace"); - return 2; - } - if ((tracefile = fopen(filename,"rb")) == NULL) { - PrintAndLog("Could not open file %s", filename); - free(trace); - return 0; - } - while (!feof(tracefile)) { - bytes_read = fread(trace+traceLen, 1, TRACE_CHUNK_SIZE, tracefile); - traceLen += bytes_read; - if (!feof(tracefile)) { - uint8_t *p = realloc(trace, traceLen + TRACE_CHUNK_SIZE); - if (p == NULL) { - PrintAndLog("Cannot allocate memory for trace"); - free(trace); - fclose(tracefile); - return 2; - } - trace = p; - } - } - fclose(tracefile); - } else { - trace = malloc(USB_CMD_DATA_SIZE); - // Query for the size of the trace - UsbCommand response; - GetFromBigBuf(trace, USB_CMD_DATA_SIZE, 0, &response, -1, false); - traceLen = response.arg[2]; - if (traceLen > USB_CMD_DATA_SIZE) { - uint8_t *p = realloc(trace, traceLen); - if (p == NULL) { - PrintAndLog("Cannot allocate memory for trace"); - free(trace); - return 2; - } - trace = p; - GetFromBigBuf(trace, traceLen, 0, NULL, -1, false); - } - } - - if (saveToFile) { - FILE *tracefile = NULL; - if ((tracefile = fopen(filename,"wb")) == NULL) { - PrintAndLog("Could not create file %s", filename); - return 1; - } - fwrite(trace, 1, traceLen, tracefile); - PrintAndLog("Recorded Activity (TraceLen = %d bytes) written to file %s", traceLen, filename); - fclose(tracefile); - } else { - PrintAndLog("Recorded Activity (TraceLen = %d bytes)", traceLen); - PrintAndLog(""); - PrintAndLog("Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer"); - PrintAndLog("iso14443a - All times are in carrier periods (1/13.56Mhz)"); - PrintAndLog("iClass - Timings are not as accurate"); - PrintAndLog(""); - PrintAndLog(" Start | End | Src | Data (! denotes parity error) | CRC | Annotation |"); - PrintAndLog("------------|------------|-----|-----------------------------------------------------------------|-----|--------------------|"); - - ClearAuthData(); - while(tracepos < traceLen) - { - tracepos = printTraceLine(tracepos, traceLen, trace, protocol, showWaitCycles, markCRCBytes); - } - } - - free(trace); - return 0; -} - int CmdHFSearch(const char *Cmd){ int ans = 0; PrintAndLog(""); diff --git a/client/cmdhf.h b/client/cmdhf.h index 026357b5..ff20a950 100644 --- a/client/cmdhf.h +++ b/client/cmdhf.h @@ -13,5 +13,5 @@ int CmdHF(const char *Cmd); int CmdHFTune(const char *Cmd); -int CmdHFList(const char *Cmd); + #endif diff --git a/client/cmdhflist.c b/client/cmdhflist.c index 5538b6fb..67326c98 100644 --- a/client/cmdhflist.c +++ b/client/cmdhflist.c @@ -1,11 +1,12 @@ //----------------------------------------------------------------------------- +// Copyright (C) 2010 iZsh // Copyright (C) Merlok - 2017 // // 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. //----------------------------------------------------------------------------- -// Command: hf mf list. It shows data from arm buffer. +// Command: hf list. It shows data from arm buffer. //----------------------------------------------------------------------------- #include "cmdhflist.h" @@ -17,13 +18,30 @@ #include #include "util.h" #include "ui.h" +#include "comms.h" #include "iso14443crc.h" +#include "iso15693tools.h" #include "parity.h" #include "protocols.h" #include "crapto1/crapto1.h" #include "mifarehost.h" #include "mifaredefault.h" +#include "usb_cmd.h" +typedef struct { + uint32_t uid; // UID + uint32_t nt; // tag challenge + uint32_t nt_enc; // encrypted tag challenge + uint8_t nt_enc_par; // encrypted tag challenge parity + uint32_t nr_enc; // encrypted reader challenge + uint32_t ar_enc; // encrypted reader response + uint8_t ar_enc_par; // encrypted reader response parity + uint32_t at_enc; // encrypted tag response + uint8_t at_enc_par; // encrypted tag response parity + bool first_auth; // is first authentication + uint32_t ks2; // ar ^ ar_enc + uint32_t ks3; // at ^ at_enc +} TAuthData; enum MifareAuthSeq { masNone, @@ -35,10 +53,11 @@ enum MifareAuthSeq { masData, masError, }; + static enum MifareAuthSeq MifareAuthState; static TAuthData AuthData; -void ClearAuthData() { +static void ClearAuthData() { AuthData.uid = 0; AuthData.nt = 0; AuthData.first_auth = true; @@ -55,7 +74,7 @@ void ClearAuthData() { * 1 : CRC-command, CRC ok * 2 : Not crc-command */ -uint8_t iso14443A_CRC_check(bool isResponse, uint8_t* data, uint8_t len) +static uint8_t iso14443A_CRC_check(bool isResponse, uint8_t* data, uint8_t len) { uint8_t b1,b2; @@ -71,7 +90,8 @@ uint8_t iso14443A_CRC_check(bool isResponse, uint8_t* data, uint8_t len) } } -uint8_t mifare_CRC_check(bool isResponse, uint8_t* data, uint8_t len) + +static uint8_t mifare_CRC_check(bool isResponse, uint8_t* data, uint8_t len) { switch(MifareAuthState) { case masNone: @@ -82,6 +102,101 @@ uint8_t mifare_CRC_check(bool isResponse, uint8_t* data, uint8_t len) } } + +/** + * @brief iso14443B_CRC_check Checks CRC in command or response + * @param isResponse + * @param data + * @param len + * @return 0 : CRC-command, CRC not ok + * 1 : CRC-command, CRC ok + * 2 : Not crc-command + */ +static uint8_t iso14443B_CRC_check(bool isResponse, uint8_t* data, uint8_t len) +{ + uint8_t b1,b2; + + if(len <= 2) return 2; + + ComputeCrc14443(CRC_14443_B, data, len-2, &b1, &b2); + if(b1 != data[len-2] || b2 != data[len-1]) { + return 0; + } else { + return 1; + } +} + + +static uint8_t iso15693_CRC_check(uint8_t* d, uint16_t n) +{ + if (n <= 2) return 2; + + return (Iso15693Crc(d, n) == ISO15693_CRC_CHECK ? 1 : 0); +} + + +/** + * @brief iclass_CRC_Ok Checks CRC in command or response + * @param isResponse + * @param data + * @param len + * @return 0 : CRC-command, CRC not ok + * 1 : CRC-command, CRC ok + * 2 : Not crc-command + */ +uint8_t iclass_CRC_check(bool isResponse, uint8_t* data, uint8_t len) +{ + if(len < 4) return 2;//CRC commands (and responses) are all at least 4 bytes + + uint8_t b1, b2; + + if(!isResponse)//Commands to tag + { + /** + These commands should have CRC. Total length leftmost + 4 READ + 4 READ4 + 12 UPDATE - unsecured, ends with CRC16 + 14 UPDATE - secured, ends with signature instead + 4 PAGESEL + **/ + if(len == 4 || len == 12)//Covers three of them + { + //Don't include the command byte + ComputeCrc14443(CRC_ICLASS, (data+1), len-3, &b1, &b2); + return b1 == data[len -2] && b2 == data[len-1]; + } + return 2; + }else{ + /** + These tag responses should have CRC. Total length leftmost + + 10 READ data[8] crc[2] + 34 READ4 data[32]crc[2] + 10 UPDATE data[8] crc[2] + 10 SELECT csn[8] crc[2] + 10 IDENTIFY asnb[8] crc[2] + 10 PAGESEL block1[8] crc[2] + 10 DETECT csn[8] crc[2] + + These should not + + 4 CHECK chip_response[4] + 8 READCHECK data[8] + 1 ACTALL sof[1] + 1 ACT sof[1] + + In conclusion, without looking at the command; any response + of length 10 or 34 should have CRC + **/ + if(len != 10 && len != 34) return true; + + ComputeCrc14443(CRC_ICLASS, data, len-2, &b1, &b2); + return b1 == data[len -2] && b2 == data[len-1]; + } +} + + void annotateIclass(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) { switch(cmd[0]) @@ -110,36 +225,33 @@ void annotateIclass(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) return; } + void annotateIso15693(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) { - - if(cmd[0] == 0x26) - { - switch(cmd[1]){ - case ISO15693_INVENTORY :snprintf(exp, size, "INVENTORY");break; - case ISO15693_STAYQUIET :snprintf(exp, size, "STAY_QUIET");break; - default: snprintf(exp,size,"?"); break; - - } - }else if(cmd[0] == 0x02) - { - switch(cmd[1]) - { - case ISO15693_READBLOCK :snprintf(exp, size, "READBLOCK");break; - case ISO15693_WRITEBLOCK :snprintf(exp, size, "WRITEBLOCK");break; - case ISO15693_LOCKBLOCK :snprintf(exp, size, "LOCKBLOCK");break; - case ISO15693_READ_MULTI_BLOCK :snprintf(exp, size, "READ_MULTI_BLOCK");break; - case ISO15693_SELECT :snprintf(exp, size, "SELECT");break; - case ISO15693_RESET_TO_READY :snprintf(exp, size, "RESET_TO_READY");break; - case ISO15693_WRITE_AFI :snprintf(exp, size, "WRITE_AFI");break; - case ISO15693_LOCK_AFI :snprintf(exp, size, "LOCK_AFI");break; - case ISO15693_WRITE_DSFID :snprintf(exp, size, "WRITE_DSFID");break; - case ISO15693_LOCK_DSFID :snprintf(exp, size, "LOCK_DSFID");break; - case ISO15693_GET_SYSTEM_INFO :snprintf(exp, size, "GET_SYSTEM_INFO");break; - case ISO15693_READ_MULTI_SECSTATUS :snprintf(exp, size, "READ_MULTI_SECSTATUS");break; - default: snprintf(exp,size,"?"); break; - } + switch(cmd[1]){ + // Mandatory Commands, all Tags must support them: + case ISO15693_INVENTORY :snprintf(exp, size, "INVENTORY");return; + case ISO15693_STAYQUIET :snprintf(exp, size, "STAY_QUIET");return; + // Optional Commands, Tags may support them: + case ISO15693_READBLOCK :snprintf(exp, size, "READBLOCK");return; + case ISO15693_WRITEBLOCK :snprintf(exp, size, "WRITEBLOCK");return; + case ISO15693_LOCKBLOCK :snprintf(exp, size, "LOCKBLOCK");return; + case ISO15693_READ_MULTI_BLOCK :snprintf(exp, size, "READ_MULTI_BLOCK");return; + case ISO15693_SELECT :snprintf(exp, size, "SELECT");return; + case ISO15693_RESET_TO_READY :snprintf(exp, size, "RESET_TO_READY");return; + case ISO15693_WRITE_AFI :snprintf(exp, size, "WRITE_AFI");return; + case ISO15693_LOCK_AFI :snprintf(exp, size, "LOCK_AFI");return; + case ISO15693_WRITE_DSFID :snprintf(exp, size, "WRITE_DSFID");return; + case ISO15693_LOCK_DSFID :snprintf(exp, size, "LOCK_DSFID");return; + case ISO15693_GET_SYSTEM_INFO :snprintf(exp, size, "GET_SYSTEM_INFO");return; + case ISO15693_READ_MULTI_SECSTATUS :snprintf(exp, size, "READ_MULTI_SECSTATUS");return; + default: break; } + + if (cmd[1] > ISO15693_STAYQUIET && cmd[1] < ISO15693_READBLOCK) snprintf(exp, size, "Mandatory RFU"); + else if (cmd[1] > ISO15693_READ_MULTI_SECSTATUS && cmd[1] <= 0x9F) snprintf(exp, size, "Optional RFU"); + else if ( cmd[1] >= 0xA0 && cmd[1] <= 0xDF ) snprintf(exp, size, "Custom command"); + else if ( cmd[1] >= 0xE0 && cmd[1] <= 0xFF ) snprintf(exp, size, "Proprietary command"); } @@ -367,7 +479,103 @@ void annotateMifare(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize, uint8 } -bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isResponse, uint8_t *mfData, size_t *mfDataLen) { + +static uint64_t GetCrypto1ProbableKey(TAuthData *ad) { + struct Crypto1State *revstate = lfsr_recovery64(ad->ks2, ad->ks3); + lfsr_rollback_word(revstate, 0, 0); + lfsr_rollback_word(revstate, 0, 0); + lfsr_rollback_word(revstate, ad->nr_enc, 1); + lfsr_rollback_word(revstate, ad->uid ^ ad->nt, 0); + + uint64_t lfsr = 0; + crypto1_get_lfsr(revstate, &lfsr); + crypto1_destroy(revstate); + + return lfsr; +} + + +static bool NTParityChk(TAuthData *ad, uint32_t ntx) { + if ( + (oddparity8(ntx >> 8 & 0xff) ^ (ntx & 0x01) ^ ((ad->nt_enc_par >> 5) & 0x01) ^ (ad->nt_enc & 0x01)) || + (oddparity8(ntx >> 16 & 0xff) ^ (ntx >> 8 & 0x01) ^ ((ad->nt_enc_par >> 6) & 0x01) ^ (ad->nt_enc >> 8 & 0x01)) || + (oddparity8(ntx >> 24 & 0xff) ^ (ntx >> 16 & 0x01) ^ ((ad->nt_enc_par >> 7) & 0x01) ^ (ad->nt_enc >> 16 & 0x01)) + ) + return false; + + uint32_t ar = prng_successor(ntx, 64); + if ( + (oddparity8(ar >> 8 & 0xff) ^ (ar & 0x01) ^ ((ad->ar_enc_par >> 5) & 0x01) ^ (ad->ar_enc & 0x01)) || + (oddparity8(ar >> 16 & 0xff) ^ (ar >> 8 & 0x01) ^ ((ad->ar_enc_par >> 6) & 0x01) ^ (ad->ar_enc >> 8 & 0x01)) || + (oddparity8(ar >> 24 & 0xff) ^ (ar >> 16 & 0x01) ^ ((ad->ar_enc_par >> 7) & 0x01) ^ (ad->ar_enc >> 16 & 0x01)) + ) + return false; + + uint32_t at = prng_successor(ntx, 96); + if ( + (oddparity8(ar & 0xff) ^ (at >> 24 & 0x01) ^ ((ad->ar_enc_par >> 4) & 0x01) ^ (ad->at_enc >> 24 & 0x01)) || + (oddparity8(at >> 8 & 0xff) ^ (at & 0x01) ^ ((ad->at_enc_par >> 5) & 0x01) ^ (ad->at_enc & 0x01)) || + (oddparity8(at >> 16 & 0xff) ^ (at >> 8 & 0x01) ^ ((ad->at_enc_par >> 6) & 0x01) ^ (ad->at_enc >> 8 & 0x01)) || + (oddparity8(at >> 24 & 0xff) ^ (at >> 16 & 0x01) ^ ((ad->at_enc_par >> 7) & 0x01) ^ (ad->at_enc >> 16 & 0x01)) + ) + return false; + + return true; +} + + +static bool CheckCrypto1Parity(uint8_t *cmd_enc, uint8_t cmdsize, uint8_t *cmd, uint8_t *parity_enc) { + for (int i = 0; i < cmdsize - 1; i++) { + if (oddparity8(cmd[i]) ^ (cmd[i + 1] & 0x01) ^ ((parity_enc[i / 8] >> (7 - i % 8)) & 0x01) ^ (cmd_enc[i + 1] & 0x01)) + return false; + } + + return true; +} + + +static bool NestedCheckKey(uint64_t key, TAuthData *ad, uint8_t *cmd, uint8_t cmdsize, uint8_t *parity) { + uint8_t buf[32] = {0}; + struct Crypto1State *pcs; + + AuthData.ks2 = 0; + AuthData.ks3 = 0; + + pcs = crypto1_create(key); + uint32_t nt1 = crypto1_word(pcs, ad->nt_enc ^ ad->uid, 1) ^ ad->nt_enc; + uint32_t ar = prng_successor(nt1, 64); + uint32_t at = prng_successor(nt1, 96); + + crypto1_word(pcs, ad->nr_enc, 1); +// uint32_t nr1 = crypto1_word(pcs, ad->nr_enc, 1) ^ ad->nr_enc; // if needs deciphered nr + uint32_t ar1 = crypto1_word(pcs, 0, 0) ^ ad->ar_enc; + uint32_t at1 = crypto1_word(pcs, 0, 0) ^ ad->at_enc; + + if (!(ar == ar1 && at == at1 && NTParityChk(ad, nt1))) { + crypto1_destroy(pcs); + return false; + } + + memcpy(buf, cmd, cmdsize); + mf_crypto1_decrypt(pcs, buf, cmdsize, 0); + + crypto1_destroy(pcs); + + if (!CheckCrypto1Parity(cmd, cmdsize, buf, parity)) + return false; + + if(!CheckCrc14443(CRC_14443_A, buf, cmdsize)) + return false; + + AuthData.nt = nt1; + AuthData.ks2 = AuthData.ar_enc ^ ar; + AuthData.ks3 = AuthData.at_enc ^ at; + + return true; +} + + +static bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isResponse, uint8_t *mfData, size_t *mfDataLen) { static struct Crypto1State *traceCrypto1; static uint64_t mfLastKey; @@ -514,93 +722,415 @@ bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isRes return *mfDataLen > 0; } -bool NTParityChk(TAuthData *ad, uint32_t ntx) { - if ( - (oddparity8(ntx >> 8 & 0xff) ^ (ntx & 0x01) ^ ((ad->nt_enc_par >> 5) & 0x01) ^ (ad->nt_enc & 0x01)) || - (oddparity8(ntx >> 16 & 0xff) ^ (ntx >> 8 & 0x01) ^ ((ad->nt_enc_par >> 6) & 0x01) ^ (ad->nt_enc >> 8 & 0x01)) || - (oddparity8(ntx >> 24 & 0xff) ^ (ntx >> 16 & 0x01) ^ ((ad->nt_enc_par >> 7) & 0x01) ^ (ad->nt_enc >> 16 & 0x01)) - ) - return false; - - uint32_t ar = prng_successor(ntx, 64); - if ( - (oddparity8(ar >> 8 & 0xff) ^ (ar & 0x01) ^ ((ad->ar_enc_par >> 5) & 0x01) ^ (ad->ar_enc & 0x01)) || - (oddparity8(ar >> 16 & 0xff) ^ (ar >> 8 & 0x01) ^ ((ad->ar_enc_par >> 6) & 0x01) ^ (ad->ar_enc >> 8 & 0x01)) || - (oddparity8(ar >> 24 & 0xff) ^ (ar >> 16 & 0x01) ^ ((ad->ar_enc_par >> 7) & 0x01) ^ (ad->ar_enc >> 16 & 0x01)) - ) - return false; - uint32_t at = prng_successor(ntx, 96); - if ( - (oddparity8(ar & 0xff) ^ (at >> 24 & 0x01) ^ ((ad->ar_enc_par >> 4) & 0x01) ^ (ad->at_enc >> 24 & 0x01)) || - (oddparity8(at >> 8 & 0xff) ^ (at & 0x01) ^ ((ad->at_enc_par >> 5) & 0x01) ^ (ad->at_enc & 0x01)) || - (oddparity8(at >> 16 & 0xff) ^ (at >> 8 & 0x01) ^ ((ad->at_enc_par >> 6) & 0x01) ^ (ad->at_enc >> 8 & 0x01)) || - (oddparity8(at >> 24 & 0xff) ^ (at >> 16 & 0x01) ^ ((ad->at_enc_par >> 7) & 0x01) ^ (ad->at_enc >> 16 & 0x01)) - ) - return false; - - return true; +bool is_last_record(uint16_t tracepos, uint8_t *trace, uint16_t traceLen) +{ + return(tracepos + sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t) >= traceLen); } -bool NestedCheckKey(uint64_t key, TAuthData *ad, uint8_t *cmd, uint8_t cmdsize, uint8_t *parity) { - uint8_t buf[32] = {0}; - struct Crypto1State *pcs; + +bool next_record_is_response(uint16_t tracepos, uint8_t *trace) +{ + uint16_t next_records_datalen = *((uint16_t *)(trace + tracepos + sizeof(uint32_t) + sizeof(uint16_t))); - AuthData.ks2 = 0; - AuthData.ks3 = 0; + return(next_records_datalen & 0x8000); +} - pcs = crypto1_create(key); - uint32_t nt1 = crypto1_word(pcs, ad->nt_enc ^ ad->uid, 1) ^ ad->nt_enc; - uint32_t ar = prng_successor(nt1, 64); - uint32_t at = prng_successor(nt1, 96); - crypto1_word(pcs, ad->nr_enc, 1); -// uint32_t nr1 = crypto1_word(pcs, ad->nr_enc, 1) ^ ad->nr_enc; // if needs deciphered nr - uint32_t ar1 = crypto1_word(pcs, 0, 0) ^ ad->ar_enc; - uint32_t at1 = crypto1_word(pcs, 0, 0) ^ ad->at_enc; +bool merge_topaz_reader_frames(uint32_t timestamp, uint32_t *duration, uint16_t *tracepos, uint16_t traceLen, uint8_t *trace, uint8_t *frame, uint8_t *topaz_reader_command, uint16_t *data_len) +{ - if (!(ar == ar1 && at == at1 && NTParityChk(ad, nt1))) { - crypto1_destroy(pcs); - return false; +#define MAX_TOPAZ_READER_CMD_LEN 16 + + uint32_t last_timestamp = timestamp + *duration; + + if ((*data_len != 1) || (frame[0] == TOPAZ_WUPA) || (frame[0] == TOPAZ_REQA)) return false; + + memcpy(topaz_reader_command, frame, *data_len); + + while (!is_last_record(*tracepos, trace, traceLen) && !next_record_is_response(*tracepos, trace)) { + uint32_t next_timestamp = *((uint32_t *)(trace + *tracepos)); + *tracepos += sizeof(uint32_t); + uint16_t next_duration = *((uint16_t *)(trace + *tracepos)); + *tracepos += sizeof(uint16_t); + uint16_t next_data_len = *((uint16_t *)(trace + *tracepos)) & 0x7FFF; + *tracepos += sizeof(uint16_t); + uint8_t *next_frame = (trace + *tracepos); + *tracepos += next_data_len; + if ((next_data_len == 1) && (*data_len + next_data_len <= MAX_TOPAZ_READER_CMD_LEN)) { + memcpy(topaz_reader_command + *data_len, next_frame, next_data_len); + *data_len += next_data_len; + last_timestamp = next_timestamp + next_duration; + } else { + // rewind and exit + *tracepos = *tracepos - next_data_len - sizeof(uint16_t) - sizeof(uint16_t) - sizeof(uint32_t); + break; + } + uint16_t next_parity_len = (next_data_len-1)/8 + 1; + *tracepos += next_parity_len; } - memcpy(buf, cmd, cmdsize); - mf_crypto1_decrypt(pcs, buf, cmdsize, 0); + *duration = last_timestamp - timestamp; - crypto1_destroy(pcs); - - if (!CheckCrypto1Parity(cmd, cmdsize, buf, parity)) - return false; - - if(!CheckCrc14443(CRC_14443_A, buf, cmdsize)) - return false; - - AuthData.nt = nt1; - AuthData.ks2 = AuthData.ar_enc ^ ar; - AuthData.ks3 = AuthData.at_enc ^ at; - return true; } -bool CheckCrypto1Parity(uint8_t *cmd_enc, uint8_t cmdsize, uint8_t *cmd, uint8_t *parity_enc) { - for (int i = 0; i < cmdsize - 1; i++) { - if (oddparity8(cmd[i]) ^ (cmd[i + 1] & 0x01) ^ ((parity_enc[i / 8] >> (7 - i % 8)) & 0x01) ^ (cmd_enc[i + 1] & 0x01)) - return false; + +uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, uint8_t protocol, bool showWaitCycles, bool markCRCBytes) +{ + bool isResponse; + uint16_t data_len, parity_len; + uint32_t duration; + uint8_t topaz_reader_command[9]; + uint32_t timestamp, first_timestamp, EndOfTransmissionTimestamp; + char explanation[30] = {0}; + uint8_t mfData[32] = {0}; + size_t mfDataLen = 0; + + if (tracepos + sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t) > traceLen) return traceLen; + + first_timestamp = *((uint32_t *)(trace)); + timestamp = *((uint32_t *)(trace + tracepos)); + + tracepos += 4; + duration = *((uint16_t *)(trace + tracepos)); + tracepos += 2; + data_len = *((uint16_t *)(trace + tracepos)); + tracepos += 2; + + if (data_len & 0x8000) { + data_len &= 0x7fff; + isResponse = true; + } else { + isResponse = false; + } + parity_len = (data_len-1)/8 + 1; + + if (tracepos + data_len + parity_len > traceLen) { + return traceLen; + } + uint8_t *frame = trace + tracepos; + tracepos += data_len; + uint8_t *parityBytes = trace + tracepos; + tracepos += parity_len; + + if (protocol == TOPAZ && !isResponse) { + // topaz reader commands come in 1 or 9 separate frames with 7 or 8 Bits each. + // merge them: + if (merge_topaz_reader_frames(timestamp, &duration, &tracepos, traceLen, trace, frame, topaz_reader_command, &data_len)) { + frame = topaz_reader_command; + } } - return true; -} + //Check the CRC status + uint8_t crcStatus = 2; -uint64_t GetCrypto1ProbableKey(TAuthData *ad) { - struct Crypto1State *revstate = lfsr_recovery64(ad->ks2, ad->ks3); - lfsr_rollback_word(revstate, 0, 0); - lfsr_rollback_word(revstate, 0, 0); - lfsr_rollback_word(revstate, ad->nr_enc, 1); - lfsr_rollback_word(revstate, ad->uid ^ ad->nt, 0); + if (data_len > 2) { + switch (protocol) { + case ICLASS: + crcStatus = iclass_CRC_check(isResponse, frame, data_len); + break; + case ISO_14443B: + case TOPAZ: + crcStatus = iso14443B_CRC_check(isResponse, frame, data_len); + break; + case PROTO_MIFARE: + crcStatus = mifare_CRC_check(isResponse, frame, data_len); + break; + case ISO_14443A: + crcStatus = iso14443A_CRC_check(isResponse, frame, data_len); + break; + case ISO_15693: + crcStatus = iso15693_CRC_check(frame, data_len); + break; + default: + break; + } + } + //0 CRC-command, CRC not ok + //1 CRC-command, CRC ok + //2 Not crc-command - uint64_t lfsr = 0; - crypto1_get_lfsr(revstate, &lfsr); - crypto1_destroy(revstate); + //--- Draw the data column + //char line[16][110]; + char line[16][110]; + + for (int j = 0; j < data_len && j/16 < 16; j++) { + + uint8_t parityBits = parityBytes[j>>3]; + if (protocol != ISO_14443B + && protocol != ISO_15693 + && protocol != ISO_7816_4 + && (isResponse || protocol == ISO_14443A) + && (oddparity8(frame[j]) != ((parityBits >> (7-(j&0x0007))) & 0x01))) { + snprintf(line[j/16]+(( j % 16) * 4), 110, " %02x!", frame[j]); + } else { + snprintf(line[j/16]+(( j % 16) * 4), 110, " %02x ", frame[j]); + } + + } + + if (markCRCBytes) { + if(crcStatus == 0 || crcStatus == 1) + {//CRC-command + char *pos1 = line[(data_len-2)/16]+(((data_len-2) % 16) * 4); + (*pos1) = '['; + char *pos2 = line[(data_len)/16]+(((data_len) % 16) * 4); + sprintf(pos2, "%c", ']'); + } + } + + if (data_len == 0) { + sprintf(line[0]," "); + } + + //--- Draw the CRC column + char *crc = (crcStatus == 0 ? "!crc" : (crcStatus == 1 ? " ok " : " ")); + + EndOfTransmissionTimestamp = timestamp + duration; + + if (protocol == PROTO_MIFARE) + annotateMifare(explanation, sizeof(explanation), frame, data_len, parityBytes, parity_len, isResponse); - return lfsr; + if(!isResponse) + { + switch(protocol) { + case ICLASS: annotateIclass(explanation,sizeof(explanation),frame,data_len); break; + case ISO_14443A: annotateIso14443a(explanation,sizeof(explanation),frame,data_len); break; + case ISO_14443B: annotateIso14443b(explanation,sizeof(explanation),frame,data_len); break; + case TOPAZ: annotateTopaz(explanation,sizeof(explanation),frame,data_len); break; + case ISO_15693: annotateIso15693(explanation,sizeof(explanation),frame,data_len); break; + default: break; + } + } + + int num_lines = MIN((data_len - 1)/16 + 1, 16); + for (int j = 0; j < num_lines ; j++) { + if (j == 0) { + PrintAndLog(" %10d | %10d | %s |%-64s | %s| %s", + (timestamp - first_timestamp), + (EndOfTransmissionTimestamp - first_timestamp), + (isResponse ? "Tag" : "Rdr"), + line[j], + (j == num_lines-1) ? crc : " ", + (j == num_lines-1) ? explanation : ""); + } else { + PrintAndLog(" | | |%-64s | %s| %s", + line[j], + (j == num_lines-1) ? crc : " ", + (j == num_lines-1) ? explanation : ""); + } + } + + if (DecodeMifareData(frame, data_len, parityBytes, isResponse, mfData, &mfDataLen)) { + memset(explanation, 0x00, sizeof(explanation)); + if (!isResponse) { + explanation[0] = '>'; + annotateIso14443a(&explanation[1], sizeof(explanation) - 1, mfData, mfDataLen); + } + uint8_t crcc = iso14443A_CRC_check(isResponse, mfData, mfDataLen); + PrintAndLog(" | * | dec |%-64s | %-4s| %s", + sprint_hex(mfData, mfDataLen), + (crcc == 0 ? "!crc" : (crcc == 1 ? " ok " : " ")), + (true) ? explanation : ""); + }; + + if (is_last_record(tracepos, trace, traceLen)) return traceLen; + + if (showWaitCycles && !isResponse && next_record_is_response(tracepos, trace)) { + uint32_t next_timestamp = *((uint32_t *)(trace + tracepos)); + PrintAndLog(" %10d | %10d | %s | fdt (Frame Delay Time): %d", + (EndOfTransmissionTimestamp - first_timestamp), + (next_timestamp - first_timestamp), + " ", + (next_timestamp - EndOfTransmissionTimestamp)); + } + + return tracepos; } + + +int CmdHFList(const char *Cmd) +{ + bool showWaitCycles = false; + bool markCRCBytes = false; + bool loadFromFile = false; + bool saveToFile = false; + char param1 = '\0'; + char param2 = '\0'; + char param3 = '\0'; + char type[40] = {0}; + char filename[FILE_PATH_SIZE] = {0}; + uint8_t protocol = 0; + + // parse command line + int tlen = param_getstr(Cmd, 0, type, sizeof(type)); + if (param_getlength(Cmd, 1) == 1) { + param1 = param_getchar(Cmd, 1); + } else { + param_getstr(Cmd, 1, filename, sizeof(filename)); + } + if (param_getlength(Cmd, 2) == 1) { + param2 = param_getchar(Cmd, 2); + } else if (strlen(filename) == 0) { + param_getstr(Cmd, 2, filename, sizeof(filename)); + } + if (param_getlength(Cmd, 3) == 1) { + param3 = param_getchar(Cmd, 3); + } else if (strlen(filename) == 0) { + param_getstr(Cmd, 3, filename, sizeof(filename)); + } + + // Validate param1 + bool errors = false; + + if(tlen == 0) { + errors = true; + } + + if(param1 == 'h' + || (param1 != 0 && param1 != 'f' && param1 != 'c' && param1 != 'l') + || (param2 != 0 && param2 != 'f' && param2 != 'c' && param2 != 'l') + || (param3 != 0 && param3 != 'f' && param3 != 'c' && param3 != 'l')) { + errors = true; + } + + if(!errors) { + if (strcmp(type, "iclass") == 0) protocol = ICLASS; + else if(strcmp(type, "14a") == 0) protocol = ISO_14443A; + else if(strcmp(type, "mf") == 0) protocol = PROTO_MIFARE; + else if(strcmp(type, "14b") == 0) protocol = ISO_14443B; + else if(strcmp(type, "topaz") == 0) protocol = TOPAZ; + else if(strcmp(type, "7816") == 0) protocol = ISO_7816_4; + else if(strcmp(type, "15") == 0) protocol = ISO_15693; + else if(strcmp(type, "raw") == 0) protocol = -1;//No crc, no annotations + else if (strcmp(type, "save") == 0) saveToFile = true; + else errors = true; + } + + if (param1 == 'f' || param2 == 'f' || param3 == 'f') { + showWaitCycles = true; + } + + if (param1 == 'c' || param2 == 'c' || param3 == 'c') { + markCRCBytes = true; + } + + if (param1 == 'l' || param2 == 'l' || param3 == 'l') { + loadFromFile = true; + } + + if ((loadFromFile || saveToFile) && strlen(filename) == 0) { + errors = true; + } + + if (loadFromFile && saveToFile) { + errors = true; + } + + if (errors) { + PrintAndLog("List or save protocol data."); + PrintAndLog("Usage: hf list [f] [c] [l ]"); + PrintAndLog(" hf list save "); + PrintAndLog(" f - show frame delay times as well"); + PrintAndLog(" c - mark CRC bytes"); + PrintAndLog(" l - load data from file instead of trace buffer"); + PrintAndLog(" save - save data to file"); + PrintAndLog("Supported values:"); + PrintAndLog(" raw - just show raw data without annotations"); + PrintAndLog(" 14a - interpret data as iso14443a communications"); + PrintAndLog(" mf - interpret data as iso14443a communications and decrypt crypto1 stream"); + PrintAndLog(" 14b - interpret data as iso14443b communications"); + PrintAndLog(" 15 - interpret data as iso15693 communications"); + PrintAndLog(" iclass - interpret data as iclass communications"); + PrintAndLog(" topaz - interpret data as topaz communications"); + PrintAndLog(""); + PrintAndLog("example: hf list 14a f"); + PrintAndLog("example: hf list iclass"); + PrintAndLog("example: hf list save myCardTrace.trc"); + PrintAndLog("example: hf list 14a l myCardTrace.trc"); + return 0; + } + + + uint8_t *trace; + uint32_t tracepos = 0; + uint32_t traceLen = 0; + + if (loadFromFile) { + #define TRACE_CHUNK_SIZE (1<<16) // 64K to start with. Will be enough for BigBuf and some room for future extensions + FILE *tracefile = NULL; + size_t bytes_read; + trace = malloc(TRACE_CHUNK_SIZE); + if (trace == NULL) { + PrintAndLog("Cannot allocate memory for trace"); + return 2; + } + if ((tracefile = fopen(filename,"rb")) == NULL) { + PrintAndLog("Could not open file %s", filename); + free(trace); + return 0; + } + while (!feof(tracefile)) { + bytes_read = fread(trace+traceLen, 1, TRACE_CHUNK_SIZE, tracefile); + traceLen += bytes_read; + if (!feof(tracefile)) { + uint8_t *p = realloc(trace, traceLen + TRACE_CHUNK_SIZE); + if (p == NULL) { + PrintAndLog("Cannot allocate memory for trace"); + free(trace); + fclose(tracefile); + return 2; + } + trace = p; + } + } + fclose(tracefile); + } else { + trace = malloc(USB_CMD_DATA_SIZE); + // Query for the size of the trace + UsbCommand response; + GetFromBigBuf(trace, USB_CMD_DATA_SIZE, 0, &response, -1, false); + traceLen = response.arg[2]; + if (traceLen > USB_CMD_DATA_SIZE) { + uint8_t *p = realloc(trace, traceLen); + if (p == NULL) { + PrintAndLog("Cannot allocate memory for trace"); + free(trace); + return 2; + } + trace = p; + GetFromBigBuf(trace, traceLen, 0, NULL, -1, false); + } + } + + if (saveToFile) { + FILE *tracefile = NULL; + if ((tracefile = fopen(filename,"wb")) == NULL) { + PrintAndLog("Could not create file %s", filename); + return 1; + } + fwrite(trace, 1, traceLen, tracefile); + PrintAndLog("Recorded Activity (TraceLen = %d bytes) written to file %s", traceLen, filename); + fclose(tracefile); + } else { + PrintAndLog("Recorded Activity (TraceLen = %d bytes)", traceLen); + PrintAndLog(""); + PrintAndLog("Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer"); + PrintAndLog("iso14443a - All times are in carrier periods (1/13.56Mhz)"); + PrintAndLog("iClass - Timings are not as accurate"); + PrintAndLog(""); + PrintAndLog(" Start | End | Src | Data (! denotes parity error) | CRC | Annotation |"); + PrintAndLog("------------|------------|-----|-----------------------------------------------------------------|-----|--------------------|"); + + ClearAuthData(); + while(tracepos < traceLen) + { + tracepos = printTraceLine(tracepos, traceLen, trace, protocol, showWaitCycles, markCRCBytes); + } + } + + free(trace); + return 0; +} + diff --git a/client/cmdhflist.h b/client/cmdhflist.h index 8f289b48..3187440f 100644 --- a/client/cmdhflist.h +++ b/client/cmdhflist.h @@ -1,4 +1,5 @@ //----------------------------------------------------------------------------- +// Copyright (C) 2010 iZsh // Copyright (C) Merlok - 2017 // // This code is licensed to you under the terms of the GNU GPL, version 2 or, @@ -10,38 +11,6 @@ #ifndef CMDHFLIST_H #define CMDHFLIST_H -#include -#include -#include +extern int CmdHFList(const char *Cmd); -typedef struct { - uint32_t uid; // UID - uint32_t nt; // tag challenge - uint32_t nt_enc; // encrypted tag challenge - uint8_t nt_enc_par; // encrypted tag challenge parity - uint32_t nr_enc; // encrypted reader challenge - uint32_t ar_enc; // encrypted reader response - uint8_t ar_enc_par; // encrypted reader response parity - uint32_t at_enc; // encrypted tag response - uint8_t at_enc_par; // encrypted tag response parity - bool first_auth; // is first authentication - uint32_t ks2; // ar ^ ar_enc - uint32_t ks3; // at ^ at_enc -} TAuthData; -extern void ClearAuthData(); - -extern uint8_t iso14443A_CRC_check(bool isResponse, uint8_t* data, uint8_t len); -extern uint8_t mifare_CRC_check(bool isResponse, uint8_t* data, uint8_t len); -extern void annotateIclass(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize); -extern void annotateIso15693(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize); -extern void annotateTopaz(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize); -extern void annotateIso14443b(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize); -extern void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize); -extern void annotateMifare(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize, uint8_t* parity, uint8_t paritysize, bool isResponse); -extern bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isResponse, uint8_t *mfData, size_t *mfDataLen); -extern bool NTParityChk(TAuthData *ad, uint32_t ntx); -extern bool NestedCheckKey(uint64_t key, TAuthData *ad, uint8_t *cmd, uint8_t cmdsize, uint8_t *parity); -extern bool CheckCrypto1Parity(uint8_t *cmd_enc, uint8_t cmdsize, uint8_t *cmd, uint8_t *parity_enc); -extern uint64_t GetCrypto1ProbableKey(TAuthData *ad); - -#endif // CMDHFLIST +#endif // CMDHFLIST_H diff --git a/client/cmdsmartcard.c b/client/cmdsmartcard.c index 8f3d8d2e..d5b9c287 100644 --- a/client/cmdsmartcard.c +++ b/client/cmdsmartcard.c @@ -18,7 +18,7 @@ #include "smartcard.h" #include "comms.h" #include "protocols.h" -#include "cmdhf.h" // CmdHFlist +#include "cmdhflist.h" #include "emv/apduinfo.h" // APDUcode description #include "emv/emvcore.h" // decodeTVL #include "crypto/libpcrypto.h" // sha512hash diff --git a/common/protocols.h b/common/protocols.h index 79d8e083..82b69f9d 100644 --- a/common/protocols.h +++ b/common/protocols.h @@ -234,6 +234,8 @@ NXP/Philips CUSTOM COMMANDS #define TOPAZ 3 #define PROTO_MIFARE 4 #define ISO_7816_4 5 +#define ISO_15693 6 + //-- Picopass fuses #define FUSE_FPERS 0x80 From 151a33c02724869911f22ed6b1db502404fb8f0c Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Thu, 17 Jan 2019 07:50:01 +0100 Subject: [PATCH 050/189] Add smartcard protocol T=0 (RRG repository PRs 71,72,74,75 by @merlokk) (#757) --- armsrc/i2c.c | 6 +- armsrc/i2c.h | 2 + client/cmdsmartcard.c | 207 +++++++++++++------------- client/emv/emvcore.c | 335 +++++++++++++++++++++--------------------- include/smartcard.h | 3 +- 5 files changed, 283 insertions(+), 270 deletions(-) diff --git a/armsrc/i2c.c b/armsrc/i2c.c index bd22e19a..0560d306 100644 --- a/armsrc/i2c.c +++ b/armsrc/i2c.c @@ -713,7 +713,7 @@ void SmartCardRaw( uint64_t arg0, uint64_t arg1, uint8_t *data ) { I2C_Reset_EnterMainProgram(); - if (flags & SC_SELECT) { + if ((flags & SC_SELECT)) { smart_card_atr_t card; bool gotATR = GetATR( &card ); //cmd_send(CMD_ACK, gotATR, sizeof(smart_card_atr_t), 0, &card, sizeof(smart_card_atr_t)); @@ -722,14 +722,14 @@ void SmartCardRaw( uint64_t arg0, uint64_t arg1, uint8_t *data ) { } } - if ((flags & SC_RAW)) { + if ((flags & SC_RAW) || (flags & SC_RAW_T0)) { LogTrace(data, arg1, 0, 0, NULL, true); // Send raw bytes // asBytes = A0 A4 00 00 02 // arg1 = len 5 - bool res = I2C_BufferWrite(data, arg1, I2C_DEVICE_CMD_SEND, I2C_DEVICE_ADDRESS_MAIN); + bool res = I2C_BufferWrite(data, arg1, ((flags & SC_RAW_T0) ? I2C_DEVICE_CMD_SEND_T0 : I2C_DEVICE_CMD_SEND), I2C_DEVICE_ADDRESS_MAIN); if ( !res && MF_DBGLEVEL > 3 ) DbpString(I2C_ERROR); // read bytes from module diff --git a/armsrc/i2c.h b/armsrc/i2c.h index a10ac74f..df66adef 100644 --- a/armsrc/i2c.h +++ b/armsrc/i2c.h @@ -23,6 +23,8 @@ #define I2C_DEVICE_CMD_SETBAUD 0x04 #define I2C_DEVICE_CMD_SIM_CLC 0x05 #define I2C_DEVICE_CMD_GETVERSION 0x06 +#define I2C_DEVICE_CMD_SEND_T0 0x07 + bool I2C_is_available(void); diff --git a/client/cmdsmartcard.c b/client/cmdsmartcard.c index d5b9c287..2eed6d3d 100644 --- a/client/cmdsmartcard.c +++ b/client/cmdsmartcard.c @@ -21,7 +21,7 @@ #include "cmdhflist.h" #include "emv/apduinfo.h" // APDUcode description #include "emv/emvcore.h" // decodeTVL -#include "crypto/libpcrypto.h" // sha512hash +#include "crypto/libpcrypto.h" // sha512hash #include "emv/dump.h" // dump_buffer #define SC_UPGRADE_FILES_DIRECTORY "sc_upgrade_firmware/" @@ -32,14 +32,15 @@ static int usage_sm_raw(void) { PrintAndLogEx(NORMAL, "Usage: sc raw [h|r|c] d <0A 0B 0C ... hex>"); PrintAndLogEx(NORMAL, " h : this help"); PrintAndLogEx(NORMAL, " r : do not read response"); - PrintAndLogEx(NORMAL, " a : active smartcard without select"); - PrintAndLogEx(NORMAL, " s : active smartcard with select"); + PrintAndLogEx(NORMAL, " a : active smartcard without select (reset sc module)"); + PrintAndLogEx(NORMAL, " s : active smartcard with select (get ATR)"); PrintAndLogEx(NORMAL, " t : executes TLV decoder if it possible"); + PrintAndLogEx(NORMAL, " 0 : use protocol T=0"); PrintAndLogEx(NORMAL, " d : bytes to send"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " sc raw d 00a404000e315041592e5359532e444446303100 - `1PAY.SYS.DDF01` PPSE directory"); - PrintAndLogEx(NORMAL, " sc raw d 00a404000e325041592e5359532e444446303100 - `2PAY.SYS.DDF01` PPSE directory"); + PrintAndLogEx(NORMAL, " sc raw s 0 d 00a404000e315041592e5359532e4444463031 - `1PAY.SYS.DDF01` PPSE directory with get ATR"); + PrintAndLogEx(NORMAL, " sc raw 0 d 00a404000e325041592e5359532e4444463031 - `2PAY.SYS.DDF01` PPSE directory"); return 0; } @@ -180,58 +181,46 @@ float GetATRF(uint8_t *atr, size_t atrlen) { } static int PrintATR(uint8_t *atr, size_t atrlen) { - uint8_t vxor = 0; - for (int i = 1; i < atrlen; i++) - vxor ^= atr[i]; - - if (vxor) - PrintAndLogEx(WARNING, "Check summ error. Must be 0 but: 0x%02x", vxor); - else - PrintAndLogEx(INFO, "Check summ OK."); - - if (atr[0] != 0x3b) - PrintAndLogEx(WARNING, "Not a direct convention: 0x%02x", atr[0]); uint8_t T0 = atr[1]; uint8_t K = T0 & 0x0F; - uint8_t TD1 = 0; - - uint8_t T1len = 0; - uint8_t TD1len = 0; - uint8_t TDilen = 0; + uint8_t TD1 = 0, T1len = 0, TD1len = 0, TDilen = 0; if (T0 & 0x10) { - PrintAndLog("TA1 (Maximum clock frequency, proposed bit duration): 0x%02x", atr[2 + T1len]); + PrintAndLog("\t- TA1 (Maximum clock frequency, proposed bit duration) [ 0x%02x ]", atr[2 + T1len]); T1len++; } + if (T0 & 0x20) { - PrintAndLog("TB1 (Deprecated: VPP requirements): 0x%02x", atr[2 + T1len]); + PrintAndLog("\t- TB1 (Deprecated: VPP requirements) [ 0x%02x ]", atr[2 + T1len]); T1len++; } + if (T0 & 0x40) { - PrintAndLog("TC1 (Extra delay between bytes required by card): 0x%02x", atr[2 + T1len]); + PrintAndLog("\t- TC1 (Extra delay between bytes required by card) [ 0x%02x ]", atr[2 + T1len]); T1len++; } + if (T0 & 0x80) { TD1 = atr[2 + T1len]; - PrintAndLog("TD1 (First offered transmission protocol, presence of TA2..TD2): 0x%02x. Protocol T=%d", TD1, TD1 & 0x0f); + PrintAndLog("\t- TD1 (First offered transmission protocol, presence of TA2..TD2) [ 0x%02x ] Protocol T%d", TD1, TD1 & 0x0f); T1len++; if (TD1 & 0x10) { - PrintAndLog("TA2 (Specific protocol and parameters to be used after the ATR): 0x%02x", atr[2 + T1len + TD1len]); + PrintAndLog("\t- TA2 (Specific protocol and parameters to be used after the ATR) [ 0x%02x ]", atr[2 + T1len + TD1len]); TD1len++; } if (TD1 & 0x20) { - PrintAndLog("TB2 (Deprecated: VPP precise voltage requirement): 0x%02x", atr[2 + T1len + TD1len]); + PrintAndLog("\t- TB2 (Deprecated: VPP precise voltage requirement) [ 0x%02x ]", atr[2 + T1len + TD1len]); TD1len++; } if (TD1 & 0x40) { - PrintAndLog("TC2 (Maximum waiting time for protocol T=0): 0x%02x", atr[2 + T1len + TD1len]); + PrintAndLog("\t- TC2 (Maximum waiting time for protocol T=0) [ 0x%02x ]", atr[2 + T1len + TD1len]); TD1len++; } if (TD1 & 0x80) { uint8_t TDi = atr[2 + T1len + TD1len]; - PrintAndLog("TD2 (A supported protocol or more global parameters, presence of TA3..TD3): 0x%02x. Protocol T=%d", TDi, TDi & 0x0f); + PrintAndLog("\t- TD2 (A supported protocol or more global parameters, presence of TA3..TD3) [ 0x%02x ] Protocol T%d", TDi, TDi & 0x0f); TD1len++; bool nextCycle = true; @@ -239,20 +228,20 @@ static int PrintATR(uint8_t *atr, size_t atrlen) { while (nextCycle) { nextCycle = false; if (TDi & 0x10) { - PrintAndLog("TA%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]); + PrintAndLog("\t- TA%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]); TDilen++; } if (TDi & 0x20) { - PrintAndLog("TB%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]); + PrintAndLog("\t- TB%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]); TDilen++; } if (TDi & 0x40) { - PrintAndLog("TC%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]); + PrintAndLog("\t- TC%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]); TDilen++; } if (TDi & 0x80) { TDi = atr[2 + T1len + TD1len + TDilen]; - PrintAndLog("TD%d: 0x%02x. Protocol T=%d", vi, TDi, TDi & 0x0f); + PrintAndLog("\t- TD%d [ 0x%02x ] Protocol T%d", vi, TDi, TDi & 0x0f); TDilen++; nextCycle = true; @@ -262,25 +251,35 @@ static int PrintATR(uint8_t *atr, size_t atrlen) { } } + uint8_t vxor = 0; + for (int i = 1; i < atrlen; i++) + vxor ^= atr[i]; + + if (vxor) + PrintAndLogEx(WARNING, "Check summ error. Must be 0 got 0x%02X", vxor); + else + PrintAndLogEx(INFO, "Check summ OK."); + + if (atr[0] != 0x3b) + PrintAndLogEx(WARNING, "Not a direct convention [ 0x%02x ]", atr[0]); + + uint8_t calen = 2 + T1len + TD1len + TDilen + K; if (atrlen != calen && atrlen != calen + 1) // may be CRC PrintAndLogEx(ERR, "ATR length error. len: %d, T1len: %d, TD1len: %d, TDilen: %d, K: %d", atrlen, T1len, TD1len, TDilen, K); - else - PrintAndLogEx(INFO, "ATR length OK."); - PrintAndLog("Historical bytes len: 0x%02x", K); if (K > 0) - PrintAndLog("The format of historical bytes: %02x", atr[2 + T1len + TD1len + TDilen]); + PrintAndLogEx(INFO, "\nHistorical bytes | len 0x%02d | format %02x", K, atr[2 + T1len + TD1len + TDilen]); + if (K > 1) { - PrintAndLog("Historical bytes:"); + PrintAndLogEx(INFO, "\tHistorical bytes"); dump_buffer(&atr[2 + T1len + TD1len + TDilen], K, NULL, 1); } return 0; } - static bool smart_select(bool silent) { UsbCommand c = {CMD_SMART_ATR, {0, 0, 0}}; clearCommandBuffer(); @@ -310,7 +309,7 @@ static bool smart_select(bool silent) { static int smart_wait(uint8_t *data) { UsbCommand resp; if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) { - PrintAndLogEx(WARNING, "smart card response failed"); + PrintAndLogEx(WARNING, "smart card response timeout"); return -1; } @@ -320,16 +319,17 @@ static int smart_wait(uint8_t *data) { return -2; } memcpy(data, resp.d.asBytes, len); - PrintAndLogEx(SUCCESS, " %d | %s", len, sprint_hex_inrow_ex(data, len, 32)); - if (len >= 2) { PrintAndLogEx(SUCCESS, "%02X%02X | %s", data[len - 2], data[len - 1], GetAPDUCodeDescription(data[len - 2], data[len - 1])); + } else { + PrintAndLogEx(SUCCESS, " %d | %s", len, sprint_hex_inrow_ex(data, len, 8)); } + return len; } -static int smart_response(uint8_t apduINS, uint8_t *data) { - +static int smart_response(uint8_t *data) { + int datalen = smart_wait(data); bool needGetData = false; @@ -337,20 +337,14 @@ static int smart_response(uint8_t apduINS, uint8_t *data) { goto out; } - if (datalen > 2 && data[0] != apduINS) { - PrintAndLogEx(ERR, "Card ACK error. len=0x%x data[0]=%02x", datalen, data[0]); - datalen = 0; - goto out; - } - if ( data[datalen - 2] == 0x61 || data[datalen - 2] == 0x9F ) { needGetData = true; } if (needGetData) { int len = data[datalen - 1]; - PrintAndLogEx(INFO, "Requesting response. len=0x%x", len); - uint8_t getstatus[] = {ISO7816_GETSTATUS, 0x00, 0x00, len}; + PrintAndLogEx(INFO, "Requesting 0x%02X bytes response", len); + uint8_t getstatus[] = {0x00, ISO7816_GETSTATUS, 0x00, 0x00, len}; UsbCommand cStatus = {CMD_SMART_RAW, {SC_RAW, sizeof(getstatus), 0}}; memcpy(cStatus.d.asBytes, getstatus, sizeof(getstatus) ); clearCommandBuffer(); @@ -361,21 +355,26 @@ static int smart_response(uint8_t apduINS, uint8_t *data) { if (datalen < 2 ) { goto out; } - if (datalen > 2 && data[0] != ISO7816_GETSTATUS) { - PrintAndLogEx(ERR, "GetResponse ACK error. len=0x%x data[0]=%02x", len, data[0]); - datalen = 0; - goto out; - } - if (datalen != len + 2 + 1) { // 2 - response, 1 - ACK - PrintAndLogEx(WARNING, "GetResponse wrong length. Must be: 0x%02x but: 0x%02x", len, datalen - 3); + // data wo ACK + if (datalen != len + 2) { + // data with ACK + if (datalen == len + 2 + 1) { // 2 - response, 1 - ACK + if (data[0] != ISO7816_GETSTATUS) { + PrintAndLogEx(ERR, "GetResponse ACK error. len 0x%x | data[0] %02X", len, data[0]); + datalen = 0; + goto out; + } + + datalen--; + memmove(data, &data[1], datalen); + } else { + // wrong length + PrintAndLogEx(WARNING, "GetResponse wrong length. Must be 0x%02X got 0x%02X", len, datalen - 3); + } } } - if (datalen > 2) { - datalen--; - memmove(data, &data[1], datalen); - } out: return datalen; } @@ -385,6 +384,7 @@ int CmdSmartRaw(const char *Cmd) { int hexlen = 0; bool active = false; bool active_select = false; + bool useT0 = false; uint8_t cmdp = 0; bool errors = false, reply = true, decodeTLV = false, breakloop = false; uint8_t data[USB_CMD_DATA_SIZE] = {0x00}; @@ -408,6 +408,10 @@ int CmdSmartRaw(const char *Cmd) { decodeTLV = true; cmdp++; break; + case '0': + useT0 = true; + cmdp++; + break; case 'd': { switch (param_gethex_to_eol(Cmd, cmdp+1, data, sizeof(data), &hexlen)) { case 1: @@ -448,7 +452,10 @@ int CmdSmartRaw(const char *Cmd) { } if (hexlen > 0) { - c.arg[0] |= SC_RAW; + if (useT0) + c.arg[0] |= SC_RAW_T0; + else + c.arg[0] |= SC_RAW; } memcpy(c.d.asBytes, data, hexlen ); @@ -462,7 +469,7 @@ int CmdSmartRaw(const char *Cmd) { if ( !buf ) return 1; - int len = smart_response(data[1], buf); + int len = smart_response(buf); if ( len < 0 ) { free(buf); return 2; @@ -474,13 +481,13 @@ int CmdSmartRaw(const char *Cmd) { memcpy(c.d.asBytes, data, sizeof(data) ); clearCommandBuffer(); SendCommand(&c); - len = smart_response(data[1], buf); + len = smart_response(buf); data[4] = 0; } if (decodeTLV && len > 4) - TLVPrintFromBuffer(buf+1, len-3); + TLVPrintFromBuffer(buf, len-2); free(buf); } @@ -492,38 +499,35 @@ int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leave if (activateCard) smart_select(false); - printf("* APDU SC\n"); - UsbCommand c = {CMD_SMART_RAW, {SC_RAW | SC_CONNECT, datainlen, 0}}; + PrintAndLogEx(DEBUG, "APDU SC"); + + UsbCommand c = {CMD_SMART_RAW, {SC_RAW_T0, datainlen, 0}}; if (activateCard) { - c.arg[0] |= SC_SELECT; + c.arg[0] |= SC_SELECT | SC_CONNECT; } memcpy(c.d.asBytes, datain, datainlen); clearCommandBuffer(); SendCommand(&c); - int len = smart_response(datain[1], dataout); + int len = smart_response(dataout); if ( len < 0 ) { return 2; } - // retry if (len > 1 && dataout[len - 2] == 0x6c && datainlen > 4) { - UsbCommand c2 = {CMD_SMART_RAW, {SC_RAW, datainlen, 0}}; - memcpy(c2.d.asBytes, datain, datainlen); + UsbCommand c2 = {CMD_SMART_RAW, {SC_RAW_T0, datainlen, 0}}; + memcpy(c2.d.asBytes, datain, 5); - int vlen = 5 + datain[4]; - if (datainlen == vlen) - datainlen++; - - c2.d.asBytes[vlen] = dataout[len - 1]; + // transfer length via T=0 + c2.d.asBytes[4] = dataout[len - 1]; clearCommandBuffer(); SendCommand(&c2); - len = smart_response(datain[1], dataout); + len = smart_response(dataout); } *dataoutlen = len; @@ -552,7 +556,6 @@ int CmdSmartUpgrade(const char *Cmd) { errors = true; break; } - cmdp += 2; break; case 'h': @@ -581,7 +584,7 @@ int CmdSmartUpgrade(const char *Cmd) { return 1; } - char sha512filename[FILE_PATH_SIZE] = {'\0'}; + char sha512filename[FILE_PATH_SIZE]; char *bin_extension = filename; char *dot_position = NULL; while ((dot_position = strchr(bin_extension, '.')) != NULL) { @@ -592,7 +595,7 @@ int CmdSmartUpgrade(const char *Cmd) { || !strcmp(bin_extension, "bin") #endif ) { - memcpy(sha512filename, filename, strlen(filename) - strlen("bin")); + strncpy(sha512filename, filename, strlen(filename) - strlen("bin")); strcat(sha512filename, "sha512.txt"); } else { PrintAndLogEx(FAILED, "Filename extension of Firmware Upgrade File must be .BIN"); @@ -772,32 +775,36 @@ int CmdSmartInfo(const char *Cmd){ memcpy(&card, (smart_card_atr_t *)resp.d.asBytes, sizeof(smart_card_atr_t)); // print header - PrintAndLogEx(INFO, "\n--- Smartcard Information ---------"); + PrintAndLogEx(INFO, "--- Smartcard Information ---------"); PrintAndLogEx(INFO, "-------------------------------------------------------------"); - PrintAndLogEx(INFO, "ISO76183 ATR : %s", sprint_hex(card.atr, card.atr_len)); - PrintAndLogEx(INFO, "look up ATR"); - PrintAndLogEx(INFO, "http://smartcard-atr.appspot.com/parse?ATR=%s", sprint_hex_inrow(card.atr, card.atr_len) ); + PrintAndLogEx(INFO, "ISO7618-3 ATR : %s", sprint_hex(card.atr, card.atr_len)); + PrintAndLogEx(INFO, "\nhttp://smartcard-atr.appspot.com/parse?ATR=%s", sprint_hex_inrow(card.atr, card.atr_len) ); // print ATR PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "* ATR:"); + PrintAndLogEx(INFO, "ATR"); PrintATR(card.atr, card.atr_len); // print D/F (brom byte TA1 or defaults) PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "* D/F (TA1):"); + PrintAndLogEx(INFO, "D/F (TA1)"); int Di = GetATRDi(card.atr, card.atr_len); int Fi = GetATRFi(card.atr, card.atr_len); float F = GetATRF(card.atr, card.atr_len); if (GetATRTA1(card.atr, card.atr_len) == 0x11) PrintAndLogEx(INFO, "Using default values..."); - PrintAndLogEx(NORMAL, "Di=%d", Di); - PrintAndLogEx(NORMAL, "Fi=%d", Fi); - PrintAndLogEx(NORMAL, "F=%.1f MHz", F); - PrintAndLogEx(NORMAL, "Cycles/ETU=%d", Fi/Di); - PrintAndLogEx(NORMAL, "%.1f bits/sec at 4MHz", (float)4000000 / (Fi/Di)); - PrintAndLogEx(NORMAL, "%.1f bits/sec at Fmax=%.1fMHz", (F * 1000000) / (Fi/Di), F); + PrintAndLogEx(NORMAL, "\t- Di=%d", Di); + PrintAndLogEx(NORMAL, "\t- Fi=%d", Fi); + PrintAndLogEx(NORMAL, "\t- F=%.1f MHz", F); + + if (Di && Fi) { + PrintAndLogEx(NORMAL, "\t- Cycles/ETU=%d", Fi/Di); + PrintAndLogEx(NORMAL, "\t- %.1f bits/sec at 4MHz", (float)4000000 / (Fi/Di)); + PrintAndLogEx(NORMAL, "\t- %.1f bits/sec at Fmax=%.1fMHz", (F * 1000000) / (Fi/Di), F); + } else { + PrintAndLogEx(WARNING, "\t- Di or Fi is RFU."); + }; return 0; } @@ -917,8 +924,9 @@ int CmdSmartBruteforceSFI(const char *Cmd) { } PrintAndLogEx(INFO, "Selecting PPSE aid"); - CmdSmartRaw("d 00a404000e325041592e5359532e444446303100"); - CmdSmartRaw("d 00a4040007a000000004101000"); + CmdSmartRaw("s 0 t d 00a404000e325041592e5359532e4444463031"); + CmdSmartRaw("0 t d 00a4040007a000000004101000"); // mastercard +// CmdSmartRaw("0 t d 00a4040007a0000000031010"); // visa PrintAndLogEx(INFO, "starting"); @@ -937,16 +945,15 @@ int CmdSmartBruteforceSFI(const char *Cmd) { clearCommandBuffer(); SendCommand(&c); - smart_response(data[1], buf); + smart_response(buf); - // if 0x6C if ( buf[0] == 0x6C ) { data[4] = buf[1]; memcpy(c.d.asBytes, data, sizeof(data) ); clearCommandBuffer(); SendCommand(&c); - uint8_t len = smart_response(data[1], buf); + uint8_t len = smart_response(buf); // TLV decoder if (len > 4) diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index 04d8f44c..0af75cdc 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -17,7 +17,7 @@ // Got from here. Thanks) // https://eftlab.co.uk/index.php/site-map/knowledge-base/211-emv-aid-rid-pix -static const char *PSElist [] = { +static const char *PSElist [] = { "325041592E5359532E4444463031", // 2PAY.SYS.DDF01 - Visa Proximity Payment System Environment - PPSE "315041592E5359532E4444463031" // 1PAY.SYS.DDF01 - Visa Payment System Environment - PSE }; @@ -35,28 +35,28 @@ typedef struct { const char* aid; } TAIDList; -static const TAIDList AIDlist [] = { +static const TAIDList AIDlist [] = { // Visa International - { CV_VISA, "A00000000305076010"}, // VISA ELO Credit - { CV_VISA, "A0000000031010" }, // VISA Debit/Credit (Classic) - { CV_VISA, "A000000003101001" }, // VISA Credit - { CV_VISA, "A000000003101002" }, // VISA Debit + { CV_VISA, "A00000000305076010"}, // VISA ELO Credit + { CV_VISA, "A0000000031010" }, // VISA Debit/Credit (Classic) + { CV_VISA, "A000000003101001" }, // VISA Credit + { CV_VISA, "A000000003101002" }, // VISA Debit { CV_VISA, "A0000000032010" }, // VISA Electron - { CV_VISA, "A0000000032020" }, // VISA - { CV_VISA, "A0000000033010" }, // VISA Interlink - { CV_VISA, "A0000000034010" }, // VISA Specific - { CV_VISA, "A0000000035010" }, // VISA Specific - { CV_VISA, "A0000000036010" }, // Domestic Visa Cash Stored Value - { CV_VISA, "A0000000036020" }, // International Visa Cash Stored Value - { CV_VISA, "A0000000038002" }, // VISA Auth, VisaRemAuthen EMV-CAP (DPA) - { CV_VISA, "A0000000038010" }, // VISA Plus - { CV_VISA, "A0000000039010" }, // VISA Loyalty - { CV_VISA, "A000000003999910" }, // VISA Proprietary ATM + { CV_VISA, "A0000000032020" }, // VISA + { CV_VISA, "A0000000033010" }, // VISA Interlink + { CV_VISA, "A0000000034010" }, // VISA Specific + { CV_VISA, "A0000000035010" }, // VISA Specific + { CV_VISA, "A0000000036010" }, // Domestic Visa Cash Stored Value + { CV_VISA, "A0000000036020" }, // International Visa Cash Stored Value + { CV_VISA, "A0000000038002" }, // VISA Auth, VisaRemAuthen EMV-CAP (DPA) + { CV_VISA, "A0000000038010" }, // VISA Plus + { CV_VISA, "A0000000039010" }, // VISA Loyalty + { CV_VISA, "A000000003999910" }, // VISA Proprietary ATM // Visa USA { CV_VISA, "A000000098" }, // Debit Card { CV_VISA, "A0000000980848" }, // Debit Card // Mastercard International - { CV_MASTERCARD, "A00000000401" }, // MasterCard PayPass + { CV_MASTERCARD, "A00000000401" }, // MasterCard PayPass { CV_MASTERCARD, "A0000000041010" }, // MasterCard Credit { CV_MASTERCARD, "A00000000410101213" }, // MasterCard Credit { CV_MASTERCARD, "A00000000410101215" }, // MasterCard Credit @@ -68,7 +68,7 @@ static const TAIDList AIDlist [] = { { CV_MASTERCARD, "A0000000045010" }, // MasterCard Specific { CV_MASTERCARD, "A0000000046000" }, // Cirrus { CV_MASTERCARD, "A0000000048002" }, // SecureCode Auth EMV-CAP - { CV_MASTERCARD, "A0000000049999" }, // MasterCard PayPass + { CV_MASTERCARD, "A0000000049999" }, // MasterCard PayPass // American Express { CV_AMERICANEXPRESS, "A000000025" }, { CV_AMERICANEXPRESS, "A0000000250000" }, @@ -77,14 +77,14 @@ static const TAIDList AIDlist [] = { { CV_AMERICANEXPRESS, "A000000025010701" }, { CV_AMERICANEXPRESS, "A000000025010801" }, // Groupement des Cartes Bancaires "CB" - { CV_CB, "A0000000421010" }, // Cartes Bancaire EMV Card - { CV_CB, "A0000000422010" }, - { CV_CB, "A0000000423010" }, - { CV_CB, "A0000000424010" }, - { CV_CB, "A0000000425010" }, + { CV_CB, "A0000000421010" }, // Cartes Bancaire EMV Card + { CV_CB, "A0000000422010" }, + { CV_CB, "A0000000423010" }, + { CV_CB, "A0000000424010" }, + { CV_CB, "A0000000425010" }, // JCB CO., LTD. - { CV_JCB, "A00000006510" }, // JCB - { CV_JCB, "A0000000651010" }, // JCB J Smart Credit + { CV_JCB, "A00000006510" }, // JCB + { CV_JCB, "A0000000651010" }, // JCB J Smart Credit // Other { CV_OTHER, "A0000001544442" }, // Banricompras Debito - Banrisul - Banco do Estado do Rio Grande do SUL - S.A. { CV_OTHER, "F0000000030001" }, // BRADESCO @@ -109,8 +109,8 @@ enum CardPSVendor GetCardPSVendor(uint8_t * AID, size_t AIDlen) { if (strncmp(AIDlist[i].aid, buf, strlen(AIDlist[i].aid)) == 0){ return AIDlist[i].vendor; } - } - + } + return CV_NA; } @@ -127,19 +127,19 @@ void TLVPrintFromBuffer(uint8_t *data, int datalen) { struct tlvdb *t = NULL; t = tlvdb_parse_multi(data, datalen); if (t) { - PrintAndLog("-------------------- TLV decoded --------------------"); - + PrintAndLogEx(NORMAL, "-------------------- TLV decoded --------------------"); + tlvdb_visit(t, print_cb, NULL, 0); tlvdb_free(t); } else { - PrintAndLog("TLV ERROR: Can't parse response as TLV tree."); + PrintAndLogEx(WARNING, "TLV ERROR: Can't parse response as TLV tree."); } } void TLVPrintFromTLVLev(struct tlvdb *tlv, int level) { - if (!tlv) + if (!tlv) return; - + tlvdb_visit(tlv, print_cb, NULL, level); } @@ -148,29 +148,29 @@ void TLVPrintFromTLV(struct tlvdb *tlv) { } void TLVPrintAIDlistFromSelectTLV(struct tlvdb *tlv) { - PrintAndLog("|------------------|--------|-------------------------|"); - PrintAndLog("| AID |Priority| Name |"); - PrintAndLog("|------------------|--------|-------------------------|"); + PrintAndLogEx(NORMAL, "|------------------|--------|-------------------------|"); + PrintAndLogEx(NORMAL, "| AID |Priority| Name |"); + PrintAndLogEx(NORMAL, "|------------------|--------|-------------------------|"); struct tlvdb *ttmp = tlvdb_find(tlv, 0x6f); if (!ttmp) - PrintAndLog("| none |"); - + PrintAndLogEx(NORMAL, "| none |"); + while (ttmp) { const struct tlv *tgAID = tlvdb_get_inchild(ttmp, 0x84, NULL); const struct tlv *tgName = tlvdb_get_inchild(ttmp, 0x50, NULL); const struct tlv *tgPrio = tlvdb_get_inchild(ttmp, 0x87, NULL); if (!tgAID) break; - PrintAndLog("|%s| %s |%s|", - sprint_hex_inrow_ex(tgAID->value, tgAID->len, 18), - (tgPrio) ? sprint_hex(tgPrio->value, 1) : " ", + PrintAndLogEx(NORMAL, "|%s| %s |%s|", + sprint_hex_inrow_ex(tgAID->value, tgAID->len, 18), + (tgPrio) ? sprint_hex(tgPrio->value, 1) : " ", (tgName) ? sprint_ascii_ex(tgName->value, tgName->len, 25) : " "); - + ttmp = tlvdb_find_next(ttmp, 0x6f); } - PrintAndLog("|------------------|--------|-------------------------|"); + PrintAndLogEx(NORMAL, "|------------------|--------|-------------------------|"); } struct tlvdb *GetPANFromTrack2(const struct tlv *track2) { @@ -184,19 +184,19 @@ struct tlvdb *GetPANFromTrack2(const struct tlv *track2) { for (int i = 0; i < track2->len; ++i, tmp += 2) sprintf(tmp, "%02x", (unsigned int)track2->value[i]); - + int posD = strchr(track2Hex, 'd') - track2Hex; if (posD < 1) return NULL; - + track2Hex[posD] = 0; if (strlen(track2Hex) % 2) { track2Hex[posD] = 'F'; track2Hex[posD + 1] = '\0'; } - + param_gethex_to_eol(track2Hex, 0, PAN, sizeof(PAN), &PANlen); - + return tlvdb_fixed(0x5a, PANlen, PAN); } @@ -207,13 +207,13 @@ struct tlvdb *GetdCVVRawFromTrack2(const struct tlv *track2) { int dCVVlen = 0; const int PINlen = 5; // must calculated from 9F67 MSD Offset but i have not seen this tag) char *tmp = track2Hex; - + if (!track2) return NULL; - + for (int i = 0; i < track2->len; ++i, tmp += 2) sprintf(tmp, "%02x", (unsigned int)track2->value[i]); - + int posD = strchr(track2Hex, 'd') - track2Hex; if (posD < 1) return NULL; @@ -227,9 +227,9 @@ struct tlvdb *GetdCVVRawFromTrack2(const struct tlv *track2) { memcpy(dCVVHex + 9, track2Hex + posD + 1, 4); // service code memcpy(dCVVHex + 13, track2Hex + posD + 5, 3); - + param_gethex_to_eol(dCVVHex, 0, dCVV, sizeof(dCVV), &dCVVlen); - + return tlvdb_fixed(0x02, dCVVlen, dCVV); } @@ -240,19 +240,19 @@ int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool LeaveField if (sw) *sw = 0; uint16_t isw = 0; int res = 0; - - if (ActivateField){ + + if (ActivateField) { DropField(); msleep(50); } - + // COMPUTE APDU memcpy(data, &apdu, 5); if (apdu.data) memcpy(&data[5], apdu.data, apdu.Lc); - + if (APDULogging) - PrintAndLog(">>>> %s", sprint_hex(data, (IncludeLe?6:5) + apdu.Lc)); + PrintAndLogEx(SUCCESS, ">>>> %s", sprint_hex(data, (IncludeLe?6:5) + apdu.Lc)); switch(channel) { case ECC_CONTACTLESS: @@ -264,7 +264,7 @@ int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool LeaveField break; case ECC_CONTACT: //int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); -#ifdef WITH_SMARTCARD +#ifdef WITH_SMARTCARD res = ExchangeAPDUSC(data, (IncludeLe?6:5) + apdu.Lc, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); if (res) { return res; @@ -274,12 +274,12 @@ int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool LeaveField } if (APDULogging) - PrintAndLog("<<<< %s", sprint_hex(Result, *ResultLen)); + PrintAndLogEx(SUCCESS, "<<<< %s", sprint_hex(Result, *ResultLen)); if (*ResultLen < 2) { return 200; } - + *ResultLen -= 2; isw = Result[*ResultLen] * 0x0100 + Result[*ResultLen + 1]; if (sw) @@ -288,9 +288,9 @@ int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool LeaveField if (isw != 0x9000) { if (APDULogging) { if (*sw >> 8 == 0x61) { - PrintAndLog("APDU chaining len:%02x -->", *sw & 0xff); + PrintAndLogEx(ERR, "APDU chaining len:%02x -->", *sw & 0xff); } else { - PrintAndLog("APDU(%02x%02x) ERROR: [%4X] %s", apdu.CLA, apdu.INS, isw, GetAPDUCodeDescription(*sw >> 8, *sw & 0xff)); + PrintAndLogEx(ERR, "APDU(%02x%02x) ERROR: [%4X] %s", apdu.CLA, apdu.INS, isw, GetAPDUCodeDescription(*sw >> 8, *sw & 0xff)); return 5; } } @@ -301,16 +301,16 @@ int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool LeaveField struct tlvdb *t = tlvdb_parse_multi(Result, *ResultLen); tlvdb_add(tlv, t); } - + return 0; } int EMVExchange(EMVCommandChannel channel, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - return EMVExchangeEx(channel, false, LeaveFieldON, apdu, true, Result, MaxResultLen, ResultLen, sw, tlv); + return EMVExchangeEx(channel, false, LeaveFieldON, apdu, (channel == ECC_CONTACTLESS), Result, MaxResultLen, ResultLen, sw, tlv); } int EMVSelect(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - return EMVExchangeEx(channel, ActivateField, LeaveFieldON, (sAPDU){0x00, 0xa4, 0x04, 0x00, AIDLen, AID}, true, Result, MaxResultLen, ResultLen, sw, tlv); + return EMVExchangeEx(channel, ActivateField, LeaveFieldON, (sAPDU){0x00, 0xa4, 0x04, 0x00, AIDLen, AID}, (channel == ECC_CONTACTLESS), Result, MaxResultLen, ResultLen, sw, tlv); } int EMVSelectPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { @@ -328,7 +328,7 @@ int EMVSelectPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO default: return -1; } - + // select res = EMVSelect(channel, ActivateField, LeaveFieldON, buf, len, Result, MaxResultLen, ResultLen, sw, NULL); @@ -351,8 +351,8 @@ int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO int retrycnt = 0; struct tlvdb *ttmp = tlvdb_find_path(t, (tlv_tag_t[]){0x6f, 0xa5, 0xbf0c, 0x61, 0x00}); if (!ttmp) - PrintAndLog("PPSE don't have records."); - + PrintAndLogEx(FAILED, "PPSE don't have records."); + while (ttmp) { const struct tlv *tgAID = tlvdb_get_inchild(ttmp, 0x4f, NULL); if (tgAID) { @@ -365,14 +365,14 @@ int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO } else { // card select error, proxmark error if (res == 1) { - PrintAndLog("Exit..."); + PrintAndLogEx(WARNING, "Exit..."); return 1; } - + retrycnt = 0; - PrintAndLog("Retry failed [%s]. Skiped...", sprint_hex_inrow(tgAID->value, tgAID->len)); + PrintAndLogEx(NORMAL, "Retry failed [%s]. Skiped...", sprint_hex_inrow(tgAID->value, tgAID->len)); } - + // next element ttmp = tlvdb_find_next(ttmp, 0x61); continue; @@ -381,25 +381,25 @@ int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO // all is ok if (decodeTLV){ - PrintAndLog("%s:", sprint_hex_inrow(tgAID->value, tgAID->len)); + PrintAndLogEx(NORMAL, "%s:", sprint_hex_inrow(tgAID->value, tgAID->len)); TLVPrintFromBuffer(data, datalen); } } - + ttmp = tlvdb_find_next(ttmp, 0x61); } tlvdb_free(t); } else { - PrintAndLog("PPSE ERROR: Can't get TLV from response."); - } + PrintAndLogEx(WARNING, "PPSE ERROR: Can't get TLV from response."); + } } else { - PrintAndLog("PPSE ERROR: Can't select PPSE AID. Error: %d", res); + PrintAndLogEx(WARNING, "PPSE ERROR: Can't select PPSE AID. Error: %d", res); } - + if(!LeaveFieldON) DropField(); - + return res; } @@ -409,7 +409,7 @@ int EMVSearch(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t data[APDU_RES_LEN] = {0}; size_t datalen = 0; uint16_t sw = 0; - + int res = 0; int retrycnt = 0; for(int i = 0; i < AIDlistLen; i ++) { @@ -422,22 +422,25 @@ int EMVSearch(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, } else { // (1) - card select error, proxmark error OR (200) - result length = 0 if (res == 1 || res == 200) { - PrintAndLogEx(WARNING, "Exit..."); + PrintAndLogEx(WARNING, "Exit..."); return 1; } - + retrycnt = 0; - PrintAndLog("Retry failed [%s]. Skiped...", AIDlist[i].aid); + PrintAndLogEx(FAILED, "Retry failed [%s]. Skipped...", AIDlist[i].aid); } continue; } retrycnt = 0; - + if (res) continue; - - if (decodeTLV){ - PrintAndLog("%s:", AIDlist[i].aid); + + if (!datalen) + continue; + + if (decodeTLV) { + PrintAndLogEx(SUCCESS, "%s", AIDlist[i].aid); TLVPrintFromBuffer(data, datalen); } } @@ -448,25 +451,25 @@ int EMVSearch(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, int EMVSelectApplication(struct tlvdb *tlv, uint8_t *AID, size_t *AIDlen) { // check priority. 0x00 - highest int prio = 0xffff; - + *AIDlen = 0; struct tlvdb *ttmp = tlvdb_find(tlv, 0x6f); if (!ttmp) return 1; - + while (ttmp) { const struct tlv *tgAID = tlvdb_get_inchild(ttmp, 0x84, NULL); const struct tlv *tgPrio = tlvdb_get_inchild(ttmp, 0x87, NULL); - + if (!tgAID) break; if (tgPrio) { - int pt = bytes_to_num((uint8_t*)tgPrio->value, (tgPrio->len < 2) ? tgPrio->len : 2); + int pt = bytes_to_num((uint8_t*)tgPrio->value, (tgPrio->len < 2) ? tgPrio->len : 2); if (pt < prio) { prio = pt; - + memcpy(AID, tgAID->value, tgAID->len); *AIDlen = tgAID->len; } @@ -474,13 +477,13 @@ int EMVSelectApplication(struct tlvdb *tlv, uint8_t *AID, size_t *AIDlen) { // takes the first application from list wo priority if (!*AIDlen) { memcpy(AID, tgAID->value, tgAID->len); - *AIDlen = tgAID->len; + *AIDlen = tgAID->len; } } - + ttmp = tlvdb_find_next(ttmp, 0x6f); } - + return 0; } @@ -491,7 +494,7 @@ int EMVGPO(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *PDOL, size_t P int EMVReadRecord(EMVCommandChannel channel, bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { int res = EMVExchange(channel, LeaveFieldON, (sAPDU){0x00, 0xb2, SFIrec, (SFI << 3) | 0x04, 0, NULL}, Result, MaxResultLen, ResultLen, sw, tlv); if (*sw == 0x6700) { - PrintAndLogEx(INFO, ">>> trying to reissue command withouth Le..."); + PrintAndLogEx(INFO, ">>> trying to reissue command withouth Le..."); res = EMVExchangeEx(channel, false, LeaveFieldON, (sAPDU){0x00, 0xb2, SFIrec, (SFI << 3) | 0x04, 0, NULL}, false, Result, MaxResultLen, ResultLen, sw, tlv); } return res; @@ -504,7 +507,7 @@ int EMVAC(EMVCommandChannel channel, bool LeaveFieldON, uint8_t RefControl, uint int EMVGenerateChallenge(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { int res = EMVExchange(channel, LeaveFieldON, (sAPDU){0x00, 0x84, 0x00, 0x00, 0x00, NULL}, Result, MaxResultLen, ResultLen, sw, tlv); if (*sw == 0x6700) { - PrintAndLogEx(INFO, ">>> trying to reissue command withouth Le..."); + PrintAndLogEx(INFO, ">>> trying to reissue command withouth Le..."); res = EMVExchangeEx(channel, false, LeaveFieldON, (sAPDU){0x00, 0x84, 0x00, 0x00, 0x00, NULL}, false, Result, MaxResultLen, ResultLen, sw, tlv); } return res; @@ -518,7 +521,7 @@ int MSCComputeCryptoChecksum(EMVCommandChannel channel, bool LeaveFieldON, uint8 return EMVExchange(channel, LeaveFieldON, (sAPDU){0x80, 0x2a, 0x8e, 0x80, UDOLlen, UDOL}, Result, MaxResultLen, ResultLen, sw, tlv); } -// Authentication +// Authentication static struct emv_pk *get_ca_pk(struct tlvdb *db) { const struct tlv *df_tlv = tlvdb_get(db, 0x84, NULL); const struct tlv *caidx_tlv = tlvdb_get(db, 0x8f, NULL); @@ -526,7 +529,7 @@ static struct emv_pk *get_ca_pk(struct tlvdb *db) { if (!df_tlv || !caidx_tlv || df_tlv->len < 6 || caidx_tlv->len != 1) return NULL; - PrintAndLog("CA public key index 0x%0x", caidx_tlv->value[0]); + PrintAndLogEx(NORMAL, "CA public key index 0x%0x", caidx_tlv->value[0]); return emv_pk_get_ca_pk(df_tlv->value, caidx_tlv->value[0]); } @@ -534,18 +537,18 @@ int trSDA(struct tlvdb *tlv) { struct emv_pk *pk = get_ca_pk(tlv); if (!pk) { - PrintAndLog("ERROR: Key not found. Exit."); - return 2; - } - - struct emv_pk *issuer_pk = emv_pki_recover_issuer_cert(pk, tlv); - if (!issuer_pk) { - emv_pk_free(pk); - PrintAndLog("ERROR: Issuer certificate not found. Exit."); + PrintAndLogEx(WARNING, "Error: Key not found. Exit."); return 2; } - PrintAndLog("Issuer PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx", + struct emv_pk *issuer_pk = emv_pki_recover_issuer_cert(pk, tlv); + if (!issuer_pk) { + emv_pk_free(pk); + PrintAndLogEx(WARNING, "Error: Issuer certificate not found. Exit."); + return 2; + } + + PrintAndLogEx(SUCCESS, "Issuer PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx", issuer_pk->rid[0], issuer_pk->rid[1], issuer_pk->rid[2], @@ -561,22 +564,22 @@ int trSDA(struct tlvdb *tlv) { if (!sda_tlv || sda_tlv->len < 1) { emv_pk_free(issuer_pk); emv_pk_free(pk); - PrintAndLog("ERROR: Can't find input list for Offline Data Authentication. Exit."); + PrintAndLogEx(WARNING, "Can't find input list for Offline Data Authentication. Exit."); return 3; } - + struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv); if (dac_db) { const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL); - PrintAndLog("SDA verified OK. (%02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]); + PrintAndLogEx(NORMAL, "SDA verified OK. (%02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]); tlvdb_add(tlv, dac_db); } else { emv_pk_free(issuer_pk); emv_pk_free(pk); - PrintAndLog("ERROR: SSAD verify error"); + PrintAndLogEx(WARNING, "SSAD verify error"); return 4; } - + emv_pk_free(issuer_pk); emv_pk_free(pk); return 0; @@ -592,24 +595,24 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { struct emv_pk *pk = get_ca_pk(tlv); if (!pk) { - PrintAndLog("ERROR: Key not found. Exit."); + PrintAndLogEx(WARNING, "Error: Key not found. Exit."); return 2; } const struct tlv *sda_tlv = tlvdb_get(tlv, 0x21, NULL); if (!sda_tlv || sda_tlv->len < 1) { emv_pk_free(pk); - PrintAndLog("ERROR: Can't find input list for Offline Data Authentication. Exit."); + PrintAndLogEx(WARNING, "Error: Can't find input list for Offline Data Authentication. Exit."); return 3; } struct emv_pk *issuer_pk = emv_pki_recover_issuer_cert(pk, tlv); if (!issuer_pk) { emv_pk_free(pk); - PrintAndLog("ERROR: Issuer certificate not found. Exit."); + PrintAndLogEx(WARNING, "Error: Issuer certificate not found. Exit."); return 2; } - printf("Issuer PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n", + PrintAndLogEx(SUCCESS, "Issuer PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n", issuer_pk->rid[0], issuer_pk->rid[1], issuer_pk->rid[2], @@ -620,15 +623,15 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { issuer_pk->serial[1], issuer_pk->serial[2] ); - + struct emv_pk *icc_pk = emv_pki_recover_icc_cert(issuer_pk, tlv, sda_tlv); if (!icc_pk) { emv_pk_free(pk); emv_pk_free(issuer_pk); - PrintAndLog("ERROR: ICC setrificate not found. Exit."); + PrintAndLogEx(WARNING, "Error: ICC setrificate not found. Exit."); return 2; } - printf("ICC PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n", + PrintAndLogEx(SUCCESS, "ICC PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n", icc_pk->rid[0], icc_pk->rid[1], icc_pk->rid[2], @@ -642,9 +645,9 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { struct emv_pk *icc_pe_pk = emv_pki_recover_icc_pe_cert(issuer_pk, tlv); if (!icc_pe_pk) { - PrintAndLog("WARNING: ICC PE PK recover error. "); + PrintAndLogEx(WARNING, "WARNING: ICC PE PK recover error. "); } else { - printf("ICC PE PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n", + PrintAndLogEx(SUCCESS, "ICC PE PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n", icc_pe_pk->rid[0], icc_pe_pk->rid[1], icc_pe_pk->rid[2], @@ -662,11 +665,11 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { // DDA with internal authenticate OR fDDA with filled 0x9F4B tag (GPO result) // EMV kernel3 v2.4, contactless book C-3, C.1., page 147 if (sdad_tlv) { - PrintAndLog("\n* * Got Signed Dynamic Application Data (9F4B) form GPO. Maybe fDDA..."); + PrintAndLogEx(NORMAL, "\n* * Got Signed Dynamic Application Data (9F4B) form GPO. Maybe fDDA..."); const struct tlvdb *atc_db = emv_pki_recover_atc_ex(icc_pk, tlv, true); if (!atc_db) { - PrintAndLog("ERROR: Can't recover IDN (ICC Dynamic Number)"); + PrintAndLogEx(WARNING, "Error: Can't recover IDN (ICC Dynamic Number)"); emv_pk_free(pk); emv_pk_free(issuer_pk); emv_pk_free(icc_pk); @@ -676,17 +679,17 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { // 9f36 Application Transaction Counter (ATC) const struct tlv *atc_tlv = tlvdb_get(atc_db, 0x9f36, NULL); if(atc_tlv) { - PrintAndLog("\nATC (Application Transaction Counter) [%zu] %s", atc_tlv->len, sprint_hex_inrow(atc_tlv->value, atc_tlv->len)); - + PrintAndLogEx(NORMAL, "\nATC (Application Transaction Counter) [%zu] %s", atc_tlv->len, sprint_hex_inrow(atc_tlv->value, atc_tlv->len)); + const struct tlv *core_atc_tlv = tlvdb_get(tlv, 0x9f36, NULL); if(tlv_equal(core_atc_tlv, atc_tlv)) { - PrintAndLog("ATC check OK."); - PrintAndLog("fDDA (fast DDA) verified OK."); + PrintAndLogEx(SUCCESS, "ATC check OK."); + PrintAndLogEx(SUCCESS, "fDDA (fast DDA) verified OK."); } else { - PrintAndLog("ERROR: fDDA verified, but ATC in the certificate and ATC in the record not the same."); + PrintAndLogEx(WARNING, "Error: fDDA verified, but ATC in the certificate and ATC in the record not the same."); } } else { - PrintAndLog("\nERROR: fDDA (fast DDA) verify error"); + PrintAndLogEx(NORMAL, "\nERROR: fDDA (fast DDA) verify error"); emv_pk_free(pk); emv_pk_free(issuer_pk); emv_pk_free(icc_pk); @@ -696,38 +699,38 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv); if (dac_db) { const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL); - printf("SDA verified OK. (%02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]); + PrintAndLogEx(NORMAL, "SDA verified OK. (%02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]); tlvdb_add(tlv, dac_db); } else { - PrintAndLog("ERROR: SSAD verify error"); + PrintAndLogEx(WARNING, "Error: SSAD verify error"); emv_pk_free(pk); emv_pk_free(issuer_pk); emv_pk_free(icc_pk); return 4; } - - PrintAndLog("\n* Calc DDOL"); + + PrintAndLogEx(NORMAL, "\n* Calc DDOL"); const struct tlv *ddol_tlv = tlvdb_get(tlv, 0x9f49, NULL); if (!ddol_tlv) { ddol_tlv = &default_ddol_tlv; - PrintAndLog("DDOL [9f49] not found. Using default DDOL"); + PrintAndLogEx(NORMAL, "DDOL [9f49] not found. Using default DDOL"); } struct tlv *ddol_data_tlv = dol_process(ddol_tlv, tlv, 0); if (!ddol_data_tlv) { - PrintAndLog("ERROR: Can't create DDOL TLV"); + PrintAndLogEx(WARNING, "Error: Can't create DDOL TLV"); emv_pk_free(pk); emv_pk_free(issuer_pk); emv_pk_free(icc_pk); return 5; } - PrintAndLog("DDOL data[%d]: %s", ddol_data_tlv->len, sprint_hex(ddol_data_tlv->value, ddol_data_tlv->len)); + PrintAndLogEx(NORMAL, "DDOL data[%d]: %s", ddol_data_tlv->len, sprint_hex(ddol_data_tlv->value, ddol_data_tlv->len)); - PrintAndLog("\n* Internal Authenticate"); + PrintAndLogEx(NORMAL, "\n* Internal Authenticate"); int res = EMVInternalAuthenticate(channel, true, (uint8_t *)ddol_data_tlv->value, ddol_data_tlv->len, buf, sizeof(buf), &len, &sw, NULL); - if (res) { - PrintAndLogEx(WARNING, "Internal Authenticate error(%d): %4x. Exit...", res, sw); + if (res) { + PrintAndLogEx(WARNING, "Internal Authenticate error(%d): %4x. Exit...", res, sw); free(ddol_data_tlv); emv_pk_free(pk); emv_pk_free(issuer_pk); @@ -738,20 +741,20 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { struct tlvdb *dda_db = NULL; if (buf[0] == 0x80) { if (len < 3 ) { - PrintAndLog("ERROR: Internal Authenticate format1 parsing error. length=%d", len); + PrintAndLogEx(WARNING, "Error: Internal Authenticate format1 parsing error. length=%d", len); } else { // 9f4b Signed Dynamic Application Data dda_db = tlvdb_fixed(0x9f4b, len - 2, buf + 2); tlvdb_add(tlv, dda_db); if (decodeTLV){ - PrintAndLog("* * Decode response format 1:"); + PrintAndLogEx(NORMAL, "* * Decode response format 1:"); TLVPrintFromTLV(dda_db); } } } else { dda_db = tlvdb_parse_multi(buf, len); if(!dda_db) { - PrintAndLog("ERROR: Can't parse Internal Authenticate result as TLV"); + PrintAndLogEx(WARNING, "Error: Can't parse Internal Authenticate result as TLV"); free(ddol_data_tlv); emv_pk_free(pk); emv_pk_free(issuer_pk); @@ -759,7 +762,7 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { return 7; } tlvdb_add(tlv, dda_db); - + if (decodeTLV) TLVPrintFromTLV(dda_db); } @@ -767,7 +770,7 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { struct tlvdb *idn_db = emv_pki_recover_idn_ex(icc_pk, dda_db, ddol_data_tlv, true); free(ddol_data_tlv); if (!idn_db) { - PrintAndLog("ERROR: Can't recover IDN (ICC Dynamic Number)"); + PrintAndLogEx(WARNING, "Error: Can't recover IDN (ICC Dynamic Number)"); tlvdb_free(dda_db); emv_pk_free(pk); emv_pk_free(issuer_pk); @@ -779,12 +782,12 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { // 9f4c ICC Dynamic Number const struct tlv *idn_tlv = tlvdb_get(idn_db, 0x9f4c, NULL); if(idn_tlv) { - PrintAndLog("\nIDN (ICC Dynamic Number) [%zu] %s", idn_tlv->len, sprint_hex_inrow(idn_tlv->value, idn_tlv->len)); - PrintAndLog("DDA verified OK."); + PrintAndLogEx(NORMAL, "\nIDN (ICC Dynamic Number) [%zu] %s", idn_tlv->len, sprint_hex_inrow(idn_tlv->value, idn_tlv->len)); + PrintAndLogEx(NORMAL, "DDA verified OK."); tlvdb_add(tlv, idn_db); tlvdb_free(idn_db); } else { - PrintAndLog("\nERROR: DDA verify error"); + PrintAndLogEx(NORMAL, "\nERROR: DDA verify error"); tlvdb_free(idn_db); emv_pk_free(pk); @@ -793,7 +796,7 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { return 9; } } - + emv_pk_free(pk); emv_pk_free(issuer_pk); emv_pk_free(icc_pk); @@ -804,24 +807,24 @@ int trCDA(struct tlvdb *tlv, struct tlvdb *ac_tlv, struct tlv *pdol_data_tlv, st struct emv_pk *pk = get_ca_pk(tlv); if (!pk) { - PrintAndLog("ERROR: Key not found. Exit."); + PrintAndLogEx(WARNING, "Error: Key not found. Exit."); return 2; } const struct tlv *sda_tlv = tlvdb_get(tlv, 0x21, NULL); if (!sda_tlv || sda_tlv->len < 1) { - PrintAndLog("ERROR: Can't find input list for Offline Data Authentication. Exit."); + PrintAndLogEx(WARNING, "Error: Can't find input list for Offline Data Authentication. Exit."); emv_pk_free(pk); return 3; } struct emv_pk *issuer_pk = emv_pki_recover_issuer_cert(pk, tlv); if (!issuer_pk) { - PrintAndLog("ERROR: Issuer certificate not found. Exit."); + PrintAndLogEx(WARNING, "Error: Issuer certificate not found. Exit."); emv_pk_free(pk); return 2; } - printf("Issuer PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n", + PrintAndLogEx(SUCCESS, "Issuer PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n", issuer_pk->rid[0], issuer_pk->rid[1], issuer_pk->rid[2], @@ -832,15 +835,15 @@ int trCDA(struct tlvdb *tlv, struct tlvdb *ac_tlv, struct tlv *pdol_data_tlv, st issuer_pk->serial[1], issuer_pk->serial[2] ); - + struct emv_pk *icc_pk = emv_pki_recover_icc_cert(issuer_pk, tlv, sda_tlv); if (!icc_pk) { - PrintAndLog("ERROR: ICC setrificate not found. Exit."); + PrintAndLogEx(WARNING, "Error: ICC setrificate not found. Exit."); emv_pk_free(pk); emv_pk_free(issuer_pk); return 2; } - printf("ICC PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n", + PrintAndLogEx(SUCCESS, "ICC PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n", icc_pk->rid[0], icc_pk->rid[1], icc_pk->rid[2], @@ -855,29 +858,29 @@ int trCDA(struct tlvdb *tlv, struct tlvdb *ac_tlv, struct tlv *pdol_data_tlv, st struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv); if (dac_db) { const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL); - PrintAndLog("SSAD verified OK. (%02hhx:%02hhx)", dac_tlv->value[0], dac_tlv->value[1]); + PrintAndLogEx(NORMAL, "SSAD verified OK. (%02hhx:%02hhx)", dac_tlv->value[0], dac_tlv->value[1]); tlvdb_add(tlv, dac_db); } else { - PrintAndLog("ERROR: SSAD verify error"); + PrintAndLogEx(WARNING, "Error: SSAD verify error"); emv_pk_free(pk); emv_pk_free(issuer_pk); emv_pk_free(icc_pk); return 4; } - - PrintAndLog("\n* * Check Signed Dynamic Application Data (SDAD)"); + + PrintAndLogEx(NORMAL, "\n* * Check Signed Dynamic Application Data (SDAD)"); struct tlvdb *idn_db = emv_pki_perform_cda_ex(icc_pk, tlv, ac_tlv, pdol_data_tlv, // pdol ac_data_tlv, // cdol1 - NULL, // cdol2 + NULL, // cdol2 true); if (idn_db) { const struct tlv *idn_tlv = tlvdb_get(idn_db, 0x9f4c, NULL); - PrintAndLog("\nIDN (ICC Dynamic Number) [%zu] %s", idn_tlv->len, sprint_hex_inrow(idn_tlv->value, idn_tlv->len)); - PrintAndLog("CDA verified OK."); + PrintAndLogEx(NORMAL, "\nIDN (ICC Dynamic Number) [%zu] %s", idn_tlv->len, sprint_hex_inrow(idn_tlv->value, idn_tlv->len)); + PrintAndLogEx(NORMAL, "CDA verified OK."); tlvdb_add(tlv, idn_db); } else { - PrintAndLog("\nERROR: CDA verify error"); + PrintAndLogEx(NORMAL, "\nERROR: CDA verify error"); } emv_pk_free(pk); @@ -887,7 +890,7 @@ int trCDA(struct tlvdb *tlv, struct tlvdb *ac_tlv, struct tlv *pdol_data_tlv, st } int RecoveryCertificates(struct tlvdb *tlvRoot, json_t *root) { - + struct emv_pk *pk = get_ca_pk(tlvRoot); if (!pk) { PrintAndLog("ERROR: Key not found. Exit."); @@ -937,11 +940,11 @@ int RecoveryCertificates(struct tlvdb *tlvRoot, json_t *root) { icc_pk->serial[1], icc_pk->serial[2] ); - + char *icc_pk_c = emv_pk_dump_pk(icc_pk); JsonSaveStr(root, "$.ApplicationData.ICCPublicKeyDec", icc_pk_c); JsonSaveBufAsHex(root, "$.ApplicationData.ICCPublicKeyModulus", icc_pk->modulus, icc_pk->mlen); free(issuer_pk_c); - + return 0; } diff --git a/include/smartcard.h b/include/smartcard.h index 2f6e286c..70245a78 100644 --- a/include/smartcard.h +++ b/include/smartcard.h @@ -22,7 +22,8 @@ typedef enum SMARTCARD_COMMAND { SC_CONNECT = (1 << 0), SC_NO_DISCONNECT = (1 << 1), SC_RAW = (1 << 2), - SC_SELECT = (1 << 3) + SC_SELECT = (1 << 3), + SC_RAW_T0 = (1 << 4) } smartcard_command_t; From d3c606574f90881daab8585659c18223a7a3c2c3 Mon Sep 17 00:00:00 2001 From: Fl0-0 Date: Thu, 17 Jan 2019 09:13:38 +0100 Subject: [PATCH 051/189] restore #755 reverted after #757 (#761) --- client/cmdsmartcard.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/cmdsmartcard.c b/client/cmdsmartcard.c index 2eed6d3d..edd51b72 100644 --- a/client/cmdsmartcard.c +++ b/client/cmdsmartcard.c @@ -584,7 +584,7 @@ int CmdSmartUpgrade(const char *Cmd) { return 1; } - char sha512filename[FILE_PATH_SIZE]; + char sha512filename[FILE_PATH_SIZE] = {'\0'}; char *bin_extension = filename; char *dot_position = NULL; while ((dot_position = strchr(bin_extension, '.')) != NULL) { @@ -595,7 +595,7 @@ int CmdSmartUpgrade(const char *Cmd) { || !strcmp(bin_extension, "bin") #endif ) { - strncpy(sha512filename, filename, strlen(filename) - strlen("bin")); + memcpy(sha512filename, filename, strlen(filename) - strlen("bin")); strcat(sha512filename, "sha512.txt"); } else { PrintAndLogEx(FAILED, "Filename extension of Firmware Upgrade File must be .BIN"); From 1511ea28a8cc647a6fc462e9c182622a43df1318 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Mon, 21 Jan 2019 19:26:54 +0100 Subject: [PATCH 052/189] Add ROCA vulnerability test (RRG repository PR 76 by @merlokk) (#762) --- client/Makefile | 5 +- client/emv/cmdemv.c | 256 +++++++++++++++++++++++++++++++++-- client/emv/cmdemv.h | 24 +--- client/emv/emv_roca.c | 193 ++++++++++++++++++++++++++ client/emv/emv_roca.h | 36 +++++ client/emv/emvcore.c | 16 ++- client/emv/emvcore.h | 6 +- client/emv/test/cryptotest.c | 4 + 8 files changed, 491 insertions(+), 49 deletions(-) create mode 100644 client/emv/emv_roca.c create mode 100644 client/emv/emv_roca.h diff --git a/client/Makefile b/client/Makefile index 9ad8efdd..81b46f23 100644 --- a/client/Makefile +++ b/client/Makefile @@ -156,6 +156,7 @@ CMDSRCS = $(SRC_SMARTCARD) \ emv/test/dda_test.c\ emv/test/cda_test.c\ emv/cmdemv.c\ + emv/emv_roca.c \ cmdhf.c \ cmdhflist.c \ cmdhf14a.c \ @@ -250,7 +251,7 @@ endif BINS = proxmark3 flasher fpga_compress WINBINS = $(patsubst %, %.exe, $(BINS)) -CLEAN = $(BINS) $(WINBINS) $(COREOBJS) $(CMDOBJS) $(OBJCOBJS) $(ZLIBOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(OBJDIR)/*.o *.moc.cpp ui/ui_overlays.h +CLEAN = $(BINS) $(WINBINS) $(COREOBJS) $(CMDOBJS) $(OBJCOBJS) $(ZLIBOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(OBJDIR)/*.o *.moc.cpp ui/ui_overlays.h lualibs/usb_cmd.lua # need to assign dependancies to build these first... all: lua_build jansson_build mbedtls_build cbor_build $(BINS) @@ -295,7 +296,7 @@ lua_build: jansson_build: @echo Compiling jansson - cd ./jansson && make all + cd $(JANSSONLIBPATH) && make all mbedtls_build: @echo Compiling mbedtls diff --git a/client/emv/cmdemv.c b/client/emv/cmdemv.c index d9a43cb9..e7676501 100644 --- a/client/emv/cmdemv.c +++ b/client/emv/cmdemv.c @@ -8,14 +8,20 @@ // EMV commands //----------------------------------------------------------------------------- -#include -#include "mifare.h" #include "cmdemv.h" + +#include +#include "proxmark3.h" +#include "cmdparser.h" +#include "mifare.h" #include "emvjson.h" #include "emv_pki.h" +#include "emvcore.h" #include "test/cryptotest.h" #include "cliparser/cliparser.h" -#include +#include "jansson.h" +#include "emv_roca.h" + #define TLV_ADD(tag, value)( tlvdb_change_or_add_node(tlvRoot, tag, sizeof(value) - 1, (const unsigned char *)value) ) void ParamLoadDefaults(struct tlvdb *tlvRoot) { @@ -323,10 +329,8 @@ int CmdEMVReadRecord(const char *cmd) { arg_lit0("kK", "keep", "keep field ON for next command"), arg_lit0("aA", "apdu", "show APDU reqests and responses"), arg_lit0("tT", "tlv", "TLV decode results of selected applets"), -#ifdef WITH_SMARTCARD arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."), -#endif - arg_strx1(NULL, NULL, "", NULL), + arg_strx1(NULL, NULL, "", NULL), arg_param_end }; CLIExecWithReturn(cmd, argtable, true); @@ -544,8 +548,11 @@ int CmdEMVInternalAuthenticate(const char *cmd) { int datalen = 0; CLIParserInit("emv intauth", - "Generate Internal Authenticate command. Usually needs 4-byte random number. It returns data in TLV format .\nNeeds a EMV applet to be selected and GPO to be executed.", - "Usage:\n\temv intauth -k 01020304 -> execute Internal Authenticate with 4-byte DDOLdata and keep field ON after command\n" + "Generate Internal Authenticate command. Usually needs 4-byte random number. It returns data in TLV format .\n" + "Needs a EMV applet to be selected and GPO to be executed.", + + "Usage:\n" + "\temv intauth -k 01020304 -> execute Internal Authenticate with 4-byte DDOLdata and keep field ON after command\n" "\temv intauth -t 01020304 -> execute Internal Authenticate with 4-byte DDOL data, show result in TLV\n" "\temv intauth -pmt 9F 37 04 -> load params from file, make DDOL data from DDOL, Internal Authenticate with DDOL, show result in TLV"); @@ -720,7 +727,8 @@ int CmdEMVExec(const char *cmd) { CLIParserInit("emv exec", "Executes EMV contactless transaction", - "Usage:\n\temv exec -sat -> select card, execute MSD transaction, show APDU and TLV\n" + "Usage:\n" + "\temv exec -sat -> select card, execute MSD transaction, show APDU and TLV\n" "\temv exec -satc -> select card, execute CDA transaction, show APDU and TLV\n"); void* argtable[] = { @@ -735,9 +743,7 @@ int CmdEMVExec(const char *cmd) { arg_lit0("cC", "qvsdccda", "Transaction type - qVSDC or M/Chip plus CDA (SDAD generation)."), arg_lit0("xX", "vsdc", "Transaction type - VSDC. For test only. Not a standart behavior."), arg_lit0("gG", "acgpo", "VISA. generate AC from GPO."), -#ifdef WITH_SMARTCARD arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."), -#endif arg_param_end }; CLIExecWithReturn(cmd, argtable, true); @@ -762,6 +768,7 @@ int CmdEMVExec(const char *cmd) { if (arg_get_lit(11)) channel = ECC_CONTACT; #endif + uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2; CLIParserFree(); SetAPDULogging(showAPDU); @@ -776,7 +783,7 @@ int CmdEMVExec(const char *cmd) { // PPSE PrintAndLogEx(NORMAL, "\n* PPSE."); SetAPDULogging(showAPDU); - res = EMVSearchPSE(channel, activateField, true, decodeTLV, tlvSelect); + res = EMVSearchPSE(channel, activateField, true, psenum, decodeTLV, tlvSelect); // check PPSE and select application id if (!res) { @@ -1212,12 +1219,14 @@ int CmdEMVScan(const char *cmd) { char *crelfname = (char *)relfname; int relfnamelen = 0; #ifdef WITH_SMARTCARD - if (arg_get_lit(11)) + if (arg_get_lit(11)) { channel = ECC_CONTACT; + } CLIGetStrWithReturn(12, relfname, &relfnamelen); #else CLIGetStrWithReturn(11, relfname, &relfnamelen); #endif + uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2; CLIParserFree(); SetAPDULogging(showAPDU); @@ -1292,7 +1301,7 @@ int CmdEMVScan(const char *cmd) { tlvdb_free(fci); } - res = EMVSearchPSE(channel, false, true, decodeTLV, tlvSelect); + res = EMVSearchPSE(channel, false, true, psenum, decodeTLV, tlvSelect); // check PPSE and select application id if (!res) { @@ -1502,7 +1511,225 @@ int CmdEMVTest(const char *cmd) { return ExecuteCryptoTests(true); } +int CmdEMVRoca(const char *cmd) { + uint8_t AID[APDU_AID_LEN] = {0}; + size_t AIDlen = 0; + uint8_t buf[APDU_RES_LEN] = {0}; + size_t len = 0; + uint16_t sw = 0; + int res; + + CLIParserInit("emv roca", + "Tries to extract public keys and run the ROCA test against them.\n", + "Usage:\n" + "\temv roca -w -> select CONTACT card and run test\n\temv roca -> select CONTACTLESS card and run test\n"); + + void* argtable[] = { + arg_param_begin, + arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, true); + + EMVCommandChannel channel = ECC_CONTACTLESS; + if (arg_get_lit(1)) + channel = ECC_CONTACT; + + // select card + uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2; + + SetAPDULogging(false); + + // init applets list tree + const char *al = "Applets list"; + struct tlvdb *tlvSelect = tlvdb_fixed(1, strlen(al), (const unsigned char *)al); + + // EMV PPSE + PrintAndLogEx(NORMAL, "--> PPSE."); + res = EMVSearchPSE(channel, false, true, psenum, false, tlvSelect); + + // check PPSE and select application id + if (!res) { + TLVPrintAIDlistFromSelectTLV(tlvSelect); + } else { + // EMV SEARCH with AID list + PrintAndLogEx(NORMAL, "--> AID search."); + if (EMVSearch(channel, false, true, false, tlvSelect)) { + PrintAndLogEx(ERR, "Can't found any of EMV AID. Exit..."); + tlvdb_free(tlvSelect); + DropField(); + return 3; + } + + // check search and select application id + TLVPrintAIDlistFromSelectTLV(tlvSelect); + } + + // EMV SELECT application + SetAPDULogging(false); + EMVSelectApplication(tlvSelect, AID, &AIDlen); + + tlvdb_free(tlvSelect); + + if (!AIDlen) { + PrintAndLogEx(INFO, "Can't select AID. EMV AID not found. Exit..."); + DropField(); + return 4; + } + + // Init TLV tree + const char *alr = "Root terminal TLV tree"; + struct tlvdb *tlvRoot = tlvdb_fixed(1, strlen(alr), (const unsigned char *)alr); + + // EMV SELECT applet + PrintAndLogEx(NORMAL, "\n-->Selecting AID:%s.", sprint_hex_inrow(AID, AIDlen)); + res = EMVSelect(channel, false, true, AID, AIDlen, buf, sizeof(buf), &len, &sw, tlvRoot); + + if (res) { + PrintAndLogEx(ERR, "Can't select AID (%d). Exit...", res); + tlvdb_free(tlvRoot); + DropField(); + return 5; + } + + PrintAndLog("\n* Init transaction parameters."); + InitTransactionParameters(tlvRoot, true, TT_QVSDCMCHIP, false); + + PrintAndLogEx(NORMAL, "-->Calc PDOL."); + struct tlv *pdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x9f38, NULL), tlvRoot, 0x83); + if (!pdol_data_tlv){ + PrintAndLogEx(ERR, "Can't create PDOL TLV."); + tlvdb_free(tlvRoot); + DropField(); + return 6; + } + + size_t pdol_data_tlv_data_len; + unsigned char *pdol_data_tlv_data = tlv_encode(pdol_data_tlv, &pdol_data_tlv_data_len); + if (!pdol_data_tlv_data) { + PrintAndLogEx(ERR, "Can't create PDOL data."); + tlvdb_free(tlvRoot); + DropField(); + return 6; + } + PrintAndLogEx(INFO, "PDOL data[%d]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len)); + + PrintAndLogEx(INFO, "-->GPO."); + res = EMVGPO(channel, true, pdol_data_tlv_data, pdol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot); + + free(pdol_data_tlv_data); + free(pdol_data_tlv); + + if (res) { + PrintAndLogEx(ERR, "GPO error(%d): %4x. Exit...", res, sw); + tlvdb_free(tlvRoot); + DropField(); + return 7; + } + ProcessGPOResponseFormat1(tlvRoot, buf, len, false); + + PrintAndLogEx(INFO, "-->Read records from AFL."); + const struct tlv *AFL = tlvdb_get(tlvRoot, 0x94, NULL); + + while(AFL && AFL->len) { + if (AFL->len % 4) { + PrintAndLogEx(ERR, "Wrong AFL length: %d", AFL->len); + break; + } + + for (int i = 0; i < AFL->len / 4; i++) { + uint8_t SFI = AFL->value[i * 4 + 0] >> 3; + uint8_t SFIstart = AFL->value[i * 4 + 1]; + uint8_t SFIend = AFL->value[i * 4 + 2]; + uint8_t SFIoffline = AFL->value[i * 4 + 3]; + + PrintAndLogEx(INFO, "--->SFI[%02x] start:%02x end:%02x offline:%02x", SFI, SFIstart, SFIend, SFIoffline); + if (SFI == 0 || SFI == 31 || SFIstart == 0 || SFIstart > SFIend) { + PrintAndLogEx(ERR, "SFI ERROR! Skipped..."); + continue; + } + + for(int n = SFIstart; n <= SFIend; n++) { + PrintAndLogEx(INFO, "---->SFI[%02x] %d", SFI, n); + + res = EMVReadRecord(channel, true, SFI, n, buf, sizeof(buf), &len, &sw, tlvRoot); + if (res) { + PrintAndLogEx(ERR, "SFI[%02x]. APDU error %4x", SFI, sw); + continue; + } + } + } + + break; + } + + // getting certificates + if (tlvdb_get(tlvRoot, 0x90, NULL)) { + PrintAndLogEx(INFO, "-->Recovering certificates."); + PKISetStrictExecution(false); + + struct emv_pk *pk = get_ca_pk(tlvRoot); + if (!pk) { + PrintAndLogEx(ERR, "ERROR: Key not found. Exit."); + goto out; + } + + struct emv_pk *issuer_pk = emv_pki_recover_issuer_cert(pk, tlvRoot); + if (!issuer_pk) { + emv_pk_free(pk); + PrintAndLogEx(WARNING, "WARNING: Issuer certificate not found. Exit."); + goto out; + } + + PrintAndLogEx(SUCCESS, "Issuer PK recovered. RID %s IDX %02hhx CSN %s", + sprint_hex(issuer_pk->rid, 5), + issuer_pk->index, + sprint_hex(issuer_pk->serial, 3) + ); + + + struct emv_pk *icc_pk = emv_pki_recover_icc_cert(issuer_pk, tlvRoot, NULL); + if (!icc_pk) { + emv_pk_free(pk); + emv_pk_free(issuer_pk); + PrintAndLogEx(WARNING, "WARNING: ICC certificate not found. Exit."); + goto out; + } + PrintAndLogEx(SUCCESS, "ICC PK recovered. RID %s IDX %02hhx CSN %s\n", + sprint_hex(icc_pk->rid, 5), + icc_pk->index, + sprint_hex(icc_pk->serial, 3) + ); + + PrintAndLogEx(INFO, "ICC pk modulus: %s", sprint_hex_inrow(icc_pk->modulus, icc_pk->mlen)); + + // icc_pk->exp, icc_pk->elen + // icc_pk->modulus, icc_pk->mlen + if (icc_pk->elen > 0 && icc_pk->mlen > 0) { + if (emv_rocacheck(icc_pk->modulus, icc_pk->mlen, true)) { + PrintAndLogEx(INFO, "ICC pk is a subject to ROCA vulnerability, insecure.."); + } else { + PrintAndLogEx(INFO, "ICC pk is OK("); + } + } + + PKISetStrictExecution(true); + } + +out: + + // free tlv object + tlvdb_free(tlvRoot); + + if ( channel == ECC_CONTACTLESS) + DropField(); + + + return 0; +} + int CmdHelp(const char *Cmd); + static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"exec", CmdEMVExec, 0, "Executes EMV contactless transaction."}, @@ -1516,6 +1743,7 @@ static command_t CommandTable[] = { {"intauth", CmdEMVInternalAuthenticate, 0, "Internal authentication."}, {"scan", CmdEMVScan, 0, "Scan EMV card and save it contents to json file for emulator."}, {"test", CmdEMVTest, 0, "Crypto logic test."}, + {"roca", CmdEMVRoca, 0, "Extract public keys and run ROCA test"}, {NULL, NULL, 0, NULL} }; diff --git a/client/emv/cmdemv.h b/client/emv/cmdemv.h index 3dc76fa9..1a9da118 100644 --- a/client/emv/cmdemv.h +++ b/client/emv/cmdemv.h @@ -11,28 +11,6 @@ #ifndef CMDEMV_H__ #define CMDEMV_H__ -#include -#include -#include -#include -#include -#include "proxmark3.h" -#include "ui.h" -#include "cmdparser.h" -#include "common.h" -#include "util.h" -#include "util_posix.h" -#include "cmdmain.h" -#include "emvcore.h" -#include "apduinfo.h" - -int CmdEMV(const char *Cmd); - -extern int CmdEMVSelect(const char *cmd); -extern int CmdEMVSearch(const char *cmd); -extern int CmdEMVPPSE(const char *cmd); -extern int CmdEMVExec(const char *cmd); -extern int CmdEMVGetrng(const char *Cmd); -extern int CmdEMVList(const char *Cmd); +extern int CmdEMV(const char *Cmd); #endif diff --git a/client/emv/emv_roca.c b/client/emv/emv_roca.c new file mode 100644 index 00000000..3701ddf8 --- /dev/null +++ b/client/emv/emv_roca.c @@ -0,0 +1,193 @@ +/* roca.c - ROCA (CVE-2017-15361) fingerprint checker. + * Written by Rob Stradling (based on https://github.com/crocs-muni/roca/blob/master/roca/detect.py) + * Copyright (C) 2017-2018 Sectigo Limited + * modified 2018 iceman (dropped openssl bignum, now use mbedtls lib) + * modified 2018 merlok + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +//----------------------------------------------------------------------------- +// EMV roca commands +//----------------------------------------------------------------------------- + +#include "emv_roca.h" + +#include +#include +#include + +#include "ui.h" +#include "mbedtls/bignum.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 +}; + +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]); + + 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]); +} + +int bitand_is_zero( mbedtls_mpi* a, mbedtls_mpi* b ) { + + 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; +} + + +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; +} + +void print_mpi(const char *msg, int radix, const mbedtls_mpi *X) { + + char Xchar[400] = {0}; + size_t len = 0; + + mbedtls_mpi_write_string(X, radix, Xchar, sizeof(Xchar), &len); + printf("%s[%zd] %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); + + bool ret = false; + + rocacheck_init(); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary(&t_modulus, buf, buflen) ); + + for (int i = 0; i < ROCA_PRINTS_LENGTH; i++) { + + 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_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_mod_mpi(&t_temp, &t_modulus, &t_prime) ); + + 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; + } + + mbedtls_mpi_free(&g_one); + mbedtls_mpi_free(&t_temp); + mbedtls_mpi_free(&t_prime); + } + + ret = true; + if (verbose) + PrintAndLogEx(SUCCESS, "Fingerprint found!\n"); + +cleanup: + mbedtls_mpi_free(&t_modulus); + + rocacheck_cleanup(); + return ret; +} + +int roca_self_test( int verbose ) { + int ret = 0; + + if( verbose != 0 ) + printf( "\nROCA check vulnerability tests\n" ); + + // 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( verbose != 0 ) + printf( " ROCA positive test: " ); + + if (emv_rocacheck(keyp, 64, false)) { + if( verbose != 0 ) + printf( "passed\n" ); + } else { + ret = 1; + if( verbose != 0 ) + printf( "failed\n" ); + } + + // 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( verbose != 0 ) + printf( " ROCA negative test: " ); + + if (emv_rocacheck(keyn, 64, false)) { + ret = 1; + if( verbose != 0 ) + printf( "failed\n" ); + } else { + if( verbose != 0 ) + printf( "passed\n" ); + } + + + return ret; +} diff --git a/client/emv/emv_roca.h b/client/emv/emv_roca.h new file mode 100644 index 00000000..b0b9a0ea --- /dev/null +++ b/client/emv/emv_roca.h @@ -0,0 +1,36 @@ +/* roca.c - ROCA (CVE-2017-15361) fingerprint checker. + * Written by Rob Stradling (based on https://github.com/crocs-muni/roca/blob/master/roca/detect.py) + * Copyright (C) 2017-2018 Sectigo Limited + * modified 2018 iceman (dropped openssl bignum, now use mbedtls lib) + * modified 2018 merlok + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +//----------------------------------------------------------------------------- +// EMV roca commands +//----------------------------------------------------------------------------- + +#ifndef EMV_ROCA_H__ +#define EMV_ROCA_H__ + +#include +#include + +#define ROCA_PRINTS_LENGTH 17 + +extern bool emv_rocacheck( const unsigned char *buf, size_t buflen, bool verbose ); +extern int roca_self_test( int verbose ); + +#endif + diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index 0af75cdc..23aa5e38 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -123,7 +123,7 @@ static bool print_cb(void *data, const struct tlv *tlv, int level, bool is_leaf) return true; } -void TLVPrintFromBuffer(uint8_t *data, int datalen) { +bool TLVPrintFromBuffer(uint8_t *data, int datalen) { struct tlvdb *t = NULL; t = tlvdb_parse_multi(data, datalen); if (t) { @@ -131,9 +131,11 @@ void TLVPrintFromBuffer(uint8_t *data, int datalen) { tlvdb_visit(t, print_cb, NULL, 0); tlvdb_free(t); + return true; } else { PrintAndLogEx(WARNING, "TLV ERROR: Can't parse response as TLV tree."); } + return false; } void TLVPrintFromTLVLev(struct tlvdb *tlv, int level) { @@ -335,14 +337,14 @@ int EMVSelectPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO return res; } -int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv) { +int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, bool decodeTLV, struct tlvdb *tlv) { uint8_t data[APDU_RES_LEN] = {0}; size_t datalen = 0; uint16_t sw = 0; int res; // select PPSE - res = EMVSelectPSE(channel, ActivateField, true, 2, data, sizeof(data), &datalen, &sw); + res = EMVSelectPSE(channel, ActivateField, true, PSENum, data, sizeof(data), &datalen, &sw); if (!res){ struct tlvdb *t = NULL; @@ -522,7 +524,7 @@ int MSCComputeCryptoChecksum(EMVCommandChannel channel, bool LeaveFieldON, uint8 } // Authentication -static struct emv_pk *get_ca_pk(struct tlvdb *db) { +struct emv_pk *get_ca_pk(struct tlvdb *db) { const struct tlv *df_tlv = tlvdb_get(db, 0x84, NULL); const struct tlv *caidx_tlv = tlvdb_get(db, 0x8f, NULL); @@ -903,7 +905,7 @@ int RecoveryCertificates(struct tlvdb *tlvRoot, json_t *root) { PrintAndLog("WARNING: Issuer certificate not found. Exit."); return 2; } - PrintAndLog("Issuer PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx", + PrintAndLogEx(SUCCESS, "Issuer PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx", issuer_pk->rid[0], issuer_pk->rid[1], issuer_pk->rid[2], @@ -926,10 +928,10 @@ int RecoveryCertificates(struct tlvdb *tlvRoot, json_t *root) { if (!icc_pk) { emv_pk_free(pk); emv_pk_free(issuer_pk); - PrintAndLog("WARNING: ICC certificate not found. Exit."); + PrintAndLogEx(WARNING, "WARNING: ICC certificate not found. Exit."); return 2; } - printf("ICC PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n", + PrintAndLogEx(SUCCESS, "ICC PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n", icc_pk->rid[0], icc_pk->rid[1], icc_pk->rid[2], diff --git a/client/emv/emvcore.h b/client/emv/emvcore.h index d8b6a5c7..7d53e83b 100644 --- a/client/emv/emvcore.h +++ b/client/emv/emvcore.h @@ -65,7 +65,7 @@ enum CardPSVendor { }; extern enum CardPSVendor GetCardPSVendor(uint8_t * AID, size_t AIDlen); -extern void TLVPrintFromBuffer(uint8_t *data, int datalen); +extern bool TLVPrintFromBuffer(uint8_t *data, int datalen); extern void TLVPrintFromTLV(struct tlvdb *tlv); extern void TLVPrintFromTLVLev(struct tlvdb *tlv, int level); extern void TLVPrintAIDlistFromSelectTLV(struct tlvdb *tlv); @@ -78,9 +78,8 @@ extern void SetAPDULogging(bool logging); // exchange extern int EMVExchange(EMVCommandChannel channel, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); - // search application -extern int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv); +extern int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, bool decodeTLV, struct tlvdb *tlv); extern int EMVSearch(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv); extern int EMVSelectPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); extern int EMVSelect(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); @@ -103,6 +102,7 @@ extern int trCDA(struct tlvdb *tlv, struct tlvdb *ac_tlv, struct tlv *pdol_data_ extern int RecoveryCertificates(struct tlvdb *tlvRoot, json_t *root); +extern struct emv_pk *get_ca_pk(struct tlvdb *db); #endif diff --git a/client/emv/test/cryptotest.c b/client/emv/test/cryptotest.c index 1d5891fe..b0212a70 100644 --- a/client/emv/test/cryptotest.c +++ b/client/emv/test/cryptotest.c @@ -31,6 +31,7 @@ #include "dda_test.h" #include "cda_test.h" #include "crypto/libpcrypto.h" +#include "emv/emv_roca.h" int ExecuteCryptoTests(bool verbose) { int res; @@ -90,6 +91,9 @@ int ExecuteCryptoTests(bool verbose) { res = exec_crypto_test(verbose); if (res) TestFail = true; + res = roca_self_test(verbose); + if (res) TestFail = true; + PrintAndLog("\n--------------------------"); if (TestFail) PrintAndLog("Test(s) [ERROR]."); From a9104f7e31d6c134f9772fef6df2156ed06c9e78 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Mon, 28 Jan 2019 21:54:34 +0100 Subject: [PATCH 053/189] Add support for standard USB Smartcard Readers (#765) * add PCSC interface (pcsc.c and pcsc.h) * new command 'sc select' to choose an USB Smartcard Reader * updated CI/.travis.yml accordingly * remove TCK CRC check in i2c.c It is done in PrintATR() anyway * Fix TCK CRC check in PrintATR() * Add PCSC reader support to 'sc info' --- CI/.travis.yml | 2 +- armsrc/appmain.c | 17 +++- armsrc/i2c.c | 22 ------ client/Makefile | 22 +++++- client/cmdhw.c | 10 ++- client/cmdhw.h | 3 + client/cmdsmartcard.c | 158 ++++++++++++++++++++++++------------- client/pcsc.c | 177 ++++++++++++++++++++++++++++++++++++++++++ client/pcsc.h | 22 ++++++ client/proxmark3.c | 3 + client/util.c | 17 +++- client/util.h | 5 ++ include/smartcard.h | 2 + include/usb_cmd.h | 15 ++-- 14 files changed, 382 insertions(+), 93 deletions(-) create mode 100644 client/pcsc.c create mode 100644 client/pcsc.h diff --git a/CI/.travis.yml b/CI/.travis.yml index f5fed7a6..0c02c250 100644 --- a/CI/.travis.yml +++ b/CI/.travis.yml @@ -26,7 +26,7 @@ before_install: echo $REPOSITORY_EP; if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get update -qq; - sudo apt-get install -y gcc-arm-none-eabi; + sudo apt-get install -y gcc-arm-none-eabi libpcsclite-dev; elif [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; if [[ "$REPOSITORY_EP" == "" ]]; then diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 1348ef04..cdc784c0 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -34,6 +34,7 @@ #include "LCD.h" #endif +static uint32_t hw_capabilities; // Craig Young - 14a stand-alone code #ifdef WITH_ISO14443a @@ -312,8 +313,22 @@ extern struct version_information version_information; extern char *_bootphase1_version_pointer, _flash_start, _flash_end, _bootrom_start, _bootrom_end, __data_src_start__; +void set_hw_capabilities(void) +{ + if (I2C_is_available()) { + hw_capabilities |= HAS_SMARTCARD_SLOT; + } + + if (false) { // TODO: implement a test + hw_capabilities |= HAS_EXTRA_FLASH_MEM; + } +} + + void SendVersion(void) { + set_hw_capabilities(); + char temp[USB_CMD_DATA_SIZE]; /* Limited data payload in USB packets */ char VersionString[USB_CMD_DATA_SIZE] = { '\0' }; @@ -347,7 +362,7 @@ void SendVersion(void) // Send Chip ID and used flash memory uint32_t text_and_rodata_section_size = (uint32_t)&__data_src_start__ - (uint32_t)&_flash_start; uint32_t compressed_data_section_size = common_area.arg1; - cmd_send(CMD_ACK, *(AT91C_DBGU_CIDR), text_and_rodata_section_size + compressed_data_section_size, 0, VersionString, strlen(VersionString)); + cmd_send(CMD_ACK, *(AT91C_DBGU_CIDR), text_and_rodata_section_size + compressed_data_section_size, hw_capabilities, VersionString, strlen(VersionString)); } // measure the USB Speed by sending SpeedTestBufferSize bytes to client and measuring the elapsed time. diff --git a/armsrc/i2c.c b/armsrc/i2c.c index 0560d306..7ef0c9c0 100644 --- a/armsrc/i2c.c +++ b/armsrc/i2c.c @@ -656,28 +656,6 @@ static bool GetATR(smart_card_atr_t *card_ptr) { if ( !sc_rx_bytes(card_ptr->atr, &len) ) return false; - uint8_t pos_td = 1; - if ( (card_ptr->atr[1] & 0x10) == 0x10) pos_td++; - if ( (card_ptr->atr[1] & 0x20) == 0x20) pos_td++; - if ( (card_ptr->atr[1] & 0x40) == 0x40) pos_td++; - - // T0 indicate presence T=0 vs T=1. T=1 has checksum TCK - if ( (card_ptr->atr[1] & 0x80) == 0x80) { - - pos_td++; - - // 1 == T1 , presence of checksum TCK - if ( (card_ptr->atr[pos_td] & 0x01) == 0x01) { - uint8_t chksum = 0; - // xor property. will be zero when xored with chksum. - for (uint8_t i = 1; i < len; ++i) - chksum ^= card_ptr->atr[i]; - if ( chksum ) { - if ( MF_DBGLEVEL > 2) DbpString("Wrong ATR checksum"); - } - } - } - card_ptr->atr_len = len; LogTrace(card_ptr->atr, card_ptr->atr_len, 0, 0, NULL, false); diff --git a/client/Makefile b/client/Makefile index 81b46f23..aafbe375 100644 --- a/client/Makefile +++ b/client/Makefile @@ -35,13 +35,27 @@ APP_CFLAGS = include ../common/Makefile_Enabled_Options.common CFLAGS += $(APP_CFLAGS) ifneq (,$(findstring WITH_SMARTCARD,$(APP_CFLAGS))) - SRC_SMARTCARD = cmdsmartcard.c + SRC_SMARTCARD = cmdsmartcard.c pcsc.c else SRC_SMARTCARD = endif -LUAPLATFORM = generic platform = $(shell uname) + +ifneq (,$(findstring MINGW,$(platform))) + PCSC_INCLUDES := + PCSC_LIBS = -lwinscard +else + ifeq ($(platform),Darwin) + PCSC_INCLUDES = + PCSC_LIBS = -framework PCSC + else + PCSC_INCLUDES := $(shell pkg-config --cflags libpcsclite) + PCSC_LIBS := $(shell pkg-config --libs libpcsclite) + endif +endif + +LUAPLATFORM = generic ifneq (,$(findstring MINGW,$(platform))) LUAPLATFORM = mingw else @@ -259,7 +273,7 @@ all: lua_build jansson_build mbedtls_build cbor_build $(BINS) all-static: LDLIBS:=-static $(LDLIBS) all-static: proxmark3 flasher fpga_compress -proxmark3: LDLIBS+=$(LUALIB) $(JANSSONLIB) $(MBEDTLSLIB) $(CBORLIB) $(QTLDLIBS) +proxmark3: LDLIBS+=$(LUALIB) $(JANSSONLIB) $(MBEDTLSLIB) $(CBORLIB) $(QTLDLIBS) $(PCSC_LIBS) proxmark3: $(OBJDIR)/proxmark3.o $(COREOBJS) $(CMDOBJS) $(OBJCOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(ZLIBOBJS) lualibs/usb_cmd.lua $(LD) $(LDFLAGS) $(OBJDIR)/proxmark3.o $(COREOBJS) $(CMDOBJS) $(OBJCOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(ZLIBOBJS) $(LDLIBS) -o $@ @@ -328,7 +342,7 @@ $(OBJDIR)/%_AVX512.o : %.c $(OBJDIR)/%.d %.o: %.c $(OBJDIR)/%.o : %.c $(OBJDIR)/%.d - $(CC) $(DEPFLAGS) $(CFLAGS) $(ZLIBFLAGS) -c -o $@ $< + $(CC) $(DEPFLAGS) $(CFLAGS) $(ZLIBFLAGS) $(PCSC_INCLUDES) -c -o $@ $< $(POSTCOMPILE) %.o: %.cpp diff --git a/client/cmdhw.c b/client/cmdhw.c index f994e938..b6a0d11f 100644 --- a/client/cmdhw.c +++ b/client/cmdhw.c @@ -20,7 +20,8 @@ #include "cmdmain.h" #include "cmddata.h" -/* low-level hardware control */ + +static uint32_t hw_capabilities = 0; static int CmdHelp(const char *Cmd); @@ -403,6 +404,10 @@ int CmdTune(const char *Cmd) return CmdTuneSamples(Cmd); } +bool PM3hasSmartcardSlot(void) { + return (hw_capabilities & HAS_SMARTCARD_SLOT); +} + int CmdVersion(const char *Cmd) { @@ -411,10 +416,11 @@ int CmdVersion(const char *Cmd) UsbCommand resp = {0, {0, 0, 0}}; SendCommand(&c); - if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) { + if (WaitForResponseTimeout(CMD_ACK, &resp, 1000)) { PrintAndLog("Prox/RFID mark3 RFID instrument"); PrintAndLog((char*)resp.d.asBytes); lookupChipID(resp.arg[0], resp.arg[1]); + hw_capabilities = resp.arg[2]; } return 0; } diff --git a/client/cmdhw.h b/client/cmdhw.h index b8e10f74..2db2fecc 100644 --- a/client/cmdhw.h +++ b/client/cmdhw.h @@ -11,6 +11,8 @@ #ifndef CMDHW_H__ #define CMDHW_H__ +#include + int CmdHW(const char *Cmd); int CmdDetectReader(const char *Cmd); @@ -23,5 +25,6 @@ int CmdSetDivisor(const char *Cmd); int CmdSetMux(const char *Cmd); int CmdTune(const char *Cmd); int CmdVersion(const char *Cmd); +bool PM3hasSmartcardSlot(void); #endif diff --git a/client/cmdsmartcard.c b/client/cmdsmartcard.c index edd51b72..a1793240 100644 --- a/client/cmdsmartcard.c +++ b/client/cmdsmartcard.c @@ -18,14 +18,18 @@ #include "smartcard.h" #include "comms.h" #include "protocols.h" +#include "cmdhw.h" #include "cmdhflist.h" #include "emv/apduinfo.h" // APDUcode description #include "emv/emvcore.h" // decodeTVL #include "crypto/libpcrypto.h" // sha512hash #include "emv/dump.h" // dump_buffer +#include "pcsc.h" #define SC_UPGRADE_FILES_DIRECTORY "sc_upgrade_firmware/" +static bool UseAlternativeSmartcardReader = false; // default: use PM3 RDV40 Smartcard Slot (if available) + static int CmdHelp(const char *Cmd); static int usage_sm_raw(void) { @@ -44,6 +48,17 @@ static int usage_sm_raw(void) { return 0; } +static int usage_sm_select(void) { + PrintAndLogEx(NORMAL, "Usage: sc select [h|] "); + PrintAndLogEx(NORMAL, " h : this help"); + PrintAndLogEx(NORMAL, " : a card reader's name, wildcards allowed, leave empty to pick from available readers"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " sc select : list available card readers and pick"); + PrintAndLogEx(NORMAL, " sc select Gemalto* : select a connected Gemalto card reader" ); + return 0; +} + static int usage_sm_reader(void) { PrintAndLogEx(NORMAL, "Usage: sc reader [h|s]"); PrintAndLogEx(NORMAL, " h : this help"); @@ -185,6 +200,8 @@ static int PrintATR(uint8_t *atr, size_t atrlen) { uint8_t T0 = atr[1]; uint8_t K = T0 & 0x0F; uint8_t TD1 = 0, T1len = 0, TD1len = 0, TDilen = 0; + bool protocol_T0_present = true; + bool protocol_T15_present = false; if (T0 & 0x10) { PrintAndLog("\t- TA1 (Maximum clock frequency, proposed bit duration) [ 0x%02x ]", atr[2 + T1len]); @@ -204,6 +221,14 @@ static int PrintATR(uint8_t *atr, size_t atrlen) { if (T0 & 0x80) { TD1 = atr[2 + T1len]; PrintAndLog("\t- TD1 (First offered transmission protocol, presence of TA2..TD2) [ 0x%02x ] Protocol T%d", TD1, TD1 & 0x0f); + protocol_T0_present = false; + if ((TD1 & 0x0f) == 0) { + protocol_T0_present = true; + } + if ((TD1 & 0x0f) == 15) { + protocol_T15_present = true; + } + T1len++; if (TD1 & 0x10) { @@ -221,6 +246,12 @@ static int PrintATR(uint8_t *atr, size_t atrlen) { if (TD1 & 0x80) { uint8_t TDi = atr[2 + T1len + TD1len]; PrintAndLog("\t- TD2 (A supported protocol or more global parameters, presence of TA3..TD3) [ 0x%02x ] Protocol T%d", TDi, TDi & 0x0f); + if ((TDi & 0x0f) == 0) { + protocol_T0_present = true; + } + if ((TDi & 0x0f) == 15) { + protocol_T15_present = true; + } TD1len++; bool nextCycle = true; @@ -251,26 +282,27 @@ static int PrintATR(uint8_t *atr, size_t atrlen) { } } - uint8_t vxor = 0; - for (int i = 1; i < atrlen; i++) - vxor ^= atr[i]; + if (!protocol_T0_present || protocol_T15_present) { // there is CRC Check Byte TCK + uint8_t vxor = 0; + for (int i = 1; i < atrlen; i++) + vxor ^= atr[i]; + + if (vxor) + PrintAndLogEx(WARNING, "Check sum error. Must be 0 got 0x%02X", vxor); + else + PrintAndLogEx(INFO, "Check sum OK."); + } - if (vxor) - PrintAndLogEx(WARNING, "Check summ error. Must be 0 got 0x%02X", vxor); - else - PrintAndLogEx(INFO, "Check summ OK."); - if (atr[0] != 0x3b) PrintAndLogEx(WARNING, "Not a direct convention [ 0x%02x ]", atr[0]); - uint8_t calen = 2 + T1len + TD1len + TDilen + K; if (atrlen != calen && atrlen != calen + 1) // may be CRC PrintAndLogEx(ERR, "ATR length error. len: %d, T1len: %d, TD1len: %d, TDilen: %d, K: %d", atrlen, T1len, TD1len, TDilen, K); if (K > 0) - PrintAndLogEx(INFO, "\nHistorical bytes | len 0x%02d | format %02x", K, atr[2 + T1len + TD1len + TDilen]); + PrintAndLogEx(INFO, "\nHistorical bytes | len %02d | format %02x", K, atr[2 + T1len + TD1len + TDilen]); if (K > 1) { PrintAndLogEx(INFO, "\tHistorical bytes"); @@ -280,26 +312,38 @@ static int PrintATR(uint8_t *atr, size_t atrlen) { return 0; } -static bool smart_select(bool silent) { - UsbCommand c = {CMD_SMART_ATR, {0, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - if ( !WaitForResponseTimeout(CMD_ACK, &resp, 2500) ) { - if (!silent) PrintAndLogEx(WARNING, "smart card select failed"); - return false; - } +static bool smart_getATR(smart_card_atr_t *card) +{ + if (UseAlternativeSmartcardReader) { + return pcscGetATR(card); + } else { + UsbCommand c = {CMD_SMART_ATR, {0, 0, 0}}; + SendCommand(&c); - uint8_t isok = resp.arg[0] & 0xFF; - if (!isok) { + UsbCommand resp; + if ( !WaitForResponseTimeout(CMD_ACK, &resp, 2500) ) { + return false; + } + + if (resp.arg[0] & 0xff) { + return resp.arg[0] & 0xFF; + } + + memcpy(card, (smart_card_atr_t *)resp.d.asBytes, sizeof(smart_card_atr_t)); + + return true; + } +} + +static bool smart_select(bool silent) { + + smart_card_atr_t card; + if (!smart_getATR(&card)) { if (!silent) PrintAndLogEx(WARNING, "smart card select failed"); return false; } if (!silent) { - smart_card_atr_t card; - memcpy(&card, (smart_card_atr_t *)resp.d.asBytes, sizeof(smart_card_atr_t)); - PrintAndLogEx(INFO, "ISO7816-3 ATR : %s", sprint_hex(card.atr, card.atr_len)); } @@ -379,6 +423,32 @@ static int smart_response(uint8_t *data) { return datalen; } + +int CmdSmartSelect(const char *Cmd) { + + const char *readername; + + if (tolower(param_getchar(Cmd, 0)) == 'h') { + return usage_sm_select(); + } + + if (!PM3hasSmartcardSlot() && !pcscCheckForCardReaders()) { + PrintAndLogEx(WARNING, "No Smartcard Readers available"); + UseAlternativeSmartcardReader = false; + return 1; + } + + int bg, en; + if (param_getptr(Cmd, &bg, &en, 0)) { + UseAlternativeSmartcardReader = pcscSelectAlternativeCardReader(NULL); + } else { + readername = Cmd + bg; + UseAlternativeSmartcardReader = pcscSelectAlternativeCardReader(readername); + } + + return 0; +} + int CmdSmartRaw(const char *Cmd) { int hexlen = 0; @@ -756,23 +826,11 @@ int CmdSmartInfo(const char *Cmd){ //Validations if (errors ) return usage_sm_info(); - UsbCommand c = {CMD_SMART_ATR, {0, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - if ( !WaitForResponseTimeout(CMD_ACK, &resp, 2500) ) { - if (!silent) PrintAndLogEx(WARNING, "smart card select failed"); - return 1; - } - - uint8_t isok = resp.arg[0] & 0xFF; - if (!isok) { - if (!silent) PrintAndLogEx(WARNING, "smart card select failed"); - return 1; - } - smart_card_atr_t card; - memcpy(&card, (smart_card_atr_t *)resp.d.asBytes, sizeof(smart_card_atr_t)); + if (!smart_getATR(&card)) { + if (!silent) PrintAndLogEx(WARNING, "smart card select failed"); + return 1; + } // print header PrintAndLogEx(INFO, "--- Smartcard Information ---------"); @@ -830,22 +888,11 @@ int CmdSmartReader(const char *Cmd){ //Validations if (errors ) return usage_sm_reader(); - UsbCommand c = {CMD_SMART_ATR, {0, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - if ( !WaitForResponseTimeout(CMD_ACK, &resp, 2500) ) { - if (!silent) PrintAndLogEx(WARNING, "smart card select failed"); - return 1; - } - - uint8_t isok = resp.arg[0] & 0xFF; - if (!isok) { - if (!silent) PrintAndLogEx(WARNING, "smart card select failed"); - return 1; - } smart_card_atr_t card; - memcpy(&card, (smart_card_atr_t *)resp.d.asBytes, sizeof(smart_card_atr_t)); + if (!smart_getATR(&card)) { + if (!silent) PrintAndLogEx(WARNING, "smart card select failed"); + return 1; + } PrintAndLogEx(INFO, "ISO7816-3 ATR : %s", sprint_hex(card.atr, card.atr_len)); return 0; @@ -970,6 +1017,7 @@ int CmdSmartBruteforceSFI(const char *Cmd) { static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, + {"select", CmdSmartSelect, 1, "Select the Smartcard Reader to use"}, {"list", CmdSmartList, 0, "List ISO 7816 history"}, {"info", CmdSmartInfo, 0, "Tag information"}, {"reader", CmdSmartReader, 0, "Act like an IS07816 reader"}, diff --git a/client/pcsc.c b/client/pcsc.c new file mode 100644 index 00000000..dd331d0a --- /dev/null +++ b/client/pcsc.c @@ -0,0 +1,177 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2019 piwi +// +// 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. +//----------------------------------------------------------------------------- +// PCSC functions to use alternative Smartcard Readers +//----------------------------------------------------------------------------- + +#include "pcsc.h" + +#include +#include +#include +#include + +#if defined (__APPLE__) +#include +#include +#define SCARD_ATTR_VALUE(Class, Tag) ((((ULONG)(Class)) << 16) | ((ULONG)(Tag))) +#define SCARD_CLASS_ICC_STATE 9 +#define SCARD_ATTR_ATR_STRING SCARD_ATTR_VALUE(SCARD_CLASS_ICC_STATE, 0x0303) +#elif defined (_WIN32) +#include +#else +#include +#include +#endif + +#include "ui.h" +#include "util.h" +#include "cmdhw.h" + +static SCARDCONTEXT SC_Context; +static SCARDHANDLE SC_Card; +static DWORD SC_Protocol; +static char* AlternativeSmartcardReader = NULL; + + +char *getAlternativeSmartcardReader(void) +{ + return AlternativeSmartcardReader; +} + + +bool pcscCheckForCardReaders(void) +{ + LONG res = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &SC_Context); + if (res != SCARD_S_SUCCESS) { + return false; + } + + DWORD pcchReaders; + res = SCardListReaders(SC_Context, NULL, NULL, &pcchReaders); + if (res != SCARD_S_SUCCESS) { + SCardReleaseContext(SC_Context); + return false; + } + + if (res == SCARD_E_NO_READERS_AVAILABLE || res == SCARD_E_NO_SERVICE) { + SCardReleaseContext(SC_Context); + return false; + } + + return true; +} + + +static char *pickReader(LPTSTR readerlist) +{ + PrintAndLogEx(NORMAL, "Please select one of these:"); + PrintAndLogEx(NORMAL, " [0] PM3 RDV40 Smartcard Slot %s", PM3hasSmartcardSlot() ? "(default)" : "(default, not available)"); + + int num = 1; + for (LPTSTR p = readerlist; *p != '\0'; ) { + PrintAndLogEx(NORMAL, " [%1d] %s", num++, p); + while (*p++ != '\0') ; // advance to next entry + } + + num--; + + if (num == 1) { + printf("Your choice (0 or 1)?"); + } else { + printf("Your choice (0...%d)? ", num); + } + int selection = getch() - '0'; + printf("\n"); + + if (selection == 0) { + PrintAndLogEx(INFO, "Selected RDV40 Smartcard Slot"); + return NULL; + } + + if (selection >= 1 && selection <= num) { + LPTSTR p = readerlist; + for (int i = 1; i < selection; i++) { + while (*p++ != '\0') ; // advance to next entry + } + PrintAndLogEx(INFO, "Selected %s", p); + return p; + } + + PrintAndLogEx(INFO, "Invalid selection. Using RDV40 Smartcard Slot"); + return NULL; + +} + + +char *matchString(LPTSTR readerlist, const char *readername) +{ + return pickReader(readerlist); +} + + +bool pcscSelectAlternativeCardReader(const char *readername) +{ + DWORD readerlist_len; + LONG res = SCardListReaders(SC_Context, NULL, NULL, &readerlist_len); + if (res != SCARD_S_SUCCESS) { + return false; + } + + LPTSTR readerlist = calloc(readerlist_len, sizeof(char)); + res = SCardListReaders(SC_Context, NULL, readerlist, &readerlist_len); + if (res != SCARD_S_SUCCESS) { + free(readerlist); + return false; + } + + char *selected_readername = NULL; + if (readername) { + selected_readername = matchString(readerlist, readername); + } else { + selected_readername = pickReader(readerlist); + } + + if (selected_readername == NULL) { + free(readerlist); + return false; + } + + free(AlternativeSmartcardReader); + AlternativeSmartcardReader = malloc((strlen(selected_readername) + 1) * sizeof(char)); + strcpy(AlternativeSmartcardReader, selected_readername); + + return true; +} + + +bool pcscGetATR(smart_card_atr_t *card) +{ + if (!card) { + return false; + } + + card->atr_len = 0; + memset(card->atr, 0, sizeof(card->atr)); + + LONG res = SCardConnect(SC_Context, AlternativeSmartcardReader, SCARD_SHARE_SHARED, + SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &SC_Card, &SC_Protocol); + if (res != SCARD_S_SUCCESS) { + return false; + } + + DWORD atr_len = sizeof(card->atr); + res = SCardGetAttrib(SC_Card, SCARD_ATTR_ATR_STRING, card->atr, &atr_len); + if (res != SCARD_S_SUCCESS) { + return false; + } + card->atr_len = atr_len; + + // TODO: LogTrace without device + + return true; +} diff --git a/client/pcsc.h b/client/pcsc.h new file mode 100644 index 00000000..3dae06c0 --- /dev/null +++ b/client/pcsc.h @@ -0,0 +1,22 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2019 piwi +// +// 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. +//----------------------------------------------------------------------------- +// PCSC functions to use alternative Smartcard Readers +//----------------------------------------------------------------------------- + +#ifndef PCSC_H__ +#define PCSC_H__ + +#include +#include "smartcard.h" + +char *getAlternativeSmartcardReader(void); +bool pcscCheckForCardReaders(void); +bool pcscSelectAlternativeCardReader(const char *readername); +bool pcscGetATR(smart_card_atr_t *card); + +#endif diff --git a/client/proxmark3.c b/client/proxmark3.c index 6fb066e8..a25ecb41 100644 --- a/client/proxmark3.c +++ b/client/proxmark3.c @@ -28,6 +28,8 @@ #include "cmdhw.h" #include "whereami.h" #include "comms.h" +#include "pcsc.h" + void #ifdef __has_attribute @@ -48,6 +50,7 @@ main_loop(char *script_cmds_file, char *script_cmd, bool usb_present) { SetOffline(true); } + // file with script FILE *script_file = NULL; char script_cmd_buf[256] = {0}; // iceman, needs lua script the same file_path_buffer as the rest diff --git a/client/util.c b/client/util.c index dec7c5a1..f13d730c 100644 --- a/client/util.c +++ b/client/util.c @@ -52,7 +52,22 @@ int ukbhit(void) return ( error == 0 ? cnt : -1 ); } -#else +char getch(void) +{ + char c; + int error; + struct termios Otty, Ntty; + if ( tcgetattr(STDIN_FILENO, &Otty) == -1 ) return -1; + Ntty = Otty; + Ntty.c_lflag &= ~ICANON; /* disable buffered i/o */ + if (0 == (error = tcsetattr(STDIN_FILENO, TCSANOW, &Ntty))) { // set new attributes + c = getchar(); + error += tcsetattr(STDIN_FILENO, TCSANOW, &Otty); // reset attributes + } + return ( error == 0 ? c : -1 ); +} + +#else // _WIN32 #include int ukbhit(void) { diff --git a/client/util.h b/client/util.h index e3549c02..29dd7d5c 100644 --- a/client/util.h +++ b/client/util.h @@ -76,6 +76,11 @@ #endif extern int ukbhit(void); +#ifndef _WIN32 +extern char getch(void); +#else +#include +#endif extern void AddLogLine(char *fileName, char *extData, char *c); extern void AddLogHex(char *fileName, char *extData, const uint8_t * data, const size_t len); diff --git a/include/smartcard.h b/include/smartcard.h index 70245a78..82b346f5 100644 --- a/include/smartcard.h +++ b/include/smartcard.h @@ -10,6 +10,8 @@ #ifndef __SMARTCARD_H #define __SMARTCARD_H +#include + //----------------------------------------------------------------------------- // ISO 7618 Smart Card //----------------------------------------------------------------------------- diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 785435f0..4c27ac85 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -33,6 +33,7 @@ typedef struct { uint32_t asDwords[USB_CMD_DATA_SIZE/4]; } d; } PACKED UsbCommand; + // A struct used to send sample-configs over USB typedef struct{ uint8_t decimation; @@ -63,6 +64,9 @@ typedef struct{ #define CMD_STATUS 0x0108 #define CMD_PING 0x0109 +// controlling the ADC input multiplexer +#define CMD_SET_ADC_MUX 0x020F + // RDV40, Smart card operations #define CMD_SMART_RAW 0x0140 #define CMD_SMART_UPGRADE 0x0141 @@ -86,7 +90,6 @@ typedef struct{ #define CMD_HID_SIM_TAG 0x020C #define CMD_SET_LF_DIVISOR 0x020D #define CMD_LF_SIMULATE_BIDIR 0x020E -#define CMD_SET_ADC_MUX 0x020F #define CMD_HID_CLONE_TAG 0x0210 #define CMD_EM410X_WRITE_TAG 0x0211 #define CMD_INDALA_CLONE_TAG 0x0212 @@ -112,12 +115,8 @@ typedef struct{ #define CMD_VIKING_CLONE_TAG 0x0223 #define CMD_T55XX_WAKEUP 0x0224 #define CMD_COTAG 0x0225 -// misc extra #define CMD_PARADOX_CLONE_TAG 0x0226 - -/* CMD_SET_ADC_MUX: ext1 is 0 for lopkd, 1 for loraw, 2 for hipkd, 3 for hiraw */ - // For the 13.56 MHz tags #define CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693 0x0300 #define CMD_READ_SRI512_TAG 0x0303 @@ -136,7 +135,6 @@ typedef struct{ #define CMD_SNOOP_HITAG 0x0370 #define CMD_SIMULATE_HITAG 0x0371 #define CMD_READER_HITAG 0x0372 - #define CMD_SIMULATE_HITAG_S 0x0368 #define CMD_TEST_HITAGS_TRACES 0x0367 #define CMD_READ_HITAG_S 0x0373 @@ -144,7 +142,6 @@ typedef struct{ #define CMD_WR_HITAG_S 0x0375 #define CMD_EMU_HITAG_S 0x0376 - #define CMD_SIMULATE_TAG_ISO_14443B 0x0381 #define CMD_SNOOP_ISO_14443B 0x0382 #define CMD_SNOOP_ISO_14443a 0x0383 @@ -251,6 +248,10 @@ typedef struct{ #define FLAG_TUNE_HF 2 #define FLAG_TUNE_ALL 3 +// Hardware capabilities +#define HAS_EXTRA_FLASH_MEM (1 << 0) +#define HAS_SMARTCARD_SLOT (1 << 1) + // CMD_DEVICE_INFO response packet has flags in arg[0], flag definitions: /* Whether a bootloader that understands the common_area is present */ From 437035a75b2737d0b36886bc2bacaeb0219c6325 Mon Sep 17 00:00:00 2001 From: AntiCat Date: Wed, 30 Jan 2019 22:20:57 +0100 Subject: [PATCH 054/189] Legic TagSim: increased reader timeout (#771) Bug reports from @raphCode and @uhei over at the RfidResearchGroup have shown that the tag to rwd timeout is too short. --- armsrc/legicrfsim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armsrc/legicrfsim.c b/armsrc/legicrfsim.c index a149e0f9..1411fbea 100644 --- a/armsrc/legicrfsim.c +++ b/armsrc/legicrfsim.c @@ -51,7 +51,7 @@ static uint32_t last_frame_end; /* ts of last bit of previews rx or tx frame */ #define RWD_TIME_PAUSE 4 /* 18.9us */ #define RWD_TIME_1 21 /* RWD_TIME_PAUSE 18.9us off + 80.2us on = 99.1us */ #define RWD_TIME_0 13 /* RWD_TIME_PAUSE 18.9us off + 42.4us on = 61.3us */ -#define RWD_CMD_TIMEOUT 40 /* 40 * 99.1us (arbitrary value) */ +#define RWD_CMD_TIMEOUT 120 /* 120 * 99.1us (arbitrary value) */ #define RWD_MIN_FRAME_LEN 6 /* Shortest frame is 6 bits */ #define RWD_MAX_FRAME_LEN 23 /* Longest frame is 23 bits */ From 6b5105bea972d055bb2069bf8ca2c6d105b2ee8f Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Fri, 1 Feb 2019 21:12:20 +0100 Subject: [PATCH 055/189] Adding support for standard USB Smartcard Readers (#769) * add PCSC reader support to 'sc raw' and all 'emv' commands * move all APDU -> TPDU mapping to ExchangeAPDUSC() * print "PSE" instead of "PPSE" when using contact interface * fix some #defines in protocols.h * DropField only when using contactless * some refactoring --- client/cmdhffido.c | 2 +- client/cmdsmartcard.c | 300 +++++++++++++++++++---------------------- client/cmdsmartcard.h | 6 - client/emv/cmdemv.c | 115 +++++++++------- client/emv/emvcore.c | 158 ++++++++++++++-------- client/emv/emvcore.h | 17 +-- client/fido/fidocore.c | 54 +++++--- client/fido/fidocore.h | 2 +- client/pcsc.c | 38 ++++++ client/pcsc.h | 1 + client/proxmark3.c | 1 - common/protocols.h | 5 +- 12 files changed, 388 insertions(+), 311 deletions(-) diff --git a/client/cmdhffido.c b/client/cmdhffido.c index 9c812860..92f5d6cd 100644 --- a/client/cmdhffido.c +++ b/client/cmdhffido.c @@ -61,7 +61,7 @@ int CmdHFFidoInfo(const char *cmd) { PrintAndLog("--------------------------------------------"); SetAPDULogging(false); - uint8_t buf[APDU_RES_LEN] = {0}; + uint8_t buf[APDU_RESPONSE_LEN] = {0}; size_t len = 0; uint16_t sw = 0; int res = FIDOSelect(true, true, buf, sizeof(buf), &len, &sw); diff --git a/client/cmdsmartcard.c b/client/cmdsmartcard.c index a1793240..90a219ab 100644 --- a/client/cmdsmartcard.c +++ b/client/cmdsmartcard.c @@ -43,8 +43,7 @@ static int usage_sm_raw(void) { PrintAndLogEx(NORMAL, " d : bytes to send"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " sc raw s 0 d 00a404000e315041592e5359532e4444463031 - `1PAY.SYS.DDF01` PPSE directory with get ATR"); - PrintAndLogEx(NORMAL, " sc raw 0 d 00a404000e325041592e5359532e4444463031 - `2PAY.SYS.DDF01` PPSE directory"); + PrintAndLogEx(NORMAL, " sc raw s 0 d 00a404000e315041592e5359532e4444463031 - `1PAY.SYS.DDF01` PSE directory with get ATR"); return 0; } @@ -177,19 +176,19 @@ float FArray[] = { 0 // b1111 RFU }; -int GetATRDi(uint8_t *atr, size_t atrlen) { +static int GetATRDi(uint8_t *atr, size_t atrlen) { uint8_t TA1 = GetATRTA1(atr, atrlen); return DiArray[TA1 & 0x0f]; // The 4 low-order bits of TA1 (4th MSbit to 1st LSbit) encode Di } -int GetATRFi(uint8_t *atr, size_t atrlen) { +static int GetATRFi(uint8_t *atr, size_t atrlen) { uint8_t TA1 = GetATRTA1(atr, atrlen); return FiArray[TA1 >> 4]; // The 4 high-order bits of TA1 (8th MSbit to 5th LSbit) encode fmax and Fi } -float GetATRF(uint8_t *atr, size_t atrlen) { +static float GetATRF(uint8_t *atr, size_t atrlen) { uint8_t TA1 = GetATRTA1(atr, atrlen); return FArray[TA1 >> 4]; // The 4 high-order bits of TA1 (8th MSbit to 5th LSbit) encode fmax and Fi @@ -350,82 +349,48 @@ static bool smart_select(bool silent) { return true; } -static int smart_wait(uint8_t *data) { - UsbCommand resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) { - PrintAndLogEx(WARNING, "smart card response timeout"); - return -1; - } - uint32_t len = resp.arg[0]; - if ( !len ) { - PrintAndLogEx(WARNING, "smart card response failed"); - return -2; - } - memcpy(data, resp.d.asBytes, len); - if (len >= 2) { - PrintAndLogEx(SUCCESS, "%02X%02X | %s", data[len - 2], data[len - 1], GetAPDUCodeDescription(data[len - 2], data[len - 1])); +static void smart_transmit(uint8_t *data, uint32_t data_len, uint32_t flags, uint8_t *response, int *response_len, uint32_t max_response_len) +{ + // PrintAndLogEx(SUCCESS, "C-TPDU>>>> %s", sprint_hex(data, data_len)); + if (UseAlternativeSmartcardReader) { + *response_len = max_response_len; + pcscTransmit(data, data_len, flags, response, response_len); } else { - PrintAndLogEx(SUCCESS, " %d | %s", len, sprint_hex_inrow_ex(data, len, 8)); - } - - return len; -} + UsbCommand c = {CMD_SMART_RAW, {flags, data_len, 0}}; + memcpy(c.d.asBytes, data, data_len); + SendCommand(&c); -static int smart_response(uint8_t *data) { - - int datalen = smart_wait(data); - bool needGetData = false; - - if (datalen < 2 ) { - goto out; - } - - if ( data[datalen - 2] == 0x61 || data[datalen - 2] == 0x9F ) { - needGetData = true; - } - - if (needGetData) { - int len = data[datalen - 1]; - PrintAndLogEx(INFO, "Requesting 0x%02X bytes response", len); - uint8_t getstatus[] = {0x00, ISO7816_GETSTATUS, 0x00, 0x00, len}; - UsbCommand cStatus = {CMD_SMART_RAW, {SC_RAW, sizeof(getstatus), 0}}; - memcpy(cStatus.d.asBytes, getstatus, sizeof(getstatus) ); - clearCommandBuffer(); - SendCommand(&cStatus); - - datalen = smart_wait(data); - - if (datalen < 2 ) { - goto out; + if (!WaitForResponseTimeout(CMD_ACK, &c, 2500)) { + PrintAndLogEx(WARNING, "smart card response timeout"); + *response_len = -1; + return; } - // data wo ACK - if (datalen != len + 2) { - // data with ACK - if (datalen == len + 2 + 1) { // 2 - response, 1 - ACK - if (data[0] != ISO7816_GETSTATUS) { - PrintAndLogEx(ERR, "GetResponse ACK error. len 0x%x | data[0] %02X", len, data[0]); - datalen = 0; - goto out; - } - - datalen--; - memmove(data, &data[1], datalen); - } else { - // wrong length - PrintAndLogEx(WARNING, "GetResponse wrong length. Must be 0x%02X got 0x%02X", len, datalen - 3); - } + *response_len = c.arg[0]; + if (*response_len > 0) { + memcpy(response, c.d.asBytes, *response_len); } } - out: - return datalen; + if (*response_len <= 0) { + PrintAndLogEx(WARNING, "smart card response failed"); + *response_len = -2; + return; + } + + if (*response_len < 2) { + // PrintAndLogEx(SUCCESS, "R-TPDU %02X | ", response[0]); + return; + } + + // PrintAndLogEx(SUCCESS, "R-TPDU<<<< %s", sprint_hex(response, *response_len)); + // PrintAndLogEx(SUCCESS, "R-TPDU SW %02X%02X | %s", response[*response_len-2], response[*response_len-1], GetAPDUCodeDescription(response[*response_len-2], response[*response_len-1])); } -int CmdSmartSelect(const char *Cmd) { - +static int CmdSmartSelect(const char *Cmd) +{ const char *readername; if (tolower(param_getchar(Cmd, 0)) == 'h') { @@ -449,7 +414,8 @@ int CmdSmartSelect(const char *Cmd) { return 0; } -int CmdSmartRaw(const char *Cmd) { + +static int CmdSmartRaw(const char *Cmd) { int hexlen = 0; bool active = false; @@ -457,7 +423,7 @@ int CmdSmartRaw(const char *Cmd) { bool useT0 = false; uint8_t cmdp = 0; bool errors = false, reply = true, decodeTLV = false, breakloop = false; - uint8_t data[USB_CMD_DATA_SIZE] = {0x00}; + uint8_t data[ISO7816_MAX_FRAME_SIZE] = {0x00}; while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch (tolower(param_getchar(Cmd, cmdp))) { @@ -511,101 +477,107 @@ int CmdSmartRaw(const char *Cmd) { //Validations if (errors || cmdp == 0 ) return usage_sm_raw(); - // arg0 = RFU flags - // arg1 = length - UsbCommand c = {CMD_SMART_RAW, {0, hexlen, 0}}; - + uint32_t flags = 0; + uint32_t protocol = 0; if (active || active_select) { - c.arg[0] |= SC_CONNECT; + flags |= SC_CONNECT; if (active_select) - c.arg[0] |= SC_SELECT; + flags |= SC_SELECT; } - if (hexlen > 0) { if (useT0) - c.arg[0] |= SC_RAW_T0; + protocol = SC_RAW_T0; else - c.arg[0] |= SC_RAW; + protocol = SC_RAW; } - - memcpy(c.d.asBytes, data, hexlen ); - clearCommandBuffer(); - SendCommand(&c); + + int response_len = 0; + uint8_t *response = NULL; + if (reply) { + response = calloc(ISO7816_MAX_FRAME_SIZE, sizeof(uint8_t)); + if ( !response ) + return 1; + } + + smart_transmit(data, hexlen, flags|protocol, response, &response_len, ISO7816_MAX_FRAME_SIZE); // reading response from smart card if ( reply ) { - - uint8_t* buf = calloc(USB_CMD_DATA_SIZE, sizeof(uint8_t)); - if ( !buf ) - return 1; - - int len = smart_response(buf); - if ( len < 0 ) { - free(buf); + if ( response_len < 0 ) { + free(response); return 2; } - if ( buf[0] == 0x6C ) { - data[4] = buf[1]; - - memcpy(c.d.asBytes, data, sizeof(data) ); - clearCommandBuffer(); - SendCommand(&c); - len = smart_response(buf); - + if ( response[0] == 0x6C ) { + data[4] = response[1]; + smart_transmit(data, hexlen, protocol, response, &response_len, ISO7816_MAX_FRAME_SIZE); data[4] = 0; } - if (decodeTLV && len > 4) - TLVPrintFromBuffer(buf, len-2); + if (decodeTLV && response_len > 4) + TLVPrintFromBuffer(response, response_len-2); - free(buf); + free(response); } return 0; } -int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { - *dataoutlen = 0; + +int ExchangeAPDUSC(uint8_t *APDU, int APDUlen, bool activateCard, bool leaveSignalON, uint8_t *response, int maxresponselen, int *responselen) +{ + uint8_t TPDU[ISO7816_MAX_FRAME_SIZE]; + + *responselen = 0; if (activateCard) smart_select(false); - PrintAndLogEx(DEBUG, "APDU SC"); - - UsbCommand c = {CMD_SMART_RAW, {SC_RAW_T0, datainlen, 0}}; + uint32_t flags = SC_RAW_T0; if (activateCard) { - c.arg[0] |= SC_SELECT | SC_CONNECT; + flags |= SC_SELECT | SC_CONNECT; + } + + if (APDUlen == 4) { // Case 1 + memcpy(TPDU, APDU, 4); + TPDU[4] = 0x00; + smart_transmit(TPDU, 5, flags, response, responselen, maxresponselen); + } else if (APDUlen == 5) { // Case 2 Short + smart_transmit(APDU, 5, flags, response, responselen, maxresponselen); + if (response[0] == 0x6C) { // wrong Le + uint16_t Le = APDU[4] ? APDU[4] : 256; + uint8_t La = response[1]; + memcpy(TPDU, APDU, 5); + TPDU[4] = La; + smart_transmit(TPDU, 5, SC_RAW_T0, response, responselen, maxresponselen); + if (Le < La && *responselen >= 0) { + response[Le] = response[*responselen-2]; + response[Le+1] = response[*responselen-1]; + *responselen = Le + 2; + } + } + } else if (APDU[4] != 0 && APDUlen == 5 + APDU[4]) { // Case 3 Short + smart_transmit(APDU, APDUlen, flags, response, responselen, maxresponselen); + } else if (APDU[4] != 0 && APDUlen == 5 + APDU[4] + 1) { // Case 4 Short + smart_transmit(APDU, APDUlen-1, flags, response, responselen, maxresponselen); + if (response[0] == 0x90 && response[1] == 0x00) { + uint8_t Le = APDU[APDUlen-1]; + uint8_t get_response[5] = {0x00, ISO7816_GET_RESPONSE, 0x00, 0x00, Le}; + return ExchangeAPDUSC(get_response, 5, false, leaveSignalON, response, maxresponselen, responselen); + } + } else { // Long Cases not yet implemented + PrintAndLogEx(ERR, "Long APDUs not yet implemented"); + *responselen = -3; } - memcpy(c.d.asBytes, datain, datainlen); - clearCommandBuffer(); - SendCommand(&c); - int len = smart_response(dataout); - - if ( len < 0 ) { + if (*responselen < 0 ) { return 2; + } else { + return 0; } - - // retry - if (len > 1 && dataout[len - 2] == 0x6c && datainlen > 4) { - UsbCommand c2 = {CMD_SMART_RAW, {SC_RAW_T0, datainlen, 0}}; - memcpy(c2.d.asBytes, datain, 5); - - // transfer length via T=0 - c2.d.asBytes[4] = dataout[len - 1]; - - clearCommandBuffer(); - SendCommand(&c2); - - len = smart_response(dataout); - } - *dataoutlen = len; - - return 0; } -int CmdSmartUpgrade(const char *Cmd) { +static int CmdSmartUpgrade(const char *Cmd) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(WARNING, "WARNING - RDV4.0 Smartcard Socket Firmware upgrade."); @@ -805,7 +777,8 @@ int CmdSmartUpgrade(const char *Cmd) { return 0; } -int CmdSmartInfo(const char *Cmd){ + +static int CmdSmartInfo(const char *Cmd){ uint8_t cmdp = 0; bool errors = false, silent = false; @@ -898,7 +871,8 @@ int CmdSmartReader(const char *Cmd){ return 0; } -int CmdSmartSetClock(const char *Cmd){ + +static int CmdSmartSetClock(const char *Cmd){ uint8_t cmdp = 0; bool errors = false; uint8_t clock = 0; @@ -953,12 +927,14 @@ int CmdSmartSetClock(const char *Cmd){ return 0; } -int CmdSmartList(const char *Cmd) { + +static int CmdSmartList(const char *Cmd) { CmdHFList("7816"); return 0; } -int CmdSmartBruteforceSFI(const char *Cmd) { + +static int CmdSmartBruteforceSFI(const char *Cmd) { char ctmp = tolower(param_getchar(Cmd, 0)); if (ctmp == 'h') return usage_sm_brute(); @@ -970,16 +946,16 @@ int CmdSmartBruteforceSFI(const char *Cmd) { return 1; } - PrintAndLogEx(INFO, "Selecting PPSE aid"); + PrintAndLogEx(INFO, "Selecting PSE aid"); CmdSmartRaw("s 0 t d 00a404000e325041592e5359532e4444463031"); CmdSmartRaw("0 t d 00a4040007a000000004101000"); // mastercard // CmdSmartRaw("0 t d 00a4040007a0000000031010"); // visa PrintAndLogEx(INFO, "starting"); - UsbCommand c = {CMD_SMART_RAW, {SC_RAW, sizeof(data), 0}}; - uint8_t* buf = malloc(USB_CMD_DATA_SIZE); - if ( !buf ) + int response_len = 0; + uint8_t* response = malloc(ISO7816_MAX_FRAME_SIZE); + if (!response) return 1; for (uint8_t i=1; i < 4; i++) { @@ -988,53 +964,47 @@ int CmdSmartBruteforceSFI(const char *Cmd) { data[2] = p1; data[3] = (i << 3) + 4; - memcpy(c.d.asBytes, data, sizeof(data) ); - clearCommandBuffer(); - SendCommand(&c); + smart_transmit(data, sizeof(data), SC_RAW_T0, response, &response_len, ISO7816_MAX_FRAME_SIZE); - smart_response(buf); - - if ( buf[0] == 0x6C ) { - data[4] = buf[1]; - - memcpy(c.d.asBytes, data, sizeof(data) ); - clearCommandBuffer(); - SendCommand(&c); - uint8_t len = smart_response(buf); + if ( response[0] == 0x6C ) { + data[4] = response[1]; + smart_transmit(data, sizeof(data), SC_RAW_T0, response, &response_len, ISO7816_MAX_FRAME_SIZE); // TLV decoder - if (len > 4) - TLVPrintFromBuffer(buf+1, len-3); + if (response_len > 4) + TLVPrintFromBuffer(response+1, response_len-3); data[4] = 0; } - memset(buf, 0x00, USB_CMD_DATA_SIZE); + memset(response, 0x00, ISO7816_MAX_FRAME_SIZE); } } - free(buf); + free(response); return 0; } static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"select", CmdSmartSelect, 1, "Select the Smartcard Reader to use"}, - {"list", CmdSmartList, 0, "List ISO 7816 history"}, - {"info", CmdSmartInfo, 0, "Tag information"}, - {"reader", CmdSmartReader, 0, "Act like an IS07816 reader"}, - {"raw", CmdSmartRaw, 0, "Send raw hex data to tag"}, + {"list", CmdSmartList, 1, "List ISO 7816 history"}, + {"info", CmdSmartInfo, 1, "Tag information"}, + {"reader", CmdSmartReader, 1, "Act like an IS07816 reader"}, + {"raw", CmdSmartRaw, 1, "Send raw hex data to tag"}, {"upgrade", CmdSmartUpgrade, 0, "Upgrade firmware"}, - {"setclock", CmdSmartSetClock, 0, "Set clock speed"}, - {"brute", CmdSmartBruteforceSFI, 0, "Bruteforce SFI"}, + {"setclock", CmdSmartSetClock, 1, "Set clock speed"}, + {"brute", CmdSmartBruteforceSFI, 1, "Bruteforce SFI"}, {NULL, NULL, 0, NULL} }; + int CmdSmartcard(const char *Cmd) { clearCommandBuffer(); CmdsParse(CommandTable, Cmd); return 0; } -int CmdHelp(const char *Cmd) { + +static int CmdHelp(const char *Cmd) { CmdsHelp(CommandTable); return 0; } diff --git a/client/cmdsmartcard.h b/client/cmdsmartcard.h index 3a4c7956..310a417c 100644 --- a/client/cmdsmartcard.h +++ b/client/cmdsmartcard.h @@ -15,12 +15,6 @@ #include extern int CmdSmartcard(const char *Cmd); - -extern int CmdSmartRaw(const char* cmd); -extern int CmdSmartUpgrade(const char* cmd); -extern int CmdSmartInfo(const char* cmd); -extern int CmdSmartReader(const char *Cmd); - extern int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); #endif diff --git a/client/emv/cmdemv.c b/client/emv/cmdemv.c index e7676501..16835ba8 100644 --- a/client/emv/cmdemv.c +++ b/client/emv/cmdemv.c @@ -45,7 +45,7 @@ void ParamLoadDefaults(struct tlvdb *tlvRoot) { } int CmdEMVSelect(const char *cmd) { - uint8_t data[APDU_AID_LEN] = {0}; + uint8_t data[APDU_DATA_LEN] = {0}; int datalen = 0; CLIParserInit("emv select", @@ -83,7 +83,7 @@ int CmdEMVSelect(const char *cmd) { SetAPDULogging(APDULogging); // exec - uint8_t buf[APDU_RES_LEN] = {0}; + uint8_t buf[APDU_RESPONSE_LEN] = {0}; size_t len = 0; uint16_t sw = 0; int res = EMVSelect(channel, activateField, leaveSignalON, data, datalen, buf, sizeof(buf), &len, &sw, NULL); @@ -193,7 +193,7 @@ int CmdEMVPPSE(const char *cmd) { SetAPDULogging(APDULogging); // exec - uint8_t buf[APDU_RES_LEN] = {0}; + uint8_t buf[APDU_RESPONSE_LEN] = {0}; size_t len = 0; uint16_t sw = 0; int res = EMVSelectPSE(channel, activateField, leaveSignalON, PSENum, buf, sizeof(buf), &len, &sw); @@ -212,7 +212,7 @@ int CmdEMVPPSE(const char *cmd) { } int CmdEMVGPO(const char *cmd) { - uint8_t data[APDU_RES_LEN] = {0}; + uint8_t data[APDU_RESPONSE_LEN] = {0}; int datalen = 0; CLIParserInit("emv gpo", @@ -295,7 +295,7 @@ int CmdEMVGPO(const char *cmd) { PrintAndLogEx(INFO, "PDOL data[%d]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len)); // exec - uint8_t buf[APDU_RES_LEN] = {0}; + uint8_t buf[APDU_RESPONSE_LEN] = {0}; size_t len = 0; uint16_t sw = 0; int res = EMVGPO(channel, leaveSignalON, pdol_data_tlv_data, pdol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot); @@ -317,7 +317,7 @@ int CmdEMVGPO(const char *cmd) { } int CmdEMVReadRecord(const char *cmd) { - uint8_t data[APDU_RES_LEN] = {0}; + uint8_t data[APDU_RESPONSE_LEN] = {0}; int datalen = 0; CLIParserInit("emv readrec", @@ -356,7 +356,7 @@ int CmdEMVReadRecord(const char *cmd) { SetAPDULogging(APDULogging); // exec - uint8_t buf[APDU_RES_LEN] = {0}; + uint8_t buf[APDU_RESPONSE_LEN] = {0}; size_t len = 0; uint16_t sw = 0; int res = EMVReadRecord(channel, leaveSignalON, data[0], data[1], buf, sizeof(buf), &len, &sw, NULL); @@ -375,7 +375,7 @@ int CmdEMVReadRecord(const char *cmd) { } int CmdEMVAC(const char *cmd) { - uint8_t data[APDU_RES_LEN] = {0}; + uint8_t data[APDU_RESPONSE_LEN] = {0}; int datalen = 0; CLIParserInit("emv genac", @@ -474,7 +474,7 @@ int CmdEMVAC(const char *cmd) { PrintAndLogEx(INFO, "CDOL data[%d]: %s", cdol_data_tlv->len, sprint_hex(cdol_data_tlv->value, cdol_data_tlv->len)); // exec - uint8_t buf[APDU_RES_LEN] = {0}; + uint8_t buf[APDU_RESPONSE_LEN] = {0}; size_t len = 0; uint16_t sw = 0; int res = EMVAC(channel, leaveSignalON, termDecision, (uint8_t *)cdol_data_tlv->value, cdol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot); @@ -524,7 +524,7 @@ int CmdEMVGenerateChallenge(const char *cmd) { SetAPDULogging(APDULogging); // exec - uint8_t buf[APDU_RES_LEN] = {0}; + uint8_t buf[APDU_RESPONSE_LEN] = {0}; size_t len = 0; uint16_t sw = 0; int res = EMVGenerateChallenge(channel, leaveSignalON, buf, sizeof(buf), &len, &sw, NULL); @@ -544,7 +544,7 @@ int CmdEMVGenerateChallenge(const char *cmd) { } int CmdEMVInternalAuthenticate(const char *cmd) { - uint8_t data[APDU_RES_LEN] = {0}; + uint8_t data[APDU_RESPONSE_LEN] = {0}; int datalen = 0; CLIParserInit("emv intauth", @@ -624,7 +624,7 @@ int CmdEMVInternalAuthenticate(const char *cmd) { PrintAndLogEx(INFO, "DDOL data[%d]: %s", ddol_data_tlv->len, sprint_hex(ddol_data_tlv->value, ddol_data_tlv->len)); // exec - uint8_t buf[APDU_RES_LEN] = {0}; + uint8_t buf[APDU_RESPONSE_LEN] = {0}; size_t len = 0; uint16_t sw = 0; int res = EMVInternalAuthenticate(channel, leaveSignalON, data, datalen, buf, sizeof(buf), &len, &sw, NULL); @@ -711,10 +711,10 @@ void ProcessGPOResponseFormat1(struct tlvdb *tlvRoot, uint8_t *buf, size_t len, } int CmdEMVExec(const char *cmd) { - uint8_t buf[APDU_RES_LEN] = {0}; + uint8_t buf[APDU_RESPONSE_LEN] = {0}; size_t len = 0; uint16_t sw = 0; - uint8_t AID[APDU_AID_LEN] = {0}; + uint8_t AID[APDU_DATA_LEN] = {0}; size_t AIDlen = 0; uint8_t ODAiList[4096]; size_t ODAiListLen = 0; @@ -769,6 +769,8 @@ int CmdEMVExec(const char *cmd) { channel = ECC_CONTACT; #endif uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2; + char *PSE_or_PPSE = psenum == 1 ? "PSE" : "PPSE"; + CLIParserFree(); SetAPDULogging(showAPDU); @@ -780,12 +782,12 @@ int CmdEMVExec(const char *cmd) { // Application Selection // https://www.openscdp.org/scripts/tutorial/emv/applicationselection.html if (!forceSearch) { - // PPSE - PrintAndLogEx(NORMAL, "\n* PPSE."); + // PPSE / PSE + PrintAndLogEx(NORMAL, "\n* %s.", PSE_or_PPSE); SetAPDULogging(showAPDU); res = EMVSearchPSE(channel, activateField, true, psenum, decodeTLV, tlvSelect); - // check PPSE and select application id + // check PPSE / PSE and select application id if (!res) { TLVPrintAIDlistFromSelectTLV(tlvSelect); EMVSelectApplication(tlvSelect, AID, &AIDlen); @@ -1152,7 +1154,9 @@ int CmdEMVExec(const char *cmd) { } } - DropField(); + if (channel == ECC_CONTACTLESS) { + DropField(); + } // Destroy TLV's free(pdol_data_tlv); @@ -1164,9 +1168,9 @@ int CmdEMVExec(const char *cmd) { } int CmdEMVScan(const char *cmd) { - uint8_t AID[APDU_AID_LEN] = {0}; + uint8_t AID[APDU_DATA_LEN] = {0}; size_t AIDlen = 0; - uint8_t buf[APDU_RES_LEN] = {0}; + uint8_t buf[APDU_RESPONSE_LEN] = {0}; size_t len = 0; uint16_t sw = 0; int res; @@ -1260,8 +1264,10 @@ int CmdEMVScan(const char *cmd) { } // drop field at start - DropField(); - + if (channel == ECC_CONTACTLESS) { + DropField(); + } + // iso 14443 select PrintAndLogEx(NORMAL, "--> GET UID, ATS."); @@ -1329,7 +1335,9 @@ int CmdEMVScan(const char *cmd) { if (!AIDlen) { PrintAndLogEx(INFO, "Can't select AID. EMV AID not found. Exit..."); - DropField(); + if (channel == ECC_CONTACTLESS) { + DropField(); + } return 4; } @@ -1376,7 +1384,9 @@ int CmdEMVScan(const char *cmd) { if (!pdol_data_tlv){ PrintAndLogEx(ERR, "Can't create PDOL TLV."); tlvdb_free(tlvRoot); - DropField(); + if (channel == ECC_CONTACTLESS) { + DropField(); + } return 6; } @@ -1399,7 +1409,9 @@ int CmdEMVScan(const char *cmd) { if (res) { PrintAndLogEx(ERR, "GPO error(%d): %4x. Exit...", res, sw); tlvdb_free(tlvRoot); - DropField(); + if (channel == ECC_CONTACTLESS) { + DropField(); + } return 7; } ProcessGPOResponseFormat1(tlvRoot, buf, len, decodeTLV); @@ -1491,8 +1503,9 @@ int CmdEMVScan(const char *cmd) { // free tlv object tlvdb_free(tlvRoot); - // DropField - DropField(); + if (channel == ECC_CONTACTLESS) { + DropField(); + } res = json_dump_file(root, fname, JSON_INDENT(2)); if (res) { @@ -1512,9 +1525,9 @@ int CmdEMVTest(const char *cmd) { } int CmdEMVRoca(const char *cmd) { - uint8_t AID[APDU_AID_LEN] = {0}; + uint8_t AID[APDU_DATA_LEN] = {0}; size_t AIDlen = 0; - uint8_t buf[APDU_RES_LEN] = {0}; + uint8_t buf[APDU_RESPONSE_LEN] = {0}; size_t len = 0; uint16_t sw = 0; int res; @@ -1573,7 +1586,9 @@ int CmdEMVRoca(const char *cmd) { if (!AIDlen) { PrintAndLogEx(INFO, "Can't select AID. EMV AID not found. Exit..."); - DropField(); + if (channel == ECC_CONTACTLESS) { + DropField(); + } return 4; } @@ -1588,7 +1603,9 @@ int CmdEMVRoca(const char *cmd) { if (res) { PrintAndLogEx(ERR, "Can't select AID (%d). Exit...", res); tlvdb_free(tlvRoot); - DropField(); + if (channel == ECC_CONTACTLESS) { + DropField(); + } return 5; } @@ -1600,7 +1617,9 @@ int CmdEMVRoca(const char *cmd) { if (!pdol_data_tlv){ PrintAndLogEx(ERR, "Can't create PDOL TLV."); tlvdb_free(tlvRoot); - DropField(); + if (channel == ECC_CONTACTLESS) { + DropField(); + } return 6; } @@ -1623,7 +1642,9 @@ int CmdEMVRoca(const char *cmd) { if (res) { PrintAndLogEx(ERR, "GPO error(%d): %4x. Exit...", res, sw); tlvdb_free(tlvRoot); - DropField(); + if (channel == ECC_CONTACTLESS) { + DropField(); + } return 7; } ProcessGPOResponseFormat1(tlvRoot, buf, len, false); @@ -1721,9 +1742,9 @@ out: // free tlv object tlvdb_free(tlvRoot); - if ( channel == ECC_CONTACTLESS) + if (channel == ECC_CONTACTLESS) { DropField(); - + } return 0; } @@ -1732,18 +1753,18 @@ int CmdHelp(const char *Cmd); static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, - {"exec", CmdEMVExec, 0, "Executes EMV contactless transaction."}, - {"pse", CmdEMVPPSE, 0, "Execute PPSE. It selects 2PAY.SYS.DDF01 or 1PAY.SYS.DDF01 directory."}, - {"search", CmdEMVSearch, 0, "Try to select all applets from applets list and print installed applets."}, - {"select", CmdEMVSelect, 0, "Select applet."}, - {"gpo", CmdEMVGPO, 0, "Execute GetProcessingOptions."}, - {"readrec", CmdEMVReadRecord, 0, "Read files from card."}, - {"genac", CmdEMVAC, 0, "Generate ApplicationCryptogram."}, - {"challenge", CmdEMVGenerateChallenge, 0, "Generate challenge."}, - {"intauth", CmdEMVInternalAuthenticate, 0, "Internal authentication."}, - {"scan", CmdEMVScan, 0, "Scan EMV card and save it contents to json file for emulator."}, - {"test", CmdEMVTest, 0, "Crypto logic test."}, - {"roca", CmdEMVRoca, 0, "Extract public keys and run ROCA test"}, + {"exec", CmdEMVExec, 1, "Executes EMV contactless transaction."}, + {"pse", CmdEMVPPSE, 1, "Execute PPSE. It selects 2PAY.SYS.DDF01 or 1PAY.SYS.DDF01 directory."}, + {"search", CmdEMVSearch, 1, "Try to select all applets from applets list and print installed applets."}, + {"select", CmdEMVSelect, 1, "Select applet."}, + {"gpo", CmdEMVGPO, 1, "Execute GetProcessingOptions."}, + {"readrec", CmdEMVReadRecord, 1, "Read files from card."}, + {"genac", CmdEMVAC, 1, "Generate ApplicationCryptogram."}, + {"challenge", CmdEMVGenerateChallenge, 1, "Generate challenge."}, + {"intauth", CmdEMVInternalAuthenticate, 1, "Internal authentication."}, + {"scan", CmdEMVScan, 1, "Scan EMV card and save it contents to json file for emulator."}, + {"test", CmdEMVTest, 1, "Crypto logic test."}, + {"roca", CmdEMVRoca, 1, "Extract public keys and run ROCA test"}, {NULL, NULL, 0, NULL} }; diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index 23aa5e38..510e9850 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -11,6 +11,7 @@ #include "emvcore.h" #include "emvjson.h" #include "util_posix.h" +#include "protocols.h" #ifdef WITH_SMARTCARD #include "cmdsmartcard.h" #endif @@ -235,44 +236,39 @@ struct tlvdb *GetdCVVRawFromTrack2(const struct tlv *track2) { return tlvdb_fixed(0x02, dCVVlen, dCVV); } -int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, sAPDU apdu, bool IncludeLe, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - uint8_t data[APDU_RES_LEN] = {0}; +static int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *apdu, int apdu_len, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) +{ *ResultLen = 0; if (sw) *sw = 0; uint16_t isw = 0; int res = 0; - if (ActivateField) { + if (ActivateField && channel == ECC_CONTACTLESS) { DropField(); msleep(50); } - // COMPUTE APDU - memcpy(data, &apdu, 5); - if (apdu.data) - memcpy(&data[5], apdu.data, apdu.Lc); - if (APDULogging) - PrintAndLogEx(SUCCESS, ">>>> %s", sprint_hex(data, (IncludeLe?6:5) + apdu.Lc)); + PrintAndLogEx(SUCCESS, ">>>> %s", sprint_hex(apdu, apdu_len)); switch(channel) { - case ECC_CONTACTLESS: - // 6 byes + data = INS + CLA + P1 + P2 + Lc + + Le(?IncludeLe) - res = ExchangeAPDU14a(data, (IncludeLe?6:5) + apdu.Lc, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); - if (res) { - return res; - } - break; - case ECC_CONTACT: - //int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); + case ECC_CONTACTLESS: + // 6 byes + data = INS + CLA + P1 + P2 + Lc + + Le(?IncludeLe) + res = ExchangeAPDU14a(apdu, apdu_len, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); + if (res) { + return res; + } + break; + case ECC_CONTACT: + //int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); #ifdef WITH_SMARTCARD - res = ExchangeAPDUSC(data, (IncludeLe?6:5) + apdu.Lc, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); - if (res) { - return res; - } + res = ExchangeAPDUSC(apdu, apdu_len, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); + if (res) { + return res; + } #endif - break; + break; } if (APDULogging) @@ -282,6 +278,12 @@ int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool LeaveField return 200; } + if (Result[*ResultLen-2] == 0x61) { + uint8_t La = Result[*ResultLen-1]; + uint8_t get_response[5] = {apdu[0], ISO7816_GET_RESPONSE, 0x00, 0x00, La}; + return EMVExchangeEx(channel, false, LeaveFieldON, get_response, sizeof(get_response), Result, MaxResultLen, ResultLen, sw, tlv); + } + *ResultLen -= 2; isw = Result[*ResultLen] * 0x0100 + Result[*ResultLen + 1]; if (sw) @@ -289,12 +291,8 @@ int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool LeaveField if (isw != 0x9000) { if (APDULogging) { - if (*sw >> 8 == 0x61) { - PrintAndLogEx(ERR, "APDU chaining len:%02x -->", *sw & 0xff); - } else { - PrintAndLogEx(ERR, "APDU(%02x%02x) ERROR: [%4X] %s", apdu.CLA, apdu.INS, isw, GetAPDUCodeDescription(*sw >> 8, *sw & 0xff)); - return 5; - } + PrintAndLogEx(ERR, "APDU(%02x%02x) ERROR: [%4X] %s", apdu[0], apdu[1], isw, GetAPDUCodeDescription(*sw >> 8, *sw & 0xff)); + return 5; } } @@ -307,16 +305,36 @@ int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool LeaveField return 0; } -int EMVExchange(EMVCommandChannel channel, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - return EMVExchangeEx(channel, false, LeaveFieldON, apdu, (channel == ECC_CONTACTLESS), Result, MaxResultLen, ResultLen, sw, tlv); +int EMVExchange(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *apdu, int apdu_len, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) +{ + uint8_t APDU[APDU_COMMAND_LEN]; + memcpy(APDU, apdu, apdu_len); + APDU[apdu_len] = 0x00; + if (channel == ECC_CONTACTLESS) { + if (apdu_len == 5 && apdu[4] == 0) { + // there is no Lc but an Le == 0 already + } else if (apdu_len > 5 && apdu_len == 5 + apdu[4] + 1) { + // there is Lc, data and Le + } else { + apdu_len++; // no Le, add Le = 0x00 because some vendors require it for contactless + } + } + return EMVExchangeEx(channel, false, LeaveFieldON, APDU, apdu_len, Result, MaxResultLen, ResultLen, sw, tlv); } -int EMVSelect(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - return EMVExchangeEx(channel, ActivateField, LeaveFieldON, (sAPDU){0x00, 0xa4, 0x04, 0x00, AIDLen, AID}, (channel == ECC_CONTACTLESS), Result, MaxResultLen, ResultLen, sw, tlv); +int EMVSelect(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) +{ + uint8_t Select_APDU[APDU_COMMAND_LEN] = {0x00, ISO7816_SELECT_FILE, 0x04, 0x00, AIDLen, 0x00}; + memcpy(Select_APDU + 5, AID, AIDLen); + int apdulen = 5 + AIDLen; + if (channel == ECC_CONTACTLESS) { + apdulen++; // some vendors require Le = 0x00 for contactless operations + } + return EMVExchangeEx(channel, ActivateField, LeaveFieldON, Select_APDU, apdulen, Result, MaxResultLen, ResultLen, sw, tlv); } int EMVSelectPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { - uint8_t buf[APDU_AID_LEN] = {0}; + uint8_t buf[APDU_DATA_LEN] = {0}; *ResultLen = 0; int len = 0; int res = 0; @@ -325,6 +343,7 @@ int EMVSelectPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO param_gethex_to_eol(PSElist[1], 0, buf, sizeof(buf), &len); break; case 2: + param_gethex_to_eol(PSElist[0], 0, buf, sizeof(buf), &len); break; default: @@ -338,11 +357,13 @@ int EMVSelectPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO } int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, bool decodeTLV, struct tlvdb *tlv) { - uint8_t data[APDU_RES_LEN] = {0}; + uint8_t data[APDU_RESPONSE_LEN] = {0}; size_t datalen = 0; uint16_t sw = 0; int res; + char *PSE_or_PPSE = PSENum == 1 ? "PSE" : "PPSE"; + // select PPSE res = EMVSelectPSE(channel, ActivateField, true, PSENum, data, sizeof(data), &datalen, &sw); @@ -353,7 +374,7 @@ int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO int retrycnt = 0; struct tlvdb *ttmp = tlvdb_find_path(t, (tlv_tag_t[]){0x6f, 0xa5, 0xbf0c, 0x61, 0x00}); if (!ttmp) - PrintAndLogEx(FAILED, "PPSE don't have records."); + PrintAndLogEx(FAILED, "%s doesn't have any records.", PSE_or_PPSE); while (ttmp) { const struct tlv *tgAID = tlvdb_get_inchild(ttmp, 0x4f, NULL); @@ -393,22 +414,22 @@ int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO tlvdb_free(t); } else { - PrintAndLogEx(WARNING, "PPSE ERROR: Can't get TLV from response."); + PrintAndLogEx(WARNING, "%s ERROR: Can't get TLV from response.", PSE_or_PPSE); } } else { - PrintAndLogEx(WARNING, "PPSE ERROR: Can't select PPSE AID. Error: %d", res); + PrintAndLogEx(WARNING, "%s ERROR: Can't select PPSE AID. Error: %d", PSE_or_PPSE, res); } - if(!LeaveFieldON) + if(!LeaveFieldON && channel == ECC_CONTACTLESS) DropField(); return res; } int EMVSearch(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, bool decodeTLV, struct tlvdb *tlv) { - uint8_t aidbuf[APDU_AID_LEN] = {0}; + uint8_t aidbuf[APDU_DATA_LEN] = {0}; int aidlen = 0; - uint8_t data[APDU_RES_LEN] = {0}; + uint8_t data[APDU_RESPONSE_LEN] = {0}; size_t datalen = 0; uint16_t sw = 0; @@ -489,38 +510,63 @@ int EMVSelectApplication(struct tlvdb *tlv, uint8_t *AID, size_t *AIDlen) { return 0; } -int EMVGPO(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - return EMVExchange(channel, LeaveFieldON, (sAPDU){0x80, 0xa8, 0x00, 0x00, PDOLLen, PDOL}, Result, MaxResultLen, ResultLen, sw, tlv); +int EMVGPO(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) +{ + uint8_t GPO_APDU[APDU_COMMAND_LEN] = {0x80, 0xa8, 0x00, 0x00, PDOLLen, 0x00}; + memcpy(GPO_APDU + 5, PDOL, PDOLLen); + int apdulen = 5 + PDOLLen; + + return EMVExchange(channel, LeaveFieldON, GPO_APDU, apdulen, Result, MaxResultLen, ResultLen, sw, tlv); } -int EMVReadRecord(EMVCommandChannel channel, bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - int res = EMVExchange(channel, LeaveFieldON, (sAPDU){0x00, 0xb2, SFIrec, (SFI << 3) | 0x04, 0, NULL}, Result, MaxResultLen, ResultLen, sw, tlv); +int EMVReadRecord(EMVCommandChannel channel, bool LeaveFieldON, uint8_t SFI, uint8_t SFIrec, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) +{ + uint8_t read_APDU[5] = {0x00, ISO7816_READ_RECORDS, SFIrec, (SFI << 3) | 0x04, 0x00}; + int res = EMVExchange(channel, LeaveFieldON, read_APDU, sizeof(read_APDU), Result, MaxResultLen, ResultLen, sw, tlv); if (*sw == 0x6700) { PrintAndLogEx(INFO, ">>> trying to reissue command withouth Le..."); - res = EMVExchangeEx(channel, false, LeaveFieldON, (sAPDU){0x00, 0xb2, SFIrec, (SFI << 3) | 0x04, 0, NULL}, false, Result, MaxResultLen, ResultLen, sw, tlv); + res = EMVExchangeEx(channel, false, LeaveFieldON, read_APDU, sizeof(read_APDU), Result, MaxResultLen, ResultLen, sw, tlv); } return res; } -int EMVAC(EMVCommandChannel channel, bool LeaveFieldON, uint8_t RefControl, uint8_t *CDOL, size_t CDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - return EMVExchange(channel, LeaveFieldON, (sAPDU){0x80, 0xae, RefControl, 0x00, CDOLLen, CDOL}, Result, MaxResultLen, ResultLen, sw, tlv); +int EMVAC(EMVCommandChannel channel, bool LeaveFieldON, uint8_t RefControl, uint8_t *CDOL, size_t CDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) +{ + uint8_t CDOL_APDU[APDU_COMMAND_LEN] = {0x80, 0xae, RefControl, 0x00, CDOLLen, 0x00}; + memcpy(CDOL_APDU + 5, CDOL, CDOLLen); + int apdulen = 5 + CDOLLen; + + return EMVExchange(channel, LeaveFieldON, CDOL_APDU, apdulen, Result, MaxResultLen, ResultLen, sw, tlv); } -int EMVGenerateChallenge(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - int res = EMVExchange(channel, LeaveFieldON, (sAPDU){0x00, 0x84, 0x00, 0x00, 0x00, NULL}, Result, MaxResultLen, ResultLen, sw, tlv); +int EMVGenerateChallenge(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) +{ + uint8_t get_challenge_APDU[APDU_COMMAND_LEN] = {0x00, ISO7816_GET_CHALLENGE, 0x00, 0x00}; + + int res = EMVExchange(channel, LeaveFieldON, get_challenge_APDU, 4, Result, MaxResultLen, ResultLen, sw, tlv); if (*sw == 0x6700) { PrintAndLogEx(INFO, ">>> trying to reissue command withouth Le..."); - res = EMVExchangeEx(channel, false, LeaveFieldON, (sAPDU){0x00, 0x84, 0x00, 0x00, 0x00, NULL}, false, Result, MaxResultLen, ResultLen, sw, tlv); + res = EMVExchangeEx(channel, false, LeaveFieldON, get_challenge_APDU, 4, Result, MaxResultLen, ResultLen, sw, tlv); } return res; } -int EMVInternalAuthenticate(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - return EMVExchange(channel, LeaveFieldON, (sAPDU){0x00, 0x88, 0x00, 0x00, DDOLLen, DDOL}, Result, MaxResultLen, ResultLen, sw, tlv); +int EMVInternalAuthenticate(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) +{ + uint8_t authenticate_APDU[APDU_COMMAND_LEN] = {0x00, ISO7816_INTERNAL_AUTHENTICATION, 0x00, 0x00, DDOLLen, 0x00}; + memcpy(authenticate_APDU + 5, DDOL, DDOLLen); + int apdulen = 5 + DDOLLen; + + return EMVExchange(channel, LeaveFieldON, authenticate_APDU, apdulen, Result, MaxResultLen, ResultLen, sw, tlv); } -int MSCComputeCryptoChecksum(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - return EMVExchange(channel, LeaveFieldON, (sAPDU){0x80, 0x2a, 0x8e, 0x80, UDOLlen, UDOL}, Result, MaxResultLen, ResultLen, sw, tlv); +int MSCComputeCryptoChecksum(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *UDOL, uint8_t UDOLlen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) +{ + uint8_t checksum_APDU[APDU_COMMAND_LEN] = {0x80, 0x2a, 0x8e, 0x80, UDOLlen, 0x00}; + memcpy(checksum_APDU + 5, UDOL, UDOLlen); + int apdulen = 5 + UDOLlen; + + return EMVExchange(channel, LeaveFieldON, checksum_APDU, apdulen, Result, MaxResultLen, ResultLen, sw, tlv); } // Authentication @@ -591,7 +637,7 @@ static const unsigned char default_ddol_value[] = {0x9f, 0x37, 0x04}; static struct tlv default_ddol_tlv = {.tag = 0x9f49, .len = 3, .value = default_ddol_value }; int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { - uint8_t buf[APDU_RES_LEN] = {0}; + uint8_t buf[APDU_RESPONSE_LEN] = {0}; size_t len = 0; uint16_t sw = 0; diff --git a/client/emv/emvcore.h b/client/emv/emvcore.h index 7d53e83b..5d6f3984 100644 --- a/client/emv/emvcore.h +++ b/client/emv/emvcore.h @@ -29,8 +29,10 @@ #include "emv_pk.h" #include "emv_pki.h" -#define APDU_RES_LEN 260 -#define APDU_AID_LEN 50 +// maximum APDU lengths. Long APDUs not yet supported/needed +#define APDU_DATA_LEN 255 +#define APDU_COMMAND_LEN (4 + 1 + APDU_DATA_LEN + 1) +#define APDU_RESPONSE_LEN (256 + 2) typedef enum { ECC_CONTACTLESS, @@ -45,15 +47,6 @@ enum TransactionType { }; extern char *TransactionTypeStr[]; -typedef struct { - 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, @@ -76,7 +69,7 @@ extern struct tlvdb *GetdCVVRawFromTrack2(const struct tlv *track2); extern void SetAPDULogging(bool logging); // exchange -extern int EMVExchange(EMVCommandChannel channel, bool LeaveFieldON, sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); +extern int EMVExchange(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *APDU, int APDU_len, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); // search application extern int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, bool decodeTLV, struct tlvdb *tlv); diff --git a/client/fido/fidocore.c b/client/fido/fidocore.c index ee39fbbe..4d973737 100644 --- a/client/fido/fidocore.c +++ b/client/fido/fidocore.c @@ -22,6 +22,8 @@ #include "crypto/libpcrypto.h" #include "fido/additional_ca.h" #include "fido/cose.h" +#include "protocols.h" + typedef struct { uint8_t ErrorCode; @@ -173,14 +175,16 @@ int FIDOSelect(bool ActivateField, bool LeaveFieldON, uint8_t *Result, size_t Ma return EMVSelect(ECC_CONTACTLESS, ActivateField, LeaveFieldON, data, sizeof(data), Result, MaxResultLen, ResultLen, sw, NULL); } -int FIDOExchange(sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { - int res = EMVExchange(ECC_CONTACTLESS, true, apdu, Result, MaxResultLen, ResultLen, sw, NULL); +int FIDOExchange(uint8_t* apdu, int apdulen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { + int res = EMVExchange(ECC_CONTACTLESS, true, apdu, apdulen, Result, MaxResultLen, ResultLen, sw, NULL); if (res == 5) // apdu result (sw) not a 0x9000 res = 0; // software chaining while (!res && (*sw >> 8) == 0x61) { + uint8_t La = *sw & 0xff; + uint8_t get_response_APDU[5] = {apdu[0], ISO7816_GET_RESPONSE, 0x00, 0x00, La}; size_t oldlen = *ResultLen; - res = EMVExchange(ECC_CONTACTLESS, true, (sAPDU){0x00, 0xC0, 0x00, 0x00, 0x00, NULL}, &Result[oldlen], MaxResultLen - oldlen, ResultLen, sw, NULL); + res = EMVExchange(ECC_CONTACTLESS, true, get_response_APDU, sizeof(get_response_APDU), &Result[oldlen], MaxResultLen - oldlen, ResultLen, sw, NULL); if (res == 5) // apdu result (sw) not a 0x9000 res = 0; @@ -191,31 +195,41 @@ int FIDOExchange(sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *Resul return res; } -int FIDORegister(uint8_t *params, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { - return FIDOExchange((sAPDU){0x00, 0x01, 0x03, 0x00, 64, params}, Result, MaxResultLen, ResultLen, sw); +int FIDORegister(uint8_t *params, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) +{ + uint8_t APDU[4 + 64] = {0x00, 0x01, 0x03, 0x00, 64, 0x00}; + memcpy(APDU, params, 64); + return FIDOExchange(APDU, 4 + 64, Result, MaxResultLen, ResultLen, sw); } -int FIDOAuthentication(uint8_t *params, uint8_t paramslen, uint8_t controlb, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { - return FIDOExchange((sAPDU){0x00, 0x02, controlb, 0x00, paramslen, params}, Result, MaxResultLen, ResultLen, sw); +int FIDOAuthentication(uint8_t *params, uint8_t paramslen, uint8_t controlb, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) +{ + uint8_t APDU[APDU_COMMAND_LEN] = {0x00, 0x02, controlb, 0x00, paramslen, 0x00}; + memcpy(APDU+5, params, paramslen); + int apdu_len = 5 + paramslen; + return FIDOExchange(APDU, apdu_len, Result, MaxResultLen, ResultLen, sw); } -int FIDO2GetInfo(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { - uint8_t data[] = {fido2CmdGetInfo}; - return FIDOExchange((sAPDU){0x80, 0x10, 0x00, 0x00, sizeof(data), data}, Result, MaxResultLen, ResultLen, sw); +int FIDO2GetInfo(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) +{ + uint8_t APDU[5] = {0x80, 0x10, 0x00, 0x00, fido2CmdGetInfo}; + return FIDOExchange(APDU, sizeof(APDU), Result, MaxResultLen, ResultLen, sw); } -int FIDO2MakeCredential(uint8_t *params, uint8_t paramslen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { - uint8_t data[paramslen + 1]; - data[0] = fido2CmdMakeCredential; - memcpy(&data[1], params, paramslen); - return FIDOExchange((sAPDU){0x80, 0x10, 0x00, 0x00, sizeof(data), data}, Result, MaxResultLen, ResultLen, sw); +int FIDO2MakeCredential(uint8_t *params, uint8_t paramslen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) +{ + uint8_t APDU[APDU_COMMAND_LEN] = {0x80, 0x10, 0x00, 0x00, paramslen + 1, fido2CmdMakeCredential, 0x00}; + memcpy(APDU+6, params, paramslen); + int apdu_len = 5 + paramslen + 1; + return FIDOExchange(APDU, apdu_len, Result, MaxResultLen, ResultLen, sw); } -int FIDO2GetAssertion(uint8_t *params, uint8_t paramslen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { - uint8_t data[paramslen + 1]; - data[0] = fido2CmdGetAssertion; - memcpy(&data[1], params, paramslen); - return FIDOExchange((sAPDU){0x80, 0x10, 0x00, 0x00, sizeof(data), data}, Result, MaxResultLen, ResultLen, sw); +int FIDO2GetAssertion(uint8_t *params, uint8_t paramslen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) +{ + uint8_t APDU[APDU_COMMAND_LEN] = {0x80, 0x10, 0x00, 0x00, paramslen + 1, fido2CmdGetAssertion, 0x00}; + memcpy(APDU+6, params, paramslen); + int apdu_len = 5 + paramslen + 1; + return FIDOExchange(APDU, apdu_len, Result, MaxResultLen, ResultLen, sw); } int FIDOCheckDERAndGetKey(uint8_t *der, size_t derLen, bool verbose, uint8_t *publicKey, size_t publicKeyMaxLen) { diff --git a/client/fido/fidocore.h b/client/fido/fidocore.h index a1bcf876..c98e36e7 100644 --- a/client/fido/fidocore.h +++ b/client/fido/fidocore.h @@ -37,7 +37,7 @@ typedef enum { } fido2PacketType; extern int FIDOSelect(bool ActivateField, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); -extern int FIDOExchange(sAPDU apdu, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); +extern int FIDOExchange(uint8_t *APDU, int APDU_len, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); extern int FIDORegister(uint8_t *params, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); extern int FIDOAuthentication(uint8_t *params, uint8_t paramslen, uint8_t controlb, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); extern int FIDO2GetInfo(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw); diff --git a/client/pcsc.c b/client/pcsc.c index dd331d0a..7d03d052 100644 --- a/client/pcsc.c +++ b/client/pcsc.c @@ -175,3 +175,41 @@ bool pcscGetATR(smart_card_atr_t *card) return true; } + + +void pcscTransmit(uint8_t *data, uint32_t data_len, uint32_t flags, uint8_t *response, int *response_len) +{ + LPCSCARD_IO_REQUEST protocol; + if (flags & SC_RAW_T0) { + protocol = SCARD_PCI_T0; + } else { + protocol = SCARD_PCI_RAW; + } + + // TODO: tracing + // if ((flags & SC_CONNECT)) + // clear_trace(); + + // set_tracing(true); + + if ((flags & SC_CONNECT || flags & SC_SELECT)) { + LONG res = SCardConnect(SC_Context, AlternativeSmartcardReader, SCARD_SHARE_SHARED, + SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &SC_Card, &SC_Protocol); + if (res != SCARD_S_SUCCESS) { + *response_len = -1; + return; + } + } + + if ((flags & SC_RAW) || (flags & SC_RAW_T0)) { + // TODO: tracing + // LogTrace(data, arg1, 0, 0, NULL, true); + DWORD len = *response_len; + LONG res = SCardTransmit(SC_Card, protocol, data, data_len, NULL, response, &len); + if (res != SCARD_S_SUCCESS) { + *response_len = -1; + } else { + *response_len = len; + } + } +} diff --git a/client/pcsc.h b/client/pcsc.h index 3dae06c0..27083518 100644 --- a/client/pcsc.h +++ b/client/pcsc.h @@ -18,5 +18,6 @@ char *getAlternativeSmartcardReader(void); bool pcscCheckForCardReaders(void); bool pcscSelectAlternativeCardReader(const char *readername); bool pcscGetATR(smart_card_atr_t *card); +void pcscTransmit(uint8_t *data, uint32_t data_len, uint32_t flags, uint8_t *response, int *response_len); #endif diff --git a/client/proxmark3.c b/client/proxmark3.c index a25ecb41..fda9f313 100644 --- a/client/proxmark3.c +++ b/client/proxmark3.c @@ -28,7 +28,6 @@ #include "cmdhw.h" #include "whereami.h" #include "comms.h" -#include "pcsc.h" void diff --git a/common/protocols.h b/common/protocols.h index 82b69f9d..191c55f9 100644 --- a/common/protocols.h +++ b/common/protocols.h @@ -262,12 +262,13 @@ NXP/Philips CUSTOM COMMANDS #define ISO7816_VERIFY 0x20 #define ISO7816_INTERNAL_AUTHENTICATION 0x88 #define ISO7816_EXTERNAL_AUTHENTICATION 0x82 -#define ISO7816_GET_CHALLENGE 0xB4 +#define ISO7816_GET_CHALLENGE 0x84 #define ISO7816_MANAGE_CHANNEL 0x70 -#define ISO7816_GETSTATUS 0xC0 +#define ISO7816_GET_RESPONSE 0xC0 // ISO7816-4 For response APDU's #define ISO7816_OK 0x9000 // 6x xx = ERROR +#define ISO7816_MAX_FRAME_SIZE 261 From 97096af62bd25105acd3d56eda5cd9a3112aa876 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Fri, 1 Feb 2019 21:13:00 +0100 Subject: [PATCH 056/189] Update list of known EMV AIDs. Source: https://www.eftlab.co.uk/index.php/site-map/knowledge-base/211-emv-aid-rid-pix (#770) --- client/emv/emvcore.c | 104 ++++++++++++++++++++++++++++--------------- client/emv/emvcore.h | 2 + 2 files changed, 69 insertions(+), 37 deletions(-) diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index 510e9850..53559e85 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -38,38 +38,39 @@ typedef struct { static const TAIDList AIDlist [] = { // Visa International - { CV_VISA, "A00000000305076010"}, // VISA ELO Credit - { CV_VISA, "A0000000031010" }, // VISA Debit/Credit (Classic) - { CV_VISA, "A000000003101001" }, // VISA Credit - { CV_VISA, "A000000003101002" }, // VISA Debit - { CV_VISA, "A0000000032010" }, // VISA Electron - { CV_VISA, "A0000000032020" }, // VISA - { CV_VISA, "A0000000033010" }, // VISA Interlink - { CV_VISA, "A0000000034010" }, // VISA Specific - { CV_VISA, "A0000000035010" }, // VISA Specific - { CV_VISA, "A0000000036010" }, // Domestic Visa Cash Stored Value - { CV_VISA, "A0000000036020" }, // International Visa Cash Stored Value - { CV_VISA, "A0000000038002" }, // VISA Auth, VisaRemAuthen EMV-CAP (DPA) - { CV_VISA, "A0000000038010" }, // VISA Plus - { CV_VISA, "A0000000039010" }, // VISA Loyalty - { CV_VISA, "A000000003999910" }, // VISA Proprietary ATM + { CV_VISA, "A00000000305076010"}, // VISA ELO Credit + { CV_VISA, "A0000000031010" }, // VISA Debit/Credit (Classic) + { CV_VISA, "A000000003101001" }, // VISA Credit + { CV_VISA, "A000000003101002" }, // VISA Debit + { CV_VISA, "A0000000032010" }, // VISA Electron + { CV_VISA, "A0000000032020" }, // VISA + { CV_VISA, "A0000000033010" }, // VISA Interlink + { CV_VISA, "A0000000034010" }, // VISA Specific + { CV_VISA, "A0000000035010" }, // VISA Specific + { CV_VISA, "A0000000036010" }, // Domestic Visa Cash Stored Value + { CV_VISA, "A0000000036020" }, // International Visa Cash Stored Value + { CV_VISA, "A0000000038002" }, // VISA Auth, VisaRemAuthen EMV-CAP (DPA) + { CV_VISA, "A0000000038010" }, // VISA Plus + { CV_VISA, "A0000000039010" }, // VISA Loyalty + { CV_VISA, "A000000003999910" }, // VISA Proprietary ATM // Visa USA - { CV_VISA, "A000000098" }, // Debit Card - { CV_VISA, "A0000000980848" }, // Debit Card + { CV_VISA, "A000000098" }, // Debit Card + { CV_VISA, "A0000000980848" }, // Debit Card // Mastercard International - { CV_MASTERCARD, "A00000000401" }, // MasterCard PayPass - { CV_MASTERCARD, "A0000000041010" }, // MasterCard Credit - { CV_MASTERCARD, "A00000000410101213" }, // MasterCard Credit - { CV_MASTERCARD, "A00000000410101215" }, // MasterCard Credit - { CV_MASTERCARD, "A0000000042010" }, // MasterCard Specific - { CV_MASTERCARD, "A0000000043010" }, // MasterCard Specific - { CV_MASTERCARD, "A0000000043060" }, // Maestro (Debit) - { CV_MASTERCARD, "A000000004306001" }, // Maestro (Debit) - { CV_MASTERCARD, "A0000000044010" }, // MasterCard Specific - { CV_MASTERCARD, "A0000000045010" }, // MasterCard Specific - { CV_MASTERCARD, "A0000000046000" }, // Cirrus - { CV_MASTERCARD, "A0000000048002" }, // SecureCode Auth EMV-CAP - { CV_MASTERCARD, "A0000000049999" }, // MasterCard PayPass + { CV_MASTERCARD, "A00000000401" }, // MasterCard PayPass + { CV_MASTERCARD, "A0000000041010" }, // MasterCard Credit + { CV_MASTERCARD, "A00000000410101213" }, // MasterCard Credit + { CV_MASTERCARD, "A00000000410101215" }, // MasterCard Credit + { CV_MASTERCARD, "A0000000042010" }, // MasterCard Specific + { CV_MASTERCARD, "A0000000043010" }, // MasterCard Specific + { CV_MASTERCARD, "A0000000043060" }, // Maestro (Debit) + { CV_MASTERCARD, "A000000004306001" }, // Maestro (Debit) + { CV_MASTERCARD, "A0000000044010" }, // MasterCard Specific + { CV_MASTERCARD, "A0000000045010" }, // MasterCard Specific + { CV_MASTERCARD, "A0000000046000" }, // Cirrus + { CV_MASTERCARD, "A0000000048002" }, // SecureCode Auth EMV-CAP + { CV_MASTERCARD, "A0000000049999" }, // MasterCard PayPass + { CV_MASTERCARD, "B012345678" }, // Maestro TEST Used for development // American Express { CV_AMERICANEXPRESS, "A000000025" }, { CV_AMERICANEXPRESS, "A0000000250000" }, @@ -78,19 +79,48 @@ static const TAIDList AIDlist [] = { { CV_AMERICANEXPRESS, "A000000025010701" }, { CV_AMERICANEXPRESS, "A000000025010801" }, // Groupement des Cartes Bancaires "CB" - { CV_CB, "A0000000421010" }, // Cartes Bancaire EMV Card + { CV_CB, "A0000000421010" }, // Cartes Bancaire EMV Card { CV_CB, "A0000000422010" }, { CV_CB, "A0000000423010" }, { CV_CB, "A0000000424010" }, { CV_CB, "A0000000425010" }, // JCB CO., LTD. - { CV_JCB, "A00000006510" }, // JCB - { CV_JCB, "A0000000651010" }, // JCB J Smart Credit + { CV_JCB, "A00000006510" }, // JCB + { CV_JCB, "A0000000651010" }, // JCB J Smart Credit + // Switch Card Services Ltd. + { CV_SWITCH, "A0000000050001" }, // Maestro UK + { CV_SWITCH, "A0000000050002" }, // Solo + // Diners Club International Ltd. + { CV_DINERS, "A0000001523010" }, // Discover, Pulse D Pas Discover Card + { CV_DINERS, "A0000001524010" }, // Discover, Discover Debit Common Card // Other - { CV_OTHER, "A0000001544442" }, // Banricompras Debito - Banrisul - Banco do Estado do Rio Grande do SUL - S.A. - { CV_OTHER, "F0000000030001" }, // BRADESCO - { CV_OTHER, "A0000005241010" }, // RuPay - RuPay - { CV_OTHER, "D5780000021010" } // Bankaxept - Bankaxept + { CV_OTHER, "A00000002401" }, // Midland Bank Plc - Self Service + { CV_OTHER, "A0000000291010" }, // LINK Interchange Network Ltd - Link / American Express + { CV_OTHER, "A00000006900" }, // Société Européenne de Monnaie Electronique SEME - Moneo + { CV_OTHER, "A000000077010000021000000000003B" }, // Oberthur Technologies France - Visa AEPN + { CV_OTHER, "A0000001211010" }, // PBS Danmark A/S - Denmark - Dankort (VISA GEM Vision) - Danish domestic debit card + { CV_OTHER, "A0000001410001" }, // Associazione Bancaria Italiana - Italy - PagoBANCOMAT - CoGeBan Consorzio BANCOMAT (Italian domestic debit card) + { CV_OTHER, "A0000001544442" }, // Banricompras Debito - Banrisul - Banco do Estado do Rio Grande do SUL - S.A. + { CV_OTHER, "A000000172950001" }, // Financial Information Service Co. Ltd. - Taiwan - BAROC Financial Application Taiwan- The Bankers Association of the Republic of China + { CV_OTHER, "A0000001850002" }, // Post Office Limited - United Kingdom - UK Post Office Account card + { CV_OTHER, "A0000002281010" }, // Saudi Arabian Monetary Agency (SAMA) - Kingdom of Saudi Arabia - SPAN (M/Chip) - SPAN2 (Saudi Payments Network) - Saudi Arabia domestic credit/debit card (Saudi Arabia Monetary Agency) + { CV_OTHER, "A0000002282010" }, // Saudi Arabian Monetary Agency (SAMA) - Kingdom of Saudi Arabia - SPAN (VIS) - SPAN2 (Saudi Payments Network) - Saudi Arabia domestic credit/debit card (Saudi Arabia Monetary Agency) + { CV_OTHER, "A0000002771010" }, // Interac Association - Canada - INTERAC - Canadian domestic credit/debit card + { CV_OTHER, "A00000031510100528" }, // Currence Holding/PIN BV - The Netherlands- Currence PuC + { CV_OTHER, "A0000003156020" }, // Currence Holding/PIN BV - The Netherlands - Chipknip + { CV_OTHER, "A0000003591010028001" }, // Euro Alliance of Payment Schemes s.c.r.l. (EAPS) - Belgium - Girocard EAPS - ZKA (Germany) + { CV_OTHER, "A0000003710001" }, // Verve - Nigeria - InterSwitch Verve Card - Nigerian local switch company + { CV_OTHER, "A0000004540010" }, // eTranzact - Nigeria - Etranzact Genesis Card - Nigerian local switch company + { CV_OTHER, "A0000004540011" }, // eTranzact - Nigeria - Etranzact Genesis Card 2 - Nigerian local switch company + { CV_OTHER, "A0000004766C" }, // Google - United States - GOOGLE_PAYMENT_AID + { CV_OTHER, "A0000005241010" }, // RuPay - India - RuPay - RuPay (India) + { CV_OTHER, "A0000006723010" }, // TROY - Turkey - TROY chip credit card - Turkey's Payment Method + { CV_OTHER, "A0000006723020" }, // TROY - Turkey - TROY chip debit card - Turkey's Payment Method + { CV_OTHER, "A0000007705850" }, // Indian Oil Corporation Limited - India - XTRAPOWER Fleet Card Program - Indian Oil’s Pre Paid Program + { CV_OTHER, "D27600002545500100" }, // ZKA - Germany - Girocard - ZKA Girocard (Geldkarte) (Germany) + { CV_OTHER, "D5280050218002" }, // The Netherlands - ? - (Netherlands) + { CV_OTHER, "D5780000021010" }, // Bankaxept Norway Bankaxept Norwegian domestic debit card + { CV_OTHER, "F0000000030001" }, // BRADESCO - Brazilian Bank Banco Bradesco }; static const size_t AIDlistLen = sizeof(AIDlist)/sizeof(TAIDList); diff --git a/client/emv/emvcore.h b/client/emv/emvcore.h index 5d6f3984..010315ba 100644 --- a/client/emv/emvcore.h +++ b/client/emv/emvcore.h @@ -54,6 +54,8 @@ enum CardPSVendor { CV_AMERICANEXPRESS, CV_JCB, CV_CB, + CV_SWITCH, + CV_DINERS, CV_OTHER, }; extern enum CardPSVendor GetCardPSVendor(uint8_t * AID, size_t AIDlen); From 3962dce565fc63c0190d4570bfaf339ec32b7025 Mon Sep 17 00:00:00 2001 From: Oleg Moiseenko <807634+merlokk@users.noreply.github.com> Date: Mon, 4 Feb 2019 09:03:44 +0200 Subject: [PATCH 057/189] fido fix (#775) --- client/emv/emvcore.c | 7 ++++--- client/fido/fidocore.c | 10 +++++----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index 53559e85..78a30206 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -308,11 +308,11 @@ static int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool Lea return 200; } - if (Result[*ResultLen-2] == 0x61) { +/* if (Result[*ResultLen-2] == 0x61) { uint8_t La = Result[*ResultLen-1]; uint8_t get_response[5] = {apdu[0], ISO7816_GET_RESPONSE, 0x00, 0x00, La}; return EMVExchangeEx(channel, false, LeaveFieldON, get_response, sizeof(get_response), Result, MaxResultLen, ResultLen, sw, tlv); - } + }*/ *ResultLen -= 2; isw = Result[*ResultLen] * 0x0100 + Result[*ResultLen + 1]; @@ -346,7 +346,8 @@ int EMVExchange(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *apdu, int } else if (apdu_len > 5 && apdu_len == 5 + apdu[4] + 1) { // there is Lc, data and Le } else { - apdu_len++; // no Le, add Le = 0x00 because some vendors require it for contactless + if (apdu[1] != 0xc0) + apdu_len++; // no Le, add Le = 0x00 because some vendors require it for contactless } } return EMVExchangeEx(channel, false, LeaveFieldON, APDU, apdu_len, Result, MaxResultLen, ResultLen, sw, tlv); diff --git a/client/fido/fidocore.c b/client/fido/fidocore.c index 4d973737..5498c9d2 100644 --- a/client/fido/fidocore.c +++ b/client/fido/fidocore.c @@ -197,22 +197,22 @@ int FIDOExchange(uint8_t* apdu, int apdulen, uint8_t *Result, size_t MaxResultLe int FIDORegister(uint8_t *params, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { - uint8_t APDU[4 + 64] = {0x00, 0x01, 0x03, 0x00, 64, 0x00}; - memcpy(APDU, params, 64); - return FIDOExchange(APDU, 4 + 64, Result, MaxResultLen, ResultLen, sw); + uint8_t APDU[5 + 64] = {0x00, 0x01, 0x03, 0x00, 64, 0x00}; + memcpy(APDU + 5, params, 64); + return FIDOExchange(APDU, 5 + 64, Result, MaxResultLen, ResultLen, sw); } int FIDOAuthentication(uint8_t *params, uint8_t paramslen, uint8_t controlb, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { uint8_t APDU[APDU_COMMAND_LEN] = {0x00, 0x02, controlb, 0x00, paramslen, 0x00}; - memcpy(APDU+5, params, paramslen); + memcpy(APDU + 5, params, paramslen); int apdu_len = 5 + paramslen; return FIDOExchange(APDU, apdu_len, Result, MaxResultLen, ResultLen, sw); } int FIDO2GetInfo(uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { - uint8_t APDU[5] = {0x80, 0x10, 0x00, 0x00, fido2CmdGetInfo}; + uint8_t APDU[6] = {0x80, 0x10, 0x00, 0x00, 0x01, fido2CmdGetInfo}; return FIDOExchange(APDU, sizeof(APDU), Result, MaxResultLen, ResultLen, sw); } From fb27c733133554aab2888a48bdb58c4502bc8a9b Mon Sep 17 00:00:00 2001 From: Oleg Moiseenko <807634+merlokk@users.noreply.github.com> Date: Mon, 4 Feb 2019 20:53:04 +0200 Subject: [PATCH 058/189] added SoloKey certificate (#778) --- client/fido/additional_ca.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/client/fido/additional_ca.c b/client/fido/additional_ca.c index f529e99b..564eda2a 100644 --- a/client/fido/additional_ca.c +++ b/client/fido/additional_ca.c @@ -58,6 +58,23 @@ "U9psmyPzK+Vsgw2jeRQ5JlKDyqE0hebfC1tvFu0CCrJFcw==\r\n" \ "-----END CERTIFICATE-----\r\n" +// Name: SoloKey U2F Root CA Serial 14143382635911888524 (0xc44763928ff4be8c) +// Issued: 2018-11-11 +#define SOLOKEY_CA \ +"-----BEGIN CERTIFICATE-----\r\n" \ +"MIIB9DCCAZoCCQDER2OSj/S+jDAKBggqhkjOPQQDAjCBgDELMAkGA1UEBhMCVVMx\r\n" \ +"ETAPBgNVBAgMCE1hcnlsYW5kMRIwEAYDVQQKDAlTb2xvIEtleXMxEDAOBgNVBAsM\r\n" \ +"B1Jvb3QgQ0ExFTATBgNVBAMMDHNvbG9rZXlzLmNvbTEhMB8GCSqGSIb3DQEJARYS\r\n" \ +"aGVsbG9Ac29sb2tleXMuY29tMCAXDTE4MTExMTEyNTE0MloYDzIwNjgxMDI5MTI1\r\n" \ +"MTQyWjCBgDELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1hcnlsYW5kMRIwEAYDVQQK\r\n" \ +"DAlTb2xvIEtleXMxEDAOBgNVBAsMB1Jvb3QgQ0ExFTATBgNVBAMMDHNvbG9rZXlz\r\n" \ +"LmNvbTEhMB8GCSqGSIb3DQEJARYSaGVsbG9Ac29sb2tleXMuY29tMFkwEwYHKoZI\r\n" \ +"zj0CAQYIKoZIzj0DAQcDQgAEWHAN0CCJVZdMs0oktZ5m93uxmB1iyq8ELRLtqVFL\r\n" \ +"SOiHQEab56qRTB/QzrpGAY++Y2mw+vRuQMNhBiU0KzwjBjAKBggqhkjOPQQDAgNI\r\n" \ +"ADBFAiEAz9SlrAXIlEu87vra54rICPs+4b0qhp3PdzcTg7rvnP0CIGjxzlteQQx+\r\n" \ +"jQGd7rwSZuE5RWUPVygYhUstQO9zNUOs\r\n" \ +"-----END CERTIFICATE-----\r\n" + /* Concatenation of all additional CA certificates in PEM format if available */ -const char additional_ca_pem[] = GLOBALSIGN_CA YUBICO_CA; +const char additional_ca_pem[] = GLOBALSIGN_CA YUBICO_CA SOLOKEY_CA; const size_t additional_ca_pem_len = sizeof(additional_ca_pem); From 4cdd63b245e34b42df42b384009838020d8fad02 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Wed, 6 Feb 2019 07:50:57 +0100 Subject: [PATCH 059/189] EVM fixes and additions (RRG repository PRs 78-82 by @merlokk) (#776) --- armsrc/i2c.c | 11 +- client/cmdsmartcard.c | 2 +- client/emv/cmdemv.c | 131 ++++++++++++++++++++-- client/emv/emv_pki.c | 89 +++++++++++++-- client/emv/emv_pki.h | 1 + client/emv/emv_roca.c | 31 ++---- client/emv/emv_roca.h | 2 +- client/emv/emvcore.c | 205 ++++++++++++++++++++++++++--------- client/emv/test/cryptotest.c | 6 +- client/emv/tlv.c | 52 ++++++++- client/emv/tlv.h | 7 ++ 11 files changed, 433 insertions(+), 104 deletions(-) diff --git a/armsrc/i2c.c b/armsrc/i2c.c index 7ef0c9c0..51513114 100644 --- a/armsrc/i2c.c +++ b/armsrc/i2c.c @@ -257,10 +257,11 @@ static void I2C_Reset_EnterBootloader(void) { WaitMS(10); } -// Wait max 300ms or until SCL goes LOW. +// Wait max 1800ms or until SCL goes LOW. +// It timeout reading response from card // Which ever comes first -static bool WaitSCL_L_300ms(void) { - volatile uint16_t delay = 310; +bool WaitSCL_L_timeout(void){ + volatile uint16_t delay = 1800; while ( delay-- ) { // exit on SCL LOW if (!SCL_read) @@ -272,8 +273,8 @@ static bool WaitSCL_L_300ms(void) { } static bool I2C_WaitForSim() { - // variable delay here. - if (!WaitSCL_L_300ms()) + // wait for data from card + if (!WaitSCL_L_timeout()) return false; // 8051 speaks with smart card. diff --git a/client/cmdsmartcard.c b/client/cmdsmartcard.c index 90a219ab..53ee9119 100644 --- a/client/cmdsmartcard.c +++ b/client/cmdsmartcard.c @@ -570,7 +570,7 @@ int ExchangeAPDUSC(uint8_t *APDU, int APDUlen, bool activateCard, bool leaveSign } if (*responselen < 0 ) { - return 2; + return 1; } else { return 0; } diff --git a/client/emv/cmdemv.c b/client/emv/cmdemv.c index 16835ba8..832df82e 100644 --- a/client/emv/cmdemv.c +++ b/client/emv/cmdemv.c @@ -42,6 +42,20 @@ void ParamLoadDefaults(struct tlvdb *tlvRoot) { TLV_ADD(0x9F6A, "\x01\x02\x03\x04"); //9F66:(Terminal Transaction Qualifiers (TTQ)) len:4 TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC + //95:(Terminal Verification Results) len:5 + // all OK TVR + TLV_ADD(0x95, "\x00\x00\x00\x00\x00"); +} + +void PrintChannel(EMVCommandChannel channel) { + switch(channel) { + case ECC_CONTACTLESS: + PrintAndLogEx(INFO, "Channel: CONTACTLESS"); + break; + case ECC_CONTACT: + PrintAndLogEx(INFO, "Channel: CONTACT"); + break; + } } int CmdEMVSelect(const char *cmd) { @@ -74,6 +88,7 @@ int CmdEMVSelect(const char *cmd) { #ifdef WITH_SMARTCARD if (arg_get_lit(5)) channel = ECC_CONTACT; + PrintChannel(channel); CLIGetHexWithReturn(6, data, &datalen); #else CLIGetHexWithReturn(5, data, &datalen); @@ -128,6 +143,7 @@ int CmdEMVSearch(const char *cmd) { if (arg_get_lit(5)) channel = ECC_CONTACT; #endif + PrintChannel(channel); CLIParserFree(); SetAPDULogging(APDULogging); @@ -188,6 +204,7 @@ int CmdEMVPPSE(const char *cmd) { if (arg_get_lit(7)) channel = ECC_CONTACT; #endif + PrintChannel(channel); CLIParserFree(); SetAPDULogging(APDULogging); @@ -249,6 +266,7 @@ int CmdEMVGPO(const char *cmd) { #else CLIGetHexWithReturn(6, data, &datalen); #endif + PrintChannel(channel); CLIParserFree(); SetAPDULogging(APDULogging); @@ -346,6 +364,7 @@ int CmdEMVReadRecord(const char *cmd) { #else CLIGetHexWithReturn(4, data, &datalen); #endif + PrintChannel(channel); CLIParserFree(); if (datalen != 2) { @@ -434,6 +453,7 @@ int CmdEMVAC(const char *cmd) { #else CLIGetHexWithReturn(8, data, &datalen); #endif + PrintChannel(channel); CLIParserFree(); SetAPDULogging(APDULogging); @@ -519,6 +539,7 @@ int CmdEMVGenerateChallenge(const char *cmd) { if (arg_get_lit(3)) channel = ECC_CONTACT; #endif + PrintChannel(channel); CLIParserFree(); SetAPDULogging(APDULogging); @@ -584,6 +605,7 @@ int CmdEMVInternalAuthenticate(const char *cmd) { #else CLIGetHexWithReturn(6, data, &datalen); #endif + PrintChannel(channel); CLIParserFree(); SetAPDULogging(APDULogging); @@ -710,6 +732,50 @@ void ProcessGPOResponseFormat1(struct tlvdb *tlvRoot, uint8_t *buf, size_t len, } } +void ProcessACResponseFormat1(struct tlvdb *tlvRoot, uint8_t *buf, size_t len, bool decodeTLV) { + if (buf[0] == 0x80) { + if (decodeTLV){ + PrintAndLog("GPO response format1:"); + TLVPrintFromBuffer(buf, len); + } + + uint8_t elmlen = len - 2; // wo 0x80XX + + if (len < 4 + 2 || (elmlen - 2) % 4 || elmlen != buf[1]) { + PrintAndLogEx(ERR, "GPO response format1 parsing error. length=%d", len); + } else { + struct tlvdb *tlvElm = NULL; + if (decodeTLV) + PrintAndLog("\n------------ Format1 decoded ------------"); + + // CID (Cryptogram Information Data) + tlvdb_change_or_add_node_ex(tlvRoot, 0x9f27, 1, &buf[2], &tlvElm); + if (decodeTLV) + TLVPrintFromTLV(tlvElm); + + // ATC (Application Transaction Counter) + tlvdb_change_or_add_node_ex(tlvRoot, 0x9f36, 2, &buf[3], &tlvElm); + if (decodeTLV) + TLVPrintFromTLV(tlvElm); + + // AC (Application Cryptogram) + tlvdb_change_or_add_node_ex(tlvRoot, 0x9f26, MIN(8, elmlen - 3), &buf[5], &tlvElm); + if (decodeTLV) + TLVPrintFromTLV(tlvElm); + + // IAD (Issuer Application Data) - optional + if (len > 11 + 2) { + tlvdb_change_or_add_node_ex(tlvRoot, 0x9f10, elmlen - 11, &buf[13], &tlvElm); + if (decodeTLV) + TLVPrintFromTLV(tlvElm); + } + } + } else { + if (decodeTLV) + TLVPrintFromBuffer(buf, len); + } +} + int CmdEMVExec(const char *cmd) { uint8_t buf[APDU_RESPONSE_LEN] = {0}; size_t len = 0; @@ -768,6 +834,7 @@ int CmdEMVExec(const char *cmd) { if (arg_get_lit(11)) channel = ECC_CONTACT; #endif + PrintChannel(channel); uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2; char *PSE_or_PPSE = psenum == 1 ? "PSE" : "PPSE"; @@ -898,7 +965,7 @@ int CmdEMVExec(const char *cmd) { uint8_t SFIend = AFL->value[i * 4 + 2]; uint8_t SFIoffline = AFL->value[i * 4 + 3]; - PrintAndLogEx(NORMAL, "* * SFI[%02x] start:%02x end:%02x offline:%02x", SFI, SFIstart, SFIend, SFIoffline); + PrintAndLogEx(NORMAL, "* * SFI[%02x] start:%02x end:%02x offline count:%02x", SFI, SFIstart, SFIend, SFIoffline); if (SFI == 0 || SFI == 31 || SFIstart == 0 || SFIstart > SFIend) { PrintAndLogEx(NORMAL, "SFI ERROR! Skipped..."); continue; @@ -920,7 +987,7 @@ int CmdEMVExec(const char *cmd) { // Build Input list for Offline Data Authentication // EMV 4.3 book3 10.3, page 96 - if (SFIoffline) { + if (SFIoffline > 0) { if (SFI < 11) { const unsigned char *abuf = buf; size_t elmlen = len; @@ -935,6 +1002,8 @@ int CmdEMVExec(const char *cmd) { memcpy(&ODAiList[ODAiListLen], buf, len); ODAiListLen += len; } + + SFIoffline--; } } } @@ -1154,6 +1223,40 @@ int CmdEMVExec(const char *cmd) { } } + // VSDC + if (GetCardPSVendor(AID, AIDlen) == CV_VISA && (TrType == TT_VSDC || TrType == TT_CDA)){ + PrintAndLogEx(NORMAL, "\n--> VSDC transaction."); + + PrintAndLogEx(NORMAL, "* * Calc CDOL1"); + struct tlv *cdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x8c, NULL), tlvRoot, 0x01); // 0x01 - dummy tag + if (!cdol_data_tlv) { + PrintAndLogEx(WARNING, "Error: can't create CDOL1 TLV."); + dreturn(6); + } + + PrintAndLogEx(NORMAL, "CDOL1 data[%d]: %s", cdol_data_tlv->len, sprint_hex(cdol_data_tlv->value, cdol_data_tlv->len)); + + PrintAndLogEx(NORMAL, "* * AC1"); + // EMVAC_TC + EMVAC_CDAREQ --- to get SDAD + res = EMVAC(channel, true, (TrType == TT_CDA) ? EMVAC_TC + EMVAC_CDAREQ : EMVAC_TC, (uint8_t *)cdol_data_tlv->value, cdol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot); + + if (res) { + PrintAndLogEx(NORMAL, "AC1 error(%d): %4x. Exit...", res, sw); + dreturn(7); + } + + // process Format1 (0x80) and print Format2 (0x77) + ProcessACResponseFormat1(tlvRoot, buf, len, decodeTLV); + + PrintAndLogEx(NORMAL, "\n* * Processing online request\n"); + + // authorization response code from acquirer + const char HostResponse[] = "00"; //0 x3030 + PrintAndLogEx(NORMAL, "* * Host Response: `%s`", HostResponse); + tlvdb_change_or_add_node(tlvRoot, 0x8a, sizeof(HostResponse) - 1, (const unsigned char *)HostResponse); + + } + if (channel == ECC_CONTACTLESS) { DropField(); } @@ -1230,6 +1333,7 @@ int CmdEMVScan(const char *cmd) { #else CLIGetStrWithReturn(11, relfname, &relfnamelen); #endif + PrintChannel(channel); uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2; CLIParserFree(); @@ -1535,10 +1639,13 @@ int CmdEMVRoca(const char *cmd) { CLIParserInit("emv roca", "Tries to extract public keys and run the ROCA test against them.\n", "Usage:\n" - "\temv roca -w -> select CONTACT card and run test\n\temv roca -> select CONTACTLESS card and run test\n"); + "\temv roca -w -> select --CONTACT-- card and run test\n" + "\temv roca -> select --CONTACTLESS-- card and run test\n" + ); void* argtable[] = { arg_param_begin, + arg_lit0("tT", "selftest", "self test"), arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."), arg_param_end }; @@ -1546,10 +1653,16 @@ int CmdEMVRoca(const char *cmd) { EMVCommandChannel channel = ECC_CONTACTLESS; if (arg_get_lit(1)) + return roca_self_test(); +#ifdef WITH_SMARTCARD + if (arg_get_lit(2)) channel = ECC_CONTACT; +#endif + PrintChannel(channel); // select card uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2; + char *PSE_or_PPSE = psenum == 1 ? "PSE" : "PPSE"; SetAPDULogging(false); @@ -1557,18 +1670,18 @@ int CmdEMVRoca(const char *cmd) { const char *al = "Applets list"; struct tlvdb *tlvSelect = tlvdb_fixed(1, strlen(al), (const unsigned char *)al); - // EMV PPSE - PrintAndLogEx(NORMAL, "--> PPSE."); - res = EMVSearchPSE(channel, false, true, psenum, false, tlvSelect); + // EMV PSE/PPSE + PrintAndLogEx(NORMAL, "--> %s.", PSE_or_PPSE); + res = EMVSearchPSE(channel, true, true, psenum, false, tlvSelect); - // check PPSE and select application id + // check PSE/PPSE and select application id if (!res) { TLVPrintAIDlistFromSelectTLV(tlvSelect); } else { // EMV SEARCH with AID list PrintAndLogEx(NORMAL, "--> AID search."); if (EMVSearch(channel, false, true, false, tlvSelect)) { - PrintAndLogEx(ERR, "Can't found any of EMV AID. Exit..."); + PrintAndLogEx(ERR, "Couldn't find any known EMV AID. Exit..."); tlvdb_free(tlvSelect); DropField(); return 3; @@ -1579,7 +1692,7 @@ int CmdEMVRoca(const char *cmd) { } // EMV SELECT application - SetAPDULogging(false); + SetAPDULogging(true); EMVSelectApplication(tlvSelect, AID, &AIDlen); tlvdb_free(tlvSelect); diff --git a/client/emv/emv_pki.c b/client/emv/emv_pki.c index da102291..1ff1e4c6 100644 --- a/client/emv/emv_pki.c +++ b/client/emv/emv_pki.c @@ -41,7 +41,8 @@ static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk, uint8_t msgtype, size_t *len, const struct tlv *cert_tlv, - ... /* A list of tlv pointers, end with NULL */ + int tlv_count, + ... /* A list of tlv pointers */ ) { struct crypto_pk *kcp; @@ -99,20 +100,23 @@ static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk, size_t hash_len = crypto_hash_get_size(ch); crypto_hash_write(ch, data + 1, data_len - 2 - hash_len); - va_start(vl, cert_tlv); - while (true) { + 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) - break; + continue; crypto_hash_write(ch, add_tlv->value, add_tlv->len); } va_end(vl); - if (memcmp(data + data_len - 1 - hash_len, crypto_hash_read(ch), 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(crypto_hash_read(ch), hash_len)); + printf("calculated: %s\n",sprint_hex(hash, hash_len)); if (strictExecution) { crypto_hash_close(ch); @@ -165,6 +169,7 @@ static struct emv_pk *emv_pki_decode_key_ex(const struct emv_pk *enc_pk, const struct tlv *exp_tlv, const struct tlv *rem_tlv, const struct tlv *add_tlv, + const struct tlv *sdatl_tlv, bool showData ) { @@ -190,9 +195,11 @@ static struct emv_pk *emv_pki_decode_key_ex(const struct emv_pk *enc_pk, 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"); @@ -275,9 +282,10 @@ static struct emv_pk *emv_pki_decode_key(const struct emv_pk *enc_pk, const struct tlv *cert_tlv, const struct tlv *exp_tlv, const struct tlv *rem_tlv, - const struct tlv *add_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, false); + 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) @@ -287,17 +295,30 @@ struct emv_pk *emv_pki_recover_issuer_cert(const struct emv_pk *pk, struct tlvdb 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) { - return emv_pki_decode_key(pk, 4, + 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_tlv, + &sda_tdata); + + 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) @@ -307,17 +328,62 @@ struct emv_pk *emv_pki_recover_icc_pe_cert(const struct emv_pk *pk, struct tlvdb 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; + + *sdatl_len = 0; + + 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; + } + } + + if (len) { + *sdatl_len = len; + unsigned char *value = malloc(len); + memcpy(value, buf, len); + return value; + } + + 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; + + // 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); + free(sdatl); // malloc here: emv_pki_sdatl_fill + if (!data || data_len < 5) return NULL; @@ -345,6 +411,7 @@ struct tlvdb *emv_pki_recover_idn_ex(const struct emv_pk *enc_pk, const struct t 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); @@ -380,6 +447,7 @@ struct tlvdb *emv_pki_recover_atc_ex(const struct emv_pk *enc_pk, const struct t 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), @@ -456,6 +524,7 @@ struct tlvdb *emv_pki_perform_cda_ex(const struct emv_pk *enc_pk, const struct t 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) { diff --git a/client/emv/emv_pki.h b/client/emv/emv_pki.h index 6fa7b12e..f5d80bd6 100644 --- a/client/emv/emv_pki.h +++ b/client/emv/emv_pki.h @@ -23,6 +23,7 @@ extern void PKISetStrictExecution(bool se); +unsigned char *emv_pki_sdatl_fill(const struct tlvdb *db, size_t *sdatl_len); struct emv_pk *emv_pki_recover_issuer_cert(const struct emv_pk *pk, struct tlvdb *db); struct emv_pk *emv_pki_recover_icc_cert(const struct emv_pk *pk, struct tlvdb *db, const struct tlv *sda_tlv); struct emv_pk *emv_pki_recover_icc_pe_cert(const struct emv_pk *pk, struct tlvdb *db); diff --git a/client/emv/emv_roca.c b/client/emv/emv_roca.c index 3701ddf8..bc317db8 100644 --- a/client/emv/emv_roca.c +++ b/client/emv/emv_roca.c @@ -28,6 +28,7 @@ #include #include "ui.h" +#include "util.h" #include "mbedtls/bignum.h" @@ -146,11 +147,10 @@ cleanup: return ret; } -int roca_self_test( int verbose ) { +int roca_self_test( void ) { int ret = 0; - if( verbose != 0 ) - printf( "\nROCA check vulnerability tests\n" ); + 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"\ @@ -158,16 +158,13 @@ int roca_self_test( int verbose ) { "\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( verbose != 0 ) - printf( " ROCA positive test: " ); if (emv_rocacheck(keyp, 64, false)) { - if( verbose != 0 ) - printf( "passed\n" ); - } else { - ret = 1; - if( verbose != 0 ) - printf( "failed\n" ); + PrintAndLogEx(SUCCESS, "Weak modulus [ %s]", _GREEN_(PASS) ); + } + else { + ret++; + PrintAndLogEx(FAILED, "Weak modulus [ %s]", _RED_(FAIL) ); } // negative @@ -176,18 +173,12 @@ int roca_self_test( int verbose ) { "\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( verbose != 0 ) - printf( " ROCA negative test: " ); - if (emv_rocacheck(keyn, 64, false)) { - ret = 1; - if( verbose != 0 ) - printf( "failed\n" ); + ret++; + PrintAndLogEx(FAILED, "Strong modulus [ %s]", _RED_(FAIL) ); } else { - if( verbose != 0 ) - printf( "passed\n" ); + PrintAndLogEx(SUCCESS, "Strong modulus [ %s]", _GREEN_(PASS) ); } - return ret; } diff --git a/client/emv/emv_roca.h b/client/emv/emv_roca.h index b0b9a0ea..2bb391f3 100644 --- a/client/emv/emv_roca.h +++ b/client/emv/emv_roca.h @@ -30,7 +30,7 @@ #define ROCA_PRINTS_LENGTH 17 extern bool emv_rocacheck( const unsigned char *buf, size_t buflen, bool verbose ); -extern int roca_self_test( int verbose ); +extern int roca_self_test( void ); #endif diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index 78a30206..8deb4aa6 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -387,11 +387,76 @@ int EMVSelectPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO return res; } + +int EMVSelectWithRetry(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { + int retrycnt = 0; + int res = 0; + do { + res = EMVSelect(channel, false, true, AID, AIDLen, Result, MaxResultLen, ResultLen, sw, tlv); + + // retry if error and not returned sw error + if (res && res != 5) { + if (++retrycnt < 3){ + continue; + } else { + // card select error, proxmark error + if (res == 1) { + PrintAndLogEx(WARNING, "Exit..."); + return 1; + } + + retrycnt = 0; + PrintAndLogEx(NORMAL, "Retry failed [%s]. Skiped...", sprint_hex_inrow(AID, AIDLen)); + return res; + } + } + } while (res && res != 5); + + return res; +} + + +int EMVCheckAID(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlvdbelm, struct tlvdb *tlv){ + uint8_t data[APDU_RESPONSE_LEN] = {0}; + size_t datalen = 0; + int res = 0; + uint16_t sw = 0; + + while (tlvdbelm) { + const struct tlv *tgAID = tlvdb_get_inchild(tlvdbelm, 0x4f, NULL); + if (tgAID) { + res = EMVSelectWithRetry(channel, false, true, (uint8_t *)tgAID->value, tgAID->len, data, sizeof(data), &datalen, &sw, tlv); + + // if returned sw error + if (res == 5) { + // next element + tlvdbelm = tlvdb_find_next(tlvdbelm, 0x61); + continue; + } + + if (res) + break; + + // all is ok + if (decodeTLV){ + PrintAndLogEx(NORMAL, "%s:", sprint_hex_inrow(tgAID->value, tgAID->len)); + TLVPrintFromBuffer(data, datalen); + } + } + tlvdbelm = tlvdb_find_next(tlvdbelm, 0x61); + } + return res; +} + + int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, bool decodeTLV, struct tlvdb *tlv) { uint8_t data[APDU_RESPONSE_LEN] = {0}; size_t datalen = 0; + uint8_t sfidata[0x11][APDU_RESPONSE_LEN] = {0}; + size_t sfidatalen[0x11] = {0}; uint16_t sw = 0; int res; + bool fileFound = false; char *PSE_or_PPSE = PSENum == 1 ? "PSE" : "PPSE"; @@ -399,50 +464,73 @@ int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO res = EMVSelectPSE(channel, ActivateField, true, PSENum, data, sizeof(data), &datalen, &sw); if (!res){ + if (sw != 0x9000) { + PrintAndLogEx(FAILED, "Select PSE error. APDU error: %04x.", sw); + return 1; + } + struct tlvdb *t = NULL; t = tlvdb_parse_multi(data, datalen); if (t) { - int retrycnt = 0; - struct tlvdb *ttmp = tlvdb_find_path(t, (tlv_tag_t[]){0x6f, 0xa5, 0xbf0c, 0x61, 0x00}); - if (!ttmp) - PrintAndLogEx(FAILED, "%s doesn't have any records.", PSE_or_PPSE); - - while (ttmp) { - const struct tlv *tgAID = tlvdb_get_inchild(ttmp, 0x4f, NULL); - if (tgAID) { - res = EMVSelect(channel, false, true, (uint8_t *)tgAID->value, tgAID->len, data, sizeof(data), &datalen, &sw, tlv); - - // retry if error and not returned sw error - if (res && res != 5) { - if (++retrycnt < 3){ - continue; - } else { - // card select error, proxmark error - if (res == 1) { - PrintAndLogEx(WARNING, "Exit..."); - return 1; - } - - retrycnt = 0; - PrintAndLogEx(NORMAL, "Retry failed [%s]. Skiped...", sprint_hex_inrow(tgAID->value, tgAID->len)); - } - - // next element - ttmp = tlvdb_find_next(ttmp, 0x61); - continue; + // PSE/PPSE with SFI + struct tlvdb *tsfi = tlvdb_find_path(t, (tlv_tag_t[]){0x6f, 0xa5, 0x88, 0x00}); + if (tsfi) { + uint8_t sfin = 0; + tlv_get_uint8(tlvdb_get_tlv(tsfi), &sfin); + PrintAndLogEx(INFO, "* PPSE get SFI: 0x%02x.", sfin); + + for (uint8_t ui = 0x01; ui <= 0x10; ui++) { + PrintAndLogEx(INFO, "* * Get SFI: 0x%02x. num: 0x%02x", sfin, ui); + res = EMVReadRecord(channel, true, sfin, ui, sfidata[ui], APDU_RESPONSE_LEN, &sfidatalen[ui], &sw, NULL); + + // end of records + if (sw == 0x6a83) { + sfidatalen[ui] = 0; + PrintAndLogEx(INFO, "* * PPSE get SFI. End of records."); + break; + } + + // error catch! + if (sw != 0x9000) { + sfidatalen[ui] = 0; + PrintAndLogEx(FAILED, "PPSE get Error. APDU error: %04x.", sw); + break; } - retrycnt = 0; - // all is ok if (decodeTLV){ - PrintAndLogEx(NORMAL, "%s:", sprint_hex_inrow(tgAID->value, tgAID->len)); - TLVPrintFromBuffer(data, datalen); + TLVPrintFromBuffer(sfidata[ui], sfidatalen[ui]); } } - ttmp = tlvdb_find_next(ttmp, 0x61); + for (uint8_t ui = 0x01; ui <= 0x10; ui++) { + if (sfidatalen[ui]) { + struct tlvdb *tsfi = NULL; + tsfi = tlvdb_parse_multi(sfidata[ui], sfidatalen[ui]); + if (tsfi) { + struct tlvdb *tsfitmp = tlvdb_find_path(tsfi, (tlv_tag_t[]){0x70, 0x61, 0x00}); + if (!tsfitmp) { + PrintAndLogEx(FAILED, "SFI 0x%02d doesn't have any records.", sfidatalen[ui]); + continue; + } + res = EMVCheckAID(channel, decodeTLV, tsfitmp, tlv); + fileFound = true; + } + tlvdb_free(tsfi); + } + } } + + // PSE/PPSE plain (wo SFI) + struct tlvdb *ttmp = tlvdb_find_path(t, (tlv_tag_t[]){0x6f, 0xa5, 0xbf0c, 0x61, 0x00}); + if (ttmp) { + res = EMVCheckAID(channel, decodeTLV, ttmp, tlv); + fileFound = true; + } + + if (!fileFound) + PrintAndLogEx(FAILED, "PPSE doesn't have any records."); + tlvdb_free(t); } else { PrintAndLogEx(WARNING, "%s ERROR: Can't get TLV from response.", PSE_or_PPSE); @@ -650,7 +738,7 @@ int trSDA(struct tlvdb *tlv) { struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv); if (dac_db) { const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL); - PrintAndLogEx(NORMAL, "SDA verified OK. (%02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]); + PrintAndLogEx(NORMAL, "SDA verified OK. (Data Authentication Code: %02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]); tlvdb_add(tlv, dac_db); } else { emv_pk_free(issuer_pk); @@ -679,12 +767,12 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { } const struct tlv *sda_tlv = tlvdb_get(tlv, 0x21, NULL); - if (!sda_tlv || sda_tlv->len < 1) { +/* if (!sda_tlv || sda_tlv->len < 1) { it may be 0!!!! emv_pk_free(pk); PrintAndLogEx(WARNING, "Error: Can't find input list for Offline Data Authentication. Exit."); return 3; } - +*/ struct emv_pk *issuer_pk = emv_pki_recover_issuer_cert(pk, tlv); if (!issuer_pk) { emv_pk_free(pk); @@ -707,7 +795,7 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { if (!icc_pk) { emv_pk_free(pk); emv_pk_free(issuer_pk); - PrintAndLogEx(WARNING, "Error: ICC setrificate not found. Exit."); + PrintAndLogEx(WARNING, "Error: ICC certificate not found. Exit."); return 2; } PrintAndLogEx(SUCCESS, "ICC PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n", @@ -722,21 +810,25 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { icc_pk->serial[2] ); - struct emv_pk *icc_pe_pk = emv_pki_recover_icc_pe_cert(issuer_pk, tlv); - if (!icc_pe_pk) { - PrintAndLogEx(WARNING, "WARNING: ICC PE PK recover error. "); + if (tlvdb_get(tlv, 0x9f2d, NULL)) { + struct emv_pk *icc_pe_pk = emv_pki_recover_icc_pe_cert(issuer_pk, tlv); + if (!icc_pe_pk) { + PrintAndLogEx(WARNING, "WARNING: ICC PE PK recover error. "); + } else { + PrintAndLogEx(SUCCESS, "ICC PE PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n", + icc_pe_pk->rid[0], + icc_pe_pk->rid[1], + icc_pe_pk->rid[2], + icc_pe_pk->rid[3], + icc_pe_pk->rid[4], + icc_pe_pk->index, + icc_pe_pk->serial[0], + icc_pe_pk->serial[1], + icc_pe_pk->serial[2] + ); + } } else { - PrintAndLogEx(SUCCESS, "ICC PE PK recovered. RID %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx CSN %02hhx:%02hhx:%02hhx\n", - icc_pe_pk->rid[0], - icc_pe_pk->rid[1], - icc_pe_pk->rid[2], - icc_pe_pk->rid[3], - icc_pe_pk->rid[4], - icc_pe_pk->index, - icc_pe_pk->serial[0], - icc_pe_pk->serial[1], - icc_pe_pk->serial[2] - ); + PrintAndLogEx(INFO, "ICC PE PK (PIN Encipherment Public Key Certificate) not found.\n"); } // 9F4B: Signed Dynamic Application Data @@ -778,7 +870,7 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { struct tlvdb *dac_db = emv_pki_recover_dac(issuer_pk, tlv, sda_tlv); if (dac_db) { const struct tlv *dac_tlv = tlvdb_get(dac_db, 0x9f45, NULL); - PrintAndLogEx(NORMAL, "SDA verified OK. (%02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]); + PrintAndLogEx(NORMAL, "SDAD verified OK. (Data Authentication Code: %02hhx:%02hhx)\n", dac_tlv->value[0], dac_tlv->value[1]); tlvdb_add(tlv, dac_db); } else { PrintAndLogEx(WARNING, "Error: SSAD verify error"); @@ -822,9 +914,16 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { if (len < 3 ) { PrintAndLogEx(WARNING, "Error: Internal Authenticate format1 parsing error. length=%d", len); } else { + // parse response 0x80 + struct tlvdb *t80 = tlvdb_parse_multi(buf, len); + const struct tlv * t80tlv = tlvdb_get_tlv(t80); + // 9f4b Signed Dynamic Application Data - dda_db = tlvdb_fixed(0x9f4b, len - 2, buf + 2); + dda_db = tlvdb_fixed(0x9f4b, t80tlv->len, t80tlv->value); tlvdb_add(tlv, dda_db); + + tlvdb_free(t80); + if (decodeTLV){ PrintAndLogEx(NORMAL, "* * Decode response format 1:"); TLVPrintFromTLV(dda_db); diff --git a/client/emv/test/cryptotest.c b/client/emv/test/cryptotest.c index b0212a70..58cbdd4b 100644 --- a/client/emv/test/cryptotest.c +++ b/client/emv/test/cryptotest.c @@ -91,14 +91,14 @@ int ExecuteCryptoTests(bool verbose) { res = exec_crypto_test(verbose); if (res) TestFail = true; - res = roca_self_test(verbose); + res = roca_self_test(); if (res) TestFail = true; PrintAndLog("\n--------------------------"); if (TestFail) - PrintAndLog("Test(s) [ERROR]."); + PrintAndLogEx(FAILED, "\tTest(s) [ %s ]", _RED_(FAIL) ); else - PrintAndLog("Tests [OK]."); + PrintAndLogEx(SUCCESS, "\tTest(s) [ %s ]", _GREEN_(OK) ); return TestFail; } diff --git a/client/emv/tlv.c b/client/emv/tlv.c index 35bdb5d4..9722c931 100644 --- a/client/emv/tlv.c +++ b/client/emv/tlv.c @@ -359,12 +359,15 @@ void tlvdb_add(struct tlvdb *tlvdb, struct tlvdb *other) tlvdb->next = other; } -void tlvdb_change_or_add_node(struct tlvdb *tlvdb, tlv_tag_t tag, size_t len, const unsigned char *value) +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 - tlvdb_add(tlvdb, tlvdb_fixed(tag, len, value)); + 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)) @@ -400,11 +403,19 @@ void tlvdb_change_or_add_node(struct tlvdb *tlvdb, tlv_tag_t tag, size_t len, co // free old element with childrens telm->next = NULL; tlvdb_free(telm); + + if (tlvdb_elm) + *tlvdb_elm = tnewelm; } 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); +} + void tlvdb_visit(const struct tlvdb *tlvdb, tlv_cb cb, void *data, int level) { struct tlvdb *next = NULL; @@ -534,3 +545,40 @@ struct tlvdb *tlvdb_elm_get_parent(struct tlvdb *tlvdb) { return tlvdb->parent; } + +bool tlv_get_uint8(const struct tlv *etlv, uint8_t *value) +{ + *value = 0; + if (etlv) + { + if (etlv->len == 0) + return true; + + 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; + + if (etlv->len <= 4) + { + for (int i = 0; i < etlv->len; i++) + { + *value += etlv->value[i] * (1 << (i * 8)); + } + return true; + } + } + return false; +} diff --git a/client/emv/tlv.h b/client/emv/tlv.h index b25b51de..80f6b74f 100644 --- a/client/emv/tlv.h +++ b/client/emv/tlv.h @@ -50,6 +50,7 @@ struct tlvdb *tlvdb_find_path(struct tlvdb *tlvdb, tlv_tag_t tag[]); void tlvdb_add(struct tlvdb *tlvdb, struct tlvdb *other); void tlvdb_change_or_add_node(struct tlvdb *tlvdb, tlv_tag_t tag, size_t len, const unsigned char *value); +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); void tlvdb_visit(const struct tlvdb *tlvdb, tlv_cb cb, void *data, int level); const struct tlv *tlvdb_get(const struct tlvdb *tlvdb, tlv_tag_t tag, const struct tlv *prev); @@ -61,4 +62,10 @@ unsigned char *tlv_encode(const struct tlv *tlv, size_t *len); bool tlv_is_constructed(const struct tlv *tlv); bool tlv_equal(const struct tlv *a, const struct tlv *b); +bool tlv_get_uint8(const struct tlv *etlv, uint8_t *value); +bool tlv_get_int(const struct tlv *etlv, int *value); + +bool tlv_get_uint8(const struct tlv *etlv, uint8_t *value); +bool tlv_get_int(const struct tlv *etlv, int *value); + #endif From fbf77474f53809f57e8d32a8e6e210bf921c424b Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Wed, 6 Feb 2019 07:51:49 +0100 Subject: [PATCH 060/189] Update list of Certificate Authorities Public Keys (source: https://www.eftlab.co.uk/index.php/site-map/knowledge-base/243-ca-public-keys) (#777) * allow tabs in client/emv/capk.txt * fix issue with printing RID and CSN of certificates --- client/emv/capk.txt | 194 ++++++++++++++++++++++++++++++++++++------- client/emv/cmdemv.c | 10 ++- client/emv/emv_pk.c | 14 ++-- client/emv/emv_pki.c | 2 +- 4 files changed, 177 insertions(+), 43 deletions(-) diff --git a/client/emv/capk.txt b/client/emv/capk.txt index 0925fbad..228fa79b 100644 --- a/client/emv/capk.txt +++ b/client/emv/capk.txt @@ -1,32 +1,162 @@ -a0:00:00:00:03 01 091231 rsa 03 c6:96:03:42:13:d7:d8:54:69:84:57:9d:1d:0f:0e:a5:19:cf:f8:de:ff:c4:29:35:4c:f3:a8:71:a6:f7:18:3f:12:28:da:5c:74:70:c0:55:38:71:00:cb:93:5a:71:2c:4e:28:64:df:5d:64:ba:93:fe:7e:63:e7:1f:25:b1:e5:f5:29:85:75:eb:e1:c6:3a:a6:17:70:69:17:91:1d:c2:a7:5a:c2:8b:25:1c:7e:f4:0f:23:65:91:24:90:b9:39:bc:a2:12:4a:30:a2:8f:54:40:2c:34:ae:ca:33:1a:b6:7e:1e:79:b2:85:dd:57:71:b5:d9:ff:79:ea:63:0b:75 sha1 d3:4a:6a:77:60:11:c7:e7:ce:3a:ec:5f:03:ad:2f:8c:fc:55:03:cc -a0:00:00:00:03 07 171231 rsa 03 a8:9f:25:a5:6f:a6:da:25:8c:8c:a8:b4:04:27:d9:27:b4:a1:eb:4d:7e:a3:26:bb:b1:2f:97:de:d7:0a:e5:e4:48:0f:c9:c5:e8:a9:72:17:71:10:a1:cc:31:8d:06:d2:f8:f5:c4:84:4a:c5:fa:79:a4:dc:47:0b:b1:1e:d6:35:69:9c:17:08:1b:90:f1:b9:84:f1:2e:92:c1:c5:29:27:6d:8a:f8:ec:7f:28:49:20:97:d8:cd:5b:ec:ea:16:fe:40:88:f6:cf:ab:4a:1b:42:32:8a:1b:99:6f:92:78:b0:b7:e3:31:1c:a5:ef:85:6c:2f:88:84:74:b8:36:12:a8:2e:4e:00:d0:cd:40:69:a6:78:31:40:43:3d:50:72:5f sha1 b4:bc:56:cc:4e:88:32:49:32:cb:c6:43:d6:89:8f:6f:e5:93:b1:72 -a0:00:00:00:03 08 221231 rsa 03 d9:fd:6e:d7:5d:51:d0:e3:06:64:bd:15:70:23:ea:a1:ff:a8:71:e4:da:65:67:2b:86:3d:25:5e:81:e1:37:a5:1d:e4:f7:2b:cc:9e:44:ac:e1:21:27:f8:7e:26:3d:3a:f9:dd:9c:f3:5c:a4:a7:b0:1e:90:70:00:ba:85:d2:49:54:c2:fc:a3:07:48:25:dd:d4:c0:c8:f1:86:cb:02:0f:68:3e:02:f2:de:ad:39:69:13:3f:06:f7:84:51:66:ac:eb:57:ca:0f:c2:60:34:45:46:98:11:d2:93:bf:ef:ba:fa:b5:76:31:b3:dd:91:e7:96:bf:85:0a:25:01:2f:1a:e3:8f:05:aa:5c:4d:6d:03:b1:dc:2e:56:86:12:78:59:38:bb:c9:b3:cd:3a:91:0c:1d:a5:5a:5a:92:18:ac:e0:f7:a2:12:87:75:26:82:f1:58:32:a6:78:d6:e1:ed:0b sha1 20:d2:13:12:69:55:de:20:5a:dc:2f:d2:82:2b:d2:2d:e2:1c:f9:a8 -a0:00:00:00:03 09 221231 rsa 03 9d:91:22:48:de:0a:4e:39:c1:a7:dd:e3:f6:d2:58:89:92:c1:a4:09:5a:fb:d1:82:4d:1b:a7:48:47:f2:bc:49:26:d2:ef:d9:04:b4:b5:49:54:cd:18:9a:54:c5:d1:17:96:54:f8:f9:b0:d2:ab:5f:03:57:eb:64:2f:ed:a9:5d:39:12:c6:57:69:45:fa:b8:97:e7:06:2c:aa:44:a4:aa:06:b8:fe:6e:3d:ba:18:af:6a:e3:73:8e:30:42:9e:e9:be:03:42:7c:9d:64:f6:95:fa:8c:ab:4b:fe:37:68:53:ea:34:ad:1d:76:bf:ca:d1:59:08:c0:77:ff:e6:dc:55:21:ec:ef:5d:27:8a:96:e2:6f:57:35:9f:fa:ed:a1:94:34:b9:37:f1:ad:99:9d:c5:c4:1e:b1:19:35:b4:4c:18:10:0e:85:7f:43:1a:4a:5a:6b:b6:51:14:f1:74:c2:d7:b5:9f:df:23:7d:6b:b1:dd:09:16:e6:44:d7:09:de:d5:64:81:47:7c:75:d9:5c:dd:68:25:46:15:f7:74:0e:c0:7f:33:0a:c5:d6:7b:cd:75:bf:23:d2:8a:14:08:26:c0:26:db:de:97:1a:37:cd:3e:f9:b8:df:64:4a:c3:85:01:05:01:ef:c6:50:9d:7a:41 sha1 1f:f8:0a:40:17:3f:52:d7:d2:7e:0f:26:a1:46:a1:c8:cc:b2:90:46 -a0:00:00:00:03 95 000000 rsa 03 be:9e:1f:a5:e9:a8:03:85:29:99:c4:ab:43:2d:b2:86:00:dc:d9:da:b7:6d:fa:aa:47:35:5a:0f:e3:7b:15:08:ac:6b:f3:88:60:d3:c6:c2:e5:b1:2a:3c:aa:f2:a7:00:5a:72:41:eb:aa:77:71:11:2c:74:cf:9a:06:34:65:2f:bc:a0:e5:98:0c:54:a6:47:61:ea:10:1a:11:4e:0f:0b:55:72:ad:d5:7d:01:0b:7c:9c:88:7e:10:4c:a4:ee:12:72:da:66:d9:97:b9:a9:0b:5a:6d:62:4a:b6:c5:7e:73:c8:f9:19:00:0e:b5:f6:84:89:8e:f8:c3:db:ef:b3:30:c6:26:60:be:d8:8e:a7:8e:90:9a:ff:05:f6:da:62:7b sha1 ee:15:11:ce:c7:10:20:a9:b9:04:43:b3:7b:1d:5f:6e:70:30:30:f6 -a0:00:00:00:03 92 000000 rsa 03 99:6a:f5:6f:56:91:87:d0:92:93:c1:48:10:45:0e:d8:ee:33:57:39:7b:18:a2:45:8e:fa:a9:2d:a3:b6:df:65:14:ec:06:01:95:31:8f:d4:3b:e9:b8:f0:cc:66:9e:3f:84:40:57:cb:dd:f8:bd:a1:91:bb:64:47:3b:c8:dc:9a:73:0d:b8:f6:b4:ed:e3:92:41:86:ff:d9:b8:c7:73:57:89:c2:3a:36:ba:0b:8a:f6:53:72:eb:57:ea:5d:89:e7:d1:4e:9c:7b:6b:55:74:60:f1:08:85:da:16:ac:92:3f:15:af:37:58:f0:f0:3e:bd:3c:5c:2c:94:9c:ba:30:6d:b4:4e:6a:2c:07:6c:5f:67:e2:81:d7:ef:56:78:5d:c4:d7:59:45:e4:91:f0:19:18:80:0a:9e:2d:c6:6f:60:08:05:66:ce:0d:af:8d:17:ea:d4:6a:d8:e3:0a:24:7c:9f sha1 42:9c:95:4a:38:59:ce:f9:12:95:f6:63:c9:63:e5:82:ed:6e:b2:53 -a0:00:00:00:03 94 000000 rsa 03 ac:d2:b1:23:02:ee:64:4f:3f:83:5a:bd:1f:c7:a6:f6:2c:ce:48:ff:ec:62:2a:a8:ef:06:2b:ef:6f:b8:ba:8b:c6:8b:bf:6a:b5:87:0e:ed:57:9b:c3:97:3e:12:13:03:d3:48:41:a7:96:d6:dc:bc:41:db:f9:e5:2c:46:09:79:5c:0c:cf:7e:e8:6f:a1:d5:cb:04:10:71:ed:2c:51:d2:20:2f:63:f1:15:6c:58:a9:2d:38:bc:60:bd:f4:24:e1:77:6e:2b:c9:64:80:78:a0:3b:36:fb:55:43:75:fc:53:d5:7c:73:f5:16:0e:a5:9f:3a:fc:53:98:ec:7b:67:75:8d:65:c9:bf:f7:82:8b:6b:82:d4:be:12:4a:41:6a:b7:30:19:14:31:1e:a4:62:c1:9f:77:1f:31:b3:b5:73:36:00:0d:ff:73:2d:3b:83:de:07:05:2d:73:03:54:d2:97:be:c7:28:71:dc:cf:0e:19:3f:17:1a:ba:27:ee:46:4c:6a:97:69:09:43:d5:9b:da:bb:2a:27:eb:71:ce:eb:da:fa:11:76:04:64:78:fd:62:fe:c4:52:d5:ca:39:32:96:53:0a:a3:f4:19:27:ad:fe:43:4a:2d:f2:ae:30:54:f8:84:06:57:a2:6e:0f:c6:17 sha1 c4:a3:c4:3c:cf:87:32:7d:13:6b:80:41:60:e4:7d:43:b6:0e:6e:0f -a0:00:00:00:04 03 000000 rsa 03 c2:49:07:47:fe:17:eb:05:84:c8:8d:47:b1:60:27:04:15:0a:dc:88:c5:b9:98:bd:59:ce:04:3e:de:bf:0f:fe:e3:09:3a:c7:95:6a:d3:b6:ad:45:54:c6:de:19:a1:78:d6:da:29:5b:e1:5d:52:20:64:5e:3c:81:31:66:6f:a4:be:5b:84:fe:13:1e:a4:4b:03:93:07:63:8b:9e:74:a8:c4:25:64:f8:92:a6:4d:f1:cb:15:71:2b:73:6e:33:74:f1:bb:b6:81:93:71:60:2d:89:70:e9:7b:90:07:93:c7:c2:a8:9a:4a:16:49:a5:9b:e6:80:57:4d:d0:b6:01:45 sha1 5a:dd:f2:1d:09:27:86:61:14:11:79:cb:ef:f2:72:ea:38:4b:13:bb -a0:00:00:00:04 04 000000 rsa 03 a6:da:42:83:87:a5:02:d7:dd:fb:7a:74:d3:f4:12:be:76:26:27:19:7b:25:43:5b:7a:81:71:6a:70:01:57:dd:d0:6f:7c:c9:9d:6c:a2:8c:24:70:52:7e:2c:03:61:6b:9c:59:21:73:57:c2:67:4f:58:3b:3b:a5:c7:dc:f2:83:86:92:d0:23:e3:56:24:20:b4:61:5c:43:9c:a9:7c:44:dc:9a:24:9c:fc:e7:b3:bf:b2:2f:68:22:8c:3a:f1:33:29:aa:4a:61:3c:f8:dd:85:35:02:37:3d:62:e4:9a:b2:56:d2:bc:17:12:0e:54:ae:dc:ed:6d:96:a4:28:7a:cc:5c:04:67:7d:4a:5a:32:0d:b8:be:e2:f7:75:e5:fe:c5 sha1 38:1a:03:5d:a5:8b:48:2e:e2:af:75:f4:c3:f2:ca:46:9b:a4:aa:6c -a0:00:00:00:04 05 000000 rsa 03 b8:04:8a:bc:30:c9:0d:97:63:36:54:3e:3f:d7:09:1c:8f:e4:80:0d:f8:20:ed:55:e7:e9:48:13:ed:00:55:5b:57:3f:ec:a3:d8:4a:f6:13:1a:65:1d:66:cf:f4:28:4f:b1:3b:63:5e:dd:0e:e4:01:76:d8:bf:04:b7:fd:1c:7b:ac:f9:ac:73:27:df:aa:8a:a7:2d:10:db:3b:8e:70:b2:dd:d8:11:cb:41:96:52:5e:a3:86:ac:c3:3c:0d:9d:45:75:91:64:69:c4:e4:f5:3e:8e:1c:91:2c:c6:18:cb:22:dd:e7:c3:56:8e:90:02:2e:6b:ba:77:02:02:e4:52:2a:2d:d6:23:d1:80:e2:15:bd:1d:15:07:fe:3d:c9:0c:a3:10:d2:7b:3e:fc:cd:8f:83:de:30:52:ca:d1:e4:89:38:c6:8d:09:5a:ac:91:b5:f3:7e:28:bb:49:ec:7e:d5:97 sha1 eb:fa:0d:5d:06:d8:ce:70:2d:a3:ea:e8:90:70:1d:45:e2:74:c8:45 -a0:00:00:00:04 06 000000 rsa 03 cb:26:fc:83:0b:43:78:5b:2b:ce:37:c8:1e:d3:34:62:2f:96:22:f4:c8:9a:ae:64:10:46:b2:35:34:33:88:3f:30:7f:b7:c9:74:16:2d:a7:2f:7a:4e:c7:5d:9d:65:73:36:86:5b:8d:30:23:d3:d6:45:66:76:25:c9:a0:7a:6b:7a:13:7c:f0:c6:41:98:ae:38:fc:23:80:06:fb:26:03:f4:1f:4f:3b:b9:da:13:47:27:0f:2f:5d:8c:60:6e:42:09:58:c5:f7:d5:0a:71:de:30:14:2f:70:de:46:88:89:b5:e3:a0:86:95:b9:38:a5:0f:c9:80:39:3a:9c:bc:e4:4a:d2:d6:4f:63:0b:b3:3a:d3:f5:f5:fd:49:5d:31:f3:78:18:c1:d9:40:71:34:2e:07:f1:be:c2:19:4f:60:35:ba:5d:ed:39:36:50:0e:b8:2d:fd:a6:e8:af:b6:55:b1:ef:3d:0d:7e:bf:86:b6:6d:d9:f2:9f:6b:1d:32:4f:e8:b2:6c:e3:8a:b2:01:3d:d1:3f:61:1e:7a:59:4d:67:5c:44:32:35:0e:a2:44:cc:34:f3:87:3c:ba:06:59:29:87:a1:d7:e8:52:ad:c2:2e:f5:a2:ee:28:13:20:31:e4:8f:74:03:7e:3b:34:ab:74:7f sha1 f9:10:a1:50:4d:5f:fb:79:3d:94:f3:b5:00:76:5e:1a:bc:ad:72:d9 -a0:00:00:00:04 00 000000 rsa 03 9c:6b:e5:ad:b1:0b:4b:e3:dc:e2:09:9b:4b:21:06:72:b8:96:56:eb:a0:91:20:4f:61:3e:cc:62:3b:ed:c9:c6:d7:7b:66:0e:8b:ae:ea:7f:7c:e3:0f:1b:15:38:79:a4:e3:64:59:34:3d:1f:e4:7a:cd:bd:41:fc:d7:10:03:0c:2b:a1:d9:46:15:97:98:2c:6e:1b:dd:08:55:4b:72:6f:5e:ff:79:13:ce:59:e7:9e:35:72:95:c3:21:e2:6d:0b:8b:e2:70:a9:44:23:45:c7:53:e2:aa:2a:cf:c9:d3:08:50:60:2f:e6:ca:c0:0c:6d:df:6b:8d:9d:9b:48:79:b2:82:6b:04:2a:07:f0:e5:ae:52:6a:3d:3c:4d:22:c7:2b:9e:aa:52:ee:d8:89:38:66:f8:66:38:7a:c0:5a:13:99 sha1 ec:0a:59:d3:5d:19:f0:31:e9:e8:cb:ec:56:db:80:e2:2b:1d:e1:30 -a0:00:00:00:04 02 000000 rsa 03 a9:9a:6d:3e:07:18:89:ed:9e:3a:0c:39:1c:69:b0:b8:04:fc:16:0b:2b:4b:dd:57:0c:92:dd:5a:0f:45:f5:3e:86:21:f7:c9:6c:40:22:42:66:73:5e:1e:e1:b3:c0:62:38:ae:35:04:63:20:fd:8e:81:f8:ce:b3:f8:b4:c9:7b:94:09:30:a3:ac:5e:79:00:86:da:d4:1a:6a:4f:51:17:ba:1c:e2:43:8a:51:ac:05:3e:b0:02:ae:d8:66:d2:c4:58:fd:73:35:90:21:a1:20:29:a0:c0:43:04:5c:11:66:4f:e0:21:9e:c6:3c:10:bf:21:55:bb:27:84:60:9a:10:64:21:d4:51:63:79:97:38:c1:c3:09:09:bb:6c:6f:e5:2b:bb:76:39:7b:97:40:ce:06:4a:61:3f:f8:41:11:85:f0:88:42:a4:23:ea:d2:0e:df:fb:ff:1c:d6:c3:fe:0c:98:21:47:91:99:c2:6d:85:72:cc:8a:ff:f0:87:a9:c3 sha1 33:40:8b:96:c8:14:74:2a:d7:35:36:c7:2f:09:26:e4:47:1e:8e:47 -a0:00:00:00:04 05 000000 rsa 03 a1:f5:e1:c9:bd:86:50:bd:43:ab:6e:e5:6b:89:1e:f7:45:9c:0a:24:fa:84:f9:12:7d:1a:6c:79:d4:93:0f:6d:b1:85:2e:25:10:f1:8b:61:cd:35:4d:b8:3a:35:6b:d1:90:b8:8a:b8:df:04:28:4d:02:a4:20:4a:7b:6c:b7:c5:55:19:77:a9:b3:63:79:ca:3d:e1:a0:8e:69:f3:01:c9:5c:c1:c2:05:06:95:92:75:f4:17:23:dd:5d:29:25:29:05:79:e5:a9:5b:0d:f6:32:3f:c8:e9:27:3d:6f:84:91:98:c4:99:62:09:16:6d:9b:fc:97:3c:36:1c:c8:26:e1 sha1 53:d0:49:03:b4:96:f5:95:44:a8:43:09:af:16:92:51:f2:89:68:74 -a0:00:00:00:04 ef 000000 rsa 03 a1:91:cb:87:47:3f:29:34:9b:5d:60:a8:8b:3e:ae:e0:97:3a:a6:f1:a0:82:f3:58:d8:49:fd:df:f9:c0:91:f8:99:ed:a9:79:2c:af:09:ef:28:f5:d2:24:04:b8:8a:22:93:ee:bb:c1:94:9c:43:be:a4:d6:0c:fd:87:9a:15:39:54:4e:09:e0:f0:9f:60:f0:65:b2:bf:2a:13:ec:c7:05:f3:d4:68:b9:d3:3a:e7:7a:d9:d3:f1:9c:a4:0f:23:dc:f5:eb:7c:04:dc:8f:69:eb:a5:65:b1:eb:cb:46:86:cd:27:47:85:53:0f:f6:f6:e9:ee:43:aa:43:fd:b0:2c:e0:0d:ae:c1:5c:7b:8f:d6:a9:b3:94:ba:ba:41:9d:3f:6d:c8:5e:16:56:9b:e8:e7:69:89:68:8e:fe:a2:df:22:ff:7d:35:c0:43:33:8d:ea:a9:82:a0:2b:86:6d:e5:32:85:19:eb:bc:d6:f0:3c:dd:68:66:73:84:7f:84:db:65:1a:b8:6c:28:cf:14:62:56:2c:57:7b:85:35:64:a2:90:c8:55:6d:81:85:31:26:8d:25:cc:98:a4:cc:6a:0b:df:ff:da:2d:cc:a3:a9:4c:99:85:59:e3:07:fd:df:91:50:06:d9:a9:87:b0:7d:da:eb:3b sha1 21:76:6e:bb:0e:e1:22:af:b6:5d:78:45:b7:3d:b4:6b:ab:65:42:7a -a0:00:00:00:04 f1 000000 rsa 03 a0:dc:f4:bd:e1:9c:35:46:b4:b6:f0:41:4d:17:4d:de:29:4a:ab:bb:82:8c:5a:83:4d:73:aa:e2:7c:99:b0:b0:53:a9:02:78:00:72:39:b6:45:9f:f0:bb:cd:7b:4b:9c:6c:50:ac:02:ce:91:36:8d:a1:bd:21:aa:ea:db:c6:53:47:33:7d:89:b6:8f:5c:99:a0:9d:05:be:02:dd:1f:8c:5b:a2:0e:2f:13:fb:2a:27:c4:1d:3f:85:ca:d5:cf:66:68:e7:58:51:ec:66:ed:bf:98:85:1f:d4:e4:2c:44:c1:d5:9f:59:84:70:3b:27:d5:b9:f2:1b:8f:a0:d9:32:79:fb:bf:69:e0:90:64:29:09:c9:ea:27:f8:98:95:95:41:aa:67:57:f5:f6:24:10:4f:6e:1d:3a:95:32:f2:a6:e5:15:15:ae:ad:1b:43:b3:d7:83:50:88:a2:fa:fa:7b:e7 sha1 d8:e6:8d:a1:67:ab:5a:85:d8:c3:d5:5e:cb:9b:05:17:a1:a5:b4:bb -a0:00:00:00:04 f3 000000 rsa 03 98:f0:c7:70:f2:38:64:c2:e7:66:df:02:d1:e8:33:df:f4:ff:e9:2d:69:6e:16:42:f0:a8:8c:56:94:c6:47:9d:16:db:15:37:bf:e2:9e:4f:dc:6e:6e:8a:fd:1b:0e:b7:ea:01:24:72:3c:33:31:79:bf:19:e9:3f:10:65:8b:2f:77:6e:82:9e:87:da:ed:a9:c9:4a:8b:33:82:19:9a:35:0c:07:79:77:c9:7a:ff:08:fd:11:31:0a:c9:50:a7:2c:3c:a5:00:2e:f5:13:fc:cc:28:6e:64:6e:3c:53:87:53:5d:50:95:14:b3:b3:26:e1:23:4f:9c:b4:8c:36:dd:d4:4b:41:6d:23:65:40:34:a6:6f:40:3b:a5:11:c5:ef:a3 sha1 a6:9a:c7:60:3d:af:56:6e:97:2d:ed:c2:cb:43:3e:07:e8:b0:1a:9a -a0:00:00:00:04 f5 000000 rsa 01:00:01 a6:e6:fb:72:17:95:06:f8:60:cc:ca:8c:27:f9:9c:ec:d9:4c:7d:4f:31:91:d3:03:bb:ee:37:48:1c:7a:a1:5f:23:3b:a7:55:e9:e4:37:63:45:a9:a6:7e:79:94:bd:c1:c6:80:bb:35:22:d8:c9:3e:b0:cc:c9:1a:d3:1a:d4:50:da:30:d3:37:66:2d:19:ac:03:e2:b4:ef:5f:6e:c1:82:82:d4:91:e1:97:67:d7:b2:45:42:df:de:ff:6f:62:18:55:03:53:20:69:bb:b3:69:e3:bb:9f:b1:9a:c6:f1:c3:0b:97:d2:49:ee:e7:64:e0:ba:c9:7f:25:c8:73:d9:73:95:3e:51:53:a4:20:64:bb:fa:bf:d0:6a:4b:b4:86:86:0b:f6:63:74:06:c9:fc:36:81:3a:4a:75:f7:5c:31:cc:a9:f6:9f:8d:e5:9a:de:ce:f6:bd:e7:e0:78:00:fc:be:03:5d:31:76:af:84:73:e2:3e:9a:a3:df:ee:22:11:96:d1:14:83:02:67:7c:72:0c:fe:25:44:a0:3d:b5:53:e7:f1:b8:42:7b:a1:cc:72:b0:f2:9b:12:df:ef:4c:08:1d:07:6d:35:3e:71:88:0a:ad:ff:38:63:52:af:0a:b7:b2:8e:d4:9e:1e:67:2d:11:f9 sha1 c2:23:98:04:c8:09:81:70:be:52:d6:d5:d4:15:9e:81:ce:84:66:bf -a0:00:00:00:04 f6 000000 rsa 03 a2:5a:6b:d7:83:a5:ef:6b:8f:b6:f8:30:55:c2:60:f5:f9:9e:a1:66:78:f3:b9:05:3e:0f:64:98:e8:2c:3f:5d:1e:8c:38:f1:35:88:01:7e:2b:12:b3:d8:ff:6f:50:16:7f:46:44:29:10:72:9e:9e:4d:1b:37:39:e5:06:7c:0a:c7:a1:f4:48:7e:35:f6:75:bc:16:e2:33:31:51:65:cb:14:2b:fd:b2:5e:30:1a:63:2a:54:a3:37:1e:ba:b6:57:2d:ee:ba:f3:70:f3:37:f0:57:ee:73:b4:ae:46:d1:a8:bc:4d:a8:53:ec:3c:c1:2c:8c:bc:2d:a1:83:22:d6:85:30:c7:0b:22:bd:ac:35:1d:d3:60:68:ae:32:1e:11:ab:f2:64:f4:d3:56:9b:b7:12:14:54:50:05:55:8d:e2:60:83:c7:35:db:77:63:68:17:2f:e8:c2:f5:c8:5e:8b:5b:89:0c:c6:82:91:1d:2d:e7:1f:a6:26:b8:81:7f:cc:c0:89:22:b7:03:86:9f:3b:ae:ac:14:59:d7:7c:d8:53:76:bc:36:18:2f:42:38:31:4d:6c:42:12:fb:dd:7f:23:d3 sha1 50:29:09:ed:54:5e:3c:8d:bd:00:ea:58:2d:06:17:fe:e9:f6:f6:84 -a0:00:00:00:04 f7 000000 rsa 01:00:01 94:ea:62:f6:d5:83:20:e3:54:c0:22:ad:dc:f0:55:9d:8c:f2:06:cd:92:e8:69:56:49:05:ce:21:d7:20:f9:71:b7:ae:a3:74:83:0e:be:17:57:11:5a:85:e0:88:d4:1c:6b:77:cf:5e:c8:21:f3:0b:1d:89:04:17:bf:2f:a3:1e:59:08:de:d5:fa:67:7f:8c:7b:18:4a:d0:90:28:fd:de:96:b6:a6:10:98:50:aa:80:01:75:ea:bc:db:bb:68:4a:96:c2:eb:63:79:df:ea:08:d3:2f:e2:33:1f:e1:03:23:3a:d5:8d:cd:b1:e6:e0:77:cb:9f:24:ea:ec:5c:25:af sha1 ee:b0:dd:9b:24:77:be:e3:20:9a:91:4c:db:a9:4c:1c:4a:9b:de:d9 -a0:00:00:00:04 f8 000000 rsa 03 a1:f5:e1:c9:bd:86:50:bd:43:ab:6e:e5:6b:89:1e:f7:45:9c:0a:24:fa:84:f9:12:7d:1a:6c:79:d4:93:0f:6d:b1:85:2e:25:10:f1:8b:61:cd:35:4d:b8:3a:35:6b:d1:90:b8:8a:b8:df:04:28:4d:02:a4:20:4a:7b:6c:b7:c5:55:19:77:a9:b3:63:79:ca:3d:e1:a0:8e:69:f3:01:c9:5c:c1:c2:05:06:95:92:75:f4:17:23:dd:5d:29:25:29:05:79:e5:a9:5b:0d:f6:32:3f:c8:e9:27:3d:6f:84:91:98:c4:99:62:09:16:6d:9b:fc:97:3c:36:1c:c8:26:e1 sha1 f0:6e:cc:6d:2a:ae:bf:25:9b:7e:75:5a:38:d9:a9:b2:4e:2f:f3:dd -a0:00:00:00:04 f9 000000 rsa 03 a9:9a:6d:3e:07:18:89:ed:9e:3a:0c:39:1c:69:b0:b8:04:fc:16:0b:2b:4b:dd:57:0c:92:dd:5a:0f:45:f5:3e:86:21:f7:c9:6c:40:22:42:66:73:5e:1e:e1:b3:c0:62:38:ae:35:04:63:20:fd:8e:81:f8:ce:b3:f8:b4:c9:7b:94:09:30:a3:ac:5e:79:00:86:da:d4:1a:6a:4f:51:17:ba:1c:e2:43:8a:51:ac:05:3e:b0:02:ae:d8:66:d2:c4:58:fd:73:35:90:21:a1:20:29:a0:c0:43:04:5c:11:66:4f:e0:21:9e:c6:3c:10:bf:21:55:bb:27:84:60:9a:10:64:21:d4:51:63:79:97:38:c1:c3:09:09:bb:6c:6f:e5:2b:bb:76:39:7b:97:40:ce:06:4a:61:3f:f8:41:11:85:f0:88:42:a4:23:ea:d2:0e:df:fb:ff:1c:d6:c3:fe:0c:98:21:47:91:99:c2:6d:85:72:cc:8a:ff:f0:87:a9:c3 sha1 33:67:12:dc:c2:85:54:80:9c:6a:a9:b0:23:58:de:6f:75:51:64:db -a0:00:00:00:04 fa 000000 rsa 03 a9:0f:cd:55:aa:2d:5d:99:63:e3:5e:d0:f4:40:17:76:99:83:2f:49:c6:ba:b1:5c:da:e5:79:4b:e9:3f:93:4d:44:62:d5:d1:27:62:e4:8c:38:ba:83:d8:44:5d:ea:a7:41:95:a3:01:a1:02:b2:f1:14:ea:da:0d:18:0e:e5:e7:a5:c7:3e:0c:4e:11:f6:7a:43:dd:ab:5d:55:68:3b:14:74:cc:06:27:f4:4b:8d:30:88:a4:92:ff:aa:da:d4:f4:24:22:d0:e7:01:35:36:c3:c4:9a:d3:d0:fa:e9:64:59:b0:f6:b1:b6:05:65:38:a3:d6:d4:46:40:f9:44:67:b1:08:86:7d:ec:40:fa:ae:cd:74:0c:00:e2:b7:a8:85:2d sha1 5b:ed:40:68:d9:6e:a1:6d:2d:77:e0:3d:60:36:fc:7a:16:0e:a9:9c -b0:12:34:56:78 00 000000 rsa 03 9c:6b:e5:ad:b1:0b:4b:e3:dc:e2:09:9b:4b:21:06:72:b8:96:56:eb:a0:91:20:4f:61:3e:cc:62:3b:ed:c9:c6:d7:7b:66:0e:8b:ae:ea:7f:7c:e3:0f:1b:15:38:79:a4:e3:64:59:34:3d:1f:e4:7a:cd:bd:41:fc:d7:10:03:0c:2b:a1:d9:46:15:97:98:2c:6e:1b:dd:08:55:4b:72:6f:5e:ff:79:13:ce:59:e7:9e:35:72:95:c3:21:e2:6d:0b:8b:e2:70:a9:44:23:45:c7:53:e2:aa:2a:cf:c9:d3:08:50:60:2f:e6:ca:c0:0c:6d:df:6b:8d:9d:9b:48:79:b2:82:6b:04:2a:07:f0:e5:ae:52:6a:3d:3c:4d:22:c7:2b:9e:aa:52:ee:d8:89:38:66:f8:66:38:7a:c0:5a:13:99 sha1 5d:29:70:e6:46:75:72:7e:60:46:07:65:a8:db:75:34:2a:e1:47:83 -b0:12:34:56:78 02 000000 rsa 03 a9:9a:6d:3e:07:18:89:ed:9e:3a:0c:39:1c:69:b0:b8:04:fc:16:0b:2b:4b:dd:57:0c:92:dd:5a:0f:45:f5:3e:86:21:f7:c9:6c:40:22:42:66:73:5e:1e:e1:b3:c0:62:38:ae:35:04:63:20:fd:8e:81:f8:ce:b3:f8:b4:c9:7b:94:09:30:a3:ac:5e:79:00:86:da:d4:1a:6a:4f:51:17:ba:1c:e2:43:8a:51:ac:05:3e:b0:02:ae:d8:66:d2:c4:58:fd:73:35:90:21:a1:20:29:a0:c0:43:04:5c:11:66:4f:e0:21:9e:c6:3c:10:bf:21:55:bb:27:84:60:9a:10:64:21:d4:51:63:79:97:38:c1:c3:09:09:bb:6c:6f:e5:2b:bb:76:39:7b:97:40:ce:06:4a:61:3f:f8:41:11:85:f0:88:42:a4:23:ea:d2:0e:df:fb:ff:1c:d6:c3:fe:0c:98:21:47:91:99:c2:6d:85:72:cc:8a:ff:f0:87:a9:c3 sha1 29:4b:e2:02:39:ab:15:24:5a:63:be:a4:6c:c6:c1:75:a2:55:62:d1 -b0:12:34:56:78 05 000000 rsa 03 a1:f5:e1:c9:bd:86:50:bd:43:ab:6e:e5:6b:89:1e:f7:45:9c:0a:24:fa:84:f9:12:7d:1a:6c:79:d4:93:0f:6d:b1:85:2e:25:10:f1:8b:61:cd:35:4d:b8:3a:35:6b:d1:90:b8:8a:b8:df:04:28:4d:02:a4:20:4a:7b:6c:b7:c5:55:19:77:a9:b3:63:79:ca:3d:e1:a0:8e:69:f3:01:c9:5c:c1:c2:05:06:95:92:75:f4:17:23:dd:5d:29:25:29:05:79:e5:a9:5b:0d:f6:32:3f:c8:e9:27:3d:6f:84:91:98:c4:99:62:09:16:6d:9b:fc:97:3c:36:1c:c8:26:e1 sha1 b9:a1:d6:5c:af:e0:6b:05:4e:dd:7e:a8:25:97:ab:85:f1:30:e6:63 -b0:12:34:56:78 f3 000000 rsa 01:00:01 94:ea:62:f6:d5:83:20:e3:54:c0:22:ad:dc:f0:55:9d:8c:f2:06:cd:92:e8:69:56:49:05:ce:21:d7:20:f9:71:b7:ae:a3:74:83:0e:be:17:57:11:5a:85:e0:88:d4:1c:6b:77:cf:5e:c8:21:f3:0b:1d:89:04:17:bf:2f:a3:1e:59:08:de:d5:fa:67:7f:8c:7b:18:4a:d0:90:28:fd:de:96:b6:a6:10:98:50:aa:80:01:75:ea:bc:db:bb:68:4a:96:c2:eb:63:79:df:ea:08:d3:2f:e2:33:1f:e1:03:23:3a:d5:8d:cd:b1:e6:e0:77:cb:9f:24:ea:ec:5c:25:af sha1 56:94:b0:d2:78:48:18:14:a0:5e:12:b5:58:ce:c1:23:48:65:aa:5d -b0:12:34:56:78 f5 000000 rsa 03 a2:5a:6b:d7:83:a5:ef:6b:8f:b6:f8:30:55:c2:60:f5:f9:9e:a1:66:78:f3:b9:05:3e:0f:64:98:e8:2c:3f:5d:1e:8c:38:f1:35:88:01:7e:2b:12:b3:d8:ff:6f:50:16:7f:46:44:29:10:72:9e:9e:4d:1b:37:39:e5:06:7c:0a:c7:a1:f4:48:7e:35:f6:75:bc:16:e2:33:31:51:65:cb:14:2b:fd:b2:5e:30:1a:63:2a:54:a3:37:1e:ba:b6:57:2d:ee:ba:f3:70:f3:37:f0:57:ee:73:b4:ae:46:d1:a8:bc:4d:a8:53:ec:3c:c1:2c:8c:bc:2d:a1:83:22:d6:85:30:c7:0b:22:bd:ac:35:1d:d3:60:68:ae:32:1e:11:ab:f2:64:f4:d3:56:9b:b7:12:14:54:50:05:55:8d:e2:60:83:c7:35:db:77:63:68:17:2f:e8:c2:f5:c8:5e:8b:5b:89:0c:c6:82:91:1d:2d:e7:1f:a6:26:b8:81:7f:cc:c0:89:22:b7:03:86:9f:3b:ae:ac:14:59:d7:7c:d8:53:76:bc:36:18:2f:42:38:31:4d:6c:42:12:fb:dd:7f:23:d3 sha1 f7:5e:88:02:85:5c:9b:14:02:7e:51:73:45:71:7e:5c:36:35:b9:1b -b0:12:34:56:78 f6 000000 rsa 03 a1:f5:e1:c9:bd:86:50:bd:43:ab:6e:e5:6b:89:1e:f7:45:9c:0a:24:fa:84:f9:12:7d:1a:6c:79:d4:93:0f:6d:b1:85:2e:25:10:f1:8b:61:cd:35:4d:b8:3a:35:6b:d1:90:b8:8a:b8:df:04:28:4d:02:a4:20:4a:7b:6c:b7:c5:55:19:77:a9:b3:63:79:ca:3d:e1:a0:8e:69:f3:01:c9:5c:c1:c2:05:06:95:92:75:f4:17:23:dd:5d:29:25:29:05:79:e5:a9:5b:0d:f6:32:3f:c8:e9:27:3d:6f:84:91:98:c4:99:62:09:16:6d:9b:fc:97:3c:36:1c:c8:26:e1 sha1 e9:40:6b:65:10:c1:43:ab:1e:9b:9d:79:a3:c1:df:f8:90:9a:34:7c -b0:12:34:56:78 f7 000000 rsa 03 98:f0:c7:70:f2:38:64:c2:e7:66:df:02:d1:e8:33:df:f4:ff:e9:2d:69:6e:16:42:f0:a8:8c:56:94:c6:47:9d:16:db:15:37:bf:e2:9e:4f:dc:6e:6e:8a:fd:1b:0e:b7:ea:01:24:72:3c:33:31:79:bf:19:e9:3f:10:65:8b:2f:77:6e:82:9e:87:da:ed:a9:c9:4a:8b:33:82:19:9a:35:0c:07:79:77:c9:7a:ff:08:fd:11:31:0a:c9:50:a7:2c:3c:a5:00:2e:f5:13:fc:cc:28:6e:64:6e:3c:53:87:53:5d:50:95:14:b3:b3:26:e1:23:4f:9c:b4:8c:36:dd:d4:4b:41:6d:23:65:40:34:a6:6f:40:3b:a5:11:c5:ef:a3 sha1 f7:81:13:e8:60:f0:30:a8:72:92:3f:ce:93:e3:38:1c:77:a4:2a:30 -b0:12:34:56:78 f8 000000 rsa 03 a9:9a:6d:3e:07:18:89:ed:9e:3a:0c:39:1c:69:b0:b8:04:fc:16:0b:2b:4b:dd:57:0c:92:dd:5a:0f:45:f5:3e:86:21:f7:c9:6c:40:22:42:66:73:5e:1e:e1:b3:c0:62:38:ae:35:04:63:20:fd:8e:81:f8:ce:b3:f8:b4:c9:7b:94:09:30:a3:ac:5e:79:00:86:da:d4:1a:6a:4f:51:17:ba:1c:e2:43:8a:51:ac:05:3e:b0:02:ae:d8:66:d2:c4:58:fd:73:35:90:21:a1:20:29:a0:c0:43:04:5c:11:66:4f:e0:21:9e:c6:3c:10:bf:21:55:bb:27:84:60:9a:10:64:21:d4:51:63:79:97:38:c1:c3:09:09:bb:6c:6f:e5:2b:bb:76:39:7b:97:40:ce:06:4a:61:3f:f8:41:11:85:f0:88:42:a4:23:ea:d2:0e:df:fb:ff:1c:d6:c3:fe:0c:98:21:47:91:99:c2:6d:85:72:cc:8a:ff:f0:87:a9:c3 sha1 66:46:9c:88:e7:dc:11:15:29:c7:d3:79:d7:93:8c:8d:f3:e4:c2:5e -b0:12:34:56:78 f9 000000 rsa 01:00:01 a6:e6:fb:72:17:95:06:f8:60:cc:ca:8c:27:f9:9c:ec:d9:4c:7d:4f:31:91:d3:03:bb:ee:37:48:1c:7a:a1:5f:23:3b:a7:55:e9:e4:37:63:45:a9:a6:7e:79:94:bd:c1:c6:80:bb:35:22:d8:c9:3e:b0:cc:c9:1a:d3:1a:d4:50:da:30:d3:37:66:2d:19:ac:03:e2:b4:ef:5f:6e:c1:82:82:d4:91:e1:97:67:d7:b2:45:42:df:de:ff:6f:62:18:55:03:53:20:69:bb:b3:69:e3:bb:9f:b1:9a:c6:f1:c3:0b:97:d2:49:ee:e7:64:e0:ba:c9:7f:25:c8:73:d9:73:95:3e:51:53:a4:20:64:bb:fa:bf:d0:6a:4b:b4:86:86:0b:f6:63:74:06:c9:fc:36:81:3a:4a:75:f7:5c:31:cc:a9:f6:9f:8d:e5:9a:de:ce:f6:bd:e7:e0:78:00:fc:be:03:5d:31:76:af:84:73:e2:3e:9a:a3:df:ee:22:11:96:d1:14:83:02:67:7c:72:0c:fe:25:44:a0:3d:b5:53:e7:f1:b8:42:7b:a1:cc:72:b0:f2:9b:12:df:ef:4c:08:1d:07:6d:35:3e:71:88:0a:ad:ff:38:63:52:af:0a:b7:b2:8e:d4:9e:1e:67:2d:11:f9 sha1 ae:ac:a4:54:80:c8:83:4c:b0:be:bd:cc:57:0b:7b:2b:74:bb:4b:79 +A0:00:00:00:25 01 000000 rsa 03 AF:AD:70:10:F8:84:E2:82:46:50:F7:64:D4:7D:79:51:A1:6E:ED:6D:BB:88:1F:38:4D:ED:B6:70:2E:0F:B5:5C:0F:BE:F9:45:A2:01:77:05:E5:28:6F:A2:49:A5:91:E1:94:BD:CD:74:B2:17:20:B4:4C:E9:86:F1:44:23:7A:25:F9:57:89:F3:8B:47:EA:95:7F:9A:DB:23:72:F6:D5:D4:13:40:A1:47:EA:C2:AF:32:4E:83:58:AE:11:20:EF:3F sha1 AC:FE:73:4C:F0:9A:84:C7:BF:02:5F:0F:FC:6F:A8:CA:25:A2:28:69 +A0:00:00:00:25 02 000000 rsa 03 AF:4B:8D:23:0F:DF:CB:15:38:E9:75:79:5A:1D:B4:0C:39:6A:53:59:FA:A3:1A:E0:95:CB:52:2A:5C:82:E7:FF:FB:25:28:60:EC:28:33:EC:3D:4A:66:5F:13:3D:D9:34:EE:11:48:D8:1E:2B:7E:03:F9:29:95:DD:F7:EB:7C:90:A7:5A:B9:8E:69:C9:2E:C9:1A:53:3B:21:E1:C4:91:8B:43:AF:ED:57:80:DE:13:A3:2B:BD:37:EB:C3:84:FA:3D:D1:A4:53:E3:27:C5:60:24:DA:CA:EA:74:AA:05:2C:4D sha1 33:F5:B0:34:49:43:04:82:37:EC:89:B2:75:A9:55:69:71:8A:EE:20 +A0:00:00:00:25 03 000000 rsa 03 B0:C2:C6:E2:A6:38:69:33:CD:17:C2:39:49:6B:F4:8C:57:E3:89:16:4F:2A:96:BF:F1:33:43:9A:E8:A7:7B:20:49:8B:D4:DC:69:59:AB:0C:2D:05:D0:72:3A:F3:66:89:01:93:7B:67:4E:5A:2F:A9:2D:DD:5E:78:EA:9D:75:D7:96:20:17:3C:C2:69:B3:5F:46:3B:3D:4A:AF:F2:79:4F:92:E6:C7:A3:FB:95:32:5D:8A:B9:59:60:C3:06:6B:E5:48:08:7B:CB:6C:E1:26:88:14:4A:8B:4A:66:22:8A:E4:65:9C:63:4C:99:E3:60:11:58:4C:09:50:82:A3:A3:E3 sha1 87:08:A3:E3:BB:C1:BB:0B:E7:3E:BD:8D:19:D4:E5:D2:01:66:BF:6C +A0:00:00:00:25 04 000000 rsa 03 D0:F5:43:F0:3F:25:17:13:3E:F2:BA:4A:11:04:48:67:58:63:0D:CF:E3:A8:83:C7:7B:4E:48:44:E3:9A:9B:D6:36:0D:23:E6:64:4E:1E:07:1F:19:6D:DF:2E:4A:68:B4:A3:D9:3D:14:26:8D:72:40:F6:A1:4F:0D:71:4C:17:82:7D:27:9D:19:2E:88:93:1A:F7:30:07:27:AE:9D:A8:0A:3F:0E:36:6A:EB:A6:17:78:17:17:37:98:9E:1E:E3:09 sha1 FD:D7:13:9E:C7:E0:C3:31:67:FD:61:AD:3C:AD:BD:68:D6:6E:91:C5 +A0:00:00:00:25 0E 131231 rsa 03 AA:94:A8:C6:DA:D2:4F:9B:A5:6A:27:C0:9B:01:02:08:19:56:8B:81:A0:26:BE:9F:D0:A3:41:6C:A9:A7:11:66:ED:50:84:ED:91:CE:D4:7D:D4:57:DB:7E:6C:BC:D5:3E:56:0B:C5:DF:48:AB:C3:80:99:3B:6D:54:9F:51:96:CF:A7:7D:FB:20:A0:29:61:88:E9:69:A2:77:2E:8C:41:41:66:5F:8B:B2:51:6B:A2:C7:B5:FC:91:F8:DA:04:E8:D5:12:EB:0F:64:11:51:6F:B8:6F:C0:21:CE:7E:96:9D:A9:4D:33:93:79:09:A5:3A:57:F9:07:C4:0C:22:00:9D:A7:53:2C:B3:BE:50:9A:E1:73:B3:9A:D6:A0:1B:A5:BB:85 sha1 A7:26:6A:BA:E6:4B:42:A3:66:88:51:19:1D:49:85:6E:17:F8:FB:CD +A0:00:00:00:25 0F 221231 rsa 03 C8:D5:AC:27:A5:E1:FB:89:97:8C:7C:64:79:AF:99:3A:B3:80:0E:B2:43:99:6F:BB:2A:E2:6B:67:B2:3A:C4:82:C4:B7:46:00:5A:51:AF:A7:D2:D8:3E:89:4F:59:1A:23:57:B3:0F:85:B8:56:27:FF:15:DA:12:29:0F:70:F0:57:66:55:2B:A1:1A:D3:4B:71:09:FA:49:DE:29:DC:B0:10:96:70:87:5A:17:EA:95:54:9E:92:34:7B:94:8A:A1:F0:45:75:6D:E5:6B:70:7E:38:63:E5:9A:6C:BE:99:C1:27:2E:F6:5F:B6:6C:BB:4C:FF:07:0F:36:02:9D:D7:62:18:B2:12:42:64:5B:51:CA:75:2A:F3:7E:70:BE:1A:84:FF:31:07:9D:C0:04:8E:92:88:83:EC:4F:AD:D4:97:A7:19:38:5C:2B:BB:EB:C5:A6:6A:A5:E5:65:5D:18:03:4E:C5 sha1 A7:34:72:B3:AB:55:74:93:A9:BC:21:79:CC:80:14:05:3B:12:BA:B4 +A0:00:00:00:25 10 000000 rsa 03 CF:98:DF:ED:B3:D3:72:79:65:EE:77:97:72:33:55:E0:75:1C:81:D2:D3:DF:4D:18:EB:AB:9F:B9:D4:9F:38:C8:C4:A8:26:B9:9D:C9:DE:A3:F0:10:43:D4:BF:22:AC:35:50:E2:96:2A:59:63:9B:13:32:15:64:22:F7:88:B9:C1:6D:40:13:5E:FD:1B:A9:41:47:75:05:75:E6:36:B6:EB:C6:18:73:4C:91:C1:D1:BF:3E:DC:2A:46:A4:39:01:66:8E:0F:FC:13:67:74:08:0E:88:80:44:F6:A1:E6:5D:C9:AA:A8:92:8D:AC:BE:B0:DB:55:EA:35:14:68:6C:6A:73:2C:EF:55:EE:27:CF:87:7F:11:06:52:69:4A:0E:34:84:C8:55:D8:82:AE:19:16:74:E2:5C:29:62:05:BB:B5:99:45:51:76:FD:D7:BB:C5:49:F2:7B:A5:FE:35:33:6F:7E:29:E6:8D:78:39:73:19:94:36:63:3C:67:EE:5A:68:0F:05:16:0E:D1:2D:16:65:EC:83:D1:99:7F:10:FD:05:BB:DB:F9:43:3E:8F:79:7A:EE:3E:9F:02:A3:42:28:AC:E9:27:AB:E6:2B:8B:92:81:AD:08:D3:DF:5C:73:79:68:50:45:D7:BA:5F:CD:E5:86:37 sha1 C7:29:CF:2F:D2:62:39:4A:BC:4C:C1:73:50:65:02:44:6A:A9:B9:FD +A0:00:00:00:25 52 000000 rsa 01:00:01 B8:31:41:4E:0B:46:13:92:2B:D3:5B:4B:36:80:2B:C1:E1:E8:1C:95:A2:7C:95:8F:53:82:00:3D:F6:46:15:4C:A9:2F:C1:CE:02:C3:BE:04:7A:45:E9:B0:2A:90:89:B4:B9:02:78:23:7C:96:51:92:A0:FC:C8:6B:B4:9B:C8:2A:E6:FD:C2:DE:70:90:06:B8:6C:76:76:EF:DF:59:76:26:FA:D6:33:A4:F7:DC:48:C4:45:D3:7E:B5:5F:CB:3B:1A:BB:95:BA:AA:82:6D:53:90:E1:5F:D1:4E:D4:03:FA:2D:0C:B8:41:C6:50:60:95:24:EC:55:5E:3B:C5:6C:A9:57 sha1 9D:93:DA:5E:86:FD:F1:63:18:D2:68:CA:6A:C5:70:31:ED:FC:A3:CB +A0:00:00:00:25 60 000000 rsa 03 D0:F5:43:F0:3F:25:17:13:3E:F2:BA:4A:11:04:48:67:58:63:0D:CF:E3:A8:83:C7:7B:4E:48:44:E3:9A:9B:D6:36:0D:23:E6:64:4E:1E:07:1F:19:6D:DF:2E:4A:68:B4:A3:D9:3D:14:26:8D:72:40:F6:A1:4F:0D:71:4C:17:82:7D:27:9D:19:2E:88:93:1A:F7:30:07:27:AE:9D:A8:0A:3F:0E:36:6A:EB:A6:17:78:17:17:37:98:9E:1E:E3:09 sha1 C0:8E:25:6F:27:6E:D8:14:02:1B:11:CA:F6:EC:37:01:EC:75:53:A1 +A0:00:00:00:25 62 000000 rsa 03 BA:29:DE:83:09:0D:8D:5F:4D:FF:CE:B9:89:18:99:5A:76:8F:41:D0:18:3E:1A:CA:3E:F8:D5:ED:90:62:85:3E:40:80:E0:D2:89:A5:CE:DD:4D:D9:6B:1F:EA:2C:53:42:84:36:CE:15:A2:A1:BF:E6:9D:46:19:7D:3F:5A:79:BC:F8:F4:85:8B:FF:A0:4E:DB:07:FC:5B:E8:56:0D:9C:E3:8F:5C:3C:A3:C7:42:ED:FD:BA:E3:B5:E6:DD:A4:55:57 sha1 CC:C7:30:3F:F2:95:A9:F3:5B:A6:1B:D3:1E:27:EA:BD:59:65:82:65 +A0:00:00:00:25 64 000000 rsa 03 B0:DD:55:10:47:DA:FC:D1:0D:9A:5E:33:CF:47:A9:33:3E:3B:24:EC:57:E8:F0:66:A7:2D:ED:60:E8:81:A8:AD:42:77:7C:67:AD:DF:07:08:04:2A:B9:43:60:1E:E6:02:48:54:0B:67:E0:63:70:18:EE:B3:91:1A:E9:C8:73:DA:D6:6C:B4:0B:C8:F4:DC:77:EB:25:95:25:2B:61:C2:15:18:F7:9B:70:6A:AC:29:E7:D3:FD:4D:25:9D:B7:2B:6E:6D:44:6D:D6:03:86:DB:40:F5:FD:B0:76:D8:03:74:C9:93:B4:BB:2D:1D:B9:77:C3:87:08:97:F9:DF:A4:54:F5 sha1 79:2B:12:1D:86:D0:F3:A9:95:82:DB:06:97:44:81:F3:B2:E1:84:54 +A0:00:00:00:25 65 000000 rsa 03 E5:3E:B4:1F:83:9D:DF:B4:74:F2:72:CD:0C:BE:37:3D:54:68:EB:3F:50:F3:9C:95:BD:F4:D3:9F:A8:2B:98:DA:BC:94:76:B6:EA:35:0C:0D:CE:1C:D9:20:75:D8:C4:4D:1E:57:28:31:90:F9:6B:35:37:D9:E6:32:C4:61:81:5E:BD:2B:AF:36:89:1D:F6:BF:B1:D3:0F:A0:B7:52:C4:3D:CA:02:57:D3:5D:FF:4C:CF:C9:8F:84:19:8D:51:52:EC:61:D7:B5:F7:4B:D0:93:83:BD:0E:2A:A4:22:98:FF:B0:2F:0D:79:AD:B7:0D:72:24:3E:E5:37:F7:55:36:A8:A8:DF:96:25:82:E9:E6:81:2F:3A:0B:E0:2A:43:65:40:0D sha1 89:4C:5D:08:D4:EA:28:BB:79:DC:46:CE:AD:99:8B:87:73:22:F4:16 +A0:00:00:00:25 66 000000 rsa 03 BD:14:78:87:7B:93:33:61:2D:25:7D:9E:3C:9C:23:50:3E:28:33:6B:72:3C:71:F4:7C:25:83:66:70:39:53:60:F5:3C:10:6F:D7:4D:EE:EA:29:12:59:C0:01:AF:BE:7B:4A:83:65:4F:6E:2D:9E:81:48:E2:CB:1D:92:23:AC:59:03:DA:18:B4:33:F8:E3:52:92:27:50:5D:E8:47:48:F2:41:F7:BF:CD:21:46:E5:E9:A8:C5:D2:A0:6D:19:09:70:87:A0:69:F9:AE:3D:61:0C:7C:8E:12:14:48:1A:4F:27:02:5A:1A:2E:DB:8A:9C:DA:FA:44:56:90:51:1D:B8:05 sha1 F3:67:CB:70:F9:C9:B6:7B:58:0F:53:38:19:E3:02:BA:C0:33:00:90 +A0:00:00:00:25 67 221231 rsa 03 C6:87:AD:CC:F3:D5:7D:33:60:B1:74:E4:71:ED:A6:93:AA:55:5D:FD:C6:C8:CD:39:4C:74:BA:25:CC:DF:8E:AB:FD:1F:1C:EA:DF:BE:22:80:C9:E8:1F:7A:05:89:98:DC:22:B7:F2:25:76:FE:84:71:3D:0B:DD:3D:34:CF:CD:12:FC:D0:D2:69:01:BA:74:10:3D:07:5C:66:4D:AB:CC:AF:57:BF:78:94:94:05:1C:5E:C3:03:A2:E1:D7:84:30:6D:3D:B3:EB:66:5C:D3:60:A5:58:F4:0B:7C:05:C9:19:B2:F0:28:2F:E1:ED:9B:F6:26:1A:A8:14:64:8F:BC:26:3B:14:21:44:91:DE:42:6D:24:2D:65:CD:1F:FF:0F:BE:4D:4D:AF:F5:CF:AC:B2:AD:C7:13:1C:9B:14:7E:E7:91:95:65:51:07:62:70:69:6B:75:FD:97:37:3F:1F:D7:80:4F sha1 52:A2:90:73:00:C8:44:5B:F5:4B:97:0C:89:46:91:FE:AD:F2:D2:8E +A0:00:00:00:25 68 000000 rsa 03 F4:D1:98:F2:F0:CF:14:0E:4D:2D:81:B7:65:EB:4E:24:CE:D4:C0:83:48:22:76:98:54:D0:E9:7E:80:66:CB:E4:65:02:9B:3F:41:0E:35:0F:62:96:38:1A:25:3B:E7:1A:4B:BA:BB:D5:16:62:5D:AE:67:D0:73:D0:01:13:AA:B9:EA:4D:CE:CA:29:F3:BB:7A:5D:46:C0:D8:B9:83:E2:48:2C:2A:D7:59:73:5A:5A:B9:AA:AE:FB:31:D3:E7:18:B8:CA:66:C0:19:EC:A0:A8:BE:31:2E:24:3E:B4:7A:62:30:06:20:BD:51:CF:16:9A:91:94:C1:7A:42:E5:1B:34:D8:37:75:A9:8E:80:B2:D6:6F:4F:98:08:4A:44:8F:E0:50:7E:A2:7C:90:5A:EE:72:B6:2A:8A:29:43:8B:6A:44:80:FF:F7:2F:93:28:04:32:A5:5F:DD:64:8A:D9:3D:82:B9:EC:F0:12:75:C0:91:4B:AD:8E:B3:AA:F4:6B:12:9F:87:49:FE:A4:25:A2:DC:DD:7E:81:3A:08:FC:0C:A7:84:1E:DD:49:98:5C:D8:BC:6D:5D:56:F1:7A:B9:C6:7C:EC:50:BA:42:24:40:56:3E:CC:E2:16:99:E4:35:C8:68:2B:62:66:39:36:72:C6:93:D8:B7 sha1 41:5E:5F:E9:EC:96:6C:83:5F:BB:3E:6F:76:6A:9B:1A:4B:86:74:C3 +A0:00:00:00:25 96 000000 rsa 03 BC:9A:A2:94:B1:FD:D2:63:17:6E:32:43:D8:F4:48:BB:FF:CB:6A:BD:02:C3:18:11:28:9F:50:85:A9:26:2B:8B:1B:7C:64:77:EB:58:05:5D:9E:F3:2A:83:D1:B7:2D:4A:14:71:EC:A3:0C:E7:65:85:C3:FD:05:37:2B:68:6F:92:B7:95:B1:64:09:59:20:15:23:23:01:49:11:8D:52:D2:42:5B:D1:1C:86:3D:9B:2A:7C:4A:D0:A2:BF:DB:CA:67:B2:71:3B:29:0F:49:3C:D5:52:1E:5D:DF:05:EF:10:40:FC:23:8D:0A:85:1C:8E:3E:3B:2B:1F:0D:5D:9D:4A:ED sha1 E7:43:3E:5C:FC:60:01:15:1D:8E:CD:25:2E:BC:6E:61:F7:AB:22:17 +A0:00:00:00:25 97 000000 rsa 03 E1:78:FF:E8:34:B4:B7:67:AF:3C:9A:51:1F:97:3D:8E:85:05:C5:FC:B2:D3:76:80:75:AB:7C:C9:46:A9:55:78:99:55:87:9A:AF:73:74:07:15:15:21:99:6D:FA:43:C5:8E:6B:13:0E:B1:D8:63:B8:5D:C9:FF:B4:05:09:47:A2:67:6A:A6:A0:61:A4:A7:AE:1E:DB:0E:36:A6:97:E8:7E:03:75:17:EB:89:23:13:68:75:BA:2C:A1:08:7C:BA:7E:C7:65:3E:5E:28:A0:C2:61:A0:33:AF:27:E3:A6:7B:64:BB:A2:69:56:30:7E:C4:7E:67:4E:3F:8B:72:2B:3A:E0:49:8D:B1:6C:79:85:31:0D:9F:3D:11:73:00:D3:2B:09 sha1 EB:DA:52:2B:63:1B:3E:B4:F4:CB:FC:06:79:C4:50:13:9D:2B:69:CD +A0:00:00:00:25 98 000000 rsa 03 D3:1A:70:94:FB:22:1C:BA:66:60:FB:97:5A:AF:EA:80:DB:7B:B7:EA:FD:73:51:E7:48:82:7A:B6:2D:4A:EE:CC:FC:17:87:FD:47:A0:46:99:A0:2D:B0:0D:7C:38:2E:80:E8:04:B3:5C:59:43:4C:60:23:89:D6:91:B9:CC:D5:1E:D0:6B:E6:7A:27:61:19:C4:C1:0E:2E:40:FC:4E:DD:F9:DF:39:B9:B0:BD:EE:8D:07:6E:2A:01:2E:8A:29:2A:F8:EF:E1:85:53:47:06:39:C1:A0:32:25:2E:0E:57:48:B2:5A:3F:9B:A4:CF:CE:E0:73:03:8B:06:18:37:F2:AC:1B:04:C2:79:64:0F:5B:D1:10:A9:DC:66:5E:D2:FA:68:28:BD:5D:0F:E8:10:A8:92:DE:E6:B0:E7:4C:E8:86:3B:DE:08:FD:5F:D6:1A:0F:11:FA:0D:14:97:8D:8C:ED:7D:D3 sha1 D4:DB:A4:28:CF:11:D4:5B:AE:B0:A3:5C:AE:A8:00:7A:D8:BA:8D:71 +A0:00:00:00:25 99 000000 rsa 03 E1:74:00:74:22:9F:A0:D2:28:A9:62:35:81:D7:A3:22:90:3F:B8:9B:A7:68:67:12:E6:01:FA:8A:B2:4A:97:89:18:6F:15:B7:0C:CB:BE:74:21:B1:CB:11:0D:45:36:16:88:13:5F:FD:0D:B1:5A:3F:51:6B:B2:91:D4:A1:23:EB:F5:A0:6F:BF:7E:1E:E6:31:1B:73:7D:AB:B2:89:57:0A:79:59:D5:32:B2:5F:1D:A6:75:8C:84:DD:CC:AD:C0:49:BC:76:4C:05:39:1A:BD:2C:AD:EF:FA:7E:24:2D:5D:D0:6E:56:00:1F:0E:68:15:1E:33:88:07:4B:D9:33:0D:6A:FA:57:CB:F3:39:46:F5:31:E5:1E:0D:49:02:EE:23:5C:75:6A:90:5F:B7:33:94:0E:6E:C8:97:B4:94:4A:5E:DC:76:57:05:E2:AC:F7:6C:78:EA:D7:8D:D9:B0:66:DF:0B:2C:88:75:0B:8A:EE:00:C9:B4:D4:09:1F:A7:33:84:49:DA:92:DB:FC:90:8F:A0:78:1C:01:28:C4:92:DB:99:3C:88:BA:8B:B7:CA:DF:E2:38:D4:77:F2:51:7E:0E:7E:3D:2B:11:79:6A:03:18:CE:2A:D4:DA:1D:B8:E5:4A:B0:D9:4F:10:9D:B9:CA:EE:FB:EF sha1 F0:88:57:77:64:2C:96:BB:24:44:1F:A0:57:AD:9A:34:90:76:3B:D2 +A0:00:00:00:25 A1 000000 rsa 01:00:01 99:D1:73:96:42:1E:E3:F9:19:BA:54:9D:95:54:BE:0D:4F:92:CB:8B:53:B4:87:8E:D6:0C:C5:B2:DE:ED:C7:9B:85:C8:BD:6F:D2:F2:3C:22:E6:8B:38:1A:EE:B7:41:53:AF:B3:C9:6E:6C:96:AD:01:8E:73:C2:02:5D:1E:E7:76:22:A7:2B:EE:97:3C:1A:F7:B9:08:46:8D:74:FD:B5:3D:CE:83:80:52:3E:38:C3:0D:0A:8A:22:65:29:72:68:24:E2:09:E6:68:F4:9F:43:B0:E8:CD:2F:E5:27:CE:7C:C4:1F:33:F4:34:F9:5D:6E:2F:E2:F5:89:37:20:32:F2:D6:50:43:40:F8:C5:42:D2:98:B4:99:A5:3D:95:AF:40:83 sha1 BB:B9:AB:E8:89:61:11:98:C3:87:B5:B0:AB:37:49:34:BC:2B:2E:A9 +A0:00:00:00:25 C1 000000 rsa 03 E6:9E:31:9C:34:D1:B4:FB:43:AE:D4:BD:8B:BA:6F:7A:8B:76:3F:2F:6E:E5:DD:F7:C9:25:79:A9:84:F8:9C:4A:9C:15:B2:70:37:76:4C:58:AC:7E:45:EF:BC:34:E1:38:E5:6B:A3:8F:76:E8:03:12:9A:8D:DE:B5:E1:CC:8C:6B:30:CF:63:4A:9C:9C:12:24:BF:1F:0A:9A:18:D7:9E:D4:1E:BC:F1:BE:78:08:7A:E8:B7:D2:F8:96:B1:DE:8B:7E:78:41:61:A1:38:A0:F2:16:9A:D3:3E:14:6D:1B:16:AB:59:5F:9D:7D:98:BE:67:10:62:D2:17:F4:4E:B6:8C:68:64:0C:7D:57:46:5A:06:3F:6B:AC:77:6D:3E:2D:AC:61 sha1 DC:79:D6:B5:FC:87:93:62:29:9B:C5:A6:37:DA:D2:E0:D9:96:56:B8 +A0:00:00:00:25 C2 000000 rsa 03 B8:75:00:2F:38:BA:26:D6:11:67:C5:D4:40:36:76:04:AD:38:DF:2E:93:D8:EE:8D:A0:E8:D9:C0:CF:4C:C5:78:8D:11:DE:A6:89:E5:F4:1D:23:A3:DA:3E:0B:1F:A5:87:5A:E2:56:20:F5:A6:BC:CE:E0:98:C1:B3:5C:69:18:89:D7:D0:EF:67:0E:B8:31:2E:71:23:FC:C5:DC:7D:2F:07:19:CC:80:E1:A9:30:17:F9:44:D0:97:33:0E:DF:94:57:62:FE:E6:2B:7B:0B:A0:34:82:28:DB:F3:8D:42:16:E5:A6:7A:7E:F7:4F:5D:31:11:C4:4A:A3:13:20:F6:23:CB:3C:53:E6:09:66:D6:92:00:67:C9:E0:82:B7:46:11:7E:48:E4:F0:0E:11:09:50:CA:54:DA:3E:38:E5:45:3B:D5:54:4E:3A:67:60:E3:A6:A4:27:66:AD:22:84:E0:C9:AF sha1 8E:74:82:96:35:9A:74:28:F5:36:AD:DA:8E:2C:03:7E:2B:69:7E:F6 +A0:00:00:00:25 C3 000000 rsa 03 B9:31:82:AB:E3:43:DF:BF:38:8C:71:C4:D6:74:7D:CD:EC:60:36:7F:E6:3C:FA:A9:42:D7:D3:23:E6:88:D0:83:28:36:54:8B:F0:ED:FF:1E:DE:EB:88:2C:75:09:9F:F8:1A:93:FA:52:5C:32:42:5B:36:02:3E:A0:2A:88:99:B9:BF:7D:79:34:E8:6F:99:78:91:82:30:06:CE:AA:93:09:1A:73:C1:FD:E1:8A:BD:4F:87:A2:23:08:64:0C:06:4C:8C:02:76:85:F1:B2:DB:7B:74:1B:67:AB:0D:E0:5E:87:04:81:C5:F9:72:50:8C:17:F5:7E:4F:83:3D:63:22:0F:6E:A2:CF:BB:87:87:28:AA:58:87:DE:40:7D:10:C6:B8:F5:8D:46:77:9E:CE:C1:E2:15:54:87:D5:2C:78:A5:C0:38:97:F2:BB:58:0E:0A:2B:BD:E8:EA:2E:1C:18:F6:AA:F3:EB:3D:04:C3:47:7D:EA:B8:8F:15:0C:88:10:FD:1E:F8:EB:05:96:86:63:36:FE:2C:1F:BC:6B:EC:22:B4:FE:5D:88:56:47:72:6D:B5:97:09:A5:05:F7:5C:49:E0:D8:D7:1B:F5:1E:41:81:21:2B:E2:14:2A:B2:A1:E8:C0:D3:B7:13:6C:D7:B7:70:8E:4D sha1 12:F1:79:0C:B0:27:3D:C7:3C:6E:70:78:4B:C2:4C:12:E8:DB:71:F6 +A0:00:00:00:25 C8 000000 rsa 03 BF:0C:FC:ED:70:8F:B6:B0:48:E3:01:43:36:EA:24:AA:00:7D:79:67:B8:AA:4E:61:3D:26:D0:15:C4:FE:78:05:D9:DB:13:1C:ED:0D:2A:8E:D5:04:C3:B5:CC:D4:8C:33:19:9E:5A:5B:F6:44:DA:04:3B:54:DB:F6:02:76:F0:5B:17:50:FA:B3:90:98:C7:51:1D:04:BA:BC:64:94:82:DD:CF:7C:C4:2C:8C:43:5B:AB:8D:D0:EB:1A:62:0C:31:11:1D:1A:AA:F9:AF:65:71:EE:BD:4C:F5:A0:84:96:D5:7E:7A:BD:BB:51:80:E0:A4:2D:A8:69:AB:95:FB:62:0E:FF:26:41:C3:70:2A:F3:BE:0B:0C:13:8E:AE:F2:02:E2:1D sha1 33:BD:7A:05:9F:AB:09:49:39:B9:0A:8F:35:84:5C:9D:C7:79:BD:50 +A0:00:00:00:25 C9 000000 rsa 03 B3:62:DB:57:33:C1:5B:87:97:B8:EC:EE:55:CB:1A:37:1F:76:0E:0B:ED:D3:71:5B:B2:70:42:4F:D4:EA:26:06:2C:38:C3:F4:AA:A3:73:2A:83:D3:6E:A8:E9:60:2F:66:83:EE:CC:6B:AF:F6:3D:D2:D4:90:14:BD:E4:D6:D6:03:CD:74:42:06:B0:5B:4B:AD:0C:64:C6:3A:B3:97:6B:5C:8C:AA:F8:53:95:49:F5:92:1C:0B:70:0D:5B:0F:83:C4:E7:E9:46:06:8B:AA:AB:54:63:54:4D:B1:8C:63:80:11:18:F2:18:2E:FC:C8:A1:E8:5E:53:C2:A7:AE:83:9A:5C:6A:3C:AB:E7:37:62:B7:0D:17:0A:B6:4A:FC:6C:A4:82:94:49:02:61:1F:B0:06:1E:09:A6:7A:CB:77:E4:93:D9:98:A0:CC:F9:3D:81:A4:F6:C0:DC:6B:7D:F2:2E:62:DB sha1 8E:8D:FF:44:3D:78:CD:91:DE:88:82:1D:70:C9:8F:06:38:E5:1E:49 +A0:00:00:00:25 CA 000000 rsa 03 C2:3E:CB:D7:11:9F:47:9C:2E:E5:46:C1:23:A5:85:D6:97:A7:D1:0B:55:C2:D2:8B:EF:0D:29:9C:01:DC:65:42:0A:03:FE:52:27:EC:DE:CB:80:25:FB:C8:6E:EB:C1:93:52:98:C1:75:3A:B8:49:93:67:49:71:95:91:75:8C:31:5F:A1:50:40:07:89:BB:14:FA:DD:6E:AE:2A:D6:17:DA:38:16:31:99:D1:BA:D5:D3:F8:F6:A7:A2:0A:EF:42:0A:DF:E2:40:4D:30:B2:19:35:9C:6A:49:52:56:5C:CC:A6:F1:1E:C5:BE:56:4B:49:B0:EA:5B:F5:B3:DC:8C:5C:64:01:20:8D:00:29:C3:95:7A:8C:59:22:CB:DE:39:D3:A5:64:C6:DE:BB:6B:D2:AE:F9:1F:C2:7B:B3:D3:89:2B:EB:96:46:DC:E2:E1:EF:85:81:EF:FA:71:21:58:AA:EC:54:1C:0B:BB:4B:3E:27:9D:7D:A5:4E:45:A0:AC:C3:57:0E:71:2C:9F:7C:DF:98:5C:FA:FD:38:2A:E1:3A:3B:21:4A:9E:8E:1E:71:AB:1E:A7:07:89:51:12:AB:C3:A9:7D:0F:CB:0A:E2:EE:5C:85:49:2B:6C:FD:54:88:5C:DD:63:37:E8:95:CC:70:FB:32:55:E3 sha1 6B:DA:32:B1:AA:17:14:44:C7:E8:F8:80:75:A7:4F:BF:E8:45:76:5F +A0:00:00:01:41 02 091231 rsa 03 AF:D7:53:69:9B:6F:C2:E5:CB:EA:CB:B6:B1:47:C5:72:A5:7E:DE:98:F4:62:8B:56:CB:5E:DE:C8:06:DA:6D:CC:8C:85:CB:45:85:93:30:46:74:6D:0D:D7:9F:DD:BE:75:49:54:21:16:BB:AD:2F:D3:5F:74:A8:C3:3F:74:6F:D0:EC:5B:C6:24:1B:11:2B:21:2F:8C:5F:4A:86:4A:F4:03:BD:94:4C:3F:DA:19:24:FD:4D:7C:DF:79:07:43:06:C9:22:51:3B:88:3C:24:E5:67:AF:C2:A6:41:F3:5D:FE:FF:9C:A2:82:5F:9F:A4:40:9D:65:D3:C9:5F:32:72:89:D3 sha1 31:57:63:F6:49:BC:0C:03:66:F9:91:EB:CF:01:BA:F1:A8:33:E5:1B +A0:00:00:01:41 04 181231 rsa 03 E7:ED:CA:9D:81:0F:37:92:DC:4E:F1:A1:C9:F3:80:3F:D3:90:40:00:AF:9C:3E:32:2B:75:16:CD:41:A6:23:1A:96:29:C0:AD:5A:4C:DF:9F:40:75:0F:A5:1D:2D:A9:DC:C1:E3:F5:B3:6F:03:2A:80:86:C5:89:30:FD:C1:0B:28:39:90:9B:19:B9:CA:23:26:5A:62:76:4A:93:2C:37:C6:56:6D:13:92:F0:34:86:C6:26:A9:F6:C2:04:E1:26:60:69:60:2D:EC:0F:31:D8:A5:8C:F3:94:FD:96:93:9B:1E:14:E2:BE:91:B8:18:C4:92:CC:D1:BA:63:F4:10:E5:F3:31:ED:48:01:3F:1E:99:11:63:2A:3B:3A:5A:E2:46:29:C5:44:50:7C:BE:AD:E6:B5:CE:2F:F7:7C:2C:D4:DF:92:1D:69:34:23:EA:88:AE:A0:04:57:14:61:FA:B2:93:2E:46:C0:6E:9E:A6:3D:24:A0:56:66:DF:D9:1B:57:FC:58:95:9C:24:B9:04:16:24:FD:C3:3A:33:F0:2E:10:99:55:E1:F1:65:24:F3:24:16:1F:BD:A3:54:0C:61:41:FB:F6:70:23:C5:26:3B:F5:FB:C5:C8:3B:4E:FA:EE:82:26:55:B6:A9:EC:AB:FA:01:89:A9 sha1 C5:4E:D9:2B:16:8B:87:73:E8:CE:7E:8F:4A:6D:6C:CA:9D:AD:40:B2 +A0:00:00:01:41 05 161231 rsa 03 B5:16:58:FB:FB:57:42:3F:69:0E:73:52:DA:2E:52:7E:AC:37:23:E2:F0:B1:D8:52:1E:DB:44:F4:12:2B:72:0D:04:5A:A5:4C:29:90:CB:FA:B3:BB:3A:EF:AD:AF:A6:CB:F6:5F:33:9B:75:B9:42:23:C2:71:4B:D2:35:4B:12:28:9E:EE:8A:94:F7:54:54:DC:DE:F0:AE:FB:F0:C2:C8:8E:1A:16:15:F6:F0:33:78:7D:FF:9E:E9:48:63:C0:1E:4A:0B:19:92:F0:25:62:48:71:AD:2C:9C:57:23:4B:5F:D6:C9:B5:BE:97:82:1D:0E:B9:44:A3:21:F4:E5:B2:A8:51:6E:DB:92:11:7C:B4:AB:0D:39:50:4A:81:30:C4:BD:0D sha1 33:88:7D:29:68:6B:CB:B3:BE:86:EA:9A:33:CA:83:BB:C7:AE:1E:19 +A0:00:00:03:84 C1 171231 rsa 03 AD:6E:00:E5:88:2C:EE:F5:78:AF:B0:02:98:0F:BD:90:10:89:10:0B:92:12:00:D6:44:2C:17:6D:93:DA:5C:93:99:B8:42:7C:BE:19:C1:B2:E6:38:F5:FC:78:87:5C:82:BE:7C:E5:90:16:0D:0E:8A:04:24:23:74:E5:C4:B5:F3:07:E7:41:2C:A8:FB:2E:84:BB:4F:42:1D:6B:4C:2E:08:25:5B:25:77:F5:5E:06:67:67:3B:D7:D7:A3:D7:4E:08:3D:C1:9B:59:7A:76:53:11:35:A7:C3:B1:DB:93:53:40:45:E1:D5:2D:DB:51:70:AC:FA:A6:88:92:2C:18:76:4C:FE:59:E3:D0:57:8C:41:A7:BD:60:52:0C:AD:C5:8D:D9 sha1 BF:08:21:B4:17:74:2A:41:F1:F1:AD:54:B8:BA:56:4E:A3:76:DD:3D +A0:00:00:03:84 C2 211231 rsa 03 8B:FD:70:FC:05:45:67:18:B7:00:2F:1B:88:90:40:78:00:89:D9:59:69:F3:16:0A:39:99:B4:E0:56:D2:CE:FC:00:7D:30:33:B0:28:68:67:0C:9E:FE:48:62:40:96:C2:FD:0F:A7:FD:AF:DC:BB:4A:63:A4:CD:71:06:A9:7B:DD:8C:E3:F7:1F:21:68:AF:CB:42:30:F2:C3:34:92:46:7A:6C:18:2B:4B:FA:76:EE:60:5B:2F:EC:4B:45:19:B5:A9:27:67:DF:23:80:5E:C8:70:89:80:E1:8C:B0:89:C0:65:D0:36:AD:57:D1:96:E8:8A:C1:55:21:48:FC:3B:62:B7:71:B6:B1:44:D2:8D:F5:AE:E7:4F:C3:15:21:B6:96:89:09:A4:63:EA:01:84:26:1D:D7:51:27:8A:10:B7:C7:46:68:52:0B:25:3B:6A:86:0E:54:06:5D:2B:56:77:A7:53 sha1 C7:93:39:D4:04:DE:EC:1D:85:32:A6:44:10:D3:CB:78:6B:A1:61:24 +A0:00:00:03:84 C3 211231 rsa 03 A1:A6:2B:6A:03:93:DE:4E:F4:D9:D5:36:84:C1:4E:AE:D4:A8:81:A2:6E:E6:4D:BD:45:50:EB:35:81:E0:03:28:1A:41:17:F7:BF:9E:56:48:FD:5E:38:82:BC:4A:B4:6B:0A:5F:48:CD:F5:C2:D5:6C:7D:14:A4:CD:69:D3:37:80:00:50:C0:99:49:74:23:76:28:EF:8D:75:1E:1F:AB:BA:AD:73:ED:70:F6:04:86:93:0B:55:A5:F3:C4:AE:BB:2B:B1:AD:AA:AE:3A:37:4D:02:F1:94:20:BD:52:8A:B1:9C:9D:09:FC:41:BB:81:40:C4:04:43:AE:2C:5A:24:59:3C:21:6E:96:04:BE:0D:C6:9B:BB:1D:1F:98:CA:76:21:2D:5D:1B:59:DB:B9:07:39:14:5C:5F:98:C7:DE:FE:CB:E9:1D:A4:C5:9F:B4:0F:15:9A:26:0A:0B:05:88:61:A2:5D:0B:88:D0:B3:FF:D8:7C:EE:52:DD:28:C7:B1:FF:E5:0A:49:B6:61:16:61:5D:C4:56:96:B4:A6:1E:56:3B:3C:DD:36:E3:F2:AD:CF:FB:50:DB:C3:E8:28:04:12:76:9D:00:66:29:17:09:68:93:B1:C3:19:E8:13:3A:04:3D:DF:05:AE:82:A5:5F:AE:FE:C1:DF sha1 6D:CF:13:57:57:6D:14:2C:1F:21:7C:A5:C8:72:7E:E8:92:6F:5F:D1 +A0:00:00:03:33 01 091231 rsa 03 BB:E9:06:6D:25:17:51:1D:23:9C:7B:FA:77:88:41:44:AE:20:C7:37:2F:51:51:47:E8:CE:65:37:C5:4C:0A:6A:4D:45:F8:CA:4D:29:08:70:CD:A5:9F:13:44:EF:71:D1:7D:3F:35:D9:2F:3F:06:77:8D:0D:51:1E:C2:A7:DC:4F:FE:AD:F4:FB:12:53:CE:37:A7:B2:B5:A3:74:12:27:BE:F7:25:24:DA:7A:2B:7B:1C:B4:26:BE:E2:7B:C5:13:B0:CB:11:AB:99:BC:1B:C6:1D:F5:AC:6C:C4:D8:31:D0:84:87:88:CD:74:F6:D5:43:AD:37:C5:A2:B4:C5:D5:A9:3B sha1 E8:81:E3:90:67:5D:44:C2:DD:81:23:4D:CE:29:C3:F5:AB:22:97:A0 +A0:00:00:03:33 02 211231 rsa 03 A3:76:7A:BD:1B:6A:A6:9D:7F:3F:BF:28:C0:92:DE:9E:D1:E6:58:BA:5F:09:09:AF:7A:1C:CD:90:73:73:B7:21:0F:DE:B1:62:87:BA:8E:78:E1:52:9F:44:39:76:FD:27:F9:91:EC:67:D9:5E:5F:4E:96:B1:27:CA:B2:39:6A:94:D6:E4:5C:DA:44:CA:4C:48:67:57:0D:6B:07:54:2F:8D:4B:F9:FF:97:97:5D:B9:89:15:15:E6:6F:52:5D:2B:3C:BE:B6:D6:62:BF:B6:C3:F3:38:E9:3B:02:14:2B:FC:44:17:3A:37:64:C5:6A:AD:D2:02:07:5B:26:DC:2F:9F:7D:7A:E7:4B:D7:D0:0F:D0:5E:E4:30:03:26:63:D2:7A:57 sha1 03:BB:33:5A:85:49:A0:3B:87:AB:08:9D:00:6F:60:85:2E:4B:80:60 +A0:00:00:03:33 03 241231 rsa 03 B0:62:7D:EE:87:86:4F:9C:18:C1:3B:9A:1F:02:54:48:BF:13:C5:83:80:C9:1F:4C:EB:A9:F9:BC:B2:14:FF:84:14:E9:B5:9D:6A:BA:10:F9:41:C7:33:17:68:F4:7B:21:27:90:7D:85:7F:A3:9A:AF:8C:E0:20:45:DD:01:61:9D:68:9E:E7:31:C5:51:15:9B:E7:EB:2D:51:A3:72:FF:56:B5:56:E5:CB:2F:DE:36:E2:30:73:A4:4C:A2:15:D6:C2:6C:A6:88:47:B3:88:E3:95:20:E0:02:6E:62:29:4B:55:7D:64:70:44:0C:A0:AE:FC:94:38:C9:23:AE:C9:B2:09:8D:6D:3A:1A:F5:E8:B1:DE:36:F4:B5:30:40:10:9D:89:B7:7C:AF:AF:70:C2:6C:60:1A:BD:F5:9E:EC:0F:DC:8A:99:08:91:40:CD:2E:81:7E:33:51:75:B0:3B:7A:A3:3D sha1 87:F0:CD:7C:0E:86:F3:8F:89:A6:6F:8C:47:07:1A:8B:88:58:6F:26 +A0:00:00:03:33 04 241231 rsa 03 BC:85:3E:6B:53:65:E8:9E:7E:E9:31:7C:94:B0:2D:0A:BB:0D:BD:91:C0:5A:22:4A:25:54:AA:29:ED:9F:CB:9D:86:EB:9C:CB:B3:22:A5:78:11:F8:61:88:AA:C7:35:1C:72:BD:9E:F1:96:C5:A0:1A:CE:F7:A4:EB:0D:2A:D6:3D:9E:6A:C2:E7:83:65:47:CB:15:95:C6:8B:CB:AF:D0:F6:72:87:60:F3:A7:CA:7B:97:30:1B:7E:02:20:18:4E:FC:4F:65:30:08:D9:3C:E0:98:C0:D9:3B:45:20:10:96:D1:AD:FF:4C:F1:F9:FC:02:AF:75:9D:A2:7C:D6:DF:D6:D7:89:B0:99:F1:6F:37:8B:61:00:33:4E:63:F3:D3:5F:32:51:A5:EC:78:69:37:31:F5:23:35:19:CD:B3:80:F5:AB:8C:0F:02:72:8E:91:D4:69:AB:D0:EA:E0:D9:3B:1C:C6:6C:E1:27:B2:9C:7D:77:44:1A:49:D0:9F:CA:5D:6D:97:62:FC:74:C3:1B:B5:06:C8:BA:E3:C7:9A:D6:C2:57:87:75:B9:59:56:B5:37:0D:1D:05:19:E3:79:06:B3:84:73:62:33:25:1E:8F:09:AD:79:DF:BE:2C:6A:BF:AD:AC:8E:4D:86:24:31:8C:27:DA:F1 sha1 F5:27:08:1C:F3:71:DD:7E:1F:D4:FA:41:4A:66:50:36:E0:F5:E6:E5 +A0:00:00:03:33 08 301231 rsa 03 B6:16:45:ED:FD:54:98:FB:24:64:44:03:7A:0F:A1:8C:0F:10:1E:BD:8E:FA:54:57:3C:E6:E6:A7:FB:F6:3E:D2:1D:66:34:08:52:B0:21:1C:F5:EE:F6:A1:CD:98:9F:66:AF:21:A8:EB:19:DB:D8:DB:C3:70:6D:13:53:63:A0:D6:83:D0:46:30:4F:5A:83:6B:C1:BC:63:28:21:AF:E7:A2:F7:5D:A3:C5:0A:C7:4C:54:5A:75:45:62:20:41:37:16:96:63:CF:CC:0B:06:E6:7E:21:09:EB:A4:1B:C6:7F:F2:0C:C8:AC:80:D7:B6:EE:1A:95:46:5B:3B:26:57:53:3E:A5:6D:92:D5:39:E5:06:43:60:EA:48:50:FE:D2:D1:BF sha1 EE:23:B6:16:C9:5C:02:65:2A:D1:88:60:E4:87:87:C0:79:E8:E8:5A +A0:00:00:03:33 09 301231 rsa 03 EB:37:4D:FC:5A:96:B7:1D:28:63:87:5E:DA:2E:AF:B9:6B:1B:43:9D:3E:CE:0B:18:26:A2:67:2E:EE:FA:79:90:28:67:76:F8:BD:98:9A:15:14:1A:75:C3:84:DF:C1:4F:EF:92:43:AA:B3:27:07:65:9B:E9:E4:79:7A:24:7C:2F:0B:6D:99:37:2F:38:4A:F6:2F:E2:3B:C5:4B:CD:C5:7A:9A:CD:1D:55:85:C3:03:F2:01:EF:4E:8B:80:6A:FB:80:9D:B1:A3:DB:1C:D1:12:AC:88:4F:16:4A:67:B9:9C:7D:6E:5A:8A:6D:F1:D3:CA:E6:D7:ED:3D:5B:E7:25:B2:DE:4A:DE:23:FA:67:9B:F4:EB:15:A9:3D:8A:6E:29:C7:FF:A1:A7:0D:E2:E5:4F:59:3D:90:8A:3B:F9:EB:BD:76:0B:BF:DC:8D:B8:B5:44:97:E6:C5:BE:0E:4A:4D:AC:29:E5 sha1 A0:75:30:6E:AB:00:45:BA:F7:2C:DD:33:B3:B6:78:77:9D:E1:F5:27 +A0:00:00:03:33 0A 301231 rsa 03 B2:AB:1B:6E:9A:C5:5A:75:AD:FD:5B:BC:34:49:0E:53:C4:C3:38:1F:34:E6:0E:7F:AC:21:CC:2B:26:DD:34:46:2B:64:A6:FA:E2:49:5E:D1:DD:38:3B:81:38:BE:A1:00:FF:9B:7A:11:18:17:E7:B9:86:9A:97:42:B1:9E:5C:9D:AC:56:F8:B8:82:7F:11:B0:5A:08:EC:CF:9E:8D:5E:85:B0:F7:CF:A6:44:EF:F3:E9:B7:96:68:8F:38:E0:06:DE:B2:1E:10:1C:01:02:89:03:A0:60:23:AC:5A:AB:86:35:F8:E3:07:A5:3A:C7:42:BD:CE:6A:28:3F:58:5F:48:EF sha1 C8:8B:E6:B2:41:7C:4F:94:1C:93:71:EA:35:A3:77:15:87:67:E4:E3 +A0:00:00:03:33 0B 301231 rsa 03 CF:9F:DF:46:B3:56:37:8E:9A:F3:11:B0:F9:81:B2:1A:1F:22:F2:50:FB:11:F5:5C:95:87:09:E3:C7:24:19:18:29:34:83:28:9E:AE:68:8A:09:4C:02:C3:44:E2:99:9F:31:5A:72:84:1F:48:9E:24:B1:BA:00:56:CF:AB:3B:47:9D:0E:82:64:52:37:5D:CD:BB:67:E9:7E:C2:AA:66:F4:60:1D:77:4F:EA:EF:77:5A:CC:C6:21:BF:EB:65:FB:00:53:FC:5F:39:2A:A5:E1:D4:C4:1A:4D:E9:FF:DF:DF:13:27:C4:BB:87:4F:1F:63:A5:99:EE:39:02:FE:95:E7:29:FD:78:D4:23:4D:C7:E6:CF:1A:BA:BA:A3:F6:DB:29:B7:F0:5D:1D:90:1D:2E:76:A6:06:A8:CB:FF:FF:EC:BD:91:8F:A2:D2:78:BD:B4:3B:04:34:F5:D4:51:34:BE:1C:27:81:D1:57:D5:01:FF:43:E5:F1:C4:70:96:7C:D5:7C:E5:3B:64:D8:29:74:C8:27:59:37:C5:D8:50:2A:12:52:A8:A5:D6:08:8A:25:9B:69:4F:98:64:8D:9A:F2:CB:0E:FD:9D:94:3C:69:F8:96:D4:9F:A3:97:02:16:2A:CB:5A:F2:9B:90:BA:DE:00:5B:C1:57 sha1 BD:33:1F:99:96:A4:90:B3:3C:13:44:10:66:A0:9A:D3:FE:B5:F6:6C +A0:00:00:03:33 0C 301231 rsa 03 DE:D9:E1:BC:8E:74:9C:AD:74:94:84:BF:B4:72:44:5B:C8:1F:FA:A8:97:07:64:8C:34:2A:A3:0D:1B:E6:0D:5E:D0:F6:CE:AB:A2:5C:68:3D:45:03:CB:11:CA:F9:1A:39:72:75:93:CF:2B:EE:AE:80:32:EF:AC:C4:4F:DF:8D:A3:1D:60:07:13:9D:45:95:E8:65:5C:74:95:CF:46:A9:D5:93:A8:3E:3C:65:B2:CB:F2:AF:1E:EA:02:D1:F9:69:51:A9:46:61:6B:5A:B2:1C:A0:BF:34:D1:2D:05:F6:AE:18:35:08:A7:AC:7A:46:91:3B:DC:E5:FD:C3:91:4C:A7:50:01:8B:13:0C:A5:BA:D4:9A:D8:C0:22:91:AC:A5:CF:FD sha1 D7:DD:7A:AC:8B:67:A9:A3:CC:72:F3:5F:5D:96:F2:65:E1:6E:B3:FE +A0:00:00:00:10 00 000000 rsa 03 9E:15:21:42:12:F6:30:8A:CA:78:B8:0B:D9:86:AC:28:75:16:84:6C:8D:54:8A:9E:D0:A4:2E:7D:99:7C:90:2C:3E:12:2D:1B:9D:C3:09:95:F4:E2:5C:75:DD:7E:E0:A0:CE:29:3B:8C:C0:2B:97:72:78:EF:25:6D:76:11:94:92:47:64:94:2F:E7:14:FA:02:E4:D5:7F:28:2B:A3:B2:B6:2C:9E:38:EF:65:17:82:3F:2C:A8:31:BD:DF:6D:36:3D sha1 05:29:83:EA:C0:F9:1D:5E:C5:1C:FB:B2:5A:5D:AD:93:BF:FD:89:70 +A0:00:00:00:10 FB 000000 rsa 02 A9:54:8D:FB:39:8B:48:12:3F:AF:41:E6:CF:A4:AE:1E:23:52:B5:18:AB:4B:CE:FE:CD:B0:B3:ED:EC:09:02:87:D8:8B:12:25:9F:36:1C:1C:C0:88:E5:F0:66:49:44:17:E8:EE:8B:BF:89:91:E2:B3:2F:F1:6F:99:46:97:84:2B:3D:6C:B3:7A:2B:B5:74:2A:44:0B:63:56:C6:2A:A3:3D:B3:C4:55:E5:9E:DD:F7:86:47:01:D0:3A:5B:83:EE:9E:9B:D8:3A:B9:33:02:AC:2D:FE:63:E6:61:20:B0:51:CF:08:1F:56:32:6A:71:30:3D:95:2B:B3:36:FF:12:61:0D sha1 11:C7:E2:BC:A2:3F:B4:BA:8C:40:C9:91:51:2F:BD:8E:C0:73:04:FC +A0:00:00:00:10 FC 000000 rsa 02 B3:7B:FD:2A:96:74:AD:62:21:C1:A0:01:08:1C:62:65:3D:C2:80:B0:A9:BD:05:2C:67:7C:91:3C:E7:A0:D9:02:E7:7B:12:F4:D4:D7:90:37:B1:E9:B9:23:A8:BB:3F:AC:3C:61:20:45:BB:39:14:F8:DF:41:E9:A1:B6:1B:FA:5B:41:70:5A:69:1D:09:CE:6F:53:0F:E4:8B:30:24:0D:98:F4:E6:92:FF:D6:AA:DB:87:24:3B:A8:59:7A:B2:37:58:6E:CF:25:8F:41:48:75:1B:E5:DA:5A:3B:E6:CC:34:BD sha1 DC:B4:EC:36:B6:60:6B:7C:6B:7C:2D:5B:7D:75:D2:B0:04:F3:6C:AD +A0:00:00:00:10 FD 000000 rsa 02 B3:57:2B:A4:9A:E4:C7:B7:A0:01:9E:51:89:E1:42:CF:CD:ED:94:98:DD:B5:F0:47:05:67:AB:0B:A7:13:B8:DA:22:64:24:62:29:55:B5:4B:93:7A:BF:EF:AA:D9:79:19:E3:77:62:1E:22:19:6A:BC:14:19:D5:AD:C1:23:48:42:09:EA:7C:B7:02:9E:66:A0:D5:4C:5B:45:C8:AD:61:5A:ED:B6:AE:9E:0A:2F:75:31:0E:A8:96:12:87:24:12:45 sha1 4A:D1:78:85:53:16:28:23:24:DC:70:DC:70:C6:F8:4A:21:F4:BA:DB +A0:00:00:00:10 FE 000000 rsa 03 A6:53:EA:C1:C0:F7:86:C8:72:4F:73:7F:17:29:97:D6:3D:1C:32:51:C4:44:02:04:9B:86:5B:AE:87:7D:0F:39:8C:BF:BE:8A:60:35:E2:4A:FA:08:6B:EF:DE:93:51:E5:4B:95:70:8E:E6:72:F0:96:8B:CD:50:DC:E4:0F:78:33:22:B2:AB:A0:4E:F1:37:EF:18:AB:F0:3C:7D:BC:58:13:AE:AE:F3:AA:77:97:BA:15:DF:7D:5B:A1:CB:AF:7F:D5:20:B5:A4:82:D8:D3:FE:E1:05:07:78:71:11:3E:23:A4:9A:F3:92:65:54:A7:0F:E1:0E:D7:28:CF:79:3B:62:A1 sha1 2C:FB:B8:24:09:ED:86:A3:19:73:B0:E0:CE:EA:38:1B:C4:3C:80:97 +A0:00:00:00:10 FF 000000 rsa 03 B8:55:CC:64:31:3A:F9:9C:45:3D:18:16:42:EE:7D:D2:1A:67:D0:FF:50:C6:1F:E2:13:BC:DC:18:AF:BC:D0:77:22:EF:DD:25:94:EF:DC:22:7D:A3:DA:23:AD:CC:90:E3:FA:90:74:53:AC:C9:54:C4:73:23:BE:DC:F8:D4:86:2C:45:7D:25:F4:7B:16:D7:C3:50:2B:E0:81:91:3E:5B:04:82:D8:38:48:40:65:DA:5F:66:59:E0:0A:9E:5D:57:0A:DA:1E:C6:AF:8C:57:96:00:75:11:95:81:FC:81:46:8D sha1 EA:A6:41:A8:26:4B:BD:25:8F:13:60:08:FD:A6:6C:9B:57:2E:3A:86 +A0:00:00:00:65 07 000000 rsa 01:00:01 B8:DA:B8:83:EF:1B:57:63:E4:F8:61:F9:EA:30:44:B2:76:63:5D:40:2F:3A:E5:E6:B6:C0:54:7E:36:8E:79:A3:63:66:DA:C5:60:9B:6E:C4:86:DA:1A:8D:20:02:CA:4F:4E:FC:2C:B0:EC:15:73:A0:B0:91:79:69:EB:60:64:5B:AE:DF:11:C0:50:C5:D0:7F:ED:81:7D:11:E8:4A:17:48:59:A0:DA:E7:F7:93:5F:10:92:29:C0:AC:4E:E5:BF:B3:D6:55:33:A6:79:F0:48:6C:5A:EF:CC:93:73:79:83:3B:EC:45:D7:9D:CF:97:B5:22:8B:19:10:FA:03:76:53:31 sha1 48:96:DD:5A:9E:B5:B1:1B:9D:CC:A6:DF:E3:36:C0:09:F6:9F:50:9A +A0:00:00:00:65 08 000000 rsa 03 B7:46:70:DA:D1:DC:89:83:65:20:00:E5:A7:F2:F8:B3:5D:FD:08:3E:E5:93:E5:BA:89:5C:95:72:9F:2B:AD:E9:C8:AB:F3:DD:9C:E2:40:C4:51:C6:CE:FF:C7:68:D8:3C:BA:C7:6A:BB:8F:EA:58:F0:13:C6:47:00:7C:FF:76:17:BA:C2:AE:39:81:81:6F:25:CC:7E:52:38:EF:34:C4:F0:2D:0B:01:C2:4F:80:C2:C6:5E:7E:77:43:A4:FA:8E:23:20:6A:23:EC:E2:90:C2:6E:A5:6D:B0:85:C5:C5:EA:E2:62:92:45:1F:C8:29:2F:99:57:BE:8F:F2:0F:AD:53:E5 sha1 DD:36:D5:89:62:28:C8:C4:90:07:42:F1:07:E2:F9:1F:E5:0B:C7:EE +A0:00:00:00:65 09 121231 rsa 03 B7:2A:8F:EF:5B:27:F2:B5:50:39:8F:DC:C2:56:F7:14:BA:D4:97:FF:56:09:4B:74:08:32:8C:B6:26:AA:6F:0E:6A:9D:F8:38:8E:B9:88:7B:C9:30:17:0B:CC:12:13:E9:0F:C0:70:D5:2C:8D:CD:0F:F9:E1:0F:AD:36:80:1F:E9:3F:C9:98:A7:21:70:50:91:F1:8B:C7:C9:82:41:CA:DC:15:A2:B9:DA:7F:B9:63:14:2C:0A:B6:40:D5:D0:13:5E:77:EB:AE:95:AF:1B:4F:EF:AD:CF:9C:01:23:66:BD:DA:04:55:C1:56:4A:68:81:0D:71:27:67:6D:49:38:90:BD sha1 44:10:C6:D5:1C:2F:83:AD:FD:92:52:8F:A6:E3:8A:32:DF:04:8D:0A +A0:00:00:00:65 0A 161231 rsa 03 99:B6:34:64:EE:0B:49:57:E4:FD:23:BF:92:3D:12:B6:14:69:B8:FF:F8:81:43:46:B2:ED:6A:78:0F:89:88:EA:9C:F0:43:3B:C1:E6:55:F0:5E:FA:66:D0:C9:80:98:F2:5B:65:9D:7A:25:B8:47:8A:36:E4:89:76:0D:07:1F:54:CD:F7:41:69:48:ED:73:3D:81:63:49:DA:2A:AD:DA:22:7E:E4:59:36:20:3C:BF:62:8C:D0:33:AA:BA:5E:5A:6E:4A:E3:7F:BA:CB:46:11:B4:11:3E:D4:27:52:9C:63:6F:6C:33:04:F8:AB:DD:6D:9A:D6:60:51:6A:E8:7F:7F:2D:DF:1D:2F:A4:4C:16:47:27:E5:6B:BC:9B:A2:3C:02:85 sha1 B8:A1:7C:ED:C3:DF:D3:95:8D:87:AA:7D:87:B6:04:8C:A5:57:B7:87 +A0:00:00:00:65 0C 191231 rsa 03 AD:F0:5C:D4:C5:B4:90:B0:87:C3:46:7B:0F:30:43:75:04:38:84:84:61:28:8B:FE:FD:61:98:DD:57:6D:C3:AD:7A:7C:FA:07:DB:A1:28:C2:47:A8:EA:B3:0D:C3:A3:0B:02:FC:D7:F1:C8:16:79:65:46:36:26:FE:FF:8A:B1:AA:61:A4:B9:AE:F0:9E:E1:2B:00:98:42:A1:AB:A0:1A:DB:4A:2B:17:06:68:78:1E:C9:2B:60:F6:05:FD:12:B2:B2:A6:F1:FE:73:4B:E5:10:F6:0D:C5:D1:89:E4:01:45:1B:62:B4:E0:68:51:EC:20:EB:FF:45:22:AA:CC:2E:9C:DC:89:BC:5D:8C:DE:5D:63:3C:FD:77:22:0F:F6:BB:D4:A9:B4:41:47:3C:C3:C6:FE:FC:8D:13:E5:7C:3D:E9:7E:12:69:FA:19:F6:55:21:5B:23:56:3E:D1:D1:86:0D:86:81 sha1 CD:82:81:2F:9E:84:40:48:F4:8E:D5:6E:D8:4E:FB:32:67:E8:70:F8 +A0:00:00:00:65 0E 191231 rsa 03 AE:ED:55:B9:EE:00:E1:EC:EB:04:5F:61:D2:DA:9A:66:AB:63:7B:43:FB:5C:DB:DB:22:A2:FB:B2:5B:E0:61:E9:37:E3:82:44:EE:51:32:F5:30:14:4A:3F:26:89:07:D8:FD:64:88:63:F5:A9:6F:ED:7E:42:08:9E:93:45:7A:DC:0E:1B:C8:9C:58:A0:DB:72:67:5F:BC:47:FE:E9:FF:33:C1:6A:DE:6D:34:19:36:B0:6B:6A:6F:5E:F6:F6:6A:4E:DD:98:1D:F7:5D:A8:39:9C:30:53:F4:30:EC:A3:42:43:7C:23:AF:42:3A:21:1A:C9:F5:8E:AF:09:B0:F8:37:DE:9D:86:C7:10:9D:B1:64:65:61:AA:5A:F0:28:9A:F5:51:4A:C6:4B:C2:D9:D3:6A:17:9B:B8:A7:97:1E:2B:FA:03:A9:E4:B8:47:FD:3D:63:52:4D:43:A0:E8:00:35:47:B9:4A:8A:75:E5:19:DF:31:77:D0:A6:0B:C0:B4:BA:B1:EA:59:A2:CB:B4:D2:D6:23:54:E9:26:E9:C7:D3:BE:41:81:E8:1B:A6:0F:82:85:A8:96:D1:7D:A8:C3:24:24:81:B6:C4:05:76:9A:39:D5:47:C7:4E:D9:FF:95:A7:0A:79:60:46:B5:EF:F3:66:82:DC:29 sha1 A1:63:72:4B:2C:B9:23:37:63:67:BB:E0:6B:09:C0:3F:13:6F:43:93 +A0:00:00:00:65 0F 000000 rsa 03 9E:FB:AD:DE:40:71:D4:EF:98:C9:69:EB:32:AF:85:48:64:60:2E:51:5D:65:01:FD:E5:76:B3:10:96:4A:4F:7C:2C:E8:42:AB:EF:AF:C5:DC:9E:26:A6:19:BC:F2:61:4F:E0:73:75:B9:24:9B:EF:A0:9C:FE:E7:02:32:E7:5F:FD:64:75:71:28:0C:76:FF:CA:87:51:1A:D2:55:B9:8A:6B:57:75:91:AF:01:D0:03:BD:6B:F7:E1:FC:E4:DF:D2:0D:0D:02:97:ED:5E:CA:25:DE:26:1F:37:EF:E9:E1:75:FB:5F:12:D2:50:3D:8C:FB:06:0A:63:13:85:11:FE:0E:12:5C:F3:A6:43:AF:D7:D6:6D:CF:96:82:BD:24:6D:DE:A1 sha1 2A:1B:82:DE:00:F5:F0:C4:01:76:0A:DF:52:82:28:D3:ED:E0:F4:03 +A0:00:00:00:65 10 000000 rsa 03 99:B6:34:64:EE:0B:49:57:E4:FD:23:BF:92:3D:12:B6:14:69:B8:FF:F8:81:43:46:B2:ED:6A:78:0F:89:88:EA:9C:F0:43:3B:C1:E6:55:F0:5E:FA:66:D0:C9:80:98:F2:5B:65:9D:7A:25:B8:47:8A:36:E4:89:76:0D:07:1F:54:CD:F7:41:69:48:ED:73:3D:81:63:49:DA:2A:AD:DA:22:7E:E4:59:36:20:3C:BF:62:8C:D0:33:AA:BA:5E:5A:6E:4A:E3:7F:BA:CB:46:11:B4:11:3E:D4:27:52:9C:63:6F:6C:33:04:F8:AB:DD:6D:9A:D6:60:51:6A:E8:7F:7F:2D:DF:1D:2F:A4:4C:16:47:27:E5:6B:BC:9B:A2:3C:02:85 sha1 C7:5E:52:10:CB:E6:E8:F0:59:4A:0F:19:11:B0:74:18:CA:DB:5B:AB +A0:00:00:00:65 11 000000 rsa 03 A2:58:3A:A4:07:46:E3:A6:3C:22:47:8F:57:6D:1E:FC:5F:B0:46:13:5A:6F:C7:39:E8:2B:55:03:5F:71:B0:9B:EB:56:6E:DB:99:68:DD:64:9B:94:B6:DE:DC:03:38:99:88:4E:90:8C:27:BE:1C:D2:91:E5:43:6F:76:25:53:29:77:63:DA:A3:B8:90:D7:78:C0:F0:1E:33:44:CE:CD:FB:3B:A7:0D:7E:05:5B:8C:76:0D:01:79:A4:03:D6:B5:5F:2B:3B:08:39:12:B1:83:AD:B7:92:74:41:BE:D3:39:5A:19:9E:EF:E0:DE:BD:1F:5F:C3:26:40:33:DA:85:6F:4A:8B:93:91:68:85:BD:42:F9:C1:F4:56:AA:B8:CF:A8:3A:C5:74:83:3E:B5:E8:7B:B9:D4:C0:06:A4:B5:34:6B:D9:E1:7E:13:9A:B6:55:2D:9C:58:BC:04:11:95:33:64:85 sha1 D9:FD:62:C9:DD:4E:6D:E7:74:1E:9A:17:FB:1F:F2:C5:DB:94:8B:CB +A0:00:00:00:65 12 000000 rsa 03 AD:F0:5C:D4:C5:B4:90:B0:87:C3:46:7B:0F:30:43:75:04:38:84:84:61:28:8B:FE:FD:61:98:DD:57:6D:C3:AD:7A:7C:FA:07:DB:A1:28:C2:47:A8:EA:B3:0D:C3:A3:0B:02:FC:D7:F1:C8:16:79:65:46:36:26:FE:FF:8A:B1:AA:61:A4:B9:AE:F0:9E:E1:2B:00:98:42:A1:AB:A0:1A:DB:4A:2B:17:06:68:78:1E:C9:2B:60:F6:05:FD:12:B2:B2:A6:F1:FE:73:4B:E5:10:F6:0D:C5:D1:89:E4:01:45:1B:62:B4:E0:68:51:EC:20:EB:FF:45:22:AA:CC:2E:9C:DC:89:BC:5D:8C:DE:5D:63:3C:FD:77:22:0F:F6:BB:D4:A9:B4:41:47:3C:C3:C6:FE:FC:8D:13:E5:7C:3D:E9:7E:12:69:FA:19:F6:55:21:5B:23:56:3E:D1:D1:86:0D:86:81 sha1 87:4B:37:9B:7F:60:7D:C1:CA:F8:7A:19:E4:00:B6:A9:E2:51:63:E8 +A0:00:00:00:65 14 000000 rsa 03 AE:ED:55:B9:EE:00:E1:EC:EB:04:5F:61:D2:DA:9A:66:AB:63:7B:43:FB:5C:DB:DB:22:A2:FB:B2:5B:E0:61:E9:37:E3:82:44:EE:51:32:F5:30:14:4A:3F:26:89:07:D8:FD:64:88:63:F5:A9:6F:ED:7E:42:08:9E:93:45:7A:DC:0E:1B:C8:9C:58:A0:DB:72:67:5F:BC:47:FE:E9:FF:33:C1:6A:DE:6D:34:19:36:B0:6B:6A:6F:5E:F6:F6:6A:4E:DD:98:1D:F7:5D:A8:39:9C:30:53:F4:30:EC:A3:42:43:7C:23:AF:42:3A:21:1A:C9:F5:8E:AF:09:B0:F8:37:DE:9D:86:C7:10:9D:B1:64:65:61:AA:5A:F0:28:9A:F5:51:4A:C6:4B:C2:D9:D3:6A:17:9B:B8:A7:97:1E:2B:FA:03:A9:E4:B8:47:FD:3D:63:52:4D:43:A0:E8:00:35:47:B9:4A:8A:75:E5:19:DF:31:77:D0:A6:0B:C0:B4:BA:B1:EA:59:A2:CB:B4:D2:D6:23:54:E9:26:E9:C7:D3:BE:41:81:E8:1B:A6:0F:82:85:A8:96:D1:7D:A8:C3:24:24:81:B6:C4:05:76:9A:39:D5:47:C7:4E:D9:FF:95:A7:0A:79:60:46:B5:EF:F3:66:82:DC:29 sha1 C0:D1:5F:6C:D9:57:E4:91:DB:56:DC:DD:1C:A8:7A:03:EB:E0:6B:7B +A0:00:00:00:65 DA 000000 rsa 03 DC:74:49:EC:24:94:4E:A4:C0:9E:F3:76:56:F5:39:05:94:DE:4F:16:86:AF:C4:B1:C2:1C:89:3F:5F:3A:EF:C5:A8:10:9E:06:A5:23:89:C0:41:4E:7D:FB:C4:42:93:B0:4D:5F:4E:85:52:8F:A8:5F:1A:97:06:BA:AA:A0:34:E8:B4:41:11:C0:43:B1:CC:95:30:9C:69:46:22:59:71:D4:B1:58:90:9F:44:38:72:68:12:77:7F:AC:4D:06:87:9A:7A:A4:10:89:F0:DD:2C:27:B3:EA:A2:3A:8D:02:E2:A9:A9:B8:ED:AD:0C:A3:2A:E9:1B:38:37:40:CF:50:E5:E5 sha1 5C:03:7E:18:15:E3:8B:79:D4:D5:C1:5F:F9:0C:E4:E3:F2:07:08:63 +A0:00:00:00:65 EA 000000 rsa 03 A9:79:6C:29:E3:9C:2D:44:FD:DA:E7:EE:13:41:DA:54:61:DC:E4:DC:B3:14:38:D5:83:B2:BC:08:45:B6:4A:A3:7D:05:5B:19:0D:7F:51:52:E5:05:7A:5F:B9:CD:27:63:4E:AC:40:03:A2:80:3C:80:4E:22:D4:92:73:8A:16:43:69:A1:7F:26:5F:80:16:C6:22:DA:06:31:49:4F:03:B2:DA:4D:5E:7D:13:F7:08:2F:9B:D8:A7:39:3B:11:9A:C7:0A:39:E8:61:B6:45:B1:FB:F2:9B:A9:CC:1B:8A:5A:97:B5:A8:44:4D:B0:FC:A5:BC:51:1E:68:E7:B0:1D:7A:DC:B8:E4:6D:96:48:A9:95:E2:56:F7:71:52:51:B4:31:B3 sha1 88:F6:D0:4B:ED:35:D6:B4:3E:69:7D:76:5A:E3:29:3F:64:9A:96:1F +A0:00:00:00:65 EB 000000 rsa 03 A9:A6:96:A7:E3:C6:AC:14:21:E4:DE:89:36:EF:B6:D6:6C:E9:60:EA:FA:6E:A5:E0:3D:06:6F:29:62:84:A6:1D:A2:89:0A:6D:0D:86:9B:A8:C9:A9:E0:1E:4E:FF:3B:BE:33:1E:CE:2C:E1:42:9C:06:6D:D8:85:78:1E:2A:DA:BC:86:CF:FD:76:85:4F:B9:F1:BC:DA:ED:CE:6B:54:72:7D:9C:2C:01:C9:64:2E:9C:D1:BF:C4:CF:24:A6:A2:E4:9C:15:41:B0:2E:BC:05:34:74:44:81:CC:89:22:07:3A:21:F8:E0:D7:2B:C8:99:8B:D5:29:C6:98:56:7A:87:F1:64:50:DF:B9:69:96:1A:41:86:AB:4C:C6:48:A4:D4:1B:14:9E:3D:D2:13:93:A9:93:83:3D:5E:EE:EB:FC:BC:E0:C7:77:B5:24:47:ED:3B:81:6E:3A:29:84:93:0C:07:C0:21 sha1 A1:9C:AF:70:06:03:E3:7B:C7:C2:E5:C4:20:A1:1A:56:D1:A8:BA:C3 +A0:00:00:00:65 EC 000000 rsa 03 A9:ED:FD:C5:80:29:A7:EC:00:3D:13:F2:2F:6A:ED:56:22:78:6D:45:F7:C3:65:16:A3:DB:FE:4D:75:BF:CE:00:F4:CF:65:66:70:CD:07:A6:6A:99:A7:CD:35:D2:F5:22:8C:B2:D7:94:B9:5C:49:30:FD:DA:D1:7F:8C:92:93:16:4A:FE:C8:76:D5:64:4D:D3:1A:BF:E8:6B:7A:A5:12:C5:8D:5C:71:31:0F:B3:6E:8D:7C:CF:F4:C9:58:66:9C:00:42:DF:F0:48:F5:2E:41:2B:53:0C:3B:B7:75:55:B6:F9:B3:5E:2C:0F:1B:17:A6:18:0D:03:D9:49:14:B4:97:0A:42:30:9F:25:9D:B3:7E:C7:7F:F6:BA:04:BA:CF:6B:17:FF:7B:10:C1:A0:42:72:D0:8C:04:3A:1C:8E:89:51:68:1D:E4:1B:E3:0F:4E:42:D3:ED:3F:E3:32:8B:D4:C6:32:7B:19:D1:10:A2:E8:5D:9D:C4:C3:42:25:A2:F0:CA:76:84:FF:5C:05:C1:F0:11:35:FC:51:D7:33:1E:3A:41:3A:ED:09:42:C8:BB:DB:97:51:04:E1:71:B0:8E:E7:C2:B3:88:EC:4E:A4:93:BE:5F:CB:0C:41:6D:F2:A9:DB:BC:DF:A5:D1:23:44:EC:30:57:6B sha1 A1:59:45:94:69:35:95:68:45:AD:B8:AB:E7:3E:5B:0B:EE:F7:6E:CB +A0:00:00:00:29 01 091231 rsa 03 C6:96:03:42:13:D7:D8:54:69:84:57:9D:1D:0F:0E:A5:19:CF:F8:DE:FF:C4:29:35:4C:F3:A8:71:A6:F7:18:3F:12:28:DA:5C:74:70:C0:55:38:71:00:CB:93:5A:71:2C:4E:28:64:DF:5D:64:BA:93:FE:7E:63:E7:1F:25:B1:E5:F5:29:85:75:EB:E1:C6:3A:A6:17:70:69:17:91:1D:C2:A7:5A:C2:8B:25:1C:7E:F4:0F:23:65:91:24:90:B9:39:BC:A2:12:4A:30:A2:8F:54:40:2C:34:AE:CA:33:1A:B6:7E:1E:79:B2:85:DD:57:71:B5:D9:FF:79:EA:63:0B:75 sha1 4E:4D:5E:50:1E:A5:D9:6E:B8:1B:9E:22:E7:45:31:7C:DF:49:A4:57 +A0:00:00:00:29 03 000000 rsa 03 B3:E5:E6:67:50:6C:47:CA:AF:B1:2A:26:33:81:93:50:84:66:97:DD:65:A7:96:E5:CE:77:C5:7C:62:6A:66:F7:0B:B6:30:91:16:12:AD:28:32:90:9B:80:62:29:1B:EC:A4:6C:D3:3B:66:A6:F9:C9:D4:8C:ED:8B:4F:C8:56:1C:8A:1D:8F:B1:58:62:C9:EB:60:17:8D:EA:2B:E1:F8:22:36:FF:CF:F4:F3:84:3C:27:21:79:DC:DD:38:4D:54:10:53:DA:6A:6A:0D:3C:E4:8F:DC:2D:C4:E3:E0:EE:E1:5F sha1 3B:37:79:E1:0E:2B:B0:C1:7A:40:01:E9:CC:D0:A4:10:3C:7D:7E:32 +A0:00:00:00:29 05 000000 rsa 03 D0:13:5C:E8:A4:43:6C:7F:9D:5C:C6:65:47:E3:0E:A4:02:F9:81:05:B7:17:22:E2:4B:C0:8D:CC:80:AB:7E:71:EC:23:B8:CE:6A:1D:C6:AC:2A:8C:F5:55:43:D7:4A:8A:E7:B3:88:F9:B1:74:B7:F0:D7:56:C2:2C:BB:59:74:F9:01:6A:56:B6:01:CC:A6:4C:71:F0:4B:78:E8:6C:50:1B:19:3A:55:56:D5:38:9E:CE:4D:EA:25:8A:B9:7F:52:A3 sha1 0F:D0:6A:0F:4D:59:73:4D:F0:B5:1B:76:F3:30:71:CE:67:20:67:47 +A0:00:00:00:29 06 000000 rsa 03 F9:34:FC:03:2B:E5:9B:60:9A:9A:64:9E:04:44:6F:1B:36:5D:1D:23:A1:E6:57:4E:49:01:70:52:7E:DF:32:F3:98:32:61:59:B3:9B:63:D0:7E:95:E6:27:6D:7F:CB:B7:86:92:51:82:BC:06:67:FB:D8:F6:56:6B:36:1C:A4:1A:38:DD:F2:27:09:1B:87:FA:4F:47:BA:C7:80:AC:47:E1:5A:6A:0F:B6:53:93:EB:34:73:E8:D1:93:A0:7E:B5:79 sha1 ED:18:09:78:9A:1D:4B:10:83:EF:19:74:0D:76:26:F6:89:FF:39:E4 +A0:00:00:00:29 07 141231 rsa 03 A8:9F:25:A5:6F:A6:DA:25:8C:8C:A8:B4:04:27:D9:27:B4:A1:EB:4D:7E:A3:26:BB:B1:2F:97:DE:D7:0A:E5:E4:48:0F:C9:C5:E8:A9:72:17:71:10:A1:CC:31:8D:06:D2:F8:F5:C4:84:4A:C5:FA:79:A4:DC:47:0B:B1:1E:D6:35:69:9C:17:08:1B:90:F1:B9:84:F1:2E:92:C1:C5:29:27:6D:8A:F8:EC:7F:28:49:20:97:D8:CD:5B:EC:EA:16:FE:40:88:F6:CF:AB:4A:1B:42:32:8A:1B:99:6F:92:78:B0:B7:E3:31:1C:A5:EF:85:6C:2F:88:84:74:B8:36:12:A8:2E:4E:00:D0:CD:40:69:A6:78:31:40:43:3D:50:72:5F sha1 31:A7:87:E1:4B:59:F7:D9:26:3E:87:76:E6:E0:1E:88:63:E1:DB:F1 +A0:00:00:00:29 08 151231 rsa 03 D9:FD:6E:D7:5D:51:D0:E3:06:64:BD:15:70:23:EA:A1:FF:A8:71:E4:DA:65:67:2B:86:3D:25:5E:81:E1:37:A5:1D:E4:F7:2B:CC:9E:44:AC:E1:21:27:F8:7E:26:3D:3A:F9:DD:9C:F3:5C:A4:A7:B0:1E:90:70:00:BA:85:D2:49:54:C2:FC:A3:07:48:25:DD:D4:C0:C8:F1:86:CB:02:0F:68:3E:02:F2:DE:AD:39:69:13:3F:06:F7:84:51:66:AC:EB:57:CA:0F:C2:60:34:45:46:98:11:D2:93:BF:EF:BA:FA:B5:76:31:B3:DD:91:E7:96:BF:85:0A:25:01:2F:1A:E3:8F:05:AA:5C:4D:6D:03:B1:DC:2E:56:86:12:78:59:38:BB:C9:B3:CD:3A:91:0C:1D:A5:5A:5A:92:18:AC:E0:F7:A2:12:87:75:26:82:F1:58:32:A6:78:D6:E1:ED:0B sha1 A9:60:F5:8B:E9:B0:26:6B:6A:6D:AD:BA:7C:6C:92:72:4B:58:AD:DE +A0:00:00:00:29 09 171231 rsa 03 9D:91:22:48:DE:0A:4E:39:C1:A7:DD:E3:F6:D2:58:89:92:C1:A4:09:5A:FB:D1:82:4D:1B:A7:48:47:F2:BC:49:26:D2:EF:D9:04:B4:B5:49:54:CD:18:9A:54:C5:D1:17:96:54:F8:F9:B0:D2:AB:5F:03:57:EB:64:2F:ED:A9:5D:39:12:C6:57:69:45:FA:B8:97:E7:06:2C:AA:44:A4:AA:06:B8:FE:6E:3D:BA:18:AF:6A:E3:73:8E:30:42:9E:E9:BE:03:42:7C:9D:64:F6:95:FA:8C:AB:4B:FE:37:68:53:EA:34:AD:1D:76:BF:CA:D1:59:08:C0:77:FF:E6:DC:55:21:EC:EF:5D:27:8A:96:E2:6F:57:35:9F:FA:ED:A1:94:34:B9:37:F1:AD:99:9D:C5:C4:1E:B1:19:35:B4:4C:18:10:0E:85:7F:43:1A:4A:5A:6B:B6:51:14:F1:74:C2:D7:B5:9F:DF:23:7D:6B:B1:DD:09:16:E6:44:D7:09:DE:D5:64:81:47:7C:75:D9:5C:DD:68:25:46:15:F7:74:0E:C0:7F:33:0A:C5:D6:7B:CD:75:BF:23:D2:8A:14:08:26:C0:26:DB:DE:97:1A:37:CD:3E:F9:B8:DF:64:4A:C3:85:01:05:01:EF:C6:50:9D:7A:41 sha1 F0:00:60:35:56:42:54:DC:DD:DE:B7:9B:30:BD:28:41:B7:6B:5C:0C +A0:00:00:00:29 0E 131231 rsa 03 AA:94:A8:C6:DA:D2:4F:9B:A5:6A:27:C0:9B:01:02:08:19:56:8B:81:A0:26:BE:9F:D0:A3:41:6C:A9:A7:11:66:ED:50:84:ED:91:CE:D4:7D:D4:57:DB:7E:6C:BC:D5:3E:56:0B:C5:DF:48:AB:C3:80:99:3B:6D:54:9F:51:96:CF:A7:7D:FB:20:A0:29:61:88:E9:69:A2:77:2E:8C:41:41:66:5F:8B:B2:51:6B:A2:C7:B5:FC:91:F8:DA:04:E8:D5:12:EB:0F:64:11:51:6F:B8:6F:C0:21:CE:7E:96:9D:A9:4D:33:93:79:09:A5:3A:57:F9:07:C4:0C:22:00:9D:A7:53:2C:B3:BE:50:9A:E1:73:B3:9A:D6:A0:1B:A5:BB:85 sha1 B2:21:AC:62:62:27:9E:9D:56:C5:4B:C5:F0:81:B3:7F:27:24:34:1F +A0:00:00:00:29 0F 221231 rsa 03 C8:D5:AC:27:A5:E1:FB:89:97:8C:7C:64:79:AF:99:3A:B3:80:0E:B2:43:99:6F:BB:2A:E2:6B:67:B2:3A:C4:82:C4:B7:46:00:5A:51:AF:A7:D2:D8:3E:89:4F:59:1A:23:57:B3:0F:85:B8:56:27:FF:15:DA:12:29:0F:70:F0:57:66:55:2B:A1:1A:D3:4B:71:09:FA:49:DE:29:DC:B0:10:96:70:87:5A:17:EA:95:54:9E:92:34:7B:94:8A:A1:F0:45:75:6D:E5:6B:70:7E:38:63:E5:9A:6C:BE:99:C1:27:2E:F6:5F:B6:6C:BB:4C:FF:07:0F:36:02:9D:D7:62:18:B2:12:42:64:5B:51:CA:75:2A:F3:7E:70:BE:1A:84:FF:31:07:9D:C0:04:8E:92:88:83:EC:4F:AD:D4:97:A7:19:38:5C:2B:BB:EB:C5:A6:6A:A5:E5:65:5D:18:03:4E:C5 sha1 8D:4D:7F:8D:BD:71:82:C7:11:AD:A8:A0:44:EE:27:FE:1A:05:50:43 +A0:00:00:00:29 67 221231 rsa 03 C6:87:AD:CC:F3:D5:7D:33:60:B1:74:E4:71:ED:A6:93:AA:55:5D:FD:C6:C8:CD:39:4C:74:BA:25:CC:DF:8E:AB:FD:1F:1C:EA:DF:BE:22:80:C9:E8:1F:7A:05:89:98:DC:22:B7:F2:25:76:FE:84:71:3D:0B:DD:3D:34:CF:CD:12:FC:D0:D2:69:01:BA:74:10:3D:07:5C:66:4D:AB:CC:AF:57:BF:78:94:94:05:1C:5E:C3:03:A2:E1:D7:84:30:6D:3D:B3:EB:66:5C:D3:60:A5:58:F4:0B:7C:05:C9:19:B2:F0:28:2F:E1:ED:9B:F6:26:1A:A8:14:64:8F:BC:26:3B:14:21:44:91:DE:42:6D:24:2D:65:CD:1F:FF:0F:BE:4D:4D:AF:F5:CF:AC:B2:AD:C7:13:1C:9B:14:7E:E7:91:95:65:51:07:62:70:69:6B:75:FD:97:37:3F:1F:D7:80:4F sha1 A6:26:9F:40:9E:9B:7C:57:46:91:B5:E7:00:E4:A8:FC:D4:99:76:2A +A0:00:00:00:29 92 000000 rsa 03 99:6A:F5:6F:56:91:87:D0:92:93:C1:48:10:45:0E:D8:EE:33:57:39:7B:18:A2:45:8E:FA:A9:2D:A3:B6:DF:65:14:EC:06:01:95:31:8F:D4:3B:E9:B8:F0:CC:66:9E:3F:84:40:57:CB:DD:F8:BD:A1:91:BB:64:47:3B:C8:DC:9A:73:0D:B8:F6:B4:ED:E3:92:41:86:FF:D9:B8:C7:73:57:89:C2:3A:36:BA:0B:8A:F6:53:72:EB:57:EA:5D:89:E7:D1:4E:9C:7B:6B:55:74:60:F1:08:85:DA:16:AC:92:3F:15:AF:37:58:F0:F0:3E:BD:3C:5C:2C:94:9C:BA:30:6D:B4:4E:6A:2C:07:6C:5F:67:E2:81:D7:EF:56:78:5D:C4:D7:59:45:E4:91:F0:19:18:80:0A:9E:2D:C6:6F:60:08:05:66:CE:0D:AF:8D:17:EA:D4:6A:D8:E3:0A:24:7C:9F sha1 08:67:2C:6A:69:C3:92:CA:F8:29:DB:67:FF:79:DE:F3:D5:C7:FA:1C +A0:00:00:00:29 94 000000 rsa 03 AC:D2:B1:23:02:EE:64:4F:3F:83:5A:BD:1F:C7:A6:F6:2C:CE:48:FF:EC:62:2A:A8:EF:06:2B:EF:6F:B8:BA:8B:C6:8B:BF:6A:B5:87:0E:ED:57:9B:C3:97:3E:12:13:03:D3:48:41:A7:96:D6:DC:BC:41:DB:F9:E5:2C:46:09:79:5C:0C:CF:7E:E8:6F:A1:D5:CB:04:10:71:ED:2C:51:D2:20:2F:63:F1:15:6C:58:A9:2D:38:BC:60:BD:F4:24:E1:77:6E:2B:C9:64:80:78:A0:3B:36:FB:55:43:75:FC:53:D5:7C:73:F5:16:0E:A5:9F:3A:FC:53:98:EC:7B:67:75:8D:65:C9:BF:F7:82:8B:6B:82:D4:BE:12:4A:41:6A:B7:30:19:14:31:1E:A4:62:C1:9F:77:1F:31:B3:B5:73:36:00:0D:FF:73:2D:3B:83:DE:07:05:2D:73:03:54:D2:97:BE:C7:28:71:DC:CF:0E:19:3F:17:1A:BA:27:EE:46:4C:6A:97:69:09:43:D5:9B:DA:BB:2A:27:EB:71:CE:EB:DA:FA:11:76:04:64:78:FD:62:FE:C4:52:D5:CA:39:32:96:53:0A:A3:F4:19:27:AD:FE:43:4A:2D:F2:AE:30:54:F8:84:06:57:A2:6E:0F:C6:17 sha1 43:AE:4F:38:49:E6:BC:75:37:34:DB:20:00:45:D7:A7:A9:37:7E:91 +A0:00:00:00:29 95 000000 rsa 03 BE:9E:1F:A5:E9:A8:03:85:29:99:C4:AB:43:2D:B2:86:00:DC:D9:DA:B7:6D:FA:AA:47:35:5A:0F:E3:7B:15:08:AC:6B:F3:88:60:D3:C6:C2:E5:B1:2A:3C:AA:F2:A7:00:5A:72:41:EB:AA:77:71:11:2C:74:CF:9A:06:34:65:2F:BC:A0:E5:98:0C:54:A6:47:61:EA:10:1A:11:4E:0F:0B:55:72:AD:D5:7D:01:0B:7C:9C:88:7E:10:4C:A4:EE:12:72:DA:66:D9:97:B9:A9:0B:5A:6D:62:4A:B6:C5:7E:73:C8:F9:19:00:0E:B5:F6:84:89:8E:F8:C3:DB:EF:B3:30:C6:26:60:BE:D8:8E:A7:8E:90:9A:FF:05:F6:DA:62:7B sha1 E6:8C:36:84:88:B8:84:64:03:AF:13:D7:2D:53:0F:27:91:6D:F0:8C +A0:00:00:00:29 96 000000 rsa 03 B7:45:86:D1:9A:20:7B:E6:62:7C:5B:0A:AF:BC:44:A2:EC:F5:A2:94:2D:3A:26:CE:19:C4:FF:AE:EE:92:05:21:86:89:22:E8:93:E7:83:82:25:A3:94:7A:26:14:79:6F:B2:C0:62:8C:E8:C1:1E:38:25:A5:6D:3B:1B:BA:EF:78:3A:5C:6A:81:F3:6F:86:25:39:51:26:FA:98:3C:52:16:D3:16:6D:48:AC:DE:8A:43:12:12:FF:76:3A:7F:79:D9:ED:B7:FE:D7:6B:48:5D:E4:5B:EB:82:9A:3D:47:30:84:8A:36:6D:33:24:C3:02:70:32:FF:8D:16:A1:E4:4D:8D sha1 ED:0B:CD:6C:46:30:07:DE:FC:8B:66:ED:B0:43:00:2A:AF:FC:F3:6D +A0:00:00:00:29 97 000000 rsa 03 AF:07:54:EA:ED:97:70:43:AB:6F:41:D6:31:2A:B1:E2:2A:68:09:17:5B:EB:28:E7:0D:5F:99:B2:DF:18:CA:E7:35:19:34:1B:BB:D3:27:D0:B8:BE:9D:4D:0E:15:F0:7D:36:EA:3E:3A:05:C8:92:F5:B1:9A:3E:9D:34:13:B0:D9:7E:7A:D1:0A:5F:5D:E8:E3:88:60:C0:AD:00:4B:1E:06:F4:04:0C:29:5A:CB:45:7A:78:85:51:B6:12:7C:0B:29 sha1 04:6E:BB:71:36:51:7C:2B:D0:10:05:FB:00:21:FF:DE:2C:AA:B7:2D +A0:00:00:00:29 98 000000 rsa 03 CA:02:6E:52:A6:95:E7:2B:D3:0A:F9:28:19:6E:ED:C9:FA:F4:A6:19:F2:49:2E:3F:B3:11:69:78:9C:27:6F:FB:B7:D4:31:16:64:7B:A9:E0:D1:06:A3:54:2E:39:65:29:2C:F7:78:23:DD:34:CA:8E:EC:7D:E3:67:E0:80:70:89:50:77:C7:EF:AD:93:99:24:CB:18:70:67:DB:F9:2C:B1:E7:85:91:7B:D3:8B:AC:E0:C1:94:CA:12:DF:0C:E5:B7:A5:02:75:AC:61:BE:7C:3B:43:68:87:CA:98:C9:FD:39 sha1 BA:D4:0E:C6:2E:3B:53:C7:5E:92:EC:FB:CC:9E:99:49:A4:00:23:32 +A0:00:00:00:29 99 000000 rsa 03 AB:79:FC:C9:52:08:96:96:7E:77:6E:64:44:4E:5D:CD:D6:E1:36:11:87:4F:39:85:72:25:20:42:52:95:EE:A4:BD:0C:27:81:DE:7F:31:CD:3D:04:1F:56:5F:74:73:06:EE:D6:29:54:B1:7E:DA:BA:3A:6C:5B:85:A1:DE:1B:EB:9A:34:14:1A:F3:8F:CF:82:79:C9:DE:A0:D5:A6:71:0D:08:DB:41:24:F0:41:94:55:87:E2:03:59:BA:B4:7B:75:75:AD:94:26:2D:4B:25:F2:64:AF:33:DE:DC:F2:8E:09:61:5E:93:7D:E3:2E:DC:03:C5:44:45:FE:7E:38:27:77 sha1 B2:D5:D4:01:E8:13:D0:58:BC:92:F9:69:19:2A:88:2E:7C:30:70:FC +A0:00:00:00:04 00 000000 rsa 03 9C:6B:E5:AD:B1:0B:4B:E3:DC:E2:09:9B:4B:21:06:72:B8:96:56:EB:A0:91:20:4F:61:3E:CC:62:3B:ED:C9:C6:D7:7B:66:0E:8B:AE:EA:7F:7C:E3:0F:1B:15:38:79:A4:E3:64:59:34:3D:1F:E4:7A:CD:BD:41:FC:D7:10:03:0C:2B:A1:D9:46:15:97:98:2C:6E:1B:DD:08:55:4B:72:6F:5E:FF:79:13:CE:59:E7:9E:35:72:95:C3:21:E2:6D:0B:8B:E2:70:A9:44:23:45:C7:53:E2:AA:2A:CF:C9:D3:08:50:60:2F:E6:CA:C0:0C:6D:DF:6B:8D:9D:9B:48:79:B2:82:6B:04:2A:07:F0:E5:AE:52:6A:3D:3C:4D:22:C7:2B:9E:AA:52:EE:D8:89:38:66:F8:66:38:7A:C0:5A:13:99 sha1 EC:0A:59:D3:5D:19:F0:31:E9:E8:CB:EC:56:DB:80:E2:2B:1D:E1:30 +A0:00:00:00:04 00 091231 rsa 03 9E:15:21:42:12:F6:30:8A:CA:78:B8:0B:D9:86:AC:28:75:16:84:6C:8D:54:8A:9E:D0:A4:2E:7D:99:7C:90:2C:3E:12:2D:1B:9D:C3:09:95:F4:E2:5C:75:DD:7E:E0:A0:CE:29:3B:8C:C0:2B:97:72:78:EF:25:6D:76:11:94:92:47:64:94:2F:E7:14:FA:02:E4:D5:7F:28:2B:A3:B2:B6:2C:9E:38:EF:65:17:82:3F:2C:A8:31:BD:DF:6D:36:3D sha1 8B:B9:9A:DD:F7:B5:60:11:09:55:01:45:05:FB:6B:5F:83:08:CE:27 +A0:00:00:00:04 01 000000 rsa 03 C6:96:03:42:13:D7:D8:54:69:84:57:9D:1D:0F:0E:A5:19:CF:F8:DE:FF:C4:29:35:4C:F3:A8:71:A6:F7:18:3F:12:28:DA:5C:74:70:C0:55:38:71:00:CB:93:5A:71:2C:4E:28:64:DF:5D:64:BA:93:FE:7E:63:E7:1F:25:B1:E5:F5:29:85:75:EB:E1:C6:3A:A6:17:70:69:17:91:1D:C2:A7:5A:C2:8B:25:1C:7E:F4:0F:23:65:91:24:90:B9:39:BC:A2:12:4A:30:A2:8F:54:40:2C:34:AE:CA:33:1A:B6:7E:1E:79:B2:85:DD:57:71:B5:D9:FF:79:EA:63:0B:75 sha1 8C:05:A6:41:27:48:5B:92:3C:94:B6:3D:26:4A:F0:BF:85:CB:45:D9 +A0:00:00:00:04 01 091231 rsa 03 D2:01:07:16:C9:FB:52:64:D8:C9:1A:14:F4:F3:2F:89:81:EE:95:4F:20:08:7E:D7:7C:DC:58:68:43:17:28:D3:63:7C:63:2C:CF:27:18:A4:F5:D9:2E:A8:AB:16:6A:B9:92:D2:DE:24:E9:FB:DC:7C:AB:97:29:40:1E:91:C5:02:D7:2B:39:F6:86:6F:5C:09:8B:12:43:B1:32:AF:EE:65:F5:03:6E:16:83:23:11:63:38:F8:04:08:34:B9:87:25 sha1 EA:95:0D:D4:23:4F:EB:7C:90:0C:0B:E8:17:F6:4D:E6:6E:EE:F7:C4 +A0:00:00:00:04 02 000000 rsa 03 A9:9A:6D:3E:07:18:89:ED:9E:3A:0C:39:1C:69:B0:B8:04:FC:16:0B:2B:4B:DD:57:0C:92:DD:5A:0F:45:F5:3E:86:21:F7:C9:6C:40:22:42:66:73:5E:1E:E1:B3:C0:62:38:AE:35:04:63:20:FD:8E:81:F8:CE:B3:F8:B4:C9:7B:94:09:30:A3:AC:5E:79:00:86:DA:D4:1A:6A:4F:51:17:BA:1C:E2:43:8A:51:AC:05:3E:B0:02:AE:D8:66:D2:C4:58:FD:73:35:90:21:A1:20:29:A0:C0:43:04:5C:11:66:4F:E0:21:9E:C6:3C:10:BF:21:55:BB:27:84:60:9A:10:64:21:D4:51:63:79:97:38:C1:C3:09:09:BB:6C:6F:E5:2B:BB:76:39:7B:97:40:CE:06:4A:61:3F:F8:41:11:85:F0:88:42:A4:23:EA:D2:0E:DF:FB:FF:1C:D6:C3:FE:0C:98:21:47:91:99:C2:6D:85:72:CC:8A:FF:F0:87:A9:C3 sha1 33:40:8B:96:C8:14:74:2A:D7:35:36:C7:2F:09:26:E4:47:1E:8E:47 +A0:00:00:00:04 02 091231 rsa 03 CF:42:64:E1:70:2D:34:CA:89:7D:1F:9B:66:C5:D6:36:91:EA:CC:61:2C:8F:14:71:16:BB:22:D0:C4:63:49:5B:D5:BA:70:FB:15:38:48:89:52:20:B8:AD:EE:C3:E7:BA:B3:1E:A2:2C:1D:C9:97:2F:A0:27:D5:42:65:BE:BF:0A:E3:A2:3A:8A:09:18:7F:21:C8:56:60:7B:98:BD:A6:FC:90:81:16:81:6C:50:2B:3E:58:A1:45:25:4E:EF:EE:2A:33:35:11:02:24:02:8B:67:80:9D:CB:80:58:E2:48:95 sha1 AF:1C:C1:FD:1C:1B:C9:BC:A0:7E:78:DA:6C:BA:21:63:F1:69:CB:B7 +A0:00:00:00:04 03 091231 rsa 03 C2:49:07:47:FE:17:EB:05:84:C8:8D:47:B1:60:27:04:15:0A:DC:88:C5:B9:98:BD:59:CE:04:3E:DE:BF:0F:FE:E3:09:3A:C7:95:6A:D3:B6:AD:45:54:C6:DE:19:A1:78:D6:DA:29:5B:E1:5D:52:20:64:5E:3C:81:31:66:6F:A4:BE:5B:84:FE:13:1E:A4:4B:03:93:07:63:8B:9E:74:A8:C4:25:64:F8:92:A6:4D:F1:CB:15:71:2B:73:6E:33:74:F1:BB:B6:81:93:71:60:2D:89:70:E9:7B:90:07:93:C7:C2:A8:9A:4A:16:49:A5:9B:E6:80:57:4D:D0:B6:01:45 sha1 5A:DD:F2:1D:09:27:86:61:14:11:79:CB:EF:F2:72:EA:38:4B:13:BB +A0:00:00:00:04 04 171231 rsa 03 A6:DA:42:83:87:A5:02:D7:DD:FB:7A:74:D3:F4:12:BE:76:26:27:19:7B:25:43:5B:7A:81:71:6A:70:01:57:DD:D0:6F:7C:C9:9D:6C:A2:8C:24:70:52:7E:2C:03:61:6B:9C:59:21:73:57:C2:67:4F:58:3B:3B:A5:C7:DC:F2:83:86:92:D0:23:E3:56:24:20:B4:61:5C:43:9C:A9:7C:44:DC:9A:24:9C:FC:E7:B3:BF:B2:2F:68:22:8C:3A:F1:33:29:AA:4A:61:3C:F8:DD:85:35:02:37:3D:62:E4:9A:B2:56:D2:BC:17:12:0E:54:AE:DC:ED:6D:96:A4:28:7A:CC:5C:04:67:7D:4A:5A:32:0D:B8:BE:E2:F7:75:E5:FE:C5 sha1 38:1A:03:5D:A5:8B:48:2E:E2:AF:75:F4:C3:F2:CA:46:9B:A4:AA:6C +A0:00:00:00:04 05 000000 rsa 03 A1:F5:E1:C9:BD:86:50:BD:43:AB:6E:E5:6B:89:1E:F7:45:9C:0A:24:FA:84:F9:12:7D:1A:6C:79:D4:93:0F:6D:B1:85:2E:25:10:F1:8B:61:CD:35:4D:B8:3A:35:6B:D1:90:B8:8A:B8:DF:04:28:4D:02:A4:20:4A:7B:6C:B7:C5:55:19:77:A9:B3:63:79:CA:3D:E1:A0:8E:69:F3:01:C9:5C:C1:C2:05:06:95:92:75:F4:17:23:DD:5D:29:25:29:05:79:E5:A9:5B:0D:F6:32:3F:C8:E9:27:3D:6F:84:91:98:C4:99:62:09:16:6D:9B:FC:97:3C:36:1C:C8:26:E1 sha1 53:D0:49:03:B4:96:F5:95:44:A8:43:09:AF:16:92:51:F2:89:68:74 +A0:00:00:00:04 05 241231 rsa 03 B8:04:8A:BC:30:C9:0D:97:63:36:54:3E:3F:D7:09:1C:8F:E4:80:0D:F8:20:ED:55:E7:E9:48:13:ED:00:55:5B:57:3F:EC:A3:D8:4A:F6:13:1A:65:1D:66:CF:F4:28:4F:B1:3B:63:5E:DD:0E:E4:01:76:D8:BF:04:B7:FD:1C:7B:AC:F9:AC:73:27:DF:AA:8A:A7:2D:10:DB:3B:8E:70:B2:DD:D8:11:CB:41:96:52:5E:A3:86:AC:C3:3C:0D:9D:45:75:91:64:69:C4:E4:F5:3E:8E:1C:91:2C:C6:18:CB:22:DD:E7:C3:56:8E:90:02:2E:6B:BA:77:02:02:E4:52:2A:2D:D6:23:D1:80:E2:15:BD:1D:15:07:FE:3D:C9:0C:A3:10:D2:7B:3E:FC:CD:8F:83:DE:30:52:CA:D1:E4:89:38:C6:8D:09:5A:AC:91:B5:F3:7E:28:BB:49:EC:7E:D5:97 sha1 EB:FA:0D:5D:06:D8:CE:70:2D:A3:EA:E8:90:70:1D:45:E2:74:C8:45 +A0:00:00:00:04 06 281231 rsa 03 CB:26:FC:83:0B:43:78:5B:2B:CE:37:C8:1E:D3:34:62:2F:96:22:F4:C8:9A:AE:64:10:46:B2:35:34:33:88:3F:30:7F:B7:C9:74:16:2D:A7:2F:7A:4E:C7:5D:9D:65:73:36:86:5B:8D:30:23:D3:D6:45:66:76:25:C9:A0:7A:6B:7A:13:7C:F0:C6:41:98:AE:38:FC:23:80:06:FB:26:03:F4:1F:4F:3B:B9:DA:13:47:27:0F:2F:5D:8C:60:6E:42:09:58:C5:F7:D5:0A:71:DE:30:14:2F:70:DE:46:88:89:B5:E3:A0:86:95:B9:38:A5:0F:C9:80:39:3A:9C:BC:E4:4A:D2:D6:4F:63:0B:B3:3A:D3:F5:F5:FD:49:5D:31:F3:78:18:C1:D9:40:71:34:2E:07:F1:BE:C2:19:4F:60:35:BA:5D:ED:39:36:50:0E:B8:2D:FD:A6:E8:AF:B6:55:B1:EF:3D:0D:7E:BF:86:B6:6D:D9:F2:9F:6B:1D:32:4F:E8:B2:6C:E3:8A:B2:01:3D:D1:3F:61:1E:7A:59:4D:67:5C:44:32:35:0E:A2:44:CC:34:F3:87:3C:BA:06:59:29:87:A1:D7:E8:52:AD:C2:2E:F5:A2:EE:28:13:20:31:E4:8F:74:03:7E:3B:34:AB:74:7F sha1 F9:10:A1:50:4D:5F:FB:79:3D:94:F3:B5:00:76:5E:1A:BC:AD:72:D9 +A0:00:00:00:04 06 000000 rsa 03 D2:4C:24:D2:D7:FB:55:09:D5:B2:6E:BD:40:77:CE:74:51:6A:2B:89:E4:06:2D:83:DC:1F:7E:27:D5:E5:AA:66:57:F3:76:DA:BD:DB:6B:42:51:F3:23:42:6E:62:1F:5D:FC:1D:FA:07:C0:60:35:90:8B:7E:DF:67:4C:BE:B5:98:F5:9F:9C:CB:5C:55:41:05:21:C1:59:5E:7B:D8:6A:D7:1C:42:C3:28:FC:D9:D8:2C:9D:D6:8D:F1:E6:D3:F1:89:C3:2F:57:8B:7E:34:87:E8:4D:64:2E:D2:DA:3F:68:9A:A1:88:C2:A1:F3:7E:13:95:73:2E:18:72:95:4F:FE:B1:9D:5C:40:45:15:E7:C3:F6:37:E4:B9:E0:F8:89:88:7C:0C:43:19:49:42:B3:A9:2D:43:B0:AB:09:1C:55:10:FB:3C:24:A1:26:47:64:CB:EE:BA:FE:C0:AA:CC:A6:F9:48:FC:97:3C:89:50:DF:93:41:40:B7:DF:87:E7:71:93:B9:54:19:3E:B3:B7:5E:60:BB:B8:17:C4:FE:EA:A5:42:CE:38:87:82:88:5B:84:60:C4:C9:44:29:37:EC:FD:B8:08:FD:8B:89:79:E5:36:8E:B8:59:C9:06:8D:3D:0E:A9:16:78:D6:3B:C0:2C:87:B8:9D:B3:EB:E6:CF:1D:8F:6B:E6 sha1 7A:B3:72:2A:CE:9C:19:AC:D5:9E:DC:8B:F2:A4:84:7B:B2:4A:65:82 +A0:00:00:00:04 09 000000 rsa 03 96:7B:62:64:43:6C:96:AA:93:05:77:6A:59:19:C7:0D:A7:96:34:0F:99:97:A6:C6:EF:7B:EF:1D:4D:BF:9C:B4:28:9F:B7:99:0A:BF:F1:F3:AE:69:2F:12:84:4B:24:52:A5:0A:E0:75:FB:32:79:76:A4:0E:80:28:F2:79:B1:E3:CC:B6:23:95:7D:69:6F:C1:22:5C:A2:EC:95:0E:2D:41:5E:9A:A9:31:FF:18:B1:31:68:D6:61:FB:D0:6F:0A:BB sha1 1D:90:59:5C:2E:F9:FC:6E:71:B0:C7:21:11:83:33:DF:8A:71:FE:21 +A0:00:00:00:04 22 000000 rsa 03 BB:E4:38:77:CC:28:C0:CE:1E:14:BC:14:E8:47:73:17:E2:18:36:45:31:D1:55:BB:8A:C5:B6:3C:0D:6E:28:4D:D2:42:59:19:38:99:F9:C0:4C:30:BA:F1:67:D5:79:29:45:1F:67:AE:BD:3B:BD:0D:41:44:45:01:84:7D:8F:02:F2:C2:A2:D1:48:17:D9:7A:E2:62:5D:C1:63:BF:8B:48:4C:40:FF:B5:17:49:CE:DD:E9:43:4F:B2:A0:A4:10:99 sha1 00:8C:39:B1:D1:19:49:82:68:B0:78:43:34:94:27:AC:6E:98:F8:07 +A0:00:00:00:04 52 000000 rsa 01:00:01 B8:31:41:4E:0B:46:13:92:2B:D3:5B:4B:36:80:2B:C1:E1:E8:1C:95:A2:7C:95:8F:53:82:00:3D:F6:46:15:4C:A9:2F:C1:CE:02:C3:BE:04:7A:45:E9:B0:2A:90:89:B4:B9:02:78:23:7C:96:51:92:A0:FC:C8:6B:B4:9B:C8:2A:E6:FD:C2:DE:70:90:06:B8:6C:76:76:EF:DF:59:76:26:FA:D6:33:A4:F7:DC:48:C4:45:D3:7E:B5:5F:CB:3B:1A:BB:95:BA:AA:82:6D:53:90:E1:5F:D1:4E:D4:03:FA:2D:0C:B8:41:C6:50:60:95:24:EC:55:5E:3B:C5:6C:A9:57 sha1 DE:B8:1E:DB:26:26:A4:BB:6A:E2:3B:77:D1:9A:77:53:9D:0E:67:16 +A0:00:00:00:04 EF 000000 rsa 03 A1:91:CB:87:47:3F:29:34:9B:5D:60:A8:8B:3E:AE:E0:97:3A:A6:F1:A0:82:F3:58:D8:49:FD:DF:F9:C0:91:F8:99:ED:A9:79:2C:AF:09:EF:28:F5:D2:24:04:B8:8A:22:93:EE:BB:C1:94:9C:43:BE:A4:D6:0C:FD:87:9A:15:39:54:4E:09:E0:F0:9F:60:F0:65:B2:BF:2A:13:EC:C7:05:F3:D4:68:B9:D3:3A:E7:7A:D9:D3:F1:9C:A4:0F:23:DC:F5:EB:7C:04:DC:8F:69:EB:A5:65:B1:EB:CB:46:86:CD:27:47:85:53:0F:F6:F6:E9:EE:43:AA:43:FD:B0:2C:E0:0D:AE:C1:5C:7B:8F:D6:A9:B3:94:BA:BA:41:9D:3F:6D:C8:5E:16:56:9B:E8:E7:69:89:68:8E:FE:A2:DF:22:FF:7D:35:C0:43:33:8D:EA:A9:82:A0:2B:86:6D:E5:32:85:19:EB:BC:D6:F0:3C:DD:68:66:73:84:7F:84:DB:65:1A:B8:6C:28:CF:14:62:56:2C:57:7B:85:35:64:A2:90:C8:55:6D:81:85:31:26:8D:25:CC:98:A4:CC:6A:0B:DF:FF:DA:2D:CC:A3:A9:4C:99:85:59:E3:07:FD:DF:91:50:06:D9:A9:87:B0:7D:DA:EB:3B sha1 21:76:6E:BB:0E:E1:22:AF:B6:5D:78:45:B7:3D:B4:6B:AB:65:42:7A +A0:00:00:00:04 F0 000000 rsa 03 75:63:C5:1B:52:76:AA:63:70:AB:84:05:52:24:14:64:58:32:B6:BE:F2:A9:89:C7:71:47:5B:2E:8D:C6:54:DC:8A:5B:FF:9E:28:E3:1F:F1:A3:70:A4:0D:C3:FF:EB:06:BC:85:48:7D:5F:1C:B6:1C:24:41:FD:71:CB:CD:05:D8:83:F8:DE:41:3B:24:3A:FC:9D:CA:76:8B:06:1E:35:B8:84:B5:D2:1B:6B:01:6A:A3:6B:A1:2D:AB:CF:E4:9F:8E:52:8C:89:3C:34:C7:D4:79:39:77:E4:CC:99:AB:09:64:0D:9C:7A:AB:7E:C5:FF:3F:40:E3:D4:D1:8D:F7:E3:A7 sha1 AE:66:74:45:F8:DE:6F:82:C3:88:00:E5:EB:AB:A3:22:F0:3F:58:F2 +A0:00:00:00:04 F1 000000 rsa 03 A0:DC:F4:BD:E1:9C:35:46:B4:B6:F0:41:4D:17:4D:DE:29:4A:AB:BB:82:8C:5A:83:4D:73:AA:E2:7C:99:B0:B0:53:A9:02:78:00:72:39:B6:45:9F:F0:BB:CD:7B:4B:9C:6C:50:AC:02:CE:91:36:8D:A1:BD:21:AA:EA:DB:C6:53:47:33:7D:89:B6:8F:5C:99:A0:9D:05:BE:02:DD:1F:8C:5B:A2:0E:2F:13:FB:2A:27:C4:1D:3F:85:CA:D5:CF:66:68:E7:58:51:EC:66:ED:BF:98:85:1F:D4:E4:2C:44:C1:D5:9F:59:84:70:3B:27:D5:B9:F2:1B:8F:A0:D9:32:79:FB:BF:69:E0:90:64:29:09:C9:EA:27:F8:98:95:95:41:AA:67:57:F5:F6:24:10:4F:6E:1D:3A:95:32:F2:A6:E5:15:15:AE:AD:1B:43:B3:D7:83:50:88:A2:FA:FA:7B:E7 sha1 D8:E6:8D:A1:67:AB:5A:85:D8:C3:D5:5E:CB:9B:05:17:A1:A5:B4:BB +A0:00:00:00:04 F3 000000 rsa 03 98:F0:C7:70:F2:38:64:C2:E7:66:DF:02:D1:E8:33:DF:F4:FF:E9:2D:69:6E:16:42:F0:A8:8C:56:94:C6:47:9D:16:DB:15:37:BF:E2:9E:4F:DC:6E:6E:8A:FD:1B:0E:B7:EA:01:24:72:3C:33:31:79:BF:19:E9:3F:10:65:8B:2F:77:6E:82:9E:87:DA:ED:A9:C9:4A:8B:33:82:19:9A:35:0C:07:79:77:C9:7A:FF:08:FD:11:31:0A:C9:50:A7:2C:3C:A5:00:2E:F5:13:FC:CC:28:6E:64:6E:3C:53:87:53:5D:50:95:14:B3:B3:26:E1:23:4F:9C:B4:8C:36:DD:D4:4B:41:6D:23:65:40:34:A6:6F:40:3B:A5:11:C5:EF:A3 sha1 A6:9A:C7:60:3D:AF:56:6E:97:2D:ED:C2:CB:43:3E:07:E8:B0:1A:9A +A0:00:00:00:04 F5 000000 rsa 01:00:01 A6:E6:FB:72:17:95:06:F8:60:CC:CA:8C:27:F9:9C:EC:D9:4C:7D:4F:31:91:D3:03:BB:EE:37:48:1C:7A:A1:5F:23:3B:A7:55:E9:E4:37:63:45:A9:A6:7E:79:94:BD:C1:C6:80:BB:35:22:D8:C9:3E:B0:CC:C9:1A:D3:1A:D4:50:DA:30:D3:37:66:2D:19:AC:03:E2:B4:EF:5F:6E:C1:82:82:D4:91:E1:97:67:D7:B2:45:42:DF:DE:FF:6F:62:18:55:03:53:20:69:BB:B3:69:E3:BB:9F:B1:9A:C6:F1:C3:0B:97:D2:49:EE:E7:64:E0:BA:C9:7F:25:C8:73:D9:73:95:3E:51:53:A4:20:64:BB:FA:BF:D0:6A:4B:B4:86:86:0B:F6:63:74:06:C9:FC:36:81:3A:4A:75:F7:5C:31:CC:A9:F6:9F:8D:E5:9A:DE:CE:F6:BD:E7:E0:78:00:FC:BE:03:5D:31:76:AF:84:73:E2:3E:9A:A3:DF:EE:22:11:96:D1:14:83:02:67:7C:72:0C:FE:25:44:A0:3D:B5:53:E7:F1:B8:42:7B:A1:CC:72:B0:F2:9B:12:DF:EF:4C:08:1D:07:6D:35:3E:71:88:0A:AD:FF:38:63:52:AF:0A:B7:B2:8E:D4:9E:1E:67:2D:11:F9 sha1 C2:23:98:04:C8:09:81:70:BE:52:D6:D5:D4:15:9E:81:CE:84:66:BF +A0:00:00:00:04 F6 000000 rsa 03 A2:5A:6B:D7:83:A5:EF:6B:8F:B6:F8:30:55:C2:60:F5:F9:9E:A1:66:78:F3:B9:05:3E:0F:64:98:E8:2C:3F:5D:1E:8C:38:F1:35:88:01:7E:2B:12:B3:D8:FF:6F:50:16:7F:46:44:29:10:72:9E:9E:4D:1B:37:39:E5:06:7C:0A:C7:A1:F4:48:7E:35:F6:75:BC:16:E2:33:31:51:65:CB:14:2B:FD:B2:5E:30:1A:63:2A:54:A3:37:1E:BA:B6:57:2D:EE:BA:F3:70:F3:37:F0:57:EE:73:B4:AE:46:D1:A8:BC:4D:A8:53:EC:3C:C1:2C:8C:BC:2D:A1:83:22:D6:85:30:C7:0B:22:BD:AC:35:1D:D3:60:68:AE:32:1E:11:AB:F2:64:F4:D3:56:9B:B7:12:14:54:50:05:55:8D:E2:60:83:C7:35:DB:77:63:68:17:2F:E8:C2:F5:C8:5E:8B:5B:89:0C:C6:82:91:1D:2D:E7:1F:A6:26:B8:81:7F:CC:C0:89:22:B7:03:86:9F:3B:AE:AC:14:59:D7:7C:D8:53:76:BC:36:18:2F:42:38:31:4D:6C:42:12:FB:DD:7F:23:D3 sha1 50:29:09:ED:54:5E:3C:8D:BD:00:EA:58:2D:06:17:FE:E9:F6:F6:84 +A0:00:00:00:04 F7 000000 rsa 01:00:01 94:EA:62:F6:D5:83:20:E3:54:C0:22:AD:DC:F0:55:9D:8C:F2:06:CD:92:E8:69:56:49:05:CE:21:D7:20:F9:71:B7:AE:A3:74:83:0E:BE:17:57:11:5A:85:E0:88:D4:1C:6B:77:CF:5E:C8:21:F3:0B:1D:89:04:17:BF:2F:A3:1E:59:08:DE:D5:FA:67:7F:8C:7B:18:4A:D0:90:28:FD:DE:96:B6:A6:10:98:50:AA:80:01:75:EA:BC:DB:BB:68:4A:96:C2:EB:63:79:DF:EA:08:D3:2F:E2:33:1F:E1:03:23:3A:D5:8D:CD:B1:E6:E0:77:CB:9F:24:EA:EC:5C:25:AF sha1 EE:B0:DD:9B:24:77:BE:E3:20:9A:91:4C:DB:A9:4C:1C:4A:9B:DE:D9 +A0:00:00:00:04 F8 000000 rsa 03 A1:F5:E1:C9:BD:86:50:BD:43:AB:6E:E5:6B:89:1E:F7:45:9C:0A:24:FA:84:F9:12:7D:1A:6C:79:D4:93:0F:6D:B1:85:2E:25:10:F1:8B:61:CD:35:4D:B8:3A:35:6B:D1:90:B8:8A:B8:DF:04:28:4D:02:A4:20:4A:7B:6C:B7:C5:55:19:77:A9:B3:63:79:CA:3D:E1:A0:8E:69:F3:01:C9:5C:C1:C2:05:06:95:92:75:F4:17:23:DD:5D:29:25:29:05:79:E5:A9:5B:0D:F6:32:3F:C8:E9:27:3D:6F:84:91:98:C4:99:62:09:16:6D:9B:FC:97:3C:36:1C:C8:26:E1 sha1 F0:6E:CC:6D:2A:AE:BF:25:9B:7E:75:5A:38:D9:A9:B2:4E:2F:F3:DD +A0:00:00:00:04 F9 000000 rsa 03 A9:9A:6D:3E:07:18:89:ED:9E:3A:0C:39:1C:69:B0:B8:04:FC:16:0B:2B:4B:DD:57:0C:92:DD:5A:0F:45:F5:3E:86:21:F7:C9:6C:40:22:42:66:73:5E:1E:E1:B3:C0:62:38:AE:35:04:63:20:FD:8E:81:F8:CE:B3:F8:B4:C9:7B:94:09:30:A3:AC:5E:79:00:86:DA:D4:1A:6A:4F:51:17:BA:1C:E2:43:8A:51:AC:05:3E:B0:02:AE:D8:66:D2:C4:58:FD:73:35:90:21:A1:20:29:A0:C0:43:04:5C:11:66:4F:E0:21:9E:C6:3C:10:BF:21:55:BB:27:84:60:9A:10:64:21:D4:51:63:79:97:38:C1:C3:09:09:BB:6C:6F:E5:2B:BB:76:39:7B:97:40:CE:06:4A:61:3F:F8:41:11:85:F0:88:42:A4:23:EA:D2:0E:DF:FB:FF:1C:D6:C3:FE:0C:98:21:47:91:99:C2:6D:85:72:CC:8A:FF:F0:87:A9:C3 sha1 33:67:12:DC:C2:85:54:80:9C:6A:A9:B0:23:58:DE:6F:75:51:64:DB +A0:00:00:00:04 FA 000000 rsa 03 9C:6B:E5:AD:B1:0B:4B:E3:DC:E2:09:9B:4B:21:06:72:B8:96:56:EB:A0:91:20:4F:61:3E:CC:62:3B:ED:C9:C6:D7:7B:66:0E:8B:AE:EA:7F:7C:E3:0F:1B:15:38:79:A4:E3:64:59:34:3D:1F:E4:7A:CD:BD:41:FC:D7:10:03:0C:2B:A1:D9:46:15:97:98:2C:6E:1B:DD:08:55:4B:72:6F:5E:FF:79:13:CE:59:E7:9E:35:72:95:C3:21:E2:6D:0B:8B:E2:70:A9:44:23:45:C7:53:E2:AA:2A:CF:C9:D3:08:50:60:2F:E6:CA:C0:0C:6D:DF:6B:8D:9D:9B:48:79:B2:82:6B:04:2A:07:F0:E5:AE:52:6A:3D:3C:4D:22:C7:2B:9E:AA:52:EE:D8:89:38:66:F8:66:38:7A:C0:5A:13:99 sha1 0A:BC:AD:AD:2C:75:58:CA:9C:70:81:AE:55:DD:DC:71:4F:8D:45:F8 +A0:00:00:00:04 FA 000000 rsa 03 A9:0F:CD:55:AA:2D:5D:99:63:E3:5E:D0:F4:40:17:76:99:83:2F:49:C6:BA:B1:5C:DA:E5:79:4B:E9:3F:93:4D:44:62:D5:D1:27:62:E4:8C:38:BA:83:D8:44:5D:EA:A7:41:95:A3:01:A1:02:B2:F1:14:EA:DA:0D:18:0E:E5:E7:A5:C7:3E:0C:4E:11:F6:7A:43:DD:AB:5D:55:68:3B:14:74:CC:06:27:F4:4B:8D:30:88:A4:92:FF:AA:DA:D4:F4:24:22:D0:E7:01:35:36:C3:C4:9A:D3:D0:FA:E9:64:59:B0:F6:B1:B6:05:65:38:A3:D6:D4:46:40:F9:44:67:B1:08:86:7D:EC:40:FA:AE:CD:74:0C:00:E2:B7:A8:85:2D sha1 5B:ED:40:68:D9:6E:A1:6D:2D:77:E0:3D:60:36:FC:7A:16:0E:A9:9C +A0:00:00:00:04 FB 000000 rsa 02 A9:54:8D:FB:39:8B:48:12:3F:AF:41:E6:CF:A4:AE:1E:23:52:B5:18:AB:4B:CE:FE:CD:B0:B3:ED:EC:09:02:87:D8:8B:12:25:9F:36:1C:1C:C0:88:E5:F0:66:49:44:17:E8:EE:8B:BF:89:91:E2:B3:2F:F1:6F:99:46:97:84:2B:3D:6C:B3:7A:2B:B5:74:2A:44:0B:63:56:C6:2A:A3:3D:B3:C4:55:E5:9E:DD:F7:86:47:01:D0:3A:5B:83:EE:9E:9B:D8:3A:B9:33:02:AC:2D:FE:63:E6:61:20:B0:51:CF:08:1F:56:32:6A:71:30:3D:95:2B:B3:36:FF:12:61:0D sha1 6C:72:89:63:29:19:AB:EE:6E:11:63:D7:E6:BF:69:3F:D8:8E:BD:35 +A0:00:00:00:04 FC 000000 rsa 02 B3:7B:FD:2A:96:74:AD:62:21:C1:A0:01:08:1C:62:65:3D:C2:80:B0:A9:BD:05:2C:67:7C:91:3C:E7:A0:D9:02:E7:7B:12:F4:D4:D7:90:37:B1:E9:B9:23:A8:BB:3F:AC:3C:61:20:45:BB:39:14:F8:DF:41:E9:A1:B6:1B:FA:5B:41:70:5A:69:1D:09:CE:6F:53:0F:E4:8B:30:24:0D:98:F4:E6:92:FF:D6:AA:DB:87:24:3B:A8:59:7A:B2:37:58:6E:CF:25:8F:41:48:75:1B:E5:DA:5A:3B:E6:CC:34:BD sha1 7F:B3:77:EE:BB:CF:7E:3A:6D:04:01:5D:10:E1:BD:CB:15:E2:1B:80 +A0:00:00:00:04 FD 000000 rsa 02 B3:57:2B:A4:9A:E4:C7:B7:A0:01:9E:51:89:E1:42:CF:CD:ED:94:98:DD:B5:F0:47:05:67:AB:0B:A7:13:B8:DA:22:64:24:62:29:55:B5:4B:93:7A:BF:EF:AA:D9:79:19:E3:77:62:1E:22:19:6A:BC:14:19:D5:AD:C1:23:48:42:09:EA:7C:B7:02:9E:66:A0:D5:4C:5B:45:C8:AD:61:5A:ED:B6:AE:9E:0A:2F:75:31:0E:A8:96:12:87:24:12:45 sha1 23:CF:0D:70:2E:0A:EF:E5:18:E4:FA:6B:83:6D:3C:D4:5B:8A:AA:71 +A0:00:00:00:04 FE 000000 rsa 03 A6:53:EA:C1:C0:F7:86:C8:72:4F:73:7F:17:29:97:D6:3D:1C:32:51:C4:44:02:04:9B:86:5B:AE:87:7D:0F:39:8C:BF:BE:8A:60:35:E2:4A:FA:08:6B:EF:DE:93:51:E5:4B:95:70:8E:E6:72:F0:96:8B:CD:50:DC:E4:0F:78:33:22:B2:AB:A0:4E:F1:37:EF:18:AB:F0:3C:7D:BC:58:13:AE:AE:F3:AA:77:97:BA:15:DF:7D:5B:A1:CB:AF:7F:D5:20:B5:A4:82:D8:D3:FE:E1:05:07:78:71:11:3E:23:A4:9A:F3:92:65:54:A7:0F:E1:0E:D7:28:CF:79:3B:62:A1 sha1 9A:29:5B:05:FB:39:0E:F7:92:3F:57:61:8A:9F:DA:29:41:FC:34:E0 +A0:00:00:00:04 FF 000000 rsa 03 B8:55:CC:64:31:3A:F9:9C:45:3D:18:16:42:EE:7D:D2:1A:67:D0:FF:50:C6:1F:E2:13:BC:DC:18:AF:BC:D0:77:22:EF:DD:25:94:EF:DC:22:7D:A3:DA:23:AD:CC:90:E3:FA:90:74:53:AC:C9:54:C4:73:23:BE:DC:F8:D4:86:2C:45:7D:25:F4:7B:16:D7:C3:50:2B:E0:81:91:3E:5B:04:82:D8:38:48:40:65:DA:5F:66:59:E0:0A:9E:5D:57:0A:DA:1E:C6:AF:8C:57:96:00:75:11:95:81:FC:81:46:8D sha1 B4:E7:69:CE:CF:7A:AC:47:83:F3:05:E0:B1:10:60:2A:07:A6:35:5B +B0:12:34:56:78 00 000000 rsa 03 9C:6B:E5:AD:B1:0B:4B:E3:DC:E2:09:9B:4B:21:06:72:B8:96:56:EB:A0:91:20:4F:61:3E:CC:62:3B:ED:C9:C6:D7:7B:66:0E:8B:AE:EA:7F:7C:E3:0F:1B:15:38:79:A4:E3:64:59:34:3D:1F:E4:7A:CD:BD:41:FC:D7:10:03:0C:2B:A1:D9:46:15:97:98:2C:6E:1B:DD:08:55:4B:72:6F:5E:FF:79:13:CE:59:E7:9E:35:72:95:C3:21:E2:6D:0B:8B:E2:70:A9:44:23:45:C7:53:E2:AA:2A:CF:C9:D3:08:50:60:2F:E6:CA:C0:0C:6D:DF:6B:8D:9D:9B:48:79:B2:82:6B:04:2A:07:F0:E5:AE:52:6A:3D:3C:4D:22:C7:2B:9E:AA:52:EE:D8:89:38:66:F8:66:38:7A:C0:5A:13:99 sha1 5D:29:70:E6:46:75:72:7E:60:46:07:65:A8:DB:75:34:2A:E1:47:83 +B0:12:34:56:78 02 000000 rsa 03 A9:9A:6D:3E:07:18:89:ED:9E:3A:0C:39:1C:69:B0:B8:04:FC:16:0B:2B:4B:DD:57:0C:92:DD:5A:0F:45:F5:3E:86:21:F7:C9:6C:40:22:42:66:73:5E:1E:E1:B3:C0:62:38:AE:35:04:63:20:FD:8E:81:F8:CE:B3:F8:B4:C9:7B:94:09:30:A3:AC:5E:79:00:86:DA:D4:1A:6A:4F:51:17:BA:1C:E2:43:8A:51:AC:05:3E:B0:02:AE:D8:66:D2:C4:58:FD:73:35:90:21:A1:20:29:A0:C0:43:04:5C:11:66:4F:E0:21:9E:C6:3C:10:BF:21:55:BB:27:84:60:9A:10:64:21:D4:51:63:79:97:38:C1:C3:09:09:BB:6C:6F:E5:2B:BB:76:39:7B:97:40:CE:06:4A:61:3F:F8:41:11:85:F0:88:42:A4:23:EA:D2:0E:DF:FB:FF:1C:D6:C3:FE:0C:98:21:47:91:99:C2:6D:85:72:CC:8A:FF:F0:87:A9:C3 sha1 29:4B:E2:02:39:AB:15:24:5A:63:BE:A4:6C:C6:C1:75:A2:55:62:D1 +B0:12:34:56:78 05 000000 rsa 03 A1:F5:E1:C9:BD:86:50:BD:43:AB:6E:E5:6B:89:1E:F7:45:9C:0A:24:FA:84:F9:12:7D:1A:6C:79:D4:93:0F:6D:B1:85:2E:25:10:F1:8B:61:CD:35:4D:B8:3A:35:6B:D1:90:B8:8A:B8:DF:04:28:4D:02:A4:20:4A:7B:6C:B7:C5:55:19:77:A9:B3:63:79:CA:3D:E1:A0:8E:69:F3:01:C9:5C:C1:C2:05:06:95:92:75:F4:17:23:DD:5D:29:25:29:05:79:E5:A9:5B:0D:F6:32:3F:C8:E9:27:3D:6F:84:91:98:C4:99:62:09:16:6D:9B:FC:97:3C:36:1C:C8:26:E1 sha1 B9:A1:D6:5C:AF:E0:6B:05:4E:DD:7E:A8:25:97:AB:85:F1:30:E6:63 +B0:12:34:56:78 F3 000000 rsa 01:00:01 94:EA:62:F6:D5:83:20:E3:54:C0:22:AD:DC:F0:55:9D:8C:F2:06:CD:92:E8:69:56:49:05:CE:21:D7:20:F9:71:B7:AE:A3:74:83:0E:BE:17:57:11:5A:85:E0:88:D4:1C:6B:77:CF:5E:C8:21:F3:0B:1D:89:04:17:BF:2F:A3:1E:59:08:DE:D5:FA:67:7F:8C:7B:18:4A:D0:90:28:FD:DE:96:B6:A6:10:98:50:AA:80:01:75:EA:BC:DB:BB:68:4A:96:C2:EB:63:79:DF:EA:08:D3:2F:E2:33:1F:E1:03:23:3A:D5:8D:CD:B1:E6:E0:77:CB:9F:24:EA:EC:5C:25:AF sha1 56:94:B0:D2:78:48:18:14:A0:5E:12:B5:58:CE:C1:23:48:65:AA:5D +B0:12:34:56:78 F3 000000 rsa 03 98:F0:C7:70:F2:38:64:C2:E7:66:DF:02:D1:E8:33:DF:F4:FF:E9:2D:69:6E:16:42:F0:A8:8C:56:94:C6:47:9D:16:DB:15:37:BF:E2:9E:4F:DC:6E:6E:8A:FD:1B:0E:B7:EA:01:24:72:3C:33:31:79:BF:19:E9:3F:10:65:8B:2F:77:6E:82:9E:87:DA:ED:A9:C9:4A:8B:33:82:19:9A:35:0C:07:79:77:C9:7A:FF:08:FD:11:31:0A:C9:50:A7:2C:3C:A5:00:2E:F5:13:FC:CC:28:6E:64:6E:3C:53:87:53:5D:50:95:14:B3:B3:26:E1:23:4F:9C:B4:8C:36:DD:D4:4B:41:6D:23:65:40:34:A6:6F:40:3B:A5:11:C5:EF:A3 sha1 13:AA:E8:50:31:78:05:D1:EA:97:45:3F:E3:60:57:C5:7D:D6:52:8B +B0:12:34:56:78 F5 000000 rsa 03 A2:5A:6B:D7:83:A5:EF:6B:8F:B6:F8:30:55:C2:60:F5:F9:9E:A1:66:78:F3:B9:05:3E:0F:64:98:E8:2C:3F:5D:1E:8C:38:F1:35:88:01:7E:2B:12:B3:D8:FF:6F:50:16:7F:46:44:29:10:72:9E:9E:4D:1B:37:39:E5:06:7C:0A:C7:A1:F4:48:7E:35:F6:75:BC:16:E2:33:31:51:65:CB:14:2B:FD:B2:5E:30:1A:63:2A:54:A3:37:1E:BA:B6:57:2D:EE:BA:F3:70:F3:37:F0:57:EE:73:B4:AE:46:D1:A8:BC:4D:A8:53:EC:3C:C1:2C:8C:BC:2D:A1:83:22:D6:85:30:C7:0B:22:BD:AC:35:1D:D3:60:68:AE:32:1E:11:AB:F2:64:F4:D3:56:9B:B7:12:14:54:50:05:55:8D:E2:60:83:C7:35:DB:77:63:68:17:2F:E8:C2:F5:C8:5E:8B:5B:89:0C:C6:82:91:1D:2D:E7:1F:A6:26:B8:81:7F:CC:C0:89:22:B7:03:86:9F:3B:AE:AC:14:59:D7:7C:D8:53:76:BC:36:18:2F:42:38:31:4D:6C:42:12:FB:DD:7F:23:D3 sha1 F7:5E:88:02:85:5C:9B:14:02:7E:51:73:45:71:7E:5C:36:35:B9:1B +B0:12:34:56:78 F6 000000 rsa 03 A1:F5:E1:C9:BD:86:50:BD:43:AB:6E:E5:6B:89:1E:F7:45:9C:0A:24:FA:84:F9:12:7D:1A:6C:79:D4:93:0F:6D:B1:85:2E:25:10:F1:8B:61:CD:35:4D:B8:3A:35:6B:D1:90:B8:8A:B8:DF:04:28:4D:02:A4:20:4A:7B:6C:B7:C5:55:19:77:A9:B3:63:79:CA:3D:E1:A0:8E:69:F3:01:C9:5C:C1:C2:05:06:95:92:75:F4:17:23:DD:5D:29:25:29:05:79:E5:A9:5B:0D:F6:32:3F:C8:E9:27:3D:6F:84:91:98:C4:99:62:09:16:6D:9B:FC:97:3C:36:1C:C8:26:E1 sha1 E9:40:6B:65:10:C1:43:AB:1E:9B:9D:79:A3:C1:DF:F8:90:9A:34:7C +B0:12:34:56:78 F7 000000 rsa 03 98:F0:C7:70:F2:38:64:C2:E7:66:DF:02:D1:E8:33:DF:F4:FF:E9:2D:69:6E:16:42:F0:A8:8C:56:94:C6:47:9D:16:DB:15:37:BF:E2:9E:4F:DC:6E:6E:8A:FD:1B:0E:B7:EA:01:24:72:3C:33:31:79:BF:19:E9:3F:10:65:8B:2F:77:6E:82:9E:87:DA:ED:A9:C9:4A:8B:33:82:19:9A:35:0C:07:79:77:C9:7A:FF:08:FD:11:31:0A:C9:50:A7:2C:3C:A5:00:2E:F5:13:FC:CC:28:6E:64:6E:3C:53:87:53:5D:50:95:14:B3:B3:26:E1:23:4F:9C:B4:8C:36:DD:D4:4B:41:6D:23:65:40:34:A6:6F:40:3B:A5:11:C5:EF:A3 sha1 F7:81:13:E8:60:F0:30:A8:72:92:3F:CE:93:E3:38:1C:77:A4:2A:30 +B0:12:34:56:78 F8 000000 rsa 03 A9:9A:6D:3E:07:18:89:ED:9E:3A:0C:39:1C:69:B0:B8:04:FC:16:0B:2B:4B:DD:57:0C:92:DD:5A:0F:45:F5:3E:86:21:F7:C9:6C:40:22:42:66:73:5E:1E:E1:B3:C0:62:38:AE:35:04:63:20:FD:8E:81:F8:CE:B3:F8:B4:C9:7B:94:09:30:A3:AC:5E:79:00:86:DA:D4:1A:6A:4F:51:17:BA:1C:E2:43:8A:51:AC:05:3E:B0:02:AE:D8:66:D2:C4:58:FD:73:35:90:21:A1:20:29:A0:C0:43:04:5C:11:66:4F:E0:21:9E:C6:3C:10:BF:21:55:BB:27:84:60:9A:10:64:21:D4:51:63:79:97:38:C1:C3:09:09:BB:6C:6F:E5:2B:BB:76:39:7B:97:40:CE:06:4A:61:3F:F8:41:11:85:F0:88:42:A4:23:EA:D2:0E:DF:FB:FF:1C:D6:C3:FE:0C:98:21:47:91:99:C2:6D:85:72:CC:8A:FF:F0:87:A9:C3 sha1 66:46:9C:88:E7:DC:11:15:29:C7:D3:79:D7:93:8C:8D:F3:E4:C2:5E +B0:12:34:56:78 F9 000000 rsa 01:00:01 A6:E6:FB:72:17:95:06:F8:60:CC:CA:8C:27:F9:9C:EC:D9:4C:7D:4F:31:91:D3:03:BB:EE:37:48:1C:7A:A1:5F:23:3B:A7:55:E9:E4:37:63:45:A9:A6:7E:79:94:BD:C1:C6:80:BB:35:22:D8:C9:3E:B0:CC:C9:1A:D3:1A:D4:50:DA:30:D3:37:66:2D:19:AC:03:E2:B4:EF:5F:6E:C1:82:82:D4:91:E1:97:67:D7:B2:45:42:DF:DE:FF:6F:62:18:55:03:53:20:69:BB:B3:69:E3:BB:9F:B1:9A:C6:F1:C3:0B:97:D2:49:EE:E7:64:E0:BA:C9:7F:25:C8:73:D9:73:95:3E:51:53:A4:20:64:BB:FA:BF:D0:6A:4B:B4:86:86:0B:F6:63:74:06:C9:FC:36:81:3A:4A:75:F7:5C:31:CC:A9:F6:9F:8D:E5:9A:DE:CE:F6:BD:E7:E0:78:00:FC:BE:03:5D:31:76:AF:84:73:E2:3E:9A:A3:DF:EE:22:11:96:D1:14:83:02:67:7C:72:0C:FE:25:44:A0:3D:B5:53:E7:F1:B8:42:7B:A1:CC:72:B0:F2:9B:12:DF:EF:4C:08:1D:07:6D:35:3E:71:88:0A:AD:FF:38:63:52:AF:0A:B7:B2:8E:D4:9E:1E:67:2D:11:F9 sha1 AE:AC:A4:54:80:C8:83:4C:B0:BE:BD:CC:57:0B:7B:2B:74:BB:4B:79 +50:16:49:FF:20 05 000000 rsa 03 B5:A5:8B:54:38:D3:B0:22:3B:BC:E4:D4:29:94:CA:9C:07:93:CA:1E:53:65:43:F9:E7:56:3B:99:B6:71:77:BB:90:0F:0A:BC:5B:BE:DF:31:2B:E4:0E:09:01:23:DE:F9:43:BC:32:1C:1C:2C:BE:F6:DB:21:EB:70:0A:D7:CF:CB:62:62:1C:C8:12:C9:F4:73:55:F2:E4:22:98:FB:9A:A3:F0:39:37:15:72:A7:FD:E8:2E:3D:E8:C2:EE:1A:31:1C:D3:48:F4:38:7A:DD:89:FA:FE:E3:69:77:32:6F:E5:86:EA:79:66:8A:50:8D:91:D3:A5:FB:9B:04:28:66:F1:7D sha1 AE:3A:EA:43:8C:A3:60:3E:A2:41:59:21:E0:DF:54:37:2F:EB:B6:9C +50:16:49:FF:20 07 000000 rsa 03 B1:C7:95:BB:8F:65:33:E9:12:D8:D5:20:AA:4F:E3:65:AE:92:A3:1A:57:BB:25:38:22:A8:12:64:E1:B8:CD:30:B0:53:37:FB:4A:09:10:EC:92:5E:DC:A4:94:12:98:99:74:21:D4:A5:7B:06:0C:A8:66:FC:EC:E3:46:91:C0:E8:AA:0F:4F:7C:CC:46:70:9F:7E:92:4D:87:66:8C:19:6F:31:33:38:87:8F:02:7A:F5:17:B6:67:38:62:44:21:0E:6A:20:0D:46:F3:BC:9C:72:11:93:07:5D:6F:64:F5:5D:57:03:C6:4A:73:46:DA:73:4C:84:DE:4E:B9:92:81:D5:B5:9C:D8:D6:53:5A:06:35:3D:FD:22:7A:3F:63:94:43 sha1 B6:B8:54:43:AE:B3:86:36:AC:80:AA:A2:55:0C:FF:22:79:15:13:8E +50:16:49:FF:20 23 000000 rsa 03 C3:7A:ED:39:CA:98:DA:84:6B:B7:DC:99:AA:E4:7F:A5:DA:64:75:4A:7B:65:62:82:48:B4:EA:A1:CF:6D:70:3C:D0:52:B8:99:4C:A2:AC:C7:6F:EA:2F:7A:15:20:75:8F:BA:74:4A:65:7F:45:8D:A8:6A:C9:EA:D3:78:C7:5F:62:0A:27:00:9E:A4:9F:B8:30:1D:69:70:7A:35:48:CA:45:5F:CB:16:55:C6:D2:30:CC:61:2C:2A:E8:27:7F:2D:FC:2E:10:32:78:C1:6A:DC:64:3E:DA:C5:23:40:2B:7E:47:9A:1A:3F:78:CC:98:26:A2:8F:5F:03:A6:B9:CD:BB:89:A7:F3:C8:B0:14:A3:6B:6D:20:54:C1:7E:20:2C:B4:E3 sha1 E1:00:72:3D:F6:12:5E:E0:40:9A:57:5B:E2:6E:0E:EC:1E:B8:1E:37 +A0:00:00:00:03 01 091231 rsa 03 C6:96:03:42:13:D7:D8:54:69:84:57:9D:1D:0F:0E:A5:19:CF:F8:DE:FF:C4:29:35:4C:F3:A8:71:A6:F7:18:3F:12:28:DA:5C:74:70:C0:55:38:71:00:CB:93:5A:71:2C:4E:28:64:DF:5D:64:BA:93:FE:7E:63:E7:1F:25:B1:E5:F5:29:85:75:EB:E1:C6:3A:A6:17:70:69:17:91:1D:C2:A7:5A:C2:8B:25:1C:7E:F4:0F:23:65:91:24:90:B9:39:BC:A2:12:4A:30:A2:8F:54:40:2C:34:AE:CA:33:1A:B6:7E:1E:79:B2:85:DD:57:71:B5:D9:FF:79:EA:63:0B:75 sha1 D3:4A:6A:77:60:11:C7:E7:CE:3A:EC:5F:03:AD:2F:8C:FC:55:03:CC +A0:00:00:00:03 03 000000 rsa 03 B3:E5:E6:67:50:6C:47:CA:AF:B1:2A:26:33:81:93:50:84:66:97:DD:65:A7:96:E5:CE:77:C5:7C:62:6A:66:F7:0B:B6:30:91:16:12:AD:28:32:90:9B:80:62:29:1B:EC:A4:6C:D3:3B:66:A6:F9:C9:D4:8C:ED:8B:4F:C8:56:1C:8A:1D:8F:B1:58:62:C9:EB:60:17:8D:EA:2B:E1:F8:22:36:FF:CF:F4:F3:84:3C:27:21:79:DC:DD:38:4D:54:10:53:DA:6A:6A:0D:3C:E4:8F:DC:2D:C4:E3:E0:EE:E1:5F sha1 FE:70:AB:3B:4D:5A:1B:99:24:22:8A:DF:80:27:C7:58:48:3A:8B:7E +A0:00:00:00:03 05 000000 rsa 03 D0:13:5C:E8:A4:43:6C:7F:9D:5C:C6:65:47:E3:0E:A4:02:F9:81:05:B7:17:22:E2:4B:C0:8D:CC:80:AB:7E:71:EC:23:B8:CE:6A:1D:C6:AC:2A:8C:F5:55:43:D7:4A:8A:E7:B3:88:F9:B1:74:B7:F0:D7:56:C2:2C:BB:59:74:F9:01:6A:56:B6:01:CC:A6:4C:71:F0:4B:78:E8:6C:50:1B:19:3A:55:56:D5:38:9E:CE:4D:EA:25:8A:B9:7F:52:A3 sha1 86:DF:04:1E:79:95:02:35:52:A7:9E:26:23:E4:91:80:C0:CD:95:7A +A0:00:00:00:03 06 000000 rsa 03 F9:34:FC:03:2B:E5:9B:60:9A:9A:64:9E:04:44:6F:1B:36:5D:1D:23:A1:E6:57:4E:49:01:70:52:7E:DF:32:F3:98:32:61:59:B3:9B:63:D0:7E:95:E6:27:6D:7F:CB:B7:86:92:51:82:BC:06:67:FB:D8:F6:56:6B:36:1C:A4:1A:38:DD:F2:27:09:1B:87:FA:4F:47:BA:C7:80:AC:47:E1:5A:6A:0F:B6:53:93:EB:34:73:E8:D1:93:A0:7E:B5:79 sha1 A0:DF:5D:AA:38:5A:E3:E0:E2:1B:FD:34:D9:D8:A3:05:06:B1:9B:12 +A0:00:00:00:03 07 171231 rsa 03 A8:9F:25:A5:6F:A6:DA:25:8C:8C:A8:B4:04:27:D9:27:B4:A1:EB:4D:7E:A3:26:BB:B1:2F:97:DE:D7:0A:E5:E4:48:0F:C9:C5:E8:A9:72:17:71:10:A1:CC:31:8D:06:D2:F8:F5:C4:84:4A:C5:FA:79:A4:DC:47:0B:B1:1E:D6:35:69:9C:17:08:1B:90:F1:B9:84:F1:2E:92:C1:C5:29:27:6D:8A:F8:EC:7F:28:49:20:97:D8:CD:5B:EC:EA:16:FE:40:88:F6:CF:AB:4A:1B:42:32:8A:1B:99:6F:92:78:B0:B7:E3:31:1C:A5:EF:85:6C:2F:88:84:74:B8:36:12:A8:2E:4E:00:D0:CD:40:69:A6:78:31:40:43:3D:50:72:5F sha1 B4:BC:56:CC:4E:88:32:49:32:CB:C6:43:D6:89:8F:6F:E5:93:B1:72 +A0:00:00:00:03 08 241231 rsa 03 D9:FD:6E:D7:5D:51:D0:E3:06:64:BD:15:70:23:EA:A1:FF:A8:71:E4:DA:65:67:2B:86:3D:25:5E:81:E1:37:A5:1D:E4:F7:2B:CC:9E:44:AC:E1:21:27:F8:7E:26:3D:3A:F9:DD:9C:F3:5C:A4:A7:B0:1E:90:70:00:BA:85:D2:49:54:C2:FC:A3:07:48:25:DD:D4:C0:C8:F1:86:CB:02:0F:68:3E:02:F2:DE:AD:39:69:13:3F:06:F7:84:51:66:AC:EB:57:CA:0F:C2:60:34:45:46:98:11:D2:93:BF:EF:BA:FA:B5:76:31:B3:DD:91:E7:96:BF:85:0A:25:01:2F:1A:E3:8F:05:AA:5C:4D:6D:03:B1:DC:2E:56:86:12:78:59:38:BB:C9:B3:CD:3A:91:0C:1D:A5:5A:5A:92:18:AC:E0:F7:A2:12:87:75:26:82:F1:58:32:A6:78:D6:E1:ED:0B sha1 20:D2:13:12:69:55:DE:20:5A:DC:2F:D2:82:2B:D2:2D:E2:1C:F9:A8 +A0:00:00:00:03 09 251231 rsa 03 9D:91:22:48:DE:0A:4E:39:C1:A7:DD:E3:F6:D2:58:89:92:C1:A4:09:5A:FB:D1:82:4D:1B:A7:48:47:F2:BC:49:26:D2:EF:D9:04:B4:B5:49:54:CD:18:9A:54:C5:D1:17:96:54:F8:F9:B0:D2:AB:5F:03:57:EB:64:2F:ED:A9:5D:39:12:C6:57:69:45:FA:B8:97:E7:06:2C:AA:44:A4:AA:06:B8:FE:6E:3D:BA:18:AF:6A:E3:73:8E:30:42:9E:E9:BE:03:42:7C:9D:64:F6:95:FA:8C:AB:4B:FE:37:68:53:EA:34:AD:1D:76:BF:CA:D1:59:08:C0:77:FF:E6:DC:55:21:EC:EF:5D:27:8A:96:E2:6F:57:35:9F:FA:ED:A1:94:34:B9:37:F1:AD:99:9D:C5:C4:1E:B1:19:35:B4:4C:18:10:0E:85:7F:43:1A:4A:5A:6B:B6:51:14:F1:74:C2:D7:B5:9F:DF:23:7D:6B:B1:DD:09:16:E6:44:D7:09:DE:D5:64:81:47:7C:75:D9:5C:DD:68:25:46:15:F7:74:0E:C0:7F:33:0A:C5:D6:7B:CD:75:BF:23:D2:8A:14:08:26:C0:26:DB:DE:97:1A:37:CD:3E:F9:B8:DF:64:4A:C3:85:01:05:01:EF:C6:50:9D:7A:41 sha1 1F:F8:0A:40:17:3F:52:D7:D2:7E:0F:26:A1:46:A1:C8:CC:B2:90:46 +A0:00:00:00:03 10 000000 rsa 03 9F:27:01:C0:90:9C:CB:D8:C3:ED:3E:07:1C:69:F7:76:16:00:22:FF:32:99:80:7E:D7:A0:35:ED:57:52:77:0E:23:2D:56:CC:3B:E1:59:BD:8F:0C:A8:B5:94:35:68:89:22:F4:06:F5:5C:75:63:94:57:BB:AB:EF:E9:A8:6B:22:69:EF:22:3E:34:B9:1A:A6:DF:2C:CA:D0:3B:4A:D4:B4:43:D6:15:75:CA:96:08:45:E6:C6:90:40:10:1E:23:1D:9E:F8:11:AD:99:B0:71:50:65:A0:E6:61:44:9C:41:B4:B0:23:B7:71:6D:1E:4A:FF:1C:90:70:4E:55:AE:12:25 sha1 83:3B:19:47:77:80:36:B6:D7:59:FC:E3:F6:18:DD:EB:27:49:37:2C +A0:00:00:00:03 20 000000 rsa 03 99:8D:2A:D9:46:A6:0F:C5:97:D9:38:07:DB:54:B2:B0:A5:50:87:1E:43:F1:77:9F:07:3A:F0:8D:9B:04:AB:D1:7C:8A:7D:AA:3E:66:EE:44:3F:30:F9:26:48:FC:53:DA:57:A7:83:64:B0:62:FE:DB:50:F7:23:5B:93:7E:16:E5:F6:D9:E6:BA:8F:10:6F:B3:25:EC:A2:51:25:11:1C:E0:4B:43:09:8C:DE:A8:A4:14:26:FC:6D:94:F8:A4:76:19:ED:B1:27:89:58:18:08:69:2C:FB:A1:F3:8E:80:08:CC:5E:02:06:6A:18:89:D5:2F:77:B9:A1:21:E6:59:7F:39 sha1 7A:C3:D8:0E:F0:1E:9A:99:8F:0A:77:18:1E:64:B3:67:47:DC:51:EB +A0:00:00:00:03 50 000000 rsa 01:00:01 D1:11:97:59:00:57:B8:41:96:C2:F4:D1:1A:8F:3C:05:40:8F:42:2A:35:D7:02:F9:01:06:EA:5B:01:9B:B2:8A:E6:07:AA:9C:DE:BC:D0:D8:1A:38:D4:8C:7E:BB:00:62:D2:87:36:9E:C0:C4:21:24:24:6A:C3:0D:80:CD:60:2A:B7:23:8D:51:08:4D:ED:46:98:16:2C:59:D2:5E:AC:1E:66:25:5B:4D:B2:35:25:26:EF:09:82:C3:B8:AD:3D:1C:CE:85:B0:1D:B5:78:8E:75:E0:9F:44:BE:73:61:36:6D:EF:9D:1E:13:17:B0:5E:5D:0F:F5:29:0F:88:A0:DB:47 sha1 B7:69:77:56:68:CA:CB:5D:22:A6:47:D1:D9:93:14:1E:DA:B7:23:7B +A0:00:00:00:03 51 000000 rsa 03 BB:E4:38:77:CC:28:C0:CE:1E:14:BC:14:E8:47:73:17:E2:18:36:45:31:D1:55:BB:8A:C5:B6:3C:0D:6E:28:4D:D2:42:59:19:38:99:F9:C0:4C:30:BA:F1:67:D5:79:29:45:1F:67:AE:BD:3B:BD:0D:41:44:45:01:84:7D:8F:02:F2:C2:A2:D1:48:17:D9:7A:E2:62:5D:C1:63:BF:8B:48:4C:40:FF:B5:17:49:CE:DD:E9:43:4F:B2:A0:A4:10:99 sha1 D3:D9:0B:35:BA:8C:48:73:11:71:EA:C4:07:D8:90:05:AC:F6:F9:DA +A0:00:00:00:03 51 000000 rsa 03 DB:5F:A2:9D:1F:DA:8C:16:34:B0:4D:CC:FF:14:8A:BE:E6:3C:77:20:35:C7:98:51:D3:51:21:07:58:6E:02:A9:17:F7:C7:E8:85:E7:C4:A7:D5:29:71:0A:14:53:34:CE:67:DC:41:2C:B1:59:7B:77:AA:25:43:B9:8D:19:CF:2C:B8:0C:52:2B:DB:EA:0F:1B:11:3F:A2:C8:62:16:C8:C6:10:A2:D5:8F:29:CF:33:55:CE:B1:BD:3E:F4:10:D1:ED:D1:F7:AE:0F:16:89:79:79:DE:28:C6:EF:29:3E:0A:19:28:2B:D1:D7:93:F1:33:15:23:FC:71:A2:28:80:04:68:C0:1A:36:53:D1:4C:6B:48:51:A5:C0:29:47:8E:75:7F sha1 96:92:99:D7:92:D3:CC:08:AD:28:F2:D5:44:CE:E3:30:9D:AD:F1:B9 +A0:00:00:00:03 52 000000 rsa 01:00:01 B8:31:41:4E:0B:46:13:92:2B:D3:5B:4B:36:80:2B:C1:E1:E8:1C:95:A2:7C:95:8F:53:82:00:3D:F6:46:15:4C:A9:2F:C1:CE:02:C3:BE:04:7A:45:E9:B0:2A:90:89:B4:B9:02:78:23:7C:96:51:92:A0:FC:C8:6B:B4:9B:C8:2A:E6:FD:C2:DE:70:90:06:B8:6C:76:76:EF:DF:59:76:26:FA:D6:33:A4:F7:DC:48:C4:45:D3:7E:B5:5F:CB:3B:1A:BB:95:BA:AA:82:6D:53:90:E1:5F:D1:4E:D4:03:FA:2D:0C:B8:41:C6:50:60:95:24:EC:55:5E:3B:C5:6C:A9:57 sha1 73:A7:CA:6B:A7:DB:3C:37:B7:8E:86:95:2B:C4:EC:77:54:92:5D:54 +A0:00:00:00:03 52 000000 rsa 03 AF:F7:40:F8:DB:E7:63:F3:33:A1:01:3A:43:72:20:55:C8:E2:2F:41:77:9E:21:9B:0E:1C:40:9D:60:AF:D4:5C:87:89:C5:7E:EC:D7:1E:A4:A2:69:A6:75:91:6C:C1:C5:E1:A0:5A:35:BD:74:5A:79:F9:45:55:CE:29:61:2A:C9:33:87:69:66:5B:87:C3:CA:8E:1A:C4:95:7F:9F:61:FA:7B:FF:E4:E1:76:31:E9:37:83:7C:AB:F4:3D:D6:18:3D:63:60:A2:28:A3:EB:C7:3A:1D:1C:DC:72:BF:09:95:3C:81:20:3A:B7:E4:92:14:8E:4C:B7:74:CD:DF:AA:C3:54:4D:0D:D4:F8:C8:A0:E9:C7:0B:87:7E:A7:9F:2C:22:E4:CE:52:C6:9F:3E:F3:76:F6:1B:0F:43:A5:40:FE:96:C6:3F:58:63:10:C3:B6:E3:9C:78:C4:D6:47:CA:DB:59:33 sha1 D6:F7:8F:B1:4C:B5:8B:0E:0B:67:BF:A7:87:0F:B8:DF:BE:E2:AD:01 +A0:00:00:00:03 53 000000 rsa 03 BC:D8:37:21:BE:52:CC:CC:4B:64:57:32:1F:22:A7:DC:76:9F:54:EB:80:25:91:3B:E8:04:D9:EA:BB:FA:19:B3:D7:C5:D3:CA:65:8D:76:8C:AF:57:06:7E:EC:83:C7:E6:E9:F8:1D:05:86:70:3E:D9:DD:DA:DD:20:67:5D:63:42:49:80:B1:0E:B3:64:E8:1E:B3:7D:B4:0E:D1:00:34:4C:92:88:86:FF:4C:CC:37:20:3E:E6:10:6D:5B:59:D1:AC:10:2E:2C:D2:D7:AC:17:F4:D9:6C:39:8E:5F:D9:93:EC:B4:FF:DF:79:B1:75:47:FF:9F:A2:AA:8E:EF:D6:CB:DA:12:4C:BB:17:A0:F8:52:81:46:38:71:35:E2:26:B0:05:A4:74:B9:06:2F:F2:64:D2:FF:8E:FA:36:81:4A:A2:95:00:65:B1:B0:4C:0A:1A:E9:B2:F6:9D:4A:4A:A9:79:D6:CE:95:FE:E9:48:5E:D0:A0:3A:EE:9B:D9:53:E8:1C:FD:1E:F6:E8:14:DF:D3:C2:CE:37:AE:FA:38:C1:F9:87:73:71:E9:1D:6A:5E:B5:9F:DE:DF:75:D3:32:5F:A3:CA:66:CD:FB:A0:E5:71:46:CC:78:98:18:FF:06:BE:5F:CC:50:AB:D3:62:AE:4B:80:99:6D sha1 A8:4A:53:96:45:13:A5:D9:36:3B:4B:A1:3A:F5:D4:3B:83:A8:3C:E7 +A0:00:00:00:03 58 000000 rsa 01:00:01 99:55:2C:4A:1E:CD:68:A0:26:01:57:FC:41:51:B5:99:28:37:44:5D:3F:C5:73:65:CA:56:92:C8:7B:E3:58:CD:CD:F2:C9:2F:B6:83:75:22:84:2A:48:EB:11:CD:FF:E2:FD:91:77:0C:72:21:E4:AF:62:07:C2:DE:40:04:C7:DE:E1:B6:27:6D:C6:2D:52:A8:7D:2C:D0:1F:BF:2D:C4:06:5D:B5:28:24:D2:A2:16:7A:06:D1:9E:6A:0F:78:10:71:CD:B2:DD:31:4C:B9:44:41:D8:DC:0E:93:63:17:B7:7B:F0:6F:51:77:F6:C5:AB:A3:A3:BC:6A:A3:02:09:C9:72:60:B7:A1:AD:3A:19:2C:9B:8C:D1:D1:53:57:0A:FC:C8:7C:3C:D6:81:D1:3E:99:7F:E3:3B:39:63:A0:A1:C7:97:72:AC:F9:91:03:3E:1B:83:97:AD:03:41:50:0E:48:A2:47:70:BC:4C:BE:19:D2:CC:F4:19:50:4F:DB:F0:38:9B:C2:F2:FD:CD:4D:44:E6:1F sha1 E6:D3:02:EB:E7:DC:6F:26:7E:4D:00:F7:D4:88:F0:AB:62:35:F1:05 +A0:00:00:00:03 90 000000 rsa 03 C2:6B:3C:B3:83:3E:42:D8:27:0D:C1:0C:89:99:B2:DA:18:10:68:38:65:0D:A0:DB:F1:54:EF:D5:11:00:AD:14:47:41:B2:A8:7D:68:81:F8:63:0E:33:48:DE:A3:F7:80:38:E9:B2:1A:69:7E:B2:A6:71:6D:32:CB:F2:60:86:F1 sha1 B3:AE:2B:C3:CA:FC:05:EE:EF:AA:46:A2:A4:7E:D5:1D:E6:79:F8:23 +A0:00:00:00:03 92 000000 rsa 03 99:6A:F5:6F:56:91:87:D0:92:93:C1:48:10:45:0E:D8:EE:33:57:39:7B:18:A2:45:8E:FA:A9:2D:A3:B6:DF:65:14:EC:06:01:95:31:8F:D4:3B:E9:B8:F0:CC:66:9E:3F:84:40:57:CB:DD:F8:BD:A1:91:BB:64:47:3B:C8:DC:9A:73:0D:B8:F6:B4:ED:E3:92:41:86:FF:D9:B8:C7:73:57:89:C2:3A:36:BA:0B:8A:F6:53:72:EB:57:EA:5D:89:E7:D1:4E:9C:7B:6B:55:74:60:F1:08:85:DA:16:AC:92:3F:15:AF:37:58:F0:F0:3E:BD:3C:5C:2C:94:9C:BA:30:6D:B4:4E:6A:2C:07:6C:5F:67:E2:81:D7:EF:56:78:5D:C4:D7:59:45:E4:91:F0:19:18:80:0A:9E:2D:C6:6F:60:08:05:66:CE:0D:AF:8D:17:EA:D4:6A:D8:E3:0A:24:7C:9F sha1 42:9C:95:4A:38:59:CE:F9:12:95:F6:63:C9:63:E5:82:ED:6E:B2:53 +A0:00:00:00:03 94 000000 rsa 03 AC:D2:B1:23:02:EE:64:4F:3F:83:5A:BD:1F:C7:A6:F6:2C:CE:48:FF:EC:62:2A:A8:EF:06:2B:EF:6F:B8:BA:8B:C6:8B:BF:6A:B5:87:0E:ED:57:9B:C3:97:3E:12:13:03:D3:48:41:A7:96:D6:DC:BC:41:DB:F9:E5:2C:46:09:79:5C:0C:CF:7E:E8:6F:A1:D5:CB:04:10:71:ED:2C:51:D2:20:2F:63:F1:15:6C:58:A9:2D:38:BC:60:BD:F4:24:E1:77:6E:2B:C9:64:80:78:A0:3B:36:FB:55:43:75:FC:53:D5:7C:73:F5:16:0E:A5:9F:3A:FC:53:98:EC:7B:67:75:8D:65:C9:BF:F7:82:8B:6B:82:D4:BE:12:4A:41:6A:B7:30:19:14:31:1E:A4:62:C1:9F:77:1F:31:B3:B5:73:36:00:0D:FF:73:2D:3B:83:DE:07:05:2D:73:03:54:D2:97:BE:C7:28:71:DC:CF:0E:19:3F:17:1A:BA:27:EE:46:4C:6A:97:69:09:43:D5:9B:DA:BB:2A:27:EB:71:CE:EB:DA:FA:11:76:04:64:78:FD:62:FE:C4:52:D5:CA:39:32:96:53:0A:A3:F4:19:27:AD:FE:43:4A:2D:F2:AE:30:54:F8:84:06:57:A2:6E:0F:C6:17 sha1 C4:A3:C4:3C:CF:87:32:7D:13:6B:80:41:60:E4:7D:43:B6:0E:6E:0F +A0:00:00:00:03 95 000000 rsa 03 BE:9E:1F:A5:E9:A8:03:85:29:99:C4:AB:43:2D:B2:86:00:DC:D9:DA:B7:6D:FA:AA:47:35:5A:0F:E3:7B:15:08:AC:6B:F3:88:60:D3:C6:C2:E5:B1:2A:3C:AA:F2:A7:00:5A:72:41:EB:AA:77:71:11:2C:74:CF:9A:06:34:65:2F:BC:A0:E5:98:0C:54:A6:47:61:EA:10:1A:11:4E:0F:0B:55:72:AD:D5:7D:01:0B:7C:9C:88:7E:10:4C:A4:EE:12:72:DA:66:D9:97:B9:A9:0B:5A:6D:62:4A:B6:C5:7E:73:C8:F9:19:00:0E:B5:F6:84:89:8E:F8:C3:DB:EF:B3:30:C6:26:60:BE:D8:8E:A7:8E:90:9A:FF:05:F6:DA:62:7B sha1 EE:15:11:CE:C7:10:20:A9:B9:04:43:B3:7B:1D:5F:6E:70:30:30:F6 +A0:00:00:00:03 96 000000 rsa 03 B7:45:86:D1:9A:20:7B:E6:62:7C:5B:0A:AF:BC:44:A2:EC:F5:A2:94:2D:3A:26:CE:19:C4:FF:AE:EE:92:05:21:86:89:22:E8:93:E7:83:82:25:A3:94:7A:26:14:79:6F:B2:C0:62:8C:E8:C1:1E:38:25:A5:6D:3B:1B:BA:EF:78:3A:5C:6A:81:F3:6F:86:25:39:51:26:FA:98:3C:52:16:D3:16:6D:48:AC:DE:8A:43:12:12:FF:76:3A:7F:79:D9:ED:B7:FE:D7:6B:48:5D:E4:5B:EB:82:9A:3D:47:30:84:8A:36:6D:33:24:C3:02:70:32:FF:8D:16:A1:E4:4D:8D sha1 76:16:E9:AC:8B:E0:14:AF:88:CA:11:A8:FB:17:96:7B:73:94:03:0E +A0:00:00:00:03 97 000000 rsa 03 AF:07:54:EA:ED:97:70:43:AB:6F:41:D6:31:2A:B1:E2:2A:68:09:17:5B:EB:28:E7:0D:5F:99:B2:DF:18:CA:E7:35:19:34:1B:BB:D3:27:D0:B8:BE:9D:4D:0E:15:F0:7D:36:EA:3E:3A:05:C8:92:F5:B1:9A:3E:9D:34:13:B0:D9:7E:7A:D1:0A:5F:5D:E8:E3:88:60:C0:AD:00:4B:1E:06:F4:04:0C:29:5A:CB:45:7A:78:85:51:B6:12:7C:0B:29 sha1 80:01:CA:76:C1:20:39:55:E2:C6:28:41:CD:6F:20:10:87:E5:64:BF +A0:00:00:00:03 98 000000 rsa 03 CA:02:6E:52:A6:95:E7:2B:D3:0A:F9:28:19:6E:ED:C9:FA:F4:A6:19:F2:49:2E:3F:B3:11:69:78:9C:27:6F:FB:B7:D4:31:16:64:7B:A9:E0:D1:06:A3:54:2E:39:65:29:2C:F7:78:23:DD:34:CA:8E:EC:7D:E3:67:E0:80:70:89:50:77:C7:EF:AD:93:99:24:CB:18:70:67:DB:F9:2C:B1:E7:85:91:7B:D3:8B:AC:E0:C1:94:CA:12:DF:0C:E5:B7:A5:02:75:AC:61:BE:7C:3B:43:68:87:CA:98:C9:FD:39 sha1 E7:AC:9A:A8:EE:D1:B5:FF:1B:D5:32:CF:14:89:A3:E5:55:75:72:C1 +A0:00:00:00:03 99 000000 rsa 03 AB:79:FC:C9:52:08:96:96:7E:77:6E:64:44:4E:5D:CD:D6:E1:36:11:87:4F:39:85:72:25:20:42:52:95:EE:A4:BD:0C:27:81:DE:7F:31:CD:3D:04:1F:56:5F:74:73:06:EE:D6:29:54:B1:7E:DA:BA:3A:6C:5B:85:A1:DE:1B:EB:9A:34:14:1A:F3:8F:CF:82:79:C9:DE:A0:D5:A6:71:0D:08:DB:41:24:F0:41:94:55:87:E2:03:59:BA:B4:7B:75:75:AD:94:26:2D:4B:25:F2:64:AF:33:DE:DC:F2:8E:09:61:5E:93:7D:E3:2E:DC:03:C5:44:45:FE:7E:38:27:77 sha1 4A:BF:FD:6B:1C:51:21:2D:05:55:2E:43:1C:5B:17:00:7D:2F:5E:6D +A0:00:00:00:03 F3 000000 rsa 03 98:F0:C7:70:F2:38:64:C2:E7:66:DF:02:D1:E8:33:DF:F4:FF:E9:2D:69:6E:16:42:F0:A8:8C:56:94:C6:47:9D:16:DB:15:37:BF:E2:9E:4F:DC:6E:6E:8A:FD:1B:0E:B7:EA:01:24:72:3C:33:31:79:BF:19:E9:3F:10:65:8B:2F:77:6E:82:9E:87:DA:ED:A9:C9:4A:8B:33:82:19:9A:35:0C:07:79:77:C9:7A:FF:08:FD:11:31:0A:C9:50:A7:2C:3C:A5:00:2E:F5:13:FC:CC:28:6E:64:6E:3C:53:87:53:5D:50:95:14:B3:B3:26:E1:23:4F:9C:B4:8C:36:DD:D4:4B:41:6D:23:65:40:34:A6:6F:40:3B:A5:11:C5:EF:A3 sha1 12:8E:B3:31:28:E6:3E:38:C9:A8:3A:2B:1A:93:49:E1:78:F8:21:96 +A0:00:00:05:24 6A 000000 rsa 03 92:79:5E:AA:4F:E3:9E:B3:04:41:FE:95:2D:54:23:77:8E:02:F8:67:83:B8:9D:D7:C5:87:AE:80:A6:9F:4D:6D:C5:5E:AF:B6:60:40:40:D8:75:C7:20:02:42:5E:E5:29:CE:4E:A2:6F:D8:64:BA:D7:60:16:0C:2A:A0:C5:AF:92:38:18:94:A5:CB:BC:8A:B3:AF:26:41:60:6C:37:9B:92:7A:39:7C:B1:E9:B9:EA:2E:F8:C0:A9:C0:DD:EB:B8:1B:0F:89:13:A1:18:F7:04:41:56:EA:7D:23:AF:62:6E:AF:30:C2:C9:EC:E8:53:4D:35:63:EF:5F:E9:5D:E7:62:49 sha1 51:ED:45:70:32:3C:D4:1A:03:48:BD:FE:A8:1C:CC:0B:8D:9B:AB:3F +A0:00:00:05:24 6B 000000 rsa 03 C9:DF:DB:62:5A:DA:4B:5E:86:04:9F:85:A0:23:76:27:B5:95:24:F5:2B:D4:99:B4:C5:48:2C:1E:E0:12:D6:1A:14:46:E9:38:3C:C0:B7:EE:29:22:D3:23:A5:EC:DA:12:94:1E:A8:17:7C:FA:51:2D:A6:B5:B7:66:3A:89:B7:93:B1:0D:31:4C:BB:77:6E:B9:6D:0B:17:34:ED:E7:E1:59:17:13:91:5E:99:91:B7:B4:E8:A0:17:A6:90:12:79:AE:BD:D6:13:6C:9F:E7:E0:C6:CB:F9:4C:77:FA:60:6B:62:9D:00:B1:F8:90:47:39:05:EB:4D:AD:1A:D9:3B:29:C2:C1:82:9A:82:F8:80:B0:89:86:B9:38:76:11:EE:40:9D sha1 96:02:42:8A:46:27:1C:63:CC:C6:DD:99:47:7C:DB:70:43:5D:6D:5B +A0:00:00:05:24 6C 000000 rsa 03 C7:62:59:FF:78:5A:BD:5F:F6:13:22:3C:01:F5:BD:A0:F3:6F:93:42:CF:33:6B:66:C3:2D:4B:2C:D5:09:6E:09:4D:8E:04:DF:A1:1A:9B:2E:3B:C7:8D:A6:3B:5C:10:14:8D:8E:D7:9E:BA:68:5D:5D:0E:FE:1C:58:B3:F9:29:D8:61:B4:0F:F3:AA:A3:B5:27:14:8D:0C:24:92:1E:E4:2D:A0:48:E0:1E:38:F6:A3:A4:9D:FA:67:DD:1C:D5:DD:20:91:41:2D:D3:6D:32:69:FA:F7:D2:E0:FF:B1:A3:E0:28:96:9C:B6:BA:5A:93:03:A6:FF:65:54:0F:42:1B:06:9A:31:B5:53:39:8E:E5:25:EF:A5:C2:CE:26:BC:B8:1C:53:45:01:8D:5E:3E:9B:71:30:F7:2F:59:8C:0E:AA:46:82:D4:DA:2F:22:04:51:87:80:A8:10:8F:82:DD:C9:CF:1F sha1 3B:18:A2:1B:F3:4F:78:12:08:14:5D:75:67:98:25:13:D1:CE:8C:92 +A0:00:00:05:24 6D 000000 rsa 03 B7:47:E8:CB:36:15:E8:D2:62:31:35:54:88:F3:C7:6C:47:46:F7:BB:1C:38:1E:6C:6E:6A:BF:0A:6D:7C:D9:3C:FC:6B:2C:31:02:88:CA:8B:E7:EE:17:30:DE:62:1A:59:D1:BB:2D:8C:02:C9:14:8F:A0:6E:5D:1F:5E:67:2E:EF:CE:8A:EC:BA:D4:A1:C1:8F:31:75:F1:BE:A1:AE:F5:39:37:65:92:36:6B:46:A5:04:4E:32:E5:9B:3F:35:F5:0E:85:F8:43:BA:01:85:1E:53:86:B7:EB:E2:73:67:D3:D4:83:C5:47:2D:30:20:AF:42:11:6D:DD:A3:23:41:55:7E:BA:BB:04:3E:BC:60:06:B9:9A:65:20:09:04:5B:FA:50:C5:27:02:85:86:E0:59:42:E1:D5:94:22:3B:49:FE:85:66:93:1C:31:FB:E8:C9:03:AB:D4:F2:83:E1:FA:B0:3D:75:82:47:EC:4B:72:8A:85:A9:89:76:01:B7:53:29:32:63:AD:BD:10:BE:98:8D:0C:52:FE:00:91:C2:72:1D:C0:2C:51:30:FC:76:63:E9:57:39:A7:0E:E2:F8:4D:FD:2E:50:C8:8A:1A:26:58:7E:F7:CC:04:7F:CA:2D:03:C2:CF:0C:E4:B5:24:B4:EC:3F:07 sha1 41:10:08:F9:92:1B:89:C6:2E:21:60:F6:D0:35:86:14:11:5E:CD:4A +A0:00:00:05:24 03 171231 rsa 03 E7:03:A9:08:FF:AE:37:30:F8:2E:55:08:69:A2:94:C1:FF:1D:A2:5F:2B:53:D2:C8:BB:18:F7:70:DA:D5:05:13:5D:03:D5:EC:8E:E3:92:65:50:05:1C:3D:48:57:F6:FE:DB:88:2C:28:89:E0:B2:5F:38:9F:78:74:1F:29:31:A9:2D:45:D3:A4:7E:62:81:0D:32:53:65:3A:B0:AB:35:70:C3:5D:FD:08:D3:16:7B:6D:B4:2E:D2:8F:76:51:86:F4:28:7C:DA:F9:D9:BA:D2:0B:CE:2C:4E:CF:EC:DD:21:8E:50:F1:FC:C7:18:87:88:82:F3:93:4A:6F:EB:50:2C:FC:AD:61:5A:2B:2E:27:9A:08:68:DD:A9:48:9D:FA:9C:D9 sha1 4B:93:D1:E1:F5:7C:FA:16:97:05:01:F1:7D:3E:06:41:10:43:F1:D5 +A0:00:00:05:24 04 241231 rsa 03 AC:00:19:62:4F:C0:A7:22:70:C6:88:5C:C0:B3:C9:14:0C:35:1F:CF:E6:F8:14:58:81:A2:77:50:39:34:53:D3:26:5F:69:E7:65:81:32:D8:D2:53:ED:F8:99:1E:2B:A3:2B:78:2D:39:AD:E1:FF:1F:C8:F2:11:F5:DF:51:A0:00:7C:76:1A:D9:88:25:87:BD:6A:36:AE:CD:3A:BB:F9:44:30:7A:C9:7A:2D:90:5F:AB:48:9C:3E:1C:CD:76:DE:9E:B9:3E:CF:AB:2B:B8:4F:34:E7:70:11:9E:35:6D:C6:37:2D:86:85:DA:8E:B9:2F:CA:C7:B5:3C:01:67:10:0E:4C:DF:B9:83:0D:1C:45:E7:87:E4:4C:9F:6A:42:EC:13:1A:6A:4C:D6:6B:BE:4F:93:CA:91:FD:F1:57:C7:B2:2F:C7:22:1A:63:48:F0:ED:A6:15:13:02:A8:0E:F7:7D:6C:A5 sha1 6F:84:3C:E7:65:B9:14:4C:E1:A6:BF:EA:46:BC:37:B6:50:81:CE:7F +A0:00:00:05:24 05 241231 rsa 03 C0:4E:80:18:03:69:89:8A:AE:F6:EE:77:41:ED:ED:25:23:9D:76:53:01:61:4B:5B:41:A0:08:CA:30:09:35:8D:62:6D:82:8B:C5:F1:B1:E0:4A:2D:C1:36:71:01:26:69:05:D2:62:00:3B:E7:47:FD:23:1C:9B:00:11:F2:F2:B2:1B:A8:E4:C0:F4:CA:5E:93:ED:9D:BB:2E:92:AB:C4:50:57:6A:4E:B5:9A:D0:0D:CA:59:C8:BF:32:30:E4:B1:9D:43:45:28:71:C6:21:5D:83:76:63:31:0D:F4:3C:AE:A1:B9:B0:8C:1F:50:0A:F1:B5:50:F6:2E:18:D7:0E:EE:9E:94:75:32:1B:CD:17:99:AB:19:3E:0B:C8:49:DA:CE:89:2A:0E:6A:1F:42:FE:07:86:DB:30:34:5A:E1:A0:E7:E4:C4:B7:16:40:E0:3B:FD:28:32:C4:91:A7:D8:3F:3B:4E:F4:D3:88:CD:DB:B7:48:C2:FD:1D:9D:4A:9B:F5:2F:C8:56:CB:A0:88:D4:B2:74:84:60:02:C2:3C:DA:72:2C:5C:FF:3B:1F:82:18:A1:84:3B:04:26:47:4B:DC:92:F2:F5:E3:1F:BF:32:1C:C1:74:80:AD:06:9D:F5:53:81:F2:E6:01:D5:CB:A7:B8:71:25:3F sha1 70:81:DF:2A:0C:36:36:0F:24:C1:22:C5:74:F0:AD:2E:57:89:3D:D2 +A0:00:00:05:24 06 241231 rsa 03 9D:8A:75:B3:6B:CB:DF:25:0B:87:61:5A:46:F6:EA:35:DE:35:22:6E:EA:B7:B4:73:D7:DC:0A:28:B5:DF:07:5C:83:B2:77:5F:23:33:7E:6C:EE:36:CC:FE:3A:65:68:C9:C8:22:D6:DE:81:29:95:65:A8:29:34:8E:03:D4:79:B6:31:BB:18:A2:42:9A:85:90:C5:97:F4:46:A3:CE:A3:BE:2E:82:21:06:F4:3D:FB:B9:81:EC:0F:11:21:91:9C:B3:5F:85:DB:A3:35:5C:5E:7F:F3:5F:2B:22:1F:D6:5E:DB:EA:41:F2:3A:7A:10:9F:BB:C4:A7:74:A7:56:D8:9B:59:3B:19:9E:1E:9D:A9:A9:92:17:D4:BF:31:F6:7C:DA:8C:4E:1B:81:FA:2A:37:7C:83:B5:D1:CD:6A:F1:F1:88:04:48:CF:F4:8D:3A:4A:DB:BC:7F:BD:73:00:61:50:8A:6E:A8:FD:FC:5B:D6:6A:2E:94:E3:3B:83:F8:1E:0E:56:CF:1C:94:73:E4:42:6E:E4:35:F9:E8:01:36:76:0D:8F:4A:D9:46:80:5B:03:A6:7C:55:36:15:82:F5:AD:8F:40:40:43:92:FA:4C:B4:F5:C2:BA:F6:E2:68:57:A1:D6:09:41:E3:D0:55:AC:D9:AC:0B:EF sha1 E9:8F:41:34:E1:94:9A:9A:05:4E:46:79:AC:9A:7E:C8:39:69:E2:09 +A0:00:00:00:42 04 171231 rsa 03 D0:20:CF:48:11:D0:F0:7E:45:C7:8A:AC:85:DA:5D:9C:5F:49:9E:70:A4:0D:9F:7F:51:95:4B:8F:88:8D:FE:81:13:39:98:4F:F7:7B:AC:99:67:92:C7:3B:50:BF:22:0E:A8:6B:01:6D:A7:F3:3B:17:7B:37:65:AB:94:69:A7:85:64:63:11:D6:49:F0:C4:68:D2:9A:A2:3F:60:D1:91:ED:FF:D6:0D:7A:51:83:43:06:45:3A:1B:C8:39:CB:85:8E:91:FB:10:C8:E9:BB:74:91:FB:03:6A:0D:3C:E8:4A:42:EA:04:5A:29:4B:82:E6:3C:9A:6E:AE:36:0F:35:BC:0B:24:38:38:9D:8D:78:0F:4C:78:83:64:D2:D3:03:49:31 sha1 95:48:2A:83:2B:5B:98:0A:9F:9C:78:BE:81:0E:14:9A:C9:42:5F:47 +A0:00:00:00:42 06 171231 rsa 03 B5:4B:10:57:A9:FE:FD:E4:AB:0B:0A:F8:AF:BF:9B:F0:DE:CE:97:5A:E9:49:39:1A:DD:E4:54:D7:45:5C:E3:77:BF:3E:5F:5A:45:10:C7:43:47:F0:1D:02:94:90:B1:E8:34:36:42:09:CF:4E:89:E2:3A:24:21:35:D1:E6:1B:F1:AF:5A:1E:5C:77:0A:46:37:DE:E8:16:61:77:5B:F1:2B:B8:F0:33:73:25:53:7A:AC:FE:73:50:7E:A0:A3:CE:4C:30:9B:EF:40:4E:D4:5C:69:27:F8:4F:F2:51:01:A2:95:22:4B:39:FC:89:83:95:4A:B2:91:BF:F6:B4:5E:12:BE:CD:F2:AE:51:3B:14:BD:D4:09:38:54:5C:20:F2:A3:D9 sha1 EF:6E:FF:2F:B8:90:9A:9B:2E:DF:8A:BB:3E:2A:F1:CC:38:B3:BD:19 +A0:00:00:00:42 07 211231 rsa 03 BA:6D:5B:9C:D8:35:79:E9:18:64:B6:B6:6B:27:4C:0A:6A:B2:98:BC:E2:84:2C:FA:53:B0:70:35:6E:AD:3E:7C:B5:88:8F:EF:FE:C1:B6:57:A9:BE:0A:5A:F5:76:A8:D9:8C:88:A2:E3:C9:8B:B0:DE:AE:E4:EA:DD:B2:E9:00:66:A7:03:B5:49:EC:04:80:54:E8:2C:BA:7E:DB:14:BC:8C:1A:5A:07:BE:03:EE:D8:F1:35:15:80:6F:A0:F1:B9:FA:E9:6D:E4:14:2A:BD:4A:BB:C8:B7:CC:F7:DE:FB:CA:B3:9C:5A:12:B1:FE:68:C4:BD:ED:29:F3:D3:F0:6B:F6:E5:8B:A8:CB:47:48:3F:92:BA:C7:69:71:EF:89:5A:57:FC:3E:6F:46:BF:43:F9:F1:BC:AE:4F:42:FF:00:B1:B4:5F:6C:C4:7F:4A:FC:E8:44:A8:E7:CF:35:A4:99:FA:54:ED sha1 14:23:BF:39:A1:B0:72:0F:53:4F:37:54:23:F7:AE:8D:7D:D2:F4:6E +A0:00:00:00:42 08 211231 rsa 03 D3:E3:46:3D:40:03:9D:F1:5F:A5:30:D4:36:7B:3B:55:8C:9B:18:B3:4C:97:22:63:32:14:69:80:34:21:E8:1B:75:DD:9C:A5:E3:57:8D:C4:1F:B2:4D:0F:4B:85:EF:6E:9D:BF:AE:AA:47:E2:53:35:42:B2:EC:39:7A:28:18:77:4F:2B:9B:31:9C:18:CE:EA:3A:8C:66:87:0E:31:38:2F:58:2D:2C:66:16:42:52:DD:43:12:92:08:B6:F3:99:55:4C:58:4E:43:D3:F9:84:38:3C:B8:66:91:B5:D8:1C:9C:A9:08:9A:28:9A:08:B2:2C:EB:CF:9C:0E:7B:B2:45:8F:C0:57:D9:C5:6D:0B:9B:4E:63:6B:64:A3:59:C0:7D:43:F8:30:5B:50:27:85:1F:FC:A4:37:88:A5:A3:87:FE:D7:50:DB:AE:D6:1C:78:52:4D:DE:2E:36:F0:90:C5:29:13:BF:90:9D:F1:A2:FD:3C:17:8C:8D:2E:30:07:CA:2C:A6:7C:EA:7C:F0:2A:CF:8A:22:8D:BE:A7:58:9B:2C:C1:93:05:B3:C0:A6:4E:FD:47:24:2A:6F:D9:58:A3:81:EF:AE:C1:91:B7:90:A9:AB:DB:04:3D:1A:B1:BD:B8:AA:B6:6D:0F:E0:DC:82:A0:73:8F:AB sha1 85:19:DA:94:E9:38:A5:35:2A:E0:79:90:D1:5A:D4:0D:BB:9A:8F:1C +A0:00:00:00:42 85 181203 rsa 03 D5:BD:27:FF:D6:8F:05:C9:16:C4:A1:13:B8:29:65:F0:6B:B9:BD:84:D1:D0:46:69:BA:AF:2D:70:40:D0:72:FC:4A:16:D1:67:A5:D9:9D:B5:CA:44:66:F5:56:B4:61:74:EF:8E:65:D6:CA:77:9B:B8:55:7F:3E:5A:D8:61:A7:25:71:7F:7A:7D:70:F4:1D:A5:3F:6A:57:4E:DA:64:87:62:C8:63:7A:86:02:BD:A3:78:DD:D6:DF:AC:DD:B1:56:36:62:B7:8F:1E:25:F7:FC:81:64:08:1E:29:3D:5C:BF:3F:57:18:70:33:A9:68:AE:17:3B:E7:D7:8A:46:CB:70:EA:68:FB:65:DD:50:19:CD:40:04:21:CB:B7:03:70:24:75 sha1 E8:82:F4:7B:8E:F9:25:BE:DD:F3:2C:20:55:58:27:DA:7F:DD:75:70 +A0:00:00:00:42 86 181203 rsa 03 D7:68:6F:54:E4:C6:5D:FC:16:2B:45:5D:61:2D:91:87:39:05:9B:A2:44:5B:79:A1:BD:07:0A:44:8C:E0:62:BD:0C:6E:7E:56:83:22:34:90:C6:6A:B4:B8:08:A4:D3:A5:9E:27:6D:8B:77:99:25:75:2F:CE:14:0B:A1:36:C0:E0:5C:0B:DB:AE:0A:9F:75:1B:93:40:BA:88:60:39:67:F4:3D:40:A0:4C:FD:65:25:03:B7:82:34:D1:88:F6:B2:1D:5A:3A:E9:9B:B8:4B:2E:50:23:5E:F9:D7:ED:7A:70:A1:17:80:67:78:E9:F0:D1:B3:DA:DC:1C:E9:B2:5C:2D:DE:07:B3:B6:E1:DE:48:7E:0F:7E:9F:FE:DD:D4:D1:52:55:CE:C4:53:63:1E:F4:7E:14:B4:98:A3:53:84:48:02:A4:A2:5A:62:B9:91:8E:9A:12:A0:0B:F8:87:AA:D4:79:9F sha1 96:A6:90:81:1A:A2:19:6E:3D:10:90:CE:01:49:AA:29:35:C0:4F:E2 diff --git a/client/emv/cmdemv.c b/client/emv/cmdemv.c index 832df82e..627b4ab2 100644 --- a/client/emv/cmdemv.c +++ b/client/emv/cmdemv.c @@ -1804,7 +1804,7 @@ int CmdEMVRoca(const char *cmd) { struct emv_pk *pk = get_ca_pk(tlvRoot); if (!pk) { - PrintAndLogEx(ERR, "ERROR: Key not found. Exit."); + PrintAndLogEx(ERR, "CA Public Key not found. Exit."); goto out; } @@ -1815,8 +1815,10 @@ int CmdEMVRoca(const char *cmd) { goto out; } + char RID[15] = {0}; + memcpy(RID, sprint_hex(issuer_pk->rid, 5), 14); PrintAndLogEx(SUCCESS, "Issuer PK recovered. RID %s IDX %02hhx CSN %s", - sprint_hex(issuer_pk->rid, 5), + RID, issuer_pk->index, sprint_hex(issuer_pk->serial, 3) ); @@ -1829,8 +1831,10 @@ int CmdEMVRoca(const char *cmd) { PrintAndLogEx(WARNING, "WARNING: ICC certificate not found. Exit."); goto out; } + + memcpy(RID, sprint_hex(icc_pk->rid, 5), 14); PrintAndLogEx(SUCCESS, "ICC PK recovered. RID %s IDX %02hhx CSN %s\n", - sprint_hex(icc_pk->rid, 5), + RID, icc_pk->index, sprint_hex(icc_pk->serial, 3) ); diff --git a/client/emv/emv_pk.c b/client/emv/emv_pk.c index b577855e..f4a5f56a 100644 --- a/client/emv/emv_pk.c +++ b/client/emv/emv_pk.c @@ -44,7 +44,7 @@ static ssize_t emv_pk_read_bin(char *buf, unsigned char *bin, size_t size, size_ { size_t left = size; char *p = buf; - while (*p && *p == ' ') + while (*p && (*p == ' ' || *p == '\t')) p++; while (left > 0) { @@ -71,7 +71,7 @@ static ssize_t emv_pk_read_bin(char *buf, unsigned char *bin, size_t size, size_ return -(p - buf); } - while (*p && *p == ' ') + while (*p && (*p == ' ' || *p == '\t')) p++; p--; @@ -87,7 +87,7 @@ static ssize_t emv_pk_read_ymv(char *buf, unsigned *ymv) *ymv = 0; - while (*p && *p == ' ') + while (*p && (*p == ' ' || *p == '\t')) p++; for (i = 0; i < 3; i++) { @@ -103,7 +103,7 @@ static ssize_t emv_pk_read_ymv(char *buf, unsigned *ymv) temp[i] = (c1 * 16 + c2); } - while (*p && *p == ' ') + while (*p && (*p == ' ' || *p == '\t')) p++; p--; @@ -119,11 +119,11 @@ static ssize_t emv_pk_read_ymv(char *buf, unsigned *ymv) static ssize_t emv_pk_read_string(char *buf, char *str, size_t size) { char *p = buf; - while (*p && *p == ' ') + while (*p && (*p == ' ' || *p == '\t')) p++; while (size > 1) { - if (*p == ' ') + if (*p == ' ' || *p == '\t') break; else if (*p < 0x20 || *p >= 0x7f) return -(p - buf); @@ -135,7 +135,7 @@ static ssize_t emv_pk_read_string(char *buf, char *str, size_t size) *str = 0; - while (*p && *p == ' ') + while (*p && (*p == ' ' || *p == '\t')) p++; p--; diff --git a/client/emv/emv_pki.c b/client/emv/emv_pki.c index 1ff1e4c6..d36382df 100644 --- a/client/emv/emv_pki.c +++ b/client/emv/emv_pki.c @@ -75,7 +75,7 @@ static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk, 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); From 41bdfce385e2c614a55c3e13734c307c03b6ffed Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Sat, 9 Feb 2019 15:15:17 +0100 Subject: [PATCH 061/189] emv/sc fixes and modifications: (#780) * print selected Smartcard Reader in PrintChannel() * implement 'sc sel '. Readername can include wildcards * and ? * fixing EMV APDU exchange (again) * use EMVExchangeEx() instead of EMVExchange() in fidocore.c --- client/cmdhffido.c | 1 + client/emv/cmdemv.c | 71 ++++++++++++++--------------------- client/emv/emvcore.c | 71 +++++++++++++++++++++++------------ client/emv/emvcore.h | 21 +++-------- client/fido/cbortools.c | 3 ++ client/fido/fidocore.c | 33 ++++++++-------- client/pcsc.c | 83 +++++++++++++++++++++++++++++++---------- 7 files changed, 165 insertions(+), 118 deletions(-) diff --git a/client/cmdhffido.c b/client/cmdhffido.c index 92f5d6cd..8a98cf19 100644 --- a/client/cmdhffido.c +++ b/client/cmdhffido.c @@ -40,6 +40,7 @@ #include "emv/emvcore.h" #include "emv/emvjson.h" #include "emv/dump.h" +#include "emv/apduinfo.h" #include "cliparser/cliparser.h" #include "crypto/asn1utils.h" #include "crypto/libpcrypto.h" diff --git a/client/emv/cmdemv.c b/client/emv/cmdemv.c index 627b4ab2..abb84d43 100644 --- a/client/emv/cmdemv.c +++ b/client/emv/cmdemv.c @@ -11,8 +11,11 @@ #include "cmdemv.h" #include +#include #include "proxmark3.h" #include "cmdparser.h" +#include "ui.h" +#include "util.h" #include "mifare.h" #include "emvjson.h" #include "emv_pki.h" @@ -21,7 +24,11 @@ #include "cliparser/cliparser.h" #include "jansson.h" #include "emv_roca.h" - +#include "pcsc.h" +#include "apduinfo.h" +#include "dol.h" +#include "emv_tags.h" +#include "cmdhf14a.h" #define TLV_ADD(tag, value)( tlvdb_change_or_add_node(tlvRoot, tag, sizeof(value) - 1, (const unsigned char *)value) ) void ParamLoadDefaults(struct tlvdb *tlvRoot) { @@ -53,7 +60,7 @@ void PrintChannel(EMVCommandChannel channel) { PrintAndLogEx(INFO, "Channel: CONTACTLESS"); break; case ECC_CONTACT: - PrintAndLogEx(INFO, "Channel: CONTACT"); + PrintAndLogEx(INFO, "Channel: CONTACT, using %s", getAlternativeSmartcardReader()); break; } } @@ -667,7 +674,7 @@ int CmdEMVInternalAuthenticate(const char *cmd) { return 0; } -#define dreturn(n) {free(pdol_data_tlv);tlvdb_free(tlvSelect);tlvdb_free(tlvRoot);DropField();return n;} +#define dreturn(n) {free(pdol_data_tlv); tlvdb_free(tlvSelect); tlvdb_free(tlvRoot); DropFieldEx( channel ); return n;} void InitTransactionParameters(struct tlvdb *tlvRoot, bool paramLoadJSON, enum TransactionType TrType, bool GenACGPO) { @@ -1255,12 +1262,11 @@ int CmdEMVExec(const char *cmd) { PrintAndLogEx(NORMAL, "* * Host Response: `%s`", HostResponse); tlvdb_change_or_add_node(tlvRoot, 0x8a, sizeof(HostResponse) - 1, (const unsigned char *)HostResponse); - } - if (channel == ECC_CONTACTLESS) { - DropField(); } + DropFieldEx( channel ); + // Destroy TLV's free(pdol_data_tlv); tlvdb_free(tlvSelect); @@ -1368,9 +1374,7 @@ int CmdEMVScan(const char *cmd) { } // drop field at start - if (channel == ECC_CONTACTLESS) { - DropField(); - } + DropFieldEx( channel ); // iso 14443 select PrintAndLogEx(NORMAL, "--> GET UID, ATS."); @@ -1423,7 +1427,7 @@ int CmdEMVScan(const char *cmd) { if (EMVSearch(channel, false, true, decodeTLV, tlvSelect)) { PrintAndLogEx(ERR, "Can't found any of EMV AID. Exit..."); tlvdb_free(tlvSelect); - DropField(); + DropFieldEx( channel ); return 3; } @@ -1439,9 +1443,7 @@ int CmdEMVScan(const char *cmd) { if (!AIDlen) { PrintAndLogEx(INFO, "Can't select AID. EMV AID not found. Exit..."); - if (channel == ECC_CONTACTLESS) { - DropField(); - } + DropFieldEx( channel ); return 4; } @@ -1460,7 +1462,7 @@ int CmdEMVScan(const char *cmd) { if (res) { PrintAndLogEx(ERR, "Can't select AID (%d). Exit...", res); tlvdb_free(tlvRoot); - DropField(); + DropFieldEx( channel ); return 5; } @@ -1488,9 +1490,7 @@ int CmdEMVScan(const char *cmd) { if (!pdol_data_tlv){ PrintAndLogEx(ERR, "Can't create PDOL TLV."); tlvdb_free(tlvRoot); - if (channel == ECC_CONTACTLESS) { - DropField(); - } + DropFieldEx( channel ); return 6; } @@ -1499,7 +1499,7 @@ int CmdEMVScan(const char *cmd) { if (!pdol_data_tlv_data) { PrintAndLogEx(ERR, "Can't create PDOL data."); tlvdb_free(tlvRoot); - DropField(); + DropFieldEx( channel ); return 6; } PrintAndLogEx(INFO, "PDOL data[%d]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len)); @@ -1513,9 +1513,7 @@ int CmdEMVScan(const char *cmd) { if (res) { PrintAndLogEx(ERR, "GPO error(%d): %4x. Exit...", res, sw); tlvdb_free(tlvRoot); - if (channel == ECC_CONTACTLESS) { - DropField(); - } + DropFieldEx( channel ); return 7; } ProcessGPOResponseFormat1(tlvRoot, buf, len, decodeTLV); @@ -1607,9 +1605,7 @@ int CmdEMVScan(const char *cmd) { // free tlv object tlvdb_free(tlvRoot); - if (channel == ECC_CONTACTLESS) { - DropField(); - } + DropFieldEx( channel ); res = json_dump_file(root, fname, JSON_INDENT(2)); if (res) { @@ -1683,7 +1679,7 @@ int CmdEMVRoca(const char *cmd) { if (EMVSearch(channel, false, true, false, tlvSelect)) { PrintAndLogEx(ERR, "Couldn't find any known EMV AID. Exit..."); tlvdb_free(tlvSelect); - DropField(); + DropFieldEx( channel ); return 3; } @@ -1692,16 +1688,14 @@ int CmdEMVRoca(const char *cmd) { } // EMV SELECT application - SetAPDULogging(true); + SetAPDULogging(false); EMVSelectApplication(tlvSelect, AID, &AIDlen); tlvdb_free(tlvSelect); if (!AIDlen) { PrintAndLogEx(INFO, "Can't select AID. EMV AID not found. Exit..."); - if (channel == ECC_CONTACTLESS) { - DropField(); - } + DropFieldEx( channel ); return 4; } @@ -1716,9 +1710,7 @@ int CmdEMVRoca(const char *cmd) { if (res) { PrintAndLogEx(ERR, "Can't select AID (%d). Exit...", res); tlvdb_free(tlvRoot); - if (channel == ECC_CONTACTLESS) { - DropField(); - } + DropFieldEx( channel ); return 5; } @@ -1730,9 +1722,7 @@ int CmdEMVRoca(const char *cmd) { if (!pdol_data_tlv){ PrintAndLogEx(ERR, "Can't create PDOL TLV."); tlvdb_free(tlvRoot); - if (channel == ECC_CONTACTLESS) { - DropField(); - } + DropFieldEx( channel ); return 6; } @@ -1741,7 +1731,7 @@ int CmdEMVRoca(const char *cmd) { if (!pdol_data_tlv_data) { PrintAndLogEx(ERR, "Can't create PDOL data."); tlvdb_free(tlvRoot); - DropField(); + DropFieldEx( channel ); return 6; } PrintAndLogEx(INFO, "PDOL data[%d]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len)); @@ -1755,9 +1745,7 @@ int CmdEMVRoca(const char *cmd) { if (res) { PrintAndLogEx(ERR, "GPO error(%d): %4x. Exit...", res, sw); tlvdb_free(tlvRoot); - if (channel == ECC_CONTACTLESS) { - DropField(); - } + DropFieldEx( channel ); return 7; } ProcessGPOResponseFormat1(tlvRoot, buf, len, false); @@ -1859,10 +1847,7 @@ out: // free tlv object tlvdb_free(tlvRoot); - if (channel == ECC_CONTACTLESS) { - DropField(); - } - + DropFieldEx( channel ); return 0; } diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index 8deb4aa6..93235f5e 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -9,13 +9,27 @@ //----------------------------------------------------------------------------- #include "emvcore.h" + +#include #include "emvjson.h" #include "util_posix.h" #include "protocols.h" +#include "ui.h" +#include "util.h" +#include "emv_tags.h" +#include "emv_pk.h" +#include "emv_pki.h" +#include "cmdhf14a.h" +#include "apduinfo.h" +#include "tlv.h" +#include "dump.h" +#include "dol.h" + #ifdef WITH_SMARTCARD #include "cmdsmartcard.h" #endif + // Got from here. Thanks) // https://eftlab.co.uk/index.php/site-map/knowledge-base/211-emv-aid-rid-pix static const char *PSElist [] = { @@ -129,6 +143,12 @@ void SetAPDULogging(bool logging) { APDULogging = logging; } +void DropFieldEx(EMVCommandChannel channel) { + if (channel == ECC_CONTACTLESS) { + DropField(); + } +} + enum CardPSVendor GetCardPSVendor(uint8_t * AID, size_t AIDlen) { char buf[100] = {0}; if (AIDlen < 1) @@ -267,39 +287,38 @@ struct tlvdb *GetdCVVRawFromTrack2(const struct tlv *track2) { } -static int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *apdu, int apdu_len, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) +int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *apdu, int apdu_len, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { *ResultLen = 0; if (sw) *sw = 0; uint16_t isw = 0; int res = 0; - if (ActivateField && channel == ECC_CONTACTLESS) { - DropField(); + if (ActivateField) { + DropFieldEx( channel ); msleep(50); } if (APDULogging) PrintAndLogEx(SUCCESS, ">>>> %s", sprint_hex(apdu, apdu_len)); +#ifdef WITH_SMARTCARD switch(channel) { case ECC_CONTACTLESS: // 6 byes + data = INS + CLA + P1 + P2 + Lc + + Le(?IncludeLe) res = ExchangeAPDU14a(apdu, apdu_len, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); - if (res) { - return res; - } break; case ECC_CONTACT: - //int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); -#ifdef WITH_SMARTCARD res = ExchangeAPDUSC(apdu, apdu_len, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); - if (res) { - return res; - } -#endif break; } +#else + res = ExchangeAPDU14a(apdu, apdu_len, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); +#endif + + if (res) { + return res; + } if (APDULogging) PrintAndLogEx(SUCCESS, "<<<< %s", sprint_hex(Result, *ResultLen)); @@ -308,13 +327,18 @@ static int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool Lea return 200; } -/* if (Result[*ResultLen-2] == 0x61) { + if (Result[*ResultLen-2] == 0x61) { uint8_t La = Result[*ResultLen-1]; uint8_t get_response[5] = {apdu[0], ISO7816_GET_RESPONSE, 0x00, 0x00, La}; - return EMVExchangeEx(channel, false, LeaveFieldON, get_response, sizeof(get_response), Result, MaxResultLen, ResultLen, sw, tlv); - }*/ + size_t oldlen = *ResultLen; + res = EMVExchangeEx(channel, false, LeaveFieldON, get_response, sizeof(get_response), &Result[oldlen-2], MaxResultLen-oldlen+2, ResultLen, sw, tlv); + *ResultLen += oldlen; + } + + if (res) return res; *ResultLen -= 2; + isw = Result[*ResultLen] * 0x0100 + Result[*ResultLen + 1]; if (sw) *sw = isw; @@ -335,19 +359,18 @@ static int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool Lea return 0; } -int EMVExchange(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *apdu, int apdu_len, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) +static int EMVExchange(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *apdu, int apdu_len, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { uint8_t APDU[APDU_COMMAND_LEN]; memcpy(APDU, apdu, apdu_len); APDU[apdu_len] = 0x00; if (channel == ECC_CONTACTLESS) { - if (apdu_len == 5 && apdu[4] == 0) { - // there is no Lc but an Le == 0 already + if (apdu_len == 5) { + // there is no Lc but an Le already } else if (apdu_len > 5 && apdu_len == 5 + apdu[4] + 1) { // there is Lc, data and Le } else { - if (apdu[1] != 0xc0) - apdu_len++; // no Le, add Le = 0x00 because some vendors require it for contactless + apdu_len++; // no Le, add Le = 0x00 because some vendors require it for contactless } } return EMVExchangeEx(channel, false, LeaveFieldON, APDU, apdu_len, Result, MaxResultLen, ResultLen, sw, tlv); @@ -539,8 +562,8 @@ int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO PrintAndLogEx(WARNING, "%s ERROR: Can't select PPSE AID. Error: %d", PSE_or_PPSE, res); } - if(!LeaveFieldON && channel == ECC_CONTACTLESS) - DropField(); + if (!LeaveFieldON) + DropFieldEx( channel ); return res; } @@ -696,7 +719,7 @@ struct emv_pk *get_ca_pk(struct tlvdb *db) { if (!df_tlv || !caidx_tlv || df_tlv->len < 6 || caidx_tlv->len != 1) return NULL; - PrintAndLogEx(NORMAL, "CA public key index 0x%0x", caidx_tlv->value[0]); + PrintAndLogEx(NORMAL, "CA Public Key index 0x%0x", caidx_tlv->value[0]); return emv_pk_get_ca_pk(df_tlv->value, caidx_tlv->value[0]); } @@ -1016,7 +1039,7 @@ int trCDA(struct tlvdb *tlv, struct tlvdb *ac_tlv, struct tlv *pdol_data_tlv, st struct emv_pk *icc_pk = emv_pki_recover_icc_cert(issuer_pk, tlv, sda_tlv); if (!icc_pk) { - PrintAndLogEx(WARNING, "Error: ICC setrificate not found. Exit."); + PrintAndLogEx(WARNING, "Error: ICC certificate not found. Exit."); emv_pk_free(pk); emv_pk_free(issuer_pk); return 2; diff --git a/client/emv/emvcore.h b/client/emv/emvcore.h index 010315ba..19f26028 100644 --- a/client/emv/emvcore.h +++ b/client/emv/emvcore.h @@ -11,23 +11,10 @@ #ifndef EMVCORE_H__ #define EMVCORE_H__ -#include #include -#include -#include -#include -#include -#include "util.h" -#include "common.h" -#include "ui.h" -#include "cmdhf14a.h" -#include "apduinfo.h" +#include #include "tlv.h" -#include "dol.h" -#include "dump.h" -#include "emv_tags.h" -#include "emv_pk.h" -#include "emv_pki.h" +#include "jansson.h" // maximum APDU lengths. Long APDUs not yet supported/needed #define APDU_DATA_LEN 255 @@ -60,6 +47,8 @@ enum CardPSVendor { }; extern enum CardPSVendor GetCardPSVendor(uint8_t * AID, size_t AIDlen); +extern void DropFieldEx(EMVCommandChannel channel); + extern bool TLVPrintFromBuffer(uint8_t *data, int datalen); extern void TLVPrintFromTLV(struct tlvdb *tlv); extern void TLVPrintFromTLVLev(struct tlvdb *tlv, int level); @@ -71,7 +60,7 @@ extern struct tlvdb *GetdCVVRawFromTrack2(const struct tlv *track2); extern void SetAPDULogging(bool logging); // exchange -extern int EMVExchange(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *APDU, int APDU_len, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); +extern int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *apdu, int apdu_len, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv); // search application extern int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t PSENum, bool decodeTLV, struct tlvdb *tlv); diff --git a/client/fido/cbortools.c b/client/fido/cbortools.c index 01691dad..4674afc9 100644 --- a/client/fido/cbortools.c +++ b/client/fido/cbortools.c @@ -11,7 +11,10 @@ // #include "cbortools.h" + #include +#include + #include "emv/emvjson.h" #include "util.h" #include "fidocore.h" diff --git a/client/fido/fidocore.c b/client/fido/fidocore.c index 5498c9d2..13768b75 100644 --- a/client/fido/fidocore.c +++ b/client/fido/fidocore.c @@ -22,7 +22,10 @@ #include "crypto/libpcrypto.h" #include "fido/additional_ca.h" #include "fido/cose.h" +#include "emv/dump.h" #include "protocols.h" +#include "ui.h" +#include "util.h" typedef struct { @@ -176,22 +179,22 @@ int FIDOSelect(bool ActivateField, bool LeaveFieldON, uint8_t *Result, size_t Ma } int FIDOExchange(uint8_t* apdu, int apdulen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw) { - int res = EMVExchange(ECC_CONTACTLESS, true, apdu, apdulen, Result, MaxResultLen, ResultLen, sw, NULL); - if (res == 5) // apdu result (sw) not a 0x9000 - res = 0; - // software chaining - while (!res && (*sw >> 8) == 0x61) { - uint8_t La = *sw & 0xff; - uint8_t get_response_APDU[5] = {apdu[0], ISO7816_GET_RESPONSE, 0x00, 0x00, La}; - size_t oldlen = *ResultLen; - res = EMVExchange(ECC_CONTACTLESS, true, get_response_APDU, sizeof(get_response_APDU), &Result[oldlen], MaxResultLen - oldlen, ResultLen, sw, NULL); - if (res == 5) // apdu result (sw) not a 0x9000 - res = 0; + int res = EMVExchangeEx(ECC_CONTACTLESS, false, true, apdu, apdulen, Result, MaxResultLen, ResultLen, sw, NULL); + // if (res == 5) // apdu result (sw) not a 0x9000 + // res = 0; + // // software chaining + // while (!res && (*sw >> 8) == 0x61) { + // uint8_t La = *sw & 0xff; + // uint8_t get_response_APDU[5] = {apdu[0], ISO7816_GET_RESPONSE, 0x00, 0x00, La}; + // size_t oldlen = *ResultLen; + // res = EMVExchange(ECC_CONTACTLESS, true, get_response_APDU, sizeof(get_response_APDU), &Result[oldlen], MaxResultLen - oldlen, ResultLen, sw, NULL); + // if (res == 5) // apdu result (sw) not a 0x9000 + // res = 0; - *ResultLen += oldlen; - if (*ResultLen > MaxResultLen) - return 100; - } + // *ResultLen += oldlen; + // if (*ResultLen > MaxResultLen) + // return 100; + // } return res; } diff --git a/client/pcsc.c b/client/pcsc.c index 7d03d052..c54efacc 100644 --- a/client/pcsc.c +++ b/client/pcsc.c @@ -19,7 +19,7 @@ #include #include #define SCARD_ATTR_VALUE(Class, Tag) ((((ULONG)(Class)) << 16) | ((ULONG)(Tag))) -#define SCARD_CLASS_ICC_STATE 9 +#define SCARD_CLASS_ICC_STATE 9 #define SCARD_ATTR_ATR_STRING SCARD_ATTR_VALUE(SCARD_CLASS_ICC_STATE, 0x0303) #elif defined (_WIN32) #include @@ -32,6 +32,8 @@ #include "util.h" #include "cmdhw.h" +#define PM3_SMARTCARD_DEFAULT_NAME "PM3 RDV40 Smartcard Slot" + static SCARDCONTEXT SC_Context; static SCARDHANDLE SC_Card; static DWORD SC_Protocol; @@ -40,7 +42,7 @@ static char* AlternativeSmartcardReader = NULL; char *getAlternativeSmartcardReader(void) { - return AlternativeSmartcardReader; + return AlternativeSmartcardReader ? AlternativeSmartcardReader : PM3_SMARTCARD_DEFAULT_NAME; } @@ -62,7 +64,7 @@ bool pcscCheckForCardReaders(void) SCardReleaseContext(SC_Context); return false; } - + return true; } @@ -70,7 +72,7 @@ bool pcscCheckForCardReaders(void) static char *pickReader(LPTSTR readerlist) { PrintAndLogEx(NORMAL, "Please select one of these:"); - PrintAndLogEx(NORMAL, " [0] PM3 RDV40 Smartcard Slot %s", PM3hasSmartcardSlot() ? "(default)" : "(default, not available)"); + PrintAndLogEx(NORMAL, " [0] %s %s", PM3_SMARTCARD_DEFAULT_NAME, PM3hasSmartcardSlot() ? "(default)" : "(default, not available)"); int num = 1; for (LPTSTR p = readerlist; *p != '\0'; ) { @@ -79,17 +81,17 @@ static char *pickReader(LPTSTR readerlist) } num--; - + if (num == 1) { printf("Your choice (0 or 1)?"); } else { printf("Your choice (0...%d)? ", num); } int selection = getch() - '0'; - printf("\n"); + printf("\n"); if (selection == 0) { - PrintAndLogEx(INFO, "Selected RDV40 Smartcard Slot"); + PrintAndLogEx(INFO, "Selected %s", PM3_SMARTCARD_DEFAULT_NAME); return NULL; } @@ -102,18 +104,58 @@ static char *pickReader(LPTSTR readerlist) return p; } - PrintAndLogEx(INFO, "Invalid selection. Using RDV40 Smartcard Slot"); + PrintAndLogEx(INFO, "Invalid selection. Using %s", PM3_SMARTCARD_DEFAULT_NAME); return NULL; - + } -char *matchString(LPTSTR readerlist, const char *readername) +static bool matchString(char *string, const char *search) { - return pickReader(readerlist); + if (search[0] == '*' && search[1] == '\0') { // the wildcard only string "*" matches everything + return true; + } + + if (search[0] == '\0' && string[0] != '\0') { // string is longer than pattern. No match. + return false; + } + + if (search[0] == '?' || search[0] == string[0]) { // wildcard '?' matches any character + return matchString(string + 1, search + 1); + } + + if (search[0] == '*') { // wildcard '*' matches any sequence of characters + for (size_t i = 0; i < strlen(string); i++) { + if (matchString(string + i, search + 1)) { + return true; + } + } + } + + return false; } - + +static char *matchReader(LPTSTR readerlist, const char *readername) +{ + if (matchString(PM3_SMARTCARD_DEFAULT_NAME, readername)) { + PrintAndLogEx(INFO, "Selected %s", PM3_SMARTCARD_DEFAULT_NAME); + return NULL; + } + + for (LPTSTR p = readerlist; *p != '\0'; ) { + if (matchString(p, readername)) { + PrintAndLogEx(INFO, "Selected %s", p); + return p; + } + while (*p++ != '\0') ; // advance to next entry + } + + PrintAndLogEx(INFO, "No match. Using %s", PM3_SMARTCARD_DEFAULT_NAME); + return NULL; +} + + bool pcscSelectAlternativeCardReader(const char *readername) { DWORD readerlist_len; @@ -131,7 +173,7 @@ bool pcscSelectAlternativeCardReader(const char *readername) char *selected_readername = NULL; if (readername) { - selected_readername = matchString(readerlist, readername); + selected_readername = matchReader(readerlist, readername); } else { selected_readername = pickReader(readerlist); } @@ -144,7 +186,8 @@ bool pcscSelectAlternativeCardReader(const char *readername) free(AlternativeSmartcardReader); AlternativeSmartcardReader = malloc((strlen(selected_readername) + 1) * sizeof(char)); strcpy(AlternativeSmartcardReader, selected_readername); - + + free(readerlist); return true; } @@ -154,7 +197,7 @@ bool pcscGetATR(smart_card_atr_t *card) if (!card) { return false; } - + card->atr_len = 0; memset(card->atr, 0, sizeof(card->atr)); @@ -170,10 +213,10 @@ bool pcscGetATR(smart_card_atr_t *card) return false; } card->atr_len = atr_len; - + // TODO: LogTrace without device - - return true; + + return true; } @@ -192,7 +235,7 @@ void pcscTransmit(uint8_t *data, uint32_t data_len, uint32_t flags, uint8_t *res // set_tracing(true); - if ((flags & SC_CONNECT || flags & SC_SELECT)) { + if ((flags & SC_CONNECT || flags & SC_SELECT)) { LONG res = SCardConnect(SC_Context, AlternativeSmartcardReader, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &SC_Card, &SC_Protocol); if (res != SCARD_S_SUCCESS) { @@ -200,7 +243,7 @@ void pcscTransmit(uint8_t *data, uint32_t data_len, uint32_t flags, uint8_t *res return; } } - + if ((flags & SC_RAW) || (flags & SC_RAW_T0)) { // TODO: tracing // LogTrace(data, arg1, 0, 0, NULL, true); From c719d385ef376c848eb881565af23a8e304362d7 Mon Sep 17 00:00:00 2001 From: Oleg Moiseenko <807634+merlokk@users.noreply.github.com> Date: Sat, 9 Feb 2019 23:38:09 +0200 Subject: [PATCH 062/189] fix endless loop (#782) --- armsrc/iso14443a.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index f5fcc91c..50160798 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -1955,7 +1955,7 @@ int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data, uint8_t *res) { return 0; //DATA LINK ERROR } else{ // S-Block WTX - while((data_bytes[0] & 0xF2) == 0xF2) { + while(len && ((data_bytes[0] & 0xF2) == 0xF2)) { uint32_t save_iso14a_timeout = iso14a_get_timeout(); // temporarily increase timeout iso14a_set_timeout(MAX((data_bytes[1] & 0x3f) * save_iso14a_timeout, MAX_ISO14A_TIMEOUT)); @@ -1994,12 +1994,14 @@ int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data, uint8_t *res) { } - // cut frame byte - len -= 1; - // memmove(data_bytes, data_bytes + 1, len); - for (int i = 0; i < len; i++) - data_bytes[i] = data_bytes[i + 1]; - + if (len) { + // cut frame byte + len -= 1; + // memmove(data_bytes, data_bytes + 1, len); + for (int i = 0; i < len; i++) + data_bytes[i] = data_bytes[i + 1]; + } + return len; } From 3783c45af1ec1f478c3f17e8d75522a3043ad955 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Tue, 12 Feb 2019 09:06:30 +0100 Subject: [PATCH 063/189] fix emv roca hash error (#781) * fix ICC Public Key Hash calculation * add -a option to 'emv roca' * replace print() by PrintAndLogEx() in emv_pki.c --- client/emv/cmdemv.c | 573 +++++++++++++++++++++++-------------------- client/emv/emv_pk.c | 2 +- client/emv/emv_pki.c | 65 ++--- 3 files changed, 337 insertions(+), 303 deletions(-) diff --git a/client/emv/cmdemv.c b/client/emv/cmdemv.c index abb84d43..7e29b584 100644 --- a/client/emv/cmdemv.c +++ b/client/emv/cmdemv.c @@ -69,8 +69,8 @@ int CmdEMVSelect(const char *cmd) { uint8_t data[APDU_DATA_LEN] = {0}; int datalen = 0; - CLIParserInit("emv select", - "Executes select applet command", + CLIParserInit("emv select", + "Executes select applet command", "Usage:\n\temv select -s a00000000101 -> select card, select applet\n\temv select -st a00000000101 -> select card, select applet, show result in TLV\n"); void* argtable[] = { @@ -86,7 +86,7 @@ int CmdEMVSelect(const char *cmd) { arg_param_end }; CLIExecWithReturn(cmd, argtable, true); - + bool activateField = arg_get_lit(1); bool leaveSignalON = arg_get_lit(2); bool APDULogging = arg_get_lit(3); @@ -101,9 +101,9 @@ int CmdEMVSelect(const char *cmd) { CLIGetHexWithReturn(5, data, &datalen); #endif CLIParserFree(); - + SetAPDULogging(APDULogging); - + // exec uint8_t buf[APDU_RESPONSE_LEN] = {0}; size_t len = 0; @@ -111,11 +111,11 @@ int CmdEMVSelect(const char *cmd) { int res = EMVSelect(channel, activateField, leaveSignalON, data, datalen, buf, sizeof(buf), &len, &sw, NULL); if (sw) - PrintAndLogEx(INFO, "APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - + PrintAndLogEx(INFO, "APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + if (res) return res; - + if (decodeTLV) TLVPrintFromBuffer(buf, len); @@ -124,8 +124,8 @@ int CmdEMVSelect(const char *cmd) { int CmdEMVSearch(const char *cmd) { - CLIParserInit("emv search", - "Tries to select all applets from applet list:\n", + CLIParserInit("emv search", + "Tries to select all applets from applet list:\n", "Usage:\n\temv search -s -> select card and search\n\temv search -st -> select card, search and show result in TLV\n"); void* argtable[] = { @@ -140,21 +140,21 @@ int CmdEMVSearch(const char *cmd) { arg_param_end }; CLIExecWithReturn(cmd, argtable, true); - + bool activateField = arg_get_lit(1); bool leaveSignalON = arg_get_lit(2); bool APDULogging = arg_get_lit(3); bool decodeTLV = arg_get_lit(4); EMVCommandChannel channel = ECC_CONTACTLESS; -#ifdef WITH_SMARTCARD +#ifdef WITH_SMARTCARD if (arg_get_lit(5)) channel = ECC_CONTACT; #endif PrintChannel(channel); CLIParserFree(); - + SetAPDULogging(APDULogging); - + struct tlvdb *t = NULL; const char *al = "Applets list"; t = tlvdb_fixed(1, strlen(al), (const unsigned char *)al); @@ -163,23 +163,23 @@ int CmdEMVSearch(const char *cmd) { tlvdb_free(t); return 2; } - + PrintAndLogEx(SUCCESS, "Search completed."); // print list here - if (!decodeTLV) { + if (!decodeTLV) { TLVPrintAIDlistFromSelectTLV(t); } - + tlvdb_free(t); - + return 0; } int CmdEMVPPSE(const char *cmd) { - - CLIParserInit("emv pse", - "Executes PSE/PPSE select command. It returns list of applet on the card:\n", + + CLIParserInit("emv pse", + "Executes PSE/PPSE select command. It returns list of applet on the card:\n", "Usage:\n\temv pse -s1 -> select, get pse\n\temv pse -st2 -> select, get ppse, show result in TLV\n"); void* argtable[] = { @@ -196,7 +196,7 @@ int CmdEMVPPSE(const char *cmd) { arg_param_end }; CLIExecWithReturn(cmd, argtable, true); - + bool activateField = arg_get_lit(1); bool leaveSignalON = arg_get_lit(2); uint8_t PSENum = 2; @@ -212,23 +212,23 @@ int CmdEMVPPSE(const char *cmd) { channel = ECC_CONTACT; #endif PrintChannel(channel); - CLIParserFree(); - + CLIParserFree(); + SetAPDULogging(APDULogging); - + // exec uint8_t buf[APDU_RESPONSE_LEN] = {0}; size_t len = 0; uint16_t sw = 0; int res = EMVSelectPSE(channel, activateField, leaveSignalON, PSENum, buf, sizeof(buf), &len, &sw); - + if (sw) - PrintAndLogEx(INFO, "APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + PrintAndLogEx(INFO, "APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); if (res) return res; - - + + if (decodeTLV) TLVPrintFromBuffer(buf, len); @@ -239,11 +239,11 @@ int CmdEMVGPO(const char *cmd) { uint8_t data[APDU_RESPONSE_LEN] = {0}; int datalen = 0; - CLIParserInit("emv gpo", - "Executes Get Processing Options command. It returns data in TLV format (0x77 - format2) or plain format (0x80 - format1).\nNeeds a EMV applet to be selected.", + CLIParserInit("emv gpo", + "Executes Get Processing Options command. It returns data in TLV format (0x77 - format2) or plain format (0x80 - format1).\nNeeds a EMV applet to be selected.", "Usage:\n\temv gpo -k -> execute GPO\n" "\temv gpo -t 01020304 -> execute GPO with 4-byte PDOL data, show result in TLV\n" - "\temv gpo -pmt 9F 37 04 -> load params from file, make PDOL data from PDOL, execute GPO with PDOL, show result in TLV\n"); + "\temv gpo -pmt 9F 37 04 -> load params from file, make PDOL data from PDOL, execute GPO with PDOL, show result in TLV\n"); void* argtable[] = { arg_param_begin, @@ -259,7 +259,7 @@ int CmdEMVGPO(const char *cmd) { arg_param_end }; CLIExecWithReturn(cmd, argtable, true); - + bool leaveSignalON = arg_get_lit(1); bool paramsLoadFromFile = arg_get_lit(2); bool dataMakeFromPDOL = arg_get_lit(3); @@ -274,14 +274,14 @@ int CmdEMVGPO(const char *cmd) { CLIGetHexWithReturn(6, data, &datalen); #endif PrintChannel(channel); - CLIParserFree(); - + CLIParserFree(); + SetAPDULogging(APDULogging); - + // Init TLV tree const char *alr = "Root terminal TLV tree"; struct tlvdb *tlvRoot = tlvdb_fixed(1, strlen(alr), (const unsigned char *)alr); - + // calc PDOL struct tlv *pdol_data_tlv = NULL; struct tlv data_tlv = { @@ -296,7 +296,7 @@ int CmdEMVGPO(const char *cmd) { PrintAndLogEx(INFO, "Params loading from file..."); ParamLoadFromJson(tlvRoot); }; - + pdol_data_tlv = dol_process((const struct tlv *)tlvdb_external(0x9f38, datalen, data), tlvRoot, 0x83); if (!pdol_data_tlv){ PrintAndLogEx(ERR, "Can't create PDOL TLV."); @@ -318,23 +318,23 @@ int CmdEMVGPO(const char *cmd) { return 4; } PrintAndLogEx(INFO, "PDOL data[%d]: %s", pdol_data_tlv_data_len, sprint_hex(pdol_data_tlv_data, pdol_data_tlv_data_len)); - + // exec uint8_t buf[APDU_RESPONSE_LEN] = {0}; size_t len = 0; uint16_t sw = 0; int res = EMVGPO(channel, leaveSignalON, pdol_data_tlv_data, pdol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot); - + if (pdol_data_tlv != &data_tlv) free(pdol_data_tlv); tlvdb_free(tlvRoot); - + if (sw) - PrintAndLogEx(INFO, "APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + PrintAndLogEx(INFO, "APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); if (res) return res; - + if (decodeTLV) TLVPrintFromBuffer(buf, len); @@ -345,8 +345,8 @@ int CmdEMVReadRecord(const char *cmd) { uint8_t data[APDU_RESPONSE_LEN] = {0}; int datalen = 0; - CLIParserInit("emv readrec", - "Executes Read Record command. It returns data in TLV format.\nNeeds a bank applet to be selected and sometimes needs GPO to be executed.", + CLIParserInit("emv readrec", + "Executes Read Record command. It returns data in TLV format.\nNeeds a bank applet to be selected and sometimes needs GPO to be executed.", "Usage:\n\temv readrec -k 0101 -> read file SFI=01, SFIrec=01\n\temv readrec -kt 0201-> read file 0201 and show result in TLV\n"); void* argtable[] = { @@ -359,7 +359,7 @@ int CmdEMVReadRecord(const char *cmd) { arg_param_end }; CLIExecWithReturn(cmd, argtable, true); - + bool leaveSignalON = arg_get_lit(1); bool APDULogging = arg_get_lit(2); bool decodeTLV = arg_get_lit(3); @@ -373,27 +373,27 @@ int CmdEMVReadRecord(const char *cmd) { #endif PrintChannel(channel); CLIParserFree(); - + if (datalen != 2) { PrintAndLogEx(ERR, "Command needs to have 2 bytes of data"); return 1; } - + SetAPDULogging(APDULogging); - + // exec uint8_t buf[APDU_RESPONSE_LEN] = {0}; size_t len = 0; uint16_t sw = 0; int res = EMVReadRecord(channel, leaveSignalON, data[0], data[1], buf, sizeof(buf), &len, &sw, NULL); - + if (sw) - PrintAndLogEx(INFO, "APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + PrintAndLogEx(INFO, "APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); if (res) return res; - - + + if (decodeTLV) TLVPrintFromBuffer(buf, len); @@ -404,12 +404,12 @@ int CmdEMVAC(const char *cmd) { uint8_t data[APDU_RESPONSE_LEN] = {0}; int datalen = 0; - CLIParserInit("emv genac", - "Generate Application Cryptogram command. It returns data in TLV format .\nNeeds a EMV applet to be selected and GPO to be executed.", + CLIParserInit("emv genac", + "Generate Application Cryptogram command. It returns data in TLV format .\nNeeds a EMV applet to be selected and GPO to be executed.", "Usage:\n\temv genac -k 0102 -> generate AC with 2-byte CDOLdata and keep field ON after command\n" "\temv genac -t 01020304 -> generate AC with 4-byte CDOL data, show result in TLV\n" "\temv genac -Daac 01020304 -> generate AC with 4-byte CDOL data and terminal decision 'declined'\n" - "\temv genac -pmt 9F 37 04 -> load params from file, make CDOL data from CDOL, generate AC with CDOL, show result in TLV"); + "\temv genac -pmt 9F 37 04 -> load params from file, make CDOL data from CDOL, generate AC with CDOL, show result in TLV"); void* argtable[] = { arg_param_begin, @@ -427,7 +427,7 @@ int CmdEMVAC(const char *cmd) { arg_param_end }; CLIExecWithReturn(cmd, argtable, false); - + bool leaveSignalON = arg_get_lit(1); bool trTypeCDA = arg_get_lit(2); uint8_t termDecision = 0xff; @@ -461,14 +461,14 @@ int CmdEMVAC(const char *cmd) { CLIGetHexWithReturn(8, data, &datalen); #endif PrintChannel(channel); - CLIParserFree(); - + CLIParserFree(); + SetAPDULogging(APDULogging); - + // Init TLV tree const char *alr = "Root terminal TLV tree"; struct tlvdb *tlvRoot = tlvdb_fixed(1, strlen(alr), (const unsigned char *)alr); - + // calc CDOL struct tlv *cdol_data_tlv = NULL; struct tlv data_tlv = { @@ -476,7 +476,7 @@ int CmdEMVAC(const char *cmd) { .len = datalen, .value = (uint8_t *)data, }; - + if (dataMakeFromCDOL) { ParamLoadDefaults(tlvRoot); @@ -484,7 +484,7 @@ int CmdEMVAC(const char *cmd) { PrintAndLogEx(INFO, "Params loading from file..."); ParamLoadFromJson(tlvRoot); }; - + cdol_data_tlv = dol_process((const struct tlv *)tlvdb_external(0x8c, datalen, data), tlvRoot, 0x01); // 0x01 - dummy tag if (!cdol_data_tlv){ PrintAndLogEx(ERR, "Can't create CDOL TLV."); @@ -497,7 +497,7 @@ int CmdEMVAC(const char *cmd) { } cdol_data_tlv = &data_tlv; } - + PrintAndLogEx(INFO, "CDOL data[%d]: %s", cdol_data_tlv->len, sprint_hex(cdol_data_tlv->value, cdol_data_tlv->len)); // exec @@ -505,27 +505,27 @@ int CmdEMVAC(const char *cmd) { size_t len = 0; uint16_t sw = 0; int res = EMVAC(channel, leaveSignalON, termDecision, (uint8_t *)cdol_data_tlv->value, cdol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot); - + if (cdol_data_tlv != &data_tlv) free(cdol_data_tlv); tlvdb_free(tlvRoot); - + if (sw) - PrintAndLogEx(INFO, "APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + PrintAndLogEx(INFO, "APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); if (res) return res; - + if (decodeTLV) TLVPrintFromBuffer(buf, len); - return 0; + return 0; } int CmdEMVGenerateChallenge(const char *cmd) { - CLIParserInit("emv challenge", - "Executes Generate Challenge command. It returns 4 or 8-byte random number from card.\nNeeds a EMV applet to be selected and GPO to be executed.", + CLIParserInit("emv challenge", + "Executes Generate Challenge command. It returns 4 or 8-byte random number from card.\nNeeds a EMV applet to be selected and GPO to be executed.", "Usage:\n\temv challenge -> get challenge\n\temv challenge -k -> get challenge, keep fileld ON\n"); void* argtable[] = { @@ -538,7 +538,7 @@ int CmdEMVGenerateChallenge(const char *cmd) { arg_param_end }; CLIExecWithReturn(cmd, argtable, true); - + bool leaveSignalON = arg_get_lit(1); bool APDULogging = arg_get_lit(2); EMVCommandChannel channel = ECC_CONTACTLESS; @@ -547,27 +547,27 @@ int CmdEMVGenerateChallenge(const char *cmd) { channel = ECC_CONTACT; #endif PrintChannel(channel); - CLIParserFree(); - + CLIParserFree(); + SetAPDULogging(APDULogging); - + // exec uint8_t buf[APDU_RESPONSE_LEN] = {0}; size_t len = 0; uint16_t sw = 0; int res = EMVGenerateChallenge(channel, leaveSignalON, buf, sizeof(buf), &len, &sw, NULL); - + if (sw) - PrintAndLogEx(INFO, "APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + PrintAndLogEx(INFO, "APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); if (res) return res; PrintAndLogEx(SUCCESS, "Challenge: %s", sprint_hex(buf, len)); - + if (len != 4 && len != 8) PrintAndLogEx(WARNING, "Length of challenge must be 4 or 8, but it %d", len); - + return 0; } @@ -575,14 +575,14 @@ int CmdEMVInternalAuthenticate(const char *cmd) { uint8_t data[APDU_RESPONSE_LEN] = {0}; int datalen = 0; - CLIParserInit("emv intauth", + CLIParserInit("emv intauth", "Generate Internal Authenticate command. Usually needs 4-byte random number. It returns data in TLV format .\n" - "Needs a EMV applet to be selected and GPO to be executed.", - + "Needs a EMV applet to be selected and GPO to be executed.", + "Usage:\n" "\temv intauth -k 01020304 -> execute Internal Authenticate with 4-byte DDOLdata and keep field ON after command\n" "\temv intauth -t 01020304 -> execute Internal Authenticate with 4-byte DDOL data, show result in TLV\n" - "\temv intauth -pmt 9F 37 04 -> load params from file, make DDOL data from DDOL, Internal Authenticate with DDOL, show result in TLV"); + "\temv intauth -pmt 9F 37 04 -> load params from file, make DDOL data from DDOL, Internal Authenticate with DDOL, show result in TLV"); void* argtable[] = { arg_param_begin, @@ -598,7 +598,7 @@ int CmdEMVInternalAuthenticate(const char *cmd) { arg_param_end }; CLIExecWithReturn(cmd, argtable, false); - + bool leaveSignalON = arg_get_lit(1); bool paramsLoadFromFile = arg_get_lit(2); bool dataMakeFromDDOL = arg_get_lit(3); @@ -613,14 +613,14 @@ int CmdEMVInternalAuthenticate(const char *cmd) { CLIGetHexWithReturn(6, data, &datalen); #endif PrintChannel(channel); - CLIParserFree(); - + CLIParserFree(); + SetAPDULogging(APDULogging); // Init TLV tree const char *alr = "Root terminal TLV tree"; struct tlvdb *tlvRoot = tlvdb_fixed(1, strlen(alr), (const unsigned char *)alr); - + // calc DDOL struct tlv *ddol_data_tlv = NULL; struct tlv data_tlv = { @@ -628,7 +628,7 @@ int CmdEMVInternalAuthenticate(const char *cmd) { .len = datalen, .value = (uint8_t *)data, }; - + if (dataMakeFromDDOL) { ParamLoadDefaults(tlvRoot); @@ -636,7 +636,7 @@ int CmdEMVInternalAuthenticate(const char *cmd) { PrintAndLogEx(INFO, "Params loading from file..."); ParamLoadFromJson(tlvRoot); }; - + ddol_data_tlv = dol_process((const struct tlv *)tlvdb_external(0x9f49, datalen, data), tlvRoot, 0x01); // 0x01 - dummy tag if (!ddol_data_tlv){ PrintAndLogEx(ERR, "Can't create DDOL TLV."); @@ -649,42 +649,42 @@ int CmdEMVInternalAuthenticate(const char *cmd) { } ddol_data_tlv = &data_tlv; } - + PrintAndLogEx(INFO, "DDOL data[%d]: %s", ddol_data_tlv->len, sprint_hex(ddol_data_tlv->value, ddol_data_tlv->len)); - + // exec uint8_t buf[APDU_RESPONSE_LEN] = {0}; size_t len = 0; uint16_t sw = 0; int res = EMVInternalAuthenticate(channel, leaveSignalON, data, datalen, buf, sizeof(buf), &len, &sw, NULL); - + if (ddol_data_tlv != &data_tlv) free(ddol_data_tlv); - tlvdb_free(tlvRoot); - + tlvdb_free(tlvRoot); + if (sw) - PrintAndLogEx(INFO, "APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + PrintAndLogEx(INFO, "APDU response status: %04x - %s", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); if (res) return res; - + if (decodeTLV) TLVPrintFromBuffer(buf, len); - return 0; + return 0; } #define dreturn(n) {free(pdol_data_tlv); tlvdb_free(tlvSelect); tlvdb_free(tlvRoot); DropFieldEx( channel ); return n;} void InitTransactionParameters(struct tlvdb *tlvRoot, bool paramLoadJSON, enum TransactionType TrType, bool GenACGPO) { - + ParamLoadDefaults(tlvRoot); if (paramLoadJSON) { PrintAndLog("* * Transaction parameters loading from JSON..."); ParamLoadFromJson(tlvRoot); } - + //9F66:(Terminal Transaction Qualifiers (TTQ)) len:4 char *qVSDC = "\x26\x00\x00\x00"; if (GenACGPO) { @@ -695,7 +695,7 @@ void InitTransactionParameters(struct tlvdb *tlvRoot, bool paramLoadJSON, enum T TLV_ADD(0x9F66, "\x86\x00\x00\x00"); // MSD break; // not standard for contactless. just for test. - case TT_VSDC: + case TT_VSDC: TLV_ADD(0x9F66, "\x46\x00\x00\x00"); // VSDC break; case TT_QVSDCMCHIP: @@ -715,7 +715,7 @@ void ProcessGPOResponseFormat1(struct tlvdb *tlvRoot, uint8_t *buf, size_t len, PrintAndLog("GPO response format1:"); TLVPrintFromBuffer(buf, len); } - + if (len < 4 || (len - 4) % 4) { PrintAndLogEx(ERR, "GPO response format1 parsing error. length=%d", len); } else { @@ -732,7 +732,7 @@ void ProcessGPOResponseFormat1(struct tlvdb *tlvRoot, uint8_t *buf, size_t len, tlvdb_add(tlvRoot, f1AFL); if (decodeTLV) TLVPrintFromTLV(f1AFL); - } + } } else { if (decodeTLV) TLVPrintFromBuffer(buf, len); @@ -745,38 +745,38 @@ void ProcessACResponseFormat1(struct tlvdb *tlvRoot, uint8_t *buf, size_t len, b PrintAndLog("GPO response format1:"); TLVPrintFromBuffer(buf, len); } - + uint8_t elmlen = len - 2; // wo 0x80XX - + if (len < 4 + 2 || (elmlen - 2) % 4 || elmlen != buf[1]) { PrintAndLogEx(ERR, "GPO response format1 parsing error. length=%d", len); } else { struct tlvdb *tlvElm = NULL; if (decodeTLV) PrintAndLog("\n------------ Format1 decoded ------------"); - + // CID (Cryptogram Information Data) tlvdb_change_or_add_node_ex(tlvRoot, 0x9f27, 1, &buf[2], &tlvElm); if (decodeTLV) TLVPrintFromTLV(tlvElm); // ATC (Application Transaction Counter) - tlvdb_change_or_add_node_ex(tlvRoot, 0x9f36, 2, &buf[3], &tlvElm); + tlvdb_change_or_add_node_ex(tlvRoot, 0x9f36, 2, &buf[3], &tlvElm); if (decodeTLV) TLVPrintFromTLV(tlvElm); // AC (Application Cryptogram) - tlvdb_change_or_add_node_ex(tlvRoot, 0x9f26, MIN(8, elmlen - 3), &buf[5], &tlvElm); + tlvdb_change_or_add_node_ex(tlvRoot, 0x9f26, MIN(8, elmlen - 3), &buf[5], &tlvElm); if (decodeTLV) TLVPrintFromTLV(tlvElm); // IAD (Issuer Application Data) - optional if (len > 11 + 2) { - tlvdb_change_or_add_node_ex(tlvRoot, 0x9f10, elmlen - 11, &buf[13], &tlvElm); + tlvdb_change_or_add_node_ex(tlvRoot, 0x9f10, elmlen - 11, &buf[13], &tlvElm); if (decodeTLV) TLVPrintFromTLV(tlvElm); - } - } + } + } } else { if (decodeTLV) TLVPrintFromBuffer(buf, len); @@ -791,15 +791,15 @@ int CmdEMVExec(const char *cmd) { size_t AIDlen = 0; uint8_t ODAiList[4096]; size_t ODAiListLen = 0; - + int res; - + struct tlvdb *tlvSelect = NULL; struct tlvdb *tlvRoot = NULL; struct tlv *pdol_data_tlv = NULL; - CLIParserInit("emv exec", - "Executes EMV contactless transaction", + CLIParserInit("emv exec", + "Executes EMV contactless transaction", "Usage:\n" "\temv exec -sat -> select card, execute MSD transaction, show APDU and TLV\n" "\temv exec -satc -> select card, execute CDA transaction, show APDU and TLV\n"); @@ -820,7 +820,7 @@ int CmdEMVExec(const char *cmd) { arg_param_end }; CLIExecWithReturn(cmd, argtable, true); - + bool activateField = arg_get_lit(1); bool showAPDU = arg_get_lit(2); bool decodeTLV = arg_get_lit(3); @@ -844,11 +844,11 @@ int CmdEMVExec(const char *cmd) { PrintChannel(channel); uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2; char *PSE_or_PPSE = psenum == 1 ? "PSE" : "PPSE"; - + CLIParserFree(); - + SetAPDULogging(showAPDU); - + // init applets list tree const char *al = "Applets list"; tlvSelect = tlvdb_fixed(1, strlen(al), (const unsigned char *)al); @@ -862,12 +862,12 @@ int CmdEMVExec(const char *cmd) { res = EMVSearchPSE(channel, activateField, true, psenum, decodeTLV, tlvSelect); // check PPSE / PSE and select application id - if (!res) { + if (!res) { TLVPrintAIDlistFromSelectTLV(tlvSelect); EMVSelectApplication(tlvSelect, AID, &AIDlen); } } - + // Search if (!AIDlen) { PrintAndLogEx(NORMAL, "\n* Search AID in list."); @@ -880,42 +880,42 @@ int CmdEMVExec(const char *cmd) { TLVPrintAIDlistFromSelectTLV(tlvSelect); EMVSelectApplication(tlvSelect, AID, &AIDlen); } - + // Init TLV tree const char *alr = "Root terminal TLV tree"; tlvRoot = tlvdb_fixed(1, strlen(alr), (const unsigned char *)alr); - + // check if we found EMV application on card if (!AIDlen) { PrintAndLogEx(WARNING, "Can't select AID. EMV AID not found"); dreturn(2); } - + // Select PrintAndLogEx(NORMAL, "\n* Selecting AID:%s", sprint_hex_inrow(AID, AIDlen)); SetAPDULogging(showAPDU); res = EMVSelect(channel, false, true, AID, AIDlen, buf, sizeof(buf), &len, &sw, tlvRoot); - - if (res) { + + if (res) { PrintAndLogEx(WARNING, "Can't select AID (%d). Exit...", res); dreturn(3); } - + if (decodeTLV) TLVPrintFromBuffer(buf, len); PrintAndLogEx(INFO, "* Selected."); - + PrintAndLogEx(INFO, "\n* Init transaction parameters."); InitTransactionParameters(tlvRoot, paramLoadJSON, TrType, GenACGPO); TLVPrintFromTLV(tlvRoot); // TODO delete!!! - + PrintAndLogEx(NORMAL, "\n* Calc PDOL."); pdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x9f38, NULL), tlvRoot, 0x83); if (!pdol_data_tlv){ PrintAndLogEx(WARNING, "Error: can't create PDOL TLV."); dreturn(4); } - + size_t pdol_data_tlv_data_len; unsigned char *pdol_data_tlv_data = tlv_encode(pdol_data_tlv, &pdol_data_tlv_data_len); if (!pdol_data_tlv_data) { @@ -926,40 +926,40 @@ int CmdEMVExec(const char *cmd) { PrintAndLogEx(NORMAL, "\n* GPO."); res = EMVGPO(channel, true, pdol_data_tlv_data, pdol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot); - + free(pdol_data_tlv_data); //free(pdol_data_tlv); --- free on exit. - - if (res) { + + if (res) { PrintAndLogEx(NORMAL, "GPO error(%d): %4x. Exit...", res, sw); dreturn(5); } // process response template format 1 [id:80 2b AIP + x4b AFL] and format 2 [id:77 TLV] ProcessGPOResponseFormat1(tlvRoot, buf, len, decodeTLV); - + // extract PAN from track2 { const struct tlv *track2 = tlvdb_get(tlvRoot, 0x57, NULL); if (!tlvdb_get(tlvRoot, 0x5a, NULL) && track2 && track2->len >= 8) { struct tlvdb *pan = GetPANFromTrack2(track2); if (pan) { - tlvdb_add(tlvRoot, pan); - - const struct tlv *pantlv = tlvdb_get(tlvRoot, 0x5a, NULL); + tlvdb_add(tlvRoot, pan); + + const struct tlv *pantlv = tlvdb_get(tlvRoot, 0x5a, NULL); PrintAndLogEx(NORMAL, "\n* * Extracted PAN from track2: %s", sprint_hex(pantlv->value, pantlv->len)); } else { PrintAndLogEx(NORMAL, "\n* * WARNING: Can't extract PAN from track2."); } } } - + PrintAndLogEx(NORMAL, "\n* Read records from AFL."); const struct tlv *AFL = tlvdb_get(tlvRoot, 0x94, NULL); if (!AFL || !AFL->len) { PrintAndLogEx(WARNING, "AFL not found."); } - + while(AFL && AFL->len) { if (AFL->len % 4) { PrintAndLogEx(WARNING, "Error: Wrong AFL length: %d", AFL->len); @@ -971,27 +971,27 @@ int CmdEMVExec(const char *cmd) { uint8_t SFIstart = AFL->value[i * 4 + 1]; uint8_t SFIend = AFL->value[i * 4 + 2]; uint8_t SFIoffline = AFL->value[i * 4 + 3]; - + PrintAndLogEx(NORMAL, "* * SFI[%02x] start:%02x end:%02x offline count:%02x", SFI, SFIstart, SFIend, SFIoffline); if (SFI == 0 || SFI == 31 || SFIstart == 0 || SFIstart > SFIend) { PrintAndLogEx(NORMAL, "SFI ERROR! Skipped..."); continue; } - + for(int n = SFIstart; n <= SFIend; n++) { PrintAndLogEx(NORMAL, "* * * SFI[%02x] %d", SFI, n); - + res = EMVReadRecord(channel, true, SFI, n, buf, sizeof(buf), &len, &sw, tlvRoot); if (res) { PrintAndLogEx(WARNING, "Error SFI[%02x]. APDU error %4x", SFI, sw); continue; } - + if (decodeTLV) { TLVPrintFromBuffer(buf, len); PrintAndLogEx(NORMAL, ""); } - + // Build Input list for Offline Data Authentication // EMV 4.3 book3 10.3, page 96 if (SFIoffline > 0) { @@ -1009,25 +1009,25 @@ int CmdEMVExec(const char *cmd) { memcpy(&ODAiList[ODAiListLen], buf, len); ODAiListLen += len; } - + SFIoffline--; } } } - + break; - } - + } + // copy Input list for Offline Data Authentication if (ODAiListLen) { struct tlvdb *oda = tlvdb_fixed(0x21, ODAiListLen, ODAiList); // not a standard tag - tlvdb_add(tlvRoot, oda); + tlvdb_add(tlvRoot, oda); PrintAndLogEx(NORMAL, "* Input list for Offline Data Authentication added to TLV. len=%d \n", ODAiListLen); } - + // get AIP uint16_t AIP = 0; - const struct tlv *AIPtlv = tlvdb_get(tlvRoot, 0x82, NULL); + const struct tlv *AIPtlv = tlvdb_get(tlvRoot, 0x82, NULL); if (AIPtlv) { AIP = AIPtlv->value[0] + AIPtlv->value[1] * 0x100; PrintAndLogEx(NORMAL, "* * AIP=%04x", AIP); @@ -1045,10 +1045,10 @@ int CmdEMVExec(const char *cmd) { if (AIP & 0x0020) { PrintAndLogEx(NORMAL, "\n* DDA"); trDDA(channel, decodeTLV, tlvRoot); - } - + } + // transaction check - + // qVSDC if (TrType == TT_QVSDCMCHIP|| TrType == TT_CDA){ // 9F26: Application Cryptogram @@ -1056,11 +1056,11 @@ int CmdEMVExec(const char *cmd) { if (AC) { PrintAndLogEx(NORMAL, "\n--> qVSDC transaction."); PrintAndLogEx(NORMAL, "* AC path"); - + // 9F36: Application Transaction Counter (ATC) const struct tlv *ATC = tlvdb_get(tlvRoot, 0x9F36, NULL); if (ATC) { - + // 9F10: Issuer Application Data - optional const struct tlv *IAD = tlvdb_get(tlvRoot, 0x9F10, NULL); @@ -1069,7 +1069,7 @@ int CmdEMVExec(const char *cmd) { PrintAndLogEx(NORMAL, "AC: %s", sprint_hex(AC->value, AC->len)); if (IAD){ PrintAndLogEx(NORMAL, "IAD: %s", sprint_hex(IAD->value, IAD->len)); - + if (IAD->len >= IAD->value[0] + 1) { PrintAndLogEx(NORMAL, "\tKey index: 0x%02x", IAD->value[1]); PrintAndLogEx(NORMAL, "\tCrypto ver: 0x%02x(%03d)", IAD->value[2], IAD->value[2]); @@ -1080,13 +1080,13 @@ int CmdEMVExec(const char *cmd) { } else { PrintAndLogEx(WARNING, "IAD not found."); } - + } else { PrintAndLogEx(ERR, "AC: Application Transaction Counter (ATC) not found."); } } } - + // Mastercard M/CHIP if (GetCardPSVendor(AID, AIDlen) == CV_MASTERCARD && (TrType == TT_QVSDCMCHIP || TrType == TT_CDA)){ const struct tlv *CDOL1 = tlvdb_get(tlvRoot, 0x8c, NULL); @@ -1103,7 +1103,7 @@ int CmdEMVExec(const char *cmd) { PrintAndLogEx(WARNING, "GetChallenge. Wrong challenge length %d", len); dreturn(6); } - + // ICC Dynamic Number struct tlvdb * ICCDynN = tlvdb_fixed(0x9f4c, len, buf); tlvdb_add(tlvRoot, ICCDynN); @@ -1111,7 +1111,7 @@ int CmdEMVExec(const char *cmd) { PrintAndLogEx(NORMAL, "\n* * ICC Dynamic Number:"); TLVPrintFromTLV(ICCDynN); } - + PrintAndLogEx(NORMAL, "* * Calc CDOL1"); struct tlv *cdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x8c, NULL), tlvRoot, 0x01); // 0x01 - dummy tag if (!cdol_data_tlv){ @@ -1119,29 +1119,29 @@ int CmdEMVExec(const char *cmd) { dreturn(6); } PrintAndLogEx(NORMAL, "CDOL1 data[%d]: %s", cdol_data_tlv->len, sprint_hex(cdol_data_tlv->value, cdol_data_tlv->len)); - + PrintAndLogEx(NORMAL, "* * AC1"); // EMVAC_TC + EMVAC_CDAREQ --- to get SDAD res = EMVAC(channel, true, (TrType == TT_CDA) ? EMVAC_TC + EMVAC_CDAREQ : EMVAC_TC, (uint8_t *)cdol_data_tlv->value, cdol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot); - - if (res) { + + if (res) { PrintAndLogEx(NORMAL, "AC1 error(%d): %4x. Exit...", res, sw); dreturn(7); } - + if (decodeTLV) TLVPrintFromBuffer(buf, len); - + // CDA PrintAndLogEx(NORMAL, "\n* CDA:"); struct tlvdb *ac_tlv = tlvdb_parse_multi(buf, len); res = trCDA(tlvRoot, ac_tlv, pdol_data_tlv, cdol_data_tlv); - if (res) { + if (res) { PrintAndLogEx(NORMAL, "CDA error (%d)", res); } free(ac_tlv); free(cdol_data_tlv); - + PrintAndLogEx(NORMAL, "\n* M/Chip transaction result:"); // 9F27: Cryptogram Information Data (CID) const struct tlv *CID = tlvdb_get(tlvRoot, 0x9F27, NULL); @@ -1169,14 +1169,14 @@ int CmdEMVExec(const char *cmd) { } else { PrintAndLogEx(WARNING, "CID(9F27) not found."); } - + } } - + // MSD - if (AIP & 0x8000 && TrType == TT_MSD) { + if (AIP & 0x8000 && TrType == TT_MSD) { PrintAndLogEx(NORMAL, "\n--> MSD transaction."); - + PrintAndLogEx(NORMAL, "* MSD dCVV path. Check dCVV"); const struct tlv *track2 = tlvdb_get(tlvRoot, 0x57, NULL); @@ -1186,7 +1186,7 @@ int CmdEMVExec(const char *cmd) { struct tlvdb *dCVV = GetdCVVRawFromTrack2(track2); PrintAndLogEx(NORMAL, "dCVV raw data:"); TLVPrintFromTLV(dCVV); - + if (GetCardPSVendor(AID, AIDlen) == CV_MASTERCARD) { PrintAndLogEx(NORMAL, "\n* Mastercard calculate UDOL"); @@ -1208,16 +1208,16 @@ int CmdEMVExec(const char *cmd) { } PrintAndLogEx(NORMAL, "UDOL data[%d]: %s", udol_data_tlv->len, sprint_hex(udol_data_tlv->value, udol_data_tlv->len)); - + PrintAndLogEx(NORMAL, "\n* Mastercard compute cryptographic checksum(UDOL)"); - + res = MSCComputeCryptoChecksum(channel, true, (uint8_t *)udol_data_tlv->value, udol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot); if (res) { PrintAndLogEx(WARNING, "Compute Crypto Checksum. APDU error %4x", sw); free(udol_data_tlv); dreturn(9); } - + // Mastercard compute cryptographic checksum result TLVPrintFromBuffer(buf, len); PrintAndLogEx(NORMAL, ""); @@ -1240,33 +1240,33 @@ int CmdEMVExec(const char *cmd) { PrintAndLogEx(WARNING, "Error: can't create CDOL1 TLV."); dreturn(6); } - + PrintAndLogEx(NORMAL, "CDOL1 data[%d]: %s", cdol_data_tlv->len, sprint_hex(cdol_data_tlv->value, cdol_data_tlv->len)); - + PrintAndLogEx(NORMAL, "* * AC1"); // EMVAC_TC + EMVAC_CDAREQ --- to get SDAD res = EMVAC(channel, true, (TrType == TT_CDA) ? EMVAC_TC + EMVAC_CDAREQ : EMVAC_TC, (uint8_t *)cdol_data_tlv->value, cdol_data_tlv->len, buf, sizeof(buf), &len, &sw, tlvRoot); - - if (res) { + + if (res) { PrintAndLogEx(NORMAL, "AC1 error(%d): %4x. Exit...", res, sw); dreturn(7); } // process Format1 (0x80) and print Format2 (0x77) ProcessACResponseFormat1(tlvRoot, buf, len, decodeTLV); - + PrintAndLogEx(NORMAL, "\n* * Processing online request\n"); // authorization response code from acquirer const char HostResponse[] = "00"; //0 x3030 PrintAndLogEx(NORMAL, "* * Host Response: `%s`", HostResponse); - tlvdb_change_or_add_node(tlvRoot, 0x8a, sizeof(HostResponse) - 1, (const unsigned char *)HostResponse); - + tlvdb_change_or_add_node(tlvRoot, 0x8a, sizeof(HostResponse) - 1, (const unsigned char *)HostResponse); + } - + DropFieldEx( channel ); - + // Destroy TLV's free(pdol_data_tlv); tlvdb_free(tlvSelect); @@ -1286,8 +1286,8 @@ int CmdEMVScan(const char *cmd) { json_t *root; json_error_t error; - CLIParserInit("emv scan", - "Scan EMV card and save it contents to a file.", + CLIParserInit("emv scan", + "Scan EMV card and save it contents to a file.", "It executes EMV contactless transaction and saves result to a file which can be used for emulation\n" "Usage:\n\temv scan -at -> scan MSD transaction mode and show APDU and TLV\n" "\temv scan -c -> scan CDA transaction mode\n"); @@ -1311,7 +1311,7 @@ int CmdEMVScan(const char *cmd) { arg_param_end }; CLIExecWithReturn(cmd, argtable, true); - + bool showAPDU = arg_get_lit(1); bool decodeTLV = arg_get_lit(2); bool extractTLVElements = arg_get_lit(3); @@ -1331,7 +1331,7 @@ int CmdEMVScan(const char *cmd) { uint8_t relfname[250] = {0}; char *crelfname = (char *)relfname; int relfnamelen = 0; -#ifdef WITH_SMARTCARD +#ifdef WITH_SMARTCARD if (arg_get_lit(11)) { channel = ECC_CONTACT; } @@ -1342,15 +1342,15 @@ int CmdEMVScan(const char *cmd) { PrintChannel(channel); uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2; CLIParserFree(); - + SetAPDULogging(showAPDU); - + // TODO if (channel == ECC_CONTACT) { PrintAndLogEx(ERR, "Do not use contact interface. Exit."); return 1; } - + // current path + file name if (!strstr(crelfname, ".json")) strcat(crelfname, ".json"); @@ -1362,12 +1362,12 @@ int CmdEMVScan(const char *cmd) { root = json_load_file(fname, 0, &error); if (!root) { PrintAndLogEx(ERR, "json error on line %d: %s", error.line, error.text); - return 1; + return 1; } - + if (!json_is_object(root)) { PrintAndLogEx(ERR, "Invalid json format. root must be an object."); - return 1; + return 1; } } else { root = json_object(); @@ -1375,27 +1375,27 @@ int CmdEMVScan(const char *cmd) { // drop field at start DropFieldEx( channel ); - + // iso 14443 select PrintAndLogEx(NORMAL, "--> GET UID, ATS."); - + iso14a_card_select_t card; if (Hf14443_4aGetCardData(&card)) { return 2; } JsonSaveStr(root, "$.File.Created", "proxmark3 `emv scan`"); - + JsonSaveStr(root, "$.Card.Communication", "iso14443-4a"); JsonSaveBufAsHex(root, "$.Card.UID", (uint8_t *)&card.uid, card.uidlen); JsonSaveHex(root, "$.Card.ATQA", card.atqa[0] + (card.atqa[1] << 2), 2); JsonSaveHex(root, "$.Card.SAK", card.sak, 0); JsonSaveBufAsHex(root, "$.Card.ATS", (uint8_t *)card.ats, card.ats_len); - + // init applets list tree const char *al = "Applets list"; struct tlvdb *tlvSelect = tlvdb_fixed(1, strlen(al), (const unsigned char *)al); - + // EMV PPSE PrintAndLogEx(NORMAL, "--> PPSE."); res = EMVSelectPSE(channel, true, true, 2, buf, sizeof(buf), &len, &sw); @@ -1403,9 +1403,9 @@ int CmdEMVScan(const char *cmd) { if (!res && sw == 0x9000){ if (decodeTLV) TLVPrintFromBuffer(buf, len); - + JsonSaveBufAsHex(root, "$.PPSE.AID", (uint8_t *)"2PAY.SYS.DDF01", 14); - + struct tlvdb *fci = tlvdb_parse_multi(buf, len); if (extractTLVElements) JsonSaveTLVTree(root, root, "$.PPSE.FCITemplate", fci); @@ -1418,8 +1418,8 @@ int CmdEMVScan(const char *cmd) { res = EMVSearchPSE(channel, false, true, psenum, decodeTLV, tlvSelect); // check PPSE and select application id - if (!res) { - TLVPrintAIDlistFromSelectTLV(tlvSelect); + if (!res) { + TLVPrintAIDlistFromSelectTLV(tlvSelect); } else { // EMV SEARCH with AID list SetAPDULogging(false); @@ -1448,7 +1448,7 @@ int CmdEMVScan(const char *cmd) { } JsonSaveBufAsHex(root, "$.Application.AID", AID, AIDlen); - + // Init TLV tree const char *alr = "Root terminal TLV tree"; struct tlvdb *tlvRoot = tlvdb_fixed(1, strlen(alr), (const unsigned char *)alr); @@ -1458,14 +1458,14 @@ int CmdEMVScan(const char *cmd) { PrintAndLogEx(NORMAL, "\n-->Selecting AID:%s.", sprint_hex_inrow(AID, AIDlen)); SetAPDULogging(showAPDU); res = EMVSelect(channel, false, true, AID, AIDlen, buf, sizeof(buf), &len, &sw, tlvRoot); - - if (res) { + + if (res) { PrintAndLogEx(ERR, "Can't select AID (%d). Exit...", res); tlvdb_free(tlvRoot); DropFieldEx( channel ); return 5; } - + if (decodeTLV) TLVPrintFromBuffer(buf, len); @@ -1484,7 +1484,7 @@ int CmdEMVScan(const char *cmd) { // create transaction parameters PrintAndLogEx(NORMAL, "-->Init transaction parameters."); InitTransactionParameters(tlvRoot, paramLoadJSON, TrType, GenACGPO); - + PrintAndLogEx(NORMAL, "-->Calc PDOL."); struct tlv *pdol_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x9f38, NULL), tlvRoot, 0x83); if (!pdol_data_tlv){ @@ -1493,7 +1493,7 @@ int CmdEMVScan(const char *cmd) { DropFieldEx( channel ); return 6; } - + size_t pdol_data_tlv_data_len; unsigned char *pdol_data_tlv_data = tlv_encode(pdol_data_tlv, &pdol_data_tlv_data_len); if (!pdol_data_tlv_data) { @@ -1506,18 +1506,18 @@ int CmdEMVScan(const char *cmd) { PrintAndLogEx(INFO, "-->GPO."); res = EMVGPO(channel, true, pdol_data_tlv_data, pdol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot); - + free(pdol_data_tlv_data); free(pdol_data_tlv); - - if (res) { + + if (res) { PrintAndLogEx(ERR, "GPO error(%d): %4x. Exit...", res, sw); tlvdb_free(tlvRoot); DropFieldEx( channel ); return 7; } ProcessGPOResponseFormat1(tlvRoot, buf, len, decodeTLV); - + struct tlvdb *gpofci = tlvdb_parse_multi(buf, len); if (extractTLVElements) JsonSaveTLVTree(root, root, "$.Application.GPO", gpofci); @@ -1531,7 +1531,7 @@ int CmdEMVScan(const char *cmd) { PrintAndLogEx(INFO, "-->Read records from AFL."); const struct tlv *AFL = tlvdb_get(tlvRoot, 0x94, NULL); - + while(AFL && AFL->len) { if (AFL->len % 4) { PrintAndLogEx(ERR, "Wrong AFL length: %d", AFL->len); @@ -1542,7 +1542,7 @@ int CmdEMVScan(const char *cmd) { if (!sfijson) { json_t *app = json_path_get(root, "$.Application"); json_object_set_new(app, "Records", json_array()); - + sfijson = json_path_get(root, "$.Application.Records"); } if (!json_is_array(sfijson)) { @@ -1554,34 +1554,34 @@ int CmdEMVScan(const char *cmd) { uint8_t SFIstart = AFL->value[i * 4 + 1]; uint8_t SFIend = AFL->value[i * 4 + 2]; uint8_t SFIoffline = AFL->value[i * 4 + 3]; - + PrintAndLogEx(INFO, "--->SFI[%02x] start:%02x end:%02x offline:%02x", SFI, SFIstart, SFIend, SFIoffline); if (SFI == 0 || SFI == 31 || SFIstart == 0 || SFIstart > SFIend) { PrintAndLogEx(ERR, "SFI ERROR! Skipped..."); continue; } - + for(int n = SFIstart; n <= SFIend; n++) { PrintAndLogEx(INFO, "---->SFI[%02x] %d", SFI, n); - + res = EMVReadRecord(channel, true, SFI, n, buf, sizeof(buf), &len, &sw, tlvRoot); if (res) { PrintAndLogEx(ERR, "SFI[%02x]. APDU error %4x", SFI, sw); continue; } - + if (decodeTLV) { TLVPrintFromBuffer(buf, len); PrintAndLogEx(NORMAL, ""); } - + json_t *jsonelm = json_object(); json_array_append_new(sfijson, jsonelm); JsonSaveHex(jsonelm, "SFI", SFI, 1); JsonSaveHex(jsonelm, "RecordNum", n, 1); JsonSaveHex(jsonelm, "Offline", SFIoffline, 1); - + struct tlvdb *rsfi = tlvdb_parse_multi(buf, len); if (extractTLVElements) JsonSaveTLVTree(root, jsonelm, "$.Data", rsfi); @@ -1590,10 +1590,10 @@ int CmdEMVScan(const char *cmd) { tlvdb_free(rsfi); } } - + break; } - + // getting certificates if (tlvdb_get(tlvRoot, 0x90, NULL)) { PrintAndLogEx(INFO, "-->Recovering certificates."); @@ -1601,22 +1601,22 @@ int CmdEMVScan(const char *cmd) { RecoveryCertificates(tlvRoot, root); PKISetStrictExecution(true); } - + // free tlv object tlvdb_free(tlvRoot); DropFieldEx( channel ); - + res = json_dump_file(root, fname, JSON_INDENT(2)); if (res) { PrintAndLogEx(ERR, "Can't save the file: %s", fname); return 200; } PrintAndLogEx(SUCCESS, "File `%s` saved.", fname); - + // free json object json_decref(root); - + return 0; } @@ -1631,9 +1631,11 @@ int CmdEMVRoca(const char *cmd) { size_t len = 0; uint16_t sw = 0; int res; - - CLIParserInit("emv roca", - "Tries to extract public keys and run the ROCA test against them.\n", + uint8_t ODAiList[4096]; + size_t ODAiListLen = 0; + + CLIParserInit("emv roca", + "Tries to extract public keys and run the ROCA test against them.\n", "Usage:\n" "\temv roca -w -> select --CONTACT-- card and run test\n" "\temv roca -> select --CONTACTLESS-- card and run test\n" @@ -1642,26 +1644,30 @@ int CmdEMVRoca(const char *cmd) { void* argtable[] = { arg_param_begin, arg_lit0("tT", "selftest", "self test"), + arg_lit0("aA", "apdu", "show APDU reqests and responses"), arg_lit0("wW", "wired", "Send data via contact (iso7816) interface. Contactless interface set by default."), arg_param_end }; CLIExecWithReturn(cmd, argtable, true); - - EMVCommandChannel channel = ECC_CONTACTLESS; + if (arg_get_lit(1)) - return roca_self_test(); + return roca_self_test(); + bool showAPDU = arg_get_lit(2); + + EMVCommandChannel channel = ECC_CONTACTLESS; #ifdef WITH_SMARTCARD - if (arg_get_lit(2)) + if (arg_get_lit(3)) channel = ECC_CONTACT; #endif PrintChannel(channel); + CLIParserFree(); // select card uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2; char *PSE_or_PPSE = psenum == 1 ? "PSE" : "PPSE"; - - SetAPDULogging(false); - + + SetAPDULogging(showAPDU); + // init applets list tree const char *al = "Applets list"; struct tlvdb *tlvSelect = tlvdb_fixed(1, strlen(al), (const unsigned char *)al); @@ -1671,8 +1677,8 @@ int CmdEMVRoca(const char *cmd) { res = EMVSearchPSE(channel, true, true, psenum, false, tlvSelect); // check PSE/PPSE and select application id - if (!res) { - TLVPrintAIDlistFromSelectTLV(tlvSelect); + if (!res) { + TLVPrintAIDlistFromSelectTLV(tlvSelect); } else { // EMV SEARCH with AID list PrintAndLogEx(NORMAL, "--> AID search."); @@ -1688,7 +1694,6 @@ int CmdEMVRoca(const char *cmd) { } // EMV SELECT application - SetAPDULogging(false); EMVSelectApplication(tlvSelect, AID, &AIDlen); tlvdb_free(tlvSelect); @@ -1706,8 +1711,8 @@ int CmdEMVRoca(const char *cmd) { // EMV SELECT applet PrintAndLogEx(NORMAL, "\n-->Selecting AID:%s.", sprint_hex_inrow(AID, AIDlen)); res = EMVSelect(channel, false, true, AID, AIDlen, buf, sizeof(buf), &len, &sw, tlvRoot); - - if (res) { + + if (res) { PrintAndLogEx(ERR, "Can't select AID (%d). Exit...", res); tlvdb_free(tlvRoot); DropFieldEx( channel ); @@ -1725,7 +1730,7 @@ int CmdEMVRoca(const char *cmd) { DropFieldEx( channel ); return 6; } - + size_t pdol_data_tlv_data_len; unsigned char *pdol_data_tlv_data = tlv_encode(pdol_data_tlv, &pdol_data_tlv_data_len); if (!pdol_data_tlv_data) { @@ -1738,21 +1743,21 @@ int CmdEMVRoca(const char *cmd) { PrintAndLogEx(INFO, "-->GPO."); res = EMVGPO(channel, true, pdol_data_tlv_data, pdol_data_tlv_data_len, buf, sizeof(buf), &len, &sw, tlvRoot); - + free(pdol_data_tlv_data); free(pdol_data_tlv); - - if (res) { + + if (res) { PrintAndLogEx(ERR, "GPO error(%d): %4x. Exit...", res, sw); tlvdb_free(tlvRoot); DropFieldEx( channel ); return 7; } ProcessGPOResponseFormat1(tlvRoot, buf, len, false); - + PrintAndLogEx(INFO, "-->Read records from AFL."); const struct tlv *AFL = tlvdb_get(tlvRoot, 0x94, NULL); - + while(AFL && AFL->len) { if (AFL->len % 4) { PrintAndLogEx(ERR, "Wrong AFL length: %d", AFL->len); @@ -1764,29 +1769,57 @@ int CmdEMVRoca(const char *cmd) { uint8_t SFIstart = AFL->value[i * 4 + 1]; uint8_t SFIend = AFL->value[i * 4 + 2]; uint8_t SFIoffline = AFL->value[i * 4 + 3]; - + PrintAndLogEx(INFO, "--->SFI[%02x] start:%02x end:%02x offline:%02x", SFI, SFIstart, SFIend, SFIoffline); if (SFI == 0 || SFI == 31 || SFIstart == 0 || SFIstart > SFIend) { PrintAndLogEx(ERR, "SFI ERROR! Skipped..."); continue; } - + for(int n = SFIstart; n <= SFIend; n++) { PrintAndLogEx(INFO, "---->SFI[%02x] %d", SFI, n); - + res = EMVReadRecord(channel, true, SFI, n, buf, sizeof(buf), &len, &sw, tlvRoot); if (res) { PrintAndLogEx(ERR, "SFI[%02x]. APDU error %4x", SFI, sw); continue; } + + // Build Input list for Offline Data Authentication + // EMV 4.3 book3 10.3, page 96 + if (SFIoffline > 0) { + if (SFI < 11) { + const unsigned char *abuf = buf; + size_t elmlen = len; + struct tlv e; + if (tlv_parse_tl(&abuf, &elmlen, &e)) { + memcpy(&ODAiList[ODAiListLen], &buf[len - elmlen], elmlen); + ODAiListLen += elmlen; + } else { + PrintAndLogEx(WARNING, "Error SFI[%02x]. Creating input list for Offline Data Authentication error.", SFI); + } + } else { + memcpy(&ODAiList[ODAiListLen], buf, len); + ODAiListLen += len; + } + + SFIoffline--; + } } } - + break; } + // copy Input list for Offline Data Authentication + if (ODAiListLen) { + struct tlvdb *oda = tlvdb_fixed(0x21, ODAiListLen, ODAiList); // not a standard tag + tlvdb_add(tlvRoot, oda); + PrintAndLogEx(NORMAL, "* Input list for Offline Data Authentication added to TLV. len=%d \n", ODAiListLen); + } + // getting certificates - if (tlvdb_get(tlvRoot, 0x90, NULL)) { + if (tlvdb_get(tlvRoot, 0x90, NULL)) { PrintAndLogEx(INFO, "-->Recovering certificates."); PKISetStrictExecution(false); @@ -1802,17 +1835,17 @@ int CmdEMVRoca(const char *cmd) { PrintAndLogEx(WARNING, "WARNING: Issuer certificate not found. Exit."); goto out; } - + char RID[15] = {0}; memcpy(RID, sprint_hex(issuer_pk->rid, 5), 14); - PrintAndLogEx(SUCCESS, "Issuer PK recovered. RID %s IDX %02hhx CSN %s", + PrintAndLogEx(SUCCESS, "Issuer Public Key recovered. RID %s IDX %02hhx CSN %s", RID, issuer_pk->index, sprint_hex(issuer_pk->serial, 3) ); - - struct emv_pk *icc_pk = emv_pki_recover_icc_cert(issuer_pk, tlvRoot, NULL); + const struct tlv *sda_tlv = tlvdb_get(tlvRoot, 0x21, NULL); + struct emv_pk *icc_pk = emv_pki_recover_icc_cert(issuer_pk, tlvRoot, sda_tlv); if (!icc_pk) { emv_pk_free(pk); emv_pk_free(issuer_pk); @@ -1821,29 +1854,29 @@ int CmdEMVRoca(const char *cmd) { } memcpy(RID, sprint_hex(icc_pk->rid, 5), 14); - PrintAndLogEx(SUCCESS, "ICC PK recovered. RID %s IDX %02hhx CSN %s\n", + PrintAndLogEx(SUCCESS, "ICC Public Key recovered. RID %s IDX %02hhx CSN %s\n", RID, icc_pk->index, sprint_hex(icc_pk->serial, 3) ); - - PrintAndLogEx(INFO, "ICC pk modulus: %s", sprint_hex_inrow(icc_pk->modulus, icc_pk->mlen)); - - // icc_pk->exp, icc_pk->elen - // icc_pk->modulus, icc_pk->mlen + + PrintAndLogEx(INFO, "ICC Public Key modulus: %s\n", sprint_hex_inrow(icc_pk->modulus, icc_pk->mlen)); + + // icc_pk->exp, icc_pk->elen + // icc_pk->modulus, icc_pk->mlen if (icc_pk->elen > 0 && icc_pk->mlen > 0) { - if (emv_rocacheck(icc_pk->modulus, icc_pk->mlen, true)) { - PrintAndLogEx(INFO, "ICC pk is a subject to ROCA vulnerability, insecure.."); + if (emv_rocacheck(icc_pk->modulus, icc_pk->mlen, false)) { + PrintAndLogEx(INFO, "ICC Public Key is subject to ROCA vulnerability (it is NOT secure)."); } else { - PrintAndLogEx(INFO, "ICC pk is OK("); + PrintAndLogEx(INFO, "ICC Public Key is not subject to ROCA vulnerability (it is secure)"); } - } - + } + PKISetStrictExecution(true); } out: - + // free tlv object tlvdb_free(tlvRoot); @@ -1866,7 +1899,7 @@ static command_t CommandTable[] = { {"intauth", CmdEMVInternalAuthenticate, 1, "Internal authentication."}, {"scan", CmdEMVScan, 1, "Scan EMV card and save it contents to json file for emulator."}, {"test", CmdEMVTest, 1, "Crypto logic test."}, - {"roca", CmdEMVRoca, 1, "Extract public keys and run ROCA test"}, + {"roca", CmdEMVRoca, 1, "Extract public keys and run ROCA test"}, {NULL, NULL, 0, NULL} }; diff --git a/client/emv/emv_pk.c b/client/emv/emv_pk.c index f4a5f56a..bbaf0294 100644 --- a/client/emv/emv_pk.c +++ b/client/emv/emv_pk.c @@ -503,7 +503,7 @@ struct emv_pk *emv_pk_get_ca_pk(const unsigned char *rid, unsigned char idx) if (!pk) return NULL; - printf("Verifying CA PK for %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx %zd bits...", + printf("Verifying CA Public Key for %02hhx:%02hhx:%02hhx:%02hhx:%02hhx IDX %02hhx %zd bits...", pk->rid[0], pk->rid[1], pk->rid[2], diff --git a/client/emv/emv_pki.c b/client/emv/emv_pki.c index d36382df..4e14483f 100644 --- a/client/emv/emv_pki.c +++ b/client/emv/emv_pki.c @@ -18,14 +18,14 @@ #endif #include "emv_pki.h" -#include "crypto.h" -#include "dump.h" -#include "util.h" -#include #include #include #include +#include "crypto.h" +#include "dump.h" +#include "util.h" +#include "ui.h" static bool strictExecution = true; void PKISetStrictExecution(bool se) { @@ -54,12 +54,12 @@ static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk, return NULL; if (!cert_tlv) { - printf("ERROR: Can't find certificate\n"); + PrintAndLogEx(ERR, "Can't find certificate\n"); return NULL; } if (cert_tlv->len != enc_pk->mlen) { - printf("ERROR: Certificate length (%zd) not equal key length (%zd)\n", cert_tlv->len, enc_pk->mlen); + PrintAndLogEx(ERR, "Certificate length (%zd) not equal key length (%zd)\n", cert_tlv->len, enc_pk->mlen); return NULL; } kcp = crypto_pk_open(enc_pk->pk_algo, @@ -71,20 +71,20 @@ static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk, data = crypto_pk_encrypt(kcp, cert_tlv->value, cert_tlv->len, &data_len); crypto_pk_close(kcp); -/* if (true){ - printf("Recovered data:\n"); + /*if (true){ + PrintAndLogEx(INFO, "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"); + PrintAndLogEx(ERR, "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"); + PrintAndLogEx(ERR, "Can't get hash position in the certificate\n"); free(data); return NULL; } @@ -92,7 +92,7 @@ static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk, struct crypto_hash *ch; ch = crypto_hash_open(data[hash_pos]); if (!ch) { - printf("ERROR: Cant do hash\n"); + PrintAndLogEx(ERR, "Can't do hash\n"); free(data); return NULL; } @@ -114,9 +114,9 @@ static unsigned char *emv_pki_decode_message(const struct emv_pk *enc_pk, 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)); + PrintAndLogEx(ERR, "Calculated wrong hash\n"); + PrintAndLogEx(INFO, "decoded: %s\n",sprint_hex(data + data_len - 1 - hash_len, hash_len)); + PrintAndLogEx(INFO, "calculated: %s\n",sprint_hex(hash, hash_len)); if (strictExecution) { crypto_hash_close(ch); @@ -189,7 +189,7 @@ static struct emv_pk *emv_pki_decode_key_ex(const struct emv_pk *enc_pk, else if (msgtype == 4) pan_length = 10; else { - printf("ERROR: Message type must be 2 or 4\n"); + PrintAndLogEx(ERR, "Message type must be 2 or 4\n"); return NULL; } @@ -202,12 +202,12 @@ static struct emv_pk *emv_pki_decode_key_ex(const struct emv_pk *enc_pk, sdatl_tlv, NULL); if (!data || data_len < 11 + pan_length) { - printf("ERROR: Can't decode message\n"); + PrintAndLogEx(ERR, "Can't decode message\n"); return NULL; } if (showData){ - printf("Recovered data:\n"); + PrintAndLogEx(INFO, "Recovered data:\n"); dump_buffer(data, data_len, stdout, 0); } @@ -223,7 +223,7 @@ static struct emv_pk *emv_pki_decode_key_ex(const struct emv_pk *enc_pk, if (((msgtype == 2) && (pan2_len < 4 || pan2_len > pan_len)) || ((msgtype == 4) && (pan2_len != pan_len))) { - printf("ERROR: Invalid PAN lengths\n"); + PrintAndLogEx(ERR, "Invalid PAN lengths\n"); free(data); return NULL; @@ -232,9 +232,9 @@ static struct emv_pk *emv_pki_decode_key_ex(const struct emv_pk *enc_pk, 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)); + PrintAndLogEx(ERR, "PAN data mismatch\n"); + PrintAndLogEx(INFO, "tlv pan=%s\n", sprint_hex(pan_tlv->value, pan_tlv->len)); + PrintAndLogEx(INFO, "cert pan=%s\n", sprint_hex(pan2_tlv.value, pan2_tlv.len)); free(data); return NULL; @@ -242,7 +242,7 @@ static struct emv_pk *emv_pki_decode_key_ex(const struct emv_pk *enc_pk, pk_len = data[9 + pan_length]; if (pk_len > data_len - 11 - pan_length + rem_tlv->len) { - printf("ERROR: Invalid pk length\n"); + PrintAndLogEx(ERR, "Invalid pk length\n"); free(data); return NULL; } @@ -388,7 +388,7 @@ struct tlvdb *emv_pki_recover_dac_ex(const struct emv_pk *enc_pk, const struct t return NULL; if (showData){ - printf("Recovered data:\n"); + PrintAndLogEx(INFO, "Recovered data:\n"); dump_buffer(data, data_len, stdout, 0); } @@ -398,6 +398,7 @@ struct tlvdb *emv_pki_recover_dac_ex(const struct emv_pk *enc_pk, const struct t 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); } @@ -424,7 +425,7 @@ struct tlvdb *emv_pki_recover_idn_ex(const struct emv_pk *enc_pk, const struct t } if (showData){ - printf("Recovered data:\n"); + PrintAndLogEx(INFO, "Recovered data:\n"); dump_buffer(data, data_len, stdout, 0); } @@ -463,7 +464,7 @@ struct tlvdb *emv_pki_recover_atc_ex(const struct emv_pk *enc_pk, const struct t } if (showData){ - printf("Recovered data:\n"); + PrintAndLogEx(INFO, "Recovered data:\n"); dump_buffer(data, data_len, stdout, 0); } @@ -528,23 +529,23 @@ struct tlvdb *emv_pki_perform_cda_ex(const struct emv_pk *enc_pk, const struct t un_tlv, NULL); if (!data || data_len < 3) { - printf("ERROR: can't decode message. len %zd\n", data_len); + PrintAndLogEx(ERR, "can't decode message. len %zd\n", data_len); return NULL; } if (showData){ - printf("Recovered data:\n"); + PrintAndLogEx(INFO, "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"); + PrintAndLogEx(ERR, "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"); + PrintAndLogEx(ERR, "CID mismatch\n"); free(data); return NULL; } @@ -552,7 +553,7 @@ struct tlvdb *emv_pki_perform_cda_ex(const struct emv_pk *enc_pk, const struct t struct crypto_hash *ch; ch = crypto_hash_open(enc_pk->hash_algo); if (!ch) { - printf("ERROR: can't create hash\n"); + PrintAndLogEx(ERR, "Can't create hash\n"); free(data); return NULL; } @@ -567,7 +568,7 @@ struct tlvdb *emv_pki_perform_cda_ex(const struct emv_pk *enc_pk, const struct t 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"); + PrintAndLogEx(ERR, "Calculated hash error\n"); crypto_hash_close(ch); free(data); return NULL; @@ -576,7 +577,7 @@ struct tlvdb *emv_pki_perform_cda_ex(const struct emv_pk *enc_pk, const struct t size_t idn_len = data[4]; if (idn_len > data[3] - 1) { - printf("ERROR: Invalid IDN length\n"); + PrintAndLogEx(ERR, "Invalid IDN length\n"); free(data); return NULL; } From 53fb848a0ad6bb8315c1ba5c382bf30ef4998007 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Sat, 16 Feb 2019 17:51:04 +0100 Subject: [PATCH 064/189] add tracing functions (#784) * add trace buffer for PCSC smartcard readers * new option 'p' in 'hf list' to select PCSC trace buffer * 'sc list' now supports PCSC smartcard readers * add 'hf list 14-4' for ISO 14443-4 protocol --- client/cmdhflist.c | 402 ++++++++++++++++++++++++++---------------- client/cmdsmartcard.c | 6 +- client/emv/emvcore.c | 4 +- client/pcsc.c | 107 ++++++++++- client/pcsc.h | 3 + common/protocols.h | 29 +-- 6 files changed, 377 insertions(+), 174 deletions(-) diff --git a/client/cmdhflist.c b/client/cmdhflist.c index 67326c98..db3e5287 100644 --- a/client/cmdhflist.c +++ b/client/cmdhflist.c @@ -27,6 +27,7 @@ #include "mifarehost.h" #include "mifaredefault.h" #include "usb_cmd.h" +#include "pcsc.h" typedef struct { uint32_t uid; // UID @@ -39,7 +40,7 @@ typedef struct { uint32_t at_enc; // encrypted tag response uint8_t at_enc_par; // encrypted tag response parity bool first_auth; // is first authentication - uint32_t ks2; // ar ^ ar_enc + uint32_t ks2; // ar ^ ar_enc uint32_t ks3; // at ^ at_enc } TAuthData; @@ -81,7 +82,22 @@ static uint8_t iso14443A_CRC_check(bool isResponse, uint8_t* data, uint8_t len) if(len <= 2) return 2; if(isResponse & (len < 6)) return 2; - + + ComputeCrc14443(CRC_14443_A, data, len-2, &b1, &b2); + if (b1 != data[len-2] || b2 != data[len-1]) { + return 0; + } else { + return 1; + } +} + + +static uint8_t iso14443_4_CRC_check(uint8_t* data, uint8_t len) +{ + uint8_t b1,b2; + + if(len <= 2) return 2; + ComputeCrc14443(CRC_14443_A, data, len-2, &b1, &b2); if (b1 != data[len-2] || b2 != data[len-1]) { return 0; @@ -127,10 +143,10 @@ static uint8_t iso14443B_CRC_check(bool isResponse, uint8_t* data, uint8_t len) } -static uint8_t iso15693_CRC_check(uint8_t* d, uint16_t n) +static uint8_t iso15693_CRC_check(uint8_t* d, uint16_t n) { if (n <= 2) return 2; - + return (Iso15693Crc(d, n) == ISO15693_CRC_CHECK ? 1 : 0); } @@ -141,7 +157,7 @@ static uint8_t iso15693_CRC_check(uint8_t* d, uint16_t n) * @param data * @param len * @return 0 : CRC-command, CRC not ok - * 1 : CRC-command, CRC ok + * 1 : CRC-command, CRC ok * 2 : Not crc-command */ uint8_t iclass_CRC_check(bool isResponse, uint8_t* data, uint8_t len) @@ -154,7 +170,7 @@ uint8_t iclass_CRC_check(bool isResponse, uint8_t* data, uint8_t len) { /** These commands should have CRC. Total length leftmost - 4 READ + 4 READ 4 READ4 12 UPDATE - unsecured, ends with CRC16 14 UPDATE - secured, ends with signature instead @@ -171,20 +187,20 @@ uint8_t iclass_CRC_check(bool isResponse, uint8_t* data, uint8_t len) /** These tag responses should have CRC. Total length leftmost - 10 READ data[8] crc[2] - 34 READ4 data[32]crc[2] - 10 UPDATE data[8] crc[2] - 10 SELECT csn[8] crc[2] + 10 READ data[8] crc[2] + 34 READ4 data[32]crc[2] + 10 UPDATE data[8] crc[2] + 10 SELECT csn[8] crc[2] 10 IDENTIFY asnb[8] crc[2] 10 PAGESEL block1[8] crc[2] 10 DETECT csn[8] crc[2] These should not - 4 CHECK chip_response[4] + 4 CHECK chip_response[4] 8 READCHECK data[8] 1 ACTALL sof[1] - 1 ACT sof[1] + 1 ACT sof[1] In conclusion, without looking at the command; any response of length 10 or 34 should have CRC @@ -230,50 +246,113 @@ void annotateIso15693(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) { switch(cmd[1]){ // Mandatory Commands, all Tags must support them: - case ISO15693_INVENTORY :snprintf(exp, size, "INVENTORY");return; - case ISO15693_STAYQUIET :snprintf(exp, size, "STAY_QUIET");return; + case ISO15693_INVENTORY :snprintf(exp, size, "INVENTORY");return; + case ISO15693_STAYQUIET :snprintf(exp, size, "STAY_QUIET");return; // Optional Commands, Tags may support them: - case ISO15693_READBLOCK :snprintf(exp, size, "READBLOCK");return; - case ISO15693_WRITEBLOCK :snprintf(exp, size, "WRITEBLOCK");return; - case ISO15693_LOCKBLOCK :snprintf(exp, size, "LOCKBLOCK");return; - case ISO15693_READ_MULTI_BLOCK :snprintf(exp, size, "READ_MULTI_BLOCK");return; - case ISO15693_SELECT :snprintf(exp, size, "SELECT");return; - case ISO15693_RESET_TO_READY :snprintf(exp, size, "RESET_TO_READY");return; - case ISO15693_WRITE_AFI :snprintf(exp, size, "WRITE_AFI");return; - case ISO15693_LOCK_AFI :snprintf(exp, size, "LOCK_AFI");return; - case ISO15693_WRITE_DSFID :snprintf(exp, size, "WRITE_DSFID");return; - case ISO15693_LOCK_DSFID :snprintf(exp, size, "LOCK_DSFID");return; - case ISO15693_GET_SYSTEM_INFO :snprintf(exp, size, "GET_SYSTEM_INFO");return; - case ISO15693_READ_MULTI_SECSTATUS :snprintf(exp, size, "READ_MULTI_SECSTATUS");return; + case ISO15693_READBLOCK :snprintf(exp, size, "READBLOCK");return; + case ISO15693_WRITEBLOCK :snprintf(exp, size, "WRITEBLOCK");return; + case ISO15693_LOCKBLOCK :snprintf(exp, size, "LOCKBLOCK");return; + case ISO15693_READ_MULTI_BLOCK :snprintf(exp, size, "READ_MULTI_BLOCK");return; + case ISO15693_SELECT :snprintf(exp, size, "SELECT");return; + case ISO15693_RESET_TO_READY :snprintf(exp, size, "RESET_TO_READY");return; + case ISO15693_WRITE_AFI :snprintf(exp, size, "WRITE_AFI");return; + case ISO15693_LOCK_AFI :snprintf(exp, size, "LOCK_AFI");return; + case ISO15693_WRITE_DSFID :snprintf(exp, size, "WRITE_DSFID");return; + case ISO15693_LOCK_DSFID :snprintf(exp, size, "LOCK_DSFID");return; + case ISO15693_GET_SYSTEM_INFO :snprintf(exp, size, "GET_SYSTEM_INFO");return; + case ISO15693_READ_MULTI_SECSTATUS :snprintf(exp, size, "READ_MULTI_SECSTATUS");return; default: break; } if (cmd[1] > ISO15693_STAYQUIET && cmd[1] < ISO15693_READBLOCK) snprintf(exp, size, "Mandatory RFU"); - else if (cmd[1] > ISO15693_READ_MULTI_SECSTATUS && cmd[1] <= 0x9F) snprintf(exp, size, "Optional RFU"); - else if ( cmd[1] >= 0xA0 && cmd[1] <= 0xDF ) snprintf(exp, size, "Custom command"); - else if ( cmd[1] >= 0xE0 && cmd[1] <= 0xFF ) snprintf(exp, size, "Proprietary command"); + else if (cmd[1] > ISO15693_READ_MULTI_SECSTATUS && cmd[1] <= 0x9F) snprintf(exp, size, "Optional RFU"); + else if ( cmd[1] >= 0xA0 && cmd[1] <= 0xDF ) snprintf(exp, size, "Custom command"); + else if ( cmd[1] >= 0xE0 && cmd[1] <= 0xFF ) snprintf(exp, size, "Proprietary command"); } void annotateTopaz(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) { switch(cmd[0]) { - case TOPAZ_REQA :snprintf(exp, size, "REQA");break; - case TOPAZ_WUPA :snprintf(exp, size, "WUPA");break; - case TOPAZ_RID :snprintf(exp, size, "RID");break; - case TOPAZ_RALL :snprintf(exp, size, "RALL");break; - case TOPAZ_READ :snprintf(exp, size, "READ");break; - case TOPAZ_WRITE_E :snprintf(exp, size, "WRITE-E");break; - case TOPAZ_WRITE_NE :snprintf(exp, size, "WRITE-NE");break; - case TOPAZ_RSEG :snprintf(exp, size, "RSEG");break; - case TOPAZ_READ8 :snprintf(exp, size, "READ8");break; - case TOPAZ_WRITE_E8 :snprintf(exp, size, "WRITE-E8");break; - case TOPAZ_WRITE_NE8 :snprintf(exp, size, "WRITE-NE8");break; + case TOPAZ_REQA :snprintf(exp, size, "REQA");break; + case TOPAZ_WUPA :snprintf(exp, size, "WUPA");break; + case TOPAZ_RID :snprintf(exp, size, "RID");break; + case TOPAZ_RALL :snprintf(exp, size, "RALL");break; + case TOPAZ_READ :snprintf(exp, size, "READ");break; + case TOPAZ_WRITE_E :snprintf(exp, size, "WRITE-E");break; + case TOPAZ_WRITE_NE :snprintf(exp, size, "WRITE-NE");break; + case TOPAZ_RSEG :snprintf(exp, size, "RSEG");break; + case TOPAZ_READ8 :snprintf(exp, size, "READ8");break; + case TOPAZ_WRITE_E8 :snprintf(exp, size, "WRITE-E8");break; + case TOPAZ_WRITE_NE8 :snprintf(exp, size, "WRITE-NE8");break; default: snprintf(exp,size,"?"); break; } } +void annotateIso7816(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) +{ + switch ( cmd[1] ){ + case ISO7816_READ_BINARY :snprintf(exp, size, "READ BINARY");break; + case ISO7816_WRITE_BINARY :snprintf(exp, size, "WRITE BINARY");break; + case ISO7816_UPDATE_BINARY :snprintf(exp, size, "UPDATE BINARY");break; + case ISO7816_ERASE_BINARY :snprintf(exp, size, "ERASE BINARY");break; + case ISO7816_READ_RECORDS :snprintf(exp, size, "READ RECORD(S)");break; + case ISO7816_WRITE_RECORD :snprintf(exp, size, "WRITE RECORD");break; + case ISO7816_APPEND_RECORD :snprintf(exp, size, "APPEND RECORD");break; + case ISO7816_UPDATE_DATA :snprintf(exp, size, "UPDATE DATA");break; + case ISO7816_GET_DATA :snprintf(exp, size, "GET DATA");break; + case ISO7816_PUT_DATA :snprintf(exp, size, "PUT DATA");break; + case ISO7816_SELECT_FILE :snprintf(exp, size, "SELECT FILE");break; + case ISO7816_VERIFY :snprintf(exp, size, "VERIFY");break; + case ISO7816_INTERNAL_AUTHENTICATE :snprintf(exp, size, "INTERNAL AUTHENTICATE");break; + case ISO7816_EXTERNAL_AUTHENTICATE :snprintf(exp, size, "EXTERNAL AUTHENTICATE");break; + case ISO7816_GET_CHALLENGE :snprintf(exp, size, "GET CHALLENGE");break; + case ISO7816_MANAGE_CHANNEL :snprintf(exp, size, "MANAGE CHANNEL");break; + case ISO7816_GET_RESPONSE :snprintf(exp, size, "GET RESPONSE");break; + case ISO7816_ENVELOPE :snprintf(exp, size, "ENVELOPE");break; + case ISO7816_GET_PROCESSING_OPTIONS :snprintf(exp, size, "GET PROCESSING OPTIONS");break; + default :snprintf(exp,size,"?"); break; + } +} + + +void annotateIso14443_4(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize){ + // S-block + if ((cmd[0] & 0xc3) == 0xc2) { + switch (cmd[0] & 0x30) { + case 0x00 : snprintf(exp, size, "S-block DESELECT"); break; + case 0x30 : snprintf(exp, size, "S-block WTX"); break; + default : snprintf(exp, size, "S-block (RFU)"); break; + } + } + // R-block (ack) + else if ((cmd[0] & 0xe0) == 0xa0) { + if ((cmd[0] & 0x10) == 0) + snprintf(exp, size, "R-block ACK"); + else + snprintf(exp, size, "R-block NACK"); + } + // I-block + else { + int pos = 1; + switch (cmd[0] & 0x0c) { + case 0x08: // CID following + case 0x04: // NAD following + pos = 2; + break; + case 0x0c: // CID and NAD following + pos = 3; + break; + default: + pos = 1; // no CID, no NAD + break; + } + annotateIso7816(exp, size, &cmd[pos], cmdsize-pos); + } +} + + /** 06 00 = INITIATE 0E xx = SELECT ID (xx = Chip-ID) @@ -308,8 +387,8 @@ void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) { switch(cmd[0]) { - case ISO14443A_CMD_WUPA: - snprintf(exp,size,"WUPA"); + case ISO14443A_CMD_WUPA: + snprintf(exp,size,"WUPA"); break; case ISO14443A_CMD_ANTICOLL_OR_SELECT:{ // 93 20 = Anticollision (usage: 9320 - answer: 4bytes UID+1byte UID-bytes-xor) @@ -333,38 +412,38 @@ void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) snprintf(exp,size,"ANTICOLL-2"); break; } } - case ISO14443A_CMD_REQA: - snprintf(exp,size,"REQA"); + case ISO14443A_CMD_REQA: + snprintf(exp,size,"REQA"); break; - case ISO14443A_CMD_READBLOCK: snprintf(exp,size,"READBLOCK(%d)",cmd[1]); break; - case ISO14443A_CMD_WRITEBLOCK: snprintf(exp,size,"WRITEBLOCK(%d)",cmd[1]); break; - case ISO14443A_CMD_HALT: - snprintf(exp,size,"HALT"); + case ISO14443A_CMD_READBLOCK: snprintf(exp,size,"READBLOCK(%d)",cmd[1]); break; + case ISO14443A_CMD_WRITEBLOCK: snprintf(exp,size,"WRITEBLOCK(%d)",cmd[1]); break; + case ISO14443A_CMD_HALT: + snprintf(exp,size,"HALT"); MifareAuthState = masNone; break; - case ISO14443A_CMD_RATS: snprintf(exp,size,"RATS"); break; - case MIFARE_CMD_INC: snprintf(exp,size,"INC(%d)",cmd[1]); break; - case MIFARE_CMD_DEC: snprintf(exp,size,"DEC(%d)",cmd[1]); break; - case MIFARE_CMD_RESTORE: snprintf(exp,size,"RESTORE(%d)",cmd[1]); break; - case MIFARE_CMD_TRANSFER: snprintf(exp,size,"TRANSFER(%d)",cmd[1]); break; + case ISO14443A_CMD_RATS: snprintf(exp,size,"RATS"); break; + case MIFARE_CMD_INC: snprintf(exp,size,"INC(%d)",cmd[1]); break; + case MIFARE_CMD_DEC: snprintf(exp,size,"DEC(%d)",cmd[1]); break; + case MIFARE_CMD_RESTORE: snprintf(exp,size,"RESTORE(%d)",cmd[1]); break; + case MIFARE_CMD_TRANSFER: snprintf(exp,size,"TRANSFER(%d)",cmd[1]); break; case MIFARE_AUTH_KEYA: if ( cmdsize > 3) { - snprintf(exp,size,"AUTH-A(%d)",cmd[1]); + snprintf(exp,size,"AUTH-A(%d)",cmd[1]); MifareAuthState = masNt; } else { - // case MIFARE_ULEV1_VERSION : both 0x60. + // case MIFARE_ULEV1_VERSION : both 0x60. snprintf(exp,size,"EV1 VERSION"); } break; case MIFARE_AUTH_KEYB: MifareAuthState = masNt; - snprintf(exp,size,"AUTH-B(%d)",cmd[1]); + snprintf(exp,size,"AUTH-B(%d)",cmd[1]); break; - case MIFARE_MAGICWUPC1: snprintf(exp,size,"MAGIC WUPC1"); break; - case MIFARE_MAGICWUPC2: snprintf(exp,size,"MAGIC WUPC2"); break; - case MIFARE_MAGICWIPEC: snprintf(exp,size,"MAGIC WIPEC"); break; - case MIFARE_ULC_AUTH_1: snprintf(exp,size,"AUTH "); break; - case MIFARE_ULC_AUTH_2: snprintf(exp,size,"AUTH_ANSW"); break; + case MIFARE_MAGICWUPC1: snprintf(exp,size,"MAGIC WUPC1"); break; + case MIFARE_MAGICWUPC2: snprintf(exp,size,"MAGIC WUPC2"); break; + case MIFARE_MAGICWIPEC: snprintf(exp,size,"MAGIC WIPEC"); break; + case MIFARE_ULC_AUTH_1: snprintf(exp,size,"AUTH "); break; + case MIFARE_ULC_AUTH_2: snprintf(exp,size,"AUTH_ANSW"); break; case MIFARE_ULEV1_AUTH: if ( cmdsize == 7 ) snprintf(exp,size,"PWD-AUTH KEY: 0x%02x%02x%02x%02x", cmd[1], cmd[2], cmd[3], cmd[4] ); @@ -373,14 +452,14 @@ void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) break; case MIFARE_ULEV1_FASTREAD:{ if ( cmdsize >=3 && cmd[2] <= 0xE6) - snprintf(exp,size,"READ RANGE (%d-%d)",cmd[1],cmd[2]); + snprintf(exp,size,"READ RANGE (%d-%d)",cmd[1],cmd[2]); else snprintf(exp,size,"?"); break; } case MIFARE_ULC_WRITE:{ if ( cmd[1] < 0x21 ) - snprintf(exp,size,"WRITEBLOCK(%d)",cmd[1]); + snprintf(exp,size,"WRITEBLOCK(%d)",cmd[1]); else snprintf(exp,size,"?"); break; @@ -399,10 +478,10 @@ void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) snprintf(exp,size,"?"); break; } - case MIFARE_ULEV1_READSIG: snprintf(exp,size,"READ_SIG"); break; - case MIFARE_ULEV1_CHECKTEAR: snprintf(exp,size,"CHK_TEARING(%d)",cmd[1]); break; - case MIFARE_ULEV1_VCSL: snprintf(exp,size,"VCSL"); break; - default: snprintf(exp,size,"?"); break; + case MIFARE_ULEV1_READSIG: snprintf(exp,size,"READ_SIG"); break; + case MIFARE_ULEV1_CHECKTEAR: snprintf(exp,size,"CHK_TEARING(%d)",cmd[1]); break; + case MIFARE_ULEV1_VCSL: snprintf(exp,size,"VCSL"); break; + default: snprintf(exp,size,"?"); break; } return; } @@ -410,15 +489,15 @@ void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) void annotateMifare(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize, uint8_t* parity, uint8_t paritysize, bool isResponse) { if (!isResponse && cmdsize == 1) { switch(cmd[0]) { - case ISO14443A_CMD_WUPA: - case ISO14443A_CMD_REQA: + case ISO14443A_CMD_WUPA: + case ISO14443A_CMD_REQA: MifareAuthState = masNone; break; default: break; } } - + // get UID if (MifareAuthState == masNone) { if (cmdsize == 9 && cmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && cmd[1] == 0x70) { @@ -430,7 +509,7 @@ void annotateMifare(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize, uint8 AuthData.uid = bytes_to_num(&cmd[2], 4); } } - + switch(MifareAuthState) { case masNt: if (cmdsize == 4 && isResponse) { @@ -473,10 +552,10 @@ void annotateMifare(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize, uint8 default: break; } - + if (!isResponse && ((MifareAuthState == masNone) || (MifareAuthState == masError))) annotateIso14443a(exp, size, cmd, cmdsize); - + } @@ -490,7 +569,7 @@ static uint64_t GetCrypto1ProbableKey(TAuthData *ad) { uint64_t lfsr = 0; crypto1_get_lfsr(revstate, &lfsr); crypto1_destroy(revstate); - + return lfsr; } @@ -502,7 +581,7 @@ static bool NTParityChk(TAuthData *ad, uint32_t ntx) { (oddparity8(ntx >> 24 & 0xff) ^ (ntx >> 16 & 0x01) ^ ((ad->nt_enc_par >> 7) & 0x01) ^ (ad->nt_enc >> 16 & 0x01)) ) return false; - + uint32_t ar = prng_successor(ntx, 64); if ( (oddparity8(ar >> 8 & 0xff) ^ (ar & 0x01) ^ ((ad->ar_enc_par >> 5) & 0x01) ^ (ad->ar_enc & 0x01)) || @@ -519,7 +598,7 @@ static bool NTParityChk(TAuthData *ad, uint32_t ntx) { (oddparity8(at >> 24 & 0xff) ^ (at >> 16 & 0x01) ^ ((ad->at_enc_par >> 7) & 0x01) ^ (ad->at_enc >> 16 & 0x01)) ) return false; - + return true; } @@ -529,7 +608,7 @@ static bool CheckCrypto1Parity(uint8_t *cmd_enc, uint8_t cmdsize, uint8_t *cmd, if (oddparity8(cmd[i]) ^ (cmd[i + 1] & 0x01) ^ ((parity_enc[i / 8] >> (7 - i % 8)) & 0x01) ^ (cmd_enc[i + 1] & 0x01)) return false; } - + return true; } @@ -537,7 +616,7 @@ static bool CheckCrypto1Parity(uint8_t *cmd_enc, uint8_t cmdsize, uint8_t *cmd, static bool NestedCheckKey(uint64_t key, TAuthData *ad, uint8_t *cmd, uint8_t cmdsize, uint8_t *parity) { uint8_t buf[32] = {0}; struct Crypto1State *pcs; - + AuthData.ks2 = 0; AuthData.ks3 = 0; @@ -547,7 +626,7 @@ static bool NestedCheckKey(uint64_t key, TAuthData *ad, uint8_t *cmd, uint8_t cm uint32_t at = prng_successor(nt1, 96); crypto1_word(pcs, ad->nr_enc, 1); -// uint32_t nr1 = crypto1_word(pcs, ad->nr_enc, 1) ^ ad->nr_enc; // if needs deciphered nr +// uint32_t nr1 = crypto1_word(pcs, ad->nr_enc, 1) ^ ad->nr_enc; // if needs deciphered nr uint32_t ar1 = crypto1_word(pcs, 0, 0) ^ ad->ar_enc; uint32_t at1 = crypto1_word(pcs, 0, 0) ^ ad->at_enc; @@ -558,15 +637,15 @@ static bool NestedCheckKey(uint64_t key, TAuthData *ad, uint8_t *cmd, uint8_t cm memcpy(buf, cmd, cmdsize); mf_crypto1_decrypt(pcs, buf, cmdsize, 0); - + crypto1_destroy(pcs); - + if (!CheckCrypto1Parity(cmd, cmdsize, buf, parity)) return false; - if(!CheckCrc14443(CRC_14443_A, buf, cmdsize)) + if(!CheckCrc14443(CRC_14443_A, buf, cmdsize)) return false; - + AuthData.nt = nt1; AuthData.ks2 = AuthData.ar_enc ^ ar; AuthData.ks3 = AuthData.at_enc ^ at; @@ -576,11 +655,11 @@ static bool NestedCheckKey(uint64_t key, TAuthData *ad, uint8_t *cmd, uint8_t cm static bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isResponse, uint8_t *mfData, size_t *mfDataLen) { - static struct Crypto1State *traceCrypto1; + static struct Crypto1State *traceCrypto1; static uint64_t mfLastKey; - + *mfDataLen = 0; - + if (MifareAuthState == masAuthComplete) { if (traceCrypto1) { crypto1_destroy(traceCrypto1); @@ -590,22 +669,22 @@ static bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, boo MifareAuthState = masFirstData; return false; } - + if (cmdsize > 32) return false; - + if (MifareAuthState == masFirstData) { if (AuthData.first_auth) { AuthData.ks2 = AuthData.ar_enc ^ prng_successor(AuthData.nt, 64); AuthData.ks3 = AuthData.at_enc ^ prng_successor(AuthData.nt, 96); mfLastKey = GetCrypto1ProbableKey(&AuthData); - PrintAndLog(" | * | key | probable key:%012"PRIx64" Prng:%s ks2:%08x ks3:%08x | |", + PrintAndLog(" | * | key | probable key:%012"PRIx64" Prng:%s ks2:%08x ks3:%08x | |", mfLastKey, validate_prng_nonce(AuthData.nt) ? "WEAK": "HARD", AuthData.ks2, AuthData.ks3); - + AuthData.first_auth = false; traceCrypto1 = lfsr_recovery64(AuthData.ks2, AuthData.ks3); @@ -618,7 +697,7 @@ static bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, boo // check last used key if (mfLastKey) { if (NestedCheckKey(mfLastKey, &AuthData, cmd, cmdsize, parity)) { - PrintAndLog(" | * | key | last used key:%012"PRIx64" ks2:%08x ks3:%08x | |", + PrintAndLog(" | * | key | last used key:%012"PRIx64" ks2:%08x ks3:%08x | |", mfLastKey, AuthData.ks2, AuthData.ks3); @@ -626,12 +705,12 @@ static bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, boo traceCrypto1 = lfsr_recovery64(AuthData.ks2, AuthData.ks3); }; } - + // check default keys if (!traceCrypto1) { for (int defaultKeyCounter = 0; defaultKeyCounter < MifareDefaultKeysSize; defaultKeyCounter++){ if (NestedCheckKey(MifareDefaultKeys[defaultKeyCounter], &AuthData, cmd, cmdsize, parity)) { - PrintAndLog(" | * | key | default key:%012"PRIx64" ks2:%08x ks3:%08x | |", + PrintAndLog(" | * | key | default key:%012"PRIx64" ks2:%08x ks3:%08x | |", MifareDefaultKeys[defaultKeyCounter], AuthData.ks2, AuthData.ks3); @@ -642,10 +721,10 @@ static bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, boo }; } } - + // nested if (!traceCrypto1 && validate_prng_nonce(AuthData.nt)) { - uint32_t ntx = prng_successor(AuthData.nt, 90); + uint32_t ntx = prng_successor(AuthData.nt, 90); for (int i = 0; i < 16383; i++) { ntx = prng_successor(ntx, 1); if (NTParityChk(&AuthData, ntx)){ @@ -655,7 +734,7 @@ static bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, boo struct Crypto1State *pcs = lfsr_recovery64(ks2, ks3); memcpy(mfData, cmd, cmdsize); mf_crypto1_decrypt(pcs, mfData, cmdsize, 0); - + crypto1_destroy(pcs); if (CheckCrypto1Parity(cmd, cmdsize, mfData, parity) && CheckCrc14443(CRC_14443_A, mfData, cmdsize)) { AuthData.ks2 = ks2; @@ -663,7 +742,7 @@ static bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, boo AuthData.nt = ntx; mfLastKey = GetCrypto1ProbableKey(&AuthData); - PrintAndLog(" | * | key | nested probable key:%012"PRIx64" ks2:%08x ks3:%08x | |", + PrintAndLog(" | * | key | nested probable key:%012"PRIx64" ks2:%08x ks3:%08x | |", mfLastKey, AuthData.ks2, AuthData.ks3); @@ -671,10 +750,10 @@ static bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, boo traceCrypto1 = lfsr_recovery64(AuthData.ks2, AuthData.ks3); break; } - } + } } } - + //hardnested if (!traceCrypto1) { printf("hardnested not implemented. uid:%x nt:%x ar_enc:%x at_enc:%x\n", AuthData.uid, AuthData.nt, AuthData.ar_enc, AuthData.at_enc); @@ -707,18 +786,18 @@ static bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, boo */ } } - - - + + + MifareAuthState = masData; } - + if (MifareAuthState == masData && traceCrypto1) { memcpy(mfData, cmd, cmdsize); mf_crypto1_decrypt(traceCrypto1, mfData, cmdsize, 0); *mfDataLen = cmdsize; } - + return *mfDataLen > 0; } @@ -732,7 +811,7 @@ bool is_last_record(uint16_t tracepos, uint8_t *trace, uint16_t traceLen) bool next_record_is_response(uint16_t tracepos, uint8_t *trace) { uint16_t next_records_datalen = *((uint16_t *)(trace + tracepos + sizeof(uint32_t) + sizeof(uint16_t))); - + return(next_records_datalen & 0x8000); } @@ -740,7 +819,7 @@ bool next_record_is_response(uint16_t tracepos, uint8_t *trace) bool merge_topaz_reader_frames(uint32_t timestamp, uint32_t *duration, uint16_t *tracepos, uint16_t traceLen, uint8_t *trace, uint8_t *frame, uint8_t *topaz_reader_command, uint16_t *data_len) { -#define MAX_TOPAZ_READER_CMD_LEN 16 +#define MAX_TOPAZ_READER_CMD_LEN 16 uint32_t last_timestamp = timestamp + *duration; @@ -771,7 +850,7 @@ bool merge_topaz_reader_frames(uint32_t timestamp, uint32_t *duration, uint16_t } *duration = last_timestamp - timestamp; - + return true; } @@ -788,7 +867,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui size_t mfDataLen = 0; if (tracepos + sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t) > traceLen) return traceLen; - + first_timestamp = *((uint32_t *)(trace)); timestamp = *((uint32_t *)(trace + tracepos)); @@ -821,7 +900,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui frame = topaz_reader_command; } } - + //Check the CRC status uint8_t crcStatus = 2; @@ -832,7 +911,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui break; case ISO_14443B: case TOPAZ: - crcStatus = iso14443B_CRC_check(isResponse, frame, data_len); + crcStatus = iso14443B_CRC_check(isResponse, frame, data_len); break; case PROTO_MIFARE: crcStatus = mifare_CRC_check(isResponse, frame, data_len); @@ -840,10 +919,13 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui case ISO_14443A: crcStatus = iso14443A_CRC_check(isResponse, frame, data_len); break; + case ISO_14443_4: + crcStatus = iso14443_4_CRC_check(frame, data_len); + break; case ISO_15693: crcStatus = iso15693_CRC_check(frame, data_len); break; - default: + default: break; } } @@ -852,17 +934,16 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui //2 Not crc-command //--- Draw the data column - //char line[16][110]; char line[16][110]; for (int j = 0; j < data_len && j/16 < 16; j++) { uint8_t parityBits = parityBytes[j>>3]; - if (protocol != ISO_14443B - && protocol != ISO_15693 - && protocol != ISO_7816_4 - && (isResponse || protocol == ISO_14443A) - && (oddparity8(frame[j]) != ((parityBits >> (7-(j&0x0007))) & 0x01))) { + if (protocol != ISO_14443B + && protocol != ISO_15693 + && protocol != ISO_7816_4 + && (isResponse || protocol == ISO_14443A) + && (oddparity8(frame[j]) != ((parityBits >> (7-(j&0x0007))) & 0x01))) { snprintf(line[j/16]+(( j % 16) * 4), 110, " %02x!", frame[j]); } else { snprintf(line[j/16]+(( j % 16) * 4), 110, " %02x ", frame[j]); @@ -891,16 +972,18 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui if (protocol == PROTO_MIFARE) annotateMifare(explanation, sizeof(explanation), frame, data_len, parityBytes, parity_len, isResponse); - + if(!isResponse) { switch(protocol) { - case ICLASS: annotateIclass(explanation,sizeof(explanation),frame,data_len); break; - case ISO_14443A: annotateIso14443a(explanation,sizeof(explanation),frame,data_len); break; - case ISO_14443B: annotateIso14443b(explanation,sizeof(explanation),frame,data_len); break; - case TOPAZ: annotateTopaz(explanation,sizeof(explanation),frame,data_len); break; - case ISO_15693: annotateIso15693(explanation,sizeof(explanation),frame,data_len); break; - default: break; + case ICLASS: annotateIclass(explanation,sizeof(explanation),frame,data_len); break; + case ISO_14443A: annotateIso14443a(explanation,sizeof(explanation),frame,data_len); break; + case ISO_14443B: annotateIso14443b(explanation,sizeof(explanation),frame,data_len); break; + case TOPAZ: annotateTopaz(explanation,sizeof(explanation),frame,data_len); break; + case ISO_15693: annotateIso15693(explanation,sizeof(explanation),frame,data_len); break; + case ISO_7816_4: annotateIso7816(explanation, sizeof(explanation), frame, data_len); break; + case ISO_14443_4: annotateIso14443_4(explanation, sizeof(explanation), frame, data_len); break; + default: break; } } @@ -921,7 +1004,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui (j == num_lines-1) ? explanation : ""); } } - + if (DecodeMifareData(frame, data_len, parityBytes, isResponse, mfData, &mfDataLen)) { memset(explanation, 0x00, sizeof(explanation)); if (!isResponse) { @@ -936,7 +1019,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui }; if (is_last_record(tracepos, trace, traceLen)) return traceLen; - + if (showWaitCycles && !isResponse && next_record_is_response(tracepos, trace)) { uint32_t next_timestamp = *((uint32_t *)(trace + tracepos)); PrintAndLog(" %10d | %10d | %s | fdt (Frame Delay Time): %d", @@ -955,14 +1038,16 @@ int CmdHFList(const char *Cmd) bool showWaitCycles = false; bool markCRCBytes = false; bool loadFromFile = false; + bool PCSCtrace = false; bool saveToFile = false; char param1 = '\0'; char param2 = '\0'; char param3 = '\0'; + char param4 = '\0'; char type[40] = {0}; char filename[FILE_PATH_SIZE] = {0}; uint8_t protocol = 0; - + // parse command line int tlen = param_getstr(Cmd, 0, type, sizeof(type)); if (param_getlength(Cmd, 1) == 1) { @@ -980,8 +1065,13 @@ int CmdHFList(const char *Cmd) } else if (strlen(filename) == 0) { param_getstr(Cmd, 3, filename, sizeof(filename)); } + if (param_getlength(Cmd, 4) == 1) { + param4 = param_getchar(Cmd, 4); + } else if (strlen(filename) == 0) { + param_getstr(Cmd, 4, filename, sizeof(filename)); + } - // Validate param1 + // Validate params bool errors = false; if(tlen == 0) { @@ -989,37 +1079,43 @@ int CmdHFList(const char *Cmd) } if(param1 == 'h' - || (param1 != 0 && param1 != 'f' && param1 != 'c' && param1 != 'l') - || (param2 != 0 && param2 != 'f' && param2 != 'c' && param2 != 'l') - || (param3 != 0 && param3 != 'f' && param3 != 'c' && param3 != 'l')) { + || (param1 != 0 && param1 != 'f' && param1 != 'c' && param1 != 'l' && param1 != 'p') + || (param2 != 0 && param2 != 'f' && param2 != 'c' && param2 != 'l' && param1 != 'p') + || (param3 != 0 && param3 != 'f' && param3 != 'c' && param3 != 'l' && param1 != 'p') + || (param4 != 0 && param4 != 'f' && param4 != 'c' && param4 != 'l' && param4 != 'p')) { errors = true; } if(!errors) { - if (strcmp(type, "iclass") == 0) protocol = ICLASS; - else if(strcmp(type, "14a") == 0) protocol = ISO_14443A; - else if(strcmp(type, "mf") == 0) protocol = PROTO_MIFARE; - else if(strcmp(type, "14b") == 0) protocol = ISO_14443B; - else if(strcmp(type, "topaz") == 0) protocol = TOPAZ; - else if(strcmp(type, "7816") == 0) protocol = ISO_7816_4; - else if(strcmp(type, "15") == 0) protocol = ISO_15693; - else if(strcmp(type, "raw") == 0) protocol = -1;//No crc, no annotations - else if (strcmp(type, "save") == 0) saveToFile = true; + if (strcmp(type, "iclass") == 0) protocol = ICLASS; + else if(strcmp(type, "14a") == 0) protocol = ISO_14443A; + else if(strcmp(type, "mf") == 0) protocol = PROTO_MIFARE; + else if(strcmp(type, "14b") == 0) protocol = ISO_14443B; + else if(strcmp(type, "topaz") == 0) protocol = TOPAZ; + else if(strcmp(type, "7816") == 0) protocol = ISO_7816_4; + else if(strcmp(type, "14-4") == 0) protocol = ISO_14443_4; + else if(strcmp(type, "15") == 0) protocol = ISO_15693; + else if(strcmp(type, "raw") == 0) protocol = -1;//No crc, no annotations + else if (strcmp(type, "save") == 0) saveToFile = true; else errors = true; } - - if (param1 == 'f' || param2 == 'f' || param3 == 'f') { + + if (param1 == 'f' || param2 == 'f' || param3 == 'f' || param4 == 'f') { showWaitCycles = true; } - if (param1 == 'c' || param2 == 'c' || param3 == 'c') { + if (param1 == 'c' || param2 == 'c' || param3 == 'c' || param4 == 'c') { markCRCBytes = true; } - if (param1 == 'l' || param2 == 'l' || param3 == 'l') { + if (param1 == 'l' || param2 == 'l' || param3 == 'l' || param4 == 'l') { loadFromFile = true; } + if (param1 == 'p' || param2 == 'p' || param3 == 'p' || param4 == 'p') { + PCSCtrace = true; + } + if ((loadFromFile || saveToFile) && strlen(filename) == 0) { errors = true; } @@ -1027,13 +1123,14 @@ int CmdHFList(const char *Cmd) if (loadFromFile && saveToFile) { errors = true; } - + if (errors) { PrintAndLog("List or save protocol data."); - PrintAndLog("Usage: hf list [f] [c] [l ]"); + PrintAndLog("Usage: hf list [f] [c] [p] [l ]"); PrintAndLog(" hf list save "); PrintAndLog(" f - show frame delay times as well"); PrintAndLog(" c - mark CRC bytes"); + PrintAndLog(" p - use trace buffer from PCSC card reader instead of PM3"); PrintAndLog(" l - load data from file instead of trace buffer"); PrintAndLog(" save - save data to file"); PrintAndLog("Supported values:"); @@ -1044,6 +1141,8 @@ int CmdHFList(const char *Cmd) PrintAndLog(" 15 - interpret data as iso15693 communications"); PrintAndLog(" iclass - interpret data as iclass communications"); PrintAndLog(" topaz - interpret data as topaz communications"); + PrintAndLog(" 7816 - interpret data as 7816-4 APDU communications"); + PrintAndLog(" 14-4 - interpret data as ISO14443-4 communications"); PrintAndLog(""); PrintAndLog("example: hf list 14a f"); PrintAndLog("example: hf list iclass"); @@ -1056,9 +1155,9 @@ int CmdHFList(const char *Cmd) uint8_t *trace; uint32_t tracepos = 0; uint32_t traceLen = 0; - + if (loadFromFile) { - #define TRACE_CHUNK_SIZE (1<<16) // 64K to start with. Will be enough for BigBuf and some room for future extensions + #define TRACE_CHUNK_SIZE (1<<16) // 64K to start with. Will be enough for BigBuf and some room for future extensions FILE *tracefile = NULL; size_t bytes_read; trace = malloc(TRACE_CHUNK_SIZE); @@ -1066,7 +1165,7 @@ int CmdHFList(const char *Cmd) PrintAndLog("Cannot allocate memory for trace"); return 2; } - if ((tracefile = fopen(filename,"rb")) == NULL) { + if ((tracefile = fopen(filename,"rb")) == NULL) { PrintAndLog("Could not open file %s", filename); free(trace); return 0; @@ -1086,6 +1185,9 @@ int CmdHFList(const char *Cmd) } } fclose(tracefile); + } else if (PCSCtrace) { + trace = pcsc_get_trace_addr(); + traceLen = pcsc_get_traceLen(); } else { trace = malloc(USB_CMD_DATA_SIZE); // Query for the size of the trace @@ -1106,7 +1208,7 @@ int CmdHFList(const char *Cmd) if (saveToFile) { FILE *tracefile = NULL; - if ((tracefile = fopen(filename,"wb")) == NULL) { + if ((tracefile = fopen(filename,"wb")) == NULL) { PrintAndLog("Could not create file %s", filename); return 1; } diff --git a/client/cmdsmartcard.c b/client/cmdsmartcard.c index 53ee9119..ac642fc9 100644 --- a/client/cmdsmartcard.c +++ b/client/cmdsmartcard.c @@ -929,7 +929,11 @@ static int CmdSmartSetClock(const char *Cmd){ static int CmdSmartList(const char *Cmd) { - CmdHFList("7816"); + if (UseAlternativeSmartcardReader) { + CmdHFList("7816 p"); + } else { + CmdHFList("7816"); + } return 0; } diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index 93235f5e..46fc1b1e 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -654,7 +654,7 @@ int EMVSelectApplication(struct tlvdb *tlv, uint8_t *AID, size_t *AIDlen) { int EMVGPO(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - uint8_t GPO_APDU[APDU_COMMAND_LEN] = {0x80, 0xa8, 0x00, 0x00, PDOLLen, 0x00}; + uint8_t GPO_APDU[APDU_COMMAND_LEN] = {0x80, ISO7816_GET_PROCESSING_OPTIONS, 0x00, 0x00, PDOLLen, 0x00}; memcpy(GPO_APDU + 5, PDOL, PDOLLen); int apdulen = 5 + PDOLLen; @@ -695,7 +695,7 @@ int EMVGenerateChallenge(EMVCommandChannel channel, bool LeaveFieldON, uint8_t * int EMVInternalAuthenticate(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { - uint8_t authenticate_APDU[APDU_COMMAND_LEN] = {0x00, ISO7816_INTERNAL_AUTHENTICATION, 0x00, 0x00, DDOLLen, 0x00}; + uint8_t authenticate_APDU[APDU_COMMAND_LEN] = {0x00, ISO7816_INTERNAL_AUTHENTICATE, 0x00, 0x00, DDOLLen, 0x00}; memcpy(authenticate_APDU + 5, DDOL, DDOLLen); int apdulen = 5 + DDOLLen; diff --git a/client/pcsc.c b/client/pcsc.c index c54efacc..ca87eb34 100644 --- a/client/pcsc.c +++ b/client/pcsc.c @@ -39,6 +39,92 @@ static SCARDHANDLE SC_Card; static DWORD SC_Protocol; static char* AlternativeSmartcardReader = NULL; +#define PCSC_MAX_TRACELEN 60000 +static uint8_t pcsc_trace_buf[PCSC_MAX_TRACELEN]; +static bool tracing = false; +static uint32_t traceLen = 0; + + +uint8_t *pcsc_get_trace_addr(void) +{ + return pcsc_trace_buf; +} + + +uint32_t pcsc_get_traceLen(void) +{ + return traceLen; +} + + +static void pcsc_clear_trace(void) +{ + traceLen = 0; +} + + +static void pcsc_set_tracing(bool enable) { + tracing = enable; +} + + +static bool pcsc_LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, bool readerToTag) +{ + if (!tracing) return false; + + uint8_t *trace = pcsc_trace_buf; + + uint32_t num_paritybytes = (iLen-1)/8 + 1; // number of paritybytes + uint32_t duration = timestamp_end - timestamp_start; + + // Return when trace is full + if (traceLen + sizeof(iLen) + sizeof(timestamp_start) + sizeof(duration) + num_paritybytes + iLen >= PCSC_MAX_TRACELEN) { + tracing = false; // don't trace any more + return false; + } + // Traceformat: + // 32 bits timestamp (little endian) + // 16 bits duration (little endian) + // 16 bits data length (little endian, Highest Bit used as readerToTag flag) + // y Bytes data + // x Bytes parity (one byte per 8 bytes data) + + // timestamp (start) + trace[traceLen++] = ((timestamp_start >> 0) & 0xff); + trace[traceLen++] = ((timestamp_start >> 8) & 0xff); + trace[traceLen++] = ((timestamp_start >> 16) & 0xff); + trace[traceLen++] = ((timestamp_start >> 24) & 0xff); + + // duration + trace[traceLen++] = ((duration >> 0) & 0xff); + trace[traceLen++] = ((duration >> 8) & 0xff); + + // data length + trace[traceLen++] = ((iLen >> 0) & 0xff); + trace[traceLen++] = ((iLen >> 8) & 0xff); + + // readerToTag flag + if (!readerToTag) { + trace[traceLen - 1] |= 0x80; + } + + // data bytes + if (btBytes != NULL && iLen != 0) { + for (int i = 0; i < iLen; i++) { + trace[traceLen++] = *btBytes++; + } + } + + // dummy parity bytes + if (num_paritybytes != 0) { + for (int i = 0; i < num_paritybytes; i++) { + trace[traceLen++] = 0x00; + } + } + + return true; +} + char *getAlternativeSmartcardReader(void) { @@ -194,6 +280,9 @@ bool pcscSelectAlternativeCardReader(const char *readername) bool pcscGetATR(smart_card_atr_t *card) { + pcsc_clear_trace(); + pcsc_set_tracing(true); + if (!card) { return false; } @@ -214,8 +303,10 @@ bool pcscGetATR(smart_card_atr_t *card) } card->atr_len = atr_len; - // TODO: LogTrace without device - + pcsc_LogTrace(card->atr, card->atr_len, 0, 0, false); + + pcsc_set_tracing(false); + return true; } @@ -229,11 +320,10 @@ void pcscTransmit(uint8_t *data, uint32_t data_len, uint32_t flags, uint8_t *res protocol = SCARD_PCI_RAW; } - // TODO: tracing - // if ((flags & SC_CONNECT)) - // clear_trace(); + if ((flags & SC_CONNECT)) + pcsc_clear_trace(); - // set_tracing(true); + pcsc_set_tracing(true); if ((flags & SC_CONNECT || flags & SC_SELECT)) { LONG res = SCardConnect(SC_Context, AlternativeSmartcardReader, SCARD_SHARE_SHARED, @@ -245,14 +335,15 @@ void pcscTransmit(uint8_t *data, uint32_t data_len, uint32_t flags, uint8_t *res } if ((flags & SC_RAW) || (flags & SC_RAW_T0)) { - // TODO: tracing - // LogTrace(data, arg1, 0, 0, NULL, true); + pcsc_LogTrace(data, data_len, 0, 0, true); DWORD len = *response_len; LONG res = SCardTransmit(SC_Card, protocol, data, data_len, NULL, response, &len); if (res != SCARD_S_SUCCESS) { *response_len = -1; } else { + pcsc_LogTrace(response, len, 0, 0, false); *response_len = len; } } + pcsc_set_tracing(false); } diff --git a/client/pcsc.h b/client/pcsc.h index 27083518..4de8499f 100644 --- a/client/pcsc.h +++ b/client/pcsc.h @@ -11,9 +11,12 @@ #ifndef PCSC_H__ #define PCSC_H__ +#include #include #include "smartcard.h" +uint8_t *pcsc_get_trace_addr(void); +uint32_t pcsc_get_traceLen(void); char *getAlternativeSmartcardReader(void); bool pcscCheckForCardReaders(void); bool pcscSelectAlternativeCardReader(const char *readername); diff --git a/common/protocols.h b/common/protocols.h index 191c55f9..39fed40f 100644 --- a/common/protocols.h +++ b/common/protocols.h @@ -235,6 +235,7 @@ NXP/Philips CUSTOM COMMANDS #define PROTO_MIFARE 4 #define ISO_7816_4 5 #define ISO_15693 6 +#define ISO_14443_4 7 //-- Picopass fuses @@ -248,23 +249,25 @@ NXP/Philips CUSTOM COMMANDS #define FUSE_RA 0x01 // ISO 7816-4 Basic interindustry commands. For command APDU's. -#define ISO7816_READ_BINARY 0xB0 -#define ISO7816_WRITE_BINARY 0xD0 -#define ISO7816_UPDATE_BINARY 0xD6 #define ISO7816_ERASE_BINARY 0x0E -#define ISO7816_READ_RECORDS 0xB2 -#define ISO7816_WRITE_RECORDS 0xD2 -#define ISO7816_APPEND_RECORD 0xE2 -#define ISO7816_UPDATE_RECORD 0xDC -#define ISO7816_GET_DATA 0xCA -#define ISO7816_PUT_DATA 0xDA -#define ISO7816_SELECT_FILE 0xA4 #define ISO7816_VERIFY 0x20 -#define ISO7816_INTERNAL_AUTHENTICATION 0x88 -#define ISO7816_EXTERNAL_AUTHENTICATION 0x82 -#define ISO7816_GET_CHALLENGE 0x84 #define ISO7816_MANAGE_CHANNEL 0x70 +#define ISO7816_EXTERNAL_AUTHENTICATE 0x82 +#define ISO7816_GET_CHALLENGE 0x84 +#define ISO7816_INTERNAL_AUTHENTICATE 0x88 +#define ISO7816_SELECT_FILE 0xA4 +#define ISO7816_GET_PROCESSING_OPTIONS 0xA8 +#define ISO7816_READ_BINARY 0xB0 +#define ISO7816_READ_RECORDS 0xB2 #define ISO7816_GET_RESPONSE 0xC0 +#define ISO7816_ENVELOPE 0xC2 +#define ISO7816_GET_DATA 0xCA +#define ISO7816_WRITE_BINARY 0xD0 +#define ISO7816_WRITE_RECORD 0xD2 +#define ISO7816_UPDATE_BINARY 0xD6 +#define ISO7816_PUT_DATA 0xDA +#define ISO7816_UPDATE_DATA 0xDC +#define ISO7816_APPEND_RECORD 0xE2 // ISO7816-4 For response APDU's #define ISO7816_OK 0x9000 // 6x xx = ERROR From 7afa751a9673c0427d75116eac14dce2d19adedb Mon Sep 17 00:00:00 2001 From: Fl0-0 Date: Sun, 17 Feb 2019 14:43:40 +0100 Subject: [PATCH 065/189] Fix for USB uart slowness since PR #720 (#787) --- uart/uart_posix.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/uart/uart_posix.c b/uart/uart_posix.c index 1db375b2..214cb56a 100644 --- a/uart/uart_posix.c +++ b/uart/uart_posix.c @@ -69,9 +69,9 @@ typedef struct { } serial_port_unix; // Set time-out on 30 miliseconds -const struct timeval timeout = { +struct timeval timeout = { .tv_sec = 0, // 0 second - .tv_usec = 300000 // 300000 micro seconds + .tv_usec = 30000 // 30000 micro seconds }; serial_port uart_open(const char* pcPortName) @@ -88,6 +88,10 @@ serial_port uart_open(const char* pcPortName) } char *colon = strrchr(addrstr, ':'); char *portstr; + + // Set time-out to 300 miliseconds only for TCP port + timeout.tv_usec = 300000; + if (colon) { portstr = colon + 1; *colon = '\0'; From 7527c2bdd821ac194ed362f327b5e6b7aef7d1bb Mon Sep 17 00:00:00 2001 From: Oleg Moiseenko <807634+merlokk@users.noreply.github.com> Date: Wed, 20 Feb 2019 19:35:39 +0200 Subject: [PATCH 066/189] fix rare bug in tlv.c (#788) --- client/emv/tlv.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/client/emv/tlv.c b/client/emv/tlv.c index 9722c931..05de928e 100644 --- a/client/emv/tlv.c +++ b/client/emv/tlv.c @@ -352,7 +352,13 @@ struct tlvdb *tlvdb_find_path(struct tlvdb *tlvdb, tlv_tag_t tag[]) { void tlvdb_add(struct tlvdb *tlvdb, struct tlvdb *other) { + if (tlvdb == other) + return; + while (tlvdb->next) { + if (tlvdb->next == other) + return; + tlvdb = tlvdb->next; } From fc52fbd42f576d889826f4a0c60d18fad41bc3af Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Wed, 20 Feb 2019 19:18:12 +0100 Subject: [PATCH 067/189] Add raw HF signal plotting (#786) * Add raw HF signal plotting * new fpga module hi_get_trace.v - store A/D converter output to circular buffer on FPGA * new command 'hf plot' - pull data from FPGA and display it in Graph Window --- CHANGELOG.md | 7 +- armsrc/appmain.c | 8 ++- armsrc/apps.h | 6 -- armsrc/fpgaloader.c | 22 +++++- armsrc/fpgaloader.h | 15 +++- armsrc/hfsnoop.c | 48 ++++++++++++- armsrc/hfsnoop.h | 17 +++++ armsrc/hitag2.c | 1 + armsrc/hitagS.c | 1 + armsrc/iclass.c | 1 + armsrc/iso14443a.c | 24 +++++-- armsrc/iso14443b.c | 4 +- armsrc/iso15693.c | 1 + armsrc/legicrf.c | 5 +- armsrc/legicrfsim.c | 5 +- armsrc/lfops.c | 1 + armsrc/lfsampling.c | 2 +- armsrc/mifarecmd.c | 2 +- armsrc/mifaresniff.c | 5 +- armsrc/pcf7931.c | 1 + client/cmdhf.c | 93 ++++++++++++++++++++----- client/cmdparser.h | 2 +- client/comms.c | 33 +++++++++ client/comms.h | 1 + common/fpga.h | 1 + fpga/Makefile | 2 +- fpga/fpga_hf.bit | Bin 42175 -> 42175 bytes fpga/fpga_hf.v | 34 +++++---- fpga/hi_get_trace.v | 160 +++++++++++++++++++++++++++++++++++++++++++ include/usb_cmd.h | 1 + 30 files changed, 441 insertions(+), 62 deletions(-) create mode 100644 armsrc/hfsnoop.h create mode 100644 fpga/hi_get_trace.v diff --git a/CHANGELOG.md b/CHANGELOG.md index f2c285b4..c2bf52c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ### Fixed - AC-Mode decoding for HitagS - Wrong UID at HitagS simulation -- 'hf 15 sim' now works as expected (piwi) +- `hf 15 sim` now works as expected (piwi) ### Added - Support Standard Communication Mode in HITAG S @@ -25,8 +25,9 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added `hf fido` `assert` and `make` commands from fido2 protocol (authenticatorMakeCredential and authenticatorGetAssertion) (Merlok) - Added `lf paradox clone` to clone a Paradox card - Added `emv` commmands working for both contactless and smart cards (Merlok) -- Added 'hf 15 snoop' (piwi) - +- Added `hf 15 snoop` (piwi) +- Added support for standard USB Smartcard Readers (piwi) +- Added `hf plot` (piwi) ## [v3.1.0][2018-10-10] diff --git a/armsrc/appmain.c b/armsrc/appmain.c index cdc784c0..2a16f5f0 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -30,6 +30,8 @@ #include "mifareutil.h" #include "pcf7931.h" #include "i2c.h" +#include "hfsnoop.h" +#include "fpgaloader.h" #ifdef WITH_LCD #include "LCD.h" #endif @@ -1323,11 +1325,16 @@ void UsbPacketReceived(uint8_t *packet, int len) iClass_Clone(c->arg[0], c->arg[1], c->d.asBytes); break; #endif + #ifdef WITH_HFSNOOP case CMD_HF_SNIFFER: HfSnoop(c->arg[0], c->arg[1]); break; + case CMD_HF_PLOT: + HfPlot(); + break; #endif + #ifdef WITH_SMARTCARD case CMD_SMART_ATR: { SmartCardAtr(); @@ -1377,7 +1384,6 @@ void UsbPacketReceived(uint8_t *packet, int len) break; case CMD_DOWNLOAD_RAW_ADC_SAMPLES_125K: - LED_B_ON(); uint8_t *BigBuf = BigBuf_get_addr(); for(size_t i=0; iarg[1]; i += USB_CMD_DATA_SIZE) { diff --git a/armsrc/apps.h b/armsrc/apps.h index fad9e6eb..aaa128ab 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -21,7 +21,6 @@ #include "mifare.h" #include "../common/crc32.h" #include "BigBuf.h" -#include "fpgaloader.h" extern const uint8_t OddByteParity[256]; extern int rsamples; // = 0; @@ -174,13 +173,8 @@ void SimulateHitagSTag(bool tag_mem_supplied, byte_t* data); void WritePageHitagS(hitag_function htf, hitag_data* htd,int page); void check_challenges_cmd(bool file_given, byte_t* data, uint64_t tagMode); - - // cmd.h bool cmd_receive(UsbCommand* cmd); bool cmd_send(uint32_t cmd, uint32_t arg0, uint32_t arg1, uint32_t arg2, void* data, size_t len); -/// util.h -void HfSnoop(int , int); - #endif diff --git a/armsrc/fpgaloader.c b/armsrc/fpgaloader.c index 45294d60..d1d527c4 100644 --- a/armsrc/fpgaloader.c +++ b/armsrc/fpgaloader.c @@ -166,7 +166,7 @@ bool FpgaSetupSscDma(uint8_t *buf, uint16_t sample_count) AT91C_BASE_PDC_SSC->PDC_RPR = (uint32_t) buf; // transfer to this memory address AT91C_BASE_PDC_SSC->PDC_RCR = sample_count; // transfer this many samples AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) buf; // next transfer to same memory address - AT91C_BASE_PDC_SSC->PDC_RNCR = sample_count; // ... with same number of samples AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN; // go! + AT91C_BASE_PDC_SSC->PDC_RNCR = sample_count; // ... with same number of samples AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN; // go! return true; } @@ -417,8 +417,10 @@ void FpgaDownloadAndGo(int bitstream_version) uint8_t output_buffer[OUTPUT_BUFFER_LEN] = {0x00}; // check whether or not the bitstream is already loaded - if (downloaded_bitstream == bitstream_version) + if (downloaded_bitstream == bitstream_version) { + FpgaEnableTracing(); return; + } // make sure that we have enough memory to decompress BigBuf_free(); BigBuf_Clear_ext(false); @@ -454,16 +456,30 @@ void FpgaSendCommand(uint16_t cmd, uint16_t v) while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0); // wait for the transfer to complete AT91C_BASE_SPI->SPI_TDR = AT91C_SPI_LASTXFER | cmd | v; // send the data } + //----------------------------------------------------------------------------- // Write the FPGA setup word (that determines what mode the logic is in, read // vs. clone vs. etc.). This is now a special case of FpgaSendCommand() to // avoid changing this function's occurence everywhere in the source code. //----------------------------------------------------------------------------- -void FpgaWriteConfWord(uint8_t v) +void FpgaWriteConfWord(uint16_t v) { FpgaSendCommand(FPGA_CMD_SET_CONFREG, v); } +//----------------------------------------------------------------------------- +// enable/disable FPGA internal tracing +//----------------------------------------------------------------------------- +void FpgaEnableTracing(void) +{ + FpgaSendCommand(FPGA_CMD_TRACE_ENABLE, 1); +} + +void FpgaDisableTracing(void) +{ + FpgaSendCommand(FPGA_CMD_TRACE_ENABLE, 0); +} + //----------------------------------------------------------------------------- // Set up the CMOS switches that mux the ADC: four switches, independently // closable, but should only close one at a time. Not an FPGA thing, but diff --git a/armsrc/fpgaloader.h b/armsrc/fpgaloader.h index 0600067e..006de8de 100644 --- a/armsrc/fpgaloader.h +++ b/armsrc/fpgaloader.h @@ -17,13 +17,15 @@ #include void FpgaSendCommand(uint16_t cmd, uint16_t v); -void FpgaWriteConfWord(uint8_t v); +void FpgaWriteConfWord(uint16_t v); void FpgaDownloadAndGo(int bitstream_version); void FpgaSetupSsc(uint8_t mode); void SetupSpi(int mode); bool FpgaSetupSscDma(uint8_t *buf, uint16_t sample_count); void Fpga_print_status(); int FpgaGetCurrent(); +void FpgaEnableTracing(void); +void FpgaDisableTracing(void); #define FpgaDisableSscDma(void) AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; #define FpgaEnableSscDma(void) AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN; void SetAdcMuxFor(uint32_t whichGpio); @@ -33,9 +35,14 @@ void SetAdcMuxFor(uint32_t whichGpio); #define FPGA_BITSTREAM_HF 2 // Definitions for the FPGA commands. +// BOTH #define FPGA_CMD_SET_CONFREG (1<<12) +// LF #define FPGA_CMD_SET_DIVISOR (2<<12) #define FPGA_CMD_SET_USER_BYTE1 (3<<12) +// HF +#define FPGA_CMD_TRACE_ENABLE (2<<12) + // Definitions for the FPGA configuration word. // LF #define FPGA_MAJOR_MODE_LF_ADC (0<<5) @@ -47,21 +54,27 @@ void SetAdcMuxFor(uint32_t whichGpio); #define FPGA_MAJOR_MODE_HF_SIMULATOR (2<<5) #define FPGA_MAJOR_MODE_HF_ISO14443A (3<<5) #define FPGA_MAJOR_MODE_HF_SNOOP (4<<5) +#define FPGA_MAJOR_MODE_HF_GET_TRACE (5<<5) // BOTH #define FPGA_MAJOR_MODE_OFF (7<<5) + // Options for LF_ADC #define FPGA_LF_ADC_READER_FIELD (1<<0) + // Options for LF_EDGE_DETECT #define FPGA_CMD_SET_EDGE_DETECT_THRESHOLD FPGA_CMD_SET_USER_BYTE1 #define FPGA_LF_EDGE_DETECT_READER_FIELD (1<<0) #define FPGA_LF_EDGE_DETECT_TOGGLE_MODE (1<<1) + // Options for the HF reader, tx to tag #define FPGA_HF_READER_TX_SHALLOW_MOD (1<<0) + // Options for the HF reader, correlating against rx from tag #define FPGA_HF_READER_RX_XCORR_848_KHZ (1<<0) #define FPGA_HF_READER_RX_XCORR_SNOOP (1<<1) #define FPGA_HF_READER_RX_XCORR_QUARTER_FREQ (1<<2) #define FPGA_HF_READER_RX_XCORR_AMPLITUDE (1<<3) + // Options for the HF simulated tag, how to modulate #define FPGA_HF_SIMULATOR_NO_MODULATION (0<<0) #define FPGA_HF_SIMULATOR_MODULATE_BPSK (1<<0) diff --git a/armsrc/hfsnoop.c b/armsrc/hfsnoop.c index e492c474..755ac0cc 100644 --- a/armsrc/hfsnoop.c +++ b/armsrc/hfsnoop.c @@ -1,10 +1,22 @@ +//----------------------------------------------------------------------------- +// piwi, 2019 +// +// 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. +//----------------------------------------------------------------------------- +// Routines to get sample data from FPGA. +//----------------------------------------------------------------------------- + +#include "hfsnoop.h" + #include "proxmark3.h" -#include "apps.h" #include "BigBuf.h" #include "util.h" +#include "apps.h" #include "usb_cdc.h" // for usb_poll_validate_length - -static void RAMFUNC optimizedSnoop(void); +#include "fpga.h" +#include "fpgaloader.h" static void RAMFUNC optimizedSnoop(void) { @@ -74,3 +86,33 @@ void HfSnoop(int samplesToSkip, int triggersToSkip) LED_D_OFF(); } +void HfPlot(void) +{ + uint8_t *buf = ToSend; + uint8_t *this_buf = buf; + + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_GET_TRACE); + AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; // Disable DMA Transfer + AT91C_BASE_PDC_SSC->PDC_RPR = (uint32_t) this_buf; // start transfer to this memory address + AT91C_BASE_PDC_SSC->PDC_RCR = USB_CMD_DATA_SIZE; // transfer this many samples + buf[0] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; // clear receive register + AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN; // Start DMA transfer + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_GET_TRACE); // let FPGA transfer its internal Block-RAM + + LED_B_ON(); + for(size_t i = 0; i < FPGA_TRACE_SIZE; i += USB_CMD_DATA_SIZE) { + // prepare next DMA transfer: + uint8_t *next_buf = buf + ((i + USB_CMD_DATA_SIZE) % (2 * USB_CMD_DATA_SIZE)); + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t)next_buf; + AT91C_BASE_PDC_SSC->PDC_RNCR = USB_CMD_DATA_SIZE; + size_t len = MIN(FPGA_TRACE_SIZE - i, USB_CMD_DATA_SIZE); + while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX))) ; // wait for DMA transfer to complete + cmd_send(CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K, i, len, FPGA_TRACE_SIZE, this_buf, len); + this_buf = next_buf; + } + // Trigger a finish downloading signal with an ACK frame + cmd_send(CMD_ACK, 1, 0, FPGA_TRACE_SIZE, 0, 0); + LED_B_OFF(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); +} diff --git a/armsrc/hfsnoop.h b/armsrc/hfsnoop.h new file mode 100644 index 00000000..8c45e170 --- /dev/null +++ b/armsrc/hfsnoop.h @@ -0,0 +1,17 @@ +//----------------------------------------------------------------------------- +// piwi, 2019 +// +// 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. +//----------------------------------------------------------------------------- +// Routines to get sample data from FPGA. +//----------------------------------------------------------------------------- + +#ifndef HFSNOOP_H__ +#define HFSNOOP_H__ + +void HfSnoop(int samplesToSkip, int triggersToSkip); +void HfPlot(void); + +#endif diff --git a/armsrc/hitag2.c b/armsrc/hitag2.c index 8e690a7b..0fd8d745 100644 --- a/armsrc/hitag2.c +++ b/armsrc/hitag2.c @@ -22,6 +22,7 @@ #include "hitag2.h" #include "string.h" #include "BigBuf.h" +#include "fpgaloader.h" static bool bQuiet; diff --git a/armsrc/hitagS.c b/armsrc/hitagS.c index 3c247d55..8a451606 100644 --- a/armsrc/hitagS.c +++ b/armsrc/hitagS.c @@ -20,6 +20,7 @@ #include "hitag2.h" #include "string.h" #include "BigBuf.h" +#include "fpgaloader.h" #define CRC_PRESET 0xFF #define CRC_POLYNOM 0x1D diff --git a/armsrc/iclass.c b/armsrc/iclass.c index d27fc1c6..be7da703 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -51,6 +51,7 @@ #include "protocols.h" #include "optimized_cipher.h" #include "usb_cdc.h" // for usb_poll_validate_length +#include "fpgaloader.h" static int timeout = 4096; diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 50160798..2fffe837 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -25,6 +25,7 @@ #include "BigBuf.h" #include "protocols.h" #include "parity.h" +#include "fpgaloader.h" typedef struct { enum { @@ -1771,7 +1772,9 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u if (anticollision) { // SELECT_ALL ReaderTransmit(sel_all, sizeof(sel_all), NULL); - if (!ReaderReceive(resp, resp_par)) return 0; + if (!ReaderReceive(resp, resp_par)) { + return 0; + } if (Demod.collisionPos) { // we had a collision and need to construct the UID bit by bit memset(uid_resp, 0, 4); @@ -1793,7 +1796,9 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u } collision_answer_offset = uid_resp_bits%8; ReaderTransmitBits(sel_uid, 16 + uid_resp_bits, NULL); - if (!ReaderReceiveOffset(resp, collision_answer_offset, resp_par)) return 0; + if (!ReaderReceiveOffset(resp, collision_answer_offset, resp_par)) { + return 0; + } } // finally, add the last bits and BCC of the UID for (uint16_t i = collision_answer_offset; i < (Demod.len-1)*8; i++, uid_resp_bits++) { @@ -1827,7 +1832,9 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u ReaderTransmit(sel_uid, sizeof(sel_uid), NULL); // Receive the SAK - if (!ReaderReceive(resp, resp_par)) return 0; + if (!ReaderReceive(resp, resp_par)) { + return 0; + } sak = resp[0]; // Test if more parts of the uid are coming @@ -1862,7 +1869,9 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u AppendCrc14443a(rats, 2); ReaderTransmit(rats, sizeof(rats), NULL); - if (!(len = ReaderReceive(resp, resp_par))) return 0; + if (!(len = ReaderReceive(resp, resp_par))) { + return 0; + } if(p_hi14a_card) { memcpy(p_hi14a_card->ats, resp, len); @@ -2044,7 +2053,7 @@ void ReaderIso14443a(UsbCommand *c) // 1 - all is OK with ATS, 2 - without ATS cantSELECT = true; } - + FpgaDisableTracing(); LED_B_ON(); cmd_send(CMD_ACK,arg0,card->uidlen,0,buf,sizeof(iso14a_card_select_t)); LED_B_OFF(); @@ -2058,6 +2067,7 @@ void ReaderIso14443a(UsbCommand *c) if(param & ISO14A_APDU && !cantSELECT) { uint8_t res; arg0 = iso14_apdu(cmd, len, buf, &res); + FpgaDisableTracing(); LED_B_ON(); cmd_send(CMD_ACK, arg0, res, 0, buf, sizeof(buf)); LED_B_OFF(); @@ -2099,6 +2109,7 @@ void ReaderIso14443a(UsbCommand *c) } } arg0 = ReaderReceive(buf, par); + FpgaDisableTracing(); LED_B_ON(); cmd_send(CMD_ACK,arg0,0,0,buf,sizeof(buf)); @@ -2415,6 +2426,8 @@ void ReaderMifare(bool first_try) } } + FpgaDisableTracing(); + uint8_t buf[32]; memcpy(buf + 0, uid, 4); num_to_bytes(nt, 4, buf + 4); @@ -2587,6 +2600,7 @@ void RAMFUNC SniffMifare(uint8_t param) { DbpString("COMMAND FINISHED."); FpgaDisableSscDma(); + FpgaDisableTracing(); MfSniffEnd(); Dbprintf("maxDataLen=%x, Uart.state=%x, Uart.len=%x", maxDataLen, Uart.state, Uart.len); diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index 76d7a075..3ebaa539 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -10,12 +10,14 @@ // the `fake tag' modes. //----------------------------------------------------------------------------- +#include "iso14443b.h" + #include "proxmark3.h" #include "apps.h" #include "util.h" #include "string.h" - #include "iso14443crc.h" +#include "fpgaloader.h" #define RECEIVE_SAMPLES_TIMEOUT 1000 // TR0 max is 256/fs = 256/(848kHz) = 302us or 64 samples from FPGA. 1000 seems to be much too high? #define ISO14443B_DMA_BUFFER_SIZE 128 diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 9dc4bf18..13b8a174 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -60,6 +60,7 @@ #include "protocols.h" #include "cmd.h" #include "BigBuf.h" +#include "fpgaloader.h" #define arraylen(x) (sizeof(x)/sizeof((x)[0])) diff --git a/armsrc/legicrf.c b/armsrc/legicrf.c index d3fd35d1..947d6cd5 100644 --- a/armsrc/legicrf.c +++ b/armsrc/legicrf.c @@ -10,15 +10,16 @@ // LEGIC RF simulation code //----------------------------------------------------------------------------- +#include "legicrf.h" + #include "proxmark3.h" #include "apps.h" #include "util.h" #include "string.h" - -#include "legicrf.h" #include "legic_prng.h" #include "legic.h" #include "crc.h" +#include "fpgaloader.h" static legic_card_select_t card;/* metadata of currently selected card */ static crc_t legic_crc; diff --git a/armsrc/legicrfsim.c b/armsrc/legicrfsim.c index 1411fbea..409235af 100644 --- a/armsrc/legicrfsim.c +++ b/armsrc/legicrfsim.c @@ -10,16 +10,17 @@ // LEGIC RF simulation code //----------------------------------------------------------------------------- +#include "legicrfsim.h" + #include "proxmark3.h" #include "apps.h" #include "util.h" #include "string.h" - -#include "legicrfsim.h" #include "legic_prng.h" #include "legic.h" #include "crc.h" #include "usb_cdc.h" // for usb_poll_validate_length +#include "fpgaloader.h" static uint8_t* legic_mem; /* card memory, used for sim */ static legic_card_select_t card;/* metadata of currently selected card */ diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 1816bdca..81fdd7a6 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -18,6 +18,7 @@ #include "lfsampling.h" #include "protocols.h" #include "usb_cdc.h" // for usb_poll_validate_length +#include "fpgaloader.h" /** * Function to do a modulation and then get samples. diff --git a/armsrc/lfsampling.c b/armsrc/lfsampling.c index ffbc0da8..03bccf41 100644 --- a/armsrc/lfsampling.c +++ b/armsrc/lfsampling.c @@ -12,7 +12,7 @@ #include "string.h" #include "lfsampling.h" #include "usb_cdc.h" // for usb_poll_validate_length -//#include "ticks.h" // for StartTicks +#include "fpgaloader.h" sample_config config = { 1, 8, 1, 95, 0 } ; diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index ca513cec..14ce1bcc 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -15,10 +15,10 @@ #include "mifarecmd.h" -#include "apps.h" #include "util.h" #include "parity.h" #include "crc.h" +#include "fpgaloader.h" #define HARDNESTED_AUTHENTICATION_TIMEOUT 848 // card times out 1ms after wrong authentication (according to NXP documentation) #define HARDNESTED_PRE_AUTHENTICATION_LEADTIME 400 // some (non standard) cards need a pause after select before they are ready for first authentication diff --git a/armsrc/mifaresniff.c b/armsrc/mifaresniff.c index 5391e5f9..4dbcd904 100644 --- a/armsrc/mifaresniff.c +++ b/armsrc/mifaresniff.c @@ -9,7 +9,7 @@ //----------------------------------------------------------------------------- #include "mifaresniff.h" -#include "apps.h" + #include "proxmark3.h" #include "util.h" #include "string.h" @@ -18,6 +18,9 @@ #include "crapto1/crapto1.h" #include "mifareutil.h" #include "common.h" +#include "cmd.h" +#include "BigBuf.h" +#include "fpgaloader.h" static int sniffState = SNF_INIT; diff --git a/armsrc/pcf7931.c b/armsrc/pcf7931.c index 16b7912d..9aa0d9be 100644 --- a/armsrc/pcf7931.c +++ b/armsrc/pcf7931.c @@ -4,6 +4,7 @@ #include "pcf7931.h" #include "util.h" #include "string.h" +#include "fpgaloader.h" #define T0_PCF 8 //period for the pcf7931 in us #define ALLOC 16 diff --git a/client/cmdhf.c b/client/cmdhf.c index f11c5b65..73b0bc76 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -11,10 +11,12 @@ #include "cmdhf.h" +#include #include "usb_cmd.h" #include "comms.h" #include "ui.h" #include "cmdparser.h" +#include "cliparser/cliparser.h" #include "cmdhf14a.h" #include "cmdhf14b.h" #include "cmdhf15.h" @@ -27,6 +29,9 @@ #include "cmdhftopaz.h" #include "cmdhflist.h" #include "cmdhffido.h" +#include "cmddata.h" +#include "graph.h" +#include "fpga.h" static int CmdHelp(const char *Cmd); @@ -73,31 +78,83 @@ int CmdHFSnoop(const char *Cmd) return 0; } -static command_t CommandTable[] = + +// static void InterpolateShannon(int *source, size_t source_len, int *dest, size_t dest_len) +// { + // int *buf = (int*)malloc(source_len * sizeof(int)); + // memcpy(buf, source, source_len * sizeof(int)); + // for (int i = 0; i < source_len; i++) { + // buf[i] += 128; + // } + // for (int i = 0; i < dest_len; i++) { + // float value = 0.0; + // for (int j = 0; j < source_len; j++) { + // if (i * source_len == j * dest_len) { // sin(0) / 0 = 1 + // value += (float)buf[j]; + // } else { + // value += (float)buf[j] * sin(((float)i*source_len/dest_len-j)*3.1415) / (((float)i*source_len/dest_len-j)*3.1415); + // } + // } + // dest[i] = value - 128; + // } + // free(buf); +// } + + +static int CmdHFPlot(const char *Cmd) { - {"help", CmdHelp, 1, "This help"}, - {"14a", CmdHF14A, 1, "{ ISO14443A RFIDs... }"}, - {"14b", CmdHF14B, 1, "{ ISO14443B RFIDs... }"}, - {"15", CmdHF15, 1, "{ ISO15693 RFIDs... }"}, - {"epa", CmdHFEPA, 1, "{ German Identification Card... }"}, - {"legic", CmdHFLegic, 0, "{ LEGIC RFIDs... }"}, - {"iclass", CmdHFiClass, 1, "{ ICLASS RFIDs... }"}, - {"mf", CmdHFMF, 1, "{ MIFARE RFIDs... }"}, - {"mfu", CmdHFMFUltra, 1, "{ MIFARE Ultralight RFIDs... }"}, - {"mfp", CmdHFMFP, 1, "{ MIFARE Plus RFIDs... }"}, - {"topaz", CmdHFTopaz, 1, "{ TOPAZ (NFC Type 1) RFIDs... }"}, - {"fido", CmdHFFido, 1, "{ FIDO and FIDO2 authenticators... }"}, - {"tune", CmdHFTune, 0, "Continuously measure HF antenna tuning"}, - {"list", CmdHFList, 1, "List protocol data in trace buffer"}, - {"search", CmdHFSearch, 1, "Search for known HF tags [preliminary]"}, + CLIParserInit("hf plot", + "Plots HF signal after RF signal path and A/D conversion.", + "This can be used after any hf command and will show the last few milliseconds of the HF signal.\n" + "Note: If the last hf command terminated because of a timeout you will most probably see nothing.\n"); + void* argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(Cmd, argtable, true); + + uint8_t buf[FPGA_TRACE_SIZE]; + + if (GetFromFpgaRAM(buf, FPGA_TRACE_SIZE)) { + for (size_t i = 0; i < FPGA_TRACE_SIZE; i++) { + GraphBuffer[i] = (int)buf[i] - 128; + } + GraphTraceLen = FPGA_TRACE_SIZE; + // InterpolateShannon(GraphBuffer, FPGA_TRACE_SIZE, GraphBuffer, FPGA_TRACE_SIZE*8/7); + // GraphTraceLen = FPGA_TRACE_SIZE*8/7; + ShowGraphWindow(); + RepaintGraphWindow(); + } + return 0; +} + + +static command_t CommandTable[] = +{ + {"help", CmdHelp, 1, "This help"}, + {"14a", CmdHF14A, 0, "{ ISO14443A RFIDs... }"}, + {"14b", CmdHF14B, 0, "{ ISO14443B RFIDs... }"}, + {"15", CmdHF15, 1, "{ ISO15693 RFIDs... }"}, + {"epa", CmdHFEPA, 0, "{ German Identification Card... }"}, + {"legic", CmdHFLegic, 0, "{ LEGIC RFIDs... }"}, + {"iclass", CmdHFiClass, 1, "{ ICLASS RFIDs... }"}, + {"mf", CmdHFMF, 1, "{ MIFARE RFIDs... }"}, + {"mfu", CmdHFMFUltra, 1, "{ MIFARE Ultralight RFIDs... }"}, + {"mfp", CmdHFMFP, 0, "{ MIFARE Plus RFIDs... }"}, + {"topaz", CmdHFTopaz, 0, "{ TOPAZ (NFC Type 1) RFIDs... }"}, + {"fido", CmdHFFido, 0, "{ FIDO and FIDO2 authenticators... }"}, + {"tune", CmdHFTune, 0, "Continuously measure HF antenna tuning"}, + {"list", CmdHFList, 1, "List protocol data in trace buffer"}, + {"plot", CmdHFPlot, 0, "Plot signal"}, + {"search", CmdHFSearch, 0, "Search for known HF tags [preliminary]"}, {"snoop", CmdHFSnoop, 0, " Generic HF Snoop"}, - {NULL, NULL, 0, NULL} + {NULL, NULL, 0, NULL} }; int CmdHF(const char *Cmd) { CmdsParse(CommandTable, Cmd); - return 0; + return 0; } int CmdHelp(const char *Cmd) diff --git a/client/cmdparser.h b/client/cmdparser.h index 5217d04b..cd4d1625 100644 --- a/client/cmdparser.h +++ b/client/cmdparser.h @@ -9,7 +9,7 @@ //----------------------------------------------------------------------------- #ifndef CMDPARSER_H__ -#define CMDPARSER_H__ +#define CMDPARSER_H__ typedef struct command_s { diff --git a/client/comms.c b/client/comms.c index 190b9110..5af53715 100644 --- a/client/comms.c +++ b/client/comms.c @@ -301,6 +301,39 @@ bool GetFromBigBuf(uint8_t *dest, int bytes, int start_index, UsbCommand *respon } +bool GetFromFpgaRAM(uint8_t *dest, int bytes) +{ + UsbCommand c = {CMD_HF_PLOT, {0, 0, 0}}; + SendCommand(&c); + + uint64_t start_time = msclock(); + + UsbCommand response; + + int bytes_completed = 0; + bool show_warning = true; + while(true) { + if (getCommand(&response)) { + if (response.cmd == CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K) { + int copy_bytes = MIN(bytes - bytes_completed, response.arg[1]); + memcpy(dest + response.arg[0], response.d.asBytes, copy_bytes); + bytes_completed += copy_bytes; + } else if (response.cmd == CMD_ACK) { + return true; + } + } + + if (msclock() - start_time > 2000 && show_warning) { + PrintAndLog("Waiting for a response from the proxmark..."); + PrintAndLog("You can cancel this operation by pressing the pm3 button"); + show_warning = false; + } + } + + return false; +} + + bool OpenProxmark(void *port, bool wait_for_port, int timeout, bool flash_mode) { char *portname = (char *)port; if (!wait_for_port) { diff --git a/client/comms.h b/client/comms.h index 68981165..65294695 100644 --- a/client/comms.h +++ b/client/comms.h @@ -35,5 +35,6 @@ bool WaitForResponseTimeoutW(uint32_t cmd, UsbCommand* response, size_t ms_timeo bool WaitForResponseTimeout(uint32_t cmd, UsbCommand* response, size_t ms_timeout); bool WaitForResponse(uint32_t cmd, UsbCommand* response); bool GetFromBigBuf(uint8_t *dest, int bytes, int start_index, UsbCommand *response, size_t ms_timeout, bool show_warning); +bool GetFromFpgaRAM(uint8_t *dest, int bytes); #endif // COMMS_H_ diff --git a/common/fpga.h b/common/fpga.h index b99a7593..65268ecf 100644 --- a/common/fpga.h +++ b/common/fpga.h @@ -10,6 +10,7 @@ #define FPGA_BITSTREAM_FIXED_HEADER_SIZE sizeof(bitparse_fixed_header) #define FPGA_INTERLEAVE_SIZE 288 #define FPGA_CONFIG_SIZE 42336L // our current fpga_[lh]f.bit files are 42175 bytes. Rounded up to next multiple of FPGA_INTERLEAVE_SIZE +#define FPGA_TRACE_SIZE 3072 static const uint8_t bitparse_fixed_header[] = {0x00, 0x09, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x01}; extern const int fpga_bitstream_num; diff --git a/fpga/Makefile b/fpga/Makefile index 2f93e741..70b0b5fe 100644 --- a/fpga/Makefile +++ b/fpga/Makefile @@ -5,7 +5,7 @@ clean: $(DELETE) *.bgn *.drc *.ncd *.ngd *_par.xrpt *-placed.* *-placed_pad.* *_usage.xml xst_hf.srp xst_lf.srp $(DELETE) *.map *.ngc *.xrpt *.pcf *.rbt *_auto_* *.bld *.mrp *.ngm *.unroutes *_summary.xml netlist.lst xst -fpga_hf.ngc: fpga_hf.v fpga.ucf xst_hf.scr util.v hi_simulate.v hi_read_tx.v hi_read_rx_xcorr.v hi_iso14443a.v hi_sniffer.v +fpga_hf.ngc: fpga_hf.v fpga.ucf xst_hf.scr util.v hi_simulate.v hi_read_tx.v hi_read_rx_xcorr.v hi_iso14443a.v hi_sniffer.v hi_get_trace.v $(DELETE) $@ $(XILINX_TOOLS_PREFIX)xst -ifn xst_hf.scr diff --git a/fpga/fpga_hf.bit b/fpga/fpga_hf.bit index f16fd0614fbd2614e713a29da5f47a29094953e5..2ea2c24e76d0e4b64f173d48cf67dc299283e53d 100644 GIT binary patch literal 42175 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 H^0)s7_0XSf literal 42175 zcma&Pe{>Yrl`gvbR7oy%wbX?W9*vEiQcK_lx1>hG7-Jz7f|u80lhEUvnZ8 z$gylQMBYTm5{e63%BPt6{dH*BwZKC<#=={%{{!_;{ z>N_9a^w8HgH+=h{&GaDooBp~v`d_}YEE=VUNNMwFzFh;EAd68!&K)Mxrgw$(?;;s2)D-IscwMmH)fvsNQq_J$>f?Z=d7-^16Xn5~EwFRQhb{ zq}!=PQi8r9Z_4?cwh@OrIVGRSNopPs46n`P{zz@P;8~@WKDL|9z*!}Ve}o@toR=x5 zKdU_^YUo9+!MZ;q0<`PTLsH8KQ;l+;RLQHf*Dy7WDplXXc@gVRqv+F3=o1wopZgqV z!L#)I&d{b*-;;~!MQT{1A83zIFNv+;jEJfUehw{|pbvVQh9Z4REnT73w}KfxB3`FK zJ20dhs{5Rr?>L=Pzu@c|Q@*QxPHkhsDdj5t)@idFXOwBo5I>f&-I%dfq=ItodAg!C zIl)ZrB)vjSGLlioRFnH;OCq$4LT}xFn;55;osgqv+9#jsTb^BDQ`jF^<&6qc#uVj5cvKc??ydZDK#p>GktQD2sOO*G!6?kASm+7^-Zo)gnl z`iz#VL8JQ(G@=xYDx>s@u}TJ_%3I#XvC0n-mSCMbozJy4l^f!78^ zWI}#|Sp?Iy<9I(S?LbDEq$_KhBpOS-^@`2gW4%Ckt+}={v!+Mu6zAwjyhfr? z>Ah!%p4N`YO}4&KysI9xAL_5>F(1r5!()aq@pr|l{vZ#U`+lS^7jMu(vQ2H77)8Uh zwF7vLyY3SUel9Ojb0(M*Gjy3&$;f~*L075SjtuClyzh!pj;5_vBbZdspjHY>uc4yx z7TyJZG~;19=`_W6J*}wb3Br1%l{(tuYqA1QE5iFOscxq2!~HRRVW_TZyR{--v0Kz> zN2%Y^_6U;s6wT4v=YSyG5zD7MiMB-DIx2)hJchbye2I z{Z;-FI*>5qT9pv68T<^DKh&QZXqp$?(OcV}{jiD0Y+~?D6d=7pao4@?Pv4i7GQJWPUQ^wK2bkfQqI@!@=1*?=&Z@pF; zIU4dc(EU=NL7{MXhd)Fq$29NH`YXJ-YbB$YMa0q#F`^!zP3>AdStYkp&3*a<7_;|X z3--}b*?_tCkJC|}@&lrZ9uu`O^eOe$!mfH&&cs^R>uKdZ6B}tA##1LwVqkdTVb8w8 zw2x+dtq`ncXAZa=k6)Q@T371icT+TIIVPISyZN4vTFU%OV@!4AEZUX_h@WJ154{wNRR zA{&*Zf`>!eZI~CeIzbyIbJ^D_(U_o5F-FX5*t0LID6>Cs*+ z=Yv(W)mTK@M&Wq&m8g2v93<>IO^l`nDFp9{fu>|#omMTf-ntJg_yx>->2%;JN-rb82=1V~Vpb%I~L3eb~B(LJ9p@F=-5GjZ#arucVi##tDy!oMmtyS+W_fJ2a)I z#Uvdw8?3T)h;1-LSlpbq7895_Uwza%@`rf3TvTVrWPuf zu=g3Zue9QL_GRC8(YPd5TkHnmQrakJ=~HODOt7YjQg_cgC0HiemJ2vfT{K2`nYJiR zJg*cQ2pZfm8-JkR%T-A&O%s&DyHEAChv?&9EFJU@74VBaTZA+k9(DU@b_He;HJ_*+ zOok9n;K!M_A9G)7YJFnDN>P7ElVUObJuQ{~JbqaV;EkzuAdphVwbT<$naFNEq+X#x z8Ch10Umw%GGMJu!PF$63GWa22>k6%wm}wrr_VaU6!9FEIS!zlLZ1|1OgzM)G&%PMH zUZiiQ^(RC`j>SWVV%5sGte2@4xU4+ltwoOQOEfs}8>&xIe_9KR`_zNNmSs_~a?ZYP zrz5gH0W4_p?U6OM784JcM`TTZ*|dmx&xvUPz*fWxE}vf}oEkG3uIi5AlO|anRVuN( z__1y~jyDfqH>Hg6di6AZ;+yh)ZnX6@{JMZ&?)!1zPRFqtE1W)N=!VvAtV* zT$};w);QWGv5*d$&&y)``YDh30-*LCI)pK&vf^uWByA29b=P4;ePPj#U z8LJ$Y+R6fc4PYO(rGw+jv~}HX?t6Ht{(a{dH3P_Qz%OE7r{vUWIwml9+XJ$$0)CBS z_x`{Nrn|@KBw(u|Be9=-Q7e!x#;>E)kbv!si|467uBGR1Ha_r$)|IFI1^j~RZs^o^ zBPQwcU1-;yDE);zK)^Vo2)`H$*6H)a$QlG)>tJ6abRcZrS7sFOD}fO<82aPguh`Pc z80+0Jf2V0-WUDfVU$^m?+d6{pDA$wM?6!`7NGso^52)1&#tZo6_VMtGe}(B_UZR=M zD8?_*K)NJ{27Ha|3QQwIODQEq9=|X`55LZcXGOiGrTr>CG21ctV*DcDS6^~m{Gz5Y zu02V0cpG6W{6rqV7VvmlABM;Nop8s~=c|)5G-w5?^*Q|V?ZXH$3&2)CI$MoHYbWUw zcrsX19=~Q+5TS@Ti|y9Xqs-#F)aUT4BuvMsF|D7+H|>xiS#J9IlaL17@q2dR;ul5U zLX0#?Ptjrt*Zr78jFi)&p;`R0eJ*}Edc5=uJ({YOWm7*|=sQBSS?#YwVedHu8r$IN zL~x7pF8x;Cl?!a?{weTl*>vEtp2sit2@USN#AQ0}C@Yi+x?&w4YdqXNi(gc7-TFL@ zFn(Hj2e5Uoy?$D0qtmCFrvlTuWw<^Q_(gY9{n-7MlD78KUg_^tzDmEPS_k&EbPm7v zsCQ$T^iDBtZZ+;4FYAO2ZZlwvok`2XFSE+EuPyqIgrtEg^8^6;%hpq5I>^GJXGFdEW*6VqX^z?pDU-Wh_(0;M$z=8RK%M2)}%; zZyBp?q0`j-$mDeG3fh2(H87>nI`_MPU%tPi#nJosh&p(MP@;Uu?@#=_Z$&N@73M5{ z`63#qhpG2H8m8@PKUEKk2zz>-2`S_(rwC`|AaalzVU)J|hOIqy9)|3Xab0AV!@ z-gfjT!i;AyFYvDmUVP}x>j$&}snhLs){qr~!HRzY{|fQEro6SV7QAAPs?ByFuHQkI zttQ%#nSX(PkH906@r}*#uS1wc>*n&@Q_~#WP6Qnc^>cdJ2~N$=}X$e+O-M8al(f{m+T*R+9xEo+E?b5BQhZuH6xjjSVlS zUl@(+Qey&)%nEa#*XHa?B`}wDTD<*cYiqiGbM=1|`>3nKybt_qHa;9Gf6&ejtXQ>v zN76?*tHlVcQ$mytty&n7${#%Y>bvbC-Q#=do8ZFlr)KQd4*hB6FSMDSdo1|*JpURu zuF19zP_yOq1_Iz+V+zyRCaXNHyymUfN@IeC;wwm#N`iJ!Na_-B>{`kW@uoL-t%UJw zfBe3xc2(;l)8c@NxKU;#hiCcMyyt*c&tawyuCsg;vhFu37s)O)gik`Rd23;N_+?e3 zyBE_*t1=P%5#IAj8szaz%=EAxp)r^!qA|~eW>t^#a zc@JPqIYy65IFJe7?I2<+Kfos+3LefJ{~~zx33|u3!ohS#1@_?>KFQQ5e%~R#m-Fg1?L*tNk*B8sbo-`6$t2YI-II!ti+B>3sN6c~}@GotJ z;ac26dXyl2Y!ZjiFdYEdEdMgAUZp{^L6lWO*GgF-L+cSeWPARwn14B|5`p7NBfai4 z%>-Ujo=fz?&zDaX@h@mHi{p(^<-OE&sC8rcbK>iWD#0|1@QWk-rZs^BpeNXeY9Omr zA=YX;5h=p2Z>mSLq0aDrQ4@m0CyZyYOi_cQP5I~Wt0ZE9L3hHMBJ%IU{bSk-%t3q& zC*Z@2@C&?>G{P3$i!G`daj-jz@S5iFs{&W!0|F7VfnTlkKjhsUf#mV)5AXo<)x98kORd-2-+Lh{nHL?HpZP!-iNFoG79TC1>#H>f+Yt8)5Ya~%fFbX zd|+KMS~KNOC?8o^LGL*xKgZ)=4US?9Oi(tEwotrDL$rd&lgF?1Jg*5o3Kn<33|P1N z#hd2A%>eNzwm#N{pdY&Yi@D5i=mpuBxFv>=^krF+!zWqKzC8Zb;sgzR@)^4VpYkdi zQ3pceTl^H7<6q7$=F6WOtF3ZgxPPU#5v*4pzufo3rgs5ur!@z60rfz*do_<=dzgPY zdfYezM_uofTS*R)7deOqi|`BlE2nQP{nYm}*=YM?7`*$*jrfIKr<BRIzU6Y6BK+D6|IGX=^gDSp$3mI-9e=`&0)EYXGA@sr*lbUTar1evPZ55( z{0mwf9jJmRS1m@2S$31hFXmt1j2Nl`@so#|1L1WWdHiz6+z}i@Sa{7|jbZSH^tE!d zT);0(r_I{H5**_fepRP3y9pHG7t4mszc34iEgk&J{R9HV4fut%FvKW5?+aTlejShz ztJ(nOx^_{$U?1lGZGIcfPnTM~X<#?MAI9!t{A#c^JdN#lo{s&OV3l4+GhMA5C*<)9 z{EL@hkMalWZF7YM)5ETFTt;>SetEB@Yuaqpf?M%^rlYQqScG54@ZvBXEMyKsq7Aq? z=4(J~18lN*&(HENSQDMV+X+N_wNgjTSQSoL5q`P+OJetq@y1Srh>g(;*w~22^7zGS z;p!at*E@8$XSErODeqVp!KCVo@M}Nw6bfeMBd0*ET_F4KsWWR@M=-%We!2c|Q{A+3 zxAi$52tWTRje3kMk6&zGkk^<}9f{XF{&@SC@hsJ6^&1}H#?EO7sLc)h5UiH>A&%cJ) ztgKdN1AGFllsDqnoQFJkwFdIO6&O=4TUS*V3kv!n{T($tSeB`L&pay4v;HT=#}Yf! zsmK)cL)NTdgBj=>LvY=iEFEX($v!jZt*OVqU{+D=)eIopPhwO(C?k$PIu{=@|H2Yj z?$$aAI*AE_3wxOBD6U_%Z)5(|W|em;R}JtK$2Bze^A%G?_+^}SSLaTI8A)Klgz|m5 zF59x@8K(5iuYyMSNNvDIU;VG4FJoBzs|Og!IhKI~x30nzO`JrUCe zDKb`;357iSa)4jGa_%`jc+P+bYsc_@fZenCFKfXm>lAxqThS24!wqH>M(Q@Fe6XM& z9-`~i)*Z|#(*_z6?j1gpRy(_j@?QfIesu)TnV5af+6lU>x@&5vCfm;0k~-s90^_Mm zPKX`8hCNsU*cUZU=}~`^w-&jQHFO{piR+c(Rf!NH4kweP!D!?HW;&}M4*71jUXb;s zzOnL>wN=(9^ceWpVOgKkr@=-o{;rr-hM2a+3L44?EENq>vg5^N{u$ zo9`w~)*+VQdAWORtTe&T87LXX_d`{a$}pv1jBtaP7x%$__SP#qZ@1AycM)jU81+y+ zX>oCu4im1i~pH@ai~R_@j<$tmu^`L9!*lIlpKb_WUv z#9^ZpbN3cEk6$mkY%4PNp7+}r^Ce!m$zuLBooqEWq=328PAhZ#oH|6UK4d40@yplL z3H}98u$y9-7a9igGEa94HOk`w|4JR$Y;M$^Y#+A{B+WG-^5e!)6WOjlIDCWqfPcY< z*IL?`xJbY98sqq+-_niBqWssdj9M$q`sxd6jfF(Uh{_2gB+JA+ehl(on`qh^#5;md zxa>}v{WCS0@W*-m@RIz*X0N^$L*+H?1Afg=MO?oj|Ah#|g6UnPS83UrT~GMN4Fnz? zr_U$_{-rT~-Ou=SR)pyO9hCqwUt?8oY7W0*F8_*vQi&1hHW;db2_iVL?yn5pfL|_} zPa<^e2YywK`yNvpfoSao{Hk`bDUE$NoAw%qfa7A*EPi$Pp0j5AjH_OwnJ0)oPZsen zIjuFZ6zskh3dptGK(s9L`LB|DxaMUsu=@*A>TwbroXfD9D{|I8*MDT2}eu!B(yj}+9zc#qI%=6m4HjiJI=x#aR48E=30{XUWJn%gx zV#&5d@SH-PeGSapt-erGqhdVO28jH64YD$At3rk@UeFJB^H512E3Ky8kQQT~JlaCr zSk>Pm5c2XKGppVU50ROMC($SkKd(h^=9&R`{zC=*@Hsg{(UG8uG{HY3+yyZVi`RJ; z2lSmeS2A#5yFj5QpVFcr891iy->o}; z;~V)GD{qxdVG`J)Z_?vEwNuE|7V)nsY8eegbuQ$9uY-OlhH1GKG4k~rod1fqy~)$D z5N22?+qi1|fLHK_{MTix)hWx=eq>|0t>8+fJ`JSKtuL*_O(8jctJ1-Ytn+=!nyp)BZ-}>o?r^(9wQU`j5Q*6213S258U+9iZuk z{Fl`t>+Q84CJ}G+2W@=`U2HI-;(&*qqjA-R#`2H1^KgkM+oHpK&bV5cV~ z<~68H(u_6;#MkrqwV94OA*6NuED1Jzmx%@)^`S_EZKnvoLRJ{mgSN-v%sCN;{4)0` z;1?aV;4Z2JOK_0{%<5J3D1$CnjB)^+(~x|jICnCA3&FN(#GMIoJ3VUElWv9HrEO}xEbC0p#)n}S zzm}Q7X}v;hled{5V%O;(B?#0O-48#CAMLjNG-I|Ni}S4fX~6DslHb*Kdr<=9)+hy673KS9w-h6(6PM z+^$^hEdK(28Ngf<`LB?gk`3GlldJp50)Ayl$_@fmR1r%=%rfnPu;h%GzOsN{&&po8 zG~wrHIhAU#0c7>Sci>l_n8h#fFLLBiqM}dH=&Wop%TxN2s%)&u*$^-Aub0GCWKhee z^lO;l7p!2ecDntz`tpelMf&0MG+_Ysx|Cm<6LOWhODYp|0iGYbcb0!;OX_-hrMQ3* zLdGP(@p3T=`)bG{U?}jfo@WwjpR!nVk(~%n>&+r-*c3Ud8U9)R#r22V(u-`pBUDK} zvL=B-j(5v78V`?W7#7bkLZ9fYa&(i~|4KO@B1*U5C{(L(%Vl{6&vAKoS})We8rw=Bxp!7pAw&ni=nS!bSnu3l zTz{za$VE9V=D(e`%0+frhj_I zNQZLE@SCZ-c9(N4&2@=5DxnnDAFgSQ2DjIqN37LK6<*K|i%S*o>wW9wn!%31)4@7A z+1J#83DyC>S~~)LN)di_S)mS865bK&qNRzH;jaTWH6*krit%eZamFXPS)viIPD7tR z3gV3DE014wSWNUWLcln=)Y7V9RRD!J>KKdg3t2ok6~z>&|8W~Yv{s6w3jFJg3bb;9 z@%dLd56ii&>vYX(O$4tN@N1Gza21N7sD$;h0&xVusNb;QY4i0P?A7~$Uw%`hN@^)= zBmXr7A_l|H*Kb^$_ZTnbSm|=C=^YNHmoqOyp8{Z8&pM7HP;2!!7z z8ncSxM1g+|fFWXM%A5B4*km@?3Zh)XnC+W}OA~CTRC1Xv%4NAg46yabWb?!q-oEJ) zDmwmlUocyn=U;owBUEFgIxFYV#cGhOzy9JGI%0fF)vW@4^;s{|ojux==p&Tyh3}8I zpEHm6>PK`7&~5TpnN|Nt8K?l^60w!@L}PlLIL&h>9g)i%em!SgNe`t1NA+J+zer6Z z!RM7p%eD7oN*=!^pNZ40Z@P`2C|BqTve8E=o_;r!48g1wHc_^&8Zd63*8JLi6&c%ns@uBLf%}m>|1QI~z2IMl&zsfHf zvsobo_Hcu{X7fahX!-gLP?#v!A1a?Q97h8=EXze^lmdQ%3pc=I+9zdi5`+I) za=dQ4+20NWnbi;7{MYixDX@}1P`9rkriBpqqRt_PSba`E>}+=V+qEJ~am2#WuU z`4?o>;J{5LZ&3%G-^2TX?!zTG>8cg6h1^l9esC4R0 zAT0bDhlLQ~LBwjTSSOA*BzTW;{l*a+P}_l+mid?eVR2adF~GNMf^Ohnh%WvV*;{PC zbN>Cq<%F2TT9U`F$pxJMLOp*@Sp^}n&91POqx5b`Q&;)>#r%ss+XktC!eFnKNoA9m z?qVS8F5+J^vNgW*iEiMR*$UpRY&O}`!eJzMfZWQycYL}Iu z524Q?u}*Bamd0}=b^62t)G`E*>8r6>gSn%AsRF)RpWqVT7J~a(hnKY;>G;y0IL~>;ItR_5zFP) z6#D#S0l%320j=Ee&|s`$&)R*DzO6P{YN3AK2ma-2wRR0EG96LFN4 zoPg*GpZAA>ab6tm19MqZZ=#(0UFy;59sRpvq1dI>jQKYskhXX~vwnC{w%L(yD%XKu ztL@-~zRGw_-fK5Z7w~I8P1m`u@}t~k6F_Dw6XH{9l?Vd!_yw2ZG~4AH5oeutnsbmJ zZ>KkUniD|k0)Ek9Q6po2kz6Q$Mm58FJh_lKx`-9w7w5lfscZ}sriW^z?h`B9cSBJu z%kwX;KXmIHgs4~pB}?km?x(cYPi2(_{g4qBRm#Ve)r2_e4D!M^(LcenmDd&YLnsw+ z1;`*wMqyu0Fw;Hm{GM9R2a53PDqT)Dr-R=E?Yag+8O;5M?}#_)pbShYbNHn`OhYPa z<98ySe~}uco)b~=xIhKYl#;Lve$TQb0{0b?kgCu}gU>W7H^b1t`ehM*5z<}~QLgJV z-3=+WV?!cBYxnVE$jg5<5ysqt!8gdDR1%nAl-3)1UO#01RS&e%?AB;gpj5D`M+ zSOLF2CAVyz`PXQ=*$jNDT-Q*@;RHVI&g0hw0^7=gcGXd@xiqK!O1uxGZkz(Y$m7>I z&w@42upzm@IvX7RSS(sPhhGbRNvR}Ke*Ktf@4Tg~i;nvs+&NmNG@t)^jk2;S8h8@B zh2vhlUU1&L4_zcwy*fw{=kaSF!TT8%Y54i9)8xPy zBXq@Tae__7_|=^P63r8f+ItPuuU$pBu)1;IoO#*uZtElGUUU& z=m(z$UQlkR-`MMfJN*jjDJZGaTuFQ$(N~OLT5BAqz3ME~A6lHG(7?aYDAXTrCa7WYSUPlvvHgLD zn4W&{JphLbWVs^!Fxgf+x_cZ=8N;zMRGz&N8xwYn_CB!)mD%oF8? zJ^OO;3s4)7dJW2=F!&Tg*{jrQ?n)KcAN~>NQySy*asEq!f1QEDN3g_|%tiRckyXIU ze?ds>V<4l}1ZG-{Up|x%Nltsgc49r1;9t~0;gK8l!-p~E(h(S%OR`Xvhf`5V-WBvi z^Qic?1vdH`8{-$N$13i^+#9Xxu>yX*Z*i(_ec#&mk|!ye05MzyU~RS57va})ZrZD{ z57WWO1j1{?yu`NnUF-BsNX$K2T_4lqh5Exih>dI0 z)l&kgF+dxBb2Jyn<&o>{G@ouVBjFdeQB0jBE4!3;JQ|UaXE1HBV~?+XFde zH1Q^OCa}O+=YALJ=dtU|C{*iO>NeoR)8Ya)k{fvB3ix%*So+1-p2~>qRnccC)Iq3f zkXYQ@oP7l-Eun8vNEM(kXn@NgfzF0DYhR3CIH5+M|Ln(_*6alMazKtT7tViS%(R*q zwvbY9qegDH_~jJv>pHzEkJbbnrNsdjBEU4i|*0A`yVmR6T zi5iuWCOu&N3%N$bIo1qY(_4bO0KdF>0l%)re@nn+p3diVFE_?Y6WnK@Bu7xcIduHk zo7YMNFjr`~6IfZ$57V%2gnXOC8?YV3tDPu3MmE{;cedyG*Wc00a*2%*B9-8ddGXgU z<~wX;@n-qg`l>g~gY!%Rg>h37Jooh~=04`n^REf!U-DiV+}Ax@Cu1w$vo6zJa=pE_ zpdWGxpSeq(2Yx{`KncWNA(I?-5|@Y1er+tqa_UUm~(mOFvNO zJL+q&AUlt%M@b~g)36)eCw=c%8%kUCkO6egKSGeTyLy*ToAX)*xCb>G)+I3vvbG{6G~ z)g|NTbGP#_^Bq*-S#THdHq6Mz3iTVzzu*dJ7PfQ_7KiMm68hl{^@nwqW(e>v&lS8% z2Q<_33Ep>c{h>g7nD%5b(>I&{`WFqKa8C1-XJ2mpe5y9B+3jH;WO=x_ z&;;-+WCwGixc+d&G{Vu!fUleFYh~#uz38(~z?tXk=NHm(QLAW=h})&NpPxGyI3iHd zkq{G}oihKr)U&K6@HcDQ#5TD)7u=}4tA5_K?EHV~So@)8U!4D%rXd+Ty!IoTeG90) z*QmGwzpnS(YX+~1>u`hY4-wCw?pc;w{eez5;1?;VCz&0OI2Zlgs2Qo=RL~Fi&~aK) zs((kE(`Ie(ER3xOHpumdsU}PicWVH5{ImQk3p?G5 zZHw^9VW^eB+{lh@6X!TGA|y@rEvP>kwN`YFK zuC0Y5f?ShP>ahWEV5$he!WvLm;>`yT#)qOvphrY628w~@@oOEXW3u0n*lcD9L)Eaj zU~PH)%K1XtR#{_f9pb0f3xF+(iB(T-lQrYOf~@CPk^hn>2<1ajeJ319v^_wICSI}l z6OqTSA;Nic#LIf8afuowrgK()PROtTzivwKI~*t(rB|TN1qYM{o{p@@)UHEgMJ|%j z{n#}4$<9ktkEpSFHTV*beevULQ$M)3($mM%b?bzaV~Y5&wm@*^6@8 zG_2iyPOR!3D=E$J{aSKu59Po;d-`#6MI4E+jK9+JQ4uF_Sc zA9kr&3%6{85ZAdy8nhIS8VRF3e*FaWBs^8>)*m|IF|iIrEQCG<{cyRf_Gs}C&O6}! zfWnlJw8CC4iC-b=4-<42_64+JeI5-H@p``n^69>zGm4W1h@l-c@?4&S5NOsIA9F8oTHc>)sz5fdMz z(MT)rczYv^9B|fgS->WmwxAXCAcQz;t%B(n^ur~Z2U|dyV-&FwqI0GXgv~~6hWisP zS(Ah&<i5>v_LO}DSPyKe?Z^!PjBbU4V!rdF%ZMGj#6IQSmA_mq1ck+Bh&}3wAaE^aj zCBLCJcDL;V+iJ4jl(pl*>6_k_A4~ABX~mesuigHwM*TL#ht->Lw(B=~=bxOD|DEb3 z&}ud(h4WvuRl_Fy*Qc9vP^&lTFd!#pG3Lv@zx>=!dR95Ec$%f}fcU za#sesH$nK3#}eCSF-5ZH8uY#vVTo7(y2&qy->d)T(sh2%d8*nno^F7&xPCQ@aFE6Oq-(` zZUY$BkEhQ?59We7<+~F1r8tij@vo1y?XQKto7y9eJE(XlcJHv4Jj$R|aqyinrfVrRg-1iLpvbXy}Yr=bX>=#I&JNke>Z2r9&Iu8Vy z<6rZx(5O6UMn;wWTGniGu#vtOKS>93kwc2(jXCE#CT5J)n_*3(29lCaFrjA!3pl~4 z+B|-B(J*e?h%8nj;*{xzBHv_0Lq%e3o_~eKb~E&q*uL&-)SE>t@k`~eD0y~yN;@bn zd2!u%Nz8}oP*@Xznr`P|M{f{cq%I4I=H&(cRdM1`Y1(BQE8n$TF0)bmrFcyKEQf>4 z*S+U}f5}(K&PEKxBo2Xp^(gD@SJoKW$npaJI-dGl(5{OAhOKqYYIH!HaqElW;a6#b z-!tonEUQ-RQzG(pZ(dMJO=#Wu`uW(ro%AT}#jaDnWVx|lLhKQ+CddDX__UD!>fUPS zZrOsE_R(ZLHk)`Hh!)8$`JTvmJ_`Dw)-8b4_lWh>EhCQpi{vg1jX@N;0351sNg z$p#zesZZIh66-ZocdDmtsJ=))yih%*w)l2Q<-9=AkuNB3&H0i4G8&5Ui}l__xdHu< z)0Dxq{>A>+_coz;pnKTcV^UqGLKaIbO)p&xvft0Og^Q`HtN#Ho!~*|<#nonGXN8JB zfVRFJo3-s<48?9O(huth33JOI_m>!5RtJ|Is^s&{av6Tjz^?}>+tp+u>#@|x%2m)0 zA9|2t#P#!Q^XI?*m1fqq#y9N7T^2{36(~Cl;S*n596K}5zup%g$fiV~ubcS}=5@CF z8>O#`<_9C_kl7$rFK)caB9B5zkDb| zl3@#40dHg00mP$Z8r4PTzbeEl(oU3D>rd0~(yMd94&`g&H*%R7=qQ|DhJHvGs$Kh$ zm~m~V>?0e6^c2iIHSF0J*Kb_!y8Aq$_cprD2a8aDXuO+Qwl6SKz^^{Q=rXBU_f@Cv zB8&%#X6sR7@6H|H5kL3rix4*qV!ixdMGU!OwvTw!e28K>QHtVC{FqgzD3dnpPMJWo z0~+SOUj$5e(S6W2`n)|qu;3r$6=X|c?{yxxI@Dc3!-%6`?+xB};ry41vpI4*?%$wK zE%>@j_b+L}`GK+_{ZNs9cp4*$(ELtN7&p}4Pkg=8Ux+Abbv$2ee{k6 z|2*D~!ZtNzmZw9r_9cB`+TnBA*0*UWvDnemrTeYaSC&To`=EYXJTFZR6MUvbgpFcb@6H8qnF^-UY{Oui2s$=1vb=r>goV7N4TKg8q+fI3AipG6NX!)U z!%cosnS4fl?d|p4?4-^iq(GC#%pQT-z*=`#{DiDA79DZ^A{O@VS ziNH?f4w*F}B-)CJ02oFjmArlk6vlKKZRMhIIgO(4G2ImsC4!1Pe(g73H&%^Q%v0*3 zpBXqNoKYes$n|T%XYm{pubIy;o4sS9i%92{m@kfn2J|l6+cRV~EYtTC_}8~F=B19G z{7E$f_o9~wqD(A8y3s$YA0~WU0#TE|wNXFS4$GRHvZWFg9kM=$>WJ(denG}mS6UUS zvXiC=<9Sj?MTdbnsz^UPZed;)X7M-JV_2q~GG$=}*9A`$^utM1Ycx6Km<}AiVK2mWy)8CV!2#%1t>xfXo|nUO$Xganw|o zLrK_r2W1=bKH|BfrUCU)`TD~F)LJf<x^V2`~ySXGw|LUAR zKUBU3Y~m3k@bhkyvIC%9J&MWmA{6oF@$3EMjQzJA`j~RYBVte2f@JYt?VH0d=3kgs zJdnP19oDPg3XEZbZXc(h9}Y`tnp9rcG2V=mSYF~XOuf2dZ*cYK2Blrz+FpAFCky?8#1`>jSz#J!I43HuGm zhTT!DGKg5Rz`x+@2$A_f%=FZHK_ON6bscOW!TT(d$PlO4(o@U_Cnp@JM?QbP`_~t zpZ~IhGx}c%{wmbZ+w4iC8}onYd+A9`d6Gea6~$y}g8Nt{*Xb(!VMSJX1dZlJ!I`y} z35gZvUwQp7BX$`zD%6aH))BSF(H|1$5iRXJ92q^2fQbRZVC;3`MKJtKDS@?>5=v@yaJvf}vs5qa5JB{Aj? z>56Pkd;#@Z-kPRSP>6Z0Yt(!lG~@i}&ryFk3NHcHb{zaG%HNg7eNrDoo5TsHCV7@% zdK1bP`Zx`5bG1;v@i(*+sw~_)WGJ&?Snm-L1Gz1$_jrMSnKYn+kxA4!AT?&`HF8_k*fwk=esfoz7hCf2xT@ed?gpY><{*|B!0$b12!ZD&$67D?=&yRhW z(Mj>v-Q{11-W|OYX|FG^yKwzHd&r4Wch5T|mk4P}Cvq0Qa`Tnh+9=_qTLR%g)Qb;M zKOg8dYsXRU{s(+lD4{2l5w%-jgd>Ie4fr|@vAQ7~I6V}fG+~+CDrL1j9J$L!W`NQ4<@ z;08ZtlR2wgV}i-m@&){ouZv|4?DS0^wkY9n9}eAHuw1iHzflettv!SFn#9sJXiS`q zV`QFq?Ab#7#yXzPSjtGAlvsWgiG^}>z%;FJc<%hNi5nMyU%4=s&AaEnI!fOO9Dz!) zqyxri@p|$78?T#C3k~H2q5d$<=a&)XX4Ydom3US7;rb06XTy5U=j*UA9i0E-i#SG4 z=L+~WO0T!KI_p{X!McyZ7=LF%nY04W74WN%wk@bXqs7Gt-9+{0^h9V>{qJUtvo!H! zKL7Po+BO`SNNq$+dy}l6(6{uzwP@F&XA-#JaW?;j^UI=F#c8jF$u~tWp=6~F6-!U$ z%-w#ofL~9Wr>s`F{twC(iL`P*?BWCU&Ee(@D(dt4A#RJ(TBuPfITMD4HLXR%Xw^2{ zaQ`9FxK`i^MP(w^fwNQ*a2b43RDbw&KSPpM?O#M7@;Tk`FVcRcnt!fgM4pbs`7fqs zteAQDmBt=JRo+-^cc^sEzDlXfa&^dc*rH|v;S&;J?KoMsd(OUCKg{}?Z0tHS#D}(F zUm=>7D5U4}U#@+zemK+98gCp^4sof!wc#v%UA?yEWeYnq&%Z9x2iCy^%I53nq}9SO zfku}*ucG=5)JGBf1WNTZV2=qC2kJuT1#>W2Em z?Qz7$Kf*rUF5p{?WJ&6WwB*mU!u`Dq#;p%v1?$uLA{5dyY~lWmx2_f9Z$%f{Hy~7%m!#?!S;TNJWvtEWf#ZKBLYja41Ei`|$ z2A-CmY_aVye*H1M+6LSDDV>%F>TvC$hQ>h~+jgmEU!4EC5<U-ogX4iIr8AFTh?@GN8o=4v9<3e5X%3QLh?@3k()8Xl*Ut|criwZ}RuRKl ztx~9F+BCDUxCit2g|lxV!Eq*h%Tg!I1`F-f2L#F2A5PMBYgtv`ta1;WoW!Xiom`? znpRmEHh0jUIJjVc$w+Ufc~09>z_0amP}Vss!|kQMt_%R$1SGMcVO}de`||FOs>vb$ zb+du9R5_%*Zl<1ejfu0sMfmkuc)1fW;V#@nn2B)C;ep*yKMxch2_}?_G035BLE^q@ zVd3fkWMicXcR!bK#EAMs=3gM-)8)3JsjpxW0)qwo+QZw%(K?}3CJC3YP2nII5@C*Z zcM<<0t}p?&`WpR6)=ZRj`1!VpheCz=4fp;-JSVn7JZwEF!#w4kJohOy3jB*c#rBKr zQ~pXkokO9ot)%#c_XO-4>gTD20NH!1CpF-gBRT~q!hmQ6{zWt93h&q#?w@DBx=;JS zUe)pCr}d<_$N2vFqcW609JNS7__ZpkfKA&S+{RXo*w5hip$Y!(@@?PiU)C(}{}u+4zw0Ye=pzaoQ^+Mx8+u_+=wv zyq79c$}i{e3vA13jo$?QkY;kLzf%F)MI0ORf#1?jcRW5^JD+Mv1m00r$Tw`h_E6u< z0F8!HgkM8eLzUL!uT^1IVJ#IBDOBp3TDEZhYXobGY!}X4C%P@Oz3hSHR~Bv6mbB{+ zoD!aWdFPkiY!@^T%v~Gfmmu%7b`;egGDB=Yo)O&hBxQIQ-vF?##0xLr*FMHC2cL|f z;bPqT0J6hi4+Z`OE~COKNnsmrqH?D;%0!G4g@yVOuv=L;}@O(+7A!;(plH5!_UiIwmyN395y6sggpBKerbOz+otphWfk!2 zZaeUS(iA_}bGL~HQUSk!r&;|$5q)5*StGUoAQn2fn|CCYnB!kWIKS+}iOU3zt~{#! zX9*kJjWI8B%JTUyuAfIKjsx0-P~QR(3yAF`osbbDk>_8iKSZ8Lx0NuR7+WDDIB{i; zB~~<*%Q^lvdw&$r3OAi#y^zlHZDt^IfM_{#v5E2P8g8`>@(mB85I^A8m9OIHu*=7uV0f$R~Dfae)s7OU=fij})PpJPjMP zc+WHca?g5j1&)-MR~q<*#f9^nJD&7*-~)Igr7fP_W%3VYVL~Jzt znE2eny^b|{s?zp+%TC}IlqCm|15vkWa{~uD!dM-dKmUbVQ1>~Qsp(Efg7~E5x3jn> zC*#E}7W6}e=nOYC#N`%&{oRvvHifm|x_5Ux%)hSM&=31`$NxDm(*i53i=@pIha?PVU!x3m=wn`p3rfOIbXlAo(6gDX+OgjCP;#- zL+dQ)Hu?I)+v$)~pF?DI3vvDn?)0ZxPwLq^y`wbitts=bDFfqKrl{f-IEO$K<2g&q zN09x`*Kc567Ungz*1dm&%jU1r59r=A!J_&@ydTTmnasbMCIY`yB5B-M(iu41T~t4h zG`FL73ch~>`OT>E)q%rQZ^a%duAk>Iqilog4Pho1y~D%Vx_6i!ds-aWd|D~!hs39Gamv^uSru*}hqEHyJCvN$4@;2x zG0aUbB9+s6#Gqw(6DeF48L+bXLJsV4kJ{1yW*>VShay`lc_7)MRL{*ZuunZZ;o z4zH;Y5{v2&F+$n;V8cHvmrOJ|Q8xb`UF%_opU1BfcNSJ~4B->=9c)NkglM7uFjLSE zbCj`HEXDb+r4nXE2=H>e4}I8&dHoP0^r{V2h4~lkYlON?+d|Nu*AMq$?%&`k^W4#g z=iV!ENkSq2<=)?m@Ssn*!yQiqMTX*}*%U*yVWIvIe{u-3s8mKI#zYjxUS!KAqU5cnmvTqw`KCg>$uJEZS}XR~;Zx%Y24b&ke=KjkTQ zaZxc!M-%2*%&U<9g7Sv2Fp*qn{MfF^0=CW(>JPEQD<{0?xco~V$py~h@2C7WcW^4Q zMR}KSvLk^+*oT6@%DsQ%3Or;Z%Z9)2XnhAufZKkUr|c`jFS_ou>SU&7{4+S9?~ms zfRkB)&bYCf?JLi}z!^5Q?TM`t+vt2F9s9tRdU>s*ZE`gzoFJ9?Ek&ev`@F&3tFI-%U_J;TNIhbDZ& zZpH$3jG0PYRwjXHDQsHHea~vZ#R6Cphr95ZSW^h~*sH8{a~Jpg7yEe(HR8<+f8RQ6*Fgf;r2-Xu&7eMWfjY{2IFYH3|GW)D0bpaR<8S9Del!n{e)?4`aS&v`z(c zid%?C7;|1f+{8UZbj^xdOSt0RV?NGWVr>{h1 zzQuhQzi|F56)~}1peI=bu8zEH;5=*;cPnxi=!g3)oZXhey~?C@IgQ1A0vmFss&zbg zpqPIR(<*C26n-A~^=`mcOuU~;3LKo{Us<<)18JR3p~80d!rqbpI?Vj5Guh-}iX`ZV zatY(t?Ua-?Q#g`SNrz;u3I1hz_Qm+s?Sm&-fu&6Hn&NCJ*eDvABK`$8vosytr-#v4 zMgcefB{Q;^e>pT|wJ`s}MfA{Z8r^doxQM>7M=8QDW+m(U6qWuA_n|$WuB~%#idf%Q ze1FvT1hDA|_RrifFhM37u{{{G!S9gy7g9elZLAXa&zm8~Ki1x2Jf_y-U$vKdYoV#L z*OJ7=0`V-$01#f@B_6Y$iECAr!pD!{`VHJaKe#lqqc^l~av)j0;y%MLjM?CaR+;g9tc>xX1s08IQE`?+Q`-01;FR=Zftzdi&10&HEbd_^vs z2mrt2KMu5w2fp81tRH$llke|s8Eb@3kXI6|=T0A)!!OQ%q1rG9*us4dAYy2Iu6~}n zjXyC8{A(7H&OU&~Fv=j$C4g4Lh!1CTQq=_g5GN(^tG8VI;xXg?sQMAi!XlIBo?!d( z+qbi;cxWTeF!oC?-A}sGB|4edJf|`4q*M}bJAxGw<7~{A?K+lw#-kLK1;v-bys6RC~L02h7 zpE-R4^@j#RBL{9d4L=54&HztO)4lAUO(o7__U?}Y{~AN8ZuS~jRzY1LE8<`7u`kG> z_NZ(-g=KmRH*yr?7tbB(AxHmLagR*N#V39K+TXo>!)TUx-`q&+!TTs^&fie?NusJ%f8ZOnyJvl885+i{SXZ zW+N}kB<BbVTVNrm~nH%*(<}%4!pvBea00Eaw1~Q;Sv3`hs z_=RPPCV%bmuWUOIjdxuhzh>ukv3Ht2+UUg_$bX^nN%yRN$mi_bc^y(FdXRYHy*e(h zn1i_+^+PxIdqiZNZD#!$0NMXA55{YqRP&AcA;$cD@s9JToBtATN!-Z6gU{!`u%^O| z4`E-JI~ErwnlbnA4f-Lf8YEclbm=MSHa;|Q;q49h1-8X14dd6e0U$%H?tOBjeuz*X zSWu^)MDP#4I?G&&@?VC}ll|3W;*pXBvJ2WZt#$aW#^MYH^i<3mJx6{^8|mH&QNa-Zr2J+pm6Y6+j+*3zZ;gArbzQqR|+egnhs#)HHh%H}apZT@?KNN^f=Y^&2+O3bf1N`?ahV0GYBEZ;TPGSU+^(7}s=@-vn&gQ0rVq zR+Rr*kF5p#3L`Xn%5?3^{rg`I4$J59>;G@>d}8Cc>Nx&;voo8qyKZKZ-DnO5jTLB3 z6jfuTX(}}+&ui~ysSGUmFO?5t)I*VSu$u$r0D9}X!G|DKP^2Cz5}KH- zWg$}{5eW$_QK29}YNQ}IG%CgXesA7;JG@B1@58^E_Y z?snn)OMD+r@1g{t7SMR?vevJ4_mkGU;+>7t&lZk~->!d_gzN`^Z_@Z6yZ?o21$3`& zK6VHG8p^%nKf#Cmso&v7*j6#77}EaN9dRMX)hGPfFM&V%b+52b<&b`v^}{zY&iLd^ zf}_(b_^_)yANqbJg3>QqKl~AGdo5VQ*rkjljpZV}!|gN4pm}}+$~!=>#l|}m$A=up z&ry*!$48S>kzPMsm->bM*ap5Y;g`)b$t7A6+-E;a9>3dJKm1GDCu|hn$C1L%v5SL0 zh9ANci9?De^^4XIQ3Ax#yM;Y?H>B4=6#gZo7HsPE!)x|Scy*o<*t1;%d`}?thkq8T z$Ih%D{uFO59Bbhhe)0VqIRBzCKdQqfjv+aPaMX4&<8X@>aJdG*l7#KD=%u)_CsFwY zLsMyfyiD$A-Om2k2ROIFZLga+|HAh<;KCG6Sky#J=@+!e3(I`Z zJ7*7FH^7$1r6n1o(*bBtIxB3E&wG^{2r~*`k02S7T8Zb$LeU71x%Mgo*B~t-l*NDm z7Q+IZ0DSL)21mn4>eFsGFSA84A69m9pzCUL90UeX1SayJ&$(gaz8dZ+diVfn3c?N* zXrJeuYOA?1Gg=wcU@!f`iqPlG3-ryTXJANZ zz&9Hyi}tD7QL7YAxE`*&8NlYFMaNJ8-q<(^1e{bT;M5;UO9=A7YZ{5E@Hl>PT?2mi zERmK(`LwG}+*%0d+{&tkSDiR%kVWWrRlD0=q)0?9841&_svWn2u7Gw+6y` z!#6&$v%uzHR#ZB`0#+pp*Vn7a#ziwO2Tlrh3NvJZPP+haQ4cq383Eq37PG~8=rty_ zPrF|DlDHM04TcDAC}_PwpzCVaot4&NJRelH5f(H^i_V=|y|5zo;&Z{!wgGhBi@zRx zBJtBW*K|4ME6zx3acMr7-LBvk1r}IN{4~G7%I23!v>5Lu&visv3_y`BiG}z?;9T*S z)>2?gtwuZ-RJ2cxJIibl=An{En1(XJl(eY2YE_6u5EfmwDgo$vQC(;e`kbq{_KFV> zyWXk73+uoDZ9kr?jLWH;{ZxL+ZE+Rr}oh-U8Yhhfr-YJ*$$(O!+O%gj#vpM0N+iJLNl>r?6uL7Xcw7ZJeyxP;Zqn%X;DrN8{<>W z<7K<8q2`Q1gX5cqOgSf=m#)9CJa@J7Lxe9!3SJ-(ow`CS*#hig5rh@O>#{CsQBLmU zSN$NVkNE2ZcAX)_ez1m?PC2!vKV#3b3RmEBjuwY3x-NI5>f&#Ihp!QMtCjGz#z?g^ zLl*4#Z&|NgOOesO2>ol68; zzsiF7^E2nCetrD!H+KIf;Y=2c&vW1U!XLi(liPRh5q$UD?eE-s?v=*&@gLuQ{~N}K zS$dJmKb676JXb=e5C1mj~J&~Hek4s4;z0l2@OY9H5rnGK7Jp}*4uqkf`& z9;}>RT~-1e<9oZ*ams$ab!=nuZ9fmn!%a#cyRHbku3kvDYDw9kSC^HAvvgPoZo+li znEdI09Qu)u9kT%H;EOz@J|5#%3~#~{Fd%ZUnw~VT9jMExKqqN`$kDY|myJMUd+6YJ zf|0=IKJmxGbC5_Ept`#B)CenrP<5el_KZicpH~)53%BN{`S?aqHdI?+ldRh0&FV_~TE^Paf2;ySEuH-=ZKrOak!FBwL!hbIZ`rg3n z)uqcuph=fiU3k5^blC_r>9X>{djr3K5l*_kl>^Z2DnK(SM^1@N*m>~hw{L6yBa+bkP(F>Z5IH^@iDE- zT`;a)9;z;P%dr;dZ<@ODa;z;M8J{j)HUcfd_*iSWel*GlJ%U{g(qeodI~Al3J2N>n zPWV6~xZLs}586jhP-I8A3pi!zl&pPl<{jelmt5@X0p-#e8TQ{ySlslv?@BWd|0$am*c^ai0#5<7*2Aql`2N39DG78 z>JIquma5D&#j8KL)uB6BTGdO31^N@T*rEB)e}MDn4{!P(POs>I(k1`QEuY_aoevV|1HD zQ2pHfeERl&1o{!^N1z{pegygv=ttmDj({95;eZLpOZ-ueL%;3)2=pV+k3c^H{Rs3U r@MuN=m-89Gi(iXC;J<*&`+VR*BBA`92sY^N=&1wz_j+erN)_^NlvGR& diff --git a/fpga/fpga_hf.v b/fpga/fpga_hf.v index 5d55cb89..ef935260 100644 --- a/fpga/fpga_hf.v +++ b/fpga/fpga_hf.v @@ -18,6 +18,7 @@ `include "hi_simulate.v" `include "hi_iso14443a.v" `include "hi_sniffer.v" +`include "hi_get_trace.v" `include "util.v" module fpga_hf( @@ -40,6 +41,7 @@ module fpga_hf( reg [15:0] shift_reg; reg [7:0] conf_word; +reg trace_enable; // We switch modes between transmitting to the 13.56 MHz tag and receiving // from it, which means that we must make sure that we can do so without @@ -48,6 +50,7 @@ always @(posedge ncs) begin case(shift_reg[15:12]) 4'b0001: conf_word <= shift_reg[7:0]; // FPGA_CMD_SET_CONFREG + 4'b0010: trace_enable <= shift_reg[0]; // FPGA_CMD_TRACE_ENABLE endcase end @@ -129,7 +132,7 @@ hi_iso14443a hisn( hi_sniffer he( pck0, ck_1356meg, ck_1356megb, - he_pwr_lo, he_pwr_hi, he_pwr_oe1, he_pwr_oe2, he_pwr_oe3, he_pwr_oe4, + he_pwr_lo, he_pwr_hi, he_pwr_oe1, he_pwr_oe2, he_pwr_oe3, he_pwr_oe4, adc_d, he_adc_clk, he_ssp_frame, he_ssp_din, ssp_dout, he_ssp_clk, cross_hi, cross_lo, @@ -137,6 +140,12 @@ hi_sniffer he( hi_read_rx_xcorr_848, hi_read_rx_xcorr_snoop, hi_read_rx_xcorr_quarter ); +hi_get_trace gt( + ck_1356megb, + adc_d, trace_enable, major_mode, + gt_ssp_frame, gt_ssp_din, gt_ssp_clk +); + // Major modes: // 000 -- HF reader, transmitting to tag; modulation depth selectable @@ -144,19 +153,20 @@ hi_sniffer he( // 010 -- HF simulated tag // 011 -- HF ISO14443-A // 100 -- HF Snoop +// 101 -- HF get trace // 111 -- everything off -mux8 mux_ssp_clk (major_mode, ssp_clk, ht_ssp_clk, hrxc_ssp_clk, hs_ssp_clk, hisn_ssp_clk, he_ssp_clk, 1'b0, 1'b0, 1'b0); -mux8 mux_ssp_din (major_mode, ssp_din, ht_ssp_din, hrxc_ssp_din, hs_ssp_din, hisn_ssp_din, he_ssp_din, 1'b0, 1'b0, 1'b0); -mux8 mux_ssp_frame (major_mode, ssp_frame, ht_ssp_frame, hrxc_ssp_frame, hs_ssp_frame, hisn_ssp_frame, he_ssp_frame, 1'b0, 1'b0, 1'b0); -mux8 mux_pwr_oe1 (major_mode, pwr_oe1, ht_pwr_oe1, hrxc_pwr_oe1, hs_pwr_oe1, hisn_pwr_oe1, he_pwr_oe1, 1'b0, 1'b0, 1'b0); -mux8 mux_pwr_oe2 (major_mode, pwr_oe2, ht_pwr_oe2, hrxc_pwr_oe2, hs_pwr_oe2, hisn_pwr_oe2, he_pwr_oe2, 1'b0, 1'b0, 1'b0); -mux8 mux_pwr_oe3 (major_mode, pwr_oe3, ht_pwr_oe3, hrxc_pwr_oe3, hs_pwr_oe3, hisn_pwr_oe3, he_pwr_oe3, 1'b0, 1'b0, 1'b0); -mux8 mux_pwr_oe4 (major_mode, pwr_oe4, ht_pwr_oe4, hrxc_pwr_oe4, hs_pwr_oe4, hisn_pwr_oe4, he_pwr_oe4, 1'b0, 1'b0, 1'b0); -mux8 mux_pwr_lo (major_mode, pwr_lo, ht_pwr_lo, hrxc_pwr_lo, hs_pwr_lo, hisn_pwr_lo, he_pwr_lo, 1'b0, 1'b0, 1'b0); -mux8 mux_pwr_hi (major_mode, pwr_hi, ht_pwr_hi, hrxc_pwr_hi, hs_pwr_hi, hisn_pwr_hi, he_pwr_hi, 1'b0, 1'b0, 1'b0); -mux8 mux_adc_clk (major_mode, adc_clk, ht_adc_clk, hrxc_adc_clk, hs_adc_clk, hisn_adc_clk, he_adc_clk, 1'b0, 1'b0, 1'b0); -mux8 mux_dbg (major_mode, dbg, ht_dbg, hrxc_dbg, hs_dbg, hisn_dbg, he_dbg, 1'b0, 1'b0, 1'b0); +mux8 mux_ssp_clk (major_mode, ssp_clk, ht_ssp_clk, hrxc_ssp_clk, hs_ssp_clk, hisn_ssp_clk, he_ssp_clk, gt_ssp_clk, 1'b0, 1'b0); +mux8 mux_ssp_din (major_mode, ssp_din, ht_ssp_din, hrxc_ssp_din, hs_ssp_din, hisn_ssp_din, he_ssp_din, gt_ssp_din, 1'b0, 1'b0); +mux8 mux_ssp_frame (major_mode, ssp_frame, ht_ssp_frame, hrxc_ssp_frame, hs_ssp_frame, hisn_ssp_frame, he_ssp_frame, gt_ssp_frame, 1'b0, 1'b0); +mux8 mux_pwr_oe1 (major_mode, pwr_oe1, ht_pwr_oe1, hrxc_pwr_oe1, hs_pwr_oe1, hisn_pwr_oe1, he_pwr_oe1, 1'b0, 1'b0, 1'b0); +mux8 mux_pwr_oe2 (major_mode, pwr_oe2, ht_pwr_oe2, hrxc_pwr_oe2, hs_pwr_oe2, hisn_pwr_oe2, he_pwr_oe2, 1'b0, 1'b0, 1'b0); +mux8 mux_pwr_oe3 (major_mode, pwr_oe3, ht_pwr_oe3, hrxc_pwr_oe3, hs_pwr_oe3, hisn_pwr_oe3, he_pwr_oe3, 1'b0, 1'b0, 1'b0); +mux8 mux_pwr_oe4 (major_mode, pwr_oe4, ht_pwr_oe4, hrxc_pwr_oe4, hs_pwr_oe4, hisn_pwr_oe4, he_pwr_oe4, 1'b0, 1'b0, 1'b0); +mux8 mux_pwr_lo (major_mode, pwr_lo, ht_pwr_lo, hrxc_pwr_lo, hs_pwr_lo, hisn_pwr_lo, he_pwr_lo, 1'b0, 1'b0, 1'b0); +mux8 mux_pwr_hi (major_mode, pwr_hi, ht_pwr_hi, hrxc_pwr_hi, hs_pwr_hi, hisn_pwr_hi, he_pwr_hi, 1'b0, 1'b0, 1'b0); +mux8 mux_adc_clk (major_mode, adc_clk, ht_adc_clk, hrxc_adc_clk, hs_adc_clk, hisn_adc_clk, he_adc_clk, 1'b0, 1'b0, 1'b0); +mux8 mux_dbg (major_mode, dbg, ht_dbg, hrxc_dbg, hs_dbg, hisn_dbg, he_dbg, 1'b0, 1'b0, 1'b0); // In all modes, let the ADC's outputs be enabled. assign adc_noe = 1'b0; diff --git a/fpga/hi_get_trace.v b/fpga/hi_get_trace.v new file mode 100644 index 00000000..7acecf80 --- /dev/null +++ b/fpga/hi_get_trace.v @@ -0,0 +1,160 @@ +//----------------------------------------------------------------------------- +// +// piwi, Feb 2019 +//----------------------------------------------------------------------------- + +module hi_get_trace( + ck_1356megb, + adc_d, trace_enable, major_mode, + ssp_frame, ssp_din, ssp_clk +); + input ck_1356megb; + input [7:0] adc_d; + input trace_enable; + input [2:0] major_mode; + output ssp_frame, ssp_din, ssp_clk; + +// constants for some major_modes: +`define OFF 3'b111 +`define GET_TRACE 3'b101 + + +// clock divider +reg [6:0] clock_cnt; +always @(negedge ck_1356megb) +begin + clock_cnt <= clock_cnt + 1; +end + +// sample at 13,56MHz / 8. The highest signal frequency (subcarrier) is 848,5kHz, i.e. in this case we oversample by a factor of 2 +reg [2:0] sample_clock; +always @(negedge ck_1356megb) +begin + if (sample_clock == 3'd3) + sample_clock <= 3'd0; + else + sample_clock <= sample_clock + 1; +end + + +reg [11:0] addr; +reg [11:0] start_addr; +reg [2:0] previous_major_mode; +reg write_enable1; +reg write_enable2; +always @(negedge ck_1356megb) +begin + previous_major_mode <= major_mode; + if (major_mode == `GET_TRACE) + begin + write_enable1 <= 1'b0; + write_enable2 <= 1'b0; + if (previous_major_mode != `GET_TRACE) // just switched into GET_TRACE mode + addr <= start_addr; + if (clock_cnt == 7'd0) + begin + if (addr == 12'd3071) + addr <= 12'd0; + else + addr <= addr + 1; + end + end + else if (major_mode != `OFF) + begin + if (trace_enable) + begin + if (addr[11] == 1'b0) + begin + write_enable1 <= 1'b1; + write_enable2 <= 1'b0; + end + else + begin + write_enable1 <= 1'b0; + write_enable2 <= 1'b1; + end + if (sample_clock == 3'b000) + begin + if (addr == 12'd3071) + begin + addr <= 12'd0; + write_enable1 <= 1'b1; + write_enable2 <= 1'b0; + end + else + addr <= addr + 1; + end + end + else + begin + write_enable1 <= 1'b0; + write_enable2 <= 1'b0; + start_addr <= addr; + end + end + else // major_mode == `OFF + begin + write_enable1 <= 1'b0; + write_enable2 <= 1'b0; + if (previous_major_mode != `OFF && previous_major_mode != `GET_TRACE) // just switched off + start_addr <= addr; + end +end + + +// (2+1)k RAM +reg [7:0] D_out1, D_out2; +reg [7:0] ram1 [2047:0]; +reg [7:0] ram2 [1023:0]; + +always @(negedge ck_1356megb) +begin + if (write_enable1) + begin + ram1[addr[10:0]] <= adc_d; + D_out1 <= adc_d; + end + else + D_out1 <= ram1[addr[10:0]]; + if (write_enable2) + begin + ram2[addr[9:0]] <= adc_d; + D_out2 <= adc_d; + end + else + D_out2 <= ram2[addr[9:0]]; +end + + +// SSC communication to ARM +reg ssp_clk; +reg ssp_frame; +reg [7:0] shift_out; + +always @(negedge ck_1356megb) +begin + if(clock_cnt[3:0] == 4'd0) // update shift register every 16 clock cycles + begin + if(clock_cnt[6:4] == 3'd0) // either load new value + begin + if (addr[11] == 1'b0) + shift_out <= D_out1; + else + shift_out <= D_out2; + end + else // or shift left + shift_out[7:1] <= shift_out[6:0]; + end + + ssp_clk <= ~clock_cnt[3]; // ssp_clk frequency = 13,56MHz / 16 = 847,5 kHz + + if(clock_cnt[6:4] == 3'b000) // set ssp_frame for 0...31 + ssp_frame <= 1'b1; + else + ssp_frame <= 1'b0; + +end + +assign ssp_din = shift_out[7]; + +endmodule diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 4c27ac85..ef282256 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -220,6 +220,7 @@ typedef struct{ #define CMD_MIFARE_DESFIRE 0x072e #define CMD_HF_SNIFFER 0x0800 +#define CMD_HF_PLOT 0x0801 #define CMD_UNKNOWN 0xFFFF From 0b6efd01ec437f17bcd94475083108eacde144c7 Mon Sep 17 00:00:00 2001 From: Oleg Moiseenko <807634+merlokk@users.noreply.github.com> Date: Thu, 21 Feb 2019 23:02:22 +0200 Subject: [PATCH 068/189] Emv scan via contact interface (#789) * share getATR from smartcard.h/c * remove duplicates in tlv.h and add get_uint_8 * check ATS/ATR length --- client/cmdsmartcard.c | 7 +- client/cmdsmartcard.h | 2 + client/emv/cmdemv.c | 161 +++++++++++++++++++++++++++++++++++------- client/emv/tlv.c | 6 ++ client/emv/tlv.h | 3 +- 5 files changed, 151 insertions(+), 28 deletions(-) diff --git a/client/cmdsmartcard.c b/client/cmdsmartcard.c index ac642fc9..b0d96f13 100644 --- a/client/cmdsmartcard.c +++ b/client/cmdsmartcard.c @@ -311,7 +311,7 @@ static int PrintATR(uint8_t *atr, size_t atrlen) { return 0; } -static bool smart_getATR(smart_card_atr_t *card) +bool smart_getATR(smart_card_atr_t *card) { if (UseAlternativeSmartcardReader) { return pcscGetATR(card); @@ -804,6 +804,11 @@ static int CmdSmartInfo(const char *Cmd){ if (!silent) PrintAndLogEx(WARNING, "smart card select failed"); return 1; } + + if (!card.atr_len) { + if (!silent) PrintAndLogEx(ERR, "can't get ATR from a smart card"); + return 1; + } // print header PrintAndLogEx(INFO, "--- Smartcard Information ---------"); diff --git a/client/cmdsmartcard.h b/client/cmdsmartcard.h index 310a417c..8925ac5a 100644 --- a/client/cmdsmartcard.h +++ b/client/cmdsmartcard.h @@ -13,8 +13,10 @@ #include #include +#include "smartcard.h" extern int CmdSmartcard(const char *Cmd); +extern bool smart_getATR(smart_card_atr_t *card); extern int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); #endif diff --git a/client/emv/cmdemv.c b/client/emv/cmdemv.c index 7e29b584..0e84260a 100644 --- a/client/emv/cmdemv.c +++ b/client/emv/cmdemv.c @@ -29,6 +29,7 @@ #include "dol.h" #include "emv_tags.h" #include "cmdhf14a.h" +#include "cmdsmartcard.h" #define TLV_ADD(tag, value)( tlvdb_change_or_add_node(tlvRoot, tag, sizeof(value) - 1, (const unsigned char *)value) ) void ParamLoadDefaults(struct tlvdb *tlvRoot) { @@ -1255,16 +1256,113 @@ int CmdEMVExec(const char *cmd) { // process Format1 (0x80) and print Format2 (0x77) ProcessACResponseFormat1(tlvRoot, buf, len, decodeTLV); - PrintAndLogEx(NORMAL, "\n* * Processing online request\n"); + uint8_t CID = 0; + tlvdb_get_uint8(tlvRoot, 0x9f27, &CID); + + // AC1 print result + PrintAndLog(""); + if ((CID & EMVAC_AC_MASK) == EMVAC_AAC) PrintAndLogEx(INFO, "AC1 result: AAC (Transaction declined)"); + if ((CID & EMVAC_AC_MASK) == EMVAC_TC) PrintAndLogEx(INFO, "AC1 result: TC (Transaction approved)"); + if ((CID & EMVAC_AC_MASK) == EMVAC_ARQC) PrintAndLogEx(INFO, "AC1 result: ARQC (Online authorisation requested)"); + if ((CID & EMVAC_AC_MASK) == EMVAC_AC_MASK) PrintAndLogEx(INFO, "AC1 result: RFU"); + + // decode Issuer Application Data (IAD) + uint8_t CryptoVersion = 0; + const struct tlv *IAD = tlvdb_get(tlvRoot, 0x9f10, NULL); + if (IAD && (IAD->len > 1)) { + PrintAndLogEx(NORMAL, "\n* * Issuer Application Data (IAD):"); + uint8_t VDDlen = IAD->value[0]; // Visa discretionary data length + uint8_t IDDlen = 0; // Issuer discretionary data length + PrintAndLogEx(NORMAL, "IAD length: %d", IAD->len); + PrintAndLogEx(NORMAL, "VDDlen: %d", VDDlen); + if (VDDlen < IAD->len - 1) + IDDlen = IAD->value[VDDlen + 1]; + PrintAndLogEx(NORMAL, "IDDlen: %d", IDDlen); + + uint8_t DerivKeyIndex = IAD->value[1]; + CryptoVersion = IAD->value[2]; + + PrintAndLogEx(NORMAL, "CryptoVersion: %d", CryptoVersion); + PrintAndLogEx(NORMAL, "DerivKeyIndex: %d", DerivKeyIndex); + + // Card Verification Results (CVR) decode + if ((VDDlen - 2) > 0) { + uint8_t CVRlen = IAD->value[3]; + if (CVRlen == (VDDlen - 2 - 1)) { + PrintAndLogEx(NORMAL, "CVR length: %d", CVRlen); + PrintAndLogEx(NORMAL, "CVR: %s", sprint_hex(&IAD->value[4], CVRlen)); + } else { + PrintAndLogEx(NORMAL, "Wrong CVR length! CVR: %s", sprint_hex(&IAD->value[3], VDDlen - 2)); + } + } + if (IDDlen) + PrintAndLogEx(NORMAL, "IDD: %s", sprint_hex(&IAD->value[VDDlen + 1], IDDlen)); + } else { + PrintAndLogEx(NORMAL, "Issuer Application Data (IAD) not found."); + } + + PrintAndLogEx(NORMAL, "\n* * Processing online request"); // authorization response code from acquirer - const char HostResponse[] = "00"; //0 x3030 - PrintAndLogEx(NORMAL, "* * Host Response: `%s`", HostResponse); - tlvdb_change_or_add_node(tlvRoot, 0x8a, sizeof(HostResponse) - 1, (const unsigned char *)HostResponse); + const char HostResponse[] = "00"; // 0x3030 + size_t HostResponseLen = sizeof(HostResponse) - 1; + PrintAndLogEx(NORMAL, "Host Response: `%s`", HostResponse); + tlvdb_change_or_add_node(tlvRoot, 0x8a, HostResponseLen, (const unsigned char *)HostResponse); + + if (CryptoVersion == 10) { + PrintAndLogEx(NORMAL, "\n* * Generate ARPC"); + + // Application Cryptogram (AC) + const struct tlv *AC = tlvdb_get(tlvRoot, 0x9f26, NULL); + if (AC && (AC->len > 0)) { + PrintAndLogEx(NORMAL, "AC: %s", sprint_hex(AC->value, AC->len)); + size_t rawARPClen = AC->len; + uint8_t rawARPC[rawARPClen]; + memcpy(rawARPC, AC->value, AC->len); + for (int i = 0; (i < HostResponseLen) && (i < rawARPClen); i++) + rawARPC[i] ^= HostResponse[i]; + PrintAndLogEx(NORMAL, "raw ARPC: %s", sprint_hex(rawARPC, rawARPClen)); + + // here must be calculation of ARPC, but we dont know a bank keys. + PrintAndLogEx(NORMAL, "ARPC: n/a"); + + } else { + PrintAndLogEx(NORMAL, "Application Cryptogram (AC) not found."); + } + // here must be external authenticate, but we dont know ARPC + } + + // needs to send AC2 command (res == ARQC) + if ((CID & EMVAC_AC_MASK) == EMVAC_ARQC) { + PrintAndLogEx(NORMAL, "\n* * Calc CDOL2"); + struct tlv *cdol2_data_tlv = dol_process(tlvdb_get(tlvRoot, 0x8d, NULL), tlvRoot, 0x01); // 0x01 - dummy tag + if (!cdol2_data_tlv) { + PrintAndLogEx(WARNING, "Error: can't create CDOL2 TLV."); + dreturn(6); + } + + PrintAndLogEx(NORMAL, "CDOL2 data[%d]: %s", cdol2_data_tlv->len, sprint_hex(cdol2_data_tlv->value, cdol2_data_tlv->len)); + + //PrintAndLogEx(NORMAL, "* * AC2"); + + + // here must be AC2, but we dont make external authenticate ( + +/* // AC2 + PRINT_INDENT(level); + if ((CID & EMVAC_AC2_MASK) == EMVAC_AAC2) fprintf(f, "\tAC2: AAC (Transaction declined)\n"); + if ((CID & EMVAC_AC2_MASK) == EMVAC_TC2) fprintf(f, "\tAC2: TC (Transaction approved)\n"); + if ((CID & EMVAC_AC2_MASK) == EMVAC_ARQC2) fprintf(f, "\tAC2: not requested (ARQC)\n"); + if ((CID & EMVAC_AC2_MASK) == EMVAC_AC2_MASK) fprintf(f, "\tAC2: RFU\n"); +*/ + } + + } + DropFieldEx( channel ); // Destroy TLV's @@ -1342,15 +1440,9 @@ int CmdEMVScan(const char *cmd) { PrintChannel(channel); uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2; CLIParserFree(); - + SetAPDULogging(showAPDU); - - // TODO - if (channel == ECC_CONTACT) { - PrintAndLogEx(ERR, "Do not use contact interface. Exit."); - return 1; - } - + // current path + file name if (!strstr(crelfname, ".json")) strcat(crelfname, ".json"); @@ -1376,22 +1468,41 @@ int CmdEMVScan(const char *cmd) { // drop field at start DropFieldEx( channel ); - // iso 14443 select - PrintAndLogEx(NORMAL, "--> GET UID, ATS."); - - iso14a_card_select_t card; - if (Hf14443_4aGetCardData(&card)) { - return 2; - } - JsonSaveStr(root, "$.File.Created", "proxmark3 `emv scan`"); + + if (channel == ECC_CONTACTLESS) { + // iso 14443 select + PrintAndLogEx(NORMAL, "--> GET UID, ATS."); - JsonSaveStr(root, "$.Card.Communication", "iso14443-4a"); - JsonSaveBufAsHex(root, "$.Card.UID", (uint8_t *)&card.uid, card.uidlen); - JsonSaveHex(root, "$.Card.ATQA", card.atqa[0] + (card.atqa[1] << 2), 2); - JsonSaveHex(root, "$.Card.SAK", card.sak, 0); - JsonSaveBufAsHex(root, "$.Card.ATS", (uint8_t *)card.ats, card.ats_len); + iso14a_card_select_t card; + if (Hf14443_4aGetCardData(&card)) { + return 2; + } + if (!card.uidlen) { + PrintAndLogEx(ERR, "get ATS error"); + return 2; + } + JsonSaveStr(root, "$.Card.Contactless.Communication", "iso14443-4a"); + JsonSaveBufAsHex(root, "$.Card.Contactless.UID", (uint8_t *)&card.uid, card.uidlen); + JsonSaveHex(root, "$.Card.Contactless.ATQA", card.atqa[0] + (card.atqa[1] << 2), 2); + JsonSaveHex(root, "$.Card.Contactless.SAK", card.sak, 0); + JsonSaveBufAsHex(root, "$.Card.Contactless.ATS", (uint8_t *)card.ats, card.ats_len); + } else { + PrintAndLogEx(NORMAL, "--> GET ATR."); + + smart_card_atr_t ccard; + smart_getATR(&ccard); + + if (!ccard.atr_len) { + PrintAndLogEx(ERR, "get ATR error"); + return 2; + } + + JsonSaveStr(root, "$.Card.Contact.Communication", "iso7816"); + JsonSaveBufAsHex(root, "$.Card.Contact.ATR", (uint8_t *)ccard.atr, ccard.atr_len); + } + // init applets list tree const char *al = "Applets list"; struct tlvdb *tlvSelect = tlvdb_fixed(1, strlen(al), (const unsigned char *)al); diff --git a/client/emv/tlv.c b/client/emv/tlv.c index 05de928e..5472c47a 100644 --- a/client/emv/tlv.c +++ b/client/emv/tlv.c @@ -588,3 +588,9 @@ bool tlv_get_int(const struct tlv *etlv, int *value) } return false; } + +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); +} diff --git a/client/emv/tlv.h b/client/emv/tlv.h index 80f6b74f..54900f41 100644 --- a/client/emv/tlv.h +++ b/client/emv/tlv.h @@ -65,7 +65,6 @@ bool tlv_equal(const struct tlv *a, const struct tlv *b); bool tlv_get_uint8(const struct tlv *etlv, uint8_t *value); bool tlv_get_int(const struct tlv *etlv, int *value); -bool tlv_get_uint8(const struct tlv *etlv, uint8_t *value); -bool tlv_get_int(const struct tlv *etlv, int *value); +bool tlvdb_get_uint8(struct tlvdb *tlvRoot, tlv_tag_t tag, uint8_t *value); #endif From b6851c194edcb16ef0ec3c13038216cabb6a46e0 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Tue, 26 Feb 2019 19:48:25 +0100 Subject: [PATCH 069/189] fix ATR length (#790) * TS, T0, T[A-D][1-4], max. 15 HB, TCK = 34 Bytes --- include/smartcard.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/smartcard.h b/include/smartcard.h index 82b346f5..161c6f6d 100644 --- a/include/smartcard.h +++ b/include/smartcard.h @@ -17,7 +17,7 @@ //----------------------------------------------------------------------------- typedef struct { uint8_t atr_len; - uint8_t atr[30]; + uint8_t atr[34]; } __attribute__((__packed__)) smart_card_atr_t; typedef enum SMARTCARD_COMMAND { From 1338d245c2ff5930a059d3d1fdea93a535fe6e61 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Sun, 3 Mar 2019 11:59:38 +0100 Subject: [PATCH 070/189] chip manufacturer and type identification: (#796) * add more manufacturers * refactor chipID decoding * move to separate file taginfo.[ch] --- client/Makefile | 3 +- client/cmdhf14a.c | 98 +---------------- client/cmdhf14a.h | 1 - client/cmdhf14b.c | 25 +---- client/cmdhf15.c | 211 +++---------------------------------- client/cmdhfmfu.c | 6 +- client/cmdhftopaz.c | 3 +- client/cmdlft55xx.c | 4 +- client/taginfo.c | 251 ++++++++++++++++++++++++++++++++++++++++++++ client/taginfo.h | 13 +++ 10 files changed, 294 insertions(+), 321 deletions(-) create mode 100644 client/taginfo.c create mode 100644 client/taginfo.h diff --git a/client/Makefile b/client/Makefile index aafbe375..5fc1d226 100644 --- a/client/Makefile +++ b/client/Makefile @@ -218,7 +218,8 @@ CMDSRCS = $(SRC_SMARTCARD) \ cmdscript.c\ pm3_binlib.c\ pm3_bitlib.c\ - protocols.c + protocols.c\ + taginfo.c cpu_arch = $(shell uname -m) ifneq ($(findstring 86, $(cpu_arch)), ) diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 922a9449..2bf84d22 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -31,105 +31,11 @@ #include "cliparser/cliparser.h" #include "emv/apduinfo.h" #include "emv/emvcore.h" +#include "taginfo.h" static int CmdHelp(const char *Cmd); static int waitCmd(uint8_t iLen); -// structure and database for uid -> tagtype lookups -typedef struct { - uint8_t uid; - char* desc; -} manufactureName; - -static const manufactureName manufactureMapping[] = { - // ID, "Vendor Country" - { 0x01, "Motorola UK" }, - { 0x02, "ST Microelectronics SA France" }, - { 0x03, "Hitachi, Ltd Japan" }, - { 0x04, "NXP Semiconductors Germany" }, - { 0x05, "Infineon Technologies AG Germany" }, - { 0x06, "Cylink USA" }, - { 0x07, "Texas Instrument France" }, - { 0x08, "Fujitsu Limited Japan" }, - { 0x09, "Matsushita Electronics Corporation, Semiconductor Company Japan" }, - { 0x0A, "NEC Japan" }, - { 0x0B, "Oki Electric Industry Co. Ltd Japan" }, - { 0x0C, "Toshiba Corp. Japan" }, - { 0x0D, "Mitsubishi Electric Corp. Japan" }, - { 0x0E, "Samsung Electronics Co. Ltd Korea" }, - { 0x0F, "Hynix / Hyundai, Korea" }, - { 0x10, "LG-Semiconductors Co. Ltd Korea" }, - { 0x11, "Emosyn-EM Microelectronics USA" }, - { 0x12, "INSIDE Technology France" }, - { 0x13, "ORGA Kartensysteme GmbH Germany" }, - { 0x14, "SHARP Corporation Japan" }, - { 0x15, "ATMEL France" }, - { 0x16, "EM Microelectronic-Marin SA Switzerland" }, - { 0x17, "KSW Microtec GmbH Germany" }, - { 0x18, "ZMD AG Germany" }, - { 0x19, "XICOR, Inc. USA" }, - { 0x1A, "Sony Corporation Japan Identifier Company Country" }, - { 0x1B, "Malaysia Microelectronic Solutions Sdn. Bhd Malaysia" }, - { 0x1C, "Emosyn USA" }, - { 0x1D, "Shanghai Fudan Microelectronics Co. Ltd. P.R. China" }, - { 0x1E, "Magellan Technology Pty Limited Australia" }, - { 0x1F, "Melexis NV BO Switzerland" }, - { 0x20, "Renesas Technology Corp. Japan" }, - { 0x21, "TAGSYS France" }, - { 0x22, "Transcore USA" }, - { 0x23, "Shanghai belling corp., ltd. China" }, - { 0x24, "Masktech Germany Gmbh Germany" }, - { 0x25, "Innovision Research and Technology Plc UK" }, - { 0x26, "Hitachi ULSI Systems Co., Ltd. Japan" }, - { 0x27, "Cypak AB Sweden" }, - { 0x28, "Ricoh Japan" }, - { 0x29, "ASK France" }, - { 0x2A, "Unicore Microsystems, LLC Russian Federation" }, - { 0x2B, "Dallas Semiconductor/Maxim USA" }, - { 0x2C, "Impinj, Inc. USA" }, - { 0x2D, "RightPlug Alliance USA" }, - { 0x2E, "Broadcom Corporation USA" }, - { 0x2F, "MStar Semiconductor, Inc Taiwan, ROC" }, - { 0x30, "BeeDar Technology Inc. USA" }, - { 0x31, "RFIDsec Denmark" }, - { 0x32, "Schweizer Electronic AG Germany" }, - { 0x33, "AMIC Technology Corp Taiwan" }, - { 0x34, "Mikron JSC Russia" }, - { 0x35, "Fraunhofer Institute for Photonic Microsystems Germany" }, - { 0x36, "IDS Microchip AG Switzerland" }, - { 0x37, "Kovio USA" }, - { 0x38, "HMT Microelectronic Ltd Switzerland Identifier Company Country" }, - { 0x39, "Silicon Craft Technology Thailand" }, - { 0x3A, "Advanced Film Device Inc. Japan" }, - { 0x3B, "Nitecrest Ltd UK" }, - { 0x3C, "Verayo Inc. USA" }, - { 0x3D, "HID Global USA" }, - { 0x3E, "Productivity Engineering Gmbh Germany" }, - { 0x3F, "Austriamicrosystems AG (reserved) Austria" }, - { 0x40, "Gemalto SA France" }, - { 0x41, "Renesas Electronics Corporation Japan" }, - { 0x42, "3Alogics Inc Korea" }, - { 0x43, "Top TroniQ Asia Limited Hong Kong" }, - { 0x44, "Gentag Inc (USA) USA" }, - { 0x00, "no tag-info available" } // must be the last entry -}; - -// get a product description based on the UID -// uid[8] tag uid -// returns description of the best match -char* getTagInfo(uint8_t uid) { - - int i; - int len = sizeof(manufactureMapping) / sizeof(manufactureName); - - for ( i = 0; i < len; ++i ) - if ( uid == manufactureMapping[i].uid) - return manufactureMapping[i].desc; - - //No match, return default - return manufactureMapping[len-1].desc; -} - int CmdHF14AList(const char *Cmd) { PrintAndLog("Deprecated command, use 'hf list 14a' instead"); @@ -363,7 +269,7 @@ int CmdHF14AInfo(const char *Cmd) // Double & triple sized UID, can be mapped to a manufacturer. // HACK: does this apply for Ultralight cards? if ( card.uidlen > 4 ) { - PrintAndLog("MANUFACTURER : %s", getTagInfo(card.uid[0])); + PrintAndLog("MANUFACTURER : %s", getManufacturerName(card.uid[0])); } // try to request ATS even if tag claims not to support it diff --git a/client/cmdhf14a.h b/client/cmdhf14a.h index d961d570..c4294b4c 100644 --- a/client/cmdhf14a.h +++ b/client/cmdhf14a.h @@ -23,7 +23,6 @@ int CmdHF14AReader(const char *Cmd); extern int CmdHF14AInfo(const char *Cmd); int CmdHF14ASim(const char *Cmd); int CmdHF14ASnoop(const char *Cmd); -char* getTagInfo(uint8_t uid); extern void DropField(); diff --git a/client/cmdhf14b.c b/client/cmdhf14b.c index ff0bf7c9..7cd55476 100644 --- a/client/cmdhf14b.c +++ b/client/cmdhf14b.c @@ -22,7 +22,8 @@ #include "ui.h" #include "cmdparser.h" #include "cmdmain.h" -#include "cmdhf14a.h" +#include "taginfo.h" + static int CmdHelp(const char *Cmd); @@ -305,24 +306,6 @@ static void print_atqb_resp(uint8_t *data){ return; } -// get SRx chip model (from UID) // from ST Microelectronics -char *get_ST_Chip_Model(uint8_t data){ - static char model[20]; - char *retStr = model; - memset(model,0, sizeof(model)); - - switch (data) { - case 0x0: sprintf(retStr, "SRIX4K (Special)"); break; - case 0x2: sprintf(retStr, "SR176"); break; - case 0x3: sprintf(retStr, "SRIX4K"); break; - case 0x4: sprintf(retStr, "SRIX512"); break; - case 0x6: sprintf(retStr, "SRI512"); break; - case 0x7: sprintf(retStr, "SRI4K"); break; - case 0xC: sprintf(retStr, "SRT512"); break; - default : sprintf(retStr, "Unknown"); break; - } - return retStr; -} int print_ST_Lock_info(uint8_t model){ //assume connection open and tag selected... @@ -393,8 +376,8 @@ int print_ST_Lock_info(uint8_t model){ static void print_st_general_info(uint8_t *data){ //uid = first 8 bytes in data PrintAndLog(" UID: %s", sprint_hex(SwapEndian64(data,8,8),8)); - PrintAndLog(" MFG: %02X, %s", data[6], getTagInfo(data[6])); - PrintAndLog(" Chip: %02X, %s", data[5]>>2, get_ST_Chip_Model(data[5]>>2)); + PrintAndLog(" MFG: %02X, %s", data[6], getManufacturerName(data[6])); + PrintAndLog(" Chip: %02X, %s", data[5], getChipInfo(data[6], data[5])); return; } diff --git a/client/cmdhf15.c b/client/cmdhf15.c index da83ccaf..5a7973f6 100644 --- a/client/cmdhf15.c +++ b/client/cmdhf15.c @@ -37,6 +37,7 @@ #include "iso15693tools.h" #include "protocols.h" #include "cmdmain.h" +#include "taginfo.h" #define Crc(data,datalen) Iso15693Crc(data,datalen) #define AddCrc(data,datalen) Iso15693AddCrc(data,datalen) @@ -86,158 +87,6 @@ static const int Iso15693FrameEOF[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; -// structure and database for uid -> tagtype lookups -typedef struct { - uint64_t uid; - int mask; // how many MSB bits used - char* desc; -} productName; - - -const productName uidmapping[] = { - - // UID, #significant Bits, "Vendor(+Product)" - { 0xE001000000000000LL, 16, "Motorola UK" }, - - // E0 02 xx - // 02 = ST Microelectronics - // XX = IC id (Chip ID Family) - { 0xE002000000000000LL, 16, "ST Microelectronics SA France" }, - { 0xE002050000000000LL, 24, "ST Microelectronics; LRI64 [IC id = 05]"}, - { 0xE002080000000000LL, 24, "ST Microelectronics; LRI2K [IC id = 08]"}, - { 0xE0020A0000000000LL, 24, "ST Microelectronics; LRIS2K [IC id = 10]"}, - { 0xE002440000000000LL, 24, "ST Microelectronics; LRIS64K [IC id = 68]"}, - - { 0xE003000000000000LL, 16, "Hitachi, Ltd Japan" }, - - // E0 04 xx - // 04 = Manufacturer code (Philips/NXP) - // XX = IC id (Chip ID Family) - //I-Code SLI SL2 ICS20 [IC id = 01] - //I-Code SLI-S [IC id = 02] - //I-Code SLI-L [IC id = 03] - //I-Code SLIX [IC id = 01 + bit36 set to 1 (starting from bit0 - different from normal SLI)] - //I-Code SLIX-S [IC id = 02 + bit36 set to 1] - //I-Code SLIX-L [IC id = 03 + bit36 set to 1] - { 0xE004000000000000LL, 16, "NXP Semiconductors Germany (Philips)" }, - { 0xE004010000000000LL, 24, "NXP(Philips); IC SL2 ICS20/ICS21(SLI) ICS2002/ICS2102(SLIX)" }, - { 0xE004020000000000LL, 24, "NXP(Philips); IC SL2 ICS53/ICS54(SLI-S) ICS5302/ICS5402(SLIX-S)" }, - { 0xE004030000000000LL, 24, "NXP(Philips); IC SL2 ICS50/ICS51(SLI-L) ICS5002/ICS5102(SLIX-L)" }, - - // E0 05 XX .. .. .. - // 05 = Manufacturer code (Infineon) - // XX = IC id (Chip ID Family) - { 0xE005000000000000LL, 16, "Infineon Technologies AG Germany" }, - { 0xE005A10000000000LL, 24, "Infineon; SRF55V01P [IC id = 161] plain mode 1kBit"}, - { 0xE005A80000000000LL, 24, "Infineon; SRF55V01P [IC id = 168] pilot series 1kBit"}, - { 0xE005400000000000LL, 24, "Infineon; SRF55V02P [IC id = 64] plain mode 2kBit"}, - { 0xE005000000000000LL, 24, "Infineon; SRF55V10P [IC id = 00] plain mode 10KBit"}, - { 0xE005500000000000LL, 24, "Infineon; SRF55V02S [IC id = 80] secure mode 2kBit"}, - { 0xE005100000000000LL, 24, "Infineon; SRF55V10S [IC id = 16] secure mode 10KBit"}, - { 0xE0051E0000000000LL, 23, "Infineon; SLE66r01P [IC id = 3x = My-d Move or My-d move NFC]"}, - { 0xE005200000000000LL, 21, "Infineon; SLE66r01P [IC id = 3x = My-d Move or My-d move NFC]"}, - - { 0xE006000000000000LL, 16, "Cylink USA" }, - - - // E0 07 xx - // 07 = Texas Instruments - // XX = from bit 41 to bit 43 = product configuration - from bit 44 to bit 47 IC id (Chip ID Family) - //Tag IT RFIDType-I Plus, 2kBit, TI Inlay - //Tag-it HF-I Plus Inlay [IC id = 00] -> b'0000 000 2kBit - //Tag-it HF-I Plus Chip [IC id = 64] -> b'1000 000 2kBit - //Tag-it HF-I Standard Chip / Inlays [IC id = 96] -> b'1100 000 256Bit - //Tag-it HF-I Pro Chip / Inlays [IC id = 98] -> b'1100 010 256Bit, Password protection - { 0xE007000000000000LL, 16, "Texas Instrument France" }, - { 0xE007000000000000LL, 20, "Texas Instrument; Tag-it HF-I Plus Inlay; 64x32bit" }, - { 0xE007100000000000LL, 20, "Texas Instrument; Tag-it HF-I Plus Chip; 64x32bit" }, - { 0xE007800000000000LL, 23, "Texas Instrument; Tag-it HF-I Plus (RF-HDT-DVBB tag or Third Party Products)" }, - { 0xE007C00000000000LL, 23, "Texas Instrument; Tag-it HF-I Standard; 8x32bit" }, - { 0xE007C40000000000LL, 23, "Texas Instrument; Tag-it HF-I Pro; 8x23bit; password" }, - - { 0xE008000000000000LL, 16, "Fujitsu Limited Japan" }, - { 0xE009000000000000LL, 16, "Matsushita Electronics Corporation, Semiconductor Company Japan" }, - { 0xE00A000000000000LL, 16, "NEC Japan" }, - { 0xE00B000000000000LL, 16, "Oki Electric Industry Co. Ltd Japan" }, - { 0xE00C000000000000LL, 16, "Toshiba Corp. Japan" }, - { 0xE00D000000000000LL, 16, "Mitsubishi Electric Corp. Japan" }, - { 0xE00E000000000000LL, 16, "Samsung Electronics Co. Ltd Korea" }, - { 0xE00F000000000000LL, 16, "Hynix / Hyundai, Korea" }, - { 0xE010000000000000LL, 16, "LG-Semiconductors Co. Ltd Korea" }, - { 0xE011000000000000LL, 16, "Emosyn-EM Microelectronics USA" }, - - { 0xE012000000000000LL, 16, "HID Corporation" }, - { 0xE012000000000000LL, 16, "INSIDE Technology France" }, - { 0xE013000000000000LL, 16, "ORGA Kartensysteme GmbH Germany" }, - { 0xE014000000000000LL, 16, "SHARP Corporation Japan" }, - { 0xE015000000000000LL, 16, "ATMEL France" }, - - { 0xE016000000000000LL, 16, "EM Microelectronic-Marin SA Switzerland (Skidata)"}, - { 0xE016040000000000LL, 24, "EM-Marin SA (Skidata Keycard-eco); EM4034 [IC id = 01] (Read/Write - no AFI)"}, - { 0xE0160C0000000000LL, 24, "EM-Marin SA (Skidata); EM4035 [IC id = 03] (Read/Write - replaced by 4233)"}, - { 0xE016100000000000LL, 24, "EM-Marin SA (Skidata); EM4135 [IC id = 04] (Read/Write - replaced by 4233) 36x64bit start page 13"}, - { 0xE016140000000000LL, 24, "EM-Marin SA (Skidata); EM4036 [IC id = 05] 28pF"}, - { 0xE016180000000000LL, 24, "EM-Marin SA (Skidata); EM4006 [IC id = 06] (Read Only)"}, - { 0xE0161C0000000000LL, 24, "EM-Marin SA (Skidata); EM4133 [IC id = 07] 23,5pF (Read/Write)"}, - { 0xE016200000000000LL, 24, "EM-Marin SA (Skidata); EM4033 [IC id = 08] 23,5pF (Read Only - no AFI / no DSFID / no security blocks)"}, - { 0xE016240000000000LL, 24, "EM-Marin SA (Skidata); EM4233 [IC id = 09] 23,5pF CustomerID-102"}, - { 0xE016280000000000LL, 24, "EM-Marin SA (Skidata); EM4233 SLIC [IC id = 10] 23,5pF (1Kb flash memory - not provide High Security mode and QuietStorage feature)" }, - { 0xE0163C0000000000LL, 24, "EM-Marin SA (Skidata); EM4237 [IC id = 15] 23,5pF"}, - { 0xE0167C0000000000LL, 24, "EM-Marin SA (Skidata); EM4233 [IC id = 31] 95pF"}, - { 0xE016940000000000LL, 24, "EM-Marin SA (Skidata); EM4036 [IC id = 37] 95pF 51x64bit "}, - { 0xE0169c0000000000LL, 24, "EM-Marin SA (Skidata); EM4133 [IC id = 39] 95pF (Read/Write)" }, - { 0xE016A80000000000LL, 24, "EM-Marin SA (Skidata); EM4233 SLIC [IC id = 42] 97pF" }, - { 0xE016BC0000000000LL, 24, "EM-Marin SA (Skidata); EM4237 [IC id = 47] 97pF" }, - - { 0xE017000000000000LL, 16, "KSW Microtec GmbH Germany" }, - { 0xE018000000000000LL, 16, "ZMD AG Germany" }, - { 0xE019000000000000LL, 16, "XICOR, Inc. USA" }, - { 0xE01A000000000000LL, 16, "Sony Corporation Japan Identifier Company Country" }, - { 0xE01B000000000000LL, 16, "Malaysia Microelectronic Solutions Sdn. Bhd Malaysia" }, - { 0xE01C000000000000LL, 16, "Emosyn USA" }, - { 0xE01D000000000000LL, 16, "Shanghai Fudan Microelectronics Co. Ltd. P.R. China" }, - { 0xE01E000000000000LL, 16, "Magellan Technology Pty Limited Australia" }, - { 0xE01F000000000000LL, 16, "Melexis NV BO Switzerland" }, - { 0xE020000000000000LL, 16, "Renesas Technology Corp. Japan" }, - { 0xE021000000000000LL, 16, "TAGSYS France" }, - { 0xE022000000000000LL, 16, "Transcore USA" }, - { 0xE023000000000000LL, 16, "Shanghai belling corp., ltd. China" }, - { 0xE024000000000000LL, 16, "Masktech Germany Gmbh Germany" }, - { 0xE025000000000000LL, 16, "Innovision Research and Technology Plc UK" }, - { 0xE026000000000000LL, 16, "Hitachi ULSI Systems Co., Ltd. Japan" }, - { 0xE027000000000000LL, 16, "Cypak AB Sweden" }, - { 0xE028000000000000LL, 16, "Ricoh Japan" }, - { 0xE029000000000000LL, 16, "ASK France" }, - { 0xE02A000000000000LL, 16, "Unicore Microsystems, LLC Russian Federation" }, - { 0xE02B000000000000LL, 16, "Dallas Semiconductor/Maxim USA" }, - { 0xE02C000000000000LL, 16, "Impinj, Inc. USA" }, - { 0xE02D000000000000LL, 16, "RightPlug Alliance USA" }, - { 0xE02E000000000000LL, 16, "Broadcom Corporation USA" }, - { 0xE02F000000000000LL, 16, "MStar Semiconductor, Inc Taiwan, ROC" }, - { 0xE030000000000000LL, 16, "BeeDar Technology Inc. USA" }, - { 0xE031000000000000LL, 16, " RFIDsec Denmark" }, - { 0xE032000000000000LL, 16, " Schweizer Electronic AG Germany" }, - { 0xE033000000000000LL, 16, " AMIC Technology Corp Taiwan" }, - { 0xE034000000000000LL, 16, "Mikron JSC Russia" }, - { 0xE035000000000000LL, 16, "Fraunhofer Institute for Photonic Microsystems Germany" }, - { 0xE036000000000000LL, 16, "IDS Microchip AG Switzerland" }, - { 0xE037000000000000LL, 16, "Kovio USA" }, - { 0xE038000000000000LL, 16, "HMT Microelectronic Ltd Switzerland Identifier Company Country" }, - { 0xE039000000000000LL, 16, "Silicon Craft Technology Thailand" }, - { 0xE03A000000000000LL, 16, "Advanced Film Device Inc. Japan" }, - { 0xE03B000000000000LL, 16, "Nitecrest Ltd UK" }, - { 0xE03C000000000000LL, 16, "Verayo Inc. USA" }, - { 0xE03D000000000000LL, 16, "HID Global USA" }, - { 0xE03E000000000000LL, 16, "Productivity Engineering Gmbh Germany" }, - { 0xE03F000000000000LL, 16, "Austriamicrosystems AG (reserved) Austria" }, - { 0xE040000000000000LL, 16, "Gemalto SA France" }, - { 0xE041000000000000LL, 16, "Renesas Electronics Corporation Japan" }, - { 0xE042000000000000LL, 16, "3Alogics Inc Korea" }, - { 0xE043000000000000LL, 16, "Top TroniQ Asia Limited Hong Kong" }, - { 0xE044000000000000LL, 16, "Gentag Inc (USA) USA" }, - { 0,0,"no tag-info available" } // must be the last entry -}; - // fast method to just read the UID of a tag (collission detection not supported) // *buf should be large enough to fit the 64bit uid @@ -272,34 +121,6 @@ int getUID(uint8_t *buf) } - -// get a product description based on the UID -// uid[8] tag uid -// returns description of the best match -static char* getTagInfo(uint8_t *uid) { - uint64_t myuid,mask; - int i=0, best=-1; - memcpy(&myuid,uid,sizeof(uint64_t)); - while (uidmapping[i].mask>0) { - mask=(~0LL) <<(64-uidmapping[i].mask); - if ((myuid & mask) == uidmapping[i].uid) { - if (best==-1) { - best=i; - } else { - if (uidmapping[i].mask>uidmapping[best].mask) { - best=i; - } - } - } - i++; - } - - if (best>=0) return uidmapping[best].desc; - - return uidmapping[i].desc; -} - - // return a clear-text message to an errorcode static char* TagErrorStr(uint8_t error) { switch (error) { @@ -429,8 +250,9 @@ int HF15Reader(const char *Cmd, bool verbose) return 0; } - PrintAndLog("Tag UID : %s",sprintUID(NULL,uid)); - PrintAndLog("Tag Info: %s",getTagInfo(uid)); + PrintAndLog("UID: %s", sprintUID(NULL,uid)); + PrintAndLog("Manufacturer byte: %02X, %s", uid[6], getManufacturerName(uid[6])); + PrintAndLog("Chip ID: %02X, %s", uid[5], getChipInfo(uid[6], uid[5])); return 1; } @@ -496,8 +318,10 @@ int CmdHF15DumpMem(const char*Cmd) { return 0; } - PrintAndLog("Reading memory from tag UID=%s",sprintUID(NULL,uid)); - PrintAndLog("Tag Info: %s",getTagInfo(uid)); + PrintAndLog("Reading memory from tag"); + PrintAndLog("UID: %s", sprintUID(NULL,uid)); + PrintAndLog("Manufacturer byte: %02X, %s", uid[6], getManufacturerName(uid[6])); + PrintAndLog("Chip ID: %02X, %s", uid[5], getChipInfo(uid[6], uid[5])); for (int retry=0; retry<5; retry++) { @@ -595,9 +419,10 @@ int CmdHF15CmdInquiry(const char *Cmd) if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) { if (resp.arg[0]>=12) { - recv = resp.d.asBytes; - PrintAndLog("UID=%s",sprintUID(NULL,&recv[2])); - PrintAndLog("Tag Info: %s",getTagInfo(&recv[2])); + recv = resp.d.asBytes; + PrintAndLog("UID: %s", sprintUID(NULL,recv+2)); + PrintAndLog("Manufacturer byte: %02X, %s", recv[8], getManufacturerName(recv[8])); + PrintAndLog("Chip ID: %02X, %s", recv[7], getChipInfo(recv[8], recv[7])); } else { PrintAndLog("Response to short, just %i bytes. No tag?\n",resp.arg[0]); } @@ -855,15 +680,9 @@ int CmdHF15CmdSysinfo(const char *Cmd) { if (ISO15693_CRC_CHECK==Crc(recv,resp.arg[0])) { if (!(recv[0] & ISO15693_RES_ERROR)) { *output=0; // reset outputstring - for ( i=1; i> 4) == 2 ) { // is infineon and 66RxxP uint8_t chip = (data[8] & 0xC7); // 11000111 mask, bit 3,4,5 RFU switch (chip){ @@ -516,7 +516,7 @@ static int ulev1_print_signature( uint8_t *data, uint8_t len){ static int ulev1_print_version(uint8_t *data){ PrintAndLog("\n--- Tag Version"); PrintAndLog(" Raw bytes : %s",sprint_hex(data, 8) ); - PrintAndLog(" Vendor ID : %02X, %s", data[1], getTagInfo(data[1])); + PrintAndLog(" Vendor ID : %02X, %s", data[1], getManufacturerName(data[1])); PrintAndLog(" Product type : %s", getProductTypeStr(data[2])); PrintAndLog(" Product subtype : %02X, %s", data[3], (data[3]==1) ?"17 pF":"50pF"); PrintAndLog(" Major version : %02X", data[4]); diff --git a/client/cmdhftopaz.c b/client/cmdhftopaz.c index 6058cabe..261d78aa 100644 --- a/client/cmdhftopaz.c +++ b/client/cmdhftopaz.c @@ -22,6 +22,7 @@ #include "comms.h" #include "iso14443crc.h" #include "protocols.h" +#include "taginfo.h" #define TOPAZ_STATIC_MEMORY (0x0f * 8) // 15 blocks with 8 Bytes each @@ -477,7 +478,7 @@ int CmdHFTopazReader(const char *Cmd) topaz_tag.uid[0]); PrintAndLog(" UID[6] (Manufacturer Byte) = %02x, Manufacturer: %s", topaz_tag.uid[6], - getTagInfo(topaz_tag.uid[6])); + getManufacturerName(topaz_tag.uid[6])); memcpy(topaz_tag.data_blocks, rall_response+2, 0x0f*8); PrintAndLog(""); diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index 2a096cd0..b286c392 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -23,8 +23,8 @@ #include "cmdlf.h" #include "util.h" #include "lfdemod.h" -#include "cmdhf14a.h" //for getTagInfo #include "protocols.h" +#include "taginfo.h" #define T55x7_CONFIGURATION_BLOCK 0x00 #define T55x7_PAGE0 0x00 @@ -1070,7 +1070,7 @@ void printT55x7Trace( t55x7_tracedata_t data, uint8_t repeat ){ PrintAndLog("-- T55x7 Trace Information ----------------------------------"); PrintAndLog("-------------------------------------------------------------"); PrintAndLog(" ACL Allocation class (ISO/IEC 15963-1) : 0x%02X (%d)", data.acl, data.acl); - PrintAndLog(" MFC Manufacturer ID (ISO/IEC 7816-6) : 0x%02X (%d) - %s", data.mfc, data.mfc, getTagInfo(data.mfc)); + PrintAndLog(" MFC Manufacturer ID (ISO/IEC 7816-6) : 0x%02X (%d) - %s", data.mfc, data.mfc, getManufacturerName(data.mfc)); PrintAndLog(" CID : 0x%02X (%d) - %s", data.cid, data.cid, GetModelStrFromCID(data.cid)); PrintAndLog(" ICR IC Revision : %d", data.icr ); PrintAndLog(" Manufactured"); diff --git a/client/taginfo.c b/client/taginfo.c new file mode 100644 index 00000000..0949e43f --- /dev/null +++ b/client/taginfo.c @@ -0,0 +1,251 @@ +//----------------------------------------------------------------------------- +// Functions for Chip Identification +//----------------------------------------------------------------------------- + +#include "taginfo.h" + +#include + +// ISO/IEC 7816-6 manufacturer byte decoding + +typedef struct { + uint8_t manufacturer_byte; + char* desc; +} manufacturerName_t; + +// based on ISO/IEC JTC1/SC17 STANDING DOCUMENT 5 (Updated March 2018) Register of IC manufacturers +static const manufacturerName_t manufacturerMapping[] = { + // ID, "Vendor Country" + { 0x01, "Motorola UK"}, + { 0x02, "STMicroelectronics SA France"}, + { 0x03, "Hitachi, Ltd Japan"}, + { 0x04, "NXP Semiconductors Germany"}, + { 0x05, "Infineon Technologies AG Germany"}, + { 0x06, "Cylink USA"}, + { 0x07, "Texas Instrument France"}, + { 0x08, "Fujitsu Limited Japan"}, + { 0x09, "Matsushita Electronics Corporation, Semiconductor Company Japan"}, + { 0x0A, "NEC Japan"}, + { 0x0B, "Oki Electric Industry Co. Ltd Japan"}, + { 0x0C, "Toshiba Corp. Japan"}, + { 0x0D, "Mitsubishi Electric Corp. Japan"}, + { 0x0E, "Samsung Electronics Co. Ltd Korea"}, + { 0x0F, "Hynix Korea"}, + { 0x10, "LG-Semiconductors Co. Ltd Korea"}, + { 0x11, "Emosyn-EM Microelectronics USA"}, + { 0x12, "INSIDE Technology France"}, + { 0x13, "ORGA Kartensysteme GmbH Germany"}, + { 0x14, "SHARP Corporation Japan"}, + { 0x15, "ATMEL France"}, + { 0x16, "EM Microelectronic-Marin SA Switzerland"}, + { 0x17, "SMARTRAC TECHNOLOGY GmbH Germany"}, + { 0x18, "ZMD AG Germany"}, + { 0x19, "XICOR, Inc. USA"}, + { 0x1A, "Sony Corporation Japan"}, + { 0x1B, "Malaysia Microelectronic Solutions Sdn. Bhd Malaysia"}, + { 0x1C, "Emosyn USA"}, + { 0x1D, "Shanghai Fudan Microelectronics Co. Ltd. P.R. China"}, + { 0x1E, "Magellan Technology Pty Limited Australia"}, + { 0x1F, "Melexis NV BO Switzerland"}, + { 0x20, "Renesas Technology Corp. Japan"}, + { 0x21, "TAGSYS France"}, + { 0x22, "Transcore USA"}, + { 0x23, "Shanghai belling corp., ltd. China"}, + { 0x24, "Masktech Germany Gmbh Germany"}, + { 0x25, "Innovision Research and Technology Plc UK"}, + { 0x26, "Hitachi ULSI Systems Co., Ltd. Japan"}, + { 0x27, "Yubico AB Sweden"}, + { 0x28, "Ricoh Japan"}, + { 0x29, "ASK France"}, + { 0x2A, "Unicore Microsystems, LLC Russian Federation"}, + { 0x2B, "Dallas Semiconductor/Maxim USA"}, + { 0x2C, "Impinj, Inc. USA"}, + { 0x2D, "RightPlug Alliance USA"}, + { 0x2E, "Broadcom Corporation USA"}, + { 0x2F, "MStar Semiconductor, Inc Taiwan, ROC"}, + { 0x30, "BeeDar Technology Inc. USA"}, + { 0x31, "RFIDsec Denmark"}, + { 0x32, "Schweizer Electronic AG Germany"}, + { 0x33, "AMIC Technology Corp Taiwan"}, + { 0x34, "Mikron JSC Russia"}, + { 0x35, "Fraunhofer Institute for Photonic Microsystems Germany"}, + { 0x36, "IDS Microchip AG Switzerland"}, + { 0x37, "Kovio USA"}, + { 0x38, "HMT Microelectronic Ltd Switzerland"}, + { 0x39, "Silicon Craft Technology Thailand"}, + { 0x3A, "Advanced Film Device Inc. Japan"}, + { 0x3B, "Nitecrest Ltd UK"}, + { 0x3C, "Verayo Inc. USA"}, + { 0x3D, "HID Global USA"}, + { 0x3E, "Productivity Engineering Gmbh Germany"}, + { 0x3F, "Austriamicrosystems AG (reserved) Austria"}, + { 0x40, "Gemalto SA France"}, + { 0x41, "Renesas Electronics Corporation Japan"}, + { 0x42, "3Alogics Inc Korea"}, + { 0x43, "Top TroniQ Asia Limited Hong Kong"}, + { 0x44, "Gentag Inc (USA) USA"}, + { 0x45, "Invengo Information Technology Co.Ltd China"}, + { 0x46, "Guangzhou Sysur Microelectronics, Inc China"}, + { 0x47, "CEITEC S.A. Brazil"}, + { 0x48, "Shanghai Quanray Electronics Co. Ltd. China"}, + { 0x49, "MediaTek Inc Taiwan"}, + { 0x4A, "Angstrem PJSC Russia"}, + { 0x4B, "Celisic Semiconductor (Hong Kong) Limited China"}, + { 0x4C, "LEGIC Identsystems AG Switzerland"}, + { 0x4D, "Balluff GmbH Germany"}, + { 0x4E, "Oberthur Technologies France"}, + { 0x4F, "Silterra Malaysia Sdn. Bhd. Malaysia"}, + { 0x50, "DELTA Danish Electronics, Light & Acoustics Denmark"}, + { 0x51, "Giesecke & Devrient GmbH Germany"}, + { 0x52, "Shenzhen China Vision Microelectronics Co., Ltd. China"}, + { 0x53, "Shanghai Feiju Microelectronics Co. Ltd. China"}, + { 0x54, "Intel Corporation USA"}, + { 0x55, "Microsensys GmbH Germany"}, + { 0x56, "Sonix Technology Co., Ltd. Taiwan"}, + { 0x57, "Qualcomm Technologies Inc USA"}, + { 0x58, "Realtek Semiconductor Corp Taiwan"}, + { 0x59, "Freevision Technologies Co. Ltd China"}, + { 0x5A, "Giantec Semiconductor Inc. China"}, + { 0x5B, "JSC Angstrem-T Russia"}, + { 0x5C, "STARCHIP France"}, + { 0x5D, "SPIRTECH France"}, + { 0x5E, "GANTNER Electronic GmbH Austria"}, + { 0x5F, "Nordic Semiconductor Norway"}, + { 0x60, "Verisiti Inc USA"}, + { 0x61, "Wearlinks Technology Inc. China"}, + { 0x62, "Userstar Information Systems Co., Ltd Taiwan"}, + { 0x63, "Pragmatic Printing Ltd. UK"}, + { 0x64, "Associacao do Laboratorio de Sistemas Integraveis Tecnologico – LSI-TEC Brazil"}, + { 0x65, "Tendyron Corporation China"}, + { 0x66, "MUTO Smart Co., Ltd. Korea"}, + { 0x67, "ON Semiconductor USA"}, + { 0x68, "TÜBİTAK BİLGEM Turkey"}, + { 0x69, "Huada Semiconductor Co., Ltd China"}, + { 0x6A, "SEVENEY France"}, + { 0x6B, "ISSM France"}, + { 0x6C, "Wisesec Ltd Israel"}, + { 0x7E, "Holtek Taiwan"}, + { 0x00, "Unknown" } // must be the last entry +}; + +// get manufacturer's name and country based on the manufacturer byte +char *getManufacturerName(uint8_t vendorID) +{ + int i; + int len = sizeof(manufacturerMapping) / sizeof(manufacturerName_t); + + for (i = 0; i < len; ++i) + if (vendorID == manufacturerMapping[i].manufacturer_byte) + return manufacturerMapping[i].desc; + + //No match, return default + return manufacturerMapping[len-1].desc; +} + + +// Chip ID encoding + +typedef struct { + uint8_t manufacturer; // chip info is manufacturer specific + uint8_t chipID; + uint8_t mask; // relevant bits + char* desc; +} chipinfo_t; + + +const chipinfo_t chipIDmapping[] = { + // manufacturer_byte, chip_id, bitmask for chip_id, Text + + // 0x02 = ST Microelectronics + { 0x02, 0x05, 0xFF, "LRI64 [IC id = 05]"}, + { 0x02, 0x08, 0xFF, "LRI2K [IC id = 08]"}, + { 0x02, 0x0A, 0xFF, "LRIS2K [IC id = 10]"}, + { 0x02, 0x44, 0xFF, "LRIS64K [IC id = 68]"}, + { 0x02, 0x00, 0xFC, "SRIX4K (Special)"}, + { 0x02, 0x08, 0xFC, "SR176"}, + { 0x02, 0x0C, 0xFC, "SRIX4K"}, + { 0x02, 0x10, 0xFC, "SRIX512"}, + { 0x02, 0x18, 0xFC, "SRI512"}, + { 0x02, 0x1C, 0xFC, "SRI4K"}, + { 0x02, 0x30, 0xFC, "SRT512"}, + + // 0x04 = Philips/NXP + //I-Code SLI SL2 ICS20 [IC id = 01] + //I-Code SLI-S [IC id = 02] + //I-Code SLI-L [IC id = 03] + //I-Code SLIX [IC id = 01 + bit36 set to 1 (starting from bit0 - different from normal SLI)] + //I-Code SLIX-S [IC id = 02 + bit36 set to 1] + //I-Code SLIX-L [IC id = 03 + bit36 set to 1] + { 0x04, 0x01, 0xFF, "IC SL2 ICS20/ICS21(SLI) ICS2002/ICS2102(SLIX)" }, + { 0x04, 0x02, 0xFF, "IC SL2 ICS53/ICS54(SLI-S) ICS5302/ICS5402(SLIX-S)" }, + { 0x04, 0x03, 0xFF, "IC SL2 ICS50/ICS51(SLI-L) ICS5002/ICS5102(SLIX-L)" }, + + // 0x05 = Infineon + { 0x05, 0xA1, 0xFF, "SRF55V01P [IC id = 161] plain mode 1kBit"}, + { 0x05, 0xA8, 0xFF, "SRF55V01P [IC id = 168] pilot series 1kBit"}, + { 0x05, 0x40, 0xFF, "SRF55V02P [IC id = 64] plain mode 2kBit"}, + { 0x05, 0x00, 0xFF, "SRF55V10P [IC id = 00] plain mode 10KBit"}, + { 0x05, 0x50, 0xFF, "SRF55V02S [IC id = 80] secure mode 2kBit"}, + { 0x05, 0x10, 0xFF, "SRF55V10S [IC id = 16] secure mode 10KBit"}, + { 0x05, 0x1E, 0xFE, "SLE66r01P [IC id = 3x = My-d Move or My-d move NFC]"}, + { 0x05, 0x20, 0xF8, "SLE66r01P [IC id = 3x = My-d Move or My-d move NFC]"}, + + // 0x07 = Texas Instruments + // XX = from bit 41 to bit 43 = product configuration - from bit 44 to bit 47 IC id (Chip ID Family) + //Tag IT RFIDType-I Plus, 2kBit, TI Inlay + //Tag-it HF-I Plus Inlay [IC id = 00] -> b'0000 000 2kBit + //Tag-it HF-I Plus Chip [IC id = 64] -> b'1000 000 2kBit + //Tag-it HF-I Standard Chip / Inlays [IC id = 96] -> b'1100 000 256Bit + //Tag-it HF-I Pro Chip / Inlays [IC id = 98] -> b'1100 010 256Bit, Password protection + { 0x07, 0x00, 0xF0, "Tag-it HF-I Plus Inlay; 64x32bit" }, + { 0x07, 0x10, 0xF0, "Tag-it HF-I Plus Chip; 64x32bit" }, + { 0x07, 0x80, 0xFE, "Tag-it HF-I Plus (RF-HDT-DVBB tag or Third Party Products)" }, + { 0x07, 0xC0, 0xFE, "Tag-it HF-I Standard; 8x32bit" }, + { 0x07, 0xC4, 0xFE, "Tag-it HF-I Pro; 8x23bit; password" }, + + + // 0x16 = EM Microelectronic-Marin SA Switzerland (Skidata) + { 0x16, 0x04, 0xFF, "EM4034 [IC id = 01] (Read/Write - no AFI)"}, + { 0x16, 0x0C, 0xFF, "EM4035 [IC id = 03] (Read/Write - replaced by 4233)"}, + { 0x16, 0x10, 0xFF, "EM4135 [IC id = 04] (Read/Write - replaced by 4233) 36x64bit start page 13"}, + { 0x16, 0x14, 0xFF, "EM4036 [IC id = 05] 28pF"}, + { 0x16, 0x18, 0xFF, "EM4006 [IC id = 06] (Read Only)"}, + { 0x16, 0x1C, 0xFF, "EM4133 [IC id = 07] 23,5pF (Read/Write)"}, + { 0x16, 0x20, 0xFF, "EM4033 [IC id = 08] 23,5pF (Read Only - no AFI / no DSFID / no security blocks)"}, + { 0x16, 0x24, 0xFF, "EM4233 [IC id = 09] 23,5pF CustomerID-102"}, + { 0x16, 0x28, 0xFF, "EM4233 SLIC [IC id = 10] 23,5pF (1Kb flash memory - not provide High Security mode and QuietStorage feature)" }, + { 0x16, 0x3C, 0xFF, "EM4237 [IC id = 15] 23,5pF"}, + { 0x16, 0x7C, 0xFF, "EM4233 [IC id = 31] 95pF"}, + { 0x16, 0x94, 0xFF, "EM4036 [IC id = 37] 95pF 51x64bit "}, + { 0x16, 0x9c, 0xFF, "EM4133 [IC id = 39] 95pF (Read/Write)" }, + { 0x16, 0xA8, 0xFF, "EM4233 SLIC [IC id = 42] 97pF" }, + { 0x16, 0xBC, 0xFF, "EM4237 [IC id = 47] 97pF" }, + + { 0x00, 0x00, 0x00, "no tag-info available" } // must be the last entry +}; + + +// get a product description based on the UID +// uid[8] tag uid +// returns description of the best match +char *getChipInfo(uint8_t vendorID, uint8_t chipID) { + int i = 0; + int best = -1; + while (chipIDmapping[i].mask > 0) { + if (vendorID == chipIDmapping[i].manufacturer + && (chipID & chipIDmapping[i].mask) == chipIDmapping[i].chipID) { + if (best == -1) { + best = i; + } else { + if (chipIDmapping[i].mask > chipIDmapping[best].mask) { + best = i; + } + } + } + i++; + } + + if (best >= 0) return chipIDmapping[best].desc; + + return chipIDmapping[i].desc; +} diff --git a/client/taginfo.h b/client/taginfo.h new file mode 100644 index 00000000..6c1d6d42 --- /dev/null +++ b/client/taginfo.h @@ -0,0 +1,13 @@ +//----------------------------------------------------------------------------- +// ISO/IEC 7816-6 manufacturer byte decoding +//----------------------------------------------------------------------------- + +#ifndef MANUFACTURERS_H__ +#define MANUFACTURERS_H__ + +#include + +extern char *getManufacturerName(uint8_t vendorID); +extern char *getChipInfo(uint8_t vendorID, uint8_t chipID); + +#endif From 189b81774036217d93272ff7e89b4c60ce7b4ef7 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Tue, 12 Mar 2019 07:46:49 +0100 Subject: [PATCH 071/189] add 14a apdu send framing (based on RRG repo PR86 by Merlokk) (#795) --- armsrc/epa.c | 2 +- armsrc/iso14443a.c | 7 +- armsrc/iso14443a.h | 2 +- client/cmdhf14a.c | 478 +++++++++++++++++++++++++---------------- client/fido/fidocore.c | 4 +- include/mifare.h | 3 +- 6 files changed, 308 insertions(+), 188 deletions(-) diff --git a/armsrc/epa.c b/armsrc/epa.c index 01aff302..0e999e1e 100644 --- a/armsrc/epa.c +++ b/armsrc/epa.c @@ -116,7 +116,7 @@ int EPA_APDU(uint8_t *apdu, size_t length, uint8_t *response) switch(iso_type) { case 'a': - return iso14_apdu(apdu, (uint16_t) length, response, NULL); + return iso14_apdu(apdu, (uint16_t) length, false, response, NULL); break; case 'b': return iso14443b_apdu(apdu, length, response); diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 2fffe837..0247820e 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -1938,13 +1938,16 @@ b8 b7 b6 b5 b4 b3 b2 b1 b5,b6 = 00 - DESELECT 11 - WTX */ -int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data, uint8_t *res) { +int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, bool send_chaining, void *data, uint8_t *res) { uint8_t parity[MAX_PARITY_SIZE]; uint8_t real_cmd[cmd_len + 4]; if (cmd_len) { // ISO 14443 APDU frame: PCB [CID] [NAD] APDU CRC PCB=0x02 real_cmd[0] = 0x02; // bnr,nad,cid,chn=0; i-block(0x00) + if (send_chaining) { + real_cmd[0] |= 0x10; + } // put block number into the PCB real_cmd[0] |= iso14_pcb_blocknum; memcpy(real_cmd + 1, cmd, cmd_len); @@ -2066,7 +2069,7 @@ void ReaderIso14443a(UsbCommand *c) if(param & ISO14A_APDU && !cantSELECT) { uint8_t res; - arg0 = iso14_apdu(cmd, len, buf, &res); + arg0 = iso14_apdu(cmd, len, (param & ISO14A_SEND_CHAINING), buf, &res); FpgaDisableTracing(); LED_B_ON(); cmd_send(CMD_ACK, arg0, res, 0, buf, sizeof(buf)); diff --git a/armsrc/iso14443a.h b/armsrc/iso14443a.h index 396b2100..6954a29b 100644 --- a/armsrc/iso14443a.h +++ b/armsrc/iso14443a.h @@ -49,7 +49,7 @@ extern int EmSendPrecompiledCmd(tag_response_info_t *response_info); extern bool prepare_allocated_tag_modulation(tag_response_info_t *response_info, uint8_t **buffer, size_t *buffer_size); extern void iso14443a_setup(uint8_t fpga_minor_mode); -extern int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data, uint8_t *res); +extern int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, bool send_chaining, void *data, uint8_t *res); extern int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *resp_data, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats); extern void iso14a_set_trigger(bool enable); extern void iso14a_set_timeout(uint32_t timeout); diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 2bf84d22..9611a2d1 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -1,6 +1,6 @@ //----------------------------------------------------------------------------- -// 2011, 2017 Merlok // Copyright (C) 2010 iZsh , Hagen Fritsch +// 2011, 2017 - 2019 Merlok // // 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 @@ -36,6 +36,10 @@ static int CmdHelp(const char *Cmd); static int waitCmd(uint8_t iLen); +// iso14a apdu input frame length +static uint16_t frameLength = 0; +uint16_t atsFSC[] = {16, 24, 32, 40, 48, 64, 96, 128, 256}; + int CmdHF14AList(const char *Cmd) { PrintAndLog("Deprecated command, use 'hf list 14a' instead"); @@ -48,11 +52,11 @@ int Hf14443_4aGetCardData(iso14a_card_select_t * card) { UsbCommand resp; WaitForResponse(CMD_ACK,&resp); - + memcpy(card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t)); - uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision - + uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision + if(select_status == 0) { PrintAndLog("E->iso14443a card select failed"); return 1; @@ -72,19 +76,19 @@ int Hf14443_4aGetCardData(iso14a_card_select_t * card) { PrintAndLog(" UID: %s", sprint_hex(card->uid, card->uidlen)); PrintAndLog("ATQA: %02x %02x", card->atqa[1], card->atqa[0]); PrintAndLog(" SAK: %02x [%" PRIu64 "]", card->sak, resp.arg[0]); - if(card->ats_len < 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes + if(card->ats_len < 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes PrintAndLog("E-> Error ATS length(%d) : %s", card->ats_len, sprint_hex(card->ats, card->ats_len)); return 1; } PrintAndLog(" ATS: %s", sprint_hex(card->ats, card->ats_len)); - + return 0; } int CmdHF14AReader(const char *Cmd) { uint32_t cm = ISO14A_CONNECT; bool leaveSignalON = false; - + CLIParserInit("hf 14a reader", "Executes ISO1443A anticollision-select group of commands.", NULL); void* argtable[] = { arg_param_begin, @@ -97,7 +101,7 @@ int CmdHF14AReader(const char *Cmd) { CLIParserFree(); return 0; } - + leaveSignalON = arg_get_lit(1); if (arg_get_lit(2)) { cm = cm - ISO14A_CONNECT; @@ -105,24 +109,24 @@ int CmdHF14AReader(const char *Cmd) { if (arg_get_lit(3)) { cm |= ISO14A_NO_RATS; } - + CLIParserFree(); - + if (leaveSignalON) - cm |= ISO14A_NO_DISCONNECT; - + cm |= ISO14A_NO_DISCONNECT; + UsbCommand c = {CMD_READER_ISO_14443a, {cm, 0, 0}}; SendCommand(&c); if (ISO14A_CONNECT & cm) { UsbCommand resp; WaitForResponse(CMD_ACK,&resp); - + iso14a_card_select_t card; memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t)); - uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision - + uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision + if(select_status == 0) { PrintAndLog("iso14443a card select failed"); return 1; @@ -137,7 +141,7 @@ int CmdHF14AReader(const char *Cmd) { PrintAndLog(" UID : %s", sprint_hex(card.uid, card.uidlen)); PrintAndLog("ATQA : %02x %02x", card.atqa[1], card.atqa[0]); PrintAndLog(" SAK : %02x [%" PRIu64 "]", card.sak, resp.arg[0]); - if(card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes + if(card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes PrintAndLog(" ATS : %s", sprint_hex(card.ats, card.ats_len)); } if (leaveSignalON) { @@ -148,7 +152,7 @@ int CmdHF14AReader(const char *Cmd) { if (!leaveSignalON) { PrintAndLog("Field dropped."); } - + return 0; } @@ -159,12 +163,12 @@ int CmdHF14AInfo(const char *Cmd) UsbCommand resp; WaitForResponse(CMD_ACK,&resp); - + iso14a_card_select_t card; memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t)); - uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision - + uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision + if(select_status == 0) { if (Cmd[0] != 's') PrintAndLog("iso14443a card select failed"); // disconnect @@ -192,7 +196,7 @@ int CmdHF14AInfo(const char *Cmd) bool isMifareClassic = true; switch (card.sak) { - case 0x00: + case 0x00: isMifareClassic = false; //***************************************test**************** @@ -201,7 +205,7 @@ int CmdHF14AInfo(const char *Cmd) c.arg[1] = 0; c.arg[2] = 0; SendCommand(&c); - + uint32_t tagT = GetHF14AMfU_Type(); ul_print_type(tagT, 0); @@ -214,11 +218,11 @@ int CmdHF14AInfo(const char *Cmd) UsbCommand resp; WaitForResponse(CMD_ACK,&resp); - + memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t)); - select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS - + select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS + if(select_status == 0) { //PrintAndLog("iso14443a card select failed"); // disconnect @@ -246,7 +250,7 @@ int CmdHF14AInfo(const char *Cmd) // UL-EV1, size, check version[6] == 0x0b (smaller) 0x0b * 4 == 48 case 0x0A:PrintAndLog("TYPE : NXP MIFARE Ultralight EV1 %d bytes", (version[6] == 0xB) ? 48 : 128);break; case 0x01:PrintAndLog("TYPE : NXP MIFARE Ultralight C");break; - case 0x00:PrintAndLog("TYPE : NXP MIFARE Ultralight");break; + case 0x00:PrintAndLog("TYPE : NXP MIFARE Ultralight");break; } */ break; @@ -281,12 +285,12 @@ int CmdHF14AInfo(const char *Cmd) memcpy(c.d.asBytes, rats, 2); SendCommand(&c); WaitForResponse(CMD_ACK,&resp); - - memcpy(card.ats, resp.d.asBytes, resp.arg[0]); - card.ats_len = resp.arg[0]; // note: ats_len includes CRC Bytes - } - if(card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes + memcpy(card.ats, resp.d.asBytes, resp.arg[0]); + card.ats_len = resp.arg[0]; // note: ats_len includes CRC Bytes + } + + if(card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes bool ta1 = 0, tb1 = 0, tc1 = 0; int pos; @@ -298,8 +302,8 @@ int CmdHF14AInfo(const char *Cmd) if (card.ats[0] != card.ats_len - 2) { PrintAndLog("ATS may be corrupted. Length of ATS (%d bytes incl. 2 Bytes CRC) doesn't match TL", card.ats_len); } - - if (card.ats[0] > 1) { // there is a format byte (T0) + + if (card.ats[0] > 1) { // there is a format byte (T0) ta1 = (card.ats[1] & 0x10) == 0x10; tb1 = (card.ats[1] & 0x20) == 0x20; tc1 = (card.ats[1] & 0x40) == 0x40; @@ -308,10 +312,7 @@ int CmdHF14AInfo(const char *Cmd) "TC1 is%s present, FSCI is %d (FSC = %ld)", (ta1 ? "" : " NOT"), (tb1 ? "" : " NOT"), (tc1 ? "" : " NOT"), fsci, - fsci < 5 ? (fsci - 2) * 8 : - fsci < 8 ? (fsci - 3) * 32 : - fsci == 8 ? 256 : - -1 + fsci < sizeof(atsFSC) ? atsFSC[fsci] : -1 ); } pos = 2; @@ -357,7 +358,7 @@ int CmdHF14AInfo(const char *Cmd) } else if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) { tip = "-> MIFARE Plus S 2K or 4K"; } - } + } PrintAndLog(" - HB : %s%s", sprint_hex(card.ats + pos, card.ats[0] - pos), tip); if (card.ats[pos] == 0xC1) { PrintAndLog(" c1 -> Mifare or (multiple) virtual cards of various type"); @@ -424,23 +425,23 @@ int CmdHF14AInfo(const char *Cmd) PrintAndLog("proprietary non iso14443-4 card found, RATS not supported"); } - + // try to see if card responses to "chinese magic backdoor" commands. (void)mfCIdentify(); - - if (isMifareClassic) { + + if (isMifareClassic) { switch(DetectClassicPrng()) { case 0: - PrintAndLog("Prng detection: HARDENED (hardnested)"); + PrintAndLog("Prng detection: HARDENED (hardnested)"); break; case 1: PrintAndLog("Prng detection: WEAK"); break; default: - PrintAndLog("Prng detection error."); + PrintAndLog("Prng detection error."); } } - + return select_status; } @@ -459,7 +460,7 @@ int CmdHF14ACUIDs(const char *Cmd) // execute anticollision procedure UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_RATS, 0, 0}}; SendCommand(&c); - + UsbCommand resp; WaitForResponse(CMD_ACK,&resp); @@ -486,10 +487,10 @@ int CmdHF14ACUIDs(const char *Cmd) int CmdHF14ASim(const char *Cmd) { UsbCommand c = {CMD_SIMULATE_TAG_ISO_14443a,{0,0,0}}; - + // Retrieve the tag type uint8_t tagtype = param_get8ex(Cmd,0,0,10); - + // When no argument was given, just print help message if (tagtype == 0) { PrintAndLog(""); @@ -500,15 +501,15 @@ int CmdHF14ASim(const char *Cmd) PrintAndLog(" 2 = MIFARE Ultralight"); PrintAndLog(" 3 = MIFARE Desfire"); PrintAndLog(" 4 = ISO/IEC 14443-4"); - PrintAndLog(" 5 = MIFARE Tnp3xxx"); + PrintAndLog(" 5 = MIFARE Tnp3xxx"); PrintAndLog(""); return 1; } - + // Store the tag type c.arg[0] = tagtype; - - // Retrieve the full 4 or 7 byte long uid + + // Retrieve the full 4 or 7 byte long uid uint64_t long_uid = param_get64ex(Cmd,1,0,16); // Are we handling the (optional) second part uid? @@ -531,7 +532,7 @@ int CmdHF14ASim(const char *Cmd) if (c.arg[1] == 0) { PrintAndLog("Emulating ISO/IEC 14443 type A tag with UID %01d %08x %08x",c.arg[0],c.arg[1],c.arg[2]); } - + switch (c.arg[0]) { case 1: { PrintAndLog("Emulating ISO/IEC 14443-3 type A tag with 4 byte UID"); @@ -547,25 +548,26 @@ int CmdHF14ASim(const char *Cmd) return 1; } break; - } + } */ /* unsigned int hi = 0, lo = 0; int n = 0, i = 0; while (sscanf(&Cmd[i++], "%1x", &n ) == 1) { - hi= (hi << 4) | (lo >> 28); - lo= (lo << 4) | (n & 0xf); + hi= (hi << 4) | (lo >> 28); + lo= (lo << 4) | (n & 0xf); } */ -// UsbCommand c = {CMD_SIMULATE_TAG_ISO_14443a,param_get32ex(Cmd,0,0,10),param_get32ex(Cmd,1,0,16),param_get32ex(Cmd,2,0,16)}; +// UsbCommand c = {CMD_SIMULATE_TAG_ISO_14443a,param_get32ex(Cmd,0,0,10),param_get32ex(Cmd,1,0,16),param_get32ex(Cmd,2,0,16)}; // PrintAndLog("Emulating ISO/IEC 14443 type A tag with UID %01d %08x %08x",c.arg[0],c.arg[1],c.arg[2]); SendCommand(&c); return 0; } + int CmdHF14ASnoop(const char *Cmd) { int param = 0; - + uint8_t ctmp = param_getchar(Cmd, 0) ; if (ctmp == 'h' || ctmp == 'H') { PrintAndLog("It get data from the field and saves it into command buffer."); @@ -575,8 +577,8 @@ int CmdHF14ASnoop(const char *Cmd) { PrintAndLog("r - triggered by first 7-bit request from reader (REQ,WUP,...)"); PrintAndLog("sample: hf 14a snoop c r"); return 0; - } - + } + for (int i = 0; i < 2; i++) { ctmp = param_getchar(Cmd, i); if (ctmp == 'c' || ctmp == 'C') param |= 0x01; @@ -588,16 +590,18 @@ int CmdHF14ASnoop(const char *Cmd) { return 0; } + void DropField() { - UsbCommand c = {CMD_READER_ISO_14443a, {0, 0, 0}}; + UsbCommand c = {CMD_READER_ISO_14443a, {0, 0, 0}}; SendCommand(&c); } + int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { static bool responseNum = false; uint16_t cmdc = 0; *dataoutlen = 0; - + if (activateField) { responseNum = false; UsbCommand resp; @@ -621,9 +625,9 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav return 1; } - if (resp.arg[0] == 2) { // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision - // get ATS - UsbCommand cr = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT, 2, 0}}; + if (resp.arg[0] == 2) { // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision + // get ATS + UsbCommand cr = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT, 2, 0}}; uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0 memcpy(cr.d.asBytes, rats, 2); SendCommand(&cr); @@ -631,52 +635,52 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav PrintAndLog("14aRAW ERROR: Proxmark connection timeout."); return 1; } - + if (resp.arg[0] <= 0) { // ats_len PrintAndLog("14aRAW ERROR: Can't get ATS."); return 1; } } } - + if (leaveSignalON) cmdc |= ISO14A_NO_DISCONNECT; - UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_APPEND_CRC | cmdc, (datainlen & 0xFFFF) + 2, 0}}; + UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_APPEND_CRC | cmdc, (datainlen & 0xFFFF) + 2, 0}}; uint8_t header[] = {0x0a | responseNum, 0x00}; responseNum ^= 1; memcpy(c.d.asBytes, header, 2); memcpy(&c.d.asBytes[2], datain, datainlen); SendCommand(&c); - - uint8_t *recv; - UsbCommand resp; - if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { - recv = resp.d.asBytes; - int iLen = resp.arg[0]; - - if(!iLen) { + uint8_t *recv; + UsbCommand resp; + + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + recv = resp.d.asBytes; + int iLen = resp.arg[0]; + + if(!iLen) { PrintAndLog("14aRAW ERROR: No card response."); - return 1; + return 1; } - + *dataoutlen = iLen - 2; if (*dataoutlen < 0) *dataoutlen = 0; - + if (maxdataoutlen && *dataoutlen > maxdataoutlen) { PrintAndLog("14aRAW ERROR: Buffer too small(%d). Needs %d bytes", *dataoutlen, maxdataoutlen); return 2; } - + if (recv[0] != header[0]) { PrintAndLog("14aRAW ERROR: iso14443-4 framing error. Card send %2x must be %2x", dataout[0], header[0]); return 2; } - + memcpy(dataout, &recv[2], *dataoutlen); - + // CRC Check if (iLen == -1) { PrintAndLog("14aRAW ERROR: ISO 14443A CRC error."); @@ -684,72 +688,140 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav } - } else { - PrintAndLog("14aRAW ERROR: Reply timeout."); + } else { + PrintAndLog("14aRAW ERROR: Reply timeout."); return 4; - } - + } + return 0; } -int CmdExchangeAPDU(uint8_t *datain, int datainlen, bool activateField, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool *chaining) { - uint16_t cmdc = 0; - *chaining = false; - - if (activateField) { - cmdc |= ISO14A_CONNECT | ISO14A_CLEAR_TRACE; +static int SelectCard14443_4(bool disconnect, iso14a_card_select_t *card) { + UsbCommand resp; + + frameLength = 0; + + if (card) + memset(card, 0, sizeof(iso14a_card_select_t)); + + DropField(); + + // Anticollision + SELECT card + UsbCommand ca = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0}}; + SendCommand(&ca); + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + PrintAndLogEx(ERR, "Proxmark connection timeout."); + return 1; } + // check result + if (resp.arg[0] == 0) { + PrintAndLogEx(ERR, "No card in field."); + return 1; + } + + if (resp.arg[0] != 1 && resp.arg[0] != 2) { + PrintAndLogEx(ERR, "Card not in iso14443-4. res=%d.", resp.arg[0]); + return 1; + } + + if (resp.arg[0] == 2) { // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision + // try to get ATS although SAK indicated that it is not ISO14443-4 compliant + UsbCommand cr = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT, 2, 0}}; + uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0 + memcpy(cr.d.asBytes, rats, 2); + SendCommand(&cr); + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + PrintAndLogEx(ERR, "Proxmark connection timeout."); + return 1; + } + + if (resp.arg[0] <= 0) { // ats_len + PrintAndLogEx(ERR, "Can't get ATS."); + return 1; + } + } + + // get frame length from ATS + iso14a_card_select_t *vcard = (iso14a_card_select_t *) resp.d.asBytes; + if (vcard->ats_len > 1) { + uint8_t fsci = vcard->ats[1] & 0x0f; + if (fsci < sizeof(atsFSC)) + frameLength = atsFSC[fsci]; + } + + if (card) { + memcpy(card, vcard, sizeof(iso14a_card_select_t)); + } + + if (disconnect) { + DropField(); + } + + return 0; +} + + +static int ExchangeAPDU(bool chainingin, uint8_t *datain, int datainlen, bool activateField, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool *chainingout) +{ + *chainingout = false; + + if (activateField) { + // select with no disconnect and set frameLength + int selres = SelectCard14443_4(false, NULL); + if (selres) + return selres; + } + + uint16_t cmdc = 0; + if (chainingin) + cmdc = ISO14A_SEND_CHAINING; + // "Command APDU" length should be 5+255+1, but javacard's APDU buffer might be smaller - 133 bytes // https://stackoverflow.com/questions/32994936/safe-max-java-card-apdu-data-command-and-respond-size // here length USB_CMD_DATA_SIZE=512 // timeout must be authomatically set by "get ATS" - UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_APDU | ISO14A_NO_DISCONNECT | cmdc, (datainlen & 0xFFFF), 0}}; + UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_APDU | ISO14A_NO_DISCONNECT | cmdc, (datainlen & 0xFFFF), 0}}; memcpy(c.d.asBytes, datain, datainlen); SendCommand(&c); - - uint8_t *recv; - UsbCommand resp; - if (activateField) { - if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { - PrintAndLog("APDU ERROR: Proxmark connection timeout."); - return 1; - } - if (resp.arg[0] != 1) { - PrintAndLog("APDU ERROR: Proxmark error %d.", resp.arg[0]); - DropField(); - return 1; - } - } + uint8_t *recv; + UsbCommand resp; - if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { - recv = resp.d.asBytes; - int iLen = resp.arg[0]; + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + recv = resp.d.asBytes; + int iLen = resp.arg[0]; uint8_t res = resp.arg[1]; - + int dlen = iLen - 2; if (dlen < 0) dlen = 0; *dataoutlen += dlen; - + if (maxdataoutlen && *dataoutlen > maxdataoutlen) { PrintAndLog("APDU ERROR: Buffer too small(%d). Needs %d bytes", *dataoutlen, maxdataoutlen); return 2; } - - if(!iLen) { + + // I-block ACK + if ((res & 0xf2) == 0xa2) { + *dataoutlen = 0; + *chainingout = true; + return 0; + } + + if(!iLen) { PrintAndLog("APDU ERROR: No APDU response."); - return 1; + return 1; } // check apdu length - if (iLen < 4 && iLen >= 0) { + if (iLen < 2 && iLen >= 0) { PrintAndLog("APDU ERROR: Small APDU response. Len=%d", iLen); return 2; } - + // check block TODO if (iLen == -2) { PrintAndLog("APDU ERROR: Block type mismatch."); @@ -757,21 +829,21 @@ int CmdExchangeAPDU(uint8_t *datain, int datainlen, bool activateField, uint8_t } memcpy(dataout, recv, dlen); - + // chaining if ((res & 0x10) != 0) { - *chaining = true; + *chainingout = true; } - + // CRC Check if (iLen == -1) { PrintAndLog("APDU ERROR: ISO 14443A CRC error."); return 3; } - } else { - PrintAndLog("APDU ERROR: Reply timeout."); + } else { + PrintAndLog("APDU ERROR: Reply timeout."); return 4; - } + } return 0; } @@ -780,24 +852,68 @@ int CmdExchangeAPDU(uint8_t *datain, int datainlen, bool activateField, uint8_t int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { *dataoutlen = 0; bool chaining = false; - - int res = CmdExchangeAPDU(datain, datainlen, activateField, dataout, maxdataoutlen, dataoutlen, &chaining); + int res; - while (chaining) { - // I-block with chaining - res = CmdExchangeAPDU(NULL, 0, false, &dataout[*dataoutlen], maxdataoutlen, dataoutlen, &chaining); - + // 3 byte here - 1b framing header, 2b crc16 + if ( (frameLength && (datainlen > frameLength - 3)) || (datainlen > USB_CMD_DATA_SIZE - 3) ) { + int clen = 0; + + bool vActivateField = activateField; + + do { + int vlen = MIN(frameLength - 3, datainlen - clen); + bool chainBlockNotLast = ((clen + vlen) < datainlen); + + *dataoutlen = 0; + res = ExchangeAPDU(chainBlockNotLast, &datain[clen], vlen, vActivateField, dataout, maxdataoutlen, dataoutlen, &chaining); + if (res) { + if (!leaveSignalON) + DropField(); + + return 200; + } + + // check R-block ACK + if ((*dataoutlen == 0) && (*dataoutlen != 0 || chaining != chainBlockNotLast)) { + if (!leaveSignalON) + DropField(); + + return 201; + } + + clen += vlen; + vActivateField = false; + if (*dataoutlen) { + if (clen != datainlen) + PrintAndLogEx(WARNING, "APDU: I-block/R-block sequence error. Data len=%d, Sent=%d, Last packet len=%d", datainlen, clen, *dataoutlen); + break; + } + } while (clen < datainlen); + } else { + res = ExchangeAPDU(false, datain, datainlen, activateField, dataout, maxdataoutlen, dataoutlen, &chaining); if (res) { if (!leaveSignalON) DropField(); - + + return res; + } + } + + while (chaining) { + // I-block with chaining + res = ExchangeAPDU(false, NULL, 0, false, &dataout[*dataoutlen], maxdataoutlen, dataoutlen, &chaining); + + if (res) { + if (!leaveSignalON) + DropField(); + return 100; } - } - + } + if (!leaveSignalON) DropField(); - + return 0; } @@ -809,8 +925,8 @@ int CmdHF14AAPDU(const char *cmd) { bool leaveSignalON = false; bool decodeTLV = false; - CLIParserInit("hf 14a apdu", - "Sends an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol (T=CL)", + CLIParserInit("hf 14a apdu", + "Sends an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol (T=CL)", "Sample:\n\thf 14a apdu -st 00A404000E325041592E5359532E444446303100\n"); void* argtable[] = { @@ -822,7 +938,7 @@ int CmdHF14AAPDU(const char *cmd) { arg_param_end }; CLIExecWithReturn(cmd, argtable, false); - + activateField = arg_get_lit(1); leaveSignalON = arg_get_lit(2); decodeTLV = arg_get_lit(3); @@ -831,23 +947,23 @@ int CmdHF14AAPDU(const char *cmd) { CLIParserFree(); -// PrintAndLog("---str [%d] %s", arg_get_str(4)->count, arg_get_str(4)->sval[0]); +// PrintAndLog("---str [%d] %s", arg_get_str(4)->count, arg_get_str(4)->sval[0]); PrintAndLog(">>>>[%s%s%s] %s", activateField ? "sel ": "", leaveSignalON ? "keep ": "", decodeTLV ? "TLV": "", sprint_hex(data, datalen)); - + int res = ExchangeAPDU14a(data, datalen, activateField, leaveSignalON, data, USB_CMD_DATA_SIZE, &datalen); if (res) return res; PrintAndLog("<<<< %s", sprint_hex(data, datalen)); - - PrintAndLog("APDU response: %02x %02x - %s", data[datalen - 2], data[datalen - 1], GetAPDUCodeDescription(data[datalen - 2], data[datalen - 1])); + + PrintAndLog("APDU response: %02x %02x - %s", data[datalen - 2], data[datalen - 1], GetAPDUCodeDescription(data[datalen - 2], data[datalen - 1])); // TLV decoder if (decodeTLV && datalen > 4) { TLVPrintFromBuffer(data, datalen - 2); } - + return 0; } @@ -867,7 +983,7 @@ int CmdHF14ACmdRaw(const char *cmd) { int datalen = 0; // extract parameters - CLIParserInit("hf 14a raw", "Send raw hex data to tag", + CLIParserInit("hf 14a raw", "Send raw hex data to tag", "Sample:\n"\ "\thf 14a raw -pa -b7 -t1000 52 -- execute WUPA\n"\ "\thf 14a raw -p 9320 -- anticollision\n"\ @@ -889,12 +1005,12 @@ int CmdHF14ACmdRaw(const char *cmd) { // defaults arg_get_int(6) = 0; arg_get_int(7) = 0; - + if (CLIParserParseString(cmd, argtable, arg_getsize(argtable), false)){ CLIParserFree(); return 0; } - + reply = !arg_get_lit(1); crc = arg_get_lit(2); power = arg_get_lit(3); @@ -902,7 +1018,7 @@ int CmdHF14ACmdRaw(const char *cmd) { active_select = arg_get_lit(5); numbits = arg_get_int(6) & 0xFFFF; timeout = arg_get_int(7); - bTimeout = (timeout > 0); + bTimeout = (timeout > 0); topazmode = arg_get_lit(8); no_rats = arg_get_lit(9); // len = data + CRC(2b) @@ -910,10 +1026,10 @@ int CmdHF14ACmdRaw(const char *cmd) { CLIParserFree(); return 1; } - - CLIParserFree(); - - // logic + + CLIParserFree(); + + // logic if(crc && datalen>0 && datalen MAX_TIMEOUT) { timeout = MAX_TIMEOUT; @@ -977,13 +1093,13 @@ int CmdHF14ACmdRaw(const char *cmd) { static int waitCmd(uint8_t iSelect) { - uint8_t *recv; - UsbCommand resp; - char *hexout; + uint8_t *recv; + UsbCommand resp; + char *hexout; - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - recv = resp.d.asBytes; - uint8_t iLen = resp.arg[0]; + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + recv = resp.d.asBytes; + uint8_t iLen = resp.arg[0]; if (iSelect){ iLen = resp.arg[1]; if (iLen){ @@ -994,38 +1110,38 @@ static int waitCmd(uint8_t iSelect) { } else { PrintAndLog("received %i bytes:", iLen); } - if(!iLen) - return 1; - hexout = (char *)malloc(iLen * 3 + 1); - if (hexout != NULL) { - for (int i = 0; i < iLen; i++) { // data in hex - sprintf(&hexout[i * 3], "%02X ", recv[i]); - } - PrintAndLog("%s", hexout); - free(hexout); - } else { - PrintAndLog("malloc failed your client has low memory?"); + if(!iLen) + return 1; + hexout = (char *)malloc(iLen * 3 + 1); + if (hexout != NULL) { + for (int i = 0; i < iLen; i++) { // data in hex + sprintf(&hexout[i * 3], "%02X ", recv[i]); + } + PrintAndLog("%s", hexout); + free(hexout); + } else { + PrintAndLog("malloc failed your client has low memory?"); return 2; - } - } else { - PrintAndLog("timeout while waiting for reply."); + } + } else { + PrintAndLog("timeout while waiting for reply."); return 3; - } + } return 0; } -static command_t CommandTable[] = +static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help"}, - {"list", CmdHF14AList, 0, "[Deprecated] List ISO 14443a history"}, - {"reader", CmdHF14AReader, 0, "Start acting like an ISO14443 Type A reader"}, - {"info", CmdHF14AInfo, 0, "Reads card and shows information about it"}, - {"cuids", CmdHF14ACUIDs, 0, " Collect n>0 ISO14443 Type A UIDs in one go"}, - {"sim", CmdHF14ASim, 0, " -- Simulate ISO 14443a tag"}, - {"snoop", CmdHF14ASnoop, 0, "Eavesdrop ISO 14443 Type A"}, - {"apdu", CmdHF14AAPDU, 0, "Send an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol"}, - {"raw", CmdHF14ACmdRaw, 0, "Send raw hex data to tag"}, - {NULL, NULL, 0, NULL} + {"help", CmdHelp, 1, "This help"}, + {"list", CmdHF14AList, 0, "[Deprecated] List ISO 14443a history"}, + {"reader", CmdHF14AReader, 0, "Start acting like an ISO14443 Type A reader"}, + {"info", CmdHF14AInfo, 0, "Reads card and shows information about it"}, + {"cuids", CmdHF14ACUIDs, 0, " Collect n>0 ISO14443 Type A UIDs in one go"}, + {"sim", CmdHF14ASim, 0, " -- Simulate ISO 14443a tag"}, + {"snoop", CmdHF14ASnoop, 0, "Eavesdrop ISO 14443 Type A"}, + {"apdu", CmdHF14AAPDU, 0, "Send an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol"}, + {"raw", CmdHF14ACmdRaw, 0, "Send raw hex data to tag"}, + {NULL, NULL, 0, NULL} }; int CmdHF14A(const char *Cmd) { diff --git a/client/fido/fidocore.c b/client/fido/fidocore.c index 13768b75..6e021ea6 100644 --- a/client/fido/fidocore.c +++ b/client/fido/fidocore.c @@ -267,9 +267,9 @@ int FIDOCheckDERAndGetKey(uint8_t *der, size_t derLen, bool verbose, uint8_t *pu uint32_t verifyflags = 0; res = mbedtls_x509_crt_verify(&cert, &cacert, NULL, NULL, &verifyflags, NULL, NULL); if (res) { - PrintAndLog("ERROR: DER verify returned 0x%x - %s", (res<0)?-res:res, ecdsa_get_error(res)); + PrintAndLog("ERROR: DER verify returned 0x%x - %s\n", (res<0)?-res:res, ecdsa_get_error(res)); } else { - PrintAndLog("Certificate OK."); + PrintAndLog("Certificate OK.\n"); } if (verbose) { diff --git a/include/mifare.h b/include/mifare.h index b821f32b..bb07adcd 100644 --- a/include/mifare.h +++ b/include/mifare.h @@ -36,7 +36,8 @@ typedef enum ISO14A_COMMAND { ISO14A_NO_SELECT = (1 << 7), ISO14A_TOPAZMODE = (1 << 8), ISO14A_NO_RATS = (1 << 9), - ISO14A_CLEAR_TRACE = (1 << 10) + ISO14A_SEND_CHAINING = (1 << 10), + ISO14A_CLEAR_TRACE = (1 << 11) } iso14a_command_t; typedef struct { From 1523527f94c4c294d0c04d0fd3396ce7eda095e4 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Tue, 12 Mar 2019 07:49:23 +0100 Subject: [PATCH 072/189] fix LED signalling in hf 15 snoop and hf 14a snoop (#797) * LED_A (yellow): PM3 is active (snooping) * LED_B (green): reader is sending a command * LED_C (red): tag is sending a reply --- armsrc/iso14443a.c | 54 ++++++++++++++++++++-------------------------- armsrc/iso15693.c | 4 +--- 2 files changed, 24 insertions(+), 34 deletions(-) diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 0247820e..d3d0138b 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -319,15 +319,18 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) Uart.startTime -= Uart.syncBit; Uart.endTime = Uart.startTime; Uart.state = STATE_START_OF_COMMUNICATION; + LED_B_ON(); } } else { if (IsMillerModulationNibble1(Uart.fourBits >> Uart.syncBit)) { if (IsMillerModulationNibble2(Uart.fourBits >> Uart.syncBit)) { // Modulation in both halves - error + LED_B_OFF(); UartReset(); } else { // Modulation in first half = Sequence Z = logic "0" if (Uart.state == STATE_MILLER_X) { // error - must not follow after X + LED_B_OFF(); UartReset(); } else { Uart.bitCount++; @@ -366,6 +369,7 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) } } else { // no modulation in both halves - Sequence Y if (Uart.state == STATE_MILLER_Z || Uart.state == STATE_MILLER_Y) { // Y after logic "0" - End of Communication + LED_B_OFF(); Uart.state = STATE_UNSYNCD; Uart.bitCount--; // last "0" was part of EOC sequence Uart.shiftReg <<= 1; // drop it @@ -387,6 +391,7 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) } } if (Uart.state == STATE_START_OF_COMMUNICATION) { // error - must not follow directly after SOC + LED_B_OFF(); UartReset(); } else { // a logic "0" Uart.bitCount++; @@ -492,6 +497,7 @@ static RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non Demod.startTime -= Demod.syncBit; Demod.bitCount = offset; // number of decoded data bits Demod.state = DEMOD_MANCHESTER_DATA; + LED_C_ON(); } } @@ -534,6 +540,7 @@ static RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non } Demod.endTime = Demod.startTime + 8*(9*Demod.len + Demod.bitCount + 1); } else { // no modulation in both halves - End of communication + LED_C_OFF(); if(Demod.bitCount > 0) { // there are some remaining data bits Demod.shiftReg >>= (9 - Demod.bitCount); // right align the decoded bits Demod.output[Demod.len++] = Demod.shiftReg & 0xff; // and add them to the output @@ -574,6 +581,7 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { // bit 1 - trigger from first reader 7-bit request LEDsoff(); + LED_A_ON(); iso14443a_setup(FPGA_HF_ISO14443A_SNIFFER); @@ -626,7 +634,6 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { break; } - LED_A_ON(); WDT_HIT(); int register readBufDataP = data - dmaBuf; @@ -658,18 +665,15 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; } - LED_A_OFF(); - if (rsamples & 0x01) { // Need two samples to feed Miller and Manchester-Decoder if(!TagIsActive) { // no need to try decoding reader data if the tag is sending uint8_t readerdata = (previous_data & 0xF0) | (*data >> 4); if (MillerDecoding(readerdata, (rsamples-1)*4)) { - LED_C_ON(); - // check - if there is a short 7bit request from reader - if ((!triggered) && (param & 0x02) && (Uart.len == 1) && (Uart.bitCount == 7)) triggered = true; - + if ((!triggered) && (param & 0x02) && (Uart.len == 1) && (Uart.bitCount == 7)) { + triggered = true; + } if(triggered) { if (!LogTrace(receivedCmd, Uart.len, @@ -683,31 +687,24 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { /* And also reset the demod code, which might have been */ /* false-triggered by the commands from the reader. */ DemodReset(); - LED_B_OFF(); } ReaderIsActive = (Uart.state != STATE_UNSYNCD); } - if(!ReaderIsActive) { // no need to try decoding tag data if the reader is sending - and we cannot afford the time + if (!ReaderIsActive) { // no need to try decoding tag data if the reader is sending - and we cannot afford the time uint8_t tagdata = (previous_data << 4) | (*data & 0x0F); - if(ManchesterDecoding(tagdata, 0, (rsamples-1)*4)) { - LED_B_ON(); - + if (ManchesterDecoding(tagdata, 0, (rsamples-1)*4)) { if (!LogTrace(receivedResponse, Demod.len, Demod.startTime*16 - DELAY_TAG_AIR2ARM_AS_SNIFFER, Demod.endTime*16 - DELAY_TAG_AIR2ARM_AS_SNIFFER, Demod.parity, false)) break; - if ((!triggered) && (param & 0x01)) triggered = true; - // And ready to receive another response. DemodReset(); // And reset the Miller decoder including itS (now outdated) input buffer UartInit(receivedCmd, receivedCmdPar); - - LED_C_OFF(); } TagIsActive = (Demod.state != DEMOD_UNSYNCD); } @@ -721,12 +718,12 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { } } // main cycle - DbpString("COMMAND FINISHED"); - FpgaDisableSscDma(); + LEDsoff(); + + DbpString("COMMAND FINISHED"); Dbprintf("maxDataLen=%d, Uart.state=%x, Uart.len=%d", maxDataLen, Uart.state, Uart.len); Dbprintf("traceLen=%d, Uart.output[0]=%08x", BigBuf_get_traceLen(), (uint32_t)Uart.output[0]); - LEDsoff(); } //----------------------------------------------------------------------------- @@ -1267,7 +1264,7 @@ static void PrepareDelayedTransfer(uint16_t delay) //------------------------------------------------------------------------------------- static void TransmitFor14443a(const uint8_t *cmd, uint16_t len, uint32_t *timing) { - + LED_D_ON(); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); uint32_t ThisTransferTime = 0; @@ -1471,6 +1468,7 @@ static int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen) bool correctionNeeded; // Modulate Manchester + LED_D_OFF(); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_MOD); // include correction bit if necessary @@ -2459,6 +2457,8 @@ void RAMFUNC SniffMifare(uint8_t param) { // C(red) A(yellow) B(green) LEDsoff(); + LED_A_ON(); + // init trace buffer clear_trace(); set_tracing(true); @@ -2494,8 +2494,6 @@ void RAMFUNC SniffMifare(uint8_t param) { // Setup for the DMA. FpgaSetupSscDma((uint8_t *)dmaBuf, DMA_BUFFER_SIZE); // set transfer address and number of bytes. Start transfer. - LED_D_OFF(); - // init sniffer MfSniffInit(); @@ -2507,7 +2505,6 @@ void RAMFUNC SniffMifare(uint8_t param) { break; } - LED_A_ON(); WDT_HIT(); if ((sniffCounter & 0x0000FFFF) == 0) { // from time to time @@ -2553,15 +2550,11 @@ void RAMFUNC SniffMifare(uint8_t param) { AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; } - LED_A_OFF(); - if (sniffCounter & 0x01) { if(!TagIsActive) { // no need to try decoding tag data if the reader is sending uint8_t readerdata = (previous_data & 0xF0) | (*data >> 4); if(MillerDecoding(readerdata, (sniffCounter-1)*4)) { - LED_B_ON(); - LED_C_OFF(); if (MfSniffLogic(receivedCmd, Uart.len, Uart.parity, Uart.bitCount, true)) break; @@ -2577,8 +2570,6 @@ void RAMFUNC SniffMifare(uint8_t param) { if(!ReaderIsActive) { // no need to try decoding tag data if the reader is sending uint8_t tagdata = (previous_data << 4) | (*data & 0x0F); if(ManchesterDecoding(tagdata, 0, (sniffCounter-1)*4)) { - LED_B_OFF(); - LED_C_ON(); if (MfSniffLogic(receivedResponse, Demod.len, Demod.parity, Demod.bitCount, false)) break; @@ -2600,12 +2591,13 @@ void RAMFUNC SniffMifare(uint8_t param) { } // main cycle + FpgaDisableSscDma(); + LEDsoff(); + DbpString("COMMAND FINISHED."); - FpgaDisableSscDma(); FpgaDisableTracing(); MfSniffEnd(); Dbprintf("maxDataLen=%x, Uart.state=%x, Uart.len=%x", maxDataLen, Uart.state, Uart.len); - LEDsoff(); } diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 13b8a174..d988e2b9 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -1040,6 +1040,7 @@ void AcquireRawAdcSamplesIso15693(void) void SnoopIso15693(void) { + LED_A_ON(); FpgaDownloadAndGo(FPGA_BITSTREAM_HF); BigBuf_free(); @@ -1073,9 +1074,6 @@ void SnoopIso15693(void) } Dbprintf("Snoop started. Press button to stop."); - // Signal field is off, no reader signal, no tag signal - LEDsoff(); - // And put the FPGA in the appropriate mode FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_SNOOP | FPGA_HF_READER_RX_XCORR_AMPLITUDE); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); From 5866c187ef916dd683eacbe4698914c6a1394589 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Wed, 13 Mar 2019 10:53:40 +0100 Subject: [PATCH 073/189] fix hitag functions (issue #798) (#800) * ... and whitespace formating --- armsrc/apps.h | 12 -- armsrc/hitag2.c | 430 +++++++++++++++++++++++--------------------- armsrc/hitag2.h | 24 +++ armsrc/hitagS.c | 315 +++++++++++++++++--------------- armsrc/hitagS.h | 26 +++ client/cmdlfhitag.c | 3 +- include/hitag.h | 93 ++++++++++ include/hitag2.h | 55 ------ include/hitagS.h | 51 ------ 9 files changed, 532 insertions(+), 477 deletions(-) create mode 100644 armsrc/hitag2.h create mode 100644 armsrc/hitagS.h create mode 100644 include/hitag.h delete mode 100644 include/hitag2.h delete mode 100644 include/hitagS.h diff --git a/armsrc/apps.h b/armsrc/apps.h index aaa128ab..5b8516eb 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -161,18 +161,6 @@ void iClass_Dump(uint8_t blockno, uint8_t numblks); void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data); void iClass_ReadCheck(uint8_t blockNo, uint8_t keyType); -// hitag2.h -void SnoopHitag(uint32_t type); -void SimulateHitagTag(bool tag_mem_supplied, byte_t* data); -void ReaderHitag(hitag_function htf, hitag_data* htd); -void WriterHitag(hitag_function htf, hitag_data* htd, int page); - -//hitagS.h -void ReadHitagSCmd(hitag_function htf, hitag_data* htd, uint64_t startPage, uint64_t tagMode, bool readBlock); -void SimulateHitagSTag(bool tag_mem_supplied, byte_t* data); -void WritePageHitagS(hitag_function htf, hitag_data* htd,int page); -void check_challenges_cmd(bool file_given, byte_t* data, uint64_t tagMode); - // cmd.h bool cmd_receive(UsbCommand* cmd); bool cmd_send(uint32_t cmd, uint32_t arg0, uint32_t arg1, uint32_t arg2, void* data, size_t len); diff --git a/armsrc/hitag2.c b/armsrc/hitag2.c index 0fd8d745..270958ce 100644 --- a/armsrc/hitag2.c +++ b/armsrc/hitag2.c @@ -16,10 +16,12 @@ // (c) 2012 Roel Verdult //----------------------------------------------------------------------------- +#include "hitag2.h" + #include "proxmark3.h" #include "apps.h" #include "util.h" -#include "hitag2.h" +#include "hitag.h" #include "string.h" #include "BigBuf.h" #include "fpgaloader.h" @@ -48,21 +50,21 @@ struct hitag2_tag { }; static struct hitag2_tag tag = { - .state = TAG_STATE_RESET, - .sectors = { // Password mode: | Crypto mode: - [0] = { 0x02, 0x4e, 0x02, 0x20}, // UID | UID - [1] = { 0x4d, 0x49, 0x4b, 0x52}, // Password RWD | 32 bit LSB key - [2] = { 0x20, 0xf0, 0x4f, 0x4e}, // Reserved | 16 bit MSB key, 16 bit reserved - [3] = { 0x0e, 0xaa, 0x48, 0x54}, // Configuration, password TAG | Configuration, password TAG - [4] = { 0x46, 0x5f, 0x4f, 0x4b}, // Data: F_OK - [5] = { 0x55, 0x55, 0x55, 0x55}, // Data: UUUU - [6] = { 0xaa, 0xaa, 0xaa, 0xaa}, // Data: .... - [7] = { 0x55, 0x55, 0x55, 0x55}, // Data: UUUU - [8] = { 0x00, 0x00, 0x00, 0x00}, // RSK Low - [9] = { 0x00, 0x00, 0x00, 0x00}, // RSK High - [10] = { 0x00, 0x00, 0x00, 0x00}, // RCF - [11] = { 0x00, 0x00, 0x00, 0x00}, // SYNC - }, + .state = TAG_STATE_RESET, + .sectors = { // Password mode: | Crypto mode: + [0] = { 0x02, 0x4e, 0x02, 0x20}, // UID | UID + [1] = { 0x4d, 0x49, 0x4b, 0x52}, // Password RWD | 32 bit LSB key + [2] = { 0x20, 0xf0, 0x4f, 0x4e}, // Reserved | 16 bit MSB key, 16 bit reserved + [3] = { 0x0e, 0xaa, 0x48, 0x54}, // Configuration, password TAG | Configuration, password TAG + [4] = { 0x46, 0x5f, 0x4f, 0x4b}, // Data: F_OK + [5] = { 0x55, 0x55, 0x55, 0x55}, // Data: UUUU + [6] = { 0xaa, 0xaa, 0xaa, 0xaa}, // Data: .... + [7] = { 0x55, 0x55, 0x55, 0x55}, // Data: UUUU + [8] = { 0x00, 0x00, 0x00, 0x00}, // RSK Low + [9] = { 0x00, 0x00, 0x00, 0x00}, // RSK High + [10] = { 0x00, 0x00, 0x00, 0x00}, // RCF + [11] = { 0x00, 0x00, 0x00, 0x00}, // SYNC + }, }; static enum { @@ -70,9 +72,9 @@ static enum { WRITE_STATE_PAGENUM_WRITTEN, WRITE_STATE_PROG } writestate; - -// ToDo: define a meaningful maximum size for auth_table. The bigger this is, the lower will be the available memory for traces. + +// ToDo: define a meaningful maximum size for auth_table. The bigger this is, the lower will be the available memory for traces. // Historically it used to be FREE_BUFFER_SIZE, which was 2744. #define AUTH_TABLE_LENGTH 2744 static byte_t* auth_table; @@ -93,30 +95,30 @@ static uint64_t cipher_state; // Basic macros: -#define u8 uint8_t -#define u32 uint32_t -#define u64 uint64_t -#define rev8(x) ((((x)>>7)&1)+((((x)>>6)&1)<<1)+((((x)>>5)&1)<<2)+((((x)>>4)&1)<<3)+((((x)>>3)&1)<<4)+((((x)>>2)&1)<<5)+((((x)>>1)&1)<<6)+(((x)&1)<<7)) -#define rev16(x) (rev8 (x)+(rev8 (x>> 8)<< 8)) -#define rev32(x) (rev16(x)+(rev16(x>>16)<<16)) -#define rev64(x) (rev32(x)+(rev32(x>>32)<<32)) -#define bit(x,n) (((x)>>(n))&1) -#define bit32(x,n) ((((x)[(n)>>5])>>((n)))&1) -#define inv32(x,i,n) ((x)[(i)>>5]^=((u32)(n))<<((i)&31)) -#define rotl64(x, n) ((((u64)(x))<<((n)&63))+(((u64)(x))>>((0-(n))&63))) +#define u8 uint8_t +#define u32 uint32_t +#define u64 uint64_t +#define rev8(x) ((((x)>>7)&1)+((((x)>>6)&1)<<1)+((((x)>>5)&1)<<2)+((((x)>>4)&1)<<3)+((((x)>>3)&1)<<4)+((((x)>>2)&1)<<5)+((((x)>>1)&1)<<6)+(((x)&1)<<7)) +#define rev16(x) (rev8 (x)+(rev8 (x>> 8)<< 8)) +#define rev32(x) (rev16(x)+(rev16(x>>16)<<16)) +#define rev64(x) (rev32(x)+(rev32(x>>32)<<32)) +#define bit(x,n) (((x)>>(n))&1) +#define bit32(x,n) ((((x)[(n)>>5])>>((n)))&1) +#define inv32(x,i,n) ((x)[(i)>>5]^=((u32)(n))<<((i)&31)) +#define rotl64(x, n) ((((u64)(x))<<((n)&63))+(((u64)(x))>>((0-(n))&63))) // Single bit Hitag2 functions: -#define i4(x,a,b,c,d) ((u32)((((x)>>(a))&1)+(((x)>>(b))&1)*2+(((x)>>(c))&1)*4+(((x)>>(d))&1)*8)) +#define i4(x,a,b,c,d) ((u32)((((x)>>(a))&1)+(((x)>>(b))&1)*2+(((x)>>(c))&1)*4+(((x)>>(d))&1)*8)) -static const u32 ht2_f4a = 0x2C79; // 0010 1100 0111 1001 -static const u32 ht2_f4b = 0x6671; // 0110 0110 0111 0001 -static const u32 ht2_f5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011 +static const u32 ht2_f4a = 0x2C79; // 0010 1100 0111 1001 +static const u32 ht2_f4b = 0x6671; // 0110 0110 0111 0001 +static const u32 ht2_f5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011 static u32 _f20 (const u64 x) { - u32 i5; - + u32 i5; + i5 = ((ht2_f4a >> i4 (x, 1, 2, 4, 5)) & 1)* 1 + ((ht2_f4b >> i4 (x, 7,11,13,14)) & 1)* 2 + ((ht2_f4b >> i4 (x,16,20,22,25)) & 1)* 4 @@ -128,8 +130,8 @@ static u32 _f20 (const u64 x) static u64 _hitag2_init (const u64 key, const u32 serial, const u32 IV) { - u32 i; - u64 x = ((key & 0xFFFF) << 32) + serial; + u32 i; + u64 x = ((key & 0xFFFF) << 32) + serial; for (i = 0; i < 32; i++) { @@ -141,7 +143,7 @@ static u64 _hitag2_init (const u64 key, const u32 serial, const u32 IV) static u64 _hitag2_round (u64 *state) { - u64 x = *state; + u64 x = *state; x = (x >> 1) + ((((x >> 0) ^ (x >> 2) ^ (x >> 3) ^ (x >> 6) @@ -155,7 +157,7 @@ static u64 _hitag2_round (u64 *state) static u32 _hitag2_byte (u64 * x) { - u32 i, c; + u32 i, c; for (i = 0, c = 0; i < 8; i++) c += (u32) _hitag2_round (x) << (i^7); return c; @@ -170,7 +172,7 @@ static int hitag2_reset(void) static int hitag2_init(void) { -// memcpy(&tag, &resetdata, sizeof(tag)); +// memcpy(&tag, &resetdata, sizeof(tag)); hitag2_reset(); return 0; } @@ -218,40 +220,40 @@ static int hitag2_cipher_transcrypt(uint64_t* cs, byte_t *data, unsigned int byt // T0 = TIMER_CLOCK1 / 125000 = 192 #define T0 192 -#define SHORT_COIL() LOW(GPIO_SSC_DOUT) -#define OPEN_COIL() HIGH(GPIO_SSC_DOUT) +#define SHORT_COIL() LOW(GPIO_SSC_DOUT) +#define OPEN_COIL() HIGH(GPIO_SSC_DOUT) #define HITAG_FRAME_LEN 20 #define HITAG_T_STOP 36 /* T_EOF should be > 36 */ -#define HITAG_T_LOW 8 /* T_LOW should be 4..10 */ +#define HITAG_T_LOW 8 /* T_LOW should be 4..10 */ #define HITAG_T_0_MIN 15 /* T[0] should be 18..22 */ #define HITAG_T_1_MIN 25 /* T[1] should be 26..30 */ //#define HITAG_T_EOF 40 /* T_EOF should be > 36 */ -#define HITAG_T_EOF 80 /* T_EOF should be > 36 */ +#define HITAG_T_EOF 80 /* T_EOF should be > 36 */ #define HITAG_T_WAIT_1 200 /* T_wresp should be 199..206 */ #define HITAG_T_WAIT_2 90 /* T_wresp should be 199..206 */ #define HITAG_T_WAIT_MAX 300 /* bit more than HITAG_T_WAIT_1 + HITAG_T_WAIT_2 */ #define HITAG_T_PROG 614 -#define HITAG_T_TAG_ONE_HALF_PERIOD 10 -#define HITAG_T_TAG_TWO_HALF_PERIOD 25 -#define HITAG_T_TAG_THREE_HALF_PERIOD 41 -#define HITAG_T_TAG_FOUR_HALF_PERIOD 57 +#define HITAG_T_TAG_ONE_HALF_PERIOD 10 +#define HITAG_T_TAG_TWO_HALF_PERIOD 25 +#define HITAG_T_TAG_THREE_HALF_PERIOD 41 +#define HITAG_T_TAG_FOUR_HALF_PERIOD 57 -#define HITAG_T_TAG_HALF_PERIOD 16 -#define HITAG_T_TAG_FULL_PERIOD 32 +#define HITAG_T_TAG_HALF_PERIOD 16 +#define HITAG_T_TAG_FULL_PERIOD 32 -#define HITAG_T_TAG_CAPTURE_ONE_HALF 13 -#define HITAG_T_TAG_CAPTURE_TWO_HALF 25 -#define HITAG_T_TAG_CAPTURE_THREE_HALF 41 -#define HITAG_T_TAG_CAPTURE_FOUR_HALF 57 +#define HITAG_T_TAG_CAPTURE_ONE_HALF 13 +#define HITAG_T_TAG_CAPTURE_TWO_HALF 25 +#define HITAG_T_TAG_CAPTURE_THREE_HALF 41 +#define HITAG_T_TAG_CAPTURE_FOUR_HALF 57 static void hitag_send_bit(int bit) { LED_A_ON(); - // Reset clock for the next bit + // Reset clock for the next bit AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - + // Fixed modulation, earlier proxmark version used inverted signal if(bit == 0) { // Manchester: Unloaded, then loaded |__--| @@ -289,20 +291,20 @@ static void hitag_send_frame(const byte_t* frame, size_t frame_len) static void hitag2_handle_reader_command(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { byte_t rx_air[HITAG_FRAME_LEN]; - + // Copy the (original) received frame how it is send over the air memcpy(rx_air,rx,nbytes(rxlen)); if(tag.crypto_active) { hitag2_cipher_transcrypt(&(tag.cs),rx,rxlen/8,rxlen%8); } - - // Reset the transmission frame length + + // Reset the transmission frame length *txlen = 0; - + // Try to find out which command was send by selecting on length (in bits) switch (rxlen) { - // Received 11000 from the reader, request for UID, send UID + // Received 11000 from the reader, request for UID, send UID case 05: { // Always send over the air in the clear plaintext mode if(rx_air[0] != 0xC0) { @@ -315,7 +317,7 @@ static void hitag2_handle_reader_command(byte_t* rx, const size_t rxlen, byte_t* } break; - // Read/Write command: ..xx x..y yy with yyy == ~xxx, xxx is sector number + // Read/Write command: ..xx x..y yy with yyy == ~xxx, xxx is sector number case 10: { unsigned int sector = (~( ((rx[0]<<2)&0x04) | ((rx[1]>>6)&0x03) ) & 0x07); // Verify complement of sector index @@ -330,7 +332,7 @@ static void hitag2_handle_reader_command(byte_t* rx, const size_t rxlen, byte_t* memcpy(tx,tag.sectors[sector],4); *txlen = 32; break; - + // Inverted Read command: 01xx x10y case 0x44: for (size_t i=0; i<4; i++) { @@ -347,7 +349,7 @@ static void hitag2_handle_reader_command(byte_t* rx, const size_t rxlen, byte_t* tag.active_sector = sector; tag.state=TAG_STATE_WRITING; break; - + // Unknown command default: Dbprintf("Unknown command: %02x %02x",rx[0],rx[1]); @@ -405,9 +407,9 @@ static void hitag2_handle_reader_command(byte_t* rx, const size_t rxlen, byte_t* break; } -// LogTraceHitag(rx,rxlen,0,0,false); -// LogTraceHitag(tx,*txlen,0,0,true); - +// LogTraceHitag(rx,rxlen,0,0,false); +// LogTraceHitag(tx,*txlen,0,0,true); + if(tag.crypto_active) { hitag2_cipher_transcrypt(&(tag.cs), tx, *txlen/8, *txlen%8); } @@ -415,30 +417,30 @@ static void hitag2_handle_reader_command(byte_t* rx, const size_t rxlen, byte_t* static void hitag_reader_send_bit(int bit) { LED_A_ON(); - // Reset clock for the next bit + // Reset clock for the next bit AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - + // Binary puls length modulation (BPLM) is used to encode the data stream // This means that a transmission of a one takes longer than that of a zero - + // Enable modulation, which means, drop the field HIGH(GPIO_SSC_DOUT); - + // Wait for 4-10 times the carrier period while(AT91C_BASE_TC0->TC_CV < T0*6); - // SpinDelayUs(8*8); - + // SpinDelayUs(8*8); + // Disable modulation, just activates the field again LOW(GPIO_SSC_DOUT); - + if(bit == 0) { // Zero bit: |_-| while(AT91C_BASE_TC0->TC_CV < T0*22); - // SpinDelayUs(16*8); + // SpinDelayUs(16*8); } else { // One bit: |_--| while(AT91C_BASE_TC0->TC_CV < T0*28); - // SpinDelayUs(22*8); + // SpinDelayUs(22*8); } LED_A_OFF(); } @@ -450,7 +452,7 @@ static void hitag_reader_send_frame(const byte_t* frame, size_t frame_len) for(size_t i=0; i> (7-(i%8)))&1); } - // Send EOF + // Send EOF AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; // Enable modulation, which means, drop the field HIGH(GPIO_SSC_DOUT); @@ -465,7 +467,7 @@ size_t blocknr; static bool hitag2_password(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { // Reset the transmission frame length *txlen = 0; - + // Try to find out which command was send by selecting on length (in bits) switch (rxlen) { // No answer, try to resurrect @@ -478,7 +480,7 @@ static bool hitag2_password(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* *txlen = 5; memcpy(tx,"\xc0",nbytes(*txlen)); } break; - + // Received UID, tag password case 32: { if (!bPwd) { @@ -488,14 +490,14 @@ static bool hitag2_password(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* memcpy(tag.sectors[blocknr],rx,4); blocknr++; } else { - + if(blocknr == 1){ //store password in block1, the TAG answers with Block3, but we need the password in memory memcpy(tag.sectors[blocknr],tx,4); }else{ memcpy(tag.sectors[blocknr],rx,4); } - + blocknr++; if (blocknr > 7) { DbpString("Read succesful!"); @@ -507,7 +509,7 @@ static bool hitag2_password(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* tx[1] = ((blocknr^7) << 6); } } break; - + // Unexpected response default: { Dbprintf("Uknown frame length: %d",rxlen); @@ -529,8 +531,8 @@ static bool hitag2_write_page(byte_t* rx, const size_t rxlen, byte_t* tx, size_t case WRITE_STATE_PAGENUM_WRITTEN: // Check if page number was received correctly if ((rxlen == 10) && - (rx[0] == (0x82 | (blocknr << 3) | ((blocknr^7) >> 2))) && - (rx[1] == (((blocknr & 0x3) ^ 0x3) << 6))) { + (rx[0] == (0x82 | (blocknr << 3) | ((blocknr^7) >> 2))) && + (rx[1] == (((blocknr & 0x3) ^ 0x3) << 6))) { *txlen = 32; memset(tx, 0, HITAG_FRAME_LEN); memcpy(tx, writedata, 4); @@ -562,7 +564,7 @@ static bool hitag2_write_page(byte_t* rx, const size_t rxlen, byte_t* tx, size_t static bool hitag2_crypto(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen, bool write) { // Reset the transmission frame length *txlen = 0; - + if(bCrypto) { hitag2_cipher_transcrypt(&cipher_state,rx,rxlen/8,rxlen%8); @@ -651,7 +653,7 @@ static bool hitag2_crypto(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* tx } } } break; - + // Unexpected response default: { Dbprintf("Uknown frame length: %d",rxlen); @@ -659,7 +661,7 @@ static bool hitag2_crypto(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* tx } break; } } - + if(bCrypto) { // We have to return now to avoid double encryption if (!bAuthenticating) { @@ -672,9 +674,9 @@ static bool hitag2_crypto(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* tx static bool hitag2_authenticate(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { - // Reset the transmission frame length + // Reset the transmission frame length *txlen = 0; - + // Try to find out which command was send by selecting on length (in bits) switch (rxlen) { // No answer, try to resurrect @@ -687,7 +689,7 @@ static bool hitag2_authenticate(byte_t* rx, const size_t rxlen, byte_t* tx, size *txlen = 5; memcpy(tx,"\xc0",nbytes(*txlen)); } break; - + // Received UID, crypto tag answer case 32: { if (!bCrypto) { @@ -700,23 +702,23 @@ static bool hitag2_authenticate(byte_t* rx, const size_t rxlen, byte_t* tx, size return false; } } break; - + // Unexpected response default: { Dbprintf("Uknown frame length: %d",rxlen); return false; } break; } - + return true; } static bool hitag2_test_auth_attempts(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { - // Reset the transmission frame length + // Reset the transmission frame length *txlen = 0; - + // Try to find out which command was send by selecting on length (in bits) switch (rxlen) { // No answer, try to resurrect @@ -740,8 +742,8 @@ static bool hitag2_test_auth_attempts(byte_t* rx, const size_t rxlen, byte_t* tx } *txlen = 5; memcpy(tx,"\xc0",nbytes(*txlen)); - } break; - + } break; + // Received UID, crypto tag answer, or read block response case 32: { if (!bCrypto) { @@ -758,13 +760,13 @@ static bool hitag2_test_auth_attempts(byte_t* rx, const size_t rxlen, byte_t* tx memcpy(NrAr,auth_table+auth_table_pos,8); } } break; - + default: { Dbprintf("Uknown frame length: %d",rxlen); return false; } break; } - + return true; } @@ -816,13 +818,13 @@ void SnoopHitag(uint32_t type) { int tag_sof; byte_t rx[HITAG_FRAME_LEN] = {0}; size_t rxlen=0; - + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); // Clean up trace and prepare it for storing frames set_tracing(true); clear_trace(); - + auth_table_len = 0; auth_table_pos = 0; @@ -832,36 +834,36 @@ void SnoopHitag(uint32_t type) { DbpString("Starting Hitag2 snoop"); LED_D_ON(); - + // Set up eavesdropping mode, frequency divisor which will drive the FPGA // and analog mux selection. FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_TOGGLE_MODE); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz SetAdcMuxFor(GPIO_MUXSEL_LOPKD); RELAY_OFF(); - + // Configure output pin that is connected to the FPGA (for modulating) AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; // Disable modulation, we are going to eavesdrop, not modulate ;) LOW(GPIO_SSC_DOUT); - + // Enable Peripheral Clock for TIMER_CLOCK1, used to capture edges of the reader frames AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; - - // Disable timer during configuration + + // Disable timer during configuration AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - - // Capture mode, defaul timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, + + // TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, // external trigger rising edge, load RA on rising edge of TIOA. uint32_t t1_channel_mode = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_BOTH | AT91C_TC_ABETRG | AT91C_TC_LDRA_BOTH; AT91C_BASE_TC1->TC_CMR = t1_channel_mode; - + // Enable and reset counter AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - + // Reset the received frame, frame count and timing info frame_count = 0; response = 0; @@ -870,18 +872,18 @@ void SnoopHitag(uint32_t type) { lastbit = 1; bSkip = true; tag_sof = 4; - + while(!BUTTON_PRESS()) { // Watchdog hit WDT_HIT(); - + // Receive frame, watch for at most T0*EOF periods while (AT91C_BASE_TC1->TC_CV < T0*HITAG_T_EOF) { // Check if rising edge in modulation is detected if(AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { - // Retrieve the new timing values + // Retrieve the new timing values int ra = (AT91C_BASE_TC1->TC_RA/T0); - + // Find out if we are dealing with a rising or falling edge rising_edge = (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME) > 0; @@ -893,17 +895,17 @@ void SnoopHitag(uint32_t type) { memset(rx,0x00,sizeof(rx)); rxlen = 0; } - + // Only handle if reader frame and rising edge, or tag frame and falling edge if (reader_frame != rising_edge) { overflow += ra; continue; } - + // Add the buffered timing values of earlier captured edges which were skipped ra += overflow; overflow = 0; - + if (reader_frame) { LED_B_ON(); // Capture reader frame @@ -914,11 +916,11 @@ void SnoopHitag(uint32_t type) { // Capture the T0 periods that have passed since last communication or field drop (reset) response = (ra - HITAG_T_LOW); } else if(ra >= HITAG_T_1_MIN ) { - // '1' bit + // '1' bit rx[rxlen / 8] |= 1 << (7-(rxlen%8)); rxlen++; } else if(ra >= HITAG_T_0_MIN) { - // '0' bit + // '0' bit rx[rxlen / 8] |= 0 << (7-(rxlen%8)); rxlen++; } else { @@ -944,7 +946,7 @@ void SnoopHitag(uint32_t type) { // Manchester coding example |_-|...|_-|-_| (0...01) rx[rxlen / 8] |= 0 << (7-(rxlen%8)); rxlen++; - // We have to skip this half period at start and add the 'one' the second time + // We have to skip this half period at start and add the 'one' the second time if (!bSkip) { rx[rxlen / 8] |= 1 << (7-(rxlen%8)); rxlen++; @@ -967,7 +969,7 @@ void SnoopHitag(uint32_t type) { } } } - + // Check if frame was captured if(rxlen > 0) { frame_count++; @@ -984,7 +986,7 @@ void SnoopHitag(uint32_t type) { auth_table_len += 8; } } - + // Reset the received frame and response timing info memset(rx,0x00,sizeof(rx)); response = 0; @@ -993,7 +995,7 @@ void SnoopHitag(uint32_t type) { bSkip = true; tag_sof = 4; overflow = 0; - + LED_B_OFF(); LED_C_OFF(); } else { @@ -1013,10 +1015,10 @@ void SnoopHitag(uint32_t type) { AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_A_OFF(); - -// Dbprintf("frame received: %d",frame_count); -// Dbprintf("Authentication Attempts: %d",(auth_table_len/8)); -// DbpString("All done"); + +// Dbprintf("frame received: %d",frame_count); +// Dbprintf("Authentication Attempts: %d",(auth_table_len/8)); +// DbpString("All done"); } void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { @@ -1029,7 +1031,7 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { size_t txlen=0; bool bQuitTraceFull = false; bQuiet = false; - + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); // Clean up trace and prepare it for storing frames @@ -1046,7 +1048,7 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { DbpString("Starting Hitag2 simulation"); LED_D_ON(); hitag2_init(); - + if (tag_mem_supplied) { DbpString("Loading hitag2 memory..."); memcpy((byte_t*)tag.sectors,data,48); @@ -1060,7 +1062,7 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { } Dbprintf("| %d | %08x |",i,block); } - + // Set up simulator mode, frequency divisor which will drive the FPGA // and analog mux selection. FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); @@ -1074,21 +1076,25 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { // Disable modulation at default, which means release resistance LOW(GPIO_SSC_DOUT); - + // Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0); - + // Enable Peripheral Clock for TIMER_CLOCK1, used to capture edges of the reader frames AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; - - // Disable timer during configuration + + // Disable timer during configuration + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - // Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, + // TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers + AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; + + // TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, // external trigger rising edge, load RA on rising edge of TIOA. AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_RISING | AT91C_TC_ABETRG | AT91C_TC_LDRA_RISING; - + // Reset the received frame, frame count and timing info memset(rx,0x00,sizeof(rx)); frame_count = 0; @@ -1097,24 +1103,24 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { // Enable and reset counter AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - + while(!BUTTON_PRESS()) { // Watchdog hit WDT_HIT(); - + // Receive frame, watch for at most T0*EOF periods while (AT91C_BASE_TC1->TC_CV < T0*HITAG_T_EOF) { // Check if rising edge in modulation is detected if(AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { - // Retrieve the new timing values + // Retrieve the new timing values int ra = (AT91C_BASE_TC1->TC_RA/T0) + overflow; overflow = 0; // Reset timer every frame, we have to capture the last edge for timing AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - + LED_B_ON(); - + // Capture reader frame if(ra >= HITAG_T_STOP) { if (rxlen != 0) { @@ -1123,11 +1129,11 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { // Capture the T0 periods that have passed since last communication or field drop (reset) response = (ra - HITAG_T_LOW); } else if(ra >= HITAG_T_1_MIN ) { - // '1' bit + // '1' bit rx[rxlen / 8] |= 1 << (7-(rxlen%8)); rxlen++; } else if(ra >= HITAG_T_0_MIN) { - // '0' bit + // '0' bit rx[rxlen / 8] |= 0 << (7-(rxlen%8)); rxlen++; } else { @@ -1135,7 +1141,7 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { } } } - + // Check if frame was captured if(rxlen > 4) { frame_count++; @@ -1149,17 +1155,17 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { } } } - + // Disable timer 1 with external trigger to avoid triggers during our own modulation AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // Process the incoming frame (rx) and prepare the outgoing frame (tx) hitag2_handle_reader_command(rx,rxlen,tx,&txlen); - + // Wait for HITAG_T_WAIT_1 carrier periods after the last reader bit, // not that since the clock counts since the rising edge, but T_Wait1 is // with respect to the falling edge, we need to wait actually (T_Wait1 - T_Low) - // periods. The gap time T_Low varies (4..10). All timer values are in + // periods. The gap time T_Low varies (4..10). All timer values are in // terms of T0 units while(AT91C_BASE_TC0->TC_CV < T0*(HITAG_T_WAIT_1-HITAG_T_LOW)); @@ -1179,11 +1185,11 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { } } } - + // Reset the received frame and response timing info memset(rx,0x00,sizeof(rx)); response = 0; - + // Enable and reset external trigger in timer for capturing future frames AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; LED_B_OFF(); @@ -1200,9 +1206,9 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - + DbpString("Sim Stopped"); - + } void ReaderHitag(hitag_function htf, hitag_data* htd) { @@ -1215,16 +1221,16 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { size_t txlen=0; int lastbit; bool bSkip; - int reset_sof; + int reset_sof; int tag_sof; int t_wait = HITAG_T_WAIT_MAX; bool bStop = false; bool bQuitTraceFull = false; - + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); // Reset the return status bSuccessful = false; - + // Clean up trace and prepare it for storing frames set_tracing(true); clear_trace(); @@ -1250,10 +1256,10 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { bAuthenticating = false; bQuitTraceFull = true; } break; - case RHT2F_CRYPTO: + case RHT2F_CRYPTO: { DbpString("Authenticating using key:"); - memcpy(key,htd->crypto.key,6); //HACK; 4 or 6?? I read both in the code. + memcpy(key,htd->crypto.key,6); //HACK; 4 or 6?? I read both in the code. Dbhexdump(6,key,false); blocknr = 0; bQuiet = false; @@ -1281,14 +1287,14 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { return; } break; } - + LED_D_ON(); hitag2_init(); - + // Configure output and enable pin that is connected to the FPGA (for modulating) AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; - + // Set fpga in edge detect with reader field, we can modulate as reader now FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD); @@ -1302,21 +1308,25 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { // Give it a bit of time for the resonant antenna to settle. SpinDelay(30); - + // Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0); // Enable Peripheral Clock for TIMER_CLOCK1, used to capture edges of the tag frames AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; - - // Disable timer during configuration + + // Disable timer during configuration + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - - // Capture mode, defaul timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, + + // TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers + AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; + + // TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, // external trigger rising edge, load RA on falling edge of TIOA. AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_FALLING | AT91C_TC_ABETRG | AT91C_TC_LDRA_FALLING; - + // Enable and reset counters AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; @@ -1350,7 +1360,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { while(!bStop && !BUTTON_PRESS()) { // Watchdog hit WDT_HIT(); - + // Check if frame was captured and store it if(rxlen > 0) { frame_count++; @@ -1365,7 +1375,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { } } } - + // By default reset the transmission buffer tx = txbuf; switch(htf) { @@ -1404,7 +1414,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { while(AT91C_BASE_TC0->TC_CV < T0*(t_wait+(HITAG_T_TAG_HALF_PERIOD*lastbit))); //Dbprintf("DEBUG: Sending reader frame"); - + // Transmit the reader frame hitag_reader_send_frame(tx,txlen); @@ -1440,14 +1450,14 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { while (AT91C_BASE_TC1->TC_CV < T0*HITAG_T_WAIT_MAX) { // Check if falling edge in tag modulation is detected if(AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { - // Retrieve the new timing values + // Retrieve the new timing values int ra = (AT91C_BASE_TC1->TC_RA/T0); - + // Reset timer every frame, we have to capture the last edge for timing AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - + LED_B_ON(); - + // Capture tag frame (manchester decoding using only falling edges) if(ra >= HITAG_T_EOF) { if (rxlen != 0) { @@ -1461,7 +1471,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { //need to test to verify we don't exceed memory... //if ( ((rxlen+2) / 8) > HITAG_FRAME_LEN) { - // break; + // break; //} rx[rxlen / 8] |= 0 << (7-(rxlen%8)); rxlen++; @@ -1469,14 +1479,14 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { rxlen++; } else if(ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { // Manchester coding example |_-|...|_-|-_| (0...01) - + //need to test to verify we don't exceed memory... //if ( ((rxlen+2) / 8) > HITAG_FRAME_LEN) { - // break; + // break; //} rx[rxlen / 8] |= 0 << (7-(rxlen%8)); rxlen++; - // We have to skip this half period at start and add the 'one' the second time + // We have to skip this half period at start and add the 'one' the second time if (!bSkip) { rx[rxlen / 8] |= 1 << (7-(rxlen%8)); rxlen++; @@ -1488,7 +1498,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { //need to test to verify we don't exceed memory... //if ( ((rxlen+2) / 8) > HITAG_FRAME_LEN) { - // break; + // break; //} if (tag_sof) { // Ignore bits that are transmitted during SOF @@ -1513,7 +1523,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { } } //Dbprintf("DEBUG: Done waiting for frame"); - + LED_B_OFF(); LED_D_OFF(); AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; @@ -1538,16 +1548,16 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { size_t txlen=0; int lastbit; bool bSkip; - int reset_sof; + int reset_sof; int tag_sof; int t_wait = HITAG_T_WAIT_MAX; bool bStop; bool bQuitTraceFull = false; - + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); // Reset the return status bSuccessful = false; - + // Clean up trace and prepare it for storing frames set_tracing(true); clear_trace(); @@ -1559,7 +1569,7 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { case WHT2F_CRYPTO: { DbpString("Authenticating using key:"); - memcpy(key,htd->crypto.key,6); //HACK; 4 or 6?? I read both in the code. + memcpy(key,htd->crypto.key,6); //HACK; 4 or 6?? I read both in the code. memcpy(writedata, htd->crypto.data, 4); Dbhexdump(6,key,false); blocknr = page; @@ -1574,14 +1584,14 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { return; } break; } - + LED_D_ON(); hitag2_init(); - + // Configure output and enable pin that is connected to the FPGA (for modulating) AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; - + // Set fpga in edge detect with reader field, we can modulate as reader now FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD); @@ -1595,21 +1605,25 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { // Give it a bit of time for the resonant antenna to settle. SpinDelay(30); - + // Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0); // Enable Peripheral Clock for TIMER_CLOCK1, used to capture edges of the tag frames AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; - - // Disable timer during configuration + + // Disable timer during configuration + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - - // Capture mode, defaul timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, + + // TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers + AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; + + // TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, // external trigger rising edge, load RA on falling edge of TIOA. AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_FALLING | AT91C_TC_ABETRG | AT91C_TC_LDRA_FALLING; - + // Enable and reset counters AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; @@ -1643,7 +1657,7 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { while(!bStop && !BUTTON_PRESS()) { // Watchdog hit WDT_HIT(); - + // Check if frame was captured and store it if(rxlen > 0) { frame_count++; @@ -1658,7 +1672,7 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { } } } - + // By default reset the transmission buffer tx = txbuf; switch(htf) { @@ -1670,24 +1684,24 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { return; } break; } - + // Send and store the reader command // Disable timer 1 with external trigger to avoid triggers during our own modulation AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - + // Wait for HITAG_T_WAIT_2 carrier periods after the last tag bit before transmitting, // Since the clock counts since the last falling edge, a 'one' means that the // falling edge occured halfway the period. with respect to this falling edge, // we need to wait (T_Wait2 + half_tag_period) when the last was a 'one'. // All timer values are in terms of T0 units while(AT91C_BASE_TC0->TC_CV < T0*(t_wait+(HITAG_T_TAG_HALF_PERIOD*lastbit))); - + //Dbprintf("DEBUG: Sending reader frame"); - + // Transmit the reader frame hitag_reader_send_frame(tx,txlen); - // Enable and reset external trigger in timer for capturing future frames + // Enable and reset external trigger in timer for capturing future frames AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // Add transmitted frame to total count @@ -1719,14 +1733,14 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { while (AT91C_BASE_TC1->TC_CV < T0*HITAG_T_WAIT_MAX) { // Check if falling edge in tag modulation is detected if(AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { - // Retrieve the new timing values + // Retrieve the new timing values int ra = (AT91C_BASE_TC1->TC_RA/T0); - + // Reset timer every frame, we have to capture the last edge for timing AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - + LED_B_ON(); - + // Capture tag frame (manchester decoding using only falling edges) if(ra >= HITAG_T_EOF) { if (rxlen != 0) { @@ -1740,7 +1754,7 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { //need to test to verify we don't exceed memory... //if ( ((rxlen+2) / 8) > HITAG_FRAME_LEN) { - // break; + // break; //} rx[rxlen / 8] |= 0 << (7-(rxlen%8)); rxlen++; @@ -1748,14 +1762,14 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { rxlen++; } else if(ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { // Manchester coding example |_-|...|_-|-_| (0...01) - + //need to test to verify we don't exceed memory... //if ( ((rxlen+2) / 8) > HITAG_FRAME_LEN) { - // break; + // break; //} rx[rxlen / 8] |= 0 << (7-(rxlen%8)); rxlen++; - // We have to skip this half period at start and add the 'one' the second time + // We have to skip this half period at start and add the 'one' the second time if (!bSkip) { rx[rxlen / 8] |= 1 << (7-(rxlen%8)); rxlen++; @@ -1767,7 +1781,7 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { //need to test to verify we don't exceed memory... //if ( ((rxlen+2) / 8) > HITAG_FRAME_LEN) { - // break; + // break; //} if (tag_sof) { // Ignore bits that are transmitted during SOF @@ -1790,7 +1804,7 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { if (rxlen>0) break; } } - + // Wait some extra time for flash to be programmed if ((rxlen == 0) && (writestate == WRITE_STATE_PROG)) { @@ -1799,7 +1813,7 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { } } //Dbprintf("DEBUG: Done waiting for frame"); - + LED_B_OFF(); LED_D_OFF(); AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; diff --git a/armsrc/hitag2.h b/armsrc/hitag2.h new file mode 100644 index 00000000..555f04ee --- /dev/null +++ b/armsrc/hitag2.h @@ -0,0 +1,24 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- +// Hitag2 emulation +// +// (c) 2009 Henryk Plötz +// (c) 2012 Roel Verdult +//----------------------------------------------------------------------------- + +#ifndef HITAG2_H__ +#define HITAG2_H__ + +#include +#include +#include "hitag.h" + +void SnoopHitag(uint32_t type); +void SimulateHitagTag(bool tag_mem_supplied, uint8_t* data); +void ReaderHitag(hitag_function htf, hitag_data* htd); +void WriterHitag(hitag_function htf, hitag_data* htd, int page); + +#endif diff --git a/armsrc/hitagS.c b/armsrc/hitagS.c index 8a451606..9e8f1432 100644 --- a/armsrc/hitagS.c +++ b/armsrc/hitagS.c @@ -12,12 +12,13 @@ //----------------------------------------------------------------------------- +#include "hitagS.h" + #include #include "proxmark3.h" #include "apps.h" #include "util.h" -#include "hitagS.h" -#include "hitag2.h" +#include "hitag.h" #include "string.h" #include "BigBuf.h" #include "fpgaloader.h" @@ -25,17 +26,17 @@ #define CRC_PRESET 0xFF #define CRC_POLYNOM 0x1D -#define u8 uint8_t -#define u32 uint32_t -#define u64 uint64_t -#define rev8(x) ((((x)>>7)&1)+((((x)>>6)&1)<<1)+((((x)>>5)&1)<<2)+((((x)>>4)&1)<<3)+((((x)>>3)&1)<<4)+((((x)>>2)&1)<<5)+((((x)>>1)&1)<<6)+(((x)&1)<<7)) -#define rev16(x) (rev8 (x)+(rev8 (x>> 8)<< 8)) -#define rev32(x) (rev16(x)+(rev16(x>>16)<<16)) -#define rev64(x) (rev32(x)+(rev32(x>>32)<<32)) -#define bit(x,n) (((x)>>(n))&1) -#define bit32(x,n) ((((x)[(n)>>5])>>((n)))&1) -#define inv32(x,i,n) ((x)[(i)>>5]^=((u32)(n))<<((i)&31)) -#define rotl64(x, n) ((((u64)(x))<<((n)&63))+(((u64)(x))>>((0-(n))&63))) +#define u8 uint8_t +#define u32 uint32_t +#define u64 uint64_t +#define rev8(x) ((((x)>>7)&1)+((((x)>>6)&1)<<1)+((((x)>>5)&1)<<2)+((((x)>>4)&1)<<3)+((((x)>>3)&1)<<4)+((((x)>>2)&1)<<5)+((((x)>>1)&1)<<6)+(((x)&1)<<7)) +#define rev16(x) (rev8 (x)+(rev8 (x>> 8)<< 8)) +#define rev32(x) (rev16(x)+(rev16(x>>16)<<16)) +#define rev64(x) (rev32(x)+(rev32(x>>32)<<32)) +#define bit(x,n) (((x)>>(n))&1) +#define bit32(x,n) ((((x)[(n)>>5])>>((n)))&1) +#define inv32(x,i,n) ((x)[(i)>>5]^=((u32)(n))<<((i)&31)) +#define rotl64(x, n) ((((u64)(x))<<((n)&63))+(((u64)(x))>>((0-(n))&63))) static bool bQuiet; static bool bSuccessful; @@ -45,25 +46,25 @@ static int block_data_left = 0; typedef enum modulation { AC2K = 0, AC4K, MC4K, MC8K } MOD; -static MOD m = AC2K; //used modulation +static MOD m = AC2K; //used modulation static uint32_t temp_uid; static int temp2 = 0; -static int sof_bits; //number of start-of-frame bits -static byte_t pwdh0, pwdl0, pwdl1; //password bytes -static uint32_t rnd = 0x74124485; //randomnumber +static int sof_bits; //number of start-of-frame bits +static byte_t pwdh0, pwdl0, pwdl1; //password bytes +static uint32_t rnd = 0x74124485; //randomnumber static int test = 0; size_t blocknr; bool end=false; // Single bit Hitag2 functions: -#define i4(x,a,b,c,d) ((u32)((((x)>>(a))&1)+(((x)>>(b))&1)*2+(((x)>>(c))&1)*4+(((x)>>(d))&1)*8)) -static const u32 ht2_f4a = 0x2C79; // 0010 1100 0111 1001 -static const u32 ht2_f4b = 0x6671; // 0110 0110 0111 0001 -static const u32 ht2_f5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011 -#define ht2bs_4a(a,b,c,d) (~(((a|b)&c)^(a|d)^b)) -#define ht2bs_4b(a,b,c,d) (~(((d|c)&(a^b))^(d|a|b))) -#define ht2bs_5c(a,b,c,d,e) (~((((((c^e)|d)&a)^b)&(c^b))^(((d^e)|a)&((d^b)|c)))) -#define uf20bs u32 +#define i4(x,a,b,c,d) ((u32)((((x)>>(a))&1)+(((x)>>(b))&1)*2+(((x)>>(c))&1)*4+(((x)>>(d))&1)*8)) +static const u32 ht2_f4a = 0x2C79; // 0010 1100 0111 1001 +static const u32 ht2_f4b = 0x6671; // 0110 0110 0111 0001 +static const u32 ht2_f5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011 +#define ht2bs_4a(a,b,c,d) (~(((a|b)&c)^(a|d)^b)) +#define ht2bs_4b(a,b,c,d) (~(((d|c)&(a^b))^(d|a|b))) +#define ht2bs_5c(a,b,c,d,e) (~((((((c^e)|d)&a)^b)&(c^b))^(((d^e)|a)&((d^b)|c)))) +#define uf20bs u32 static u32 f20(const u64 x) { u32 i5; @@ -109,34 +110,34 @@ static u32 hitag2_byte(u64 *x) { // TIMER_CLOCK1 = MCK/2, MCK is running at 48 MHz, Timer is running at 48/2 = 24 MHz // Hitag units (T0) have duration of 8 microseconds (us), which is 1/125000 per second (carrier) // T0 = TIMER_CLOCK1 / 125000 = 192 -#define T0 192 +#define T0 192 -#define SHORT_COIL() LOW(GPIO_SSC_DOUT) -#define OPEN_COIL() HIGH(GPIO_SSC_DOUT) +#define SHORT_COIL() LOW(GPIO_SSC_DOUT) +#define OPEN_COIL() HIGH(GPIO_SSC_DOUT) -#define HITAG_FRAME_LEN 20 -#define HITAG_T_STOP 36 /* T_EOF should be > 36 */ -#define HITAG_T_LOW 8 /* T_LOW should be 4..10 */ -#define HITAG_T_0_MIN 15 /* T[0] should be 18..22 */ -#define HITAG_T_1_MIN 25 /* T[1] should be 26..30 */ +#define HITAG_FRAME_LEN 20 +#define HITAG_T_STOP 36 /* T_EOF should be > 36 */ +#define HITAG_T_LOW 8 /* T_LOW should be 4..10 */ +#define HITAG_T_0_MIN 15 /* T[0] should be 18..22 */ +#define HITAG_T_1_MIN 25 /* T[1] should be 26..30 */ //#define HITAG_T_EOF 40 /* T_EOF should be > 36 */ -#define HITAG_T_EOF 80 /* T_EOF should be > 36 */ -#define HITAG_T_WAIT_1 200 /* T_wresp should be 199..206 */ -#define HITAG_T_WAIT_2 90 /* T_wresp should be 199..206 */ -#define HITAG_T_WAIT_MAX 300 /* bit more than HITAG_T_WAIT_1 + HITAG_T_WAIT_2 */ +#define HITAG_T_EOF 80 /* T_EOF should be > 36 */ +#define HITAG_T_WAIT_1 200 /* T_wresp should be 199..206 */ +#define HITAG_T_WAIT_2 90 /* T_wresp should be 199..206 */ +#define HITAG_T_WAIT_MAX 300 /* bit more than HITAG_T_WAIT_1 + HITAG_T_WAIT_2 */ -#define HITAG_T_TAG_ONE_HALF_PERIOD 10 -#define HITAG_T_TAG_TWO_HALF_PERIOD 25 -#define HITAG_T_TAG_THREE_HALF_PERIOD 41 -#define HITAG_T_TAG_FOUR_HALF_PERIOD 57 - -#define HITAG_T_TAG_HALF_PERIOD 16 -#define HITAG_T_TAG_FULL_PERIOD 32 - -#define HITAG_T_TAG_CAPTURE_ONE_HALF 13 -#define HITAG_T_TAG_CAPTURE_TWO_HALF 25 -#define HITAG_T_TAG_CAPTURE_THREE_HALF 41 -#define HITAG_T_TAG_CAPTURE_FOUR_HALF 57 +#define HITAG_T_TAG_ONE_HALF_PERIOD 10 +#define HITAG_T_TAG_TWO_HALF_PERIOD 25 +#define HITAG_T_TAG_THREE_HALF_PERIOD 41 +#define HITAG_T_TAG_FOUR_HALF_PERIOD 57 + +#define HITAG_T_TAG_HALF_PERIOD 16 +#define HITAG_T_TAG_FULL_PERIOD 32 + +#define HITAG_T_TAG_CAPTURE_ONE_HALF 13 +#define HITAG_T_TAG_CAPTURE_TWO_HALF 25 +#define HITAG_T_TAG_CAPTURE_THREE_HALF 41 +#define HITAG_T_TAG_CAPTURE_FOUR_HALF 57 #define DEBUG 0 @@ -290,7 +291,7 @@ static void hitag_reader_send_bit(int bit) { // Wait for 4-10 times the carrier period while (AT91C_BASE_TC0->TC_CV < T0 * 6) ; - // SpinDelayUs(8*8); + // SpinDelayUs(8*8); // Disable modulation, just activates the field again LOW(GPIO_SSC_DOUT); @@ -299,18 +300,18 @@ static void hitag_reader_send_bit(int bit) { // Zero bit: |_-| while (AT91C_BASE_TC0->TC_CV < T0 * 11) ; - // SpinDelayUs(16*8); + // SpinDelayUs(16*8); } else { // One bit: |_--| while (AT91C_BASE_TC0->TC_CV < T0 * 14) ; - // SpinDelayUs(22*8); + // SpinDelayUs(22*8); } } else { // Wait for 4-10 times the carrier period while (AT91C_BASE_TC0->TC_CV < T0 * 6) ; - // SpinDelayUs(8*8); + // SpinDelayUs(8*8); // Disable modulation, just activates the field again LOW(GPIO_SSC_DOUT); @@ -319,12 +320,12 @@ static void hitag_reader_send_bit(int bit) { // Zero bit: |_-| while (AT91C_BASE_TC0->TC_CV < T0 * 22) ; - // SpinDelayUs(16*8); + // SpinDelayUs(16*8); } else { // One bit: |_--| while (AT91C_BASE_TC0->TC_CV < T0 * 28) ; - // SpinDelayUs(22*8); + // SpinDelayUs(22*8); } } @@ -403,11 +404,11 @@ static void hitag_decode_frame_MC(int bitRate, int sofBits, byte_t* rx, size_t* } else { // Ignore wierd value, is to small to mean anything } - } + } *rxlenOrg = rxlen; } -/* +/* static void hitag_decode_frame_AC2K_rising(byte_t* rx, size_t* rxlenOrg, int* response, int rawMod[], int rawLen) { int tag_sof = 1; //skip start of frame size_t rxlen = 0; @@ -461,7 +462,7 @@ static void hitag_decode_frame_AC(int bitRate, int sofBits, byte_t* rx, size_t* if (bitRate == 4) { timing = 2; } - + for (int i=0; i < rawLen; i++) { int ra = rawMod[i]; @@ -534,11 +535,11 @@ static void hitag_receive_frame(byte_t* rx, size_t* rxlen, int* response) { break; case ADVANCED: m = AC2K; - sofBits = 5; //3 sof bits but 5 captures + sofBits = 5; //3 sof bits but 5 captures break; case FAST_ADVANCED: m = AC4K; - sofBits = 5; //3 sof bits but 5 captures + sofBits = 5; //3 sof bits but 5 captures break; default: break; @@ -561,7 +562,7 @@ static void hitag_receive_frame(byte_t* rx, size_t* rxlen, int* response) { break; } } - + //rising AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_RISING | AT91C_TC_ABETRG | AT91C_TC_LDRA_RISING; AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_FALLING | AT91C_TC_ABETRG | AT91C_TC_LDRA_FALLING; @@ -596,7 +597,7 @@ static void hitag_receive_frame(byte_t* rx, size_t* rxlen, int* response) { if (DEBUG >= 2) { for (i=0; i < rawLen; i+=20) { - Dbprintf("raw modulation: - %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", + Dbprintf("raw modulation: - %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", rawMod[i],rawMod[i+1],rawMod[i+2],rawMod[i+3], rawMod[i+4],rawMod[i+5],rawMod[i+6],rawMod[i+7], rawMod[i+8],rawMod[i+9],rawMod[i+10],rawMod[i+11], rawMod[i+12],rawMod[i+13],rawMod[i+14],rawMod[i+15], rawMod[i+16],rawMod[i+17],rawMod[i+18],rawMod[i+19] @@ -608,8 +609,8 @@ static void hitag_receive_frame(byte_t* rx, size_t* rxlen, int* response) { // DATA | 1 | 0 | 1 | 1 | 0 | // Manchester |--__|__--|--__|--__|__--| // Anti Collision |-_-_|--__|-_-_|-_-_|--__| - // |<-->| - // | T | + // |<-->| + // | T | case AC2K: if (DEBUG >= 2) { Dbprintf("decoding frame with modulation AC2K"); } hitag_decode_frame_AC(2, sofBits, rx, rxlen, response, rawMod, rawLen); @@ -683,7 +684,7 @@ static int hitag_read_page(hitag_function htf, uint64_t key, byte_t* rx, size_t* calc_crc(&crc, tx[0], 8); calc_crc(&crc, 0x00 + ((pageNum % 16) * 16), 4); tx[1] = 0x00 + ((pageNum % 16) * 16) + (crc / 16); - tx[2] = 0x00 + (crc % 16) * 16; + tx[2] = 0x00 + (crc % 16) * 16; } else if (tag.pstate == SELECTED && tag.tstate == READING_PAGE && *rxlen > 0) { //save received data z = 0; @@ -704,9 +705,9 @@ static int hitag_read_page(hitag_function htf, uint64_t key, byte_t* rx, size_t* tag.pages[pageNum][i] = 0x0; } for (i = 0; i < 4; i++) { - tag.pages[pageNum][i] += ((pageData[i * 8] << 7) | (pageData[1 + (i * 8)] << 6) | - (pageData[2 + (i * 8)] << 5) | (pageData[3 + (i * 8)] << 4) | - (pageData[4 + (i * 8)] << 3) | (pageData[5 + (i * 8)] << 2) | + tag.pages[pageNum][i] += ((pageData[i * 8] << 7) | (pageData[1 + (i * 8)] << 6) | + (pageData[2 + (i * 8)] << 5) | (pageData[3 + (i * 8)] << 4) | + (pageData[4 + (i * 8)] << 3) | (pageData[5 + (i * 8)] << 2) | (pageData[6 + (i * 8)] << 1) | pageData[7 + (i * 8)]); } @@ -715,11 +716,11 @@ static int hitag_read_page(hitag_function htf, uint64_t key, byte_t* rx, size_t* tag.pages[pageNum][2], tag.pages[pageNum][1], tag.pages[pageNum][0]); } else { Dbprintf("Page[%2d]: %02X %02X %02X %02X", pageNum, - tag.pages[pageNum][3], tag.pages[pageNum][2], + tag.pages[pageNum][3], tag.pages[pageNum][2], tag.pages[pageNum][1], tag.pages[pageNum][0]); } - + //display key and password if possible if (pageNum == 1 && tag.auth == 1 && tag.LKP) { if (htf == 02) { //RHTS_KEY @@ -771,7 +772,7 @@ static int hitag_read_block(hitag_function htf, uint64_t key, byte_t* rx, size_t calc_crc(&crc, tx[0], 8); calc_crc(&crc, 0x00 + ((blockNum % 16) * 16), 4); tx[1] = 0x00 + ((blockNum % 16) * 16) + (crc / 16); - tx[2] = 0x00 + (crc % 16) * 16; + tx[2] = 0x00 + (crc % 16) * 16; } else if (tag.pstate == SELECTED && tag.tstate == READING_BLOCK && *rxlen > 0) { //save received data z = 0; @@ -796,16 +797,16 @@ static int hitag_read_block(hitag_function htf, uint64_t key, byte_t* rx, size_t for (z = 0; z < 4; z++) { //4 pages for (i = 0; i < 4; i++) { j = (i * 8) + (z*32); //bit in page + pageStart - tag.pages[blockNum+z][i] = ((blockData[j] << 7) | (blockData[1 + j] << 6) | - (blockData[2 + j] << 5) | (blockData[3 + j] << 4) | - (blockData[4 + j] << 3) | (blockData[5 + j] << 2) | + tag.pages[blockNum+z][i] = ((blockData[j] << 7) | (blockData[1 + j] << 6) | + (blockData[2 + j] << 5) | (blockData[3 + j] << 4) | + (blockData[4 + j] << 3) | (blockData[5 + j] << 2) | (blockData[6 + j] << 1) | blockData[7 + j]); } } if (DEBUG) { - for (z = 0; z < 4; z++) { + for (z = 0; z < 4; z++) { Dbprintf("Page[%2d]: %02X %02X %02X %02X", blockNum+z, - tag.pages[blockNum+z][3], tag.pages[blockNum+z][2], + tag.pages[blockNum+z][3], tag.pages[blockNum+z][2], tag.pages[blockNum+z][1], tag.pages[blockNum+z][0]); } } @@ -1055,7 +1056,7 @@ static void hitagS_handle_reader_command(byte_t* rx, const size_t rxlen, tx[1] = tag.pages[page][1]; tx[2] = tag.pages[page][2]; tx[3] = tag.pages[page][3]; - + if (tag.LKP && page == 1) tx[3] = 0xff; @@ -1206,7 +1207,7 @@ static void hitagS_handle_reader_command(byte_t* rx, const size_t rxlen, /* * to autenticate to a tag with the given key or challenge */ -static int hitagS_handle_tag_auth(hitag_function htf,uint64_t key, uint64_t NrAr, byte_t* rx, +static int hitagS_handle_tag_auth(hitag_function htf,uint64_t key, uint64_t NrAr, byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { byte_t rx_air[HITAG_FRAME_LEN]; int response_bit[200] = {0}; @@ -1222,8 +1223,8 @@ static int hitagS_handle_tag_auth(hitag_function htf,uint64_t key, uint64_t NrAr *txlen = 0; if (DEBUG) { - Dbprintf("START hitagS_handle_tag_auth - rxlen: %d, tagstate=%d", rxlen, (int)tag.pstate); - } + Dbprintf("START hitagS_handle_tag_auth - rxlen: %d, tagstate=%d", rxlen, (int)tag.pstate); + } if (tag.pstate == READY && rxlen >= 32) { //received uid @@ -1243,7 +1244,7 @@ static int hitagS_handle_tag_auth(hitag_function htf,uint64_t key, uint64_t NrAr for (i = 0; i < 32; i++) { uid[i] = response_bit[i]; } - + uid1 = (uid[0] << 7) | (uid[1] << 6) | (uid[2] << 5) | (uid[3] << 4) | (uid[4] << 3) | (uid[5] << 2) | (uid[6] << 1) | uid[7]; uid2 = (uid[8] << 7) | (uid[9] << 6) | (uid[10] << 5) | (uid[11] << 4) @@ -1251,7 +1252,7 @@ static int hitagS_handle_tag_auth(hitag_function htf,uint64_t key, uint64_t NrAr uid3 = (uid[16] << 7) | (uid[17] << 6) | (uid[18] << 5) | (uid[19] << 4) | (uid[20] << 3) | (uid[21] << 2) | (uid[22] << 1) | uid[23]; uid4 = (uid[24] << 7) | (uid[25] << 6) | (uid[26] << 5) | (uid[27] << 4) - | (uid[28] << 3) | (uid[29] << 2) | (uid[30] << 1) | uid[31]; + | (uid[28] << 3) | (uid[29] << 2) | (uid[30] << 1) | uid[31]; Dbprintf("UID: %02X %02X %02X %02X", uid1, uid2, uid3, uid4); tag.uid = (uid4 << 24 | uid3 << 16 | uid2 << 8 | uid1); @@ -1269,7 +1270,7 @@ static int hitagS_handle_tag_auth(hitag_function htf,uint64_t key, uint64_t NrAr response_bit[i] = 0; } - //skip the first 5 + //skip the first 5 for (i = 5; i < 37; i++) { response_bit[i] = uid[i - 5]; } @@ -1322,7 +1323,7 @@ static int hitagS_handle_tag_auth(hitag_function htf,uint64_t key, uint64_t NrAr //tag.TTFM in response_bit[12] and response_bit[13] tag.LCON = response_bit[14]; tag.LKP = response_bit[15]; - + //CON2 tag.LCK7 = response_bit[16]; tag.LCK6 = response_bit[17]; @@ -1357,9 +1358,9 @@ static int hitagS_handle_tag_auth(hitag_function htf,uint64_t key, uint64_t NrAr if(htf==02||htf==04){ //RHTS_KEY //WHTS_KEY state = hitag2_init(rev64(key), rev32(tag.uid), rev32(rnd)); /* - Dbprintf("key: %02X %02X\n\n", key, rev64(key)); - Dbprintf("tag.uid: %02X %02X\n\n", tag.uid, rev32(tag.uid)); - Dbprintf("rnd: %02X %02X\n\n", rnd, rev32(rnd)); + Dbprintf("key: %02X %02X\n\n", key, rev64(key)); + Dbprintf("tag.uid: %02X %02X\n\n", tag.uid, rev32(tag.uid)); + Dbprintf("rnd: %02X %02X\n\n", rnd, rev32(rnd)); */ for (i = 0; i < 4; i++) { auth_ks[i] = hitag2_byte(&state) ^ 0xff; @@ -1390,7 +1391,7 @@ static int hitagS_handle_tag_auth(hitag_function htf,uint64_t key, uint64_t NrAr } else if (tag.auth == 0) { tag.pstate = SELECTED; } - + } else if (tag.pstate == AUTHENTICATE && rxlen >= 32) { //encrypted con2,password received. if (DEBUG) { @@ -1418,8 +1419,8 @@ static int hitagS_handle_tag_auth(hitag_function htf,uint64_t key, uint64_t NrAr } if (DEBUG) { - Dbprintf("END hitagS_handle_tag_auth - tagstate=%d", (int)tag.pstate); - } + Dbprintf("END hitagS_handle_tag_auth - tagstate=%d", (int)tag.pstate); + } return 0; } @@ -1459,7 +1460,7 @@ void SimulateHitagSTag(bool tag_mem_supplied, byte_t* data) { } } - for (i = 0; i < 64; i++) { + for (i = 0; i < 64; i++) { for (j = 0; j < 4; j++) { tag.pages[i][j] = data[(i*4)+j]; } @@ -1491,7 +1492,7 @@ void SimulateHitagSTag(bool tag_mem_supplied, byte_t* data) { //tag.TTFM in response_bit[12] and response_bit[13] tag.LCON = ((con1 & 0x2) == 0x2) ? 1 : 0; tag.LKP = ((con1 & 0x1) == 0x1) ? 1 : 0; - + //CON2 tag.LCK7 = ((con2 & 0x80) == 0x80) ? 1 : 0; tag.LCK6 = ((con2 & 0x40) == 0x40) ? 1 : 0; @@ -1535,9 +1536,13 @@ void SimulateHitagSTag(bool tag_mem_supplied, byte_t* data) { AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; // Disable timer during configuration + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - // Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, + // TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers + AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; + + // TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, // external trigger rising edge, load RA on rising edge of TIOA. AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_RISING | AT91C_TC_ABETRG | AT91C_TC_LDRA_RISING; @@ -1677,7 +1682,7 @@ void ReadHitagSintern(hitag_function htf, hitag_data* htd, stype tagMode, int st bool bQuitTraceFull = false; page_to_be_written = 0; - + //read given key/challenge byte_t NrAr_[8]; uint64_t key=0; @@ -1690,12 +1695,12 @@ void ReadHitagSintern(hitag_function htf, hitag_data* htd, stype tagMode, int st memcpy(NrAr_,htd->auth.NrAr,8); Dbhexdump(8,NrAr_,false); NrAr=NrAr_[7] | ((uint64_t)NrAr_[6]) << 8 | ((uint64_t)NrAr_[5]) << 16 | ((uint64_t)NrAr_[4]) << 24 | ((uint64_t)NrAr_[3]) << 32 | - ((uint64_t)NrAr_[2]) << 40| ((uint64_t)NrAr_[1]) << 48 | ((uint64_t)NrAr_[0]) << 56; + ((uint64_t)NrAr_[2]) << 40| ((uint64_t)NrAr_[1]) << 48 | ((uint64_t)NrAr_[0]) << 56; } break; case 02: case 04: { //RHTS_KEY DbpString("Authenticating using key:"); - memcpy(key_,htd->crypto.key,6); + memcpy(key_,htd->crypto.key,6); Dbhexdump(6,key_,false); key=key_[5] | ((uint64_t)key_[4]) << 8 | ((uint64_t)key_[3]) << 16 | ((uint64_t)key_[2]) << 24 | ((uint64_t)key_[1]) << 32 | ((uint64_t)key_[0]) << 40; } break; @@ -1708,10 +1713,10 @@ void ReadHitagSintern(hitag_function htf, hitag_data* htd, stype tagMode, int st FpgaDownloadAndGo(FPGA_BITSTREAM_LF); -// Reset the return status + // Reset the return status bSuccessful = false; -// Clean up trace and prepare it for storing frames + // Clean up trace and prepare it for storing frames set_tracing(true); clear_trace(); @@ -1719,43 +1724,47 @@ void ReadHitagSintern(hitag_function htf, hitag_data* htd, stype tagMode, int st LED_D_ON(); -// Configure output and enable pin that is connected to the FPGA (for modulating) + // Configure output and enable pin that is connected to the FPGA (for modulating) AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; -// Set fpga in edge detect with reader field, we can modulate as reader now + // Set fpga in edge detect with reader field, we can modulate as reader now FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD); -// Set Frequency divisor which will drive the FPGA and analog mux selection - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + // Set Frequency divisor which will drive the FPGA and analog mux selection + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz SetAdcMuxFor(GPIO_MUXSEL_LOPKD); RELAY_OFF(); -// Disable modulation at default, which means enable the field + // Disable modulation at default, which means enable the field LOW(GPIO_SSC_DOUT); -// Give it a bit of time for the resonant antenna to settle. + // Give it a bit of time for the resonant antenna to settle. SpinDelay(30); -// Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering + // Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0); -// Enable Peripheral Clock for TIMER_CLOCK1, used to capture edges of the tag frames + // Enable Peripheral Clock for TIMER_CLOCK1, used to capture edges of the tag frames AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; -// Disable timer during configuration + // Disable timer during configuration + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; -// Capture mode, defaul timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, -// external trigger rising edge, load RA on falling edge of TIOA. + // TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers + AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; + + // TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, + // external trigger rising edge, load RA on falling edge of TIOA. AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_FALLING | AT91C_TC_ABETRG | AT91C_TC_LDRA_FALLING; -// Enable and reset counters + // Enable and reset counters AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; -// Reset the received frame, frame count and timing info + // Reset the received frame, frame count and timing info frame_count = 0; response = 0; lastbit = 1; @@ -1808,8 +1817,8 @@ void ReadHitagSintern(hitag_function htf, hitag_data* htd, stype tagMode, int st txlen = 0; if (DEBUG >= 2) { - Dbprintf("FRO %d rxlen: %d, pstate=%d, tstate=%d", frame_count, rxlen, (int)tag.pstate, (int)tag.tstate); - } + Dbprintf("FRO %d rxlen: %d, pstate=%d, tstate=%d", frame_count, rxlen, (int)tag.pstate, (int)tag.tstate); + } if (rxlen == 0) { //start authentication @@ -1822,7 +1831,7 @@ void ReadHitagSintern(hitag_function htf, hitag_data* htd, stype tagMode, int st } - + if (readBlock && tag.pstate == SELECTED && (tag.tstate == READING_BLOCK || tag.tstate == NO_OP) && rxlen > 0) { i = hitag_read_block(htf, key, rx, &rxlen, tx, &txlen, sendNum); if (i > 0) { sendNum+=4; } @@ -1863,8 +1872,8 @@ void ReadHitagSintern(hitag_function htf, hitag_data* htd, stype tagMode, int st lastbit = 1; response = 0; - // get tag id in anti-collision mode (proprietary data format, so switch off manchester and read at double the data rate, for 4 x the data bits) - hitag_receive_frame(rx, &rxlen, &response); + // get tag id in anti-collision mode (proprietary data format, so switch off manchester and read at double the data rate, for 4 x the data bits) + hitag_receive_frame(rx, &rxlen, &response); } end=false; LED_B_OFF(); @@ -1885,7 +1894,7 @@ void ReadHitagSCmd(hitag_function htf, hitag_data* htd, uint64_t startPage, uint } else { Dbprintf("ReadHitagS in mode=STANDARD, blockRead=%d, startPage=%d", readBlock, startPage); ReadHitagSintern(htf, htd, STANDARD, (int)startPage, readBlock); - } + } } @@ -1909,7 +1918,7 @@ void WritePageHitagS(hitag_function htf, hitag_data* htd,int page_) { int page = page_; unsigned char crc; byte_t data[4]= {0,0,0,0}; - + //read given key/challenge, the page and the data byte_t NrAr_[8]; uint64_t key=0; @@ -1922,12 +1931,12 @@ void WritePageHitagS(hitag_function htf, hitag_data* htd,int page_) { memcpy(NrAr_,htd->auth.NrAr,8); Dbhexdump(8,NrAr_,false); NrAr=NrAr_[7] | ((uint64_t)NrAr_[6]) << 8 | ((uint64_t)NrAr_[5]) << 16 | ((uint64_t)NrAr_[4]) << 24 | ((uint64_t)NrAr_[3]) << 32 | - ((uint64_t)NrAr_[2]) << 40| ((uint64_t)NrAr_[1]) << 48 | ((uint64_t)NrAr_[0]) << 56; + ((uint64_t)NrAr_[2]) << 40| ((uint64_t)NrAr_[1]) << 48 | ((uint64_t)NrAr_[0]) << 56; } break; case 04: { //WHTS_KEY memcpy(data,htd->crypto.data,4); DbpString("Authenticating using key:"); - memcpy(key_,htd->crypto.key,6); + memcpy(key_,htd->crypto.key,6); Dbhexdump(6,key_,false); key=key_[5] | ((uint64_t)key_[4]) << 8 | ((uint64_t)key_[3]) << 16 | ((uint64_t)key_[2]) << 24 | ((uint64_t)key_[1]) << 32 | ((uint64_t)key_[0]) << 40; } break; @@ -1940,13 +1949,13 @@ void WritePageHitagS(hitag_function htf, hitag_data* htd,int page_) { Dbprintf("Page: %d",page_); Dbprintf("DATA: %02X %02X %02X %02X", data[0], data[1], data[2], data[3]); FpgaDownloadAndGo(FPGA_BITSTREAM_LF); -// Reset the return status + // Reset the return status bSuccessful = false; tag.pstate = READY; tag.tstate = NO_OP; -// Clean up trace and prepare it for storing frames + // Clean up trace and prepare it for storing frames set_tracing(true); clear_trace(); @@ -1954,45 +1963,49 @@ void WritePageHitagS(hitag_function htf, hitag_data* htd,int page_) { LED_D_ON(); -// Configure output and enable pin that is connected to the FPGA (for modulating) + // Configure output and enable pin that is connected to the FPGA (for modulating) AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; -// Set fpga in edge detect with reader field, we can modulate as reader now + // Set fpga in edge detect with reader field, we can modulate as reader now FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD); -// Set Frequency divisor which will drive the FPGA and analog mux selection + // Set Frequency divisor which will drive the FPGA and analog mux selection FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz SetAdcMuxFor(GPIO_MUXSEL_LOPKD); RELAY_OFF(); -// Disable modulation at default, which means enable the field + // Disable modulation at default, which means enable the field LOW(GPIO_SSC_DOUT); -// Give it a bit of time for the resonant antenna to settle. + // Give it a bit of time for the resonant antenna to settle. SpinDelay(30); -// Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering + // Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0); -// Enable Peripheral Clock for TIMER_CLOCK1, used to capture edges of the tag frames + // Enable Peripheral Clock for TIMER_CLOCK1, used to capture edges of the tag frames AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; -// Disable timer during configuration + // Disable timer during configuration + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; -// Capture mode, defaul timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, -// external trigger rising edge, load RA on falling edge of TIOA. + // TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers + AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; + + // TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, + // external trigger rising edge, load RA on falling edge of TIOA. AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_FALLING | AT91C_TC_ABETRG | AT91C_TC_LDRA_FALLING; -// Enable and reset counters + // Enable and reset counters AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; -// Reset the received frame, frame count and timing info + // Reset the received frame, frame count and timing info frame_count = 0; response = 0; lastbit = 1; @@ -2181,10 +2194,10 @@ void check_challenges_cmd(bool file_given, byte_t* data, uint64_t tagMode) { FpgaDownloadAndGo(FPGA_BITSTREAM_LF); -// Reset the return status + // Reset the return status bSuccessful = false; -// Clean up trace and prepare it for storing frames + // Clean up trace and prepare it for storing frames set_tracing(true); clear_trace(); @@ -2192,44 +2205,48 @@ void check_challenges_cmd(bool file_given, byte_t* data, uint64_t tagMode) { LED_D_ON(); -// Configure output and enable pin that is connected to the FPGA (for modulating) + // Configure output and enable pin that is connected to the FPGA (for modulating) AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; -// Set fpga in edge detect with reader field, we can modulate as reader now + // Set fpga in edge detect with reader field, we can modulate as reader now FpgaWriteConfWord( FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD); -// Set Frequency divisor which will drive the FPGA and analog mux selection - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + // Set Frequency divisor which will drive the FPGA and analog mux selection + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz SetAdcMuxFor(GPIO_MUXSEL_LOPKD); RELAY_OFF(); -// Disable modulation at default, which means enable the field + // Disable modulation at default, which means enable the field LOW(GPIO_SSC_DOUT); -// Give it a bit of time for the resonant antenna to settle. + // Give it a bit of time for the resonant antenna to settle. SpinDelay(30); -// Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering + // Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0); -// Enable Peripheral Clock for TIMER_CLOCK1, used to capture edges of the tag frames + // Enable Peripheral Clock for TIMER_CLOCK1, used to capture edges of the tag frames AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; -// Disable timer during configuration + // Disable timer during configuration + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; -// Capture mode, defaul timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, -// external trigger rising edge, load RA on falling edge of TIOA. + // TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers + AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; + + // TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, + // external trigger rising edge, load RA on falling edge of TIOA. AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_FALLING | AT91C_TC_ABETRG | AT91C_TC_LDRA_FALLING; -// Enable and reset counters + // Enable and reset counters AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; -// Reset the received frame, frame count and timing info + // Reset the received frame, frame count and timing info frame_count = 0; response = 0; lastbit = 1; diff --git a/armsrc/hitagS.h b/armsrc/hitagS.h new file mode 100644 index 00000000..8451b2cf --- /dev/null +++ b/armsrc/hitagS.h @@ -0,0 +1,26 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- +// HitagS emulation (preliminary test version) +// +// (c) 2016 Oguzhan Cicek, Hendrik Schwartke, Ralf Spenneberg +// +//----------------------------------------------------------------------------- +// Some code was copied from Hitag2.c +//----------------------------------------------------------------------------- + +#ifndef HITAGS_H__ +#define HITAGS_H__ + +#include +#include +#include "hitag.h" + +void ReadHitagSCmd(hitag_function htf, hitag_data* htd, uint64_t startPage, uint64_t tagMode, bool readBlock); +void SimulateHitagSTag(bool tag_mem_supplied, uint8_t* data); +void WritePageHitagS(hitag_function htf, hitag_data* htd, int page); +void check_challenges_cmd(bool file_given, uint8_t* data, uint64_t tagMode); + +#endif \ No newline at end of file diff --git a/client/cmdlfhitag.c b/client/cmdlfhitag.c index 84fb5458..cd23f88c 100644 --- a/client/cmdlfhitag.c +++ b/client/cmdlfhitag.c @@ -19,8 +19,7 @@ #include "common.h" #include "util.h" #include "parity.h" -#include "hitag2.h" -#include "hitagS.h" +#include "hitag.h" #include "cmdmain.h" static int CmdHelp(const char *Cmd); diff --git a/include/hitag.h b/include/hitag.h new file mode 100644 index 00000000..35660dcb --- /dev/null +++ b/include/hitag.h @@ -0,0 +1,93 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- +// Hitag2, HitagS +// +// (c) 2012 Roel Verdult +// (c) 2016 Oguzhan Cicek, Hendrik Schwartke, Ralf Spenneberg +// +//----------------------------------------------------------------------------- + + +#ifndef HITAG_H__ +#define HITAG_H__ + +#ifdef _MSC_VER +#define PACKED +#else +#define PACKED __attribute__((packed)) +#endif + +typedef enum { + RHTSF_CHALLENGE = 01, + RHTSF_KEY = 02, + WHTSF_CHALLENGE = 03, + WHTSF_KEY = 04, + RHT2F_PASSWORD = 21, + RHT2F_AUTHENTICATE = 22, + RHT2F_CRYPTO = 23, + WHT2F_CRYPTO = 24, + RHT2F_TEST_AUTH_ATTEMPTS = 25, + RHT2F_UID_ONLY = 26, +} hitag_function; + +typedef struct { + uint8_t password[4]; +} PACKED rht2d_password; + +typedef struct { + uint8_t NrAr[8]; + uint8_t data[4]; +} PACKED rht2d_authenticate; + +typedef struct { + uint8_t key[6]; + uint8_t data[4]; +} PACKED rht2d_crypto; + +typedef union { + rht2d_password pwd; + rht2d_authenticate auth; + rht2d_crypto crypto; +} hitag_data; + + +//--------------------------------------------------------- +// Hitag S +//--------------------------------------------------------- +typedef enum PROTO_STATE {READY=0,INIT,AUTHENTICATE,SELECTED,QUIET,TTF,FAIL} PSTATE; //protocol-state +typedef enum TAG_STATE {NO_OP=0,READING_PAGE,READING_BLOCK,WRITING_PAGE_ACK,WRITING_PAGE_DATA,WRITING_BLOCK_DATA} TSATE; //tag-state +typedef enum SOF_TYPE {STANDARD=0,ADVANCED,FAST_ADVANCED,ONE,NO_BITS} stype; //number of start-of-frame bits + +struct hitagS_tag { + PSTATE pstate; //protocol-state + TSATE tstate; //tag-state + uint32_t uid; + uint8_t pages[64][4]; + uint64_t key; + uint8_t pwdl0, pwdl1, pwdh0; + //con0 + int max_page; + stype mode; + //con1 + bool auth; //0=Plain 1=Auth + bool TTFC; //Transponder Talks first coding. 0=Manchester 1=Biphase + int TTFDR; //data rate in TTF Mode + int TTFM; //the number of pages that are sent to the RWD + bool LCON; //0=con1/2 read write 1=con1 read only and con2 OTP + bool LKP; //0=page2/3 read write 1=page2/3 read only in Plain mode and no access in authenticate mode + //con2 + //0=read write 1=read only + bool LCK7; //page4/5 + bool LCK6; //page6/7 + bool LCK5; //page8-11 + bool LCK4; //page12-15 + bool LCK3; //page16-23 + bool LCK2; //page24-31 + bool LCK1; //page32-47 + bool LCK0; //page48-63 +} ; + +#endif diff --git a/include/hitag2.h b/include/hitag2.h deleted file mode 100644 index 2406c649..00000000 --- a/include/hitag2.h +++ /dev/null @@ -1,55 +0,0 @@ -//----------------------------------------------------------------------------- -// (c) 2012 Roel Verdult -// -// 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. -//----------------------------------------------------------------------------- -// Hitag2 type prototyping -//----------------------------------------------------------------------------- -// HitagS added -//----------------------------------------------------------------------------- - -#ifndef _HITAG2_H_ -#define _HITAG2_H_ - -#ifdef _MSC_VER -#define PACKED -#else -#define PACKED __attribute__((packed)) -#endif - -typedef enum { - RHTSF_CHALLENGE = 01, - RHTSF_KEY = 02, - WHTSF_CHALLENGE = 03, - WHTSF_KEY = 04, - RHT2F_PASSWORD = 21, - RHT2F_AUTHENTICATE = 22, - RHT2F_CRYPTO = 23, - WHT2F_CRYPTO = 24, - RHT2F_TEST_AUTH_ATTEMPTS = 25, - RHT2F_UID_ONLY = 26, -} hitag_function; - -typedef struct { - byte_t password[4]; -} PACKED rht2d_password; - -typedef struct { - byte_t NrAr[8]; - byte_t data[4]; -} PACKED rht2d_authenticate; - -typedef struct { - byte_t key[6]; - byte_t data[4]; -} PACKED rht2d_crypto; - -typedef union { - rht2d_password pwd; - rht2d_authenticate auth; - rht2d_crypto crypto; -} hitag_data; - -#endif diff --git a/include/hitagS.h b/include/hitagS.h deleted file mode 100644 index 6fd31841..00000000 --- a/include/hitagS.h +++ /dev/null @@ -1,51 +0,0 @@ -//----------------------------------------------------------------------------- -// 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. -//----------------------------------------------------------------------------- -// HitagS emulation (preliminary test version) -// -// (c) 2016 Oguzhan Cicek, Hendrik Schwartke, Ralf Spenneberg -// -//----------------------------------------------------------------------------- - - -#ifndef _HITAGS_H_ -#define _HITAGS_H_ - -#include "hitag2.h" - -typedef enum PROTO_STATE {READY=0,INIT,AUTHENTICATE,SELECTED,QUIET,TTF,FAIL} PSTATE; //protocol-state -typedef enum TAG_STATE {NO_OP=0,READING_PAGE,READING_BLOCK,WRITING_PAGE_ACK,WRITING_PAGE_DATA,WRITING_BLOCK_DATA} TSATE; //tag-state -typedef enum SOF_TYPE {STANDARD=0,ADVANCED,FAST_ADVANCED,ONE,NO_BITS} stype; //number of start-of-frame bits - -struct hitagS_tag { - PSTATE pstate; //protocol-state - TSATE tstate; //tag-state - uint32_t uid; - uint8_t pages[64][4]; - uint64_t key; - byte_t pwdl0,pwdl1,pwdh0; - //con0 - int max_page; - stype mode; - //con1 - bool auth; //0=Plain 1=Auth - bool TTFC; //Transponder Talks first coding. 0=Manchester 1=Biphase - int TTFDR; //data rate in TTF Mode - int TTFM; //the number of pages that are sent to the RWD - bool LCON; //0=con1/2 read write 1=con1 read only and con2 OTP - bool LKP; //0=page2/3 read write 1=page2/3 read only in Plain mode and no access in authenticate mode - //con2 - //0=read write 1=read only - bool LCK7; //page4/5 - bool LCK6; //page6/7 - bool LCK5; //page8-11 - bool LCK4; //page12-15 - bool LCK3; //page16-23 - bool LCK2; //page24-31 - bool LCK1; //page32-47 - bool LCK0; //page48-63 -} ; - -#endif From 3d057cfb918fb7e296cd27d6ced98008ea967753 Mon Sep 17 00:00:00 2001 From: Samson Gama Date: Thu, 14 Mar 2019 23:41:07 -0700 Subject: [PATCH 074/189] Added some LED utility functions (#802) --- armsrc/appmain.c | 7 ++----- armsrc/iclass.c | 5 +---- armsrc/util.c | 16 ++++++++++++++++ armsrc/util.h | 2 ++ 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 2a16f5f0..8824847e 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1490,11 +1490,8 @@ void __attribute__((noreturn)) AppMain(void) } common_area.flags.osimage_present = 1; - LED_D_OFF(); - LED_C_OFF(); - LED_B_OFF(); - LED_A_OFF(); - + LEDsoff(); + // Init USB device usb_enable(); diff --git a/armsrc/iclass.c b/armsrc/iclass.c index be7da703..83c9a75b 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -810,10 +810,7 @@ done: AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; Dbprintf("%x %x %x", maxBehindBy, Uart.state, Uart.byteCnt); Dbprintf("%x %x %x", Uart.byteCntMax, BigBuf_get_traceLen(), (int)Uart.output[0]); - LED_A_OFF(); - LED_B_OFF(); - LED_C_OFF(); - LED_D_OFF(); + LEDsoff(); } void rotateCSN(uint8_t* originalCSN, uint8_t* rotatedCSN) { diff --git a/armsrc/util.c b/armsrc/util.c index fbb6d489..aac68a34 100644 --- a/armsrc/util.c +++ b/armsrc/util.c @@ -89,6 +89,22 @@ void LEDsoff() LED_D_OFF(); } +void LEDson() +{ + LED_A_ON(); + LED_B_ON(); + LED_C_ON(); + LED_D_ON(); +} + +void LEDsinvert() +{ + LED_A_INV(); + LED_B_INV(); + LED_C_INV(); + LED_D_INV(); +} + // LEDs: R(C) O(A) G(B) -- R(D) [1, 2, 4 and 8] void LED(int led, int ms) { diff --git a/armsrc/util.h b/armsrc/util.h index fb50ecc8..da333e01 100644 --- a/armsrc/util.h +++ b/armsrc/util.h @@ -37,6 +37,8 @@ void lsl (uint8_t *data, size_t len); void LED(int led, int ms); void LEDsoff(); +void LEDson(); +void LEDsinvert(); int BUTTON_CLICKED(int ms); int BUTTON_HELD(int ms); void FormatVersionInformation(char *dst, int len, const char *prefix, void *version_information); From fdd9395d1a0f331f9cc74d6cdd6dd71447524e6c Mon Sep 17 00:00:00 2001 From: Oleg Moiseenko <807634+merlokk@users.noreply.github.com> Date: Tue, 19 Mar 2019 08:51:10 +0200 Subject: [PATCH 075/189] Ndef and MAD (#801) * move mifare stuff to separate folder * add mad and ndef --- CHANGELOG.md | 2 + client/Makefile | 8 +- client/cmdhf14a.c | 2 +- client/cmdhflist.c | 4 +- client/cmdhfmf.c | 206 ++- client/cmdhfmf.h | 3 +- client/cmdhfmfp.c | 324 ++-- client/cmdhfmfp.h | 2 +- client/mifare/mad.c | 256 ++++ client/mifare/mad.h | 29 + client/{ => mifare}/mfkey.c | 0 client/{ => mifare}/mfkey.h | 0 client/mifare/mifare4.c | 469 ++++++ client/{ => mifare}/mifare4.h | 9 + client/{ => mifare}/mifaredefault.h | 5 + client/{ => mifare}/mifarehost.c | 2201 ++++++++++++++------------- client/{ => mifare}/mifarehost.h | 138 +- client/mifare/ndef.c | 359 +++++ client/mifare/ndef.h | 62 + client/mifare4.c | 311 ---- client/obj/mifare/.dummy | 0 client/scripting.c | 2 +- common/crc.c | 24 + common/crc.h | 5 + include/mifare.h | 6 + tools/mfkey/Makefile | 2 +- tools/mfkey/mfkey32.c | 2 +- 27 files changed, 2843 insertions(+), 1588 deletions(-) create mode 100644 client/mifare/mad.c create mode 100644 client/mifare/mad.h rename client/{ => mifare}/mfkey.c (100%) rename client/{ => mifare}/mfkey.h (100%) create mode 100644 client/mifare/mifare4.c rename client/{ => mifare}/mifare4.h (65%) rename client/{ => mifare}/mifaredefault.h (70%) rename client/{ => mifare}/mifarehost.c (96%) rename client/{ => mifare}/mifarehost.h (96%) create mode 100644 client/mifare/ndef.c create mode 100644 client/mifare/ndef.h delete mode 100644 client/mifare4.c create mode 100644 client/obj/mifare/.dummy diff --git a/CHANGELOG.md b/CHANGELOG.md index c2bf52c5..50c33d0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added `hf 15 snoop` (piwi) - Added support for standard USB Smartcard Readers (piwi) - Added `hf plot` (piwi) +- Added `hf mfp mad` `hf mf mad` parsing MAD1 and MAD2 (Merlok) +- Added `hf mfp ndef` `hf mf ndef` parsing NDEF records (Merlok) ## [v3.1.0][2018-10-10] diff --git a/client/Makefile b/client/Makefile index 5fc1d226..2b5e9ae6 100644 --- a/client/Makefile +++ b/client/Makefile @@ -134,15 +134,17 @@ CMDSRCS = $(SRC_SMARTCARD) \ fido/cose.c \ fido/cbortools.c \ fido/fidocore.c \ - mfkey.c \ + mifare/mfkey.c \ loclass/cipher.c \ loclass/cipherutils.c \ loclass/ikeys.c \ loclass/elite_crack.c\ loclass/fileutils.c\ whereami.c\ - mifarehost.c\ - mifare4.c\ + mifare/mifarehost.c\ + mifare/mifare4.c\ + mifare/mad.c \ + mifare/ndef.c \ parity.c\ crc.c \ crc16.c \ diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 9611a2d1..90032022 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -27,7 +27,7 @@ #include "cmdmain.h" #include "mifare.h" #include "cmdhfmfu.h" -#include "mifarehost.h" +#include "mifare/mifarehost.h" #include "cliparser/cliparser.h" #include "emv/apduinfo.h" #include "emv/emvcore.h" diff --git a/client/cmdhflist.c b/client/cmdhflist.c index db3e5287..1aa501e6 100644 --- a/client/cmdhflist.c +++ b/client/cmdhflist.c @@ -24,8 +24,8 @@ #include "parity.h" #include "protocols.h" #include "crapto1/crapto1.h" -#include "mifarehost.h" -#include "mifaredefault.h" +#include "mifare/mifarehost.h" +#include "mifare/mifaredefault.h" #include "usb_cmd.h" #include "pcsc.h" diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 5bf3324a..1c006fbf 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -23,13 +23,16 @@ #include "util_posix.h" #include "usb_cmd.h" #include "ui.h" -#include "mifarehost.h" +#include "mifare/mifarehost.h" #include "mifare.h" -#include "mfkey.h" +#include "mifare/mfkey.h" #include "hardnested/hardnested_bf_core.h" #include "cliparser/cliparser.h" #include "cmdhf14a.h" -#include "mifare4.h" +#include "mifare/mifare4.h" +#include "mifare/mad.h" +#include "mifare/ndef.h" +#include "emv/dump.h" #define NESTED_SECTOR_RETRY 10 // how often we try mfested() until we give up @@ -2712,6 +2715,201 @@ int CmdHF14AMfAuth4(const char *cmd) { return MifareAuth4(NULL, keyn, key, true, false, true); } +// https://www.nxp.com/docs/en/application-note/AN10787.pdf +int CmdHF14AMfMAD(const char *cmd) { + + CLIParserInit("hf mf mad", + "Checks and prints Mifare Application Directory (MAD)", + "Usage:\n\thf mf mad -> shows MAD if exists\n" + "\thf mf mad -a 03e1 -k ffffffffffff -b -> shows NDEF data if exists. read card with custom key and key B\n"); + + void *argtable[] = { + arg_param_begin, + arg_lit0("vV", "verbose", "show technical data"), + arg_str0("aA", "aid", "print all sectors with aid", NULL), + arg_str0("kK", "key", "key for printing sectors", NULL), + arg_lit0("bB", "keyb", "use key B for access printing sectors (by default: key A)"), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, true); + bool verbose = arg_get_lit(1); + uint8_t aid[2] = {0}; + int aidlen; + CLIGetHexWithReturn(2, aid, &aidlen); + uint8_t key[6] = {0}; + int keylen; + CLIGetHexWithReturn(3, key, &keylen); + bool keyB = arg_get_lit(4); + + CLIParserFree(); + + if (aidlen != 2 && keylen > 0) { + PrintAndLogEx(WARNING, "do not need a key without aid."); + } + + uint8_t sector0[16 * 4] = {0}; + uint8_t sector10[16 * 4] = {0}; + if (mfReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector0)) { + PrintAndLogEx(ERR, "read sector 0 error. card don't have MAD or don't have MAD on default keys."); + return 2; + } + + if (verbose) { + for (int i = 0; i < 4; i ++) + PrintAndLogEx(NORMAL, "[%d] %s", i, sprint_hex(§or0[i * 16], 16)); + } + + bool haveMAD2 = false; + MAD1DecodeAndPrint(sector0, verbose, &haveMAD2); + + if (haveMAD2) { + if (mfReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector10)) { + PrintAndLogEx(ERR, "read sector 0x10 error. card don't have MAD or don't have MAD on default keys."); + return 2; + } + + MAD2DecodeAndPrint(sector10, verbose); + } + + if (aidlen == 2) { + uint16_t aaid = (aid[0] << 8) + aid[1]; + PrintAndLogEx(NORMAL, "\n-------------- AID 0x%04x ---------------", aaid); + + uint16_t mad[7 + 8 + 8 + 8 + 8] = {0}; + size_t madlen = 0; + if (MADDecode(sector0, sector10, mad, &madlen)) { + PrintAndLogEx(ERR, "can't decode mad."); + return 10; + } + + uint8_t akey[6] = {0}; + memcpy(akey, g_mifare_ndef_key, 6); + if (keylen == 6) { + memcpy(akey, key, 6); + } + + for (int i = 0; i < madlen; i++) { + if (aaid == mad[i]) { + uint8_t vsector[16 * 4] = {0}; + if (mfReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, akey, vsector)) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(ERR, "read sector %d error.", i + 1); + return 2; + } + + for (int j = 0; j < (verbose ? 4 : 3); j ++) + PrintAndLogEx(NORMAL, " [%03d] %s", (i + 1) * 4 + j, sprint_hex(&vsector[j * 16], 16)); + } + } + } + + return 0; +} + +int CmdHFMFNDEF(const char *cmd) { + + CLIParserInit("hf mf ndef", + "Prints NFC Data Exchange Format (NDEF)", + "Usage:\n\thf mf ndef -> shows NDEF data\n" + "\thf mf ndef -a 03e1 -k ffffffffffff -b -> shows NDEF data with custom AID, key and with key B\n"); + + void *argtable[] = { + arg_param_begin, + arg_litn("vV", "verbose", 0, 2, "show technical data"), + arg_str0("aA", "aid", "replace default aid for NDEF", NULL), + arg_str0("kK", "key", "replace default key for NDEF", NULL), + arg_lit0("bB", "keyb", "use key B for access sectors (by default: key A)"), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, true); + + bool verbose = arg_get_lit(1); + bool verbose2 = arg_get_lit(1) > 1; + uint8_t aid[2] = {0}; + int aidlen; + CLIGetHexWithReturn(2, aid, &aidlen); + uint8_t key[6] = {0}; + int keylen; + CLIGetHexWithReturn(3, key, &keylen); + bool keyB = arg_get_lit(4); + + CLIParserFree(); + + uint16_t ndefAID = 0x03e1; + if (aidlen == 2) + ndefAID = (aid[0] << 8) + aid[1]; + + uint8_t ndefkey[6] = {0}; + memcpy(ndefkey, g_mifare_ndef_key, 6); + if (keylen == 6) { + memcpy(ndefkey, key, 6); + } + + uint8_t sector0[16 * 4] = {0}; + uint8_t sector10[16 * 4] = {0}; + uint8_t data[4096] = {0}; + int datalen = 0; + + PrintAndLogEx(NORMAL, ""); + + if (mfReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector0)) { + PrintAndLogEx(ERR, "read sector 0 error. card don't have MAD or don't have MAD on default keys."); + return 2; + } + + bool haveMAD2 = false; + int res = MADCheck(sector0, NULL, verbose, &haveMAD2); + if (res) { + PrintAndLogEx(ERR, "MAD error %d.", res); + return res; + } + + if (haveMAD2) { + if (mfReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector10)) { + PrintAndLogEx(ERR, "read sector 0x10 error. card don't have MAD or don't have MAD on default keys."); + return 2; + } + } + + uint16_t mad[7 + 8 + 8 + 8 + 8] = {0}; + size_t madlen = 0; + if (MADDecode(sector0, (haveMAD2 ? sector10 : NULL), mad, &madlen)) { + PrintAndLogEx(ERR, "can't decode mad."); + return 10; + } + + printf("data reading:"); + for (int i = 0; i < madlen; i++) { + if (ndefAID == mad[i]) { + uint8_t vsector[16 * 4] = {0}; + if (mfReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, ndefkey, vsector)) { + PrintAndLogEx(ERR, "read sector %d error.", i + 1); + return 2; + } + + memcpy(&data[datalen], vsector, 16 * 3); + datalen += 16 * 3; + + printf("."); + } + } + printf(" OK\n"); + + if (!datalen) { + PrintAndLogEx(ERR, "no NDEF data."); + return 11; + } + + if (verbose2) { + PrintAndLogEx(NORMAL, "NDEF data:"); + dump_buffer(data, datalen, stdout, 1); + } + + NDEFDecodeAndPrint(data, datalen, verbose); + + return 0; +} + static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, @@ -2743,6 +2941,8 @@ static command_t CommandTable[] = {"cload", CmdHF14AMfCLoad, 0, "Load dump into magic Chinese card"}, {"csave", CmdHF14AMfCSave, 0, "Save dump from magic Chinese card into file or emulator"}, {"decrypt", CmdDecryptTraceCmds, 1, "[nt] [ar_enc] [at_enc] [data] - to decrypt snoop or trace"}, + {"mad", CmdHF14AMfMAD, 0, "Checks and prints MAD"}, + {"ndef", CmdHFMFNDEF, 0, "Prints NDEF records from card"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdhfmf.h b/client/cmdhfmf.h index 3bd3e95a..746fcbc1 100644 --- a/client/cmdhfmf.h +++ b/client/cmdhfmf.h @@ -11,8 +11,9 @@ #ifndef CMDHFMF_H__ #define CMDHFMF_H__ -#include "mifaredefault.h" +#include "mifare/mifaredefault.h" +extern int CmdHFMF(const char *Cmd); extern int CmdHFMF(const char *Cmd); extern int CmdHF14AMfDbg(const char* cmd); diff --git a/client/cmdhfmfp.c b/client/cmdhfmfp.c index 1e5bbe1a..5255e5a8 100644 --- a/client/cmdhfmfp.c +++ b/client/cmdhfmfp.c @@ -22,109 +22,17 @@ #include "ui.h" #include "cmdhf14a.h" #include "mifare.h" -#include "mifare4.h" +#include "mifare/mifare4.h" +#include "mifare/mad.h" +#include "mifare/ndef.h" #include "cliparser/cliparser.h" #include "crypto/libpcrypto.h" +#include "emv/dump.h" static const uint8_t DefaultKey[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -typedef struct { - uint8_t Code; - const char *Description; -} PlusErrorsElm; - -static const PlusErrorsElm PlusErrors[] = { - {0xFF, ""}, - {0x00, "Transfer cannot be granted within the current authentication."}, - {0x06, "Access Conditions not fulfilled. Block does not exist, block is not a value block."}, - {0x07, "Too many read or write commands in the session or in the transaction."}, - {0x08, "Invalid MAC in command or response"}, - {0x09, "Block Number is not valid"}, - {0x0a, "Invalid block number, not existing block number"}, - {0x0b, "The current command code not available at the current card state."}, - {0x0c, "Length error"}, - {0x0f, "General Manipulation Error. Failure in the operation of the PICC (cannot write to the data block), etc."}, - {0x90, "OK"}, -}; -int PlusErrorsLen = sizeof(PlusErrors) / sizeof(PlusErrorsElm); - -const char * GetErrorDescription(uint8_t errorCode) { - for(int i = 0; i < PlusErrorsLen; i++) - if (errorCode == PlusErrors[i].Code) - return PlusErrors[i].Description; - - return PlusErrors[0].Description; -} - static int CmdHelp(const char *Cmd); -static bool VerboseMode = false; -void SetVerboseMode(bool verbose) { - VerboseMode = verbose; -} - -int intExchangeRAW14aPlus(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { - if(VerboseMode) - PrintAndLog(">>> %s", sprint_hex(datain, datainlen)); - - int res = ExchangeRAW14a(datain, datainlen, activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); - - if(VerboseMode) - PrintAndLog("<<< %s", sprint_hex(dataout, *dataoutlen)); - - return res; -} - -int MFPWritePerso(uint8_t *keyNum, uint8_t *key, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { - uint8_t rcmd[3 + 16] = {0xa8, keyNum[1], keyNum[0], 0x00}; - memmove(&rcmd[3], key, 16); - - return intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); -} - -int MFPCommitPerso(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { - uint8_t rcmd[1] = {0xaa}; - - return intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); -} - -int MFPReadBlock(mf4Session *session, bool plain, uint8_t blockNum, uint8_t blockCount, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) { - uint8_t rcmd[4 + 8] = {(plain?(0x37):(0x33)), blockNum, 0x00, blockCount}; - if (!plain && session) - CalculateMAC(session, mtypReadCmd, blockNum, blockCount, rcmd, 4, &rcmd[4], VerboseMode); - - int res = intExchangeRAW14aPlus(rcmd, plain?4:sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); - if(res) - return res; - - if (session) - session->R_Ctr++; - - if(session && mac && *dataoutlen > 11) - CalculateMAC(session, mtypReadResp, blockNum, blockCount, dataout, *dataoutlen - 8 - 2, mac, VerboseMode); - - return 0; -} - -int MFPWriteBlock(mf4Session *session, uint8_t blockNum, uint8_t *data, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) { - uint8_t rcmd[1 + 2 + 16 + 8] = {0xA3, blockNum, 0x00}; - memmove(&rcmd[3], data, 16); - if (session) - CalculateMAC(session, mtypWriteCmd, blockNum, 1, rcmd, 19, &rcmd[19], VerboseMode); - - int res = intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); - if(res) - return res; - - if (session) - session->W_Ctr++; - - if(session && mac && *dataoutlen > 3) - CalculateMAC(session, mtypWriteResp, blockNum, 1, dataout, *dataoutlen, mac, VerboseMode); - - return 0; -} - int CmdHFMFPInfo(const char *cmd) { if (cmd && strlen(cmd) > 0) @@ -229,7 +137,7 @@ int CmdHFMFPWritePerso(const char *cmd) { CLIGetHexWithReturn(3, key, &keyLen); CLIParserFree(); - SetVerboseMode(verbose); + mfpSetVerboseMode(verbose); if (!keyLen) { memmove(key, DefaultKey, 16); @@ -260,7 +168,7 @@ int CmdHFMFPWritePerso(const char *cmd) { } if (data[0] != 0x90) { - PrintAndLog("Command error: %02x %s", data[0], GetErrorDescription(data[0])); + PrintAndLog("Command error: %02x %s", data[0], mfpGetErrorDescription(data[0])); return 1; } PrintAndLog("Write OK."); @@ -304,7 +212,7 @@ int CmdHFMFPInitPerso(const char *cmd) { if (!keyLen) memmove(key, DefaultKey, 16); - SetVerboseMode(verbose2); + mfpSetVerboseMode(verbose2); for (uint16_t sn = 0x4000; sn < 0x4050; sn++) { keyNum[0] = sn >> 8; keyNum[1] = sn & 0xff; @@ -319,7 +227,7 @@ int CmdHFMFPInitPerso(const char *cmd) { } } - SetVerboseMode(verbose); + mfpSetVerboseMode(verbose); for (int i = 0; i < sizeof(CardAddresses) / 2; i++) { keyNum[0] = CardAddresses[i] >> 8; keyNum[1] = CardAddresses[i] & 0xff; @@ -360,7 +268,7 @@ int CmdHFMFPCommitPerso(const char *cmd) { bool verbose = arg_get_lit(1); CLIParserFree(); - SetVerboseMode(verbose); + mfpSetVerboseMode(verbose); uint8_t data[250] = {0}; int datalen = 0; @@ -377,7 +285,7 @@ int CmdHFMFPCommitPerso(const char *cmd) { } if (data[0] != 0x90) { - PrintAndLog("Command error: %02x %s", data[0], GetErrorDescription(data[0])); + PrintAndLog("Command error: %02x %s", data[0], mfpGetErrorDescription(data[0])); return 1; } PrintAndLog("Switch level OK."); @@ -453,7 +361,7 @@ int CmdHFMFPRdbl(const char *cmd) { CLIGetHexWithReturn(6, key, &keylen); CLIParserFree(); - SetVerboseMode(verbose); + mfpSetVerboseMode(verbose); if (!keylen) { memmove(key, DefaultKey, 16); @@ -504,7 +412,7 @@ int CmdHFMFPRdbl(const char *cmd) { } if (datalen && data[0] != 0x90) { - PrintAndLog("Card read error: %02x %s", data[0], GetErrorDescription(data[0])); + PrintAndLog("Card read error: %02x %s", data[0], mfpGetErrorDescription(data[0])); return 6; } @@ -563,7 +471,7 @@ int CmdHFMFPRdsc(const char *cmd) { CLIGetHexWithReturn(5, key, &keylen); CLIParserFree(); - SetVerboseMode(verbose); + mfpSetVerboseMode(verbose); if (!keylen) { memmove(key, DefaultKey, 16); @@ -605,7 +513,7 @@ int CmdHFMFPRdsc(const char *cmd) { } if (datalen && data[0] != 0x90) { - PrintAndLog("Card read error: %02x %s", data[0], GetErrorDescription(data[0])); + PrintAndLog("Card read error: %02x %s", data[0], mfpGetErrorDescription(data[0])); DropField(); return 6; } @@ -661,7 +569,7 @@ int CmdHFMFPWrbl(const char *cmd) { CLIGetHexWithReturn(5, key, &keylen); CLIParserFree(); - SetVerboseMode(verbose); + mfpSetVerboseMode(verbose); if (!keylen) { memmove(key, DefaultKey, 16); @@ -714,7 +622,7 @@ int CmdHFMFPWrbl(const char *cmd) { } if (datalen && data[0] != 0x90) { - PrintAndLog("Card write error: %02x %s", data[0], GetErrorDescription(data[0])); + PrintAndLog("Card write error: %02x %s", data[0], mfpGetErrorDescription(data[0])); DropField(); return 6; } @@ -733,6 +641,204 @@ int CmdHFMFPWrbl(const char *cmd) { return 0; } +int CmdHFMFPMAD(const char *cmd) { + + CLIParserInit("hf mfp mad", + "Checks and prints Mifare Application Directory (MAD)", + "Usage:\n\thf mfp mad -> shows MAD if exists\n" + "\thf mfp mad -a 03e1 -k d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 -> shows NDEF data if exists\n"); + + void *argtable[] = { + arg_param_begin, + arg_lit0("vV", "verbose", "show technical data"), + arg_str0("aA", "aid", "print all sectors with aid", NULL), + arg_str0("kK", "key", "key for printing sectors", NULL), + arg_lit0("bB", "keyb", "use key B for access printing sectors (by default: key A)"), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, true); + + bool verbose = arg_get_lit(1); + uint8_t aid[2] = {0}; + int aidlen; + CLIGetHexWithReturn(2, aid, &aidlen); + uint8_t key[16] = {0}; + int keylen; + CLIGetHexWithReturn(3, key, &keylen); + bool keyB = arg_get_lit(4); + + CLIParserFree(); + + if (aidlen != 2 && keylen > 0) { + PrintAndLogEx(WARNING, "do not need a key without aid."); + } + + uint8_t sector0[16 * 4] = {0}; + uint8_t sector10[16 * 4] = {0}; + + if (mfpReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifarep_mad_key, sector0, verbose)) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(ERR, "read sector 0 error. card don't have MAD or don't have MAD on default keys."); + return 2; + } + + if (verbose) { + for (int i = 0; i < 4; i ++) + PrintAndLogEx(NORMAL, "[%d] %s", i, sprint_hex(§or0[i * 16], 16)); + } + + bool haveMAD2 = false; + MAD1DecodeAndPrint(sector0, verbose, &haveMAD2); + + if (haveMAD2) { + if (mfpReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifarep_mad_key, sector10, verbose)) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(ERR, "read sector 0x10 error. card don't have MAD or don't have MAD on default keys."); + return 2; + } + + MAD2DecodeAndPrint(sector10, verbose); + } + + if (aidlen == 2) { + uint16_t aaid = (aid[0] << 8) + aid[1]; + PrintAndLogEx(NORMAL, "\n-------------- AID 0x%04x ---------------", aaid); + + uint16_t mad[7 + 8 + 8 + 8 + 8] = {0}; + size_t madlen = 0; + if (MADDecode(sector0, sector10, mad, &madlen)) { + PrintAndLogEx(ERR, "can't decode mad."); + return 10; + } + + uint8_t akey[16] = {0}; + memcpy(akey, g_mifarep_ndef_key, 16); + if (keylen == 16) { + memcpy(akey, key, 16); + } + + for (int i = 0; i < madlen; i++) { + if (aaid == mad[i]) { + uint8_t vsector[16 * 4] = {0}; + if (mfpReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, akey, vsector, false)) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(ERR, "read sector %d error.", i + 1); + return 2; + } + + for (int j = 0; j < (verbose ? 4 : 3); j ++) + PrintAndLogEx(NORMAL, " [%03d] %s", (i + 1) * 4 + j, sprint_hex(&vsector[j * 16], 16)); + } + } + } + + return 0; +} + +int CmdHFMFPNDEF(const char *cmd) { + + CLIParserInit("hf mfp ndef", + "Prints NFC Data Exchange Format (NDEF)", + "Usage:\n\thf mfp ndef -> shows NDEF data\n" + "\thf mfp ndef -a 03e1 -k d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 -> shows NDEF data with custom AID and key\n"); + + void *argtable[] = { + arg_param_begin, + arg_litn("vV", "verbose", 0, 2, "show technical data"), + arg_str0("aA", "aid", "replace default aid for NDEF", NULL), + arg_str0("kK", "key", "replace default key for NDEF", NULL), + arg_lit0("bB", "keyb", "use key B for access sectors (by default: key A)"), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, true); + + bool verbose = arg_get_lit(1); + bool verbose2 = arg_get_lit(1) > 1; + uint8_t aid[2] = {0}; + int aidlen; + CLIGetHexWithReturn(2, aid, &aidlen); + uint8_t key[16] = {0}; + int keylen; + CLIGetHexWithReturn(3, key, &keylen); + bool keyB = arg_get_lit(4); + + CLIParserFree(); + + uint16_t ndefAID = 0x03e1; + if (aidlen == 2) + ndefAID = (aid[0] << 8) + aid[1]; + + uint8_t ndefkey[16] = {0}; + memcpy(ndefkey, g_mifarep_ndef_key, 16); + if (keylen == 16) { + memcpy(ndefkey, key, 16); + } + + uint8_t sector0[16 * 4] = {0}; + uint8_t sector10[16 * 4] = {0}; + uint8_t data[4096] = {0}; + int datalen = 0; + + PrintAndLogEx(NORMAL, ""); + + if (mfpReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifarep_mad_key, sector0, verbose)) { + PrintAndLogEx(ERR, "read sector 0 error. card don't have MAD or don't have MAD on default keys."); + return 2; + } + + bool haveMAD2 = false; + int res = MADCheck(sector0, NULL, verbose, &haveMAD2); + if (res) { + PrintAndLogEx(ERR, "MAD error %d.", res); + return res; + } + + if (haveMAD2) { + if (mfpReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifarep_mad_key, sector10, verbose)) { + PrintAndLogEx(ERR, "read sector 0x10 error. card don't have MAD or don't have MAD on default keys."); + return 2; + } + } + + uint16_t mad[7 + 8 + 8 + 8 + 8] = {0}; + size_t madlen = 0; + if (MADDecode(sector0, (haveMAD2 ? sector10 : NULL), mad, &madlen)) { + PrintAndLogEx(ERR, "can't decode mad."); + return 10; + } + + printf("data reading:"); + for (int i = 0; i < madlen; i++) { + if (ndefAID == mad[i]) { + uint8_t vsector[16 * 4] = {0}; + if (mfpReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, ndefkey, vsector, false)) { + PrintAndLogEx(ERR, "read sector %d error.", i + 1); + return 2; + } + + memcpy(&data[datalen], vsector, 16 * 3); + datalen += 16 * 3; + + printf("."); + } + } + printf(" OK\n"); + + if (!datalen) { + PrintAndLogEx(ERR, "no NDEF data."); + return 11; + } + + if (verbose2) { + PrintAndLogEx(NORMAL, "NDEF data:"); + dump_buffer(data, datalen, stdout, 1); + } + + NDEFDecodeAndPrint(data, datalen, verbose); + + return 0; +} + static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, @@ -744,6 +850,8 @@ static command_t CommandTable[] = {"rdbl", CmdHFMFPRdbl, 0, "Read blocks"}, {"rdsc", CmdHFMFPRdsc, 0, "Read sectors"}, {"wrbl", CmdHFMFPWrbl, 0, "Write blocks"}, + {"mad", CmdHFMFPMAD, 0, "Checks and prints MAD"}, + {"ndef", CmdHFMFPNDEF, 0, "Prints NDEF records from card"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdhfmfp.h b/client/cmdhfmfp.h index b1ac7c34..a5cacb51 100644 --- a/client/cmdhfmfp.h +++ b/client/cmdhfmfp.h @@ -10,7 +10,7 @@ #ifndef CMDHFMFP_H__ #define CMDHFMFP_H__ -#include "mifaredefault.h" +#include "mifare/mifaredefault.h" extern int CmdHFMFP(const char *Cmd); diff --git a/client/mifare/mad.c b/client/mifare/mad.c new file mode 100644 index 00000000..4c3d2102 --- /dev/null +++ b/client/mifare/mad.c @@ -0,0 +1,256 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2019 Merlok +// +// 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. +//----------------------------------------------------------------------------- +// MIFARE Application Directory (MAD) functions +//----------------------------------------------------------------------------- + +#include "mad.h" +#include "ui.h" +#include "crc.h" +#include "util.h" + +// https://www.nxp.com/docs/en/application-note/AN10787.pdf +static madAIDDescr madKnownAIDs[] = { + {0x0000, "free"}, + {0x0001, "defect, e.g. access keys are destroyed or unknown"}, + {0x0002, "reserved"}, + {0x0003, "contains additional directory info"}, + {0x0004, "contains card holder information in ASCII format."}, + {0x0005, "not applicable (above memory size)"}, + + {0x03e1, "NDEF"}, +}; + +static madAIDDescr madKnownClusterCodes[] = { + {0x00, "cluster: card administration"}, + {0x01, "cluster: miscellaneous applications"}, + {0x02, "cluster: miscellaneous applications"}, + {0x03, "cluster: miscellaneous applications"}, + {0x04, "cluster: miscellaneous applications"}, + {0x05, "cluster: miscellaneous applications"}, + {0x06, "cluster: miscellaneous applications"}, + {0x07, "cluster: miscellaneous applications"}, + {0x08, "cluster: airlines"}, + {0x09, "cluster: ferry traffic"}, + {0x10, "cluster: railway services"}, + {0x11, "cluster: miscellaneous applications"}, + {0x12, "cluster: transport"}, + {0x14, "cluster: security solutions"}, + {0x18, "cluster: city traffic"}, + {0x19, "cluster: Czech Railways"}, + {0x20, "cluster: bus services"}, + {0x21, "cluster: multi modal transit"}, + {0x28, "cluster: taxi"}, + {0x30, "cluster: road toll"}, + {0x31, "cluster: generic transport"}, + {0x38, "cluster: company services"}, + {0x40, "cluster: city card services"}, + {0x47, "cluster: access control & security"}, + {0x48, "cluster: access control & security"}, + {0x49, "cluster: VIGIK"}, + {0x4A, "cluster: Ministry of Defence, Netherlands"}, + {0x4B, "cluster: Bosch Telecom, Germany"}, + {0x4C, "cluster: European Union Institutions"}, + {0x50, "cluster: ski ticketing"}, + {0x51, "cluster: access control & security"}, + {0x52, "cluster: access control & security"}, + {0x53, "cluster: access control & security"}, + {0x54, "cluster: access control & security"}, + {0x55, "cluster: SOAA standard for offline access standard"}, + {0x56, "cluster: access control & security"}, + {0x58, "cluster: academic services"}, + {0x60, "cluster: food"}, + {0x68, "cluster: non-food trade"}, + {0x70, "cluster: hotel"}, + {0x71, "cluster: loyalty"}, + {0x75, "cluster: airport services"}, + {0x78, "cluster: car rental"}, + {0x79, "cluster: Dutch government"}, + {0x80, "cluster: administration services"}, + {0x88, "cluster: electronic purse"}, + {0x90, "cluster: television"}, + {0x91, "cluster: cruise ship"}, + {0x95, "cluster: IOPTA"}, + {0x97, "cluster: metering"}, + {0x98, "cluster: telephone"}, + {0xA0, "cluster: health services"}, + {0xA8, "cluster: warehouse"}, + {0xB0, "cluster: electronic trade"}, + {0xB8, "cluster: banking"}, + {0xC0, "cluster: entertainment & sports"}, + {0xC8, "cluster: car parking"}, + {0xC9, "cluster: fleet management"}, + {0xD0, "cluster: fuel, gasoline"}, + {0xD8, "cluster: info services"}, + {0xE0, "cluster: press"}, + {0xE1, "cluster: NFC Forum"}, + {0xE8, "cluster: computer"}, + {0xF0, "cluster: mail"}, + {0xF8, "cluster: miscellaneous applications"}, +}; + +static const char unknownAID[] = ""; + +static const char *GetAIDDescription(uint16_t AID) { + for (int i = 0; i < ARRAYLEN(madKnownAIDs); i++) + if (madKnownAIDs[i].AID == AID) + return madKnownAIDs[i].Description; + + for (int i = 0; i < ARRAYLEN(madKnownClusterCodes); i++) + if (madKnownClusterCodes[i].AID == (AID >> 8)) // high byte - cluster code + return madKnownClusterCodes[i].Description; + + return unknownAID; +} + +int madCRCCheck(uint8_t *sector, bool verbose, int MADver) { + if (MADver == 1) { + uint8_t crc = CRC8Mad(§or[16 + 1], 15 + 16); + if (crc != sector[16]) { + PrintAndLogEx(WARNING, "Wrong MAD%d CRC. Calculated: 0x%02x, from card: 0x%02x", MADver, crc, sector[16]); + return 3; + }; + } else { + uint8_t crc = CRC8Mad(§or[1], 15 + 16 + 16); + if (crc != sector[0]) { + PrintAndLogEx(WARNING, "Wrong MAD%d CRC. Calculated: 0x%02x, from card: 0x%02x", MADver, crc, sector[16]); + return 3; + }; + } + + return 0; +} + +uint16_t madGetAID(uint8_t *sector, int MADver, int sectorNo) { + if (MADver == 1) + return (sector[16 + 2 + (sectorNo - 1) * 2] << 8) + (sector[16 + 2 + (sectorNo - 1) * 2 + 1]); + else + return (sector[2 + (sectorNo - 1) * 2] << 8) + (sector[2 + (sectorNo - 1) * 2 + 1]); +} + +int MADCheck(uint8_t *sector0, uint8_t *sector10, bool verbose, bool *haveMAD2) { + int res = 0; + + if (!sector0) + return 1; + + uint8_t GPB = sector0[3 * 16 + 9]; + if (verbose) + PrintAndLogEx(NORMAL, "GPB: 0x%02x", GPB); + + // DA (MAD available) + if (!(GPB & 0x80)) { + PrintAndLogEx(ERR, "DA=0! MAD not available."); + return 1; + } + + // MA (multi-application card) + if (verbose) { + if (GPB & 0x40) + PrintAndLogEx(NORMAL, "Multi application card."); + else + PrintAndLogEx(NORMAL, "Single application card."); + } + + uint8_t MADVer = GPB & 0x03; + if (verbose) + PrintAndLogEx(NORMAL, "MAD version: %d", MADVer); + + // MAD version + if ((MADVer != 0x01) && (MADVer != 0x02)) { + PrintAndLogEx(ERR, "Wrong MAD version: 0x%02x", MADVer); + return 2; + }; + + if (haveMAD2) + *haveMAD2 = (MADVer == 2); + + res = madCRCCheck(sector0, true, 1); + + if (verbose && !res) + PrintAndLogEx(NORMAL, "CRC8-MAD1 OK."); + + if (MADVer == 2 && sector10) { + int res2 = madCRCCheck(sector10, true, 2); + if (!res) + res = res2; + + if (verbose & !res2) + PrintAndLogEx(NORMAL, "CRC8-MAD2 OK."); + } + + return res; +} + +int MADDecode(uint8_t *sector0, uint8_t *sector10, uint16_t *mad, size_t *madlen) { + *madlen = 0; + bool haveMAD2 = false; + MADCheck(sector0, sector10, false, &haveMAD2); + + for (int i = 1; i < 16; i++) { + mad[*madlen] = madGetAID(sector0, 1, i); + (*madlen)++; + } + + if (haveMAD2) { + // mad2 sector (0x10 == 16dec) here + mad[*madlen] = 0x0005; + (*madlen)++; + + for (int i = 1; i < 24; i++) { + mad[*madlen] = madGetAID(sector10, 2, i); + (*madlen)++; + } + } + + return 0; +} + + +int MAD1DecodeAndPrint(uint8_t *sector, bool verbose, bool *haveMAD2) { + + // check MAD1 only + MADCheck(sector, NULL, verbose, haveMAD2); + + // info byte + uint8_t InfoByte = sector[16 + 1] & 0x3f; + if (InfoByte) { + PrintAndLogEx(NORMAL, "Card publisher sector: 0x%02x", InfoByte); + } else { + if (verbose) + PrintAndLogEx(NORMAL, "Card publisher sector not present."); + } + if (InfoByte == 0x10 || InfoByte >= 0x28) + PrintAndLogEx(WARNING, "Info byte error"); + + PrintAndLogEx(NORMAL, "00 MAD1"); + for (int i = 1; i < 16; i++) { + uint16_t AID = madGetAID(sector, 1, i); + PrintAndLogEx(NORMAL, "%02d [%04X] %s", i, AID, GetAIDDescription(AID)); + }; + + return 0; +}; + +int MAD2DecodeAndPrint(uint8_t *sector, bool verbose) { + PrintAndLogEx(NORMAL, "16 MAD2"); + + int res = madCRCCheck(sector, true, 2); + + if (verbose && !res) + PrintAndLogEx(NORMAL, "CRC8-MAD2 OK."); + + uint8_t InfoByte = sector[1] & 0x3f; + PrintAndLogEx(NORMAL, "MAD2 Card publisher sector: 0x%02x", InfoByte); + + for (int i = 1; i < 8 + 8 + 7 + 1; i++) { + uint16_t AID = madGetAID(sector, 2, i); + PrintAndLogEx(NORMAL, "%02d [%04X] %s", i + 16, AID, GetAIDDescription(AID)); + }; + + return 0; +}; diff --git a/client/mifare/mad.h b/client/mifare/mad.h new file mode 100644 index 00000000..89fcd795 --- /dev/null +++ b/client/mifare/mad.h @@ -0,0 +1,29 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2019 Merlok +// +// 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. +//----------------------------------------------------------------------------- +// MIFARE Application Directory (MAD) functions +//----------------------------------------------------------------------------- + +#ifndef _MAD_H_ +#define _MAD_H_ + +#include +#include +#include + +typedef struct { + uint16_t AID; + const char *Description; +} madAIDDescr; + +extern int MADCheck(uint8_t *sector0, uint8_t *sector10, bool verbose, bool *haveMAD2); +extern int MADDecode(uint8_t *sector0, uint8_t *sector10, uint16_t *mad, size_t *madlen); +extern int MAD1DecodeAndPrint(uint8_t *sector, bool verbose, bool *haveMAD2); +extern int MAD2DecodeAndPrint(uint8_t *sector, bool verbose); + + +#endif // _MAD_H_ diff --git a/client/mfkey.c b/client/mifare/mfkey.c similarity index 100% rename from client/mfkey.c rename to client/mifare/mfkey.c diff --git a/client/mfkey.h b/client/mifare/mfkey.h similarity index 100% rename from client/mfkey.h rename to client/mifare/mfkey.h diff --git a/client/mifare/mifare4.c b/client/mifare/mifare4.c new file mode 100644 index 00000000..dfb137d8 --- /dev/null +++ b/client/mifare/mifare4.c @@ -0,0 +1,469 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2018 Merlok +// Copyright (C) 2018 drHatson +// +// 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. +//----------------------------------------------------------------------------- +// iso14443-4 mifare commands +//----------------------------------------------------------------------------- + +#include "mifare4.h" +#include +#include +#include "cmdhf14a.h" +#include "util.h" +#include "ui.h" +#include "crypto/libpcrypto.h" + +static bool VerboseMode = false; +void mfpSetVerboseMode(bool verbose) { + VerboseMode = verbose; +} + +typedef struct { + uint8_t Code; + const char *Description; +} PlusErrorsElm; + +static const PlusErrorsElm PlusErrors[] = { + {0xFF, ""}, + {0x00, "Transfer cannot be granted within the current authentication."}, + {0x06, "Access Conditions not fulfilled. Block does not exist, block is not a value block."}, + {0x07, "Too many read or write commands in the session or in the transaction."}, + {0x08, "Invalid MAC in command or response"}, + {0x09, "Block Number is not valid"}, + {0x0a, "Invalid block number, not existing block number"}, + {0x0b, "The current command code not available at the current card state."}, + {0x0c, "Length error"}, + {0x0f, "General Manipulation Error. Failure in the operation of the PICC (cannot write to the data block), etc."}, + {0x90, "OK"}, +}; +int PlusErrorsLen = sizeof(PlusErrors) / sizeof(PlusErrorsElm); + +const char *mfpGetErrorDescription(uint8_t errorCode) { + for (int i = 0; i < PlusErrorsLen; i++) + if (errorCode == PlusErrors[i].Code) + return PlusErrors[i].Description; + + return PlusErrors[0].Description; +} + +AccessConditions_t MFAccessConditions[] = { + {0x00, "read AB; write AB; increment AB; decrement transfer restore AB"}, + {0x01, "read AB; decrement transfer restore AB"}, + {0x02, "read AB"}, + {0x03, "read B; write B"}, + {0x04, "read AB; writeB"}, + {0x05, "read B"}, + {0x06, "read AB; write B; increment B; decrement transfer restore AB"}, + {0x07, "none"} +}; + +AccessConditions_t MFAccessConditionsTrailer[] = { + {0x00, "read A by A; read ACCESS by A; read B by A; write B by A"}, + {0x01, "write A by A; read ACCESS by A write ACCESS by A; read B by A; write B by A"}, + {0x02, "read ACCESS by A; read B by A"}, + {0x03, "write A by B; read ACCESS by AB; write ACCESS by B; write B by B"}, + {0x04, "write A by B; read ACCESS by AB; write B by B"}, + {0x05, "read ACCESS by AB; write ACCESS by B"}, + {0x06, "read ACCESS by AB"}, + {0x07, "read ACCESS by AB"} +}; + +char *mfGetAccessConditionsDesc(uint8_t blockn, uint8_t *data) { + static char StaticNone[] = "none"; + + uint8_t data1 = ((data[1] >> 4) & 0x0f) >> blockn; + uint8_t data2 = ((data[2]) & 0x0f) >> blockn; + uint8_t data3 = ((data[2] >> 4) & 0x0f) >> blockn; + + uint8_t cond = (data1 & 0x01) << 2 | (data2 & 0x01) << 1 | (data3 & 0x01); + + if (blockn == 3) { + for (int i = 0; i < ARRAYLEN(MFAccessConditionsTrailer); i++) + if (MFAccessConditionsTrailer[i].cond == cond) { + return MFAccessConditionsTrailer[i].description; + } + } else { + for (int i = 0; i < ARRAYLEN(MFAccessConditions); i++) + if (MFAccessConditions[i].cond == cond) { + return MFAccessConditions[i].description; + } + }; + + return StaticNone; +}; + +int CalculateEncIVCommand(mf4Session *session, uint8_t *iv, bool verbose) { + memcpy(&iv[0], session->TI, 4); + memcpy(&iv[4], &session->R_Ctr, 2); + memcpy(&iv[6], &session->W_Ctr, 2); + memcpy(&iv[8], &session->R_Ctr, 2); + memcpy(&iv[10], &session->W_Ctr, 2); + memcpy(&iv[12], &session->R_Ctr, 2); + memcpy(&iv[14], &session->W_Ctr, 2); + + return 0; +} + +int CalculateEncIVResponse(mf4Session *session, uint8_t *iv, bool verbose) { + memcpy(&iv[0], &session->R_Ctr, 2); + memcpy(&iv[2], &session->W_Ctr, 2); + memcpy(&iv[4], &session->R_Ctr, 2); + memcpy(&iv[6], &session->W_Ctr, 2); + memcpy(&iv[8], &session->R_Ctr, 2); + memcpy(&iv[10], &session->W_Ctr, 2); + memcpy(&iv[12], session->TI, 4); + + return 0; +} + + +int CalculateMAC(mf4Session *session, MACType_t mtype, uint8_t blockNum, uint8_t blockCount, uint8_t *data, int datalen, uint8_t *mac, bool verbose) { + if (!session || !session->Authenticated || !mac || !data || !datalen || datalen < 1) + return 1; + + memset(mac, 0x00, 8); + + uint16_t ctr = session->R_Ctr; + switch (mtype) { + case mtypWriteCmd: + case mtypWriteResp: + ctr = session->W_Ctr; + break; + case mtypReadCmd: + case mtypReadResp: + break; + } + + uint8_t macdata[2049] = {data[0], (ctr & 0xFF), (ctr >> 8), 0}; + int macdatalen = datalen; + memcpy(&macdata[3], session->TI, 4); + + switch (mtype) { + case mtypReadCmd: + memcpy(&macdata[7], &data[1], datalen - 1); + macdatalen = datalen + 6; + break; + case mtypReadResp: + macdata[7] = blockNum; + macdata[8] = 0; + macdata[9] = blockCount; + memcpy(&macdata[10], &data[1], datalen - 1); + macdatalen = datalen + 9; + break; + case mtypWriteCmd: + memcpy(&macdata[7], &data[1], datalen - 1); + macdatalen = datalen + 6; + break; + case mtypWriteResp: + macdatalen = 1 + 6; + break; + } + + if (verbose) + PrintAndLog("MAC data[%d]: %s", macdatalen, sprint_hex(macdata, macdatalen)); + + return aes_cmac8(NULL, session->Kmac, macdata, mac, macdatalen); +} + +int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool verbose) { + uint8_t data[257] = {0}; + int datalen = 0; + + uint8_t RndA[17] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00}; + uint8_t RndB[17] = {0}; + + if (session) + session->Authenticated = false; + + uint8_t cmd1[] = {0x70, keyn[1], keyn[0], 0x00}; + int res = ExchangeRAW14a(cmd1, sizeof(cmd1), activateField, true, data, sizeof(data), &datalen); + if (res) { + PrintAndLogEx(ERR, "Exchande raw error: %d", res); + DropField(); + return 2; + } + + if (verbose) + PrintAndLogEx(INFO, "phase2: %s", sprint_hex(cmd2, 33)); + + res = ExchangeRAW14a(cmd2, sizeof(cmd2), false, true, data, sizeof(data), &datalen); + if (res) { + PrintAndLogEx(ERR, "Exchande raw error: %d", res); + DropField(); + return 4; + } + + if (verbose) + PrintAndLogEx(INFO, "Authenticated = true; + session->R_Ctr = 0; + session->W_Ctr = 0; + session->KeyNum = keyn[1] + (keyn[0] << 8); + memmove(session->RndA, RndA, 16); + memmove(session->RndB, RndB, 16); + memmove(session->Key, key, 16); + memmove(session->TI, raw, 4); + memmove(session->PICCap2, &raw[20], 6); + memmove(session->PCDCap2, &raw[26], 6); + memmove(session->Kenc, kenc, 16); + memmove(session->Kmac, kmac, 16); + } + + if (verbose) + PrintAndLogEx(INFO, "Authentication OK"); + + return 0; +} + +int intExchangeRAW14aPlus(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { + if (VerboseMode) + PrintAndLogEx(INFO, ">>> %s", sprint_hex(datain, datainlen)); + + int res = ExchangeRAW14a(datain, datainlen, activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); + + if (VerboseMode) + PrintAndLogEx(INFO, "<<< %s", sprint_hex(dataout, *dataoutlen)); + + return res; +} + +int MFPWritePerso(uint8_t *keyNum, uint8_t *key, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { + uint8_t rcmd[3 + 16] = {0xa8, keyNum[1], keyNum[0], 0x00}; + memmove(&rcmd[3], key, 16); + + return intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); +} + +int MFPCommitPerso(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { + uint8_t rcmd[1] = {0xaa}; + + return intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); +} + +int MFPReadBlock(mf4Session *session, bool plain, uint8_t blockNum, uint8_t blockCount, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) { + uint8_t rcmd[4 + 8] = {(plain ? (0x37) : (0x33)), blockNum, 0x00, blockCount}; + if (!plain && session) + CalculateMAC(session, mtypReadCmd, blockNum, blockCount, rcmd, 4, &rcmd[4], VerboseMode); + + int res = intExchangeRAW14aPlus(rcmd, plain ? 4 : sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); + if (res) + return res; + + if (session) + session->R_Ctr++; + + if (session && mac && *dataoutlen > 11) + CalculateMAC(session, mtypReadResp, blockNum, blockCount, dataout, *dataoutlen - 8 - 2, mac, VerboseMode); + + return 0; +} + +int MFPWriteBlock(mf4Session *session, uint8_t blockNum, uint8_t *data, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) { + uint8_t rcmd[1 + 2 + 16 + 8] = {0xA3, blockNum, 0x00}; + memmove(&rcmd[3], data, 16); + if (session) + CalculateMAC(session, mtypWriteCmd, blockNum, 1, rcmd, 19, &rcmd[19], VerboseMode); + + int res = intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); + if (res) + return res; + + if (session) + session->W_Ctr++; + + if (session && mac && *dataoutlen > 3) + CalculateMAC(session, mtypWriteResp, blockNum, 1, dataout, *dataoutlen, mac, VerboseMode); + + return 0; +} + +int mfpReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *dataout, bool verbose) { + uint8_t keyn[2] = {0}; + bool plain = false; + + uint16_t uKeyNum = 0x4000 + sectorNo * 2 + (keyType ? 1 : 0); + keyn[0] = uKeyNum >> 8; + keyn[1] = uKeyNum & 0xff; + if (verbose) + PrintAndLogEx(INFO, "--sector[%d]:%02x key:%04x", mfNumBlocksPerSector(sectorNo), sectorNo, uKeyNum); + + mf4Session session; + int res = MifareAuth4(&session, keyn, key, true, true, verbose); + if (res) { + PrintAndLogEx(ERR, "Sector %d authentication error: %d", sectorNo, res); + return res; + } + + uint8_t data[250] = {0}; + int datalen = 0; + uint8_t mac[8] = {0}; + uint8_t firstBlockNo = mfFirstBlockOfSector(sectorNo); + for (int n = firstBlockNo; n < firstBlockNo + mfNumBlocksPerSector(sectorNo); n++) { + res = MFPReadBlock(&session, plain, n & 0xff, 1, false, true, data, sizeof(data), &datalen, mac); + if (res) { + PrintAndLogEx(ERR, "Sector %d read error: %d", sectorNo, res); + DropField(); + return res; + } + + if (datalen && data[0] != 0x90) { + PrintAndLogEx(ERR, "Sector %d card read error: %02x %s", sectorNo, data[0], mfpGetErrorDescription(data[0])); + DropField(); + return 5; + } + if (datalen != 1 + 16 + 8 + 2) { + PrintAndLogEx(ERR, "Sector %d error returned data length:%d", sectorNo, datalen); + DropField(); + return 6; + } + + memcpy(&dataout[(n - firstBlockNo) * 16], &data[1], 16); + + if (verbose) + PrintAndLogEx(INFO, "data[%03d]: %s", n, sprint_hex(&data[1], 16)); + + if (memcmp(&data[1 + 16], mac, 8)) { + PrintAndLogEx(WARNING, "WARNING: mac on block %d not equal...", n); + PrintAndLogEx(WARNING, "MAC card: %s", sprint_hex(&data[1 + 16], 8)); + PrintAndLogEx(WARNING, "MAC reader: %s", sprint_hex(mac, 8)); + + if (!verbose) + return 7; + } else { + if (verbose) + PrintAndLogEx(INFO, "MAC: %s", sprint_hex(&data[1 + 16], 8)); + } + } + DropField(); + + return 0; +} + +// Mifare Memory Structure: up to 32 Sectors with 4 blocks each (1k and 2k cards), +// plus evtl. 8 sectors with 16 blocks each (4k cards) +uint8_t mfNumBlocksPerSector(uint8_t sectorNo) { + if (sectorNo < 32) + return 4; + else + return 16; +} + +uint8_t mfFirstBlockOfSector(uint8_t sectorNo) { + if (sectorNo < 32) + return sectorNo * 4; + else + return 32 * 4 + (sectorNo - 32) * 16; +} + +uint8_t mfSectorTrailer(uint8_t blockNo) { + if (blockNo < 32 * 4) { + return (blockNo | 0x03); + } else { + return (blockNo | 0x0f); + } +} + +bool mfIsSectorTrailer(uint8_t blockNo) { + return (blockNo == mfSectorTrailer(blockNo)); +} + +uint8_t mfSectorNum(uint8_t blockNo) { + if (blockNo < 32 * 4) + return blockNo / 4; + else + return 32 + (blockNo - 32 * 4) / 16; + +} diff --git a/client/mifare4.h b/client/mifare/mifare4.h similarity index 65% rename from client/mifare4.h rename to client/mifare/mifare4.h index 5d9735da..0659bea3 100644 --- a/client/mifare4.h +++ b/client/mifare/mifare4.h @@ -43,9 +43,18 @@ typedef struct { char *description; } AccessConditions_t; +extern void mfpSetVerboseMode(bool verbose); +extern const char *mfpGetErrorDescription(uint8_t errorCode); + extern int CalculateMAC(mf4Session *session, MACType_t mtype, uint8_t blockNum, uint8_t blockCount, uint8_t *data, int datalen, uint8_t *mac, bool verbose); extern int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool verbose); +extern int MFPWritePerso(uint8_t *keyNum, uint8_t *key, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); +extern int MFPCommitPerso(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); +extern int MFPReadBlock(mf4Session *session, bool plain, uint8_t blockNum, uint8_t blockCount, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac); +extern int MFPWriteBlock(mf4Session *session, uint8_t blockNum, uint8_t *data, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac); +extern int mfpReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *dataout, bool verbose); + extern char *mfGetAccessConditionsDesc(uint8_t blockn, uint8_t *data); extern uint8_t mfNumBlocksPerSector(uint8_t sectorNo); diff --git a/client/mifaredefault.h b/client/mifare/mifaredefault.h similarity index 70% rename from client/mifaredefault.h rename to client/mifare/mifaredefault.h index 78231c86..55675bad 100644 --- a/client/mifaredefault.h +++ b/client/mifare/mifaredefault.h @@ -37,4 +37,9 @@ static const uint64_t MifareDefaultKeys[] = 0x8fd0a4f256e9 }; +static const uint8_t g_mifare_mad_key[] = {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5}; +static const uint8_t g_mifare_ndef_key[] = {0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7}; +static const uint8_t g_mifarep_mad_key[] = {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7}; +static const uint8_t g_mifarep_ndef_key[] = {0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7}; + #endif diff --git a/client/mifarehost.c b/client/mifare/mifarehost.c similarity index 96% rename from client/mifarehost.c rename to client/mifare/mifarehost.c index 9be04b4d..90c69878 100644 --- a/client/mifarehost.c +++ b/client/mifare/mifarehost.c @@ -1,1087 +1,1114 @@ -// Merlok, 2011, 2012 -// people from mifare@nethemba.com, 2010 -// -// 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. -//----------------------------------------------------------------------------- -// mifare commands -//----------------------------------------------------------------------------- - -#include "mifarehost.h" - -#include -#include -#include -#include - -#include "crapto1/crapto1.h" -#include "comms.h" -#include "usb_cmd.h" -#include "cmdmain.h" -#include "ui.h" -#include "parity.h" -#include "util.h" -#include "iso14443crc.h" - -#include "mifare.h" - -// mifare tracer flags used in mfTraceDecode() -#define TRACE_IDLE 0x00 -#define TRACE_AUTH1 0x01 -#define TRACE_AUTH2 0x02 -#define TRACE_AUTH_OK 0x03 -#define TRACE_READ_DATA 0x04 -#define TRACE_WRITE_OK 0x05 -#define TRACE_WRITE_DATA 0x06 -#define TRACE_ERROR 0xFF - - -static int compare_uint64(const void *a, const void *b) { - // didn't work: (the result is truncated to 32 bits) - //return (*(int64_t*)b - *(int64_t*)a); - - // better: - if (*(uint64_t*)b == *(uint64_t*)a) return 0; - else if (*(uint64_t*)b < *(uint64_t*)a) return 1; - else return -1; -} - - -// create the intersection (common members) of two sorted lists. Lists are terminated by -1. Result will be in list1. Number of elements is returned. -static uint32_t intersection(uint64_t *list1, uint64_t *list2) -{ - if (list1 == NULL || list2 == NULL) { - return 0; - } - uint64_t *p1, *p2, *p3; - p1 = p3 = list1; - p2 = list2; - - while ( *p1 != -1 && *p2 != -1 ) { - if (compare_uint64(p1, p2) == 0) { - *p3++ = *p1++; - p2++; - } - else { - while (compare_uint64(p1, p2) < 0) ++p1; - while (compare_uint64(p1, p2) > 0) ++p2; - } - } - *p3 = -1; - return p3 - list1; -} - - -// Darkside attack (hf mf mifare) -static uint32_t nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint32_t ar, uint64_t par_info, uint64_t ks_info, uint64_t **keys) { - struct Crypto1State *states; - uint32_t i, pos; - uint8_t bt, ks3x[8], par[8][8]; - uint64_t key_recovered; - uint64_t *keylist; - - // Reset the last three significant bits of the reader nonce - nr &= 0xffffff1f; - - for (pos=0; pos<8; pos++) { - ks3x[7-pos] = (ks_info >> (pos*8)) & 0x0f; - bt = (par_info >> (pos*8)) & 0xff; - for (i=0; i<8; i++) { - par[7-pos][i] = (bt >> i) & 0x01; - } - } - - states = lfsr_common_prefix(nr, ar, ks3x, par, (par_info == 0)); - - if (states == NULL) { - *keys = NULL; - return 0; - } - - keylist = (uint64_t*)states; - - for (i = 0; keylist[i]; i++) { - lfsr_rollback_word(states+i, uid^nt, 0); - crypto1_get_lfsr(states+i, &key_recovered); - keylist[i] = key_recovered; - } - keylist[i] = -1; - - *keys = keylist; - return i; -} - - -int mfDarkside(uint64_t *key) -{ - uint32_t uid = 0; - uint32_t nt = 0, nr = 0, ar = 0; - uint64_t par_list = 0, ks_list = 0; - uint64_t *keylist = NULL, *last_keylist = NULL; - uint32_t keycount = 0; - int16_t isOK = 0; - - UsbCommand c = {CMD_READER_MIFARE, {true, 0, 0}}; - - // message - printf("-------------------------------------------------------------------------\n"); - printf("Executing command. Expected execution time: 25sec on average\n"); - printf("Press button on the proxmark3 device to abort both proxmark3 and client.\n"); - printf("-------------------------------------------------------------------------\n"); - - - while (true) { - clearCommandBuffer(); - SendCommand(&c); - - //flush queue - while (ukbhit()) { - int c = getchar(); (void) c; - } - - // wait cycle - while (true) { - printf("."); - fflush(stdout); - if (ukbhit()) { - return -5; - break; - } - - UsbCommand resp; - if (WaitForResponseTimeout(CMD_ACK, &resp, 1000)) { - isOK = resp.arg[0]; - if (isOK < 0) { - return isOK; - } - uid = (uint32_t)bytes_to_num(resp.d.asBytes + 0, 4); - nt = (uint32_t)bytes_to_num(resp.d.asBytes + 4, 4); - par_list = bytes_to_num(resp.d.asBytes + 8, 8); - ks_list = bytes_to_num(resp.d.asBytes + 16, 8); - nr = (uint32_t)bytes_to_num(resp.d.asBytes + 24, 4); - ar = (uint32_t)bytes_to_num(resp.d.asBytes + 28, 4); - break; - } - } - - if (par_list == 0 && c.arg[0] == true) { - PrintAndLog("Parity is all zero. Most likely this card sends NACK on every failed authentication."); - } - c.arg[0] = false; - - keycount = nonce2key(uid, nt, nr, ar, par_list, ks_list, &keylist); - - if (keycount == 0) { - PrintAndLog("Key not found (lfsr_common_prefix list is null). Nt=%08x", nt); - PrintAndLog("This is expected to happen in 25%% of all cases. Trying again with a different reader nonce..."); - continue; - } - - if (par_list == 0) { - qsort(keylist, keycount, sizeof(*keylist), compare_uint64); - keycount = intersection(last_keylist, keylist); - if (keycount == 0) { - free(last_keylist); - last_keylist = keylist; - continue; - } - } - - if (keycount > 1) { - PrintAndLog("Found %u possible keys. Trying to authenticate with each of them ...\n", keycount); - } else { - PrintAndLog("Found a possible key. Trying to authenticate...\n"); - } - - *key = -1; - uint8_t keyBlock[USB_CMD_DATA_SIZE]; - int max_keys = USB_CMD_DATA_SIZE/6; - for (int i = 0; i < keycount; i += max_keys) { - int size = keycount - i > max_keys ? max_keys : keycount - i; - for (int j = 0; j < size; j++) { - if (par_list == 0) { - num_to_bytes(last_keylist[i*max_keys + j], 6, keyBlock+(j*6)); - } else { - num_to_bytes(keylist[i*max_keys + j], 6, keyBlock+(j*6)); - } - } - if (!mfCheckKeys(0, 0, false, size, keyBlock, key)) { - break; - } - } - - if (*key != -1) { - free(last_keylist); - free(keylist); - break; - } else { - PrintAndLog("Authentication failed. Trying again..."); - free(last_keylist); - last_keylist = keylist; - } - } - - return 0; -} - - -int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t * keyBlock, uint64_t * key){ - - *key = -1; - - UsbCommand c = {CMD_MIFARE_CHKKEYS, {((blockNo & 0xff) | ((keyType & 0xff) << 8)), clear_trace, keycnt}}; - memcpy(c.d.asBytes, keyBlock, 6 * keycnt); - SendCommand(&c); - - UsbCommand resp; - if (!WaitForResponseTimeout(CMD_ACK,&resp,3000)) return 1; - if ((resp.arg[0] & 0xff) != 0x01) return 2; - *key = bytes_to_num(resp.d.asBytes, 6); - return 0; -} - -int mfCheckKeysSec(uint8_t sectorCnt, uint8_t keyType, uint8_t timeout14a, bool clear_trace, uint8_t keycnt, uint8_t * keyBlock, sector_t * e_sector){ - - uint8_t keyPtr = 0; - - if (e_sector == NULL) - return -1; - - UsbCommand c = {CMD_MIFARE_CHKKEYS, {((sectorCnt & 0xff) | ((keyType & 0xff) << 8)), (clear_trace | 0x02)|((timeout14a & 0xff) << 8), keycnt}}; - memcpy(c.d.asBytes, keyBlock, 6 * keycnt); - SendCommand(&c); - - UsbCommand resp; - if (!WaitForResponseTimeoutW(CMD_ACK, &resp, MAX(3000, 1000 + 13 * sectorCnt * keycnt * (keyType == 2 ? 2 : 1)), false)) return 1; // timeout: 13 ms / fail auth - if ((resp.arg[0] & 0xff) != 0x01) return 2; - - bool foundAKey = false; - for(int sec = 0; sec < sectorCnt; sec++){ - for(int keyAB = 0; keyAB < 2; keyAB++){ - keyPtr = *(resp.d.asBytes + keyAB * 40 + sec); - if (keyPtr){ - e_sector[sec].foundKey[keyAB] = true; - e_sector[sec].Key[keyAB] = bytes_to_num(keyBlock + (keyPtr - 1) * 6, 6); - foundAKey = true; - } - } - } - return foundAKey ? 0 : 3; -} - -// Compare 16 Bits out of cryptostate -int Compare16Bits(const void * a, const void * b) { - if ((*(uint64_t*)b & 0x00ff000000ff0000) == (*(uint64_t*)a & 0x00ff000000ff0000)) return 0; - else if ((*(uint64_t*)b & 0x00ff000000ff0000) > (*(uint64_t*)a & 0x00ff000000ff0000)) return 1; - else return -1; -} - -typedef - struct { - union { - struct Crypto1State *slhead; - uint64_t *keyhead; - } head; - union { - struct Crypto1State *sltail; - uint64_t *keytail; - } tail; - uint32_t len; - uint32_t uid; - uint32_t blockNo; - uint32_t keyType; - uint32_t nt; - uint32_t ks1; - } StateList_t; - - -// wrapper function for multi-threaded lfsr_recovery32 -void -#ifdef __has_attribute -#if __has_attribute(force_align_arg_pointer) -__attribute__((force_align_arg_pointer)) -#endif -#endif -*nested_worker_thread(void *arg) -{ - struct Crypto1State *p1; - StateList_t *statelist = arg; - - statelist->head.slhead = lfsr_recovery32(statelist->ks1, statelist->nt ^ statelist->uid); - for (p1 = statelist->head.slhead; *(uint64_t *)p1 != 0; p1++); - statelist->len = p1 - statelist->head.slhead; - statelist->tail.sltail = --p1; - qsort(statelist->head.slhead, statelist->len, sizeof(uint64_t), Compare16Bits); - - return statelist->head.slhead; -} - - -int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *resultKey, bool calibrate) -{ - uint16_t i; - uint32_t uid; - UsbCommand resp; - - StateList_t statelists[2]; - struct Crypto1State *p1, *p2, *p3, *p4; - - // flush queue - (void)WaitForResponseTimeout(CMD_ACK,NULL,100); - - UsbCommand c = {CMD_MIFARE_NESTED, {blockNo + keyType * 0x100, trgBlockNo + trgKeyType * 0x100, calibrate}}; - memcpy(c.d.asBytes, key, 6); - SendCommand(&c); - - if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { - return -1; - } - - if (resp.arg[0]) { - return resp.arg[0]; // error during nested - } - - memcpy(&uid, resp.d.asBytes, 4); - PrintAndLog("uid:%08x trgbl=%d trgkey=%x", uid, (uint16_t)resp.arg[2] & 0xff, (uint16_t)resp.arg[2] >> 8); - - for (i = 0; i < 2; i++) { - statelists[i].blockNo = resp.arg[2] & 0xff; - statelists[i].keyType = (resp.arg[2] >> 8) & 0xff; - statelists[i].uid = uid; - memcpy(&statelists[i].nt, (void *)(resp.d.asBytes + 4 + i * 8 + 0), 4); - memcpy(&statelists[i].ks1, (void *)(resp.d.asBytes + 4 + i * 8 + 4), 4); - } - - // calc keys - - pthread_t thread_id[2]; - - // create and run worker threads - for (i = 0; i < 2; i++) { - pthread_create(thread_id + i, NULL, nested_worker_thread, &statelists[i]); - } - - // wait for threads to terminate: - for (i = 0; i < 2; i++) { - pthread_join(thread_id[i], (void*)&statelists[i].head.slhead); - } - - - // the first 16 Bits of the cryptostate already contain part of our key. - // Create the intersection of the two lists based on these 16 Bits and - // roll back the cryptostate - p1 = p3 = statelists[0].head.slhead; - p2 = p4 = statelists[1].head.slhead; - while (p1 <= statelists[0].tail.sltail && p2 <= statelists[1].tail.sltail) { - if (Compare16Bits(p1, p2) == 0) { - struct Crypto1State savestate, *savep = &savestate; - savestate = *p1; - while(Compare16Bits(p1, savep) == 0 && p1 <= statelists[0].tail.sltail) { - *p3 = *p1; - lfsr_rollback_word(p3, statelists[0].nt ^ statelists[0].uid, 0); - p3++; - p1++; - } - savestate = *p2; - while(Compare16Bits(p2, savep) == 0 && p2 <= statelists[1].tail.sltail) { - *p4 = *p2; - lfsr_rollback_word(p4, statelists[1].nt ^ statelists[1].uid, 0); - p4++; - p2++; - } - } - else { - while (Compare16Bits(p1, p2) == -1) p1++; - while (Compare16Bits(p1, p2) == 1) p2++; - } - } - *(uint64_t*)p3 = -1; - *(uint64_t*)p4 = -1; - statelists[0].len = p3 - statelists[0].head.slhead; - statelists[1].len = p4 - statelists[1].head.slhead; - statelists[0].tail.sltail=--p3; - statelists[1].tail.sltail=--p4; - - // the statelists now contain possible keys. The key we are searching for must be in the - // intersection of both lists. Create the intersection: - qsort(statelists[0].head.keyhead, statelists[0].len, sizeof(uint64_t), compare_uint64); - qsort(statelists[1].head.keyhead, statelists[1].len, sizeof(uint64_t), compare_uint64); - statelists[0].len = intersection(statelists[0].head.keyhead, statelists[1].head.keyhead); - - memset(resultKey, 0, 6); - // The list may still contain several key candidates. Test each of them with mfCheckKeys - for (i = 0; i < statelists[0].len; i++) { - uint8_t keyBlock[6]; - uint64_t key64; - crypto1_get_lfsr(statelists[0].head.slhead + i, &key64); - num_to_bytes(key64, 6, keyBlock); - key64 = 0; - if (!mfCheckKeys(statelists[0].blockNo, statelists[0].keyType, false, 1, keyBlock, &key64)) { - num_to_bytes(key64, 6, resultKey); - break; - } - } - - free(statelists[0].head.slhead); - free(statelists[1].head.slhead); - - return 0; -} - -// EMULATOR - -int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount) { - UsbCommand c = {CMD_MIFARE_EML_MEMGET, {blockNum, blocksCount, 0}}; - SendCommand(&c); - - UsbCommand resp; - if (!WaitForResponseTimeout(CMD_ACK,&resp,1500)) return 1; - memcpy(data, resp.d.asBytes, blocksCount * 16); - return 0; -} - -int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount) { - UsbCommand c = {CMD_MIFARE_EML_MEMSET, {blockNum, blocksCount, 0}}; - memcpy(c.d.asBytes, data, blocksCount * 16); - SendCommand(&c); - return 0; -} - -// "MAGIC" CARD - -int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params) { - uint8_t isOK = 0; - - UsbCommand c = {CMD_MIFARE_CGETBLOCK, {params, 0, blockNo}}; - SendCommand(&c); - - UsbCommand resp; - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - isOK = resp.arg[0] & 0xff; - memcpy(data, resp.d.asBytes, 16); - if (!isOK) return 2; - } else { - PrintAndLog("Command execute timeout"); - return 1; - } - return 0; -} - -int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, bool wantWipe, uint8_t params) { - - uint8_t isOK = 0; - UsbCommand c = {CMD_MIFARE_CSETBLOCK, {wantWipe, params & (0xFE | (uid == NULL ? 0:1)), blockNo}}; - memcpy(c.d.asBytes, data, 16); - SendCommand(&c); - - UsbCommand resp; - if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { - isOK = resp.arg[0] & 0xff; - if (uid != NULL) - memcpy(uid, resp.d.asBytes, 4); - if (!isOK) - return 2; - } else { - PrintAndLog("Command execute timeout"); - return 1; - } - - return 0; -} - -int mfCWipe(uint32_t numSectors, bool gen1b, bool wantWipe, bool wantFill) { - uint8_t isOK = 0; - uint8_t cmdParams = wantWipe + wantFill * 0x02 + gen1b * 0x04; - UsbCommand c = {CMD_MIFARE_CWIPE, {numSectors, cmdParams, 0}}; - SendCommand(&c); - - UsbCommand resp; - WaitForResponse(CMD_ACK,&resp); - isOK = resp.arg[0] & 0xff; - - return isOK; -} - -int mfCSetUID(uint8_t *uid, uint8_t *atqa, uint8_t *sak, uint8_t *oldUID) { - uint8_t oldblock0[16] = {0x00}; - uint8_t block0[16] = {0x00}; - int gen = 0, res; - - gen = mfCIdentify(); - - /* generation 1a magic card by default */ - uint8_t cmdParams = CSETBLOCK_SINGLE_OPER; - if (gen == 2) { - /* generation 1b magic card */ - cmdParams = CSETBLOCK_SINGLE_OPER | CSETBLOCK_MAGIC_1B; - } - - res = mfCGetBlock(0, oldblock0, cmdParams); - - if (res == 0) { - memcpy(block0, oldblock0, 16); - PrintAndLog("old block 0: %s", sprint_hex(block0,16)); - } else { - PrintAndLog("Couldn't get old data. Will write over the last bytes of Block 0."); - } - - // fill in the new values - // UID - memcpy(block0, uid, 4); - // Mifare UID BCC - block0[4] = block0[0] ^ block0[1] ^ block0[2] ^ block0[3]; - // mifare classic SAK(byte 5) and ATQA(byte 6 and 7, reversed) - if (sak != NULL) - block0[5] = sak[0]; - if (atqa != NULL) { - block0[6] = atqa[1]; - block0[7] = atqa[0]; - } - PrintAndLog("new block 0: %s", sprint_hex(block0, 16)); - - res = mfCSetBlock(0, block0, oldUID, false, cmdParams); - if (res) { - PrintAndLog("Can't set block 0. Error: %d", res); - return res; - } - - return 0; -} - -int mfCIdentify() { - UsbCommand c = {CMD_MIFARE_CIDENT, {0, 0, 0}}; - SendCommand(&c); - UsbCommand resp; - WaitForResponse(CMD_ACK,&resp); - - uint8_t isGeneration = resp.arg[0] & 0xff; - switch( isGeneration ){ - case 1: PrintAndLog("Chinese magic backdoor commands (GEN 1a) detected"); break; - case 2: PrintAndLog("Chinese magic backdoor command (GEN 1b) detected"); break; - default: PrintAndLog("No chinese magic backdoor command detected"); break; - } - - return (int) isGeneration; -} - - -// SNIFFER - -// constants -static uint8_t trailerAccessBytes[4] = {0x08, 0x77, 0x8F, 0x00}; - -// variables -char logHexFileName[FILE_PATH_SIZE] = {0x00}; -static uint8_t traceCard[4096] = {0x00}; -static char traceFileName[FILE_PATH_SIZE] = {0x00}; -static int traceState = TRACE_IDLE; -static uint8_t traceCurBlock = 0; -static uint8_t traceCurKey = 0; - -struct Crypto1State *traceCrypto1 = NULL; - -struct Crypto1State *revstate; -uint64_t lfsr; -uint64_t ui64Key; -uint32_t ks2; -uint32_t ks3; - -uint32_t uid; // serial number -uint32_t nt; // tag challenge -uint32_t nt_enc; // encrypted tag challenge -uint8_t nt_enc_par; // encrypted tag challenge parity -uint32_t nr_enc; // encrypted reader challenge -uint32_t ar_enc; // encrypted reader response -uint8_t ar_enc_par; // encrypted reader response parity -uint32_t at_enc; // encrypted tag response -uint8_t at_enc_par; // encrypted tag response parity - -int isTraceCardEmpty(void) { - return ((traceCard[0] == 0) && (traceCard[1] == 0) && (traceCard[2] == 0) && (traceCard[3] == 0)); -} - -int isBlockEmpty(int blockN) { - for (int i = 0; i < 16; i++) - if (traceCard[blockN * 16 + i] != 0) return 0; - - return 1; -} - -int isBlockTrailer(int blockN) { - return ((blockN & 0x03) == 0x03); -} - -int saveTraceCard(void) { - FILE * f; - - if ((!strlen(traceFileName)) || (isTraceCardEmpty())) return 0; - - f = fopen(traceFileName, "w+"); - if ( !f ) return 1; - - for (int i = 0; i < 64; i++) { // blocks - for (int j = 0; j < 16; j++) // bytes - fprintf(f, "%02x", *(traceCard + i * 16 + j)); - if (i < 63) - fprintf(f,"\n"); - } - fclose(f); - return 0; -} - -int loadTraceCard(uint8_t *tuid) { - FILE * f; - char buf[64] = {0x00}; - uint8_t buf8[64] = {0x00}; - int i, blockNum; - - if (!isTraceCardEmpty()) - saveTraceCard(); - - memset(traceCard, 0x00, 4096); - memcpy(traceCard, tuid + 3, 4); - - FillFileNameByUID(traceFileName, tuid, ".eml", 7); - - f = fopen(traceFileName, "r"); - if (!f) return 1; - - blockNum = 0; - - while(!feof(f)){ - - memset(buf, 0, sizeof(buf)); - if (fgets(buf, sizeof(buf), f) == NULL) { - PrintAndLog("File reading error."); - fclose(f); - return 2; - } - - if (strlen(buf) < 32){ - if (feof(f)) break; - PrintAndLog("File content error. Block data must include 32 HEX symbols"); - fclose(f); - return 2; - } - for (i = 0; i < 32; i += 2) - sscanf(&buf[i], "%02x", (unsigned int *)&buf8[i / 2]); - - memcpy(traceCard + blockNum * 16, buf8, 16); - - blockNum++; - } - fclose(f); - - return 0; -} - -int mfTraceInit(uint8_t *tuid, uint8_t *atqa, uint8_t sak, bool wantSaveToEmlFile) { - - if (traceCrypto1) - crypto1_destroy(traceCrypto1); - - traceCrypto1 = NULL; - - if (wantSaveToEmlFile) - loadTraceCard(tuid); - - traceCard[4] = traceCard[0] ^ traceCard[1] ^ traceCard[2] ^ traceCard[3]; - traceCard[5] = sak; - memcpy(&traceCard[6], atqa, 2); - traceCurBlock = 0; - uid = bytes_to_num(tuid + 3, 4); - - traceState = TRACE_IDLE; - - return 0; -} - -void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len, bool isEncrypted){ - uint8_t bt = 0; - int i; - - if (len != 1) { - for (i = 0; i < len; i++) - data[i] = crypto1_byte(pcs, 0x00, isEncrypted) ^ data[i]; - } else { - bt = 0; - for (i = 0; i < 4; i++) - bt |= (crypto1_bit(pcs, 0, isEncrypted) ^ BIT(data[0], i)) << i; - - data[0] = bt; - } - return; -} - -bool NTParityCheck(uint32_t ntx) { - if ( - (oddparity8(ntx >> 8 & 0xff) ^ (ntx & 0x01) ^ ((nt_enc_par >> 5) & 0x01) ^ (nt_enc & 0x01)) || - (oddparity8(ntx >> 16 & 0xff) ^ (ntx >> 8 & 0x01) ^ ((nt_enc_par >> 6) & 0x01) ^ (nt_enc >> 8 & 0x01)) || - (oddparity8(ntx >> 24 & 0xff) ^ (ntx >> 16 & 0x01) ^ ((nt_enc_par >> 7) & 0x01) ^ (nt_enc >> 16 & 0x01)) - ) - return false; - - uint32_t ar = prng_successor(ntx, 64); - if ( - (oddparity8(ar >> 8 & 0xff) ^ (ar & 0x01) ^ ((ar_enc_par >> 5) & 0x01) ^ (ar_enc & 0x01)) || - (oddparity8(ar >> 16 & 0xff) ^ (ar >> 8 & 0x01) ^ ((ar_enc_par >> 6) & 0x01) ^ (ar_enc >> 8 & 0x01)) || - (oddparity8(ar >> 24 & 0xff) ^ (ar >> 16 & 0x01) ^ ((ar_enc_par >> 7) & 0x01) ^ (ar_enc >> 16 & 0x01)) - ) - return false; - - uint32_t at = prng_successor(ntx, 96); - if ( - (oddparity8(ar & 0xff) ^ (at >> 24 & 0x01) ^ ((ar_enc_par >> 4) & 0x01) ^ (at_enc >> 24 & 0x01)) || - (oddparity8(at >> 8 & 0xff) ^ (at & 0x01) ^ ((at_enc_par >> 5) & 0x01) ^ (at_enc & 0x01)) || - (oddparity8(at >> 16 & 0xff) ^ (at >> 8 & 0x01) ^ ((at_enc_par >> 6) & 0x01) ^ (at_enc >> 8 & 0x01)) || - (oddparity8(at >> 24 & 0xff) ^ (at >> 16 & 0x01) ^ ((at_enc_par >> 7) & 0x01) ^ (at_enc >> 16 & 0x01)) - ) - return false; - - return true; -} - - -int mfTraceDecode(uint8_t *data_src, int len, uint8_t parity, bool wantSaveToEmlFile) { - uint8_t data[64]; - - if (traceState == TRACE_ERROR) return 1; - if (len > 64) { - traceState = TRACE_ERROR; - return 1; - } - - memcpy(data, data_src, len); - if ((traceCrypto1) && ((traceState == TRACE_IDLE) || (traceState > TRACE_AUTH_OK))) { - mf_crypto1_decrypt(traceCrypto1, data, len, 0); - uint8_t parity[16]; - oddparitybuf(data, len, parity); - PrintAndLog("dec> %s [%s]", sprint_hex(data, len), printBitsPar(parity, len)); - AddLogHex(logHexFileName, "dec> ", data, len); - } - - switch (traceState) { - case TRACE_IDLE: - // check packet crc16! - if ((len >= 4) && (!CheckCrc14443(CRC_14443_A, data, len))) { - PrintAndLog("dec> CRC ERROR!!!"); - AddLogLine(logHexFileName, "dec> ", "CRC ERROR!!!"); - traceState = TRACE_ERROR; // do not decrypt the next commands - return 1; - } - - // AUTHENTICATION - if ((len ==4) && ((data[0] == 0x60) || (data[0] == 0x61))) { - traceState = TRACE_AUTH1; - traceCurBlock = data[1]; - traceCurKey = data[0] == 60 ? 1:0; - return 0; - } - - // READ - if ((len ==4) && ((data[0] == 0x30))) { - traceState = TRACE_READ_DATA; - traceCurBlock = data[1]; - return 0; - } - - // WRITE - if ((len ==4) && ((data[0] == 0xA0))) { - traceState = TRACE_WRITE_OK; - traceCurBlock = data[1]; - return 0; - } - - // HALT - if ((len ==4) && ((data[0] == 0x50) && (data[1] == 0x00))) { - traceState = TRACE_ERROR; // do not decrypt the next commands - return 0; - } - - return 0; - break; - - case TRACE_READ_DATA: - if (len == 18) { - traceState = TRACE_IDLE; - - if (isBlockTrailer(traceCurBlock)) { - memcpy(traceCard + traceCurBlock * 16 + 6, data + 6, 4); - } else { - memcpy(traceCard + traceCurBlock * 16, data, 16); - } - if (wantSaveToEmlFile) saveTraceCard(); - return 0; - } else { - traceState = TRACE_ERROR; - return 1; - } - break; - - case TRACE_WRITE_OK: - if ((len == 1) && (data[0] == 0x0a)) { - traceState = TRACE_WRITE_DATA; - - return 0; - } else { - traceState = TRACE_ERROR; - return 1; - } - break; - - case TRACE_WRITE_DATA: - if (len == 18) { - traceState = TRACE_IDLE; - - memcpy(traceCard + traceCurBlock * 16, data, 16); - if (wantSaveToEmlFile) saveTraceCard(); - return 0; - } else { - traceState = TRACE_ERROR; - return 1; - } - break; - - case TRACE_AUTH1: - if (len == 4) { - traceState = TRACE_AUTH2; - if (!traceCrypto1) { - nt = bytes_to_num(data, 4); - } else { - nt_enc = bytes_to_num(data, 4); - nt_enc_par = parity; - } - return 0; - } else { - traceState = TRACE_ERROR; - return 1; - } - break; - - case TRACE_AUTH2: - if (len == 8) { - traceState = TRACE_AUTH_OK; - - nr_enc = bytes_to_num(data, 4); - ar_enc = bytes_to_num(data + 4, 4); - ar_enc_par = parity << 4; - return 0; - } else { - traceState = TRACE_ERROR; - return 1; - } - break; - - case TRACE_AUTH_OK: - if (len ==4) { - traceState = TRACE_IDLE; - - at_enc = bytes_to_num(data, 4); - at_enc_par = parity; - if (!traceCrypto1) { - - // decode key here) - ks2 = ar_enc ^ prng_successor(nt, 64); - ks3 = at_enc ^ prng_successor(nt, 96); - revstate = lfsr_recovery64(ks2, ks3); - lfsr_rollback_word(revstate, 0, 0); - lfsr_rollback_word(revstate, 0, 0); - lfsr_rollback_word(revstate, nr_enc, 1); - lfsr_rollback_word(revstate, uid ^ nt, 0); - - crypto1_get_lfsr(revstate, &lfsr); - crypto1_destroy(revstate); - ui64Key = lfsr; - printf("key> probable key:%x%x Prng:%s ks2:%08x ks3:%08x\n", - (unsigned int)((lfsr & 0xFFFFFFFF00000000) >> 32), (unsigned int)(lfsr & 0xFFFFFFFF), - validate_prng_nonce(nt) ? "WEAK": "HARDEND", - ks2, - ks3); - AddLogUint64(logHexFileName, "key> ", lfsr); - } else { - if (validate_prng_nonce(nt)) { - struct Crypto1State *pcs; - pcs = crypto1_create(ui64Key); - uint32_t nt1 = crypto1_word(pcs, nt_enc ^ uid, 1) ^ nt_enc; - uint32_t ar = prng_successor(nt1, 64); - uint32_t at = prng_successor(nt1, 96); - printf("key> nested auth uid: %08x nt: %08x nt_parity: %s ar: %08x at: %08x\n", uid, nt1, printBitsPar(&nt_enc_par, 4), ar, at); - uint32_t nr1 = crypto1_word(pcs, nr_enc, 1) ^ nr_enc; - uint32_t ar1 = crypto1_word(pcs, 0, 0) ^ ar_enc; - uint32_t at1 = crypto1_word(pcs, 0, 0) ^ at_enc; - crypto1_destroy(pcs); - printf("key> the same key test. nr1: %08x ar1: %08x at1: %08x \n", nr1, ar1, at1); - - if (NTParityCheck(nt1)) - printf("key> the same key test OK. key=%x%x\n", (unsigned int)((ui64Key & 0xFFFFFFFF00000000) >> 32), (unsigned int)(ui64Key & 0xFFFFFFFF)); - else - printf("key> the same key test. check nt parity error.\n"); - - uint32_t ntc = prng_successor(nt, 90); - uint32_t ntx = 0; - int ntcnt = 0; - for (int i = 0; i < 16383; i++) { - ntc = prng_successor(ntc, 1); - if (NTParityCheck(ntc)){ - if (!ntcnt) - ntx = ntc; - ntcnt++; - } - } - if (ntcnt) - printf("key> nt candidate=%08x nonce distance=%d candidates count=%d\n", ntx, nonce_distance(nt, ntx), ntcnt); - else - printf("key> don't have any nt candidate( \n"); - - nt = ntx; - ks2 = ar_enc ^ prng_successor(ntx, 64); - ks3 = at_enc ^ prng_successor(ntx, 96); - - // decode key - revstate = lfsr_recovery64(ks2, ks3); - lfsr_rollback_word(revstate, 0, 0); - lfsr_rollback_word(revstate, 0, 0); - lfsr_rollback_word(revstate, nr_enc, 1); - lfsr_rollback_word(revstate, uid ^ nt, 0); - - crypto1_get_lfsr(revstate, &lfsr); - crypto1_destroy(revstate); - ui64Key = lfsr; - printf("key> probable key:%x%x ks2:%08x ks3:%08x\n", - (unsigned int)((lfsr & 0xFFFFFFFF00000000) >> 32), (unsigned int)(lfsr & 0xFFFFFFFF), - ks2, - ks3); - AddLogUint64(logHexFileName, "key> ", lfsr); - } else { - printf("key> hardnested not implemented!\n"); - - crypto1_destroy(traceCrypto1); - - // not implemented - traceState = TRACE_ERROR; - } - } - - int blockShift = ((traceCurBlock & 0xFC) + 3) * 16; - if (isBlockEmpty((traceCurBlock & 0xFC) + 3)) memcpy(traceCard + blockShift + 6, trailerAccessBytes, 4); - - if (traceCurKey) { - num_to_bytes(lfsr, 6, traceCard + blockShift + 10); - } else { - num_to_bytes(lfsr, 6, traceCard + blockShift); - } - if (wantSaveToEmlFile) saveTraceCard(); - - if (traceCrypto1) { - crypto1_destroy(traceCrypto1); - } - - // set cryptosystem state - traceCrypto1 = lfsr_recovery64(ks2, ks3); - return 0; - } else { - traceState = TRACE_ERROR; - return 1; - } - break; - - default: - traceState = TRACE_ERROR; - return 1; - } - - return 0; -} - -// DECODING - -int tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, int len){ - /* - uint32_t nt; // tag challenge - uint32_t ar_enc; // encrypted reader response - uint32_t at_enc; // encrypted tag response - */ - if (traceCrypto1) { - crypto1_destroy(traceCrypto1); - } - ks2 = ar_enc ^ prng_successor(nt, 64); - ks3 = at_enc ^ prng_successor(nt, 96); - traceCrypto1 = lfsr_recovery64(ks2, ks3); - - mf_crypto1_decrypt(traceCrypto1, data, len, 0); - - PrintAndLog("Decrypted data: [%s]", sprint_hex(data,len) ); - crypto1_destroy(traceCrypto1); - return 0; -} - -/** validate_prng_nonce - * Determine if nonce is deterministic. ie: Suspectable to Darkside attack. - * returns - * true = weak prng - * false = hardend prng - */ -bool validate_prng_nonce(uint32_t nonce) { - uint16_t *dist = 0; - uint16_t x, i; - - dist = malloc(2 << 16); - if(!dist) - return -1; - - // init prng table: - for (x = i = 1; i; ++i) { - dist[(x & 0xff) << 8 | x >> 8] = i; - x = x >> 1 | (x ^ x >> 2 ^ x >> 3 ^ x >> 5) << 15; - } - - uint32_t res = (65535 - dist[nonce >> 16] + dist[nonce & 0xffff]) % 65535; - - free(dist); - return (res == 16); -} - -/* Detect Tag Prng, -* function performs a partial AUTH, where it tries to authenticate against block0, key A, but only collects tag nonce. -* the tag nonce is check to see if it has a predictable PRNG. -* @returns -* TRUE if tag uses WEAK prng (ie Now the NACK bug also needs to be present for Darkside attack) -* FALSE is tag uses HARDEND prng (ie hardnested attack possible, with known key) -*/ -int DetectClassicPrng(void){ - - UsbCommand resp, respA; - uint8_t cmd[] = {0x60, 0x00}; // MIFARE_AUTH_KEYA - uint32_t flags = ISO14A_CONNECT | ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_RATS; - - UsbCommand c = {CMD_READER_ISO_14443a, {flags, sizeof(cmd), 0}}; - memcpy(c.d.asBytes, cmd, sizeof(cmd)); - - clearCommandBuffer(); - SendCommand(&c); - if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { - PrintAndLog("PRNG UID: Reply timeout."); - return -1; - } - - // if select tag failed. - if (resp.arg[0] == 0) { - PrintAndLog("PRNG error: selecting tag failed, can't detect prng."); - return -1; - } - - if (!WaitForResponseTimeout(CMD_ACK, &respA, 5000)) { - PrintAndLog("PRNG data: Reply timeout."); - return -1; - } - - // check respA - if (respA.arg[0] != 4) { - PrintAndLog("PRNG data error: Wrong length: %d", respA.arg[0]); - return -1; - } - - uint32_t nonce = bytes_to_num(respA.d.asBytes, respA.arg[0]); - return validate_prng_nonce(nonce); -} +// Merlok, 2011, 2012 +// people from mifare@nethemba.com, 2010 +// +// 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. +//----------------------------------------------------------------------------- +// mifare commands +//----------------------------------------------------------------------------- + +#include "mifarehost.h" + +#include +#include +#include +#include + +#include "crapto1/crapto1.h" +#include "comms.h" +#include "usb_cmd.h" +#include "cmdmain.h" +#include "ui.h" +#include "parity.h" +#include "util.h" +#include "iso14443crc.h" + +#include "mifare.h" +#include "mifare4.h" + +// mifare tracer flags used in mfTraceDecode() +#define TRACE_IDLE 0x00 +#define TRACE_AUTH1 0x01 +#define TRACE_AUTH2 0x02 +#define TRACE_AUTH_OK 0x03 +#define TRACE_READ_DATA 0x04 +#define TRACE_WRITE_OK 0x05 +#define TRACE_WRITE_DATA 0x06 +#define TRACE_ERROR 0xFF + + +static int compare_uint64(const void *a, const void *b) { + // didn't work: (the result is truncated to 32 bits) + //return (*(int64_t*)b - *(int64_t*)a); + + // better: + if (*(uint64_t*)b == *(uint64_t*)a) return 0; + else if (*(uint64_t*)b < *(uint64_t*)a) return 1; + else return -1; +} + + +// create the intersection (common members) of two sorted lists. Lists are terminated by -1. Result will be in list1. Number of elements is returned. +static uint32_t intersection(uint64_t *list1, uint64_t *list2) +{ + if (list1 == NULL || list2 == NULL) { + return 0; + } + uint64_t *p1, *p2, *p3; + p1 = p3 = list1; + p2 = list2; + + while ( *p1 != -1 && *p2 != -1 ) { + if (compare_uint64(p1, p2) == 0) { + *p3++ = *p1++; + p2++; + } + else { + while (compare_uint64(p1, p2) < 0) ++p1; + while (compare_uint64(p1, p2) > 0) ++p2; + } + } + *p3 = -1; + return p3 - list1; +} + + +// Darkside attack (hf mf mifare) +static uint32_t nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint32_t ar, uint64_t par_info, uint64_t ks_info, uint64_t **keys) { + struct Crypto1State *states; + uint32_t i, pos; + uint8_t bt, ks3x[8], par[8][8]; + uint64_t key_recovered; + uint64_t *keylist; + + // Reset the last three significant bits of the reader nonce + nr &= 0xffffff1f; + + for (pos=0; pos<8; pos++) { + ks3x[7-pos] = (ks_info >> (pos*8)) & 0x0f; + bt = (par_info >> (pos*8)) & 0xff; + for (i=0; i<8; i++) { + par[7-pos][i] = (bt >> i) & 0x01; + } + } + + states = lfsr_common_prefix(nr, ar, ks3x, par, (par_info == 0)); + + if (states == NULL) { + *keys = NULL; + return 0; + } + + keylist = (uint64_t*)states; + + for (i = 0; keylist[i]; i++) { + lfsr_rollback_word(states+i, uid^nt, 0); + crypto1_get_lfsr(states+i, &key_recovered); + keylist[i] = key_recovered; + } + keylist[i] = -1; + + *keys = keylist; + return i; +} + + +int mfDarkside(uint64_t *key) +{ + uint32_t uid = 0; + uint32_t nt = 0, nr = 0, ar = 0; + uint64_t par_list = 0, ks_list = 0; + uint64_t *keylist = NULL, *last_keylist = NULL; + uint32_t keycount = 0; + int16_t isOK = 0; + + UsbCommand c = {CMD_READER_MIFARE, {true, 0, 0}}; + + // message + printf("-------------------------------------------------------------------------\n"); + printf("Executing command. Expected execution time: 25sec on average\n"); + printf("Press button on the proxmark3 device to abort both proxmark3 and client.\n"); + printf("-------------------------------------------------------------------------\n"); + + + while (true) { + clearCommandBuffer(); + SendCommand(&c); + + //flush queue + while (ukbhit()) { + int c = getchar(); (void) c; + } + + // wait cycle + while (true) { + printf("."); + fflush(stdout); + if (ukbhit()) { + return -5; + break; + } + + UsbCommand resp; + if (WaitForResponseTimeout(CMD_ACK, &resp, 1000)) { + isOK = resp.arg[0]; + if (isOK < 0) { + return isOK; + } + uid = (uint32_t)bytes_to_num(resp.d.asBytes + 0, 4); + nt = (uint32_t)bytes_to_num(resp.d.asBytes + 4, 4); + par_list = bytes_to_num(resp.d.asBytes + 8, 8); + ks_list = bytes_to_num(resp.d.asBytes + 16, 8); + nr = (uint32_t)bytes_to_num(resp.d.asBytes + 24, 4); + ar = (uint32_t)bytes_to_num(resp.d.asBytes + 28, 4); + break; + } + } + + if (par_list == 0 && c.arg[0] == true) { + PrintAndLog("Parity is all zero. Most likely this card sends NACK on every failed authentication."); + } + c.arg[0] = false; + + keycount = nonce2key(uid, nt, nr, ar, par_list, ks_list, &keylist); + + if (keycount == 0) { + PrintAndLog("Key not found (lfsr_common_prefix list is null). Nt=%08x", nt); + PrintAndLog("This is expected to happen in 25%% of all cases. Trying again with a different reader nonce..."); + continue; + } + + if (par_list == 0) { + qsort(keylist, keycount, sizeof(*keylist), compare_uint64); + keycount = intersection(last_keylist, keylist); + if (keycount == 0) { + free(last_keylist); + last_keylist = keylist; + continue; + } + } + + if (keycount > 1) { + PrintAndLog("Found %u possible keys. Trying to authenticate with each of them ...\n", keycount); + } else { + PrintAndLog("Found a possible key. Trying to authenticate...\n"); + } + + *key = -1; + uint8_t keyBlock[USB_CMD_DATA_SIZE]; + int max_keys = USB_CMD_DATA_SIZE/6; + for (int i = 0; i < keycount; i += max_keys) { + int size = keycount - i > max_keys ? max_keys : keycount - i; + for (int j = 0; j < size; j++) { + if (par_list == 0) { + num_to_bytes(last_keylist[i*max_keys + j], 6, keyBlock+(j*6)); + } else { + num_to_bytes(keylist[i*max_keys + j], 6, keyBlock+(j*6)); + } + } + if (!mfCheckKeys(0, 0, false, size, keyBlock, key)) { + break; + } + } + + if (*key != -1) { + free(last_keylist); + free(keylist); + break; + } else { + PrintAndLog("Authentication failed. Trying again..."); + free(last_keylist); + last_keylist = keylist; + } + } + + return 0; +} + + +int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t * keyBlock, uint64_t * key){ + + *key = -1; + + UsbCommand c = {CMD_MIFARE_CHKKEYS, {((blockNo & 0xff) | ((keyType & 0xff) << 8)), clear_trace, keycnt}}; + memcpy(c.d.asBytes, keyBlock, 6 * keycnt); + SendCommand(&c); + + UsbCommand resp; + if (!WaitForResponseTimeout(CMD_ACK,&resp,3000)) return 1; + if ((resp.arg[0] & 0xff) != 0x01) return 2; + *key = bytes_to_num(resp.d.asBytes, 6); + return 0; +} + +int mfCheckKeysSec(uint8_t sectorCnt, uint8_t keyType, uint8_t timeout14a, bool clear_trace, uint8_t keycnt, uint8_t * keyBlock, sector_t * e_sector){ + + uint8_t keyPtr = 0; + + if (e_sector == NULL) + return -1; + + UsbCommand c = {CMD_MIFARE_CHKKEYS, {((sectorCnt & 0xff) | ((keyType & 0xff) << 8)), (clear_trace | 0x02)|((timeout14a & 0xff) << 8), keycnt}}; + memcpy(c.d.asBytes, keyBlock, 6 * keycnt); + SendCommand(&c); + + UsbCommand resp; + if (!WaitForResponseTimeoutW(CMD_ACK, &resp, MAX(3000, 1000 + 13 * sectorCnt * keycnt * (keyType == 2 ? 2 : 1)), false)) return 1; // timeout: 13 ms / fail auth + if ((resp.arg[0] & 0xff) != 0x01) return 2; + + bool foundAKey = false; + for(int sec = 0; sec < sectorCnt; sec++){ + for(int keyAB = 0; keyAB < 2; keyAB++){ + keyPtr = *(resp.d.asBytes + keyAB * 40 + sec); + if (keyPtr){ + e_sector[sec].foundKey[keyAB] = true; + e_sector[sec].Key[keyAB] = bytes_to_num(keyBlock + (keyPtr - 1) * 6, 6); + foundAKey = true; + } + } + } + return foundAKey ? 0 : 3; +} + +// Compare 16 Bits out of cryptostate +int Compare16Bits(const void * a, const void * b) { + if ((*(uint64_t*)b & 0x00ff000000ff0000) == (*(uint64_t*)a & 0x00ff000000ff0000)) return 0; + else if ((*(uint64_t*)b & 0x00ff000000ff0000) > (*(uint64_t*)a & 0x00ff000000ff0000)) return 1; + else return -1; +} + +typedef + struct { + union { + struct Crypto1State *slhead; + uint64_t *keyhead; + } head; + union { + struct Crypto1State *sltail; + uint64_t *keytail; + } tail; + uint32_t len; + uint32_t uid; + uint32_t blockNo; + uint32_t keyType; + uint32_t nt; + uint32_t ks1; + } StateList_t; + + +// wrapper function for multi-threaded lfsr_recovery32 +void +#ifdef __has_attribute +#if __has_attribute(force_align_arg_pointer) +__attribute__((force_align_arg_pointer)) +#endif +#endif +*nested_worker_thread(void *arg) +{ + struct Crypto1State *p1; + StateList_t *statelist = arg; + + statelist->head.slhead = lfsr_recovery32(statelist->ks1, statelist->nt ^ statelist->uid); + for (p1 = statelist->head.slhead; *(uint64_t *)p1 != 0; p1++); + statelist->len = p1 - statelist->head.slhead; + statelist->tail.sltail = --p1; + qsort(statelist->head.slhead, statelist->len, sizeof(uint64_t), Compare16Bits); + + return statelist->head.slhead; +} + + +int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *resultKey, bool calibrate) +{ + uint16_t i; + uint32_t uid; + UsbCommand resp; + + StateList_t statelists[2]; + struct Crypto1State *p1, *p2, *p3, *p4; + + // flush queue + (void)WaitForResponseTimeout(CMD_ACK,NULL,100); + + UsbCommand c = {CMD_MIFARE_NESTED, {blockNo + keyType * 0x100, trgBlockNo + trgKeyType * 0x100, calibrate}}; + memcpy(c.d.asBytes, key, 6); + SendCommand(&c); + + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + return -1; + } + + if (resp.arg[0]) { + return resp.arg[0]; // error during nested + } + + memcpy(&uid, resp.d.asBytes, 4); + PrintAndLog("uid:%08x trgbl=%d trgkey=%x", uid, (uint16_t)resp.arg[2] & 0xff, (uint16_t)resp.arg[2] >> 8); + + for (i = 0; i < 2; i++) { + statelists[i].blockNo = resp.arg[2] & 0xff; + statelists[i].keyType = (resp.arg[2] >> 8) & 0xff; + statelists[i].uid = uid; + memcpy(&statelists[i].nt, (void *)(resp.d.asBytes + 4 + i * 8 + 0), 4); + memcpy(&statelists[i].ks1, (void *)(resp.d.asBytes + 4 + i * 8 + 4), 4); + } + + // calc keys + + pthread_t thread_id[2]; + + // create and run worker threads + for (i = 0; i < 2; i++) { + pthread_create(thread_id + i, NULL, nested_worker_thread, &statelists[i]); + } + + // wait for threads to terminate: + for (i = 0; i < 2; i++) { + pthread_join(thread_id[i], (void*)&statelists[i].head.slhead); + } + + + // the first 16 Bits of the cryptostate already contain part of our key. + // Create the intersection of the two lists based on these 16 Bits and + // roll back the cryptostate + p1 = p3 = statelists[0].head.slhead; + p2 = p4 = statelists[1].head.slhead; + while (p1 <= statelists[0].tail.sltail && p2 <= statelists[1].tail.sltail) { + if (Compare16Bits(p1, p2) == 0) { + struct Crypto1State savestate, *savep = &savestate; + savestate = *p1; + while(Compare16Bits(p1, savep) == 0 && p1 <= statelists[0].tail.sltail) { + *p3 = *p1; + lfsr_rollback_word(p3, statelists[0].nt ^ statelists[0].uid, 0); + p3++; + p1++; + } + savestate = *p2; + while(Compare16Bits(p2, savep) == 0 && p2 <= statelists[1].tail.sltail) { + *p4 = *p2; + lfsr_rollback_word(p4, statelists[1].nt ^ statelists[1].uid, 0); + p4++; + p2++; + } + } + else { + while (Compare16Bits(p1, p2) == -1) p1++; + while (Compare16Bits(p1, p2) == 1) p2++; + } + } + *(uint64_t*)p3 = -1; + *(uint64_t*)p4 = -1; + statelists[0].len = p3 - statelists[0].head.slhead; + statelists[1].len = p4 - statelists[1].head.slhead; + statelists[0].tail.sltail=--p3; + statelists[1].tail.sltail=--p4; + + // the statelists now contain possible keys. The key we are searching for must be in the + // intersection of both lists. Create the intersection: + qsort(statelists[0].head.keyhead, statelists[0].len, sizeof(uint64_t), compare_uint64); + qsort(statelists[1].head.keyhead, statelists[1].len, sizeof(uint64_t), compare_uint64); + statelists[0].len = intersection(statelists[0].head.keyhead, statelists[1].head.keyhead); + + memset(resultKey, 0, 6); + // The list may still contain several key candidates. Test each of them with mfCheckKeys + for (i = 0; i < statelists[0].len; i++) { + uint8_t keyBlock[6]; + uint64_t key64; + crypto1_get_lfsr(statelists[0].head.slhead + i, &key64); + num_to_bytes(key64, 6, keyBlock); + key64 = 0; + if (!mfCheckKeys(statelists[0].blockNo, statelists[0].keyType, false, 1, keyBlock, &key64)) { + num_to_bytes(key64, 6, resultKey); + break; + } + } + + free(statelists[0].head.slhead); + free(statelists[1].head.slhead); + + return 0; +} + +// MIFARE +int mfReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *data) { + + UsbCommand c = {CMD_MIFARE_READSC, {sectorNo, keyType, 0}}; + memcpy(c.d.asBytes, key, 6); + clearCommandBuffer(); + SendCommand(&c); + + UsbCommand resp; + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + + if (isOK) { + memcpy(data, resp.d.asBytes, mfNumBlocksPerSector(sectorNo) * 16); + return 0; + } else { + return 1; + } + } else { + PrintAndLogEx(ERR, "Command execute timeout"); + return 2; + } + + return 0; +} + +// EMULATOR + +int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount) { + UsbCommand c = {CMD_MIFARE_EML_MEMGET, {blockNum, blocksCount, 0}}; + SendCommand(&c); + + UsbCommand resp; + if (!WaitForResponseTimeout(CMD_ACK,&resp,1500)) return 1; + memcpy(data, resp.d.asBytes, blocksCount * 16); + return 0; +} + +int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount) { + UsbCommand c = {CMD_MIFARE_EML_MEMSET, {blockNum, blocksCount, 0}}; + memcpy(c.d.asBytes, data, blocksCount * 16); + SendCommand(&c); + return 0; +} + +// "MAGIC" CARD + +int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params) { + uint8_t isOK = 0; + + UsbCommand c = {CMD_MIFARE_CGETBLOCK, {params, 0, blockNo}}; + SendCommand(&c); + + UsbCommand resp; + if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + isOK = resp.arg[0] & 0xff; + memcpy(data, resp.d.asBytes, 16); + if (!isOK) return 2; + } else { + PrintAndLog("Command execute timeout"); + return 1; + } + return 0; +} + +int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, bool wantWipe, uint8_t params) { + + uint8_t isOK = 0; + UsbCommand c = {CMD_MIFARE_CSETBLOCK, {wantWipe, params & (0xFE | (uid == NULL ? 0:1)), blockNo}}; + memcpy(c.d.asBytes, data, 16); + SendCommand(&c); + + UsbCommand resp; + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + isOK = resp.arg[0] & 0xff; + if (uid != NULL) + memcpy(uid, resp.d.asBytes, 4); + if (!isOK) + return 2; + } else { + PrintAndLog("Command execute timeout"); + return 1; + } + + return 0; +} + +int mfCWipe(uint32_t numSectors, bool gen1b, bool wantWipe, bool wantFill) { + uint8_t isOK = 0; + uint8_t cmdParams = wantWipe + wantFill * 0x02 + gen1b * 0x04; + UsbCommand c = {CMD_MIFARE_CWIPE, {numSectors, cmdParams, 0}}; + SendCommand(&c); + + UsbCommand resp; + WaitForResponse(CMD_ACK,&resp); + isOK = resp.arg[0] & 0xff; + + return isOK; +} + +int mfCSetUID(uint8_t *uid, uint8_t *atqa, uint8_t *sak, uint8_t *oldUID) { + uint8_t oldblock0[16] = {0x00}; + uint8_t block0[16] = {0x00}; + int gen = 0, res; + + gen = mfCIdentify(); + + /* generation 1a magic card by default */ + uint8_t cmdParams = CSETBLOCK_SINGLE_OPER; + if (gen == 2) { + /* generation 1b magic card */ + cmdParams = CSETBLOCK_SINGLE_OPER | CSETBLOCK_MAGIC_1B; + } + + res = mfCGetBlock(0, oldblock0, cmdParams); + + if (res == 0) { + memcpy(block0, oldblock0, 16); + PrintAndLog("old block 0: %s", sprint_hex(block0,16)); + } else { + PrintAndLog("Couldn't get old data. Will write over the last bytes of Block 0."); + } + + // fill in the new values + // UID + memcpy(block0, uid, 4); + // Mifare UID BCC + block0[4] = block0[0] ^ block0[1] ^ block0[2] ^ block0[3]; + // mifare classic SAK(byte 5) and ATQA(byte 6 and 7, reversed) + if (sak != NULL) + block0[5] = sak[0]; + if (atqa != NULL) { + block0[6] = atqa[1]; + block0[7] = atqa[0]; + } + PrintAndLog("new block 0: %s", sprint_hex(block0, 16)); + + res = mfCSetBlock(0, block0, oldUID, false, cmdParams); + if (res) { + PrintAndLog("Can't set block 0. Error: %d", res); + return res; + } + + return 0; +} + +int mfCIdentify() { + UsbCommand c = {CMD_MIFARE_CIDENT, {0, 0, 0}}; + SendCommand(&c); + UsbCommand resp; + WaitForResponse(CMD_ACK,&resp); + + uint8_t isGeneration = resp.arg[0] & 0xff; + switch( isGeneration ){ + case 1: PrintAndLog("Chinese magic backdoor commands (GEN 1a) detected"); break; + case 2: PrintAndLog("Chinese magic backdoor command (GEN 1b) detected"); break; + default: PrintAndLog("No chinese magic backdoor command detected"); break; + } + + return (int) isGeneration; +} + + +// SNIFFER + +// constants +static uint8_t trailerAccessBytes[4] = {0x08, 0x77, 0x8F, 0x00}; + +// variables +char logHexFileName[FILE_PATH_SIZE] = {0x00}; +static uint8_t traceCard[4096] = {0x00}; +static char traceFileName[FILE_PATH_SIZE] = {0x00}; +static int traceState = TRACE_IDLE; +static uint8_t traceCurBlock = 0; +static uint8_t traceCurKey = 0; + +struct Crypto1State *traceCrypto1 = NULL; + +struct Crypto1State *revstate; +uint64_t lfsr; +uint64_t ui64Key; +uint32_t ks2; +uint32_t ks3; + +uint32_t uid; // serial number +uint32_t nt; // tag challenge +uint32_t nt_enc; // encrypted tag challenge +uint8_t nt_enc_par; // encrypted tag challenge parity +uint32_t nr_enc; // encrypted reader challenge +uint32_t ar_enc; // encrypted reader response +uint8_t ar_enc_par; // encrypted reader response parity +uint32_t at_enc; // encrypted tag response +uint8_t at_enc_par; // encrypted tag response parity + +int isTraceCardEmpty(void) { + return ((traceCard[0] == 0) && (traceCard[1] == 0) && (traceCard[2] == 0) && (traceCard[3] == 0)); +} + +int isBlockEmpty(int blockN) { + for (int i = 0; i < 16; i++) + if (traceCard[blockN * 16 + i] != 0) return 0; + + return 1; +} + +int isBlockTrailer(int blockN) { + return ((blockN & 0x03) == 0x03); +} + +int saveTraceCard(void) { + FILE * f; + + if ((!strlen(traceFileName)) || (isTraceCardEmpty())) return 0; + + f = fopen(traceFileName, "w+"); + if ( !f ) return 1; + + for (int i = 0; i < 64; i++) { // blocks + for (int j = 0; j < 16; j++) // bytes + fprintf(f, "%02x", *(traceCard + i * 16 + j)); + if (i < 63) + fprintf(f,"\n"); + } + fclose(f); + return 0; +} + +int loadTraceCard(uint8_t *tuid) { + FILE * f; + char buf[64] = {0x00}; + uint8_t buf8[64] = {0x00}; + int i, blockNum; + + if (!isTraceCardEmpty()) + saveTraceCard(); + + memset(traceCard, 0x00, 4096); + memcpy(traceCard, tuid + 3, 4); + + FillFileNameByUID(traceFileName, tuid, ".eml", 7); + + f = fopen(traceFileName, "r"); + if (!f) return 1; + + blockNum = 0; + + while(!feof(f)){ + + memset(buf, 0, sizeof(buf)); + if (fgets(buf, sizeof(buf), f) == NULL) { + PrintAndLog("File reading error."); + fclose(f); + return 2; + } + + if (strlen(buf) < 32){ + if (feof(f)) break; + PrintAndLog("File content error. Block data must include 32 HEX symbols"); + fclose(f); + return 2; + } + for (i = 0; i < 32; i += 2) + sscanf(&buf[i], "%02x", (unsigned int *)&buf8[i / 2]); + + memcpy(traceCard + blockNum * 16, buf8, 16); + + blockNum++; + } + fclose(f); + + return 0; +} + +int mfTraceInit(uint8_t *tuid, uint8_t *atqa, uint8_t sak, bool wantSaveToEmlFile) { + + if (traceCrypto1) + crypto1_destroy(traceCrypto1); + + traceCrypto1 = NULL; + + if (wantSaveToEmlFile) + loadTraceCard(tuid); + + traceCard[4] = traceCard[0] ^ traceCard[1] ^ traceCard[2] ^ traceCard[3]; + traceCard[5] = sak; + memcpy(&traceCard[6], atqa, 2); + traceCurBlock = 0; + uid = bytes_to_num(tuid + 3, 4); + + traceState = TRACE_IDLE; + + return 0; +} + +void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len, bool isEncrypted){ + uint8_t bt = 0; + int i; + + if (len != 1) { + for (i = 0; i < len; i++) + data[i] = crypto1_byte(pcs, 0x00, isEncrypted) ^ data[i]; + } else { + bt = 0; + for (i = 0; i < 4; i++) + bt |= (crypto1_bit(pcs, 0, isEncrypted) ^ BIT(data[0], i)) << i; + + data[0] = bt; + } + return; +} + +bool NTParityCheck(uint32_t ntx) { + if ( + (oddparity8(ntx >> 8 & 0xff) ^ (ntx & 0x01) ^ ((nt_enc_par >> 5) & 0x01) ^ (nt_enc & 0x01)) || + (oddparity8(ntx >> 16 & 0xff) ^ (ntx >> 8 & 0x01) ^ ((nt_enc_par >> 6) & 0x01) ^ (nt_enc >> 8 & 0x01)) || + (oddparity8(ntx >> 24 & 0xff) ^ (ntx >> 16 & 0x01) ^ ((nt_enc_par >> 7) & 0x01) ^ (nt_enc >> 16 & 0x01)) + ) + return false; + + uint32_t ar = prng_successor(ntx, 64); + if ( + (oddparity8(ar >> 8 & 0xff) ^ (ar & 0x01) ^ ((ar_enc_par >> 5) & 0x01) ^ (ar_enc & 0x01)) || + (oddparity8(ar >> 16 & 0xff) ^ (ar >> 8 & 0x01) ^ ((ar_enc_par >> 6) & 0x01) ^ (ar_enc >> 8 & 0x01)) || + (oddparity8(ar >> 24 & 0xff) ^ (ar >> 16 & 0x01) ^ ((ar_enc_par >> 7) & 0x01) ^ (ar_enc >> 16 & 0x01)) + ) + return false; + + uint32_t at = prng_successor(ntx, 96); + if ( + (oddparity8(ar & 0xff) ^ (at >> 24 & 0x01) ^ ((ar_enc_par >> 4) & 0x01) ^ (at_enc >> 24 & 0x01)) || + (oddparity8(at >> 8 & 0xff) ^ (at & 0x01) ^ ((at_enc_par >> 5) & 0x01) ^ (at_enc & 0x01)) || + (oddparity8(at >> 16 & 0xff) ^ (at >> 8 & 0x01) ^ ((at_enc_par >> 6) & 0x01) ^ (at_enc >> 8 & 0x01)) || + (oddparity8(at >> 24 & 0xff) ^ (at >> 16 & 0x01) ^ ((at_enc_par >> 7) & 0x01) ^ (at_enc >> 16 & 0x01)) + ) + return false; + + return true; +} + + +int mfTraceDecode(uint8_t *data_src, int len, uint8_t parity, bool wantSaveToEmlFile) { + uint8_t data[64]; + + if (traceState == TRACE_ERROR) return 1; + if (len > 64) { + traceState = TRACE_ERROR; + return 1; + } + + memcpy(data, data_src, len); + if ((traceCrypto1) && ((traceState == TRACE_IDLE) || (traceState > TRACE_AUTH_OK))) { + mf_crypto1_decrypt(traceCrypto1, data, len, 0); + uint8_t parity[16]; + oddparitybuf(data, len, parity); + PrintAndLog("dec> %s [%s]", sprint_hex(data, len), printBitsPar(parity, len)); + AddLogHex(logHexFileName, "dec> ", data, len); + } + + switch (traceState) { + case TRACE_IDLE: + // check packet crc16! + if ((len >= 4) && (!CheckCrc14443(CRC_14443_A, data, len))) { + PrintAndLog("dec> CRC ERROR!!!"); + AddLogLine(logHexFileName, "dec> ", "CRC ERROR!!!"); + traceState = TRACE_ERROR; // do not decrypt the next commands + return 1; + } + + // AUTHENTICATION + if ((len ==4) && ((data[0] == 0x60) || (data[0] == 0x61))) { + traceState = TRACE_AUTH1; + traceCurBlock = data[1]; + traceCurKey = data[0] == 60 ? 1:0; + return 0; + } + + // READ + if ((len ==4) && ((data[0] == 0x30))) { + traceState = TRACE_READ_DATA; + traceCurBlock = data[1]; + return 0; + } + + // WRITE + if ((len ==4) && ((data[0] == 0xA0))) { + traceState = TRACE_WRITE_OK; + traceCurBlock = data[1]; + return 0; + } + + // HALT + if ((len ==4) && ((data[0] == 0x50) && (data[1] == 0x00))) { + traceState = TRACE_ERROR; // do not decrypt the next commands + return 0; + } + + return 0; + break; + + case TRACE_READ_DATA: + if (len == 18) { + traceState = TRACE_IDLE; + + if (isBlockTrailer(traceCurBlock)) { + memcpy(traceCard + traceCurBlock * 16 + 6, data + 6, 4); + } else { + memcpy(traceCard + traceCurBlock * 16, data, 16); + } + if (wantSaveToEmlFile) saveTraceCard(); + return 0; + } else { + traceState = TRACE_ERROR; + return 1; + } + break; + + case TRACE_WRITE_OK: + if ((len == 1) && (data[0] == 0x0a)) { + traceState = TRACE_WRITE_DATA; + + return 0; + } else { + traceState = TRACE_ERROR; + return 1; + } + break; + + case TRACE_WRITE_DATA: + if (len == 18) { + traceState = TRACE_IDLE; + + memcpy(traceCard + traceCurBlock * 16, data, 16); + if (wantSaveToEmlFile) saveTraceCard(); + return 0; + } else { + traceState = TRACE_ERROR; + return 1; + } + break; + + case TRACE_AUTH1: + if (len == 4) { + traceState = TRACE_AUTH2; + if (!traceCrypto1) { + nt = bytes_to_num(data, 4); + } else { + nt_enc = bytes_to_num(data, 4); + nt_enc_par = parity; + } + return 0; + } else { + traceState = TRACE_ERROR; + return 1; + } + break; + + case TRACE_AUTH2: + if (len == 8) { + traceState = TRACE_AUTH_OK; + + nr_enc = bytes_to_num(data, 4); + ar_enc = bytes_to_num(data + 4, 4); + ar_enc_par = parity << 4; + return 0; + } else { + traceState = TRACE_ERROR; + return 1; + } + break; + + case TRACE_AUTH_OK: + if (len ==4) { + traceState = TRACE_IDLE; + + at_enc = bytes_to_num(data, 4); + at_enc_par = parity; + if (!traceCrypto1) { + + // decode key here) + ks2 = ar_enc ^ prng_successor(nt, 64); + ks3 = at_enc ^ prng_successor(nt, 96); + revstate = lfsr_recovery64(ks2, ks3); + lfsr_rollback_word(revstate, 0, 0); + lfsr_rollback_word(revstate, 0, 0); + lfsr_rollback_word(revstate, nr_enc, 1); + lfsr_rollback_word(revstate, uid ^ nt, 0); + + crypto1_get_lfsr(revstate, &lfsr); + crypto1_destroy(revstate); + ui64Key = lfsr; + printf("key> probable key:%x%x Prng:%s ks2:%08x ks3:%08x\n", + (unsigned int)((lfsr & 0xFFFFFFFF00000000) >> 32), (unsigned int)(lfsr & 0xFFFFFFFF), + validate_prng_nonce(nt) ? "WEAK": "HARDEND", + ks2, + ks3); + AddLogUint64(logHexFileName, "key> ", lfsr); + } else { + if (validate_prng_nonce(nt)) { + struct Crypto1State *pcs; + pcs = crypto1_create(ui64Key); + uint32_t nt1 = crypto1_word(pcs, nt_enc ^ uid, 1) ^ nt_enc; + uint32_t ar = prng_successor(nt1, 64); + uint32_t at = prng_successor(nt1, 96); + printf("key> nested auth uid: %08x nt: %08x nt_parity: %s ar: %08x at: %08x\n", uid, nt1, printBitsPar(&nt_enc_par, 4), ar, at); + uint32_t nr1 = crypto1_word(pcs, nr_enc, 1) ^ nr_enc; + uint32_t ar1 = crypto1_word(pcs, 0, 0) ^ ar_enc; + uint32_t at1 = crypto1_word(pcs, 0, 0) ^ at_enc; + crypto1_destroy(pcs); + printf("key> the same key test. nr1: %08x ar1: %08x at1: %08x \n", nr1, ar1, at1); + + if (NTParityCheck(nt1)) + printf("key> the same key test OK. key=%x%x\n", (unsigned int)((ui64Key & 0xFFFFFFFF00000000) >> 32), (unsigned int)(ui64Key & 0xFFFFFFFF)); + else + printf("key> the same key test. check nt parity error.\n"); + + uint32_t ntc = prng_successor(nt, 90); + uint32_t ntx = 0; + int ntcnt = 0; + for (int i = 0; i < 16383; i++) { + ntc = prng_successor(ntc, 1); + if (NTParityCheck(ntc)){ + if (!ntcnt) + ntx = ntc; + ntcnt++; + } + } + if (ntcnt) + printf("key> nt candidate=%08x nonce distance=%d candidates count=%d\n", ntx, nonce_distance(nt, ntx), ntcnt); + else + printf("key> don't have any nt candidate( \n"); + + nt = ntx; + ks2 = ar_enc ^ prng_successor(ntx, 64); + ks3 = at_enc ^ prng_successor(ntx, 96); + + // decode key + revstate = lfsr_recovery64(ks2, ks3); + lfsr_rollback_word(revstate, 0, 0); + lfsr_rollback_word(revstate, 0, 0); + lfsr_rollback_word(revstate, nr_enc, 1); + lfsr_rollback_word(revstate, uid ^ nt, 0); + + crypto1_get_lfsr(revstate, &lfsr); + crypto1_destroy(revstate); + ui64Key = lfsr; + printf("key> probable key:%x%x ks2:%08x ks3:%08x\n", + (unsigned int)((lfsr & 0xFFFFFFFF00000000) >> 32), (unsigned int)(lfsr & 0xFFFFFFFF), + ks2, + ks3); + AddLogUint64(logHexFileName, "key> ", lfsr); + } else { + printf("key> hardnested not implemented!\n"); + + crypto1_destroy(traceCrypto1); + + // not implemented + traceState = TRACE_ERROR; + } + } + + int blockShift = ((traceCurBlock & 0xFC) + 3) * 16; + if (isBlockEmpty((traceCurBlock & 0xFC) + 3)) memcpy(traceCard + blockShift + 6, trailerAccessBytes, 4); + + if (traceCurKey) { + num_to_bytes(lfsr, 6, traceCard + blockShift + 10); + } else { + num_to_bytes(lfsr, 6, traceCard + blockShift); + } + if (wantSaveToEmlFile) saveTraceCard(); + + if (traceCrypto1) { + crypto1_destroy(traceCrypto1); + } + + // set cryptosystem state + traceCrypto1 = lfsr_recovery64(ks2, ks3); + return 0; + } else { + traceState = TRACE_ERROR; + return 1; + } + break; + + default: + traceState = TRACE_ERROR; + return 1; + } + + return 0; +} + +// DECODING + +int tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, int len){ + /* + uint32_t nt; // tag challenge + uint32_t ar_enc; // encrypted reader response + uint32_t at_enc; // encrypted tag response + */ + if (traceCrypto1) { + crypto1_destroy(traceCrypto1); + } + ks2 = ar_enc ^ prng_successor(nt, 64); + ks3 = at_enc ^ prng_successor(nt, 96); + traceCrypto1 = lfsr_recovery64(ks2, ks3); + + mf_crypto1_decrypt(traceCrypto1, data, len, 0); + + PrintAndLog("Decrypted data: [%s]", sprint_hex(data,len) ); + crypto1_destroy(traceCrypto1); + return 0; +} + +/** validate_prng_nonce + * Determine if nonce is deterministic. ie: Suspectable to Darkside attack. + * returns + * true = weak prng + * false = hardend prng + */ +bool validate_prng_nonce(uint32_t nonce) { + uint16_t *dist = 0; + uint16_t x, i; + + dist = malloc(2 << 16); + if(!dist) + return -1; + + // init prng table: + for (x = i = 1; i; ++i) { + dist[(x & 0xff) << 8 | x >> 8] = i; + x = x >> 1 | (x ^ x >> 2 ^ x >> 3 ^ x >> 5) << 15; + } + + uint32_t res = (65535 - dist[nonce >> 16] + dist[nonce & 0xffff]) % 65535; + + free(dist); + return (res == 16); +} + +/* Detect Tag Prng, +* function performs a partial AUTH, where it tries to authenticate against block0, key A, but only collects tag nonce. +* the tag nonce is check to see if it has a predictable PRNG. +* @returns +* TRUE if tag uses WEAK prng (ie Now the NACK bug also needs to be present for Darkside attack) +* FALSE is tag uses HARDEND prng (ie hardnested attack possible, with known key) +*/ +int DetectClassicPrng(void){ + + UsbCommand resp, respA; + uint8_t cmd[] = {0x60, 0x00}; // MIFARE_AUTH_KEYA + uint32_t flags = ISO14A_CONNECT | ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_RATS; + + UsbCommand c = {CMD_READER_ISO_14443a, {flags, sizeof(cmd), 0}}; + memcpy(c.d.asBytes, cmd, sizeof(cmd)); + + clearCommandBuffer(); + SendCommand(&c); + if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + PrintAndLog("PRNG UID: Reply timeout."); + return -1; + } + + // if select tag failed. + if (resp.arg[0] == 0) { + PrintAndLog("PRNG error: selecting tag failed, can't detect prng."); + return -1; + } + + if (!WaitForResponseTimeout(CMD_ACK, &respA, 5000)) { + PrintAndLog("PRNG data: Reply timeout."); + return -1; + } + + // check respA + if (respA.arg[0] != 4) { + PrintAndLog("PRNG data error: Wrong length: %d", respA.arg[0]); + return -1; + } + + uint32_t nonce = bytes_to_num(respA.d.asBytes, respA.arg[0]); + return validate_prng_nonce(nonce); +} diff --git a/client/mifarehost.h b/client/mifare/mifarehost.h similarity index 96% rename from client/mifarehost.h rename to client/mifare/mifarehost.h index 6a37fef1..18a8a5e1 100644 --- a/client/mifarehost.h +++ b/client/mifare/mifarehost.h @@ -1,68 +1,70 @@ -// Merlok, 2011, 2017 -// people from mifare@nethemba.com, 2010 -// -// 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 ISO14443A commands -//----------------------------------------------------------------------------- - -#ifndef MIFAREHOST_H -#define MIFAREHOST_H - -#include -#include -#include "crapto1/crapto1.h" -#include "util.h" - -// defaults -// timeout in units. (ms * 106)/10 or us*0.0106 -// 5 == 500us -#define MF_CHKKEYS_DEFTIMEOUT 5 - -// mfCSetBlock work flags -#define CSETBLOCK_UID 0x01 -#define CSETBLOCK_WUPC 0x02 -#define CSETBLOCK_HALT 0x04 -#define CSETBLOCK_INIT_FIELD 0x08 -#define CSETBLOCK_RESET_FIELD 0x10 -#define CSETBLOCK_SINGLE_OPER 0x1F -#define CSETBLOCK_MAGIC_1B 0x40 - -typedef struct { - uint64_t Key[2]; - int foundKey[2]; -} sector_t; - -extern char logHexFileName[FILE_PATH_SIZE]; - -extern int mfDarkside(uint64_t *key); -extern int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *ResultKeys, bool calibrate); -extern int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t *keyBlock, uint64_t *key); -extern int mfCheckKeysSec(uint8_t sectorCnt, uint8_t keyType, uint8_t timeout14a, bool clear_trace, uint8_t keycnt, uint8_t * keyBlock, sector_t * e_sector); - -extern int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount); -extern int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount); - -extern int mfCWipe(uint32_t numSectors, bool gen1b, bool wantWipe, bool wantFill); -extern int mfCSetUID(uint8_t *uid, uint8_t *atqa, uint8_t *sak, uint8_t *oldUID); -extern int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, bool wantWipe, uint8_t params); -extern int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params); - -extern int mfTraceInit(uint8_t *tuid, uint8_t *atqa, uint8_t sak, bool wantSaveToEmlFile); -extern int mfTraceDecode(uint8_t *data_src, int len, uint8_t parity, bool wantSaveToEmlFile); - -extern int isTraceCardEmpty(void); -extern int isBlockEmpty(int blockN); -extern int isBlockTrailer(int blockN); -extern int loadTraceCard(uint8_t *tuid); -extern int saveTraceCard(void); -extern int tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, int len); - -extern int mfCIdentify(); -extern int DetectClassicPrng(void); -extern bool validate_prng_nonce(uint32_t nonce); -extern void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len, bool isEncrypted); - -#endif +// Merlok, 2011, 2017 +// people from mifare@nethemba.com, 2010 +// +// 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 ISO14443A commands +//----------------------------------------------------------------------------- + +#ifndef MIFAREHOST_H +#define MIFAREHOST_H + +#include +#include +#include "crapto1/crapto1.h" +#include "util.h" + +// defaults +// timeout in units. (ms * 106)/10 or us*0.0106 +// 5 == 500us +#define MF_CHKKEYS_DEFTIMEOUT 5 + +// mfCSetBlock work flags +#define CSETBLOCK_UID 0x01 +#define CSETBLOCK_WUPC 0x02 +#define CSETBLOCK_HALT 0x04 +#define CSETBLOCK_INIT_FIELD 0x08 +#define CSETBLOCK_RESET_FIELD 0x10 +#define CSETBLOCK_SINGLE_OPER 0x1F +#define CSETBLOCK_MAGIC_1B 0x40 + +typedef struct { + uint64_t Key[2]; + int foundKey[2]; +} sector_t; + +extern char logHexFileName[FILE_PATH_SIZE]; + +extern int mfDarkside(uint64_t *key); +extern int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *ResultKeys, bool calibrate); +extern int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t *keyBlock, uint64_t *key); +extern int mfCheckKeysSec(uint8_t sectorCnt, uint8_t keyType, uint8_t timeout14a, bool clear_trace, uint8_t keycnt, uint8_t * keyBlock, sector_t * e_sector); + +extern int mfReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *data); + +extern int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount); +extern int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount); + +extern int mfCWipe(uint32_t numSectors, bool gen1b, bool wantWipe, bool wantFill); +extern int mfCSetUID(uint8_t *uid, uint8_t *atqa, uint8_t *sak, uint8_t *oldUID); +extern int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, bool wantWipe, uint8_t params); +extern int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params); + +extern int mfTraceInit(uint8_t *tuid, uint8_t *atqa, uint8_t sak, bool wantSaveToEmlFile); +extern int mfTraceDecode(uint8_t *data_src, int len, uint8_t parity, bool wantSaveToEmlFile); + +extern int isTraceCardEmpty(void); +extern int isBlockEmpty(int blockN); +extern int isBlockTrailer(int blockN); +extern int loadTraceCard(uint8_t *tuid); +extern int saveTraceCard(void); +extern int tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, int len); + +extern int mfCIdentify(); +extern int DetectClassicPrng(void); +extern bool validate_prng_nonce(uint32_t nonce); +extern void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len, bool isEncrypted); + +#endif diff --git a/client/mifare/ndef.c b/client/mifare/ndef.c new file mode 100644 index 00000000..adc15839 --- /dev/null +++ b/client/mifare/ndef.c @@ -0,0 +1,359 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2019 Merlok +// +// 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. +//----------------------------------------------------------------------------- +// NFC Data Exchange Format (NDEF) functions +//----------------------------------------------------------------------------- + +#include "ndef.h" +#include "ui.h" +#include "emv/dump.h" +#include "crypto/asn1utils.h" +#include "util.h" +#include + +#define STRBOOL(p) ((p) ? "+" : "-") + +static const char *TypeNameFormat_s[] = { + "Empty Record", + "Well Known Record", + "MIME Media Record", + "Absolute URI Record", + "External Record", + "Unknown Record", + "Unchanged Record", + "n/a" +}; + +static const char *ndefSigType_s[] = { + "Not present", // No signature present + "RSASSA_PSS_SHA_1", // PKCS_1 + "RSASSA_PKCS1_v1_5_WITH_SHA_1", // PKCS_1 + "DSA", + "ECDSA", + "n/a" +}; + +static const char *ndefCertificateFormat_s[] = { + "X_509", + "X9_68", + "n/a" +}; + +static const char *URI_s[] = { + "", // 0x00 + "http://www.", // 0x01 + "https://www.", // 0x02 + "http://", // 0x03 + "https://", // 0x04 + "tel:", // 0x05 + "mailto:", // 0x06 + "ftp://anonymous:anonymous@", // 0x07 + "ftp://ftp.", // 0x08 + "ftps://", // 0x09 + "sftp://", // 0x0A + "smb://", // 0x0B + "nfs://", // 0x0C + "ftp://", // 0x0D + "dav://", // 0x0E + "news:", // 0x0F + "telnet://", // 0x10 + "imap:", // 0x11 + "rtsp://", // 0x12 + "urn:", // 0x13 + "pop:", // 0x14 + "sip:", // 0x15 + "sips:", // 0x16 + "tftp:", // 0x17 + "btspp://", // 0x18 + "btl2cap://", // 0x19 + "btgoep://", // 0x1A + "tcpobex://", // 0x1B + "irdaobex://", // 0x1C + "file://", // 0x1D + "urn:epc:id:", // 0x1E + "urn:epc:tag:", // 0x1F + "urn:epc:pat:", // 0x20 + "urn:epc:raw:", // 0x21 + "urn:epc:", // 0x22 + "urn:nfc:" // 0x23 +}; + +uint16_t ndefTLVGetLength(uint8_t *data, size_t *indx) { + uint16_t len = 0; + if (data[0] == 0xff) { + len = (data[1] << 8) + data[2]; + *indx += 3; + } else { + len = data[0]; + *indx += 1; + } + + return len; +} + +int ndefDecodeHeader(uint8_t *data, size_t datalen, NDEFHeader_t *header) { + header->Type = NULL; + header->Payload = NULL; + header->ID = NULL; + + header->MessageBegin = data[0] & 0x80; + header->MessageEnd = data[0] & 0x40; + header->ChunkFlag = data[0] & 0x20; + header->ShortRecordBit = data[0] & 0x10; + header->IDLenPresent = data[0] & 0x08; + header->TypeNameFormat = data[0] & 0x07; + header->len = 1 + 1 + (header->ShortRecordBit ? 1 : 4) + (header->IDLenPresent ? 1 : 0); // header + typelen + payloadlen + idlen + if (header->len > datalen) + return 1; + + header->TypeLen = data[1]; + header->Type = data + header->len; + + header->PayloadLen = (header->ShortRecordBit ? (data[2]) : ((data[2] << 24) + (data[3] << 16) + (data[4] << 8) + data[5])); + + if (header->IDLenPresent) { + header->IDLen = (header->ShortRecordBit ? (data[3]) : (data[6])); + header->Payload = header->Type + header->TypeLen; + } else { + header->IDLen = 0; + } + + header->Payload = header->Type + header->TypeLen + header->IDLen; + + header->RecLen = header->len + header->TypeLen + header->PayloadLen + header->IDLen; + + if (header->RecLen > datalen) + return 3; + + return 0; +} + +int ndefPrintHeader(NDEFHeader_t *header) { + PrintAndLogEx(INFO, "Header:"); + + PrintAndLogEx(NORMAL, "\tMessage Begin: %s", STRBOOL(header->MessageBegin)); + PrintAndLogEx(NORMAL, "\tMessage End: %s", STRBOOL(header->MessageEnd)); + PrintAndLogEx(NORMAL, "\tChunk Flag: %s", STRBOOL(header->ChunkFlag)); + PrintAndLogEx(NORMAL, "\tShort Record Bit: %s", STRBOOL(header->ShortRecordBit)); + PrintAndLogEx(NORMAL, "\tID Len Present: %s", STRBOOL(header->IDLenPresent)); + PrintAndLogEx(NORMAL, "\tType Name Format: [0x%02x] %s", header->TypeNameFormat, TypeNameFormat_s[header->TypeNameFormat]); + + PrintAndLogEx(NORMAL, "\tHeader length : %d", header->len); + PrintAndLogEx(NORMAL, "\tType length : %d", header->TypeLen); + PrintAndLogEx(NORMAL, "\tPayload length : %d", header->PayloadLen); + PrintAndLogEx(NORMAL, "\tID length : %d", header->IDLen); + PrintAndLogEx(NORMAL, "\tRecord length : %d", header->RecLen); + + return 0; +} + +int ndefDecodeSig(uint8_t *sig, size_t siglen) { + size_t indx = 0; + PrintAndLogEx(NORMAL, "\tsignature version: 0x%02x", sig[0]); + if (sig[0] != 0x01) { + PrintAndLogEx(ERR, "signature version unknown."); + return 1; + } + indx++; + + uint8_t sigType = sig[indx] & 0x7f; + bool sigURI = sig[indx] & 0x80; + + PrintAndLogEx(NORMAL, "\tsignature type: %s", ((sigType < stNA) ? ndefSigType_s[sigType] : ndefSigType_s[stNA])); + PrintAndLogEx(NORMAL, "\tsignature uri: %s", (sigURI ? "present" : "not present")); + + size_t intsiglen = (sig[indx + 1] << 8) + sig[indx + 2]; + // ecdsa 0x04 + if (sigType == stECDSA) { + indx += 3; + PrintAndLogEx(NORMAL, "\tsignature [%d]: %s", intsiglen, sprint_hex_inrow(&sig[indx], intsiglen)); + + uint8_t rval[300] = {0}; + uint8_t sval[300] = {0}; + int res = ecdsa_asn1_get_signature(&sig[indx], intsiglen, rval, sval); + if (!res) { + PrintAndLogEx(NORMAL, "\t\tr: %s", sprint_hex(rval, 32)); + PrintAndLogEx(NORMAL, "\t\ts: %s", sprint_hex(sval, 32)); + } + } + indx += intsiglen; + + if (sigURI) { + size_t intsigurilen = (sig[indx] << 8) + sig[indx + 1]; + indx += 2; + PrintAndLogEx(NORMAL, "\tsignature uri [%d]: %.*s", intsigurilen, intsigurilen, &sig[indx]); + indx += intsigurilen; + } + + uint8_t certFormat = (sig[indx] >> 4) & 0x07; + uint8_t certCount = sig[indx] & 0x0f; + bool certURI = sig[indx] & 0x80; + + PrintAndLogEx(NORMAL, "\tcertificate format: %s", ((certFormat < sfNA) ? ndefCertificateFormat_s[certFormat] : ndefCertificateFormat_s[sfNA])); + PrintAndLogEx(NORMAL, "\tcertificates count: %d", certCount); + + // print certificates + indx++; + for (int i = 0; i < certCount; i++) { + size_t intcertlen = (sig[indx + 1] << 8) + sig[indx + 2]; + indx += 2; + + PrintAndLogEx(NORMAL, "\tcertificate %d [%d]: %s", i + 1, intcertlen, sprint_hex_inrow(&sig[indx], intcertlen)); + indx += intcertlen; + } + + // have certificate uri + if ((indx <= siglen) && certURI) { + size_t inturilen = (sig[indx] << 8) + sig[indx + 1]; + indx += 2; + PrintAndLogEx(NORMAL, "\tcertificate uri [%d]: %.*s", inturilen, inturilen, &sig[indx]); + indx += inturilen; + } + + return 0; +}; + +int ndefDecodePayload(NDEFHeader_t *ndef) { + + switch (ndef->TypeNameFormat) { + case tnfWellKnownRecord: + PrintAndLogEx(INFO, "Well Known Record"); + PrintAndLogEx(NORMAL, "\ttype: %.*s", ndef->TypeLen, ndef->Type); + + if (!strncmp((char *)ndef->Type, "T", ndef->TypeLen)) { + PrintAndLogEx(NORMAL, "\ttext : %.*s", ndef->PayloadLen, ndef->Payload); + } + + if (!strncmp((char *)ndef->Type, "U", ndef->TypeLen)) { + PrintAndLogEx(NORMAL, "\turi : %s%.*s", (ndef->Payload[0] <= 0x23 ? URI_s[ndef->Payload[0]] : "[err]"), ndef->PayloadLen, &ndef->Payload[1]); + } + + if (!strncmp((char *)ndef->Type, "Sig", ndef->TypeLen)) { + ndefDecodeSig(ndef->Payload, ndef->PayloadLen); + } + + break; + case tnfAbsoluteURIRecord: + PrintAndLogEx(INFO, "Absolute URI Record"); + PrintAndLogEx(NORMAL, "\ttype: %.*s", ndef->TypeLen, ndef->Type); + PrintAndLogEx(NORMAL, "\tpayload: %.*s", ndef->PayloadLen, ndef->Payload); + break; + default: + break; + } + return 0; +} + +int ndefRecordDecodeAndPrint(uint8_t *ndefRecord, size_t ndefRecordLen) { + NDEFHeader_t NDEFHeader = {0}; + int res = ndefDecodeHeader(ndefRecord, ndefRecordLen, &NDEFHeader); + if (res) + return res; + + ndefPrintHeader(&NDEFHeader); + + if (NDEFHeader.TypeLen) { + PrintAndLogEx(INFO, "Type data:"); + dump_buffer(NDEFHeader.Type, NDEFHeader.TypeLen, stdout, 1); + } + if (NDEFHeader.IDLen) { + PrintAndLogEx(INFO, "ID data:"); + dump_buffer(NDEFHeader.ID, NDEFHeader.IDLen, stdout, 1); + } + if (NDEFHeader.PayloadLen) { + PrintAndLogEx(INFO, "Payload data:"); + dump_buffer(NDEFHeader.Payload, NDEFHeader.PayloadLen, stdout, 1); + if (NDEFHeader.TypeLen) + ndefDecodePayload(&NDEFHeader); + } + + return 0; +} + +int ndefRecordsDecodeAndPrint(uint8_t *ndefRecord, size_t ndefRecordLen) { + bool firstRec = true; + size_t len = 0; + + while (len < ndefRecordLen) { + NDEFHeader_t NDEFHeader = {0}; + int res = ndefDecodeHeader(&ndefRecord[len], ndefRecordLen - len, &NDEFHeader); + if (res) + return res; + + if (firstRec) { + if (!NDEFHeader.MessageBegin) { + PrintAndLogEx(ERR, "NDEF first record have MessageBegin=false!"); + return 1; + } + firstRec = false; + } + + if (NDEFHeader.MessageEnd && len + NDEFHeader.RecLen != ndefRecordLen) { + PrintAndLogEx(ERR, "NDEF records have wrong length. Must be %d, calculated %d", ndefRecordLen, len + NDEFHeader.RecLen); + return 1; + } + + ndefRecordDecodeAndPrint(&ndefRecord[len], NDEFHeader.RecLen); + + len += NDEFHeader.RecLen; + + if (NDEFHeader.MessageEnd) + break; + } + + return 0; +} + +int NDEFDecodeAndPrint(uint8_t *ndef, size_t ndefLen, bool verbose) { + + size_t indx = 0; + + PrintAndLogEx(INFO, "NDEF decoding:"); + while (indx < ndefLen) { + switch (ndef[indx]) { + case 0x00: { + indx++; + uint16_t len = ndefTLVGetLength(&ndef[indx], &indx); + PrintAndLogEx(INFO, "-- NDEF NULL block."); + if (len) + PrintAndLogEx(WARNING, "NDEF NULL block size must be 0 instead of %d.", len); + indx += len; + break; + } + case 0x03: { + indx++; + uint16_t len = ndefTLVGetLength(&ndef[indx], &indx); + PrintAndLogEx(INFO, "-- NDEF message. len: %d", len); + + int res = ndefRecordsDecodeAndPrint(&ndef[indx], len); + if (res) + return res; + + indx += len; + break; + } + case 0xfd: { + indx++; + uint16_t len = ndefTLVGetLength(&ndef[indx], &indx); + PrintAndLogEx(INFO, "-- NDEF proprietary info. Skipped %d bytes.", len); + indx += len; + break; + } + case 0xfe: { + PrintAndLogEx(INFO, "-- NDEF Terminator. Done."); + return 0; + break; + } + default: { + PrintAndLogEx(ERR, "unknown tag 0x%02x", ndef[indx]); + return 1; + } + } + } + + return 0; +} diff --git a/client/mifare/ndef.h b/client/mifare/ndef.h new file mode 100644 index 00000000..1130ebba --- /dev/null +++ b/client/mifare/ndef.h @@ -0,0 +1,62 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2019 Merlok +// +// 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. +//----------------------------------------------------------------------------- +// NFC Data Exchange Format (NDEF) functions +//----------------------------------------------------------------------------- + +#ifndef _NDEF_H_ +#define _NDEF_H_ + +#include +#include +#include + +typedef enum { + tnfEmptyRecord = 0x00, + tnfWellKnownRecord = 0x01, + tnfMIMEMediaRecord = 0x02, + tnfAbsoluteURIRecord = 0x03, + tnfExternalRecord = 0x04, + tnfUnknownRecord = 0x05, + tnfUnchangedRecord = 0x06 +} TypeNameFormat_t; + +typedef enum { + stNotPresent = 0x00, + stRSASSA_PSS_SHA_1 = 0x01, + stRSASSA_PKCS1_v1_5_WITH_SHA_1 = 0x02, + stDSA = 0x03, + stECDSA = 0x04, + stNA = 0x05 +} ndefSigType_t; + +typedef enum { + sfX_509 = 0x00, + sfX9_68 = 0x01, + sfNA = 0x02 +} ndefCertificateFormat_t; + +typedef struct { + bool MessageBegin; + bool MessageEnd; + bool ChunkFlag; + bool ShortRecordBit; + bool IDLenPresent; + TypeNameFormat_t TypeNameFormat; + size_t TypeLen; + size_t PayloadLen; + size_t IDLen; + size_t len; + size_t RecLen; + uint8_t *Type; + uint8_t *Payload; + uint8_t *ID; +} NDEFHeader_t; + +extern int NDEFDecodeAndPrint(uint8_t *ndef, size_t ndefLen, bool verbose); + +#endif // _NDEF_H_ diff --git a/client/mifare4.c b/client/mifare4.c deleted file mode 100644 index 419e9b23..00000000 --- a/client/mifare4.c +++ /dev/null @@ -1,311 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (C) 2018 Merlok -// Copyright (C) 2018 drHatson -// -// 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. -//----------------------------------------------------------------------------- -// iso14443-4 mifare commands -//----------------------------------------------------------------------------- - -#include "mifare4.h" -#include -#include -#include "cmdhf14a.h" -#include "util.h" -#include "ui.h" -#include "crypto/libpcrypto.h" - -AccessConditions_t MFAccessConditions[] = { - {0x00, "read AB; write AB; increment AB; decrement transfer restore AB"}, - {0x01, "read AB; decrement transfer restore AB"}, - {0x02, "read AB"}, - {0x03, "read B; write B"}, - {0x04, "read AB; writeB"}, - {0x05, "read B"}, - {0x06, "read AB; write B; increment B; decrement transfer restore AB"}, - {0x07, "none"} -}; - -AccessConditions_t MFAccessConditionsTrailer[] = { - {0x00, "read A by A; read ACCESS by A; read B by A; write B by A"}, - {0x01, "write A by A; read ACCESS by A write ACCESS by A; read B by A; write B by A"}, - {0x02, "read ACCESS by A; read B by A"}, - {0x03, "write A by B; read ACCESS by AB; write ACCESS by B; write B by B"}, - {0x04, "write A by B; read ACCESS by AB; write B by B"}, - {0x05, "read ACCESS by AB; write ACCESS by B"}, - {0x06, "read ACCESS by AB"}, - {0x07, "read ACCESS by AB"} -}; - -char *mfGetAccessConditionsDesc(uint8_t blockn, uint8_t *data) { - static char StaticNone[] = "none"; - - uint8_t data1 = ((data[1] >> 4) & 0x0f) >> blockn; - uint8_t data2 = ((data[2]) & 0x0f) >> blockn; - uint8_t data3 = ((data[2] >> 4) & 0x0f) >> blockn; - - uint8_t cond = (data1 & 0x01) << 2 | (data2 & 0x01) << 1 | (data3 & 0x01); - - if (blockn == 3) { - for (int i = 0; i < ARRAYLEN(MFAccessConditionsTrailer); i++) - if (MFAccessConditionsTrailer[i].cond == cond) { - return MFAccessConditionsTrailer[i].description; - } - } else { - for (int i = 0; i < ARRAYLEN(MFAccessConditions); i++) - if (MFAccessConditions[i].cond == cond) { - return MFAccessConditions[i].description; - } - }; - - return StaticNone; -}; - -int CalculateEncIVCommand(mf4Session *session, uint8_t *iv, bool verbose) { - memcpy(&iv[0], session->TI, 4); - memcpy(&iv[4], &session->R_Ctr, 2); - memcpy(&iv[6], &session->W_Ctr, 2); - memcpy(&iv[8], &session->R_Ctr, 2); - memcpy(&iv[10], &session->W_Ctr, 2); - memcpy(&iv[12], &session->R_Ctr, 2); - memcpy(&iv[14], &session->W_Ctr, 2); - - return 0; -} - -int CalculateEncIVResponse(mf4Session *session, uint8_t *iv, bool verbose) { - memcpy(&iv[0], &session->R_Ctr, 2); - memcpy(&iv[2], &session->W_Ctr, 2); - memcpy(&iv[4], &session->R_Ctr, 2); - memcpy(&iv[6], &session->W_Ctr, 2); - memcpy(&iv[8], &session->R_Ctr, 2); - memcpy(&iv[10], &session->W_Ctr, 2); - memcpy(&iv[12], session->TI, 4); - - return 0; -} - - -int CalculateMAC(mf4Session *session, MACType_t mtype, uint8_t blockNum, uint8_t blockCount, uint8_t *data, int datalen, uint8_t *mac, bool verbose) { - if (!session || !session->Authenticated || !mac || !data || !datalen || datalen < 1) - return 1; - - memset(mac, 0x00, 8); - - uint16_t ctr = session->R_Ctr; - switch(mtype) { - case mtypWriteCmd: - case mtypWriteResp: - ctr = session->W_Ctr; - break; - case mtypReadCmd: - case mtypReadResp: - break; - } - - uint8_t macdata[2049] = {data[0], (ctr & 0xFF), (ctr >> 8), 0}; - int macdatalen = datalen; - memcpy(&macdata[3], session->TI, 4); - - switch(mtype) { - case mtypReadCmd: - memcpy(&macdata[7], &data[1], datalen - 1); - macdatalen = datalen + 6; - break; - case mtypReadResp: - macdata[7] = blockNum; - macdata[8] = 0; - macdata[9] = blockCount; - memcpy(&macdata[10], &data[1], datalen - 1); - macdatalen = datalen + 9; - break; - case mtypWriteCmd: - memcpy(&macdata[7], &data[1], datalen - 1); - macdatalen = datalen + 6; - break; - case mtypWriteResp: - macdatalen = 1 + 6; - break; - } - - if (verbose) - PrintAndLog("MAC data[%d]: %s", macdatalen, sprint_hex(macdata, macdatalen)); - - return aes_cmac8(NULL, session->Kmac, macdata, mac, macdatalen); -} - -int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool verbose) { - uint8_t data[257] = {0}; - int datalen = 0; - - uint8_t RndA[17] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00}; - uint8_t RndB[17] = {0}; - - if (session) - session->Authenticated = false; - - uint8_t cmd1[] = {0x70, keyn[1], keyn[0], 0x00}; - int res = ExchangeRAW14a(cmd1, sizeof(cmd1), activateField, true, data, sizeof(data), &datalen); - if (res) { - PrintAndLog("ERROR exchande raw error: %d", res); - DropField(); - return 2; - } - - if (verbose) - PrintAndLog("phase2: %s", sprint_hex(cmd2, 33)); - - res = ExchangeRAW14a(cmd2, sizeof(cmd2), false, true, data, sizeof(data), &datalen); - if (res) { - PrintAndLog("ERROR exchande raw error: %d", res); - DropField(); - return 4; - } - - if (verbose) - PrintAndLog("Authenticated = true; - session->R_Ctr = 0; - session->W_Ctr = 0; - session->KeyNum = keyn[1] + (keyn[0] << 8); - memmove(session->RndA, RndA, 16); - memmove(session->RndB, RndB, 16); - memmove(session->Key, key, 16); - memmove(session->TI, raw, 4); - memmove(session->PICCap2, &raw[20], 6); - memmove(session->PCDCap2, &raw[26], 6); - memmove(session->Kenc, kenc, 16); - memmove(session->Kmac, kmac, 16); - } - - PrintAndLog("Authentication OK"); - - return 0; -} - -// Mifare Memory Structure: up to 32 Sectors with 4 blocks each (1k and 2k cards), -// plus evtl. 8 sectors with 16 blocks each (4k cards) -uint8_t mfNumBlocksPerSector(uint8_t sectorNo) { - if (sectorNo < 32) - return 4; - else - return 16; -} - -uint8_t mfFirstBlockOfSector(uint8_t sectorNo) { - if (sectorNo < 32) - return sectorNo * 4; - else - return 32 * 4 + (sectorNo - 32) * 16; -} - -uint8_t mfSectorTrailer(uint8_t blockNo) { - if (blockNo < 32*4) { - return (blockNo | 0x03); - } else { - return (blockNo | 0x0f); - } -} - -bool mfIsSectorTrailer(uint8_t blockNo) { - return (blockNo == mfSectorTrailer(blockNo)); -} - -uint8_t mfSectorNum(uint8_t blockNo) { - if (blockNo < 32 * 4) - return blockNo / 4; - else - return 32 + (blockNo - 32 * 4) / 16; - -} diff --git a/client/obj/mifare/.dummy b/client/obj/mifare/.dummy new file mode 100644 index 00000000..e69de29b diff --git a/client/scripting.c b/client/scripting.c index ed7ae007..85a788e9 100644 --- a/client/scripting.c +++ b/client/scripting.c @@ -19,7 +19,7 @@ #include "usb_cmd.h" #include "cmdmain.h" #include "util.h" -#include "mifarehost.h" +#include "mifare/mifarehost.h" #include "../common/iso15693tools.h" #include "iso14443crc.h" #include "../common/crc16.h" diff --git a/common/crc.c b/common/crc.c index 0c73474f..b6d7551e 100644 --- a/common/crc.c +++ b/common/crc.c @@ -9,6 +9,20 @@ #include #include +#define BITMASK(X) (1 << (X)) + +uint32_t reflect(uint32_t v, int b) { + uint32_t t = v; + for (int i = 0; i < b; ++i) { + if (t & 1) + v |= BITMASK((b - 1) - i); + else + v &= ~BITMASK((b - 1) - i); + t >>= 1; + } + return v; +} + void crc_init(crc_t *crc, int order, uint32_t polynom, uint32_t initial_value, uint32_t final_xor) { crc->order = order; @@ -54,3 +68,13 @@ uint32_t CRC8Maxim(uint8_t *buff, size_t size) } return crc_finish(&crc); } + +// width=8 poly=0x1d, init=0xc7 (0xe3 - WRONG! but it mentioned in MAD datasheet) refin=false refout=false xorout=0x00 name="CRC-8/MIFARE-MAD" +uint32_t CRC8Mad(uint8_t *buff, size_t size) { + crc_t crc; + crc_init(&crc, 8, reflect(0x1d, 8), reflect(0xc7, 8), 0); + for (int i = 0; i < size; ++i) + crc_update(&crc, reflect(buff[i], 8), 8); + + return reflect(crc_finish(&crc), 8); +} diff --git a/common/crc.h b/common/crc.h index 946be8a1..e2ccd34b 100644 --- a/common/crc.h +++ b/common/crc.h @@ -11,6 +11,7 @@ #include #include +#include typedef struct crc { uint32_t state; @@ -39,6 +40,10 @@ extern uint32_t crc_finish(crc_t *crc); // Calculate CRC-8/Maxim checksum uint32_t CRC8Maxim(uint8_t *buff, size_t size ); + +// Calculate CRC-8 Mifare MAD checksum +uint32_t CRC8Mad(uint8_t *buff, size_t size); + /* Static initialization of a crc structure */ #define CRC_INITIALIZER(_order, _polynom, _initial_value, _final_xor) { \ .state = ((_initial_value) & ((1L<<(_order))-1)), \ diff --git a/include/mifare.h b/include/mifare.h index bb07adcd..144094f0 100644 --- a/include/mifare.h +++ b/include/mifare.h @@ -13,6 +13,12 @@ #include "common.h" +#define MF_KEY_A 0 +#define MF_KEY_B 1 + +#define MF_MAD1_SECTOR 0x00 +#define MF_MAD2_SECTOR 0x10 + //----------------------------------------------------------------------------- // ISO 14443A //----------------------------------------------------------------------------- diff --git a/tools/mfkey/Makefile b/tools/mfkey/Makefile index 9dab37f5..5d6de924 100755 --- a/tools/mfkey/Makefile +++ b/tools/mfkey/Makefile @@ -1,4 +1,4 @@ -VPATH = ../../common ../../common/crapto1 ../../client +VPATH = ../../common ../../common/crapto1 ../../client ../../client/mifare CC = gcc LD = gcc CFLAGS += -std=c99 -D_ISOC99_SOURCE -I../../include -I../../common -I../../client -Wall -O3 diff --git a/tools/mfkey/mfkey32.c b/tools/mfkey/mfkey32.c index d84305d0..1f7747b5 100755 --- a/tools/mfkey/mfkey32.c +++ b/tools/mfkey/mfkey32.c @@ -3,7 +3,7 @@ #include #include #include "crapto1/crapto1.h" -#include "mfkey.h" +#include "mifare/mfkey.h" #include "util_posix.h" From ca8a3478d949a03953129ec34d209a9c80079252 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Sun, 24 Mar 2019 18:04:42 +0100 Subject: [PATCH 076/189] iso14443b modifications (#804) * LED handling * improve 'hf plot' support --- armsrc/iso14443a.c | 2 +- armsrc/iso14443b.c | 41 +++++++++++++++++++++++++++-------------- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index d3d0138b..2f4baf17 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -2591,12 +2591,12 @@ void RAMFUNC SniffMifare(uint8_t param) { } // main cycle + FpgaDisableTracing(); FpgaDisableSscDma(); LEDsoff(); DbpString("COMMAND FINISHED."); - FpgaDisableTracing(); MfSniffEnd(); Dbprintf("maxDataLen=%x, Uart.state=%x, Uart.len=%x", maxDataLen, Uart.state, Uart.len); diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index 3ebaa539..5e770a77 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -327,6 +327,7 @@ static int GetIso14443bCommandFromReader(uint8_t *received, uint16_t *len) //----------------------------------------------------------------------------- void SimulateIso14443bTag(void) { + LED_A_ON(); // the only commands we understand is WUPB, AFI=0, Select All, N=1: static const uint8_t cmd1[] = { 0x05, 0x00, 0x08, 0x39, 0x73 }; // WUPB // ... and REQB, AFI=0, Normal Request, N=1: @@ -465,6 +466,9 @@ void SimulateIso14443bTag(void) LogTrace(resp, respLen, 0, 0, NULL, false); } + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_A_OFF(); } //============================================================================= @@ -861,6 +865,7 @@ static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len) */ int iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *response) { + LED_A_ON(); uint8_t message_frame[message_length + 4]; // PCB message_frame[0] = 0x0A | pcb_blocknum; @@ -875,8 +880,10 @@ int iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *respo CodeAndTransmit14443bAsReader(message_frame, message_length + 4); // get response GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); + FpgaDisableTracing(); if(Demod.len < 3) { + LED_A_OFF(); return 0; } // TODO: Check CRC @@ -885,6 +892,7 @@ int iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *respo { memcpy(response, Demod.output, Demod.len); } + LED_A_OFF(); return Demod.len; } @@ -957,6 +965,7 @@ void iso14443b_setup() { //----------------------------------------------------------------------------- void ReadSTMemoryIso14443b(uint32_t dwLast) { + LED_A_ON(); uint8_t i = 0x00; FpgaDownloadAndGo(FPGA_BITSTREAM_HF); @@ -984,9 +993,9 @@ void ReadSTMemoryIso14443b(uint32_t dwLast) GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); if (Demod.len == 0) { - DbpString("No response from tag"); - LED_D_OFF(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + DbpString("No response from tag"); + LEDsoff(); return; } else { Dbprintf("Randomly generated Chip ID (+ 2 byte CRC): %02x %02x %02x", @@ -1001,24 +1010,24 @@ void ReadSTMemoryIso14443b(uint32_t dwLast) CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1)); GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); if (Demod.len != 3) { - Dbprintf("Expected 3 bytes from tag, got %d", Demod.len); - LED_D_OFF(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + Dbprintf("Expected 3 bytes from tag, got %d", Demod.len); + LEDsoff(); return; } // Check the CRC of the answer: ComputeCrc14443(CRC_14443_B, Demod.output, 1 , &cmd1[2], &cmd1[3]); if(cmd1[2] != Demod.output[1] || cmd1[3] != Demod.output[2]) { - DbpString("CRC Error reading select response."); - LED_D_OFF(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + DbpString("CRC Error reading select response."); + LEDsoff(); return; } // Check response from the tag: should be the same UID as the command we just sent: if (cmd1[1] != Demod.output[0]) { - Dbprintf("Bad response to SELECT from Tag, aborting: %02x %02x", cmd1[1], Demod.output[0]); - LED_D_OFF(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + Dbprintf("Bad response to SELECT from Tag, aborting: %02x %02x", cmd1[1], Demod.output[0]); + LEDsoff(); return; } @@ -1029,9 +1038,9 @@ void ReadSTMemoryIso14443b(uint32_t dwLast) CodeAndTransmit14443bAsReader(cmd1, 3); // Only first three bytes for this one GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); if (Demod.len != 10) { - Dbprintf("Expected 10 bytes from tag, got %d", Demod.len); - LED_D_OFF(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + Dbprintf("Expected 10 bytes from tag, got %d", Demod.len); + LEDsoff(); return; } // The check the CRC of the answer (use cmd1 as temporary variable): @@ -1060,9 +1069,9 @@ void ReadSTMemoryIso14443b(uint32_t dwLast) CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1)); GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); if (Demod.len != 6) { // Check if we got an answer from the tag - DbpString("Expected 6 bytes from tag, got less..."); - LED_D_OFF(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + DbpString("Expected 6 bytes from tag, got less..."); + LEDsoff(); return; } // The check the CRC of the answer (use cmd1 as temporary variable): @@ -1082,8 +1091,8 @@ void ReadSTMemoryIso14443b(uint32_t dwLast) i++; } - LED_D_OFF(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); } @@ -1106,6 +1115,7 @@ void ReadSTMemoryIso14443b(uint32_t dwLast) */ void RAMFUNC SnoopIso14443b(void) { + LED_A_ON(); FpgaDownloadAndGo(FPGA_BITSTREAM_HF); BigBuf_free(); @@ -1221,13 +1231,13 @@ void RAMFUNC SnoopIso14443b(void) } FpgaDisableSscDma(); - LEDsoff(); DbpString("Snoop statistics:"); Dbprintf(" Max behind by: %i", maxBehindBy); Dbprintf(" Uart State: %x", Uart.state); Dbprintf(" Uart ByteCnt: %i", Uart.byteCnt); Dbprintf(" Uart ByteCntMax: %i", Uart.byteCntMax); Dbprintf(" Trace length: %i", BigBuf_get_traceLen()); + LEDsoff(); } @@ -1260,9 +1270,12 @@ void SendRawCommand14443B(uint32_t datalen, uint32_t recv, uint8_t powerfield, u if(recv) { GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); + FpgaDisableTracing(); uint16_t iLen = MIN(Demod.len, USB_CMD_DATA_SIZE); cmd_send(CMD_ACK, iLen, 0, 0, Demod.output, iLen); } + + FpgaDisableTracing(); } if(!powerfield) { From 5ea2a24839c71ba6e58af937a392a6204b8b4696 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Sun, 24 Mar 2019 18:11:41 +0100 Subject: [PATCH 077/189] FPGA changes (#803) * merge hf_rx_xcorr and hf_tx modes into one module with common ssp_clk and ssp_frame * get rid of most of the warnings when compiling the HF verilog sources * refactoring the constants in Verilog sources --- armsrc/appmain.c | 5 +- armsrc/fpgaloader.c | 10 +- armsrc/fpgaloader.h | 30 +-- armsrc/iso14443b.c | 63 ++++--- armsrc/iso14443b.h | 18 +- armsrc/iso15693.c | 138 +++++++------- armsrc/legicrf.c | 16 +- fpga/Makefile | 4 +- fpga/fpga.ucf | 60 +++--- fpga/fpga_hf.bit | Bin 42175 -> 42175 bytes fpga/fpga_hf.v | 161 ++++++++-------- fpga/hi_get_trace.v | 17 +- fpga/hi_iso14443a.v | 55 +++--- fpga/hi_read_tx.v | 78 -------- fpga/{hi_read_rx_xcorr.v => hi_reader.v} | 223 +++++++++++++---------- fpga/hi_simulate.v | 33 ++-- fpga/hi_sniffer.v | 13 +- 17 files changed, 426 insertions(+), 498 deletions(-) delete mode 100644 fpga/hi_read_tx.v rename fpga/{hi_read_rx_xcorr.v => hi_reader.v} (58%) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 8824847e..926ac52e 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -24,6 +24,7 @@ #include "legicrfsim.h" #include "hitag2.h" #include "hitagS.h" +#include "iso14443b.h" #include "iso15693.h" #include "lfsampling.h" #include "BigBuf.h" @@ -243,7 +244,7 @@ void MeasureAntennaTuningHfOnly(int *vHf) // Let the FPGA drive the high-frequency antenna around 13.56 MHz. LED_A_ON(); FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER); SpinDelay(20); *vHf = AvgAdc_Voltage_HF(); LED_A_OFF(); @@ -285,7 +286,7 @@ void MeasureAntennaTuningHf(void) // Let the FPGA drive the high-frequency antenna around 13.56 MHz. FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER); for (;;) { SpinDelay(500); diff --git a/armsrc/fpgaloader.c b/armsrc/fpgaloader.c index d1d527c4..214f4843 100644 --- a/armsrc/fpgaloader.c +++ b/armsrc/fpgaloader.c @@ -130,21 +130,21 @@ void FpgaSetupSsc(uint8_t FPGA_mode) // Now set up the SSC proper, starting from a known state. AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST; - // RX clock comes from TX clock, RX starts when TX starts, data changes - // on RX clock rising edge, sampled on falling edge + // RX clock comes from TX clock, RX starts on Transmit Start, + // data and frame signal is sampled on falling edge of RK AT91C_BASE_SSC->SSC_RCMR = SSC_CLOCK_MODE_SELECT(1) | SSC_CLOCK_MODE_START(1); // 8, 16 or 32 bits per transfer, no loopback, MSB first, 1 transfer per sync // pulse, no output sync - if ((FPGA_mode & 0xe0) == FPGA_MAJOR_MODE_HF_READER_RX_XCORR) { + if ((FPGA_mode & 0xe0) == FPGA_MAJOR_MODE_HF_READER) { AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(16) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0); } else { AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0); } // TX clock comes from TK pin, no clock output, outputs change on falling - // edge of TK, sample on rising edge of TK, start on positive-going edge of sync - AT91C_BASE_SSC->SSC_TCMR = SSC_CLOCK_MODE_SELECT(2) | SSC_CLOCK_MODE_START(5); + // edge of TK, frame sync is sampled on rising edge of TK, start TX on rising edge of TF + AT91C_BASE_SSC->SSC_TCMR = SSC_CLOCK_MODE_SELECT(2) | SSC_CLOCK_MODE_START(5); // tx framing is the same as the rx framing AT91C_BASE_SSC->SSC_TFMR = AT91C_BASE_SSC->SSC_RFMR; diff --git a/armsrc/fpgaloader.h b/armsrc/fpgaloader.h index 006de8de..42f9ccc6 100644 --- a/armsrc/fpgaloader.h +++ b/armsrc/fpgaloader.h @@ -49,12 +49,11 @@ void SetAdcMuxFor(uint32_t whichGpio); #define FPGA_MAJOR_MODE_LF_EDGE_DETECT (1<<5) #define FPGA_MAJOR_MODE_LF_PASSTHRU (2<<5) // HF -#define FPGA_MAJOR_MODE_HF_READER_TX (0<<5) -#define FPGA_MAJOR_MODE_HF_READER_RX_XCORR (1<<5) -#define FPGA_MAJOR_MODE_HF_SIMULATOR (2<<5) -#define FPGA_MAJOR_MODE_HF_ISO14443A (3<<5) -#define FPGA_MAJOR_MODE_HF_SNOOP (4<<5) -#define FPGA_MAJOR_MODE_HF_GET_TRACE (5<<5) +#define FPGA_MAJOR_MODE_HF_READER (0<<5) +#define FPGA_MAJOR_MODE_HF_SIMULATOR (1<<5) +#define FPGA_MAJOR_MODE_HF_ISO14443A (2<<5) +#define FPGA_MAJOR_MODE_HF_SNOOP (3<<5) +#define FPGA_MAJOR_MODE_HF_GET_TRACE (4<<5) // BOTH #define FPGA_MAJOR_MODE_OFF (7<<5) @@ -66,14 +65,19 @@ void SetAdcMuxFor(uint32_t whichGpio); #define FPGA_LF_EDGE_DETECT_READER_FIELD (1<<0) #define FPGA_LF_EDGE_DETECT_TOGGLE_MODE (1<<1) -// Options for the HF reader, tx to tag -#define FPGA_HF_READER_TX_SHALLOW_MOD (1<<0) +// Options for the HF reader +#define FPGA_HF_READER_MODE_RECEIVE_IQ (0<<0) +#define FPGA_HF_READER_MODE_RECEIVE_AMPLITUDE (1<<0) +#define FPGA_HF_READER_MODE_RECEIVE_PHASE (2<<0) +#define FPGA_HF_READER_MODE_SEND_FULL_MOD (3<<0) +#define FPGA_HF_READER_MODE_SEND_SHALLOW_MOD (4<<0) +#define FPGA_HF_READER_MODE_SNOOP_IQ (5<<0) +#define FPGA_HF_READER_MODE_SNOOP_AMPLITUDE (6<<0) +#define FPGA_HF_READER_MODE_SNOOP_PHASE (7<<0) -// Options for the HF reader, correlating against rx from tag -#define FPGA_HF_READER_RX_XCORR_848_KHZ (1<<0) -#define FPGA_HF_READER_RX_XCORR_SNOOP (1<<1) -#define FPGA_HF_READER_RX_XCORR_QUARTER_FREQ (1<<2) -#define FPGA_HF_READER_RX_XCORR_AMPLITUDE (1<<3) +#define FPGA_HF_READER_SUBCARRIER_848_KHZ (0<<3) +#define FPGA_HF_READER_SUBCARRIER_424_KHZ (1<<3) +#define FPGA_HF_READER_SUBCARRIER_212_KHZ (2<<3) // Options for the HF simulated tag, how to modulate #define FPGA_HF_SIMULATOR_NO_MODULATION (0<<0) diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index 5e770a77..f276158f 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -18,8 +18,9 @@ #include "string.h" #include "iso14443crc.h" #include "fpgaloader.h" +#include "BigBuf.h" -#define RECEIVE_SAMPLES_TIMEOUT 1000 // TR0 max is 256/fs = 256/(848kHz) = 302us or 64 samples from FPGA. 1000 seems to be much too high? +#define RECEIVE_SAMPLES_TIMEOUT 64 // TR0 max is 256/fs = 256/(848kHz) = 302us or 64 samples from FPGA #define ISO14443B_DMA_BUFFER_SIZE 128 // PCB Block number for APDUs @@ -692,7 +693,7 @@ static void DemodInit(uint8_t *data) * Demodulate the samples we received from the tag, also log to tracebuffer * quiet: set to 'true' to disable debug output */ -static void GetSamplesFor14443bDemod(int n, bool quiet) +static void GetSamplesFor14443bDemod(int timeout, bool quiet) { int maxBehindBy = 0; bool gotFrame = false; @@ -716,7 +717,7 @@ static void GetSamplesFor14443bDemod(int n, bool quiet) while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)) // Setup and start DMA. - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); FpgaSetupSscDma((uint8_t*) dmaBuf, ISO14443B_DMA_BUFFER_SIZE); uint16_t *upTo = dmaBuf; @@ -725,7 +726,7 @@ static void GetSamplesFor14443bDemod(int n, bool quiet) // Signal field is ON with the appropriate LED: LED_D_ON(); // And put the FPGA in the appropriate mode - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_848_KHZ | FPGA_HF_READER_MODE_RECEIVE_IQ); for(;;) { int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & (ISO14443B_DMA_BUFFER_SIZE-1); @@ -754,7 +755,8 @@ static void GetSamplesFor14443bDemod(int n, bool quiet) break; } - if(samples > n) { + if(samples > timeout && Demod.state < DEMOD_PHASE_REF_TRAINING) { + LED_C_OFF(); break; } } @@ -774,28 +776,21 @@ static void GetSamplesFor14443bDemod(int n, bool quiet) //----------------------------------------------------------------------------- static void TransmitFor14443b(void) { - int c; - - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_TX); - - // Signal field is ON with the appropriate Red LED - LED_D_ON(); - // Signal we are transmitting with the Green LED + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_SHALLOW_MOD); LED_B_ON(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD); - - c = 0; - for(;;) { - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = ~ToSend[c]; - c++; - if(c >= ToSendMax) { - break; - } + for(int c = 0; c < ToSendMax; c++) { + uint8_t data = ToSend[c]; + for (int i = 0; i < 8; i++) { + uint16_t send_word = (data & 0x80) ? 0x0000 : 0xffff; + while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ; + AT91C_BASE_SSC->SSC_THR = send_word; + while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ; + AT91C_BASE_SSC->SSC_THR = send_word; + data <<= 1; } WDT_HIT(); } - LED_B_OFF(); // Finished sending + LED_B_OFF(); } @@ -942,13 +937,13 @@ int iso14443b_select_card() void iso14443b_setup() { FpgaDownloadAndGo(FPGA_BITSTREAM_HF); // Set up the synchronous serial port - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_TX); + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); // connect Demodulated Signal to ADC: SetAdcMuxFor(GPIO_MUXSEL_HIPKD); // Signal field is on with the appropriate LED LED_D_ON(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_SHALLOW_MOD); DemodReset(); UartReset(); @@ -976,12 +971,12 @@ void ReadSTMemoryIso14443b(uint32_t dwLast) SpinDelay(200); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); // Now give it time to spin up. // Signal field is on with the appropriate LED LED_D_ON(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_SHALLOW_MOD); SpinDelay(200); clear_trace(); @@ -1143,15 +1138,15 @@ void RAMFUNC SnoopIso14443b(void) Dbprintf(" tag -> Reader: %i bytes", MAX_FRAME_SIZE); Dbprintf(" DMA: %i bytes", ISO14443B_DMA_BUFFER_SIZE); - // Signal field is off, no reader signal, no tag signal - LEDsoff(); + // Signal field is off + LED_D_OFF(); // And put the FPGA in the appropriate mode - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ | FPGA_HF_READER_RX_XCORR_SNOOP); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_848_KHZ | FPGA_HF_READER_MODE_SNOOP_IQ); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); // Setup for the DMA. - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); upTo = dmaBuf; lastRxCounter = ISO14443B_DMA_BUFFER_SIZE; FpgaSetupSscDma((uint8_t*) dmaBuf, ISO14443B_DMA_BUFFER_SIZE); @@ -1255,12 +1250,14 @@ void RAMFUNC SnoopIso14443b(void) */ void SendRawCommand14443B(uint32_t datalen, uint32_t recv, uint8_t powerfield, uint8_t data[]) { + LED_A_ON(); FpgaDownloadAndGo(FPGA_BITSTREAM_HF); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); // switch field on and give tag some time to power up LED_D_ON(); - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_TX); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_SHALLOW_MOD); + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); SpinDelay(10); if (datalen){ @@ -1282,5 +1279,7 @@ void SendRawCommand14443B(uint32_t datalen, uint32_t recv, uint8_t powerfield, u FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_D_OFF(); } + + LED_A_OFF(); } diff --git a/armsrc/iso14443b.h b/armsrc/iso14443b.h index de6faa92..3326ab12 100644 --- a/armsrc/iso14443b.h +++ b/armsrc/iso14443b.h @@ -10,12 +10,18 @@ // Routines to support ISO 14443 type B. //----------------------------------------------------------------------------- -#ifndef __ISO14443B_H -#define __ISO14443B_H -#include "common.h" +#ifndef ISO14443B_H__ +#define ISO14443B_H__ -int iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *response); -void iso14443b_setup(); -int iso14443b_select_card(); +#include +#include + +extern int iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *response); +extern void iso14443b_setup(); +extern int iso14443b_select_card(); +extern void SimulateIso14443bTag(void); +extern void ReadSTMemoryIso14443b(uint32_t); +extern void SnoopIso14443b(void); +extern void SendRawCommand14443B(uint32_t, uint32_t, uint8_t, uint8_t[]); #endif /* __ISO14443B_H */ diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index d988e2b9..e3524375 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -80,11 +80,14 @@ static int DEBUG = 0; #define ISO15693_MAX_RESPONSE_LENGTH 36 // allows read single block with the maximum block size of 256bits. Read multiple blocks not supported yet #define ISO15693_MAX_COMMAND_LENGTH 45 // allows write single block with the maximum block size of 256bits. Write multiple blocks not supported yet -// timing. Delays in SSP_CLK ticks. -#define DELAY_READER_TO_ARM 8 -#define DELAY_ARM_TO_READER 1 -#define DELAY_ISO15693_VCD_TO_VICC 132 // 132/423.75kHz = 311.5us from end of EOF to start of tag response -#define DELAY_ISO15693_VICC_TO_VCD 1017 // 1017/3.39MHz = 300us between end of tag response and next reader command +// timing. Delays in SSP_CLK ticks. +// SSP_CLK runs at 13,56MHz / 32 = 423.75kHz when simulating a tag +#define DELAY_READER_TO_ARM_SIM 8 +#define DELAY_ARM_TO_READER_SIM 1 +#define DELAY_ISO15693_VCD_TO_VICC_SIM 132 // 132/423.75kHz = 311.5us from end of command EOF to start of tag response +//SSP_CLK runs at 13.56MHz / 4 = 3,39MHz when acting as reader +#define DELAY_ISO15693_VCD_TO_VICC_READER 1056 // 1056/3,39MHz = 311.5us from end of command EOF to start of tag response +#define DELAY_ISO15693_VICC_TO_VCD_READER 1017 // 1017/3.39MHz = 300us between end of tag response and next reader command // --------------------------- // Signal Processing @@ -269,22 +272,28 @@ static void CodeIso15693AsTag(uint8_t *cmd, int n) // Transmit the command (to the tag) that was placed in cmd[]. static void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t start_time) { - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_TX); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_FULL_MOD); + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); - while (GetCountSspClk() < start_time); + while (GetCountSspClk() < start_time) ; LED_B_ON(); - for(int c = 0; c < len; ) { - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = ~cmd[c]; - c++; - } - WDT_HIT(); - } + for(int c = 0; c < len; c++) { + uint8_t data = cmd[c]; + for (int i = 0; i < 8; i++) { + uint16_t send_word = (data & 0x80) ? 0x0000 : 0xffff; + while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ; + AT91C_BASE_SSC->SSC_THR = send_word; + while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ; + AT91C_BASE_SSC->SSC_THR = send_word; + data <<= 1; + } + WDT_HIT(); + } LED_B_OFF(); } + //----------------------------------------------------------------------------- // Transmit the tag response (to the reader) that was placed in cmd[]. //----------------------------------------------------------------------------- @@ -562,10 +571,10 @@ static int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, int tim while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)); // And put the FPGA in the appropriate mode - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_AMPLITUDE); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_424_KHZ | FPGA_HF_READER_MODE_RECEIVE_AMPLITUDE); // Setup and start DMA. - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); FpgaSetupSscDma((uint8_t*) dmaBuf, ISO15693_DMA_BUFFER_SIZE); uint16_t *upTo = dmaBuf; @@ -927,7 +936,7 @@ static int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint3 for (int i = 7; i >= 0; i--) { if (Handle15693SampleFromReader((b >> i) & 0x01, &DecodeReader)) { - *eof_time = bit_time + samples - DELAY_READER_TO_ARM; // end of EOF + *eof_time = bit_time + samples - DELAY_READER_TO_ARM_SIM; // end of EOF gotFrame = true; break; } @@ -954,7 +963,7 @@ static int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint3 samples, gotFrame, DecodeReader.state, DecodeReader.byteCount, DecodeReader.bitCount, DecodeReader.posCount); if (DecodeReader.byteCount > 0) { - LogTrace(DecodeReader.output, DecodeReader.byteCount, 0, 0, NULL, true); + LogTrace(DecodeReader.output, DecodeReader.byteCount, 0, *eof_time, NULL, true); } return DecodeReader.byteCount; @@ -997,34 +1006,23 @@ void AcquireRawAdcSamplesIso15693(void) uint8_t *dest = BigBuf_get_addr(); FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - BuildIdentifyRequest(); - + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER); + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + BuildIdentifyRequest(); + // Give the tags time to energize LED_D_ON(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); SpinDelay(100); // Now send the command - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_TX); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX); - - LED_B_ON(); - for(int c = 0; c < ToSendMax; ) { - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = ~ToSend[c]; - c++; - } - WDT_HIT(); - } - LED_B_OFF(); + TransmitTo15693Tag(ToSend, ToSendMax, 0); // wait for last transfer to complete - while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)); + while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)) ; - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_AMPLITUDE); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_424_KHZ | FPGA_HF_READER_MODE_RECEIVE_AMPLITUDE); for(int c = 0; c < 4000; ) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { @@ -1047,7 +1045,6 @@ void SnoopIso15693(void) clear_trace(); set_tracing(true); - // The DMA buffer, used to stream samples from the FPGA uint16_t* dmaBuf = (uint16_t*)BigBuf_malloc(ISO15693_DMA_BUFFER_SIZE*sizeof(uint16_t)); uint16_t *upTo; @@ -1072,13 +1069,13 @@ void SnoopIso15693(void) Dbprintf(" tag -> Reader: %i bytes", ISO15693_MAX_RESPONSE_LENGTH); Dbprintf(" DMA: %i bytes", ISO15693_DMA_BUFFER_SIZE * sizeof(uint16_t)); } - Dbprintf("Snoop started. Press button to stop."); + Dbprintf("Snoop started. Press PM3 Button to stop."); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_SNOOP | FPGA_HF_READER_RX_XCORR_AMPLITUDE); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNOOP_AMPLITUDE); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); // Setup for the DMA. - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); upTo = dmaBuf; FpgaSetupSscDma((uint8_t*) dmaBuf, ISO15693_DMA_BUFFER_SIZE); @@ -1173,7 +1170,6 @@ void SnoopIso15693(void) // Initialize the proxmark as iso15k reader -// (this might produces glitches that confuse some tags static void Iso15693InitReader() { FpgaDownloadAndGo(FPGA_BITSTREAM_HF); // Setup SSC @@ -1185,11 +1181,11 @@ static void Iso15693InitReader() { SpinDelay(10); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); // Give the tags time to energize LED_D_ON(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER); SpinDelay(250); } @@ -1284,7 +1280,7 @@ int SendDataTag(uint8_t *send, int sendlen, bool init, int speed, uint8_t *recv, // Now wait for a response if (recv != NULL) { - answerLen = GetIso15693AnswerFromTag(recv, max_recv_len, DELAY_ISO15693_VCD_TO_VICC * 2); + answerLen = GetIso15693AnswerFromTag(recv, max_recv_len, DELAY_ISO15693_VCD_TO_VICC_READER * 2); } LED_A_OFF(); @@ -1368,10 +1364,10 @@ void SetDebugIso15693(uint32_t debug) { } -//----------------------------------------------------------------------------- -// Simulate an ISO15693 reader, perform anti-collision and then attempt to read a sector +//--------------------------------------------------------------------------------------- +// Simulate an ISO15693 reader, perform anti-collision and then attempt to read a sector. // all demodulation performed in arm rather than host. - greg -//----------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------- void ReaderIso15693(uint32_t parameter) { LEDsoff(); @@ -1388,7 +1384,7 @@ void ReaderIso15693(uint32_t parameter) SetAdcMuxFor(GPIO_MUXSEL_HIPKD); // Setup SSC - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); // Start from off (no field generated) FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); @@ -1396,7 +1392,7 @@ void ReaderIso15693(uint32_t parameter) // Give the tags time to energize LED_D_ON(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER); SpinDelay(200); StartCountSspClk(); @@ -1407,10 +1403,10 @@ void ReaderIso15693(uint32_t parameter) // Now send the IDENTIFY command BuildIdentifyRequest(); TransmitTo15693Tag(ToSend, ToSendMax, 0); - + // Now wait for a response - answerLen = GetIso15693AnswerFromTag(answer, sizeof(answer), DELAY_ISO15693_VCD_TO_VICC * 2) ; - uint32_t start_time = GetCountSspClk() + DELAY_ISO15693_VICC_TO_VCD; + answerLen = GetIso15693AnswerFromTag(answer, sizeof(answer), DELAY_ISO15693_VCD_TO_VICC_READER * 2) ; + uint32_t start_time = GetCountSspClk() + DELAY_ISO15693_VICC_TO_VCD_READER; if (answerLen >=12) // we should do a better check than this { @@ -1446,22 +1442,17 @@ void ReaderIso15693(uint32_t parameter) // read all pages if (answerLen >= 12 && DEBUG) { - - // debugptr = BigBuf_get_addr(); - - int i = 0; - while (i < 32) { // sanity check, assume max 32 pages + for (int i = 0; i < 32; i++) { // sanity check, assume max 32 pages BuildReadBlockRequest(TagUID, i); TransmitTo15693Tag(ToSend, ToSendMax, start_time); - int answerLen = GetIso15693AnswerFromTag(answer, sizeof(answer), DELAY_ISO15693_VCD_TO_VICC * 2); - start_time = GetCountSspClk() + DELAY_ISO15693_VICC_TO_VCD; + int answerLen = GetIso15693AnswerFromTag(answer, sizeof(answer), DELAY_ISO15693_VCD_TO_VICC_READER * 2); + start_time = GetCountSspClk() + DELAY_ISO15693_VICC_TO_VCD_READER; if (answerLen > 0) { Dbprintf("READ SINGLE BLOCK %d returned %d octets:", i, answerLen); DbdecodeIso15693Answer(answerLen, answer); Dbhexdump(answerLen, answer, false); if ( *((uint32_t*) answer) == 0x07160101 ) break; // exit on NoPageErr } - i++; } } @@ -1501,7 +1492,7 @@ void SimTagIso15693(uint32_t parameter, uint8_t *uid) if ((cmd_len >= 5) && (cmd[0] & ISO15693_REQ_INVENTORY) && (cmd[1] == ISO15693_INVENTORY)) { // TODO: check more flags bool slow = !(cmd[0] & ISO15693_REQ_DATARATE_HIGH); - start_time = eof_time + DELAY_ISO15693_VCD_TO_VICC - DELAY_ARM_TO_READER; + start_time = eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM - DELAY_ARM_TO_READER_SIM; TransmitTo15693Reader(ToSend, ToSendMax, start_time, slow); } @@ -1509,6 +1500,7 @@ void SimTagIso15693(uint32_t parameter, uint8_t *uid) Dbhexdump(cmd_len, cmd, false); } + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); } @@ -1536,7 +1528,7 @@ void BruteforceIso15693Afi(uint32_t speed) data[2] = 0; // mask length datalen = AddCrc(data,3); recvlen = SendDataTag(data, datalen, false, speed, recv, sizeof(recv), 0); - uint32_t start_time = GetCountSspClk() + DELAY_ISO15693_VCD_TO_VICC; + uint32_t start_time = GetCountSspClk() + DELAY_ISO15693_VICC_TO_VCD_READER; WDT_HIT(); if (recvlen>=12) { Dbprintf("NoAFI UID=%s", sprintUID(NULL, &recv[2])); @@ -1553,7 +1545,7 @@ void BruteforceIso15693Afi(uint32_t speed) data[2] = i & 0xFF; datalen = AddCrc(data,4); recvlen = SendDataTag(data, datalen, false, speed, recv, sizeof(recv), start_time); - start_time = GetCountSspClk() + DELAY_ISO15693_VCD_TO_VICC; + start_time = GetCountSspClk() + DELAY_ISO15693_VICC_TO_VCD_READER; WDT_HIT(); if (recvlen >= 12) { Dbprintf("AFI=%i UID=%s", i, sprintUID(NULL, &recv[2])); @@ -1614,8 +1606,8 @@ static void __attribute__((unused)) BuildSysInfoRequest(uint8_t *uid) uint8_t cmd[12]; uint16_t crc; - // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block - // followed by teh block data + // If we set the Option_Flag in this request, the VICC will respond with the security status of the block + // followed by the block data // one sub-carrier, inventory, 1 slot, fast rate cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit // System Information command code @@ -1645,8 +1637,8 @@ static void __attribute__((unused)) BuildReadMultiBlockRequest(uint8_t *uid) uint8_t cmd[14]; uint16_t crc; - // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block - // followed by teh block data + // If we set the Option_Flag in this request, the VICC will respond with the security status of the block + // followed by the block data // one sub-carrier, inventory, 1 slot, fast rate cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit // READ Multi BLOCK command code @@ -1679,8 +1671,8 @@ static void __attribute__((unused)) BuildArbitraryRequest(uint8_t *uid,uint8_t C uint8_t cmd[14]; uint16_t crc; - // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block - // followed by teh block data + // If we set the Option_Flag in this request, the VICC will respond with the security status of the block + // followed by the block data // one sub-carrier, inventory, 1 slot, fast rate cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit // READ BLOCK command code @@ -1714,8 +1706,8 @@ static void __attribute__((unused)) BuildArbitraryCustomRequest(uint8_t uid[], u uint8_t cmd[14]; uint16_t crc; - // If we set the Option_Flag in this request, the VICC will respond with the secuirty status of the block - // followed by teh block data + // If we set the Option_Flag in this request, the VICC will respond with the security status of the block + // followed by the block data // one sub-carrier, inventory, 1 slot, fast rate cmd[0] = (1 << 5) | (1 << 1); // no SELECT bit // READ BLOCK command code @@ -1731,7 +1723,7 @@ static void __attribute__((unused)) BuildArbitraryCustomRequest(uint8_t uid[], u cmd[8] = 0x05; cmd[9]= 0xe0; // always e0 (not exactly unique) // Parameter - cmd[10] = 0x05; // for custom codes this must be manufcturer code + cmd[10] = 0x05; // for custom codes this must be manufacturer code cmd[11] = 0x00; // cmd[12] = 0x00; diff --git a/armsrc/legicrf.c b/armsrc/legicrf.c index 947d6cd5..c848e647 100644 --- a/armsrc/legicrf.c +++ b/armsrc/legicrf.c @@ -152,7 +152,7 @@ static inline void tx_bit(bool bit) { //----------------------------------------------------------------------------- static void tx_frame(uint32_t frame, uint8_t len) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_FULL_MOD); // wait for next tx timeslot last_frame_end += RWD_FRAME_WAIT; @@ -173,9 +173,7 @@ static void tx_frame(uint32_t frame, uint8_t len) { } static uint32_t rx_frame(uint8_t len) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR - | FPGA_HF_READER_RX_XCORR_848_KHZ - | FPGA_HF_READER_RX_XCORR_QUARTER_FREQ); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_212_KHZ | FPGA_HF_READER_MODE_RECEIVE_IQ); // hold sampling until card is expected to respond last_frame_end += TAG_FRAME_WAIT; @@ -196,9 +194,7 @@ static uint32_t rx_frame(uint8_t len) { static bool rx_ack() { // change fpga into rx mode - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR - | FPGA_HF_READER_RX_XCORR_848_KHZ - | FPGA_HF_READER_RX_XCORR_QUARTER_FREQ); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_212_KHZ | FPGA_HF_READER_MODE_RECEIVE_IQ); // hold sampling until card is expected to respond last_frame_end += TAG_FRAME_WAIT; @@ -258,14 +254,12 @@ static int init_card(uint8_t cardtype, legic_card_select_t *p_card) { static void init_reader(bool clear_mem) { // configure FPGA FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR - | FPGA_HF_READER_RX_XCORR_848_KHZ - | FPGA_HF_READER_RX_XCORR_QUARTER_FREQ); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_212_KHZ | FPGA_HF_READER_MODE_RECEIVE_IQ); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); LED_D_ON(); // configure SSC with defaults - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); // re-claim GPIO_SSC_DOUT as GPIO and enable output AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; diff --git a/fpga/Makefile b/fpga/Makefile index 70b0b5fe..01b848fb 100644 --- a/fpga/Makefile +++ b/fpga/Makefile @@ -1,11 +1,11 @@ -include ../common/Makefile.common +include ../common/Makefile.common # for $(DETECTED_OS) all: fpga_lf.bit fpga_hf.bit clean: $(DELETE) *.bgn *.drc *.ncd *.ngd *_par.xrpt *-placed.* *-placed_pad.* *_usage.xml xst_hf.srp xst_lf.srp $(DELETE) *.map *.ngc *.xrpt *.pcf *.rbt *_auto_* *.bld *.mrp *.ngm *.unroutes *_summary.xml netlist.lst xst -fpga_hf.ngc: fpga_hf.v fpga.ucf xst_hf.scr util.v hi_simulate.v hi_read_tx.v hi_read_rx_xcorr.v hi_iso14443a.v hi_sniffer.v hi_get_trace.v +fpga_hf.ngc: fpga_hf.v fpga.ucf xst_hf.scr util.v hi_simulate.v hi_reader.v hi_iso14443a.v hi_sniffer.v hi_get_trace.v $(DELETE) $@ $(XILINX_TOOLS_PREFIX)xst -ifn xst_hf.scr diff --git a/fpga/fpga.ucf b/fpga/fpga.ucf index f20e2da0..545ce5d0 100644 --- a/fpga/fpga.ucf +++ b/fpga/fpga.ucf @@ -1,38 +1,38 @@ # See the schematic for the pin assignment. -NET "adc_d<0>" LOC = "P62" ; -NET "adc_d<1>" LOC = "P60" ; -NET "adc_d<2>" LOC = "P58" ; -NET "adc_d<3>" LOC = "P57" ; -NET "adc_d<4>" LOC = "P56" ; -NET "adc_d<5>" LOC = "P55" ; -NET "adc_d<6>" LOC = "P54" ; -NET "adc_d<7>" LOC = "P53" ; -#NET "cross_hi" LOC = "P88" ; -#NET "miso" LOC = "P40" ; +NET "adc_d<0>" LOC = "P62" ; +NET "adc_d<1>" LOC = "P60" ; +NET "adc_d<2>" LOC = "P58" ; +NET "adc_d<3>" LOC = "P57" ; +NET "adc_d<4>" LOC = "P56" ; +NET "adc_d<5>" LOC = "P55" ; +NET "adc_d<6>" LOC = "P54" ; +NET "adc_d<7>" LOC = "P53" ; +NET "cross_hi" LOC = "P88" ; +#NET "miso" LOC = "P40" ; #PACE: Start of Constraints generated by PACE #PACE: Start of PACE I/O Pin Assignments -NET "adc_clk" LOC = "P46" ; -NET "adc_noe" LOC = "P47" ; -NET "ck_1356meg" LOC = "P91" ; -NET "ck_1356megb" LOC = "P93" ; -NET "cross_lo" LOC = "P87" ; -NET "dbg" LOC = "P22" ; -NET "mosi" LOC = "P43" ; -NET "ncs" LOC = "P44" ; -NET "pck0" LOC = "P36" ; -NET "pwr_hi" LOC = "P80" ; -NET "pwr_lo" LOC = "P81" ; -NET "pwr_oe1" LOC = "P82" ; -NET "pwr_oe2" LOC = "P83" ; -NET "pwr_oe3" LOC = "P84" ; -NET "pwr_oe4" LOC = "P86" ; -NET "spck" LOC = "P39" ; -NET "ssp_clk" LOC = "P71" ; -NET "ssp_din" LOC = "P32" ; -NET "ssp_dout" LOC = "P34" ; -NET "ssp_frame" LOC = "P31" ; +NET "adc_clk" LOC = "P46" ; +NET "adc_noe" LOC = "P47" ; +NET "ck_1356meg" LOC = "P91" ; +NET "ck_1356megb" LOC = "P93" ; +NET "cross_lo" LOC = "P87" ; +NET "dbg" LOC = "P22" ; +NET "mosi" LOC = "P43" ; +NET "ncs" LOC = "P44" ; +NET "pck0" LOC = "P36" ; +NET "pwr_hi" LOC = "P80" ; +NET "pwr_lo" LOC = "P81" ; +NET "pwr_oe1" LOC = "P82" ; +NET "pwr_oe2" LOC = "P83" ; +NET "pwr_oe3" LOC = "P84" ; +NET "pwr_oe4" LOC = "P86" ; +NET "spck" LOC = "P39" ; +NET "ssp_clk" LOC = "P71" ; +NET "ssp_din" LOC = "P32" ; +NET "ssp_dout" LOC = "P34" ; +NET "ssp_frame" LOC = "P31" ; #PACE: Start of PACE Area Constraints diff --git a/fpga/fpga_hf.bit b/fpga/fpga_hf.bit index 2ea2c24e76d0e4b64f173d48cf67dc299283e53d..665f7bcbe9df8553e37ddf040bf7406f7b59798e 100644 GIT binary patch literal 42175 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 literal 42175 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 H^0)s7_0XSf diff --git a/fpga/fpga_hf.v b/fpga/fpga_hf.v index ef935260..01c6ebb2 100644 --- a/fpga/fpga_hf.v +++ b/fpga/fpga_hf.v @@ -13,8 +13,47 @@ // iZsh , June 2014 //----------------------------------------------------------------------------- -`include "hi_read_tx.v" -`include "hi_read_rx_xcorr.v" +// Defining modes and options. This must be aligned to the definitions in fpgaloader.h +// Note: the definitions here are without shifts +// Major modes: +`define FPGA_MAJOR_MODE_LF_ADC 0 +`define FPGA_MAJOR_MODE_LF_EDGE_DETECT 1 +`define FPGA_MAJOR_MODE_LF_PASSTHRU 2 +`define FPGA_MAJOR_MODE_HF_READER 0 +`define FPGA_MAJOR_MODE_HF_SIMULATOR 1 +`define FPGA_MAJOR_MODE_HF_ISO14443A 2 +`define FPGA_MAJOR_MODE_HF_SNOOP 3 +`define FPGA_MAJOR_MODE_HF_GET_TRACE 4 +`define FPGA_MAJOR_MODE_OFF 7 + +// Options for the generic HF reader +`define FPGA_HF_READER_MODE_RECEIVE_IQ 0 +`define FPGA_HF_READER_MODE_RECEIVE_AMPLITUDE 1 +`define FPGA_HF_READER_MODE_RECEIVE_PHASE 2 +`define FPGA_HF_READER_MODE_SEND_FULL_MOD 3 +`define FPGA_HF_READER_MODE_SEND_SHALLOW_MOD 4 +`define FPGA_HF_READER_MODE_SNIFF_IQ 5 +`define FPGA_HF_READER_MODE_SNIFF_AMPLITUDE 6 +`define FPGA_HF_READER_MODE_SNIFF_PHASE 7 +`define FPGA_HF_READER_SUBCARRIER_848_KHZ 0 +`define FPGA_HF_READER_SUBCARRIER_424_KHZ 1 +`define FPGA_HF_READER_SUBCARRIER_212_KHZ 2 + +// Options for the HF simulated tag, how to modulate +`define FPGA_HF_SIMULATOR_NO_MODULATION 0 +`define FPGA_HF_SIMULATOR_MODULATE_BPSK 1 +`define FPGA_HF_SIMULATOR_MODULATE_212K 2 +`define FPGA_HF_SIMULATOR_MODULATE_424K 4 +`define FPGA_HF_SIMULATOR_MODULATE_424K_8BIT 5 + +// Options for ISO14443A +`define FPGA_HF_ISO14443A_SNIFFER 0 +`define FPGA_HF_ISO14443A_TAGSIM_LISTEN 1 +`define FPGA_HF_ISO14443A_TAGSIM_MOD 2 +`define FPGA_HF_ISO14443A_READER_LISTEN 3 +`define FPGA_HF_ISO14443A_READER_MOD 4 + +`include "hi_reader.v" `include "hi_simulate.v" `include "hi_iso14443a.v" `include "hi_sniffer.v" @@ -49,8 +88,8 @@ reg trace_enable; always @(posedge ncs) begin case(shift_reg[15:12]) - 4'b0001: conf_word <= shift_reg[7:0]; // FPGA_CMD_SET_CONFREG - 4'b0010: trace_enable <= shift_reg[0]; // FPGA_CMD_TRACE_ENABLE + 4'b0001: conf_word <= shift_reg[7:0]; // FPGA_CMD_SET_CONFREG + 4'b0010: trace_enable <= shift_reg[0]; // FPGA_CMD_TRACE_ENABLE endcase end @@ -63,26 +102,12 @@ begin end end -wire [2:0] major_mode; -assign major_mode = conf_word[7:5]; +// select module (outputs) based on major mode +wire [2:0] major_mode = conf_word[7:5]; -// For the high-frequency transmit configuration: modulation depth, either -// 100% (just quite driving antenna, steady LOW), or shallower (tri-state -// some fraction of the buffers) -wire hi_read_tx_shallow_modulation = conf_word[0]; - -// For the high-frequency receive correlator: frequency against which to -// correlate. -wire hi_read_rx_xcorr_848 = conf_word[0]; -// and whether to drive the coil (reader) or just short it (snooper) -wire hi_read_rx_xcorr_snoop = conf_word[1]; -// divide subcarrier frequency by 4 -wire hi_read_rx_xcorr_quarter = conf_word[2]; -// send amplitude only instead of ci/cq pair -wire hi_read_rx_xcorr_amplitude = conf_word[3]; - -// For the high-frequency simulated tag: what kind of modulation to use. -wire [2:0] hi_simulate_mod_type = conf_word[2:0]; +// configuring the HF reader +wire [1:0] subcarrier_frequency = conf_word[4:3]; +wire [2:0] minor_mode = conf_word[2:0]; //----------------------------------------------------------------------------- // And then we instantiate the modules corresponding to each of the FPGA's @@ -90,85 +115,71 @@ wire [2:0] hi_simulate_mod_type = conf_word[2:0]; // the output pins. //----------------------------------------------------------------------------- -hi_read_tx ht( - pck0, ck_1356meg, ck_1356megb, - ht_pwr_lo, ht_pwr_hi, ht_pwr_oe1, ht_pwr_oe2, ht_pwr_oe3, ht_pwr_oe4, - adc_d, ht_adc_clk, - ht_ssp_frame, ht_ssp_din, ssp_dout, ht_ssp_clk, - cross_hi, cross_lo, - ht_dbg, - hi_read_tx_shallow_modulation -); - -hi_read_rx_xcorr hrxc( - pck0, ck_1356meg, ck_1356megb, - hrxc_pwr_lo, hrxc_pwr_hi, hrxc_pwr_oe1, hrxc_pwr_oe2, hrxc_pwr_oe3, hrxc_pwr_oe4, - adc_d, hrxc_adc_clk, - hrxc_ssp_frame, hrxc_ssp_din, ssp_dout, hrxc_ssp_clk, - cross_hi, cross_lo, - hrxc_dbg, - hi_read_rx_xcorr_848, hi_read_rx_xcorr_snoop, hi_read_rx_xcorr_quarter, hi_read_rx_xcorr_amplitude +hi_reader hr( + ck_1356megb, + hr_pwr_lo, hr_pwr_hi, hr_pwr_oe1, hr_pwr_oe2, hr_pwr_oe3, hr_pwr_oe4, + adc_d, hr_adc_clk, + hr_ssp_frame, hr_ssp_din, ssp_dout, hr_ssp_clk, + hr_dbg, + subcarrier_frequency, minor_mode ); hi_simulate hs( - pck0, ck_1356meg, ck_1356megb, + ck_1356meg, hs_pwr_lo, hs_pwr_hi, hs_pwr_oe1, hs_pwr_oe2, hs_pwr_oe3, hs_pwr_oe4, adc_d, hs_adc_clk, hs_ssp_frame, hs_ssp_din, ssp_dout, hs_ssp_clk, - cross_hi, cross_lo, hs_dbg, - hi_simulate_mod_type + minor_mode ); hi_iso14443a hisn( - pck0, ck_1356meg, ck_1356megb, - hisn_pwr_lo, hisn_pwr_hi, hisn_pwr_oe1, hisn_pwr_oe2, hisn_pwr_oe3, hisn_pwr_oe4, + ck_1356meg, + hisn_pwr_lo, hisn_pwr_hi, hisn_pwr_oe1, hisn_pwr_oe2, hisn_pwr_oe3, hisn_pwr_oe4, adc_d, hisn_adc_clk, hisn_ssp_frame, hisn_ssp_din, ssp_dout, hisn_ssp_clk, - cross_hi, cross_lo, hisn_dbg, - hi_simulate_mod_type + minor_mode ); hi_sniffer he( - pck0, ck_1356meg, ck_1356megb, - he_pwr_lo, he_pwr_hi, he_pwr_oe1, he_pwr_oe2, he_pwr_oe3, he_pwr_oe4, - adc_d, he_adc_clk, - he_ssp_frame, he_ssp_din, ssp_dout, he_ssp_clk, - cross_hi, cross_lo, - he_dbg, - hi_read_rx_xcorr_848, hi_read_rx_xcorr_snoop, hi_read_rx_xcorr_quarter + ck_1356megb, + he_pwr_lo, he_pwr_hi, he_pwr_oe1, he_pwr_oe2, he_pwr_oe3, he_pwr_oe4, + adc_d, he_adc_clk, + he_ssp_frame, he_ssp_din, he_ssp_clk ); hi_get_trace gt( - ck_1356megb, - adc_d, trace_enable, major_mode, - gt_ssp_frame, gt_ssp_din, gt_ssp_clk + ck_1356megb, + adc_d, trace_enable, major_mode, + gt_ssp_frame, gt_ssp_din, gt_ssp_clk ); // Major modes: -// 000 -- HF reader, transmitting to tag; modulation depth selectable -// 001 -- HF reader, receiving from tag, correlating as it goes; frequency selectable -// 010 -- HF simulated tag -// 011 -- HF ISO14443-A -// 100 -- HF Snoop -// 101 -- HF get trace +// 000 -- HF reader; subcarrier frequency and modulation depth selectable +// 001 -- HF simulated tag +// 010 -- HF ISO14443-A +// 011 -- HF Snoop +// 100 -- HF get trace // 111 -- everything off -mux8 mux_ssp_clk (major_mode, ssp_clk, ht_ssp_clk, hrxc_ssp_clk, hs_ssp_clk, hisn_ssp_clk, he_ssp_clk, gt_ssp_clk, 1'b0, 1'b0); -mux8 mux_ssp_din (major_mode, ssp_din, ht_ssp_din, hrxc_ssp_din, hs_ssp_din, hisn_ssp_din, he_ssp_din, gt_ssp_din, 1'b0, 1'b0); -mux8 mux_ssp_frame (major_mode, ssp_frame, ht_ssp_frame, hrxc_ssp_frame, hs_ssp_frame, hisn_ssp_frame, he_ssp_frame, gt_ssp_frame, 1'b0, 1'b0); -mux8 mux_pwr_oe1 (major_mode, pwr_oe1, ht_pwr_oe1, hrxc_pwr_oe1, hs_pwr_oe1, hisn_pwr_oe1, he_pwr_oe1, 1'b0, 1'b0, 1'b0); -mux8 mux_pwr_oe2 (major_mode, pwr_oe2, ht_pwr_oe2, hrxc_pwr_oe2, hs_pwr_oe2, hisn_pwr_oe2, he_pwr_oe2, 1'b0, 1'b0, 1'b0); -mux8 mux_pwr_oe3 (major_mode, pwr_oe3, ht_pwr_oe3, hrxc_pwr_oe3, hs_pwr_oe3, hisn_pwr_oe3, he_pwr_oe3, 1'b0, 1'b0, 1'b0); -mux8 mux_pwr_oe4 (major_mode, pwr_oe4, ht_pwr_oe4, hrxc_pwr_oe4, hs_pwr_oe4, hisn_pwr_oe4, he_pwr_oe4, 1'b0, 1'b0, 1'b0); -mux8 mux_pwr_lo (major_mode, pwr_lo, ht_pwr_lo, hrxc_pwr_lo, hs_pwr_lo, hisn_pwr_lo, he_pwr_lo, 1'b0, 1'b0, 1'b0); -mux8 mux_pwr_hi (major_mode, pwr_hi, ht_pwr_hi, hrxc_pwr_hi, hs_pwr_hi, hisn_pwr_hi, he_pwr_hi, 1'b0, 1'b0, 1'b0); -mux8 mux_adc_clk (major_mode, adc_clk, ht_adc_clk, hrxc_adc_clk, hs_adc_clk, hisn_adc_clk, he_adc_clk, 1'b0, 1'b0, 1'b0); -mux8 mux_dbg (major_mode, dbg, ht_dbg, hrxc_dbg, hs_dbg, hisn_dbg, he_dbg, 1'b0, 1'b0, 1'b0); +mux8 mux_ssp_clk (major_mode, ssp_clk, hr_ssp_clk, hs_ssp_clk, hisn_ssp_clk, he_ssp_clk, gt_ssp_clk, 1'b0, 1'b0, 1'b0); +mux8 mux_ssp_din (major_mode, ssp_din, hr_ssp_din, hs_ssp_din, hisn_ssp_din, he_ssp_din, gt_ssp_din, 1'b0, 1'b0, 1'b0); +mux8 mux_ssp_frame (major_mode, ssp_frame, hr_ssp_frame, hs_ssp_frame, hisn_ssp_frame, he_ssp_frame, gt_ssp_frame, 1'b0, 1'b0, 1'b0); +mux8 mux_pwr_oe1 (major_mode, pwr_oe1, hr_pwr_oe1, hs_pwr_oe1, hisn_pwr_oe1, he_pwr_oe1, 1'b0, 1'b0, 1'b0, 1'b0); +mux8 mux_pwr_oe2 (major_mode, pwr_oe2, hr_pwr_oe2, hs_pwr_oe2, hisn_pwr_oe2, he_pwr_oe2, 1'b0, 1'b0, 1'b0, 1'b0); +mux8 mux_pwr_oe3 (major_mode, pwr_oe3, hr_pwr_oe3, hs_pwr_oe3, hisn_pwr_oe3, he_pwr_oe3, 1'b0, 1'b0, 1'b0, 1'b0); +mux8 mux_pwr_oe4 (major_mode, pwr_oe4, hr_pwr_oe4, hs_pwr_oe4, hisn_pwr_oe4, he_pwr_oe4, 1'b0, 1'b0, 1'b0, 1'b0); +mux8 mux_pwr_lo (major_mode, pwr_lo, hr_pwr_lo, hs_pwr_lo, hisn_pwr_lo, he_pwr_lo, 1'b0, 1'b0, 1'b0, 1'b0); +mux8 mux_pwr_hi (major_mode, pwr_hi, hr_pwr_hi, hs_pwr_hi, hisn_pwr_hi, he_pwr_hi, 1'b0, 1'b0, 1'b0, 1'b0); +mux8 mux_adc_clk (major_mode, adc_clk, hr_adc_clk, hs_adc_clk, hisn_adc_clk, he_adc_clk, 1'b0, 1'b0, 1'b0, 1'b0); +mux8 mux_dbg (major_mode, dbg, hr_dbg, hs_dbg, hisn_dbg, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0); // In all modes, let the ADC's outputs be enabled. assign adc_noe = 1'b0; +// not used +assign miso = 1'b0; + endmodule diff --git a/fpga/hi_get_trace.v b/fpga/hi_get_trace.v index 7acecf80..3e7412f7 100644 --- a/fpga/hi_get_trace.v +++ b/fpga/hi_get_trace.v @@ -14,11 +14,6 @@ module hi_get_trace( input [2:0] major_mode; output ssp_frame, ssp_din, ssp_clk; -// constants for some major_modes: -`define OFF 3'b111 -`define GET_TRACE 3'b101 - - // clock divider reg [6:0] clock_cnt; always @(negedge ck_1356megb) @@ -30,7 +25,7 @@ end reg [2:0] sample_clock; always @(negedge ck_1356megb) begin - if (sample_clock == 3'd3) + if (sample_clock == 3'd7) sample_clock <= 3'd0; else sample_clock <= sample_clock + 1; @@ -45,11 +40,11 @@ reg write_enable2; always @(negedge ck_1356megb) begin previous_major_mode <= major_mode; - if (major_mode == `GET_TRACE) + if (major_mode == `FPGA_MAJOR_MODE_HF_GET_TRACE) begin write_enable1 <= 1'b0; write_enable2 <= 1'b0; - if (previous_major_mode != `GET_TRACE) // just switched into GET_TRACE mode + if (previous_major_mode != `FPGA_MAJOR_MODE_HF_GET_TRACE) // just switched into GET_TRACE mode addr <= start_addr; if (clock_cnt == 7'd0) begin @@ -59,7 +54,7 @@ begin addr <= addr + 1; end end - else if (major_mode != `OFF) + else if (major_mode != `FPGA_MAJOR_MODE_OFF) begin if (trace_enable) begin @@ -92,11 +87,11 @@ begin start_addr <= addr; end end - else // major_mode == `OFF + else // major_mode == `FPGA_MAJOR_MODE_OFF begin write_enable1 <= 1'b0; write_enable2 <= 1'b0; - if (previous_major_mode != `OFF && previous_major_mode != `GET_TRACE) // just switched off + if (previous_major_mode != `FPGA_MAJOR_MODE_OFF && previous_major_mode != `FPGA_MAJOR_MODE_HF_GET_TRACE) // just switched off start_addr <= addr; end end diff --git a/fpga/hi_iso14443a.v b/fpga/hi_iso14443a.v index b1b7b141..e460a2cc 100644 --- a/fpga/hi_iso14443a.v +++ b/fpga/hi_iso14443a.v @@ -3,29 +3,20 @@ // Gerhard de Koning Gans, April 2008 //----------------------------------------------------------------------------- -// constants for the different modes: -`define SNIFFER 3'b000 -`define TAGSIM_LISTEN 3'b001 -`define TAGSIM_MOD 3'b010 -`define READER_LISTEN 3'b011 -`define READER_MOD 3'b100 - module hi_iso14443a( - pck0, ck_1356meg, ck_1356megb, + ck_1356meg, pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4, adc_d, adc_clk, ssp_frame, ssp_din, ssp_dout, ssp_clk, - cross_hi, cross_lo, dbg, mod_type ); - input pck0, ck_1356meg, ck_1356megb; + input ck_1356meg; output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4; input [7:0] adc_d; output adc_clk; input ssp_dout; output ssp_frame, ssp_din, ssp_clk; - input cross_hi, cross_lo; output dbg; input [2:0] mod_type; @@ -151,7 +142,7 @@ begin end // adjust internal timer counter if necessary: - if (negedge_cnt[3:0] == 4'd13 && (mod_type == `SNIFFER || mod_type == `TAGSIM_LISTEN) && deep_modulation) + if (negedge_cnt[3:0] == 4'd13 && (mod_type == `FPGA_HF_ISO14443A_SNIFFER || mod_type == `FPGA_HF_ISO14443A_TAGSIM_LISTEN) && deep_modulation) begin if (reader_falling_edge_time == 4'd1) // reader signal changes right after sampling. Better sample earlier next time. begin @@ -185,7 +176,7 @@ reg [3:0] mod_detect_reset_time; always @(negedge adc_clk) begin - if (mod_type == `READER_LISTEN) + if (mod_type == `FPGA_HF_ISO14443A_READER_LISTEN) // (our) reader signal changes at negedge_cnt[3:0]=9, tag response expected to start n*16+4 ticks later, further delayed by // 3 ticks ADC conversion. The maximum filter output (edge detected) will be detected after subcarrier zero crossing (+7 ticks). // To allow some timing variances, we want to have the maximum filter outputs well within the detection window, i.e. @@ -195,7 +186,7 @@ begin mod_detect_reset_time <= 4'd4; end else - if (mod_type == `SNIFFER) + if (mod_type == `FPGA_HF_ISO14443A_SNIFFER) begin // detect a rising edge of reader's signal and sync modulation detector to the tag's answer: if (~pre_after_hysteresis && after_hysteresis && deep_modulation) @@ -320,7 +311,7 @@ reg [3:0] sub_carrier_cnt; // response window of 1128 - 774 = 354 ticks. // reset on a pause in listen mode. I.e. the counter starts when the pause is over: -assign fdt_reset = ~after_hysteresis && mod_type == `TAGSIM_LISTEN; +assign fdt_reset = ~after_hysteresis && mod_type == `FPGA_HF_ISO14443A_TAGSIM_LISTEN; always @(negedge adc_clk) begin @@ -363,7 +354,7 @@ reg mod_sig_coil; always @(negedge adc_clk) begin - if (mod_type == `TAGSIM_MOD) // need to take care of proper fdt timing + if (mod_type == `FPGA_HF_ISO14443A_TAGSIM_MOD) // need to take care of proper fdt timing begin if(fdt_counter == `FDT_COUNT) begin @@ -438,7 +429,7 @@ always @(negedge adc_clk) begin if (negedge_cnt[5:0] == 6'd63) // fill the buffer begin - if (mod_type == `SNIFFER) + if (mod_type == `FPGA_HF_ISO14443A_SNIFFER) begin if(deep_modulation) // a reader is sending (or there's no field at all) begin @@ -455,7 +446,7 @@ begin end end - if(negedge_cnt[2:0] == 3'b000 && mod_type == `SNIFFER) // shift at double speed + if(negedge_cnt[2:0] == 3'b000 && mod_type == `FPGA_HF_ISO14443A_SNIFFER) // shift at double speed begin // Don't shift if we just loaded new data, obviously. if(negedge_cnt[5:0] != 6'd0) @@ -464,7 +455,7 @@ begin end end - if(negedge_cnt[3:0] == 4'b0000 && mod_type != `SNIFFER) + if(negedge_cnt[3:0] == 4'b0000 && mod_type != `FPGA_HF_ISO14443A_SNIFFER) begin // Don't shift if we just loaded new data, obviously. if(negedge_cnt[6:0] != 7'd0) @@ -484,8 +475,8 @@ reg ssp_frame; always @(negedge adc_clk) begin - if(mod_type == `SNIFFER) - // SNIFFER mode (ssp_clk = adc_clk / 8, ssp_frame clock = adc_clk / 64)): + if(mod_type == `FPGA_HF_ISO14443A_SNIFFER) + // FPGA_HF_ISO14443A_SNIFFER mode (ssp_clk = adc_clk / 8, ssp_frame clock = adc_clk / 64)): begin if(negedge_cnt[2:0] == 3'd0) ssp_clk <= 1'b1; @@ -505,7 +496,7 @@ begin if(negedge_cnt[3:0] == 4'd8) ssp_clk <= 1'b0; - if(negedge_cnt[6:0] == 7'd7) // ssp_frame rising edge indicates start of frame + if(negedge_cnt[6:0] == 7'd7) // ssp_frame rising edge indicates start of frame, sampled on falling edge of ssp_clk ssp_frame <= 1'b1; if(negedge_cnt[6:0] == 7'd23) ssp_frame <= 1'b0; @@ -525,23 +516,23 @@ begin if(negedge_cnt[3:0] == 4'd0) begin // What do we communicate to the ARM - if(mod_type == `TAGSIM_LISTEN) + if(mod_type == `FPGA_HF_ISO14443A_TAGSIM_LISTEN) sendbit = after_hysteresis; - else if(mod_type == `TAGSIM_MOD) + else if(mod_type == `FPGA_HF_ISO14443A_TAGSIM_MOD) /* if(fdt_counter > 11'd772) sendbit = mod_sig_coil; // huh? else */ sendbit = fdt_indicator; - else if (mod_type == `READER_LISTEN) + else if (mod_type == `FPGA_HF_ISO14443A_READER_LISTEN) sendbit = curbit; else sendbit = 1'b0; end - if(mod_type == `SNIFFER) + if(mod_type == `FPGA_HF_ISO14443A_SNIFFER) // send sampled reader and tag data: bit_to_arm = to_arm[7]; - else if (mod_type == `TAGSIM_MOD && fdt_elapsed && temp_buffer_reset) + else if (mod_type == `FPGA_HF_ISO14443A_TAGSIM_MOD && fdt_elapsed && temp_buffer_reset) // send timing information: bit_to_arm = to_arm[7]; else @@ -554,22 +545,22 @@ end assign ssp_din = bit_to_arm; -// Subcarrier (adc_clk/16, for TAGSIM_MOD only). +// Subcarrier (adc_clk/16, for FPGA_HF_ISO14443A_TAGSIM_MOD only). wire sub_carrier; assign sub_carrier = ~sub_carrier_cnt[3]; -// in READER_MOD: drop carrier for mod_sig_coil==1 (pause); in READER_LISTEN: carrier always on; in other modes: carrier always off -assign pwr_hi = (ck_1356megb & (((mod_type == `READER_MOD) & ~mod_sig_coil) || (mod_type == `READER_LISTEN))); +// in FPGA_HF_ISO14443A_READER_MOD: drop carrier for mod_sig_coil==1 (pause); in FPGA_HF_ISO14443A_READER_LISTEN: carrier always on; in other modes: carrier always off +assign pwr_hi = (ck_1356meg & (((mod_type == `FPGA_HF_ISO14443A_READER_MOD) & ~mod_sig_coil) || (mod_type == `FPGA_HF_ISO14443A_READER_LISTEN))); // Enable HF antenna drivers: assign pwr_oe1 = 1'b0; assign pwr_oe3 = 1'b0; -// TAGSIM_MOD: short circuit antenna with different resistances (modulated by sub_carrier modulated by mod_sig_coil) +// FPGA_HF_ISO14443A_TAGSIM_MOD: short circuit antenna with different resistances (modulated by sub_carrier modulated by mod_sig_coil) // for pwr_oe4 = 1 (tristate): antenna load = 10k || 33 = 32,9 Ohms // for pwr_oe4 = 0 (active): antenna load = 10k || 33 || 33 = 16,5 Ohms -assign pwr_oe4 = mod_sig_coil & sub_carrier & (mod_type == `TAGSIM_MOD); +assign pwr_oe4 = mod_sig_coil & sub_carrier & (mod_type == `FPGA_HF_ISO14443A_TAGSIM_MOD); // This is all LF, so doesn't matter. assign pwr_oe2 = 1'b0; diff --git a/fpga/hi_read_tx.v b/fpga/hi_read_tx.v deleted file mode 100644 index 819f1697..00000000 --- a/fpga/hi_read_tx.v +++ /dev/null @@ -1,78 +0,0 @@ -//----------------------------------------------------------------------------- -// The way that we connect things when transmitting a command to an ISO -// 15693 tag, using 100% modulation only for now. -// -// Jonathan Westhues, April 2006 -//----------------------------------------------------------------------------- - -module hi_read_tx( - pck0, ck_1356meg, ck_1356megb, - pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4, - adc_d, adc_clk, - ssp_frame, ssp_din, ssp_dout, ssp_clk, - cross_hi, cross_lo, - dbg, - shallow_modulation -); - input pck0, ck_1356meg, ck_1356megb; - output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4; - input [7:0] adc_d; - output adc_clk; - input ssp_dout; - output ssp_frame, ssp_din, ssp_clk; - input cross_hi, cross_lo; - output dbg; - input shallow_modulation; - -// low frequency outputs, not relevant -assign pwr_lo = 1'b0; -assign pwr_oe2 = 1'b0; - -// The high-frequency stuff. For now, for testing, just bring out the carrier, -// and allow the ARM to modulate it over the SSP. -reg pwr_hi; -reg pwr_oe1; -reg pwr_oe3; -reg pwr_oe4; - -always @(ck_1356megb or ssp_dout or shallow_modulation) -begin - if(shallow_modulation) - begin - pwr_hi <= ck_1356megb; - pwr_oe1 <= 1'b0; - pwr_oe3 <= 1'b0; - pwr_oe4 <= ssp_dout; - end - else - begin - pwr_hi <= ck_1356megb & ~ssp_dout; - pwr_oe1 <= 1'b0; - pwr_oe3 <= 1'b0; - pwr_oe4 <= 1'b0; - end -end - - -// Then just divide the 13.56 MHz clock down to produce appropriate clocks -// for the synchronous serial port. - -reg [6:0] hi_div_by_128; - -always @(posedge ck_1356meg) - hi_div_by_128 <= hi_div_by_128 + 1; - -assign ssp_clk = hi_div_by_128[6]; - -reg [2:0] hi_byte_div; - -always @(negedge ssp_clk) - hi_byte_div <= hi_byte_div + 1; - -assign ssp_frame = (hi_byte_div == 3'b000); - -assign ssp_din = 1'b0; - -assign dbg = ssp_frame; - -endmodule \ No newline at end of file diff --git a/fpga/hi_read_rx_xcorr.v b/fpga/hi_reader.v similarity index 58% rename from fpga/hi_read_rx_xcorr.v rename to fpga/hi_reader.v index 503c8d67..b0b21e30 100644 --- a/fpga/hi_read_rx_xcorr.v +++ b/fpga/hi_reader.v @@ -3,35 +3,25 @@ // Jonathan Westhues, April 2006 //----------------------------------------------------------------------------- -module hi_read_rx_xcorr( - pck0, ck_1356meg, ck_1356megb, +module hi_reader( + ck_1356meg, pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4, adc_d, adc_clk, ssp_frame, ssp_din, ssp_dout, ssp_clk, - cross_hi, cross_lo, dbg, - xcorr_is_848, snoop, xcorr_quarter_freq, hi_read_rx_xcorr_amplitude + subcarrier_frequency, minor_mode ); - input pck0, ck_1356meg, ck_1356megb; + input ck_1356meg; output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4; input [7:0] adc_d; output adc_clk; input ssp_dout; output ssp_frame, ssp_din, ssp_clk; - input cross_hi, cross_lo; output dbg; - input xcorr_is_848, snoop, xcorr_quarter_freq, hi_read_rx_xcorr_amplitude; + input [1:0] subcarrier_frequency; + input [2:0] minor_mode; -// Carrier is steady on through this, unless we're snooping. -assign pwr_hi = ck_1356megb & (~snoop); -assign pwr_oe1 = 1'b0; -assign pwr_oe3 = 1'b0; -assign pwr_oe4 = 1'b0; -// Unused. -assign pwr_lo = 1'b0; -assign pwr_oe2 = 1'b0; - -assign adc_clk = ck_1356megb; // sample frequency is 13,56 MHz +assign adc_clk = ck_1356meg; // sample frequency is 13,56 MHz // When we're a reader, we just need to do the BPSK demod; but when we're an // eavesdropper, we also need to pick out the commands sent by the reader, @@ -71,7 +61,8 @@ begin corr_i_cnt <= corr_i_cnt + 1; end -// And a couple of registers in which to accumulate the correlations. From the 64 samples + +// A couple of registers in which to accumulate the correlations. From the 64 samples // we would add at most 32 times the difference between unmodulated and modulated signal. It should // be safe to assume that a tag will not be able to modulate the carrier signal by more than 25%. // 32 * 255 * 0,25 = 2040, which can be held in 11 bits. Add 1 bit for sign. @@ -84,18 +75,13 @@ reg signed [13:0] corr_q_accum; reg signed [7:0] corr_i_out; reg signed [7:0] corr_q_out; -// clock and frame signal for communication to ARM -reg ssp_clk; -reg ssp_frame; - - // the amplitude of the subcarrier is sqrt(ci^2 + cq^2). // approximate by amplitude = max(|ci|,|cq|) + 1/2*min(|ci|,|cq|) -reg [13:0] corr_amplitude, abs_ci, abs_cq, max_ci_cq, min_ci_cq; +reg [13:0] corr_amplitude, abs_ci, abs_cq, max_ci_cq; +reg [12:0] min_ci_cq_2; // min_ci_cq / 2 - -always @(corr_i_accum or corr_q_accum) +always @(*) begin if (corr_i_accum[13] == 1'b0) abs_ci <= corr_i_accum; @@ -110,15 +96,15 @@ begin if (abs_ci > abs_cq) begin max_ci_cq <= abs_ci; - min_ci_cq <= abs_cq; + min_ci_cq_2 <= abs_cq / 2; end else begin max_ci_cq <= abs_cq; - min_ci_cq <= abs_ci; + min_ci_cq_2 <= abs_ci / 2; end - corr_amplitude <= max_ci_cq + min_ci_cq/2; + corr_amplitude <= max_ci_cq + min_ci_cq_2; end @@ -127,14 +113,14 @@ end reg subcarrier_I; reg subcarrier_Q; -always @(corr_i_cnt or xcorr_is_848 or xcorr_quarter_freq) +always @(*) begin - if (xcorr_is_848 & ~xcorr_quarter_freq) // 848 kHz + if (subcarrier_frequency == `FPGA_HF_READER_SUBCARRIER_848_KHZ) begin subcarrier_I = ~corr_i_cnt[3]; subcarrier_Q = ~(corr_i_cnt[3] ^ corr_i_cnt[2]); end - else if (xcorr_is_848 & xcorr_quarter_freq) // 212 kHz + else if (subcarrier_frequency == `FPGA_HF_READER_SUBCARRIER_212_KHZ) begin subcarrier_I = ~corr_i_cnt[5]; subcarrier_Q = ~(corr_i_cnt[5] ^ corr_i_cnt[4]); @@ -155,62 +141,56 @@ begin // resulting amplitude to send out later over the SSP. if(corr_i_cnt == 6'd0) begin - if(snoop) + if (minor_mode == `FPGA_HF_READER_MODE_SNIFF_AMPLITUDE) begin - if (hi_read_rx_xcorr_amplitude) - begin - // send amplitude plus 2 bits reader signal - corr_i_out <= corr_amplitude[13:6]; - corr_q_out <= {corr_amplitude[5:0], after_hysteresis_prev_prev, after_hysteresis_prev}; - end - else - begin - // Send 7 most significant bits of in phase tag signal (signed), plus 1 bit reader signal - if (corr_i_accum[13:11] == 3'b000 || corr_i_accum[13:11] == 3'b111) - corr_i_out <= {corr_i_accum[11:5], after_hysteresis_prev_prev}; - else // truncate to maximum value - if (corr_i_accum[13] == 1'b0) - corr_i_out <= {7'b0111111, after_hysteresis_prev_prev}; - else - corr_i_out <= {7'b1000000, after_hysteresis_prev_prev}; - // Send 7 most significant bits of quadrature phase tag signal (signed), plus 1 bit reader signal - if (corr_q_accum[13:11] == 3'b000 || corr_q_accum[13:11] == 3'b111) - corr_q_out <= {corr_q_accum[11:5], after_hysteresis_prev}; - else // truncate to maximum value - if (corr_q_accum[13] == 1'b0) - corr_q_out <= {7'b0111111, after_hysteresis_prev}; - else - corr_q_out <= {7'b1000000, after_hysteresis_prev}; - end - end - else + // send amplitude plus 2 bits reader signal + corr_i_out <= corr_amplitude[13:6]; + corr_q_out <= {corr_amplitude[5:0], after_hysteresis_prev_prev, after_hysteresis_prev}; + end + else if (minor_mode == `FPGA_HF_READER_MODE_SNIFF_IQ) + begin + // Send 7 most significant bits of in phase tag signal (signed), plus 1 bit reader signal + if (corr_i_accum[13:11] == 3'b000 || corr_i_accum[13:11] == 3'b111) + corr_i_out <= {corr_i_accum[11:5], after_hysteresis_prev_prev}; + else // truncate to maximum value + if (corr_i_accum[13] == 1'b0) + corr_i_out <= {7'b0111111, after_hysteresis_prev_prev}; + else + corr_i_out <= {7'b1000000, after_hysteresis_prev_prev}; + // Send 7 most significant bits of quadrature phase tag signal (signed), plus 1 bit reader signal + if (corr_q_accum[13:11] == 3'b000 || corr_q_accum[13:11] == 3'b111) + corr_q_out <= {corr_q_accum[11:5], after_hysteresis_prev}; + else // truncate to maximum value + if (corr_q_accum[13] == 1'b0) + corr_q_out <= {7'b0111111, after_hysteresis_prev}; + else + corr_q_out <= {7'b1000000, after_hysteresis_prev}; + end + else if (minor_mode == `FPGA_HF_READER_MODE_RECEIVE_AMPLITUDE) begin - if (hi_read_rx_xcorr_amplitude) - begin - // send amplitude - corr_i_out <= {2'b00, corr_amplitude[13:8]}; - corr_q_out <= corr_amplitude[7:0]; - end - else - begin - // Send 8 bits of in phase tag signal - if (corr_i_accum[13:11] == 3'b000 || corr_i_accum[13:11] == 3'b111) - corr_i_out <= corr_i_accum[11:4]; - else // truncate to maximum value - if (corr_i_accum[13] == 1'b0) - corr_i_out <= 8'b01111111; - else - corr_i_out <= 8'b10000000; - // Send 8 bits of quadrature phase tag signal - if (corr_q_accum[13:11] == 3'b000 || corr_q_accum[13:11] == 3'b111) - corr_q_out <= corr_q_accum[11:4]; - else // truncate to maximum value - if (corr_q_accum[13] == 1'b0) - corr_q_out <= 8'b01111111; - else - corr_q_out <= 8'b10000000; - end - end + // send amplitude + corr_i_out <= {2'b00, corr_amplitude[13:8]}; + corr_q_out <= corr_amplitude[7:0]; + end + else if (minor_mode == `FPGA_HF_READER_MODE_RECEIVE_IQ) + begin + // Send 8 bits of in phase tag signal + if (corr_i_accum[13:11] == 3'b000 || corr_i_accum[13:11] == 3'b111) + corr_i_out <= corr_i_accum[11:4]; + else // truncate to maximum value + if (corr_i_accum[13] == 1'b0) + corr_i_out <= 8'b01111111; + else + corr_i_out <= 8'b10000000; + // Send 8 bits of quadrature phase tag signal + if (corr_q_accum[13:11] == 3'b000 || corr_q_accum[13:11] == 3'b111) + corr_q_out <= corr_q_accum[11:4]; + else // truncate to maximum value + if (corr_q_accum[13] == 1'b0) + corr_q_out <= 8'b01111111; + else + corr_q_out <= 8'b10000000; + end // for each Q/I pair report two reader signal samples when sniffing. Store the 1st. after_hysteresis_prev_prev <= after_hysteresis; @@ -241,12 +221,8 @@ begin // ssp_clk should be the adc_clk divided by 64/16 = 4. // ssp_clk frequency = 13,56MHz / 4 = 3.39MHz - if(corr_i_cnt[1:0] == 2'b10) - ssp_clk <= 1'b0; - if(corr_i_cnt[1:0] == 2'b00) begin - ssp_clk <= 1'b1; // Don't shift if we just loaded new data, obviously. if(corr_i_cnt != 6'd0) begin @@ -255,17 +231,70 @@ begin end end - // set ssp_frame signal for corr_i_cnt = 0..3 - // (send one frame with 16 Bits) - if(corr_i_cnt[5:2] == 4'b0000) - ssp_frame = 1'b1; - else - ssp_frame = 1'b0; - end + +// ssp clock and frame signal for communication to and from ARM +reg ssp_clk; +reg ssp_frame; + +always @(negedge adc_clk) +begin + if (corr_i_cnt[1:0] == 2'b00) + ssp_clk <= 1'b1; + if (corr_i_cnt[1:0] == 2'b10) + ssp_clk <= 1'b0; + + // set ssp_frame signal for corr_i_cnt = 1..3 + // (send one frame with 16 Bits) + if (corr_i_cnt == 6'd2) + ssp_frame <= 1'b1; + if (corr_i_cnt == 6'd14) + ssp_frame <= 1'b0; +end + + assign ssp_din = corr_i_out[7]; + +// Antenna drivers +reg pwr_hi, pwr_oe4; + +always @(*) +begin + if (minor_mode == `FPGA_HF_READER_MODE_SEND_SHALLOW_MOD) + begin + pwr_hi = ck_1356meg; + pwr_oe4 = ssp_dout; + end + else if (minor_mode == `FPGA_HF_READER_MODE_SEND_FULL_MOD) + begin + pwr_hi = ck_1356meg & ~ssp_dout; + pwr_oe4 = 1'b0; + end + else if (minor_mode == `FPGA_HF_READER_MODE_SNIFF_IQ + || minor_mode == `FPGA_HF_READER_MODE_SNIFF_AMPLITUDE + || minor_mode == `FPGA_HF_READER_MODE_SNIFF_PHASE) + begin + pwr_hi = 1'b0; + pwr_oe4 = 1'b0; + end + else // receiving from tag + begin + pwr_hi = ck_1356meg; + pwr_oe4 = 1'b0; + end +end + +// always on +assign pwr_oe1 = 1'b0; +assign pwr_oe3 = 1'b0; + +// Unused. +assign pwr_lo = 1'b0; +assign pwr_oe2 = 1'b0; + +// Debug Output assign dbg = corr_i_cnt[3]; endmodule diff --git a/fpga/hi_simulate.v b/fpga/hi_simulate.v index 8d70bb1b..de58a74e 100644 --- a/fpga/hi_simulate.v +++ b/fpga/hi_simulate.v @@ -16,29 +16,20 @@ // Jonathan Westhues, October 2006 //----------------------------------------------------------------------------- -// possible mod_types: -`define NO_MODULATION 3'b000 -`define MODULATE_BPSK 3'b001 -`define MODULATE_212K 3'b010 -`define MODULATE_424K 3'b100 -`define MODULATE_424K_8BIT 3'b101 - module hi_simulate( - pck0, ck_1356meg, ck_1356megb, + ck_1356meg, pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4, adc_d, adc_clk, ssp_frame, ssp_din, ssp_dout, ssp_clk, - cross_hi, cross_lo, dbg, mod_type ); - input pck0, ck_1356meg, ck_1356megb; + input ck_1356meg; output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4; input [7:0] adc_d; output adc_clk; input ssp_dout; output ssp_frame, ssp_din, ssp_clk; - input cross_hi, cross_lo; output dbg; input [2:0] mod_type; @@ -49,8 +40,8 @@ assign adc_clk = ck_1356meg; always @(negedge adc_clk) begin - if(& adc_d[7:5]) after_hysteresis = 1'b1; - else if(~(| adc_d[7:5])) after_hysteresis = 1'b0; + if(& adc_d[7:5]) after_hysteresis = 1'b1; // if (adc_d >= 224) + else if(~(| adc_d[7:5])) after_hysteresis = 1'b0; // if (adc_d <= 31) end @@ -65,10 +56,10 @@ reg ssp_clk; always @(negedge adc_clk) begin - if(mod_type == `MODULATE_424K_8BIT) + if(mod_type == `FPGA_HF_SIMULATOR_MODULATE_424K_8BIT) // Get bit every at 53KHz (every 8th carrier bit of 424kHz) ssp_clk <= ssp_clk_divider[7]; - else if(mod_type == `MODULATE_212K) + else if(mod_type == `FPGA_HF_SIMULATOR_MODULATE_212K) // Get next bit at 212kHz ssp_clk <= ssp_clk_divider[5]; else @@ -92,7 +83,7 @@ always @(negedge ssp_clk) reg ssp_frame; always @(ssp_frame_divider_to_arm or ssp_frame_divider_from_arm or mod_type) - if(mod_type == `NO_MODULATION) // not modulating, so listening, to ARM + if(mod_type == `FPGA_HF_SIMULATOR_NO_MODULATION) // not modulating, so listening, to ARM ssp_frame = (ssp_frame_divider_to_arm == 3'b000); else ssp_frame = (ssp_frame_divider_from_arm == 3'b000); @@ -104,14 +95,14 @@ always @(posedge ssp_clk) // Modulating carrier frequency is fc/64 (212kHz) to fc/16 (848kHz). Reuse ssp_clk divider for that. reg modulating_carrier; -always @(mod_type or ssp_clk or ssp_dout) - if (mod_type == `NO_MODULATION) +always @(*) + if (mod_type == `FPGA_HF_SIMULATOR_NO_MODULATION) modulating_carrier <= 1'b0; // no modulation - else if (mod_type == `MODULATE_BPSK) + else if (mod_type == `FPGA_HF_SIMULATOR_MODULATE_BPSK) modulating_carrier <= ssp_dout ^ ssp_clk_divider[3]; // XOR means BPSK - else if (mod_type == `MODULATE_212K) + else if (mod_type == `FPGA_HF_SIMULATOR_MODULATE_212K) modulating_carrier <= ssp_dout & ssp_clk_divider[5]; // switch 212kHz subcarrier on/off - else if (mod_type == `MODULATE_424K || mod_type == `MODULATE_424K_8BIT) + else if (mod_type == `FPGA_HF_SIMULATOR_MODULATE_424K || mod_type == `FPGA_HF_SIMULATOR_MODULATE_424K_8BIT) modulating_carrier <= ssp_dout & ssp_clk_divider[4]; // switch 424kHz modulation on/off else modulating_carrier <= 1'b0; // yet unused diff --git a/fpga/hi_sniffer.v b/fpga/hi_sniffer.v index 3a989ce6..c2dc844a 100644 --- a/fpga/hi_sniffer.v +++ b/fpga/hi_sniffer.v @@ -1,21 +1,14 @@ module hi_sniffer( - pck0, ck_1356meg, ck_1356megb, + ck_1356meg, pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4, adc_d, adc_clk, - ssp_frame, ssp_din, ssp_dout, ssp_clk, - cross_hi, cross_lo, - dbg, - xcorr_is_848, snoop, xcorr_quarter_freq // not used. + ssp_frame, ssp_din, ssp_clk ); - input pck0, ck_1356meg, ck_1356megb; + input ck_1356meg; output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4; input [7:0] adc_d; output adc_clk; - input ssp_dout; output ssp_frame, ssp_din, ssp_clk; - input cross_hi, cross_lo; - output dbg; - input xcorr_is_848, snoop, xcorr_quarter_freq; // not used. // We are only snooping, all off. assign pwr_hi = 1'b0; From ba778bc3c4493d3dae969b5d6148fbfb97640763 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Tue, 26 Mar 2019 21:50:41 +0100 Subject: [PATCH 078/189] fix FpgaSetupSsc() (#807) * ouch! Be aware that same major modes are used in LF and HF! --- armsrc/fpgaloader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armsrc/fpgaloader.c b/armsrc/fpgaloader.c index 214f4843..5ca0cce1 100644 --- a/armsrc/fpgaloader.c +++ b/armsrc/fpgaloader.c @@ -136,7 +136,7 @@ void FpgaSetupSsc(uint8_t FPGA_mode) // 8, 16 or 32 bits per transfer, no loopback, MSB first, 1 transfer per sync // pulse, no output sync - if ((FPGA_mode & 0xe0) == FPGA_MAJOR_MODE_HF_READER) { + if ((FPGA_mode & 0xe0) == FPGA_MAJOR_MODE_HF_READER && FpgaGetCurrent() == FPGA_BITSTREAM_HF) { AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(16) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0); } else { AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0); From 9c1d59ce6978e43b9626b008692d6eac1cf67423 Mon Sep 17 00:00:00 2001 From: "Malte F. Hillmann" Date: Wed, 27 Mar 2019 14:04:01 +0100 Subject: [PATCH 079/189] fixed bug in CmdBiphaseDecodeRaw() --- client/cmddata.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/client/cmddata.c b/client/cmddata.c index c4f0e8a3..fd31fac4 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -367,18 +367,20 @@ int Cmdmandecoderaw(const char *Cmd) return 1; } -//by marshmellow -//biphase decode -//take 01 or 10 = 0 and 11 or 00 = 1 -//takes 2 arguments "offset" default = 0 if 1 it will shift the decode by one bit -// and "invert" default = 0 if 1 it will invert output -// the argument offset allows us to manually shift if the output is incorrect - [EDIT: now auto detects] +/** + * @author marshmellow + * biphase decode + * decdoes 01 or 10 to 0 and 11 or 00 to 1 + * param offset adjust start position + * param invert invert output + * param maxErr maximum tolerated errors + */ int CmdBiphaseDecodeRaw(const char *Cmd) { size_t size=0; int offset=0, invert=0, maxErr=20, errCnt=0; char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) > 3 || cmdp == 'h' || cmdp == 'H') { + if (strlen(Cmd) > 5 || cmdp == 'h' || cmdp == 'H') { PrintAndLog("Usage: data biphaserawdecode [offset] [invert] [maxErr]"); PrintAndLog(" Converts 10 or 01 to 1 and 11 or 00 to 0"); PrintAndLog(" --must have binary sequence in demodbuffer (run data askrawdemod first)"); From 7361a18f7a24a7b0dd6e76919ef389202543cdc5 Mon Sep 17 00:00:00 2001 From: "Malte F. Hillmann" Date: Wed, 27 Mar 2019 14:34:42 +0100 Subject: [PATCH 080/189] fixed bug in ASKbiphaseDemod() --- client/cmddata.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/cmddata.c b/client/cmddata.c index fd31fac4..30148163 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -429,7 +429,7 @@ int CmdBiphaseDecodeRaw(const char *Cmd) int ASKbiphaseDemod(const char *Cmd, bool verbose) { //ask raw demod GraphBuffer first - int offset=0, clk=0, invert=0, maxErr=0; + int offset=0, clk=0, invert=0, maxErr=100; sscanf(Cmd, "%i %i %i %i", &offset, &clk, &invert, &maxErr); uint8_t BitStream[MAX_GRAPH_TRACE_LEN]; From 4306de82770fb4e7e033e03996710d3c50f699f7 Mon Sep 17 00:00:00 2001 From: "Malte F. Hillmann" Date: Wed, 27 Mar 2019 14:36:39 +0100 Subject: [PATCH 081/189] fixed bug in CmdFdxDemod --- client/cmdlffdx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/cmdlffdx.c b/client/cmdlffdx.c index 20f834ce..5677c79d 100644 --- a/client/cmdlffdx.c +++ b/client/cmdlffdx.c @@ -137,7 +137,7 @@ int CmdFdxDemod(const char *Cmd){ //Differential Biphase / di-phase (inverted biphase) //get binary from ask wave - if (!ASKbiphaseDemod("0 32 1 0", false)) { + if (!ASKbiphaseDemod("0 32 1 100", false)) { if (g_debugMode) PrintAndLog("DEBUG: Error - FDX-B ASKbiphaseDemod failed"); return 0; } From 3f306c6ded0e995a7150de7d4168ca689e09868f Mon Sep 17 00:00:00 2001 From: "Malte F. Hillmann" Date: Thu, 28 Mar 2019 22:40:29 +0100 Subject: [PATCH 082/189] Bugfixes for LF FDX Changed CmdBiphaseDecodeRaw to allow 7 digits Changed CmdFdxRead to read 39999 samples instead of 10000 to improve reading from small tags --- client/cmddata.c | 2 +- client/cmdlffdx.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/cmddata.c b/client/cmddata.c index 30148163..8f93ba17 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -380,7 +380,7 @@ int CmdBiphaseDecodeRaw(const char *Cmd) size_t size=0; int offset=0, invert=0, maxErr=20, errCnt=0; char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) > 5 || cmdp == 'h' || cmdp == 'H') { + if (strlen(Cmd) > 7 || cmdp == 'h' || cmdp == 'H') { PrintAndLog("Usage: data biphaserawdecode [offset] [invert] [maxErr]"); PrintAndLog(" Converts 10 or 01 to 1 and 11 or 00 to 0"); PrintAndLog(" --must have binary sequence in demodbuffer (run data askrawdemod first)"); diff --git a/client/cmdlffdx.c b/client/cmdlffdx.c index 5677c79d..d0ac52c0 100644 --- a/client/cmdlffdx.c +++ b/client/cmdlffdx.c @@ -206,7 +206,7 @@ int CmdFdxDemod(const char *Cmd){ } int CmdFdxRead(const char *Cmd) { - lf_read(true, 10000); + lf_read(true, 39999); return CmdFdxDemod(Cmd); } From bad582468fd7617e99db8c37789b5523e3ff6b9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20Veres-Szentkir=C3=A1lyi?= Date: Fri, 12 Apr 2019 08:52:18 +0200 Subject: [PATCH 083/189] Added support for Legic tags to `hf search` command (#815) * hf legic: use CMD_ACK instead of Dbprintf * hf search: add support for Legic tags --- CHANGELOG.md | 1 + armsrc/legicrf.c | 10 ++++------ client/cmdhf.c | 5 +++++ client/cmdhflegic.c | 17 ++++++++++++++++- 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 50c33d0f..adff821f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added `hf plot` (piwi) - Added `hf mfp mad` `hf mf mad` parsing MAD1 and MAD2 (Merlok) - Added `hf mfp ndef` `hf mf ndef` parsing NDEF records (Merlok) +- Added Legic detection to `hf search` (dnet) ## [v3.1.0][2018-10-10] diff --git a/armsrc/legicrf.c b/armsrc/legicrf.c index c848e647..97af8843 100644 --- a/armsrc/legicrf.c +++ b/armsrc/legicrf.c @@ -379,8 +379,9 @@ void LegicRfReader(int offset, int bytes) { // establish shared secret and detect card type DbpString("Reading card ..."); uint8_t card_type = setup_phase(SESSION_IV); + uint8_t result = 0; if(init_card(card_type, &card) != 0) { - Dbprintf("No or unknown card found, aborting"); + result = 1; goto OUT; } @@ -397,17 +398,14 @@ void LegicRfReader(int offset, int bytes) { for(uint16_t i = 0; i < bytes; ++i) { int16_t byte = read_byte(offset + i, card.cmdsize); if(byte == -1) { - Dbprintf("operation failed @ 0x%03.3x", bytes); + result = 2; goto OUT; } BigBuf[i] = byte; } - // OK - Dbprintf("Card (MIM %i) read, use 'hf legic decode' or", card.cardsize); - Dbprintf("'data hexsamples %d' to view results", (bytes+7) & ~7); - OUT: + cmd_send(CMD_ACK, result, bytes, 0, &card, sizeof(card)); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_B_OFF(); LED_C_OFF(); diff --git a/client/cmdhf.c b/client/cmdhf.c index 73b0bc76..6d25cac0 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -66,6 +66,11 @@ int CmdHFSearch(const char *Cmd){ PrintAndLog("\nValid ISO14443B Tag Found - Quiting Search\n"); return ans; } + ans = CmdLegicRFRead(""); + if (ans == 0) { + PrintAndLog("\nValid Legic Tag Found - Quiting Search\n"); + return ans; + } PrintAndLog("\nno known/supported 13.56 MHz tags found\n"); return 0; } diff --git a/client/cmdhflegic.c b/client/cmdhflegic.c index 8fbd4578..66e8ebb1 100644 --- a/client/cmdhflegic.c +++ b/client/cmdhflegic.c @@ -18,6 +18,7 @@ #include "cmdparser.h" #include "cmdmain.h" #include "util.h" +#include "../include/legic.h" static int CmdHelp(const char *Cmd); @@ -214,7 +215,21 @@ int CmdLegicRFRead(const char *Cmd) if(byte_count + offset > 1024) byte_count = 1024 - offset; UsbCommand c={CMD_READER_LEGIC_RF, {offset, byte_count, 0}}; SendCommand(&c); - return 0; + UsbCommand resp; + WaitForResponse(CMD_ACK,&resp); + switch (resp.arg[0]) { + case 0: + PrintAndLog("Card (MIM %i) read, use 'hf legic decode' or", ((legic_card_select_t*)resp.d.asBytes)->cardsize); + PrintAndLog("'data hexsamples %d' to view results", (resp.arg[1] + 7) & ~7); + break; + case 1: + PrintAndLog("No or unknown card found, aborting"); + break; + case 2: + PrintAndLog("operation failed @ 0x%03.3x", resp.arg[1]); + break; + } + return resp.arg[0]; } int CmdLegicLoad(const char *Cmd) From a8561e356bd39b45e7ba4ae66e9ed6233b66a356 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Fri, 19 Apr 2019 10:22:10 +0200 Subject: [PATCH 084/189] fix hf mf sim (#812) * fix parity encryption (thanks to Eloff, http://www.proxmark.org/forum/viewtopic.php?id=6347) * add support to simulate Mifare Mini, Mifare 2K and Mifare 4K * change to standard LED handling (A: PM is working, B: reader is sending, C: tag is responding, D: HF field is on) * NAK on unknown commands * allow unencrypted HALT * don't display messages during simulation (or we will miss next reader command) * use DMA to receive reader command * switch earlier from send to listen mode * move ADC initializer to iso14443_setup * remove remainders of incomplete Mifare 10Byte UID simulation * show 'short' bytes (7Bits or 8Bits without parity) in 'hf list mf' and 'hf list 14a' * whitespace --- CHANGELOG.md | 1 + armsrc/BigBuf.c | 35 +- armsrc/BigBuf.h | 2 +- armsrc/appmain.c | 3 +- armsrc/apps.h | 1 - armsrc/iso14443a.c | 862 ++++++++++++++++++++++---------------------- armsrc/iso14443a.h | 1 - armsrc/mifaresim.c | 431 +++++++++++++--------- armsrc/mifaresim.h | 2 +- armsrc/mifareutil.c | 280 +++++++------- armsrc/mifareutil.h | 11 +- client/cmdhflist.c | 15 +- client/cmdhfmf.c | 93 +++-- include/usb_cmd.h | 11 +- 14 files changed, 944 insertions(+), 804 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index adff821f..2a8ee1fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added `hf plot` (piwi) - Added `hf mfp mad` `hf mf mad` parsing MAD1 and MAD2 (Merlok) - Added `hf mfp ndef` `hf mf ndef` parsing NDEF records (Merlok) +- Added Mifare Mini, Mifare 2K and 4K support to `hf mf sim` (piwi) - Added Legic detection to `hf search` (dnet) ## [v3.1.0][2018-10-10] diff --git a/armsrc/BigBuf.c b/armsrc/BigBuf.c index e2f51311..ce97e41f 100644 --- a/armsrc/BigBuf.c +++ b/armsrc/BigBuf.c @@ -21,8 +21,8 @@ /* BigBuf memory layout: Pointer to highest available memory: BigBuf_hi - high BIGBUF_SIZE - reserved = BigBuf_malloc() subtracts amount from BigBuf_hi, + high BIGBUF_SIZE + reserved = BigBuf_malloc() subtracts amount from BigBuf_hi, low 0x00 */ @@ -39,6 +39,7 @@ static uint8_t *emulator_memory = NULL; static uint32_t traceLen = 0; static bool tracing = true; + // get the address of BigBuf uint8_t *BigBuf_get_addr(void) { @@ -53,7 +54,7 @@ uint8_t *BigBuf_get_EM_addr(void) if (emulator_memory == NULL) { emulator_memory = BigBuf_malloc(CARD_MEMORY_SIZE); } - + return emulator_memory; } @@ -63,17 +64,22 @@ void BigBuf_Clear(void) { BigBuf_Clear_ext(true); } + + // clear ALL of BigBuf void BigBuf_Clear_ext(bool verbose) { memset(BigBuf, 0, BIGBUF_SIZE); - if (verbose) - Dbprintf("Buffer cleared (%i bytes)",BIGBUF_SIZE); + if (verbose) + Dbprintf("Buffer cleared (%i bytes)", BIGBUF_SIZE); } + + void BigBuf_Clear_EM(void){ memset(BigBuf_get_EM_addr(), 0, CARD_MEMORY_SIZE); } + void BigBuf_Clear_keep_EM(void) { memset(BigBuf, 0, BigBuf_hi); @@ -83,11 +89,11 @@ void BigBuf_Clear_keep_EM(void) // at the beginning of BigBuf is always for traces/samples uint8_t *BigBuf_malloc(uint16_t chunksize) { - if (BigBuf_hi - chunksize < 0) { - return NULL; // no memory left + if (BigBuf_hi - chunksize < 0) { + return NULL; // no memory left } else { - chunksize = (chunksize + 3) & 0xfffc; // round to next multiple of 4 - BigBuf_hi -= chunksize; // aligned to 4 Byte boundary + chunksize = (chunksize + 3) & 0xfffc; // round to next multiple of 4 + BigBuf_hi -= chunksize; // aligned to 4 Byte boundary return (uint8_t *)BigBuf + BigBuf_hi; } } @@ -128,18 +134,22 @@ uint16_t BigBuf_max_traceLen(void) return BigBuf_hi; } + void clear_trace() { traceLen = 0; } + void set_tracing(bool enable) { tracing = enable; } + bool get_tracing(void) { return tracing; } + /** * Get the number of bytes traced * @return @@ -149,6 +159,7 @@ uint16_t BigBuf_get_traceLen(void) return traceLen; } + /** This is a function to store traces. All protocols can use this generic tracer-function. The traces produced by calling this function can be fetched on the client-side @@ -162,14 +173,14 @@ bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_ uint8_t *trace = BigBuf_get_addr(); - uint32_t num_paritybytes = (iLen-1)/8 + 1; // number of valid paritybytes in *parity + uint32_t num_paritybytes = (iLen-1)/8 + 1; // number of valid paritybytes in *parity uint32_t duration = timestamp_end - timestamp_start; // Return when trace is full uint16_t max_traceLen = BigBuf_max_traceLen(); if (traceLen + sizeof(iLen) + sizeof(timestamp_start) + sizeof(duration) + num_paritybytes + iLen >= max_traceLen) { - tracing = false; // don't trace any more + tracing = false; // don't trace any more return false; } // Traceformat: @@ -237,7 +248,7 @@ int LogTraceHitag(const uint8_t * btBytes, int iBits, int iSamples, uint32_t dwP // Return when trace is full if (traceLen + sizeof(rsamples) + sizeof(dwParity) + sizeof(iBits) + iLen > BigBuf_max_traceLen()) { return false; - } + } //Hitag traces appear to use this traceformat: // 32 bits timestamp (little endian,Highest Bit used as readerToTag flag) diff --git a/armsrc/BigBuf.h b/armsrc/BigBuf.h index 05538044..00d5145f 100644 --- a/armsrc/BigBuf.h +++ b/armsrc/BigBuf.h @@ -20,7 +20,7 @@ #define MAX_PARITY_SIZE ((MAX_FRAME_SIZE + 7) / 8) #define MAX_MIFARE_FRAME_SIZE 18 // biggest Mifare frame is answer to a read (one block = 16 Bytes) + 2 Bytes CRC #define MAX_MIFARE_PARITY_SIZE 3 // need 18 parity bits for the 18 Byte above. 3 Bytes are enough to store these -#define CARD_MEMORY_SIZE 4096 +#define CARD_MEMORY_SIZE 4096 #define DMA_BUFFER_SIZE 128 extern uint8_t *BigBuf_get_addr(void); diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 926ac52e..37328a50 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -29,6 +29,7 @@ #include "lfsampling.h" #include "BigBuf.h" #include "mifareutil.h" +#include "mifaresim.h" #include "pcf7931.h" #include "i2c.h" #include "hfsnoop.h" @@ -1249,7 +1250,7 @@ void UsbPacketReceived(uint8_t *packet, int len) MifareChkKeys(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); break; case CMD_SIMULATE_MIFARE_CARD: - Mifare1ksim(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); + MifareSim(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); break; // emulator diff --git a/armsrc/apps.h b/armsrc/apps.h index 5b8516eb..72a62628 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -119,7 +119,6 @@ void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain); void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain); void MifareChkKeys(uint16_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain); -void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); void MifareSetDbgLvl(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); void MifareEMemClr(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); void MifareEMemSet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 2f4baf17..0ca9873b 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -68,7 +68,7 @@ typedef struct { // DROP_FIRST_HALF, } state; uint16_t shiftReg; - int16_t bitCount; + int16_t bitCount; uint16_t len; uint16_t byteCntMax; uint16_t posCnt; @@ -77,7 +77,7 @@ typedef struct { uint8_t parityLen; uint32_t fourBits; uint32_t startTime, endTime; - uint8_t *output; + uint8_t *output; uint8_t *parity; } tUart; @@ -94,8 +94,8 @@ static uint8_t iso14_pcb_blocknum = 0; // // minimum time between the start bits of consecutive transfers from reader to tag: 7000 carrier (13.56Mhz) cycles #define REQUEST_GUARD_TIME (7000/16 + 1) -// minimum time between last modulation of tag and next start bit from reader to tag: 1172 carrier cycles -#define FRAME_DELAY_TIME_PICC_TO_PCD (1172/16 + 1) +// minimum time between last modulation of tag and next start bit from reader to tag: 1172 carrier cycles +#define FRAME_DELAY_TIME_PICC_TO_PCD (1172/16 + 1) // bool LastCommandWasRequest = false; // @@ -107,8 +107,8 @@ static uint8_t iso14_pcb_blocknum = 0; // 8 ticks until bit_to_arm is assigned from curbit // 8*16 ticks for the transfer from FPGA to ARM // 4*16 ticks until we measure the time -// - 8*16 ticks because we measure the time of the previous transfer -#define DELAY_AIR2ARM_AS_READER (3 + 16 + 8 + 8*16 + 4*16 - 8*16) +// - 8*16 ticks because we measure the time of the previous transfer +#define DELAY_AIR2ARM_AS_READER (3 + 16 + 8 + 8*16 + 4*16 - 8*16) // When the PM acts as a reader and is sending, it takes // 4*16 ticks until we can write data to the sending hold register @@ -125,10 +125,10 @@ static uint8_t iso14_pcb_blocknum = 0; // 8 ticks until the SSC samples the first data // 7*16 ticks to complete the transfer from FPGA to ARM // 8 ticks until the next ssp_clk rising edge -// 4*16 ticks until we measure the time -// - 8*16 ticks because we measure the time of the previous transfer +// 4*16 ticks until we measure the time +// - 8*16 ticks because we measure the time of the previous transfer #define DELAY_AIR2ARM_AS_TAG (2 + 3 + 8 + 8 + 7*16 + 8 + 4*16 - 8*16) - + // The FPGA will report its internal sending delay in uint16_t FpgaSendQueueDelay; // the 5 first bits are the number of bits buffered in mod_sig_buf @@ -150,16 +150,16 @@ uint16_t FpgaSendQueueDelay; // 8 ticks (on average) until the result is stored in to_arm // + the delays in transferring data - which is the same for // sniffing reader and tag data and therefore not relevant -#define DELAY_TAG_AIR2ARM_AS_SNIFFER (3 + 14 + 8) - +#define DELAY_TAG_AIR2ARM_AS_SNIFFER (3 + 14 + 8) + // When the PM acts as sniffer and is receiving reader data, it takes -// 2 ticks delay in analogue RF receiver (for the falling edge of the +// 2 ticks delay in analogue RF receiver (for the falling edge of the // start bit, which marks the start of the communication) // 3 ticks A/D conversion // 8 ticks on average until the data is stored in to_arm. // + the delays in transferring data - which is the same for // sniffing reader and tag data and therefore not relevant -#define DELAY_READER_AIR2ARM_AS_SNIFFER (2 + 3 + 8) +#define DELAY_READER_AIR2ARM_AS_SNIFFER (2 + 3 + 8) //variables used for timing purposes: //these are in ssp_clk cycles: @@ -177,12 +177,12 @@ static uint32_t LastProxToAirDuration; // Sequence X: 00001100 drop after half a period // Sequence Y: 00000000 no drop // Sequence Z: 11000000 drop at start -#define SEC_D 0xf0 -#define SEC_E 0x0f -#define SEC_F 0x00 -#define SEC_X 0x0c -#define SEC_Y 0x00 -#define SEC_Z 0xc0 +#define SEC_D 0xf0 +#define SEC_E 0x0f +#define SEC_F 0x00 +#define SEC_X 0x0c +#define SEC_Y 0x00 +#define SEC_Z 0xc0 void iso14a_set_trigger(bool enable) { trigger = enable; @@ -214,8 +214,8 @@ void GetParity(const uint8_t *pbtCmd, uint16_t iLen, uint8_t *par) // Generate the parity bits parityBits |= ((oddparity8(pbtCmd[i])) << (7-paritybit_cnt)); if (paritybit_cnt == 7) { - par[paritybyte_cnt] = parityBits; // save 8 Bits parity - parityBits = 0; // and advance to next Parity Byte + par[paritybyte_cnt] = parityBits; // save 8 Bits parity + parityBits = 0; // and advance to next Parity Byte paritybyte_cnt++; paritybit_cnt = 0; } else { @@ -225,7 +225,7 @@ void GetParity(const uint8_t *pbtCmd, uint16_t iLen, uint8_t *par) // save remaining parity bits par[paritybyte_cnt] = parityBits; - + } void AppendCrc14443a(uint8_t* data, int len) @@ -244,14 +244,14 @@ static void AppendCrc14443b(uint8_t* data, int len) //============================================================================= // Basics: // This decoder is used when the PM3 acts as a tag. -// The reader will generate "pauses" by temporarily switching of the field. -// At the PM3 antenna we will therefore measure a modulated antenna voltage. +// The reader will generate "pauses" by temporarily switching of the field. +// At the PM3 antenna we will therefore measure a modulated antenna voltage. // The FPGA does a comparison with a threshold and would deliver e.g.: // ........ 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 ....... // The Miller decoder needs to identify the following sequences: -// 2 (or 3) ticks pause followed by 6 (or 5) ticks unmodulated: pause at beginning - Sequence Z ("start of communication" or a "0") -// 8 ticks without a modulation: no pause - Sequence Y (a "0" or "end of communication" or "no information") -// 4 ticks unmodulated followed by 2 (or 3) ticks pause: pause in second half - Sequence X (a "1") +// 2 (or 3) ticks pause followed by 6 (or 5) ticks unmodulated: pause at beginning - Sequence Z ("start of communication" or a "0") +// 8 ticks without a modulation: no pause - Sequence Y (a "0" or "end of communication" or "no information") +// 4 ticks unmodulated followed by 2 (or 3) ticks pause: pause in second half - Sequence X (a "1") // Note 1: the bitstream may start at any time. We therefore need to sync. // Note 2: the interpretation of Sequence Y and Z depends on the preceding sequence. //----------------------------------------------------------------------------- @@ -274,19 +274,19 @@ static void UartReset() { Uart.state = STATE_UNSYNCD; Uart.bitCount = 0; - Uart.len = 0; // number of decoded data bytes - Uart.parityLen = 0; // number of decoded parity bytes - Uart.shiftReg = 0; // shiftreg to hold decoded data bits - Uart.parityBits = 0; // holds 8 parity bits - Uart.startTime = 0; - Uart.endTime = 0; + Uart.len = 0; // number of decoded data bytes + Uart.parityLen = 0; // number of decoded parity bytes + Uart.shiftReg = 0; // shiftreg to hold decoded data bits + Uart.parityBits = 0; // holds 8 parity bits } static void UartInit(uint8_t *data, uint8_t *parity) { Uart.output = data; Uart.parity = parity; - Uart.fourBits = 0x00000000; // clear the buffer for 4 Bits + Uart.fourBits = 0x00000000; // clear the buffer for 4 Bits + Uart.startTime = 0; + Uart.endTime = 0; UartReset(); } @@ -295,17 +295,17 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) { Uart.fourBits = (Uart.fourBits << 8) | bit; - - if (Uart.state == STATE_UNSYNCD) { // not yet synced - - Uart.syncBit = 9999; // not set + + if (Uart.state == STATE_UNSYNCD) { // not yet synced + + Uart.syncBit = 9999; // not set // The start bit is one ore more Sequence Y followed by a Sequence Z (... 11111111 00x11111). We need to distinguish from // Sequence X followed by Sequence Y followed by Sequence Z (111100x1 11111111 00x11111) - // we therefore look for a ...xx11111111111100x11111xxxxxx... pattern + // we therefore look for a ...xx11111111111100x11111xxxxxx... pattern // (12 '1's followed by 2 '0's, eventually followed by another '0', followed by 5 '1's) - #define ISO14443A_STARTBIT_MASK 0x07FFEF80 // mask is 00000111 11111111 11101111 10000000 - #define ISO14443A_STARTBIT_PATTERN 0x07FF8F80 // pattern is 00000111 11111111 10001111 10000000 - if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 0)) == ISO14443A_STARTBIT_PATTERN >> 0) Uart.syncBit = 7; + #define ISO14443A_STARTBIT_MASK 0x07FFEF80 // mask is 00000111 11111111 11101111 10000000 + #define ISO14443A_STARTBIT_PATTERN 0x07FF8F80 // pattern is 00000111 11111111 10001111 10000000 + if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 0)) == ISO14443A_STARTBIT_PATTERN >> 0) Uart.syncBit = 7; else if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 1)) == ISO14443A_STARTBIT_PATTERN >> 1) Uart.syncBit = 6; else if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 2)) == ISO14443A_STARTBIT_PATTERN >> 2) Uart.syncBit = 5; else if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 3)) == ISO14443A_STARTBIT_PATTERN >> 3) Uart.syncBit = 4; @@ -314,7 +314,7 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) else if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 6)) == ISO14443A_STARTBIT_PATTERN >> 6) Uart.syncBit = 1; else if ((Uart.fourBits & (ISO14443A_STARTBIT_MASK >> 7)) == ISO14443A_STARTBIT_PATTERN >> 7) Uart.syncBit = 0; - if (Uart.syncBit != 9999) { // found a sync bit + if (Uart.syncBit != 9999) { // found a sync bit Uart.startTime = non_real_time?non_real_time:(GetCountSspClk() & 0xfffffff8); Uart.startTime -= Uart.syncBit; Uart.endTime = Uart.startTime; @@ -324,97 +324,97 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) } else { - if (IsMillerModulationNibble1(Uart.fourBits >> Uart.syncBit)) { - if (IsMillerModulationNibble2(Uart.fourBits >> Uart.syncBit)) { // Modulation in both halves - error + if (IsMillerModulationNibble1(Uart.fourBits >> Uart.syncBit)) { + if (IsMillerModulationNibble2(Uart.fourBits >> Uart.syncBit)) { // Modulation in both halves - error LED_B_OFF(); UartReset(); - } else { // Modulation in first half = Sequence Z = logic "0" - if (Uart.state == STATE_MILLER_X) { // error - must not follow after X + } else { // Modulation in first half = Sequence Z = logic "0" + if (Uart.state == STATE_MILLER_X) { // error - must not follow after X LED_B_OFF(); UartReset(); } else { Uart.bitCount++; - Uart.shiftReg = (Uart.shiftReg >> 1); // add a 0 to the shiftreg + Uart.shiftReg = (Uart.shiftReg >> 1); // add a 0 to the shiftreg Uart.state = STATE_MILLER_Z; Uart.endTime = Uart.startTime + 8*(9*Uart.len + Uart.bitCount + 1) - 6; - if(Uart.bitCount >= 9) { // if we decoded a full byte (including parity) + if(Uart.bitCount >= 9) { // if we decoded a full byte (including parity) Uart.output[Uart.len++] = (Uart.shiftReg & 0xff); - Uart.parityBits <<= 1; // make room for the parity bit - Uart.parityBits |= ((Uart.shiftReg >> 8) & 0x01); // store parity bit + Uart.parityBits <<= 1; // make room for the parity bit + Uart.parityBits |= ((Uart.shiftReg >> 8) & 0x01); // store parity bit Uart.bitCount = 0; Uart.shiftReg = 0; - if((Uart.len&0x0007) == 0) { // every 8 data bytes - Uart.parity[Uart.parityLen++] = Uart.parityBits; // store 8 parity bits + if((Uart.len&0x0007) == 0) { // every 8 data bytes + Uart.parity[Uart.parityLen++] = Uart.parityBits; // store 8 parity bits Uart.parityBits = 0; } } } } } else { - if (IsMillerModulationNibble2(Uart.fourBits >> Uart.syncBit)) { // Modulation second half = Sequence X = logic "1" + if (IsMillerModulationNibble2(Uart.fourBits >> Uart.syncBit)) { // Modulation second half = Sequence X = logic "1" Uart.bitCount++; - Uart.shiftReg = (Uart.shiftReg >> 1) | 0x100; // add a 1 to the shiftreg + Uart.shiftReg = (Uart.shiftReg >> 1) | 0x100; // add a 1 to the shiftreg Uart.state = STATE_MILLER_X; Uart.endTime = Uart.startTime + 8*(9*Uart.len + Uart.bitCount + 1) - 2; - if(Uart.bitCount >= 9) { // if we decoded a full byte (including parity) + if(Uart.bitCount >= 9) { // if we decoded a full byte (including parity) Uart.output[Uart.len++] = (Uart.shiftReg & 0xff); - Uart.parityBits <<= 1; // make room for the new parity bit - Uart.parityBits |= ((Uart.shiftReg >> 8) & 0x01); // store parity bit + Uart.parityBits <<= 1; // make room for the new parity bit + Uart.parityBits |= ((Uart.shiftReg >> 8) & 0x01); // store parity bit Uart.bitCount = 0; Uart.shiftReg = 0; - if ((Uart.len&0x0007) == 0) { // every 8 data bytes - Uart.parity[Uart.parityLen++] = Uart.parityBits; // store 8 parity bits + if ((Uart.len&0x0007) == 0) { // every 8 data bytes + Uart.parity[Uart.parityLen++] = Uart.parityBits; // store 8 parity bits Uart.parityBits = 0; } } - } else { // no modulation in both halves - Sequence Y - if (Uart.state == STATE_MILLER_Z || Uart.state == STATE_MILLER_Y) { // Y after logic "0" - End of Communication + } else { // no modulation in both halves - Sequence Y + if (Uart.state == STATE_MILLER_Z || Uart.state == STATE_MILLER_Y) { // Y after logic "0" - End of Communication LED_B_OFF(); Uart.state = STATE_UNSYNCD; - Uart.bitCount--; // last "0" was part of EOC sequence - Uart.shiftReg <<= 1; // drop it - if(Uart.bitCount > 0) { // if we decoded some bits - Uart.shiftReg >>= (9 - Uart.bitCount); // right align them - Uart.output[Uart.len++] = (Uart.shiftReg & 0xff); // add last byte to the output - Uart.parityBits <<= 1; // add a (void) parity bit - Uart.parityBits <<= (8 - (Uart.len&0x0007)); // left align parity bits - Uart.parity[Uart.parityLen++] = Uart.parityBits; // and store it + Uart.bitCount--; // last "0" was part of EOC sequence + Uart.shiftReg <<= 1; // drop it + if(Uart.bitCount > 0) { // if we decoded some bits + Uart.shiftReg >>= (9 - Uart.bitCount); // right align them + Uart.output[Uart.len++] = (Uart.shiftReg & 0xff); // add last byte to the output + Uart.parityBits <<= 1; // add a (void) parity bit + Uart.parityBits <<= (8 - (Uart.len&0x0007)); // left align parity bits + Uart.parity[Uart.parityLen++] = Uart.parityBits; // and store it return true; - } else if (Uart.len & 0x0007) { // there are some parity bits to store - Uart.parityBits <<= (8 - (Uart.len&0x0007)); // left align remaining parity bits - Uart.parity[Uart.parityLen++] = Uart.parityBits; // and store them + } else if (Uart.len & 0x0007) { // there are some parity bits to store + Uart.parityBits <<= (8 - (Uart.len&0x0007)); // left align remaining parity bits + Uart.parity[Uart.parityLen++] = Uart.parityBits; // and store them } if (Uart.len) { - return true; // we are finished with decoding the raw data sequence + return true; // we are finished with decoding the raw data sequence } else { - UartReset(); // Nothing received - start over + UartReset(); // Nothing received - start over } } - if (Uart.state == STATE_START_OF_COMMUNICATION) { // error - must not follow directly after SOC + if (Uart.state == STATE_START_OF_COMMUNICATION) { // error - must not follow directly after SOC LED_B_OFF(); UartReset(); - } else { // a logic "0" + } else { // a logic "0" Uart.bitCount++; - Uart.shiftReg = (Uart.shiftReg >> 1); // add a 0 to the shiftreg + Uart.shiftReg = (Uart.shiftReg >> 1); // add a 0 to the shiftreg Uart.state = STATE_MILLER_Y; - if(Uart.bitCount >= 9) { // if we decoded a full byte (including parity) + if(Uart.bitCount >= 9) { // if we decoded a full byte (including parity) Uart.output[Uart.len++] = (Uart.shiftReg & 0xff); - Uart.parityBits <<= 1; // make room for the parity bit - Uart.parityBits |= ((Uart.shiftReg >> 8) & 0x01); // store parity bit + Uart.parityBits <<= 1; // make room for the parity bit + Uart.parityBits |= ((Uart.shiftReg >> 8) & 0x01); // store parity bit Uart.bitCount = 0; Uart.shiftReg = 0; - if ((Uart.len&0x0007) == 0) { // every 8 data bytes - Uart.parity[Uart.parityLen++] = Uart.parityBits; // store 8 parity bits + if ((Uart.len&0x0007) == 0) { // every 8 data bytes + Uart.parity[Uart.parityLen++] = Uart.parityBits; // store 8 parity bits Uart.parityBits = 0; } } } } } - - } - return false; // not finished yet, need more data + } + + return false; // not finished yet, need more data } @@ -428,10 +428,10 @@ static RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time) // at the reader antenna will be modulated as well. The FPGA detects the modulation for us and would deliver e.g. the following: // ........ 0 0 1 1 1 1 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ....... // The Manchester decoder needs to identify the following sequences: -// 4 ticks modulated followed by 4 ticks unmodulated: Sequence D = 1 (also used as "start of communication") -// 4 ticks unmodulated followed by 4 ticks modulated: Sequence E = 0 -// 8 ticks unmodulated: Sequence F = end of communication -// 8 ticks modulated: A collision. Save the collision position and treat as Sequence D +// 4 ticks modulated followed by 4 ticks unmodulated: Sequence D = 1 (also used as "start of communication") +// 4 ticks unmodulated followed by 4 ticks modulated: Sequence E = 0 +// 8 ticks unmodulated: Sequence F = end of communication +// 8 ticks modulated: A collision. Save the collision position and treat as Sequence D // Note 1: the bitstream may start at any time. We therefore need to sync. // Note 2: parameter offset is used to determine the position of the parity bits (required for the anticollision command only) static tDemod Demod; @@ -450,12 +450,12 @@ const bool Mod_Manchester_LUT[] = { static void DemodReset() { Demod.state = DEMOD_UNSYNCD; - Demod.len = 0; // number of decoded data bytes + Demod.len = 0; // number of decoded data bytes Demod.parityLen = 0; - Demod.shiftReg = 0; // shiftreg to hold decoded data bits - Demod.parityBits = 0; // - Demod.collisionPos = 0; // Position of collision bit - Demod.twoBits = 0xffff; // buffer for 2 Bits + Demod.shiftReg = 0; // shiftreg to hold decoded data bits + Demod.parityBits = 0; // + Demod.collisionPos = 0; // Position of collision bit + Demod.twoBits = 0xffff; // buffer for 2 Bits Demod.highCnt = 0; Demod.startTime = 0; Demod.endTime = 0; @@ -473,18 +473,18 @@ static RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non { Demod.twoBits = (Demod.twoBits << 8) | bit; - + if (Demod.state == DEMOD_UNSYNCD) { - if (Demod.highCnt < 2) { // wait for a stable unmodulated signal + if (Demod.highCnt < 2) { // wait for a stable unmodulated signal if (Demod.twoBits == 0x0000) { Demod.highCnt++; } else { Demod.highCnt = 0; } } else { - Demod.syncBit = 0xFFFF; // not set - if ((Demod.twoBits & 0x7700) == 0x7000) Demod.syncBit = 7; + Demod.syncBit = 0xFFFF; // not set + if ((Demod.twoBits & 0x7700) == 0x7000) Demod.syncBit = 7; else if ((Demod.twoBits & 0x3B80) == 0x3800) Demod.syncBit = 6; else if ((Demod.twoBits & 0x1DC0) == 0x1C00) Demod.syncBit = 5; else if ((Demod.twoBits & 0x0EE0) == 0x0E00) Demod.syncBit = 4; @@ -495,7 +495,7 @@ static RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non if (Demod.syncBit != 0xFFFF) { Demod.startTime = non_real_time?non_real_time:(GetCountSspClk() & 0xfffffff8); Demod.startTime -= Demod.syncBit; - Demod.bitCount = offset; // number of decoded data bits + Demod.bitCount = offset; // number of decoded data bits Demod.state = DEMOD_MANCHESTER_DATA; LED_C_ON(); } @@ -503,66 +503,66 @@ static RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non } else { - if (IsManchesterModulationNibble1(Demod.twoBits >> Demod.syncBit)) { // modulation in first half - if (IsManchesterModulationNibble2(Demod.twoBits >> Demod.syncBit)) { // ... and in second half = collision + if (IsManchesterModulationNibble1(Demod.twoBits >> Demod.syncBit)) { // modulation in first half + if (IsManchesterModulationNibble2(Demod.twoBits >> Demod.syncBit)) { // ... and in second half = collision if (!Demod.collisionPos) { Demod.collisionPos = (Demod.len << 3) + Demod.bitCount; } - } // modulation in first half only - Sequence D = 1 + } // modulation in first half only - Sequence D = 1 Demod.bitCount++; - Demod.shiftReg = (Demod.shiftReg >> 1) | 0x100; // in both cases, add a 1 to the shiftreg - if(Demod.bitCount == 9) { // if we decoded a full byte (including parity) + Demod.shiftReg = (Demod.shiftReg >> 1) | 0x100; // in both cases, add a 1 to the shiftreg + if(Demod.bitCount == 9) { // if we decoded a full byte (including parity) Demod.output[Demod.len++] = (Demod.shiftReg & 0xff); - Demod.parityBits <<= 1; // make room for the parity bit - Demod.parityBits |= ((Demod.shiftReg >> 8) & 0x01); // store parity bit + Demod.parityBits <<= 1; // make room for the parity bit + Demod.parityBits |= ((Demod.shiftReg >> 8) & 0x01); // store parity bit Demod.bitCount = 0; Demod.shiftReg = 0; - if((Demod.len&0x0007) == 0) { // every 8 data bytes - Demod.parity[Demod.parityLen++] = Demod.parityBits; // store 8 parity bits + if((Demod.len&0x0007) == 0) { // every 8 data bytes + Demod.parity[Demod.parityLen++] = Demod.parityBits; // store 8 parity bits Demod.parityBits = 0; } } Demod.endTime = Demod.startTime + 8*(9*Demod.len + Demod.bitCount + 1) - 4; - } else { // no modulation in first half - if (IsManchesterModulationNibble2(Demod.twoBits >> Demod.syncBit)) { // and modulation in second half = Sequence E = 0 + } else { // no modulation in first half + if (IsManchesterModulationNibble2(Demod.twoBits >> Demod.syncBit)) { // and modulation in second half = Sequence E = 0 Demod.bitCount++; - Demod.shiftReg = (Demod.shiftReg >> 1); // add a 0 to the shiftreg - if(Demod.bitCount >= 9) { // if we decoded a full byte (including parity) + Demod.shiftReg = (Demod.shiftReg >> 1); // add a 0 to the shiftreg + if(Demod.bitCount >= 9) { // if we decoded a full byte (including parity) Demod.output[Demod.len++] = (Demod.shiftReg & 0xff); - Demod.parityBits <<= 1; // make room for the new parity bit + Demod.parityBits <<= 1; // make room for the new parity bit Demod.parityBits |= ((Demod.shiftReg >> 8) & 0x01); // store parity bit Demod.bitCount = 0; Demod.shiftReg = 0; - if ((Demod.len&0x0007) == 0) { // every 8 data bytes - Demod.parity[Demod.parityLen++] = Demod.parityBits; // store 8 parity bits1 + if ((Demod.len&0x0007) == 0) { // every 8 data bytes + Demod.parity[Demod.parityLen++] = Demod.parityBits; // store 8 parity bits1 Demod.parityBits = 0; } } Demod.endTime = Demod.startTime + 8*(9*Demod.len + Demod.bitCount + 1); - } else { // no modulation in both halves - End of communication + } else { // no modulation in both halves - End of communication LED_C_OFF(); - if(Demod.bitCount > 0) { // there are some remaining data bits - Demod.shiftReg >>= (9 - Demod.bitCount); // right align the decoded bits - Demod.output[Demod.len++] = Demod.shiftReg & 0xff; // and add them to the output - Demod.parityBits <<= 1; // add a (void) parity bit - Demod.parityBits <<= (8 - (Demod.len&0x0007)); // left align remaining parity bits - Demod.parity[Demod.parityLen++] = Demod.parityBits; // and store them + if(Demod.bitCount > 0) { // there are some remaining data bits + Demod.shiftReg >>= (9 - Demod.bitCount); // right align the decoded bits + Demod.output[Demod.len++] = Demod.shiftReg & 0xff; // and add them to the output + Demod.parityBits <<= 1; // add a (void) parity bit + Demod.parityBits <<= (8 - (Demod.len&0x0007)); // left align remaining parity bits + Demod.parity[Demod.parityLen++] = Demod.parityBits; // and store them return true; - } else if (Demod.len & 0x0007) { // there are some parity bits to store - Demod.parityBits <<= (8 - (Demod.len&0x0007)); // left align remaining parity bits - Demod.parity[Demod.parityLen++] = Demod.parityBits; // and store them + } else if (Demod.len & 0x0007) { // there are some parity bits to store + Demod.parityBits <<= (8 - (Demod.len&0x0007)); // left align remaining parity bits + Demod.parity[Demod.parityLen++] = Demod.parityBits; // and store them } if (Demod.len) { - return true; // we are finished with decoding the raw data sequence - } else { // nothing received. Start over + return true; // we are finished with decoding the raw data sequence + } else { // nothing received. Start over DemodReset(); } } } - - } - return false; // not finished yet, need more data + } + + return false; // not finished yet, need more data } //============================================================================= @@ -579,7 +579,7 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { // param: // bit 0 - trigger from first card answer // bit 1 - trigger from first reader 7-bit request - + LEDsoff(); LED_A_ON(); @@ -592,11 +592,11 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { // The command (reader -> tag) that we're receiving. uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE); uint8_t *receivedCmdPar = BigBuf_malloc(MAX_PARITY_SIZE); - + // The response (tag -> reader) that we're receiving. uint8_t *receivedResponse = BigBuf_malloc(MAX_FRAME_SIZE); uint8_t *receivedResponsePar = BigBuf_malloc(MAX_PARITY_SIZE); - + // The DMA buffer, used to stream samples from the FPGA uint8_t *dmaBuf = BigBuf_malloc(DMA_BUFFER_SIZE); @@ -610,26 +610,26 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { int dataLen = 0; bool TagIsActive = false; bool ReaderIsActive = false; - + // Set up the demodulator for tag -> reader responses. DemodInit(receivedResponse, receivedResponsePar); - + // Set up the demodulator for the reader -> tag commands UartInit(receivedCmd, receivedCmdPar); - + // Setup and start DMA. FpgaSetupSscDma((uint8_t *)dmaBuf, DMA_BUFFER_SIZE); - + // We won't start recording the frames that we acquire until we trigger; // a good trigger condition to get started is probably when we see a // response from the tag. // triggered == false -- to wait first for card - bool triggered = !(param & 0x03); - - // And now we loop, receiving samples. - for(uint32_t rsamples = 0; true; ) { + bool triggered = !(param & 0x03); - if(BUTTON_PRESS()) { + // And now we loop, receiving samples. + for (uint32_t rsamples = 0; true; ) { + + if (BUTTON_PRESS()) { DbpString("cancelled by button"); break; } @@ -665,9 +665,9 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; } - if (rsamples & 0x01) { // Need two samples to feed Miller and Manchester-Decoder + if (rsamples & 0x01) { // Need two samples to feed Miller and Manchester-Decoder - if(!TagIsActive) { // no need to try decoding reader data if the tag is sending + if(!TagIsActive) { // no need to try decoding reader data if the tag is sending uint8_t readerdata = (previous_data & 0xF0) | (*data >> 4); if (MillerDecoding(readerdata, (rsamples-1)*4)) { // check - if there is a short 7bit request from reader @@ -675,11 +675,11 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { triggered = true; } if(triggered) { - if (!LogTrace(receivedCmd, - Uart.len, + if (!LogTrace(receivedCmd, + Uart.len, Uart.startTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, Uart.endTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, - Uart.parity, + Uart.parity, true)) break; } /* And ready to receive another command. */ @@ -691,12 +691,12 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { ReaderIsActive = (Uart.state != STATE_UNSYNCD); } - if (!ReaderIsActive) { // no need to try decoding tag data if the reader is sending - and we cannot afford the time + if (!ReaderIsActive) { // no need to try decoding tag data if the reader is sending - and we cannot afford the time uint8_t tagdata = (previous_data << 4) | (*data & 0x0F); if (ManchesterDecoding(tagdata, 0, (rsamples-1)*4)) { - if (!LogTrace(receivedResponse, - Demod.len, - Demod.startTime*16 - DELAY_TAG_AIR2ARM_AS_SNIFFER, + if (!LogTrace(receivedResponse, + Demod.len, + Demod.startTime*16 - DELAY_TAG_AIR2ARM_AS_SNIFFER, Demod.endTime*16 - DELAY_TAG_AIR2ARM_AS_SNIFFER, Demod.parity, false)) break; @@ -705,7 +705,7 @@ void RAMFUNC SnoopIso14443a(uint8_t param) { DemodReset(); // And reset the Miller decoder including itS (now outdated) input buffer UartInit(receivedCmd, receivedCmdPar); - } + } TagIsActive = (Demod.state != DEMOD_UNSYNCD); } } @@ -742,16 +742,16 @@ static void CodeIso14443aAsTagPar(const uint8_t *cmd, uint16_t len, uint8_t *par ToSendStuffBit(0); ToSendStuffBit(0); ToSendStuffBit(0); - + // Send startbit ToSend[++ToSendMax] = SEC_D; LastProxToAirDuration = 8 * ToSendMax - 4; - for(uint16_t i = 0; i < len; i++) { + for (uint16_t i = 0; i < len; i++) { uint8_t b = cmd[i]; // Data bits - for(uint16_t j = 0; j < 8; j++) { + for (uint16_t j = 0; j < 8; j++) { if(b & 1) { ToSend[++ToSendMax] = SEC_D; } else { @@ -798,7 +798,7 @@ static void Code4bitAnswerAsTag(uint8_t cmd) ToSend[++ToSendMax] = SEC_D; uint8_t b = cmd; - for(i = 0; i < 4; i++) { + for (i = 0; i < 4; i++) { if(b & 1) { ToSend[++ToSendMax] = SEC_D; LastProxToAirDuration = 8 * ToSendMax - 4; @@ -839,7 +839,7 @@ static void FixLastReaderTraceTime(uint32_t tag_StartTime) { LastReaderTraceTime[3] = (reader_StartTime >> 24) & 0xff; } - + static void EmLogTraceTag(uint8_t *tag_data, uint16_t tag_len, uint8_t *tag_Parity, uint32_t ProxToAirDuration) { uint32_t tag_StartTime = LastTimeProxToAirStart*16 + DELAY_ARM2AIR_AS_TAG; uint32_t tag_EndTime = (LastTimeProxToAirStart + ProxToAirDuration)*16 + DELAY_ARM2AIR_AS_TAG; @@ -855,39 +855,38 @@ static void EmLogTraceTag(uint8_t *tag_data, uint16_t tag_len, uint8_t *tag_Pari //----------------------------------------------------------------------------- static int GetIso14443aCommandFromReader(uint8_t *received, uint8_t *parity, int *len) { - // Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen - // only, since we are receiving, not transmitting). - // Signal field is off with the appropriate LED - LED_D_OFF(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN); + // Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen + // only, since we are receiving, not transmitting). + // Signal field is off with the appropriate LED + LED_D_OFF(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN); - // Now run a `software UART' on the stream of incoming samples. + // Now run a `software UART' on the stream of incoming samples. UartInit(received, parity); // clear RXRDY: - uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - for(;;) { - WDT_HIT(); + for (;;) { + WDT_HIT(); - if(BUTTON_PRESS()) return false; - - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + if(BUTTON_PRESS()) return false; + + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; if(MillerDecoding(b, 0)) { *len = Uart.len; EmLogTraceReader(); return true; } - } - } + } + } } -static int EmSend4bitEx(uint8_t resp); int EmSend4bit(uint8_t resp); static int EmSendCmdExPar(uint8_t *resp, uint16_t respLen, uint8_t *par); -int EmSendCmdEx(uint8_t *resp, uint16_t respLen); +int EmSendCmd(uint8_t *resp, uint16_t respLen); int EmSendPrecompiledCmd(tag_response_info_t *response_info); @@ -902,32 +901,32 @@ static bool prepare_tag_modulation(tag_response_info_t* response_info, size_t ma // ----------- + // 166 bytes, since every bit that needs to be send costs us a byte // - - + + // Prepare the tag modulation bits from the message GetParity(response_info->response, response_info->response_n, &(response_info->par)); CodeIso14443aAsTagPar(response_info->response,response_info->response_n, &(response_info->par)); - + // Make sure we do not exceed the free buffer space if (ToSendMax > max_buffer_size) { - Dbprintf("Out of memory, when modulating bits for tag answer:"); - Dbhexdump(response_info->response_n, response_info->response, false); - return false; + Dbprintf("Out of memory, when modulating bits for tag answer:"); + Dbhexdump(response_info->response_n, response_info->response, false); + return false; } - + // Copy the byte array, used for this modulation to the buffer position memcpy(response_info->modulation, ToSend, ToSendMax); - + // Store the number of bytes that were used for encoding/modulation and the time needed to transfer them response_info->modulation_n = ToSendMax; response_info->ProxToAirDuration = LastProxToAirDuration; - + return true; } // "precompile" responses. There are 7 predefined responses with a total of 28 bytes data to transmit. -// Coded responses need one byte per bit to transfer (data, parity, start, stop, correction) +// Coded responses need one byte per bit to transfer (data, parity, start, stop, correction) // 28 * 8 data bits, 28 * 1 parity bits, 7 start bits, 7 stop bits, 7 correction bits for the modulation // -> need 273 bytes buffer #define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 273 @@ -936,15 +935,15 @@ bool prepare_allocated_tag_modulation(tag_response_info_t* response_info, uint8_ // Retrieve and store the current buffer index response_info->modulation = *buffer; - + // Forward the prepare tag modulation function to the inner function if (prepare_tag_modulation(response_info, *max_buffer_size)) { - // Update the free buffer offset and the remaining buffer size - *buffer += ToSendMax; + // Update the free buffer offset and the remaining buffer size + *buffer += ToSendMax; *max_buffer_size -= ToSendMax; - return true; + return true; } else { - return false; + return false; } } @@ -958,7 +957,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) // The first response contains the ATQA (note: bytes are transmitted in reverse order). uint8_t response1[2]; - + switch (tagType) { case 1: { // MIFARE Classic // Says: I am Mifare 1k - original line @@ -989,19 +988,19 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) response1[0] = 0x01; response1[1] = 0x0f; sak = 0x01; - } break; + } break; default: { Dbprintf("Error: unkown tagtype (%d)",tagType); return; } break; } - + // The second response contains the (mandatory) first 24 bits of the UID uint8_t response2[5] = {0x00}; // Check if the uid uses the (optional) part uint8_t response2a[5] = {0x00}; - + if (uid_2nd) { response2[0] = 0x88; num_to_bytes(uid_1st,3,response2+1); @@ -1032,8 +1031,8 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) ComputeCrc14443(CRC_14443_A, response3a, 1, &response3a[1], &response3a[2]); uint8_t response5[] = { 0x00, 0x00, 0x00, 0x00 }; // Very random tag nonce - uint8_t response6[] = { 0x04, 0x58, 0x80, 0x02, 0x00, 0x00 }; // dummy ATS (pseudo-ATR), answer to RATS: - // Format byte = 0x58: FSCI=0x08 (FSC=256), TA(1) and TC(1) present, + uint8_t response6[] = { 0x04, 0x58, 0x80, 0x02, 0x00, 0x00 }; // dummy ATS (pseudo-ATR), answer to RATS: + // Format byte = 0x58: FSCI=0x08 (FSC=256), TA(1) and TC(1) present, // TA(1) = 0x80: different divisors not supported, DR = 1, DS = 1 // TB(1) = not present. Defaults: FWI = 4 (FWT = 256 * 16 * 2^4 * 1/fc = 4833us), SFGI = 0 (SFG = 256 * 16 * 2^0 * 1/fc = 302us) // TC(1) = 0x02: CID supported, NAD not supported @@ -1062,7 +1061,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) .modulation = dynamic_modulation_buffer, .modulation_n = 0 }; - + // We need to listen to the high-frequency, peak-detected path. iso14443a_setup(FPGA_HF_ISO14443A_TAGSIM_LISTEN); @@ -1098,7 +1097,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) tag_response_info_t* p_response; LED_A_ON(); - for(;;) { + for (;;) { // Clean receive command buffer if(!GetIso14443aCommandFromReader(receivedCmd, receivedCmdPar, &len)) { DbpString("Button press"); @@ -1106,32 +1105,32 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) } p_response = NULL; - + // Okay, look at the command now. lastorder = order; if(receivedCmd[0] == 0x26) { // Received a REQUEST p_response = &responses[0]; order = 1; } else if(receivedCmd[0] == 0x52) { // Received a WAKEUP p_response = &responses[0]; order = 6; - } else if(receivedCmd[1] == 0x20 && receivedCmd[0] == 0x93) { // Received request for UID (cascade 1) + } else if(receivedCmd[1] == 0x20 && receivedCmd[0] == 0x93) { // Received request for UID (cascade 1) p_response = &responses[1]; order = 2; - } else if(receivedCmd[1] == 0x20 && receivedCmd[0] == 0x95) { // Received request for UID (cascade 2) + } else if(receivedCmd[1] == 0x20 && receivedCmd[0] == 0x95) { // Received request for UID (cascade 2) p_response = &responses[2]; order = 20; - } else if(receivedCmd[1] == 0x70 && receivedCmd[0] == 0x93) { // Received a SELECT (cascade 1) + } else if(receivedCmd[1] == 0x70 && receivedCmd[0] == 0x93) { // Received a SELECT (cascade 1) p_response = &responses[3]; order = 3; - } else if(receivedCmd[1] == 0x70 && receivedCmd[0] == 0x95) { // Received a SELECT (cascade 2) + } else if(receivedCmd[1] == 0x70 && receivedCmd[0] == 0x95) { // Received a SELECT (cascade 2) p_response = &responses[4]; order = 30; - } else if(receivedCmd[0] == 0x30) { // Received a (plain) READ - EmSendCmdEx(data+(4*receivedCmd[1]),16); + } else if(receivedCmd[0] == 0x30) { // Received a (plain) READ + EmSendCmd(data+(4*receivedCmd[1]),16); // Dbprintf("Read request from reader: %x %x",receivedCmd[0],receivedCmd[1]); // We already responded, do not send anything with the EmSendCmd14443aRaw() that is called below p_response = NULL; - } else if(receivedCmd[0] == 0x50) { // Received a HALT + } else if(receivedCmd[0] == 0x50) { // Received a HALT p_response = NULL; - } else if(receivedCmd[0] == 0x60 || receivedCmd[0] == 0x61) { // Received an authentication request + } else if(receivedCmd[0] == 0x60 || receivedCmd[0] == 0x61) { // Received an authentication request p_response = &responses[5]; order = 7; - } else if(receivedCmd[0] == 0xE0) { // Received a RATS request - if (tagType == 1 || tagType == 2) { // RATS not supported + } else if(receivedCmd[0] == 0xE0) { // Received a RATS request + if (tagType == 1 || tagType == 2) { // RATS not supported EmSend4bit(CARD_NACK_NA); p_response = NULL; } else { @@ -1165,7 +1164,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) dynamic_response_info.response[0] = receivedCmd[0] ^ 0x11; dynamic_response_info.response_n = 2; } break; - + case 0xBA: { // memcpy(dynamic_response_info.response,"\xAB\x00",2); dynamic_response_info.response_n = 2; @@ -1185,7 +1184,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) dynamic_response_info.response_n = 0; } break; } - + if (dynamic_response_info.response_n > 0) { // Copy the CID from the reader query dynamic_response_info.response[1] = receivedCmd[1]; @@ -1193,7 +1192,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) // Add CRC bytes, always used in ISO 14443A-4 compliant cards AppendCrc14443a(dynamic_response_info.response,dynamic_response_info.response_n); dynamic_response_info.response_n += 2; - + if (prepare_tag_modulation(&dynamic_response_info,DYNAMIC_MODULATION_BUFFER_SIZE) == false) { Dbprintf("Error preparing tag response"); break; @@ -1217,7 +1216,7 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) if (p_response != NULL) { EmSendPrecompiledCmd(p_response); } - + if (!get_tracing()) { Dbprintf("Trace Full. Simulation stopped."); break; @@ -1237,7 +1236,7 @@ static void PrepareDelayedTransfer(uint16_t delay) uint8_t bitmask = 0; uint8_t bits_to_shift = 0; uint8_t bits_shifted = 0; - + delay &= 0x07; if (delay) { for (uint16_t i = 0; i < delay; i++) { @@ -1258,37 +1257,38 @@ static void PrepareDelayedTransfer(uint16_t delay) // Transmit the command (to the tag) that was placed in ToSend[]. // Parameter timing: // if NULL: transfer at next possible time, taking into account -// request guard time, startup frame guard time and frame delay time -// if == 0: transfer immediately and return time of transfer +// request guard time, startup frame guard time and frame delay time +// if == 0: transfer immediately and return time of transfer // if != 0: delay transfer until time specified //------------------------------------------------------------------------------------- static void TransmitFor14443a(const uint8_t *cmd, uint16_t len, uint32_t *timing) { + LED_B_ON(); LED_D_ON(); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); uint32_t ThisTransferTime = 0; if (timing) { - if(*timing == 0) { // Measure time + if(*timing == 0) { // Measure time *timing = (GetCountSspClk() + 8) & 0xfffffff8; } else { - PrepareDelayedTransfer(*timing & 0x00000007); // Delay transfer (fine tuning - up to 7 MF clock ticks) + PrepareDelayedTransfer(*timing & 0x00000007); // Delay transfer (fine tuning - up to 7 MF clock ticks) } if(MF_DBGLEVEL >= 4 && GetCountSspClk() >= (*timing & 0xfffffff8)) Dbprintf("TransmitFor14443a: Missed timing"); - while(GetCountSspClk() < (*timing & 0xfffffff8)); // Delay transfer (multiple of 8 MF clock ticks) + while (GetCountSspClk() < (*timing & 0xfffffff8)); // Delay transfer (multiple of 8 MF clock ticks) LastTimeProxToAirStart = *timing; } else { ThisTransferTime = ((MAX(NextTransferTime, GetCountSspClk()) & 0xfffffff8) + 8); - while(GetCountSspClk() < ThisTransferTime); + while (GetCountSspClk() < ThisTransferTime); LastTimeProxToAirStart = ThisTransferTime; } - + // clear TXRDY AT91C_BASE_SSC->SSC_THR = SEC_Y; uint16_t c = 0; - for(;;) { + for (;;) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { AT91C_BASE_SSC->SSC_THR = cmd[c]; c++; @@ -1297,8 +1297,9 @@ static void TransmitFor14443a(const uint8_t *cmd, uint16_t len, uint32_t *timing } } } - + NextTransferTime = MAX(NextTransferTime, LastTimeProxToAirStart + REQUEST_GUARD_TIME); + LED_B_OFF(); } @@ -1391,84 +1392,98 @@ static void CodeIso14443aBitsAsReaderPar(const uint8_t *cmd, uint16_t bits, cons //----------------------------------------------------------------------------- int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *parity) { + uint32_t field_off_time = -1; + uint32_t samples = 0; + int ret = 0; + uint8_t b = 0;; + uint8_t dmaBuf[DMA_BUFFER_SIZE]; + uint8_t *upTo = dmaBuf; + *len = 0; - uint32_t timer = 0, vtime = 0; - int analogCnt = 0; - int analogAVG = 0; - - // Set ADC to read field strength - AT91C_BASE_ADC->ADC_CR = AT91C_ADC_SWRST; - AT91C_BASE_ADC->ADC_MR = - ADC_MODE_PRESCALE(63) | - ADC_MODE_STARTUP_TIME(1) | - ADC_MODE_SAMPLE_HOLD_TIME(15); - AT91C_BASE_ADC->ADC_CHER = ADC_CHANNEL(ADC_CHAN_HF_LOW); - // start ADC - AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START; - // Run a 'software UART' on the stream of incoming samples. UartInit(received, parity); + // start ADC + AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START; + // Ensure that the FPGA Delay Queue is empty before we switch to TAGSIM_LISTEN - do { - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = SEC_F; - uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; (void) b; - } - } while (GetCountSspClk() < LastTimeProxToAirStart + LastProxToAirDuration + (FpgaSendQueueDelay>>3)); + while (GetCountSspClk() < LastTimeProxToAirStart + LastProxToAirDuration + (FpgaSendQueueDelay>>3) - 8 - 3) /* wait */ ; // Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen // only, since we are receiving, not transmitting). - // Signal field is off with the appropriate LED - LED_D_OFF(); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN); + // clear receive register, measure time of next transfer + uint32_t temp = AT91C_BASE_SSC->SSC_RHR; (void) temp; + while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)) ; + uint32_t start_time = GetCountSspClk() & 0xfffffff8; + + // Setup and start DMA. + FpgaSetupSscDma(dmaBuf, DMA_BUFFER_SIZE); + for(;;) { - WDT_HIT(); + uint16_t behindBy = ((uint8_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (DMA_BUFFER_SIZE-1); - if (BUTTON_PRESS()) return 1; + if (behindBy == 0) continue; - // test if the field exists - if (AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ADC_CHAN_HF_LOW)) { - analogCnt++; - analogAVG += AT91C_BASE_ADC->ADC_CDR[ADC_CHAN_HF_LOW]; - AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START; - if (analogCnt >= 32) { - if ((MAX_ADC_HF_VOLTAGE_LOW * (analogAVG / analogCnt) >> 10) < MF_MINFIELDV) { - vtime = GetTickCount(); - if (!timer) timer = vtime; - // 50ms no field --> card to idle state - if (vtime - timer > 50) return 2; - } else - if (timer) timer = 0; - analogCnt = 0; - analogAVG = 0; + b = *upTo++; + + if(upTo >= dmaBuf + DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. + upTo = dmaBuf; // start reading the circular buffer from the beginning + if(behindBy > (9*DMA_BUFFER_SIZE/10)) { + Dbprintf("About to blow circular buffer - aborted! behindBy=%d", behindBy); + ret = 1; + break; } } + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated. + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and + AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; // DMA Next Counter registers + } - // receive and test the miller decoding - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - if(MillerDecoding(b, 0)) { - *len = Uart.len; - EmLogTraceReader(); - return 0; + if (BUTTON_PRESS()) { + ret = 1; + break; + } + + // check reader's HF field + if (AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ADC_CHAN_HF_LOW)) { + if ((MAX_ADC_HF_VOLTAGE_LOW * AT91C_BASE_ADC->ADC_CDR[ADC_CHAN_HF_LOW]) >> 10 < MF_MINFIELDV) { + if (GetTickCount() - field_off_time > 50) { + ret = 2; // reader has switched off HF field for more than 50ms. Timeout + break; + } + } else { + field_off_time = GetTickCount(); // HF field is still there. Reset timer } - } + AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START; // restart ADC + } + if (MillerDecoding(b, start_time + samples*8)) { + *len = Uart.len; + EmLogTraceReader(); + ret = 0; + break; + } + + samples++; } + + FpgaDisableSscDma(); + return ret; } static int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen) { + LED_C_ON(); + uint8_t b; uint16_t i = 0; bool correctionNeeded; // Modulate Manchester - LED_D_OFF(); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_MOD); // include correction bit if necessary @@ -1483,73 +1498,61 @@ static int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen) correctionNeeded = Uart.parity[(Uart.len-1)/8] & (0x80 >> ((Uart.len-1) & 7)); } - if(correctionNeeded) { + if (correctionNeeded) { // 1236, so correction bit needed i = 0; } else { i = 1; } - // clear receiving shift register and holding register - while(!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)); + // clear receiving shift register and holding register b = AT91C_BASE_SSC->SSC_RHR; (void) b; - while(!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)); + while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)); b = AT91C_BASE_SSC->SSC_RHR; (void) b; - + // wait for the FPGA to signal fdt_indicator == 1 (the FPGA is ready to queue new data in its delay line) - for (uint16_t j = 0; j < 5; j++) { // allow timeout - better late than never - while(!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)); + for (uint16_t j = 0; j < 5; j++) { // allow timeout - better late than never + while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)); if (AT91C_BASE_SSC->SSC_RHR) break; } LastTimeProxToAirStart = (GetCountSspClk() & 0xfffffff8) + (correctionNeeded?8:0); // send cycle - for(; i < respLen; ) { + for (; i < respLen; ) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { AT91C_BASE_SSC->SSC_THR = resp[i++]; FpgaSendQueueDelay = (uint8_t)AT91C_BASE_SSC->SSC_RHR; } - + if(BUTTON_PRESS()) { break; } } + LED_C_OFF(); return 0; } -static int EmSend4bitEx(uint8_t resp){ +int EmSend4bit(uint8_t resp){ Code4bitAnswerAsTag(resp); int res = EmSendCmd14443aRaw(ToSend, ToSendMax); - // do the tracing for the previous reader request and this tag answer: + // Log this tag answer and fix timing of previous reader command: EmLogTraceTag(&resp, 1, NULL, LastProxToAirDuration); return res; } -int EmSend4bit(uint8_t resp){ - return EmSend4bitEx(resp); -} - - static int EmSendCmdExPar(uint8_t *resp, uint16_t respLen, uint8_t *par){ CodeIso14443aAsTagPar(resp, respLen, par); int res = EmSendCmd14443aRaw(ToSend, ToSendMax); - // do the tracing for the previous reader request and this tag answer: + // Log this tag answer and fix timing of previous reader command: EmLogTraceTag(resp, respLen, par, LastProxToAirDuration); return res; } -int EmSendCmdEx(uint8_t *resp, uint16_t respLen){ - uint8_t par[MAX_PARITY_SIZE]; - GetParity(resp, respLen, par); - return EmSendCmdExPar(resp, respLen, par); -} - - int EmSendCmd(uint8_t *resp, uint16_t respLen){ uint8_t par[MAX_PARITY_SIZE]; GetParity(resp, respLen, par); @@ -1564,7 +1567,7 @@ int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par){ int EmSendPrecompiledCmd(tag_response_info_t *response_info) { int ret = EmSendCmd14443aRaw(response_info->modulation, response_info->modulation_n); - // do the tracing for the previous reader request and this tag answer: + // Log this tag answer and fix timing of previous reader command: EmLogTraceTag(response_info->response, response_info->response_n, &(response_info->par), response_info->ProxToAirDuration); return ret; } @@ -1578,21 +1581,21 @@ int EmSendPrecompiledCmd(tag_response_info_t *response_info) { static int GetIso14443aAnswerFromTag(uint8_t *receivedResponse, uint8_t *receivedResponsePar, uint16_t offset) { uint32_t c; - + // Set FPGA mode to "reader listen mode", no modulation (listen // only, since we are receiving, not transmitting). // Signal field is on with the appropriate LED LED_D_ON(); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_LISTEN); - + // Now get the answer from the card DemodInit(receivedResponse, receivedResponsePar); // clear RXRDY: - uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; c = 0; - for(;;) { + for (;;) { WDT_HIT(); if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { @@ -1601,7 +1604,7 @@ static int GetIso14443aAnswerFromTag(uint8_t *receivedResponse, uint8_t *receive NextTransferTime = MAX(NextTransferTime, Demod.endTime - (DELAY_AIR2ARM_AS_READER + DELAY_ARM2AIR_AS_READER)/16 + FRAME_DELAY_TIME_PICC_TO_PCD); return true; } else if (c++ > iso14a_timeout && Demod.state == DEMOD_UNSYNCD) { - return false; + return false; } } } @@ -1611,12 +1614,12 @@ static int GetIso14443aAnswerFromTag(uint8_t *receivedResponse, uint8_t *receive void ReaderTransmitBitsPar(uint8_t* frame, uint16_t bits, uint8_t *par, uint32_t *timing) { CodeIso14443aBitsAsReaderPar(frame, bits, par); - + // Send command to tag TransmitFor14443a(ToSend, ToSendMax, timing); if(trigger) LED_A_ON(); - + // Log reader command in trace buffer LogTrace(frame, nbytes(bits), LastTimeProxToAirStart*16 + DELAY_ARM2AIR_AS_READER, (LastTimeProxToAirStart + LastProxToAirDuration)*16 + DELAY_ARM2AIR_AS_READER, par, true); } @@ -1665,24 +1668,24 @@ int ReaderReceive(uint8_t *receivedAnswer, uint8_t *parity) static void iso14a_set_ATS_times(uint8_t *ats) { uint8_t tb1; - uint8_t fwi, sfgi; + uint8_t fwi, sfgi; uint32_t fwt, sfgt; - - if (ats[0] > 1) { // there is a format byte T0 - if ((ats[1] & 0x20) == 0x20) { // there is an interface byte TB(1) - if ((ats[1] & 0x10) == 0x10) { // there is an interface byte TA(1) preceding TB(1) + + if (ats[0] > 1) { // there is a format byte T0 + if ((ats[1] & 0x20) == 0x20) { // there is an interface byte TB(1) + if ((ats[1] & 0x10) == 0x10) { // there is an interface byte TA(1) preceding TB(1) tb1 = ats[3]; } else { tb1 = ats[2]; } - fwi = (tb1 & 0xf0) >> 4; // frame waiting time integer (FWI) + fwi = (tb1 & 0xf0) >> 4; // frame waiting time integer (FWI) if (fwi != 15) { - fwt = 256 * 16 * (1 << fwi); // frame waiting time (FWT) in 1/fc + fwt = 256 * 16 * (1 << fwi); // frame waiting time (FWT) in 1/fc iso14a_set_timeout(fwt/(8*16)); } - sfgi = tb1 & 0x0f; // startup frame guard time integer (SFGI) + sfgi = tb1 & 0x0f; // startup frame guard time integer (SFGI) if (sfgi != 0 && sfgi != 15) { - sfgt = 256 * 16 * (1 << sfgi); // startup frame guard time (SFGT) in 1/fc + sfgt = 256 * 16 * (1 << sfgi); // startup frame guard time (SFGT) in 1/fc NextTransferTime = MAX(NextTransferTime, Demod.endTime + (sfgt - DELAY_AIR2ARM_AS_READER - DELAY_ARM2AIR_AS_READER)/16); } } @@ -1692,15 +1695,15 @@ static void iso14a_set_ATS_times(uint8_t *ats) { static int GetATQA(uint8_t *resp, uint8_t *resp_par) { -#define WUPA_RETRY_TIMEOUT 10 // 10ms +#define WUPA_RETRY_TIMEOUT 10 // 10ms uint8_t wupa[] = { 0x52 }; // 0x26 - REQA 0x52 - WAKE-UP uint32_t save_iso14a_timeout = iso14a_get_timeout(); - iso14a_set_timeout(1236/(16*8)+1); // response to WUPA is expected at exactly 1236/fc. No need to wait longer. - + iso14a_set_timeout(1236/(16*8)+1); // response to WUPA is expected at exactly 1236/fc. No need to wait longer. + uint32_t start_time = GetTickCount(); int len; - + // we may need several tries if we did send an unknown command or a wrong authentication before... do { // Broadcast for a card, WUPA (0x52) will force response from all cards in the field @@ -1708,7 +1711,7 @@ static int GetATQA(uint8_t *resp, uint8_t *resp_par) { // Receive the ATQA len = ReaderReceive(resp, resp_par); } while (len == 0 && GetTickCount() <= start_time + WUPA_RETRY_TIMEOUT); - + iso14a_set_timeout(save_iso14a_timeout); return len; } @@ -1717,7 +1720,7 @@ static int GetATQA(uint8_t *resp, uint8_t *resp_par) { // performs iso14443a anticollision (optional) and card select procedure // fills the uid and cuid pointer unless NULL // fills the card info record unless NULL -// if anticollision is false, then the UID must be provided in uid_ptr[] +// if anticollision is false, then the UID must be provided in uid_ptr[] // and num_cascades must be set (1: 4 Byte UID, 2: 7 Byte UID, 3: 10 Byte UID) // requests ATS unless no_rats is true int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats) { @@ -1759,11 +1762,11 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u if ((resp[0] & 0x1F) == 0) { return 3; } - + // OK we will select at least at cascade 1, lets see if first byte of UID was 0x88 in // which case we need to make a cascade 2 request and select - this is a long UID - // While the UID is not complete, the 3nd bit (from the right) is set in the SAK. - for(; sak & 0x04; cascade_level++) { + // While the UID is not complete, the 3rd bit (from the right) is set in the SAK. + for (; sak & 0x04; cascade_level++) { // SELECT_* (L1: 0x93, L2: 0x95, L3: 0x97) sel_uid[0] = sel_all[0] = 0x93 + cascade_level * 2; @@ -1774,21 +1777,21 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u return 0; } - if (Demod.collisionPos) { // we had a collision and need to construct the UID bit by bit + if (Demod.collisionPos) { // we had a collision and need to construct the UID bit by bit memset(uid_resp, 0, 4); uint16_t uid_resp_bits = 0; uint16_t collision_answer_offset = 0; // anti-collision-loop: while (Demod.collisionPos) { Dbprintf("Multiple tags detected. Collision after Bit %d", Demod.collisionPos); - for (uint16_t i = collision_answer_offset; i < Demod.collisionPos; i++, uid_resp_bits++) { // add valid UID bits before collision point + for (uint16_t i = collision_answer_offset; i < Demod.collisionPos; i++, uid_resp_bits++) { // add valid UID bits before collision point uint16_t UIDbit = (resp[i/8] >> (i % 8)) & 0x01; uid_resp[uid_resp_bits / 8] |= UIDbit << (uid_resp_bits % 8); } - uid_resp[uid_resp_bits/8] |= 1 << (uid_resp_bits % 8); // next time select the card(s) with a 1 in the collision position + uid_resp[uid_resp_bits/8] |= 1 << (uid_resp_bits % 8); // next time select the card(s) with a 1 in the collision position uid_resp_bits++; // construct anticollosion command: - sel_uid[1] = ((2 + uid_resp_bits/8) << 4) | (uid_resp_bits & 0x07); // length of data in bytes and bits + sel_uid[1] = ((2 + uid_resp_bits/8) << 4) | (uid_resp_bits & 0x07); // length of data in bytes and bits for (uint16_t i = 0; i <= uid_resp_bits/8; i++) { sel_uid[2+i] = uid_resp[i]; } @@ -1804,7 +1807,7 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u uid_resp[uid_resp_bits/8] |= UIDbit << (uid_resp_bits % 8); } - } else { // no collision, use the response to SELECT_ALL as current uid + } else { // no collision, use the response to SELECT_ALL as current uid memcpy(uid_resp, resp, 4); } } else { @@ -1823,10 +1826,10 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u } // Construct SELECT UID command - sel_uid[1] = 0x70; // transmitting a full UID (1 Byte cmd, 1 Byte NVB, 4 Byte UID, 1 Byte BCC, 2 Bytes CRC) - memcpy(sel_uid+2, uid_resp, 4); // the UID received during anticollision, or the provided UID - sel_uid[6] = sel_uid[2] ^ sel_uid[3] ^ sel_uid[4] ^ sel_uid[5]; // calculate and add BCC - AppendCrc14443a(sel_uid, 7); // calculate and add CRC + sel_uid[1] = 0x70; // transmitting a full UID (1 Byte cmd, 1 Byte NVB, 4 Byte UID, 1 Byte BCC, 2 Bytes CRC) + memcpy(sel_uid+2, uid_resp, 4); // the UID received during anticollision, or the provided UID + sel_uid[6] = sel_uid[2] ^ sel_uid[3] ^ sel_uid[4] ^ sel_uid[5]; // calculate and add BCC + AppendCrc14443a(sel_uid, 7); // calculate and add CRC ReaderTransmit(sel_uid, sizeof(sel_uid), NULL); // Receive the SAK @@ -1834,14 +1837,14 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u return 0; } sak = resp[0]; - + // Test if more parts of the uid are coming if ((sak & 0x04) /* && uid_resp[0] == 0x88 */) { // Remove first byte, 0x88 is not an UID byte, it CT, see page 3 of: // http://www.nxp.com/documents/application_note/AN10927.pdf uid_resp[0] = uid_resp[1]; uid_resp[1] = uid_resp[2]; - uid_resp[2] = uid_resp[3]; + uid_resp[2] = uid_resp[3]; uid_resp_len = 3; } @@ -1860,7 +1863,7 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u } // PICC compilant with iso14443a-4 ---> (SAK & 0x20 != 0) - if( (sak & 0x20) == 0) return 2; + if( (sak & 0x20) == 0) return 2; if (!no_rats) { // Request for answer to select @@ -1881,9 +1884,9 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u // set default timeout and delay next transfer based on ATS iso14a_set_ATS_times(resp); - + } - return 1; + return 1; } @@ -1903,11 +1906,22 @@ void iso14443a_setup(uint8_t fpga_minor_mode) { } FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | fpga_minor_mode); + // Set ADC to read field strength + AT91C_BASE_ADC->ADC_CR = AT91C_ADC_SWRST; + AT91C_BASE_ADC->ADC_MR = + ADC_MODE_PRESCALE(63) | + ADC_MODE_STARTUP_TIME(1) | + ADC_MODE_SAMPLE_HOLD_TIME(15); + AT91C_BASE_ADC->ADC_CHER = ADC_CHANNEL(ADC_CHAN_HF_LOW); + // Start the timer StartCountSspClk(); - + DemodReset(); UartReset(); + LastTimeProxToAirStart = 0; + FpgaSendQueueDelay = 0; + LastProxToAirDuration = 20; // arbitrary small value. Avoid lock in EmGetCmd() NextTransferTime = 2*DELAY_ARM2AIR_AS_READER; iso14a_set_timeout(1060); // 10ms default } @@ -1932,17 +1946,17 @@ b8 b7 b6 b5 b4 b3 b2 b1 b5 = ACK/NACK Coding of S-block: b8 b7 b6 b5 b4 b3 b2 b1 -1 1 x x x 0 1 0 +1 1 x x x 0 1 0 b5,b6 = 00 - DESELECT - 11 - WTX -*/ + 11 - WTX +*/ int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, bool send_chaining, void *data, uint8_t *res) { uint8_t parity[MAX_PARITY_SIZE]; uint8_t real_cmd[cmd_len + 4]; - + if (cmd_len) { // ISO 14443 APDU frame: PCB [CID] [NAD] APDU CRC PCB=0x02 - real_cmd[0] = 0x02; // bnr,nad,cid,chn=0; i-block(0x00) + real_cmd[0] = 0x02; // bnr,nad,cid,chn=0; i-block(0x00) if (send_chaining) { real_cmd[0] |= 0x10; } @@ -1951,11 +1965,11 @@ int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, bool send_chaining, void *data, u memcpy(real_cmd + 1, cmd, cmd_len); } else { // R-block. ACK - real_cmd[0] = 0xA2; // r-block + ACK + real_cmd[0] = 0xA2; // r-block + ACK real_cmd[0] |= iso14_pcb_blocknum; } AppendCrc14443a(real_cmd, cmd_len + 1); - + ReaderTransmit(real_cmd, cmd_len + 3, NULL); size_t len = ReaderReceive(data, parity); @@ -1963,20 +1977,20 @@ int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, bool send_chaining, void *data, u if (!len) { return 0; //DATA LINK ERROR - } else{ - // S-Block WTX - while(len && ((data_bytes[0] & 0xF2) == 0xF2)) { + } else { + // S-Block WTX + while (len && ((data_bytes[0] & 0xF2) == 0xF2)) { uint32_t save_iso14a_timeout = iso14a_get_timeout(); // temporarily increase timeout iso14a_set_timeout(MAX((data_bytes[1] & 0x3f) * save_iso14a_timeout, MAX_ISO14A_TIMEOUT)); - // Transmit WTX back + // Transmit WTX back // byte1 - WTXM [1..59]. command FWT=FWT*WTXM data_bytes[1] = data_bytes[1] & 0x3f; // 2 high bits mandatory set to 0b // now need to fix CRC. AppendCrc14443a(data_bytes, len - 2); // transmit S-Block ReaderTransmit(data_bytes, len, NULL); - // retrieve the result again (with increased timeout) + // retrieve the result again (with increased timeout) len = ReaderReceive(data, parity); data_bytes = data; // restore timeout @@ -1986,13 +2000,13 @@ int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, bool send_chaining, void *data, u // if we received an I- or R(ACK)-Block with a block number equal to the // current block number, toggle the current block number if (len >= 3 // PCB+CRC = 3 bytes - && ((data_bytes[0] & 0xC0) == 0 // I-Block - || (data_bytes[0] & 0xD0) == 0x80) // R-Block with ACK bit set to 0 - && (data_bytes[0] & 0x01) == iso14_pcb_blocknum) // equal block numbers + && ((data_bytes[0] & 0xC0) == 0 // I-Block + || (data_bytes[0] & 0xD0) == 0x80) // R-Block with ACK bit set to 0 + && (data_bytes[0] & 0x01) == iso14_pcb_blocknum) // equal block numbers { iso14_pcb_blocknum ^= 1; } - + // if we received I-block with chaining we need to send ACK and receive another block of data if (res) *res = data_bytes[0]; @@ -2001,9 +2015,9 @@ int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, bool send_chaining, void *data, u if (len >= 3 && !CheckCrc14443(CRC_14443_A, data_bytes, len)) { return -1; } - + } - + if (len) { // cut frame byte len -= 1; @@ -2011,7 +2025,7 @@ int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, bool send_chaining, void *data, u for (int i = 0; i < len; i++) data_bytes[i] = data_bytes[i + 1]; } - + return len; } @@ -2031,9 +2045,9 @@ void ReaderIso14443a(UsbCommand *c) byte_t buf[USB_CMD_DATA_SIZE] = {0}; uint8_t par[MAX_PARITY_SIZE]; bool cantSELECT = false; - + set_tracing(true); - + if(param & ISO14A_CLEAR_TRACE) { clear_trace(); } @@ -2084,29 +2098,29 @@ void ReaderIso14443a(UsbCommand *c) len += 2; if (lenbits) lenbits += 16; } - if(lenbits>0) { // want to send a specific number of bits (e.g. short commands) + if(lenbits>0) { // want to send a specific number of bits (e.g. short commands) if(param & ISO14A_TOPAZMODE) { int bits_to_send = lenbits; uint16_t i = 0; - ReaderTransmitBitsPar(&cmd[i++], MIN(bits_to_send, 7), NULL, NULL); // first byte is always short (7bits) and no parity + ReaderTransmitBitsPar(&cmd[i++], MIN(bits_to_send, 7), NULL, NULL); // first byte is always short (7bits) and no parity bits_to_send -= 7; while (bits_to_send > 0) { - ReaderTransmitBitsPar(&cmd[i++], MIN(bits_to_send, 8), NULL, NULL); // following bytes are 8 bit and no parity + ReaderTransmitBitsPar(&cmd[i++], MIN(bits_to_send, 8), NULL, NULL); // following bytes are 8 bit and no parity bits_to_send -= 8; } } else { GetParity(cmd, lenbits/8, par); - ReaderTransmitBitsPar(cmd, lenbits, par, NULL); // bytes are 8 bit with odd parity + ReaderTransmitBitsPar(cmd, lenbits, par, NULL); // bytes are 8 bit with odd parity } - } else { // want to send complete bytes only + } else { // want to send complete bytes only if(param & ISO14A_TOPAZMODE) { uint16_t i = 0; - ReaderTransmitBitsPar(&cmd[i++], 7, NULL, NULL); // first byte: 7 bits, no paritiy + ReaderTransmitBitsPar(&cmd[i++], 7, NULL, NULL); // first byte: 7 bits, no paritiy while (i < len) { - ReaderTransmitBitsPar(&cmd[i++], 8, NULL, NULL); // following bytes: 8 bits, no paritiy + ReaderTransmitBitsPar(&cmd[i++], 8, NULL, NULL); // following bytes: 8 bits, no paritiy } } else { - ReaderTransmit(cmd,len, NULL); // 8 bits, odd parity + ReaderTransmit(cmd,len, NULL); // 8 bits, odd parity } } arg0 = ReaderReceive(buf, par); @@ -2142,14 +2156,14 @@ static int32_t dist_nt(uint32_t nt1, uint32_t nt2) { nttmp1 = nt1; nttmp2 = nt2; - + for (i = 1; i < 32768; i++) { nttmp1 = prng_successor(nttmp1, 1); if (nttmp1 == nt2) return i; nttmp2 = prng_successor(nttmp2, 1); if (nttmp2 == nt1) return -i; } - + return(-99999); // either nt1 or nt2 are invalid nonces } @@ -2171,15 +2185,15 @@ void ReaderMifare(bool first_try) uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); - + // free eventually allocated BigBuf memory. We want all for tracing. BigBuf_free(); - + clear_trace(); set_tracing(true); uint8_t nt_diff = 0; - uint8_t par[1] = {0}; // maximum 8 Bytes to be sent here, 1 byte parity is therefore enough + uint8_t par[1] = {0}; // maximum 8 Bytes to be sent here, 1 byte parity is therefore enough static uint8_t par_low = 0; bool led_on = true; uint8_t uid[10] ={0}; @@ -2200,10 +2214,10 @@ void ReaderMifare(bool first_try) uint16_t consecutive_resyncs = 0; int isOK = 0; - if (first_try) { + if (first_try) { mf_nr_ar3 = 0; par[0] = par_low = 0; - sync_cycles = PRNG_SEQUENCE_LENGTH; // theory: Mifare Classic's random generator repeats every 2^16 cycles (and so do the tag nonces). + sync_cycles = PRNG_SEQUENCE_LENGTH; // theory: Mifare Classic's random generator repeats every 2^16 cycles (and so do the tag nonces). nt_attacked = 0; } else { @@ -2216,13 +2230,13 @@ void ReaderMifare(bool first_try) LED_A_ON(); LED_B_OFF(); LED_C_OFF(); - - #define MAX_UNEXPECTED_RANDOM 4 // maximum number of unexpected (i.e. real) random numbers when trying to sync. Then give up. - #define MAX_SYNC_TRIES 32 - #define SYNC_TIME_BUFFER 16 // if there is only SYNC_TIME_BUFFER left before next planned sync, wait for next PRNG cycle - #define NUM_DEBUG_INFOS 8 // per strategy - #define MAX_STRATEGY 3 + + #define MAX_UNEXPECTED_RANDOM 4 // maximum number of unexpected (i.e. real) random numbers when trying to sync. Then give up. + #define MAX_SYNC_TRIES 32 + #define SYNC_TIME_BUFFER 16 // if there is only SYNC_TIME_BUFFER left before next planned sync, wait for next PRNG cycle + #define NUM_DEBUG_INFOS 8 // per strategy + #define MAX_STRATEGY 3 uint16_t unexpected_random = 0; uint16_t sync_tries = 0; int16_t debug_info_nr = -1; @@ -2230,9 +2244,9 @@ void ReaderMifare(bool first_try) int32_t debug_info[MAX_STRATEGY][NUM_DEBUG_INFOS]; uint32_t select_time; uint32_t halt_time; - - for(uint16_t i = 0; true; i++) { - + + for (uint16_t i = 0; true; i++) { + LED_C_ON(); WDT_HIT(); @@ -2241,7 +2255,7 @@ void ReaderMifare(bool first_try) isOK = -1; break; } - + if (strategy == 2) { // test with additional hlt command halt_time = 0; @@ -2258,9 +2272,9 @@ void ReaderMifare(bool first_try) iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD); SpinDelay(100); } - + if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Mifare: Can't select card"); + if (MF_DBGLEVEL >= 1) Dbprintf("Mifare: Can't select card"); continue; } select_time = GetCountSspClk(); @@ -2276,11 +2290,11 @@ void ReaderMifare(bool first_try) sync_time = (sync_time & 0xfffffff8) + sync_cycles; } - // Transmit MIFARE_CLASSIC_AUTH at synctime. Should result in returning the same tag nonce (== nt_attacked) + // Transmit MIFARE_CLASSIC_AUTH at synctime. Should result in returning the same tag nonce (== nt_attacked) ReaderTransmit(mf_auth, sizeof(mf_auth), &sync_time); } else { // collect some information on tag nonces for debugging: - #define DEBUG_FIXED_SYNC_CYCLES PRNG_SEQUENCE_LENGTH + #define DEBUG_FIXED_SYNC_CYCLES PRNG_SEQUENCE_LENGTH if (strategy == 0) { // nonce distances at fixed time after card select: sync_time = select_time + DEBUG_FIXED_SYNC_CYCLES; @@ -2295,11 +2309,11 @@ void ReaderMifare(bool first_try) sync_time = DEBUG_FIXED_SYNC_CYCLES; } ReaderTransmit(mf_auth, sizeof(mf_auth), &sync_time); - } + } // Receive the (4 Byte) "random" nonce if (!ReaderReceive(receivedAnswer, receivedAnswerPar)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Mifare: Couldn't receive tag nonce"); + if (MF_DBGLEVEL >= 1) Dbprintf("Mifare: Couldn't receive tag nonce"); continue; } @@ -2317,17 +2331,17 @@ void ReaderMifare(bool first_try) if (nt_distance == -99999) { // invalid nonce received unexpected_random++; if (unexpected_random > MAX_UNEXPECTED_RANDOM) { - isOK = -3; // Card has an unpredictable PRNG. Give up + isOK = -3; // Card has an unpredictable PRNG. Give up break; } else { - continue; // continue trying... + continue; // continue trying... } } if (++sync_tries > MAX_SYNC_TRIES) { if (strategy > MAX_STRATEGY || MF_DBGLEVEL < 3) { - isOK = -4; // Card's PRNG runs at an unexpected frequency or resets unexpectedly + isOK = -4; // Card's PRNG runs at an unexpected frequency or resets unexpectedly break; - } else { // continue for a while, just to collect some debug info + } else { // continue for a while, just to collect some debug info debug_info[strategy][debug_info_nr] = nt_distance; debug_info_nr++; if (debug_info_nr == NUM_DEBUG_INFOS) { @@ -2348,9 +2362,9 @@ void ReaderMifare(bool first_try) } } - if ((nt != nt_attacked) && nt_attacked) { // we somehow lost sync. Try to catch up again... + if ((nt != nt_attacked) && nt_attacked) { // we somehow lost sync. Try to catch up again... catch_up_cycles = -dist_nt(nt_attacked, nt); - if (catch_up_cycles == 99999) { // invalid nonce received. Don't resync on that one. + if (catch_up_cycles == 99999) { // invalid nonce received. Don't resync on that one. catch_up_cycles = 0; continue; } @@ -2360,12 +2374,12 @@ void ReaderMifare(bool first_try) } else { last_catch_up = catch_up_cycles; - consecutive_resyncs = 0; + consecutive_resyncs = 0; } if (consecutive_resyncs < 3) { if (MF_DBGLEVEL >= 3) Dbprintf("Lost sync in cycle %d. nt_distance=%d. Consecutive Resyncs = %d. Trying one time catch up...\n", i, -catch_up_cycles, consecutive_resyncs); } - else { + else { sync_cycles = sync_cycles + catch_up_cycles; if (MF_DBGLEVEL >= 3) Dbprintf("Lost sync in cycle %d for the fourth time consecutively (nt_distance = %d). Adjusting sync_cycles to %d.\n", i, -catch_up_cycles, sync_cycles); last_catch_up = 0; @@ -2374,13 +2388,13 @@ void ReaderMifare(bool first_try) } continue; } - + consecutive_resyncs = 0; - + // Receive answer. This will be a 4 Bit NACK when the 8 parity bits are OK after decoding if (ReaderReceive(receivedAnswer, receivedAnswerPar)) { - catch_up_cycles = 8; // the PRNG is delayed by 8 cycles due to the NAC (4Bits = 0x05 encrypted) transfer - + catch_up_cycles = 8; // the PRNG is delayed by 8 cycles due to the NAC (4Bits = 0x05 encrypted) transfer + if (nt_diff == 0) { par_low = par[0] & 0xE0; // there is no need to check all parities for other nt_diff. Parity Bits for mf_nr_ar[0..2] won't change } @@ -2404,7 +2418,7 @@ void ReaderMifare(bool first_try) if (nt_diff == 0 && first_try) { par[0]++; - if (par[0] == 0x00) { // tried all 256 possible parities without success. Card doesn't send NACK. + if (par[0] == 0x00) { // tried all 256 possible parities without success. Card doesn't send NACK. isOK = -2; break; } @@ -2420,13 +2434,13 @@ void ReaderMifare(bool first_try) if (isOK == -4) { if (MF_DBGLEVEL >= 3) { for (uint16_t i = 0; i <= MAX_STRATEGY; i++) { - for(uint16_t j = 0; j < NUM_DEBUG_INFOS; j++) { + for (uint16_t j = 0; j < NUM_DEBUG_INFOS; j++) { Dbprintf("collected debug info[%d][%d] = %d", i, j, debug_info[i][j]); } } } } - + FpgaDisableTracing(); uint8_t buf[32]; @@ -2435,7 +2449,7 @@ void ReaderMifare(bool first_try) memcpy(buf + 8, par_list, 8); memcpy(buf + 16, ks_list, 8); memcpy(buf + 24, mf_nr_ar, 8); - + cmd_send(CMD_ACK, isOK, 0, 0, buf, 32); // Thats it... @@ -2447,8 +2461,8 @@ void ReaderMifare(bool first_try) //----------------------------------------------------------------------------- -// MIFARE sniffer. -// +// MIFARE sniffer. +// //----------------------------------------------------------------------------- void RAMFUNC SniffMifare(uint8_t param) { // param: @@ -2458,7 +2472,7 @@ void RAMFUNC SniffMifare(uint8_t param) { // C(red) A(yellow) B(green) LEDsoff(); LED_A_ON(); - + // init trace buffer clear_trace(); set_tracing(true); @@ -2498,19 +2512,19 @@ void RAMFUNC SniffMifare(uint8_t param) { MfSniffInit(); // And now we loop, receiving samples. - for(uint32_t sniffCounter = 0; true; ) { - + for (uint32_t sniffCounter = 0; true; ) { + if(BUTTON_PRESS()) { DbpString("Canceled by button."); break; } WDT_HIT(); - - if ((sniffCounter & 0x0000FFFF) == 0) { // from time to time + + if ((sniffCounter & 0x0000FFFF) == 0) { // from time to time // check if a transaction is completed (timeout after 2000ms). // if yes, stop the DMA transfer and send what we have so far to the client - if (MfSniffSend(2000)) { + if (MfSniffSend(2000)) { // Reset everything - we missed some sniffed data anyway while the DMA was stopped sniffCounter = 0; data = dmaBuf; @@ -2520,17 +2534,17 @@ void RAMFUNC SniffMifare(uint8_t param) { FpgaSetupSscDma((uint8_t *)dmaBuf, DMA_BUFFER_SIZE); // set transfer address and number of bytes. Start transfer. } } - - int register readBufDataP = data - dmaBuf; // number of bytes we have processed so far + + int register readBufDataP = data - dmaBuf; // number of bytes we have processed so far int register dmaBufDataP = DMA_BUFFER_SIZE - AT91C_BASE_PDC_SSC->PDC_RCR; // number of bytes already transferred - if (readBufDataP <= dmaBufDataP){ // we are processing the same block of data which is currently being transferred - dataLen = dmaBufDataP - readBufDataP; // number of bytes still to be processed - } else { + if (readBufDataP <= dmaBufDataP){ // we are processing the same block of data which is currently being transferred + dataLen = dmaBufDataP - readBufDataP; // number of bytes still to be processed + } else { dataLen = DMA_BUFFER_SIZE - readBufDataP + dmaBufDataP; // number of bytes still to be processed } // test for length of buffer - if(dataLen > maxDataLen) { // we are more behind than ever... - maxDataLen = dataLen; + if(dataLen > maxDataLen) { // we are more behind than ever... + maxDataLen = dataLen; if(dataLen > (9 * DMA_BUFFER_SIZE / 10)) { Dbprintf("blew circular buffer! dataLen=0x%x", dataLen); break; @@ -2552,7 +2566,7 @@ void RAMFUNC SniffMifare(uint8_t param) { if (sniffCounter & 0x01) { - if(!TagIsActive) { // no need to try decoding tag data if the reader is sending + if(!TagIsActive) { // no need to try decoding tag data if the reader is sending uint8_t readerdata = (previous_data & 0xF0) | (*data >> 4); if(MillerDecoding(readerdata, (sniffCounter-1)*4)) { @@ -2560,14 +2574,14 @@ void RAMFUNC SniffMifare(uint8_t param) { /* And ready to receive another command. */ UartInit(receivedCmd, receivedCmdPar); - + /* And also reset the demod code */ DemodReset(); } ReaderIsActive = (Uart.state != STATE_UNSYNCD); } - - if(!ReaderIsActive) { // no need to try decoding tag data if the reader is sending + + if(!ReaderIsActive) { // no need to try decoding tag data if the reader is sending uint8_t tagdata = (previous_data << 4) | (*data & 0x0F); if(ManchesterDecoding(tagdata, 0, (sniffCounter-1)*4)) { @@ -2598,6 +2612,6 @@ void RAMFUNC SniffMifare(uint8_t param) { DbpString("COMMAND FINISHED."); MfSniffEnd(); - + Dbprintf("maxDataLen=%x, Uart.state=%x, Uart.len=%x", maxDataLen, Uart.state, Uart.len); } diff --git a/armsrc/iso14443a.h b/armsrc/iso14443a.h index 6954a29b..df2dcbea 100644 --- a/armsrc/iso14443a.h +++ b/armsrc/iso14443a.h @@ -41,7 +41,6 @@ extern void ReaderMifare(bool first_try); extern int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *parity); extern int EmSendCmd(uint8_t *resp, uint16_t respLen); -extern int EmSendCmdEx(uint8_t *resp, uint16_t respLen); extern int EmSend4bit(uint8_t resp); extern int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par); extern int EmSendPrecompiledCmd(tag_response_info_t *response_info); diff --git a/armsrc/mifaresim.c b/armsrc/mifaresim.c index c9264836..6f97e1b4 100644 --- a/armsrc/mifaresim.c +++ b/armsrc/mifaresim.c @@ -25,26 +25,24 @@ #include "apps.h" //mifare emulator states -#define MFEMUL_NOFIELD 0 -#define MFEMUL_IDLE 1 -#define MFEMUL_SELECT1 2 -#define MFEMUL_SELECT2 3 -#define MFEMUL_SELECT3 4 -#define MFEMUL_AUTH1 5 -#define MFEMUL_AUTH2 6 -#define MFEMUL_WORK 7 -#define MFEMUL_WRITEBL2 8 -#define MFEMUL_INTREG_INC 9 -#define MFEMUL_INTREG_DEC 10 -#define MFEMUL_INTREG_REST 11 -#define MFEMUL_HALTED 12 - -#define cardSTATE_TO_IDLE() { cardSTATE = MFEMUL_IDLE; LED_B_OFF(); LED_C_OFF(); } +#define MFEMUL_NOFIELD 0 +#define MFEMUL_IDLE 1 +#define MFEMUL_SELECT1 2 +#define MFEMUL_SELECT2 3 +#define MFEMUL_SELECT3 4 +#define MFEMUL_AUTH1 5 +#define MFEMUL_AUTH2 6 +#define MFEMUL_WORK 7 +#define MFEMUL_WRITEBL2 8 +#define MFEMUL_INTREG_INC 9 +#define MFEMUL_INTREG_DEC 10 +#define MFEMUL_INTREG_REST 11 +#define MFEMUL_HALTED 12 #define AC_DATA_READ 0 #define AC_DATA_WRITE 1 -#define AC_DATA_INC 2 -#define AC_DATA_DEC_TRANS_REST 3 +#define AC_DATA_INC 2 +#define AC_DATA_DEC_TRANS_REST 3 #define AC_KEYA_READ 0 #define AC_KEYA_WRITE 1 #define AC_KEYB_READ 2 @@ -57,11 +55,30 @@ #define AUTHKEYNONE 0xff +static int ParamCardSizeBlocks(const char c) { + int numBlocks = 16 * 4; + switch (c) { + case '0' : numBlocks = 5 * 4; break; + case '2' : numBlocks = 32 * 4; break; + case '4' : numBlocks = 32 * 4 + 8 * 16; break; + default: numBlocks = 16 * 4; + } + return numBlocks; +} + +static uint8_t BlockToSector(int block_num) { + if (block_num < 32 * 4) { // 4 blocks per sector + return (block_num / 4); + } else { // 16 blocks per sector + return 32 + (block_num - 32 * 4) / 16; + } +} + static bool IsTrailerAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t action) { uint8_t sector_trailer[16]; emlGetMem(sector_trailer, blockNo, 1); uint8_t AC = ((sector_trailer[7] >> 5) & 0x04) - | ((sector_trailer[8] >> 2) & 0x02) + | ((sector_trailer[8] >> 2) & 0x02) | ((sector_trailer[8] >> 7) & 0x01); switch (action) { case AC_KEYA_READ: { @@ -69,8 +86,8 @@ static bool IsTrailerAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t act break; } case AC_KEYA_WRITE: { - return ((keytype == AUTHKEYA && (AC == 0x00 || AC == 0x01)) - || (keytype == AUTHKEYB && (AC == 0x04 || AC == 0x03))); + return ((keytype == AUTHKEYA && (AC == 0x00 || AC == 0x01)) + || (keytype == AUTHKEYB && (AC == 0x04 || AC == 0x03))); break; } case AC_KEYB_READ: { @@ -79,17 +96,17 @@ static bool IsTrailerAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t act } case AC_KEYB_WRITE: { return ((keytype == AUTHKEYA && (AC == 0x00 || AC == 0x04)) - || (keytype == AUTHKEYB && (AC == 0x04 || AC == 0x03))); + || (keytype == AUTHKEYB && (AC == 0x04 || AC == 0x03))); break; } case AC_AC_READ: { return ((keytype == AUTHKEYA) - || (keytype == AUTHKEYB && !(AC == 0x00 || AC == 0x02 || AC == 0x01))); + || (keytype == AUTHKEYB && !(AC == 0x00 || AC == 0x02 || AC == 0x01))); break; } case AC_AC_WRITE: { return ((keytype == AUTHKEYA && (AC == 0x01)) - || (keytype == AUTHKEYB && (AC == 0x03 || AC == 0x05))); + || (keytype == AUTHKEYB && (AC == 0x03 || AC == 0x05))); break; } default: return false; @@ -129,33 +146,33 @@ static bool IsDataAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t action | ((sector_trailer[8] >> 6) & 0x01); break; } - default: + default: return false; } - + switch (action) { case AC_DATA_READ: { return ((keytype == AUTHKEYA && !(AC == 0x03 || AC == 0x05 || AC == 0x07)) - || (keytype == AUTHKEYB && !(AC == 0x07))); + || (keytype == AUTHKEYB && !(AC == 0x07))); break; } case AC_DATA_WRITE: { return ((keytype == AUTHKEYA && (AC == 0x00)) - || (keytype == AUTHKEYB && (AC == 0x00 || AC == 0x04 || AC == 0x06 || AC == 0x03))); + || (keytype == AUTHKEYB && (AC == 0x00 || AC == 0x04 || AC == 0x06 || AC == 0x03))); break; } case AC_DATA_INC: { return ((keytype == AUTHKEYA && (AC == 0x00)) - || (keytype == AUTHKEYB && (AC == 0x00 || AC == 0x06))); + || (keytype == AUTHKEYB && (AC == 0x00 || AC == 0x06))); break; } case AC_DATA_DEC_TRANS_REST: { return ((keytype == AUTHKEYA && (AC == 0x00 || AC == 0x06 || AC == 0x01)) - || (keytype == AUTHKEYB && (AC == 0x00 || AC == 0x06 || AC == 0x01))); + || (keytype == AUTHKEYB && (AC == 0x00 || AC == 0x06 || AC == 0x01))); break; } } - + return false; } @@ -169,18 +186,18 @@ static bool IsAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t action) { } -static void MifareSimInit(uint8_t flags, uint8_t *datain, tag_response_info_t **responses, uint32_t *cuid, uint8_t *uid_len) { +static void MifareSimInit(uint8_t flags, uint8_t *datain, tag_response_info_t **responses, uint32_t *cuid, uint8_t *uid_len, uint8_t cardsize) { - #define TAG_RESPONSE_COUNT 5 // number of precompiled responses - static uint8_t rATQA[] = {0x04, 0x00}; // indicate Mifare classic 1k 4Byte UID - static uint8_t rUIDBCC1[] = {0x00, 0x00, 0x00, 0x00, 0x00}; // UID 1st cascade level - static uint8_t rUIDBCC2[] = {0x00, 0x00, 0x00, 0x00, 0x00}; // UID 2nd cascade level - static uint8_t rSAKfinal[]= {0x08, 0xb6, 0xdd}; // mifare 1k indicated - static uint8_t rSAK1[] = {0x04, 0xda, 0x17}; // indicate UID not finished + #define TAG_RESPONSE_COUNT 5 // number of precompiled responses + static uint8_t rATQA[] = {0x00, 0x00}; + static uint8_t rUIDBCC1[] = {0x00, 0x00, 0x00, 0x00, 0x00}; // UID 1st cascade level + static uint8_t rUIDBCC2[] = {0x00, 0x00, 0x00, 0x00, 0x00}; // UID 2nd cascade level + static uint8_t rSAKfinal[]= {0x00, 0x00, 0x00}; // SAK after UID complete + static uint8_t rSAK1[] = {0x00, 0x00, 0x00}; // indicate UID not finished *uid_len = 4; // UID can be set from emulator memory or incoming data and can be 4 or 7 bytes long - if (flags & FLAG_4B_UID_IN_DATA) { // get UID from datain + if (flags & FLAG_4B_UID_IN_DATA) { // get UID from datain memcpy(rUIDBCC1, datain, 4); } else if (flags & FLAG_7B_UID_IN_DATA) { rUIDBCC1[0] = 0x88; @@ -189,10 +206,10 @@ static void MifareSimInit(uint8_t flags, uint8_t *datain, tag_response_info_t ** *uid_len = 7; } else { uint8_t probable_atqa; - emlGetMemBt(&probable_atqa, 7, 1); // get UID from emul memory - weak guess at length - if (probable_atqa == 0x00) { // ---------- 4BUID + emlGetMemBt(&probable_atqa, 7, 1); // get UID from emul memory - weak guess at length + if (probable_atqa == 0x00) { // ---------- 4BUID emlGetMemBt(rUIDBCC1, 0, 4); - } else { // ---------- 7BUID + } else { // ---------- 7BUID rUIDBCC1[0] = 0x88; emlGetMemBt(rUIDBCC1+1, 0, 3); emlGetMemBt(rUIDBCC2, 3, 4); @@ -204,37 +221,65 @@ static void MifareSimInit(uint8_t flags, uint8_t *datain, tag_response_info_t ** case 4: *cuid = bytes_to_num(rUIDBCC1, 4); rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; - if (MF_DBGLEVEL >= 2) { - Dbprintf("4B UID: %02x%02x%02x%02x", - rUIDBCC1[0], rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3] ); + if (MF_DBGLEVEL >= MF_DBG_INFO) { + Dbprintf("4B UID: %02x%02x%02x%02x", + rUIDBCC1[0], rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3] ); } break; case 7: - rATQA[0] |= 0x40; *cuid = bytes_to_num(rUIDBCC2, 4); - rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; - rUIDBCC2[4] = rUIDBCC2[0] ^ rUIDBCC2[1] ^ rUIDBCC2[2] ^ rUIDBCC2[3]; - if (MF_DBGLEVEL >= 2) { + rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; + rUIDBCC2[4] = rUIDBCC2[0] ^ rUIDBCC2[1] ^ rUIDBCC2[2] ^ rUIDBCC2[3]; + if (MF_DBGLEVEL >= MF_DBG_INFO) { Dbprintf("7B UID: %02x %02x %02x %02x %02x %02x %02x", rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3], rUIDBCC2[0], rUIDBCC2[1], rUIDBCC2[2], rUIDBCC2[3] ); } break; - default: + default: break; } - + + // set SAK based on cardsize + switch (cardsize) { + case '0': rSAKfinal[0] = 0x09; break; // Mifare Mini + case '2': rSAKfinal[0] = 0x10; break; // Mifare 2K + case '4': rSAKfinal[0] = 0x18; break; // Mifare 4K + default: rSAKfinal[0] = 0x08; // Mifare 1K + } + ComputeCrc14443(CRC_14443_A, rSAKfinal, 1, rSAKfinal + 1, rSAKfinal + 2); + if (MF_DBGLEVEL >= MF_DBG_INFO) { + Dbprintf("SAK: %02x", rSAKfinal[0]); + } + + // set SAK for incomplete UID + rSAK1[0] = 0x04; // Bit 3 indicates incomplete UID + ComputeCrc14443(CRC_14443_A, rSAK1, 1, rSAK1 + 1, rSAK1 + 2); + + // set ATQA based on cardsize and UIDlen + if (cardsize == '4') { + rATQA[0] = 0x02; + } else { + rATQA[0] = 0x04; + } + if (*uid_len == 7) { + rATQA[0] |= 0x40; + } + if (MF_DBGLEVEL >= MF_DBG_INFO) { + Dbprintf("ATQA: %02x %02x", rATQA[1], rATQA[0]); + } + static tag_response_info_t responses_init[TAG_RESPONSE_COUNT] = { - { .response = rATQA, .response_n = sizeof(rATQA) }, // Answer to request - respond with card type - { .response = rUIDBCC1, .response_n = sizeof(rUIDBCC1) }, // Anticollision cascade1 - respond with first part of uid - { .response = rUIDBCC2, .response_n = sizeof(rUIDBCC2) }, // Anticollision cascade2 - respond with 2nd part of uid - { .response = rSAKfinal, .response_n = sizeof(rSAKfinal) }, // Acknowledge select - last cascade - { .response = rSAK1, .response_n = sizeof(rSAK1) } // Acknowledge select - previous cascades + { .response = rATQA, .response_n = sizeof(rATQA) }, // Answer to request - respond with card type + { .response = rUIDBCC1, .response_n = sizeof(rUIDBCC1) }, // Anticollision cascade1 - respond with first part of uid + { .response = rUIDBCC2, .response_n = sizeof(rUIDBCC2) }, // Anticollision cascade2 - respond with 2nd part of uid + { .response = rSAKfinal, .response_n = sizeof(rSAKfinal) }, // Acknowledge select - last cascade + { .response = rSAK1, .response_n = sizeof(rSAK1) } // Acknowledge select - previous cascades }; // Prepare ("precompile") the responses of the anticollision phase. There will be not enough time to do this at the moment the reader sends its REQA or SELECT - // There are 7 predefined responses with a total of 18 bytes data to transmit. Coded responses need one byte per bit to transfer (data, parity, start, stop, correction) + // There are 5 predefined responses with a total of 18 bytes data to transmit. Coded responses need one byte per bit to transfer (data, parity, start, stop, correction) // 18 * 8 data bits, 18 * 1 parity bits, 5 start bits, 5 stop bits, 5 correction bits -> need 177 bytes buffer - #define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 177 // number of bytes required for precompiled responses + #define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 177 // number of bytes required for precompiled responses uint8_t *free_buffer_pointer = BigBuf_malloc(ALLOCATED_TAG_MODULATION_BUFFER_SIZE); size_t free_buffer_size = ALLOCATED_TAG_MODULATION_BUFFER_SIZE; @@ -262,22 +307,23 @@ static bool HasValidCRC(uint8_t *receivedCmd, uint16_t receivedCmd_len) { /** - *MIFARE 1K simulate. + *MIFARE simulate. * *@param flags : - * FLAG_INTERACTIVE - In interactive mode, we are expected to finish the operation with an ACK + * FLAG_INTERACTIVE - In interactive mode, we are expected to finish the operation with an ACK * FLAG_4B_UID_IN_DATA - means that there is a 4-byte UID in the data-section, we're expected to use that * FLAG_7B_UID_IN_DATA - means that there is a 7-byte UID in the data-section, we're expected to use that - * FLAG_10B_UID_IN_DATA - use 10-byte UID in the data-section not finished - * FLAG_NR_AR_ATTACK - means we should collect NR_AR responses for bruteforcing later + * FLAG_NR_AR_ATTACK - means we should collect NR_AR responses for bruteforcing later * FLAG_RANDOM_NONCE - means we should generate some pseudo-random nonce data (only allows moebius attack) *@param exitAfterNReads, exit simulation after n blocks have been read, 0 is infinite ... * (unless reader attack mode enabled then it runs util it gets enough nonces to recover all keys attmpted) */ -void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *datain) +void MifareSim(uint8_t flags, uint8_t exitAfterNReads, uint8_t cardsize, uint8_t *datain) { + LED_A_ON(); + tag_response_info_t *responses; - uint8_t uid_len = 4; + uint8_t uid_len = 4; uint32_t cuid = 0; uint8_t cardWRBL = 0; uint8_t cardAUTHSC = 0; @@ -288,48 +334,47 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * uint32_t cardINTREG = 0; uint8_t cardINTBLOCK = 0; struct Crypto1State mpcs = {0, 0}; - struct Crypto1State *pcs; - pcs = &mpcs; - uint32_t numReads = 0;//Counts numer of times reader reads a block + struct Crypto1State *pcs = &mpcs; + uint32_t numReads = 0; //Counts numer of times reader reads a block uint8_t receivedCmd[MAX_MIFARE_FRAME_SIZE]; uint8_t receivedCmd_dec[MAX_MIFARE_FRAME_SIZE]; uint8_t receivedCmd_par[MAX_MIFARE_PARITY_SIZE]; uint16_t receivedCmd_len; uint8_t response[MAX_MIFARE_FRAME_SIZE]; uint8_t response_par[MAX_MIFARE_PARITY_SIZE]; - - uint8_t rAUTH_NT[] = {0x01, 0x02, 0x03, 0x04}; - uint8_t rAUTH_AT[] = {0x00, 0x00, 0x00, 0x00}; - - //Here, we collect UID,sector,keytype,NT,AR,NR,NT2,AR2,NR2 + uint8_t fixed_nonce[] = {0x01, 0x02, 0x03, 0x04}; + + int num_blocks = ParamCardSizeBlocks(cardsize); + + // Here we collect UID, sector, keytype, NT, AR, NR, NT2, AR2, NR2 // This will be used in the reader-only attack. - //allow collecting up to 7 sets of nonces to allow recovery of up to 7 keys + // allow collecting up to 7 sets of nonces to allow recovery of up to 7 keys #define ATTACK_KEY_COUNT 7 // keep same as define in cmdhfmf.c -> readerAttack() (Cannot be more than 7) - nonces_t ar_nr_resp[ATTACK_KEY_COUNT*2]; //*2 for 2 separate attack types (nml, moebius) 36 * 7 * 2 bytes = 504 bytes + nonces_t ar_nr_resp[ATTACK_KEY_COUNT*2]; // *2 for 2 separate attack types (nml, moebius) 36 * 7 * 2 bytes = 504 bytes memset(ar_nr_resp, 0x00, sizeof(ar_nr_resp)); - uint8_t ar_nr_collected[ATTACK_KEY_COUNT*2]; //*2 for 2nd attack type (moebius) + uint8_t ar_nr_collected[ATTACK_KEY_COUNT*2]; // *2 for 2nd attack type (moebius) memset(ar_nr_collected, 0x00, sizeof(ar_nr_collected)); - uint8_t nonce1_count = 0; - uint8_t nonce2_count = 0; - uint8_t moebius_n_count = 0; + uint8_t nonce1_count = 0; + uint8_t nonce2_count = 0; + uint8_t moebius_n_count = 0; bool gettingMoebius = false; - uint8_t mM = 0; //moebius_modifier for collection storage + uint8_t mM = 0; // moebius_modifier for collection storage // Authenticate response - nonce uint32_t nonce; if (flags & FLAG_RANDOM_NONCE) { nonce = prand(); } else { - nonce = bytes_to_num(rAUTH_NT, 4); + nonce = bytes_to_num(fixed_nonce, 4); } // free eventually allocated BigBuf memory but keep Emulator Memory BigBuf_free_keep_EM(); - MifareSimInit(flags, datain, &responses, &cuid, &uid_len); - + MifareSimInit(flags, datain, &responses, &cuid, &uid_len, cardsize); + // We need to listen to the high-frequency, peak-detected path. iso14443a_setup(FPGA_HF_ISO14443A_TAGSIM_LISTEN); @@ -337,7 +382,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * clear_trace(); set_tracing(true); ResetSspClk(); - + bool finished = false; bool button_pushed = BUTTON_PRESS(); int cardSTATE = MFEMUL_NOFIELD; @@ -345,25 +390,28 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * while (!button_pushed && !finished && !usb_poll_validate_length()) { WDT_HIT(); - // find reader field if (cardSTATE == MFEMUL_NOFIELD) { + // wait for reader HF field int vHf = (MAX_ADC_HF_VOLTAGE_LOW * AvgAdc(ADC_CHAN_HF_LOW)) >> 10; if (vHf > MF_MINFIELDV) { - LED_A_ON(); - cardSTATE_TO_IDLE(); + LED_D_ON(); + cardSTATE = MFEMUL_IDLE; } button_pushed = BUTTON_PRESS(); continue; } //Now, get data + FpgaEnableTracing(); int res = EmGetCmd(receivedCmd, &receivedCmd_len, receivedCmd_par); - - if (res == 2) { //Field is off! - LEDsoff(); + + if (res == 2) { // Reader has dropped the HF field. Power off. + FpgaDisableTracing(); + LED_D_OFF(); cardSTATE = MFEMUL_NOFIELD; continue; } else if (res == 1) { // button pressed + FpgaDisableTracing(); button_pushed = true; break; } @@ -371,6 +419,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * // WUPA in HALTED state or REQA or WUPA in any other state if (receivedCmd_len == 1 && ((receivedCmd[0] == ISO14443A_CMD_REQA && cardSTATE != MFEMUL_HALTED) || receivedCmd[0] == ISO14443A_CMD_WUPA)) { EmSendPrecompiledCmd(&responses[ATQA]); + FpgaDisableTracing(); // init crypto block crypto1_destroy(pcs); @@ -378,66 +427,68 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * if (flags & FLAG_RANDOM_NONCE) { nonce = prand(); } - LED_B_OFF(); - LED_C_OFF(); cardSTATE = MFEMUL_SELECT1; continue; } - + switch (cardSTATE) { case MFEMUL_NOFIELD: case MFEMUL_HALTED: case MFEMUL_IDLE:{ break; } + case MFEMUL_SELECT1:{ // select all - 0x93 0x20 if (receivedCmd_len == 2 && (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && receivedCmd[1] == 0x20)) { - if (MF_DBGLEVEL >= 4) Dbprintf("SELECT ALL CL1 received"); EmSendPrecompiledCmd(&responses[UIDBCC1]); + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("SELECT ALL CL1 received"); break; } // select card - 0x93 0x70 ... if (receivedCmd_len == 9 && (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && receivedCmd[1] == 0x70 && memcmp(&receivedCmd[2], responses[UIDBCC1].response, 4) == 0)) { - if (MF_DBGLEVEL >= 4) Dbprintf("SELECT CL1 %02x%02x%02x%02x received",receivedCmd[2],receivedCmd[3],receivedCmd[4],receivedCmd[5]); if (uid_len == 4) { EmSendPrecompiledCmd(&responses[SAKfinal]); - LED_B_ON(); cardSTATE = MFEMUL_WORK; - break; } else if (uid_len == 7) { EmSendPrecompiledCmd(&responses[SAK1]); - cardSTATE = MFEMUL_SELECT2; - break; + cardSTATE = MFEMUL_SELECT2; } + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("SELECT CL1 %02x%02x%02x%02x received",receivedCmd[2],receivedCmd[3],receivedCmd[4],receivedCmd[5]); + break; } - cardSTATE_TO_IDLE(); + cardSTATE = MFEMUL_IDLE; break; } + case MFEMUL_SELECT2:{ // select all cl2 - 0x95 0x20 if (receivedCmd_len == 2 && (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && receivedCmd[1] == 0x20)) { - if (MF_DBGLEVEL >= 4) Dbprintf("SELECT ALL CL2 received"); EmSendPrecompiledCmd(&responses[UIDBCC2]); + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("SELECT ALL CL2 received"); break; } // select cl2 card - 0x95 0x70 xxxxxxxxxxxx - if (receivedCmd_len == 9 && + if (receivedCmd_len == 9 && (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && receivedCmd[1] == 0x70 && memcmp(&receivedCmd[2], responses[UIDBCC2].response, 4) == 0)) { if (uid_len == 7) { - if (MF_DBGLEVEL >= 4) Dbprintf("SELECT CL2 %02x%02x%02x%02x received",receivedCmd[2],receivedCmd[3],receivedCmd[4],receivedCmd[5]); EmSendPrecompiledCmd(&responses[SAKfinal]); - LED_B_ON(); + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("SELECT CL2 %02x%02x%02x%02x received",receivedCmd[2],receivedCmd[3],receivedCmd[4],receivedCmd[5]); cardSTATE = MFEMUL_WORK; break; } } - cardSTATE_TO_IDLE(); + cardSTATE = MFEMUL_IDLE; break; } + case MFEMUL_WORK:{ - if (receivedCmd_len != 4) { // all commands must have exactly 4 bytes + if (receivedCmd_len != 4) { // all commands must have exactly 4 bytes break; } bool encrypted_data = (cardAUTHKEY != AUTHKEYNONE) ; @@ -448,76 +499,92 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * memcpy(receivedCmd_dec, receivedCmd, receivedCmd_len); } if (!HasValidCRC(receivedCmd_dec, receivedCmd_len)) { // all commands must have a valid CRC - EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); + EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_TR)); break; } + if (receivedCmd_dec[0] == MIFARE_AUTH_KEYA || receivedCmd_dec[0] == MIFARE_AUTH_KEYB) { // if authenticating to a block that shouldn't exist - as long as we are not doing the reader attack - if (receivedCmd_dec[1] >= 16 * 4 && !(flags & FLAG_NR_AR_ATTACK)) { + if (receivedCmd_dec[1] >= num_blocks && !(flags & FLAG_NR_AR_ATTACK)) { //is this the correct response to an auth on a out of range block? marshmellow EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); - if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate (0x%02x) on out of range block: %d (0x%02x), nacking",receivedCmd_dec[0],receivedCmd_dec[1],receivedCmd_dec[1]); + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Reader tried to operate (0x%02x) on out of range block: %d (0x%02x), nacking", receivedCmd_dec[0], receivedCmd_dec[1], receivedCmd_dec[1]); break; } - cardAUTHSC = receivedCmd_dec[1] / 4; // received block num + cardAUTHSC = BlockToSector(receivedCmd_dec[1]); // received block num cardAUTHKEY = receivedCmd_dec[0] & 0x01; crypto1_destroy(pcs);//Added by martin crypto1_create(pcs, emlGetKey(cardAUTHSC, cardAUTHKEY)); if (!encrypted_data) { // first authentication - if (MF_DBGLEVEL >= 4) Dbprintf("Reader authenticating for block %d (0x%02x) with key %d",receivedCmd_dec[1], receivedCmd_dec[1], cardAUTHKEY); - crypto1_word(pcs, cuid ^ nonce, 0);//Update crypto state - num_to_bytes(nonce, 4, rAUTH_AT); // Send nonce + crypto1_word(pcs, cuid ^ nonce, 0); // Update crypto state + num_to_bytes(nonce, 4, response); // Send unencrypted nonce + EmSendCmd(response, sizeof(nonce)); + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Reader authenticating for block %d (0x%02x) with key %d", receivedCmd_dec[1], receivedCmd_dec[1], cardAUTHKEY); } else { // nested authentication - if (MF_DBGLEVEL >= 4) Dbprintf("Reader doing nested authentication for block %d (0x%02x) with key %d", receivedCmd_dec[1], receivedCmd_dec[1], cardAUTHKEY); - ans = nonce ^ crypto1_word(pcs, cuid ^ nonce, 0); - num_to_bytes(ans, 4, rAUTH_AT); + num_to_bytes(nonce, sizeof(nonce), response); + uint8_t pcs_in[4] = {0}; + num_to_bytes(cuid ^ nonce, sizeof(nonce), pcs_in); + mf_crypto1_encryptEx(pcs, response, pcs_in, sizeof(nonce), response_par); + EmSendCmdPar(response, sizeof(nonce), response_par); // send encrypted nonce + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Reader doing nested authentication for block %d (0x%02x) with key %d", receivedCmd_dec[1], receivedCmd_dec[1], cardAUTHKEY); } - EmSendCmd(rAUTH_AT, sizeof(rAUTH_AT)); cardSTATE = MFEMUL_AUTH1; break; } - if (!encrypted_data) { // all other commands must be encrypted (authenticated) + + // halt can be sent encrypted or in clear + if (receivedCmd_dec[0] == ISO14443A_CMD_HALT && receivedCmd_dec[1] == 0x00) { + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("--> HALTED."); + cardSTATE = MFEMUL_HALTED; break; } + if(receivedCmd_dec[0] == ISO14443A_CMD_READBLOCK || receivedCmd_dec[0] == ISO14443A_CMD_WRITEBLOCK || receivedCmd_dec[0] == MIFARE_CMD_INC || receivedCmd_dec[0] == MIFARE_CMD_DEC || receivedCmd_dec[0] == MIFARE_CMD_RESTORE || receivedCmd_dec[0] == MIFARE_CMD_TRANSFER) { - if (receivedCmd_dec[1] >= 16 * 4) { + if (receivedCmd_dec[1] >= num_blocks) { EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); - if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate (0x%02x) on out of range block: %d (0x%02x), nacking",receivedCmd_dec[0],receivedCmd_dec[1],receivedCmd_dec[1]); + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Reader tried to operate (0x%02x) on out of range block: %d (0x%02x), nacking",receivedCmd_dec[0],receivedCmd_dec[1],receivedCmd_dec[1]); break; } - if (receivedCmd_dec[1] / 4 != cardAUTHSC) { + if (BlockToSector(receivedCmd_dec[1]) != cardAUTHSC) { EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); - if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate (0x%02x) on block (0x%02x) not authenticated for (0x%02x), nacking",receivedCmd_dec[0],receivedCmd_dec[1],cardAUTHSC); + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Reader tried to operate (0x%02x) on block (0x%02x) not authenticated for (0x%02x), nacking",receivedCmd_dec[0],receivedCmd_dec[1],cardAUTHSC); break; } } + if (receivedCmd_dec[0] == ISO14443A_CMD_READBLOCK) { uint8_t blockNo = receivedCmd_dec[1]; - if (MF_DBGLEVEL >= 4) { - Dbprintf("Reader reading block %d (0x%02x)", blockNo, blockNo); - } emlGetMem(response, blockNo, 1); if (IsSectorTrailer(blockNo)) { - memset(response, 0x00, 6); // keyA can never be read + memset(response, 0x00, 6); // keyA can never be read if (!IsAccessAllowed(blockNo, cardAUTHKEY, AC_KEYB_READ)) { - memset(response+10, 0x00, 6); // keyB cannot be read + memset(response+10, 0x00, 6); // keyB cannot be read } if (!IsAccessAllowed(blockNo, cardAUTHKEY, AC_AC_READ)) { - memset(response+6, 0x00, 4); // AC bits cannot be read + memset(response+6, 0x00, 4); // AC bits cannot be read } } else { if (!IsAccessAllowed(blockNo, cardAUTHKEY, AC_DATA_READ)) { - memset(response, 0x00, 16); // datablock cannot be read + memset(response, 0x00, 16); // datablock cannot be read } } AppendCrc14443a(response, 16); mf_crypto1_encrypt(pcs, response, 18, response_par); EmSendCmdPar(response, 18, response_par); + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) { + Dbprintf("Reader reading block %d (0x%02x)", blockNo, blockNo); + } numReads++; if(exitAfterNReads > 0 && numReads == exitAfterNReads) { Dbprintf("%d reads done, exiting", numReads); @@ -525,23 +592,33 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * } break; } + if (receivedCmd_dec[0] == ISO14443A_CMD_WRITEBLOCK) { uint8_t blockNo = receivedCmd_dec[1]; - if (MF_DBGLEVEL >= 4) Dbprintf("RECV 0xA0 write block %d (%02x)", blockNo, blockNo); EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("RECV 0xA0 write block %d (%02x)", blockNo, blockNo); cardWRBL = blockNo; cardSTATE = MFEMUL_WRITEBL2; break; } + if (receivedCmd_dec[0] == MIFARE_CMD_INC || receivedCmd_dec[0] == MIFARE_CMD_DEC || receivedCmd_dec[0] == MIFARE_CMD_RESTORE) { uint8_t blockNo = receivedCmd_dec[1]; - if (MF_DBGLEVEL >= 4) Dbprintf("RECV 0x%02x inc(0xC1)/dec(0xC0)/restore(0xC2) block %d (%02x)",receivedCmd_dec[0], blockNo, blockNo); if (emlCheckValBl(blockNo)) { - if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate on block, but emlCheckValBl failed, nacking"); EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) { + Dbprintf("RECV 0x%02x inc(0xC1)/dec(0xC0)/restore(0xC2) block %d (%02x)",receivedCmd_dec[0], blockNo, blockNo); + } + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Reader tried to operate on block, but emlCheckValBl failed, nacking"); break; } EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) { + Dbprintf("RECV 0x%02x inc(0xC1)/dec(0xC0)/restore(0xC2) block %d (%02x)",receivedCmd_dec[0], blockNo, blockNo); + } cardWRBL = blockNo; if (receivedCmd_dec[0] == MIFARE_CMD_INC) cardSTATE = MFEMUL_INTREG_INC; @@ -551,31 +628,29 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * cardSTATE = MFEMUL_INTREG_REST; break; } + if (receivedCmd_dec[0] == MIFARE_CMD_TRANSFER) { uint8_t blockNo = receivedCmd_dec[1]; - if (MF_DBGLEVEL >= 4) Dbprintf("RECV 0x%02x transfer block %d (%02x)",receivedCmd_dec[0], blockNo, blockNo); if (emlSetValBl(cardINTREG, cardINTBLOCK, receivedCmd_dec[1])) EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); else EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("RECV 0x%02x transfer block %d (%02x)",receivedCmd_dec[0], blockNo, blockNo); break; } - // halt - if (receivedCmd_dec[0] == ISO14443A_CMD_HALT && receivedCmd_dec[1] == 0x00) { - if (MF_DBGLEVEL >= 4) Dbprintf("--> HALTED."); - LED_B_OFF(); - LED_C_OFF(); - cardSTATE = MFEMUL_HALTED; - break; - } + // command not allowed - if (MF_DBGLEVEL >= 4) Dbprintf("Received command not allowed, nacking"); EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Received command not allowed, nacking"); + cardSTATE = MFEMUL_IDLE; break; } + case MFEMUL_AUTH1:{ if (receivedCmd_len != 8) { - cardSTATE_TO_IDLE(); + cardSTATE = MFEMUL_IDLE; break; } @@ -590,7 +665,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * if (ar_nr_collected[i+mM] < 2) { // if we haven't already collected 2 nonces for this sector if (ar_nr_resp[ar_nr_collected[i+mM]].ar != ar) { - // Avoid duplicates... probably not necessary, ar should vary. + // Avoid duplicates... probably not necessary, ar should vary. if (ar_nr_collected[i+mM]==0) { // first nonce collect ar_nr_resp[i+mM].cuid = cuid; @@ -618,7 +693,7 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * if ( nonce2_count == nonce1_count ) { // done collecting std test switch to moebius // first finish incrementing last sample - ar_nr_collected[i+mM]++; + ar_nr_collected[i+mM]++; // switch to moebius collection gettingMoebius = true; mM = ATTACK_KEY_COUNT; @@ -650,25 +725,28 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * // test if auth OK if (cardRr != prng_successor(nonce, 64)){ - if (MF_DBGLEVEL >= 2) Dbprintf("AUTH FAILED for sector %d with key %c. cardRr=%08x, succ=%08x", + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("AUTH FAILED for sector %d with key %c. cardRr=%08x, succ=%08x", cardAUTHSC, cardAUTHKEY == AUTHKEYA ? 'A' : 'B', cardRr, prng_successor(nonce, 64)); // Shouldn't we respond anything here? // Right now, we don't nack or anything, which causes the // reader to do a WUPA after a while. /Martin // -- which is the correct response. /piwi - cardAUTHKEY = AUTHKEYNONE; // not authenticated - cardSTATE_TO_IDLE(); + cardAUTHKEY = AUTHKEYNONE; // not authenticated + cardSTATE = MFEMUL_IDLE; break; } - ans = prng_successor(nonce, 96) ^ crypto1_word(pcs, 0, 0); - num_to_bytes(ans, 4, rAUTH_AT); - EmSendCmd(rAUTH_AT, sizeof(rAUTH_AT)); - if (MF_DBGLEVEL >= 4) Dbprintf("AUTH COMPLETED for sector %d with key %c.", cardAUTHSC, cardAUTHKEY == AUTHKEYA ? 'A' : 'B'); - LED_C_ON(); + ans = prng_successor(nonce, 96); + num_to_bytes(ans, 4, response); + mf_crypto1_encrypt(pcs, response, 4, response_par); + EmSendCmdPar(response, 4, response_par); + FpgaDisableTracing(); + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("AUTH COMPLETED for sector %d with key %c.", cardAUTHSC, cardAUTHKEY == AUTHKEYA ? 'A' : 'B'); cardSTATE = MFEMUL_WORK; break; } + case MFEMUL_WRITEBL2:{ if (receivedCmd_len == 18) { mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, receivedCmd_dec); @@ -676,73 +754,80 @@ void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t * if (IsSectorTrailer(cardWRBL)) { emlGetMem(response, cardWRBL, 1); if (!IsAccessAllowed(cardWRBL, cardAUTHKEY, AC_KEYA_WRITE)) { - memcpy(receivedCmd_dec, response, 6); // don't change KeyA + memcpy(receivedCmd_dec, response, 6); // don't change KeyA } if (!IsAccessAllowed(cardWRBL, cardAUTHKEY, AC_KEYB_WRITE)) { - memcpy(receivedCmd_dec+10, response+10, 6); // don't change KeyA + memcpy(receivedCmd_dec+10, response+10, 6); // don't change KeyA } if (!IsAccessAllowed(cardWRBL, cardAUTHKEY, AC_AC_WRITE)) { - memcpy(receivedCmd_dec+6, response+6, 4); // don't change AC bits + memcpy(receivedCmd_dec+6, response+6, 4); // don't change AC bits } } else { if (!IsAccessAllowed(cardWRBL, cardAUTHKEY, AC_DATA_WRITE)) { - memcpy(receivedCmd_dec, response, 16); // don't change anything + memcpy(receivedCmd_dec, response, 16); // don't change anything } } emlSetMem(receivedCmd_dec, cardWRBL, 1); - EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); // always ACK? + EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); // always ACK? cardSTATE = MFEMUL_WORK; break; } } - cardSTATE_TO_IDLE(); + cardSTATE = MFEMUL_IDLE; break; } + case MFEMUL_INTREG_INC:{ if (receivedCmd_len == 6) { mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, (uint8_t*)&ans); if (emlGetValBl(&cardINTREG, &cardINTBLOCK, cardWRBL)) { EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); - cardSTATE_TO_IDLE(); + cardSTATE = MFEMUL_IDLE; break; } cardINTREG = cardINTREG + ans; + cardSTATE = MFEMUL_WORK; } - cardSTATE = MFEMUL_WORK; break; } + case MFEMUL_INTREG_DEC:{ if (receivedCmd_len == 6) { mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, (uint8_t*)&ans); if (emlGetValBl(&cardINTREG, &cardINTBLOCK, cardWRBL)) { EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); - cardSTATE_TO_IDLE(); + cardSTATE = MFEMUL_IDLE; break; } + cardINTREG = cardINTREG - ans; + cardSTATE = MFEMUL_WORK; } - cardINTREG = cardINTREG - ans; - cardSTATE = MFEMUL_WORK; break; } + case MFEMUL_INTREG_REST:{ mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, (uint8_t*)&ans); if (emlGetValBl(&cardINTREG, &cardINTBLOCK, cardWRBL)) { EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); - cardSTATE_TO_IDLE(); + cardSTATE = MFEMUL_IDLE; break; } cardSTATE = MFEMUL_WORK; break; } - } + + } // end of switch + + FpgaDisableTracing(); button_pushed = BUTTON_PRESS(); - } + + } // end of while FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); - if(flags & FLAG_NR_AR_ATTACK && MF_DBGLEVEL >= 1) { - for ( uint8_t i = 0; i < ATTACK_KEY_COUNT; i++) { + if(flags & FLAG_NR_AR_ATTACK && MF_DBGLEVEL >= MF_DBG_INFO) { + for ( uint8_t i = 0; i < ATTACK_KEY_COUNT; i++) { if (ar_nr_collected[i] == 2) { Dbprintf("Collected two pairs of AR/NR which can be used to extract %s from reader for sector %d:", (i= 1) Dbprintf("Emulator stopped. Tracing: %d trace length: %d ", get_tracing(), BigBuf_get_traceLen()); + if (MF_DBGLEVEL >= MF_DBG_INFO) Dbprintf("Emulator stopped. Tracing: %d trace length: %d ", get_tracing(), BigBuf_get_traceLen()); if(flags & FLAG_INTERACTIVE) { // Interactive mode flag, means we need to send ACK //Send the collected ar_nr in the response - cmd_send(CMD_ACK,CMD_SIMULATE_MIFARE_CARD,button_pushed,0,&ar_nr_resp,sizeof(ar_nr_resp)); + cmd_send(CMD_ACK, CMD_SIMULATE_MIFARE_CARD, button_pushed, 0, &ar_nr_resp, sizeof(ar_nr_resp)); } + + LED_A_OFF(); } diff --git a/armsrc/mifaresim.h b/armsrc/mifaresim.h index 1e17a882..8f089b85 100644 --- a/armsrc/mifaresim.h +++ b/armsrc/mifaresim.h @@ -15,6 +15,6 @@ #include -extern void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *datain); +extern void MifareSim(uint8_t flags, uint8_t exitAfterNReads, uint8_t cardsize, uint8_t *datain); #endif diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index ab04aee4..36e29721 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -23,13 +23,13 @@ #include "crapto1/crapto1.h" #include "mbedtls/des.h" -int MF_DBGLEVEL = MF_DBG_ALL; +int MF_DBGLEVEL = MF_DBG_INFO; // crypto1 helpers void mf_crypto1_decryptEx(struct Crypto1State *pcs, uint8_t *data_in, int len, uint8_t *data_out){ - uint8_t bt = 0; + uint8_t bt = 0; int i; - + if (len != 1) { for (i = 0; i < len; i++) data_out[i] = crypto1_byte(pcs, 0x00, 0) ^ data_in[i]; @@ -37,7 +37,7 @@ void mf_crypto1_decryptEx(struct Crypto1State *pcs, uint8_t *data_in, int len, u bt = 0; for (i = 0; i < 4; i++) bt |= (crypto1_bit(pcs, 0, 0) ^ BIT(data_in[0], i)) << i; - + data_out[0] = bt; } return; @@ -47,28 +47,32 @@ void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len){ mf_crypto1_decryptEx(pcs, data, len, data); } -void mf_crypto1_encrypt(struct Crypto1State *pcs, uint8_t *data, uint16_t len, uint8_t *par) { +void mf_crypto1_encryptEx(struct Crypto1State *pcs, uint8_t *data, uint8_t *in, uint16_t len, uint8_t *par) { uint8_t bt = 0; int i; par[0] = 0; - + for (i = 0; i < len; i++) { bt = data[i]; - data[i] = crypto1_byte(pcs, 0x00, 0) ^ data[i]; - if((i&0x0007) == 0) + data[i] = crypto1_byte(pcs, in==NULL?0x00:in[i], 0) ^ data[i]; + if((i&0x0007) == 0) par[i>>3] = 0; par[i>>3] |= (((filter(pcs->odd) ^ oddparity8(bt)) & 0x01)<<(7-(i&0x0007))); - } + } return; } +void mf_crypto1_encrypt(struct Crypto1State *pcs, uint8_t *data, uint16_t len, uint8_t *par) { + mf_crypto1_encryptEx(pcs, data, NULL, len, par); +} + uint8_t mf_crypto1_encrypt4bit(struct Crypto1State *pcs, uint8_t data) { uint8_t bt = 0; int i; for (i = 0; i < 4; i++) bt |= (crypto1_bit(pcs, 0, 0) ^ BIT(data, i)) << i; - + return bt; } @@ -94,20 +98,20 @@ int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, { uint8_t dcmd[4], ecmd[4]; uint16_t pos, res; - uint8_t par[1]; // 1 Byte parity is enough here + uint8_t par[1]; // 1 Byte parity is enough here dcmd[0] = cmd; dcmd[1] = data; AppendCrc14443a(dcmd, 2); - + memcpy(ecmd, dcmd, sizeof(dcmd)); - + if (crypted) { par[0] = 0; for (pos = 0; pos < 4; pos++) { ecmd[pos] = crypto1_byte(pcs, 0x00, 0) ^ dcmd[pos]; par[0] |= (((filter(pcs->odd) ^ oddparity8(dcmd[pos])) & 0x01) << (7-pos)); - } + } ReaderTransmitPar(ecmd, sizeof(ecmd), par, timing); @@ -116,17 +120,17 @@ int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, } int len = ReaderReceive(answer, par); - + if (answer_parity) *answer_parity = par[0]; - + if (crypted == CRYPT_ALL) { if (len == 1) { res = 0; for (pos = 0; pos < 4; pos++) res |= (crypto1_bit(pcs, 0, 0) ^ BIT(answer[0], pos)) << pos; - + answer[0] = res; - + } else { for (pos = 0; pos < len; pos++) { @@ -134,41 +138,41 @@ int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, } } } - + return len; } // mifare classic commands -int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested) +int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested) { return mifare_classic_authex(pcs, uid, blockNo, keyType, ui64Key, isNested, NULL, NULL); } -int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *timing) +int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *timing) { // variables - int len; + int len; uint32_t pos; uint8_t tmp4[4]; uint8_t par[1] = {0x00}; byte_t nr[4]; uint32_t nt, ntpp; // Supplied tag nonce - + uint8_t mf_nr_ar[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; - + // Transmit MIFARE_CLASSIC_AUTH len = mifare_sendcmd_short(pcs, isNested, 0x60 + (keyType & 0x01), blockNo, receivedAnswer, receivedAnswerPar, timing); - if (MF_DBGLEVEL >= 4) Dbprintf("rand tag nonce len: %x", len); + if (MF_DBGLEVEL >= 4) Dbprintf("rand tag nonce len: %x", len); if (len != 4) return 1; - + // "random" reader nonce: nr[0] = 0x55; nr[1] = 0x41; nr[2] = 0x49; - nr[3] = 0x92; - + nr[3] = 0x92; + // Save the tag nonce (nt) nt = bytes_to_num(receivedAnswer, 4); @@ -180,7 +184,7 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN crypto1_create(pcs, ui64Key); if (isNested == AUTH_NESTED) { - // decrypt nt with help of new key + // decrypt nt with help of new key nt = crypto1_word(pcs, nt ^ uid, 1) ^ nt; } else { // Load (plain) uid^nt into the cipher @@ -189,8 +193,8 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN // some statistic if (!ntptr && (MF_DBGLEVEL >= 3)) - Dbprintf("auth uid: %08x nt: %08x", uid, nt); - + Dbprintf("auth uid: %08x nt: %08x", uid, nt); + // save Nt if (ntptr) *ntptr = nt; @@ -201,8 +205,8 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN { mf_nr_ar[pos] = crypto1_byte(pcs, nr[pos], 0) ^ nr[pos]; par[0] |= (((filter(pcs->odd) ^ oddparity8(nr[pos])) & 0x01) << (7-pos)); - } - + } + // Skip 32 bits in pseudo random generator nt = prng_successor(nt,32); @@ -212,8 +216,8 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN nt = prng_successor(nt,8); mf_nr_ar[pos] = crypto1_byte(pcs,0x00,0) ^ (nt & 0xff); par[0] |= (((filter(pcs->odd) ^ oddparity8(nt)) & 0x01) << (7-pos)); - } - + } + // Transmit reader nonce and reader answer ReaderTransmitPar(mf_nr_ar, sizeof(mf_nr_ar), par, NULL); @@ -221,48 +225,48 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN len = ReaderReceive(receivedAnswer, receivedAnswerPar); if (!len) { - if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Card timeout."); + if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Card timeout."); return 2; } - + memcpy(tmp4, receivedAnswer, 4); ntpp = prng_successor(nt, 32) ^ crypto1_word(pcs, 0,0); - + if (ntpp != bytes_to_num(tmp4, 4)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Error card response."); + if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Error card response."); return 3; } return 0; } -int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData) +int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData) { // variables - int len; - uint8_t bt[2]; - + int len; + uint8_t bt[2]; + uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; - + // command MIFARE_CLASSIC_READBLOCK len = mifare_sendcmd_short(pcs, 1, 0x30, blockNo, receivedAnswer, receivedAnswerPar, NULL); if (len == 1) { - if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); return 1; } if (len != 18) { - if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: card timeout. len: %x", len); + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: card timeout. len: %x", len); return 2; } memcpy(bt, receivedAnswer + 16, 2); AppendCrc14443a(receivedAnswer, 16); if (bt[0] != receivedAnswer[16] || bt[1] != receivedAnswer[17]) { - if (MF_DBGLEVEL >= 1) Dbprintf("Cmd CRC response error."); + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd CRC response error."); return 3; } - + memcpy(blockData, receivedAnswer, 16); return 0; } @@ -277,7 +281,7 @@ int mifare_ul_ev1_auth(uint8_t *keybytes, uint8_t *pack){ memcpy(key, keybytes, 4); if (MF_DBGLEVEL >= MF_DBG_EXTENDED) - Dbprintf("EV1 Auth : %02x%02x%02x%02x", key[0], key[1], key[2], key[3]); + Dbprintf("EV1 Auth : %02x%02x%02x%02x", key[0], key[1], key[2], key[3]); len = mifare_sendcmd(0x1B, key, sizeof(key), resp, respPar, NULL); //len = mifare_sendcmd_short_mfuev1auth(NULL, 0, 0x1B, key, resp, respPar, NULL); if (len != 4) { @@ -322,12 +326,12 @@ int mifare_ultra_auth(uint8_t *keybytes){ // decrypt nonce. // tdes_2key_dec(random_b, enc_random_b, sizeof(random_b), key, IV ); mbedtls_des3_set2key_dec(&ctx, key); - mbedtls_des3_crypt_cbc(&ctx // des3_context - , MBEDTLS_DES_DECRYPT // int mode - , sizeof(random_b) // length - , IV // iv[8] - , enc_random_b // input - , random_b // output + mbedtls_des3_crypt_cbc(&ctx // des3_context + , MBEDTLS_DES_DECRYPT // int mode + , sizeof(random_b) // length + , IV // iv[8] + , enc_random_b // input + , random_b // output ); rol(random_b,8); @@ -351,12 +355,12 @@ int mifare_ultra_auth(uint8_t *keybytes){ // encrypt out, in, length, key, iv //tdes_2key_enc(rnd_ab, rnd_ab, sizeof(rnd_ab), key, enc_random_b); mbedtls_des3_set2key_enc(&ctx, key); - mbedtls_des3_crypt_cbc(&ctx // des3_context - , MBEDTLS_DES_ENCRYPT // int mode - , sizeof(rnd_ab) // length - , enc_random_b // iv[8] - , rnd_ab // input - , rnd_ab // output + mbedtls_des3_crypt_cbc(&ctx // des3_context + , MBEDTLS_DES_ENCRYPT // int mode + , sizeof(rnd_ab) // length + , enc_random_b // iv[8] + , rnd_ab // input + , rnd_ab // output ); //len = mifare_sendcmd_short_mfucauth(NULL, 1, 0xAF, rnd_ab, resp, respPar, NULL); @@ -370,15 +374,15 @@ int mifare_ultra_auth(uint8_t *keybytes){ uint8_t resp_random_a[8] = { 0,0,0,0,0,0,0,0 }; memcpy(enc_resp, resp+1, 8); - // decrypt out, in, length, key, iv + // decrypt out, in, length, key, iv // tdes_2key_dec(resp_random_a, enc_resp, 8, key, enc_random_b); mbedtls_des3_set2key_dec(&ctx, key); - mbedtls_des3_crypt_cbc(&ctx // des3_context - , MBEDTLS_DES_DECRYPT // int mode - , 8 // length - , enc_random_b // iv[8] - , enc_resp // input - , resp_random_a // output + mbedtls_des3_crypt_cbc(&ctx // des3_context + , MBEDTLS_DES_DECRYPT // int mode + , 8 // length + , enc_random_b // iv[8] + , enc_resp // input + , resp_random_a // output ); if ( memcmp(resp_random_a, random_a, 8) != 0 ) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("failed authentication"); @@ -386,7 +390,7 @@ int mifare_ultra_auth(uint8_t *keybytes){ } if (MF_DBGLEVEL >= MF_DBG_EXTENDED) { - Dbprintf("e_AB: %02x %02x %02x %02x %02x %02x %02x %02x", + Dbprintf("e_AB: %02x %02x %02x %02x %02x %02x %02x %02x", rnd_ab[0],rnd_ab[1],rnd_ab[2],rnd_ab[3], rnd_ab[4],rnd_ab[5],rnd_ab[6],rnd_ab[7]); @@ -410,7 +414,7 @@ int mifare_ultra_auth(uint8_t *keybytes){ int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData) { uint16_t len; - uint8_t bt[2]; + uint8_t bt[2]; uint8_t receivedAnswer[MAX_FRAME_SIZE]; uint8_t receivedAnswerPar[MAX_PARITY_SIZE]; uint8_t retries; @@ -451,55 +455,55 @@ int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData) return 0; } -int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData) +int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData) { // variables - uint16_t len, i; + uint16_t len, i; uint32_t pos; - uint8_t par[3] = {0}; // enough for 18 Bytes to send + uint8_t par[3] = {0}; // enough for 18 Bytes to send byte_t res; - + uint8_t d_block[18], d_block_enc[18]; uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; - + // command MIFARE_CLASSIC_WRITEBLOCK len = mifare_sendcmd_short(pcs, 1, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL); if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK - if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); return 1; } - + memcpy(d_block, blockData, 16); AppendCrc14443a(d_block, 16); - + // crypto for (pos = 0; pos < 18; pos++) { d_block_enc[pos] = crypto1_byte(pcs, 0x00, 0) ^ d_block[pos]; par[pos>>3] |= (((filter(pcs->odd) ^ oddparity8(d_block[pos])) & 0x01) << (7 - (pos&0x0007))); - } + } ReaderTransmitPar(d_block_enc, sizeof(d_block_enc), par, NULL); // Receive the response - len = ReaderReceive(receivedAnswer, receivedAnswerPar); + len = ReaderReceive(receivedAnswer, receivedAnswerPar); res = 0; for (i = 0; i < 4; i++) res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], i)) << i; if ((len != 1) || (res != 0x0A)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Cmd send data2 Error: %02x", res); + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd send data2 Error: %02x", res); return 2; } - + return 0; } /* // command not needed, but left for future testing -int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData) +int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData) { uint16_t len; uint8_t par[3] = {0}; // enough for 18 parity bits @@ -553,16 +557,16 @@ int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData) return 0; } -int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid) +int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid) { - uint16_t len; + uint16_t len; uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; len = mifare_sendcmd_short(pcs, pcs == NULL ? false:true, 0x50, 0x00, receivedAnswer, receivedAnswerPar, NULL); if (len != 0) { if (MF_DBGLEVEL >= MF_DBG_ERROR) - Dbprintf("halt error. response len: %x", len); + Dbprintf("halt error. response len: %x", len); return 1; } @@ -574,7 +578,7 @@ int mifare_ultra_halt() uint16_t len; uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; - + len = mifare_sendcmd_short(NULL, true, 0x50, 0x00, receivedAnswer, receivedAnswerPar, NULL); if (len != 0) { if (MF_DBGLEVEL >= MF_DBG_ERROR) @@ -587,21 +591,21 @@ int mifare_ultra_halt() // Mifare Memory Structure: up to 32 Sectors with 4 blocks each (1k and 2k cards), // plus evtl. 8 sectors with 16 blocks each (4k cards) -uint8_t NumBlocksPerSector(uint8_t sectorNo) +uint8_t NumBlocksPerSector(uint8_t sectorNo) { - if (sectorNo < 32) + if (sectorNo < 32) return 4; else return 16; } -uint8_t FirstBlockOfSector(uint8_t sectorNo) +uint8_t FirstBlockOfSector(uint8_t sectorNo) { if (sectorNo < 32) return sectorNo * 4; else return 32*4 + (sectorNo - 32) * 16; - + } uint8_t SectorTrailer(uint8_t blockNo) @@ -644,7 +648,7 @@ int emlCheckValBl(int blockNum) { (data[3] != (data[7] ^ 0xff)) || (data[3] != data[11]) || (data[12] != (data[13] ^ 0xff)) || (data[12] != data[14]) || (data[12] != (data[15] ^ 0xff)) - ) + ) return 1; return 0; } @@ -652,11 +656,11 @@ int emlCheckValBl(int blockNum) { int emlGetValBl(uint32_t *blReg, uint8_t *blBlock, int blockNum) { uint8_t* emCARD = BigBuf_get_EM_addr(); uint8_t* data = emCARD + blockNum * 16; - + if (emlCheckValBl(blockNum)) { return 1; } - + memcpy(blReg, data, 4); *blBlock = data[12]; return 0; @@ -665,41 +669,41 @@ int emlGetValBl(uint32_t *blReg, uint8_t *blBlock, int blockNum) { int emlSetValBl(uint32_t blReg, uint8_t blBlock, int blockNum) { uint8_t* emCARD = BigBuf_get_EM_addr(); uint8_t* data = emCARD + blockNum * 16; - + memcpy(data + 0, &blReg, 4); memcpy(data + 8, &blReg, 4); blReg = blReg ^ 0xffffffff; memcpy(data + 4, &blReg, 4); - + data[12] = blBlock; data[13] = blBlock ^ 0xff; data[14] = blBlock; data[15] = blBlock ^ 0xff; - + return 0; } uint64_t emlGetKey(int sectorNum, int keyType) { uint8_t key[6]; uint8_t* emCARD = BigBuf_get_EM_addr(); - + memcpy(key, emCARD + 16 * (FirstBlockOfSector(sectorNum) + NumBlocksPerSector(sectorNum) - 1) + keyType * 10, 6); return bytes_to_num(key, 6); } void emlClearMem(void) { int b; - + const uint8_t trailer[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x80, 0x69, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; const uint8_t uid[] = {0xe6, 0x84, 0x87, 0xf3, 0x16, 0x88, 0x04, 0x00, 0x46, 0x8e, 0x45, 0x55, 0x4d, 0x70, 0x41, 0x04}; uint8_t* emCARD = BigBuf_get_EM_addr(); - + memset(emCARD, 0, CARD_MEMORY_SIZE); - + // fill sectors trailer data for(b = 3; b < 256; b<127?(b+=4):(b+=16)) { emlSetMem((uint8_t *)trailer, b , 1); - } + } // uid emlSetMem((uint8_t *)uid, 0, 1); @@ -710,35 +714,35 @@ void emlClearMem(void) { // Mifare desfire commands int mifare_sendcmd_special(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t* data, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing) { - uint8_t dcmd[5] = {0x00}; - dcmd[0] = cmd; - memcpy(dcmd+1,data,2); + uint8_t dcmd[5] = {0x00}; + dcmd[0] = cmd; + memcpy(dcmd+1,data,2); AppendCrc14443a(dcmd, 3); - + ReaderTransmit(dcmd, sizeof(dcmd), NULL); int len = ReaderReceive(answer, answer_parity); if(!len) { - if (MF_DBGLEVEL >= MF_DBG_ERROR) + if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Authentication failed. Card timeout."); return 1; - } + } return len; } int mifare_sendcmd_special2(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t* data, uint8_t* answer,uint8_t *answer_parity, uint32_t *timing) { - uint8_t dcmd[20] = {0x00}; - dcmd[0] = cmd; - memcpy(dcmd+1,data,17); + uint8_t dcmd[20] = {0x00}; + dcmd[0] = cmd; + memcpy(dcmd+1,data,17); AppendCrc14443a(dcmd, 18); ReaderTransmit(dcmd, sizeof(dcmd), NULL); int len = ReaderReceive(answer, answer_parity); if(!len){ - if (MF_DBGLEVEL >= MF_DBG_ERROR) + if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Authentication failed. Card timeout."); return 1; - } + } return len; } @@ -749,23 +753,23 @@ int mifare_desfire_des_auth1(uint32_t uid, uint8_t *blockData){ uint8_t data[2]={0x0a, 0x00}; uint8_t receivedAnswer[MAX_FRAME_SIZE]; uint8_t receivedAnswerPar[MAX_PARITY_SIZE]; - + len = mifare_sendcmd_special(NULL, 1, 0x02, data, receivedAnswer,receivedAnswerPar,NULL); if (len == 1) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); return 1; } - + if (len == 12) { - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) { + if (MF_DBGLEVEL >= MF_DBG_EXTENDED) { Dbprintf("Auth1 Resp: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", receivedAnswer[0],receivedAnswer[1],receivedAnswer[2],receivedAnswer[3],receivedAnswer[4], receivedAnswer[5],receivedAnswer[6],receivedAnswer[7],receivedAnswer[8],receivedAnswer[9], receivedAnswer[10],receivedAnswer[11]); } memcpy(blockData, receivedAnswer, 12); - return 0; + return 0; } return 1; } @@ -776,18 +780,18 @@ int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData){ uint8_t data[17] = {0x00}; data[0] = 0xAF; memcpy(data+1,key,16); - + uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; - + len = mifare_sendcmd_special2(NULL, 1, 0x03, data, receivedAnswer, receivedAnswerPar ,NULL); - + if ((receivedAnswer[0] == 0x03) && (receivedAnswer[1] == 0xae)) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Auth Error: %02x %02x", receivedAnswer[0], receivedAnswer[1]); return 1; } - + if (len == 12){ if (MF_DBGLEVEL >= MF_DBG_EXTENDED) { Dbprintf("Auth2 Resp: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", @@ -816,7 +820,7 @@ int MifareChkBlockKey(uint8_t *uid, uint32_t *cuid, uint8_t *cascade_levels, uin if (*cascade_levels == 0) { // need a full select cycle to get the uid first iso14a_card_select_t card_info; if(!iso14443a_select_card(uid, &card_info, cuid, true, 0, true)) { - if (debugLevel >= 1) Dbprintf("ChkKeys: Can't select card"); + if (debugLevel >= 1) Dbprintf("ChkKeys: Can't select card"); return 1; } switch (card_info.uidlen) { @@ -827,26 +831,26 @@ int MifareChkBlockKey(uint8_t *uid, uint32_t *cuid, uint8_t *cascade_levels, uin } } else { // no need for anticollision. We can directly select the card if(!iso14443a_select_card(uid, NULL, NULL, false, *cascade_levels, true)) { - if (debugLevel >= 1) Dbprintf("ChkKeys: Can't select card (UID) lvl=%d", *cascade_levels); + if (debugLevel >= 1) Dbprintf("ChkKeys: Can't select card (UID) lvl=%d", *cascade_levels); return 1; } } - + if(mifare_classic_auth(pcs, *cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) { -// SpinDelayUs(AUTHENTICATION_TIMEOUT); // it not needs because mifare_classic_auth have timeout from iso14a_set_timeout() +// SpinDelayUs(AUTHENTICATION_TIMEOUT); // it not needs because mifare_classic_auth have timeout from iso14a_set_timeout() return 2; } else { -/* // let it be here. it like halt command, but maybe it will work in some strange cases +/* // let it be here. it like halt command, but maybe it will work in some strange cases uint8_t dummy_answer = 0; ReaderTransmit(&dummy_answer, 1, NULL); - int timeout = GetCountSspClk() + AUTHENTICATION_TIMEOUT; + int timeout = GetCountSspClk() + AUTHENTICATION_TIMEOUT; // wait for the card to become ready again while(GetCountSspClk() < timeout) {}; */ // it needs after success authentication mifare_classic_halt(pcs, *cuid); } - + return 0; } @@ -861,14 +865,14 @@ int MifareChkBlockKeys(uint8_t *keys, uint8_t keyCount, uint8_t blockNo, uint8_t for (uint8_t i = 0; i < keyCount; i++) { // Allow button press / usb cmd to interrupt device - if (BUTTON_PRESS() && !usb_poll_validate_length()) { + if (BUTTON_PRESS() && !usb_poll_validate_length()) { Dbprintf("ChkKeys: Cancel operation. Exit..."); return -2; } ui64Key = bytes_to_num(keys + i * 6, 6); int res = MifareChkBlockKey(uid, &cuid, &cascade_levels, ui64Key, blockNo, keyType, debugLevel); - + // can't select if (res == 1) { retryCount++; @@ -879,10 +883,10 @@ int MifareChkBlockKeys(uint8_t *keys, uint8_t keyCount, uint8_t blockNo, uint8_t --i; // try the same key once again SpinDelay(20); -// Dbprintf("ChkKeys: block=%d key=%d. Try the same key once again...", blockNo, keyType); +// Dbprintf("ChkKeys: block=%d key=%d. Try the same key once again...", blockNo, keyType); continue; } - + // can't authenticate if (res == 2) { retryCount = 0; @@ -891,15 +895,15 @@ int MifareChkBlockKeys(uint8_t *keys, uint8_t keyCount, uint8_t blockNo, uint8_t return i + 1; } - + return 0; } // multisector multikey check int MifareMultisectorChk(uint8_t *keys, uint8_t keyCount, uint8_t SectorCount, uint8_t keyType, uint8_t debugLevel, TKeyIndex *keyIndex) { int res = 0; - -// int clk = GetCountSspClk(); + +// int clk = GetCountSspClk(); for(int sc = 0; sc < SectorCount; sc++){ WDT_HIT(); @@ -915,9 +919,9 @@ int MifareMultisectorChk(uint8_t *keys, uint8_t keyCount, uint8_t SectorCount, u } } while(--keyAB > 0); } - -// Dbprintf("%d %d", GetCountSspClk() - clk, (GetCountSspClk() - clk)/(SectorCount*keyCount*(keyType==2?2:1))); - + +// Dbprintf("%d %d", GetCountSspClk() - clk, (GetCountSspClk() - clk)/(SectorCount*keyCount*(keyType==2?2:1))); + return 0; } diff --git a/armsrc/mifareutil.h b/armsrc/mifareutil.h index b2912895..589f780b 100644 --- a/armsrc/mifareutil.h +++ b/armsrc/mifareutil.h @@ -34,11 +34,11 @@ #define MF_MINFIELDV 4000 // debug -// 0 - no debug messages 1 - error messages 2 - all messages 4 - extended debug mode -#define MF_DBG_NONE 0 -#define MF_DBG_ERROR 1 -#define MF_DBG_ALL 2 -#define MF_DBG_EXTENDED 4 +#define MF_DBG_NONE 0 // no messages +#define MF_DBG_ERROR 1 // errors only +#define MF_DBG_INFO 2 // errors + info messages +#define MF_DBG_DEBUG 3 // errors + info + debug messages +#define MF_DBG_EXTENDED 4 // errors + info + debug + breaking debug messages extern int MF_DBGLEVEL; @@ -71,6 +71,7 @@ int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData); void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *receivedCmd, int len); void mf_crypto1_decryptEx(struct Crypto1State *pcs, uint8_t *data_in, int len, uint8_t *data_out); void mf_crypto1_encrypt(struct Crypto1State *pcs, uint8_t *data, uint16_t len, uint8_t *par); +void mf_crypto1_encryptEx(struct Crypto1State *pcs, uint8_t *data, uint8_t *in, uint16_t len, uint8_t *par); uint8_t mf_crypto1_encrypt4bit(struct Crypto1State *pcs, uint8_t data); // Mifare memory structure diff --git a/client/cmdhflist.c b/client/cmdhflist.c index 1aa501e6..4499cd0d 100644 --- a/client/cmdhflist.c +++ b/client/cmdhflist.c @@ -937,7 +937,6 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui char line[16][110]; for (int j = 0; j < data_len && j/16 < 16; j++) { - uint8_t parityBits = parityBytes[j>>3]; if (protocol != ISO_14443B && protocol != ISO_15693 @@ -948,7 +947,6 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui } else { snprintf(line[j/16]+(( j % 16) * 4), 110, " %02x ", frame[j]); } - } if (markCRCBytes) { @@ -961,6 +959,13 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui } } + // mark short bytes (less than 8 Bit + Parity) + if (protocol == ISO_14443A || protocol == PROTO_MIFARE) { + if (duration < 128 * (9 * data_len)) { + line[(data_len-1)/16][((data_len-1)%16) * 4 + 3] = '\''; + } + } + if (data_len == 0) { sprintf(line[0]," "); } @@ -990,7 +995,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui int num_lines = MIN((data_len - 1)/16 + 1, 16); for (int j = 0; j < num_lines ; j++) { if (j == 0) { - PrintAndLog(" %10d | %10d | %s |%-64s | %s| %s", + PrintAndLog(" %10" PRIu32 " | %10" PRIu32 " | %s |%-64s | %s| %s", (timestamp - first_timestamp), (EndOfTransmissionTimestamp - first_timestamp), (isResponse ? "Tag" : "Rdr"), @@ -1004,7 +1009,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui (j == num_lines-1) ? explanation : ""); } } - + if (DecodeMifareData(frame, data_len, parityBytes, isResponse, mfData, &mfDataLen)) { memset(explanation, 0x00, sizeof(explanation)); if (!isResponse) { @@ -1222,7 +1227,7 @@ int CmdHFList(const char *Cmd) PrintAndLog("iso14443a - All times are in carrier periods (1/13.56Mhz)"); PrintAndLog("iClass - Timings are not as accurate"); PrintAndLog(""); - PrintAndLog(" Start | End | Src | Data (! denotes parity error) | CRC | Annotation |"); + PrintAndLog(" Start | End | Src | Data (! denotes parity error, ' denotes short bytes) | CRC | Annotation |"); PrintAndLog("------------|------------|-----|-----------------------------------------------------------------|-----|--------------------|"); ClearAuthData(); diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 1c006fbf..903e8575 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -254,14 +254,14 @@ uint8_t NumBlocksPerSector(uint8_t sectorNo) } static int ParamCardSizeSectors(const char c) { - int numBlocks = 16; + int numSectors = 16; switch (c) { - case '0' : numBlocks = 5; break; - case '2' : numBlocks = 32; break; - case '4' : numBlocks = 40; break; - default: numBlocks = 16; + case '0' : numSectors = 5; break; + case '2' : numSectors = 32; break; + case '4' : numSectors = 40; break; + default: numSectors = 16; } - return numBlocks; + return numSectors; } static int ParamCardSizeBlocks(const char c) { @@ -1421,11 +1421,12 @@ void readerAttack(nonces_t ar_resp[], bool setEmulatorMem, bool doStandardAttack }*/ } -int usage_hf14_mf1ksim(void) { - PrintAndLog("Usage: hf mf sim h u n i x"); +int usage_hf14_mfsim(void) { + PrintAndLog("Usage: hf mf sim [h] [*] [u ] [n ] [i] [x]"); PrintAndLog("options:"); - PrintAndLog(" h this help"); - PrintAndLog(" u (Optional) UID 4,7 or 10 bytes. If not specified, the UID 4B from emulator memory will be used"); + PrintAndLog(" h (Optional) this help"); + PrintAndLog(" card memory: 0 - MINI(320 bytes), 1 - 1K, 2 - 2K, 4 - 4K, - 1K"); + PrintAndLog(" u (Optional) UID 4 or 7 bytes. If not specified, the UID 4B from emulator memory will be used"); PrintAndLog(" n (Optional) Automatically exit simulation after blocks have been read by reader. 0 = infinite"); PrintAndLog(" i (Optional) Interactive, means that console will not be returned until simulation finishes or is aborted"); PrintAndLog(" x (Optional) Crack, performs the 'reader attack', nr/ar attack against a legitimate reader, fishes out the key(s)"); @@ -1434,21 +1435,20 @@ int usage_hf14_mf1ksim(void) { PrintAndLog(" r (Optional) Generate random nonces instead of sequential nonces. Standard reader attack won't work with this option, only moebius attack works."); PrintAndLog("samples:"); PrintAndLog(" hf mf sim u 0a0a0a0a"); + PrintAndLog(" hf mf sim *4"); PrintAndLog(" hf mf sim u 11223344556677"); - PrintAndLog(" hf mf sim u 112233445566778899AA"); PrintAndLog(" hf mf sim f uids.txt"); PrintAndLog(" hf mf sim u 0a0a0a0a e"); return 0; } -int CmdHF14AMf1kSim(const char *Cmd) { +int CmdHF14AMfSim(const char *Cmd) { UsbCommand resp; - uint8_t uid[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + uint8_t uid[7] = {0}; uint8_t exitAfterNReads = 0; uint8_t flags = 0; int uidlen = 0; - uint8_t pnr = 0; bool setEmulatorMem = false; bool attackFromFile = false; FILE *f; @@ -1459,9 +1459,21 @@ int CmdHF14AMf1kSim(const char *Cmd) { uint8_t cmdp = 0; bool errors = false; + uint8_t cardsize = '1'; while(param_getchar(Cmd, cmdp) != 0x00) { switch(param_getchar(Cmd, cmdp)) { + case '*': + cardsize = param_getchar(Cmd + 1, cmdp); + switch(cardsize) { + case '0': + case '1': + case '2': + case '4': break; + default: cardsize = '1'; + } + cmdp++; + break; case 'e': case 'E': setEmulatorMem = true; @@ -1485,7 +1497,7 @@ int CmdHF14AMf1kSim(const char *Cmd) { break; case 'h': case 'H': - return usage_hf14_mf1ksim(); + return usage_hf14_mfsim(); case 'i': case 'I': flags |= FLAG_INTERACTIVE; @@ -1493,7 +1505,7 @@ int CmdHF14AMf1kSim(const char *Cmd) { break; case 'n': case 'N': - exitAfterNReads = param_get8(Cmd, pnr+1); + exitAfterNReads = param_get8(Cmd, cmdp+1); cmdp += 2; break; case 'r': @@ -1505,10 +1517,9 @@ int CmdHF14AMf1kSim(const char *Cmd) { case 'U': param_gethex_ex(Cmd, cmdp+1, uid, &uidlen); switch(uidlen) { - case 20: flags = FLAG_10B_UID_IN_DATA; break; //not complete case 14: flags = FLAG_7B_UID_IN_DATA; break; case 8: flags = FLAG_4B_UID_IN_DATA; break; - default: return usage_hf14_mf1ksim(); + default: return usage_hf14_mfsim(); } cmdp += 2; break; @@ -1525,7 +1536,7 @@ int CmdHF14AMf1kSim(const char *Cmd) { if(errors) break; } //Validations - if(errors) return usage_hf14_mf1ksim(); + if(errors) return usage_hf14_mfsim(); //get uid from file if (attackFromFile) { @@ -1552,7 +1563,6 @@ int CmdHF14AMf1kSim(const char *Cmd) { uidlen = strlen(buf)-1; switch(uidlen) { - case 20: flags |= FLAG_10B_UID_IN_DATA; break; //not complete case 14: flags |= FLAG_7B_UID_IN_DATA; break; case 8: flags |= FLAG_4B_UID_IN_DATA; break; default: @@ -1565,18 +1575,22 @@ int CmdHF14AMf1kSim(const char *Cmd) { sscanf(&buf[i], "%02x", (unsigned int *)&uid[i / 2]); } - PrintAndLog("mf 1k sim uid: %s, numreads:%d, flags:%d (0x%02x) - press button to abort", - flags & FLAG_4B_UID_IN_DATA ? sprint_hex(uid,4): - flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): - flags & FLAG_10B_UID_IN_DATA ? sprint_hex(uid,10): "N/A" - , exitAfterNReads, flags, flags); + PrintAndLog("mf sim cardsize: %s, uid: %s, numreads:%d, flags:%d (0x%02x) - press button to abort", + cardsize == '0' ? "Mini" : + cardsize == '2' ? "2K" : + cardsize == '4' ? "4K" : "1K", + flags & FLAG_4B_UID_IN_DATA ? sprint_hex(uid,4): + flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): "N/A", + exitAfterNReads, + flags, + flags); - UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {flags, exitAfterNReads,0}}; + UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {flags, exitAfterNReads, cardsize}}; memcpy(c.d.asBytes, uid, sizeof(uid)); clearCommandBuffer(); SendCommand(&c); - while(! WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + while (! WaitForResponseTimeout(CMD_ACK,&resp,1500)) { //We're waiting only 1.5 s at a time, otherwise we get the // annoying message about "Waiting for a response... " } @@ -1593,22 +1607,27 @@ int CmdHF14AMf1kSim(const char *Cmd) { count++; } fclose(f); + } else { //not from file - PrintAndLog("mf 1k sim uid: %s, numreads:%d, flags:%d (0x%02x) ", - flags & FLAG_4B_UID_IN_DATA ? sprint_hex(uid,4): - flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): - flags & FLAG_10B_UID_IN_DATA ? sprint_hex(uid,10): "N/A" - , exitAfterNReads, flags, flags); + PrintAndLog("mf sim cardsize: %s, uid: %s, numreads:%d, flags:%d (0x%02x) ", + cardsize == '0' ? "Mini" : + cardsize == '2' ? "2K" : + cardsize == '4' ? "4K" : "1K", + flags & FLAG_4B_UID_IN_DATA ? sprint_hex(uid,4): + flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): "N/A", + exitAfterNReads, + flags, + flags); - UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {flags, exitAfterNReads,0}}; + UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {flags, exitAfterNReads, cardsize}}; memcpy(c.d.asBytes, uid, sizeof(uid)); clearCommandBuffer(); SendCommand(&c); if(flags & FLAG_INTERACTIVE) { PrintAndLog("Press pm3-button to abort simulation"); - while(! WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + while(! WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { //We're waiting only 1.5 s at a time, otherwise we get the // annoying message about "Waiting for a response... " } @@ -1745,7 +1764,7 @@ int CmdHF14AMfELoad(const char *Cmd) } } - len = param_getstr(Cmd,nameParamNo,filename,sizeof(filename)); + len = param_getstr(Cmd, nameParamNo, filename, sizeof(filename)); if (len > FILE_PATH_SIZE - 5) len = FILE_PATH_SIZE - 5; @@ -2925,8 +2944,8 @@ static command_t CommandTable[] = {"hardnested", CmdHF14AMfNestedHard, 0, "Nested attack for hardened Mifare cards"}, {"nested", CmdHF14AMfNested, 0, "Test nested authentication"}, {"sniff", CmdHF14AMfSniff, 0, "Sniff card-reader communication"}, - {"sim", CmdHF14AMf1kSim, 0, "Simulate MIFARE card"}, - {"eclr", CmdHF14AMfEClear, 0, "Clear simulator memory block"}, + {"sim", CmdHF14AMfSim, 0, "Simulate MIFARE card"}, + {"eclr", CmdHF14AMfEClear, 0, "Clear simulator memory"}, {"eget", CmdHF14AMfEGet, 0, "Get simulator memory block"}, {"eset", CmdHF14AMfESet, 0, "Set simulator memory block"}, {"eload", CmdHF14AMfELoad, 0, "Load from file emul dump"}, diff --git a/include/usb_cmd.h b/include/usb_cmd.h index ef282256..9ef929b9 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -226,12 +226,11 @@ typedef struct{ //Mifare simulation flags -#define FLAG_INTERACTIVE 0x01 -#define FLAG_4B_UID_IN_DATA 0x02 -#define FLAG_7B_UID_IN_DATA 0x04 -#define FLAG_10B_UID_IN_DATA 0x08 -#define FLAG_NR_AR_ATTACK 0x10 -#define FLAG_RANDOM_NONCE 0x20 +#define FLAG_INTERACTIVE (1<<0) +#define FLAG_4B_UID_IN_DATA (1<<1) +#define FLAG_7B_UID_IN_DATA (1<<2) +#define FLAG_NR_AR_ATTACK (1<<4) +#define FLAG_RANDOM_NONCE (1<<5) //Iclass reader flags From 131c44883c8ecc92910c09cff450b43b8c6b986c Mon Sep 17 00:00:00 2001 From: Fl0-0 Date: Fri, 19 Apr 2019 13:14:41 +0200 Subject: [PATCH 085/189] Fix typo lf config usage --- client/cmdlf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/cmdlf.c b/client/cmdlf.c index c09a299c..12d30663 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -227,7 +227,7 @@ int usage_lf_config(void) PrintAndLog(" h This help"); PrintAndLog(" L Low frequency (125 KHz)"); PrintAndLog(" H High frequency (134 KHz)"); - PrintAndLog(" q Manually set divisor. 88-> 134KHz, 95-> 125 Hz"); + PrintAndLog(" q Manually set divisor. 88-> 134 KHz, 95-> 125 KHz"); PrintAndLog(" b Sets resolution of bits per sample. Default (max): 8"); PrintAndLog(" d Sets decimation. A value of N saves only 1 in N samples. Default: 1"); PrintAndLog(" a [0|1] Averaging - if set, will average the stored sample value when decimating. Default: 1"); From 9ebbfd898ca6ce4f9e32b64aca3f3972a3a74e2c Mon Sep 17 00:00:00 2001 From: Iceman Date: Mon, 22 Apr 2019 18:25:52 +0200 Subject: [PATCH 086/189] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 09f23a6b..2f7007e2 100644 --- a/README.md +++ b/README.md @@ -30,9 +30,10 @@ following locations: * [RyscCorp](https://proxmark3.com/) (US) * [Hackerwarehouse](https://hackerwarehouse.com/) (US) * [Elechouse](http://www.elechouse.com/) (HK) -* [Lab401](https://lab401.com/) (FR) +* [Lab401](https://lab401.com/) (HK) * [RFxSecure](http://www.rfxsecure.com/) (SG) -* [IceSQL](http://proxmark3.tictail.com/) (SE) +* [Sneaktechnology](https://www.sneaktechnology.com/) (ASIA/OCEANIA) + Most of the ultra-low-volume contract assemblers could put something like this together with a reasonable yield. A run of around From a39af1cb9cab6298fcf01d7243e9f48db0f45f26 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Wed, 22 May 2019 19:02:58 +0200 Subject: [PATCH 087/189] Add: new option 'd' in 'hf mf ekeyprn' to create dumpkeys.bin from emulator memory (#822) (and whitespace fixes) --- client/cmdhfmf.c | 572 +++++++++++++++++++++++++---------------------- 1 file changed, 302 insertions(+), 270 deletions(-) diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 903e8575..9284d14c 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -34,7 +34,7 @@ #include "mifare/ndef.h" #include "emv/dump.h" -#define NESTED_SECTOR_RETRY 10 // how often we try mfested() until we give up +#define NESTED_SECTOR_RETRY 10 // how often we try mfested() until we give up static int CmdHelp(const char *Cmd); @@ -65,7 +65,7 @@ int CmdHF14AMfWrBl(const char *Cmd) uint8_t key[6] = {0, 0, 0, 0, 0, 0}; uint8_t bldata[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - char cmdp = 0x00; + char cmdp = 0x00; if (strlen(Cmd)<3) { PrintAndLog("Usage: hf mf wrbl "); @@ -113,7 +113,7 @@ int CmdHF14AMfRdBl(const char *Cmd) uint8_t keyType = 0; uint8_t key[6] = {0, 0, 0, 0, 0, 0}; - char cmdp = 0x00; + char cmdp = 0x00; if (strlen(Cmd)<3) { @@ -177,7 +177,7 @@ int CmdHF14AMfRdSc(const char *Cmd) uint8_t key[6] = {0, 0, 0, 0, 0, 0}; uint8_t isOK = 0; uint8_t *data = NULL; - char cmdp = 0x00; + char cmdp = 0x00; if (strlen(Cmd)<3) { PrintAndLog("Usage: hf mf rdsc "); @@ -218,15 +218,15 @@ int CmdHF14AMfRdSc(const char *Cmd) PrintAndLog("data : %s", sprint_hex(data + i * 16, 16)); } PrintAndLog("trailer: %s", sprint_hex(data + (sectorNo<32?3:15) * 16, 16)); - + PrintAndLogEx(NORMAL, "Trailer decoded:"); - int bln = mfFirstBlockOfSector(sectorNo); - int blinc = (mfNumBlocksPerSector(sectorNo) > 4) ? 5 : 1; - for (i = 0; i < 4; i++) { - PrintAndLogEx(NORMAL, "Access block %d%s: %s", bln, ((blinc > 1) && (i < 3) ? "+" : "") , mfGetAccessConditionsDesc(i, &(data + (sectorNo<32?3:15) * 16)[6])); - bln += blinc; - } - PrintAndLogEx(NORMAL, "UserData: %s", sprint_hex_inrow(&(data + (sectorNo<32?3:15) * 16)[9], 1)); + int bln = mfFirstBlockOfSector(sectorNo); + int blinc = (mfNumBlocksPerSector(sectorNo) > 4) ? 5 : 1; + for (i = 0; i < 4; i++) { + PrintAndLogEx(NORMAL, "Access block %d%s: %s", bln, ((blinc > 1) && (i < 3) ? "+" : "") , mfGetAccessConditionsDesc(i, &(data + (sectorNo<32?3:15) * 16)[6])); + bln += blinc; + } + PrintAndLogEx(NORMAL, "UserData: %s", sprint_hex_inrow(&(data + (sectorNo<32?3:15) * 16)[9], 1)); } } else { PrintAndLog("Command execute timeout"); @@ -324,7 +324,7 @@ int CmdHF14AMfDump(const char *Cmd) fclose(fin); return 2; } - } + } } fclose(fin); @@ -371,7 +371,7 @@ int CmdHF14AMfDump(const char *Cmd) for (blockNo = 0; isOK && blockNo < NumBlocksPerSector(sectorNo); blockNo++) { bool received = false; for (tries = 0; tries < 3; tries++) { - if (blockNo == NumBlocksPerSector(sectorNo) - 1) { // sector trailer. At least the Access Conditions can always be read with key A. + if (blockNo == NumBlocksPerSector(sectorNo) - 1) { // sector trailer. At least the Access Conditions can always be read with key A. UsbCommand c = {CMD_MIFARE_READBL, {FirstBlockOfSector(sectorNo) + blockNo, 0, 0}}; memcpy(c.d.asBytes, keys[0][sectorNo], 6); SendCommand(&c); @@ -387,14 +387,14 @@ int CmdHF14AMfDump(const char *Cmd) // Don't try the other one on success. if (resp.arg[0] & 0xff) break; } - } else { // data block. Check if it can be read with key A or key B + } else { // data block. Check if it can be read with key A or key B uint8_t data_area = sectorNo<32?blockNo:blockNo/5; - if ((rights[sectorNo][data_area] == 0x03) || (rights[sectorNo][data_area] == 0x05)) { // only key B would work + if ((rights[sectorNo][data_area] == 0x03) || (rights[sectorNo][data_area] == 0x05)) { // only key B would work UsbCommand c = {CMD_MIFARE_READBL, {FirstBlockOfSector(sectorNo) + blockNo, 1, 0}}; memcpy(c.d.asBytes, keys[1][sectorNo], 6); SendCommand(&c); received = WaitForResponseTimeout(CMD_ACK,&resp,1500); - } else if (rights[sectorNo][data_area] == 0x07) { // no key would work + } else if (rights[sectorNo][data_area] == 0x07) { // no key would work PrintAndLog("Access rights do not allow reading of sector %2d block %3d", sectorNo, blockNo); if (nullMissingKeys) { memset(resp.d.asBytes, 0, 16); @@ -405,7 +405,7 @@ int CmdHF14AMfDump(const char *Cmd) isOK = false; tries = 2; } - } else { // key A would work + } else { // key A would work UsbCommand c = {CMD_MIFARE_READBL, {FirstBlockOfSector(sectorNo) + blockNo, 0, 0}}; memcpy(c.d.asBytes, keys[0][sectorNo], 6); SendCommand(&c); @@ -421,13 +421,13 @@ int CmdHF14AMfDump(const char *Cmd) if (received) { isOK = resp.arg[0] & 0xff; uint8_t *data = resp.d.asBytes; - if (blockNo == NumBlocksPerSector(sectorNo) - 1) { // sector trailer. Fill in the keys. + if (blockNo == NumBlocksPerSector(sectorNo) - 1) { // sector trailer. Fill in the keys. memcpy(data, keys[0][sectorNo], 6); memcpy(data + 10, keys[1][sectorNo], 6); } if (isOK) { memcpy(carddata[FirstBlockOfSector(sectorNo) + blockNo], data, 16); - PrintAndLog("Successfully read block %2d of sector %2d.", blockNo, sectorNo); + PrintAndLog("Successfully read block %2d of sector %2d.", blockNo, sectorNo); } else { PrintAndLog("Could not read block %2d of sector %2d", blockNo, sectorNo); break; @@ -530,7 +530,7 @@ int CmdHF14AMfRestore(const char *Cmd) return 2; } - if (blockNo == NumBlocksPerSector(sectorNo) - 1) { // sector trailer + if (blockNo == NumBlocksPerSector(sectorNo) - 1) { // sector trailer bldata[0] = (keyA[sectorNo][0]); bldata[1] = (keyA[sectorNo][1]); bldata[2] = (keyA[sectorNo][2]); @@ -573,7 +573,7 @@ static void parseParamTDS(const char *Cmd, const uint8_t indx, bool *paramT, boo int len = param_getlength(Cmd, indx); if (len > 0 && len < 4){ param_getstr(Cmd, indx, ctmp3, sizeof(ctmp3)); - + *paramT |= (ctmp3[0] == 't' || ctmp3[0] == 'T'); *paramD |= (ctmp3[0] == 'd' || ctmp3[0] == 'D'); bool paramS1 = *paramT || *paramD; @@ -581,7 +581,7 @@ static void parseParamTDS(const char *Cmd, const uint8_t indx, bool *paramT, boo // slow and very slow if (ctmp3[0] == 's' || ctmp3[0] == 'S' || ctmp3[1] == 's' || ctmp3[1] == 'S') { *timeout = 11; // slow - + if (!paramS1 && (ctmp3[1] == 's' || ctmp3[1] == 'S')) { *timeout = 53; // very slow } @@ -606,7 +606,7 @@ int CmdHF14AMfNested(const char *Cmd) uint64_t key64 = 0; // timeout in units. (ms * 106)/10 or us*0.0106 uint8_t btimeout14a = MF_CHKKEYS_DEFTIMEOUT; // fast by default - + bool autosearchKey = false; bool transferToEml = false; @@ -647,14 +647,14 @@ int CmdHF14AMfNested(const char *Cmd) } else { SectorsCnt = ParamCardSizeSectors(cmdp); } - + // . number or autosearch key (*) if (param_getchar(Cmd, 1) == '*') { autosearchKey = true; parseParamTDS(Cmd, 2, &transferToEml, &createDumpFile, &btimeout14a); - PrintAndLog("--nested. sectors:%2d, block no:*, eml:%c, dmp=%c checktimeout=%d us", + PrintAndLog("--nested. sectors:%2d, block no:*, eml:%c, dmp=%c checktimeout=%d us", SectorsCnt, transferToEml?'y':'n', createDumpFile?'y':'n', ((int)btimeout14a * 10000) / 106); } else { blockNo = param_get8(Cmd, 1); @@ -681,7 +681,7 @@ int CmdHF14AMfNested(const char *Cmd) } // one sector nested - if (cmdp == 'o') { + if (cmdp == 'o') { trgBlockNo = param_get8(Cmd, 4); ctmp = param_getchar(Cmd, 5); @@ -697,7 +697,7 @@ int CmdHF14AMfNested(const char *Cmd) parseParamTDS(Cmd, 4, &transferToEml, &createDumpFile, &btimeout14a); } - PrintAndLog("--nested. sectors:%2d, block no:%3d, key type:%c, eml:%c, dmp=%c checktimeout=%d us", + PrintAndLog("--nested. sectors:%2d, block no:%3d, key type:%c, eml:%c, dmp=%c checktimeout=%d us", SectorsCnt, blockNo, keyType?'B':'A', transferToEml?'y':'n', createDumpFile?'y':'n', ((int)btimeout14a * 10000) / 106); } @@ -721,9 +721,9 @@ int CmdHF14AMfNested(const char *Cmd) // transfer key to the emulator if (transferToEml) { uint8_t sectortrailer; - if (trgBlockNo < 32*4) { // 4 block sector + if (trgBlockNo < 32*4) { // 4 block sector sectortrailer = trgBlockNo | 0x03; - } else { // 16 block sector + } else { // 16 block sector sectortrailer = trgBlockNo | 0x0f; } mfEmlGetMem(keyBlock, sectortrailer, 1); @@ -753,7 +753,7 @@ int CmdHF14AMfNested(const char *Cmd) PrintAndLog("Testing known keys. Sector count=%d", SectorsCnt); mfCheckKeysSec(SectorsCnt, 2, btimeout14a, true, MifareDefaultKeysSize, keyBlock, e_sector); - + // get known key from array bool keyFound = false; if (autosearchKey) { @@ -769,7 +769,7 @@ int CmdHF14AMfNested(const char *Cmd) } } if (keyFound) break; - } + } // Can't found a key.... if (!keyFound) { @@ -810,7 +810,7 @@ int CmdHF14AMfNested(const char *Cmd) PrintAndLog("Found valid key:%012" PRIx64, key64); e_sector[sectorNo].foundKey[trgKeyType] = 1; e_sector[sectorNo].Key[trgKeyType] = key64; - + // try to check this key as a key to the other sectors mfCheckKeysSec(SectorsCnt, 2, btimeout14a, true, 1, keyBlock, e_sector); } @@ -821,7 +821,7 @@ int CmdHF14AMfNested(const char *Cmd) // print nested statistic PrintAndLog("\n\n-----------------------------------------------\nNested statistic:\nIterations count: %d", iterations); PrintAndLog("Time in nested: %1.3f (%1.3f sec per key)", ((float)(msclock() - msclock1))/1000.0, ((float)(msclock() - msclock1))/iterations/1000.0); - + // print result PrintAndLog("|---|----------------|---|----------------|---|"); PrintAndLog("|sec|key A |res|key B |res|"); @@ -990,7 +990,7 @@ int CmdHF14AMfNestedHard(const char *Cmd) i++; } } - + SetSIMDInstr(SIMD_AUTO); if (iindx > 0) { while ((ctmp = param_getchar(Cmd, iindx))) { @@ -1020,7 +1020,7 @@ int CmdHF14AMfNestedHard(const char *Cmd) } } iindx++; - } + } } PrintAndLog("--target block no:%3d, target key type:%c, known target key: 0x%02x%02x%02x%02x%02x%02x%s, file action: %s, Slow: %s, Tests: %d ", @@ -1072,8 +1072,8 @@ int CmdHF14AMfChk(const char *Cmd) uint16_t stKeyBlock = 20; int i, res; - int keycnt = 0; - char ctmp = 0x00; + int keycnt = 0; + char ctmp = 0x00; int clen = 0; uint8_t blockNo = 0; uint8_t SectorsCnt = 0; @@ -1085,7 +1085,7 @@ int CmdHF14AMfChk(const char *Cmd) bool transferToEml = 0; bool createDumpFile = 0; - + sector_t *e_sector = NULL; keyBlock = calloc(stKeyBlock, 6); @@ -1123,12 +1123,12 @@ int CmdHF14AMfChk(const char *Cmd) } parseParamTDS(Cmd, 2, &transferToEml, &createDumpFile, &btimeout14a); - + param3InUse = transferToEml | createDumpFile | (btimeout14a != MF_CHKKEYS_DEFTIMEOUT); - PrintAndLog("--chk keys. sectors:%2d, block no:%3d, key type:%c, eml:%c, dmp=%c checktimeout=%d us", + PrintAndLog("--chk keys. sectors:%2d, block no:%3d, key type:%c, eml:%c, dmp=%c checktimeout=%d us", SectorsCnt, blockNo, keyType?'B':'A', transferToEml?'y':'n', createDumpFile?'y':'n', ((int)btimeout14a * 10000) / 106); - + for (i = param3InUse; param_getchar(Cmd, 2 + i); i++) { if (!param_gethex(Cmd, 2 + i, keyBlock + 6 * keycnt, 12)) { if ( stKeyBlock - keycnt < 2) { @@ -1142,7 +1142,7 @@ int CmdHF14AMfChk(const char *Cmd) } PrintAndLog("chk key[%2d] %02x%02x%02x%02x%02x%02x", keycnt, (keyBlock + 6*keycnt)[0],(keyBlock + 6*keycnt)[1], (keyBlock + 6*keycnt)[2], - (keyBlock + 6*keycnt)[3], (keyBlock + 6*keycnt)[4], (keyBlock + 6*keycnt)[5], 6); + (keyBlock + 6*keycnt)[3], (keyBlock + 6*keycnt)[4], (keyBlock + 6*keycnt)[5], 6); keycnt++; } else { // May be a dic file @@ -1159,7 +1159,7 @@ int CmdHF14AMfChk(const char *Cmd) while (fgetc(f) != '\n' && !feof(f)) ; //goto next line - if( buf[0]=='#' ) continue; //The line start with # is comment, skip + if( buf[0]=='#' ) continue; //The line start with # is comment, skip if (!isxdigit((unsigned char)buf[0])){ PrintAndLog("File content error. '%s' must include 12 HEX symbols",buf); @@ -1200,7 +1200,7 @@ int CmdHF14AMfChk(const char *Cmd) for (;keycnt < defaultKeysSize; keycnt++) PrintAndLog("chk default key[%2d] %02x%02x%02x%02x%02x%02x", keycnt, (keyBlock + 6*keycnt)[0],(keyBlock + 6*keycnt)[1], (keyBlock + 6*keycnt)[2], - (keyBlock + 6*keycnt)[3], (keyBlock + 6*keycnt)[4], (keyBlock + 6*keycnt)[5], 6); + (keyBlock + 6*keycnt)[3], (keyBlock + 6*keycnt)[4], (keyBlock + 6*keycnt)[5], 6); } // initialize storage for found keys @@ -1245,7 +1245,7 @@ int CmdHF14AMfChk(const char *Cmd) for (uint32_t c = 0; c < keycnt; c+=max_keys) { uint32_t size = keycnt-c > max_keys ? max_keys : keycnt-c; - res = mfCheckKeys(blockNo, keyAB & 0x01, true, size, &keyBlock[6 * c], &key64); + res = mfCheckKeys(blockNo, keyAB & 0x01, true, size, &keyBlock[6 * c], &key64); if (res != 1) { if (!res) { @@ -1258,7 +1258,7 @@ int CmdHF14AMfChk(const char *Cmd) } } while(--keyAB > 0); } - + // print result if (foundAKey) { if (SectorsCnt) { @@ -1275,8 +1275,8 @@ int CmdHF14AMfChk(const char *Cmd) } else { PrintAndLog(""); PrintAndLog("No valid keys found."); - } - + } + if (transferToEml) { uint8_t block[16]; for (uint16_t sectorNo = 0; sectorNo < SectorsCnt; sectorNo++) { @@ -1320,7 +1320,7 @@ int CmdHF14AMfChk(const char *Cmd) void readerAttack(nonces_t ar_resp[], bool setEmulatorMem, bool doStandardAttack) { #define ATTACK_KEY_COUNT 7 // keep same as define in iso14443a.c -> Mifare1ksim() - // cannot be more than 7 or it will overrun c.d.asBytes(512) + // cannot be more than 7 or it will overrun c.d.asBytes(512) uint64_t key = 0; typedef struct { uint64_t keyA; @@ -1329,7 +1329,7 @@ void readerAttack(nonces_t ar_resp[], bool setEmulatorMem, bool doStandardAttack st_t sector_trailer[ATTACK_KEY_COUNT]; memset(sector_trailer, 0x00, sizeof(sector_trailer)); - uint8_t stSector[ATTACK_KEY_COUNT]; + uint8_t stSector[ATTACK_KEY_COUNT]; memset(stSector, 0x00, sizeof(stSector)); uint8_t key_cnt[ATTACK_KEY_COUNT]; memset(key_cnt, 0x00, sizeof(key_cnt)); @@ -1392,7 +1392,7 @@ void readerAttack(nonces_t ar_resp[], bool setEmulatorMem, bool doStandardAttack if (setEmulatorMem) { for (uint8_t i = 0; i0) { - uint8_t memBlock[16]; + uint8_t memBlock[16]; memset(memBlock, 0x00, sizeof(memBlock)); char cmd1[36]; memset(cmd1,0x00,sizeof(cmd1)); @@ -1463,7 +1463,7 @@ int CmdHF14AMfSim(const char *Cmd) { while(param_getchar(Cmd, cmdp) != 0x00) { switch(param_getchar(Cmd, cmdp)) { - case '*': + case '*': cardsize = param_getchar(Cmd + 1, cmdp); switch(cardsize) { case '0': @@ -1580,7 +1580,7 @@ int CmdHF14AMfSim(const char *Cmd) { cardsize == '2' ? "2K" : cardsize == '4' ? "4K" : "1K", flags & FLAG_4B_UID_IN_DATA ? sprint_hex(uid,4): - flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): "N/A", + flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): "N/A", exitAfterNReads, flags, flags); @@ -1615,7 +1615,7 @@ int CmdHF14AMfSim(const char *Cmd) { cardsize == '2' ? "2K" : cardsize == '4' ? "4K" : "1K", flags & FLAG_4B_UID_IN_DATA ? sprint_hex(uid,4): - flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): "N/A", + flags & FLAG_7B_UID_IN_DATA ? sprint_hex(uid,7): "N/A", exitAfterNReads, flags, flags); @@ -1951,31 +1951,37 @@ int CmdHF14AMfECFill(const char *Cmd) return 0; } + int CmdHF14AMfEKeyPrn(const char *Cmd) { int i; - uint8_t numSectors; + uint8_t numSectors = 16; uint8_t data[16]; uint64_t keyA, keyB; + bool createDumpFile = false; if (param_getchar(Cmd, 0) == 'h') { PrintAndLog("It prints the keys loaded in the emulator memory"); - PrintAndLog("Usage: hf mf ekeyprn [card memory]"); + PrintAndLog("Usage: hf mf ekeyprn [card memory] [d]"); PrintAndLog(" [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K"); + PrintAndLog(" [d] : write keys to binary file dumpkeys.bin"); PrintAndLog(""); PrintAndLog(" sample: hf mf ekeyprn 1"); return 0; } - char cmdp = param_getchar(Cmd, 0); - - switch (cmdp) { - case '0' : numSectors = 5; break; - case '1' : - case '\0': numSectors = 16; break; - case '2' : numSectors = 32; break; - case '4' : numSectors = 40; break; - default: numSectors = 16; + uint8_t cmdp = 0; + while (param_getchar(Cmd, cmdp) != 0x00) { + switch (param_getchar(Cmd, cmdp)) { + case '0' : numSectors = 5; break; + case '1' : + case '\0': numSectors = 16; break; + case '2' : numSectors = 32; break; + case '4' : numSectors = 40; break; + case 'd' : + case 'D' : createDumpFile = true; break; + } + cmdp++; } PrintAndLog("|---|----------------|----------------|"); @@ -1992,9 +1998,35 @@ int CmdHF14AMfEKeyPrn(const char *Cmd) } PrintAndLog("|---|----------------|----------------|"); + // Create dump file + if (createDumpFile) { + FILE *fkeys; + if ((fkeys = fopen("dumpkeys.bin","wb")) == NULL) { + PrintAndLog("Could not create file dumpkeys.bin"); + return 1; + } + PrintAndLog("Printing keys to binary file dumpkeys.bin..."); + for(i = 0; i < numSectors; i++) { + if (mfEmlGetMem(data, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1)) { + PrintAndLog("error get block %d", FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1); + break; + } + fwrite(data+6, 1, 6, fkeys); + } + for(i = 0; i < numSectors; i++) { + if (mfEmlGetMem(data, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1)) { + PrintAndLog("error get block %d", FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1); + break; + } + fwrite(data+10, 1, 6, fkeys); + } + fclose(fkeys); + } + return 0; } + int CmdHF14AMfCSetUID(const char *Cmd) { uint8_t uid[8] = {0x00}; @@ -2006,7 +2038,7 @@ int CmdHF14AMfCSetUID(const char *Cmd) uint8_t needHelp = 0; char cmdp = 1; - + if (param_getchar(Cmd, 0) && param_gethex(Cmd, 0, uid, 8)) { PrintAndLog("UID must include 8 HEX symbols"); return 1; @@ -2015,12 +2047,12 @@ int CmdHF14AMfCSetUID(const char *Cmd) if (param_getlength(Cmd, 1) > 1 && param_getlength(Cmd, 2) > 1) { atqaPresent = 1; cmdp = 3; - + if (param_gethex(Cmd, 1, atqa, 4)) { PrintAndLog("ATQA must include 4 HEX symbols"); return 1; } - + if (param_gethex(Cmd, 2, sak, 2)) { PrintAndLog("SAK must include 2 HEX symbols"); return 1; @@ -2074,7 +2106,7 @@ int CmdHF14AMfCWipe(const char *Cmd) int numBlocks = 16 * 4; bool wipeCard = false; bool fillCard = false; - + if (strlen(Cmd) < 1 || param_getchar(Cmd, 0) == 'h') { PrintAndLog("Usage: hf mf cwipe [card size] [w] [f]"); PrintAndLog("sample: hf mf cwipe 1 w f"); @@ -2085,9 +2117,9 @@ int CmdHF14AMfCWipe(const char *Cmd) } gen = mfCIdentify(); - if ((gen != 1) && (gen != 2)) + if ((gen != 1) && (gen != 2)) return 1; - + numBlocks = ParamCardSizeBlocks(param_getchar(Cmd, 0)); char cmdp = 0; @@ -2107,7 +2139,7 @@ int CmdHF14AMfCWipe(const char *Cmd) cmdp++; } - if (!wipeCard && !fillCard) + if (!wipeCard && !fillCard) wipeCard = true; PrintAndLog("--blocks count:%2d wipe:%c fill:%c", numBlocks, (wipeCard)?'y':'n', (fillCard)?'y':'n'); @@ -2117,10 +2149,10 @@ int CmdHF14AMfCWipe(const char *Cmd) if (wipeCard) { PrintAndLog("WARNING: can't wipe magic card 1b generation"); } - res = mfCWipe(numBlocks, true, false, fillCard); + res = mfCWipe(numBlocks, true, false, fillCard); } else { /* generation 1a magic card by default */ - res = mfCWipe(numBlocks, false, wipeCard, fillCard); + res = mfCWipe(numBlocks, false, wipeCard, fillCard); } if (res) { @@ -2147,7 +2179,7 @@ int CmdHF14AMfCSetBlk(const char *Cmd) } gen = mfCIdentify(); - if ((gen != 1) && (gen != 2)) + if ((gen != 1) && (gen != 2)) return 1; blockNo = param_get8(Cmd, 0); @@ -2213,9 +2245,9 @@ int CmdHF14AMfCLoad(const char *Cmd) PrintAndLog("Cant get block: %d", blockNum); return 2; } - if (blockNum == 0) flags = CSETBLOCK_INIT_FIELD + CSETBLOCK_WUPC; // switch on field and send magic sequence - if (blockNum == 1) flags = 0; // just write - if (blockNum == numblock - 1) flags = CSETBLOCK_HALT + CSETBLOCK_RESET_FIELD; // Done. Magic Halt and switch off field. + if (blockNum == 0) flags = CSETBLOCK_INIT_FIELD + CSETBLOCK_WUPC; // switch on field and send magic sequence + if (blockNum == 1) flags = 0; // just write + if (blockNum == numblock - 1) flags = CSETBLOCK_HALT + CSETBLOCK_RESET_FIELD; // Done. Magic Halt and switch off field. if (gen == 2) /* generation 1b magic card */ @@ -2265,9 +2297,9 @@ int CmdHF14AMfCLoad(const char *Cmd) for (i = 0; i < 32; i += 2) sscanf(&buf[i], "%02x", (unsigned int *)&buf8[i / 2]); - if (blockNum == 0) flags = CSETBLOCK_INIT_FIELD + CSETBLOCK_WUPC; // switch on field and send magic sequence - if (blockNum == 1) flags = 0; // just write - if (blockNum == numblock - 1) flags = CSETBLOCK_HALT + CSETBLOCK_RESET_FIELD; // Done. Switch off field. + if (blockNum == 0) flags = CSETBLOCK_INIT_FIELD + CSETBLOCK_WUPC; // switch on field and send magic sequence + if (blockNum == 1) flags = 0; // just write + if (blockNum == numblock - 1) flags = CSETBLOCK_HALT + CSETBLOCK_RESET_FIELD; // Done. Switch off field. if (gen == 2) /* generation 1b magic card */ @@ -2326,7 +2358,7 @@ int CmdHF14AMfCGetBlk(const char *Cmd) { } PrintAndLog("block data:%s", sprint_hex(memBlock, 16)); - + if (mfIsSectorTrailer(blockNo)) { PrintAndLogEx(NORMAL, "Trailer decoded:"); PrintAndLogEx(NORMAL, "Key A: %s", sprint_hex_inrow(memBlock, 6)); @@ -2339,7 +2371,7 @@ int CmdHF14AMfCGetBlk(const char *Cmd) { } PrintAndLogEx(NORMAL, "UserData: %s", sprint_hex_inrow(&memBlock[9], 1)); } - + return 0; } @@ -2390,19 +2422,19 @@ int CmdHF14AMfCGetSc(const char *Cmd) { } PrintAndLog("block %3d data:%s", baseblock + i, sprint_hex(memBlock, 16)); - + if (mfIsSectorTrailer(baseblock + i)) { - PrintAndLogEx(NORMAL, "Trailer decoded:"); - PrintAndLogEx(NORMAL, "Key A: %s", sprint_hex_inrow(memBlock, 6)); - PrintAndLogEx(NORMAL, "Key B: %s", sprint_hex_inrow(&memBlock[10], 6)); - int bln = baseblock; - int blinc = (mfNumBlocksPerSector(sectorNo) > 4) ? 5 : 1; - for (int i = 0; i < 4; i++) { - PrintAndLogEx(NORMAL, "Access block %d%s: %s", bln, ((blinc > 1) && (i < 3) ? "+" : "") , mfGetAccessConditionsDesc(i, &memBlock[6])); - bln += blinc; - } - PrintAndLogEx(NORMAL, "UserData: %s", sprint_hex_inrow(&memBlock[9], 1)); - } + PrintAndLogEx(NORMAL, "Trailer decoded:"); + PrintAndLogEx(NORMAL, "Key A: %s", sprint_hex_inrow(memBlock, 6)); + PrintAndLogEx(NORMAL, "Key B: %s", sprint_hex_inrow(&memBlock[10], 6)); + int bln = baseblock; + int blinc = (mfNumBlocksPerSector(sectorNo) > 4) ? 5 : 1; + for (int i = 0; i < 4; i++) { + PrintAndLogEx(NORMAL, "Access block %d%s: %s", bln, ((blinc > 1) && (i < 3) ? "+" : "") , mfGetAccessConditionsDesc(i, &memBlock[6])); + bln += blinc; + } + PrintAndLogEx(NORMAL, "UserData: %s", sprint_hex_inrow(&memBlock[9], 1)); + } } return 0; } @@ -2599,17 +2631,17 @@ int CmdHF14AMfSniff(const char *Cmd){ uint16_t traceLen = resp.arg[1]; len = resp.arg[2]; - if (res == 0) { // we are done + if (res == 0) { // we are done break; } - if (res == 1) { // there is (more) data to be transferred - if (pckNum == 0) { // first packet, (re)allocate necessary buffer + if (res == 1) { // there is (more) data to be transferred + if (pckNum == 0) { // first packet, (re)allocate necessary buffer if (traceLen > bufsize || buf == NULL) { uint8_t *p; - if (buf == NULL) { // not yet allocated + if (buf == NULL) { // not yet allocated p = malloc(traceLen); - } else { // need more memory + } else { // need more memory p = realloc(buf, traceLen); } if (p == NULL) { @@ -2628,13 +2660,13 @@ int CmdHF14AMfSniff(const char *Cmd){ pckNum++; } - if (res == 2) { // received all data, start displaying + if (res == 2) { // received all data, start displaying blockLen = bufPtr - buf; bufPtr = buf; printf(">\n"); PrintAndLog("received trace len: %d packages: %d", blockLen, pckNum); while (bufPtr - buf < blockLen) { - bufPtr += 6; // skip (void) timing information + bufPtr += 6; // skip (void) timing information len = *((uint16_t *)bufPtr); if(len & 0x8000) { isTag = true; @@ -2662,11 +2694,11 @@ int CmdHF14AMfSniff(const char *Cmd){ mfTraceInit(uid, atqa, sak, wantSaveToEmlFile); } else { oddparitybuf(bufPtr, len, parity); - PrintAndLog("%s(%d):%s [%s] c[%s]%c", - isTag ? "TAG":"RDR", - num, - sprint_hex(bufPtr, len), - printBitsPar(bufPtr + len, len), + PrintAndLog("%s(%d):%s [%s] c[%s]%c", + isTag ? "TAG":"RDR", + num, + sprint_hex(bufPtr, len), + printBitsPar(bufPtr + len, len), printBitsPar(parity, len), memcmp(bufPtr + len, parity, len / 8 + 1) ? '!' : ' '); if (wantLogToFile) @@ -2676,7 +2708,7 @@ int CmdHF14AMfSniff(const char *Cmd){ num++; } bufPtr += len; - bufPtr += parlen; // ignore parity + bufPtr += parlen; // ignore parity } pckNum = 0; } @@ -2684,7 +2716,7 @@ int CmdHF14AMfSniff(const char *Cmd){ } // while (true) free(buf); - + msleep(300); // wait for exiting arm side. PrintAndLog("Done."); return 0; @@ -2704,8 +2736,8 @@ int CmdHF14AMfAuth4(const char *cmd) { uint8_t key[16] = {0}; int keylen = 0; - CLIParserInit("hf mf auth4", - "Executes AES authentication command in ISO14443-4", + CLIParserInit("hf mf auth4", + "Executes AES authentication command in ISO14443-4", "Usage:\n\thf mf auth4 4000 000102030405060708090a0b0c0d0e0f -> executes authentication\n" "\thf mf auth4 9003 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -> executes authentication\n"); @@ -2716,16 +2748,16 @@ int CmdHF14AMfAuth4(const char *cmd) { arg_param_end }; CLIExecWithReturn(cmd, argtable, true); - + CLIGetHexWithReturn(1, keyn, &keynlen); CLIGetHexWithReturn(2, key, &keylen); CLIParserFree(); - + if (keynlen != 2) { PrintAndLog("ERROR: must be 2 bytes long instead of: %d", keynlen); return 1; } - + if (keylen != 16) { PrintAndLog("ERROR: must be 16 bytes long instead of: %d", keylen); return 1; @@ -2737,196 +2769,196 @@ int CmdHF14AMfAuth4(const char *cmd) { // https://www.nxp.com/docs/en/application-note/AN10787.pdf int CmdHF14AMfMAD(const char *cmd) { - CLIParserInit("hf mf mad", - "Checks and prints Mifare Application Directory (MAD)", - "Usage:\n\thf mf mad -> shows MAD if exists\n" - "\thf mf mad -a 03e1 -k ffffffffffff -b -> shows NDEF data if exists. read card with custom key and key B\n"); + CLIParserInit("hf mf mad", + "Checks and prints Mifare Application Directory (MAD)", + "Usage:\n\thf mf mad -> shows MAD if exists\n" + "\thf mf mad -a 03e1 -k ffffffffffff -b -> shows NDEF data if exists. read card with custom key and key B\n"); - void *argtable[] = { - arg_param_begin, - arg_lit0("vV", "verbose", "show technical data"), - arg_str0("aA", "aid", "print all sectors with aid", NULL), - arg_str0("kK", "key", "key for printing sectors", NULL), - arg_lit0("bB", "keyb", "use key B for access printing sectors (by default: key A)"), - arg_param_end - }; - CLIExecWithReturn(cmd, argtable, true); - bool verbose = arg_get_lit(1); - uint8_t aid[2] = {0}; - int aidlen; - CLIGetHexWithReturn(2, aid, &aidlen); - uint8_t key[6] = {0}; - int keylen; - CLIGetHexWithReturn(3, key, &keylen); - bool keyB = arg_get_lit(4); + void *argtable[] = { + arg_param_begin, + arg_lit0("vV", "verbose", "show technical data"), + arg_str0("aA", "aid", "print all sectors with aid", NULL), + arg_str0("kK", "key", "key for printing sectors", NULL), + arg_lit0("bB", "keyb", "use key B for access printing sectors (by default: key A)"), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, true); + bool verbose = arg_get_lit(1); + uint8_t aid[2] = {0}; + int aidlen; + CLIGetHexWithReturn(2, aid, &aidlen); + uint8_t key[6] = {0}; + int keylen; + CLIGetHexWithReturn(3, key, &keylen); + bool keyB = arg_get_lit(4); - CLIParserFree(); + CLIParserFree(); - if (aidlen != 2 && keylen > 0) { - PrintAndLogEx(WARNING, "do not need a key without aid."); - } + if (aidlen != 2 && keylen > 0) { + PrintAndLogEx(WARNING, "do not need a key without aid."); + } - uint8_t sector0[16 * 4] = {0}; - uint8_t sector10[16 * 4] = {0}; - if (mfReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector0)) { - PrintAndLogEx(ERR, "read sector 0 error. card don't have MAD or don't have MAD on default keys."); - return 2; - } + uint8_t sector0[16 * 4] = {0}; + uint8_t sector10[16 * 4] = {0}; + if (mfReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector0)) { + PrintAndLogEx(ERR, "read sector 0 error. card don't have MAD or don't have MAD on default keys."); + return 2; + } - if (verbose) { - for (int i = 0; i < 4; i ++) - PrintAndLogEx(NORMAL, "[%d] %s", i, sprint_hex(§or0[i * 16], 16)); - } + if (verbose) { + for (int i = 0; i < 4; i ++) + PrintAndLogEx(NORMAL, "[%d] %s", i, sprint_hex(§or0[i * 16], 16)); + } - bool haveMAD2 = false; - MAD1DecodeAndPrint(sector0, verbose, &haveMAD2); + bool haveMAD2 = false; + MAD1DecodeAndPrint(sector0, verbose, &haveMAD2); - if (haveMAD2) { - if (mfReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector10)) { - PrintAndLogEx(ERR, "read sector 0x10 error. card don't have MAD or don't have MAD on default keys."); - return 2; - } + if (haveMAD2) { + if (mfReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector10)) { + PrintAndLogEx(ERR, "read sector 0x10 error. card don't have MAD or don't have MAD on default keys."); + return 2; + } - MAD2DecodeAndPrint(sector10, verbose); - } + MAD2DecodeAndPrint(sector10, verbose); + } - if (aidlen == 2) { - uint16_t aaid = (aid[0] << 8) + aid[1]; - PrintAndLogEx(NORMAL, "\n-------------- AID 0x%04x ---------------", aaid); + if (aidlen == 2) { + uint16_t aaid = (aid[0] << 8) + aid[1]; + PrintAndLogEx(NORMAL, "\n-------------- AID 0x%04x ---------------", aaid); - uint16_t mad[7 + 8 + 8 + 8 + 8] = {0}; - size_t madlen = 0; - if (MADDecode(sector0, sector10, mad, &madlen)) { - PrintAndLogEx(ERR, "can't decode mad."); - return 10; - } + uint16_t mad[7 + 8 + 8 + 8 + 8] = {0}; + size_t madlen = 0; + if (MADDecode(sector0, sector10, mad, &madlen)) { + PrintAndLogEx(ERR, "can't decode mad."); + return 10; + } - uint8_t akey[6] = {0}; - memcpy(akey, g_mifare_ndef_key, 6); - if (keylen == 6) { - memcpy(akey, key, 6); - } + uint8_t akey[6] = {0}; + memcpy(akey, g_mifare_ndef_key, 6); + if (keylen == 6) { + memcpy(akey, key, 6); + } - for (int i = 0; i < madlen; i++) { - if (aaid == mad[i]) { - uint8_t vsector[16 * 4] = {0}; - if (mfReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, akey, vsector)) { - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(ERR, "read sector %d error.", i + 1); - return 2; - } + for (int i = 0; i < madlen; i++) { + if (aaid == mad[i]) { + uint8_t vsector[16 * 4] = {0}; + if (mfReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, akey, vsector)) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(ERR, "read sector %d error.", i + 1); + return 2; + } - for (int j = 0; j < (verbose ? 4 : 3); j ++) - PrintAndLogEx(NORMAL, " [%03d] %s", (i + 1) * 4 + j, sprint_hex(&vsector[j * 16], 16)); - } - } - } + for (int j = 0; j < (verbose ? 4 : 3); j ++) + PrintAndLogEx(NORMAL, " [%03d] %s", (i + 1) * 4 + j, sprint_hex(&vsector[j * 16], 16)); + } + } + } - return 0; + return 0; } int CmdHFMFNDEF(const char *cmd) { - CLIParserInit("hf mf ndef", - "Prints NFC Data Exchange Format (NDEF)", - "Usage:\n\thf mf ndef -> shows NDEF data\n" - "\thf mf ndef -a 03e1 -k ffffffffffff -b -> shows NDEF data with custom AID, key and with key B\n"); + CLIParserInit("hf mf ndef", + "Prints NFC Data Exchange Format (NDEF)", + "Usage:\n\thf mf ndef -> shows NDEF data\n" + "\thf mf ndef -a 03e1 -k ffffffffffff -b -> shows NDEF data with custom AID, key and with key B\n"); - void *argtable[] = { - arg_param_begin, - arg_litn("vV", "verbose", 0, 2, "show technical data"), - arg_str0("aA", "aid", "replace default aid for NDEF", NULL), - arg_str0("kK", "key", "replace default key for NDEF", NULL), - arg_lit0("bB", "keyb", "use key B for access sectors (by default: key A)"), - arg_param_end - }; - CLIExecWithReturn(cmd, argtable, true); + void *argtable[] = { + arg_param_begin, + arg_litn("vV", "verbose", 0, 2, "show technical data"), + arg_str0("aA", "aid", "replace default aid for NDEF", NULL), + arg_str0("kK", "key", "replace default key for NDEF", NULL), + arg_lit0("bB", "keyb", "use key B for access sectors (by default: key A)"), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, true); - bool verbose = arg_get_lit(1); - bool verbose2 = arg_get_lit(1) > 1; - uint8_t aid[2] = {0}; - int aidlen; - CLIGetHexWithReturn(2, aid, &aidlen); - uint8_t key[6] = {0}; - int keylen; - CLIGetHexWithReturn(3, key, &keylen); - bool keyB = arg_get_lit(4); + bool verbose = arg_get_lit(1); + bool verbose2 = arg_get_lit(1) > 1; + uint8_t aid[2] = {0}; + int aidlen; + CLIGetHexWithReturn(2, aid, &aidlen); + uint8_t key[6] = {0}; + int keylen; + CLIGetHexWithReturn(3, key, &keylen); + bool keyB = arg_get_lit(4); - CLIParserFree(); + CLIParserFree(); - uint16_t ndefAID = 0x03e1; - if (aidlen == 2) - ndefAID = (aid[0] << 8) + aid[1]; + uint16_t ndefAID = 0x03e1; + if (aidlen == 2) + ndefAID = (aid[0] << 8) + aid[1]; - uint8_t ndefkey[6] = {0}; - memcpy(ndefkey, g_mifare_ndef_key, 6); - if (keylen == 6) { - memcpy(ndefkey, key, 6); - } + uint8_t ndefkey[6] = {0}; + memcpy(ndefkey, g_mifare_ndef_key, 6); + if (keylen == 6) { + memcpy(ndefkey, key, 6); + } - uint8_t sector0[16 * 4] = {0}; - uint8_t sector10[16 * 4] = {0}; - uint8_t data[4096] = {0}; - int datalen = 0; + uint8_t sector0[16 * 4] = {0}; + uint8_t sector10[16 * 4] = {0}; + uint8_t data[4096] = {0}; + int datalen = 0; - PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, ""); - if (mfReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector0)) { - PrintAndLogEx(ERR, "read sector 0 error. card don't have MAD or don't have MAD on default keys."); - return 2; - } + if (mfReadSector(MF_MAD1_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector0)) { + PrintAndLogEx(ERR, "read sector 0 error. card don't have MAD or don't have MAD on default keys."); + return 2; + } - bool haveMAD2 = false; - int res = MADCheck(sector0, NULL, verbose, &haveMAD2); - if (res) { - PrintAndLogEx(ERR, "MAD error %d.", res); - return res; - } + bool haveMAD2 = false; + int res = MADCheck(sector0, NULL, verbose, &haveMAD2); + if (res) { + PrintAndLogEx(ERR, "MAD error %d.", res); + return res; + } - if (haveMAD2) { - if (mfReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector10)) { - PrintAndLogEx(ERR, "read sector 0x10 error. card don't have MAD or don't have MAD on default keys."); - return 2; - } - } + if (haveMAD2) { + if (mfReadSector(MF_MAD2_SECTOR, MF_KEY_A, (uint8_t *)g_mifare_mad_key, sector10)) { + PrintAndLogEx(ERR, "read sector 0x10 error. card don't have MAD or don't have MAD on default keys."); + return 2; + } + } - uint16_t mad[7 + 8 + 8 + 8 + 8] = {0}; - size_t madlen = 0; - if (MADDecode(sector0, (haveMAD2 ? sector10 : NULL), mad, &madlen)) { - PrintAndLogEx(ERR, "can't decode mad."); - return 10; - } + uint16_t mad[7 + 8 + 8 + 8 + 8] = {0}; + size_t madlen = 0; + if (MADDecode(sector0, (haveMAD2 ? sector10 : NULL), mad, &madlen)) { + PrintAndLogEx(ERR, "can't decode mad."); + return 10; + } - printf("data reading:"); - for (int i = 0; i < madlen; i++) { - if (ndefAID == mad[i]) { - uint8_t vsector[16 * 4] = {0}; - if (mfReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, ndefkey, vsector)) { - PrintAndLogEx(ERR, "read sector %d error.", i + 1); - return 2; - } + printf("data reading:"); + for (int i = 0; i < madlen; i++) { + if (ndefAID == mad[i]) { + uint8_t vsector[16 * 4] = {0}; + if (mfReadSector(i + 1, keyB ? MF_KEY_B : MF_KEY_A, ndefkey, vsector)) { + PrintAndLogEx(ERR, "read sector %d error.", i + 1); + return 2; + } - memcpy(&data[datalen], vsector, 16 * 3); - datalen += 16 * 3; + memcpy(&data[datalen], vsector, 16 * 3); + datalen += 16 * 3; - printf("."); - } - } - printf(" OK\n"); + printf("."); + } + } + printf(" OK\n"); - if (!datalen) { - PrintAndLogEx(ERR, "no NDEF data."); - return 11; - } + if (!datalen) { + PrintAndLogEx(ERR, "no NDEF data."); + return 11; + } - if (verbose2) { - PrintAndLogEx(NORMAL, "NDEF data:"); - dump_buffer(data, datalen, stdout, 1); - } + if (verbose2) { + PrintAndLogEx(NORMAL, "NDEF data:"); + dump_buffer(data, datalen, stdout, 1); + } - NDEFDecodeAndPrint(data, datalen, verbose); + NDEFDecodeAndPrint(data, datalen, verbose); - return 0; + return 0; } static command_t CommandTable[] = @@ -2936,7 +2968,7 @@ static command_t CommandTable[] = {"rdbl", CmdHF14AMfRdBl, 0, "Read MIFARE classic block"}, {"rdsc", CmdHF14AMfRdSc, 0, "Read MIFARE classic sector"}, {"dump", CmdHF14AMfDump, 0, "Dump MIFARE classic tag to binary file"}, - {"restore", CmdHF14AMfRestore, 0, "Restore MIFARE classic binary file to BLANK tag"}, + {"restore", CmdHF14AMfRestore, 0, "Restore MIFARE classic binary file to BLANK tag"}, {"wrbl", CmdHF14AMfWrBl, 0, "Write MIFARE classic block"}, {"auth4", CmdHF14AMfAuth4, 0, "ISO14443-4 AES authentication"}, {"chk", CmdHF14AMfChk, 0, "Test block keys"}, From 2378bb24c3d4ce21d71b4ab5739c58a9979b8b69 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Mon, 27 May 2019 07:57:40 +0200 Subject: [PATCH 088/189] fix compiler warning in cmdhflegic.c (and whitespace fixes) (#826) --- client/cmdhflegic.c | 570 ++++++++++++++++++++++---------------------- 1 file changed, 286 insertions(+), 284 deletions(-) diff --git a/client/cmdhflegic.c b/client/cmdhflegic.c index 66e8ebb1..14942017 100644 --- a/client/cmdhflegic.c +++ b/client/cmdhflegic.c @@ -22,29 +22,29 @@ static int CmdHelp(const char *Cmd); -static command_t CommandTable[] = +static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help"}, - {"decode", CmdLegicDecode, 0, "Display deobfuscated and decoded LEGIC RF tag data (use after hf legic reader)"}, - {"reader", CmdLegicRFRead, 0, "[offset [length]] -- read bytes from a LEGIC card"}, - {"save", CmdLegicSave, 0, " [] -- Store samples"}, - {"load", CmdLegicLoad, 0, " -- Restore samples"}, - {"sim", CmdLegicRfSim, 0, "[tagtype, 0:MIM22, 1:MIM256, 2:MIM1024] Start tag simulator (use after load or read)"}, - {"write", CmdLegicRfWrite,0, " -- Write sample buffer (user after load or read)"}, - {"fill", CmdLegicRfFill, 0, " -- Fill/Write tag with constant value"}, - {NULL, NULL, 0, NULL} + {"help", CmdHelp, 1, "This help"}, + {"decode", CmdLegicDecode, 0, "Display deobfuscated and decoded LEGIC RF tag data (use after hf legic reader)"}, + {"reader", CmdLegicRFRead, 0, "[offset [length]] -- read bytes from a LEGIC card"}, + {"save", CmdLegicSave, 0, " [] -- Store samples"}, + {"load", CmdLegicLoad, 0, " -- Restore samples"}, + {"sim", CmdLegicRfSim, 0, "[tagtype, 0:MIM22, 1:MIM256, 2:MIM1024] Start tag simulator (use after load or read)"}, + {"write", CmdLegicRfWrite,0, " -- Write sample buffer (user after load or read)"}, + {"fill", CmdLegicRfFill, 0, " -- Fill/Write tag with constant value"}, + {NULL, NULL, 0, NULL} }; int CmdHFLegic(const char *Cmd) { - CmdsParse(CommandTable, Cmd); - return 0; + CmdsParse(CommandTable, Cmd); + return 0; } int CmdHelp(const char *Cmd) { - CmdsHelp(CommandTable); - return 0; + CmdsHelp(CommandTable); + return 0; } /* @@ -54,189 +54,191 @@ int CmdHelp(const char *Cmd) */ int CmdLegicDecode(const char *Cmd) { - int i, j, k, n; - int segment_len = 0; - int segment_flag = 0; - int stamp_len = 0; - int crc = 0; - int wrp = 0; - int wrc = 0; - uint8_t data_buf[1053]; // receiver buffer - char out_string[3076]; // just use big buffer - bad practice - char token_type[4]; - - // copy data from proxmark into buffer - GetFromBigBuf(data_buf, sizeof(data_buf), 0, NULL, -1, false); - - // Output CDF System area (9 bytes) plus remaining header area (12 bytes) - - PrintAndLog("\nCDF: System Area"); - - PrintAndLog("MCD: %02x, MSN: %02x %02x %02x, MCC: %02x", - data_buf[0], - data_buf[1], - data_buf[2], - data_buf[3], - data_buf[4] - ); - - crc = data_buf[4]; - - switch (data_buf[5]&0x7f) { - case 0x00 ... 0x2f: - strncpy(token_type, "IAM",sizeof(token_type)); - break; - case 0x30 ... 0x6f: - strcpy(token_type, "SAM"); - break; - case 0x70 ... 0x7f: - strcpy(token_type, "GAM"); - break; - default: - strcpy(token_type, "???"); - break; - } - - stamp_len = 0xfc - data_buf[6]; - - PrintAndLog("DCF: %02x %02x, Token_Type=%s (OLE=%01u), Stamp_len=%02u", - data_buf[5], - data_buf[6], - token_type, - (data_buf[5]&0x80)>>7, - stamp_len - ); - - PrintAndLog("WRP=%02u, WRC=%01u, RD=%01u, raw=%02x, SSC=%02x", - data_buf[7]&0x0f, - (data_buf[7]&0x70)>>4, - (data_buf[7]&0x80)>>7, - data_buf[7], - data_buf[8] - ); - - PrintAndLog("Remaining Header Area"); - - PrintAndLog("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", - data_buf[9], - data_buf[10], - data_buf[11], - data_buf[12], - data_buf[13], - data_buf[14], - data_buf[15], - data_buf[16], - data_buf[17], - data_buf[18], - data_buf[19], - data_buf[20], - data_buf[21] - ); - - PrintAndLog("\nADF: User Area"); - - i = 22; - for (n=0; n<64; n++) { - segment_len = ((data_buf[i+1]^crc)&0x0f) * 256 + (data_buf[i]^crc); - segment_flag = ((data_buf[i+1]^crc)&0xf0)>>4; - - wrp = (data_buf[i+2]^crc); - wrc = ((data_buf[i+3]^crc)&0x70)>>4; - - PrintAndLog("Segment %02u: raw header=%02x %02x %02x %02x, flag=%01x (valid=%01u, last=%01u), len=%04u, WRP=%02u, WRC=%02u, RD=%01u, CRC=%02x", - n, - data_buf[i]^crc, - data_buf[i+1]^crc, - data_buf[i+2]^crc, - data_buf[i+3]^crc, - segment_flag, - (segment_flag&0x4)>>2, - (segment_flag&0x8)>>3, - segment_len, - wrp, - wrc, - ((data_buf[i+3]^crc)&0x80)>>7, - (data_buf[i+4]^crc) - ); - - i+=5; - - if (wrc>0) { - PrintAndLog("WRC protected area:"); - for (k=0, j=0; k < wrc && j<(sizeof(out_string)-3); k++, i++, j += 3) { - sprintf(&out_string[j], "%02x", (data_buf[i]^crc)); - out_string[j+2] = ' '; - }; - - out_string[j] = '\0'; - - PrintAndLog("%s", out_string); - } - - if (wrp>wrc) { - PrintAndLog("Remaining write protected area:"); - - for (k=0, j=0; k < (wrp-wrc) && j<(sizeof(out_string)-3); k++, i++, j += 3) { - sprintf(&out_string[j], "%02x", (data_buf[i]^crc)); - out_string[j+2] = ' '; - }; - - out_string[j] = '\0'; - - PrintAndLog("%s", out_string); - if((wrp-wrc) == 8) { - sprintf(out_string,"Card ID: %2X%02X%02X",data_buf[i-4]^crc,data_buf[i-3]^crc,data_buf[i-2]^crc); - PrintAndLog("%s", out_string); - } - } - - PrintAndLog("Remaining segment payload:"); - for (k=0, j=0; k < (segment_len - wrp - 5) && j<(sizeof(out_string)-3); k++, i++, j += 3) { - sprintf(&out_string[j], "%02x", (data_buf[i]^crc)); - out_string[j+2] = ' '; - }; - - out_string[j] = '\0'; - - PrintAndLog("%s", out_string); - - // end with last segment - if (segment_flag & 0x8) - return 0; - }; - return 0; + int i, j, k, n; + int segment_len = 0; + int segment_flag = 0; + int stamp_len = 0; + int crc = 0; + int wrp = 0; + int wrc = 0; + uint8_t data_buf[1053]; // receiver buffer + char out_string[3076]; // just use big buffer - bad practice + char token_type[4]; + + // copy data from proxmark into buffer + GetFromBigBuf(data_buf, sizeof(data_buf), 0, NULL, -1, false); + + // Output CDF System area (9 bytes) plus remaining header area (12 bytes) + + PrintAndLog("\nCDF: System Area"); + + PrintAndLog("MCD: %02x, MSN: %02x %02x %02x, MCC: %02x", + data_buf[0], + data_buf[1], + data_buf[2], + data_buf[3], + data_buf[4] + ); + + crc = data_buf[4]; + + switch (data_buf[5]&0x7f) { + case 0x00 ... 0x2f: + strncpy(token_type, "IAM",sizeof(token_type)); + break; + case 0x30 ... 0x6f: + strcpy(token_type, "SAM"); + break; + case 0x70 ... 0x7f: + strcpy(token_type, "GAM"); + break; + default: + strcpy(token_type, "???"); + break; + } + + stamp_len = 0xfc - data_buf[6]; + + PrintAndLog("DCF: %02x %02x, Token_Type=%s (OLE=%01u), Stamp_len=%02u", + data_buf[5], + data_buf[6], + token_type, + (data_buf[5]&0x80)>>7, + stamp_len + ); + + PrintAndLog("WRP=%02u, WRC=%01u, RD=%01u, raw=%02x, SSC=%02x", + data_buf[7]&0x0f, + (data_buf[7]&0x70)>>4, + (data_buf[7]&0x80)>>7, + data_buf[7], + data_buf[8] + ); + + PrintAndLog("Remaining Header Area"); + + PrintAndLog("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", + data_buf[9], + data_buf[10], + data_buf[11], + data_buf[12], + data_buf[13], + data_buf[14], + data_buf[15], + data_buf[16], + data_buf[17], + data_buf[18], + data_buf[19], + data_buf[20], + data_buf[21] + ); + + PrintAndLog("\nADF: User Area"); + + i = 22; + for (n=0; n<64; n++) { + segment_len = ((data_buf[i+1]^crc)&0x0f) * 256 + (data_buf[i]^crc); + segment_flag = ((data_buf[i+1]^crc)&0xf0)>>4; + + wrp = (data_buf[i+2]^crc); + wrc = ((data_buf[i+3]^crc)&0x70)>>4; + + PrintAndLog("Segment %02u: raw header=%02x %02x %02x %02x, flag=%01x (valid=%01u, last=%01u), len=%04u, WRP=%02u, WRC=%02u, RD=%01u, CRC=%02x", + n, + data_buf[i]^crc, + data_buf[i+1]^crc, + data_buf[i+2]^crc, + data_buf[i+3]^crc, + segment_flag, + (segment_flag&0x4)>>2, + (segment_flag&0x8)>>3, + segment_len, + wrp, + wrc, + ((data_buf[i+3]^crc)&0x80)>>7, + (data_buf[i+4]^crc) + ); + + i+=5; + + if (wrc>0) { + PrintAndLog("WRC protected area:"); + for (k=0, j=0; k < wrc && j<(sizeof(out_string)-3); k++, i++, j += 3) { + sprintf(&out_string[j], "%02x", (data_buf[i]^crc)); + out_string[j+2] = ' '; + }; + + out_string[j] = '\0'; + + PrintAndLog("%s", out_string); + } + + if (wrp>wrc) { + PrintAndLog("Remaining write protected area:"); + + for (k=0, j=0; k < (wrp-wrc) && j<(sizeof(out_string)-3); k++, i++, j += 3) { + sprintf(&out_string[j], "%02x", (data_buf[i]^crc)); + out_string[j+2] = ' '; + }; + + out_string[j] = '\0'; + + PrintAndLog("%s", out_string); + if((wrp-wrc) == 8) { + sprintf(out_string,"Card ID: %2X%02X%02X",data_buf[i-4]^crc,data_buf[i-3]^crc,data_buf[i-2]^crc); + PrintAndLog("%s", out_string); + } + } + + PrintAndLog("Remaining segment payload:"); + for (k=0, j=0; k < (segment_len - wrp - 5) && j<(sizeof(out_string)-3); k++, i++, j += 3) { + sprintf(&out_string[j], "%02x", (data_buf[i]^crc)); + out_string[j+2] = ' '; + }; + + out_string[j] = '\0'; + + PrintAndLog("%s", out_string); + + // end with last segment + if (segment_flag & 0x8) + return 0; + }; + return 0; } int CmdLegicRFRead(const char *Cmd) { - int byte_count=0,offset=0; - sscanf(Cmd, "%i %i", &offset, &byte_count); - if(byte_count == 0) byte_count = -1; - if(byte_count + offset > 1024) byte_count = 1024 - offset; - UsbCommand c={CMD_READER_LEGIC_RF, {offset, byte_count, 0}}; - SendCommand(&c); - UsbCommand resp; - WaitForResponse(CMD_ACK,&resp); - switch (resp.arg[0]) { - case 0: - PrintAndLog("Card (MIM %i) read, use 'hf legic decode' or", ((legic_card_select_t*)resp.d.asBytes)->cardsize); - PrintAndLog("'data hexsamples %d' to view results", (resp.arg[1] + 7) & ~7); - break; - case 1: - PrintAndLog("No or unknown card found, aborting"); - break; - case 2: - PrintAndLog("operation failed @ 0x%03.3x", resp.arg[1]); - break; - } - return resp.arg[0]; + int byte_count=0,offset=0; + sscanf(Cmd, "%i %i", &offset, &byte_count); + if(byte_count == 0) byte_count = -1; + if(byte_count + offset > 1024) byte_count = 1024 - offset; + UsbCommand c={CMD_READER_LEGIC_RF, {offset, byte_count, 0}}; + SendCommand(&c); + UsbCommand resp; + WaitForResponse(CMD_ACK,&resp); + switch (resp.arg[0]) { + legic_card_select_t card; + case 0: + memcpy(&card, resp.d.asBytes, sizeof(card)); + PrintAndLog("Card (MIM %i) read, use 'hf legic decode' or", card.cardsize); + PrintAndLog("'data hexsamples %d' to view results", (resp.arg[1] + 7) & ~7); + break; + case 1: + PrintAndLog("No or unknown card found, aborting"); + break; + case 2: + PrintAndLog("operation failed @ 0x%03.3x", resp.arg[1]); + break; + } + return resp.arg[0]; } int CmdLegicLoad(const char *Cmd) { char filename[FILE_PATH_SIZE] = {0x00}; int len = 0; - + if (param_getchar(Cmd, 0) == 'h' || param_getchar(Cmd, 0)== 0x00) { PrintAndLog("It loads datasamples from the file `filename`"); PrintAndLog("Usage: hf legic load "); @@ -244,92 +246,92 @@ int CmdLegicLoad(const char *Cmd) return 0; } - len = strlen(Cmd); + len = strlen(Cmd); if (len > FILE_PATH_SIZE) { PrintAndLog("Filepath too long (was %s bytes), max allowed is %s ", len, FILE_PATH_SIZE); return 0; } memcpy(filename, Cmd, len); - FILE *f = fopen(filename, "r"); - if(!f) { - PrintAndLog("couldn't open '%s'", Cmd); - return -1; - } - char line[80]; int offset = 0; unsigned int data[8]; - while(fgets(line, sizeof(line), f)) { - int res = sscanf(line, "%x %x %x %x %x %x %x %x", - &data[0], &data[1], &data[2], &data[3], - &data[4], &data[5], &data[6], &data[7]); - if(res != 8) { - PrintAndLog("Error: could not read samples"); - fclose(f); - return -1; - } - UsbCommand c={CMD_DOWNLOADED_SIM_SAMPLES_125K, {offset, 1, 0}}; - int j; for(j = 0; j < 8; j++) { - c.d.asBytes[j] = data[j]; - } - SendCommand(&c); - WaitForResponse(CMD_ACK, NULL); - offset += 8; - } - fclose(f); - PrintAndLog("loaded %u samples", offset); - return 0; + FILE *f = fopen(filename, "r"); + if (!f) { + PrintAndLog("couldn't open '%s'", Cmd); + return -1; + } + char line[80]; int offset = 0; unsigned int data[8]; + while (fgets(line, sizeof(line), f)) { + int res = sscanf(line, "%x %x %x %x %x %x %x %x", + &data[0], &data[1], &data[2], &data[3], + &data[4], &data[5], &data[6], &data[7]); + if (res != 8) { + PrintAndLog("Error: could not read samples"); + fclose(f); + return -1; + } + UsbCommand c={CMD_DOWNLOADED_SIM_SAMPLES_125K, {offset, 1, 0}}; + int j; for(j = 0; j < 8; j++) { + c.d.asBytes[j] = data[j]; + } + SendCommand(&c); + WaitForResponse(CMD_ACK, NULL); + offset += 8; + } + fclose(f); + PrintAndLog("loaded %u samples", offset); + return 0; } int CmdLegicSave(const char *Cmd) { - int requested = 1024; - int offset = 0; - int delivered = 0; - char filename[FILE_PATH_SIZE]; - uint8_t got[1024]; - - sscanf(Cmd, " %s %i %i", filename, &requested, &offset); + int requested = 1024; + int offset = 0; + int delivered = 0; + char filename[FILE_PATH_SIZE]; + uint8_t got[1024]; - /* If no length given save entire legic read buffer */ - /* round up to nearest 8 bytes so the saved data can be used with legicload */ - if (requested == 0) { - requested = 1024; - } - if (requested % 8 != 0) { - int remainder = requested % 8; - requested = requested + 8 - remainder; - } - if (offset + requested > sizeof(got)) { - PrintAndLog("Tried to read past end of buffer, + > 1024"); - return 0; - } - - FILE *f = fopen(filename, "w"); - if(!f) { - PrintAndLog("couldn't open '%s'", Cmd+1); - return -1; - } + sscanf(Cmd, " %s %i %i", filename, &requested, &offset); - GetFromBigBuf(got, requested, offset, NULL, -1, false); + /* If no length given save entire legic read buffer */ + /* round up to nearest 8 bytes so the saved data can be used with legicload */ + if (requested == 0) { + requested = 1024; + } + if (requested % 8 != 0) { + int remainder = requested % 8; + requested = requested + 8 - remainder; + } + if (offset + requested > sizeof(got)) { + PrintAndLog("Tried to read past end of buffer, + > 1024"); + return 0; + } - for (int j = 0; j < requested; j += 8) { - fprintf(f, "%02x %02x %02x %02x %02x %02x %02x %02x\n", - got[j+0], - got[j+1], - got[j+2], - got[j+3], - got[j+4], - got[j+5], - got[j+6], - got[j+7] - ); - delivered += 8; - if (delivered >= requested) - break; - } + FILE *f = fopen(filename, "w"); + if (!f) { + PrintAndLog("couldn't open '%s'", Cmd+1); + return -1; + } - fclose(f); - PrintAndLog("saved %u samples", delivered); - return 0; + GetFromBigBuf(got, requested, offset, NULL, -1, false); + + for (int j = 0; j < requested; j += 8) { + fprintf(f, "%02x %02x %02x %02x %02x %02x %02x %02x\n", + got[j+0], + got[j+1], + got[j+2], + got[j+3], + got[j+4], + got[j+5], + got[j+6], + got[j+7] + ); + delivered += 8; + if (delivered >= requested) + break; + } + + fclose(f); + PrintAndLog("saved %u samples", delivered); + return 0; } int CmdLegicRfSim(const char *Cmd) @@ -343,36 +345,36 @@ int CmdLegicRfSim(const char *Cmd) int CmdLegicRfWrite(const char *Cmd) { - UsbCommand c={CMD_WRITER_LEGIC_RF}; - int res = sscanf(Cmd, " 0x%" SCNx64 " 0x%" SCNx64, &c.arg[0], &c.arg[1]); - if(res != 2) { + UsbCommand c={CMD_WRITER_LEGIC_RF}; + int res = sscanf(Cmd, " 0x%" SCNx64 " 0x%" SCNx64, &c.arg[0], &c.arg[1]); + if (res != 2) { PrintAndLog("Please specify the offset and length as two hex strings"); - return -1; - } - SendCommand(&c); - return 0; + return -1; + } + SendCommand(&c); + return 0; } int CmdLegicRfFill(const char *Cmd) { - UsbCommand cmd ={CMD_WRITER_LEGIC_RF}; - int res = sscanf(Cmd, " 0x%" SCNx64 " 0x%" SCNx64 " 0x%" SCNx64, &cmd.arg[0], &cmd.arg[1], &cmd.arg[2]); - if(res != 3) { - PrintAndLog("Please specify the offset, length and value as two hex strings"); - return -1; - } + UsbCommand cmd ={CMD_WRITER_LEGIC_RF}; + int res = sscanf(Cmd, " 0x%" SCNx64 " 0x%" SCNx64 " 0x%" SCNx64, &cmd.arg[0], &cmd.arg[1], &cmd.arg[2]); + if (res != 3) { + PrintAndLog("Please specify the offset, length and value as two hex strings"); + return -1; + } - int i; - UsbCommand c={CMD_DOWNLOADED_SIM_SAMPLES_125K, {0, 1, 0}}; - for(i = 0; i < 48; i++) { - c.d.asBytes[i] = cmd.arg[2]; - } - for(i = 0; i < 22; i++) { - c.arg[0] = i*48; - SendCommand(&c); - WaitForResponse(CMD_ACK,NULL); - } - SendCommand(&cmd); - return 0; + int i; + UsbCommand c={CMD_DOWNLOADED_SIM_SAMPLES_125K, {0, 1, 0}}; + for (i = 0; i < 48; i++) { + c.d.asBytes[i] = cmd.arg[2]; + } + for (i = 0; i < 22; i++) { + c.arg[0] = i*48; + SendCommand(&c); + WaitForResponse(CMD_ACK,NULL); + } + SendCommand(&cmd); + return 0; } From 5f18b0c45dba436e05df637b1b91137ab68cbefb Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Mon, 27 May 2019 07:58:09 +0200 Subject: [PATCH 089/189] add: Home (Pos1) and End key bindings in graph GUI (based on @mcd1992 change on RRG repo) (#823) --- CHANGELOG.md | 1 + client/proxguiqt.cpp | 37 ++++++++++++++++++++++++------------- client/proxguiqt.h | 14 +++++++------- 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a8ee1fe..399f87f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added `hf mfp ndef` `hf mf ndef` parsing NDEF records (Merlok) - Added Mifare Mini, Mifare 2K and 4K support to `hf mf sim` (piwi) - Added Legic detection to `hf search` (dnet) +- Added Home (Pos1) and End key bindings to the plot GUI (based on @mcd1992) ## [v3.1.0][2018-10-10] diff --git a/client/proxguiqt.cpp b/client/proxguiqt.cpp index 30e4c8de..cda90cc0 100644 --- a/client/proxguiqt.cpp +++ b/client/proxguiqt.cpp @@ -34,8 +34,8 @@ extern "C" { bool g_useOverlays = false; int g_absVMax = 0; -int startMax; -int PageWidth; +int startMax; // Maximum offset in the graph (right side of graph) +int PageWidth; // How many samples are currently visible on this 'page' / graph int unlockStart = 0; void ProxGuiQT::ShowGraphWindow(void) @@ -134,8 +134,8 @@ ProxGuiQT::~ProxGuiQT(void) { //if (plotwidget) { //plotwidget->destroy(true,true); - // delete plotwidget; - // plotwidget = NULL; + // delete plotwidget; + // plotwidget = NULL; //} if (plotapp) { plotapp->quit(); @@ -474,7 +474,7 @@ void Plot::plotGridLines(QPainter* painter,QRect r) if ((PlotGridX > 0) && ((PlotGridX * GraphPixelsPerPoint) > 1)) { for(i = (offset * GraphPixelsPerPoint); i < r.right(); i += grid_delta_x) { painter->drawLine(r.left()+i, r.top(), r.left()+i, r.bottom()); - } + } } if (PlotGridY > 0) { for(i = 0; yCoordOf(i,r,g_absVMax) > r.top(); i += grid_delta_y) { @@ -509,8 +509,9 @@ void Plot::paintEvent(QPaintEvent *event) if(CursorDPos > GraphTraceLen) CursorDPos= 0; - QRect plotRect(WIDTH_AXES, 0, width()-WIDTH_AXES, height()-HEIGHT_INFO); - QRect infoRect(0, height()-HEIGHT_INFO, width(), HEIGHT_INFO); + QRect plotRect(WIDTH_AXES, 0, width() - WIDTH_AXES, height() - HEIGHT_INFO); + QRect infoRect(0, height() - HEIGHT_INFO, width(), HEIGHT_INFO); + PageWidth = plotRect.width() / GraphPixelsPerPoint; //Grey background painter.fillRect(rect(), QColor(60, 60, 60)); @@ -529,7 +530,7 @@ void Plot::paintEvent(QPaintEvent *event) //Start painting graph PlotGraph(GraphBuffer, GraphTraceLen,plotRect,infoRect,&painter,0); - if (showDemod && DemodBufferLen > 8) { + if (showDemod && DemodBufferLen > 8) { PlotDemod(DemodBuffer, DemodBufferLen,plotRect,infoRect,&painter,2,g_DemodStartIdx); } if (g_useOverlays) { @@ -564,7 +565,7 @@ void Plot::paintEvent(QPaintEvent *event) //Draw annotations char str[200]; sprintf(str, "@%d dt=%d [%2.2f] zoom=%2.2f CursorAPos=%d CursorBPos=%d GridX=%d GridY=%d (%s) GridXoffset=%d", - GraphStart, CursorBPos - CursorAPos, (CursorBPos - CursorAPos)/CursorScaleFactor, + GraphStart, CursorBPos - CursorAPos, (CursorBPos - CursorAPos)/CursorScaleFactor, GraphPixelsPerPoint,CursorAPos,CursorBPos,PlotGridXdefault,PlotGridYdefault,GridLocked?"Locked":"Unlocked",GridOffset); painter.setPen(QColor(255, 255, 255)); painter.drawText(20, infoRect.bottom() - 3, str); @@ -616,14 +617,14 @@ void Plot::mouseMoveEvent(QMouseEvent *event) void Plot::keyPressEvent(QKeyEvent *event) { - int offset; + int offset; // Left/right movement offset (in sample size) if(event->modifiers() & Qt::ShiftModifier) { if (PlotGridX) offset= PageWidth - (PageWidth % PlotGridX); else offset= PageWidth; - } else + } else if(event->modifiers() & Qt::ControlModifier) offset= 1; else @@ -671,20 +672,22 @@ void Plot::keyPressEvent(QKeyEvent *event) case Qt::Key_H: puts("Plot Window Keystrokes:\n"); puts(" Key Action\n"); + puts(" UP Zoom out"); puts(" DOWN Zoom in"); puts(" G Toggle grid display"); puts(" H Show help"); puts(" L Toggle lock grid relative to samples"); + puts(" Q Hide window"); + puts(" HOME Move to the start of the graph"); + puts(" END Move to the end of the graph"); puts(" LEFT Move left"); puts(" LEFT Move left 1 sample"); puts(" LEFT Page left"); puts(" LEFT-MOUSE-CLICK Set yellow cursor"); - puts(" Q Hide window"); puts(" RIGHT Move right"); puts(" RIGHT Move right 1 sample"); puts(" RIGHT Page right"); puts(" RIGHT-MOUSE-CLICK Set purple cursor"); - puts(" UP Zoom out"); puts(""); puts("Use client window 'data help' for more plot commands\n"); break; @@ -701,6 +704,14 @@ void Plot::keyPressEvent(QKeyEvent *event) master->hide(); break; + case Qt::Key_Home: + GraphStart = 0; + break; + + case Qt::Key_End: + GraphStart = startMax; + break; + default: QWidget::keyPressEvent(event); return; diff --git a/client/proxguiqt.h b/client/proxguiqt.h index 5f7199fc..9677b49c 100644 --- a/client/proxguiqt.h +++ b/client/proxguiqt.h @@ -29,8 +29,8 @@ class Plot: public QWidget { private: QWidget *master; - int GraphStart; - double GraphPixelsPerPoint; + int GraphStart; // Starting point/offset for the left side of the graph + double GraphPixelsPerPoint; // How many visual pixels are between each sample point (x axis) int CursorAPos; int CursorBPos; void PlotGraph(int *buffer, int len, QRect r,QRect r2, QPainter* painter, int graphNum); @@ -73,13 +73,13 @@ class ProxWidget : public QWidget //OpsShow(void); protected: - // void paintEvent(QPaintEvent *event); + // void paintEvent(QPaintEvent *event); void closeEvent(QCloseEvent *event); void showEvent(QShowEvent *event); void hideEvent(QHideEvent *event); - // void mouseMoveEvent(QMouseEvent *event); - // void mousePressEvent(QMouseEvent *event) { mouseMoveEvent(event); } - // void keyPressEvent(QKeyEvent *event); + // void mouseMoveEvent(QMouseEvent *event); + // void mousePressEvent(QMouseEvent *event) { mouseMoveEvent(event); } + // void keyPressEvent(QKeyEvent *event); public slots: void applyOperation(); void stickOperation(); @@ -111,7 +111,7 @@ class ProxGuiQT : public QObject int argc; char **argv; WorkerThread *proxmarkThread; - + public: ProxGuiQT(int argc, char **argv, WorkerThread *wthread); ~ProxGuiQT(void); From 4be9f36ebe31c2ade9754518f848db754a5d0e26 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Tue, 28 May 2019 07:48:55 +0200 Subject: [PATCH 090/189] start updating 'hf mfu' commands (#818) * use PrintAndLogEx() * fix some printouts * some #include refactoring * whitespace --- client/cmdhf14a.h | 13 +- client/cmdhficlass.c | 1 + client/cmdhfmf.c | 1 + client/cmdhfmf.h | 32 -- client/cmdhfmfu.c | 839 +++++++++++++++++++++++-------------------- client/cmdhfmfu.h | 52 +-- client/util.c | 6 +- client/util.h | 1 + 8 files changed, 464 insertions(+), 481 deletions(-) diff --git a/client/cmdhf14a.h b/client/cmdhf14a.h index c4294b4c..d1669f3a 100644 --- a/client/cmdhf14a.h +++ b/client/cmdhf14a.h @@ -16,13 +16,14 @@ #include #include "mifare.h" -int CmdHF14A(const char *Cmd); -int CmdHF14AList(const char *Cmd); -int CmdHF14AMifare(const char *Cmd); -int CmdHF14AReader(const char *Cmd); +extern int CmdHF14A(const char *Cmd); +extern int CmdHF14AMfDbg(const char* cmd); +extern int CmdHF14AList(const char *Cmd); +extern int CmdHF14AMifare(const char *Cmd); +extern int CmdHF14AReader(const char *Cmd); extern int CmdHF14AInfo(const char *Cmd); -int CmdHF14ASim(const char *Cmd); -int CmdHF14ASnoop(const char *Cmd); +extern int CmdHF14ASim(const char *Cmd); +extern int CmdHF14ASnoop(const char *Cmd); extern void DropField(); diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index 55804cf8..a2e31754 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -33,6 +33,7 @@ #include "usb_cmd.h" #include "cmdhfmfu.h" #include "util_posix.h" +#include "cmdhf14a.h" // DropField() static int CmdHelp(const char *Cmd); diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 9284d14c..38b7f988 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -29,6 +29,7 @@ #include "hardnested/hardnested_bf_core.h" #include "cliparser/cliparser.h" #include "cmdhf14a.h" +#include "mifare/mifaredefault.h" #include "mifare/mifare4.h" #include "mifare/mad.h" #include "mifare/ndef.h" diff --git a/client/cmdhfmf.h b/client/cmdhfmf.h index 746fcbc1..d7c981f4 100644 --- a/client/cmdhfmf.h +++ b/client/cmdhfmf.h @@ -11,38 +11,6 @@ #ifndef CMDHFMF_H__ #define CMDHFMF_H__ -#include "mifare/mifaredefault.h" - extern int CmdHFMF(const char *Cmd); -extern int CmdHFMF(const char *Cmd); - -extern int CmdHF14AMfDbg(const char* cmd); -extern int CmdHF14AMfRdBl(const char* cmd); -extern int CmdHF14AMfURdBl(const char* cmd); -extern int CmdHF14AMfRdSc(const char* cmd); -extern int CmdHF14SMfURdCard(const char* cmd); -extern int CmdHF14AMfDump(const char* cmd); -extern int CmdHF14AMfRestore(const char* cmd); -extern int CmdHF14AMfWrBl(const char* cmd); -extern int CmdHF14AMfUWrBl(const char* cmd); -extern int CmdHF14AMfChk(const char* cmd); -extern int CmdHF14AMifare(const char* cmd); -extern int CmdHF14AMfNested(const char* cmd); -extern int CmdHF14AMfSniff(const char* cmd); -extern int CmdHF14AMf1kSim(const char* cmd); -extern int CmdHF14AMfEClear(const char* cmd); -extern int CmdHF14AMfEGet(const char* cmd); -extern int CmdHF14AMfESet(const char* cmd); -extern int CmdHF14AMfELoad(const char* cmd); -extern int CmdHF14AMfESave(const char* cmd); -extern int CmdHF14AMfECFill(const char* cmd); -extern int CmdHF14AMfEKeyPrn(const char* cmd); -extern int CmdHF14AMfCWipe(const char* cmd); -extern int CmdHF14AMfCSetUID(const char* cmd); -extern int CmdHF14AMfCSetBlk(const char* cmd); -extern int CmdHF14AMfCGetBlk(const char* cmd); -extern int CmdHF14AMfCGetSc(const char* cmd); -extern int CmdHF14AMfCLoad(const char* cmd); -extern int CmdHF14AMfCSave(const char* cmd); #endif diff --git a/client/cmdhfmfu.c b/client/cmdhfmfu.c index 9bdc6ce3..dac51be3 100644 --- a/client/cmdhfmfu.c +++ b/client/cmdhfmfu.c @@ -18,11 +18,39 @@ #include "ui.h" #include "mbedtls/des.h" #include "cmdhfmf.h" +#include "cmdhf14a.h" // DropField() #include "mifare.h" #include "util.h" #include "protocols.h" #include "taginfo.h" +typedef enum TAGTYPE_UL { + UNKNOWN = 0x000000, + UL = 0x000001, + UL_C = 0x000002, + UL_EV1_48 = 0x000004, + UL_EV1_128 = 0x000008, + NTAG = 0x000010, + NTAG_203 = 0x000020, + NTAG_210 = 0x000040, + NTAG_212 = 0x000080, + NTAG_213 = 0x000100, + NTAG_215 = 0x000200, + NTAG_216 = 0x000400, + MY_D = 0x000800, + MY_D_NFC = 0x001000, + MY_D_MOVE = 0x002000, + MY_D_MOVE_NFC = 0x004000, + MY_D_MOVE_LEAN= 0x008000, + NTAG_I2C_1K = 0x010000, + NTAG_I2C_2K = 0x020000, + FUDAN_UL = 0x040000, + MAGIC = 0x080000, + UL_MAGIC = UL | MAGIC, + UL_C_MAGIC = UL_C | MAGIC, + UL_ERROR = 0xFFFFFF, +} TagTypeUL_t; + #define MAX_UL_BLOCKS 0x0f #define MAX_ULC_BLOCKS 0x2b #define MAX_ULEV1a_BLOCKS 0x13 @@ -37,57 +65,63 @@ #define MAX_MY_D_MOVE 0x25 #define MAX_MY_D_MOVE_LEAN 0x0f +#define PUBLIC_ECDA_KEYLEN 33 +static uint8_t public_ecda_key[PUBLIC_ECDA_KEYLEN] = { + 0x04, 0x49, 0x4e, 0x1a, 0x38, 0x6d, 0x3d, 0x3c, + 0xfe, 0x3d, 0xc1, 0x0e, 0x5d, 0xe6, 0x8a, 0x49, + 0x9b, 0x1c, 0x20, 0x2d, 0xb5, 0xb1, 0x32, 0x39, + 0x3e, 0x89, 0xed, 0x19, 0xfe, 0x5b, 0xe8, 0xbc, + 0x61 +}; + #define KEYS_3DES_COUNT 7 -uint8_t default_3des_keys[KEYS_3DES_COUNT][16] = { - { 0x42,0x52,0x45,0x41,0x4b,0x4d,0x45,0x49,0x46,0x59,0x4f,0x55,0x43,0x41,0x4e,0x21 },// 3des std key - { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },// all zeroes - { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f },// 0x00-0x0F - { 0x49,0x45,0x4D,0x4B,0x41,0x45,0x52,0x42,0x21,0x4E,0x41,0x43,0x55,0x4F,0x59,0x46 },// NFC-key - { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 },// all ones - { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF },// all FF - { 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF } // 11 22 33 +static uint8_t default_3des_keys[KEYS_3DES_COUNT][16] = { + { 0x42,0x52,0x45,0x41,0x4b,0x4d,0x45,0x49,0x46,0x59,0x4f,0x55,0x43,0x41,0x4e,0x21 },// 3des std key + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },// all zeroes + { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f },// 0x00-0x0F + { 0x49,0x45,0x4D,0x4B,0x41,0x45,0x52,0x42,0x21,0x4E,0x41,0x43,0x55,0x4F,0x59,0x46 },// NFC-key + { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 },// all ones + { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF },// all FF + { 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF } // 11 22 33 }; #define KEYS_PWD_COUNT 6 -uint8_t default_pwd_pack[KEYS_PWD_COUNT][4] = { +static uint8_t default_pwd_pack[KEYS_PWD_COUNT][4] = { {0xFF,0xFF,0xFF,0xFF}, // PACK 0x00,0x00 -- factory default - {0x4A,0xF8,0x4B,0x19}, // PACK 0xE5,0xBE -- italian bus (sniffed) {0x33,0x6B,0xA1,0x19}, // PACK 0x9c,0x2d -- italian bus (sniffed) - {0xFF,0x90,0x6C,0xB2}, // PACK 0x12,0x9e -- italian bus (sniffed) + {0xFF,0x90,0x6C,0xB2}, // PACK 0x12,0x9e -- italian bus (sniffed) {0x46,0x1c,0xA3,0x19}, // PACK 0xE9,0x5A -- italian bus (sniffed) {0x35,0x1C,0xD0,0x19}, // PACK 0x9A,0x5a -- italian bus (sniffed) }; #define MAX_UL_TYPES 18 -uint32_t UL_TYPES_ARRAY[MAX_UL_TYPES] = {UNKNOWN, UL, UL_C, UL_EV1_48, UL_EV1_128, NTAG, NTAG_203, - NTAG_210, NTAG_212, NTAG_213, NTAG_215, NTAG_216, MY_D, MY_D_NFC, MY_D_MOVE, MY_D_MOVE_NFC, MY_D_MOVE_LEAN, FUDAN_UL}; +static uint32_t UL_TYPES_ARRAY[MAX_UL_TYPES] = {UNKNOWN, UL, UL_C, UL_EV1_48, UL_EV1_128, NTAG, NTAG_203, + NTAG_210, NTAG_212, NTAG_213, NTAG_215, NTAG_216, MY_D, MY_D_NFC, MY_D_MOVE, MY_D_MOVE_NFC, MY_D_MOVE_LEAN, FUDAN_UL}; -uint8_t UL_MEMORY_ARRAY[MAX_UL_TYPES] = {MAX_UL_BLOCKS, MAX_UL_BLOCKS, MAX_ULC_BLOCKS, MAX_ULEV1a_BLOCKS, - MAX_ULEV1b_BLOCKS, MAX_NTAG_203, MAX_NTAG_203, MAX_NTAG_210, MAX_NTAG_212, MAX_NTAG_213, - MAX_NTAG_215, MAX_NTAG_216, MAX_UL_BLOCKS, MAX_MY_D_NFC, MAX_MY_D_MOVE, MAX_MY_D_MOVE, MAX_MY_D_MOVE_LEAN, MAX_UL_BLOCKS}; +static uint8_t UL_MEMORY_ARRAY[MAX_UL_TYPES] = {MAX_UL_BLOCKS, MAX_UL_BLOCKS, MAX_ULC_BLOCKS, MAX_ULEV1a_BLOCKS, + MAX_ULEV1b_BLOCKS, MAX_NTAG_203, MAX_NTAG_203, MAX_NTAG_210, MAX_NTAG_212, MAX_NTAG_213, + MAX_NTAG_215, MAX_NTAG_216, MAX_UL_BLOCKS, MAX_MY_D_NFC, MAX_MY_D_MOVE, MAX_MY_D_MOVE, MAX_MY_D_MOVE_LEAN, MAX_UL_BLOCKS}; -static int CmdHelp(const char *Cmd); - -// get version nxp product type -char *getProductTypeStr( uint8_t id){ +// get version nxp product type +static char *getProductTypeStr( uint8_t id){ static char buf[20]; char *retStr = buf; switch(id) { case 3: sprintf(retStr, "%02X, Ultralight", id); break; - case 4: sprintf(retStr, "%02X, NTAG", id); break; + case 4: sprintf(retStr, "%02X, NTAG", id); break; default: sprintf(retStr, "%02X, unknown", id); break; } return buf; } /* - The 7 MSBits (=n) code the storage size itself based on 2^n, + The 7 MSBits (=n) code the storage size itself based on 2^n, the LSBit is set to '0' if the size is exactly 2^n - and set to '1' if the storage size is between 2^n and 2^(n+1). + and set to '1' if the storage size is between 2^n and 2^(n+1). */ char *getUlev1CardSizeStr( uint8_t fsize ){ @@ -101,8 +135,8 @@ char *getUlev1CardSizeStr( uint8_t fsize ){ // is LSB set? if ( fsize & 1 ) sprintf(retStr, "%02X, (%u <-> %u bytes)",fsize, usize, lsize); - else - sprintf(retStr, "%02X, (%u bytes)", fsize, lsize); + else + sprintf(retStr, "%02X, (%u bytes)", fsize, lsize); return buf; } @@ -131,7 +165,7 @@ static int ul_send_cmd_raw_crc( uint8_t *cmd, uint8_t cmdlen, uint8_t *response, if (append_crc) c.arg[0] |= ISO14A_APPEND_CRC; - memcpy(c.d.asBytes, cmd, cmdlen); + memcpy(c.d.asBytes, cmd, cmdlen); clearCommandBuffer(); SendCommand(&c); UsbCommand resp; @@ -151,7 +185,7 @@ static int ul_select( iso14a_card_select_t *card ){ bool ans = false; ans = WaitForResponseTimeout(CMD_ACK, &resp, 1500); if (!ans || resp.arg[0] < 1) { - PrintAndLog("iso14443a card select failed"); + PrintAndLogEx(WARNING, "iso14443a card select failed"); DropField(); return 0; } @@ -217,7 +251,7 @@ static int ul_auth_select( iso14a_card_select_t *card, TagTypeUL_t tagtype, bool if ( hasAuthKey && (tagtype & UL_C)) { //will select card automatically and close connection on error if (!ulc_authentication(authenticationkey, false)) { - PrintAndLog("Error: Authentication Failed UL-C"); + PrintAndLogEx(WARNING, "Authentication Failed UL-C"); return 0; } } else { @@ -226,7 +260,7 @@ static int ul_auth_select( iso14a_card_select_t *card, TagTypeUL_t tagtype, bool if (hasAuthKey) { if (ulev1_requestAuthentication(authenticationkey, pack, packSize) < 1) { DropField(); - PrintAndLog("Error: Authentication Failed UL-EV1/NTAG"); + PrintAndLogEx(WARNING, "Authentication Failed UL-EV1/NTAG"); return 0; } } @@ -236,15 +270,15 @@ static int ul_auth_select( iso14a_card_select_t *card, TagTypeUL_t tagtype, bool static int ulev1_getVersion( uint8_t *response, uint16_t responseLength ){ - uint8_t cmd[] = {MIFARE_ULEV1_VERSION}; + uint8_t cmd[] = {MIFARE_ULEV1_VERSION}; int len = ul_send_cmd_raw(cmd, sizeof(cmd), response, responseLength); return len; } // static int ulev1_fastRead( uint8_t startblock, uint8_t endblock, uint8_t *response ){ - + // uint8_t cmd[] = {MIFARE_ULEV1_FASTREAD, startblock, endblock}; - + // if ( !ul_send_cmd_raw(cmd, sizeof(cmd), response)){ // return -1; // } @@ -276,7 +310,7 @@ static int ulev1_readSignature( uint8_t *response, uint16_t responseLength ){ // Fudan check checks for which error is given for a command with incorrect crc // NXP UL chip responds with 01, fudan 00. // other possible checks: -// send a0 + crc +// send a0 + crc // UL responds with 00, fudan doesn't respond // or // send a200 + crc @@ -288,7 +322,7 @@ static int ulev1_readSignature( uint8_t *response, uint16_t responseLength ){ // make sure field is off before calling this function static int ul_fudan_check( void ){ iso14a_card_select_t card; - if ( !ul_select(&card) ) + if ( !ul_select(&card) ) return UL_ERROR; UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_NO_DISCONNECT, 4, 0}}; @@ -315,39 +349,43 @@ static int ul_print_default( uint8_t *data){ uid[5] = data[6]; uid[6] = data[7]; - PrintAndLog(" UID : %s ", sprint_hex(uid, 7)); - PrintAndLog(" UID[0] : %02X, %s", uid[0], getManufacturerName(uid[0])); + PrintAndLogEx(NORMAL," UID : %s ", sprint_hex(uid, 7)); + PrintAndLogEx(NORMAL," UID[0] : %02X, %s", uid[0], getManufacturerName(uid[0])); if ( uid[0] == 0x05 && ((uid[1] & 0xf0) >> 4) == 2 ) { // is infineon and 66RxxP uint8_t chip = (data[8] & 0xC7); // 11000111 mask, bit 3,4,5 RFU switch (chip){ - case 0xc2: PrintAndLog(" IC type : SLE 66R04P 770 Bytes"); break; //77 pages - case 0xc4: PrintAndLog(" IC type : SLE 66R16P 2560 Bytes"); break; //256 pages - case 0xc6: PrintAndLog(" IC type : SLE 66R32P 5120 Bytes"); break; //512 pages /2 sectors + case 0xc2: PrintAndLogEx(NORMAL, " IC type : SLE 66R04P 770 Bytes"); break; //77 pages + case 0xc4: PrintAndLogEx(NORMAL, " IC type : SLE 66R16P 2560 Bytes"); break; //256 pages + case 0xc6: PrintAndLogEx(NORMAL, " IC type : SLE 66R32P 5120 Bytes"); break; //512 pages /2 sectors } } - // CT (cascade tag byte) 0x88 xor SN0 xor SN1 xor SN2 + // CT (cascade tag byte) 0x88 xor SN0 xor SN1 xor SN2 int crc0 = 0x88 ^ data[0] ^ data[1] ^data[2]; if ( data[3] == crc0 ) - PrintAndLog(" BCC0 : %02X, Ok", data[3]); + PrintAndLogEx(NORMAL, " BCC0 : %02X, Ok", data[3]); else - PrintAndLog(" BCC0 : %02X, crc should be %02X", data[3], crc0); + PrintAndLogEx(NORMAL, " BCC0 : %02X, crc should be %02X", data[3], crc0); int crc1 = data[4] ^ data[5] ^ data[6] ^data[7]; if ( data[8] == crc1 ) - PrintAndLog(" BCC1 : %02X, Ok", data[8]); + PrintAndLogEx(NORMAL, " BCC1 : %02X, Ok", data[8]); else - PrintAndLog(" BCC1 : %02X, crc should be %02X", data[8], crc1 ); + PrintAndLogEx(NORMAL, " BCC1 : %02X, crc should be %02X", data[8], crc1 ); - PrintAndLog(" Internal : %02X, %sdefault", data[9], (data[9]==0x48)?"":"not " ); + PrintAndLogEx(NORMAL, " Internal : %02X, %sdefault", data[9], (data[9]==0x48)?"":"not " ); - PrintAndLog(" Lock : %s - %s", + PrintAndLogEx(NORMAL, " Lock : %s (binary %s %s)", sprint_hex(data+10, 2), - printBits(2, data+10) + printBits(1, data+10), + printBits(1, data+11) ); - PrintAndLog("OneTimePad : %s - %s\n", + PrintAndLogEx(NORMAL, "OneTimePad : %s (binary %s %s %s %s)\n", sprint_hex(data + 12, 4), - printBits(4, data+12) + printBits(1, data+12), + printBits(1, data+13), + printBits(1, data+14), + printBits(1, data+15) ); return 0; @@ -358,20 +396,20 @@ static int ndef_print_CC(uint8_t *data) { if(data[0] != 0xe1) return -1; - PrintAndLog("--- NDEF Message"); - PrintAndLog("Capability Container: %s", sprint_hex(data,4) ); - PrintAndLog(" %02X : NDEF Magic Number", data[0]); - PrintAndLog(" %02X : version %d.%d supported by tag", data[1], (data[1] & 0xF0) >> 4, data[1] & 0x0f); - PrintAndLog(" %02X : Physical Memory Size: %d bytes", data[2], (data[2] + 1) * 8); + PrintAndLogEx(NORMAL, "--- NDEF Message"); + PrintAndLogEx(NORMAL, "Capability Container: %s", sprint_hex(data,4) ); + PrintAndLogEx(NORMAL, " %02X : NDEF Magic Number", data[0]); + PrintAndLogEx(NORMAL, " %02X : version %d.%d supported by tag", data[1], (data[1] & 0xF0) >> 4, data[1] & 0x0f); + PrintAndLogEx(NORMAL, " %02X : Physical Memory Size: %d bytes", data[2], (data[2] + 1) * 8); if ( data[2] == 0x12 ) - PrintAndLog(" %02X : NDEF Memory Size: %d bytes", data[2], 144); + PrintAndLogEx(NORMAL, " %02X : NDEF Memory Size: %d bytes", data[2], 144); else if ( data[2] == 0x3e ) - PrintAndLog(" %02X : NDEF Memory Size: %d bytes", data[2], 496); + PrintAndLogEx(NORMAL, " %02X : NDEF Memory Size: %d bytes", data[2], 496); else if ( data[2] == 0x6d ) - PrintAndLog(" %02X : NDEF Memory Size: %d bytes", data[2], 872); + PrintAndLogEx(NORMAL, " %02X : NDEF Memory Size: %d bytes", data[2], 872); - PrintAndLog(" %02X : %s / %s", data[3], - (data[3] & 0xF0) ? "(RFU)" : "Read access granted without any security", + PrintAndLogEx(NORMAL, " %02X : %s / %s", data[3], + (data[3] & 0xF0) ? "(RFU)" : "Read access granted without any security", (data[3] & 0x0F)==0 ? "Write access granted without any security" : (data[3] & 0x0F)==0x0F ? "No write access granted at all" : "(RFU)"); return 0; } @@ -381,75 +419,85 @@ int ul_print_type(uint32_t tagtype, uint8_t spaces){ spc[10]=0x00; char *spacer = spc + (10-spaces); - if ( tagtype & UL ) - PrintAndLog("%sTYPE : MIFARE Ultralight (MF0ICU1) %s", spacer, (tagtype & MAGIC) ? "" : "" ); + if ( tagtype & UL ) + PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight (MF0ICU1) %s", spacer, (tagtype & MAGIC) ? "" : "" ); else if ( tagtype & UL_C) - PrintAndLog("%sTYPE : MIFARE Ultralight C (MF0ULC) %s", spacer, (tagtype & MAGIC) ? "" : "" ); + PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight C (MF0ULC) %s", spacer, (tagtype & MAGIC) ? "" : "" ); else if ( tagtype & UL_EV1_48) - PrintAndLog("%sTYPE : MIFARE Ultralight EV1 48bytes (MF0UL1101)", spacer); - else if ( tagtype & UL_EV1_128) - PrintAndLog("%sTYPE : MIFARE Ultralight EV1 128bytes (MF0UL2101)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight EV1 48bytes (MF0UL1101)", spacer); + else if ( tagtype & UL_EV1_128) + PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight EV1 128bytes (MF0UL2101)", spacer); else if ( tagtype & NTAG ) - PrintAndLog("%sTYPE : NTAG UNKNOWN", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : NTAG UNKNOWN", spacer); else if ( tagtype & NTAG_203 ) - PrintAndLog("%sTYPE : NTAG 203 144bytes (NT2H0301F0DT)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : NTAG 203 144bytes (NT2H0301F0DT)", spacer); else if ( tagtype & NTAG_210 ) - PrintAndLog("%sTYPE : NTAG 210 48bytes (NT2L1011G0DU)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : NTAG 210 48bytes (NT2L1011G0DU)", spacer); else if ( tagtype & NTAG_212 ) - PrintAndLog("%sTYPE : NTAG 212 128bytes (NT2L1211G0DU)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : NTAG 212 128bytes (NT2L1211G0DU)", spacer); else if ( tagtype & NTAG_213 ) - PrintAndLog("%sTYPE : NTAG 213 144bytes (NT2H1311G0DU)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : NTAG 213 144bytes (NT2H1311G0DU)", spacer); else if ( tagtype & NTAG_215 ) - PrintAndLog("%sTYPE : NTAG 215 504bytes (NT2H1511G0DU)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : NTAG 215 504bytes (NT2H1511G0DU)", spacer); else if ( tagtype & NTAG_216 ) - PrintAndLog("%sTYPE : NTAG 216 888bytes (NT2H1611G0DU)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : NTAG 216 888bytes (NT2H1611G0DU)", spacer); else if ( tagtype & NTAG_I2C_1K ) - PrintAndLog("%sTYPE : NTAG I%sC 888bytes (NT3H1101FHK)", spacer, "\xFD"); - else if ( tagtype & NTAG_I2C_2K ) - PrintAndLog("%sTYPE : NTAG I%sC 1904bytes (NT3H1201FHK)", spacer, "\xFD"); + PrintAndLogEx(NORMAL, "%sTYPE : NTAG I%sC 888bytes (NT3H1101FHK)", spacer, "\xFD"); + else if ( tagtype & NTAG_I2C_2K ) + PrintAndLogEx(NORMAL, "%sTYPE : NTAG I%sC 1904bytes (NT3H1201FHK)", spacer, "\xFD"); else if ( tagtype & MY_D ) - PrintAndLog("%sTYPE : INFINEON my-d\x99 (SLE 66RxxS)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 (SLE 66RxxS)", spacer); else if ( tagtype & MY_D_NFC ) - PrintAndLog("%sTYPE : INFINEON my-d\x99 NFC (SLE 66RxxP)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 NFC (SLE 66RxxP)", spacer); else if ( tagtype & MY_D_MOVE ) - PrintAndLog("%sTYPE : INFINEON my-d\x99 move (SLE 66R01P)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 move (SLE 66R01P)", spacer); else if ( tagtype & MY_D_MOVE_NFC ) - PrintAndLog("%sTYPE : INFINEON my-d\x99 move NFC (SLE 66R01P)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 move NFC (SLE 66R01P)", spacer); else if ( tagtype & MY_D_MOVE_LEAN ) - PrintAndLog("%sTYPE : INFINEON my-d\x99 move lean (SLE 66R01L)", spacer); + PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 move lean (SLE 66R01L)", spacer); else if ( tagtype & FUDAN_UL ) - PrintAndLog("%sTYPE : FUDAN Ultralight Compatible (or other compatible) %s", spacer, (tagtype & MAGIC) ? "" : "" ); + PrintAndLogEx(NORMAL, "%sTYPE : FUDAN Ultralight Compatible (or other compatible) %s", spacer, (tagtype & MAGIC) ? "" : "" ); else - PrintAndLog("%sTYPE : Unknown %06x", spacer, tagtype); + PrintAndLogEx(NORMAL, "%sTYPE : Unknown %06x", spacer, tagtype); return 0; } static int ulc_print_3deskey( uint8_t *data){ - PrintAndLog(" deskey1 [44/0x2C] : %s [%.4s]", sprint_hex(data ,4),data); - PrintAndLog(" deskey1 [45/0x2D] : %s [%.4s]", sprint_hex(data+4 ,4),data+4); - PrintAndLog(" deskey2 [46/0x2E] : %s [%.4s]", sprint_hex(data+8 ,4),data+8); - PrintAndLog(" deskey2 [47/0x2F] : %s [%.4s]", sprint_hex(data+12,4),data+12); - PrintAndLog("\n 3des key : %s", sprint_hex(SwapEndian64(data, 16, 8), 16)); + PrintAndLogEx(NORMAL, " deskey1 [44/0x2C] : %s [%.4s]", sprint_hex(data ,4),data); + PrintAndLogEx(NORMAL, " deskey1 [45/0x2D] : %s [%.4s]", sprint_hex(data+4 ,4),data+4); + PrintAndLogEx(NORMAL, " deskey2 [46/0x2E] : %s [%.4s]", sprint_hex(data+8 ,4),data+8); + PrintAndLogEx(NORMAL, " deskey2 [47/0x2F] : %s [%.4s]", sprint_hex(data+12,4),data+12); + PrintAndLogEx(NORMAL, "\n 3des key : %s", sprint_hex(SwapEndian64(data, 16, 8), 16)); return 0; } static int ulc_print_configuration( uint8_t *data){ - PrintAndLog("--- UL-C Configuration"); - PrintAndLog(" Higher Lockbits [40/0x28] : %s - %s", sprint_hex(data, 4), printBits(2, data)); - PrintAndLog(" Counter [41/0x29] : %s - %s", sprint_hex(data+4, 4), printBits(2, data+4)); + PrintAndLogEx(NORMAL, "--- UL-C Configuration"); + PrintAndLogEx(NORMAL, " Higher Lockbits [40/0x28] : %s (binary %s %s)", + sprint_hex(data, 2), + printBits(1, data), + printBits(1, data+1) + ); + PrintAndLogEx(NORMAL, " Counter [41/0x29] : %s (binary %s %s %s %s)", + sprint_hex(data+4, 4), + printBits(1, data+4), + printBits(1, data+5), + printBits(1, data+6), + printBits(1, data+7) + ); bool validAuth = (data[8] >= 0x03 && data[8] <= 0x30); if ( validAuth ) - PrintAndLog(" Auth0 [42/0x2A] : %s page %d/0x%02X and above need authentication", sprint_hex(data+8, 4), data[8],data[8] ); + PrintAndLogEx(NORMAL, " Auth0 [42/0x2A] : %s page %d/0x%02X and above need authentication", sprint_hex(data+8, 4), data[8], data[8] ); else{ if ( data[8] == 0){ - PrintAndLog(" Auth0 [42/0x2A] : %s default", sprint_hex(data+8, 4) ); + PrintAndLogEx(NORMAL, " Auth0 [42/0x2A] : %s default", sprint_hex(data+8, 4) ); } else { - PrintAndLog(" Auth0 [42/0x2A] : %s auth byte is out-of-range", sprint_hex(data+8, 4) ); + PrintAndLogEx(NORMAL, " Auth0 [42/0x2A] : %s auth byte is out-of-range", sprint_hex(data+8, 4) ); } } - PrintAndLog(" Auth1 [43/0x2B] : %s %s", + PrintAndLogEx(NORMAL, " Auth1 [43/0x2B] : %s %s", sprint_hex(data+12, 4), (data[12] & 1) ? "write access restricted": "read and write access restricted" ); @@ -458,7 +506,7 @@ static int ulc_print_configuration( uint8_t *data){ static int ulev1_print_configuration( uint8_t *data, uint8_t startPage){ - PrintAndLog("\n--- Tag Configuration"); + PrintAndLogEx(NORMAL, "\n--- Tag Configuration"); bool strg_mod_en = (data[0] & 2); uint8_t authlim = (data[4] & 0x07); @@ -466,28 +514,28 @@ static int ulev1_print_configuration( uint8_t *data, uint8_t startPage){ bool prot = (data[4] & 0x80); uint8_t vctid = data[5]; - PrintAndLog(" cfg0 [%u/0x%02X] : %s", startPage, startPage, sprint_hex(data, 4)); + PrintAndLogEx(NORMAL, " cfg0 [%u/0x%02X] : %s", startPage, startPage, sprint_hex(data, 4)); if ( data[3] < 0xff ) - PrintAndLog(" - page %d and above need authentication",data[3]); - else - PrintAndLog(" - pages don't need authentication"); - PrintAndLog(" - strong modulation mode %s", (strg_mod_en) ? "enabled":"disabled"); - PrintAndLog(" cfg1 [%u/0x%02X] : %s", startPage + 1, startPage + 1, sprint_hex(data+4, 4) ); - if ( authlim == 0) - PrintAndLog(" - Unlimited password attempts"); + PrintAndLogEx(NORMAL, " - page %d and above need authentication",data[3]); else - PrintAndLog(" - Max number of password attempts is %d", authlim); - PrintAndLog(" - user configuration %s", cfglck ? "permanently locked":"writeable"); - PrintAndLog(" - %s access is protected with password", prot ? "read and write":"write"); - PrintAndLog(" - %02X, Virtual Card Type Identifier is %s default", vctid, (vctid==0x05)? "":"not"); - PrintAndLog(" PWD [%u/0x%02X] : %s- (cannot be read)", startPage + 2, startPage + 2, sprint_hex(data+8, 4)); - PrintAndLog(" PACK [%u/0x%02X] : %s - (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data+12, 2)); - PrintAndLog(" RFU [%u/0x%02X] : %s- (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data+12, 2)); + PrintAndLogEx(NORMAL, " - pages don't need authentication"); + PrintAndLogEx(NORMAL, " - strong modulation mode %s", (strg_mod_en) ? "enabled" : "disabled"); + PrintAndLogEx(NORMAL, " cfg1 [%u/0x%02X] : %s", startPage + 1, startPage + 1, sprint_hex(data+4, 4) ); + if ( authlim == 0) + PrintAndLogEx(NORMAL, " - Unlimited password attempts"); + else + PrintAndLogEx(NORMAL, " - Max number of password attempts is %d", authlim); + PrintAndLogEx(NORMAL, " - user configuration %s", cfglck ? "permanently locked":"writeable"); + PrintAndLogEx(NORMAL, " - %s access is protected with password", prot ? "read and write":"write"); + PrintAndLogEx(NORMAL, " - %02X, Virtual Card Type Identifier is %s default", vctid, (vctid==0x05)? "":"not"); + PrintAndLogEx(NORMAL, " PWD [%u/0x%02X] : %s- (cannot be read)", startPage + 2, startPage + 2, sprint_hex(data+8, 4)); + PrintAndLogEx(NORMAL, " PACK [%u/0x%02X] : %s - (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data+12, 2)); + PrintAndLogEx(NORMAL, " RFU [%u/0x%02X] : %s- (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data+14, 2)); return 0; } static int ulev1_print_counters(){ - PrintAndLog("--- Tag Counters"); + PrintAndLogEx(NORMAL, "--- Tag Counters"); uint8_t tear[1] = {0}; uint8_t counter[3] = {0,0,0}; uint16_t len = 0; @@ -495,34 +543,34 @@ static int ulev1_print_counters(){ ulev1_readTearing(i,tear,sizeof(tear)); len = ulev1_readCounter(i,counter, sizeof(counter) ); if (len == 3) { - PrintAndLog(" [%0d] : %s", i, sprint_hex(counter,3)); - PrintAndLog(" - %02X tearing %s", tear[0], ( tear[0]==0xBD)?"Ok":"failure"); + PrintAndLogEx(NORMAL, " [%0d] : %s", i, sprint_hex(counter,3)); + PrintAndLogEx(NORMAL, " - %02X tearing %s", tear[0], ( tear[0]==0xBD)?"Ok":"failure"); } } return len; } static int ulev1_print_signature( uint8_t *data, uint8_t len){ - PrintAndLog("\n--- Tag Signature"); - //PrintAndLog("IC signature public key name : NXP NTAG21x 2013"); // don't know if there is other NXP public keys.. :( - PrintAndLog("IC signature public key value : 04494e1a386d3d3cfe3dc10e5de68a499b1c202db5b132393e89ed19fe5be8bc61"); - PrintAndLog(" Elliptic curve parameters : secp128r1"); - PrintAndLog(" Tag ECC Signature : %s", sprint_hex(data, len)); + PrintAndLogEx(NORMAL, "\n--- Tag Signature"); + PrintAndLogEx(NORMAL, "IC signature public key name : NXP NTAG21x (2013)"); + PrintAndLogEx(NORMAL, "IC signature public key value : %s", sprint_hex(public_ecda_key, PUBLIC_ECDA_KEYLEN)); + PrintAndLogEx(NORMAL, " Elliptic curve parameters : secp128r1"); + PrintAndLogEx(NORMAL, " Tag ECC Signature : %s", sprint_hex(data, len)); //to do: verify if signature is valid - //PrintAndLog("IC signature status: %s valid", (iseccvalid() )?"":"not"); + //PrintAndLogEx(NORMAL, "IC signature status: %s valid", (iseccvalid() )?"":"not"); return 0; } static int ulev1_print_version(uint8_t *data){ - PrintAndLog("\n--- Tag Version"); - PrintAndLog(" Raw bytes : %s",sprint_hex(data, 8) ); - PrintAndLog(" Vendor ID : %02X, %s", data[1], getManufacturerName(data[1])); - PrintAndLog(" Product type : %s", getProductTypeStr(data[2])); - PrintAndLog(" Product subtype : %02X, %s", data[3], (data[3]==1) ?"17 pF":"50pF"); - PrintAndLog(" Major version : %02X", data[4]); - PrintAndLog(" Minor version : %02X", data[5]); - PrintAndLog(" Size : %s", getUlev1CardSizeStr(data[6])); - PrintAndLog(" Protocol type : %02X", data[7]); + PrintAndLogEx(NORMAL, "\n--- Tag Version"); + PrintAndLogEx(NORMAL, " Raw bytes : %s",sprint_hex(data, 8) ); + PrintAndLogEx(NORMAL, " Vendor ID : %02X, %s", data[1], getManufacturerName(data[1])); + PrintAndLogEx(NORMAL, " Product type : %s", getProductTypeStr(data[2])); + PrintAndLogEx(NORMAL, " Product subtype : %02X, %s", data[3], (data[3]==1) ?"17 pF":"50pF"); + PrintAndLogEx(NORMAL, " Major version : %02X", data[4]); + PrintAndLogEx(NORMAL, " Minor version : %02X", data[5]); + PrintAndLogEx(NORMAL, " Size : %s", getUlev1CardSizeStr(data[6])); + PrintAndLogEx(NORMAL, " Protocol type : %02X", data[7]); return 0; } @@ -548,7 +596,7 @@ static int ulc_magic_test(){ returnValue = ( !memcmp(nonce1, nonce2, 11) ) ? UL_C_MAGIC : UL_C; } else { returnValue = UL; - } + } DropField(); return returnValue; } @@ -556,14 +604,14 @@ static int ulc_magic_test(){ static int ul_magic_test(){ // Magic Ultralight tests - // 1) take present UID, and try to write it back. OBSOLETE + // 1) take present UID, and try to write it back. OBSOLETE // 2) make a wrong length write to page0, and see if tag answers with ACK/NACK: iso14a_card_select_t card; - if ( !ul_select(&card) ) + if ( !ul_select(&card) ) return UL_ERROR; int status = ul_comp_write(0, NULL, 0); DropField(); - if ( status == 0 ) + if ( status == 0 ) return MAGIC; return 0; } @@ -578,9 +626,9 @@ uint32_t GetHF14AMfU_Type(void){ if (!ul_select(&card)) return UL_ERROR; - // Ultralight - ATQA / SAK + // Ultralight - ATQA / SAK if ( card.atqa[1] != 0x00 || card.atqa[0] != 0x44 || card.sak != 0x00 ) { - PrintAndLog("Tag is not Ultralight | NTAG | MY-D [ATQA: %02X %02X SAK: %02X]\n", card.atqa[1], card.atqa[0], card.sak); + PrintAndLogEx(NORMAL, "Tag is not Ultralight | NTAG | MY-D [ATQA: %02X %02X SAK: %02X]\n", card.atqa[1], card.atqa[0], card.sak); DropField(); return UL_ERROR; } @@ -631,7 +679,7 @@ uint32_t GetHF14AMfU_Type(void){ DropField(); if (status > 1) { tagtype = UL_C; - } else { + } else { // need to re-select after authentication error if ( !ul_select(&card) ) return UL_ERROR; @@ -653,18 +701,18 @@ uint32_t GetHF14AMfU_Type(void){ } } if (tagtype & UL) { - tagtype = ul_fudan_check(); + tagtype = ul_fudan_check(); DropField(); } } else { DropField(); - // Infinition MY-D tests Exam high nibble + // Infinition MY-D tests Exam high nibble uint8_t nib = (card.uid[1] & 0xf0) >> 4; switch ( nib ){ // case 0: tagtype = SLE66R35E7; break; //or SLE 66R35E7 - mifare compat... should have different sak/atqa for mf 1k - case 1: tagtype = MY_D; break; //or SLE 66RxxS ... up to 512 pages of 8 user bytes... - case 2: tagtype = (MY_D_NFC); break; //or SLE 66RxxP ... up to 512 pages of 8 user bytes... (or in nfc mode FF pages of 4 bytes) - case 3: tagtype = (MY_D_MOVE | MY_D_MOVE_NFC); break; //or SLE 66R01P // 38 pages of 4 bytes //notice: we can not currently distinguish between these two + case 1: tagtype = MY_D; break; //or SLE 66RxxS ... up to 512 pages of 8 user bytes... + case 2: tagtype = (MY_D_NFC); break; //or SLE 66RxxP ... up to 512 pages of 8 user bytes... (or in nfc mode FF pages of 4 bytes) + case 3: tagtype = (MY_D_MOVE | MY_D_MOVE_NFC); break; //or SLE 66R01P // 38 pages of 4 bytes //notice: we can not currently distinguish between these two case 7: tagtype = MY_D_MOVE_LEAN; break; //or SLE 66R01L // 16 pages of 4 bytes } } @@ -674,7 +722,25 @@ uint32_t GetHF14AMfU_Type(void){ return tagtype; } -int CmdHF14AMfUInfo(const char *Cmd){ +static int usage_hf_mfu_info(void) { + PrintAndLogEx(NORMAL, "It gathers information about the tag and tries to detect what kind it is."); + PrintAndLogEx(NORMAL, "Sometimes the tags are locked down, and you may need a key to be able to read the information"); + PrintAndLogEx(NORMAL, "The following tags can be identified:\n"); + PrintAndLogEx(NORMAL, "Ultralight, Ultralight-C, Ultralight EV1, NTAG 203, NTAG 210,"); + PrintAndLogEx(NORMAL, "NTAG 212, NTAG 213, NTAG 215, NTAG 216, NTAG I2C 1K & 2K"); + PrintAndLogEx(NORMAL, "my-d, my-d NFC, my-d move, my-d move NFC\n"); + PrintAndLogEx(NORMAL, "Usage: hf mfu info k l"); + PrintAndLogEx(NORMAL, " Options : "); + PrintAndLogEx(NORMAL, " k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); + PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, " sample : hf mfu info"); + PrintAndLogEx(NORMAL, " : hf mfu info k 00112233445566778899AABBCCDDEEFF"); + PrintAndLogEx(NORMAL, " : hf mfu info k AABBCCDDD"); + return 0; +} + +static int CmdHF14AMfUInfo(const char *Cmd){ uint8_t authlim = 0xff; uint8_t data[16] = {0x00}; @@ -688,7 +754,7 @@ int CmdHF14AMfUInfo(const char *Cmd){ uint8_t dataLen = 0; uint8_t authenticationkey[16] = {0x00}; uint8_t *authkeyptr = authenticationkey; - uint8_t *key; + uint8_t *key; uint8_t pack[4] = {0,0,0,0}; int len = 0; char tempStr[50]; @@ -707,7 +773,7 @@ int CmdHF14AMfUInfo(const char *Cmd){ errors = param_gethex(tempStr, 0, authenticationkey, dataLen); dataLen /= 2; // handled as bytes from now on } else { - PrintAndLog("\nERROR: Key is incorrect length\n"); + PrintAndLogEx(ERR, "Key has incorrect length\n"); errors = true; } cmdp += 2; @@ -719,7 +785,7 @@ int CmdHF14AMfUInfo(const char *Cmd){ cmdp++; break; default: - PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; break; } @@ -732,11 +798,11 @@ int CmdHF14AMfUInfo(const char *Cmd){ TagTypeUL_t tagtype = GetHF14AMfU_Type(); if (tagtype == UL_ERROR) return -1; - PrintAndLog("\n--- Tag Information ---------"); - PrintAndLog("-------------------------------------------------------------"); + PrintAndLogEx(NORMAL, "\n--- Tag Information ---------"); + PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); ul_print_type(tagtype, 6); - // Swap endianness + // Swap endianness if (swapEndian && hasAuthKey) authkeyptr = SwapEndian64(authenticationkey, dataLen, (dataLen == 16) ? 8 : 4 ); if (!ul_auth_select( &card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack))) return -1; @@ -745,7 +811,7 @@ int CmdHF14AMfUInfo(const char *Cmd){ status = ul_read(0, data, sizeof(data)); if ( status == -1 ) { DropField(); - PrintAndLog("Error: tag didn't answer to READ"); + PrintAndLogEx(WARNING, "Error: tag didn't answer to READ"); return status; } else if (status == 16) { ul_print_default(data); @@ -761,10 +827,10 @@ int CmdHF14AMfUInfo(const char *Cmd){ uint8_t ulc_conf[16] = {0x00}; status = ul_read(0x28, ulc_conf, sizeof(ulc_conf)); if ( status == -1 ){ - PrintAndLog("Error: tag didn't answer to READ UL-C"); + PrintAndLogEx(WARNING, "Error: tag didn't answer to READ UL-C"); DropField(); return status; - } + } if (status == 16) ulc_print_configuration(ulc_conf); else locked = true; @@ -774,33 +840,33 @@ int CmdHF14AMfUInfo(const char *Cmd){ status = ul_read(0x2C, ulc_deskey, sizeof(ulc_deskey)); if ( status == -1 ) { DropField(); - PrintAndLog("Error: tag didn't answer to READ magic"); + PrintAndLogEx(WARNING, "Error: tag didn't answer to READ magic"); return status; } if (status == 16) ulc_print_3deskey(ulc_deskey); } else { DropField(); - // if we called info with key, just return + // if we called info with key, just return if ( hasAuthKey ) return 1; // also try to diversify default keys.. look into CmdHF14AMfuGenDiverseKeys - PrintAndLog("Trying some default 3des keys"); + PrintAndLogEx(INFO, "Trying some default 3des keys"); for (uint8_t i = 0; i < KEYS_3DES_COUNT; ++i ) { key = default_3des_keys[i]; if (ulc_authentication(key, true)) { - PrintAndLog("Found default 3des key: "); + PrintAndLogEx(SUCCESS, "Found default 3des key: "); uint8_t keySwap[16]; memcpy(keySwap, SwapEndian64(key,16,8), 16); ulc_print_3deskey(keySwap); return 1; - } + } } return 1; } } - // do counters and signature first (don't neet auth) + // do counters and signature first (don't neet auth) // ul counters are different than ntag counters if ((tagtype & (UL_EV1_48 | UL_EV1_128))) { @@ -810,11 +876,11 @@ int CmdHF14AMfUInfo(const char *Cmd){ } } - if ((tagtype & (UL_EV1_48 | UL_EV1_128 | NTAG_213 | NTAG_215 | NTAG_216 | NTAG_I2C_1K | NTAG_I2C_2K ))) { + if ((tagtype & (UL_EV1_48 | UL_EV1_128 | NTAG_213 | NTAG_215 | NTAG_216 | NTAG_I2C_1K | NTAG_I2C_2K ))) { uint8_t ulev1_signature[32] = {0x00}; status = ulev1_readSignature( ulev1_signature, sizeof(ulev1_signature)); if ( status == -1 ) { - PrintAndLog("Error: tag didn't answer to READ SIGNATURE"); + PrintAndLogEx(WARNING, "Error: tag didn't answer to READ SIGNATURE"); DropField(); return status; } @@ -829,7 +895,7 @@ int CmdHF14AMfUInfo(const char *Cmd){ uint8_t version[10] = {0x00}; status = ulev1_getVersion(version, sizeof(version)); if ( status == -1 ) { - PrintAndLog("Error: tag didn't answer to GETVERSION"); + PrintAndLogEx(WARNING, "Error: tag didn't answer to GETVERSION"); DropField(); return status; } else if (status == 10) { @@ -849,7 +915,7 @@ int CmdHF14AMfUInfo(const char *Cmd){ if (startconfigblock){ // if we know where the config block is... status = ul_read(startconfigblock, ulev1_conf, sizeof(ulev1_conf)); if ( status == -1 ) { - PrintAndLog("Error: tag didn't answer to READ EV1"); + PrintAndLogEx(WARNING, "Error: tag didn't answer to READ EV1"); DropField(); return status; } else if (status == 16) { @@ -864,32 +930,46 @@ int CmdHF14AMfUInfo(const char *Cmd){ // 1-7 = limit. No automatic tries then. // hasAuthKey, if we was called with key, skip test. if ( !authlim && !hasAuthKey ) { - PrintAndLog("\n--- Known EV1/NTAG passwords."); + PrintAndLogEx(NORMAL, "\n--- Known EV1/NTAG passwords."); len = 0; for (uint8_t i = 0; i < KEYS_PWD_COUNT; ++i ) { key = default_pwd_pack[i]; len = ulev1_requestAuthentication(key, pack, sizeof(pack)); if (len >= 1) { - PrintAndLog("Found a default password: %s || Pack: %02X %02X",sprint_hex(key, 4), pack[0], pack[1]); + PrintAndLogEx(SUCCESS, "Found a default password: %s || Pack: %02X %02X",sprint_hex(key, 4), pack[0], pack[1]); break; } else { if (!ul_auth_select( &card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack))) return -1; } } - if (len < 1) PrintAndLog("password not known"); + if (len < 1) PrintAndLogEx(WARNING, "password not known"); } } DropField(); - if (locked) PrintAndLog("\nTag appears to be locked, try using the key to get more info"); - PrintAndLog(""); + if (locked) PrintAndLogEx(FAILED, "\nTag appears to be locked, try using the key to get more info"); + PrintAndLogEx(NORMAL, ""); return 1; } // // Write Single Block // -int CmdHF14AMfUWrBl(const char *Cmd){ +static int usage_hf_mfu_wrbl(void) { + PrintAndLogEx(NORMAL, "Write a block. It autodetects card type.\n"); + PrintAndLogEx(NORMAL, "Usage: hf mfu wrbl b d k l\n"); + PrintAndLogEx(NORMAL, " Options:"); + PrintAndLogEx(NORMAL, " b : block to write"); + PrintAndLogEx(NORMAL, " d : block data - (8 hex symbols)"); + PrintAndLogEx(NORMAL, " k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); + PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, " sample : hf mfu wrbl b 0 d 01234567"); + PrintAndLogEx(NORMAL, " : hf mfu wrbl b 0 d 01234567 k AABBCCDDD\n"); + return 0; +} + +static int CmdHF14AMfUWrBl(const char *Cmd){ int blockNo = -1; bool errors = false; @@ -921,7 +1001,7 @@ int CmdHF14AMfUWrBl(const char *Cmd){ hasPwdKey = true; break; } - // UL-C size key + // UL-C size key keylen = param_gethex(Cmd, cmdp+1, data, 32); if (!keylen){ memcpy(authenticationkey, data, 16); @@ -929,14 +1009,14 @@ int CmdHF14AMfUWrBl(const char *Cmd){ hasAuthKey = true; break; } - PrintAndLog("\nERROR: Key is incorrect length\n"); - errors = true; + PrintAndLogEx(ERR, "Key has incorrect length\n"); + errors = true; break; case 'b': case 'B': blockNo = param_get8(Cmd, cmdp+1); if (blockNo < 0) { - PrintAndLog("Wrong block number"); + PrintAndLogEx(ERR, "Wrong block number"); errors = true; } cmdp += 2; @@ -944,19 +1024,19 @@ int CmdHF14AMfUWrBl(const char *Cmd){ case 'l': case 'L': swapEndian = true; - cmdp++; + cmdp++; break; case 'd': case 'D': if ( param_gethex(Cmd, cmdp+1, blockdata, 8) ) { - PrintAndLog("Block data must include 8 HEX symbols"); + PrintAndLogEx(ERR, "Block data must include 8 HEX symbols"); errors = true; break; } cmdp += 2; break; default: - PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + PrintAndLogEx(ERR, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; break; } @@ -975,18 +1055,18 @@ int CmdHF14AMfUWrBl(const char *Cmd){ maxblockno = UL_MEMORY_ARRAY[idx]; } if (blockNo > maxblockno){ - PrintAndLog("block number too large. Max block is %u/0x%02X \n", maxblockno,maxblockno); + PrintAndLogEx(WARNING, "block number too large. Max block is %u/0x%02X \n", maxblockno,maxblockno); return usage_hf_mfu_wrbl(); } - // Swap endianness + // Swap endianness if (swapEndian && hasAuthKey) authKeyPtr = SwapEndian64(authenticationkey, 16, 8); if (swapEndian && hasPwdKey) authKeyPtr = SwapEndian64(authenticationkey, 4, 4); if ( blockNo <= 3) - PrintAndLog("Special Block: %0d (0x%02X) [ %s]", blockNo, blockNo, sprint_hex(blockdata, 4)); + PrintAndLogEx(NORMAL, "Special Block: %0d (0x%02X) [ %s]", blockNo, blockNo, sprint_hex(blockdata, 4)); else - PrintAndLog("Block: %0d (0x%02X) [ %s]", blockNo, blockNo, sprint_hex(blockdata, 4)); + PrintAndLogEx(NORMAL, "Block: %0d (0x%02X) [ %s]", blockNo, blockNo, sprint_hex(blockdata, 4)); //Send write Block UsbCommand c = {CMD_MIFAREU_WRITEBL, {blockNo}}; @@ -1006,19 +1086,35 @@ int CmdHF14AMfUWrBl(const char *Cmd){ UsbCommand resp; if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { uint8_t isOK = resp.arg[0] & 0xff; - PrintAndLog("isOk:%02x", isOK); + PrintAndLogEx(SUCCESS, "isOk:%02x", isOK); } else { - PrintAndLog("Command execute timeout"); + PrintAndLogEx(ERR, "Command execute timeout"); } return 0; } + + // // Read Single Block // -int CmdHF14AMfURdBl(const char *Cmd){ +static int usage_hf_mfu_rdbl(void) { + PrintAndLogEx(NORMAL, "Read a block and print. It autodetects card type.\n"); + PrintAndLogEx(NORMAL, "Usage: hf mfu rdbl b k l\n"); + PrintAndLogEx(NORMAL, " Options:"); + PrintAndLogEx(NORMAL, " b : block to read"); + PrintAndLogEx(NORMAL, " k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); + PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, " sample : hf mfu rdbl b 0"); + PrintAndLogEx(NORMAL, " : hf mfu rdbl b 0 k 00112233445566778899AABBCCDDEEFF"); + PrintAndLogEx(NORMAL, " : hf mfu rdbl b 0 k AABBCCDDD\n"); + return 0; +} - int blockNo = -1; +static int CmdHF14AMfURdBl(const char *Cmd){ + + int blockNo = -1; bool errors = false; bool hasAuthKey = false; bool hasPwdKey = false; @@ -1046,7 +1142,7 @@ int CmdHF14AMfURdBl(const char *Cmd){ hasPwdKey = true; break; } - // UL-C size key + // UL-C size key keylen = param_gethex(Cmd, cmdp+1, data, 32); if (!keylen){ memcpy(authenticationkey, data, 16); @@ -1054,14 +1150,14 @@ int CmdHF14AMfURdBl(const char *Cmd){ hasAuthKey = true; break; } - PrintAndLog("\nERROR: Key is incorrect length\n"); - errors = true; + PrintAndLogEx(ERR, "Key has incorrect length\n"); + errors = true; break; case 'b': case 'B': blockNo = param_get8(Cmd, cmdp+1); if (blockNo < 0) { - PrintAndLog("Wrong block number"); + PrintAndLogEx(ERR, "Wrong block number"); errors = true; } cmdp += 2; @@ -1072,7 +1168,7 @@ int CmdHF14AMfURdBl(const char *Cmd){ cmdp++; break; default: - PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; break; } @@ -1091,11 +1187,11 @@ int CmdHF14AMfURdBl(const char *Cmd){ maxblockno = UL_MEMORY_ARRAY[idx]; } if (blockNo > maxblockno){ - PrintAndLog("block number to large. Max block is %u/0x%02X \n", maxblockno,maxblockno); + PrintAndLogEx(WARNING, "block number to large. Max block is %u/0x%02X \n", maxblockno,maxblockno); return usage_hf_mfu_rdbl(); } - // Swap endianness + // Swap endianness if (swapEndian && hasAuthKey) authKeyPtr = SwapEndian64(authenticationkey, 16, 8); if (swapEndian && hasPwdKey) authKeyPtr = SwapEndian64(authenticationkey, 4, 4); @@ -1117,90 +1213,44 @@ int CmdHF14AMfURdBl(const char *Cmd){ uint8_t isOK = resp.arg[0] & 0xff; if (isOK) { uint8_t *data = resp.d.asBytes; - PrintAndLog("\n Block# | Data | Ascii"); - PrintAndLog("---------+-------------+------"); - PrintAndLog(" %02d/0x%02X | %s| %.4s\n", blockNo, blockNo, sprint_hex(data, 4), data); - } - else { - PrintAndLog("Failed reading block: (%02x)", isOK); + PrintAndLogEx(NORMAL, "\n Block# | Data | Ascii"); + PrintAndLogEx(NORMAL, "---------+-------------+------"); + PrintAndLogEx(NORMAL, " %02d/0x%02X | %s| %s\n", blockNo, blockNo, sprint_hex(data, 4), sprint_ascii(data, 4)); + } else { + PrintAndLogEx(ERR, "Failed reading block: (%02x)", isOK); } } else { - PrintAndLog("Command execute time-out"); + PrintAndLogEx(ERR, "Command execute time-out"); } return 0; } -int usage_hf_mfu_info(void) { - PrintAndLog("It gathers information about the tag and tries to detect what kind it is."); - PrintAndLog("Sometimes the tags are locked down, and you may need a key to be able to read the information"); - PrintAndLog("The following tags can be identified:\n"); - PrintAndLog("Ultralight, Ultralight-C, Ultralight EV1, NTAG 203, NTAG 210,"); - PrintAndLog("NTAG 212, NTAG 213, NTAG 215, NTAG 216, NTAG I2C 1K & 2K"); - PrintAndLog("my-d, my-d NFC, my-d move, my-d move NFC\n"); - PrintAndLog("Usage: hf mfu info k l"); - PrintAndLog(" Options : "); - PrintAndLog(" k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); - PrintAndLog(" l : (optional) swap entered key's endianness"); - PrintAndLog(""); - PrintAndLog(" sample : hf mfu info"); - PrintAndLog(" : hf mfu info k 00112233445566778899AABBCCDDEEFF"); - PrintAndLog(" : hf mfu info k AABBCCDDD"); - return 0; -} - -int usage_hf_mfu_dump(void) { - PrintAndLog("Reads all pages from Ultralight, Ultralight-C, Ultralight EV1"); - PrintAndLog("NTAG 203, NTAG 210, NTAG 212, NTAG 213, NTAG 215, NTAG 216"); - PrintAndLog("and saves binary dump into the file `filename.bin` or `cardUID.bin`"); - PrintAndLog("It autodetects card type.\n"); - PrintAndLog("Usage: hf mfu dump k l n "); - PrintAndLog(" Options : "); - PrintAndLog(" k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); - PrintAndLog(" l : (optional) swap entered key's endianness"); - PrintAndLog(" n : filename w/o .bin to save the dump as"); - PrintAndLog(" p : starting Page number to manually set a page to start the dump at"); - PrintAndLog(" q : number of Pages to manually set how many pages to dump"); - - PrintAndLog(""); - PrintAndLog(" sample : hf mfu dump"); - PrintAndLog(" : hf mfu dump n myfile"); - PrintAndLog(" : hf mfu dump k 00112233445566778899AABBCCDDEEFF"); - PrintAndLog(" : hf mfu dump k AABBCCDDD\n"); - return 0; -} - -int usage_hf_mfu_rdbl(void) { - PrintAndLog("Read a block and print. It autodetects card type.\n"); - PrintAndLog("Usage: hf mfu rdbl b k l\n"); - PrintAndLog(" Options:"); - PrintAndLog(" b : block to read"); - PrintAndLog(" k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); - PrintAndLog(" l : (optional) swap entered key's endianness"); - PrintAndLog(""); - PrintAndLog(" sample : hf mfu rdbl b 0"); - PrintAndLog(" : hf mfu rdbl b 0 k 00112233445566778899AABBCCDDEEFF"); - PrintAndLog(" : hf mfu rdbl b 0 k AABBCCDDD\n"); - return 0; -} - -int usage_hf_mfu_wrbl(void) { - PrintAndLog("Write a block. It autodetects card type.\n"); - PrintAndLog("Usage: hf mfu wrbl b d k l\n"); - PrintAndLog(" Options:"); - PrintAndLog(" b : block to write"); - PrintAndLog(" d : block data - (8 hex symbols)"); - PrintAndLog(" k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); - PrintAndLog(" l : (optional) swap entered key's endianness"); - PrintAndLog(""); - PrintAndLog(" sample : hf mfu wrbl b 0 d 01234567"); - PrintAndLog(" : hf mfu wrbl b 0 d 01234567 k AABBCCDDD\n"); - return 0; -} // // Mifare Ultralight / Ultralight-C / Ultralight-EV1 // Read and Dump Card Contents, using auto detection of tag size. -int CmdHF14AMfUDump(const char *Cmd){ +static int usage_hf_mfu_dump(void) { + PrintAndLogEx(NORMAL, "Reads all pages from Ultralight, Ultralight-C, Ultralight EV1"); + PrintAndLogEx(NORMAL, "NTAG 203, NTAG 210, NTAG 212, NTAG 213, NTAG 215, NTAG 216"); + PrintAndLogEx(NORMAL, "and saves binary dump into the file `filename.bin` or `cardUID.bin`"); + PrintAndLogEx(NORMAL, "It autodetects card type.\n"); + PrintAndLogEx(NORMAL, "Usage: hf mfu dump k l n "); + PrintAndLogEx(NORMAL, " Options : "); + PrintAndLogEx(NORMAL, " k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); + PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness"); + PrintAndLogEx(NORMAL, " n : filename w/o .bin to save the dump as"); + PrintAndLogEx(NORMAL, " p : starting Page number to manually set a page to start the dump at"); + PrintAndLogEx(NORMAL, " q : number of Pages to manually set how many pages to dump"); + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, " sample : hf mfu dump"); + PrintAndLogEx(NORMAL, " : hf mfu dump n myfile"); + PrintAndLogEx(NORMAL, " : hf mfu dump k 00112233445566778899AABBCCDDEEFF"); + PrintAndLogEx(NORMAL, " : hf mfu dump k AABBCCDDD\n"); + return 0; +} + +static int CmdHF14AMfUDump(const char *Cmd){ FILE *fout; char filename[FILE_PATH_SIZE] = {0x00}; @@ -1219,7 +1269,7 @@ int CmdHF14AMfUDump(const char *Cmd){ uint8_t dataLen = 0; uint8_t cmdp = 0; uint8_t authenticationkey[16] = {0x00}; - uint8_t *authKeyPtr = authenticationkey; + uint8_t *authKeyPtr = authenticationkey; size_t fileNlen = 0; bool errors = false; bool swapEndian = false; @@ -1242,7 +1292,7 @@ int CmdHF14AMfUDump(const char *Cmd){ errors = param_gethex(tempStr, 0, authenticationkey, dataLen); dataLen /= 2; } else { - PrintAndLog("\nERROR: Key is incorrect length\n"); + PrintAndLogEx(ERR, "Key has incorrect length\n"); errors = true; } cmdp += 2; @@ -1256,7 +1306,7 @@ int CmdHF14AMfUDump(const char *Cmd){ case 'n': case 'N': fileNlen = param_getstr(Cmd, cmdp+1, filename, sizeof(filename)); - if (!fileNlen) errors = true; + if (!fileNlen) errors = true; if (fileNlen > FILE_PATH_SIZE-5) fileNlen = FILE_PATH_SIZE-5; cmdp += 2; break; @@ -1273,7 +1323,7 @@ int CmdHF14AMfUDump(const char *Cmd){ manualPages = true; break; default: - PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; break; } @@ -1283,7 +1333,7 @@ int CmdHF14AMfUDump(const char *Cmd){ //Validations if(errors) return usage_hf_mfu_dump(); - if (swapEndian && hasAuthKey) + if (swapEndian && hasAuthKey) authKeyPtr = SwapEndian64(authenticationkey, dataLen, (dataLen == 16) ? 8 : 4); TagTypeUL_t tagtype = GetHF14AMfU_Type(); @@ -1295,7 +1345,7 @@ int CmdHF14AMfUDump(const char *Cmd){ Pages = UL_MEMORY_ARRAY[idx]+1; //add one as maxblks starts at 0 ul_print_type(tagtype, 0); - PrintAndLog("Reading tag memory..."); + PrintAndLogEx(NORMAL, "Reading tag memory..."); UsbCommand c = {CMD_MIFAREU_READCARD, {startPage,Pages}}; if ( hasAuthKey ) { if (tagtype & UL_C) @@ -1310,18 +1360,18 @@ int CmdHF14AMfUDump(const char *Cmd){ SendCommand(&c); UsbCommand resp; if (!WaitForResponseTimeout(CMD_ACK, &resp,1500)) { - PrintAndLog("Command execute time-out"); + PrintAndLogEx(ERR, "Command execute time-out"); return 1; } if (resp.arg[0] != 1) { - PrintAndLog("Failed reading block: (%02x)", i); + PrintAndLogEx(ERR, "Failed reading block: (%02x)", i); return 1; } uint32_t startindex = resp.arg[2]; uint32_t bufferSize = resp.arg[1]; if (bufferSize > sizeof(data)) { - PrintAndLog("Data exceeded Buffer size!"); + PrintAndLogEx(FAILED, "Data exceeded Buffer size!"); bufferSize = sizeof(data); } GetFromBigBuf(data, bufferSize, startindex, NULL, -1, false); @@ -1358,17 +1408,17 @@ int CmdHF14AMfUDump(const char *Cmd){ if (tagtype & UL_C){ //add 4 pages memcpy(data + Pages*4, authKeyPtr, dataLen); - Pages += dataLen/4; + Pages += dataLen/4; } else { // 2nd page from end memcpy(data + (Pages*4) - 8, authenticationkey, dataLen); } } - PrintAndLog("\n Block# | Data |lck| Ascii"); - PrintAndLog("---------+-------------+---+------"); + PrintAndLogEx(NORMAL, "\n Block# | Data |lck| Ascii"); + PrintAndLogEx(NORMAL, "---------+-------------+---+------"); for (i = 0; i < Pages; ++i) { if ( i < 3 ) { - PrintAndLog("%3d/0x%02X | %s| | ", i+startPage, i+startPage, sprint_hex(data + i * 4, 4)); + PrintAndLogEx(NORMAL, "%3d/0x%02X | %s| | ", i+startPage, i+startPage, sprint_hex(data + i * 4, 4)); continue; } switch(i){ @@ -1392,7 +1442,7 @@ int CmdHF14AMfUDump(const char *Cmd){ case 20: case 21: case 22: - case 23: tmplockbit = bit2[5]; break; + case 23: tmplockbit = bit2[5]; break; case 24: case 25: case 26: @@ -1404,11 +1454,11 @@ int CmdHF14AMfUDump(const char *Cmd){ case 32: case 33: case 34: - case 35: tmplockbit = bit2[1]; break; + case 35: tmplockbit = bit2[1]; break; case 36: case 37: case 38: - case 39: tmplockbit = bit2[0]; break; + case 39: tmplockbit = bit2[0]; break; case 40: tmplockbit = bit2[12]; break; case 41: tmplockbit = bit2[11]; break; case 42: tmplockbit = bit2[10]; break; //auth0 @@ -1420,9 +1470,9 @@ int CmdHF14AMfUDump(const char *Cmd){ memcpy(cleanASCII, data+i*4, 4); clean_ascii(cleanASCII, 4); - PrintAndLog("%3d/0x%02X | %s| %d | %.4s", i+startPage, i+startPage, sprint_hex(data + i * 4, 4), tmplockbit, cleanASCII); + PrintAndLogEx(NORMAL, "%3d/0x%02X | %s| %d | %.4s", i+startPage, i+startPage, sprint_hex(data + i * 4, 4), tmplockbit, cleanASCII); } - PrintAndLog("---------------------------------"); + PrintAndLogEx(NORMAL, "---------------------------------"); // user supplied filename? if (fileNlen < 1) { @@ -1433,14 +1483,14 @@ int CmdHF14AMfUDump(const char *Cmd){ sprintf(fnameptr + fileNlen,".bin"); } - if ((fout = fopen(filename,"wb")) == NULL) { - PrintAndLog("Could not create file name %s", filename); + if ((fout = fopen(filename,"wb")) == NULL) { + PrintAndLogEx(NORMAL, "Could not create file name %s", filename); return 1; } fwrite( data, 1, Pages*4, fout ); fclose(fout); - - PrintAndLog("Dumped %d pages, wrote %d bytes to %s", Pages, Pages*4, filename); + + PrintAndLogEx(SUCCESS, "Dumped %d pages, wrote %d bytes to %s", Pages, Pages*4, filename); return 0; } @@ -1451,7 +1501,7 @@ int CmdHF14AMfUDump(const char *Cmd){ // // Ultralight C Authentication Demo {currently uses hard-coded key} // -int CmdHF14AMfucAuth(const char *Cmd){ +static int CmdHF14AMfucAuth(const char *Cmd){ uint8_t keyNo = 3; bool errors = false; @@ -1461,49 +1511,49 @@ int CmdHF14AMfucAuth(const char *Cmd){ //Change key to user defined one if (cmdp == 'k' || cmdp == 'K'){ keyNo = param_get8(Cmd, 1); - if(keyNo > KEYS_3DES_COUNT-1) + if(keyNo > KEYS_3DES_COUNT-1) errors = true; } if (cmdp == 'h' || cmdp == 'H') errors = true; - + if (errors) { - PrintAndLog("Usage: hf mfu cauth k "); - PrintAndLog(" 0 (default): 3DES standard key"); - PrintAndLog(" 1 : all 0x00 key"); - PrintAndLog(" 2 : 0x00-0x0F key"); - PrintAndLog(" 3 : nfc key"); - PrintAndLog(" 4 : all 0x01 key"); - PrintAndLog(" 5 : all 0xff key"); - PrintAndLog(" 6 : 0x00-0xFF key"); - PrintAndLog("\n sample : hf mfu cauth k"); - PrintAndLog(" : hf mfu cauth k 3"); + PrintAndLogEx(NORMAL, "Usage: hf mfu cauth k "); + PrintAndLogEx(NORMAL, " 0 (default): 3DES standard key"); + PrintAndLogEx(NORMAL, " 1 : all 0x00 key"); + PrintAndLogEx(NORMAL, " 2 : 0x00-0x0F key"); + PrintAndLogEx(NORMAL, " 3 : nfc key"); + PrintAndLogEx(NORMAL, " 4 : all 0x01 key"); + PrintAndLogEx(NORMAL, " 5 : all 0xff key"); + PrintAndLogEx(NORMAL, " 6 : 0x00-0xFF key"); + PrintAndLogEx(NORMAL, "\n sample : hf mfu cauth k"); + PrintAndLogEx(NORMAL, " : hf mfu cauth k 3"); return 0; - } + } uint8_t *key = default_3des_keys[keyNo]; if (ulc_authentication(key, true)) - PrintAndLog("Authentication successful. 3des key: %s",sprint_hex(key, 16)); + PrintAndLogEx(SUCCESS, "Authentication successful. 3des key: %s",sprint_hex(key, 16)); else - PrintAndLog("Authentication failed"); - + PrintAndLogEx(WARNING, "Authentication failed"); + return 0; } /** -A test function to validate that the polarssl-function works the same -was as the openssl-implementation. -Commented out, since it requires openssl +A test function to validate that the polarssl-function works the same +was as the openssl-implementation. +Commented out, since it requires openssl int CmdTestDES(const char * cmd) { - uint8_t key[16] = {0x00}; - - memcpy(key,key3_3des_data,16); + uint8_t key[16] = {0x00}; + + memcpy(key,key3_3des_data,16); DES_cblock RndA, RndB; - PrintAndLog("----------OpenSSL DES implementation----------"); + PrintAndLogEx(NORMAL, "----------OpenSSL DES implementation----------"); { uint8_t e_RndB[8] = {0x00}; unsigned char RndARndB[16] = {0x00}; @@ -1512,7 +1562,7 @@ int CmdTestDES(const char * cmd) DES_key_schedule ks1,ks2; DES_cblock key1,key2; - memcpy(key,key3_3des_data,16); + memcpy(key,key3_3des_data,16); memcpy(key1,key,8); memcpy(key2,key+8,8); @@ -1521,23 +1571,23 @@ int CmdTestDES(const char * cmd) DES_set_key((DES_cblock *)key2,&ks2); DES_random_key(&RndA); - PrintAndLog(" RndA:%s",sprint_hex(RndA, 8)); - PrintAndLog(" e_RndB:%s",sprint_hex(e_RndB, 8)); + PrintAndLogEx(NORMAL, " RndA:%s",sprint_hex(RndA, 8)); + PrintAndLogEx(NORMAL, " e_RndB:%s",sprint_hex(e_RndB, 8)); //void DES_ede2_cbc_encrypt(const unsigned char *input, // unsigned char *output, long length, DES_key_schedule *ks1, // DES_key_schedule *ks2, DES_cblock *ivec, int enc); DES_ede2_cbc_encrypt(e_RndB,RndB,sizeof(e_RndB),&ks1,&ks2,&iv,0); - PrintAndLog(" RndB:%s",sprint_hex(RndB, 8)); + PrintAndLogEx(NORMAL, " RndB:%s",sprint_hex(RndB, 8)); rol(RndB,8); memcpy(RndARndB,RndA,8); memcpy(RndARndB+8,RndB,8); - PrintAndLog(" RA+B:%s",sprint_hex(RndARndB, 16)); + PrintAndLogEx(NORMAL, " RA+B:%s",sprint_hex(RndARndB, 16)); DES_ede2_cbc_encrypt(RndARndB,RndARndB,sizeof(RndARndB),&ks1,&ks2,&e_RndB,1); - PrintAndLog("enc(RA+B):%s",sprint_hex(RndARndB, 16)); + PrintAndLogEx(NORMAL, "enc(RA+B):%s",sprint_hex(RndARndB, 16)); } - PrintAndLog("----------PolarSSL implementation----------"); + PrintAndLogEx(NORMAL, "----------PolarSSL implementation----------"); { uint8_t random_a[8] = { 0 }; uint8_t enc_random_a[8] = { 0 }; @@ -1551,8 +1601,8 @@ int CmdTestDES(const char * cmd) uint8_t output[8] = { 0 }; uint8_t iv[8] = { 0 }; - PrintAndLog(" RndA :%s",sprint_hex(random_a, 8)); - PrintAndLog(" e_RndB:%s",sprint_hex(enc_random_b, 8)); + PrintAndLogEx(NORMAL, " RndA :%s",sprint_hex(random_a, 8)); + PrintAndLogEx(NORMAL, " e_RndB:%s",sprint_hex(enc_random_b, 8)); des3_set2key_dec(&ctx, key); @@ -1564,13 +1614,13 @@ int CmdTestDES(const char * cmd) , random_b // unsigned char *output ); - PrintAndLog(" RndB:%s",sprint_hex(random_b, 8)); + PrintAndLogEx(NORMAL, " RndB:%s",sprint_hex(random_b, 8)); rol(random_b,8); memcpy(random_a_and_b ,random_a,8); memcpy(random_a_and_b+8,random_b,8); - - PrintAndLog(" RA+B:%s",sprint_hex(random_a_and_b, 16)); + + PrintAndLogEx(NORMAL, " RA+B:%s",sprint_hex(random_a_and_b, 16)); des3_set2key_enc(&ctx, key); @@ -1582,97 +1632,97 @@ int CmdTestDES(const char * cmd) , random_a_and_b // unsigned char *output ); - PrintAndLog("enc(RA+B):%s",sprint_hex(random_a_and_b, 16)); + PrintAndLogEx(NORMAL, "enc(RA+B):%s",sprint_hex(random_a_and_b, 16)); } - return 0; + return 0; } **/ -// +// // Mifare Ultralight C - Set password // -int CmdHF14AMfucSetPwd(const char *Cmd){ +static int CmdHF14AMfucSetPwd(const char *Cmd){ uint8_t pwd[16] = {0x00}; - + char cmdp = param_getchar(Cmd, 0); - - if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: hf mfu setpwd "); - PrintAndLog(" [password] - (32 hex symbols)"); - PrintAndLog(""); - PrintAndLog("sample: hf mfu setpwd 000102030405060708090a0b0c0d0e0f"); - PrintAndLog(""); + + if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') { + PrintAndLogEx(NORMAL, "Usage: hf mfu setpwd "); + PrintAndLogEx(NORMAL, " [password] - (32 hex symbols)"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "sample: hf mfu setpwd 000102030405060708090a0b0c0d0e0f"); + PrintAndLogEx(NORMAL, ""); return 0; } - + if (param_gethex(Cmd, 0, pwd, 32)) { - PrintAndLog("Password must include 32 HEX symbols"); + PrintAndLogEx(WARNING, "Password must include 32 HEX symbols"); return 1; } - - UsbCommand c = {CMD_MIFAREUC_SETPWD}; + + UsbCommand c = {CMD_MIFAREUC_SETPWD}; memcpy( c.d.asBytes, pwd, 16); clearCommandBuffer(); SendCommand(&c); UsbCommand resp; - + if (WaitForResponseTimeout(CMD_ACK,&resp,1500) ) { if ( (resp.arg[0] & 0xff) == 1) - PrintAndLog("Ultralight-C new password: %s", sprint_hex(pwd,16)); + PrintAndLogEx(INFO, "Ultralight-C new password: %s", sprint_hex(pwd,16)); else{ - PrintAndLog("Failed writing at block %d", resp.arg[1] & 0xff); + PrintAndLogEx(ERR, "Failed writing at block %d", resp.arg[1] & 0xff); return 1; } } else { - PrintAndLog("command execution time out"); + PrintAndLogEx(ERR, "command execution time out"); return 1; } - + return 0; } // // Magic UL / UL-C tags - Set UID // -int CmdHF14AMfucSetUid(const char *Cmd){ +static int CmdHF14AMfucSetUid(const char *Cmd){ UsbCommand c; UsbCommand resp; uint8_t uid[7] = {0x00}; char cmdp = param_getchar(Cmd, 0); - - if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') { - PrintAndLog("Usage: hf mfu setuid "); - PrintAndLog(" [uid] - (14 hex symbols)"); - PrintAndLog("\nThis only works for Magic Ultralight tags."); - PrintAndLog(""); - PrintAndLog("sample: hf mfu setuid 11223344556677"); - PrintAndLog(""); + + if (strlen(Cmd) == 0 || cmdp == 'h' || cmdp == 'H') { + PrintAndLogEx(NORMAL, "Usage: hf mfu setuid "); + PrintAndLogEx(NORMAL, " [uid] - (14 hex symbols)"); + PrintAndLogEx(NORMAL, "\nThis only works for Magic Ultralight tags."); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "sample: hf mfu setuid 11223344556677"); + PrintAndLogEx(NORMAL, ""); return 0; } - + if (param_gethex(Cmd, 0, uid, 14)) { - PrintAndLog("UID must include 14 HEX symbols"); + PrintAndLogEx(WARNING, "UID must include 14 HEX symbols"); return 1; } - // read block2. + // read block2. c.cmd = CMD_MIFAREU_READBL; c.arg[0] = 2; clearCommandBuffer(); SendCommand(&c); if (!WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - PrintAndLog("Command execute timeout"); + PrintAndLogEx(WARNING, "Command execute timeout"); return 2; } - + // save old block2. uint8_t oldblock2[4] = {0x00}; memcpy(resp.d.asBytes, oldblock2, 4); - + // block 0. c.cmd = CMD_MIFAREU_WRITEBL; c.arg[0] = 0; @@ -1683,10 +1733,10 @@ int CmdHF14AMfucSetUid(const char *Cmd){ clearCommandBuffer(); SendCommand(&c); if (!WaitForResponseTimeout(CMD_ACK,&resp,1500)) { - PrintAndLog("Command execute timeout"); + PrintAndLogEx(WARNING, "Command execute timeout"); return 3; } - + // block 1. c.arg[0] = 1; c.d.asBytes[0] = uid[3]; @@ -1696,7 +1746,7 @@ int CmdHF14AMfucSetUid(const char *Cmd){ clearCommandBuffer(); SendCommand(&c); if (!WaitForResponseTimeout(CMD_ACK,&resp,1500) ) { - PrintAndLog("Command execute timeout"); + PrintAndLogEx(WARNING, "Command execute timeout"); return 4; } @@ -1709,14 +1759,14 @@ int CmdHF14AMfucSetUid(const char *Cmd){ clearCommandBuffer(); SendCommand(&c); if (!WaitForResponseTimeout(CMD_ACK,&resp,1500) ) { - PrintAndLog("Command execute timeout"); + PrintAndLogEx(WARNING, "Command execute timeout"); return 5; } - + return 0; } -int CmdHF14AMfuGenDiverseKeys(const char *Cmd){ +static int CmdHF14AMfuGenDiverseKeys(const char *Cmd){ uint8_t iv[8] = { 0x00 }; uint8_t block = 0x07; @@ -1729,9 +1779,9 @@ int CmdHF14AMfuGenDiverseKeys(const char *Cmd){ uint8_t mifarekeyB[] = { 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5 }; uint8_t dkeyA[8] = { 0x00 }; uint8_t dkeyB[8] = { 0x00 }; - + uint8_t masterkey[] = { 0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff }; - + uint8_t mix[8] = { 0x00 }; uint8_t divkey[8] = { 0x00 }; @@ -1753,26 +1803,24 @@ int CmdHF14AMfuGenDiverseKeys(const char *Cmd){ , divkey // output ); - PrintAndLog("3DES version"); - PrintAndLog("Masterkey :\t %s", sprint_hex(masterkey,sizeof(masterkey))); - PrintAndLog("UID :\t %s", sprint_hex(uid, sizeof(uid))); - PrintAndLog("Sector :\t %0d", block); - PrintAndLog("Mifare key :\t %s", sprint_hex(mifarekeyA, sizeof(mifarekeyA))); - PrintAndLog("Message :\t %s", sprint_hex(mix, sizeof(mix))); - PrintAndLog("Diversified key: %s", sprint_hex(divkey+1, 6)); - - PrintAndLog("\n DES version"); + PrintAndLogEx(NORMAL, "-- 3DES version"); + PrintAndLogEx(NORMAL, "Masterkey :\t %s", sprint_hex(masterkey,sizeof(masterkey))); + PrintAndLogEx(NORMAL, "UID :\t %s", sprint_hex(uid, sizeof(uid))); + PrintAndLogEx(NORMAL, "Block :\t %0d", block); + PrintAndLogEx(NORMAL, "Mifare key :\t %s", sprint_hex(mifarekeyA, sizeof(mifarekeyA))); + PrintAndLogEx(NORMAL, "Message :\t %s", sprint_hex(mix, sizeof(mix))); + PrintAndLogEx(NORMAL, "Diversified key: %s", sprint_hex(divkey+1, 6)); for (int i=0; i < sizeof(mifarekeyA); ++i){ dkeyA[i] = (mifarekeyA[i] << 1) & 0xff; dkeyA[6] |= ((mifarekeyA[i] >> 7) & 1) << (i+1); } - + for (int i=0; i < sizeof(mifarekeyB); ++i){ dkeyB[1] |= ((mifarekeyB[i] >> 7) & 1) << (i+1); dkeyB[2+i] = (mifarekeyB[i] << 1) & 0xff; } - + uint8_t zeros[8] = {0x00}; uint8_t newpwd[8] = {0x00}; uint8_t dmkey[24] = {0x00}; @@ -1790,17 +1838,18 @@ int CmdHF14AMfuGenDiverseKeys(const char *Cmd){ , zeros // input , newpwd // output ); - - PrintAndLog("Mifare dkeyA :\t %s", sprint_hex(dkeyA, sizeof(dkeyA))); - PrintAndLog("Mifare dkeyB :\t %s", sprint_hex(dkeyB, sizeof(dkeyB))); - PrintAndLog("Mifare ABA :\t %s", sprint_hex(dmkey, sizeof(dmkey))); - PrintAndLog("Mifare Pwd :\t %s", sprint_hex(newpwd, sizeof(newpwd))); - + + PrintAndLogEx(NORMAL, "\n-- DES version"); + PrintAndLogEx(NORMAL, "Mifare dkeyA :\t %s", sprint_hex(dkeyA, sizeof(dkeyA))); + PrintAndLogEx(NORMAL, "Mifare dkeyB :\t %s", sprint_hex(dkeyB, sizeof(dkeyB))); + PrintAndLogEx(NORMAL, "Mifare ABA :\t %s", sprint_hex(dmkey, sizeof(dmkey))); + PrintAndLogEx(NORMAL, "Mifare Pwd :\t %s", sprint_hex(newpwd, sizeof(newpwd))); + return 0; } // static uint8_t * diversify_key(uint8_t * key){ - + // for(int i=0; i<16; i++){ // if(i<=6) key[i]^=cuid[i]; // if(i>6) key[i]^=cuid[i%7]; @@ -1810,7 +1859,7 @@ int CmdHF14AMfuGenDiverseKeys(const char *Cmd){ // static void GenerateUIDe( uint8_t *uid, uint8_t len){ // for (int i=0; i -//Crypto Cards -int CmdHF14AMfucAuth(const char *Cmd); - -//general stuff -int CmdHF14AMfUDump(const char *Cmd); -int CmdHF14AMfUInfo(const char *Cmd); - -uint32_t GetHF14AMfU_Type(void); -int ul_print_type(uint32_t tagtype, uint8_t spacer); - -int usage_hf_mfu_dump(void); -int usage_hf_mfu_info(void); -int usage_hf_mfu_rdbl(void); -int usage_hf_mfu_wrbl(void); - -int CmdHFMFUltra(const char *Cmd); - -typedef enum TAGTYPE_UL { - UNKNOWN = 0x000000, - UL = 0x000001, - UL_C = 0x000002, - UL_EV1_48 = 0x000004, - UL_EV1_128 = 0x000008, - NTAG = 0x000010, - NTAG_203 = 0x000020, - NTAG_210 = 0x000040, - NTAG_212 = 0x000080, - NTAG_213 = 0x000100, - NTAG_215 = 0x000200, - NTAG_216 = 0x000400, - MY_D = 0x000800, - MY_D_NFC = 0x001000, - MY_D_MOVE = 0x002000, - MY_D_MOVE_NFC = 0x004000, - MY_D_MOVE_LEAN= 0x008000, - NTAG_I2C_1K = 0x010000, - NTAG_I2C_2K = 0x020000, - FUDAN_UL = 0x040000, - MAGIC = 0x080000, - UL_MAGIC = UL | MAGIC, - UL_C_MAGIC = UL_C | MAGIC, - UL_ERROR = 0xFFFFFF, -} TagTypeUL_t; +extern int CmdHFMFUltra(const char *Cmd); +extern uint32_t GetHF14AMfU_Type(void); +extern int ul_print_type(uint32_t tagtype, uint8_t spacer); #endif diff --git a/client/util.c b/client/util.c index f13d730c..eef97e2a 100644 --- a/client/util.c +++ b/client/util.c @@ -268,6 +268,10 @@ char *sprint_ascii_ex(const uint8_t *data, const size_t len, const size_t min_st return buf; } +char *sprint_ascii(const uint8_t *data, const size_t len) { + return sprint_ascii_ex(data, len, 0); +} + void num_to_bytes(uint64_t n, size_t len, uint8_t* dest) { while (len--) { @@ -329,7 +333,7 @@ uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockS } //assumes little endian -char * printBits(size_t const size, void const * const ptr) +char *printBits(size_t const size, void const * const ptr) { unsigned char *b = (unsigned char*) ptr; unsigned char byte; diff --git a/client/util.h b/client/util.h index 29dd7d5c..18482dfe 100644 --- a/client/util.h +++ b/client/util.h @@ -101,6 +101,7 @@ extern char *sprint_hex_inrow_ex(const uint8_t *data, const size_t len, const si extern char *sprint_bin(const uint8_t * data, const size_t len); extern char *sprint_bin_break(const uint8_t *data, const size_t len, const uint8_t breaks); extern char *sprint_ascii_ex(const uint8_t *data, const size_t len, const size_t min_str_len); +extern char *sprint_ascii(const uint8_t *data, const size_t len); extern void num_to_bytes(uint64_t n, size_t len, uint8_t* dest); extern uint64_t bytes_to_num(uint8_t* src, size_t len); From caaa4293ad077ba5cf2205288984a3f470464286 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Tue, 28 May 2019 07:50:58 +0200 Subject: [PATCH 091/189] fix 'lf pcf7931 bruteforce' (bug reported in http://www.proxmark.org/forum/viewtopic.php?id=6490) (#824) (and whitespace fixes) --- armsrc/pcf7931.c | 116 ++++++++++++++++++++---------------------- client/cmdlfpcf7931.c | 56 ++++++++++---------- 2 files changed, 83 insertions(+), 89 deletions(-) diff --git a/armsrc/pcf7931.c b/armsrc/pcf7931.c index 9aa0d9be..e3bac386 100644 --- a/armsrc/pcf7931.c +++ b/armsrc/pcf7931.c @@ -13,11 +13,11 @@ size_t DemodPCF7931(uint8_t **outBlocks) { uint8_t bits[256] = {0x00}; uint8_t blocks[8][16]; uint8_t *dest = BigBuf_get_addr(); - + int GraphTraceLen = BigBuf_max_traceLen(); if (GraphTraceLen > 18000) GraphTraceLen = 18000; - + int i, j, lastval, bitidx, half_switch; int clock = 64; int tolerance = clock / 8; @@ -107,7 +107,7 @@ size_t DemodPCF7931(uint8_t **outBlocks) { for(j = 0; j < 16; ++j) { blocks[num_blocks][j] = 128 * bits[j*8 + 7]+ - 64 * bits[j*8 + 6] + + 64 * bits[j*8 + 6] + 32 * bits[j*8 + 5] + 16 * bits[j*8 + 4] + 8 * bits[j*8 + 3] + @@ -161,44 +161,44 @@ bool IsBlock1PCF7931(uint8_t *block) { void ReadPCF7931() { int found_blocks = 0; // successfully read blocks - int max_blocks = 8; // readable blocks + int max_blocks = 8; // readable blocks uint8_t memory_blocks[8][17]; // PCF content - + uint8_t single_blocks[8][17]; // PFC blocks with unknown position int single_blocks_cnt = 0; - size_t n = 0; // transmitted blocks + size_t n = 0; // transmitted blocks uint8_t tmp_blocks[4][16]; // temporary read buffer - + uint8_t found_0_1 = 0; // flag: blocks 0 and 1 were found int errors = 0; // error counter int tries = 0; // tries counter - + memset(memory_blocks, 0, 8*17*sizeof(uint8_t)); memset(single_blocks, 0, 8*17*sizeof(uint8_t)); - + int i = 0, j = 0; do { i = 0; - + memset(tmp_blocks, 0, 4*16*sizeof(uint8_t)); n = DemodPCF7931((uint8_t**)tmp_blocks); if(!n) ++errors; - - // exit if no block is received + + // exit if no block is received if (errors >= 10 && found_blocks == 0 && single_blocks_cnt == 0) { Dbprintf("Error, no tag or bad tag"); return; } - // exit if too many errors during reading + // exit if too many errors during reading if (tries > 50 && (2*errors > tries)) { Dbprintf("Error reading the tag"); Dbprintf("Here is the partial content"); goto end; } - + // our logic breaks if we don't get at least two blocks if (n < 2) { if (n == 0 || !memcmp(tmp_blocks[0], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)) @@ -219,12 +219,12 @@ void ReadPCF7931() { } ++tries; continue; - } - - Dbprintf("(dbg) got %d blocks (%d/%d found) (%d tries, %d errors)", n, found_blocks, (max_blocks == 0 ? found_blocks : max_blocks), tries, errors); + } + + Dbprintf("(dbg) got %d blocks (%d/%d found) (%d tries, %d errors)", n, found_blocks, (max_blocks == 0 ? found_blocks : max_blocks), tries, errors); i = 0; - if(!found_0_1) { + if(!found_0_1) { while (i < n - 1) { if (IsBlock0PCF7931(tmp_blocks[i]) && IsBlock1PCF7931(tmp_blocks[i+1])) { found_0_1 = 1; @@ -234,9 +234,9 @@ void ReadPCF7931() { // block 1 tells how many blocks are going to be sent max_blocks = MAX((memory_blocks[1][14] & 0x7f), memory_blocks[1][15]) + 1; found_blocks = 2; - + Dbprintf("Found blocks 0 and 1. PCF is transmitting %d blocks.", max_blocks); - + // handle the following blocks for (j = i + 2; j < n; ++j) { memcpy(memory_blocks[found_blocks], tmp_blocks[j], 16); @@ -297,14 +297,14 @@ void ReadPCF7931() { Dbprintf("", i); } Dbprintf("-----------------------------------------"); - + if (found_blocks < max_blocks) { Dbprintf("-----------------------------------------"); Dbprintf("Blocks with unknown position:"); Dbprintf("-----------------------------------------"); for (i = 0; i < single_blocks_cnt; ++i) print_result("Block", single_blocks[i], 16); - + Dbprintf("-----------------------------------------"); } cmd_send(CMD_ACK,0,0,0,0,0); @@ -332,42 +332,42 @@ static void RealWritePCF7931(uint8_t *pass, uint16_t init_delay, int32_t l, int3 AddBytePCF7931(pass[6], tab, l, p); //programming mode (0 or 1) AddBitPCF7931(0, tab, l, p); - + //block adress on 6 bits for (u = 0; u < 6; ++u) { - if (address & (1 << u)) { // bit 1 + if (address & (1 << u)) { // bit 1 ++parity; AddBitPCF7931(1, tab, l, p); - } else { // bit 0 + } else { // bit 0 AddBitPCF7931(0, tab, l, p); } } - + //byte address on 4 bits for (u = 0; u < 4; ++u) { - if (byte & (1 << u)) { // bit 1 + if (byte & (1 << u)) { // bit 1 parity++; AddBitPCF7931(1, tab, l, p); } - else // bit 0 + else // bit 0 AddBitPCF7931(0, tab, l, p); } - + //data on 8 bits for (u=0; u<8; u++) { - if (data&(1<> 8) & 0xFF; - pass_array[2] = (password >> 16) & 0xFF; - pass_array[3] = (password >> 24) & 0xFF; - pass_array[4] = (password >> 32) & 0xFF; - pass_array[5] = (password >> 40) & 0xFF; - pass_array[6] = (password >> 48) & 0xFF; + + num_to_bytes(password, 7, pass_array); Dbprintf("Trying: %02x %02x %02x %02x %02x %02x %02x ...", pass_array[0], @@ -417,7 +411,7 @@ void BruteForcePCF7931(uint64_t password, uint8_t tries, uint16_t init_delay, in pass_array[4], pass_array[5], pass_array[6]); - + for (i = 0; i < tries; ++i) RealWritePCF7931 ( @@ -429,15 +423,15 @@ void BruteForcePCF7931(uint64_t password, uint8_t tries, uint16_t init_delay, in 7, 0x01 ); - - ++password; + + ++password; } } /* Write on a byte of a PCF7931 tag * @param address : address of the block to write @param byte : address of the byte to write - @param data : data to write + @param data : data to write */ void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, uint8_t pass5, uint8_t pass6, uint8_t pass7, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data) { Dbprintf("Initialization delay : %d us", init_delay); @@ -446,9 +440,9 @@ void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, ui Dbprintf("Block address : %02x", address); Dbprintf("Byte address : %02x", byte); Dbprintf("Data : %02x", data); - + uint8_t password[7] = {pass1, pass2, pass3, pass4, pass5, pass6, pass7}; - + RealWritePCF7931 (password, init_delay, l, p, address, byte, data); } @@ -488,7 +482,7 @@ void SendCmdPCF7931(uint32_t * tab) { HIGH(GPIO_SSC_DOUT); while(tempo != tab[u]) tempo = AT91C_BASE_TC0->TC_CV; - + // stop modulating antenna LOW(GPIO_SSC_DOUT); while(tempo != tab[u+1]) @@ -510,7 +504,7 @@ void SendCmdPCF7931(uint32_t * tab) { } -/* Add a byte for building the data frame of PCF7931 tags +/* Add a byte for building the data frame of PCF7931 tags * @param b : byte to add * @param tab : array of the data frame * @param l : offset on low pulse width @@ -519,7 +513,7 @@ void SendCmdPCF7931(uint32_t * tab) { bool AddBytePCF7931(uint8_t byte, uint32_t * tab, int32_t l, int32_t p) { uint32_t u; for (u = 0; u < 8; ++u) { - if (byte & (1 << u)) { //bit is 1 + if (byte & (1 << u)) { //bit is 1 if(AddBitPCF7931(1, tab, l, p)==1)return 1; } else { //bit is 0 if(AddBitPCF7931(0, tab, l, p)==1)return 1; @@ -529,7 +523,7 @@ bool AddBytePCF7931(uint8_t byte, uint32_t * tab, int32_t l, int32_t p) { return 0; } -/* Add a bits for building the data frame of PCF7931 tags +/* Add a bits for building the data frame of PCF7931 tags * @param b : bit to add * @param tab : array of the data frame * @param l : offset on low pulse width @@ -540,23 +534,23 @@ bool AddBitPCF7931(bool b, uint32_t * tab, int32_t l, int32_t p) { for (u = 0; tab[u] != 0; u += 3){} //we put the cursor at the last value of the array - if (b == 1) { //add a bit 1 - if (u == 0) tab[u] = 34 * T0_PCF + p; - else tab[u] = 34 * T0_PCF + tab[u-1] + p; + if (b == 1) { //add a bit 1 + if (u == 0) tab[u] = 34 * T0_PCF + p; + else tab[u] = 34 * T0_PCF + tab[u-1] + p; tab[u+1] = 6 * T0_PCF+tab[u] + l; tab[u+2] = 88 * T0_PCF+tab[u + 1] - l - p; return 0; - } else { //add a bit 0 + } else { //add a bit 0 - if (u == 0) tab[u] = 98 * T0_PCF + p; - else tab[u] = 98 * T0_PCF + tab[u-1] + p; + if (u == 0) tab[u] = 98 * T0_PCF + p; + else tab[u] = 98 * T0_PCF + tab[u-1] + p; tab[u + 1] = 6 * T0_PCF + tab[u] + l; tab[u + 2] = 24 * T0_PCF + tab[u + 1] - l - p; return 0; } - + return 1; } @@ -570,8 +564,8 @@ bool AddPatternPCF7931(uint32_t a, uint32_t b, uint32_t c, uint32_t * tab) { uint32_t u = 0; for(u = 0; tab[u] != 0; u += 3){} //we put the cursor at the last value of the array - if (u == 0) tab[u] = a; - else tab[u] = a + tab[u - 1]; + if (u == 0) tab[u] = a; + else tab[u] = a + tab[u - 1]; tab[u + 1] = b + tab[u]; tab[u + 2] = c + tab[u + 1]; diff --git a/client/cmdlfpcf7931.c b/client/cmdlfpcf7931.c index 9882da5f..74bc3b3e 100644 --- a/client/cmdlfpcf7931.c +++ b/client/cmdlfpcf7931.c @@ -1,7 +1,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 2012 Chalk // 2015 Dake -// 2018 sguerrini97 +// 2018 sguerrini97 // 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 @@ -33,7 +33,7 @@ static int CmdHelp(const char *Cmd); struct pcf7931_config configPcf = { {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}, PCF7931_DEFAULT_INITDELAY, - PCF7931_DEFAULT_OFFSET_WIDTH, + PCF7931_DEFAULT_OFFSET_WIDTH, PCF7931_DEFAULT_OFFSET_POSITION }; @@ -41,8 +41,8 @@ struct pcf7931_config configPcf = { int pcf7931_resetConfig(){ memset(configPcf.Pwd, 0xFF, sizeof(configPcf.Pwd) ); configPcf.InitDelay = PCF7931_DEFAULT_INITDELAY; - configPcf.OffsetWidth = PCF7931_DEFAULT_OFFSET_WIDTH; - configPcf.OffsetPosition = PCF7931_DEFAULT_OFFSET_POSITION; + configPcf.OffsetWidth = PCF7931_DEFAULT_OFFSET_WIDTH; + configPcf.OffsetPosition = PCF7931_DEFAULT_OFFSET_POSITION; return 0; } @@ -103,7 +103,7 @@ int usage_pcf7931_config(){ PrintAndLog(" pwd Password, hex, 7bytes, LSB-order"); PrintAndLog(" delay Tag initialization delay (in us) decimal"); PrintAndLog(" offset Low pulses width (in us) decimal"); - PrintAndLog(" offset Low pulses position (in us) decimal"); + PrintAndLog(" offset Low pulses position (in us) decimal"); PrintAndLog("Examples:"); PrintAndLog(" lf pcf7931 config"); PrintAndLog(" lf pcf7931 config r"); @@ -112,7 +112,7 @@ int usage_pcf7931_config(){ return 0; } -int CmdLFPCF7931Read(const char *Cmd){ +int CmdLFPCF7931Read(const char *Cmd){ uint8_t ctmp = param_getchar(Cmd, 0); if ( ctmp == 'H' || ctmp == 'h' ) return usage_pcf7931_read(); @@ -128,12 +128,12 @@ int CmdLFPCF7931Read(const char *Cmd){ return 0; } -int CmdLFPCF7931Config(const char *Cmd){ +int CmdLFPCF7931Config(const char *Cmd){ uint8_t ctmp = param_getchar(Cmd, 0); if ( ctmp == 0) return pcf7931_printConfig(); if ( ctmp == 'H' || ctmp == 'h' ) return usage_pcf7931_config(); - if ( ctmp == 'R' || ctmp == 'r' ) return pcf7931_resetConfig(); + if ( ctmp == 'R' || ctmp == 'r' ) return pcf7931_resetConfig(); if ( param_gethex(Cmd, 0, configPcf.Pwd, 14) ) return usage_pcf7931_config(); @@ -148,17 +148,17 @@ int CmdLFPCF7931Config(const char *Cmd){ int CmdLFPCF7931Write(const char *Cmd){ uint8_t ctmp = param_getchar(Cmd, 0); - if (strlen(Cmd) < 1 || ctmp == 'h' || ctmp == 'H') return usage_pcf7931_write(); + if (strlen(Cmd) < 1 || ctmp == 'h' || ctmp == 'H') return usage_pcf7931_write(); uint8_t block = 0, bytepos = 0, data = 0; - + if ( param_getdec(Cmd, 0, &block) ) return usage_pcf7931_write(); if ( param_getdec(Cmd, 1, &bytepos) ) return usage_pcf7931_write(); - + if ( (block > 7) || (bytepos > 15) ) return usage_pcf7931_write(); data = param_get8ex(Cmd, 2, 0, 16); - + PrintAndLog("Writing block: %d", block); PrintAndLog(" pos: %d", bytepos); PrintAndLog(" data: 0x%02X", data); @@ -178,27 +178,27 @@ int CmdLFPCF7931Write(const char *Cmd){ int CmdLFPCF7931BruteForce(const char *Cmd){ uint8_t ctmp = param_getchar(Cmd, 0); - if (strlen(Cmd) < 1 || ctmp == 'h' || ctmp == 'H') return usage_pcf7931_bruteforce(); + if (strlen(Cmd) < 1 || ctmp == 'h' || ctmp == 'H') return usage_pcf7931_bruteforce(); - uint64_t start_password = 0; + uint8_t start_password[7] = {0}; uint8_t tries = 3; - - if (param_gethex(Cmd, 0, (uint8_t*)(&start_password), 14)) return usage_pcf7931_bruteforce(); + + if (param_gethex(Cmd, 0, start_password, 14)) return usage_pcf7931_bruteforce(); if (param_getdec(Cmd, 1, &tries)) return usage_pcf7931_bruteforce(); - + PrintAndLog("Bruteforcing from password: %02x %02x %02x %02x %02x %02x %02x", - start_password & 0xFF, - (start_password >> 8) & 0xFF, - (start_password >> 16) & 0xFF, - (start_password >> 24) & 0xFF, - (start_password >> 32) & 0xFF, - (start_password >> 48) & 0xFF, - (start_password >> 56) & 0xFF); - + start_password[0], + start_password[1], + start_password[2], + start_password[3], + start_password[4], + start_password[5], + start_password[6]); + PrintAndLog("Trying each password %d times", tries); - UsbCommand c = {CMD_PCF7931_BRUTEFORCE, {start_password, tries} }; - + UsbCommand c = {CMD_PCF7931_BRUTEFORCE, {bytes_to_num(start_password, 7), tries} }; + c.d.asDwords[7] = (configPcf.OffsetWidth + 128); c.d.asDwords[8] = (configPcf.OffsetPosition + 128); c.d.asDwords[9] = configPcf.InitDelay; @@ -209,7 +209,7 @@ int CmdLFPCF7931BruteForce(const char *Cmd){ return 0; } -static command_t CommandTable[] = +static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"read", CmdLFPCF7931Read, 0, "Read content of a PCF7931 transponder"}, From d38bb3acc3957efdac0204f147de1d8494a03966 Mon Sep 17 00:00:00 2001 From: Vladimir Serbinenko Date: Wed, 29 May 2019 18:57:17 +0200 Subject: [PATCH 092/189] Specify that we need TCP and not UDP connection (#828) --- uart/uart_posix.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/uart/uart_posix.c b/uart/uart_posix.c index 214cb56a..29a02cf7 100644 --- a/uart/uart_posix.c +++ b/uart/uart_posix.c @@ -80,7 +80,7 @@ serial_port uart_open(const char* pcPortName) if (sp == 0) return INVALID_SERIAL_PORT; if (memcmp(pcPortName, "tcp:", 4) == 0) { - struct addrinfo *addr, *rp; + struct addrinfo *addr = NULL, *rp; char *addrstr = strdup(pcPortName + 4); if (addrstr == NULL) { printf("Error: strdup\n"); @@ -98,7 +98,13 @@ serial_port uart_open(const char* pcPortName) } else portstr = "7901"; - int s = getaddrinfo(addrstr, portstr, NULL, &addr); + struct addrinfo info; + + memset (&info, 0, sizeof(info)); + + info.ai_socktype = SOCK_STREAM; + + int s = getaddrinfo(addrstr, portstr, &info, &addr); if (s != 0) { printf("Error: getaddrinfo: %s\n", gai_strerror(s)); return INVALID_SERIAL_PORT; From b8dd1ef6490a49784c797e9312df8622445e28dd Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Thu, 6 Jun 2019 07:33:12 +0200 Subject: [PATCH 093/189] upgrading 'hf mfu' (#830) * chg: write new dump file format by @mceloff * chg: rename 'hf mfu dump' option 'n' to 'f' to align with other commands and RRG repo * chg: replace ISO14443A_CMD_READBLOCK by MIFARE_CMD_READBLOCK, same for WRITEBLOCK * fix: mifare_ultra_readblock() returned 14 bytes instead of 16 * chg: param_gethex_ex() now checks maximum output buffer length * chg: ul_comp_write() was incomplete and for magic testing only * fix: 16bit ULC counter had been displayed as 32bit * chg: add check for 7 Byte UID, drop check for ATQA in type identification GetHF14AMfU_Type() * fix: send HALT instead of dropping field in order to maintain a defined state * chg: DropField() when command ends * chg: check for invalid page ranges in 'hf mfu dump' * fix: print correct lock bits when page range is used * fix: do not write (incomplete) dumpfile when page range is used * add: use UID for filename when no filename is given (RRG repo) * chg: don't clear trace on each ULC authentication, clear trace at beginning of each command * fix: don't send (DESFire?) deselect command after authentication --- armsrc/apps.h | 2 - armsrc/iclass.c | 5 +- armsrc/mifarecmd.c | 82 ++- armsrc/mifaresim.c | 8 +- armsrc/mifareutil.c | 2 +- armsrc/mifareutil.h | 5 - client/cmdhflist.c | 4 +- client/cmdhfmf.c | 13 +- client/cmdhfmfu.c | 1304 +++++++++++++++++++++---------------------- client/util.c | 17 +- common/protocols.h | 59 +- 11 files changed, 729 insertions(+), 772 deletions(-) diff --git a/armsrc/apps.h b/armsrc/apps.h index 72a62628..d1c885ab 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -142,8 +142,6 @@ void MifareDES_Auth1(uint8_t arg0,uint8_t arg1,uint8_t arg2, uint8_t *datain); void ReaderMifareDES(uint32_t param, uint32_t param2, uint8_t * datain); int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout); size_t CreateAPDU( uint8_t *datain, size_t len, uint8_t *dataout); -void OnSuccess(); -void OnError(uint8_t reason); /// iclass.h diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 83c9a75b..7ffac62d 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -1963,7 +1963,10 @@ void iClass_Dump(uint8_t blockno, uint8_t numblks) { uint8_t *dataout = BigBuf_malloc(255*8); if (dataout == NULL){ Dbprintf("out of memory"); - OnError(1); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); + cmd_send(CMD_ACK,0,1,0,0,0); + LED_A_OFF(); return; } memset(dataout,0xFF,255*8); diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 14ce1bcc..a3807cf7 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -23,24 +23,42 @@ #define HARDNESTED_AUTHENTICATION_TIMEOUT 848 // card times out 1ms after wrong authentication (according to NXP documentation) #define HARDNESTED_PRE_AUTHENTICATION_LEADTIME 400 // some (non standard) cards need a pause after select before they are ready for first authentication +/* // the block number for the ISO14443-4 PCB static uint8_t pcb_blocknum = 0; // Deselect card by sending a s-block. the crc is precalced for speed static uint8_t deselect_cmd[] = {0xc2,0xe0,0xb4}; +static void OnSuccess(){ + pcb_blocknum = 0; + ReaderTransmit(deselect_cmd, 3 , NULL); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); +} +*/ + +static void OnError(uint8_t reason){ + // pcb_blocknum = 0; + // ReaderTransmit(deselect_cmd, 3 , NULL); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); + cmd_send(CMD_ACK,0,reason,0,0,0); + LED_A_OFF(); +} + //----------------------------------------------------------------------------- // Select, Authenticate, Read a MIFARE tag. // read block //----------------------------------------------------------------------------- void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) { - // params + LED_A_ON(); + uint8_t blockNo = arg0; uint8_t keyType = arg1; uint64_t ui64Key = 0; ui64Key = bytes_to_num(datain, 6); - // variables byte_t isOK = 0; byte_t dataoutbuf[16]; uint8_t uid[10]; @@ -53,10 +71,6 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) clear_trace(); - LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); - while (true) { if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); @@ -97,21 +111,18 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes){ + LED_A_ON(); bool turnOffField = (arg0 == 1); - LED_A_ON(); LED_B_OFF(); LED_C_OFF(); - iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - clear_trace(); - - if(!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) { + if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card"); OnError(0); return; }; - if(!mifare_ultra_auth(keybytes)){ + if (!mifare_ultra_auth(keybytes)){ if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Authentication failed"); OnError(1); return; @@ -119,9 +130,11 @@ void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes){ if (turnOffField) { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); + LED_D_OFF(); } + cmd_send(CMD_ACK,1,0,0,0,0); + LED_A_OFF(); } // Arg0 = BlockNo, @@ -129,17 +142,15 @@ void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes){ // datain = PWD bytes, void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) { + LED_A_ON(); + uint8_t blockNo = arg0; byte_t dataout[16] = {0x00}; bool useKey = (arg1 == 1); //UL_C bool usePwd = (arg1 == 2); //UL_EV1/NTAG - LEDsoff(); - LED_A_ON(); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - clear_trace(); - int len = iso14443a_select_card(NULL, NULL, NULL, true, 0, true); if(!len) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card (RC:%02X)",len); @@ -148,7 +159,7 @@ void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) } // UL-C authentication - if ( useKey ) { + if (useKey) { uint8_t key[16] = {0x00}; memcpy(key, datain, sizeof(key) ); @@ -159,7 +170,7 @@ void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) } // UL-EV1 / NTAG authentication - if ( usePwd ) { + if (usePwd) { uint8_t pwd[4] = {0x00}; memcpy(pwd, datain, 4); uint8_t pack[4] = {0,0,0,0}; @@ -169,13 +180,13 @@ void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) } } - if( mifare_ultra_readblock(blockNo, dataout) ) { + if (mifare_ultra_readblock(blockNo, dataout)) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Read block error"); OnError(2); return; } - if( mifare_ultra_halt() ) { + if (mifare_ultra_halt()) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Halt error"); OnError(3); return; @@ -183,7 +194,8 @@ void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) cmd_send(CMD_ACK,1,0,0,dataout,16); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); + LED_D_OFF(); + LED_A_OFF(); } //----------------------------------------------------------------------------- @@ -259,13 +271,11 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) // datain = KEY bytes void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain) { - LEDsoff(); LED_A_ON(); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); // free eventually allocated BigBuf memory BigBuf_free(); - clear_trace(); // params uint8_t blockNo = arg0; @@ -288,7 +298,7 @@ void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain) } // UL-C authentication - if ( useKey ) { + if (useKey) { uint8_t key[16] = {0x00}; memcpy(key, datain, sizeof(key) ); @@ -340,14 +350,14 @@ void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain) return; } - if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("Blocks read %d", countblocks); + if (MF_DBGLEVEL >= MF_DBG_DEBUG) Dbprintf("Blocks read %d", countblocks); - countblocks *= 4; + cmd_send(CMD_ACK, 1, countblocks*4, BigBuf_max_traceLen(), 0, 0); - cmd_send(CMD_ACK, 1, countblocks, BigBuf_max_traceLen(), 0, 0); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); + LED_D_OFF(); BigBuf_free(); + LED_A_OFF(); } //----------------------------------------------------------------------------- @@ -1598,17 +1608,3 @@ void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain){ LEDsoff(); } -void OnSuccess(){ - pcb_blocknum = 0; - ReaderTransmit(deselect_cmd, 3 , NULL); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); -} - -void OnError(uint8_t reason){ - pcb_blocknum = 0; - ReaderTransmit(deselect_cmd, 3 , NULL); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - cmd_send(CMD_ACK,0,reason,0,0,0); - LEDsoff(); -} diff --git a/armsrc/mifaresim.c b/armsrc/mifaresim.c index 6f97e1b4..137a586d 100644 --- a/armsrc/mifaresim.c +++ b/armsrc/mifaresim.c @@ -542,8 +542,8 @@ void MifareSim(uint8_t flags, uint8_t exitAfterNReads, uint8_t cardsize, uint8_t break; } - if(receivedCmd_dec[0] == ISO14443A_CMD_READBLOCK - || receivedCmd_dec[0] == ISO14443A_CMD_WRITEBLOCK + if(receivedCmd_dec[0] == MIFARE_CMD_READBLOCK + || receivedCmd_dec[0] == MIFARE_CMD_WRITEBLOCK || receivedCmd_dec[0] == MIFARE_CMD_INC || receivedCmd_dec[0] == MIFARE_CMD_DEC || receivedCmd_dec[0] == MIFARE_CMD_RESTORE @@ -562,7 +562,7 @@ void MifareSim(uint8_t flags, uint8_t exitAfterNReads, uint8_t cardsize, uint8_t } } - if (receivedCmd_dec[0] == ISO14443A_CMD_READBLOCK) { + if (receivedCmd_dec[0] == MIFARE_CMD_READBLOCK) { uint8_t blockNo = receivedCmd_dec[1]; emlGetMem(response, blockNo, 1); if (IsSectorTrailer(blockNo)) { @@ -593,7 +593,7 @@ void MifareSim(uint8_t flags, uint8_t exitAfterNReads, uint8_t cardsize, uint8_t break; } - if (receivedCmd_dec[0] == ISO14443A_CMD_WRITEBLOCK) { + if (receivedCmd_dec[0] == MIFARE_CMD_WRITEBLOCK) { uint8_t blockNo = receivedCmd_dec[1]; EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); FpgaDisableTracing(); diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index 36e29721..647305e8 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -451,7 +451,7 @@ int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData) return result; } - memcpy(blockData, receivedAnswer, 14); + memcpy(blockData, receivedAnswer, 16); return 0; } diff --git a/armsrc/mifareutil.h b/armsrc/mifareutil.h index 589f780b..856040ca 100644 --- a/armsrc/mifareutil.h +++ b/armsrc/mifareutil.h @@ -25,11 +25,6 @@ #define AUTH_FIRST 0 #define AUTH_NESTED 2 -// mifare 4bit card answers -#define CARD_ACK 0x0A // 1010 - ACK -#define CARD_NACK_NA 0x04 // 0100 - NACK, not allowed (command not allowed) -#define CARD_NACK_TR 0x05 // 0101 - NACK, transmission error - // reader voltage field detector #define MF_MINFIELDV 4000 diff --git a/client/cmdhflist.c b/client/cmdhflist.c index 4499cd0d..5384bfce 100644 --- a/client/cmdhflist.c +++ b/client/cmdhflist.c @@ -415,8 +415,8 @@ void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) case ISO14443A_CMD_REQA: snprintf(exp,size,"REQA"); break; - case ISO14443A_CMD_READBLOCK: snprintf(exp,size,"READBLOCK(%d)",cmd[1]); break; - case ISO14443A_CMD_WRITEBLOCK: snprintf(exp,size,"WRITEBLOCK(%d)",cmd[1]); break; + case MIFARE_CMD_READBLOCK: snprintf(exp,size,"READBLOCK(%d)",cmd[1]); break; + case MIFARE_CMD_WRITEBLOCK: snprintf(exp,size,"WRITEBLOCK(%d)",cmd[1]); break; case ISO14443A_CMD_HALT: snprintf(exp,size,"HALT"); MifareAuthState = masNone; diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 38b7f988..ef48b825 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -1516,8 +1516,11 @@ int CmdHF14AMfSim(const char *Cmd) { break; case 'u': case 'U': - param_gethex_ex(Cmd, cmdp+1, uid, &uidlen); - switch(uidlen) { + uidlen = 14; + if (param_gethex_ex(Cmd, cmdp+1, uid, &uidlen)) { + return usage_hf14_mfsim(); + } + switch (uidlen) { case 14: flags = FLAG_7B_UID_IN_DATA; break; case 8: flags = FLAG_4B_UID_IN_DATA; break; default: return usage_hf14_mfsim(); @@ -2726,9 +2729,9 @@ int CmdHF14AMfSniff(const char *Cmd){ //needs nt, ar, at, Data to decrypt int CmdDecryptTraceCmds(const char *Cmd){ uint8_t data[50]; - int len = 0; - param_gethex_ex(Cmd,3,data,&len); - return tryDecryptWord(param_get32ex(Cmd,0,0,16),param_get32ex(Cmd,1,0,16),param_get32ex(Cmd,2,0,16),data,len/2); + int len = 100; + param_gethex_ex(Cmd, 3, data, &len); + return tryDecryptWord(param_get32ex(Cmd, 0, 0, 16), param_get32ex(Cmd, 1, 0, 16), param_get32ex(Cmd, 2, 0, 16), data, len/2); } int CmdHF14AMfAuth4(const char *cmd) { diff --git a/client/cmdhfmfu.c b/client/cmdhfmfu.c index dac51be3..89e58263 100644 --- a/client/cmdhfmfu.c +++ b/client/cmdhfmfu.c @@ -21,6 +21,7 @@ #include "cmdhf14a.h" // DropField() #include "mifare.h" #include "util.h" +#include "util_posix.h" #include "protocols.h" #include "taginfo.h" @@ -40,12 +41,11 @@ typedef enum TAGTYPE_UL { MY_D = 0x000800, MY_D_NFC = 0x001000, MY_D_MOVE = 0x002000, - MY_D_MOVE_NFC = 0x004000, - MY_D_MOVE_LEAN= 0x008000, - NTAG_I2C_1K = 0x010000, - NTAG_I2C_2K = 0x020000, - FUDAN_UL = 0x040000, - MAGIC = 0x080000, + MY_D_MOVE_LEAN= 0x004000, + NTAG_I2C_1K = 0x008000, + NTAG_I2C_2K = 0x010000, + FUDAN_UL = 0x020000, + MAGIC = 0x040000, UL_MAGIC = UL | MAGIC, UL_C_MAGIC = UL_C | MAGIC, UL_ERROR = 0xFFFFFF, @@ -95,14 +95,13 @@ static uint8_t default_pwd_pack[KEYS_PWD_COUNT][4] = { {0x35,0x1C,0xD0,0x19}, // PACK 0x9A,0x5a -- italian bus (sniffed) }; -#define MAX_UL_TYPES 18 +#define MAX_UL_TYPES 17 static uint32_t UL_TYPES_ARRAY[MAX_UL_TYPES] = {UNKNOWN, UL, UL_C, UL_EV1_48, UL_EV1_128, NTAG, NTAG_203, - NTAG_210, NTAG_212, NTAG_213, NTAG_215, NTAG_216, MY_D, MY_D_NFC, MY_D_MOVE, MY_D_MOVE_NFC, MY_D_MOVE_LEAN, FUDAN_UL}; + NTAG_210, NTAG_212, NTAG_213, NTAG_215, NTAG_216, MY_D, MY_D_NFC, MY_D_MOVE, MY_D_MOVE_LEAN, FUDAN_UL}; static uint8_t UL_MEMORY_ARRAY[MAX_UL_TYPES] = {MAX_UL_BLOCKS, MAX_UL_BLOCKS, MAX_ULC_BLOCKS, MAX_ULEV1a_BLOCKS, MAX_ULEV1b_BLOCKS, MAX_NTAG_203, MAX_NTAG_203, MAX_NTAG_210, MAX_NTAG_212, MAX_NTAG_213, - MAX_NTAG_215, MAX_NTAG_216, MAX_UL_BLOCKS, MAX_MY_D_NFC, MAX_MY_D_MOVE, MAX_MY_D_MOVE, MAX_MY_D_MOVE_LEAN, MAX_UL_BLOCKS}; - + MAX_NTAG_215, MAX_NTAG_216, MAX_UL_BLOCKS, MAX_MY_D_NFC, MAX_MY_D_MOVE, MAX_MY_D_MOVE_LEAN, MAX_UL_BLOCKS}; // get version nxp product type static char *getProductTypeStr( uint8_t id){ @@ -123,7 +122,7 @@ static char *getProductTypeStr( uint8_t id){ the LSBit is set to '0' if the size is exactly 2^n and set to '1' if the storage size is between 2^n and 2^(n+1). */ -char *getUlev1CardSizeStr( uint8_t fsize ){ +static char *getUlev1CardSizeStr( uint8_t fsize ){ static char buf[40]; char *retStr = buf; @@ -140,13 +139,8 @@ char *getUlev1CardSizeStr( uint8_t fsize ){ return buf; } -static void ul_switch_on_field(void) { - UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT | ISO14A_NO_RATS, 0, 0}}; - clearCommandBuffer(); - SendCommand(&c); -} -static int ul_send_cmd_raw( uint8_t *cmd, uint8_t cmdlen, uint8_t *response, uint16_t responseLength ) { +static int ul_send_cmd_raw(uint8_t *cmd, uint8_t cmdlen, uint8_t *response, uint16_t responseLength) { UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_NO_DISCONNECT | ISO14A_APPEND_CRC, cmdlen, 0}}; memcpy(c.d.asBytes, cmd, cmdlen); clearCommandBuffer(); @@ -159,34 +153,19 @@ static int ul_send_cmd_raw( uint8_t *cmd, uint8_t cmdlen, uint8_t *response, uin memcpy(response, resp.d.asBytes, resplen); return resplen; } -/* -static int ul_send_cmd_raw_crc( uint8_t *cmd, uint8_t cmdlen, uint8_t *response, uint16_t responseLength, bool append_crc ) { - UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_NO_DISCONNECT , cmdlen, 0}}; - if (append_crc) - c.arg[0] |= ISO14A_APPEND_CRC; - memcpy(c.d.asBytes, cmd, cmdlen); + +static int ul_select(iso14a_card_select_t *card, bool clear_trace) { + + UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT | ISO14A_NO_RATS | (clear_trace?ISO14A_CLEAR_TRACE:0), 0, 0}}; clearCommandBuffer(); SendCommand(&c); - UsbCommand resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) return -1; - if (!resp.arg[0] && responseLength) return -1; - - uint16_t resplen = (resp.arg[0] < responseLength) ? resp.arg[0] : responseLength; - memcpy(response, resp.d.asBytes, resplen); - return resplen; -} -*/ -static int ul_select( iso14a_card_select_t *card ){ - - ul_switch_on_field(); UsbCommand resp; bool ans = false; ans = WaitForResponseTimeout(CMD_ACK, &resp, 1500); - if (!ans || resp.arg[0] < 1) { + if (ans == 0 || resp.arg[0] == 0) { PrintAndLogEx(WARNING, "iso14443a card select failed"); - DropField(); return 0; } @@ -194,40 +173,62 @@ static int ul_select( iso14a_card_select_t *card ){ return 1; } -// This read command will at least return 16bytes. -static int ul_read( uint8_t page, uint8_t *response, uint16_t responseLength ){ - uint8_t cmd[] = {ISO14443A_CMD_READBLOCK, page}; +// This read command will return 16 bytes. +static int ul_read(uint8_t page, uint8_t *response, uint16_t responseLength) { + uint8_t cmd[] = {MIFARE_CMD_READBLOCK, page}; int len = ul_send_cmd_raw(cmd, sizeof(cmd), response, responseLength); return len; } -static int ul_comp_write( uint8_t page, uint8_t *data, uint8_t datalen ){ - uint8_t cmd[18]; - memset(cmd, 0x00, sizeof(cmd)); - datalen = ( datalen > 16) ? 16 : datalen; - - cmd[0] = ISO14443A_CMD_WRITEBLOCK; - cmd[1] = page; - memcpy(cmd+2, data, datalen); - - uint8_t response[1] = {0xff}; - ul_send_cmd_raw(cmd, 2+datalen, response, sizeof(response)); - // ACK - if ( response[0] == 0x0a ) return 0; - // NACK - return -1; +static int ul_halt(void) { + uint8_t cmd[] = {ISO14443A_CMD_HALT, 0x00}; + uint8_t response; + int len = ul_send_cmd_raw(cmd, sizeof(cmd), &response, sizeof(response)); + return len; } -static int ulc_requestAuthentication( uint8_t *nonce, uint16_t nonceLength ){ + +static int ul_comp_write_ex(uint8_t page, uint8_t *data, uint8_t datalen, bool first_part_only) { + + uint8_t cmd[18] = {0x00}; + datalen = ( datalen > 16) ? 16 : datalen; + + cmd[0] = MIFARE_CMD_WRITEBLOCK; + cmd[1] = page; + + uint8_t response = {0xff}; + ul_send_cmd_raw(cmd, 2, &response, sizeof(response)); + if (response != CARD_ACK) + return -1; + if (first_part_only) + return 0; + + memcpy(cmd, data, datalen); + ul_send_cmd_raw(cmd, 16, &response, sizeof(response)); + if (response != CARD_ACK) + return -1; + + return 0; +} + + +// not used yet +// static int ul_comp_write(uint8_t page, uint8_t *data, uint8_t datalen) { + // return ul_comp_write_ex(page, data, datalen, false); +// } + + +static int ulc_requestAuthentication(uint8_t *nonce, uint16_t nonceLength) { uint8_t cmd[] = {MIFARE_ULC_AUTH_1, 0x00}; int len = ul_send_cmd_raw(cmd, sizeof(cmd), nonce, nonceLength); return len; } -static int ulc_authentication( uint8_t *key, bool switch_off_field ){ + +static int ulc_authentication(uint8_t *key, bool switch_off_field) { UsbCommand c = {CMD_MIFAREUC_AUTH, {switch_off_field}}; memcpy(c.d.asBytes, key, 16); @@ -240,27 +241,29 @@ static int ulc_authentication( uint8_t *key, bool switch_off_field ){ return 0; } -static int ulev1_requestAuthentication( uint8_t *pwd, uint8_t *pack, uint16_t packLength ){ + +static int ulev1_requestAuthentication(uint8_t *pwd, uint8_t *pack, uint16_t packLength) { uint8_t cmd[] = {MIFARE_ULEV1_AUTH, pwd[0], pwd[1], pwd[2], pwd[3]}; int len = ul_send_cmd_raw(cmd, sizeof(cmd), pack, packLength); return len; } -static int ul_auth_select( iso14a_card_select_t *card, TagTypeUL_t tagtype, bool hasAuthKey, uint8_t *authenticationkey, uint8_t *pack, uint8_t packSize){ - if ( hasAuthKey && (tagtype & UL_C)) { + +static int ul_auth_select(iso14a_card_select_t *card, TagTypeUL_t tagtype, bool hasAuthKey, uint8_t *authenticationkey, uint8_t *pack, uint8_t packSize) { + + if (hasAuthKey && (tagtype & UL_C)) { //will select card automatically and close connection on error if (!ulc_authentication(authenticationkey, false)) { - PrintAndLogEx(WARNING, "Authentication Failed UL-C"); + PrintAndLogEx(ERR, "Authentication Failed UL-C"); return 0; } } else { - if ( !ul_select(card) ) return 0; + if (!ul_select(card, false)) return 0; if (hasAuthKey) { if (ulev1_requestAuthentication(authenticationkey, pack, packSize) < 1) { - DropField(); - PrintAndLogEx(WARNING, "Authentication Failed UL-EV1/NTAG"); + PrintAndLogEx(ERR, "Authentication Failed UL-EV1/NTAG"); return 0; } } @@ -268,7 +271,7 @@ static int ul_auth_select( iso14a_card_select_t *card, TagTypeUL_t tagtype, bool return 1; } -static int ulev1_getVersion( uint8_t *response, uint16_t responseLength ){ +static int ulev1_getVersion(uint8_t *response, uint16_t responseLength) { uint8_t cmd[] = {MIFARE_ULEV1_VERSION}; int len = ul_send_cmd_raw(cmd, sizeof(cmd), response, responseLength); @@ -285,21 +288,24 @@ static int ulev1_getVersion( uint8_t *response, uint16_t responseLength ){ // return 0; // } -static int ulev1_readCounter( uint8_t counter, uint8_t *response, uint16_t responseLength ){ + +static int ulev1_readCounter(uint8_t counter, uint8_t *response, uint16_t responseLength) { uint8_t cmd[] = {MIFARE_ULEV1_READ_CNT, counter}; int len = ul_send_cmd_raw(cmd, sizeof(cmd), response, responseLength); return len; } -static int ulev1_readTearing( uint8_t counter, uint8_t *response, uint16_t responseLength ){ + +static int ulev1_readTearing(uint8_t counter, uint8_t *response, uint16_t responseLength) { uint8_t cmd[] = {MIFARE_ULEV1_CHECKTEAR, counter}; int len = ul_send_cmd_raw(cmd, sizeof(cmd), response, responseLength); return len; } -static int ulev1_readSignature( uint8_t *response, uint16_t responseLength ){ + +static int ulev1_readSignature(uint8_t *response, uint16_t responseLength) { uint8_t cmd[] = {MIFARE_ULEV1_READSIG, 0x00}; int len = ul_send_cmd_raw(cmd, sizeof(cmd), response, responseLength); @@ -320,9 +326,9 @@ static int ulev1_readSignature( uint8_t *response, uint16_t responseLength ){ // UL responds with read of page 0, fudan doesn't respond. // // make sure field is off before calling this function -static int ul_fudan_check( void ){ +static int ul_fudan_check(void) { iso14a_card_select_t card; - if ( !ul_select(&card) ) + if (!ul_select(&card, false)) return UL_ERROR; UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_NO_DISCONNECT, 4, 0}}; @@ -338,20 +344,17 @@ static int ul_fudan_check( void ){ return (!resp.d.asBytes[0]) ? FUDAN_UL : UL; //if response == 0x00 then Fudan, else Genuine NXP } -static int ul_print_default( uint8_t *data){ + +static int ul_print_default(uint8_t *data) { uint8_t uid[7]; - uid[0] = data[0]; - uid[1] = data[1]; - uid[2] = data[2]; - uid[3] = data[4]; - uid[4] = data[5]; - uid[5] = data[6]; - uid[6] = data[7]; + memcpy(uid, data, 3); + memcpy(uid+3, data+4, 4); - PrintAndLogEx(NORMAL," UID : %s ", sprint_hex(uid, 7)); + PrintAndLogEx(NORMAL," UID : %s", sprint_hex(uid, 7)); PrintAndLogEx(NORMAL," UID[0] : %02X, %s", uid[0], getManufacturerName(uid[0])); - if ( uid[0] == 0x05 && ((uid[1] & 0xf0) >> 4) == 2 ) { // is infineon and 66RxxP + + if (uid[0] == 0x05 && ((uid[1] & 0xf0) >> 4) == 2 ) { // is infineon and 66RxxP uint8_t chip = (data[8] & 0xC7); // 11000111 mask, bit 3,4,5 RFU switch (chip){ case 0xc2: PrintAndLogEx(NORMAL, " IC type : SLE 66R04P 770 Bytes"); break; //77 pages @@ -360,13 +363,13 @@ static int ul_print_default( uint8_t *data){ } } // CT (cascade tag byte) 0x88 xor SN0 xor SN1 xor SN2 - int crc0 = 0x88 ^ data[0] ^ data[1] ^data[2]; + int crc0 = 0x88 ^ uid[0] ^ uid[1] ^ uid[2]; if ( data[3] == crc0 ) PrintAndLogEx(NORMAL, " BCC0 : %02X, Ok", data[3]); else PrintAndLogEx(NORMAL, " BCC0 : %02X, crc should be %02X", data[3], crc0); - int crc1 = data[4] ^ data[5] ^ data[6] ^data[7]; + int crc1 = uid[3] ^ uid[4] ^ uid[5] ^ uid[6]; if ( data[8] == crc1 ) PrintAndLogEx(NORMAL, " BCC1 : %02X, Ok", data[8]); else @@ -374,14 +377,14 @@ static int ul_print_default( uint8_t *data){ PrintAndLogEx(NORMAL, " Internal : %02X, %sdefault", data[9], (data[9]==0x48)?"":"not " ); - PrintAndLogEx(NORMAL, " Lock : %s (binary %s %s)", + PrintAndLogEx(NORMAL, " Lock : %s (binary %s %s)", sprint_hex(data+10, 2), printBits(1, data+10), printBits(1, data+11) ); PrintAndLogEx(NORMAL, "OneTimePad : %s (binary %s %s %s %s)\n", - sprint_hex(data + 12, 4), + sprint_hex(data+12, 4), printBits(1, data+12), printBits(1, data+13), printBits(1, data+14), @@ -391,6 +394,7 @@ static int ul_print_default( uint8_t *data){ return 0; } + static int ndef_print_CC(uint8_t *data) { // no NDEF message if(data[0] != 0xe1) @@ -414,55 +418,55 @@ static int ndef_print_CC(uint8_t *data) { return 0; } + int ul_print_type(uint32_t tagtype, uint8_t spaces){ char spc[11] = " "; spc[10]=0x00; char *spacer = spc + (10-spaces); - if ( tagtype & UL ) + if (tagtype & UL ) PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight (MF0ICU1) %s", spacer, (tagtype & MAGIC) ? "" : "" ); - else if ( tagtype & UL_C) + else if (tagtype & UL_C) PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight C (MF0ULC) %s", spacer, (tagtype & MAGIC) ? "" : "" ); - else if ( tagtype & UL_EV1_48) + else if (tagtype & UL_EV1_48) PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight EV1 48bytes (MF0UL1101)", spacer); - else if ( tagtype & UL_EV1_128) + else if (tagtype & UL_EV1_128) PrintAndLogEx(NORMAL, "%sTYPE : MIFARE Ultralight EV1 128bytes (MF0UL2101)", spacer); - else if ( tagtype & NTAG ) + else if (tagtype & NTAG) PrintAndLogEx(NORMAL, "%sTYPE : NTAG UNKNOWN", spacer); - else if ( tagtype & NTAG_203 ) + else if (tagtype & NTAG_203) PrintAndLogEx(NORMAL, "%sTYPE : NTAG 203 144bytes (NT2H0301F0DT)", spacer); - else if ( tagtype & NTAG_210 ) + else if (tagtype & NTAG_210) PrintAndLogEx(NORMAL, "%sTYPE : NTAG 210 48bytes (NT2L1011G0DU)", spacer); - else if ( tagtype & NTAG_212 ) + else if (tagtype & NTAG_212) PrintAndLogEx(NORMAL, "%sTYPE : NTAG 212 128bytes (NT2L1211G0DU)", spacer); - else if ( tagtype & NTAG_213 ) + else if (tagtype & NTAG_213) PrintAndLogEx(NORMAL, "%sTYPE : NTAG 213 144bytes (NT2H1311G0DU)", spacer); - else if ( tagtype & NTAG_215 ) + else if (tagtype & NTAG_215) PrintAndLogEx(NORMAL, "%sTYPE : NTAG 215 504bytes (NT2H1511G0DU)", spacer); - else if ( tagtype & NTAG_216 ) + else if (tagtype & NTAG_216) PrintAndLogEx(NORMAL, "%sTYPE : NTAG 216 888bytes (NT2H1611G0DU)", spacer); - else if ( tagtype & NTAG_I2C_1K ) + else if (tagtype & NTAG_I2C_1K) PrintAndLogEx(NORMAL, "%sTYPE : NTAG I%sC 888bytes (NT3H1101FHK)", spacer, "\xFD"); - else if ( tagtype & NTAG_I2C_2K ) + else if (tagtype & NTAG_I2C_2K) PrintAndLogEx(NORMAL, "%sTYPE : NTAG I%sC 1904bytes (NT3H1201FHK)", spacer, "\xFD"); - else if ( tagtype & MY_D ) + else if (tagtype & MY_D) PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 (SLE 66RxxS)", spacer); - else if ( tagtype & MY_D_NFC ) + else if (tagtype & MY_D_NFC) PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 NFC (SLE 66RxxP)", spacer); - else if ( tagtype & MY_D_MOVE ) - PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 move (SLE 66R01P)", spacer); - else if ( tagtype & MY_D_MOVE_NFC ) - PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 move NFC (SLE 66R01P)", spacer); - else if ( tagtype & MY_D_MOVE_LEAN ) + else if (tagtype & MY_D_MOVE) + PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 move | my-d\x99move NFC (SLE 66R01P)", spacer); + else if (tagtype & MY_D_MOVE_LEAN) PrintAndLogEx(NORMAL, "%sTYPE : INFINEON my-d\x99 move lean (SLE 66R01L)", spacer); - else if ( tagtype & FUDAN_UL ) + else if (tagtype & FUDAN_UL) PrintAndLogEx(NORMAL, "%sTYPE : FUDAN Ultralight Compatible (or other compatible) %s", spacer, (tagtype & MAGIC) ? "" : "" ); else PrintAndLogEx(NORMAL, "%sTYPE : Unknown %06x", spacer, tagtype); return 0; } -static int ulc_print_3deskey( uint8_t *data){ + +static int ulc_print_3deskey(uint8_t *data) { PrintAndLogEx(NORMAL, " deskey1 [44/0x2C] : %s [%.4s]", sprint_hex(data ,4),data); PrintAndLogEx(NORMAL, " deskey1 [45/0x2D] : %s [%.4s]", sprint_hex(data+4 ,4),data+4); PrintAndLogEx(NORMAL, " deskey2 [46/0x2E] : %s [%.4s]", sprint_hex(data+8 ,4),data+8); @@ -471,27 +475,22 @@ static int ulc_print_3deskey( uint8_t *data){ return 0; } -static int ulc_print_configuration( uint8_t *data){ + +static int ulc_print_configuration(uint8_t *data) { PrintAndLogEx(NORMAL, "--- UL-C Configuration"); - PrintAndLogEx(NORMAL, " Higher Lockbits [40/0x28] : %s (binary %s %s)", + PrintAndLogEx(NORMAL, " Higher Lockbits [40/0x28] : %s (binary %s %s)", sprint_hex(data, 2), printBits(1, data), printBits(1, data+1) ); - PrintAndLogEx(NORMAL, " Counter [41/0x29] : %s (binary %s %s %s %s)", - sprint_hex(data+4, 4), - printBits(1, data+4), - printBits(1, data+5), - printBits(1, data+6), - printBits(1, data+7) - ); + PrintAndLogEx(NORMAL, " Counter [41/0x29] : %s", sprint_hex(data+4, 2)); bool validAuth = (data[8] >= 0x03 && data[8] <= 0x30); - if ( validAuth ) + if (validAuth) PrintAndLogEx(NORMAL, " Auth0 [42/0x2A] : %s page %d/0x%02X and above need authentication", sprint_hex(data+8, 4), data[8], data[8] ); else{ - if ( data[8] == 0){ + if (data[8] == 0) { PrintAndLogEx(NORMAL, " Auth0 [42/0x2A] : %s default", sprint_hex(data+8, 4) ); } else { PrintAndLogEx(NORMAL, " Auth0 [42/0x2A] : %s auth byte is out-of-range", sprint_hex(data+8, 4) ); @@ -504,7 +503,8 @@ static int ulc_print_configuration( uint8_t *data){ return 0; } -static int ulev1_print_configuration( uint8_t *data, uint8_t startPage){ + +static int ulev1_print_configuration(uint8_t *data, uint8_t startPage) { PrintAndLogEx(NORMAL, "\n--- Tag Configuration"); @@ -515,33 +515,34 @@ static int ulev1_print_configuration( uint8_t *data, uint8_t startPage){ uint8_t vctid = data[5]; PrintAndLogEx(NORMAL, " cfg0 [%u/0x%02X] : %s", startPage, startPage, sprint_hex(data, 4)); - if ( data[3] < 0xff ) - PrintAndLogEx(NORMAL, " - page %d and above need authentication",data[3]); + if (data[3] < 0xff) + PrintAndLogEx(NORMAL, " - page %d and above need authentication", data[3]); else PrintAndLogEx(NORMAL, " - pages don't need authentication"); PrintAndLogEx(NORMAL, " - strong modulation mode %s", (strg_mod_en) ? "enabled" : "disabled"); PrintAndLogEx(NORMAL, " cfg1 [%u/0x%02X] : %s", startPage + 1, startPage + 1, sprint_hex(data+4, 4) ); - if ( authlim == 0) + if (authlim == 0) PrintAndLogEx(NORMAL, " - Unlimited password attempts"); else PrintAndLogEx(NORMAL, " - Max number of password attempts is %d", authlim); PrintAndLogEx(NORMAL, " - user configuration %s", cfglck ? "permanently locked":"writeable"); PrintAndLogEx(NORMAL, " - %s access is protected with password", prot ? "read and write":"write"); PrintAndLogEx(NORMAL, " - %02X, Virtual Card Type Identifier is %s default", vctid, (vctid==0x05)? "":"not"); - PrintAndLogEx(NORMAL, " PWD [%u/0x%02X] : %s- (cannot be read)", startPage + 2, startPage + 2, sprint_hex(data+8, 4)); - PrintAndLogEx(NORMAL, " PACK [%u/0x%02X] : %s - (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data+12, 2)); - PrintAndLogEx(NORMAL, " RFU [%u/0x%02X] : %s- (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data+14, 2)); + PrintAndLogEx(NORMAL, " PWD [%u/0x%02X] : %s- (cannot be read)", startPage + 2, startPage + 2, sprint_hex(data+8, 4)); + PrintAndLogEx(NORMAL, " PACK [%u/0x%02X] : %s - (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data+12, 2)); + PrintAndLogEx(NORMAL, " RFU [%u/0x%02X] : %s- (cannot be read)", startPage + 3, startPage + 3, sprint_hex(data+14, 2)); return 0; } -static int ulev1_print_counters(){ + +static int ulev1_print_counters(void) { PrintAndLogEx(NORMAL, "--- Tag Counters"); uint8_t tear[1] = {0}; uint8_t counter[3] = {0,0,0}; uint16_t len = 0; for ( uint8_t i = 0; i<3; ++i) { - ulev1_readTearing(i,tear,sizeof(tear)); - len = ulev1_readCounter(i,counter, sizeof(counter) ); + ulev1_readTearing(i, tear, sizeof(tear)); + len = ulev1_readCounter(i, counter, sizeof(counter) ); if (len == 3) { PrintAndLogEx(NORMAL, " [%0d] : %s", i, sprint_hex(counter,3)); PrintAndLogEx(NORMAL, " - %02X tearing %s", tear[0], ( tear[0]==0xBD)?"Ok":"failure"); @@ -550,6 +551,7 @@ static int ulev1_print_counters(){ return len; } + static int ulev1_print_signature( uint8_t *data, uint8_t len){ PrintAndLogEx(NORMAL, "\n--- Tag Signature"); PrintAndLogEx(NORMAL, "IC signature public key name : NXP NTAG21x (2013)"); @@ -561,9 +563,10 @@ static int ulev1_print_signature( uint8_t *data, uint8_t len){ return 0; } + static int ulev1_print_version(uint8_t *data){ PrintAndLogEx(NORMAL, "\n--- Tag Version"); - PrintAndLogEx(NORMAL, " Raw bytes : %s",sprint_hex(data, 8) ); + PrintAndLogEx(NORMAL, " Raw bytes : %s", sprint_hex(data, 8) ); PrintAndLogEx(NORMAL, " Vendor ID : %02X, %s", data[1], getManufacturerName(data[1])); PrintAndLogEx(NORMAL, " Product type : %s", getProductTypeStr(data[2])); PrintAndLogEx(NORMAL, " Product subtype : %02X, %s", data[3], (data[3]==1) ?"17 pF":"50pF"); @@ -574,154 +577,131 @@ static int ulev1_print_version(uint8_t *data){ return 0; } -/* -static int ulc_magic_test(){ - // Magic Ultralight test - // Magic UL-C, by observation, - // 1) it seems to have a static nonce response to 0x1A command. - // 2) the deskey bytes is not-zero:d out on as datasheet states. - // 3) UID - changeable, not only, but pages 0-1-2-3. - // 4) use the ul_magic_test ! magic tags answers specially! - int returnValue = UL_ERROR; - iso14a_card_select_t card; - uint8_t nonce1[11] = {0x00}; - uint8_t nonce2[11] = {0x00}; - int status = ul_select(&card); - if ( !status ){ - return UL_ERROR; - } - status = ulc_requestAuthentication(nonce1, sizeof(nonce1)); - if ( status > 0 ) { - status = ulc_requestAuthentication(nonce2, sizeof(nonce2)); - returnValue = ( !memcmp(nonce1, nonce2, 11) ) ? UL_C_MAGIC : UL_C; - } else { - returnValue = UL; - } - DropField(); - return returnValue; -} -*/ -static int ul_magic_test(){ - // Magic Ultralight tests - // 1) take present UID, and try to write it back. OBSOLETE - // 2) make a wrong length write to page0, and see if tag answers with ACK/NACK: +static int ul_magic_test(void) { + // try a compatibility write to page0, and see if tag answers with ACK/NACK to the first part of the command iso14a_card_select_t card; - if ( !ul_select(&card) ) + if (!ul_select(&card, false)) return UL_ERROR; - int status = ul_comp_write(0, NULL, 0); - DropField(); - if ( status == 0 ) + int status = ul_comp_write_ex(0, NULL, 0, true); + if (status == 0) { return MAGIC; + } return 0; } + uint32_t GetHF14AMfU_Type(void){ TagTypeUL_t tagtype = UNKNOWN; iso14a_card_select_t card; uint8_t version[10] = {0x00}; - int status = 0; int len; - if (!ul_select(&card)) return UL_ERROR; - - // Ultralight - ATQA / SAK - if ( card.atqa[1] != 0x00 || card.atqa[0] != 0x44 || card.sak != 0x00 ) { - PrintAndLogEx(NORMAL, "Tag is not Ultralight | NTAG | MY-D [ATQA: %02X %02X SAK: %02X]\n", card.atqa[1], card.atqa[0], card.sak); + if (!ul_select(&card, true)) { DropField(); + msleep(200); return UL_ERROR; } - if ( card.uid[0] != 0x05) { - - len = ulev1_getVersion(version, sizeof(version)); + // Check for Ultralight Family + if (card.uidlen != 7 || (card.sak & 0x38) != 0x00) { DropField(); + PrintAndLogEx(NORMAL, "Tag is not Ultralight | NTAG | MY-D [ATQA: %02X %02X SAK: %02X]\n", card.atqa[1], card.atqa[0], card.sak); + return UL_ERROR; + } - switch (len) { - case 0x0A: { - - if ( version[2] == 0x03 && version[6] == 0x0B ) - tagtype = UL_EV1_48; - else if ( version[2] == 0x03 && version[6] != 0x0B ) - tagtype = UL_EV1_128; - else if ( version[2] == 0x04 && version[3] == 0x01 && version[6] == 0x0B ) - tagtype = NTAG_210; - else if ( version[2] == 0x04 && version[3] == 0x01 && version[6] == 0x0E ) - tagtype = NTAG_212; - else if ( version[2] == 0x04 && version[3] == 0x02 && version[6] == 0x0F ) - tagtype = NTAG_213; - else if ( version[2] == 0x04 && version[3] == 0x02 && version[6] == 0x11 ) - tagtype = NTAG_215; - else if ( version[2] == 0x04 && version[3] == 0x02 && version[6] == 0x13 ) - tagtype = NTAG_216; - else if ( version[2] == 0x04 && version[3] == 0x05 && version[6] == 0x13 ) - tagtype = NTAG_I2C_1K; - else if ( version[2] == 0x04 && version[3] == 0x05 && version[6] == 0x15 ) - tagtype = NTAG_I2C_2K; - else if ( version[2] == 0x04 ) - tagtype = NTAG; - - break; - } - case 0x01: tagtype = UL_C; break; - case 0x00: tagtype = UL; break; - case -1 : tagtype = (UL | UL_C | NTAG_203); break; // could be UL | UL_C magic tags - default : tagtype = UNKNOWN; break; + if (card.uid[0] != 0x05) { + len = ulev1_getVersion(version, sizeof(version)); + if (len == 10) { + if (version[2] == 0x03 && version[6] == 0x0B) + tagtype = UL_EV1_48; + else if (version[2] == 0x03 && version[6] != 0x0B) + tagtype = UL_EV1_128; + else if (version[2] == 0x04 && version[3] == 0x01 && version[6] == 0x0B) + tagtype = NTAG_210; + else if (version[2] == 0x04 && version[3] == 0x01 && version[6] == 0x0E) + tagtype = NTAG_212; + else if (version[2] == 0x04 && version[3] == 0x02 && version[6] == 0x0F) + tagtype = NTAG_213; + else if (version[2] == 0x04 && version[3] == 0x02 && version[6] == 0x11) + tagtype = NTAG_215; + else if (version[2] == 0x04 && version[3] == 0x02 && version[6] == 0x13) + tagtype = NTAG_216; + else if (version[2] == 0x04 && version[3] == 0x05 && version[6] == 0x13) + tagtype = NTAG_I2C_1K; + else if (version[2] == 0x04 && version[3] == 0x05 && version[6] == 0x15) + tagtype = NTAG_I2C_2K; + else if (version[2] == 0x04) + tagtype = NTAG; } + // UL vs UL-C vs ntag203 test - if (tagtype & (UL | UL_C | NTAG_203)) { - if ( !ul_select(&card) ) return UL_ERROR; + if (tagtype == UNKNOWN) { + ul_halt(); + if (!ul_select(&card, false)) { + DropField(); + msleep(200); + return UL_ERROR; + } // do UL_C check first... uint8_t nonce[11] = {0x00}; - status = ulc_requestAuthentication(nonce, sizeof(nonce)); - DropField(); - if (status > 1) { + len = ulc_requestAuthentication(nonce, sizeof(nonce)); + ul_halt(); + if (len == 11) { tagtype = UL_C; } else { // need to re-select after authentication error - if ( !ul_select(&card) ) return UL_ERROR; + if (!ul_select(&card, false)) { + DropField(); + msleep(200); + return UL_ERROR; + } uint8_t data[16] = {0x00}; - // read page 0x26-0x29 (last valid ntag203 page) - status = ul_read(0x26, data, sizeof(data)); - if ( status <= 1 ) { + // read page 0x29 (last valid ntag203 page) + len = ul_read(0x29, data, sizeof(data)); + if (len <= 1) { tagtype = UL; } else { // read page 0x30 (should error if it is a ntag203) - status = ul_read(0x30, data, sizeof(data)); - if ( status <= 1 ){ + len = ul_read(0x30, data, sizeof(data)); + if (len <= 1) { + ul_halt(); tagtype = NTAG_203; - } else { - tagtype = UNKNOWN; } } - DropField(); } } if (tagtype & UL) { tagtype = ul_fudan_check(); - DropField(); + ul_halt(); } - } else { - DropField(); - // Infinition MY-D tests Exam high nibble + + } else { // manufacturer Infineon. Check for my-d variants + uint8_t nib = (card.uid[1] & 0xf0) >> 4; - switch ( nib ){ - // case 0: tagtype = SLE66R35E7; break; //or SLE 66R35E7 - mifare compat... should have different sak/atqa for mf 1k - case 1: tagtype = MY_D; break; //or SLE 66RxxS ... up to 512 pages of 8 user bytes... - case 2: tagtype = (MY_D_NFC); break; //or SLE 66RxxP ... up to 512 pages of 8 user bytes... (or in nfc mode FF pages of 4 bytes) - case 3: tagtype = (MY_D_MOVE | MY_D_MOVE_NFC); break; //or SLE 66R01P // 38 pages of 4 bytes //notice: we can not currently distinguish between these two - case 7: tagtype = MY_D_MOVE_LEAN; break; //or SLE 66R01L // 16 pages of 4 bytes + switch (nib) { + case 1: tagtype = MY_D; break; //or SLE 66RxxS ... up to 512 pages of 8 user bytes... + case 2: tagtype = MY_D_NFC; break; //or SLE 66RxxP ... up to 512 pages of 8 user bytes... (or in nfc mode FF pages of 4 bytes) + case 3: tagtype = MY_D_MOVE; break; //or SLE 66R01P // 38 pages of 4 bytes + case 7: tagtype = MY_D_MOVE_LEAN; break; //or SLE 66R01L // 16 pages of 4 bytes } } tagtype |= ul_magic_test(); + if (tagtype == (UNKNOWN | MAGIC)) tagtype = (UL_MAGIC); + + DropField(); + msleep(200); + + printf("Tagtype: %08x\n", tagtype); return tagtype; } + static int usage_hf_mfu_info(void) { PrintAndLogEx(NORMAL, "It gathers information about the tag and tries to detect what kind it is."); PrintAndLogEx(NORMAL, "Sometimes the tags are locked down, and you may need a key to be able to read the information"); @@ -740,24 +720,21 @@ static int usage_hf_mfu_info(void) { return 0; } -static int CmdHF14AMfUInfo(const char *Cmd){ + +static int CmdHF14AMfUInfo(const char *Cmd) { uint8_t authlim = 0xff; - uint8_t data[16] = {0x00}; iso14a_card_select_t card; - int status; bool errors = false; + uint8_t keybytes[16] = {0x00}; + uint8_t *authenticationkey = keybytes; + int keyLen = 0; bool hasAuthKey = false; bool locked = false; bool swapEndian = false; uint8_t cmdp = 0; - uint8_t dataLen = 0; - uint8_t authenticationkey[16] = {0x00}; - uint8_t *authkeyptr = authenticationkey; - uint8_t *key; uint8_t pack[4] = {0,0,0,0}; int len = 0; - char tempStr[50]; while(param_getchar(Cmd, cmdp) != 0x00) { @@ -768,15 +745,14 @@ static int CmdHF14AMfUInfo(const char *Cmd){ return usage_hf_mfu_info(); case 'k': case 'K': - dataLen = param_getstr(Cmd, cmdp+1, tempStr, sizeof(tempStr)); - if (dataLen == 32 || dataLen == 8) { //ul-c or ev1/ntag key length - errors = param_gethex(tempStr, 0, authenticationkey, dataLen); - dataLen /= 2; // handled as bytes from now on - } else { - PrintAndLogEx(ERR, "Key has incorrect length\n"); + keyLen = 32; + errors = param_gethex_ex(Cmd, cmdp+1, authenticationkey, &keyLen); + if (errors || (keyLen != 32 && keyLen != 8)) { //ul-c or ev1/ntag key length + PrintAndLogEx(ERR, "Key has incorrect length.\n"); errors = true; } cmdp += 2; + keyLen /= 2; hasAuthKey = true; break; case 'l': @@ -793,27 +769,35 @@ static int CmdHF14AMfUInfo(const char *Cmd){ } //Validations - if(errors) return usage_hf_mfu_info(); + if (errors) + return usage_hf_mfu_info(); TagTypeUL_t tagtype = GetHF14AMfU_Type(); - if (tagtype == UL_ERROR) return -1; + if (tagtype == UL_ERROR) { + return -1; + } PrintAndLogEx(NORMAL, "\n--- Tag Information ---------"); PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); ul_print_type(tagtype, 6); // Swap endianness - if (swapEndian && hasAuthKey) authkeyptr = SwapEndian64(authenticationkey, dataLen, (dataLen == 16) ? 8 : 4 ); + if (swapEndian && hasAuthKey) + authenticationkey = SwapEndian64(authenticationkey, keyLen, (keyLen == 16) ? 8 : 4 ); - if (!ul_auth_select( &card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack))) return -1; + if (!ul_auth_select(&card, tagtype, hasAuthKey, authenticationkey, pack, sizeof(pack))) { + DropField(); + return -1; + } // read pages 0,1,2,3 (should read 4pages) - status = ul_read(0, data, sizeof(data)); - if ( status == -1 ) { + uint8_t data[16]; + len = ul_read(0, data, sizeof(data)); + if (len == -1) { DropField(); PrintAndLogEx(WARNING, "Error: tag didn't answer to READ"); - return status; - } else if (status == 16) { + return -1; + } else if (len == 16) { ul_print_default(data); ndef_print_CC(data+12); } else { @@ -825,36 +809,41 @@ static int CmdHF14AMfUInfo(const char *Cmd){ // read pages 0x28, 0x29, 0x2A, 0x2B uint8_t ulc_conf[16] = {0x00}; - status = ul_read(0x28, ulc_conf, sizeof(ulc_conf)); - if ( status == -1 ){ - PrintAndLogEx(WARNING, "Error: tag didn't answer to READ UL-C"); + len = ul_read(0x28, ulc_conf, sizeof(ulc_conf)); + if (len == -1) { DropField(); - return status; + PrintAndLogEx(WARNING, "Error: tag didn't answer to READ UL-C"); + return -1; + } + if (len == 16) { + ulc_print_configuration(ulc_conf); + } else { + locked = true; } - if (status == 16) ulc_print_configuration(ulc_conf); - else locked = true; if ((tagtype & MAGIC)) { //just read key uint8_t ulc_deskey[16] = {0x00}; - status = ul_read(0x2C, ulc_deskey, sizeof(ulc_deskey)); - if ( status == -1 ) { + len = ul_read(0x2C, ulc_deskey, sizeof(ulc_deskey)); + if (len == -1) { DropField(); PrintAndLogEx(WARNING, "Error: tag didn't answer to READ magic"); - return status; + return -1; } - if (status == 16) ulc_print_3deskey(ulc_deskey); - + if (len == 16) ulc_print_3deskey(ulc_deskey); } else { - DropField(); // if we called info with key, just return - if ( hasAuthKey ) return 1; + if (hasAuthKey) { + DropField(); + return 1; + } // also try to diversify default keys.. look into CmdHF14AMfuGenDiverseKeys PrintAndLogEx(INFO, "Trying some default 3des keys"); for (uint8_t i = 0; i < KEYS_3DES_COUNT; ++i ) { - key = default_3des_keys[i]; + uint8_t *key = default_3des_keys[i]; if (ulc_authentication(key, true)) { + DropField(); PrintAndLogEx(SUCCESS, "Found default 3des key: "); uint8_t keySwap[16]; memcpy(keySwap, SwapEndian64(key,16,8), 16); @@ -862,6 +851,7 @@ static int CmdHF14AMfUInfo(const char *Cmd){ return 1; } } + DropField(); return 1; } } @@ -872,53 +862,66 @@ static int CmdHF14AMfUInfo(const char *Cmd){ if ((tagtype & (UL_EV1_48 | UL_EV1_128))) { if (ulev1_print_counters() != 3) { // failed - re-select - if (!ul_auth_select( &card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack))) return -1; + if (!ul_auth_select( &card, tagtype, hasAuthKey, authenticationkey, pack, sizeof(pack))) { + DropField(); + return -1; + } } } if ((tagtype & (UL_EV1_48 | UL_EV1_128 | NTAG_213 | NTAG_215 | NTAG_216 | NTAG_I2C_1K | NTAG_I2C_2K ))) { uint8_t ulev1_signature[32] = {0x00}; - status = ulev1_readSignature( ulev1_signature, sizeof(ulev1_signature)); - if ( status == -1 ) { - PrintAndLogEx(WARNING, "Error: tag didn't answer to READ SIGNATURE"); + len = ulev1_readSignature(ulev1_signature, sizeof(ulev1_signature)); + if (len == -1) { DropField(); - return status; + PrintAndLogEx(WARNING, "Error: tag didn't answer to READ SIGNATURE"); + return -1; } - if (status == 32) ulev1_print_signature( ulev1_signature, sizeof(ulev1_signature)); - else { + if (len == 32) { + ulev1_print_signature( ulev1_signature, sizeof(ulev1_signature)); + } else { // re-select - if (!ul_auth_select( &card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack))) return -1; + if (!ul_auth_select( &card, tagtype, hasAuthKey, authenticationkey, pack, sizeof(pack))) { + DropField(); + return -1; + } } } if ((tagtype & (UL_EV1_48 | UL_EV1_128 | NTAG_210 | NTAG_212 | NTAG_213 | NTAG_215 | NTAG_216 | NTAG_I2C_1K | NTAG_I2C_2K))) { uint8_t version[10] = {0x00}; - status = ulev1_getVersion(version, sizeof(version)); - if ( status == -1 ) { - PrintAndLogEx(WARNING, "Error: tag didn't answer to GETVERSION"); + len = ulev1_getVersion(version, sizeof(version)); + if (len == -1) { DropField(); - return status; - } else if (status == 10) { + PrintAndLogEx(WARNING, "Error: tag didn't answer to GETVERSION"); + return -1; + } else if (len == 10) { ulev1_print_version(version); } else { locked = true; - if (!ul_auth_select( &card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack))) return -1; + if (!ul_auth_select( &card, tagtype, hasAuthKey, authenticationkey, pack, sizeof(pack))) { + DropField(); + return -1; + } } uint8_t startconfigblock = 0; uint8_t ulev1_conf[16] = {0x00}; // config blocks always are last 4 pages - for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++) - if (tagtype & UL_TYPES_ARRAY[idx]) + for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++) { + if (tagtype & UL_TYPES_ARRAY[idx]) { startconfigblock = UL_MEMORY_ARRAY[idx]-3; + break; + } + } - if (startconfigblock){ // if we know where the config block is... - status = ul_read(startconfigblock, ulev1_conf, sizeof(ulev1_conf)); - if ( status == -1 ) { - PrintAndLogEx(WARNING, "Error: tag didn't answer to READ EV1"); + if (startconfigblock) { // if we know where the config block is... + len = ul_read(startconfigblock, ulev1_conf, sizeof(ulev1_conf)); + if (len == -1) { DropField(); - return status; - } else if (status == 16) { + PrintAndLogEx(WARNING, "Error: tag didn't answer to READ EV1"); + return -1; + } else if (len == 16) { // save AUTHENTICATION LIMITS for later: authlim = (ulev1_conf[4] & 0x07); ulev1_print_configuration(ulev1_conf, startconfigblock); @@ -929,17 +932,20 @@ static int CmdHF14AMfUInfo(const char *Cmd){ // 0 = limitless. // 1-7 = limit. No automatic tries then. // hasAuthKey, if we was called with key, skip test. - if ( !authlim && !hasAuthKey ) { + if (!authlim && !hasAuthKey) { PrintAndLogEx(NORMAL, "\n--- Known EV1/NTAG passwords."); len = 0; for (uint8_t i = 0; i < KEYS_PWD_COUNT; ++i ) { - key = default_pwd_pack[i]; + uint8_t *key = default_pwd_pack[i]; len = ulev1_requestAuthentication(key, pack, sizeof(pack)); if (len >= 1) { - PrintAndLogEx(SUCCESS, "Found a default password: %s || Pack: %02X %02X",sprint_hex(key, 4), pack[0], pack[1]); + PrintAndLogEx(SUCCESS, "Found a default password: %s || Pack: %02X %02X", sprint_hex(key, 4), pack[0], pack[1]); break; } else { - if (!ul_auth_select( &card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack))) return -1; + if (!ul_auth_select( &card, tagtype, hasAuthKey, authenticationkey, pack, sizeof(pack))) { + DropField(); + return -1; + } } } if (len < 1) PrintAndLogEx(WARNING, "password not known"); @@ -947,8 +953,11 @@ static int CmdHF14AMfUInfo(const char *Cmd){ } DropField(); - if (locked) PrintAndLogEx(FAILED, "\nTag appears to be locked, try using the key to get more info"); + + if (locked) + PrintAndLogEx(FAILED, "\nTag appears to be locked, try using the key to get more info"); PrintAndLogEx(NORMAL, ""); + return 1; } @@ -969,48 +978,35 @@ static int usage_hf_mfu_wrbl(void) { return 0; } + static int CmdHF14AMfUWrBl(const char *Cmd){ int blockNo = -1; bool errors = false; + uint8_t keybytes[16] = {0x00}; + uint8_t *authenticationkey = keybytes; + int keyLen = 0; bool hasAuthKey = false; - bool hasPwdKey = false; bool swapEndian = false; - uint8_t cmdp = 0; - uint8_t keylen = 0; uint8_t blockdata[20] = {0x00}; - uint8_t data[16] = {0x00}; - uint8_t authenticationkey[16] = {0x00}; - uint8_t *authKeyPtr = authenticationkey; - while(param_getchar(Cmd, cmdp) != 0x00) - { - switch(param_getchar(Cmd, cmdp)) - { + while(param_getchar(Cmd, cmdp) != 0x00) { + switch(param_getchar(Cmd, cmdp)) { case 'h': case 'H': return usage_hf_mfu_wrbl(); case 'k': case 'K': - // EV1/NTAG size key - keylen = param_gethex(Cmd, cmdp+1, data, 8); - if ( !keylen ) { - memcpy(authenticationkey, data, 4); - cmdp += 2; - hasPwdKey = true; - break; + keyLen = 32; + errors = param_gethex_ex(Cmd, cmdp+1, authenticationkey, &keyLen); + if (errors || (keyLen != 32 && keyLen != 8)) { //ul-c or ev1/ntag key length + PrintAndLogEx(ERR, "Key has incorrect length.\n"); + errors = true; } - // UL-C size key - keylen = param_gethex(Cmd, cmdp+1, data, 32); - if (!keylen){ - memcpy(authenticationkey, data, 16); - cmdp += 2; - hasAuthKey = true; - break; - } - PrintAndLogEx(ERR, "Key has incorrect length\n"); - errors = true; + cmdp += 2; + keyLen /= 2; + hasAuthKey = true; break; case 'b': case 'B': @@ -1044,24 +1040,28 @@ static int CmdHF14AMfUWrBl(const char *Cmd){ if(errors) return usage_hf_mfu_wrbl(); } - if ( blockNo == -1 ) return usage_hf_mfu_wrbl(); + if (blockNo == -1) return usage_hf_mfu_wrbl(); // starting with getting tagtype TagTypeUL_t tagtype = GetHF14AMfU_Type(); - if (tagtype == UL_ERROR) return -1; + if (tagtype == UL_ERROR) { + return -1; + } uint8_t maxblockno = 0; - for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++){ - if (tagtype & UL_TYPES_ARRAY[idx]) + for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++) { + if (tagtype & UL_TYPES_ARRAY[idx]) { maxblockno = UL_MEMORY_ARRAY[idx]; + break; + } } if (blockNo > maxblockno){ + DropField(); PrintAndLogEx(WARNING, "block number too large. Max block is %u/0x%02X \n", maxblockno,maxblockno); return usage_hf_mfu_wrbl(); } // Swap endianness - if (swapEndian && hasAuthKey) authKeyPtr = SwapEndian64(authenticationkey, 16, 8); - if (swapEndian && hasPwdKey) authKeyPtr = SwapEndian64(authenticationkey, 4, 4); + if (swapEndian && hasAuthKey) authenticationkey = SwapEndian64(authenticationkey, keyLen, (keyLen == 16) ? 8 : 4); if ( blockNo <= 3) PrintAndLogEx(NORMAL, "Special Block: %0d (0x%02X) [ %s]", blockNo, blockNo, sprint_hex(blockdata, 4)); @@ -1070,27 +1070,24 @@ static int CmdHF14AMfUWrBl(const char *Cmd){ //Send write Block UsbCommand c = {CMD_MIFAREU_WRITEBL, {blockNo}}; - memcpy(c.d.asBytes,blockdata,4); + memcpy(c.d.asBytes, blockdata, 4); - if ( hasAuthKey ) { - c.arg[1] = 1; - memcpy(c.d.asBytes+4,authKeyPtr,16); - } - else if ( hasPwdKey ) { - c.arg[1] = 2; - memcpy(c.d.asBytes+4,authKeyPtr,4); + if (hasAuthKey) { + c.arg[1] = (keyLen == 16) ? 1 : 2; + memcpy(c.d.asBytes+4, authenticationkey, keyLen); } clearCommandBuffer(); SendCommand(&c); UsbCommand resp; - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { uint8_t isOK = resp.arg[0] & 0xff; PrintAndLogEx(SUCCESS, "isOk:%02x", isOK); } else { PrintAndLogEx(ERR, "Command execute timeout"); } + DropField(); return 0; } @@ -1112,18 +1109,17 @@ static int usage_hf_mfu_rdbl(void) { return 0; } + static int CmdHF14AMfURdBl(const char *Cmd){ int blockNo = -1; bool errors = false; + uint8_t keybytes[16] = {0x00}; + uint8_t *authenticationkey = keybytes; + int keyLen = 0; bool hasAuthKey = false; - bool hasPwdKey = false; bool swapEndian = false; uint8_t cmdp = 0; - uint8_t keylen = 0; - uint8_t data[16] = {0x00}; - uint8_t authenticationkey[16] = {0x00}; - uint8_t *authKeyPtr = authenticationkey; while(param_getchar(Cmd, cmdp) != 0x00) { @@ -1134,24 +1130,15 @@ static int CmdHF14AMfURdBl(const char *Cmd){ return usage_hf_mfu_rdbl(); case 'k': case 'K': - // EV1/NTAG size key - keylen = param_gethex(Cmd, cmdp+1, data, 8); - if ( !keylen ) { - memcpy(authenticationkey, data, 4); - cmdp += 2; - hasPwdKey = true; - break; + keyLen = 32; + errors = param_gethex_ex(Cmd, cmdp+1, authenticationkey, &keyLen); + if (errors || (keyLen != 32 && keyLen != 8)) { //ul-c or ev1/ntag key length + PrintAndLogEx(ERR, "Key has incorrect length.\n"); + errors = true; } - // UL-C size key - keylen = param_gethex(Cmd, cmdp+1, data, 32); - if (!keylen){ - memcpy(authenticationkey, data, 16); - cmdp += 2; - hasAuthKey = true; - break; - } - PrintAndLogEx(ERR, "Key has incorrect length\n"); - errors = true; + cmdp += 2; + keyLen /= 2; + hasAuthKey = true; break; case 'b': case 'B': @@ -1173,43 +1160,43 @@ static int CmdHF14AMfURdBl(const char *Cmd){ break; } //Validations - if(errors) return usage_hf_mfu_rdbl(); + if (errors) return usage_hf_mfu_rdbl(); } - if ( blockNo == -1 ) return usage_hf_mfu_rdbl(); + if (blockNo == -1) return usage_hf_mfu_rdbl(); // start with getting tagtype TagTypeUL_t tagtype = GetHF14AMfU_Type(); - if (tagtype == UL_ERROR) return -1; + if (tagtype == UL_ERROR) { + return -1; + } uint8_t maxblockno = 0; - for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++){ - if (tagtype & UL_TYPES_ARRAY[idx]) + for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++) { + if (tagtype & UL_TYPES_ARRAY[idx]) { maxblockno = UL_MEMORY_ARRAY[idx]; + break; + } } if (blockNo > maxblockno){ + DropField(); PrintAndLogEx(WARNING, "block number to large. Max block is %u/0x%02X \n", maxblockno,maxblockno); return usage_hf_mfu_rdbl(); } // Swap endianness - if (swapEndian && hasAuthKey) authKeyPtr = SwapEndian64(authenticationkey, 16, 8); - if (swapEndian && hasPwdKey) authKeyPtr = SwapEndian64(authenticationkey, 4, 4); + if (swapEndian) authenticationkey = SwapEndian64(authenticationkey, keyLen, (keyLen == 16) ? 8 : 4); //Read Block UsbCommand c = {CMD_MIFAREU_READBL, {blockNo}}; - if ( hasAuthKey ){ - c.arg[1] = 1; - memcpy(c.d.asBytes,authKeyPtr,16); - } - else if ( hasPwdKey ) { - c.arg[1] = 2; - memcpy(c.d.asBytes,authKeyPtr,4); + if (hasAuthKey) { + c.arg[1] = (keyLen == 16) ? 1 : 2; + memcpy(c.d.asBytes, authenticationkey, keyLen); } clearCommandBuffer(); SendCommand(&c); UsbCommand resp; - if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { uint8_t isOK = resp.arg[0] & 0xff; if (isOK) { uint8_t *data = resp.d.asBytes; @@ -1222,6 +1209,7 @@ static int CmdHF14AMfURdBl(const char *Cmd){ } else { PrintAndLogEx(ERR, "Command execute time-out"); } + DropField(); return 0; } @@ -1229,196 +1217,43 @@ static int CmdHF14AMfURdBl(const char *Cmd){ // // Mifare Ultralight / Ultralight-C / Ultralight-EV1 // Read and Dump Card Contents, using auto detection of tag size. -static int usage_hf_mfu_dump(void) { - PrintAndLogEx(NORMAL, "Reads all pages from Ultralight, Ultralight-C, Ultralight EV1"); - PrintAndLogEx(NORMAL, "NTAG 203, NTAG 210, NTAG 212, NTAG 213, NTAG 215, NTAG 216"); - PrintAndLogEx(NORMAL, "and saves binary dump into the file `filename.bin` or `cardUID.bin`"); - PrintAndLogEx(NORMAL, "It autodetects card type.\n"); - PrintAndLogEx(NORMAL, "Usage: hf mfu dump k l n "); - PrintAndLogEx(NORMAL, " Options : "); - PrintAndLogEx(NORMAL, " k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); - PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness"); - PrintAndLogEx(NORMAL, " n : filename w/o .bin to save the dump as"); - PrintAndLogEx(NORMAL, " p : starting Page number to manually set a page to start the dump at"); - PrintAndLogEx(NORMAL, " q : number of Pages to manually set how many pages to dump"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, " sample : hf mfu dump"); - PrintAndLogEx(NORMAL, " : hf mfu dump n myfile"); - PrintAndLogEx(NORMAL, " : hf mfu dump k 00112233445566778899AABBCCDDEEFF"); - PrintAndLogEx(NORMAL, " : hf mfu dump k AABBCCDDD\n"); - return 0; -} +typedef struct { + uint8_t version[8]; + uint8_t tbo[2]; + uint8_t tbo1[1]; + uint8_t pages; // max page number in dump + uint8_t signature[32]; + uint8_t counter_tearing[3][4]; // 3 bytes counter, 1 byte tearing flag + uint8_t data[1024]; +} mfu_dump_t; -static int CmdHF14AMfUDump(const char *Cmd){ - FILE *fout; - char filename[FILE_PATH_SIZE] = {0x00}; - char *fnameptr = filename; - uint8_t *lockbytes_t = NULL; - uint8_t lockbytes[2] = {0x00}; - uint8_t *lockbytes_t2 = NULL; - uint8_t lockbytes2[2] = {0x00}; - bool bit[16] = {0x00}; - bool bit2[16] = {0x00}; - uint8_t data[1024] = {0x00}; - bool hasAuthKey = false; - int i = 0; - int Pages = 16; +static void printMFUdumpEx(mfu_dump_t *card, uint16_t pages, uint8_t startpage, TagTypeUL_t tagtype) { + bool tmplockbit = false; - uint8_t dataLen = 0; - uint8_t cmdp = 0; - uint8_t authenticationkey[16] = {0x00}; - uint8_t *authKeyPtr = authenticationkey; - size_t fileNlen = 0; - bool errors = false; - bool swapEndian = false; - bool manualPages = false; - uint8_t startPage = 0; - char tempStr[50]; - unsigned char cleanASCII[4]; + bool bit[16] = {false}; + bool bit2[16] = {false}; - while(param_getchar(Cmd, cmdp) != 0x00) - { - switch(param_getchar(Cmd, cmdp)) - { - case 'h': - case 'H': - return usage_hf_mfu_dump(); - case 'k': - case 'K': - dataLen = param_getstr(Cmd, cmdp+1, tempStr, sizeof(tempStr)); - if (dataLen == 32 || dataLen == 8) { //ul-c or ev1/ntag key length - errors = param_gethex(tempStr, 0, authenticationkey, dataLen); - dataLen /= 2; - } else { - PrintAndLogEx(ERR, "Key has incorrect length\n"); - errors = true; - } - cmdp += 2; - hasAuthKey = true; - break; - case 'l': - case 'L': - swapEndian = true; - cmdp++; - break; - case 'n': - case 'N': - fileNlen = param_getstr(Cmd, cmdp+1, filename, sizeof(filename)); - if (!fileNlen) errors = true; - if (fileNlen > FILE_PATH_SIZE-5) fileNlen = FILE_PATH_SIZE-5; - cmdp += 2; - break; - case 'p': - case 'P': - startPage = param_get8(Cmd, cmdp+1); - manualPages = true; - cmdp += 2; - break; - case 'q': - case 'Q': - Pages = param_get8(Cmd, cmdp+1); - cmdp += 2; - manualPages = true; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - if(errors) break; + // standard lock bits + for(int i = 0; i < 16; i++){ + bit[i] = card->data[10+i/8] & (1 << (7-i%8)); } - //Validations - if(errors) return usage_hf_mfu_dump(); - - if (swapEndian && hasAuthKey) - authKeyPtr = SwapEndian64(authenticationkey, dataLen, (dataLen == 16) ? 8 : 4); - - TagTypeUL_t tagtype = GetHF14AMfU_Type(); - if (tagtype == UL_ERROR) return -1; - - if (!manualPages) //get number of pages to read - for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++) - if (tagtype & UL_TYPES_ARRAY[idx]) - Pages = UL_MEMORY_ARRAY[idx]+1; //add one as maxblks starts at 0 - - ul_print_type(tagtype, 0); - PrintAndLogEx(NORMAL, "Reading tag memory..."); - UsbCommand c = {CMD_MIFAREU_READCARD, {startPage,Pages}}; - if ( hasAuthKey ) { - if (tagtype & UL_C) - c.arg[2] = 1; //UL_C auth - else - c.arg[2] = 2; //UL_EV1/NTAG auth - - memcpy(c.d.asBytes, authKeyPtr, dataLen); - } - - clearCommandBuffer(); - SendCommand(&c); - UsbCommand resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp,1500)) { - PrintAndLogEx(ERR, "Command execute time-out"); - return 1; - } - if (resp.arg[0] != 1) { - PrintAndLogEx(ERR, "Failed reading block: (%02x)", i); - return 1; - } - - uint32_t startindex = resp.arg[2]; - uint32_t bufferSize = resp.arg[1]; - if (bufferSize > sizeof(data)) { - PrintAndLogEx(FAILED, "Data exceeded Buffer size!"); - bufferSize = sizeof(data); - } - GetFromBigBuf(data, bufferSize, startindex, NULL, -1, false); - - Pages = bufferSize/4; - // Load lock bytes. - int j = 0; - - lockbytes_t = data + 8; - lockbytes[0] = lockbytes_t[2]; - lockbytes[1] = lockbytes_t[3]; - for(j = 0; j < 16; j++){ - bit[j] = lockbytes[j/8] & ( 1 <<(7-j%8)); - } - - // Load bottom lockbytes if available - // TODO -- FIGURE OUT LOCK BYTES FOR TO EV1 and/or NTAG - if ( Pages == 44 ) { - lockbytes_t2 = data + (40*4); - lockbytes2[0] = lockbytes_t2[2]; - lockbytes2[1] = lockbytes_t2[3]; - for (j = 0; j < 16; j++) { - bit2[j] = lockbytes2[j/8] & ( 1 <<(7-j%8)); - } - } - - // add keys to block dump - if (hasAuthKey) { - if (!swapEndian){ - authKeyPtr = SwapEndian64(authenticationkey, dataLen, (dataLen == 16) ? 8 : 4); - } else { - authKeyPtr = authenticationkey; - } - - if (tagtype & UL_C){ //add 4 pages - memcpy(data + Pages*4, authKeyPtr, dataLen); - Pages += dataLen/4; - } else { // 2nd page from end - memcpy(data + (Pages*4) - 8, authenticationkey, dataLen); + // dynamic lock bits + // TODO -- FIGURE OUT LOCK BYTES FOR EV1 and/or NTAG + if (tagtype & UL_C) { + for (int i = 0; i < 16; i++) { + bit2[i] = card->data[40*4+i/8] & (1 << (7-i%8)); } } PrintAndLogEx(NORMAL, "\n Block# | Data |lck| Ascii"); PrintAndLogEx(NORMAL, "---------+-------------+---+------"); - for (i = 0; i < Pages; ++i) { - if ( i < 3 ) { - PrintAndLogEx(NORMAL, "%3d/0x%02X | %s| | ", i+startPage, i+startPage, sprint_hex(data + i * 4, 4)); + + for (int i = startpage; i < startpage + pages; i++) { + if (i < 3) { + PrintAndLogEx(NORMAL, "%3d/0x%02X | %s| | ", i, i, sprint_hex(card->data + i * 4, 4)); continue; } switch(i){ @@ -1466,34 +1301,240 @@ static int CmdHF14AMfUDump(const char *Cmd){ default: break; } - // convert unprintable characters and line breaks to dots - memcpy(cleanASCII, data+i*4, 4); - clean_ascii(cleanASCII, 4); - - PrintAndLogEx(NORMAL, "%3d/0x%02X | %s| %d | %.4s", i+startPage, i+startPage, sprint_hex(data + i * 4, 4), tmplockbit, cleanASCII); + PrintAndLogEx(NORMAL, "%3d/0x%02X | %s| %d | %.4s", i, i, sprint_hex(card->data + i * 4, 4), tmplockbit, sprint_ascii(card->data + i * 4, 4)); } PrintAndLogEx(NORMAL, "---------------------------------"); +} - // user supplied filename? - if (fileNlen < 1) { - // UID = data 0-1-2 4-5-6-7 (skips a beat) - sprintf(fnameptr,"%02X%02X%02X%02X%02X%02X%02X.bin", - data[0],data[1], data[2], data[4],data[5],data[6], data[7]); - } else { - sprintf(fnameptr + fileNlen,".bin"); - } - if ((fout = fopen(filename,"wb")) == NULL) { - PrintAndLogEx(NORMAL, "Could not create file name %s", filename); - return 1; - } - fwrite( data, 1, Pages*4, fout ); - fclose(fout); +static int usage_hf_mfu_dump(void) { + PrintAndLogEx(NORMAL, "Reads all pages from Ultralight, Ultralight-C, Ultralight EV1"); + PrintAndLogEx(NORMAL, "NTAG 203, NTAG 210, NTAG 212, NTAG 213, NTAG 215, NTAG 216"); + PrintAndLogEx(NORMAL, "and saves binary dump into the file `filename.bin` or `cardUID.bin`"); + PrintAndLogEx(NORMAL, "It autodetects card type.\n"); + PrintAndLogEx(NORMAL, "Usage: hf mfu dump k l n "); + PrintAndLogEx(NORMAL, " Options : "); + PrintAndLogEx(NORMAL, " k : (optional) key for authentication [UL-C 16bytes, EV1/NTAG 4bytes]"); + PrintAndLogEx(NORMAL, " l : (optional) swap entered key's endianness"); + PrintAndLogEx(NORMAL, " f : filename w/o .bin to save the dump as"); + PrintAndLogEx(NORMAL, " p : starting Page number to manually set a page to start the dump at"); + PrintAndLogEx(NORMAL, " q : number of Pages to manually set how many pages to dump"); - PrintAndLogEx(SUCCESS, "Dumped %d pages, wrote %d bytes to %s", Pages, Pages*4, filename); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, " sample : hf mfu dump"); + PrintAndLogEx(NORMAL, " : hf mfu dump n myfile"); + PrintAndLogEx(NORMAL, " : hf mfu dump k 00112233445566778899AABBCCDDEEFF"); + PrintAndLogEx(NORMAL, " : hf mfu dump k AABBCCDDD\n"); return 0; } + +static int CmdHF14AMfUDump(const char *Cmd){ + + char filename[FILE_PATH_SIZE] = {'\0'}; + size_t fileNameLen = 0; + uint8_t keybytes[16] = {0x00}; + uint8_t *authenticationkey = keybytes; + int keyLen = 0; + bool hasAuthKey = false; + uint8_t cmdp = 0; + bool errors = false; + bool swapEndian = false; + bool manualPages = false; + uint8_t startPage = 0; + int Pages = 16; + iso14a_card_select_t card_select; + mfu_dump_t card; + + while(param_getchar(Cmd, cmdp) != 0x00) + { + switch(param_getchar(Cmd, cmdp)) + { + case 'h': + case 'H': + return usage_hf_mfu_dump(); + case 'k': + case 'K': + keyLen = 32; + errors = param_gethex_ex(Cmd, cmdp+1, authenticationkey, &keyLen); + if (errors || (keyLen != 32 && keyLen != 8)) { //ul-c or ev1/ntag key length + PrintAndLogEx(ERR, "Key has incorrect length.\n"); + errors = true; + } + cmdp += 2; + keyLen /= 2; + hasAuthKey = true; + break; + case 'l': + case 'L': + swapEndian = true; + cmdp++; + break; + case 'f': + case 'F': + fileNameLen = param_getstr(Cmd, cmdp+1, filename, sizeof(filename)); + if (fileNameLen == 0) errors = true; + if (fileNameLen > FILE_PATH_SIZE-5) fileNameLen = FILE_PATH_SIZE-5; + cmdp += 2; + break; + case 'p': + case 'P': + startPage = param_get8(Cmd, cmdp+1); + manualPages = true; + cmdp += 2; + break; + case 'q': + case 'Q': + Pages = param_get8(Cmd, cmdp+1); + cmdp += 2; + manualPages = true; + break; + default: + PrintAndLogEx(ERR, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + if (errors) break; + } + + //Validations + if (errors) return usage_hf_mfu_dump(); + + if (swapEndian && hasAuthKey) + authenticationkey = SwapEndian64(authenticationkey, keyLen, (keyLen == 16) ? 8 : 4); + + TagTypeUL_t tagtype = GetHF14AMfU_Type(); + + if (tagtype == UL_ERROR) { + return -1; + } + + uint8_t maxPages = 0; + for (uint8_t idx = 0; idx < MAX_UL_TYPES; idx++) { + if (tagtype & UL_TYPES_ARRAY[idx]) { + maxPages = UL_MEMORY_ARRAY[idx]+1; //add one as maxblks starts at 0 + break; + } + } + + if (!manualPages) { + Pages = maxPages; + } else { + if (startPage + Pages - 1 > maxPages - 1) { + PrintAndLogEx(ERR, "Invalid page range. Card has only %d readable pages.", maxPages); + DropField(); + return 1; + } + } + + ul_print_type(tagtype, 0); + + PrintAndLogEx(NORMAL, "Reading tag memory..."); + memset(&card, 0x00, sizeof(card)); + UsbCommand c = {CMD_MIFAREU_READCARD, {startPage, Pages}}; + if (hasAuthKey) { + if (tagtype & UL_C) + c.arg[2] = 1; //UL_C auth + else + c.arg[2] = 2; //UL_EV1/NTAG auth + memcpy(c.d.asBytes, authenticationkey, keyLen); + } + + clearCommandBuffer(); + SendCommand(&c); + UsbCommand resp; + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + PrintAndLogEx(ERR, "Command execution timeout"); + DropField(); + return 1; + } + if (resp.arg[0] != 1) { + PrintAndLogEx(ERR, "Failed reading card"); + DropField(); + return 1; + } + + uint32_t startindex = resp.arg[2]; + uint32_t bufferSize = resp.arg[1]; + if (bufferSize > sizeof(card.data)) { + PrintAndLogEx(FAILED, "Data exceeded Buffer size!"); + bufferSize = sizeof(card.data); + } + + if (!GetFromBigBuf(card.data + startPage*4, bufferSize, startindex, NULL, -1, false)) { + PrintAndLogEx(ERR, "Command execution timeout"); + DropField(); + return 1; + } + + // not ul_c and not std ul then attempt to collect + // VERSION, SIGNATURE, COUNTERS, TEARING, PACK + if (!(tagtype & UL_C || tagtype & UL)) { + //attempt to read pack + if (!ul_auth_select(&card_select, tagtype, true, authenticationkey, card.data + maxPages*4 - 4, 2)) { + //reset pack + card.data[maxPages*4 - 4] = 0; + card.data[maxPages*4 - 3] = 0; + } + + if (hasAuthKey) { + uint8_t dummy_pack[2]; + ul_auth_select(&card_select, tagtype, hasAuthKey, authenticationkey, dummy_pack, sizeof(dummy_pack)); + } else { + ul_select(&card_select, false); + } + ulev1_getVersion(card.version, sizeof(card.version)); + for (uint8_t n = 0; n < 3; ++n) { + ulev1_readTearing(n, &card.counter_tearing[n][3], 1); + ulev1_readCounter(n, &card.counter_tearing[n][0], 3); + } + + ulev1_readSignature(card.signature, sizeof(card.signature)); + } + + DropField(); + + // add key to dump data + if (hasAuthKey) { + authenticationkey = SwapEndian64(authenticationkey, keyLen, (keyLen == 16) ? 8 : 4); + if (tagtype & UL_C){ // additional 4 pages + memcpy(card.data + maxPages*4, authenticationkey, keyLen); + maxPages += 4; + } else { // 2nd page from end + memcpy(card.data + (maxPages*4) - 8, authenticationkey, 4); + } + } + + printMFUdumpEx(&card, Pages, startPage, tagtype); + + if (!manualPages) { + // user supplied filename? + if (fileNameLen < 1) { + char *fptr = filename; + fptr += sprintf(fptr, "hf-mfu-"); + uint8_t UID[] = {card.data[0], card.data[1], card.data[2], card.data[4], card.data[5], card.data[6], card.data[7]}; + FillFileNameByUID(fptr, UID, "-dump.bin", 7); + } else { + sprintf(filename + fileNameLen, ".bin"); + } + +#define MFU_DUMP_PREFIX_LENGTH (sizeof(card) - sizeof(card.data)) + + FILE *fout; + if ((fout = fopen(filename, "wb")) == NULL) { + PrintAndLogEx(ERR, "Could not create file name %s", filename); + return 1; + } + fwrite(&card, 1, MFU_DUMP_PREFIX_LENGTH + maxPages*4, fout); + fclose(fout); + + PrintAndLogEx(SUCCESS, "Dumped %d pages, wrote %d bytes to %s", maxPages, MFU_DUMP_PREFIX_LENGTH + maxPages*4, filename); + } + + return 0; +} + + //------------------------------------------------------------------------------- // Ultralight C Methods //------------------------------------------------------------------------------- @@ -1533,110 +1574,16 @@ static int CmdHF14AMfucAuth(const char *Cmd){ } uint8_t *key = default_3des_keys[keyNo]; - if (ulc_authentication(key, true)) + if (ulc_authentication(key, true)) { + DropField(); PrintAndLogEx(SUCCESS, "Authentication successful. 3des key: %s",sprint_hex(key, 16)); - else + } else { + DropField(); PrintAndLogEx(WARNING, "Authentication failed"); - - return 0; -} - -/** -A test function to validate that the polarssl-function works the same -was as the openssl-implementation. -Commented out, since it requires openssl - -int CmdTestDES(const char * cmd) -{ - uint8_t key[16] = {0x00}; - - memcpy(key,key3_3des_data,16); - DES_cblock RndA, RndB; - - PrintAndLogEx(NORMAL, "----------OpenSSL DES implementation----------"); - { - uint8_t e_RndB[8] = {0x00}; - unsigned char RndARndB[16] = {0x00}; - - DES_cblock iv = { 0 }; - DES_key_schedule ks1,ks2; - DES_cblock key1,key2; - - memcpy(key,key3_3des_data,16); - memcpy(key1,key,8); - memcpy(key2,key+8,8); - - - DES_set_key((DES_cblock *)key1,&ks1); - DES_set_key((DES_cblock *)key2,&ks2); - - DES_random_key(&RndA); - PrintAndLogEx(NORMAL, " RndA:%s",sprint_hex(RndA, 8)); - PrintAndLogEx(NORMAL, " e_RndB:%s",sprint_hex(e_RndB, 8)); - //void DES_ede2_cbc_encrypt(const unsigned char *input, - // unsigned char *output, long length, DES_key_schedule *ks1, - // DES_key_schedule *ks2, DES_cblock *ivec, int enc); - DES_ede2_cbc_encrypt(e_RndB,RndB,sizeof(e_RndB),&ks1,&ks2,&iv,0); - - PrintAndLogEx(NORMAL, " RndB:%s",sprint_hex(RndB, 8)); - rol(RndB,8); - memcpy(RndARndB,RndA,8); - memcpy(RndARndB+8,RndB,8); - PrintAndLogEx(NORMAL, " RA+B:%s",sprint_hex(RndARndB, 16)); - DES_ede2_cbc_encrypt(RndARndB,RndARndB,sizeof(RndARndB),&ks1,&ks2,&e_RndB,1); - PrintAndLogEx(NORMAL, "enc(RA+B):%s",sprint_hex(RndARndB, 16)); - - } - PrintAndLogEx(NORMAL, "----------PolarSSL implementation----------"); - { - uint8_t random_a[8] = { 0 }; - uint8_t enc_random_a[8] = { 0 }; - uint8_t random_b[8] = { 0 }; - uint8_t enc_random_b[8] = { 0 }; - uint8_t random_a_and_b[16] = { 0 }; - des3_context ctx = { 0 }; - - memcpy(random_a, RndA,8); - - uint8_t output[8] = { 0 }; - uint8_t iv[8] = { 0 }; - - PrintAndLogEx(NORMAL, " RndA :%s",sprint_hex(random_a, 8)); - PrintAndLogEx(NORMAL, " e_RndB:%s",sprint_hex(enc_random_b, 8)); - - des3_set2key_dec(&ctx, key); - - des3_crypt_cbc(&ctx // des3_context *ctx - , DES_DECRYPT // int mode - , sizeof(random_b) // size_t length - , iv // unsigned char iv[8] - , enc_random_b // const unsigned char *input - , random_b // unsigned char *output - ); - - PrintAndLogEx(NORMAL, " RndB:%s",sprint_hex(random_b, 8)); - - rol(random_b,8); - memcpy(random_a_and_b ,random_a,8); - memcpy(random_a_and_b+8,random_b,8); - - PrintAndLogEx(NORMAL, " RA+B:%s",sprint_hex(random_a_and_b, 16)); - - des3_set2key_enc(&ctx, key); - - des3_crypt_cbc(&ctx // des3_context *ctx - , DES_ENCRYPT // int mode - , sizeof(random_a_and_b) // size_t length - , enc_random_b // unsigned char iv[8] - , random_a_and_b // const unsigned char *input - , random_a_and_b // unsigned char *output - ); - - PrintAndLogEx(NORMAL, "enc(RA+B):%s",sprint_hex(random_a_and_b, 16)); } return 0; } -**/ + // // Mifare Ultralight C - Set password @@ -1668,16 +1615,18 @@ static int CmdHF14AMfucSetPwd(const char *Cmd){ UsbCommand resp; - if (WaitForResponseTimeout(CMD_ACK,&resp,1500) ) { - if ( (resp.arg[0] & 0xff) == 1) + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) ) { + DropField(); + if ((resp.arg[0] & 0xff) == 1) { PrintAndLogEx(INFO, "Ultralight-C new password: %s", sprint_hex(pwd,16)); - else{ + return 0; + } else { PrintAndLogEx(ERR, "Failed writing at block %d", resp.arg[1] & 0xff); return 1; } - } - else { - PrintAndLogEx(ERR, "command execution time out"); + } else { + DropField(); + PrintAndLogEx(ERR, "command execution timeout"); return 1; } @@ -1715,6 +1664,7 @@ static int CmdHF14AMfucSetUid(const char *Cmd){ clearCommandBuffer(); SendCommand(&c); if (!WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + DropField(); PrintAndLogEx(WARNING, "Command execute timeout"); return 2; } @@ -1732,7 +1682,8 @@ static int CmdHF14AMfucSetUid(const char *Cmd){ c.d.asBytes[3] = 0x88 ^ uid[0] ^ uid[1] ^ uid[2]; clearCommandBuffer(); SendCommand(&c); - if (!WaitForResponseTimeout(CMD_ACK,&resp,1500)) { + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + DropField(); PrintAndLogEx(WARNING, "Command execute timeout"); return 3; } @@ -1745,7 +1696,8 @@ static int CmdHF14AMfucSetUid(const char *Cmd){ c.d.asBytes[3] = uid[6]; clearCommandBuffer(); SendCommand(&c); - if (!WaitForResponseTimeout(CMD_ACK,&resp,1500) ) { + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500) ) { + DropField(); PrintAndLogEx(WARNING, "Command execute timeout"); return 4; } @@ -1758,14 +1710,17 @@ static int CmdHF14AMfucSetUid(const char *Cmd){ c.d.asBytes[3] = oldblock2[3]; clearCommandBuffer(); SendCommand(&c); - if (!WaitForResponseTimeout(CMD_ACK,&resp,1500) ) { + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500) ) { + DropField(); PrintAndLogEx(WARNING, "Command execute timeout"); return 5; } + DropField(); return 0; } + static int CmdHF14AMfuGenDiverseKeys(const char *Cmd){ uint8_t iv[8] = { 0x00 }; @@ -1875,6 +1830,7 @@ static command_t CommandTable[] = {"dbg", CmdHF14AMfDbg, 0, "Set default debug mode"}, {"info", CmdHF14AMfUInfo, 0, "Tag information"}, {"dump", CmdHF14AMfUDump, 0, "Dump Ultralight / Ultralight-C / NTAG tag to binary file"}, + // {"restore", CmdHF14AMfURestore, 0, "Restore a dump onto a MFU MAGIC tag"}, {"rdbl", CmdHF14AMfURdBl, 0, "Read block"}, {"wrbl", CmdHF14AMfUWrBl, 0, "Write block"}, {"cauth", CmdHF14AMfucAuth, 0, "Authentication - Ultralight C"}, diff --git a/client/util.c b/client/util.c index eef97e2a..cd18fc00 100644 --- a/client/util.c +++ b/client/util.c @@ -117,9 +117,8 @@ void AddLogCurrentDT(char *fileName) { AddLogLine(fileName, "\nanticollision: ", buff); } -void FillFileNameByUID(char *fileName, uint8_t * uid, char *ext, int byteCount) { +void FillFileNameByUID(char *fileName, uint8_t *uid, char *ext, int byteCount) { char * fnameptr = fileName; - memset(fileName, 0x00, 200); for (int j = 0; j < byteCount; j++, fnameptr += 2) sprintf(fnameptr, "%02x", (unsigned int) uid[j]); @@ -323,13 +322,12 @@ uint32_t SwapBits(uint32_t value, int nrbits) { uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockSize){ static uint8_t buf[64]; memset(buf, 0x00, 64); - uint8_t *tmp = buf; for (uint8_t block=0; block < (uint8_t)(len/blockSize); block++){ for (size_t i = 0; i < blockSize; i++){ - tmp[i+(blockSize*block)] = src[(blockSize-1-i)+(blockSize*block)]; + buf[i+(blockSize*block)] = src[(blockSize-1-i)+(blockSize*block)]; } } - return tmp; + return buf; } //assumes little endian @@ -338,7 +336,7 @@ char *printBits(size_t const size, void const * const ptr) unsigned char *b = (unsigned char*) ptr; unsigned char byte; static char buf[1024]; - char * tmp = buf; + char *tmp = buf; int i, j; for (i=size-1;i>=0;i--) @@ -354,7 +352,7 @@ char *printBits(size_t const size, void const * const ptr) return buf; } -char * printBitsPar(const uint8_t *b, size_t len) { +char *printBitsPar(const uint8_t *b, size_t len) { static char buf1[512] = {0}; static char buf2[512] = {0}; static char *buf; @@ -519,7 +517,8 @@ int param_gethex(const char *line, int paramnum, uint8_t * data, int hexcnt) return 0; } -int param_gethex_ex(const char *line, int paramnum, uint8_t * data, int *hexcnt) + +int param_gethex_ex(const char *line, int paramnum, uint8_t *data, int *hexcnt) { int bg, en, temp, i; @@ -528,6 +527,8 @@ int param_gethex_ex(const char *line, int paramnum, uint8_t * data, int *hexcnt) if (param_getptr(line, &bg, &en, paramnum)) return 1; + if (en - bg + 1 > *hexcnt) return 1; + *hexcnt = en - bg + 1; if (*hexcnt % 2) //error if not complete hex bytes return 1; diff --git a/common/protocols.h b/common/protocols.h index 39fed40f..ab556516 100644 --- a/common/protocols.h +++ b/common/protocols.h @@ -105,44 +105,49 @@ NXP/Philips CUSTOM COMMANDS #define ISO14443A_CMD_REQA 0x26 -#define ISO14443A_CMD_READBLOCK 0x30 #define ISO14443A_CMD_WUPA 0x52 #define ISO14443A_CMD_ANTICOLL_OR_SELECT 0x93 #define ISO14443A_CMD_ANTICOLL_OR_SELECT_2 0x95 #define ISO14443A_CMD_ANTICOLL_OR_SELECT_3 0x97 -#define ISO14443A_CMD_WRITEBLOCK 0xA0 // or 0xA2 ? #define ISO14443A_CMD_HALT 0x50 #define ISO14443A_CMD_RATS 0xE0 -#define MIFARE_AUTH_KEYA 0x60 -#define MIFARE_AUTH_KEYB 0x61 -#define MIFARE_MAGICWUPC1 0x40 -#define MIFARE_MAGICWUPC2 0x43 -#define MIFARE_MAGICWIPEC 0x41 -#define MIFARE_CMD_INC 0xC0 -#define MIFARE_CMD_DEC 0xC1 -#define MIFARE_CMD_RESTORE 0xC2 -#define MIFARE_CMD_TRANSFER 0xB0 +#define MIFARE_CMD_READBLOCK 0x30 +#define MIFARE_CMD_WRITEBLOCK 0xA0 +#define MIFARE_AUTH_KEYA 0x60 +#define MIFARE_AUTH_KEYB 0x61 +#define MIFARE_MAGICWUPC1 0x40 +#define MIFARE_MAGICWUPC2 0x43 +#define MIFARE_MAGICWIPEC 0x41 +#define MIFARE_CMD_INC 0xC0 +#define MIFARE_CMD_DEC 0xC1 +#define MIFARE_CMD_RESTORE 0xC2 +#define MIFARE_CMD_TRANSFER 0xB0 -#define MIFARE_EV1_PERSONAL_UID 0x40 -#define MIFARE_EV1_SETMODE 0x43 +#define MIFARE_EV1_PERSONAL_UID 0x40 +#define MIFARE_EV1_SETMODE 0x43 +#define MIFARE_ULC_WRITE 0xA2 +#define MIFARE_ULC_COMP_WRITE MIFARE_CMD_WRITEBLOCK +#define MIFARE_ULC_AUTH_1 0x1A +#define MIFARE_ULC_AUTH_2 0xAF -#define MIFARE_ULC_WRITE 0xA2 -//#define MIFARE_ULC__COMP_WRITE 0xA0 -#define MIFARE_ULC_AUTH_1 0x1A -#define MIFARE_ULC_AUTH_2 0xAF +#define MIFARE_ULEV1_AUTH 0x1B +#define MIFARE_ULEV1_VERSION 0x60 +#define MIFARE_ULEV1_FASTREAD 0x3A +#define MIFARE_ULEV1_WRITE 0xA2 +#define MIFARE_ULEV1_COMP_WRITE MIFARE_CMD_WRITEBLOCK +#define MIFARE_ULEV1_READ_CNT 0x39 +#define MIFARE_ULEV1_INCR_CNT 0xA5 +#define MIFARE_ULEV1_READSIG 0x3C +#define MIFARE_ULEV1_CHECKTEAR 0x3E +#define MIFARE_ULEV1_VCSL 0x4B + +// mifare 4bit card answers +#define CARD_ACK 0x0A // 1010 - ACK +#define CARD_NACK_NA 0x04 // 0100 - NACK, not allowed (command not allowed) +#define CARD_NACK_TR 0x05 // 0101 - NACK, transmission error -#define MIFARE_ULEV1_AUTH 0x1B -#define MIFARE_ULEV1_VERSION 0x60 -#define MIFARE_ULEV1_FASTREAD 0x3A -//#define MIFARE_ULEV1_WRITE 0xA2 -//#define MIFARE_ULEV1_COMP_WRITE 0xA0 -#define MIFARE_ULEV1_READ_CNT 0x39 -#define MIFARE_ULEV1_INCR_CNT 0xA5 -#define MIFARE_ULEV1_READSIG 0x3C -#define MIFARE_ULEV1_CHECKTEAR 0x3E -#define MIFARE_ULEV1_VCSL 0x4B /** 06 00 = INITIATE From dd8e45133090d9684a7f0d37ef59137e6b7159a9 Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Sun, 16 Jun 2019 15:35:10 +1000 Subject: [PATCH 094/189] T55xx downlink Modes Changes : - Added t55xx downlink protocols (long leading reference, leading 0 and 1 of 4) - Added function to all read to call differnet downlink functions (to match write) - Update functions to support using differnet downlink modes. - Added support for calling downlink modes for lf t55 read, write and detect - Added new function lf t55 bruteforcedl to support downlink modes as well as try each mode for each password in password file. for functions with downlink mode extenstion. e - OPTIONAL downlink encoding '0' fixed-bit-length (default), '1' Long Zero Reference, '2' Leading Zero, '3' 1 of 4 --- armsrc/lfops.c | 442 +++++++++++++++++++++++++++++++++++++++++++- client/cmdlft55xx.c | 332 +++++++++++++++++++++++++++++++-- client/cmdlft55xx.h | 3 +- 3 files changed, 755 insertions(+), 22 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 81fdd7a6..36efe729 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1203,6 +1203,8 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) #define WRITE_0 18*8 // was 144 // SPEC: 16*8 to 32*8 - typ 24*8 (or 24fc) #define WRITE_1 50*8 // was 400 // SPEC: 48*8 to 64*8 - typ 56*8 (or 56fc) 432 for T55x7; 448 for E5550 #define READ_GAP 15*8 +// Long Leading Reference +#define Reference_llr (136+18)*8 // Needs to be WRITR_0 + 136 clocks. void TurnReadLFOn(int delay) { FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); @@ -1220,6 +1222,265 @@ void T55xxWriteBit(int bit) { WaitUS(WRITE_GAP); } +void T55xxWrite_LLR (void) +{ + TurnReadLFOn (Reference_llr); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + WaitUS(WRITE_GAP); +} + +#define START_GAPlz 31*8 +#define WRITE_GAPlz 20*8 +#define WRITElz_0 18*8 +#define WRITElz_1 40*8 +#define READ_GAP 15*8 + +void T55xxWriteBit_Leading0(int bit) { + if (!bit) + TurnReadLFOn(WRITElz_0); + else + TurnReadLFOn(WRITElz_1); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + WaitUS(WRITE_GAPlz); +// WaitUS(160); +} + +#define START_GAP1of4 31*8 // SPEC: 1*8 to 50*8 - typ 10*8 (or 15fc) +#define WRITE_GAP1of4 20*8 // SPEC: 1*8 to 20*8 - typ 10*8 (or 10fc) +// 00 = reference // 8 * 8 - - 68 * 8 +#define WRITE1of4_00 18*8 // SPEC: 8*8 to 68*8 - typ 24*8 (or 24fc) +#define WRITE1of4_01 34*8 // SPEC: dref+9 - dref+16 - dref+24 +#define WRITE1of4_10 50*8 // SPEC: dref+25 - dref+32 - dref+40 +#define WRITE1of4_11 66*8 // SPEC: dref+41 - dref+48 - dref+56 +#define READ1of4_GAP 15*8 + +void T55xxWriteBit_1of4(int bits) { + + switch (bits) + { + case 0 : TurnReadLFOn(WRITE1of4_00); break; + case 1 : TurnReadLFOn(WRITE1of4_01); break; + case 2 : TurnReadLFOn(WRITE1of4_10); break; + case 3 : TurnReadLFOn(WRITE1of4_11); break; + default: + TurnReadLFOn(WRITE1of4_00); + } + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + WaitUS(WRITE_GAP1of4); +// WaitUS(160); +} + +void T55xxWriteBlockExt_Leading0 (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { + + LED_A_ON(); + bool PwdMode = arg & 0x1; + uint8_t Page = (arg & 0x2)>>1; + bool testMode = arg & 0x4; + uint32_t i = 0; + + // Set up FPGA, 125kHz + LFSetupFPGAForADC(95, true); + StartTicks(); + // make sure tag is fully powered up... + WaitMS(5); + // Trigger T55x7 in mode. + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + + WaitUS(START_GAPlz); + + + /* + 0 : Leading Zero + 11 : Opcode + 00 : Fixed 00 if protected write (i.e. have password) + <32 bit Password> + 0 : Lock Bit + <32 bit data> + <3 bit addr> + + Standard Write : 0 1p L <32 data bits> <3 bit addr> + 0 10 0 00000000000000000000000000000000 001 + Protected Write: 0 1p 00 <32 pwd bits> L <32 data bits> <3 bit addr> + 0 10 00 00000000000000000000000000000000 0 00000000000000000000000000000000 001 + Wake Up 0 10 00 <32 pwd bits> + Protected Read 0 1p 00 <32 pwd bits> 0 <3 bit addr> + Standard Read 0 1p 0 <3 bit addr> + Page 0/1 read 0 1p + Reset 0 00 + + */ + T55xxWriteBit_Leading0 (0); //T55xxWriteBit(0); + + + if (testMode) Dbprintf("TestMODE"); + // Std Opcode 10 + T55xxWriteBit_Leading0 (testMode ? 0 : 1); + T55xxWriteBit_Leading0 (testMode ? 1 : Page); //Page 0 + + + if (PwdMode) { + // Leading zero - insert two fixed 00 between opcode and password + T55xxWriteBit_Leading0 (0); + T55xxWriteBit_Leading0 (0); + // Send Pwd + for (i = 0x80000000; i != 0; i >>= 1) + T55xxWriteBit_Leading0 (Pwd & i); + } + + // Send Lock bit + T55xxWriteBit_Leading0 (0); + + // Send Data + for (i = 0x80000000; i != 0; i >>= 1) + T55xxWriteBit_Leading0(Data & i); + + // Send Block number + for (i = 0x04; i != 0; i >>= 1) + T55xxWriteBit_Leading0 (Block & i); + + // Perform write (nominal is 5.6 ms for T55x7 and 18ms for E5550, + // so wait a little more) + // "there is a clock delay before programming" + // - programming takes ~5.6ms for t5577 ~18ms for E5550 or t5567 + // so we should wait 1 clock + 5.6ms then read response? + // but we need to know we are dealing with t5577 vs t5567 vs e5550 (or q5) marshmellow... + if (testMode) { + //TESTMODE TIMING TESTS: + // <566us does nothing + // 566-568 switches between wiping to 0s and doing nothing + // 5184 wipes and allows 1 block to be programmed. + // indefinite power on wipes and then programs all blocks with bitshifted data sent. + TurnReadLFOn(5184); + + } else { + TurnReadLFOn(20 * 1000); + //could attempt to do a read to confirm write took + // as the tag should repeat back the new block + // until it is reset, but to confirm it we would + // need to know the current block 0 config mode for + // modulation clock an other details to demod the response... + // response should be (for t55x7) a 0 bit then (ST if on) + // block data written in on repeat until reset. + + //DoPartialAcquisition(20, true, 12000); + } + + // turn field off + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_A_OFF(); + +} +void T55xxWriteBlockExt_1of4 (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { + + LED_A_ON(); + bool PwdMode = arg & 0x1; + uint8_t Page = (arg & 0x2)>>1; + bool testMode = arg & 0x4; + int bitpos; + uint8_t bits; + + // Set up FPGA, 125kHz + LFSetupFPGAForADC(95, true); + StartTicks(); + // make sure tag is fully powered up... + WaitMS(5); + // Trigger T55x7 in mode. + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + + + WaitUS(START_GAP1of4); + + + /* + 00 : 1 if 4 + 11 : Opcode + 00 : Fixed 00 if protected write (i.e. have password) + <32 bit Password> + 0 : Lock Bit + <32 bit data> + <3 bit addr> + + Standard Write : 00 1p L <32 data bits> <3 bit addr> + 00 10 0 00000000000000000000000000000000 001 + Protected Write: 00 1p 00 <32 pwd bits> L <32 data bits> <3 bit addr> + 00 10 00 00000000000000000000000000000000 0 00000000000000000000000000000000 001 + Wake Up 00 10 00 <32 pwd bits> + Protected Read 00 1p 00 <32 pwd bits> 0 <3 bit addr> + Standard Read 00 1p 0 <3 bit addr> + Page 0/1 read 00 1p + Reset 00 00 + + */ + T55xxWriteBit_1of4 (0); //Send Reference 00 + + if (testMode) Dbprintf("TestMODE"); + // Std Opcode 10 + if (testMode) bits = 0; else bits = 2; // 0x or 1x + if (testMode) bits |= 1; else bits += (Page); // x0 or x1 + T55xxWriteBit_1of4 (bits); + + if (PwdMode) { + // 1 of 4 00 - insert two fixed 00 between opcode and password + T55xxWriteBit_1of4 (0); // 00 + + // Send Pwd + for (bitpos = 31; bitpos >= 1; bitpos -= 2) { // 2 bits at a time + bits = (((Pwd >> bitpos) & 1) << 1) + ((Pwd >> (bitpos-1)) & 1); + T55xxWriteBit_1of4 (bits); + } + } + + // Send Lock bit + bits = 0; // Add lock bit (Not Set) to the next 2 bits + + // Send Data - offset by 1 bit due to lock bit + // 2 bits at a time - Initilised with lock bit above + for (bitpos = 31; bitpos >= 1; bitpos -= 2) { + bits |= ((Data >> bitpos) & 1); // Add Low bit + T55xxWriteBit_1of4 (bits); + bits = ((Data >> (bitpos-1)) & 1) << 1; // Set next high bit + } + + // Send Block number + bits |= ((Block >> 2) & 1); + T55xxWriteBit_1of4 (bits); + bits = (Block & 3);// 1) & 2) + (Block & 1); + T55xxWriteBit_1of4 (bits); + + // Perform write (nominal is 5.6 ms for T55x7 and 18ms for E5550, + // so wait a little more) + // "there is a clock delay before programming" + // - programming takes ~5.6ms for t5577 ~18ms for E5550 or t5567 + // so we should wait 1 clock + 5.6ms then read response? + // but we need to know we are dealing with t5577 vs t5567 vs e5550 (or q5) marshmellow... + if (testMode) { + //TESTMODE TIMING TESTS: + // <566us does nothing + // 566-568 switches between wiping to 0s and doing nothing + // 5184 wipes and allows 1 block to be programmed. + // indefinite power on wipes and then programs all blocks with bitshifted data sent. + TurnReadLFOn(5184); + + } else { + TurnReadLFOn(20 * 1000); + //could attempt to do a read to confirm write took + // as the tag should repeat back the new block + // until it is reset, but to confirm it we would + // need to know the current block 0 config mode for + // modulation clock an other details to demod the response... + // response should be (for t55x7) a 0 bit then (ST if on) + // block data written in on repeat until reset. + + //DoPartialAcquisition(20, true, 12000); + } + + // turn field off + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_A_OFF(); + +} + // Send T5577 reset command then read stream (see if we can identify the start of the stream) void T55xxResetRead(void) { LED_A_ON(); @@ -1324,12 +1585,34 @@ void T55xxWriteBlockExt(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg // Write one card block in page 0, no lock void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { - T55xxWriteBlockExt(Data, Block, Pwd, arg); +// arg 8 bit 00000000 +// 0000000x Password +// 000000x0 Page +// 00000x00 Test Mode +// 000xx000 (0x18) where xx : 00 - Normal Write, 01 - Long Leading Reference +// 10 - Leading 0, 11 - 1 of 4 + uint8_t downlink_mode; + + downlink_mode = (arg >> 3) & 0x03; + + switch (downlink_mode) + { + case 0 : T55xxWriteBlockExt (Data, Block, Pwd, arg); break; + case 1 : T55xxWrite_LLR (); + T55xxWriteBlockExt (Data, Block, Pwd, arg); + break; + case 2 : T55xxWriteBlockExt_Leading0 (Data, Block, Pwd, arg); break; + case 3 : T55xxWriteBlockExt_1of4 (Data, Block, Pwd, arg); break; + + default: + T55xxWriteBlockExt (Data, Block, Pwd, arg); + } + cmd_send(CMD_ACK,0,0,0,0,0); } // Read one card block in page [page] -void T55xxReadBlock(uint16_t arg0, uint8_t Block, uint32_t Pwd) { +void T55xxReadBlockExt (uint16_t arg0, uint8_t Block, uint32_t Pwd) { LED_A_ON(); bool PwdMode = arg0 & 0x1; uint8_t Page = (arg0 & 0x2) >> 1; @@ -1379,10 +1662,163 @@ void T55xxReadBlock(uint16_t arg0, uint8_t Block, uint32_t Pwd) { // Turn the field off FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off - cmd_send(CMD_ACK,0,0,0,0,0); +// cmd_send(CMD_ACK,0,0,0,0,0); LED_A_OFF(); } +void T55xxReadBlockExt_Leading0 (uint16_t arg0, uint8_t Block, uint32_t Pwd) { + LED_A_ON(); + bool PwdMode = arg0 & 0x1; + uint8_t Page = (arg0 & 0x2) >> 1; + uint32_t i = 0; + bool RegReadMode = (Block == 0xFF);//regular read mode + + //clear buffer now so it does not interfere with timing later + BigBuf_Clear_ext(false); + + //make sure block is at max 7 + Block &= 0x7; + + // Set up FPGA, 125kHz to power up the tag + LFSetupFPGAForADC(95, true); + StartTicks(); + // make sure tag is fully powered up... + WaitMS(5); + // Trigger T55x7 Direct Access Mode with start gap + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + WaitUS(START_GAPlz); + + T55xxWriteBit_Leading0 (0); + + // Opcode 1[page] + T55xxWriteBit_Leading0 (1); + T55xxWriteBit_Leading0 (Page); //Page 0 + + if (PwdMode){ + // Send Pwd + T55xxWriteBit_Leading0 (0); + T55xxWriteBit_Leading0 (0); + + for (i = 0x80000000; i != 0; i >>= 1) + T55xxWriteBit_Leading0 (Pwd & i); + } + // Send a zero bit separation + T55xxWriteBit_Leading0(0); + + // Send Block number (if direct access mode) + if (!RegReadMode) + for (i = 0x04; i != 0; i >>= 1) + T55xxWriteBit_Leading0(Block & i); + + // Turn field on to read the response + // 137*8 seems to get to the start of data pretty well... + // but we want to go past the start and let the repeating data settle in... + TurnReadLFOn(210*8); + + // Acquisition + // Now do the acquisition + DoPartialAcquisition(0, true, 12000, 0); + + // Turn the field off + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off +// cmd_send(CMD_ACK,0,0,0,0,0); + LED_A_OFF(); +} + +void T55xxReadBlockExt_1of4 (uint16_t arg0, uint8_t Block, uint32_t Pwd) { + LED_A_ON(); + bool PwdMode = arg0 & 0x1; + uint8_t Page = (arg0 & 0x2) >> 1; + //uint32_t i = 0; + bool RegReadMode = (Block == 0xFF);//regular read mode + uint8_t bits; + int bitpos; + + //clear buffer now so it does not interfere with timing later + BigBuf_Clear_ext(false); + + //make sure block is at max 7 + Block &= 0x7; + + // Set up FPGA, 125kHz to power up the tag + LFSetupFPGAForADC(95, true); + StartTicks(); + // make sure tag is fully powered up... + WaitMS(5); + // Trigger T55x7 Direct Access Mode with start gap + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + WaitUS(START_GAP1of4); + + T55xxWriteBit_1of4 (0); // 2 Bit 00 leading reference + + // Opcode 1[page] + bits = 2 + Page; + T55xxWriteBit_1of4 (bits); + + if (PwdMode) { + // 1 of 4 00 - insert two fixed 00 between opcode and password + T55xxWriteBit_1of4 (0); // 00 + + // Send Pwd + for (bitpos = 31; bitpos >= 1; bitpos -= 2) { // 2 bits at a time + bits = (((Pwd >> bitpos) & 1) << 1) + ((Pwd >> (bitpos-1)) & 1); + T55xxWriteBit_1of4 (bits); + } + } + + // Send Lock bit + bits = 0; // Add lock bit (Not Set) to the next 2 bits + + // Send Block number (if direct access mode) + if (!RegReadMode){ + // Send Block number + bits += ((Block >> 2) & 1); + T55xxWriteBit_1of4 (bits); + bits = (Block & 3); // + (Block & 1); + T55xxWriteBit_1of4 (bits); + } + + // Turn field on to read the response + // 137*8 seems to get to the start of data pretty well... + // but we want to go past the start and let the repeating data settle in... + TurnReadLFOn(210*8); + + // Acquisition + // Now do the acquisition + DoPartialAcquisition(0, true, 12000, 0); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off +// cmd_send(CMD_ACK,0,0,0,0,0); + LED_A_OFF(); +} + +void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) { +// arg0 16 bit 00000000 +// 0000000x Password +// 000000x0 Page +// 00000x00 +// 000xx000 (0x18) where xx : 00 - Normal Write, 01 - Long Leading Reference +// 10 - Leading 0, 11 - 1 of 4 + uint8_t downlink_mode; + + downlink_mode = (arg0 >> 3) & 0x03; + + // downlink mode id set to match the 2 bit as per Tech Sheet + switch (downlink_mode) + { + case 0 : T55xxReadBlockExt (arg0, Block, Pwd); break; + case 1 : T55xxWrite_LLR (); + T55xxReadBlockExt (arg0, Block, Pwd); + break; + case 2 : T55xxReadBlockExt_Leading0 (arg0, Block, Pwd); break; + case 3 : T55xxReadBlockExt_1of4 (arg0, Block, Pwd); break; + default: + T55xxReadBlockExt (arg0, Block, Pwd) ; + } + +// T55xxReadBlockExt (arg0, Block, Pwd) ; + cmd_send(CMD_ACK,0,0,0,0,0); +} + void T55xxWakeUp(uint32_t Pwd){ LED_B_ON(); uint32_t i = 0; diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index b286c392..25df4c76 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -67,6 +67,8 @@ int usage_t55xx_read(){ PrintAndLog(" p - OPTIONAL password (8 hex characters)"); PrintAndLog(" o - OPTIONAL override safety check"); PrintAndLog(" 1 - OPTIONAL read Page 1 instead of Page 0"); + PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed-bit-length (default), '1' Long Zero Reference"); + PrintAndLog(" '2' Leading Zero, '3' 1 of 4 "); PrintAndLog(" ****WARNING****"); PrintAndLog(" Use of read with password on a tag not configured for a pwd"); PrintAndLog(" can damage the tag"); @@ -86,6 +88,8 @@ int usage_t55xx_write(){ PrintAndLog(" p - OPTIONAL password 4bytes (8 hex characters)"); PrintAndLog(" 1 - OPTIONAL write Page 1 instead of Page 0"); PrintAndLog(" t - OPTIONAL test mode write - ****DANGER****"); + PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed-bit-length (default), '1' Long Zero Reference"); + PrintAndLog(" '2' Leading Zero, '3' 1 of 4 "); PrintAndLog(""); PrintAndLog("Examples:"); PrintAndLog(" lf t55xx write b 3 d 11223344 - write 11223344 to block 3"); @@ -132,6 +136,8 @@ int usage_t55xx_detect(){ PrintAndLog("Options:"); PrintAndLog(" 1 - if set, use Graphbuffer otherwise read data from tag."); PrintAndLog(" p - OPTIONAL password (8 hex characters)"); + PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed-bit-length (default), '1' Long Zero Reference"); + PrintAndLog(" '2' Leading Zero, '3' 1 of 4 "); PrintAndLog(""); PrintAndLog("Examples:"); PrintAndLog(" lf t55xx detect"); @@ -182,6 +188,24 @@ int usage_t55xx_bruteforce(){ PrintAndLog(""); return 0; } +int usage_t55xx_bruteforce_downlink(){ + PrintAndLog("This command uses A) bruteforce to scan a number range"); + PrintAndLog(" B) a dictionary attack"); + PrintAndLog("Usage: lf t55xx bruteforce [i <*.dic>]"); + PrintAndLog(" password must be 4 bytes (8 hex symbols)"); + PrintAndLog("Options:"); + PrintAndLog(" h - this help"); + PrintAndLog(" r - 4 byte hex value to start and end pwd search at"); + PrintAndLog(" i <*.dic> - loads a default keys dictionary file <*.dic>"); + PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed-bit-length (default), '1' Long Zero Reference"); + PrintAndLog(" '2' Leading Zero, '3' 1 of 4 "); + PrintAndLog(""); + PrintAndLog("Examples:"); + PrintAndLog(" lf t55xx bruteforce aaaaaaaa bbbbbbbb"); + PrintAndLog(" lf t55xx bruteforce i default_pwd.dic"); + PrintAndLog(""); + return 0; +} int usage_t55xx_wipe(){ PrintAndLog("Usage: lf t55xx wipe [h] [Q5]"); PrintAndLog("This commands wipes a tag, fills blocks 1-7 with zeros and a default configuration block"); @@ -311,12 +335,12 @@ int CmdT55xxSetConfig(const char *Cmd) { return printConfiguration ( config ); } -int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, bool override, uint32_t password){ +int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, bool override, uint32_t password, uint8_t downlink_mode){ //Password mode if ( usepwd ) { // try reading the config block and verify that PWD bit is set before doing this! if ( !override ) { - if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, false, 0 ) ) return 0; + if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, false, 0,downlink_mode ) ) return 0; if ( !tryDetectModulation() ) { PrintAndLog("Safety Check: Could not detect if PWD bit is set in config block. Exits."); return 0; @@ -330,7 +354,7 @@ int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, bool override, uint32 } } - if (!AquireData(page1, block, usepwd, password) ) return 0; + if (!AquireData(page1, block, usepwd, password,downlink_mode) ) return 0; if (!DecodeT55xxBlock()) return 0; char blk[10]={0}; @@ -342,6 +366,8 @@ int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, bool override, uint32 int CmdT55xxReadBlock(const char *Cmd) { uint8_t block = REGULAR_READ_MODE_BLOCK; uint32_t password = 0; //default to blank Block 7 + uint8_t downlink_mode = 0; + bool usepwd = false; bool override = false; bool page1 = false; @@ -372,6 +398,12 @@ int CmdT55xxReadBlock(const char *Cmd) { page1 = true; cmdp++; break; + case 'e': + case 'E': + downlink_mode = param_getchar(Cmd, cmdp+1) - '0'; + if (downlink_mode > 3) downlink_mode = 0; + cmdp +=2; + break; default: PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; @@ -386,7 +418,7 @@ int CmdT55xxReadBlock(const char *Cmd) { } printT5xxHeader(page1); - return T55xxReadBlock(block, page1, usepwd, override, password); + return T55xxReadBlock(block, page1, usepwd, override, password, downlink_mode); } bool DecodeT55xxBlock(){ @@ -465,6 +497,7 @@ int CmdT55xxDetect(const char *Cmd){ bool usepwd = false; uint32_t password = 0; uint8_t cmdp = 0; + uint8_t downlink_mode = 0; while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch(param_getchar(Cmd, cmdp)) { @@ -482,6 +515,12 @@ int CmdT55xxDetect(const char *Cmd){ useGB = true; cmdp++; break; + case 'e': + case 'E': + downlink_mode = param_getchar(Cmd, cmdp+1) - '0'; + if (downlink_mode > 3) downlink_mode = 0; + cmdp +=2; + break; default: PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; @@ -491,13 +530,24 @@ int CmdT55xxDetect(const char *Cmd){ if (errors) return usage_t55xx_detect(); if ( !useGB) { - if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password) ) + if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password,downlink_mode) ) return 0; } if ( !tryDetectModulation() ) PrintAndLog("Could not detect modulation automatically. Try setting it manually with \'lf t55xx config\'"); - + else { + // Add downlink mode to reference. + switch (downlink_mode) { + case 0 : PrintAndLog ("Downlink : e 0 - Default/Fixed Bit Length"); break; + case 1 : PrintAndLog ("Downlink : e 1 - Long Leading Reference"); break; + case 2 : PrintAndLog ("Downlink : e 2 - Leading Zero Reference"); break; + case 3 : PrintAndLog ("Downlink : e 3 - 1 of 4 Coding"); break; + // default: + + // No default action + } + } return 1; } @@ -898,6 +948,8 @@ int CmdT55xxWriteBlock(const char *Cmd) { uint8_t block = 0xFF; //default to invalid block uint32_t data = 0; //default to blank Block uint32_t password = 0; //default to blank Block 7 + uint32_t downlink_mode = 0; + bool usepwd = false; bool page1 = false; bool gotdata = false; @@ -935,6 +987,12 @@ int CmdT55xxWriteBlock(const char *Cmd) { page1 = true; cmdp++; break; + case 'e': + case 'E': + downlink_mode = param_getchar(Cmd, cmdp+1) - '0'; + if (downlink_mode > 3) downlink_mode = 0; + cmdp +=2; + break; default: PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; @@ -952,17 +1010,19 @@ int CmdT55xxWriteBlock(const char *Cmd) { UsbCommand resp; c.d.asBytes[0] = (page1) ? 0x2 : 0; c.d.asBytes[0] |= (testMode) ? 0x4 : 0; - + c.d.asBytes[0] |= (downlink_mode << 3); + char pwdStr[16] = {0}; snprintf(pwdStr, sizeof(pwdStr), "pwd: 0x%08X", password); PrintAndLog("Writing page %d block: %02d data: 0x%08X %s", page1, block, data, (usepwd) ? pwdStr : "" ); - + //Password mode if (usepwd) { c.arg[2] = password; c.d.asBytes[0] |= 0x1; } + clearCommandBuffer(); SendCommand(&c); if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)){ @@ -980,7 +1040,7 @@ int CmdT55xxReadTrace(const char *Cmd) { return usage_t55xx_trace(); if (strlen(Cmd)==0) - if ( !AquireData( T55x7_PAGE1, REGULAR_READ_MODE_BLOCK, pwdmode, password ) ) + if ( !AquireData( T55x7_PAGE1, REGULAR_READ_MODE_BLOCK, pwdmode, password,0 ) ) return 0; if ( config.Q5 ) { @@ -1144,7 +1204,7 @@ int CmdT55xxInfo(const char *Cmd){ return usage_t55xx_info(); if (strlen(Cmd)==0) - if ( !AquireData( T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, pwdmode, password ) ) + if ( !AquireData( T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, pwdmode, password,0 ) ) return 1; if (!DecodeT55xxBlock()) return 1; @@ -1212,20 +1272,21 @@ int CmdT55xxDump(const char *Cmd){ printT5xxHeader(0); for ( uint8_t i = 0; i <8; ++i) - T55xxReadBlock(i, 0, usepwd, override, password); + T55xxReadBlock(i, 0, usepwd, override, password,0); printT5xxHeader(1); for ( uint8_t i = 0; i<4; i++) - T55xxReadBlock(i, 1, usepwd, override, password); + T55xxReadBlock(i, 1, usepwd, override, password,0); return 1; } -int AquireData( uint8_t page, uint8_t block, bool pwdmode, uint32_t password ){ +int AquireData( uint8_t page, uint8_t block, bool pwdmode, uint32_t password, uint8_t downlink_mode ){ // arg0 bitmodes: // bit0 = pwdmode // bit1 = page to read from uint8_t arg0 = (page<<1) | pwdmode; + arg0 |= (downlink_mode << 3); UsbCommand c = {CMD_T55XX_READ_BLOCK, {arg0, block, password}}; clearCommandBuffer(); @@ -1397,6 +1458,7 @@ int CmdT55xxBruteForce(const char *Cmd) { char buf[9]; char filename[FILE_PATH_SIZE]={0}; int keycnt = 0; + uint8_t downlink_mode = 0; int ch; uint8_t stKeyBlock = 20; uint8_t *keyBlock = NULL, *p = NULL; @@ -1480,7 +1542,7 @@ int CmdT55xxBruteForce(const char *Cmd) { PrintAndLog("Testing %08X", testpwd); - if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, testpwd)) { + if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, testpwd,downlink_mode)) { PrintAndLog("Aquireing data from device failed. Quitting"); free(keyBlock); return 0; @@ -1525,7 +1587,7 @@ int CmdT55xxBruteForce(const char *Cmd) { return 0; } - if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, i)) { + if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, i,downlink_mode)) { PrintAndLog("Aquireing data from device failed. Quitting"); free(keyBlock); return 0; @@ -1547,6 +1609,239 @@ int CmdT55xxBruteForce(const char *Cmd) { return 0; } +int CmdT55xxBruteForce_downlink(const char *Cmd) { + + // load a default pwd file. + char buf[9]; + char filename[FILE_PATH_SIZE]={0}; + int keycnt = 0; + uint8_t downlink_mode = 0; + int ch; + uint8_t stKeyBlock = 20; + uint8_t *keyBlock = NULL, *p = NULL; + uint32_t start_password = 0x00000000; //start password + uint32_t end_password = 0xFFFFFFFF; //end password + bool found = false; + uint8_t cmdp = 0; + int cmd_offset = 0; + int errors = 0; + int len; + bool use_file = false; + bool use_range = false; + bool try_all_dl_modes = false; + uint8_t dl_mode = 0; + + keyBlock = calloc(stKeyBlock, 6); + if (keyBlock == NULL) return 1; + + PrintAndLog("New Downlink Supprt"); + + while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch(param_getchar(Cmd, cmdp)) { + case 'h': + case 'H': + return usage_t55xx_bruteforce_downlink(); + case 'e': + case 'E': + downlink_mode = param_getchar(Cmd, cmdp+1) - '0'; + if (downlink_mode == 4) try_all_dl_modes = true; + if (downlink_mode > 3) downlink_mode = 0; + cmdp +=2; + cmd_offset += 4; + PrintAndLog ("DL Mode : %d",downlink_mode); + break; + case 'i': + case 'I': + if (use_range) { + PrintAndLog ("use Range or File"); + return 0; + } + use_file = true; + len = strlen(Cmd+2); + if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; + memcpy(filename, Cmd+cmd_offset+2, len); + cmdp += 2; + // PrintAndLog (" File : [%s]",filename); + break; + case 'r': + case 'R': + if (use_file) { + PrintAndLog ("use Range or File"); + return 0; + } + use_range = true; // = param_get32ex(Cmd, cmdp+1, 0, 16); + start_password = param_get32ex(Cmd, cmdp+1, 0, 16); + end_password = param_get32ex(Cmd, cmdp+2, 0, 16); + cmdp += 3; + cmd_offset += 20; // 8 + 8 + 1 + 1 + 1 + // PrintAndLog (" Range : [%0X] - [%0X]",start_password,end_password); + break; + default: + PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + +// if (cmdp == 'i' || cmdp == 'I') { + + if (use_file) + { + FILE * f = fopen( filename , "r"); + + if ( !f ) { + PrintAndLog("File: %s: not found or locked.", filename); + free(keyBlock); + return 1; + } + + while( fgets(buf, sizeof(buf), f) ) { + if (strlen(buf) < 8 || buf[7] == '\n') continue; + + while (fgetc(f) != '\n' && !feof(f)) ; //goto next line + + //The line start with # is comment, skip + if( buf[0]=='#' ) continue; + + if (!isxdigit((unsigned char)buf[0])) { + PrintAndLog("File content error. '%s' must include 8 HEX symbols", buf); + continue; + } + + buf[8] = 0; + + if ( stKeyBlock - keycnt < 2) { + p = realloc(keyBlock, 6*(stKeyBlock+=10)); + if (!p) { + PrintAndLog("Cannot allocate memory for defaultKeys"); + free(keyBlock); + fclose(f); + return 2; + } + keyBlock = p; + } + memset(keyBlock + 4 * keycnt, 0, 4); + num_to_bytes(strtoll(buf, NULL, 16), 4, keyBlock + 4*keycnt); + PrintAndLog("chk custom pwd[%2d] %08X", keycnt, bytes_to_num(keyBlock + 4*keycnt, 4)); + keycnt++; + memset(buf, 0, sizeof(buf)); + } + fclose(f); + + if (keycnt == 0) { + PrintAndLog("No keys found in file"); + free(keyBlock); + return 1; + } + PrintAndLog("Loaded %d keys", keycnt); + + // loop + uint64_t testpwd = 0x00; + for (uint16_t c = 0; c < keycnt; ++c ) { + + if (ukbhit()) { + ch = getchar(); + (void)ch; + printf("\naborted via keyboard!\n"); + free(keyBlock); + return 0; + } + + testpwd = bytes_to_num(keyBlock + 4*c, 4); + + PrintAndLog("Testing %08X", testpwd); + + // Try each downlink_mode of asked to + // donwlink_mode will = 0 if > 3 or set to 0, so loop from 0 - 3 + for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++) + { + if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, testpwd,dl_mode)) { + PrintAndLog("Aquireing data from device failed. Quitting"); + free(keyBlock); + return 0; + } + + found = tryDetectModulation(); + + if ( found ) { + PrintAndLog("Found valid password: [%08X]", testpwd); + free(keyBlock); + // Add downlink mode to reference. + switch (dl_mode) { + case 0 : PrintAndLog ("Downlink : e 0 - Default/Fixed Bit Length"); break; + case 1 : PrintAndLog ("Downlink : e 1 - Long Leading Reference"); break; + case 2 : PrintAndLog ("Downlink : e 2 - Leading Zero Reference"); break; + case 3 : PrintAndLog ("Downlink : e 3 - 1 of 4 Coding"); break; + } + return 0; + } + if (!try_all_dl_modes) // Exit loop + dl_mode = 4; + } + } + PrintAndLog("Password NOT found."); + free(keyBlock); + return 0; + } + + if (use_range) + { + // incremental pwd range search + // start_password = param_get32ex(Cmd, 0, 0, 16); + // end_password = param_get32ex(Cmd, 1, 0, 16); + + if ( start_password >= end_password ) { + free(keyBlock); + return usage_t55xx_bruteforce_downlink(); + } + PrintAndLog("Search password range [%08X -> %08X]", start_password, end_password); + + uint32_t i = start_password; + + while ((!found) && (i <= end_password)) { + + printf("."); + fflush(stdout); + if (ukbhit()) { + ch = getchar(); + (void)ch; + printf("\naborted via keyboard!\n"); + free(keyBlock); + return 0; + } + + if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, i,downlink_mode)) { + PrintAndLog("Aquireing data from device failed. Quitting"); + free(keyBlock); + return 0; + } + found = tryDetectModulation(); + + if (found) break; + i++; + } + + PrintAndLog(""); + + if (found) { + PrintAndLog("Found valid password: [%08x]", i); + // Add downlink mode to reference. + switch (downlink_mode) { + case 0 : PrintAndLog ("Downlink : e 0 - Default/Fixed Bit Length"); break; + case 1 : PrintAndLog ("Downlink : e 1 - Long Leading Reference"); break; + case 2 : PrintAndLog ("Downlink : e 2 - Leading Zero Reference"); break; + case 3 : PrintAndLog ("Downlink : e 3 - 1 of 4 Coding"); break; + } + } + else + PrintAndLog("Password NOT found. Last tried: [%08x]", --i); + + free(keyBlock); + } + return 0; +} + // note length of data returned is different for different chips. // some return all page 1 (64 bits) and others return just that block (32 bits) // unfortunately the 64 bits makes this more likely to get a false positive... @@ -1558,7 +1853,7 @@ bool tryDetectP1(bool getData) { bool st = true; if ( getData ) { - if ( !AquireData(T55x7_PAGE1, 1, false, 0) ) + if ( !AquireData(T55x7_PAGE1, 1, false, 0,0) ) return false; } @@ -1687,7 +1982,7 @@ int CmdT55xxDetectPage1(const char *Cmd){ if (errors) return usage_t55xx_detectP1(); if ( !useGB ) { - if ( !AquireData(T55x7_PAGE1, 1, usepwd, password) ) + if ( !AquireData(T55x7_PAGE1, 1, usepwd, password,0) ) return false; } bool success = tryDetectP1(false); @@ -1697,7 +1992,8 @@ int CmdT55xxDetectPage1(const char *Cmd){ static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, - {"bruteforce",CmdT55xxBruteForce,0, " [i <*.dic>] Simple bruteforce attack to find password"}, + {"bruteforce",CmdT55xxBruteForce,0, " [i <*.dic>] Simple bruteforce attack to find password"}, + {"bruteforcedl",CmdT55xxBruteForce_downlink,0, "r [i <*.dic>] [e ] Simple bruteforce attack to find password"}, {"config", CmdT55xxSetConfig, 1, "Set/Get T55XX configuration (modulation, inverted, offset, rate)"}, {"detect", CmdT55xxDetect, 1, "[1] Try detecting the tag modulation from reading the configuration block."}, {"p1detect", CmdT55xxDetectPage1,1, "[1] Try detecting if this is a t55xx tag by reading page 1"}, diff --git a/client/cmdlft55xx.h b/client/cmdlft55xx.h index 2ae3e69b..1ba4dca4 100644 --- a/client/cmdlft55xx.h +++ b/client/cmdlft55xx.h @@ -74,6 +74,7 @@ void Set_t55xx_Config(t55xx_conf_block_t conf); extern int CmdLFT55XX(const char *Cmd); extern int CmdT55xxBruteForce(const char *Cmd); +extern int CmdT55xxBruteForce_downlink(const char *Cmd); extern int CmdT55xxSetConfig(const char *Cmd); extern int CmdT55xxReadBlock(const char *Cmd); extern int CmdT55xxWriteBlock(const char *Cmd); @@ -98,7 +99,7 @@ bool tryDetectModulation(void); extern bool tryDetectP1(bool getData); bool test(uint8_t mode, uint8_t *offset, int *fndBitRate, uint8_t clk, bool *Q5); int special(const char *Cmd); -int AquireData( uint8_t page, uint8_t block, bool pwdmode, uint32_t password ); +int AquireData( uint8_t page, uint8_t block, bool pwdmode, uint32_t password,uint8_t downlink_mode ); void printT55x7Trace( t55x7_tracedata_t data, uint8_t repeat ); void printT5555Trace( t5555_tracedata_t data, uint8_t repeat ); From 6dd0ff3035ed40ab47f22d76dbc22942a492dca3 Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Mon, 17 Jun 2019 21:37:50 +1000 Subject: [PATCH 095/189] Update cmdlft55xx.c Minor Cleanup --- client/cmdlft55xx.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index 25df4c76..a05838b4 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -67,8 +67,8 @@ int usage_t55xx_read(){ PrintAndLog(" p - OPTIONAL password (8 hex characters)"); PrintAndLog(" o - OPTIONAL override safety check"); PrintAndLog(" 1 - OPTIONAL read Page 1 instead of Page 0"); - PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed-bit-length (default), '1' Long Zero Reference"); - PrintAndLog(" '2' Leading Zero, '3' 1 of 4 "); + PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed bit length (default), '1' long leading reference"); + PrintAndLog(" '2' leading zero, '3' 1 of 4 coding reference"); PrintAndLog(" ****WARNING****"); PrintAndLog(" Use of read with password on a tag not configured for a pwd"); PrintAndLog(" can damage the tag"); @@ -88,8 +88,8 @@ int usage_t55xx_write(){ PrintAndLog(" p - OPTIONAL password 4bytes (8 hex characters)"); PrintAndLog(" 1 - OPTIONAL write Page 1 instead of Page 0"); PrintAndLog(" t - OPTIONAL test mode write - ****DANGER****"); - PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed-bit-length (default), '1' Long Zero Reference"); - PrintAndLog(" '2' Leading Zero, '3' 1 of 4 "); + PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed bit length (default), '1' long leading reference"); + PrintAndLog(" '2' leading zero, '3' 1 of 4 coding reference"); PrintAndLog(""); PrintAndLog("Examples:"); PrintAndLog(" lf t55xx write b 3 d 11223344 - write 11223344 to block 3"); @@ -136,8 +136,8 @@ int usage_t55xx_detect(){ PrintAndLog("Options:"); PrintAndLog(" 1 - if set, use Graphbuffer otherwise read data from tag."); PrintAndLog(" p - OPTIONAL password (8 hex characters)"); - PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed-bit-length (default), '1' Long Zero Reference"); - PrintAndLog(" '2' Leading Zero, '3' 1 of 4 "); + PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed bit length (default), '1' long leading reference"); + PrintAndLog(" '2' leading zero, '3' 1 of 4 coding reference"); PrintAndLog(""); PrintAndLog("Examples:"); PrintAndLog(" lf t55xx detect"); @@ -196,9 +196,10 @@ int usage_t55xx_bruteforce_downlink(){ PrintAndLog("Options:"); PrintAndLog(" h - this help"); PrintAndLog(" r - 4 byte hex value to start and end pwd search at"); - PrintAndLog(" i <*.dic> - loads a default keys dictionary file <*.dic>"); - PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed-bit-length (default), '1' Long Zero Reference"); - PrintAndLog(" '2' Leading Zero, '3' 1 of 4 "); + PrintAndLog(" i <*.dic> - loads a default keys dictionary file <*.dic>"); + PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed bit length (default)"); + PrintAndLog(" '1' long leading reference, '2' leading zero "); + PrintAndLog(" '3' 1 of 4 coding reference, '4' special - try all downlink modes"); PrintAndLog(""); PrintAndLog("Examples:"); PrintAndLog(" lf t55xx bruteforce aaaaaaaa bbbbbbbb"); From be1b97d81fe44d9227a5c581fd279fed062a18cd Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Mon, 17 Jun 2019 22:01:25 +1000 Subject: [PATCH 096/189] Update cmdlft55xx.c Fixed bruteforce filename --- client/cmdlft55xx.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index a05838b4..da8fc703 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -1635,8 +1635,6 @@ int CmdT55xxBruteForce_downlink(const char *Cmd) { keyBlock = calloc(stKeyBlock, 6); if (keyBlock == NULL) return 1; - PrintAndLog("New Downlink Supprt"); - while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch(param_getchar(Cmd, cmdp)) { case 'h': @@ -1649,7 +1647,6 @@ int CmdT55xxBruteForce_downlink(const char *Cmd) { if (downlink_mode > 3) downlink_mode = 0; cmdp +=2; cmd_offset += 4; - PrintAndLog ("DL Mode : %d",downlink_mode); break; case 'i': case 'I': @@ -1661,8 +1658,11 @@ int CmdT55xxBruteForce_downlink(const char *Cmd) { len = strlen(Cmd+2); if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; memcpy(filename, Cmd+cmd_offset+2, len); + // Drop any characters after space + char *p = strstr(filename," "); + if (p) *p = 0; cmdp += 2; - // PrintAndLog (" File : [%s]",filename); + // PrintAndLog (" File : [%s]",filename); break; case 'r': case 'R': @@ -1670,12 +1670,11 @@ int CmdT55xxBruteForce_downlink(const char *Cmd) { PrintAndLog ("use Range or File"); return 0; } - use_range = true; // = param_get32ex(Cmd, cmdp+1, 0, 16); + use_range = true; start_password = param_get32ex(Cmd, cmdp+1, 0, 16); end_password = param_get32ex(Cmd, cmdp+2, 0, 16); cmdp += 3; - cmd_offset += 20; // 8 + 8 + 1 + 1 + 1 - // PrintAndLog (" Range : [%0X] - [%0X]",start_password,end_password); + cmd_offset += 20; break; default: PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); @@ -1684,9 +1683,6 @@ int CmdT55xxBruteForce_downlink(const char *Cmd) { } } - -// if (cmdp == 'i' || cmdp == 'I') { - if (use_file) { FILE * f = fopen( filename , "r"); @@ -1753,7 +1749,7 @@ int CmdT55xxBruteForce_downlink(const char *Cmd) { PrintAndLog("Testing %08X", testpwd); - // Try each downlink_mode of asked to + // Try each downlink_mode if asked to // donwlink_mode will = 0 if > 3 or set to 0, so loop from 0 - 3 for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++) { @@ -1768,7 +1764,7 @@ int CmdT55xxBruteForce_downlink(const char *Cmd) { if ( found ) { PrintAndLog("Found valid password: [%08X]", testpwd); free(keyBlock); - // Add downlink mode to reference. + // Add downlink mode for reference. switch (dl_mode) { case 0 : PrintAndLog ("Downlink : e 0 - Default/Fixed Bit Length"); break; case 1 : PrintAndLog ("Downlink : e 1 - Long Leading Reference"); break; @@ -1788,9 +1784,6 @@ int CmdT55xxBruteForce_downlink(const char *Cmd) { if (use_range) { - // incremental pwd range search - // start_password = param_get32ex(Cmd, 0, 0, 16); - // end_password = param_get32ex(Cmd, 1, 0, 16); if ( start_password >= end_password ) { free(keyBlock); @@ -1827,7 +1820,7 @@ int CmdT55xxBruteForce_downlink(const char *Cmd) { if (found) { PrintAndLog("Found valid password: [%08x]", i); - // Add downlink mode to reference. + // Add downlink mode for reference. switch (downlink_mode) { case 0 : PrintAndLog ("Downlink : e 0 - Default/Fixed Bit Length"); break; case 1 : PrintAndLog ("Downlink : e 1 - Long Leading Reference"); break; From 6763dc17a3f76370c766bfdb39179bde3ff7619f Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Tue, 18 Jun 2019 21:17:12 +1000 Subject: [PATCH 097/189] Cleanup Code Update downlink option from e to r fixed long leading reference added downling option to original bruteforce --- armsrc/lfops.c | 23 ++- client/cmdlft55xx.c | 379 ++++++++++---------------------------------- client/cmdlft55xx.h | 1 - 3 files changed, 103 insertions(+), 300 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 36efe729..112a1173 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1519,6 +1519,10 @@ void T55xxWriteBlockExt(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg uint8_t Page = (arg & 0x2)>>1; bool testMode = arg & 0x4; uint32_t i = 0; + uint8_t downlink_mode; + + downlink_mode = (arg >> 3) & 0x03; + // Set up FPGA, 125kHz LFSetupFPGAForADC(95, true); @@ -1529,6 +1533,9 @@ void T55xxWriteBlockExt(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); WaitUS(START_GAP); + // Long Leading Reference, same as fixed/default just with leading reference + if (downlink_mode == 1) T55xxWrite_LLR (); + if (testMode) Dbprintf("TestMODE"); // Std Opcode 10 T55xxWriteBit(testMode ? 0 : 1); @@ -1597,8 +1604,8 @@ void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { switch (downlink_mode) { - case 0 : T55xxWriteBlockExt (Data, Block, Pwd, arg); break; - case 1 : T55xxWrite_LLR (); + case 0 :// T55xxWriteBlockExt (Data, Block, Pwd, arg); break; + case 1 : // T55xxWrite_LLR (); T55xxWriteBlockExt (Data, Block, Pwd, arg); break; case 2 : T55xxWriteBlockExt_Leading0 (Data, Block, Pwd, arg); break; @@ -1618,7 +1625,10 @@ void T55xxReadBlockExt (uint16_t arg0, uint8_t Block, uint32_t Pwd) { uint8_t Page = (arg0 & 0x2) >> 1; uint32_t i = 0; bool RegReadMode = (Block == 0xFF);//regular read mode - + uint8_t downlink_mode; + + downlink_mode = (arg0 >> 3) & 0x03; + //clear buffer now so it does not interfere with timing later BigBuf_Clear_ext(false); @@ -1634,6 +1644,9 @@ void T55xxReadBlockExt (uint16_t arg0, uint8_t Block, uint32_t Pwd) { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); WaitUS(START_GAP); + // Long Leading Reference, same as fixed/default just with leading reference + if (downlink_mode == 1) T55xxWrite_LLR (); + // Opcode 1[page] T55xxWriteBit(1); T55xxWriteBit(Page); //Page 0 @@ -1805,8 +1818,8 @@ void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) { // downlink mode id set to match the 2 bit as per Tech Sheet switch (downlink_mode) { - case 0 : T55xxReadBlockExt (arg0, Block, Pwd); break; - case 1 : T55xxWrite_LLR (); + case 0 :// T55xxReadBlockExt (arg0, Block, Pwd); break; + case 1 : // T55xxWrite_LLR (); T55xxReadBlockExt (arg0, Block, Pwd); break; case 2 : T55xxReadBlockExt_Leading0 (arg0, Block, Pwd); break; diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index da8fc703..ed980f9b 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -67,7 +67,7 @@ int usage_t55xx_read(){ PrintAndLog(" p - OPTIONAL password (8 hex characters)"); PrintAndLog(" o - OPTIONAL override safety check"); PrintAndLog(" 1 - OPTIONAL read Page 1 instead of Page 0"); - PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed bit length (default), '1' long leading reference"); + PrintAndLog(" r - OPTIONAL downlink encoding '0' fixed bit length (default), '1' long leading reference"); PrintAndLog(" '2' leading zero, '3' 1 of 4 coding reference"); PrintAndLog(" ****WARNING****"); PrintAndLog(" Use of read with password on a tag not configured for a pwd"); @@ -88,7 +88,7 @@ int usage_t55xx_write(){ PrintAndLog(" p - OPTIONAL password 4bytes (8 hex characters)"); PrintAndLog(" 1 - OPTIONAL write Page 1 instead of Page 0"); PrintAndLog(" t - OPTIONAL test mode write - ****DANGER****"); - PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed bit length (default), '1' long leading reference"); + PrintAndLog(" r - OPTIONAL downlink encoding '0' fixed bit length (default), '1' long leading reference"); PrintAndLog(" '2' leading zero, '3' 1 of 4 coding reference"); PrintAndLog(""); PrintAndLog("Examples:"); @@ -136,7 +136,7 @@ int usage_t55xx_detect(){ PrintAndLog("Options:"); PrintAndLog(" 1 - if set, use Graphbuffer otherwise read data from tag."); PrintAndLog(" p - OPTIONAL password (8 hex characters)"); - PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed bit length (default), '1' long leading reference"); + PrintAndLog(" r - OPTIONAL downlink encoding '0' fixed bit length (default), '1' long leading reference"); PrintAndLog(" '2' leading zero, '3' 1 of 4 coding reference"); PrintAndLog(""); PrintAndLog("Examples:"); @@ -168,7 +168,7 @@ int usage_t55xx_wakup(){ PrintAndLog(" - [required] password 4bytes (8 hex symbols)"); PrintAndLog(""); PrintAndLog("Examples:"); - PrintAndLog(" lf t55xx wakeup 11223344 - send wakeup password"); + PrintAndLog(" lf t55xx wakeup 11223344 - send wakeup password"); return 0; } int usage_t55xx_bruteforce(){ @@ -178,32 +178,16 @@ int usage_t55xx_bruteforce(){ PrintAndLog(" password must be 4 bytes (8 hex symbols)"); PrintAndLog("Options:"); PrintAndLog(" h - this help"); + PrintAndLog(" r - OPTIONAL downlink encoding '0' fixed bit length (default)"); + PrintAndLog(" '1' long leading reference, '2' leading zero "); + PrintAndLog(" '3' 1 of 4 coding reference, '4' special - try all downlink modes"); PrintAndLog(" - 4 byte hex value to start pwd search at"); PrintAndLog(" - 4 byte hex value to end pwd search at"); PrintAndLog(" i <*.dic> - loads a default keys dictionary file <*.dic>"); PrintAndLog(""); PrintAndLog("Examples:"); - PrintAndLog(" lf t55xx bruteforce aaaaaaaa bbbbbbbb"); - PrintAndLog(" lf t55xx bruteforce i default_pwd.dic"); - PrintAndLog(""); - return 0; -} -int usage_t55xx_bruteforce_downlink(){ - PrintAndLog("This command uses A) bruteforce to scan a number range"); - PrintAndLog(" B) a dictionary attack"); - PrintAndLog("Usage: lf t55xx bruteforce [i <*.dic>]"); - PrintAndLog(" password must be 4 bytes (8 hex symbols)"); - PrintAndLog("Options:"); - PrintAndLog(" h - this help"); - PrintAndLog(" r - 4 byte hex value to start and end pwd search at"); - PrintAndLog(" i <*.dic> - loads a default keys dictionary file <*.dic>"); - PrintAndLog(" e - OPTIONAL downlink encoding '0' fixed bit length (default)"); - PrintAndLog(" '1' long leading reference, '2' leading zero "); - PrintAndLog(" '3' 1 of 4 coding reference, '4' special - try all downlink modes"); - PrintAndLog(""); - PrintAndLog("Examples:"); - PrintAndLog(" lf t55xx bruteforce aaaaaaaa bbbbbbbb"); - PrintAndLog(" lf t55xx bruteforce i default_pwd.dic"); + PrintAndLog(" lf t55xx bruteforce [r 2] aaaaaaaa bbbbbbbb"); + PrintAndLog(" lf t55xx bruteforce [r 2] i default_pwd.dic"); PrintAndLog(""); return 0; } @@ -399,8 +383,8 @@ int CmdT55xxReadBlock(const char *Cmd) { page1 = true; cmdp++; break; - case 'e': - case 'E': + case 'r': + case 'R': downlink_mode = param_getchar(Cmd, cmdp+1) - '0'; if (downlink_mode > 3) downlink_mode = 0; cmdp +=2; @@ -516,8 +500,8 @@ int CmdT55xxDetect(const char *Cmd){ useGB = true; cmdp++; break; - case 'e': - case 'E': + case 'r': + case 'R': downlink_mode = param_getchar(Cmd, cmdp+1) - '0'; if (downlink_mode > 3) downlink_mode = 0; cmdp +=2; @@ -540,13 +524,10 @@ int CmdT55xxDetect(const char *Cmd){ else { // Add downlink mode to reference. switch (downlink_mode) { - case 0 : PrintAndLog ("Downlink : e 0 - Default/Fixed Bit Length"); break; - case 1 : PrintAndLog ("Downlink : e 1 - Long Leading Reference"); break; - case 2 : PrintAndLog ("Downlink : e 2 - Leading Zero Reference"); break; - case 3 : PrintAndLog ("Downlink : e 3 - 1 of 4 Coding"); break; - // default: - - // No default action + case 0 : PrintAndLog ("Downlink : r 0 - default/fixed bit length"); break; + case 1 : PrintAndLog ("Downlink : r 1 - long leading reference"); break; + case 2 : PrintAndLog ("Downlink : r 2 - leading zero reference"); break; + case 3 : PrintAndLog ("Downlink : r 3 - 1 of 4 coding reference"); break; } } return 1; @@ -988,8 +969,8 @@ int CmdT55xxWriteBlock(const char *Cmd) { page1 = true; cmdp++; break; - case 'e': - case 'E': + case 'r': + case 'R': downlink_mode = param_getchar(Cmd, cmdp+1) - '0'; if (downlink_mode > 3) downlink_mode = 0; cmdp +=2; @@ -1459,16 +1440,29 @@ int CmdT55xxBruteForce(const char *Cmd) { char buf[9]; char filename[FILE_PATH_SIZE]={0}; int keycnt = 0; - uint8_t downlink_mode = 0; int ch; uint8_t stKeyBlock = 20; uint8_t *keyBlock = NULL, *p = NULL; uint32_t start_password = 0x00000000; //start password uint32_t end_password = 0xFFFFFFFF; //end password bool found = false; - + uint8_t downlink_mode = 0; + bool try_all_dl_modes = false; + uint8_t dl_mode = 0; + uint8_t cmd_offset = 0; + int cmd_opt = 0; + char cmdp = param_getchar(Cmd, 0); + if (cmdp == 'h' || cmdp == 'H') return usage_t55xx_bruteforce(); + if (cmdp == 'r' || cmdp == 'R') { + downlink_mode = param_getchar(Cmd, 1) - '0'; // get 2nd option, as this is fixed order. + if (downlink_mode == 4) try_all_dl_modes = true; + if (downlink_mode > 3) downlink_mode = 0; + cmd_opt += 2; // To help start/end passwords for range to be found + cmd_offset += 4; // r x To help the string offset for filename start position in cmd + cmdp = param_getchar(Cmd, 2); // get 3rd option, as this is fixed order. + } keyBlock = calloc(stKeyBlock, 6); if (keyBlock == NULL) return 1; @@ -1477,7 +1471,7 @@ int CmdT55xxBruteForce(const char *Cmd) { int len = strlen(Cmd+2); if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; - memcpy(filename, Cmd+2, len); + memcpy(filename, Cmd+2+cmd_offset, len); FILE * f = fopen( filename , "r"); @@ -1542,20 +1536,32 @@ int CmdT55xxBruteForce(const char *Cmd) { testpwd = bytes_to_num(keyBlock + 4*c, 4); PrintAndLog("Testing %08X", testpwd); + + // Try each downlink_mode if asked to + // donwlink_mode will = 0 if > 3 or set to 0, so loop from 0 - 3 + for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++){ + if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, testpwd, dl_mode)) { + PrintAndLog("Aquireing data from device failed. Quitting"); + free(keyBlock); + return 0; + } - if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, testpwd,downlink_mode)) { - PrintAndLog("Aquireing data from device failed. Quitting"); - free(keyBlock); - return 0; - } + found = tryDetectModulation(); - found = tryDetectModulation(); - - if ( found ) { - PrintAndLog("Found valid password: [%08X]", testpwd); - free(keyBlock); - return 0; - } + if ( found ) { + PrintAndLog("Found valid password: [%08X]", testpwd); + free(keyBlock); + switch (dl_mode) { + case 0 : PrintAndLog ("Downlink : r 0 - default/fixed bit length"); break; + case 1 : PrintAndLog ("Downlink : r 1 - long leading reference"); break; + case 2 : PrintAndLog ("Downlink : r 2 - leading zero reference"); break; + case 3 : PrintAndLog ("Downlink : r 3 - 1 of 4 coding reference"); break; + } + return 0; + } + if (!try_all_dl_modes) // Exit loop if not trying all downlink modes + dl_mode = 4; + } } PrintAndLog("Password NOT found."); free(keyBlock); @@ -1565,8 +1571,8 @@ int CmdT55xxBruteForce(const char *Cmd) { // Try to read Block 7, first :) // incremental pwd range search - start_password = param_get32ex(Cmd, 0, 0, 16); - end_password = param_get32ex(Cmd, 1, 0, 16); + start_password = param_get32ex(Cmd, cmd_opt , 0, 16); + end_password = param_get32ex(Cmd, cmd_opt+1 , 0, 16); if ( start_password >= end_password ) { free(keyBlock); @@ -1587,225 +1593,10 @@ int CmdT55xxBruteForce(const char *Cmd) { free(keyBlock); return 0; } - - if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, i,downlink_mode)) { - PrintAndLog("Aquireing data from device failed. Quitting"); - free(keyBlock); - return 0; - } - found = tryDetectModulation(); - - if (found) break; - i++; - } - - PrintAndLog(""); - - if (found) - PrintAndLog("Found valid password: [%08x]", i); - else - PrintAndLog("Password NOT found. Last tried: [%08x]", --i); - - free(keyBlock); - return 0; -} - -int CmdT55xxBruteForce_downlink(const char *Cmd) { - - // load a default pwd file. - char buf[9]; - char filename[FILE_PATH_SIZE]={0}; - int keycnt = 0; - uint8_t downlink_mode = 0; - int ch; - uint8_t stKeyBlock = 20; - uint8_t *keyBlock = NULL, *p = NULL; - uint32_t start_password = 0x00000000; //start password - uint32_t end_password = 0xFFFFFFFF; //end password - bool found = false; - uint8_t cmdp = 0; - int cmd_offset = 0; - int errors = 0; - int len; - bool use_file = false; - bool use_range = false; - bool try_all_dl_modes = false; - uint8_t dl_mode = 0; - - keyBlock = calloc(stKeyBlock, 6); - if (keyBlock == NULL) return 1; - - while(param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch(param_getchar(Cmd, cmdp)) { - case 'h': - case 'H': - return usage_t55xx_bruteforce_downlink(); - case 'e': - case 'E': - downlink_mode = param_getchar(Cmd, cmdp+1) - '0'; - if (downlink_mode == 4) try_all_dl_modes = true; - if (downlink_mode > 3) downlink_mode = 0; - cmdp +=2; - cmd_offset += 4; - break; - case 'i': - case 'I': - if (use_range) { - PrintAndLog ("use Range or File"); - return 0; - } - use_file = true; - len = strlen(Cmd+2); - if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; - memcpy(filename, Cmd+cmd_offset+2, len); - // Drop any characters after space - char *p = strstr(filename," "); - if (p) *p = 0; - cmdp += 2; - // PrintAndLog (" File : [%s]",filename); - break; - case 'r': - case 'R': - if (use_file) { - PrintAndLog ("use Range or File"); - return 0; - } - use_range = true; - start_password = param_get32ex(Cmd, cmdp+1, 0, 16); - end_password = param_get32ex(Cmd, cmdp+2, 0, 16); - cmdp += 3; - cmd_offset += 20; - break; - default: - PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - - if (use_file) - { - FILE * f = fopen( filename , "r"); - - if ( !f ) { - PrintAndLog("File: %s: not found or locked.", filename); - free(keyBlock); - return 1; - } - - while( fgets(buf, sizeof(buf), f) ) { - if (strlen(buf) < 8 || buf[7] == '\n') continue; - - while (fgetc(f) != '\n' && !feof(f)) ; //goto next line - - //The line start with # is comment, skip - if( buf[0]=='#' ) continue; - - if (!isxdigit((unsigned char)buf[0])) { - PrintAndLog("File content error. '%s' must include 8 HEX symbols", buf); - continue; - } - - buf[8] = 0; - - if ( stKeyBlock - keycnt < 2) { - p = realloc(keyBlock, 6*(stKeyBlock+=10)); - if (!p) { - PrintAndLog("Cannot allocate memory for defaultKeys"); - free(keyBlock); - fclose(f); - return 2; - } - keyBlock = p; - } - memset(keyBlock + 4 * keycnt, 0, 4); - num_to_bytes(strtoll(buf, NULL, 16), 4, keyBlock + 4*keycnt); - PrintAndLog("chk custom pwd[%2d] %08X", keycnt, bytes_to_num(keyBlock + 4*keycnt, 4)); - keycnt++; - memset(buf, 0, sizeof(buf)); - } - fclose(f); - - if (keycnt == 0) { - PrintAndLog("No keys found in file"); - free(keyBlock); - return 1; - } - PrintAndLog("Loaded %d keys", keycnt); - - // loop - uint64_t testpwd = 0x00; - for (uint16_t c = 0; c < keycnt; ++c ) { - - if (ukbhit()) { - ch = getchar(); - (void)ch; - printf("\naborted via keyboard!\n"); - free(keyBlock); - return 0; - } - - testpwd = bytes_to_num(keyBlock + 4*c, 4); - - PrintAndLog("Testing %08X", testpwd); - - // Try each downlink_mode if asked to - // donwlink_mode will = 0 if > 3 or set to 0, so loop from 0 - 3 - for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++) - { - if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, testpwd,dl_mode)) { - PrintAndLog("Aquireing data from device failed. Quitting"); - free(keyBlock); - return 0; - } - - found = tryDetectModulation(); - - if ( found ) { - PrintAndLog("Found valid password: [%08X]", testpwd); - free(keyBlock); - // Add downlink mode for reference. - switch (dl_mode) { - case 0 : PrintAndLog ("Downlink : e 0 - Default/Fixed Bit Length"); break; - case 1 : PrintAndLog ("Downlink : e 1 - Long Leading Reference"); break; - case 2 : PrintAndLog ("Downlink : e 2 - Leading Zero Reference"); break; - case 3 : PrintAndLog ("Downlink : e 3 - 1 of 4 Coding"); break; - } - return 0; - } - if (!try_all_dl_modes) // Exit loop - dl_mode = 4; - } - } - PrintAndLog("Password NOT found."); - free(keyBlock); - return 0; - } - - if (use_range) - { - - if ( start_password >= end_password ) { - free(keyBlock); - return usage_t55xx_bruteforce_downlink(); - } - PrintAndLog("Search password range [%08X -> %08X]", start_password, end_password); - - uint32_t i = start_password; - - while ((!found) && (i <= end_password)) { - - printf("."); - fflush(stdout); - if (ukbhit()) { - ch = getchar(); - (void)ch; - printf("\naborted via keyboard!\n"); - free(keyBlock); - return 0; - } - - if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, i,downlink_mode)) { + // Try each downlink_mode if asked to + // donwlink_mode will = 0 if > 3 or set to 0, so loop from 0 - 3 + for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++){ + if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, i,dl_mode)) { PrintAndLog("Aquireing data from device failed. Quitting"); free(keyBlock); return 0; @@ -1813,29 +1604,30 @@ int CmdT55xxBruteForce_downlink(const char *Cmd) { found = tryDetectModulation(); if (found) break; - i++; + if (!try_all_dl_modes) // Exit loop if not trying all downlink modes + dl_mode = 4; } - - PrintAndLog(""); - - if (found) { - PrintAndLog("Found valid password: [%08x]", i); - // Add downlink mode for reference. - switch (downlink_mode) { - case 0 : PrintAndLog ("Downlink : e 0 - Default/Fixed Bit Length"); break; - case 1 : PrintAndLog ("Downlink : e 1 - Long Leading Reference"); break; - case 2 : PrintAndLog ("Downlink : e 2 - Leading Zero Reference"); break; - case 3 : PrintAndLog ("Downlink : e 3 - 1 of 4 Coding"); break; - } - } - else - PrintAndLog("Password NOT found. Last tried: [%08x]", --i); - - free(keyBlock); + if (found) break; + i++; } + + if (found){ + PrintAndLog("Found valid password: [%08x]", i); + switch (dl_mode) { + case 0 : PrintAndLog ("Downlink : r 0 - default/fixed bit length"); break; + case 1 : PrintAndLog ("Downlink : r 1 - long leading reference"); break; + case 2 : PrintAndLog ("Downlink : r 2 - leading Zero reference"); break; + case 3 : PrintAndLog ("Downlink : r 3 - 1 of 4 coding reference"); break; + } + } + else{ + PrintAndLog(""); + PrintAndLog("Password NOT found. Last tried: [%08x]", --i); + } + + free(keyBlock); return 0; } - // note length of data returned is different for different chips. // some return all page 1 (64 bits) and others return just that block (32 bits) // unfortunately the 64 bits makes this more likely to get a false positive... @@ -1987,7 +1779,6 @@ int CmdT55xxDetectPage1(const char *Cmd){ static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"bruteforce",CmdT55xxBruteForce,0, " [i <*.dic>] Simple bruteforce attack to find password"}, - {"bruteforcedl",CmdT55xxBruteForce_downlink,0, "r [i <*.dic>] [e ] Simple bruteforce attack to find password"}, {"config", CmdT55xxSetConfig, 1, "Set/Get T55XX configuration (modulation, inverted, offset, rate)"}, {"detect", CmdT55xxDetect, 1, "[1] Try detecting the tag modulation from reading the configuration block."}, {"p1detect", CmdT55xxDetectPage1,1, "[1] Try detecting if this is a t55xx tag by reading page 1"}, diff --git a/client/cmdlft55xx.h b/client/cmdlft55xx.h index 1ba4dca4..4541bd3a 100644 --- a/client/cmdlft55xx.h +++ b/client/cmdlft55xx.h @@ -74,7 +74,6 @@ void Set_t55xx_Config(t55xx_conf_block_t conf); extern int CmdLFT55XX(const char *Cmd); extern int CmdT55xxBruteForce(const char *Cmd); -extern int CmdT55xxBruteForce_downlink(const char *Cmd); extern int CmdT55xxSetConfig(const char *Cmd); extern int CmdT55xxReadBlock(const char *Cmd); extern int CmdT55xxWriteBlock(const char *Cmd); From 4be71814b4a7f5647a01d55882664c5889f4e605 Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Sat, 22 Jun 2019 15:26:56 +1000 Subject: [PATCH 098/189] T55xx Downlink - Updates Improved code. --- CHANGELOG.md | 28 ++ armsrc/lfops.c | 799 ++++++++++++++++---------------------------- client/cmdlft55xx.c | 57 ++-- 3 files changed, 341 insertions(+), 543 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 399f87f9..55f1d1f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,34 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ## [unreleased][unreleased] +## T55xx Downlink Protocol - 22 Jun 2019 + +# armsrc/lfops + +### Added +- Added typedef T55xx_Timing to hold downlink timings. +- Added Timing Records for long leading reference (llr), Leading 0 and 1 of 4 +- Added some constant defines for code readability +- Added function T55xx_SetBits to build a bit stream for writing to T55xx +- Added function T55xx_SendCMD to build the bit stream and send to T55xx + +### Changed +- Converted Timing for default/fixed bit to T55xx_Timing +- Updated T55xxWriteBit (and calls) to support all downlink protocols +- Updated T55xxWriteBlock to call T55xx_SendCMD (removed local bit writes) +- Updated T55xxReadBlock to call T55xx_SendCMD (removed local bit writes) + +# client/cmdlft55xx + +### Added +- Added function T55xx_Print_DownlinkMode to print downlink mode information when uesd + +### Changes +- Added downlink mode options r [ 0 (or missing) default/fixed bit, 1 long leading, leading 0 and 1 of 4 ] +- Added r 4 option to bruteforce to try all downlink modes (0,1,2 and 3) +- Updated help messages for each support functions t55xx_read, t55xx_write, t55_detect, t55xx_bruteforce + + ### Changed - Changed hf mfp security. Now it works in all the modes. (drHatson) - `hf fido` - show/check DER certificate and signatures (Merlok) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 112a1173..c1f32f87 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1198,13 +1198,90 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) * and enlarge the gap ones. * Q5 tags seems to have issues when these values changes. */ + /* + // Original Timings for reference + #define START_GAP 31*8 // was 250 // SPEC: 1*8 to 50*8 - typ 15*8 (or 15fc) #define WRITE_GAP 20*8 // was 160 // SPEC: 1*8 to 20*8 - typ 10*8 (or 10fc) #define WRITE_0 18*8 // was 144 // SPEC: 16*8 to 32*8 - typ 24*8 (or 24fc) #define WRITE_1 50*8 // was 400 // SPEC: 48*8 to 64*8 - typ 56*8 (or 56fc) 432 for T55x7; 448 for E5550 #define READ_GAP 15*8 -// Long Leading Reference -#define Reference_llr (136+18)*8 // Needs to be WRITR_0 + 136 clocks. +*/ + +// Structure to hold Timing values. In future will be simplier to add user changable timings. +typedef struct { + uint16_t START_GAP; + uint16_t WRITE_GAP; + uint16_t WRITE_0; + uint16_t WRITE_1; + uint16_t WRITE_2; + uint16_t WRITE_3; + uint16_t READ_GAP; +} T55xx_Timing; + +/* + T5577 Timeing from datasheet for reference + + Fixed bit length + ---------------- + Normal Down Link Fast Downlink + Min Typ Max Min Typ Max + Start gap 8 15 50 8 15 50 + Write gap 8 10 20 8 10 20 + 0 data 16 24 32 8 12 16 + 1 data 48 56 64 24 28 32 + + + Long Leading Reference + ---------------------- + Normal Down Link Fast Downlink + Min Typ Max Min Typ Max + Start gap 8 10 50 8 10 50 + Write gap 8 10 20 8 10 20 + Reference(r) 152 160 168 140 144 148 + 136 + 0 data 132 + 0 data + 0 data r - 143 r - 136 r - 128 r - 135 r - 132 r - 124 + 1 data r - 111 r - 104 r - 96 r - 119 r - 116 r - 112 + + + Leading Zero Reference + ---------------------- + Normal Down Link Fast Downlink + Min Typ Max Min Typ Max + Start gap 8 10 50 8 10 50 + Write gap 8 10 20 8 10 20 + Reference(r) 12 - 72 8 - 68 + 0 data r - 7 r r + 8 r - 3 r r + 4 + 1 data r + 9 r + 16 r + 24 r + 5 r + 8 r + 12 + + + 1 of 4 Coding + ------------- + Normal Down Link Fast Downlink + Min Typ Max Min Typ Max + Start gap 8 10 50 8 10 50 + Write gap 8 10 20 8 10 20 + Reference(r) 8 - 68 12 - 72 + 00 data r - 7 r r + 8 r - 3 r r + 4 + 01 data r + 9 r + 16 r + 24 r + 5 r + 8 r + 12 + 10 data r + 25 r + 32 r + 40 r + 13 r + 16 r + 20 + 11 data r + 41 r + 48 r + 56 r + 21 r + 24 r + 28 + +*/ + +// Set Initial/Default Values. Note: *8 can occure when used. This should keep things simplier here. +T55xx_Timing T55xx_Timing_FixedBit = { 31 * 8 , 20 * 8 , 18 * 8 , 50 * 8 , 0 , 0 , 15 * 8 }; +T55xx_Timing T55xx_Timing_LLR = { 31 * 8 , 20 * 8 , 18 * 8 , 50 * 8 , 0 , 0 , 15 * 8 }; +T55xx_Timing T55xx_Timing_Leading0 = { 31 * 8 , 20 * 8 , 18 * 8 , 40 * 8 , 0 , 0 , 15 * 8 }; +T55xx_Timing T55xx_Timing_1of4 = { 31 * 8 , 20 * 8 , 18 * 8 , 34 * 8 , 50 * 8 , 66 * 8 , 15 * 8 }; + + +// Some defines for readability +#define T55xx_LongLeadingReference 4 // Value to tell Write Bit to send long reference +#define T55xx_DLMode_Fixed 0 // Default Mode +#define T55xx_DLMode_LLR 1 // Long Leading Reference +#define T55xx_DLMode_Leading0 2 // Leading Zero +#define T55xx_DLMode_1of4 3 // 1 of 4 void TurnReadLFOn(int delay) { FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); @@ -1213,272 +1290,59 @@ void TurnReadLFOn(int delay) { } // Write one bit to card -void T55xxWriteBit(int bit) { - if (!bit) - TurnReadLFOn(WRITE_0); - else - TurnReadLFOn(WRITE_1); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(WRITE_GAP); -} +void T55xxWriteBit(int bit, T55xx_Timing *Timings) { -void T55xxWrite_LLR (void) -{ - TurnReadLFOn (Reference_llr); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(WRITE_GAP); -} + // If bit = 4 Send Long Leading Reference which is 138 + WRITE_0 -#define START_GAPlz 31*8 -#define WRITE_GAPlz 20*8 -#define WRITElz_0 18*8 -#define WRITElz_1 40*8 -#define READ_GAP 15*8 - -void T55xxWriteBit_Leading0(int bit) { - if (!bit) - TurnReadLFOn(WRITElz_0); - else - TurnReadLFOn(WRITElz_1); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(WRITE_GAPlz); -// WaitUS(160); -} - -#define START_GAP1of4 31*8 // SPEC: 1*8 to 50*8 - typ 10*8 (or 15fc) -#define WRITE_GAP1of4 20*8 // SPEC: 1*8 to 20*8 - typ 10*8 (or 10fc) -// 00 = reference // 8 * 8 - - 68 * 8 -#define WRITE1of4_00 18*8 // SPEC: 8*8 to 68*8 - typ 24*8 (or 24fc) -#define WRITE1of4_01 34*8 // SPEC: dref+9 - dref+16 - dref+24 -#define WRITE1of4_10 50*8 // SPEC: dref+25 - dref+32 - dref+40 -#define WRITE1of4_11 66*8 // SPEC: dref+41 - dref+48 - dref+56 -#define READ1of4_GAP 15*8 - -void T55xxWriteBit_1of4(int bits) { - - switch (bits) - { - case 0 : TurnReadLFOn(WRITE1of4_00); break; - case 1 : TurnReadLFOn(WRITE1of4_01); break; - case 2 : TurnReadLFOn(WRITE1of4_10); break; - case 3 : TurnReadLFOn(WRITE1of4_11); break; - default: - TurnReadLFOn(WRITE1of4_00); + switch (bit){ + case 0 : TurnReadLFOn(Timings->WRITE_0); break; // Send bit 0/00 + case 1 : TurnReadLFOn(Timings->WRITE_1); break; // Send bit 1/01 + case 2 : TurnReadLFOn(Timings->WRITE_2); break; // Send bits 10 + case 3 : TurnReadLFOn(Timings->WRITE_3); break; // Send bits 11 + case 4 : TurnReadLFOn(Timings->WRITE_0 + (136 * 8)); break; // Send Long Leading Reference } - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(WRITE_GAP1of4); -// WaitUS(160); + WaitUS(Timings->WRITE_GAP); } -void T55xxWriteBlockExt_Leading0 (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { - LED_A_ON(); - bool PwdMode = arg & 0x1; - uint8_t Page = (arg & 0x2)>>1; - bool testMode = arg & 0x4; - uint32_t i = 0; - - // Set up FPGA, 125kHz - LFSetupFPGAForADC(95, true); - StartTicks(); - // make sure tag is fully powered up... - WaitMS(5); - // Trigger T55x7 in mode. - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); +// Function to abstract an Arbitrary length byte array to store bit pattern. +// bit_array - Array to hold data/bit pattern +// start_offset - bit location to start storing new bits. +// data - upto 32 bits of data to store +// num_bits - how many bits (low x bits of data) Max 32 bits at a time +// max_len - how many bytes can the bit_array hold (ensure no buffer overflow) +// returns "Next" bit offset / bits stored (for next store) +int T55xx_SetBits (uint8_t *bit_array, int start_offset, uint32_t data , int num_bits, int max_len) +{ + int bit,byte_idx, bit_idx; + int offset; + int NextOffset = start_offset; - WaitUS(START_GAPlz); - - - /* - 0 : Leading Zero - 11 : Opcode - 00 : Fixed 00 if protected write (i.e. have password) - <32 bit Password> - 0 : Lock Bit - <32 bit data> - <3 bit addr> + // Check if data will fit. + if ((start_offset + num_bits) <= (max_len*8)) { + + // Loop through the data and store + for (offset = (num_bits-1); offset >= 0; offset--) { + + bit = (data >> offset) & 1; // Get data bit value (0/1) + byte_idx = (NextOffset / 8); // Get Array Byte Index to Store + bit_idx = NextOffset - (byte_idx * 8); // Get Bit Index to set/clr - Standard Write : 0 1p L <32 data bits> <3 bit addr> - 0 10 0 00000000000000000000000000000000 001 - Protected Write: 0 1p 00 <32 pwd bits> L <32 data bits> <3 bit addr> - 0 10 00 00000000000000000000000000000000 0 00000000000000000000000000000000 001 - Wake Up 0 10 00 <32 pwd bits> - Protected Read 0 1p 00 <32 pwd bits> 0 <3 bit addr> - Standard Read 0 1p 0 <3 bit addr> - Page 0/1 read 0 1p - Reset 0 00 - - */ - T55xxWriteBit_Leading0 (0); //T55xxWriteBit(0); - - - if (testMode) Dbprintf("TestMODE"); - // Std Opcode 10 - T55xxWriteBit_Leading0 (testMode ? 0 : 1); - T55xxWriteBit_Leading0 (testMode ? 1 : Page); //Page 0 - - - if (PwdMode) { - // Leading zero - insert two fixed 00 between opcode and password - T55xxWriteBit_Leading0 (0); - T55xxWriteBit_Leading0 (0); - // Send Pwd - for (i = 0x80000000; i != 0; i >>= 1) - T55xxWriteBit_Leading0 (Pwd & i); - } - - // Send Lock bit - T55xxWriteBit_Leading0 (0); + // If set (1) we OR, if clear (0) we AND with inverse + // Dbprintf ("Add Bit : %d at byte %d bit %d",bit,byte_idx,bit_idx); + if (bit == 1) + bit_array[byte_idx] |= (1 << bit_idx); // Set the bit to 1 + + else + bit_array[byte_idx] &= (0xff ^ (1 << bit_idx)); // Set the bit to 0 (clr) - // Send Data - for (i = 0x80000000; i != 0; i >>= 1) - T55xxWriteBit_Leading0(Data & i); - - // Send Block number - for (i = 0x04; i != 0; i >>= 1) - T55xxWriteBit_Leading0 (Block & i); - - // Perform write (nominal is 5.6 ms for T55x7 and 18ms for E5550, - // so wait a little more) - // "there is a clock delay before programming" - // - programming takes ~5.6ms for t5577 ~18ms for E5550 or t5567 - // so we should wait 1 clock + 5.6ms then read response? - // but we need to know we are dealing with t5577 vs t5567 vs e5550 (or q5) marshmellow... - if (testMode) { - //TESTMODE TIMING TESTS: - // <566us does nothing - // 566-568 switches between wiping to 0s and doing nothing - // 5184 wipes and allows 1 block to be programmed. - // indefinite power on wipes and then programs all blocks with bitshifted data sent. - TurnReadLFOn(5184); - - } else { - TurnReadLFOn(20 * 1000); - //could attempt to do a read to confirm write took - // as the tag should repeat back the new block - // until it is reset, but to confirm it we would - // need to know the current block 0 config mode for - // modulation clock an other details to demod the response... - // response should be (for t55x7) a 0 bit then (ST if on) - // block data written in on repeat until reset. - - //DoPartialAcquisition(20, true, 12000); - } - - // turn field off - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_A_OFF(); - -} -void T55xxWriteBlockExt_1of4 (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { - - LED_A_ON(); - bool PwdMode = arg & 0x1; - uint8_t Page = (arg & 0x2)>>1; - bool testMode = arg & 0x4; - int bitpos; - uint8_t bits; - - // Set up FPGA, 125kHz - LFSetupFPGAForADC(95, true); - StartTicks(); - // make sure tag is fully powered up... - WaitMS(5); - // Trigger T55x7 in mode. - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - - - WaitUS(START_GAP1of4); - - - /* - 00 : 1 if 4 - 11 : Opcode - 00 : Fixed 00 if protected write (i.e. have password) - <32 bit Password> - 0 : Lock Bit - <32 bit data> - <3 bit addr> - - Standard Write : 00 1p L <32 data bits> <3 bit addr> - 00 10 0 00000000000000000000000000000000 001 - Protected Write: 00 1p 00 <32 pwd bits> L <32 data bits> <3 bit addr> - 00 10 00 00000000000000000000000000000000 0 00000000000000000000000000000000 001 - Wake Up 00 10 00 <32 pwd bits> - Protected Read 00 1p 00 <32 pwd bits> 0 <3 bit addr> - Standard Read 00 1p 0 <3 bit addr> - Page 0/1 read 00 1p - Reset 00 00 - - */ - T55xxWriteBit_1of4 (0); //Send Reference 00 - - if (testMode) Dbprintf("TestMODE"); - // Std Opcode 10 - if (testMode) bits = 0; else bits = 2; // 0x or 1x - if (testMode) bits |= 1; else bits += (Page); // x0 or x1 - T55xxWriteBit_1of4 (bits); - - if (PwdMode) { - // 1 of 4 00 - insert two fixed 00 between opcode and password - T55xxWriteBit_1of4 (0); // 00 - - // Send Pwd - for (bitpos = 31; bitpos >= 1; bitpos -= 2) { // 2 bits at a time - bits = (((Pwd >> bitpos) & 1) << 1) + ((Pwd >> (bitpos-1)) & 1); - T55xxWriteBit_1of4 (bits); - } - } - - // Send Lock bit - bits = 0; // Add lock bit (Not Set) to the next 2 bits - - // Send Data - offset by 1 bit due to lock bit - // 2 bits at a time - Initilised with lock bit above - for (bitpos = 31; bitpos >= 1; bitpos -= 2) { - bits |= ((Data >> bitpos) & 1); // Add Low bit - T55xxWriteBit_1of4 (bits); - bits = ((Data >> (bitpos-1)) & 1) << 1; // Set next high bit - } - - // Send Block number - bits |= ((Block >> 2) & 1); - T55xxWriteBit_1of4 (bits); - bits = (Block & 3);// 1) & 2) + (Block & 1); - T55xxWriteBit_1of4 (bits); - - // Perform write (nominal is 5.6 ms for T55x7 and 18ms for E5550, - // so wait a little more) - // "there is a clock delay before programming" - // - programming takes ~5.6ms for t5577 ~18ms for E5550 or t5567 - // so we should wait 1 clock + 5.6ms then read response? - // but we need to know we are dealing with t5577 vs t5567 vs e5550 (or q5) marshmellow... - if (testMode) { - //TESTMODE TIMING TESTS: - // <566us does nothing - // 566-568 switches between wiping to 0s and doing nothing - // 5184 wipes and allows 1 block to be programmed. - // indefinite power on wipes and then programs all blocks with bitshifted data sent. - TurnReadLFOn(5184); - - } else { - TurnReadLFOn(20 * 1000); - //could attempt to do a read to confirm write took - // as the tag should repeat back the new block - // until it is reset, but to confirm it we would - // need to know the current block 0 config mode for - // modulation clock an other details to demod the response... - // response should be (for t55x7) a 0 bit then (ST if on) - // block data written in on repeat until reset. - - //DoPartialAcquisition(20, true, 12000); - } - - // turn field off - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_A_OFF(); - + NextOffset++; + } + } + else + Dbprintf ("Too Many Bits to fit into bit buffer"); + return NextOffset; } // Send T5577 reset command then read stream (see if we can identify the start of the stream) @@ -1495,13 +1359,13 @@ void T55xxResetRead(void) { // Trigger T55x7 in mode. FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(START_GAP); + WaitUS(T55xx_Timing_FixedBit.START_GAP); // reset tag - op code 00 - T55xxWriteBit(0); - T55xxWriteBit(0); + T55xxWriteBit(0,&T55xx_Timing_FixedBit); + T55xxWriteBit(0,&T55xx_Timing_FixedBit); - TurnReadLFOn(READ_GAP); + TurnReadLFOn(T55xx_Timing_FixedBit.READ_GAP); // Acquisition DoPartialAcquisition(0, true, BigBuf_max_traceLen(), 0); @@ -1512,18 +1376,85 @@ void T55xxResetRead(void) { LED_A_OFF(); } -// Write one card block in page 0, no lock -void T55xxWriteBlockExt(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { - LED_A_ON(); - bool PwdMode = arg & 0x1; - uint8_t Page = (arg & 0x2)>>1; - bool testMode = arg & 0x4; - uint32_t i = 0; - uint8_t downlink_mode; +// Send one downlink command to the card +void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { //, bool read_cmd) {//, struct T55xx_Timing *Timing) { - downlink_mode = (arg >> 3) & 0x03; + /* + arg bits + xxxxxxx1 0x01 PwdMode + xxxxxx1x 0x02 Page + xxxxx1xx 0x04 testMode + xxx11xxx 0x18 downlink mode + xx1xxxxx 0x20 reg_readmode + x1xxxxxx 0x40 called for a read, so no data packet + + */ + bool PwdMode = ((arg & 0x01) == 0x01); + uint8_t Page = (arg & 0x02) >> 1; + bool testMode = ((arg & 0x04) == 0x04); + uint8_t downlink_mode = (arg >> 3) & 0x03;; + bool reg_readmode = ((arg & 0x20) == 0x20); + bool read_cmd = ((arg & 0x40) == 0x40); + + int i = 0; + uint8_t BitStream[10]; // Max Downlink Command size ~75 bits, so 10 bytes (80 bits) + uint8_t BitStreamLen; + int byte_idx, bit_idx; + T55xx_Timing *Timing; + // Assigning Downlink Timeing for write + switch (downlink_mode) + { + case T55xx_DLMode_Fixed : Timing = &T55xx_Timing_FixedBit; break; + case T55xx_DLMode_LLR : Timing = &T55xx_Timing_LLR; break; + case T55xx_DLMode_Leading0 : Timing = &T55xx_Timing_Leading0; break; + case T55xx_DLMode_1of4 : Timing = &T55xx_Timing_1of4; break; + default: + Timing = &T55xx_Timing_FixedBit; + } + + // Build Bit Stream to send. + memset (BitStream,0x00,sizeof(BitStream)); + + BitStreamLen = 0; + + // Add Leading 0 and 1 of 4 reference bit + if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); + + // Add extra reference 0 for 1 of 4 + if (downlink_mode == T55xx_DLMode_1of4) + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); + + // Add Opcode + if (testMode) Dbprintf("TestMODE"); + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 0 : 1 , 1,sizeof(BitStream)); + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 1 : Page , 1,sizeof(BitStream)); + + if (PwdMode) { + + // Leading 0 and 1 of 4 00 fixed bits if passsword used + if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) { + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); + } + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Pwd, 32,sizeof(BitStream)); + + } + // Add Lock bit + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); + + // Add Data if a write command + if (!read_cmd) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Data, 32,sizeof(BitStream)); + + // Add Address + if (!reg_readmode) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Block, 3,sizeof(BitStream)); + + + + // Send Bits to T55xx + // Set up FPGA, 125kHz LFSetupFPGAForADC(95, true); StartTicks(); @@ -1531,31 +1462,56 @@ void T55xxWriteBlockExt(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg WaitMS(5); // Trigger T55x7 in mode. FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(START_GAP); + WaitUS(Timing->START_GAP); - // Long Leading Reference, same as fixed/default just with leading reference - if (downlink_mode == 1) T55xxWrite_LLR (); - if (testMode) Dbprintf("TestMODE"); - // Std Opcode 10 - T55xxWriteBit(testMode ? 0 : 1); - T55xxWriteBit(testMode ? 1 : Page); //Page 0 + // If long leading 0 send long reference pulse + if (downlink_mode == T55xx_DLMode_LLR) + T55xxWriteBit (T55xx_LongLeadingReference,Timing); // Send Long Leading Start Reference - if (PwdMode) { - // Send Pwd - for (i = 0x80000000; i != 0; i >>= 1) - T55xxWriteBit(Pwd & i); + uint8_t SendBits; + + if (downlink_mode == T55xx_DLMode_1of4) { // 1 of 4 need to send 2 bits at a time + for (i = 0; i < BitStreamLen; i+=2) { + byte_idx = i / 8; + bit_idx = i - (byte_idx * 8); + SendBits = ((BitStream[byte_idx] >> bit_idx) & 1) << 1; + + byte_idx = (i+1) / 8; + bit_idx = (i+1) - (byte_idx * 8); + SendBits += (BitStream[byte_idx] >> bit_idx) & 1; + + T55xxWriteBit (SendBits,Timing); + } } - // Send Lock bit - T55xxWriteBit(0); + else { + for (i = 0; i < BitStreamLen; i++) { + byte_idx = i / 8; + bit_idx = i - (byte_idx * 8); + SendBits = (BitStream[byte_idx] >> bit_idx) & 1; + T55xxWriteBit (SendBits,Timing); + } + } + +} - // Send Data - for (i = 0x80000000; i != 0; i >>= 1) - T55xxWriteBit(Data & i); - - // Send Block number - for (i = 0x04; i != 0; i >>= 1) - T55xxWriteBit(Block & i); +// Write one card block in page 0, no lock +void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { + /* + arg bits + xxxxxxx1 0x01 PwdMode + xxxxxx1x 0x02 Page + xxxxx1xx 0x04 testMode + xxx11xxx 0x18 downlink mode + xx1xxxxx 0x20 reg_readmode + x1xxxxxx 0x40 called for a read, so no data packet + */ + + bool testMode = ((arg & 0x04) == 0x04); + arg &= (0xff ^ 0x40); // Called for a write, so ensure it is clear/0 + + LED_A_ON (); + T55xx_SendCMD (Data, Block, Pwd, arg) ;//, false); // Perform write (nominal is 5.6 ms for T55x7 and 18ms for E5550, // so wait a little more) @@ -1584,86 +1540,43 @@ void T55xxWriteBlockExt(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg //DoPartialAcquisition(20, true, 12000); } - // turn field off FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_A_OFF(); -} - -// Write one card block in page 0, no lock -void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { -// arg 8 bit 00000000 -// 0000000x Password -// 000000x0 Page -// 00000x00 Test Mode -// 000xx000 (0x18) where xx : 00 - Normal Write, 01 - Long Leading Reference -// 10 - Leading 0, 11 - 1 of 4 - uint8_t downlink_mode; - - downlink_mode = (arg >> 3) & 0x03; - - switch (downlink_mode) - { - case 0 :// T55xxWriteBlockExt (Data, Block, Pwd, arg); break; - case 1 : // T55xxWrite_LLR (); - T55xxWriteBlockExt (Data, Block, Pwd, arg); - break; - case 2 : T55xxWriteBlockExt_Leading0 (Data, Block, Pwd, arg); break; - case 3 : T55xxWriteBlockExt_1of4 (Data, Block, Pwd, arg); break; - default: - T55xxWriteBlockExt (Data, Block, Pwd, arg); - } - cmd_send(CMD_ACK,0,0,0,0,0); + + LED_A_OFF (); } // Read one card block in page [page] -void T55xxReadBlockExt (uint16_t arg0, uint8_t Block, uint32_t Pwd) { +void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) {//, struct T55xx_Timing *Timing) { + LED_A_ON(); - bool PwdMode = arg0 & 0x1; - uint8_t Page = (arg0 & 0x2) >> 1; - uint32_t i = 0; - bool RegReadMode = (Block == 0xFF);//regular read mode - uint8_t downlink_mode; - - downlink_mode = (arg0 >> 3) & 0x03; - - //clear buffer now so it does not interfere with timing later - BigBuf_Clear_ext(false); + /* + arg bits + xxxxxxx1 0x01 PwdMode + xxxxxx1x 0x02 Page + xxxxx1xx 0x04 testMode + xxx11xxx 0x18 downlink mode + xx1xxxxx 0x20 reg_readmode + x1xxxxxx 0x40 called for a read, so no data packet + */ + + // Set Read Flag to ensure SendCMD does not add "data" to the packet + arg0 |= 0x40; + + + if (Block == 0xff) arg0 |= 0x20; + //make sure block is at max 7 Block &= 0x7; - - // Set up FPGA, 125kHz to power up the tag - LFSetupFPGAForADC(95, true); - StartTicks(); - // make sure tag is fully powered up... - WaitMS(5); - // Trigger T55x7 Direct Access Mode with start gap - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(START_GAP); - - // Long Leading Reference, same as fixed/default just with leading reference - if (downlink_mode == 1) T55xxWrite_LLR (); + //clear buffer now so it does not interfere with timing later + BigBuf_Clear_ext(false); + + T55xx_SendCMD (0, Block, Pwd, arg0); //, true); + - // Opcode 1[page] - T55xxWriteBit(1); - T55xxWriteBit(Page); //Page 0 - - if (PwdMode){ - // Send Pwd - for (i = 0x80000000; i != 0; i >>= 1) - T55xxWriteBit(Pwd & i); - } - // Send a zero bit separation - T55xxWriteBit(0); - - // Send Block number (if direct access mode) - if (!RegReadMode) - for (i = 0x04; i != 0; i >>= 1) - T55xxWriteBit(Block & i); - // Turn field on to read the response // 137*8 seems to get to the start of data pretty well... // but we want to go past the start and let the repeating data settle in... @@ -1675,163 +1588,11 @@ void T55xxReadBlockExt (uint16_t arg0, uint8_t Block, uint32_t Pwd) { // Turn the field off FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off -// cmd_send(CMD_ACK,0,0,0,0,0); + cmd_send(CMD_ACK,0,0,0,0,0); + LED_A_OFF(); } -void T55xxReadBlockExt_Leading0 (uint16_t arg0, uint8_t Block, uint32_t Pwd) { - LED_A_ON(); - bool PwdMode = arg0 & 0x1; - uint8_t Page = (arg0 & 0x2) >> 1; - uint32_t i = 0; - bool RegReadMode = (Block == 0xFF);//regular read mode - - //clear buffer now so it does not interfere with timing later - BigBuf_Clear_ext(false); - - //make sure block is at max 7 - Block &= 0x7; - - // Set up FPGA, 125kHz to power up the tag - LFSetupFPGAForADC(95, true); - StartTicks(); - // make sure tag is fully powered up... - WaitMS(5); - // Trigger T55x7 Direct Access Mode with start gap - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(START_GAPlz); - - T55xxWriteBit_Leading0 (0); - - // Opcode 1[page] - T55xxWriteBit_Leading0 (1); - T55xxWriteBit_Leading0 (Page); //Page 0 - - if (PwdMode){ - // Send Pwd - T55xxWriteBit_Leading0 (0); - T55xxWriteBit_Leading0 (0); - - for (i = 0x80000000; i != 0; i >>= 1) - T55xxWriteBit_Leading0 (Pwd & i); - } - // Send a zero bit separation - T55xxWriteBit_Leading0(0); - - // Send Block number (if direct access mode) - if (!RegReadMode) - for (i = 0x04; i != 0; i >>= 1) - T55xxWriteBit_Leading0(Block & i); - - // Turn field on to read the response - // 137*8 seems to get to the start of data pretty well... - // but we want to go past the start and let the repeating data settle in... - TurnReadLFOn(210*8); - - // Acquisition - // Now do the acquisition - DoPartialAcquisition(0, true, 12000, 0); - - // Turn the field off - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off -// cmd_send(CMD_ACK,0,0,0,0,0); - LED_A_OFF(); -} - -void T55xxReadBlockExt_1of4 (uint16_t arg0, uint8_t Block, uint32_t Pwd) { - LED_A_ON(); - bool PwdMode = arg0 & 0x1; - uint8_t Page = (arg0 & 0x2) >> 1; - //uint32_t i = 0; - bool RegReadMode = (Block == 0xFF);//regular read mode - uint8_t bits; - int bitpos; - - //clear buffer now so it does not interfere with timing later - BigBuf_Clear_ext(false); - - //make sure block is at max 7 - Block &= 0x7; - - // Set up FPGA, 125kHz to power up the tag - LFSetupFPGAForADC(95, true); - StartTicks(); - // make sure tag is fully powered up... - WaitMS(5); - // Trigger T55x7 Direct Access Mode with start gap - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(START_GAP1of4); - - T55xxWriteBit_1of4 (0); // 2 Bit 00 leading reference - - // Opcode 1[page] - bits = 2 + Page; - T55xxWriteBit_1of4 (bits); - - if (PwdMode) { - // 1 of 4 00 - insert two fixed 00 between opcode and password - T55xxWriteBit_1of4 (0); // 00 - - // Send Pwd - for (bitpos = 31; bitpos >= 1; bitpos -= 2) { // 2 bits at a time - bits = (((Pwd >> bitpos) & 1) << 1) + ((Pwd >> (bitpos-1)) & 1); - T55xxWriteBit_1of4 (bits); - } - } - - // Send Lock bit - bits = 0; // Add lock bit (Not Set) to the next 2 bits - - // Send Block number (if direct access mode) - if (!RegReadMode){ - // Send Block number - bits += ((Block >> 2) & 1); - T55xxWriteBit_1of4 (bits); - bits = (Block & 3); // + (Block & 1); - T55xxWriteBit_1of4 (bits); - } - - // Turn field on to read the response - // 137*8 seems to get to the start of data pretty well... - // but we want to go past the start and let the repeating data settle in... - TurnReadLFOn(210*8); - - // Acquisition - // Now do the acquisition - DoPartialAcquisition(0, true, 12000, 0); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off -// cmd_send(CMD_ACK,0,0,0,0,0); - LED_A_OFF(); -} - -void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) { -// arg0 16 bit 00000000 -// 0000000x Password -// 000000x0 Page -// 00000x00 -// 000xx000 (0x18) where xx : 00 - Normal Write, 01 - Long Leading Reference -// 10 - Leading 0, 11 - 1 of 4 - uint8_t downlink_mode; - - downlink_mode = (arg0 >> 3) & 0x03; - - // downlink mode id set to match the 2 bit as per Tech Sheet - switch (downlink_mode) - { - case 0 :// T55xxReadBlockExt (arg0, Block, Pwd); break; - case 1 : // T55xxWrite_LLR (); - T55xxReadBlockExt (arg0, Block, Pwd); - break; - case 2 : T55xxReadBlockExt_Leading0 (arg0, Block, Pwd); break; - case 3 : T55xxReadBlockExt_1of4 (arg0, Block, Pwd); break; - default: - T55xxReadBlockExt (arg0, Block, Pwd) ; - } - -// T55xxReadBlockExt (arg0, Block, Pwd) ; - cmd_send(CMD_ACK,0,0,0,0,0); -} - void T55xxWakeUp(uint32_t Pwd){ LED_B_ON(); uint32_t i = 0; @@ -1844,15 +1605,16 @@ void T55xxWakeUp(uint32_t Pwd){ // Trigger T55x7 Direct Access Mode FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(START_GAP); + WaitUS(T55xx_Timing_FixedBit.START_GAP); // Opcode 10 - T55xxWriteBit(1); - T55xxWriteBit(0); //Page 0 + T55xxWriteBit(1,&T55xx_Timing_FixedBit); + T55xxWriteBit(0,&T55xx_Timing_FixedBit); //Page 0 // Send Pwd + for (i = 0x80000000; i != 0; i >>= 1) - T55xxWriteBit(Pwd & i); + T55xxWriteBit(Pwd & i,&T55xx_Timing_FixedBit); // Turn and leave field on to let the begin repeating transmission TurnReadLFOn(20*1000); @@ -1863,7 +1625,8 @@ void T55xxWakeUp(uint32_t Pwd){ void WriteT55xx(uint32_t *blockdata, uint8_t startblock, uint8_t numblocks) { // write last block first and config block last (if included) for (uint8_t i = numblocks+startblock; i > startblock; i--) { - T55xxWriteBlockExt(blockdata[i-1],i-1,0,0); + T55xxWriteBlock(blockdata[i-1],i-1,0,0);//,false); //,&T55xx_Timing_FixedBit); + // T55xx_SendCMD (blockdata[i-1],i-1,0,0);//,false); //,&T55xx_Timing_FixedBit); } } diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index ed980f9b..c64e5ef2 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -311,13 +311,13 @@ int CmdT55xxSetConfig(const char *Cmd) { } // No args - if (cmdp == 0) return printConfiguration( config ); + if (cmdp == 0) return printConfiguration( config); //Validations if (errors) return usage_t55xx_config(); config.block0 = 0; - return printConfiguration ( config ); + return printConfiguration ( config); } int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, bool override, uint32_t password, uint8_t downlink_mode){ @@ -476,6 +476,25 @@ bool DecodeT5555TraceBlock() { return (bool) ASKDemod("64 0 1", false, false, 1); } +void T55xx_Print_DownlinkMode (uint8_t downlink_mode) +{ + char Msg[80]; + sprintf (Msg,"Downlink Mode used : "); + + switch (downlink_mode) { + case 0 : strcat (Msg,"default/fixed bit length"); break; + case 1 : strcat (Msg,"long leading reference (r 1)"); break; + case 2 : strcat (Msg,"leading zero reference (r 2)"); break; + case 3 : strcat (Msg,"1 of 4 coding reference (r 3)"); break; + default : + strcat (Msg,"default/fixed bit length"); break; + + } + + PrintAndLog (Msg); + +} + int CmdT55xxDetect(const char *Cmd){ bool errors = false; bool useGB = false; @@ -522,13 +541,8 @@ int CmdT55xxDetect(const char *Cmd){ if ( !tryDetectModulation() ) PrintAndLog("Could not detect modulation automatically. Try setting it manually with \'lf t55xx config\'"); else { - // Add downlink mode to reference. - switch (downlink_mode) { - case 0 : PrintAndLog ("Downlink : r 0 - default/fixed bit length"); break; - case 1 : PrintAndLog ("Downlink : r 1 - long leading reference"); break; - case 2 : PrintAndLog ("Downlink : r 2 - leading zero reference"); break; - case 3 : PrintAndLog ("Downlink : r 3 - 1 of 4 coding reference"); break; - } + // Add downlink mode for reference. + T55xx_Print_DownlinkMode (downlink_mode); } return 1; } @@ -681,7 +695,8 @@ bool tryDetectModulation(){ config.block0 = tests[0].block0; config.Q5 = tests[0].Q5; config.ST = tests[0].ST; - printConfiguration( config ); + + printConfiguration( config); return true; } @@ -689,7 +704,7 @@ bool tryDetectModulation(){ PrintAndLog("Found [%d] possible matches for modulation.",hits); for(int i=0; i 3 or set to 0, so loop from 0 - 3 for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++){ if ( !AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, testpwd, dl_mode)) { - PrintAndLog("Aquireing data from device failed. Quitting"); + PrintAndLog("Acquiring data from device failed. Quitting"); free(keyBlock); return 0; } @@ -1551,12 +1566,9 @@ int CmdT55xxBruteForce(const char *Cmd) { if ( found ) { PrintAndLog("Found valid password: [%08X]", testpwd); free(keyBlock); - switch (dl_mode) { - case 0 : PrintAndLog ("Downlink : r 0 - default/fixed bit length"); break; - case 1 : PrintAndLog ("Downlink : r 1 - long leading reference"); break; - case 2 : PrintAndLog ("Downlink : r 2 - leading zero reference"); break; - case 3 : PrintAndLog ("Downlink : r 3 - 1 of 4 coding reference"); break; - } + + T55xx_Print_DownlinkMode (dl_mode); + return 0; } if (!try_all_dl_modes) // Exit loop if not trying all downlink modes @@ -1597,7 +1609,7 @@ int CmdT55xxBruteForce(const char *Cmd) { // donwlink_mode will = 0 if > 3 or set to 0, so loop from 0 - 3 for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++){ if (!AquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, i,dl_mode)) { - PrintAndLog("Aquireing data from device failed. Quitting"); + PrintAndLog("Acquiring data from device failed. Quitting"); free(keyBlock); return 0; } @@ -1613,12 +1625,7 @@ int CmdT55xxBruteForce(const char *Cmd) { if (found){ PrintAndLog("Found valid password: [%08x]", i); - switch (dl_mode) { - case 0 : PrintAndLog ("Downlink : r 0 - default/fixed bit length"); break; - case 1 : PrintAndLog ("Downlink : r 1 - long leading reference"); break; - case 2 : PrintAndLog ("Downlink : r 2 - leading Zero reference"); break; - case 3 : PrintAndLog ("Downlink : r 3 - 1 of 4 coding reference"); break; - } + T55xx_Print_DownlinkMode (downlink_mode); } else{ PrintAndLog(""); From 2de26056ce3650d8ae48f30bf657e27b3669a0a3 Mon Sep 17 00:00:00 2001 From: marshmellow42 Date: Sun, 23 Jun 2019 07:43:56 -0400 Subject: [PATCH 099/189] add lf em 4x05protect plus lf config s option (#833) * add "samples to skip" for lf config (mainly for lf snoop) * add lf em 4x05protect command to write protection on em4x05 chips * fix spacing * and remove old comment git added back in.. * update changelog * fix flags - only need 1 bit --- CHANGELOG.md | 2 + armsrc/appmain.c | 3 ++ armsrc/apps.h | 1 + armsrc/lfops.c | 81 ++++++++++++++++++++++++++++--- armsrc/lfsampling.c | 20 +++++--- client/cmdlf.c | 34 +++++++------ client/cmdlfem4x.c | 114 ++++++++++++++++++++++++++++++++++++++++++++ include/usb_cmd.h | 2 + 8 files changed, 231 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 399f87f9..cb508cd9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - `hf 15 sim` now works as expected (piwi) ### Added +- Added `lf config s xxxx` option to allow skipping x samples before capture (marshmellow) +- Added `lf em 4x05protect` to support changing protection blocks on em4x05 chips (marshmellow) - Support Standard Communication Mode in HITAG S - Added `hf emv scan` - commands for scan EMV card and dump data to json file (Merlok) - `hf mfp` group of commands (Merlok) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 37328a50..5169383e 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1088,6 +1088,9 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_EM4X_WRITE_WORD: EM4xWriteWord(c->arg[0], c->arg[1], c->arg[2]); break; + case CMD_EM4X_PROTECT: + EM4xProtect(c->arg[0], c->arg[1], c->arg[2]); + break; case CMD_AWID_DEMOD_FSK: // Set realtime AWID demodulation CmdAWIDdemodFSK(c->arg[0], 0, 0, 1); break; diff --git a/armsrc/apps.h b/armsrc/apps.h index d1c885ab..4d9a1482 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -89,6 +89,7 @@ void TurnReadLFOn(); //void T55xxReadTrace(void); void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode); void EM4xWriteWord(uint32_t flag, uint32_t Data, uint32_t Pwd); +void EM4xProtect(uint32_t flag, uint32_t Data, uint32_t Pwd); void Cotag(uint32_t arg0); /// iso14443.h diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 81fdd7a6..ed207dbb 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1198,10 +1198,45 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) * and enlarge the gap ones. * Q5 tags seems to have issues when these values changes. */ -#define START_GAP 31*8 // was 250 // SPEC: 1*8 to 50*8 - typ 15*8 (or 15fc) -#define WRITE_GAP 20*8 // was 160 // SPEC: 1*8 to 20*8 - typ 10*8 (or 10fc) -#define WRITE_0 18*8 // was 144 // SPEC: 16*8 to 32*8 - typ 24*8 (or 24fc) -#define WRITE_1 50*8 // was 400 // SPEC: 48*8 to 64*8 - typ 56*8 (or 56fc) 432 for T55x7; 448 for E5550 + +/* Q5 timing datasheet: + * Type | MIN | Typical | Max | + * Start_Gap | 10*8 | ? | 50*8 | + * Write_Gap Normal mode | 8*8 | 14*8 | 20*8 | + * Write_Gap Fast Mode | 8*8 | ? | 20*8 | + * Write_0 Normal mode | 16*8 | 24*8 | 32*8 | + * Write_1 Normal mode | 48*8 | 56*8 | 64*8 | + * Write_0 Fast Mode | 8*8 | 12*8 | 16*8 | + * Write_1 Fast Mode | 24*8 | 28*8 | 32*8 | +*/ + +/* T5557 timing datasheet: + * Type | MIN | Typical | Max | + * Start_Gap | 10*8 | ? | 50*8 | + * Write_Gap Normal mode | 8*8 |50-150us | 30*8 | + * Write_Gap Fast Mode | 8*8 | ? | 20*8 | + * Write_0 Normal mode | 16*8 | 24*8 | 31*8 | + * Write_1 Normal mode | 48*8 | 54*8 | 63*8 | + * Write_0 Fast Mode | 8*8 | 12*8 | 15*8 | + * Write_1 Fast Mode | 24*8 | 28*8 | 31*8 | +*/ + +/* T5577C timing datasheet for Fixed-Bit-Length protocol (defualt): + * Type | MIN | Typical | Max | + * Start_Gap | 8*8 | 15*8 | 50*8 | + * Write_Gap Normal mode | 8*8 | 10*8 | 20*8 | + * Write_Gap Fast Mode | 8*8 | 10*8 | 20*8 | + * Write_0 Normal mode | 16*8 | 24*8 | 32*8 | + * Write_1 Normal mode | 48*8 | 56*8 | 64*8 | + * Write_0 Fast Mode | 8*8 | 12*8 | 16*8 | + * Write_1 Fast Mode | 24*8 | 28*8 | 32*8 | +*/ + +//note startgap must be sent after tag has been powered up for more than 3ms (per T5557 ds) +#define START_GAP 31*8 //31*8 // was 250 // SPEC: 1*8 to 50*8 - typ 15*8 (or 15fc) - T5557: 10*8 to 50*8 +#define WRITE_GAP 20*8 //20*8 // was 160 // SPEC: 1*8 to 20*8 - typ 10*8 (or 10fc) - T5557: 8*8 to 30*8 typ 50-150us +#define WRITE_0 18*8 //18*8 // was 144 // SPEC: 16*8 to 32*8 - typ 24*8 (or 24fc) - T5557: 16*8 to 31*8 typ 24*8 +#define WRITE_1 50*8 //50*8 // was 400 // SPEC: 48*8 to 64*8 - typ 56*8 (or 56fc) - T5557: 48*8 to 63*8 typ 54*8 432 for T55x7; 448 for E5550 #define READ_GAP 15*8 void TurnReadLFOn(int delay) { @@ -1355,7 +1390,7 @@ void T55xxReadBlock(uint16_t arg0, uint8_t Block, uint32_t Pwd) { T55xxWriteBit(1); T55xxWriteBit(Page); //Page 0 - if (PwdMode){ + if (PwdMode) { // Send Pwd for (i = 0x80000000; i != 0; i >>= 1) T55xxWriteBit(Pwd & i); @@ -1614,6 +1649,7 @@ void WriteEM410x(uint32_t card, uint32_t id_hi, uint32_t id_lo) { #define FWD_CMD_WRITE 0xA #define FWD_CMD_READ 0x9 #define FWD_CMD_DISABLE 0x5 +#define FWD_CMD_PROTECT 0x3 uint8_t forwardLink_data[64]; //array of forwarded bits uint8_t * forward_ptr; //ptr for forward message preparation @@ -1783,7 +1819,7 @@ void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode) { void EM4xWriteWord(uint32_t flag, uint32_t Data, uint32_t Pwd) { - bool PwdMode = (flag & 0xF); + bool PwdMode = (flag & 0x1); uint8_t Address = (flag >> 8) & 0xFF; uint8_t fwd_bit_count; @@ -1813,6 +1849,39 @@ void EM4xWriteWord(uint32_t flag, uint32_t Data, uint32_t Pwd) { LED_A_OFF(); cmd_send(CMD_ACK,0,0,0,0,0); } + +void EM4xProtect(uint32_t flag, uint32_t Data, uint32_t Pwd) { + + bool PwdMode = (flag & 0x1); + uint8_t fwd_bit_count; + + //clear buffer now so it does not interfere with timing later + BigBuf_Clear_ext(false); + + LED_A_ON(); + StartTicks(); + //If password mode do login + if (PwdMode) EM4xLogin(Pwd); + + forward_ptr = forwardLink_data; + fwd_bit_count = Prepare_Cmd( FWD_CMD_PROTECT ); + + //unsure if this needs the full packet config... + fwd_bit_count += Prepare_Data( Data&0xFFFF, Data>>16 ); + + SendForward(fwd_bit_count); + + //Wait for write to complete + //SpinDelay(10); + + WaitUS(6500); + //Capture response if one exists + DoPartialAcquisition(20, true, 6000, 1000); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off + LED_A_OFF(); + cmd_send(CMD_ACK,0,0,0,0,0); +} /* Reading a COTAG. diff --git a/armsrc/lfsampling.c b/armsrc/lfsampling.c index 03bccf41..e53d0205 100644 --- a/armsrc/lfsampling.c +++ b/armsrc/lfsampling.c @@ -14,7 +14,7 @@ #include "usb_cdc.h" // for usb_poll_validate_length #include "fpgaloader.h" -sample_config config = { 1, 8, 1, 95, 0 } ; +sample_config config = { 1, 8, 1, 95, 0, 0 } ; void printConfig() { @@ -24,6 +24,7 @@ void printConfig() Dbprintf(" [d] decimation: %d ", config.decimation); Dbprintf(" [a] averaging: %d ", config.averaging); Dbprintf(" [t] trigger threshold: %d ", config.trigger_threshold); + Dbprintf(" [s] samples to skip: %d ", config.samples_to_skip); } @@ -34,7 +35,7 @@ void printConfig() * Other functions may read samples and ignore the sampling config, * such as functions to read the UID from a prox tag or similar. * - * Values set to '0' implies no change (except for averaging) + * Values set to '0' implies no change (except for averaging, threshold, samples_to_skip) * @brief setSamplingConfig * @param sc */ @@ -44,6 +45,7 @@ void setSamplingConfig(sample_config *sc) if(sc->bits_per_sample!= 0) config.bits_per_sample= sc->bits_per_sample; if(sc->decimation!= 0) config.decimation= sc->decimation; if(sc->trigger_threshold != -1) config.trigger_threshold= sc->trigger_threshold; + if(sc->samples_to_skip != -1) config.samples_to_skip = sc->samples_to_skip; config.averaging= sc->averaging; if(config.bits_per_sample > 8) config.bits_per_sample = 8; @@ -119,7 +121,7 @@ void LFSetupFPGAForADC(int divisor, bool lf_field) * @param silent - is true, now outputs are made. If false, dbprints the status * @return the number of bits occupied by the samples. */ -uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averaging, int trigger_threshold, bool silent, int bufsize, int cancel_after) +uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averaging, int trigger_threshold, bool silent, int bufsize, int cancel_after, int samples_to_skip) { //. uint8_t *dest = BigBuf_get_addr(); @@ -141,6 +143,7 @@ uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averag uint32_t sample_total_numbers =0 ; uint32_t sample_total_saved =0 ; uint32_t cancel_counter = 0; + uint32_t samples_skipped = 0; while(!BUTTON_PRESS() && !usb_poll_validate_length() ) { WDT_HIT(); @@ -160,6 +163,10 @@ uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averag continue; } trigger_threshold = 0; + if (samples_to_skip > samples_skipped) { + samples_skipped++; + continue; + } sample_total_numbers++; if(averaging) @@ -218,7 +225,7 @@ uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averag */ uint32_t DoAcquisition_default(int trigger_threshold, bool silent) { - return DoAcquisition(1,8,0,trigger_threshold,silent,0,0); + return DoAcquisition(1,8,0,trigger_threshold,silent,0,0,0); } uint32_t DoAcquisition_config(bool silent, int sample_size) { @@ -228,11 +235,12 @@ uint32_t DoAcquisition_config(bool silent, int sample_size) ,config.trigger_threshold ,silent ,sample_size - ,0); + ,0 + ,config.samples_to_skip); } uint32_t DoPartialAcquisition(int trigger_threshold, bool silent, int sample_size, int cancel_after) { - return DoAcquisition(1,8,0,trigger_threshold,silent,sample_size,cancel_after); + return DoAcquisition(1,8,0,trigger_threshold,silent,sample_size,cancel_after,0); } uint32_t ReadLF(bool activeField, bool silent, int sample_size) diff --git a/client/cmdlf.c b/client/cmdlf.c index 12d30663..f661e518 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -224,24 +224,25 @@ int usage_lf_config(void) { PrintAndLog("Usage: lf config [H|] [b ] [d ] [a 0|1]"); PrintAndLog("Options: "); - PrintAndLog(" h This help"); - PrintAndLog(" L Low frequency (125 KHz)"); - PrintAndLog(" H High frequency (134 KHz)"); - PrintAndLog(" q Manually set divisor. 88-> 134 KHz, 95-> 125 KHz"); - PrintAndLog(" b Sets resolution of bits per sample. Default (max): 8"); - PrintAndLog(" d Sets decimation. A value of N saves only 1 in N samples. Default: 1"); - PrintAndLog(" a [0|1] Averaging - if set, will average the stored sample value when decimating. Default: 1"); - PrintAndLog(" t Sets trigger threshold. 0 means no threshold (range: 0-128)"); + PrintAndLog(" h This help"); + PrintAndLog(" L Low frequency (125 KHz)"); + PrintAndLog(" H High frequency (134 KHz)"); + PrintAndLog(" q Manually set divisor. 88-> 134 KHz, 95-> 125 KHz"); + PrintAndLog(" b Sets resolution of bits per sample. Default (max): 8"); + PrintAndLog(" d Sets decimation. A value of N saves only 1 in N samples. Default: 1"); + PrintAndLog(" a [0|1] Averaging - if set, will average the stored sample value when decimating. Default: 1"); + PrintAndLog(" t Sets trigger threshold. 0 means no threshold (range: 0-128)"); + PrintAndLog(" s Sets a number of samples to skip before capture. Default: 0"); PrintAndLog("Examples:"); PrintAndLog(" lf config b 8 L"); - PrintAndLog(" Samples at 125KHz, 8bps."); + PrintAndLog(" Samples at 125KHz, 8bps."); PrintAndLog(" lf config H b 4 d 3"); - PrintAndLog(" Samples at 134KHz, averages three samples into one, stored with "); - PrintAndLog(" a resolution of 4 bits per sample."); + PrintAndLog(" Samples at 134KHz, averages three samples into one, stored with "); + PrintAndLog(" a resolution of 4 bits per sample."); PrintAndLog(" lf read"); - PrintAndLog(" Performs a read (active field)"); + PrintAndLog(" Performs a read (active field)"); PrintAndLog(" lf snoop"); - PrintAndLog(" Performs a snoop (no active field)"); + PrintAndLog(" Performs a snoop (no active field)"); return 0; } @@ -255,6 +256,7 @@ int CmdLFSetConfig(const char *Cmd) bool errors = false; int trigger_threshold =-1;//Means no change uint8_t unsigned_trigg = 0; + int samples_to_skip = -1; uint8_t cmdp =0; while(param_getchar(Cmd, cmdp) != 0x00) @@ -295,6 +297,10 @@ int CmdLFSetConfig(const char *Cmd) averaging = param_getchar(Cmd,cmdp+1) == '1'; cmdp+=2; break; + case 's': + samples_to_skip = param_get32ex(Cmd,cmdp+1,0,10); + cmdp+=2; + break; default: PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = 1; @@ -316,7 +322,7 @@ int CmdLFSetConfig(const char *Cmd) if(bps >> 4) bps = 8; sample_config config = { - decimation,bps,averaging,divisor,trigger_threshold + decimation,bps,averaging,divisor,trigger_threshold,samples_to_skip }; //Averaging is a flag on high-bit of arg[1] UsbCommand c = {CMD_SET_LF_SAMPLING_CONFIG}; diff --git a/client/cmdlfem4x.c b/client/cmdlfem4x.c index cdaeb5ed..d1bde911 100644 --- a/client/cmdlfem4x.c +++ b/client/cmdlfem4x.c @@ -1161,6 +1161,119 @@ int CmdEM4x05WriteWord(const char *Cmd) { return EM4x05WriteWord(addr, data, pwd, usePwd, swap, invert); } +int usage_lf_em_protect(void) { + PrintAndLog("Protect EM4x05. Tag must be on antenna. "); + PrintAndLog(""); + PrintAndLog("Usage: lf em 4x05protect [h] d p [s] [i]"); + PrintAndLog("Options:"); + PrintAndLog(" h - this help"); + PrintAndLog(" d - data to write (hex)"); + PrintAndLog(" p - password (hex) (optional)"); + PrintAndLog(" s - swap the data bit order before write"); + PrintAndLog(" i - invert the data bits before write"); + PrintAndLog("samples:"); + PrintAndLog(" lf em 4x05protect d 11223344"); + PrintAndLog(" lf em 4x05protect p deadc0de d 11223344 s i"); + return 0; +} + +int EM4x05Protect(uint32_t data, uint32_t pwd, bool usePwd, bool swap, bool invert) { + if (swap) data = SwapBits(data, 32); + + if (invert) data ^= 0xFFFFFFFF; + + if ( !usePwd ) { + PrintAndLog("Writing Protect data %08X", data); + } else { + PrintAndLog("Writing Protect data %08X using password %08X", data, pwd); + } + + uint16_t flag = usePwd; + + UsbCommand c = {CMD_EM4X_PROTECT, {flag, data, pwd}}; + clearCommandBuffer(); + SendCommand(&c); + UsbCommand resp; + if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)){ + PrintAndLog("Error occurred, device did not respond during protect operation."); + return -1; + } + if ( !downloadSamplesEM() ) { + return -1; + } + //check response for 00001010 for write confirmation! + //attempt demod: + uint32_t dummy = 0; + int result = demodEM4x05resp(&dummy,false); + if (result == 1) { + PrintAndLog("Protect Verified"); + } else { + PrintAndLog("Protect could not be verified"); + } + return result; +} + +int CmdEM4x05ProtectWrite(const char *Cmd) { + bool errors = false; + bool usePwd = false; + uint32_t data = 0xFFFFFFFF; + uint32_t pwd = 0xFFFFFFFF; + bool swap = false; + bool invert = false; + bool gotData = false; + char cmdp = 0; + while(param_getchar(Cmd, cmdp) != 0x00) + { + switch(param_getchar(Cmd, cmdp)) + { + case 'h': + case 'H': + return usage_lf_em_write(); + case 'd': + case 'D': + data = param_get32ex(Cmd, cmdp+1, 0, 16); + gotData = true; + cmdp += 2; + break; + case 'i': + case 'I': + invert = true; + cmdp++; + break; + case 'p': + case 'P': + pwd = param_get32ex(Cmd, cmdp+1, 1, 16); + if (pwd == 1) { + PrintAndLog("invalid pwd"); + errors = true; + } + usePwd = true; + cmdp += 2; + break; + case 's': + case 'S': + swap = true; + cmdp++; + break; + default: + PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + if(errors) break; + } + //Validations + if(errors) return usage_lf_em_protect(); + + if ( strlen(Cmd) == 0 ) return usage_lf_em_protect(); + + if (!gotData) { + PrintAndLog("You must enter the data you want to write"); + return usage_lf_em_protect(); + } + return EM4x05Protect(data, pwd, usePwd, swap, invert); +} + void printEM4x05config(uint32_t wordData) { uint16_t datarate = EM4x05_GET_BITRATE(wordData); uint8_t encoder = ((wordData >> 6) & 0xF); @@ -1345,6 +1458,7 @@ static command_t CommandTable[] = {"4x05info", CmdEM4x05info, 0, "(pwd) -- Get info from EM4x05/EM4x69 tag"}, {"4x05readword", CmdEM4x05ReadWord, 0, " (pwd) -- Read EM4x05/EM4x69 word data"}, {"4x05writeword", CmdEM4x05WriteWord, 0, " (pwd) -- Write EM4x05/EM4x69 word data"}, + {"4x05protect", CmdEM4x05ProtectWrite, 0, " (pwd) -- Write Protection to EM4x05"}, {"4x50read", CmdEM4x50Read, 1, "demod data from EM4x50 tag from the graph buffer"}, {NULL, NULL, 0, NULL} }; diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 9ef929b9..82981acf 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -41,6 +41,7 @@ typedef struct{ bool averaging; int divisor; int trigger_threshold; + int samples_to_skip; } sample_config; // For the bootloader @@ -116,6 +117,7 @@ typedef struct{ #define CMD_T55XX_WAKEUP 0x0224 #define CMD_COTAG 0x0225 #define CMD_PARADOX_CLONE_TAG 0x0226 +#define CMD_EM4X_PROTECT 0x0228 // For the 13.56 MHz tags #define CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693 0x0300 From 99c52f9d85cf952d6a13dbd0be35cb6be1f50cdf Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Sun, 23 Jun 2019 22:23:08 +1000 Subject: [PATCH 100/189] Update CHANGELOG.md Change Log Update --- CHANGELOG.md | 30 ++++-------------------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55f1d1f9..19a20557 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,33 +4,11 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ## [unreleased][unreleased] -## T55xx Downlink Protocol - 22 Jun 2019 - -# armsrc/lfops - +## T55xx Downlink Protocol ### Added -- Added typedef T55xx_Timing to hold downlink timings. -- Added Timing Records for long leading reference (llr), Leading 0 and 1 of 4 -- Added some constant defines for code readability -- Added function T55xx_SetBits to build a bit stream for writing to T55xx -- Added function T55xx_SendCMD to build the bit stream and send to T55xx - -### Changed -- Converted Timing for default/fixed bit to T55xx_Timing -- Updated T55xxWriteBit (and calls) to support all downlink protocols -- Updated T55xxWriteBlock to call T55xx_SendCMD (removed local bit writes) -- Updated T55xxReadBlock to call T55xx_SendCMD (removed local bit writes) - -# client/cmdlft55xx - -### Added -- Added function T55xx_Print_DownlinkMode to print downlink mode information when uesd - -### Changes -- Added downlink mode options r [ 0 (or missing) default/fixed bit, 1 long leading, leading 0 and 1 of 4 ] -- Added r 4 option to bruteforce to try all downlink modes (0,1,2 and 3) -- Updated help messages for each support functions t55xx_read, t55xx_write, t55_detect, t55xx_bruteforce - +- Added downlink reference mode option r [ 0 - (or missing) default/fixed bit, 1 - long leading, 2 - leading 0 and 3 - 1 of 4 ] +- Added special option r 4 to bruteforce, to try all downlink modes (0,1,2 and 3) for each password +- Support added to lf t55xx detect, read, write, bruteforce ### Changed - Changed hf mfp security. Now it works in all the modes. (drHatson) From d3521ae609658fa00955c8fd57f69eb84ce7a7cd Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Mon, 24 Jun 2019 08:42:57 +0200 Subject: [PATCH 101/189] Update CHANGELOG.md --- CHANGELOG.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 19a20557..9439399a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,12 +4,6 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ## [unreleased][unreleased] -## T55xx Downlink Protocol -### Added -- Added downlink reference mode option r [ 0 - (or missing) default/fixed bit, 1 - long leading, 2 - leading 0 and 3 - 1 of 4 ] -- Added special option r 4 to bruteforce, to try all downlink modes (0,1,2 and 3) for each password -- Support added to lf t55xx detect, read, write, bruteforce - ### Changed - Changed hf mfp security. Now it works in all the modes. (drHatson) - `hf fido` - show/check DER certificate and signatures (Merlok) @@ -39,6 +33,9 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added Mifare Mini, Mifare 2K and 4K support to `hf mf sim` (piwi) - Added Legic detection to `hf search` (dnet) - Added Home (Pos1) and End key bindings to the plot GUI (based on @mcd1992) +- Added downlink reference mode option r [ 0 - (or missing) default/fixed bit, 1 - long leading, 2 - leading 0 and 3 - 1 of 4 ] to `lf t55xx detect`, `lf t55xx read`, `lf t55xx write`, and `lf t55xx bruteforce` +- Added special option `r 4` to bruteforce, to try all downlink modes (0,1,2 and 3) for each password + ## [v3.1.0][2018-10-10] From e220fc63aaa4f61ca2f91216c4420c18612dd544 Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Tue, 25 Jun 2019 18:56:32 +1000 Subject: [PATCH 102/189] Update lfops.c --- armsrc/lfops.c | 50 +------------------------------------------------- 1 file changed, 1 insertion(+), 49 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index c1f32f87..c56d08f9 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1219,55 +1219,7 @@ typedef struct { uint16_t READ_GAP; } T55xx_Timing; -/* - T5577 Timeing from datasheet for reference - - Fixed bit length - ---------------- - Normal Down Link Fast Downlink - Min Typ Max Min Typ Max - Start gap 8 15 50 8 15 50 - Write gap 8 10 20 8 10 20 - 0 data 16 24 32 8 12 16 - 1 data 48 56 64 24 28 32 - - - Long Leading Reference - ---------------------- - Normal Down Link Fast Downlink - Min Typ Max Min Typ Max - Start gap 8 10 50 8 10 50 - Write gap 8 10 20 8 10 20 - Reference(r) 152 160 168 140 144 148 - 136 + 0 data 132 + 0 data - 0 data r - 143 r - 136 r - 128 r - 135 r - 132 r - 124 - 1 data r - 111 r - 104 r - 96 r - 119 r - 116 r - 112 - - - Leading Zero Reference - ---------------------- - Normal Down Link Fast Downlink - Min Typ Max Min Typ Max - Start gap 8 10 50 8 10 50 - Write gap 8 10 20 8 10 20 - Reference(r) 12 - 72 8 - 68 - 0 data r - 7 r r + 8 r - 3 r r + 4 - 1 data r + 9 r + 16 r + 24 r + 5 r + 8 r + 12 - - - 1 of 4 Coding - ------------- - Normal Down Link Fast Downlink - Min Typ Max Min Typ Max - Start gap 8 10 50 8 10 50 - Write gap 8 10 20 8 10 20 - Reference(r) 8 - 68 12 - 72 - 00 data r - 7 r r + 8 r - 3 r r + 4 - 01 data r + 9 r + 16 r + 24 r + 5 r + 8 r + 12 - 10 data r + 25 r + 32 r + 40 r + 13 r + 16 r + 20 - 11 data r + 41 r + 48 r + 56 r + 21 r + 24 r + 28 - -*/ + // Set Initial/Default Values. Note: *8 can occure when used. This should keep things simplier here. T55xx_Timing T55xx_Timing_FixedBit = { 31 * 8 , 20 * 8 , 18 * 8 , 50 * 8 , 0 , 0 , 15 * 8 }; From 50764caadcf78a3657ca014d4710fd2521dbd534 Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Tue, 25 Jun 2019 19:28:06 +1000 Subject: [PATCH 103/189] Update lfops.c --- armsrc/lfops.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index efa75652..819653f0 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1206,8 +1206,8 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) #define WRITE_GAP 20*8 // was 160 // SPEC: 1*8 to 20*8 - typ 10*8 (or 10fc) #define WRITE_0 18*8 // was 144 // SPEC: 16*8 to 32*8 - typ 24*8 (or 24fc) #define WRITE_1 50*8 // was 400 // SPEC: 48*8 to 64*8 - typ 56*8 (or 56fc) 432 for T55x7; 448 for E5550 -======= +*/ /* Q5 timing datasheet: * Type | MIN | Typical | Max | * Start_Gap | 10*8 | ? | 50*8 | @@ -1240,7 +1240,7 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) * Write_0 Fast Mode | 8*8 | 12*8 | 16*8 | * Write_1 Fast Mode | 24*8 | 28*8 | 32*8 | */ - +/* //note startgap must be sent after tag has been powered up for more than 3ms (per T5557 ds) #define START_GAP 31*8 //31*8 // was 250 // SPEC: 1*8 to 50*8 - typ 15*8 (or 15fc) - T5557: 10*8 to 50*8 #define WRITE_GAP 20*8 //20*8 // was 160 // SPEC: 1*8 to 20*8 - typ 10*8 (or 10fc) - T5557: 8*8 to 30*8 typ 50-150us @@ -1271,11 +1271,11 @@ T55xx_Timing T55xx_Timing_1of4 = { 31 * 8 , 20 * 8 , 18 * 8 , 34 * 8 , 5 // Some defines for readability -#define T55xx_LongLeadingReference 4 // Value to tell Write Bit to send long reference #define T55xx_DLMode_Fixed 0 // Default Mode #define T55xx_DLMode_LLR 1 // Long Leading Reference #define T55xx_DLMode_Leading0 2 // Leading Zero #define T55xx_DLMode_1of4 3 // 1 of 4 +#define T55xx_LongLeadingReference 4 // Value to tell Write Bit to send long reference void TurnReadLFOn(int delay) { FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); @@ -1324,7 +1324,7 @@ int T55xx_SetBits (uint8_t *bit_array, int start_offset, uint32_t data , in bit_idx = NextOffset - (byte_idx * 8); // Get Bit Index to set/clr // If set (1) we OR, if clear (0) we AND with inverse - // Dbprintf ("Add Bit : %d at byte %d bit %d",bit,byte_idx,bit_idx); + // Dbprintf ("Add Bit : %d at byte %d bit %d",bit,byte_idx,bit_idx); if (bit == 1) bit_array[byte_idx] |= (1 << bit_idx); // Set the bit to 1 From 5a9964829e8e6ef8382ed8b61dc71b1705a270f7 Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Tue, 25 Jun 2019 20:46:10 +1000 Subject: [PATCH 104/189] Resolved Conflicts --- armsrc/lfops.c | 45 ++++++++++----------------------------------- 1 file changed, 10 insertions(+), 35 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 819653f0..19bf6555 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1307,32 +1307,17 @@ void T55xxWriteBit(int bit, T55xx_Timing *Timings) { // num_bits - how many bits (low x bits of data) Max 32 bits at a time // max_len - how many bytes can the bit_array hold (ensure no buffer overflow) // returns "Next" bit offset / bits stored (for next store) -int T55xx_SetBits (uint8_t *bit_array, int start_offset, uint32_t data , int num_bits, int max_len) +//int T55xx_SetBits (uint8_t *bit_array, int start_offset, uint32_t data , int num_bits, int max_len) +int T55xx_SetBits (bool *bit_array, int start_offset, uint32_t data , int num_bits, int max_len) { - int bit,byte_idx, bit_idx; int offset; int NextOffset = start_offset; // Check if data will fit. - if ((start_offset + num_bits) <= (max_len*8)) { - + if ((start_offset + num_bits) <= (max_len*8)) { // Loop through the data and store - for (offset = (num_bits-1); offset >= 0; offset--) { - - bit = (data >> offset) & 1; // Get data bit value (0/1) - byte_idx = (NextOffset / 8); // Get Array Byte Index to Store - bit_idx = NextOffset - (byte_idx * 8); // Get Bit Index to set/clr - - // If set (1) we OR, if clear (0) we AND with inverse - // Dbprintf ("Add Bit : %d at byte %d bit %d",bit,byte_idx,bit_idx); - if (bit == 1) - bit_array[byte_idx] |= (1 << bit_idx); // Set the bit to 1 - - else - bit_array[byte_idx] &= (0xff ^ (1 << bit_idx)); // Set the bit to 0 (clr) - - NextOffset++; - } + for (offset = (num_bits-1); offset >= 0; offset--) + bit_array[NextOffset++] = (data >> offset) & 1; } else Dbprintf ("Too Many Bits to fit into bit buffer"); @@ -1390,11 +1375,11 @@ void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { bool reg_readmode = ((arg & 0x20) == 0x20); bool read_cmd = ((arg & 0x40) == 0x40); - int i = 0; - uint8_t BitStream[10]; // Max Downlink Command size ~75 bits, so 10 bytes (80 bits) + int i = 0; + bool BitStream[100]; // Max Downlink Command size ~75 bits, so 10 bytes (80 bits) uint8_t BitStreamLen; - int byte_idx, bit_idx; T55xx_Timing *Timing; + uint8_t SendBits; // Assigning Downlink Timeing for write @@ -1463,26 +1448,16 @@ void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { if (downlink_mode == T55xx_DLMode_LLR) T55xxWriteBit (T55xx_LongLeadingReference,Timing); // Send Long Leading Start Reference - uint8_t SendBits; if (downlink_mode == T55xx_DLMode_1of4) { // 1 of 4 need to send 2 bits at a time for (i = 0; i < BitStreamLen; i+=2) { - byte_idx = i / 8; - bit_idx = i - (byte_idx * 8); - SendBits = ((BitStream[byte_idx] >> bit_idx) & 1) << 1; - - byte_idx = (i+1) / 8; - bit_idx = (i+1) - (byte_idx * 8); - SendBits += (BitStream[byte_idx] >> bit_idx) & 1; - + SendBits = (BitStream[i] << 1) + BitStream[i+1]; T55xxWriteBit (SendBits,Timing); } } else { for (i = 0; i < BitStreamLen; i++) { - byte_idx = i / 8; - bit_idx = i - (byte_idx * 8); - SendBits = (BitStream[byte_idx] >> bit_idx) & 1; + SendBits = (BitStream[i]); T55xxWriteBit (SendBits,Timing); } } From 2994ab10d64e4121a1894b8f01e350be4fc1e988 Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Tue, 25 Jun 2019 20:52:29 +1000 Subject: [PATCH 105/189] Update CHANGELOG.md --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 037bab99..a3421c77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ## [unreleased][unreleased] +## T55xx Downlink Protocol +### Added +- Added downlink reference mode option r [ 0 - (default) fixed bit, 1 - long leading, 2 - leading 0 and 3 - 1 of 4 ] +Supported commands lf t55xx detect, read, write, bruteforce (with special r 4 to try all downlink modes) (mwalker33) + + ### Changed - Changed hf mfp security. Now it works in all the modes. (drHatson) - `hf fido` - show/check DER certificate and signatures (Merlok) From 59f75a789546405310e6ba06c01d9c6582a69071 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Tue, 25 Jun 2019 18:37:25 +0200 Subject: [PATCH 106/189] Update CHANGELOG.md --- CHANGELOG.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3421c77..037bab99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,12 +4,6 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac ## [unreleased][unreleased] -## T55xx Downlink Protocol -### Added -- Added downlink reference mode option r [ 0 - (default) fixed bit, 1 - long leading, 2 - leading 0 and 3 - 1 of 4 ] -Supported commands lf t55xx detect, read, write, bruteforce (with special r 4 to try all downlink modes) (mwalker33) - - ### Changed - Changed hf mfp security. Now it works in all the modes. (drHatson) - `hf fido` - show/check DER certificate and signatures (Merlok) From 7db36608a266a1f0f46dd4032cede2930e221d51 Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Wed, 26 Jun 2019 11:34:31 +1000 Subject: [PATCH 107/189] Code improved for less memory --- armsrc/lfops.c | 236 ++++++++++++++++++++++++------------------------- 1 file changed, 117 insertions(+), 119 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 19bf6555..95fa9e7c 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1261,21 +1261,22 @@ typedef struct { uint16_t READ_GAP; } T55xx_Timing; - - // Set Initial/Default Values. Note: *8 can occure when used. This should keep things simplier here. T55xx_Timing T55xx_Timing_FixedBit = { 31 * 8 , 20 * 8 , 18 * 8 , 50 * 8 , 0 , 0 , 15 * 8 }; T55xx_Timing T55xx_Timing_LLR = { 31 * 8 , 20 * 8 , 18 * 8 , 50 * 8 , 0 , 0 , 15 * 8 }; T55xx_Timing T55xx_Timing_Leading0 = { 31 * 8 , 20 * 8 , 18 * 8 , 40 * 8 , 0 , 0 , 15 * 8 }; T55xx_Timing T55xx_Timing_1of4 = { 31 * 8 , 20 * 8 , 18 * 8 , 34 * 8 , 50 * 8 , 66 * 8 , 15 * 8 }; - // Some defines for readability #define T55xx_DLMode_Fixed 0 // Default Mode #define T55xx_DLMode_LLR 1 // Long Leading Reference #define T55xx_DLMode_Leading0 2 // Leading Zero #define T55xx_DLMode_1of4 3 // 1 of 4 #define T55xx_LongLeadingReference 4 // Value to tell Write Bit to send long reference +// Macro for code readability +#define BitStream_Byte(X) ((X) / 8) +#define BitStream_Bit(X) ((X) - ((X) / 8) * 8) + void TurnReadLFOn(int delay) { FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); @@ -1299,7 +1300,6 @@ void T55xxWriteBit(int bit, T55xx_Timing *Timings) { WaitUS(Timings->WRITE_GAP); } - // Function to abstract an Arbitrary length byte array to store bit pattern. // bit_array - Array to hold data/bit pattern // start_offset - bit location to start storing new bits. @@ -1308,22 +1308,129 @@ void T55xxWriteBit(int bit, T55xx_Timing *Timings) { // max_len - how many bytes can the bit_array hold (ensure no buffer overflow) // returns "Next" bit offset / bits stored (for next store) //int T55xx_SetBits (uint8_t *bit_array, int start_offset, uint32_t data , int num_bits, int max_len) -int T55xx_SetBits (bool *bit_array, int start_offset, uint32_t data , int num_bits, int max_len) +int T55xx_SetBits (uint8_t *BitStream, uint8_t start_offset, uint32_t data , uint8_t num_bits, uint8_t max_len) { - int offset; - int NextOffset = start_offset; + int8_t offset; + int8_t NextOffset = start_offset; // Check if data will fit. if ((start_offset + num_bits) <= (max_len*8)) { // Loop through the data and store - for (offset = (num_bits-1); offset >= 0; offset--) - bit_array[NextOffset++] = (data >> offset) & 1; + for (offset = (num_bits-1); offset >= 0; offset--) { + + if ((data >> offset) & 1) BitStream[BitStream_Byte(NextOffset)] |= (1 << BitStream_Bit(NextOffset)); // Set the bit to 1 + else BitStream[BitStream_Byte(NextOffset)] &= (0xff ^ (1 << BitStream_Bit(NextOffset))); // Set the bit to 0 + + NextOffset++; + } } else Dbprintf ("Too Many Bits to fit into bit buffer"); + return NextOffset; } +// Send one downlink command to the card +void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { //, bool read_cmd) {//, struct T55xx_Timing *Timing) { + + /* + arg bits + xxxxxxx1 0x01 PwdMode + xxxxxx1x 0x02 Page + xxxxx1xx 0x04 testMode + xxx11xxx 0x18 downlink mode + xx1xxxxx 0x20 reg_readmode + x1xxxxxx 0x40 called for a read, so no data packet + + */ + bool PwdMode = ((arg & 0x01) == 0x01); + uint8_t Page = (arg & 0x02) >> 1; + bool testMode = ((arg & 0x04) == 0x04); + uint8_t downlink_mode = (arg >> 3) & 0x03; + bool reg_readmode = ((arg & 0x20) == 0x20); + bool read_cmd = ((arg & 0x40) == 0x40); + uint8_t i = 0; + uint8_t BitStream[10]; // Max Downlink Command size ~74 bits, so 10 bytes (80 bits) + uint8_t BitStreamLen; + T55xx_Timing *Timing; + uint8_t SendBits; + + // Assigning Downlink Timeing for write + switch (downlink_mode) + { + case T55xx_DLMode_Fixed : Timing = &T55xx_Timing_FixedBit; break; + case T55xx_DLMode_LLR : Timing = &T55xx_Timing_LLR; break; + case T55xx_DLMode_Leading0 : Timing = &T55xx_Timing_Leading0; break; + case T55xx_DLMode_1of4 : Timing = &T55xx_Timing_1of4; break; + default: + Timing = &T55xx_Timing_FixedBit; + } + + // Build Bit Stream to send. + memset (BitStream,0x00,sizeof(BitStream)); + + BitStreamLen = 0; + + // Add Leading 0 and 1 of 4 reference bit + if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); + + // Add extra reference 0 for 1 of 4 + if (downlink_mode == T55xx_DLMode_1of4) + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); + + // Add Opcode + if (testMode) Dbprintf("TestMODE"); + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 0 : 1 , 1,sizeof(BitStream)); + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 1 : Page , 1,sizeof(BitStream)); + + if (PwdMode) { + // Leading 0 and 1 of 4 00 fixed bits if passsword used + if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) { + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); + } + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Pwd, 32,sizeof(BitStream)); + } + + // Add Lock bit 0 + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); + + // Add Data if a write command + if (!read_cmd) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Data, 32,sizeof(BitStream)); + + // Add Address + if (!reg_readmode) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Block, 3,sizeof(BitStream)); + + // Send Bits to T55xx + // Set up FPGA, 125kHz + LFSetupFPGAForADC(95, true); + StartTicks(); + // make sure tag is fully powered up... + WaitMS(5); + // Trigger T55x7 in mode. + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + WaitUS(Timing->START_GAP); + + // If long leading 0 send long reference pulse + if (downlink_mode == T55xx_DLMode_LLR) + T55xxWriteBit (T55xx_LongLeadingReference,Timing); // Send Long Leading Start Reference + + if (downlink_mode == T55xx_DLMode_1of4) { // 1 of 4 need to send 2 bits at a time + for ( i = 0; i < BitStreamLen; i+=2 ) { + SendBits = (BitStream[BitStream_Byte(i )] >> (BitStream_Bit(i )) & 1) << 1; // Bit i + SendBits += (BitStream[BitStream_Byte(i+1)] >> (BitStream_Bit(i+1)) & 1); // Bit i+1; + T55xxWriteBit (SendBits & 3,Timing); + } + } + else { + for (i = 0; i < BitStreamLen; i++) { + SendBits = (BitStream[BitStream_Byte(i)] >> BitStream_Bit(i)); + T55xxWriteBit (SendBits & 1,Timing); + } + } +} + // Send T5577 reset command then read stream (see if we can identify the start of the stream) void T55xxResetRead(void) { LED_A_ON(); @@ -1355,115 +1462,6 @@ void T55xxResetRead(void) { LED_A_OFF(); } -// Send one downlink command to the card -void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { //, bool read_cmd) {//, struct T55xx_Timing *Timing) { - - /* - arg bits - xxxxxxx1 0x01 PwdMode - xxxxxx1x 0x02 Page - xxxxx1xx 0x04 testMode - xxx11xxx 0x18 downlink mode - xx1xxxxx 0x20 reg_readmode - x1xxxxxx 0x40 called for a read, so no data packet - - */ - bool PwdMode = ((arg & 0x01) == 0x01); - uint8_t Page = (arg & 0x02) >> 1; - bool testMode = ((arg & 0x04) == 0x04); - uint8_t downlink_mode = (arg >> 3) & 0x03;; - bool reg_readmode = ((arg & 0x20) == 0x20); - bool read_cmd = ((arg & 0x40) == 0x40); - - int i = 0; - bool BitStream[100]; // Max Downlink Command size ~75 bits, so 10 bytes (80 bits) - uint8_t BitStreamLen; - T55xx_Timing *Timing; - uint8_t SendBits; - - - // Assigning Downlink Timeing for write - switch (downlink_mode) - { - case T55xx_DLMode_Fixed : Timing = &T55xx_Timing_FixedBit; break; - case T55xx_DLMode_LLR : Timing = &T55xx_Timing_LLR; break; - case T55xx_DLMode_Leading0 : Timing = &T55xx_Timing_Leading0; break; - case T55xx_DLMode_1of4 : Timing = &T55xx_Timing_1of4; break; - default: - Timing = &T55xx_Timing_FixedBit; - } - - // Build Bit Stream to send. - memset (BitStream,0x00,sizeof(BitStream)); - - BitStreamLen = 0; - - // Add Leading 0 and 1 of 4 reference bit - if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); - - // Add extra reference 0 for 1 of 4 - if (downlink_mode == T55xx_DLMode_1of4) - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); - - // Add Opcode - if (testMode) Dbprintf("TestMODE"); - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 0 : 1 , 1,sizeof(BitStream)); - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 1 : Page , 1,sizeof(BitStream)); - - if (PwdMode) { - - // Leading 0 and 1 of 4 00 fixed bits if passsword used - if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) { - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); - } - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Pwd, 32,sizeof(BitStream)); - - } - // Add Lock bit - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); - - // Add Data if a write command - if (!read_cmd) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Data, 32,sizeof(BitStream)); - - // Add Address - if (!reg_readmode) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Block, 3,sizeof(BitStream)); - - - - // Send Bits to T55xx - - // Set up FPGA, 125kHz - LFSetupFPGAForADC(95, true); - StartTicks(); - // make sure tag is fully powered up... - WaitMS(5); - // Trigger T55x7 in mode. - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(Timing->START_GAP); - - - // If long leading 0 send long reference pulse - if (downlink_mode == T55xx_DLMode_LLR) - T55xxWriteBit (T55xx_LongLeadingReference,Timing); // Send Long Leading Start Reference - - - if (downlink_mode == T55xx_DLMode_1of4) { // 1 of 4 need to send 2 bits at a time - for (i = 0; i < BitStreamLen; i+=2) { - SendBits = (BitStream[i] << 1) + BitStream[i+1]; - T55xxWriteBit (SendBits,Timing); - } - } - else { - for (i = 0; i < BitStreamLen; i++) { - SendBits = (BitStream[i]); - T55xxWriteBit (SendBits,Timing); - } - } - -} - // Write one card block in page 0, no lock void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { /* @@ -1518,6 +1516,7 @@ void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { } // Read one card block in page [page] +//void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) {//, struct T55xx_Timing *Timing) { void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) {//, struct T55xx_Timing *Timing) { LED_A_ON(); @@ -1613,7 +1612,6 @@ void T55xxWakeUp(uint32_t Pwd){ T55xxWriteBit(0,&T55xx_Timing_FixedBit); //Page 0 // Send Pwd - for (i = 0x80000000; i != 0; i >>= 1) T55xxWriteBit(Pwd & i,&T55xx_Timing_FixedBit); From 28597bb6c742c6d717d33aebdbb5b0ba98bc95eb Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Thu, 27 Jun 2019 16:57:28 +1000 Subject: [PATCH 108/189] Update lfops.c moved wakeup and reset to call T55xx_SendCMD. Small code improvements --- armsrc/lfops.c | 110 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 76 insertions(+), 34 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 95fa9e7c..16a46910 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1274,8 +1274,8 @@ T55xx_Timing T55xx_Timing_1of4 = { 31 * 8 , 20 * 8 , 18 * 8 , 34 * 8 , 5 #define T55xx_DLMode_1of4 3 // 1 of 4 #define T55xx_LongLeadingReference 4 // Value to tell Write Bit to send long reference // Macro for code readability -#define BitStream_Byte(X) ((X) / 8) -#define BitStream_Bit(X) ((X) - ((X) / 8) * 8) +#define BitStream_Byte(X) ((X) >> 3) +#define BitStream_Bit(X) ((X) & 7) void TurnReadLFOn(int delay) { @@ -1288,7 +1288,7 @@ void TurnReadLFOn(int delay) { void T55xxWriteBit(int bit, T55xx_Timing *Timings) { // If bit = 4 Send Long Leading Reference which is 138 + WRITE_0 - + // Dbprintf ("Bits : %d",bit); switch (bit){ case 0 : TurnReadLFOn(Timings->WRITE_0); break; // Send bit 0/00 case 1 : TurnReadLFOn(Timings->WRITE_1); break; // Send bit 1/01 @@ -1324,14 +1324,16 @@ int T55xx_SetBits (uint8_t *BitStream, uint8_t start_offset, uint32_t data , uin NextOffset++; } } - else - Dbprintf ("Too Many Bits to fit into bit buffer"); - + else{ + // Note: This should never happen unless some code changes cause it. + // So short message for coders when testing. + Dbprintf ("T55 too many bits"); + } return NextOffset; } // Send one downlink command to the card -void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { //, bool read_cmd) {//, struct T55xx_Timing *Timing) { +void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { /* arg bits @@ -1339,16 +1341,19 @@ void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { xxxxxx1x 0x02 Page xxxxx1xx 0x04 testMode xxx11xxx 0x18 downlink mode - xx1xxxxx 0x20 reg_readmode + xx1xxxxx 0x20 !reg_readmode x1xxxxxx 0x40 called for a read, so no data packet - + 1xxxxxxx 0x80 reset + */ bool PwdMode = ((arg & 0x01) == 0x01); - uint8_t Page = (arg & 0x02) >> 1; + bool Page = (arg & 0x02); bool testMode = ((arg & 0x04) == 0x04); uint8_t downlink_mode = (arg >> 3) & 0x03; bool reg_readmode = ((arg & 0x20) == 0x20); bool read_cmd = ((arg & 0x40) == 0x40); + bool reset = (arg & 0x80); + uint8_t i = 0; uint8_t BitStream[10]; // Max Downlink Command size ~74 bits, so 10 bytes (80 bits) uint8_t BitStreamLen; @@ -1379,29 +1384,35 @@ void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { if (downlink_mode == T55xx_DLMode_1of4) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); - // Add Opcode - if (testMode) Dbprintf("TestMODE"); - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 0 : 1 , 1,sizeof(BitStream)); - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 1 : Page , 1,sizeof(BitStream)); + // Add Opcode + if (reset) { + // Reset : r*) 00 + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 2,sizeof(BitStream)); + } + else + { + if (testMode) Dbprintf("TestMODE"); + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 0 : 1 , 1,sizeof(BitStream)); + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 1 : Page , 1,sizeof(BitStream)); - if (PwdMode) { - // Leading 0 and 1 of 4 00 fixed bits if passsword used - if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) { - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); - } - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Pwd, 32,sizeof(BitStream)); - } + if (PwdMode) { + // Leading 0 and 1 of 4 00 fixed bits if passsword used + if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) { + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 2,sizeof(BitStream)); + } + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Pwd, 32,sizeof(BitStream)); + } - // Add Lock bit 0 - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); + // Add Lock bit 0 + if (!reg_readmode) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); - // Add Data if a write command - if (!read_cmd) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Data, 32,sizeof(BitStream)); - - // Add Address - if (!reg_readmode) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Block, 3,sizeof(BitStream)); + // Add Data if a write command + if (!read_cmd) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Data, 32,sizeof(BitStream)); + // Add Address + if (!reg_readmode) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Block, 3,sizeof(BitStream)); + } + // Send Bits to T55xx // Set up FPGA, 125kHz LFSetupFPGAForADC(95, true); @@ -1434,6 +1445,7 @@ void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { // Send T5577 reset command then read stream (see if we can identify the start of the stream) void T55xxResetRead(void) { LED_A_ON(); +/* //clear buffer now so it does not interfere with timing later BigBuf_Clear_keep_EM(); @@ -1452,6 +1464,15 @@ void T55xxResetRead(void) { T55xxWriteBit(0,&T55xx_Timing_FixedBit); TurnReadLFOn(T55xx_Timing_FixedBit.READ_GAP); +*/ + + // send r* 00 + uint8_t arg = 0x80; // SendCMD will add correct reference mode based on flags (when added). + + // Add in downlink_mode when ready + // arg |= 0x00; // dlmode << 3 (00 default - 08 leading 0 - 10 Fixed - 18 1 of 4 ) + + T55xx_SendCMD (0, 0, 0, arg); //, true); // Acquisition DoPartialAcquisition(0, true, BigBuf_max_traceLen(), 0); @@ -1470,8 +1491,9 @@ void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { xxxxxx1x 0x02 Page xxxxx1xx 0x04 testMode xxx11xxx 0x18 downlink mode - xx1xxxxx 0x20 reg_readmode + xx1xxxxx 0x20 !reg_readmode x1xxxxxx 0x40 called for a read, so no data packet + 1xxxxxxx 0x80 reset */ bool testMode = ((arg & 0x04) == 0x04); @@ -1516,7 +1538,6 @@ void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { } // Read one card block in page [page] -//void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) {//, struct T55xx_Timing *Timing) { void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) {//, struct T55xx_Timing *Timing) { LED_A_ON(); @@ -1527,14 +1548,15 @@ void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) {//, struct T55 xxxxxx1x 0x02 Page xxxxx1xx 0x04 testMode xxx11xxx 0x18 downlink mode - xx1xxxxx 0x20 reg_readmode + xx1xxxxx 0x20 !reg_readmode x1xxxxxx 0x40 called for a read, so no data packet + 1xxxxxxx 0x80 reset */ // Set Read Flag to ensure SendCMD does not add "data" to the packet arg0 |= 0x40; - + // RegRead Mode true of block 0xff if (Block == 0xff) arg0 |= 0x20; //make sure block is at max 7 @@ -1595,8 +1617,8 @@ void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) {//, struct T55 void T55xxWakeUp(uint32_t Pwd){ LED_B_ON(); + /* uint32_t i = 0; - // Set up FPGA, 125kHz LFSetupFPGAForADC(95, true); StartTicks(); @@ -1614,6 +1636,26 @@ void T55xxWakeUp(uint32_t Pwd){ // Send Pwd for (i = 0x80000000; i != 0; i >>= 1) T55xxWriteBit(Pwd & i,&T55xx_Timing_FixedBit); +*/ + /* + arg bits + xxxxxxx1 0x01 PwdMode + xxxxxx1x 0x02 Page + xxxxx1xx 0x04 testMode + xxx11xxx 0x18 downlink mode + xx1xxxxx 0x20 !reg_readmode + x1xxxxxx 0x40 called for a read, so no data packet + 1xxxxxxx 0x80 reset + */ + + // r* 10 (00) r* for llr , L0 and 1/4 - (00) for L0 and 1/4 - All handled in SendCMD + // So, default Opcode 10 and pwd. + uint8_t arg = 0x01 | 0x40 | 0x20; //Password Read Call no data | reg_read no block + + // Add in downlink_mode when ready + // arg |= 0x00; // dlmode << 3 (00 default - 08 leading 0 - 10 Fixed - 18 1 of 4 ) + + T55xx_SendCMD (0, 0, Pwd, arg); //, true); // Turn and leave field on to let the begin repeating transmission TurnReadLFOn(20*1000); From d7569065cb7464f42005b2fdbc17feef7d2f129b Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Wed, 3 Jul 2019 19:58:49 +1000 Subject: [PATCH 109/189] Code tidy removed commented code --- armsrc/lfops.c | 72 -------------------------------------------------- 1 file changed, 72 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 16a46910..4a7de24d 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1445,26 +1445,6 @@ void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { // Send T5577 reset command then read stream (see if we can identify the start of the stream) void T55xxResetRead(void) { LED_A_ON(); -/* - //clear buffer now so it does not interfere with timing later - BigBuf_Clear_keep_EM(); - - // Set up FPGA, 125kHz - LFSetupFPGAForADC(95, true); - StartTicks(); - // make sure tag is fully powered up... - WaitMS(5); - - // Trigger T55x7 in mode. - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(T55xx_Timing_FixedBit.START_GAP); - - // reset tag - op code 00 - T55xxWriteBit(0,&T55xx_Timing_FixedBit); - T55xxWriteBit(0,&T55xx_Timing_FixedBit); - - TurnReadLFOn(T55xx_Timing_FixedBit.READ_GAP); -*/ // send r* 00 uint8_t arg = 0x80; // SendCMD will add correct reference mode based on flags (when added). @@ -1566,39 +1546,7 @@ void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) {//, struct T55 BigBuf_Clear_ext(false); T55xx_SendCMD (0, Block, Pwd, arg0); //, true); - -/* -// the send has been moved to the above SendCMD Call -======= - // Set up FPGA, 125kHz to power up the tag - LFSetupFPGAForADC(95, true); - StartTicks(); - // make sure tag is fully powered up... - WaitMS(5); - // Trigger T55x7 Direct Access Mode with start gap - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(START_GAP); - - // Opcode 1[page] - T55xxWriteBit(1); - T55xxWriteBit(Page); //Page 0 - - if (PwdMode) { - // Send Pwd - for (i = 0x80000000; i != 0; i >>= 1) - T55xxWriteBit(Pwd & i); - } - // Send a zero bit separation - T55xxWriteBit(0); - - // Send Block number (if direct access mode) - if (!RegReadMode) - for (i = 0x04; i != 0; i >>= 1) - T55xxWriteBit(Block & i); - - -*/ // Turn field on to read the response // 137*8 seems to get to the start of data pretty well... // but we want to go past the start and let the repeating data settle in... @@ -1617,26 +1565,6 @@ void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) {//, struct T55 void T55xxWakeUp(uint32_t Pwd){ LED_B_ON(); - /* - uint32_t i = 0; - // Set up FPGA, 125kHz - LFSetupFPGAForADC(95, true); - StartTicks(); - // make sure tag is fully powered up... - WaitMS(5); - - // Trigger T55x7 Direct Access Mode - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - WaitUS(T55xx_Timing_FixedBit.START_GAP); - - // Opcode 10 - T55xxWriteBit(1,&T55xx_Timing_FixedBit); - T55xxWriteBit(0,&T55xx_Timing_FixedBit); //Page 0 - - // Send Pwd - for (i = 0x80000000; i != 0; i >>= 1) - T55xxWriteBit(Pwd & i,&T55xx_Timing_FixedBit); -*/ /* arg bits xxxxxxx1 0x01 PwdMode From dcd936a1da12a50a4084f4445d8ebbb080b5bc36 Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Sat, 6 Jul 2019 15:20:25 +1000 Subject: [PATCH 110/189] Update lfops.c Fixed lf t55 reset --- armsrc/lfops.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 4a7de24d..c6aecf0f 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1201,11 +1201,13 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) /* // Original Timings for reference +//note startgap must be sent after tag has been powered up for more than 3ms (per T5557 ds) #define START_GAP 31*8 // was 250 // SPEC: 1*8 to 50*8 - typ 15*8 (or 15fc) #define WRITE_GAP 20*8 // was 160 // SPEC: 1*8 to 20*8 - typ 10*8 (or 10fc) #define WRITE_0 18*8 // was 144 // SPEC: 16*8 to 32*8 - typ 24*8 (or 24fc) #define WRITE_1 50*8 // was 400 // SPEC: 48*8 to 64*8 - typ 56*8 (or 56fc) 432 for T55x7; 448 for E5550 +#define READ_GAP 15*8 */ /* Q5 timing datasheet: @@ -1240,15 +1242,6 @@ void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol) * Write_0 Fast Mode | 8*8 | 12*8 | 16*8 | * Write_1 Fast Mode | 24*8 | 28*8 | 32*8 | */ -/* -//note startgap must be sent after tag has been powered up for more than 3ms (per T5557 ds) -#define START_GAP 31*8 //31*8 // was 250 // SPEC: 1*8 to 50*8 - typ 15*8 (or 15fc) - T5557: 10*8 to 50*8 -#define WRITE_GAP 20*8 //20*8 // was 160 // SPEC: 1*8 to 20*8 - typ 10*8 (or 10fc) - T5557: 8*8 to 30*8 typ 50-150us -#define WRITE_0 18*8 //18*8 // was 144 // SPEC: 16*8 to 32*8 - typ 24*8 (or 24fc) - T5557: 16*8 to 31*8 typ 24*8 -#define WRITE_1 50*8 //50*8 // was 400 // SPEC: 48*8 to 64*8 - typ 56*8 (or 56fc) - T5557: 48*8 to 63*8 typ 54*8 432 for T55x7; 448 for E5550 - -#define READ_GAP 15*8 -*/ // Structure to hold Timing values. In future will be simplier to add user changable timings. typedef struct { @@ -1374,7 +1367,7 @@ void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { // Build Bit Stream to send. memset (BitStream,0x00,sizeof(BitStream)); - BitStreamLen = 0; + BitStreamLen = 0; // Ensure 0 bit index to start. // Add Leading 0 and 1 of 4 reference bit if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) @@ -1427,8 +1420,8 @@ void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { if (downlink_mode == T55xx_DLMode_LLR) T55xxWriteBit (T55xx_LongLeadingReference,Timing); // Send Long Leading Start Reference - if (downlink_mode == T55xx_DLMode_1of4) { // 1 of 4 need to send 2 bits at a time - for ( i = 0; i < BitStreamLen; i+=2 ) { + if (downlink_mode == T55xx_DLMode_1of4) { // 1 of 4 need to send 2 bits at a time + for ( i = 0; i < BitStreamLen-1; i+=2 ) { SendBits = (BitStream[BitStream_Byte(i )] >> (BitStream_Bit(i )) & 1) << 1; // Bit i SendBits += (BitStream[BitStream_Byte(i+1)] >> (BitStream_Bit(i+1)) & 1); // Bit i+1; T55xxWriteBit (SendBits & 3,Timing); @@ -1452,8 +1445,13 @@ void T55xxResetRead(void) { // Add in downlink_mode when ready // arg |= 0x00; // dlmode << 3 (00 default - 08 leading 0 - 10 Fixed - 18 1 of 4 ) + //clear buffer now so it does not interfere with timing later + BigBuf_Clear_keep_EM(); + T55xx_SendCMD (0, 0, 0, arg); //, true); + TurnReadLFOn(T55xx_Timing_FixedBit.READ_GAP); + // Acquisition DoPartialAcquisition(0, true, BigBuf_max_traceLen(), 0); From bdc97796459e46419e72468b2e92d46f0a10a56e Mon Sep 17 00:00:00 2001 From: mwalker33 Date: Sun, 7 Jul 2019 05:00:08 +1000 Subject: [PATCH 111/189] Update lfops.c boundary length check --- armsrc/lfops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index c6aecf0f..ed83df48 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1420,7 +1420,7 @@ void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { if (downlink_mode == T55xx_DLMode_LLR) T55xxWriteBit (T55xx_LongLeadingReference,Timing); // Send Long Leading Start Reference - if (downlink_mode == T55xx_DLMode_1of4) { // 1 of 4 need to send 2 bits at a time + if ((downlink_mode == T55xx_DLMode_1of4) && (BitStreamLen > 0)) { // 1 of 4 need to send 2 bits at a time for ( i = 0; i < BitStreamLen-1; i+=2 ) { SendBits = (BitStream[BitStream_Byte(i )] >> (BitStream_Bit(i )) & 1) << 1; // Bit i SendBits += (BitStream[BitStream_Byte(i+1)] >> (BitStream_Bit(i+1)) & 1); // Bit i+1; From 347efc12741e72e6ce3a3c4f3ed554fae0cefc73 Mon Sep 17 00:00:00 2001 From: jmorsch Date: Thu, 11 Jul 2019 13:01:36 -0400 Subject: [PATCH 112/189] whitespace cleaning --- armsrc/lfops.c | 172 ++++++++++++++++++++++++------------------------- 1 file changed, 86 insertions(+), 86 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index ed83df48..c9947d97 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1264,7 +1264,7 @@ T55xx_Timing T55xx_Timing_1of4 = { 31 * 8 , 20 * 8 , 18 * 8 , 34 * 8 , 5 #define T55xx_DLMode_Fixed 0 // Default Mode #define T55xx_DLMode_LLR 1 // Long Leading Reference #define T55xx_DLMode_Leading0 2 // Leading Zero -#define T55xx_DLMode_1of4 3 // 1 of 4 +#define T55xx_DLMode_1of4 3 // 1 of 4 #define T55xx_LongLeadingReference 4 // Value to tell Write Bit to send long reference // Macro for code readability #define BitStream_Byte(X) ((X) >> 3) @@ -1281,14 +1281,14 @@ void TurnReadLFOn(int delay) { void T55xxWriteBit(int bit, T55xx_Timing *Timings) { // If bit = 4 Send Long Leading Reference which is 138 + WRITE_0 - // Dbprintf ("Bits : %d",bit); + // Dbprintf ("Bits : %d",bit); switch (bit){ case 0 : TurnReadLFOn(Timings->WRITE_0); break; // Send bit 0/00 case 1 : TurnReadLFOn(Timings->WRITE_1); break; // Send bit 1/01 case 2 : TurnReadLFOn(Timings->WRITE_2); break; // Send bits 10 - case 3 : TurnReadLFOn(Timings->WRITE_3); break; // Send bits 11 - case 4 : TurnReadLFOn(Timings->WRITE_0 + (136 * 8)); break; // Send Long Leading Reference - } + case 3 : TurnReadLFOn(Timings->WRITE_3); break; // Send bits 11 + case 4 : TurnReadLFOn(Timings->WRITE_0 + (136 * 8)); break; // Send Long Leading Reference + } FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); WaitUS(Timings->WRITE_GAP); } @@ -1303,31 +1303,31 @@ void T55xxWriteBit(int bit, T55xx_Timing *Timings) { //int T55xx_SetBits (uint8_t *bit_array, int start_offset, uint32_t data , int num_bits, int max_len) int T55xx_SetBits (uint8_t *BitStream, uint8_t start_offset, uint32_t data , uint8_t num_bits, uint8_t max_len) { - int8_t offset; - int8_t NextOffset = start_offset; + int8_t offset; + int8_t NextOffset = start_offset; - // Check if data will fit. - if ((start_offset + num_bits) <= (max_len*8)) { - // Loop through the data and store - for (offset = (num_bits-1); offset >= 0; offset--) { + // Check if data will fit. + if ((start_offset + num_bits) <= (max_len*8)) { + // Loop through the data and store + for (offset = (num_bits-1); offset >= 0; offset--) { - if ((data >> offset) & 1) BitStream[BitStream_Byte(NextOffset)] |= (1 << BitStream_Bit(NextOffset)); // Set the bit to 1 - else BitStream[BitStream_Byte(NextOffset)] &= (0xff ^ (1 << BitStream_Bit(NextOffset))); // Set the bit to 0 + if ((data >> offset) & 1) BitStream[BitStream_Byte(NextOffset)] |= (1 << BitStream_Bit(NextOffset)); // Set the bit to 1 + else BitStream[BitStream_Byte(NextOffset)] &= (0xff ^ (1 << BitStream_Bit(NextOffset))); // Set the bit to 0 - NextOffset++; - } - } - else{ - // Note: This should never happen unless some code changes cause it. - // So short message for coders when testing. - Dbprintf ("T55 too many bits"); - } - return NextOffset; + NextOffset++; + } + } + else { + // Note: This should never happen unless some code changes cause it. + // So short message for coders when testing. + Dbprintf ("T55 too many bits"); + } + return NextOffset; } // Send one downlink command to the card void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { - + /* arg bits xxxxxxx1 0x01 PwdMode @@ -1337,32 +1337,32 @@ void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { xx1xxxxx 0x20 !reg_readmode x1xxxxxx 0x40 called for a read, so no data packet 1xxxxxxx 0x80 reset - + */ - bool PwdMode = ((arg & 0x01) == 0x01); - bool Page = (arg & 0x02); - bool testMode = ((arg & 0x04) == 0x04); - uint8_t downlink_mode = (arg >> 3) & 0x03; - bool reg_readmode = ((arg & 0x20) == 0x20); - bool read_cmd = ((arg & 0x40) == 0x40); - bool reset = (arg & 0x80); - - uint8_t i = 0; + bool PwdMode = ((arg & 0x01) == 0x01); + bool Page = (arg & 0x02); + bool testMode = ((arg & 0x04) == 0x04); + uint8_t downlink_mode = (arg >> 3) & 0x03; + bool reg_readmode = ((arg & 0x20) == 0x20); + bool read_cmd = ((arg & 0x40) == 0x40); + bool reset = (arg & 0x80); + + uint8_t i = 0; uint8_t BitStream[10]; // Max Downlink Command size ~74 bits, so 10 bytes (80 bits) uint8_t BitStreamLen; T55xx_Timing *Timing; uint8_t SendBits; - + // Assigning Downlink Timeing for write switch (downlink_mode) { case T55xx_DLMode_Fixed : Timing = &T55xx_Timing_FixedBit; break; - case T55xx_DLMode_LLR : Timing = &T55xx_Timing_LLR; break; + case T55xx_DLMode_LLR : Timing = &T55xx_Timing_LLR; break; case T55xx_DLMode_Leading0 : Timing = &T55xx_Timing_Leading0; break; case T55xx_DLMode_1of4 : Timing = &T55xx_Timing_1of4; break; default: Timing = &T55xx_Timing_FixedBit; - } + } // Build Bit Stream to send. memset (BitStream,0x00,sizeof(BitStream)); @@ -1370,42 +1370,42 @@ void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { BitStreamLen = 0; // Ensure 0 bit index to start. // Add Leading 0 and 1 of 4 reference bit - if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) + if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); // Add extra reference 0 for 1 of 4 - if (downlink_mode == T55xx_DLMode_1of4) + if (downlink_mode == T55xx_DLMode_1of4) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); // Add Opcode - if (reset) { - // Reset : r*) 00 - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 2,sizeof(BitStream)); - } - else - { - if (testMode) Dbprintf("TestMODE"); - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 0 : 1 , 1,sizeof(BitStream)); - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 1 : Page , 1,sizeof(BitStream)); - - if (PwdMode) { - // Leading 0 and 1 of 4 00 fixed bits if passsword used - if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) { - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 2,sizeof(BitStream)); - } - BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Pwd, 32,sizeof(BitStream)); - } + if (reset) { + // Reset : r*) 00 + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 2,sizeof(BitStream)); + } + else + { + if (testMode) Dbprintf("TestMODE"); + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 0 : 1 , 1,sizeof(BitStream)); + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen,testMode ? 1 : Page , 1,sizeof(BitStream)); - // Add Lock bit 0 - if (!reg_readmode) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); + if (PwdMode) { + // Leading 0 and 1 of 4 00 fixed bits if passsword used + if ((downlink_mode == T55xx_DLMode_Leading0) || (downlink_mode == T55xx_DLMode_1of4)) { + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 2,sizeof(BitStream)); + } + BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Pwd, 32,sizeof(BitStream)); + } - // Add Data if a write command - if (!read_cmd) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Data, 32,sizeof(BitStream)); + // Add Lock bit 0 + if (!reg_readmode) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, 0, 1,sizeof(BitStream)); + + // Add Data if a write command + if (!read_cmd) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Data, 32,sizeof(BitStream)); + + // Add Address + if (!reg_readmode) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Block, 3,sizeof(BitStream)); + } - // Add Address - if (!reg_readmode) BitStreamLen = T55xx_SetBits (BitStream, BitStreamLen, Block, 3,sizeof(BitStream)); - } - // Send Bits to T55xx // Set up FPGA, 125kHz LFSetupFPGAForADC(95, true); @@ -1420,18 +1420,18 @@ void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { if (downlink_mode == T55xx_DLMode_LLR) T55xxWriteBit (T55xx_LongLeadingReference,Timing); // Send Long Leading Start Reference - if ((downlink_mode == T55xx_DLMode_1of4) && (BitStreamLen > 0)) { // 1 of 4 need to send 2 bits at a time + if ((downlink_mode == T55xx_DLMode_1of4) && (BitStreamLen > 0)) { // 1 of 4 need to send 2 bits at a time for ( i = 0; i < BitStreamLen-1; i+=2 ) { SendBits = (BitStream[BitStream_Byte(i )] >> (BitStream_Bit(i )) & 1) << 1; // Bit i - SendBits += (BitStream[BitStream_Byte(i+1)] >> (BitStream_Bit(i+1)) & 1); // Bit i+1; + SendBits += (BitStream[BitStream_Byte(i+1)] >> (BitStream_Bit(i+1)) & 1); // Bit i+1; T55xxWriteBit (SendBits & 3,Timing); } } else { for (i = 0; i < BitStreamLen; i++) { - SendBits = (BitStream[BitStream_Byte(i)] >> BitStream_Bit(i)); + SendBits = (BitStream[BitStream_Byte(i)] >> BitStream_Bit(i)); T55xxWriteBit (SendBits & 1,Timing); - } + } } } @@ -1439,11 +1439,11 @@ void T55xx_SendCMD (uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { void T55xxResetRead(void) { LED_A_ON(); - // send r* 00 - uint8_t arg = 0x80; // SendCMD will add correct reference mode based on flags (when added). + // send r* 00 + uint8_t arg = 0x80; // SendCMD will add correct reference mode based on flags (when added). - // Add in downlink_mode when ready - // arg |= 0x00; // dlmode << 3 (00 default - 08 leading 0 - 10 Fixed - 18 1 of 4 ) + // Add in downlink_mode when ready + // arg |= 0x00; // dlmode << 3 (00 default - 08 leading 0 - 10 Fixed - 18 1 of 4 ) //clear buffer now so it does not interfere with timing later BigBuf_Clear_keep_EM(); @@ -1474,7 +1474,7 @@ void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { 1xxxxxxx 0x80 reset */ - bool testMode = ((arg & 0x04) == 0x04); + bool testMode = ((arg & 0x04) == 0x04); arg &= (0xff ^ 0x40); // Called for a write, so ensure it is clear/0 LED_A_ON (); @@ -1509,7 +1509,7 @@ void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { } // turn field off FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - + cmd_send(CMD_ACK,0,0,0,0,0); LED_A_OFF (); @@ -1517,7 +1517,7 @@ void T55xxWriteBlock(uint32_t Data, uint32_t Block, uint32_t Pwd, uint8_t arg) { // Read one card block in page [page] void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) {//, struct T55xx_Timing *Timing) { - + LED_A_ON(); /* @@ -1530,11 +1530,11 @@ void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) {//, struct T55 x1xxxxxx 0x40 called for a read, so no data packet 1xxxxxxx 0x80 reset */ - + // Set Read Flag to ensure SendCMD does not add "data" to the packet arg0 |= 0x40; - // RegRead Mode true of block 0xff + // RegRead Mode true of block 0xff if (Block == 0xff) arg0 |= 0x20; //make sure block is at max 7 @@ -1542,7 +1542,7 @@ void T55xxReadBlock (uint16_t arg0, uint8_t Block, uint32_t Pwd) {//, struct T55 //clear buffer now so it does not interfere with timing later BigBuf_Clear_ext(false); - + T55xx_SendCMD (0, Block, Pwd, arg0); //, true); // Turn field on to read the response @@ -1573,13 +1573,13 @@ void T55xxWakeUp(uint32_t Pwd){ x1xxxxxx 0x40 called for a read, so no data packet 1xxxxxxx 0x80 reset */ - - // r* 10 (00) r* for llr , L0 and 1/4 - (00) for L0 and 1/4 - All handled in SendCMD - // So, default Opcode 10 and pwd. - uint8_t arg = 0x01 | 0x40 | 0x20; //Password Read Call no data | reg_read no block - - // Add in downlink_mode when ready - // arg |= 0x00; // dlmode << 3 (00 default - 08 leading 0 - 10 Fixed - 18 1 of 4 ) + + // r* 10 (00) r* for llr , L0 and 1/4 - (00) for L0 and 1/4 - All handled in SendCMD + // So, default Opcode 10 and pwd. + uint8_t arg = 0x01 | 0x40 | 0x20; //Password Read Call no data | reg_read no block + + // Add in downlink_mode when ready + // arg |= 0x00; // dlmode << 3 (00 default - 08 leading 0 - 10 Fixed - 18 1 of 4 ) T55xx_SendCMD (0, 0, Pwd, arg); //, true); @@ -1592,8 +1592,8 @@ void T55xxWakeUp(uint32_t Pwd){ void WriteT55xx(uint32_t *blockdata, uint8_t startblock, uint8_t numblocks) { // write last block first and config block last (if included) for (uint8_t i = numblocks+startblock; i > startblock; i--) { - T55xxWriteBlock(blockdata[i-1],i-1,0,0);//,false); //,&T55xx_Timing_FixedBit); - // T55xx_SendCMD (blockdata[i-1],i-1,0,0);//,false); //,&T55xx_Timing_FixedBit); + T55xxWriteBlock(blockdata[i-1],i-1,0,0);//,false); //,&T55xx_Timing_FixedBit); + //T55xx_SendCMD (blockdata[i-1],i-1,0,0);//,false); //,&T55xx_Timing_FixedBit); } } From 817611f5651d4e99e13f091baf098d8385c69cb8 Mon Sep 17 00:00:00 2001 From: marshmellow42 Date: Thu, 11 Jul 2019 14:31:51 -0400 Subject: [PATCH 113/189] update em4x05 timing (#846) See @mwalker33 issue #838 --- armsrc/lfops.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/armsrc/lfops.c b/armsrc/lfops.c index c9947d97..12f9de08 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1907,7 +1907,7 @@ void SendForward(uint8_t fwd_bit_count) { FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);//field on WaitUS(18*8); //18 cycles on (8us each) - // now start writting + // now start writting - each bit should be 32*8 total length while(fwd_bit_sz-- > 0) { //prepare next bit modulation if(((*fwd_write_ptr++) & 1) == 1) WaitUS(32*8); //32 cycles at 125Khz (8us each) @@ -1916,7 +1916,7 @@ void SendForward(uint8_t fwd_bit_count) { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off WaitUS(23*8); //23 cycles off (8us each) FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);//field on - WaitUS(18*8); //18 cycles on (8us each) + WaitUS((32-23)*8); //remaining cycles on (8us each) } } } From 096dee178438c0a722eaf112c8b63ad4eaa9064a Mon Sep 17 00:00:00 2001 From: t0m4 Date: Sun, 14 Jul 2019 12:31:33 +0200 Subject: [PATCH 114/189] Add 'hf 15 csetuid' command to set UID on ISO15693 Magic tags (#842) --- CHANGELOG.md | 1 + armsrc/appmain.c | 5 +++ armsrc/iso15693.c | 79 +++++++++++++++++++++++++++++++++++++++++ armsrc/iso15693.h | 1 + client/cmdhf15.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++- client/cmdhf15.h | 1 + include/usb_cmd.h | 1 + 7 files changed, 177 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 037bab99..d5cd979d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - `hf 15 sim` now works as expected (piwi) ### Added +- Added `hf 15 csetuid` - set UID on ISO-15693 Magic tags (t0m4) - Added `lf config s xxxx` option to allow skipping x samples before capture (marshmellow) - Added `lf em 4x05protect` to support changing protection blocks on em4x05 chips (marshmellow) - Support Standard Communication Mode in HITAG S diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 5169383e..9b9acb6f 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1158,9 +1158,14 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_READER_ISO_15693: ReaderIso15693(c->arg[0]); break; + case CMD_SIMTAG_ISO_15693: SimTagIso15693(c->arg[0], c->d.asBytes); break; + + case CMD_CSETUID_ISO_15693: + SetTag15693Uid(c->d.asBytes); + break; #endif #ifdef WITH_LEGICRF diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index e3524375..f4120512 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -1591,6 +1591,85 @@ void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint LED_A_OFF(); } +//----------------------------------------------------------------------------- +// Work with "magic Chinese" card. +// +//----------------------------------------------------------------------------- + +// Set the UID to the tag (based on Iceman work). +void SetTag15693Uid(uint8_t *uid) +{ + uint8_t cmd[4][9] = {0x00}; + + uint16_t crc; + + int recvlen = 0; + uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; + + LED_A_ON(); + + // Command 1 : 02213E00000000 + cmd[0][0] = 0x02; + cmd[0][1] = 0x21; + cmd[0][2] = 0x3e; + cmd[0][3] = 0x00; + cmd[0][4] = 0x00; + cmd[0][5] = 0x00; + cmd[0][6] = 0x00; + + // Command 2 : 02213F69960000 + cmd[1][0] = 0x02; + cmd[1][1] = 0x21; + cmd[1][2] = 0x3f; + cmd[1][3] = 0x69; + cmd[1][4] = 0x96; + cmd[1][5] = 0x00; + cmd[1][6] = 0x00; + + // Command 3 : 022138u8u7u6u5 (where uX = uid byte X) + cmd[2][0] = 0x02; + cmd[2][1] = 0x21; + cmd[2][2] = 0x38; + cmd[2][3] = uid[7]; + cmd[2][4] = uid[6]; + cmd[2][5] = uid[5]; + cmd[2][6] = uid[4]; + + // Command 4 : 022139u4u3u2u1 (where uX = uid byte X) + cmd[3][0] = 0x02; + cmd[3][1] = 0x21; + cmd[3][2] = 0x39; + cmd[3][3] = uid[3]; + cmd[3][4] = uid[2]; + cmd[3][5] = uid[1]; + cmd[3][6] = uid[0]; + + for (int i=0; i<4; i++) { + // Add the CRC + crc = Crc(cmd[i], 7); + cmd[i][7] = crc & 0xff; + cmd[i][8] = crc >> 8; + + if (DEBUG) { + Dbprintf("SEND:"); + Dbhexdump(sizeof(cmd[i]), cmd[i], false); + } + + recvlen = SendDataTag(cmd[i], sizeof(cmd[i]), true, 1, recvbuf, sizeof(recvbuf), 0); + + if (DEBUG) { + Dbprintf("RECV:"); + Dbhexdump(recvlen, recvbuf, false); + DbdecodeIso15693Answer(recvlen, recvbuf); + } + + cmd_send(CMD_ACK, recvlen>ISO15693_MAX_RESPONSE_LENGTH?ISO15693_MAX_RESPONSE_LENGTH:recvlen, 0, 0, recvbuf, ISO15693_MAX_RESPONSE_LENGTH); + } + + LED_D_OFF(); + + LED_A_OFF(); +} diff --git a/armsrc/iso15693.h b/armsrc/iso15693.h index e5b78a8a..68df2693 100644 --- a/armsrc/iso15693.h +++ b/armsrc/iso15693.h @@ -19,6 +19,7 @@ void ReaderIso15693(uint32_t parameter); void SimTagIso15693(uint32_t parameter, uint8_t *uid); void BruteforceIso15693Afi(uint32_t speed); void DirectTag15693Command(uint32_t datalen,uint32_t speed, uint32_t recv, uint8_t data[]); +void SetTag15693Uid(uint8_t *uid); void SetDebugIso15693(uint32_t flag); #endif diff --git a/client/cmdhf15.c b/client/cmdhf15.c index 5a7973f6..c2a13354 100644 --- a/client/cmdhf15.c +++ b/client/cmdhf15.c @@ -382,6 +382,7 @@ static command_t CommandTable15[] = {"cmd", CmdHF15Cmd, 0, "Send direct commands to ISO15693 tag"}, {"findafi", CmdHF15Afi, 0, "Brute force AFI of an ISO15693 tag"}, {"dumpmemory", CmdHF15DumpMem, 0, "Read all memory pages of an ISO15693 tag"}, + {"csetuid", CmdHF15CSetUID, 0, "Set UID for magic Chinese card"}, {NULL, NULL, 0, NULL} }; @@ -954,6 +955,92 @@ int CmdHF15CmdWrite(const char *Cmd) { return 0; } +int CmdHF15CSetUID(const char *Cmd) +{ + uint8_t uid[8] = {0x00}; + uint8_t oldUid[8], newUid[8] = {0x00}; + + uint8_t needHelp = 0; + char cmdp = 1; + + if (param_getchar(Cmd, 0) && param_gethex(Cmd, 0, uid, 16)) { + PrintAndLog("UID must include 16 HEX symbols"); + return 1; + } + + if (uid[0] != 0xe0) { + PrintAndLog("UID must begin with the byte 'E0'"); + return 1; + } + + while(param_getchar(Cmd, cmdp) != 0x00) + { + switch(param_getchar(Cmd, cmdp)) + { + case 'h': + case 'H': + needHelp = 1; + break; + default: + PrintAndLog("ERROR: Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + needHelp = 1; + break; + } + cmdp++; + } + + if (strlen(Cmd) < 1 || needHelp) { + PrintAndLog(""); + PrintAndLog("Usage: hf 15 csetuid "); + PrintAndLog("sample: hf 15 csetuid E004013344556677"); + PrintAndLog("Set UID for magic Chinese card (only works with such cards)"); + return 0; + } + + PrintAndLog(""); + PrintAndLog("new UID | %s", sprint_hex(uid, 8)); + PrintAndLog("Using backdoor Magic tag function"); + + if (!getUID(oldUid)) { + PrintAndLog("Can't get old UID."); + return 1; + } + + UsbCommand resp; + uint8_t *recv; + char *hexout; + UsbCommand c = {CMD_CSETUID_ISO_15693, {0, 0, 0}}; + memcpy(c.d.asBytes, uid, 8); + + SendCommand(&c); + + for (int i=0; i<4; i++) { + if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) { + recv = resp.d.asBytes; + PrintAndLog("received %i octets",resp.arg[0]); + hexout = (char *)malloc(resp.arg[0] * 3 + 1); + if (hexout != NULL) { + for (int i = 0; i < resp.arg[0]; i++) { // data in hex + sprintf(&hexout[i * 3], "%02X ", recv[i]); + } + PrintAndLog("%s", hexout); + free(hexout); + } + } else { + PrintAndLog("timeout while waiting for reply."); + } + } + + if (!getUID(newUid)) { + PrintAndLog("Can't get new UID."); + return 1; + } + + PrintAndLog(""); + PrintAndLog("old UID : %02X %02X %02X %02X %02X %02X %02X %02X", oldUid[7], oldUid[6], oldUid[5], oldUid[4], oldUid[3], oldUid[2], oldUid[1], oldUid[0]); + PrintAndLog("new UID : %02X %02X %02X %02X %02X %02X %02X %02X", newUid[7], newUid[6], newUid[5], newUid[4], newUid[3], newUid[2], newUid[1], newUid[0]); + return 0; +} static command_t CommandTable15Cmd[] = @@ -967,7 +1054,8 @@ static command_t CommandTable15Cmd[] = {"write", CmdHF15CmdWrite, 0, "Write a block"}, {"readmulti",CmdHF15CmdReadmulti, 0, "Reads multiple Blocks"}, {"sysinfo",CmdHF15CmdSysinfo, 0, "Get Card Information"}, - {"raw", CmdHF15CmdRaw, 0, "Send raw hex data to tag"}, + {"raw", CmdHF15CmdRaw, 0, "Send raw hex data to tag"}, + {"csetuid", CmdHF15CSetUID, 0, "Set UID for magic Chinese card"}, {"debug", CmdHF15CmdDebug, 0, "Turn debugging on/off"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdhf15.h b/client/cmdhf15.h index d0517fe5..ddaa4f71 100644 --- a/client/cmdhf15.h +++ b/client/cmdhf15.h @@ -22,6 +22,7 @@ int CmdHF15Reader(const char *Cmd); int CmdHF15Sim(const char *Cmd); int CmdHF15Record(const char *Cmd); int CmdHF15Cmd(const char*Cmd); +int CmdHF15CSetUID(const char *Cmd); int CmdHF15CmdHelp(const char*Cmd); int CmdHF15Help(const char*Cmd); diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 82981acf..c998bf94 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -132,6 +132,7 @@ typedef struct{ #define CMD_ISO_15693_FIND_AFI 0x0315 #define CMD_ISO_15693_DEBUG 0x0316 #define CMD_LF_SNOOP_RAW_ADC_SAMPLES 0x0317 +#define CMD_CSETUID_ISO_15693 0x0318 // For Hitag2 transponders #define CMD_SNOOP_HITAG 0x0370 From 88b3dada70ca624a96d188a8590c642b2ff84c78 Mon Sep 17 00:00:00 2001 From: mwalker33 <51802811+mwalker33@users.noreply.github.com> Date: Wed, 24 Jul 2019 04:47:29 +1000 Subject: [PATCH 115/189] Fix Issue #843 - hf mf chk - t Doesnt save to emulator memory --- CHANGELOG.md | 1 + client/cmdhfmf.c | 102 ++++++++++++++++++++++++++++++----------------- 2 files changed, 66 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d5cd979d..e740099a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - AC-Mode decoding for HitagS - Wrong UID at HitagS simulation - `hf 15 sim` now works as expected (piwi) +- 'hf mf chk t` save to emulator memory now works as expeted (mwalker) ### Added - Added `hf 15 csetuid` - set UID on ISO-15693 Magic tags (t0m4) diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index ef48b825..a4461e37 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -1054,7 +1054,7 @@ int CmdHF14AMfChk(const char *Cmd) PrintAndLog("Usage: hf mf chk |<*card memory> [t|d|s|ss] [] []"); PrintAndLog(" * - all sectors"); PrintAndLog("card memory - 0 - MINI(320 bytes), 1 - 1K, 2 - 2K, 4 - 4K, - 1K"); - PrintAndLog("d - write keys to binary file\n"); + PrintAndLog("d - write keys to binary file (not used when supplied)"); PrintAndLog("t - write keys to emulator memory"); PrintAndLog("s - slow execute. timeout 1ms"); PrintAndLog("ss - very slow execute. timeout 5ms"); @@ -1066,27 +1066,27 @@ int CmdHF14AMfChk(const char *Cmd) return 0; } - FILE * f; - char filename[FILE_PATH_SIZE]={0}; - char buf[13]; - uint8_t *keyBlock = NULL, *p; - uint16_t stKeyBlock = 20; - - int i, res; - int keycnt = 0; - char ctmp = 0x00; - int clen = 0; - uint8_t blockNo = 0; - uint8_t SectorsCnt = 0; - uint8_t keyType = 0; - uint64_t key64 = 0; + FILE * f; + char filename[FILE_PATH_SIZE]={0}; + char buf[13]; + uint8_t *keyBlock = NULL, *p; + uint16_t stKeyBlock = 20; + int i, res; + int keycnt = 0; + char ctmp = 0x00; + int clen = 0; + uint8_t blockNo = 0; + uint8_t SectorsCnt = 0; + uint8_t keyType = 0; + uint64_t key64 = 0; // timeout in units. (ms * 106)/10 or us*0.0106 - uint8_t btimeout14a = MF_CHKKEYS_DEFTIMEOUT; // fast by default - bool param3InUse = false; - - bool transferToEml = 0; - bool createDumpFile = 0; - + uint8_t btimeout14a = MF_CHKKEYS_DEFTIMEOUT; // fast by default + bool param3InUse = false; + bool transferToEml = 0; + bool createDumpFile = 0; + bool singleBlock = false; // Flag to ID if a single or multi key check + uint8_t keyFoundCount = 0; // Counter to display the number of keys found/transfered to emulator + sector_t *e_sector = NULL; keyBlock = calloc(stKeyBlock, 6); @@ -1100,8 +1100,17 @@ int CmdHF14AMfChk(const char *Cmd) if (param_getchar(Cmd, 0)=='*') { SectorsCnt = ParamCardSizeSectors(param_getchar(Cmd + 1, 0)); } - else + else { blockNo = param_get8(Cmd, 0); + // Singe Key check, so Set Sector count to cover sectors (1 to sector that contains the block) + // 1 and 2 Cards : Sector = blockNo/4 + 1 + // Sectors 0 - 31 : 4 blocks per sector : Blocks 0 - 127 + // Sectors 32 - 39 : 16 blocks per sector : Blocks 128 - 255 (4K) + if (blockNo < 128) SectorsCnt = (blockNo / 4) + 1; + else SectorsCnt = 32 + ((blockNo-128)/16) + 1; + + singleBlock = true; // Set flag for single key check + } ctmp = param_getchar(Cmd, 1); clen = param_getlength(Cmd, 1); @@ -1122,9 +1131,15 @@ int CmdHF14AMfChk(const char *Cmd) return 1; }; } - + parseParamTDS(Cmd, 2, &transferToEml, &createDumpFile, &btimeout14a); + if (singleBlock & createDumpFile) { + PrintAndLog (" block key check () and write to dump file (d) combination is not supported "); + PrintAndLog (" please remove option d and try again"); + return 1; + } + param3InUse = transferToEml | createDumpFile | (btimeout14a != MF_CHKKEYS_DEFTIMEOUT); PrintAndLog("--chk keys. sectors:%2d, block no:%3d, key type:%c, eml:%c, dmp=%c checktimeout=%d us", @@ -1142,7 +1157,7 @@ int CmdHF14AMfChk(const char *Cmd) keyBlock = p; } PrintAndLog("chk key[%2d] %02x%02x%02x%02x%02x%02x", keycnt, - (keyBlock + 6*keycnt)[0],(keyBlock + 6*keycnt)[1], (keyBlock + 6*keycnt)[2], + (keyBlock + 6*keycnt)[0], (keyBlock + 6*keycnt)[1], (keyBlock + 6*keycnt)[2], (keyBlock + 6*keycnt)[3], (keyBlock + 6*keycnt)[4], (keyBlock + 6*keycnt)[5], 6); keycnt++; } else { @@ -1190,7 +1205,6 @@ int CmdHF14AMfChk(const char *Cmd) PrintAndLog("File: %s: not found or locked.", filename); free(keyBlock); return 1; - } } } @@ -1200,7 +1214,7 @@ int CmdHF14AMfChk(const char *Cmd) PrintAndLog("No key specified, trying default keys"); for (;keycnt < defaultKeysSize; keycnt++) PrintAndLog("chk default key[%2d] %02x%02x%02x%02x%02x%02x", keycnt, - (keyBlock + 6*keycnt)[0],(keyBlock + 6*keycnt)[1], (keyBlock + 6*keycnt)[2], + (keyBlock + 6*keycnt)[0], (keyBlock + 6*keycnt)[1], (keyBlock + 6*keycnt)[2], (keyBlock + 6*keycnt)[3], (keyBlock + 6*keycnt)[4], (keyBlock + 6*keycnt)[5], 6); } @@ -1218,9 +1232,11 @@ int CmdHF14AMfChk(const char *Cmd) } printf("\n"); - bool foundAKey = false; - uint32_t max_keys = keycnt > USB_CMD_DATA_SIZE / 6 ? USB_CMD_DATA_SIZE / 6 : keycnt; - if (SectorsCnt) { + bool foundAKey = false; + uint32_t max_keys = keycnt > USB_CMD_DATA_SIZE / 6 ? USB_CMD_DATA_SIZE / 6 : keycnt; + + // !SingleKey, so all key check (if SectorsCnt > 0) + if (!singleBlock) { PrintAndLog("To cancel this operation press the button on the proxmark..."); printf("--"); for (uint32_t c = 0; c < keycnt; c += max_keys) { @@ -1240,7 +1256,7 @@ int CmdHF14AMfChk(const char *Cmd) PrintAndLog("Command execute timeout"); } } - } else { + } else { int keyAB = keyType; do { for (uint32_t c = 0; c < keycnt; c+=max_keys) { @@ -1249,9 +1265,16 @@ int CmdHF14AMfChk(const char *Cmd) res = mfCheckKeys(blockNo, keyAB & 0x01, true, size, &keyBlock[6 * c], &key64); if (res != 1) { - if (!res) { - PrintAndLog("Found valid key:[%d:%c]%012" PRIx64, blockNo, (keyAB & 0x01)?'B':'A', key64); + if (!res) { + // Use the common format below + // PrintAndLog("Found valid key:[%d:%c]%012" PRIx64, blockNo, (keyAB & 0x01)?'B':'A', key64); foundAKey = true; + + // Store the Single Key for display list + // For a single block check, SectorsCnt = Sector that contains the block + e_sector[SectorsCnt-1].foundKey[(keyAB & 0x01)] = true; // flag key found + e_sector[SectorsCnt-1].Key[(keyAB & 0x01)] = key64; // Save key data + } } else { PrintAndLog("Command execute timeout"); @@ -1268,8 +1291,11 @@ int CmdHF14AMfChk(const char *Cmd) PrintAndLog("|sec|key A |res|key B |res|"); PrintAndLog("|---|----------------|---|----------------|---|"); for (i = 0; i < SectorsCnt; i++) { - PrintAndLog("|%03d| %012" PRIx64 " | %d | %012" PRIx64 " | %d |", i, - e_sector[i].Key[0], e_sector[i].foundKey[0], e_sector[i].Key[1], e_sector[i].foundKey[1]); + // If a block key check, only print a line if a key was found. + if (!singleBlock || (e_sector[i].foundKey[0]) || (e_sector[i].foundKey[1]) ){ + PrintAndLog("|%03d| %012" PRIx64 " | %d | %012" PRIx64 " | %d |", i, + e_sector[i].Key[0], e_sector[i].foundKey[0], e_sector[i].Key[1], e_sector[i].foundKey[1]); + } } PrintAndLog("|---|----------------|---|----------------|---|"); } @@ -1286,15 +1312,17 @@ int CmdHF14AMfChk(const char *Cmd) for (uint16_t t = 0; t < 2; t++) { if (e_sector[sectorNo].foundKey[t]) { num_to_bytes(e_sector[sectorNo].Key[t], 6, block + t * 10); + keyFoundCount++; // Key found count for information } } mfEmlSetMem(block, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1); } } - PrintAndLog("Found keys have been transferred to the emulator memory"); + // Updated to show the actual number of keys found/transfered. + PrintAndLog("%d keys(s) found have been transferred to the emulator memory",keyFoundCount); } - if (createDumpFile) { + if (createDumpFile && !singleBlock) { FILE *fkeys = fopen("dumpkeys.bin","wb"); if (fkeys == NULL) { PrintAndLog("Could not create file dumpkeys.bin"); @@ -1312,7 +1340,7 @@ int CmdHF14AMfChk(const char *Cmd) fclose(fkeys); PrintAndLog("Found keys have been dumped to file dumpkeys.bin. 0xffffffffffff has been inserted for unknown keys."); } - + free(e_sector); free(keyBlock); PrintAndLog(""); From 3a5ffba7c13354c0ad9ba48c8b97ee39ea46a1ba Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Thu, 1 Aug 2019 10:53:26 -0400 Subject: [PATCH 116/189] Implement Originality Signature Check in 'hf mfu info' * add support for elliptic curve 'secp128r1' to mbedtls library * change ecdsa_signature_verify() to allow different curves, signature lengths, and skipping hash * add another public key for Mifare Ultralight EV1 --- CHANGELOG.md | 1 + client/cmdhffido.c | 8 +- client/cmdhfmfu.c | 42 +++-- client/crypto/libpcrypto.c | 299 ++++++++++++++++++++-------------- client/crypto/libpcrypto.h | 9 +- client/fido/fidocore.c | 6 +- common/mbedtls/check_config.h | 1 + common/mbedtls/config.h | 1 + common/mbedtls/ecdsa.c | 2 +- common/mbedtls/ecdsa.h | 2 + common/mbedtls/ecp.c | 30 ++-- common/mbedtls/ecp.h | 1 + common/mbedtls/ecp_curves.c | 41 +++++ 13 files changed, 278 insertions(+), 165 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e740099a..a764787b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added Home (Pos1) and End key bindings to the plot GUI (based on @mcd1992) - Added downlink reference mode option r [ 0 - (or missing) default/fixed bit, 1 - long leading, 2 - leading 0 and 3 - 1 of 4 ] to `lf t55xx detect`, `lf t55xx read`, `lf t55xx write`, and `lf t55xx bruteforce` - Added special option `r 4` to bruteforce, to try all downlink modes (0,1,2 and 3) for each password +- `hf mfu info` now checks the NXP Originality Signature if availabe (piwi) ## [v3.1.0][2018-10-10] diff --git a/client/cmdhffido.c b/client/cmdhffido.c index 8a98cf19..25862445 100644 --- a/client/cmdhffido.c +++ b/client/cmdhffido.c @@ -353,9 +353,9 @@ int CmdHFFidoRegister(const char *cmd) { &buf[1], 65, // user public key NULL, 0); //PrintAndLog("--xbuf(%d)[%d]: %s", res, xbuflen, sprint_hex(xbuf, xbuflen)); - res = ecdsa_signature_verify(public_key, xbuf, xbuflen, &buf[hashp], len - hashp); + res = ecdsa_signature_verify(MBEDTLS_ECP_DP_SECP256R1, public_key, xbuf, xbuflen, &buf[hashp], len - hashp, true); if (res) { - if (res == -0x4e00) { + if (res == MBEDTLS_ERR_ECP_VERIFY_FAILED) { PrintAndLog("Signature is NOT VALID."); } else { PrintAndLog("Other signature check error: %x %s", (res<0)?-res:res, ecdsa_get_error(res)); @@ -579,9 +579,9 @@ int CmdHFFidoAuthenticate(const char *cmd) { data, 32, // challenge parameter NULL, 0); //PrintAndLog("--xbuf(%d)[%d]: %s", res, xbuflen, sprint_hex(xbuf, xbuflen)); - res = ecdsa_signature_verify(public_key, xbuf, xbuflen, &buf[5], len - 5); + res = ecdsa_signature_verify(MBEDTLS_ECP_DP_SECP256R1, public_key, xbuf, xbuflen, &buf[5], len - 5, true); if (res) { - if (res == -0x4e00) { + if (res == MBEDTLS_ERR_ECP_VERIFY_FAILED) { PrintAndLog("Signature is NOT VALID."); } else { PrintAndLog("Other signature check error: %x %s", (res<0)?-res:res, ecdsa_get_error(res)); diff --git a/client/cmdhfmfu.c b/client/cmdhfmfu.c index 89e58263..39a00d63 100644 --- a/client/cmdhfmfu.c +++ b/client/cmdhfmfu.c @@ -24,6 +24,7 @@ #include "util_posix.h" #include "protocols.h" #include "taginfo.h" +#include "crypto/libpcrypto.h" typedef enum TAGTYPE_UL { UNKNOWN = 0x000000, @@ -65,15 +66,6 @@ typedef enum TAGTYPE_UL { #define MAX_MY_D_MOVE 0x25 #define MAX_MY_D_MOVE_LEAN 0x0f -#define PUBLIC_ECDA_KEYLEN 33 -static uint8_t public_ecda_key[PUBLIC_ECDA_KEYLEN] = { - 0x04, 0x49, 0x4e, 0x1a, 0x38, 0x6d, 0x3d, 0x3c, - 0xfe, 0x3d, 0xc1, 0x0e, 0x5d, 0xe6, 0x8a, 0x49, - 0x9b, 0x1c, 0x20, 0x2d, 0xb5, 0xb1, 0x32, 0x39, - 0x3e, 0x89, 0xed, 0x19, 0xfe, 0x5b, 0xe8, 0xbc, - 0x61 -}; - #define KEYS_3DES_COUNT 7 static uint8_t default_3des_keys[KEYS_3DES_COUNT][16] = { { 0x42,0x52,0x45,0x41,0x4b,0x4d,0x45,0x49,0x46,0x59,0x4f,0x55,0x43,0x41,0x4e,0x21 },// 3des std key @@ -95,6 +87,13 @@ static uint8_t default_pwd_pack[KEYS_PWD_COUNT][4] = { {0x35,0x1C,0xD0,0x19}, // PACK 0x9A,0x5a -- italian bus (sniffed) }; +// known public keys for the originality check (source: https://github.com/alexbatalov/node-nxp-originality-verifier) +uint8_t public_keys[2][33] = {{0x04,0x49,0x4e,0x1a,0x38,0x6d,0x3d,0x3c,0xfe,0x3d,0xc1,0x0e,0x5d,0xe6,0x8a,0x49,0x9b, // UL and NDEF + 0x1c,0x20,0x2d,0xb5,0xb1,0x32,0x39,0x3e,0x89,0xed,0x19,0xfe,0x5b,0xe8,0xbc,0x61}, + {0x04,0x90,0x93,0x3b,0xdc,0xd6,0xe9,0x9b,0x4e,0x25,0x5e,0x3d,0xa5,0x53,0x89,0xa8,0x27, // UL EV1 + 0x56,0x4e,0x11,0x71,0x8e,0x01,0x72,0x92,0xfa,0xf2,0x32,0x26,0xa9,0x66,0x14,0xb8} +}; + #define MAX_UL_TYPES 17 static uint32_t UL_TYPES_ARRAY[MAX_UL_TYPES] = {UNKNOWN, UL, UL_C, UL_EV1_48, UL_EV1_128, NTAG, NTAG_203, NTAG_210, NTAG_212, NTAG_213, NTAG_215, NTAG_216, MY_D, MY_D_NFC, MY_D_MOVE, MY_D_MOVE_LEAN, FUDAN_UL}; @@ -552,14 +551,20 @@ static int ulev1_print_counters(void) { } -static int ulev1_print_signature( uint8_t *data, uint8_t len){ - PrintAndLogEx(NORMAL, "\n--- Tag Signature"); - PrintAndLogEx(NORMAL, "IC signature public key name : NXP NTAG21x (2013)"); - PrintAndLogEx(NORMAL, "IC signature public key value : %s", sprint_hex(public_ecda_key, PUBLIC_ECDA_KEYLEN)); +static int ulev1_print_signature(TagTypeUL_t tagtype, uint8_t *uid, uint8_t *signature, size_t signature_len){ + uint8_t public_key = 0; + if (tagtype == UL_EV1_48 || tagtype == UL_EV1_128) { + public_key = 1; + } + int res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, public_keys[public_key], uid, 7, signature, signature_len, false); + bool signature_valid = (res == 0); + + PrintAndLogEx(NORMAL, "\n--- Tag Originality Signature"); + //PrintAndLogEx(NORMAL, "IC signature public key name : NXP NTAG21x 2013"); // don't know if there is other NXP public keys.. :( + PrintAndLogEx(NORMAL, " Signature public key : %s", sprint_hex(public_keys[public_key]+1, sizeof(public_keys[public_key])-1)); PrintAndLogEx(NORMAL, " Elliptic curve parameters : secp128r1"); - PrintAndLogEx(NORMAL, " Tag ECC Signature : %s", sprint_hex(data, len)); - //to do: verify if signature is valid - //PrintAndLogEx(NORMAL, "IC signature status: %s valid", (iseccvalid() )?"":"not"); + PrintAndLogEx(NORMAL, " Tag ECC Signature : %s", sprint_hex(signature, signature_len)); + PrintAndLogEx(NORMAL, " Originality signature check : signature is %svalid", signature_valid?"":"NOT "); return 0; } @@ -725,6 +730,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) { uint8_t authlim = 0xff; iso14a_card_select_t card; + uint8_t uid[7]; bool errors = false; uint8_t keybytes[16] = {0x00}; uint8_t *authenticationkey = keybytes; @@ -798,6 +804,8 @@ static int CmdHF14AMfUInfo(const char *Cmd) { PrintAndLogEx(WARNING, "Error: tag didn't answer to READ"); return -1; } else if (len == 16) { + memcpy(uid, data, 3); + memcpy(uid+3, data+4, 4); ul_print_default(data); ndef_print_CC(data+12); } else { @@ -878,7 +886,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) { return -1; } if (len == 32) { - ulev1_print_signature( ulev1_signature, sizeof(ulev1_signature)); + ulev1_print_signature(tagtype, uid, ulev1_signature, sizeof(ulev1_signature)); } else { // re-select if (!ul_auth_select( &card, tagtype, hasAuthKey, authenticationkey, pack, sizeof(pack))) { diff --git a/client/crypto/libpcrypto.c b/client/crypto/libpcrypto.c index ebc1e987..b20961d8 100644 --- a/client/crypto/libpcrypto.c +++ b/client/crypto/libpcrypto.c @@ -26,12 +26,13 @@ #include #include + // NIST Special Publication 800-38A — Recommendation for block cipher modes of operation: methods and techniques, 2001. int aes_encode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length){ uint8_t iiv[16] = {0}; if (iv) memcpy(iiv, iv, 16); - + mbedtls_aes_context aes; mbedtls_aes_init(&aes); if (mbedtls_aes_setkey_enc(&aes, key, 128)) @@ -43,11 +44,12 @@ int aes_encode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int l return 0; } + int aes_decode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length){ uint8_t iiv[16] = {0}; if (iv) memcpy(iiv, iv, 16); - + mbedtls_aes_context aes; mbedtls_aes_init(&aes); if (mbedtls_aes_setkey_dec(&aes, key, 128)) @@ -59,164 +61,176 @@ int aes_decode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int l return 0; } + // NIST Special Publication 800-38B — Recommendation for block cipher modes of operation: The CMAC mode for authentication. // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/AES_CMAC.pdf int aes_cmac(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, int length) { memset(mac, 0x00, 16); - - // NIST 800-38B + + // NIST 800-38B return mbedtls_aes_cmac_prf_128(key, MBEDTLS_AES_BLOCK_SIZE, input, length, mac); } + int aes_cmac8(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, int length) { uint8_t cmac[16] = {0}; memset(mac, 0x00, 8); - + int res = aes_cmac(iv, key, input, cmac, length); if (res) return res; - - for(int i = 0; i < 8; i++) + + for(int i = 0; i < 8; i++) mac[i] = cmac[i * 2 + 1]; return 0; } + static uint8_t fixed_rand_value[250] = {0}; + static int fixed_rand(void *rng_state, unsigned char *output, size_t len) { if (len <= 250) { memcpy(output, fixed_rand_value, len); } else { memset(output, 0x00, len); } - + return 0; } + int sha256hash(uint8_t *input, int length, uint8_t *hash) { if (!hash || !input) return 1; - + mbedtls_sha256_context sctx; mbedtls_sha256_init(&sctx); - mbedtls_sha256_starts(&sctx, 0); // SHA-256, not 224 + mbedtls_sha256_starts(&sctx, 0); // SHA-256, not 224 mbedtls_sha256_update(&sctx, input, length); - mbedtls_sha256_finish(&sctx, hash); + mbedtls_sha256_finish(&sctx, hash); mbedtls_sha256_free(&sctx); - + return 0; } + int sha512hash(uint8_t *input, int length, uint8_t *hash) { if (!hash || !input) return 1; - + mbedtls_sha512_context sctx; mbedtls_sha512_init(&sctx); mbedtls_sha512_starts(&sctx, 0); //SHA-512, not 384 mbedtls_sha512_update(&sctx, input, length); - mbedtls_sha512_finish(&sctx, hash); + mbedtls_sha512_finish(&sctx, hash); mbedtls_sha512_free(&sctx); - + return 0; } -int ecdsa_init_str(mbedtls_ecdsa_context *ctx, char * key_d, char *key_x, char *key_y) { + +int ecdsa_init_str(mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id curveID, char *key_d, char *key_x, char *key_y) { if (!ctx) return 1; - + int res; mbedtls_ecdsa_init(ctx); - res = mbedtls_ecp_group_load(&ctx->grp, MBEDTLS_ECP_DP_SECP256R1); // secp256r1 - if (res) + res = mbedtls_ecp_group_load(&ctx->grp, curveID); + if (res) return res; - + if (key_d) { res = mbedtls_mpi_read_string(&ctx->d, 16, key_d); - if (res) + if (res) return res; } - + if (key_x && key_y) { res = mbedtls_ecp_point_read_string(&ctx->Q, 16, key_x, key_y); - if (res) + if (res) return res; } - + return 0; } -int ecdsa_init(mbedtls_ecdsa_context *ctx, uint8_t * key_d, uint8_t *key_xy) { + +int ecdsa_init(mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id curveID, uint8_t *key_d, uint8_t *key_xy) { if (!ctx) return 1; - + int res; mbedtls_ecdsa_init(ctx); - res = mbedtls_ecp_group_load(&ctx->grp, MBEDTLS_ECP_DP_SECP256R1); // secp256r1 - if (res) + res = mbedtls_ecp_group_load(&ctx->grp, curveID); + if (res) return res; - + + size_t keylen = (ctx->grp.nbits + 7 ) / 8; if (key_d) { - res = mbedtls_mpi_read_binary(&ctx->d, key_d, 32); - if (res) + res = mbedtls_mpi_read_binary(&ctx->d, key_d, keylen); + if (res) return res; } - + if (key_xy) { - res = mbedtls_ecp_point_read_binary(&ctx->grp, &ctx->Q, key_xy, 32 * 2 + 1); - if (res) + res = mbedtls_ecp_point_read_binary(&ctx->grp, &ctx->Q, key_xy, keylen * 2 + 1); + if (res) return res; } - + return 0; } -int ecdsa_key_create(uint8_t * key_d, uint8_t *key_xy) { + +int ecdsa_key_create(mbedtls_ecp_group_id curveID, uint8_t *key_d, uint8_t *key_xy) { int res; mbedtls_ecdsa_context ctx; - ecdsa_init(&ctx, NULL, NULL); + ecdsa_init(&ctx, curveID, NULL, NULL); - mbedtls_entropy_context entropy; - mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; const char *pers = "ecdsaproxmark"; - mbedtls_entropy_init(&entropy); - mbedtls_ctr_drbg_init(&ctr_drbg); + mbedtls_entropy_init(&entropy); + mbedtls_ctr_drbg_init(&ctr_drbg); - res = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)pers, strlen(pers)); - if (res) - goto exit; - - res = mbedtls_ecdsa_genkey(&ctx, MBEDTLS_ECP_DP_SECP256R1, mbedtls_ctr_drbg_random, &ctr_drbg); + res = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)pers, strlen(pers)); if (res) goto exit; - res = mbedtls_mpi_write_binary(&ctx.d, key_d, 32); + res = mbedtls_ecdsa_genkey(&ctx, curveID, mbedtls_ctr_drbg_random, &ctr_drbg); if (res) goto exit; - size_t keylen = 0; + size_t keylen = (ctx.grp.nbits + 7) / 8; + res = mbedtls_mpi_write_binary(&ctx.d, key_d, keylen); + if (res) + goto exit; + + size_t public_keylen = 0; uint8_t public_key[200] = {0}; - res = mbedtls_ecp_point_write_binary(&ctx.grp, &ctx.Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &keylen, public_key, sizeof(public_key)); + res = mbedtls_ecp_point_write_binary(&ctx.grp, &ctx.Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &public_keylen, public_key, sizeof(public_key)); if (res) goto exit; - - if (keylen != 65) { // 0x04 + + if (public_keylen != 1 + 2 * keylen) { // 0x04 res = 1; goto exit; } - memcpy(key_xy, public_key, 65); + memcpy(key_xy, public_key, public_keylen); exit: - mbedtls_entropy_free(&entropy); - mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + mbedtls_ctr_drbg_free(&ctr_drbg); mbedtls_ecdsa_free(&ctx); return res; } + char *ecdsa_get_error(int ret) { static char retstr[300]; memset(retstr, 0x00, sizeof(retstr)); @@ -224,111 +238,149 @@ char *ecdsa_get_error(int ret) { return retstr; } -int ecdsa_public_key_from_pk(mbedtls_pk_context *pk, uint8_t *key, size_t keylen) { + +int ecdsa_public_key_from_pk(mbedtls_pk_context *pk, mbedtls_ecp_group_id curveID, uint8_t *key, size_t keylen) { int res = 0; size_t realkeylen = 0; - if (keylen < 65) - return 1; - + mbedtls_ecdsa_context ctx; mbedtls_ecdsa_init(&ctx); - - res = mbedtls_ecp_group_load(&ctx.grp, MBEDTLS_ECP_DP_SECP256R1); // secp256r1 + + res = mbedtls_ecp_group_load(&ctx.grp, curveID); if (res) goto exit; - + + size_t private_keylen = (ctx.grp.nbits + 7) / 8; + if (keylen < 1 + 2 * private_keylen) { + res = 1; + goto exit; + } + res = mbedtls_ecdsa_from_keypair(&ctx, mbedtls_pk_ec(*pk) ); if (res) goto exit; - + res = mbedtls_ecp_point_write_binary(&ctx.grp, &ctx.Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &realkeylen, key, keylen); - if (realkeylen != 65) + if (realkeylen != 1 + 2 * private_keylen) res = 2; exit: mbedtls_ecdsa_free(&ctx); return res; } -int ecdsa_signature_create(uint8_t *key_d, uint8_t *key_xy, uint8_t *input, int length, uint8_t *signature, size_t *signaturelen) { + +int ecdsa_signature_create(mbedtls_ecp_group_id curveID, uint8_t *key_d, uint8_t *key_xy, uint8_t *input, int length, uint8_t *signature, size_t *signaturelen, bool hash) { int res; *signaturelen = 0; - - uint8_t shahash[32] = {0}; + + uint8_t shahash[32] = {0}; res = sha256hash(input, length, shahash); if (res) return res; - mbedtls_entropy_context entropy; - mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; const char *pers = "ecdsaproxmark"; - mbedtls_entropy_init(&entropy); - mbedtls_ctr_drbg_init(&ctr_drbg); + mbedtls_entropy_init(&entropy); + mbedtls_ctr_drbg_init(&ctr_drbg); - res = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)pers, strlen(pers)); + res = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)pers, strlen(pers)); if (res) - goto exit; + goto exit; + + mbedtls_ecdsa_context ctx; + ecdsa_init(&ctx, curveID, key_d, key_xy); + res = mbedtls_ecdsa_write_signature(&ctx, MBEDTLS_MD_SHA256, hash?shahash:input, hash?sizeof(shahash):length, signature, signaturelen, mbedtls_ctr_drbg_random, &ctr_drbg); - mbedtls_ecdsa_context ctx; - ecdsa_init(&ctx, key_d, key_xy); - res = mbedtls_ecdsa_write_signature(&ctx, MBEDTLS_MD_SHA256, shahash, sizeof(shahash), signature, signaturelen, mbedtls_ctr_drbg_random, &ctr_drbg); - exit: - mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_ctr_drbg_free(&ctr_drbg); mbedtls_ecdsa_free(&ctx); return res; } -int ecdsa_signature_create_test(char * key_d, char *key_x, char *key_y, char *random, uint8_t *input, int length, uint8_t *signature, size_t *signaturelen) { + +int ecdsa_signature_create_test(mbedtls_ecp_group_id curveID, char *key_d, char *key_x, char *key_y, char *random, uint8_t *input, int length, uint8_t *signature, size_t *signaturelen) { int res; *signaturelen = 0; - - uint8_t shahash[32] = {0}; + + uint8_t shahash[32] = {0}; res = sha256hash(input, length, shahash); if (res) return res; int rndlen = 0; param_gethex_to_eol(random, 0, fixed_rand_value, sizeof(fixed_rand_value), &rndlen); - - mbedtls_ecdsa_context ctx; - ecdsa_init_str(&ctx, key_d, key_x, key_y); + + mbedtls_ecdsa_context ctx; + ecdsa_init_str(&ctx, curveID, key_d, key_x, key_y); res = mbedtls_ecdsa_write_signature(&ctx, MBEDTLS_MD_SHA256, shahash, sizeof(shahash), signature, signaturelen, fixed_rand, NULL); - + mbedtls_ecdsa_free(&ctx); return res; } -int ecdsa_signature_verify_keystr(char *key_x, char *key_y, uint8_t *input, int length, uint8_t *signature, size_t signaturelen) { + +int ecdsa_signature_verify_keystr(mbedtls_ecp_group_id curveID, char *key_x, char *key_y, uint8_t *input, int length, uint8_t *signature, size_t signaturelen, bool hash) { int res; - uint8_t shahash[32] = {0}; + uint8_t shahash[32] = {0}; res = sha256hash(input, length, shahash); if (res) return res; - mbedtls_ecdsa_context ctx; - ecdsa_init_str(&ctx, NULL, key_x, key_y); - res = mbedtls_ecdsa_read_signature(&ctx, shahash, sizeof(shahash), signature, signaturelen); - + mbedtls_ecdsa_context ctx; + ecdsa_init_str(&ctx, curveID, NULL, key_x, key_y); + res = mbedtls_ecdsa_read_signature(&ctx, hash?shahash:input, hash?sizeof(shahash):length, signature, signaturelen); + mbedtls_ecdsa_free(&ctx); return res; } -int ecdsa_signature_verify(uint8_t *key_xy, uint8_t *input, int length, uint8_t *signature, size_t signaturelen) { + +int ecdsa_signature_verify(mbedtls_ecp_group_id curveID, uint8_t *key_xy, uint8_t *input, int length, uint8_t *signature, size_t signaturelen, bool hash) { int res; - uint8_t shahash[32] = {0}; - res = sha256hash(input, length, shahash); - if (res) - return res; + uint8_t shahash[32] = {0}; + if (hash) { + res = sha256hash(input, length, shahash); + if (res) + return res; + } + + mbedtls_ecdsa_context ctx; + res = ecdsa_init(&ctx, curveID, NULL, key_xy); + res = mbedtls_ecdsa_read_signature(&ctx, hash?shahash:input, hash?sizeof(shahash):length, signature, signaturelen); - mbedtls_ecdsa_context ctx; - ecdsa_init(&ctx, NULL, key_xy); - res = mbedtls_ecdsa_read_signature(&ctx, shahash, sizeof(shahash), signature, signaturelen); - mbedtls_ecdsa_free(&ctx); return res; } + +int ecdsa_signature_r_s_verify(mbedtls_ecp_group_id curveID, uint8_t *key_xy, uint8_t *input, int length, uint8_t *r_s, size_t r_s_len, bool hash) { + int res; + uint8_t signature[MBEDTLS_ECDSA_MAX_LEN]; + size_t signature_len; + + // convert r & s to ASN.1 signature + mbedtls_mpi r, s; + mbedtls_mpi_init(&r); + mbedtls_mpi_init(&s); + mbedtls_mpi_read_binary(&r, r_s, r_s_len/2); + mbedtls_mpi_read_binary(&s, r_s + r_s_len/2, r_s_len/2); + + res = ecdsa_signature_to_asn1(&r, &s, signature, &signature_len); + if (res < 0) { + return res; + } + + res = ecdsa_signature_verify(curveID, key_xy, input, length, signature, signature_len, hash); + + mbedtls_mpi_free(&r); + mbedtls_mpi_free(&s); + + return res; +} + + #define T_PRIVATE_KEY "C477F9F65C22CCE20657FAA5B2D1D8122336F851A508A1ED04E479C34985BF96" #define T_Q_X "B7E08AFDFE94BAD3F1DC8C734798BA1C62B3A0AD1E9EA2A38201CD0889BC7A19" #define T_Q_Y "3603F747959DBF7A4BB226E41928729063ADC7AE43529E61B563BBC606CC5E09" @@ -339,45 +391,46 @@ int ecdsa_signature_verify(uint8_t *key_xy, uint8_t *input, int length, uint8_t int ecdsa_nist_test(bool verbose) { int res; uint8_t input[] = "Example of ECDSA with P-256"; + mbedtls_ecp_group_id curveID = MBEDTLS_ECP_DP_SECP256R1; int length = strlen((char *)input); - uint8_t signature[300] = {0}; - size_t siglen = 0; + uint8_t signature[300] = {0}; + size_t siglen = 0; // NIST ecdsa test if (verbose) printf(" ECDSA NIST test: "); // make signature - res = ecdsa_signature_create_test(T_PRIVATE_KEY, T_Q_X, T_Q_Y, T_K, input, length, signature, &siglen); + res = ecdsa_signature_create_test(curveID, T_PRIVATE_KEY, T_Q_X, T_Q_Y, T_K, input, length, signature, &siglen); // printf("res: %x signature[%x]: %s\n", (res<0)?-res:res, siglen, sprint_hex(signature, siglen)); - if (res) + if (res) goto exit; // check vectors - uint8_t rval[300] = {0}; - uint8_t sval[300] = {0}; + uint8_t rval[300] = {0}; + uint8_t sval[300] = {0}; res = ecdsa_asn1_get_signature(signature, siglen, rval, sval); if (res) goto exit; - + int slen = 0; uint8_t rval_s[33] = {0}; param_gethex_to_eol(T_R, 0, rval_s, sizeof(rval_s), &slen); - uint8_t sval_s[33] = {0}; + uint8_t sval_s[33] = {0}; param_gethex_to_eol(T_S, 0, sval_s, sizeof(sval_s), &slen); if (strncmp((char *)rval, (char *)rval_s, 32) || strncmp((char *)sval, (char *)sval_s, 32)) { printf("R or S check error\n"); res = 100; goto exit; } - + // verify signature - res = ecdsa_signature_verify_keystr(T_Q_X, T_Q_Y, input, length, signature, siglen); - if (res) + res = ecdsa_signature_verify_keystr(curveID, T_Q_X, T_Q_Y, input, length, signature, siglen, true); + if (res) goto exit; - + // verify wrong signature input[0] ^= 0xFF; - res = ecdsa_signature_verify_keystr(T_Q_X, T_Q_Y, input, length, signature, siglen); + res = ecdsa_signature_verify_keystr(curveID, T_Q_X, T_Q_Y, input, length, signature, siglen, true); if (!res) { res = 1; goto exit; @@ -393,27 +446,27 @@ int ecdsa_nist_test(bool verbose) { uint8_t key_xy[32 * 2 + 2] = {0}; memset(signature, 0x00, sizeof(signature)); siglen = 0; - - res = ecdsa_key_create(key_d, key_xy); - if (res) + + res = ecdsa_key_create(curveID, key_d, key_xy); + if (res) goto exit; - res = ecdsa_signature_create(key_d, key_xy, input, length, signature, &siglen); - if (res) + res = ecdsa_signature_create(curveID, key_d, key_xy, input, length, signature, &siglen, true); + if (res) goto exit; - res = ecdsa_signature_verify(key_xy, input, length, signature, siglen); - if (res) + res = ecdsa_signature_verify(curveID, key_xy, input, length, signature, siglen, true); + if (res) goto exit; input[0] ^= 0xFF; - res = ecdsa_signature_verify(key_xy, input, length, signature, siglen); - if (!res) + res = ecdsa_signature_verify(curveID, key_xy, input, length, signature, siglen, true); + if (!res) goto exit; - + if (verbose) printf("passed\n\n"); - + return 0; exit: if (verbose) diff --git a/client/crypto/libpcrypto.h b/client/crypto/libpcrypto.h index 7e70cbfc..e29f92b4 100644 --- a/client/crypto/libpcrypto.h +++ b/client/crypto/libpcrypto.h @@ -24,10 +24,11 @@ extern int aes_cmac8(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, in extern int sha256hash(uint8_t *input, int length, uint8_t *hash); extern int sha512hash(uint8_t *input, int length, uint8_t *hash); -extern int ecdsa_key_create(uint8_t * key_d, uint8_t *key_xy); -extern int ecdsa_public_key_from_pk(mbedtls_pk_context *pk, uint8_t *key, size_t keylen); -extern int ecdsa_signature_create(uint8_t *key_d, uint8_t *key_xy, uint8_t *input, int length, uint8_t *signature, size_t *signaturelen); -extern int ecdsa_signature_verify(uint8_t *key_xy, uint8_t *input, int length, uint8_t *signature, size_t signaturelen); +extern int ecdsa_key_create(mbedtls_ecp_group_id curveID, uint8_t * key_d, uint8_t *key_xy); +extern int ecdsa_public_key_from_pk(mbedtls_pk_context *pk, mbedtls_ecp_group_id curveID, uint8_t *key, size_t keylen); +extern int ecdsa_signature_create(mbedtls_ecp_group_id curveID, uint8_t *key_d, uint8_t *key_xy, uint8_t *input, int length, uint8_t *signature, size_t *signaturelen, bool hash); +extern int ecdsa_signature_verify(mbedtls_ecp_group_id curveID, uint8_t *key_xy, uint8_t *input, int length, uint8_t *signature, size_t signaturelen, bool hash); +extern int ecdsa_signature_r_s_verify(mbedtls_ecp_group_id curveID, uint8_t *key_xy, uint8_t *input, int length, uint8_t *r_s, size_t r_s_len, bool hash); extern char *ecdsa_get_error(int ret); extern int ecdsa_nist_test(bool verbose); diff --git a/client/fido/fidocore.c b/client/fido/fidocore.c index 6e021ea6..6af7671a 100644 --- a/client/fido/fidocore.c +++ b/client/fido/fidocore.c @@ -279,7 +279,7 @@ int FIDOCheckDERAndGetKey(uint8_t *der, size_t derLen, bool verbose, uint8_t *pu } // get public key - res = ecdsa_public_key_from_pk(&cert.pk, publicKey, publicKeyMaxLen); + res = ecdsa_public_key_from_pk(&cert.pk, MBEDTLS_ECP_DP_SECP256R1, publicKey, publicKeyMaxLen); if (res) { PrintAndLog("ERROR: getting public key from certificate 0x%x - %s", (res<0)?-res:res, ecdsa_get_error(res)); } else { @@ -396,9 +396,9 @@ int FIDO2CheckSignature(json_t *root, uint8_t *publickey, uint8_t *sign, size_t clientDataHash, 32, // Hash of the serialized client data. "$.ClientDataHash" from json NULL, 0); //PrintAndLog("--xbuf(%d)[%d]: %s", res, xbuflen, sprint_hex(xbuf, xbuflen)); - res = ecdsa_signature_verify(publickey, xbuf, xbuflen, sign, signLen); + res = ecdsa_signature_verify(MBEDTLS_ECP_DP_SECP256R1, publickey, xbuf, xbuflen, sign, signLen, true); if (res) { - if (res == -0x4e00) { + if (res == MBEDTLS_ERR_ECP_VERIFY_FAILED) { PrintAndLog("Signature is NOT VALID."); } else { PrintAndLog("Other signature check error: %x %s", (res<0)?-res:res, ecdsa_get_error(res)); diff --git a/common/mbedtls/check_config.h b/common/mbedtls/check_config.h index a4fa7bdd..b395844d 100644 --- a/common/mbedtls/check_config.h +++ b/common/mbedtls/check_config.h @@ -115,6 +115,7 @@ #endif #if defined(MBEDTLS_ECP_C) && ( !defined(MBEDTLS_BIGNUM_C) || ( \ + !defined(MBEDTLS_ECP_DP_SECP128R1_ENABLED) && \ !defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) && \ !defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) && \ !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) && \ diff --git a/common/mbedtls/config.h b/common/mbedtls/config.h index dfda7ca4..278b2163 100644 --- a/common/mbedtls/config.h +++ b/common/mbedtls/config.h @@ -645,6 +645,7 @@ * * Comment macros to disable the curve and functions for it */ +#define MBEDTLS_ECP_DP_SECP128R1_ENABLED #define MBEDTLS_ECP_DP_SECP192R1_ENABLED #define MBEDTLS_ECP_DP_SECP224R1_ENABLED #define MBEDTLS_ECP_DP_SECP256R1_ENABLED diff --git a/common/mbedtls/ecdsa.c b/common/mbedtls/ecdsa.c index e97e6cb4..1145bcc2 100644 --- a/common/mbedtls/ecdsa.c +++ b/common/mbedtls/ecdsa.c @@ -291,7 +291,7 @@ cleanup: /* * Convert a signature (given by context) to ASN.1 */ -static int ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s, +int ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s, unsigned char *sig, size_t *slen ) { int ret; diff --git a/common/mbedtls/ecdsa.h b/common/mbedtls/ecdsa.h index a56cc0a5..426a19cd 100644 --- a/common/mbedtls/ecdsa.h +++ b/common/mbedtls/ecdsa.h @@ -334,6 +334,8 @@ void mbedtls_ecdsa_init( mbedtls_ecdsa_context *ctx ); */ void mbedtls_ecdsa_free( mbedtls_ecdsa_context *ctx ); +int ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s, unsigned char *sig, size_t *slen ); + #ifdef __cplusplus } #endif diff --git a/common/mbedtls/ecp.c b/common/mbedtls/ecp.c index 028c7fe3..925c024c 100644 --- a/common/mbedtls/ecp.c +++ b/common/mbedtls/ecp.c @@ -84,7 +84,8 @@ static unsigned long add_count, dbl_count, mul_count; #endif -#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) || \ +#if defined(MBEDTLS_ECP_DP_SECP128R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) || \ defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) || \ defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \ defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) || \ @@ -128,39 +129,42 @@ typedef enum static const mbedtls_ecp_curve_info ecp_supported_curves[] = { #if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) - { MBEDTLS_ECP_DP_SECP521R1, 25, 521, "secp521r1" }, + { MBEDTLS_ECP_DP_SECP521R1, 25, 521, "secp521r1" }, #endif #if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) - { MBEDTLS_ECP_DP_BP512R1, 28, 512, "brainpoolP512r1" }, + { MBEDTLS_ECP_DP_BP512R1, 28, 512, "brainpoolP512r1" }, #endif #if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) - { MBEDTLS_ECP_DP_SECP384R1, 24, 384, "secp384r1" }, + { MBEDTLS_ECP_DP_SECP384R1, 24, 384, "secp384r1" }, #endif #if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) - { MBEDTLS_ECP_DP_BP384R1, 27, 384, "brainpoolP384r1" }, + { MBEDTLS_ECP_DP_BP384R1, 27, 384, "brainpoolP384r1" }, #endif #if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) - { MBEDTLS_ECP_DP_SECP256R1, 23, 256, "secp256r1" }, + { MBEDTLS_ECP_DP_SECP256R1, 23, 256, "secp256r1" }, #endif #if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) - { MBEDTLS_ECP_DP_SECP256K1, 22, 256, "secp256k1" }, + { MBEDTLS_ECP_DP_SECP256K1, 22, 256, "secp256k1" }, #endif #if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) - { MBEDTLS_ECP_DP_BP256R1, 26, 256, "brainpoolP256r1" }, + { MBEDTLS_ECP_DP_BP256R1, 26, 256, "brainpoolP256r1" }, #endif #if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) - { MBEDTLS_ECP_DP_SECP224R1, 21, 224, "secp224r1" }, + { MBEDTLS_ECP_DP_SECP224R1, 21, 224, "secp224r1" }, #endif #if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) - { MBEDTLS_ECP_DP_SECP224K1, 20, 224, "secp224k1" }, + { MBEDTLS_ECP_DP_SECP224K1, 20, 224, "secp224k1" }, #endif #if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) - { MBEDTLS_ECP_DP_SECP192R1, 19, 192, "secp192r1" }, + { MBEDTLS_ECP_DP_SECP192R1, 19, 192, "secp192r1" }, #endif #if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) - { MBEDTLS_ECP_DP_SECP192K1, 18, 192, "secp192k1" }, + { MBEDTLS_ECP_DP_SECP192K1, 18, 192, "secp192k1" }, #endif - { MBEDTLS_ECP_DP_NONE, 0, 0, NULL }, +#if defined(MBEDTLS_ECP_DP_SECP128R1_ENABLED) + { MBEDTLS_ECP_DP_SECP128R1, 0xFE00, 128, "secp128r1" }, +#endif + { MBEDTLS_ECP_DP_NONE, 0, 0, NULL }, }; #define ECP_NB_CURVES sizeof( ecp_supported_curves ) / \ diff --git a/common/mbedtls/ecp.h b/common/mbedtls/ecp.h index 1821a72f..725d52b6 100644 --- a/common/mbedtls/ecp.h +++ b/common/mbedtls/ecp.h @@ -82,6 +82,7 @@ typedef enum MBEDTLS_ECP_DP_SECP224K1, /*!< Domain parameters for 224-bit "Koblitz" curve. */ MBEDTLS_ECP_DP_SECP256K1, /*!< Domain parameters for 256-bit "Koblitz" curve. */ MBEDTLS_ECP_DP_CURVE448, /*!< Domain parameters for Curve448. */ + MBEDTLS_ECP_DP_SECP128R1, /*!< Domain parameters for the 128-bit curve used for NXP originality check. */ } mbedtls_ecp_group_id; /** diff --git a/common/mbedtls/ecp_curves.c b/common/mbedtls/ecp_curves.c index 01efe8ba..bc0cbd5b 100644 --- a/common/mbedtls/ecp_curves.c +++ b/common/mbedtls/ecp_curves.c @@ -84,6 +84,42 @@ * to be directly usable in MPIs */ +/* + * Domain parameters for secp128r1 + */ +#if defined(MBEDTLS_ECP_DP_SECP128R1_ENABLED) +static const mbedtls_mpi_uint secp128r1_p[] = { + // 2^128 - 2^97 - 1 // TODO + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF ), +}; +static const mbedtls_mpi_uint secp128r1_a[] = { + // FFFFFFFDFFFFFFFF FFFFFFFFFFFFFFFC + BYTES_TO_T_UINT_8( 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF ), +}; +static const mbedtls_mpi_uint secp128r1_b[] = { + // E87579C11079F43D D824993C2CEE5ED3 + BYTES_TO_T_UINT_8( 0xD3, 0x5E, 0xEE, 0x2C, 0x3C, 0x99, 0x24, 0xD8 ), + BYTES_TO_T_UINT_8( 0x3D, 0xF4, 0x79, 0x10, 0xC1, 0x79, 0x75, 0xE8 ), +}; +static const mbedtls_mpi_uint secp128r1_gx[] = { + // 161FF7528B899B2D 0C28607CA52C5B86 + BYTES_TO_T_UINT_8( 0x86, 0x5B, 0x2C, 0xA5, 0x7C, 0x60, 0x28, 0x0C ), + BYTES_TO_T_UINT_8( 0x2D, 0x9B, 0x89, 0x8B, 0x52, 0xF7, 0x1F, 0x16 ), +}; +static const mbedtls_mpi_uint secp128r1_gy[] = { + // CF5AC8395BAFEB13 C02DA292DDED7A83 + BYTES_TO_T_UINT_8( 0x83, 0x7A, 0xED, 0xDD, 0x92, 0xA2, 0x2D, 0xC0 ), + BYTES_TO_T_UINT_8( 0x13, 0xEB, 0xAF, 0x5B, 0x39, 0xC8, 0x5A, 0xCF ), +}; +static const mbedtls_mpi_uint secp128r1_n[] = { + // FFFFFFFE00000000 75A30D1B9038A115 + BYTES_TO_T_UINT_8( 0x15, 0xA1, 0x38, 0x90, 0x1B, 0x0D, 0xA3, 0x75 ), + BYTES_TO_T_UINT_8( 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF ), +}; +#endif /* MBEDTLS_ECP_DP_SECP128R1_ENABLED */ + /* * Domain parameters for secp192r1 */ @@ -754,6 +790,11 @@ int mbedtls_ecp_group_load( mbedtls_ecp_group *grp, mbedtls_ecp_group_id id ) switch( id ) { +#if defined(MBEDTLS_ECP_DP_SECP128R1_ENABLED) + case MBEDTLS_ECP_DP_SECP128R1: + grp->modp = NULL; + return( LOAD_GROUP_A( secp128r1 ) ); +#endif /* MBEDTLS_ECP_DP_SECP128R1_ENABLED */ #if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) case MBEDTLS_ECP_DP_SECP192R1: NIST_MODP( p192 ); From faa35ae02952b47fc04fb018b0c9f46b058243fc Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Thu, 1 Aug 2019 10:55:47 -0400 Subject: [PATCH 117/189] fix 'hf mf sim': access conditions to write Key B were not decoded correctly (from PR 279 https://github.com/RfidResearchGroup/proxmark3) --- CHANGELOG.md | 7 ++++--- armsrc/mifaresim.c | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a764787b..4640e72e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,8 +14,9 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - AC-Mode decoding for HitagS - Wrong UID at HitagS simulation - `hf 15 sim` now works as expected (piwi) -- 'hf mf chk t` save to emulator memory now works as expeted (mwalker) - +- `hf mf chk t` save to emulator memory now works as expected (mwalker) + - Fix `hf mf sim` - wrong access rights to write key B in trailer (@McEloff) + ### Added - Added `hf 15 csetuid` - set UID on ISO-15693 Magic tags (t0m4) - Added `lf config s xxxx` option to allow skipping x samples before capture (marshmellow) @@ -28,7 +29,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added `lf hitag reader 04` - read block (instead of pages) - Added `hf fido` `assert` and `make` commands from fido2 protocol (authenticatorMakeCredential and authenticatorGetAssertion) (Merlok) - Added `lf paradox clone` to clone a Paradox card -- Added `emv` commmands working for both contactless and smart cards (Merlok) +- Added `emv` commands working for both contactless and smart cards (Merlok) - Added `hf 15 snoop` (piwi) - Added support for standard USB Smartcard Readers (piwi) - Added `hf plot` (piwi) diff --git a/armsrc/mifaresim.c b/armsrc/mifaresim.c index 137a586d..891e0daf 100644 --- a/armsrc/mifaresim.c +++ b/armsrc/mifaresim.c @@ -95,7 +95,7 @@ static bool IsTrailerAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t act break; } case AC_KEYB_WRITE: { - return ((keytype == AUTHKEYA && (AC == 0x00 || AC == 0x04)) + return ((keytype == AUTHKEYA && (AC == 0x00 || AC == 0x01)) || (keytype == AUTHKEYB && (AC == 0x04 || AC == 0x03))); break; } From ca24170fd4fe631b9ee5deedaa93f9e00cfe3f4f Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Thu, 1 Aug 2019 10:58:22 -0400 Subject: [PATCH 118/189] fix emv search behavior (taken from PRs 261 and 262 by @merlokk on https://github.com/RfidResearchGroup/proxmark3) + whitespace fixes --- client/emv/emvcore.c | 71 ++++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 33 deletions(-) diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index 46fc1b1e..53c1c611 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -287,10 +287,10 @@ struct tlvdb *GetdCVVRawFromTrack2(const struct tlv *track2) { } -int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *apdu, int apdu_len, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) +int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *apdu, int apdu_len, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { *ResultLen = 0; - if (sw) *sw = 0; + if (sw) *sw = 0; uint16_t isw = 0; int res = 0; @@ -314,7 +314,7 @@ int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool LeaveField } #else res = ExchangeAPDU14a(apdu, apdu_len, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen); -#endif +#endif if (res) { return res; @@ -338,7 +338,7 @@ int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool LeaveField if (res) return res; *ResultLen -= 2; - + isw = Result[*ResultLen] * 0x0100 + Result[*ResultLen + 1]; if (sw) *sw = isw; @@ -359,11 +359,11 @@ int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool LeaveField return 0; } -static int EMVExchange(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *apdu, int apdu_len, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) +static int EMVExchange(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *apdu, int apdu_len, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { uint8_t APDU[APDU_COMMAND_LEN]; memcpy(APDU, apdu, apdu_len); - APDU[apdu_len] = 0x00; + APDU[apdu_len] = 0x00; if (channel == ECC_CONTACTLESS) { if (apdu_len == 5) { // there is no Lc but an Le already @@ -376,7 +376,7 @@ static int EMVExchange(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *ap return EMVExchangeEx(channel, false, LeaveFieldON, APDU, apdu_len, Result, MaxResultLen, ResultLen, sw, tlv); } -int EMVSelect(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) +int EMVSelect(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, uint8_t *AID, size_t AIDLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { uint8_t Select_APDU[APDU_COMMAND_LEN] = {0x00, ISO7816_SELECT_FILE, 0x04, 0x00, AIDLen, 0x00}; memcpy(Select_APDU + 5, AID, AIDLen); @@ -397,7 +397,7 @@ int EMVSelectPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO param_gethex_to_eol(PSElist[1], 0, buf, sizeof(buf), &len); break; case 2: - + param_gethex_to_eol(PSElist[0], 0, buf, sizeof(buf), &len); break; default: @@ -427,11 +427,11 @@ int EMVSelectWithRetry(EMVCommandChannel channel, bool ActivateField, bool Leave PrintAndLogEx(WARNING, "Exit..."); return 1; } - + retrycnt = 0; PrintAndLogEx(NORMAL, "Retry failed [%s]. Skiped...", sprint_hex_inrow(AID, AIDLen)); return res; - } + } } } while (res && res != 5); @@ -456,7 +456,7 @@ int EMVCheckAID(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlvdbel tlvdbelm = tlvdb_find_next(tlvdbelm, 0x61); continue; } - + if (res) break; @@ -482,7 +482,7 @@ int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO bool fileFound = false; char *PSE_or_PPSE = PSENum == 1 ? "PSE" : "PPSE"; - + // select PPSE res = EMVSelectPSE(channel, ActivateField, true, PSENum, data, sizeof(data), &datalen, &sw); @@ -491,7 +491,7 @@ int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO PrintAndLogEx(FAILED, "Select PSE error. APDU error: %04x.", sw); return 1; } - + struct tlvdb *t = NULL; t = tlvdb_parse_multi(data, datalen); if (t) { @@ -501,18 +501,18 @@ int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO uint8_t sfin = 0; tlv_get_uint8(tlvdb_get_tlv(tsfi), &sfin); PrintAndLogEx(INFO, "* PPSE get SFI: 0x%02x.", sfin); - + for (uint8_t ui = 0x01; ui <= 0x10; ui++) { PrintAndLogEx(INFO, "* * Get SFI: 0x%02x. num: 0x%02x", sfin, ui); res = EMVReadRecord(channel, true, sfin, ui, sfidata[ui], APDU_RESPONSE_LEN, &sfidatalen[ui], &sw, NULL); - + // end of records if (sw == 0x6a83) { sfidatalen[ui] = 0; PrintAndLogEx(INFO, "* * PPSE get SFI. End of records."); break; } - + // error catch! if (sw != 0x9000) { sfidatalen[ui] = 0; @@ -535,7 +535,7 @@ int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO PrintAndLogEx(FAILED, "SFI 0x%02d doesn't have any records.", sfidatalen[ui]); continue; } - res = EMVCheckAID(channel, decodeTLV, tsfitmp, tlv); + res = EMVCheckAID(channel, decodeTLV, tsfitmp, tlv); fileFound = true; } tlvdb_free(tsfi); @@ -550,7 +550,7 @@ int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO res = EMVCheckAID(channel, decodeTLV, ttmp, tlv); fileFound = true; } - + if (!fileFound) PrintAndLogEx(FAILED, "PPSE doesn't have any records."); @@ -579,14 +579,16 @@ int EMVSearch(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, int retrycnt = 0; for(int i = 0; i < AIDlistLen; i ++) { param_gethex_to_eol(AIDlist[i].aid, 0, aidbuf, sizeof(aidbuf), &aidlen); - res = EMVSelect(channel, (i == 0) ? ActivateField : false, (i == AIDlistLen - 1) ? LeaveFieldON : true, aidbuf, aidlen, data, sizeof(data), &datalen, &sw, tlv); + res = EMVSelect(channel, (i == 0) ? ActivateField : false, true, aidbuf, aidlen, data, sizeof(data), &datalen, &sw, tlv); // retry if error and not returned sw error if (res && res != 5) { if (++retrycnt < 3){ i--; } else { - // (1) - card select error, proxmark error OR (200) - result length = 0 - if (res == 1 || res == 200) { + // (1) - card select error, (4) reply timeout, (200) - result length = 0 + if (res == 1 || res == 4 || res == 200) { + if (!LeaveFieldON) + DropFieldEx(channel); PrintAndLogEx(WARNING, "Exit..."); return 1; } @@ -610,6 +612,9 @@ int EMVSearch(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldON, } } + if (!LeaveFieldON) + DropFieldEx(channel); + return 0; } @@ -652,12 +657,12 @@ int EMVSelectApplication(struct tlvdb *tlv, uint8_t *AID, size_t *AIDlen) { return 0; } -int EMVGPO(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) +int EMVGPO(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *PDOL, size_t PDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { uint8_t GPO_APDU[APDU_COMMAND_LEN] = {0x80, ISO7816_GET_PROCESSING_OPTIONS, 0x00, 0x00, PDOLLen, 0x00}; memcpy(GPO_APDU + 5, PDOL, PDOLLen); int apdulen = 5 + PDOLLen; - + return EMVExchange(channel, LeaveFieldON, GPO_APDU, apdulen, Result, MaxResultLen, ResultLen, sw, tlv); } @@ -677,14 +682,14 @@ int EMVAC(EMVCommandChannel channel, bool LeaveFieldON, uint8_t RefControl, uint uint8_t CDOL_APDU[APDU_COMMAND_LEN] = {0x80, 0xae, RefControl, 0x00, CDOLLen, 0x00}; memcpy(CDOL_APDU + 5, CDOL, CDOLLen); int apdulen = 5 + CDOLLen; - + return EMVExchange(channel, LeaveFieldON, CDOL_APDU, apdulen, Result, MaxResultLen, ResultLen, sw, tlv); } -int EMVGenerateChallenge(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) +int EMVGenerateChallenge(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { uint8_t get_challenge_APDU[APDU_COMMAND_LEN] = {0x00, ISO7816_GET_CHALLENGE, 0x00, 0x00}; - + int res = EMVExchange(channel, LeaveFieldON, get_challenge_APDU, 4, Result, MaxResultLen, ResultLen, sw, tlv); if (*sw == 0x6700) { PrintAndLogEx(INFO, ">>> trying to reissue command withouth Le..."); @@ -693,12 +698,12 @@ int EMVGenerateChallenge(EMVCommandChannel channel, bool LeaveFieldON, uint8_t * return res; } -int EMVInternalAuthenticate(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) +int EMVInternalAuthenticate(EMVCommandChannel channel, bool LeaveFieldON, uint8_t *DDOL, size_t DDOLLen, uint8_t *Result, size_t MaxResultLen, size_t *ResultLen, uint16_t *sw, struct tlvdb *tlv) { uint8_t authenticate_APDU[APDU_COMMAND_LEN] = {0x00, ISO7816_INTERNAL_AUTHENTICATE, 0x00, 0x00, DDOLLen, 0x00}; memcpy(authenticate_APDU + 5, DDOL, DDOLLen); int apdulen = 5 + DDOLLen; - + return EMVExchange(channel, LeaveFieldON, authenticate_APDU, apdulen, Result, MaxResultLen, ResultLen, sw, tlv); } @@ -707,7 +712,7 @@ int MSCComputeCryptoChecksum(EMVCommandChannel channel, bool LeaveFieldON, uint8 uint8_t checksum_APDU[APDU_COMMAND_LEN] = {0x80, 0x2a, 0x8e, 0x80, UDOLlen, 0x00}; memcpy(checksum_APDU + 5, UDOL, UDOLlen); int apdulen = 5 + UDOLlen; - + return EMVExchange(channel, LeaveFieldON, checksum_APDU, apdulen, Result, MaxResultLen, ResultLen, sw, tlv); } @@ -790,7 +795,7 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { } const struct tlv *sda_tlv = tlvdb_get(tlv, 0x21, NULL); -/* if (!sda_tlv || sda_tlv->len < 1) { it may be 0!!!! +/* if (!sda_tlv || sda_tlv->len < 1) { it may be 0!!!! emv_pk_free(pk); PrintAndLogEx(WARNING, "Error: Can't find input list for Offline Data Authentication. Exit."); return 3; @@ -940,13 +945,13 @@ int trDDA(EMVCommandChannel channel, bool decodeTLV, struct tlvdb *tlv) { // parse response 0x80 struct tlvdb *t80 = tlvdb_parse_multi(buf, len); const struct tlv * t80tlv = tlvdb_get_tlv(t80); - + // 9f4b Signed Dynamic Application Data dda_db = tlvdb_fixed(0x9f4b, t80tlv->len, t80tlv->value); tlvdb_add(tlv, dda_db); - + tlvdb_free(t80); - + if (decodeTLV){ PrintAndLogEx(NORMAL, "* * Decode response format 1:"); TLVPrintFromTLV(dda_db); From 5a446cb212f7ff26f209da765b79b44011d41045 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Thu, 1 Aug 2019 11:01:56 -0400 Subject: [PATCH 119/189] 'hf 14a apdu' improvement (PR 249 by @merlokk on https://github.com/RfidResearchGroup/proxmark3) * add option to print APDU (if it can be decoded) * add option to cconstruct extended and normal size APDUs --- CHANGELOG.md | 1 + client/cmdhf14a.c | 90 +++++- client/emv/apduinfo.c | 709 +++++++++++++++++++++++++++--------------- client/emv/apduinfo.h | 56 +++- client/util.h | 6 + 5 files changed, 581 insertions(+), 281 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4640e72e..5210edbc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Fix `hf mf sim` - wrong access rights to write key B in trailer (@McEloff) ### Added +- Added to `hf 14a apdu` print apdu and compose apdu (@merlokk) - Added `hf 15 csetuid` - set UID on ISO-15693 Magic tags (t0m4) - Added `lf config s xxxx` option to allow skipping x samples before capture (marshmellow) - Added `lf em 4x05protect` to support changing protection blocks on em4x05 chips (marshmellow) diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 90032022..eba33947 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -921,20 +921,34 @@ int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool lea int CmdHF14AAPDU(const char *cmd) { uint8_t data[USB_CMD_DATA_SIZE]; int datalen = 0; + uint8_t header[5]; + int headerlen = 0; bool activateField = false; bool leaveSignalON = false; bool decodeTLV = false; + bool decodeAPDU = false; + bool makeAPDU = false; + bool extendedAPDU = false; + int le = 0; + int res = 0; CLIParserInit("hf 14a apdu", - "Sends an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol (T=CL)", - "Sample:\n\thf 14a apdu -st 00A404000E325041592E5359532E444446303100\n"); + "Sends an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol (T=CL). Works with all APDU types from ISO 7816-4:2013", + "Examples:\n\thf 14a apdu -st 00A404000E325041592E5359532E444446303100\n" + "\thf 14a apdu -sd 00A404000E325041592E5359532E444446303100 - decode APDU\n" + "\thf 14a apdu -sm 00A40400 325041592E5359532E4444463031 -l 256 - encode standard APDU\n" + "\thf 14a apdu -sm 00A40400 325041592E5359532E4444463031 -el 65536 - encode extended APDU\n"); void* argtable[] = { arg_param_begin, - arg_lit0("sS", "select", "activate field and select card"), - arg_lit0("kK", "keep", "leave the signal field ON after receive response"), - arg_lit0("tT", "tlv", "executes TLV decoder if it possible"), - arg_strx1(NULL, NULL, "", NULL), + arg_lit0("sS", "select", "activate field and select card"), + arg_lit0("kK", "keep", "leave the signal field ON after receive response"), + arg_lit0("tT", "tlv", "executes TLV decoder if it possible"), + arg_lit0("dD", "decapdu", "decode APDU request if it possible"), + arg_str0("mM", "make", "", "make APDU with head from this field and data from data field. Must be 4 bytes length: "), + arg_lit0("eE", "extended", "make extended length APDU (requires `-m`)"), + arg_int0("lL", "le", "", "Le APDU parameter (requires `-m`)"), + arg_strx1(NULL, NULL, "", "APDU (without `-m`), or data (with `-m`)"), arg_param_end }; CLIExecWithReturn(cmd, argtable, false); @@ -942,15 +956,71 @@ int CmdHF14AAPDU(const char *cmd) { activateField = arg_get_lit(1); leaveSignalON = arg_get_lit(2); decodeTLV = arg_get_lit(3); - // len = data + PCB(1b) + CRC(2b) - CLIGetHexBLessWithReturn(4, data, &datalen, 1 + 2); + decodeAPDU = arg_get_lit(4); + res = CLIParamHexToBuf(arg_get_str(5), header, sizeof(header), &headerlen); + makeAPDU = headerlen > 0; + if (res || (makeAPDU && headerlen != 4)) { + PrintAndLogEx(ERR, "header length must be exactly 4 bytes"); + CLIParserFree(); + return 1; + } + extendedAPDU = arg_get_lit(6); + le = arg_get_int_def(7, 0); + + if (makeAPDU) { + uint8_t apdudata[USB_CMD_DATA_SIZE] = {0}; + int apdudatalen = 0; + + CLIGetHexBLessWithReturn(8, apdudata, &apdudatalen, 1 + 2); + + APDUStruct apdu; + apdu.cla = header[0]; + apdu.ins = header[1]; + apdu.p1 = header[2]; + apdu.p2 = header[3]; + + apdu.lc = apdudatalen; + apdu.data = apdudata; + + apdu.extended_apdu = extendedAPDU; + apdu.le = le; + + if (APDUEncode(&apdu, data, &datalen)) { + PrintAndLogEx(ERR, "can't make apdu with provided parameters."); + CLIParserFree(); + return 2; + } + } else { + if (extendedAPDU) { + PrintAndLogEx(ERR, "`-e` without `-m`."); + CLIParserFree(); + return 3; + } + if (le > 0) { + PrintAndLogEx(ERR, "`-l` without `-m`."); + CLIParserFree(); + return 3; + } + + // len = data + PCB(1b) + CRC(2b) + CLIGetHexBLessWithReturn(8, data, &datalen, 1 + 2); + } CLIParserFree(); // PrintAndLog("---str [%d] %s", arg_get_str(4)->count, arg_get_str(4)->sval[0]); - PrintAndLog(">>>>[%s%s%s] %s", activateField ? "sel ": "", leaveSignalON ? "keep ": "", decodeTLV ? "TLV": "", sprint_hex(data, datalen)); + PrintAndLogEx(NORMAL, ">>>>[%s%s%s] %s", activateField ? "sel ": "", leaveSignalON ? "keep ": "", decodeTLV ? "TLV": "", sprint_hex(data, datalen)); - int res = ExchangeAPDU14a(data, datalen, activateField, leaveSignalON, data, USB_CMD_DATA_SIZE, &datalen); + if (decodeAPDU) { + APDUStruct apdu; + + if (APDUDecode(data, datalen, &apdu) == 0) + APDUPrint(apdu); + else + PrintAndLogEx(WARNING, "can't decode APDU."); + } + + res = ExchangeAPDU14a(data, datalen, activateField, leaveSignalON, data, USB_CMD_DATA_SIZE, &datalen); if (res) return res; diff --git a/client/emv/apduinfo.c b/client/emv/apduinfo.c index d14e3ff6..65d7404e 100644 --- a/client/emv/apduinfo.c +++ b/client/emv/apduinfo.c @@ -10,256 +10,261 @@ #include "apduinfo.h" +#include +#include +#include "ui.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)"} + {"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 successfully 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 successfully 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 successfully 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 successfully 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 successfully verified, PIN not installed"}, + {"9F00", APDUCODE_TYPE_NONE, "PIN blocked and Unblock Try Counter is 3"}, + {"9F04", APDUCODE_TYPE_NONE, "PIN not successfully 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); +const size_t APDUCodeTableLen = sizeof(APDUCodeTable) / sizeof(APDUCode); -int CodeCmp(const char *code1, const char *code2) { +static int CodeCmp(const char *code1, const char *code2) { int xsymb = 0; int cmp = 0; for (int i = 0; i < 4; i++) { @@ -270,29 +275,28 @@ int CodeCmp(const char *code1, const char *code2) { } if (cmp == 4) return 0; - + if (cmp + xsymb == 4) return xsymb; - + return -1; } -const APDUCode* const GetAPDUCode(uint8_t sw1, uint8_t sw2) { - char buf[5] = {0}; - int res; +const APDUCode *GetAPDUCode(uint8_t sw1, uint8_t sw2) { + char buf[6] = {0}; int mineq = APDUCodeTableLen; int mineqindx = 0; - + sprintf(buf, "%02X%02X", sw1, sw2); - + for (int i = 0; i < APDUCodeTableLen; i++) { - res = CodeCmp(APDUCodeTable[i].ID, buf); - + int res = CodeCmp(APDUCodeTable[i].ID, buf); + // equal - if (res == 0) { + if (res == 0) { return &APDUCodeTable[i]; } - + // with some 'X' if (res > 0 && mineq > res) { mineq = res; @@ -304,14 +308,201 @@ const APDUCode* const GetAPDUCode(uint8_t sw1, uint8_t sw2) { if (mineqindx < APDUCodeTableLen) { return &APDUCodeTable[mineqindx]; } - + return NULL; } -const char* GetAPDUCodeDescription(uint8_t sw1, uint8_t sw2) { +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 } + +int APDUDecode(uint8_t *data, int len, APDUStruct *apdu) { + ExtAPDUHeader *hapdu = (ExtAPDUHeader *)data; + + apdu->cla = hapdu->cla; + apdu->ins = hapdu->ins; + apdu->p1 = hapdu->p1; + apdu->p2 = hapdu->p2; + + apdu->lc = 0; + apdu->data = NULL; + apdu->le = 0; + apdu->extended_apdu = false; + apdu->case_type = 0x00; + + uint8_t b0 = hapdu->lc[0]; + + // case 1 + if (len == 4) { + apdu->case_type = 0x01; + } + + // case 2S (Le) + if (len == 5) { + apdu->case_type = 0x02; + apdu->le = b0; + if (!apdu->le) + apdu->le = 0x100; + } + + // case 3S (Lc + data) + if (len == 5U + b0 && b0 != 0) { + apdu->case_type = 0x03; + apdu->lc = b0; + } + + // case 4S (Lc + data + Le) + if (len == 5U + b0 + 1U && b0 != 0) { + apdu->case_type = 0x04; + apdu->lc = b0; + apdu->le = data[len - 1]; + if (!apdu->le) + apdu->le = 0x100; + } + + // extended length apdu + if (len >= 7 && b0 == 0) { + uint16_t extlen = (hapdu->lc[1] << 8) + hapdu->lc[2]; + + // case 2E (Le) - extended + if (len == 7) { + apdu->case_type = 0x12; + apdu->extended_apdu = true; + apdu->le = extlen; + if (!apdu->le) + apdu->le = 0x10000; + } + + // case 3E (Lc + data) - extended + if (len == 7U + extlen) { + apdu->case_type = 0x13; + apdu->extended_apdu = true; + apdu->lc = extlen; + } + + // case 4E (Lc + data + Le) - extended 2-byte Le + if (len == 7U + extlen + 2U) { + apdu->case_type = 0x14; + apdu->extended_apdu = true; + apdu->lc = extlen; + apdu->le = (data[len - 2] << 8) + data[len - 1]; + if (!apdu->le) + apdu->le = 0x10000; + } + + // case 4E (Lc + data + Le) - extended 3-byte Le + if (len == 7U + extlen + 3U && data[len - 3] == 0) { + apdu->case_type = 0x24; + apdu->extended_apdu = true; + apdu->lc = extlen; + apdu->le = (data[len - 2] << 8) + data[len - 1]; + if (!apdu->le) + apdu->le = 0x10000; + } + } + + if (!apdu->case_type) + return 1; + + if (apdu->lc) { + if (apdu->extended_apdu) { + apdu->data = data + 7; + } else { + apdu->data = data + 5; + } + + } + + return 0; +} + +int APDUEncode(APDUStruct *apdu, uint8_t *data, int *len) { + if (len) + *len = 0; + + if (apdu->le > 0x10000 || apdu->lc > 0xffff) + return 1; + + size_t dptr = 0; + data[dptr++] = apdu->cla; + data[dptr++] = apdu->ins; + data[dptr++] = apdu->p1; + data[dptr++] = apdu->p2; + + if (apdu->lc) { + if (apdu->extended_apdu || apdu->lc > 0xff || apdu->le > 0x100) { + data[dptr++] = 0x00; + data[dptr++] = (apdu->lc >> 8) & 0xff; + data[dptr++] = (apdu->lc) & 0xff; + memmove(&data[dptr], apdu->data, apdu->lc); + dptr += apdu->lc; + apdu->extended_apdu = true; + } else { + data[dptr++] = apdu->lc; + memmove(&data[dptr], apdu->data, apdu->lc); + dptr += apdu->lc; + } + } + + if (apdu->le) { + if (apdu->extended_apdu) { + if (apdu->le != 0x10000) { + data[dptr++] = 0x00; + data[dptr++] = (apdu->le >> 8) & 0xff; + data[dptr++] = (apdu->le) & 0xff; + } else { + data[dptr++] = 0x00; + data[dptr++] = 0x00; + data[dptr++] = 0x00; + } + } else { + if (apdu->le != 0x100) + data[dptr++] = apdu->le; + else + data[dptr++] = 0x00; + } + } + + if (len) + *len = dptr; + return 0; +} + +int APDUEncodeS(sAPDU *sapdu, bool extended, uint16_t le, uint8_t *data, int *len) { + if (extended && le > 0x100) + return 10; + + APDUStruct apdu; + + apdu.cla = sapdu->CLA; + apdu.ins = sapdu->INS; + apdu.p1 = sapdu->P1; + apdu.p2 = sapdu->P2; + + apdu.lc = sapdu->Lc; + if (sapdu->Lc) + apdu.data = sapdu->data; + else + apdu.data = NULL; + apdu.le = le; + + apdu.extended_apdu = extended; + apdu.case_type = 0x00; + + return APDUEncode(&apdu, data, len); +} + +void APDUPrint(APDUStruct apdu) { + APDUPrintEx(apdu, 0); +} + +void APDUPrintEx(APDUStruct apdu, size_t maxdatalen) { + PrintAndLogEx(INFO, "APDU: %scase=0x%02x cla=0x%02x ins=0x%02x p1=0x%02x p2=0x%02x Lc=0x%02x(%d) Le=0x%02x(%d)", + apdu.extended_apdu ? "[e]" : "", apdu.case_type, apdu.cla, apdu.ins, apdu.p1, apdu.p2, apdu.lc, apdu.lc, apdu.le, apdu.le); + if (maxdatalen > 0) + PrintAndLogEx(INFO, "data: %s%s", sprint_hex(apdu.data, MIN(apdu.lc, maxdatalen)), apdu.lc > maxdatalen ? "..." : ""); +} diff --git a/client/emv/apduinfo.h b/client/emv/apduinfo.h index a3fa2049..d407a125 100644 --- a/client/emv/apduinfo.h +++ b/client/emv/apduinfo.h @@ -11,24 +11,56 @@ #ifndef APDUINFO_H__ #define APDUINFO_H__ -#include -#include -#include -#include +#include "util.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; } APDUCode; - -extern const APDUCode* const GetAPDUCode(uint8_t sw1, uint8_t sw2); -extern const char* GetAPDUCodeDescription(uint8_t sw1, uint8_t sw2); + +typedef struct { + uint8_t CLA; + uint8_t INS; + uint8_t P1; + uint8_t P2; + uint8_t Lc; + uint8_t *data; +} PACKED sAPDU; + +typedef struct { + uint8_t cla; + uint8_t ins; + uint8_t p1; + uint8_t p2; + uint8_t lc[3]; +} PACKED ExtAPDUHeader; + +typedef struct { + uint8_t cla; + uint8_t ins; + uint8_t p1; + uint8_t p2; + uint16_t lc; + uint8_t *data; + uint32_t le; + bool extended_apdu; + uint8_t case_type; +} PACKED APDUStruct; + +extern const APDUCode *GetAPDUCode(uint8_t sw1, uint8_t sw2); +extern const char *GetAPDUCodeDescription(uint8_t sw1, uint8_t sw2); +extern int APDUDecode(uint8_t *data, int len, APDUStruct *apdu); +extern int APDUEncode(APDUStruct *apdu, uint8_t *data, int *len); +extern int APDUEncodeS(sAPDU *apdu, bool extended, uint16_t le, uint8_t *data, int *len); +extern void APDUPrint(APDUStruct apdu); +extern void APDUPrintEx(APDUStruct apdu, size_t maxdatalen); #endif diff --git a/client/util.h b/client/util.h index 18482dfe..5f3335ac 100644 --- a/client/util.h +++ b/client/util.h @@ -15,6 +15,12 @@ #include #include +#ifdef _MSC_VER +#define PACKED +#else +#define PACKED __attribute__((packed)) +#endif + #ifndef ROTR # define ROTR(x,n) (((uintmax_t)(x) >> (n)) | ((uintmax_t)(x) << ((sizeof(x) * 8) - (n)))) #endif From f98702bace48fde3ec1492d1c732e23cd2eb8613 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Sat, 10 Aug 2019 23:30:47 +0200 Subject: [PATCH 120/189] chg 'hf mf chk': * don't repeatedly clear trace while running (PR 243 by @mceloff from https://github.com/RfidResearchGroup/proxmark3) * standard LED handling * better check for key file syntax * get rid of "res" column when printing the result. Show unknown keys more prominent as " ? " --- armsrc/mifarecmd.c | 17 ++++++----- client/cmdhfmf.c | 70 ++++++++++++++++++++++++++++------------------ 2 files changed, 51 insertions(+), 36 deletions(-) diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index a3807cf7..8fe502ca 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -980,16 +980,17 @@ void MifareChkKeys(uint16_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain) uint8_t set14aTimeout = (arg1 >> 8) & 0xff; uint8_t keyCount = arg2; + LED_A_ON(); + // clear debug level int OLD_MF_DBGLEVEL = MF_DBGLEVEL; MF_DBGLEVEL = MF_DBG_NONE; - LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); - if (clearTrace) clear_trace(); + if (clearTrace) { + clear_trace(); + } set_tracing(true); if (set14aTimeout){ @@ -1001,30 +1002,28 @@ void MifareChkKeys(uint16_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain) uint8_t sectorCnt = blockNo; int res = MifareMultisectorChk(datain, keyCount, sectorCnt, keyType, OLD_MF_DBGLEVEL, &keyIndex); - LED_B_ON(); if (res >= 0) { cmd_send(CMD_ACK, 1, 0, 0, keyIndex, 80); } else { cmd_send(CMD_ACK, 0, 0, 0, NULL, 0); } - LED_B_OFF(); } else { int res = MifareChkBlockKeys(datain, keyCount, blockNo, keyType, OLD_MF_DBGLEVEL); - LED_B_ON(); if (res > 0) { cmd_send(CMD_ACK, 1, 0, 0, datain + (res - 1) * 6, 6); } else { cmd_send(CMD_ACK, 0, 0, 0, NULL, 0); } - LED_B_OFF(); } FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); + LED_D_OFF(); // restore debug level MF_DBGLEVEL = OLD_MF_DBGLEVEL; + + LED_A_OFF(); } //----------------------------------------------------------------------------- diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index a4461e37..c38e276e 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -1099,16 +1099,17 @@ int CmdHF14AMfChk(const char *Cmd) if (param_getchar(Cmd, 0)=='*') { SectorsCnt = ParamCardSizeSectors(param_getchar(Cmd + 1, 0)); - } - else { + } else { blockNo = param_get8(Cmd, 0); // Singe Key check, so Set Sector count to cover sectors (1 to sector that contains the block) // 1 and 2 Cards : Sector = blockNo/4 + 1 // Sectors 0 - 31 : 4 blocks per sector : Blocks 0 - 127 // Sectors 32 - 39 : 16 blocks per sector : Blocks 128 - 255 (4K) - if (blockNo < 128) SectorsCnt = (blockNo / 4) + 1; - else SectorsCnt = 32 + ((blockNo-128)/16) + 1; - + if (blockNo < 128) { + SectorsCnt = (blockNo / 4) + 1; + } else { + SectorsCnt = 32 + ((blockNo-128)/16) + 1; + } singleBlock = true; // Set flag for single key check } @@ -1143,7 +1144,7 @@ int CmdHF14AMfChk(const char *Cmd) param3InUse = transferToEml | createDumpFile | (btimeout14a != MF_CHKKEYS_DEFTIMEOUT); PrintAndLog("--chk keys. sectors:%2d, block no:%3d, key type:%c, eml:%c, dmp=%c checktimeout=%d us", - SectorsCnt, blockNo, keyType?'B':'A', transferToEml?'y':'n', createDumpFile?'y':'n', ((int)btimeout14a * 10000) / 106); + SectorsCnt, blockNo, keyType==0?'A':keyType==1?'B':'?', transferToEml?'y':'n', createDumpFile?'y':'n', ((int)btimeout14a * 10000) / 106); for (i = param3InUse; param_getchar(Cmd, 2 + i); i++) { if (!param_gethex(Cmd, 2 + i, keyBlock + 6 * keycnt, 12)) { @@ -1168,8 +1169,8 @@ int CmdHF14AMfChk(const char *Cmd) return 2; } - if ( (f = fopen( filename , "r")) ) { - while( fgets(buf, sizeof(buf), f) ){ + if ((f = fopen( filename , "r"))) { + while (fgets(buf, sizeof(buf), f)) { if (strlen(buf) < 12 || buf[11] == '\n') continue; @@ -1177,14 +1178,20 @@ int CmdHF14AMfChk(const char *Cmd) if( buf[0]=='#' ) continue; //The line start with # is comment, skip - if (!isxdigit((unsigned char)buf[0])){ - PrintAndLog("File content error. '%s' must include 12 HEX symbols",buf); + bool content_error = false; + for (int i = 0; i < 12; i++) { + if (!isxdigit((unsigned char)buf[i])) { + content_error = true; + } + } + if (content_error) { + PrintAndLog("File content error. '%s' must include 12 HEX symbols", buf); continue; } buf[12] = 0; - if ( stKeyBlock - keycnt < 2) { + if (stKeyBlock - keycnt < 2) { p = realloc(keyBlock, 6*(stKeyBlock+=10)); if (!p) { PrintAndLog("Cannot allocate memory for defKeys"); @@ -1232,8 +1239,9 @@ int CmdHF14AMfChk(const char *Cmd) } printf("\n"); - bool foundAKey = false; - uint32_t max_keys = keycnt > USB_CMD_DATA_SIZE / 6 ? USB_CMD_DATA_SIZE / 6 : keycnt; + bool foundAKey = false; + bool clearTraceLog = true; + uint32_t max_keys = keycnt > USB_CMD_DATA_SIZE / 6 ? USB_CMD_DATA_SIZE / 6 : keycnt; // !SingleKey, so all key check (if SectorsCnt > 0) if (!singleBlock) { @@ -1242,7 +1250,8 @@ int CmdHF14AMfChk(const char *Cmd) for (uint32_t c = 0; c < keycnt; c += max_keys) { uint32_t size = keycnt-c > max_keys ? max_keys : keycnt-c; - res = mfCheckKeysSec(SectorsCnt, keyType, btimeout14a, true, size, &keyBlock[6 * c], e_sector); // timeout is (ms * 106)/10 or us*0.0106 + res = mfCheckKeysSec(SectorsCnt, keyType, btimeout14a, clearTraceLog, size, &keyBlock[6 * c], e_sector); // timeout is (ms * 106)/10 or us*0.0106 + clearTraceLog = false; if (res != 1) { if (!res) { @@ -1259,10 +1268,11 @@ int CmdHF14AMfChk(const char *Cmd) } else { int keyAB = keyType; do { - for (uint32_t c = 0; c < keycnt; c+=max_keys) { + for (uint32_t c = 0; c < keycnt; c += max_keys) { uint32_t size = keycnt-c > max_keys ? max_keys : keycnt-c; res = mfCheckKeys(blockNo, keyAB & 0x01, true, size, &keyBlock[6 * c], &key64); + clearTraceLog = false; if (res != 1) { if (!res) { @@ -1285,20 +1295,25 @@ int CmdHF14AMfChk(const char *Cmd) // print result if (foundAKey) { - if (SectorsCnt) { - PrintAndLog(""); - PrintAndLog("|---|----------------|---|----------------|---|"); - PrintAndLog("|sec|key A |res|key B |res|"); - PrintAndLog("|---|----------------|---|----------------|---|"); - for (i = 0; i < SectorsCnt; i++) { - // If a block key check, only print a line if a key was found. - if (!singleBlock || (e_sector[i].foundKey[0]) || (e_sector[i].foundKey[1]) ){ - PrintAndLog("|%03d| %012" PRIx64 " | %d | %012" PRIx64 " | %d |", i, - e_sector[i].Key[0], e_sector[i].foundKey[0], e_sector[i].Key[1], e_sector[i].foundKey[1]); - } + PrintAndLog(""); + PrintAndLog("|---|----------------|----------------|"); + PrintAndLog("|sec|key A |key B |"); + PrintAndLog("|---|----------------|----------------|"); + for (i = 0; i < SectorsCnt; i++) { + // If a block key check, only print a line if a key was found. + if (!singleBlock || e_sector[i].foundKey[0] || e_sector[i].foundKey[1]) { + char keyAString[13] = " ? "; + char keyBString[13] = " ? "; + if (e_sector[i].foundKey[0]) { + sprintf(keyAString, "%012" PRIx64, e_sector[i].Key[0]); + } + if (e_sector[i].foundKey[1]) { + sprintf(keyBString, "%012" PRIx64, e_sector[i].Key[1]); + } + PrintAndLog("|%03d| %s | %s |", i, keyAString, keyBString); } - PrintAndLog("|---|----------------|---|----------------|---|"); } + PrintAndLog("|---|----------------|----------------|"); } else { PrintAndLog(""); PrintAndLog("No valid keys found."); @@ -1347,6 +1362,7 @@ int CmdHF14AMfChk(const char *Cmd) return 0; } + void readerAttack(nonces_t ar_resp[], bool setEmulatorMem, bool doStandardAttack) { #define ATTACK_KEY_COUNT 7 // keep same as define in iso14443a.c -> Mifare1ksim() // cannot be more than 7 or it will overrun c.d.asBytes(512) From 17505ce2a74468c89747c996a72139aa9f3ca225 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Wed, 21 Aug 2019 22:10:24 +0200 Subject: [PATCH 121/189] cleaning up iclass.c and optimized_cipher.c * add iclass.h * reformatting * whitespace fixes * (no functional changes) --- armsrc/appmain.c | 1 + armsrc/apps.h | 19 - armsrc/iclass.c | 1510 ++++++++++++++++++------------------- armsrc/optimized_cipher.c | 203 +++-- armsrc/optimized_cipher.h | 19 +- 5 files changed, 829 insertions(+), 923 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 9b9acb6f..34d1747b 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -24,6 +24,7 @@ #include "legicrfsim.h" #include "hitag2.h" #include "hitagS.h" +#include "iclass.h" #include "iso14443b.h" #include "iso15693.h" #include "lfsampling.h" diff --git a/armsrc/apps.h b/armsrc/apps.h index 4d9a1482..0302a9f6 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -26,10 +26,6 @@ extern const uint8_t OddByteParity[256]; extern int rsamples; // = 0; extern uint8_t trigger; -// This may be used (sparingly) to declare a function to be copied to -// and executed from RAM -#define RAMFUNC __attribute((long_call, section(".ramfunc"))) - /// appmain.h void ReadMem(int addr); void __attribute__((noreturn)) AppMain(void); @@ -144,21 +140,6 @@ void ReaderMifareDES(uint32_t param, uint32_t param2, uint8_t * datain); int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout); size_t CreateAPDU( uint8_t *datain, size_t len, uint8_t *dataout); - -/// iclass.h -void RAMFUNC SnoopIClass(void); -void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); -void ReaderIClass(uint8_t arg0); -void ReaderIClass_Replay(uint8_t arg0,uint8_t *MAC); -void IClass_iso14443A_GetPublic(uint8_t arg0); -void iClass_Authentication(uint8_t *MAC); -void iClass_WriteBlock(uint8_t blockNo, uint8_t *data); -void iClass_ReadBlk(uint8_t blockNo); -bool iClass_ReadBlock(uint8_t blockNo, uint8_t *readdata); -void iClass_Dump(uint8_t blockno, uint8_t numblks); -void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data); -void iClass_ReadCheck(uint8_t blockNo, uint8_t keyType); - // cmd.h bool cmd_receive(UsbCommand* cmd); bool cmd_send(uint32_t cmd, uint32_t arg0, uint32_t arg1, uint32_t arg2, void* data, size_t len); diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 7ffac62d..ee305a26 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -12,7 +12,7 @@ //----------------------------------------------------------------------------- // Based on ISO14443a implementation. Still in experimental phase. // Contribution made during a security research at Radboud University Nijmegen -// +// // Please feel free to contribute and extend iClass support!! //----------------------------------------------------------------------------- // @@ -21,7 +21,7 @@ // We still have sometimes a demodulation error when snooping iClass communication. // The resulting trace of a read-block-03 command may look something like this: // -// + 22279: : 0c 03 e8 01 +// + 22279: : 0c 03 e8 01 // // ...with an incorrect answer... // @@ -31,11 +31,13 @@ // // A correct trace should look like this: // -// + 21112: : 0c 03 e8 01 -// + 85: 0: TAG ff ff ff ff ff ff ff ff ea f5 +// + 21112: : 0c 03 e8 01 +// + 85: 0: TAG ff ff ff ff ff ff ff ff ea f5 // //----------------------------------------------------------------------------- +#include "iclass.h" + #include "proxmark3.h" #include "apps.h" #include "util.h" @@ -55,173 +57,159 @@ static int timeout = 4096; - -static int SendIClassAnswer(uint8_t *resp, int respLen, int delay); - //----------------------------------------------------------------------------- // The software UART that receives commands from the reader, and its state // variables. //----------------------------------------------------------------------------- static struct { - enum { - STATE_UNSYNCD, - STATE_START_OF_COMMUNICATION, - STATE_RECEIVING - } state; - uint16_t shiftReg; - int bitCnt; - int byteCnt; - int byteCntMax; - int posCnt; - int nOutOfCnt; - int OutOfCnt; - int syncBit; - int samples; - int highCnt; - int swapper; - int counter; - int bitBuffer; - int dropPosition; - uint8_t *output; + enum { + STATE_UNSYNCD, + STATE_START_OF_COMMUNICATION, + STATE_RECEIVING + } state; + uint16_t shiftReg; + int bitCnt; + int byteCnt; + int byteCntMax; + int posCnt; + int nOutOfCnt; + int OutOfCnt; + int syncBit; + int samples; + int highCnt; + int swapper; + int counter; + int bitBuffer; + int dropPosition; + uint8_t *output; } Uart; -static RAMFUNC int OutOfNDecoding(int bit) -{ +static RAMFUNC int OutOfNDecoding(int bit) { //int error = 0; int bitright; - if(!Uart.bitBuffer) { + if (!Uart.bitBuffer) { Uart.bitBuffer = bit ^ 0xFF0; return false; - } - else { + } else { Uart.bitBuffer <<= 4; Uart.bitBuffer ^= bit; } - - /*if(Uart.swapper) { + + /*if (Uart.swapper) { Uart.output[Uart.byteCnt] = Uart.bitBuffer & 0xFF; Uart.byteCnt++; Uart.swapper = 0; - if(Uart.byteCnt > 15) { return true; } + if (Uart.byteCnt > 15) { return true; } } else { Uart.swapper = 1; }*/ - if(Uart.state != STATE_UNSYNCD) { + if (Uart.state != STATE_UNSYNCD) { Uart.posCnt++; - if((Uart.bitBuffer & Uart.syncBit) ^ Uart.syncBit) { + if ((Uart.bitBuffer & Uart.syncBit) ^ Uart.syncBit) { bit = 0x00; - } - else { + } else { bit = 0x01; } - if(((Uart.bitBuffer << 1) & Uart.syncBit) ^ Uart.syncBit) { + if (((Uart.bitBuffer << 1) & Uart.syncBit) ^ Uart.syncBit) { bitright = 0x00; - } - else { + } else { bitright = 0x01; } - if(bit != bitright) { bit = bitright; } + if (bit != bitright) { + bit = bitright; + } + - // So, now we only have to deal with *bit*, lets see... - if(Uart.posCnt == 1) { + if (Uart.posCnt == 1) { // measurement first half bitperiod - if(!bit) { + if (!bit) { // Drop in first half means that we are either seeing // an SOF or an EOF. - if(Uart.nOutOfCnt == 1) { + if (Uart.nOutOfCnt == 1) { // End of Communication Uart.state = STATE_UNSYNCD; Uart.highCnt = 0; - if(Uart.byteCnt == 0) { + if (Uart.byteCnt == 0) { // Its not straightforward to show single EOFs // So just leave it and do not return true Uart.output[0] = 0xf0; Uart.byteCnt++; - } - else { + } else { return true; } - } - else if(Uart.state != STATE_START_OF_COMMUNICATION) { + } else if (Uart.state != STATE_START_OF_COMMUNICATION) { // When not part of SOF or EOF, it is an error Uart.state = STATE_UNSYNCD; Uart.highCnt = 0; //error = 4; } } - } - else { + } else { // measurement second half bitperiod // Count the bitslot we are in... (ISO 15693) Uart.nOutOfCnt++; - - if(!bit) { - if(Uart.dropPosition) { - if(Uart.state == STATE_START_OF_COMMUNICATION) { + + if (!bit) { + if (Uart.dropPosition) { + if (Uart.state == STATE_START_OF_COMMUNICATION) { //error = 1; - } - else { + } else { //error = 7; } // It is an error if we already have seen a drop in current frame Uart.state = STATE_UNSYNCD; Uart.highCnt = 0; - } - else { + } else { Uart.dropPosition = Uart.nOutOfCnt; } } Uart.posCnt = 0; - - if(Uart.nOutOfCnt == Uart.OutOfCnt && Uart.OutOfCnt == 4) { + + if (Uart.nOutOfCnt == Uart.OutOfCnt && Uart.OutOfCnt == 4) { Uart.nOutOfCnt = 0; - - if(Uart.state == STATE_START_OF_COMMUNICATION) { - if(Uart.dropPosition == 4) { + + if (Uart.state == STATE_START_OF_COMMUNICATION) { + if (Uart.dropPosition == 4) { Uart.state = STATE_RECEIVING; Uart.OutOfCnt = 256; - } - else if(Uart.dropPosition == 3) { + } else if (Uart.dropPosition == 3) { Uart.state = STATE_RECEIVING; Uart.OutOfCnt = 4; //Uart.output[Uart.byteCnt] = 0xdd; //Uart.byteCnt++; - } - else { + } else { Uart.state = STATE_UNSYNCD; Uart.highCnt = 0; } Uart.dropPosition = 0; - } - else { + } else { // RECEIVING DATA // 1 out of 4 - if(!Uart.dropPosition) { + if (!Uart.dropPosition) { Uart.state = STATE_UNSYNCD; Uart.highCnt = 0; //error = 9; - } - else { + } else { Uart.shiftReg >>= 2; - + // Swap bit order Uart.dropPosition--; - //if(Uart.dropPosition == 1) { Uart.dropPosition = 2; } - //else if(Uart.dropPosition == 2) { Uart.dropPosition = 1; } - + //if (Uart.dropPosition == 1) { Uart.dropPosition = 2; } + //else if (Uart.dropPosition == 2) { Uart.dropPosition = 1; } + Uart.shiftReg ^= ((Uart.dropPosition & 0x03) << 6); Uart.bitCnt += 2; Uart.dropPosition = 0; - if(Uart.bitCnt == 8) { + if (Uart.bitCnt == 8) { Uart.output[Uart.byteCnt] = (Uart.shiftReg & 0xff); Uart.byteCnt++; Uart.bitCnt = 0; @@ -229,16 +217,14 @@ static RAMFUNC int OutOfNDecoding(int bit) } } } - } - else if(Uart.nOutOfCnt == Uart.OutOfCnt) { + } else if (Uart.nOutOfCnt == Uart.OutOfCnt) { // RECEIVING DATA // 1 out of 256 - if(!Uart.dropPosition) { + if (!Uart.dropPosition) { Uart.state = STATE_UNSYNCD; Uart.highCnt = 0; //error = 3; - } - else { + } else { Uart.dropPosition--; Uart.output[Uart.byteCnt] = (Uart.dropPosition & 0xff); Uart.byteCnt++; @@ -249,7 +235,7 @@ static RAMFUNC int OutOfNDecoding(int bit) } } - /*if(error) { + /*if (error) { Uart.output[Uart.byteCnt] = 0xAA; Uart.byteCnt++; Uart.output[Uart.byteCnt] = error & 0xFF; @@ -268,35 +254,33 @@ static RAMFUNC int OutOfNDecoding(int bit) }*/ } - } - else { + } else { bit = Uart.bitBuffer & 0xf0; bit >>= 4; bit ^= 0x0F; // drops become 1s ;-) - if(bit) { + if (bit) { // should have been high or at least (4 * 128) / fc // according to ISO this should be at least (9 * 128 + 20) / fc - if(Uart.highCnt == 8) { + if (Uart.highCnt == 8) { // we went low, so this could be start of communication // it turns out to be safer to choose a less significant // syncbit... so we check whether the neighbour also represents the drop Uart.posCnt = 1; // apparently we are busy with our first half bit period Uart.syncBit = bit & 8; Uart.samples = 3; - if(!Uart.syncBit) { Uart.syncBit = bit & 4; Uart.samples = 2; } - else if(bit & 4) { Uart.syncBit = bit & 4; Uart.samples = 2; bit <<= 2; } - if(!Uart.syncBit) { Uart.syncBit = bit & 2; Uart.samples = 1; } - else if(bit & 2) { Uart.syncBit = bit & 2; Uart.samples = 1; bit <<= 1; } - if(!Uart.syncBit) { Uart.syncBit = bit & 1; Uart.samples = 0; - if(Uart.syncBit && (Uart.bitBuffer & 8)) { + if (!Uart.syncBit) { Uart.syncBit = bit & 4; Uart.samples = 2; } + else if (bit & 4) { Uart.syncBit = bit & 4; Uart.samples = 2; bit <<= 2; } + if (!Uart.syncBit) { Uart.syncBit = bit & 2; Uart.samples = 1; } + else if (bit & 2) { Uart.syncBit = bit & 2; Uart.samples = 1; bit <<= 1; } + if (!Uart.syncBit) { Uart.syncBit = bit & 1; Uart.samples = 0; + if (Uart.syncBit && (Uart.bitBuffer & 8)) { Uart.syncBit = 8; // the first half bit period is expected in next sample Uart.posCnt = 0; Uart.samples = 3; } - } - else if(bit & 1) { Uart.syncBit = bit & 1; Uart.samples = 0; } + } else if (bit & 1) { Uart.syncBit = bit & 1; Uart.samples = 0; } Uart.syncBit <<= 4; Uart.state = STATE_START_OF_COMMUNICATION; @@ -307,28 +291,25 @@ static RAMFUNC int OutOfNDecoding(int bit) Uart.dropPosition = 0; Uart.shiftReg = 0; //error = 0; - } - else { + } else { Uart.highCnt = 0; } - } - else { - if(Uart.highCnt < 8) { - Uart.highCnt++; - } + } else if (Uart.highCnt < 8) { + Uart.highCnt++; } } - return false; + return false; } + //============================================================================= // Manchester //============================================================================= static struct { - enum { - DEMOD_UNSYNCD, + enum { + DEMOD_UNSYNCD, DEMOD_START_OF_COMMUNICATION, DEMOD_START_OF_COMMUNICATION2, DEMOD_START_OF_COMMUNICATION3, @@ -338,29 +319,28 @@ static struct { DEMOD_END_OF_COMMUNICATION, DEMOD_END_OF_COMMUNICATION2, DEMOD_MANCHESTER_F, - DEMOD_ERROR_WAIT - } state; - int bitCount; - int posCount; - int syncBit; - uint16_t shiftReg; - int buffer; - int buffer2; - int buffer3; - int buff; - int samples; - int len; + DEMOD_ERROR_WAIT + } state; + int bitCount; + int posCount; + int syncBit; + uint16_t shiftReg; + int buffer; + int buffer2; + int buffer3; + int buff; + int samples; + int len; enum { SUB_NONE, SUB_FIRST_HALF, SUB_SECOND_HALF, SUB_BOTH - } sub; - uint8_t *output; + } sub; + uint8_t *output; } Demod; -static RAMFUNC int ManchesterDecoding(int v) -{ +static RAMFUNC int ManchesterDecoding(int v) { int bit; int modulation; int error = 0; @@ -370,48 +350,48 @@ static RAMFUNC int ManchesterDecoding(int v) Demod.buffer2 = Demod.buffer3; Demod.buffer3 = v; - if(Demod.buff < 3) { + if (Demod.buff < 3) { Demod.buff++; return false; } - if(Demod.state==DEMOD_UNSYNCD) { + if (Demod.state==DEMOD_UNSYNCD) { Demod.output[Demod.len] = 0xfa; Demod.syncBit = 0; //Demod.samples = 0; - Demod.posCount = 1; // This is the first half bit period, so after syncing handle the second part + Demod.posCount = 1; // This is the first half bit period, so after syncing handle the second part - if(bit & 0x08) { + if (bit & 0x08) { Demod.syncBit = 0x08; } - if(bit & 0x04) { - if(Demod.syncBit) { + if (bit & 0x04) { + if (Demod.syncBit) { bit <<= 4; } Demod.syncBit = 0x04; } - if(bit & 0x02) { - if(Demod.syncBit) { + if (bit & 0x02) { + if (Demod.syncBit) { bit <<= 2; } Demod.syncBit = 0x02; } - if(bit & 0x01 && Demod.syncBit) { + if (bit & 0x01 && Demod.syncBit) { Demod.syncBit = 0x01; } - - if(Demod.syncBit) { + + if (Demod.syncBit) { Demod.len = 0; Demod.state = DEMOD_START_OF_COMMUNICATION; Demod.sub = SUB_FIRST_HALF; Demod.bitCount = 0; Demod.shiftReg = 0; Demod.samples = 0; - if(Demod.posCount) { - //if(trigger) LED_A_OFF(); // Not useful in this case... + if (Demod.posCount) { + //if (trigger) LED_A_OFF(); // Not useful in this case... switch(Demod.syncBit) { case 0x08: Demod.samples = 3; break; case 0x04: Demod.samples = 2; break; @@ -419,13 +399,12 @@ static RAMFUNC int ManchesterDecoding(int v) case 0x01: Demod.samples = 0; break; } // SOF must be long burst... otherwise stay unsynced!!! - if(!(Demod.buffer & Demod.syncBit) || !(Demod.buffer2 & Demod.syncBit)) { + if (!(Demod.buffer & Demod.syncBit) || !(Demod.buffer2 & Demod.syncBit)) { Demod.state = DEMOD_UNSYNCD; } - } - else { + } else { // SOF must be long burst... otherwise stay unsynced!!! - if(!(Demod.buffer2 & Demod.syncBit) || !(Demod.buffer3 & Demod.syncBit)) { + if (!(Demod.buffer2 & Demod.syncBit) || !(Demod.buffer3 & Demod.syncBit)) { Demod.state = DEMOD_UNSYNCD; error = 0x88; } @@ -434,53 +413,47 @@ static RAMFUNC int ManchesterDecoding(int v) error = 0; } - } - else { + } else { modulation = bit & Demod.syncBit; modulation |= ((bit << 1) ^ ((Demod.buffer & 0x08) >> 3)) & Demod.syncBit; Demod.samples += 4; - if(Demod.posCount==0) { + if (Demod.posCount==0) { Demod.posCount = 1; - if(modulation) { + if (modulation) { Demod.sub = SUB_FIRST_HALF; - } - else { + } else { Demod.sub = SUB_NONE; } - } - else { + } else { Demod.posCount = 0; /*(modulation && (Demod.sub == SUB_FIRST_HALF)) { - if(Demod.state!=DEMOD_ERROR_WAIT) { + if (Demod.state!=DEMOD_ERROR_WAIT) { Demod.state = DEMOD_ERROR_WAIT; Demod.output[Demod.len] = 0xaa; error = 0x01; } }*/ - //else if(modulation) { - if(modulation) { - if(Demod.sub == SUB_FIRST_HALF) { + //else if (modulation) { + if (modulation) { + if (Demod.sub == SUB_FIRST_HALF) { Demod.sub = SUB_BOTH; - } - else { + } else { Demod.sub = SUB_SECOND_HALF; } - } - else if(Demod.sub == SUB_NONE) { - if(Demod.state == DEMOD_SOF_COMPLETE) { + } else if (Demod.sub == SUB_NONE) { + if (Demod.state == DEMOD_SOF_COMPLETE) { Demod.output[Demod.len] = 0x0f; Demod.len++; Demod.state = DEMOD_UNSYNCD; -// error = 0x0f; +// error = 0x0f; return true; - } - else { + } else { Demod.state = DEMOD_ERROR_WAIT; error = 0x33; } - /*if(Demod.state!=DEMOD_ERROR_WAIT) { + /*if (Demod.state!=DEMOD_ERROR_WAIT) { Demod.state = DEMOD_ERROR_WAIT; Demod.output[Demod.len] = 0xaa; error = 0x01; @@ -489,36 +462,33 @@ static RAMFUNC int ManchesterDecoding(int v) switch(Demod.state) { case DEMOD_START_OF_COMMUNICATION: - if(Demod.sub == SUB_BOTH) { + if (Demod.sub == SUB_BOTH) { //Demod.state = DEMOD_MANCHESTER_D; Demod.state = DEMOD_START_OF_COMMUNICATION2; Demod.posCount = 1; Demod.sub = SUB_NONE; - } - else { + } else { Demod.output[Demod.len] = 0xab; Demod.state = DEMOD_ERROR_WAIT; error = 0xd2; } break; case DEMOD_START_OF_COMMUNICATION2: - if(Demod.sub == SUB_SECOND_HALF) { + if (Demod.sub == SUB_SECOND_HALF) { Demod.state = DEMOD_START_OF_COMMUNICATION3; - } - else { + } else { Demod.output[Demod.len] = 0xab; Demod.state = DEMOD_ERROR_WAIT; error = 0xd3; } break; case DEMOD_START_OF_COMMUNICATION3: - if(Demod.sub == SUB_SECOND_HALF) { -// Demod.state = DEMOD_MANCHESTER_D; + if (Demod.sub == SUB_SECOND_HALF) { +// Demod.state = DEMOD_MANCHESTER_D; Demod.state = DEMOD_SOF_COMPLETE; //Demod.output[Demod.len] = Demod.syncBit & 0xFF; //Demod.len++; - } - else { + } else { Demod.output[Demod.len] = 0xab; Demod.state = DEMOD_ERROR_WAIT; error = 0xd4; @@ -529,20 +499,17 @@ static RAMFUNC int ManchesterDecoding(int v) case DEMOD_MANCHESTER_E: // OPPOSITE FROM ISO14443 - 11110000 = 0 (1 in 14443) // 00001111 = 1 (0 in 14443) - if(Demod.sub == SUB_SECOND_HALF) { // SUB_FIRST_HALF + if (Demod.sub == SUB_SECOND_HALF) { // SUB_FIRST_HALF Demod.bitCount++; Demod.shiftReg = (Demod.shiftReg >> 1) ^ 0x100; Demod.state = DEMOD_MANCHESTER_D; - } - else if(Demod.sub == SUB_FIRST_HALF) { // SUB_SECOND_HALF + } else if (Demod.sub == SUB_FIRST_HALF) { // SUB_SECOND_HALF Demod.bitCount++; Demod.shiftReg >>= 1; Demod.state = DEMOD_MANCHESTER_E; - } - else if(Demod.sub == SUB_BOTH) { + } else if (Demod.sub == SUB_BOTH) { Demod.state = DEMOD_MANCHESTER_F; - } - else { + } else { Demod.state = DEMOD_ERROR_WAIT; error = 0x55; } @@ -550,17 +517,16 @@ static RAMFUNC int ManchesterDecoding(int v) case DEMOD_MANCHESTER_F: // Tag response does not need to be a complete byte! - if(Demod.len > 0 || Demod.bitCount > 0) { - if(Demod.bitCount > 1) { // was > 0, do not interpret last closing bit, is part of EOF - Demod.shiftReg >>= (9 - Demod.bitCount); // right align data + if (Demod.len > 0 || Demod.bitCount > 0) { + if (Demod.bitCount > 1) { // was > 0, do not interpret last closing bit, is part of EOF + Demod.shiftReg >>= (9 - Demod.bitCount); // right align data Demod.output[Demod.len] = Demod.shiftReg & 0xff; Demod.len++; } Demod.state = DEMOD_UNSYNCD; return true; - } - else { + } else { Demod.output[Demod.len] = 0xad; Demod.state = DEMOD_ERROR_WAIT; error = 0x03; @@ -577,7 +543,7 @@ static RAMFUNC int ManchesterDecoding(int v) break; } - /*if(Demod.bitCount>=9) { + /*if (Demod.bitCount>=9) { Demod.output[Demod.len] = Demod.shiftReg & 0xff; Demod.len++; @@ -587,7 +553,7 @@ static RAMFUNC int ManchesterDecoding(int v) Demod.bitCount = 0; Demod.shiftReg = 0; }*/ - if(Demod.bitCount>=8) { + if (Demod.bitCount >= 8) { Demod.shiftReg >>= 1; Demod.output[Demod.len] = (Demod.shiftReg & 0xff); Demod.len++; @@ -595,7 +561,7 @@ static RAMFUNC int ManchesterDecoding(int v) Demod.shiftReg = 0; } - if(error) { + if (error) { Demod.output[Demod.len] = 0xBB; Demod.len++; Demod.output[Demod.len] = error & 0xFF; @@ -620,7 +586,7 @@ static RAMFUNC int ManchesterDecoding(int v) } // end (state != UNSYNCED) - return false; + return false; } //============================================================================= @@ -633,189 +599,185 @@ static RAMFUNC int ManchesterDecoding(int v) // triggering so that we start recording at the point that the tag is moved // near the reader. //----------------------------------------------------------------------------- -void RAMFUNC SnoopIClass(void) -{ +void RAMFUNC SnoopIClass(void) { + // We won't start recording the frames that we acquire until we trigger; + // a good trigger condition to get started is probably when we see a + // response from the tag. + //int triggered = false; // false to wait first for card - // We won't start recording the frames that we acquire until we trigger; - // a good trigger condition to get started is probably when we see a - // response from the tag. - //int triggered = false; // false to wait first for card - - // The command (reader -> tag) that we're receiving. + // The command (reader -> tag) that we're receiving. // The length of a received command will in most cases be no more than 18 bytes. // So 32 should be enough! #define ICLASS_BUFFER_SIZE 32 uint8_t readerToTagCmd[ICLASS_BUFFER_SIZE]; - // The response (tag -> reader) that we're receiving. + // The response (tag -> reader) that we're receiving. uint8_t tagToReaderResponse[ICLASS_BUFFER_SIZE]; - - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - - // free all BigBuf memory + + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + + // free all BigBuf memory BigBuf_free(); - // The DMA buffer, used to stream samples from the FPGA - uint8_t *dmaBuf = BigBuf_malloc(DMA_BUFFER_SIZE); - + // The DMA buffer, used to stream samples from the FPGA + uint8_t *dmaBuf = BigBuf_malloc(DMA_BUFFER_SIZE); + set_tracing(true); clear_trace(); - iso14a_set_trigger(false); + iso14a_set_trigger(false); int lastRxCounter; - uint8_t *upTo; - int smpl; - int maxBehindBy = 0; + uint8_t *upTo; + int smpl; + int maxBehindBy = 0; - // Count of samples received so far, so that we can include timing - // information in the trace buffer. - int samples = 0; - rsamples = 0; + // Count of samples received so far, so that we can include timing + // information in the trace buffer. + int samples = 0; + rsamples = 0; - // Set up the demodulator for tag -> reader responses. + // Set up the demodulator for tag -> reader responses. Demod.output = tagToReaderResponse; - Demod.len = 0; - Demod.state = DEMOD_UNSYNCD; + Demod.len = 0; + Demod.state = DEMOD_UNSYNCD; - // Setup for the DMA. - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_ISO14443A); - upTo = dmaBuf; - lastRxCounter = DMA_BUFFER_SIZE; - FpgaSetupSscDma((uint8_t *)dmaBuf, DMA_BUFFER_SIZE); + // Setup for the DMA. + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_ISO14443A); + upTo = dmaBuf; + lastRxCounter = DMA_BUFFER_SIZE; + FpgaSetupSscDma((uint8_t *)dmaBuf, DMA_BUFFER_SIZE); - // And the reader -> tag commands - memset(&Uart, 0, sizeof(Uart)); + // And the reader -> tag commands + memset(&Uart, 0, sizeof(Uart)); Uart.output = readerToTagCmd; - Uart.byteCntMax = 32; // was 100 (greg)//////////////////////////////////////////////////////////////////////// - Uart.state = STATE_UNSYNCD; + Uart.byteCntMax = 32; // was 100 (greg)//////////////////////////////////////////////////////////////////////// + Uart.state = STATE_UNSYNCD; - // And put the FPGA in the appropriate mode - // Signal field is off with the appropriate LED - LED_D_OFF(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_SNIFFER); - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + // And put the FPGA in the appropriate mode + // Signal field is off with the appropriate LED + LED_D_OFF(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_SNIFFER); + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); uint32_t time_0 = GetCountSspClk(); uint32_t time_start = 0; uint32_t time_stop = 0; - int div = 0; - //int div2 = 0; - int decbyte = 0; - int decbyter = 0; + int div = 0; + //int div2 = 0; + int decbyte = 0; + int decbyter = 0; - // And now we loop, receiving samples. - for(;;) { - LED_A_ON(); - WDT_HIT(); - int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & - (DMA_BUFFER_SIZE-1); - if(behindBy > maxBehindBy) { - maxBehindBy = behindBy; - if(behindBy > (9 * DMA_BUFFER_SIZE / 10)) { - Dbprintf("blew circular buffer! behindBy=0x%x", behindBy); - goto done; - } - } - if(behindBy < 1) continue; - - LED_A_OFF(); - smpl = upTo[0]; - upTo++; - lastRxCounter -= 1; - if(upTo - dmaBuf > DMA_BUFFER_SIZE) { - upTo -= DMA_BUFFER_SIZE; - lastRxCounter += DMA_BUFFER_SIZE; - AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) upTo; - AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; - } - - //samples += 4; - samples += 1; - - if(smpl & 0xF) { - decbyte ^= (1 << (3 - div)); - } - - // FOR READER SIDE COMMUMICATION... - - decbyter <<= 2; - decbyter ^= (smpl & 0x30); - - div++; - - if((div + 1) % 2 == 0) { - smpl = decbyter; - if(OutOfNDecoding((smpl & 0xF0) >> 4)) { - rsamples = samples - Uart.samples; - time_stop = (GetCountSspClk()-time_0) << 4; - LED_C_ON(); - - //if(!LogTrace(Uart.output,Uart.byteCnt, rsamples, Uart.parityBits,true)) break; - //if(!LogTrace(NULL, 0, Uart.endTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, 0, true)) break; - uint8_t parity[MAX_PARITY_SIZE]; - GetParity(Uart.output, Uart.byteCnt, parity); - LogTrace(Uart.output,Uart.byteCnt, time_start, time_stop, parity, true); - - /* And ready to receive another command. */ - Uart.state = STATE_UNSYNCD; - /* And also reset the demod code, which might have been */ - /* false-triggered by the commands from the reader. */ - Demod.state = DEMOD_UNSYNCD; - LED_B_OFF(); - Uart.byteCnt = 0; - }else{ - time_start = (GetCountSspClk()-time_0) << 4; + // And now we loop, receiving samples. + for (;;) { + LED_A_ON(); + WDT_HIT(); + int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & (DMA_BUFFER_SIZE-1); + if (behindBy > maxBehindBy) { + maxBehindBy = behindBy; + if (behindBy > (9 * DMA_BUFFER_SIZE / 10)) { + Dbprintf("blew circular buffer! behindBy=0x%x", behindBy); + goto done; + } } - decbyter = 0; - } + if (behindBy < 1) continue; - if(div > 3) { - smpl = decbyte; - if(ManchesterDecoding(smpl & 0x0F)) { - time_stop = (GetCountSspClk()-time_0) << 4; - - rsamples = samples - Demod.samples; - LED_B_ON(); - - uint8_t parity[MAX_PARITY_SIZE]; - GetParity(Demod.output, Demod.len, parity); - LogTrace(Demod.output, Demod.len, time_start, time_stop, parity, false); - - // And ready to receive another response. - memset(&Demod, 0, sizeof(Demod)); - Demod.output = tagToReaderResponse; - Demod.state = DEMOD_UNSYNCD; - LED_C_OFF(); - }else{ - time_start = (GetCountSspClk()-time_0) << 4; + LED_A_OFF(); + smpl = upTo[0]; + upTo++; + lastRxCounter -= 1; + if (upTo - dmaBuf > DMA_BUFFER_SIZE) { + upTo -= DMA_BUFFER_SIZE; + lastRxCounter += DMA_BUFFER_SIZE; + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) upTo; + AT91C_BASE_PDC_SSC->PDC_RNCR = DMA_BUFFER_SIZE; + } + + //samples += 4; + samples += 1; + + if (smpl & 0xF) { + decbyte ^= (1 << (3 - div)); + } + + // FOR READER SIDE COMMUMICATION... + + decbyter <<= 2; + decbyter ^= (smpl & 0x30); + + div++; + + if ((div + 1) % 2 == 0) { + smpl = decbyter; + if (OutOfNDecoding((smpl & 0xF0) >> 4)) { + rsamples = samples - Uart.samples; + time_stop = (GetCountSspClk()-time_0) << 4; + LED_C_ON(); + + //if (!LogTrace(Uart.output, Uart.byteCnt, rsamples, Uart.parityBits,true)) break; + //if (!LogTrace(NULL, 0, Uart.endTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, 0, true)) break; + uint8_t parity[MAX_PARITY_SIZE]; + GetParity(Uart.output, Uart.byteCnt, parity); + LogTrace(Uart.output, Uart.byteCnt, time_start, time_stop, parity, true); + + /* And ready to receive another command. */ + Uart.state = STATE_UNSYNCD; + /* And also reset the demod code, which might have been */ + /* false-triggered by the commands from the reader. */ + Demod.state = DEMOD_UNSYNCD; + LED_B_OFF(); + Uart.byteCnt = 0; + } else { + time_start = (GetCountSspClk()-time_0) << 4; + } + decbyter = 0; + } + + if (div > 3) { + smpl = decbyte; + if (ManchesterDecoding(smpl & 0x0F)) { + time_stop = (GetCountSspClk()-time_0) << 4; + + rsamples = samples - Demod.samples; + LED_B_ON(); + + uint8_t parity[MAX_PARITY_SIZE]; + GetParity(Demod.output, Demod.len, parity); + LogTrace(Demod.output, Demod.len, time_start, time_stop, parity, false); + + // And ready to receive another response. + memset(&Demod, 0, sizeof(Demod)); + Demod.output = tagToReaderResponse; + Demod.state = DEMOD_UNSYNCD; + LED_C_OFF(); + } else { + time_start = (GetCountSspClk()-time_0) << 4; + } + + div = 0; + decbyte = 0x00; + } + + if (BUTTON_PRESS()) { + DbpString("cancelled_a"); + goto done; } - - div = 0; - decbyte = 0x00; } - //} - if(BUTTON_PRESS()) { - DbpString("cancelled_a"); - goto done; - } - } + DbpString("COMMAND FINISHED"); - DbpString("COMMAND FINISHED"); - - Dbprintf("%x %x %x", maxBehindBy, Uart.state, Uart.byteCnt); + Dbprintf("%x %x %x", maxBehindBy, Uart.state, Uart.byteCnt); Dbprintf("%x %x %x", Uart.byteCntMax, BigBuf_get_traceLen(), (int)Uart.output[0]); done: - AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; - Dbprintf("%x %x %x", maxBehindBy, Uart.state, Uart.byteCnt); + AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; + Dbprintf("%x %x %x", maxBehindBy, Uart.state, Uart.byteCnt); Dbprintf("%x %x %x", Uart.byteCntMax, BigBuf_get_traceLen(), (int)Uart.output[0]); - LEDsoff(); + LEDsoff(); } void rotateCSN(uint8_t* originalCSN, uint8_t* rotatedCSN) { - int i; - for(i = 0; i < 8; i++) { + int i; + for (i = 0; i < 8; i++) { rotatedCSN[i] = (originalCSN[i] >> 3) | (originalCSN[(i+1)%8] << 5); } } @@ -827,38 +789,37 @@ void rotateCSN(uint8_t* originalCSN, uint8_t* rotatedCSN) { //----------------------------------------------------------------------------- static int GetIClassCommandFromReader(uint8_t *received, int *len, int maxLen) { - // Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen - // only, since we are receiving, not transmitting). - // Signal field is off with the appropriate LED - LED_D_OFF(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN); + // Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen + // only, since we are receiving, not transmitting). + // Signal field is off with the appropriate LED + LED_D_OFF(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN); - // Now run a `software UART' on the stream of incoming samples. - Uart.output = received; - Uart.byteCntMax = maxLen; - Uart.state = STATE_UNSYNCD; + // Now run a `software UART' on the stream of incoming samples. + Uart.output = received; + Uart.byteCntMax = maxLen; + Uart.state = STATE_UNSYNCD; - for(;;) { - WDT_HIT(); + for (;;) { + WDT_HIT(); - if(BUTTON_PRESS()) return false; + if (BUTTON_PRESS()) return false; - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0x00; - } - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0x00; + } + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - if(OutOfNDecoding(b & 0x0f)) { + if (OutOfNDecoding(b & 0x0f)) { *len = Uart.byteCnt; return true; } - } - } + } + } } -static uint8_t encode4Bits(const uint8_t b) -{ +static uint8_t encode4Bits(const uint8_t b) { uint8_t c = b & 0xF; // OTA, the least significant bits first // The columns are @@ -892,13 +853,12 @@ static uint8_t encode4Bits(const uint8_t b) //----------------------------------------------------------------------------- // Prepare tag messages //----------------------------------------------------------------------------- -static void CodeIClassTagAnswer(const uint8_t *cmd, int len) -{ +static void CodeIClassTagAnswer(const uint8_t *cmd, int len) { /* * SOF comprises 3 parts; * * An unmodulated time of 56.64 us - * * 24 pulses of 423.75 KHz (fc/32) + * * 24 pulses of 423.75 kHz (fc/32) * * A logic 1, which starts with an unmodulated time of 18.88us * followed by 8 pulses of 423.75kHz (fc/32) * @@ -919,7 +879,7 @@ static void CodeIClassTagAnswer(const uint8_t *cmd, int len) * The mode FPGA_HF_SIMULATOR_MODULATE_424K_8BIT which we use to simulate tag, * works like this. * - A 1-bit input to the FPGA becomes 8 pulses on 423.5kHz (fc/32) (18.88us). - * - A 0-bit inptu to the FPGA becomes an unmodulated time of 18.88us + * - A 0-bit input to the FPGA becomes an unmodulated time of 18.88us * * In this mode the SOF can be written as 00011101 = 0x1D * The EOF can be written as 10111000 = 0xb8 @@ -935,10 +895,10 @@ static void CodeIClassTagAnswer(const uint8_t *cmd, int len) // Send SOF ToSend[++ToSendMax] = 0x1D; - for(i = 0; i < len; i++) { + for (i = 0; i < len; i++) { uint8_t b = cmd[i]; - ToSend[++ToSendMax] = encode4Bits(b & 0xF); //Least significant half - ToSend[++ToSendMax] = encode4Bits((b >>4) & 0xF);//Most significant half + ToSend[++ToSendMax] = encode4Bits(b & 0xF); // Least significant half + ToSend[++ToSendMax] = encode4Bits((b >>4) & 0xF); // Most significant half } // Send EOF @@ -948,123 +908,87 @@ static void CodeIClassTagAnswer(const uint8_t *cmd, int len) ToSendMax++; } -// Only SOF -static void CodeIClassTagSOF() -{ +// Only SOF +static void CodeIClassTagSOF() { //So far a dummy implementation, not used //int lastProxToAirDuration =0; ToSendReset(); // Send SOF ToSend[++ToSendMax] = 0x1D; -// lastProxToAirDuration = 8*ToSendMax - 3*8;//Not counting zeroes in the beginning +// lastProxToAirDuration = 8*ToSendMax - 3*8;//Not counting zeroes in the beginning // Convert from last byte pos to length ToSendMax++; } + +static void AppendCrc(uint8_t *data, int len) { + ComputeCrc14443(CRC_ICLASS, data, len, data+len, data+len+1); +} + +static int SendIClassAnswer(uint8_t *resp, int respLen, int delay) { + int i = 0, d = 0;//, u = 0, d = 0; + uint8_t b = 0; + + //FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR|FPGA_HF_SIMULATOR_MODULATE_424K); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_424K_8BIT); + + AT91C_BASE_SSC->SSC_THR = 0x00; + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR); + while (!BUTTON_PRESS()) { + if ((AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)){ + b = AT91C_BASE_SSC->SSC_RHR; (void) b; + } + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)){ + b = 0x00; + if (d < delay) { + d++; + } + else { + if (i < respLen) { + b = resp[i]; + //Hack + //b = 0xAC; + } + i++; + } + AT91C_BASE_SSC->SSC_THR = b; + } + +// if (i > respLen +4) break; + if (i > respLen + 1) break; + } + + return 0; +} + + #define MODE_SIM_CSN 0 #define MODE_EXIT_AFTER_MAC 1 #define MODE_FULLSIM 2 -int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf); -/** - * @brief SimulateIClass simulates an iClass card. - * @param arg0 type of simulation - * - 0 uses the first 8 bytes in usb data as CSN - * - 2 "dismantling iclass"-attack. This mode iterates through all CSN's specified - * in the usb data. This mode collects MAC from the reader, in order to do an offline - * attack on the keys. For more info, see "dismantling iclass" and proxclone.com. - * - Other : Uses the default CSN (031fec8af7ff12e0) - * @param arg1 - number of CSN's contained in datain (applicable for mode 2 only) - * @param arg2 - * @param datain - */ -void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain) -{ - uint32_t simType = arg0; - uint32_t numberOfCSNS = arg1; - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - - // Enable and clear the trace - set_tracing(true); - clear_trace(); - //Use the emulator memory for SIM - uint8_t *emulator = BigBuf_get_EM_addr(); - - if(simType == 0) { - // Use the CSN from commandline - memcpy(emulator, datain, 8); - doIClassSimulation(MODE_SIM_CSN,NULL); - }else if(simType == 1) - { - //Default CSN - uint8_t csn_crc[] = { 0x03, 0x1f, 0xec, 0x8a, 0xf7, 0xff, 0x12, 0xe0, 0x00, 0x00 }; - // Use the CSN from commandline - memcpy(emulator, csn_crc, 8); - doIClassSimulation(MODE_SIM_CSN,NULL); - } - else if(simType == 2) - { - - uint8_t mac_responses[USB_CMD_DATA_SIZE] = { 0 }; - Dbprintf("Going into attack mode, %d CSNS sent", numberOfCSNS); - // In this mode, a number of csns are within datain. We'll simulate each one, one at a time - // in order to collect MAC's from the reader. This can later be used in an offlne-attack - // in order to obtain the keys, as in the "dismantling iclass"-paper. - int i = 0; - for( ; i < numberOfCSNS && i*8+8 < USB_CMD_DATA_SIZE; i++) - { - // The usb data is 512 bytes, fitting 65 8-byte CSNs in there. - - memcpy(emulator, datain+(i*8), 8); - if(doIClassSimulation(MODE_EXIT_AFTER_MAC,mac_responses+i*8)) - { - cmd_send(CMD_ACK,CMD_SIMULATE_TAG_ICLASS,i,0,mac_responses,i*8); - return; // Button pressed - } - } - cmd_send(CMD_ACK,CMD_SIMULATE_TAG_ICLASS,i,0,mac_responses,i*8); - - }else if(simType == 3){ - //This is 'full sim' mode, where we use the emulator storage for data. - doIClassSimulation(MODE_FULLSIM, NULL); - } - else{ - // We may want a mode here where we hardcode the csns to use (from proxclone). - // That will speed things up a little, but not required just yet. - Dbprintf("The mode is not implemented, reserved for future use"); - } - Dbprintf("Done..."); - -} -void AppendCrc(uint8_t* data, int len) -{ - ComputeCrc14443(CRC_ICLASS,data,len,data+len,data+len+1); -} - /** * @brief Does the actual simulation * @param csn - csn to use * @param breakAfterMacReceived if true, returns after reader MAC has been received. */ -int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf) -{ +int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { // free eventually allocated BigBuf memory BigBuf_free_keep_EM(); State cipher_state; -// State cipher_state_reserve; +// State cipher_state_reserve; uint8_t *csn = BigBuf_get_EM_addr(); uint8_t *emulator = csn; uint8_t sof_data[] = { 0x0F} ; // CSN followed by two CRC bytes uint8_t anticoll_data[10] = { 0 }; uint8_t csn_data[10] = { 0 }; - memcpy(csn_data,csn,sizeof(csn_data)); - Dbprintf("Simulating CSN %02x%02x%02x%02x%02x%02x%02x%02x",csn[0],csn[1],csn[2],csn[3],csn[4],csn[5],csn[6],csn[7]); + memcpy(csn_data, csn, sizeof(csn_data)); + Dbprintf("Simulating CSN %02x%02x%02x%02x%02x%02x%02x%02x", csn[0], csn[1], csn[2], csn[3], csn[4], csn[5], csn[6], csn[7]); // Construct anticollision-CSN - rotateCSN(csn_data,anticoll_data); + rotateCSN(csn_data, anticoll_data); // Compute CRC on both CSNs ComputeCrc14443(CRC_ICLASS, anticoll_data, 8, &anticoll_data[8], &anticoll_data[9]); @@ -1073,17 +997,14 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf) uint8_t diversified_key[8] = { 0 }; // e-Purse uint8_t card_challenge_data[8] = { 0x00 }; - if(simulationMode == MODE_FULLSIM) - { + if (simulationMode == MODE_FULLSIM) { //The diversified key should be stored on block 3 //Get the diversified key from emulator memory - memcpy(diversified_key, emulator+(8*3),8); - + memcpy(diversified_key, emulator + (8*3), 8); //Card challenge, a.k.a e-purse is on block 2 - memcpy(card_challenge_data,emulator + (8 * 2) , 8); + memcpy(card_challenge_data, emulator + (8 * 2), 8); //Precalculate the cipher state, feeding it the CC - cipher_state = opt_doTagMAC_1(card_challenge_data,diversified_key); - + cipher_state = opt_doTagMAC_1(card_challenge_data, diversified_key); } int exitLoop = 0; @@ -1096,10 +1017,9 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf) uint8_t *modulated_response; int modulated_response_size = 0; - uint8_t* trace_data = NULL; + uint8_t *trace_data = NULL; int trace_data_size = 0; - // Respond SOF -- takes 1 bytes uint8_t *resp_sof = BigBuf_malloc(2); int resp_sof_Len; @@ -1127,15 +1047,18 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf) // First card answer: SOF CodeIClassTagSOF(); - memcpy(resp_sof, ToSend, ToSendMax); resp_sof_Len = ToSendMax; + memcpy(resp_sof, ToSend, ToSendMax); + resp_sof_Len = ToSendMax; // Anticollision CSN CodeIClassTagAnswer(anticoll_data, sizeof(anticoll_data)); - memcpy(resp_anticoll, ToSend, ToSendMax); resp_anticoll_len = ToSendMax; + memcpy(resp_anticoll, ToSend, ToSendMax); + resp_anticoll_len = ToSendMax; // CSN CodeIClassTagAnswer(csn_data, sizeof(csn_data)); - memcpy(resp_csn, ToSend, ToSendMax); resp_csn_len = ToSendMax; + memcpy(resp_csn, ToSend, ToSendMax); + resp_csn_len = ToSendMax; // e-Purse CodeIClassTagAnswer(card_challenge_data, sizeof(card_challenge_data)); @@ -1167,14 +1090,14 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf) LED_A_ON(); bool buttonPressed = false; uint8_t response_delay = 1; - while(!exitLoop) { + while (!exitLoop) { response_delay = 1; LED_B_OFF(); //Signal tracer // Can be used to get a trigger for an oscilloscope.. LED_C_OFF(); - if(!GetIClassCommandFromReader(receivedCmd, &len, 100)) { + if (!GetIClassCommandFromReader(receivedCmd, &len, 100)) { buttonPressed = true; break; } @@ -1183,52 +1106,55 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf) LED_C_ON(); // Okay, look at the command now. - if(receivedCmd[0] == ICLASS_CMD_ACTALL ) { + if (receivedCmd[0] == ICLASS_CMD_ACTALL) { // Reader in anticollission phase - modulated_response = resp_sof; modulated_response_size = resp_sof_Len; //order = 1; + modulated_response = resp_sof; + modulated_response_size = resp_sof_Len; //order = 1; trace_data = sof_data; trace_data_size = sizeof(sof_data); - } else if(receivedCmd[0] == ICLASS_CMD_READ_OR_IDENTIFY && len == 1) { + } else if (receivedCmd[0] == ICLASS_CMD_READ_OR_IDENTIFY && len == 1) { // Reader asks for anticollission CSN - modulated_response = resp_anticoll; modulated_response_size = resp_anticoll_len; //order = 2; + modulated_response = resp_anticoll; + modulated_response_size = resp_anticoll_len; //order = 2; trace_data = anticoll_data; trace_data_size = sizeof(anticoll_data); //DbpString("Reader requests anticollission CSN:"); - } else if(receivedCmd[0] == ICLASS_CMD_SELECT) { + } else if (receivedCmd[0] == ICLASS_CMD_SELECT) { // Reader selects anticollission CSN. // Tag sends the corresponding real CSN - modulated_response = resp_csn; modulated_response_size = resp_csn_len; //order = 3; + modulated_response = resp_csn; + modulated_response_size = resp_csn_len; //order = 3; trace_data = csn_data; trace_data_size = sizeof(csn_data); //DbpString("Reader selects anticollission CSN:"); - } else if(receivedCmd[0] == ICLASS_CMD_READCHECK_KD) { + } else if (receivedCmd[0] == ICLASS_CMD_READCHECK_KD) { // Read e-purse (88 02) - modulated_response = resp_cc; modulated_response_size = resp_cc_len; //order = 4; + modulated_response = resp_cc; + modulated_response_size = resp_cc_len; //order = 4; trace_data = card_challenge_data; trace_data_size = sizeof(card_challenge_data); LED_B_ON(); - } else if(receivedCmd[0] == ICLASS_CMD_CHECK) { + } else if (receivedCmd[0] == ICLASS_CMD_CHECK) { // Reader random and reader MAC!!! - if(simulationMode == MODE_FULLSIM) - { + if (simulationMode == MODE_FULLSIM) { //NR, from reader, is in receivedCmd +1 - opt_doTagMAC_2(cipher_state,receivedCmd+1,data_generic_trace,diversified_key); + opt_doTagMAC_2(cipher_state, receivedCmd+1, data_generic_trace, diversified_key); trace_data = data_generic_trace; trace_data_size = 4; - CodeIClassTagAnswer(trace_data , trace_data_size); + CodeIClassTagAnswer(trace_data, trace_data_size); memcpy(data_response, ToSend, ToSendMax); modulated_response = data_response; modulated_response_size = ToSendMax; response_delay = 0;//We need to hurry here... //exitLoop = true; - }else - { //Not fullsim, we don't respond + } else { //Not fullsim, we don't respond // We do not know what to answer, so lets keep quiet - modulated_response = resp_sof; modulated_response_size = 0; + modulated_response = resp_sof; + modulated_response_size = 0; trace_data = NULL; trace_data_size = 0; - if (simulationMode == MODE_EXIT_AFTER_MAC){ + if (simulationMode == MODE_EXIT_AFTER_MAC) { // dbprintf:ing ... Dbprintf("CSN: %02x %02x %02x %02x %02x %02x %02x %02x" ,csn[0],csn[1],csn[2],csn[3],csn[4],csn[5],csn[6],csn[7]); @@ -1236,57 +1162,55 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf) receivedCmd[0], receivedCmd[1], receivedCmd[2], receivedCmd[3], receivedCmd[4], receivedCmd[5], receivedCmd[6], receivedCmd[7], receivedCmd[8]); - if (reader_mac_buf != NULL) - { - memcpy(reader_mac_buf,receivedCmd+1,8); + if (reader_mac_buf != NULL) { + memcpy(reader_mac_buf, receivedCmd+1, 8); } exitLoop = true; } } - } else if(receivedCmd[0] == ICLASS_CMD_HALT && len == 1) { + } else if (receivedCmd[0] == ICLASS_CMD_HALT && len == 1) { // Reader ends the session - modulated_response = resp_sof; modulated_response_size = 0; //order = 0; + modulated_response = resp_sof; + modulated_response_size = 0; //order = 0; trace_data = NULL; trace_data_size = 0; - } else if(simulationMode == MODE_FULLSIM && receivedCmd[0] == ICLASS_CMD_READ_OR_IDENTIFY && len == 4){ + } else if (simulationMode == MODE_FULLSIM && receivedCmd[0] == ICLASS_CMD_READ_OR_IDENTIFY && len == 4) { //Read block uint16_t blk = receivedCmd[1]; //Take the data... - memcpy(data_generic_trace, emulator+(blk << 3),8); + memcpy(data_generic_trace, emulator + (blk << 3), 8); //Add crc AppendCrc(data_generic_trace, 8); trace_data = data_generic_trace; trace_data_size = 10; - CodeIClassTagAnswer(trace_data , trace_data_size); + CodeIClassTagAnswer(trace_data, trace_data_size); memcpy(data_response, ToSend, ToSendMax); modulated_response = data_response; modulated_response_size = ToSendMax; - }else if(receivedCmd[0] == ICLASS_CMD_UPDATE && simulationMode == MODE_FULLSIM) - {//Probably the reader wants to update the nonce. Let's just ignore that for now. + } else if (receivedCmd[0] == ICLASS_CMD_UPDATE && simulationMode == MODE_FULLSIM) { + //Probably the reader wants to update the nonce. Let's just ignore that for now. // OBS! If this is implemented, don't forget to regenerate the cipher_state //We're expected to respond with the data+crc, exactly what's already in the receivedcmd //receivedcmd is now UPDATE 1b | ADDRESS 1b| DATA 8b| Signature 4b or CRC 2b| //Take the data... - memcpy(data_generic_trace, receivedCmd+2,8); + memcpy(data_generic_trace, receivedCmd+2, 8); //Add crc AppendCrc(data_generic_trace, 8); trace_data = data_generic_trace; trace_data_size = 10; - CodeIClassTagAnswer(trace_data , trace_data_size); + CodeIClassTagAnswer(trace_data, trace_data_size); memcpy(data_response, ToSend, ToSendMax); modulated_response = data_response; modulated_response_size = ToSendMax; - } - else if(receivedCmd[0] == ICLASS_CMD_PAGESEL) - {//Pagesel + } else if (receivedCmd[0] == ICLASS_CMD_PAGESEL) { + //Pagesel //Pagesel enables to select a page in the selected chip memory and return its configuration block //Chips with a single page will not answer to this command // It appears we're fine ignoring this. //Otherwise, we should answer 8bytes (block) + 2bytes CRC - } - else { + } else { //#db# Unknown command received from reader (len=5): 26 1 0 f6 a 44 44 44 44 // Never seen this command before Dbprintf("Unknown command received from reader (len=%d): %x %x %x %x %x %x %x %x %x", @@ -1295,35 +1219,35 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf) receivedCmd[3], receivedCmd[4], receivedCmd[5], receivedCmd[6], receivedCmd[7], receivedCmd[8]); // Do not respond - modulated_response = resp_sof; modulated_response_size = 0; //order = 0; + modulated_response = resp_sof; + modulated_response_size = 0; //order = 0; trace_data = NULL; trace_data_size = 0; } - if(cmdsRecvd > 100) { + if (cmdsRecvd > 100) { //DbpString("100 commands later..."); //break; - } - else { + } else { cmdsRecvd++; } /** A legit tag has about 380us delay between reader EOT and tag SOF. **/ - if(modulated_response_size > 0) { + if (modulated_response_size > 0) { SendIClassAnswer(modulated_response, modulated_response_size, response_delay); t2r_time = GetCountSspClk(); } uint8_t parity[MAX_PARITY_SIZE]; GetParity(receivedCmd, len, parity); - LogTrace(receivedCmd,len, (r2t_time-time_0)<< 4, (r2t_time-time_0) << 4, parity, true); + LogTrace(receivedCmd, len, (r2t_time-time_0) << 4, (r2t_time-time_0) << 4, parity, true); if (trace_data != NULL) { GetParity(trace_data, trace_data_size, parity); LogTrace(trace_data, trace_data_size, (t2r_time-time_0) << 4, (t2r_time-time_0) << 4, parity, false); } - if(!get_tracing()) { + if (!get_tracing()) { DbpString("Trace full"); //break; } @@ -1334,168 +1258,184 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf) LED_B_OFF(); LED_C_OFF(); - if(buttonPressed) + if (buttonPressed) { DbpString("Button pressed"); } return buttonPressed; } -static int SendIClassAnswer(uint8_t *resp, int respLen, int delay) -{ - int i = 0, d=0;//, u = 0, d = 0; - uint8_t b = 0; +/** + * @brief SimulateIClass simulates an iClass card. + * @param arg0 type of simulation + * - 0 uses the first 8 bytes in usb data as CSN + * - 2 "dismantling iclass"-attack. This mode iterates through all CSN's specified + * in the usb data. This mode collects MAC from the reader, in order to do an offline + * attack on the keys. For more info, see "dismantling iclass" and proxclone.com. + * - Other : Uses the default CSN (031fec8af7ff12e0) + * @param arg1 - number of CSN's contained in datain (applicable for mode 2 only) + * @param arg2 + * @param datain + */ +void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain) { + uint32_t simType = arg0; + uint32_t numberOfCSNS = arg1; + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - //FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR|FPGA_HF_SIMULATOR_MODULATE_424K); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR|FPGA_HF_SIMULATOR_MODULATE_424K_8BIT); + // Enable and clear the trace + set_tracing(true); + clear_trace(); + //Use the emulator memory for SIM + uint8_t *emulator = BigBuf_get_EM_addr(); - AT91C_BASE_SSC->SSC_THR = 0x00; - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR); - while(!BUTTON_PRESS()) { - if((AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)){ - b = AT91C_BASE_SSC->SSC_RHR; (void) b; - } - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)){ - b = 0x00; - if(d < delay) { - d++; + if (simType == 0) { + // Use the CSN from commandline + memcpy(emulator, datain, 8); + doIClassSimulation(MODE_SIM_CSN,NULL); + } else if (simType == 1) { + //Default CSN + uint8_t csn_crc[] = { 0x03, 0x1f, 0xec, 0x8a, 0xf7, 0xff, 0x12, 0xe0, 0x00, 0x00 }; + // Use the CSN from commandline + memcpy(emulator, csn_crc, 8); + doIClassSimulation(MODE_SIM_CSN,NULL); + } else if (simType == 2) { + uint8_t mac_responses[USB_CMD_DATA_SIZE] = { 0 }; + Dbprintf("Going into attack mode, %d CSNS sent", numberOfCSNS); + // In this mode, a number of csns are within datain. We'll simulate each one, one at a time + // in order to collect MAC's from the reader. This can later be used in an offlne-attack + // in order to obtain the keys, as in the "dismantling iclass"-paper. + int i = 0; + for ( ; i < numberOfCSNS && i*8+8 < USB_CMD_DATA_SIZE; i++) { + // The usb data is 512 bytes, fitting 65 8-byte CSNs in there. + memcpy(emulator, datain+(i*8), 8); + if (doIClassSimulation(MODE_EXIT_AFTER_MAC,mac_responses+i*8)) { + cmd_send(CMD_ACK, CMD_SIMULATE_TAG_ICLASS, i, 0, mac_responses, i*8); + return; // Button pressed } - else { - if( i < respLen){ - b = resp[i]; - //Hack - //b = 0xAC; - } - i++; - } - AT91C_BASE_SSC->SSC_THR = b; } - -// if (i > respLen +4) break; - if (i > respLen +1) break; + cmd_send(CMD_ACK, CMD_SIMULATE_TAG_ICLASS, i, 0, mac_responses, i*8); + } else if (simType == 3) { + //This is 'full sim' mode, where we use the emulator storage for data. + doIClassSimulation(MODE_FULLSIM, NULL); + } else { + // We may want a mode here where we hardcode the csns to use (from proxclone). + // That will speed things up a little, but not required just yet. + Dbprintf("The mode is not implemented, reserved for future use"); } + Dbprintf("Done..."); - return 0; } + /// THE READER CODE //----------------------------------------------------------------------------- // Transmit the command (to the tag) that was placed in ToSend[]. //----------------------------------------------------------------------------- -static void TransmitIClassCommand(const uint8_t *cmd, int len, int *samples, int *wait) -{ - int c; - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); - AT91C_BASE_SSC->SSC_THR = 0x00; - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_ISO14443A); +static void TransmitIClassCommand(const uint8_t *cmd, int len, int *samples, int *wait) { + int c; + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); + AT91C_BASE_SSC->SSC_THR = 0x00; + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_ISO14443A); - if (wait) - { - if(*wait < 10) *wait = 10; - - for(c = 0; c < *wait;) { - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0x00; // For exact timing! - c++; - } - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR; - (void)r; - } - WDT_HIT(); - } + if (wait) { + if (*wait < 10) *wait = 10; - } + for (c = 0; c < *wait;) { + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0x00; // For exact timing! + c++; + } + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR; + (void)r; + } + WDT_HIT(); + } + } + uint8_t sendbyte; + bool firstpart = true; + c = 0; + for (;;) { + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - uint8_t sendbyte; - bool firstpart = true; - c = 0; - for(;;) { - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + // DOUBLE THE SAMPLES! + if (firstpart) { + sendbyte = (cmd[c] & 0xf0) | (cmd[c] >> 4); + } else { + sendbyte = (cmd[c] & 0x0f) | (cmd[c] << 4); + c++; + } + if (sendbyte == 0xff) { + sendbyte = 0xfe; + } + AT91C_BASE_SSC->SSC_THR = sendbyte; + firstpart = !firstpart; - // DOUBLE THE SAMPLES! - if(firstpart) { - sendbyte = (cmd[c] & 0xf0) | (cmd[c] >> 4); - } - else { - sendbyte = (cmd[c] & 0x0f) | (cmd[c] << 4); - c++; - } - if(sendbyte == 0xff) { - sendbyte = 0xfe; - } - AT91C_BASE_SSC->SSC_THR = sendbyte; - firstpart = !firstpart; - - if(c >= len) { - break; - } - } - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR; - (void)r; - } - WDT_HIT(); - } - if (samples && wait) *samples = (c + *wait) << 3; + if (c >= len) { + break; + } + } + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR; + (void)r; + } + WDT_HIT(); + } + if (samples && wait) *samples = (c + *wait) << 3; } //----------------------------------------------------------------------------- // Prepare iClass reader command to send to FPGA //----------------------------------------------------------------------------- -void CodeIClassCommand(const uint8_t * cmd, int len) -{ - int i, j, k; - uint8_t b; +void CodeIClassCommand(const uint8_t *cmd, int len) { + int i, j, k; - ToSendReset(); + ToSendReset(); - // Start of Communication: 1 out of 4 - ToSend[++ToSendMax] = 0xf0; - ToSend[++ToSendMax] = 0x00; - ToSend[++ToSendMax] = 0x0f; - ToSend[++ToSendMax] = 0x00; + // Start of Communication: 1 out of 4 + ToSend[++ToSendMax] = 0xf0; + ToSend[++ToSendMax] = 0x00; + ToSend[++ToSendMax] = 0x0f; + ToSend[++ToSendMax] = 0x00; - // Modulate the bytes - for (i = 0; i < len; i++) { - b = cmd[i]; - for(j = 0; j < 4; j++) { - for(k = 0; k < 4; k++) { - if(k == (b & 3)) { - ToSend[++ToSendMax] = 0xf0; + // Modulate the bytes + for (i = 0; i < len; i++) { + uint8_t b = cmd[i]; + for (j = 0; j < 4; j++) { + for (k = 0; k < 4; k++) { + if (k == (b & 3)) { + ToSend[++ToSendMax] = 0xf0; + } else { + ToSend[++ToSendMax] = 0x00; + } } - else { - ToSend[++ToSendMax] = 0x00; - } - } - b >>= 2; - } - } + b >>= 2; + } + } - // End of Communication - ToSend[++ToSendMax] = 0x00; - ToSend[++ToSendMax] = 0x00; - ToSend[++ToSendMax] = 0xf0; - ToSend[++ToSendMax] = 0x00; + // End of Communication + ToSend[++ToSendMax] = 0x00; + ToSend[++ToSendMax] = 0x00; + ToSend[++ToSendMax] = 0xf0; + ToSend[++ToSendMax] = 0x00; - // Convert from last character reference to length - ToSendMax++; + // Convert from last character reference to length + ToSendMax++; } -void ReaderTransmitIClass(uint8_t* frame, int len) -{ +static void ReaderTransmitIClass(uint8_t *frame, int len) { int wait = 0; int samples = 0; // This is tied to other size changes - CodeIClassCommand(frame,len); + CodeIClassCommand(frame, len); // Select the card TransmitIClassCommand(ToSend, ToSendMax, &samples, &wait); - if(trigger) + if (trigger) LED_A_ON(); // Store reader command in buffer @@ -1509,8 +1449,8 @@ void ReaderTransmitIClass(uint8_t* frame, int len) // If a response is captured return true // If it takes too long return false //----------------------------------------------------------------------------- -static int GetIClassAnswer(uint8_t *receivedResponse, int maxLen, int *samples, int *elapsed) //uint8_t *buffer -{ +static int GetIClassAnswer(uint8_t *receivedResponse, int maxLen, int *samples, int *elapsed) { + //uint8_t *buffer // buffer needs to be 512 bytes int c; @@ -1529,22 +1469,26 @@ static int GetIClassAnswer(uint8_t *receivedResponse, int maxLen, int *samples, bool skip = false; c = 0; - for(;;) { + for (;;) { WDT_HIT(); - if(BUTTON_PRESS()) return false; + if (BUTTON_PRESS()) return false; - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { AT91C_BASE_SSC->SSC_THR = 0x00; // To make use of exact timing of next command from reader!! if (elapsed) (*elapsed)++; } - if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - if(c < timeout) { c++; } else { return false; } + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + if (c < timeout) { + c++; + } else { + return false; + } b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; skip = !skip; - if(skip) continue; - - if(ManchesterDecoding(b & 0x0f)) { + if (skip) continue; + + if (ManchesterDecoding(b & 0x0f)) { *samples = c << 3; return true; } @@ -1552,49 +1496,47 @@ static int GetIClassAnswer(uint8_t *receivedResponse, int maxLen, int *samples, } } -int ReaderReceiveIClass(uint8_t* receivedAnswer) -{ - int samples = 0; - if (!GetIClassAnswer(receivedAnswer,160,&samples,0)) return false; - rsamples += samples; - uint8_t parity[MAX_PARITY_SIZE]; - GetParity(receivedAnswer, Demod.len, parity); - LogTrace(receivedAnswer,Demod.len,rsamples,rsamples,parity,false); - if(samples == 0) return false; - return Demod.len; +static int ReaderReceiveIClass(uint8_t *receivedAnswer) { + int samples = 0; + if (!GetIClassAnswer(receivedAnswer, 160, &samples, 0)) { + return false; + } + rsamples += samples; + uint8_t parity[MAX_PARITY_SIZE]; + GetParity(receivedAnswer, Demod.len, parity); + LogTrace(receivedAnswer, Demod.len, rsamples, rsamples, parity, false); + if (samples == 0) return false; + return Demod.len; } -void setupIclassReader() -{ - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - // Reset trace buffer - set_tracing(true); - clear_trace(); +static void setupIclassReader() { + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + // Reset trace buffer + set_tracing(true); + clear_trace(); - // Setup SSC - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_ISO14443A); - // Start from off (no field generated) - // Signal field is off with the appropriate LED - LED_D_OFF(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(200); + // Setup SSC + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_ISO14443A); + // Start from off (no field generated) + // Signal field is off with the appropriate LED + LED_D_OFF(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - // Now give it time to spin up. - // Signal field is on with the appropriate LED - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); - SpinDelay(200); - LED_A_ON(); + // Now give it time to spin up. + // Signal field is on with the appropriate LED + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); + SpinDelay(200); + LED_A_ON(); } -bool sendCmdGetResponseWithRetries(uint8_t* command, size_t cmdsize, uint8_t* resp, uint8_t expected_size, uint8_t retries) -{ - while(retries-- > 0) - { +static bool sendCmdGetResponseWithRetries(uint8_t* command, size_t cmdsize, uint8_t* resp, uint8_t expected_size, uint8_t retries) { + while (retries-- > 0) { ReaderTransmitIClass(command, cmdsize); - if(expected_size == ReaderReceiveIClass(resp)){ + if (expected_size == ReaderReceiveIClass(resp)) { return true; } } @@ -1608,8 +1550,7 @@ bool sendCmdGetResponseWithRetries(uint8_t* command, size_t cmdsize, uint8_t* re * 1 = Got CSN * 2 = Got CSN and CC */ -uint8_t handshakeIclassTag_ext(uint8_t *card_data, bool use_credit_key) -{ +static uint8_t handshakeIclassTag_ext(uint8_t *card_data, bool use_credit_key) { static uint8_t act_all[] = { 0x0a }; //static uint8_t identify[] = { 0x0c }; static uint8_t identify[] = { 0x0c, 0x00, 0x73, 0x33 }; @@ -1627,39 +1568,40 @@ uint8_t handshakeIclassTag_ext(uint8_t *card_data, bool use_credit_key) // Send act_all ReaderTransmitIClass(act_all, 1); // Card present? - if(!ReaderReceiveIClass(resp)) return read_status;//Fail + if (!ReaderReceiveIClass(resp)) return read_status;//Fail //Send Identify ReaderTransmitIClass(identify, 1); //We expect a 10-byte response here, 8 byte anticollision-CSN and 2 byte CRC - uint8_t len = ReaderReceiveIClass(resp); - if(len != 10) return read_status;//Fail + uint8_t len = ReaderReceiveIClass(resp); + if (len != 10) return read_status;//Fail //Copy the Anti-collision CSN to our select-packet - memcpy(&select[1],resp,8); + memcpy(&select[1], resp, 8); //Select the card ReaderTransmitIClass(select, sizeof(select)); //We expect a 10-byte response here, 8 byte CSN and 2 byte CRC - len = ReaderReceiveIClass(resp); - if(len != 10) return read_status;//Fail + len = ReaderReceiveIClass(resp); + if (len != 10) return read_status;//Fail //Success - level 1, we got CSN //Save CSN in response data - memcpy(card_data,resp,8); + memcpy(card_data, resp, 8); //Flag that we got to at least stage 1, read CSN read_status = 1; // Card selected, now read e-purse (cc) (only 8 bytes no CRC) ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc)); - if(ReaderReceiveIClass(resp) == 8) { + if (ReaderReceiveIClass(resp) == 8) { //Save CC (e-purse) in response data - memcpy(card_data+8,resp,8); + memcpy(card_data+8, resp, 8); read_status++; } return read_status; } -uint8_t handshakeIclassTag(uint8_t *card_data) { + +static uint8_t handshakeIclassTag(uint8_t *card_data) { return handshakeIclassTag_ext(card_data, false); } @@ -1667,15 +1609,15 @@ uint8_t handshakeIclassTag(uint8_t *card_data) { // Reader iClass Anticollission void ReaderIClass(uint8_t arg0) { - uint8_t card_data[6 * 8]={0}; + uint8_t card_data[6 * 8] = {0}; memset(card_data, 0xFF, sizeof(card_data)); - uint8_t last_csn[8]={0,0,0,0,0,0,0,0}; + uint8_t last_csn[8] = {0,0,0,0,0,0,0,0}; uint8_t resp[ICLASS_BUFFER_SIZE]; memset(resp, 0xFF, sizeof(resp)); //Read conf block CRC(0x01) => 0xfa 0x22 - uint8_t readConf[] = { ICLASS_CMD_READ_OR_IDENTIFY,0x01, 0xfa, 0x22}; + uint8_t readConf[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x01, 0xfa, 0x22}; //Read App Issuer Area block CRC(0x05) => 0xde 0x64 - uint8_t readAA[] = { ICLASS_CMD_READ_OR_IDENTIFY,0x05, 0xde, 0x64}; + uint8_t readAA[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x05, 0xde, 0x64}; int read_status= 0; uint8_t result_status = 0; @@ -1694,14 +1636,15 @@ void ReaderIClass(uint8_t arg0) { set_tracing(true); setupIclassReader(); - uint16_t tryCnt=0; + uint16_t tryCnt = 0; bool userCancelled = BUTTON_PRESS() || usb_poll_validate_length(); - while(!userCancelled) - { + while (!userCancelled) { // if only looking for one card try 2 times if we missed it the first time - if (try_once && tryCnt > 2) break; + if (try_once && tryCnt > 2) { + break; + } tryCnt++; - if(!get_tracing()) { + if (!get_tracing()) { DbpString("Trace full"); break; } @@ -1709,18 +1652,17 @@ void ReaderIClass(uint8_t arg0) { read_status = handshakeIclassTag_ext(card_data, use_credit_key); - if(read_status == 0) continue; - if(read_status == 1) result_status = FLAG_ICLASS_READER_CSN; - if(read_status == 2) result_status = FLAG_ICLASS_READER_CSN|FLAG_ICLASS_READER_CC; + if (read_status == 0) continue; + if (read_status == 1) result_status = FLAG_ICLASS_READER_CSN; + if (read_status == 2) result_status = FLAG_ICLASS_READER_CSN | FLAG_ICLASS_READER_CC; // handshakeIclass returns CSN|CC, but the actual block // layout is CSN|CONFIG|CC, so here we reorder the data, // moving CC forward 8 bytes - memcpy(card_data+16,card_data+8, 8); + memcpy(card_data+16, card_data+8, 8); //Read block 1, config - if(flagReadConfig) { - if(sendCmdGetResponseWithRetries(readConf, sizeof(readConf), resp, 10, 10)) - { + if (flagReadConfig) { + if (sendCmdGetResponseWithRetries(readConf, sizeof(readConf), resp, 10, 10)) { result_status |= FLAG_ICLASS_READER_CONF; memcpy(card_data+8, resp, 8); } else { @@ -1729,11 +1671,10 @@ void ReaderIClass(uint8_t arg0) { } //Read block 5, AA - if(flagReadAA) { - if(sendCmdGetResponseWithRetries(readAA, sizeof(readAA), resp, 10, 10)) - { + if (flagReadAA) { + if (sendCmdGetResponseWithRetries(readAA, sizeof(readAA), resp, 10, 10)) { result_status |= FLAG_ICLASS_READER_AA; - memcpy(card_data+(8*5), resp, 8); + memcpy(card_data + (8*5), resp, 8); } else { //Dbprintf("Failed to dump AA block"); } @@ -1749,14 +1690,13 @@ void ReaderIClass(uint8_t arg0) { // with 0xFF:s in block 3 and 4. LED_B_ON(); - //Send back to client, but don't bother if we already sent this - + //Send back to client, but don't bother if we already sent this - // only useful if looping in arm (not try_once && not abort_after_read) - if(memcmp(last_csn, card_data, 8) != 0) - { + if (memcmp(last_csn, card_data, 8) != 0) { // If caller requires that we get Conf, CC, AA, continue until we got it - if( (result_status ^ FLAG_ICLASS_READER_CSN ^ flagReadConfig ^ flagReadCC ^ flagReadAA) == 0) { - cmd_send(CMD_ACK,result_status,0,0,card_data,sizeof(card_data)); - if(abort_after_read) { + if ( (result_status ^ FLAG_ICLASS_READER_CSN ^ flagReadConfig ^ flagReadCC ^ flagReadAA) == 0) { + cmd_send(CMD_ACK, result_status, 0, 0, card_data, sizeof(card_data)); + if (abort_after_read) { LED_A_OFF(); LED_B_OFF(); return; @@ -1770,9 +1710,9 @@ void ReaderIClass(uint8_t arg0) { userCancelled = BUTTON_PRESS() || usb_poll_validate_length(); } if (userCancelled) { - cmd_send(CMD_ACK,0xFF,0,0,card_data, 0); + cmd_send(CMD_ACK, 0xFF, 0, 0, card_data, 0); } else { - cmd_send(CMD_ACK,0,0,0,card_data, 0); + cmd_send(CMD_ACK, 0, 0, 0, card_data, 0); } LED_A_OFF(); } @@ -1782,100 +1722,95 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { uint8_t card_data[USB_CMD_DATA_SIZE]={0}; uint16_t block_crc_LUT[255] = {0}; - {//Generate a lookup table for block crc - for(int block = 0; block < 255; block++){ - char bl = block; - block_crc_LUT[block] = iclass_crc16(&bl ,1); - } + //Generate a lookup table for block crc + for (int block = 0; block < 255; block++){ + char bl = block; + block_crc_LUT[block] = iclass_crc16(&bl ,1); } //Dbprintf("Lookup table: %02x %02x %02x" ,block_crc_LUT[0],block_crc_LUT[1],block_crc_LUT[2]); uint8_t check[] = { 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t read[] = { 0x0c, 0x00, 0x00, 0x00 }; - - uint16_t crc = 0; - uint8_t cardsize=0; - uint8_t mem=0; - - static struct memory_t{ - int k16; - int book; - int k2; - int lockauth; - int keyaccess; + + uint16_t crc = 0; + uint8_t cardsize = 0; + uint8_t mem = 0; + + static struct memory_t { + int k16; + int book; + int k2; + int lockauth; + int keyaccess; } memory; - + uint8_t resp[ICLASS_BUFFER_SIZE]; - - setupIclassReader(); + + setupIclassReader(); set_tracing(true); - while(!BUTTON_PRESS()) { - + while (!BUTTON_PRESS()) { + WDT_HIT(); - if(!get_tracing()) { + if (!get_tracing()) { DbpString("Trace full"); break; } - + uint8_t read_status = handshakeIclassTag(card_data); - if(read_status < 2) continue; + if (read_status < 2) continue; //for now replay captured auth (as cc not updated) - memcpy(check+5,MAC,4); + memcpy(check+5, MAC, 4); - if(!sendCmdGetResponseWithRetries(check, sizeof(check),resp, 4, 5)) - { + if (!sendCmdGetResponseWithRetries(check, sizeof(check), resp, 4, 5)) { Dbprintf("Error: Authentication Fail!"); continue; } //first get configuration block (block 1) crc = block_crc_LUT[1]; - read[1]=1; + read[1] = 1; read[2] = crc >> 8; read[3] = crc & 0xff; - if(!sendCmdGetResponseWithRetries(read, sizeof(read),resp, 10, 10)) - { + if (!sendCmdGetResponseWithRetries(read, sizeof(read),resp, 10, 10)) { Dbprintf("Dump config (block 1) failed"); continue; } - mem=resp[5]; - memory.k16= (mem & 0x80); - memory.book= (mem & 0x20); - memory.k2= (mem & 0x8); - memory.lockauth= (mem & 0x2); - memory.keyaccess= (mem & 0x1); + mem = resp[5]; + memory.k16 = (mem & 0x80); + memory.book = (mem & 0x20); + memory.k2 = (mem & 0x8); + memory.lockauth = (mem & 0x2); + memory.keyaccess = (mem & 0x1); cardsize = memory.k16 ? 255 : 32; WDT_HIT(); //Set card_data to all zeroes, we'll fill it with data - memset(card_data,0x0,USB_CMD_DATA_SIZE); - uint8_t failedRead =0; - uint32_t stored_data_length =0; + memset(card_data, 0x0, USB_CMD_DATA_SIZE); + uint8_t failedRead = 0; + uint32_t stored_data_length = 0; //then loop around remaining blocks - for(int block=0; block < cardsize; block++){ - - read[1]= block; + for (int block = 0; block < cardsize; block++) { + read[1] = block; crc = block_crc_LUT[block]; read[2] = crc >> 8; read[3] = crc & 0xff; - if(sendCmdGetResponseWithRetries(read, sizeof(read), resp, 10, 10)) - { + if (sendCmdGetResponseWithRetries(read, sizeof(read), resp, 10, 10)) { Dbprintf(" %02x: %02x %02x %02x %02x %02x %02x %02x %02x", - block, resp[0], resp[1], resp[2], + block, resp[0], resp[1], resp[2], resp[3], resp[4], resp[5], resp[6], resp[7]); //Fill up the buffer - memcpy(card_data+stored_data_length,resp,8); + memcpy(card_data+stored_data_length, resp, 8); stored_data_length += 8; - if(stored_data_length +8 > USB_CMD_DATA_SIZE) - {//Time to send this off and start afresh + if (stored_data_length +8 > USB_CMD_DATA_SIZE) { + //Time to send this off and start afresh cmd_send(CMD_ACK, stored_data_length,//data length failedRead,//Failed blocks? @@ -1886,21 +1821,21 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { failedRead = 0; } - }else{ + } else { failedRead = 1; - stored_data_length +=8;//Otherwise, data becomes misaligned + stored_data_length += 8;//Otherwise, data becomes misaligned Dbprintf("Failed to dump block %d", block); } } //Send off any remaining data - if(stored_data_length > 0) - { + if (stored_data_length > 0) { cmd_send(CMD_ACK, stored_data_length,//data length failedRead,//Failed blocks? 0,//Not used ATM - card_data, stored_data_length); + card_data, + stored_data_length); } //If we got here, let's break break; @@ -1910,27 +1845,29 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { 0,//data length 0,//Failed blocks? 0,//Not used ATM - card_data, 0); + card_data, + 0); LED_A_OFF(); } -void iClass_ReadCheck(uint8_t blockNo, uint8_t keyType) { +void iClass_ReadCheck(uint8_t blockNo, uint8_t keyType) { uint8_t readcheck[] = { keyType, blockNo }; uint8_t resp[] = {0,0,0,0,0,0,0,0}; size_t isOK = 0; isOK = sendCmdGetResponseWithRetries(readcheck, sizeof(readcheck), resp, sizeof(resp), 6); - cmd_send(CMD_ACK,isOK,0,0,0,0); + cmd_send(CMD_ACK,isOK, 0, 0, 0, 0); } void iClass_Authentication(uint8_t *MAC) { uint8_t check[] = { ICLASS_CMD_CHECK, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t resp[ICLASS_BUFFER_SIZE]; - memcpy(check+5,MAC,4); + memcpy(check+5, MAC, 4); bool isOK; isOK = sendCmdGetResponseWithRetries(check, sizeof(check), resp, 4, 6); - cmd_send(CMD_ACK,isOK,0,0,0,0); + cmd_send(CMD_ACK,isOK, 0, 0, 0, 0); } + bool iClass_ReadBlock(uint8_t blockNo, uint8_t *readdata) { uint8_t readcmd[] = {ICLASS_CMD_READ_OR_IDENTIFY, blockNo, 0x00, 0x00}; //0x88, 0x00 // can i use 0C? char bl = blockNo; @@ -1961,17 +1898,17 @@ void iClass_Dump(uint8_t blockno, uint8_t numblks) { BigBuf_free(); uint8_t *dataout = BigBuf_malloc(255*8); - if (dataout == NULL){ + if (dataout == NULL) { Dbprintf("out of memory"); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_D_OFF(); - cmd_send(CMD_ACK,0,1,0,0,0); + cmd_send(CMD_ACK, 0, 1, 0, 0, 0); LED_A_OFF(); return; } - memset(dataout,0xFF,255*8); + memset(dataout, 0xFF, 255*8); - for (;blkCnt < numblks; blkCnt++) { + for ( ; blkCnt < numblks; blkCnt++) { isOK = iClass_ReadBlock(blockno+blkCnt, readblockdata); if (!isOK || (readblockdata[0] == 0xBB || readblockdata[7] == 0xBB || readblockdata[2] == 0xBB)) { //try again isOK = iClass_ReadBlock(blockno+blkCnt, readblockdata); @@ -1980,36 +1917,35 @@ void iClass_Dump(uint8_t blockno, uint8_t numblks) { break; } } - memcpy(dataout+(blkCnt*8),readblockdata,8); + memcpy(dataout + (blkCnt*8), readblockdata, 8); } //return pointer to dump memory in arg3 - cmd_send(CMD_ACK,isOK,blkCnt,BigBuf_max_traceLen(),0,0); + cmd_send(CMD_ACK, isOK, blkCnt, BigBuf_max_traceLen(), 0, 0); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); BigBuf_free(); } -bool iClass_WriteBlock_ext(uint8_t blockNo, uint8_t *data) { +static bool iClass_WriteBlock_ext(uint8_t blockNo, uint8_t *data) { uint8_t write[] = { ICLASS_CMD_UPDATE, blockNo, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; //uint8_t readblockdata[10]; //write[1] = blockNo; memcpy(write+2, data, 12); // data + mac - char *wrCmd = (char *)(write+1); + char *wrCmd = (char *)(write+1); uint16_t wrCrc = iclass_crc16(wrCmd, 13); write[14] = wrCrc >> 8; write[15] = wrCrc & 0xff; uint8_t resp[] = {0,0,0,0,0,0,0,0,0,0}; bool isOK = false; - isOK = sendCmdGetResponseWithRetries(write,sizeof(write),resp,sizeof(resp),10); + isOK = sendCmdGetResponseWithRetries(write, sizeof(write), resp, sizeof(resp), 10); if (isOK) { //if reader responded correctly //Dbprintf("WriteResp: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",resp[0],resp[1],resp[2],resp[3],resp[4],resp[5],resp[6],resp[7],resp[8],resp[9]); - if (memcmp(write+2,resp,8)) { //if response is not equal to write values + if (memcmp(write+2, resp, 8)) { //if response is not equal to write values if (blockNo != 3 && blockNo != 4) { //if not programming key areas (note key blocks don't get programmed with actual key data it is xor data) //error try again - isOK = sendCmdGetResponseWithRetries(write,sizeof(write),resp,sizeof(resp),10); - } - + isOK = sendCmdGetResponseWithRetries(write, sizeof(write), resp, sizeof(resp), 10); + } } } return isOK; @@ -2018,37 +1954,37 @@ bool iClass_WriteBlock_ext(uint8_t blockNo, uint8_t *data) { void iClass_WriteBlock(uint8_t blockNo, uint8_t *data) { bool isOK = iClass_WriteBlock_ext(blockNo, data); if (isOK){ - Dbprintf("Write block [%02x] successful",blockNo); + Dbprintf("Write block [%02x] successful", blockNo); } else { - Dbprintf("Write block [%02x] failed",blockNo); + Dbprintf("Write block [%02x] failed", blockNo); } - cmd_send(CMD_ACK,isOK,0,0,0,0); + cmd_send(CMD_ACK, isOK, 0, 0, 0, 0); } void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data) { int i; int written = 0; int total_block = (endblock - startblock) + 1; - for (i = 0; i < total_block;i++){ + for (i = 0; i < total_block; i++) { // block number - if (iClass_WriteBlock_ext(i+startblock, data+(i*12))){ - Dbprintf("Write block [%02x] successful",i + startblock); + if (iClass_WriteBlock_ext(i+startblock, data + (i*12))){ + Dbprintf("Write block [%02x] successful", i + startblock); written++; } else { - if (iClass_WriteBlock_ext(i+startblock, data+(i*12))){ - Dbprintf("Write block [%02x] successful",i + startblock); + if (iClass_WriteBlock_ext(i+startblock, data + (i*12))){ + Dbprintf("Write block [%02x] successful", i + startblock); written++; } else { - Dbprintf("Write block [%02x] failed",i + startblock); + Dbprintf("Write block [%02x] failed", i + startblock); } } } if (written == total_block) Dbprintf("Clone complete"); else - Dbprintf("Clone incomplete"); + Dbprintf("Clone incomplete"); - cmd_send(CMD_ACK,1,0,0,0,0); + cmd_send(CMD_ACK, 1, 0, 0, 0, 0); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); } diff --git a/armsrc/optimized_cipher.c b/armsrc/optimized_cipher.c index b1f33737..ee9d5568 100644 --- a/armsrc/optimized_cipher.c +++ b/armsrc/optimized_cipher.c @@ -1,13 +1,13 @@ /***************************************************************************** * WARNING * - * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. - * - * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL - * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, - * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. - * - * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. * ***************************************************************************** * @@ -31,9 +31,9 @@ * * You should have received a copy of the GNU General Public License * along with loclass. If not, see . - * - * - * + * + * + * ****************************************************************************/ /** @@ -87,22 +87,20 @@ uint8_t xopt__select(bool x, bool y, uint8_t r) // z0 // z1 -// uint8_t z0 = (r0 & r2) ^ (r1 & ~r3) ^ (r2 | r4); // <-- original +// uint8_t z0 = (r0 & r2) ^ (r1 & ~r3) ^ (r2 | r4); // <-- original uint8_t z0 = (r_and_ls2 >> 5) ^ ((r & ~r_ls2) >> 4) ^ ( r_or_ls2 >> 3); -// uint8_t z1 = (r0 | r2) ^ ( r5 | r7) ^ r1 ^ r6 ^ x ^ y; // <-- original +// uint8_t z1 = (r0 | r2) ^ ( r5 | r7) ^ r1 ^ r6 ^ x ^ y; // <-- original uint8_t z1 = (r_or_ls2 >> 6) ^ ( r_or_ls2 >> 1) ^ (r >> 5) ^ r ^ ((x^y) << 1); -// uint8_t z2 = (r3 & ~r5) ^ (r4 & r6 ) ^ r7 ^ x; // <-- original +// uint8_t z2 = (r3 & ~r5) ^ (r4 & r6 ) ^ r7 ^ x; // <-- original uint8_t z2 = ((r & ~r_ls2) >> 4) ^ (r_and_ls2 >> 3) ^ r ^ x; return (z0 & 4) | (z1 & 2) | (z2 & 1); } */ -void opt_successor(const uint8_t* k, State *s, bool y, State* successor) -{ - +void opt_successor(const uint8_t *k, State *s, bool y, State *successor) { uint8_t Tt = 1 & opt_T(s); successor->t = (s->t >> 1); @@ -111,136 +109,124 @@ void opt_successor(const uint8_t* k, State *s, bool y, State* successor) successor->b = s->b >> 1; successor->b |= (opt_B(s) ^ (s->r & 0x1)) << 7; - successor->r = (k[opt__select(Tt,y,s->r)] ^ successor->b) + s->l ; - successor->l = successor->r+s->r; - + successor->r = (k[opt__select(Tt, y, s->r)] ^ successor->b) + s->l ; + successor->l = successor->r + s->r; } -void opt_suc(const uint8_t* k,State* s, uint8_t *in, uint8_t length, bool add32Zeroes) -{ +void opt_suc(const uint8_t *k, State *s, uint8_t *in, uint8_t length, bool add32Zeroes) { State x2; - int i; - uint8_t head = 0; - for(i =0 ; i < length ; i++) - { + for (int i = 0; i < length; i++) { + uint8_t head; head = 1 & (in[i] >> 7); - opt_successor(k,s,head,&x2); + opt_successor(k, s, head, &x2); head = 1 & (in[i] >> 6); - opt_successor(k,&x2,head,s); + opt_successor(k, &x2, head, s); head = 1 & (in[i] >> 5); - opt_successor(k,s,head,&x2); + opt_successor(k, s, head, &x2); head = 1 & (in[i] >> 4); - opt_successor(k,&x2,head,s); + opt_successor(k, &x2, head, s); head = 1 & (in[i] >> 3); - opt_successor(k,s,head,&x2); + opt_successor(k, s, head, &x2); head = 1 & (in[i] >> 2); - opt_successor(k,&x2,head,s); + opt_successor(k, &x2, head, s); head = 1 & (in[i] >> 1); - opt_successor(k,s,head,&x2); + opt_successor(k, s, head, &x2); head = 1 & in[i]; - opt_successor(k,&x2,head,s); - + opt_successor(k, &x2, head, s); } //For tag MAC, an additional 32 zeroes - if(add32Zeroes) - for(i =0 ; i < 16 ; i++) - { - opt_successor(k,s,0,&x2); - opt_successor(k,&x2,0,s); + if (add32Zeroes) { + for(int i = 0; i < 16; i++) { + opt_successor(k, s, 0, &x2); + opt_successor(k, &x2, 0, s); } + } } -void opt_output(const uint8_t* k,State* s, uint8_t *buffer) -{ - uint8_t times = 0; - uint8_t bout = 0; - State temp = {0,0,0,0}; - for( ; times < 4 ; times++) - { - bout =0; +void opt_output(const uint8_t *k, State *s, uint8_t *buffer) { + State temp = {0, 0, 0, 0}; + for (uint8_t times = 0; times < 4; times++) { + uint8_t bout = 0; bout |= (s->r & 0x4) << 5; - opt_successor(k,s,0,&temp); + opt_successor(k, s, 0, &temp); bout |= (temp.r & 0x4) << 4; - opt_successor(k,&temp,0,s); + opt_successor(k, &temp, 0, s); bout |= (s->r & 0x4) << 3; - opt_successor(k,s,0,&temp); + opt_successor(k, s, 0, &temp); bout |= (temp.r & 0x4) << 2; - opt_successor(k,&temp,0,s); + opt_successor(k, &temp, 0, s); bout |= (s->r & 0x4) << 1; - opt_successor(k,s,0,&temp); + opt_successor(k, s, 0, &temp); bout |= (temp.r & 0x4) ; - opt_successor(k,&temp,0,s); + opt_successor(k, &temp, 0, s); bout |= (s->r & 0x4) >> 1; - opt_successor(k,s,0,&temp); + opt_successor(k, s, 0, &temp); bout |= (temp.r & 0x4) >> 2; - opt_successor(k,&temp,0,s); + opt_successor(k, &temp, 0, s); buffer[times] = bout; } - } -void opt_MAC(uint8_t* k, uint8_t* input, uint8_t* out) -{ +void opt_MAC(uint8_t *k, uint8_t *input, uint8_t *out) { State _init = { - ((k[0] ^ 0x4c) + 0xEC) & 0xFF,// l - ((k[0] ^ 0x4c) + 0x21) & 0xFF,// r - 0x4c, // b - 0xE012 // t - }; + ((k[0] ^ 0x4c) + 0xEC) & 0xFF,// l + ((k[0] ^ 0x4c) + 0x21) & 0xFF,// r + 0x4c, // b + 0xE012 // t + }; - opt_suc(k,&_init,input,12, false); + opt_suc(k, &_init, input, 12, false); //printf("\noutp "); - opt_output(k,&_init, out); + opt_output(k, &_init, out); } + uint8_t rev_byte(uint8_t b) { b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; b = (b & 0xCC) >> 2 | (b & 0x33) << 2; b = (b & 0xAA) >> 1 | (b & 0x55) << 1; - return b; + return b; } -void opt_reverse_arraybytecpy(uint8_t* dest, uint8_t *src, size_t len) -{ - uint8_t i; - for( i =0; i< len ; i++) + +void opt_reverse_arraybytecpy(uint8_t *dest, uint8_t *src, size_t len) { + for (size_t i = 0; i < len; i++) { dest[i] = rev_byte(src[i]); + } } -void opt_doReaderMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4]) -{ +void opt_doReaderMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4]) { static uint8_t cc_nr[12]; - - opt_reverse_arraybytecpy(cc_nr, cc_nr_p,12); - uint8_t dest []= {0,0,0,0,0,0,0,0}; - opt_MAC(div_key_p,cc_nr, dest); + opt_reverse_arraybytecpy(cc_nr, cc_nr_p, 12); + uint8_t dest[] = {0, 0, 0, 0, 0, 0, 0, 0}; + opt_MAC(div_key_p, cc_nr, dest); //The output MAC must also be reversed - opt_reverse_arraybytecpy(mac, dest,4); + opt_reverse_arraybytecpy(mac, dest, 4); return; } -void opt_doTagMAC(uint8_t *cc_p, const uint8_t *div_key_p, uint8_t mac[4]) -{ + +void opt_doTagMAC(uint8_t *cc_p, const uint8_t *div_key_p, uint8_t mac[4]) { static uint8_t cc_nr[8+4+4]; - opt_reverse_arraybytecpy(cc_nr, cc_p,12); - State _init = { - ((div_key_p[0] ^ 0x4c) + 0xEC) & 0xFF,// l - ((div_key_p[0] ^ 0x4c) + 0x21) & 0xFF,// r - 0x4c, // b - 0xE012 // t - }; - opt_suc(div_key_p,&_init,cc_nr, 12,true); - uint8_t dest []= {0,0,0,0}; - opt_output(div_key_p,&_init, dest); + opt_reverse_arraybytecpy(cc_nr, cc_p, 12); + State _init = { + ((div_key_p[0] ^ 0x4c) + 0xEC) & 0xFF,// l + ((div_key_p[0] ^ 0x4c) + 0x21) & 0xFF,// r + 0x4c, // b + 0xE012 // t + }; + opt_suc(div_key_p, &_init,cc_nr, 12, true); + uint8_t dest[] = {0, 0, 0, 0}; + opt_output(div_key_p, &_init, dest); //The output MAC must also be reversed - opt_reverse_arraybytecpy(mac, dest,4); + opt_reverse_arraybytecpy(mac, dest, 4); return; - } + /** * The tag MAC can be divided (both can, but no point in dividing the reader mac) into * two functions, since the first 8 bytes are known, we can pre-calculate the state @@ -249,19 +235,19 @@ void opt_doTagMAC(uint8_t *cc_p, const uint8_t *div_key_p, uint8_t mac[4]) * @param div_key_p * @return the cipher state */ -State opt_doTagMAC_1(uint8_t *cc_p, const uint8_t *div_key_p) -{ +State opt_doTagMAC_1(uint8_t *cc_p, const uint8_t *div_key_p) { static uint8_t cc_nr[8]; - opt_reverse_arraybytecpy(cc_nr, cc_p,8); - State _init = { - ((div_key_p[0] ^ 0x4c) + 0xEC) & 0xFF,// l - ((div_key_p[0] ^ 0x4c) + 0x21) & 0xFF,// r - 0x4c, // b - 0xE012 // t - }; - opt_suc(div_key_p,&_init,cc_nr, 8,false); + opt_reverse_arraybytecpy(cc_nr, cc_p, 8); + State _init = { + ((div_key_p[0] ^ 0x4c) + 0xEC) & 0xFF,// l + ((div_key_p[0] ^ 0x4c) + 0x21) & 0xFF,// r + 0x4c, // b + 0xE012 // t + }; + opt_suc(div_key_p, &_init, cc_nr, 8, false); return _init; } + /** * The second part of the tag MAC calculation, since the CC is already calculated into the state, * this function is fed only the NR, and internally feeds the remaining 32 0-bits to generate the tag @@ -271,15 +257,14 @@ State opt_doTagMAC_1(uint8_t *cc_p, const uint8_t *div_key_p) * @param mac - where to store the MAC * @param div_key_p - the key to use */ -void opt_doTagMAC_2(State _init, uint8_t* nr, uint8_t mac[4], const uint8_t* div_key_p) -{ - static uint8_t _nr [4]; +void opt_doTagMAC_2(State _init, uint8_t *nr, uint8_t mac[4], const uint8_t *div_key_p) { + static uint8_t _nr[4]; opt_reverse_arraybytecpy(_nr, nr, 4); - opt_suc(div_key_p,&_init,_nr, 4, true); - //opt_suc(div_key_p,&_init,nr, 4, false); - uint8_t dest []= {0,0,0,0}; - opt_output(div_key_p,&_init, dest); + opt_suc(div_key_p, &_init, _nr, 4, true); + //opt_suc(div_key_p, &_init,nr, 4, false); + uint8_t dest[] = {0, 0, 0, 0}; + opt_output(div_key_p, &_init, dest); //The output MAC must also be reversed - opt_reverse_arraybytecpy(mac, dest,4); + opt_reverse_arraybytecpy(mac, dest, 4); return; } diff --git a/armsrc/optimized_cipher.h b/armsrc/optimized_cipher.h index 6a4e2641..be77a250 100644 --- a/armsrc/optimized_cipher.h +++ b/armsrc/optimized_cipher.h @@ -35,17 +35,18 @@ * ****************************************************************************/ - #ifndef OPTIMIZED_CIPHER_H -#define OPTIMIZED_CIPHER_H +#ifndef OPTIMIZED_CIPHER_H__ +#define OPTIMIZED_CIPHER_H__ + #include /** * Definition 1 (Cipher state). A cipher state of iClass s is an element of F 40/2 * consisting of the following four components: -* 1. the left register l = (l 0 . . . l 7 ) ∈ F 8/2 ; -* 2. the right register r = (r 0 . . . r 7 ) ∈ F 8/2 ; -* 3. the top register t = (t 0 . . . t 15 ) ∈ F 16/2 . -* 4. the bottom register b = (b 0 . . . b 7 ) ∈ F 8/2 . +* 1. the left register l = (l 0 . . . l 7 ) ∈ F 8/2 ; +* 2. the right register r = (r 0 . . . r 7 ) ∈ F 8/2 ; +* 3. the top register t = (t 0 . . . t 15 ) ∈ F 16/2 . +* 4. the bottom register b = (b 0 . . . b 7 ) ∈ F 8/2 . **/ typedef struct { uint8_t l; @@ -57,6 +58,7 @@ typedef struct { /** The reader MAC is MAC(key, CC * NR ) **/ void opt_doReaderMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4]); + /** * The tag MAC is MAC(key, CC * NR * 32x0)) */ @@ -71,6 +73,7 @@ void opt_doTagMAC(uint8_t *cc_p, const uint8_t *div_key_p, uint8_t mac[4]); * @return the cipher state */ State opt_doTagMAC_1(uint8_t *cc_p, const uint8_t *div_key_p); + /** * The second part of the tag MAC calculation, since the CC is already calculated into the state, * this function is fed only the NR, and internally feeds the remaining 32 0-bits to generate the tag @@ -80,6 +83,6 @@ State opt_doTagMAC_1(uint8_t *cc_p, const uint8_t *div_key_p); * @param mac - where to store the MAC * @param div_key_p - the key to use */ -void opt_doTagMAC_2(State _init, uint8_t* nr, uint8_t mac[4], const uint8_t* div_key_p); +void opt_doTagMAC_2(State _init, uint8_t *nr, uint8_t mac[4], const uint8_t *div_key_p); -#endif // OPTIMIZED_CIPHER_H +#endif // OPTIMIZED_CIPHER_H__ From cfa9c98d573c5a0d35c6ce86501fc6fd57f91b81 Mon Sep 17 00:00:00 2001 From: Samuele Date: Thu, 22 Aug 2019 07:51:46 +0200 Subject: [PATCH 122/189] PCF7931: Print found single/consecutive block(s), fixes to block 1 check --- armsrc/pcf7931.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/armsrc/pcf7931.c b/armsrc/pcf7931.c index e3bac386..147f6fb8 100644 --- a/armsrc/pcf7931.c +++ b/armsrc/pcf7931.c @@ -152,8 +152,14 @@ bool IsBlock0PCF7931(uint8_t *block) { bool IsBlock1PCF7931(uint8_t *block) { // assuming all RFU bits are set to 0 + + uint8_t rb1 = block[14] & 0x80; + uint8_t rfb = block[14] & 0x7f; + uint8_t rlb = block[15]; + if (block[10] == 0 && block[11] == 0 && block[12] == 0 && block[13] == 0) - if((block[14] & 0x7f) <= 9 && block[15] <= 9) + // block 1 is sent only if (RLB >= 1 && RFB <= 1) or RB1 enabled + if(rfb <= rlb && rfb <= 9 && rlb <= 9 && ((rfb <= 1 && rlb >= 1) || rb1)) return true; return false; @@ -192,6 +198,7 @@ void ReadPCF7931() { Dbprintf("Error, no tag or bad tag"); return; } + // exit if too many errors during reading if (tries > 50 && (2*errors > tries)) { Dbprintf("Error reading the tag"); @@ -201,9 +208,11 @@ void ReadPCF7931() { // our logic breaks if we don't get at least two blocks if (n < 2) { + // skip if all 0s block or no blocks if (n == 0 || !memcmp(tmp_blocks[0], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)) continue; + // add block to single blocks list if (single_blocks_cnt < max_blocks) { for (i = 0; i < single_blocks_cnt; ++i) { if (!memcmp(single_blocks[i], tmp_blocks[0], 16)) { @@ -213,6 +222,7 @@ void ReadPCF7931() { } if (j != 1) { memcpy(single_blocks[single_blocks_cnt], tmp_blocks[0], 16); + print_result("got single block", single_blocks[single_blocks_cnt], 16); single_blocks_cnt++; } j = 0; @@ -222,6 +232,10 @@ void ReadPCF7931() { } Dbprintf("(dbg) got %d blocks (%d/%d found) (%d tries, %d errors)", n, found_blocks, (max_blocks == 0 ? found_blocks : max_blocks), tries, errors); + for (i = 0; i < n; ++i) + { + print_result("got consecutive blocks", tmp_blocks[i], 16); + } i = 0; if(!found_0_1) { @@ -284,7 +298,7 @@ void ReadPCF7931() { goto end; } } - while (found_blocks != max_blocks); + while (found_blocks < max_blocks); end: Dbprintf("-----------------------------------------"); From 0b4efbdef20ccf33ba7b5f6dbe36ab80cfe5477a Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Thu, 22 Aug 2019 07:53:17 +0200 Subject: [PATCH 123/189] add: 'hf mf personalize' (personalize UID on Mifare Classic EV1 7byte UID cards) * add/use some #defines * whitespace fixes * #include refactoring * add line to CHANGELOG.md --- CHANGELOG.md | 1 + armsrc/appmain.c | 4 + armsrc/apps.h | 43 ++----- armsrc/mifarecmd.c | 270 ++++++++++++++++++++++++++----------------- armsrc/mifarecmd.h | 40 +++++-- armsrc/mifareutil.c | 21 ++-- client/cmdhfmf.c | 212 +++++++++++++++++++++++----------- client/util.c | 274 ++++++++++++++++++++++---------------------- common/protocols.h | 4 + include/usb_cmd.h | 14 +-- 10 files changed, 514 insertions(+), 369 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5210edbc..e95ccde6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added downlink reference mode option r [ 0 - (or missing) default/fixed bit, 1 - long leading, 2 - leading 0 and 3 - 1 of 4 ] to `lf t55xx detect`, `lf t55xx read`, `lf t55xx write`, and `lf t55xx bruteforce` - Added special option `r 4` to bruteforce, to try all downlink modes (0,1,2 and 3) for each password - `hf mfu info` now checks the NXP Originality Signature if availabe (piwi) +- Added `hf mf personalize` to personalize the UID option of Mifare Classic EV1 cards (piwi) ## [v3.1.0][2018-10-10] diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 9b9acb6f..f5f3c237 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -28,6 +28,7 @@ #include "iso15693.h" #include "lfsampling.h" #include "BigBuf.h" +#include "mifarecmd.h" #include "mifareutil.h" #include "mifaresim.h" #include "pcf7931.h" @@ -1242,6 +1243,9 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_MIFARE_WRITEBL: MifareWriteBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); break; + case CMD_MIFARE_PERSONALIZE_UID: + MifarePersonalizeUID(c->arg[0], c->arg[1], c->d.asBytes); + break; //case CMD_MIFAREU_WRITEBL_COMPAT: //MifareUWriteBlockCompat(c->arg[0], c->d.asBytes); //break; diff --git a/armsrc/apps.h b/armsrc/apps.h index 4d9a1482..ae5e3977 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -108,41 +108,14 @@ void RAMFUNC SniffMifare(uint8_t param); void EPA_PACE_Collect_Nonce(UsbCommand * c); void EPA_PACE_Replay(UsbCommand *c); -// mifarecmd.h -void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *data); -void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain); -void MifareUC_Auth(uint8_t arg0, uint8_t *datain); -void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain); -void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); -void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); -//void MifareUWriteBlockCompat(uint8_t arg0,uint8_t *datain); -void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain); -void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); -void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain); -void MifareChkKeys(uint16_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain); -void MifareSetDbgLvl(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); -void MifareEMemClr(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); -void MifareEMemSet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); -void MifareEMemGet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); -void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); -void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); // Work with "magic Chinese" card -void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); -void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); -void MifareCIdent(); // is "magic chinese" card? -void MifareUSetPwd(uint8_t arg0, uint8_t *datain); - -//desfire -void Mifare_DES_Auth1(uint8_t arg0,uint8_t *datain); -void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain); - // mifaredesfire.h -bool InitDesfireCard(); -void MifareSendCommand(uint8_t arg0,uint8_t arg1, uint8_t *datain); -void MifareDesfireGetInformation(); -void MifareDES_Auth1(uint8_t arg0,uint8_t arg1,uint8_t arg2, uint8_t *datain); -void ReaderMifareDES(uint32_t param, uint32_t param2, uint8_t * datain); -int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout); -size_t CreateAPDU( uint8_t *datain, size_t len, uint8_t *dataout); +bool InitDesfireCard(); +void MifareSendCommand(uint8_t arg0,uint8_t arg1, uint8_t *datain); +void MifareDesfireGetInformation(); +void MifareDES_Auth1(uint8_t arg0,uint8_t arg1,uint8_t arg2, uint8_t *datain); +void ReaderMifareDES(uint32_t param, uint32_t param2, uint8_t * datain); +int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout); +size_t CreateAPDU( uint8_t *datain, size_t len, uint8_t *dataout); /// iclass.h @@ -157,7 +130,7 @@ void iClass_ReadBlk(uint8_t blockNo); bool iClass_ReadBlock(uint8_t blockNo, uint8_t *readdata); void iClass_Dump(uint8_t blockno, uint8_t numblks); void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data); -void iClass_ReadCheck(uint8_t blockNo, uint8_t keyType); +void iClass_ReadCheck(uint8_t blockNo, uint8_t keyType); // cmd.h bool cmd_receive(UsbCommand* cmd); diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 8fe502ca..bed2f076 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -15,13 +15,23 @@ #include "mifarecmd.h" +#include + +#include "proxmark3.h" +#include "cmd.h" +#include "crapto1/crapto1.h" +#include "iso14443a.h" +#include "BigBuf.h" +#include "mifareutil.h" +#include "apps.h" +#include "protocols.h" #include "util.h" #include "parity.h" #include "crc.h" #include "fpgaloader.h" -#define HARDNESTED_AUTHENTICATION_TIMEOUT 848 // card times out 1ms after wrong authentication (according to NXP documentation) -#define HARDNESTED_PRE_AUTHENTICATION_LEADTIME 400 // some (non standard) cards need a pause after select before they are ready for first authentication +#define HARDNESTED_AUTHENTICATION_TIMEOUT 848 // card times out 1ms after wrong authentication (according to NXP documentation) +#define HARDNESTED_PRE_AUTHENTICATION_LEADTIME 400 // some (non standard) cards need a pause after select before they are ready for first authentication /* // the block number for the ISO14443-4 PCB @@ -73,22 +83,22 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) while (true) { if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); break; }; if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Auth error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Auth error"); break; }; if(mifare_classic_readblock(pcs, cuid, blockNo, dataoutbuf)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Read block error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Read block error"); break; }; if(mifare_classic_halt(pcs, cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); break; }; @@ -99,7 +109,7 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) // ----------------------------- crypto1 destroy crypto1_destroy(pcs); - if (MF_DBGLEVEL >= 2) DbpString("READ BLOCK FINISHED"); + if (MF_DBGLEVEL >= 2) DbpString("READ BLOCK FINISHED"); LED_B_ON(); cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,16); @@ -230,25 +240,25 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) isOK = 1; if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { isOK = 0; - if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); } if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_FIRST)) { isOK = 0; - if (MF_DBGLEVEL >= 1) Dbprintf("Auth error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Auth error"); } for (uint8_t blockNo = 0; isOK && blockNo < NumBlocksPerSector(sectorNo); blockNo++) { if(mifare_classic_readblock(pcs, cuid, FirstBlockOfSector(sectorNo) + blockNo, dataoutbuf + 16 * blockNo)) { isOK = 0; - if (MF_DBGLEVEL >= 1) Dbprintf("Read sector %2d block %2d error", sectorNo, blockNo); + if (MF_DBGLEVEL >= 1) Dbprintf("Read sector %2d block %2d error", sectorNo, blockNo); break; } } if(mifare_classic_halt(pcs, cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); } // ----------------------------- crypto1 destroy @@ -393,22 +403,22 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) while (true) { if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); break; }; if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Auth error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Auth error"); break; }; if(mifare_classic_writeblock(pcs, cuid, blockNo, blockdata)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Write block error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Write block error"); break; }; if(mifare_classic_halt(pcs, cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); break; }; @@ -419,7 +429,7 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) // ----------------------------- crypto1 destroy crypto1_destroy(pcs); - if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED"); + if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED"); LED_B_ON(); cmd_send(CMD_ACK,isOK,0,0,0,0); @@ -455,7 +465,7 @@ void MifareUWriteBlockCompat(uint8_t arg0, uint8_t *datain) if(mifare_ultra_writeblock_compat(blockNo, blockdata)) { if (MF_DBGLEVEL >= 1) Dbprintf("Write block error"); OnError(0); - return; }; + return; }; if(mifare_ultra_halt()) { if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); @@ -672,7 +682,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, if (!have_uid) { // need a full select cycle to get the uid first iso14a_card_select_t card_info; if(!iso14443a_select_card(uid, &card_info, &cuid, true, 0, true)) { - if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (ALL)"); + if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (ALL)"); continue; } switch (card_info.uidlen) { @@ -684,7 +694,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, have_uid = true; } else { // no need for anticollision. We can directly select the card if(!iso14443a_select_card(uid, NULL, NULL, false, cascade_levels, true)) { - if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (UID)"); + if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (UID)"); continue; } } @@ -696,14 +706,14 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint32_t nt1; if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, NULL)) { - if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Auth1 error"); + if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Auth1 error"); continue; } // nested authentication uint16_t len = mifare_sendcmd_short(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, par_enc, NULL); if (len != 4) { - if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Auth2 error len=%d", len); + if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Auth2 error len=%d", len); continue; } @@ -712,7 +722,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, ReaderTransmit(dummy_answer, 1, NULL); timeout = GetCountSspClk() + HARDNESTED_AUTHENTICATION_TIMEOUT; - + num_nonces++; if (num_nonces % 2) { memcpy(buf+i, receivedAnswer, 4); @@ -737,7 +747,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, cmd_send(CMD_ACK, isOK, cuid, num_nonces, buf, sizeof(buf)); LED_B_OFF(); - if (MF_DBGLEVEL >= 3) DbpString("AcquireEncryptedNonces finished"); + if (MF_DBGLEVEL >= 3) DbpString("AcquireEncryptedNonces finished"); if (field_off) { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); @@ -794,7 +804,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat int16_t isOK = 0; #define NESTED_MAX_TRIES 12 uint16_t unsuccessfull_tries = 0; - if (calibrate) { // for first call only. Otherwise reuse previous calibration + if (calibrate) { // for first call only. Otherwise reuse previous calibration LED_B_ON(); WDT_HIT(); @@ -812,20 +822,20 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat // prepare next select. No need to power down the card. if(mifare_classic_halt(pcs, cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Halt error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Halt error"); rtr--; continue; } if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Can't select card"); + if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Can't select card"); rtr--; continue; }; auth1_time = 0; if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, &auth1_time)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth1 error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth1 error"); rtr--; continue; }; @@ -836,12 +846,12 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat auth2_time = 0; } if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_NESTED, &nt2, &auth2_time)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth2 error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth2 error"); rtr--; continue; }; - nttmp = prng_successor(nt1, 100); //NXP Mifare is typical around 840,but for some unlicensed/compatible mifare card this can be 160 + nttmp = prng_successor(nt1, 100); //NXP Mifare is typical around 840,but for some unlicensed/compatible mifare card this can be 160 for (i = 101; i < 1200; i++) { nttmp = prng_successor(nttmp, 1); if (nttmp == nt2) break; @@ -859,7 +869,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat if (MF_DBGLEVEL >= 3) Dbprintf("Nested: calibrating... ntdist=%d", i); } else { unsuccessfull_tries++; - if (unsuccessfull_tries > NESTED_MAX_TRIES) { // card isn't vulnerable to nested attack (random numbers are not predictable) + if (unsuccessfull_tries > NESTED_MAX_TRIES) { // card isn't vulnerable to nested attack (random numbers are not predictable) isOK = -3; } } @@ -887,18 +897,18 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat // prepare next select. No need to power down the card. if(mifare_classic_halt(pcs, cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Halt error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Halt error"); continue; } if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Can't select card"); + if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Can't select card"); continue; }; auth1_time = 0; if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, &auth1_time)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth1 error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth1 error"); continue; }; @@ -906,7 +916,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat auth2_time = auth1_time + delta_time; len = mifare_sendcmd_short(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, par, &auth2_time); if (len != 4) { - if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth2 error len=%d", len); + if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth2 error len=%d", len); continue; }; @@ -925,7 +935,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat ks1 = nt2 ^ nttest; if (valid_nonce(nttest, nt2, ks1, par_array)){ - if (ncount > 0) { // we are only interested in disambiguous nonces, try again + if (ncount > 0) { // we are only interested in disambiguous nonces, try again if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#%d: dismissed (ambigous), ntdist=%d", i+1, j); target_nt[i] = 0; break; @@ -961,7 +971,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat cmd_send(CMD_ACK, isOK, 0, targetBlockNo + (targetKeyType * 0x100), buf, sizeof(buf)); LED_B_OFF(); - if (MF_DBGLEVEL >= 3) DbpString("NESTED FINISHED"); + if (MF_DBGLEVEL >= 3) DbpString("NESTED FINISHED"); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); @@ -996,7 +1006,7 @@ void MifareChkKeys(uint16_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain) if (set14aTimeout){ iso14a_set_timeout(set14aTimeout * 10); // timeout: ms = x/106 35-minimum, 50-OK 106-recommended 500-safe } - + if (multisectorCheck) { TKeyIndex keyIndex = {{0}}; uint8_t sectorCnt = blockNo; @@ -1026,6 +1036,60 @@ void MifareChkKeys(uint16_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain) LED_A_OFF(); } + +//----------------------------------------------------------------------------- +// MIFARE Personalize UID. Only for Mifare Classic EV1 7Byte UID +//----------------------------------------------------------------------------- +void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint8_t *data) { + + uint8_t uid[10]; + uint32_t cuid; + struct Crypto1State mpcs = {0, 0}; + struct Crypto1State *pcs; + pcs = &mpcs; + + LED_A_ON(); + clear_trace(); + + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + bool isOK = false; + while (true) { + if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); + break; + } + + uint8_t block_number = 0; + uint64_t key = bytes_to_num(data, 6); + if (mifare_classic_auth(pcs, cuid, block_number, keyType, key, AUTH_FIRST)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Auth error"); + break; + } + + uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; + uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; + int len = mifare_sendcmd_short(pcs, true, MIFARE_EV1_PERSONAL_UID, perso_option, receivedAnswer, receivedAnswerPar, NULL); + if (len != 1 || receivedAnswer[0] != CARD_ACK) { + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); + break;; + } + isOK = true; + break; + } + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); + + crypto1_destroy(pcs); + + if (MF_DBGLEVEL >= 2) DbpString("PERSONALIZE UID FINISHED"); + + cmd_send(CMD_ACK, isOK, 0, 0, NULL, 0); + + LED_A_OFF(); +} + //----------------------------------------------------------------------------- // MIFARE commands set debug level // @@ -1093,7 +1157,7 @@ void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { isOK = false; - if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); } for (uint8_t sectorNo = 0; isOK && sectorNo < numSectors; sectorNo++) { @@ -1101,13 +1165,13 @@ void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai if (sectorNo == 0){ if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_FIRST)) { isOK = false; - if (MF_DBGLEVEL >= 1) Dbprintf("Sector[%2d]. Auth error", sectorNo); + if (MF_DBGLEVEL >= 1) Dbprintf("Sector[%2d]. Auth error", sectorNo); break; } } else { if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_NESTED)) { isOK = false; - if (MF_DBGLEVEL >= 1) Dbprintf("Sector[%2d]. Auth nested error", sectorNo); + if (MF_DBGLEVEL >= 1) Dbprintf("Sector[%2d]. Auth nested error", sectorNo); break; } } @@ -1115,13 +1179,13 @@ void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai for (uint8_t blockNo = 0; isOK && blockNo < NumBlocksPerSector(sectorNo); blockNo++) { if(isOK && mifare_classic_readblock(pcs, cuid, FirstBlockOfSector(sectorNo) + blockNo, dataoutbuf)) { isOK = false; - if (MF_DBGLEVEL >= 1) Dbprintf("Error reading sector %2d block %2d", sectorNo, blockNo); + if (MF_DBGLEVEL >= 1) Dbprintf("Error reading sector %2d block %2d", sectorNo, blockNo); break; }; if (isOK) { if (blockNo < NumBlocksPerSector(sectorNo) - 1) { emlSetMem(dataoutbuf, FirstBlockOfSector(sectorNo) + blockNo, 1); - } else { // sector trailer, keep the keys, set only the AC + } else { // sector trailer, keep the keys, set only the AC emlGetMem(dataoutbuf2, FirstBlockOfSector(sectorNo) + blockNo, 1); memcpy(&dataoutbuf2[6], &dataoutbuf[6], 4); emlSetMem(dataoutbuf2, FirstBlockOfSector(sectorNo) + blockNo, 1); @@ -1132,7 +1196,7 @@ void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai } if(mifare_classic_halt(pcs, cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); }; // ----------------------------- crypto1 destroy @@ -1173,20 +1237,20 @@ void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){ bool needWipe = cmdParams & 0x01; bool needFill = cmdParams & 0x02; bool gen1b = cmdParams & 0x04; - + uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; - + uint8_t block0[16] = {0x01, 0x02, 0x03, 0x04, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0xAF}; uint8_t block1[16] = {0x00}; uint8_t blockK[16] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x08, 0x77, 0x8F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; uint8_t d_block[18] = {0x00}; - + // card commands uint8_t wupC1[] = { 0x40 }; uint8_t wupC2[] = { 0x43 }; uint8_t wipeC[] = { 0x41 }; - + // iso14443 setup LED_A_ON(); LED_B_OFF(); @@ -1196,54 +1260,54 @@ void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){ // tracing clear_trace(); set_tracing(true); - + while (true){ // wipe if (needWipe){ ReaderTransmitBitsPar(wupC1,7,0, NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) { + if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); break; }; ReaderTransmit(wipeC, sizeof(wipeC), NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= 1) Dbprintf("wipeC error"); + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) { + if (MF_DBGLEVEL >= 1) Dbprintf("wipeC error"); break; }; if(mifare_classic_halt(NULL, 0)) { - if (MF_DBGLEVEL > 2) Dbprintf("Halt error"); + if (MF_DBGLEVEL > 2) Dbprintf("Halt error"); }; }; - + // put default data if (needFill){ // select commands ReaderTransmitBitsPar(wupC1, 7, 0, NULL); - // gen1b magic tag : do no issue wupC2 and don't expect 0x0a response after SELECT_UID (after getting UID from chip in 'hf mf csetuid' command) - if (!gen1b) { + // gen1b magic tag : do no issue wupC2 and don't expect CARD_ACK response after SELECT_UID (after getting UID from chip in 'hf mf csetuid' command) + if (!gen1b) { - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) { + if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); break; }; ReaderTransmit(wupC2, sizeof(wupC2), NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error"); + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) { + if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error"); break; }; } // send blocks command for (int blockNo = 0; blockNo < numBlocks; blockNo++) { - if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= 1) Dbprintf("write block send command error"); + if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != CARD_ACK)) { + if (MF_DBGLEVEL >= 1) Dbprintf("write block send command error"); break; }; - + // check type of block and add crc if (!isBlockTrailer(blockNo)){ memcpy(d_block, block1, 16); @@ -1257,33 +1321,33 @@ void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){ // send write command ReaderTransmit(d_block, sizeof(d_block), NULL); - if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= 1) Dbprintf("write block send data error"); + if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != CARD_ACK)) { + if (MF_DBGLEVEL >= 1) Dbprintf("write block send data error"); break; }; } - + // halt - // do no issue halt command for gen1b + // do no issue halt command for gen1b if (!gen1b) { if (mifare_classic_halt(NULL, 0)) { - if (MF_DBGLEVEL > 2) Dbprintf("Halt error"); + if (MF_DBGLEVEL > 2) Dbprintf("Halt error"); break; } } } break; - } + } // send USB response LED_B_ON(); cmd_send(CMD_ACK,isOK,0,0,NULL,0); LED_B_OFF(); - + // reset fpga FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); - + return; } @@ -1330,13 +1394,13 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai // get UID from chip if (workFlags & 0x01) { if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); // Continue, if we set wrong UID or wrong UID checksum or some ATQA or SAK we will can't select card. But we need to write block 0 to make card work. //break; }; if(mifare_classic_halt(NULL, cuid)) { - if (MF_DBGLEVEL > 2) Dbprintf("Halt error"); + if (MF_DBGLEVEL > 2) Dbprintf("Halt error"); // Continue, some magic tags misbehavies and send an answer to it. // break; }; @@ -1346,21 +1410,21 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai // Wipe command don't work with gen1b if (needWipe && !(workFlags & 0x40)){ ReaderTransmitBitsPar(wupC1,7,0, NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) { + if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); break; }; ReaderTransmit(wipeC, sizeof(wipeC), NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= 1) Dbprintf("wipeC error"); + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) { + if (MF_DBGLEVEL >= 1) Dbprintf("wipeC error"); break; }; if(mifare_classic_halt(NULL, 0)) { - if (MF_DBGLEVEL > 2) Dbprintf("Halt error"); + if (MF_DBGLEVEL > 2) Dbprintf("Halt error"); // Continue, some magic tags misbehavies and send an answer to it. - // break; + // break; }; }; @@ -1368,24 +1432,24 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai if (workFlags & 0x02) { ReaderTransmitBitsPar(wupC1,7,0, NULL); - // gen1b magic tag : do no issue wupC2 and don't expect 0x0a response after SELECT_UID (after getting UID from chip in 'hf mf csetuid' command) + // gen1b magic tag : do no issue wupC2 and don't expect CARD_ACK response after SELECT_UID (after getting UID from chip in 'hf mf csetuid' command) if (!(workFlags & 0x40)) { - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) { + if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); break; }; ReaderTransmit(wupC2, sizeof(wupC2), NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error"); + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) { + if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error"); break; }; } } - if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= 1) Dbprintf("write block send command error"); + if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != CARD_ACK)) { + if (MF_DBGLEVEL >= 1) Dbprintf("write block send command error"); break; }; @@ -1393,8 +1457,8 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai AppendCrc14443a(d_block, 16); ReaderTransmit(d_block, sizeof(d_block), NULL); - if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= 1) Dbprintf("write block send data error"); + if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != CARD_ACK)) { + if (MF_DBGLEVEL >= 1) Dbprintf("write block send data error"); break; }; @@ -1402,7 +1466,7 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai // do no issue halt command for gen1b magic tag (#db# halt error. response len: 1) if (!(workFlags & 0x40)) { if (mifare_classic_halt(NULL, 0)) { - if (MF_DBGLEVEL > 2) Dbprintf("Halt error"); + if (MF_DBGLEVEL > 2) Dbprintf("Halt error"); // Continue, some magic tags misbehavies and send an answer to it. // break; } @@ -1461,15 +1525,15 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai while (true) { if (workFlags & 0x02) { ReaderTransmitBitsPar(wupC1,7,0, NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) { + if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error"); break; }; // do no issue for gen1b magic tag if (!(workFlags & 0x40)) { ReaderTransmit(wupC2, sizeof(wupC2), NULL); - if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) { - if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error"); + if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != CARD_ACK)) { + if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error"); break; }; } @@ -1477,7 +1541,7 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai // read block if ((mifare_sendcmd_short(NULL, 0, 0x30, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 18)) { - if (MF_DBGLEVEL >= 1) Dbprintf("read block send command error"); + if (MF_DBGLEVEL >= 1) Dbprintf("read block send command error"); break; }; memcpy(data, receivedAnswer, 18); @@ -1486,9 +1550,9 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai // do no issue halt command for gen1b magic tag (#db# halt error. response len: 1) if (!(workFlags & 0x40)) { if (mifare_classic_halt(NULL, cuid)) { - if (MF_DBGLEVEL > 1) Dbprintf("Halt error"); + if (MF_DBGLEVEL > 1) Dbprintf("Halt error"); // Continue, some magic tags misbehavies and send an answer to it. - // break; + // break; } } } @@ -1523,34 +1587,34 @@ void MifareCIdent(){ uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; - + LED_A_ON(); LED_B_OFF(); LED_C_OFF(); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); clear_trace(); - set_tracing(true); + set_tracing(true); ReaderTransmitBitsPar(wupC1,7,0, NULL); - if(ReaderReceive(receivedAnswer, receivedAnswerPar) && (receivedAnswer[0] == 0x0a)) { + if(ReaderReceive(receivedAnswer, receivedAnswerPar) && (receivedAnswer[0] == CARD_ACK)) { isOK = 2; ReaderTransmit(wupC2, sizeof(wupC2), NULL); - if(ReaderReceive(receivedAnswer, receivedAnswerPar) && (receivedAnswer[0] == 0x0a)) { + if(ReaderReceive(receivedAnswer, receivedAnswerPar) && (receivedAnswer[0] == CARD_ACK)) { isOK = 1; }; }; // From iceman1001: removed the if, since some magic tags misbehavies and send an answer to it. mifare_classic_halt(NULL, 0); - + LED_B_ON(); cmd_send(CMD_ACK,isOK,0,0,0,0); LED_B_OFF(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); + LEDsoff(); } // @@ -1580,7 +1644,7 @@ void Mifare_DES_Auth1(uint8_t arg0, uint8_t *datain){ } if (MF_DBGLEVEL >= MF_DBG_EXTENDED) DbpString("AUTH 1 FINISHED"); - cmd_send(CMD_ACK,1,cuid,0,dataout, sizeof(dataout)); + cmd_send(CMD_ACK,1,cuid,0,dataout, sizeof(dataout)); } void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain){ diff --git a/armsrc/mifarecmd.h b/armsrc/mifarecmd.h index e17fa998..c16c3a3e 100644 --- a/armsrc/mifarecmd.h +++ b/armsrc/mifarecmd.h @@ -10,18 +10,36 @@ // Routines to support ISO 14443 type A. //----------------------------------------------------------------------------- -#ifndef __MIFARECMD_H -#define __MIFARECMD_H +#ifndef MIFARECMD_H__ +#define MIFARECMD_H__ -#include "proxmark3.h" -#include "apps.h" -#include "util.h" +#include -#include "iso14443crc.h" -#include "iso14443a.h" -#include "crapto1/crapto1.h" -#include "mifareutil.h" -#include "common.h" +extern void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *data); +extern void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain); +extern void MifareUC_Auth(uint8_t arg0, uint8_t *datain); +extern void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain); +extern void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); +extern void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); +//extern void MifareUWriteBlockCompat(uint8_t arg0,uint8_t *datain); +extern void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain); +extern void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); +extern void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain); +extern void MifareChkKeys(uint16_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain); +extern void MifareSetDbgLvl(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); +extern void MifareEMemClr(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); +extern void MifareEMemSet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); +extern void MifareEMemGet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); +extern void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); +extern void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); // Work with "magic Chinese" card +extern void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); +extern void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); +extern void MifareCIdent(); // is "magic chinese" card? +extern void MifareUSetPwd(uint8_t arg0, uint8_t *datain); +extern void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint8_t *datain); +//desfire +extern void Mifare_DES_Auth1(uint8_t arg0,uint8_t *datain); +extern void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain); -#endif \ No newline at end of file +#endif diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index 647305e8..fe5a7485 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -22,6 +22,7 @@ #include "iso14443a.h" #include "crapto1/crapto1.h" #include "mbedtls/des.h" +#include "protocols.h" int MF_DBGLEVEL = MF_DBG_INFO; @@ -163,7 +164,7 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; // Transmit MIFARE_CLASSIC_AUTH - len = mifare_sendcmd_short(pcs, isNested, 0x60 + (keyType & 0x01), blockNo, receivedAnswer, receivedAnswerPar, timing); + len = mifare_sendcmd_short(pcs, isNested, keyType & 0x01 ? MIFARE_AUTH_KEYB : MIFARE_AUTH_KEYA, blockNo, receivedAnswer, receivedAnswerPar, timing); if (MF_DBGLEVEL >= 4) Dbprintf("rand tag nonce len: %x", len); if (len != 4) return 1; @@ -250,7 +251,7 @@ int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blo uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; // command MIFARE_CLASSIC_READBLOCK - len = mifare_sendcmd_short(pcs, 1, 0x30, blockNo, receivedAnswer, receivedAnswerPar, NULL); + len = mifare_sendcmd_short(pcs, 1, MIFARE_CMD_READBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL); if (len == 1) { if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); return 1; @@ -282,7 +283,7 @@ int mifare_ul_ev1_auth(uint8_t *keybytes, uint8_t *pack){ if (MF_DBGLEVEL >= MF_DBG_EXTENDED) Dbprintf("EV1 Auth : %02x%02x%02x%02x", key[0], key[1], key[2], key[3]); - len = mifare_sendcmd(0x1B, key, sizeof(key), resp, respPar, NULL); + len = mifare_sendcmd(MIFARE_ULEV1_AUTH, key, sizeof(key), resp, respPar, NULL); //len = mifare_sendcmd_short_mfuev1auth(NULL, 0, 0x1B, key, resp, respPar, NULL); if (len != 4) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x %u", resp[0], len); @@ -314,7 +315,7 @@ int mifare_ultra_auth(uint8_t *keybytes){ uint8_t respPar[3] = {0,0,0}; // REQUEST AUTHENTICATION - len = mifare_sendcmd_short(NULL, 1, 0x1A, 0x00, resp, respPar ,NULL); + len = mifare_sendcmd_short(NULL, 1, MIFARE_ULC_AUTH_1, 0x00, resp, respPar ,NULL); if (len != 11) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", resp[0]); return 0; @@ -364,7 +365,7 @@ int mifare_ultra_auth(uint8_t *keybytes){ ); //len = mifare_sendcmd_short_mfucauth(NULL, 1, 0xAF, rnd_ab, resp, respPar, NULL); - len = mifare_sendcmd(0xAF, rnd_ab, sizeof(rnd_ab), resp, respPar, NULL); + len = mifare_sendcmd(MIFARE_ULC_AUTH_2, rnd_ab, sizeof(rnd_ab), resp, respPar, NULL); if (len != 11) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", resp[0]); return 0; @@ -421,7 +422,7 @@ int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData) int result = 0; for (retries = 0; retries < MFU_MAX_RETRIES; retries++) { - len = mifare_sendcmd_short(NULL, 1, 0x30, blockNo, receivedAnswer, receivedAnswerPar, NULL); + len = mifare_sendcmd_short(NULL, 1, MIFARE_CMD_READBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL); if (len == 1) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); result = 1; @@ -468,7 +469,7 @@ int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t bl uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; // command MIFARE_CLASSIC_WRITEBLOCK - len = mifare_sendcmd_short(pcs, 1, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL); + len = mifare_sendcmd_short(pcs, 1, MIFARE_CMD_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL); if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); @@ -511,7 +512,7 @@ int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData) uint8_t receivedAnswer[MAX_FRAME_SIZE]; uint8_t receivedAnswerPar[MAX_PARITY_SIZE]; - len = mifare_sendcmd_short(NULL, true, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL); + len = mifare_sendcmd_short(NULL, true, MIFARE_CMD_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL); if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK if (MF_DBGLEVEL >= MF_DBG_ERROR) @@ -563,7 +564,7 @@ int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid) uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; - len = mifare_sendcmd_short(pcs, pcs == NULL ? false:true, 0x50, 0x00, receivedAnswer, receivedAnswerPar, NULL); + len = mifare_sendcmd_short(pcs, pcs == NULL ? false:true, ISO14443A_CMD_HALT, 0x00, receivedAnswer, receivedAnswerPar, NULL); if (len != 0) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("halt error. response len: %x", len); @@ -579,7 +580,7 @@ int mifare_ultra_halt() uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; - len = mifare_sendcmd_short(NULL, true, 0x50, 0x00, receivedAnswer, receivedAnswerPar, NULL); + len = mifare_sendcmd_short(NULL, true, ISO14443A_CMD_HALT, 0x00, receivedAnswer, receivedAnswerPar, NULL); if (len != 0) { if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("halt error. response len: %x", len); diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index c38e276e..9ecf99fb 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -34,6 +34,7 @@ #include "mifare/mad.h" #include "mifare/ndef.h" #include "emv/dump.h" +#include "protocols.h" #define NESTED_SECTOR_RETRY 10 // how often we try mfested() until we give up @@ -92,10 +93,10 @@ int CmdHF14AMfWrBl(const char *Cmd) PrintAndLog("--block no:%d, key type:%c, key:%s", blockNo, keyType?'B':'A', sprint_hex(key, 6)); PrintAndLog("--data: %s", sprint_hex(bldata, 16)); - UsbCommand c = {CMD_MIFARE_WRITEBL, {blockNo, keyType, 0}}; + UsbCommand c = {CMD_MIFARE_WRITEBL, {blockNo, keyType, 0}}; memcpy(c.d.asBytes, key, 6); memcpy(c.d.asBytes + 10, bldata, 16); - SendCommand(&c); + SendCommand(&c); UsbCommand resp; if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { @@ -136,9 +137,9 @@ int CmdHF14AMfRdBl(const char *Cmd) } PrintAndLog("--block no:%d, key type:%c, key:%s ", blockNo, keyType?'B':'A', sprint_hex(key, 6)); - UsbCommand c = {CMD_MIFARE_READBL, {blockNo, keyType, 0}}; + UsbCommand c = {CMD_MIFARE_READBL, {blockNo, keyType, 0}}; memcpy(c.d.asBytes, key, 6); - SendCommand(&c); + SendCommand(&c); UsbCommand resp; if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) { @@ -167,7 +168,7 @@ int CmdHF14AMfRdBl(const char *Cmd) return 2; } - return 0; + return 0; } int CmdHF14AMfRdSc(const char *Cmd) @@ -233,7 +234,7 @@ int CmdHF14AMfRdSc(const char *Cmd) PrintAndLog("Command execute timeout"); } - return 0; + return 0; } uint8_t FirstBlockOfSector(uint8_t sectorNo) @@ -1086,7 +1087,7 @@ int CmdHF14AMfChk(const char *Cmd) bool createDumpFile = 0; bool singleBlock = false; // Flag to ID if a single or multi key check uint8_t keyFoundCount = 0; // Counter to display the number of keys found/transfered to emulator - + sector_t *e_sector = NULL; keyBlock = calloc(stKeyBlock, 6); @@ -1132,7 +1133,7 @@ int CmdHF14AMfChk(const char *Cmd) return 1; }; } - + parseParamTDS(Cmd, 2, &transferToEml, &createDumpFile, &btimeout14a); if (singleBlock & createDumpFile) { @@ -1244,7 +1245,7 @@ int CmdHF14AMfChk(const char *Cmd) uint32_t max_keys = keycnt > USB_CMD_DATA_SIZE / 6 ? USB_CMD_DATA_SIZE / 6 : keycnt; // !SingleKey, so all key check (if SectorsCnt > 0) - if (!singleBlock) { + if (!singleBlock) { PrintAndLog("To cancel this operation press the button on the proxmark..."); printf("--"); for (uint32_t c = 0; c < keycnt; c += max_keys) { @@ -1265,7 +1266,7 @@ int CmdHF14AMfChk(const char *Cmd) PrintAndLog("Command execute timeout"); } } - } else { + } else { int keyAB = keyType; do { for (uint32_t c = 0; c < keycnt; c += max_keys) { @@ -1275,16 +1276,16 @@ int CmdHF14AMfChk(const char *Cmd) clearTraceLog = false; if (res != 1) { - if (!res) { + if (!res) { // Use the common format below // PrintAndLog("Found valid key:[%d:%c]%012" PRIx64, blockNo, (keyAB & 0x01)?'B':'A', key64); foundAKey = true; - + // Store the Single Key for display list // For a single block check, SectorsCnt = Sector that contains the block - e_sector[SectorsCnt-1].foundKey[(keyAB & 0x01)] = true; // flag key found - e_sector[SectorsCnt-1].Key[(keyAB & 0x01)] = key64; // Save key data - + e_sector[SectorsCnt-1].foundKey[(keyAB & 0x01)] = true; // flag key found + e_sector[SectorsCnt-1].Key[(keyAB & 0x01)] = key64; // Save key data + } } else { PrintAndLog("Command execute timeout"); @@ -1327,7 +1328,7 @@ int CmdHF14AMfChk(const char *Cmd) for (uint16_t t = 0; t < 2; t++) { if (e_sector[sectorNo].foundKey[t]) { num_to_bytes(e_sector[sectorNo].Key[t], 6, block + t * 10); - keyFoundCount++; // Key found count for information + keyFoundCount++; // Key found count for information } } mfEmlSetMem(block, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1); @@ -1355,7 +1356,7 @@ int CmdHF14AMfChk(const char *Cmd) fclose(fkeys); PrintAndLog("Found keys have been dumped to file dumpkeys.bin. 0xffffffffffff has been inserted for unknown keys."); } - + free(e_sector); free(keyBlock); PrintAndLog(""); @@ -1710,10 +1711,10 @@ int CmdHF14AMfDbg(const char *Cmd) return 0; } - UsbCommand c = {CMD_MIFARE_SET_DBGMODE, {dbgMode, 0, 0}}; - SendCommand(&c); + UsbCommand c = {CMD_MIFARE_SET_DBGMODE, {dbgMode, 0, 0}}; + SendCommand(&c); - return 0; + return 0; } int CmdHF14AMfEGet(const char *Cmd) @@ -1736,7 +1737,7 @@ int CmdHF14AMfEGet(const char *Cmd) PrintAndLog("Command execute timeout"); } - return 0; + return 0; } int CmdHF14AMfEClear(const char *Cmd) @@ -1747,9 +1748,9 @@ int CmdHF14AMfEClear(const char *Cmd) return 0; } - UsbCommand c = {CMD_MIFARE_EML_MEMCLR, {0, 0, 0}}; - SendCommand(&c); - return 0; + UsbCommand c = {CMD_MIFARE_EML_MEMCLR, {0, 0, 0}}; + SendCommand(&c); + return 0; } @@ -1956,7 +1957,7 @@ int CmdHF14AMfESave(const char *Cmd) PrintAndLog("Saved %d blocks to file: %s", numBlocks, filename); - return 0; + return 0; } @@ -2026,7 +2027,7 @@ int CmdHF14AMfEKeyPrn(const char *Cmd) case '\0': numSectors = 16; break; case '2' : numSectors = 32; break; case '4' : numSectors = 40; break; - case 'd' : + case 'd' : case 'D' : createDumpFile = true; break; } cmdp++; @@ -3009,51 +3010,130 @@ int CmdHFMFNDEF(const char *cmd) { return 0; } -static command_t CommandTable[] = -{ - {"help", CmdHelp, 1, "This help"}, - {"dbg", CmdHF14AMfDbg, 0, "Set default debug mode"}, - {"rdbl", CmdHF14AMfRdBl, 0, "Read MIFARE classic block"}, - {"rdsc", CmdHF14AMfRdSc, 0, "Read MIFARE classic sector"}, - {"dump", CmdHF14AMfDump, 0, "Dump MIFARE classic tag to binary file"}, - {"restore", CmdHF14AMfRestore, 0, "Restore MIFARE classic binary file to BLANK tag"}, - {"wrbl", CmdHF14AMfWrBl, 0, "Write MIFARE classic block"}, - {"auth4", CmdHF14AMfAuth4, 0, "ISO14443-4 AES authentication"}, - {"chk", CmdHF14AMfChk, 0, "Test block keys"}, - {"mifare", CmdHF14AMifare, 0, "Read parity error messages."}, - {"hardnested", CmdHF14AMfNestedHard, 0, "Nested attack for hardened Mifare cards"}, - {"nested", CmdHF14AMfNested, 0, "Test nested authentication"}, - {"sniff", CmdHF14AMfSniff, 0, "Sniff card-reader communication"}, - {"sim", CmdHF14AMfSim, 0, "Simulate MIFARE card"}, - {"eclr", CmdHF14AMfEClear, 0, "Clear simulator memory"}, - {"eget", CmdHF14AMfEGet, 0, "Get simulator memory block"}, - {"eset", CmdHF14AMfESet, 0, "Set simulator memory block"}, - {"eload", CmdHF14AMfELoad, 0, "Load from file emul dump"}, - {"esave", CmdHF14AMfESave, 0, "Save to file emul dump"}, - {"ecfill", CmdHF14AMfECFill, 0, "Fill simulator memory with help of keys from simulator"}, - {"ekeyprn", CmdHF14AMfEKeyPrn, 0, "Print keys from simulator memory"}, - {"cwipe", CmdHF14AMfCWipe, 0, "Wipe magic Chinese card"}, - {"csetuid", CmdHF14AMfCSetUID, 0, "Set UID for magic Chinese card"}, - {"csetblk", CmdHF14AMfCSetBlk, 0, "Write block - Magic Chinese card"}, - {"cgetblk", CmdHF14AMfCGetBlk, 0, "Read block - Magic Chinese card"}, - {"cgetsc", CmdHF14AMfCGetSc, 0, "Read sector - Magic Chinese card"}, - {"cload", CmdHF14AMfCLoad, 0, "Load dump into magic Chinese card"}, - {"csave", CmdHF14AMfCSave, 0, "Save dump from magic Chinese card into file or emulator"}, - {"decrypt", CmdDecryptTraceCmds, 1, "[nt] [ar_enc] [at_enc] [data] - to decrypt snoop or trace"}, - {"mad", CmdHF14AMfMAD, 0, "Checks and prints MAD"}, - {"ndef", CmdHFMFNDEF, 0, "Prints NDEF records from card"}, - {NULL, NULL, 0, NULL} +int CmdHFMFPersonalize(const char *cmd) { + + CLIParserInit("hf mf personalize", + "Personalize the UID of a Mifare Classic EV1 card. This is only possible if it is a 7Byte UID card and if it is not already personalized.", + "Usage:\n\thf mf personalize UIDF0 -> double size UID according to ISO/IEC14443-3\n" + "\thf mf personalize UIDF1 -> double size UID according to ISO/IEC14443-3, optional usage of selection process shortcut\n" + "\thf mf personalize UIDF2 -> single size random ID according to ISO/IEC14443-3\n" + "\thf mf personalize UIDF3 -> single size NUID according to ISO/IEC14443-3\n" + "\thf mf personalize -t B -k B0B1B2B3B4B5 UIDF3 -> use key B = 0xB0B1B2B3B4B5 instead of default key A\n"); + + void *argtable[] = { + arg_param_begin, + arg_str0("tT", "keytype", "", "key type (A or B) to authenticate sector 0 (default: A)"), + arg_str0("kK", "key", "", "key to authenticate sector 0 (default: FFFFFFFFFFFF)"), + arg_str1(NULL, NULL, "", "Personalization Option"), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, true); + + char keytypestr[2] = "A"; + uint8_t keytype = 0x00; + int keytypestr_len; + int res = CLIParamStrToBuf(arg_get_str(1), (uint8_t*)keytypestr, 1, &keytypestr_len); + if (res || (keytypestr[0] != 'a' && keytypestr[0] != 'A' && keytypestr[0] != 'b' && keytypestr[0] != 'B')) { + PrintAndLog("ERROR: not a valid key type. Key type must be A or B"); + CLIParserFree(); + return 1; + } + if (keytypestr[0] == 'B' || keytypestr[0] == 'b') { + keytype = 0x01; + } + + uint8_t key[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + int key_len; + res = CLIParamHexToBuf(arg_get_str(2), key, 6, &key_len); + if (res || (!res && key_len > 0 && key_len != 6)) { + PrintAndLog("ERROR: not a valid key. Key must be 12 hex digits"); + CLIParserFree(); + return 1; + } + + char pers_optionstr[6]; + int opt_len; + uint8_t pers_option; + res = CLIParamStrToBuf(arg_get_str(3), (uint8_t*)pers_optionstr, 5, &opt_len); + if (res || (!res && opt_len > 0 && opt_len != 5) + || (strncmp(pers_optionstr, "UIDF0", 5) && strncmp(pers_optionstr, "UIDF1", 5) && strncmp(pers_optionstr, "UIDF2", 5) && strncmp(pers_optionstr, "UIDF3", 5))) { + PrintAndLog("ERROR: invalid personalization option. Must be one of UIDF0, UIDF1, UIDF2, or UIDF3"); + CLIParserFree(); + return 1; + } + if (!strncmp(pers_optionstr, "UIDF0", 5)) { + pers_option = MIFARE_EV1_UIDF0; + } else if (!strncmp(pers_optionstr, "UIDF1", 5)) { + pers_option = MIFARE_EV1_UIDF1; + } else if (!strncmp(pers_optionstr, "UIDF2", 5)) { + pers_option = MIFARE_EV1_UIDF2; + } else { + pers_option = MIFARE_EV1_UIDF3; + } + + CLIParserFree(); + + UsbCommand c = {CMD_MIFARE_PERSONALIZE_UID, {keytype, pers_option, 0}}; + memcpy(c.d.asBytes, key, 6); + SendCommand(&c); + + UsbCommand resp; + if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + uint8_t isOK = resp.arg[0] & 0xff; + PrintAndLog("Personalization %s", isOK ? "FAILED" : "SUCCEEDED"); + } else { + PrintAndLog("Command execute timeout"); + } + + return 0; +} + + +static command_t CommandTable[] = { + {"help", CmdHelp, 1, "This help"}, + {"dbg", CmdHF14AMfDbg, 0, "Set default debug mode"}, + {"rdbl", CmdHF14AMfRdBl, 0, "Read MIFARE classic block"}, + {"rdsc", CmdHF14AMfRdSc, 0, "Read MIFARE classic sector"}, + {"dump", CmdHF14AMfDump, 0, "Dump MIFARE classic tag to binary file"}, + {"restore", CmdHF14AMfRestore, 0, "Restore MIFARE classic binary file to BLANK tag"}, + {"wrbl", CmdHF14AMfWrBl, 0, "Write MIFARE classic block"}, + {"auth4", CmdHF14AMfAuth4, 0, "ISO14443-4 AES authentication"}, + {"chk", CmdHF14AMfChk, 0, "Test block keys"}, + {"mifare", CmdHF14AMifare, 0, "Read parity error messages."}, + {"hardnested", CmdHF14AMfNestedHard, 0, "Nested attack for hardened Mifare cards"}, + {"nested", CmdHF14AMfNested, 0, "Test nested authentication"}, + {"sniff", CmdHF14AMfSniff, 0, "Sniff card-reader communication"}, + {"sim", CmdHF14AMfSim, 0, "Simulate MIFARE card"}, + {"eclr", CmdHF14AMfEClear, 0, "Clear simulator memory"}, + {"eget", CmdHF14AMfEGet, 0, "Get simulator memory block"}, + {"eset", CmdHF14AMfESet, 0, "Set simulator memory block"}, + {"eload", CmdHF14AMfELoad, 0, "Load from file emul dump"}, + {"esave", CmdHF14AMfESave, 0, "Save to file emul dump"}, + {"ecfill", CmdHF14AMfECFill, 0, "Fill simulator memory with help of keys from simulator"}, + {"ekeyprn", CmdHF14AMfEKeyPrn, 0, "Print keys from simulator memory"}, + {"cwipe", CmdHF14AMfCWipe, 0, "Wipe magic Chinese card"}, + {"csetuid", CmdHF14AMfCSetUID, 0, "Set UID for magic Chinese card"}, + {"csetblk", CmdHF14AMfCSetBlk, 0, "Write block - Magic Chinese card"}, + {"cgetblk", CmdHF14AMfCGetBlk, 0, "Read block - Magic Chinese card"}, + {"cgetsc", CmdHF14AMfCGetSc, 0, "Read sector - Magic Chinese card"}, + {"cload", CmdHF14AMfCLoad, 0, "Load dump into magic Chinese card"}, + {"csave", CmdHF14AMfCSave, 0, "Save dump from magic Chinese card into file or emulator"}, + {"decrypt", CmdDecryptTraceCmds, 1, "[nt] [ar_enc] [at_enc] [data] - to decrypt snoop or trace"}, + {"mad", CmdHF14AMfMAD, 0, "Checks and prints MAD"}, + {"ndef", CmdHFMFNDEF, 0, "Prints NDEF records from card"}, + {"personalize", CmdHFMFPersonalize, 0, "Personalize UID (Mifare Classic EV1 only)"}, + {NULL, NULL, 0, NULL} }; -int CmdHFMF(const char *Cmd) -{ + +int CmdHFMF(const char *Cmd) { (void)WaitForResponseTimeout(CMD_ACK,NULL,100); CmdsParse(CommandTable, Cmd); return 0; } -int CmdHelp(const char *Cmd) -{ - CmdsHelp(CommandTable); - return 0; + +int CmdHelp(const char *Cmd) { + CmdsHelp(CommandTable); + return 0; } diff --git a/client/util.c b/client/util.c index cd18fc00..7e230488 100644 --- a/client/util.c +++ b/client/util.c @@ -26,7 +26,7 @@ #ifndef _WIN32 #include -#include +#include #include int ukbhit(void) @@ -42,11 +42,11 @@ int ukbhit(void) Ntty.c_oflag = 0x0000; // output mode Ntty.c_lflag &= ~ICANON; // control mode = raw Ntty.c_cc[VMIN] = 1; // return if at least 1 character is in the queue - Ntty.c_cc[VTIME] = 0; // no timeout. Wait forever - + Ntty.c_cc[VTIME] = 0; // no timeout. Wait forever + if (0 == (error = tcsetattr(STDIN_FILENO, TCSANOW, &Ntty))) { // set new attributes - error += ioctl(STDIN_FILENO, FIONREAD, &cnt); // get number of characters availabe - error += tcsetattr(STDIN_FILENO, TCSANOW, &Otty); // reset attributes + error += ioctl(STDIN_FILENO, FIONREAD, &cnt); // get number of characters availabe + error += tcsetattr(STDIN_FILENO, TCSANOW, &Otty); // reset attributes } return ( error == 0 ? cnt : -1 ); @@ -78,13 +78,13 @@ int ukbhit(void) { // log files functions void AddLogLine(char *file, char *extData, char *c) { FILE *fLog = NULL; - char filename[FILE_PATH_SIZE] = {0x00}; - int len = 0; + char filename[FILE_PATH_SIZE] = {0x00}; + int len = 0; + + len = strlen(file); + if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; + memcpy(filename, file, len); - len = strlen(file); - if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; - memcpy(filename, file, len); - fLog = fopen(filename, "a"); if (!fLog) { printf("Could not append log file %s", filename); @@ -119,10 +119,10 @@ void AddLogCurrentDT(char *fileName) { void FillFileNameByUID(char *fileName, uint8_t *uid, char *ext, int byteCount) { char * fnameptr = fileName; - + for (int j = 0; j < byteCount; j++, fnameptr += 2) - sprintf(fnameptr, "%02x", (unsigned int) uid[j]); - sprintf(fnameptr, "%s", ext); + sprintf(fnameptr, "%02x", (unsigned int) uid[j]); + sprintf(fnameptr, "%s", ext); } // fill buffer from structure [{uint8_t data, size_t length},...] @@ -130,25 +130,25 @@ int FillBuffer(uint8_t *data, size_t maxDataLength, size_t *dataLength, ...) { *dataLength = 0; va_list valist; va_start(valist, dataLength); - + uint8_t *vdata = NULL; size_t vlength = 0; do{ vdata = va_arg(valist, uint8_t *); if (!vdata) break; - + vlength = va_arg(valist, size_t); if (*dataLength + vlength > maxDataLength) { va_end(valist); return 1; } - + memcpy(&data[*dataLength], vdata, vlength); *dataLength += vlength; - + } while (vdata); - + va_end(valist); return 0; @@ -161,13 +161,13 @@ bool CheckStringIsHEXValue(const char *value) { if (strlen(value) % 2) return false; - + return true; } -void hex_to_buffer(const uint8_t *buf, const uint8_t *hex_data, const size_t hex_len, const size_t hex_max_len, +void hex_to_buffer(const uint8_t *buf, const uint8_t *hex_data, const size_t hex_len, const size_t hex_max_len, const size_t min_str_len, const size_t spaces_between, bool uppercase) { - + char *tmp = (char *)buf; size_t i; memset(tmp, 0x00, hex_max_len); @@ -175,17 +175,17 @@ void hex_to_buffer(const uint8_t *buf, const uint8_t *hex_data, const size_t hex int maxLen = ( hex_len > hex_max_len) ? hex_max_len : hex_len; for (i = 0; i < maxLen; ++i, tmp += 2 + spaces_between) { - sprintf(tmp, (uppercase) ? "%02X" : "%02x", (unsigned int) hex_data[i]); - + sprintf(tmp, (uppercase) ? "%02X" : "%02x", (unsigned int) hex_data[i]); + for (int j = 0; j < spaces_between; j++) sprintf(tmp + 2 + j, " "); } - + i *= (2 + spaces_between); int minStrLen = min_str_len > i ? min_str_len : 0; if (minStrLen > hex_max_len) minStrLen = hex_max_len; - for(; i < minStrLen; i++, tmp += 1) + for(; i < minStrLen; i++, tmp += 1) sprintf(tmp, " "); return; @@ -195,7 +195,7 @@ void hex_to_buffer(const uint8_t *buf, const uint8_t *hex_data, const size_t hex char *sprint_hex(const uint8_t *data, const size_t len) { static char buf[4097] = {0}; - + hex_to_buffer((uint8_t *)buf, data, len, sizeof(buf) - 1, 0, 1, false); return buf; @@ -259,16 +259,16 @@ char *sprint_ascii_ex(const uint8_t *data, const size_t len, const size_t min_st tmp[i] = ((c < 32) || (c == 127)) ? '.' : c; ++i; } - + int minStrLen = min_str_len > i ? min_str_len : 0; - for(; i < minStrLen; ++i) + for(; i < minStrLen; ++i) tmp[i] = ' '; - + return buf; } char *sprint_ascii(const uint8_t *data, const size_t len) { - return sprint_ascii_ex(data, len, 0); + return sprint_ascii_ex(data, len, 0); } void num_to_bytes(uint64_t n, size_t len, uint8_t* dest) @@ -290,7 +290,7 @@ uint64_t bytes_to_num(uint8_t* src, size_t len) return num; } -void num_to_bytebits(uint64_t n, size_t len, uint8_t *dest) { +void num_to_bytebits(uint64_t n, size_t len, uint8_t *dest) { while (len--) { dest[len] = n & 1; n >>= 1; @@ -333,22 +333,22 @@ uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockS //assumes little endian char *printBits(size_t const size, void const * const ptr) { - unsigned char *b = (unsigned char*) ptr; - unsigned char byte; + unsigned char *b = (unsigned char*) ptr; + unsigned char byte; static char buf[1024]; char *tmp = buf; - int i, j; + int i, j; - for (i=size-1;i>=0;i--) - { - for (j=7;j>=0;j--) - { - byte = b[i] & (1<>= j; - sprintf(tmp, "%u", (unsigned int)byte); + for (i=size-1;i>=0;i--) + { + for (j=7;j>=0;j--) + { + byte = b[i] & (1<>= j; + sprintf(tmp, "%u", (unsigned int)byte); tmp++; - } - } + } + } return buf; } @@ -382,10 +382,10 @@ int param_getptr(const char *line, int *bg, int *en, int paramnum) { int i; int len = strlen(line); - + *bg = 0; *en = 0; - + // skip spaces while (line[*bg] ==' ' || line[*bg]=='\t') (*bg)++; if (*bg >= len) { @@ -395,13 +395,13 @@ int param_getptr(const char *line, int *bg, int *en, int paramnum) for (i = 0; i < paramnum; i++) { while (line[*bg]!=' ' && line[*bg]!='\t' && line[*bg] != '\0') (*bg)++; while (line[*bg]==' ' || line[*bg]=='\t') (*bg)++; - + if (line[*bg] == '\0') return 1; } - + *en = *bg; while (line[*en] != ' ' && line[*en] != '\t' && line[*en] != '\0') (*en)++; - + (*en)--; return 0; @@ -411,7 +411,7 @@ int param_getptr(const char *line, int *bg, int *en, int paramnum) int param_getlength(const char *line, int paramnum) { int bg, en; - + if (param_getptr(line, &bg, &en, paramnum)) return 0; return en - bg + 1; @@ -423,12 +423,12 @@ char param_getchar(const char *line, int paramnum) { char param_getchar_indx(const char *line, int indx, int paramnum) { int bg, en; - + if (param_getptr(line, &bg, &en, paramnum)) return 0x00; if (bg + indx > en) return '\0'; - + return line[bg + indx]; } @@ -461,7 +461,7 @@ uint8_t param_isdec(const char *line, int paramnum) int bg, en; //TODO, check more thorougly if (!param_getptr(line, &bg, &en, paramnum)) return 1; - // return strtoul(&line[bg], NULL, 10) & 0xff; + // return strtoul(&line[bg], NULL, 10) & 0xff; return 0; } @@ -470,7 +470,7 @@ uint8_t param_get8ex(const char *line, int paramnum, int deflt, int base) { int bg, en; - if (!param_getptr(line, &bg, &en, paramnum)) + if (!param_getptr(line, &bg, &en, paramnum)) return strtoul(&line[bg], NULL, base) & 0xff; else return deflt; @@ -480,7 +480,7 @@ uint32_t param_get32ex(const char *line, int paramnum, int deflt, int base) { int bg, en; - if (!param_getptr(line, &bg, &en, paramnum)) + if (!param_getptr(line, &bg, &en, paramnum)) return strtoul(&line[bg], NULL, base); else return deflt; @@ -490,30 +490,30 @@ uint64_t param_get64ex(const char *line, int paramnum, int deflt, int base) { int bg, en; - if (!param_getptr(line, &bg, &en, paramnum)) + if (!param_getptr(line, &bg, &en, paramnum)) return strtoull(&line[bg], NULL, base); else return deflt; } -int param_gethex(const char *line, int paramnum, uint8_t * data, int hexcnt) +int param_gethex(const char *line, int paramnum, uint8_t *data, int hexcnt) { int bg, en, temp, i; if (hexcnt % 2) return 1; - + if (param_getptr(line, &bg, &en, paramnum)) return 1; - if (en - bg + 1 != hexcnt) + if (en - bg + 1 != hexcnt) return 1; for(i = 0; i < hexcnt; i += 2) { - if (!(isxdigit((unsigned char)line[bg + i]) && isxdigit((unsigned char)line[bg + i + 1])) ) return 1; - + if (!(isxdigit((unsigned char)line[bg + i]) && isxdigit((unsigned char)line[bg + i + 1])) ) return 1; + sscanf((char[]){line[bg + i], line[bg + i + 1], 0}, "%X", &temp); data[i / 2] = temp & 0xff; - } + } return 0; } @@ -523,22 +523,22 @@ int param_gethex_ex(const char *line, int paramnum, uint8_t *data, int *hexcnt) int bg, en, temp, i; //if (hexcnt % 2) - // return 1; - + // return 1; + if (param_getptr(line, &bg, &en, paramnum)) return 1; if (en - bg + 1 > *hexcnt) return 1; - + *hexcnt = en - bg + 1; if (*hexcnt % 2) //error if not complete hex bytes return 1; for(i = 0; i < *hexcnt; i += 2) { - if (!(isxdigit((unsigned char)line[bg + i]) && isxdigit((unsigned char)line[bg + i + 1])) ) return 1; - + if (!(isxdigit((unsigned char)line[bg + i]) && isxdigit((unsigned char)line[bg + i + 1])) ) return 1; + sscanf((char[]){line[bg + i], line[bg + i + 1], 0}, "%X", &temp); data[i / 2] = temp & 0xff; - } + } return 0; } @@ -551,21 +551,21 @@ int param_gethex_to_eol(const char *line, int paramnum, uint8_t * data, int maxd if (param_getptr(line, &bg, &en, paramnum)) return 1; *datalen = 0; - + int indx = bg; while (line[indx]) { if (line[indx] == '\t' || line[indx] == ' ') { indx++; continue; } - + if (isxdigit((unsigned char)line[indx])) { buf[strlen(buf) + 1] = 0x00; buf[strlen(buf)] = line[indx]; } else { // if we have symbols other than spaces and hex return 1; - } + } if (*datalen >= maxdatalen) { // if we dont have space in buffer and have symbols to translate @@ -578,14 +578,14 @@ int param_gethex_to_eol(const char *line, int paramnum, uint8_t * data, int maxd *buf = 0; (*datalen)++; } - + indx++; } - if (strlen(buf) > 0) + if (strlen(buf) > 0) //error when not completed hex bytes return 3; - + return 0; } @@ -593,7 +593,7 @@ int param_getstr(const char *line, int paramnum, char * str, size_t buffersize) { int bg, en; - if (param_getptr(line, &bg, &en, paramnum)) { + if (param_getptr(line, &bg, &en, paramnum)) { return 0; } @@ -602,10 +602,10 @@ int param_getstr(const char *line, int paramnum, char * str, size_t buffersize) printf("out of bounds error: want %d bytes have %zd bytes\n", en - bg + 1 + 1, buffersize); return 0; } - + memcpy(str, line + bg, en - bg + 1); str[en - bg + 1] = 0; - + return en - bg + 1; } @@ -618,100 +618,100 @@ https://github.com/ApertureLabsLtd/RFIDler/blob/master/firmware/Pic32/RFIDler.X/ // returns number of bits converted int hextobinarray(char *target, char *source) { - int length, i, count= 0; - char* start = source; - char x; + int length, i, count= 0; + char* start = source; + char x; - length = strlen(source); - // process 4 bits (1 hex digit) at a time - while(length--) - { - x= *(source++); - // capitalize - if (x >= 'a' && x <= 'f') - x -= 32; - // convert to numeric value - if (x >= '0' && x <= '9') - x -= '0'; - else if (x >= 'A' && x <= 'F') - x -= 'A' - 10; - else { - printf("Discovered unknown character %c %d at idx %tu of %s\n", x, x, source - start, start); - return 0; - } - // output - for(i= 0 ; i < 4 ; ++i, ++count) - *(target++)= (x >> (3 - i)) & 1; - } - - return count; + length = strlen(source); + // process 4 bits (1 hex digit) at a time + while(length--) + { + x= *(source++); + // capitalize + if (x >= 'a' && x <= 'f') + x -= 32; + // convert to numeric value + if (x >= '0' && x <= '9') + x -= '0'; + else if (x >= 'A' && x <= 'F') + x -= 'A' - 10; + else { + printf("Discovered unknown character %c %d at idx %tu of %s\n", x, x, source - start, start); + return 0; + } + // output + for(i= 0 ; i < 4 ; ++i, ++count) + *(target++)= (x >> (3 - i)) & 1; + } + + return count; } // convert binary array of 0x00/0x01 values to hex (safe to do in place as target will always be shorter than source) // return number of bits converted int binarraytohex(char *target,char *source, int length) { - unsigned char i, x; - int j = length; + unsigned char i, x; + int j = length; - if(j % 4) - return 0; + if(j % 4) + return 0; - while(j) - { - for(i= x= 0 ; i < 4 ; ++i) - x += ( source[i] << (3 - i)); - sprintf(target,"%X", (unsigned int)x); - ++target; - source += 4; - j -= 4; - } - return length; + while(j) + { + for(i= x= 0 ; i < 4 ; ++i) + x += ( source[i] << (3 - i)); + sprintf(target,"%X", (unsigned int)x); + ++target; + source += 4; + j -= 4; + } + return length; } // return parity bit required to match type uint8_t GetParity( uint8_t *bits, uint8_t type, int length) { - int x; + int x; - for(x= 0 ; length > 0 ; --length) - x += bits[length - 1]; - x %= 2; + for(x= 0 ; length > 0 ; --length) + x += bits[length - 1]; + x %= 2; - return x ^ type; + return x ^ type; } // add HID parity to binary array: EVEN prefix for 1st half of ID, ODD suffix for 2nd half void wiegand_add_parity(uint8_t *target, uint8_t *source, uint8_t length) { - *(target++)= GetParity(source, EVEN, length / 2); - memcpy(target, source, length); - target += length; - *(target)= GetParity(source + length / 2, ODD, length / 2); + *(target++)= GetParity(source, EVEN, length / 2); + memcpy(target, source, length); + target += length; + *(target)= GetParity(source + length / 2, ODD, length / 2); } // xor two arrays together for len items. The dst array contains the new xored values. void xor(unsigned char *dst, unsigned char *src, size_t len) { for( ; len > 0; len--,dst++,src++) - *dst ^= *src; + *dst ^= *src; } // RotateLeft - Ultralight, Desfire, works on byte level // 00-01-02 >> 01-02-00 void rol(uint8_t *data, const size_t len){ - uint8_t first = data[0]; - for (size_t i = 0; i < len-1; i++) { - data[i] = data[i+1]; - } - data[len-1] = first; + uint8_t first = data[0]; + for (size_t i = 0; i < len-1; i++) { + data[i] = data[i+1]; + } + data[len-1] = first; } // Replace unprintable characters with a dot in char buffer void clean_ascii(unsigned char *buf, size_t len) { for (size_t i = 0; i < len; i++) { - if (!isprint(buf[i])) - buf[i] = '.'; + if (!isprint(buf[i])) + buf[i] = '.'; } } @@ -724,8 +724,8 @@ void strcleanrn(char *buf, size_t len) { // replace char in buffer void strcreplace(char *buf, size_t len, char from, char to) { for (size_t i = 0; i < len; i++) { - if (buf[i] == from) - buf[i] = to; + if (buf[i] == from) + buf[i] = to; } } @@ -734,7 +734,7 @@ char *strmcopy(char *buf) { if ((str = (char*) malloc(strlen(buf) + 1)) != NULL) { memset(str, 0, strlen(buf) + 1); strcpy(str, buf); - } + } return str; } diff --git a/common/protocols.h b/common/protocols.h index ab556516..51fe579e 100644 --- a/common/protocols.h +++ b/common/protocols.h @@ -125,6 +125,10 @@ NXP/Philips CUSTOM COMMANDS #define MIFARE_CMD_TRANSFER 0xB0 #define MIFARE_EV1_PERSONAL_UID 0x40 +#define MIFARE_EV1_UIDF0 0x00 +#define MIFARE_EV1_UIDF1 0x40 +#define MIFARE_EV1_UIDF2 0x20 +#define MIFARE_EV1_UIDF3 0x60 #define MIFARE_EV1_SETMODE 0x43 #define MIFARE_ULC_WRITE 0xA2 diff --git a/include/usb_cmd.h b/include/usb_cmd.h index c998bf94..1bc5e5ba 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -197,17 +197,17 @@ typedef struct{ #define CMD_MIFARE_ACQUIRE_ENCRYPTED_NONCES 0x0613 #define CMD_MIFARE_READBL 0x0620 -#define CMD_MIFAREU_READBL 0x0720 #define CMD_MIFARE_READSC 0x0621 -#define CMD_MIFAREU_READCARD 0x0721 #define CMD_MIFARE_WRITEBL 0x0622 +#define CMD_MIFARE_CHKKEYS 0x0623 +#define CMD_MIFARE_PERSONALIZE_UID 0x0624 +#define CMD_MIFARE_SNIFFER 0x0630 + +//ultralightC +#define CMD_MIFAREU_READBL 0x0720 +#define CMD_MIFAREU_READCARD 0x0721 #define CMD_MIFAREU_WRITEBL 0x0722 #define CMD_MIFAREU_WRITEBL_COMPAT 0x0723 - -#define CMD_MIFARE_CHKKEYS 0x0623 - -#define CMD_MIFARE_SNIFFER 0x0630 -//ultralightC #define CMD_MIFAREUC_AUTH 0x0724 //0x0725 and 0x0726 no longer used #define CMD_MIFAREUC_SETPWD 0x0727 From f2dbf3d2aafb2fde8822ec16fd7b360a0308a295 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Thu, 22 Aug 2019 07:54:55 +0200 Subject: [PATCH 124/189] 'lf hitag writer': add Hitag2 password auth * (PRs 233, 303, 304 by @ViRb3 on https://github.com/RfidResearchGroup/proxmark3) * replace byte_t by uint8_t * note that Hitag1 commands are not yet available * whitespace fixes * #define Hitag2 commands * whitespace * add EOF wait time * add powerup wait time --- armsrc/apps.h | 1 - armsrc/hitag2.c | 1486 ++++++++++++++++++++++--------------------- armsrc/hitag2.h | 8 +- armsrc/hitagS.c | 75 +-- armsrc/util.h | 22 +- client/cmdlfhitag.c | 319 ++++++---- client/cmdlfhitag.h | 8 +- common/protocols.h | 20 + include/hitag.h | 1 + 9 files changed, 1026 insertions(+), 914 deletions(-) diff --git a/armsrc/apps.h b/armsrc/apps.h index ae5e3977..8aef19fb 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -16,7 +16,6 @@ #include #include "common.h" #include "usb_cmd.h" -#include "hitag2.h" #include "hitagS.h" #include "mifare.h" #include "../common/crc32.h" diff --git a/armsrc/hitag2.c b/armsrc/hitag2.c index 270958ce..7cdabefa 100644 --- a/armsrc/hitag2.c +++ b/armsrc/hitag2.c @@ -19,12 +19,14 @@ #include "hitag2.h" #include "proxmark3.h" +#include "cmd.h" #include "apps.h" #include "util.h" #include "hitag.h" #include "string.h" #include "BigBuf.h" #include "fpgaloader.h" +#include "protocols.h" static bool bQuiet; @@ -44,9 +46,9 @@ struct hitag2_tag { TAG_STATE_WRITING = 0x04, // In write command, awaiting sector contents to be written } state; unsigned int active_sector; - byte_t crypto_active; + uint8_t crypto_active; uint64_t cs; - byte_t sectors[12][4]; + uint8_t sectors[12][4]; }; static struct hitag2_tag tag = { @@ -77,14 +79,14 @@ static enum { // ToDo: define a meaningful maximum size for auth_table. The bigger this is, the lower will be the available memory for traces. // Historically it used to be FREE_BUFFER_SIZE, which was 2744. #define AUTH_TABLE_LENGTH 2744 -static byte_t* auth_table; +static uint8_t *auth_table; static size_t auth_table_pos = 0; static size_t auth_table_len = AUTH_TABLE_LENGTH; -static byte_t password[4]; -static byte_t NrAr[8]; -static byte_t key[8]; -static byte_t writedata[4]; +static uint8_t password[4]; +static uint8_t NrAr[8]; +static uint8_t key[8]; +static uint8_t writedata[4]; static uint64_t cipher_state; /* Following is a modified version of cryptolib.com/ciphers/hitag2/ */ @@ -93,57 +95,39 @@ static uint64_t cipher_state; // No warranties or guarantees of any kind. // This code is released into the public domain by its author. -// Basic macros: - -#define u8 uint8_t -#define u32 uint32_t -#define u64 uint64_t -#define rev8(x) ((((x)>>7)&1)+((((x)>>6)&1)<<1)+((((x)>>5)&1)<<2)+((((x)>>4)&1)<<3)+((((x)>>3)&1)<<4)+((((x)>>2)&1)<<5)+((((x)>>1)&1)<<6)+(((x)&1)<<7)) -#define rev16(x) (rev8 (x)+(rev8 (x>> 8)<< 8)) -#define rev32(x) (rev16(x)+(rev16(x>>16)<<16)) -#define rev64(x) (rev32(x)+(rev32(x>>32)<<32)) -#define bit(x,n) (((x)>>(n))&1) -#define bit32(x,n) ((((x)[(n)>>5])>>((n)))&1) -#define inv32(x,i,n) ((x)[(i)>>5]^=((u32)(n))<<((i)&31)) -#define rotl64(x, n) ((((u64)(x))<<((n)&63))+(((u64)(x))>>((0-(n))&63))) - // Single bit Hitag2 functions: -#define i4(x,a,b,c,d) ((u32)((((x)>>(a))&1)+(((x)>>(b))&1)*2+(((x)>>(c))&1)*4+(((x)>>(d))&1)*8)) +#define i4(x,a,b,c,d) ((uint32_t)((((x)>>(a))&1)+(((x)>>(b))&1)*2+(((x)>>(c))&1)*4+(((x)>>(d))&1)*8)) -static const u32 ht2_f4a = 0x2C79; // 0010 1100 0111 1001 -static const u32 ht2_f4b = 0x6671; // 0110 0110 0111 0001 -static const u32 ht2_f5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011 +static const uint32_t ht2_f4a = 0x2C79; // 0010 1100 0111 1001 +static const uint32_t ht2_f4b = 0x6671; // 0110 0110 0111 0001 +static const uint32_t ht2_f5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011 -static u32 _f20 (const u64 x) -{ - u32 i5; +static uint32_t _f20(const uint64_t x) { + uint32_t i5; - i5 = ((ht2_f4a >> i4 (x, 1, 2, 4, 5)) & 1)* 1 - + ((ht2_f4b >> i4 (x, 7,11,13,14)) & 1)* 2 - + ((ht2_f4b >> i4 (x,16,20,22,25)) & 1)* 4 - + ((ht2_f4b >> i4 (x,27,28,30,32)) & 1)* 8 - + ((ht2_f4a >> i4 (x,33,42,43,45)) & 1)*16; + i5 = ((ht2_f4a >> i4(x, 1, 2, 4, 5)) & 1) * 1 + + ((ht2_f4b >> i4(x, 7,11,13,14)) & 1) * 2 + + ((ht2_f4b >> i4(x,16,20,22,25)) & 1) * 4 + + ((ht2_f4b >> i4(x,27,28,30,32)) & 1) * 8 + + ((ht2_f4a >> i4(x,33,42,43,45)) & 1) * 16; return (ht2_f5c >> i5) & 1; } -static u64 _hitag2_init (const u64 key, const u32 serial, const u32 IV) -{ - u32 i; - u64 x = ((key & 0xFFFF) << 32) + serial; +static uint64_t _hitag2_init(const uint64_t key, const uint32_t serial, const uint32_t IV) { + uint32_t i; + uint64_t x = ((key & 0xFFFF) << 32) + serial; - for (i = 0; i < 32; i++) - { + for (i = 0; i < 32; i++) { x >>= 1; - x += (u64) (_f20 (x) ^ (((IV >> i) ^ (key >> (i+16))) & 1)) << 47; + x += (uint64_t)(_f20(x) ^ (((IV >> i) ^ (key >> (i+16))) & 1)) << 47; } return x; } -static u64 _hitag2_round (u64 *state) -{ - u64 x = *state; +static uint64_t _hitag2_round(uint64_t *state) { + uint64_t x = *state; x = (x >> 1) + ((((x >> 0) ^ (x >> 2) ^ (x >> 3) ^ (x >> 6) @@ -152,40 +136,36 @@ static u64 _hitag2_round (u64 *state) ^ (x >> 42) ^ (x >> 43) ^ (x >> 46) ^ (x >> 47)) & 1) << 47); *state = x; - return _f20 (x); + return _f20(x); } -static u32 _hitag2_byte (u64 * x) -{ - u32 i, c; - - for (i = 0, c = 0; i < 8; i++) c += (u32) _hitag2_round (x) << (i^7); +static uint32_t _hitag2_byte(uint64_t *x) { + uint32_t i, c; + for (i = 0, c = 0; i < 8; i++) { + c += (uint32_t) _hitag2_round(x) << (i^7); + } return c; } -static int hitag2_reset(void) -{ +static int hitag2_reset(void) { tag.state = TAG_STATE_RESET; tag.crypto_active = 0; return 0; } -static int hitag2_init(void) -{ -// memcpy(&tag, &resetdata, sizeof(tag)); +static int hitag2_init(void) { hitag2_reset(); return 0; } -static void hitag2_cipher_reset(struct hitag2_tag *tag, const byte_t *iv) -{ - uint64_t key = ((uint64_t)tag->sectors[2][2]) | +static void hitag2_cipher_reset(struct hitag2_tag *tag, const uint8_t *iv) { + uint64_t key = ((uint64_t)tag->sectors[2][2]) | ((uint64_t)tag->sectors[2][3] << 8) | ((uint64_t)tag->sectors[1][0] << 16) | ((uint64_t)tag->sectors[1][1] << 24) | ((uint64_t)tag->sectors[1][2] << 32) | ((uint64_t)tag->sectors[1][3] << 40); - uint32_t uid = ((uint32_t)tag->sectors[0][0]) | + uint32_t uid = ((uint32_t)tag->sectors[0][0]) | ((uint32_t)tag->sectors[0][1] << 8) | ((uint32_t)tag->sectors[0][2] << 16) | ((uint32_t)tag->sectors[0][3] << 24); @@ -193,12 +173,11 @@ static void hitag2_cipher_reset(struct hitag2_tag *tag, const byte_t *iv) (((uint32_t)(iv[1])) << 8) | (((uint32_t)(iv[2])) << 16) | (((uint32_t)(iv[3])) << 24); - tag->cs = _hitag2_init(rev64(key), rev32(uid), rev32(iv_)); + tag->cs = _hitag2_init(REV64(key), REV32(uid), REV32(iv_)); } -static int hitag2_cipher_authenticate(uint64_t* cs, const byte_t *authenticator_is) -{ - byte_t authenticator_should[4]; +static int hitag2_cipher_authenticate(uint64_t *cs, const uint8_t *authenticator_is) { + uint8_t authenticator_should[4]; authenticator_should[0] = ~_hitag2_byte(cs); authenticator_should[1] = ~_hitag2_byte(cs); authenticator_should[2] = ~_hitag2_byte(cs); @@ -206,11 +185,10 @@ static int hitag2_cipher_authenticate(uint64_t* cs, const byte_t *authenticator_ return (memcmp(authenticator_should, authenticator_is, 4) == 0); } -static int hitag2_cipher_transcrypt(uint64_t* cs, byte_t *data, unsigned int bytes, unsigned int bits) -{ +static int hitag2_cipher_transcrypt(uint64_t *cs, uint8_t *data, unsigned int bytes, unsigned int bits) { int i; - for(i=0; i 36 */ -#define HITAG_T_LOW 8 /* T_LOW should be 4..10 */ -#define HITAG_T_0_MIN 15 /* T[0] should be 18..22 */ -#define HITAG_T_1_MIN 25 /* T[1] should be 26..30 */ -//#define HITAG_T_EOF 40 /* T_EOF should be > 36 */ -#define HITAG_T_EOF 80 /* T_EOF should be > 36 */ -#define HITAG_T_WAIT_1 200 /* T_wresp should be 199..206 */ -#define HITAG_T_WAIT_2 90 /* T_wresp should be 199..206 */ +#define HITAG_FRAME_LEN 20 +#define HITAG_T_STOP 36 /* T_EOF should be > 36 */ +#define HITAG_T_LOW 8 /* T_LOW should be 4..10 */ +#define HITAG_T_0_MIN 15 /* T[0] should be 18..22 */ +#define HITAG_T_1_MIN 25 /* T[1] should be 26..30 */ +//#define HITAG_T_EOF 40 /* T_EOF should be > 36 */ +#define HITAG_T_EOF 80 /* T_EOF should be > 36 */ +#define HITAG_T_WAIT_1 200 /* T_wresp should be 199..206 */ +#define HITAG_T_WAIT_2 90 /* T_wresp should be 199..206 */ #define HITAG_T_WAIT_MAX 300 /* bit more than HITAG_T_WAIT_1 + HITAG_T_WAIT_2 */ -#define HITAG_T_PROG 614 +#define HITAG_T_PROG 614 -#define HITAG_T_TAG_ONE_HALF_PERIOD 10 -#define HITAG_T_TAG_TWO_HALF_PERIOD 25 -#define HITAG_T_TAG_THREE_HALF_PERIOD 41 +#define HITAG_T_TAG_ONE_HALF_PERIOD 10 +#define HITAG_T_TAG_TWO_HALF_PERIOD 25 +#define HITAG_T_TAG_THREE_HALF_PERIOD 41 #define HITAG_T_TAG_FOUR_HALF_PERIOD 57 -#define HITAG_T_TAG_HALF_PERIOD 16 -#define HITAG_T_TAG_FULL_PERIOD 32 +#define HITAG_T_TAG_HALF_PERIOD 16 +#define HITAG_T_TAG_FULL_PERIOD 32 -#define HITAG_T_TAG_CAPTURE_ONE_HALF 13 -#define HITAG_T_TAG_CAPTURE_TWO_HALF 25 +#define HITAG_T_TAG_CAPTURE_ONE_HALF 13 +#define HITAG_T_TAG_CAPTURE_TWO_HALF 25 #define HITAG_T_TAG_CAPTURE_THREE_HALF 41 #define HITAG_T_TAG_CAPTURE_FOUR_HALF 57 - static void hitag_send_bit(int bit) { LED_A_ON(); // Reset clock for the next bit AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; // Fixed modulation, earlier proxmark version used inverted signal - if(bit == 0) { + if (bit == 0) { // Manchester: Unloaded, then loaded |__--| LOW(GPIO_SSC_DOUT); - while(AT91C_BASE_TC0->TC_CV < T0*HITAG_T_TAG_HALF_PERIOD); + while (AT91C_BASE_TC0->TC_CV < T0*HITAG_T_TAG_HALF_PERIOD); HIGH(GPIO_SSC_DOUT); - while(AT91C_BASE_TC0->TC_CV < T0*HITAG_T_TAG_FULL_PERIOD); + while (AT91C_BASE_TC0->TC_CV < T0*HITAG_T_TAG_FULL_PERIOD); } else { // Manchester: Loaded, then unloaded |--__| HIGH(GPIO_SSC_DOUT); - while(AT91C_BASE_TC0->TC_CV < T0*HITAG_T_TAG_HALF_PERIOD); + while (AT91C_BASE_TC0->TC_CV < T0*HITAG_T_TAG_HALF_PERIOD); LOW(GPIO_SSC_DOUT); - while(AT91C_BASE_TC0->TC_CV < T0*HITAG_T_TAG_FULL_PERIOD); + while (AT91C_BASE_TC0->TC_CV < T0*HITAG_T_TAG_FULL_PERIOD); } LED_A_OFF(); } -static void hitag_send_frame(const byte_t* frame, size_t frame_len) +static void hitag_send_frame(const uint8_t *frame, size_t frame_len) { // Send start of frame - for(size_t i=0; i<5; i++) { + for(size_t i = 0; i < 5; i++) { hitag_send_bit(1); } // Send the content of the frame - for(size_t i=0; i> (7-(i%8)))&1); + for (size_t i = 0; i < frame_len; i++) { + hitag_send_bit((frame[i/8] >> (7-(i%8))) & 0x01); } // Drop the modulation LOW(GPIO_SSC_DOUT); } - -static void hitag2_handle_reader_command(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) -{ - byte_t rx_air[HITAG_FRAME_LEN]; +static void hitag2_handle_reader_command(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen) { + uint8_t rx_air[HITAG_FRAME_LEN]; // Copy the (original) received frame how it is send over the air - memcpy(rx_air,rx,nbytes(rxlen)); + memcpy(rx_air, rx, nbytes(rxlen)); - if(tag.crypto_active) { - hitag2_cipher_transcrypt(&(tag.cs),rx,rxlen/8,rxlen%8); + if (tag.crypto_active) { + hitag2_cipher_transcrypt(&(tag.cs), rx, rxlen/8, rxlen%8); } // Reset the transmission frame length @@ -305,112 +277,112 @@ static void hitag2_handle_reader_command(byte_t* rx, const size_t rxlen, byte_t* // Try to find out which command was send by selecting on length (in bits) switch (rxlen) { // Received 11000 from the reader, request for UID, send UID - case 05: { - // Always send over the air in the clear plaintext mode - if(rx_air[0] != 0xC0) { - // Unknown frame ? - return; - } - *txlen = 32; - memcpy(tx,tag.sectors[0],4); - tag.crypto_active = 0; - } - break; - - // Read/Write command: ..xx x..y yy with yyy == ~xxx, xxx is sector number - case 10: { - unsigned int sector = (~( ((rx[0]<<2)&0x04) | ((rx[1]>>6)&0x03) ) & 0x07); - // Verify complement of sector index - if(sector != ((rx[0]>>3)&0x07)) { - //DbpString("Transmission error (read/write)"); - return; - } - - switch (rx[0] & 0xC6) { - // Read command: 11xx x00y - case 0xC0: - memcpy(tx,tag.sectors[sector],4); - *txlen = 32; - break; - - // Inverted Read command: 01xx x10y - case 0x44: - for (size_t i=0; i<4; i++) { - tx[i] = tag.sectors[sector][i] ^ 0xff; - } - *txlen = 32; - break; - - // Write command: 10xx x01y - case 0x82: - // Prepare write, acknowledge by repeating command - memcpy(tx,rx,nbytes(rxlen)); - *txlen = rxlen; - tag.active_sector = sector; - tag.state=TAG_STATE_WRITING; - break; - - // Unknown command - default: - Dbprintf("Unknown command: %02x %02x",rx[0],rx[1]); - return; - break; - } - } - break; - - // Writing data or Reader password - case 32: { - if(tag.state == TAG_STATE_WRITING) { - // These are the sector contents to be written. We don't have to do anything else. - memcpy(tag.sectors[tag.active_sector],rx,nbytes(rxlen)); - tag.state=TAG_STATE_RESET; - return; - } else { - // Received RWD password, respond with configuration and our password - if(memcmp(rx,tag.sectors[1],4) != 0) { - DbpString("Reader password is wrong"); + case 05: { + // Always send over the air in the clear plaintext mode + if (rx_air[0] != HITAG2_START_AUTH) { + // Unknown frame ? return; } *txlen = 32; - memcpy(tx,tag.sectors[3],4); + memcpy(tx, tag.sectors[0], 4); + tag.crypto_active = 0; + } + break; + + // Read/Write command: ..xx x..y yy with yyy == ~xxx, xxx is sector number + case 10: { + unsigned int sector = (~( ((rx[0]<<2) & 0x04) | ((rx[1]>>6) & 0x03) ) & 0x07); + // Verify complement of sector index + if (sector != ((rx[0]>>3) & 0x07)) { + //DbpString("Transmission error (read/write)"); + return; + } + + switch (rx[0] & 0xC6) { + // Read command: 11xx x00y + case HITAG2_READ_PAGE: + memcpy(tx, tag.sectors[sector], 4); + *txlen = 32; + break; + + // Inverted Read command: 01xx x10y + case HITAG2_READ_PAGE_INVERTED: + for (size_t i = 0; i < 4; i++) { + tx[i] = tag.sectors[sector][i] ^ 0xff; + } + *txlen = 32; + break; + + // Write command: 10xx x01y + case HITAG2_WRITE_PAGE: + // Prepare write, acknowledge by repeating command + memcpy(tx, rx, nbytes(rxlen)); + *txlen = rxlen; + tag.active_sector = sector; + tag.state = TAG_STATE_WRITING; + break; + + // Unknown command + default: + Dbprintf("Unknown command: %02x %02x", rx[0], rx[1]); + return; + break; + } + } + break; + + // Writing data or Reader password + case 32: { + if (tag.state == TAG_STATE_WRITING) { + // These are the sector contents to be written. We don't have to do anything else. + memcpy(tag.sectors[tag.active_sector], rx, nbytes(rxlen)); + tag.state = TAG_STATE_RESET; + return; + } else { + // Received RWD password, respond with configuration and our password + if (memcmp(rx, tag.sectors[1], 4) != 0) { + DbpString("Reader password is wrong"); + return; + } + *txlen = 32; + memcpy(tx, tag.sectors[3], 4); + } } - } break; // Received RWD authentication challenge and respnse - case 64: { - // Store the authentication attempt - if (auth_table_len < (AUTH_TABLE_LENGTH-8)) { - memcpy(auth_table+auth_table_len,rx,8); - auth_table_len += 8; + case 64: { + // Store the authentication attempt + if (auth_table_len < (AUTH_TABLE_LENGTH-8)) { + memcpy(auth_table+auth_table_len, rx, 8); + auth_table_len += 8; + } + + // Reset the cipher state + hitag2_cipher_reset(&tag, rx); + // Check if the authentication was correct + if (!hitag2_cipher_authenticate(&(tag.cs), rx+4)) { + // The reader failed to authenticate, do nothing + Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x Failed!", rx[0], rx[1], rx[2], rx[3], rx[4], rx[5], rx[6], rx[7]); + return; + } + // Succesful, but commented out reporting back to the Host, this may delay to much. + // Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x OK!",rx[0],rx[1],rx[2],rx[3],rx[4],rx[5],rx[6],rx[7]); + + // Activate encryption algorithm for all further communication + tag.crypto_active = 1; + + // Use the tag password as response + memcpy(tx, tag.sectors[3], 4); + *txlen = 32; } - - // Reset the cipher state - hitag2_cipher_reset(&tag,rx); - // Check if the authentication was correct - if(!hitag2_cipher_authenticate(&(tag.cs),rx+4)) { - // The reader failed to authenticate, do nothing - Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x Failed!",rx[0],rx[1],rx[2],rx[3],rx[4],rx[5],rx[6],rx[7]); - return; - } - // Succesful, but commented out reporting back to the Host, this may delay to much. - // Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x OK!",rx[0],rx[1],rx[2],rx[3],rx[4],rx[5],rx[6],rx[7]); - - // Activate encryption algorithm for all further communication - tag.crypto_active = 1; - - // Use the tag password as response - memcpy(tx,tag.sectors[3],4); - *txlen = 32; - } break; } -// LogTraceHitag(rx,rxlen,0,0,false); -// LogTraceHitag(tx,*txlen,0,0,true); + // LogTraceHitag(rx, rxlen, 0, 0, false); + // LogTraceHitag(tx, *txlen, 0, 0, true); - if(tag.crypto_active) { + if (tag.crypto_active) { hitag2_cipher_transcrypt(&(tag.cs), tx, *txlen/8, *txlen%8); } } @@ -426,389 +398,410 @@ static void hitag_reader_send_bit(int bit) { // Enable modulation, which means, drop the field HIGH(GPIO_SSC_DOUT); - // Wait for 4-10 times the carrier period - while(AT91C_BASE_TC0->TC_CV < T0*6); - // SpinDelayUs(8*8); + // t_low = 4...10 carrier periods + while (AT91C_BASE_TC0->TC_CV < T0*6); // Disable modulation, just activates the field again LOW(GPIO_SSC_DOUT); - if(bit == 0) { - // Zero bit: |_-| - while(AT91C_BASE_TC0->TC_CV < T0*22); - // SpinDelayUs(16*8); + if (bit == 0) { + // Zero bit: |_-|, T[0] = 18...22 carrier periods + while (AT91C_BASE_TC0->TC_CV < T0*22); } else { - // One bit: |_--| - while(AT91C_BASE_TC0->TC_CV < T0*28); - // SpinDelayUs(22*8); + // One bit: |_--|, T[1] = 26...32 carrier periods + while (AT91C_BASE_TC0->TC_CV < T0*28); } LED_A_OFF(); } -static void hitag_reader_send_frame(const byte_t* frame, size_t frame_len) +static void hitag_reader_send_frame(const uint8_t *frame, size_t frame_len) { // Send the content of the frame - for(size_t i=0; i> (7-(i%8)))&1); + for(size_t i = 0; i < frame_len; i++) { + hitag_reader_send_bit((frame[i/8] >> (7-(i%8))) & 0x01); } // Send EOF AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; // Enable modulation, which means, drop the field HIGH(GPIO_SSC_DOUT); - // Wait for 4-10 times the carrier period - while(AT91C_BASE_TC0->TC_CV < T0*6); + // t_low = 4...10 carrier periods + while (AT91C_BASE_TC0->TC_CV < T0*6); // Disable modulation, just activates the field again LOW(GPIO_SSC_DOUT); + // t_stop > 36 carrier periods + while (AT91C_BASE_TC0->TC_CV < T0*36); } size_t blocknr; -static bool hitag2_password(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { - // Reset the transmission frame length - *txlen = 0; +//----------------------------------------------------------------------------- +// Hitag2 operations +//----------------------------------------------------------------------------- - // Try to find out which command was send by selecting on length (in bits) - switch (rxlen) { - // No answer, try to resurrect - case 0: { - // Stop if there is no answer (after sending password) - if (bPwd) { - DbpString("Password failed!"); - return false; - } - *txlen = 5; - memcpy(tx,"\xc0",nbytes(*txlen)); - } break; - - // Received UID, tag password - case 32: { - if (!bPwd) { - *txlen = 32; - memcpy(tx,password,4); - bPwd = true; - memcpy(tag.sectors[blocknr],rx,4); - blocknr++; - } else { - - if(blocknr == 1){ - //store password in block1, the TAG answers with Block3, but we need the password in memory - memcpy(tag.sectors[blocknr],tx,4); - }else{ - memcpy(tag.sectors[blocknr],rx,4); - } - - blocknr++; - if (blocknr > 7) { - DbpString("Read succesful!"); - bSuccessful = true; +static bool hitag2_write_page(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen) { + switch (writestate) { + case WRITE_STATE_START: + tx[0] = HITAG2_WRITE_PAGE | (blocknr << 3) | ((blocknr^7) >> 2); + tx[1] = ((blocknr^7) << 6); + *txlen = 10; + writestate = WRITE_STATE_PAGENUM_WRITTEN; + break; + case WRITE_STATE_PAGENUM_WRITTEN: + // Check if page number was received correctly + if ((rxlen == 10) + && (rx[0] == (HITAG2_WRITE_PAGE | (blocknr << 3) | ((blocknr^7) >> 2))) + && (rx[1] == (((blocknr & 0x3) ^ 0x3) << 6))) { + *txlen = 32; + memset(tx, 0, HITAG_FRAME_LEN); + memcpy(tx, writedata, 4); + writestate = WRITE_STATE_PROG; + } else { + Dbprintf("hitag2_write_page: Page number was not received correctly: rxlen=%d rx=%02x%02x%02x%02x", + rxlen, rx[0], rx[1], rx[2], rx[3]); + bSuccessful = false; return false; } - *txlen = 10; - tx[0] = 0xc0 | (blocknr << 3) | ((blocknr^7) >> 2); - tx[1] = ((blocknr^7) << 6); - } - } break; - - // Unexpected response - default: { - Dbprintf("Uknown frame length: %d",rxlen); - return false; - } break; - } - return true; -} - -static bool hitag2_write_page(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) -{ - switch (writestate) { - case WRITE_STATE_START: - *txlen = 10; - tx[0] = 0x82 | (blocknr << 3) | ((blocknr^7) >> 2); - tx[1] = ((blocknr^7) << 6); - writestate = WRITE_STATE_PAGENUM_WRITTEN; - break; - case WRITE_STATE_PAGENUM_WRITTEN: - // Check if page number was received correctly - if ((rxlen == 10) && - (rx[0] == (0x82 | (blocknr << 3) | ((blocknr^7) >> 2))) && - (rx[1] == (((blocknr & 0x3) ^ 0x3) << 6))) { - *txlen = 32; - memset(tx, 0, HITAG_FRAME_LEN); - memcpy(tx, writedata, 4); - writestate = WRITE_STATE_PROG; - } else { - Dbprintf("hitag2_write_page: Page number was not received correctly: rxlen=%d rx=%02x%02x%02x%02x", - rxlen, rx[0], rx[1], rx[2], rx[3]); + break; + case WRITE_STATE_PROG: + if (rxlen == 0) { + bSuccessful = true; + } else { + bSuccessful = false; + Dbprintf("hitag2_write_page: unexpected rx data (%d) after page write", rxlen); + } + return false; + default: + DbpString("hitag2_write_page: Unknown state %d"); bSuccessful = false; return false; - } - break; - case WRITE_STATE_PROG: - if (rxlen == 0) { - bSuccessful = true; - } else { - bSuccessful = false; - Dbprintf("hitag2_write_page: unexpected rx data (%d) after page write", rxlen); - } - return false; - default: - DbpString("hitag2_write_page: Unknown state %d"); - bSuccessful = false; - return false; } return true; } -static bool hitag2_crypto(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen, bool write) { +static bool hitag2_password(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen, bool write) { // Reset the transmission frame length *txlen = 0; - if(bCrypto) { - hitag2_cipher_transcrypt(&cipher_state,rx,rxlen/8,rxlen%8); + if (bPwd && !bAuthenticating && write) { + if (!hitag2_write_page(rx, rxlen, tx, txlen)) { + return false; + } + } else { + // Try to find out which command was send by selecting on length (in bits) + switch (rxlen) { + // No answer, try to resurrect + case 0: { + // Stop if there is no answer (after sending password) + if (bPwd) { + DbpString("Password failed!"); + return false; + } + tx[0] = HITAG2_START_AUTH; + *txlen = 5; + } + break; + // Received UID, tag password + case 32: { + if (!bPwd) { + bPwd = true; + bAuthenticating = true; + memcpy(tx, password, 4); + *txlen = 32; + } else { + if (bAuthenticating) { + bAuthenticating = false; + if (write) { + if (!hitag2_write_page(rx, rxlen, tx, txlen)) { + return false; + } + break; + } + } else { + memcpy(tag.sectors[blocknr], rx, 4); + blocknr++; + } + + if (blocknr > 7) { + DbpString("Read successful!"); + bSuccessful = true; + return false; + } + tx[0] = HITAG2_READ_PAGE | (blocknr << 3) | ((blocknr^7) >> 2); + tx[1] = ((blocknr^7) << 6); + *txlen = 10; + } + } + break; + + // Unexpected response + default: { + Dbprintf("Unknown frame length: %d", rxlen); + return false; + } + break; + } + } + + return true; +} + +static bool hitag2_crypto(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen, bool write) { + // Reset the transmission frame length + *txlen = 0; + + if (bCrypto) { + hitag2_cipher_transcrypt(&cipher_state, rx, rxlen/8, rxlen%8); } if (bCrypto && !bAuthenticating && write) { if (!hitag2_write_page(rx, rxlen, tx, txlen)) { return false; } + } else { + + // Try to find out which command was send by selecting on length (in bits) + switch (rxlen) { + // No answer, try to resurrect + case 0: { + // Stop if there is no answer while we are in crypto mode (after sending NrAr) + if (bCrypto) { + // Failed during authentication + if (bAuthenticating) { + DbpString("Authentication failed!"); + return false; + } else { + // Failed reading a block, could be (read/write) locked, skip block and re-authenticate + if (blocknr == 1) { + // Write the low part of the key in memory + memcpy(tag.sectors[1], key+2, 4); + } else if (blocknr == 2) { + // Write the high part of the key in memory + tag.sectors[2][0] = 0x00; + tag.sectors[2][1] = 0x00; + tag.sectors[2][2] = key[0]; + tag.sectors[2][3] = key[1]; + } else { + // Just put zero's in the memory (of the unreadable block) + memset(tag.sectors[blocknr], 0x00, 4); + } + blocknr++; + bCrypto = false; + } + } else { + tx[0] = HITAG2_START_AUTH; + *txlen = 5; + } + break; + } + // Received UID, crypto tag answer + case 32: { + if (!bCrypto) { + uint64_t ui64key = key[0] | ((uint64_t)key[1]) << 8 | ((uint64_t)key[2]) << 16 | ((uint64_t)key[3]) << 24 | ((uint64_t)key[4]) << 32 | ((uint64_t)key[5]) << 40; + uint32_t ui32uid = rx[0] | ((uint32_t)rx[1]) << 8 | ((uint32_t)rx[2]) << 16 | ((uint32_t)rx[3]) << 24; + Dbprintf("hitag2_crypto: key=0x%x%x uid=0x%x", (uint32_t) ((REV64(ui64key)) >> 32), (uint32_t) ((REV64(ui64key)) & 0xffffffff), REV32(ui32uid)); + cipher_state = _hitag2_init(REV64(ui64key), REV32(ui32uid), 0); + memset(tx, 0x00, 4); + memset(tx+4, 0xff, 4); + hitag2_cipher_transcrypt(&cipher_state, tx+4, 4, 0); + *txlen = 64; + bCrypto = true; + bAuthenticating = true; + } else { + // Check if we received answer tag (at) + if (bAuthenticating) { + bAuthenticating = false; + if (write) { + if (!hitag2_write_page(rx, rxlen, tx, txlen)) { + return false; + } + break; + } + } + // stage 2+, got data block + else { + // Store the received block + memcpy(tag.sectors[blocknr], rx, 4); + blocknr++; + } + if (blocknr > 7) { + DbpString("Read successful!"); + bSuccessful = true; + return false; + } else { + tx[0] = HITAG2_READ_PAGE | (blocknr << 3) | ((blocknr ^ 7) >> 2); + tx[1] = ((blocknr ^ 7) << 6); + *txlen = 10; + } + } + } + break; + + // Unexpected response + default: { + Dbprintf("Unknown frame length: %d",rxlen); + return false; + } + break; + } } - else - { + + if (bCrypto) { + // We have to return now to avoid double encryption + if (!bAuthenticating) { + hitag2_cipher_transcrypt(&cipher_state, tx, *txlen/8, *txlen%8); + } + } + + return true; +} + +static bool hitag2_authenticate(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen) { + // Reset the transmission frame length + *txlen = 0; // Try to find out which command was send by selecting on length (in bits) switch (rxlen) { // No answer, try to resurrect - case 0: - { - // Stop if there is no answer while we are in crypto mode (after sending NrAr) - if (bCrypto) { - // Failed during authentication - if (bAuthenticating) { + case 0: { + // Stop if there is no answer while we are in crypto mode (after sending NrAr) + if (bCrypto) { DbpString("Authentication failed!"); return false; - } else { - // Failed reading a block, could be (read/write) locked, skip block and re-authenticate - if (blocknr == 1) { - // Write the low part of the key in memory - memcpy(tag.sectors[1],key+2,4); - } else if (blocknr == 2) { - // Write the high part of the key in memory - tag.sectors[2][0] = 0x00; - tag.sectors[2][1] = 0x00; - tag.sectors[2][2] = key[0]; - tag.sectors[2][3] = key[1]; - } else { - // Just put zero's in the memory (of the unreadable block) - memset(tag.sectors[blocknr],0x00,4); - } - blocknr++; - bCrypto = false; } - } else { + tx[0] = HITAG2_START_AUTH; *txlen = 5; - memcpy(tx,"\xc0",nbytes(*txlen)); } - break; + break; + + // Received UID, crypto tag answer + case 32: { + if (!bCrypto) { + memcpy(tx, NrAr, 8); + *txlen = 64; + bCrypto = true; + } else { + DbpString("Authentication successful!"); + // We are done... for now + return false; + } + } + break; + + // Unexpected response + default: { + Dbprintf("Unknown frame length: %d",rxlen); + return false; + } + break; } - // Received UID, crypto tag answer - case 32: { - if (!bCrypto) { - uint64_t ui64key = key[0] | ((uint64_t)key[1]) << 8 | ((uint64_t)key[2]) << 16 | ((uint64_t)key[3]) << 24 | ((uint64_t)key[4]) << 32 | ((uint64_t)key[5]) << 40; - uint32_t ui32uid = rx[0] | ((uint32_t)rx[1]) << 8 | ((uint32_t)rx[2]) << 16 | ((uint32_t)rx[3]) << 24; - Dbprintf("hitag2_crypto: key=0x%x%x uid=0x%x", (uint32_t) ((rev64(ui64key)) >> 32), (uint32_t) ((rev64(ui64key)) & 0xffffffff), rev32(ui32uid)); - cipher_state = _hitag2_init(rev64(ui64key), rev32(ui32uid), 0); - memset(tx,0x00,4); - memset(tx+4,0xff,4); - hitag2_cipher_transcrypt(&cipher_state, tx+4, 4, 0); - *txlen = 64; - bCrypto = true; - bAuthenticating = true; - } else { + + return true; +} + +static bool hitag2_test_auth_attempts(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen) { + + // Reset the transmission frame length + *txlen = 0; + + // Try to find out which command was send by selecting on length (in bits) + switch (rxlen) { + // No answer, try to resurrect + case 0: { + // Stop if there is no answer while we are in crypto mode (after sending NrAr) + if (bCrypto) { + Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x Failed, removed entry!", NrAr[0], NrAr[1], NrAr[2], NrAr[3], NrAr[4], NrAr[5], NrAr[6], NrAr[7]); + + // Removing failed entry from authentiations table + memcpy(auth_table+auth_table_pos, auth_table+auth_table_pos+8, 8); + auth_table_len -= 8; + + // Return if we reached the end of the authentications table + bCrypto = false; + if (auth_table_pos == auth_table_len) { + return false; + } + + // Copy the next authentication attempt in row (at the same position, b/c we removed last failed entry) + memcpy(NrAr, auth_table+auth_table_pos, 8); + } + tx[0] = HITAG2_START_AUTH; + *txlen = 5; + } + break; + + // Received UID, crypto tag answer, or read block response + case 32: { + if (!bCrypto) { + *txlen = 64; + memcpy(tx, NrAr, 8); + bCrypto = true; + } else { + Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x OK", NrAr[0], NrAr[1], NrAr[2], NrAr[3], NrAr[4], NrAr[5], NrAr[6], NrAr[7]); + bCrypto = false; + if ((auth_table_pos+8) == auth_table_len) { + return false; + } + auth_table_pos += 8; + memcpy(NrAr, auth_table+auth_table_pos, 8); + } + } + break; + + default: { + Dbprintf("Unknown frame length: %d",rxlen); + return false; + } + break; + } + + return true; +} + +static bool hitag2_read_uid(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen) { + // Reset the transmission frame length + *txlen = 0; + + // Try to find out which command was send by selecting on length (in bits) + switch (rxlen) { + // No answer, try to resurrect + case 0: { + // Just starting or if there is no answer + tx[0] = HITAG2_START_AUTH; + *txlen = 5; + } + break; + // Received UID + case 32: { // Check if we received answer tag (at) if (bAuthenticating) { bAuthenticating = false; - if (write) { - if (!hitag2_write_page(rx, rxlen, tx, txlen)) { - return false; - } - break; - } } else { // Store the received block - memcpy(tag.sectors[blocknr],rx,4); + memcpy(tag.sectors[blocknr], rx, 4); blocknr++; } - - if (blocknr > 7) { - DbpString("Read succesful!"); + if (blocknr > 0) { + //DbpString("Read successful!"); bSuccessful = true; return false; - } else { - *txlen = 10; - tx[0] = 0xc0 | (blocknr << 3) | ((blocknr^7) >> 2); - tx[1] = ((blocknr^7) << 6); } } - } break; - + break; // Unexpected response - default: { - Dbprintf("Uknown frame length: %d",rxlen); - return false; - } break; - } - } - - if(bCrypto) { - // We have to return now to avoid double encryption - if (!bAuthenticating) { - hitag2_cipher_transcrypt(&cipher_state,tx,*txlen/8,*txlen%8); - } - } - - return true; -} - - -static bool hitag2_authenticate(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { - // Reset the transmission frame length - *txlen = 0; - - // Try to find out which command was send by selecting on length (in bits) - switch (rxlen) { - // No answer, try to resurrect - case 0: { - // Stop if there is no answer while we are in crypto mode (after sending NrAr) - if (bCrypto) { - DbpString("Authentication failed!"); + default: { + Dbprintf("Unknown frame length: %d",rxlen); return false; } - *txlen = 5; - memcpy(tx,"\xc0",nbytes(*txlen)); - } break; - - // Received UID, crypto tag answer - case 32: { - if (!bCrypto) { - *txlen = 64; - memcpy(tx,NrAr,8); - bCrypto = true; - } else { - DbpString("Authentication succesful!"); - // We are done... for now - return false; - } - } break; - - // Unexpected response - default: { - Dbprintf("Uknown frame length: %d",rxlen); - return false; - } break; - } - - return true; -} - - -static bool hitag2_test_auth_attempts(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { - - // Reset the transmission frame length - *txlen = 0; - - // Try to find out which command was send by selecting on length (in bits) - switch (rxlen) { - // No answer, try to resurrect - case 0: { - // Stop if there is no answer while we are in crypto mode (after sending NrAr) - if (bCrypto) { - Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x Failed, removed entry!",NrAr[0],NrAr[1],NrAr[2],NrAr[3],NrAr[4],NrAr[5],NrAr[6],NrAr[7]); - - // Removing failed entry from authentiations table - memcpy(auth_table+auth_table_pos,auth_table+auth_table_pos+8,8); - auth_table_len -= 8; - - // Return if we reached the end of the authentications table - bCrypto = false; - if (auth_table_pos == auth_table_len) { - return false; - } - - // Copy the next authentication attempt in row (at the same position, b/c we removed last failed entry) - memcpy(NrAr,auth_table+auth_table_pos,8); - } - *txlen = 5; - memcpy(tx,"\xc0",nbytes(*txlen)); - } break; - - // Received UID, crypto tag answer, or read block response - case 32: { - if (!bCrypto) { - *txlen = 64; - memcpy(tx,NrAr,8); - bCrypto = true; - } else { - Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x OK",NrAr[0],NrAr[1],NrAr[2],NrAr[3],NrAr[4],NrAr[5],NrAr[6],NrAr[7]); - bCrypto = false; - if ((auth_table_pos+8) == auth_table_len) { - return false; - } - auth_table_pos += 8; - memcpy(NrAr,auth_table+auth_table_pos,8); - } - } break; - - default: { - Dbprintf("Uknown frame length: %d",rxlen); - return false; - } break; - } - - return true; -} - -static bool hitag2_read_uid(byte_t* rx, const size_t rxlen, byte_t* tx, size_t* txlen) { - // Reset the transmission frame length - *txlen = 0; - - // Try to find out which command was send by selecting on length (in bits) - switch (rxlen) { - // No answer, try to resurrect - case 0: { - // Just starting or if there is no answer - *txlen = 5; - memcpy(tx,"\xc0",nbytes(*txlen)); - } break; - // Received UID - case 32: { - // Check if we received answer tag (at) - if (bAuthenticating) { - bAuthenticating = false; - } else { - // Store the received block - memcpy(tag.sectors[blocknr],rx,4); - blocknr++; - } - if (blocknr > 0) { - //DbpString("Read successful!"); - bSuccessful = true; - return false; - } - } break; - // Unexpected response - default: { - Dbprintf("Uknown frame length: %d",rxlen); - return false; - } break; + break; } return true; } void SnoopHitag(uint32_t type) { - int frame_count; + // int frame_count; int response; int overflow; bool rising_edge; @@ -816,8 +809,8 @@ void SnoopHitag(uint32_t type) { int lastbit; bool bSkip; int tag_sof; - byte_t rx[HITAG_FRAME_LEN] = {0}; - size_t rxlen=0; + uint8_t rx[HITAG_FRAME_LEN] = {0}; + size_t rxlen = 0; FpgaDownloadAndGo(FPGA_BITSTREAM_LF); @@ -829,7 +822,7 @@ void SnoopHitag(uint32_t type) { auth_table_pos = 0; BigBuf_free(); - auth_table = (byte_t *)BigBuf_malloc(AUTH_TABLE_LENGTH); + auth_table = (uint8_t *)BigBuf_malloc(AUTH_TABLE_LENGTH); memset(auth_table, 0x00, AUTH_TABLE_LENGTH); DbpString("Starting Hitag2 snoop"); @@ -840,7 +833,6 @@ void SnoopHitag(uint32_t type) { FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_TOGGLE_MODE); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - RELAY_OFF(); // Configure output pin that is connected to the FPGA (for modulating) AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; @@ -858,14 +850,13 @@ void SnoopHitag(uint32_t type) { // TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, // external trigger rising edge, load RA on rising edge of TIOA. - uint32_t t1_channel_mode = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_BOTH | AT91C_TC_ABETRG | AT91C_TC_LDRA_BOTH; - AT91C_BASE_TC1->TC_CMR = t1_channel_mode; + AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_BOTH | AT91C_TC_ABETRG | AT91C_TC_LDRA_BOTH; // Enable and reset counter AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // Reset the received frame, frame count and timing info - frame_count = 0; + // frame_count = 0; response = 0; overflow = 0; reader_frame = false; @@ -873,14 +864,14 @@ void SnoopHitag(uint32_t type) { bSkip = true; tag_sof = 4; - while(!BUTTON_PRESS()) { + while (!BUTTON_PRESS()) { // Watchdog hit WDT_HIT(); // Receive frame, watch for at most T0*EOF periods while (AT91C_BASE_TC1->TC_CV < T0*HITAG_T_EOF) { // Check if rising edge in modulation is detected - if(AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { + if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { // Retrieve the new timing values int ra = (AT91C_BASE_TC1->TC_RA/T0); @@ -892,7 +883,7 @@ void SnoopHitag(uint32_t type) { // Switch from tag to reader capture LED_C_OFF(); reader_frame = true; - memset(rx,0x00,sizeof(rx)); + memset(rx, 0x00, sizeof(rx)); rxlen = 0; } @@ -909,17 +900,17 @@ void SnoopHitag(uint32_t type) { if (reader_frame) { LED_B_ON(); // Capture reader frame - if(ra >= HITAG_T_STOP) { + if (ra >= HITAG_T_STOP) { if (rxlen != 0) { //DbpString("wierd0?"); } // Capture the T0 periods that have passed since last communication or field drop (reset) response = (ra - HITAG_T_LOW); - } else if(ra >= HITAG_T_1_MIN ) { + } else if (ra >= HITAG_T_1_MIN) { // '1' bit rx[rxlen / 8] |= 1 << (7-(rxlen%8)); rxlen++; - } else if(ra >= HITAG_T_0_MIN) { + } else if (ra >= HITAG_T_0_MIN) { // '0' bit rx[rxlen / 8] |= 0 << (7-(rxlen%8)); rxlen++; @@ -929,20 +920,20 @@ void SnoopHitag(uint32_t type) { } else { LED_C_ON(); // Capture tag frame (manchester decoding using only falling edges) - if(ra >= HITAG_T_EOF) { + if (ra >= HITAG_T_EOF) { if (rxlen != 0) { //DbpString("wierd1?"); } // Capture the T0 periods that have passed since last communication or field drop (reset) // We always recieve a 'one' first, which has the falling edge after a half period |-_| - response = ra-HITAG_T_TAG_HALF_PERIOD; - } else if(ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { + response = ra - HITAG_T_TAG_HALF_PERIOD; + } else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { // Manchester coding example |-_|_-|-_| (101) rx[rxlen / 8] |= 0 << (7-(rxlen%8)); rxlen++; rx[rxlen / 8] |= 1 << (7-(rxlen%8)); rxlen++; - } else if(ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { + } else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { // Manchester coding example |_-|...|_-|-_| (0...01) rx[rxlen / 8] |= 0 << (7-(rxlen%8)); rxlen++; @@ -953,7 +944,7 @@ void SnoopHitag(uint32_t type) { } lastbit = !lastbit; bSkip = !bSkip; - } else if(ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { + } else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { // Manchester coding example |_-|_-| (00) or |-_|-_| (11) if (tag_sof) { // Ignore bits that are transmitted during SOF @@ -971,9 +962,9 @@ void SnoopHitag(uint32_t type) { } // Check if frame was captured - if(rxlen > 0) { - frame_count++; - if (!LogTraceHitag(rx,rxlen,response,0,reader_frame)) { + if (rxlen > 0) { + // frame_count++; + if (!LogTraceHitag(rx, rxlen, response, 0, reader_frame)) { DbpString("Trace full"); break; } @@ -988,7 +979,7 @@ void SnoopHitag(uint32_t type) { } // Reset the received frame and response timing info - memset(rx,0x00,sizeof(rx)); + memset(rx, 0x00, sizeof(rx)); response = 0; reader_frame = false; lastbit = 1; @@ -1021,14 +1012,14 @@ void SnoopHitag(uint32_t type) { // DbpString("All done"); } -void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { - int frame_count; +void SimulateHitagTag(bool tag_mem_supplied, uint8_t *data) { + // int frame_count; int response; int overflow; - byte_t rx[HITAG_FRAME_LEN]; - size_t rxlen=0; - byte_t tx[HITAG_FRAME_LEN]; - size_t txlen=0; + uint8_t rx[HITAG_FRAME_LEN]; + size_t rxlen = 0; + uint8_t tx[HITAG_FRAME_LEN]; + size_t txlen = 0; bool bQuitTraceFull = false; bQuiet = false; @@ -1040,9 +1031,9 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { auth_table_len = 0; auth_table_pos = 0; - byte_t* auth_table; + uint8_t *auth_table; BigBuf_free(); - auth_table = (byte_t *)BigBuf_malloc(AUTH_TABLE_LENGTH); + auth_table = BigBuf_malloc(AUTH_TABLE_LENGTH); memset(auth_table, 0x00, AUTH_TABLE_LENGTH); DbpString("Starting Hitag2 simulation"); @@ -1051,16 +1042,16 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { if (tag_mem_supplied) { DbpString("Loading hitag2 memory..."); - memcpy((byte_t*)tag.sectors,data,48); + memcpy((uint8_t*)tag.sectors, data, 48); } uint32_t block = 0; - for (size_t i=0; i<12; i++) { - for (size_t j=0; j<4; j++) { + for (size_t i = 0; i < 12; i++) { + for (size_t j = 0; j < 4; j++) { block <<= 8; block |= tag.sectors[i][j]; } - Dbprintf("| %d | %08x |",i,block); + Dbprintf("| %d | %08x |", i, block); } // Set up simulator mode, frequency divisor which will drive the FPGA @@ -1068,7 +1059,6 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - RELAY_OFF(); // Configure output pin that is connected to the FPGA (for modulating) AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; @@ -1096,22 +1086,22 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_RISING | AT91C_TC_ABETRG | AT91C_TC_LDRA_RISING; // Reset the received frame, frame count and timing info - memset(rx,0x00,sizeof(rx)); - frame_count = 0; + memset(rx, 0x00, sizeof(rx)); + // frame_count = 0; response = 0; overflow = 0; // Enable and reset counter AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - while(!BUTTON_PRESS()) { + while (!BUTTON_PRESS()) { // Watchdog hit WDT_HIT(); // Receive frame, watch for at most T0*EOF periods while (AT91C_BASE_TC1->TC_CV < T0*HITAG_T_EOF) { // Check if rising edge in modulation is detected - if(AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { + if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { // Retrieve the new timing values int ra = (AT91C_BASE_TC1->TC_RA/T0) + overflow; overflow = 0; @@ -1122,17 +1112,17 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { LED_B_ON(); // Capture reader frame - if(ra >= HITAG_T_STOP) { + if (ra >= HITAG_T_STOP) { if (rxlen != 0) { //DbpString("wierd0?"); } // Capture the T0 periods that have passed since last communication or field drop (reset) response = (ra - HITAG_T_LOW); - } else if(ra >= HITAG_T_1_MIN ) { + } else if (ra >= HITAG_T_1_MIN) { // '1' bit rx[rxlen / 8] |= 1 << (7-(rxlen%8)); rxlen++; - } else if(ra >= HITAG_T_0_MIN) { + } else if (ra >= HITAG_T_0_MIN) { // '0' bit rx[rxlen / 8] |= 0 << (7-(rxlen%8)); rxlen++; @@ -1143,10 +1133,10 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { } // Check if frame was captured - if(rxlen > 4) { - frame_count++; + if (rxlen > 4) { + // frame_count++; if (!bQuiet) { - if (!LogTraceHitag(rx,rxlen,response,0,true)) { + if (!LogTraceHitag(rx, rxlen, response, 0, true)) { DbpString("Trace full"); if (bQuitTraceFull) { break; @@ -1160,22 +1150,22 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // Process the incoming frame (rx) and prepare the outgoing frame (tx) - hitag2_handle_reader_command(rx,rxlen,tx,&txlen); + hitag2_handle_reader_command(rx, rxlen, tx, &txlen); // Wait for HITAG_T_WAIT_1 carrier periods after the last reader bit, // not that since the clock counts since the rising edge, but T_Wait1 is // with respect to the falling edge, we need to wait actually (T_Wait1 - T_Low) // periods. The gap time T_Low varies (4..10). All timer values are in // terms of T0 units - while(AT91C_BASE_TC0->TC_CV < T0*(HITAG_T_WAIT_1-HITAG_T_LOW)); + while (AT91C_BASE_TC0->TC_CV < T0*(HITAG_T_WAIT_1-HITAG_T_LOW)); // Send and store the tag answer (if there is any) if (txlen) { // Transmit the tag frame - hitag_send_frame(tx,txlen); + hitag_send_frame(tx, txlen); // Store the frame in the trace if (!bQuiet) { - if (!LogTraceHitag(tx,txlen,0,0,false)) { + if (!LogTraceHitag(tx, txlen, 0, 0, false)) { DbpString("Trace full"); if (bQuitTraceFull) { break; @@ -1187,7 +1177,7 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { } // Reset the received frame and response timing info - memset(rx,0x00,sizeof(rx)); + memset(rx, 0x00, sizeof(rx)); response = 0; // Enable and reset external trigger in timer for capturing future frames @@ -1211,14 +1201,14 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) { } -void ReaderHitag(hitag_function htf, hitag_data* htd) { - int frame_count; +void ReaderHitag(hitag_function htf, hitag_data *htd) { + // int frame_count; int response; - byte_t rx[HITAG_FRAME_LEN]; - size_t rxlen=0; - byte_t txbuf[HITAG_FRAME_LEN]; - byte_t* tx = txbuf; - size_t txlen=0; + uint8_t rx[HITAG_FRAME_LEN]; + size_t rxlen = 0; + uint8_t txbuf[HITAG_FRAME_LEN]; + uint8_t *tx = txbuf; + size_t txlen = 0; int lastbit; bool bSkip; int reset_sof; @@ -1238,54 +1228,61 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { //DbpString("Starting Hitag reader family"); // Check configuration - switch(htf) { - case RHT2F_PASSWORD: { - Dbprintf("List identifier in password mode"); - memcpy(password,htd->pwd.password,4); - blocknr = 0; - bQuitTraceFull = false; - bQuiet = false; - bPwd = false; - } break; - case RHT2F_AUTHENTICATE: { - DbpString("Authenticating using nr,ar pair:"); - memcpy(NrAr,htd->auth.NrAr,8); - Dbhexdump(8,NrAr,false); - bQuiet = false; - bCrypto = false; - bAuthenticating = false; - bQuitTraceFull = true; - } break; - case RHT2F_CRYPTO: - { - DbpString("Authenticating using key:"); - memcpy(key,htd->crypto.key,6); //HACK; 4 or 6?? I read both in the code. - Dbhexdump(6,key,false); - blocknr = 0; - bQuiet = false; - bCrypto = false; - bAuthenticating = false; - bQuitTraceFull = true; - } break; - case RHT2F_TEST_AUTH_ATTEMPTS: { - Dbprintf("Testing %d authentication attempts",(auth_table_len/8)); - auth_table_pos = 0; - memcpy(NrAr, auth_table, 8); - bQuitTraceFull = false; - bQuiet = false; - bCrypto = false; - } break; - case RHT2F_UID_ONLY: { - blocknr = 0; - bQuiet = false; - bCrypto = false; - bAuthenticating = false; - bQuitTraceFull = true; - } break; - default: { - Dbprintf("Error, unknown function: %d",htf); - return; - } break; + switch (htf) { + case RHT2F_PASSWORD: { + Dbprintf("List identifier in password mode"); + memcpy(password, htd->pwd.password, 4); + blocknr = 0; + bQuitTraceFull = false; + bQuiet = false; + bPwd = false; + bAuthenticating = false; + } + break; + case RHT2F_AUTHENTICATE: { + DbpString("Authenticating using nr,ar pair:"); + memcpy(NrAr, htd->auth.NrAr, 8); + Dbhexdump(8, NrAr, false); + bQuiet = false; + bCrypto = false; + bAuthenticating = false; + bQuitTraceFull = true; + } + break; + case RHT2F_CRYPTO: + { + DbpString("Authenticating using key:"); + memcpy(key, htd->crypto.key, 6); //HACK; 4 or 6?? I read both in the code. + Dbhexdump(6, key, false); + blocknr = 0; + bQuiet = false; + bCrypto = false; + bAuthenticating = false; + bQuitTraceFull = true; + } + break; + case RHT2F_TEST_AUTH_ATTEMPTS: { + Dbprintf("Testing %d authentication attempts", (auth_table_len/8)); + auth_table_pos = 0; + memcpy(NrAr, auth_table, 8); + bQuitTraceFull = false; + bQuiet = false; + bCrypto = false; + } + break; + case RHT2F_UID_ONLY: { + blocknr = 0; + bQuiet = false; + bCrypto = false; + bAuthenticating = false; + bQuitTraceFull = true; + } + break; + default: { + Dbprintf("Error, unknown function: %d", htf); + return; + } + break; } LED_D_ON(); @@ -1301,14 +1298,10 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { // Set Frequency divisor which will drive the FPGA and analog mux selection FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - RELAY_OFF(); // Disable modulation at default, which means enable the field LOW(GPIO_SSC_DOUT); - // Give it a bit of time for the resonant antenna to settle. - SpinDelay(30); - // Enable Peripheral Clock for TIMER_CLOCK0, used to measure exact timing before answering AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0); @@ -1332,12 +1325,12 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // Reset the received frame, frame count and timing info - frame_count = 0; + // frame_count = 0; response = 0; lastbit = 1; // Tag specific configuration settings (sof, timings, etc.) - if (htf < 10){ + if (htf < 10) { // hitagS settings reset_sof = 1; t_wait = 200; @@ -1353,19 +1346,23 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { t_wait = HITAG_T_WAIT_2; //DbpString("Configured for hitag2 reader"); } else { - Dbprintf("Error, unknown hitag reader type: %d",htf); - return; + Dbprintf("Error, unknown hitag reader type: %d", htf); + goto out; } - uint8_t attempt_count=0; - while(!bStop && !BUTTON_PRESS()) { - // Watchdog hit + + // wait for tag to power up + // t_PowerUp = 312,5 carrier periods + while (AT91C_BASE_TC0->TC_CV < T0*(312-t_wait)); + + uint8_t attempt_count = 0; + while (!bStop && !BUTTON_PRESS()) { WDT_HIT(); // Check if frame was captured and store it - if(rxlen > 0) { - frame_count++; + if (rxlen > 0) { + // frame_count++; if (!bQuiet) { - if (!LogTraceHitag(rx,rxlen,response,0,false)) { + if (!LogTraceHitag(rx, rxlen, response, 0, false)) { DbpString("Trace full"); if (bQuitTraceFull) { break; @@ -1378,28 +1375,34 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { // By default reset the transmission buffer tx = txbuf; - switch(htf) { + switch (htf) { case RHT2F_PASSWORD: { - bStop = !hitag2_password(rx,rxlen,tx,&txlen); - } break; + bStop = !hitag2_password(rx, rxlen, tx, &txlen, false); + } + break; case RHT2F_AUTHENTICATE: { - bStop = !hitag2_authenticate(rx,rxlen,tx,&txlen); - } break; + bStop = !hitag2_authenticate(rx, rxlen, tx, &txlen); + } + break; case RHT2F_CRYPTO: { - bStop = !hitag2_crypto(rx,rxlen,tx,&txlen, false); - } break; + bStop = !hitag2_crypto(rx, rxlen, tx, &txlen, false); + } + break; case RHT2F_TEST_AUTH_ATTEMPTS: { - bStop = !hitag2_test_auth_attempts(rx,rxlen,tx,&txlen); - } break; + bStop = !hitag2_test_auth_attempts(rx, rxlen, tx, &txlen); + } + break; case RHT2F_UID_ONLY: { bStop = !hitag2_read_uid(rx, rxlen, tx, &txlen); attempt_count++; //attempt 3 times to get uid then quit - if (!bStop && attempt_count == 3) bStop = true; - } break; + if (!bStop && attempt_count == 3) + bStop = true; + } + break; default: { - Dbprintf("Error, unknown function: %d",htf); - return; - } break; + Dbprintf("Error, unknown function: %d", htf); + goto out; + } } // Send and store the reader command @@ -1411,22 +1414,22 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { // falling edge occured halfway the period. with respect to this falling edge, // we need to wait (T_Wait2 + half_tag_period) when the last was a 'one'. // All timer values are in terms of T0 units - while(AT91C_BASE_TC0->TC_CV < T0*(t_wait+(HITAG_T_TAG_HALF_PERIOD*lastbit))); + while (AT91C_BASE_TC0->TC_CV < T0*(t_wait+(HITAG_T_TAG_HALF_PERIOD*lastbit))); //Dbprintf("DEBUG: Sending reader frame"); // Transmit the reader frame - hitag_reader_send_frame(tx,txlen); + hitag_reader_send_frame(tx, txlen); // Enable and reset external trigger in timer for capturing future frames AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // Add transmitted frame to total count - if(txlen > 0) { - frame_count++; + if (txlen > 0) { + // frame_count++; if (!bQuiet) { // Store the frame in the trace - if (!LogTraceHitag(tx,txlen,HITAG_T_WAIT_2,0,true)) { + if (!LogTraceHitag(tx, txlen, HITAG_T_WAIT_2, 0, true)) { if (bQuitTraceFull) { break; } else { @@ -1437,7 +1440,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { } // Reset values for receiving frames - memset(rx,0x00,sizeof(rx)); + memset(rx, 0x00, sizeof(rx)); rxlen = 0; lastbit = 1; bSkip = true; @@ -1449,7 +1452,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { // Receive frame, watch for at most T0*EOF periods while (AT91C_BASE_TC1->TC_CV < T0*HITAG_T_WAIT_MAX) { // Check if falling edge in tag modulation is detected - if(AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { + if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { // Retrieve the new timing values int ra = (AT91C_BASE_TC1->TC_RA/T0); @@ -1459,14 +1462,14 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { LED_B_ON(); // Capture tag frame (manchester decoding using only falling edges) - if(ra >= HITAG_T_EOF) { + if (ra >= HITAG_T_EOF) { if (rxlen != 0) { //Dbprintf("DEBUG: Wierd1"); } // Capture the T0 periods that have passed since last communication or field drop (reset) // We always recieve a 'one' first, which has the falling edge after a half period |-_| - response = ra-HITAG_T_TAG_HALF_PERIOD; - } else if(ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { + response = ra - HITAG_T_TAG_HALF_PERIOD; + } else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { // Manchester coding example |-_|_-|-_| (101) //need to test to verify we don't exceed memory... @@ -1477,7 +1480,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { rxlen++; rx[rxlen / 8] |= 1 << (7-(rxlen%8)); rxlen++; - } else if(ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { + } else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { // Manchester coding example |_-|...|_-|-_| (0...01) //need to test to verify we don't exceed memory... @@ -1493,7 +1496,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { } lastbit = !lastbit; bSkip = !bSkip; - } else if(ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { + } else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { // Manchester coding example |_-|_-| (00) or |-_|-_| (11) //need to test to verify we don't exceed memory... @@ -1515,13 +1518,15 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { } } //if we saw over 100 wierd values break it probably isn't hitag... - if (errorCount >100) break; + if (errorCount > 100) break; // We can break this loop if we received the last bit from a frame if (AT91C_BASE_TC1->TC_CV > T0*HITAG_T_EOF) { - if (rxlen>0) break; + if (rxlen > 0) break; } } } + +out: //Dbprintf("DEBUG: Done waiting for frame"); LED_B_OFF(); @@ -1532,20 +1537,19 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) { //Dbprintf("frame received: %d",frame_count); //DbpString("All done"); if (bSuccessful) - cmd_send(CMD_ACK,bSuccessful,0,0,(byte_t*)tag.sectors,48); + cmd_send(CMD_ACK, bSuccessful, 0, 0, (uint8_t*)tag.sectors, 48); else - cmd_send(CMD_ACK,bSuccessful,0,0,0,0); - + cmd_send(CMD_ACK, bSuccessful, 0, 0, 0, 0); } -void WriterHitag(hitag_function htf, hitag_data* htd, int page) { - int frame_count; +void WriterHitag(hitag_function htf, hitag_data *htd, int page) { + // int frame_count; int response; - byte_t rx[HITAG_FRAME_LEN]; - size_t rxlen=0; - byte_t txbuf[HITAG_FRAME_LEN]; - byte_t* tx = txbuf; - size_t txlen=0; + uint8_t rx[HITAG_FRAME_LEN]; + size_t rxlen = 0; + uint8_t txbuf[HITAG_FRAME_LEN]; + uint8_t *tx = txbuf; + size_t txlen = 0; int lastbit; bool bSkip; int reset_sof; @@ -1565,24 +1569,36 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { //DbpString("Starting Hitag reader family"); // Check configuration - switch(htf) { - case WHT2F_CRYPTO: - { - DbpString("Authenticating using key:"); - memcpy(key,htd->crypto.key,6); //HACK; 4 or 6?? I read both in the code. - memcpy(writedata, htd->crypto.data, 4); - Dbhexdump(6,key,false); - blocknr = page; - bQuiet = false; - bCrypto = false; - bAuthenticating = false; - bQuitTraceFull = true; - writestate = WRITE_STATE_START; - } break; - default: { - Dbprintf("Error, unknown function: %d",htf); - return; - } break; + switch (htf) { + case WHT2F_CRYPTO: { + DbpString("Authenticating using key:"); + memcpy(key, htd->crypto.key, 6); //HACK; 4 or 6?? I read both in the code. + memcpy(writedata, htd->crypto.data, 4); + Dbhexdump(6, key, false); + blocknr = page; + bQuiet = false; + bCrypto = false; + bAuthenticating = false; + bQuitTraceFull = true; + writestate = WRITE_STATE_START; + } + break; + case WHT2F_PASSWORD: { + DbpString("Authenticating using password:"); + memcpy(password, htd->pwd.password, 4); + memcpy(writedata, htd->crypto.data, 4); + Dbhexdump(4, password, false); + blocknr = page; + bPwd = false; + bAuthenticating = false; + writestate = WRITE_STATE_START; + } + break; + default: { + Dbprintf("Error, unknown function: %d", htf); + return; + } + break; } LED_D_ON(); @@ -1598,7 +1614,6 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { // Set Frequency divisor which will drive the FPGA and analog mux selection FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - RELAY_OFF(); // Disable modulation at default, which means enable the field LOW(GPIO_SSC_DOUT); @@ -1629,13 +1644,13 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // Reset the received frame, frame count and timing info - frame_count = 0; + // frame_count = 0; response = 0; lastbit = 1; bStop = false; // Tag specific configuration settings (sof, timings, etc.) - if (htf < 10){ + if (htf < 10) { // hitagS settings reset_sof = 1; t_wait = 200; @@ -1651,18 +1666,18 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { t_wait = HITAG_T_WAIT_2; //DbpString("Configured for hitag2 reader"); } else { - Dbprintf("Error, unknown hitag reader type: %d",htf); + Dbprintf("Error, unknown hitag reader type: %d", htf); return; } - while(!bStop && !BUTTON_PRESS()) { - // Watchdog hit + while (!bStop && !BUTTON_PRESS()) { + WDT_HIT(); // Check if frame was captured and store it - if(rxlen > 0) { - frame_count++; + if (rxlen > 0) { + // frame_count++; if (!bQuiet) { - if (!LogTraceHitag(rx,rxlen,response,0,false)) { + if (!LogTraceHitag(rx, rxlen, response, 0, false)) { DbpString("Trace full"); if (bQuitTraceFull) { break; @@ -1675,14 +1690,20 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { // By default reset the transmission buffer tx = txbuf; - switch(htf) { - case WHT2F_CRYPTO: { - bStop = !hitag2_crypto(rx,rxlen,tx,&txlen, true); - } break; - default: { - Dbprintf("Error, unknown function: %d",htf); - return; - } break; + switch (htf) { + case WHT2F_CRYPTO: { + bStop = !hitag2_crypto(rx, rxlen, tx, &txlen, true); + } + break; + case WHT2F_PASSWORD: { + bStop = !hitag2_password(rx, rxlen, tx, &txlen, true); + } + break; + default: { + Dbprintf("Error, unknown function: %d", htf); + return; + } + break; } // Send and store the reader command @@ -1694,22 +1715,22 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { // falling edge occured halfway the period. with respect to this falling edge, // we need to wait (T_Wait2 + half_tag_period) when the last was a 'one'. // All timer values are in terms of T0 units - while(AT91C_BASE_TC0->TC_CV < T0*(t_wait+(HITAG_T_TAG_HALF_PERIOD*lastbit))); + while (AT91C_BASE_TC0->TC_CV < T0*(t_wait+(HITAG_T_TAG_HALF_PERIOD*lastbit))); //Dbprintf("DEBUG: Sending reader frame"); // Transmit the reader frame - hitag_reader_send_frame(tx,txlen); + hitag_reader_send_frame(tx, txlen); - // Enable and reset external trigger in timer for capturing future frames + // Enable and reset external trigger in timer for capturing future frames AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // Add transmitted frame to total count - if(txlen > 0) { - frame_count++; + if (txlen > 0) { + // frame_count++; if (!bQuiet) { // Store the frame in the trace - if (!LogTraceHitag(tx,txlen,HITAG_T_WAIT_2,0,true)) { + if (!LogTraceHitag(tx, txlen, HITAG_T_WAIT_2, 0, true)) { if (bQuitTraceFull) { break; } else { @@ -1720,7 +1741,7 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { } // Reset values for receiving frames - memset(rx,0x00,sizeof(rx)); + memset(rx, 0x00, sizeof(rx)); rxlen = 0; lastbit = 1; bSkip = true; @@ -1732,7 +1753,7 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { // Receive frame, watch for at most T0*EOF periods while (AT91C_BASE_TC1->TC_CV < T0*HITAG_T_WAIT_MAX) { // Check if falling edge in tag modulation is detected - if(AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { + if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { // Retrieve the new timing values int ra = (AT91C_BASE_TC1->TC_RA/T0); @@ -1742,31 +1763,31 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { LED_B_ON(); // Capture tag frame (manchester decoding using only falling edges) - if(ra >= HITAG_T_EOF) { + if (ra >= HITAG_T_EOF) { if (rxlen != 0) { //Dbprintf("DEBUG: Wierd1"); } // Capture the T0 periods that have passed since last communication or field drop (reset) // We always recieve a 'one' first, which has the falling edge after a half period |-_| - response = ra-HITAG_T_TAG_HALF_PERIOD; - } else if(ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { + response = ra - HITAG_T_TAG_HALF_PERIOD; + } else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { // Manchester coding example |-_|_-|-_| (101) - //need to test to verify we don't exceed memory... - //if ( ((rxlen+2) / 8) > HITAG_FRAME_LEN) { - // break; - //} + // need to test to verify we don't exceed memory... + // if ( ((rxlen+2) / 8) > HITAG_FRAME_LEN) { + // break; + // } rx[rxlen / 8] |= 0 << (7-(rxlen%8)); rxlen++; rx[rxlen / 8] |= 1 << (7-(rxlen%8)); rxlen++; - } else if(ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { + } else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { // Manchester coding example |_-|...|_-|-_| (0...01) - //need to test to verify we don't exceed memory... - //if ( ((rxlen+2) / 8) > HITAG_FRAME_LEN) { - // break; - //} + // need to test to verify we don't exceed memory... + // if ( ((rxlen+2) / 8) > HITAG_FRAME_LEN) { + // break; + // } rx[rxlen / 8] |= 0 << (7-(rxlen%8)); rxlen++; // We have to skip this half period at start and add the 'one' the second time @@ -1776,13 +1797,13 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { } lastbit = !lastbit; bSkip = !bSkip; - } else if(ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { + } else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { // Manchester coding example |_-|_-| (00) or |-_|-_| (11) - //need to test to verify we don't exceed memory... - //if ( ((rxlen+2) / 8) > HITAG_FRAME_LEN) { - // break; - //} + // need to test to verify we don't exceed memory... + // if ( ((rxlen+2) / 8) > HITAG_FRAME_LEN) { + // break; + // } if (tag_sof) { // Ignore bits that are transmitted during SOF tag_sof--; @@ -1792,24 +1813,23 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { rxlen++; } } else { - //Dbprintf("DEBUG: Wierd2"); + // Dbprintf("DEBUG: Wierd2"); errorCount++; - // Ignore wierd value, is to small to mean anything + // Ignore wierd value, it is too small to mean anything } } - //if we saw over 100 wierd values break it probably isn't hitag... - if (errorCount >100) break; + // if we saw over 100 wierd values break it probably isn't hitag... + if (errorCount > 100) break; // We can break this loop if we received the last bit from a frame if (AT91C_BASE_TC1->TC_CV > T0*HITAG_T_EOF) { - if (rxlen>0) break; + if (rxlen > 0) break; } } // Wait some extra time for flash to be programmed - if ((rxlen == 0) && (writestate == WRITE_STATE_PROG)) - { + if ((rxlen == 0) && (writestate == WRITE_STATE_PROG)) { AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - while(AT91C_BASE_TC0->TC_CV < T0*(HITAG_T_PROG - HITAG_T_WAIT_MAX)); + while (AT91C_BASE_TC0->TC_CV < T0*(HITAG_T_PROG - HITAG_T_WAIT_MAX)); } } //Dbprintf("DEBUG: Done waiting for frame"); @@ -1821,5 +1841,5 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); //Dbprintf("frame received: %d",frame_count); //DbpString("All done"); - cmd_send(CMD_ACK,bSuccessful,0,0,(byte_t*)tag.sectors,48); + cmd_send(CMD_ACK, bSuccessful, 0, 0, (uint8_t*)tag.sectors, 48); } diff --git a/armsrc/hitag2.h b/armsrc/hitag2.h index 555f04ee..3883c17b 100644 --- a/armsrc/hitag2.h +++ b/armsrc/hitag2.h @@ -16,9 +16,9 @@ #include #include "hitag.h" -void SnoopHitag(uint32_t type); -void SimulateHitagTag(bool tag_mem_supplied, uint8_t* data); -void ReaderHitag(hitag_function htf, hitag_data* htd); -void WriterHitag(hitag_function htf, hitag_data* htd, int page); +extern void SnoopHitag(uint32_t type); +extern void SimulateHitagTag(bool tag_mem_supplied, uint8_t* data); +extern void ReaderHitag(hitag_function htf, hitag_data* htd); +extern void WriterHitag(hitag_function htf, hitag_data* htd, int page); #endif diff --git a/armsrc/hitagS.c b/armsrc/hitagS.c index 9e8f1432..5da170bb 100644 --- a/armsrc/hitagS.c +++ b/armsrc/hitagS.c @@ -26,18 +26,6 @@ #define CRC_PRESET 0xFF #define CRC_POLYNOM 0x1D -#define u8 uint8_t -#define u32 uint32_t -#define u64 uint64_t -#define rev8(x) ((((x)>>7)&1)+((((x)>>6)&1)<<1)+((((x)>>5)&1)<<2)+((((x)>>4)&1)<<3)+((((x)>>3)&1)<<4)+((((x)>>2)&1)<<5)+((((x)>>1)&1)<<6)+(((x)&1)<<7)) -#define rev16(x) (rev8 (x)+(rev8 (x>> 8)<< 8)) -#define rev32(x) (rev16(x)+(rev16(x>>16)<<16)) -#define rev64(x) (rev32(x)+(rev32(x>>32)<<32)) -#define bit(x,n) (((x)>>(n))&1) -#define bit32(x,n) ((((x)[(n)>>5])>>((n)))&1) -#define inv32(x,i,n) ((x)[(i)>>5]^=((u32)(n))<<((i)&31)) -#define rotl64(x, n) ((((u64)(x))<<((n)&63))+(((u64)(x))>>((0-(n))&63))) - static bool bQuiet; static bool bSuccessful; static struct hitagS_tag tag; @@ -57,17 +45,17 @@ size_t blocknr; bool end=false; // Single bit Hitag2 functions: -#define i4(x,a,b,c,d) ((u32)((((x)>>(a))&1)+(((x)>>(b))&1)*2+(((x)>>(c))&1)*4+(((x)>>(d))&1)*8)) -static const u32 ht2_f4a = 0x2C79; // 0010 1100 0111 1001 -static const u32 ht2_f4b = 0x6671; // 0110 0110 0111 0001 -static const u32 ht2_f5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011 +#define i4(x,a,b,c,d) ((uint32_t)((((x)>>(a))&1)+(((x)>>(b))&1)*2+(((x)>>(c))&1)*4+(((x)>>(d))&1)*8)) +static const uint32_t ht2_f4a = 0x2C79; // 0010 1100 0111 1001 +static const uint32_t ht2_f4b = 0x6671; // 0110 0110 0111 0001 +static const uint32_t ht2_f5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011 #define ht2bs_4a(a,b,c,d) (~(((a|b)&c)^(a|d)^b)) #define ht2bs_4b(a,b,c,d) (~(((d|c)&(a^b))^(d|a|b))) #define ht2bs_5c(a,b,c,d,e) (~((((((c^e)|d)&a)^b)&(c^b))^(((d^e)|a)&((d^b)|c)))) -#define uf20bs u32 +#define uf20bs uint32_t -static u32 f20(const u64 x) { - u32 i5; +static uint32_t f20(const uint64_t x) { + uint32_t i5; i5 = ((ht2_f4a >> i4(x, 1, 2, 4, 5)) & 1) * 1 + ((ht2_f4b >> i4(x, 7, 11, 13, 14)) & 1) * 2 @@ -77,8 +65,19 @@ static u32 f20(const u64 x) { return (ht2_f5c >> i5) & 1; } -static u64 hitag2_round(u64 *state) { - u64 x = *state; + +static uint64_t hitag2_init(const uint64_t key, const uint32_t serial, const uint32_t IV) { + uint32_t i; + uint64_t x = ((key & 0xFFFF) << 32) + serial; + for (i = 0; i < 32; i++) { + x >>= 1; + x += (uint64_t) (f20(x) ^ (((IV >> i) ^ (key >> (i + 16))) & 1)) << 47; + } + return x; +} + +static uint64_t hitag2_round(uint64_t *state) { + uint64_t x = *state; x = (x >> 1) + ((((x >> 0) ^ (x >> 2) ^ (x >> 3) ^ (x >> 6) ^ (x >> 7) ^ (x >> 8) @@ -89,20 +88,12 @@ static u64 hitag2_round(u64 *state) { *state = x; return f20(x); } -static u64 hitag2_init(const u64 key, const u32 serial, const u32 IV) { - u32 i; - u64 x = ((key & 0xFFFF) << 32) + serial; - for (i = 0; i < 32; i++) { - x >>= 1; - x += (u64) (f20(x) ^ (((IV >> i) ^ (key >> (i + 16))) & 1)) << 47; - } - return x; -} -static u32 hitag2_byte(u64 *x) { - u32 i, c; + +static uint32_t hitag2_byte(uint64_t *x) { + uint32_t i, c; for (i = 0, c = 0; i < 8; i++) - c += (u32) hitag2_round(x) << (i ^ 7); + c += (uint32_t) hitag2_round(x) << (i ^ 7); return c; } @@ -858,7 +849,7 @@ static void hitagS_handle_reader_command(byte_t* rx, const size_t rxlen, byte_t rx_air[HITAG_FRAME_LEN]; byte_t page; int i; - u64 state; + uint64_t state; unsigned char crc; // Copy the (original) received frame how it is send over the air @@ -956,8 +947,8 @@ static void hitagS_handle_reader_command(byte_t* rx, const size_t rxlen, //challenge message received Dbprintf("Challenge for UID: %X", temp_uid); temp2++; - state = hitag2_init(rev64(tag.key), rev32(tag.pages[0][0]), - rev32(((rx[3] << 24) + (rx[2] << 16) + (rx[1] << 8) + rx[0]))); + state = hitag2_init(REV64(tag.key), REV32(tag.pages[0][0]), + REV32(((rx[3] << 24) + (rx[2] << 16) + (rx[1] << 8) + rx[0]))); Dbprintf( ",{0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X}", rx[0], rx[1], rx[2], rx[3], rx[4], rx[5], rx[6], rx[7]); @@ -1216,7 +1207,7 @@ static int hitagS_handle_tag_auth(hitag_function htf,uint64_t key, uint64_t NrAr unsigned char uid[32]; byte_t uid1 = 0x00, uid2 = 0x00, uid3 = 0x00, uid4 = 0x00; unsigned char crc; - u64 state; + uint64_t state; byte_t auth_ks[4]; byte_t conf_pages[3]; memcpy(rx_air, rx, nbytes(rxlen)); @@ -1356,11 +1347,11 @@ static int hitagS_handle_tag_auth(hitag_function htf,uint64_t key, uint64_t NrAr *txlen = 64; if(end!=true){ if(htf==02||htf==04){ //RHTS_KEY //WHTS_KEY - state = hitag2_init(rev64(key), rev32(tag.uid), rev32(rnd)); + state = hitag2_init(REV64(key), REV32(tag.uid), REV32(rnd)); /* - Dbprintf("key: %02X %02X\n\n", key, rev64(key)); - Dbprintf("tag.uid: %02X %02X\n\n", tag.uid, rev32(tag.uid)); - Dbprintf("rnd: %02X %02X\n\n", rnd, rev32(rnd)); + Dbprintf("key: %02X %02X\n\n", key, REV64(key)); + Dbprintf("tag.uid: %02X %02X\n\n", tag.uid, REV32(tag.uid)); + Dbprintf("rnd: %02X %02X\n\n", rnd, REV32(rnd)); */ for (i = 0; i < 4; i++) { auth_ks[i] = hitag2_byte(&state) ^ 0xff; @@ -1404,7 +1395,7 @@ static int hitagS_handle_tag_auth(hitag_function htf,uint64_t key, uint64_t NrAr pwdl0=0; pwdl1=0; if(htf==02 || htf==04) { //RHTS_KEY //WHTS_KEY - state = hitag2_init(rev64(key), rev32(tag.uid), rev32(rnd)); + state = hitag2_init(REV64(key), REV32(tag.uid), REV32(rnd)); for (i = 0; i < 5; i++) { hitag2_byte(&state); } diff --git a/armsrc/util.h b/armsrc/util.h index da333e01..7b3d0849 100644 --- a/armsrc/util.h +++ b/armsrc/util.h @@ -17,15 +17,21 @@ #define BYTEx(x, n) (((x) >> (n * 8)) & 0xff ) -#define LED_RED 1 +#define LED_RED 1 #define LED_ORANGE 2 -#define LED_GREEN 4 -#define LED_RED2 8 -#define BUTTON_HOLD 1 -#define BUTTON_NO_CLICK 0 -#define BUTTON_SINGLE_CLICK -1 -#define BUTTON_DOUBLE_CLICK -2 -#define BUTTON_ERROR -99 +#define LED_GREEN 4 +#define LED_RED2 8 + +#define BUTTON_HOLD 1 +#define BUTTON_NO_CLICK 0 +#define BUTTON_SINGLE_CLICK -1 +#define BUTTON_DOUBLE_CLICK -2 +#define BUTTON_ERROR -99 + +#define REV8(x) ((((x)>>7)&1)|((((x)>>6)&1)<<1)|((((x)>>5)&1)<<2)|((((x)>>4)&1)<<3)|((((x)>>3)&1)<<4)|((((x)>>2)&1)<<5)|((((x)>>1)&1)<<6)|(((x)&1)<<7)) +#define REV16(x) (REV8(x) | (REV8 (x >> 8) << 8)) +#define REV32(x) (REV16(x) | (REV16(x >> 16) << 16)) +#define REV64(x) (REV32(x) | (REV32(x >> 32) << 32)) void print_result(char *name, uint8_t *buf, size_t len); size_t nbytes(size_t nbits); diff --git a/client/cmdlfhitag.c b/client/cmdlfhitag.c index cd23f88c..be807222 100644 --- a/client/cmdlfhitag.c +++ b/client/cmdlfhitag.c @@ -22,15 +22,13 @@ #include "hitag.h" #include "cmdmain.h" -static int CmdHelp(const char *Cmd); - -size_t nbytes(size_t nbits) { - return (nbits/8)+((nbits%8)>0); +static size_t nbytes(size_t nbits) { + return (nbits/8) + ((nbits%8)>0); } -int CmdLFHitagList(const char *Cmd) -{ - uint8_t *got = malloc(USB_CMD_DATA_SIZE); + +static int CmdLFHitagList(const char *Cmd) { + uint8_t *got = malloc(USB_CMD_DATA_SIZE); // Query for the actual size of the trace UsbCommand response; GetFromBigBuf(got, USB_CMD_DATA_SIZE, 0, &response, -1, false); @@ -45,7 +43,7 @@ int CmdLFHitagList(const char *Cmd) got = p; GetFromBigBuf(got, traceLen, 0, NULL, -1, false); } - + PrintAndLog("recorded activity (TraceLen = %d bytes):"); PrintAndLog(" ETU :nbits: who bytes"); PrintAndLog("---------+-----+----+-----------"); @@ -57,11 +55,11 @@ int CmdLFHitagList(const char *Cmd) char filename[FILE_PATH_SIZE] = { 0x00 }; FILE* pf = NULL; - - if (len > FILE_PATH_SIZE) + + if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; memcpy(filename, Cmd, len); - + if (strlen(filename) > 0) { if ((pf = fopen(filename,"wb")) == NULL) { PrintAndLog("Error: Could not open file [%s]",filename); @@ -71,7 +69,7 @@ int CmdLFHitagList(const char *Cmd) } for (;;) { - + if(i > traceLen) { break; } bool isResponse; @@ -95,7 +93,7 @@ int CmdLFHitagList(const char *Cmd) int len = nbytes(bits); if (len > 100) { - break; + break; } if (i + len > traceLen) { break;} @@ -104,7 +102,7 @@ int CmdLFHitagList(const char *Cmd) int fillupBits = 8 - (bits % 8); byte_t framefilled[bits+fillupBits]; byte_t* ff = framefilled; - + int response_bit[200] = {0}; int z = 0; for (int y = 0; y < len; y++) { @@ -133,12 +131,12 @@ int CmdLFHitagList(const char *Cmd) char line[1000] = ""; for (j = 0; j < len; j++) { - //if((parityBits >> (len - j - 1)) & 0x01) { - if (isResponse && (oddparity8(frame[j]) != ((parityBits >> (len - j - 1)) & 0x01))) { - sprintf(line+(j*4), "%02x! ", frame[j]); - } else { - sprintf(line+(j*4), "%02x ", frame[j]); - } + //if((parityBits >> (len - j - 1)) & 0x01) { + if (isResponse && (oddparity8(frame[j]) != ((parityBits >> (len - j - 1)) & 0x01))) { + sprintf(line+(j*4), "%02x! ", frame[j]); + } else { + sprintf(line+(j*4), "%02x ", frame[j]); + } } PrintAndLog(" +%7d: %3d: %s %s", @@ -154,11 +152,11 @@ int CmdLFHitagList(const char *Cmd) (isResponse ? "TAG" : " "), line); } - + prev = timestamp; i += (len + 9); } - + if (pf) { fclose(pf); PrintAndLog("Recorded activity succesfully written to file: %s", filename); @@ -168,22 +166,24 @@ int CmdLFHitagList(const char *Cmd) return 0; } -int CmdLFHitagSnoop(const char *Cmd) { - UsbCommand c = {CMD_SNOOP_HITAG}; - SendCommand(&c); - return 0; + +static int CmdLFHitagSnoop(const char *Cmd) { + UsbCommand c = {CMD_SNOOP_HITAG}; + SendCommand(&c); + return 0; } -int CmdLFHitagSim(const char *Cmd) { - - UsbCommand c = {CMD_SIMULATE_HITAG}; + +static int CmdLFHitagSim(const char *Cmd) { + + UsbCommand c = {CMD_SIMULATE_HITAG}; char filename[FILE_PATH_SIZE] = { 0x00 }; FILE* pf; bool tag_mem_supplied; int len = strlen(Cmd); if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; memcpy(filename, Cmd, len); - + if (strlen(filename) > 0) { if ((pf = fopen(filename,"rb+")) == NULL) { PrintAndLog("Error: Could not open file [%s]",filename); @@ -199,56 +199,114 @@ int CmdLFHitagSim(const char *Cmd) { } else { tag_mem_supplied = false; } - + // Does the tag comes with memory c.arg[0] = (uint32_t)tag_mem_supplied; - SendCommand(&c); - return 0; + SendCommand(&c); + return 0; } -int CmdLFHitagReader(const char *Cmd) { - UsbCommand c = {CMD_READER_HITAG};//, {param_get32ex(Cmd,0,0,10),param_get32ex(Cmd,1,0,16),param_get32ex(Cmd,2,0,16),param_get32ex(Cmd,3,0,16)}}; - hitag_data* htd = (hitag_data*)c.d.asBytes; - hitag_function htf = param_get32ex(Cmd,0,0,10); + +static bool getHitagUid(uint32_t *uid) { + // ToDo: this is for Hitag2 only (??) + UsbCommand c = {CMD_READER_HITAG, {RHT2F_UID_ONLY}}; + + SendCommand(&c); + + UsbCommand resp; + if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) { + PrintAndLogEx(WARNING, "timeout while waiting for reply."); + return false; + } + + if (resp.arg[0] == false) { + PrintAndLogEx(DEBUG, "DEBUG: Error - failed getting UID"); + return false; + } + + if (uid) + *uid = bytes_to_num(resp.d.asBytes, 4); + + return true; +} + + +static int CmdLFHitagInfo(const char *Cmd) { + char ctmp = param_getchar(Cmd, 0); + if (ctmp != '\0') { + PrintAndLog("Usage: lf hitag info [h]"); + PrintAndLog("Options:"); + PrintAndLog(" h This help"); + PrintAndLog("Examples:"); + PrintAndLog(" lf hitag info"); + return 0; + } + + // read UID + uint32_t uid = 0; + if (getHitagUid(&uid) == false) + return 1; + + PrintAndLogEx(SUCCESS, "UID: %08X", uid); + + // how to detemine Hitag types? + // read block3, get configuration byte. + // PrintAndLogEx(FAILED, _RED_("TODO: This is a hardcoded example!")); + + // common configurations. + // printHitagConfiguration(0x06); + //printHitagConfiguration( 0x0E ); + //printHitagConfiguration( 0x02 ); + //printHitagConfiguration( 0x00 ); + //printHitagConfiguration( 0x04 ); + return 0; +} + + +int CmdLFHitagReader(const char *Cmd) { + UsbCommand c = {CMD_READER_HITAG}; + hitag_data* htd = (hitag_data*)c.d.asBytes; + hitag_function htf = param_get32ex(Cmd, 0, 0, 10); + switch (htf) { case 01: { //RHTSF_CHALLENGE c = (UsbCommand){ CMD_READ_HITAG_S }; - num_to_bytes(param_get32ex(Cmd,1,0,16),4,htd->auth.NrAr); - num_to_bytes(param_get32ex(Cmd,2,0,16),4,htd->auth.NrAr+4); - c.arg[1] = param_get64ex(Cmd,3,0,0); //firstpage - c.arg[2] = param_get64ex(Cmd,4,0,0); //tag mode + num_to_bytes(param_get32ex(Cmd, 1, 0, 16), 4, htd->auth.NrAr); + num_to_bytes(param_get32ex(Cmd, 2, 0, 16), 4, htd->auth.NrAr+4); + c.arg[1] = param_get64ex(Cmd, 3, 0, 0); //firstpage + c.arg[2] = param_get64ex(Cmd, 4, 0, 0); //tag mode } break; case 02: { //RHTSF_KEY c = (UsbCommand){ CMD_READ_HITAG_S }; - num_to_bytes(param_get64ex(Cmd,1,0,16),6,htd->crypto.key); - c.arg[1] = param_get64ex(Cmd,2,0,0); //firstpage - c.arg[2] = param_get64ex(Cmd,3,0,0); //tag mode + num_to_bytes(param_get64ex(Cmd, 1, 0, 16), 6, htd->crypto.key); + c.arg[1] = param_get64ex(Cmd, 2, 0, 0); //firstpage + c.arg[2] = param_get64ex(Cmd, 3, 0, 0); //tag mode } break; case 03: { //RHTSF_CHALLENGE BLOCK c = (UsbCommand){ CMD_READ_HITAG_S_BLK }; - num_to_bytes(param_get32ex(Cmd,1,0,16),4,htd->auth.NrAr); - num_to_bytes(param_get32ex(Cmd,2,0,16),4,htd->auth.NrAr+4); - c.arg[1] = param_get64ex(Cmd,3,0,0); //firstpage - c.arg[2] = param_get64ex(Cmd,4,0,0); //tag mode + num_to_bytes(param_get32ex(Cmd, 1, 0, 16), 4, htd->auth.NrAr); + num_to_bytes(param_get32ex(Cmd, 2, 0, 16), 4, htd->auth.NrAr+4); + c.arg[1] = param_get64ex(Cmd, 3, 0, 0); //firstpage + c.arg[2] = param_get64ex(Cmd, 4, 0, 0); //tag mode } break; case 04: { //RHTSF_KEY BLOCK c = (UsbCommand){ CMD_READ_HITAG_S_BLK }; - num_to_bytes(param_get64ex(Cmd,1,0,16),6,htd->crypto.key); - c.arg[1] = param_get64ex(Cmd,2,0,0); //firstpage - c.arg[2] = param_get64ex(Cmd,3,0,0); //tag mode + num_to_bytes(param_get64ex(Cmd, 1, 0, 16), 6, htd->crypto.key); + c.arg[1] = param_get64ex(Cmd, 2, 0, 0); //firstpage + c.arg[2] = param_get64ex(Cmd, 3, 0, 0); //tag mode } break; case RHT2F_PASSWORD: { - num_to_bytes(param_get32ex(Cmd,1,0,16),4,htd->pwd.password); + num_to_bytes(param_get32ex(Cmd, 1, 0, 16), 4, htd->pwd.password); } break; case RHT2F_AUTHENTICATE: { - num_to_bytes(param_get32ex(Cmd,1,0,16),4,htd->auth.NrAr); - num_to_bytes(param_get32ex(Cmd,2,0,16),4,htd->auth.NrAr+4); + num_to_bytes(param_get32ex(Cmd, 1, 0, 16), 4, htd->auth.NrAr); + num_to_bytes(param_get32ex(Cmd, 2, 0, 16), 4, htd->auth.NrAr+4); } break; case RHT2F_CRYPTO: { - num_to_bytes(param_get64ex(Cmd,1,0,16),6,htd->crypto.key); - // num_to_bytes(param_get32ex(Cmd,2,0,16),4,htd->auth.NrAr+4); + num_to_bytes(param_get64ex(Cmd, 1, 0, 16), 6, htd->crypto.key); + // num_to_bytes(param_get32ex(Cmd,2,0,16),4,htd->auth.NrAr+4); } break; case RHT2F_TEST_AUTH_ATTEMPTS: { // No additional parameters needed @@ -261,19 +319,20 @@ int CmdLFHitagReader(const char *Cmd) { PrintAndLog(""); PrintAndLog("Usage: hitag reader "); PrintAndLog("Reader Functions:"); - PrintAndLog(" HitagS (0*)"); - PrintAndLog(" 01 (Challenge) read all pages from a Hitag S tag"); - PrintAndLog(" 02 (set to 0 if no authentication is needed) read all pages from a Hitag S tag"); - PrintAndLog(" 03 (Challenge) read all blocks from a Hitag S tag"); - PrintAndLog(" 04 (set to 0 if no authentication is needed) read all blocks from a Hitag S tag"); - PrintAndLog(" Valid tagmodes are 0=STANDARD, 1=ADVANCED, 2=FAST_ADVANCED (default is ADVANCED)"); - PrintAndLog(" Hitag1 (1*)"); - PrintAndLog(" Hitag2 (2*)"); - PrintAndLog(" 21 (password mode)"); - PrintAndLog(" 22 (authentication)"); - PrintAndLog(" 23 (authentication) key is in format: ISK high + ISK low"); - PrintAndLog(" 25 (test recorded authentications)"); - PrintAndLog(" 26 just read UID"); + PrintAndLog(" HitagS (0*):"); + PrintAndLog(" 01 (Challenge) read all pages from a Hitag S tag"); + PrintAndLog(" 02 (set to 0 if no authentication is needed) read all pages from a Hitag S tag"); + PrintAndLog(" 03 (Challenge) read all blocks from a Hitag S tag"); + PrintAndLog(" 04 (set to 0 if no authentication is needed) read all blocks from a Hitag S tag"); + PrintAndLog(" Valid tagmodes are 0=STANDARD, 1=ADVANCED, 2=FAST_ADVANCED (default is ADVANCED)"); + PrintAndLog(" Hitag1 (1*):"); + PrintAndLog(" (not yet implemented)"); + PrintAndLog(" Hitag2 (2*):"); + PrintAndLog(" 21 (password mode)"); + PrintAndLog(" 22 (authentication)"); + PrintAndLog(" 23 (authentication) key is in format: ISK high + ISK low"); + PrintAndLog(" 25 (test recorded authentications)"); + PrintAndLog(" 26 just read UID"); return 1; } break; } @@ -286,13 +345,19 @@ int CmdLFHitagReader(const char *Cmd) { SendCommand(&c); UsbCommand resp; - WaitForResponse(CMD_ACK,&resp); + if (!WaitForResponseTimeout(CMD_ACK, &resp, 4000)) { + PrintAndLogEx(WARNING, "timeout while waiting for reply."); + return 1; + } // Check the return status, stored in the first argument - if (resp.arg[0] == false) return 1; - + if (resp.arg[0] == false) { + PrintAndLogEx(DEBUG, "DEBUG: Error - hitag failed"); + return 1; + } + uint32_t id = bytes_to_num(resp.d.asBytes,4); - + if (htf == RHT2F_UID_ONLY){ PrintAndLog("Valid Hitag2 tag found - UID: %08x",id); } else { @@ -312,12 +377,11 @@ int CmdLFHitagReader(const char *Cmd) { PrintAndLog("Succesfully saved tag memory to [%s]",filename); } - return 0; } -int CmdLFHitagSimS(const char *Cmd) { +static int CmdLFHitagSimS(const char *Cmd) { UsbCommand c = { CMD_SIMULATE_HITAG_S }; char filename[FILE_PATH_SIZE] = { 0x00 }; FILE* pf; @@ -350,7 +414,8 @@ int CmdLFHitagSimS(const char *Cmd) { return 0; } -int CmdLFHitagCheckChallenges(const char *Cmd) { + +static int CmdLFHitagCheckChallenges(const char *Cmd) { UsbCommand c = { CMD_TEST_HITAGS_TRACES }; char filename[FILE_PATH_SIZE] = { 0x00 }; FILE* pf; @@ -358,7 +423,7 @@ int CmdLFHitagCheckChallenges(const char *Cmd) { int len = strlen(Cmd); if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; memcpy(filename, Cmd, len); - + if (strlen(filename) > 0) { if ((pf = fopen(filename,"rb+")) == NULL) { PrintAndLog("Error: Could not open file [%s]",filename); @@ -369,87 +434,101 @@ int CmdLFHitagCheckChallenges(const char *Cmd) { PrintAndLog("Error: File reading error"); fclose(pf); return 1; - } + } fclose(pf); } else { file_given = false; } - + //file with all the challenges to try c.arg[0] = (uint32_t)file_given; c.arg[1] = param_get64ex(Cmd,2,0,0); //get mode - SendCommand(&c); - return 0; + SendCommand(&c); + return 0; } -int CmdLFHitagWP(const char *Cmd) { +static int CmdLFHitagWriter(const char *Cmd) { UsbCommand c = { CMD_WR_HITAG_S }; hitag_data* htd = (hitag_data*)c.d.asBytes; hitag_function htf = param_get32ex(Cmd,0,0,10); switch (htf) { - case 03: { //WHTSF_CHALLENGE + case WHTSF_CHALLENGE: { num_to_bytes(param_get64ex(Cmd,1,0,16),8,htd->auth.NrAr); c.arg[2]= param_get32ex(Cmd, 2, 0, 10); num_to_bytes(param_get32ex(Cmd,3,0,16),4,htd->auth.data); } break; - case 04: - case 24: - { //WHTSF_KEY + case WHTSF_KEY: + case WHT2F_CRYPTO: { num_to_bytes(param_get64ex(Cmd,1,0,16),6,htd->crypto.key); c.arg[2]= param_get32ex(Cmd, 2, 0, 10); num_to_bytes(param_get32ex(Cmd,3,0,16),4,htd->crypto.data); - + } break; + case WHT2F_PASSWORD: { + num_to_bytes(param_get64ex(Cmd, 1, 0, 16), 4, htd->pwd.password); + c.arg[2] = param_get32ex(Cmd, 2, 0, 10); + num_to_bytes(param_get32ex(Cmd, 3, 0, 16), 4, htd->crypto.data); } break; default: { PrintAndLog("Error: unkown writer function %d",htf); PrintAndLog("Hitag writer functions"); - PrintAndLog(" HitagS (0*)"); - PrintAndLog(" 03 (Challenge) write page on a Hitag S tag"); - PrintAndLog(" 04 (set to 0 if no authentication is needed) write page on a Hitag S tag"); - PrintAndLog(" Hitag1 (1*)"); - PrintAndLog(" Hitag2 (2*)"); - PrintAndLog(" 24 (set to 0 if no authentication is needed) write page on a Hitag S tag"); + PrintAndLog(" HitagS (0*):"); + PrintAndLog(" 03 (Challenge) write page on a Hitag S tag"); + PrintAndLog(" 04 (set to 0 if no authentication is needed) write page on a Hitag S tag"); + PrintAndLog(" Hitag1 (1*)"); + PrintAndLog(" (not yet implemented)"); + PrintAndLog(" Hitag2 (2*):"); + PrintAndLog(" 24 (set to 0 if no authentication is needed) write page on a Hitag S tag"); + PrintAndLog(" 27 write page on a Hitag2 tag"); return 1; } break; } // Copy the hitag function into the first argument c.arg[0] = htf; - // Send the command to the proxmark - SendCommand(&c); - - UsbCommand resp; - WaitForResponse(CMD_ACK,&resp); - - // Check the return status, stored in the first argument - if (resp.arg[0] == false) return 1; - return 0; + // Send the command to the proxmark + SendCommand(&c); + + UsbCommand resp; + if (!WaitForResponseTimeout(CMD_ACK, &resp, 4000)) { + PrintAndLogEx(WARNING, "timeout while waiting for reply."); + return 1; + } + + // Check the return status, stored in the first argument + if (resp.arg[0] == false) { + PrintAndLogEx(DEBUG, "DEBUG: Error - hitag write failed"); + return 1; + } + return 0; } -static command_t CommandTable[] = +static int CmdHelp(const char *Cmd); + +static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help"}, - {"list", CmdLFHitagList, 1, " List Hitag trace history"}, - {"reader", CmdLFHitagReader, 1, "Act like a Hitag Reader"}, - {"sim", CmdLFHitagSim, 1, " Simulate Hitag transponder"}, - {"snoop", CmdLFHitagSnoop, 1, "Eavesdrop Hitag communication"}, - {"writer", CmdLFHitagWP, 1, "Act like a Hitag Writer" }, - {"simS", CmdLFHitagSimS, 1, " Simulate HitagS transponder" }, - {"checkChallenges", CmdLFHitagCheckChallenges, 1, " test all challenges" }, { - NULL,NULL, 0, NULL } + {"help", CmdHelp, 1, "This help"}, + {"list", CmdLFHitagList, 0, " List Hitag trace history"}, + {"info", CmdLFHitagInfo, 0, "Tag information" }, + {"reader", CmdLFHitagReader, 0, "Act like a Hitag Reader"}, + {"sim", CmdLFHitagSim, 0, "Simulate Hitag transponder"}, + {"snoop", CmdLFHitagSnoop, 0, "Eavesdrop Hitag communication"}, + {"writer", CmdLFHitagWriter, 0, "Act like a Hitag Writer" }, + {"simS", CmdLFHitagSimS, 0, "Simulate HitagS transponder" }, + {"checkChallenges", CmdLFHitagCheckChallenges, 0, "Test challenges from a file" }, + { NULL, NULL, 0, NULL } }; -int CmdLFHitag(const char *Cmd) -{ - CmdsParse(CommandTable, Cmd); - return 0; + +static int CmdHelp(const char *Cmd) { + CmdsHelp(CommandTable); + return 0; } -int CmdHelp(const char *Cmd) -{ - CmdsHelp(CommandTable); - return 0; + +int CmdLFHitag(const char *Cmd) { + CmdsParse(CommandTable, Cmd); + return 0; } diff --git a/client/cmdlfhitag.h b/client/cmdlfhitag.h index 22b6bb06..062ed484 100644 --- a/client/cmdlfhitag.h +++ b/client/cmdlfhitag.h @@ -11,11 +11,7 @@ #ifndef CMDLFHITAG_H__ #define CMDLFHITAG_H__ -int CmdLFHitag(const char *Cmd); - -int CmdLFHitagList(const char *Cmd); -int CmdLFHitagSnoop(const char *Cmd); -int CmdLFHitagSim(const char *Cmd); -int CmdLFHitagReader(const char *Cmd); +extern int CmdLFHitag(const char *Cmd); +extern int CmdLFHitagReader(const char *Cmd); #endif diff --git a/common/protocols.h b/common/protocols.h index 51fe579e..9de72661 100644 --- a/common/protocols.h +++ b/common/protocols.h @@ -236,6 +236,26 @@ NXP/Philips CUSTOM COMMANDS #define TOPAZ_WRITE_E8 0x54 // Write-with-erase (eight bytes) #define TOPAZ_WRITE_NE8 0x1B // Write-no-erase (eight bytes) +// HITAG1 commands +#define HITAG1_SET_CCNEW 0xC2 // left 5 bits only +#define HITAG1_READ_ID 0x00 // not a real command, consists of 5 bits length, bits partial SN, 8 bits CRC +#define HITAG1_SELECT 0x00 // left 5 bits only, followed by 32 bits SN and 8 bits CRC +#define HITAG1_WRPPAGE 0x80 // left 4 bits only, followed by 8 bits page and 8 bits CRC +#define HITAG1_WRPBLK 0x90 // left 4 bits only, followed by 8 bits block and 8 bits CRC +#define HITAG1_WRCPAGE 0xA0 // left 4 bits only, followed by 8 bits page or key information and 8 bits CRC +#define HITAG1_WRCBLK 0xB0 // left 4 bits only, followed by 8 bits block and 8 bits CRC +#define HITAG1_RDPPAGE 0xC0 // left 4 bits only, followed by 8 bits page and 8 bits CRC +#define HITAG1_RDPBLK 0xD0 // left 4 bits only, followed by 8 bits block and 8 bits CRC +#define HITAG1_RDCPAGE 0xE0 // left 4 bits only, followed by 8 bits page and 8 bits CRC +#define HITAG1_RDCBLK 0xF0 // left 4 bits only, followed by 8 bits block and 8 bits CRC +#define HITAG1_HALT 0x70 // left 4 bits only, followed by 8 bits (dummy) page and 8 bits CRC + +// HITAG2 commands +#define HITAG2_START_AUTH 0xC0 // left 5 bits only +#define HITAG2_READ_PAGE 0xC0 // page number in bits 5 to 3, page number inverted in bit 0 and following 2 bits +#define HITAG2_READ_PAGE_INVERTED 0x44 // page number in bits 5 to 3, page number inverted in bit 0 and following 2 bits +#define HITAG2_WRITE_PAGE 0x82 // page number in bits 5 to 3, page number inverted in bit 0 and following 2 bits +#define HITAG2_HALT 0x00 // left 5 bits only #define ISO_14443A 0 #define ICLASS 1 diff --git a/include/hitag.h b/include/hitag.h index 35660dcb..b5b13c31 100644 --- a/include/hitag.h +++ b/include/hitag.h @@ -31,6 +31,7 @@ typedef enum { WHT2F_CRYPTO = 24, RHT2F_TEST_AUTH_ATTEMPTS = 25, RHT2F_UID_ONLY = 26, + WHT2F_PASSWORD = 27, } hitag_function; typedef struct { From 1477ba8a3c34f9b7eb624167251efea927755194 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Sat, 24 Aug 2019 15:07:56 +0200 Subject: [PATCH 125/189] iclass.c: speeding up MAC calculation --- armsrc/iclass.c | 2 +- armsrc/optimized_cipher.c | 206 ++++++++++++++++++++++---------------- 2 files changed, 119 insertions(+), 89 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index ee305a26..5d7375a7 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -1146,7 +1146,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { memcpy(data_response, ToSend, ToSendMax); modulated_response = data_response; modulated_response_size = ToSendMax; - response_delay = 0;//We need to hurry here... + response_delay = 0; //We need to hurry here... (but maybe not too much... ??) //exitLoop = true; } else { //Not fullsim, we don't respond // We do not know what to answer, so lets keep quiet diff --git a/armsrc/optimized_cipher.c b/armsrc/optimized_cipher.c index ee9d5568..2ac72ec0 100644 --- a/armsrc/optimized_cipher.c +++ b/armsrc/optimized_cipher.c @@ -60,15 +60,63 @@ -- MHS 2015 **/ +/** + + The runtime of opt_doTagMAC_2() with the MHS optimized version was 403 microseconds on Proxmark3. + This was still to slow for some newer readers which didn't want to wait that long. + + Further optimizations to speedup the MAC calculations: + * Optimized opt_Tt logic + * Look up table for opt_select + * Removing many unnecessary bit maskings (& 0x1) + * updating state in place instead of alternating use of a second state structure + * remove the necessity to reverse bits of input and output bytes + + opt_doTagMAC_2() now completes in 270 microseconds. + + -- piwi 2019 +**/ + #include "optimized_cipher.h" #include #include #include +#include "string.h" +static const uint8_t opt_select_LUT[256] = { + 00, 03, 02, 01, 02, 03, 00, 01, 04, 07, 07, 04, 06, 07, 05, 04, + 01, 02, 03, 00, 02, 03, 00, 01, 05, 06, 06, 05, 06, 07, 05, 04, + 06, 05, 04, 07, 04, 05, 06, 07, 06, 05, 05, 06, 04, 05, 07, 06, + 07, 04, 05, 06, 04, 05, 06, 07, 07, 04, 04, 07, 04, 05, 07, 06, + 06, 05, 04, 07, 04, 05, 06, 07, 02, 01, 01, 02, 00, 01, 03, 02, + 03, 00, 01, 02, 00, 01, 02, 03, 07, 04, 04, 07, 04, 05, 07, 06, + 00, 03, 02, 01, 02, 03, 00, 01, 00, 03, 03, 00, 02, 03, 01, 00, + 05, 06, 07, 04, 06, 07, 04, 05, 05, 06, 06, 05, 06, 07, 05, 04, + 02, 01, 00, 03, 00, 01, 02, 03, 06, 05, 05, 06, 04, 05, 07, 06, + 03, 00, 01, 02, 00, 01, 02, 03, 07, 04, 04, 07, 04, 05, 07, 06, + 02, 01, 00, 03, 00, 01, 02, 03, 02, 01, 01, 02, 00, 01, 03, 02, + 03, 00, 01, 02, 00, 01, 02, 03, 03, 00, 00, 03, 00, 01, 03, 02, + 04, 07, 06, 05, 06, 07, 04, 05, 00, 03, 03, 00, 02, 03, 01, 00, + 01, 02, 03, 00, 02, 03, 00, 01, 05, 06, 06, 05, 06, 07, 05, 04, + 04, 07, 06, 05, 06, 07, 04, 05, 04, 07, 07, 04, 06, 07, 05, 04, + 01, 02, 03, 00, 02, 03, 00, 01, 01, 02, 02, 01, 02, 03, 01, 00 +}; -#define opt_T(s) (0x1 & ((s->t >> 15) ^ (s->t >> 14)^ (s->t >> 10)^ (s->t >> 8)^ (s->t >> 5)^ (s->t >> 4)^ (s->t >> 1)^ s->t)) - -#define opt_B(s) (((s->b >> 6) ^ (s->b >> 5) ^ (s->b >> 4) ^ (s->b)) & 0x1) +/********************** the table above has been generated with this code: ******** +#include "util.h" +static void init_opt_select_LUT(void) { + for (int r = 0; r < 256; r++) { + uint8_t r_ls2 = r << 2; + uint8_t r_and_ls2 = r & r_ls2; + uint8_t r_or_ls2 = r | r_ls2; + uint8_t z0 = (r_and_ls2 >> 5) ^ ((r & ~r_ls2) >> 4) ^ ( r_or_ls2 >> 3); + uint8_t z1 = (r_or_ls2 >> 6) ^ ( r_or_ls2 >> 1) ^ (r >> 5) ^ r; + uint8_t z2 = ((r & ~r_ls2) >> 4) ^ (r_and_ls2 >> 3) ^ r; + opt_select_LUT[r] = (z0 & 4) | (z1 & 2) | (z2 & 1); + } + print_result("", opt_select_LUT, 256); +} +***********************************************************************************/ #define opt__select(x,y,r) (4 & (((r & (r << 2)) >> 5) ^ ((r & ~(r << 2)) >> 4) ^ ( (r | r << 2) >> 3)))\ |(2 & (((r | r << 2) >> 6) ^ ( (r | r << 2) >> 1) ^ (r >> 5) ^ r ^ ((x^y) << 1)))\ @@ -78,9 +126,6 @@ * Some background on the expression above can be found here... uint8_t xopt__select(bool x, bool y, uint8_t r) { - uint8_t r_ls2 = r << 2; - uint8_t r_and_ls2 = r & r_ls2; - uint8_t r_or_ls2 = r | r_ls2; //r: r0 r1 r2 r3 r4 r5 r6 r7 //r_ls2: r2 r3 r4 r5 r6 r7 0 0 @@ -100,81 +145,95 @@ uint8_t xopt__select(bool x, bool y, uint8_t r) } */ -void opt_successor(const uint8_t *k, State *s, bool y, State *successor) { - uint8_t Tt = 1 & opt_T(s); +static void opt_successor(const uint8_t *k, State *s, uint8_t y) { +// #define opt_T(s) (0x1 & ((s->t >> 15) ^ (s->t >> 14) ^ (s->t >> 10) ^ (s->t >> 8) ^ (s->t >> 5) ^ (s->t >> 4)^ (s->t >> 1) ^ s->t)) + // uint8_t Tt = opt_T(s); + uint16_t Tt = s->t & 0xc533; + Tt = Tt ^ (Tt >> 1); + Tt = Tt ^ (Tt >> 4); + Tt = Tt ^ (Tt >> 10); + Tt = Tt ^ (Tt >> 8); - successor->t = (s->t >> 1); - successor->t |= (Tt ^ (s->r >> 7 & 0x1) ^ (s->r >> 3 & 0x1)) << 15; + s->t = (s->t >> 1); + s->t |= (Tt ^ (s->r >> 7) ^ (s->r >> 3)) << 15; - successor->b = s->b >> 1; - successor->b |= (opt_B(s) ^ (s->r & 0x1)) << 7; + uint8_t opt_B = s->b; + opt_B ^= s->b >> 6; + opt_B ^= s->b >> 5; + opt_B ^= s->b >> 4; - successor->r = (k[opt__select(Tt, y, s->r)] ^ successor->b) + s->l ; - successor->l = successor->r + s->r; + s->b = s->b >> 1; + s->b |= (opt_B ^ s->r) << 7; + + uint8_t opt_select = opt_select_LUT[s->r] & 0x04; + opt_select |= (opt_select_LUT[s->r] ^ ((Tt ^ y) << 1)) & 0x02; + opt_select |= (opt_select_LUT[s->r] ^ Tt) & 0x01; + + uint8_t r = s->r; + s->r = (k[opt_select] ^ s->b) + s->l ; + s->l = s->r + r; } -void opt_suc(const uint8_t *k, State *s, uint8_t *in, uint8_t length, bool add32Zeroes) { - State x2; +static void opt_suc(const uint8_t *k, State *s, uint8_t *in, uint8_t length, bool add32Zeroes) { for (int i = 0; i < length; i++) { uint8_t head; - head = 1 & (in[i] >> 7); - opt_successor(k, s, head, &x2); + head = in[i]; + opt_successor(k, s, head); - head = 1 & (in[i] >> 6); - opt_successor(k, &x2, head, s); + head >>= 1; + opt_successor(k, s, head); - head = 1 & (in[i] >> 5); - opt_successor(k, s, head, &x2); + head >>= 1; + opt_successor(k, s, head); - head = 1 & (in[i] >> 4); - opt_successor(k, &x2, head, s); + head >>= 1; + opt_successor(k, s, head); - head = 1 & (in[i] >> 3); - opt_successor(k, s, head, &x2); + head >>= 1; + opt_successor(k, s, head); - head = 1 & (in[i] >> 2); - opt_successor(k, &x2, head, s); + head >>= 1; + opt_successor(k, s, head); - head = 1 & (in[i] >> 1); - opt_successor(k, s, head, &x2); + head >>= 1; + opt_successor(k, s, head); - head = 1 & in[i]; - opt_successor(k, &x2, head, s); + head >>= 1; + opt_successor(k, s, head); } //For tag MAC, an additional 32 zeroes if (add32Zeroes) { for(int i = 0; i < 16; i++) { - opt_successor(k, s, 0, &x2); - opt_successor(k, &x2, 0, s); + opt_successor(k, s, 0); + opt_successor(k, s, 0); } } } -void opt_output(const uint8_t *k, State *s, uint8_t *buffer) { - State temp = {0, 0, 0, 0}; +static void opt_output(const uint8_t *k, State *s, uint8_t *buffer) { for (uint8_t times = 0; times < 4; times++) { uint8_t bout = 0; - bout |= (s->r & 0x4) << 5; - opt_successor(k, s, 0, &temp); - bout |= (temp.r & 0x4) << 4; - opt_successor(k, &temp, 0, s); - bout |= (s->r & 0x4) << 3; - opt_successor(k, s, 0, &temp); - bout |= (temp.r & 0x4) << 2; - opt_successor(k, &temp, 0, s); - bout |= (s->r & 0x4) << 1; - opt_successor(k, s, 0, &temp); - bout |= (temp.r & 0x4) ; - opt_successor(k, &temp, 0, s); + bout |= (s->r & 0x4) >> 2; + opt_successor(k, s, 0); bout |= (s->r & 0x4) >> 1; - opt_successor(k, s, 0, &temp); - bout |= (temp.r & 0x4) >> 2; - opt_successor(k, &temp, 0, s); + opt_successor(k, s, 0); + bout |= (s->r & 0x4); + opt_successor(k, s, 0); + bout |= (s->r & 0x4) << 1; + opt_successor(k, s, 0); + bout |= (s->r & 0x4) << 2; + opt_successor(k, s, 0); + bout |= (s->r & 0x4) << 3; + opt_successor(k, s, 0); + bout |= (s->r & 0x4) << 4; + opt_successor(k, s, 0); + bout |= (s->r & 0x4) << 5; + opt_successor(k, s, 0); buffer[times] = bout; } } -void opt_MAC(uint8_t *k, uint8_t *input, uint8_t *out) { +static void opt_MAC(uint8_t *k, uint8_t *input, uint8_t *out) { State _init = { ((k[0] ^ 0x4c) + 0xEC) & 0xFF,// l ((k[0] ^ 0x4c) + 0x21) & 0xFF,// r @@ -187,43 +246,22 @@ void opt_MAC(uint8_t *k, uint8_t *input, uint8_t *out) { opt_output(k, &_init, out); } -uint8_t rev_byte(uint8_t b) { - b = (b & 0xF0) >> 4 | (b & 0x0F) << 4; - b = (b & 0xCC) >> 2 | (b & 0x33) << 2; - b = (b & 0xAA) >> 1 | (b & 0x55) << 1; - return b; -} - -void opt_reverse_arraybytecpy(uint8_t *dest, uint8_t *src, size_t len) { - for (size_t i = 0; i < len; i++) { - dest[i] = rev_byte(src[i]); - } -} - void opt_doReaderMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4]) { - static uint8_t cc_nr[12]; - opt_reverse_arraybytecpy(cc_nr, cc_nr_p, 12); uint8_t dest[] = {0, 0, 0, 0, 0, 0, 0, 0}; - opt_MAC(div_key_p, cc_nr, dest); - //The output MAC must also be reversed - opt_reverse_arraybytecpy(mac, dest, 4); + opt_MAC(div_key_p, cc_nr_p, dest); + memcpy(mac, dest, 4); return; } void opt_doTagMAC(uint8_t *cc_p, const uint8_t *div_key_p, uint8_t mac[4]) { - static uint8_t cc_nr[8+4+4]; - opt_reverse_arraybytecpy(cc_nr, cc_p, 12); State _init = { ((div_key_p[0] ^ 0x4c) + 0xEC) & 0xFF,// l ((div_key_p[0] ^ 0x4c) + 0x21) & 0xFF,// r 0x4c, // b 0xE012 // t }; - opt_suc(div_key_p, &_init,cc_nr, 12, true); - uint8_t dest[] = {0, 0, 0, 0}; - opt_output(div_key_p, &_init, dest); - //The output MAC must also be reversed - opt_reverse_arraybytecpy(mac, dest, 4); + opt_suc(div_key_p, &_init, cc_p, 12, true); + opt_output(div_key_p, &_init, mac); return; } @@ -236,15 +274,13 @@ void opt_doTagMAC(uint8_t *cc_p, const uint8_t *div_key_p, uint8_t mac[4]) { * @return the cipher state */ State opt_doTagMAC_1(uint8_t *cc_p, const uint8_t *div_key_p) { - static uint8_t cc_nr[8]; - opt_reverse_arraybytecpy(cc_nr, cc_p, 8); State _init = { ((div_key_p[0] ^ 0x4c) + 0xEC) & 0xFF,// l ((div_key_p[0] ^ 0x4c) + 0x21) & 0xFF,// r 0x4c, // b 0xE012 // t }; - opt_suc(div_key_p, &_init, cc_nr, 8, false); + opt_suc(div_key_p, &_init, cc_p, 8, false); return _init; } @@ -258,13 +294,7 @@ State opt_doTagMAC_1(uint8_t *cc_p, const uint8_t *div_key_p) { * @param div_key_p - the key to use */ void opt_doTagMAC_2(State _init, uint8_t *nr, uint8_t mac[4], const uint8_t *div_key_p) { - static uint8_t _nr[4]; - opt_reverse_arraybytecpy(_nr, nr, 4); - opt_suc(div_key_p, &_init, _nr, 4, true); - //opt_suc(div_key_p, &_init,nr, 4, false); - uint8_t dest[] = {0, 0, 0, 0}; - opt_output(div_key_p, &_init, dest); - //The output MAC must also be reversed - opt_reverse_arraybytecpy(mac, dest, 4); + opt_suc(div_key_p, &_init, nr, 4, true); + opt_output(div_key_p, &_init, mac); return; } From deb965b54df637e3170ef365ea7d87443bd72bee Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Sun, 25 Aug 2019 14:03:11 +0200 Subject: [PATCH 126/189] add iclass.h --- armsrc/iclass.h | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 armsrc/iclass.h diff --git a/armsrc/iclass.h b/armsrc/iclass.h new file mode 100644 index 00000000..828792c5 --- /dev/null +++ b/armsrc/iclass.h @@ -0,0 +1,33 @@ +//----------------------------------------------------------------------------- +// Gerhard de Koning Gans - May 2008 +// Hagen Fritsch - June 2010 +// Gerhard de Koning Gans - May 2011 +// Gerhard de Koning Gans - June 2012 - Added iClass card and reader emulation +// +// 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. +//----------------------------------------------------------------------------- +// Routines to support iClass. +//----------------------------------------------------------------------------- + +#ifndef ICLASS_H__ +#define ICLASS_H__ + +#include +#include "common.h" // for RAMFUNC + +extern void RAMFUNC SnoopIClass(void); +extern void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); +extern void ReaderIClass(uint8_t arg0); +extern void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC); +extern void IClass_iso14443A_GetPublic(uint8_t arg0); +extern void iClass_Authentication(uint8_t *MAC); +extern void iClass_WriteBlock(uint8_t blockNo, uint8_t *data); +extern void iClass_ReadBlk(uint8_t blockNo); +extern bool iClass_ReadBlock(uint8_t blockNo, uint8_t *readdata); +extern void iClass_Dump(uint8_t blockno, uint8_t numblks); +extern void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data); +extern void iClass_ReadCheck(uint8_t blockNo, uint8_t keyType); + +#endif From 0ab9002f36f8297c640cf9920c06d106ccae2d70 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Wed, 28 Aug 2019 11:57:53 +0200 Subject: [PATCH 127/189] fix hf iclass sim * sim 2: add responses to read(1) (Config) and read(5) (AIA) * sim 2/3: don't restrict CC to 00 bytes only * sim 3: add responding to read block commands * sim 2/3: add responding to READ_CHECK_KC * fix sizes of pre-encoded tag answers * change default card challenge * remove commented code * use #defines instead of numerical constants for simulation modes * some reformatting --- armsrc/iclass.c | 320 ++++++++++++++++++----------------- client/cmdhficlass.c | 67 +++----- client/loclass/cipher.c | 1 + client/loclass/elite_crack.c | 49 +++--- include/usb_cmd.h | 14 +- 5 files changed, 227 insertions(+), 224 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 5d7375a7..23d407f7 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -391,8 +391,7 @@ static RAMFUNC int ManchesterDecoding(int v) { Demod.shiftReg = 0; Demod.samples = 0; if (Demod.posCount) { - //if (trigger) LED_A_OFF(); // Not useful in this case... - switch(Demod.syncBit) { + switch (Demod.syncBit) { case 0x08: Demod.samples = 3; break; case 0x04: Demod.samples = 2; break; case 0x02: Demod.samples = 1; break; @@ -414,12 +413,13 @@ static RAMFUNC int ManchesterDecoding(int v) { } } else { + // state is DEMOD is in SYNC from here on. modulation = bit & Demod.syncBit; modulation |= ((bit << 1) ^ ((Demod.buffer & 0x08) >> 3)) & Demod.syncBit; Demod.samples += 4; - if (Demod.posCount==0) { + if (Demod.posCount == 0) { Demod.posCount = 1; if (modulation) { Demod.sub = SUB_FIRST_HALF; @@ -428,14 +428,6 @@ static RAMFUNC int ManchesterDecoding(int v) { } } else { Demod.posCount = 0; - /*(modulation && (Demod.sub == SUB_FIRST_HALF)) { - if (Demod.state!=DEMOD_ERROR_WAIT) { - Demod.state = DEMOD_ERROR_WAIT; - Demod.output[Demod.len] = 0xaa; - error = 0x01; - } - }*/ - //else if (modulation) { if (modulation) { if (Demod.sub == SUB_FIRST_HALF) { Demod.sub = SUB_BOTH; @@ -447,23 +439,16 @@ static RAMFUNC int ManchesterDecoding(int v) { Demod.output[Demod.len] = 0x0f; Demod.len++; Demod.state = DEMOD_UNSYNCD; -// error = 0x0f; return true; } else { Demod.state = DEMOD_ERROR_WAIT; error = 0x33; } - /*if (Demod.state!=DEMOD_ERROR_WAIT) { - Demod.state = DEMOD_ERROR_WAIT; - Demod.output[Demod.len] = 0xaa; - error = 0x01; - }*/ } switch(Demod.state) { case DEMOD_START_OF_COMMUNICATION: if (Demod.sub == SUB_BOTH) { - //Demod.state = DEMOD_MANCHESTER_D; Demod.state = DEMOD_START_OF_COMMUNICATION2; Demod.posCount = 1; Demod.sub = SUB_NONE; @@ -484,10 +469,7 @@ static RAMFUNC int ManchesterDecoding(int v) { break; case DEMOD_START_OF_COMMUNICATION3: if (Demod.sub == SUB_SECOND_HALF) { -// Demod.state = DEMOD_MANCHESTER_D; Demod.state = DEMOD_SOF_COMPLETE; - //Demod.output[Demod.len] = Demod.syncBit & 0xFF; - //Demod.len++; } else { Demod.output[Demod.len] = 0xab; Demod.state = DEMOD_ERROR_WAIT; @@ -543,16 +525,6 @@ static RAMFUNC int ManchesterDecoding(int v) { break; } - /*if (Demod.bitCount>=9) { - Demod.output[Demod.len] = Demod.shiftReg & 0xff; - Demod.len++; - - Demod.parityBits <<= 1; - Demod.parityBits ^= ((Demod.shiftReg >> 8) & 0x01); - - Demod.bitCount = 0; - Demod.shiftReg = 0; - }*/ if (Demod.bitCount >= 8) { Demod.shiftReg >>= 1; Demod.output[Demod.len] = (Demod.shiftReg & 0xff); @@ -787,8 +759,7 @@ void rotateCSN(uint8_t* originalCSN, uint8_t* rotatedCSN) { // Stop when button is pressed // Or return true when command is captured //----------------------------------------------------------------------------- -static int GetIClassCommandFromReader(uint8_t *received, int *len, int maxLen) -{ +static int GetIClassCommandFromReader(uint8_t *received, int *len, int maxLen) { // Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen // only, since we are receiving, not transmitting). // Signal field is off with the appropriate LED @@ -825,7 +796,7 @@ static uint8_t encode4Bits(const uint8_t b) { // The columns are // 1 - Bit value to send // 2 - Reversed (big-endian) - // 3 - Encoded + // 3 - Manchester Encoded // 4 - Hex values switch(c){ @@ -935,20 +906,19 @@ static int SendIClassAnswer(uint8_t *resp, int respLen, int delay) { AT91C_BASE_SSC->SSC_THR = 0x00; FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR); - while (!BUTTON_PRESS()) { + while (true) { if ((AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)){ - b = AT91C_BASE_SSC->SSC_RHR; (void) b; + b = AT91C_BASE_SSC->SSC_RHR; + (void) b; } if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)){ b = 0x00; if (d < delay) { + // send 0x00 byte (causing a 2048/13,56MHz = 151us delay) d++; - } - else { + } else { if (i < respLen) { b = resp[i]; - //Hack - //b = 0xAC; } i++; } @@ -957,15 +927,13 @@ static int SendIClassAnswer(uint8_t *resp, int respLen, int delay) { // if (i > respLen +4) break; if (i > respLen + 1) break; + // send 2 more 0x00 bytes (causing a 302us delay) } return 0; } -#define MODE_SIM_CSN 0 -#define MODE_EXIT_AFTER_MAC 1 -#define MODE_FULLSIM 2 /** * @brief Does the actual simulation @@ -973,14 +941,16 @@ static int SendIClassAnswer(uint8_t *resp, int respLen, int delay) { * @param breakAfterMacReceived if true, returns after reader MAC has been received. */ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { + // free eventually allocated BigBuf memory BigBuf_free_keep_EM(); State cipher_state; -// State cipher_state_reserve; - uint8_t *csn = BigBuf_get_EM_addr(); - uint8_t *emulator = csn; - uint8_t sof_data[] = { 0x0F} ; + + uint8_t *emulator = BigBuf_get_EM_addr(); + uint8_t *csn = emulator; + uint8_t sof_data[] = { 0x0F } ; + // CSN followed by two CRC bytes uint8_t anticoll_data[10] = { 0 }; uint8_t csn_data[10] = { 0 }; @@ -991,21 +961,26 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { rotateCSN(csn_data, anticoll_data); // Compute CRC on both CSNs - ComputeCrc14443(CRC_ICLASS, anticoll_data, 8, &anticoll_data[8], &anticoll_data[9]); - ComputeCrc14443(CRC_ICLASS, csn_data, 8, &csn_data[8], &csn_data[9]); + AppendCrc(anticoll_data, 8); + AppendCrc(csn_data, 8); uint8_t diversified_key[8] = { 0 }; // e-Purse - uint8_t card_challenge_data[8] = { 0x00 }; - if (simulationMode == MODE_FULLSIM) { - //The diversified key should be stored on block 3 - //Get the diversified key from emulator memory - memcpy(diversified_key, emulator + (8*3), 8); - //Card challenge, a.k.a e-purse is on block 2 + uint8_t card_challenge_data[8] = { 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + //uint8_t card_challenge_data[8] = { 0 }; + if (simulationMode == ICLASS_SIM_MODE_FULL) { + // The diversified key should be stored on block 3 + // Get the diversified key from emulator memory + memcpy(diversified_key, emulator + (8 * 3), 8); + // Card challenge, a.k.a e-purse is on block 2 memcpy(card_challenge_data, emulator + (8 * 2), 8); - //Precalculate the cipher state, feeding it the CC + // Precalculate the cipher state, feeding it the CC cipher_state = opt_doTagMAC_1(card_challenge_data, diversified_key); } + // save card challenge for sim2,4 attack + if (reader_mac_buf != NULL) { + memcpy(reader_mac_buf, card_challenge_data, 8); + } int exitLoop = 0; // Reader 0a @@ -1026,19 +1001,31 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { // Anticollision CSN (rotated CSN) // 22: Takes 2 bytes for SOF/EOF and 10 * 2 = 20 bytes (2 bytes/byte) - uint8_t *resp_anticoll = BigBuf_malloc(28); + uint8_t *resp_anticoll = BigBuf_malloc(22); int resp_anticoll_len; - // CSN + // CSN (block 0) // 22: Takes 2 bytes for SOF/EOF and 10 * 2 = 20 bytes (2 bytes/byte) - uint8_t *resp_csn = BigBuf_malloc(30); + uint8_t *resp_csn = BigBuf_malloc(22); int resp_csn_len; - // e-Purse + // configuration (block 1) picopass 2ks + uint8_t *resp_conf = BigBuf_malloc(22); + int resp_conf_len; + uint8_t conf_data[10] = {0x12, 0xFF, 0xFF, 0xFF, 0x7F, 0x1F, 0xFF, 0x3C, 0x00, 0x00}; + AppendCrc(conf_data, 8); + + // e-Purse (block 2) // 18: Takes 2 bytes for SOF/EOF and 8 * 2 = 16 bytes (2 bytes/bit) - uint8_t *resp_cc = BigBuf_malloc(20); + uint8_t *resp_cc = BigBuf_malloc(18); int resp_cc_len; + // Application Issuer Area (block 5) + uint8_t *resp_aia = BigBuf_malloc(22); + int resp_aia_len; + uint8_t aia_data[10] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00}; + AppendCrc(aia_data, 8); + uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE); int len; @@ -1055,25 +1042,30 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { memcpy(resp_anticoll, ToSend, ToSendMax); resp_anticoll_len = ToSendMax; - // CSN + // CSN (block 0) CodeIClassTagAnswer(csn_data, sizeof(csn_data)); memcpy(resp_csn, ToSend, ToSendMax); resp_csn_len = ToSendMax; - // e-Purse + // Configuration (block 1) + CodeIClassTagAnswer(conf_data, sizeof(conf_data)); + memcpy(resp_conf, ToSend, ToSendMax); + resp_conf_len = ToSendMax; + + // e-Purse (block 2) CodeIClassTagAnswer(card_challenge_data, sizeof(card_challenge_data)); - memcpy(resp_cc, ToSend, ToSendMax); resp_cc_len = ToSendMax; + memcpy(resp_cc, ToSend, ToSendMax); + resp_cc_len = ToSendMax; + + // Application Issuer Area (block 5) + CodeIClassTagAnswer(aia_data, sizeof(aia_data)); + memcpy(resp_aia, ToSend, ToSendMax); + resp_aia_len = ToSendMax; //This is used for responding to READ-block commands or other data which is dynamically generated - //First the 'trace'-data, not encoded for FPGA - uint8_t *data_generic_trace = BigBuf_malloc(8 + 2);//8 bytes data + 2byte CRC is max tag answer - //Then storage for the modulated data - //Each bit is doubled when modulated for FPGA, and we also have SOF and EOF (2 bytes) - uint8_t *data_response = BigBuf_malloc( (8+2) * 2 + 2); + uint8_t *data_generic_trace = BigBuf_malloc(8 + 2); // 8 bytes data + 2byte CRC is max tag answer + uint8_t *data_response = BigBuf_malloc( (8 + 2) * 2 + 2); - // Start from off (no field generated) - //FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - //SpinDelay(200); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN); SpinDelay(100); StartCountSspClk(); @@ -1081,8 +1073,6 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { SetAdcMuxFor(GPIO_MUXSEL_HIPKD); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_ISO14443A); - // To control where we are in the protocol - int cmdsRecvd = 0; uint32_t time_0 = GetCountSspClk(); uint32_t t2r_time =0; uint32_t r2t_time =0; @@ -1091,6 +1081,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { bool buttonPressed = false; uint8_t response_delay = 1; while (!exitLoop) { + WDT_HIT(); response_delay = 1; LED_B_OFF(); //Signal tracer @@ -1105,41 +1096,95 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { //Signal tracer LED_C_ON(); - // Okay, look at the command now. + // Now look at the reader command and provide appropriate responses + // default is no response: + modulated_response = NULL; + modulated_response_size = 0; + trace_data = NULL; + trace_data_size = 0; if (receivedCmd[0] == ICLASS_CMD_ACTALL) { // Reader in anticollission phase modulated_response = resp_sof; - modulated_response_size = resp_sof_Len; //order = 1; + modulated_response_size = resp_sof_Len; trace_data = sof_data; trace_data_size = sizeof(sof_data); - } else if (receivedCmd[0] == ICLASS_CMD_READ_OR_IDENTIFY && len == 1) { + + } else if (receivedCmd[0] == ICLASS_CMD_READ_OR_IDENTIFY && len == 1) { // identify // Reader asks for anticollission CSN modulated_response = resp_anticoll; - modulated_response_size = resp_anticoll_len; //order = 2; + modulated_response_size = resp_anticoll_len; trace_data = anticoll_data; trace_data_size = sizeof(anticoll_data); //DbpString("Reader requests anticollission CSN:"); + + } else if (receivedCmd[0] == ICLASS_CMD_READ_OR_IDENTIFY && len == 4) { // read block + uint16_t blockNo = receivedCmd[1]; + if (simulationMode != ICLASS_SIM_MODE_FULL) { + // provide defaults for blocks 0, 1, 2, 5 + switch (blockNo) { + case 0: // csn (block 00) + modulated_response = resp_csn; + modulated_response_size = resp_csn_len; + trace_data = csn_data; + trace_data_size = sizeof(csn_data); + break; + case 1: // configuration (block 01) + modulated_response = resp_conf; + modulated_response_size = resp_conf_len; + trace_data = conf_data; + trace_data_size = sizeof(conf_data); + break; + case 2: // e-purse (block 02) + modulated_response = resp_cc; + modulated_response_size = resp_cc_len; + trace_data = card_challenge_data; + trace_data_size = sizeof(card_challenge_data); + // set epurse of sim2,4 attack + if (reader_mac_buf != NULL) { + memcpy(reader_mac_buf, card_challenge_data, 8); + } + break; + case 5: // Application Issuer Area (block 05) + modulated_response = resp_aia; + modulated_response_size = resp_aia_len; + trace_data = aia_data; + trace_data_size = sizeof(aia_data); + break; + // default: don't respond + } + } else { // use data from emulator memory + memcpy(data_generic_trace, emulator + (receivedCmd[1] << 3), 8); + AppendCrc(data_generic_trace, 8); + trace_data = data_generic_trace; + trace_data_size = 10; + CodeIClassTagAnswer(trace_data, trace_data_size); + memcpy(data_response, ToSend, ToSendMax); + modulated_response = data_response; + modulated_response_size = ToSendMax; + } + } else if (receivedCmd[0] == ICLASS_CMD_SELECT) { // Reader selects anticollission CSN. // Tag sends the corresponding real CSN modulated_response = resp_csn; - modulated_response_size = resp_csn_len; //order = 3; + modulated_response_size = resp_csn_len; trace_data = csn_data; trace_data_size = sizeof(csn_data); - //DbpString("Reader selects anticollission CSN:"); - } else if (receivedCmd[0] == ICLASS_CMD_READCHECK_KD) { - // Read e-purse (88 02) + + } else if (receivedCmd[0] == ICLASS_CMD_READCHECK_KD + || receivedCmd[0] == ICLASS_CMD_READCHECK_KC) { + // Read e-purse (88 02 || 18 02) modulated_response = resp_cc; - modulated_response_size = resp_cc_len; //order = 4; + modulated_response_size = resp_cc_len; trace_data = card_challenge_data; trace_data_size = sizeof(card_challenge_data); LED_B_ON(); + } else if (receivedCmd[0] == ICLASS_CMD_CHECK) { // Reader random and reader MAC!!! - if (simulationMode == MODE_FULLSIM) { + if (simulationMode == ICLASS_SIM_MODE_FULL) { //NR, from reader, is in receivedCmd +1 opt_doTagMAC_2(cipher_state, receivedCmd+1, data_generic_trace, diversified_key); - trace_data = data_generic_trace; trace_data_size = 4; CodeIClassTagAnswer(trace_data, trace_data_size); @@ -1148,13 +1193,9 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { modulated_response_size = ToSendMax; response_delay = 0; //We need to hurry here... (but maybe not too much... ??) //exitLoop = true; - } else { //Not fullsim, we don't respond + } else { // Not fullsim, we don't respond // We do not know what to answer, so lets keep quiet - modulated_response = resp_sof; - modulated_response_size = 0; - trace_data = NULL; - trace_data_size = 0; - if (simulationMode == MODE_EXIT_AFTER_MAC) { + if (simulationMode == ICLASS_SIM_MODE_EXIT_AFTER_MAC) { // dbprintf:ing ... Dbprintf("CSN: %02x %02x %02x %02x %02x %02x %02x %02x" ,csn[0],csn[1],csn[2],csn[3],csn[4],csn[5],csn[6],csn[7]); @@ -1163,7 +1204,8 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { receivedCmd[3], receivedCmd[4], receivedCmd[5], receivedCmd[6], receivedCmd[7], receivedCmd[8]); if (reader_mac_buf != NULL) { - memcpy(reader_mac_buf, receivedCmd+1, 8); + // save NR and MAC for sim 2,4 + memcpy(reader_mac_buf + 8, receivedCmd + 1, 8); } exitLoop = true; } @@ -1172,30 +1214,18 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { } else if (receivedCmd[0] == ICLASS_CMD_HALT && len == 1) { // Reader ends the session modulated_response = resp_sof; - modulated_response_size = 0; //order = 0; + modulated_response_size = 0; trace_data = NULL; trace_data_size = 0; - } else if (simulationMode == MODE_FULLSIM && receivedCmd[0] == ICLASS_CMD_READ_OR_IDENTIFY && len == 4) { - //Read block - uint16_t blk = receivedCmd[1]; - //Take the data... - memcpy(data_generic_trace, emulator + (blk << 3), 8); - //Add crc - AppendCrc(data_generic_trace, 8); - trace_data = data_generic_trace; - trace_data_size = 10; - CodeIClassTagAnswer(trace_data, trace_data_size); - memcpy(data_response, ToSend, ToSendMax); - modulated_response = data_response; - modulated_response_size = ToSendMax; - } else if (receivedCmd[0] == ICLASS_CMD_UPDATE && simulationMode == MODE_FULLSIM) { - //Probably the reader wants to update the nonce. Let's just ignore that for now. + + } else if (receivedCmd[0] == ICLASS_CMD_UPDATE && simulationMode == ICLASS_SIM_MODE_FULL) { + // Probably the reader wants to update the nonce. Let's just ignore that for now. // OBS! If this is implemented, don't forget to regenerate the cipher_state - //We're expected to respond with the data+crc, exactly what's already in the receivedcmd - //receivedcmd is now UPDATE 1b | ADDRESS 1b| DATA 8b| Signature 4b or CRC 2b| + // We're expected to respond with the data+crc, exactly what's already in the receivedCmd + // receivedCmd is now UPDATE 1b | ADDRESS 1b | DATA 8b | Signature 4b or CRC 2b //Take the data... - memcpy(data_generic_trace, receivedCmd+2, 8); + memcpy(data_generic_trace, receivedCmd + 2, 8); //Add crc AppendCrc(data_generic_trace, 8); trace_data = data_generic_trace; @@ -1204,35 +1234,23 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { memcpy(data_response, ToSend, ToSendMax); modulated_response = data_response; modulated_response_size = ToSendMax; + } else if (receivedCmd[0] == ICLASS_CMD_PAGESEL) { - //Pagesel - //Pagesel enables to select a page in the selected chip memory and return its configuration block - //Chips with a single page will not answer to this command + // Pagesel + // Pagesel enables to select a page in the selected chip memory and return its configuration block + // Chips with a single page will not answer to this command // It appears we're fine ignoring this. - //Otherwise, we should answer 8bytes (block) + 2bytes CRC + // Otherwise, we should answer 8bytes (block) + 2bytes CRC + } else { //#db# Unknown command received from reader (len=5): 26 1 0 f6 a 44 44 44 44 // Never seen this command before - Dbprintf("Unknown command received from reader (len=%d): %x %x %x %x %x %x %x %x %x", - len, - receivedCmd[0], receivedCmd[1], receivedCmd[2], - receivedCmd[3], receivedCmd[4], receivedCmd[5], - receivedCmd[6], receivedCmd[7], receivedCmd[8]); + print_result("Unhandled command received from reader ", receivedCmd, len); // Do not respond - modulated_response = resp_sof; - modulated_response_size = 0; //order = 0; - trace_data = NULL; - trace_data_size = 0; } - if (cmdsRecvd > 100) { - //DbpString("100 commands later..."); - //break; - } else { - cmdsRecvd++; - } /** - A legit tag has about 380us delay between reader EOT and tag SOF. + A legit tag has about 330us delay between reader EOT and tag SOF. **/ if (modulated_response_size > 0) { SendIClassAnswer(modulated_response, modulated_response_size, response_delay); @@ -1253,7 +1271,6 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { } } - //Dbprintf("%x", cmdsRecvd); LED_A_OFF(); LED_B_OFF(); LED_C_OFF(); @@ -1280,6 +1297,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain) { uint32_t simType = arg0; uint32_t numberOfCSNS = arg1; + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); // Enable and clear the trace @@ -1288,35 +1306,35 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain //Use the emulator memory for SIM uint8_t *emulator = BigBuf_get_EM_addr(); - if (simType == 0) { + if (simType == ICLASS_SIM_MODE_CSN) { // Use the CSN from commandline memcpy(emulator, datain, 8); - doIClassSimulation(MODE_SIM_CSN,NULL); - } else if (simType == 1) { + doIClassSimulation(ICLASS_SIM_MODE_CSN, NULL); + } else if (simType == ICLASS_SIM_MODE_CSN_DEFAULT) { //Default CSN uint8_t csn_crc[] = { 0x03, 0x1f, 0xec, 0x8a, 0xf7, 0xff, 0x12, 0xe0, 0x00, 0x00 }; // Use the CSN from commandline memcpy(emulator, csn_crc, 8); - doIClassSimulation(MODE_SIM_CSN,NULL); - } else if (simType == 2) { + doIClassSimulation(ICLASS_SIM_MODE_CSN, NULL); + } else if (simType == ICLASS_SIM_MODE_READER_ATTACK) { uint8_t mac_responses[USB_CMD_DATA_SIZE] = { 0 }; Dbprintf("Going into attack mode, %d CSNS sent", numberOfCSNS); // In this mode, a number of csns are within datain. We'll simulate each one, one at a time - // in order to collect MAC's from the reader. This can later be used in an offlne-attack + // in order to collect MAC's from the reader. This can later be used in an offline-attack // in order to obtain the keys, as in the "dismantling iclass"-paper. - int i = 0; - for ( ; i < numberOfCSNS && i*8+8 < USB_CMD_DATA_SIZE; i++) { - // The usb data is 512 bytes, fitting 65 8-byte CSNs in there. + int i; + for (i = 0; i < numberOfCSNS && i*16+16 <= USB_CMD_DATA_SIZE; i++) { + // The usb data is 512 bytes, fitting 32 responses (8 byte CC + 4 Byte NR + 4 Byte MAC = 16 Byte response). memcpy(emulator, datain+(i*8), 8); - if (doIClassSimulation(MODE_EXIT_AFTER_MAC,mac_responses+i*8)) { - cmd_send(CMD_ACK, CMD_SIMULATE_TAG_ICLASS, i, 0, mac_responses, i*8); - return; // Button pressed + if (doIClassSimulation(ICLASS_SIM_MODE_EXIT_AFTER_MAC, mac_responses+i*16)) { + // Button pressed + break; } } - cmd_send(CMD_ACK, CMD_SIMULATE_TAG_ICLASS, i, 0, mac_responses, i*8); - } else if (simType == 3) { + cmd_send(CMD_ACK, CMD_SIMULATE_TAG_ICLASS, i, 0, mac_responses, i*16); + } else if (simType == ICLASS_SIM_MODE_FULL) { //This is 'full sim' mode, where we use the emulator storage for data. - doIClassSimulation(MODE_FULLSIM, NULL); + doIClassSimulation(ICLASS_SIM_MODE_FULL, NULL); } else { // We may want a mode here where we hardcode the csns to use (from proxclone). // That will speed things up a little, but not required just yet. @@ -1683,10 +1701,10 @@ void ReaderIClass(uint8_t arg0) { // 0 : CSN // 1 : Configuration // 2 : e-purse - // (3,4 write-only, kc and kd) - // 5 Application issuer area - // - //Then we can 'ship' back the 8 * 6 bytes of data, + // 3 : kd / debit / aa2 (write-only) + // 4 : kc / credit / aa1 (write-only) + // 5 : AIA, Application issuer area + //Then we can 'ship' back the 6 * 8 bytes of data, // with 0xFF:s in block 3 and 4. LED_B_ON(); diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index a2e31754..ee0dd16e 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -110,28 +110,20 @@ int CmdHFiClassSim(const char *Cmd) { } simType = param_get8ex(Cmd, 0, 0, 10); - if(simType == 0) - { + if (simType == ICLASS_SIM_MODE_CSN) { if (param_gethex(Cmd, 1, CSN, 16)) { PrintAndLog("A CSN should consist of 16 HEX symbols"); return usage_hf_iclass_sim(); } - PrintAndLog("--simtype:%02x csn:%s", simType, sprint_hex(CSN, 8)); } - if(simType > 3) - { - PrintAndLog("Undefined simptype %d", simType); - return usage_hf_iclass_sim(); - } - uint8_t numberOfCSNs=0; - if(simType == 2) - { - UsbCommand c = {CMD_SIMULATE_TAG_ICLASS, {simType,NUM_CSNS}}; + uint8_t numberOfCSNs = 0; + if (simType == ICLASS_SIM_MODE_READER_ATTACK) { + UsbCommand c = {CMD_SIMULATE_TAG_ICLASS, {simType, NUM_CSNS}}; UsbCommand resp = {0}; - uint8_t csns[8*NUM_CSNS] = { + uint8_t csns[8 * NUM_CSNS] = { 0x00, 0x0B, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0, 0x00, 0x04, 0x0E, 0x08, 0xF7, 0xFF, 0x12, 0xE0, 0x00, 0x09, 0x0D, 0x05, 0xF7, 0xFF, 0x12, 0xE0, @@ -148,7 +140,7 @@ int CmdHFiClassSim(const char *Cmd) { 0x00, 0x00, 0x02, 0x24, 0xF7, 0xFF, 0x12, 0xE0, 0x00, 0x05, 0x01, 0x21, 0xF7, 0xFF, 0x12, 0xE0 }; - memcpy(c.d.asBytes, csns, 8*NUM_CSNS); + memcpy(c.d.asBytes, csns, 8 * NUM_CSNS); SendCommand(&c); if (!WaitForResponseTimeout(CMD_ACK, &resp, -1)) { @@ -157,9 +149,9 @@ int CmdHFiClassSim(const char *Cmd) { } uint8_t num_mac_responses = resp.arg[1]; - PrintAndLog("Mac responses: %d MACs obtained (should be %d)", num_mac_responses,NUM_CSNS); + PrintAndLog("Mac responses: %d MACs obtained (should be %d)", num_mac_responses, NUM_CSNS); - size_t datalen = NUM_CSNS*24; + size_t datalen = NUM_CSNS * 24; /* * Now, time to dump to file. We'll use this format: * <8-byte CSN><8-byte CC><4 byte NR><4 byte MAC>.... @@ -167,28 +159,29 @@ int CmdHFiClassSim(const char *Cmd) { * 8 * 24 bytes. * * The returndata from the pm3 is on the following format - * <4 byte NR><4 byte MAC> - * CC are all zeroes, CSN is the same as was sent in + * <8 byte CC><4 byte NR><4 byte MAC> + * CSN is the same as was sent in **/ void* dump = malloc(datalen); - memset(dump,0,datalen);//<-- Need zeroes for the CC-field - uint8_t i = 0; - for(i = 0 ; i < NUM_CSNS ; i++) - { - memcpy(dump+i*24, csns+i*8,8); //CSN - //8 zero bytes here... + for(int i = 0; i < NUM_CSNS; i++) { + memcpy(dump + i*24, csns+i*8, 8); //CSN + //copy CC from response + memcpy(dump + i*24 + 8, resp.d.asBytes + i*16, 8); //Then comes NR_MAC (eight bytes from the response) - memcpy(dump+i*24+16,resp.d.asBytes+i*8,8); - + memcpy(dump + i*24 + 16, resp.d.asBytes + i*16 + 8, 8); } /** Now, save to dumpfile **/ saveFile("iclass_mac_attack", "bin", dump,datalen); free(dump); - }else - { - UsbCommand c = {CMD_SIMULATE_TAG_ICLASS, {simType,numberOfCSNs}}; + + } else if (simType == ICLASS_SIM_MODE_CSN || simType == ICLASS_SIM_MODE_CSN_DEFAULT) { + UsbCommand c = {CMD_SIMULATE_TAG_ICLASS, {simType, numberOfCSNs}}; memcpy(c.d.asBytes, CSN, 8); SendCommand(&c); + + } else { + PrintAndLog("Undefined simtype %d", simType); + return usage_hf_iclass_sim(); } return 0; @@ -1265,24 +1258,18 @@ int CmdHFiClass_loclass(const char *Cmd) { return 0; } char fileName[255] = {0}; - if(opt == 'f') - { - if(param_getstr(Cmd, 1, fileName, sizeof(fileName)) > 0) - { + if(opt == 'f') { + if(param_getstr(Cmd, 1, fileName, sizeof(fileName)) > 0) { return bruteforceFileNoKeys(fileName); - }else - { + } else { PrintAndLog("You must specify a filename"); } - } - else if(opt == 't') - { + } else if(opt == 't') { int errors = testCipherUtils(); errors += testMAC(); errors += doKeyTests(0); errors += testElite(); - if(errors) - { + if(errors) { prnlog("OBS! There were errors!!!"); } return errors; diff --git a/client/loclass/cipher.c b/client/loclass/cipher.c index 3b146b10..03275a4f 100644 --- a/client/loclass/cipher.c +++ b/client/loclass/cipher.c @@ -240,6 +240,7 @@ void doMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4]) //free(cc_nr); return; } + void doMAC_N(uint8_t *address_data_p, uint8_t address_data_size, uint8_t *div_key_p, uint8_t mac[4]) { uint8_t *address_data; diff --git a/client/loclass/elite_crack.c b/client/loclass/elite_crack.c index 0cd00830..21a67f54 100644 --- a/client/loclass/elite_crack.c +++ b/client/loclass/elite_crack.c @@ -333,16 +333,14 @@ int bruteforceItem(dumpdata item, uint16_t keytable[]) * Only the lower eight bits correspond to the (hopefully cracked) key-value. **/ uint8_t bytes_to_recover[3] = {0}; - uint8_t numbytes_to_recover = 0 ; - int i; - for(i =0 ; i < 8 ; i++) - { - if(keytable[key_index[i]] & (CRACKED | BEING_CRACKED)) continue; + uint8_t numbytes_to_recover = 0; + + for(int i = 0; i < 8; i++) { + if (keytable[key_index[i]] & (CRACKED | BEING_CRACKED)) continue; bytes_to_recover[numbytes_to_recover++] = key_index[i]; keytable[key_index[i]] |= BEING_CRACKED; - if(numbytes_to_recover > 3) - { + if(numbytes_to_recover > 3) { prnlog("The CSN requires > 3 byte bruteforce, not supported"); printvar("CSN", item.csn,8); printvar("HASH1", key_index,8); @@ -370,15 +368,14 @@ int bruteforceItem(dumpdata item, uint16_t keytable[]) uint32_t endmask = 1 << 8*numbytes_to_recover; - for(i =0 ; i < numbytes_to_recover && numbytes_to_recover > 1; i++) + for (int i = 0; i < numbytes_to_recover && numbytes_to_recover > 1; i++) { prnlog("Bruteforcing byte %d", bytes_to_recover[i]); + } - while(!found && !(brute & endmask)) - { + while(!found && !(brute & endmask)) { //Update the keytable with the brute-values - for(i =0 ; i < numbytes_to_recover; i++) - { + for (int i = 0; i < numbytes_to_recover; i++) { keytable[bytes_to_recover[i]] &= 0xFF00; keytable[bytes_to_recover[i]] |= (brute >> (i*8) & 0xFF); } @@ -394,42 +391,34 @@ int bruteforceItem(dumpdata item, uint16_t keytable[]) //Diversify diversifyKey(item.csn, key_sel_p, div_key); //Calc mac - doMAC(item.cc_nr, div_key,calculated_MAC); + doMAC(item.cc_nr, div_key, calculated_MAC); - if(memcmp(calculated_MAC, item.mac, 4) == 0) - { - for(i =0 ; i < numbytes_to_recover; i++) - prnlog("=> %d: 0x%02x", bytes_to_recover[i],0xFF & keytable[bytes_to_recover[i]]); + if (memcmp(calculated_MAC, item.mac, 4) == 0) { + for (int i =0 ; i < numbytes_to_recover; i++) + prnlog("=> %d: 0x%02x", bytes_to_recover[i], 0xFF & keytable[bytes_to_recover[i]]); found = true; break; } brute++; - if((brute & 0xFFFF) == 0) - { + if ((brute & 0xFFFF) == 0) { printf("%d",(brute >> 16) & 0xFF); fflush(stdout); } } - if(! found) - { + if (! found) { prnlog("Failed to recover %d bytes using the following CSN",numbytes_to_recover); printvar("CSN",item.csn,8); errors++; //Before we exit, reset the 'BEING_CRACKED' to zero - for(i =0 ; i < numbytes_to_recover; i++) - { + for (int i = 0; i < numbytes_to_recover; i++) { keytable[bytes_to_recover[i]] &= 0xFF; keytable[bytes_to_recover[i]] |= CRACK_FAILED; } - - }else - { - for(i =0 ; i < numbytes_to_recover; i++) - { + } else { + for (int i = 0 ;i < numbytes_to_recover; i++) { keytable[bytes_to_recover[i]] &= 0xFF; keytable[bytes_to_recover[i]] |= CRACKED; } - } return errors; } @@ -516,7 +505,7 @@ int bruteforceDump(uint8_t dump[], size_t dumpsize, uint16_t keytable[]) dumpdata* attack = (dumpdata* ) malloc(itemsize); - for(i = 0 ; i * itemsize < dumpsize ; i++ ) + for (i = 0 ; i * itemsize < dumpsize ; i++ ) { memcpy(attack,dump+i*itemsize, itemsize); errors += bruteforceItem(*attack, keytable); diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 1bc5e5ba..934b0924 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -228,7 +228,7 @@ typedef struct{ #define CMD_UNKNOWN 0xFFFF -//Mifare simulation flags +// Mifare simulation flags #define FLAG_INTERACTIVE (1<<0) #define FLAG_4B_UID_IN_DATA (1<<1) #define FLAG_7B_UID_IN_DATA (1<<2) @@ -236,7 +236,7 @@ typedef struct{ #define FLAG_RANDOM_NONCE (1<<5) -//Iclass reader flags +// iCLASS reader flags #define FLAG_ICLASS_READER_ONLY_ONCE 0x01 #define FLAG_ICLASS_READER_CC 0x02 #define FLAG_ICLASS_READER_CSN 0x04 @@ -245,8 +245,16 @@ typedef struct{ #define FLAG_ICLASS_READER_ONE_TRY 0x20 #define FLAG_ICLASS_READER_CEDITKEY 0x40 +// iCLASS simulation modes +#define ICLASS_SIM_MODE_CSN 0 +#define ICLASS_SIM_MODE_CSN_DEFAULT 1 +#define ICLASS_SIM_MODE_READER_ATTACK 2 +#define ICLASS_SIM_MODE_FULL 3 +#define ICLASS_SIM_MODE_READER_ATTACK_KEYROLL 4 +#define ICLASS_SIM_MODE_EXIT_AFTER_MAC 5 // note: device internal only -//hw tune args + +// hw tune args #define FLAG_TUNE_LF 1 #define FLAG_TUNE_HF 2 #define FLAG_TUNE_ALL 3 From 3d2c9c9b066c5a0b6a8dab467d86561223ddac10 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Mon, 2 Sep 2019 11:10:45 +0200 Subject: [PATCH 128/189] fix 'hf iclass sim' * fix debug print on unhandled commands * deduplicate: use sim functions from iso15693.c * fix times in tracelog and 'hf list iclass' (sim only) * don't check parity in 'hf list iclass' * fix timing in TransmitTo15693Reader() --- armsrc/iclass.c | 254 ++++++----------------------------------- armsrc/iso15693.c | 199 ++++++++++++++++++-------------- armsrc/iso15693.h | 20 +++- client/cmdhflist.c | 52 +++++---- common/iso15693tools.h | 6 +- 5 files changed, 204 insertions(+), 327 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 23d407f7..daa44256 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -42,9 +42,11 @@ #include "apps.h" #include "util.h" #include "string.h" +#include "printf.h" #include "common.h" #include "cmd.h" #include "iso14443a.h" +#include "iso15693.h" // Needed for CRC in emulation mode; // same construction as in ISO 14443; // different initial value (CRC_ICLASS) @@ -754,132 +756,7 @@ void rotateCSN(uint8_t* originalCSN, uint8_t* rotatedCSN) { } } -//----------------------------------------------------------------------------- -// Wait for commands from reader -// Stop when button is pressed -// Or return true when command is captured -//----------------------------------------------------------------------------- -static int GetIClassCommandFromReader(uint8_t *received, int *len, int maxLen) { - // Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen - // only, since we are receiving, not transmitting). - // Signal field is off with the appropriate LED - LED_D_OFF(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN); - - // Now run a `software UART' on the stream of incoming samples. - Uart.output = received; - Uart.byteCntMax = maxLen; - Uart.state = STATE_UNSYNCD; - - for (;;) { - WDT_HIT(); - - if (BUTTON_PRESS()) return false; - - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0x00; - } - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - - if (OutOfNDecoding(b & 0x0f)) { - *len = Uart.byteCnt; - return true; - } - } - } -} - -static uint8_t encode4Bits(const uint8_t b) { - uint8_t c = b & 0xF; - // OTA, the least significant bits first - // The columns are - // 1 - Bit value to send - // 2 - Reversed (big-endian) - // 3 - Manchester Encoded - // 4 - Hex values - - switch(c){ - // 1 2 3 4 - case 15: return 0x55; // 1111 -> 1111 -> 01010101 -> 0x55 - case 14: return 0x95; // 1110 -> 0111 -> 10010101 -> 0x95 - case 13: return 0x65; // 1101 -> 1011 -> 01100101 -> 0x65 - case 12: return 0xa5; // 1100 -> 0011 -> 10100101 -> 0xa5 - case 11: return 0x59; // 1011 -> 1101 -> 01011001 -> 0x59 - case 10: return 0x99; // 1010 -> 0101 -> 10011001 -> 0x99 - case 9: return 0x69; // 1001 -> 1001 -> 01101001 -> 0x69 - case 8: return 0xa9; // 1000 -> 0001 -> 10101001 -> 0xa9 - case 7: return 0x56; // 0111 -> 1110 -> 01010110 -> 0x56 - case 6: return 0x96; // 0110 -> 0110 -> 10010110 -> 0x96 - case 5: return 0x66; // 0101 -> 1010 -> 01100110 -> 0x66 - case 4: return 0xa6; // 0100 -> 0010 -> 10100110 -> 0xa6 - case 3: return 0x5a; // 0011 -> 1100 -> 01011010 -> 0x5a - case 2: return 0x9a; // 0010 -> 0100 -> 10011010 -> 0x9a - case 1: return 0x6a; // 0001 -> 1000 -> 01101010 -> 0x6a - default: return 0xaa; // 0000 -> 0000 -> 10101010 -> 0xaa - - } -} - -//----------------------------------------------------------------------------- -// Prepare tag messages -//----------------------------------------------------------------------------- -static void CodeIClassTagAnswer(const uint8_t *cmd, int len) { - - /* - * SOF comprises 3 parts; - * * An unmodulated time of 56.64 us - * * 24 pulses of 423.75 kHz (fc/32) - * * A logic 1, which starts with an unmodulated time of 18.88us - * followed by 8 pulses of 423.75kHz (fc/32) - * - * - * EOF comprises 3 parts: - * - A logic 0 (which starts with 8 pulses of fc/32 followed by an unmodulated - * time of 18.88us. - * - 24 pulses of fc/32 - * - An unmodulated time of 56.64 us - * - * - * A logic 0 starts with 8 pulses of fc/32 - * followed by an unmodulated time of 256/fc (~18,88us). - * - * A logic 0 starts with unmodulated time of 256/fc (~18,88us) followed by - * 8 pulses of fc/32 (also 18.88us) - * - * The mode FPGA_HF_SIMULATOR_MODULATE_424K_8BIT which we use to simulate tag, - * works like this. - * - A 1-bit input to the FPGA becomes 8 pulses on 423.5kHz (fc/32) (18.88us). - * - A 0-bit input to the FPGA becomes an unmodulated time of 18.88us - * - * In this mode the SOF can be written as 00011101 = 0x1D - * The EOF can be written as 10111000 = 0xb8 - * A logic 1 is 01 - * A logic 0 is 10 - * - * */ - - int i; - - ToSendReset(); - - // Send SOF - ToSend[++ToSendMax] = 0x1D; - - for (i = 0; i < len; i++) { - uint8_t b = cmd[i]; - ToSend[++ToSendMax] = encode4Bits(b & 0xF); // Least significant half - ToSend[++ToSendMax] = encode4Bits((b >>4) & 0xF); // Most significant half - } - - // Send EOF - ToSend[++ToSendMax] = 0xB8; - //lastProxToAirDuration = 8*ToSendMax - 3*8 - 3*8;//Not counting zeroes in the beginning or end - // Convert from last byte pos to length - ToSendMax++; -} - -// Only SOF +// Encode SOF only static void CodeIClassTagSOF() { //So far a dummy implementation, not used //int lastProxToAirDuration =0; @@ -897,43 +774,6 @@ static void AppendCrc(uint8_t *data, int len) { ComputeCrc14443(CRC_ICLASS, data, len, data+len, data+len+1); } -static int SendIClassAnswer(uint8_t *resp, int respLen, int delay) { - int i = 0, d = 0;//, u = 0, d = 0; - uint8_t b = 0; - - //FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR|FPGA_HF_SIMULATOR_MODULATE_424K); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_424K_8BIT); - - AT91C_BASE_SSC->SSC_THR = 0x00; - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR); - while (true) { - if ((AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)){ - b = AT91C_BASE_SSC->SSC_RHR; - (void) b; - } - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)){ - b = 0x00; - if (d < delay) { - // send 0x00 byte (causing a 2048/13,56MHz = 151us delay) - d++; - } else { - if (i < respLen) { - b = resp[i]; - } - i++; - } - AT91C_BASE_SSC->SSC_THR = b; - } - -// if (i > respLen +4) break; - if (i > respLen + 1) break; - // send 2 more 0x00 bytes (causing a 302us delay) - } - - return 0; -} - - /** * @brief Does the actual simulation @@ -1032,33 +872,33 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { // Prepare card messages ToSendMax = 0; - // First card answer: SOF + // First card answer: SOF only CodeIClassTagSOF(); memcpy(resp_sof, ToSend, ToSendMax); resp_sof_Len = ToSendMax; // Anticollision CSN - CodeIClassTagAnswer(anticoll_data, sizeof(anticoll_data)); + CodeIso15693AsTag(anticoll_data, sizeof(anticoll_data)); memcpy(resp_anticoll, ToSend, ToSendMax); resp_anticoll_len = ToSendMax; // CSN (block 0) - CodeIClassTagAnswer(csn_data, sizeof(csn_data)); + CodeIso15693AsTag(csn_data, sizeof(csn_data)); memcpy(resp_csn, ToSend, ToSendMax); resp_csn_len = ToSendMax; // Configuration (block 1) - CodeIClassTagAnswer(conf_data, sizeof(conf_data)); + CodeIso15693AsTag(conf_data, sizeof(conf_data)); memcpy(resp_conf, ToSend, ToSendMax); resp_conf_len = ToSendMax; // e-Purse (block 2) - CodeIClassTagAnswer(card_challenge_data, sizeof(card_challenge_data)); + CodeIso15693AsTag(card_challenge_data, sizeof(card_challenge_data)); memcpy(resp_cc, ToSend, ToSendMax); resp_cc_len = ToSendMax; // Application Issuer Area (block 5) - CodeIClassTagAnswer(aia_data, sizeof(aia_data)); + CodeIso15693AsTag(aia_data, sizeof(aia_data)); memcpy(resp_aia, ToSend, ToSendMax); resp_aia_len = ToSendMax; @@ -1066,33 +906,22 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { uint8_t *data_generic_trace = BigBuf_malloc(8 + 2); // 8 bytes data + 2byte CRC is max tag answer uint8_t *data_response = BigBuf_malloc( (8 + 2) * 2 + 2); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN); - SpinDelay(100); - StartCountSspClk(); - // We need to listen to the high-frequency, peak-detected path. - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_ISO14443A); - - uint32_t time_0 = GetCountSspClk(); - uint32_t t2r_time =0; - uint32_t r2t_time =0; - LED_A_ON(); bool buttonPressed = false; - uint8_t response_delay = 1; while (!exitLoop) { WDT_HIT(); - response_delay = 1; LED_B_OFF(); //Signal tracer // Can be used to get a trigger for an oscilloscope.. LED_C_OFF(); - if (!GetIClassCommandFromReader(receivedCmd, &len, 100)) { + uint32_t reader_eof_time = 0; + len = GetIso15693CommandFromReader(receivedCmd, MAX_FRAME_SIZE, &reader_eof_time); + if (len < 0) { buttonPressed = true; break; } - r2t_time = GetCountSspClk(); + //Signal tracer LED_C_ON(); @@ -1116,7 +945,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { trace_data = anticoll_data; trace_data_size = sizeof(anticoll_data); //DbpString("Reader requests anticollission CSN:"); - + } else if (receivedCmd[0] == ICLASS_CMD_READ_OR_IDENTIFY && len == 4) { // read block uint16_t blockNo = receivedCmd[1]; if (simulationMode != ICLASS_SIM_MODE_FULL) { @@ -1157,7 +986,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { AppendCrc(data_generic_trace, 8); trace_data = data_generic_trace; trace_data_size = 10; - CodeIClassTagAnswer(trace_data, trace_data_size); + CodeIso15693AsTag(trace_data, trace_data_size); memcpy(data_response, ToSend, ToSendMax); modulated_response = data_response; modulated_response_size = ToSendMax; @@ -1183,26 +1012,18 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { } else if (receivedCmd[0] == ICLASS_CMD_CHECK) { // Reader random and reader MAC!!! if (simulationMode == ICLASS_SIM_MODE_FULL) { - //NR, from reader, is in receivedCmd +1 + //NR, from reader, is in receivedCmd+1 opt_doTagMAC_2(cipher_state, receivedCmd+1, data_generic_trace, diversified_key); trace_data = data_generic_trace; trace_data_size = 4; - CodeIClassTagAnswer(trace_data, trace_data_size); + CodeIso15693AsTag(trace_data, trace_data_size); memcpy(data_response, ToSend, ToSendMax); modulated_response = data_response; modulated_response_size = ToSendMax; - response_delay = 0; //We need to hurry here... (but maybe not too much... ??) //exitLoop = true; } else { // Not fullsim, we don't respond // We do not know what to answer, so lets keep quiet if (simulationMode == ICLASS_SIM_MODE_EXIT_AFTER_MAC) { - // dbprintf:ing ... - Dbprintf("CSN: %02x %02x %02x %02x %02x %02x %02x %02x" - ,csn[0],csn[1],csn[2],csn[3],csn[4],csn[5],csn[6],csn[7]); - Dbprintf("RDR: (len=%02d): %02x %02x %02x %02x %02x %02x %02x %02x %02x",len, - receivedCmd[0], receivedCmd[1], receivedCmd[2], - receivedCmd[3], receivedCmd[4], receivedCmd[5], - receivedCmd[6], receivedCmd[7], receivedCmd[8]); if (reader_mac_buf != NULL) { // save NR and MAC for sim 2,4 memcpy(reader_mac_buf + 8, receivedCmd + 1, 8); @@ -1223,14 +1044,11 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { // OBS! If this is implemented, don't forget to regenerate the cipher_state // We're expected to respond with the data+crc, exactly what's already in the receivedCmd // receivedCmd is now UPDATE 1b | ADDRESS 1b | DATA 8b | Signature 4b or CRC 2b - - //Take the data... memcpy(data_generic_trace, receivedCmd + 2, 8); - //Add crc AppendCrc(data_generic_trace, 8); trace_data = data_generic_trace; trace_data_size = 10; - CodeIClassTagAnswer(trace_data, trace_data_size); + CodeIso15693AsTag(trace_data, trace_data_size); memcpy(data_response, ToSend, ToSendMax); modulated_response = data_response; modulated_response_size = ToSendMax; @@ -1243,9 +1061,13 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { // Otherwise, we should answer 8bytes (block) + 2bytes CRC } else { - //#db# Unknown command received from reader (len=5): 26 1 0 f6 a 44 44 44 44 // Never seen this command before - print_result("Unhandled command received from reader ", receivedCmd, len); + char debug_message[250]; // should be enough + sprintf(debug_message, "Unhandled command (len = %d) received from reader:", len); + for (int i = 0; i < len && strlen(debug_message) < sizeof(debug_message) - 3 - 1; i++) { + sprintf(debug_message + strlen(debug_message), " %02x", receivedCmd[i]); + } + Dbprintf("%s", debug_message); // Do not respond } @@ -1253,22 +1075,11 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { A legit tag has about 330us delay between reader EOT and tag SOF. **/ if (modulated_response_size > 0) { - SendIClassAnswer(modulated_response, modulated_response_size, response_delay); - t2r_time = GetCountSspClk(); + uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM - DELAY_ARM_TO_READER_SIM; + TransmitTo15693Reader(modulated_response, modulated_response_size, response_time, false); + LogTrace(trace_data, trace_data_size, response_time + DELAY_ARM_TO_READER_SIM, response_time + (modulated_response_size << 6) + DELAY_ARM_TO_READER_SIM, NULL, false); } - uint8_t parity[MAX_PARITY_SIZE]; - GetParity(receivedCmd, len, parity); - LogTrace(receivedCmd, len, (r2t_time-time_0) << 4, (r2t_time-time_0) << 4, parity, true); - - if (trace_data != NULL) { - GetParity(trace_data, trace_data_size, parity); - LogTrace(trace_data, trace_data_size, (t2r_time-time_0) << 4, (t2r_time-time_0) << 4, parity, false); - } - if (!get_tracing()) { - DbpString("Trace full"); - //break; - } } LED_A_OFF(); @@ -1298,7 +1109,12 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain uint32_t simType = arg0; uint32_t numberOfCSNS = arg1; + // setup hardware for simulation: FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION); + FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR); + StartCountSspClk(); // Enable and clear the trace set_tracing(true); @@ -1330,6 +1146,12 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain // Button pressed break; } + Dbprintf("CSN: %02x %02x %02x %02x %02x %02x %02x %02x", + datain[i*8+0], datain[i*8+1], datain[i*8+2], datain[i*8+3], + datain[i*8+4], datain[i*8+5], datain[i*8+6], datain[i*8+7]); + Dbprintf("NR,MAC: %02x %02x %02x %02x %02x %02x %02x %02x", + datain[i*8+ 8], datain[i*8+ 9], datain[i*8+10], datain[i*8+11], + datain[i*8+12], datain[i*8+13], datain[i*8+14], datain[i*8+15]); } cmd_send(CMD_ACK, CMD_SIMULATE_TAG_ICLASS, i, 0, mac_responses, i*16); } else if (simType == ICLASS_SIM_MODE_FULL) { diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index f4120512..7fdf2a35 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -68,27 +68,14 @@ static int DEBUG = 0; /////////////////////////////////////////////////////////////////////// // ISO 15693 Part 2 - Air Interface -// This section basicly contains transmission and receiving of bits +// This section basically contains transmission and receiving of bits /////////////////////////////////////////////////////////////////////// -#define Crc(data,datalen) Iso15693Crc(data,datalen) -#define AddCrc(data,datalen) Iso15693AddCrc(data,datalen) -#define sprintUID(target,uid) Iso15693sprintUID(target,uid) - // buffers -#define ISO15693_DMA_BUFFER_SIZE 2048 // must be a power of 2 +#define ISO15693_DMA_BUFFER_SIZE 2048 // must be a power of 2 #define ISO15693_MAX_RESPONSE_LENGTH 36 // allows read single block with the maximum block size of 256bits. Read multiple blocks not supported yet #define ISO15693_MAX_COMMAND_LENGTH 45 // allows write single block with the maximum block size of 256bits. Write multiple blocks not supported yet -// timing. Delays in SSP_CLK ticks. -// SSP_CLK runs at 13,56MHz / 32 = 423.75kHz when simulating a tag -#define DELAY_READER_TO_ARM_SIM 8 -#define DELAY_ARM_TO_READER_SIM 1 -#define DELAY_ISO15693_VCD_TO_VICC_SIM 132 // 132/423.75kHz = 311.5us from end of command EOF to start of tag response -//SSP_CLK runs at 13.56MHz / 4 = 3,39MHz when acting as reader -#define DELAY_ISO15693_VCD_TO_VICC_READER 1056 // 1056/3,39MHz = 311.5us from end of command EOF to start of tag response -#define DELAY_ISO15693_VICC_TO_VCD_READER 1017 // 1017/3.39MHz = 300us between end of tag response and next reader command - // --------------------------- // Signal Processing // --------------------------- @@ -228,22 +215,72 @@ static void CodeIso15693AsReader256(uint8_t *cmd, int n) } -static void CodeIso15693AsTag(uint8_t *cmd, int n) -{ +// static uint8_t encode4Bits(const uint8_t b) { + // uint8_t c = b & 0xF; + // // OTA, the least significant bits first + // // The columns are + // // 1 - Bit value to send + // // 2 - Reversed (big-endian) + // // 3 - Manchester Encoded + // // 4 - Hex values + + // switch(c){ + // // 1 2 3 4 + // case 15: return 0x55; // 1111 -> 1111 -> 01010101 -> 0x55 + // case 14: return 0x95; // 1110 -> 0111 -> 10010101 -> 0x95 + // case 13: return 0x65; // 1101 -> 1011 -> 01100101 -> 0x65 + // case 12: return 0xa5; // 1100 -> 0011 -> 10100101 -> 0xa5 + // case 11: return 0x59; // 1011 -> 1101 -> 01011001 -> 0x59 + // case 10: return 0x99; // 1010 -> 0101 -> 10011001 -> 0x99 + // case 9: return 0x69; // 1001 -> 1001 -> 01101001 -> 0x69 + // case 8: return 0xa9; // 1000 -> 0001 -> 10101001 -> 0xa9 + // case 7: return 0x56; // 0111 -> 1110 -> 01010110 -> 0x56 + // case 6: return 0x96; // 0110 -> 0110 -> 10010110 -> 0x96 + // case 5: return 0x66; // 0101 -> 1010 -> 01100110 -> 0x66 + // case 4: return 0xa6; // 0100 -> 0010 -> 10100110 -> 0xa6 + // case 3: return 0x5a; // 0011 -> 1100 -> 01011010 -> 0x5a + // case 2: return 0x9a; // 0010 -> 0100 -> 10011010 -> 0x9a + // case 1: return 0x6a; // 0001 -> 1000 -> 01101010 -> 0x6a + // default: return 0xaa; // 0000 -> 0000 -> 10101010 -> 0xaa + + // } +// } + +void CodeIso15693AsTag(uint8_t *cmd, size_t len) { + /* + * SOF comprises 3 parts; + * * An unmodulated time of 56.64 us + * * 24 pulses of 423.75 kHz (fc/32) + * * A logic 1, which starts with an unmodulated time of 18.88us + * followed by 8 pulses of 423.75kHz (fc/32) + * + * EOF comprises 3 parts: + * - A logic 0 (which starts with 8 pulses of fc/32 followed by an unmodulated + * time of 18.88us. + * - 24 pulses of fc/32 + * - An unmodulated time of 56.64 us + * + * A logic 0 starts with 8 pulses of fc/32 + * followed by an unmodulated time of 256/fc (~18,88us). + * + * A logic 0 starts with unmodulated time of 256/fc (~18,88us) followed by + * 8 pulses of fc/32 (also 18.88us) + * + * A bit here becomes 8 pulses of fc/32. Therefore: + * The SOF can be written as 00011101 = 0x1D + * The EOF can be written as 10111000 = 0xb8 + * A logic 1 is 01 + * A logic 0 is 10 + * + * */ + ToSendReset(); // SOF - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(0); - ToSendStuffBit(1); + ToSend[++ToSendMax] = 0x1D; // 00011101 // data - for(int i = 0; i < n; i++) { + for(int i = 0; i < len; i++) { for(int j = 0; j < 8; j++) { if ((cmd[i] >> j) & 0x01) { ToSendStuffBit(0); @@ -256,14 +293,7 @@ static void CodeIso15693AsTag(uint8_t *cmd, int n) } // EOF - ToSendStuffBit(1); - ToSendStuffBit(0); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(0); - ToSendStuffBit(0); - ToSendStuffBit(0); + ToSend[++ToSendMax] = 0xB8; // 10111000 ToSendMax++; } @@ -297,41 +327,41 @@ static void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t start_time) //----------------------------------------------------------------------------- // Transmit the tag response (to the reader) that was placed in cmd[]. //----------------------------------------------------------------------------- -static void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t start_time, bool slow) -{ +void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t start_time, bool slow) { // don't use the FPGA_HF_SIMULATOR_MODULATE_424K_8BIT minor mode. It would spoil GetCountSspClk() FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_424K); uint8_t shift_delay = start_time & 0x00000007; - uint8_t bitmask = 0x00; - for (int i = 0; i < shift_delay; i++) { - bitmask |= (0x01 << i); - } while (GetCountSspClk() < (start_time & 0xfffffff8)) ; - AT91C_BASE_SSC->SSC_THR = 0x00; // clear TXRDY - LED_C_ON(); uint8_t bits_to_shift = 0x00; - for(size_t c = 0; c <= len; c++) { - uint8_t bits_to_send = bits_to_shift << (8 - shift_delay) | (c==len?0x00:cmd[c]) >> shift_delay; - bits_to_shift = cmd[c] & bitmask; + uint8_t bits_to_send = 0x00; + for(size_t c = 0; c < len; c++) { for (int i = 7; i >= 0; i--) { + uint8_t cmd_bits = ((cmd[c] >> i) & 0x01) ? 0xff : 0x00; for (int j = 0; j < (slow?4:1); ) { + bits_to_send = bits_to_shift << (8 - shift_delay) | cmd_bits >> shift_delay; + bits_to_shift = cmd_bits; if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { - if (bits_to_send >> i & 0x01) { - AT91C_BASE_SSC->SSC_THR = 0xff; - } else { - AT91C_BASE_SSC->SSC_THR = 0x00; - } + AT91C_BASE_SSC->SSC_THR = bits_to_send; j++; } - WDT_HIT(); } } + WDT_HIT(); } + // send the remaining bits, padded with 0: + bits_to_send = bits_to_shift << (8 - shift_delay); + for ( ; ; ) { + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { + AT91C_BASE_SSC->SSC_THR = bits_to_send; + break; + } + } LED_C_OFF(); + } @@ -682,9 +712,9 @@ static void DecodeReaderReset(DecodeReader_t* DecodeReader) static int inline __attribute__((always_inline)) Handle15693SampleFromReader(uint8_t bit, DecodeReader_t *restrict DecodeReader) { - switch(DecodeReader->state) { + switch (DecodeReader->state) { case STATE_READER_UNSYNCD: - if(!bit) { + if (!bit) { // we went low, so this could be the beginning of a SOF DecodeReader->posCount = 1; DecodeReader->state = STATE_READER_AWAIT_1ST_RISING_EDGE_OF_SOF; @@ -693,14 +723,14 @@ static int inline __attribute__((always_inline)) Handle15693SampleFromReader(uin case STATE_READER_AWAIT_1ST_RISING_EDGE_OF_SOF: DecodeReader->posCount++; - if(bit) { // detected rising edge - if(DecodeReader->posCount < 4) { // rising edge too early (nominally expected at 5) + if (bit) { // detected rising edge + if (DecodeReader->posCount < 4) { // rising edge too early (nominally expected at 5) DecodeReaderReset(DecodeReader); } else { // SOF DecodeReader->state = STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF; } } else { - if(DecodeReader->posCount > 5) { // stayed low for too long + if (DecodeReader->posCount > 5) { // stayed low for too long DecodeReaderReset(DecodeReader); } else { // do nothing, keep waiting @@ -710,7 +740,7 @@ static int inline __attribute__((always_inline)) Handle15693SampleFromReader(uin case STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF: DecodeReader->posCount++; - if(!bit) { // detected a falling edge + if (!bit) { // detected a falling edge if (DecodeReader->posCount < 20) { // falling edge too early (nominally expected at 21 earliest) DecodeReaderReset(DecodeReader); } else if (DecodeReader->posCount < 23) { // SOF for 1 out of 4 coding @@ -723,7 +753,7 @@ static int inline __attribute__((always_inline)) Handle15693SampleFromReader(uin DecodeReader->state = STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF; } } else { - if(DecodeReader->posCount > 29) { // stayed high for too long + if (DecodeReader->posCount > 29) { // stayed high for too long DecodeReaderReset(DecodeReader); } else { // do nothing, keep waiting @@ -881,19 +911,18 @@ static int inline __attribute__((always_inline)) Handle15693SampleFromReader(uin // Receive a command (from the reader to us, where we are the simulated tag), // and store it in the given buffer, up to the given maximum length. Keeps // spinning, waiting for a well-framed command, until either we get one -// (returns true) or someone presses the pushbutton on the board (false). +// (returns len) or someone presses the pushbutton on the board (returns -1). // // Assume that we're called with the SSC (to the FPGA) and ADC path set // correctly. //----------------------------------------------------------------------------- -static int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eof_time) -{ +int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eof_time) { int samples = 0; bool gotFrame = false; uint8_t b; - uint8_t *dmaBuf = BigBuf_malloc(ISO15693_DMA_BUFFER_SIZE); + uint8_t dmaBuf[ISO15693_DMA_BUFFER_SIZE]; // the decoder data structure DecodeReader_t DecodeReader = {0}; @@ -910,21 +939,21 @@ static int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint3 (void) temp; while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)) ; - uint32_t bit_time = GetCountSspClk() & 0xfffffff8; + uint32_t dma_start_time = GetCountSspClk() & 0xfffffff8; // Setup and start DMA. FpgaSetupSscDma(dmaBuf, ISO15693_DMA_BUFFER_SIZE); uint8_t *upTo = dmaBuf; - for(;;) { + for (;;) { uint16_t behindBy = ((uint8_t*)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (ISO15693_DMA_BUFFER_SIZE-1); if (behindBy == 0) continue; b = *upTo++; - if(upTo >= dmaBuf + ISO15693_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. + if (upTo >= dmaBuf + ISO15693_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. upTo = dmaBuf; // start reading the circular buffer from the beginning - if(behindBy > (9*ISO15693_DMA_BUFFER_SIZE/10)) { + if (behindBy > (9*ISO15693_DMA_BUFFER_SIZE/10)) { Dbprintf("About to blow circular buffer - aborted! behindBy=%d", behindBy); break; } @@ -936,7 +965,7 @@ static int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint3 for (int i = 7; i >= 0; i--) { if (Handle15693SampleFromReader((b >> i) & 0x01, &DecodeReader)) { - *eof_time = bit_time + samples - DELAY_READER_TO_ARM_SIM; // end of EOF + *eof_time = dma_start_time + samples - DELAY_READER_TO_ARM_SIM; // end of EOF gotFrame = true; break; } @@ -948,22 +977,24 @@ static int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint3 } if (BUTTON_PRESS()) { - DecodeReader.byteCount = 0; + DecodeReader.byteCount = -1; break; } WDT_HIT(); } - FpgaDisableSscDma(); - BigBuf_free_keep_EM(); if (DEBUG) Dbprintf("samples = %d, gotFrame = %d, Decoder: state = %d, len = %d, bitCount = %d, posCount = %d", samples, gotFrame, DecodeReader.state, DecodeReader.byteCount, DecodeReader.bitCount, DecodeReader.posCount); if (DecodeReader.byteCount > 0) { - LogTrace(DecodeReader.output, DecodeReader.byteCount, 0, *eof_time, NULL, true); + uint32_t sof_time = *eof_time + - DecodeReader.byteCount * (DecodeReader.Coding==CODING_1_OUT_OF_4?128:2048) // time for byte transfers + - 32 // time for SOF transfer + - 16; // time for EOF transfer + LogTrace(DecodeReader.output, DecodeReader.byteCount, sof_time, *eof_time, NULL, true); } return DecodeReader.byteCount; @@ -985,7 +1016,7 @@ static void BuildIdentifyRequest(void) // no mask cmd[2] = 0x00; //Now the CRC - crc = Crc(cmd, 3); + crc = Iso15693Crc(cmd, 3); cmd[3] = crc & 0xff; cmd[4] = crc >> 8; @@ -1219,7 +1250,7 @@ static void BuildReadBlockRequest(uint8_t *uid, uint8_t blockNumber ) // Block number to read cmd[10] = blockNumber; //Now the CRC - crc = Crc(cmd, 11); // the crc needs to be calculated over 11 bytes + crc = Iso15693Crc(cmd, 11); // the crc needs to be calculated over 11 bytes cmd[11] = crc & 0xff; cmd[12] = crc >> 8; @@ -1246,7 +1277,7 @@ static void BuildInventoryResponse(uint8_t *uid) cmd[8] = uid[1]; //0x05; cmd[9] = uid[0]; //0xe0; //Now the CRC - crc = Crc(cmd, 10); + crc = Iso15693Crc(cmd, 10); cmd[10] = crc & 0xff; cmd[11] = crc >> 8; @@ -1341,7 +1372,7 @@ void DbdecodeIso15693Answer(int len, uint8_t *d) { strncat(status,"NoErr ", DBD15STATLEN); } - crc=Crc(d,len-2); + crc=Iso15693Crc(d,len-2); if ( (( crc & 0xff ) == d[len-2]) && (( crc >> 8 ) == d[len-1]) ) strncat(status,"CrcOK",DBD15STATLEN); else @@ -1526,12 +1557,12 @@ void BruteforceIso15693Afi(uint32_t speed) data[0] = ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_INVENTORY | ISO15693_REQINV_SLOT1; data[1] = ISO15693_INVENTORY; data[2] = 0; // mask length - datalen = AddCrc(data,3); + datalen = Iso15693AddCrc(data,3); recvlen = SendDataTag(data, datalen, false, speed, recv, sizeof(recv), 0); uint32_t start_time = GetCountSspClk() + DELAY_ISO15693_VICC_TO_VCD_READER; WDT_HIT(); if (recvlen>=12) { - Dbprintf("NoAFI UID=%s", sprintUID(NULL, &recv[2])); + Dbprintf("NoAFI UID=%s", Iso15693sprintUID(NULL, &recv[2])); } // now with AFI @@ -1543,12 +1574,12 @@ void BruteforceIso15693Afi(uint32_t speed) for (int i = 0; i < 256; i++) { data[2] = i & 0xFF; - datalen = AddCrc(data,4); + datalen = Iso15693AddCrc(data,4); recvlen = SendDataTag(data, datalen, false, speed, recv, sizeof(recv), start_time); start_time = GetCountSspClk() + DELAY_ISO15693_VICC_TO_VCD_READER; WDT_HIT(); if (recvlen >= 12) { - Dbprintf("AFI=%i UID=%s", i, sprintUID(NULL, &recv[2])); + Dbprintf("AFI=%i UID=%s", i, Iso15693sprintUID(NULL, &recv[2])); } } Dbprintf("AFI Bruteforcing done."); @@ -1646,7 +1677,7 @@ void SetTag15693Uid(uint8_t *uid) for (int i=0; i<4; i++) { // Add the CRC - crc = Crc(cmd[i], 7); + crc = Iso15693Crc(cmd[i], 7); cmd[i][7] = crc & 0xff; cmd[i][8] = crc >> 8; @@ -1702,7 +1733,7 @@ static void __attribute__((unused)) BuildSysInfoRequest(uint8_t *uid) cmd[8] = 0x05; cmd[9]= 0xe0; // always e0 (not exactly unique) //Now the CRC - crc = Crc(cmd, 10); // the crc needs to be calculated over 2 bytes + crc = Iso15693Crc(cmd, 10); // the crc needs to be calculated over 2 bytes cmd[10] = crc & 0xff; cmd[11] = crc >> 8; @@ -1737,7 +1768,7 @@ static void __attribute__((unused)) BuildReadMultiBlockRequest(uint8_t *uid) // Number of Blocks to read cmd[11] = 0x2f; // read quite a few //Now the CRC - crc = Crc(cmd, 12); // the crc needs to be calculated over 2 bytes + crc = Iso15693Crc(cmd, 12); // the crc needs to be calculated over 2 bytes cmd[12] = crc & 0xff; cmd[13] = crc >> 8; @@ -1772,7 +1803,7 @@ static void __attribute__((unused)) BuildArbitraryRequest(uint8_t *uid,uint8_t C // cmd[12] = 0x00; // cmd[13] = 0x00; //Now the CRC - crc = Crc(cmd, 12); // the crc needs to be calculated over 2 bytes + crc = Iso15693Crc(cmd, 12); // the crc needs to be calculated over 2 bytes cmd[12] = crc & 0xff; cmd[13] = crc >> 8; @@ -1807,7 +1838,7 @@ static void __attribute__((unused)) BuildArbitraryCustomRequest(uint8_t uid[], u // cmd[12] = 0x00; // cmd[13] = 0x00; //Now the CRC - crc = Crc(cmd, 12); // the crc needs to be calculated over 2 bytes + crc = Iso15693Crc(cmd, 12); // the crc needs to be calculated over 2 bytes cmd[12] = crc & 0xff; cmd[13] = crc >> 8; diff --git a/armsrc/iso15693.h b/armsrc/iso15693.h index 68df2693..f6cf29f1 100644 --- a/armsrc/iso15693.h +++ b/armsrc/iso15693.h @@ -8,17 +8,31 @@ // Routines to support ISO 15693. //----------------------------------------------------------------------------- -#ifndef __ISO15693_H -#define __ISO15693_H +#ifndef ISO15693_H__ +#define ISO15693_H__ #include +#include +#include +// Delays in SSP_CLK ticks. +// SSP_CLK runs at 13,56MHz / 32 = 423.75kHz when simulating a tag +#define DELAY_READER_TO_ARM_SIM 8 +#define DELAY_ARM_TO_READER_SIM 1 +#define DELAY_ISO15693_VCD_TO_VICC_SIM 132 // 132/423.75kHz = 311.5us from end of command EOF to start of tag response +//SSP_CLK runs at 13.56MHz / 4 = 3,39MHz when acting as reader +#define DELAY_ISO15693_VCD_TO_VICC_READER 1056 // 1056/3,39MHz = 311.5us from end of command EOF to start of tag response +#define DELAY_ISO15693_VICC_TO_VCD_READER 1017 // 1017/3.39MHz = 300us between end of tag response and next reader command + +void CodeIso15693AsTag(uint8_t *cmd, size_t len); +int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eof_time); +void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t start_time, bool slow); void SnoopIso15693(void); void AcquireRawAdcSamplesIso15693(void); void ReaderIso15693(uint32_t parameter); void SimTagIso15693(uint32_t parameter, uint8_t *uid); void BruteforceIso15693Afi(uint32_t speed); -void DirectTag15693Command(uint32_t datalen,uint32_t speed, uint32_t recv, uint8_t data[]); +void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint8_t data[]); void SetTag15693Uid(uint8_t *uid); void SetDebugIso15693(uint32_t flag); diff --git a/client/cmdhflist.c b/client/cmdhflist.c index 5384bfce..1b8e0955 100644 --- a/client/cmdhflist.c +++ b/client/cmdhflist.c @@ -213,30 +213,29 @@ uint8_t iclass_CRC_check(bool isResponse, uint8_t* data, uint8_t len) } -void annotateIclass(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) -{ +void annotateIclass(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) { switch(cmd[0]) { - case ICLASS_CMD_ACTALL: snprintf(exp,size,"ACTALL"); break; - case ICLASS_CMD_READ_OR_IDENTIFY:{ - if(cmdsize > 1){ + case ICLASS_CMD_ACTALL: snprintf(exp, size, "ACTALL"); break; + case ICLASS_CMD_READ_OR_IDENTIFY: { + if (cmdsize > 1){ snprintf(exp,size,"READ(%d)",cmd[1]); - }else{ + } else { snprintf(exp,size,"IDENTIFY"); } break; } - case ICLASS_CMD_SELECT: snprintf(exp,size,"SELECT"); break; - case ICLASS_CMD_PAGESEL: snprintf(exp,size,"PAGESEL(%d)", cmd[1]); break; - case ICLASS_CMD_READCHECK_KC:snprintf(exp,size,"READCHECK[Kc](%d)", cmd[1]); break; - case ICLASS_CMD_READCHECK_KD:snprintf(exp,size,"READCHECK[Kd](%d)", cmd[1]); break; - case ICLASS_CMD_CHECK: snprintf(exp,size,"CHECK"); break; - case ICLASS_CMD_DETECT: snprintf(exp,size,"DETECT"); break; - case ICLASS_CMD_HALT: snprintf(exp,size,"HALT"); break; - case ICLASS_CMD_UPDATE: snprintf(exp,size,"UPDATE(%d)",cmd[1]); break; - case ICLASS_CMD_ACT: snprintf(exp,size,"ACT"); break; - case ICLASS_CMD_READ4: snprintf(exp,size,"READ4(%d)",cmd[1]); break; - default: snprintf(exp,size,"?"); break; + case ICLASS_CMD_SELECT: snprintf(exp,size, "SELECT"); break; + case ICLASS_CMD_PAGESEL: snprintf(exp,size, "PAGESEL(%d)", cmd[1]); break; + case ICLASS_CMD_READCHECK_KC:snprintf(exp,size, "READCHECK[Kc](%d)", cmd[1]); break; + case ICLASS_CMD_READCHECK_KD:snprintf(exp,size, "READCHECK[Kd](%d)", cmd[1]); break; + case ICLASS_CMD_CHECK: snprintf(exp,size, "CHECK"); break; + case ICLASS_CMD_DETECT: snprintf(exp,size, "DETECT"); break; + case ICLASS_CMD_HALT: snprintf(exp,size, "HALT"); break; + case ICLASS_CMD_UPDATE: snprintf(exp,size, "UPDATE(%d)",cmd[1]); break; + case ICLASS_CMD_ACT: snprintf(exp,size, "ACT"); break; + case ICLASS_CMD_READ4: snprintf(exp,size, "READ4(%d)",cmd[1]); break; + default: snprintf(exp,size, "?"); break; } return; } @@ -901,6 +900,13 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui } } + // adjust for different time scales + if (protocol == ICLASS || protocol == ISO_15693) { + first_timestamp *= 32; + timestamp *= 32; + duration *= 32; + } + //Check the CRC status uint8_t crcStatus = 2; @@ -940,6 +946,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui uint8_t parityBits = parityBytes[j>>3]; if (protocol != ISO_14443B && protocol != ISO_15693 + && protocol != ICLASS && protocol != ISO_7816_4 && (isResponse || protocol == ISO_14443A) && (oddparity8(frame[j]) != ((parityBits >> (7-(j&0x0007))) & 0x01))) { @@ -950,8 +957,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui } if (markCRCBytes) { - if(crcStatus == 0 || crcStatus == 1) - {//CRC-command + if (crcStatus == 0 || crcStatus == 1) { //CRC-command char *pos1 = line[(data_len-2)/16]+(((data_len-2) % 16) * 4); (*pos1) = '['; char *pos2 = line[(data_len)/16]+(((data_len) % 16) * 4); @@ -978,8 +984,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui if (protocol == PROTO_MIFARE) annotateMifare(explanation, sizeof(explanation), frame, data_len, parityBytes, parity_len, isResponse); - if(!isResponse) - { + if (!isResponse) { switch(protocol) { case ICLASS: annotateIclass(explanation,sizeof(explanation),frame,data_len); break; case ISO_14443A: annotateIso14443a(explanation,sizeof(explanation),frame,data_len); break; @@ -1027,6 +1032,11 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui if (showWaitCycles && !isResponse && next_record_is_response(tracepos, trace)) { uint32_t next_timestamp = *((uint32_t *)(trace + tracepos)); + // adjust for different time scales + if (protocol == ICLASS || protocol == ISO_15693) { + next_timestamp *= 32; + } + PrintAndLog(" %10d | %10d | %s | fdt (Frame Delay Time): %d", (EndOfTransmissionTimestamp - first_timestamp), (next_timestamp - first_timestamp), diff --git a/common/iso15693tools.h b/common/iso15693tools.h index d9f59cc6..ceb6393e 100644 --- a/common/iso15693tools.h +++ b/common/iso15693tools.h @@ -1,8 +1,8 @@ // ISO15693 commons // Adrian Dabrowski 2010 and others, GPLv2 -#ifndef ISO15693_H__ -#define ISO15693_H__ +#ifndef ISO15693TOOLS_H__ +#define ISO15693TOOLS_H__ // ISO15693 CRC #define ISO15693_CRC_PRESET (uint16_t)0xFFFF @@ -11,7 +11,7 @@ uint16_t Iso15693Crc(uint8_t *v, int n); int Iso15693AddCrc(uint8_t *req, int n); -char* Iso15693sprintUID(char *target,uint8_t *uid); +char* Iso15693sprintUID(char *target, uint8_t *uid); unsigned short iclass_crc16(char *data_p, unsigned short length); #endif From a66f26da182040ac798a7c629d255cb86803e9c2 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Tue, 10 Sep 2019 18:18:54 +0200 Subject: [PATCH 129/189] fix 'hf iclass sim': * add simulation of block 3 and 4 reads * add simulation of READ4 (4 blocks read) * fixing TransmitTo15693Reader() (again) * FPGA change (hi_simulate.v): avoid spp_clk phase changes * some whitespace fixes --- armsrc/iclass.c | 85 +++++++++++++----- armsrc/iso15693.c | 216 ++++++++++++++++++++++----------------------- armsrc/iso15693.h | 2 +- fpga/fpga_hf.bit | Bin 42175 -> 42175 bytes fpga/hi_simulate.v | 54 ++++++------ 5 files changed, 198 insertions(+), 159 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index daa44256..66238a10 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -860,6 +860,12 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { uint8_t *resp_cc = BigBuf_malloc(18); int resp_cc_len; + // Kd, Kc (blocks 3 and 4). Cannot be read. Always respond with 0xff bytes only + uint8_t *resp_ff = BigBuf_malloc(22); + int resp_ff_len; + uint8_t ff_data[10] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00}; + AppendCrc(ff_data, 8); + // Application Issuer Area (block 5) uint8_t *resp_aia = BigBuf_malloc(22); int resp_aia_len; @@ -897,14 +903,19 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { memcpy(resp_cc, ToSend, ToSendMax); resp_cc_len = ToSendMax; + // Kd, Kc (blocks 3 and 4) + CodeIso15693AsTag(ff_data, sizeof(ff_data)); + memcpy(resp_ff, ToSend, ToSendMax); + resp_ff_len = ToSendMax; + // Application Issuer Area (block 5) CodeIso15693AsTag(aia_data, sizeof(aia_data)); memcpy(resp_aia, ToSend, ToSendMax); resp_aia_len = ToSendMax; //This is used for responding to READ-block commands or other data which is dynamically generated - uint8_t *data_generic_trace = BigBuf_malloc(8 + 2); // 8 bytes data + 2byte CRC is max tag answer - uint8_t *data_response = BigBuf_malloc( (8 + 2) * 2 + 2); + uint8_t *data_generic_trace = BigBuf_malloc(32 + 2); // 32 bytes data + 2byte CRC is max tag answer + uint8_t *data_response = BigBuf_malloc( (32 + 2) * 2 + 2); LED_A_ON(); bool buttonPressed = false; @@ -921,7 +932,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { buttonPressed = true; break; } - + //Signal tracer LED_C_ON(); @@ -931,6 +942,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { modulated_response_size = 0; trace_data = NULL; trace_data_size = 0; + if (receivedCmd[0] == ICLASS_CMD_ACTALL) { // Reader in anticollission phase modulated_response = resp_sof; @@ -944,12 +956,11 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { modulated_response_size = resp_anticoll_len; trace_data = anticoll_data; trace_data_size = sizeof(anticoll_data); - //DbpString("Reader requests anticollission CSN:"); - + } else if (receivedCmd[0] == ICLASS_CMD_READ_OR_IDENTIFY && len == 4) { // read block uint16_t blockNo = receivedCmd[1]; - if (simulationMode != ICLASS_SIM_MODE_FULL) { - // provide defaults for blocks 0, 1, 2, 5 + if (simulationMode == ICLASS_SIM_MODE_EXIT_AFTER_MAC) { + // provide defaults for blocks 0 ... 5 switch (blockNo) { case 0: // csn (block 00) modulated_response = resp_csn; @@ -973,6 +984,13 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { memcpy(reader_mac_buf, card_challenge_data, 8); } break; + case 3: + case 4: // Kd, Kd, always respond with 0xff bytes + modulated_response = resp_ff; + modulated_response_size = resp_ff_len; + trace_data = ff_data; + trace_data_size = sizeof(ff_data); + break; case 5: // Application Issuer Area (block 05) modulated_response = resp_aia; modulated_response_size = resp_aia_len; @@ -981,15 +999,22 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { break; // default: don't respond } - } else { // use data from emulator memory - memcpy(data_generic_trace, emulator + (receivedCmd[1] << 3), 8); - AppendCrc(data_generic_trace, 8); - trace_data = data_generic_trace; - trace_data_size = 10; - CodeIso15693AsTag(trace_data, trace_data_size); - memcpy(data_response, ToSend, ToSendMax); - modulated_response = data_response; - modulated_response_size = ToSendMax; + } else if (simulationMode == ICLASS_SIM_MODE_FULL) { + if (blockNo == 3 || blockNo == 4) { // Kd, Kc, always respond with 0xff bytes + modulated_response = resp_ff; + modulated_response_size = resp_ff_len; + trace_data = ff_data; + trace_data_size = sizeof(ff_data); + } else { // use data from emulator memory + memcpy(data_generic_trace, emulator + (receivedCmd[1] << 3), 8); + AppendCrc(data_generic_trace, 8); + trace_data = data_generic_trace; + trace_data_size = 10; + CodeIso15693AsTag(trace_data, trace_data_size); + memcpy(data_response, ToSend, ToSendMax); + modulated_response = data_response; + modulated_response_size = ToSendMax; + } } } else if (receivedCmd[0] == ICLASS_CMD_SELECT) { @@ -1039,6 +1064,18 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { trace_data = NULL; trace_data_size = 0; + } else if (simulationMode == ICLASS_SIM_MODE_FULL && receivedCmd[0] == ICLASS_CMD_READ4 && len == 4) { // 0x06 + //Read block + //Take the data... + memcpy(data_generic_trace, emulator + (receivedCmd[1] << 3), 8 * 4); + AppendCrc(data_generic_trace, 8 * 4); + trace_data = data_generic_trace; + trace_data_size = 8 * 4 + 2; + CodeIso15693AsTag(trace_data, trace_data_size); + memcpy(data_response, ToSend, ToSendMax); + modulated_response = data_response; + modulated_response_size = ToSendMax; + } else if (receivedCmd[0] == ICLASS_CMD_UPDATE && simulationMode == ICLASS_SIM_MODE_FULL) { // Probably the reader wants to update the nonce. Let's just ignore that for now. // OBS! If this is implemented, don't forget to regenerate the cipher_state @@ -1072,7 +1109,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { } /** - A legit tag has about 330us delay between reader EOT and tag SOF. + A legit tag has about 311,5us delay between reader EOT and tag SOF. **/ if (modulated_response_size > 0) { uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM - DELAY_ARM_TO_READER_SIM; @@ -1112,7 +1149,7 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain // setup hardware for simulation: FpgaDownloadAndGo(FPGA_BITSTREAM_HF); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR); StartCountSspClk(); @@ -1150,8 +1187,8 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain datain[i*8+0], datain[i*8+1], datain[i*8+2], datain[i*8+3], datain[i*8+4], datain[i*8+5], datain[i*8+6], datain[i*8+7]); Dbprintf("NR,MAC: %02x %02x %02x %02x %02x %02x %02x %02x", - datain[i*8+ 8], datain[i*8+ 9], datain[i*8+10], datain[i*8+11], - datain[i*8+12], datain[i*8+13], datain[i*8+14], datain[i*8+15]); + datain[i*8+ 8], datain[i*8+ 9], datain[i*8+10], datain[i*8+11], + datain[i*8+12], datain[i*8+13], datain[i*8+14], datain[i*8+15]); } cmd_send(CMD_ACK, CMD_SIMULATE_TAG_ICLASS, i, 0, mac_responses, i*16); } else if (simType == ICLASS_SIM_MODE_FULL) { @@ -1319,10 +1356,10 @@ static int GetIClassAnswer(uint8_t *receivedResponse, int maxLen, int *samples, if (elapsed) (*elapsed)++; } if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - if (c < timeout) { - c++; - } else { - return false; + if (c < timeout) { + c++; + } else { + return false; } b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; skip = !skip; diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 7fdf2a35..4b4577e7 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -2,7 +2,7 @@ // Jonathan Westhues, split Nov 2006 // Modified by Greg Jones, Jan 2009 // Modified by Adrian Dabrowski "atrox", Mar-Sept 2010,Oct 2011 -// Modified by piwi, Oct 2018 +// Modified by piwi, Oct 2018 // // 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 @@ -16,26 +16,26 @@ // transmission modes from tag to reader. As of Oct 2018 this code supports // both reader modes and the high speed variant with one subcarrier from card to reader. // As long as the card fully support ISO 15693 this is no problem, since the -// reader chooses both data rates, but some non-standard tags do not. +// reader chooses both data rates, but some non-standard tags do not. // For card simulation, the code supports both high and low speed modes with one subcarrier. // // VCD (reader) -> VICC (tag) // 1 out of 256: -// data rate: 1,66 kbit/s (fc/8192) -// used for long range +// data rate: 1,66 kbit/s (fc/8192) +// used for long range // 1 out of 4: -// data rate: 26,48 kbit/s (fc/512) -// used for short range, high speed +// data rate: 26,48 kbit/s (fc/512) +// used for short range, high speed // // VICC (tag) -> VCD (reader) // Modulation: -// ASK / one subcarrier (423,75 khz) -// FSK / two subcarriers (423,75 khz && 484,28 khz) +// ASK / one subcarrier (423,75 khz) +// FSK / two subcarriers (423,75 khz && 484,28 khz) // Data Rates / Modes: -// low ASK: 6,62 kbit/s -// low FSK: 6.67 kbit/s -// high ASK: 26,48 kbit/s -// high FSK: 26,69 kbit/s +// low ASK: 6,62 kbit/s +// low FSK: 6.67 kbit/s +// high ASK: 26,48 kbit/s +// high FSK: 26,69 kbit/s //----------------------------------------------------------------------------- @@ -161,7 +161,7 @@ static void CodeIso15693AsReader(uint8_t *cmd, int n) for(i = 0; i < 4; i++) { ToSendStuffBit(1); } - + ToSendMax++; } @@ -338,20 +338,20 @@ void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t start_time, LED_C_ON(); uint8_t bits_to_shift = 0x00; uint8_t bits_to_send = 0x00; - for(size_t c = 0; c < len; c++) { + for(size_t c = 0; c < len; c++) { for (int i = 7; i >= 0; i--) { uint8_t cmd_bits = ((cmd[c] >> i) & 0x01) ? 0xff : 0x00; for (int j = 0; j < (slow?4:1); ) { - bits_to_send = bits_to_shift << (8 - shift_delay) | cmd_bits >> shift_delay; - bits_to_shift = cmd_bits; if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { + bits_to_send = bits_to_shift << (8 - shift_delay) | cmd_bits >> shift_delay; AT91C_BASE_SSC->SSC_THR = bits_to_send; + bits_to_shift = cmd_bits; j++; } } - } + } WDT_HIT(); - } + } // send the remaining bits, padded with 0: bits_to_send = bits_to_shift << (8 - shift_delay); for ( ; ; ) { @@ -408,7 +408,7 @@ typedef struct DecodeTag { static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint16_t amplitude, DecodeTag_t *DecodeTag) { switch(DecodeTag->state) { - case STATE_TAG_SOF_LOW: + case STATE_TAG_SOF_LOW: // waiting for 12 times low (11 times low is accepted as well) if (amplitude < NOISE_THRESHOLD) { DecodeTag->posCount++; @@ -422,7 +422,7 @@ static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint1 } } break; - + case STATE_TAG_SOF_HIGH: // waiting for 10 times high. Take average over the last 8 if (amplitude > NOISE_THRESHOLD) { @@ -592,7 +592,7 @@ static int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, int tim bool gotFrame = false; uint16_t *dmaBuf = (uint16_t*)BigBuf_malloc(ISO15693_DMA_BUFFER_SIZE*sizeof(uint16_t)); - + // the Decoder data structure DecodeTag_t DecodeTag = { 0 }; DecodeTagInit(&DecodeTag, response, max_len); @@ -643,9 +643,9 @@ static int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, int tim FpgaDisableSscDma(); BigBuf_free(); - + if (DEBUG) Dbprintf("samples = %d, gotFrame = %d, Decoder: state = %d, len = %d, bitCount = %d, posCount = %d", - samples, gotFrame, DecodeTag.state, DecodeTag.len, DecodeTag.bitCount, DecodeTag.posCount); + samples, gotFrame, DecodeTag.state, DecodeTag.len, DecodeTag.bitCount, DecodeTag.posCount); if (DecodeTag.len > 0) { LogTrace(DecodeTag.output, DecodeTag.len, 0, 0, NULL, false); @@ -687,7 +687,7 @@ typedef struct DecodeReader { int byteCount; int byteCountMax; int posCount; - int sum1, sum2; + int sum1, sum2; uint8_t *output; } DecodeReader_t; @@ -985,12 +985,12 @@ int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eo } FpgaDisableSscDma(); - + if (DEBUG) Dbprintf("samples = %d, gotFrame = %d, Decoder: state = %d, len = %d, bitCount = %d, posCount = %d", - samples, gotFrame, DecodeReader.state, DecodeReader.byteCount, DecodeReader.bitCount, DecodeReader.posCount); + samples, gotFrame, DecodeReader.state, DecodeReader.byteCount, DecodeReader.bitCount, DecodeReader.posCount); if (DecodeReader.byteCount > 0) { - uint32_t sof_time = *eof_time + uint32_t sof_time = *eof_time - DecodeReader.byteCount * (DecodeReader.Coding==CODING_1_OUT_OF_4?128:2048) // time for byte transfers - 32 // time for SOF transfer - 16; // time for EOF transfer @@ -1101,7 +1101,7 @@ void SnoopIso15693(void) Dbprintf(" DMA: %i bytes", ISO15693_DMA_BUFFER_SIZE * sizeof(uint16_t)); } Dbprintf("Snoop started. Press PM3 Button to stop."); - + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SNOOP_AMPLITUDE); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); @@ -1139,7 +1139,7 @@ void SnoopIso15693(void) } } samples++; - + if (!TagIsActive) { // no need to try decoding reader data if the tag is sending if (Handle15693SampleFromReader(snoopdata & 0x02, &DecodeReader)) { FpgaDisableSscDma(); @@ -1168,7 +1168,7 @@ void SnoopIso15693(void) ReaderIsActive = (DecodeReader.state >= STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF); } - if (!ReaderIsActive && ExpectTagAnswer) { // no need to try decoding tag data if the reader is currently sending or no answer expected yet + if (!ReaderIsActive && ExpectTagAnswer) { // no need to try decoding tag data if the reader is currently sending or no answer expected yet if (Handle15693SamplesFromTag(snoopdata >> 2, &DecodeTag)) { FpgaDisableSscDma(); //Use samples as a time measurement @@ -1187,7 +1187,7 @@ void SnoopIso15693(void) FpgaDisableSscDma(); BigBuf_free(); - + LEDsoff(); DbpString("Snoop statistics:"); @@ -1234,7 +1234,7 @@ static void BuildReadBlockRequest(uint8_t *uid, uint8_t blockNumber ) uint16_t crc; // If we set the Option_Flag in this request, the VICC will respond with the security status of the block // followed by the block data - cmd[0] = ISO15693_REQ_OPTION | ISO15693_REQ_ADDRESS | ISO15693_REQ_DATARATE_HIGH; + cmd[0] = ISO15693_REQ_OPTION | ISO15693_REQ_ADDRESS | ISO15693_REQ_DATARATE_HIGH; // READ BLOCK command code cmd[1] = ISO15693_READBLOCK; // UID may be optionally specified here @@ -1285,10 +1285,10 @@ static void BuildInventoryResponse(uint8_t *uid) } // Universal Method for sending to and recv bytes from a tag -// init ... should we initialize the reader? -// speed ... 0 low speed, 1 hi speed -// *recv will contain the tag's answer -// return: lenght of received data +// init ... should we initialize the reader? +// speed ... 0 low speed, 1 hi speed +// *recv will contain the tag's answer +// return: lenght of received data int SendDataTag(uint8_t *send, int sendlen, bool init, int speed, uint8_t *recv, uint16_t max_recv_len, uint32_t start_time) { LED_A_ON(); @@ -1405,7 +1405,7 @@ void ReaderIso15693(uint32_t parameter) LED_A_ON(); set_tracing(true); - + int answerLen = 0; uint8_t TagUID[8] = {0x00}; @@ -1418,8 +1418,8 @@ void ReaderIso15693(uint32_t parameter) FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); // Start from off (no field generated) - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(200); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); // Give the tags time to energize LED_D_ON(); @@ -1434,7 +1434,7 @@ void ReaderIso15693(uint32_t parameter) // Now send the IDENTIFY command BuildIdentifyRequest(); TransmitTo15693Tag(ToSend, ToSendMax, 0); - + // Now wait for a response answerLen = GetIso15693AnswerFromTag(answer, sizeof(answer), DELAY_ISO15693_VCD_TO_VICC_READER * 2) ; uint32_t start_time = GetCountSspClk() + DELAY_ISO15693_VICC_TO_VCD_READER; @@ -1489,7 +1489,7 @@ void ReaderIso15693(uint32_t parameter) // for the time being, switch field off to protect rdv4.0 // note: this prevents using hf 15 cmd with s option - which isn't implemented yet anyway - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_D_OFF(); LED_A_OFF(); @@ -1506,7 +1506,7 @@ void SimTagIso15693(uint32_t parameter, uint8_t *uid) FpgaDownloadAndGo(FPGA_BITSTREAM_HF); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR); StartCountSspClk(); @@ -1531,7 +1531,7 @@ void SimTagIso15693(uint32_t parameter, uint8_t *uid) Dbhexdump(cmd_len, cmd, false); } - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); } @@ -1545,12 +1545,12 @@ void BruteforceIso15693Afi(uint32_t speed) uint8_t data[6]; uint8_t recv[ISO15693_MAX_RESPONSE_LENGTH]; - + int datalen=0, recvlen=0; Iso15693InitReader(); StartCountSspClk(); - + // first without AFI // Tags should respond without AFI and with AFI=0 even when AFI is active @@ -1584,7 +1584,7 @@ void BruteforceIso15693Afi(uint32_t speed) } Dbprintf("AFI Bruteforcing done."); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); } @@ -1616,7 +1616,7 @@ void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint // for the time being, switch field off to protect rdv4.0 // note: this prevents using hf 15 cmd with s option - which isn't implemented yet anyway - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_D_OFF(); LED_A_OFF(); @@ -1630,76 +1630,76 @@ void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint // Set the UID to the tag (based on Iceman work). void SetTag15693Uid(uint8_t *uid) { - uint8_t cmd[4][9] = {0x00}; + uint8_t cmd[4][9] = {0x00}; - uint16_t crc; + uint16_t crc; - int recvlen = 0; - uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; + int recvlen = 0; + uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; - LED_A_ON(); + LED_A_ON(); - // Command 1 : 02213E00000000 - cmd[0][0] = 0x02; - cmd[0][1] = 0x21; - cmd[0][2] = 0x3e; - cmd[0][3] = 0x00; - cmd[0][4] = 0x00; - cmd[0][5] = 0x00; - cmd[0][6] = 0x00; + // Command 1 : 02213E00000000 + cmd[0][0] = 0x02; + cmd[0][1] = 0x21; + cmd[0][2] = 0x3e; + cmd[0][3] = 0x00; + cmd[0][4] = 0x00; + cmd[0][5] = 0x00; + cmd[0][6] = 0x00; - // Command 2 : 02213F69960000 - cmd[1][0] = 0x02; - cmd[1][1] = 0x21; - cmd[1][2] = 0x3f; - cmd[1][3] = 0x69; - cmd[1][4] = 0x96; - cmd[1][5] = 0x00; - cmd[1][6] = 0x00; + // Command 2 : 02213F69960000 + cmd[1][0] = 0x02; + cmd[1][1] = 0x21; + cmd[1][2] = 0x3f; + cmd[1][3] = 0x69; + cmd[1][4] = 0x96; + cmd[1][5] = 0x00; + cmd[1][6] = 0x00; - // Command 3 : 022138u8u7u6u5 (where uX = uid byte X) - cmd[2][0] = 0x02; - cmd[2][1] = 0x21; - cmd[2][2] = 0x38; - cmd[2][3] = uid[7]; - cmd[2][4] = uid[6]; - cmd[2][5] = uid[5]; - cmd[2][6] = uid[4]; + // Command 3 : 022138u8u7u6u5 (where uX = uid byte X) + cmd[2][0] = 0x02; + cmd[2][1] = 0x21; + cmd[2][2] = 0x38; + cmd[2][3] = uid[7]; + cmd[2][4] = uid[6]; + cmd[2][5] = uid[5]; + cmd[2][6] = uid[4]; - // Command 4 : 022139u4u3u2u1 (where uX = uid byte X) - cmd[3][0] = 0x02; - cmd[3][1] = 0x21; - cmd[3][2] = 0x39; - cmd[3][3] = uid[3]; - cmd[3][4] = uid[2]; - cmd[3][5] = uid[1]; - cmd[3][6] = uid[0]; + // Command 4 : 022139u4u3u2u1 (where uX = uid byte X) + cmd[3][0] = 0x02; + cmd[3][1] = 0x21; + cmd[3][2] = 0x39; + cmd[3][3] = uid[3]; + cmd[3][4] = uid[2]; + cmd[3][5] = uid[1]; + cmd[3][6] = uid[0]; - for (int i=0; i<4; i++) { - // Add the CRC - crc = Iso15693Crc(cmd[i], 7); - cmd[i][7] = crc & 0xff; - cmd[i][8] = crc >> 8; + for (int i=0; i<4; i++) { + // Add the CRC + crc = Iso15693Crc(cmd[i], 7); + cmd[i][7] = crc & 0xff; + cmd[i][8] = crc >> 8; - if (DEBUG) { - Dbprintf("SEND:"); - Dbhexdump(sizeof(cmd[i]), cmd[i], false); - } + if (DEBUG) { + Dbprintf("SEND:"); + Dbhexdump(sizeof(cmd[i]), cmd[i], false); + } - recvlen = SendDataTag(cmd[i], sizeof(cmd[i]), true, 1, recvbuf, sizeof(recvbuf), 0); + recvlen = SendDataTag(cmd[i], sizeof(cmd[i]), true, 1, recvbuf, sizeof(recvbuf), 0); - if (DEBUG) { - Dbprintf("RECV:"); - Dbhexdump(recvlen, recvbuf, false); - DbdecodeIso15693Answer(recvlen, recvbuf); - } + if (DEBUG) { + Dbprintf("RECV:"); + Dbhexdump(recvlen, recvbuf, false); + DbdecodeIso15693Answer(recvlen, recvbuf); + } - cmd_send(CMD_ACK, recvlen>ISO15693_MAX_RESPONSE_LENGTH?ISO15693_MAX_RESPONSE_LENGTH:recvlen, 0, 0, recvbuf, ISO15693_MAX_RESPONSE_LENGTH); - } - - LED_D_OFF(); + cmd_send(CMD_ACK, recvlen>ISO15693_MAX_RESPONSE_LENGTH?ISO15693_MAX_RESPONSE_LENGTH:recvlen, 0, 0, recvbuf, ISO15693_MAX_RESPONSE_LENGTH); + } - LED_A_OFF(); + LED_D_OFF(); + + LED_A_OFF(); } @@ -1801,8 +1801,8 @@ static void __attribute__((unused)) BuildArbitraryRequest(uint8_t *uid,uint8_t C cmd[10] = 0x00; cmd[11] = 0x0a; -// cmd[12] = 0x00; -// cmd[13] = 0x00; //Now the CRC +// cmd[12] = 0x00; +// cmd[13] = 0x00; //Now the CRC crc = Iso15693Crc(cmd, 12); // the crc needs to be calculated over 2 bytes cmd[12] = crc & 0xff; cmd[13] = crc >> 8; @@ -1836,8 +1836,8 @@ static void __attribute__((unused)) BuildArbitraryCustomRequest(uint8_t uid[], u cmd[10] = 0x05; // for custom codes this must be manufacturer code cmd[11] = 0x00; -// cmd[12] = 0x00; -// cmd[13] = 0x00; //Now the CRC +// cmd[12] = 0x00; +// cmd[13] = 0x00; //Now the CRC crc = Iso15693Crc(cmd, 12); // the crc needs to be calculated over 2 bytes cmd[12] = crc & 0xff; cmd[13] = crc >> 8; diff --git a/armsrc/iso15693.h b/armsrc/iso15693.h index f6cf29f1..7964d79e 100644 --- a/armsrc/iso15693.h +++ b/armsrc/iso15693.h @@ -18,7 +18,7 @@ // Delays in SSP_CLK ticks. // SSP_CLK runs at 13,56MHz / 32 = 423.75kHz when simulating a tag #define DELAY_READER_TO_ARM_SIM 8 -#define DELAY_ARM_TO_READER_SIM 1 +#define DELAY_ARM_TO_READER_SIM 0 #define DELAY_ISO15693_VCD_TO_VICC_SIM 132 // 132/423.75kHz = 311.5us from end of command EOF to start of tag response //SSP_CLK runs at 13.56MHz / 4 = 3,39MHz when acting as reader #define DELAY_ISO15693_VCD_TO_VICC_READER 1056 // 1056/3,39MHz = 311.5us from end of command EOF to start of tag response diff --git a/fpga/fpga_hf.bit b/fpga/fpga_hf.bit index 665f7bcbe9df8553e37ddf040bf7406f7b59798e..70c7909aeb328809bb41a63c389b1db42501aceb 100644 GIT binary patch literal 42175 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 OIriLoM!!1$Z~qrf_Yi^r literal 42175 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 diff --git a/fpga/hi_simulate.v b/fpga/hi_simulate.v index de58a74e..92ebcb51 100644 --- a/fpga/hi_simulate.v +++ b/fpga/hi_simulate.v @@ -47,46 +47,48 @@ end // Divide 13.56 MHz to produce various frequencies for SSP_CLK // and modulation. -reg [7:0] ssp_clk_divider; +reg [8:0] ssp_clk_divider; -always @(posedge adc_clk) +always @(negedge adc_clk) ssp_clk_divider <= (ssp_clk_divider + 1); reg ssp_clk; always @(negedge adc_clk) begin - if(mod_type == `FPGA_HF_SIMULATOR_MODULATE_424K_8BIT) + if (mod_type == `FPGA_HF_SIMULATOR_MODULATE_424K_8BIT) // Get bit every at 53KHz (every 8th carrier bit of 424kHz) - ssp_clk <= ssp_clk_divider[7]; - else if(mod_type == `FPGA_HF_SIMULATOR_MODULATE_212K) + ssp_clk <= ~ssp_clk_divider[7]; + else if (mod_type == `FPGA_HF_SIMULATOR_MODULATE_212K) // Get next bit at 212kHz - ssp_clk <= ssp_clk_divider[5]; + ssp_clk <= ~ssp_clk_divider[5]; else // Get next bit at 424Khz - ssp_clk <= ssp_clk_divider[4]; + ssp_clk <= ~ssp_clk_divider[4]; end -// Divide SSP_CLK by 8 to produce the byte framing signal; the phase of -// this is arbitrary, because it's just a bitstream. -// One nasty issue, though: I can't make it work with both rx and tx at -// once. The phase wrt ssp_clk must be changed. TODO to find out why -// that is and make a better fix. -reg [2:0] ssp_frame_divider_to_arm; -always @(posedge ssp_clk) - ssp_frame_divider_to_arm <= (ssp_frame_divider_to_arm + 1); -reg [2:0] ssp_frame_divider_from_arm; -always @(negedge ssp_clk) - ssp_frame_divider_from_arm <= (ssp_frame_divider_from_arm + 1); - - +// Produce the byte framing signal; the phase of this signal +// is arbitrary, because it's just a bit stream in this module. reg ssp_frame; -always @(ssp_frame_divider_to_arm or ssp_frame_divider_from_arm or mod_type) - if(mod_type == `FPGA_HF_SIMULATOR_NO_MODULATION) // not modulating, so listening, to ARM - ssp_frame = (ssp_frame_divider_to_arm == 3'b000); - else - ssp_frame = (ssp_frame_divider_from_arm == 3'b000); +always @(negedge adc_clk) +begin + if (mod_type == `FPGA_HF_SIMULATOR_MODULATE_212K) + begin + if (ssp_clk_divider[8:5] == 4'd1) + ssp_frame <= 1'b1; + if (ssp_clk_divider[8:5] == 4'd5) + ssp_frame <= 1'b0; + end + else + begin + if (ssp_clk_divider[7:4] == 4'd1) + ssp_frame <= 1'b1; + if (ssp_clk_divider[7:4] == 4'd5) + ssp_frame <= 1'b0; + end +end + // Synchronize up the after-hysteresis signal, to produce DIN. reg ssp_din; @@ -120,6 +122,6 @@ assign pwr_lo = 1'b0; assign pwr_oe2 = 1'b0; -assign dbg = ssp_din; +assign dbg = ssp_frame; endmodule From d8ecc98a8eeebb814c28cd2eb4e21e53a59f6c4f Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Thu, 12 Sep 2019 09:21:10 +0200 Subject: [PATCH 130/189] 'hf iclass loclass': fix error handling (#865) * fix handling of "BEING_CRACKED" flag * don't try to calculate KCus when some bytes couldn't be brute forced * whitespace fixes --- client/loclass/elite_crack.c | 325 +++++++++++++++++------------------ 1 file changed, 158 insertions(+), 167 deletions(-) diff --git a/client/loclass/elite_crack.c b/client/loclass/elite_crack.c index 0cd00830..cfadcfbc 100644 --- a/client/loclass/elite_crack.c +++ b/client/loclass/elite_crack.c @@ -1,13 +1,13 @@ /***************************************************************************** * WARNING * - * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. - * - * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL - * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, - * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. - * - * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. + * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY. + * + * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL + * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL, + * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES. + * + * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS. * ***************************************************************************** * @@ -22,7 +22,7 @@ * * This is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, or, at your option, any later version. + * by the Free Software Foundation, or, at your option, any later version. * * This file is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -31,8 +31,8 @@ * * You should have received a copy of the GNU General Public License * along with loclass. If not, see . - * - * + * + * ****************************************************************************/ #include @@ -50,21 +50,21 @@ /** * @brief Permutes a key from standard NIST format to Iclass specific format - * from http://www.proxmark.org/forum/viewtopic.php?pid=11220#p11220 + * from http://www.proxmark.org/forum/viewtopic.php?pid=11220#p11220 * - * If you permute [6c 8d 44 f9 2a 2d 01 bf] you get [8a 0d b9 88 bb a7 90 ea] as shown below. + * If you permute [6c 8d 44 f9 2a 2d 01 bf] you get [8a 0d b9 88 bb a7 90 ea] as shown below. * - * 1 0 1 1 1 1 1 1 bf - * 0 0 0 0 0 0 0 1 01 - * 0 0 1 0 1 1 0 1 2d - * 0 0 1 0 1 0 1 0 2a - * 1 1 1 1 1 0 0 1 f9 - * 0 1 0 0 0 1 0 0 44 - * 1 0 0 0 1 1 0 1 8d - * 0 1 1 0 1 1 0 0 6c + * 1 0 1 1 1 1 1 1 bf + * 0 0 0 0 0 0 0 1 01 + * 0 0 1 0 1 1 0 1 2d + * 0 0 1 0 1 0 1 0 2a + * 1 1 1 1 1 0 0 1 f9 + * 0 1 0 0 0 1 0 0 44 + * 1 0 0 0 1 1 0 1 8d + * 0 1 1 0 1 1 0 0 6c * - * 8 0 b 8 b a 9 e - * a d 9 8 b 7 0 a + * 8 0 b 8 b a 9 e + * a d 9 8 b 7 0 a * * @param key * @param dest @@ -75,7 +75,7 @@ void permutekey(uint8_t key[8], uint8_t dest[8]) int i; for(i = 0 ; i < 8 ; i++) { - dest[i] = (((key[7] & (0x80 >> i)) >> (7-i)) << 7) | + dest[i] = (((key[7] & (0x80 >> i)) >> (7-i)) << 7) | (((key[6] & (0x80 >> i)) >> (7-i)) << 6) | (((key[5] & (0x80 >> i)) >> (7-i)) << 5) | (((key[4] & (0x80 >> i)) >> (7-i)) << 4) | @@ -98,7 +98,7 @@ void permutekey_rev(uint8_t key[8], uint8_t dest[8]) int i; for(i = 0 ; i < 8 ; i++) { - dest[7-i] = (((key[0] & (0x80 >> i)) >> (7-i)) << 7) | + dest[7-i] = (((key[0] & (0x80 >> i)) >> (7-i)) << 7) | (((key[1] & (0x80 >> i)) >> (7-i)) << 6) | (((key[2] & (0x80 >> i)) >> (7-i)) << 5) | (((key[3] & (0x80 >> i)) >> (7-i)) << 4) | @@ -168,15 +168,15 @@ rk(x [0] . . . x [7] , n + 1) = rk(rl(x [0] ) . . . rl(x [7] ), n) void rk(uint8_t *key, uint8_t n, uint8_t *outp_key) { - memcpy(outp_key, key, 8); + memcpy(outp_key, key, 8); - uint8_t j; + uint8_t j; - while(n-- > 0) - for(j=0; j < 8 ; j++) - outp_key[j] = rl(outp_key[j]); + while(n-- > 0) + for(j=0; j < 8 ; j++) + outp_key[j] = rl(outp_key[j]); - return; + return; } static mbedtls_des_context ctx_enc = { {0} }; @@ -184,17 +184,17 @@ static mbedtls_des_context ctx_dec = { {0} }; void desdecrypt_iclass(uint8_t *iclass_key, uint8_t *input, uint8_t *output) { - uint8_t key_std_format[8] = {0}; - permutekey_rev(iclass_key, key_std_format); - mbedtls_des_setkey_dec( &ctx_dec, key_std_format); - mbedtls_des_crypt_ecb(&ctx_dec,input,output); + uint8_t key_std_format[8] = {0}; + permutekey_rev(iclass_key, key_std_format); + mbedtls_des_setkey_dec( &ctx_dec, key_std_format); + mbedtls_des_crypt_ecb(&ctx_dec,input,output); } void desencrypt_iclass(uint8_t *iclass_key, uint8_t *input, uint8_t *output) { - uint8_t key_std_format[8] = {0}; - permutekey_rev(iclass_key, key_std_format); - mbedtls_des_setkey_enc( &ctx_enc, key_std_format); - mbedtls_des_crypt_ecb(&ctx_enc,input,output); + uint8_t key_std_format[8] = {0}; + permutekey_rev(iclass_key, key_std_format); + mbedtls_des_setkey_enc( &ctx_enc, key_std_format); + mbedtls_des_crypt_ecb(&ctx_enc,input,output); } /** @@ -205,9 +205,9 @@ void desencrypt_iclass(uint8_t *iclass_key, uint8_t *input, uint8_t *output) */ void hash2(uint8_t *key64, uint8_t *outp_keytable) { - /** - *Expected: - * High Security Key Table + /** + *Expected: + * High Security Key Table 00 F1 35 59 A1 0D 5A 26 7F 18 60 0B 96 8A C0 25 C1 10 BF A1 3B B0 FF 85 28 75 F2 1F C6 8F 0E 74 8F 21 @@ -219,60 +219,60 @@ void hash2(uint8_t *key64, uint8_t *outp_keytable) 70 43 08 A0 2F FE B3 26 D7 98 0B 34 7B 47 70 A0 AB **** The 64-bit HS Custom Key Value = 5B7C62C491C11B39 ******/ - uint8_t key64_negated[8] = {0}; - uint8_t z[8][8]={{0},{0}}; - uint8_t temp_output[8]={0}; - //calculate complement of key - int i; - for(i=0;i<8;i++) - key64_negated[i]= ~key64[i]; + uint8_t key64_negated[8] = {0}; + uint8_t z[8][8]={{0},{0}}; + uint8_t temp_output[8]={0}; + //calculate complement of key + int i; + for(i=0;i<8;i++) + key64_negated[i]= ~key64[i]; - // Once again, key is on iclass-format - desencrypt_iclass(key64, key64_negated, z[0]); + // Once again, key is on iclass-format + desencrypt_iclass(key64, key64_negated, z[0]); - prnlog("\nHigh security custom key (Kcus):"); - printvar("z0 ", z[0],8); + prnlog("\nHigh security custom key (Kcus):"); + printvar("z0 ", z[0],8); - uint8_t y[8][8]={{0},{0}}; + uint8_t y[8][8]={{0},{0}}; - // y[0]=DES_dec(z[0],~key) - // Once again, key is on iclass-format - desdecrypt_iclass(z[0], key64_negated, y[0]); - printvar("y0 ", y[0],8); + // y[0]=DES_dec(z[0],~key) + // Once again, key is on iclass-format + desdecrypt_iclass(z[0], key64_negated, y[0]); + printvar("y0 ", y[0],8); - for(i=1; i<8; i++) - { + for(i=1; i<8; i++) + { - // z [i] = DES dec (rk(K cus , i), z [i−1] ) - rk(key64, i, temp_output); - //y [i] = DES enc (rk(K cus , i), y [i−1] ) + // z [i] = DES dec (rk(K cus , i), z [i−1] ) + rk(key64, i, temp_output); + //y [i] = DES enc (rk(K cus , i), y [i−1] ) - desdecrypt_iclass(temp_output,z[i-1], z[i]); - desencrypt_iclass(temp_output,y[i-1], y[i]); + desdecrypt_iclass(temp_output,z[i-1], z[i]); + desencrypt_iclass(temp_output,y[i-1], y[i]); - } - if(outp_keytable != NULL) - { - for(i = 0 ; i < 8 ; i++) - { - memcpy(outp_keytable+i*16,y[i],8); - memcpy(outp_keytable+8+i*16,z[i],8); - } - }else - { - printarr_human_readable("hash2", outp_keytable,128); - } + } + if(outp_keytable != NULL) + { + for(i = 0 ; i < 8 ; i++) + { + memcpy(outp_keytable+i*16,y[i],8); + memcpy(outp_keytable+8+i*16,z[i],8); + } + }else + { + printarr_human_readable("hash2", outp_keytable,128); + } } /** * @brief Reads data from the iclass-reader-attack dump file. * @param dump, data from a iclass reader attack dump. The format of the dumpdata is expected to be as follows: - * <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC><8 byte HASH1><1 byte NUM_BYTES_TO_RECOVER><3 bytes BYTES_TO_RECOVER> - * .. N times... + * <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC><8 byte HASH1><1 byte NUM_BYTES_TO_RECOVER><3 bytes BYTES_TO_RECOVER> + * .. N times... * - * So the first attack, with 3 bytes to recover would be : ... 03000145 - * And a later attack, with 1 byte to recover (byte 0x5)would be : ...01050000 - * And an attack, with 2 bytes to recover (byte 0x5 and byte 0x07 )would be : ...02050700 + * So the first attack, with 3 bytes to recover would be : ... 03000145 + * And a later attack, with 1 byte to recover (byte 0x5)would be : ...01050000 + * And an attack, with 2 bytes to recover (byte 0x5 and byte 0x07 )would be : ...02050700 * * @param cc_nr an array to store cc_nr into (12 bytes) * @param csn an arracy ot store CSN into (8 bytes) @@ -306,8 +306,7 @@ static uint32_t startvalue = 0; * @param keytable where to write found values. * @return */ -int bruteforceItem(dumpdata item, uint16_t keytable[]) -{ +int bruteforceItem(dumpdata item, uint16_t keytable[]) { int errors = 0; uint8_t key_sel_p[8] = { 0 }; uint8_t div_key[8] = {0}; @@ -319,6 +318,8 @@ int bruteforceItem(dumpdata item, uint16_t keytable[]) uint8_t key_index[8] = {0}; hash1(item.csn, key_index); + printvar("CSN ", item.csn, 8); + printvar("HASH1", key_index, 8); /* * Determine which bytes to retrieve. A hash is typically @@ -333,26 +334,20 @@ int bruteforceItem(dumpdata item, uint16_t keytable[]) * Only the lower eight bits correspond to the (hopefully cracked) key-value. **/ uint8_t bytes_to_recover[3] = {0}; - uint8_t numbytes_to_recover = 0 ; - int i; - for(i =0 ; i < 8 ; i++) - { - if(keytable[key_index[i]] & (CRACKED | BEING_CRACKED)) continue; - bytes_to_recover[numbytes_to_recover++] = key_index[i]; - keytable[key_index[i]] |= BEING_CRACKED; + uint8_t numbytes_to_recover = 0; - if(numbytes_to_recover > 3) - { + for (int i = 0; i < 8; i++) { + if (keytable[key_index[i]] & (CRACKED | BEING_CRACKED)) continue; + if (numbytes_to_recover == 3) { prnlog("The CSN requires > 3 byte bruteforce, not supported"); - printvar("CSN", item.csn,8); - printvar("HASH1", key_index,8); - //Before we exit, reset the 'BEING_CRACKED' to zero - keytable[bytes_to_recover[0]] &= ~BEING_CRACKED; - keytable[bytes_to_recover[1]] &= ~BEING_CRACKED; - keytable[bytes_to_recover[2]] &= ~BEING_CRACKED; - + keytable[bytes_to_recover[0]] &= ~BEING_CRACKED; + keytable[bytes_to_recover[1]] &= ~BEING_CRACKED; + keytable[bytes_to_recover[2]] &= ~BEING_CRACKED; return 1; + } else { + bytes_to_recover[numbytes_to_recover++] = key_index[i]; + keytable[key_index[i]] |= BEING_CRACKED; } } @@ -370,24 +365,27 @@ int bruteforceItem(dumpdata item, uint16_t keytable[]) uint32_t endmask = 1 << 8*numbytes_to_recover; - for(i =0 ; i < numbytes_to_recover && numbytes_to_recover > 1; i++) + for (int i = 0; i < numbytes_to_recover; i++) { prnlog("Bruteforcing byte %d", bytes_to_recover[i]); + } - while(!found && !(brute & endmask)) - { + while (!found && !(brute & endmask)) { //Update the keytable with the brute-values - for(i =0 ; i < numbytes_to_recover; i++) - { + for(int i = 0 ; i < numbytes_to_recover; i++) { keytable[bytes_to_recover[i]] &= 0xFF00; - keytable[bytes_to_recover[i]] |= (brute >> (i*8) & 0xFF); + keytable[bytes_to_recover[i]] |= ((brute >> (i*8)) & 0xFF); } // Piece together the key - key_sel[0] = keytable[key_index[0]] & 0xFF;key_sel[1] = keytable[key_index[1]] & 0xFF; - key_sel[2] = keytable[key_index[2]] & 0xFF;key_sel[3] = keytable[key_index[3]] & 0xFF; - key_sel[4] = keytable[key_index[4]] & 0xFF;key_sel[5] = keytable[key_index[5]] & 0xFF; - key_sel[6] = keytable[key_index[6]] & 0xFF;key_sel[7] = keytable[key_index[7]] & 0xFF; + key_sel[0] = keytable[key_index[0]] & 0xFF; + key_sel[1] = keytable[key_index[1]] & 0xFF; + key_sel[2] = keytable[key_index[2]] & 0xFF; + key_sel[3] = keytable[key_index[3]] & 0xFF; + key_sel[4] = keytable[key_index[4]] & 0xFF; + key_sel[5] = keytable[key_index[5]] & 0xFF; + key_sel[6] = keytable[key_index[6]] & 0xFF; + key_sel[7] = keytable[key_index[7]] & 0xFF; //Permute from iclass format to standard format permutekey_rev(key_sel,key_sel_p); @@ -396,10 +394,9 @@ int bruteforceItem(dumpdata item, uint16_t keytable[]) //Calc mac doMAC(item.cc_nr, div_key,calculated_MAC); - if(memcmp(calculated_MAC, item.mac, 4) == 0) - { - for(i =0 ; i < numbytes_to_recover; i++) - prnlog("=> %d: 0x%02x", bytes_to_recover[i],0xFF & keytable[bytes_to_recover[i]]); + if (memcmp(calculated_MAC, item.mac, 4) == 0) { + for (int i = 0; i < numbytes_to_recover; i++) + prnlog("=> %d: 0x%02x", bytes_to_recover[i], 0xFF & keytable[bytes_to_recover[i]]); found = true; break; } @@ -410,39 +407,34 @@ int bruteforceItem(dumpdata item, uint16_t keytable[]) fflush(stdout); } } - if(! found) - { - prnlog("Failed to recover %d bytes using the following CSN",numbytes_to_recover); - printvar("CSN",item.csn,8); + + if (!found) { + prnlog("\nFailed to recover %d bytes", numbytes_to_recover); errors++; //Before we exit, reset the 'BEING_CRACKED' to zero - for(i =0 ; i < numbytes_to_recover; i++) - { - keytable[bytes_to_recover[i]] &= 0xFF; - keytable[bytes_to_recover[i]] |= CRACK_FAILED; + for (int i = 0; i < numbytes_to_recover; i++) { + keytable[bytes_to_recover[i]] &= ~BEING_CRACKED; } - - }else - { - for(i =0 ; i < numbytes_to_recover; i++) - { - keytable[bytes_to_recover[i]] &= 0xFF; - keytable[bytes_to_recover[i]] |= CRACKED; + } else { + for (int i = 0; i < numbytes_to_recover; i++) { + keytable[bytes_to_recover[i]] &= ~BEING_CRACKED; + keytable[bytes_to_recover[i]] |= CRACKED; } } + return errors; } /** * From dismantling iclass-paper: - * Assume that an adversary somehow learns the first 16 bytes of hash2(K_cus ), i.e., y [0] and z [0] . - * Then he can simply recover the master custom key K_cus by computing - * K_cus = ~DES(z[0] , y[0] ) . + * Assume that an adversary somehow learns the first 16 bytes of hash2(K_cus ), i.e., y [0] and z [0] . + * Then he can simply recover the master custom key K_cus by computing + * K_cus = ~DES(z[0] , y[0] ) . * - * Furthermore, the adversary is able to verify that he has the correct K cus by - * checking whether z [0] = DES enc (K_cus , ~K_cus ). + * Furthermore, the adversary is able to verify that he has the correct K cus by + * checking whether z [0] = DES enc (K_cus , ~K_cus ). * @param keytable an array (128 bytes) of hash2(kcus) * @param master_key where to put the master key * @return 0 for ok, 1 for failz @@ -532,12 +524,11 @@ int bruteforceDump(uint8_t dump[], size_t dumpsize, uint16_t keytable[]) // master key calculation uint8_t first16bytes[16] = {0}; - for(i = 0 ; i < 16 ; i++) - { + for (int i = 0; i < 16; i++) { first16bytes[i] = keytable[i] & 0xFF; - if(!(keytable[i] & CRACKED)) - { - prnlog("Error, we are missing byte %d, custom key calculation will fail...", i); + if (!(keytable[i] & CRACKED)) { + prnlog("Error, we are missing byte %d, cannot calculate custom key.", i); + return 1; } } errors += calculateMasterKey(first16bytes, NULL); @@ -670,29 +661,29 @@ int _test_iclass_key_permutation() } int _testHash1() { - uint8_t csn[8]= {0x01,0x02,0x03,0x04,0xF7,0xFF,0x12,0xE0}; - uint8_t k[8] = {0}; - hash1(csn, k); - uint8_t expected[8] = {0x7E,0x72,0x2F,0x40,0x2D,0x02,0x51,0x42}; - if(memcmp(k,expected,8) != 0) - { - prnlog("Error with hash1!"); - printarr("calculated", k, 8); - printarr("expected", expected, 8); - return 1; - } - return 0; + uint8_t csn[8]= {0x01,0x02,0x03,0x04,0xF7,0xFF,0x12,0xE0}; + uint8_t k[8] = {0}; + hash1(csn, k); + uint8_t expected[8] = {0x7E,0x72,0x2F,0x40,0x2D,0x02,0x51,0x42}; + if(memcmp(k,expected,8) != 0) + { + prnlog("Error with hash1!"); + printarr("calculated", k, 8); + printarr("expected", expected, 8); + return 1; + } + return 0; } int testElite() { prnlog("[+] Testing iClass Elite functinality..."); - prnlog("[+] Testing hash2"); - uint8_t k_cus[8] = {0x5B,0x7C,0x62,0xC4,0x91,0xC1,0x1B,0x39}; + prnlog("[+] Testing hash2"); + uint8_t k_cus[8] = {0x5B,0x7C,0x62,0xC4,0x91,0xC1,0x1B,0x39}; - /** - *Expected: - * High Security Key Table + /** + *Expected: + * High Security Key Table 00 F1 35 59 A1 0D 5A 26 7F 18 60 0B 96 8A C0 25 C1 10 BF A1 3B B0 FF 85 28 75 F2 1F C6 8F 0E 74 8F 21 @@ -706,20 +697,20 @@ int testElite() **** The 64-bit HS Custom Key Value = 5B7C62C491C11B39 **** - */ - uint8_t keytable[128] = {0}; - hash2(k_cus, keytable); - printarr_human_readable("Hash2", keytable, 128); - if(keytable[3] == 0xA1 && keytable[0x30] == 0xA3 && keytable[0x6F] == 0x95) - { - prnlog("[+] Hash2 looks fine..."); - } + */ + uint8_t keytable[128] = {0}; + hash2(k_cus, keytable); + printarr_human_readable("Hash2", keytable, 128); + if(keytable[3] == 0xA1 && keytable[0x30] == 0xA3 && keytable[0x6F] == 0x95) + { + prnlog("[+] Hash2 looks fine..."); + } int errors = 0 ; - prnlog("[+] Testing hash1..."); - errors += _testHash1(); - prnlog("[+] Testing key diversification ..."); - errors +=_test_iclass_key_permutation(); + prnlog("[+] Testing hash1..."); + errors += _testHash1(); + prnlog("[+] Testing key diversification ..."); + errors +=_test_iclass_key_permutation(); errors += _testBruteforce(); return errors; From 70dbfc3fc7a177a81331bd8c86c9d993900f056b Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Sat, 21 Sep 2019 13:56:01 +0100 Subject: [PATCH 131/189] fix compile issue with gcc 9.1.0 (issue #868) --- armsrc/appmain.c | 2 +- armsrc/lfsampling.c | 18 +++++++++--------- armsrc/lfsampling.h | 10 +++++----- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 93f32f5f..c7c716a7 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -998,7 +998,7 @@ void UsbPacketReceived(uint8_t *packet, int len) switch(c->cmd) { #ifdef WITH_LF case CMD_SET_LF_SAMPLING_CONFIG: - setSamplingConfig((sample_config *) c->d.asBytes); + setSamplingConfig(c->d.asBytes); break; case CMD_ACQUIRE_RAW_ADC_SAMPLES_125K: cmd_send(CMD_ACK,SampleLF(c->arg[0], c->arg[1]),0,0,0,0); diff --git a/armsrc/lfsampling.c b/armsrc/lfsampling.c index e53d0205..e0764063 100644 --- a/armsrc/lfsampling.c +++ b/armsrc/lfsampling.c @@ -39,17 +39,17 @@ void printConfig() * @brief setSamplingConfig * @param sc */ -void setSamplingConfig(sample_config *sc) -{ - if(sc->divisor != 0) config.divisor = sc->divisor; - if(sc->bits_per_sample!= 0) config.bits_per_sample= sc->bits_per_sample; - if(sc->decimation!= 0) config.decimation= sc->decimation; - if(sc->trigger_threshold != -1) config.trigger_threshold= sc->trigger_threshold; - if(sc->samples_to_skip != -1) config.samples_to_skip = sc->samples_to_skip; +void setSamplingConfig(uint8_t *config_data) { + sample_config *sc = (sample_config *)config_data; + if (sc->divisor != 0) config.divisor = sc->divisor; + if (sc->bits_per_sample != 0) config.bits_per_sample = sc->bits_per_sample; + if (sc->decimation != 0) config.decimation = sc->decimation; + if (sc->trigger_threshold != -1) config.trigger_threshold = sc->trigger_threshold; + if (sc->samples_to_skip != -1) config.samples_to_skip = sc->samples_to_skip; config.averaging= sc->averaging; - if(config.bits_per_sample > 8) config.bits_per_sample = 8; - if(config.decimation < 1) config.decimation = 1; + if (config.bits_per_sample > 8) config.bits_per_sample = 8; + if (config.decimation < 1) config.decimation = 1; printConfig(); } diff --git a/armsrc/lfsampling.h b/armsrc/lfsampling.h index ea044f3c..3c0fc93e 100644 --- a/armsrc/lfsampling.h +++ b/armsrc/lfsampling.h @@ -1,5 +1,5 @@ -#ifndef LFSAMPLING_H -#define LFSAMPLING_H +#ifndef LFSAMPLING_H__ +#define LFSAMPLING_H__ /** * acquisition of Cotag LF signal. Similar to other LF, since the Cotag has such long datarate RF/384 @@ -45,7 +45,7 @@ uint32_t DoAcquisition_config(bool silent, int sample_size); * Setup the FPGA to listen for samples. This method downloads the FPGA bitstream * if not already loaded, sets divisor and starts up the antenna. * @param divisor : 1, 88> 255 or negative ==> 134.8 KHz -* 0 or 95 ==> 125 KHz +* 0 or 95 ==> 125 KHz * **/ void LFSetupFPGAForADC(int divisor, bool lf_field); @@ -61,9 +61,9 @@ void LFSetupFPGAForADC(int divisor, bool lf_field); * @brief setSamplingConfig * @param sc */ -void setSamplingConfig(sample_config *sc); +void setSamplingConfig(uint8_t *config_data); -sample_config * getSamplingConfig(); +sample_config *getSamplingConfig(); void printConfig(); From 5b12974a7f01a94c40552402b66b01bf8ec0e214 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Sat, 21 Sep 2019 11:58:51 +0200 Subject: [PATCH 132/189] fix 'hf iclass sim': * chg to reader command decoder in iso15693.c (require no modulation before SOF) * add 'has_been_low_for' logic to hi_simulate.v (same as in other FPGA modes, default to "no modulation") * add simulation of chip status (IDLE, ACTIVE, SELECTED, HALTED) * check ACSN on SELECT * add simulation of RESELECT * always check length of reader commands * fix printing of NR, MAC in sim 2 mode * fix response length to CHECK command --- armsrc/iclass.c | 290 ++++++++++++++++++++++++------------------- armsrc/iso15693.c | 25 ++-- client/cmdhficlass.c | 56 ++++++--- fpga/fpga_hf.bit | Bin 42175 -> 42175 bytes fpga/hi_simulate.v | 24 +++- 5 files changed, 238 insertions(+), 157 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 66238a10..23701540 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -777,8 +777,6 @@ static void AppendCrc(uint8_t *data, int len) { /** * @brief Does the actual simulation - * @param csn - csn to use - * @param breakAfterMacReceived if true, returns after reader MAC has been received. */ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { @@ -919,6 +917,8 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { LED_A_ON(); bool buttonPressed = false; + enum { IDLE, ACTIVATED, SELECTED, HALTED } chip_state = IDLE; + while (!exitLoop) { WDT_HIT(); LED_B_OFF(); @@ -943,162 +943,193 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { trace_data = NULL; trace_data_size = 0; - if (receivedCmd[0] == ICLASS_CMD_ACTALL) { - // Reader in anticollission phase - modulated_response = resp_sof; - modulated_response_size = resp_sof_Len; - trace_data = sof_data; - trace_data_size = sizeof(sof_data); + if (receivedCmd[0] == ICLASS_CMD_ACTALL && len == 1) { + // Reader in anticollision phase + if (chip_state != HALTED) { + modulated_response = resp_sof; + modulated_response_size = resp_sof_Len; + trace_data = sof_data; + trace_data_size = sizeof(sof_data); + chip_state = ACTIVATED; + } } else if (receivedCmd[0] == ICLASS_CMD_READ_OR_IDENTIFY && len == 1) { // identify - // Reader asks for anticollission CSN - modulated_response = resp_anticoll; - modulated_response_size = resp_anticoll_len; - trace_data = anticoll_data; - trace_data_size = sizeof(anticoll_data); + // Reader asks for anticollision CSN + if (chip_state == SELECTED || chip_state == ACTIVATED) { + modulated_response = resp_anticoll; + modulated_response_size = resp_anticoll_len; + trace_data = anticoll_data; + trace_data_size = sizeof(anticoll_data); + } + + } else if (receivedCmd[0] == ICLASS_CMD_SELECT && len == 9) { + // Reader selects anticollision CSN. + // Tag sends the corresponding real CSN + if (chip_state == ACTIVATED || chip_state == SELECTED) { + if (!memcmp(receivedCmd+1, anticoll_data, 8)) { + modulated_response = resp_csn; + modulated_response_size = resp_csn_len; + trace_data = csn_data; + trace_data_size = sizeof(csn_data); + chip_state = SELECTED; + } else { + chip_state = IDLE; + } + } else if (chip_state == HALTED) { + // RESELECT with CSN + if (!memcmp(receivedCmd+1, csn_data, 8)) { + modulated_response = resp_csn; + modulated_response_size = resp_csn_len; + trace_data = csn_data; + trace_data_size = sizeof(csn_data); + chip_state = SELECTED; + } + } } else if (receivedCmd[0] == ICLASS_CMD_READ_OR_IDENTIFY && len == 4) { // read block uint16_t blockNo = receivedCmd[1]; - if (simulationMode == ICLASS_SIM_MODE_EXIT_AFTER_MAC) { - // provide defaults for blocks 0 ... 5 - switch (blockNo) { - case 0: // csn (block 00) - modulated_response = resp_csn; - modulated_response_size = resp_csn_len; - trace_data = csn_data; - trace_data_size = sizeof(csn_data); - break; - case 1: // configuration (block 01) - modulated_response = resp_conf; - modulated_response_size = resp_conf_len; - trace_data = conf_data; - trace_data_size = sizeof(conf_data); - break; - case 2: // e-purse (block 02) - modulated_response = resp_cc; - modulated_response_size = resp_cc_len; - trace_data = card_challenge_data; - trace_data_size = sizeof(card_challenge_data); - // set epurse of sim2,4 attack - if (reader_mac_buf != NULL) { - memcpy(reader_mac_buf, card_challenge_data, 8); - } - break; - case 3: - case 4: // Kd, Kd, always respond with 0xff bytes + if (chip_state == SELECTED) { + if (simulationMode == ICLASS_SIM_MODE_EXIT_AFTER_MAC) { + // provide defaults for blocks 0 ... 5 + switch (blockNo) { + case 0: // csn (block 00) + modulated_response = resp_csn; + modulated_response_size = resp_csn_len; + trace_data = csn_data; + trace_data_size = sizeof(csn_data); + break; + case 1: // configuration (block 01) + modulated_response = resp_conf; + modulated_response_size = resp_conf_len; + trace_data = conf_data; + trace_data_size = sizeof(conf_data); + break; + case 2: // e-purse (block 02) + modulated_response = resp_cc; + modulated_response_size = resp_cc_len; + trace_data = card_challenge_data; + trace_data_size = sizeof(card_challenge_data); + // set epurse of sim2,4 attack + if (reader_mac_buf != NULL) { + memcpy(reader_mac_buf, card_challenge_data, 8); + } + break; + case 3: + case 4: // Kd, Kc, always respond with 0xff bytes + modulated_response = resp_ff; + modulated_response_size = resp_ff_len; + trace_data = ff_data; + trace_data_size = sizeof(ff_data); + break; + case 5: // Application Issuer Area (block 05) + modulated_response = resp_aia; + modulated_response_size = resp_aia_len; + trace_data = aia_data; + trace_data_size = sizeof(aia_data); + break; + // default: don't respond + } + } else if (simulationMode == ICLASS_SIM_MODE_FULL) { + if (blockNo == 3 || blockNo == 4) { // Kd, Kc, always respond with 0xff bytes modulated_response = resp_ff; modulated_response_size = resp_ff_len; trace_data = ff_data; trace_data_size = sizeof(ff_data); - break; - case 5: // Application Issuer Area (block 05) - modulated_response = resp_aia; - modulated_response_size = resp_aia_len; - trace_data = aia_data; - trace_data_size = sizeof(aia_data); - break; - // default: don't respond + } else { // use data from emulator memory + memcpy(data_generic_trace, emulator + 8*blockNo, 8); + AppendCrc(data_generic_trace, 8); + trace_data = data_generic_trace; + trace_data_size = 10; + CodeIso15693AsTag(trace_data, trace_data_size); + memcpy(data_response, ToSend, ToSendMax); + modulated_response = data_response; + modulated_response_size = ToSendMax; + } } - } else if (simulationMode == ICLASS_SIM_MODE_FULL) { - if (blockNo == 3 || blockNo == 4) { // Kd, Kc, always respond with 0xff bytes - modulated_response = resp_ff; - modulated_response_size = resp_ff_len; - trace_data = ff_data; - trace_data_size = sizeof(ff_data); - } else { // use data from emulator memory - memcpy(data_generic_trace, emulator + (receivedCmd[1] << 3), 8); - AppendCrc(data_generic_trace, 8); + } + + } else if ((receivedCmd[0] == ICLASS_CMD_READCHECK_KD + || receivedCmd[0] == ICLASS_CMD_READCHECK_KC) && len == 2) { + // Read e-purse (88 02 || 18 02) + if (chip_state == SELECTED) { + modulated_response = resp_cc; + modulated_response_size = resp_cc_len; + trace_data = card_challenge_data; + trace_data_size = sizeof(card_challenge_data); + LED_B_ON(); + } + + } else if (receivedCmd[0] == ICLASS_CMD_CHECK && len == 9) { + // Reader random and reader MAC!!! + if (chip_state == SELECTED) { + if (simulationMode == ICLASS_SIM_MODE_FULL) { + //NR, from reader, is in receivedCmd+1 + opt_doTagMAC_2(cipher_state, receivedCmd+1, data_generic_trace, diversified_key); trace_data = data_generic_trace; - trace_data_size = 10; + trace_data_size = 4; CodeIso15693AsTag(trace_data, trace_data_size); memcpy(data_response, ToSend, ToSendMax); modulated_response = data_response; modulated_response_size = ToSendMax; - } - } - - } else if (receivedCmd[0] == ICLASS_CMD_SELECT) { - // Reader selects anticollission CSN. - // Tag sends the corresponding real CSN - modulated_response = resp_csn; - modulated_response_size = resp_csn_len; - trace_data = csn_data; - trace_data_size = sizeof(csn_data); - - } else if (receivedCmd[0] == ICLASS_CMD_READCHECK_KD - || receivedCmd[0] == ICLASS_CMD_READCHECK_KC) { - // Read e-purse (88 02 || 18 02) - modulated_response = resp_cc; - modulated_response_size = resp_cc_len; - trace_data = card_challenge_data; - trace_data_size = sizeof(card_challenge_data); - LED_B_ON(); - - } else if (receivedCmd[0] == ICLASS_CMD_CHECK) { - // Reader random and reader MAC!!! - if (simulationMode == ICLASS_SIM_MODE_FULL) { - //NR, from reader, is in receivedCmd+1 - opt_doTagMAC_2(cipher_state, receivedCmd+1, data_generic_trace, diversified_key); - trace_data = data_generic_trace; - trace_data_size = 4; - CodeIso15693AsTag(trace_data, trace_data_size); - memcpy(data_response, ToSend, ToSendMax); - modulated_response = data_response; - modulated_response_size = ToSendMax; - //exitLoop = true; - } else { // Not fullsim, we don't respond - // We do not know what to answer, so lets keep quiet - if (simulationMode == ICLASS_SIM_MODE_EXIT_AFTER_MAC) { - if (reader_mac_buf != NULL) { - // save NR and MAC for sim 2,4 - memcpy(reader_mac_buf + 8, receivedCmd + 1, 8); + //exitLoop = true; + } else { // Not fullsim, we don't respond + // We do not know what to answer, so lets keep quiet + if (simulationMode == ICLASS_SIM_MODE_EXIT_AFTER_MAC) { + if (reader_mac_buf != NULL) { + // save NR and MAC for sim 2,4 + memcpy(reader_mac_buf + 8, receivedCmd + 1, 8); + } + exitLoop = true; } - exitLoop = true; } } } else if (receivedCmd[0] == ICLASS_CMD_HALT && len == 1) { - // Reader ends the session - modulated_response = resp_sof; - modulated_response_size = 0; - trace_data = NULL; - trace_data_size = 0; + if (chip_state == SELECTED) { + // Reader ends the session + chip_state = HALTED; + } } else if (simulationMode == ICLASS_SIM_MODE_FULL && receivedCmd[0] == ICLASS_CMD_READ4 && len == 4) { // 0x06 - //Read block - //Take the data... - memcpy(data_generic_trace, emulator + (receivedCmd[1] << 3), 8 * 4); - AppendCrc(data_generic_trace, 8 * 4); - trace_data = data_generic_trace; - trace_data_size = 8 * 4 + 2; - CodeIso15693AsTag(trace_data, trace_data_size); - memcpy(data_response, ToSend, ToSendMax); - modulated_response = data_response; - modulated_response_size = ToSendMax; + //Read 4 blocks + if (chip_state == SELECTED) { + memcpy(data_generic_trace, emulator + (receivedCmd[1] << 3), 8 * 4); + AppendCrc(data_generic_trace, 8 * 4); + trace_data = data_generic_trace; + trace_data_size = 8 * 4 + 2; + CodeIso15693AsTag(trace_data, trace_data_size); + memcpy(data_response, ToSend, ToSendMax); + modulated_response = data_response; + modulated_response_size = ToSendMax; + } - } else if (receivedCmd[0] == ICLASS_CMD_UPDATE && simulationMode == ICLASS_SIM_MODE_FULL) { + } else if (receivedCmd[0] == ICLASS_CMD_UPDATE && (len == 12 || len == 14)) { // Probably the reader wants to update the nonce. Let's just ignore that for now. // OBS! If this is implemented, don't forget to regenerate the cipher_state // We're expected to respond with the data+crc, exactly what's already in the receivedCmd // receivedCmd is now UPDATE 1b | ADDRESS 1b | DATA 8b | Signature 4b or CRC 2b - memcpy(data_generic_trace, receivedCmd + 2, 8); - AppendCrc(data_generic_trace, 8); - trace_data = data_generic_trace; - trace_data_size = 10; - CodeIso15693AsTag(trace_data, trace_data_size); - memcpy(data_response, ToSend, ToSendMax); - modulated_response = data_response; - modulated_response_size = ToSendMax; + if (chip_state == SELECTED) { + memcpy(data_generic_trace, receivedCmd + 2, 8); + AppendCrc(data_generic_trace, 8); + trace_data = data_generic_trace; + trace_data_size = 10; + CodeIso15693AsTag(trace_data, trace_data_size); + memcpy(data_response, ToSend, ToSendMax); + modulated_response = data_response; + modulated_response_size = ToSendMax; + } - } else if (receivedCmd[0] == ICLASS_CMD_PAGESEL) { + } else if (receivedCmd[0] == ICLASS_CMD_PAGESEL && len == 4) { // Pagesel - // Pagesel enables to select a page in the selected chip memory and return its configuration block - // Chips with a single page will not answer to this command - // It appears we're fine ignoring this. - // Otherwise, we should answer 8bytes (block) + 2bytes CRC + if (chip_state == SELECTED) { + // Pagesel enables to select a page in the selected chip memory and return its configuration block + // Chips with a single page will not answer to this command + // It appears we're fine ignoring this. + // Otherwise, we should answer 8bytes (block) + 2bytes CRC + } } else { - // Never seen this command before + // don't know how to handle this command char debug_message[250]; // should be enough sprintf(debug_message, "Unhandled command (len = %d) received from reader:", len); for (int i = 0; i < len && strlen(debug_message) < sizeof(debug_message) - 3 - 1; i++) { @@ -1187,8 +1218,9 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain datain[i*8+0], datain[i*8+1], datain[i*8+2], datain[i*8+3], datain[i*8+4], datain[i*8+5], datain[i*8+6], datain[i*8+7]); Dbprintf("NR,MAC: %02x %02x %02x %02x %02x %02x %02x %02x", - datain[i*8+ 8], datain[i*8+ 9], datain[i*8+10], datain[i*8+11], - datain[i*8+12], datain[i*8+13], datain[i*8+14], datain[i*8+15]); + mac_responses[i*16+ 8], mac_responses[i*16+ 9], mac_responses[i*16+10], mac_responses[i*16+11], + mac_responses[i*16+12], mac_responses[i*16+13], mac_responses[i*16+14], mac_responses[i*16+15]); + SpinDelay(100); // give the reader some time to prepare for next CSN } cmd_send(CMD_ACK, CMD_SIMULATE_TAG_ICLASS, i, 0, mac_responses, i*16); } else if (simType == ICLASS_SIM_MODE_FULL) { diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 4b4577e7..f33e0156 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -671,6 +671,7 @@ static int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, int tim typedef struct DecodeReader { enum { STATE_READER_UNSYNCD, + STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF, STATE_READER_AWAIT_1ST_RISING_EDGE_OF_SOF, STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF, STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF, @@ -714,6 +715,13 @@ static int inline __attribute__((always_inline)) Handle15693SampleFromReader(uin { switch (DecodeReader->state) { case STATE_READER_UNSYNCD: + // wait for unmodulated carrier + if (bit) { + DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; + } + break; + + case STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF: if (!bit) { // we went low, so this could be the beginning of a SOF DecodeReader->posCount = 1; @@ -725,7 +733,7 @@ static int inline __attribute__((always_inline)) Handle15693SampleFromReader(uin DecodeReader->posCount++; if (bit) { // detected rising edge if (DecodeReader->posCount < 4) { // rising edge too early (nominally expected at 5) - DecodeReaderReset(DecodeReader); + DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; } else { // SOF DecodeReader->state = STATE_READER_AWAIT_2ND_FALLING_EDGE_OF_SOF; } @@ -748,13 +756,13 @@ static int inline __attribute__((always_inline)) Handle15693SampleFromReader(uin DecodeReader->state = STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF; } else if (DecodeReader->posCount < 28) { // falling edge too early (nominally expected at 29 latest) DecodeReaderReset(DecodeReader); - } else { // SOF for 1 out of 4 coding + } else { // SOF for 1 out of 256 coding DecodeReader->Coding = CODING_1_OUT_OF_256; DecodeReader->state = STATE_READER_AWAIT_2ND_RISING_EDGE_OF_SOF; } } else { if (DecodeReader->posCount > 29) { // stayed high for too long - DecodeReaderReset(DecodeReader); + DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; } else { // do nothing, keep waiting } @@ -766,7 +774,7 @@ static int inline __attribute__((always_inline)) Handle15693SampleFromReader(uin if (bit) { // detected rising edge if (DecodeReader->Coding == CODING_1_OUT_OF_256) { if (DecodeReader->posCount < 32) { // rising edge too early (nominally expected at 33) - DecodeReaderReset(DecodeReader); + DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; } else { DecodeReader->posCount = 1; DecodeReader->bitCount = 0; @@ -777,21 +785,22 @@ static int inline __attribute__((always_inline)) Handle15693SampleFromReader(uin } } else { // CODING_1_OUT_OF_4 if (DecodeReader->posCount < 24) { // rising edge too early (nominally expected at 25) - DecodeReaderReset(DecodeReader); + DecodeReader->state = STATE_READER_AWAIT_1ST_FALLING_EDGE_OF_SOF; } else { + DecodeReader->posCount = 1; DecodeReader->state = STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4; } } } else { if (DecodeReader->Coding == CODING_1_OUT_OF_256) { if (DecodeReader->posCount > 34) { // signal stayed low for too long - DecodeReaderReset(DecodeReader); + DecodeReaderReset(DecodeReader); } else { // do nothing, keep waiting } } else { // CODING_1_OUT_OF_4 if (DecodeReader->posCount > 26) { // signal stayed low for too long - DecodeReaderReset(DecodeReader); + DecodeReaderReset(DecodeReader); } else { // do nothing, keep waiting } @@ -802,7 +811,7 @@ static int inline __attribute__((always_inline)) Handle15693SampleFromReader(uin case STATE_READER_AWAIT_END_OF_SOF_1_OUT_OF_4: DecodeReader->posCount++; if (bit) { - if (DecodeReader->posCount == 33) { + if (DecodeReader->posCount == 9) { DecodeReader->posCount = 1; DecodeReader->bitCount = 0; DecodeReader->byteCount = 0; diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index ee0dd16e..48b62b17 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -100,7 +100,46 @@ int usage_hf_iclass_sim(void) { return 0; } +// the original malicious IDs from Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult, +// and Milosch Meriac. Dismantling iClass and iClass Elite. #define NUM_CSNS 15 +static uint8_t csns[8 * NUM_CSNS] = { + 0x00, 0x0B, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x04, 0x0E, 0x08, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x09, 0x0D, 0x05, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x0A, 0x0C, 0x06, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x0F, 0x0B, 0x03, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x08, 0x0A, 0x0C, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x0D, 0x09, 0x09, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x0E, 0x08, 0x0A, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x03, 0x07, 0x17, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x3C, 0x06, 0xE0, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x01, 0x05, 0x1D, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x02, 0x04, 0x1E, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x07, 0x03, 0x1B, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x00, 0x02, 0x24, 0xF7, 0xFF, 0x12, 0xE0, + 0x00, 0x05, 0x01, 0x21, 0xF7, 0xFF, 0x12, 0xE0 }; + + +// pre-defined 9 CSNs by iceman. +// only one csn depend on several others. +// six depends only on the first csn, (0,1, 0x45) + +// #define NUM_CSNS 9 +// static uint8_t csns[8 * NUM_CSNS] = { + // 0x01, 0x0A, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0, + // 0x0C, 0x06, 0x0C, 0xFE, 0xF7, 0xFF, 0x12, 0xE0, + // 0x10, 0x97, 0x83, 0x7B, 0xF7, 0xFF, 0x12, 0xE0, + // 0x13, 0x97, 0x82, 0x7A, 0xF7, 0xFF, 0x12, 0xE0, + // 0x07, 0x0E, 0x0D, 0xF9, 0xF7, 0xFF, 0x12, 0xE0, + // 0x14, 0x96, 0x84, 0x76, 0xF7, 0xFF, 0x12, 0xE0, + // 0x17, 0x96, 0x85, 0x71, 0xF7, 0xFF, 0x12, 0xE0, + // 0xCE, 0xC5, 0x0F, 0x77, 0xF7, 0xFF, 0x12, 0xE0, + // 0xD2, 0x5A, 0x82, 0xF8, 0xF7, 0xFF, 0x12, 0xE0 + // //0x04, 0x08, 0x9F, 0x78, 0x6E, 0xFF, 0x12, 0xE0 +// }; + + int CmdHFiClassSim(const char *Cmd) { uint8_t simType = 0; uint8_t CSN[8] = {0, 0, 0, 0, 0, 0, 0, 0}; @@ -123,23 +162,6 @@ int CmdHFiClassSim(const char *Cmd) { UsbCommand c = {CMD_SIMULATE_TAG_ICLASS, {simType, NUM_CSNS}}; UsbCommand resp = {0}; - uint8_t csns[8 * NUM_CSNS] = { - 0x00, 0x0B, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x04, 0x0E, 0x08, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x09, 0x0D, 0x05, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x0A, 0x0C, 0x06, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x0F, 0x0B, 0x03, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x08, 0x0A, 0x0C, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x0D, 0x09, 0x09, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x0E, 0x08, 0x0A, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x03, 0x07, 0x17, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x3C, 0x06, 0xE0, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x01, 0x05, 0x1D, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x02, 0x04, 0x1E, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x07, 0x03, 0x1B, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x00, 0x02, 0x24, 0xF7, 0xFF, 0x12, 0xE0, - 0x00, 0x05, 0x01, 0x21, 0xF7, 0xFF, 0x12, 0xE0 }; - memcpy(c.d.asBytes, csns, 8 * NUM_CSNS); SendCommand(&c); diff --git a/fpga/fpga_hf.bit b/fpga/fpga_hf.bit index 70c7909aeb328809bb41a63c389b1db42501aceb..1bd3c416fe728c26ee204ede9bc882c8f87486c8 100644 GIT binary patch literal 42175 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 OIriLoM!!1$Z~qrf_Yi^r diff --git a/fpga/hi_simulate.v b/fpga/hi_simulate.v index 92ebcb51..097b8a08 100644 --- a/fpga/hi_simulate.v +++ b/fpga/hi_simulate.v @@ -33,15 +33,33 @@ module hi_simulate( output dbg; input [2:0] mod_type; +assign adc_clk = ck_1356meg; // The comparator with hysteresis on the output from the peak detector. reg after_hysteresis; -assign adc_clk = ck_1356meg; +reg [11:0] has_been_low_for; always @(negedge adc_clk) begin - if(& adc_d[7:5]) after_hysteresis = 1'b1; // if (adc_d >= 224) - else if(~(| adc_d[7:5])) after_hysteresis = 1'b0; // if (adc_d <= 31) + if (& adc_d[7:5]) after_hysteresis <= 1'b1; // if (adc_d >= 224) + else if (~(| adc_d[7:5])) after_hysteresis <= 1'b0; // if (adc_d <= 31) + + if (adc_d >= 224) + begin + has_been_low_for <= 12'd0; + end + else + begin + if (has_been_low_for == 12'd4095) + begin + has_been_low_for <= 12'd0; + after_hysteresis <= 1'b1; + end + else + begin + has_been_low_for <= has_been_low_for + 1; + end + end end From e49d31c0e798d14d8b0607b953f06dceecb4a42e Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Wed, 25 Sep 2019 14:24:36 +0200 Subject: [PATCH 133/189] fix 'hf iclass sim': * ignore standard iso15693 INVENTORY commands silently * make iso15693 command decoder more strict (prevent decoding rubbish) * re-enable sim 3 --- armsrc/iclass.c | 3 +++ armsrc/iso15693.c | 16 ++++++---------- client/cmdhficlass.c | 7 +++---- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 23701540..2e3a4db8 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -1128,6 +1128,9 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { // Otherwise, we should answer 8bytes (block) + 2bytes CRC } + } else if (receivedCmd[0] == 0x26 && len == 5) { + // standard ISO15693 INVENTORY command. Ignore. + } else { // don't know how to handle this command char debug_message[250]; // should be enough diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index f33e0156..dbc1ca4c 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -827,6 +827,7 @@ static int inline __attribute__((always_inline)) Handle15693SampleFromReader(uin break; case STATE_READER_RECEIVE_DATA_1_OUT_OF_4: + bit = !!bit; DecodeReader->posCount++; if (DecodeReader->posCount == 1) { DecodeReader->sum1 = bit; @@ -839,17 +840,14 @@ static int inline __attribute__((always_inline)) Handle15693SampleFromReader(uin } if (DecodeReader->posCount == 8) { DecodeReader->posCount = 0; - int corr10 = DecodeReader->sum1 - DecodeReader->sum2; - int corr01 = DecodeReader->sum2 - DecodeReader->sum1; - int corr11 = (DecodeReader->sum1 + DecodeReader->sum2) / 2; - if (corr01 > corr11 && corr01 > corr10) { // EOF + if (DecodeReader->sum1 <= 1 && DecodeReader->sum2 >= 3) { // EOF LED_B_OFF(); // Finished receiving DecodeReaderReset(DecodeReader); if (DecodeReader->byteCount != 0) { return true; } } - if (corr10 > corr11) { // detected a 2bit position + if (DecodeReader->sum1 >= 3 && DecodeReader->sum2 <= 1) { // detected a 2bit position DecodeReader->shiftReg >>= 2; DecodeReader->shiftReg |= (DecodeReader->bitCount << 6); } @@ -869,6 +867,7 @@ static int inline __attribute__((always_inline)) Handle15693SampleFromReader(uin break; case STATE_READER_RECEIVE_DATA_1_OUT_OF_256: + bit = !!bit; DecodeReader->posCount++; if (DecodeReader->posCount == 1) { DecodeReader->sum1 = bit; @@ -881,17 +880,14 @@ static int inline __attribute__((always_inline)) Handle15693SampleFromReader(uin } if (DecodeReader->posCount == 8) { DecodeReader->posCount = 0; - int corr10 = DecodeReader->sum1 - DecodeReader->sum2; - int corr01 = DecodeReader->sum2 - DecodeReader->sum1; - int corr11 = (DecodeReader->sum1 + DecodeReader->sum2) / 2; - if (corr01 > corr11 && corr01 > corr10) { // EOF + if (DecodeReader->sum1 <= 1 && DecodeReader->sum2 >= 3) { // EOF LED_B_OFF(); // Finished receiving DecodeReaderReset(DecodeReader); if (DecodeReader->byteCount != 0) { return true; } } - if (corr10 > corr11) { // detected the bit position + if (DecodeReader->sum1 >= 3 && DecodeReader->sum2 <= 1) { // detected the bit position DecodeReader->shiftReg = DecodeReader->bitCount; } if (DecodeReader->bitCount == 255) { // we have a full byte diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index 48b62b17..6f7cc4a4 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -144,7 +144,7 @@ int CmdHFiClassSim(const char *Cmd) { uint8_t simType = 0; uint8_t CSN[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - if (strlen(Cmd)<1) { + if (strlen(Cmd) < 1) { return usage_hf_iclass_sim(); } simType = param_get8ex(Cmd, 0, 0, 10); @@ -157,7 +157,6 @@ int CmdHFiClassSim(const char *Cmd) { PrintAndLog("--simtype:%02x csn:%s", simType, sprint_hex(CSN, 8)); } - uint8_t numberOfCSNs = 0; if (simType == ICLASS_SIM_MODE_READER_ATTACK) { UsbCommand c = {CMD_SIMULATE_TAG_ICLASS, {simType, NUM_CSNS}}; UsbCommand resp = {0}; @@ -196,8 +195,8 @@ int CmdHFiClassSim(const char *Cmd) { saveFile("iclass_mac_attack", "bin", dump,datalen); free(dump); - } else if (simType == ICLASS_SIM_MODE_CSN || simType == ICLASS_SIM_MODE_CSN_DEFAULT) { - UsbCommand c = {CMD_SIMULATE_TAG_ICLASS, {simType, numberOfCSNs}}; + } else if (simType == ICLASS_SIM_MODE_CSN || simType == ICLASS_SIM_MODE_CSN_DEFAULT || simType == ICLASS_SIM_MODE_FULL) { + UsbCommand c = {CMD_SIMULATE_TAG_ICLASS, {simType, 0}}; memcpy(c.d.asBytes, CSN, 8); SendCommand(&c); From 8ddb81a2175d69da00f1def3aec571d23e2563b9 Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Wed, 25 Sep 2019 18:40:05 +0200 Subject: [PATCH 134/189] fix 'hf iclass sim': * implement CHECK[Kc] based on @sherhannn79 * implement UPDATE based on @sherhannn79 --- armsrc/iclass.c | 64 ++++++++++++++++++++++++++++++++++++---------- common/protocols.h | 3 ++- 2 files changed, 52 insertions(+), 15 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 2e3a4db8..0b77a039 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -783,7 +783,8 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { // free eventually allocated BigBuf memory BigBuf_free_keep_EM(); - State cipher_state; + State cipher_state_KC; + State cipher_state_KD; uint8_t *emulator = BigBuf_get_EM_addr(); uint8_t *csn = emulator; @@ -802,18 +803,20 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { AppendCrc(anticoll_data, 8); AppendCrc(csn_data, 8); - uint8_t diversified_key[8] = { 0 }; + uint8_t diversified_key_d[8] = { 0 }; + uint8_t diversified_key_c[8] = { 0 }; // e-Purse uint8_t card_challenge_data[8] = { 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; //uint8_t card_challenge_data[8] = { 0 }; if (simulationMode == ICLASS_SIM_MODE_FULL) { - // The diversified key should be stored on block 3 - // Get the diversified key from emulator memory - memcpy(diversified_key, emulator + (8 * 3), 8); + // Get the diversified keys from emulator memory + memcpy(diversified_key_d, emulator + (8 * 3), 8); + memcpy(diversified_key_c, emulator + (8 * 4), 8); // Card challenge, a.k.a e-purse is on block 2 memcpy(card_challenge_data, emulator + (8 * 2), 8); - // Precalculate the cipher state, feeding it the CC - cipher_state = opt_doTagMAC_1(card_challenge_data, diversified_key); + // Precalculate the cipher states, feeding it the CC + cipher_state_KD = opt_doTagMAC_1(card_challenge_data, diversified_key_d); + cipher_state_KC = opt_doTagMAC_1(card_challenge_data, diversified_key_c); } // save card challenge for sim2,4 attack if (reader_mac_buf != NULL) { @@ -1049,7 +1052,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { } } else if ((receivedCmd[0] == ICLASS_CMD_READCHECK_KD - || receivedCmd[0] == ICLASS_CMD_READCHECK_KC) && len == 2) { + || receivedCmd[0] == ICLASS_CMD_READCHECK_KC) && receivedCmd[1] == 0x02 && len == 2) { // Read e-purse (88 02 || 18 02) if (chip_state == SELECTED) { modulated_response = resp_cc; @@ -1059,12 +1062,17 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { LED_B_ON(); } - } else if (receivedCmd[0] == ICLASS_CMD_CHECK && len == 9) { + } else if ((receivedCmd[0] == ICLASS_CMD_CHECK_KC + || receivedCmd[0] == ICLASS_CMD_CHECK_KD) && len == 9) { // Reader random and reader MAC!!! if (chip_state == SELECTED) { if (simulationMode == ICLASS_SIM_MODE_FULL) { //NR, from reader, is in receivedCmd+1 - opt_doTagMAC_2(cipher_state, receivedCmd+1, data_generic_trace, diversified_key); + if (receivedCmd[0] == ICLASS_CMD_CHECK_KC) { + opt_doTagMAC_2(cipher_state_KC, receivedCmd+1, data_generic_trace, diversified_key_c); + } else { + opt_doTagMAC_2(cipher_state_KD, receivedCmd+1, data_generic_trace, diversified_key_d); + } trace_data = data_generic_trace; trace_data_size = 4; CodeIso15693AsTag(trace_data, trace_data_size); @@ -1093,7 +1101,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { } else if (simulationMode == ICLASS_SIM_MODE_FULL && receivedCmd[0] == ICLASS_CMD_READ4 && len == 4) { // 0x06 //Read 4 blocks if (chip_state == SELECTED) { - memcpy(data_generic_trace, emulator + (receivedCmd[1] << 3), 8 * 4); + memcpy(data_generic_trace, emulator + receivedCmd[1]*8, 8 * 4); AppendCrc(data_generic_trace, 8 * 4); trace_data = data_generic_trace; trace_data_size = 8 * 4 + 2; @@ -1104,11 +1112,39 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { } } else if (receivedCmd[0] == ICLASS_CMD_UPDATE && (len == 12 || len == 14)) { - // Probably the reader wants to update the nonce. Let's just ignore that for now. - // OBS! If this is implemented, don't forget to regenerate the cipher_state // We're expected to respond with the data+crc, exactly what's already in the receivedCmd // receivedCmd is now UPDATE 1b | ADDRESS 1b | DATA 8b | Signature 4b or CRC 2b if (chip_state == SELECTED) { + uint8_t blockNo = receivedCmd[1]; + if (blockNo == 2) { // update e-purse + memcpy(card_challenge_data, receivedCmd+2, 8); + CodeIso15693AsTag(card_challenge_data, sizeof(card_challenge_data)); + memcpy(resp_cc, ToSend, ToSendMax); + resp_cc_len = ToSendMax; + cipher_state_KD = opt_doTagMAC_1(card_challenge_data, diversified_key_d); + cipher_state_KC = opt_doTagMAC_1(card_challenge_data, diversified_key_c); + if (simulationMode == ICLASS_SIM_MODE_FULL) { + memcpy(emulator + 8*2, card_challenge_data, 8); + } + } else if (blockNo == 3) { // update Kd + for (int i = 0; i < 8; i++){ + diversified_key_d[i] = diversified_key_d[i] ^ receivedCmd[2 + i]; + } + cipher_state_KD = opt_doTagMAC_1(card_challenge_data, diversified_key_d); + if (simulationMode == ICLASS_SIM_MODE_FULL) { + memcpy(emulator + 8*3, diversified_key_d, 8); + } + } else if (blockNo == 4) { // update Kc + for(int i = 0; i < 8; i++){ + diversified_key_c[i] = diversified_key_c[i] ^ receivedCmd[2 + i]; + } + cipher_state_KC = opt_doTagMAC_1(card_challenge_data, diversified_key_c); + if (simulationMode == ICLASS_SIM_MODE_FULL) { + memcpy(emulator + 8*4, diversified_key_c, 8); + } + } else if (simulationMode == ICLASS_SIM_MODE_FULL) { // update any other data block + memcpy(emulator + 8*blockNo, receivedCmd+2, 8); + } memcpy(data_generic_trace, receivedCmd + 2, 8); AppendCrc(data_generic_trace, 8); trace_data = data_generic_trace; @@ -1772,7 +1808,7 @@ void iClass_ReadCheck(uint8_t blockNo, uint8_t keyType) { } void iClass_Authentication(uint8_t *MAC) { - uint8_t check[] = { ICLASS_CMD_CHECK, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t check[] = { ICLASS_CMD_CHECK_KD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t resp[ICLASS_BUFFER_SIZE]; memcpy(check+5, MAC, 4); bool isOK; diff --git a/common/protocols.h b/common/protocols.h index 9de72661..703855f6 100644 --- a/common/protocols.h +++ b/common/protocols.h @@ -96,7 +96,8 @@ NXP/Philips CUSTOM COMMANDS #define ICLASS_CMD_PAGESEL 0x84 #define ICLASS_CMD_READCHECK_KD 0x88 #define ICLASS_CMD_READCHECK_KC 0x18 -#define ICLASS_CMD_CHECK 0x05 +#define ICLASS_CMD_CHECK_KC 0x95 +#define ICLASS_CMD_CHECK_KD 0x05 #define ICLASS_CMD_DETECT 0x0F #define ICLASS_CMD_HALT 0x00 #define ICLASS_CMD_UPDATE 0x87 From 26d0156a469ce972c5115a96b96551664ff4dd2f Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Mon, 30 Sep 2019 07:29:20 +0100 Subject: [PATCH 135/189] fix 'hf iclass eload' (thanks to @sherhannn79) --- CHANGELOG.md | 3 ++- client/cmdhficlass.c | 14 ++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e95ccde6..fdd499fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Wrong UID at HitagS simulation - `hf 15 sim` now works as expected (piwi) - `hf mf chk t` save to emulator memory now works as expected (mwalker) - - Fix `hf mf sim` - wrong access rights to write key B in trailer (@McEloff) +- Fix `hf mf sim` - wrong access rights to write key B in trailer (@McEloff) +- allow files > 512Bytes in 'hf iclass eload' (@Sherhannn79) ### Added - Added to `hf 14a apdu` print apdu and compose apdu (@merlokk) diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index a2e31754..35cf350c 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -294,14 +294,13 @@ int CmdHFiClassELoad(const char *Cmd) { //File handling and reading FILE *f; char filename[FILE_PATH_SIZE]; - if(opt == 'f' && param_getstr(Cmd, 1, filename, sizeof(filename)) > 0) - { + if (opt == 'f' && param_getstr(Cmd, 1, filename, sizeof(filename)) > 0) { f = fopen(filename, "rb"); - }else{ + } else { return hf_iclass_eload_usage(); } - if(!f) { + if (!f) { PrintAndLog("Failed to read from file '%s'", filename); return 1; } @@ -324,8 +323,7 @@ int CmdHFiClassELoad(const char *Cmd) { printIclassDumpInfo(dump); //Validate - if (bytes_read < fsize) - { + if (bytes_read < fsize) { prnlog("Error, could only read %d bytes (should be %d)",bytes_read, fsize ); free(dump); return 1; @@ -334,10 +332,10 @@ int CmdHFiClassELoad(const char *Cmd) { uint32_t bytes_sent = 0; uint32_t bytes_remaining = bytes_read; - while(bytes_remaining > 0){ + while (bytes_remaining > 0) { uint32_t bytes_in_packet = MIN(USB_CMD_DATA_SIZE, bytes_remaining); UsbCommand c = {CMD_ICLASS_EML_MEMSET, {bytes_sent,bytes_in_packet,0}}; - memcpy(c.d.asBytes, dump, bytes_in_packet); + memcpy(c.d.asBytes, dump+bytes_sent, bytes_in_packet); SendCommand(&c); bytes_remaining -= bytes_in_packet; bytes_sent += bytes_in_packet; From ae60ceca92b802fc980a883cb280d1c57b7932cf Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Tue, 1 Oct 2019 21:03:18 +0200 Subject: [PATCH 136/189] fix 'hf iclass sim' * add simulation of multiple pages (PAGESEL by @sherhannn9) * maintain cipher states per page * update cipher state after UPDATE commands (@sherhannn9) * add simulation of personalization mode * respond with SOF on HALT * display "" instead of "0f" in 'hf list iclass' * standard LED handling --- armsrc/iclass.c | 178 ++++++++++++++++++++++++++++----------------- client/cmdhflist.c | 39 +++++----- 2 files changed, 132 insertions(+), 85 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 0b77a039..d8f68c78 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -758,15 +758,8 @@ void rotateCSN(uint8_t* originalCSN, uint8_t* rotatedCSN) { // Encode SOF only static void CodeIClassTagSOF() { - //So far a dummy implementation, not used - //int lastProxToAirDuration =0; - ToSendReset(); - // Send SOF ToSend[++ToSendMax] = 0x1D; -// lastProxToAirDuration = 8*ToSendMax - 3*8;//Not counting zeroes in the beginning - - // Convert from last byte pos to length ToSendMax++; } @@ -783,16 +776,20 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { // free eventually allocated BigBuf memory BigBuf_free_keep_EM(); - State cipher_state_KC; - State cipher_state_KD; + uint16_t page_size = 32 * 8; + uint8_t current_page = 0; + // maintain cipher states for both credit and debit key for each page + State cipher_state_KC[8]; + State cipher_state_KD[8]; + State *cipher_state = &cipher_state_KD[0]; + uint8_t *emulator = BigBuf_get_EM_addr(); uint8_t *csn = emulator; - uint8_t sof_data[] = { 0x0F } ; // CSN followed by two CRC bytes - uint8_t anticoll_data[10] = { 0 }; - uint8_t csn_data[10] = { 0 }; + uint8_t anticoll_data[10]; + uint8_t csn_data[10]; memcpy(csn_data, csn, sizeof(csn_data)); Dbprintf("Simulating CSN %02x%02x%02x%02x%02x%02x%02x%02x", csn[0], csn[1], csn[2], csn[3], csn[4], csn[5], csn[6], csn[7]); @@ -803,26 +800,56 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { AppendCrc(anticoll_data, 8); AppendCrc(csn_data, 8); - uint8_t diversified_key_d[8] = { 0 }; - uint8_t diversified_key_c[8] = { 0 }; + uint8_t diversified_key_d[8]; + uint8_t diversified_key_c[8]; + uint8_t *diversified_key = diversified_key_d; + + // configuration block + uint8_t conf_block[10] = {0x12, 0xFF, 0xFF, 0xFF, 0x7F, 0x1F, 0xFF, 0x3C, 0x00, 0x00}; + AppendCrc(conf_block, 8); + // e-Purse uint8_t card_challenge_data[8] = { 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - //uint8_t card_challenge_data[8] = { 0 }; + if (simulationMode == ICLASS_SIM_MODE_FULL) { - // Get the diversified keys from emulator memory - memcpy(diversified_key_d, emulator + (8 * 3), 8); - memcpy(diversified_key_c, emulator + (8 * 4), 8); - // Card challenge, a.k.a e-purse is on block 2 - memcpy(card_challenge_data, emulator + (8 * 2), 8); - // Precalculate the cipher states, feeding it the CC - cipher_state_KD = opt_doTagMAC_1(card_challenge_data, diversified_key_d); - cipher_state_KC = opt_doTagMAC_1(card_challenge_data, diversified_key_c); + // initialize from page 0 + memcpy(conf_block, emulator + 8 * 1, 8); + memcpy(card_challenge_data, emulator + 8 * 2, 8); // e-purse + memcpy(diversified_key_d, emulator + 8 * 3, 8); // Kd + memcpy(diversified_key_c, emulator + 8 * 4, 8); // Kc } + // save card challenge for sim2,4 attack if (reader_mac_buf != NULL) { memcpy(reader_mac_buf, card_challenge_data, 8); } + if (conf_block[5] & 0x80) { + page_size = 256 * 8; + } + + // From PicoPass DS: + // When the page is in personalization mode this bit is equal to 1. + // Once the application issuer has personalized and coded its dedicated areas, this bit must be set to 0: + // the page is then "in application mode". + bool personalization_mode = conf_block[7] & 0x80; + + // chip memory may be divided in 8 pages + uint8_t max_page = conf_block[4] & 0x10 ? 0 : 7; + + // Precalculate the cipher states, feeding it the CC + cipher_state_KD[0] = opt_doTagMAC_1(card_challenge_data, diversified_key_d); + cipher_state_KC[0] = opt_doTagMAC_1(card_challenge_data, diversified_key_c); + if (simulationMode == ICLASS_SIM_MODE_FULL) { + for (int i = 1; i < max_page; i++) { + uint8_t *epurse = emulator + i*page_size + 8*2; + uint8_t *Kd = emulator + i*page_size + 8*3; + uint8_t *Kc = emulator + i*page_size + 8*4; + cipher_state_KD[i] = opt_doTagMAC_1(epurse, Kd); + cipher_state_KC[i] = opt_doTagMAC_1(epurse, Kc); + } + } + int exitLoop = 0; // Reader 0a // Tag 0f @@ -837,7 +864,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { int trace_data_size = 0; // Respond SOF -- takes 1 bytes - uint8_t *resp_sof = BigBuf_malloc(2); + uint8_t *resp_sof = BigBuf_malloc(1); int resp_sof_Len; // Anticollision CSN (rotated CSN) @@ -853,8 +880,6 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { // configuration (block 1) picopass 2ks uint8_t *resp_conf = BigBuf_malloc(22); int resp_conf_len; - uint8_t conf_data[10] = {0x12, 0xFF, 0xFF, 0xFF, 0x7F, 0x1F, 0xFF, 0x3C, 0x00, 0x00}; - AppendCrc(conf_data, 8); // e-Purse (block 2) // 18: Takes 2 bytes for SOF/EOF and 8 * 2 = 16 bytes (2 bytes/bit) @@ -877,7 +902,6 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { int len; // Prepare card messages - ToSendMax = 0; // First card answer: SOF only CodeIClassTagSOF(); @@ -895,7 +919,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { resp_csn_len = ToSendMax; // Configuration (block 1) - CodeIso15693AsTag(conf_data, sizeof(conf_data)); + CodeIso15693AsTag(conf_block, sizeof(conf_block)); memcpy(resp_conf, ToSend, ToSendMax); resp_conf_len = ToSendMax; @@ -918,16 +942,11 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { uint8_t *data_generic_trace = BigBuf_malloc(32 + 2); // 32 bytes data + 2byte CRC is max tag answer uint8_t *data_response = BigBuf_malloc( (32 + 2) * 2 + 2); - LED_A_ON(); bool buttonPressed = false; enum { IDLE, ACTIVATED, SELECTED, HALTED } chip_state = IDLE; while (!exitLoop) { WDT_HIT(); - LED_B_OFF(); - //Signal tracer - // Can be used to get a trigger for an oscilloscope.. - LED_C_OFF(); uint32_t reader_eof_time = 0; len = GetIso15693CommandFromReader(receivedCmd, MAX_FRAME_SIZE, &reader_eof_time); @@ -936,9 +955,6 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { break; } - //Signal tracer - LED_C_ON(); - // Now look at the reader command and provide appropriate responses // default is no response: modulated_response = NULL; @@ -951,8 +967,6 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { if (chip_state != HALTED) { modulated_response = resp_sof; modulated_response_size = resp_sof_Len; - trace_data = sof_data; - trace_data_size = sizeof(sof_data); chip_state = ACTIVATED; } @@ -1004,8 +1018,8 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { case 1: // configuration (block 01) modulated_response = resp_conf; modulated_response_size = resp_conf_len; - trace_data = conf_data; - trace_data_size = sizeof(conf_data); + trace_data = conf_block; + trace_data_size = sizeof(conf_block); break; case 2: // e-purse (block 02) modulated_response = resp_cc; @@ -1039,7 +1053,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { trace_data = ff_data; trace_data_size = sizeof(ff_data); } else { // use data from emulator memory - memcpy(data_generic_trace, emulator + 8*blockNo, 8); + memcpy(data_generic_trace, emulator + current_page*page_size + 8*blockNo, 8); AppendCrc(data_generic_trace, 8); trace_data = data_generic_trace; trace_data_size = 10; @@ -1055,11 +1069,17 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { || receivedCmd[0] == ICLASS_CMD_READCHECK_KC) && receivedCmd[1] == 0x02 && len == 2) { // Read e-purse (88 02 || 18 02) if (chip_state == SELECTED) { + if(receivedCmd[0] == ICLASS_CMD_READCHECK_KD){ + cipher_state = &cipher_state_KD[current_page]; + diversified_key = diversified_key_d; + } else { + cipher_state = &cipher_state_KC[current_page]; + diversified_key = diversified_key_c; + } modulated_response = resp_cc; modulated_response_size = resp_cc_len; trace_data = card_challenge_data; trace_data_size = sizeof(card_challenge_data); - LED_B_ON(); } } else if ((receivedCmd[0] == ICLASS_CMD_CHECK_KC @@ -1068,11 +1088,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { if (chip_state == SELECTED) { if (simulationMode == ICLASS_SIM_MODE_FULL) { //NR, from reader, is in receivedCmd+1 - if (receivedCmd[0] == ICLASS_CMD_CHECK_KC) { - opt_doTagMAC_2(cipher_state_KC, receivedCmd+1, data_generic_trace, diversified_key_c); - } else { - opt_doTagMAC_2(cipher_state_KD, receivedCmd+1, data_generic_trace, diversified_key_d); - } + opt_doTagMAC_2(*cipher_state, receivedCmd+1, data_generic_trace, diversified_key); trace_data = data_generic_trace; trace_data_size = 4; CodeIso15693AsTag(trace_data, trace_data_size); @@ -1095,13 +1111,16 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { } else if (receivedCmd[0] == ICLASS_CMD_HALT && len == 1) { if (chip_state == SELECTED) { // Reader ends the session + modulated_response = resp_sof; + modulated_response_size = resp_sof_Len; chip_state = HALTED; } } else if (simulationMode == ICLASS_SIM_MODE_FULL && receivedCmd[0] == ICLASS_CMD_READ4 && len == 4) { // 0x06 //Read 4 blocks if (chip_state == SELECTED) { - memcpy(data_generic_trace, emulator + receivedCmd[1]*8, 8 * 4); + uint8_t blockNo = receivedCmd[1]; + memcpy(data_generic_trace, emulator + current_page*page_size + blockNo*8, 8 * 4); AppendCrc(data_generic_trace, 8 * 4); trace_data = data_generic_trace; trace_data_size = 8 * 4 + 2; @@ -1121,29 +1140,37 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { CodeIso15693AsTag(card_challenge_data, sizeof(card_challenge_data)); memcpy(resp_cc, ToSend, ToSendMax); resp_cc_len = ToSendMax; - cipher_state_KD = opt_doTagMAC_1(card_challenge_data, diversified_key_d); - cipher_state_KC = opt_doTagMAC_1(card_challenge_data, diversified_key_c); + cipher_state_KD[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_key_d); + cipher_state_KC[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_key_c); if (simulationMode == ICLASS_SIM_MODE_FULL) { - memcpy(emulator + 8*2, card_challenge_data, 8); + memcpy(emulator + current_page*page_size + 8*2, card_challenge_data, 8); } } else if (blockNo == 3) { // update Kd - for (int i = 0; i < 8; i++){ - diversified_key_d[i] = diversified_key_d[i] ^ receivedCmd[2 + i]; + for (int i = 0; i < 8; i++) { + if (personalization_mode) { + diversified_key_d[i] = receivedCmd[2 + i]; + } else { + diversified_key_d[i] ^= receivedCmd[2 + i]; + } } - cipher_state_KD = opt_doTagMAC_1(card_challenge_data, diversified_key_d); + cipher_state_KD[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_key_d); if (simulationMode == ICLASS_SIM_MODE_FULL) { - memcpy(emulator + 8*3, diversified_key_d, 8); + memcpy(emulator + current_page*page_size + 8*3, diversified_key_d, 8); } } else if (blockNo == 4) { // update Kc - for(int i = 0; i < 8; i++){ - diversified_key_c[i] = diversified_key_c[i] ^ receivedCmd[2 + i]; + for (int i = 0; i < 8; i++) { + if (personalization_mode) { + diversified_key_c[i] = receivedCmd[2 + i]; + } else { + diversified_key_c[i] ^= receivedCmd[2 + i]; + } } - cipher_state_KC = opt_doTagMAC_1(card_challenge_data, diversified_key_c); + cipher_state_KC[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_key_c); if (simulationMode == ICLASS_SIM_MODE_FULL) { - memcpy(emulator + 8*4, diversified_key_c, 8); + memcpy(emulator + current_page*page_size + 8*4, diversified_key_c, 8); } } else if (simulationMode == ICLASS_SIM_MODE_FULL) { // update any other data block - memcpy(emulator + 8*blockNo, receivedCmd+2, 8); + memcpy(emulator + current_page*page_size + 8*blockNo, receivedCmd+2, 8); } memcpy(data_generic_trace, receivedCmd + 2, 8); AppendCrc(data_generic_trace, 8); @@ -1157,11 +1184,24 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { } else if (receivedCmd[0] == ICLASS_CMD_PAGESEL && len == 4) { // Pagesel + // Chips with a single page will not answer to this command + // Otherwise, we should answer 8bytes (block) + 2bytes CRC if (chip_state == SELECTED) { - // Pagesel enables to select a page in the selected chip memory and return its configuration block - // Chips with a single page will not answer to this command - // It appears we're fine ignoring this. - // Otherwise, we should answer 8bytes (block) + 2bytes CRC + if (simulationMode == ICLASS_SIM_MODE_FULL && max_page > 0) { + current_page = receivedCmd[1]; + memcpy(data_generic_trace, emulator + current_page*page_size + 8*1, 8); + memcpy(diversified_key_d, emulator + current_page*page_size + 8*3, 8); + memcpy(diversified_key_c, emulator + current_page*page_size + 8*4, 8); + cipher_state = &cipher_state_KD[current_page]; + personalization_mode = data_generic_trace[7] & 0x80; + AppendCrc(data_generic_trace, 8); + trace_data = data_generic_trace; + trace_data_size = 10; + CodeIso15693AsTag(trace_data, trace_data_size); + memcpy(data_response, ToSend, ToSendMax); + modulated_response = data_response; + modulated_response_size = ToSendMax; + } } } else if (receivedCmd[0] == 0x26 && len == 5) { @@ -1189,10 +1229,6 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { } - LED_A_OFF(); - LED_B_OFF(); - LED_C_OFF(); - if (buttonPressed) { DbpString("Button pressed"); @@ -1213,6 +1249,9 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { * @param datain */ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain) { + + LED_A_ON(); + uint32_t simType = arg0; uint32_t numberOfCSNS = arg1; @@ -1220,6 +1259,7 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain FpgaDownloadAndGo(FPGA_BITSTREAM_HF); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_NO_MODULATION); + LED_D_OFF(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR); StartCountSspClk(); @@ -1270,8 +1310,10 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain // That will speed things up a little, but not required just yet. Dbprintf("The mode is not implemented, reserved for future use"); } + Dbprintf("Done..."); + LED_A_OFF(); } diff --git a/client/cmdhflist.c b/client/cmdhflist.c index 1b8e0955..07a286cc 100644 --- a/client/cmdhflist.c +++ b/client/cmdhflist.c @@ -225,17 +225,18 @@ void annotateIclass(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize) { } break; } - case ICLASS_CMD_SELECT: snprintf(exp,size, "SELECT"); break; - case ICLASS_CMD_PAGESEL: snprintf(exp,size, "PAGESEL(%d)", cmd[1]); break; - case ICLASS_CMD_READCHECK_KC:snprintf(exp,size, "READCHECK[Kc](%d)", cmd[1]); break; - case ICLASS_CMD_READCHECK_KD:snprintf(exp,size, "READCHECK[Kd](%d)", cmd[1]); break; - case ICLASS_CMD_CHECK: snprintf(exp,size, "CHECK"); break; - case ICLASS_CMD_DETECT: snprintf(exp,size, "DETECT"); break; - case ICLASS_CMD_HALT: snprintf(exp,size, "HALT"); break; - case ICLASS_CMD_UPDATE: snprintf(exp,size, "UPDATE(%d)",cmd[1]); break; - case ICLASS_CMD_ACT: snprintf(exp,size, "ACT"); break; - case ICLASS_CMD_READ4: snprintf(exp,size, "READ4(%d)",cmd[1]); break; - default: snprintf(exp,size, "?"); break; + case ICLASS_CMD_SELECT: snprintf(exp,size, "SELECT"); break; + case ICLASS_CMD_PAGESEL: snprintf(exp,size, "PAGESEL(%d)", cmd[1]); break; + case ICLASS_CMD_READCHECK_KC: snprintf(exp,size, "READCHECK[Kc](%d)", cmd[1]); break; + case ICLASS_CMD_READCHECK_KD: snprintf(exp,size, "READCHECK[Kd](%d)", cmd[1]); break; + case ICLASS_CMD_CHECK_KC: + case ICLASS_CMD_CHECK_KD: snprintf(exp,size, "CHECK"); break; + case ICLASS_CMD_DETECT: snprintf(exp,size, "DETECT"); break; + case ICLASS_CMD_HALT: snprintf(exp,size, "HALT"); break; + case ICLASS_CMD_UPDATE: snprintf(exp,size, "UPDATE(%d)",cmd[1]); break; + case ICLASS_CMD_ACT: snprintf(exp,size, "ACT"); break; + case ICLASS_CMD_READ4: snprintf(exp,size, "READ4(%d)",cmd[1]); break; + default: snprintf(exp,size, "?"); break; } return; } @@ -336,7 +337,7 @@ void annotateIso14443_4(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize){ else { int pos = 1; switch (cmd[0] & 0x0c) { - case 0x08: // CID following + case 0x08: // CID following case 0x04: // NAD following pos = 2; break; @@ -906,7 +907,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui timestamp *= 32; duration *= 32; } - + //Check the CRC status uint8_t crcStatus = 2; @@ -969,11 +970,15 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui if (protocol == ISO_14443A || protocol == PROTO_MIFARE) { if (duration < 128 * (9 * data_len)) { line[(data_len-1)/16][((data_len-1)%16) * 4 + 3] = '\''; - } + } } - + if (data_len == 0) { - sprintf(line[0]," "); + if (protocol == ICLASS && duration == 2048) { + sprintf(line[0], " "); + } else { + sprintf(line[0], " "); + } } //--- Draw the CRC column @@ -1014,7 +1019,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui (j == num_lines-1) ? explanation : ""); } } - + if (DecodeMifareData(frame, data_len, parityBytes, isResponse, mfData, &mfDataLen)) { memset(explanation, 0x00, sizeof(explanation)); if (!isResponse) { From 8efd0b80f2d11946b2fc0911cde939f9f93eb40f Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Sat, 5 Oct 2019 17:57:16 +0200 Subject: [PATCH 137/189] fix 'hf iclass sim' * fix tag response timing. iClass differs from ISO15693 in this respect. * speedup CodeIso15693AsTag() * TransmitTo15693Tag(): don't send unmodulated start of SOF * reduce modulation depth in hi_simulate.v * calculate CRC for configuration block when simulating * Show real response time instead of planned response time in 'hf list iclass' --- armsrc/iclass.c | 57 ++++++++++++++++++++++++++------------------- armsrc/iso15693.c | 41 ++++++++++++++++++-------------- armsrc/iso15693.h | 2 +- fpga/fpga_hf.bit | Bin 42175 -> 42175 bytes fpga/hi_simulate.v | 2 +- 5 files changed, 59 insertions(+), 43 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index d8f68c78..0e42fb06 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -59,6 +59,13 @@ static int timeout = 4096; +// iCLASS has a slightly different timing compared to ISO15693. According to the picopass data sheet the tag response is expected 330us after +// the reader command. This is measured from end of reader EOF to first modulation of the tag's SOF which starts with a 56,64us unmodulated period. +// 330us = 140 ssp_clk cycles @ 423,75kHz when simulating. +// 56,64us = 24 ssp_clk_cycles +#define DELAY_ICLASS_VCD_TO_VICC_SIM 140 +#define TAG_SOF_UNMODULATED 24 + //----------------------------------------------------------------------------- // The software UART that receives commands from the reader, and its state // variables. @@ -783,7 +790,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { State cipher_state_KC[8]; State cipher_state_KD[8]; State *cipher_state = &cipher_state_KD[0]; - + uint8_t *emulator = BigBuf_get_EM_addr(); uint8_t *csn = emulator; @@ -800,13 +807,12 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { AppendCrc(anticoll_data, 8); AppendCrc(csn_data, 8); - uint8_t diversified_key_d[8]; - uint8_t diversified_key_c[8]; + uint8_t diversified_key_d[8] = { 0x00 }; + uint8_t diversified_key_c[8] = { 0x00 }; uint8_t *diversified_key = diversified_key_d; - + // configuration block uint8_t conf_block[10] = {0x12, 0xFF, 0xFF, 0xFF, 0x7F, 0x1F, 0xFF, 0x3C, 0x00, 0x00}; - AppendCrc(conf_block, 8); // e-Purse uint8_t card_challenge_data[8] = { 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; @@ -819,6 +825,8 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { memcpy(diversified_key_c, emulator + 8 * 4, 8); // Kc } + AppendCrc(conf_block, 8); + // save card challenge for sim2,4 attack if (reader_mac_buf != NULL) { memcpy(reader_mac_buf, card_challenge_data, 8); @@ -836,7 +844,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { // chip memory may be divided in 8 pages uint8_t max_page = conf_block[4] & 0x10 ? 0 : 7; - + // Precalculate the cipher states, feeding it the CC cipher_state_KD[0] = opt_doTagMAC_1(card_challenge_data, diversified_key_d); cipher_state_KC[0] = opt_doTagMAC_1(card_challenge_data, diversified_key_c); @@ -849,7 +857,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { cipher_state_KC[i] = opt_doTagMAC_1(epurse, Kc); } } - + int exitLoop = 0; // Reader 0a // Tag 0f @@ -1073,7 +1081,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { cipher_state = &cipher_state_KD[current_page]; diversified_key = diversified_key_d; } else { - cipher_state = &cipher_state_KC[current_page]; + cipher_state = &cipher_state_KC[current_page]; diversified_key = diversified_key_c; } modulated_response = resp_cc; @@ -1082,7 +1090,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { trace_data_size = sizeof(card_challenge_data); } - } else if ((receivedCmd[0] == ICLASS_CMD_CHECK_KC + } else if ((receivedCmd[0] == ICLASS_CMD_CHECK_KC || receivedCmd[0] == ICLASS_CMD_CHECK_KD) && len == 9) { // Reader random and reader MAC!!! if (chip_state == SELECTED) { @@ -1148,22 +1156,22 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { } else if (blockNo == 3) { // update Kd for (int i = 0; i < 8; i++) { if (personalization_mode) { - diversified_key_d[i] = receivedCmd[2 + i]; + diversified_key_d[i] = receivedCmd[2 + i]; } else { diversified_key_d[i] ^= receivedCmd[2 + i]; - } + } } - cipher_state_KD[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_key_d); + cipher_state_KD[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_key_d); if (simulationMode == ICLASS_SIM_MODE_FULL) { memcpy(emulator + current_page*page_size + 8*3, diversified_key_d, 8); } - } else if (blockNo == 4) { // update Kc + } else if (blockNo == 4) { // update Kc for (int i = 0; i < 8; i++) { if (personalization_mode) { - diversified_key_c[i] = receivedCmd[2 + i]; + diversified_key_c[i] = receivedCmd[2 + i]; } else { diversified_key_c[i] ^= receivedCmd[2 + i]; - } + } } cipher_state_KC[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_key_c); if (simulationMode == ICLASS_SIM_MODE_FULL) { @@ -1171,7 +1179,7 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { } } else if (simulationMode == ICLASS_SIM_MODE_FULL) { // update any other data block memcpy(emulator + current_page*page_size + 8*blockNo, receivedCmd+2, 8); - } + } memcpy(data_generic_trace, receivedCmd + 2, 8); AppendCrc(data_generic_trace, 8); trace_data = data_generic_trace; @@ -1185,20 +1193,20 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { } else if (receivedCmd[0] == ICLASS_CMD_PAGESEL && len == 4) { // Pagesel // Chips with a single page will not answer to this command - // Otherwise, we should answer 8bytes (block) + 2bytes CRC + // Otherwise, we should answer 8bytes (conf block 1) + 2bytes CRC if (chip_state == SELECTED) { if (simulationMode == ICLASS_SIM_MODE_FULL && max_page > 0) { current_page = receivedCmd[1]; memcpy(data_generic_trace, emulator + current_page*page_size + 8*1, 8); memcpy(diversified_key_d, emulator + current_page*page_size + 8*3, 8); - memcpy(diversified_key_c, emulator + current_page*page_size + 8*4, 8); + memcpy(diversified_key_c, emulator + current_page*page_size + 8*4, 8); cipher_state = &cipher_state_KD[current_page]; personalization_mode = data_generic_trace[7] & 0x80; AppendCrc(data_generic_trace, 8); trace_data = data_generic_trace; trace_data_size = 10; CodeIso15693AsTag(trace_data, trace_data_size); - memcpy(data_response, ToSend, ToSendMax); + memcpy(data_response, ToSend, ToSendMax); modulated_response = data_response; modulated_response_size = ToSendMax; } @@ -1219,11 +1227,11 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { } /** - A legit tag has about 311,5us delay between reader EOT and tag SOF. + A legit tag has about 273,4us delay between reader EOT and tag SOF. **/ if (modulated_response_size > 0) { - uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM - DELAY_ARM_TO_READER_SIM; - TransmitTo15693Reader(modulated_response, modulated_response_size, response_time, false); + uint32_t response_time = reader_eof_time + DELAY_ICLASS_VCD_TO_VICC_SIM - TAG_SOF_UNMODULATED - DELAY_ARM_TO_READER_SIM; + TransmitTo15693Reader(modulated_response, modulated_response_size, &response_time, 0, false); LogTrace(trace_data, trace_data_size, response_time + DELAY_ARM_TO_READER_SIM, response_time + (modulated_response_size << 6) + DELAY_ARM_TO_READER_SIM, NULL, false); } @@ -1249,9 +1257,9 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { * @param datain */ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain) { - + LED_A_ON(); - + uint32_t simType = arg0; uint32_t numberOfCSNS = arg1; @@ -1559,6 +1567,7 @@ static uint8_t handshakeIclassTag_ext(uint8_t *card_data, bool use_credit_key) { ReaderTransmitIClass(act_all, 1); // Card present? if (!ReaderReceiveIClass(resp)) return read_status;//Fail + //Send Identify ReaderTransmitIClass(identify, 1); //We expect a 10-byte response here, 8 byte anticollision-CSN and 2 byte CRC diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index dbc1ca4c..85af0859 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -246,6 +246,8 @@ static void CodeIso15693AsReader256(uint8_t *cmd, int n) // } // } +static const uint8_t encode_4bits[16] = { 0xaa, 0x6a, 0x9a, 0x5a, 0xa6, 0x66, 0x96, 0x56, 0xa9, 0x69, 0x99, 0x59, 0xa5, 0x65, 0x95, 0x55 }; + void CodeIso15693AsTag(uint8_t *cmd, size_t len) { /* * SOF comprises 3 parts; @@ -280,16 +282,9 @@ void CodeIso15693AsTag(uint8_t *cmd, size_t len) { ToSend[++ToSendMax] = 0x1D; // 00011101 // data - for(int i = 0; i < len; i++) { - for(int j = 0; j < 8; j++) { - if ((cmd[i] >> j) & 0x01) { - ToSendStuffBit(0); - ToSendStuffBit(1); - } else { - ToSendStuffBit(1); - ToSendStuffBit(0); - } - } + for (int i = 0; i < len; i++) { + ToSend[++ToSendMax] = encode_4bits[cmd[i] & 0xF]; + ToSend[++ToSendMax] = encode_4bits[cmd[i] >> 4]; } // EOF @@ -327,19 +322,32 @@ static void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t start_time) //----------------------------------------------------------------------------- // Transmit the tag response (to the reader) that was placed in cmd[]. //----------------------------------------------------------------------------- -void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t start_time, bool slow) { +void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, uint32_t slot_time, bool slow) { // don't use the FPGA_HF_SIMULATOR_MODULATE_424K_8BIT minor mode. It would spoil GetCountSspClk() FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_424K); - uint8_t shift_delay = start_time & 0x00000007; + uint32_t modulation_start_time = *start_time + 3 * 8; // no need to transfer the unmodulated start of SOF + + while (GetCountSspClk() > (modulation_start_time & 0xfffffff8) + 3) { // we will miss the intended time + if (slot_time) { + modulation_start_time += slot_time; // use next available slot + } else { + modulation_start_time = (modulation_start_time & 0xfffffff8) + 8; // next possible time + } + } - while (GetCountSspClk() < (start_time & 0xfffffff8)) ; + while (GetCountSspClk() < (modulation_start_time & 0xfffffff8)) + /* wait */ ; + + uint8_t shift_delay = modulation_start_time & 0x00000007; + + *start_time = modulation_start_time - 3 * 8; LED_C_ON(); uint8_t bits_to_shift = 0x00; uint8_t bits_to_send = 0x00; - for(size_t c = 0; c < len; c++) { - for (int i = 7; i >= 0; i--) { + for (size_t c = 0; c < len; c++) { + for (int i = (c==0?4:7); i >= 0; i--) { uint8_t cmd_bits = ((cmd[c] >> i) & 0x01) ? 0xff : 0x00; for (int j = 0; j < (slow?4:1); ) { if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { @@ -361,7 +369,6 @@ void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t start_time, } } LED_C_OFF(); - } @@ -1529,7 +1536,7 @@ void SimTagIso15693(uint32_t parameter, uint8_t *uid) if ((cmd_len >= 5) && (cmd[0] & ISO15693_REQ_INVENTORY) && (cmd[1] == ISO15693_INVENTORY)) { // TODO: check more flags bool slow = !(cmd[0] & ISO15693_REQ_DATARATE_HIGH); start_time = eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM - DELAY_ARM_TO_READER_SIM; - TransmitTo15693Reader(ToSend, ToSendMax, start_time, slow); + TransmitTo15693Reader(ToSend, ToSendMax, &start_time, 0, slow); } Dbprintf("%d bytes read from reader:", cmd_len); diff --git a/armsrc/iso15693.h b/armsrc/iso15693.h index 7964d79e..7d2e7598 100644 --- a/armsrc/iso15693.h +++ b/armsrc/iso15693.h @@ -26,7 +26,7 @@ void CodeIso15693AsTag(uint8_t *cmd, size_t len); int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eof_time); -void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t start_time, bool slow); +void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, uint32_t slot_time, bool slow); void SnoopIso15693(void); void AcquireRawAdcSamplesIso15693(void); void ReaderIso15693(uint32_t parameter); diff --git a/fpga/fpga_hf.bit b/fpga/fpga_hf.bit index 1bd3c416fe728c26ee204ede9bc882c8f87486c8..44b2428040ab74e66878d78bf7cc7a79ee3c7266 100644 GIT binary patch literal 42175 zcma&Pe|%Kcoj?4Ub8q6!+)3t=1UD+`%_QJ}lQ2v$B8JH!r0!H{nYMnvFSgrfpV3k` z+qK=)^|cT6yHEFI5@1LojFh%%m-@PdXrra=5I}xN^@33c2r}|@U9_&f&`6`AjTUWy zAkX{EBs1}k@AKN(KlV7B+&Sl-^ZC3#@Av0(PN~E@p8G!{*L_s+K>Od{_kXuNP}lz8 zec$}nn)>g4a}C{3?$AFs1pnoGi-JM=Ch4KzqB|BY3N8#b(i$pR)VOrf9ZN$&`WDeZ z`&E3N{^|dCAV|VRMArmeG5Pn1 z`lurNFaM1`F7|(VM)v#MbN)Mh{u{sb-x_np|KE7j>_2{HP>ibRTDnG%Lu=`JDkhhp zHR8HhaaHrMEj!so<8*==sBAJY$MMBXm1g(|VBFWglUTxq3unP!nt(CG7g( z-67_qgz$Y^TM#$ZpzM<&mJHbrq_V}n|J8M^C@;Nm7ed@MDOWZ<2rG6!AOJTNZFXOA9Kcs8&4U>M2P03Y8;xNP*uQEdW~azh&+~(R883@ zUF4=XH}9(2&)yRUP2Xy*iv`4+!bh6LLd0bsr-)OBX}Yw|mSdE7e74_Y z`?1CFFqWJxtz~c19`O%mVl6A@k0q)dt&M59=R`DOwvp2O^OO-9H}(sUS|eKj zw<{B_~tXpIKNunJm7WyK2sc%eFlrtbd18}F;bA+Swf1OLb@zzlGJYY%Ru4<=(SRL$prRnc5_~ z7GthUVW@vc8{*X#8smm3e=AaXB-YUvIOpHbJbd?fz^MwxPl!&JDYQX6C%f)rvwzB7 zq2{FK+^~c`BcJW6Gu6Z$(HhL6hN4C}+%Z9@aJs#l|e8aV*&T_vc)HSq`d{J#1yM+$)nfNDmj&1Dl$%bhd z@;OySwdm8&{Ye%u52(H(RSW# zFg8m*hW3}RTyUMX%Zz>nCUdxtm zep4BxixlRinVNIO?eaNQMWe8i|GVg#62l=ewP}!$539%t=AI6rUccKZZcC# zz_c{c;;@9;FRBE4B{z4iXc#LP;5P)BDwi^*1=%odCqLJW;v+fxs+v8(d(3*S8?e)j zv+!EB`bODCa{=BDy_8!EtMV7(C=cK3?bB<`qdXK1Jccp9OG~5vJ~o!KFF$Q!m_^L{ zGi8*0L~|bS?pKEC&$O6(f2thI*_YqgVWiEF<`FAQV*;BgAQUH-rjUWg-8uX6t9TN> zwO@1C^|9v?HA$G&CAHh!A@EIiZY}&pUzRpFUa~murQMpD!MskgjyMT4x~J`HHf<1o zr$p}OXQgQTD0`LtC+!vfkJ*CUdnVcn8>}{T&L(NSQGFPFqHG^o z$&&UsT!tJ^ta5}pd9AINvBM;|C3KD1^g|l3N|rD!x9)?pchU<+=vAzRbF3p8vb_VH zZS*Yd8Y)?NCRK?KH? zL3Yw?5ZXAS)}S0uhx#CG6bq{E>1{blJx9!kw0?G+I>pmMOEHTZvX3ZgF}sCN(>vH1 zD$(XSnkfH}ddMf-=#yIujfizHzpYb?tpOBxAF;I3Nq%vCip8@qjm6+}Tn&*|RP1!Y zUDzv=D=a$BLZW_L5jp#^Zj_F&nY^|#P8VFcM%7=aS(J_|V>$Z*ehHw}vA`)M6(6x1 z%&yFia?e$<%<)`M5Hw`RY`ic>vugcWZ7;KO?>SMF=E7Bb z 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 Date: Tue, 8 Oct 2019 11:48:49 +0200 Subject: [PATCH 138/189] fix iclass reader functions * remove unused CMD_ICLASS_READCHECK * fix wrong command coding in CodeIClassCommand() * switch field off at end of commands to avoid RDV4 overheating --- armsrc/appmain.c | 3 --- armsrc/iclass.c | 16 ++++++---------- armsrc/iclass.h | 2 -- client/hid-flasher/usb_cmd.h | 1 - include/usb_cmd.h | 1 - 5 files changed, 6 insertions(+), 17 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index c7c716a7..e3bd1fe0 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1324,9 +1324,6 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_ICLASS_WRITEBLOCK: iClass_WriteBlock(c->arg[0], c->d.asBytes); break; - case CMD_ICLASS_READCHECK: // auth step 1 - iClass_ReadCheck(c->arg[0], c->arg[1]); - break; case CMD_ICLASS_READBLOCK: iClass_ReadBlk(c->arg[0]); break; diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 5d7375a7..ab63dcea 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -1407,7 +1407,7 @@ void CodeIClassCommand(const uint8_t *cmd, int len) { for (j = 0; j < 4; j++) { for (k = 0; k < 4; k++) { if (k == (b & 3)) { - ToSend[++ToSendMax] = 0xf0; + ToSend[++ToSendMax] = 0x0f; } else { ToSend[++ToSendMax] = 0x00; } @@ -1697,6 +1697,7 @@ void ReaderIClass(uint8_t arg0) { if ( (result_status ^ FLAG_ICLASS_READER_CSN ^ flagReadConfig ^ flagReadCC ^ flagReadAA) == 0) { cmd_send(CMD_ACK, result_status, 0, 0, card_data, sizeof(card_data)); if (abort_after_read) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_A_OFF(); LED_B_OFF(); return; @@ -1848,17 +1849,10 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { card_data, 0); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_A_OFF(); } -void iClass_ReadCheck(uint8_t blockNo, uint8_t keyType) { - uint8_t readcheck[] = { keyType, blockNo }; - uint8_t resp[] = {0,0,0,0,0,0,0,0}; - size_t isOK = 0; - isOK = sendCmdGetResponseWithRetries(readcheck, sizeof(readcheck), resp, sizeof(resp), 6); - cmd_send(CMD_ACK,isOK, 0, 0, 0, 0); -} - void iClass_Authentication(uint8_t *MAC) { uint8_t check[] = { ICLASS_CMD_CHECK, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t resp[ICLASS_BUFFER_SIZE]; @@ -1868,7 +1862,7 @@ void iClass_Authentication(uint8_t *MAC) { cmd_send(CMD_ACK,isOK, 0, 0, 0, 0); } -bool iClass_ReadBlock(uint8_t blockNo, uint8_t *readdata) { +static bool iClass_ReadBlock(uint8_t blockNo, uint8_t *readdata) { uint8_t readcmd[] = {ICLASS_CMD_READ_OR_IDENTIFY, blockNo, 0x00, 0x00}; //0x88, 0x00 // can i use 0C? char bl = blockNo; uint16_t rdCrc = iclass_crc16(&bl, 1); @@ -1889,6 +1883,7 @@ void iClass_ReadBlk(uint8_t blockno) { bool isOK = false; isOK = iClass_ReadBlock(blockno, readblockdata); cmd_send(CMD_ACK, isOK, 0, 0, readblockdata, 8); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); } void iClass_Dump(uint8_t blockno, uint8_t numblks) { @@ -1959,6 +1954,7 @@ void iClass_WriteBlock(uint8_t blockNo, uint8_t *data) { Dbprintf("Write block [%02x] failed", blockNo); } cmd_send(CMD_ACK, isOK, 0, 0, 0, 0); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); } void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data) { diff --git a/armsrc/iclass.h b/armsrc/iclass.h index 828792c5..3cbe79fb 100644 --- a/armsrc/iclass.h +++ b/armsrc/iclass.h @@ -25,9 +25,7 @@ extern void IClass_iso14443A_GetPublic(uint8_t arg0); extern void iClass_Authentication(uint8_t *MAC); extern void iClass_WriteBlock(uint8_t blockNo, uint8_t *data); extern void iClass_ReadBlk(uint8_t blockNo); -extern bool iClass_ReadBlock(uint8_t blockNo, uint8_t *readdata); extern void iClass_Dump(uint8_t blockno, uint8_t numblks); extern void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data); -extern void iClass_ReadCheck(uint8_t blockNo, uint8_t keyType); #endif diff --git a/client/hid-flasher/usb_cmd.h b/client/hid-flasher/usb_cmd.h index ae1f0586..5b2c1114 100644 --- a/client/hid-flasher/usb_cmd.h +++ b/client/hid-flasher/usb_cmd.h @@ -124,7 +124,6 @@ typedef struct { #define CMD_WRITER_LEGIC_RF 0x0389 #define CMD_EPA_PACE_COLLECT_NONCE 0x038A -#define CMD_ICLASS_READCHECK 0x038F #define CMD_ICLASS_CLONE 0x0390 #define CMD_ICLASS_DUMP 0x0391 #define CMD_SNOOP_ICLASS 0x0392 diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 1bc5e5ba..ece12260 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -156,7 +156,6 @@ typedef struct{ #define CMD_EPA_PACE_COLLECT_NONCE 0x038A #define CMD_EPA_PACE_REPLAY 0x038B -#define CMD_ICLASS_READCHECK 0x038F #define CMD_ICLASS_CLONE 0x0390 #define CMD_ICLASS_DUMP 0x0391 #define CMD_SNOOP_ICLASS 0x0392 From a5346295050fffc8166e07512370308be0cdedd1 Mon Sep 17 00:00:00 2001 From: quantum-x Date: Tue, 8 Oct 2019 13:24:25 +0200 Subject: [PATCH 139/189] Update README.md Updated reference to Lab401 as an EU reseller, not a HK reseller. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2f7007e2..43b6f90a 100644 --- a/README.md +++ b/README.md @@ -29,8 +29,8 @@ following locations: * [RyscCorp](https://proxmark3.com/) (US) * [Hackerwarehouse](https://hackerwarehouse.com/) (US) +* [Lab401](https://lab401.com/) (Europe) * [Elechouse](http://www.elechouse.com/) (HK) -* [Lab401](https://lab401.com/) (HK) * [RFxSecure](http://www.rfxsecure.com/) (SG) * [Sneaktechnology](https://www.sneaktechnology.com/) (ASIA/OCEANIA) From 5eacacfd9ac485f753919b07404878e6c54b4156 Mon Sep 17 00:00:00 2001 From: quantum-x Date: Tue, 8 Oct 2019 14:40:11 +0200 Subject: [PATCH 140/189] Update README.md Updated as per PR discussion thead --- README.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 43b6f90a..49fcb366 100644 --- a/README.md +++ b/README.md @@ -27,12 +27,14 @@ your operating system. Please refer to [the wiki](https://github.com/Proxmark/pr The Proxmark3 is available for purchase (assembled and tested) from the following locations: -* [RyscCorp](https://proxmark3.com/) (US) -* [Hackerwarehouse](https://hackerwarehouse.com/) (US) -* [Lab401](https://lab401.com/) (Europe) -* [Elechouse](http://www.elechouse.com/) (HK) -* [RFxSecure](http://www.rfxsecure.com/) (SG) -* [Sneaktechnology](https://www.sneaktechnology.com/) (ASIA/OCEANIA) +| Distributor Name | Warehouse Location | Entity Location | +|------------------|--------------------|-----------------| +| [RyscCorp](https://proxmark3.com/) | USA | USA | +| [Hackerwarehouse](https://hackerwarehouse.com/) | USA | USA | +| [Elechouse](http://www.elechouse.com/) | HK | HK | +| [Lab401](https://lab401.com/) | EU | HK | +| [RFxSecure](http://www.rfxsecure.com/) | CN | SG | +| [Sneaktechnology](https://www.sneaktechnology.com/) | CN | CN | Most of the ultra-low-volume contract assemblers could put From c41dd5f9f690777eefd08eaeb43db52f599ce38c Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Wed, 16 Oct 2019 09:36:37 +0200 Subject: [PATCH 141/189] fix 'hf iclass reader' * code deduplication. Use functions from iso15693.c * speedup CodeIso15693AsReader() * invert reader command coding. 0 now means 'unmodulated' ( = field on) * decode SOF only as a valid tag response in Handle15693SamplesFromTag() * complete decoding of EOF in Handle15693SamplesFromTag() * determine and write correct times to trace * FPGA-change: generate shorter frame signal to allow proper sync in StartCountSspClk() * modify StartCountSspClk() for 16bit SSC transfers * whitespace in util.c * add specific LogTrace_ISO15693() with scaled down duration. Modify cmdhflist.c accordingly. * allow 'hf 15 raw' with single byte commands * check for buffer overflow, card timeout and single SOF in 'hf 15 raw' --- armsrc/iclass.c | 324 ++++++++------------------------ armsrc/iso15693.c | 446 +++++++++++++++++++++++++-------------------- armsrc/iso15693.h | 15 +- armsrc/util.c | 153 ++++++++-------- armsrc/util.h | 2 +- client/cmdhf15.c | 31 ++-- client/cmdhflist.c | 6 - fpga/fpga_hf.bit | Bin 42175 -> 42175 bytes fpga/hi_reader.v | 4 +- 9 files changed, 446 insertions(+), 535 deletions(-) diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 2533d1f9..392271bd 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -57,14 +57,17 @@ #include "usb_cdc.h" // for usb_poll_validate_length #include "fpgaloader.h" -static int timeout = 4096; - // iCLASS has a slightly different timing compared to ISO15693. According to the picopass data sheet the tag response is expected 330us after // the reader command. This is measured from end of reader EOF to first modulation of the tag's SOF which starts with a 56,64us unmodulated period. // 330us = 140 ssp_clk cycles @ 423,75kHz when simulating. // 56,64us = 24 ssp_clk_cycles -#define DELAY_ICLASS_VCD_TO_VICC_SIM 140 -#define TAG_SOF_UNMODULATED 24 +#define DELAY_ICLASS_VCD_TO_VICC_SIM (140 - 24) +// times in ssp_clk_cycles @ 3,3625MHz when acting as reader +#define DELAY_ICLASS_VICC_TO_VCD_READER DELAY_ISO15693_VICC_TO_VCD_READER +// times in samples @ 212kHz when acting as reader +#define ICLASS_READER_TIMEOUT_ACTALL 330 // 1558us, nominal 330us + 7slots*160us = 1450us +#define ICLASS_READER_TIMEOUT_OTHERS 80 // 380us, nominal 330us + //----------------------------------------------------------------------------- // The software UART that receives commands from the reader, and its state @@ -698,7 +701,7 @@ void RAMFUNC SnoopIClass(void) { //if (!LogTrace(NULL, 0, Uart.endTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, 0, true)) break; uint8_t parity[MAX_PARITY_SIZE]; GetParity(Uart.output, Uart.byteCnt, parity); - LogTrace(Uart.output, Uart.byteCnt, time_start, time_stop, parity, true); + LogTrace_ISO15693(Uart.output, Uart.byteCnt, time_start*32, time_stop*32, parity, true); /* And ready to receive another command. */ Uart.state = STATE_UNSYNCD; @@ -723,7 +726,7 @@ void RAMFUNC SnoopIClass(void) { uint8_t parity[MAX_PARITY_SIZE]; GetParity(Demod.output, Demod.len, parity); - LogTrace(Demod.output, Demod.len, time_start, time_stop, parity, false); + LogTrace_ISO15693(Demod.output, Demod.len, time_start*32, time_stop*32, parity, false); // And ready to receive another response. memset(&Demod, 0, sizeof(Demod)); @@ -1230,9 +1233,9 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { A legit tag has about 273,4us delay between reader EOT and tag SOF. **/ if (modulated_response_size > 0) { - uint32_t response_time = reader_eof_time + DELAY_ICLASS_VCD_TO_VICC_SIM - TAG_SOF_UNMODULATED - DELAY_ARM_TO_READER_SIM; + uint32_t response_time = reader_eof_time + DELAY_ICLASS_VCD_TO_VICC_SIM; TransmitTo15693Reader(modulated_response, modulated_response_size, &response_time, 0, false); - LogTrace(trace_data, trace_data_size, response_time + DELAY_ARM_TO_READER_SIM, response_time + (modulated_response_size << 6) + DELAY_ARM_TO_READER_SIM, NULL, false); + LogTrace_ISO15693(trace_data, trace_data_size, response_time*32, response_time*32 + modulated_response_size/2, NULL, false); } } @@ -1327,214 +1330,22 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain /// THE READER CODE -//----------------------------------------------------------------------------- -// Transmit the command (to the tag) that was placed in ToSend[]. -//----------------------------------------------------------------------------- -static void TransmitIClassCommand(const uint8_t *cmd, int len, int *samples, int *wait) { - int c; - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); - AT91C_BASE_SSC->SSC_THR = 0x00; - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_ISO14443A); +static void ReaderTransmitIClass(uint8_t *frame, int len, uint32_t *start_time) { - if (wait) { - if (*wait < 10) *wait = 10; + CodeIso15693AsReader(frame, len); - for (c = 0; c < *wait;) { - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0x00; // For exact timing! - c++; - } - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR; - (void)r; - } - WDT_HIT(); - } - } + TransmitTo15693Tag(ToSend, ToSendMax, start_time); - uint8_t sendbyte; - bool firstpart = true; - c = 0; - for (;;) { - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - - // DOUBLE THE SAMPLES! - if (firstpart) { - sendbyte = (cmd[c] & 0xf0) | (cmd[c] >> 4); - } else { - sendbyte = (cmd[c] & 0x0f) | (cmd[c] << 4); - c++; - } - if (sendbyte == 0xff) { - sendbyte = 0xfe; - } - AT91C_BASE_SSC->SSC_THR = sendbyte; - firstpart = !firstpart; - - if (c >= len) { - break; - } - } - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR; - (void)r; - } - WDT_HIT(); - } - if (samples && wait) *samples = (c + *wait) << 3; + uint32_t end_time = *start_time + 32*(8*ToSendMax-4); // substract the 4 padding bits after EOF + LogTrace_ISO15693(frame, len, *start_time*4, end_time*4, NULL, true); } -//----------------------------------------------------------------------------- -// Prepare iClass reader command to send to FPGA -//----------------------------------------------------------------------------- -void CodeIClassCommand(const uint8_t *cmd, int len) { - int i, j, k; - - ToSendReset(); - - // Start of Communication: 1 out of 4 - ToSend[++ToSendMax] = 0xf0; - ToSend[++ToSendMax] = 0x00; - ToSend[++ToSendMax] = 0x0f; - ToSend[++ToSendMax] = 0x00; - - // Modulate the bytes - for (i = 0; i < len; i++) { - uint8_t b = cmd[i]; - for (j = 0; j < 4; j++) { - for (k = 0; k < 4; k++) { - if (k == (b & 3)) { - ToSend[++ToSendMax] = 0x0f; - } else { - ToSend[++ToSendMax] = 0x00; - } - } - b >>= 2; - } - } - - // End of Communication - ToSend[++ToSendMax] = 0x00; - ToSend[++ToSendMax] = 0x00; - ToSend[++ToSendMax] = 0xf0; - ToSend[++ToSendMax] = 0x00; - - // Convert from last character reference to length - ToSendMax++; -} - -static void ReaderTransmitIClass(uint8_t *frame, int len) { - int wait = 0; - int samples = 0; - - // This is tied to other size changes - CodeIClassCommand(frame, len); - - // Select the card - TransmitIClassCommand(ToSend, ToSendMax, &samples, &wait); - if (trigger) - LED_A_ON(); - - // Store reader command in buffer - uint8_t par[MAX_PARITY_SIZE]; - GetParity(frame, len, par); - LogTrace(frame, len, rsamples, rsamples, par, true); -} - -//----------------------------------------------------------------------------- -// Wait a certain time for tag response -// If a response is captured return true -// If it takes too long return false -//----------------------------------------------------------------------------- -static int GetIClassAnswer(uint8_t *receivedResponse, int maxLen, int *samples, int *elapsed) { - //uint8_t *buffer - // buffer needs to be 512 bytes - int c; - - // Set FPGA mode to "reader listen mode", no modulation (listen - // only, since we are receiving, not transmitting). - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_LISTEN); - - // Now get the answer from the card - Demod.output = receivedResponse; - Demod.len = 0; - Demod.state = DEMOD_UNSYNCD; - - uint8_t b; - if (elapsed) *elapsed = 0; - - bool skip = false; - - c = 0; - for (;;) { - WDT_HIT(); - - if (BUTTON_PRESS()) return false; - - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { - AT91C_BASE_SSC->SSC_THR = 0x00; // To make use of exact timing of next command from reader!! - if (elapsed) (*elapsed)++; - } - if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - if (c < timeout) { - c++; - } else { - return false; - } - b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; - skip = !skip; - if (skip) continue; - - if (ManchesterDecoding(b & 0x0f)) { - *samples = c << 3; - return true; - } - } - } -} - -static int ReaderReceiveIClass(uint8_t *receivedAnswer) { - int samples = 0; - if (!GetIClassAnswer(receivedAnswer, 160, &samples, 0)) { - return false; - } - rsamples += samples; - uint8_t parity[MAX_PARITY_SIZE]; - GetParity(receivedAnswer, Demod.len, parity); - LogTrace(receivedAnswer, Demod.len, rsamples, rsamples, parity, false); - if (samples == 0) return false; - return Demod.len; -} - -static void setupIclassReader() { - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - // Reset trace buffer - set_tracing(true); - clear_trace(); - - // Setup SSC - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_ISO14443A); - // Start from off (no field generated) - // Signal field is off with the appropriate LED - LED_D_OFF(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(200); - - SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - - // Now give it time to spin up. - // Signal field is on with the appropriate LED - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); - SpinDelay(200); - LED_A_ON(); - -} - -static bool sendCmdGetResponseWithRetries(uint8_t* command, size_t cmdsize, uint8_t* resp, uint8_t expected_size, uint8_t retries) { +static bool sendCmdGetResponseWithRetries(uint8_t* command, size_t cmdsize, uint8_t* resp, size_t max_resp_size, + uint8_t expected_size, uint8_t retries, uint32_t start_time, uint32_t *eof_time) { while (retries-- > 0) { - ReaderTransmitIClass(command, cmdsize); - if (expected_size == ReaderReceiveIClass(resp)) { + ReaderTransmitIClass(command, cmdsize, &start_time); + if (expected_size == GetIso15693AnswerFromTag(resp, max_resp_size, ICLASS_READER_TIMEOUT_OTHERS, eof_time)) { return true; } } @@ -1548,12 +1359,11 @@ static bool sendCmdGetResponseWithRetries(uint8_t* command, size_t cmdsize, uint * 1 = Got CSN * 2 = Got CSN and CC */ -static uint8_t handshakeIclassTag_ext(uint8_t *card_data, bool use_credit_key) { - static uint8_t act_all[] = { 0x0a }; - //static uint8_t identify[] = { 0x0c }; - static uint8_t identify[] = { 0x0c, 0x00, 0x73, 0x33 }; - static uint8_t select[] = { 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - static uint8_t readcheck_cc[]= { 0x88, 0x02 }; +static uint8_t handshakeIclassTag_ext(uint8_t *card_data, bool use_credit_key, uint32_t *eof_time) { + uint8_t act_all[] = { 0x0a }; + uint8_t identify[] = { 0x0c }; + uint8_t select[] = { 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t readcheck_cc[] = { 0x88, 0x02 }; if (use_credit_key) readcheck_cc[0] = 0x18; else @@ -1562,24 +1372,28 @@ static uint8_t handshakeIclassTag_ext(uint8_t *card_data, bool use_credit_key) { uint8_t resp[ICLASS_BUFFER_SIZE]; uint8_t read_status = 0; + uint32_t start_time = GetCountSspClk(); // Send act_all - ReaderTransmitIClass(act_all, 1); + ReaderTransmitIClass(act_all, 1, &start_time); // Card present? - if (!ReaderReceiveIClass(resp)) return read_status;//Fail - + if (GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_ACTALL, eof_time) < 0) return read_status;//Fail + //Send Identify - ReaderTransmitIClass(identify, 1); + start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + ReaderTransmitIClass(identify, 1, &start_time); + // FpgaDisableTracing(); // DEBUGGING //We expect a 10-byte response here, 8 byte anticollision-CSN and 2 byte CRC - uint8_t len = ReaderReceiveIClass(resp); + uint8_t len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); if (len != 10) return read_status;//Fail //Copy the Anti-collision CSN to our select-packet memcpy(&select[1], resp, 8); //Select the card - ReaderTransmitIClass(select, sizeof(select)); + start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + ReaderTransmitIClass(select, sizeof(select), &start_time); //We expect a 10-byte response here, 8 byte CSN and 2 byte CRC - len = ReaderReceiveIClass(resp); + len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); if (len != 10) return read_status;//Fail //Success - level 1, we got CSN @@ -1590,8 +1404,9 @@ static uint8_t handshakeIclassTag_ext(uint8_t *card_data, bool use_credit_key) { read_status = 1; // Card selected, now read e-purse (cc) (only 8 bytes no CRC) - ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc)); - if (ReaderReceiveIClass(resp) == 8) { + start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc), &start_time); + if (GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time) == 8) { //Save CC (e-purse) in response data memcpy(card_data+8, resp, 8); read_status++; @@ -1600,8 +1415,8 @@ static uint8_t handshakeIclassTag_ext(uint8_t *card_data, bool use_credit_key) { return read_status; } -static uint8_t handshakeIclassTag(uint8_t *card_data) { - return handshakeIclassTag_ext(card_data, false); +static uint8_t handshakeIclassTag(uint8_t *card_data, uint32_t *eof_time) { + return handshakeIclassTag_ext(card_data, false, eof_time); } @@ -1633,8 +1448,13 @@ void ReaderIClass(uint8_t arg0) { uint8_t flagReadAA = arg0 & FLAG_ICLASS_READER_AA; set_tracing(true); - setupIclassReader(); + clear_trace(); + Iso15693InitReader(); + StartCountSspClk(); + uint32_t start_time = 0; + uint32_t eof_time = 0; + uint16_t tryCnt = 0; bool userCancelled = BUTTON_PRESS() || usb_poll_validate_length(); while (!userCancelled) { @@ -1649,29 +1469,31 @@ void ReaderIClass(uint8_t arg0) { } WDT_HIT(); - read_status = handshakeIclassTag_ext(card_data, use_credit_key); + read_status = handshakeIclassTag_ext(card_data, use_credit_key, &eof_time); if (read_status == 0) continue; if (read_status == 1) result_status = FLAG_ICLASS_READER_CSN; if (read_status == 2) result_status = FLAG_ICLASS_READER_CSN | FLAG_ICLASS_READER_CC; + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; // handshakeIclass returns CSN|CC, but the actual block // layout is CSN|CONFIG|CC, so here we reorder the data, // moving CC forward 8 bytes memcpy(card_data+16, card_data+8, 8); //Read block 1, config if (flagReadConfig) { - if (sendCmdGetResponseWithRetries(readConf, sizeof(readConf), resp, 10, 10)) { + if (sendCmdGetResponseWithRetries(readConf, sizeof(readConf), resp, sizeof(resp), 10, 10, start_time, &eof_time)) { result_status |= FLAG_ICLASS_READER_CONF; memcpy(card_data+8, resp, 8); } else { Dbprintf("Failed to dump config block"); } + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; } //Read block 5, AA if (flagReadAA) { - if (sendCmdGetResponseWithRetries(readAA, sizeof(readAA), resp, 10, 10)) { + if (sendCmdGetResponseWithRetries(readAA, sizeof(readAA), resp, sizeof(resp), 10, 10, start_time, &eof_time)) { result_status |= FLAG_ICLASS_READER_AA; memcpy(card_data + (8*5), resp, 8); } else { @@ -1746,9 +1568,14 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { uint8_t resp[ICLASS_BUFFER_SIZE]; - setupIclassReader(); set_tracing(true); + clear_trace(); + Iso15693InitReader(); + StartCountSspClk(); + uint32_t start_time = 0; + uint32_t eof_time = 0; + while (!BUTTON_PRESS()) { WDT_HIT(); @@ -1758,28 +1585,34 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { break; } - uint8_t read_status = handshakeIclassTag(card_data); + uint8_t read_status = handshakeIclassTag(card_data, &eof_time); + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + if (read_status < 2) continue; //for now replay captured auth (as cc not updated) memcpy(check+5, MAC, 4); - if (!sendCmdGetResponseWithRetries(check, sizeof(check), resp, 4, 5)) { + if (!sendCmdGetResponseWithRetries(check, sizeof(check), resp, sizeof(resp), 4, 5, start_time, &eof_time)) { + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; Dbprintf("Error: Authentication Fail!"); continue; } + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; //first get configuration block (block 1) crc = block_crc_LUT[1]; read[1] = 1; read[2] = crc >> 8; read[3] = crc & 0xff; - if (!sendCmdGetResponseWithRetries(read, sizeof(read),resp, 10, 10)) { + if (!sendCmdGetResponseWithRetries(read, sizeof(read), resp, sizeof(resp), 10, 10, start_time, &eof_time)) { + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; Dbprintf("Dump config (block 1) failed"); continue; } + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; mem = resp[5]; memory.k16 = (mem & 0x80); memory.book = (mem & 0x20); @@ -1800,7 +1633,8 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { read[2] = crc >> 8; read[3] = crc & 0xff; - if (sendCmdGetResponseWithRetries(read, sizeof(read), resp, 10, 10)) { + if (sendCmdGetResponseWithRetries(read, sizeof(read), resp, sizeof(resp), 10, 10, start_time, &eof_time)) { + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; Dbprintf(" %02x: %02x %02x %02x %02x %02x %02x %02x %02x", block, resp[0], resp[1], resp[2], resp[3], resp[4], resp[5], @@ -1857,7 +1691,8 @@ void iClass_Authentication(uint8_t *MAC) { uint8_t resp[ICLASS_BUFFER_SIZE]; memcpy(check+5, MAC, 4); bool isOK; - isOK = sendCmdGetResponseWithRetries(check, sizeof(check), resp, 4, 6); + uint32_t eof_time; + isOK = sendCmdGetResponseWithRetries(check, sizeof(check), resp, sizeof(resp), 4, 6, 0, &eof_time); cmd_send(CMD_ACK,isOK, 0, 0, 0, 0); } @@ -1867,11 +1702,12 @@ static bool iClass_ReadBlock(uint8_t blockNo, uint8_t *readdata) { uint16_t rdCrc = iclass_crc16(&bl, 1); readcmd[2] = rdCrc >> 8; readcmd[3] = rdCrc & 0xff; - uint8_t resp[] = {0,0,0,0,0,0,0,0,0,0}; + uint8_t resp[10]; bool isOK = false; - + uint32_t eof_time; + //readcmd[1] = blockNo; - isOK = sendCmdGetResponseWithRetries(readcmd, sizeof(readcmd), resp, 10, 10); + isOK = sendCmdGetResponseWithRetries(readcmd, sizeof(readcmd), resp, sizeof(resp), 10, 10, 0, &eof_time); memcpy(readdata, resp, sizeof(resp)); return isOK; @@ -1929,16 +1765,18 @@ static bool iClass_WriteBlock_ext(uint8_t blockNo, uint8_t *data) { uint16_t wrCrc = iclass_crc16(wrCmd, 13); write[14] = wrCrc >> 8; write[15] = wrCrc & 0xff; - uint8_t resp[] = {0,0,0,0,0,0,0,0,0,0}; + uint8_t resp[10]; bool isOK = false; - - isOK = sendCmdGetResponseWithRetries(write, sizeof(write), resp, sizeof(resp), 10); + uint32_t eof_time = 0; + + isOK = sendCmdGetResponseWithRetries(write, sizeof(write), resp, sizeof(resp), 10, 10, 0, &eof_time); + uint32_t start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; if (isOK) { //if reader responded correctly //Dbprintf("WriteResp: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",resp[0],resp[1],resp[2],resp[3],resp[4],resp[5],resp[6],resp[7],resp[8],resp[9]); if (memcmp(write+2, resp, 8)) { //if response is not equal to write values if (blockNo != 3 && blockNo != 4) { //if not programming key areas (note key blocks don't get programmed with actual key data it is xor data) //error try again - isOK = sendCmdGetResponseWithRetries(write, sizeof(write), resp, sizeof(resp), 10); + isOK = sendCmdGetResponseWithRetries(write, sizeof(write), resp, sizeof(resp), 10, 10, start_time, &eof_time); } } } diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 85af0859..fff8b370 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -64,8 +64,26 @@ #define arraylen(x) (sizeof(x)/sizeof((x)[0])) +// Delays in SSP_CLK ticks. +// SSP_CLK runs at 13,56MHz / 32 = 423.75kHz when simulating a tag +#define DELAY_READER_TO_ARM 8 +#define DELAY_ARM_TO_READER 0 +//SSP_CLK runs at 13.56MHz / 4 = 3,39MHz when acting as reader. All values should be multiples of 16 +#define DELAY_TAG_TO_ARM 32 +#define DELAY_ARM_TO_TAG 16 + static int DEBUG = 0; + +// specific LogTrace function for ISO15693: the duration needs to be scaled because otherwise it won't fit into a uint16_t +bool LogTrace_ISO15693(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag) { + uint32_t duration = timestamp_end - timestamp_start; + duration /= 32; + timestamp_end = timestamp_start + duration; + return LogTrace(btBytes, iLen, timestamp_start, timestamp_end, parity, readerToTag); +} + + /////////////////////////////////////////////////////////////////////// // ISO 15693 Part 2 - Air Interface // This section basically contains transmission and receiving of bits @@ -84,84 +102,37 @@ static int DEBUG = 0; // resulting data rate is 26.48 kbit/s (fc/512) // cmd ... data // n ... length of data -static void CodeIso15693AsReader(uint8_t *cmd, int n) -{ - int i, j; +void CodeIso15693AsReader(uint8_t *cmd, int n) { ToSendReset(); - // Give it a bit of slack at the beginning - for(i = 0; i < 24; i++) { - ToSendStuffBit(1); - } - // SOF for 1of4 - ToSendStuffBit(0); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(0); - ToSendStuffBit(1); - ToSendStuffBit(1); - for(i = 0; i < n; i++) { - for(j = 0; j < 8; j += 2) { - int these = (cmd[i] >> j) & 3; + ToSend[++ToSendMax] = 0x84; //10000100 + + // data + for (int i = 0; i < n; i++) { + for (int j = 0; j < 8; j += 2) { + int these = (cmd[i] >> j) & 0x03; switch(these) { case 0: - ToSendStuffBit(1); - ToSendStuffBit(0); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); + ToSend[++ToSendMax] = 0x40; //01000000 break; case 1: - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(0); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); + ToSend[++ToSendMax] = 0x10; //00010000 break; case 2: - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(0); - ToSendStuffBit(1); - ToSendStuffBit(1); + ToSend[++ToSendMax] = 0x04; //00000100 break; case 3: - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(0); + ToSend[++ToSendMax] = 0x01; //00000001 break; } } } + // EOF - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(0); - ToSendStuffBit(1); - - // Fill remainder of last byte with 1 - for(i = 0; i < 4; i++) { - ToSendStuffBit(1); - } - + ToSend[++ToSendMax] = 0x20; //0010 + 0000 padding + ToSendMax++; } @@ -170,46 +141,26 @@ static void CodeIso15693AsReader(uint8_t *cmd, int n) // is designed for more robust communication over longer distances static void CodeIso15693AsReader256(uint8_t *cmd, int n) { - int i, j; - ToSendReset(); - // Give it a bit of slack at the beginning - for(i = 0; i < 24; i++) { - ToSendStuffBit(1); - } - // SOF for 1of256 - ToSendStuffBit(0); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(0); + ToSend[++ToSendMax] = 0x81; //10000001 - for(i = 0; i < n; i++) { - for (j = 0; j<=255; j++) { - if (cmd[i]==j) { - ToSendStuffBit(1); + // data + for(int i = 0; i < n; i++) { + for (int j = 0; j <= 255; j++) { + if (cmd[i] == j) { ToSendStuffBit(0); + ToSendStuffBit(1); } else { - ToSendStuffBit(1); - ToSendStuffBit(1); + ToSendStuffBit(0); + ToSendStuffBit(0); } } } - // EOF - ToSendStuffBit(1); - ToSendStuffBit(1); - ToSendStuffBit(0); - ToSendStuffBit(1); - // Fill remainder of last byte with 1 - for(i = 0; i < 4; i++) { - ToSendStuffBit(1); - } + // EOF + ToSend[++ToSendMax] = 0x20; //0010 + 0000 padding ToSendMax++; } @@ -295,27 +246,38 @@ void CodeIso15693AsTag(uint8_t *cmd, size_t len) { // Transmit the command (to the tag) that was placed in cmd[]. -static void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t start_time) -{ - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_FULL_MOD); - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); +void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time) { - while (GetCountSspClk() < start_time) ; + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_FULL_MOD); + + *start_time = (*start_time - DELAY_ARM_TO_TAG) & 0xfffffff0; + + while (GetCountSspClk() > *start_time) { // we may miss the intended time + *start_time += 16; // next possible time + } + + + while (GetCountSspClk() < *start_time) + /* wait */ ; LED_B_ON(); - for(int c = 0; c < len; c++) { + for (int c = 0; c < len; c++) { uint8_t data = cmd[c]; for (int i = 0; i < 8; i++) { - uint16_t send_word = (data & 0x80) ? 0x0000 : 0xffff; + uint16_t send_word = (data & 0x80) ? 0xffff : 0x0000; while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ; AT91C_BASE_SSC->SSC_THR = send_word; while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))) ; AT91C_BASE_SSC->SSC_THR = send_word; + data <<= 1; } WDT_HIT(); } LED_B_OFF(); + + *start_time = *start_time + DELAY_ARM_TO_TAG; + } @@ -326,7 +288,7 @@ void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, // don't use the FPGA_HF_SIMULATOR_MODULATE_424K_8BIT minor mode. It would spoil GetCountSspClk() FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_424K); - uint32_t modulation_start_time = *start_time + 3 * 8; // no need to transfer the unmodulated start of SOF + uint32_t modulation_start_time = *start_time - DELAY_ARM_TO_READER + 3 * 8; // no need to transfer the unmodulated start of SOF while (GetCountSspClk() > (modulation_start_time & 0xfffffff8) + 3) { // we will miss the intended time if (slot_time) { @@ -341,7 +303,7 @@ void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, uint8_t shift_delay = modulation_start_time & 0x00000007; - *start_time = modulation_start_time - 3 * 8; + *start_time = modulation_start_time + DELAY_ARM_TO_READER - 3 * 8; LED_C_ON(); uint8_t bits_to_shift = 0x00; @@ -386,15 +348,18 @@ void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, // false if we are still waiting for some more //============================================================================= -#define NOISE_THRESHOLD 160 // don't try to correlate noise +#define NOISE_THRESHOLD 160 // don't try to correlate noise +#define MAX_PREVIOUS_AMPLITUDE (-1 - NOISE_THRESHOLD) typedef struct DecodeTag { enum { STATE_TAG_SOF_LOW, + STATE_TAG_SOF_RISING_EDGE, STATE_TAG_SOF_HIGH, STATE_TAG_SOF_HIGH_END, STATE_TAG_RECEIVING_DATA, - STATE_TAG_EOF + STATE_TAG_EOF, + STATE_TAG_EOF_TAIL } state; int bitCount; int posCount; @@ -409,6 +374,9 @@ typedef struct DecodeTag { uint8_t *output; int len; int sum1, sum2; + int threshold_sof; + int threshold_half; + uint16_t previous_amplitude; } DecodeTag_t; @@ -416,40 +384,58 @@ static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint1 { switch(DecodeTag->state) { case STATE_TAG_SOF_LOW: - // waiting for 12 times low (11 times low is accepted as well) - if (amplitude < NOISE_THRESHOLD) { - DecodeTag->posCount++; - } else { + // waiting for a rising edge + if (amplitude > NOISE_THRESHOLD + DecodeTag->previous_amplitude) { if (DecodeTag->posCount > 10) { - DecodeTag->posCount = 1; - DecodeTag->sum1 = 0; - DecodeTag->state = STATE_TAG_SOF_HIGH; + DecodeTag->threshold_sof = amplitude - DecodeTag->previous_amplitude; + DecodeTag->threshold_half = 0; + DecodeTag->state = STATE_TAG_SOF_RISING_EDGE; } else { DecodeTag->posCount = 0; } + } else { + DecodeTag->posCount++; + DecodeTag->previous_amplitude = amplitude; } break; + case STATE_TAG_SOF_RISING_EDGE: + if (amplitude - DecodeTag->previous_amplitude > DecodeTag->threshold_sof) { // edge still rising + if (amplitude - DecodeTag->threshold_sof > DecodeTag->threshold_sof) { // steeper edge, take this as time reference + DecodeTag->posCount = 1; + } else { + DecodeTag->posCount = 2; + } + DecodeTag->threshold_sof = (amplitude - DecodeTag->previous_amplitude) / 2; + } else { + DecodeTag->posCount = 2; + DecodeTag->threshold_sof = DecodeTag->threshold_sof/2; + } + // DecodeTag->posCount = 2; + DecodeTag->state = STATE_TAG_SOF_HIGH; + break; + case STATE_TAG_SOF_HIGH: // waiting for 10 times high. Take average over the last 8 - if (amplitude > NOISE_THRESHOLD) { + if (amplitude > DecodeTag->threshold_sof) { DecodeTag->posCount++; if (DecodeTag->posCount > 2) { - DecodeTag->sum1 += amplitude; // keep track of average high value + DecodeTag->threshold_half += amplitude; // keep track of average high value } if (DecodeTag->posCount == 10) { - DecodeTag->sum1 >>= 4; // calculate half of average high value (8 samples) + DecodeTag->threshold_half >>= 2; // (4 times 1/2 average) DecodeTag->state = STATE_TAG_SOF_HIGH_END; } } else { // high phase was too short DecodeTag->posCount = 1; + DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; DecodeTag->state = STATE_TAG_SOF_LOW; } break; case STATE_TAG_SOF_HIGH_END: - // waiting for a falling edge - if (amplitude < DecodeTag->sum1) { // signal drops below 50% average high: a falling edge + // check for falling edge + if (DecodeTag->posCount == 13 && amplitude < DecodeTag->threshold_sof) { DecodeTag->lastBit = SOF_PART1; // detected 1st part of SOF (12 samples low and 12 samples high) DecodeTag->shiftReg = 0; DecodeTag->bitCount = 0; @@ -458,11 +444,18 @@ static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint1 DecodeTag->sum2 = 0; DecodeTag->posCount = 2; DecodeTag->state = STATE_TAG_RECEIVING_DATA; + // FpgaDisableTracing(); // DEBUGGING + // Dbprintf("amplitude = %d, threshold_sof = %d, threshold_half/4 = %d, previous_amplitude = %d", + // amplitude, + // DecodeTag->threshold_sof, + // DecodeTag->threshold_half/4, + // DecodeTag->previous_amplitude); // DEBUGGING LED_C_ON(); } else { DecodeTag->posCount++; if (DecodeTag->posCount > 13) { // high phase too long DecodeTag->posCount = 0; + DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; DecodeTag->state = STATE_TAG_SOF_LOW; LED_C_OFF(); } @@ -480,18 +473,16 @@ static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint1 DecodeTag->sum2 += amplitude; } if (DecodeTag->posCount == 8) { - int32_t corr_1 = DecodeTag->sum2 - DecodeTag->sum1; - int32_t corr_0 = -corr_1; - int32_t corr_EOF = (DecodeTag->sum1 + DecodeTag->sum2) / 2; - if (corr_EOF > corr_0 && corr_EOF > corr_1) { + if (DecodeTag->sum1 > DecodeTag->threshold_half && DecodeTag->sum2 > DecodeTag->threshold_half) { // modulation in both halves if (DecodeTag->lastBit == LOGIC0) { // this was already part of EOF DecodeTag->state = STATE_TAG_EOF; } else { DecodeTag->posCount = 0; + DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; DecodeTag->state = STATE_TAG_SOF_LOW; LED_C_OFF(); } - } else if (corr_1 > corr_0) { + } else if (DecodeTag->sum1 < DecodeTag->threshold_half && DecodeTag->sum2 > DecodeTag->threshold_half) { // modulation in second half // logic 1 if (DecodeTag->lastBit == SOF_PART1) { // still part of SOF DecodeTag->lastBit = SOF_PART2; // SOF completed @@ -503,20 +494,21 @@ static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint1 if (DecodeTag->bitCount == 8) { DecodeTag->output[DecodeTag->len] = DecodeTag->shiftReg; DecodeTag->len++; + // if (DecodeTag->shiftReg == 0x12 && DecodeTag->len == 1) FpgaDisableTracing(); // DEBUGGING if (DecodeTag->len > DecodeTag->max_len) { // buffer overflow, give up - DecodeTag->posCount = 0; - DecodeTag->state = STATE_TAG_SOF_LOW; LED_C_OFF(); + return true; } DecodeTag->bitCount = 0; DecodeTag->shiftReg = 0; } } - } else { + } else if (DecodeTag->sum1 > DecodeTag->threshold_half && DecodeTag->sum2 < DecodeTag->threshold_half) { // modulation in first half // logic 0 if (DecodeTag->lastBit == SOF_PART1) { // incomplete SOF DecodeTag->posCount = 0; + DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; DecodeTag->state = STATE_TAG_SOF_LOW; LED_C_OFF(); } else { @@ -526,9 +518,11 @@ static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint1 if (DecodeTag->bitCount == 8) { DecodeTag->output[DecodeTag->len] = DecodeTag->shiftReg; DecodeTag->len++; + // if (DecodeTag->shiftReg == 0x12 && DecodeTag->len == 1) FpgaDisableTracing(); // DEBUGGING if (DecodeTag->len > DecodeTag->max_len) { // buffer overflow, give up DecodeTag->posCount = 0; + DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; DecodeTag->state = STATE_TAG_SOF_LOW; LED_C_OFF(); } @@ -536,6 +530,15 @@ static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint1 DecodeTag->shiftReg = 0; } } + } else { // no modulation + if (DecodeTag->lastBit == SOF_PART2) { // only SOF (this is OK for iClass) + LED_C_OFF(); + return true; + } else { + DecodeTag->posCount = 0; + DecodeTag->state = STATE_TAG_SOF_LOW; + LED_C_OFF(); + } } DecodeTag->posCount = 0; } @@ -553,21 +556,42 @@ static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint1 DecodeTag->sum2 += amplitude; } if (DecodeTag->posCount == 8) { - int32_t corr_1 = DecodeTag->sum2 - DecodeTag->sum1; - int32_t corr_0 = -corr_1; - int32_t corr_EOF = (DecodeTag->sum1 + DecodeTag->sum2) / 2; - if (corr_EOF > corr_0 || corr_1 > corr_0) { + if (DecodeTag->sum1 > DecodeTag->threshold_half && DecodeTag->sum2 < DecodeTag->threshold_half) { // modulation in first half DecodeTag->posCount = 0; + DecodeTag->state = STATE_TAG_EOF_TAIL; + } else { + DecodeTag->posCount = 0; + DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; DecodeTag->state = STATE_TAG_SOF_LOW; LED_C_OFF(); - } else { - LED_C_OFF(); - return true; } } DecodeTag->posCount++; break; + case STATE_TAG_EOF_TAIL: + if (DecodeTag->posCount == 1) { + DecodeTag->sum1 = 0; + DecodeTag->sum2 = 0; + } + if (DecodeTag->posCount <= 4) { + DecodeTag->sum1 += amplitude; + } else { + DecodeTag->sum2 += amplitude; + } + if (DecodeTag->posCount == 8) { + if (DecodeTag->sum1 < DecodeTag->threshold_half && DecodeTag->sum2 < DecodeTag->threshold_half) { // no modulation in both halves + LED_C_OFF(); + return true; + } else { + DecodeTag->posCount = 0; + DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; + DecodeTag->state = STATE_TAG_SOF_LOW; + LED_C_OFF(); + } + } + DecodeTag->posCount++; + break; } return false; @@ -576,6 +600,7 @@ static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint1 static void DecodeTagInit(DecodeTag_t *DecodeTag, uint8_t *data, uint16_t max_len) { + DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; DecodeTag->posCount = 0; DecodeTag->state = STATE_TAG_SOF_LOW; DecodeTag->output = data; @@ -587,18 +612,19 @@ static void DecodeTagReset(DecodeTag_t *DecodeTag) { DecodeTag->posCount = 0; DecodeTag->state = STATE_TAG_SOF_LOW; + DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; } /* * Receive and decode the tag response, also log to tracebuffer */ -static int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, int timeout) -{ - int samples = 0; - bool gotFrame = false; +int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeout, uint32_t *eof_time) { - uint16_t *dmaBuf = (uint16_t*)BigBuf_malloc(ISO15693_DMA_BUFFER_SIZE*sizeof(uint16_t)); + int samples = 0; + int ret = 0; + + uint16_t dmaBuf[ISO15693_DMA_BUFFER_SIZE]; // the Decoder data structure DecodeTag_t DecodeTag = { 0 }; @@ -613,6 +639,7 @@ static int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, int tim // Setup and start DMA. FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); FpgaSetupSscDma((uint8_t*) dmaBuf, ISO15693_DMA_BUFFER_SIZE); + uint32_t dma_start_time = 0; uint16_t *upTo = dmaBuf; for(;;) { @@ -620,12 +647,19 @@ static int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, int tim if (behindBy == 0) continue; + samples++; + if (samples == 1) { + // DMA has transferred the very first data + dma_start_time = GetCountSspClk() & 0xfffffff0; + } + uint16_t tagdata = *upTo++; if(upTo >= dmaBuf + ISO15693_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. upTo = dmaBuf; // start reading the circular buffer from the beginning if(behindBy > (9*ISO15693_DMA_BUFFER_SIZE/10)) { Dbprintf("About to blow circular buffer - aborted! behindBy=%d", behindBy); + ret = -1; break; } } @@ -634,30 +668,42 @@ static int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, int tim AT91C_BASE_PDC_SSC->PDC_RNCR = ISO15693_DMA_BUFFER_SIZE; // DMA Next Counter registers } - samples++; - if (Handle15693SamplesFromTag(tagdata, &DecodeTag)) { - gotFrame = true; + *eof_time = dma_start_time + samples*16 - DELAY_TAG_TO_ARM; // end of EOF + if (DecodeTag.lastBit == SOF_PART2) { + *eof_time -= 8*16; // needed 8 additional samples to confirm single SOF (iCLASS) + } + if (DecodeTag.len > DecodeTag.max_len) { + ret = -2; // buffer overflow + } break; } if (samples > timeout && DecodeTag.state < STATE_TAG_RECEIVING_DATA) { - DecodeTag.len = 0; + ret = -1; // timeout break; } } FpgaDisableSscDma(); - BigBuf_free(); - if (DEBUG) Dbprintf("samples = %d, gotFrame = %d, Decoder: state = %d, len = %d, bitCount = %d, posCount = %d", - samples, gotFrame, DecodeTag.state, DecodeTag.len, DecodeTag.bitCount, DecodeTag.posCount); + if (DEBUG) Dbprintf("samples = %d, ret = %d, Decoder: state = %d, lastBit = %d, len = %d, bitCount = %d, posCount = %d", + samples, ret, DecodeTag.state, DecodeTag.lastBit, DecodeTag.len, DecodeTag.bitCount, DecodeTag.posCount); - if (DecodeTag.len > 0) { - LogTrace(DecodeTag.output, DecodeTag.len, 0, 0, NULL, false); + if (ret < 0) { + return ret; } + uint32_t sof_time = *eof_time + - DecodeTag.len * 8 * 8 * 16 // time for byte transfers + - 32 * 16 // time for SOF transfer + - (DecodeTag.lastBit != SOF_PART2?32*16:0); // time for EOF transfer + + if (DEBUG) Dbprintf("timing: sof_time = %d, eof_time = %d", sof_time, *eof_time); + + LogTrace_ISO15693(DecodeTag.output, DecodeTag.len, sof_time*4, *eof_time*4, NULL, false); + return DecodeTag.len; } @@ -977,7 +1023,7 @@ int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eo for (int i = 7; i >= 0; i--) { if (Handle15693SampleFromReader((b >> i) & 0x01, &DecodeReader)) { - *eof_time = dma_start_time + samples - DELAY_READER_TO_ARM_SIM; // end of EOF + *eof_time = dma_start_time + samples - DELAY_READER_TO_ARM; // end of EOF gotFrame = true; break; } @@ -1006,7 +1052,7 @@ int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eo - DecodeReader.byteCount * (DecodeReader.Coding==CODING_1_OUT_OF_4?128:2048) // time for byte transfers - 32 // time for SOF transfer - 16; // time for EOF transfer - LogTrace(DecodeReader.output, DecodeReader.byteCount, sof_time, *eof_time, NULL, true); + LogTrace_ISO15693(DecodeReader.output, DecodeReader.byteCount, sof_time*32, *eof_time*32, NULL, true); } return DecodeReader.byteCount; @@ -1060,7 +1106,8 @@ void AcquireRawAdcSamplesIso15693(void) SpinDelay(100); // Now send the command - TransmitTo15693Tag(ToSend, ToSendMax, 0); + uint32_t start_time = 0; + TransmitTo15693Tag(ToSend, ToSendMax, &start_time); // wait for last transfer to complete while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)) ; @@ -1156,7 +1203,7 @@ void SnoopIso15693(void) if (Handle15693SampleFromReader(snoopdata & 0x02, &DecodeReader)) { FpgaDisableSscDma(); ExpectTagAnswer = true; - LogTrace(DecodeReader.output, DecodeReader.byteCount, samples, samples, NULL, true); + LogTrace_ISO15693(DecodeReader.output, DecodeReader.byteCount, samples*64, samples*64, NULL, true); /* And ready to receive another command. */ DecodeReaderReset(&DecodeReader); /* And also reset the demod code, which might have been */ @@ -1168,7 +1215,7 @@ void SnoopIso15693(void) if (Handle15693SampleFromReader(snoopdata & 0x01, &DecodeReader)) { FpgaDisableSscDma(); ExpectTagAnswer = true; - LogTrace(DecodeReader.output, DecodeReader.byteCount, samples, samples, NULL, true); + LogTrace_ISO15693(DecodeReader.output, DecodeReader.byteCount, samples*64, samples*64, NULL, true); /* And ready to receive another command. */ DecodeReaderReset(&DecodeReader); /* And also reset the demod code, which might have been */ @@ -1184,7 +1231,7 @@ void SnoopIso15693(void) if (Handle15693SamplesFromTag(snoopdata >> 2, &DecodeTag)) { FpgaDisableSscDma(); //Use samples as a time measurement - LogTrace(DecodeTag.output, DecodeTag.len, samples, samples, NULL, false); + LogTrace_ISO15693(DecodeTag.output, DecodeTag.len, samples*64, samples*64, NULL, false); // And ready to receive another response. DecodeTagReset(&DecodeTag); DecodeReaderReset(&DecodeReader); @@ -1213,10 +1260,8 @@ void SnoopIso15693(void) // Initialize the proxmark as iso15k reader -static void Iso15693InitReader() { +void Iso15693InitReader() { FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - // Setup SSC - // FpgaSetupSsc(); // Start from off (no field generated) LED_D_OFF(); @@ -1300,17 +1345,20 @@ static void BuildInventoryResponse(uint8_t *uid) // init ... should we initialize the reader? // speed ... 0 low speed, 1 hi speed // *recv will contain the tag's answer -// return: lenght of received data -int SendDataTag(uint8_t *send, int sendlen, bool init, int speed, uint8_t *recv, uint16_t max_recv_len, uint32_t start_time) { +// return: length of received data, or -1 for timeout +int SendDataTag(uint8_t *send, int sendlen, bool init, int speed, uint8_t *recv, uint16_t max_recv_len, uint32_t start_time, uint32_t *eof_time) { LED_A_ON(); LED_B_OFF(); LED_C_OFF(); - if (init) Iso15693InitReader(); - - int answerLen=0; - + if (init) { + Iso15693InitReader(); + StartCountSspClk(); + } + + int answerLen = 0; + if (!speed) { // low speed (1 out of 256) CodeIso15693AsReader256(send, sendlen); @@ -1319,11 +1367,14 @@ int SendDataTag(uint8_t *send, int sendlen, bool init, int speed, uint8_t *recv, CodeIso15693AsReader(send, sendlen); } - TransmitTo15693Tag(ToSend, ToSendMax, start_time); + if (start_time == 0) { + start_time = GetCountSspClk(); + } + TransmitTo15693Tag(ToSend, ToSendMax, &start_time); // Now wait for a response if (recv != NULL) { - answerLen = GetIso15693AnswerFromTag(recv, max_recv_len, DELAY_ISO15693_VCD_TO_VICC_READER * 2); + answerLen = GetIso15693AnswerFromTag(recv, max_recv_len, DELAY_ISO15693_VCD_TO_VICC_READER * 2, eof_time); } LED_A_OFF(); @@ -1445,11 +1496,13 @@ void ReaderIso15693(uint32_t parameter) // Now send the IDENTIFY command BuildIdentifyRequest(); - TransmitTo15693Tag(ToSend, ToSendMax, 0); + uint32_t start_time = 0; + TransmitTo15693Tag(ToSend, ToSendMax, &start_time); // Now wait for a response - answerLen = GetIso15693AnswerFromTag(answer, sizeof(answer), DELAY_ISO15693_VCD_TO_VICC_READER * 2) ; - uint32_t start_time = GetCountSspClk() + DELAY_ISO15693_VICC_TO_VCD_READER; + uint32_t eof_time; + answerLen = GetIso15693AnswerFromTag(answer, sizeof(answer), DELAY_ISO15693_VCD_TO_VICC_READER * 2, &eof_time) ; + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; if (answerLen >=12) // we should do a better check than this { @@ -1487,9 +1540,9 @@ void ReaderIso15693(uint32_t parameter) if (answerLen >= 12 && DEBUG) { for (int i = 0; i < 32; i++) { // sanity check, assume max 32 pages BuildReadBlockRequest(TagUID, i); - TransmitTo15693Tag(ToSend, ToSendMax, start_time); - int answerLen = GetIso15693AnswerFromTag(answer, sizeof(answer), DELAY_ISO15693_VCD_TO_VICC_READER * 2); - start_time = GetCountSspClk() + DELAY_ISO15693_VICC_TO_VCD_READER; + TransmitTo15693Tag(ToSend, ToSendMax, &start_time); + int answerLen = GetIso15693AnswerFromTag(answer, sizeof(answer), DELAY_ISO15693_VCD_TO_VICC_READER * 2, &eof_time); + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; if (answerLen > 0) { Dbprintf("READ SINGLE BLOCK %d returned %d octets:", i, answerLen); DbdecodeIso15693Answer(answerLen, answer); @@ -1535,7 +1588,7 @@ void SimTagIso15693(uint32_t parameter, uint8_t *uid) if ((cmd_len >= 5) && (cmd[0] & ISO15693_REQ_INVENTORY) && (cmd[1] == ISO15693_INVENTORY)) { // TODO: check more flags bool slow = !(cmd[0] & ISO15693_REQ_DATARATE_HIGH); - start_time = eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM - DELAY_ARM_TO_READER_SIM; + start_time = eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM; TransmitTo15693Reader(ToSend, ToSendMax, &start_time, 0, slow); } @@ -1557,11 +1610,8 @@ void BruteforceIso15693Afi(uint32_t speed) uint8_t data[6]; uint8_t recv[ISO15693_MAX_RESPONSE_LENGTH]; - - int datalen=0, recvlen=0; - - Iso15693InitReader(); - StartCountSspClk(); + int datalen = 0, recvlen = 0; + uint32_t eof_time; // first without AFI // Tags should respond without AFI and with AFI=0 even when AFI is active @@ -1570,8 +1620,9 @@ void BruteforceIso15693Afi(uint32_t speed) data[1] = ISO15693_INVENTORY; data[2] = 0; // mask length datalen = Iso15693AddCrc(data,3); - recvlen = SendDataTag(data, datalen, false, speed, recv, sizeof(recv), 0); - uint32_t start_time = GetCountSspClk() + DELAY_ISO15693_VICC_TO_VCD_READER; + uint32_t start_time = GetCountSspClk(); + recvlen = SendDataTag(data, datalen, true, speed, recv, sizeof(recv), 0, &eof_time); + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; WDT_HIT(); if (recvlen>=12) { Dbprintf("NoAFI UID=%s", Iso15693sprintUID(NULL, &recv[2])); @@ -1587,8 +1638,8 @@ void BruteforceIso15693Afi(uint32_t speed) for (int i = 0; i < 256; i++) { data[2] = i & 0xFF; datalen = Iso15693AddCrc(data,4); - recvlen = SendDataTag(data, datalen, false, speed, recv, sizeof(recv), start_time); - start_time = GetCountSspClk() + DELAY_ISO15693_VICC_TO_VCD_READER; + recvlen = SendDataTag(data, datalen, false, speed, recv, sizeof(recv), start_time, &eof_time); + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; WDT_HIT(); if (recvlen >= 12) { Dbprintf("AFI=%i UID=%s", i, Iso15693sprintUID(NULL, &recv[2])); @@ -1605,7 +1656,8 @@ void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint int recvlen = 0; uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; - + uint32_t eof_time; + LED_A_ON(); if (DEBUG) { @@ -1613,24 +1665,27 @@ void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint Dbhexdump(datalen, data, false); } - recvlen = SendDataTag(data, datalen, true, speed, (recv?recvbuf:NULL), sizeof(recvbuf), 0); - - if (recv) { - if (DEBUG) { - Dbprintf("RECV:"); - Dbhexdump(recvlen, recvbuf, false); - DbdecodeIso15693Answer(recvlen, recvbuf); - } - - cmd_send(CMD_ACK, recvlen>ISO15693_MAX_RESPONSE_LENGTH?ISO15693_MAX_RESPONSE_LENGTH:recvlen, 0, 0, recvbuf, ISO15693_MAX_RESPONSE_LENGTH); - - } + recvlen = SendDataTag(data, datalen, true, speed, (recv?recvbuf:NULL), sizeof(recvbuf), 0, &eof_time); // for the time being, switch field off to protect rdv4.0 // note: this prevents using hf 15 cmd with s option - which isn't implemented yet anyway FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_D_OFF(); + if (recv) { + if (DEBUG) { + Dbprintf("RECV:"); + if (recvlen > 0) { + Dbhexdump(recvlen, recvbuf, false); + DbdecodeIso15693Answer(recvlen, recvbuf); + } + } + if (recvlen > ISO15693_MAX_RESPONSE_LENGTH) { + recvlen = ISO15693_MAX_RESPONSE_LENGTH; + } + cmd_send(CMD_ACK, recvlen, 0, 0, recvbuf, ISO15693_MAX_RESPONSE_LENGTH); + } + LED_A_OFF(); } @@ -1648,7 +1703,8 @@ void SetTag15693Uid(uint8_t *uid) int recvlen = 0; uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; - + uint32_t eof_time; + LED_A_ON(); // Command 1 : 02213E00000000 @@ -1687,7 +1743,7 @@ void SetTag15693Uid(uint8_t *uid) cmd[3][5] = uid[1]; cmd[3][6] = uid[0]; - for (int i=0; i<4; i++) { + for (int i = 0; i < 4; i++) { // Add the CRC crc = Iso15693Crc(cmd[i], 7); cmd[i][7] = crc & 0xff; @@ -1698,12 +1754,14 @@ void SetTag15693Uid(uint8_t *uid) Dbhexdump(sizeof(cmd[i]), cmd[i], false); } - recvlen = SendDataTag(cmd[i], sizeof(cmd[i]), true, 1, recvbuf, sizeof(recvbuf), 0); + recvlen = SendDataTag(cmd[i], sizeof(cmd[i]), true, 1, recvbuf, sizeof(recvbuf), 0, &eof_time); if (DEBUG) { Dbprintf("RECV:"); - Dbhexdump(recvlen, recvbuf, false); - DbdecodeIso15693Answer(recvlen, recvbuf); + if (recvlen > 0) { + Dbhexdump(recvlen, recvbuf, false); + DbdecodeIso15693Answer(recvlen, recvbuf); + } } cmd_send(CMD_ACK, recvlen>ISO15693_MAX_RESPONSE_LENGTH?ISO15693_MAX_RESPONSE_LENGTH:recvlen, 0, 0, recvbuf, ISO15693_MAX_RESPONSE_LENGTH); diff --git a/armsrc/iso15693.h b/armsrc/iso15693.h index 7d2e7598..96a2b39b 100644 --- a/armsrc/iso15693.h +++ b/armsrc/iso15693.h @@ -17,16 +17,18 @@ // Delays in SSP_CLK ticks. // SSP_CLK runs at 13,56MHz / 32 = 423.75kHz when simulating a tag -#define DELAY_READER_TO_ARM_SIM 8 -#define DELAY_ARM_TO_READER_SIM 0 -#define DELAY_ISO15693_VCD_TO_VICC_SIM 132 // 132/423.75kHz = 311.5us from end of command EOF to start of tag response -//SSP_CLK runs at 13.56MHz / 4 = 3,39MHz when acting as reader +#define DELAY_ISO15693_VCD_TO_VICC_SIM 132 // 132/423.75kHz = 311.5us from end of command EOF to start of tag response +//SSP_CLK runs at 13.56MHz / 4 = 3,39MHz when acting as reader. All values should be multiples of 16 #define DELAY_ISO15693_VCD_TO_VICC_READER 1056 // 1056/3,39MHz = 311.5us from end of command EOF to start of tag response -#define DELAY_ISO15693_VICC_TO_VCD_READER 1017 // 1017/3.39MHz = 300us between end of tag response and next reader command +#define DELAY_ISO15693_VICC_TO_VCD_READER 1024 // 1024/3.39MHz = 302.1us between end of tag response and next reader command +void Iso15693InitReader(); +void CodeIso15693AsReader(uint8_t *cmd, int n); void CodeIso15693AsTag(uint8_t *cmd, size_t len); -int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eof_time); void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, uint32_t slot_time, bool slow); +int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eof_time); +void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time); +int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeout, uint32_t *eof_time); void SnoopIso15693(void); void AcquireRawAdcSamplesIso15693(void); void ReaderIso15693(uint32_t parameter); @@ -35,5 +37,6 @@ void BruteforceIso15693Afi(uint32_t speed); void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint8_t data[]); void SetTag15693Uid(uint8_t *uid); void SetDebugIso15693(uint32_t flag); +bool LogTrace_ISO15693(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag); #endif diff --git a/armsrc/util.c b/armsrc/util.c index aac68a34..4bff3a26 100644 --- a/armsrc/util.c +++ b/armsrc/util.c @@ -21,7 +21,7 @@ void print_result(char *name, uint8_t *buf, size_t len) { if ( len % 16 == 0 ) { for(; p-buf < len; p += 16) - Dbprintf("[%s:%d/%d] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", + Dbprintf("[%s:%d/%d] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", name, p-buf, len, @@ -30,7 +30,7 @@ void print_result(char *name, uint8_t *buf, size_t len) { } else { for(; p-buf < len; p += 8) - Dbprintf("[%s:%d/%d] %02x %02x %02x %02x %02x %02x %02x %02x", name, p-buf, len, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); + Dbprintf("[%s:%d/%d] %02x %02x %02x %02x %02x %02x %02x %02x", name, p-buf, len, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); } } @@ -68,17 +68,17 @@ uint64_t bytes_to_num(uint8_t* src, size_t len) // RotateLeft - Ultralight, Desfire void rol(uint8_t *data, const size_t len){ - uint8_t first = data[0]; - for (size_t i = 0; i < len-1; i++) { - data[i] = data[i+1]; - } - data[len-1] = first; + uint8_t first = data[0]; + for (size_t i = 0; i < len-1; i++) { + data[i] = data[i+1]; + } + data[len-1] = first; } void lsl (uint8_t *data, size_t len) { - for (size_t n = 0; n < len - 1; n++) { - data[n] = (data[n] << 1) | (data[n+1] >> 7); - } - data[len - 1] <<= 1; + for (size_t n = 0; n < len - 1; n++) { + data[n] = (data[n] << 1) | (data[n+1] >> 7); + } + data[len - 1] <<= 1; } void LEDsoff() @@ -309,16 +309,16 @@ void FormatVersionInformation(char *dst, int len, const char *prefix, void *vers // ------------------------------------------------------------------------- // test procedure: // -// ti = GetTickCount(); -// SpinDelay(1000); -// ti = GetTickCount() - ti; -// Dbprintf("timer(1s): %d t=%d", ti, GetTickCount()); +// ti = GetTickCount(); +// SpinDelay(1000); +// ti = GetTickCount() - ti; +// Dbprintf("timer(1s): %d t=%d", ti, GetTickCount()); void StartTickCount() { // This timer is based on the slow clock. The slow clock frequency is between 22kHz and 40kHz. // We can determine the actual slow clock frequency by looking at the Main Clock Frequency Register. - uint16_t mainf = AT91C_BASE_PMC->PMC_MCFR & 0xffff; // = 16 * main clock frequency (16MHz) / slow clock frequency + uint16_t mainf = AT91C_BASE_PMC->PMC_MCFR & 0xffff; // = 16 * main clock frequency (16MHz) / slow clock frequency // set RealTimeCounter divider to count at 1kHz: AT91C_BASE_RTTC->RTTC_RTMR = AT91C_RTTC_RTTRST | ((256000 + (mainf/2)) / mainf); // note: worst case precision is approx 2.5% @@ -334,12 +334,12 @@ uint32_t RAMFUNC GetTickCount(){ // ------------------------------------------------------------------------- -// microseconds timer +// microseconds timer // ------------------------------------------------------------------------- void StartCountUS() { AT91C_BASE_PMC->PMC_PCER |= (0x1 << 12) | (0x1 << 13) | (0x1 << 14); -// AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC1XC1S_TIOA0; +// AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC1XC1S_TIOA0; AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE; // fast clock @@ -349,10 +349,10 @@ void StartCountUS() AT91C_TC_ACPC_SET | AT91C_TC_ASWTRG_SET; AT91C_BASE_TC0->TC_RA = 1; AT91C_BASE_TC0->TC_RC = 0xBFFF + 1; // 0xC000 - - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // timer disable + + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // timer disable AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_XC1; // from timer 0 - + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN; AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN; AT91C_BASE_TCB->TCB_BCR = 1; @@ -375,61 +375,72 @@ uint32_t RAMFUNC GetDeltaCountUS(){ // ------------------------------------------------------------------------- -// Timer for iso14443 commands. Uses ssp_clk from FPGA +// Timer for iso14443 commands. Uses ssp_clk from FPGA // ------------------------------------------------------------------------- void StartCountSspClk() { AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1) | (1 << AT91C_ID_TC2); // Enable Clock to all timers - AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_TIOA1 // XC0 Clock = TIOA1 - | AT91C_TCB_TC1XC1S_NONE // XC1 Clock = none - | AT91C_TCB_TC2XC2S_TIOA0; // XC2 Clock = TIOA0 + AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_TIOA1 // XC0 Clock = TIOA1 + | AT91C_TCB_TC1XC1S_NONE // XC1 Clock = none + | AT91C_TCB_TC2XC2S_TIOA0; // XC2 Clock = TIOA0 // configure TC1 to create a short pulse on TIOA1 when a rising edge on TIOB1 (= ssp_clk from FPGA) occurs: - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // disable TC1 + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // disable TC1 AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK // TC1 Clock = MCK(48MHz)/2 = 24MHz - | AT91C_TC_CPCSTOP // Stop clock on RC compare - | AT91C_TC_EEVTEDG_RISING // Trigger on rising edge of Event - | AT91C_TC_EEVT_TIOB // Event-Source: TIOB1 (= ssp_clk from FPGA = 13,56MHz/16 ... 13,56MHz/4) - | AT91C_TC_ENETRG // Enable external trigger event - | AT91C_TC_WAVESEL_UP // Upmode without automatic trigger on RC compare - | AT91C_TC_WAVE // Waveform Mode - | AT91C_TC_AEEVT_SET // Set TIOA1 on external event - | AT91C_TC_ACPC_CLEAR; // Clear TIOA1 on RC Compare - AT91C_BASE_TC1->TC_RC = 0x02; // RC Compare value = 0x02 + | AT91C_TC_CPCSTOP // Stop clock on RC compare + | AT91C_TC_EEVTEDG_RISING // Trigger on rising edge of Event + | AT91C_TC_EEVT_TIOB // Event-Source: TIOB1 (= ssp_clk from FPGA = 13,56MHz/16 ... 13,56MHz/4) + | AT91C_TC_ENETRG // Enable external trigger event + | AT91C_TC_WAVESEL_UP // Upmode without automatic trigger on RC compare + | AT91C_TC_WAVE // Waveform Mode + | AT91C_TC_AEEVT_SET // Set TIOA1 on external event + | AT91C_TC_ACPC_CLEAR; // Clear TIOA1 on RC Compare + AT91C_BASE_TC1->TC_RC = 0x02; // RC Compare value = 0x02 // use TC0 to count TIOA1 pulses - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // disable TC0 - AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_XC0 // TC0 clock = XC0 clock = TIOA1 - | AT91C_TC_WAVE // Waveform Mode - | AT91C_TC_WAVESEL_UP // just count - | AT91C_TC_ACPA_CLEAR // Clear TIOA0 on RA Compare - | AT91C_TC_ACPC_SET; // Set TIOA0 on RC Compare - AT91C_BASE_TC0->TC_RA = 1; // RA Compare value = 1; pulse width to TC2 - AT91C_BASE_TC0->TC_RC = 0; // RC Compare value = 0; increment TC2 on overflow + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // disable TC0 + AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_XC0 // TC0 clock = XC0 clock = TIOA1 + | AT91C_TC_WAVE // Waveform Mode + | AT91C_TC_WAVESEL_UP // just count + | AT91C_TC_ACPA_CLEAR // Clear TIOA0 on RA Compare + | AT91C_TC_ACPC_SET; // Set TIOA0 on RC Compare + AT91C_BASE_TC0->TC_RA = 1; // RA Compare value = 1; pulse width to TC2 + AT91C_BASE_TC0->TC_RC = 0; // RC Compare value = 0; increment TC2 on overflow // use TC2 to count TIOA0 pulses (giving us a 32bit counter (TC0/TC2) clocked by ssp_clk) - AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKDIS; // disable TC2 - AT91C_BASE_TC2->TC_CMR = AT91C_TC_CLKS_XC2 // TC2 clock = XC2 clock = TIOA0 - | AT91C_TC_WAVE // Waveform Mode - | AT91C_TC_WAVESEL_UP; // just count - - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN; // enable TC0 - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN; // enable TC1 - AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN; // enable TC2 + AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKDIS; // disable TC2 + AT91C_BASE_TC2->TC_CMR = AT91C_TC_CLKS_XC2 // TC2 clock = XC2 clock = TIOA0 + | AT91C_TC_WAVE // Waveform Mode + | AT91C_TC_WAVESEL_UP; // just count + + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN; // enable TC0 + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN; // enable TC1 + AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN; // enable TC2 // - // synchronize the counter with the ssp_frame signal. Note: FPGA must be in a FPGA mode with SSC transfer, otherwise SSC_FRAME and SSC_CLK signals would not be present + // synchronize the counter with the ssp_frame signal. Note: FPGA must be in a FPGA mode with SSC transfer, otherwise SSC_FRAME and SSC_CLK signals would not be present // - while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME)); // wait for ssp_frame to go high (start of frame) - while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME); // wait for ssp_frame to be low - while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high - // note: up to now two ssp_clk rising edges have passed since the rising edge of ssp_frame + while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME); // wait for ssp_frame to be low + while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME)); // wait for ssp_frame to go high (start of frame) + while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 1st ssp_clk after start of frame + while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low; + while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 2nd ssp_clk after start of frame + if ((AT91C_BASE_SSC->SSC_RFMR & SSC_FRAME_MODE_BITS_IN_WORD(32)) == SSC_FRAME_MODE_BITS_IN_WORD(16)) { + while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low; + while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 3rd ssp_clk after start of frame + while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low; + while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 4th ssp_clk after start of frame + while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low; + while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 5th ssp_clk after start of frame + while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low; + while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 6th ssp_clk after start of frame + } // it is now safe to assert a sync signal. This sets all timers to 0 on next active clock edge - AT91C_BASE_TCB->TCB_BCR = 1; // assert Sync (set all timers to 0 on next active clock edge) - // at the next (3rd) ssp_clk rising edge, TC1 will be reset (and not generate a clock signal to TC0) - // at the next (4th) ssp_clk rising edge, TC0 (the low word of our counter) will be reset. From now on, + AT91C_BASE_TCB->TCB_BCR = 1; // assert Sync (set all timers to 0 on next active clock edge) + // at the next (3rd/7th) ssp_clk rising edge, TC1 will be reset (and not generate a clock signal to TC0) + // at the next (4th/8th) ssp_clk rising edge, TC0 (the low word of our counter) will be reset. From now on, // whenever the last three bits of our counter go 0, we can be sure to be in the middle of a frame transfer. - // (just started with the transfer of the 4th Bit). + // (just started with the transfer of the 3rd Bit). // The high word of the counter (TC2) will not reset until the low word (TC0) overflows. Therefore need to wait quite some time before // we can use the counter. while (AT91C_BASE_TC0->TC_CV < 0xFFFF); @@ -445,19 +456,17 @@ void ResetSspClk(void) { while (AT91C_BASE_TC2->TC_CV > 0); } - uint32_t GetCountSspClk(){ uint32_t hi, lo; - do { + do { hi = AT91C_BASE_TC2->TC_CV; lo = AT91C_BASE_TC0->TC_CV; - } while(hi != AT91C_BASE_TC2->TC_CV); - + } while (hi != AT91C_BASE_TC2->TC_CV); + return (hi << 16) | lo; } - // ------------------------------------------------------------------------- // Timer for bitbanging, or LF stuff when you need a very precis timer // 1us = 1.5ticks @@ -476,11 +485,11 @@ void StartTicks(void){ AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // re-enable timer and wait for TC0 // second configure TC0 (lower, 0x0000FFFF) 16 bit counter - AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK | // MCK(48MHz) / 32 - AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO | - AT91C_TC_ACPA_CLEAR | // RA comperator clears TIOA (carry bit) - AT91C_TC_ACPC_SET | // RC comperator sets TIOA (carry bit) - AT91C_TC_ASWTRG_SET; // SWTriger sets TIOA (carry bit) + AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK | // MCK(48MHz) / 32 + AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO | + AT91C_TC_ACPA_CLEAR | // RA comperator clears TIOA (carry bit) + AT91C_TC_ACPC_SET | // RC comperator sets TIOA (carry bit) + AT91C_TC_ASWTRG_SET; // SWTriger sets TIOA (carry bit) AT91C_BASE_TC0->TC_RC = 0; // set TIOA (carry bit) on overflow, return to zero AT91C_BASE_TC0->TC_RA = 1; // clear carry bit on next clock cycle AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // reset and re-enable timer @@ -517,7 +526,7 @@ void WaitTicks(uint32_t ticks){ } -// Wait / Spindelay in us (microseconds) +// Wait / Spindelay in us (microseconds) // 1us = 1.5ticks. void WaitUS(uint16_t us){ WaitTicks( (uint32_t)us * 3 / 2 ) ; @@ -546,7 +555,7 @@ void ResetTimer(AT91PS_TC timer){ // stop clock void StopTicks(void){ AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; } diff --git a/armsrc/util.h b/armsrc/util.h index 7b3d0849..14ac5e10 100644 --- a/armsrc/util.h +++ b/armsrc/util.h @@ -66,7 +66,7 @@ uint32_t RAMFUNC GetDeltaCountUS(); void StartCountSspClk(); void ResetSspClk(void); -uint32_t RAMFUNC GetCountSspClk(); +uint32_t GetCountSspClk(); extern void StartTicks(void); extern uint32_t GetTicks(void); diff --git a/client/cmdhf15.c b/client/cmdhf15.c index c2a13354..6bcad201 100644 --- a/client/cmdhf15.c +++ b/client/cmdhf15.c @@ -464,7 +464,7 @@ int CmdHF15CmdRaw (const char *cmd) { char *hexout; - if (strlen(cmd)<3) { + if (strlen(cmd)<2) { PrintAndLog("Usage: hf 15 cmd raw [-r] [-2] [-c] <0A 0B 0C ... hex>"); PrintAndLog(" -r do not read response"); PrintAndLog(" -2 use slower '1 out of 256' mode"); @@ -526,22 +526,31 @@ int CmdHF15CmdRaw (const char *cmd) { SendCommand(&c); if (reply) { - if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) { + if (WaitForResponseTimeout(CMD_ACK, &resp, 1000)) { recv = resp.d.asBytes; - PrintAndLog("received %i octets",resp.arg[0]); - hexout = (char *)malloc(resp.arg[0] * 3 + 1); - if (hexout != NULL) { - for (int i = 0; i < resp.arg[0]; i++) { // data in hex - sprintf(&hexout[i * 3], "%02X ", recv[i]); + int recv_len = resp.arg[0]; + if (recv_len == 0) { + PrintAndLog("received SOF only. Maybe Picopass/iCLASS?"); + } else if (recv_len > 0) { + PrintAndLog("received %i octets", recv_len); + hexout = (char *)malloc(resp.arg[0] * 3 + 1); + if (hexout != NULL) { + for (int i = 0; i < resp.arg[0]; i++) { // data in hex + sprintf(&hexout[i * 3], "%02X ", recv[i]); + } + PrintAndLog("%s", hexout); + free(hexout); } - PrintAndLog("%s", hexout); - free(hexout); + } else if (recv_len == -1) { + PrintAndLog("card didn't respond"); + } else if (recv_len == -2) { + PrintAndLog("receive buffer overflow"); } } else { PrintAndLog("timeout while waiting for reply."); } - - } // if reply + } + return 0; } diff --git a/client/cmdhflist.c b/client/cmdhflist.c index 07a286cc..29d10d92 100644 --- a/client/cmdhflist.c +++ b/client/cmdhflist.c @@ -903,8 +903,6 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui // adjust for different time scales if (protocol == ICLASS || protocol == ISO_15693) { - first_timestamp *= 32; - timestamp *= 32; duration *= 32; } @@ -1037,10 +1035,6 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui if (showWaitCycles && !isResponse && next_record_is_response(tracepos, trace)) { uint32_t next_timestamp = *((uint32_t *)(trace + tracepos)); - // adjust for different time scales - if (protocol == ICLASS || protocol == ISO_15693) { - next_timestamp *= 32; - } PrintAndLog(" %10d | %10d | %s | fdt (Frame Delay Time): %d", (EndOfTransmissionTimestamp - first_timestamp), diff --git a/fpga/fpga_hf.bit b/fpga/fpga_hf.bit index 44b2428040ab74e66878d78bf7cc7a79ee3c7266..3899059714dcdd9904577d9aaa21d64cf3efdbd5 100644 GIT binary patch literal 42175 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�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

+G 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 z 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 Date: Tue, 22 Oct 2019 21:02:02 +0200 Subject: [PATCH 142/189] 'hf 14b' formatting * renaming a few functions * whitespace * moving a bit towards RRG repo --- client/cmdhf.c | 2 +- client/cmdhf14b.c | 401 ++++++++++++++++++++++++++-------------------- client/cmdhf14b.h | 2 +- 3 files changed, 226 insertions(+), 179 deletions(-) diff --git a/client/cmdhf.c b/client/cmdhf.c index 6d25cac0..83170cae 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -61,7 +61,7 @@ int CmdHFSearch(const char *Cmd){ return ans; } //14b is longest test currently (and rarest chip type) ... put last - ans = HF14BInfo(false); + ans = infoHF14B(false); if (ans) { PrintAndLog("\nValid ISO14443B Tag Found - Quiting Search\n"); return ans; diff --git a/client/cmdhf14b.c b/client/cmdhf14b.c index 7cd55476..8a83df8f 100644 --- a/client/cmdhf14b.c +++ b/client/cmdhf14b.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "iso14443crc.h" #include "comms.h" #include "graph.h" @@ -25,101 +26,98 @@ #include "taginfo.h" -static int CmdHelp(const char *Cmd); - -int CmdHF14BList(const char *Cmd) -{ +int CmdHF14BList(const char *Cmd) { PrintAndLog("Deprecated command, use 'hf list 14b' instead"); - return 0; } -int CmdHF14BSim(const char *Cmd) -{ + +int CmdHF14BSim(const char *Cmd) { UsbCommand c={CMD_SIMULATE_TAG_ISO_14443B}; clearCommandBuffer(); SendCommand(&c); return 0; } -int CmdHF14BSnoop(const char *Cmd) -{ + +int CmdHF14BSnoop(const char *Cmd) { UsbCommand c = {CMD_SNOOP_ISO_14443B}; clearCommandBuffer(); SendCommand(&c); return 0; } + /* New command to read the contents of a SRI512 tag * SRI512 tags are ISO14443-B modulated memory tags, * this command just dumps the contents of the memory */ -int CmdSri512Read(const char *Cmd) -{ +int CmdSri512Read(const char *Cmd) { UsbCommand c = {CMD_READ_SRI512_TAG, {strtol(Cmd, NULL, 0), 0, 0}}; clearCommandBuffer(); SendCommand(&c); return 0; } + /* New command to read the contents of a SRIX4K tag * SRIX4K tags are ISO14443-B modulated memory tags, * this command just dumps the contents of the memory/ */ -int CmdSrix4kRead(const char *Cmd) -{ +int CmdSrix4kRead(const char *Cmd) { UsbCommand c = {CMD_READ_SRIX4K_TAG, {strtol(Cmd, NULL, 0), 0, 0}}; clearCommandBuffer(); SendCommand(&c); return 0; } -int rawClose(void){ + +static bool switch_off_field_14b(void) { UsbCommand resp; UsbCommand c = {CMD_ISO_14443B_COMMAND, {0, 0, 0}}; clearCommandBuffer(); SendCommand(&c); - if (!WaitForResponseTimeout(CMD_ACK,&resp,1000)) { - return 0; + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) { + return false; } - return 0; + return false; } -int HF14BCmdRaw(bool reply, bool *crc, bool power, uint8_t *data, uint8_t *datalen, bool verbose){ + +int HF14BCmdRaw(bool reply, bool *crc, bool power, uint8_t *data, uint8_t *datalen, bool verbose) { UsbCommand resp; UsbCommand c = {CMD_ISO_14443B_COMMAND, {0, 0, 0}}; // len,recv,power - if(*crc) - { + if (*crc) { uint8_t first, second; ComputeCrc14443(CRC_14443_B, data, *datalen, &first, &second); data[*datalen] = first; data[*datalen + 1] = second; *datalen += 2; } - + c.arg[0] = *datalen; c.arg[1] = reply; c.arg[2] = power; - memcpy(c.d.asBytes,data,*datalen); + memcpy(c.d.asBytes,data, *datalen); clearCommandBuffer(); SendCommand(&c); - - if (!reply) return 1; - if (!WaitForResponseTimeout(CMD_ACK,&resp,1000)) { + if (!reply) return 1; + + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) { if (verbose) PrintAndLog("timeout while waiting for reply."); return 0; } *datalen = resp.arg[0]; if (verbose) PrintAndLog("received %u octets", *datalen); - if(*datalen<2) return 0; + if (*datalen < 2) return 0; memcpy(data, resp.d.asBytes, *datalen); if (verbose) PrintAndLog("%s", sprint_hex(data, *datalen)); uint8_t first, second; ComputeCrc14443(CRC_14443_B, data, *datalen-2, &first, &second); - if(data[*datalen-2] == first && data[*datalen-1] == second) { + if (data[*datalen-2] == first && data[*datalen-1] == second) { if (verbose) PrintAndLog("CRC OK"); *crc = true; } else { @@ -129,7 +127,8 @@ int HF14BCmdRaw(bool reply, bool *crc, bool power, uint8_t *data, uint8_t *datal return 1; } -int CmdHF14BCmdRaw (const char *Cmd) { + +static int CmdHF14BCmdRaw (const char *Cmd) { bool reply = true; bool crc = false; bool power = false; @@ -140,7 +139,7 @@ int CmdHF14BCmdRaw (const char *Cmd) { uint8_t datalen = 0; unsigned int temp; int i = 0; - if (strlen(Cmd)<3) { + if (strlen(Cmd) < 3) { PrintAndLog("Usage: hf 14b raw [-r] [-c] [-p] [-s || -ss] <0A 0B 0C ... hex>"); PrintAndLog(" -r do not read response"); PrintAndLog(" -c calculate and append CRC"); @@ -151,28 +150,28 @@ int CmdHF14BCmdRaw (const char *Cmd) { } // strip - while (*Cmd==' ' || *Cmd=='\t') Cmd++; - - while (Cmd[i]!='\0') { - if (Cmd[i]==' ' || Cmd[i]=='\t') { i++; continue; } - if (Cmd[i]=='-') { + while (*Cmd == ' ' || *Cmd == '\t') Cmd++; + + while (Cmd[i] != '\0') { + if (Cmd[i] == ' ' || Cmd[i] == '\t') { i++; continue; } + if (Cmd[i] == '-') { switch (Cmd[i+1]) { - case 'r': - case 'R': + case 'r': + case 'R': reply = false; break; case 'c': - case 'C': + case 'C': crc = true; break; - case 'p': - case 'P': + case 'p': + case 'P': power = true; break; case 's': case 'S': select = true; - if (Cmd[i+2]=='s' || Cmd[i+2]=='S') { + if (Cmd[i+2] == 's' || Cmd[i+2] == 'S') { SRx = true; i++; } @@ -181,34 +180,33 @@ int CmdHF14BCmdRaw (const char *Cmd) { PrintAndLog("Invalid option"); return 0; } - i+=2; + i += 2; continue; } - if ((Cmd[i]>='0' && Cmd[i]<='9') || - (Cmd[i]>='a' && Cmd[i]<='f') || - (Cmd[i]>='A' && Cmd[i]<='F') ) { - buf[strlen(buf)+1]=0; - buf[strlen(buf)]=Cmd[i]; + if ((Cmd[i] >= '0' && Cmd[i] <= '9') || + (Cmd[i] >= 'a' && Cmd[i] <= 'f') || + (Cmd[i] >= 'A' && Cmd[i] <= 'F') ) { + buf[strlen(buf)+1] = 0; + buf[strlen(buf)] = Cmd[i]; i++; - - if (strlen(buf)>=2) { - sscanf(buf,"%x",&temp); - data[datalen++]=(uint8_t)(temp & 0xff); - *buf=0; + + if (strlen(buf) >= 2) { + sscanf(buf, "%x", &temp); + data[datalen++] = (uint8_t)(temp & 0xff); + *buf = 0; } continue; } PrintAndLog("Invalid char on input"); return 0; } - if (datalen == 0) - { + if (datalen == 0) { PrintAndLog("Missing data input"); return 0; } - if (select){ //auto select 14b tag - uint8_t cmd2[16]; + if (select) { //auto select 14b tag + uint8_t cmd2[16]; bool crc2 = true; uint8_t cmdLen; @@ -225,11 +223,11 @@ int CmdHF14BCmdRaw (const char *Cmd) { cmd2[2] = 0x08; } - if (HF14BCmdRaw(true, &crc2, true, cmd2, &cmdLen, false)==0) return rawClose(); + if (HF14BCmdRaw(true, &crc2, true, cmd2, &cmdLen, false) == 0) return switch_off_field_14b(); + + if (SRx && (cmdLen != 3 || !crc2) ) return switch_off_field_14b(); + else if (cmd2[0] != 0x50 || cmdLen != 14 || !crc2) return switch_off_field_14b(); - if ( SRx && (cmdLen != 3 || !crc2) ) return rawClose(); - else if (cmd2[0] != 0x50 || cmdLen != 14 || !crc2) return rawClose(); - uint8_t chipID = 0; if (SRx) { // select @@ -239,7 +237,7 @@ int CmdHF14BCmdRaw (const char *Cmd) { cmdLen = 2; } else { // attrib - cmd2[0] = 0x1D; + cmd2[0] = 0x1D; // UID from cmd2[1 - 4] cmd2[5] = 0x00; cmd2[6] = 0x08; @@ -248,39 +246,40 @@ int CmdHF14BCmdRaw (const char *Cmd) { cmdLen = 9; } - if (HF14BCmdRaw(true, &crc2, true, cmd2, &cmdLen, false)==0) return rawClose(); + if (HF14BCmdRaw(true, &crc2, true, cmd2, &cmdLen, false) == 0) return switch_off_field_14b(); - if (cmdLen != 3 || !crc2) return rawClose(); - if (SRx && cmd2[0] != chipID) return rawClose(); + if (cmdLen != 3 || !crc2) return switch_off_field_14b(); + if (SRx && cmd2[0] != chipID) return switch_off_field_14b(); } return HF14BCmdRaw(reply, &crc, power, data, &datalen, true); } + // print full atqb info -static void print_atqb_resp(uint8_t *data){ +static void print_atqb_resp(uint8_t *data) { //PrintAndLog (" UID: %s", sprint_hex(data+1,4)); - PrintAndLog (" App Data: %s", sprint_hex(data+5,4)); - PrintAndLog (" Protocol: %s", sprint_hex(data+9,3)); + PrintAndLog(" App Data: %s", sprint_hex(data+5,4)); + PrintAndLog(" Protocol: %s", sprint_hex(data+9,3)); uint8_t BitRate = data[9]; - if (!BitRate) + if (!BitRate) PrintAndLog (" Bit Rate: 106 kbit/s only PICC <-> PCD"); if (BitRate & 0x10) PrintAndLog (" Bit Rate: 212 kbit/s PICC -> PCD supported"); if (BitRate & 0x20) - PrintAndLog (" Bit Rate: 424 kbit/s PICC -> PCD supported"); + PrintAndLog (" Bit Rate: 424 kbit/s PICC -> PCD supported"); if (BitRate & 0x40) - PrintAndLog (" Bit Rate: 847 kbit/s PICC -> PCD supported"); + PrintAndLog (" Bit Rate: 847 kbit/s PICC -> PCD supported"); if (BitRate & 0x01) PrintAndLog (" Bit Rate: 212 kbit/s PICC <- PCD supported"); if (BitRate & 0x02) - PrintAndLog (" Bit Rate: 424 kbit/s PICC <- PCD supported"); + PrintAndLog (" Bit Rate: 424 kbit/s PICC <- PCD supported"); if (BitRate & 0x04) - PrintAndLog (" Bit Rate: 847 kbit/s PICC <- PCD supported"); - if (BitRate & 0x80) + PrintAndLog (" Bit Rate: 847 kbit/s PICC <- PCD supported"); + if (BitRate & 0x80) PrintAndLog (" Same bit rate <-> required"); - uint16_t maxFrame = data[10]>>4; - if (maxFrame < 5) + uint16_t maxFrame = data[10] >> 4; + if (maxFrame < 5) maxFrame = 8*maxFrame + 16; else if (maxFrame == 5) maxFrame = 64; @@ -293,7 +292,7 @@ static void print_atqb_resp(uint8_t *data){ else maxFrame = 257; - PrintAndLog ("Max Frame Size: %u%s",maxFrame, (maxFrame == 257) ? "+ RFU" : ""); + PrintAndLog ("Max Frame Size: %u%s", maxFrame, (maxFrame == 257) ? "+ RFU" : ""); uint8_t protocolT = data[10] & 0xF; PrintAndLog (" Protocol Type: Protocol is %scompliant with ISO/IEC 14443-4",(protocolT) ? "" : "not " ); @@ -302,32 +301,32 @@ static void print_atqb_resp(uint8_t *data){ PrintAndLog (" Frame Options: NAD is %ssupported",(data[11]&2) ? "" : "not "); PrintAndLog (" Frame Options: CID is %ssupported",(data[11]&1) ? "" : "not "); PrintAndLog ("Max Buf Length: %u (MBLI) %s",data[14]>>4, (data[14] & 0xF0) ? "" : "not supported"); - + return; } -int print_ST_Lock_info(uint8_t model){ +int print_ST_Lock_info(uint8_t model) { //assume connection open and tag selected... uint8_t data[16] = {0x00}; uint8_t datalen = 2; bool crc = true; uint8_t resplen; - uint8_t blk1; + uint8_t blk1; data[0] = 0x08; - if (model == 0x2) { //SR176 has special command: - data[1] = 0xf; - resplen = 4; + if (model == 0x02) { //SR176 has special command: + data[1] = 0x0f; + resplen = 4; } else { data[1] = 0xff; resplen = 6; } //std read cmd - if (HF14BCmdRaw(true, &crc, true, data, &datalen, false)==0) return rawClose(); + if (HF14BCmdRaw(true, &crc, true, data, &datalen, false) == 0) return switch_off_field_14b(); - if (datalen != resplen || !crc) return rawClose(); + if (datalen != resplen || !crc) return switch_off_field_14b(); PrintAndLog("Chip Write Protection Bits:"); // now interpret the data @@ -339,7 +338,7 @@ int print_ST_Lock_info(uint8_t model){ blk1 = 9; PrintAndLog(" raw: %s",printBits(1,data+3)); PrintAndLog(" 07/08:%slocked", (data[3] & 1) ? " not " : " " ); - for (uint8_t i = 1; i<8; i++){ + for (uint8_t i = 1; i < 8; i++){ PrintAndLog(" %02u:%slocked", blk1, (data[3] & (1 << i)) ? " not " : " " ); blk1++; } @@ -349,9 +348,9 @@ int print_ST_Lock_info(uint8_t model){ case 0xC: // (SRT512) //need data[2] and data[3] blk1 = 0; - PrintAndLog(" raw: %s",printBits(2,data+2)); - for (uint8_t b=2; b<4; b++){ - for (uint8_t i=0; i<8; i++){ + PrintAndLog(" raw: %s", printBits(2,data+2)); + for (uint8_t b = 2; b < 4; b++) { + for (uint8_t i = 0; i < 8; i++) { PrintAndLog(" %02u:%slocked", blk1, (data[b] & (1 << i)) ? " not " : " " ); blk1++; } @@ -360,29 +359,31 @@ int print_ST_Lock_info(uint8_t model){ case 0x2: // (SR176) //need data[2] blk1 = 0; - PrintAndLog(" raw: %s",printBits(1,data+2)); - for (uint8_t i = 0; i<8; i++){ + PrintAndLog(" raw: %s",printBits(1, data+2)); + for (uint8_t i = 0; i < 8; i++){ PrintAndLog(" %02u/%02u:%slocked", blk1, blk1+1, (data[2] & (1 << i)) ? " " : " not " ); - blk1+=2; + blk1 += 2; } break; default: - return rawClose(); + return switch_off_field_14b(); } return 1; } + // print UID info from SRx chips (ST Microelectronics) -static void print_st_general_info(uint8_t *data){ +static void print_st_general_info(uint8_t *data) { //uid = first 8 bytes in data - PrintAndLog(" UID: %s", sprint_hex(SwapEndian64(data,8,8),8)); + PrintAndLog(" UID: %s", sprint_hex(SwapEndian64(data, 8, 8), 8)); PrintAndLog(" MFG: %02X, %s", data[6], getManufacturerName(data[6])); PrintAndLog(" Chip: %02X, %s", data[5], getChipInfo(data[6], data[5])); return; } + // 14b get and print UID only (general info) -int HF14BStdReader(uint8_t *data, uint8_t *datalen){ +int HF14BStdReader(uint8_t *data, uint8_t *datalen) { //05 00 00 = find one tag in field //1d xx xx xx xx 00 08 01 00 = attrib xx=UID (resp 10 [f9 e0]) //a3 = ? (resp 03 [e2 c2]) @@ -407,18 +408,18 @@ int HF14BStdReader(uint8_t *data, uint8_t *datalen){ data[1] = 0x00; data[2] = 0x08; - if (HF14BCmdRaw(true, &crc, true, data, datalen, false)==0) return rawClose(); + if (HF14BCmdRaw(true, &crc, true, data, datalen, false) == 0) return switch_off_field_14b(); - if (data[0] != 0x50 || *datalen != 14 || !crc) return rawClose(); + if (data[0] != 0x50 || *datalen != 14 || !crc) return switch_off_field_14b(); PrintAndLog ("\n14443-3b tag found:"); - PrintAndLog (" UID: %s", sprint_hex(data+1,4)); + PrintAndLog (" UID: %s", sprint_hex(data+1, 4)); - uint8_t cmd2[16]; + uint8_t cmd2[16]; uint8_t cmdLen = 3; bool crc2 = true; - cmd2[0] = 0x1D; + cmd2[0] = 0x1D; // UID from data[1 - 4] cmd2[1] = data[1]; cmd2[2] = data[2]; @@ -431,28 +432,29 @@ int HF14BStdReader(uint8_t *data, uint8_t *datalen){ cmdLen = 9; // attrib - if (HF14BCmdRaw(true, &crc2, true, cmd2, &cmdLen, false)==0) return rawClose(); + if (HF14BCmdRaw(true, &crc2, true, cmd2, &cmdLen, false) == 0) return switch_off_field_14b(); - if (cmdLen != 3 || !crc2) return rawClose(); + if (cmdLen != 3 || !crc2) return switch_off_field_14b(); // add attrib responce to data data[14] = cmd2[0]; - rawClose(); + switch_off_field_14b(); return 1; } + // 14b get and print Full Info (as much as we know) -int HF14BStdInfo(uint8_t *data, uint8_t *datalen){ - if (!HF14BStdReader(data,datalen)) return 0; +static bool HF14B_Std_Info(uint8_t *data, uint8_t *datalen) { + if (!HF14BStdReader(data, datalen)) return false; //add more info here print_atqb_resp(data); - - return 1; + return true; } + // SRx get and print general info about SRx chip from UID -int HF14B_ST_Reader(uint8_t *data, uint8_t *datalen, bool closeCon){ +static bool HF14B_ST_Reader(uint8_t *data, uint8_t *datalen, bool closeCon){ bool crc = true; *datalen = 2; //wake cmd @@ -461,9 +463,9 @@ int HF14B_ST_Reader(uint8_t *data, uint8_t *datalen, bool closeCon){ //leave power on // verbose on for now for testing - turn off when functional - if (HF14BCmdRaw(true, &crc, true, data, datalen, false)==0) return rawClose(); + if (HF14BCmdRaw(true, &crc, true, data, datalen, false) == 0) return switch_off_field_14b(); - if (*datalen != 3 || !crc) return rawClose(); + if (*datalen != 3 || !crc) return switch_off_field_14b(); uint8_t chipID = data[0]; // select @@ -472,118 +474,143 @@ int HF14B_ST_Reader(uint8_t *data, uint8_t *datalen, bool closeCon){ *datalen = 2; //leave power on - if (HF14BCmdRaw(true, &crc, true, data, datalen, false)==0) return rawClose(); + if (HF14BCmdRaw(true, &crc, true, data, datalen, false) == 0) return switch_off_field_14b(); - if (*datalen != 3 || !crc || data[0] != chipID) return rawClose(); + if (*datalen != 3 || !crc || data[0] != chipID) return switch_off_field_14b(); // get uid data[0] = 0x0B; *datalen = 1; //leave power on - if (HF14BCmdRaw(true, &crc, true, data, datalen, false)==0) return rawClose(); + if (HF14BCmdRaw(true, &crc, true, data, datalen, false) == 0) return switch_off_field_14b(); - if (*datalen != 10 || !crc) return rawClose(); + if (*datalen != 10 || !crc) return switch_off_field_14b(); //power off ? - if (closeCon) rawClose(); + if (closeCon) switch_off_field_14b(); PrintAndLog("\n14443-3b ST tag found:"); print_st_general_info(data); return 1; } -// SRx get and print full info (needs more info...) -int HF14B_ST_Info(uint8_t *data, uint8_t *datalen){ - if (!HF14B_ST_Reader(data, datalen, false)) return 0; - - //add locking bit information here. - if (print_ST_Lock_info(data[5]>>2)) - rawClose(); - return 1; +// SRx get and print full info (needs more info...) +static bool HF14B_ST_Info(bool verbose) { + uint8_t data[100]; + uint8_t datalen; + + if (!HF14B_ST_Reader(data, &datalen, false)) return false; + + //add locking bit information here. + if (print_ST_Lock_info(data[5] >> 2)) + switch_off_field_14b(); + + return true; } + // test for other 14b type tags (mimic another reader - don't have tags to identify) -int HF14B_Other_Reader(uint8_t *data, uint8_t *datalen){ +static bool HF14B_Other_Reader(bool verbose) { + uint8_t data[4]; + uint8_t datalen; + bool crc = true; - *datalen = 4; + datalen = 4; //std read cmd data[0] = 0x00; data[1] = 0x0b; data[2] = 0x3f; data[3] = 0x80; - if (HF14BCmdRaw(true, &crc, true, data, datalen, false)!=0) { - if (*datalen > 2 || !crc) { + if (HF14BCmdRaw(true, &crc, true, data, &datalen, false) != 0) { + if (datalen > 2 || !crc) { PrintAndLog ("\n14443-3b tag found:"); PrintAndLog ("Unknown tag type answered to a 0x000b3f80 command ans:"); - PrintAndLog ("%s",sprint_hex(data,*datalen)); - rawClose(); - return 1; + PrintAndLog ("%s", sprint_hex(data, datalen)); + switch_off_field_14b(); + return true; } } crc = false; - *datalen = 1; + datalen = 1; data[0] = 0x0a; - if (HF14BCmdRaw(true, &crc, true, data, datalen, false)!=0) { - if (*datalen > 0) { + if (HF14BCmdRaw(true, &crc, true, data, &datalen, false) != 0) { + if (datalen > 0) { PrintAndLog ("\n14443-3b tag found:"); PrintAndLog ("Unknown tag type answered to a 0x0A command ans:"); - PrintAndLog ("%s",sprint_hex(data,*datalen)); - rawClose(); - return 1; + PrintAndLog ("%s", sprint_hex(data, datalen)); + switch_off_field_14b(); + return true; } } - + crc = false; - *datalen = 1; + datalen = 1; data[0] = 0x0c; - if (HF14BCmdRaw(true, &crc, true, data, datalen, false)!=0) { - if (*datalen > 0) { + if (HF14BCmdRaw(true, &crc, true, data, &datalen, false) != 0) { + if (datalen > 0) { PrintAndLog ("\n14443-3b tag found:"); PrintAndLog ("Unknown tag type answered to a 0x0C command ans:"); - PrintAndLog ("%s",sprint_hex(data,*datalen)); - rawClose(); - return 1; + PrintAndLog ("%s", sprint_hex(data, datalen)); + switch_off_field_14b(); + return true; } } - rawClose(); + switch_off_field_14b(); + return false; +} + + +// get and print all info known about any known 14b tag +static int usage_hf_14b_info(void) { + PrintAndLogEx(NORMAL, "Usage: hf 14b info [h] [s]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h this help"); + PrintAndLogEx(NORMAL, " s silently"); + PrintAndLogEx(NORMAL, "Example:"); + PrintAndLogEx(NORMAL, " hf 14b info"); return 0; } -// get and print all info known about any known 14b tag -int HF14BInfo(bool verbose){ +int infoHF14B(bool verbose) { uint8_t data[100]; - uint8_t datalen = 5; - + uint8_t datalen; + // try std 14b (atqb) - if (HF14BStdInfo(data, &datalen)) return 1; + if (HF14B_Std_Info(data, &datalen)) return 1; // try st 14b - if (HF14B_ST_Info(data, &datalen)) return 1; + if (HF14B_ST_Info(verbose)) return 1; // try unknown 14b read commands (to be identified later) // could be read of calypso, CEPAS, moneo, or pico pass. - if (HF14B_Other_Reader(data, &datalen)) return 1; + if (HF14B_Other_Reader(verbose)) return 1; if (verbose) PrintAndLog("no 14443B tag found"); return 0; } + // menu command to get and print all info known about any known 14b tag -int CmdHF14Binfo(const char *Cmd){ - return HF14BInfo(true); +static int CmdHF14Binfo(const char *Cmd){ + char cmdp = tolower(param_getchar(Cmd, 0)); + if (cmdp == 'h') return usage_hf_14b_info(); + + bool verbose = !(cmdp == 's'); + return infoHF14B(verbose); } + // get and print general info about all known 14b chips -int HF14BReader(bool verbose){ +int readHF14B(bool verbose){ uint8_t data[100]; uint8_t datalen = 5; - + // try std 14b (atqb) if (HF14BStdReader(data, &datalen)) return 1; @@ -592,33 +619,50 @@ int HF14BReader(bool verbose){ // try unknown 14b read commands (to be identified later) // could be read of calypso, CEPAS, moneo, or pico pass. - if (HF14B_Other_Reader(data, &datalen)) return 1; + if (HF14B_Other_Reader(verbose)) return 1; if (verbose) PrintAndLog("no 14443B tag found"); return 0; } + // menu command to get and print general info about all known 14b chips -int CmdHF14BReader(const char *Cmd){ - return HF14BReader(true); +static int usage_hf_14b_reader(void) { + PrintAndLogEx(NORMAL, "Usage: hf 14b reader [h] [s]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h this help"); + PrintAndLogEx(NORMAL, " s silently"); + PrintAndLogEx(NORMAL, "Example:"); + PrintAndLogEx(NORMAL, " hf 14b reader"); + return 0; } -int CmdSriWrite( const char *Cmd){ + +static int CmdHF14BReader(const char *Cmd) { + char cmdp = tolower(param_getchar(Cmd, 0)); + if (cmdp == 'h') return usage_hf_14b_reader(); + + bool verbose = !(cmdp == 's'); + return readHF14B(verbose); +} + + +int CmdSriWrite(const char *Cmd) { /* * For SRIX4K blocks 00 - 7F * hf 14b raw -c -p 09 $srix4kwblock $srix4kwdata * * For SR512 blocks 00 - 0F * hf 14b raw -c -p 09 $sr512wblock $sr512wdata - * + * * Special block FF = otp_lock_reg block. * Data len 4 bytes- */ - char cmdp = param_getchar(Cmd, 0); + char cmdp = param_getchar(Cmd, 0); uint8_t blockno = -1; uint8_t data[4] = {0x00}; bool isSrix4k = true; - char str[20]; + char str[20]; if (strlen(Cmd) < 1 || cmdp == 'h' || cmdp == 'H') { PrintAndLog("Usage: hf 14b write <1|2> "); @@ -634,43 +678,46 @@ int CmdSriWrite( const char *Cmd){ if ( cmdp == '2' ) isSrix4k = false; - + //blockno = param_get8(Cmd, 1); - - if ( param_gethex(Cmd,1, &blockno, 2) ) { + + if (param_gethex(Cmd,1, &blockno, 2) ) { PrintAndLog("Block number must include 2 HEX symbols"); return 0; } - - if ( isSrix4k ){ - if ( blockno > 0x7f && blockno != 0xff ){ + + if (isSrix4k) { + if (blockno > 0x7f && blockno != 0xff){ PrintAndLog("Block number out of range"); return 0; - } + } } else { - if ( blockno > 0x0f && blockno != 0xff ){ + if (blockno > 0x0f && blockno != 0xff){ PrintAndLog("Block number out of range"); return 0; - } + } } - + if (param_gethex(Cmd, 2, data, 8)) { PrintAndLog("Data must include 8 HEX symbols"); return 0; } - - if ( blockno == 0xff) - PrintAndLog("[%s] Write special block %02X [ %s ]", (isSrix4k)?"SRIX4K":"SRI512" , blockno, sprint_hex(data,4) ); + + if (blockno == 0xff) + PrintAndLog("[%s] Write special block %02X [ %s ]", (isSrix4k)?"SRIX4K":"SRI512", blockno, sprint_hex(data, 4)); else - PrintAndLog("[%s] Write block %02X [ %s ]", (isSrix4k)?"SRIX4K":"SRI512", blockno, sprint_hex(data,4) ); - + PrintAndLog("[%s] Write block %02X [ %s ]", (isSrix4k)?"SRIX4K":"SRI512", blockno, sprint_hex(data, 4)); + sprintf(str, "-c 09 %02x %02x%02x%02x%02x", blockno, data[0], data[1], data[2], data[3]); CmdHF14BCmdRaw(str); return 0; } -static command_t CommandTable[] = + +static int CmdHelp(const char *Cmd); + +static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"info", CmdHF14Binfo, 0, "Find and print details about a 14443B tag"}, diff --git a/client/cmdhf14b.h b/client/cmdhf14b.h index 4fcae927..4897d879 100644 --- a/client/cmdhf14b.h +++ b/client/cmdhf14b.h @@ -21,6 +21,6 @@ int CmdHF14BSnoop(const char *Cmd); int CmdSri512Read(const char *Cmd); int CmdSrix4kRead(const char *Cmd); int CmdHF14BWrite( const char *cmd); -int HF14BInfo(bool verbose); +int infoHF14B(bool verbose); #endif From a3bef9863b9e06a820c7559b9caffeaaa1bb575b Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Wed, 23 Oct 2019 09:09:13 +0200 Subject: [PATCH 143/189] iso14443b: trying to approach iClass * decode and handle SOF only responses in Handle14443bSamplesDemod() * allow 1 byte commands with 'hf 14b raw' --- armsrc/iso14443b.c | 94 ++++++++++++++++++++++++---------------------- client/cmdhf14b.c | 20 ++++++++-- 2 files changed, 66 insertions(+), 48 deletions(-) diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index f276158f..6434409d 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -586,9 +586,10 @@ static RAMFUNC int Handle14443bSamplesDemod(int ci, int cq) Demod.state = DEMOD_UNSYNCD; } else { LED_C_ON(); // Got SOF - Demod.state = DEMOD_AWAITING_START_BIT; Demod.posCount = 0; + Demod.bitCount = 0; Demod.len = 0; + Demod.state = DEMOD_AWAITING_START_BIT; /* this had been used to add RSSI (Received Signal Strength Indication) to traces. Currently not implemented. Demod.metricN = 0; Demod.metric = 0; @@ -605,13 +606,16 @@ static RAMFUNC int Handle14443bSamplesDemod(int ci, int cq) case DEMOD_AWAITING_START_BIT: Demod.posCount++; MAKE_SOFT_DECISION(); - if(v > 0) { - if(Demod.posCount > 3*2) { // max 19us between characters = 16 1/fs, max 3 etu after low phase of SOF = 24 1/fs - Demod.state = DEMOD_UNSYNCD; + if (v > 0) { + if (Demod.posCount > 3*2) { // max 19us between characters = 16 1/fs, max 3 etu after low phase of SOF = 24 1/fs LED_C_OFF(); + if (Demod.bitCount == 0 && Demod.len == 0) { // received SOF only, this is valid for iClass/Picopass + return true; + } else { + Demod.state = DEMOD_UNSYNCD; + } } } else { // start bit detected - Demod.bitCount = 0; Demod.posCount = 1; // this was the first half Demod.thisBit = v; Demod.shiftReg = 0; @@ -621,7 +625,7 @@ static RAMFUNC int Handle14443bSamplesDemod(int ci, int cq) case DEMOD_RECEIVING_DATA: MAKE_SOFT_DECISION(); - if(Demod.posCount == 0) { // first half of bit + if (Demod.posCount == 0) { // first half of bit Demod.thisBit = v; Demod.posCount = 1; } else { // second half of bit @@ -637,22 +641,23 @@ static RAMFUNC int Handle14443bSamplesDemod(int ci, int cq) */ Demod.shiftReg >>= 1; - if(Demod.thisBit > 0) { // logic '1' + if (Demod.thisBit > 0) { // logic '1' Demod.shiftReg |= 0x200; } Demod.bitCount++; - if(Demod.bitCount == 10) { + if (Demod.bitCount == 10) { uint16_t s = Demod.shiftReg; - if((s & 0x200) && !(s & 0x001)) { // stop bit == '1', start bit == '0' + if ((s & 0x200) && !(s & 0x001)) { // stop bit == '1', start bit == '0' uint8_t b = (s >> 1); Demod.output[Demod.len] = b; Demod.len++; + Demod.bitCount = 0; Demod.state = DEMOD_AWAITING_START_BIT; } else { Demod.state = DEMOD_UNSYNCD; LED_C_OFF(); - if(s == 0x000) { + if (s == 0x000) { // This is EOF (start, stop and all data bits == '0' return true; } @@ -693,8 +698,8 @@ static void DemodInit(uint8_t *data) * Demodulate the samples we received from the tag, also log to tracebuffer * quiet: set to 'true' to disable debug output */ -static void GetSamplesFor14443bDemod(int timeout, bool quiet) -{ +static int GetSamplesFor14443bDemod(int timeout, bool quiet) { + int ret = 0; int maxBehindBy = 0; bool gotFrame = false; int lastRxCounter, samples = 0; @@ -750,12 +755,14 @@ static void GetSamplesFor14443bDemod(int timeout, bool quiet) } samples++; - if(Handle14443bSamplesDemod(ci, cq)) { + if (Handle14443bSamplesDemod(ci, cq)) { + ret = Demod.len; gotFrame = true; break; } if(samples > timeout && Demod.state < DEMOD_PHASE_REF_TRAINING) { + ret = -1; LED_C_OFF(); break; } @@ -764,10 +771,14 @@ static void GetSamplesFor14443bDemod(int timeout, bool quiet) FpgaDisableSscDma(); if (!quiet) Dbprintf("max behindby = %d, samples = %d, gotFrame = %d, Demod.len = %d, Demod.sumI = %d, Demod.sumQ = %d", maxBehindBy, samples, gotFrame, Demod.len, Demod.sumI, Demod.sumQ); - //Tracing - if (Demod.len > 0) { - LogTrace(Demod.output, Demod.len, 0, 0, NULL, false); + + if (ret < 0) { + return ret; } + //Tracing + LogTrace(Demod.output, Demod.len, 0, 0, NULL, false); + + return ret; } @@ -858,8 +869,7 @@ static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len) /* Sends an APDU to the tag * TODO: check CRC and preamble */ -int iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *response) -{ +int iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *response) { LED_A_ON(); uint8_t message_frame[message_length + 4]; // PCB @@ -874,21 +884,19 @@ int iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *respo // send CodeAndTransmit14443bAsReader(message_frame, message_length + 4); // get response - GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); + int ret = GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); FpgaDisableTracing(); - if(Demod.len < 3) - { + if (ret < 3) { LED_A_OFF(); return 0; } // TODO: Check CRC // copy response contents - if(response != NULL) - { + if (response != NULL) { memcpy(response, Demod.output, Demod.len); } LED_A_OFF(); - return Demod.len; + return ret; } /* Perform the ISO 14443 B Card Selection procedure @@ -907,10 +915,9 @@ int iso14443b_select_card() // first, wake up the tag CodeAndTransmit14443bAsReader(wupb, sizeof(wupb)); - GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); + int ret = GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); // ATQB too short? - if (Demod.len < 14) - { + if (ret < 14) { return 2; } @@ -922,10 +929,9 @@ int iso14443b_select_card() attrib[7] = Demod.output[10] & 0x0F; ComputeCrc14443(CRC_14443_B, attrib, 9, attrib + 9, attrib + 10); CodeAndTransmit14443bAsReader(attrib, sizeof(attrib)); - GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); + ret = GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); // Answer to ATTRIB too short? - if(Demod.len < 3) - { + if (ret < 3) { return 2; } // reset PCB block number @@ -985,9 +991,9 @@ void ReadSTMemoryIso14443b(uint32_t dwLast) // First command: wake up the tag using the INITIATE command uint8_t cmd1[] = {0x06, 0x00, 0x97, 0x5b}; CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1)); - GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); + int ret = GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); - if (Demod.len == 0) { + if (ret < 0) { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); DbpString("No response from tag"); LEDsoff(); @@ -1003,7 +1009,7 @@ void ReadSTMemoryIso14443b(uint32_t dwLast) cmd1[1] = Demod.output[0]; ComputeCrc14443(CRC_14443_B, cmd1, 2, &cmd1[2], &cmd1[3]); CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1)); - GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); + ret = GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); if (Demod.len != 3) { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); Dbprintf("Expected 3 bytes from tag, got %d", Demod.len); @@ -1031,8 +1037,8 @@ void ReadSTMemoryIso14443b(uint32_t dwLast) cmd1[0] = 0x0B; ComputeCrc14443(CRC_14443_B, cmd1, 1 , &cmd1[1], &cmd1[2]); CodeAndTransmit14443bAsReader(cmd1, 3); // Only first three bytes for this one - GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); - if (Demod.len != 10) { + ret = GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); + if (ret != 10) { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); Dbprintf("Expected 10 bytes from tag, got %d", Demod.len); LEDsoff(); @@ -1062,8 +1068,8 @@ void ReadSTMemoryIso14443b(uint32_t dwLast) cmd1[1] = i; ComputeCrc14443(CRC_14443_B, cmd1, 2, &cmd1[2], &cmd1[3]); CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1)); - GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); - if (Demod.len != 6) { // Check if we got an answer from the tag + ret = GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); + if (ret != 6) { // Check if we got an answer from the tag FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); DbpString("Expected 6 bytes from tag, got less..."); LEDsoff(); @@ -1071,7 +1077,7 @@ void ReadSTMemoryIso14443b(uint32_t dwLast) } // The check the CRC of the answer (use cmd1 as temporary variable): ComputeCrc14443(CRC_14443_B, Demod.output, 4, &cmd1[2], &cmd1[3]); - if(cmd1[2] != Demod.output[4] || cmd1[3] != Demod.output[5]) { + if (cmd1[2] != Demod.output[4] || cmd1[3] != Demod.output[5]) { Dbprintf("CRC Error reading block! Expected: %04x got: %04x", (cmd1[2]<<8)+cmd1[3], (Demod.output[4]<<8)+Demod.output[5]); // Do not return;, let's go on... (we should retry, maybe ?) @@ -1213,8 +1219,8 @@ void RAMFUNC SnoopIso14443b(void) ReaderIsActive = (Uart.state > STATE_GOT_FALLING_EDGE_OF_SOF); } - if(!ReaderIsActive && triggered) { // no need to try decoding tag data if the reader is sending or not yet triggered - if(Handle14443bSamplesDemod(ci/2, cq/2)) { + if (!ReaderIsActive && triggered) { // no need to try decoding tag data if the reader is sending or not yet triggered + if (Handle14443bSamplesDemod(ci/2, cq/2) >= 0) { //Use samples as a time measurement LogTrace(Demod.output, Demod.len, samples, samples, NULL, false); // And ready to receive another response. @@ -1265,17 +1271,17 @@ void SendRawCommand14443B(uint32_t datalen, uint32_t recv, uint8_t powerfield, u CodeAndTransmit14443bAsReader(data, datalen); - if(recv) { - GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); + if (recv) { + int ret = GetSamplesFor14443bDemod(5*RECEIVE_SAMPLES_TIMEOUT, true); FpgaDisableTracing(); uint16_t iLen = MIN(Demod.len, USB_CMD_DATA_SIZE); - cmd_send(CMD_ACK, iLen, 0, 0, Demod.output, iLen); + cmd_send(CMD_ACK, ret, 0, 0, Demod.output, iLen); } FpgaDisableTracing(); } - if(!powerfield) { + if (!powerfield) { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_D_OFF(); } diff --git a/client/cmdhf14b.c b/client/cmdhf14b.c index 8a83df8f..4685f3f5 100644 --- a/client/cmdhf14b.c +++ b/client/cmdhf14b.c @@ -108,9 +108,21 @@ int HF14BCmdRaw(bool reply, bool *crc, bool power, uint8_t *data, uint8_t *datal if (verbose) PrintAndLog("timeout while waiting for reply."); return 0; } - *datalen = resp.arg[0]; - if (verbose) PrintAndLog("received %u octets", *datalen); - if (*datalen < 2) return 0; + + int ret = resp.arg[0]; + if (verbose) { + if (ret < 0) { + PrintAndLog("tag didn't respond"); + } else if (ret == 0) { + PrintAndLog("received SOF only (maybe iCLASS/Picopass)"); + } else { + PrintAndLog("received %u octets", ret); + } + } + + *datalen = ret; + + if (ret < 2) return 0; memcpy(data, resp.d.asBytes, *datalen); if (verbose) PrintAndLog("%s", sprint_hex(data, *datalen)); @@ -139,7 +151,7 @@ static int CmdHF14BCmdRaw (const char *Cmd) { uint8_t datalen = 0; unsigned int temp; int i = 0; - if (strlen(Cmd) < 3) { + if (strlen(Cmd) < 2) { PrintAndLog("Usage: hf 14b raw [-r] [-c] [-p] [-s || -ss] <0A 0B 0C ... hex>"); PrintAndLog(" -r do not read response"); PrintAndLog(" -c calculate and append CRC"); From ece38ef311b28eefb1d716937139aad9ee00985c Mon Sep 17 00:00:00 2001 From: pwpiwi Date: Sun, 27 Oct 2019 16:51:27 +0100 Subject: [PATCH 144/189] fix 'hf iclass reader' and 'hf iclass readblk' * don't do READCHECK when not trying to authenticate * standard LED handling * remove unused FLAG_ICLASS_READER_ONLY_ONCE and FLAG_ICLASS_READER_ONE_TRY * sanity check for negative times in TransmitTo15693Tag() * increase reader timeout for 'hf 15' functions to be enough for slot 7 answers to ACTALL * add 'hf iclass permute' inspired by RRG repository * whitespace fixes --- armsrc/appmain.c | 7 +- armsrc/iclass.c | 277 ++++++------ armsrc/iclass.h | 4 +- armsrc/iso15693.c | 112 +++-- armsrc/iso15693.h | 2 + client/cmdhficlass.c | 821 ++++++++++++++++++++--------------- client/cmdhficlass.h | 24 +- client/loclass/elite_crack.h | 2 +- include/usb_cmd.h | 7 +- 9 files changed, 674 insertions(+), 582 deletions(-) diff --git a/armsrc/appmain.c b/armsrc/appmain.c index e3bd1fe0..56da5434 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1327,8 +1327,11 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_ICLASS_READBLOCK: iClass_ReadBlk(c->arg[0]); break; - case CMD_ICLASS_AUTHENTICATION: //check - iClass_Authentication(c->d.asBytes); + case CMD_ICLASS_CHECK: + iClass_Check(c->d.asBytes); + break; + case CMD_ICLASS_READCHECK: + iClass_Readcheck(c->arg[0], c->arg[1]); break; case CMD_ICLASS_DUMP: iClass_Dump(c->arg[0], c->arg[1]); diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 392271bd..1a729f3f 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -63,9 +63,9 @@ // 56,64us = 24 ssp_clk_cycles #define DELAY_ICLASS_VCD_TO_VICC_SIM (140 - 24) // times in ssp_clk_cycles @ 3,3625MHz when acting as reader -#define DELAY_ICLASS_VICC_TO_VCD_READER DELAY_ISO15693_VICC_TO_VCD_READER +#define DELAY_ICLASS_VICC_TO_VCD_READER DELAY_ISO15693_VICC_TO_VCD_READER // times in samples @ 212kHz when acting as reader -#define ICLASS_READER_TIMEOUT_ACTALL 330 // 1558us, nominal 330us + 7slots*160us = 1450us +#define ICLASS_READER_TIMEOUT_ACTALL 330 // 1558us, nominal 330us + 7slots*160us = 1450us #define ICLASS_READER_TIMEOUT_OTHERS 80 // 380us, nominal 330us @@ -695,7 +695,6 @@ void RAMFUNC SnoopIClass(void) { if (OutOfNDecoding((smpl & 0xF0) >> 4)) { rsamples = samples - Uart.samples; time_stop = (GetCountSspClk()-time_0) << 4; - LED_C_ON(); //if (!LogTrace(Uart.output, Uart.byteCnt, rsamples, Uart.parityBits,true)) break; //if (!LogTrace(NULL, 0, Uart.endTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, 0, true)) break; @@ -708,7 +707,6 @@ void RAMFUNC SnoopIClass(void) { /* And also reset the demod code, which might have been */ /* false-triggered by the commands from the reader. */ Demod.state = DEMOD_UNSYNCD; - LED_B_OFF(); Uart.byteCnt = 0; } else { time_start = (GetCountSspClk()-time_0) << 4; @@ -722,7 +720,6 @@ void RAMFUNC SnoopIClass(void) { time_stop = (GetCountSspClk()-time_0) << 4; rsamples = samples - Demod.samples; - LED_B_ON(); uint8_t parity[MAX_PARITY_SIZE]; GetParity(Demod.output, Demod.len, parity); @@ -732,7 +729,6 @@ void RAMFUNC SnoopIClass(void) { memset(&Demod, 0, sizeof(Demod)); Demod.output = tagToReaderResponse; Demod.state = DEMOD_UNSYNCD; - LED_C_OFF(); } else { time_start = (GetCountSspClk()-time_0) << 4; } @@ -1341,7 +1337,7 @@ static void ReaderTransmitIClass(uint8_t *frame, int len, uint32_t *start_time) } -static bool sendCmdGetResponseWithRetries(uint8_t* command, size_t cmdsize, uint8_t* resp, size_t max_resp_size, +static bool sendCmdGetResponseWithRetries(uint8_t* command, size_t cmdsize, uint8_t* resp, size_t max_resp_size, uint8_t expected_size, uint8_t retries, uint32_t start_time, uint32_t *eof_time) { while (retries-- > 0) { ReaderTransmitIClass(command, cmdsize, &start_time); @@ -1353,39 +1349,31 @@ static bool sendCmdGetResponseWithRetries(uint8_t* command, size_t cmdsize, uint } /** - * @brief Talks to an iclass tag, sends the commands to get CSN and CC. - * @param card_data where the CSN and CC are stored for return - * @return 0 = fail - * 1 = Got CSN - * 2 = Got CSN and CC + * @brief Selects an iclass tag + * @param card_data where the CSN is stored for return + * @return false = fail + * true = success */ -static uint8_t handshakeIclassTag_ext(uint8_t *card_data, bool use_credit_key, uint32_t *eof_time) { +static bool selectIclassTag(uint8_t *card_data, uint32_t *eof_time) { uint8_t act_all[] = { 0x0a }; uint8_t identify[] = { 0x0c }; uint8_t select[] = { 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - uint8_t readcheck_cc[] = { 0x88, 0x02 }; - if (use_credit_key) - readcheck_cc[0] = 0x18; - else - readcheck_cc[0] = 0x88; uint8_t resp[ICLASS_BUFFER_SIZE]; - uint8_t read_status = 0; uint32_t start_time = GetCountSspClk(); // Send act_all ReaderTransmitIClass(act_all, 1, &start_time); // Card present? - if (GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_ACTALL, eof_time) < 0) return read_status;//Fail - + if (GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_ACTALL, eof_time) < 0) return false;//Fail + //Send Identify start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; ReaderTransmitIClass(identify, 1, &start_time); - // FpgaDisableTracing(); // DEBUGGING //We expect a 10-byte response here, 8 byte anticollision-CSN and 2 byte CRC uint8_t len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); - if (len != 10) return read_status;//Fail + if (len != 10) return false;//Fail //Copy the Anti-collision CSN to our select-packet memcpy(&select[1], resp, 8); @@ -1394,54 +1382,33 @@ static uint8_t handshakeIclassTag_ext(uint8_t *card_data, bool use_credit_key, u ReaderTransmitIClass(select, sizeof(select), &start_time); //We expect a 10-byte response here, 8 byte CSN and 2 byte CRC len = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time); - if (len != 10) return read_status;//Fail + if (len != 10) return false;//Fail - //Success - level 1, we got CSN + //Success - we got CSN //Save CSN in response data memcpy(card_data, resp, 8); - //Flag that we got to at least stage 1, read CSN - read_status = 1; - - // Card selected, now read e-purse (cc) (only 8 bytes no CRC) - start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc), &start_time); - if (GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time) == 8) { - //Save CC (e-purse) in response data - memcpy(card_data+8, resp, 8); - read_status++; - } - - return read_status; -} - -static uint8_t handshakeIclassTag(uint8_t *card_data, uint32_t *eof_time) { - return handshakeIclassTag_ext(card_data, false, eof_time); + return true; } -// Reader iClass Anticollission +// Select an iClass tag and read all blocks which are always readable without authentication void ReaderIClass(uint8_t arg0) { + LED_A_ON(); + uint8_t card_data[6 * 8] = {0}; memset(card_data, 0xFF, sizeof(card_data)); - uint8_t last_csn[8] = {0,0,0,0,0,0,0,0}; uint8_t resp[ICLASS_BUFFER_SIZE]; - memset(resp, 0xFF, sizeof(resp)); //Read conf block CRC(0x01) => 0xfa 0x22 - uint8_t readConf[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x01, 0xfa, 0x22}; + uint8_t readConf[] = {ICLASS_CMD_READ_OR_IDENTIFY, 0x01, 0xfa, 0x22}; + //Read e-purse block CRC(0x02) => 0x61 0x10 + uint8_t readEpurse[] = {ICLASS_CMD_READ_OR_IDENTIFY, 0x02, 0x61, 0x10}; //Read App Issuer Area block CRC(0x05) => 0xde 0x64 - uint8_t readAA[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x05, 0xde, 0x64}; + uint8_t readAA[] = {ICLASS_CMD_READ_OR_IDENTIFY, 0x05, 0xde, 0x64}; - int read_status= 0; uint8_t result_status = 0; - // flag to read until one tag is found successfully - bool abort_after_read = arg0 & FLAG_ICLASS_READER_ONLY_ONCE; - // flag to only try 5 times to find one tag then return - bool try_once = arg0 & FLAG_ICLASS_READER_ONE_TRY; - // if neither abort_after_read nor try_once then continue reading until button pressed. - bool use_credit_key = arg0 & FLAG_ICLASS_READER_CEDITKEY; // test flags for what blocks to be sure to read uint8_t flagReadConfig = arg0 & FLAG_ICLASS_READER_CONF; uint8_t flagReadCC = arg0 & FLAG_ICLASS_READER_CC; @@ -1454,93 +1421,57 @@ void ReaderIClass(uint8_t arg0) { StartCountSspClk(); uint32_t start_time = 0; uint32_t eof_time = 0; + + if (selectIclassTag(resp, &eof_time)) { + result_status = FLAG_ICLASS_READER_CSN; + memcpy(card_data, resp, 8); + } - uint16_t tryCnt = 0; - bool userCancelled = BUTTON_PRESS() || usb_poll_validate_length(); - while (!userCancelled) { - // if only looking for one card try 2 times if we missed it the first time - if (try_once && tryCnt > 2) { - break; + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + + //Read block 1, config + if (flagReadConfig) { + if (sendCmdGetResponseWithRetries(readConf, sizeof(readConf), resp, sizeof(resp), 10, 10, start_time, &eof_time)) { + result_status |= FLAG_ICLASS_READER_CONF; + memcpy(card_data+8, resp, 8); + } else { + Dbprintf("Failed to read config block"); } - tryCnt++; - if (!get_tracing()) { - DbpString("Trace full"); - break; - } - WDT_HIT(); - - read_status = handshakeIclassTag_ext(card_data, use_credit_key, &eof_time); - - if (read_status == 0) continue; - if (read_status == 1) result_status = FLAG_ICLASS_READER_CSN; - if (read_status == 2) result_status = FLAG_ICLASS_READER_CSN | FLAG_ICLASS_READER_CC; - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - // handshakeIclass returns CSN|CC, but the actual block - // layout is CSN|CONFIG|CC, so here we reorder the data, - // moving CC forward 8 bytes - memcpy(card_data+16, card_data+8, 8); - //Read block 1, config - if (flagReadConfig) { - if (sendCmdGetResponseWithRetries(readConf, sizeof(readConf), resp, sizeof(resp), 10, 10, start_time, &eof_time)) { - result_status |= FLAG_ICLASS_READER_CONF; - memcpy(card_data+8, resp, 8); - } else { - Dbprintf("Failed to dump config block"); - } - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - } - - //Read block 5, AA - if (flagReadAA) { - if (sendCmdGetResponseWithRetries(readAA, sizeof(readAA), resp, sizeof(resp), 10, 10, start_time, &eof_time)) { - result_status |= FLAG_ICLASS_READER_AA; - memcpy(card_data + (8*5), resp, 8); - } else { - //Dbprintf("Failed to dump AA block"); - } - } - - // 0 : CSN - // 1 : Configuration - // 2 : e-purse - // 3 : kd / debit / aa2 (write-only) - // 4 : kc / credit / aa1 (write-only) - // 5 : AIA, Application issuer area - //Then we can 'ship' back the 6 * 8 bytes of data, - // with 0xFF:s in block 3 and 4. - - LED_B_ON(); - //Send back to client, but don't bother if we already sent this - - // only useful if looping in arm (not try_once && not abort_after_read) - if (memcmp(last_csn, card_data, 8) != 0) { - // If caller requires that we get Conf, CC, AA, continue until we got it - if ( (result_status ^ FLAG_ICLASS_READER_CSN ^ flagReadConfig ^ flagReadCC ^ flagReadAA) == 0) { - cmd_send(CMD_ACK, result_status, 0, 0, card_data, sizeof(card_data)); - if (abort_after_read) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LED_A_OFF(); - LED_B_OFF(); - return; - } - //Save that we already sent this.... - memcpy(last_csn, card_data, 8); - } - - } - LED_B_OFF(); - userCancelled = BUTTON_PRESS() || usb_poll_validate_length(); } - if (userCancelled) { - cmd_send(CMD_ACK, 0xFF, 0, 0, card_data, 0); - } else { - cmd_send(CMD_ACK, 0, 0, 0, card_data, 0); + + //Read block 2, e-purse + if (flagReadCC) { + if (sendCmdGetResponseWithRetries(readEpurse, sizeof(readEpurse), resp, sizeof(resp), 10, 10, start_time, &eof_time)) { + result_status |= FLAG_ICLASS_READER_CC; + memcpy(card_data + (8*2), resp, 8); + } else { + Dbprintf("Failed to read e-purse"); + } + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; } + + //Read block 5, AA + if (flagReadAA) { + if (sendCmdGetResponseWithRetries(readAA, sizeof(readAA), resp, sizeof(resp), 10, 10, start_time, &eof_time)) { + result_status |= FLAG_ICLASS_READER_AA; + memcpy(card_data + (8*5), resp, 8); + } else { + Dbprintf("Failed to read AA block"); + } + } + + cmd_send(CMD_ACK, result_status, 0, 0, card_data, sizeof(card_data)); + LED_A_OFF(); } + void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { + LED_A_ON(); + + bool use_credit_key = false; uint8_t card_data[USB_CMD_DATA_SIZE]={0}; uint16_t block_crc_LUT[255] = {0}; @@ -1551,6 +1482,9 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { } //Dbprintf("Lookup table: %02x %02x %02x" ,block_crc_LUT[0],block_crc_LUT[1],block_crc_LUT[2]); + uint8_t readcheck_cc[] = { ICLASS_CMD_READCHECK_KD, 0x02 }; + if (use_credit_key) + readcheck_cc[0] = ICLASS_CMD_READCHECK_KC; uint8_t check[] = { 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t read[] = { 0x0c, 0x00, 0x00, 0x00 }; @@ -1575,7 +1509,7 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { StartCountSspClk(); uint32_t start_time = 0; uint32_t eof_time = 0; - + while (!BUTTON_PRESS()) { WDT_HIT(); @@ -1585,34 +1519,33 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { break; } - uint8_t read_status = handshakeIclassTag(card_data, &eof_time); + if (!selectIclassTag(card_data, &eof_time)) continue; + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + if (!sendCmdGetResponseWithRetries(readcheck_cc, sizeof(readcheck_cc), resp, sizeof(resp), 8, 3, start_time, &eof_time)) continue; - if (read_status < 2) continue; - - //for now replay captured auth (as cc not updated) + // replay captured auth (cc must not have been updated) memcpy(check+5, MAC, 4); + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; if (!sendCmdGetResponseWithRetries(check, sizeof(check), resp, sizeof(resp), 4, 5, start_time, &eof_time)) { - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; Dbprintf("Error: Authentication Fail!"); continue; } - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; //first get configuration block (block 1) crc = block_crc_LUT[1]; read[1] = 1; read[2] = crc >> 8; read[3] = crc & 0xff; + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; if (!sendCmdGetResponseWithRetries(read, sizeof(read), resp, sizeof(resp), 10, 10, start_time, &eof_time)) { start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; Dbprintf("Dump config (block 1) failed"); continue; } - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; mem = resp[5]; memory.k16 = (mem & 0x80); memory.book = (mem & 0x20); @@ -1633,8 +1566,8 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { read[2] = crc >> 8; read[3] = crc & 0xff; + start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; if (sendCmdGetResponseWithRetries(read, sizeof(read), resp, sizeof(resp), 10, 10, start_time, &eof_time)) { - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; Dbprintf(" %02x: %02x %02x %02x %02x %02x %02x %02x %02x", block, resp[0], resp[1], resp[2], resp[3], resp[4], resp[5], @@ -1683,19 +1616,33 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) { 0); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); LED_A_OFF(); } -void iClass_Authentication(uint8_t *MAC) { - uint8_t check[] = { ICLASS_CMD_CHECK_KD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - uint8_t resp[ICLASS_BUFFER_SIZE]; + +void iClass_Check(uint8_t *MAC) { + uint8_t check[9] = {ICLASS_CMD_CHECK_KD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t resp[4]; memcpy(check+5, MAC, 4); - bool isOK; uint32_t eof_time; - isOK = sendCmdGetResponseWithRetries(check, sizeof(check), resp, sizeof(resp), 4, 6, 0, &eof_time); - cmd_send(CMD_ACK,isOK, 0, 0, 0, 0); + bool isOK = sendCmdGetResponseWithRetries(check, sizeof(check), resp, sizeof(resp), 4, 6, 0, &eof_time); + cmd_send(CMD_ACK, isOK, 0, 0, resp, sizeof(resp)); } + +void iClass_Readcheck(uint8_t block, bool use_credit_key) { + uint8_t readcheck[2] = {ICLASS_CMD_READCHECK_KD, block}; + if (use_credit_key) { + readcheck[0] = ICLASS_CMD_READCHECK_KC; + } + uint8_t resp[8]; + uint32_t eof_time; + bool isOK = sendCmdGetResponseWithRetries(readcheck, sizeof(readcheck), resp, sizeof(resp), 8, 6, 0, &eof_time); + cmd_send(CMD_ACK, isOK, 0, 0, resp, sizeof(resp)); +} + + static bool iClass_ReadBlock(uint8_t blockNo, uint8_t *readdata) { uint8_t readcmd[] = {ICLASS_CMD_READ_OR_IDENTIFY, blockNo, 0x00, 0x00}; //0x88, 0x00 // can i use 0C? char bl = blockNo; @@ -1705,23 +1652,32 @@ static bool iClass_ReadBlock(uint8_t blockNo, uint8_t *readdata) { uint8_t resp[10]; bool isOK = false; uint32_t eof_time; - - //readcmd[1] = blockNo; + isOK = sendCmdGetResponseWithRetries(readcmd, sizeof(readcmd), resp, sizeof(resp), 10, 10, 0, &eof_time); memcpy(readdata, resp, sizeof(resp)); return isOK; } + void iClass_ReadBlk(uint8_t blockno) { + + LED_A_ON(); + uint8_t readblockdata[] = {0,0,0,0,0,0,0,0,0,0}; bool isOK = false; isOK = iClass_ReadBlock(blockno, readblockdata); cmd_send(CMD_ACK, isOK, 0, 0, readblockdata, 8); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); + + LED_A_OFF(); } void iClass_Dump(uint8_t blockno, uint8_t numblks) { + + LED_A_ON(); + uint8_t readblockdata[] = {0,0,0,0,0,0,0,0,0,0}; bool isOK = false; uint8_t blkCnt = 0; @@ -1751,12 +1707,19 @@ void iClass_Dump(uint8_t blockno, uint8_t numblks) { } //return pointer to dump memory in arg3 cmd_send(CMD_ACK, isOK, blkCnt, BigBuf_max_traceLen(), 0, 0); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); + LED_D_OFF(); BigBuf_free(); + + LED_A_OFF(); } + static bool iClass_WriteBlock_ext(uint8_t blockNo, uint8_t *data) { + + LED_A_ON(); + uint8_t write[] = { ICLASS_CMD_UPDATE, blockNo, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; //uint8_t readblockdata[10]; //write[1] = blockNo; @@ -1768,7 +1731,7 @@ static bool iClass_WriteBlock_ext(uint8_t blockNo, uint8_t *data) { uint8_t resp[10]; bool isOK = false; uint32_t eof_time = 0; - + isOK = sendCmdGetResponseWithRetries(write, sizeof(write), resp, sizeof(resp), 10, 10, 0, &eof_time); uint32_t start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; if (isOK) { //if reader responded correctly @@ -1780,10 +1743,17 @@ static bool iClass_WriteBlock_ext(uint8_t blockNo, uint8_t *data) { } } } + + LED_A_OFF(); + return isOK; } + void iClass_WriteBlock(uint8_t blockNo, uint8_t *data) { + + LED_A_ON(); + bool isOK = iClass_WriteBlock_ext(blockNo, data); if (isOK){ Dbprintf("Write block [%02x] successful", blockNo); @@ -1791,7 +1761,11 @@ void iClass_WriteBlock(uint8_t blockNo, uint8_t *data) { Dbprintf("Write block [%02x] failed", blockNo); } cmd_send(CMD_ACK, isOK, 0, 0, 0, 0); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); + + LED_A_OFF(); } void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data) { @@ -1819,5 +1793,6 @@ void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data) { cmd_send(CMD_ACK, 1, 0, 0, 0, 0); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); + LED_D_OFF(); + LED_A_OFF(); } diff --git a/armsrc/iclass.h b/armsrc/iclass.h index 3cbe79fb..9666e888 100644 --- a/armsrc/iclass.h +++ b/armsrc/iclass.h @@ -15,6 +15,7 @@ #define ICLASS_H__ #include +#include #include "common.h" // for RAMFUNC extern void RAMFUNC SnoopIClass(void); @@ -22,7 +23,8 @@ extern void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t extern void ReaderIClass(uint8_t arg0); extern void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC); extern void IClass_iso14443A_GetPublic(uint8_t arg0); -extern void iClass_Authentication(uint8_t *MAC); +extern void iClass_Readcheck(uint8_t block, bool use_credit_key); +extern void iClass_Check(uint8_t *MAC); extern void iClass_WriteBlock(uint8_t blockNo, uint8_t *data); extern void iClass_ReadBlk(uint8_t blockNo); extern void iClass_Dump(uint8_t blockno, uint8_t numblks); diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index fff8b370..3b39d576 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -132,7 +132,7 @@ void CodeIso15693AsReader(uint8_t *cmd, int n) { // EOF ToSend[++ToSendMax] = 0x20; //0010 + 0000 padding - + ToSendMax++; } @@ -249,14 +249,18 @@ void CodeIso15693AsTag(uint8_t *cmd, size_t len) { void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time) { FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_FULL_MOD); - + + if (*start_time < DELAY_ARM_TO_TAG) { + *start_time = DELAY_ARM_TO_TAG; + } + *start_time = (*start_time - DELAY_ARM_TO_TAG) & 0xfffffff0; while (GetCountSspClk() > *start_time) { // we may miss the intended time *start_time += 16; // next possible time } - + while (GetCountSspClk() < *start_time) /* wait */ ; @@ -275,7 +279,7 @@ void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time) { WDT_HIT(); } LED_B_OFF(); - + *start_time = *start_time + DELAY_ARM_TO_TAG; } @@ -289,7 +293,7 @@ void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_424K); uint32_t modulation_start_time = *start_time - DELAY_ARM_TO_READER + 3 * 8; // no need to transfer the unmodulated start of SOF - + while (GetCountSspClk() > (modulation_start_time & 0xfffffff8) + 3) { // we will miss the intended time if (slot_time) { modulation_start_time += slot_time; // use next available slot @@ -298,7 +302,7 @@ void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, } } - while (GetCountSspClk() < (modulation_start_time & 0xfffffff8)) + while (GetCountSspClk() < (modulation_start_time & 0xfffffff8)) /* wait */ ; uint8_t shift_delay = modulation_start_time & 0x00000007; @@ -414,7 +418,7 @@ static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint1 // DecodeTag->posCount = 2; DecodeTag->state = STATE_TAG_SOF_HIGH; break; - + case STATE_TAG_SOF_HIGH: // waiting for 10 times high. Take average over the last 8 if (amplitude > DecodeTag->threshold_sof) { @@ -428,7 +432,7 @@ static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint1 } } else { // high phase was too short DecodeTag->posCount = 1; - DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; + DecodeTag->previous_amplitude = amplitude; DecodeTag->state = STATE_TAG_SOF_LOW; } break; @@ -444,18 +448,18 @@ static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint1 DecodeTag->sum2 = 0; DecodeTag->posCount = 2; DecodeTag->state = STATE_TAG_RECEIVING_DATA; - // FpgaDisableTracing(); // DEBUGGING - // Dbprintf("amplitude = %d, threshold_sof = %d, threshold_half/4 = %d, previous_amplitude = %d", - // amplitude, - // DecodeTag->threshold_sof, - // DecodeTag->threshold_half/4, - // DecodeTag->previous_amplitude); // DEBUGGING + FpgaDisableTracing(); // DEBUGGING + Dbprintf("amplitude = %d, threshold_sof = %d, threshold_half/4 = %d, previous_amplitude = %d", + amplitude, + DecodeTag->threshold_sof, + DecodeTag->threshold_half/4, + DecodeTag->previous_amplitude); // DEBUGGING LED_C_ON(); } else { DecodeTag->posCount++; if (DecodeTag->posCount > 13) { // high phase too long DecodeTag->posCount = 0; - DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; + DecodeTag->previous_amplitude = amplitude; DecodeTag->state = STATE_TAG_SOF_LOW; LED_C_OFF(); } @@ -478,7 +482,7 @@ static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint1 DecodeTag->state = STATE_TAG_EOF; } else { DecodeTag->posCount = 0; - DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; + DecodeTag->previous_amplitude = amplitude; DecodeTag->state = STATE_TAG_SOF_LOW; LED_C_OFF(); } @@ -508,7 +512,7 @@ static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint1 // logic 0 if (DecodeTag->lastBit == SOF_PART1) { // incomplete SOF DecodeTag->posCount = 0; - DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; + DecodeTag->previous_amplitude = amplitude; DecodeTag->state = STATE_TAG_SOF_LOW; LED_C_OFF(); } else { @@ -522,7 +526,7 @@ static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint1 if (DecodeTag->len > DecodeTag->max_len) { // buffer overflow, give up DecodeTag->posCount = 0; - DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; + DecodeTag->previous_amplitude = amplitude; DecodeTag->state = STATE_TAG_SOF_LOW; LED_C_OFF(); } @@ -561,7 +565,7 @@ static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint1 DecodeTag->state = STATE_TAG_EOF_TAIL; } else { DecodeTag->posCount = 0; - DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; + DecodeTag->previous_amplitude = amplitude; DecodeTag->state = STATE_TAG_SOF_LOW; LED_C_OFF(); } @@ -585,7 +589,7 @@ static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint1 return true; } else { DecodeTag->posCount = 0; - DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; + DecodeTag->previous_amplitude = amplitude; DecodeTag->state = STATE_TAG_SOF_LOW; LED_C_OFF(); } @@ -598,8 +602,7 @@ static int inline __attribute__((always_inline)) Handle15693SamplesFromTag(uint1 } -static void DecodeTagInit(DecodeTag_t *DecodeTag, uint8_t *data, uint16_t max_len) -{ +static void DecodeTagInit(DecodeTag_t *DecodeTag, uint8_t *data, uint16_t max_len) { DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; DecodeTag->posCount = 0; DecodeTag->state = STATE_TAG_SOF_LOW; @@ -608,8 +611,7 @@ static void DecodeTagInit(DecodeTag_t *DecodeTag, uint8_t *data, uint16_t max_le } -static void DecodeTagReset(DecodeTag_t *DecodeTag) -{ +static void DecodeTagReset(DecodeTag_t *DecodeTag) { DecodeTag->posCount = 0; DecodeTag->state = STATE_TAG_SOF_LOW; DecodeTag->previous_amplitude = MAX_PREVIOUS_AMPLITUDE; @@ -649,10 +651,10 @@ int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeo samples++; if (samples == 1) { - // DMA has transferred the very first data + // DMA has transferred the very first data dma_start_time = GetCountSspClk() & 0xfffffff0; } - + uint16_t tagdata = *upTo++; if(upTo >= dmaBuf + ISO15693_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content. @@ -680,7 +682,7 @@ int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeo } if (samples > timeout && DecodeTag.state < STATE_TAG_RECEIVING_DATA) { - ret = -1; // timeout + ret = -1; // timeout break; } @@ -699,9 +701,9 @@ int GetIso15693AnswerFromTag(uint8_t* response, uint16_t max_len, uint16_t timeo - DecodeTag.len * 8 * 8 * 16 // time for byte transfers - 32 * 16 // time for SOF transfer - (DecodeTag.lastBit != SOF_PART2?32*16:0); // time for EOF transfer - + if (DEBUG) Dbprintf("timing: sof_time = %d, eof_time = %d", sof_time, *eof_time); - + LogTrace_ISO15693(DecodeTag.output, DecodeTag.len, sof_time*4, *eof_time*4, NULL, false); return DecodeTag.len; @@ -1089,20 +1091,19 @@ static void BuildIdentifyRequest(void) //----------------------------------------------------------------------------- void AcquireRawAdcSamplesIso15693(void) { - LEDsoff(); LED_A_ON(); uint8_t *dest = BigBuf_get_addr(); FpgaDownloadAndGo(FPGA_BITSTREAM_HF); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER); + LED_D_ON(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); BuildIdentifyRequest(); // Give the tags time to energize - LED_D_ON(); SpinDelay(100); // Now send the command @@ -1129,6 +1130,7 @@ void AcquireRawAdcSamplesIso15693(void) void SnoopIso15693(void) { LED_A_ON(); + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); BigBuf_free(); @@ -1348,17 +1350,13 @@ static void BuildInventoryResponse(uint8_t *uid) // return: length of received data, or -1 for timeout int SendDataTag(uint8_t *send, int sendlen, bool init, int speed, uint8_t *recv, uint16_t max_recv_len, uint32_t start_time, uint32_t *eof_time) { - LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); - if (init) { Iso15693InitReader(); StartCountSspClk(); } - + int answerLen = 0; - + if (!speed) { // low speed (1 out of 256) CodeIso15693AsReader256(send, sendlen); @@ -1367,18 +1365,13 @@ int SendDataTag(uint8_t *send, int sendlen, bool init, int speed, uint8_t *recv, CodeIso15693AsReader(send, sendlen); } - if (start_time == 0) { - start_time = GetCountSspClk(); - } TransmitTo15693Tag(ToSend, ToSendMax, &start_time); // Now wait for a response if (recv != NULL) { - answerLen = GetIso15693AnswerFromTag(recv, max_recv_len, DELAY_ISO15693_VCD_TO_VICC_READER * 2, eof_time); + answerLen = GetIso15693AnswerFromTag(recv, max_recv_len, ISO15693_READER_TIMEOUT, eof_time); } - LED_A_OFF(); - return answerLen; } @@ -1462,9 +1455,8 @@ void SetDebugIso15693(uint32_t debug) { // Simulate an ISO15693 reader, perform anti-collision and then attempt to read a sector. // all demodulation performed in arm rather than host. - greg //--------------------------------------------------------------------------------------- -void ReaderIso15693(uint32_t parameter) -{ - LEDsoff(); +void ReaderIso15693(uint32_t parameter) { + LED_A_ON(); set_tracing(true); @@ -1564,9 +1556,8 @@ void ReaderIso15693(uint32_t parameter) // Simulate an ISO15693 TAG. // For Inventory command: print command and send Inventory Response with given UID // TODO: interpret other reader commands and send appropriate response -void SimTagIso15693(uint32_t parameter, uint8_t *uid) -{ - LEDsoff(); +void SimTagIso15693(uint32_t parameter, uint8_t *uid) { + LED_A_ON(); FpgaDownloadAndGo(FPGA_BITSTREAM_HF); @@ -1597,7 +1588,8 @@ void SimTagIso15693(uint32_t parameter, uint8_t *uid) } FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); + LED_D_OFF(); + LED_A_OFF(); } @@ -1605,7 +1597,6 @@ void SimTagIso15693(uint32_t parameter, uint8_t *uid) // (some manufactures offer a way to read the AFI, though) void BruteforceIso15693Afi(uint32_t speed) { - LEDsoff(); LED_A_ON(); uint8_t data[6]; @@ -1648,17 +1639,19 @@ void BruteforceIso15693Afi(uint32_t speed) Dbprintf("AFI Bruteforcing done."); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); + LED_D_OFF(); + LED_A_OFF(); + } // Allows to directly send commands to the tag via the client void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint8_t data[]) { + LED_A_ON(); + int recvlen = 0; uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; uint32_t eof_time; - - LED_A_ON(); if (DEBUG) { Dbprintf("SEND:"); @@ -1695,17 +1688,16 @@ void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint //----------------------------------------------------------------------------- // Set the UID to the tag (based on Iceman work). -void SetTag15693Uid(uint8_t *uid) -{ - uint8_t cmd[4][9] = {0x00}; +void SetTag15693Uid(uint8_t *uid) { + LED_A_ON(); + + uint8_t cmd[4][9] = {0x00}; uint16_t crc; int recvlen = 0; uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; uint32_t eof_time; - - LED_A_ON(); // Command 1 : 02213E00000000 cmd[0][0] = 0x02; @@ -1767,8 +1759,6 @@ void SetTag15693Uid(uint8_t *uid) cmd_send(CMD_ACK, recvlen>ISO15693_MAX_RESPONSE_LENGTH?ISO15693_MAX_RESPONSE_LENGTH:recvlen, 0, 0, recvbuf, ISO15693_MAX_RESPONSE_LENGTH); } - LED_D_OFF(); - LED_A_OFF(); } diff --git a/armsrc/iso15693.h b/armsrc/iso15693.h index 96a2b39b..5cbe5ecc 100644 --- a/armsrc/iso15693.h +++ b/armsrc/iso15693.h @@ -21,6 +21,8 @@ //SSP_CLK runs at 13.56MHz / 4 = 3,39MHz when acting as reader. All values should be multiples of 16 #define DELAY_ISO15693_VCD_TO_VICC_READER 1056 // 1056/3,39MHz = 311.5us from end of command EOF to start of tag response #define DELAY_ISO15693_VICC_TO_VCD_READER 1024 // 1024/3.39MHz = 302.1us between end of tag response and next reader command +// times in samples @ 212kHz when acting as reader +#define ISO15693_READER_TIMEOUT 330 // 330/212kHz = 1558us, should be even enough for iClass tags responding to ACTALL void Iso15693InitReader(); void CodeIso15693AsReader(uint8_t *cmd, int n); diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index 81738686..195a282d 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -35,7 +35,6 @@ #include "util_posix.h" #include "cmdhf14a.h" // DropField() -static int CmdHelp(const char *Cmd); #define ICLASS_KEYS_MAX 8 static uint8_t iClass_Key_Table[ICLASS_KEYS_MAX][8] = { @@ -49,12 +48,14 @@ static uint8_t iClass_Key_Table[ICLASS_KEYS_MAX][8] = { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }; + typedef struct iclass_block { - uint8_t d[8]; + uint8_t d[8]; } iclass_block_t; -int usage_hf_iclass_chk(void) { - PrintAndLog("Checkkeys loads a dictionary text file with 8byte hex keys to test authenticating against a iClass tag"); + +static void usage_hf_iclass_chk(void) { + PrintAndLog("Checkkeys loads a dictionary text file with 8byte hex keys to test authenticating against a iClass tag"); PrintAndLog("Usage: hf iclass chk [h|e|r] "); PrintAndLog("Options:"); PrintAndLog("h Show this help"); @@ -62,31 +63,25 @@ int usage_hf_iclass_chk(void) { PrintAndLog(" e target Elite / High security key scheme"); PrintAndLog(" r interpret dictionary file as raw (diversified keys)"); PrintAndLog("Samples:"); - PrintAndLog(" hf iclass chk f default_iclass_keys.dic"); - PrintAndLog(" hf iclass chk f default_iclass_keys.dic e"); - return 0; + PrintAndLog(" hf iclass chk f default_iclass_keys.dic"); + PrintAndLog(" hf iclass chk f default_iclass_keys.dic e"); } -int xorbits_8(uint8_t val) { - uint8_t res = val ^ (val >> 1); //1st pass - res = res ^ (res >> 1); // 2nd pass - res = res ^ (res >> 2); // 3rd pass - res = res ^ (res >> 4); // 4th pass - return res & 1; -} -int CmdHFiClassList(const char *Cmd) { +static int CmdHFiClassList(const char *Cmd) { PrintAndLog("Deprecated command, use 'hf list iclass' instead"); return 0; } -int CmdHFiClassSnoop(const char *Cmd) { + +static int CmdHFiClassSnoop(const char *Cmd) { UsbCommand c = {CMD_SNOOP_ICLASS}; SendCommand(&c); return 0; } -int usage_hf_iclass_sim(void) { + +static void usage_hf_iclass_sim(void) { PrintAndLog("Usage: hf iclass sim