- Added support for PKCS#8 wrapper on reading private keys (Fixes ticket #20)
diff --git a/library/x509parse.c b/library/x509parse.c
index c5da0fc..874cf0b 100644
--- a/library/x509parse.c
+++ b/library/x509parse.c
@@ -622,7 +622,7 @@
can_handle = 1;
if( can_handle == 0 )
- return( POLARSSL_ERR_X509_CERT_UNKNOWN_PK_ALG );
+ return( POLARSSL_ERR_X509_UNKNOWN_PK_ALG );
if( ( ret = asn1_get_tag( p, end, &len, ASN1_BIT_STRING ) ) != 0 )
return( POLARSSL_ERR_X509_CERT_INVALID_PUBKEY + ret );
@@ -1870,6 +1870,9 @@
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;
@@ -1879,6 +1882,14 @@
"-----END RSA PRIVATE KEY-----",
key, pwd, pwdlen, &len );
+ if( ret == POLARSSL_ERR_PEM_NO_HEADER_PRESENT )
+ {
+ ret = pem_read_buffer( &pem,
+ "-----BEGIN PRIVATE KEY-----",
+ "-----END PRIVATE KEY-----",
+ key, pwd, pwdlen, &len );
+ }
+
if( ret == 0 )
{
/*
@@ -1901,6 +1912,19 @@
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 {
+ * algorithm AlgorithmIdentifier,
+ * PrivateKey BIT STRING
+ * }
+ *
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL
+ * }
+ *
* RSAPrivateKey ::= SEQUENCE {
* version Version,
* modulus INTEGER, -- n
@@ -1944,6 +1968,110 @@
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
+ {
+ int can_handle;
+
+ /*
+ * only RSA keys handled at this time
+ */
+ can_handle = 0;
+
+ if( pk_alg_oid.len == 9 &&
+ memcmp( pk_alg_oid.p, OID_PKCS1_RSA, 9 ) == 0 )
+ can_handle = 1;
+
+ if( pk_alg_oid.len == 9 &&
+ memcmp( pk_alg_oid.p, OID_PKCS1, 8 ) == 0 )
+ {
+ if( pk_alg_oid.p[8] >= 2 && pk_alg_oid.p[8] <= 5 )
+ can_handle = 1;
+
+ if ( pk_alg_oid.p[8] >= 11 && pk_alg_oid.p[8] <= 14 )
+ can_handle = 1;
+ }
+
+ if( pk_alg_oid.len == 5 &&
+ memcmp( pk_alg_oid.p, OID_RSA_SHA_OBS, 5 ) == 0 )
+ can_handle = 1;
+
+ if( can_handle == 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 ||