Merge pull request #7242 from mpg/md-dispatch-psa

Implement MD dispatch to PSA
diff --git a/docs/architecture/psa-migration/md-cipher-dispatch.md b/docs/architecture/psa-migration/md-cipher-dispatch.md
index eee59c4..355f561 100644
--- a/docs/architecture/psa-migration/md-cipher-dispatch.md
+++ b/docs/architecture/psa-migration/md-cipher-dispatch.md
@@ -312,13 +312,16 @@
 ```
 #if defined(MBEDTLS_MD_LIGHT)
 #if defined(MBEDTLS_SHA256_C) || \
-    ((defined(MBEDTLS_PSA_CRYPTO_C) || defined(MBEDTLS_PSA_CRYPTO_CLIENT)) && \
-     PSA_WANT_ALG_SHA_256)
+    (defined(MBEDTLS_PSA_CRYPTO_C) && PSA_WANT_ALG_SHA_256)
 #define MBEDTLS_MD_CAN_SHA256
 #endif
 #endif
 ```
 
+Note: in the future, we may want to replace `defined(MBEDTLS_PSA_CRYPTO_C)`
+with `defined(MBEDTLS_PSA_CRYTO_C) || defined(MBEDTLS_PSA_CRYPTO_CLIENT)` but
+for now this is out of scope.
+
 #### MD light internal support macros
 
 * If at least one hash has a PSA driver, define `MBEDTLS_MD_SOME_PSA`.
@@ -337,16 +340,11 @@
 } mbedtls_md_engine_t; // private type
 
 typedef struct mbedtls_md_context_t {
-    const mbedtls_md_type_t type;
-    const mbedtls_md_engine_t engine;
-    union {
-#if defined(MBEDTLS_MD_SOME_LEGACY)
-        void *legacy; // used if engine == LEGACY
-#endif
+    mbedtls_md_type_t type;
 #if defined(MBEDTLS_MD_SOME_PSA)
-        psa_hash_operation_t *psa; // used if engine == PSA
+    mbedtls_md_engine_t engine;
 #endif
-    } digest;
+    void *md_ctx; // mbedtls_xxx_context or psa_hash_operation
 #if defined(MBEDTLS_MD_C)
     void *hmac_ctx;
 #endif
diff --git a/include/mbedtls/md.h b/include/mbedtls/md.h
index 3341d1c..7bad24d 100644
--- a/include/mbedtls/md.h
+++ b/include/mbedtls/md.h
@@ -32,6 +32,93 @@
 #include "mbedtls/build_info.h"
 #include "mbedtls/platform_util.h"
 
+#if defined(MBEDTLS_MD_LIGHT)
+
+/*
+ * - MBEDTLS_MD_CAN_xxx is defined if the md module can perform xxx.
+ * - MBEDTLS_MD_xxx_VIA_PSA is defined if the md module may perform xxx via PSA
+ *   (see below).
+ * - MBEDTLS_MD_SOME_PSA is defined if at least one algorithm may be performed
+ *   via PSA (see below).
+ * - MBEDTLS_MD_SOME_LEGACY is defined if at least one algorithm may be performed
+ *   via a direct legacy call (see below).
+ *
+ * The md module performs an algorithm via PSA if there is a PSA hash
+ * accelerator and the PSA driver subsytem is initialized at the time the
+ * operation is started, and makes a direct legacy call otherwise.
+ */
+
+/* PSA accelerated implementations */
+#if defined(MBEDTLS_PSA_CRYPTO_C)
+#if defined(MBEDTLS_PSA_ACCEL_ALG_MD5)
+#define MBEDTLS_MD_CAN_MD5
+#define MBEDTLS_MD_MD5_VIA_PSA
+#define MBEDTLS_MD_SOME_PSA
+#endif
+#if defined(MBEDTLS_PSA_ACCEL_ALG_SHA_1)
+#define MBEDTLS_MD_CAN_SHA1
+#define MBEDTLS_MD_SHA1_VIA_PSA
+#define MBEDTLS_MD_SOME_PSA
+#endif
+#if defined(MBEDTLS_PSA_ACCEL_ALG_SHA_224)
+#define MBEDTLS_MD_CAN_SHA224
+#define MBEDTLS_MD_SHA224_VIA_PSA
+#define MBEDTLS_MD_SOME_PSA
+#endif
+#if defined(MBEDTLS_PSA_ACCEL_ALG_SHA_256)
+#define MBEDTLS_MD_CAN_SHA256
+#define MBEDTLS_MD_SHA256_VIA_PSA
+#define MBEDTLS_MD_SOME_PSA
+#endif
+#if defined(MBEDTLS_PSA_ACCEL_ALG_SHA_384)
+#define MBEDTLS_MD_CAN_SHA384
+#define MBEDTLS_MD_SHA384_VIA_PSA
+#define MBEDTLS_MD_SOME_PSA
+#endif
+#if defined(MBEDTLS_PSA_ACCEL_ALG_SHA_512)
+#define MBEDTLS_MD_CAN_SHA512
+#define MBEDTLS_MD_SHA512_VIA_PSA
+#define MBEDTLS_MD_SOME_PSA
+#endif
+#if defined(MBEDTLS_PSA_ACCEL_ALG_RIPEMD160)
+#define MBEDTLS_MD_CAN_RIPEMD160
+#define MBEDTLS_MD_RIPEMD160_VIA_PSA
+#define MBEDTLS_MD_SOME_PSA
+#endif
+#endif /* MBEDTLS_PSA_CRYPTO_C */
+
+/* Built-in implementations */
+#if defined(MBEDTLS_MD5_C)
+#define MBEDTLS_MD_CAN_MD5
+#define MBEDTLS_MD_SOME_LEGACY
+#endif
+#if defined(MBEDTLS_SHA1_C)
+#define MBEDTLS_MD_CAN_SHA1
+#define MBEDTLS_MD_SOME_LEGACY
+#endif
+#if defined(MBEDTLS_SHA224_C)
+#define MBEDTLS_MD_CAN_SHA224
+#define MBEDTLS_MD_SOME_LEGACY
+#endif
+#if defined(MBEDTLS_SHA256_C)
+#define MBEDTLS_MD_CAN_SHA256
+#define MBEDTLS_MD_SOME_LEGACY
+#endif
+#if defined(MBEDTLS_SHA384_C)
+#define MBEDTLS_MD_CAN_SHA384
+#define MBEDTLS_MD_SOME_LEGACY
+#endif
+#if defined(MBEDTLS_SHA512_C)
+#define MBEDTLS_MD_CAN_SHA512
+#define MBEDTLS_MD_SOME_LEGACY
+#endif
+#if defined(MBEDTLS_RIPEMD160_C)
+#define MBEDTLS_MD_CAN_RIPEMD160
+#define MBEDTLS_MD_SOME_LEGACY
+#endif
+
+#endif /* MBEDTLS_MD_LIGHT */
+
 /** The selected feature is not available. */
 #define MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE                -0x5080
 /** Bad input parameters to function. */
@@ -64,19 +151,20 @@
     MBEDTLS_MD_RIPEMD160, /**< The RIPEMD-160 message digest. */
 } mbedtls_md_type_t;
 
-#if defined(MBEDTLS_SHA512_C)
+#if defined(MBEDTLS_MD_CAN_SHA512)
 #define MBEDTLS_MD_MAX_SIZE         64  /* longest known is SHA512 */
