Provide direct way of setting up a CRT frame from legacy CRT struct

Previously, `mbedtls_x509_crt_cache_provide_frame()` provided the requested
CRT frame by always parsing the raw data underlying the CRT. That's inefficient
in legacy mode, where the CRTs fields are permanently accessible through the
legacy `mbedtls_x509_crt` structure.

This commit modifies `mbedtls_x509_crt_cache_provide_frame()` in legacy mode
(that is, !MBEDTLS_X509_ON_DEMAND_PARSING) to setup the CRT frame by copying
fields from the legacy CRT structure.
diff --git a/library/x509_crt.c b/library/x509_crt.c
index 03222d5..bb064d6 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -90,6 +90,7 @@
 static int x509_crt_ext_key_usage_from_frame( mbedtls_x509_crt_frame *frame,
                                         mbedtls_x509_sequence *ext_key_usage );
 
+static int x509_crt_frame_parse_ext( mbedtls_x509_crt_frame *frame );
 int mbedtls_x509_crt_cache_provide_frame( mbedtls_x509_crt const *crt )
 {
     mbedtls_x509_crt_cache *cache = crt->cache;
@@ -100,9 +101,57 @@
         return( MBEDTLS_ERR_X509_ALLOC_FAILED );
     cache->frame = frame;
 
+#if defined(MBEDTLS_X509_ON_DEMAND_PARSING)
+    /* This would work with !MBEDTLS_X509_ON_DEMAND_PARSING, too,
+     * but is inefficient compared to copying the respective fields
+     * from the legacy mbedtls_x509_crt. */
     return( x509_crt_parse_frame( crt->raw.p,
                                   crt->raw.p + crt->raw.len,
                                   frame ) );
+#else /* MBEDTLS_X509_ON_DEMAND_PARSING */
+    /* Make sure all extension related fields are properly initialized. */
+    frame->ca_istrue = 0;
+    frame->max_pathlen = 0;
+    frame->ext_types = 0;
+    frame->version = crt->version;
+    frame->sig_md = crt->sig_md;
+    frame->sig_pk = crt->sig_pk;
+    frame->valid_from = crt->valid_from;
+    frame->valid_to = crt->valid_to;
+    frame->raw.p   = crt->raw.p;
+    frame->raw.len = crt->raw.len;
+    frame->tbs.p   = crt->tbs.p;
+    frame->tbs.len = crt->tbs.len;
+    frame->serial.p   = crt->serial.p;
+    frame->serial.len = crt->serial.len;
+    frame->pubkey_raw.p   = crt->pk_raw.p;
+    frame->pubkey_raw.len = crt->pk_raw.len;
+    frame->issuer_raw = crt->issuer_raw_no_hdr;
+    frame->subject_raw = crt->subject_raw_no_hdr;
+    frame->issuer_id.p   = crt->issuer_id.p;
+    frame->issuer_id.len = crt->issuer_id.len;
+    frame->subject_id.p   = crt->subject_id.p;
+    frame->subject_id.len = crt->subject_id.len;
+    frame->sig.p   = crt->sig.p;
+    frame->sig.len = crt->sig.len;
+    frame->v3_ext.p   = crt->v3_ext.p;
+    frame->v3_ext.len = crt->v3_ext.len;
+    frame->subject_alt_raw = crt->subject_alt_raw;
+    frame->ext_key_usage_raw = crt->ext_key_usage_raw;
+    frame->issuer_raw_with_hdr.p   = crt->issuer_raw.p;
+    frame->issuer_raw_with_hdr.len = crt->issuer_raw.len;
+    frame->subject_raw_with_hdr.p   = crt->subject_raw.p;
+    frame->subject_raw_with_hdr.len = crt->subject_raw.len;
+
+    /* The legacy CRT structure doesn't explicitly contain
+     * the `AlgorithmIdentifier` bounds; however, those can
+     * be inferred from the surrounding (mandatory) `SerialNumber`
+     * and `Issuer` fields. */
+    frame->sig_alg.p = crt->serial.p + crt->serial.len;
+    frame->sig_alg.len = crt->issuer_raw.p - frame->sig_alg.p;
+
+    return( x509_crt_frame_parse_ext( frame ) );
+#endif /* !MBEDTLS_X509_ON_DEMAND_PARSING */
 }
 
 int mbedtls_x509_crt_cache_provide_pk( mbedtls_x509_crt const *crt )
@@ -1376,24 +1425,30 @@
     crt->cache = cache;
     x509_crt_cache_init( cache );
 
+#if defined(MBEDTLS_X509_ON_DEMAND_PARSING)
+
     ret = mbedtls_x509_crt_cache_provide_frame( crt );
     if( ret != 0 )
         goto exit;
 
     frame = mbedtls_x509_crt_cache_get_frame( crt->cache );
 
-    /* Currently, we accept DER encoded CRTs with trailing garbage
-     * and promise to not account for the garbage in the `raw` field.
-     *
-     * Note that this means that `crt->raw.len` is not necessarily the
-     * full size of the heap buffer allocated at `crt->raw.p` in case
-     * of copy-mode, but this is not a problem: freeing the buffer doesn't
-     * need the size, and the garbage data doesn't need zeroization. */
-    crt->raw.len = frame->raw.len;
+#else /* MBEDTLS_X509_ON_DEMAND_PARSING */
 
-    cache->pk_raw = frame->pubkey_raw;
+    frame = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt_frame ) );
+    if( frame == NULL )
+    {
+        ret = MBEDTLS_ERR_X509_ALLOC_FAILED;
+        goto exit;
+    }
+    cache->frame = frame;
 
-#if !defined(MBEDTLS_X509_ON_DEMAND_PARSING)
+    ret = x509_crt_parse_frame( crt->raw.p,
+                                crt->raw.p + crt->raw.len,
+                                frame );
+    if( ret != 0 )
+        goto exit;
+
     /* Copy frame to legacy CRT structure -- that's inefficient, but if
      * memory matters, the new CRT structure should be used anyway. */
     crt->tbs.p   = frame->tbs.p;
@@ -1484,6 +1539,17 @@
         goto exit;
 #endif /* !MBEDTLS_X509_ON_DEMAND_PARSING */
 
+    /* Currently, we accept DER encoded CRTs with trailing garbage
+     * and promise to not account for the garbage in the `raw` field.
+     *
+     * Note that this means that `crt->raw.len` is not necessarily the
+     * full size of the heap buffer allocated at `crt->raw.p` in case
+     * of copy-mode, but this is not a problem: freeing the buffer doesn't
+     * need the size, and the garbage data doesn't need zeroization. */
+    crt->raw.len = frame->raw.len;
+
+    cache->pk_raw = frame->pubkey_raw;
+
     /* Free the frame before parsing the public key to
      * keep peak RAM usage low. This is slightly inefficient
      * because the frame will need to be parsed again on the