Define "light" subset of MD

See docs/architecture/psa-migration/md-cipher-dispatch.md

Regarding testing, the no_md component was never very useful, as that's
not something people are likely to want to do: it was mostly useful as
executable documentation of what depends on MD. It's going to be even
less useful when more and more modules auto-enable MD_LIGHT or even
MD_C. So, recycle it to test the build with only MD_LIGHT, which is
something that might happen in practice, and is necessary to ensure that
the division is consistent.

Signed-off-by: Manuel Pégourié-Gonnard <manuel.pegourie-gonnard@arm.com>
diff --git a/include/mbedtls/build_info.h b/include/mbedtls/build_info.h
index bbfd5d4..bc94acf 100644
--- a/include/mbedtls/build_info.h
+++ b/include/mbedtls/build_info.h
@@ -80,6 +80,13 @@
 #include MBEDTLS_USER_CONFIG_FILE
 #endif
 
+/* Auto-enable MBEDTLS_MD_LIGHT based on MBEDTLS_MD_C.
+ * This allows checking for MD_LIGHT rather than MD_LIGHT || MD_C.
+ */
+#if defined(MBEDTLS_MD_C)
+#define MBEDTLS_MD_LIGHT
+#endif
+
 /* The PK wrappers need pk_write functions to format RSA key objects
  * when they are dispatching to the PSA API. This happens under USE_PSA_CRYPTO,
  * and also even without USE_PSA_CRYPTO for mbedtls_pk_sign_ext().
diff --git a/include/mbedtls/mbedtls_config.h b/include/mbedtls/mbedtls_config.h
index 9ae51c9..41a007e 100644
--- a/include/mbedtls/mbedtls_config.h
+++ b/include/mbedtls/mbedtls_config.h
@@ -2643,7 +2643,7 @@
 /**
  * \def MBEDTLS_MD_C
  *
- * Enable the generic message digest layer.
+ * Enable the generic layer for message digest (hashing) and HMAC.
  *
  * Requires: one of: MBEDTLS_MD5_C, MBEDTLS_RIPEMD160_C, MBEDTLS_SHA1_C,
  *                   MBEDTLS_SHA224_C, MBEDTLS_SHA256_C, MBEDTLS_SHA384_C,
@@ -2673,6 +2673,25 @@
 #define MBEDTLS_MD_C
 
 /**
+ * \def MBEDTLS_MD_LIGHT
+ *
+ * Enable the "light" subset of MBEDTLS_MD_C: just hashing and basic
+ * meta-data.
+ *
+ * This is automatically enabled whenever MBEDTLS_MD_C is enabled, but it is
+ * possible to enable this with MBEDTLS_MD_C if support for HMAC or extra
+ * metadata functions is not needed.
+ *
+ * Requires: one of: MBEDTLS_MD5_C, MBEDTLS_RIPEMD160_C, MBEDTLS_SHA1_C,
+ *                   MBEDTLS_SHA224_C, MBEDTLS_SHA256_C, MBEDTLS_SHA384_C,
+ *                   MBEDTLS_SHA512_C.
+ * Module:  library/md.c
+ *
+ * Uncomment to enabled the "light" subsect of MD.
+ */
+#define MBEDTLS_MD_LIGHT
+
+/**
  * \def MBEDTLS_MD5_C
  *
  * Enable the MD5 hash algorithm.
diff --git a/include/mbedtls/md.h b/include/mbedtls/md.h
index bcf56a5..f9349e1 100644
--- a/include/mbedtls/md.h
+++ b/include/mbedtls/md.h
@@ -1,7 +1,15 @@
 /**
  * \file md.h
  *
- * \brief This file contains the generic message-digest wrapper.
+ * \brief   This file contains the generic functions for message-digest
+ *          (hashing) and HMAC.
+ *
+ *          Availability of function in this modules is controled by two
+ *          feature macros:
+ *          - MBEDTLS_MD_C enables the whole module;
+ *          - MBEDTLS_MD_LIGHT enables only functions for hashing an accessing
+ *          some hash metadata; is it automatically set whenever MBEDTLS_MD_C
+ *          is set.
  *
  * \author Adriaan de Jong <dejong@fox-it.com>
  */
@@ -107,6 +115,7 @@
     void *MBEDTLS_PRIVATE(hmac_ctx);
 } mbedtls_md_context_t;
 
+#if defined(MBEDTLS_MD_C)
 /**
  * \brief           This function returns the list of digests supported by the
  *                  generic digest module.
@@ -130,6 +139,7 @@
  * \return          NULL if the associated message-digest information is not found.
  */
 const mbedtls_md_info_t *mbedtls_md_info_from_string(const char *md_name);
