Merge pull request #298 from gilles-peskine-arm/config-symmetric-only

Test a build without any asymmetric cryptography
diff --git a/docs/getting_started.md b/docs/getting_started.md
index 236c1a2..9938909 100644
--- a/docs/getting_started.md
+++ b/docs/getting_started.md
@@ -72,9 +72,10 @@
 
 This example shows how to import a key:
 ```C
+void import_a_key(const uint8_t *key, size_t key_len)
+{
     psa_status_t status;
     psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
-    uint8_t data[] = AES_KEY;
     psa_key_handle_t handle;
 
     printf("Import an AES key...\t");
@@ -94,7 +95,7 @@
     psa_set_key_bits(&attributes, 128);
 
     /* Import the key */
-    status = psa_import_key(&attributes, data, sizeof(data), &handle);
+    status = psa_import_key(&attributes, key, key_len, &handle);
     if (status != PSA_SUCCESS) {
         printf("Failed to import key\n");
         return;
@@ -108,6 +109,7 @@
     psa_destroy_key(handle);
 
     mbedtls_psa_crypto_free();
+}
 ```
 
 ### Signing a message using RSA
@@ -123,9 +125,10 @@
 
 This example shows how to sign a hash that has already been calculated:
 ```C
+void sign_a_message_using_rsa(const uint8_t *key, size_t key_len)
+{
     psa_status_t status;
     psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
-    uint8_t key[] = RSA_KEY;
     uint8_t hash[32] = {0x50, 0xd8, 0x58, 0xe0, 0x98, 0x5e, 0xcc, 0x7f,
                         0x60, 0x41, 0x8a, 0xaf, 0x0c, 0xc5, 0xab, 0x58,
                         0x7f, 0x42, 0xc2, 0x57, 0x0a, 0x88, 0x40, 0x95,
@@ -151,7 +154,7 @@
     psa_set_key_bits(&attributes, 1024);
 
     /* Import the key */
-    status = psa_import_key(&attributes, key, sizeof(key), &handle);
+    status = psa_import_key(&attributes, key, key_len, &handle);
     if (status != PSA_SUCCESS) {
         printf("Failed to import key\n");
         return;
@@ -176,6 +179,7 @@
     psa_destroy_key(handle);
 
     mbedtls_psa_crypto_free();
+}
 ```
 
 ### Using symmetric ciphers
@@ -196,6 +200,8 @@
 
 This example shows how to encrypt data using an AES (Advanced Encryption Standard) key in CBC (Cipher Block Chaining) mode with no padding (assuming all prerequisites have been fulfilled):
 ```c
+void encrypt_with_symmetric_ciphers(const uint8_t *key, size_t key_len)
+{
     enum {
         block_size = PSA_BLOCK_CIPHER_BLOCK_SIZE(PSA_KEY_TYPE_AES),
     };
@@ -205,7 +211,6 @@
     uint8_t plaintext[block_size] = SOME_PLAINTEXT;
     uint8_t iv[block_size];
     size_t iv_len;
-    uint8_t key[] = AES_KEY;
     uint8_t output[block_size];
     size_t output_len;
     psa_key_handle_t handle;
@@ -227,7 +232,7 @@
     psa_set_key_algorithm(&attributes, alg);
     psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
     psa_set_key_bits(&attributes, 128);
-    status = psa_import_key(&attributes, key, sizeof(key), &handle);
+    status = psa_import_key(&attributes, key, key_len, &handle);
     if (status != PSA_SUCCESS) {
         printf("Failed to import a key\n");
         return;
@@ -266,6 +271,7 @@
     psa_destroy_key(handle);
 
     mbedtls_psa_crypto_free();
+}
 ```
 
 **To decrypt a message with a symmetric cipher:**
@@ -279,6 +285,8 @@
 This example shows how to decrypt encrypted data using an AES key in CBC mode with no padding
 (assuming all prerequisites have been fulfilled):
 ```c
+void decrypt_with_symmetric_ciphers(const uint8_t *key, size_t key_len)
+{
     enum {
         block_size = PSA_BLOCK_CIPHER_BLOCK_SIZE(PSA_KEY_TYPE_AES),
     };
@@ -288,7 +296,6 @@
     psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT;
     uint8_t ciphertext[block_size] = SOME_CIPHERTEXT;
     uint8_t iv[block_size] = ENCRYPTED_WITH_IV;
-    uint8_t key[] = AES_KEY;
     uint8_t output[block_size];
     size_t output_len;
     psa_key_handle_t handle;
@@ -309,7 +316,7 @@
     psa_set_key_algorithm(&attributes, alg);
     psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
     psa_set_key_bits(&attributes, 128);
-    status = psa_import_key(&attributes, key, sizeof(key), &handle);
+    status = psa_import_key(&attributes, key, key_len, &handle);
     if (status != PSA_SUCCESS) {
         printf("Failed to import a key\n");
         return;
@@ -348,6 +355,7 @@
     psa_destroy_key(handle);
 
     mbedtls_psa_crypto_free();
+}
 ```
 
 #### Handling cipher operation contexts
diff --git a/include/mbedtls/ctr_drbg.h b/include/mbedtls/ctr_drbg.h
index 2db4021..091f15a 100644
--- a/include/mbedtls/ctr_drbg.h
+++ b/include/mbedtls/ctr_drbg.h
@@ -12,30 +12,14 @@
  * The Mbed TLS implementation of CTR_DRBG uses AES-256 (default) or AES-128
  * (if \c MBEDTLS_CTR_DRBG_USE_128_BIT_KEY is enabled at compile time)
  * as the underlying block cipher, with a derivation function.
- * The initial seeding grabs #MBEDTLS_CTR_DRBG_ENTROPY_LEN bytes of entropy.
- * See the documentation of mbedtls_ctr_drbg_seed() for more details.
  *
