Merge pull request #6487 from gilles-peskine-arm/legacy_or_psa-internal

diff --git a/ChangeLog.d/psa_rsa_needs_pk.txt b/ChangeLog.d/psa_rsa_needs_pk.txt
new file mode 100644
index 0000000..995963d
--- /dev/null
+++ b/ChangeLog.d/psa_rsa_needs_pk.txt
@@ -0,0 +1,5 @@
+Bugfix
+   * Fix build failure with MBEDTLS_RSA_C and MBEDTLS_PSA_CRYPTO_C but not
+     MBEDTLS_USE_PSA_CRYPTO or MBEDTLS_PK_WRITE_C. Fixes #6408.
+   * Fix build failure with MBEDTLS_RSA_C and MBEDTLS_PSA_CRYPTO_C but not
+     MBEDTLS_PK_PARSE_C. Fixes #6409.
diff --git a/README.md b/README.md
index 9c9cf91..cc61da0 100644
--- a/README.md
+++ b/README.md
@@ -242,7 +242,7 @@
 -   `tests/ssl-opt.sh` runs integration tests for various TLS options (renegotiation, resumption, etc.) and tests interoperability of these options with other implementations.
 -   `tests/compat.sh` tests interoperability of every ciphersuite with other implementations.
 -   `tests/scripts/test-ref-configs.pl` test builds in various reduced configurations.
--   `tests/scripts/key-exchanges.pl` test builds in configurations with a single key exchange enabled
+-   `tests/scripts/depends.py` test builds in configurations with a single curve, key exchange, hash, cipher, or pkalg on.
 -   `tests/scripts/all.sh` runs a combination of the above tests, plus some more, with various build options (such as ASan, full `mbedtls_config.h`, etc).
 
 Porting Mbed TLS
diff --git a/include/mbedtls/build_info.h b/include/mbedtls/build_info.h
index 9c9a345..170cbeb 100644
--- a/include/mbedtls/build_info.h
+++ b/include/mbedtls/build_info.h
@@ -74,7 +74,23 @@
 #include MBEDTLS_USER_CONFIG_FILE
 #endif
 
-#if defined(MBEDTLS_PK_C) && defined(MBEDTLS_USE_PSA_CRYPTO)
+/* The PK wrappers need pk_write functions to format RSA key objects
+ * when they are dispatching to the PSA API. This happens under USE_PSA_CRYPTO,
+ * and also even without USE_PSA_CRYPTO for mbedtls_pk_sign_ext().
+ * PSA crypto also needs pk_write to export RSA keys (otherwise the build
+ * goes through but psa_export_key() and psa_export_public_key() fail on
+ * RSA keys), and pk_parse to work with RSA keys in almost any way.
+ */
+#if defined(MBEDTLS_PSA_CRYPTO_C) && defined(MBEDTLS_RSA_C)
+#define MBEDTLS_PK_C
+#define MBEDTLS_PK_WRITE_C
+#define MBEDTLS_PK_PARSE_C
+#endif
+
+/* Under MBEDTLS_USE_PSA_CRYPTO, the pk module needs pk_write functions
+ * to pass ECC keys to PSA. */
+#if defined(MBEDTLS_PK_C) &&                                    \
+    defined(MBEDTLS_USE_PSA_CRYPTO) && defined(MBEDTLS_ECP_C)
 #define MBEDTLS_PK_WRITE_C
 #endif
 
@@ -96,6 +112,7 @@
 #undef MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED
 #undef MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED
 #undef MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED
+#undef MBEDTLS_SSL_EARLY_DATA
 #endif
 
 #if defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED) || \
diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h
index 6a96479..d36db4a 100644
--- a/include/mbedtls/check_config.h
+++ b/include/mbedtls/check_config.h
@@ -842,6 +842,13 @@
         "but no key exchange methods defined with MBEDTLS_KEY_EXCHANGE_xxxx"
 #endif
 
+/* Early data requires PSK related mode defined */
+#if defined(MBEDTLS_SSL_EARLY_DATA) && \
+        ( !defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED) && \
+          !defined(MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED))
+#error "MBEDTLS_SSL_EARLY_DATA  defined, but not all prerequisites"
+#endif
+
 #if defined(MBEDTLS_SSL_PROTO_DTLS)     && \
     !defined(MBEDTLS_SSL_PROTO_TLS1_2)
 #error "MBEDTLS_SSL_PROTO_DTLS defined, but not all prerequisites"
diff --git a/include/mbedtls/mbedtls_config.h b/include/mbedtls/mbedtls_config.h
index a7af96a..b4c8635 100644
--- a/include/mbedtls/mbedtls_config.h
+++ b/include/mbedtls/mbedtls_config.h
@@ -1633,6 +1633,23 @@
 #define MBEDTLS_SSL_TLS1_3_DEFAULT_NEW_SESSION_TICKETS 1
 
 /**
+* \def MBEDTLS_SSL_EARLY_DATA
+*
+* Enable support for RFC 8446 TLS 1.3 early data.
+*
+* Requires: MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED or
+*           MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED
+*
+* Comment this to disable support for early data. If MBEDTLS_SSL_PROTO_TLS1_3
+* is not enabled, this option does not have any effect on the build.
+*
+* This feature is experimental, not completed and thus not ready for
+* production.
+*
+*/
+//#define MBEDTLS_SSL_EARLY_DATA
+
+/**
  * \def MBEDTLS_SSL_PROTO_DTLS
  *
  * Enable support for DTLS (all available versions).
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index 9677c71..01ede40 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -329,6 +329,9 @@
 #define MBEDTLS_SSL_CERT_REQ_CA_LIST_ENABLED       1
 #define MBEDTLS_SSL_CERT_REQ_CA_LIST_DISABLED      0
 
+#define MBEDTLS_SSL_EARLY_DATA_DISABLED        0
+#define MBEDTLS_SSL_EARLY_DATA_ENABLED         1
+
 #define MBEDTLS_SSL_DTLS_SRTP_MKI_UNSUPPORTED    0
 #define MBEDTLS_SSL_DTLS_SRTP_MKI_SUPPORTED      1
 
@@ -1496,6 +1499,12 @@
                                      *   is not \c 0. */
 #endif /* MBEDTLS_SSL_HANDSHAKE_WITH_PSK_ENABLED */
 
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+    int MBEDTLS_PRIVATE(early_data_enabled);     /*!< Early data enablement:
+                                                  *   - MBEDTLS_SSL_EARLY_DATA_DISABLED,
+                                                  *   - MBEDTLS_SSL_EARLY_DATA_ENABLED */
+#endif /* MBEDTLS_SSL_EARLY_DATA */
+
 #if defined(MBEDTLS_SSL_ALPN)
     const char **MBEDTLS_PRIVATE(alpn_list);         /*!< ordered list of protocols          */
 #endif
@@ -1905,6 +1914,30 @@
  */
 void mbedtls_ssl_conf_authmode( mbedtls_ssl_config *conf, int authmode );
 
