mirror of
https://github.com/Proxmark/proxmark3.git
synced 2025-08-19 12:59:44 -07:00
Fido U2F complete (#716)
* add pkwrite * asn1print * asn1dump and CA * added PrintAndLogEx for merge commits between repo easier than now * changelog
This commit is contained in:
parent
e0991f6aa7
commit
6b882a3918
21 changed files with 3703 additions and 17 deletions
|
@ -6,6 +6,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Changed hf mfp security. Now it works in all the modes. (drHatson)
|
- Changed hf mfp security. Now it works in all the modes. (drHatson)
|
||||||
|
- `hf fido` - show/check DER certificate and signatures (Merlok)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
|
|
@ -109,8 +109,10 @@ CMDSRCS = $(SRC_SMARTCARD) \
|
||||||
crapto1/crypto1.c\
|
crapto1/crypto1.c\
|
||||||
crypto/libpcrypto.c\
|
crypto/libpcrypto.c\
|
||||||
crypto/asn1utils.c\
|
crypto/asn1utils.c\
|
||||||
|
crypto/asn1dump.c\
|
||||||
cliparser/argtable3.c\
|
cliparser/argtable3.c\
|
||||||
cliparser/cliparser.c\
|
cliparser/cliparser.c\
|
||||||
|
fido/additional_ca.c \
|
||||||
mfkey.c\
|
mfkey.c\
|
||||||
loclass/cipher.c \
|
loclass/cipher.c \
|
||||||
loclass/cipherutils.c \
|
loclass/cipherutils.c \
|
||||||
|
|
|
@ -39,6 +39,12 @@
|
||||||
#include "emv/emvjson.h"
|
#include "emv/emvjson.h"
|
||||||
#include "emv/dump.h"
|
#include "emv/dump.h"
|
||||||
#include "cliparser/cliparser.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);
|
static int CmdHelp(const char *Cmd);
|
||||||
|
|
||||||
|
@ -201,8 +207,9 @@ int CmdHFFidoRegister(const char *cmd) {
|
||||||
void* argtable[] = {
|
void* argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_lit0("aA", "apdu", "show APDU reqests and responses"),
|
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("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("jJ", "json", "fido.json", "JSON input / output file name for parameters."),
|
||||||
arg_str0(NULL, NULL, "<HEX/ASCII challenge parameter (32b HEX/1..16 chars)>", NULL),
|
arg_str0(NULL, NULL, "<HEX/ASCII challenge parameter (32b HEX/1..16 chars)>", NULL),
|
||||||
arg_str0(NULL, NULL, "<HEX/ASCII application parameter (32b HEX/1..16 chars)>", NULL),
|
arg_str0(NULL, NULL, "<HEX/ASCII application parameter (32b HEX/1..16 chars)>", NULL),
|
||||||
|
@ -212,11 +219,13 @@ int CmdHFFidoRegister(const char *cmd) {
|
||||||
|
|
||||||
bool APDULogging = arg_get_lit(1);
|
bool APDULogging = arg_get_lit(1);
|
||||||
bool verbose = arg_get_lit(2);
|
bool verbose = arg_get_lit(2);
|
||||||
|
bool verbose2 = arg_get_lit(2) > 1;
|
||||||
bool paramsPlain = arg_get_lit(3);
|
bool paramsPlain = arg_get_lit(3);
|
||||||
|
bool showDERTLV = arg_get_lit(4);
|
||||||
|
|
||||||
char fname[250] = {0};
|
char fname[250] = {0};
|
||||||
bool err;
|
bool err;
|
||||||
root = OpenJson(4, fname, argtable, &err);
|
root = OpenJson(5, fname, argtable, &err);
|
||||||
if(err)
|
if(err)
|
||||||
return 1;
|
return 1;
|
||||||
if (root) {
|
if (root) {
|
||||||
|
@ -227,13 +236,13 @@ int CmdHFFidoRegister(const char *cmd) {
|
||||||
|
|
||||||
if (paramsPlain) {
|
if (paramsPlain) {
|
||||||
memset(cdata, 0x00, 32);
|
memset(cdata, 0x00, 32);
|
||||||
CLIGetStrWithReturn(5, cdata, &chlen);
|
CLIGetStrWithReturn(6, cdata, &chlen);
|
||||||
if (chlen && chlen > 16) {
|
if (chlen && chlen > 16) {
|
||||||
PrintAndLog("ERROR: challenge parameter length in ASCII mode must be less than 16 chars instead of: %d", chlen);
|
PrintAndLog("ERROR: challenge parameter length in ASCII mode must be less than 16 chars instead of: %d", chlen);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
CLIGetHexWithReturn(5, cdata, &chlen);
|
CLIGetHexWithReturn(6, cdata, &chlen);
|
||||||
if (chlen && chlen != 32) {
|
if (chlen && chlen != 32) {
|
||||||
PrintAndLog("ERROR: challenge parameter length must be 32 bytes only.");
|
PrintAndLog("ERROR: challenge parameter length must be 32 bytes only.");
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -245,13 +254,13 @@ int CmdHFFidoRegister(const char *cmd) {
|
||||||
|
|
||||||
if (paramsPlain) {
|
if (paramsPlain) {
|
||||||
memset(adata, 0x00, 32);
|
memset(adata, 0x00, 32);
|
||||||
CLIGetStrWithReturn(6, adata, &applen);
|
CLIGetStrWithReturn(7, adata, &applen);
|
||||||
if (applen && applen > 16) {
|
if (applen && applen > 16) {
|
||||||
PrintAndLog("ERROR: application parameter length in ASCII mode must be less than 16 chars instead of: %d", applen);
|
PrintAndLog("ERROR: application parameter length in ASCII mode must be less than 16 chars instead of: %d", applen);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
CLIGetHexWithReturn(6, adata, &applen);
|
CLIGetHexWithReturn(7, adata, &applen);
|
||||||
if (applen && applen != 32) {
|
if (applen && applen != 32) {
|
||||||
PrintAndLog("ERROR: application parameter length must be 32 bytes only.");
|
PrintAndLog("ERROR: application parameter length must be 32 bytes only.");
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -302,7 +311,7 @@ int CmdHFFidoRegister(const char *cmd) {
|
||||||
if (APDULogging)
|
if (APDULogging)
|
||||||
PrintAndLog("---------------------------------------------------------------");
|
PrintAndLog("---------------------------------------------------------------");
|
||||||
PrintAndLog("data len: %d", len);
|
PrintAndLog("data len: %d", len);
|
||||||
if (verbose) {
|
if (verbose2) {
|
||||||
PrintAndLog("--------------data----------------------");
|
PrintAndLog("--------------data----------------------");
|
||||||
dump_buffer((const unsigned char *)buf, len, NULL, 0);
|
dump_buffer((const unsigned char *)buf, len, NULL, 0);
|
||||||
PrintAndLog("--------------data----------------------");
|
PrintAndLog("--------------data----------------------");
|
||||||
|
@ -319,20 +328,119 @@ int CmdHFFidoRegister(const char *cmd) {
|
||||||
|
|
||||||
int derp = 67 + keyHandleLen;
|
int derp = 67 + keyHandleLen;
|
||||||
int derLen = (buf[derp + 2] << 8) + buf[derp + 3] + 4;
|
int derLen = (buf[derp + 2] << 8) + buf[derp + 3] + 4;
|
||||||
// needs to decode DER certificate
|
if (verbose2) {
|
||||||
if (verbose) {
|
PrintAndLog("DER certificate[%d]:\n------------------DER-------------------", derLen);
|
||||||
PrintAndLog("DER certificate[%d]:------------------DER-------------------", derLen);
|
dump_buffer_simple((const unsigned char *)&buf[derp], derLen, NULL);
|
||||||
dump_buffer_simple((const unsigned char *)&buf[67 + keyHandleLen], derLen, NULL);
|
|
||||||
PrintAndLog("\n----------------DER---------------------");
|
PrintAndLog("\n----------------DER---------------------");
|
||||||
} else {
|
} else {
|
||||||
|
if (verbose)
|
||||||
|
PrintAndLog("------------------DER-------------------");
|
||||||
PrintAndLog("DER certificate[%d]: %s...", derLen, sprint_hex(&buf[derp], 20));
|
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;
|
int hashp = 1 + 65 + 1 + keyHandleLen + derLen;
|
||||||
PrintAndLog("Hash[%d]: %s", len - hashp, sprint_hex(&buf[hashp], len - hashp));
|
PrintAndLog("Hash[%d]: %s", len - hashp, sprint_hex(&buf[hashp], len - hashp));
|
||||||
|
|
||||||
// check ANSI X9.62 format ECDSA signature (on P-256)
|
// 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: ");
|
PrintAndLog("\nauth command: ");
|
||||||
printf("hf fido auth %s%s", paramsPlain?"-p ":"", sprint_hex_inrow(&buf[67], keyHandleLen));
|
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) {
|
if (root) {
|
||||||
JsonSaveBufAsHex(root, "ChallengeParam", data, 32);
|
JsonSaveBufAsHex(root, "ChallengeParam", data, 32);
|
||||||
JsonSaveBufAsHex(root, "ApplicationParam", &data[32], 32);
|
JsonSaveBufAsHex(root, "ApplicationParam", &data[32], 32);
|
||||||
|
JsonSaveBufAsHexCompact(root, "PublicKey", &buf[1], 65);
|
||||||
JsonSaveInt(root, "KeyHandleLen", keyHandleLen);
|
JsonSaveInt(root, "KeyHandleLen", keyHandleLen);
|
||||||
JsonSaveBufAsHexCompact(root, "KeyHandle", &buf[67], keyHandleLen);
|
JsonSaveBufAsHexCompact(root, "KeyHandle", &buf[67], keyHandleLen);
|
||||||
JsonSaveBufAsHexCompact(root, "DER", &buf[67 + keyHandleLen], derLen);
|
JsonSaveBufAsHexCompact(root, "DER", &buf[67 + keyHandleLen], derLen);
|
||||||
|
@ -366,6 +475,8 @@ int CmdHFFidoRegister(const char *cmd) {
|
||||||
int CmdHFFidoAuthenticate(const char *cmd) {
|
int CmdHFFidoAuthenticate(const char *cmd) {
|
||||||
uint8_t data[512] = {0};
|
uint8_t data[512] = {0};
|
||||||
uint8_t hdata[250] = {0};
|
uint8_t hdata[250] = {0};
|
||||||
|
bool public_key_loaded = false;
|
||||||
|
uint8_t public_key[65] = {0};
|
||||||
int hdatalen = 0;
|
int hdatalen = 0;
|
||||||
uint8_t keyHandleLen = 0;
|
uint8_t keyHandleLen = 0;
|
||||||
json_t *root = NULL;
|
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("uU", "user", "mode: enforce-user-presence-and-sign"),
|
||||||
arg_lit0("cC", "check", "mode: check-only"),
|
arg_lit0("cC", "check", "mode: check-only"),
|
||||||
arg_str0("jJ", "json", "fido.json", "JSON input / output file name for parameters."),
|
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, "<HEX key handle (var 0..255b)>", NULL),
|
arg_str0(NULL, NULL, "<HEX key handle (var 0..255b)>", NULL),
|
||||||
arg_str0(NULL, NULL, "<HEX/ASCII challenge parameter (32b HEX/1..16 chars)>", NULL),
|
arg_str0(NULL, NULL, "<HEX/ASCII challenge parameter (32b HEX/1..16 chars)>", NULL),
|
||||||
arg_str0(NULL, NULL, "<HEX/ASCII application parameter (32b HEX/1..16 chars)>", NULL),
|
arg_str0(NULL, NULL, "<HEX/ASCII application parameter (32b HEX/1..16 chars)>", NULL),
|
||||||
|
@ -393,7 +505,7 @@ int CmdHFFidoAuthenticate(const char *cmd) {
|
||||||
CLIExecWithReturn(cmd, argtable, true);
|
CLIExecWithReturn(cmd, argtable, true);
|
||||||
|
|
||||||
bool APDULogging = arg_get_lit(1);
|
bool APDULogging = arg_get_lit(1);
|
||||||
//bool verbose = arg_get_lit(2);
|
bool verbose = arg_get_lit(2);
|
||||||
bool paramsPlain = arg_get_lit(3);
|
bool paramsPlain = arg_get_lit(3);
|
||||||
uint8_t controlByte = 0x08;
|
uint8_t controlByte = 0x08;
|
||||||
if (arg_get_lit(5))
|
if (arg_get_lit(5))
|
||||||
|
@ -413,9 +525,22 @@ int CmdHFFidoAuthenticate(const char *cmd) {
|
||||||
JsonLoadBufAsHex(root, "$.KeyHandle", &data[65], 512 - 67, &jlen);
|
JsonLoadBufAsHex(root, "$.KeyHandle", &data[65], 512 - 67, &jlen);
|
||||||
keyHandleLen = jlen & 0xff;
|
keyHandleLen = jlen & 0xff;
|
||||||
data[64] = keyHandleLen;
|
data[64] = keyHandleLen;
|
||||||
|
JsonLoadBufAsHex(root, "$.PublicKey", public_key, 65, &jlen);
|
||||||
|
public_key_loaded = (jlen > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// public key
|
||||||
CLIGetHexWithReturn(8, hdata, &hdatalen);
|
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) {
|
if (hdatalen > 255) {
|
||||||
PrintAndLog("ERROR: application parameter length must be less than 255.");
|
PrintAndLog("ERROR: application parameter length must be less than 255.");
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -434,7 +559,7 @@ int CmdHFFidoAuthenticate(const char *cmd) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
CLIGetHexWithReturn(9, hdata, &hdatalen);
|
CLIGetHexWithReturn(10, hdata, &hdatalen);
|
||||||
if (hdatalen && hdatalen != 32) {
|
if (hdatalen && hdatalen != 32) {
|
||||||
PrintAndLog("ERROR: challenge parameter length must be 32 bytes only.");
|
PrintAndLog("ERROR: challenge parameter length must be 32 bytes only.");
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -445,7 +570,7 @@ int CmdHFFidoAuthenticate(const char *cmd) {
|
||||||
|
|
||||||
if (paramsPlain) {
|
if (paramsPlain) {
|
||||||
memset(hdata, 0x00, 32);
|
memset(hdata, 0x00, 32);
|
||||||
CLIGetStrWithReturn(10, hdata, &hdatalen);
|
CLIGetStrWithReturn(11, hdata, &hdatalen);
|
||||||
if (hdatalen && hdatalen > 16) {
|
if (hdatalen && hdatalen > 16) {
|
||||||
PrintAndLog("ERROR: application parameter length in ASCII mode must be less than 16 chars instead of: %d", hdatalen);
|
PrintAndLog("ERROR: application parameter length in ASCII mode must be less than 16 chars instead of: %d", hdatalen);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -509,6 +634,42 @@ int CmdHFFidoAuthenticate(const char *cmd) {
|
||||||
PrintAndLog("Counter: %d", cntr);
|
PrintAndLog("Counter: %d", cntr);
|
||||||
PrintAndLog("Hash[%d]: %s", len - 5, sprint_hex(&buf[5], len - 5));
|
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) {
|
if (root) {
|
||||||
JsonSaveBufAsHex(root, "ChallengeParam", data, 32);
|
JsonSaveBufAsHex(root, "ChallengeParam", data, 32);
|
||||||
JsonSaveBufAsHex(root, "ApplicationParam", &data[32], 32);
|
JsonSaveBufAsHex(root, "ApplicationParam", &data[32], 32);
|
||||||
|
|
353
client/crypto/asn1dump.c
Normal file
353
client/crypto/asn1dump.c
Normal file
|
@ -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 <ctype.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <jansson.h>
|
||||||
|
#include <mbedtls/asn1.h>
|
||||||
|
#include <mbedtls/oid.h>
|
||||||
|
#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;
|
||||||
|
}
|
21
client/crypto/asn1dump.h
Normal file
21
client/crypto/asn1dump.h
Normal file
|
@ -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 <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "emv/tlv.h"
|
||||||
|
|
||||||
|
extern bool asn1_tag_dump(const struct tlv *tlv, FILE *f, int level, bool *candump);
|
||||||
|
|
||||||
|
#endif /* asn1utils.h */
|
|
@ -9,7 +9,14 @@
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
#include "asn1utils.h"
|
#include "asn1utils.h"
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <mbedtls/asn1.h>
|
#include <mbedtls/asn1.h>
|
||||||
|
#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) {
|
int ecdsa_asn1_get_signature(uint8_t *signature, size_t signaturelen, uint8_t *rval, uint8_t *sval) {
|
||||||
if (!signature || !signaturelen || !rval || !sval)
|
if (!signature || !signaturelen || !rval || !sval)
|
||||||
|
@ -55,7 +62,27 @@ exit:
|
||||||
return res;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
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);
|
extern int ecdsa_asn1_get_signature(uint8_t *signature, size_t signaturelen, uint8_t *rval, uint8_t *sval);
|
||||||
|
|
||||||
#endif /* asn1utils.h */
|
#endif /* asn1utils.h */
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <mbedtls/asn1.h>
|
#include <mbedtls/asn1.h>
|
||||||
#include <mbedtls/aes.h>
|
#include <mbedtls/aes.h>
|
||||||
#include <mbedtls/cmac.h>
|
#include <mbedtls/cmac.h>
|
||||||
|
#include <mbedtls/pk.h>
|
||||||
#include <mbedtls/ecdsa.h>
|
#include <mbedtls/ecdsa.h>
|
||||||
#include <mbedtls/sha256.h>
|
#include <mbedtls/sha256.h>
|
||||||
#include <mbedtls/ctr_drbg.h>
|
#include <mbedtls/ctr_drbg.h>
|
||||||
|
@ -208,6 +209,31 @@ char *ecdsa_get_error(int ret) {
|
||||||
return retstr;
|
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 ecdsa_signature_create(uint8_t *key_d, uint8_t *key_xy, uint8_t *input, int length, uint8_t *signature, size_t *signaturelen) {
|
||||||
int res;
|
int res;
|
||||||
*signaturelen = 0;
|
*signaturelen = 0;
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <mbedtls/pk.h>
|
||||||
|
|
||||||
extern int aes_encode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length);
|
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_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 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_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_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_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 char *ecdsa_get_error(int ret);
|
||||||
|
|
2325
client/crypto/oids.json
Normal file
2325
client/crypto/oids.json
Normal file
File diff suppressed because it is too large
Load diff
|
@ -264,6 +264,23 @@ bool HexToBuffer(const char *errormsg, const char *hexvalue, uint8_t * buffer, s
|
||||||
return true;
|
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) {
|
int JsonLoadBufAsHex(json_t *elm, char *path, uint8_t *data, size_t maxbufferlen, size_t *datalen) {
|
||||||
if (datalen)
|
if (datalen)
|
||||||
*datalen = 0;
|
*datalen = 0;
|
||||||
|
|
|
@ -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 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 int JsonLoadBufAsHex(json_t *elm, char *path, uint8_t *data, size_t maxbufferlen, size_t *datalen);
|
||||||
|
|
||||||
extern bool ParamLoadFromJson(struct tlvdb *tlv);
|
extern bool ParamLoadFromJson(struct tlvdb *tlv);
|
||||||
|
|
63
client/fido/additional_ca.c
Normal file
63
client/fido/additional_ca.c
Normal file
|
@ -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);
|
21
client/fido/additional_ca.h
Normal file
21
client/fido/additional_ca.h
Normal file
|
@ -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 <stddef.h>
|
||||||
|
|
||||||
|
// 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__ */
|
0
client/obj/fido/.dummy
Normal file
0
client/obj/fido/.dummy
Normal file
72
client/ui.c
72
client/ui.c
|
@ -16,6 +16,7 @@
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <readline/readline.h>
|
#include <readline/readline.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
#include "util.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
|
@ -32,6 +33,77 @@ static char *logfilename = "proxmark3.log";
|
||||||
#ifndef EXTERNAL_PRINTANDLOG
|
#ifndef EXTERNAL_PRINTANDLOG
|
||||||
static pthread_mutex_t print_lock = PTHREAD_MUTEX_INITIALIZER;
|
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, ...)
|
void PrintAndLog(char *fmt, ...)
|
||||||
{
|
{
|
||||||
char *saved_line;
|
char *saved_line;
|
||||||
|
|
|
@ -14,11 +14,15 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define MAX_PRINT_BUFFER 2048
|
||||||
|
typedef enum logLevel {NORMAL, SUCCESS, INFO, FAILED, WARNING, ERR, DEBUG} logLevel_t;
|
||||||
|
|
||||||
void ShowGui(void);
|
void ShowGui(void);
|
||||||
void HideGraphWindow(void);
|
void HideGraphWindow(void);
|
||||||
void ShowGraphWindow(void);
|
void ShowGraphWindow(void);
|
||||||
void RepaintGraphWindow(void);
|
void RepaintGraphWindow(void);
|
||||||
void PrintAndLog(char *fmt, ...);
|
void PrintAndLog(char *fmt, ...);
|
||||||
|
void PrintAndLogEx(logLevel_t level, char *fmt, ...);
|
||||||
void SetLogFilename(char *fn);
|
void SetLogFilename(char *fn);
|
||||||
void SetFlushAfterWrite(bool flush_after_write);
|
void SetFlushAfterWrite(bool flush_after_write);
|
||||||
|
|
||||||
|
|
|
@ -110,6 +110,35 @@ void FillFileNameByUID(char *fileName, uint8_t * uid, char *ext, int byteCount)
|
||||||
sprintf(fnameptr, "%s", ext);
|
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,
|
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) {
|
const size_t min_str_len, const size_t spaces_between, bool uppercase) {
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,46 @@
|
||||||
#define FILE_PATH_SIZE 2000
|
#define FILE_PATH_SIZE 2000
|
||||||
#endif
|
#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 int ukbhit(void);
|
||||||
|
|
||||||
extern void AddLogLine(char *fileName, char *extData, char *c);
|
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 AddLogCurrentDT(char *fileName);
|
||||||
extern void FillFileNameByUID(char *fileName, uint8_t * uid, char *ext, int byteCount);
|
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,
|
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);
|
const size_t hex_max_len, const size_t min_str_len, const size_t spaces_between, bool uppercase);
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ mbedtls_SOURCES = \
|
||||||
arc4.c \
|
arc4.c \
|
||||||
pk.c \
|
pk.c \
|
||||||
pk_wrap.c \
|
pk_wrap.c \
|
||||||
|
pkwrite.c \
|
||||||
pkcs5.c \
|
pkcs5.c \
|
||||||
pkcs12.c \
|
pkcs12.c \
|
||||||
pkparse.c \
|
pkparse.c \
|
||||||
|
|
517
common/mbedtls/pkwrite.c
Normal file
517
common/mbedtls/pkwrite.c
Normal file
|
@ -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 <string.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
|
||||||
|
#if defined(MBEDTLS_PEM_WRITE_C)
|
||||||
|
#include "mbedtls/pem.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MBEDTLS_PLATFORM_C)
|
||||||
|
#include "mbedtls/platform.h"
|
||||||
|
#else
|
||||||
|
#include <stdlib.h>
|
||||||
|
#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 */
|
Loading…
Add table
Add a link
Reference in a new issue