-#elif defined(MBEDTLS_SHA384_C)
+#elif defined(MBEDTLS_MD_CAN_SHA384)
 #define MBEDTLS_MD_MAX_SIZE         48  /* longest known is SHA384 */
-#elif defined(MBEDTLS_SHA256_C)
+#elif defined(MBEDTLS_MD_CAN_SHA256)
 #define MBEDTLS_MD_MAX_SIZE         32  /* longest known is SHA256 */
-#elif defined(MBEDTLS_SHA224_C)
+#elif defined(MBEDTLS_MD_CAN_SHA224)
 #define MBEDTLS_MD_MAX_SIZE         28  /* longest known is SHA224 */
 #else
-#define MBEDTLS_MD_MAX_SIZE         20  /* longest known is SHA1 or RIPE MD-160 */
+#define MBEDTLS_MD_MAX_SIZE         20  /* longest known is SHA1 or RIPE MD-160
+                                           or smaller (MD5 and earlier) */
 #endif
 
-#if defined(MBEDTLS_SHA512_C)
+#if defined(MBEDTLS_MD_CAN_SHA512)
 #define MBEDTLS_MD_MAX_BLOCK_SIZE         128
 #else
 #define MBEDTLS_MD_MAX_BLOCK_SIZE         64
@@ -95,17 +183,34 @@
 typedef struct mbedtls_md_info_t mbedtls_md_info_t;
 
 /**
+ * Used internally to indicate whether a context uses legacy or PSA.
+ *
+ * Internal use only.
+ */
+typedef enum {
+    MBEDTLS_MD_ENGINE_LEGACY = 0,
+    MBEDTLS_MD_ENGINE_PSA,
+} mbedtls_md_engine_t;
+
+/**
  * The generic message-digest context.
  */
 typedef struct mbedtls_md_context_t {
     /** Information about the associated message digest. */
     const mbedtls_md_info_t *MBEDTLS_PRIVATE(md_info);
 
-    /** The digest-specific context. */
+#if defined(MBEDTLS_MD_SOME_PSA)
+    /** Are hash operations dispatched to PSA or legacy? */
+    mbedtls_md_engine_t MBEDTLS_PRIVATE(engine);
+#endif
+
+    /** The digest-specific context (legacy) or the PSA operation. */
     void *MBEDTLS_PRIVATE(md_ctx);
 
+#if defined(MBEDTLS_MD_C)
     /** The HMAC part of the context. */
     void *MBEDTLS_PRIVATE(hmac_ctx);
+#endif
 } mbedtls_md_context_t;
 
 /**
@@ -185,6 +290,10 @@
  *
  * \return          \c 0 on success.
  * \return          #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification failure.
+ * \return          #MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE if both contexts are
+ *                  not using the same engine. This can be avoided by moving
+ *                  the call to psa_crypto_init() before the first call to
+ *                  mbedtls_md_setup().
  */
 MBEDTLS_CHECK_RETURN_TYPICAL
 int mbedtls_md_clone(mbedtls_md_context_t *dst,
diff --git a/library/md.c b/library/md.c
index 6681f9a..bebe358 100644
--- a/library/md.c
+++ b/library/md.c
@@ -52,6 +52,11 @@
 #include "mbedtls/sha256.h"
 #include "mbedtls/sha512.h"
 
+#if defined(MBEDTLS_MD_SOME_PSA)
+#include <psa/crypto.h>
+#include "psa_crypto_core.h"
+#endif
+
 #include "mbedtls/platform.h"
 
 #include <string.h>
@@ -60,7 +65,7 @@
 #include <stdio.h>
 #endif
 
-#if defined(MBEDTLS_MD5_C)
+#if defined(MBEDTLS_MD_CAN_MD5)
 const mbedtls_md_info_t mbedtls_md5_info = {
     "MD5",
     MBEDTLS_MD_MD5,
@@ -69,7 +74,7 @@
 };
 #endif
 
-#if defined(MBEDTLS_RIPEMD160_C)
+#if defined(MBEDTLS_MD_CAN_RIPEMD160)
 const mbedtls_md_info_t mbedtls_ripemd160_info = {
     "RIPEMD160",
     MBEDTLS_MD_RIPEMD160,
@@ -78,7 +83,7 @@
 };
 #endif
 
-#if defined(MBEDTLS_SHA1_C)
+#if defined(MBEDTLS_MD_CAN_SHA1)
 const mbedtls_md_info_t mbedtls_sha1_info = {
     "SHA1",
     MBEDTLS_MD_SHA1,
@@ -87,7 +92,7 @@
 };
 #endif
 
-#if defined(MBEDTLS_SHA224_C)
+#if defined(MBEDTLS_MD_CAN_SHA224)
 const mbedtls_md_info_t mbedtls_sha224_info = {
     "SHA224",
     MBEDTLS_MD_SHA224,
@@ -96,7 +101,7 @@
 };
 #endif
 
-#if defined(MBEDTLS_SHA256_C)
+#if defined(MBEDTLS_MD_CAN_SHA256)
 const mbedtls_md_info_t mbedtls_sha256_info = {
     "SHA256",
     MBEDTLS_MD_SHA256,
@@ -105,7 +110,7 @@
 };
 #endif
 
-#if defined(MBEDTLS_SHA384_C)
+#if defined(MBEDTLS_MD_CAN_SHA384)
 const mbedtls_md_info_t mbedtls_sha384_info = {
     "SHA384",
     MBEDTLS_MD_SHA384,
@@ -114,7 +119,7 @@
 };
 #endif
 
-#if defined(MBEDTLS_SHA512_C)
+#if defined(MBEDTLS_MD_CAN_SHA512)
 const mbedtls_md_info_t mbedtls_sha512_info = {
     "SHA512",
     MBEDTLS_MD_SHA512,
@@ -126,31 +131,31 @@
 const mbedtls_md_info_t *mbedtls_md_info_from_type(mbedtls_md_type_t md_type)
 {
     switch (md_type) {
-#if defined(MBEDTLS_MD5_C)
+#if defined(MBEDTLS_MD_CAN_MD5)
         case MBEDTLS_MD_MD5:
             return &mbedtls_md5_info;
 #endif
-#if defined(MBEDTLS_RIPEMD160_C)
+#if defined(MBEDTLS_MD_CAN_RIPEMD160)
         case MBEDTLS_MD_RIPEMD160:
             return &mbedtls_ripemd160_info;
 #endif
-#if defined(MBEDTLS_SHA1_C)
+#if defined(MBEDTLS_MD_CAN_SHA1)
         case MBEDTLS_MD_SHA1:
             return &mbedtls_sha1_info;
 #endif
-#if defined(MBEDTLS_SHA224_C)
+#if defined(MBEDTLS_MD_CAN_SHA224)
         case MBEDTLS_MD_SHA224:
             return &mbedtls_sha224_info;
 #endif
-#if defined(MBEDTLS_SHA256_C)
+#if defined(MBEDTLS_MD_CAN_SHA256)
         case MBEDTLS_MD_SHA256:
             return &mbedtls_sha256_info;
 #endif
-#if defined(MBEDTLS_SHA384_C)
+#if defined(MBEDTLS_MD_CAN_SHA384)
         case MBEDTLS_MD_SHA384:
             return &mbedtls_sha384_info;
 #endif
-#if defined(MBEDTLS_SHA512_C)
+#if defined(MBEDTLS_MD_CAN_SHA512)
         case MBEDTLS_MD_SHA512:
             return &mbedtls_sha512_info;
 #endif
@@ -159,8 +164,71 @@
     }
 }
 
+#if defined(MBEDTLS_MD_SOME_PSA)
+static psa_algorithm_t psa_alg_of_md(const mbedtls_md_info_t *info)
+{
+    switch (info->type) {
+#if defined(MBEDTLS_MD_MD5_VIA_PSA)
+        case MBEDTLS_MD_MD5:
+            return PSA_ALG_MD5;
+#endif
+#if defined(MBEDTLS_MD_RIPEMD160_VIA_PSA)
+        case MBEDTLS_MD_RIPEMD160:
+            return PSA_ALG_RIPEMD160;
+#endif
+#if defined(MBEDTLS_MD_SHA1_VIA_PSA)
+        case MBEDTLS_MD_SHA1:
+            return PSA_ALG_SHA_1;
+#endif
+#if defined(MBEDTLS_MD_SHA224_VIA_PSA)
+        case MBEDTLS_MD_SHA224:
+            return PSA_ALG_SHA_224;
+#endif
+#if defined(MBEDTLS_MD_SHA256_VIA_PSA)
+        case MBEDTLS_MD_SHA256:
+            return PSA_ALG_SHA_256;
+#endif
+#if defined(MBEDTLS_MD_SHA384_VIA_PSA)
+        case MBEDTLS_MD_SHA384:
+            return PSA_ALG_SHA_384;
+#endif
+#if defined(MBEDTLS_MD_SHA512_VIA_PSA)
+        case MBEDTLS_MD_SHA512:
+            return PSA_ALG_SHA_512;
+#endif
+        default:
+            return PSA_ALG_NONE;
+    }
+}
+
+static int md_can_use_psa(const mbedtls_md_info_t *info)
+{
+    psa_algorithm_t alg = psa_alg_of_md(info);
+    if (alg == PSA_ALG_NONE) {
+        return 0;
+    }
+
+    return psa_can_do_hash(alg);
+}
+
+static int mbedtls_md_error_from_psa(psa_status_t status)
+{
+    switch (status) {
+        case PSA_SUCCESS:
+            return 0;
+        case PSA_ERROR_NOT_SUPPORTED:
+            return MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE;
+        case PSA_ERROR_INSUFFICIENT_MEMORY:
+            return MBEDTLS_ERR_MD_ALLOC_FAILED;
+        default:
+            return MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED;
+    }
+}
+#endif /* MBEDTLS_MD_SOME_PSA */
+
 void mbedtls_md_init(mbedtls_md_context_t *ctx)
 {
+    /* Note: this sets engine (if present) to MBEDTLS_MD_ENGINE_LEGACY */
     memset(ctx, 0, sizeof(mbedtls_md_context_t));
 }
 
@@ -171,6 +239,11 @@
     }
 
     if (ctx->md_ctx != NULL) {
+#if defined(MBEDTLS_MD_SOME_PSA)
+        if (ctx->engine == MBEDTLS_MD_ENGINE_PSA) {
+            psa_hash_abort(ctx->md_ctx);
+        } else
+#endif
         switch (ctx->md_info->type) {
 #if defined(MBEDTLS_MD5_C)
             case MBEDTLS_MD_MD5:
@@ -214,11 +287,13 @@
         mbedtls_free(ctx->md_ctx);
     }
 
+#if defined(MBEDTLS_MD_C)
     if (ctx->hmac_ctx != NULL) {
         mbedtls_platform_zeroize(ctx->hmac_ctx,
                                  2 * ctx->md_info->block_size);
         mbedtls_free(ctx->hmac_ctx);
     }
+#endif
 
     mbedtls_platform_zeroize(ctx, sizeof(mbedtls_md_context_t));
 }
@@ -232,6 +307,21 @@
         return MBEDTLS_ERR_MD_BAD_INPUT_DATA;
     }
 
