25
25
#define BR_ENABLE_INTRINSICS 1
26
26
#include "inner.h"
27
27
28
+ #if BR_USE_GETENTROPY
29
+ #include <unistd.h>
30
+ #endif
31
+
28
32
#if BR_USE_URANDOM
29
33
#include <sys/types.h>
30
34
#include <unistd.h>
38
42
#pragma comment(lib, "advapi32")
39
43
#endif
40
44
45
+ /*
46
+ * Seeder that uses the RDRAND opcodes (on x86 CPU).
47
+ */
41
48
#if BR_RDRAND
42
49
BR_TARGETS_X86_UP
43
50
BR_TARGET ("rdrnd" )
@@ -57,9 +64,24 @@ seeder_rdrand(const br_prng_class **ctx)
57
64
*
58
65
* Intel recommends trying at least 10 times in case of
59
66
* failure.
67
+ *
68
+ * AMD bug: there are reports that some AMD processors
69
+ * have a bug that makes them fail silently after a
70
+ * suspend/resume cycle, in which case RDRAND will report
71
+ * a success but always return 0xFFFFFFFF.
72
+ * see: https://bugzilla.kernel.org/show_bug.cgi?id=85911
73
+ *
74
+ * As a mitigation, if the 32-bit value is 0 or -1, then
75
+ * it is considered a failure and tried again. This should
76
+ * reliably detect the buggy case, at least. This also
77
+ * implies that the selected seed values can never be
78
+ * 0x00000000 or 0xFFFFFFFF, which is not a problem since
79
+ * we are generating a seed for a PRNG, and we overdo it
80
+ * a bit (we generate 32 bytes of randomness, and 256 bits
81
+ * of entropy are really overkill).
60
82
*/
61
83
for (j = 0 ; j < 10 ; j ++ ) {
62
- if (_rdrand32_step (& x )) {
84
+ if (_rdrand32_step (& x ) && x != 0 && x != ( uint32_t ) -1 ) {
63
85
goto next_word ;
64
86
}
65
87
}
@@ -80,9 +102,11 @@ rdrand_supported(void)
80
102
*/
81
103
return br_cpuid (0 , 0 , 0x40000000 , 0 );
82
104
}
83
-
84
105
#endif
85
106
107
+ /*
108
+ * Seeder that uses /dev/urandom (on Unix-like systems).
109
+ */
86
110
#if BR_USE_URANDOM
87
111
static int
88
112
seeder_urandom (const br_prng_class * * ctx )
@@ -116,6 +140,32 @@ seeder_urandom(const br_prng_class **ctx)
116
140
}
117
141
#endif
118
142
143
+ /*
144
+ * Seeder that uses getentropy() (backed by getrandom() on some systems,
145
+ * e.g. Linux). On failure, it will use the /dev/urandom seeder (if
146
+ * enabled).
147
+ */
148
+ #if BR_USE_GETENTROPY
149
+ static int
150
+ seeder_getentropy (const br_prng_class * * ctx )
151
+ {
152
+ unsigned char tmp [32 ];
153
+
154
+ if (getentropy (tmp , sizeof tmp ) == 0 ) {
155
+ (* ctx )-> update (ctx , tmp , sizeof tmp );
156
+ return 1 ;
157
+ }
158
+ #if BR_USE_URANDOM
159
+ return seeder_urandom (ctx );
160
+ #else
161
+ return 0 ;
162
+ #endif
163
+ }
164
+ #endif
165
+
166
+ /*
167
+ * Seeder that uses CryptGenRandom() (on Windows).
168
+ */
119
169
#if BR_USE_WIN32_RAND
120
170
static int
121
171
seeder_win32 (const br_prng_class * * ctx )
@@ -139,6 +189,29 @@ seeder_win32(const br_prng_class **ctx)
139
189
}
140
190
#endif
141
191
192
+ /*
193
+ * An aggregate seeder that uses RDRAND, and falls back to an OS-provided
194
+ * source if RDRAND fails.
195
+ */
196
+ #if BR_RDRAND && (BR_USE_GETENTROPY || BR_USE_URANDOM || BR_USE_WIN32_RAND )
197
+ static int
198
+ seeder_rdrand_with_fallback (const br_prng_class * * ctx )
199
+ {
200
+ if (!seeder_rdrand (ctx )) {
201
+ #if BR_USE_GETENTROPY
202
+ return seeder_getentropy (ctx );
203
+ #elif BR_USE_URANDOM
204
+ return seeder_urandom (ctx );
205
+ #elif BR_USE_WIN32_RAND
206
+ return seeder_win32 (ctx );
207
+ #else
208
+ #error "macro selection has gone wrong"
209
+ #endif
210
+ }
211
+ return 1 ;
212
+ }
213
+ #endif
214
+
142
215
/* see bearssl_rand.h */
143
216
br_prng_seeder
144
217
br_prng_seeder_system (const char * * name )
@@ -148,10 +221,19 @@ br_prng_seeder_system(const char **name)
148
221
if (name != NULL ) {
149
222
* name = "rdrand" ;
150
223
}
224
+ #if BR_USE_GETENTROPY || BR_USE_URANDOM || BR_USE_WIN32_RAND
225
+ return & seeder_rdrand_with_fallback ;
226
+ #else
151
227
return & seeder_rdrand ;
228
+ #endif
152
229
}
153
230
#endif
154
- #if BR_USE_URANDOM
231
+ #if BR_USE_GETENTROPY
232
+ if (name != NULL ) {
233
+ * name = "getentropy" ;
234
+ }
235
+ return & seeder_getentropy ;
236
+ #elif BR_USE_URANDOM
155
237
if (name != NULL ) {
156
238
* name = "urandom" ;
157
239
}
0 commit comments