+#if defined(MBEDTLS_SSL_PROTO_TLS1_3) && defined(MBEDTLS_SSL_EARLY_DATA)
+/**
+* \brief    Set the early data mode
+*           Default: disabled on server and client
+*
+* \param conf   The SSL configuration to use.
+* \param early_data_enabled can be:
+*
+*  MBEDTLS_SSL_EARLY_DATA_DISABLED:  early data functionality is disabled
+*                                    This is the default on client and server.
+*
+*  MBEDTLS_SSL_EARLY_DATA_ENABLED:  early data functionality is enabled and
+*                        may be negotiated in the handshake. Application using
+*                        early data functionality needs to be aware of the
+*                        lack of replay protection of the early data application
+*                        payloads.
+*
+* \warning This interface is experimental and may change without notice.
+*
+*/
+void mbedtls_ssl_tls13_conf_early_data( mbedtls_ssl_config *conf,
+                                        int early_data_enabled );
+#endif /* MBEDTLS_SSL_PROTO_TLS1_3 && MBEDTLS_SSL_EARLY_DATA */
+
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
 /**
  * \brief          Set the verification callback (Optional).
diff --git a/library/bignum.c b/library/bignum.c
index 58cd2f7..d33f07c 100644
--- a/library/bignum.c
+++ b/library/bignum.c
@@ -867,8 +867,7 @@
 int mbedtls_mpi_add_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
-    size_t i, j;
-    mbedtls_mpi_uint *o, *p, c, tmp;
+    size_t j;
     MPI_VALIDATE_RET( X != NULL );
     MPI_VALIDATE_RET( A != NULL );
     MPI_VALIDATE_RET( B != NULL );
@@ -882,7 +881,7 @@
         MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, A ) );
 
     /*
-     * X should always be positive as a result of unsigned additions.
+     * X must always be positive as a result of unsigned additions.
      */
     X->s = 1;
 
@@ -892,27 +891,25 @@
 
     MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) );
 
-    o = B->p; p = X->p; c = 0;
+    /* j is the number of non-zero limbs of B. Add those to X. */
 
-    /*
-     * tmp is used because it might happen that p == o
-     */
-    for( i = 0; i < j; i++, o++, p++ )
-    {
-        tmp= *o;
-        *p +=  c; c  = ( *p <  c );
-        *p += tmp; c += ( *p < tmp );
-    }
+    mbedtls_mpi_uint *p = X->p;
+
+    mbedtls_mpi_uint c = mbedtls_mpi_core_add( p, p, B->p, j );
+
+    p += j;
+
+    /* Now propagate any carry */
 
     while( c != 0 )
     {
-        if( i >= X->n )
+        if( j >= X->n )
         {
-            MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i + 1 ) );
-            p = X->p + i;
+            MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j + 1 ) );
+            p = X->p + j;
         }
 
-        *p += c; c = ( *p < c ); i++; p++;
+        *p += c; c = ( *p < c ); j++; p++;
     }
 
 cleanup:
diff --git a/library/bignum_core.c b/library/bignum_core.c
index 963af5b..b401fa3 100644
--- a/library/bignum_core.c
+++ b/library/bignum_core.c
@@ -316,8 +316,6 @@
     return( 0 );
 }
 
-
-
 void mbedtls_mpi_core_shift_r( mbedtls_mpi_uint *X, size_t limbs,
                                size_t count )
 {
@@ -360,7 +358,24 @@
     }
 }
 
+mbedtls_mpi_uint mbedtls_mpi_core_add( mbedtls_mpi_uint *X,
+                                       const mbedtls_mpi_uint *A,
+                                       const mbedtls_mpi_uint *B,
+                                       size_t limbs )
+{
+    mbedtls_mpi_uint c = 0;
 
+    for( size_t i = 0; i < limbs; i++ )
+    {
+        mbedtls_mpi_uint t = c + A[i];
+        c = ( t < A[i] );
+        t += B[i];
+        c += ( t < B[i] );
+        X[i] = t;
+    }
+
+    return( c );
+}
 
 mbedtls_mpi_uint mbedtls_mpi_core_add_if( mbedtls_mpi_uint *X,
                                           const mbedtls_mpi_uint *A,
diff --git a/library/bignum_core.h b/library/bignum_core.h
index 503bc1d..9a5b89f 100644
--- a/library/bignum_core.h
+++ b/library/bignum_core.h
@@ -278,6 +278,28 @@
                                size_t count );
 
 /**
+ * \brief Add two fixed-size large unsigned integers, returning the carry.
+ *
+ * Calculates `A + B` where `A` and `B` have the same size.
+ *
+ * This function operates modulo `2^(biL*limbs)` and returns the carry
+ * (1 if there was a wraparound, and 0 otherwise).
+ *
+ * \p X may be aliased to \p A or \p B.
+ *
+ * \param[out] X    The result of the addition.
+ * \param[in] A     Little-endian presentation of the left operand.
+ * \param[in] B     Little-endian presentation of the right operand.
+ * \param limbs     Number of limbs of \p X, \p A and \p B.
+ *
+ * \return          1 if `A + B >= 2^(biL*limbs)`, 0 otherwise.
+ */
+mbedtls_mpi_uint mbedtls_mpi_core_add( mbedtls_mpi_uint *X,
+                                       const mbedtls_mpi_uint *A,
+                                       const mbedtls_mpi_uint *B,
+                                       size_t limbs );
+
+/**
  * \brief Conditional addition of two fixed-size large unsigned integers,
  *        returning the carry.
  *
diff --git a/library/ecp.c b/library/ecp.c
index 5c597d5..08e33e2 100644
--- a/library/ecp.c
+++ b/library/ecp.c
@@ -2461,7 +2461,7 @@
     MBEDTLS_MPI_CHK( ecp_randomize_mxz( grp, &RP, f_rng, p_rng ) );
 
     /* Loop invariant: R = result so far, RP = R + P */
-    i = mbedtls_mpi_bitlen( m ); /* one past the (zero-based) most significant bit */
+    i = grp->nbits + 1; /* one past the (zero-based) required msb for private keys */
     while( i-- > 0 )
     {
         b = mbedtls_mpi_get_bit( m, i );
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 0759ef9..a49f774 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -1427,6 +1427,14 @@
 {
     conf->tls13_kex_modes = kex_modes & MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_ALL;
 }
+
+#if defined(MBEDTLS_SSL_EARLY_DATA)
+void mbedtls_ssl_tls13_conf_early_data( mbedtls_ssl_config *conf,
+                                        int early_data_enabled )
+{
+    conf->early_data_enabled = early_data_enabled;
+}
+#endif /* MBEDTLS_SSL_EARLY_DATA */
 #endif /* MBEDTLS_SSL_PROTO_TLS1_3 */
 
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
@@ -5269,6 +5277,13 @@
 #endif /* MBEDTLS_HAS_ALG_SHA_256_VIA_MD_OR_PSA_BASED_ON_USE_PSA*/
 
     default:
+#if !defined(MBEDTLS_HAS_ALG_SHA_384_VIA_MD_OR_PSA_BASED_ON_USE_PSA) && \
+    !defined(MBEDTLS_HAS_ALG_SHA_256_VIA_MD_OR_PSA_BASED_ON_USE_PSA)
+    (void) ssl;
+    (void) dst;
+    (void) dst_len;
+    (void) olen;
+#endif
         break;
     }
     return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
@@ -5455,8 +5470,8 @@
     return( PSA_SUCCESS );
 }
 
-#if defined(MBEDTLS_HAS_ALG_SHA_384_VIA_MD_OR_PSA_BASED_ON_USE_PSA) || \
-    defined(MBEDTLS_HAS_ALG_SHA_256_VIA_MD_OR_PSA_BASED_ON_USE_PSA)
+#if defined(PSA_WANT_ALG_SHA_384) || \
+    defined(PSA_WANT_ALG_SHA_256)
 MBEDTLS_CHECK_RETURN_CRITICAL
 static int tls_prf_generic( mbedtls_md_type_t md_type,
                             const unsigned char *secret, size_t slen,
@@ -5531,9 +5546,12 @@
 
     return( 0 );
 }
-#endif
+#endif /* PSA_WANT_ALG_SHA_256 || PSA_WANT_ALG_SHA_384 */
 #else /* MBEDTLS_USE_PSA_CRYPTO */
 