- * Based on NIST SP 800-90A §10.2.1 table 3 and NIST SP 800-57 part 1 table 2,
- * here are the security strengths achieved in typical configuration:
- * - 256 bits under the default configuration of the library, with AES-256
- *   and with #MBEDTLS_CTR_DRBG_ENTROPY_LEN set to 48 or more.
- * - 256 bits if AES-256 is used, #MBEDTLS_CTR_DRBG_ENTROPY_LEN is set
- *   to 32 or more, and the DRBG is initialized with an explicit
- *   nonce in the \c custom parameter to mbedtls_ctr_drbg_seed().
- * - 128 bits if AES-256 is used but #MBEDTLS_CTR_DRBG_ENTROPY_LEN is
- *   between 24 and 47 and the DRBG is not initialized with an explicit
- *   nonce (see mbedtls_ctr_drbg_seed()).
- * - 128 bits if AES-128 is used (\c MBEDTLS_CTR_DRBG_USE_128_BIT_KEY enabled)
- *   and #MBEDTLS_CTR_DRBG_ENTROPY_LEN is set to 24 or more (which is
- *   always the case unless it is explicitly set to a different value
- *   in config.h).
- *
- * Note that the value of #MBEDTLS_CTR_DRBG_ENTROPY_LEN defaults to:
- * - \c 48 if the module \c MBEDTLS_SHA512_C is enabled and the symbol
- *   \c MBEDTLS_ENTROPY_FORCE_SHA256 is disabled at compile time.
- *   This is the default configuration of the library.
- * - \c 32 if the module \c MBEDTLS_SHA512_C is disabled at compile time.
- * - \c 32 if \c MBEDTLS_ENTROPY_FORCE_SHA256 is enabled at compile time.
+ * The security strength as defined in NIST SP 800-90A is
+ * 128 bits when AES-128 is used (\c MBEDTLS_CTR_DRBG_USE_128_BIT_KEY enabled)
+ * and 256 bits otherwise, provided that #MBEDTLS_CTR_DRBG_ENTROPY_LEN is
+ * kept at its default value (and not overridden in config.h) and that the
+ * DRBG instance is set up with default parameters.
+ * See the documentation of mbedtls_ctr_drbg_seed() for more
+ * information.
  */
 /*
  *  Copyright (C) 2006-2019, Arm Limited (or its affiliates), All Rights Reserved
@@ -163,20 +147,47 @@
 extern "C" {
 #endif
 
+#if MBEDTLS_CTR_DRBG_ENTROPY_LEN >= MBEDTLS_CTR_DRBG_KEYSIZE * 3 / 2
+/** The default length of the nonce read from the entropy source.
+ *
+ * This is \c 0 because a single read from the entropy source is sufficient
+ * to include a nonce.
+ * See the documentation of mbedtls_ctr_drbg_seed() for more information.
+ */
+#define MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN 0
+#else
+/** The default length of the nonce read from the entropy source.
+ *
+ * This is half of the default entropy length because a single read from
+ * the entropy source does not provide enough material to form a nonce.
+ * See the documentation of mbedtls_ctr_drbg_seed() for more information.
+ */
+#define MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN ( MBEDTLS_CTR_DRBG_ENTROPY_LEN + 1 ) / 2
+#endif
+
 /**
  * \brief          The CTR_DRBG context structure.
  */
 typedef struct mbedtls_ctr_drbg_context
 {
     unsigned char counter[16];  /*!< The counter (V). */
-    int reseed_counter;         /*!< The reseed counter. */
+    int reseed_counter;         /*!< The reseed counter.
+                                 * This is the number of requests that have
+                                 * been made since the last (re)seeding,
+                                 * minus one.
+                                 * Before the initial seeding, this field
+                                 * contains the amount of entropy in bytes
+                                 * to use as a nonce for the initial seeding.
+                                 */
     int prediction_resistance;  /*!< This determines whether prediction
                                      resistance is enabled, that is
                                      whether to systematically reseed before
                                      each random generation. */
     size_t entropy_len;         /*!< The amount of entropy grabbed on each
-                                     seed or reseed operation. */
-    int reseed_interval;        /*!< The reseed interval. */
+                                     seed or reseed operation, in bytes. */
+    int reseed_interval;        /*!< The reseed interval.
+                                 * This is the maximum number of requests
+                                 * that can be made between reseedings. */
 
     mbedtls_aes_context aes_ctx;        /*!< The AES context. */
 
@@ -214,47 +225,71 @@
  *   with mbedtls_entropy_init() (which registers the platform's default
  *   entropy sources).
  *
- * \p f_entropy is always called with a buffer size equal to the entropy
- * length. The entropy length is initially #MBEDTLS_CTR_DRBG_ENTROPY_LEN
- * and this value is always used for the initial seeding. You can change
- * the entropy length for subsequent seeding by calling
- * mbedtls_ctr_drbg_set_entropy_len() after this function.
+ * The entropy length is #MBEDTLS_CTR_DRBG_ENTROPY_LEN by default.
+ * You can override it by calling mbedtls_ctr_drbg_set_entropy_len().
  *
- * You can provide a personalization string in addition to the
+ * The entropy nonce length is:
+ * - \c 0 if the entropy length is at least 3/2 times the entropy length,
+ *   which guarantees that the security strength is the maximum permitted
+ *   by the key size and entropy length according to NIST SP 800-90A §10.2.1;
+ * - Half the entropy length otherwise.
+ * You can override it by calling mbedtls_ctr_drbg_set_nonce_len().
+ * With the default entropy length, the entropy nonce length is
+ * #MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN.
+ *
+ * You can provide a nonce and personalization string in addition to the
  * entropy source, to make this instantiation as unique as possible.
+ * See SP 800-90A §8.6.7 for more details about nonces.
  *
- * \note                The _seed_material_ value passed to the derivation
- *                      function in the CTR_DRBG Instantiate Process
- *                      described in NIST SP 800-90A §10.2.1.3.2
- *                      is the concatenation of the string obtained from
- *                      calling \p f_entropy and the \p custom string.
- *                      The origin of the nonce depends on the value of
- *                      the entropy length relative to the security strength.
- *                      - If the entropy length is at least 1.5 times the
- *                        security strength then the nonce is taken from the
- *                        string obtained with \p f_entropy.
- *                      - If the entropy length is less than the security
- *                        strength, then the nonce is taken from \p custom.
- *                        In this case, for compliance with SP 800-90A,
- *                        you must pass a unique value of \p custom at
- *                        each invocation. See SP 800-90A §8.6.7 for more
- *                        details.
+ * The _seed_material_ value passed to the derivation function in
+ * the CTR_DRBG Instantiate Process described in NIST SP 800-90A §10.2.1.3.2
+ * is the concatenation of the following strings:
+ * - A string obtained by calling \p f_entropy function for the entropy
+ *   length.
  */
-#if MBEDTLS_CTR_DRBG_ENTROPY_LEN < MBEDTLS_CTR_DRBG_KEYSIZE * 3 / 2
-/** \warning            When #MBEDTLS_CTR_DRBG_ENTROPY_LEN is less than
- *                      #MBEDTLS_CTR_DRBG_KEYSIZE * 3 / 2, to achieve the
- *                      maximum security strength permitted by CTR_DRBG,
- *                      you must pass a value of \p custom that is a nonce:
- *                      this value must never be repeated in subsequent
- *                      runs of the same application or on a different
- *                      device.
+#if MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN == 0
+/**
+ * - If mbedtls_ctr_drbg_set_nonce_len() has been called, a string
+ *   obtained by calling \p f_entropy function for the specified length.
+ */
+#else
+/**
+ * - A string obtained by calling \p f_entropy function for the entropy nonce
+ *   length. If the entropy nonce length is \c 0, this function does not
+ *   make a second call to \p f_entropy.
  */
 #endif
 /**
+ * - The \p custom string.
+ *
+ * \note                To achieve the nominal security strength permitted
+ *                      by CTR_DRBG, the entropy length must be:
+ *                      - at least 16 bytes for a 128-bit strength
+ *                      (maximum achievable strength when using AES-128);
+ *                      - at least 32 bytes for a 256-bit strength
+ *                      (maximum achievable strength when using AES-256).
+ *
+ *                      In addition, if you do not pass a nonce in \p custom,
+ *                      the sum of the entropy length
+ *                      and the entropy nonce length must be:
+ *                      - at least 24 bytes for a 128-bit strength
+ *                      (maximum achievable strength when using AES-128);
+ *                      - at least 48 bytes for a 256-bit strength
+ *                      (maximum achievable strength when using AES-256).
+ *
  * \param ctx           The CTR_DRBG context to seed.
+ *                      It must have been initialized with
+ *                      mbedtls_ctr_drbg_init().
+ *                      After a successful call to mbedtls_ctr_drbg_seed(),
+ *                      you may not call mbedtls_ctr_drbg_seed() again on
+ *                      the same context unless you call
+ *                      mbedtls_ctr_drbg_free() and mbedtls_ctr_drbg_init()
+ *                      again first.
  * \param f_entropy     The entropy callback, taking as arguments the
  *                      \p p_entropy context, the buffer to fill, and the
  *                      length of the buffer.
+ *                      \p f_entropy is always called with a buffer size
+ *                      less than or equal to the entropy length.
  * \param p_entropy     The entropy context to pass to \p f_entropy.
  * \param custom        The personalization string.
  *                      This can be \c NULL, in which case the personalization
@@ -298,15 +333,10 @@
 
 /**
  * \brief               This function sets the amount of entropy grabbed on each
- *                      subsequent reseed.
+ *                      seed or reseed.
  *
  * The default value is #MBEDTLS_CTR_DRBG_ENTROPY_LEN.
  *
- * \note                mbedtls_ctr_drbg_seed() always sets the entropy length
- *                      to #MBEDTLS_CTR_DRBG_ENTROPY_LEN, so this function
- *                      only has an effect when it is called after
- *                      mbedtls_ctr_drbg_seed().
- *
  * \note                The security strength of CTR_DRBG is bounded by the
  *                      entropy length. Thus:
  *                      - When using AES-256
@@ -321,12 +351,36 @@
  *
  * \param ctx           The CTR_DRBG context.
  * \param len           The amount of entropy to grab, in bytes.
- *                      This must be at most #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT.
+ *                      This must be at most #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT
+ *                      and at most the maximum length accepted by the
+ *                      entropy function that is set in the context.
  */
 void mbedtls_ctr_drbg_set_entropy_len( mbedtls_ctr_drbg_context *ctx,
                                size_t len );
 
 /**
+ * \brief               This function sets the amount of entropy grabbed
+ *                      as a nonce for the initial seeding.
+ *
+ * Call this function before calling mbedtls_ctr_drbg_seed() to read
+ * a nonce from the entropy source during the initial seeding.
+ *
+ * \param ctx           The CTR_DRBG context.
+ * \param len           The amount of entropy to grab for the nonce, in bytes.
+ *                      This must be at most #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT
+ *                      and at most the maximum length accepted by the
+ *                      entropy function that is set in the context.
+ *
+ * \return              \c 0 on success.
+ * \return              #MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG if \p len is
+ *                      more than #MBEDTLS_CTR_DRBG_MAX_SEED_INPUT.
+ * \return              #MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED
+ *                      if the initial seeding has already taken place.
+ */
+int mbedtls_ctr_drbg_set_nonce_len( mbedtls_ctr_drbg_context *ctx,
+                                    size_t len );
+
+/**
  * \brief               This function sets the reseed interval.
  *
  * The reseed interval is the number of calls to mbedtls_ctr_drbg_random()
@@ -499,11 +553,6 @@
 
 #endif /* MBEDTLS_SELF_TEST */
 
-/* Internal functions (do not call directly) */
-int mbedtls_ctr_drbg_seed_entropy_len( mbedtls_ctr_drbg_context *,
-                               int (*)(void *, unsigned char *, size_t), void *,
-                               const unsigned char *, size_t, size_t );
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/mbedtls/hmac_drbg.h b/include/mbedtls/hmac_drbg.h
index 519d692..00be9df 100644
--- a/include/mbedtls/hmac_drbg.h
+++ b/include/mbedtls/hmac_drbg.h
@@ -139,13 +139,11 @@
  *                      Note that SHA-256 is just as efficient as SHA-224.
  *                      The security strength can be reduced if a smaller
  *                      entropy length is set with
- *                      mbedtls_hmac_drbg_set_entropy_len() afterwards.
+ *                      mbedtls_hmac_drbg_set_entropy_len().
  *
- * \note                The entropy length for the initial seeding is
- *                      the security strength (converted from bits to bytes).
- *                      You can set a different entropy length for subsequent
- *                      seeding by calling mbedtls_hmac_drbg_set_entropy_len()
- *                      after this function.
+ * \note                The default entropy length is the security strength
+ *                      (converted from bits to bytes). You can override
+ *                      it by calling mbedtls_hmac_drbg_set_entropy_len().
  *
  * \note                During the initial seeding, this function calls
  *                      the entropy source to obtain a nonce
@@ -224,14 +222,9 @@
 
 /**
  * \brief               This function sets the amount of entropy grabbed on each
- *                      reseed.
+ *                      seed or reseed.
  *
- * The default value is set by mbedtls_hmac_drbg_seed().
- *
- * \note                mbedtls_hmac_drbg_seed() always sets the entropy length
- *                      to the default value based on the chosen MD algorithm,
- *                      so this function only has an effect if it is called
- *                      after mbedtls_hmac_drbg_seed().
+ * See the documentation of mbedtls_hmac_drbg_seed() for the default value.
  *
  * \param ctx           The HMAC_DRBG context.
  * \param len           The amount of entropy to grab, in bytes.
diff --git a/include/psa/crypto.h b/include/psa/crypto.h
index d3b7522..7291c3e 100644
--- a/include/psa/crypto.h
+++ b/include/psa/crypto.h
@@ -459,9 +459,12 @@
  * maintain the key handle until after the multipart operation has finished.
  *
  * \param handle        The key handle to close.
+ *                      If this is \c 0, do nothing and return \c PSA_SUCCESS.
  *
  * \retval #PSA_SUCCESS
+ *         \p handle was a valid handle or \c 0. It is now closed.
  * \retval #PSA_ERROR_INVALID_HANDLE
+ *         \p handle is not a valid handle nor \c 0.
  * \retval #PSA_ERROR_COMMUNICATION_FAILURE
  * \retval #PSA_ERROR_CORRUPTION_DETECTED
  * \retval #PSA_ERROR_BAD_STATE
@@ -579,13 +582,17 @@
  * key will cause the multipart operation to fail.
  *
  * \param handle        Handle to the key to erase.
+ *                      If this is \c 0, do nothing and return \c PSA_SUCCESS.
  *
  * \retval #PSA_SUCCESS
- *         The key material has been erased.
+ *         \p handle was a valid handle and the key material that it
+ *         referred to has been erased.
+ *         Alternatively, \p handle is \c 0.
  * \retval #PSA_ERROR_NOT_PERMITTED
  *         The key cannot be erased because it is
  *         read-only, either due to a policy or due to physical restrictions.
  * \retval #PSA_ERROR_INVALID_HANDLE
+ *         \p handle is not a valid handle nor \c 0.
  * \retval #PSA_ERROR_COMMUNICATION_FAILURE
  *         There was an failure in communication with the cryptoprocessor.
  *         The key material may still be present in the cryptoprocessor.
diff --git a/library/ctr_drbg.c b/library/ctr_drbg.c
index 0db7beb..047bb2a 100644
--- a/library/ctr_drbg.c
+++ b/library/ctr_drbg.c
@@ -56,76 +56,15 @@
 void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx )
 {
     memset( ctx, 0, sizeof( mbedtls_ctr_drbg_context ) );
+    /* Indicate that the entropy nonce length is not set explicitly.
+     * See mbedtls_ctr_drbg_set_nonce_len(). */
+    ctx->reseed_counter = -1;
 
 #if defined(MBEDTLS_THREADING_C)
     mbedtls_mutex_init( &ctx->mutex );
 #endif
 }
 
