blob: 611768cd8556d588abc1cafd0088c0409a332fc9 [file] [log] [blame]
Jens Wiklander817466c2018-05-22 13:49:31 +02001/*
2 * Platform-specific and custom entropy polling functions
3 *
Jerome Forissier79013242021-07-28 10:24:04 +02004 * Copyright The Mbed TLS Contributors
Tom Van Eyckb0563632024-06-13 16:20:14 +02005 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
Jens Wiklander817466c2018-05-22 13:49:31 +02006 */
7
Sungbae Yoo4d211f32024-11-19 02:47:55 +00008#if defined(__linux__) || defined(__midipix__)
Jens Wiklander3d3b0592019-03-20 15:30:29 +01009/* Ensure that syscall() is available even when compiling with -std=c99 */
Sungbae Yoo4d211f32024-11-19 02:47:55 +000010#if !defined(_GNU_SOURCE)
Jens Wiklander3d3b0592019-03-20 15:30:29 +010011#define _GNU_SOURCE
12#endif
Sungbae Yoo4d211f32024-11-19 02:47:55 +000013#endif
Jens Wiklander3d3b0592019-03-20 15:30:29 +010014
Jerome Forissier79013242021-07-28 10:24:04 +020015#include "common.h"
Jens Wiklander817466c2018-05-22 13:49:31 +020016
Jens Wiklander3d3b0592019-03-20 15:30:29 +010017#include <string.h>
18
Jens Wiklander817466c2018-05-22 13:49:31 +020019#if defined(MBEDTLS_ENTROPY_C)
20
21#include "mbedtls/entropy.h"
Jens Wiklander32b31802023-10-06 16:59:46 +020022#include "entropy_poll.h"
Jerome Forissier11fa71b2020-04-20 17:17:56 +020023#include "mbedtls/error.h"
Jens Wiklander817466c2018-05-22 13:49:31 +020024
25#if defined(MBEDTLS_TIMING_C)
Jens Wiklander817466c2018-05-22 13:49:31 +020026#include "mbedtls/timing.h"
27#endif
Jens Wiklander817466c2018-05-22 13:49:31 +020028#include "mbedtls/platform.h"
Jens Wiklander817466c2018-05-22 13:49:31 +020029
30#if !defined(MBEDTLS_NO_PLATFORM_ENTROPY)
31
32#if !defined(unix) && !defined(__unix__) && !defined(__unix) && \
Jens Wiklander3d3b0592019-03-20 15:30:29 +010033 !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \
Tom Van Eyckb0563632024-06-13 16:20:14 +020034 !defined(__HAIKU__) && !defined(__midipix__) && !defined(__MVS__)
Jens Wiklander32b31802023-10-06 16:59:46 +020035#error \
36 "Platform entropy sources only work on Unix and Windows, see MBEDTLS_NO_PLATFORM_ENTROPY in mbedtls_config.h"
Jens Wiklander817466c2018-05-22 13:49:31 +020037#endif
38
39#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
40
Jens Wiklander817466c2018-05-22 13:49:31 +020041#include <windows.h>
Tom Van Eyckb0563632024-06-13 16:20:14 +020042#include <bcrypt.h>
43#include <intsafe.h>
Jens Wiklander817466c2018-05-22 13:49:31 +020044
Jens Wiklander32b31802023-10-06 16:59:46 +020045int mbedtls_platform_entropy_poll(void *data, unsigned char *output, size_t len,
46 size_t *olen)
Jens Wiklander817466c2018-05-22 13:49:31 +020047{
Jens Wiklander817466c2018-05-22 13:49:31 +020048 ((void) data);
49 *olen = 0;
50
Tom Van Eyckb0563632024-06-13 16:20:14 +020051 /*
52 * BCryptGenRandom takes ULONG for size, which is smaller than size_t on
53 * 64-bit Windows platforms. Extract entropy in chunks of len (dependent
54 * on ULONG_MAX) size.
55 */
56 while (len != 0) {
57 unsigned long ulong_bytes =
58 (len > ULONG_MAX) ? ULONG_MAX : (unsigned long) len;
Jens Wiklander817466c2018-05-22 13:49:31 +020059
Tom Van Eyckb0563632024-06-13 16:20:14 +020060 if (!BCRYPT_SUCCESS(BCryptGenRandom(NULL, output, ulong_bytes,
61 BCRYPT_USE_SYSTEM_PREFERRED_RNG))) {
62 return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
63 }
Jens Wiklander817466c2018-05-22 13:49:31 +020064
Tom Van Eyckb0563632024-06-13 16:20:14 +020065 *olen += ulong_bytes;
66 len -= ulong_bytes;
67 }
Jens Wiklander817466c2018-05-22 13:49:31 +020068
Jens Wiklander32b31802023-10-06 16:59:46 +020069 return 0;
Jens Wiklander817466c2018-05-22 13:49:31 +020070}
71#else /* _WIN32 && !EFIX64 && !EFI32 */
72
73/*
74 * Test for Linux getrandom() support.
75 * Since there is no wrapper in the libc yet, use the generic syscall wrapper
76 * available in GNU libc and compatible libc's (eg uClibc).
77 */
Jerome Forissier79013242021-07-28 10:24:04 +020078#if ((defined(__linux__) && defined(__GLIBC__)) || defined(__midipix__))
Jens Wiklander817466c2018-05-22 13:49:31 +020079#include <unistd.h>
80#include <sys/syscall.h>
81#if defined(SYS_getrandom)
82#define HAVE_GETRANDOM
Jens Wiklander3d3b0592019-03-20 15:30:29 +010083#include <errno.h>
Jens Wiklander817466c2018-05-22 13:49:31 +020084
Jens Wiklander32b31802023-10-06 16:59:46 +020085static int getrandom_wrapper(void *buf, size_t buflen, unsigned int flags)
Jens Wiklander817466c2018-05-22 13:49:31 +020086{
87 /* MemSan cannot understand that the syscall writes to the buffer */
88#if defined(__has_feature)
89#if __has_feature(memory_sanitizer)
Jens Wiklander32b31802023-10-06 16:59:46 +020090 memset(buf, 0, buflen);
Jens Wiklander817466c2018-05-22 13:49:31 +020091#endif
92#endif
Tom Van Eyckb0563632024-06-13 16:20:14 +020093 return (int) syscall(SYS_getrandom, buf, buflen, flags);
Jens Wiklander817466c2018-05-22 13:49:31 +020094}
Jens Wiklander817466c2018-05-22 13:49:31 +020095#endif /* SYS_getrandom */
Jerome Forissier79013242021-07-28 10:24:04 +020096#endif /* __linux__ || __midipix__ */
97
98#if defined(__FreeBSD__) || defined(__DragonFly__)
99#include <sys/param.h>
100#if (defined(__FreeBSD__) && __FreeBSD_version >= 1200000) || \
101 (defined(__DragonFly__) && __DragonFly_version >= 500700)
102#include <errno.h>
103#include <sys/random.h>
104#define HAVE_GETRANDOM
Jens Wiklander32b31802023-10-06 16:59:46 +0200105static int getrandom_wrapper(void *buf, size_t buflen, unsigned int flags)
Jerome Forissier79013242021-07-28 10:24:04 +0200106{
Tom Van Eyckb0563632024-06-13 16:20:14 +0200107 return (int) getrandom(buf, buflen, flags);
Jerome Forissier79013242021-07-28 10:24:04 +0200108}
109#endif /* (__FreeBSD__ && __FreeBSD_version >= 1200000) ||
110 (__DragonFly__ && __DragonFly_version >= 500700) */
111#endif /* __FreeBSD__ || __DragonFly__ */
112
113/*
114 * Some BSD systems provide KERN_ARND.
115 * This is equivalent to reading from /dev/urandom, only it doesn't require an
116 * open file descriptor, and provides up to 256 bytes per call (basically the
117 * same as getentropy(), but with a longer history).
118 *
119 * Documentation: https://netbsd.gw.com/cgi-bin/man-cgi?sysctl+7
120 */
121#if (defined(__FreeBSD__) || defined(__NetBSD__)) && !defined(HAVE_GETRANDOM)
122#include <sys/param.h>
123#include <sys/sysctl.h>
124#if defined(KERN_ARND)
125#define HAVE_SYSCTL_ARND
126
Jens Wiklander32b31802023-10-06 16:59:46 +0200127static int sysctl_arnd_wrapper(unsigned char *buf, size_t buflen)
Jerome Forissier79013242021-07-28 10:24:04 +0200128{
129 int name[2];
130 size_t len;
131
132 name[0] = CTL_KERN;
133 name[1] = KERN_ARND;
134
Jens Wiklander32b31802023-10-06 16:59:46 +0200135 while (buflen > 0) {
Jerome Forissier79013242021-07-28 10:24:04 +0200136 len = buflen > 256 ? 256 : buflen;
Jens Wiklander32b31802023-10-06 16:59:46 +0200137 if (sysctl(name, 2, buf, &len, NULL, 0) == -1) {
138 return -1;
139 }
Jerome Forissier79013242021-07-28 10:24:04 +0200140 buflen -= len;
141 buf += len;
142 }
Jens Wiklander32b31802023-10-06 16:59:46 +0200143 return 0;
Jerome Forissier79013242021-07-28 10:24:04 +0200144}
145#endif /* KERN_ARND */
146#endif /* __FreeBSD__ || __NetBSD__ */
Jens Wiklander817466c2018-05-22 13:49:31 +0200147
148#include <stdio.h>
149
Jens Wiklander32b31802023-10-06 16:59:46 +0200150int mbedtls_platform_entropy_poll(void *data,
151 unsigned char *output, size_t len, size_t *olen)
Jens Wiklander817466c2018-05-22 13:49:31 +0200152{
153 FILE *file;
154 size_t read_len;
Jerome Forissier11fa71b2020-04-20 17:17:56 +0200155 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Jens Wiklander817466c2018-05-22 13:49:31 +0200156 ((void) data);
157
158#if defined(HAVE_GETRANDOM)
Jens Wiklander32b31802023-10-06 16:59:46 +0200159 ret = getrandom_wrapper(output, len, 0);
160 if (ret >= 0) {
Tom Van Eyckb0563632024-06-13 16:20:14 +0200161 *olen = (size_t) ret;
Jens Wiklander32b31802023-10-06 16:59:46 +0200162 return 0;
163 } else if (errno != ENOSYS) {
164 return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
Jens Wiklander817466c2018-05-22 13:49:31 +0200165 }
Jens Wiklander3d3b0592019-03-20 15:30:29 +0100166 /* Fall through if the system call isn't known. */
167#else
168 ((void) ret);
Jens Wiklander817466c2018-05-22 13:49:31 +0200169#endif /* HAVE_GETRANDOM */
170
Jerome Forissier79013242021-07-28 10:24:04 +0200171#if defined(HAVE_SYSCTL_ARND)
172 ((void) file);
173 ((void) read_len);
Jens Wiklander32b31802023-10-06 16:59:46 +0200174 if (sysctl_arnd_wrapper(output, len) == -1) {
175 return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
176 }
Jerome Forissier79013242021-07-28 10:24:04 +0200177 *olen = len;
Jens Wiklander32b31802023-10-06 16:59:46 +0200178 return 0;
Jerome Forissier79013242021-07-28 10:24:04 +0200179#else
180
Jens Wiklander817466c2018-05-22 13:49:31 +0200181 *olen = 0;
182
Jens Wiklander32b31802023-10-06 16:59:46 +0200183 file = fopen("/dev/urandom", "rb");
184 if (file == NULL) {
185 return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
Jens Wiklander817466c2018-05-22 13:49:31 +0200186 }
187
Jens Wiklander32b31802023-10-06 16:59:46 +0200188 /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
189 mbedtls_setbuf(file, NULL);
190
191 read_len = fread(output, 1, len, file);
192 if (read_len != len) {
193 fclose(file);
194 return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
195 }
196
197 fclose(file);
Jens Wiklander817466c2018-05-22 13:49:31 +0200198 *olen = len;
199
Jens Wiklander32b31802023-10-06 16:59:46 +0200200 return 0;
Jerome Forissier79013242021-07-28 10:24:04 +0200201#endif /* HAVE_SYSCTL_ARND */
Jens Wiklander817466c2018-05-22 13:49:31 +0200202}
203#endif /* _WIN32 && !EFIX64 && !EFI32 */
204#endif /* !MBEDTLS_NO_PLATFORM_ENTROPY */
205
Jens Wiklander817466c2018-05-22 13:49:31 +0200206#if defined(MBEDTLS_ENTROPY_NV_SEED)
Jens Wiklander32b31802023-10-06 16:59:46 +0200207int mbedtls_nv_seed_poll(void *data,
208 unsigned char *output, size_t len, size_t *olen)
Jens Wiklander817466c2018-05-22 13:49:31 +0200209{
210 unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE];
211 size_t use_len = MBEDTLS_ENTROPY_BLOCK_SIZE;
212 ((void) data);
213
Jens Wiklander32b31802023-10-06 16:59:46 +0200214 memset(buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE);
Jens Wiklander817466c2018-05-22 13:49:31 +0200215
Jens Wiklander32b31802023-10-06 16:59:46 +0200216 if (mbedtls_nv_seed_read(buf, MBEDTLS_ENTROPY_BLOCK_SIZE) < 0) {
217 return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
218 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200219
Jens Wiklander32b31802023-10-06 16:59:46 +0200220 if (len < use_len) {
221 use_len = len;
222 }
Jens Wiklander817466c2018-05-22 13:49:31 +0200223
Jens Wiklander32b31802023-10-06 16:59:46 +0200224 memcpy(output, buf, use_len);
Jens Wiklander817466c2018-05-22 13:49:31 +0200225 *olen = use_len;
226
Jens Wiklander32b31802023-10-06 16:59:46 +0200227 return 0;
Jens Wiklander817466c2018-05-22 13:49:31 +0200228}
229#endif /* MBEDTLS_ENTROPY_NV_SEED */
230
231#endif /* MBEDTLS_ENTROPY_C */