+#if defined(MBEDTLS_MD_C) &&       \
+    ( defined(MBEDTLS_SHA256_C) || \
+      defined(MBEDTLS_SHA384_C) )
 MBEDTLS_CHECK_RETURN_CRITICAL
 static int tls_prf_generic( mbedtls_md_type_t md_type,
                             const unsigned char *secret, size_t slen,
@@ -5624,6 +5642,7 @@
 
     return( ret );
 }
+#endif /* MBEDTLS_MD_C && ( MBEDTLS_SHA256_C || MBEDTLS_SHA384_C ) */
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
 #if defined(MBEDTLS_HAS_ALG_SHA_256_VIA_MD_OR_PSA_BASED_ON_USE_PSA)
diff --git a/library/ssl_tls12_client.c b/library/ssl_tls12_client.c
index d82918f..5360b3c 100644
--- a/library/ssl_tls12_client.c
+++ b/library/ssl_tls12_client.c
@@ -1750,10 +1750,10 @@
 #endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED ||
           MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */
 
-#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) ||     \
-    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) ||     \
-    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
+#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED)   ||   \
+    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED)   ||   \
+    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
 MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_server_ecdh_params( mbedtls_ssl_context *ssl,
                                              unsigned char **p,
@@ -1818,7 +1818,15 @@
 
     return( 0 );
 }
+#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED   ||
+          MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED   ||
+          MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */
 #else
+#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED)   ||   \
+    defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED)    ||   \
+    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED)   ||   \
+    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) ||   \
+    defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)
 MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_check_server_ecdh_params( const mbedtls_ssl_context *ssl )
 {
@@ -1848,6 +1856,15 @@
     return( 0 );
 }
 
+#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED   ||
+          MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED    ||
+          MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED   ||
+          MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED ||
+          MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */
+
+#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) ||     \
+    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) ||     \
+    defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)
 MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_server_ecdh_params( mbedtls_ssl_context *ssl,
                                          unsigned char **p,
@@ -1883,11 +1900,10 @@
 
     return( ret );
 }
-#endif /* MBEDTLS_USE_PSA_CRYPTO */
-#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED ||
-          MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED ||
-          MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */
-
+#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED ||     \
+          MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED ||     \
+          MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */
+#endif /* !MBEDTLS_USE_PSA_CRYPTO */
 #if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED)
 MBEDTLS_CHECK_RETURN_CRITICAL
 static int ssl_parse_server_psk_hint( mbedtls_ssl_context *ssl,
diff --git a/scripts/mbedtls_dev/bignum_core.py b/scripts/mbedtls_dev/bignum_core.py
index e46364b..0d238e7 100644
--- a/scripts/mbedtls_dev/bignum_core.py
+++ b/scripts/mbedtls_dev/bignum_core.py
@@ -144,12 +144,12 @@
             yield cls(a_value, b_value, 32).create_test_case()
             yield cls(a_value, b_value, 64).create_test_case()
 
-class BignumCoreAddIf(BignumCoreOperationArchSplit):
-    """Test cases for bignum core add if."""
+class BignumCoreAddAndAddIf(BignumCoreOperationArchSplit):
+    """Test cases for bignum core add and add-if."""
     count = 0
     symbol = "+"
-    test_function = "mpi_core_add_if"
-    test_name = "mbedtls_mpi_core_add_if"
+    test_function = "mpi_core_add_and_add_if"
+    test_name = "mpi_core_add_and_add_if"
 
     def result(self) -> List[str]:
         result = self.int_a + self.int_b
diff --git a/tests/data_files/dh.optlen.der b/tests/data_files/dh.optlen.der
new file mode 100644
index 0000000..3c3bf17
--- /dev/null
+++ b/tests/data_files/dh.optlen.der
Binary files differ
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index bfd865b..e8f1726 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -1717,6 +1717,37 @@
   are_empty_libraries library/libmbedx509.* library/libmbedtls.*
 }
 
+component_test_crypto_for_psa_service () {
+  msg "build: make, config for PSA crypto service"
+  scripts/config.py crypto
+  scripts/config.py set MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER
+  # Disable things that are not needed for just cryptography, to
+  # reach a configuration that would be typical for a PSA cryptography
+  # service providing all implemented PSA algorithms.
+  # System stuff
+  scripts/config.py unset MBEDTLS_ERROR_C
+  scripts/config.py unset MBEDTLS_TIMING_C
+  scripts/config.py unset MBEDTLS_VERSION_FEATURES
+  # Crypto stuff with no PSA interface
+  scripts/config.py unset MBEDTLS_BASE64_C
+  # Keep MBEDTLS_CIPHER_C because psa_crypto_cipher, CCM and GCM need it.
+  scripts/config.py unset MBEDTLS_HKDF_C # PSA's HKDF is independent
+  # Keep MBEDTLS_MD_C because deterministic ECDSA needs it for HMAC_DRBG.
+  scripts/config.py unset MBEDTLS_NIST_KW_C
+  scripts/config.py unset MBEDTLS_PEM_PARSE_C
+  scripts/config.py unset MBEDTLS_PEM_WRITE_C
+  scripts/config.py unset MBEDTLS_PKCS12_C
+  scripts/config.py unset MBEDTLS_PKCS5_C
+  # MBEDTLS_PK_PARSE_C and MBEDTLS_PK_WRITE_C are actually currently needed
+  # in PSA code to work with RSA keys. We don't require users to set those:
+  # they will be reenabled in build_info.h.
+  scripts/config.py unset MBEDTLS_PK_C
+  scripts/config.py unset MBEDTLS_PK_PARSE_C
+  scripts/config.py unset MBEDTLS_PK_WRITE_C
+  make CFLAGS='-O1 -Werror' all test
+  are_empty_libraries library/libmbedx509.* library/libmbedtls.*
+}
+
 component_build_crypto_baremetal () {
   msg "build: make, crypto only, baremetal config"
   scripts/config.py crypto_baremetal
@@ -1739,76 +1770,75 @@
     ! grep -q -F time.h /usr/include/x86_64-linux-gnu/sys/types.h
 }
 