+#if defined(MBEDTLS_MD_SOME_PSA)
+    if (src->engine != dst->engine) {
+        /* This can happen with src set to legacy because PSA wasn't ready
+         * yet, and dst to PSA because it became ready in the meantime.
+         * We currently don't support that case (we'd need to re-allocate
+         * md_ctx to the size of the appropriate MD context). */
+        return MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE;
+    }
+
+    if (src->engine == MBEDTLS_MD_ENGINE_PSA) {
+        psa_status_t status = psa_hash_clone(src->md_ctx, dst->md_ctx);
+        return mbedtls_md_error_from_psa(status);
+    }
+#endif
+
     switch (src->md_info->type) {
 #if defined(MBEDTLS_MD5_C)
         case MBEDTLS_MD_MD5:
@@ -292,8 +382,23 @@
 
     ctx->md_info = md_info;
     ctx->md_ctx = NULL;
+#if defined(MBEDTLS_MD_C)
     ctx->hmac_ctx = NULL;
+#else
+    if (hmac != 0) {
+        return MBEDTLS_ERR_MD_BAD_INPUT_DATA;
+    }
+#endif
 
+#if defined(MBEDTLS_MD_SOME_PSA)
+    if (md_can_use_psa(ctx->md_info)) {
+        ctx->md_ctx = mbedtls_calloc(1, sizeof(psa_hash_operation_t));
+        if (ctx->md_ctx == NULL) {
+            return MBEDTLS_ERR_MD_ALLOC_FAILED;
+        }
+        ctx->engine = MBEDTLS_MD_ENGINE_PSA;
+    } else
+#endif
     switch (md_info->type) {
 #if defined(MBEDTLS_MD5_C)
         case MBEDTLS_MD_MD5:
@@ -334,6 +439,7 @@
             return MBEDTLS_ERR_MD_BAD_INPUT_DATA;
     }
 
+#if defined(MBEDTLS_MD_C)
     if (hmac != 0) {
         ctx->hmac_ctx = mbedtls_calloc(2, md_info->block_size);
         if (ctx->hmac_ctx == NULL) {
@@ -341,6 +447,7 @@
             return MBEDTLS_ERR_MD_ALLOC_FAILED;
         }
     }
+#endif
 
     return 0;
 }
@@ -352,6 +459,15 @@
         return MBEDTLS_ERR_MD_BAD_INPUT_DATA;
     }
 
+#if defined(MBEDTLS_MD_SOME_PSA)
+    if (ctx->engine == MBEDTLS_MD_ENGINE_PSA) {
+        psa_algorithm_t alg = psa_alg_of_md(ctx->md_info);
+        psa_hash_abort(ctx->md_ctx);
+        psa_status_t status = psa_hash_setup(ctx->md_ctx, alg);
+        return mbedtls_md_error_from_psa(status);
+    }
+#endif
+
     switch (ctx->md_info->type) {
 #if defined(MBEDTLS_MD5_C)
         case MBEDTLS_MD_MD5:
@@ -392,6 +508,13 @@
         return MBEDTLS_ERR_MD_BAD_INPUT_DATA;
     }
 
