From 73c0cda34638f48cc9f052be2b354898f3ded252 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Mon, 1 Jul 2013 19:45:45 +0200 Subject: [PATCH] Complete x509parse_public_key_ec() Warning: due to a bug in oid_descriptor_from_buf(), keys associated to some curves (secp224r1, secp384r1, secp521r1) are incorrectly rejected, since their namedCurve OID contains a nul byte. --- library/x509parse.c | 113 +++++++++++++++++++++++++++++------- tests/data_files/ec_pub.der | Bin 80 -> 75 bytes tests/data_files/ec_pub.pem | 4 +- 3 files changed, 95 insertions(+), 22 deletions(-) diff --git a/library/x509parse.c b/library/x509parse.c index 840319f43..e04d56b0e 100644 --- a/library/x509parse.c +++ b/library/x509parse.c @@ -233,6 +233,40 @@ static int x509_get_ecparams( unsigned char **p, const unsigned char *end, return( 0 ); } +/* + * subjectPublicKey BIT STRING + * -- which, in our case, contains + * ECPoint ::= octet string (not ASN.1) + */ +static int x509_get_subpubkey_ec( unsigned char **p, const unsigned char *end, + const ecp_group *grp, ecp_point *pt ) +{ + int ret; + size_t len; + + if( ( ret = asn1_get_tag( p, end, &len, ASN1_BIT_STRING ) ) != 0 ) + return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret ); + + if( *p + len != end ) + return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + + /* + * First byte in the content of BIT STRING is the nummber of padding bit. + * Here it is always 0 since ECPoint is an octet string, so skip it. + */ + ++*p; + --len; + + if( ( ret = ecp_point_read_binary( grp, pt, + (const unsigned char *) *p, len ) ) != 0 ) + { + return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret ); + } + + return( 0 ); +} + /* * AttributeTypeAndValue ::= SEQUENCE { * type AttributeType, @@ -2633,6 +2667,59 @@ int x509parse_key_ec( ecp_keypair *eckey, return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT ); } +/* + * Parse a public EC key in RFC 5480 format, der-encoded + */ +static int x509parse_public_key_ec_der( ecp_keypair *key, + const unsigned char *buf, size_t len ) +{ + int ret; + ecp_group_id grp_id; + x509_buf alg_oid; + pk_type_t alg = POLARSSL_PK_NONE; + unsigned char *p = (unsigned char *) buf; + unsigned char *end = p + len; + const unsigned char *params_end; + /* + * SubjectPublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * subjectPublicKey BIT STRING + * } + * -- algorithm parameters are ECParameters + * -- subjectPublicKey is an ECPoint + */ + if( ( ret = asn1_get_tag( &p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret ); + } + + if( ( ret = x509_get_alg( &p, end, &alg_oid, ¶ms_end ) ) != 0 ) + return( ret ); + + if( oid_get_pk_alg( &alg_oid, &alg ) != 0 ) + return( POLARSSL_ERR_X509_UNKNOWN_PK_ALG ); + + if( alg != POLARSSL_PK_ECKEY && alg != POLARSSL_PK_ECKEY_DH ) + return( POLARSSL_ERR_X509_UNKNOWN_PK_ALG ); + + if ( alg == POLARSSL_PK_ECKEY_DH ) + key->alg = POLARSSL_ECP_KEY_ALG_ECDH; + + if( ( ret = x509_get_ecparams( &p, params_end, &grp_id ) ) != 0 ) + return( ret ); + + if( ( ret = ecp_use_known_dp( &key->grp, grp_id ) ) != 0 ) + return( ret ); + + if( ( ret = x509_get_subpubkey_ec( &p, end, &key->grp, &key->Q ) ) != 0 ) + { + return( ret ); + } + + return( 0 ); +} + /* * Parse a public EC key */ @@ -2640,14 +2727,12 @@ int x509parse_public_key_ec( ecp_keypair *eckey, const unsigned char *key, size_t keylen ) { int ret; - size_t len; - unsigned char *p, *end; - x509_buf alg_oid; #if defined(POLARSSL_PEM_C) + size_t len; pem_context pem; pem_init( &pem ); - ret = pem_read_buffer( &pem, /* TODO: check header */ + ret = pem_read_buffer( &pem, "-----BEGIN PUBLIC KEY-----", "-----END PUBLIC KEY-----", key, NULL, 0, &len ); @@ -2657,6 +2742,7 @@ int x509parse_public_key_ec( ecp_keypair *eckey, /* * Was PEM encoded */ + key = pem.buf; keylen = pem.buflen; } else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) @@ -2664,32 +2750,19 @@ int x509parse_public_key_ec( ecp_keypair *eckey, pem_free( &pem ); return( ret ); } - - p = ( ret == 0 ) ? pem.buf : (unsigned char *) key; -#else - p = (unsigned char *) key; #endif - end = p + keylen; - /* TODO: parse key */ - (void) alg_oid; - (void) end; - (void) eckey; - - if( ( ret = ecp_check_pubkey( &eckey->grp, &eckey->Q ) ) != 0 ) + if( ( ret = x509parse_public_key_ec_der ( eckey, key, keylen ) ) != 0 || + ( ret = ecp_check_pubkey( &eckey->grp, &eckey->Q ) ) != 0 ) { -#if defined(POLARSSL_PEM_C) - pem_free( &pem ); -#endif ecp_keypair_free( eckey ); - return( ret ); } #if defined(POLARSSL_PEM_C) pem_free( &pem ); #endif - return( 0 ); + return( ret ); } #endif /* defined(POLARSSL_ECP_C) */ diff --git a/tests/data_files/ec_pub.der b/tests/data_files/ec_pub.der index 954bf3b29f43091f52625b01d9f8b40ac774b1dd..74c5951f60c2c13c29369f85c95958c4af70dc3c 100644 GIT binary patch literal 75 zcmXr;G!SNE*J|@PXUoLM#sOw9Gcqz8F|h2Ztlhk>p5u+JXSV+q!Oh