Merge pull request #4110 from gilles-peskine-arm/psa-external-random-in-mbedtls

Expose the PSA RNG in mbedtls
diff --git a/ChangeLog.d/mbedtls_psa_get_random.txt b/ChangeLog.d/mbedtls_psa_get_random.txt
new file mode 100644
index 0000000..f6e6b09
--- /dev/null
+++ b/ChangeLog.d/mbedtls_psa_get_random.txt
@@ -0,0 +1,9 @@
+Features
+   * Partial implementation of the PSA crypto driver interface: Mbed TLS can
+     now use an external random generator instead of the library's own
+     entropy collection and DRBG code. Enable MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
+     and see the documentation of mbedtls_psa_external_get_random() for details.
+   * Applications using both mbedtls_xxx and psa_xxx functions (for example,
+     applications using TLS and MBEDTLS_USE_PSA_CRYPTO) can now use the PSA
+     random generator with mbedtls_xxx functions. See the documentation of
+     mbedtls_psa_get_random() for details.
diff --git a/include/mbedtls/psa_util.h b/include/mbedtls/psa_util.h
index 0b8a216..f18857c 100644
--- a/include/mbedtls/psa_util.h
+++ b/include/mbedtls/psa_util.h
@@ -419,4 +419,90 @@
 
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
+/* Expose whatever RNG the PSA subsystem uses to applications using the
+ * mbedtls_xxx API. The declarations and definitions here need to be
+ * consistent with the implementation in library/psa_crypto_random_impl.h.
+ * See that file for implementation documentation. */
+#if defined(MBEDTLS_PSA_CRYPTO_C)
+
+/* The type of a `f_rng` random generator function that many library functions
+ * take.
+ *
+ * This type name is not part of the Mbed TLS stable API. It may be renamed
+ * or moved without warning.
+ */
+typedef int mbedtls_f_rng_t( void *p_rng, unsigned char *output, size_t output_size );
+
+#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
+
+/** The random generator function for the PSA subsystem.
+ *
+ * This function is suitable as the `f_rng` random generator function
+ * parameter of many `mbedtls_xxx` functions. Use #MBEDTLS_PSA_RANDOM_STATE
+ * to obtain the \p p_rng parameter.
+ *
+ * The implementation of this function depends on the configuration of the
+ * library.
+ *
+ * \note Depending on the configuration, this may be a function or
+ *       a pointer to a function.
+ *
+ * \note This function may only be used if the PSA crypto subsystem is active.
+ *       This means that you must call psa_crypto_init() before any call to
+ *       this function, and you must not call this function after calling
+ *       mbedtls_psa_crypto_free().
+ *
+ * \param p_rng         The random generator context. This must be
+ *                      #MBEDTLS_PSA_RANDOM_STATE. No other state is
+ *                      supported.
+ * \param output        The buffer to fill. It must have room for
+ *                      \c output_size bytes.
+ * \param output_size   The number of bytes to write to \p output.
+ *                      This function may fail if \p output_size is too
+ *                      large. It is guaranteed to accept any output size
+ *                      requested by Mbed TLS library functions. The
+ *                      maximum request size depends on the library
+ *                      configuration.
+ *
+ * \return              \c 0 on success.
+ * \return              An `MBEDTLS_ERR_ENTROPY_xxx`,
+ *                      `MBEDTLS_ERR_PLATFORM_xxx,
+ *                      `MBEDTLS_ERR_CTR_DRBG_xxx` or
+ *                      `MBEDTLS_ERR_HMAC_DRBG_xxx` on error.
+ */
+int mbedtls_psa_get_random( void *p_rng,
+                            unsigned char *output,
+                            size_t output_size );
+
+/** The random generator state for the PSA subsystem.
+ *
+ * This macro expands to an expression which is suitable as the `p_rng`
+ * random generator state parameter of many `mbedtls_xxx` functions.
+ * It must be used in combination with the random generator function
+ * mbedtls_psa_get_random().
+ *
+ * The implementation of this macro depends on the configuration of the
+ * library. Do not make any assumption on its nature.
+ */
+#define MBEDTLS_PSA_RANDOM_STATE NULL
+
+#else /* !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) */
+
+#if defined(MBEDTLS_CTR_DRBG_C)
+#include "mbedtls/ctr_drbg.h"
+typedef mbedtls_ctr_drbg_context mbedtls_psa_drbg_context_t;
+static mbedtls_f_rng_t *const mbedtls_psa_get_random = mbedtls_ctr_drbg_random;
+#elif defined(MBEDTLS_HMAC_DRBG_C)
+#include "mbedtls/hmac_drbg.h"
+typedef mbedtls_hmac_drbg_context mbedtls_psa_drbg_context_t;
+static mbedtls_f_rng_t *const mbedtls_psa_get_random = mbedtls_hmac_drbg_random;
+#endif
+extern mbedtls_psa_drbg_context_t *const mbedtls_psa_random_state;
+
+#define MBEDTLS_PSA_RANDOM_STATE mbedtls_psa_random_state
+
+#endif /* !defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) */
+
+#endif /* MBEDTLS_PSA_CRYPTO_C */
+
 #endif /* MBEDTLS_PSA_UTIL_H */
diff --git a/library/entropy_poll.c b/library/entropy_poll.c
index 84b70fe..2c1e093 100644
--- a/library/entropy_poll.c
+++ b/library/entropy_poll.c
@@ -220,13 +220,13 @@
 {
     ((void) data);
     ((void) output);
-    *olen = 0;
 
+    *olen = 0;
     if( len < sizeof(unsigned char) )
         return( 0 );
 
+    output[0] = 0;
     *olen = sizeof(unsigned char);
-
     return( 0 );
 }
 #endif
