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