mirror of
https://github.com/Proxmark/proxmark3.git
synced 2024-09-20 14:56:21 +08:00
Fido U2F complete (#716)
* add pkwrite * asn1print * asn1dump and CA * added PrintAndLogEx for merge commits between repo easier than now * changelog
This commit is contained in:
parent
e0991f6aa7
commit
6b882a3918
|
@ -6,6 +6,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
|||
|
||||
### Changed
|
||||
- Changed hf mfp security. Now it works in all the modes. (drHatson)
|
||||
- `hf fido` - show/check DER certificate and signatures (Merlok)
|
||||
|
||||
### Fixed
|
||||
|
||||
|
|
|
@ -109,8 +109,10 @@ CMDSRCS = $(SRC_SMARTCARD) \
|
|||
crapto1/crypto1.c\
|
||||
crypto/libpcrypto.c\
|
||||
crypto/asn1utils.c\
|
||||
crypto/asn1dump.c\
|
||||
cliparser/argtable3.c\
|
||||
cliparser/cliparser.c\
|
||||
fido/additional_ca.c \
|
||||
mfkey.c\
|
||||
loclass/cipher.c \
|
||||
loclass/cipherutils.c \
|
||||
|
|
|
@ -39,6 +39,12 @@
|
|||
#include "emv/emvjson.h"
|
||||
#include "emv/dump.h"
|
||||
#include "cliparser/cliparser.h"
|
||||
#include "crypto/asn1utils.h"
|
||||
#include "crypto/libpcrypto.h"
|
||||
#include "fido/additional_ca.h"
|
||||
#include "mbedtls/x509_crt.h"
|
||||
#include "mbedtls/x509.h"
|
||||
#include "mbedtls/pk.h"
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
|
@ -201,8 +207,9 @@ int CmdHFFidoRegister(const char *cmd) {
|
|||
void* argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("aA", "apdu", "show APDU reqests and responses"),
|
||||
arg_lit0("vV", "verbose", "show technical data"),
|
||||
arg_litn("vV", "verbose", 0, 2, "show technical data. vv - show full certificates data"),
|
||||
arg_lit0("pP", "plain", "send plain ASCII to challenge and application parameters instead of HEX"),
|
||||
arg_lit0("tT", "tlv", "Show DER certificate contents in TLV representation"),
|
||||
arg_str0("jJ", "json", "fido.json", "JSON input / output file name for parameters."),
|
||||
arg_str0(NULL, NULL, "<HEX/ASCII challenge 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 verbose = arg_get_lit(2);
|
||||
bool verbose2 = arg_get_lit(2) > 1;
|
||||
bool paramsPlain = arg_get_lit(3);
|
||||
bool showDERTLV = arg_get_lit(4);
|
||||
|
||||
char fname[250] = {0};
|
||||
bool err;
|
||||
root = OpenJson(4, fname, argtable, &err);
|
||||
root = OpenJson(5, fname, argtable, &err);
|
||||
if(err)
|
||||
return 1;
|
||||
if (root) {
|
||||
|
@ -227,13 +236,13 @@ int CmdHFFidoRegister(const char *cmd) {
|
|||
|
||||
if (paramsPlain) {
|
||||
memset(cdata, 0x00, 32);
|
||||
CLIGetStrWithReturn(5, cdata, &chlen);
|
||||
CLIGetStrWithReturn(6, cdata, &chlen);
|
||||
if (chlen && chlen > 16) {
|
||||
PrintAndLog("ERROR: challenge parameter length in ASCII mode must be less than 16 chars instead of: %d", chlen);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
CLIGetHexWithReturn(5, cdata, &chlen);
|
||||
CLIGetHexWithReturn(6, cdata, &chlen);
|
||||
if (chlen && chlen != 32) {
|
||||
PrintAndLog("ERROR: challenge parameter length must be 32 bytes only.");
|
||||
return 1;
|
||||
|
@ -245,13 +254,13 @@ int CmdHFFidoRegister(const char *cmd) {
|
|||
|
||||
if (paramsPlain) {
|
||||
memset(adata, 0x00, 32);
|
||||
CLIGetStrWithReturn(6, adata, &applen);
|
||||
CLIGetStrWithReturn(7, adata, &applen);
|
||||
if (applen && applen > 16) {
|
||||
PrintAndLog("ERROR: application parameter length in ASCII mode must be less than 16 chars instead of: %d", applen);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
CLIGetHexWithReturn(6, adata, &applen);
|
||||
CLIGetHexWithReturn(7, adata, &applen);
|
||||
if (applen && applen != 32) {
|
||||
PrintAndLog("ERROR: application parameter length must be 32 bytes only.");
|
||||
return 1;
|
||||
|
@ -302,7 +311,7 @@ int CmdHFFidoRegister(const char *cmd) {
|
|||
if (APDULogging)
|
||||
PrintAndLog("---------------------------------------------------------------");
|
||||
PrintAndLog("data len: %d", len);
|
||||
if (verbose) {
|
||||
if (verbose2) {
|
||||
PrintAndLog("--------------data----------------------");
|
||||
dump_buffer((const unsigned char *)buf, len, NULL, 0);
|
||||
PrintAndLog("--------------data----------------------");
|
||||
|
@ -319,20 +328,119 @@ int CmdHFFidoRegister(const char *cmd) {
|
|||
|
||||
int derp = 67 + keyHandleLen;
|
||||
int derLen = (buf[derp + 2] << 8) + buf[derp + 3] + 4;
|
||||
// needs to decode DER certificate
|
||||
if (verbose) {
|
||||
PrintAndLog("DER certificate[%d]:------------------DER-------------------", derLen);
|
||||
dump_buffer_simple((const unsigned char *)&buf[67 + keyHandleLen], derLen, NULL);
|
||||
if (verbose2) {
|
||||
PrintAndLog("DER certificate[%d]:\n------------------DER-------------------", derLen);
|
||||
dump_buffer_simple((const unsigned char *)&buf[derp], derLen, NULL);
|
||||
PrintAndLog("\n----------------DER---------------------");
|
||||
} else {
|
||||
if (verbose)
|
||||
PrintAndLog("------------------DER-------------------");
|
||||
PrintAndLog("DER certificate[%d]: %s...", derLen, sprint_hex(&buf[derp], 20));
|
||||
}
|
||||
|
||||
// check and print DER certificate
|
||||
uint8_t public_key[65] = {0};
|
||||
|
||||
// print DER certificate in TLV view
|
||||
if (showDERTLV) {
|
||||
PrintAndLog("----------------DER TLV-----------------");
|
||||
asn1_print(&buf[derp], derLen, " ");
|
||||
PrintAndLog("----------------DER TLV-----------------");
|
||||
}
|
||||
|
||||
// load CA's
|
||||
mbedtls_x509_crt cacert;
|
||||
mbedtls_x509_crt_init(&cacert);
|
||||
res = mbedtls_x509_crt_parse(&cacert, (const unsigned char *) additional_ca_pem, additional_ca_pem_len);
|
||||
if (res < 0) {
|
||||
PrintAndLog("ERROR: CA parse certificate returned -0x%x - %s", -res, ecdsa_get_error(res));
|
||||
}
|
||||
if (verbose)
|
||||
PrintAndLog("CA load OK. %d skipped", res);
|
||||
|
||||
// load DER certificate from authenticator's data
|
||||
mbedtls_x509_crt cert;
|
||||
mbedtls_x509_crt_init(&cert);
|
||||
res = mbedtls_x509_crt_parse_der(&cert, &buf[derp], derLen);
|
||||
if (res) {
|
||||
PrintAndLog("ERROR: DER parse returned 0x%x - %s", (res<0)?-res:res, ecdsa_get_error(res));
|
||||
}
|
||||
|
||||
// get certificate info
|
||||
char linfo[300] = {0};
|
||||
if (verbose) {
|
||||
mbedtls_x509_crt_info(linfo, sizeof(linfo), " ", &cert);
|
||||
PrintAndLog("DER certificate info:\n%s", linfo);
|
||||
}
|
||||
|
||||
// verify certificate
|
||||
uint32_t verifyflags = 0;
|
||||
res = mbedtls_x509_crt_verify(&cert, &cacert, NULL, NULL, &verifyflags, NULL, NULL);
|
||||
if (res) {
|
||||
PrintAndLog("ERROR: DER verify returned 0x%x - %s", (res<0)?-res:res, ecdsa_get_error(res));
|
||||
} else {
|
||||
PrintAndLog("Certificate OK.");
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
memset(linfo, 0x00, sizeof(linfo));
|
||||
mbedtls_x509_crt_verify_info(linfo, sizeof(linfo), " ", verifyflags);
|
||||
PrintAndLog("Verification info:\n%s", linfo);
|
||||
}
|
||||
|
||||
// get public key
|
||||
res = ecdsa_public_key_from_pk(&cert.pk, public_key, sizeof(public_key));
|
||||
if (res) {
|
||||
PrintAndLog("ERROR: getting public key from certificate 0x%x - %s", (res<0)?-res:res, ecdsa_get_error(res));
|
||||
} else {
|
||||
if (verbose)
|
||||
PrintAndLog("Got a public key from certificate:\n%s", sprint_hex_inrow(public_key, 65));
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
PrintAndLog("------------------DER-------------------");
|
||||
|
||||
mbedtls_x509_crt_free(&cert);
|
||||
mbedtls_x509_crt_free(&cacert);
|
||||
|
||||
// get hash
|
||||
int hashp = 1 + 65 + 1 + keyHandleLen + derLen;
|
||||
PrintAndLog("Hash[%d]: %s", len - hashp, sprint_hex(&buf[hashp], len - hashp));
|
||||
|
||||
// check ANSI X9.62 format ECDSA signature (on P-256)
|
||||
uint8_t rval[300] = {0};
|
||||
uint8_t sval[300] = {0};
|
||||
res = ecdsa_asn1_get_signature(&buf[hashp], len - hashp, rval, sval);
|
||||
if (!res) {
|
||||
if (verbose) {
|
||||
PrintAndLog(" r: %s", sprint_hex(rval, 32));
|
||||
PrintAndLog(" s: %s", sprint_hex(sval, 32));
|
||||
}
|
||||
|
||||
uint8_t xbuf[4096] = {0};
|
||||
size_t xbuflen = 0;
|
||||
res = FillBuffer(xbuf, sizeof(xbuf), &xbuflen,
|
||||
"\x00", 1,
|
||||
&data[32], 32, // application parameter
|
||||
&data[0], 32, // challenge parameter
|
||||
&buf[67], keyHandleLen, // keyHandle
|
||||
&buf[1], 65, // user public key
|
||||
NULL, 0);
|
||||
//PrintAndLog("--xbuf(%d)[%d]: %s", res, xbuflen, sprint_hex(xbuf, xbuflen));
|
||||
res = ecdsa_signature_verify(public_key, xbuf, xbuflen, &buf[hashp], len - hashp);
|
||||
if (res) {
|
||||
if (res == -0x4e00) {
|
||||
PrintAndLog("Signature is NOT VALID.");
|
||||
} else {
|
||||
PrintAndLog("Other signature check error: %x %s", (res<0)?-res:res, ecdsa_get_error(res));
|
||||
}
|
||||
} else {
|
||||
PrintAndLog("Signature is OK.");
|
||||
}
|
||||
|
||||
} else {
|
||||
PrintAndLog("Invalid signature. res=%d.", res);
|
||||
}
|
||||
|
||||
PrintAndLog("\nauth command: ");
|
||||
printf("hf fido auth %s%s", paramsPlain?"-p ":"", sprint_hex_inrow(&buf[67], keyHandleLen));
|
||||
|
@ -345,6 +453,7 @@ int CmdHFFidoRegister(const char *cmd) {
|
|||
if (root) {
|
||||
JsonSaveBufAsHex(root, "ChallengeParam", data, 32);
|
||||
JsonSaveBufAsHex(root, "ApplicationParam", &data[32], 32);
|
||||
JsonSaveBufAsHexCompact(root, "PublicKey", &buf[1], 65);
|
||||
JsonSaveInt(root, "KeyHandleLen", keyHandleLen);
|
||||
JsonSaveBufAsHexCompact(root, "KeyHandle", &buf[67], keyHandleLen);
|
||||
JsonSaveBufAsHexCompact(root, "DER", &buf[67 + keyHandleLen], derLen);
|
||||
|
@ -366,6 +475,8 @@ int CmdHFFidoRegister(const char *cmd) {
|
|||
int CmdHFFidoAuthenticate(const char *cmd) {
|
||||
uint8_t data[512] = {0};
|
||||
uint8_t hdata[250] = {0};
|
||||
bool public_key_loaded = false;
|
||||
uint8_t public_key[65] = {0};
|
||||
int hdatalen = 0;
|
||||
uint8_t keyHandleLen = 0;
|
||||
json_t *root = NULL;
|
||||
|
@ -385,6 +496,7 @@ int CmdHFFidoAuthenticate(const char *cmd) {
|
|||
arg_lit0("uU", "user", "mode: enforce-user-presence-and-sign"),
|
||||
arg_lit0("cC", "check", "mode: check-only"),
|
||||
arg_str0("jJ", "json", "fido.json", "JSON input / output file name for parameters."),
|
||||
arg_str0("kK", "key", "public key to verify signature", NULL),
|
||||
arg_str0(NULL, NULL, "<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 application parameter (32b HEX/1..16 chars)>", NULL),
|
||||
|
@ -393,7 +505,7 @@ int CmdHFFidoAuthenticate(const char *cmd) {
|
|||
CLIExecWithReturn(cmd, argtable, true);
|
||||
|
||||
bool APDULogging = arg_get_lit(1);
|
||||
//bool verbose = arg_get_lit(2);
|
||||
bool verbose = arg_get_lit(2);
|
||||
bool paramsPlain = arg_get_lit(3);
|
||||
uint8_t controlByte = 0x08;
|
||||
if (arg_get_lit(5))
|
||||
|
@ -413,9 +525,22 @@ int CmdHFFidoAuthenticate(const char *cmd) {
|
|||
JsonLoadBufAsHex(root, "$.KeyHandle", &data[65], 512 - 67, &jlen);
|
||||
keyHandleLen = jlen & 0xff;
|
||||
data[64] = keyHandleLen;
|
||||
JsonLoadBufAsHex(root, "$.PublicKey", public_key, 65, &jlen);
|
||||
public_key_loaded = (jlen > 0);
|
||||
}
|
||||
|
||||
// public key
|
||||
CLIGetHexWithReturn(8, hdata, &hdatalen);
|
||||
if (hdatalen && hdatalen != 130) {
|
||||
PrintAndLog("ERROR: public key length must be 65 bytes only.");
|
||||
return 1;
|
||||
}
|
||||
if (hdatalen) {
|
||||
memmove(public_key, hdata, hdatalen);
|
||||
public_key_loaded = true;
|
||||
}
|
||||
|
||||
CLIGetHexWithReturn(9, hdata, &hdatalen);
|
||||
if (hdatalen > 255) {
|
||||
PrintAndLog("ERROR: application parameter length must be less than 255.");
|
||||
return 1;
|
||||
|
@ -434,7 +559,7 @@ int CmdHFFidoAuthenticate(const char *cmd) {
|
|||
return 1;
|
||||
}
|
||||
} else {
|
||||
CLIGetHexWithReturn(9, hdata, &hdatalen);
|
||||
CLIGetHexWithReturn(10, hdata, &hdatalen);
|
||||
if (hdatalen && hdatalen != 32) {
|
||||
PrintAndLog("ERROR: challenge parameter length must be 32 bytes only.");
|
||||
return 1;
|
||||
|
@ -445,7 +570,7 @@ int CmdHFFidoAuthenticate(const char *cmd) {
|
|||
|
||||
if (paramsPlain) {
|
||||
memset(hdata, 0x00, 32);
|
||||
CLIGetStrWithReturn(10, hdata, &hdatalen);
|
||||
CLIGetStrWithReturn(11, hdata, &hdatalen);
|
||||
if (hdatalen && hdatalen > 16) {
|
||||
PrintAndLog("ERROR: application parameter length in ASCII mode must be less than 16 chars instead of: %d", hdatalen);
|
||||
return 1;
|
||||
|
@ -509,6 +634,42 @@ int CmdHFFidoAuthenticate(const char *cmd) {
|
|||
PrintAndLog("Counter: %d", cntr);
|
||||
PrintAndLog("Hash[%d]: %s", len - 5, sprint_hex(&buf[5], len - 5));
|
||||
|
||||
// check ANSI X9.62 format ECDSA signature (on P-256)
|
||||
uint8_t rval[300] = {0};
|
||||
uint8_t sval[300] = {0};
|
||||
res = ecdsa_asn1_get_signature(&buf[5], len - 5, rval, sval);
|
||||
if (!res) {
|
||||
if (verbose) {
|
||||
PrintAndLog(" r: %s", sprint_hex(rval, 32));
|
||||
PrintAndLog(" s: %s", sprint_hex(sval, 32));
|
||||
}
|
||||
if (public_key_loaded) {
|
||||
uint8_t xbuf[4096] = {0};
|
||||
size_t xbuflen = 0;
|
||||
res = FillBuffer(xbuf, sizeof(xbuf), &xbuflen,
|
||||
&data[32], 32, // application parameter
|
||||
&buf[0], 1, // user presence
|
||||
&buf[1], 4, // counter
|
||||
data, 32, // challenge parameter
|
||||
NULL, 0);
|
||||
//PrintAndLog("--xbuf(%d)[%d]: %s", res, xbuflen, sprint_hex(xbuf, xbuflen));
|
||||
res = ecdsa_signature_verify(public_key, xbuf, xbuflen, &buf[5], len - 5);
|
||||
if (res) {
|
||||
if (res == -0x4e00) {
|
||||
PrintAndLog("Signature is NOT VALID.");
|
||||
} else {
|
||||
PrintAndLog("Other signature check error: %x %s", (res<0)?-res:res, ecdsa_get_error(res));
|
||||
}
|
||||
} else {
|
||||
PrintAndLog("Signature is OK.");
|
||||
}
|
||||
} else {
|
||||
PrintAndLog("No public key provided. can't check signature.");
|
||||
}
|
||||
} else {
|
||||
PrintAndLog("Invalid signature. res=%d.", res);
|
||||
}
|
||||
|
||||
if (root) {
|
||||
JsonSaveBufAsHex(root, "ChallengeParam", data, 32);
|
||||
JsonSaveBufAsHex(root, "ApplicationParam", &data[32], 32);
|
||||
|
|
353
client/crypto/asn1dump.c
Normal file
353
client/crypto/asn1dump.c
Normal file
|
@ -0,0 +1,353 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2018 Merlok
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// asn.1 dumping
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "asn1dump.h"
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <jansson.h>
|
||||
#include <mbedtls/asn1.h>
|
||||
#include <mbedtls/oid.h>
|
||||
#include "emv/emv_tags.h"
|
||||
#include "emv/dump.h"
|
||||
#include "emv/emvjson.h"
|
||||
#include "util.h"
|
||||
#include "proxmark3.h"
|
||||
|
||||
#define PRINT_INDENT(level) {for (int i = 0; i < (level); i++) fprintf(f, " ");}
|
||||
|
||||
enum asn1_tag_t {
|
||||
ASN1_TAG_GENERIC,
|
||||
ASN1_TAG_BOOLEAN,
|
||||
ASN1_TAG_INTEGER,
|
||||
ASN1_TAG_STRING,
|
||||
ASN1_TAG_OCTET_STRING,
|
||||
ASN1_TAG_UTC_TIME,
|
||||
ASN1_TAG_STR_TIME,
|
||||
ASN1_TAG_OBJECT_ID,
|
||||
};
|
||||
|
||||
struct asn1_tag {
|
||||
tlv_tag_t tag;
|
||||
char *name;
|
||||
enum asn1_tag_t type;
|
||||
const void *data;
|
||||
};
|
||||
|
||||
static const struct asn1_tag asn1_tags[] = {
|
||||
// internal
|
||||
{ 0x00 , "Unknown ???" },
|
||||
|
||||
// ASN.1
|
||||
{ 0x01, "BOOLEAN", ASN1_TAG_BOOLEAN },
|
||||
{ 0x02, "INTEGER", ASN1_TAG_INTEGER },
|
||||
{ 0x03, "BIT STRING" },
|
||||
{ 0x04, "OCTET STRING", ASN1_TAG_OCTET_STRING},
|
||||
{ 0x05, "NULL" },
|
||||
{ 0x06, "OBJECT IDENTIFIER", ASN1_TAG_OBJECT_ID },
|
||||
{ 0x07, "OBJECT DESCRIPTOR" },
|
||||
{ 0x08, "EXTERNAL" },
|
||||
{ 0x09, "REAL" },
|
||||
{ 0x0A, "ENUMERATED" },
|
||||
{ 0x0B, "EMBEDDED_PDV" },
|
||||
{ 0x0C, "UTF8String", ASN1_TAG_STRING },
|
||||
{ 0x10, "SEQUENCE" },
|
||||
{ 0x11, "SET" },
|
||||
{ 0x12, "NumericString", ASN1_TAG_STRING },
|
||||
{ 0x13, "PrintableString", ASN1_TAG_STRING },
|
||||
{ 0x14, "T61String" },
|
||||
{ 0x15, "VideotexString" },
|
||||
{ 0x16, "IA5String" },
|
||||
{ 0x17, "UTCTime", ASN1_TAG_UTC_TIME },
|
||||
{ 0x18, "GeneralizedTime", ASN1_TAG_STR_TIME },
|
||||
{ 0x19, "GraphicString" },
|
||||
{ 0x1A, "VisibleString", ASN1_TAG_STRING },
|
||||
{ 0x1B, "GeneralString", ASN1_TAG_STRING },
|
||||
{ 0x1C, "UniversalString", ASN1_TAG_STRING },
|
||||
{ 0x1E, "BMPString" },
|
||||
{ 0x30, "SEQUENCE" },
|
||||
{ 0x31, "SET" },
|
||||
{ 0xa0, "[0]" },
|
||||
{ 0xa1, "[1]" },
|
||||
{ 0xa2, "[2]" },
|
||||
{ 0xa3, "[3]" },
|
||||
{ 0xa4, "[4]" },
|
||||
{ 0xa5, "[5]" },
|
||||
};
|
||||
|
||||
static int asn1_sort_tag(tlv_tag_t tag) {
|
||||
return (int)(tag >= 0x100 ? tag : tag << 8);
|
||||
}
|
||||
|
||||
static int asn1_tlv_compare(const void *a, const void *b) {
|
||||
const struct tlv *tlv = a;
|
||||
const struct asn1_tag *tag = b;
|
||||
|
||||
return asn1_sort_tag(tlv->tag) - (asn1_sort_tag(tag->tag));
|
||||
}
|
||||
|
||||
static const struct asn1_tag *asn1_get_tag(const struct tlv *tlv) {
|
||||
struct asn1_tag *tag = bsearch(tlv, asn1_tags, sizeof(asn1_tags) / sizeof(asn1_tags[0]),
|
||||
sizeof(asn1_tags[0]), asn1_tlv_compare);
|
||||
|
||||
return tag ? tag : &asn1_tags[0];
|
||||
}
|
||||
|
||||
static void asn1_tag_dump_str_time(const struct tlv *tlv, const struct asn1_tag *tag, FILE *f, int level, bool longyear, bool *needdump){
|
||||
int len = tlv->len;
|
||||
*needdump = false;
|
||||
|
||||
int startindx = longyear ? 4 : 2;
|
||||
|
||||
if (len > 4) {
|
||||
fprintf(f, "\tvalue: '");
|
||||
while (true) {
|
||||
// year
|
||||
if (!longyear)
|
||||
fprintf(f, "20");
|
||||
fwrite(tlv->value, 1, longyear ? 4 : 2, f);
|
||||
fprintf(f, "-");
|
||||
if (len < startindx + 2)
|
||||
break;
|
||||
// month
|
||||
fwrite(&tlv->value[startindx], 1, 2, f);
|
||||
fprintf(f, "-");
|
||||
if (len < startindx + 4)
|
||||
break;
|
||||
// day
|
||||
fwrite(&tlv->value[startindx + 2], 1, 2, f);
|
||||
fprintf(f, " ");
|
||||
if (len < startindx + 6)
|
||||
break;
|
||||
// hour
|
||||
fwrite(&tlv->value[startindx + 4], 1, 2, f);
|
||||
fprintf(f, ":");
|
||||
if (len < startindx + 8)
|
||||
break;
|
||||
// min
|
||||
fwrite(&tlv->value[startindx + 6], 1, 2, f);
|
||||
fprintf(f, ":");
|
||||
if (len < startindx + 10)
|
||||
break;
|
||||
// sec
|
||||
fwrite(&tlv->value[startindx + 8], 1, 2, f);
|
||||
if (len < startindx + 11)
|
||||
break;
|
||||
// time zone
|
||||
fprintf(f, " zone: %.*s", len - 10 - (longyear ? 4 : 2), &tlv->value[startindx + 10]);
|
||||
|
||||
break;
|
||||
}
|
||||
fprintf(f, "'\n");
|
||||
} else {
|
||||
fprintf(f, "\n");
|
||||
*needdump = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void asn1_tag_dump_string(const struct tlv *tlv, const struct asn1_tag *tag, FILE *f, int level){
|
||||
fprintf(f, "\tvalue: '");
|
||||
fwrite(tlv->value, 1, tlv->len, f);
|
||||
fprintf(f, "'\n");
|
||||
}
|
||||
|
||||
static void asn1_tag_dump_octet_string(const struct tlv *tlv, const struct asn1_tag *tag, FILE *f, int level, bool *needdump){
|
||||
*needdump = false;
|
||||
for (int i = 0; i < tlv->len; i++)
|
||||
if (!isspace(tlv->value[i]) && !isprint(tlv->value[i])){
|
||||
*needdump = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (*needdump) {
|
||||
fprintf(f, "'\n");
|
||||
} else {
|
||||
fprintf(f, "\t\t");
|
||||
asn1_tag_dump_string(tlv, tag, f, level);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned long asn1_value_integer(const struct tlv *tlv, unsigned start, unsigned end) {
|
||||
unsigned long ret = 0;
|
||||
int i;
|
||||
|
||||
if (end > tlv->len * 2)
|
||||
return ret;
|
||||
if (start >= end)
|
||||
return ret;
|
||||
|
||||
if (start & 1) {
|
||||
ret += tlv->value[start/2] & 0xf;
|
||||
i = start + 1;
|
||||
} else
|
||||
i = start;
|
||||
|
||||
for (; i < end - 1; i += 2) {
|
||||
ret *= 10;
|
||||
ret += tlv->value[i/2] >> 4;
|
||||
ret *= 10;
|
||||
ret += tlv->value[i/2] & 0xf;
|
||||
}
|
||||
|
||||
if (end & 1) {
|
||||
ret *= 10;
|
||||
ret += tlv->value[end/2] >> 4;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void asn1_tag_dump_boolean(const struct tlv *tlv, const struct asn1_tag *tag, FILE *f, int level) {
|
||||
PRINT_INDENT(level);
|
||||
if (tlv->len > 0) {
|
||||
fprintf(f, "\tvalue: %s\n", tlv->value[0]?"true":"false");
|
||||
} else {
|
||||
fprintf(f, "n/a\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void asn1_tag_dump_integer(const struct tlv *tlv, const struct asn1_tag *tag, FILE *f, int level) {
|
||||
PRINT_INDENT(level);
|
||||
if (tlv->len == 4) {
|
||||
int32_t val = 0;
|
||||
for (int i = 0; i < tlv->len; i++)
|
||||
val = (val << 8) + tlv->value[i];
|
||||
fprintf(f, "\tvalue4b: %d\n", val);
|
||||
return;
|
||||
}
|
||||
fprintf(f, "\tvalue: %lu\n", asn1_value_integer(tlv, 0, tlv->len * 2));
|
||||
}
|
||||
|
||||
static char *asn1_oid_description(const char *oid, bool with_group_desc) {
|
||||
json_error_t error;
|
||||
json_t *root = NULL;
|
||||
char fname[300] = {0};
|
||||
static char res[300];
|
||||
memset(res, 0x00, sizeof(res));
|
||||
|
||||
strcpy(fname, get_my_executable_directory());
|
||||
strcat(fname, "crypto/oids.json");
|
||||
if (access(fname, F_OK) < 0) {
|
||||
strcpy(fname, get_my_executable_directory());
|
||||
strcat(fname, "oids.json");
|
||||
if (access(fname, F_OK) < 0) {
|
||||
goto error; // file not found
|
||||
}
|
||||
}
|
||||
|
||||
// load `oids.json`
|
||||
root = json_load_file(fname, 0, &error);
|
||||
|
||||
if (!root || !json_is_object(root)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
json_t *elm = json_object_get(root, oid);
|
||||
if (!elm) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (JsonLoadStr(elm, "$.d", res))
|
||||
goto error;
|
||||
|
||||
char strext[300] = {0};
|
||||
if (!JsonLoadStr(elm, "$.c", strext)) {
|
||||
strcat(res, " (");
|
||||
strcat(res, strext);
|
||||
strcat(res, ")");
|
||||
}
|
||||
|
||||
json_decref(root);
|
||||
return res;
|
||||
|
||||
error:
|
||||
if (root)
|
||||
json_decref(root);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void asn1_tag_dump_object_id(const struct tlv *tlv, const struct asn1_tag *tag, FILE *f, int level) {
|
||||
PRINT_INDENT(level);
|
||||
mbedtls_asn1_buf asn1_buf;
|
||||
asn1_buf.len = tlv->len;
|
||||
asn1_buf.p = (uint8_t *)tlv->value;
|
||||
char pstr[300];
|
||||
mbedtls_oid_get_numeric_string(pstr, sizeof(pstr), &asn1_buf);
|
||||
fprintf(f, " %s", pstr);
|
||||
|
||||
char *jsondesc = asn1_oid_description(pstr, true);
|
||||
if (jsondesc) {
|
||||
fprintf(f, " - %s", jsondesc);
|
||||
} else {
|
||||
const char *ppstr;
|
||||
mbedtls_oid_get_attr_short_name(&asn1_buf, &ppstr);
|
||||
if (ppstr && strnlen(ppstr, 1)) {
|
||||
fprintf(f, " (%s)\n", ppstr);
|
||||
return;
|
||||
}
|
||||
mbedtls_oid_get_sig_alg_desc(&asn1_buf, &ppstr);
|
||||
if (ppstr && strnlen(ppstr, 1)) {
|
||||
fprintf(f, " (%s)\n", ppstr);
|
||||
return;
|
||||
}
|
||||
mbedtls_oid_get_extended_key_usage(&asn1_buf, &ppstr);
|
||||
if (ppstr && strnlen(ppstr, 1)) {
|
||||
fprintf(f, " (%s)\n", ppstr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
||||
bool asn1_tag_dump(const struct tlv *tlv, FILE *f, int level, bool *candump) {
|
||||
if (!tlv) {
|
||||
fprintf(f, "NULL\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
const struct asn1_tag *tag = asn1_get_tag(tlv);
|
||||
|
||||
PRINT_INDENT(level);
|
||||
fprintf(f, "--%2hx[%02zx] '%s':", tlv->tag, tlv->len, tag->name);
|
||||
|
||||
switch (tag->type) {
|
||||
case ASN1_TAG_GENERIC:
|
||||
fprintf(f, "\n");
|
||||
break;
|
||||
case ASN1_TAG_STRING:
|
||||
asn1_tag_dump_string(tlv, tag, f, level);
|
||||
*candump = false;
|
||||
break;
|
||||
case ASN1_TAG_OCTET_STRING:
|
||||
asn1_tag_dump_octet_string(tlv, tag, f, level, candump);
|
||||
break;
|
||||
case ASN1_TAG_BOOLEAN:
|
||||
asn1_tag_dump_boolean(tlv, tag, f, level);
|
||||
*candump = false;
|
||||
break;
|
||||
case ASN1_TAG_INTEGER:
|
||||
asn1_tag_dump_integer(tlv, tag, f, level);
|
||||
*candump = false;
|
||||
break;
|
||||
case ASN1_TAG_UTC_TIME:
|
||||
asn1_tag_dump_str_time(tlv, tag, f, level, false, candump);
|
||||
break;
|
||||
case ASN1_TAG_STR_TIME:
|
||||
asn1_tag_dump_str_time(tlv, tag, f, level, true, candump);
|
||||
break;
|
||||
case ASN1_TAG_OBJECT_ID:
|
||||
asn1_tag_dump_object_id(tlv, tag, f, level);
|
||||
*candump = false;
|
||||
break;
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
21
client/crypto/asn1dump.h
Normal file
21
client/crypto/asn1dump.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2018 Merlok
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// asn.1 dumping
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef ASN1DUMP_H
|
||||
#define ASN1DUMP_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include "emv/tlv.h"
|
||||
|
||||
extern bool asn1_tag_dump(const struct tlv *tlv, FILE *f, int level, bool *candump);
|
||||
|
||||
#endif /* asn1utils.h */
|
|
@ -9,7 +9,14 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "asn1utils.h"
|
||||
#include <ctype.h>
|
||||
#include <stdlib.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) {
|
||||
if (!signature || !signaturelen || !rval || !sval)
|
||||
|
@ -55,7 +62,27 @@ exit:
|
|||
return res;
|
||||
}
|
||||
|
||||
int asn1_print(uint8_t *asn1buf, int level) {
|
||||
static bool print_cb(void *data, const struct tlv *tlv, int level, bool is_leaf) {
|
||||
bool candump = true;
|
||||
asn1_tag_dump(tlv, stdout, level, &candump);
|
||||
if (is_leaf && candump) {
|
||||
dump_buffer(tlv->value, tlv->len, stdout, level);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int asn1_print(uint8_t *asn1buf, size_t asn1buflen, char *indent) {
|
||||
|
||||
struct tlvdb *t = NULL;
|
||||
t = tlvdb_parse_multi(asn1buf, asn1buflen);
|
||||
if (t) {
|
||||
tlvdb_visit(t, print_cb, NULL, 0);
|
||||
tlvdb_free(t);
|
||||
} else {
|
||||
PrintAndLogEx(ERR, "Can't parse data as TLV tree.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include <stdbool.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);
|
||||
|
||||
#endif /* asn1utils.h */
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <mbedtls/asn1.h>
|
||||
#include <mbedtls/aes.h>
|
||||
#include <mbedtls/cmac.h>
|
||||
#include <mbedtls/pk.h>
|
||||
#include <mbedtls/ecdsa.h>
|
||||
#include <mbedtls/sha256.h>
|
||||
#include <mbedtls/ctr_drbg.h>
|
||||
|
@ -208,6 +209,31 @@ char *ecdsa_get_error(int ret) {
|
|||
return retstr;
|
||||
}
|
||||
|
||||
int ecdsa_public_key_from_pk(mbedtls_pk_context *pk, uint8_t *key, size_t keylen) {
|
||||
int res = 0;
|
||||
size_t realkeylen = 0;
|
||||
if (keylen < 65)
|
||||
return 1;
|
||||
|
||||
mbedtls_ecdsa_context ctx;
|
||||
mbedtls_ecdsa_init(&ctx);
|
||||
|
||||
res = mbedtls_ecp_group_load(&ctx.grp, MBEDTLS_ECP_DP_SECP256R1); // secp256r1
|
||||
if (res)
|
||||
goto exit;
|
||||
|
||||
res = mbedtls_ecdsa_from_keypair(&ctx, mbedtls_pk_ec(*pk) );
|
||||
if (res)
|
||||
goto exit;
|
||||
|
||||
res = mbedtls_ecp_point_write_binary(&ctx.grp, &ctx.Q, MBEDTLS_ECP_PF_UNCOMPRESSED, &realkeylen, key, keylen);
|
||||
if (realkeylen != 65)
|
||||
res = 2;
|
||||
exit:
|
||||
mbedtls_ecdsa_free(&ctx);
|
||||
return res;
|
||||
}
|
||||
|
||||
int ecdsa_signature_create(uint8_t *key_d, uint8_t *key_xy, uint8_t *input, int length, uint8_t *signature, size_t *signaturelen) {
|
||||
int res;
|
||||
*signaturelen = 0;
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <stdint.h>
|
||||
#include <stdbool.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_decode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length);
|
||||
|
@ -23,6 +24,7 @@ extern int aes_cmac8(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, in
|
|||
extern int sha256hash(uint8_t *input, int length, uint8_t *hash);
|
||||
|
||||
extern int ecdsa_key_create(uint8_t * key_d, uint8_t *key_xy);
|
||||
extern int ecdsa_public_key_from_pk(mbedtls_pk_context *pk, uint8_t *key, size_t keylen);
|
||||
extern int ecdsa_signature_create(uint8_t *key_d, uint8_t *key_xy, uint8_t *input, int length, uint8_t *signature, size_t *signaturelen);
|
||||
extern int ecdsa_signature_verify(uint8_t *key_xy, uint8_t *input, int length, uint8_t *signature, size_t signaturelen);
|
||||
extern char *ecdsa_get_error(int ret);
|
||||
|
|
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;
|
||||
}
|
||||
|
||||
int JsonLoadStr(json_t *root, char *path, char *value) {
|
||||
if (!value)
|
||||
return 1;
|
||||
|
||||
json_t *jelm = json_path_get((const json_t *)root, path);
|
||||
if (!jelm || !json_is_string(jelm))
|
||||
return 2;
|
||||
|
||||
const char * strval = json_string_value(jelm);
|
||||
if (!strval)
|
||||
return 1;
|
||||
|
||||
memcpy(value, strval, strlen(strval));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int JsonLoadBufAsHex(json_t *elm, char *path, uint8_t *data, size_t maxbufferlen, size_t *datalen) {
|
||||
if (datalen)
|
||||
*datalen = 0;
|
||||
|
|
|
@ -33,6 +33,7 @@ extern int JsonSaveTLVTreeElm(json_t *elm, char *path, struct tlvdb *tlvdbelm, b
|
|||
|
||||
extern int JsonSaveTLVTree(json_t *root, json_t *elm, char *path, struct tlvdb *tlvdbelm);
|
||||
|
||||
extern int JsonLoadStr(json_t *root, char *path, char *value);
|
||||
extern int JsonLoadBufAsHex(json_t *elm, char *path, uint8_t *data, size_t maxbufferlen, size_t *datalen);
|
||||
|
||||
extern bool ParamLoadFromJson(struct tlvdb *tlv);
|
||||
|
|
63
client/fido/additional_ca.c
Normal file
63
client/fido/additional_ca.c
Normal file
|
@ -0,0 +1,63 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2018 Merlok
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// CA PEM certificates
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
#include "additional_ca.h"
|
||||
#include "mbedtls/certs.h"
|
||||
|
||||
#define GLOBALSIGN_CA \
|
||||
"-----BEGIN CERTIFICATE-----\r\n" \
|
||||
"MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG\r\n" \
|
||||
"A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv\r\n" \
|
||||
"b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw\r\n" \
|
||||
"MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i\r\n" \
|
||||
"YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT\r\n" \
|
||||
"aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ\r\n" \
|
||||
"jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp\r\n" \
|
||||
"xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp\r\n" \
|
||||
"1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG\r\n" \
|
||||
"snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ\r\n" \
|
||||
"U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8\r\n" \
|
||||
"9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E\r\n" \
|
||||
"BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B\r\n" \
|
||||
"AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz\r\n" \
|
||||
"yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE\r\n" \
|
||||
"38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP\r\n" \
|
||||
"AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad\r\n" \
|
||||
"DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME\r\n" \
|
||||
"HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\r\n" \
|
||||
"-----END CERTIFICATE-----\r\n"
|
||||
|
||||
// Name: Yubico U2F Root CA Serial 457200631
|
||||
// Issued: 2014-08-01
|
||||
#define YUBICO_CA \
|
||||
"-----BEGIN CERTIFICATE-----\r\n" \
|
||||
"MIIDHjCCAgagAwIBAgIEG0BT9zANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNZ\r\n" \
|
||||
"dWJpY28gVTJGIFJvb3QgQ0EgU2VyaWFsIDQ1NzIwMDYzMTAgFw0xNDA4MDEwMDAw\r\n" \
|
||||
"MDBaGA8yMDUwMDkwNDAwMDAwMFowLjEsMCoGA1UEAxMjWXViaWNvIFUyRiBSb290\r\n" \
|
||||
"IENBIFNlcmlhbCA0NTcyMDA2MzEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\r\n" \
|
||||
"AoIBAQC/jwYuhBVlqaiYWEMsrWFisgJ+PtM91eSrpI4TK7U53mwCIawSDHy8vUmk\r\n" \
|
||||
"5N2KAj9abvT9NP5SMS1hQi3usxoYGonXQgfO6ZXyUA9a+KAkqdFnBnlyugSeCOep\r\n" \
|
||||
"8EdZFfsaRFtMjkwz5Gcz2Py4vIYvCdMHPtwaz0bVuzneueIEz6TnQjE63Rdt2zbw\r\n" \
|
||||
"nebwTG5ZybeWSwbzy+BJ34ZHcUhPAY89yJQXuE0IzMZFcEBbPNRbWECRKgjq//qT\r\n" \
|
||||
"9nmDOFVlSRCt2wiqPSzluwn+v+suQEBsUjTGMEd25tKXXTkNW21wIWbxeSyUoTXw\r\n" \
|
||||
"LvGS6xlwQSgNpk2qXYwf8iXg7VWZAgMBAAGjQjBAMB0GA1UdDgQWBBQgIvz0bNGJ\r\n" \
|
||||
"hjgpToksyKpP9xv9oDAPBgNVHRMECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAN\r\n" \
|
||||
"BgkqhkiG9w0BAQsFAAOCAQEAjvjuOMDSa+JXFCLyBKsycXtBVZsJ4Ue3LbaEsPY4\r\n" \
|
||||
"MYN/hIQ5ZM5p7EjfcnMG4CtYkNsfNHc0AhBLdq45rnT87q/6O3vUEtNMafbhU6kt\r\n" \
|
||||
"hX7Y+9XFN9NpmYxr+ekVY5xOxi8h9JDIgoMP4VB1uS0aunL1IGqrNooL9mmFnL2k\r\n" \
|
||||
"LVVee6/VR6C5+KSTCMCWppMuJIZII2v9o4dkoZ8Y7QRjQlLfYzd3qGtKbw7xaF1U\r\n" \
|
||||
"sG/5xUb/Btwb2X2g4InpiB/yt/3CpQXpiWX/K4mBvUKiGn05ZsqeY1gx4g0xLBqc\r\n" \
|
||||
"U9psmyPzK+Vsgw2jeRQ5JlKDyqE0hebfC1tvFu0CCrJFcw==\r\n" \
|
||||
"-----END CERTIFICATE-----\r\n"
|
||||
|
||||
/* Concatenation of all additional CA certificates in PEM format if available */
|
||||
const char additional_ca_pem[] = GLOBALSIGN_CA YUBICO_CA;
|
||||
const size_t additional_ca_pem_len = sizeof(additional_ca_pem);
|
21
client/fido/additional_ca.h
Normal file
21
client/fido/additional_ca.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2018 Merlok
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// CA PEM certificates
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
#ifndef __ADDITIONAL_CA_H__
|
||||
#define __ADDITIONAL_CA_H__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
// Concatenation of all CA certificates in PEM format if available
|
||||
extern const char additional_ca_pem[];
|
||||
extern const size_t additional_ca_pem_len;
|
||||
|
||||
#endif /* __ADDITIONAL_CA_H__ */
|
0
client/obj/fido/.dummy
Normal file
0
client/obj/fido/.dummy
Normal file
72
client/ui.c
72
client/ui.c
|
@ -16,6 +16,7 @@
|
|||
#include <stdarg.h>
|
||||
#include <readline/readline.h>
|
||||
#include <pthread.h>
|
||||
#include "util.h"
|
||||
#endif
|
||||
|
||||
#include "ui.h"
|
||||
|
@ -32,6 +33,77 @@ static char *logfilename = "proxmark3.log";
|
|||
#ifndef EXTERNAL_PRINTANDLOG
|
||||
static pthread_mutex_t print_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
void PrintAndLogEx(logLevel_t level, char *fmt, ...) {
|
||||
|
||||
// skip debug messages if client debugging is turned off i.e. 'DATA SETDEBUG 0'
|
||||
// if (g_debugMode == 0 && level == DEBUG)
|
||||
// return;
|
||||
|
||||
char buffer[MAX_PRINT_BUFFER] = {0};
|
||||
char buffer2[MAX_PRINT_BUFFER] = {0};
|
||||
char prefix[20] = {0};
|
||||
char *token = NULL;
|
||||
int size = 0;
|
||||
// {NORMAL, SUCCESS, INFO, FAILED, WARNING, ERR, DEBUG}
|
||||
static char *prefixes[7] = { "", "", "INFO: ", "FAILED: ", "WARNING: ", "ERROR: ", "#: "};
|
||||
|
||||
switch( level ) {
|
||||
case FAILED:
|
||||
strncpy(prefix,_RED_(FAILED: ), sizeof(prefix)-1);
|
||||
break;
|
||||
case DEBUG:
|
||||
strncpy(prefix,_BLUE_(#: ), sizeof(prefix)-1);
|
||||
break;
|
||||
case SUCCESS:
|
||||
strncpy(prefix,_GREEN_( ), sizeof(prefix)-1);
|
||||
break;
|
||||
case WARNING:
|
||||
strncpy(prefix,_CYAN_(WARNING: ), sizeof(prefix)-1);
|
||||
break;
|
||||
default:
|
||||
strncpy(prefix, prefixes[level], sizeof(prefix)-1);
|
||||
break;
|
||||
}
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buffer, sizeof(buffer), fmt, args);
|
||||
va_end(args);
|
||||
|
||||
// no prefixes for normal
|
||||
if ( level == NORMAL ) {
|
||||
PrintAndLog(buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
if (strchr(buffer, '\n')) {
|
||||
|
||||
const char delim[2] = "\n";
|
||||
|
||||
// line starts with newline
|
||||
if (buffer[0] == '\n')
|
||||
PrintAndLog("");
|
||||
|
||||
token = strtok(buffer, delim);
|
||||
|
||||
while (token != NULL) {
|
||||
|
||||
size = strlen(buffer2);
|
||||
|
||||
if (strlen(token))
|
||||
snprintf(buffer2+size, sizeof(buffer2)-size, "%s%s\n", prefix, token);
|
||||
else
|
||||
snprintf(buffer2+size, sizeof(buffer2)-size, "\n");
|
||||
|
||||
token = strtok(NULL, delim);
|
||||
}
|
||||
PrintAndLog(buffer2);
|
||||
} else {
|
||||
snprintf(buffer2, sizeof(buffer2), "%s%s", prefix, buffer);
|
||||
PrintAndLog(buffer2);
|
||||
}
|
||||
}
|
||||
|
||||
void PrintAndLog(char *fmt, ...)
|
||||
{
|
||||
char *saved_line;
|
||||
|
|
|
@ -14,11 +14,15 @@
|
|||
#include <stdbool.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 HideGraphWindow(void);
|
||||
void ShowGraphWindow(void);
|
||||
void RepaintGraphWindow(void);
|
||||
void PrintAndLog(char *fmt, ...);
|
||||
void PrintAndLogEx(logLevel_t level, char *fmt, ...);
|
||||
void SetLogFilename(char *fn);
|
||||
void SetFlushAfterWrite(bool flush_after_write);
|
||||
|
||||
|
|
|
@ -110,6 +110,35 @@ void FillFileNameByUID(char *fileName, uint8_t * uid, char *ext, int byteCount)
|
|||
sprintf(fnameptr, "%s", ext);
|
||||
}
|
||||
|
||||
// fill buffer from structure [{uint8_t data, size_t length},...]
|
||||
int FillBuffer(uint8_t *data, size_t maxDataLength, size_t *dataLength, ...) {
|
||||
*dataLength = 0;
|
||||
va_list valist;
|
||||
va_start(valist, dataLength);
|
||||
|
||||
uint8_t *vdata = NULL;
|
||||
size_t vlength = 0;
|
||||
do{
|
||||
vdata = va_arg(valist, uint8_t *);
|
||||
if (!vdata)
|
||||
break;
|
||||
|
||||
vlength = va_arg(valist, size_t);
|
||||
if (*dataLength + vlength > maxDataLength) {
|
||||
va_end(valist);
|
||||
return 1;
|
||||
}
|
||||
|
||||
memcpy(&data[*dataLength], vdata, vlength);
|
||||
*dataLength += vlength;
|
||||
|
||||
} while (vdata);
|
||||
|
||||
va_end(valist);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hex_to_buffer(const uint8_t *buf, const uint8_t *hex_data, const size_t hex_len, const size_t hex_max_len,
|
||||
const size_t min_str_len, const size_t spaces_between, bool uppercase) {
|
||||
|
||||
|
|
|
@ -35,6 +35,46 @@
|
|||
#define FILE_PATH_SIZE 2000
|
||||
#endif
|
||||
|
||||
#ifndef ARRAYLEN
|
||||
# define ARRAYLEN(x) (sizeof(x)/sizeof((x)[0]))
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || (__APPLE__)
|
||||
# define _BLUE_(s) "\x1b[34m" #s "\x1b[0m "
|
||||
#else
|
||||
# define _BLUE_(s) #s " "
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || (__APPLE__)
|
||||
# define _RED_(s) "\x1b[31m" #s "\x1b[0m "
|
||||
#else
|
||||
# define _RED_(s) #s " "
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || (__APPLE__)
|
||||
# define _GREEN_(s) "\x1b[32m" #s "\x1b[0m "
|
||||
#else
|
||||
# define _GREEN_(s) #s " "
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || (__APPLE__)
|
||||
# define _YELLOW_(s) "\x1b[33m" #s "\x1b[0m "
|
||||
#else
|
||||
# define _YELLOW_(s) #s " "
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || (__APPLE__)
|
||||
# define _MAGENTA_(s) "\x1b[35m" #s "\x1b[0m "
|
||||
#else
|
||||
# define _MAGENTA_(s) #s " "
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || (__APPLE__)
|
||||
# define _CYAN_(s) "\x1b[36m" #s "\x1b[0m "
|
||||
#else
|
||||
# define _CYAN_(s) #s " "
|
||||
#endif
|
||||
|
||||
extern int ukbhit(void);
|
||||
|
||||
extern void AddLogLine(char *fileName, char *extData, char *c);
|
||||
|
@ -43,6 +83,9 @@ extern void AddLogUint64(char *fileName, char *extData, const uint64_t data);
|
|||
extern void AddLogCurrentDT(char *fileName);
|
||||
extern void FillFileNameByUID(char *fileName, uint8_t * uid, char *ext, int byteCount);
|
||||
|
||||
// fill buffer from structure [{uint8_t data, size_t length},...]
|
||||
extern int FillBuffer(uint8_t *data, size_t maxDataLength, size_t *dataLength, ...);
|
||||
|
||||
extern void hex_to_buffer(const uint8_t *buf, const uint8_t *hex_data, const size_t hex_len,
|
||||
const size_t hex_max_len, const size_t min_str_len, const size_t spaces_between, bool uppercase);
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ mbedtls_SOURCES = \
|
|||
arc4.c \
|
||||
pk.c \
|
||||
pk_wrap.c \
|
||||
pkwrite.c \
|
||||
pkcs5.c \
|
||||
pkcs12.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…
Reference in a new issue