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