+#endif /* MBEDTLS_MD_C */
 
 /**
  * \brief           This function returns the message-digest information
@@ -142,6 +152,7 @@
  */
 const mbedtls_md_info_t *mbedtls_md_info_from_type(mbedtls_md_type_t md_type);
 
+#if defined(MBEDTLS_MD_C)
 /**
  * \brief           This function returns the message-digest information
  *                  from the given context.
@@ -154,6 +165,7 @@
  */
 const mbedtls_md_info_t *mbedtls_md_info_from_ctx(
     const mbedtls_md_context_t *ctx);
+#endif /* MBEDTLS_MD_C */
 
 /**
  * \brief           This function initializes a message-digest context without
@@ -248,6 +260,7 @@
  */
 mbedtls_md_type_t mbedtls_md_get_type(const mbedtls_md_info_t *md_info);
 
+#if defined(MBEDTLS_MD_C)
 /**
  * \brief           This function extracts the message-digest name from the
  *                  message-digest information structure.
@@ -258,6 +271,7 @@
  * \return          The name of the message digest.
  */
 const char *mbedtls_md_get_name(const mbedtls_md_info_t *md_info);
+#endif /* MBEDTLS_MD_C */
 
 /**
  * \brief           This function starts a message-digest computation.
@@ -337,7 +351,7 @@
 int mbedtls_md(const mbedtls_md_info_t *md_info, const unsigned char *input, size_t ilen,
                unsigned char *output);
 
-#if defined(MBEDTLS_FS_IO)
+#if defined(MBEDTLS_FS_IO) && defined(MBEDTLS_MD_C)
 /**
  * \brief          This function calculates the message-digest checksum
  *                 result of the contents of the provided file.
@@ -358,8 +372,9 @@
 MBEDTLS_CHECK_RETURN_TYPICAL
 int mbedtls_md_file(const mbedtls_md_info_t *md_info, const char *path,
                     unsigned char *output);
-#endif /* MBEDTLS_FS_IO */
+#endif /* MBEDTLS_FS_IO && MBEDTLS_MD_C */
 
+#if defined(MBEDTLS_MD_C)
 /**
  * \brief           This function sets the HMAC key and prepares to
  *                  authenticate a new message.
@@ -470,6 +485,7 @@
 int mbedtls_md_hmac(const mbedtls_md_info_t *md_info, const unsigned char *key, size_t keylen,
                     const unsigned char *input, size_t ilen,
                     unsigned char *output);
+#endif /* MBEDTLS_MD_C */
 
 #ifdef __cplusplus
 }
diff --git a/library/md.c b/library/md.c
index dd5553a..8aecd39 100644
--- a/library/md.c
+++ b/library/md.c
@@ -23,7 +23,7 @@
 
 #include "common.h"
 
-#if defined(MBEDTLS_MD_C)
+#if defined(MBEDTLS_MD_LIGHT)
 
 #include "mbedtls/md.h"
 #include "md_wrap.h"
@@ -110,6 +110,7 @@
 /*
  * Reminder: update profiles in x509_crt.c when adding a new hash!
  */
+#if defined(MBEDTLS_MD_C)
 static const int supported_digests[] = {
 
 #if defined(MBEDTLS_SHA512_C)
@@ -191,6 +192,7 @@
 #endif
     return NULL;
 }
+#endif /* MBEDTLS_MD_C */
 
 const mbedtls_md_info_t *mbedtls_md_info_from_type(mbedtls_md_type_t md_type)
 {
@@ -228,6 +230,7 @@
     }
 }
 
+#if defined(MBEDTLS_MD_C)
 const mbedtls_md_info_t *mbedtls_md_info_from_ctx(
     const mbedtls_md_context_t *ctx)
 {
@@ -237,6 +240,7 @@
 
     return ctx->MBEDTLS_PRIVATE(md_info);
 }
+#endif /* MBEDTLS_MD_C */
 
 void mbedtls_md_init(mbedtls_md_context_t *ctx)
 {
@@ -586,7 +590,7 @@
     }
 }
 
-#if defined(MBEDTLS_FS_IO)
+#if defined(MBEDTLS_FS_IO) && defined(MBEDTLS_MD_C)
 int mbedtls_md_file(const mbedtls_md_info_t *md_info, const char *path, unsigned char *output)
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
@@ -635,8 +639,9 @@
 
     return ret;
 }
-#endif /* MBEDTLS_FS_IO */
+#endif /* MBEDTLS_FS_IO && MBEDTLS_MD_C */
 
+#if defined(MBEDTLS_MD_C)
 int mbedtls_md_hmac_starts(mbedtls_md_context_t *ctx, const unsigned char *key, size_t keylen)
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
@@ -773,6 +778,7 @@
 
     return ret;
 }
+#endif /* MBEDTLS_MD_C */
 
 unsigned char mbedtls_md_get_size(const mbedtls_md_info_t *md_info)
 {
@@ -792,6 +798,7 @@
     return md_info->type;
 }
 