-component_test_depends_curves () {
-    msg "test/build: curves.pl (gcc)" # ~ 4 min
-    tests/scripts/curves.pl
-}
-
-component_test_depends_curves_psa () {
-    msg "test/build: curves.pl with MBEDTLS_USE_PSA_CRYPTO defined (gcc)"
-    scripts/config.py set MBEDTLS_USE_PSA_CRYPTO
-    tests/scripts/curves.pl
-}
-
-component_test_depends_hashes () {
-    msg "test/build: depends-hashes.pl (gcc)" # ~ 2 min
-    tests/scripts/depends-hashes.pl
-}
-
-component_test_depends_hashes_psa () {
-    msg "test/build: depends-hashes.pl with MBEDTLS_USE_PSA_CRYPTO defined (gcc)"
-    scripts/config.py set MBEDTLS_USE_PSA_CRYPTO
-    tests/scripts/depends-hashes.pl
-}
-
-component_test_depends_pkalgs () {
-    msg "test/build: depends-pkalgs.pl (gcc)" # ~ 2 min
-    tests/scripts/depends-pkalgs.pl
-}
-
-component_test_depends_pkalgs_psa () {
-    msg "test/build: depends-pkalgs.pl with MBEDTLS_USE_PSA_CRYPTO defined (gcc)"
-    scripts/config.py set MBEDTLS_USE_PSA_CRYPTO
-    tests/scripts/depends-pkalgs.pl
-}
-
-component_build_key_exchanges () {
-    msg "test/build: key-exchanges (gcc)" # ~ 1 min
-    tests/scripts/key-exchanges.pl
-}
-
+# depends.py family of tests
 component_test_depends_py_cipher_id () {
     msg "test/build: depends.py cipher_id (gcc)"
-    tests/scripts/depends.py cipher_id
+    tests/scripts/depends.py cipher_id --unset-use-psa
 }
 
 component_test_depends_py_cipher_chaining () {
     msg "test/build: depends.py cipher_chaining (gcc)"
-    tests/scripts/depends.py cipher_chaining
+    tests/scripts/depends.py cipher_chaining --unset-use-psa
 }
 
 component_test_depends_py_cipher_padding () {
     msg "test/build: depends.py cipher_padding (gcc)"
-    tests/scripts/depends.py cipher_padding
+    tests/scripts/depends.py cipher_padding --unset-use-psa
 }
 
 component_test_depends_py_curves () {
     msg "test/build: depends.py curves (gcc)"
-    tests/scripts/depends.py curves
+    tests/scripts/depends.py curves --unset-use-psa
 }
 
 component_test_depends_py_hashes () {
     msg "test/build: depends.py hashes (gcc)"
-    tests/scripts/depends.py hashes
+    tests/scripts/depends.py hashes --unset-use-psa
 }
 
 component_test_depends_py_kex () {
     msg "test/build: depends.py kex (gcc)"
-    tests/scripts/depends.py kex
+    tests/scripts/depends.py kex --unset-use-psa
 }
 
 component_test_depends_py_pkalgs () {
     msg "test/build: depends.py pkalgs (gcc)"
+    tests/scripts/depends.py pkalgs --unset-use-psa
+}
+
+# PSA equivalents of the depends.py tests
+component_test_depends_py_cipher_id_psa () {
+    msg "test/build: depends.py cipher_id (gcc) with MBEDTLS_USE_PSA_CRYPTO defined"
+    tests/scripts/depends.py cipher_id
+}
+
+component_test_depends_py_cipher_chaining_psa () {
+    msg "test/build: depends.py cipher_chaining (gcc) with MBEDTLS_USE_PSA_CRYPTO defined"
+    tests/scripts/depends.py cipher_chaining
+}
+
+component_test_depends_py_cipher_padding_psa () {
+    msg "test/build: depends.py cipher_padding (gcc) with MBEDTLS_USE_PSA_CRYPTO defined"
+    tests/scripts/depends.py cipher_padding
+}
+
+component_test_depends_py_curves_psa () {
+    msg "test/build: depends.py curves (gcc) with MBEDTLS_USE_PSA_CRYPTO defined"
+    tests/scripts/depends.py curves
+}
+
+component_test_depends_py_hashes_psa () {
+    msg "test/build: depends.py hashes (gcc) with MBEDTLS_USE_PSA_CRYPTO defined"
+    tests/scripts/depends.py hashes
+}
+
+component_test_depends_py_kex_psa () {
+    msg "test/build: depends.py kex (gcc) with MBEDTLS_USE_PSA_CRYPTO defined"
+    tests/scripts/depends.py kex
+}
+
+component_test_depends_py_pkalgs_psa () {
+    msg "test/build: depends.py pkalgs (gcc) with MBEDTLS_USE_PSA_CRYPTO defined"
     tests/scripts/depends.py pkalgs
 }
 
diff --git a/tests/scripts/basic-in-docker.sh b/tests/scripts/basic-in-docker.sh
index 50bcb05..1f65710 100755
--- a/tests/scripts/basic-in-docker.sh
+++ b/tests/scripts/basic-in-docker.sh
@@ -40,6 +40,6 @@
     run_in_docker -e OSSL_NO_DTLS=1 tests/compat.sh
     run_in_docker tests/ssl-opt.sh -e '\(DTLS\|SCSV\).*openssl'
     run_in_docker tests/scripts/test-ref-configs.pl
-    run_in_docker tests/scripts/curves.pl
-    run_in_docker tests/scripts/key-exchanges.pl
+    run_in_docker tests/scripts/depends.py curves
+    run_in_docker tests/scripts/depends.py kex
 done
