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