Merge pull request #4020 from gilles-peskine-arm/ssl_test_lib-hmac_drg

Support HMAC_DRBG in SSL test programs
diff --git a/docs/architecture/testing/psa-storage-format-testing.md b/docs/architecture/testing/psa-storage-format-testing.md
new file mode 100644
index 0000000..71bf968
--- /dev/null
+++ b/docs/architecture/testing/psa-storage-format-testing.md
@@ -0,0 +1,103 @@
+# Mbed TLS PSA keystore format stability testing strategy
+
+## Introduction
+
+The PSA crypto subsystem includes a persistent key store. It is possible to create a persistent key and read it back later. This must work even if Mbed TLS has been upgraded in the meantime (except for deliberate breaks in the backward compatibility of the storage).
+
+The goal of this document is to define a test strategy for the key store that not only validates that it's possible to load a key that was saved with the version of Mbed TLS under test, but also that it's possible to load a key that was saved with previous versions of Mbed TLS.
+
+Interoperability is not a goal: PSA crypto implementations are not intended to have compatible storage formats. Downgrading is not required to work.
+
+## General approach
+
+### Limitations of a direct approach
+
+The goal of storage format stability testing is: as a user of Mbed TLS, I want to store a key under version V and read it back under version W, with W ≥ V.
+
+Doing the testing this way would be difficult because we'd need to have version V of Mbed TLS available when testing version W.
+
+An alternative, semi-direct approach consists of generating test data under version V, and reading it back under version W. Done naively, this would require keeping a large amount of test data (full test coverage multiplied by the number of versions that we want to preserve backward compatibility with).
+
+### Save-and-compare approach
+
+Importing and saving a key is deterministic. Therefore we can ensure the stability of the storage format by creating test cases under a version V of Mbed TLS, where the test case parameters include both the parameters to pass to key creation and the expected state of the storage after the key is created. The test case creates a key as indicated by the parameters, then compares the actual state of the storage with the expected state. In addition, the test case also loads the key and checks that it has the expected data and metadata.
+
+If the test passes with version V, this means that the test data is consistent with what the implementation does. When the test later runs under version W ≥ V, it creates and reads back a storage state which is known to be identical to the state that V would have produced. Thus, this approach validates that W can read storage states created by V.
+
+Use a similar approach for files other than keys where possible and relevant.
+
+### Keeping up with storage format evolution
+
+Test cases should normally not be removed from the code base: if something has worked before, it should keep working in future versions, so we should keep testing it.
+
+If the way certain keys are stored changes, and we don't deliberately decide to stop supporting old keys (which should only be done by retiring a version of the storage format), then we should keep the corresponding test cases in load-only mode: create a file with the expected content, load it and check the data that it contains.
+
+## Storage architecture overview
+
+The PSA subsystem provides storage on top of the PSA trusted storage interface. The state of the storage is a mapping from file identifer (a 64-bit number) to file content (a byte array). These files include:
+
+* [Key files](#key-storage) (files containing one key's metadata and, except for some secure element keys, key material).
+* The [random generator injected seed or state file](#random-generator-state) (`PSA_CRYPTO_ITS_RANDOM_SEED_UID`).
+* [Storage transaction file](#storage-transaction-resumption).
+* [Driver state files](#driver-state-files).
+
+For a more detailed description, refer to the [Mbed Crypto storage specification](../mbed-crypto-storage-specification.md).
+
+In addition, Mbed TLS includes an implementation of the PSA trusted storage interface on top of C stdio. This document addresses the test strategy for [PSA ITS over file](#psa-its-over-file) in a separate section below.
+
+## Key storage testing
+
+This section describes the desired test cases for keys created with the current storage format version. When the storage format changes, if backward compatibility is desired, old test data should be kept as described under [“Keeping up with storage format evolution”](#keeping-up-with-storage-format-evolution).
+
+### Keystore layout
+
+Objective: test that the key file name corresponds to the key identifier.
+
+Method: Create a key with a given identifier (using `psa_import_key`) and verify that a file with the expected name is created, and no other. Repeat for different identifiers.
+
+### General key format
+
+Objective: test the format of the key file: which field goes where and how big it is.
+
+Method: Create a key with certain metadata with `psa_import_key`. Read the file content and validate that it has the expected layout, deduced from the storage specification. Repeat with different metadata. Ensure that there are test cases covering all fields.
+
+### Enumeration of test cases for keys
+
+Objective: ensure that the coverage is sufficient to have assurance that all keys are stored correctly. This requires a sufficient selection of key types, sizes, policies, etc.
+
+In particular, the tests must validate that each `PSA_xxx` constant that is stored in a key is covered by at least once test case:
+
+* Usage flags: `PSA_KEY_USAGE_xxx`.
+* Algorithms in policies: `PSA_ALG_xxx`.
+* Key types: `PSA_KEY_TYPE_xxx`, `PSA_ECC_FAMILY_xxx`, `PSA_DH_FAMILY_xxx`.
+
+Method: Each test case creates a key with `psa_import_key`, purges it from memory, then reads it back and exercises it. Generate test cases automatically based on an enumeration of available constants and some knowledge of what attributes (sizes, algorithms, …) and content to use for keys of a certain type. Note that the generated test cases will be checked into the repository (generating test cases at runtime would not allow us to test the stability of the format, only that a given version is internally consistent).
+
+### Testing with alternative lifetime values
+
+Objective: have test coverage for lifetimes other than the default persistent lifetime (`PSA_KEY_LIFETIME_PERSISTENT`).
+
+Method:
+
+* For alternative locations: have tests conditional on the presence of a driver for that location.
+* For alternative persistence levels: TODO
+
+## Random generator state
+
+TODO
+
+## Driver state files
+
+Not yet implemented.
+
+TODO
+
+## Storage transaction resumption
+
+Only relevant for secure element support. Not yet fully implemented.
+
+TODO
+
+## PSA ITS over file
+
+TODO
diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h
index accf51e..7f403c1 100644
--- a/include/mbedtls/check_config.h
+++ b/include/mbedtls/check_config.h
@@ -886,6 +886,10 @@
 #error "MBEDTLS_SSL_DTLS_SRTP defined, but not all prerequisites"
 #endif
 
+#if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) && ( !defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) )
+#error "MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH defined, but not all prerequisites"
+#endif
+
 /*
  * Avoid warning from -pedantic. This is a convenient place for this
  * workaround since this is included by every single file before the
diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h
index c5f65e1..b563a96 100644
--- a/include/mbedtls/config.h
+++ b/include/mbedtls/config.h
@@ -1979,7 +1979,10 @@
 /**
  * \def MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH
  *
- * Enable modifying the maximum I/O buffer size.
+ * When this option is enabled, the SSL buffer will be resized automatically
+ * based on the negotiated maximum fragment length in each direction.
+ *
+ * Requires: MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
  */
 //#define MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH
 
diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h
index 577c959..2097a6d 100644
--- a/include/mbedtls/ssl_internal.h
+++ b/include/mbedtls/ssl_internal.h
@@ -275,26 +275,26 @@
 #endif
 
 #if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH)
-static inline uint32_t mbedtls_ssl_get_output_buflen( const mbedtls_ssl_context *ctx )
+static inline size_t mbedtls_ssl_get_output_buflen( const mbedtls_ssl_context *ctx )
 {
 #if defined (MBEDTLS_SSL_DTLS_CONNECTION_ID)
-    return (uint32_t) mbedtls_ssl_get_output_max_frag_len( ctx )
+    return mbedtls_ssl_get_output_max_frag_len( ctx )
                + MBEDTLS_SSL_HEADER_LEN + MBEDTLS_SSL_PAYLOAD_OVERHEAD
                + MBEDTLS_SSL_CID_OUT_LEN_MAX;
 #else
-    return (uint32_t) mbedtls_ssl_get_output_max_frag_len( ctx )
+    return mbedtls_ssl_get_output_max_frag_len( ctx )
                + MBEDTLS_SSL_HEADER_LEN + MBEDTLS_SSL_PAYLOAD_OVERHEAD;
 #endif
 }
 
-static inline uint32_t mbedtls_ssl_get_input_buflen( const mbedtls_ssl_context *ctx )
+static inline size_t mbedtls_ssl_get_input_buflen( const mbedtls_ssl_context *ctx )
 {
 #if defined (MBEDTLS_SSL_DTLS_CONNECTION_ID)
-    return (uint32_t) mbedtls_ssl_get_input_max_frag_len( ctx )
+    return mbedtls_ssl_get_input_max_frag_len( ctx )
                + MBEDTLS_SSL_HEADER_LEN + MBEDTLS_SSL_PAYLOAD_OVERHEAD
                + MBEDTLS_SSL_CID_IN_LEN_MAX;
 #else
-    return (uint32_t) mbedtls_ssl_get_input_max_frag_len( ctx )
+    return mbedtls_ssl_get_input_max_frag_len( ctx )
                + MBEDTLS_SSL_HEADER_LEN + MBEDTLS_SSL_PAYLOAD_OVERHEAD;
 #endif
 }
diff --git a/library/ecjpake.c b/library/ecjpake.c
index 315da4a..bd47169 100644
--- a/library/ecjpake.c
+++ b/library/ecjpake.c
@@ -820,6 +820,8 @@
     0x65, 0x73, 0x74
 };
 
+#if !defined(MBEDTLS_ECJPAKE_ALT)
+
 static const unsigned char ecjpake_test_x1[] = {
     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
     0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
@@ -964,6 +966,8 @@
     return( ret );
 }
 
+#endif /* ! MBEDTLS_ECJPAKE_ALT */
+
 /* For tests we don't need a secure RNG;
  * use the LGC from Numerical Recipes for simplicity */
 static int ecjpake_lgc( void *p, unsigned char *out, size_t len )
@@ -1059,6 +1063,12 @@
     if( verbose != 0 )
         mbedtls_printf( "passed\n" );
 
+#if !defined(MBEDTLS_ECJPAKE_ALT)
+    /* 'reference handshake' tests can only be run against implementations
+     * for which we have 100% control over how the random ephemeral keys
+     * are generated. This is only the case for the internal mbed TLS
+     * implementation, so these tests are skipped in case the internal
+     * implementation is swapped out for an alternative one. */
     if( verbose != 0 )
         mbedtls_printf( "  ECJPAKE test #2 (reference handshake): " );
 
@@ -1107,6 +1117,7 @@
 
     if( verbose != 0 )
         mbedtls_printf( "passed\n" );
+#endif /* ! MBEDTLS_ECJPAKE_ALT */
 
 cleanup:
     mbedtls_ecjpake_free( &cli );
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index a1a5859..336cbea 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -260,6 +260,70 @@
 
     return 0;
 }
+
+static void handle_buffer_resizing( mbedtls_ssl_context *ssl, int downsizing,
+                                    size_t in_buf_new_len,
+                                    size_t out_buf_new_len )
+{
+    int modified = 0;
+    size_t written_in = 0, iv_offset_in = 0, len_offset_in = 0;
+    size_t written_out = 0, iv_offset_out = 0, len_offset_out = 0;
+    if( ssl->in_buf != NULL )
+    {
+        written_in = ssl->in_msg - ssl->in_buf;
+        iv_offset_in = ssl->in_iv - ssl->in_buf;
+        len_offset_in = ssl->in_len - ssl->in_buf;
+        if( downsizing ?
+            ssl->in_buf_len > in_buf_new_len && ssl->in_left < in_buf_new_len :
+            ssl->in_buf_len < in_buf_new_len )
+        {
+            if( resize_buffer( &ssl->in_buf, in_buf_new_len, &ssl->in_buf_len ) != 0 )
+            {
+                MBEDTLS_SSL_DEBUG_MSG( 1, ( "input buffer resizing failed - out of memory" ) );
+            }
+            else
+            {
+                MBEDTLS_SSL_DEBUG_MSG( 2, ( "Reallocating in_buf to %d", in_buf_new_len ) );
+                modified = 1;
+            }
+        }
+    }
+
+    if( ssl->out_buf != NULL )
+    {
+        written_out = ssl->out_msg - ssl->out_buf;
+        iv_offset_out = ssl->out_iv - ssl->out_buf;
+        len_offset_out = ssl->out_len - ssl->out_buf;
+        if( downsizing ?
+            ssl->out_buf_len > out_buf_new_len && ssl->out_left < out_buf_new_len :
+            ssl->out_buf_len < out_buf_new_len )
+        {
+            if( resize_buffer( &ssl->out_buf, out_buf_new_len, &ssl->out_buf_len ) != 0 )
+            {
+                MBEDTLS_SSL_DEBUG_MSG( 1, ( "output buffer resizing failed - out of memory" ) );
+            }
+            else
+            {
+                MBEDTLS_SSL_DEBUG_MSG( 2, ( "Reallocating out_buf to %d", out_buf_new_len ) );
+                modified = 1;
+            }
+        }
+    }
+    if( modified )
+    {
+        /* Update pointers here to avoid doing it twice. */
+        mbedtls_ssl_reset_in_out_pointers( ssl );
+        /* Fields below might not be properly updated with record
+         * splitting or with CID, so they are manually updated here. */
+        ssl->out_msg = ssl->out_buf + written_out;
+        ssl->out_len = ssl->out_buf + len_offset_out;
+        ssl->out_iv = ssl->out_buf + iv_offset_out;
+
+        ssl->in_msg = ssl->in_buf + written_in;
+        ssl->in_len = ssl->in_buf + len_offset_in;
+        ssl->in_iv = ssl->in_buf + iv_offset_in;
+    }
+}
 #endif /* MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH */
 
 /*
@@ -3686,64 +3750,9 @@
     }
 #if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH)
     /* If the buffers are too small - reallocate */
-    {
-        int modified = 0;
-        size_t written_in = 0, iv_offset_in = 0, len_offset_in = 0;
-        size_t written_out = 0, iv_offset_out = 0, len_offset_out = 0;
-        if( ssl->in_buf != NULL )
-        {
-            written_in = ssl->in_msg - ssl->in_buf;
-            iv_offset_in = ssl->in_iv - ssl->in_buf;
-            len_offset_in = ssl->in_len - ssl->in_buf;
-            if( ssl->in_buf_len < MBEDTLS_SSL_IN_BUFFER_LEN )
-            {
-                if( resize_buffer( &ssl->in_buf, MBEDTLS_SSL_IN_BUFFER_LEN,
-                                   &ssl->in_buf_len ) != 0 )
-                {
-                    MBEDTLS_SSL_DEBUG_MSG( 1, ( "input buffer resizing failed - out of memory" ) );
-                }
-                else
-                {
-                    MBEDTLS_SSL_DEBUG_MSG( 2, ( "Reallocating in_buf to %d", MBEDTLS_SSL_IN_BUFFER_LEN ) );
-                    modified = 1;
-                }
-            }
-        }
 
-        if( ssl->out_buf != NULL )
-        {
-            written_out = ssl->out_msg - ssl->out_buf;
-            iv_offset_out = ssl->out_iv - ssl->out_buf;
-            len_offset_out = ssl->out_len - ssl->out_buf;
-            if( ssl->out_buf_len < MBEDTLS_SSL_OUT_BUFFER_LEN )
-            {
-                if( resize_buffer( &ssl->out_buf, MBEDTLS_SSL_OUT_BUFFER_LEN,
-                                   &ssl->out_buf_len ) != 0 )
-                {
-                    MBEDTLS_SSL_DEBUG_MSG( 1, ( "output buffer resizing failed - out of memory" ) );
-                }
-                else
-                {
-                    MBEDTLS_SSL_DEBUG_MSG( 2, ( "Reallocating out_buf to %d", MBEDTLS_SSL_OUT_BUFFER_LEN ) );
-                    modified = 1;
-                }
-            }
-        }
-        if( modified )
-        {
-            /* Update pointers here to avoid doing it twice. */
-            mbedtls_ssl_reset_in_out_pointers( ssl );
-            /* Fields below might not be properly updated with record
-             * splitting or with CID, so they are manually updated here. */
-            ssl->out_msg = ssl->out_buf + written_out;
-            ssl->out_len = ssl->out_buf + len_offset_out;
-            ssl->out_iv = ssl->out_buf + iv_offset_out;
-
-            ssl->in_msg = ssl->in_buf + written_in;
-            ssl->in_len = ssl->in_buf + len_offset_in;
-            ssl->in_iv = ssl->in_buf + iv_offset_in;
-        }
-    }
+    handle_buffer_resizing( ssl, 0, MBEDTLS_SSL_IN_BUFFER_LEN,
+                                    MBEDTLS_SSL_OUT_BUFFER_LEN );
 #endif
 
     /* All pointers should exist and can be directly freed without issue */
@@ -6068,66 +6077,8 @@
      * processes datagrams and the fact that a datagram is allowed to have
      * several records in it, it is possible that the I/O buffers are not
      * empty at this stage */
-    {
-        int modified = 0;
-        uint32_t buf_len = mbedtls_ssl_get_input_buflen( ssl );
-        size_t written_in = 0, iv_offset_in = 0, len_offset_in = 0;
-        size_t written_out = 0, iv_offset_out = 0, len_offset_out = 0;
-        if( ssl->in_buf != NULL )
-        {
-            written_in = ssl->in_msg - ssl->in_buf;
-            iv_offset_in = ssl->in_iv - ssl->in_buf;
-            len_offset_in = ssl->in_len - ssl->in_buf;
-            if( ssl->in_buf_len > buf_len && ssl->in_left < buf_len )
-            {
-                if( resize_buffer( &ssl->in_buf, buf_len, &ssl->in_buf_len ) != 0 )
-                {
-                    MBEDTLS_SSL_DEBUG_MSG( 1, ( "input buffer resizing failed - out of memory" ) );
-                }
-                else
-                {
-                    MBEDTLS_SSL_DEBUG_MSG( 2, ( "Reallocating in_buf to %d", buf_len ) );
-                    modified = 1;
-                }
-            }
-        }
-
-
-        buf_len = mbedtls_ssl_get_output_buflen( ssl );
-        if(ssl->out_buf != NULL )
-        {
-            written_out = ssl->out_msg - ssl->out_buf;
-            iv_offset_out = ssl->out_iv - ssl->out_buf;
-            len_offset_out = ssl->out_len - ssl->out_buf;
-            if( ssl->out_buf_len > mbedtls_ssl_get_output_buflen( ssl ) &&
-                ssl->out_left < buf_len )
-            {
-                if( resize_buffer( &ssl->out_buf, buf_len, &ssl->out_buf_len ) != 0 )
-                {
-                    MBEDTLS_SSL_DEBUG_MSG( 1, ( "output buffer resizing failed - out of memory" ) );
-                }
-                else
-                {
-                    MBEDTLS_SSL_DEBUG_MSG( 2, ( "Reallocating out_buf to %d", buf_len ) );
-                    modified = 1;
-                }
-            }
-        }
-        if( modified )
-        {
-            /* Update pointers here to avoid doing it twice. */
-            mbedtls_ssl_reset_in_out_pointers( ssl );
-            /* Fields below might not be properly updated with record
-             * splitting or with CID, so they are manually updated here. */
-            ssl->out_msg = ssl->out_buf + written_out;
-            ssl->out_len = ssl->out_buf + len_offset_out;
-            ssl->out_iv = ssl->out_buf + iv_offset_out;
-
-            ssl->in_msg = ssl->in_buf + written_in;
-            ssl->in_len = ssl->in_buf + len_offset_in;
-            ssl->in_iv = ssl->in_buf + iv_offset_in;
-        }
-    }
+    handle_buffer_resizing( ssl, 1, mbedtls_ssl_get_input_buflen( ssl ),
+                                    mbedtls_ssl_get_output_buflen( ssl ) );
 #endif
 }
 
diff --git a/library/x509write_crt.c b/library/x509write_crt.c
index 32c6550..498b8b0 100644
--- a/library/x509write_crt.c
+++ b/library/x509write_crt.c
@@ -163,7 +163,7 @@
     return(
         mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_BASIC_CONSTRAINTS,
                              MBEDTLS_OID_SIZE( MBEDTLS_OID_BASIC_CONSTRAINTS ),
-                             0, buf + sizeof(buf) - len, len ) );
+                             is_ca, buf + sizeof(buf) - len, len ) );
 }
 
 #if defined(MBEDTLS_SHA1_C)
