1 /* 2 * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org> 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining 5 * a copy of this software and associated documentation files (the 6 * "Software"), to deal in the Software without restriction, including 7 * without limitation the rights to use, copy, modify, merge, publish, 8 * distribute, sublicense, and/or sell copies of the Software, and to 9 * permit persons to whom the Software is furnished to do so, subject to 10 * the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be 13 * included in all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 */ 24 25 #define BR_ENABLE_INTRINSICS 1 26 #include "inner.h" 27 28 #if BR_USE_URANDOM 29 #include <sys/types.h> 30 #include <unistd.h> 31 #include <fcntl.h> 32 #include <errno.h> 33 #endif 34 35 #if BR_USE_WIN32_RAND 36 #include <windows.h> 37 #include <wincrypt.h> 38 #pragma comment(lib, "advapi32") 39 #endif 40 41 #if BR_RDRAND 42 BR_TARGETS_X86_UP 43 BR_TARGET("rdrnd") 44 static int 45 seeder_rdrand(const br_prng_class **ctx) 46 { 47 unsigned char tmp[32]; 48 size_t u; 49 50 for (u = 0; u < sizeof tmp; u += sizeof(uint32_t)) { 51 int j; 52 uint32_t x; 53 54 /* 55 * We use the 32-bit intrinsic so that code is compatible 56 * with both 32-bit and 64-bit architectures. 57 * 58 * Intel recommends trying at least 10 times in case of 59 * failure. 60 */ 61 for (j = 0; j < 10; j ++) { 62 if (_rdrand32_step(&x)) { 63 goto next_word; 64 } 65 } 66 return 0; 67 next_word: 68 br_enc32le(tmp + u, x); 69 } 70 (*ctx)->update(ctx, tmp, sizeof tmp); 71 return 1; 72 } 73 BR_TARGETS_X86_DOWN 74 75 static int 76 rdrand_supported(void) 77 { 78 /* 79 * The RDRND support is bit 30 of ECX, as returned by CPUID. 80 */ 81 return br_cpuid(0, 0, 0x40000000, 0); 82 } 83 84 #endif 85 86 #if BR_USE_URANDOM 87 static int 88 seeder_urandom(const br_prng_class **ctx) 89 { 90 int f; 91 92 f = open("/dev/urandom", O_RDONLY); 93 if (f >= 0) { 94 unsigned char tmp[32]; 95 size_t u; 96 97 for (u = 0; u < sizeof tmp;) { 98 ssize_t len; 99 100 len = read(f, tmp + u, (sizeof tmp) - u); 101 if (len < 0) { 102 if (errno == EINTR) { 103 continue; 104 } 105 break; 106 } 107 u += (size_t)len; 108 } 109 close(f); 110 if (u == sizeof tmp) { 111 (*ctx)->update(ctx, tmp, sizeof tmp); 112 return 1; 113 } 114 } 115 return 0; 116 } 117 #endif 118 119 #if BR_USE_WIN32_RAND 120 static int 121 seeder_win32(const br_prng_class **ctx) 122 { 123 HCRYPTPROV hp; 124 125 if (CryptAcquireContext(&hp, 0, 0, PROV_RSA_FULL, 126 CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) 127 { 128 BYTE buf[32]; 129 BOOL r; 130 131 r = CryptGenRandom(hp, sizeof buf, buf); 132 CryptReleaseContext(hp, 0); 133 if (r) { 134 (*ctx)->update(ctx, buf, sizeof buf); 135 return 1; 136 } 137 } 138 return 0; 139 } 140 #endif 141 142 /* see bearssl_rand.h */ 143 br_prng_seeder 144 br_prng_seeder_system(const char **name) 145 { 146 #if BR_RDRAND 147 if (rdrand_supported()) { 148 if (name != NULL) { 149 *name = "rdrand"; 150 } 151 return &seeder_rdrand; 152 } 153 #endif 154 #if BR_USE_URANDOM 155 if (name != NULL) { 156 *name = "urandom"; 157 } 158 return &seeder_urandom; 159 #elif BR_USE_WIN32_RAND 160 if (name != NULL) { 161 *name = "win32"; 162 } 163 return &seeder_win32; 164 #else 165 if (name != NULL) { 166 *name = "none"; 167 } 168 return 0; 169 #endif 170 } 171