/work/mbedtls-2.28.8/library/entropy_poll.c
Line | Count | Source (jump to first uncovered line) |
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__) && !defined(_GNU_SOURCE) |
9 | | /* Ensure that syscall() is available even when compiling with -std=c99 */ |
10 | | #define _GNU_SOURCE |
11 | | #endif |
12 | | |
13 | | #include "common.h" |
14 | | |
15 | | #include <string.h> |
16 | | |
17 | | #if defined(MBEDTLS_ENTROPY_C) |
18 | | |
19 | | #include "mbedtls/entropy.h" |
20 | | #include "mbedtls/entropy_poll.h" |
21 | | #include "mbedtls/error.h" |
22 | | |
23 | | #if defined(MBEDTLS_TIMING_C) |
24 | | #include "mbedtls/timing.h" |
25 | | #endif |
26 | | #if defined(MBEDTLS_HAVEGE_C) |
27 | | #include "mbedtls/havege.h" |
28 | | #endif |
29 | | #include "mbedtls/platform.h" |
30 | | |
31 | | #if !defined(MBEDTLS_NO_PLATFORM_ENTROPY) |
32 | | |
33 | | #if !defined(unix) && !defined(__unix__) && !defined(__unix) && \ |
34 | | !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \ |
35 | | !defined(__HAIKU__) && !defined(__midipix__) |
36 | | #error \ |
37 | | "Platform entropy sources only work on Unix and Windows, see MBEDTLS_NO_PLATFORM_ENTROPY in config.h" |
38 | | #endif |
39 | | |
40 | | #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) |
41 | | |
42 | | #if !defined(_WIN32_WINNT) |
43 | | #define _WIN32_WINNT 0x0400 |
44 | | #endif |
45 | | #include <windows.h> |
46 | | #include <wincrypt.h> |
47 | | |
48 | | int mbedtls_platform_entropy_poll(void *data, unsigned char *output, size_t len, |
49 | | size_t *olen) |
50 | | { |
51 | | HCRYPTPROV provider; |
52 | | ((void) data); |
53 | | *olen = 0; |
54 | | |
55 | | if (CryptAcquireContext(&provider, NULL, NULL, |
56 | | PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) == FALSE) { |
57 | | return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; |
58 | | } |
59 | | |
60 | | if (CryptGenRandom(provider, (DWORD) len, output) == FALSE) { |
61 | | CryptReleaseContext(provider, 0); |
62 | | return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; |
63 | | } |
64 | | |
65 | | CryptReleaseContext(provider, 0); |
66 | | *olen = len; |
67 | | |
68 | | return 0; |
69 | | } |
70 | | #else /* _WIN32 && !EFIX64 && !EFI32 */ |
71 | | |
72 | | /* |
73 | | * Test for Linux getrandom() support. |
74 | | * Since there is no wrapper in the libc yet, use the generic syscall wrapper |
75 | | * 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_GETRANDOM |
82 | | #include <errno.h> |
83 | | |
84 | | static int getrandom_wrapper(void *buf, size_t buflen, unsigned int flags) |
85 | 0 | { |
86 | | /* MemSan cannot understand that the syscall writes to the buffer */ |
87 | 0 | #if defined(__has_feature) |
88 | | #if __has_feature(memory_sanitizer) |
89 | | memset(buf, 0, buflen); |
90 | | #endif |
91 | 0 | #endif |
92 | 0 | return syscall(SYS_getrandom, buf, buflen, flags); |
93 | 0 | } |
94 | | #endif /* SYS_getrandom */ |
95 | | #endif /* __linux__ || __midipix__ */ |
96 | | |
97 | | #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_GETRANDOM |
104 | | static int getrandom_wrapper(void *buf, size_t buflen, unsigned int flags) |
105 | | { |
106 | | return getrandom(buf, buflen, flags); |
107 | | } |
108 | | #endif /* (__FreeBSD__ && __FreeBSD_version >= 1200000) || |
109 | | (__DragonFly__ && __DragonFly_version >= 500700) */ |
110 | | #endif /* __FreeBSD__ || __DragonFly__ */ |
111 | | |
112 | | /* |
113 | | * Some BSD systems provide KERN_ARND. |
114 | | * This is equivalent to reading from /dev/urandom, only it doesn't require an |
115 | | * open file descriptor, and provides up to 256 bytes per call (basically the |
116 | | * same as getentropy(), but with a longer history). |
117 | | * |
118 | | * Documentation: https://netbsd.gw.com/cgi-bin/man-cgi?sysctl+7 |
119 | | */ |
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_ARND |
125 | | |
126 | | static int sysctl_arnd_wrapper(unsigned char *buf, size_t buflen) |
127 | | { |
128 | | int name[2]; |
129 | | size_t len; |
130 | | |
131 | | name[0] = CTL_KERN; |
132 | | name[1] = KERN_ARND; |
133 | | |
134 | | while (buflen > 0) { |
135 | | len = buflen > 256 ? 256 : buflen; |
136 | | if (sysctl(name, 2, buf, &len, NULL, 0) == -1) { |
137 | | return -1; |
138 | | } |
139 | | buflen -= len; |
140 | | buf += len; |
141 | | } |
142 | | return 0; |
143 | | } |
144 | | #endif /* KERN_ARND */ |
145 | | #endif /* __FreeBSD__ || __NetBSD__ */ |
146 | | |
147 | | #include <stdio.h> |
148 | | |
149 | | int mbedtls_platform_entropy_poll(void *data, |
150 | | unsigned char *output, size_t len, size_t *olen) |
151 | 0 | { |
152 | 0 | FILE *file; |
153 | 0 | size_t read_len; |
154 | 0 | int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; |
155 | 0 | ((void) data); |
156 | |
|
157 | 0 | #if defined(HAVE_GETRANDOM) |
158 | 0 | ret = getrandom_wrapper(output, len, 0); |
159 | 0 | if (ret >= 0) { |
160 | 0 | *olen = ret; |
161 | 0 | return 0; |
162 | 0 | } else if (errno != ENOSYS) { |
163 | 0 | return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; |
164 | 0 | } |
165 | | /* Fall through if the system call isn't known. */ |
166 | | #else |
167 | | ((void) ret); |
168 | | #endif /* HAVE_GETRANDOM */ |
169 | | |
170 | | #if defined(HAVE_SYSCTL_ARND) |
171 | | ((void) file); |
172 | | ((void) read_len); |
173 | | if (sysctl_arnd_wrapper(output, len) == -1) { |
174 | | return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; |
175 | | } |
176 | | *olen = len; |
177 | | return 0; |
178 | | #else |
179 | | |
180 | 0 | *olen = 0; |
181 | |
|
182 | 0 | file = fopen("/dev/urandom", "rb"); |
183 | 0 | if (file == NULL) { |
184 | 0 | return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; |
185 | 0 | } |
186 | | |
187 | 0 | read_len = fread(output, 1, len, file); |
188 | 0 | if (read_len != len) { |
189 | 0 | fclose(file); |
190 | 0 | return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; |
191 | 0 | } |
192 | | |
193 | 0 | fclose(file); |
194 | 0 | *olen = len; |
195 | |
|
196 | 0 | return 0; |
197 | 0 | #endif /* HAVE_SYSCTL_ARND */ |
198 | 0 | } |
199 | | #endif /* _WIN32 && !EFIX64 && !EFI32 */ |
200 | | #endif /* !MBEDTLS_NO_PLATFORM_ENTROPY */ |
201 | | |
202 | | #if defined(MBEDTLS_TEST_NULL_ENTROPY) |
203 | | int mbedtls_null_entropy_poll(void *data, |
204 | | unsigned char *output, size_t len, size_t *olen) |
205 | | { |
206 | | ((void) data); |
207 | | ((void) output); |
208 | | |
209 | | *olen = 0; |
210 | | if (len < sizeof(unsigned char)) { |
211 | | return 0; |
212 | | } |
213 | | |
214 | | output[0] = 0; |
215 | | *olen = sizeof(unsigned char); |
216 | | return 0; |
217 | | } |
218 | | #endif |
219 | | |
220 | | #if defined(MBEDTLS_TIMING_C) |
221 | | int mbedtls_hardclock_poll(void *data, |
222 | | unsigned char *output, size_t len, size_t *olen) |
223 | 0 | { |
224 | 0 | unsigned long timer = mbedtls_timing_hardclock(); |
225 | 0 | ((void) data); |
226 | 0 | *olen = 0; |
227 | |
|
228 | 0 | if (len < sizeof(unsigned long)) { |
229 | 0 | return 0; |
230 | 0 | } |
231 | | |
232 | 0 | memcpy(output, &timer, sizeof(unsigned long)); |
233 | 0 | *olen = sizeof(unsigned long); |
234 | |
|
235 | 0 | return 0; |
236 | 0 | } |
237 | | #endif /* MBEDTLS_TIMING_C */ |
238 | | |
239 | | #if defined(MBEDTLS_HAVEGE_C) |
240 | | int mbedtls_havege_poll(void *data, |
241 | | unsigned char *output, size_t len, size_t *olen) |
242 | | { |
243 | | mbedtls_havege_state *hs = (mbedtls_havege_state *) data; |
244 | | *olen = 0; |
245 | | |
246 | | if (mbedtls_havege_random(hs, output, len) != 0) { |
247 | | return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; |
248 | | } |
249 | | |
250 | | *olen = len; |
251 | | |
252 | | return 0; |
253 | | } |
254 | | #endif /* MBEDTLS_HAVEGE_C */ |
255 | | |
256 | | #if defined(MBEDTLS_ENTROPY_NV_SEED) |
257 | | int mbedtls_nv_seed_poll(void *data, |
258 | | unsigned char *output, size_t len, size_t *olen) |
259 | | { |
260 | | unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; |
261 | | size_t use_len = MBEDTLS_ENTROPY_BLOCK_SIZE; |
262 | | ((void) data); |
263 | | |
264 | | memset(buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE); |
265 | | |
266 | | if (mbedtls_nv_seed_read(buf, MBEDTLS_ENTROPY_BLOCK_SIZE) < 0) { |
267 | | return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; |
268 | | } |
269 | | |
270 | | if (len < use_len) { |
271 | | use_len = len; |
272 | | } |
273 | | |
274 | | memcpy(output, buf, use_len); |
275 | | *olen = use_len; |
276 | | |
277 | | return 0; |
278 | | } |
279 | | #endif /* MBEDTLS_ENTROPY_NV_SEED */ |
280 | | |
281 | | #endif /* MBEDTLS_ENTROPY_C */ |