diff --git a/tests/scripts/curves.pl b/tests/scripts/curves.pl
deleted file mode 100755
index fcaca91..0000000
--- a/tests/scripts/curves.pl
+++ /dev/null
@@ -1,126 +0,0 @@
-#!/usr/bin/env perl
-
-# curves.pl
-#
-# Copyright The Mbed TLS Contributors
-# SPDX-License-Identifier: Apache-2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# Purpose
-#
-# The purpose of this test script is to validate that the library works
-# when only a single curve is enabled. In particular, this validates that
-# curve-specific code is guarded by the proper preprocessor conditionals,
-# both in the library and in tests.
-#
-# Since this script only tests builds with a single curve, it can't detect
-# bugs that are only triggered when multiple curves are present. We do
-# also test in many configurations where all curves are enabled, as well
-# as a few configurations in configs/*.h with a restricted subset of curves.
-#
-# Here are some known test gaps that could be addressed by testing all
-# 2^n combinations of support for n curves, which is impractical:
-# * There could be product bugs when curves A and B are enabled but not C.
-#   For example, a MAX_SIZE calculation that forgets B, where
-#   size(A) < size(B) < size(C).
-# * For test cases that require three or more curves, validate that they're
-#   not missing dependencies. This is extremely rare. (For test cases that
-#   require curves A and B but are missing a dependency on B, this is
-#   detected in the A-only build.)
-# Usage: tests/scripts/curves.pl
-#
-# This script should be executed from the root of the project directory.
-#
-# Only curves that are enabled in mbedtls_config.h will be tested.
-#
-# For best effect, run either with cmake disabled, or cmake enabled in a mode
-# that includes -Werror.
-
-use warnings;
-use strict;
-
--d 'library' && -d 'include' && -d 'tests' or die "Must be run from root\n";
-
-my $sed_cmd = 's/^#define \(MBEDTLS_ECP_DP.*_ENABLED\)/\1/p';
-my $config_h = 'include/mbedtls/mbedtls_config.h';
-my @curves = split( /\s+/, `sed -n -e '$sed_cmd' $config_h` );
-
-# Determine which curves support ECDSA by checking the dependencies of
-# ECDSA in check_config.h.
-my %curve_supports_ecdsa = ();
-{
-    local $/ = "";
-    local *CHECK_CONFIG;
-    open(CHECK_CONFIG, '<', 'include/mbedtls/check_config.h')
-        or die "open include/mbedtls/check_config.h: $!";
-    while (my $stanza = <CHECK_CONFIG>) {
-        if ($stanza =~ /\A#if defined\(MBEDTLS_ECDSA_C\)/) {
-            for my $curve ($stanza =~ /(?<=\()MBEDTLS_ECP_DP_\w+_ENABLED(?=\))/g) {
-                $curve_supports_ecdsa{$curve} = 1;
-            }
-            last;
-        }
-    }
-    close(CHECK_CONFIG);
-}
-
-system( "cp $config_h $config_h.bak" ) and die;
-sub abort {
-    system( "mv $config_h.bak $config_h" ) and warn "$config_h not restored\n";
-    # use an exit code between 1 and 124 for git bisect (die returns 255)
-    warn $_[0];
-    exit 1;
-}
-
-# Disable all the curves. We'll then re-enable them one by one.
-for my $curve (@curves) {
-    system( "scripts/config.pl unset $curve" )
-        and abort "Failed to disable $curve\n";
-}
-# Depends on a specific curve. Also, ignore error if it wasn't enabled.
-system( "scripts/config.pl unset MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED" );
-system( "scripts/config.pl unset MBEDTLS_ECJPAKE_C" );
-
-# Test with only $curve enabled, for each $curve.
-for my $curve (@curves) {
-    system( "make clean" ) and die;
-
-    print "\n******************************************\n";
-    print "* Testing with only curve: $curve\n";
-    print "******************************************\n";
-    $ENV{MBEDTLS_TEST_CONFIGURATION} = "$curve";
-
-    system( "scripts/config.pl set $curve" )
-        and abort "Failed to enable $curve\n";
-
-    my $ecdsa = $curve_supports_ecdsa{$curve} ? "set" : "unset";
-    for my $dep (qw(MBEDTLS_ECDSA_C
-                    MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED
-                    MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED)) {
-        system( "scripts/config.pl $ecdsa $dep" )
-            and abort "Failed to $ecdsa $dep\n";
-    }
-
-    system( "CFLAGS='-Werror -Wall -Wextra' make" )
-        and abort "Failed to build: only $curve\n";
-    system( "make test" )
-        and abort "Failed test suite: only $curve\n";
-
-    system( "scripts/config.pl unset $curve" )
-        and abort "Failed to disable $curve\n";
-}
-
-system( "mv $config_h.bak $config_h" ) and die "$config_h not restored\n";
-system( "make clean" ) and die;
-exit 0;
diff --git a/tests/scripts/depends-hashes.pl b/tests/scripts/depends-hashes.pl
deleted file mode 100755
index db18a92..0000000
--- a/tests/scripts/depends-hashes.pl
+++ /dev/null
@@ -1,101 +0,0 @@
-#!/usr/bin/env perl
-
-# depends-hashes.pl
-#
-# Copyright The Mbed TLS Contributors
-# SPDX-License-Identifier: Apache-2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# Purpose
-#
-# To test the code dependencies on individual hashes in each test suite. This
-# is a verification step to ensure we don't ship test suites that do not work
-# for some build options.
-#
-# The process is:
-#       for each possible hash
-#           build the library and test suites with the hash disabled
-#           execute the test suites
-#
-# And any test suite with the wrong dependencies will fail.
-#
-# Usage: tests/scripts/depends-hashes.pl
-#
-# This script should be executed from the root of the project directory.
-#
-# For best effect, run either with cmake disabled, or cmake enabled in a mode
-# that includes -Werror.
-
-use warnings;
-use strict;
-
--d 'library' && -d 'include' && -d 'tests' or die "Must be run from root\n";
-
-my $config_h = 'include/mbedtls/mbedtls_config.h';
-
-# as many SSL options depend on specific hashes,
-# and SSL is not in the test suites anyways,
-# disable it to avoid dependency issues
-my $ssl_sed_cmd = 's/^#define \(MBEDTLS_SSL.*\)/\1/p';
-my @ssl = split( /\s+/, `sed -n -e '$ssl_sed_cmd' $config_h` );
-
-# Each element of this array holds list of configuration options that
-# should be tested together. Certain options depend on each other and
-# separating them would generate invalid configurations.
-my @hash_configs = (
-    ['unset MBEDTLS_MD5_C'],
-    ['unset MBEDTLS_SHA512_C', 'unset MBEDTLS_SHA384_C '],
-    ['unset MBEDTLS_SHA384_C'],
-    ['unset MBEDTLS_SHA256_C', 'unset MBEDTLS_SHA224_C', 'unset MBEDTLS_LMS_C', 'unset MBEDTLS_LMS_PRIVATE'],
-    ['unset MBEDTLS_SHA1_C'],
-);
-
-system( "cp $config_h $config_h.bak" ) and die;
-sub abort {
-    system( "mv $config_h.bak $config_h" ) and warn "$config_h not restored\n";
-    # use an exit code between 1 and 124 for git bisect (die returns 255)
-    warn $_[0];
-    exit 1;
-}
-
-for my $hash_config (@hash_configs) {
-    system( "cp $config_h.bak $config_h" ) and die "$config_h not restored\n";
-    system( "make clean" ) and die;
-
-    my $hash_config_string = join(', ', @$hash_config);
-
-    print "\n******************************************\n";
-    print "* Testing hash options: $hash_config_string\n";
-    print "******************************************\n";
-    $ENV{MBEDTLS_TEST_CONFIGURATION} = "-$hash_config_string";
-
-    for my $hash (@$hash_config) {
-        system( "scripts/config.py $hash" )
-            and abort "Failed to $hash\n";
-    }
-
-    for my $opt (@ssl) {
-        system( "scripts/config.py unset $opt" )
-            and abort "Failed to disable $opt\n";
-    }
-
-    system( "CFLAGS='-Werror -Wall -Wextra' make lib" )
-        and abort "Failed to build lib: $hash_config_string\n";
-    system( "cd tests && make" ) and abort "Failed to build tests: $hash_config_string\n";
-    system( "make test" ) and abort "Failed test suite: $hash_config_string\n";
-}
-
-system( "mv $config_h.bak $config_h" ) and die "$config_h not restored\n";
-system( "make clean" ) and die;
-exit 0;
diff --git a/tests/scripts/depends-pkalgs.pl b/tests/scripts/depends-pkalgs.pl
deleted file mode 100755
index 6eb7269..0000000
--- a/tests/scripts/depends-pkalgs.pl
+++ /dev/null
@@ -1,107 +0,0 @@
-#!/usr/bin/env perl
-
-# depends-pkalgs.pl
-#
-# Copyright The Mbed TLS Contributors
-# SPDX-License-Identifier: Apache-2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# Purpose
-#
-# To test the code dependencies on individual PK algs (those that can be used
-# from the PK layer, so currently signature and encryption but not key
-# exchange) in each test suite. This is a verification step to ensure we don't
-# ship test suites that do not work for some build options.
-#
-# The process is:
-#       for each possible PK alg
-#           build the library and test suites with that alg disabled
-#           execute the test suites
-#
-# And any test suite with the wrong dependencies will fail.
-#
-# Usage: tests/scripts/depends-pkalgs.pl
-#
-# This script should be executed from the root of the project directory.
-#
-# For best effect, run either with cmake disabled, or cmake enabled in a mode
-# that includes -Werror.
-
-use warnings;
-use strict;
-
--d 'library' && -d 'include' && -d 'tests' or die "Must be run from root\n";
-
-my $config_h = 'include/mbedtls/mbedtls_config.h';
-
-# Some algorithms can't be disabled on their own as others depend on them, so
-# we list those reverse-dependencies here to keep check_config.h happy.
-my %algs = (
-    'MBEDTLS_ECDSA_C'   => ['MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED',
-                            'MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED'],
-    'MBEDTLS_ECP_C'     => ['MBEDTLS_ECDSA_C',
-                            'MBEDTLS_ECDH_C',
-                            'MBEDTLS_ECJPAKE_C',
-                            'MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED',
-                            'MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED',
-                            'MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED',
-                            'MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED',
-                            'MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED'],
-    'MBEDTLS_X509_RSASSA_PSS_SUPPORT'   => [],
-    'MBEDTLS_PKCS1_V21' => ['MBEDTLS_X509_RSASSA_PSS_SUPPORT'],
-    'MBEDTLS_PKCS1_V15' => ['MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED',
-                            'MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED',
-                            'MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED',
-                            'MBEDTLS_KEY_EXCHANGE_RSA_ENABLED'],
-    'MBEDTLS_RSA_C'     => ['MBEDTLS_X509_RSASSA_PSS_SUPPORT',
-                            'MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED',
-                            'MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED',
-                            'MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED',
-                            'MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED',
-                            'MBEDTLS_KEY_EXCHANGE_RSA_ENABLED'],
-);
-
-system( "cp $config_h $config_h.bak" ) and die;
-sub abort {
-    system( "mv $config_h.bak $config_h" ) and warn "$config_h not restored\n";
-    # use an exit code between 1 and 124 for git bisect (die returns 255)
-    warn $_[0];
-    exit 1;
-}
-
-while( my ($alg, $extras) = each %algs ) {
-    system( "cp $config_h.bak $config_h" ) and die "$config_h not restored\n";
-    system( "make clean" ) and die;
-
-    print "\n******************************************\n";
-    print "* Testing without alg: $alg\n";
-    print "******************************************\n";
-    $ENV{MBEDTLS_TEST_CONFIGURATION} = "-$alg";
-
-    system( "scripts/config.py unset $alg" )
-        and abort "Failed to disable $alg\n";
-    for my $opt (@$extras) {
-        system( "scripts/config.py unset $opt" )
-            and abort "Failed to disable $opt\n";
-    }
-
-    system( "CFLAGS='-Werror -Wall -Wextra' make lib" )
-        and abort "Failed to build lib: $alg\n";
-    system( "cd tests && make" ) and abort "Failed to build tests: $alg\n";
-    system( "make test" ) and abort "Failed test suite: $alg\n";
-}
-
-system( "mv $config_h.bak $config_h" ) and die "$config_h not restored\n";
-system( "make clean" ) and die;
-exit 0;
diff --git a/tests/scripts/depends.py b/tests/scripts/depends.py
index f2396ee..0d6ec94 100755
--- a/tests/scripts/depends.py
+++ b/tests/scripts/depends.py
@@ -146,6 +146,8 @@
     # Turn off options that are not relevant to the tests and slow them down.
     run_config_py(options, ['full'])
     run_config_py(options, ['unset', 'MBEDTLS_TEST_HOOKS'])
