mirror of
https://github.com/Proxmark/proxmark3.git
synced 2025-08-20 13:23:25 -07:00
Merge branch 'master' into feature/hitagS_standardmode_and_improvements
This commit is contained in:
commit
dd3c12a718
32 changed files with 3912 additions and 203 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)
|
||||||
- Changed `lf hitag reader 0x ... <firstPage> <tagmode>` - to select first page to read and tagmode (0=STANDARD, 1=ADVANCED, 2=FAST_ADVANCED)
|
- Changed `lf hitag reader 0x ... <firstPage> <tagmode>` - 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
|
- Accept hitagS con0 tags with memory bits set to 11 and handle like 2048 tag
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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) {
|
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);
|
int len = param_getlength(Cmd, indx);
|
||||||
if (len > 0 && len < 4){
|
if (len > 0 && len < 4){
|
||||||
param_getstr(Cmd, indx, ctmp3, sizeof(ctmp3));
|
param_getstr(Cmd, indx, ctmp3, sizeof(ctmp3));
|
||||||
|
@ -1021,7 +1021,7 @@ int CmdHF14AMfChk(const char *Cmd)
|
||||||
PrintAndLog("d - write keys to binary file\n");
|
PrintAndLog("d - write keys to binary file\n");
|
||||||
PrintAndLog("t - write keys to emulator memory");
|
PrintAndLog("t - write keys to emulator memory");
|
||||||
PrintAndLog("s - slow execute. timeout 1ms");
|
PrintAndLog("s - slow execute. timeout 1ms");
|
||||||
PrintAndLog("ss- very slow execute. timeout 5ms");
|
PrintAndLog("ss - very slow execute. timeout 5ms");
|
||||||
PrintAndLog(" sample: hf mf chk 0 A 1234567890ab keys.dic");
|
PrintAndLog(" sample: hf mf chk 0 A 1234567890ab keys.dic");
|
||||||
PrintAndLog(" hf mf chk *1 ? t");
|
PrintAndLog(" hf mf chk *1 ? t");
|
||||||
PrintAndLog(" hf mf chk *1 ? d");
|
PrintAndLog(" hf mf chk *1 ? d");
|
||||||
|
@ -1040,16 +1040,16 @@ int CmdHF14AMfChk(const char *Cmd)
|
||||||
int keycnt = 0;
|
int keycnt = 0;
|
||||||
char ctmp = 0x00;
|
char ctmp = 0x00;
|
||||||
int clen = 0;
|
int clen = 0;
|
||||||
char ctmp3[3] = {0x00};
|
|
||||||
uint8_t blockNo = 0;
|
uint8_t blockNo = 0;
|
||||||
uint8_t SectorsCnt = 0;
|
uint8_t SectorsCnt = 0;
|
||||||
uint8_t keyType = 0;
|
uint8_t keyType = 0;
|
||||||
uint64_t key64 = 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;
|
bool param3InUse = false;
|
||||||
|
|
||||||
int transferToEml = 0;
|
bool transferToEml = 0;
|
||||||
int createDumpFile = 0;
|
bool createDumpFile = 0;
|
||||||
|
|
||||||
sector_t *e_sector = NULL;
|
sector_t *e_sector = NULL;
|
||||||
|
|
||||||
|
@ -1087,32 +1087,12 @@ int CmdHF14AMfChk(const char *Cmd)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// transfer to emulator & create dump file
|
parseParamTDS(Cmd, 2, &transferToEml, &createDumpFile, &btimeout14a);
|
||||||
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;
|
|
||||||
|
|
||||||
param3InUse = transferToEml | createDumpFile;
|
param3InUse = transferToEml | createDumpFile | (btimeout14a != MF_CHKKEYS_DEFTIMEOUT);
|
||||||
|
|
||||||
timeout14a = 500; // fast by default
|
PrintAndLog("--chk keys. sectors:%2d, block no:%3d, key type:%c, eml:%c, dmp=%c checktimeout=%d us",
|
||||||
// double parameters - ts, ds
|
SectorsCnt, blockNo, keyType?'B':'A', transferToEml?'y':'n', createDumpFile?'y':'n', ((int)btimeout14a * 10000) / 106);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = param3InUse; param_getchar(Cmd, 2 + i); i++) {
|
for (i = param3InUse; param_getchar(Cmd, 2 + i); i++) {
|
||||||
if (!param_gethex(Cmd, 2 + i, keyBlock + 6 * keycnt, 12)) {
|
if (!param_gethex(Cmd, 2 + i, keyBlock + 6 * keycnt, 12)) {
|
||||||
|
@ -1210,7 +1190,7 @@ int CmdHF14AMfChk(const char *Cmd)
|
||||||
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;
|
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 != 1) {
|
||||||
if (!res) {
|
if (!res) {
|
||||||
|
|
356
client/crypto/asn1dump.c
Normal file
356
client/crypto/asn1dump.c
Normal file
|
@ -0,0 +1,356 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// 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
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define _POSIX_C_SOURCE 200809L // need for strnlen()
|
||||||
|
|
||||||
|
#include "asn1dump.h"
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.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__ */
|
|
@ -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)
|
static int dump_to_fd(const char *buffer, size_t size, void *data)
|
||||||
{
|
{
|
||||||
int *dest = (int *)data;
|
|
||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
|
int *dest = (int *)data;
|
||||||
if(write(*dest, buffer, size) == (ssize_t)size)
|
if(write(*dest, buffer, size) == (ssize_t)size)
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#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)
|
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;
|
const char *pos, *end, *lim;
|
||||||
int32_t codepoint;
|
int32_t codepoint = 0;
|
||||||
|
|
||||||
if(dump("\"", 1, data))
|
if(dump("\"", 1, data))
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -306,7 +306,7 @@ static int do_dump(const json_t *json, size_t flags, int depth,
|
||||||
const char *separator;
|
const char *separator;
|
||||||
int separator_length;
|
int separator_length;
|
||||||
/* Space for "0x", double the sizeof a pointer for the hex and a terminator. */
|
/* 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) {
|
if(flags & JSON_COMPACT) {
|
||||||
separator = ":";
|
separator = ":";
|
||||||
|
@ -318,7 +318,7 @@ static int do_dump(const json_t *json, size_t flags, int depth,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* detect circular references */
|
/* detect circular references */
|
||||||
if (loop_check(parents, json, key, sizeof(key)))
|
if (loop_check(parents, json, loop_key, sizeof(loop_key)))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
iter = json_object_iter((json_t *)json);
|
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))
|
if(!embed && dump("{", 1, data))
|
||||||
return -1;
|
return -1;
|
||||||
if(!iter) {
|
if(!iter) {
|
||||||
hashtable_del(parents, key);
|
hashtable_del(parents, loop_key);
|
||||||
return embed ? 0 : dump("}", 1, data);
|
return embed ? 0 : dump("}", 1, data);
|
||||||
}
|
}
|
||||||
if(dump_indent(flags, depth + 1, 0, dump, 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);
|
return embed ? 0 : dump("}", 1, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ typedef struct hashtable {
|
||||||
*
|
*
|
||||||
* Returns 0 on success, -1 on error (out of memory).
|
* 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
|
* hashtable_close - Release all resources used by a hashtable object
|
||||||
|
|
|
@ -164,7 +164,7 @@ static int seed_from_timestamp_and_pid(uint32_t *seed) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t generate_seed() {
|
static uint32_t generate_seed() {
|
||||||
uint32_t seed;
|
uint32_t seed = 0;
|
||||||
int done = 0;
|
int done = 0;
|
||||||
|
|
||||||
#if !defined(_WIN32) && defined(USE_URANDOM)
|
#if !defined(_WIN32) && defined(USE_URANDOM)
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
#define JANSSON_H
|
#define JANSSON_H
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h> /* for size_t */
|
#include <stdlib.h> /* for size_t */
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
@ -22,11 +21,11 @@ extern "C" {
|
||||||
/* version */
|
/* version */
|
||||||
|
|
||||||
#define JANSSON_MAJOR_VERSION 2
|
#define JANSSON_MAJOR_VERSION 2
|
||||||
#define JANSSON_MINOR_VERSION 11
|
#define JANSSON_MINOR_VERSION 12
|
||||||
#define JANSSON_MICRO_VERSION 0
|
#define JANSSON_MICRO_VERSION 0
|
||||||
|
|
||||||
/* Micro version is omitted if it's 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
|
/* Version as a 3-byte hex number, e.g. 0x010201 == 1.2.1. Use this
|
||||||
for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */
|
for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */
|
||||||
|
@ -40,6 +39,12 @@ extern "C" {
|
||||||
#define JANSSON_THREAD_SAFE_REFCOUNT 1
|
#define JANSSON_THREAD_SAFE_REFCOUNT 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
|
#define JANSSON_ATTRS(...) __attribute__((__VA_ARGS__))
|
||||||
|
#else
|
||||||
|
#define JANSSON_ATTRS(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* types */
|
/* types */
|
||||||
|
|
||||||
typedef enum {
|
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);
|
void json_object_seed(size_t seed);
|
||||||
size_t json_object_size(const json_t *object);
|
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(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_set_new_nocheck(json_t *object, const char *key, json_t *value);
|
||||||
int json_object_del(json_t *object, const char *key);
|
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);
|
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_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_append_new(json_t *array, json_t *value);
|
||||||
int json_array_insert_new(json_t *array, size_t index, 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 */
|
/* pack, unpack */
|
||||||
|
|
||||||
json_t *json_pack(const char *fmt, ...);
|
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, ...);
|
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);
|
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_VALIDATE_ONLY 0x1
|
||||||
#define JSON_STRICT 0x2
|
#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 */
|
/* sprintf */
|
||||||
|
|
||||||
json_t *json_sprintf(const char *fmt, ...);
|
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);
|
json_t *json_vsprintf(const char *fmt, va_list ap) JANSSON_ATTRS(warn_unused_result, format(printf, 1, 0));
|
||||||
|
|
||||||
|
|
||||||
/* equality */
|
/* equality */
|
||||||
|
@ -303,10 +308,8 @@ int json_equal(const json_t *value1, const json_t *value2);
|
||||||
|
|
||||||
/* copying */
|
/* copying */
|
||||||
|
|
||||||
json_t *json_copy(json_t *value);
|
json_t *json_copy(json_t *value) JANSSON_ATTRS(warn_unused_result);
|
||||||
json_t *json_deep_copy(const json_t *value);
|
json_t *json_deep_copy(const json_t *value) JANSSON_ATTRS(warn_unused_result);
|
||||||
|
|
||||||
/* path */
|
|
||||||
|
|
||||||
json_t *json_path_get(const json_t *json, const char *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);
|
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);
|
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_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);
|
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);
|
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);
|
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);
|
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);
|
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 */
|
/* 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);
|
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);
|
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_dumpf(const json_t *json, FILE *output, size_t flags);
|
||||||
int json_dumpfd(const json_t *json, int output, size_t flags);
|
int json_dumpfd(const json_t *json, int output, size_t flags);
|
||||||
|
|
|
@ -87,11 +87,11 @@ int jsonp_strtod(strbuffer_t *strbuffer, double *out);
|
||||||
int jsonp_dtostr(char *buffer, size_t size, double value, int prec);
|
int jsonp_dtostr(char *buffer, size_t size, double value, int prec);
|
||||||
|
|
||||||
/* Wrappers for custom memory functions */
|
/* 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);
|
void jsonp_free(void *ptr);
|
||||||
char *jsonp_strndup(const char *str, size_t length);
|
char *jsonp_strndup(const char *str, size_t length) JANSSON_ATTRS(warn_unused_result);
|
||||||
char *jsonp_strdup(const char *str);
|
char *jsonp_strdup(const char *str) JANSSON_ATTRS(warn_unused_result);
|
||||||
char *jsonp_strndup(const char *str, size_t len);
|
char *jsonp_strndup(const char *str, size_t len) JANSSON_ATTRS(warn_unused_result);
|
||||||
|
|
||||||
|
|
||||||
/* Windows compatibility */
|
/* Windows compatibility */
|
||||||
|
|
|
@ -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);
|
json = jsonp_stringn_nocheck_own(value, len);
|
||||||
if(json) {
|
|
||||||
lex->value.string.val = NULL;
|
lex->value.string.val = NULL;
|
||||||
lex->value.string.len = 0;
|
lex->value.string.len = 0;
|
||||||
}
|
|
||||||
break;
|
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)
|
static int fd_get_func(int *fd)
|
||||||
{
|
{
|
||||||
uint8_t c;
|
|
||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
|
uint8_t c;
|
||||||
if (read(*fd, &c, 1) == 1)
|
if (read(*fd, &c, 1) == 1)
|
||||||
return c;
|
return c;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -75,6 +75,9 @@ static void next_token(scanner_t *s)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!token(s) && !*s->fmt)
|
||||||
|
return;
|
||||||
|
|
||||||
t = s->fmt;
|
t = s->fmt;
|
||||||
s->column++;
|
s->column++;
|
||||||
s->pos++;
|
s->pos++;
|
||||||
|
@ -97,7 +100,7 @@ static void next_token(scanner_t *s)
|
||||||
s->token.column = s->column;
|
s->token.column = s->column;
|
||||||
s->token.pos = s->pos;
|
s->token.pos = s->pos;
|
||||||
|
|
||||||
t++;
|
if (*t) t++;
|
||||||
s->fmt = 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
|
/* ours will be set to 1 if jsonp_free() must be called for the result
|
||||||
afterwards */
|
afterwards */
|
||||||
static char *read_string(scanner_t *s, va_list *ap,
|
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;
|
char t;
|
||||||
strbuffer_t strbuff;
|
strbuffer_t strbuff;
|
||||||
|
@ -144,7 +147,10 @@ static char *read_string(scanner_t *s, va_list *ap,
|
||||||
str = va_arg(*ap, const char *);
|
str = va_arg(*ap, const char *);
|
||||||
|
|
||||||
if(!str) {
|
if(!str) {
|
||||||
set_error(s, "<args>", json_error_null_value, "NULL string argument");
|
if (!optional) {
|
||||||
|
set_error(s, "<args>", json_error_null_value, "NULL %s", purpose);
|
||||||
|
s->has_error = 1;
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,19 +158,28 @@ static char *read_string(scanner_t *s, va_list *ap,
|
||||||
|
|
||||||
if(!utf8_check_string(str, length)) {
|
if(!utf8_check_string(str, length)) {
|
||||||
set_error(s, "<args>", json_error_invalid_utf8, "Invalid UTF-8 %s", purpose);
|
set_error(s, "<args>", json_error_invalid_utf8, "Invalid UTF-8 %s", purpose);
|
||||||
|
s->has_error = 1;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
*out_len = length;
|
*out_len = length;
|
||||||
return (char *)str;
|
return (char *)str;
|
||||||
|
} else if (optional) {
|
||||||
|
set_error(s, "<format>", 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, "<internal>", json_error_out_of_memory, "Out of memory");
|
||||||
|
s->has_error = 1;
|
||||||
|
}
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
str = va_arg(*ap, const char *);
|
str = va_arg(*ap, const char *);
|
||||||
if(!str) {
|
if(!str) {
|
||||||
set_error(s, "<args>", json_error_null_value, "NULL string argument");
|
set_error(s, "<args>", json_error_null_value, "NULL %s", purpose);
|
||||||
s->has_error = 1;
|
s->has_error = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,6 +235,7 @@ static json_t *pack_object(scanner_t *s, va_list *ap)
|
||||||
size_t len;
|
size_t len;
|
||||||
int ours;
|
int ours;
|
||||||
json_t *value;
|
json_t *value;
|
||||||
|
char valueOptional;
|
||||||
|
|
||||||
if(!token(s)) {
|
if(!token(s)) {
|
||||||
set_error(s, "<format>", json_error_invalid_format, "Unexpected end of format string");
|
set_error(s, "<format>", 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;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
key = read_string(s, ap, "object key", &len, &ours);
|
key = read_string(s, ap, "object key", &len, &ours, 0);
|
||||||
if (!key)
|
|
||||||
s->has_error = 1;
|
|
||||||
|
|
||||||
next_token(s);
|
next_token(s);
|
||||||
|
|
||||||
|
next_token(s);
|
||||||
|
valueOptional = token(s);
|
||||||
|
prev_token(s);
|
||||||
|
|
||||||
value = pack(s, ap);
|
value = pack(s, ap);
|
||||||
if(!value) {
|
if(!value) {
|
||||||
if(ours)
|
if(ours)
|
||||||
jsonp_free(key);
|
jsonp_free(key);
|
||||||
|
|
||||||
if(strchr("soO", token(s)) && s->next_token.token == '*') {
|
if(valueOptional != '*') {
|
||||||
next_token(s);
|
set_error(s, "<args>", json_error_null_value, "NULL object value");
|
||||||
} else {
|
|
||||||
s->has_error = 1;
|
s->has_error = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,8 +280,6 @@ static json_t *pack_object(scanner_t *s, va_list *ap)
|
||||||
if(ours)
|
if(ours)
|
||||||
jsonp_free(key);
|
jsonp_free(key);
|
||||||
|
|
||||||
if(strchr("soO", token(s)) && s->next_token.token == '*')
|
|
||||||
next_token(s);
|
|
||||||
next_token(s);
|
next_token(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,6 +298,7 @@ static json_t *pack_array(scanner_t *s, va_list *ap)
|
||||||
|
|
||||||
while(token(s) != ']') {
|
while(token(s) != ']') {
|
||||||
json_t *value;
|
json_t *value;
|
||||||
|
char valueOptional;
|
||||||
|
|
||||||
if(!token(s)) {
|
if(!token(s)) {
|
||||||
set_error(s, "<format>", json_error_invalid_format, "Unexpected end of format string");
|
set_error(s, "<format>", 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;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
next_token(s);
|
||||||
|
valueOptional = token(s);
|
||||||
|
prev_token(s);
|
||||||
|
|
||||||
value = pack(s, ap);
|
value = pack(s, ap);
|
||||||
if(!value) {
|
if(!value) {
|
||||||
if(strchr("soO", token(s)) && s->next_token.token == '*') {
|
if(valueOptional != '*') {
|
||||||
next_token(s);
|
|
||||||
} else {
|
|
||||||
s->has_error = 1;
|
s->has_error = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,8 +328,6 @@ static json_t *pack_array(scanner_t *s, va_list *ap)
|
||||||
s->has_error = 1;
|
s->has_error = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(strchr("soO", token(s)) && s->next_token.token == '*')
|
|
||||||
next_token(s);
|
|
||||||
next_token(s);
|
next_token(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,23 +342,97 @@ error:
|
||||||
static json_t *pack_string(scanner_t *s, va_list *ap)
|
static json_t *pack_string(scanner_t *s, va_list *ap)
|
||||||
{
|
{
|
||||||
char *str;
|
char *str;
|
||||||
|
char t;
|
||||||
size_t len;
|
size_t len;
|
||||||
int ours;
|
int ours;
|
||||||
int nullable;
|
int optional;
|
||||||
|
|
||||||
next_token(s);
|
next_token(s);
|
||||||
nullable = token(s) == '?';
|
t = token(s);
|
||||||
if (!nullable)
|
optional = t == '?' || t == '*';
|
||||||
|
if (!optional)
|
||||||
prev_token(s);
|
prev_token(s);
|
||||||
|
|
||||||
str = read_string(s, ap, "string", &len, &ours);
|
str = read_string(s, ap, "string", &len, &ours, optional);
|
||||||
if (!str) {
|
|
||||||
return nullable ? json_null() : NULL;
|
if (!str)
|
||||||
} else if (ours) {
|
return t == '?' && !s->has_error ? json_null() : NULL;
|
||||||
return jsonp_stringn_nocheck_own(str, len);
|
|
||||||
} else {
|
if (s->has_error) {
|
||||||
return json_stringn_nocheck(str, len);
|
/* 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, "<args>", 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, "<internal>", 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, "<internal>", 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, "<args>", 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)
|
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();
|
return va_arg(*ap, int) ? json_true() : json_false();
|
||||||
|
|
||||||
case 'i': /* integer from int */
|
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 */
|
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 */
|
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 */
|
case 'O': /* a json_t object; increments refcount */
|
||||||
{
|
return pack_object_inter(s, ap, 1);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'o': /* a json_t object; doesn't increment refcount */
|
case 'o': /* a json_t object; doesn't increment refcount */
|
||||||
{
|
return pack_object_inter(s, ap, 0);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
set_error(s, "<format>", json_error_invalid_format, "Unexpected format character '%c'",
|
set_error(s, "<format>", 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) {
|
if(root && strict == 1) {
|
||||||
/* We need to check that all non optional items have been parsed */
|
/* We need to check that all non optional items have been parsed */
|
||||||
const char *key;
|
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;
|
strbuffer_t unrecognized_keys;
|
||||||
json_t *value;
|
json_t *value;
|
||||||
long unpacked = 0;
|
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) {
|
json_object_foreach(root, key, value) {
|
||||||
if(!hashtable_get(&key_set, key)) {
|
if(!hashtable_get(&key_set, key)) {
|
||||||
unpacked++;
|
unpacked++;
|
||||||
|
|
||||||
/* Save unrecognized keys for the error message */
|
/* Save unrecognized keys for the error message */
|
||||||
if (!have_unrecognized_keys) {
|
if (keys_res == 1) {
|
||||||
strbuffer_init(&unrecognized_keys);
|
keys_res = strbuffer_init(&unrecognized_keys);
|
||||||
have_unrecognized_keys = 1;
|
} else if (!keys_res) {
|
||||||
} else {
|
keys_res = strbuffer_append_bytes(&unrecognized_keys, ", ", 2);
|
||||||
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 (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, "<validation>", json_error_end_of_input_expected,
|
set_error(s, "<validation>", json_error_end_of_input_expected,
|
||||||
"%li object item(s) left unpacked: %s",
|
"%li object item(s) left unpacked: %s",
|
||||||
unpacked, strbuffer_value(&unrecognized_keys));
|
unpacked,
|
||||||
|
keys_res ? "<unknown>" : strbuffer_value(&unrecognized_keys));
|
||||||
strbuffer_close(&unrecognized_keys);
|
strbuffer_close(&unrecognized_keys);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -805,6 +851,7 @@ json_t *json_vpack_ex(json_error_t *error, size_t flags,
|
||||||
value = pack(&s, &ap_copy);
|
value = pack(&s, &ap_copy);
|
||||||
va_end(ap_copy);
|
va_end(ap_copy);
|
||||||
|
|
||||||
|
/* This will cover all situations where s.has_error is true */
|
||||||
if(!value)
|
if(!value)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -814,10 +861,6 @@ json_t *json_vpack_ex(json_error_t *error, size_t flags,
|
||||||
set_error(&s, "<format>", json_error_invalid_format, "Garbage after format string");
|
set_error(&s, "<format>", json_error_invalid_format, "Garbage after format string");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if(s.has_error) {
|
|
||||||
json_decref(value);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
#include <jansson.h>
|
#include <jansson.h>
|
||||||
#include "jansson_private.h"
|
#include "jansson_private.h"
|
||||||
|
|
||||||
|
|
||||||
json_t *json_path_get(const json_t *json, const char *path)
|
json_t *json_path_get(const json_t *json, const char *path)
|
||||||
{
|
{
|
||||||
static const char root_chr = '$', array_open = '[';
|
static const char root_chr = '$', array_open = '[';
|
||||||
|
|
|
@ -16,7 +16,7 @@ typedef struct {
|
||||||
size_t size; /* bytes allocated */
|
size_t size; /* bytes allocated */
|
||||||
} strbuffer_t;
|
} 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_close(strbuffer_t *strbuff);
|
||||||
|
|
||||||
void strbuffer_clear(strbuffer_t *strbuff);
|
void strbuffer_clear(strbuffer_t *strbuff);
|
||||||
|
|
|
@ -652,7 +652,6 @@ static json_t *string_create(const char *value, size_t len, int own)
|
||||||
|
|
||||||
string = jsonp_malloc(sizeof(json_string_t));
|
string = jsonp_malloc(sizeof(json_string_t));
|
||||||
if(!string) {
|
if(!string) {
|
||||||
if(!own)
|
|
||||||
jsonp_free(v);
|
jsonp_free(v);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -768,9 +767,6 @@ static int json_string_equal(const json_t *string1, const json_t *string2)
|
||||||
{
|
{
|
||||||
json_string_t *s1, *s2;
|
json_string_t *s1, *s2;
|
||||||
|
|
||||||
if(!json_is_string(string1) || !json_is_string(string2))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
s1 = json_to_string(string1);
|
s1 = json_to_string(string1);
|
||||||
s2 = json_to_string(string2);
|
s2 = json_to_string(string2);
|
||||||
return s1->length == s2->length && !memcmp(s1->value, s2->value, s1->length);
|
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;
|
json_string_t *s;
|
||||||
|
|
||||||
if(!json_is_string(string))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
s = json_to_string(string);
|
s = json_to_string(string);
|
||||||
return json_stringn_nocheck(s->value, s->length);
|
return json_stringn_nocheck(s->value, s->length);
|
||||||
}
|
}
|
||||||
|
|
||||||
json_t *json_vsprintf(const char *fmt, va_list ap) {
|
json_t *json_vsprintf(const char *fmt, va_list ap) {
|
||||||
|
json_t *json = NULL;
|
||||||
int length;
|
int length;
|
||||||
char *buf;
|
char *buf;
|
||||||
va_list aq;
|
va_list aq;
|
||||||
va_copy(aq, ap);
|
va_copy(aq, ap);
|
||||||
|
|
||||||
length = vsnprintf(NULL, 0, fmt, ap);
|
length = vsnprintf(NULL, 0, fmt, ap);
|
||||||
if (length == 0)
|
if (length == 0) {
|
||||||
return json_string("");
|
json = json_string("");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
buf = jsonp_malloc(length + 1);
|
buf = jsonp_malloc(length + 1);
|
||||||
if (!buf)
|
if (!buf)
|
||||||
return NULL;
|
goto out;
|
||||||
|
|
||||||
vsnprintf(buf, length + 1, fmt, aq);
|
vsnprintf(buf, length + 1, fmt, aq);
|
||||||
if (!utf8_check_string(buf, length)) {
|
if (!utf8_check_string(buf, length)) {
|
||||||
jsonp_free(buf);
|
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, ...) {
|
json_t *json_sprintf(const char *fmt, ...) {
|
||||||
|
@ -1044,8 +1044,6 @@ json_t *json_copy(json_t *json)
|
||||||
default:
|
default:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
json_t *json_deep_copy(const json_t *json)
|
json_t *json_deep_copy(const json_t *json)
|
||||||
|
@ -1073,6 +1071,4 @@ json_t *json_deep_copy(const json_t *json)
|
||||||
default:
|
default:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
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, MAX_PRINT_BUFFER - 20, 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);
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
@ -110,6 +111,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