diff --git a/programs/fuzz/CMakeLists.txt b/programs/fuzz/CMakeLists.txt
index f0e5705..fd55e31 100644
--- a/programs/fuzz/CMakeLists.txt
+++ b/programs/fuzz/CMakeLists.txt
@@ -32,20 +32,24 @@
 
 foreach(exe IN LISTS executables_no_common_c executables_with_common_c)
 
-    add_executable(${exe} ${exe}.c $<TARGET_OBJECTS:mbedtls_test>)
-
-    if (NOT FUZZINGENGINE_LIB)
-        target_link_libraries(${exe} ${libs})
-        set_property(TARGET ${exe} APPEND PROPERTY SOURCES onefile.c)
-    else()
-        target_link_libraries(${exe} ${libs} FuzzingEngine)
-        SET_TARGET_PROPERTIES(${exe} PROPERTIES LINKER_LANGUAGE CXX)
+    set(exe_sources ${exe}.c $<TARGET_OBJECTS:mbedtls_test>)
+    if(NOT FUZZINGENGINE_LIB)
+        list(APPEND exe_sources onefile.c)
     endif()
 
     # This emulates "if ( ... IN_LIST ... )" which becomes available in CMake 3.3
     list(FIND executables_with_common_c ${exe} exe_index)
-    if (${exe_index} GREATER -1)
-        set_property(TARGET ${exe} APPEND PROPERTY SOURCES common.c)
+    if(${exe_index} GREATER -1)
+        list(APPEND exe_sources common.c)
+    endif()
+
+    add_executable(${exe} ${exe_sources})
+
+    if (NOT FUZZINGENGINE_LIB)
+        target_link_libraries(${exe} ${libs})
+    else()
+        target_link_libraries(${exe} ${libs} FuzzingEngine)
+        SET_TARGET_PROPERTIES(${exe} PROPERTIES LINKER_LANGUAGE CXX)
     endif()
 
 endforeach()
