Merge pull request #7120 from mpg/md-light

Define "MD light" subset of MD
diff --git a/ChangeLog.d/platform-zeroization.txt b/ChangeLog.d/platform-zeroization.txt
new file mode 100644
index 0000000..f17fbbb
--- /dev/null
+++ b/ChangeLog.d/platform-zeroization.txt
@@ -0,0 +1,3 @@
+Security
+  * Use platform-provided secure zeroization function where possible, such as
+    explicit_bzero().
diff --git a/library/platform_util.c b/library/platform_util.c
index f935b90..d525acc 100644
--- a/library/platform_util.c
+++ b/library/platform_util.c
@@ -26,6 +26,11 @@
 #define _POSIX_C_SOURCE 200112L
 #endif
 
+#if !defined(_GNU_SOURCE)
+/* Clang requires this to get support for explicit_bzero */
+#define _GNU_SOURCE
+#endif
+
 #include "common.h"
 
 #include "mbedtls/platform_util.h"
@@ -33,11 +38,31 @@
 #include "mbedtls/threading.h"
 
 #include <stddef.h>
+
+#ifndef __STDC_WANT_LIB_EXT1__
+#define __STDC_WANT_LIB_EXT1__ 1 /* Ask for the C11 gmtime_s() and memset_s() if available */
+#endif
 #include <string.h>
 
+#if defined(_WIN32)
+#include <windows.h>
+#endif
+
+// Detect platforms known to support explicit_bzero()
+#if defined(__GLIBC__) && (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 25)
+#define MBEDTLS_PLATFORM_HAS_EXPLICIT_BZERO 1
+#elif defined(__FreeBSD__) && (__FreeBSD_version >= 1100037)
+#define MBEDTLS_PLATFORM_HAS_EXPLICIT_BZERO 1
+#endif
+
 #if !defined(MBEDTLS_PLATFORM_ZEROIZE_ALT)
 /*
- * This implementation should never be optimized out by the compiler
+ * Where possible, we try to detect the presence of a platform-provided
+ * secure memset, such as explicit_bzero(), that is safe against being optimized
+ * out, and use that.
+ *
+ * For other platforms, we provide an implementation that aims not to be
+ * optimized out by the compiler.
  *
  * This implementation for mbedtls_platform_zeroize() was inspired from Colin
  * Percival's blog article at:
@@ -52,30 +77,40 @@
  * (refer to http://www.daemonology.net/blog/2014-09-05-erratum.html for
  * details), optimizations of the following form are still possible:
  *
- * if( memset_func != memset )
- *     memset_func( buf, 0, len );
+ * if (memset_func != memset)
+ *     memset_func(buf, 0, len);
  *
  * Note that it is extremely difficult to guarantee that
- * mbedtls_platform_zeroize() will not be optimized out by aggressive compilers
+ * the memset() call will not be optimized out by aggressive compilers
  * in a portable way. For this reason, Mbed TLS also provides the configuration
  * option MBEDTLS_PLATFORM_ZEROIZE_ALT, which allows users to configure
  * mbedtls_platform_zeroize() to use a suitable implementation for their
  * platform and needs.
  */
+#if !defined(MBEDTLS_PLATFORM_HAS_EXPLICIT_BZERO) && !defined(__STDC_LIB_EXT1__) \
+    && !defined(_WIN32)
 static void *(*const volatile memset_func)(void *, int, size_t) = memset;
+#endif
 
 void mbedtls_platform_zeroize(void *buf, size_t len)
 {
     MBEDTLS_INTERNAL_VALIDATE(len == 0 || buf != NULL);
 
     if (len > 0) {
+#if defined(MBEDTLS_PLATFORM_HAS_EXPLICIT_BZERO)
+        explicit_bzero(buf, len);
+#elif defined(__STDC_LIB_EXT1__)
+        memset_s(buf, len, 0, len);
+#elif defined(_WIN32)
+        SecureZeroMemory(buf, len);
+#else
         memset_func(buf, 0, len);
+#endif
     }
 }
 #endif /* MBEDTLS_PLATFORM_ZEROIZE_ALT */
 
 #if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_PLATFORM_GMTIME_R_ALT)
-#define __STDC_WANT_LIB_EXT1__ 1  /* Ask for the C11 gmtime_s() if it's available */
 #include <time.h>
 #if !defined(_WIN32) && (defined(unix) || \
     defined(__unix) || defined(__unix__) || (defined(__APPLE__) && \
diff --git a/tests/suites/test_suite_platform_util.data b/tests/suites/test_suite_platform_util.data
new file mode 100644
index 0000000..948543a
--- /dev/null
+++ b/tests/suites/test_suite_platform_util.data
@@ -0,0 +1,23 @@
+Zeroize len 0, null
+mbedtls_platform_zeroize:0:1
+
+Zeroize len 0, non-null
+mbedtls_platform_zeroize:0:0
+
+Zeroize len 1
+mbedtls_platform_zeroize:1:0
+
+Zeroize len 4
+mbedtls_platform_zeroize:1:0
+
+Zeroize len 5
+mbedtls_platform_zeroize:1:0
+
+Zeroize len 32
+mbedtls_platform_zeroize:32:0
+
+Zeroize len 127
+mbedtls_platform_zeroize:127:0
+
+Zeroize len 128
+mbedtls_platform_zeroize:128:0
diff --git a/tests/suites/test_suite_platform_util.function b/tests/suites/test_suite_platform_util.function
new file mode 100644
index 0000000..e5464e0
--- /dev/null
+++ b/tests/suites/test_suite_platform_util.function
@@ -0,0 +1,41 @@
+/* BEGIN_HEADER */
+#include "mbedtls/platform_util.h"
+/* END_HEADER */
+
+/* BEGIN_CASE */
+void mbedtls_platform_zeroize(int len, int null)
+{
+    char buf[130];
+    char *p = NULL;
+
+    TEST_ASSERT(len <= 128);
+
+    /* Write sentinel values */
+    buf[0] = 2;
+    buf[len + 1] = 2;
+
+    /* Write non-zero content */
+    if (!null) {
+        p = &buf[1];
+        for (int i = 0; i < len; i++) {
+            p[i] = 1;
+        }
+    }
+
+    /* Check content is non-zero */
+    TEST_EQUAL(buf[0], 2);
+    for (int i = 0; i < len; i++) {
+        TEST_ASSERT(p[i] == 1);
+    }
+    TEST_EQUAL(buf[len + 1], 2);
+
+    mbedtls_platform_zeroize(p, len);
+
+    /* Check content is zero and sentinels un-changed */
+    TEST_EQUAL(buf[0], 2);
+    for (int i = 0; i < len; i++) {
+        TEST_ASSERT(p[i] == 0);
+    }
+    TEST_EQUAL(buf[len + 1], 2);
+}
+/* END_CASE */