Add parsing cache to `mbedtls_x509_crt`

This commit replaces the dummy implementation of the CRT acquire/release
framework by a cache-based implementation which remembers frame and PK
associated to a CRT across multiple `acquire/release` pairs.
diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h
index 25e8077..3f8350a 100644
--- a/include/mbedtls/x509_crt.h
+++ b/include/mbedtls/x509_crt.h
@@ -32,6 +32,7 @@
 
 #include "x509.h"
 #include "x509_crl.h"
+#include "threading.h"
 
 /**
  * \addtogroup x509_module
@@ -99,6 +100,22 @@
 
 } mbedtls_x509_crt_frame;
 
+/* This is an internal structure used for caching parsed data from an X.509 CRT.
+ *
+ * This structure may change at any time, and it is discouraged
+ * to access it directly.
+ */
+typedef struct mbedtls_x509_crt_cache
+{
+#if defined(MBEDTLS_THREADING_C)
+    mbedtls_threading_mutex_t frame_mutex;
+    mbedtls_threading_mutex_t pk_mutex;
+#endif
+    mbedtls_x509_buf_raw pk_raw;
+    mbedtls_x509_crt_frame *frame;
+    mbedtls_pk_context *pk;
+} mbedtls_x509_crt_cache;
+
 /**
  * Container for an X.509 certificate. The certificate may be chained.
  */
@@ -150,6 +167,8 @@
     mbedtls_pk_type_t sig_pk;           /**< Internal representation of the Public Key algorithm of the signature algorithm, e.g. MBEDTLS_PK_RSA */
     void *sig_opts;             /**< Signature options to be passed to mbedtls_pk_verify_ext(), e.g. for RSASSA-PSS */
 
+    mbedtls_x509_crt_cache *cache;     /**< Internal parsing cache. */
+
     struct mbedtls_x509_crt *next;     /**< Next certificate in the CA-chain. */
 }
 mbedtls_x509_crt;
@@ -643,6 +662,127 @@
  */
 void mbedtls_x509_crt_restart_free( mbedtls_x509_crt_restart_ctx *ctx );
 #endif /* MBEDTLS_ECDSA_C && MBEDTLS_ECP_RESTARTABLE */
