From e2f504087615b492f456e362d0d1c0b56c1eb6f1 Mon Sep 17 00:00:00 2001 From: Paul Bakker Date: Mon, 24 Jun 2013 19:00:59 +0200 Subject: [PATCH] Internally split up x509parse_key() Split up x509parse_key() into a (PEM) handler function and specific DER parser functions for the PKCS#1 (x509parse_key_pkcs1_der()) and unencrypted PKCS#8 (x509parse_key_pkcs8_unencrypted_der()) private key formats. (cherry picked from commit 65a1909dc6ff7b93f0a231a5a49d98d968c9bcdc) Conflicts: library/x509parse.c --- library/x509parse.c | 317 ++++++++++++------------- tests/suites/test_suite_x509parse.data | 14 +- 2 files changed, 165 insertions(+), 166 deletions(-) diff --git a/library/x509parse.c b/library/x509parse.c index 7603eca3b..23c57eaf9 100644 --- a/library/x509parse.c +++ b/library/x509parse.c @@ -2015,69 +2015,21 @@ int x509parse_public_keyfile( rsa_context *rsa, const char *path ) #endif /* POLARSSL_FS_IO */ /* - * Parse a private RSA key + * Parse a PKCS#1 encoded private RSA key */ -int x509parse_key( rsa_context *rsa, const unsigned char *key, size_t keylen, - const unsigned char *pwd, size_t pwdlen ) +static int x509parse_key_pkcs1_der( rsa_context *rsa, + const unsigned char *key, + size_t keylen ) { int ret; size_t len; unsigned char *p, *end; - unsigned char *p_alt; - x509_buf pk_alg_oid; -#if defined(POLARSSL_PEM_C) - pem_context pem; - - pem_init( &pem ); - ret = pem_read_buffer( &pem, - "-----BEGIN RSA PRIVATE KEY-----", - "-----END RSA PRIVATE KEY-----", - key, pwd, pwdlen, &len ); - - if( ret == POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) - { - ret = pem_read_buffer( &pem, - "-----BEGIN PRIVATE KEY-----", - "-----END PRIVATE KEY-----", - key, pwd, pwdlen, &len ); - } - - if( ret == 0 ) - { - /* - * Was PEM encoded - */ - keylen = pem.buflen; - } - else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) - { - pem_free( &pem ); - return( ret ); - } - - p = ( ret == 0 ) ? pem.buf : (unsigned char *) key; -#else - ((void) pwd); - ((void) pwdlen); p = (unsigned char *) key; -#endif end = p + keylen; /* - * Note: Depending on the type of private key file one can expect either a - * PrivatKeyInfo object (PKCS#8) or a RSAPrivateKey (PKCS#1) directly. - * - * PrivateKeyInfo ::= SEQUENCE { - * version Version, - * algorithm AlgorithmIdentifier, - * PrivateKey BIT STRING - * } - * - * AlgorithmIdentifier ::= SEQUENCE { - * algorithm OBJECT IDENTIFIER, - * parameters ANY DEFINED BY algorithm OPTIONAL - * } + * This function parses the RSAPrivateKey (PKCS#1) * * RSAPrivateKey ::= SEQUENCE { * version Version, @@ -2095,10 +2047,6 @@ int x509parse_key( rsa_context *rsa, const unsigned char *key, size_t keylen, if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) { -#if defined(POLARSSL_PEM_C) - pem_free( &pem ); -#endif - rsa_free( rsa ); return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret ); } @@ -2106,106 +2054,14 @@ int x509parse_key( rsa_context *rsa, const unsigned char *key, size_t keylen, if( ( ret = asn1_get_int( &p, end, &rsa->ver ) ) != 0 ) { -#if defined(POLARSSL_PEM_C) - pem_free( &pem ); -#endif - rsa_free( rsa ); return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret ); } if( rsa->ver != 0 ) { -#if defined(POLARSSL_PEM_C) - pem_free( &pem ); -#endif - rsa_free( rsa ); return( POLARSSL_ERR_X509_KEY_INVALID_VERSION + ret ); } - p_alt = p; - - if( ( ret = x509_get_alg( &p_alt, end, &pk_alg_oid ) ) != 0 ) - { - // Assume that we have the PKCS#1 format if wrong - // tag was encountered - // - if( ret != POLARSSL_ERR_X509_CERT_INVALID_ALG + - POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) - { -#if defined(POLARSSL_PEM_C) - pem_free( &pem ); -#endif - rsa_free( rsa ); - return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT ); - } - } - else - { - pk_type_t pk_alg = POLARSSL_PK_NONE; - - /* - * only RSA keys handled at this time - */ - if( oid_get_pk_alg( &pk_alg_oid, &pk_alg ) != 0 ) - return( POLARSSL_ERR_X509_UNKNOWN_PK_ALG ); - - /* - * Parse the PKCS#8 format - */ - - p = p_alt; - if( ( ret = asn1_get_tag( &p, end, &len, ASN1_OCTET_STRING ) ) != 0 ) - { -#if defined(POLARSSL_PEM_C) - pem_free( &pem ); -#endif - rsa_free( rsa ); - return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret ); - } - - if( ( end - p ) < 1 ) - { -#if defined(POLARSSL_PEM_C) - pem_free( &pem ); -#endif - rsa_free( rsa ); - return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + - POLARSSL_ERR_ASN1_OUT_OF_DATA ); - } - - end = p + len; - - if( ( ret = asn1_get_tag( &p, end, &len, - ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) - { -#if defined(POLARSSL_PEM_C) - pem_free( &pem ); -#endif - rsa_free( rsa ); - return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret ); - } - - end = p + len; - - if( ( ret = asn1_get_int( &p, end, &rsa->ver ) ) != 0 ) - { -#if defined(POLARSSL_PEM_C) - pem_free( &pem ); -#endif - rsa_free( rsa ); - return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret ); - } - - if( rsa->ver != 0 ) - { -#if defined(POLARSSL_PEM_C) - pem_free( &pem ); -#endif - rsa_free( rsa ); - return( POLARSSL_ERR_X509_KEY_INVALID_VERSION + ret ); - } - } - if( ( ret = asn1_get_mpi( &p, end, &rsa->N ) ) != 0 || ( ret = asn1_get_mpi( &p, end, &rsa->E ) ) != 0 || ( ret = asn1_get_mpi( &p, end, &rsa->D ) ) != 0 || @@ -2215,9 +2071,6 @@ int x509parse_key( rsa_context *rsa, const unsigned char *key, size_t keylen, ( ret = asn1_get_mpi( &p, end, &rsa->DQ ) ) != 0 || ( ret = asn1_get_mpi( &p, end, &rsa->QP ) ) != 0 ) { -#if defined(POLARSSL_PEM_C) - pem_free( &pem ); -#endif rsa_free( rsa ); return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret ); } @@ -2226,9 +2079,6 @@ int x509parse_key( rsa_context *rsa, const unsigned char *key, size_t keylen, if( p != end ) { -#if defined(POLARSSL_PEM_C) - pem_free( &pem ); -#endif rsa_free( rsa ); return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); @@ -2236,16 +2086,165 @@ int x509parse_key( rsa_context *rsa, const unsigned char *key, size_t keylen, if( ( ret = rsa_check_privkey( rsa ) ) != 0 ) { -#if defined(POLARSSL_PEM_C) - pem_free( &pem ); -#endif rsa_free( rsa ); return( ret ); } + return( 0 ); +} + +/* + * Parse an unencrypted PKCS#8 encoded private RSA key + */ +static int x509parse_key_pkcs8_unencrypted_der( + rsa_context *rsa, + const unsigned char *key, + size_t keylen ) +{ + int ret; + size_t len; + unsigned char *p, *end; + x509_buf pk_alg_oid; + pk_type_t pk_alg = POLARSSL_PK_NONE; + + p = (unsigned char *) key; + end = p + keylen; + + /* + * This function parses the PrivatKeyInfo object (PKCS#8) + * + * PrivateKeyInfo ::= SEQUENCE { + * version Version, + * algorithm AlgorithmIdentifier, + * PrivateKey BIT STRING + * } + * + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL + * } + * + * The PrivateKey BIT STRING is a PKCS#1 RSAPrivateKey + */ + if( ( ret = asn1_get_tag( &p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { + return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret ); + } + + end = p + len; + + if( ( ret = asn1_get_int( &p, end, &rsa->ver ) ) != 0 ) + return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret ); + + if( rsa->ver != 0 ) + return( POLARSSL_ERR_X509_KEY_INVALID_VERSION + ret ); + + if( ( ret = x509_get_alg( &p, end, &pk_alg_oid ) ) != 0 ) + return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret ); + + /* + * only RSA keys handled at this time + */ + if( oid_get_pk_alg( &pk_alg_oid, &pk_alg ) != 0 ) + return( POLARSSL_ERR_X509_UNKNOWN_PK_ALG ); + + /* + * Get the OCTET STRING and parse the PKCS#1 format inside + */ + if( ( ret = asn1_get_tag( &p, end, &len, ASN1_OCTET_STRING ) ) != 0 ) + return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret ); + + if( ( end - p ) < 1 ) + { + return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + + POLARSSL_ERR_ASN1_OUT_OF_DATA ); + } + + end = p + len; + + if( ( ret = x509parse_key_pkcs1_der( rsa, p, end - p ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +/* + * Parse a private RSA key + */ +int x509parse_key( rsa_context *rsa, const unsigned char *key, size_t keylen, + const unsigned char *pwd, size_t pwdlen ) +{ + int ret; + #if defined(POLARSSL_PEM_C) + size_t len; + pem_context pem; + + pem_init( &pem ); + ret = pem_read_buffer( &pem, + "-----BEGIN RSA PRIVATE KEY-----", + "-----END RSA PRIVATE KEY-----", + key, pwd, pwdlen, &len ); + if( ret == 0 ) + { + if( ( ret = x509parse_key_pkcs1_der( rsa, pem.buf, pem.buflen ) ) != 0 ) + { + rsa_free( rsa ); + } + + pem_free( &pem ); + return( ret ); + } + else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + { + pem_free( &pem ); + return( ret ); + } + + ret = pem_read_buffer( &pem, + "-----BEGIN PRIVATE KEY-----", + "-----END PRIVATE KEY-----", + key, NULL, 0, &len ); + if( ret == 0 ) + { + if( ( ret = x509parse_key_pkcs8_unencrypted_der( rsa, + pem.buf, pem.buflen ) ) != 0 ) + { + rsa_free( rsa ); + } + + pem_free( &pem ); + return( ret ); + } + else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + { + pem_free( &pem ); + return( ret ); + } + pem_free( &pem ); -#endif +#else + ((void) pwd); + ((void) pwdlen); +#endif /* POLARSSL_PEM_C */ + + // At this point we only know it's not a PEM formatted key. Could be any + // of the known DER encoded private key formats + // + // We try the different DER format parsers to see if one passes without + // error + // + if( ( ret = x509parse_key_pkcs8_unencrypted_der( rsa, key, keylen ) ) != 0 ) + { + rsa_free( rsa ); + + if( ( ret = x509parse_key_pkcs1_der( rsa, key, keylen ) ) != 0 ) + { + rsa_free( rsa ); + return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT ); + } + } return( 0 ); } diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data index 61220cfc9..a562e5654 100644 --- a/tests/suites/test_suite_x509parse.data +++ b/tests/suites/test_suite_x509parse.data @@ -584,22 +584,22 @@ X509 CRL ASN1 (TBSCertList, no entries) x509parse_crl:"30463031020100300d06092a864886f70d01010e0500300f310d300b0603550403130441424344170c303930313031303030303030300d06092a864886f70d01010e050003020001":"CRL version \: 1\nissuer name \: CN=ABCD\nthis update \: 2009-01-01 00\:00\:00\nnext update \: 0000-00-00 00\:00\:00\nRevoked certificates\:\nsigned using \: RSA with SHA-224\n":0 X509 Key ASN1 (Incorrect first tag) -x509parse_key:"":"":POLARSSL_ERR_X509_KEY_INVALID_FORMAT + POLARSSL_ERR_ASN1_OUT_OF_DATA +x509parse_key:"":"":POLARSSL_ERR_X509_KEY_INVALID_FORMAT X509 Key ASN1 (RSAPrivateKey, incorrect version tag) -x509parse_key:"300100":"":POLARSSL_ERR_X509_KEY_INVALID_FORMAT + POLARSSL_ERR_ASN1_UNEXPECTED_TAG +x509parse_key:"300100":"":POLARSSL_ERR_X509_KEY_INVALID_FORMAT X509 Key ASN1 (RSAPrivateKey, version tag missing) -x509parse_key:"3000":"":POLARSSL_ERR_X509_KEY_INVALID_FORMAT + POLARSSL_ERR_ASN1_OUT_OF_DATA +x509parse_key:"3000":"":POLARSSL_ERR_X509_KEY_INVALID_FORMAT X509 Key ASN1 (RSAPrivateKey, invalid version) -x509parse_key:"3003020101":"":POLARSSL_ERR_X509_KEY_INVALID_VERSION +x509parse_key:"3003020101":"":POLARSSL_ERR_X509_KEY_INVALID_FORMAT X509 Key ASN1 (RSAPrivateKey, correct version, incorrect tag) -x509parse_key:"300402010000":"":POLARSSL_ERR_X509_KEY_INVALID_FORMAT + POLARSSL_ERR_ASN1_UNEXPECTED_TAG +x509parse_key:"300402010000":"":POLARSSL_ERR_X509_KEY_INVALID_FORMAT X509 Key ASN1 (RSAPrivateKey, values present, length mismatch) -x509parse_key:"301c02010002010102010102010102010102010102010102010102010100":"":POLARSSL_ERR_X509_KEY_INVALID_FORMAT + POLARSSL_ERR_ASN1_LENGTH_MISMATCH +x509parse_key:"301c02010002010102010102010102010102010102010102010102010100":"":POLARSSL_ERR_X509_KEY_INVALID_FORMAT X509 Key ASN1 (RSAPrivateKey, values present, check_privkey fails) -x509parse_key:"301b020100020101020101020101020101020101020101020101020101":"":POLARSSL_ERR_RSA_KEY_CHECK_FAILED +x509parse_key:"301b020100020101020101020101020101020101020101020101020101":"":POLARSSL_ERR_X509_KEY_INVALID_FORMAT