diff --git a/library/psa_crypto_random_impl.h b/library/psa_crypto_random_impl.h
index 1232186..3c4c09a 100644
--- a/library/psa_crypto_random_impl.h
+++ b/library/psa_crypto_random_impl.h
@@ -1,6 +1,14 @@
 /** \file psa_crypto_random_impl.h
  *
  * \brief PSA crypto random generator implementation abstraction.
+ *
+ * The definitions here need to be consistent with the declarations
+ * in include/mbedtls/psa_util.h. This file contains some redundant
+ * declarations to increase the chance that a compiler will detect
+ * inconsistencies if one file is changed without updating the other,
+ * but not all potential inconsistencies can be enforced, so make sure
+ * to check the public declarations and contracts in
+ * include/mbedtls/psa_util.h if you modify this file.
  */
 /*
  *  Copyright The Mbed TLS Contributors
@@ -22,6 +30,8 @@
 #ifndef PSA_CRYPTO_RANDOM_IMPL_H
 #define PSA_CRYPTO_RANDOM_IMPL_H
 
+#include <mbedtls/psa_util.h>
+
 #if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
 
 #include <string.h>
@@ -75,14 +85,6 @@
 
 #include "mbedtls/entropy.h"
 
-/** The type of the PSA DRBG context.
- */
-#if defined(MBEDTLS_CTR_DRBG_C)
-typedef mbedtls_ctr_drbg_context mbedtls_psa_drbg_context_t;
-#elif defined(MBEDTLS_HMAC_DRBG_C)
-typedef mbedtls_hmac_drbg_context mbedtls_psa_drbg_context_t;
-#endif
-
 /** Initialize the PSA DRBG.
  *
  * \param p_rng        Pointer to the Mbed TLS DRBG state.
@@ -122,33 +124,18 @@
     mbedtls_psa_drbg_context_t drbg;
 } mbedtls_psa_random_context_t;
 
-/* The type of an Mbed TLS random generator function. This should be
- * part of the public API instead of repeating the type everywhere.
- * For the time being, declare it here. Declaring a type is necessary
- * to define mbedtls_psa_get_random as a variable of a function pointer
- * type without incurring the wrath of check-names.sh. */
-typedef int mbedtls_f_rng_t( void *p_rng, unsigned char *output, size_t output_size );
-
-/** Return random data.
- *
- * This function is suitable as the \p f_rng parameter to Mbed TLS functions
- * that require a random generator. Use #MBEDTLS_PSA_RANDOM_STATE to
- * obtain the \p p_rng parameter.
- *
- * \param p_rng         The DRBG context. This must be
- *                      #MBEDTLS_PSA_RANDOM_STATE.
- * \param output        The buffer to fill.
- * \param output_len    The length of the buffer in bytes.
- *                      It must be at most #MBEDTLS_PSA_RANDOM_MAX_REQUEST.
- *
- * \retval              \c 0 on success.
- * \return              \c MBEDTLS_ERR_xxx_DRBG_xxx or
- *                      \c MBEDTLS_ERR_PLATFORM_xxx on failure.
+/* Defined in include/mbedtls/psa_util.h so that it's visible to
+ * application code. The declaration here is redundant, but included
+ * as a safety net to make it more likely that a future change that
+ * accidentally causes the implementation to diverge from the interface
+ * will be noticed. */
+/* Do not include the declaration under MSVC because it doesn't accept it
+ * ("error C2370: 'mbedtls_psa_get_random' : redefinition; different storage class").
+ * Observed with Visual Studio 2013. A known bug apparently:
+ * https://stackoverflow.com/questions/8146541/duplicate-external-static-declarations-not-allowed-in-visual-studio
  */
-#if defined(MBEDTLS_CTR_DRBG_C)
-static mbedtls_f_rng_t *const mbedtls_psa_get_random = mbedtls_ctr_drbg_random;
-#elif defined(MBEDTLS_HMAC_DRBG_C)
-static mbedtls_f_rng_t *const mbedtls_psa_get_random = mbedtls_hmac_drbg_random;
+#if !defined(_MSC_VER)
+static mbedtls_f_rng_t *const mbedtls_psa_get_random;
 #endif
 
 /** The maximum number of bytes that mbedtls_psa_get_random() is expected to
@@ -167,6 +154,9 @@
  */
 /* psa_crypto.c sets this variable to a pointer to the DRBG state in the
  * global PSA crypto state. */
+/* The type `mbedtls_psa_drbg_context_t` is defined in
+ * include/mbedtls/psa_util.h so that `mbedtls_psa_random_state` can be
+ * declared there and be visible to application code. */
 extern mbedtls_psa_drbg_context_t *const mbedtls_psa_random_state;
 
 /** A pointer to the PSA DRBG state.
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index 876555d..4875b78 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -703,7 +703,7 @@
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
     psa_key_id_t key_slot = 0; /* invalid key slot */
 #endif
-#endif
+#endif  /* MBEDTLS_X509_CRT_PARSE_C */
     char *p, *q;
     const int *list;
 #if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
@@ -760,10 +760,10 @@
         ret = MBEDTLS_ERR_SSL_HW_ACCEL_FAILED;
         goto exit;
     }
+#endif  /* MBEDTLS_USE_PSA_CRYPTO */
 #if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
     mbedtls_test_enable_insecure_external_rng( );
 #endif  /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
-#endif  /* MBEDTLS_USE_PSA_CRYPTO */
 
     if( argc == 0 )
     {
@@ -1536,7 +1536,8 @@
     mbedtls_printf( "\n  . Seeding the random number generator..." );
     fflush( stdout );
 
-    if( rng_seed( &rng, opt.reproducible, pers ) != 0 )
+    ret = rng_seed( &rng, opt.reproducible, pers );
+    if( ret != 0 )
         goto exit;
     mbedtls_printf( " ok\n" );
 
@@ -1881,7 +1882,7 @@
 #else
         fprintf( stderr, "Warning: reproducible option used without constant time\n" );
 #endif
-#endif
+#endif  /* MBEDTLS_HAVE_TIME */
     }
     mbedtls_ssl_conf_rng( &conf, rng_get, &rng );
     mbedtls_ssl_conf_dbg( &conf, my_debug, stdout );