+#if defined(MBEDTLS_MD_C)
 const char *mbedtls_md_get_name(const mbedtls_md_info_t *md_info)
 {
     if (md_info == NULL) {
@@ -800,5 +807,6 @@
 
     return md_info->name;
 }
-
 #endif /* MBEDTLS_MD_C */
+
+#endif /* MBEDTLS_MD_LIGHT */
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index 7d91fa2..c4a8fe6 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -1219,19 +1219,25 @@
     tests/ssl-opt.sh -f 'Default\|opaque'
 }
 
-component_test_crypto_full_no_md () {
-    msg "build: crypto_full minus MD"
+component_test_crypto_full_md_light_only () {
+    msg "build: crypto_full with only the light subset of MD"
     scripts/config.py crypto_full
+    # Disable MD
     scripts/config.py unset MBEDTLS_MD_C
-    # Direct dependencies
+    # Disable direct dependencies of MD
     scripts/config.py unset MBEDTLS_HKDF_C
     scripts/config.py unset MBEDTLS_HMAC_DRBG_C
     scripts/config.py unset MBEDTLS_PKCS7_C
-    # Indirect dependencies
-    scripts/config.py unset MBEDTLS_ECDSA_DETERMINISTIC
-    make
+    # Disable indirect dependencies of MD
+    scripts/config.py unset MBEDTLS_ECDSA_DETERMINISTIC # needs HMAC_DRBG
+    # Enable "light" subset of MD
+    scripts/config.py set MBEDTLS_MD_LIGHT
+    make CFLAGS="$ASAN_CFLAGS" LDFLAGS="$ASAN_CFLAGS"
 
-    msg "test: crypto_full minus MD"
+    # Make sure we don't have the HMAC functions
+    not grep mbedtls_md_hmac library/md.o
+
+    msg "test: crypto_full with only the light subset of MD"
     make test
 }
 
diff --git a/tests/suites/test_suite_md.function b/tests/suites/test_suite_md.function
index ac3a8ba..1e8622b 100644
--- a/tests/suites/test_suite_md.function
+++ b/tests/suites/test_suite_md.function
@@ -3,11 +3,11 @@
 /* END_HEADER */
 
 /* BEGIN_DEPENDENCIES
- * depends_on:MBEDTLS_MD_C
+ * depends_on:MBEDTLS_MD_LIGHT
  * END_DEPENDENCIES
  */
 
-/* BEGIN_CASE */
+/* BEGIN_CASE depends_on:MBEDTLS_MD_C */
 void mbedtls_md_list()
 {
     const int *md_type_ptr;
@@ -38,21 +38,27 @@
 void md_null_args()
 {
     mbedtls_md_context_t ctx;
+#if defined(MBEDTLS_MD_C)
     const mbedtls_md_info_t *info = mbedtls_md_info_from_type(*(mbedtls_md_list()));
+#endif
     unsigned char buf[1] = { 0 };
 
     mbedtls_md_init(&ctx);
 
     TEST_EQUAL(0, mbedtls_md_get_size(NULL));
+#if defined(MBEDTLS_MD_C)
     TEST_EQUAL(mbedtls_md_get_type(NULL), MBEDTLS_MD_NONE);
     TEST_ASSERT(mbedtls_md_get_name(NULL) == NULL);
 
     TEST_ASSERT(mbedtls_md_info_from_string(NULL) == NULL);
     TEST_ASSERT(mbedtls_md_info_from_ctx(NULL) == NULL);
     TEST_ASSERT(mbedtls_md_info_from_ctx(&ctx) == NULL);
+#endif /* MBEDTLS_MD_C */
 
     TEST_EQUAL(mbedtls_md_setup(&ctx, NULL, 0), MBEDTLS_ERR_MD_BAD_INPUT_DATA);
+#if defined(MBEDTLS_MD_C)
     TEST_EQUAL(mbedtls_md_setup(NULL, info, 0), MBEDTLS_ERR_MD_BAD_INPUT_DATA);
+#endif
 
     TEST_EQUAL(mbedtls_md_starts(NULL), MBEDTLS_ERR_MD_BAD_INPUT_DATA);
     TEST_EQUAL(mbedtls_md_starts(&ctx), MBEDTLS_ERR_MD_BAD_INPUT_DATA);
@@ -65,6 +71,7 @@
 
     TEST_EQUAL(mbedtls_md(NULL, buf, 1, buf), MBEDTLS_ERR_MD_BAD_INPUT_DATA);
 
+#if defined(MBEDTLS_MD_C)
 #if defined(MBEDTLS_FS_IO)
     TEST_EQUAL(mbedtls_md_file(NULL, "", buf), MBEDTLS_ERR_MD_BAD_INPUT_DATA);
 #endif
@@ -87,10 +94,13 @@
 
     TEST_EQUAL(mbedtls_md_hmac(NULL, buf, 1, buf, 1, buf),
                MBEDTLS_ERR_MD_BAD_INPUT_DATA);
+#endif /* MBEDTLS_MD_C */
 
     /* Ok, this is not NULL arg but NULL return... */
     TEST_ASSERT(mbedtls_md_info_from_type(MBEDTLS_MD_NONE) == NULL);
+#if defined(MBEDTLS_MD_C)
     TEST_ASSERT(mbedtls_md_info_from_string("no such md") == NULL);
+#endif
 }
 /* END_CASE */
 
@@ -98,24 +108,31 @@
 void md_info(int md_type, char *md_name, int md_size)
 {
     const mbedtls_md_info_t *md_info;
+#if defined(MBEDTLS_MD_C)
     const int *md_type_ptr;
-    int found;
+#else
+    (void) md_name;
+#endif
 
     md_info = mbedtls_md_info_from_type(md_type);
     TEST_ASSERT(md_info != NULL);
+#if defined(MBEDTLS_MD_C)
     TEST_ASSERT(md_info == mbedtls_md_info_from_string(md_name));
+#endif
 
     TEST_EQUAL(mbedtls_md_get_type(md_info), (mbedtls_md_type_t) md_type);
     TEST_EQUAL(mbedtls_md_get_size(md_info), (unsigned char) md_size);
+#if defined(MBEDTLS_MD_C)
     TEST_EQUAL(0, strcmp(mbedtls_md_get_name(md_info), md_name));
 
-    found = 0;
+    int found = 0;
     for (md_type_ptr = mbedtls_md_list(); *md_type_ptr != 0; md_type_ptr++) {
         if (*md_type_ptr == md_type) {
             found = 1;
         }
     }
     TEST_EQUAL(found, 1);
+#endif /* MBEDTLS_MD_C */
 }
 /* END_CASE */
 
@@ -173,8 +190,10 @@
     TEST_ASSERT(md_info != NULL);
     TEST_EQUAL(0, mbedtls_md_setup(&ctx, md_info, 0));
     TEST_EQUAL(0, mbedtls_md_setup(&ctx_copy, md_info, 0));
+#if defined(MBEDTLS_MD_C)
     TEST_ASSERT(mbedtls_md_info_from_ctx(&ctx) == md_info);
     TEST_ASSERT(mbedtls_md_info_from_ctx(&ctx_copy) == md_info);
+#endif /* MBEDTLS_MD_C */
 
     TEST_EQUAL(0, mbedtls_md_starts(&ctx));
     TEST_ASSERT(ctx.md_ctx != NULL);
@@ -213,8 +232,10 @@
     TEST_ASSERT(md_info != NULL);
     TEST_EQUAL(0, mbedtls_md_setup(&ctx, md_info, 0));
     TEST_EQUAL(0, mbedtls_md_setup(&ctx_copy, md_info, 0));
+#if defined(MBEDTLS_MD_C)
     TEST_ASSERT(mbedtls_md_info_from_ctx(&ctx) == md_info);
     TEST_ASSERT(mbedtls_md_info_from_ctx(&ctx_copy) == md_info);
+#endif /* MBEDTLS_MD_C */
 
     halfway = src_str->len / 2;
 
@@ -240,7 +261,7 @@
 }
 /* END_CASE */
 
-/* BEGIN_CASE */
+/* BEGIN_CASE depends_on:MBEDTLS_MD_C */
 void mbedtls_md_hmac(int md_type, int trunc_size,
                      data_t *key_str, data_t *src_str,
                      data_t *hash)
@@ -259,7 +280,7 @@
 }
 /* END_CASE */
 
-/* BEGIN_CASE */
+/* BEGIN_CASE depends_on:MBEDTLS_MD_C */
 void md_hmac_multi(int md_type, int trunc_size, data_t *key_str,
                    data_t *src_str, data_t *hash)
 {
@@ -273,7 +294,9 @@
     md_info = mbedtls_md_info_from_type(md_type);
     TEST_ASSERT(md_info != NULL);
     TEST_EQUAL(0, mbedtls_md_setup(&ctx, md_info, 1));
+#if defined(MBEDTLS_MD_C)
     TEST_ASSERT(mbedtls_md_info_from_ctx(&ctx) == md_info);
+#endif
 
     halfway = src_str->len / 2;
 
@@ -300,7 +323,7 @@
 }
 /* END_CASE */
 
-/* BEGIN_CASE depends_on:MBEDTLS_FS_IO */
+/* BEGIN_CASE depends_on:MBEDTLS_FS_IO:MBEDTLS_MD_C */
 void mbedtls_md_file(int md_type, char *filename,
                      data_t *hash)
 {