From b1760926568f8708fb14ae3fc9b1d6e75fe8e07e Mon Sep 17 00:00:00 2001 From: Jarno Lamsa Date: Thu, 18 Apr 2019 15:58:34 +0300 Subject: [PATCH] Parse private key in uecc format Parse the private key from cert in uecc format. Accept only P-256 curve. --- include/mbedtls/oid.h | 13 ++++ include/mbedtls/pk.h | 12 ++++ library/oid.c | 26 ++++++++ library/pkparse.c | 140 ++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 187 insertions(+), 4 deletions(-) diff --git a/include/mbedtls/oid.h b/include/mbedtls/oid.h index 48f0b30c5..0b8a7faf0 100644 --- a/include/mbedtls/oid.h +++ b/include/mbedtls/oid.h @@ -471,6 +471,18 @@ int mbedtls_oid_get_pk_alg( const mbedtls_asn1_buf *oid, mbedtls_pk_type_t *pk_a int mbedtls_oid_get_oid_by_pk_alg( mbedtls_pk_type_t pk_alg, const char **oid, size_t *olen ); +#if defined(MBEDTLS_USE_TINYCRYPT) +typedef enum +{ + MBEDTLS_UECC_DP_NONE = 0, /*!< Curve not defined. */ + MBEDTLS_UECC_DP_SECP256R1, /*!< Domain parameters for the 256-bit curve defined by FIPS 186-4 and SEC1. */ +} mbedtls_uecc_group_id; + +int mbedtls_oid_get_ec_grp( const mbedtls_asn1_buf *oid, mbedtls_uecc_group_id *grp_id ); + +int mbedtls_oid_get_oid_by_ec_grp( mbedtls_uecc_group_id grp_id, + const char **oid, size_t *olen); +#else #if defined(MBEDTLS_ECP_C) /** * \brief Translate NamedCurve OID into an EC group identifier @@ -494,6 +506,7 @@ int mbedtls_oid_get_ec_grp( const mbedtls_asn1_buf *oid, mbedtls_ecp_group_id *g int mbedtls_oid_get_oid_by_ec_grp( mbedtls_ecp_group_id grp_id, const char **oid, size_t *olen ); #endif /* MBEDTLS_ECP_C */ +#endif #if defined(MBEDTLS_MD_C) /** diff --git a/include/mbedtls/pk.h b/include/mbedtls/pk.h index 91950f940..a044c57b5 100644 --- a/include/mbedtls/pk.h +++ b/include/mbedtls/pk.h @@ -45,6 +45,10 @@ #include "ecdsa.h" #endif +#if defined(MBEDTLS_USE_TINYCRYPT) +#include "ecc.h" +#endif + #if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ !defined(inline) && !defined(__cplusplus) #define inline __inline @@ -133,6 +137,14 @@ typedef struct mbedtls_pk_context void * pk_ctx; /**< Underlying public key context */ } mbedtls_pk_context; +#if defined(MBEDTLS_USE_TINYCRYPT) +typedef struct +{ + uint8_t private_key[NUM_ECC_BYTES]; + uint8_t public_key[2*NUM_ECC_BYTES]; +} mbedtls_uecc_keypair; +#endif + #if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE) /** * \brief Context for resuming operations diff --git a/library/oid.c b/library/oid.c index 3119c5768..dd73cf019 100644 --- a/library/oid.c +++ b/library/oid.c @@ -467,6 +467,12 @@ FN_OID_TYPED_FROM_ASN1(oid_pk_alg_t, pk_alg, oid_pk_alg) FN_OID_GET_ATTR1(mbedtls_oid_get_pk_alg, oid_pk_alg_t, pk_alg, mbedtls_pk_type_t, pk_alg) FN_OID_GET_OID_BY_ATTR1(mbedtls_oid_get_oid_by_pk_alg, oid_pk_alg_t, oid_pk_alg, mbedtls_pk_type_t, pk_alg) +#if defined(MBEDTLS_USE_TINYCRYPT) +typedef struct { + mbedtls_oid_descriptor_t descriptor; + mbedtls_uecc_group_id grp_id; +} oid_ecp_grp_t; +#else #if defined(MBEDTLS_ECP_C) /* * For namedCurve (RFC 5480) @@ -475,7 +481,26 @@ typedef struct { mbedtls_oid_descriptor_t descriptor; mbedtls_ecp_group_id grp_id; } oid_ecp_grp_t; +#endif +#endif +#if defined(MBEDTLS_USE_TINYCRYPT) +static const oid_ecp_grp_t oid_ecp_grp[] = +{ + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP256R1 ), "secp256r1", "secp256r1" }, + MBEDTLS_UECC_DP_SECP256R1, + }, + { + { NULL, 0, NULL, NULL }, + MBEDTLS_UECC_DP_NONE, + }, +}; +FN_OID_TYPED_FROM_ASN1(oid_ecp_grp_t, grp_id, oid_ecp_grp) +FN_OID_GET_ATTR1(mbedtls_oid_get_ec_grp, oid_ecp_grp_t, grp_id, mbedtls_uecc_group_id, grp_id) +FN_OID_GET_OID_BY_ATTR1(mbedtls_oid_get_oid_by_ec_grp, oid_ecp_grp_t, oid_ecp_grp, mbedtls_uecc_group_id, grp_id) +#else +#if defined(MBEDTLS_ECP_C) static const oid_ecp_grp_t oid_ecp_grp[] = { #if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) @@ -554,6 +579,7 @@ FN_OID_TYPED_FROM_ASN1(oid_ecp_grp_t, grp_id, oid_ecp_grp) FN_OID_GET_ATTR1(mbedtls_oid_get_ec_grp, oid_ecp_grp_t, grp_id, mbedtls_ecp_group_id, grp_id) FN_OID_GET_OID_BY_ATTR1(mbedtls_oid_get_oid_by_ec_grp, oid_ecp_grp_t, oid_ecp_grp, mbedtls_ecp_group_id, grp_id) #endif /* MBEDTLS_ECP_C */ +#endif #if defined(MBEDTLS_CIPHER_C) /* diff --git a/library/pkparse.c b/library/pkparse.c index e8a3e86ab..e25b84ec2 100644 --- a/library/pkparse.c +++ b/library/pkparse.c @@ -179,7 +179,28 @@ int mbedtls_pk_parse_public_keyfile( mbedtls_pk_context *ctx, const char *path ) } #endif /* MBEDTLS_FS_IO */ -#if defined(MBEDTLS_ECP_C) +#if defined(MBEDTLS_USE_TINYCRYPT) +static int pk_use_ecparams( const mbedtls_asn1_buf *params ) +{ + uint32_t grp_id; + + if( params->tag == MBEDTLS_ASN1_OID ) + { + if( mbedtls_oid_get_ec_grp( params, &grp_id ) != 0 ) + return( MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE ); + } + else + { + // Only P-256 is supported + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); + } + + return( 0 ); +} +#endif + +#if defined(MBEDTLS_ECP_C) || \ + defined(MBEDTLS_USE_TINYCRYPT) /* Minimally parse an ECParameters buffer to and mbedtls_asn1_buf * * ECParameters ::= CHOICE { @@ -223,7 +244,9 @@ static int pk_get_ecparams( unsigned char **p, const unsigned char *end, return( 0 ); } +#endif +#if defined(MBEDTLS_ECP_C) #if defined(MBEDTLS_PK_PARSE_EC_EXTENDED) /* * Parse a SpecifiedECDomain (SEC 1 C.2) and (mostly) fill the group with it. @@ -524,7 +547,7 @@ static int pk_get_ecpubkey( unsigned char **p, const unsigned char *end, /* * Import a point from unsigned binary data (SEC1 2.3.4) */ -static int uecc_public_key_read_binary( uint8_t **pt, +static int uecc_public_key_read_binary( uint8_t *pt, const unsigned char *buf, size_t ilen ) { @@ -539,7 +562,7 @@ static int uecc_public_key_read_binary( uint8_t **pt, if( ilen != 2 * NUM_ECC_BYTES + 1 ) return( MBEDTLS_ERR_PK_INVALID_PUBKEY ); - *pt = (uint8_t *) buf + 1; + memcpy( pt, buf + 1, ilen - 1); return( 0 ); } @@ -550,7 +573,7 @@ static int pk_get_ueccpubkey( unsigned char **p, { int ret; - ret = uecc_public_key_read_binary( &pk_context, + ret = uecc_public_key_read_binary( pk_context, (const unsigned char *) *p, end - *p ); /* @@ -854,6 +877,114 @@ cleanup: } #endif /* MBEDTLS_RSA_C */ +#if defined(MBEDTLS_USE_TINYCRYPT) +static int pk_parse_key_sec1_der( mbedtls_uecc_keypair *keypair, + const unsigned char *key, + size_t keylen) +{ + int ret; + int version, pubkey_done; + size_t len; + mbedtls_asn1_buf params; + unsigned char *p = (unsigned char *) key; + unsigned char *end = p + keylen; + unsigned char *end2; + + /* + * RFC 5915, or SEC1 Appendix C.4 + * + * ECPrivateKey ::= SEQUENCE { + * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), + * privateKey OCTET STRING, + * parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, + * publicKey [1] BIT STRING OPTIONAL + * } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + end = p + len; + + if( ( ret = mbedtls_asn1_get_int( &p, end, &version ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( version != 1 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_VERSION ); + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + memcpy(keypair->private_key, p, len); + + p += len; + + pubkey_done = 0; + if( p != end ) + { + /* + * Is 'parameters' present? + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0 ) ) == 0 ) + { + if( ( ret = pk_get_ecparams( &p, p + len, ¶ms) ) != 0 || + ( ret = pk_use_ecparams( ¶ms ) ) != 0 ) + { + return( ret ); + } + } + else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + } + + if( p != end ) + { + /* + * Is 'publickey' present? If not, or if we can't read it (eg because it + * is compressed), create it from the private key. + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 1 ) ) == 0 ) + { + end2 = p + len; + + if( ( ret = mbedtls_asn1_get_bitstring_null( &p, end2, &len ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( p + len != end2 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + if( ( ret = uecc_public_key_read_binary( keypair->public_key, + (const unsigned char *) p, end2 - p ) ) == 0 ) + pubkey_done = 1; + else + { + /* + * The only acceptable failure mode of pk_get_ecpubkey() above + * is if the point format is not recognized. + */ + if( ret != MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); + } + } + else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + } + + //TODO: Do we need to support derived public keys with uecc? + + return( 0 ); +} +#else + #if defined(MBEDTLS_ECP_C) /* * Parse a SEC1 encoded private EC key @@ -982,6 +1113,7 @@ static int pk_parse_key_sec1_der( mbedtls_ecp_keypair *eck, return( 0 ); } #endif /* MBEDTLS_ECP_C */ +#endif /* MBEDTLS_USE_TINYCRYPT */ /* * Parse an unencrypted PKCS#8 encoded private key