@@ -1927,7 +1928,7 @@
             goto exit;
         }
     }
-#endif
+#endif  /* MBEDTLS_X509_CRT_PARSE_C */
 
 #if defined(MBEDTLS_ECP_C)
     if( opt.curves != NULL &&
@@ -2999,19 +3000,7 @@
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
     psa_destroy_key( key_slot );
 #endif
-#endif
-    mbedtls_ssl_session_free( &saved_session );
-    mbedtls_ssl_free( &ssl );
-    mbedtls_ssl_config_free( &conf );
-    rng_free( &rng );
-    if( session_data != NULL )
-        mbedtls_platform_zeroize( session_data, session_data_len );
-    mbedtls_free( session_data );
-#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
-    if( context_buf != NULL )
-        mbedtls_platform_zeroize( context_buf, context_buf_len );
-    mbedtls_free( context_buf );
-#endif
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
 
 #if defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) && \
     defined(MBEDTLS_USE_PSA_CRYPTO)
@@ -3034,12 +3023,25 @@
 #endif /* MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED &&
           MBEDTLS_USE_PSA_CRYPTO */
 
+    mbedtls_ssl_session_free( &saved_session );
+    mbedtls_ssl_free( &ssl );
+    mbedtls_ssl_config_free( &conf );
+    rng_free( &rng );
+    if( session_data != NULL )
+        mbedtls_platform_zeroize( session_data, session_data_len );
+    mbedtls_free( session_data );
+#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
+    if( context_buf != NULL )
+        mbedtls_platform_zeroize( context_buf, context_buf_len );
+    mbedtls_free( context_buf );
+#endif
+
 #if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
 #if defined(MBEDTLS_MEMORY_DEBUG)
     mbedtls_memory_buffer_alloc_status();
 #endif
     mbedtls_memory_buffer_alloc_free();
-#endif
+#endif  /* MBEDTLS_MEMORY_BUFFER_ALLOC_C */
 
 #if defined(_WIN32)
     if( opt.query_config_mode == DFL_QUERY_CONFIG_MODE )
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index 57c053c..08317b5 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -1412,10 +1412,10 @@
         ret = MBEDTLS_ERR_SSL_HW_ACCEL_FAILED;
         goto exit;
     }
+#endif  /* MBEDTLS_USE_PSA_CRYPTO */
 #if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
     mbedtls_test_enable_insecure_external_rng( );
 #endif  /* MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
-#endif  /* MBEDTLS_USE_PSA_CRYPTO */
 
 #if !defined(_WIN32)
     /* Abort cleanly on SIGTERM and SIGINT */
@@ -2295,7 +2295,8 @@
     mbedtls_printf( "\n  . Seeding the random number generator..." );
     fflush( stdout );
 
-    if( rng_seed( &rng, opt.reproducible, pers ) != 0 )
+    ret = rng_seed( &rng, opt.reproducible, pers );
+    if( ret != 0 )
         goto exit;
     mbedtls_printf( " ok\n" );
 
@@ -2683,7 +2684,7 @@
 #else
         fprintf( stderr, "Warning: reproducible option used without constant time\n" );
 #endif
-#endif
+#endif  /* MBEDTLS_HAVE_TIME */
     }
     mbedtls_ssl_conf_rng( &conf, rng_get, &rng );
     mbedtls_ssl_conf_dbg( &conf, my_debug, stdout );
@@ -4002,7 +4003,7 @@
     mbedtls_memory_buffer_alloc_status();
 #endif
     mbedtls_memory_buffer_alloc_free();
-#endif
+#endif  /* MBEDTLS_MEMORY_BUFFER_ALLOC_C */
 
     if( opt.query_config_mode == DFL_QUERY_CONFIG_MODE )
     {
diff --git a/programs/ssl/ssl_test_lib.c b/programs/ssl/ssl_test_lib.c
index 46cea14..6636e9e 100644
--- a/programs/ssl/ssl_test_lib.c
+++ b/programs/ssl/ssl_test_lib.c
@@ -46,6 +46,7 @@
     return 0x5af2a056;
 }
 
+#if !defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG)
 static int dummy_entropy( void *data, unsigned char *output, size_t len )
 {
     size_t i;
@@ -60,9 +61,15 @@
     }
     return( ret );
 }
+#endif
 
 void rng_init( rng_context_t *rng )
 {
+#if defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG)
+    (void) rng;
+    psa_crypto_init( );
+#else /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
+
 #if defined(MBEDTLS_CTR_DRBG_C)
     mbedtls_ctr_drbg_init( &rng->drbg );
 #elif defined(MBEDTLS_HMAC_DRBG_C)
@@ -72,10 +79,31 @@
 #endif
 
     mbedtls_entropy_init( &rng->entropy );
+#endif /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
 }
 
 int rng_seed( rng_context_t *rng, int reproducible, const char *pers )
 {
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+    if( reproducible )
+    {
+        mbedtls_fprintf( stderr,
+                         "MBEDTLS_USE_PSA_CRYPTO does not support reproducible mode.\n" );
+        return( -1 );
+    }
+#endif
+#if defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG)
+    /* The PSA crypto RNG does its own seeding. */
+    (void) rng;
+    (void) pers;
+    if( reproducible )
+    {
+        mbedtls_fprintf( stderr,
+                         "The PSA RNG does not support reproducible mode.\n" );
+        return( -1 );
+    }
+    return( 0 );
+#else /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
     int ( *f_entropy )( void *, unsigned char *, size_t ) =
         ( reproducible ? dummy_entropy : mbedtls_entropy_func );
 
@@ -100,9 +128,9 @@
                                       f_entropy, &rng->entropy,
                                       (const unsigned char *) pers,
                                       strlen( pers ) );