+
+
+/**
+ * \brief           Flush internal X.509 CRT parsing cache, if present.
+ *
+ * \param crt       The CRT structure whose cache to flush.
+ *
+ * \note            Calling this function frequently reduces RAM usage
+ *                  at the cost of performance.
+ *
+ * \return          \c 0 on success.
+ * \return          A negative error code on failure.
+ */
+int mbedtls_x509_crt_flush_cache( mbedtls_x509_crt const *crt );
+
+/* Internal X.509 CRT cache handling functions.
+ * They are not part of the public API and may change
+ * at any time. */
+
+int mbedtls_x509_crt_cache_provide_frame( mbedtls_x509_crt const *crt );
+int mbedtls_x509_crt_cache_provide_pk( mbedtls_x509_crt const *crt );
+
+static inline int mbedtls_x509_crt_cache_frame_set(
+    mbedtls_x509_crt_cache *cache )
+{
+    return( cache->frame != NULL );
+}
+
+static inline mbedtls_x509_crt_frame* mbedtls_x509_crt_cache_get_frame(
+    mbedtls_x509_crt_cache *cache )
+{
+    return( cache->frame );
+}
+
+static inline int mbedtls_x509_crt_cache_pk_set(
+    mbedtls_x509_crt_cache *cache )
+{
+    return( cache->pk != NULL );
+}
+
+static inline mbedtls_pk_context* mbedtls_x509_crt_cache_get_pk(
+    mbedtls_x509_crt_cache *cache )
+{
+    return( cache->pk );
+}
+
+static inline int mbedtls_x509_crt_frame_acquire( mbedtls_x509_crt const *crt,
+                                         mbedtls_x509_crt_frame **frame_ptr )
+{
+#if defined(MBEDTLS_THREADING_C)
+    if( mbedtls_mutex_lock( &crt->cache->frame_mutex ) != 0 )
+        return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
+#endif
+
+    if( !mbedtls_x509_crt_cache_frame_set( crt->cache ) )
+    {
+        int ret;
+        ret = mbedtls_x509_crt_cache_provide_frame( crt );
+        if( ret != 0 )
+        {
+#if defined(MBEDTLS_THREADING_C)
+            if( mbedtls_mutex_unlock( &crt->cache->frame_mutex ) != 0 )
+                return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
+#endif
+            return( ret );
+        }
+    }
+
+    *frame_ptr = mbedtls_x509_crt_cache_get_frame( crt->cache );
+    return( 0 );
+}
+
+static inline void mbedtls_x509_crt_frame_release(
+    mbedtls_x509_crt const *crt,
+    mbedtls_x509_crt_frame *frame )
+{
+    ((void) frame);
+    ((void) crt);
+
+#if defined(MBEDTLS_THREADING_C)
+    mbedtls_mutex_unlock( &crt->cache->frame_mutex );
+#endif
+}
+
+static inline int mbedtls_x509_crt_pk_acquire( mbedtls_x509_crt *crt,
+                                               mbedtls_pk_context **pk_ptr )
+{
+#if defined(MBEDTLS_THREADING_C)
+    if( mbedtls_mutex_lock( &crt->cache->pk_mutex ) != 0 )
+        return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
+#endif
+
+    if( !mbedtls_x509_crt_cache_pk_set( crt->cache ) )
+    {
+        int ret;
+        ret = mbedtls_x509_crt_cache_provide_pk( crt );
+        if( ret != 0 )
+        {
+#if defined(MBEDTLS_THREADING_C)
+            if( mbedtls_mutex_unlock( &crt->cache->pk_mutex ) != 0 )
+                return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
+#endif
+            return( ret );
+        }
+    }
+
+    *pk_ptr = mbedtls_x509_crt_cache_get_pk( crt->cache );
+    return( 0 );
+}
+
+static inline void mbedtls_x509_crt_pk_release( mbedtls_x509_crt *crt,
+                                                mbedtls_pk_context *pk )
+{
+    ((void) pk);
+    ((void) crt);
+
+#if defined(MBEDTLS_THREADING_C)
+    mbedtls_mutex_unlock( &crt->cache->pk_mutex );
+#endif
+}
+
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
 /* \} name */
diff --git a/library/x509_crt.c b/library/x509_crt.c
index bf62f65..6c87959 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -93,55 +93,91 @@
 static void x509_free_sequence( mbedtls_x509_sequence *seq );
 static void x509_free_name( mbedtls_x509_name *name );
 
-static int x509_crt_pk_acquire( mbedtls_x509_crt *crt,
-                                mbedtls_pk_context **pk );
-static int x509_crt_frame_acquire( mbedtls_x509_crt const *crt,
-                                   mbedtls_x509_crt_frame **frame );
-static void x509_crt_pk_release( mbedtls_x509_crt *crt,
-                                 mbedtls_pk_context *pk );
-static void x509_crt_frame_release( mbedtls_x509_crt *crt,
-                                 mbedtls_pk_context *pk );
-
-static int x509_crt_frame_acquire( mbedtls_x509_crt const *crt,
-                                   mbedtls_x509_crt_frame **frame_ptr )
+int mbedtls_x509_crt_cache_provide_frame( mbedtls_x509_crt const *crt )
 {
-    int ret;
+    mbedtls_x509_crt_cache *cache = crt->cache;
     mbedtls_x509_crt_frame *frame;
 
     frame = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt_frame ) );
     if( frame == NULL )
         return( MBEDTLS_ERR_X509_ALLOC_FAILED );
+    cache->frame = frame;
 
-    ret = x509_crt_parse_frame( crt->raw.p, crt->raw.p + crt->raw.len,
-                                frame );
-    if( ret != 0 )
-        return( ret );
+    return( x509_crt_parse_frame( crt->raw.p,
+                                  crt->raw.p + crt->raw.len,
+                                  frame ) );
+}
 