diff --git a/programs/ssl/CMakeLists.txt b/programs/ssl/CMakeLists.txt
index e4038f7..dfc16a5 100644
--- a/programs/ssl/CMakeLists.txt
+++ b/programs/ssl/CMakeLists.txt
@@ -27,7 +27,13 @@
 )
 
 foreach(exe IN LISTS executables)
-    add_executable(${exe} ${exe}.c $<TARGET_OBJECTS:mbedtls_test>)
+    set(extra_sources "")
+    if(exe STREQUAL "ssl_client2" OR exe STREQUAL "ssl_server2")
+        list(APPEND extra_sources
+            ${CMAKE_CURRENT_SOURCE_DIR}/../test/query_config.c)
+    endif()
+    add_executable(${exe} ${exe}.c $<TARGET_OBJECTS:mbedtls_test>
+        ${extra_sources})
     target_link_libraries(${exe} ${libs})
     target_include_directories(${exe} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/include)
 endforeach()
diff --git a/programs/test/CMakeLists.txt b/programs/test/CMakeLists.txt
index 49b44e7..2b1e61e 100644
--- a/programs/test/CMakeLists.txt
+++ b/programs/test/CMakeLists.txt
@@ -26,7 +26,13 @@
 endif()
 
 foreach(exe IN LISTS executables_libs executables_mbedcrypto)