+#if defined(MBEDTLS_MD_SOME_PSA)
+    if (ctx->engine == MBEDTLS_MD_ENGINE_PSA) {
+        psa_status_t status = psa_hash_update(ctx->md_ctx, input, ilen);
+        return mbedtls_md_error_from_psa(status);
+    }
+#endif
+
     switch (ctx->md_info->type) {
 #if defined(MBEDTLS_MD5_C)
         case MBEDTLS_MD_MD5:
@@ -432,6 +555,15 @@
         return MBEDTLS_ERR_MD_BAD_INPUT_DATA;
     }
 
+#if defined(MBEDTLS_MD_SOME_PSA)
+    if (ctx->engine == MBEDTLS_MD_ENGINE_PSA) {
+        size_t size = ctx->md_info->size;
+        psa_status_t status = psa_hash_finish(ctx->md_ctx,
+                                              output, size, &size);
+        return mbedtls_md_error_from_psa(status);
+    }
+#endif
+
     switch (ctx->md_info->type) {
 #if defined(MBEDTLS_MD5_C)
         case MBEDTLS_MD_MD5:
@@ -473,6 +605,16 @@
         return MBEDTLS_ERR_MD_BAD_INPUT_DATA;
     }
 
+#if defined(MBEDTLS_MD_SOME_PSA)
+    if (md_can_use_psa(md_info)) {
+        size_t size = md_info->size;
+        psa_status_t status = psa_hash_compute(psa_alg_of_md(md_info),
+                                               input, ilen,
+                                               output, size, &size);
+        return mbedtls_md_error_from_psa(status);
+    }
+#endif
+
     switch (md_info->type) {
 #if defined(MBEDTLS_MD5_C)
         case MBEDTLS_MD_MD5:
@@ -536,30 +678,30 @@
  */
 static const int supported_digests[] = {
 
-#if defined(MBEDTLS_SHA512_C)
+#if defined(MBEDTLS_MD_CAN_SHA512)
     MBEDTLS_MD_SHA512,
 #endif
 
-#if defined(MBEDTLS_SHA384_C)
+#if defined(MBEDTLS_MD_CAN_SHA384)
     MBEDTLS_MD_SHA384,
 #endif
 
-#if defined(MBEDTLS_SHA256_C)
+#if defined(MBEDTLS_MD_CAN_SHA256)
     MBEDTLS_MD_SHA256,
 #endif
-#if defined(MBEDTLS_SHA224_C)
+#if defined(MBEDTLS_MD_CAN_SHA224)
     MBEDTLS_MD_SHA224,
 #endif
 
-#if defined(MBEDTLS_SHA1_C)
+#if defined(MBEDTLS_MD_CAN_SHA1)
     MBEDTLS_MD_SHA1,
 #endif
 
-#if defined(MBEDTLS_RIPEMD160_C)
+#if defined(MBEDTLS_MD_CAN_RIPEMD160)
     MBEDTLS_MD_RIPEMD160,
 #endif
 
-#if defined(MBEDTLS_MD5_C)
+#if defined(MBEDTLS_MD_CAN_MD5)
     MBEDTLS_MD_MD5,
 #endif
 
@@ -578,37 +720,37 @@
     }
 
     /* Get the appropriate digest information */
-#if defined(MBEDTLS_MD5_C)
+#if defined(MBEDTLS_MD_CAN_MD5)
     if (!strcmp("MD5", md_name)) {
         return mbedtls_md_info_from_type(MBEDTLS_MD_MD5);
     }
 #endif
-#if defined(MBEDTLS_RIPEMD160_C)
+#if defined(MBEDTLS_MD_CAN_RIPEMD160)
     if (!strcmp("RIPEMD160", md_name)) {
         return mbedtls_md_info_from_type(MBEDTLS_MD_RIPEMD160);
     }
 #endif
-#if defined(MBEDTLS_SHA1_C)
+#if defined(MBEDTLS_MD_CAN_SHA1)
     if (!strcmp("SHA1", md_name) || !strcmp("SHA", md_name)) {
         return mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
     }
 #endif
-#if defined(MBEDTLS_SHA224_C)
+#if defined(MBEDTLS_MD_CAN_SHA224)
     if (!strcmp("SHA224", md_name)) {
         return mbedtls_md_info_from_type(MBEDTLS_MD_SHA224);
     }
 #endif
-#if defined(MBEDTLS_SHA256_C)
+#if defined(MBEDTLS_MD_CAN_SHA256)
     if (!strcmp("SHA256", md_name)) {
         return mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
     }
 #endif
-#if defined(MBEDTLS_SHA384_C)
+#if defined(MBEDTLS_MD_CAN_SHA384)
     if (!strcmp("SHA384", md_name)) {
         return mbedtls_md_info_from_type(MBEDTLS_MD_SHA384);
     }
 #endif
-#if defined(MBEDTLS_SHA512_C)
+#if defined(MBEDTLS_MD_CAN_SHA512)
     if (!strcmp("SHA512", md_name)) {
         return mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
     }
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index ba204f7..46938ea 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -111,6 +111,7 @@
 typedef struct {
     unsigned initialized : 1;
     unsigned rng_state : 2;
+    unsigned drivers_initialized : 1;
     mbedtls_psa_random_context_t rng;
 } psa_global_data_t;
 
@@ -125,6 +126,12 @@
     if (global_data.initialized == 0)  \
     return PSA_ERROR_BAD_STATE;
 
+int psa_can_do_hash(psa_algorithm_t hash_alg)
+{
+    (void) hash_alg;
+    return global_data.drivers_initialized;
+}
+
 psa_status_t mbedtls_to_psa_error(int ret)
 {
     /* Mbed TLS error codes can combine a high-level error code and a
@@ -7124,6 +7131,13 @@
         return PSA_SUCCESS;
     }
 
+    /* Init drivers */
+    status = psa_driver_wrapper_init();
+    if (status != PSA_SUCCESS) {
+        goto exit;
+    }
+    global_data.drivers_initialized = 1;
+
     /* Initialize and seed the random generator. */
     mbedtls_psa_random_init(&global_data.rng);
     global_data.rng_state = RNG_INITIALIZED;
@@ -7138,12 +7152,6 @@
         goto exit;
     }
 
-    /* Init drivers */
-    status = psa_driver_wrapper_init();
-    if (status != PSA_SUCCESS) {
-        goto exit;
-    }
-
 #if defined(PSA_CRYPTO_STORAGE_HAS_TRANSACTIONS)
     status = psa_crypto_load_transaction();
     if (status == PSA_SUCCESS) {
diff --git a/library/psa_crypto_core.h b/library/psa_crypto_core.h
index d3d0188..8bc1b64 100644
--- a/library/psa_crypto_core.h
+++ b/library/psa_crypto_core.h
@@ -26,6 +26,18 @@
 #include "psa/crypto.h"
 #include "psa/crypto_se_driver.h"
 
+/**
+ * Tell if PSA is ready for this hash.
+ *
+ * \note            For now, only checks the state of the driver subsystem,
+ *                  not the algorithm. Might do more in the future.
+ *
+ * \param hash_alg  The hash algorithm (ignored for now).
+ *
+ * \return 1 if the driver subsytem is ready, 0 otherwise.
+ */
+int psa_can_do_hash(psa_algorithm_t hash_alg);
+
 /** Constant-time buffer comparison
  *
  * \param[in]  a    Left-hand buffer for comparison.
diff --git a/tests/include/test/psa_crypto_helpers.h b/tests/include/test/psa_crypto_helpers.h
index ac6eb20..38a60b4 100644
--- a/tests/include/test/psa_crypto_helpers.h
+++ b/tests/include/test/psa_crypto_helpers.h
@@ -24,15 +24,43 @@
 #include "test/helpers.h"
 
 #if defined(MBEDTLS_PSA_CRYPTO_C)
-
 #include "test/psa_helpers.h"
-
 #include <psa/crypto.h>
+#endif
 
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
 #include "mbedtls/psa_util.h"
 #endif
 
+#if defined(MBEDTLS_PSA_CRYPTO_C)
+/** Initialize the PSA Crypto subsystem. */
+#define PSA_INIT() PSA_ASSERT(psa_crypto_init())
+
+/** Shut down the PSA Crypto subsystem and destroy persistent keys.
+ * Expect a clean shutdown, with no slots in use.
+ *
+ * If some key slots are still in use, record the test case as failed,
+ * but continue executing. This macro is suitable (and primarily intended)
+ * for use in the cleanup section of test functions.
+ *
+ * \note Persistent keys must be recorded with #TEST_USES_KEY_ID before
+ *       creating them.
+ */
+#define PSA_DONE()                                                      \
+    do                                                                  \
+    {                                                                   \
+        mbedtls_test_fail_if_psa_leaking(__LINE__, __FILE__);           \
+        mbedtls_test_psa_purge_key_storage();                           \
+        mbedtls_psa_crypto_free();                                      \
+    }                                                                   \
+    while (0)
+#else /*MBEDTLS_PSA_CRYPTO_C */
+#define PSA_INIT() ((void) 0)
+#define PSA_DONE() ((void) 0)
+#endif /* MBEDTLS_PSA_CRYPTO_C */
+
+#if defined(MBEDTLS_PSA_CRYPTO_C)
+
 #if defined(MBEDTLS_PSA_CRYPTO_STORAGE_C)
 
 /* Internal function for #TEST_USES_KEY_ID. Return 1 on success, 0 on failure. */
@@ -86,8 +114,6 @@
 
 #endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C */
 
-#define PSA_INIT() PSA_ASSERT(psa_crypto_init())
-
 /** Check for things that have not been cleaned up properly in the
  * PSA subsystem.
  *
@@ -112,25 +138,6 @@
     }                                                                   \
     while (0)
 
-/** Shut down the PSA Crypto subsystem and destroy persistent keys.
- * Expect a clean shutdown, with no slots in use.
- *
- * If some key slots are still in use, record the test case as failed,
- * but continue executing. This macro is suitable (and primarily intended)
- * for use in the cleanup section of test functions.
- *
- * \note Persistent keys must be recorded with #TEST_USES_KEY_ID before
- *       creating them.
- */
-#define PSA_DONE()                                                      \
-    do                                                                  \
-    {                                                                   \
-        mbedtls_test_fail_if_psa_leaking(__LINE__, __FILE__);           \
-        mbedtls_test_psa_purge_key_storage();                           \
-        mbedtls_psa_crypto_free();                                      \
-    }                                                                   \
-    while (0)
-
 /** Shut down the PSA Crypto subsystem, allowing persistent keys to survive.
  * Expect a clean shutdown, with no slots in use.
  *
@@ -295,6 +302,7 @@
 #define PSA_INIT_IF_NO_MD() ((void) 0)
 #define PSA_DONE_IF_NO_MD() ((void) 0)
 #endif
+
 /** \def USE_PSA_INIT
  *
  * Call this macro to initialize the PSA subsystem if #MBEDTLS_USE_PSA_CRYPTO
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index b76ba57..d444cba 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -2062,12 +2062,12 @@
     scripts/config.py -f include/psa/crypto_config.h unset PSA_WANT_ALG_STREAM_CIPHER
     scripts/config.py -f include/psa/crypto_config.h unset PSA_WANT_ALG_ECB_NO_PADDING
 
-    # These hashes are needed for some ECDSA signature tests.
-    scripts/config.py -f tests/include/test/drivers/config_test_driver.h set MBEDTLS_SHA224_C
-    scripts/config.py -f tests/include/test/drivers/config_test_driver.h set MBEDTLS_SHA384_C
-    scripts/config.py -f tests/include/test/drivers/config_test_driver.h set MBEDTLS_SHA512_C
-
     loc_accel_flags=$( echo "$loc_accel_list" | sed 's/[^ ]* */-DLIBTESTDRIVER1_MBEDTLS_PSA_ACCEL_&/g' )
+    # These hashes are needed for some ECDSA signature tests.
+    loc_accel_flags="$loc_accel_flags -DLIBTESTDRIVER1_MBEDTLS_PSA_ACCEL_ALG_SHA_224"
+    loc_accel_flags="$loc_accel_flags -DLIBTESTDRIVER1_MBEDTLS_PSA_ACCEL_ALG_SHA_256"
+    loc_accel_flags="$loc_accel_flags -DLIBTESTDRIVER1_MBEDTLS_PSA_ACCEL_ALG_SHA_384"
+    loc_accel_flags="$loc_accel_flags -DLIBTESTDRIVER1_MBEDTLS_PSA_ACCEL_ALG_SHA_512"
     make -C tests libtestdriver1.a CFLAGS="$ASAN_CFLAGS $loc_accel_flags" LDFLAGS="$ASAN_CFLAGS"
 
     # Configure and build the main libraries
@@ -2135,14 +2135,13 @@
     scripts/config.py -f include/psa/crypto_config.h unset PSA_WANT_ALG_STREAM_CIPHER
     scripts/config.py -f include/psa/crypto_config.h unset PSA_WANT_ALG_ECB_NO_PADDING
 
-    # SHA-1 and all variants of SHA-2 are needed for ECDSA and X.509 tests,
-    # but only SHA-256 is enabled by default, so enable the others.
-    scripts/config.py -f tests/include/test/drivers/config_test_driver.h set MBEDTLS_SHA1_C
-    scripts/config.py -f tests/include/test/drivers/config_test_driver.h set MBEDTLS_SHA224_C
-    scripts/config.py -f tests/include/test/drivers/config_test_driver.h set MBEDTLS_SHA384_C
-    scripts/config.py -f tests/include/test/drivers/config_test_driver.h set MBEDTLS_SHA512_C
-
     loc_accel_flags=$( echo "$loc_accel_list" | sed 's/[^ ]* */-DLIBTESTDRIVER1_MBEDTLS_PSA_ACCEL_&/g' )
+    # SHA-1 and all variants of SHA-2 are needed for ECDSA and X.509 tests
+    loc_accel_flags="$loc_accel_flags -DLIBTESTDRIVER1_MBEDTLS_PSA_ACCEL_ALG_SHA_1"
+    loc_accel_flags="$loc_accel_flags -DLIBTESTDRIVER1_MBEDTLS_PSA_ACCEL_ALG_SHA_224"
+    loc_accel_flags="$loc_accel_flags -DLIBTESTDRIVER1_MBEDTLS_PSA_ACCEL_ALG_SHA_256"
+    loc_accel_flags="$loc_accel_flags -DLIBTESTDRIVER1_MBEDTLS_PSA_ACCEL_ALG_SHA_384"
+    loc_accel_flags="$loc_accel_flags -DLIBTESTDRIVER1_MBEDTLS_PSA_ACCEL_ALG_SHA_512"
     make -C tests libtestdriver1.a CFLAGS="$ASAN_CFLAGS $loc_accel_flags" LDFLAGS="$ASAN_CFLAGS"
 
     # Configure and build the main libraries with drivers enabled
@@ -2364,14 +2363,10 @@
     #   PSA_ALG_ANY_HASH as algorithm to test with the key, the chosen hash
     #   algorithm based on the hashes supported by the library is also
     #   supported by the test library.
+    # Disabled unwanted hashes here, we'll enable hashes we want in loc_accel_flags.
     scripts/config.py -f include/psa/crypto_config.h unset PSA_WANT_ALG_MD5
     scripts/config.py -f include/psa/crypto_config.h unset PSA_WANT_ALG_RIPEMD160_C
 
-    scripts/config.py -f tests/include/test/drivers/config_test_driver.h set MBEDTLS_SHA1_C
-    scripts/config.py -f tests/include/test/drivers/config_test_driver.h set MBEDTLS_SHA224_C
-    scripts/config.py -f tests/include/test/drivers/config_test_driver.h set MBEDTLS_SHA512_C
-    # We need to define either MD_C or all of the PSA_WANT_ALG_SHAxxx.
-    scripts/config.py -f tests/include/test/drivers/config_test_driver.h set MBEDTLS_MD_C
     # We need PEM parsing in the test library as well to support the import
     # of PEM encoded RSA keys.
     scripts/config.py -f tests/include/test/drivers/config_test_driver.h set MBEDTLS_PEM_PARSE_C
@@ -2379,6 +2374,12 @@
 
     loc_accel_list="ALG_RSA_PKCS1V15_SIGN ALG_RSA_PSS KEY_TYPE_RSA_KEY_PAIR KEY_TYPE_RSA_PUBLIC_KEY"
     loc_accel_flags=$( echo "$loc_accel_list" | sed 's/[^ ]* */-DLIBTESTDRIVER1_MBEDTLS_PSA_ACCEL_&/g' )
+    # These hashes are needed for some RSA-PSS signature tests.
+    loc_accel_flags="$loc_accel_flags -DLIBTESTDRIVER1_MBEDTLS_PSA_ACCEL_ALG_SHA_1"
+    loc_accel_flags="$loc_accel_flags -DLIBTESTDRIVER1_MBEDTLS_PSA_ACCEL_ALG_SHA_224"
+    loc_accel_flags="$loc_accel_flags -DLIBTESTDRIVER1_MBEDTLS_PSA_ACCEL_ALG_SHA_256"
+    loc_accel_flags="$loc_accel_flags -DLIBTESTDRIVER1_MBEDTLS_PSA_ACCEL_ALG_SHA_384"
+    loc_accel_flags="$loc_accel_flags -DLIBTESTDRIVER1_MBEDTLS_PSA_ACCEL_ALG_SHA_512"
     make -C tests libtestdriver1.a CFLAGS="$ASAN_CFLAGS $loc_accel_flags" LDFLAGS="$ASAN_CFLAGS"
 
     # Mbed TLS library build
@@ -2442,6 +2443,29 @@
     make test
 }
 
+component_test_psa_crypto_config_accel_hash_keep_builtins () {
+    msg "test: MBEDTLS_PSA_CRYPTO_CONFIG with accelerated+builtin hash"
+    # This component ensures that all the test cases for
+    # md_psa_dynamic_dispatch with legacy+driver in test_suite_md are run.
+
+    # Disable ALG_STREAM_CIPHER and ALG_ECB_NO_PADDING to avoid having
+    # partial support for cipher operations in the driver test library.
+    scripts/config.py -f include/psa/crypto_config.h unset PSA_WANT_ALG_STREAM_CIPHER
+    scripts/config.py -f include/psa/crypto_config.h unset PSA_WANT_ALG_ECB_NO_PADDING
+
+    loc_accel_list="ALG_MD5 ALG_RIPEMD160 ALG_SHA_1 ALG_SHA_224 ALG_SHA_256 ALG_SHA_384 ALG_SHA_512"
+    loc_accel_flags=$( echo "$loc_accel_list" | sed 's/[^ ]* */-DLIBTESTDRIVER1_MBEDTLS_PSA_ACCEL_&/g' )
+    make -C tests libtestdriver1.a CFLAGS="$ASAN_CFLAGS $loc_accel_flags" LDFLAGS="$ASAN_CFLAGS"
+
+    scripts/config.py set MBEDTLS_PSA_CRYPTO_DRIVERS
+    scripts/config.py set MBEDTLS_PSA_CRYPTO_CONFIG
+    loc_accel_flags="$loc_accel_flags $( echo "$loc_accel_list" | sed 's/[^ ]* */-DMBEDTLS_PSA_ACCEL_&/g' )"
+    make CFLAGS="$ASAN_CFLAGS -Werror -I../tests/include -I../tests -I../../tests -DPSA_CRYPTO_DRIVER_TEST -DMBEDTLS_TEST_LIBTESTDRIVER1 $loc_accel_flags" LDFLAGS="-ltestdriver1 $ASAN_CFLAGS"
+
+    msg "test: MBEDTLS_PSA_CRYPTO_CONFIG with accelerated+builtin hash"
+    make test
+}
+
 # Auxiliary function to build config for hashes with and without drivers
 config_psa_crypto_hash_use_psa () {
     DRIVER_ONLY="$1"
diff --git a/tests/suites/test_suite_md.data b/tests/suites/test_suite_md.data
index 79b8376..24dd39b 100644
--- a/tests/suites/test_suite_md.data
+++ b/tests/suites/test_suite_md.data
@@ -1016,3 +1016,87 @@
 generic SHA-512 Hash file #4
 depends_on:MBEDTLS_SHA512_C
 mbedtls_md_file:MBEDTLS_MD_SHA512:"data_files/hash_file_4":"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"
+
+PSA dispatch MD5 legacy only
+depends_on:MBEDTLS_MD5_C:!MBEDTLS_MD_MD5_VIA_PSA
+md_psa_dynamic_dispatch:MBEDTLS_MD_MD5:0:MBEDTLS_MD_ENGINE_LEGACY
+
+PSA dispatch MD5 driver only
+depends_on:!MBEDTLS_MD5_C:MBEDTLS_MD_MD5_VIA_PSA
+md_psa_dynamic_dispatch:MBEDTLS_MD_MD5:MBEDTLS_ERR_MD_BAD_INPUT_DATA:MBEDTLS_MD_ENGINE_PSA
+
+PSA dispatch MD5 legacy+driver
+depends_on:MBEDTLS_MD5_C:MBEDTLS_MD_MD5_VIA_PSA
+md_psa_dynamic_dispatch:MBEDTLS_MD_MD5:0:MBEDTLS_MD_ENGINE_PSA
+
+PSA dispatch RIPEMD160 legacy only
+depends_on:MBEDTLS_RIPEMD160_C:!MBEDTLS_MD_RIPEMD160_VIA_PSA
+md_psa_dynamic_dispatch:MBEDTLS_MD_RIPEMD160:0:MBEDTLS_MD_ENGINE_LEGACY
+
+PSA dispatch RIPEMD160 driver only
+depends_on:!MBEDTLS_RIPEMD160_C:MBEDTLS_MD_RIPEMD160_VIA_PSA
+md_psa_dynamic_dispatch:MBEDTLS_MD_RIPEMD160:MBEDTLS_ERR_MD_BAD_INPUT_DATA:MBEDTLS_MD_ENGINE_PSA
+
+PSA dispatch RIPEMD160 legacy+driver
+depends_on:MBEDTLS_RIPEMD160_C:MBEDTLS_MD_RIPEMD160_VIA_PSA
+md_psa_dynamic_dispatch:MBEDTLS_MD_RIPEMD160:0:MBEDTLS_MD_ENGINE_PSA
+
+PSA dispatch SHA1 legacy only
+depends_on:MBEDTLS_SHA1_C:!MBEDTLS_MD_SHA1_VIA_PSA
+md_psa_dynamic_dispatch:MBEDTLS_MD_SHA1:0:MBEDTLS_MD_ENGINE_LEGACY
+
+PSA dispatch SHA1 driver only
+depends_on:!MBEDTLS_SHA1_C:MBEDTLS_MD_SHA1_VIA_PSA
+md_psa_dynamic_dispatch:MBEDTLS_MD_SHA1:MBEDTLS_ERR_MD_BAD_INPUT_DATA:MBEDTLS_MD_ENGINE_PSA
+
+PSA dispatch SHA1 legacy+driver
+depends_on:MBEDTLS_SHA1_C:MBEDTLS_MD_SHA1_VIA_PSA
+md_psa_dynamic_dispatch:MBEDTLS_MD_SHA1:0:MBEDTLS_MD_ENGINE_PSA
+
+PSA dispatch SHA224 legacy only
+depends_on:MBEDTLS_SHA224_C:!MBEDTLS_MD_SHA224_VIA_PSA
+md_psa_dynamic_dispatch:MBEDTLS_MD_SHA224:0:MBEDTLS_MD_ENGINE_LEGACY
+
+PSA dispatch SHA224 driver only
+depends_on:!MBEDTLS_SHA224_C:MBEDTLS_MD_SHA224_VIA_PSA
+md_psa_dynamic_dispatch:MBEDTLS_MD_SHA224:MBEDTLS_ERR_MD_BAD_INPUT_DATA:MBEDTLS_MD_ENGINE_PSA
+
+PSA dispatch SHA224 legacy+driver
+depends_on:MBEDTLS_SHA224_C:MBEDTLS_MD_SHA224_VIA_PSA
+md_psa_dynamic_dispatch:MBEDTLS_MD_SHA224:0:MBEDTLS_MD_ENGINE_PSA
+
+PSA dispatch SHA256 legacy only
+depends_on:MBEDTLS_SHA256_C:!MBEDTLS_MD_SHA256_VIA_PSA
+md_psa_dynamic_dispatch:MBEDTLS_MD_SHA256:0:MBEDTLS_MD_ENGINE_LEGACY
+
+PSA dispatch SHA256 driver only
+depends_on:!MBEDTLS_SHA256_C:MBEDTLS_MD_SHA256_VIA_PSA
+md_psa_dynamic_dispatch:MBEDTLS_MD_SHA256:MBEDTLS_ERR_MD_BAD_INPUT_DATA:MBEDTLS_MD_ENGINE_PSA
+
+PSA dispatch SHA256 legacy+driver
+depends_on:MBEDTLS_SHA256_C:MBEDTLS_MD_SHA256_VIA_PSA
+md_psa_dynamic_dispatch:MBEDTLS_MD_SHA256:0:MBEDTLS_MD_ENGINE_PSA
+
+PSA dispatch SHA384 legacy only
+depends_on:MBEDTLS_SHA384_C:!MBEDTLS_MD_SHA384_VIA_PSA
+md_psa_dynamic_dispatch:MBEDTLS_MD_SHA384:0:MBEDTLS_MD_ENGINE_LEGACY
+
+PSA dispatch SHA384 driver only
+depends_on:!MBEDTLS_SHA384_C:MBEDTLS_MD_SHA384_VIA_PSA
+md_psa_dynamic_dispatch:MBEDTLS_MD_SHA384:MBEDTLS_ERR_MD_BAD_INPUT_DATA:MBEDTLS_MD_ENGINE_PSA
+
+PSA dispatch SHA384 legacy+driver
+depends_on:MBEDTLS_SHA384_C:MBEDTLS_MD_SHA384_VIA_PSA
+md_psa_dynamic_dispatch:MBEDTLS_MD_SHA384:0:MBEDTLS_MD_ENGINE_PSA
+
+PSA dispatch SHA512 legacy only
+depends_on:MBEDTLS_SHA512_C:!MBEDTLS_MD_SHA512_VIA_PSA
+md_psa_dynamic_dispatch:MBEDTLS_MD_SHA512:0:MBEDTLS_MD_ENGINE_LEGACY
+
+PSA dispatch SHA512 driver only
+depends_on:!MBEDTLS_SHA512_C:MBEDTLS_MD_SHA512_VIA_PSA
+md_psa_dynamic_dispatch:MBEDTLS_MD_SHA512:MBEDTLS_ERR_MD_BAD_INPUT_DATA:MBEDTLS_MD_ENGINE_PSA
+
+PSA dispatch SHA512 legacy+driver
+depends_on:MBEDTLS_SHA512_C:MBEDTLS_MD_SHA512_VIA_PSA
+md_psa_dynamic_dispatch:MBEDTLS_MD_SHA512:0:MBEDTLS_MD_ENGINE_PSA
diff --git a/tests/suites/test_suite_md.function b/tests/suites/test_suite_md.function
index 1e8622b..64a4171 100644
--- a/tests/suites/test_suite_md.function
+++ b/tests/suites/test_suite_md.function
@@ -1,5 +1,13 @@
 /* BEGIN_HEADER */
 #include "mbedtls/md.h"
+
+#if defined(MBEDTLS_MD_SOME_PSA)
+#define MD_PSA_INIT()   PSA_INIT()
+#define MD_PSA_DONE()   PSA_DONE()
+#else /* MBEDTLS_MD_SOME_PSA */
+#define MD_PSA_INIT() ((void) 0)
+#define MD_PSA_DONE() ((void) 0)
+#endif /* MBEDTLS_MD_SOME_PSA */
 /* END_HEADER */
 
 /* BEGIN_DEPENDENCIES
@@ -15,6 +23,7 @@
     mbedtls_md_context_t ctx;
     unsigned char out[MBEDTLS_MD_MAX_SIZE] = { 0 };
 
+    MD_PSA_INIT();
     mbedtls_md_init(&ctx);
 
     /*
@@ -31,6 +40,7 @@
 
 exit:
     mbedtls_md_free(&ctx);
+    MD_PSA_DONE();
 }
 /* END_CASE */
 
@@ -43,6 +53,7 @@
 #endif
     unsigned char buf[1] = { 0 };
 
+    MD_PSA_INIT();
     mbedtls_md_init(&ctx);
 
     TEST_EQUAL(0, mbedtls_md_get_size(NULL));
@@ -101,6 +112,9 @@
 #if defined(MBEDTLS_MD_C)
     TEST_ASSERT(mbedtls_md_info_from_string("no such md") == NULL);
 #endif
+
+exit:
+    MD_PSA_DONE();
 }
 /* END_CASE */
 
@@ -114,6 +128,8 @@
     (void) md_name;
 #endif
 
+    /* Note: PSA Crypto init not needed to info functions */
+
     md_info = mbedtls_md_info_from_type(md_type);
     TEST_ASSERT(md_info != NULL);
 #if defined(MBEDTLS_MD_C)
@@ -144,12 +160,17 @@
     unsigned char output[MBEDTLS_MD_MAX_SIZE] = { 0 };
     const mbedtls_md_info_t *md_info = NULL;
 
+    MD_PSA_INIT();
+
     md_info = mbedtls_md_info_from_type(md_type);
     TEST_ASSERT(md_info != NULL);
 
     TEST_EQUAL(0, mbedtls_md(md_info, src, src_len, output));
 
     ASSERT_COMPARE(output, mbedtls_md_get_size(md_info), hash->x, hash->len);
+
+exit:
+    MD_PSA_DONE();
 }
 /* END_CASE */
 