-    *frame_ptr = frame;
+int mbedtls_x509_crt_cache_provide_pk( mbedtls_x509_crt const *crt )
+{
+    mbedtls_x509_crt_cache *cache = crt->cache;
+    mbedtls_pk_context *pk;
+
+    pk = mbedtls_calloc( 1, sizeof( mbedtls_pk_context ) );
+    if( pk == NULL )
+        return( MBEDTLS_ERR_X509_ALLOC_FAILED );
+    *pk = crt->pk;
+
+    cache->pk = pk;
     return( 0 );
 }
 
-static void x509_crt_frame_release( mbedtls_x509_crt const *crt,
-                                    mbedtls_x509_crt_frame *frame )
+static void x509_crt_cache_init( mbedtls_x509_crt_cache *cache )
 {
-    ((void) crt);
-    if( frame == NULL )
+    memset( cache, 0, sizeof( *cache ) );
+#if defined(MBEDTLS_THREADING_C)
+    mbedtls_mutex_init( &cache->frame_mutex );
+    mbedtls_mutex_init( &cache->pk_mutex );
+#endif
+}
+
+static void x509_crt_cache_clear_pk( mbedtls_x509_crt_cache *cache )
+{
+    /* The cache holds a shallow copy of the PK context
+     * in the legacy struct, so don't free PK context. */
+    mbedtls_free( cache->pk );
+    cache->pk = NULL;
+}
+
+static void x509_crt_cache_clear_frame( mbedtls_x509_crt_cache *cache )
+{
+    mbedtls_free( cache->frame );
+    cache->frame = NULL;
+}
+
+static void x509_crt_cache_free( mbedtls_x509_crt_cache *cache )
+{
+    if( cache == NULL )
         return;
-    mbedtls_free( frame );
-}
-static int x509_crt_pk_acquire( mbedtls_x509_crt *crt,
-                                mbedtls_pk_context **pk )
-{
-    *pk = &crt->pk;
-    return( 0 );
+
+#if defined(MBEDTLS_THREADING_C)
+    mbedtls_mutex_free( &cache->frame_mutex );
+    mbedtls_mutex_free( &cache->pk_mutex );
+#endif
+
+    x509_crt_cache_clear_frame( cache );
+    x509_crt_cache_clear_pk( cache );
+
+    memset( cache, 0, sizeof( *cache ) );
 }
 
-static void x509_crt_pk_release( mbedtls_x509_crt *crt,
-                                 mbedtls_pk_context *pk )
+int mbedtls_x509_crt_flush_cache( mbedtls_x509_crt const *crt )
 {
-    ((void) crt);
-    ((void) pk);
-    return;
+#if defined(MBEDTLS_THREADING_C)
+    if( mbedtls_mutex_lock( &crt->cache->frame_mutex ) != 0 )
+        return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
+    if( mbedtls_mutex_lock( &crt->cache->pk_mutex ) != 0 )
+        return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
+#endif
+    x509_crt_cache_clear_frame( crt->cache );
+    x509_crt_cache_clear_pk( crt->cache );
+#if defined(MBEDTLS_THREADING_C)
+    if( mbedtls_mutex_unlock( &crt->cache->frame_mutex ) != 0 )
+        return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
+    if( mbedtls_mutex_unlock( &crt->cache->pk_mutex ) != 0 )
+        return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
+#endif
+    return( 0 );
 }
 
 /*
@@ -1163,7 +1199,8 @@
                                     int make_copy )
 {
     int ret;
-    mbedtls_x509_crt_frame frame;
+    mbedtls_x509_crt_frame *frame;
+    mbedtls_x509_crt_cache *cache;
 
     if( crt == NULL || buf == NULL )
         return( MBEDTLS_ERR_X509_BAD_INPUT_DATA );
@@ -1185,19 +1222,21 @@
         crt->own_buffer = 1;
     }
 
-    /* Parse CRT frame.
-     * This omits:
-     * - Issuer, Subject
-     * - ExtKeyUsage, SubjectAltNames,
-     * - Time
-     * - PK
-     */
-    ret = x509_crt_parse_frame( crt->raw.p,
-                                crt->raw.p + crt->raw.len,
-                                &frame );
+    cache = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt_cache ) );
+    if( cache == NULL )
+    {
+        ret = MBEDTLS_ERR_X509_ALLOC_FAILED;
+        goto exit;
+    }
+    crt->cache = cache;
+    x509_crt_cache_init( cache );
+
+    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.
      *