-/*
- * Non-public function wrapped by mbedtls_ctr_drbg_seed(). Necessary to allow
- * NIST tests to succeed (which require known length fixed entropy)
- */
-/* CTR_DRBG_Instantiate with derivation function (SP 800-90A &sect;10.2.1.3.2)
- * mbedtls_ctr_drbg_seed_entropy_len(ctx, f_entropy, p_entropy,
- *                                   custom, len, entropy_len)
- * implements
- * CTR_DRBG_Instantiate(entropy_input, nonce, personalization_string,
- *                      security_strength) -> initial_working_state
- * with inputs
- *   custom[:len] = nonce || personalization_string
- * where entropy_input comes from f_entropy for entropy_len bytes
- * and with outputs
- *   ctx = initial_working_state
- */
-int mbedtls_ctr_drbg_seed_entropy_len(
-                   mbedtls_ctr_drbg_context *ctx,
-                   int (*f_entropy)(void *, unsigned char *, size_t),
-                   void *p_entropy,
-                   const unsigned char *custom,
-                   size_t len,
-                   size_t entropy_len )
-{
-    int ret;
-    unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE];
-
-    memset( key, 0, MBEDTLS_CTR_DRBG_KEYSIZE );
-
-    mbedtls_aes_init( &ctx->aes_ctx );
-
-    ctx->f_entropy = f_entropy;
-    ctx->p_entropy = p_entropy;
-
-    ctx->entropy_len = entropy_len;
-    ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL;
-
-    /*
-     * Initialize with an empty key
-     */
-    if( ( ret = mbedtls_aes_setkey_enc( &ctx->aes_ctx, key,
-                                        MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 )
-    {
-        return( ret );
-    }
-
-    if( ( ret = mbedtls_ctr_drbg_reseed( ctx, custom, len ) ) != 0 )
-    {
-        return( ret );
-    }
-    return( 0 );
-}
-
-int mbedtls_ctr_drbg_seed( mbedtls_ctr_drbg_context *ctx,
-                   int (*f_entropy)(void *, unsigned char *, size_t),
-                   void *p_entropy,
-                   const unsigned char *custom,
-                   size_t len )
-{
-    return( mbedtls_ctr_drbg_seed_entropy_len( ctx, f_entropy, p_entropy,
-                                               custom, len,
-                                               MBEDTLS_CTR_DRBG_ENTROPY_LEN ) );
-}
-
 void mbedtls_ctr_drbg_free( mbedtls_ctr_drbg_context *ctx )
 {
     if( ctx == NULL )
@@ -150,6 +89,32 @@
     ctx->entropy_len = len;
 }
 
+int mbedtls_ctr_drbg_set_nonce_len( mbedtls_ctr_drbg_context *ctx,
+                                    size_t len )
+{
+    /* If mbedtls_ctr_drbg_seed() has already been called, it's
+     * too late. Return the error code that's closest to making sense. */
+    if( ctx->f_entropy != NULL )
+        return( MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED );
+
+    if( len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT )
+        return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
+#if SIZE_MAX > INT_MAX
+    /* This shouldn't be an issue because
+     * MBEDTLS_CTR_DRBG_MAX_SEED_INPUT < INT_MAX in any sensible
+     * configuration, but make sure anyway. */
+    if( len > INT_MAX )
+        return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
+#endif
+
+    /* For backward compatibility with Mbed TLS <= 2.19, store the
+     * entropy nonce length in a field that already exists, but isn't
+     * used until after the initial seeding. */
+    /* Due to the capping of len above, the value fits in an int. */
+    ctx->reseed_counter = (int) len;
+    return( 0 );
+}
+
 void mbedtls_ctr_drbg_set_reseed_interval( mbedtls_ctr_drbg_context *ctx,
                                            int interval )
 {
@@ -383,7 +348,7 @@
 #endif /* MBEDTLS_DEPRECATED_REMOVED */
 
 /* CTR_DRBG_Reseed with derivation function (SP 800-90A &sect;10.2.1.4.2)
- * mbedtls_ctr_drbg_reseed(ctx, additional, len)
+ * mbedtls_ctr_drbg_reseed(ctx, additional, len, nonce_len)
  * implements
  * CTR_DRBG_Reseed(working_state, entropy_input, additional_input)
  *                -> new_working_state
@@ -391,51 +356,57 @@
  *   ctx contains working_state
  *   additional[:len] = additional_input
  * and entropy_input comes from calling ctx->f_entropy
+ *                              for (ctx->entropy_len + nonce_len) bytes
  * and with output
  *   ctx contains new_working_state
  */
-int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx,
-                     const unsigned char *additional, size_t len )
+static int mbedtls_ctr_drbg_reseed_internal( mbedtls_ctr_drbg_context *ctx,
+                                             const unsigned char *additional,
+                                             size_t len,
+                                             size_t nonce_len )
 {
     unsigned char seed[MBEDTLS_CTR_DRBG_MAX_SEED_INPUT];
     size_t seedlen = 0;
     int ret;
 
-    if( ctx->entropy_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT ||
-        len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - ctx->entropy_len )
+    if( ctx->entropy_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT )
+        return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
+    if( nonce_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - ctx->entropy_len )
+        return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
+    if( len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - ctx->entropy_len - nonce_len )
         return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
 
     memset( seed, 0, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT );
 
-    /*
-     * Gather entropy_len bytes of entropy to seed state
-     */
-    if( 0 != ctx->f_entropy( ctx->p_entropy, seed,
-                             ctx->entropy_len ) )
+    /* Gather entropy_len bytes of entropy to seed state. */
+    if( 0 != ctx->f_entropy( ctx->p_entropy, seed, ctx->entropy_len ) )
     {
         return( MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED );
     }
-
     seedlen += ctx->entropy_len;
 
-    /*
-     * Add additional data
-     */
-    if( additional && len )
+    /* Gather entropy for a nonce if requested. */
+    if( nonce_len != 0 )
+    {
+        if( 0 != ctx->f_entropy( ctx->p_entropy, seed, nonce_len ) )
+        {
+            return( MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED );
+        }
+        seedlen += nonce_len;
+    }
+
+    /* Add additional data if provided. */
+    if( additional != NULL && len != 0 )
     {
         memcpy( seed + seedlen, additional, len );
         seedlen += len;
     }
 
-    /*
-     * Reduce to 384 bits
-     */
+    /* Reduce to 384 bits. */
     if( ( ret = block_cipher_df( seed, seed, seedlen ) ) != 0 )
         goto exit;
 
-    /*
-     * Update state
-     */
+    /* Update state. */
     if( ( ret = ctr_drbg_update_internal( ctx, seed ) ) != 0 )
         goto exit;
     ctx->reseed_counter = 1;
@@ -445,6 +416,81 @@
     return( ret );
 }
 
+int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx,
+                             const unsigned char *additional, size_t len )
+{
+    return( mbedtls_ctr_drbg_reseed_internal( ctx, additional, len, 0 ) );
+}
+
+/* Return a "good" nonce length for CTR_DRBG. The chosen nonce length
+ * is sufficient to achieve the maximum security strength given the key
+ * size and entropy length. If there is enough entropy in the initial
+ * call to the entropy function to serve as both the entropy input and
+ * the nonce, don't make a second call to get a nonce. */
+static size_t good_nonce_len( size_t entropy_len )
+{
+    if( entropy_len >= MBEDTLS_CTR_DRBG_KEYSIZE * 3 / 2 )
+        return( 0 );
+    else
+        return( ( entropy_len + 1 ) / 2 );
+}
+
+/* CTR_DRBG_Instantiate with derivation function (SP 800-90A &sect;10.2.1.3.2)
+ * mbedtls_ctr_drbg_seed(ctx, f_entropy, p_entropy, custom, len)
+ * implements
+ * CTR_DRBG_Instantiate(entropy_input, nonce, personalization_string,
+ *                      security_strength) -> initial_working_state
+ * with inputs
+ *   custom[:len] = nonce || personalization_string
+ * where entropy_input comes from f_entropy for ctx->entropy_len bytes
+ * and with outputs
+ *   ctx = initial_working_state
+ */
+int mbedtls_ctr_drbg_seed( mbedtls_ctr_drbg_context *ctx,
+                           int (*f_entropy)(void *, unsigned char *, size_t),
+                           void *p_entropy,
+                           const unsigned char *custom,
+                           size_t len )
+{
+    int ret;
+    unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE];
+    size_t nonce_len;
+
+    memset( key, 0, MBEDTLS_CTR_DRBG_KEYSIZE );
+
+    mbedtls_aes_init( &ctx->aes_ctx );
+
+    ctx->f_entropy = f_entropy;
+    ctx->p_entropy = p_entropy;
+
+    if( ctx->entropy_len == 0 )
+        ctx->entropy_len = MBEDTLS_CTR_DRBG_ENTROPY_LEN;
+    /* ctx->reseed_counter contains the desired amount of entropy to
+     * grab for a nonce (see mbedtls_ctr_drbg_set_nonce_len()).
+     * If it's -1, indicating that the entropy nonce length was not set
+     * explicitly, use a sufficiently large nonce for security. */
+    nonce_len = ( ctx->reseed_counter >= 0 ?
+                  (size_t) ctx->reseed_counter :
+                  good_nonce_len( ctx->entropy_len ) );
+
+    ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL;
+
+    /* Initialize with an empty key. */
+    if( ( ret = mbedtls_aes_setkey_enc( &ctx->aes_ctx, key,
+                                        MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 )
+    {
+        return( ret );
+    }
+
+    /* Do the initial seeding. */
+    if( ( ret = mbedtls_ctr_drbg_reseed_internal( ctx, custom, len,
+                                                  nonce_len ) ) != 0 )
+    {
+        return( ret );
+    }
+    return( 0 );
+}
+
 /* CTR_DRBG_Generate with derivation function (SP 800-90A &sect;10.2.1.5.2)
  * mbedtls_ctr_drbg_random_with_add(ctx, output, output_len, additional, add_len)
  * implements
@@ -708,8 +754,12 @@
         mbedtls_printf( "  CTR_DRBG (PR = TRUE) : " );
 
     test_offset = 0;
-    CHK( mbedtls_ctr_drbg_seed_entropy_len( &ctx, ctr_drbg_self_test_entropy,
-                         (void *) entropy_source_pr, nonce_pers_pr, 16, 32 ) );
+    mbedtls_ctr_drbg_set_entropy_len( &ctx, 32 );
+    mbedtls_ctr_drbg_set_nonce_len( &ctx, 0 );
+    CHK( mbedtls_ctr_drbg_seed( &ctx,
+                                ctr_drbg_self_test_entropy,
+                                (void *) entropy_source_pr,
+                                nonce_pers_pr, 16 ) );
     mbedtls_ctr_drbg_set_prediction_resistance( &ctx, MBEDTLS_CTR_DRBG_PR_ON );
     CHK( mbedtls_ctr_drbg_random( &ctx, buf, MBEDTLS_CTR_DRBG_BLOCKSIZE ) );
     CHK( mbedtls_ctr_drbg_random( &ctx, buf, MBEDTLS_CTR_DRBG_BLOCKSIZE ) );
@@ -729,8 +779,12 @@
     mbedtls_ctr_drbg_init( &ctx );
 
     test_offset = 0;
-    CHK( mbedtls_ctr_drbg_seed_entropy_len( &ctx, ctr_drbg_self_test_entropy,
-                     (void *) entropy_source_nopr, nonce_pers_nopr, 16, 32 ) );
+    mbedtls_ctr_drbg_set_entropy_len( &ctx, 32 );
+    mbedtls_ctr_drbg_set_nonce_len( &ctx, 0 );
+    CHK( mbedtls_ctr_drbg_seed( &ctx,
+                                ctr_drbg_self_test_entropy,
+                                (void *) entropy_source_nopr,
+                                nonce_pers_nopr, 16 ) );
     CHK( mbedtls_ctr_drbg_random( &ctx, buf, 16 ) );
     CHK( mbedtls_ctr_drbg_reseed( &ctx, NULL, 0 ) );
     CHK( mbedtls_ctr_drbg_random( &ctx, buf, 16 ) );
diff --git a/library/hmac_drbg.c b/library/hmac_drbg.c
index 50d88bd..284c9b4 100644
--- a/library/hmac_drbg.c
+++ b/library/hmac_drbg.c
@@ -273,16 +273,19 @@
 
     ctx->reseed_interval = MBEDTLS_HMAC_DRBG_RESEED_INTERVAL;
 
-    /*
-     * See SP800-57 5.6.1 (p. 65-66) for the security strength provided by
-     * each hash function, then according to SP800-90A rev1 10.1 table 2,
-     * min_entropy_len (in bits) is security_strength.
-     *
-     * (This also matches the sizes used in the NIST test vectors.)
-     */
-    ctx->entropy_len = md_size <= 20 ? 16 : /* 160-bits hash -> 128 bits */
-                       md_size <= 28 ? 24 : /* 224-bits hash -> 192 bits */
-                       32;  /* better (256+) -> 256 bits */
+    if( ctx->entropy_len == 0 )
+    {
+        /*
+         * See SP800-57 5.6.1 (p. 65-66) for the security strength provided by
+         * each hash function, then according to SP800-90A rev1 10.1 table 2,
+         * min_entropy_len (in bits) is security_strength.
+         *
+         * (This also matches the sizes used in the NIST test vectors.)
+         */
+        ctx->entropy_len = md_size <= 20 ? 16 : /* 160-bits hash -> 128 bits */
+                           md_size <= 28 ? 24 : /* 224-bits hash -> 192 bits */
+                           32;  /* better (256+) -> 256 bits */
+    }
 
     if( ( ret = hmac_drbg_reseed_core( ctx, custom, len,
                                        1 /* add nonce */ ) ) != 0 )
@@ -303,7 +306,7 @@
 }
 
 /*
- * Set entropy length grabbed for reseeds
+ * Set entropy length grabbed for seeding
  */
 void mbedtls_hmac_drbg_set_entropy_len( mbedtls_hmac_drbg_context *ctx, size_t len )
 {
diff --git a/library/pkwrite.c b/library/pkwrite.c
index 4388160..c2c5623 100644
--- a/library/pkwrite.c
+++ b/library/pkwrite.c
@@ -38,7 +38,9 @@
 #include "mbedtls/rsa.h"
 #endif
 #if defined(MBEDTLS_ECP_C)
+#include "mbedtls/bignum.h"
 #include "mbedtls/ecp.h"
+#include "mbedtls/platform_util.h"
 #endif
 #if defined(MBEDTLS_ECDSA_C)
 #include "mbedtls/ecdsa.h"
@@ -154,6 +156,26 @@
 
     return( (int) len );
 }