-    add_executable(${exe} ${exe}.c $<TARGET_OBJECTS:mbedtls_test>)
+    set(extra_sources "")
+    if(exe STREQUAL "query_compile_time_config")
+        list(APPEND extra_sources
+            ${CMAKE_CURRENT_SOURCE_DIR}/query_config.c)
+    endif()
+    add_executable(${exe} ${exe}.c $<TARGET_OBJECTS:mbedtls_test>
+        ${extra_sources})
 
     # This emulates "if ( ... IN_LIST ... )" which becomes available in CMake 3.3
     list(FIND executables_libs ${exe} exe_index)
@@ -37,9 +43,6 @@
     endif()
 endforeach()
 
-set_property(TARGET query_compile_time_config APPEND PROPERTY SOURCES
-             ${CMAKE_CURRENT_SOURCE_DIR}/query_config.c)
-
 install(TARGETS ${executables_libs} ${executables_mbedcrypto}
         DESTINATION "bin"
         PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
diff --git a/tests/data_files/Makefile b/tests/data_files/Makefile
index b90ce74..0962898 100644
--- a/tests/data_files/Makefile
+++ b/tests/data_files/Makefile
@@ -1018,6 +1018,14 @@
 	$(OPENSSL) x509 -inform PEM -in $< -outform DER -out $@
 all_final += server1.v1.crt server1.v1.der
 
+server1.ca.crt: server1.key server1.req.sha256 $(test_ca_crt) $(test_ca_key_file_rsa)
+	$(MBEDTLS_CERT_WRITE) request_file=server1.req.sha256 issuer_crt=$(test_ca_crt) issuer_key=$(test_ca_key_file_rsa) issuer_pwd=$(test_ca_pwd_rsa) version=1 not_before=20190210144406 not_after=20290210144406 md=SHA1 is_ca=1 version=3 output_file=$@
+server1.ca_noauthid.crt: server1.key server1.req.sha256 $(test_ca_crt) $(test_ca_key_file_rsa)
+	$(MBEDTLS_CERT_WRITE) request_file=server1.req.sha256 issuer_crt=$(test_ca_crt) issuer_key=$(test_ca_key_file_rsa) issuer_pwd=$(test_ca_pwd_rsa) not_before=20190210144406 not_after=20290210144406 md=SHA1 authority_identifier=0 is_ca=1 version=3 output_file=$@
+server1.ca.der: server1.ca.crt
+	$(OPENSSL) x509 -inform PEM -in $< -outform DER -out $@
+all_final += server1.ca.crt server1.ca_noauthid.crt server1.ca.der
+
 server1_ca.crt: server1.crt $(test_ca_crt)
 	cat server1.crt $(test_ca_crt) > $@
 all_final += server1_ca.crt
diff --git a/tests/data_files/server1.ca.crt b/tests/data_files/server1.ca.crt
new file mode 100644
index 0000000..84691d6
--- /dev/null
+++ b/tests/data_files/server1.ca.crt
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDRTCCAi2gAwIBAgIBATANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER
+MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN
+MTkwMjEwMTQ0NDA2WhcNMjkwMjEwMTQ0NDA2WjA8MQswCQYDVQQGEwJOTDERMA8G
+A1UECgwIUG9sYXJTU0wxGjAYBgNVBAMMEVBvbGFyU1NMIFNlcnZlciAxMIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqQIfPUBq1VVTi/027oJlLhVhXom/
+uOhFkNvuiBZS0/FDUEeWEllkh2v9K+BG+XO+3c+S4ZFb7Wagb4kpeUWA0INq1UFD
+d185fAkER4KwVzlw7aPsFRkeqDMIR8EFQqn9TMO0390GH00QUUBncxMPQPhtgSVf
+CrFTxjB+FTms+Vruf5KepgVb5xOXhbUjktnUJAbVCSWJdQfdphqPPwkZvq1lLGTr
+lZvc/kFeF6babFtpzAK6FCwWJJxK3M3Q91Jnc/EtoCP9fvQxyi1wyokLBNsupk9w
+bp7OvViJ4lNZnm5akmXiiD8MlBmj3eXonZUT7Snbq3AS3FrKaxerUoJUsQIDAQAB
+o1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQfdNY/KcF0dEU7BRIsPai9
+Q1kCpjAfBgNVHSMEGDAWgBS0WuSls97SUva51aaVD+s+vMf9/zANBgkqhkiG9w0B
+AQUFAAOCAQEAgt0Fk6cLMjsZUkVpkpTw6EJuKA48H8ieUSTDzYoaDWJQsFY34OIc
+0UpfMwl1jl0qEcVboOdcJHug0EXsfm6XUlSJkPnmcdt/N4gU3/TVkdQwqbvrwjae
+S+Jb1E7fTAiauMi6++svV/sfKqE3OCTJWF+6D0LdgnxEVZM6DvnFU9Jvw+CPTIx6
++SYZLm5sOTL0sWMIxwAEjwGJ3T1m0sjPjnnl4Jn/XtD8UuRRYB/RS6e2TlKovwWP
+G3eUdEs2QJ5lnnD+d7AUYq9nAYnb42M1ZdAxRQxxu2wweiTpUubvT4W6wkG8veix
+UM45EKsxPinnK0rK9bzrPDwpntIHhEUcSQ==
+-----END CERTIFICATE-----
diff --git a/tests/data_files/server1.ca.der b/tests/data_files/server1.ca.der
new file mode 100644
index 0000000..a5ff059
--- /dev/null
+++ b/tests/data_files/server1.ca.der
Binary files differ
diff --git a/tests/data_files/server1.ca_noauthid.crt b/tests/data_files/server1.ca_noauthid.crt
new file mode 100644
index 0000000..e66956d
--- /dev/null
+++ b/tests/data_files/server1.ca_noauthid.crt
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDJDCCAgygAwIBAgIBATANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER
+MA8GA1UECgwIUG9sYXJTU0wxGTAXBgNVBAMMEFBvbGFyU1NMIFRlc3QgQ0EwHhcN
+MTkwMjEwMTQ0NDA2WhcNMjkwMjEwMTQ0NDA2WjA8MQswCQYDVQQGEwJOTDERMA8G
+A1UECgwIUG9sYXJTU0wxGjAYBgNVBAMMEVBvbGFyU1NMIFNlcnZlciAxMIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqQIfPUBq1VVTi/027oJlLhVhXom/
+uOhFkNvuiBZS0/FDUEeWEllkh2v9K+BG+XO+3c+S4ZFb7Wagb4kpeUWA0INq1UFD
+d185fAkER4KwVzlw7aPsFRkeqDMIR8EFQqn9TMO0390GH00QUUBncxMPQPhtgSVf
+CrFTxjB+FTms+Vruf5KepgVb5xOXhbUjktnUJAbVCSWJdQfdphqPPwkZvq1lLGTr
+lZvc/kFeF6babFtpzAK6FCwWJJxK3M3Q91Jnc/EtoCP9fvQxyi1wyokLBNsupk9w
+bp7OvViJ4lNZnm5akmXiiD8MlBmj3eXonZUT7Snbq3AS3FrKaxerUoJUsQIDAQAB
+ozIwMDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQfdNY/KcF0dEU7BRIsPai9
+Q1kCpjANBgkqhkiG9w0BAQUFAAOCAQEAMblPCsjj6RJ8sOm54sdlSJOTGWEo/1LF
+q1bJnKE3FXDeU8pbhEhpfsd2zcKdJxzp7Bg8Ms/xKBuOZhn/4C/n2FwZpEeAsS7J
+tZifKp+GXVs0xbcji9aB8niWXSl/CoICpvHpMAz8k2HT4LDvbC2ElXkqLT7n7k1B
+/ODI3BME34NquyBTDezQb4Gz7bx42OKLrxZkKrO3UF3TQTYBZvlH7IO7SvZhQPGk
+b8a2jKYfeQCCIvcywWQ7qzlgzTgnXJ0RrLyCqOqLFs6ztHPgclHa+XYF5yftSKIS
+zTJLT0IWBtwgB2opv7YSx7tKYhj+uHHY7C3iSXzAgPy5TYkissGXbw==
+-----END CERTIFICATE-----
diff --git a/tests/suites/test_suite_x509write.data b/tests/suites/test_suite_x509write.data
index b3f209e..e0f80be 100644
--- a/tests/suites/test_suite_x509write.data
+++ b/tests/suites/test_suite_x509write.data
@@ -56,35 +56,43 @@
 
 Certificate write check Server1 SHA1
 depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_DES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_MD5_C
-x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20190210144406":"20290210144406":MBEDTLS_MD_SHA1:0:0:0:0:1:-1:"data_files/server1.crt":0
+x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20190210144406":"20290210144406":MBEDTLS_MD_SHA1:0:0:0:0:1:-1:"data_files/server1.crt":0:0
 
 Certificate write check Server1 SHA1, key_usage
 depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_DES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_MD5_C
-x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20190210144406":"20290210144406":MBEDTLS_MD_SHA1:MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_NON_REPUDIATION | MBEDTLS_X509_KU_KEY_ENCIPHERMENT:1:0:0:1:-1:"data_files/server1.key_usage.crt":0
+x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20190210144406":"20290210144406":MBEDTLS_MD_SHA1:MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_NON_REPUDIATION | MBEDTLS_X509_KU_KEY_ENCIPHERMENT:1:0:0:1:-1:"data_files/server1.key_usage.crt":0:0
 
 Certificate write check Server1 SHA1, ns_cert_type
 depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_DES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_MD5_C
-x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20190210144406":"20290210144406":MBEDTLS_MD_SHA1:0:0:MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER:1:1:-1:"data_files/server1.cert_type.crt":0
+x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20190210144406":"20290210144406":MBEDTLS_MD_SHA1:0:0:MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER:1:1:-1:"data_files/server1.cert_type.crt":0:0
 
 Certificate write check Server1 SHA1, version 1
 depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_DES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_MD5_C
-x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20190210144406":"20290210144406":MBEDTLS_MD_SHA1:0:0:0:0:1:MBEDTLS_X509_CRT_VERSION_1:"data_files/server1.v1.crt":0
+x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20190210144406":"20290210144406":MBEDTLS_MD_SHA1:0:0:0:0:1:MBEDTLS_X509_CRT_VERSION_1:"data_files/server1.v1.crt":0:0
+
+Certificate write check Server1 SHA1, CA
+depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_DES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_MD5_C
+x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20190210144406":"20290210144406":MBEDTLS_MD_SHA1:0:0:0:0:1:-1:"data_files/server1.ca.crt":0:1
 
 Certificate write check Server1 SHA1, RSA_ALT
 depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_DES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_MD5_C
-x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20190210144406":"20290210144406":MBEDTLS_MD_SHA1:0:0:0:0:0:-1:"data_files/server1.noauthid.crt":1
+x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20190210144406":"20290210144406":MBEDTLS_MD_SHA1:0:0:0:0:0:-1:"data_files/server1.noauthid.crt":1:0
 
 Certificate write check Server1 SHA1, RSA_ALT, key_usage
 depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_DES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_MD5_C
-x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20190210144406":"20290210144406":MBEDTLS_MD_SHA1:MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_NON_REPUDIATION | MBEDTLS_X509_KU_KEY_ENCIPHERMENT:1:0:0:0:-1:"data_files/server1.key_usage_noauthid.crt":1
+x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20190210144406":"20290210144406":MBEDTLS_MD_SHA1:MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_NON_REPUDIATION | MBEDTLS_X509_KU_KEY_ENCIPHERMENT:1:0:0:0:-1:"data_files/server1.key_usage_noauthid.crt":1:0
 
 Certificate write check Server1 SHA1, RSA_ALT, ns_cert_type
 depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_DES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_MD5_C
-x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20190210144406":"20290210144406":MBEDTLS_MD_SHA1:0:0:MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER:1:0:-1:"data_files/server1.cert_type_noauthid.crt":1
+x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20190210144406":"20290210144406":MBEDTLS_MD_SHA1:0:0:MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER:1:0:-1:"data_files/server1.cert_type_noauthid.crt":1:0
 
 Certificate write check Server1 SHA1, RSA_ALT, version 1
 depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_DES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_MD5_C
-x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20190210144406":"20290210144406":MBEDTLS_MD_SHA1:0:0:0:0:0:MBEDTLS_X509_CRT_VERSION_1:"data_files/server1.v1.crt":1
+x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20190210144406":"20290210144406":MBEDTLS_MD_SHA1:0:0:0:0:0:MBEDTLS_X509_CRT_VERSION_1:"data_files/server1.v1.crt":1:0
+
+Certificate write check Server1 SHA1, RSA_ALT, CA
+depends_on:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_DES_C:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_MD5_C
+x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20190210144406":"20290210144406":MBEDTLS_MD_SHA1:0:0:0:0:0:-1:"data_files/server1.ca_noauthid.crt":1:1
 
 
 X509 String to Names #1
diff --git a/tests/suites/test_suite_x509write.function b/tests/suites/test_suite_x509write.function
index 9b32cba..9960989 100644
--- a/tests/suites/test_suite_x509write.function
+++ b/tests/suites/test_suite_x509write.function
@@ -206,7 +206,7 @@
                      char *serial_str, char *not_before, char *not_after,
                      int md_type, int key_usage, int set_key_usage,
                      int cert_type, int set_cert_type, int auth_ident,
-                     int ver, char *cert_check_file, int rsa_alt )
+                     int ver, char *cert_check_file, int rsa_alt, int is_ca )
 {
     mbedtls_pk_context subject_key, issuer_key, issuer_key_alt;
     mbedtls_pk_context *key = &issuer_key;
@@ -269,7 +269,9 @@
 
     if( crt.version >= MBEDTLS_X509_CRT_VERSION_3 )
     {
-        TEST_ASSERT( mbedtls_x509write_crt_set_basic_constraints( &crt, 0, 0 ) == 0 );
+        /* For the CA case, a path length of -1 means unlimited. */
+        TEST_ASSERT( mbedtls_x509write_crt_set_basic_constraints( &crt, is_ca,
+                                                                  (is_ca ? -1 : 0) ) == 0 );
         TEST_ASSERT( mbedtls_x509write_crt_set_subject_key_identifier( &crt ) == 0 );
         if( auth_ident )
             TEST_ASSERT( mbedtls_x509write_crt_set_authority_key_identifier( &crt ) == 0 );