1a8e1175bSopenharmony_ci/* 2a8e1175bSopenharmony_ci * Platform-specific and custom entropy polling functions 3a8e1175bSopenharmony_ci * 4a8e1175bSopenharmony_ci * Copyright The Mbed TLS Contributors 5a8e1175bSopenharmony_ci * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 6a8e1175bSopenharmony_ci */ 7a8e1175bSopenharmony_ci 8a8e1175bSopenharmony_ci#if (defined(__linux__) || defined(__midipix__)) && !defined(_GNU_SOURCE) 9a8e1175bSopenharmony_ci/* Ensure that syscall() is available even when compiling with -std=c99 */ 10a8e1175bSopenharmony_ci#define _GNU_SOURCE 11a8e1175bSopenharmony_ci#endif 12a8e1175bSopenharmony_ci 13a8e1175bSopenharmony_ci#include "common.h" 14a8e1175bSopenharmony_ci 15a8e1175bSopenharmony_ci#include <string.h> 16a8e1175bSopenharmony_ci 17a8e1175bSopenharmony_ci#if defined(MBEDTLS_ENTROPY_C) 18a8e1175bSopenharmony_ci 19a8e1175bSopenharmony_ci#include "mbedtls/entropy.h" 20a8e1175bSopenharmony_ci#include "entropy_poll.h" 21a8e1175bSopenharmony_ci#include "mbedtls/error.h" 22a8e1175bSopenharmony_ci 23a8e1175bSopenharmony_ci#if defined(MBEDTLS_TIMING_C) 24a8e1175bSopenharmony_ci#include "mbedtls/timing.h" 25a8e1175bSopenharmony_ci#endif 26a8e1175bSopenharmony_ci#include "mbedtls/platform.h" 27a8e1175bSopenharmony_ci 28a8e1175bSopenharmony_ci#if !defined(MBEDTLS_NO_PLATFORM_ENTROPY) 29a8e1175bSopenharmony_ci 30a8e1175bSopenharmony_ci#if !defined(unix) && !defined(__unix__) && !defined(__unix) && \ 31a8e1175bSopenharmony_ci !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \ 32a8e1175bSopenharmony_ci !defined(__HAIKU__) && !defined(__midipix__) && !defined(__MVS__) 33a8e1175bSopenharmony_ci#error \ 34a8e1175bSopenharmony_ci "Platform entropy sources only work on Unix and Windows, see MBEDTLS_NO_PLATFORM_ENTROPY in mbedtls_config.h" 35a8e1175bSopenharmony_ci#endif 36a8e1175bSopenharmony_ci 37a8e1175bSopenharmony_ci#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) 38a8e1175bSopenharmony_ci 39a8e1175bSopenharmony_ci#include <windows.h> 40a8e1175bSopenharmony_ci#include <bcrypt.h> 41a8e1175bSopenharmony_ci#include <intsafe.h> 42a8e1175bSopenharmony_ci 43a8e1175bSopenharmony_ciint mbedtls_platform_entropy_poll(void *data, unsigned char *output, size_t len, 44a8e1175bSopenharmony_ci size_t *olen) 45a8e1175bSopenharmony_ci{ 46a8e1175bSopenharmony_ci ((void) data); 47a8e1175bSopenharmony_ci *olen = 0; 48a8e1175bSopenharmony_ci 49a8e1175bSopenharmony_ci /* 50a8e1175bSopenharmony_ci * BCryptGenRandom takes ULONG for size, which is smaller than size_t on 51a8e1175bSopenharmony_ci * 64-bit Windows platforms. Extract entropy in chunks of len (dependent 52a8e1175bSopenharmony_ci * on ULONG_MAX) size. 53a8e1175bSopenharmony_ci */ 54a8e1175bSopenharmony_ci while (len != 0) { 55a8e1175bSopenharmony_ci unsigned long ulong_bytes = 56a8e1175bSopenharmony_ci (len > ULONG_MAX) ? ULONG_MAX : (unsigned long) len; 57a8e1175bSopenharmony_ci 58a8e1175bSopenharmony_ci if (!BCRYPT_SUCCESS(BCryptGenRandom(NULL, output, ulong_bytes, 59a8e1175bSopenharmony_ci BCRYPT_USE_SYSTEM_PREFERRED_RNG))) { 60a8e1175bSopenharmony_ci return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; 61a8e1175bSopenharmony_ci } 62a8e1175bSopenharmony_ci 63a8e1175bSopenharmony_ci *olen += ulong_bytes; 64a8e1175bSopenharmony_ci len -= ulong_bytes; 65a8e1175bSopenharmony_ci } 66a8e1175bSopenharmony_ci 67a8e1175bSopenharmony_ci return 0; 68a8e1175bSopenharmony_ci} 69a8e1175bSopenharmony_ci#else /* _WIN32 && !EFIX64 && !EFI32 */ 70a8e1175bSopenharmony_ci 71a8e1175bSopenharmony_ci/* 72a8e1175bSopenharmony_ci * Test for Linux getrandom() support. 73a8e1175bSopenharmony_ci * Since there is no wrapper in the libc yet, use the generic syscall wrapper 74a8e1175bSopenharmony_ci * available in GNU libc and compatible libc's (eg uClibc). 75a8e1175bSopenharmony_ci */ 76a8e1175bSopenharmony_ci#if ((defined(__linux__) && defined(__GLIBC__)) || defined(__midipix__)) 77a8e1175bSopenharmony_ci#include <unistd.h> 78a8e1175bSopenharmony_ci#include <sys/syscall.h> 79a8e1175bSopenharmony_ci#if defined(SYS_getrandom) 80a8e1175bSopenharmony_ci#define HAVE_GETRANDOM 81a8e1175bSopenharmony_ci#include <errno.h> 82a8e1175bSopenharmony_ci 83a8e1175bSopenharmony_cistatic int getrandom_wrapper(void *buf, size_t buflen, unsigned int flags) 84a8e1175bSopenharmony_ci{ 85a8e1175bSopenharmony_ci /* MemSan cannot understand that the syscall writes to the buffer */ 86a8e1175bSopenharmony_ci#if defined(__has_feature) 87a8e1175bSopenharmony_ci#if __has_feature(memory_sanitizer) 88a8e1175bSopenharmony_ci memset(buf, 0, buflen); 89a8e1175bSopenharmony_ci#endif 90a8e1175bSopenharmony_ci#endif 91a8e1175bSopenharmony_ci return (int) syscall(SYS_getrandom, buf, buflen, flags); 92a8e1175bSopenharmony_ci} 93a8e1175bSopenharmony_ci#endif /* SYS_getrandom */ 94a8e1175bSopenharmony_ci#endif /* __linux__ || __midipix__ */ 95a8e1175bSopenharmony_ci 96a8e1175bSopenharmony_ci#if defined(__FreeBSD__) || defined(__DragonFly__) 97a8e1175bSopenharmony_ci#include <sys/param.h> 98a8e1175bSopenharmony_ci#if (defined(__FreeBSD__) && __FreeBSD_version >= 1200000) || \ 99a8e1175bSopenharmony_ci (defined(__DragonFly__) && __DragonFly_version >= 500700) 100a8e1175bSopenharmony_ci#include <errno.h> 101a8e1175bSopenharmony_ci#include <sys/random.h> 102a8e1175bSopenharmony_ci#define HAVE_GETRANDOM 103a8e1175bSopenharmony_cistatic int getrandom_wrapper(void *buf, size_t buflen, unsigned int flags) 104a8e1175bSopenharmony_ci{ 105a8e1175bSopenharmony_ci return (int) getrandom(buf, buflen, flags); 106a8e1175bSopenharmony_ci} 107a8e1175bSopenharmony_ci#endif /* (__FreeBSD__ && __FreeBSD_version >= 1200000) || 108a8e1175bSopenharmony_ci (__DragonFly__ && __DragonFly_version >= 500700) */ 109a8e1175bSopenharmony_ci#endif /* __FreeBSD__ || __DragonFly__ */ 110a8e1175bSopenharmony_ci 111a8e1175bSopenharmony_ci/* 112a8e1175bSopenharmony_ci * Some BSD systems provide KERN_ARND. 113a8e1175bSopenharmony_ci * This is equivalent to reading from /dev/urandom, only it doesn't require an 114a8e1175bSopenharmony_ci * open file descriptor, and provides up to 256 bytes per call (basically the 115a8e1175bSopenharmony_ci * same as getentropy(), but with a longer history). 116a8e1175bSopenharmony_ci * 117a8e1175bSopenharmony_ci * Documentation: https://netbsd.gw.com/cgi-bin/man-cgi?sysctl+7 118a8e1175bSopenharmony_ci */ 119a8e1175bSopenharmony_ci#if (defined(__FreeBSD__) || defined(__NetBSD__)) && !defined(HAVE_GETRANDOM) 120a8e1175bSopenharmony_ci#include <sys/param.h> 121a8e1175bSopenharmony_ci#include <sys/sysctl.h> 122a8e1175bSopenharmony_ci#if defined(KERN_ARND) 123a8e1175bSopenharmony_ci#define HAVE_SYSCTL_ARND 124a8e1175bSopenharmony_ci 125a8e1175bSopenharmony_cistatic int sysctl_arnd_wrapper(unsigned char *buf, size_t buflen) 126a8e1175bSopenharmony_ci{ 127a8e1175bSopenharmony_ci int name[2]; 128a8e1175bSopenharmony_ci size_t len; 129a8e1175bSopenharmony_ci 130a8e1175bSopenharmony_ci name[0] = CTL_KERN; 131a8e1175bSopenharmony_ci name[1] = KERN_ARND; 132a8e1175bSopenharmony_ci 133a8e1175bSopenharmony_ci while (buflen > 0) { 134a8e1175bSopenharmony_ci len = buflen > 256 ? 256 : buflen; 135a8e1175bSopenharmony_ci if (sysctl(name, 2, buf, &len, NULL, 0) == -1) { 136a8e1175bSopenharmony_ci return -1; 137a8e1175bSopenharmony_ci } 138a8e1175bSopenharmony_ci buflen -= len; 139a8e1175bSopenharmony_ci buf += len; 140a8e1175bSopenharmony_ci } 141a8e1175bSopenharmony_ci return 0; 142a8e1175bSopenharmony_ci} 143a8e1175bSopenharmony_ci#endif /* KERN_ARND */ 144a8e1175bSopenharmony_ci#endif /* __FreeBSD__ || __NetBSD__ */ 145a8e1175bSopenharmony_ci 146a8e1175bSopenharmony_ci#include <stdio.h> 147a8e1175bSopenharmony_ci 148a8e1175bSopenharmony_ciint mbedtls_platform_entropy_poll(void *data, 149a8e1175bSopenharmony_ci unsigned char *output, size_t len, size_t *olen) 150a8e1175bSopenharmony_ci{ 151a8e1175bSopenharmony_ci FILE *file; 152a8e1175bSopenharmony_ci size_t read_len; 153a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 154a8e1175bSopenharmony_ci ((void) data); 155a8e1175bSopenharmony_ci 156a8e1175bSopenharmony_ci#if defined(HAVE_GETRANDOM) 157a8e1175bSopenharmony_ci ret = getrandom_wrapper(output, len, 0); 158a8e1175bSopenharmony_ci if (ret >= 0) { 159a8e1175bSopenharmony_ci *olen = (size_t) ret; 160a8e1175bSopenharmony_ci return 0; 161a8e1175bSopenharmony_ci } else if (errno != ENOSYS) { 162a8e1175bSopenharmony_ci return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; 163a8e1175bSopenharmony_ci } 164a8e1175bSopenharmony_ci /* Fall through if the system call isn't known. */ 165a8e1175bSopenharmony_ci#else 166a8e1175bSopenharmony_ci ((void) ret); 167a8e1175bSopenharmony_ci#endif /* HAVE_GETRANDOM */ 168a8e1175bSopenharmony_ci 169a8e1175bSopenharmony_ci#if defined(HAVE_SYSCTL_ARND) 170a8e1175bSopenharmony_ci ((void) file); 171a8e1175bSopenharmony_ci ((void) read_len); 172a8e1175bSopenharmony_ci if (sysctl_arnd_wrapper(output, len) == -1) { 173a8e1175bSopenharmony_ci return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; 174a8e1175bSopenharmony_ci } 175a8e1175bSopenharmony_ci *olen = len; 176a8e1175bSopenharmony_ci return 0; 177a8e1175bSopenharmony_ci#else 178a8e1175bSopenharmony_ci 179a8e1175bSopenharmony_ci *olen = 0; 180a8e1175bSopenharmony_ci 181a8e1175bSopenharmony_ci file = fopen("/dev/urandom", "rb"); 182a8e1175bSopenharmony_ci if (file == NULL) { 183a8e1175bSopenharmony_ci return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; 184a8e1175bSopenharmony_ci } 185a8e1175bSopenharmony_ci 186a8e1175bSopenharmony_ci /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */ 187a8e1175bSopenharmony_ci mbedtls_setbuf(file, NULL); 188a8e1175bSopenharmony_ci 189a8e1175bSopenharmony_ci read_len = fread(output, 1, len, file); 190a8e1175bSopenharmony_ci if (read_len != len) { 191a8e1175bSopenharmony_ci fclose(file); 192a8e1175bSopenharmony_ci return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; 193a8e1175bSopenharmony_ci } 194a8e1175bSopenharmony_ci 195a8e1175bSopenharmony_ci fclose(file); 196a8e1175bSopenharmony_ci *olen = len; 197a8e1175bSopenharmony_ci 198a8e1175bSopenharmony_ci return 0; 199a8e1175bSopenharmony_ci#endif /* HAVE_SYSCTL_ARND */ 200a8e1175bSopenharmony_ci} 201a8e1175bSopenharmony_ci#endif /* _WIN32 && !EFIX64 && !EFI32 */ 202a8e1175bSopenharmony_ci#endif /* !MBEDTLS_NO_PLATFORM_ENTROPY */ 203a8e1175bSopenharmony_ci 204a8e1175bSopenharmony_ci#if defined(MBEDTLS_ENTROPY_NV_SEED) 205a8e1175bSopenharmony_ciint mbedtls_nv_seed_poll(void *data, 206a8e1175bSopenharmony_ci unsigned char *output, size_t len, size_t *olen) 207a8e1175bSopenharmony_ci{ 208a8e1175bSopenharmony_ci unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; 209a8e1175bSopenharmony_ci size_t use_len = MBEDTLS_ENTROPY_BLOCK_SIZE; 210a8e1175bSopenharmony_ci ((void) data); 211a8e1175bSopenharmony_ci 212a8e1175bSopenharmony_ci memset(buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE); 213a8e1175bSopenharmony_ci 214a8e1175bSopenharmony_ci if (mbedtls_nv_seed_read(buf, MBEDTLS_ENTROPY_BLOCK_SIZE) < 0) { 215a8e1175bSopenharmony_ci return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; 216a8e1175bSopenharmony_ci } 217a8e1175bSopenharmony_ci 218a8e1175bSopenharmony_ci if (len < use_len) { 219a8e1175bSopenharmony_ci use_len = len; 220a8e1175bSopenharmony_ci } 221a8e1175bSopenharmony_ci 222a8e1175bSopenharmony_ci memcpy(output, buf, use_len); 223a8e1175bSopenharmony_ci *olen = use_len; 224a8e1175bSopenharmony_ci 225a8e1175bSopenharmony_ci return 0; 226a8e1175bSopenharmony_ci} 227a8e1175bSopenharmony_ci#endif /* MBEDTLS_ENTROPY_NV_SEED */ 228a8e1175bSopenharmony_ci 229a8e1175bSopenharmony_ci#endif /* MBEDTLS_ENTROPY_C */ 230