@@ -1207,38 +1246,40 @@
      * need the size, and the garbage data doesn't need zeroization. */
     crt->raw.len = frame->raw.len;
 
+    cache->pk_raw = frame->pubkey_raw;
+
     /* 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;
-    crt->tbs.len = frame.tbs.len;
-    crt->serial.p   = frame.serial.p;
-    crt->serial.len = frame.serial.len;
-    crt->issuer_raw.p   = frame.issuer_raw_with_hdr.p;
-    crt->issuer_raw.len = frame.issuer_raw_with_hdr.len;
-    crt->subject_raw.p   = frame.subject_raw_with_hdr.p;
-    crt->subject_raw.len = frame.subject_raw_with_hdr.len;
-    crt->issuer_raw_no_hdr = frame.issuer_raw;
-    crt->subject_raw_no_hdr = frame.subject_raw;
-    crt->issuer_id.p   = frame.issuer_id.p;
-    crt->issuer_id.len = frame.issuer_id.len;
-    crt->subject_id.p   = frame.subject_id.p;
-    crt->subject_id.len = frame.subject_id.len;
-    crt->pk_raw.p   = frame.pubkey_raw.p;
-    crt->pk_raw.len = frame.pubkey_raw.len;
-    crt->ext_key_usage_raw = frame.ext_key_usage_raw;
-    crt->subject_alt_raw = frame.subject_alt_raw;
-    crt->sig.p   = frame.sig.p;
-    crt->sig.len = frame.sig.len;
-    crt->valid_from = frame.valid_from;
-    crt->valid_to = frame.valid_to;
-    crt->v3_ext.p   = frame.v3_ext.p;
-    crt->v3_ext.len = frame.v3_ext.len;
-    crt->version      = frame.version;
-    crt->ca_istrue    = frame.ca_istrue;
-    crt->max_pathlen  = frame.max_pathlen;
-    crt->ext_types    = frame.ext_types;
-    crt->key_usage    = frame.key_usage;
-    crt->ns_cert_type = frame.ns_cert_type;
+    crt->tbs.p   = frame->tbs.p;
+    crt->tbs.len = frame->tbs.len;
+    crt->serial.p   = frame->serial.p;
+    crt->serial.len = frame->serial.len;
+    crt->issuer_raw.p   = frame->issuer_raw_with_hdr.p;
+    crt->issuer_raw.len = frame->issuer_raw_with_hdr.len;
+    crt->subject_raw.p   = frame->subject_raw_with_hdr.p;
+    crt->subject_raw.len = frame->subject_raw_with_hdr.len;
+    crt->issuer_raw_no_hdr = frame->issuer_raw;
+    crt->subject_raw_no_hdr = frame->subject_raw;
+    crt->issuer_id.p   = frame->issuer_id.p;
+    crt->issuer_id.len = frame->issuer_id.len;
+    crt->subject_id.p   = frame->subject_id.p;
+    crt->subject_id.len = frame->subject_id.len;
+    crt->pk_raw.p   = frame->pubkey_raw.p;
+    crt->pk_raw.len = frame->pubkey_raw.len;
+    crt->ext_key_usage_raw = frame->ext_key_usage_raw;
+    crt->subject_alt_raw = frame->subject_alt_raw;
+    crt->sig.p   = frame->sig.p;
+    crt->sig.len = frame->sig.len;
+    crt->valid_from = frame->valid_from;
+    crt->valid_to = frame->valid_to;
+    crt->v3_ext.p   = frame->v3_ext.p;
+    crt->v3_ext.len = frame->v3_ext.len;
+    crt->version      = frame->version;
+    crt->ca_istrue    = frame->ca_istrue;
+    crt->max_pathlen  = frame->max_pathlen;
+    crt->ext_types    = frame->ext_types;
+    crt->key_usage    = frame->key_usage;
+    crt->ns_cert_type = frame->ns_cert_type;
 
     /*
      * Obtain the remaining fields from the frame.
@@ -1247,8 +1288,8 @@
     {
         /* sig_oid: Previously, needed for convenience in
          * mbedtls_x509_crt_info(), now pure legacy burden. */