@@ -159,6 +180,8 @@
     unsigned char output[MBEDTLS_MD_MAX_SIZE] = { 0 };
     const mbedtls_md_info_t *md_info = NULL;
 
+    MD_PSA_INIT();
+
     md_info = mbedtls_md_info_from_type(md_type);
     TEST_ASSERT(md_info != NULL);
 
@@ -166,6 +189,9 @@
 
 
     ASSERT_COMPARE(output, mbedtls_md_get_size(md_info), hash->x, hash->len);
+
+exit:
+    MD_PSA_DONE();
 }
 /* END_CASE */
 
@@ -181,6 +207,8 @@
     const mbedtls_md_info_t *md_info = NULL;
     mbedtls_md_context_t ctx, ctx_copy;
 
+    MD_PSA_INIT();
+
     mbedtls_md_init(&ctx);
     mbedtls_md_init(&ctx_copy);
 
@@ -214,6 +242,7 @@
 exit:
     mbedtls_md_free(&ctx);
     mbedtls_md_free(&ctx_copy);
+    MD_PSA_DONE();
 }
 /* END_CASE */
 
@@ -225,6 +254,8 @@
     mbedtls_md_context_t ctx, ctx_copy;
     int halfway;
 
+    MD_PSA_INIT();
+
     mbedtls_md_init(&ctx);
     mbedtls_md_init(&ctx_copy);
 