+    if options.unset_use_psa:
+        run_config_py(options, ['unset', 'MBEDTLS_USE_PSA_CRYPTO'])
 
 def collect_config_symbols(options):
     """Read the list of settings from mbedtls_config.h.
@@ -536,6 +538,9 @@
         parser.add_argument('--make-command', metavar='CMD',
                             help='Command to run instead of make (e.g. gmake)',
                             action='store', default='make')
+        parser.add_argument('--unset-use-psa',
+                            help='Unset MBEDTLS_USE_PSA_CRYPTO before any test',
+                            action='store_true', dest='unset_use_psa')
         parser.add_argument('tasks', metavar='TASKS', nargs='*',
                             help='The domain(s) or job(s) to test (default: all).',
                             default=True)
diff --git a/tests/scripts/key-exchanges.pl b/tests/scripts/key-exchanges.pl
deleted file mode 100755
index 46f1b97..0000000
--- a/tests/scripts/key-exchanges.pl
+++ /dev/null
@@ -1,76 +0,0 @@
-#!/usr/bin/env perl
-
-# key-exchanges.pl
-#
-# Copyright The Mbed TLS Contributors
-# SPDX-License-Identifier: Apache-2.0
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# Purpose
-#
-# To test the code dependencies on individual key exchanges in the SSL module.
-# is a verification step to ensure we don't ship SSL code that do not work
-# for some build options.
-#
-# The process is:
-#       for each possible key exchange
-#           build the library with all but that key exchange disabled
-#
-# Usage: tests/scripts/key-exchanges.pl
-#
-# This script should be executed from the root of the project directory.
-#
-# For best effect, run either with cmake disabled, or cmake enabled in a mode
-# that includes -Werror.
-
-use warnings;
-use strict;
-
--d 'library' && -d 'include' && -d 'tests' or die "Must be run from root\n";
-
-my $sed_cmd = 's/^#define \(MBEDTLS_KEY_EXCHANGE_.*_ENABLED\)/\1/p';
-my $config_h = 'include/mbedtls/mbedtls_config.h';
-my @kexes = split( /\s+/, `sed -n -e '$sed_cmd' $config_h` );
-
-system( "cp $config_h $config_h.bak" ) and die;
-sub abort {
-    system( "mv $config_h.bak $config_h" ) and warn "$config_h not restored\n";
-    # use an exit code between 1 and 124 for git bisect (die returns 255)
-    warn $_[0];
-    exit 1;
-}
-
-for my $kex (@kexes) {
-    system( "cp $config_h.bak $config_h" ) and die "$config_h not restored\n";
-    system( "make clean" ) and die;
-
-    print "\n******************************************\n";
-    print "* Testing with key exchange: $kex\n";
-    print "******************************************\n";
-    $ENV{MBEDTLS_TEST_CONFIGURATION} = $kex;
-
-    # full config with all key exchanges disabled except one
-    system( "scripts/config.py full" ) and abort "Failed config full\n";
-    for my $k (@kexes) {
-        next if $k eq $kex;
-        system( "scripts/config.py unset $k" )
-            and abort "Failed to disable $k\n";
-    }
-
-    system( "make lib CFLAGS='-Os -Werror'" ) and abort "Failed to build lib: $kex\n";
-}
-
-system( "mv $config_h.bak $config_h" ) and die "$config_h not restored\n";
-system( "make clean" ) and die;
-exit 0;
diff --git a/tests/suites/test_suite_bignum_core.function b/tests/suites/test_suite_bignum_core.function
index 74ee27a..57c2f37 100644
--- a/tests/suites/test_suite_bignum_core.function
+++ b/tests/suites/test_suite_bignum_core.function
@@ -5,6 +5,154 @@
 #include "constant_time_internal.h"
 #include "test/constant_flow.h"
 
+/** Verifies mbedtls_mpi_core_add().
+ *
+ * \param[in] A       Little-endian presentation of the left operand.
+ * \param[in] B       Little-endian presentation of the right operand.
+ * \param limbs       Number of limbs in each MPI (\p A, \p B, \p S and \p X).
+ * \param[in] S       Little-endian presentation of the expected sum.
+ * \param carry       Expected carry from the addition.
+ * \param[in,out] X   Temporary storage to be used for results.
+ *
+ * \return  1 if mbedtls_mpi_core_add() passes this test, otherwise 0.
+ */
+static int mpi_core_verify_add( mbedtls_mpi_uint *A,
+                                mbedtls_mpi_uint *B,
+                                size_t limbs,
+                                mbedtls_mpi_uint *S,
+                                int carry,
+                                mbedtls_mpi_uint *X )
+{
+    int ret = 0;
+
+    size_t bytes = limbs * sizeof( *A );
+
+    /* The test cases have A <= B to avoid repetition, so we test A + B then,
+     * if A != B, B + A. If A == B, we can test when A and B are aliased */
+
+    /* A + B */
+
+    /* A + B => correct result and carry */
+    TEST_EQUAL( carry, mbedtls_mpi_core_add( X, A, B, limbs ) );
+    ASSERT_COMPARE( X, bytes, S, bytes );
+
+    /* A + B; alias output and first operand => correct result and carry */
+    memcpy( X, A, bytes );
+    TEST_EQUAL( carry, mbedtls_mpi_core_add( X, X, B, limbs ) );
+    ASSERT_COMPARE( X, bytes, S, bytes );
+
+    /* A + B; alias output and second operand => correct result and carry */
+    memcpy( X, B, bytes );
+    TEST_EQUAL( carry, mbedtls_mpi_core_add( X, A, X, limbs ) );
+    ASSERT_COMPARE( X, bytes, S, bytes );
+
+    if ( memcmp( A, B, bytes ) == 0 )
+    {
+        /* A == B, so test where A and B are aliased */
+
+        /* A + A => correct result and carry */
+        TEST_EQUAL( carry, mbedtls_mpi_core_add( X, A, A, limbs ) );
+        ASSERT_COMPARE( X, bytes, S, bytes );
+
+        /* A + A, output aliased to both operands => correct result and carry */
+        memcpy( X, A, bytes );
+        TEST_EQUAL( carry, mbedtls_mpi_core_add( X, X, X, limbs ) );
+        ASSERT_COMPARE( X, bytes, S, bytes );
+    }
+    else
+    {
+        /* A != B, so test B + A */
+
+        /* B + A => correct result and carry */
+        TEST_EQUAL( carry, mbedtls_mpi_core_add( X, B, A, limbs ) );
+        ASSERT_COMPARE( X, bytes, S, bytes );
+
+        /* B + A; alias output and first operand => correct result and carry */
+        memcpy( X, B, bytes );
+        TEST_EQUAL( carry, mbedtls_mpi_core_add( X, X, A, limbs ) );
+        ASSERT_COMPARE( X, bytes, S, bytes );
+
+        /* B + A; alias output and second operand => correct result and carry */
+        memcpy( X, A, bytes );
+        TEST_EQUAL( carry, mbedtls_mpi_core_add( X, B, X, limbs ) );
+        ASSERT_COMPARE( X, bytes, S, bytes );
+    }
+
+    ret = 1;
+
+exit:
+    return ret;
+}
+
+/** Verifies mbedtls_mpi_core_add_if().
+ *
+ * \param[in] A       Little-endian presentation of the left operand.
+ * \param[in] B       Little-endian presentation of the right operand.
+ * \param limbs       Number of limbs in each MPI (\p A, \p B, \p S and \p X).
+ * \param[in] S       Little-endian presentation of the expected sum.
+ * \param carry       Expected carry from the addition.
+ * \param[in,out] X   Temporary storage to be used for results.
+ *
+ * \return  1 if mbedtls_mpi_core_add_if() passes this test, otherwise 0.
+ */
+static int mpi_core_verify_add_if( mbedtls_mpi_uint *A,
+                                   mbedtls_mpi_uint *B,
+                                   size_t limbs,
+                                   mbedtls_mpi_uint *S,
+                                   int carry,
+                                   mbedtls_mpi_uint *X )
+{
+    int ret = 0;
+
+    size_t bytes = limbs * sizeof( *A );
+
+    /* The test cases have A <= B to avoid repetition, so we test A + B then,
+     * if A != B, B + A. If A == B, we can test when A and B are aliased */
+
+    /* A + B */
+
+    /* cond = 0 => X unchanged, no carry */
+    memcpy( X, A, bytes );
+    TEST_EQUAL( 0, mbedtls_mpi_core_add_if( X, B, limbs, 0 ) );
+    ASSERT_COMPARE( X, bytes, A, bytes );
+
+    /* cond = 1 => correct result and carry */
+    TEST_EQUAL( carry, mbedtls_mpi_core_add_if( X, B, limbs, 1 ) );
+    ASSERT_COMPARE( X, bytes, S, bytes );
+
+    if ( memcmp( A, B, bytes ) == 0 )
+    {
+        /* A == B, so test where A and B are aliased */
+
+        /* cond = 0 => X unchanged, no carry */
+        memcpy( X, B, bytes );
+        TEST_EQUAL( 0, mbedtls_mpi_core_add_if( X, X, limbs, 0 ) );
+        ASSERT_COMPARE( X, bytes, B, bytes );
+
+        /* cond = 1 => correct result and carry */
+        TEST_EQUAL( carry, mbedtls_mpi_core_add_if( X, X, limbs, 1 ) );
+        ASSERT_COMPARE( X, bytes, S, bytes );
+    }
+    else
+    {
+        /* A != B, so test B + A */
+
+        /* cond = 0 => d unchanged, no carry */
+        memcpy( X, B, bytes );
+        TEST_EQUAL( 0, mbedtls_mpi_core_add_if( X, A, limbs, 0 ) );
+        ASSERT_COMPARE( X, bytes, B, bytes );
+
+        /* cond = 1 => correct result and carry */
+        TEST_EQUAL( carry, mbedtls_mpi_core_add_if( X, A, limbs, 1 ) );
+        ASSERT_COMPARE( X, bytes, S, bytes );
+    }
+
+    ret = 1;
+
+exit:
+    return ret;
+}
+
 /* END_HEADER */
 
 /* BEGIN_DEPENDENCIES
@@ -359,70 +507,28 @@
 /* END_CASE */
 
 /* BEGIN_CASE */
-void mpi_core_add_if( char * input_A, char * input_B,
-                      char * input_S, int carry )
+void mpi_core_add_and_add_if( char * input_A, char * input_B,
+                              char * input_S, int carry )
 {
     mbedtls_mpi_uint *A = NULL; /* first value to add */
-    size_t A_limbs;
     mbedtls_mpi_uint *B = NULL; /* second value to add */
-    size_t B_limbs;
     mbedtls_mpi_uint *S = NULL; /* expected result */
-    size_t S_limbs;
     mbedtls_mpi_uint *X = NULL; /* destination - the in/out first operand */
-    size_t X_limbs;
+    size_t A_limbs, B_limbs, S_limbs;
 
     TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &A, &A_limbs, input_A ) );
     TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &B, &B_limbs, input_B ) );
     TEST_EQUAL( 0, mbedtls_test_read_mpi_core( &S, &S_limbs, input_S ) );
-    X_limbs = S_limbs;
-    ASSERT_ALLOC( X, X_limbs );
 
-    /* add_if expects all operands to be the same length */
+    /* add and add_if expect all operands to be the same length */
     TEST_EQUAL( A_limbs, B_limbs );
     TEST_EQUAL( A_limbs, S_limbs );
+
     size_t limbs = A_limbs;
-    size_t bytes = limbs * sizeof( *A );
+    ASSERT_ALLOC( X, limbs );
 
-    /* The test cases have A <= B to avoid repetition, so we test A + B then,
-     * if A != B, B + A. If A == B, we can test when A and B are aliased */
-
-    /* A + B */
-
-    /* cond = 0 => X unchanged, no carry */
-    memcpy( X, A, bytes );
-    TEST_EQUAL( 0, mbedtls_mpi_core_add_if( X, B, limbs, 0 ) );
-    ASSERT_COMPARE( X, bytes, A, bytes );
-
-    /* cond = 1 => correct result and carry */
-    TEST_EQUAL( carry, mbedtls_mpi_core_add_if( X, B, limbs, 1 ) );
-    ASSERT_COMPARE( X, bytes, S, bytes );
-
-    if ( memcmp( A, B, bytes ) == 0 )
-    {
-        /* A == B, so test where A and B are aliased */
-
-        /* cond = 0 => X unchanged, no carry */
-        memcpy( X, B, bytes );
-        TEST_EQUAL( 0, mbedtls_mpi_core_add_if( X, X, limbs, 0 ) );
-        ASSERT_COMPARE( X, bytes, B, bytes );
-
-        /* cond = 1 => correct result and carry */
-        TEST_EQUAL( carry, mbedtls_mpi_core_add_if( X, X, limbs, 1 ) );
-        ASSERT_COMPARE( X, bytes, S, bytes );
-    }
-    else
-    {
-        /* A != B, so test B + A */
-
-        /* cond = 0 => d unchanged, no carry */
-        memcpy( X, B, bytes );
-        TEST_EQUAL( 0, mbedtls_mpi_core_add_if( X, A, limbs, 0 ) );
-        ASSERT_COMPARE( X, bytes, B, bytes );
-
-        /* cond = 1 => correct result and carry */
-        TEST_EQUAL( carry, mbedtls_mpi_core_add_if( X, A, limbs, 1 ) );
-        ASSERT_COMPARE( X, bytes, S, bytes );
-    }
+    TEST_ASSERT( mpi_core_verify_add( A, B, limbs, S, carry, X ) );
+    TEST_ASSERT( mpi_core_verify_add_if( A, B, limbs, S, carry, X ) );
 
 exit:
     mbedtls_free( A );
diff --git a/tests/suites/test_suite_dhm.data b/tests/suites/test_suite_dhm.data
index 3ecec3f..2ab5c43 100644
--- a/tests/suites/test_suite_dhm.data
+++ b/tests/suites/test_suite_dhm.data
@@ -109,11 +109,16 @@
 Diffie-Hellman MPI_MAX_SIZE + 1 modulus
 dhm_make_public:MBEDTLS_MPI_MAX_SIZE + 1:"5":MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED+MBEDTLS_ERR_MPI_BAD_INPUT_DATA
 
-Diffie-Hellman load parameters from file [#1]
+DH load parameters from PEM file (1024-bit, g=2)
+depends_on:MBEDTLS_PEM_PARSE_C
 dhm_file:"data_files/dhparams.pem":"9e35f430443a09904f3a39a979797d070df53378e79c2438bef4e761f3c714553328589b041c809be1d6c6b5f1fc9f47d3a25443188253a992a56818b37ba9de5a40d362e56eff0be5417474c125c199272c8fe41dea733df6f662c92ae76556e755d10c64e6a50968f67fc6ea73d0dca8569be2ba204e23580d8bca2f4975b3":"02":128
 
-Diffie-Hellman load parameters from file [#2]
+DH load parameters from PEM file (2048-bit, large g, privateValueLength)
+depends_on:MBEDTLS_PEM_PARSE_C
 dhm_file:"data_files/dh.optlen.pem":"b3126aeaf47153c7d67f403030b292b5bd5a6c9eae1c137af34087fce2a36a578d70c5c560ad2bdb924c4a4dbee20a1671be7103ce87defa76908936803dbeca60c33e1289c1a03ac2c6c4e49405e5902fa0596a1cbaa895cc402d5213ed4a5f1f5ba8b5e1ed3da951a4c475afeb0ca660b7368c38c8e809f382d96ae19e60dc984e61cb42b5dfd723322acf327f9e413cda6400c15c5b2ea1fa34405d83982fba40e6d852da3d91019bf23511314254dc211a90833e5b1798ee52a78198c555644729ad92f060367c74ded37704adfc273a4a33fec821bd2ebd3bc051730e97a4dd14d2b766062592f5eec09d16bb50efebf2cc00dd3e0e3418e60ec84870f7":"800abfe7dc667aa17bcd7c04614bc221a65482ccc04b604602b0e131908a938ea11b48dc515dab7abcbb1e0c7fd66511edc0d86551b7632496e03df94357e1c4ea07a7ce1e381a2fcafdff5f5bf00df828806020e875c00926e4d011f88477a1b01927d73813cad4847c6396b9244621be2b00b63c659253318413443cd244215cd7fd4cbe796e82c6cf70f89cc0c528fb8e344809b31876e7ef739d5160d095c9684188b0c8755c7a468d47f56d6db9ea012924ecb0556fb71312a8d7c93bb2898ea08ee54eeb594548285f06a973cbbe2a0cb02e90f323fe045521f34c68354a6d3e95dbfff1eb64692edc0a44f3d3e408d0e479a541e779a6054259e2d854":256
 
+DH load parameters from DER file (2048-bit, large g, privateValueLength)
+dhm_file:"data_files/dh.optlen.der":"b3126aeaf47153c7d67f403030b292b5bd5a6c9eae1c137af34087fce2a36a578d70c5c560ad2bdb924c4a4dbee20a1671be7103ce87defa76908936803dbeca60c33e1289c1a03ac2c6c4e49405e5902fa0596a1cbaa895cc402d5213ed4a5f1f5ba8b5e1ed3da951a4c475afeb0ca660b7368c38c8e809f382d96ae19e60dc984e61cb42b5dfd723322acf327f9e413cda6400c15c5b2ea1fa34405d83982fba40e6d852da3d91019bf23511314254dc211a90833e5b1798ee52a78198c555644729ad92f060367c74ded37704adfc273a4a33fec821bd2ebd3bc051730e97a4dd14d2b766062592f5eec09d16bb50efebf2cc00dd3e0e3418e60ec84870f7":"800abfe7dc667aa17bcd7c04614bc221a65482ccc04b604602b0e131908a938ea11b48dc515dab7abcbb1e0c7fd66511edc0d86551b7632496e03df94357e1c4ea07a7ce1e381a2fcafdff5f5bf00df828806020e875c00926e4d011f88477a1b01927d73813cad4847c6396b9244621be2b00b63c659253318413443cd244215cd7fd4cbe796e82c6cf70f89cc0c528fb8e344809b31876e7ef739d5160d095c9684188b0c8755c7a468d47f56d6db9ea012924ecb0556fb71312a8d7c93bb2898ea08ee54eeb594548285f06a973cbbe2a0cb02e90f323fe045521f34c68354a6d3e95dbfff1eb64692edc0a44f3d3e408d0e479a541e779a6054259e2d854":256
+
 Diffie-Hellman selftest
 dhm_selftest:
diff --git a/tests/suites/test_suite_pk.data b/tests/suites/test_suite_pk.data
index 3dc2b8b..bd5d31e 100644
--- a/tests/suites/test_suite_pk.data
+++ b/tests/suites/test_suite_pk.data
@@ -521,23 +521,23 @@
 pk_rsa_verify_ext_test_vec:"ae6e43dd387c25741e42fc3570cdfc52e4f51a2343294f3b677dfe01cd5339f6":MBEDTLS_MD_SHA256:1024:"00dd118a9f99bab068ca2aea3b6a6d5997ed4ec954e40deecea07da01eaae80ec2bb1340db8a128e891324a5c5f5fad8f590d7c8cacbc5fe931dafda1223735279461abaa0572b761631b3a8afe7389b088b63993a0a25ee45d21858bab9931aedd4589a631b37fcf714089f856549f359326dd1e0e86dde52ed66b4a90bda4095":"010001":"0d2bdb0456a3d651d5bd48a4204493898f72cf1aaddd71387cc058bc3f4c235ea6be4010fd61b28e1fbb275462b53775c04be9022d38b6a2e0387dddba86a3f8554d2858044a59fddbd594753fc056fe33c8daddb85dc70d164690b1182209ff84824e0be10e35c379f2f378bf176a9f7cb94d95e44d90276a298c8810f741c9":MBEDTLS_PK_RSASSA_PSS:MBEDTLS_MD_SHA256:94:129:MBEDTLS_ERR_RSA_VERIFY_FAILED
 
 Check pair #1 (EC, OK)
-depends_on:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+depends_on:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_PEM_PARSE_C
 mbedtls_pk_check_pair:"data_files/ec_256_pub.pem":"data_files/ec_256_prv.pem":0
 
 Check pair #2 (EC, bad)
-depends_on:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+depends_on:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_PEM_PARSE_C
 mbedtls_pk_check_pair:"data_files/ec_256_pub.pem":"data_files/server5.key":MBEDTLS_ERR_ECP_BAD_INPUT_DATA
 
 Check pair #3 (RSA, OK)
-depends_on:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
+depends_on:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_PEM_PARSE_C
 mbedtls_pk_check_pair:"data_files/server1.pubkey":"data_files/server1.key":0
 
 Check pair #4 (RSA, bad)
-depends_on:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
+depends_on:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_PEM_PARSE_C
 mbedtls_pk_check_pair:"data_files/server1.pubkey":"data_files/server2.key":MBEDTLS_ERR_RSA_KEY_CHECK_FAILED
 
 Check pair #5 (RSA vs EC)
-depends_on:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_RSA_C
+depends_on:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_RSA_C:MBEDTLS_PEM_PARSE_C
 mbedtls_pk_check_pair:"data_files/ec_256_pub.pem":"data_files/server1.key":MBEDTLS_ERR_PK_TYPE_MISMATCH
 
 RSA hash_len overflow (size_t vs unsigned int)