Merge pull request #952 from gilles-peskine-arm/stdio_buffering-setbuf
Turn off stdio buffering with setbuf()
diff --git a/ChangeLog.d/add_mbedtls_setbuf.txt b/ChangeLog.d/add_mbedtls_setbuf.txt
new file mode 100644
index 0000000..d14cd18
--- /dev/null
+++ b/ChangeLog.d/add_mbedtls_setbuf.txt
@@ -0,0 +1,11 @@
+Security
+ * Add the platform function mbedtls_setbuf() to allow buffering to be
+ disabled on stdio files, to stop secrets loaded from said files being
+ potentially left in memory after file operations. Reported by
+ Glenn Strauss.
+Requirement changes
+ * The library will no longer compile out of the box on a platform without
+ setbuf(). If your platform does not have setbuf(), you can configure an
+ alternative function by enabling MBEDTLS_PLATFORM_SETBUF_ALT or
+ MBEDTLS_PLATFORM_SETBUF_MACRO.
+
diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h
index bdc32e1..1c3d6ab 100644
--- a/include/mbedtls/check_config.h
+++ b/include/mbedtls/check_config.h
@@ -385,6 +385,20 @@
#error "MBEDTLS_PLATFORM_EXIT_MACRO and MBEDTLS_PLATFORM_STD_EXIT/MBEDTLS_PLATFORM_EXIT_ALT cannot be defined simultaneously"
#endif
+#if defined(MBEDTLS_PLATFORM_SETBUF_ALT) && !defined(MBEDTLS_PLATFORM_C)
+#error "MBEDTLS_PLATFORM_SETBUF_ALT defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_SETBUF_MACRO) && !defined(MBEDTLS_PLATFORM_C)
+#error "MBEDTLS_PLATFORM_SETBUF_MACRO defined, but not all prerequisites"
+#endif
+
+#if defined(MBEDTLS_PLATFORM_SETBUF_MACRO) &&\
+ ( defined(MBEDTLS_PLATFORM_STD_SETBUF) ||\
+ defined(MBEDTLS_PLATFORM_SETBUF_ALT) )
+#error "MBEDTLS_PLATFORM_SETBUF_MACRO and MBEDTLS_PLATFORM_STD_SETBUF/MBEDTLS_PLATFORM_SETBUF_ALT cannot be defined simultaneously"
+#endif
+
#if defined(MBEDTLS_PLATFORM_TIME_ALT) &&\
( !defined(MBEDTLS_PLATFORM_C) ||\
!defined(MBEDTLS_HAVE_TIME) )
diff --git a/include/mbedtls/mbedtls_config.h b/include/mbedtls/mbedtls_config.h
index 9c8ec11..060973f 100644
--- a/include/mbedtls/mbedtls_config.h
+++ b/include/mbedtls/mbedtls_config.h
@@ -225,6 +225,7 @@
* Uncomment a macro to enable alternate implementation of specific base
* platform function
*/
+//#define MBEDTLS_PLATFORM_SETBUF_ALT
//#define MBEDTLS_PLATFORM_EXIT_ALT
//#define MBEDTLS_PLATFORM_TIME_ALT
//#define MBEDTLS_PLATFORM_FPRINTF_ALT
@@ -3318,6 +3319,7 @@
//#define MBEDTLS_PLATFORM_STD_MEM_HDR <stdlib.h> /**< Header to include if MBEDTLS_PLATFORM_NO_STD_FUNCTIONS is defined. Don't define if no header is needed. */
//#define MBEDTLS_PLATFORM_STD_CALLOC calloc /**< Default allocator to use, can be undefined */
//#define MBEDTLS_PLATFORM_STD_FREE free /**< Default free to use, can be undefined */
+//#define MBEDTLS_PLATFORM_STD_SETBUF setbuf /**< Default setbuf to use, can be undefined */
//#define MBEDTLS_PLATFORM_STD_EXIT exit /**< Default exit to use, can be undefined */
//#define MBEDTLS_PLATFORM_STD_TIME time /**< Default time to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */
//#define MBEDTLS_PLATFORM_STD_FPRINTF fprintf /**< Default fprintf to use, can be undefined */
@@ -3335,6 +3337,7 @@
//#define MBEDTLS_PLATFORM_CALLOC_MACRO calloc /**< Default allocator macro to use, can be undefined */
//#define MBEDTLS_PLATFORM_FREE_MACRO free /**< Default free macro to use, can be undefined */
//#define MBEDTLS_PLATFORM_EXIT_MACRO exit /**< Default exit macro to use, can be undefined */
+//#define MBEDTLS_PLATFORM_SETBUF_MACRO setbuf /**< Default setbuf macro to use, can be undefined */
//#define MBEDTLS_PLATFORM_TIME_MACRO time /**< Default time macro to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */
//#define MBEDTLS_PLATFORM_TIME_TYPE_MACRO time_t /**< Default time macro to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */
//#define MBEDTLS_PLATFORM_FPRINTF_MACRO fprintf /**< Default fprintf macro to use, can be undefined */
diff --git a/include/mbedtls/platform.h b/include/mbedtls/platform.h
index a598434..a5a43ac 100644
--- a/include/mbedtls/platform.h
+++ b/include/mbedtls/platform.h
@@ -91,6 +91,9 @@
#if !defined(MBEDTLS_PLATFORM_STD_FREE)
#define MBEDTLS_PLATFORM_STD_FREE free /**< The default \c free function to use. */
#endif
+#if !defined(MBEDTLS_PLATFORM_STD_SETBUF)
+#define MBEDTLS_PLATFORM_STD_SETBUF setbuf /**< The default \c setbuf function to use. */
+#endif
#if !defined(MBEDTLS_PLATFORM_STD_EXIT)
#define MBEDTLS_PLATFORM_STD_EXIT exit /**< The default \c exit function to use. */
#endif
@@ -277,6 +280,56 @@
#endif /* MBEDTLS_PLATFORM_VSNPRINTF_ALT */
/*
+ * The function pointers for setbuf
+ */
+#if defined(MBEDTLS_PLATFORM_SETBUF_ALT)
+#include <stdio.h>
+/**
+ * \brief Function pointer to call for `setbuf()` functionality
+ * (changing the internal buffering on stdio calls).
+ *
+ * \note The library calls this function to disable
+ * buffering when reading or writing sensitive data,
+ * to avoid having extra copies of sensitive data
+ * remaining in stdio buffers after the file is
+ * closed. If this is not a concern, for example if
+ * your platform's stdio doesn't have any buffering,
+ * you can set mbedtls_setbuf to a function that
+ * does nothing.
+ *
+ * The library always calls this function with
+ * `buf` equal to `NULL`.
+ */
+extern void (*mbedtls_setbuf)( FILE *stream, char *buf );
+
+/**
+ * \brief Dynamically configure the function that is called
+ * when the mbedtls_setbuf() function is called by the
+ * library.
+ *
+ * \param setbuf_func The \c setbuf function implementation
+ *
+ * \return \c 0
+ */
+int mbedtls_platform_set_setbuf( void (*setbuf_func)(
+ FILE *stream, char *buf ) );
+#elif defined(MBEDTLS_PLATFORM_SETBUF_MACRO)
+/**
+ * \brief Macro defining the function for the library to
+ * call for `setbuf` functionality (changing the
+ * internal buffering on stdio calls).
+ *
+ * \note See extra comments on the mbedtls_setbuf() function
+ * pointer above.
+ *
+ * \return \c 0 on success, negative on error.
+ */
+#define mbedtls_setbuf MBEDTLS_PLATFORM_SETBUF_MACRO
+#else
+#define mbedtls_setbuf setbuf
+#endif /* MBEDTLS_PLATFORM_SETBUF_ALT / MBEDTLS_PLATFORM_SETBUF_MACRO */
+
+/*
* The function pointers for exit
*/
#if defined(MBEDTLS_PLATFORM_EXIT_ALT)
diff --git a/library/ctr_drbg.c b/library/ctr_drbg.c
index 23ea07b..43f490e 100644
--- a/library/ctr_drbg.c
+++ b/library/ctr_drbg.c
@@ -607,6 +607,9 @@
if( ( f = fopen( path, "wb" ) ) == NULL )
return( MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR );
+ /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
+ mbedtls_setbuf( f, NULL );
+
if( ( ret = mbedtls_ctr_drbg_random( ctx, buf,
MBEDTLS_CTR_DRBG_MAX_INPUT ) ) != 0 )
goto exit;
@@ -640,6 +643,9 @@
if( ( f = fopen( path, "rb" ) ) == NULL )
return( MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR );
+ /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
+ mbedtls_setbuf( f, NULL );
+
n = fread( buf, 1, sizeof( buf ), f );
if( fread( &c, 1, 1, f ) != 0 )
{
diff --git a/library/dhm.c b/library/dhm.c
index 2ce0ed4..1e95bda 100644
--- a/library/dhm.c
+++ b/library/dhm.c
@@ -620,6 +620,7 @@
if( ( f = fopen( path, "rb" ) ) == NULL )
return( MBEDTLS_ERR_DHM_FILE_IO_ERROR );
+ /* The data loaded here is public, so don't bother disabling buffering. */
fseek( f, 0, SEEK_END );
if( ( size = ftell( f ) ) == -1 )
diff --git a/library/entropy.c b/library/entropy.c
index 9e31f84..08c5bd7 100644
--- a/library/entropy.c
+++ b/library/entropy.c
@@ -457,6 +457,9 @@
goto exit;
}
+ /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
+ mbedtls_setbuf( f, NULL );
+
if( fwrite( buf, 1, MBEDTLS_ENTROPY_BLOCK_SIZE, f ) != MBEDTLS_ENTROPY_BLOCK_SIZE )
{
ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR;
@@ -484,6 +487,9 @@
if( ( f = fopen( path, "rb" ) ) == NULL )
return( MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR );
+ /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
+ mbedtls_setbuf( f, NULL );
+
fseek( f, 0, SEEK_END );
n = (size_t) ftell( f );
fseek( f, 0, SEEK_SET );
diff --git a/library/entropy_poll.c b/library/entropy_poll.c
index 058c307..2ae57fd 100644
--- a/library/entropy_poll.c
+++ b/library/entropy_poll.c
@@ -35,7 +35,7 @@
#if defined(MBEDTLS_TIMING_C)
#include "mbedtls/timing.h"
#endif
-#if defined(MBEDTLS_ENTROPY_NV_SEED)
+#if defined(MBEDTLS_ENTROPY_NV_SEED) || !defined(HAVE_SYSCTL_ARND)
#include "mbedtls/platform.h"
#endif
@@ -195,6 +195,9 @@
if( file == NULL )
return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED );
+ /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
+ mbedtls_setbuf( file, NULL );
+
read_len = fread( output, 1, len, file );
if( read_len != len )
{
diff --git a/library/hmac_drbg.c b/library/hmac_drbg.c
index ab353bf..8b13a86 100644
--- a/library/hmac_drbg.c
+++ b/library/hmac_drbg.c
@@ -436,6 +436,9 @@
if( ( f = fopen( path, "wb" ) ) == NULL )
return( MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR );
+ /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
+ mbedtls_setbuf( f, NULL );
+
if( ( ret = mbedtls_hmac_drbg_random( ctx, buf, sizeof( buf ) ) ) != 0 )
goto exit;
@@ -465,6 +468,9 @@
if( ( f = fopen( path, "rb" ) ) == NULL )
return( MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR );
+ /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
+ mbedtls_setbuf( f, NULL );
+
n = fread( buf, 1, sizeof( buf ), f );
if( fread( &c, 1, 1, f ) != 0 )
{
diff --git a/library/md.c b/library/md.c
index f2c1a90..a387da5 100644
--- a/library/md.c
+++ b/library/md.c
@@ -605,6 +605,9 @@
if( ( f = fopen( path, "rb" ) ) == NULL )
return( MBEDTLS_ERR_MD_FILE_IO_ERROR );
+ /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
+ mbedtls_setbuf( f, NULL );
+
mbedtls_md_init( &ctx );
if( ( ret = mbedtls_md_setup( &ctx, md_info, 0 ) ) != 0 )
diff --git a/library/pkparse.c b/library/pkparse.c
index 68727ec..722abd7 100644
--- a/library/pkparse.c
+++ b/library/pkparse.c
@@ -82,6 +82,9 @@
if( ( f = fopen( path, "rb" ) ) == NULL )
return( MBEDTLS_ERR_PK_FILE_IO_ERROR );
+ /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
+ mbedtls_setbuf( f, NULL );
+
fseek( f, 0, SEEK_END );
if( ( size = ftell( f ) ) == -1 )
{
diff --git a/library/platform.c b/library/platform.c
index e742fde..6151e6c 100644
--- a/library/platform.c
+++ b/library/platform.c
@@ -226,6 +226,28 @@
}
#endif /* MBEDTLS_PLATFORM_FPRINTF_ALT */
+#if defined(MBEDTLS_PLATFORM_SETBUF_ALT)
+#if !defined(MBEDTLS_PLATFORM_STD_SETBUF)
+/*
+ * Make dummy function to prevent NULL pointer dereferences
+ */
+static void platform_setbuf_uninit( FILE *stream, char *buf )
+{
+ ((void) stream);
+ ((void) buf);
+}
+
+#define MBEDTLS_PLATFORM_STD_SETBUF platform_setbuf_uninit
+#endif /* !MBEDTLS_PLATFORM_STD_SETBUF */
+void (*mbedtls_setbuf)( FILE *stream, char *buf ) = MBEDTLS_PLATFORM_STD_SETBUF;
+
+int mbedtls_platform_set_setbuf( void (*setbuf_func)( FILE *stream, char *buf ) )
+{
+ mbedtls_setbuf = setbuf_func;
+ return( 0 );
+}
+#endif /* MBEDTLS_PLATFORM_SETBUF_ALT */
+
#if defined(MBEDTLS_PLATFORM_EXIT_ALT)
#if !defined(MBEDTLS_PLATFORM_STD_EXIT)
/*
@@ -288,6 +310,9 @@
if( ( file = fopen( MBEDTLS_PLATFORM_STD_NV_SEED_FILE, "rb" ) ) == NULL )
return( -1 );
+ /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
+ mbedtls_setbuf( file, NULL );
+
if( ( n = fread( buf, 1, buf_len, file ) ) != buf_len )
{
fclose( file );
@@ -307,6 +332,9 @@
if( ( file = fopen( MBEDTLS_PLATFORM_STD_NV_SEED_FILE, "w" ) ) == NULL )
return -1;
+ /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
+ mbedtls_setbuf( file, NULL );
+
if( ( n = fwrite( buf, 1, buf_len, file ) ) != buf_len )
{
fclose( file );
diff --git a/library/psa_its_file.c b/library/psa_its_file.c
index f058720..b7c2e6b 100644
--- a/library/psa_its_file.c
+++ b/library/psa_its_file.c
@@ -102,6 +102,9 @@
if( *p_stream == NULL )
return( PSA_ERROR_DOES_NOT_EXIST );
+ /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
+ mbedtls_setbuf( *p_stream, NULL );
+
n = fread( &header, 1, sizeof( header ), *p_stream );
if( n != sizeof( header ) )
return( PSA_ERROR_DATA_CORRUPT );
@@ -201,9 +204,13 @@
psa_its_fill_filename( uid, filename );
stream = fopen( PSA_ITS_STORAGE_TEMP, "wb" );
+
if( stream == NULL )
goto exit;
+ /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
+ mbedtls_setbuf( stream, NULL );
+
status = PSA_ERROR_INSUFFICIENT_STORAGE;
n = fwrite( &header, 1, sizeof( header ), stream );
if( n != sizeof( header ) )
diff --git a/programs/aes/crypt_and_hash.c b/programs/aes/crypt_and_hash.c
index 7288548..136e25b 100644
--- a/programs/aes/crypt_and_hash.c
+++ b/programs/aes/crypt_and_hash.c
@@ -166,6 +166,10 @@
goto exit;
}
+ /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
+ mbedtls_setbuf( fin, NULL );
+ mbedtls_setbuf( fout, NULL );
+
/*
* Read the Cipher and MD from the command line
*/
diff --git a/programs/psa/key_ladder_demo.c b/programs/psa/key_ladder_demo.c
index cad875e..1303719 100644
--- a/programs/psa/key_ladder_demo.c
+++ b/programs/psa/key_ladder_demo.c
@@ -56,6 +56,7 @@
#include <stdio.h>
#include <string.h>
+#include "mbedtls/platform.h" // for mbedtls_setbuf
#include "mbedtls/platform_util.h" // for mbedtls_platform_zeroize
#include <psa/crypto.h>
@@ -177,6 +178,8 @@
key_data, sizeof( key_data ),
&key_size ) );
SYS_CHECK( ( key_file = fopen( output_file_name, "wb" ) ) != NULL );
+ /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
+ mbedtls_setbuf( key_file, NULL );
SYS_CHECK( fwrite( key_data, 1, key_size, key_file ) == key_size );
SYS_CHECK( fclose( key_file ) == 0 );
key_file = NULL;
@@ -231,6 +234,8 @@
unsigned char extra_byte;
SYS_CHECK( ( key_file = fopen( key_file_name, "rb" ) ) != NULL );
+ /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
+ mbedtls_setbuf( key_file, NULL );
SYS_CHECK( ( key_size = fread( key_data, 1, sizeof( key_data ),
key_file ) ) != 0 );
if( fread( &extra_byte, 1, 1, key_file ) != 0 )
@@ -372,6 +377,8 @@
/* Find the size of the data to wrap. */
SYS_CHECK( ( input_file = fopen( input_file_name, "rb" ) ) != NULL );
+ /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
+ mbedtls_setbuf( input_file, NULL );
SYS_CHECK( fseek( input_file, 0, SEEK_END ) == 0 );
SYS_CHECK( ( input_position = ftell( input_file ) ) != -1 );
#if LONG_MAX > SIZE_MAX
@@ -418,6 +425,8 @@
/* Write the output. */
SYS_CHECK( ( output_file = fopen( output_file_name, "wb" ) ) != NULL );
+ /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
+ mbedtls_setbuf( output_file, NULL );
SYS_CHECK( fwrite( &header, 1, sizeof( header ),
output_file ) == sizeof( header ) );
SYS_CHECK( fwrite( buffer, 1, ciphertext_size,
@@ -453,6 +462,8 @@
/* Load and validate the header. */
SYS_CHECK( ( input_file = fopen( input_file_name, "rb" ) ) != NULL );
+ /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
+ mbedtls_setbuf( input_file, NULL );
SYS_CHECK( fread( &header, 1, sizeof( header ),
input_file ) == sizeof( header ) );
if( memcmp( &header.magic, WRAPPED_DATA_MAGIC,
@@ -509,6 +520,8 @@
/* Write the output. */
SYS_CHECK( ( output_file = fopen( output_file_name, "wb" ) ) != NULL );
+ /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
+ mbedtls_setbuf( output_file, NULL );
SYS_CHECK( fwrite( buffer, 1, plaintext_size,
output_file ) == plaintext_size );
SYS_CHECK( fclose( output_file ) == 0 );
diff --git a/programs/ssl/ssl_test_common_source.c b/programs/ssl/ssl_test_common_source.c
index 511ede9..24e1f3e 100644
--- a/programs/ssl/ssl_test_common_source.c
+++ b/programs/ssl/ssl_test_common_source.c
@@ -101,6 +101,10 @@
goto exit;
}
+ /* Ensure no stdio buffering of secrets, as such buffers cannot be
+ * wiped. */
+ mbedtls_setbuf( f, NULL );
+
if( fwrite( nss_keylog_line, 1, len, f ) != len )
{
fclose( f );
diff --git a/programs/ssl/ssl_test_lib.h b/programs/ssl/ssl_test_lib.h
index 03349ba..c368f57 100644
--- a/programs/ssl/ssl_test_lib.h
+++ b/programs/ssl/ssl_test_lib.h
@@ -34,6 +34,7 @@
#define mbedtls_printf printf
#define mbedtls_fprintf fprintf
#define mbedtls_snprintf snprintf
+#define mbedtls_setbuf setbuf
#define mbedtls_exit exit
#define MBEDTLS_EXIT_SUCCESS EXIT_SUCCESS
#define MBEDTLS_EXIT_FAILURE EXIT_FAILURE
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index 27c211f..458fe8f 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -2253,6 +2253,7 @@
scripts/config.py unset MBEDTLS_PLATFORM_SNPRINTF_ALT
scripts/config.py unset MBEDTLS_PLATFORM_TIME_ALT
scripts/config.py unset MBEDTLS_PLATFORM_EXIT_ALT
+ scripts/config.py unset MBEDTLS_PLATFORM_SETBUF_ALT
scripts/config.py unset MBEDTLS_PLATFORM_NV_SEED_ALT
scripts/config.py unset MBEDTLS_ENTROPY_NV_SEED
scripts/config.py unset MBEDTLS_FS_IO