@@ -258,6 +289,7 @@
 exit:
     mbedtls_md_free(&ctx);
     mbedtls_md_free(&ctx_copy);
+    MD_PSA_DONE();
 }
 /* END_CASE */
 
@@ -269,6 +301,8 @@
     unsigned char output[MBEDTLS_MD_MAX_SIZE] = { 0 };
     const mbedtls_md_info_t *md_info = NULL;
 
+    MD_PSA_INIT();
+
     md_info = mbedtls_md_info_from_type(md_type);
     TEST_ASSERT(md_info != NULL);
 
@@ -277,6 +311,9 @@
                                   src_str->x, src_str->len, output));
 
     ASSERT_COMPARE(output, trunc_size, hash->x, hash->len);
+
+exit:
+    MD_PSA_DONE();
 }
 /* END_CASE */
 
@@ -289,6 +326,8 @@
     mbedtls_md_context_t ctx;
     int halfway;
 
+    MD_PSA_INIT();
+
     mbedtls_md_init(&ctx);
 
     md_info = mbedtls_md_info_from_type(md_type);
@@ -320,6 +359,7 @@
 
 exit:
     mbedtls_md_free(&ctx);
+    MD_PSA_DONE();
 }
 /* END_CASE */
 
@@ -330,11 +370,65 @@
     unsigned char output[MBEDTLS_MD_MAX_SIZE] = { 0 };
     const mbedtls_md_info_t *md_info = NULL;
 
