Merge pull request #305 from gilles-peskine-arm/ctr_drbg-grab_nonce_from_entropy-set_nonce_length

CTR_DRBG: grab a nonce from the entropy source if needed
diff --git a/include/mbedtls/ctr_drbg.h b/include/mbedtls/ctr_drbg.h
index 676b96e..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. */
 
@@ -217,43 +228,68 @@
  * 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
- * entropy source, to make this instantiation as unique as possible.
+ * 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.
  *
- * \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.
+ * 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.
+ *
+ * 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
- *                      equal to the entropy length.
+ *                      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
@@ -301,11 +337,6 @@
  *
  * 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
@@ -320,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()
diff --git a/include/mbedtls/hmac_drbg.h b/include/mbedtls/hmac_drbg.h
index 8ac227c..00be9df 100644
--- a/include/mbedtls/hmac_drbg.h
+++ b/include/mbedtls/hmac_drbg.h
@@ -139,7 +139,7 @@
  *                      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 default entropy length is the security strength
  *                      (converted from bits to bytes). You can override
@@ -222,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/library/ctr_drbg.c b/library/ctr_drbg.c
index ae51d54..047bb2a 100644
--- a/library/ctr_drbg.c
+++ b/library/ctr_drbg.c
@@ -56,6 +56,9 @@
 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 );
@@ -86,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 )
 {
@@ -319,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
@@ -327,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;
@@ -381,15 +416,33 @@
     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_entropy_len(ctx, f_entropy, p_entropy,
- *                                   custom, len, entropy_len)
+ * 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 entropy_len bytes
+ * where entropy_input comes from f_entropy for ctx->entropy_len bytes
  * and with outputs
  *   ctx = initial_working_state
  */
@@ -401,6 +454,7 @@
 {
     int ret;
     unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE];
+    size_t nonce_len;
 
     memset( key, 0, MBEDTLS_CTR_DRBG_KEYSIZE );
 
@@ -411,18 +465,26 @@
 
     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
-     */
+    /* 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 )
+    /* Do the initial seeding. */
+    if( ( ret = mbedtls_ctr_drbg_reseed_internal( ctx, custom, len,
+                                                  nonce_len ) ) != 0 )
     {
         return( ret );
     }
@@ -693,6 +755,7 @@
 
     test_offset = 0;
     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,
@@ -717,6 +780,7 @@
 
     test_offset = 0;
     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,
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/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 01050d9..8317c08 100644
--- a/tests/suites/test_suite_ctr_drbg.function
+++ b/tests/suites/test_suite_ctr_drbg.function
@@ -45,6 +45,7 @@
     /* CTR_DRBG_Instantiate(entropy[:entropy->len], nonce, perso, <ignored>)
      * where nonce||perso = nonce[nonce->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,
@@ -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_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 */