2011-12-03 22:45:14 +01:00
|
|
|
/*
|
|
|
|
* Platform-specific and custom entropy polling functions
|
|
|
|
*
|
2020-08-07 13:07:28 +02:00
|
|
|
* Copyright The Mbed TLS Contributors
|
2023-11-02 20:47:20 +01:00
|
|
|
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
2011-12-03 22:45:14 +01:00
|
|
|
*/
|
|
|
|
|
2020-09-30 22:18:13 +02:00
|
|
|
#if defined(__linux__) && !defined(_GNU_SOURCE)
|
2017-12-05 13:08:15 +01:00
|
|
|
/* Ensure that syscall() is available even when compiling with -std=c99 */
|
|
|
|
#define _GNU_SOURCE
|
|
|
|
#endif
|
|
|
|
|
2020-06-03 01:43:33 +02:00
|
|
|
#include "common.h"
|
2011-12-03 22:45:14 +01:00
|
|
|
|
2018-06-01 14:38:45 +02:00
|
|
|
#include <string.h>
|
|
|
|
|
2015-04-08 12:49:31 +02:00
|
|
|
#if defined(MBEDTLS_ENTROPY_C)
|
2011-12-03 22:45:14 +01:00
|
|
|
|
2015-03-09 18:05:11 +01:00
|
|
|
#include "mbedtls/entropy.h"
|
2021-03-09 20:11:19 +01:00
|
|
|
#include "entropy_poll.h"
|
2019-11-22 14:21:35 +01:00
|
|
|
#include "mbedtls/error.h"
|
2011-12-03 22:45:14 +01:00
|
|
|
|
2015-04-08 12:49:31 +02:00
|
|
|
#if defined(MBEDTLS_TIMING_C)
|
2015-03-09 18:05:11 +01:00
|
|
|
#include "mbedtls/timing.h"
|
2011-12-03 22:45:14 +01:00
|
|
|
#endif
|
2016-06-01 12:29:42 +02:00
|
|
|
#include "mbedtls/platform.h"
|
2011-12-03 22:45:14 +01:00
|
|
|
|
2015-04-08 12:49:31 +02:00
|
|
|
#if !defined(MBEDTLS_NO_PLATFORM_ENTROPY)
|
2016-02-22 10:33:34 +01:00
|
|
|
|
|
|
|
#if !defined(unix) && !defined(__unix__) && !defined(__unix) && \
|
2018-04-12 02:27:32 +02:00
|
|
|
!defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \
|
2024-01-22 11:29:49 +01:00
|
|
|
!defined(__HAIKU__) && !defined(__midipix__) && !defined(__MVS__)
|
2023-01-11 14:50:10 +01:00
|
|
|
#error \
|
|
|
|
"Platform entropy sources only work on Unix and Windows, see MBEDTLS_NO_PLATFORM_ENTROPY in mbedtls_config.h"
|
2016-02-22 10:33:34 +01:00
|
|
|
#endif
|
|
|
|
|
2013-10-28 18:48:30 +01:00
|
|
|
#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
|
2011-12-03 22:45:14 +01:00
|
|
|
|
2012-11-02 12:06:08 +01:00
|
|
|
#include <windows.h>
|
2016-12-15 18:27:16 +01:00
|
|
|
#include <bcrypt.h>
|
|
|
|
#include <intsafe.h>
|
2011-12-03 22:45:14 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
int mbedtls_platform_entropy_poll(void *data, unsigned char *output, size_t len,
|
|
|
|
size_t *olen)
|
2011-12-03 22:45:14 +01:00
|
|
|
{
|
2011-12-05 14:54:00 +01:00
|
|
|
((void) data);
|
2011-12-03 22:45:14 +01:00
|
|
|
*olen = 0;
|
|
|
|
|
2016-12-15 18:27:16 +01:00
|
|
|
/*
|
2018-03-14 18:02:16 +01:00
|
|
|
* BCryptGenRandom takes ULONG for size, which is smaller than size_t on
|
2023-09-08 15:47:37 +02:00
|
|
|
* 64-bit Windows platforms. Extract entropy in chunks of len (dependent
|
|
|
|
* on ULONG_MAX) size.
|
2016-12-15 18:27:16 +01:00
|
|
|
*/
|
2023-09-06 16:00:58 +02:00
|
|
|
while (len != 0) {
|
|
|
|
unsigned long ulong_bytes =
|
|
|
|
(len > ULONG_MAX) ? ULONG_MAX : (unsigned long) len;
|
2011-12-03 22:45:14 +01:00
|
|
|
|
2023-09-06 16:00:58 +02:00
|
|
|
if (!BCRYPT_SUCCESS(BCryptGenRandom(NULL, output, ulong_bytes,
|
|
|
|
BCRYPT_USE_SYSTEM_PREFERRED_RNG))) {
|
|
|
|
return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
|
|
|
|
}
|
2011-12-03 22:45:14 +01:00
|
|
|
|
2023-09-06 16:00:58 +02:00
|
|
|
*olen += ulong_bytes;
|
|
|
|
len -= ulong_bytes;
|
|
|
|
}
|
2011-12-03 22:45:14 +01:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return 0;
|
2011-12-03 22:45:14 +01:00
|
|
|
}
|
2014-05-01 13:03:14 +02:00
|
|
|
#else /* _WIN32 && !EFIX64 && !EFI32 */
|
2011-12-03 22:45:14 +01:00
|
|
|
|
2015-01-09 14:34:13 +01:00
|
|
|
/*
|
|
|
|
* Test for Linux getrandom() support.
|
2020-09-30 22:11:13 +02:00
|
|
|
* Since there is no wrapper in the libc yet, use the generic syscall wrapper
|
2015-01-09 14:34:13 +01:00
|
|
|
* available in GNU libc and compatible libc's (eg uClibc).
|
|
|
|
*/
|
2020-09-30 22:11:13 +02:00
|
|
|
#if ((defined(__linux__) && defined(__GLIBC__)) || defined(__midipix__))
|
2015-01-09 14:34:13 +01:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/syscall.h>
|
|
|
|
#if defined(SYS_getrandom)
|
|
|
|
#define HAVE_GETRANDOM
|
Entropy: Fall through to /dev/random if getrandom() syscall unknown
This commit fixes issue #1212 related to platform-specific entropy
polling in an syscall-emulated environment.
Previously, the implementation of the entropy gathering function
`mbedtls_platform_entropy_poll()` for linux machines used the
following logic to determine how to obtain entropy from the kernel:
1. If the getrandom() system call identifier SYS_getrandom is present and
the kernel version is 3.17 or higher, use syscall( SYS_getrandom, ... )
2. Otherwise, fall back to reading from /dev/random.
There are two issues with this:
1. Portability:
When cross-compiling the code for a different
architecture and running it through system call
emulation in qemu, qemu reports the host kernel
version through uname but, as of v.2.5.0,
doesn't support emulating the getrandom() syscall.
This leads to `mbedtls_platform_entropy_poll()`
failing even though reading from /dev/random would
have worked.
2. Style:
Extracting the linux kernel version from
the output of `uname` is slightly tedious.
This commit fixes both by implementing the suggestion in #1212:
- It removes the kernel-version detection through uname().
- Instead, it checks whether `syscall( SYS_getrandom, ... )`
fails with errno set to ENOSYS indicating an unknown system call.
If so, it falls through to trying to read from /dev/random.
Fixes #1212.
2018-10-18 12:49:25 +02:00
|
|
|
#include <errno.h>
|
2015-06-22 18:06:17 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
static int getrandom_wrapper(void *buf, size_t buflen, unsigned int flags)
|
2015-01-09 14:34:13 +01:00
|
|
|
{
|
2015-06-22 18:06:17 +02:00
|
|
|
/* MemSan cannot understand that the syscall writes to the buffer */
|
|
|
|
#if defined(__has_feature)
|
|
|
|
#if __has_feature(memory_sanitizer)
|
2023-01-11 14:50:10 +01:00
|
|
|
memset(buf, 0, buflen);
|
2015-06-22 18:06:17 +02:00
|
|
|
#endif
|
|
|
|
#endif
|
2023-11-04 00:32:39 +01:00
|
|
|
return (int) syscall(SYS_getrandom, buf, buflen, flags);
|
2015-01-09 14:34:13 +01:00
|
|
|
}
|
2015-04-29 14:03:28 +02:00
|
|
|
#endif /* SYS_getrandom */
|
2020-05-20 11:32:39 +02:00
|
|
|
#endif /* __linux__ || __midipix__ */
|
2015-01-09 14:34:13 +01:00
|
|
|
|
2020-12-28 16:51:14 +01:00
|
|
|
#if defined(__FreeBSD__) || defined(__DragonFly__)
|
|
|
|
#include <sys/param.h>
|
|
|
|
#if (defined(__FreeBSD__) && __FreeBSD_version >= 1200000) || \
|
|
|
|
(defined(__DragonFly__) && __DragonFly_version >= 500700)
|
|
|
|
#include <errno.h>
|
|
|
|
#include <sys/random.h>
|
|
|
|
#define HAVE_GETRANDOM
|
2023-01-11 14:50:10 +01:00
|
|
|
static int getrandom_wrapper(void *buf, size_t buflen, unsigned int flags)
|
2020-12-28 16:51:14 +01:00
|
|
|
{
|
2023-11-04 00:32:39 +01:00
|
|
|
return (int) getrandom(buf, buflen, flags);
|
2020-12-28 16:51:14 +01:00
|
|
|
}
|
|
|
|
#endif /* (__FreeBSD__ && __FreeBSD_version >= 1200000) ||
|
|
|
|
(__DragonFly__ && __DragonFly_version >= 500700) */
|
|
|
|
#endif /* __FreeBSD__ || __DragonFly__ */
|
|
|
|
|
2020-06-11 14:32:13 +02:00
|
|
|
/*
|
|
|
|
* Some BSD systems provide KERN_ARND.
|
|
|
|
* This is equivalent to reading from /dev/urandom, only it doesn't require an
|
|
|
|
* open file descriptor, and provides up to 256 bytes per call (basically the
|
|
|
|
* same as getentropy(), but with a longer history).
|
|
|
|
*
|
|
|
|
* Documentation: https://netbsd.gw.com/cgi-bin/man-cgi?sysctl+7
|
|
|
|
*/
|
|
|
|
#if (defined(__FreeBSD__) || defined(__NetBSD__)) && !defined(HAVE_GETRANDOM)
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/sysctl.h>
|
|
|
|
#if defined(KERN_ARND)
|
|
|
|
#define HAVE_SYSCTL_ARND
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
static int sysctl_arnd_wrapper(unsigned char *buf, size_t buflen)
|
2020-06-11 14:32:13 +02:00
|
|
|
{
|
|
|
|
int name[2];
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
name[0] = CTL_KERN;
|
|
|
|
name[1] = KERN_ARND;
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
while (buflen > 0) {
|
2020-06-11 14:32:13 +02:00
|
|
|
len = buflen > 256 ? 256 : buflen;
|
2023-01-11 14:50:10 +01:00
|
|
|
if (sysctl(name, 2, buf, &len, NULL, 0) == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
2020-06-11 14:32:13 +02:00
|
|
|
buflen -= len;
|
2020-06-24 18:15:02 +02:00
|
|
|
buf += len;
|
2020-06-11 14:32:13 +02:00
|
|
|
}
|
2023-01-11 14:50:10 +01:00
|
|
|
return 0;
|
2020-06-11 14:32:13 +02:00
|
|
|
}
|
|
|
|
#endif /* KERN_ARND */
|
|
|
|
#endif /* __FreeBSD__ || __NetBSD__ */
|
|
|
|
|
2011-12-03 22:45:14 +01:00
|
|
|
#include <stdio.h>
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
int mbedtls_platform_entropy_poll(void *data,
|
|
|
|
unsigned char *output, size_t len, size_t *olen)
|
2011-12-03 22:45:14 +01:00
|
|
|
{
|
|
|
|
FILE *file;
|
2015-08-27 12:02:40 +02:00
|
|
|
size_t read_len;
|
2019-11-22 14:21:35 +01:00
|
|
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
2011-12-03 22:45:14 +01:00
|
|
|
((void) data);
|
|
|
|
|
2015-04-29 14:03:28 +02:00
|
|
|
#if defined(HAVE_GETRANDOM)
|
2023-01-11 14:50:10 +01:00
|
|
|
ret = getrandom_wrapper(output, len, 0);
|
|
|
|
if (ret >= 0) {
|
2023-11-04 00:32:39 +01:00
|
|
|
*olen = (size_t) ret;
|
2023-01-11 14:50:10 +01:00
|
|
|
return 0;
|
|
|
|
} else if (errno != ENOSYS) {
|
|
|
|
return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
|
2015-04-29 14:03:28 +02:00
|
|
|
}
|
Entropy: Fall through to /dev/random if getrandom() syscall unknown
This commit fixes issue #1212 related to platform-specific entropy
polling in an syscall-emulated environment.
Previously, the implementation of the entropy gathering function
`mbedtls_platform_entropy_poll()` for linux machines used the
following logic to determine how to obtain entropy from the kernel:
1. If the getrandom() system call identifier SYS_getrandom is present and
the kernel version is 3.17 or higher, use syscall( SYS_getrandom, ... )
2. Otherwise, fall back to reading from /dev/random.
There are two issues with this:
1. Portability:
When cross-compiling the code for a different
architecture and running it through system call
emulation in qemu, qemu reports the host kernel
version through uname but, as of v.2.5.0,
doesn't support emulating the getrandom() syscall.
This leads to `mbedtls_platform_entropy_poll()`
failing even though reading from /dev/random would
have worked.
2. Style:
Extracting the linux kernel version from
the output of `uname` is slightly tedious.
This commit fixes both by implementing the suggestion in #1212:
- It removes the kernel-version detection through uname().
- Instead, it checks whether `syscall( SYS_getrandom, ... )`
fails with errno set to ENOSYS indicating an unknown system call.
If so, it falls through to trying to read from /dev/random.
Fixes #1212.
2018-10-18 12:49:25 +02:00
|
|
|
/* Fall through if the system call isn't known. */
|
|
|
|
#else
|
2018-11-05 12:43:07 +01:00
|
|
|
((void) ret);
|
2015-04-29 14:03:28 +02:00
|
|
|
#endif /* HAVE_GETRANDOM */
|
|
|
|
|
2020-06-11 14:32:13 +02:00
|
|
|
#if defined(HAVE_SYSCTL_ARND)
|
|
|
|
((void) file);
|
|
|
|
((void) read_len);
|
2023-01-11 14:50:10 +01:00
|
|
|
if (sysctl_arnd_wrapper(output, len) == -1) {
|
|
|
|
return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
|
|
|
|
}
|
2020-06-11 14:32:13 +02:00
|
|
|
*olen = len;
|
2023-01-11 14:50:10 +01:00
|
|
|
return 0;
|
2020-06-11 14:32:13 +02:00
|
|
|
#else
|
|
|
|
|
2011-12-03 22:45:14 +01:00
|
|
|
*olen = 0;
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
file = fopen("/dev/urandom", "rb");
|
|
|
|
if (file == NULL) {
|
|
|
|
return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
|
|
|
|
}
|
2014-05-01 13:03:14 +02:00
|
|
|
|
2022-06-30 17:03:40 +02:00
|
|
|
/* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
|
2023-01-11 14:50:10 +01:00
|
|
|
mbedtls_setbuf(file, NULL);
|
2022-06-30 17:03:40 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
read_len = fread(output, 1, len, file);
|
|
|
|
if (read_len != len) {
|
|
|
|
fclose(file);
|
|
|
|
return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
|
2011-12-03 22:45:14 +01:00
|
|
|
}
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
fclose(file);
|
2011-12-03 22:45:14 +01:00
|
|
|
*olen = len;
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return 0;
|
2020-06-11 14:32:13 +02:00
|
|
|
#endif /* HAVE_SYSCTL_ARND */
|
2011-12-03 22:45:14 +01:00
|
|
|
}
|
2014-05-01 13:03:14 +02:00
|
|
|
#endif /* _WIN32 && !EFIX64 && !EFI32 */
|
2015-04-08 12:49:31 +02:00
|
|
|
#endif /* !MBEDTLS_NO_PLATFORM_ENTROPY */
|
2011-12-03 22:45:14 +01:00
|
|
|
|
2016-06-01 12:29:42 +02:00
|
|
|
#if defined(MBEDTLS_ENTROPY_NV_SEED)
|
2023-01-11 14:50:10 +01:00
|
|
|
int mbedtls_nv_seed_poll(void *data,
|
|
|
|
unsigned char *output, size_t len, size_t *olen)
|
2016-06-01 12:29:42 +02:00
|
|
|
{
|
|
|
|
unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE];
|
|
|
|
size_t use_len = MBEDTLS_ENTROPY_BLOCK_SIZE;
|
|
|
|
((void) data);
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
memset(buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE);
|
2016-06-01 12:29:42 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (mbedtls_nv_seed_read(buf, MBEDTLS_ENTROPY_BLOCK_SIZE) < 0) {
|
|
|
|
return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
|
|
|
|
}
|
2016-06-01 12:29:42 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
if (len < use_len) {
|
|
|
|
use_len = len;
|
|
|
|
}
|
2016-06-01 12:29:42 +02:00
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
memcpy(output, buf, use_len);
|
2016-06-01 12:29:42 +02:00
|
|
|
*olen = use_len;
|
|
|
|
|
2023-01-11 14:50:10 +01:00
|
|
|
return 0;
|
2016-06-01 12:29:42 +02:00
|
|
|
}
|
|
|
|
#endif /* MBEDTLS_ENTROPY_NV_SEED */
|
|
|
|
|
2015-04-08 12:49:31 +02:00
|
|
|
#endif /* MBEDTLS_ENTROPY_C */
|