-#else
+#else /* !defined(MBEDTLS_CTR_DRBG_C) && !defined(MBEDTLS_HMAC_DRBG_C) */
 #error "No DRBG available"
-#endif
+#endif /* !defined(MBEDTLS_CTR_DRBG_C) && !defined(MBEDTLS_HMAC_DRBG_C) */
 
     if( ret != 0 )
     {
@@ -110,12 +138,21 @@
                         (unsigned int) -ret );
         return( ret );
     }
+#endif /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
 
     return( 0 );
 }
 
 void rng_free( rng_context_t *rng )
 {
+#if defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG)
+    (void) rng;
+    /* Deinitialize the PSA crypto subsystem. This deactivates all PSA APIs.
+     * This is ok because none of our applications try to do any crypto after
+     * deinitializing the RNG. */
+    mbedtls_psa_crypto_free( );
+#else /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
+
 #if defined(MBEDTLS_CTR_DRBG_C)
     mbedtls_ctr_drbg_free( &rng->drbg );
 #elif defined(MBEDTLS_HMAC_DRBG_C)
@@ -125,11 +162,18 @@
 #endif
 
     mbedtls_entropy_free( &rng->entropy );
+#endif /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
 }
 
 int rng_get( void *p_rng, unsigned char *output, size_t output_len )
 {
+#if defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG)
+    (void) p_rng;
+    return( mbedtls_psa_get_random( MBEDTLS_PSA_RANDOM_STATE,
+                                    output, output_len ) );
+#else /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
     rng_context_t *rng = p_rng;
+
 #if defined(MBEDTLS_CTR_DRBG_C)
     return( mbedtls_ctr_drbg_random( &rng->drbg, output, output_len ) );
 #elif defined(MBEDTLS_HMAC_DRBG_C)
@@ -137,6 +181,8 @@
 #else
 #error "No DRBG available"
 #endif
+
+#endif /* !MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
 }
 
 #if defined(MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK)
diff --git a/programs/ssl/ssl_test_lib.h b/programs/ssl/ssl_test_lib.h
index 861e82a..04ba158 100644
--- a/programs/ssl/ssl_test_lib.h
+++ b/programs/ssl/ssl_test_lib.h
@@ -43,23 +43,33 @@
 #define MBEDTLS_EXIT_FAILURE    EXIT_FAILURE
 #endif
 
-#if !defined(MBEDTLS_ENTROPY_C) ||                          \
-    !defined(MBEDTLS_NET_C) ||                              \
+#undef HAVE_RNG
+#if defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG) &&         \
+    ( defined(MBEDTLS_USE_PSA_CRYPTO) ||                \
+      defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG) )
+#define HAVE_RNG
+#elif defined(MBEDTLS_ENTROPY_C) && defined(MBEDTLS_CTR_DRBG_C)
+#define HAVE_RNG
+#elif defined(MBEDTLS_ENTROPY_C) && defined(MBEDTLS_HMAC_DRBG_C) &&     \
+    ( defined(MBEDTLS_SHA256_C) || defined(MBEDTLS_SHA512_C) )
+#define HAVE_RNG
+#endif
+
+#if !defined(MBEDTLS_NET_C) ||                              \
     !defined(MBEDTLS_SSL_TLS_C) ||                          \
     defined(MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER)
 #define MBEDTLS_SSL_TEST_IMPOSSIBLE                             \
-    "MBEDTLS_ENTROPY_C and/or "                                 \
     "MBEDTLS_NET_C and/or "                                     \
     "MBEDTLS_SSL_TLS_C not defined, "                           \
     "and/or MBEDTLS_PSA_CRYPTO_KEY_ID_ENCODES_OWNER defined.\n"
-#elif !( defined(MBEDTLS_CTR_DRBG_C) ||                                 \
-         defined(MBEDTLS_HMAC_DRBG_C) && ( defined(MBEDTLS_SHA256_C) || \
-                                           defined(MBEDTLS_SHA512_C) ) )
-#define MBEDTLS_SSL_TEST_IMPOSSIBLE                                     \
-    "Neither MBEDTLS_CTR_DRBG_C, nor MBEDTLS_HMAC_DRBG_C and a supported hash defined.\n"
+#elif !defined(HAVE_RNG)
+#define MBEDTLS_SSL_TEST_IMPOSSIBLE             \
+    "No random generator is available.\n"
 #else
 #undef MBEDTLS_SSL_TEST_IMPOSSIBLE
 
+#undef HAVE_RNG
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -76,7 +86,7 @@
 #include "mbedtls/timing.h"
 #include "mbedtls/base64.h"
 
-#if defined(MBEDTLS_USE_PSA_CRYPTO)
+#if defined(MBEDTLS_USE_PSA_CRYPTO) || defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG)
 #include "psa/crypto.h"
 #include "mbedtls/psa_util.h"
 #endif
@@ -130,10 +140,38 @@
 
 mbedtls_time_t dummy_constant_time( mbedtls_time_t* time );
 
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+/* If MBEDTLS_TEST_USE_PSA_CRYPTO_RNG is defined, the SSL test programs will use
+ * mbedtls_psa_get_random() rather than entropy+DRBG as a random generator.
+ *
+ * The constraints are:
+ * - Without the entropy module, the PSA RNG is the only option.
+ * - Without at least one of the DRBG modules, the PSA RNG is the only option.
+ * - The PSA RNG does not support explicit seeding, so it is incompatible with
+ *   the reproducible mode used by test programs.
+ * - For good overall test coverage, there should be at least one configuration
+ *   where the test programs use the PSA RNG while the PSA RNG is itself based
+ *   on entropy+DRBG, and at least one configuration where the test programs
+ *   do not use the PSA RNG even though it's there.
+ *
+ * A simple choice that meets the constraints is to use the PSA RNG whenever
+ * MBEDTLS_USE_PSA_CRYPTO is enabled. There's no real technical reason the
+ * choice to use the PSA RNG in the test programs and the choice to use
+ * PSA crypto when TLS code needs crypto have to be tied together, but it
+ * happens to be a good match. It's also a good match from an application
+ * perspective: either PSA is preferred for TLS (both for crypto and for
+ * random generation) or it isn't.
+ */
+#define MBEDTLS_TEST_USE_PSA_CRYPTO_RNG
+#endif
+
 /** A context for random number generation (RNG).
  */
 typedef struct
 {
+#if defined(MBEDTLS_TEST_USE_PSA_CRYPTO_RNG)
+    unsigned char dummy;
+#else /* MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
     mbedtls_entropy_context entropy;
 #if defined(MBEDTLS_CTR_DRBG_C)
     mbedtls_ctr_drbg_context drbg;
@@ -142,6 +180,7 @@
 #else
 #error "No DRBG available"
 #endif
+#endif /* MBEDTLS_TEST_USE_PSA_CRYPTO_RNG */
 } rng_context_t;
 
 /** Initialize the RNG.
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 13f0593..cefc5c9 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -153,6 +153,7 @@
 add_test_suite(psa_crypto_se_driver_hal_mocks)
 add_test_suite(psa_crypto_slot_management)
 add_test_suite(psa_its)
+add_test_suite(random)
 add_test_suite(rsa)
 add_test_suite(shax)
 add_test_suite(ssl)
diff --git a/tests/include/test/helpers.h b/tests/include/test/helpers.h
index 8b56d3a..928c636 100644
--- a/tests/include/test/helpers.h
+++ b/tests/include/test/helpers.h
@@ -256,7 +256,7 @@
 void mbedtls_test_param_failed_reset_state( void );
 #endif /* MBEDTLS_CHECK_PARAMS */
 
-#if defined(MBEDTLS_USE_PSA_CRYPTO) && defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
+#if defined(MBEDTLS_PSA_CRYPTO_C) && defined(MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG)
 #include "test/fake_external_rng_for_test.h"
 #endif
 
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index 1036a7c..43742fd 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -922,37 +922,61 @@
     if_build_succeeded tests/context-info.sh
 }
 
-component_test_no_ctr_drbg () {
-    msg "build: Full minus CTR_DRBG"
+component_test_no_ctr_drbg_classic () {
+    msg "build: Full minus CTR_DRBG, classic crypto in TLS"
     scripts/config.py full
     scripts/config.py unset MBEDTLS_CTR_DRBG_C
+    scripts/config.py unset MBEDTLS_USE_PSA_CRYPTO
 
     CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
     make
 
-    msg "test: Full minus CTR_DRBG - main suites"
+    msg "test: Full minus CTR_DRBG, classic crypto - main suites"
     make test
 
     # In this configuration, the TLS test programs use HMAC_DRBG.
     # The SSL tests are slow, so run a small subset, just enough to get
     # confidence that the SSL code copes with HMAC_DRBG.
-    msg "test: Full minus CTR_DRBG - ssl-opt.sh (subset)"
+    msg "test: Full minus CTR_DRBG, classic crypto - ssl-opt.sh (subset)"
     if_build_succeeded tests/ssl-opt.sh -f 'Default\|SSL async private.*delay=\|tickets enabled on server'
 
-    msg "test: Full minus CTR_DRBG - compat.sh (subset)"
+    msg "test: Full minus CTR_DRBG, classic crypto - compat.sh (subset)"
     if_build_succeeded tests/compat.sh -m tls1_2 -t 'ECDSA PSK' -V NO -p OpenSSL
 }
 
-component_test_no_hmac_drbg () {
-    msg "build: Full minus HMAC_DRBG"
+component_test_no_ctr_drbg_use_psa () {
+    msg "build: Full minus CTR_DRBG, PSA crypto in TLS"
     scripts/config.py full
-    scripts/config.py unset MBEDTLS_HMAC_DRBG_C
-    scripts/config.py unset MBEDTLS_ECDSA_DETERMINISTIC # requires HMAC_DRBG
+    scripts/config.py unset MBEDTLS_CTR_DRBG_C
+    scripts/config.py set MBEDTLS_USE_PSA_CRYPTO
 
     CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
     make
 
-    msg "test: Full minus HMAC_DRBG - main suites"
+    msg "test: Full minus CTR_DRBG, USE_PSA_CRYPTO - main suites"
+    make test
+
+    # In this configuration, the TLS test programs use HMAC_DRBG.
+    # The SSL tests are slow, so run a small subset, just enough to get
+    # confidence that the SSL code copes with HMAC_DRBG.
+    msg "test: Full minus CTR_DRBG, USE_PSA_CRYPTO - ssl-opt.sh (subset)"
+    if_build_succeeded tests/ssl-opt.sh -f 'Default\|SSL async private.*delay=\|tickets enabled on server'
+
+    msg "test: Full minus CTR_DRBG, USE_PSA_CRYPTO - compat.sh (subset)"
+    if_build_succeeded tests/compat.sh -m tls1_2 -t 'ECDSA PSK' -V NO -p OpenSSL
+}
+
+component_test_no_hmac_drbg_classic () {
+    msg "build: Full minus HMAC_DRBG, classic crypto in TLS"
+    scripts/config.py full
+    scripts/config.py unset MBEDTLS_HMAC_DRBG_C
+    scripts/config.py unset MBEDTLS_ECDSA_DETERMINISTIC # requires HMAC_DRBG
+    scripts/config.py unset MBEDTLS_USE_PSA_CRYPTO
+
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
+
+    msg "test: Full minus HMAC_DRBG, classic crypto - main suites"
     make test
 
     # Normally our ECDSA implementation uses deterministic ECDSA. But since
@@ -960,29 +984,84 @@
     # instead.
     # Test SSL with non-deterministic ECDSA. Only test features that
     # might be affected by how ECDSA signature is performed.
-    msg "test: Full minus HMAC_DRBG - ssl-opt.sh (subset)"
+    msg "test: Full minus HMAC_DRBG, classic crypto - ssl-opt.sh (subset)"
     if_build_succeeded tests/ssl-opt.sh -f 'Default\|SSL async private: sign'
 
     # To save time, only test one protocol version, since this part of
     # the protocol is identical in (D)TLS up to 1.2.
-    msg "test: Full minus HMAC_DRBG - compat.sh (ECDSA)"
+    msg "test: Full minus HMAC_DRBG, classic crypto - compat.sh (ECDSA)"
     if_build_succeeded tests/compat.sh -m tls1_2 -t 'ECDSA'
 }
 
-component_test_psa_external_rng_no_drbg () {
-    msg "build: PSA_CRYPTO_EXTERNAL_RNG minus *_DRBG"
+component_test_no_hmac_drbg_use_psa () {
+    msg "build: Full minus HMAC_DRBG, PSA crypto in TLS"
+    scripts/config.py full
+    scripts/config.py unset MBEDTLS_HMAC_DRBG_C
+    scripts/config.py unset MBEDTLS_ECDSA_DETERMINISTIC # requires HMAC_DRBG
+    scripts/config.py set MBEDTLS_USE_PSA_CRYPTO
+
+    CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+    make
+
+    msg "test: Full minus HMAC_DRBG, USE_PSA_CRYPTO - main suites"
+    make test
+
+    # Normally our ECDSA implementation uses deterministic ECDSA. But since
+    # HMAC_DRBG is disabled in this configuration, randomized ECDSA is used
+    # instead.
+    # Test SSL with non-deterministic ECDSA. Only test features that
+    # might be affected by how ECDSA signature is performed.
+    msg "test: Full minus HMAC_DRBG, USE_PSA_CRYPTO - ssl-opt.sh (subset)"
+    if_build_succeeded tests/ssl-opt.sh -f 'Default\|SSL async private: sign'
+
+    # To save time, only test one protocol version, since this part of
+    # the protocol is identical in (D)TLS up to 1.2.
+    msg "test: Full minus HMAC_DRBG, USE_PSA_CRYPTO - compat.sh (ECDSA)"
+    if_build_succeeded tests/compat.sh -m tls1_2 -t 'ECDSA'
+}
+
+component_test_psa_external_rng_no_drbg_classic () {
+    msg "build: PSA_CRYPTO_EXTERNAL_RNG minus *_DRBG, classic crypto in TLS"
+    scripts/config.py full
+    scripts/config.py unset MBEDTLS_USE_PSA_CRYPTO
+    scripts/config.py set MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
+    scripts/config.py unset MBEDTLS_ENTROPY_C
+    scripts/config.py unset MBEDTLS_ENTROPY_NV_SEED
+    scripts/config.py unset MBEDTLS_PLATFORM_NV_SEED_ALT
+    scripts/config.py unset MBEDTLS_CTR_DRBG_C
+    scripts/config.py unset MBEDTLS_HMAC_DRBG_C
+    scripts/config.py unset MBEDTLS_ECDSA_DETERMINISTIC # requires HMAC_DRBG
+    scripts/config.py set MBEDTLS_ECP_NO_INTERNAL_RNG
+    # When MBEDTLS_USE_PSA_CRYPTO is disabled and there is no DRBG,
+    # the SSL test programs don't have an RNG and can't work. Explicitly
+    # make them use the PSA RNG with -DMBEDTLS_TEST_USE_PSA_CRYPTO_RNG.
+    make CFLAGS="$ASAN_CFLAGS -O2 -DMBEDTLS_TEST_USE_PSA_CRYPTO_RNG" LDFLAGS="$ASAN_CFLAGS"
+
+    msg "test: PSA_CRYPTO_EXTERNAL_RNG minus *_DRBG, classic crypto - main suites"
+    make test
+
+    msg "test: PSA_CRYPTO_EXTERNAL_RNG minus *_DRBG, classic crypto - ssl-opt.sh (subset)"
+    if_build_succeeded tests/ssl-opt.sh -f 'Default'
+}
+
+component_test_psa_external_rng_no_drbg_use_psa () {
+    msg "build: PSA_CRYPTO_EXTERNAL_RNG minus *_DRBG, PSA crypto in TLS"
     scripts/config.py full
     scripts/config.py set MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
+    scripts/config.py unset MBEDTLS_ENTROPY_C
+    scripts/config.py unset MBEDTLS_ENTROPY_NV_SEED
+    scripts/config.py unset MBEDTLS_PLATFORM_NV_SEED_ALT
     scripts/config.py unset MBEDTLS_CTR_DRBG_C
     scripts/config.py unset MBEDTLS_HMAC_DRBG_C
     scripts/config.py unset MBEDTLS_ECDSA_DETERMINISTIC # requires HMAC_DRBG
     scripts/config.py set MBEDTLS_ECP_NO_INTERNAL_RNG
     make CFLAGS="$ASAN_CFLAGS -O2" LDFLAGS="$ASAN_CFLAGS"
 
-    msg "test: PSA_CRYPTO_EXTERNAL_RNG minus *_DRBG"
+    msg "test: PSA_CRYPTO_EXTERNAL_RNG minus *_DRBG, PSA crypto - main suites"
     make test
 
-    # no SSL tests as they all depend on having a DRBG
+    msg "test: PSA_CRYPTO_EXTERNAL_RNG minus *_DRBG, PSA crypto - ssl-opt.sh (subset)"
+    if_build_succeeded tests/ssl-opt.sh -f 'Default\|opaque'
 }
 
 component_test_psa_external_rng_use_psa_crypto () {
diff --git a/tests/suites/test_suite_random.data b/tests/suites/test_suite_random.data
new file mode 100644
index 0000000..c23d922
--- /dev/null
+++ b/tests/suites/test_suite_random.data
@@ -0,0 +1,55 @@
+Generate random twice with CTR_DRBG
+random_twice_with_ctr_drbg:
+
+Generate random twice with HMAC_DRBG(SHA-1)
+depends_on:MBEDTLS_SHA1_C
+random_twice_with_hmac_drbg:MBEDTLS_MD_SHA1
+
+Generate random twice with HMAC_DRBG(SHA-256)
+depends_on:MBEDTLS_SHA256_C
+random_twice_with_hmac_drbg:MBEDTLS_MD_SHA256
+
+Generate random twice with HMAC_DRBG(SHA-512)
+depends_on:MBEDTLS_SHA512_C
+random_twice_with_hmac_drbg:MBEDTLS_MD_SHA512
+
+Generate random twice with PSA classic wrapper
+random_twice_with_psa_from_classic:
+
+Generate random twice with PSA API
+random_twice_with_psa_from_psa:
+
+# This bad-usage test case currently crashes in the default configuration
+# because CTR_DRBG crashes when given an unseeded context. This is arguably
+# a good thing because it prevents misuse of mbedtls_psa_get_random().
+#PSA classic wrapper: PSA not active
+#mbedtls_psa_get_random_no_init:
+
+PSA classic wrapper: 0 bytes
+mbedtls_psa_get_random_length:0
+
+PSA classic wrapper: 1 byte
+mbedtls_psa_get_random_length:1
+
+PSA classic wrapper: 256 bytes
+mbedtls_psa_get_random_length:256
+
+# An external RNG is supposed to handle arbitrary request lengths. Test it
+# with something larger than any RNG call made by Mbed TLS itself expects.
+# CTR_DRBG and HMAC_DRBG have their own maximum request lengths which may
+# be lower than the value chosen here and are tested separately.
+PSA classic wrapper: external RNG large
+depends_on:MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
+mbedtls_psa_get_random_length:1024
+
+PSA classic wrapper: CTR_DRBG max
+depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG:MBEDTLS_CTR_DRBG_C
+mbedtls_psa_get_random_length:MBEDTLS_CTR_DRBG_MAX_REQUEST
+
+PSA classic wrapper: HMAC_DRBG max
+depends_on:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG:!MBEDTLS_CTR_DRBG_C:MBEDTLS_HMAC_DRBG_C
+mbedtls_psa_get_random_length:MBEDTLS_HMAC_DRBG_MAX_REQUEST
+
+PSA classic wrapper: ECDSA signature (SECP256R1)
+depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+mbedtls_psa_get_random_ecdsa_sign:MBEDTLS_ECP_DP_SECP256R1
diff --git a/tests/suites/test_suite_random.function b/tests/suites/test_suite_random.function
new file mode 100644
index 0000000..37fa36e
--- /dev/null
+++ b/tests/suites/test_suite_random.function
@@ -0,0 +1,202 @@
+/* BEGIN_HEADER */
+
+/* Test random generation as a whole. */
+
+#include "mbedtls/bignum.h"
+#include "mbedtls/ctr_drbg.h"
+#include "mbedtls/ecdsa.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/hmac_drbg.h"
+#include "mbedtls/psa_util.h"
+#include "psa/crypto.h"
+
+/* How many bytes to generate in each test case for repeated generation.
+ * This must be high enough that the probability of generating the same
+ * output twice is infinitesimal, but low enough that random generators
+ * are willing to deliver that much. */
+#define OUTPUT_SIZE 32
+
+/* END_HEADER */
+
+/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_C:!MBEDTLS_TEST_NULL_ENTROPY:MBEDTLS_CTR_DRBG_C */
+void random_twice_with_ctr_drbg( )
+{
+    mbedtls_entropy_context entropy;
+    mbedtls_ctr_drbg_context drbg;
+    unsigned char output1[OUTPUT_SIZE];
+    unsigned char output2[OUTPUT_SIZE];
+
+    /* First round */
+    mbedtls_entropy_init( &entropy );
+    mbedtls_ctr_drbg_init( &drbg );
+    TEST_EQUAL( 0, mbedtls_ctr_drbg_seed( &drbg,
+                                          mbedtls_entropy_func, &entropy,
+                                          NULL, 0 ) );
+    TEST_EQUAL( 0, mbedtls_ctr_drbg_random( &drbg,
+                                            output1, sizeof( output1 ) ) );
+    mbedtls_ctr_drbg_free( &drbg );
+    mbedtls_entropy_free( &entropy );
+
+    /* Second round */
+    mbedtls_entropy_init( &entropy );
+    mbedtls_ctr_drbg_init( &drbg );
+    TEST_EQUAL( 0, mbedtls_ctr_drbg_seed( &drbg,
+                                          mbedtls_entropy_func, &entropy,
+                                          NULL, 0 ) );
+    TEST_EQUAL( 0, mbedtls_ctr_drbg_random( &drbg,
+                                            output2, sizeof( output2 ) ) );
+    mbedtls_ctr_drbg_free( &drbg );
+    mbedtls_entropy_free( &entropy );
+
+    /* The two rounds must generate different random data. */
+    TEST_ASSERT( memcmp( output1, output2, OUTPUT_SIZE ) != 0 );
+
+exit:
+    mbedtls_ctr_drbg_free( &drbg );
+    mbedtls_entropy_free( &entropy );
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_ENTROPY_C:!MBEDTLS_TEST_NULL_ENTROPY:MBEDTLS_HMAC_DRBG_C */
+void random_twice_with_hmac_drbg( int md_type )
+{
+    mbedtls_entropy_context entropy;
+    mbedtls_hmac_drbg_context drbg;
+    unsigned char output1[OUTPUT_SIZE];
+    unsigned char output2[OUTPUT_SIZE];
+    const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( md_type );
+
+    /* First round */
+    mbedtls_entropy_init( &entropy );
+    mbedtls_hmac_drbg_init( &drbg );
+    TEST_EQUAL( 0, mbedtls_hmac_drbg_seed( &drbg, md_info,
+                                           mbedtls_entropy_func, &entropy,
+                                           NULL, 0 ) );
+    TEST_EQUAL( 0, mbedtls_hmac_drbg_random( &drbg,
+                                             output1, sizeof( output1 ) ) );
+    mbedtls_hmac_drbg_free( &drbg );
+    mbedtls_entropy_free( &entropy );
+
+    /* Second round */
+    mbedtls_entropy_init( &entropy );
+    mbedtls_hmac_drbg_init( &drbg );
+    TEST_EQUAL( 0, mbedtls_hmac_drbg_seed( &drbg, md_info,
+                                           mbedtls_entropy_func, &entropy,
+                                           NULL, 0 ) );
+    TEST_EQUAL( 0, mbedtls_hmac_drbg_random( &drbg,
+                                             output2, sizeof( output2 ) ) );
+    mbedtls_hmac_drbg_free( &drbg );
+    mbedtls_entropy_free( &entropy );
+
+    /* The two rounds must generate different random data. */
+    TEST_ASSERT( memcmp( output1, output2, OUTPUT_SIZE ) != 0 );
+
+exit:
+    mbedtls_hmac_drbg_free( &drbg );
+    mbedtls_entropy_free( &entropy );
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_C:!MBEDTLS_TEST_NULL_ENTROPY:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
+void random_twice_with_psa_from_classic( )
+{
+    unsigned char output1[OUTPUT_SIZE];
+    unsigned char output2[OUTPUT_SIZE];
+
+    /* First round */
+    PSA_ASSERT( psa_crypto_init( ) );
+    TEST_EQUAL( 0, mbedtls_psa_get_random( MBEDTLS_PSA_RANDOM_STATE,
+                                           output1, sizeof( output1 ) ) );
+    PSA_DONE( );
+
+    /* Second round */
+    PSA_ASSERT( psa_crypto_init( ) );
+    TEST_EQUAL( 0, mbedtls_psa_get_random( MBEDTLS_PSA_RANDOM_STATE,
+                                           output2, sizeof( output2 ) ) );
+    PSA_DONE( );
+
+    /* The two rounds must generate different random data. */
+    TEST_ASSERT( memcmp( output1, output2, OUTPUT_SIZE ) != 0 );
+
+exit:
+    PSA_DONE( );
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_C:!MBEDTLS_TEST_NULL_ENTROPY:!MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG */
+void random_twice_with_psa_from_psa( )
+{
+    unsigned char output1[OUTPUT_SIZE];
+    unsigned char output2[OUTPUT_SIZE];
+
+    /* First round */
+    PSA_ASSERT( psa_crypto_init( ) );
+    PSA_ASSERT( psa_generate_random( output1, sizeof( output1 ) ) );
+    PSA_DONE( );
+
+    /* Second round */
+    PSA_ASSERT( psa_crypto_init( ) );
+    PSA_ASSERT( psa_generate_random( output2, sizeof( output2 ) ) );
+    PSA_DONE( );
+
+    /* The two rounds must generate different random data. */
+    TEST_ASSERT( memcmp( output1, output2, OUTPUT_SIZE ) != 0 );
+
+exit:
+    PSA_DONE( );
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_C */
+void mbedtls_psa_get_random_no_init( )
+{
+    unsigned char output[1];
+
+    TEST_ASSERT( mbedtls_psa_get_random( MBEDTLS_PSA_RANDOM_STATE,
+                                         output, sizeof( output ) ) != 0 );
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_C */
+void mbedtls_psa_get_random_length( int n )
+{
+    unsigned char *output = NULL;
+
+    PSA_ASSERT( psa_crypto_init( ) );
+    ASSERT_ALLOC( output, n );
+
+    TEST_EQUAL( 0, mbedtls_psa_get_random( MBEDTLS_PSA_RANDOM_STATE,
+                                           output, n ) );
+exit:
+    mbedtls_free( output );
+    PSA_DONE( );
+}
+/* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_C:MBEDTLS_ECDSA_C */
+void mbedtls_psa_get_random_ecdsa_sign( int curve )
+{
+    mbedtls_ecp_group grp;
+    mbedtls_mpi d, r, s;
+    unsigned char buf[] = "This is not a hash.";
+
+    mbedtls_ecp_group_init( &grp );
+    mbedtls_mpi_init( &d );
+    mbedtls_mpi_init( &r );
+    mbedtls_mpi_init( &s );
+
+    TEST_EQUAL( 0, mbedtls_mpi_lset( &d, 123456789 ) );
+    TEST_EQUAL( 0, mbedtls_ecp_group_load( &grp, curve ) );
+    PSA_ASSERT( psa_crypto_init( ) );
+    TEST_EQUAL( 0, mbedtls_ecdsa_sign( &grp, &r, &s, &d,
+                                       buf, sizeof( buf ),
+                                       mbedtls_psa_get_random,
+                                       MBEDTLS_PSA_RANDOM_STATE ) );
+exit:
+    mbedtls_mpi_free( &d );
+    mbedtls_mpi_free( &r );
+    mbedtls_mpi_free( &s );
+    mbedtls_ecp_group_free( &grp );
+    PSA_DONE( );
+}
+/* END_CASE */