Path: blob/master/thirdparty/mbedtls/library/entropy_poll.c
9903 views
/*1* Platform-specific and custom entropy polling functions2*3* Copyright The Mbed TLS Contributors4* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later5*/67#if defined(__linux__) || defined(__midipix__)8/* Ensure that syscall() is available even when compiling with -std=c99 */9#if !defined(_GNU_SOURCE)10#define _GNU_SOURCE11#endif12#endif1314#include "common.h"1516#include <string.h>1718#if defined(MBEDTLS_ENTROPY_C)1920#include "mbedtls/entropy.h"21#include "entropy_poll.h"22#include "mbedtls/error.h"2324#if defined(MBEDTLS_TIMING_C)25#include "mbedtls/timing.h"26#endif27#include "mbedtls/platform.h"2829#if !defined(MBEDTLS_NO_PLATFORM_ENTROPY)3031#if !defined(unix) && !defined(__unix__) && !defined(__unix) && \32!defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \33!defined(__HAIKU__) && !defined(__midipix__) && !defined(__MVS__)34#error \35"Platform entropy sources only work on Unix and Windows, see MBEDTLS_NO_PLATFORM_ENTROPY in mbedtls_config.h"36#endif3738#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)3940#include <windows.h>41#include <bcrypt.h>42#include <intsafe.h>4344int mbedtls_platform_entropy_poll(void *data, unsigned char *output, size_t len,45size_t *olen)46{47((void) data);48*olen = 0;4950/*51* BCryptGenRandom takes ULONG for size, which is smaller than size_t on52* 64-bit Windows platforms. Extract entropy in chunks of len (dependent53* on ULONG_MAX) size.54*/55while (len != 0) {56unsigned long ulong_bytes =57(len > ULONG_MAX) ? ULONG_MAX : (unsigned long) len;5859if (!BCRYPT_SUCCESS(BCryptGenRandom(NULL, output, ulong_bytes,60BCRYPT_USE_SYSTEM_PREFERRED_RNG))) {61return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;62}6364*olen += ulong_bytes;65len -= ulong_bytes;66}6768return 0;69}70#else /* _WIN32 && !EFIX64 && !EFI32 */7172/*73* Test for Linux getrandom() support.74* Since there is no wrapper in the libc yet, use the generic syscall wrapper75* available in GNU libc and compatible libc's (eg uClibc).76*/77#if ((defined(__linux__) && defined(__GLIBC__)) || defined(__midipix__))78#include <unistd.h>79#include <sys/syscall.h>80#if defined(SYS_getrandom)81#define HAVE_GETRANDOM82#include <errno.h>8384static int getrandom_wrapper(void *buf, size_t buflen, unsigned int flags)85{86/* MemSan cannot understand that the syscall writes to the buffer */87#if defined(__has_feature)88#if __has_feature(memory_sanitizer)89memset(buf, 0, buflen);90#endif91#endif92return (int) syscall(SYS_getrandom, buf, buflen, flags);93}94#endif /* SYS_getrandom */95#endif /* __linux__ || __midipix__ */9697#if defined(__FreeBSD__) || defined(__DragonFly__)98#include <sys/param.h>99#if (defined(__FreeBSD__) && __FreeBSD_version >= 1200000) || \100(defined(__DragonFly__) && __DragonFly_version >= 500700)101#include <errno.h>102#include <sys/random.h>103#define HAVE_GETRANDOM104static int getrandom_wrapper(void *buf, size_t buflen, unsigned int flags)105{106return (int) getrandom(buf, buflen, flags);107}108#endif /* (__FreeBSD__ && __FreeBSD_version >= 1200000) ||109(__DragonFly__ && __DragonFly_version >= 500700) */110#endif /* __FreeBSD__ || __DragonFly__ */111112/*113* Some BSD systems provide KERN_ARND.114* This is equivalent to reading from /dev/urandom, only it doesn't require an115* open file descriptor, and provides up to 256 bytes per call (basically the116* same as getentropy(), but with a longer history).117*118* Documentation: https://netbsd.gw.com/cgi-bin/man-cgi?sysctl+7119*/120#if (defined(__FreeBSD__) || defined(__NetBSD__)) && !defined(HAVE_GETRANDOM)121#include <sys/param.h>122#include <sys/sysctl.h>123#if defined(KERN_ARND)124#define HAVE_SYSCTL_ARND125126static int sysctl_arnd_wrapper(unsigned char *buf, size_t buflen)127{128int name[2];129size_t len;130131name[0] = CTL_KERN;132name[1] = KERN_ARND;133134while (buflen > 0) {135len = buflen > 256 ? 256 : buflen;136if (sysctl(name, 2, buf, &len, NULL, 0) == -1) {137return -1;138}139buflen -= len;140buf += len;141}142return 0;143}144#endif /* KERN_ARND */145#endif /* __FreeBSD__ || __NetBSD__ */146147#include <stdio.h>148149int mbedtls_platform_entropy_poll(void *data,150unsigned char *output, size_t len, size_t *olen)151{152FILE *file;153size_t read_len;154int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;155((void) data);156157#if defined(HAVE_GETRANDOM)158ret = getrandom_wrapper(output, len, 0);159if (ret >= 0) {160*olen = (size_t) ret;161return 0;162} else if (errno != ENOSYS) {163return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;164}165/* Fall through if the system call isn't known. */166#else167((void) ret);168#endif /* HAVE_GETRANDOM */169170#if defined(HAVE_SYSCTL_ARND)171((void) file);172((void) read_len);173if (sysctl_arnd_wrapper(output, len) == -1) {174return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;175}176*olen = len;177return 0;178#else179180*olen = 0;181182file = fopen("/dev/urandom", "rb");183if (file == NULL) {184return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;185}186187/* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */188mbedtls_setbuf(file, NULL);189190read_len = fread(output, 1, len, file);191if (read_len != len) {192fclose(file);193return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;194}195196fclose(file);197*olen = len;198199return 0;200#endif /* HAVE_SYSCTL_ARND */201}202#endif /* _WIN32 && !EFIX64 && !EFI32 */203#endif /* !MBEDTLS_NO_PLATFORM_ENTROPY */204205#if defined(MBEDTLS_ENTROPY_NV_SEED)206int mbedtls_nv_seed_poll(void *data,207unsigned char *output, size_t len, size_t *olen)208{209unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE];210size_t use_len = MBEDTLS_ENTROPY_BLOCK_SIZE;211((void) data);212213memset(buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE);214215if (mbedtls_nv_seed_read(buf, MBEDTLS_ENTROPY_BLOCK_SIZE) < 0) {216return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;217}218219if (len < use_len) {220use_len = len;221}222223memcpy(output, buf, use_len);224*olen = use_len;225226return 0;227}228#endif /* MBEDTLS_ENTROPY_NV_SEED */229230#endif /* MBEDTLS_ENTROPY_C */231232233