From cf0a9f96c520f84a4299f68213dc0dbe06a273d0 Mon Sep 17 00:00:00 2001
From: Paul Bakker <paul@brainspark.nl>
Date: Wed, 1 Jun 2016 11:25:44 +0100
Subject: [PATCH] Introduce platform-layer functions for reading/writing seed
 from NV

Introduces mbedtls_nv_seed_read() and mbedtls_nv_seed_write().

The platform-layer functions are only available when
MBEDTLS_ENTROPY_NV_SEED is enabled.
---
 include/mbedtls/check_config.h | 34 ++++++++++++-
 include/mbedtls/config.h       | 25 ++++++++++
 include/mbedtls/platform.h     | 53 +++++++++++++++++++-
 library/platform.c             | 89 +++++++++++++++++++++++++++++++++-
 4 files changed, 198 insertions(+), 3 deletions(-)

diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h
index 407cd571ae..63f93ec160 100644
--- a/include/mbedtls/check_config.h
+++ b/include/mbedtls/check_config.h
@@ -3,7 +3,7 @@
  *
  * \brief Consistency checks for configuration options
  *
- *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ *  Copyright (C) 2006-2016, ARM Limited, All Rights Reserved
  *  SPDX-License-Identifier: Apache-2.0
  *
  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -368,6 +368,38 @@
 #error "MBEDTLS_PLATFORM_STD_SNPRINTF defined, but not all prerequisites"
 #endif
 
+#if defined(MBEDTLS_ENTROPY_NV_SEED) &&\
+    ( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_ENTROPY_C) )
+#error "MBEDTLS_ENTROPY_NV_SEED defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_NV_SEED_ALT) &&\
+    !defined(MBEDTLS_ENTROPY_NV_SEED)
+#error "MBEDTLS_PLATFORM_NV_SEED_ALT defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ) &&\
+    !defined(MBEDTLS_PLATFORM_NV_SEED_ALT)
+#error "MBEDTLS_PLATFORM_STD_NV_SEED_READ defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE) &&\
+    !defined(MBEDTLS_PLATFORM_NV_SEED_ALT)
+#error "MBEDTLS_PLATFORM_STD_NV_SEED_WRITE defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_NV_SEED_READ_MACRO) &&\
+    ( defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ) ||\
+      defined(MBEDTLS_PLATFORM_NV_SEED_ALT) )
+#error "MBEDTLS_PLATFORM_NV_SEED_READ_MACRO and MBEDTLS_PLATFORM_STD_NV_SEED_READ cannot be defined simultaneously"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO) &&\
+    ( defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE) ||\
+      defined(MBEDTLS_PLATFORM_NV_SEED_ALT) )
+#error "MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO and MBEDTLS_PLATFORM_STD_NV_SEED_WRITE cannot be defined simultaneously"
+#endif
+
 #if defined(MBEDTLS_RSA_C) && ( !defined(MBEDTLS_BIGNUM_C) ||         \
     !defined(MBEDTLS_OID_C) )
 #error "MBEDTLS_RSA_C defined, but not all prerequisites"
diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h
index f800f1346c..3e12f43dd5 100644
--- a/include/mbedtls/config.h
+++ b/include/mbedtls/config.h
@@ -156,6 +156,7 @@
 //#define MBEDTLS_PLATFORM_FPRINTF_ALT
 //#define MBEDTLS_PLATFORM_PRINTF_ALT
 //#define MBEDTLS_PLATFORM_SNPRINTF_ALT
+//#define MBEDTLS_PLATFORM_NV_SEED_ALT
 
 /**
  * \def MBEDTLS_DEPRECATED_WARNING
@@ -824,6 +825,25 @@
  */
 //#define MBEDTLS_ENTROPY_FORCE_SHA256
 
+/**
+ * \def MBEDTLS_ENTROPY_NV_SEED
+ *
+ * Enable the non-volatile (NV) seed file-based entropy source.
+ * (Also enables the NV seed read/write functions in the platform layer)
+ *
+ * This is crucial (if not required) on systems that do not have a
+ * cryptographic entropy source (in hardware or kernel) available.
+ *
+ * Requires: MBEDTLS_ENTROPY_C, MBEDTLS_PLATFORM_C
+ *
+ * Note: If you use the default implementation functions that read a seedfile
+ *       with regular fopen(), please make sure you make a seedfile with the
+ *       proper name (defined in MBEDTLS_PLATFORM_STD_NV_SEED_FILE) and at
+ *       least MBEDTLS_ENTROPY_BLOCK_SIZE bytes in size that can be read from
+ *       and written to or you will get an entropy source error!
+ */
+//#define MBEDTLS_ENTROPY_NV_SEED
+
 /**
  * \def MBEDTLS_MEMORY_DEBUG
  *
@@ -2498,6 +2518,9 @@
 //#define MBEDTLS_PLATFORM_STD_SNPRINTF    snprintf /**< Default snprintf to use, can be undefined */
 //#define MBEDTLS_PLATFORM_STD_EXIT_SUCCESS       0 /**< Default exit value to use, can be undefined */
 //#define MBEDTLS_PLATFORM_STD_EXIT_FAILURE       1 /**< Default exit value to use, can be undefined */
+//#define MBEDTLS_PLATFORM_STD_NV_SEED_READ   mbedtls_platform_std_nv_seed_read /**< Default nv_seed_read function to use, can be undefined */
+//#define MBEDTLS_PLATFORM_STD_NV_SEED_WRITE  mbedtls_platform_std_nv_seed_write /**< Default nv_seed_write function to use, can be undefined */
+//#define MBEDTLS_PLATFORM_STD_NV_SEED_FILE  "seedfile" /**< Seed file to read/write with default implementation */
 
 /* To Use Function Macros MBEDTLS_PLATFORM_C must be enabled */
 /* MBEDTLS_PLATFORM_XXX_MACRO and MBEDTLS_PLATFORM_XXX_ALT cannot both be defined */
@@ -2510,6 +2533,8 @@
 //#define MBEDTLS_PLATFORM_PRINTF_MACRO        printf /**< Default printf macro to use, can be undefined */
 /* Note: your snprintf must correclty zero-terminate the buffer! */
 //#define MBEDTLS_PLATFORM_SNPRINTF_MACRO    snprintf /**< Default snprintf macro to use, can be undefined */
+//#define MBEDTLS_PLATFORM_NV_SEED_READ_MACRO   mbedtls_platform_std_nv_seed_read /**< Default nv_seed_read function to use, can be undefined */
+//#define MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO  mbedtls_platform_std_nv_seed_write /**< Default nv_seed_write function to use, can be undefined */
 
 /* SSL Cache options */
 //#define MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT       86400 /**< 1 day  */
diff --git a/include/mbedtls/platform.h b/include/mbedtls/platform.h
index 039cb587ae..10137d7813 100644
--- a/include/mbedtls/platform.h
+++ b/include/mbedtls/platform.h
@@ -3,7 +3,7 @@
  *
  * \brief mbed TLS Platform abstraction layer
  *
