/* * Parse an unencrypted PKCS#8 encoded private key */ static int pk_parse_key_pkcs8_unencrypted_der( mbedtls_pk_context *pk, const unsigned char* key, size_t keylen ) { int ret, version; size_t len; mbedtls_asn1_buf params; unsigned char *p = (unsigned char *) key; unsigned char *end = p + keylen; mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE; const mbedtls_pk_info_t *pk_info; /* * This function parses the PrivatKeyInfo object (PKCS#8 v1.2 = RFC 5208) * * PrivateKeyInfo ::= SEQUENCE { * version Version, * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, * privateKey PrivateKey, * attributes [0] IMPLICIT Attributes OPTIONAL } * * Version ::= INTEGER * PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier * PrivateKey ::= OCTET STRING * * The PrivateKey OCTET STRING is a SEC1 ECPrivateKey */ 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 != 0 ) return( MBEDTLS_ERR_PK_KEY_INVALID_VERSION + ret ); if( ( ret = pk_get_pk_alg( &p, end, &pk_alg, ¶ms ) ) != 0 ) return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); if( len < 1 ) return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); if( ( pk_info = mbedtls_pk_info_from_type( pk_alg ) ) == NULL ) return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 ) return( ret ); #if defined(MBEDTLS_RSA_C) if( pk_alg == MBEDTLS_PK_RSA ) { if( ( ret = pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ), p, len ) ) != 0 ) { mbedtls_pk_free( pk ); return( ret ); } } else #endif /* MBEDTLS_RSA_C */ #if defined(MBEDTLS_ECP_C) if( pk_alg == MBEDTLS_PK_ECKEY || pk_alg == MBEDTLS_PK_ECKEY_DH ) { if( ( ret = pk_use_ecparams( ¶ms, &mbedtls_pk_ec( *pk )->grp ) ) != 0 || ( ret = pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ), p, len ) ) != 0 ) { mbedtls_pk_free( pk ); return( ret ); } } else #endif /* MBEDTLS_ECP_C */ return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); return( 0 ); }
/* * Parse a private key */ int mbedtls_pk_parse_key( mbedtls_pk_context *pk, const unsigned char *key, size_t keylen, const unsigned char *pwd, size_t pwdlen ) { int ret; const mbedtls_pk_info_t *pk_info; #if defined(MBEDTLS_PEM_PARSE_C) size_t len; mbedtls_pem_context pem; mbedtls_pem_init( &pem ); #if defined(MBEDTLS_RSA_C) /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ if( keylen == 0 || key[keylen - 1] != '\0' ) ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; else ret = mbedtls_pem_read_buffer( &pem, "-----BEGIN RSA PRIVATE KEY-----", "-----END RSA PRIVATE KEY-----", key, pwd, pwdlen, &len ); if( ret == 0 ) { if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == NULL ) return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 || ( ret = pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ), pem.buf, pem.buflen ) ) != 0 ) { mbedtls_pk_free( pk ); } mbedtls_pem_free( &pem ); return( ret ); } else if( ret == MBEDTLS_ERR_PEM_PASSWORD_MISMATCH ) return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); else if( ret == MBEDTLS_ERR_PEM_PASSWORD_REQUIRED ) return( MBEDTLS_ERR_PK_PASSWORD_REQUIRED ); else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) return( ret ); #endif /* MBEDTLS_RSA_C */ #if defined(MBEDTLS_ECP_C) /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ if( keylen == 0 || key[keylen - 1] != '\0' ) ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; else ret = mbedtls_pem_read_buffer( &pem, "-----BEGIN EC PRIVATE KEY-----", "-----END EC PRIVATE KEY-----", key, pwd, pwdlen, &len ); if( ret == 0 ) { if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_ECKEY ) ) == NULL ) return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 || ( ret = pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ), pem.buf, pem.buflen ) ) != 0 ) { mbedtls_pk_free( pk ); } mbedtls_pem_free( &pem ); return( ret ); } else if( ret == MBEDTLS_ERR_PEM_PASSWORD_MISMATCH ) return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); else if( ret == MBEDTLS_ERR_PEM_PASSWORD_REQUIRED ) return( MBEDTLS_ERR_PK_PASSWORD_REQUIRED ); else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) return( ret ); #endif /* MBEDTLS_ECP_C */ /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ if( keylen == 0 || key[keylen - 1] != '\0' ) ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; else ret = mbedtls_pem_read_buffer( &pem, "-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----", key, NULL, 0, &len ); if( ret == 0 ) { if( ( ret = pk_parse_key_pkcs8_unencrypted_der( pk, pem.buf, pem.buflen ) ) != 0 ) { mbedtls_pk_free( pk ); } mbedtls_pem_free( &pem ); return( ret ); } else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) return( ret ); #if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C) /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ if( keylen == 0 || key[keylen - 1] != '\0' ) ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; else ret = mbedtls_pem_read_buffer( &pem, "-----BEGIN ENCRYPTED PRIVATE KEY-----", "-----END ENCRYPTED PRIVATE KEY-----", key, NULL, 0, &len ); if( ret == 0 ) { if( ( ret = pk_parse_key_pkcs8_encrypted_der( pk, pem.buf, pem.buflen, pwd, pwdlen ) ) != 0 ) { mbedtls_pk_free( pk ); } mbedtls_pem_free( &pem ); return( ret ); } else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) return( ret ); #endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */ #else ((void) ret); ((void) pwd); ((void) pwdlen); #endif /* MBEDTLS_PEM_PARSE_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 defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C) if( ( ret = pk_parse_key_pkcs8_encrypted_der( pk, key, keylen, pwd, pwdlen ) ) == 0 ) { return( 0 ); } mbedtls_pk_free( pk ); if( ret == MBEDTLS_ERR_PK_PASSWORD_MISMATCH ) { return( ret ); } #endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */ if( ( ret = pk_parse_key_pkcs8_unencrypted_der( pk, key, keylen ) ) == 0 ) return( 0 ); mbedtls_pk_free( pk ); #if defined(MBEDTLS_RSA_C) if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == NULL ) return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 || ( ret = pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ), key, keylen ) ) == 0 ) { return( 0 ); } mbedtls_pk_free( pk ); #endif /* MBEDTLS_RSA_C */ #if defined(MBEDTLS_ECP_C) if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_ECKEY ) ) == NULL ) return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 || ( ret = pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ), key, keylen ) ) == 0 ) { return( 0 ); } mbedtls_pk_free( pk ); #endif /* MBEDTLS_ECP_C */ return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); }
/** * Parse an unencrypted PKCS#8 encoded private key. * This function does not own the key buffer. It is the responsibility of the * caller to take care of zeroizing and freeing it after use. * The function is responsible for freeing the provided PK context on failure. */ static int pk_parse_key_pkcs8_unencrypted_der(ttls_pk_context *pk, const unsigned char *key, size_t keylen) { int ret, version; size_t len; ttls_asn1_buf params; unsigned char *p = (unsigned char *)key; unsigned char *end = p + keylen; ttls_pk_type_t pk_alg = TTLS_PK_NONE; const ttls_pk_info_t *pk_info; /* * This function parses the PrivateKeyInfo object * (PKCS#8 v1.2 = RFC 5208). * * PrivateKeyInfo ::= SEQUENCE { * version Version, * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, * privateKey PrivateKey, * attributes [0] IMPLICIT Attributes OPTIONAL } * * Version ::= INTEGER * PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier * PrivateKey ::= OCTET STRING * * The PrivateKey OCTET STRING is a SEC1 ECPrivateKey */ ret = ttls_asn1_get_tag(&p, end, &len, TTLS_ASN1_CONSTRUCTED | TTLS_ASN1_SEQUENCE); if (ret) return TTLS_ERR_PK_KEY_INVALID_FORMAT + ret; end = p + len; if ((ret = ttls_asn1_get_int(&p, end, &version))) return TTLS_ERR_PK_KEY_INVALID_FORMAT + ret; if (version) return TTLS_ERR_PK_KEY_INVALID_VERSION + ret; if ((ret = pk_get_pk_alg(&p, end, &pk_alg, ¶ms))) return TTLS_ERR_PK_KEY_INVALID_FORMAT + ret; if ((ret = ttls_asn1_get_tag(&p, end, &len, TTLS_ASN1_OCTET_STRING))) return TTLS_ERR_PK_KEY_INVALID_FORMAT + ret; if (len < 1) return TTLS_ERR_PK_KEY_INVALID_FORMAT + TTLS_ERR_ASN1_OUT_OF_DATA; if (!(pk_info = ttls_pk_info_from_type(pk_alg))) return TTLS_ERR_PK_UNKNOWN_PK_ALG; if ((ret = ttls_pk_setup(pk, pk_info))) return ret; if (pk_alg == TTLS_PK_RSA) { if ((ret = pk_parse_key_pkcs1_der(ttls_pk_rsa(*pk), p, len))) { ttls_pk_free(pk); return ret; } } else if (pk_alg == TTLS_PK_ECKEY || pk_alg == TTLS_PK_ECKEY_DH) { if ((ret = pk_use_ecparams(¶ms, &ttls_pk_ec(*pk)->grp)) || (ret = pk_parse_key_sec1_der(ttls_pk_ec(*pk), p, len))) { ttls_pk_free(pk); return ret; } } else { return TTLS_ERR_PK_UNKNOWN_PK_ALG; } return 0; }
/** * Parse a private key in PEM or DER format. * On entry, ctx must be empty, either freshly initialised with ttls_pk_init() * or reset with ttls_pk_free(). If you need a specific key type, check the * result with ttls_pk_can_do(). */ int ttls_pk_parse_key(ttls_pk_context *pk, unsigned char *key, size_t keylen) { int r, dec_key_len; const ttls_pk_info_t *pk_info; size_t len; if (!keylen) return TTLS_ERR_PK_KEY_INVALID_FORMAT; /* Avoid calling ttls_pem_read_buffer() on non-null-terminated string */ if (key[keylen - 1] != '\0') goto no_pem; r = ttls_pem_read_buffer("-----BEGIN RSA PRIVATE KEY-----", "-----END RSA PRIVATE KEY-----", key, &len); if (r > 0) { dec_key_len = r; pk_info = ttls_pk_info_from_type(TTLS_PK_RSA); if ((r = ttls_pk_setup(pk, pk_info)) || (r = pk_parse_key_pkcs1_der(ttls_pk_rsa(*pk), key, dec_key_len))) { ttls_pk_free(pk); } return r; } if (r == TTLS_ERR_PEM_PASSWORD_MISMATCH || r == TTLS_ERR_PEM_PASSWORD_REQUIRED || r != TTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) { return r; } /* Try to read EC key. */ r = ttls_pem_read_buffer("-----BEGIN EC PRIVATE KEY-----", "-----END EC PRIVATE KEY-----", key, &len); if (r > 0) { dec_key_len = r; pk_info = ttls_pk_info_from_type(TTLS_PK_ECKEY); if ((r = ttls_pk_setup(pk, pk_info)) || (r = pk_parse_key_sec1_der(ttls_pk_ec(*pk), key, dec_key_len))) { ttls_pk_free(pk); } return r; } if (r == TTLS_ERR_PEM_PASSWORD_MISMATCH || r == TTLS_ERR_PEM_PASSWORD_REQUIRED || r != TTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) { return r; } /* Try to read another key. */ r = ttls_pem_read_buffer("-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----", key, &len); if (r > 0) { if ((r = pk_parse_key_pkcs8_unencrypted_der(pk, key, r))) ttls_pk_free(pk); return r; } if (r != TTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) return r; no_pem: if (!(r = pk_parse_key_pkcs8_unencrypted_der(pk, key, keylen))) return 0; ttls_pk_free(pk); pk_info = ttls_pk_info_from_type(TTLS_PK_RSA); if ((r = ttls_pk_setup(pk, pk_info)) || (r = pk_parse_key_pkcs1_der(ttls_pk_rsa(*pk), key, keylen))) { ttls_pk_free(pk); } else { return 0; } pk_info = ttls_pk_info_from_type(TTLS_PK_ECKEY); if ((r = ttls_pk_setup(pk, pk_info)) || (r = pk_parse_key_sec1_der(ttls_pk_ec(*pk), key, keylen))) { ttls_pk_free(pk); } else { return 0; } return TTLS_ERR_PK_KEY_INVALID_FORMAT; }
/* * Parse a private key */ int pk_parse_key( pk_context *pk, const unsigned char *key, size_t keylen, const unsigned char *pwd, size_t pwdlen ) { int ret; const pk_info_t *pk_info; #if defined(POLARSSL_PEM_PARSE_C) size_t len; pem_context pem; pem_init( &pem ); #if defined(POLARSSL_RSA_C) ret = pem_read_buffer( &pem, "-----BEGIN RSA PRIVATE KEY-----", "-----END RSA PRIVATE KEY-----", key, pwd, pwdlen, &len ); if( ret == 0 ) { if( ( pk_info = pk_info_from_type( POLARSSL_PK_RSA ) ) == NULL ) return( POLARSSL_ERR_PK_UNKNOWN_PK_ALG ); if( ( ret = pk_init_ctx( pk, pk_info ) ) != 0 || ( ret = pk_parse_key_pkcs1_der( pk_rsa( *pk ), pem.buf, pem.buflen ) ) != 0 ) { pk_free( pk ); } pem_free( &pem ); return( ret ); } else if( ret == POLARSSL_ERR_PEM_PASSWORD_MISMATCH ) return( POLARSSL_ERR_PK_PASSWORD_MISMATCH ); else if( ret == POLARSSL_ERR_PEM_PASSWORD_REQUIRED ) return( POLARSSL_ERR_PK_PASSWORD_REQUIRED ); else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) return( ret ); #endif /* POLARSSL_RSA_C */ #if defined(POLARSSL_ECP_C) ret = pem_read_buffer( &pem, "-----BEGIN EC PRIVATE KEY-----", "-----END EC PRIVATE KEY-----", key, pwd, pwdlen, &len ); if( ret == 0 ) { if( ( pk_info = pk_info_from_type( POLARSSL_PK_ECKEY ) ) == NULL ) return( POLARSSL_ERR_PK_UNKNOWN_PK_ALG ); if( ( ret = pk_init_ctx( pk, pk_info ) ) != 0 || ( ret = pk_parse_key_sec1_der( pk_ec( *pk ), pem.buf, pem.buflen ) ) != 0 ) { pk_free( pk ); } pem_free( &pem ); return( ret ); } else if( ret == POLARSSL_ERR_PEM_PASSWORD_MISMATCH ) return( POLARSSL_ERR_PK_PASSWORD_MISMATCH ); else if( ret == POLARSSL_ERR_PEM_PASSWORD_REQUIRED ) return( POLARSSL_ERR_PK_PASSWORD_REQUIRED ); else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) return( ret ); #endif /* POLARSSL_ECP_C */ ret = pem_read_buffer( &pem, "-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----", key, NULL, 0, &len ); if( ret == 0 ) { if( ( ret = pk_parse_key_pkcs8_unencrypted_der( pk, pem.buf, pem.buflen ) ) != 0 ) { pk_free( pk ); } pem_free( &pem ); return( ret ); } else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) return( ret ); ret = pem_read_buffer( &pem, "-----BEGIN ENCRYPTED PRIVATE KEY-----", "-----END ENCRYPTED PRIVATE KEY-----", key, NULL, 0, &len ); if( ret == 0 ) { if( ( ret = pk_parse_key_pkcs8_encrypted_der( pk, pem.buf, pem.buflen, pwd, pwdlen ) ) != 0 ) { pk_free( pk ); } pem_free( &pem ); return( ret ); } else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) return( ret ); #else ((void) pwd); ((void) pwdlen); #endif /* POLARSSL_PEM_PARSE_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 = pk_parse_key_pkcs8_encrypted_der( pk, key, keylen, pwd, pwdlen ) ) == 0 ) { return( 0 ); } pk_free( pk ); if( ret == POLARSSL_ERR_PK_PASSWORD_MISMATCH ) { return( ret ); } if( ( ret = pk_parse_key_pkcs8_unencrypted_der( pk, key, keylen ) ) == 0 ) return( 0 ); pk_free( pk ); #if defined(POLARSSL_RSA_C) if( ( pk_info = pk_info_from_type( POLARSSL_PK_RSA ) ) == NULL ) return( POLARSSL_ERR_PK_UNKNOWN_PK_ALG ); if( ( ret = pk_init_ctx( pk, pk_info ) ) != 0 || ( ret = pk_parse_key_pkcs1_der( pk_rsa( *pk ), key, keylen ) ) == 0 ) { return( 0 ); } pk_free( pk ); #endif /* POLARSSL_RSA_C */ #if defined(POLARSSL_ECP_C) if( ( pk_info = pk_info_from_type( POLARSSL_PK_ECKEY ) ) == NULL ) return( POLARSSL_ERR_PK_UNKNOWN_PK_ALG ); if( ( ret = pk_init_ctx( pk, pk_info ) ) != 0 || ( ret = pk_parse_key_sec1_der( pk_ec( *pk ), key, keylen ) ) == 0 ) { return( 0 ); } pk_free( pk ); #endif /* POLARSSL_ECP_C */ return( POLARSSL_ERR_PK_KEY_INVALID_FORMAT ); }