+
+/*
+ * privateKey  OCTET STRING -- always of length ceil(log2(n)/8)
+ */
+static int pk_write_ec_private( unsigned char **p, unsigned char *start,
+                                mbedtls_ecp_keypair *ec )
+{
+    int ret;
+    size_t byte_length = ( ec->grp.pbits + 7 ) / 8;
+    unsigned char tmp[MBEDTLS_ECP_MAX_BYTES];
+
+    ret = mbedtls_mpi_write_binary( &ec->d, tmp, byte_length );
+    if( ret != 0 )
+        goto exit;
+    ret = mbedtls_asn1_write_octet_string( p, start, tmp, byte_length );
+
+exit:
+    mbedtls_platform_zeroize( tmp, byte_length );
+    return( ret );
+}
 #endif /* MBEDTLS_ECP_C */
 
 int mbedtls_pk_write_pubkey( unsigned char **p, unsigned char *start,
@@ -424,9 +446,8 @@
                             MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0 ) );
         len += par_len;
 
-        /* privateKey: write as MPI then fix tag */
-        MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf, &ec->d ) );
-        *c = MBEDTLS_ASN1_OCTET_STRING;
+        /* privateKey */
+        MBEDTLS_ASN1_CHK_ADD( len, pk_write_ec_private( &c, buf, ec ) );
 
         /* version */
         MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, buf, 1 ) );
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index e6ef7f7..e4d4924 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -1013,6 +1013,9 @@
     psa_se_drv_table_entry_t *driver;
 #endif /* MBEDTLS_PSA_CRYPTO_SE_C */
 
+    if( handle == 0 )
+        return( PSA_SUCCESS );
+
     status = psa_get_key_slot( handle, &slot );
     if( status != PSA_SUCCESS )
         return( status );
diff --git a/library/psa_crypto_slot_management.c b/library/psa_crypto_slot_management.c
index 59be319..6cd6a11 100644
--- a/library/psa_crypto_slot_management.c
+++ b/library/psa_crypto_slot_management.c
@@ -255,6 +255,9 @@
     psa_status_t status;
     psa_key_slot_t *slot;
 
+    if( handle == 0 )
+        return( PSA_SUCCESS );
+
     status = psa_get_key_slot( handle, &slot );
     if( status != PSA_SUCCESS )
         return( status );
diff --git a/library/psa_crypto_storage.c b/library/psa_crypto_storage.c
index a27442c..1389fd4 100644
--- a/library/psa_crypto_storage.c
+++ b/library/psa_crypto_storage.c
@@ -419,7 +419,7 @@
 {
     struct psa_storage_info_t p_info;
     psa_status_t status;
-    status = psa_its_get_info( PSA_CRYPTO_ITS_RANDOM_SEED_UID, &p_info );
+    status = psa_its_get_info( PSA_CRYPTO_ITS_TRANSACTION_UID, &p_info );
     if( status == PSA_SUCCESS )
     {
         /* This shouldn't happen: we're trying to start a transaction while
diff --git a/programs/test/benchmark.c b/programs/test/benchmark.c
index b005c20..8f89c70 100644
--- a/programs/test/benchmark.c
+++ b/programs/test/benchmark.c
@@ -686,12 +686,13 @@
         mbedtls_ctr_drbg_context ctr_drbg;
 
         mbedtls_ctr_drbg_init( &ctr_drbg );
-
         if( mbedtls_ctr_drbg_seed( &ctr_drbg, myrand, NULL, NULL, 0 ) != 0 )
             mbedtls_exit(1);
         TIME_AND_TSC( "CTR_DRBG (NOPR)",
                 mbedtls_ctr_drbg_random( &ctr_drbg, buf, BUFSIZE ) );
+        mbedtls_ctr_drbg_free( &ctr_drbg );
 
+        mbedtls_ctr_drbg_init( &ctr_drbg );
         if( mbedtls_ctr_drbg_seed( &ctr_drbg, myrand, NULL, NULL, 0 ) != 0 )
             mbedtls_exit(1);
         mbedtls_ctr_drbg_set_prediction_resistance( &ctr_drbg, MBEDTLS_CTR_DRBG_PR_ON );
diff --git a/tests/data_files/ec_256_long_prv.pem b/tests/data_files/ec_256_long_prv.pem
new file mode 100644
index 0000000..5141e30
--- /dev/null
+++ b/tests/data_files/ec_256_long_prv.pem
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIIcex4mqXsQamUKTVf8vXmTAJrQvGjh5mXG8p9+OR4xAoAoGCCqGSM49
+AwEHoUQDQgAEqJ2HQjPpc6fDwE/vSa6U35USXawkTo98y4U6NsAl+rOGuqMPEFXf
+P1Srm/Jrzwa/RuppRL5kgyAsGJTUmwZEzQ==
+-----END EC PRIVATE KEY-----
diff --git a/tests/data_files/ec_521_short_prv.pem b/tests/data_files/ec_521_short_prv.pem
new file mode 100644
index 0000000..427b7ad
--- /dev/null
+++ b/tests/data_files/ec_521_short_prv.pem
@@ -0,0 +1,7 @@
+-----BEGIN EC PRIVATE KEY-----
+MIHcAgEBBEIAOXdk7W+Hf5L7Hc9fKe44wmpaRNs5ERFTkv5CrlXv/Bu3y28M673q
+vBNo7a/UE/6NNQHu2pQODEYFpMg6R34b5SigBwYFK4EEACOhgYkDgYYABAFUMHXV
+KPA4vkMgq+pFgDoH96XoM517gF2GJFV6h2gLhykzIHL/otAyEpAStw7MBvbU0V21
+ixB+hjqzO7Snxaj9mwB8g87OKxm5eGfsqvJNPdJ0RZ/EKy06Ukg6KThlhQeyrtIk
+g5PTCrPnNszlffAy6/jCOe3Moi59g15H13sSzwfX6g==
+-----END EC PRIVATE KEY-----
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index 75a51e0..282c513 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -128,6 +128,9 @@
     # Include more verbose output for failing tests run by CMake
     export CTEST_OUTPUT_ON_FAILURE=1
 
+    # CFLAGS and LDFLAGS for Asan builds that don't use CMake
+    ASAN_CFLAGS='-Werror -Wall -Wextra -fsanitize=address,undefined -fno-sanitize-recover=all'
+
     # Gather the list of available components. These are the functions
     # defined in this script whose name starts with "component_".
     # Parse the script with sed, because in sh there is no way to list
@@ -826,7 +829,7 @@
     msg "build: malloc(0) returns NULL (ASan+UBSan build)"
     scripts/config.pl full
     scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C
-    make CC=gcc CFLAGS="'-DMBEDTLS_CONFIG_FILE=\"$PWD/tests/configs/config-wrapper-malloc-0-null.h\"' -O -Werror -Wall -Wextra -fsanitize=address,undefined" LDFLAGS='-fsanitize=address,undefined'
+    make CC=gcc CFLAGS="'-DMBEDTLS_CONFIG_FILE=\"$PWD/tests/configs/config-wrapper-malloc-0-null.h\"' $ASAN_CFLAGS -O" LDFLAGS="$ASAN_CFLAGS"
 
     msg "test: malloc(0) returns NULL (ASan+UBSan build)"
     make test
@@ -868,7 +871,7 @@
 component_test_se_default () {
     msg "build: default config + MBEDTLS_PSA_CRYPTO_SE_C"
     scripts/config.pl set MBEDTLS_PSA_CRYPTO_SE_C
-    make CC=clang CFLAGS='-Werror -Wall -Wextra -Wno-unused-function -Os -fsanitize=address' LDFLAGS='-fsanitize=address'
+    make CC=clang CFLAGS="$ASAN_CFLAGS -Os" LDFLAGS="$ASAN_CFLAGS"
 
     msg "test: default config + MBEDTLS_PSA_CRYPTO_SE_C"
     make test
@@ -879,7 +882,7 @@
     scripts/config.pl full
     scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C
     scripts/config.pl set MBEDTLS_PSA_CRYPTO_SE_C
-    make CC=gcc CFLAGS='-Werror -Wall -Wextra -O2 -fsanitize=address' LDFLAGS='-fsanitize=address'
+    make CC=gcc CFLAGS="$ASAN_CFLAGS -O2" LDFLAGS="$ASAN_CFLAGS"
 
     msg "test: full config + MBEDTLS_PSA_CRYPTO_SE_C"
     make test
@@ -914,7 +917,7 @@
     # Build once with -O0, to compile out the i386 specific inline assembly
     msg "build: i386, make, gcc -O0 (ASan build)" # ~ 30s
     scripts/config.pl full
-    make CC=gcc CFLAGS='-O0 -Werror -Wall -Wextra -m32 -fsanitize=address' LDFLAGS='-m32 -fsanitize=address'
+    make CC=gcc CFLAGS="$ASAN_CFLAGS -m32 -O0" LDFLAGS="-m32 $ASAN_CFLAGS"
 
     msg "test: i386, make, gcc -O0 (ASan build)"
     make test
@@ -933,7 +936,7 @@
     scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE
     scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C
     scripts/config.pl unset MBEDTLS_MEMORY_DEBUG
-    make CC=gcc CFLAGS='-O1 -Werror -Wall -Wextra -m32 -fsanitize=address' LDFLAGS='-m32 -fsanitize=address'
+    make CC=gcc CFLAGS="$ASAN_CFLAGS -m32 -O1" LDFLAGS="-m32 $ASAN_CFLAGS"
 
     msg "test: i386, make, gcc -O1 (ASan build)"
     make test
@@ -946,7 +949,7 @@
     msg "build: i386, Everest ECDH context (ASan build)" # ~ 6 min
     scripts/config.pl unset MBEDTLS_ECDH_LEGACY_CONTEXT
     scripts/config.pl set MBEDTLS_ECDH_VARIANT_EVEREST_ENABLED
-    make CC=gcc CFLAGS='-O2 -Werror -Wall -Wextra -m32 -fsanitize=address'
+    make CC=gcc CFLAGS="$ASAN_CFLAGS -m32 -O2" LDFLAGS="-m32 $ASAN_CFLAGS"
 
     msg "test: i386, Everest ECDH context - main suites (inc. selftests) (ASan build)" # ~ 50s
     make test
diff --git a/tests/scripts/run-test-suites.pl b/tests/scripts/run-test-suites.pl
index 1c9dc1d..d06badd 100755
--- a/tests/scripts/run-test-suites.pl
+++ b/tests/scripts/run-test-suites.pl
@@ -93,7 +93,7 @@
     $suite_cases_failed = () = $result =~ /.. FAILED/g;
     $suite_cases_skipped = () = $result =~ /.. ----/g;
 
-    if( $result =~ /PASSED/ ) {
+    if( $? == 0 ) {
         print "PASS\n";
         if( $verbose > 2 ) {
             pad_print_center( 72, '-', "Begin $suite" );
diff --git a/tests/suites/test_suite_ctr_drbg.data b/tests/suites/test_suite_ctr_drbg.data
index 312910e..b50df2b 100644
--- a/tests/suites/test_suite_ctr_drbg.data
+++ b/tests/suites/test_suite_ctr_drbg.data
@@ -1070,8 +1070,22 @@
 depends_on:MBEDTLS_CTR_DRBG_USE_128_BIT_KEY
 ctr_drbg_validate_pr:"d4f1f4ae08bcb3e1":"5d4041942bcf68864a4997d8171f1f9fef55a769b7eaf03fe082029bb32a2b9d8239e865c0a42e14b964b9c09de85a20":"":"":"4155320287eedcf7d484c2c2a1e2eb64b9c9ce77c87202a1ae1616c7a5cfd1c687c7a0bfcc85bda48fdd4629fd330c22d0a76076f88fc7cd04037ee06b7af602"
 
-CTR_DRBG entropy usage
-ctr_drbg_entropy_usage:
+CTR_DRBG entropy usage (default entropy_nonce_len)
+ctr_drbg_entropy_usage:-1
+
+CTR_DRBG entropy usage (entropy_nonce_len=0)
+ctr_drbg_entropy_usage:0
+
+CTR_DRBG entropy usage (entropy_nonce_len=7)
+ctr_drbg_entropy_usage:7
+
+CTR_DRBG entropy strength: 128 bits
+depends_on:MBEDTLS_CTR_DRBG_USE_128_BIT_KEY
+ctr_drbg_entropy_strength:128
+
+CTR_DRBG entropy strength: 256 bits
+depends_on:!MBEDTLS_CTR_DRBG_USE_128_BIT_KEY
+ctr_drbg_entropy_strength:256
 
 CTR_DRBG write/update seed file [#1]
 ctr_drbg_seed_file:"data_files/ctr_drbg_seed":0
diff --git a/tests/suites/test_suite_ctr_drbg.function b/tests/suites/test_suite_ctr_drbg.function
index 4a97826..8317c08 100644
--- a/tests/suites/test_suite_ctr_drbg.function
+++ b/tests/suites/test_suite_ctr_drbg.function
@@ -44,11 +44,12 @@
 
     /* CTR_DRBG_Instantiate(entropy[:entropy->len], nonce, perso, <ignored>)
      * where nonce||perso = nonce[nonce->len] */
-    TEST_ASSERT( mbedtls_ctr_drbg_seed_entropy_len(
+    mbedtls_ctr_drbg_set_entropy_len( &ctx, entropy_chunk_len );
+    mbedtls_ctr_drbg_set_nonce_len( &ctx, 0 );
+    TEST_ASSERT( mbedtls_ctr_drbg_seed(
                      &ctx,
                      mbedtls_test_entropy_func, entropy->x,
-                     nonce->x, nonce->len,
-                     entropy_chunk_len ) == 0 );
+                     nonce->x, nonce->len ) == 0 );
     if( reseed_mode == RESEED_ALWAYS )
         mbedtls_ctr_drbg_set_prediction_resistance(
             &ctx,
@@ -187,17 +188,47 @@
 }
 /* END_CASE */
 
+/* BEGIN_CASE */
+void ctr_drbg_entropy_strength( int expected_bit_strength )
+{
+    unsigned char entropy[/*initial entropy*/ MBEDTLS_CTR_DRBG_ENTROPY_LEN +
+                          /*nonce*/     MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN +
+                          /*reseed*/          MBEDTLS_CTR_DRBG_ENTROPY_LEN];
+    mbedtls_ctr_drbg_context ctx;
+    size_t last_idx;
+    size_t byte_strength = expected_bit_strength / 8;
 
+    mbedtls_ctr_drbg_init( &ctx );
+    test_offset_idx = 0;
+    test_max_idx = sizeof( entropy );
+    memset( entropy, 0, sizeof( entropy ) );
+
+    /* The initial seeding must grab at least byte_strength bytes of entropy
+     * for the entropy input and byte_strength/2 bytes for a nonce. */
+    TEST_ASSERT( mbedtls_ctr_drbg_seed( &ctx,
+                                        mbedtls_test_entropy_func, entropy,
+                                        NULL, 0 ) == 0 );
+    TEST_ASSERT( test_offset_idx >= ( byte_strength * 3 + 1 ) / 2 );
+    last_idx = test_offset_idx;
+
+    /* A reseed must grab at least byte_strength bytes of entropy. */
+    TEST_ASSERT( mbedtls_ctr_drbg_reseed( &ctx, NULL, 0 ) == 0 );
+    TEST_ASSERT( test_offset_idx - last_idx >= byte_strength );
+
+exit:
+    mbedtls_ctr_drbg_free( &ctx );
+}
+/* END_CASE */
 
 /* BEGIN_CASE */
-void ctr_drbg_entropy_usage(  )
+void ctr_drbg_entropy_usage( int entropy_nonce_len )
 {
     unsigned char out[16];
     unsigned char add[16];
     unsigned char entropy[1024];
     mbedtls_ctr_drbg_context ctx;
     size_t i, reps = 10;
-    size_t last_idx;
+    size_t expected_idx = 0;
 
     mbedtls_ctr_drbg_init( &ctx );
     test_offset_idx = 0;
@@ -206,21 +237,27 @@
     memset( out, 0, sizeof( out ) );
     memset( add, 0, sizeof( add ) );
 
+    if( entropy_nonce_len >= 0 )
+        TEST_ASSERT( mbedtls_ctr_drbg_set_nonce_len( &ctx, entropy_nonce_len ) == 0 );
+
     /* Init must use entropy */
-    last_idx = test_offset_idx;
     TEST_ASSERT( mbedtls_ctr_drbg_seed( &ctx, mbedtls_test_entropy_func, entropy, NULL, 0 ) == 0 );
-    TEST_ASSERT( last_idx < test_offset_idx );
+    expected_idx += MBEDTLS_CTR_DRBG_ENTROPY_LEN;
+    if( entropy_nonce_len >= 0 )
+        expected_idx += entropy_nonce_len;
+    else
+        expected_idx += MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN;
+    TEST_EQUAL( test_offset_idx, expected_idx );
 
     /* By default, PR is off and reseed_interval is large,
      * so the next few calls should not use entropy */
-    last_idx = test_offset_idx;
     for( i = 0; i < reps; i++ )
     {
         TEST_ASSERT( mbedtls_ctr_drbg_random( &ctx, out, sizeof( out ) - 4 ) == 0 );
         TEST_ASSERT( mbedtls_ctr_drbg_random_with_add( &ctx, out, sizeof( out ) - 4,
                                                 add, sizeof( add ) ) == 0 );
     }
-    TEST_ASSERT( last_idx == test_offset_idx );
+    TEST_EQUAL( test_offset_idx, expected_idx );
 
     /* While at it, make sure we didn't write past the requested length */
     TEST_ASSERT( out[sizeof( out ) - 4] == 0 );
@@ -232,17 +269,17 @@
      * so the next call should reseed */
     mbedtls_ctr_drbg_set_reseed_interval( &ctx, 2 * reps );
     TEST_ASSERT( mbedtls_ctr_drbg_random( &ctx, out, sizeof( out ) ) == 0 );
-    TEST_ASSERT( last_idx < test_offset_idx );
+    expected_idx += MBEDTLS_CTR_DRBG_ENTROPY_LEN;
+    TEST_EQUAL( test_offset_idx, expected_idx );
 
     /* The new few calls should not reseed */
-    last_idx = test_offset_idx;
     for( i = 0; i < reps / 2; i++ )
     {
         TEST_ASSERT( mbedtls_ctr_drbg_random( &ctx, out, sizeof( out ) ) == 0 );
         TEST_ASSERT( mbedtls_ctr_drbg_random_with_add( &ctx, out, sizeof( out ) ,
                                                 add, sizeof( add ) ) == 0 );
     }
-    TEST_ASSERT( last_idx == test_offset_idx );
+    TEST_EQUAL( test_offset_idx, expected_idx );
 
     /* Call update with too much data (sizeof entropy > MAX(_SEED)_INPUT).
      * Make sure it's detected as an error and doesn't cause memory
@@ -253,18 +290,19 @@
     /* Now enable PR, so the next few calls should all reseed */
     mbedtls_ctr_drbg_set_prediction_resistance( &ctx, MBEDTLS_CTR_DRBG_PR_ON );
     TEST_ASSERT( mbedtls_ctr_drbg_random( &ctx, out, sizeof( out ) ) == 0 );
-    TEST_ASSERT( last_idx < test_offset_idx );
+    expected_idx += MBEDTLS_CTR_DRBG_ENTROPY_LEN;
+    TEST_EQUAL( test_offset_idx, expected_idx );
 
     /* Finally, check setting entropy_len */
     mbedtls_ctr_drbg_set_entropy_len( &ctx, 42 );
-    last_idx = test_offset_idx;
     TEST_ASSERT( mbedtls_ctr_drbg_random( &ctx, out, sizeof( out ) ) == 0 );
-    TEST_ASSERT( test_offset_idx - last_idx == 42 );
+    expected_idx += 42;
+    TEST_EQUAL( test_offset_idx, expected_idx );
 
     mbedtls_ctr_drbg_set_entropy_len( &ctx, 13 );
-    last_idx = test_offset_idx;
     TEST_ASSERT( mbedtls_ctr_drbg_random( &ctx, out, sizeof( out ) ) == 0 );
-    TEST_ASSERT( test_offset_idx - last_idx == 13 );
+    expected_idx += 13;
+    TEST_EQUAL( test_offset_idx, expected_idx );
 
 exit:
     mbedtls_ctr_drbg_free( &ctx );
diff --git a/tests/suites/test_suite_hmac_drbg.function b/tests/suites/test_suite_hmac_drbg.function
index 13bc400..b526f43 100644
--- a/tests/suites/test_suite_hmac_drbg.function
+++ b/tests/suites/test_suite_hmac_drbg.function
@@ -37,7 +37,9 @@
     const mbedtls_md_info_t *md_info;
     mbedtls_hmac_drbg_context ctx;
     entropy_ctx entropy;
-    size_t last_len, i, reps = 10;
+    size_t i, reps = 10;
+    size_t default_entropy_len;
+    size_t expected_consumed_entropy = 0;
 
     mbedtls_hmac_drbg_init( &ctx );
     memset( buf, 0, sizeof( buf ) );
@@ -48,23 +50,29 @@
 
     md_info = mbedtls_md_info_from_type( md_alg );
     TEST_ASSERT( md_info != NULL );
+    if( mbedtls_md_get_size( md_info ) <= 20 )
+        default_entropy_len = 16;
+    else if( mbedtls_md_get_size( md_info ) <= 28 )
+        default_entropy_len = 24;
+    else
+        default_entropy_len = 32;
 
     /* Init must use entropy */
-    last_len = entropy.len;
     TEST_ASSERT( mbedtls_hmac_drbg_seed( &ctx, md_info, mbedtls_test_entropy_func, &entropy,
                                  NULL, 0 ) == 0 );
-    TEST_ASSERT( entropy.len < last_len );
+    /* default_entropy_len of entropy, plus half as much for the nonce */
+    expected_consumed_entropy += default_entropy_len * 3 / 2;
+    TEST_EQUAL( sizeof( buf )  - entropy.len, expected_consumed_entropy );
 
     /* By default, PR is off and reseed_interval is large,
      * so the next few calls should not use entropy */
-    last_len = entropy.len;
     for( i = 0; i < reps; i++ )
     {
         TEST_ASSERT( mbedtls_hmac_drbg_random( &ctx, out, sizeof( out ) - 4 ) == 0 );
         TEST_ASSERT( mbedtls_hmac_drbg_random_with_add( &ctx, out, sizeof( out ) - 4,
                                                 buf, 16 ) == 0 );
     }
-    TEST_ASSERT( entropy.len == last_len );
+    TEST_EQUAL( sizeof( buf )  - entropy.len, expected_consumed_entropy );
 
     /* While at it, make sure we didn't write past the requested length */
     TEST_ASSERT( out[sizeof( out ) - 4] == 0 );
@@ -76,33 +84,34 @@
      * so the next call should reseed */
     mbedtls_hmac_drbg_set_reseed_interval( &ctx, 2 * reps );
     TEST_ASSERT( mbedtls_hmac_drbg_random( &ctx, out, sizeof( out ) ) == 0 );
-    TEST_ASSERT( entropy.len < last_len );
+    expected_consumed_entropy += default_entropy_len;
+    TEST_EQUAL( sizeof( buf )  - entropy.len, expected_consumed_entropy );
 
     /* The new few calls should not reseed */
-    last_len = entropy.len;
     for( i = 0; i < reps / 2; i++ )
     {
         TEST_ASSERT( mbedtls_hmac_drbg_random( &ctx, out, sizeof( out ) ) == 0 );
         TEST_ASSERT( mbedtls_hmac_drbg_random_with_add( &ctx, out, sizeof( out ) ,
                                                 buf, 16 ) == 0 );
     }
-    TEST_ASSERT( entropy.len == last_len );
+    TEST_EQUAL( sizeof( buf )  - entropy.len, expected_consumed_entropy );
 
     /* Now enable PR, so the next few calls should all reseed */
     mbedtls_hmac_drbg_set_prediction_resistance( &ctx, MBEDTLS_HMAC_DRBG_PR_ON );
     TEST_ASSERT( mbedtls_hmac_drbg_random( &ctx, out, sizeof( out ) ) == 0 );
-    TEST_ASSERT( entropy.len < last_len );
+    expected_consumed_entropy += default_entropy_len;
+    TEST_EQUAL( sizeof( buf )  - entropy.len, expected_consumed_entropy );
 
     /* Finally, check setting entropy_len */
     mbedtls_hmac_drbg_set_entropy_len( &ctx, 42 );
-    last_len = entropy.len;
     TEST_ASSERT( mbedtls_hmac_drbg_random( &ctx, out, sizeof( out ) ) == 0 );
-    TEST_ASSERT( (int) last_len - entropy.len == 42 );
+    expected_consumed_entropy += 42;
+    TEST_EQUAL( sizeof( buf )  - entropy.len, expected_consumed_entropy );
 
     mbedtls_hmac_drbg_set_entropy_len( &ctx, 13 );
-    last_len = entropy.len;
     TEST_ASSERT( mbedtls_hmac_drbg_random( &ctx, out, sizeof( out ) ) == 0 );
-    TEST_ASSERT( (int) last_len - entropy.len == 13 );
+    expected_consumed_entropy += 13;
+    TEST_EQUAL( sizeof( buf )  - entropy.len, expected_consumed_entropy );
 
 exit:
     mbedtls_hmac_drbg_free( &ctx );
diff --git a/tests/suites/test_suite_pkwrite.data b/tests/suites/test_suite_pkwrite.data
index c8ff177..e0101cc 100644
--- a/tests/suites/test_suite_pkwrite.data
+++ b/tests/suites/test_suite_pkwrite.data
@@ -30,10 +30,18 @@
 depends_on:MBEDTLS_ECP_C:MBEDTLS_BASE64_C:MBEDTLS_ECP_DP_SECP192R1_ENABLED
 pk_write_key_check:"data_files/ec_prv.sec1.pem"
 
+Private key write check EC 256 bits (top bit set)
+depends_on:MBEDTLS_ECP_C:MBEDTLS_BASE64_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+pk_write_key_check:"data_files/ec_256_long_prv.pem"
+
 Private key write check EC 521 bits
 depends_on:MBEDTLS_ECP_C:MBEDTLS_BASE64_C:MBEDTLS_ECP_DP_SECP521R1_ENABLED
 pk_write_key_check:"data_files/ec_521_prv.pem"
 
+Private key write check EC 521 bits (top byte is 0)
+depends_on:MBEDTLS_ECP_C:MBEDTLS_BASE64_C:MBEDTLS_ECP_DP_SECP521R1_ENABLED
+pk_write_key_check:"data_files/ec_521_short_prv.pem"
+
 Private key write check EC Brainpool 512 bits
 depends_on:MBEDTLS_ECP_C:MBEDTLS_BASE64_C:MBEDTLS_ECP_DP_BP512R1_ENABLED
 pk_write_key_check:"data_files/ec_bp512_prv.pem"
diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data
index 6efdc01..3bd3738 100644
--- a/tests/suites/test_suite_psa_crypto.data
+++ b/tests/suites/test_suite_psa_crypto.data
@@ -43,15 +43,6 @@
 depends_on:MBEDTLS_AES_C
 import_export:"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef":PSA_KEY_TYPE_AES:PSA_KEY_USAGE_EXPORT:PSA_ALG_CTR:256:0:PSA_SUCCESS:1
 
-PSA invalid handle (0)
-invalid_handle:0
-
-PSA invalid handle (smallest plausible handle)
-invalid_handle:1
-
-PSA invalid handle (largest plausible handle)
-invalid_handle:-1
-
 PSA import: bad usage flag
 import_with_policy:PSA_KEY_TYPE_RAW_DATA:0x40000000:0:PSA_ERROR_INVALID_ARGUMENT
 
@@ -1547,6 +1538,14 @@
 depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECDSA_DETERMINISTIC:MBEDTLS_SHA256_C:MBEDTLS_ECDSA_C
 sign_deterministic:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP256R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_DETERMINISTIC_ECDSA( PSA_ALG_SHA_256 ):"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b":"6a3399f69421ffe1490377adf2ea1f117d81a63cf5bf22e918d51175eb259151ce95d7c26cc04e25503e2f7a1ec3573e3c2412534bb4a19b3a7811742f49f50f"
 
+PSA sign: deterministic ECDSA SECP256R1 SHA-384
+depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECDSA_DETERMINISTIC:MBEDTLS_SHA512_C:MBEDTLS_ECDSA_C
+sign_deterministic:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP256R1):"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":PSA_ALG_DETERMINISTIC_ECDSA( PSA_ALG_SHA_384 ):"59e1748777448c69de6b800d7a33bbfb9ff1b463e44354c3553bcdb9c666fa90125a3c79f90397bdf5f6a13de828684f":"cd40ba1b555ca5994d30ddffc4ad734b1f5c604675b0f249814aa5de3992ef3ddf4d5dc5d2aab1979ce210b560754df671363d99795475882894c048e3b986ca"
+
+PSA sign: deterministic ECDSA SECP384R1 SHA-256
+depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_ECDSA_DETERMINISTIC:MBEDTLS_SHA256_C:MBEDTLS_ECDSA_C
+sign_deterministic:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP384R1):"3f5d8d9be280b5696cc5cc9f94cf8af7e6b61dd6592b2ab2b3a4c607450417ec327dcdcaed7c10053d719a0574f0a76a":PSA_ALG_DETERMINISTIC_ECDSA( PSA_ALG_SHA_256 ):"2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824":"52d92aac1fcc0fea3ecce01a9ed4bc9ac342f92470fd3f54d0d6d2fa5d2940405057a9d49a817c2b193322f05fc93ac1c7a055edac93bec0ade6814ab27b86b5295ac1ddb323818200f00c3d94d959f714f128b64a2e19628037ac009b14774f"
+
 PSA sign: RSA PKCS#1 v1.5 SHA-256, wrong hash size
 depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_SHA256_C
 sign_fail:PSA_KEY_TYPE_RSA_KEY_PAIR:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_SHA_256):"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015":128:PSA_ERROR_INVALID_ARGUMENT
@@ -1621,6 +1620,22 @@
 depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECDSA_DETERMINISTIC:MBEDTLS_SHA256_C:MBEDTLS_ECDSA_C
 sign_verify:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP256R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_DETERMINISTIC_ECDSA( PSA_ALG_SHA_256 ):"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b"
 
+PSA sign/verify: randomized ECDSA SECP256R1 SHA-384
+depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECDSA_C:MBEDTLS_SHA512_C
+sign_verify:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP256R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_ECDSA( PSA_ALG_SHA_384 ):"59e1748777448c69de6b800d7a33bbfb9ff1b463e44354c3553bcdb9c666fa90125a3c79f90397bdf5f6a13de828684f"
+
+PSA sign/verify: deterministic ECDSA SECP256R1 SHA-384
+depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECDSA_DETERMINISTIC:MBEDTLS_SHA512_C:MBEDTLS_ECDSA_C
+sign_verify:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP256R1):"ab45435712649cb30bbddac49197eebf2740ffc7f874d9244c3460f54f322d3a":PSA_ALG_DETERMINISTIC_ECDSA( PSA_ALG_SHA_384 ):"59e1748777448c69de6b800d7a33bbfb9ff1b463e44354c3553bcdb9c666fa90125a3c79f90397bdf5f6a13de828684f"
+
+PSA sign/verify: randomized ECDSA SECP384R1 SHA-256
+depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_ECDSA_C:MBEDTLS_SHA256_C
+sign_verify:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP384R1):"3f5d8d9be280b5696cc5cc9f94cf8af7e6b61dd6592b2ab2b3a4c607450417ec327dcdcaed7c10053d719a0574f0a76a":PSA_ALG_ECDSA( PSA_ALG_SHA_256 ):"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b"
+
+PSA sign/verify: deterministic ECDSA SECP384R1 SHA-256
+depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP384R1_ENABLED:MBEDTLS_ECDSA_DETERMINISTIC:MBEDTLS_SHA256_C:MBEDTLS_ECDSA_C
+sign_verify:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP384R1):"3f5d8d9be280b5696cc5cc9f94cf8af7e6b61dd6592b2ab2b3a4c607450417ec327dcdcaed7c10053d719a0574f0a76a":PSA_ALG_DETERMINISTIC_ECDSA( PSA_ALG_SHA_256 ):"9ac4335b469bbd791439248504dd0d49c71349a295fee5a1c68507f45a9e1c7b"
+
 PSA verify: RSA PKCS#1 v1.5 SHA-256, good signature
 depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_SHA256_C
 asymmetric_verify:PSA_KEY_TYPE_RSA_PUBLIC_KEY:"30818902818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc30203010001":PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_SHA_256):"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad":"a73664d55b39c7ea6c1e5b5011724a11e1d7073d3a68f48c836fad153a1d91b6abdbc8f69da13b206cc96af6363b114458b026af14b24fab8929ed634c6a2acace0bcc62d9bb6a984afbcbfcd3a0608d32a2bae535b9cd1ecdf9dd281db1e0025c3bfb5512963ec3b98ddaa69e38bc3c84b1b61a04e5648640856aacc6fc7311"
diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function
index 3e698f5..f3f79ab 100644
--- a/tests/suites/test_suite_psa_crypto.function
+++ b/tests/suites/test_suite_psa_crypto.function
@@ -736,6 +736,11 @@
     TEST_EQUAL( mbedtls_asn1_get_tag( p, end, &len,
                                       MBEDTLS_ASN1_INTEGER ),
                 0 );
+
+    /* Check if the retrieved length doesn't extend the actual buffer's size.
+     * It is assumed here, that end >= p, which validates casting to size_t. */
+    TEST_ASSERT( len <= (size_t)( end - *p) );
+
     /* Tolerate a slight departure from DER encoding:
      * - 0 may be represented by an empty string or a 1-byte string.
      * - The sign bit may be used as a value bit. */
@@ -1105,9 +1110,6 @@
                                        buffer, sizeof( buffer ), &length ),
                 PSA_ERROR_INVALID_HANDLE );
 
-    TEST_EQUAL( psa_close_key( handle ), PSA_ERROR_INVALID_HANDLE );
-    TEST_EQUAL( psa_destroy_key( handle ), PSA_ERROR_INVALID_HANDLE );
-
     ok = 1;
 
 exit:
@@ -1538,17 +1540,6 @@
 /* END_CASE */
 
 /* BEGIN_CASE */
-void invalid_handle( int handle )
-{
-    PSA_ASSERT( psa_crypto_init( ) );
-    test_operations_on_invalid_handle( handle );
-
-exit:
-    PSA_DONE( );
-}
-/* END_CASE */
-
-/* BEGIN_CASE */
 void import_export_public_key( data_t *data,
                                int type_arg,
                                int alg_arg,
diff --git a/tests/suites/test_suite_psa_crypto_init.data b/tests/suites/test_suite_psa_crypto_init.data
index c57a764..9620a64 100644
--- a/tests/suites/test_suite_psa_crypto_init.data
+++ b/tests/suites/test_suite_psa_crypto_init.data
@@ -34,15 +34,25 @@
 Fake entropy: less than the block size
 fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:-1:-1:-1:PSA_ERROR_INSUFFICIENT_ENTROPY
 
+Fake entropy: not enough for a nonce
+depends_on:ENTROPY_NONCE_LEN != 0
+fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:ENTROPY_NONCE_LEN - 1:-1:-1:-1:PSA_ERROR_INSUFFICIENT_ENTROPY
+
 Fake entropy: one block eventually
+depends_on:ENTROPY_NONCE_LEN == 0
 fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:0:0:0:MBEDTLS_ENTROPY_BLOCK_SIZE:PSA_SUCCESS
 
 Fake entropy: one block in two steps
+depends_on:ENTROPY_NONCE_LEN == 0
 fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:1:-1:-1:PSA_SUCCESS
 
 Fake entropy: more than one block in two steps
+depends_on:ENTROPY_NONCE_LEN == 0
 fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:MBEDTLS_ENTROPY_BLOCK_SIZE - 1:-1:-1:PSA_SUCCESS
 
+Fake entropy: two blocks eventually
+fake_entropy_source:MBEDTLS_ENTROPY_BLOCK_SIZE:0:MBEDTLS_ENTROPY_BLOCK_SIZE:0:MBEDTLS_ENTROPY_BLOCK_SIZE:PSA_SUCCESS
+
 NV seed only: less than minimum
 entropy_from_nv_seed:MBEDTLS_ENTROPY_MIN_PLATFORM - 1:PSA_ERROR_INSUFFICIENT_ENTROPY
 
diff --git a/tests/suites/test_suite_psa_crypto_init.function b/tests/suites/test_suite_psa_crypto_init.function
index 3c4b42e..3283ac9 100644
--- a/tests/suites/test_suite_psa_crypto_init.function
+++ b/tests/suites/test_suite_psa_crypto_init.function
@@ -11,6 +11,12 @@
 #define ENTROPY_MIN_NV_SEED_SIZE                                        \
     MAX(MBEDTLS_ENTROPY_MIN_PLATFORM, MBEDTLS_ENTROPY_BLOCK_SIZE)
 
+/* PSA crypto uses the CTR_DRBG module. In some configurations, it needs
+ * to read from the entropy source twice: once for the initial entropy
+ * and once for a nonce. */
+#include "mbedtls/ctr_drbg.h"
+#define ENTROPY_NONCE_LEN MBEDTLS_CTR_DRBG_ENTROPY_NONCE_LEN
+
 typedef struct
 {
     size_t threshold; /* Minimum bytes to make mbedtls_entropy_func happy */
diff --git a/tests/suites/test_suite_psa_crypto_slot_management.data b/tests/suites/test_suite_psa_crypto_slot_management.data
index 6fa8723..803917d 100644
--- a/tests/suites/test_suite_psa_crypto_slot_management.data
+++ b/tests/suites/test_suite_psa_crypto_slot_management.data
@@ -148,8 +148,17 @@
 depends_on:MBEDTLS_PSA_CRYPTO_STORAGE_C
 copy_to_occupied:PSA_KEY_LIFETIME_PERSISTENT:1:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_COPY:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"404142434445464748494a4b4c4d4e4f":PSA_KEY_LIFETIME_PERSISTENT:1:PSA_KEY_USAGE_EXPORT:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"404142434445464748494a4b4c4d4e4f"
 
-Close/destroy invalid handle
-invalid_handle:
+invalid handle: 0
+invalid_handle:INVALID_HANDLE_0:PSA_SUCCESS:PSA_ERROR_INVALID_HANDLE
+
+invalid handle: never opened
+invalid_handle:INVALID_HANDLE_UNOPENED:PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE
+
+invalid handle: already closed
+invalid_handle:INVALID_HANDLE_CLOSED:PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE
+
+invalid handle: huge
+invalid_handle:INVALID_HANDLE_HUGE:PSA_ERROR_INVALID_HANDLE:PSA_ERROR_INVALID_HANDLE
 
 Open many transient handles
 many_transient_handles:42
diff --git a/tests/suites/test_suite_psa_crypto_slot_management.function b/tests/suites/test_suite_psa_crypto_slot_management.function
index 3b9eada..4c824f7 100644
--- a/tests/suites/test_suite_psa_crypto_slot_management.function
+++ b/tests/suites/test_suite_psa_crypto_slot_management.function
@@ -20,6 +20,14 @@
     CLOSE_AFTER,
 } reopen_policy_t;
 
+typedef enum
+{
+    INVALID_HANDLE_0,
+    INVALID_HANDLE_UNOPENED,
+    INVALID_HANDLE_CLOSED,
+    INVALID_HANDLE_HUGE,
+} invalid_handle_construction_t;
+
 /* All test functions that create persistent keys must call
  * `TEST_USES_KEY_ID( key_id )` before creating a persistent key with this
  * identifier, and must call psa_purge_key_storage() in their cleanup
@@ -625,9 +633,13 @@
 /* END_CASE */
 
 /* BEGIN_CASE */
-void invalid_handle( )
+void invalid_handle( int handle_construction,
+                     int close_status_arg, int usage_status_arg )
 {
-    psa_key_handle_t handle1 = 0;
+    psa_key_handle_t valid_handle = 0;
+    psa_key_handle_t invalid_handle = 0;
+    psa_status_t close_status = close_status_arg;
+    psa_status_t usage_status = usage_status_arg;
     psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
     uint8_t material[1] = "a";
 
@@ -639,23 +651,50 @@
     psa_set_key_algorithm( &attributes, 0 );
     PSA_ASSERT( psa_import_key( &attributes,
                                 material, sizeof( material ),
-                                &handle1 ) );
-    TEST_ASSERT( handle1 != 0 );
+                                &valid_handle ) );
+    TEST_ASSERT( valid_handle != 0 );
 
-    /* Attempt to close and destroy some invalid handles. */
-    TEST_EQUAL( psa_close_key( 0 ), PSA_ERROR_INVALID_HANDLE );
-    TEST_EQUAL( psa_close_key( handle1 - 1 ), PSA_ERROR_INVALID_HANDLE );
-    TEST_EQUAL( psa_close_key( handle1 + 1 ), PSA_ERROR_INVALID_HANDLE );
-    TEST_EQUAL( psa_destroy_key( 0 ), PSA_ERROR_INVALID_HANDLE );
-    TEST_EQUAL( psa_destroy_key( handle1 - 1 ), PSA_ERROR_INVALID_HANDLE );
-    TEST_EQUAL( psa_destroy_key( handle1 + 1 ), PSA_ERROR_INVALID_HANDLE );
+    /* Construct an invalid handle as specified in the test case data. */
+    switch( handle_construction )
+    {
+        case INVALID_HANDLE_0:
+            invalid_handle = 0;
+            break;
+        case INVALID_HANDLE_UNOPENED:
+            /* We can't easily construct a handle that's never been opened
+             * without knowing how the implementation constructs handle
+             * values. The current test code assumes that valid handles
+             * are in a range between 1 and some maximum. */
+            if( valid_handle == 1 )
+                invalid_handle = 2;
+            else
+                invalid_handle = valid_handle - 1;
+            break;
+        case INVALID_HANDLE_CLOSED:
+            PSA_ASSERT( psa_import_key( &attributes,
+                                        material, sizeof( material ),
+                                        &invalid_handle ) );
+            PSA_ASSERT( psa_destroy_key( invalid_handle ) );
+            break;
+        case INVALID_HANDLE_HUGE:
+            invalid_handle = (psa_key_handle_t) ( -1 );
+            break;
+        default:
+            TEST_ASSERT( ! "unknown handle construction" );
+    }
+
+    /* Attempt to use the invalid handle. */
+    TEST_EQUAL( psa_get_key_attributes( invalid_handle, &attributes ),
+                usage_status );
+    TEST_EQUAL( psa_close_key( invalid_handle ), close_status );
+    TEST_EQUAL( psa_destroy_key( invalid_handle ), close_status );
 
     /* After all this, check that the original handle is intact. */
-    PSA_ASSERT( psa_get_key_attributes( handle1, &attributes ) );
+    PSA_ASSERT( psa_get_key_attributes( valid_handle, &attributes ) );
     TEST_EQUAL( psa_get_key_type( &attributes ), PSA_KEY_TYPE_RAW_DATA );
     TEST_EQUAL( psa_get_key_bits( &attributes ),
                 PSA_BYTES_TO_BITS( sizeof( material ) ) );
-    PSA_ASSERT( psa_close_key( handle1 ) );
+    PSA_ASSERT( psa_close_key( valid_handle ) );
 
 exit:
     PSA_DONE( );