-        unsigned char *tmp = frame.sig_alg.p;
-        unsigned char *end = tmp + frame.sig_alg.len;
+        unsigned char *tmp = frame->sig_alg.p;
+        unsigned char *end = tmp + frame->sig_alg.len;
         mbedtls_x509_buf sig_oid, sig_params;
 
         ret = mbedtls_x509_get_alg( &tmp, end,
@@ -1264,7 +1305,7 @@
         crt->sig_oid = sig_oid;
 
         /* Signature parameters */
-        tmp = frame.sig_alg.p;
+        tmp = frame->sig_alg.p;
         ret = mbedtls_x509_get_sig_alg_raw( &tmp, end,
                                             &crt->sig_md, &crt->sig_pk,
                                             &crt->sig_opts );
@@ -1276,23 +1317,31 @@
         }
     }
 
-    ret = x509_crt_pk_from_frame( &frame, &crt->pk );
+    ret = x509_crt_pk_from_frame( frame, &crt->pk );
     if( ret != 0 )
         goto exit;
 
-    ret = x509_crt_subject_from_frame( &frame, &crt->subject );
+    ret = x509_crt_subject_from_frame( frame, &crt->subject );
     if( ret != 0 )
         goto exit;
 
-    ret = x509_crt_issuer_from_frame( &frame, &crt->issuer );
+    ret = x509_crt_issuer_from_frame( frame, &crt->issuer );
     if( ret != 0 )
         goto exit;
 
-    ret = x509_crt_subject_alt_from_frame( &frame, &crt->subject_alt_names );
+    ret = x509_crt_subject_alt_from_frame( frame, &crt->subject_alt_names );
     if( ret != 0 )
         goto exit;
 
-    ret = x509_crt_ext_key_usage_from_frame( &frame, &crt->ext_key_usage );
+    ret = x509_crt_ext_key_usage_from_frame( frame, &crt->ext_key_usage );
+    if( ret != 0 )
+        goto exit;
+
+
+    /* The cache just references the PK structure from the legacy
+     * implementation, so set up the latter first before setting up
+     * the cache. */
+    ret = mbedtls_x509_crt_cache_provide_pk( crt );
     if( ret != 0 )
         goto exit;
 
@@ -1858,11 +1907,11 @@
         return( (int) ( size - n ) );
     }
 
-    ret = x509_crt_frame_acquire( crt_raw, &crt );
+    ret = mbedtls_x509_crt_frame_acquire( crt_raw, &crt );
     if( ret != 0 )
         return( MBEDTLS_ERR_X509_FATAL_ERROR );
 
-    ret = x509_crt_pk_acquire( (mbedtls_x509_crt*) crt_raw, &pk );
+    ret = mbedtls_x509_crt_pk_acquire( (mbedtls_x509_crt*) crt_raw, &pk );
     if( ret != 0 )
     {
         ret = MBEDTLS_ERR_X509_FATAL_ERROR;
@@ -2023,8 +2072,8 @@
 
 cleanup:
 
-    x509_crt_frame_release( crt_raw, crt );
-    x509_crt_pk_release( (mbedtls_x509_crt*) crt_raw, pk );
+    mbedtls_x509_crt_frame_release( crt_raw, crt );
+    mbedtls_x509_crt_pk_release( (mbedtls_x509_crt*) crt_raw, pk );
 
     x509_crt_free_sig_info( &sig_info );
     x509_free_name( issuer.next );
@@ -2122,12 +2171,13 @@
 {
     int ret;
     mbedtls_x509_crt_frame *frame;
-    ret = x509_crt_frame_acquire( crt, (mbedtls_x509_crt_frame**) &frame );
+    ret = mbedtls_x509_crt_frame_acquire( crt,
+                                          (mbedtls_x509_crt_frame**) &frame );
     if( ret != 0 )
         return( MBEDTLS_ERR_X509_FATAL_ERROR );
 
     ret = x509_crt_check_key_usage_frame( frame, usage );
-    x509_crt_frame_release( crt, (mbedtls_x509_crt_frame*) frame );
+    mbedtls_x509_crt_frame_release( crt, (mbedtls_x509_crt_frame*) frame );
 
     return( ret );
 }
@@ -2174,7 +2224,7 @@
     unsigned char *p, *end;
     x509_crt_check_ext_key_usage_cb_ctx_t cb_ctx = { usage_oid, usage_len };
 
-    ret = x509_crt_frame_acquire( crt, &frame );
+    ret = mbedtls_x509_crt_frame_acquire( crt, &frame );
     if( ret != 0 )
         return( MBEDTLS_ERR_X509_FATAL_ERROR );
 
@@ -2195,7 +2245,7 @@
             ret = MBEDTLS_ERR_X509_BAD_INPUT_DATA;
     }
 