- *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ *  Copyright (C) 2006-2016, ARM Limited, All Rights Reserved
  *  SPDX-License-Identifier: Apache-2.0
  *
  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -76,12 +76,22 @@ extern "C" {
 #if !defined(MBEDTLS_PLATFORM_STD_EXIT_FAILURE)
 #define MBEDTLS_PLATFORM_STD_EXIT_FAILURE  EXIT_FAILURE /**< Default exit value to use */
 #endif
+#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ)
+#define MBEDTLS_PLATFORM_STD_NV_SEED_READ   mbedtls_platform_std_nv_seed_read
+#endif
+#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE)
+#define MBEDTLS_PLATFORM_STD_NV_SEED_WRITE  mbedtls_platform_std_nv_seed_write
+#endif
+#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_FILE)
+#define MBEDTLS_PLATFORM_STD_NV_SEED_FILE   "seedfile"
+#endif
 #else /* MBEDTLS_PLATFORM_NO_STD_FUNCTIONS */
 #if defined(MBEDTLS_PLATFORM_STD_MEM_HDR)
 #include MBEDTLS_PLATFORM_STD_MEM_HDR
 #endif
 #endif /* MBEDTLS_PLATFORM_NO_STD_FUNCTIONS */
 
+
 /* \} name SECTION: Module settings */
 
 /*
@@ -262,6 +272,47 @@ int mbedtls_platform_set_time( mbedtls_time_t (*time_func)( mbedtls_time_t* time
 #endif /* MBEDTLS_PLATFORM_TIME_MACRO */
 #endif /* MBEDTLS_PLATFORM_TIME_ALT */
 
+/*
+ * The function pointers for reading from and writing a seed file to
+ * Non-Volatile storage (NV) in a platform-independent way
+ *
+ * Only enabled when the NV seed entropy source is enabled
+ */
+#if defined(MBEDTLS_ENTROPY_NV_SEED)
+#if !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS) && defined(MBEDTLS_FS_IO)
+/* Internal standard platform definitions */
+int mbedtls_platform_std_nv_seed_read( unsigned char *buf, size_t buf_len );
+int mbedtls_platform_std_nv_seed_write( unsigned char *buf, size_t buf_len );
+#endif
+
+#if defined(MBEDTLS_PLATFORM_NV_SEED_ALT)
+extern int (*mbedtls_nv_seed_read)( unsigned char *buf, size_t buf_len );
+extern int (*mbedtls_nv_seed_write)( unsigned char *buf, size_t buf_len );
+
+/**
+ * \brief   Set your own seed file writing/reading functions
+ *
+ * \param   nv_seed_read_func   the seed reading function implementation
+ * \param   nv_seed_write_func  the seed writing function implementation
+ *
+ * \return              0
+ */
+int mbedtls_platform_set_nv_seed(
+            int (*nv_seed_read_func)( unsigned char *buf, size_t buf_len ),
+            int (*nv_seed_write_func)( unsigned char *buf, size_t buf_len )
+            );
+#else
+#if defined(MBEDTLS_PLATFORM_NV_SEED_READ_MACRO) && \
+    defined(MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO)
+#define mbedtls_nv_seed_read    MBEDTLS_PLATFORM_NV_SEED_READ_MACRO
+#define mbedtls_nv_seed_write   MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO
+#else
+#define mbedtls_nv_seed_read    mbedtls_platform_std_nv_seed_read
+#define mbedtls_nv_seed_write   mbedtls_platform_std_nv_seed_write
+#endif
+#endif /* MBEDTLS_PLATFORM_NV_SEED_ALT */
+#endif /* MBEDTLS_ENTROPY_NV_SEED */
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/library/platform.c b/library/platform.c
index 89a2bd65de..68ca45d10b 100644
--- a/library/platform.c
+++ b/library/platform.c
@@ -1,7 +1,7 @@
 /*
  *  Platform abstraction layer
  *
- *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ *  Copyright (C) 2006-2016, ARM Limited, All Rights Reserved
  *  SPDX-License-Identifier: Apache-2.0
  *
  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -213,4 +213,91 @@ int mbedtls_platform_set_time( mbedtls_time_t (*time_func)( mbedtls_time_t* time
 }
 #endif /* MBEDTLS_PLATFORM_TIME_ALT */
 
+#if defined(MBEDTLS_ENTROPY_NV_SEED)
+#if !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS) && defined(MBEDTLS_FS_IO)
+/* Default implementations for the platform independent seed functions use
+ * standard libc file functions to read from and write to a pre-defined filename
+ */
+int mbedtls_platform_std_nv_seed_read( unsigned char *buf, size_t buf_len )
+{
+    FILE *file;
+    size_t n;
+
+    if( ( file = fopen( MBEDTLS_PLATFORM_STD_NV_SEED_FILE, "rb" ) ) == NULL )
+        return -1;
+
+    if( ( n = fread( buf, 1, buf_len, file ) ) != buf_len )
+    {
+        fclose( file );
+        return -1;
+    }
+
+    fclose( file );
+    return( n );
+}
+
+int mbedtls_platform_std_nv_seed_write( unsigned char *buf, size_t buf_len )
+{
+    FILE *file;
+    size_t n;
+
+    if( ( file = fopen( MBEDTLS_PLATFORM_STD_NV_SEED_FILE, "w" ) ) == NULL )
+        return -1;
+
+    if( ( n = fwrite( buf, 1, buf_len, file ) ) != buf_len )
+    {
+        fclose( file );
+        return -1;
+    }
+
+    fclose( file );
+    return( n );
+}
+#endif /* MBEDTLS_PLATFORM_NO_STD_FUNCTIONS */
+
+#if defined(MBEDTLS_PLATFORM_NV_SEED_ALT)
+#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ)
+/*
+ * Make dummy function to prevent NULL pointer dereferences
+ */
+static int platform_nv_seed_read_uninit( unsigned char *buf, size_t buf_len )
+{
+    ((void) buf);
+    ((void) buf_len);
+    return( -1 );
+}
+
+#define MBEDTLS_PLATFORM_STD_NV_SEED_READ   platform_nv_seed_read_uninit
+#endif /* !MBEDTLS_PLATFORM_STD_NV_SEED_READ */
+
+#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE)
+/*
+ * Make dummy function to prevent NULL pointer dereferences
+ */
+static int platform_nv_seed_write_uninit( unsigned char *buf, size_t buf_len )
+{
+    ((void) buf);
+    ((void) buf_len);
+    return( -1 );
+}
+
+#define MBEDTLS_PLATFORM_STD_NV_SEED_WRITE   platform_nv_seed_write_uninit
+#endif /* !MBEDTLS_PLATFORM_STD_NV_SEED_WRITE */
+
+int (*mbedtls_nv_seed_read)( unsigned char *buf, size_t buf_len ) =
+            MBEDTLS_PLATFORM_STD_NV_SEED_READ;
+int (*mbedtls_nv_seed_write)( unsigned char *buf, size_t buf_len ) =
+            MBEDTLS_PLATFORM_STD_NV_SEED_WRITE;
+
+int mbedtls_platform_set_nv_seed(
+        int (*nv_seed_read_func)( unsigned char *buf, size_t buf_len ),
+        int (*nv_seed_write_func)( unsigned char *buf, size_t buf_len ) )
+{
+    mbedtls_nv_seed_read = nv_seed_read_func;
+    mbedtls_nv_seed_write = nv_seed_write_func;
+    return( 0 );
+}
+#endif /* MBEDTLS_PLATFORM_NV_SEED_ALT */
+#endif /* MBEDTLS_ENTROPY_NV_SEED */
+
 #endif /* MBEDTLS_PLATFORM_C */