+    MD_PSA_INIT();
+
     md_info = mbedtls_md_info_from_type(md_type);
     TEST_ASSERT(md_info != NULL);
 
     TEST_EQUAL(0, mbedtls_md_file(md_info, filename, output));
 
     ASSERT_COMPARE(output, mbedtls_md_get_size(md_info), hash->x, hash->len);
+
+exit:
+    MD_PSA_DONE();
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void md_psa_dynamic_dispatch(int md_type, int pre_psa_ret, int post_psa_engine)
+{
+    const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(md_type);
+    TEST_ASSERT(md_info != NULL);
+    mbedtls_md_context_t ctx1, ctx2;
+
+    /* Intentionally no PSA init here! (Will be done later.) */
+
+    mbedtls_md_init(&ctx1);
+    mbedtls_md_init(&ctx2);
+
+    /* Before PSA crypto init */
+    TEST_EQUAL(pre_psa_ret, mbedtls_md_setup(&ctx1, md_info, 0));
+    TEST_EQUAL(pre_psa_ret, mbedtls_md_setup(&ctx2, md_info, 0));
+
+#if defined(MBEDTLS_MD_SOME_PSA)
+    TEST_EQUAL(ctx1.engine, MBEDTLS_MD_ENGINE_LEGACY);
+    TEST_EQUAL(ctx2.engine, MBEDTLS_MD_ENGINE_LEGACY);
+#endif
+
+    /* Reset ctx1 but keep ctx2 for the cloning test */
+    mbedtls_md_free(&ctx1);
+    mbedtls_md_init(&ctx1);
+
+    /* Now initilize PSA Crypto */
+    MD_PSA_INIT();
+
+    /* After PSA Crypto init */
+    TEST_EQUAL(0, mbedtls_md_setup(&ctx1, md_info, 0));
+#if defined(MBEDTLS_MD_SOME_PSA)
+    TEST_EQUAL(ctx1.engine, post_psa_engine);
+#endif
+
+    /* Cloning test */
+    if (pre_psa_ret == 0) {
+        int exp_clone_ret = post_psa_engine == MBEDTLS_MD_ENGINE_PSA
+                          ? MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE
+                          : 0;
+        TEST_EQUAL(exp_clone_ret, mbedtls_md_clone(&ctx2, &ctx1));
+    }
+
+exit:
+    mbedtls_md_free(&ctx1);
+    mbedtls_md_free(&ctx2);
+    MD_PSA_DONE();
 }
 /* END_CASE */
diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data
index eddac7f..86b2f66 100644
--- a/tests/suites/test_suite_psa_crypto.data
+++ b/tests/suites/test_suite_psa_crypto.data
@@ -1,3 +1,6 @@
+PSA can_do_hash
+psa_can_do_hash:
+
 PSA compile-time sanity checks
 static_checks:
 
diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function
index 231b47f..41a3237 100644
--- a/tests/suites/test_suite_psa_crypto.function
+++ b/tests/suites/test_suite_psa_crypto.function
@@ -13,6 +13,9 @@
 #include "psa/crypto.h"
 #include "psa_crypto_slot_management.h"
 
+/* For psa_can_do_hash() */
+#include "psa_crypto_core.h"
+
 #include "test/asn1_helpers.h"
 #include "test/psa_crypto_helpers.h"
 #include "test/psa_exercise_key.h"
@@ -1256,6 +1259,18 @@
  */
 
 /* BEGIN_CASE */
+void psa_can_do_hash()
+{
+    /* We can't test that this is specific to drivers until partial init has
+     * been implemented, but we can at least test before/after full init. */
+    TEST_EQUAL(0, psa_can_do_hash(PSA_ALG_NONE));
+    PSA_INIT();
+    TEST_EQUAL(1, psa_can_do_hash(PSA_ALG_NONE));
+    PSA_DONE();
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
 void static_checks()
 {
     size_t max_truncated_mac_size =