Add X.509 CRT test for nested calls for CRT frame / PK acquire
diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data
index f8d7875..6536cc9 100644
--- a/tests/suites/test_suite_x509parse.data
+++ b/tests/suites/test_suite_x509parse.data
@@ -935,6 +935,10 @@
 depends_on:MBEDTLS_SHA1_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_CERTS_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
 x509_selftest:
 
+X509 nested acquire
+depends_on:MBEDTLS_RSA_C:MBEDTLS_SHA256_C
+x509_nested_acquire:"308196308180a0030201008204deadbeef300d06092a864886f70d01010b0500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092a864886f70d010101050003190030160210ffffffffffffffffffffffffffffffff0202ffff300d06092a864886f70d01010b0500030200ff"
+
 X509 CRT ASN1 (Empty Certificate)
 x509parse_crt:"":"":MBEDTLS_ERR_X509_INVALID_FORMAT
 
diff --git a/tests/suites/test_suite_x509parse.function b/tests/suites/test_suite_x509parse.function
index 2df187d..25b0d7f 100644
--- a/tests/suites/test_suite_x509parse.function
+++ b/tests/suites/test_suite_x509parse.function
@@ -597,6 +597,99 @@
 }
 /* END_CASE */
 
+/* BEGIN_CASE depends_on:MBEDTLS_X509_CRT_PARSE_C */
+void x509_nested_acquire( data_t * buf )
+{
+    /* This tests exercises the behavior of the library when
+     * facing nested calls to mbedtls_x509_crt_xxx_acquire().
+     * This is allowed if !MBEDTLS_X509_ALWAYS_FLUSH or
+     * MBEDTLS_THREADING_C, but forbidden otherwise. */
+
+    mbedtls_x509_crt crt;
+    mbedtls_x509_crt_init( &crt );
+    TEST_ASSERT( mbedtls_x509_crt_parse_der( &crt, buf->x, buf->len ) == 0 );
+
+    /* Nested aquire for CRT frames */
+    {
+        int ret;
+        mbedtls_x509_crt_frame const *frame1;
+        mbedtls_x509_crt_frame const *frame2;
+
+        /* Perform a (hopefully) innocent acquire-release pair first. */
+
+        TEST_ASSERT( mbedtls_x509_crt_frame_acquire( &crt, &frame1 ) == 0 );
+        TEST_ASSERT( mbedtls_x509_crt_frame_release( &crt ) == 0 );
+
+        /* Perform two nested acquire calls. */
+
+        TEST_ASSERT( mbedtls_x509_crt_frame_acquire( &crt, &frame1 ) == 0 );
+
+        ret = mbedtls_x509_crt_frame_acquire( &crt, &frame2 );
+#if defined(MBEDTLS_X509_ALWAYS_FLUSH) &&      \
+    !defined(MBEDTLS_THREADING_C)
+        TEST_ASSERT( ret == MBEDTLS_ERR_X509_FATAL_ERROR );
+#else
+        TEST_ASSERT( ret == 0 );
+        TEST_ASSERT( mbedtls_x509_crt_frame_release( &crt ) == 0 );
+#endif
+
+        TEST_ASSERT( mbedtls_x509_crt_frame_release( &crt ) == 0 );
+
+        ret = mbedtls_x509_crt_frame_release( &crt );
+
+        /* In contexts which use resource counting, we expect an
+         * error on an attempted release() without prior acquire(). */
+#if defined(MBEDTLS_X509_ALWAYS_FLUSH) &&      \
+    !defined(MBEDTLS_THREADING_C)
+        TEST_ASSERT( ret == 0 );
+#else
+        TEST_ASSERT( ret == MBEDTLS_ERR_X509_FATAL_ERROR );
+#endif
+    }
+
+    /* Nested aquire for PK contexts */
+    {
+        int ret;
+        mbedtls_pk_context *pk1;
+        mbedtls_pk_context *pk2;
+
+        /* Perform a (hopefully) innocent acquire-release pair first. */
+
+        TEST_ASSERT( mbedtls_x509_crt_pk_acquire( &crt, &pk1 ) == 0 );
+        TEST_ASSERT( mbedtls_x509_crt_pk_release( &crt ) == 0 );
+
+        /* Perform two nested acquire calls. */
+
+        TEST_ASSERT( mbedtls_x509_crt_pk_acquire( &crt, &pk1 ) == 0 );
+
+        ret = mbedtls_x509_crt_pk_acquire( &crt, &pk2 );
+#if defined(MBEDTLS_X509_ALWAYS_FLUSH) &&      \
+    !defined(MBEDTLS_THREADING_C)
+        TEST_ASSERT( ret == MBEDTLS_ERR_X509_FATAL_ERROR );
+#else
+        TEST_ASSERT( ret == 0 );
+        TEST_ASSERT( mbedtls_x509_crt_pk_release( &crt ) == 0 );
+#endif
+
+        TEST_ASSERT( mbedtls_x509_crt_pk_release( &crt ) == 0 );
+
+        ret = mbedtls_x509_crt_pk_release( &crt );
+
+        /* In contexts which use resource counting, we expect an
+         * error on an attempted release() without prior acquire(). */
+#if defined(MBEDTLS_X509_ALWAYS_FLUSH) &&      \
+    !defined(MBEDTLS_THREADING_C)
+        TEST_ASSERT( ret == 0 );
+#else
+        TEST_ASSERT( ret == MBEDTLS_ERR_X509_FATAL_ERROR );
+#endif
+    }
+
+exit:
+    mbedtls_x509_crt_free( &crt );
+}
+/* END_CASE */
+
 /* BEGIN_CASE depends_on:MBEDTLS_X509_CRL_PARSE_C:!MBEDTLS_X509_REMOVE_INFO */
 void x509parse_crl( data_t * buf, char * result_str, int result )
 {