New mbedtls_x509_crt_parse_der_ext() routine

This routine is functionally equivalent to mbedtls_x509_crt_parse_der(),
but it accepts an additional callback function which it calls with
every unsupported certificate extension.

Proposed solution to https://github.com/ARMmbed/mbedtls/issues/3241

Signed-off-by: Nicola Di Lieto <nicola.dilieto@gmail.com>
diff --git a/library/x509_crt.c b/library/x509_crt.c
index 1e62ed5..9076b32 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -892,7 +892,8 @@
  */
 static int x509_get_crt_ext( unsigned char **p,
                              const unsigned char *end,
-                             mbedtls_x509_crt *crt )
+                             mbedtls_x509_crt *crt,
+                             mbedtls_x509_crt_ext_cb_t cb )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     size_t len;
@@ -955,6 +956,10 @@
 
         if( ret != 0 )
         {
+            /* Give the callback (if any) a chance to handle the extension */
+            if (cb && cb(crt, &extn_oid, is_critical, p, end_ext_octet) == 0)
+                continue;
+
             /* No parser found, skip extension */
             *p = end_ext_octet;
 
@@ -1061,7 +1066,8 @@
 static int x509_crt_parse_der_core( mbedtls_x509_crt *crt,
                                     const unsigned char *buf,
                                     size_t buflen,
-                                    int make_copy )
+                                    int make_copy,
+                                    mbedtls_x509_crt_ext_cb_t cb )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     size_t len;
@@ -1260,7 +1266,7 @@
     if( crt->version == 3 )
 #endif
     {
-        ret = x509_get_crt_ext( &p, end, crt );
+        ret = x509_get_crt_ext( &p, end, crt, cb );
         if( ret != 0 )
         {
             mbedtls_x509_crt_free( crt );
@@ -1323,7 +1329,8 @@
 static int mbedtls_x509_crt_parse_der_internal( mbedtls_x509_crt *chain,
                                                 const unsigned char *buf,
                                                 size_t buflen,
-                                                int make_copy )
+                                                int make_copy,
+                                                mbedtls_x509_crt_ext_cb_t cb )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     mbedtls_x509_crt *crt = chain, *prev = NULL;
@@ -1355,7 +1362,8 @@
         crt = crt->next;
     }
 
-    if( ( ret = x509_crt_parse_der_core( crt, buf, buflen, make_copy ) ) != 0 )
+    ret = x509_crt_parse_der_core( crt, buf, buflen, make_copy, cb );
+    if( ret != 0 )
     {
         if( prev )
             prev->next = NULL;
@@ -1373,14 +1381,22 @@
                                        const unsigned char *buf,
                                        size_t buflen )
 {
-    return( mbedtls_x509_crt_parse_der_internal( chain, buf, buflen, 0 ) );
+    return( mbedtls_x509_crt_parse_der_internal( chain, buf, buflen, 0, NULL ) );
+}
+
+int mbedtls_x509_crt_parse_der_ext( mbedtls_x509_crt *chain,
+                                const unsigned char *buf,
+                                size_t buflen,
+                                mbedtls_x509_crt_ext_cb_t cb )
+{
+    return( mbedtls_x509_crt_parse_der_internal( chain, buf, buflen, 1, cb ) );
 }
 
 int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain,
                                 const unsigned char *buf,
                                 size_t buflen )
 {
-    return( mbedtls_x509_crt_parse_der_internal( chain, buf, buflen, 1 ) );
+    return( mbedtls_x509_crt_parse_der_internal( chain, buf, buflen, 1, NULL ) );
 }
 
 /*