mirror of
https://github.com/yuzu-emu/mbedtls.git
synced 2025-01-09 02:45:29 +00:00
77b7a7754c
The earlier implementation had two problems: the random generator always returned 0 if the MBEDTLS_ENTROPY_HARDWARE_ALT flag was not defined and there was no protection needed if the HW RNG was malfunctioning. Both these problems have been solved in this commit by adding the linear congruential generator algorithm. Signed-off-by: Piotr Nowicki <piotr.nowicki@arm.com>
390 lines
13 KiB
C
390 lines
13 KiB
C
/*
|
|
* Common and shared functions used by multiple modules in the Mbed TLS
|
|
* library.
|
|
*
|
|
* Copyright (C) 2018, Arm Limited, All Rights Reserved
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
* not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
* This file is part of Mbed TLS (https://tls.mbed.org)
|
|
*/
|
|
|
|
/*
|
|
* Ensure gmtime_r is available even with -std=c99; must be defined before
|
|
* config.h, which pulls in glibc's features.h. Harmless on other platforms.
|
|
*/
|
|
#if !defined(_POSIX_C_SOURCE)
|
|
#define _POSIX_C_SOURCE 200112L
|
|
#endif
|
|
|
|
#if !defined(MBEDTLS_CONFIG_FILE)
|
|
#include "mbedtls/config.h"
|
|
#else
|
|
#include MBEDTLS_CONFIG_FILE
|
|
#endif
|
|
|
|
#include "mbedtls/platform_util.h"
|
|
#include "mbedtls/platform.h"
|
|
#include "mbedtls/threading.h"
|
|
|
|
#if !defined(MBEDTLS_PLATFORM_C)
|
|
#include <stdlib.h>
|
|
#define mbedtls_calloc calloc
|
|
#define mbedtls_free free
|
|
#endif
|
|
|
|
#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT)
|
|
#include "mbedtls/entropy_poll.h"
|
|
#endif
|
|
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
|
|
/* Max number of loops for mbedtls_platform_random_delay. */
|
|
#define MAX_RAND_DELAY 100
|
|
|
|
/* Parameters for the linear congruential generator used as a non-cryptographic
|
|
* random number generator. The same parameters are used by e.g. ANSI C. */
|
|
#define RAND_MULTIPLIER 1103515245
|
|
#define RAND_INCREMENT 12345
|
|
#define RAND_MODULUS 0x80000000
|
|
|
|
/* The number of iterations after which the seed of the non-cryptographic
|
|
* random number generator will be changed. This is used only if the
|
|
* MBEDTLS_ENTROPY_HARDWARE_ALT option is enabled. */
|
|
#define RAND_SEED_LIFE 10000
|
|
|
|
#if !defined(MBEDTLS_PLATFORM_ZEROIZE_ALT)
|
|
/*
|
|
* This implementation should never be optimized out by the compiler
|
|
*
|
|
* This implementation for mbedtls_platform_zeroize() was inspired from Colin
|
|
* Percival's blog article at:
|
|
*
|
|
* http://www.daemonology.net/blog/2014-09-04-how-to-zero-a-buffer.html
|
|
*
|
|
* It uses a volatile function pointer to the standard memset(). Because the
|
|
* pointer is volatile the compiler expects it to change at
|
|
* any time and will not optimize out the call that could potentially perform
|
|
* other operations on the input buffer instead of just setting it to 0.
|
|
* Nevertheless, as pointed out by davidtgoldblatt on Hacker News
|
|
* (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 );
|
|
*
|
|
* Note that it is extremely difficult to guarantee that
|
|
* mbedtls_platform_zeroize() 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.
|
|
*/
|
|
void *mbedtls_platform_memset( void *, int, size_t );
|
|
static void * (* const volatile memset_func)( void *, int, size_t ) = mbedtls_platform_memset;
|
|
|
|
void mbedtls_platform_zeroize( void *buf, size_t len )
|
|
{
|
|
MBEDTLS_INTERNAL_VALIDATE( len == 0 || buf != NULL );
|
|
|
|
if( len > 0 )
|
|
memset_func( buf, 0, len );
|
|
}
|
|
#endif /* MBEDTLS_PLATFORM_ZEROIZE_ALT */
|
|
|
|
void *mbedtls_platform_memset( void *ptr, int value, size_t num )
|
|
{
|
|
/* Randomize start offset. */
|
|
size_t start_offset = (size_t) mbedtls_platform_random_in_range( (uint32_t) num );
|
|
/* Randomize data */
|
|
uint32_t data = mbedtls_platform_random_in_range( 256 );
|
|
|
|
/* Perform a pair of memset operations from random locations with
|
|
* random data */
|
|
memset( (void *) ( (unsigned char *) ptr + start_offset ), data,
|
|
( num - start_offset ) );
|
|
memset( (void *) ptr, data, start_offset );
|
|
|
|
/* Perform the original memset */
|
|
return( memset( ptr, value, num ) );
|
|
}
|
|
|
|
void *mbedtls_platform_memcpy( void *dst, const void *src, size_t num )
|
|
{
|
|
/* Randomize start offset. */
|
|
size_t start_offset = (size_t) mbedtls_platform_random_in_range( (uint32_t) num );
|
|
/* Randomize initial data to prevent leakage while copying */
|
|
uint32_t data = mbedtls_platform_random_in_range( 256 );
|
|
|
|
/* Use memset with random value at first to increase security - memset is
|
|
not normally part of the memcpy function and here can be useed
|
|
with regular, unsecured implementation */
|
|
memset( (void *) dst, data, num );
|
|
memcpy( (void *) ( (unsigned char *) dst + start_offset ),
|
|
(void *) ( (unsigned char *) src + start_offset ),
|
|
( num - start_offset ) );
|
|
return( memcpy( (void *) dst, (void *) src, start_offset ) );
|
|
}
|
|
|
|
int mbedtls_platform_memmove( void *dst, const void *src, size_t num )
|
|
{
|
|
/* The buffers can have a common part, so we cannot do a copy from a random
|
|
* location. By using a temporary buffer we can do so, but the cost of it
|
|
* is using more memory and longer transfer time. */
|
|
void *tmp = mbedtls_calloc( 1, num );
|
|
if( tmp != NULL )
|
|
{
|
|
mbedtls_platform_memcpy( tmp, src, num );
|
|
mbedtls_platform_memcpy( dst, tmp, num );
|
|
mbedtls_free( tmp );
|
|
return 0;
|
|
}
|
|
|
|
return MBEDTLS_ERR_PLATFORM_ALLOC_FAILED;
|
|
}
|
|
|
|
int mbedtls_platform_memequal( const void *buf1, const void *buf2, size_t num )
|
|
{
|
|
volatile const unsigned char *A = (volatile const unsigned char *) buf1;
|
|
volatile const unsigned char *B = (volatile const unsigned char *) buf2;
|
|
volatile unsigned char diff = 0;
|
|
|
|
/* Start from a random location and check the correct number of iterations */
|
|
size_t i, flow_counter = 0;
|
|
size_t start_offset = (size_t) mbedtls_platform_random_in_range( (uint32_t) num );
|
|
|
|
for( i = start_offset; i < num; i++ )
|
|
{
|
|
unsigned char x = A[i], y = B[i];
|
|
flow_counter++;
|
|
diff |= x ^ y;
|
|
}
|
|
|
|
for( i = 0; i < start_offset; i++ )
|
|
{
|
|
unsigned char x = A[i], y = B[i];
|
|
flow_counter++;
|
|
diff |= x ^ y;
|
|
}
|
|
|
|
/* Return 0 only when diff is 0 and flow_counter is equal to num */
|
|
return( (int) diff | (int) ( flow_counter ^ num ) );
|
|
}
|
|
|
|
/* This function implements a non-cryptographic random number generator based
|
|
* on the linear congruential generator algorithm. Additionally, if the
|
|
* MBEDTLS_ENTROPY_HARDWARE_ALT flag is defined, the seed is set at the first
|
|
* call of this function with using a hardware random number generator and
|
|
* changed every RAND_SEED_LIFE number of iterations.
|
|
*
|
|
* The value of the returned number is in the range [0; 0xffff].
|
|
*
|
|
* Note: The range of values with a 16-bit precision is related to the modulo
|
|
* parameter of the generator and the fact that the function does not return the
|
|
* full value of the internal state of the generator.
|
|
*/
|
|
static uint32_t mbedtls_platform_random_uint16( void )
|
|
{
|
|
/* Set random_state - the first random value should not be zero. */
|
|
static uint32_t random_state = RAND_INCREMENT;
|
|
|
|
#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT)
|
|
|
|
static uint32_t random_seed_life = 0;
|
|
|
|
if( 0 < random_seed_life )
|
|
{
|
|
--random_seed_life;
|
|
}
|
|
else
|
|
{
|
|
size_t olen = 0;
|
|
uint32_t hw_random;
|
|
mbedtls_hardware_poll( NULL,
|
|
(unsigned char *) &hw_random, sizeof( hw_random ),
|
|
&olen );
|
|
if( olen == sizeof( hw_random ) )
|
|
{
|
|
random_state ^= hw_random;
|
|
random_seed_life = RAND_SEED_LIFE;
|
|
}
|
|
}
|
|
|
|
#endif /* MBEDTLS_ENTROPY_HARDWARE_ALT */
|
|
|
|
random_state = ( ( random_state * RAND_MULTIPLIER ) + RAND_INCREMENT ) % RAND_MODULUS;
|
|
|
|
/* Do not return the entire random_state to hide generator predictability for
|
|
* the next iteration */
|
|
return( ( random_state >> 15 ) & 0xffff );
|
|
}
|
|
|
|
uint32_t mbedtls_platform_random_uint32( void )
|
|
{
|
|
return( ( mbedtls_platform_random_uint16() << 16 ) |
|
|
mbedtls_platform_random_uint16() );
|
|
}
|
|
|
|
uint32_t mbedtls_platform_random_in_range( uint32_t num )
|
|
{
|
|
uint32_t result;
|
|
|
|
if( num <= 1 )
|
|
{
|
|
result = 0;
|
|
}
|
|
else
|
|
{
|
|
result = mbedtls_platform_random_uint32() % num;
|
|
}
|
|
|
|
return( result );
|
|
}
|
|
|
|
void mbedtls_platform_random_delay( void )
|
|
{
|
|
uint32_t rn_1, rn_2, rn_3;
|
|
volatile size_t i = 0;
|
|
uint8_t shift;
|
|
|
|
rn_1 = mbedtls_platform_random_in_range( MAX_RAND_DELAY );
|
|
rn_2 = mbedtls_platform_random_in_range( 0xffffffff ) + 1;
|
|
rn_3 = mbedtls_platform_random_in_range( 0xffffffff ) + 1;
|
|
|
|
do
|
|
{
|
|
i++;
|
|
/* Dummy calculations to increase the time between iterations and
|
|
* make side channel attack more difficult by reducing predictability
|
|
* of its behaviour */
|
|
shift = rn_2 & 0x07;
|
|
if ( i % 2 )
|
|
rn_2 = ( rn_2 >> shift ) | ( rn_2 << ( 32 - shift ) );
|
|
else
|
|
rn_3 = ( rn_3 << shift ) | ( rn_3 >> ( 32 - shift ) );
|
|
rn_2 ^= rn_3;
|
|
} while( i < rn_1 || rn_2 == 0 || rn_3 == 0 );
|
|
}
|
|
|
|
#if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_PLATFORM_GMTIME_R_ALT)
|
|
#include <time.h>
|
|
#if !defined(_WIN32) && (defined(unix) || \
|
|
defined(__unix) || defined(__unix__) || (defined(__APPLE__) && \
|
|
defined(__MACH__)))
|
|
#include <unistd.h>
|
|
#endif /* !_WIN32 && (unix || __unix || __unix__ ||
|
|
* (__APPLE__ && __MACH__)) */
|
|
|
|
#if !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) || \
|
|
( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) && \
|
|
_POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) )
|
|
/*
|
|
* This is a convenience shorthand macro to avoid checking the long
|
|
* preprocessor conditions above. Ideally, we could expose this macro in
|
|
* platform_util.h and simply use it in platform_util.c, threading.c and
|
|
* threading.h. However, this macro is not part of the Mbed TLS public API, so
|
|
* we keep it private by only defining it in this file
|
|
*/
|
|
#if ! ( defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) )
|
|
#define PLATFORM_UTIL_USE_GMTIME
|
|
#endif /* ! ( defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) ) */
|
|
|
|
#endif /* !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) || \
|
|
( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) && \
|
|
_POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) ) */
|
|
|
|
struct tm *mbedtls_platform_gmtime_r( const mbedtls_time_t *tt,
|
|
struct tm *tm_buf )
|
|
{
|
|
#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
|
|
return( ( gmtime_s( tm_buf, tt ) == 0 ) ? tm_buf : NULL );
|
|
#elif !defined(PLATFORM_UTIL_USE_GMTIME)
|
|
return( gmtime_r( tt, tm_buf ) );
|
|
#else
|
|
struct tm *lt;
|
|
|
|
#if defined(MBEDTLS_THREADING_C)
|
|
if( mbedtls_mutex_lock( &mbedtls_threading_gmtime_mutex ) != 0 )
|
|
return( NULL );
|
|
#endif /* MBEDTLS_THREADING_C */
|
|
|
|
lt = gmtime( tt );
|
|
|
|
if( lt != NULL )
|
|
{
|
|
memcpy( tm_buf, lt, sizeof( struct tm ) );
|
|
}
|
|
|
|
#if defined(MBEDTLS_THREADING_C)
|
|
if( mbedtls_mutex_unlock( &mbedtls_threading_gmtime_mutex ) != 0 )
|
|
return( NULL );
|
|
#endif /* MBEDTLS_THREADING_C */
|
|
|
|
return( ( lt == NULL ) ? NULL : tm_buf );
|
|
#endif /* _WIN32 && !EFIX64 && !EFI32 */
|
|
}
|
|
#endif /* MBEDTLS_HAVE_TIME_DATE && MBEDTLS_PLATFORM_GMTIME_R_ALT */
|
|
|
|
unsigned char* mbedtls_platform_put_uint32_be( unsigned char *buf,
|
|
size_t num )
|
|
{
|
|
*buf++ = (unsigned char) ( num >> 24 );
|
|
*buf++ = (unsigned char) ( num >> 16 );
|
|
*buf++ = (unsigned char) ( num >> 8 );
|
|
*buf++ = (unsigned char) ( num );
|
|
|
|
return buf;
|
|
}
|
|
|
|
unsigned char* mbedtls_platform_put_uint24_be( unsigned char *buf,
|
|
size_t num )
|
|
{
|
|
*buf++ = (unsigned char) ( num >> 16 );
|
|
*buf++ = (unsigned char) ( num >> 8 );
|
|
*buf++ = (unsigned char) ( num );
|
|
|
|
return buf;
|
|
}
|
|
|
|
unsigned char* mbedtls_platform_put_uint16_be( unsigned char *buf,
|
|
size_t num )
|
|
{
|
|
*buf++ = (unsigned char) ( num >> 8 );
|
|
*buf++ = (unsigned char) ( num );
|
|
|
|
return buf;
|
|
}
|
|
|
|
size_t mbedtls_platform_get_uint32_be( const unsigned char *buf )
|
|
{
|
|
return ( ( (unsigned int) buf[0] << 24 ) |
|
|
( (unsigned int) buf[1] << 16 ) |
|
|
( (unsigned int) buf[2] << 8 ) |
|
|
( (unsigned int) buf[3] ) );
|
|
}
|
|
|
|
size_t mbedtls_platform_get_uint24_be( const unsigned char *buf )
|
|
{
|
|
return ( ( buf[0] << 16 ) |
|
|
( buf[1] << 8) |
|
|
( buf[2] ) );
|
|
}
|
|
|
|
size_t mbedtls_platform_get_uint16_be( const unsigned char *buf )
|
|
{
|
|
return ( ( buf[0] << 8 ) |
|
|
( buf[1] ) );
|
|
}
|