- Added permissive certificate parsing to x509parse_crt() and x509parse_crtfile(). With permissive parsing the parsing does not stop on encountering a parse-error
diff --git a/library/x509parse.c b/library/x509parse.c
index e14a163..326c986 100644
--- a/library/x509parse.c
+++ b/library/x509parse.c
@@ -1006,20 +1006,13 @@
}
/*
- * Parse one or more certificates and add them to the chained list
+ * Parse and fill a single X.509 certificate in DER format
*/
-int x509parse_crt( x509_cert *chain, const unsigned char *buf, size_t buflen )
+int x509parse_crt_der( x509_cert *crt, const unsigned char *buf, size_t buflen )
{
int ret;
size_t len;
unsigned char *p, *end;
- x509_cert *crt;
-#if defined(POLARSSL_PEM_C)
- pem_context pem;
- size_t use_len;
-#endif
-
- crt = chain;
/*
* Check for valid input
@@ -1027,69 +1020,6 @@
if( crt == NULL || buf == NULL )
return( 1 );
- while( crt->version != 0 && crt->next != NULL )
- crt = crt->next;
-
- /*
- * Add new certificate on the end of the chain if needed.
- */
- if ( crt->version != 0 && crt->next == NULL)
- {
- crt->next = (x509_cert *) malloc( sizeof( x509_cert ) );
-
- if( crt->next == NULL )
- {
- x509_free( crt );
- return( 1 );
- }
-
- crt = crt->next;
- memset( crt, 0, sizeof( x509_cert ) );
- }
-
-#if defined(POLARSSL_PEM_C)
- pem_init( &pem );
- ret = pem_read_buffer( &pem,
- "-----BEGIN CERTIFICATE-----",
- "-----END CERTIFICATE-----",
- buf, NULL, 0, &use_len );
-
- if( ret == 0 )
- {
- /*
- * Was PEM encoded
- */
- buflen -= use_len;
- buf += use_len;
-
- /*
- * Steal PEM buffer
- */
- p = pem.buf;
- pem.buf = NULL;
- len = pem.buflen;
- pem_free( &pem );
- }
- else if( ret != POLARSSL_ERR_PEM_NO_HEADER_PRESENT )
- {
- pem_free( &pem );
- return( ret );
- }
- else
- {
- /*
- * nope, copy the raw DER data
- */
- p = (unsigned char *) malloc( len = buflen );
-
- if( p == NULL )
- return( 1 );
-
- memcpy( p, buf, buflen );
-
- buflen = 0;
- }
-#else
p = (unsigned char *) malloc( len = buflen );
if( p == NULL )
@@ -1098,7 +1028,6 @@
memcpy( p, buf, buflen );
buflen = 0;
-#endif
crt->raw.p = p;
crt->raw.len = len;
@@ -1324,23 +1253,154 @@
POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
}
- if( buflen > 0 )
+ return( 0 );
+}
+
+/*
+ * Parse one or more PEM certificates from a buffer and add them to the chained list
+ */
+int x509parse_crt( x509_cert *chain, const unsigned char *buf, size_t buflen,
+ int permissive )
+{
+ int ret, success = 0, first_error = 0;
+ x509_cert *crt, *prev = NULL;
+ int buf_format = X509_FORMAT_DER;
+
+ crt = chain;
+
+ /*
+ * Check for valid input
+ */
+ if( crt == NULL || buf == NULL )
+ return( 1 );
+
+ while( crt->version != 0 && crt->next != NULL )
+ {
+ prev = crt;
+ crt = crt->next;
+ }
+
+ /*
+ * Add new certificate on the end of the chain if needed.
+ */
+ if ( crt->version != 0 && crt->next == NULL)
{
crt->next = (x509_cert *) malloc( sizeof( x509_cert ) );
if( crt->next == NULL )
- {
- x509_free( crt );
return( 1 );
- }
+ prev = crt;
crt = crt->next;
memset( crt, 0, sizeof( x509_cert ) );
-
- return( x509parse_crt( crt, buf, buflen ) );
}
- return( 0 );
+ /*
+ * Determine buffer content. Buffer contains either one DER certificate or
+ * one or more PEM certificates.
+ */
+#if defined(POLARSSL_PEM_C)
+ if( strstr( (char *) buf, "-----BEGIN CERTIFICATE-----" ) != NULL )
+ buf_format = X509_FORMAT_PEM;
+#endif
+
+ if( buf_format == X509_FORMAT_DER )
+ return x509parse_crt_der( crt, buf, buflen );
+
+#if defined(POLARSSL_PEM_C)
+ if( buf_format == X509_FORMAT_PEM )
+ {
+ pem_context pem;
+
+ while( buflen > 0 )
+ {
+ size_t use_len;
+ pem_init( &pem );
+
+ ret = pem_read_buffer( &pem,
+ "-----BEGIN CERTIFICATE-----",
+ "-----END CERTIFICATE-----",
+ buf, NULL, 0, &use_len );
+
+ if( ret == 0 )
+ {
+ /*
+ * Was PEM encoded
+ */
+ buflen -= use_len;
+ buf += use_len;
+ }
+ else if( ret != POLARSSL_ERR_PEM_NO_HEADER_PRESENT )
+ {
+ pem_free( &pem );
+
+ if( first_error == 0 )
+ first_error = ret;
+
+ continue;
+ }
+ else
+ break;
+
+ ret = x509parse_crt_der( crt, pem.buf, pem.buflen );
+
+ pem_free( &pem );
+
+ if( ret != 0 )
+ {
+ /*
+ * quit parsing on a memory error or if in non-permissive parsing mode
+ */
+ if( ret == 1 || permissive != 1 )
+ {
+ if( prev )
+ prev->next = NULL;
+
+ if( crt != chain )
+ free( crt );
+
+ return( ret );
+ }
+
+ if( first_error == 0 )
+ first_error = ret;
+
+ memset( crt, 0, sizeof( x509_cert ) );
+ continue;
+ }
+
+ success = 1;
+
+ /*
+ * Add new certificate to the list
+ */
+ crt->next = (x509_cert *) malloc( sizeof( x509_cert ) );
+
+ if( crt->next == NULL )
+ return( 1 );
+
+ prev = crt;
+ crt = crt->next;
+ memset( crt, 0, sizeof( x509_cert ) );
+ }
+ }
+#endif
+
+ if( crt->version == 0 )
+ {
+ if( prev )
+ prev->next = NULL;
+
+ if( crt != chain )
+ free( crt );
+ }
+
+ if( success )
+ return( 0 );
+ else if( first_error )
+ return( first_error );
+ else
+ return( POLARSSL_ERR_X509_CERT_UNKNOWN_FORMAT );
}
/*
@@ -1667,7 +1727,7 @@
/*
* Load one or more certificates and add them to the chained list
*/
-int x509parse_crtfile( x509_cert *chain, const char *path )
+int x509parse_crtfile( x509_cert *chain, const char *path, int permissive )
{
int ret;
size_t n;
@@ -1676,7 +1736,7 @@
if ( load_file( path, &buf, &n ) )
return( 1 );
- ret = x509parse_crt( chain, buf, n );
+ ret = x509parse_crt( chain, buf, n, permissive );
memset( buf, 0, n + 1 );
free( buf );
@@ -3099,7 +3159,7 @@
memset( &clicert, 0, sizeof( x509_cert ) );
ret = x509parse_crt( &clicert, (unsigned char *) test_cli_crt,
- strlen( test_cli_crt ) );
+ strlen( test_cli_crt ), X509_NON_PERMISSIVE );
if( ret != 0 )
{
if( verbose != 0 )
@@ -3111,7 +3171,7 @@
memset( &cacert, 0, sizeof( x509_cert ) );
ret = x509parse_crt( &cacert, (unsigned char *) test_ca_crt,
- strlen( test_ca_crt ) );
+ strlen( test_ca_crt ), X509_NON_PERMISSIVE );
if( ret != 0 )
{
if( verbose != 0 )