-    x509_crt_frame_release( crt, frame );
+    mbedtls_x509_crt_frame_release( crt, frame );
     return( ret );
 }
 #endif /* MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE */
@@ -2231,14 +2281,14 @@
     int ret;
     mbedtls_x509_crt_frame *frame;
 
-    ret = x509_crt_frame_acquire( crt, &frame );
+    ret = mbedtls_x509_crt_frame_acquire( crt, &frame );
     if( ret != 0 )
         return( MBEDTLS_ERR_X509_FATAL_ERROR );
 
     ret = x509_serial_is_revoked( frame->serial.p,
                                   frame->serial.len,
                                   crl );
-    x509_crt_frame_release( crt, frame );
+    mbedtls_x509_crt_frame_release( crt, frame );
     return( ret );
 }
 
@@ -2265,7 +2315,7 @@
 
     {
         mbedtls_x509_crt_frame *ca;
-        ret = x509_crt_frame_acquire( ca_crt, &ca );
+        ret = mbedtls_x509_crt_frame_acquire( ca_crt, &ca );
         if( ret != 0 )
             return( MBEDTLS_X509_BADCRL_NOT_TRUSTED );
 
@@ -2278,10 +2328,10 @@
             can_sign = 1;
         }
 
-        x509_crt_frame_release( ca_crt, ca );
+        mbedtls_x509_crt_frame_release( ca_crt, ca );
     }
 
-    ret = x509_crt_pk_acquire( ca_crt, &pk );
+    ret = mbedtls_x509_crt_pk_acquire( ca_crt, &pk );
     if( ret != 0 )
         return( MBEDTLS_X509_BADCRL_NOT_TRUSTED );
 
@@ -2356,7 +2406,7 @@
         crl_list = crl_list->next;
     }
 
-    x509_crt_pk_release( ca_crt, pk );
+    mbedtls_x509_crt_pk_release( ca_crt, pk );
     return( flags );
 }
 #endif /* MBEDTLS_X509_CRL_PARSE_C */
@@ -2371,7 +2421,7 @@
     int ret;
     mbedtls_pk_context *pk;
 
-    ret = x509_crt_pk_acquire( parent, &pk );
+    ret = mbedtls_x509_crt_pk_acquire( parent, &pk );
     if( ret != 0 )
         return( MBEDTLS_ERR_X509_FATAL_ERROR );
 
@@ -2405,7 +2455,7 @@
     }
 
 exit:
-    x509_crt_pk_release( parent, pk );
+    mbedtls_x509_crt_pk_release( parent, pk );
     return( ret );
 }
 
@@ -2543,7 +2593,7 @@
         {
             mbedtls_x509_crt_frame *parent;
 
-            ret = x509_crt_frame_acquire( parent_crt, &parent );
+            ret = mbedtls_x509_crt_frame_acquire( parent_crt, &parent );
             if( ret != 0 )
                 return( MBEDTLS_ERR_X509_FATAL_ERROR );
 
@@ -2565,7 +2615,7 @@
                 path_len_ok = 1;
             }
 
-            x509_crt_frame_release( parent_crt, parent );
+            mbedtls_x509_crt_frame_release( parent_crt, parent );
         }
 
         if( parent_match == 0 || path_len_ok == 0 )
@@ -2836,7 +2886,7 @@
             {
                 mbedtls_x509_crt_frame *child;
 
-                ret = x509_crt_frame_acquire( child_crt, &child );
+                ret = mbedtls_x509_crt_frame_acquire( child_crt, &child );
                 if( ret != 0 )
                     return( MBEDTLS_ERR_X509_FATAL_ERROR );
 
@@ -2849,7 +2899,7 @@
                 /* Stop here for trusted roots (but not for trusted EE certs) */
                 if( child_is_trusted )
                 {
-                    x509_crt_frame_release( child_crt, child );
+                    mbedtls_x509_crt_frame_release( child_crt, child );
                     return( 0 );
                 }
 
@@ -2872,7 +2922,7 @@
                 if( ver_chain->len == 1 && self_issued &&
                     x509_crt_check_ee_locally_trusted( child, trust_ca ) == 0 )
                 {
-                    x509_crt_frame_release( child_crt, child );
+                    mbedtls_x509_crt_frame_release( child_crt, child );
                     return( 0 );
                 }
 
@@ -2881,8 +2931,8 @@
 #endif /* MBEDTLS_X509_CRL_PARSE_C */
 
                 ret = x509_crt_get_sig_info( child, &child_sig );
+                mbedtls_x509_crt_frame_release( child_crt, child );
 
-                x509_crt_frame_release( child_crt, child );
                 if( ret != 0 )
                     return( MBEDTLS_ERR_X509_FATAL_ERROR );
             }
@@ -2937,7 +2987,7 @@
 
         {
             mbedtls_pk_context *parent_pk;
-            ret = x509_crt_pk_acquire( parent_crt, &parent_pk );
+            ret = mbedtls_x509_crt_pk_acquire( parent_crt, &parent_pk );
             if( ret != 0 )
                 return( MBEDTLS_ERR_X509_FATAL_ERROR );
 
@@ -2945,7 +2995,7 @@
             if( x509_profile_check_key( profile, parent_pk ) != 0 )
                 *flags |= MBEDTLS_X509_BADCERT_BAD_KEY;
 
-            x509_crt_pk_release( parent_crt, parent_pk );
+            mbedtls_x509_crt_pk_release( parent_crt, parent_pk );
         }
 
 #if defined(MBEDTLS_X509_CRL_PARSE_C)
@@ -3037,7 +3087,7 @@
     int ret;
     mbedtls_x509_crt_frame *frame;
 
-    ret = x509_crt_frame_acquire( crt, &frame );
+    ret = mbedtls_x509_crt_frame_acquire( crt, &frame );
     if( ret != 0 )
         return( MBEDTLS_ERR_X509_FATAL_ERROR );
 
@@ -3063,7 +3113,7 @@
                                          x509_crt_check_name, (void*) cn );
     }
 
-    x509_crt_frame_release( crt, frame );
+    mbedtls_x509_crt_frame_release( crt, frame );
 
     /* x509_crt_check_name() and x509_crt_subject_alt_check_name()
      * return 1 when finding a name component matching `cn`. */
@@ -3181,7 +3231,7 @@
         mbedtls_pk_context *pk;
         mbedtls_pk_type_t pk_type;
 
-        ret = x509_crt_pk_acquire( crt, &pk );
+        ret = mbedtls_x509_crt_pk_acquire( crt, &pk );
         if( ret != 0 )
             return( MBEDTLS_ERR_X509_FATAL_ERROR );
 
@@ -3194,7 +3244,7 @@
         if( x509_profile_check_key( profile, pk ) != 0 )
             ee_flags |= MBEDTLS_X509_BADCERT_BAD_KEY;
 
-        x509_crt_pk_release( crt, pk );
+        mbedtls_x509_crt_pk_release( crt, pk );
     }
 
     /* Check the chain */
@@ -3278,6 +3328,8 @@
 
     do
     {
+        x509_crt_cache_free( cert_cur->cache );
+        mbedtls_free( cert_cur->cache );
         mbedtls_pk_free( &cert_cur->pk );
 
 #if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT)