1 /* $NetBSD: evutil_rand.c,v 1.5 2017/01/31 23:17:39 christos Exp $ */ 2 /* 3 * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 /* This file has our secure PRNG code. On platforms that have arc4random(), 29 * we just use that. Otherwise, we include arc4random.c as a bunch of static 30 * functions, and wrap it lightly. We don't expose the arc4random*() APIs 31 * because A) they aren't in our namespace, and B) it's not nice to name your 32 * APIs after their implementations. We keep them in a separate file 33 * so that other people can rip it out and use it for whatever. 34 */ 35 36 #include "event2/event-config.h" 37 #include <sys/cdefs.h> 38 __RCSID("$NetBSD: evutil_rand.c,v 1.5 2017/01/31 23:17:39 christos Exp $"); 39 #include "evconfig-private.h" 40 41 #include <limits.h> 42 43 #include "util-internal.h" 44 #include "evthread-internal.h" 45 46 #ifdef EVENT__HAVE_ARC4RANDOM 47 #include <stdlib.h> 48 #include <string.h> 49 int 50 evutil_secure_rng_set_urandom_device_file(char *fname) 51 { 52 (void) fname; 53 return -1; 54 } 55 int 56 evutil_secure_rng_init(void) 57 { 58 /* call arc4random() now to force it to self-initialize */ 59 (void) arc4random(); 60 return 0; 61 } 62 #ifndef EVENT__DISABLE_THREAD_SUPPORT 63 int 64 /*ARGSUSED*/ 65 evutil_secure_rng_global_setup_locks_(const int enable_locks) 66 { 67 return 0; 68 } 69 #endif 70 static void 71 evutil_free_secure_rng_globals_locks(void) 72 { 73 } 74 75 static void 76 /*ARGSUSED*/ 77 ev_arc4random_buf(void *buf, size_t n) 78 { 79 #if defined(EVENT__HAVE_ARC4RANDOM_BUF) && !defined(__APPLE__) 80 arc4random_buf(buf, n); 81 return; 82 #else 83 unsigned char *b = buf; 84 85 #if defined(EVENT__HAVE_ARC4RANDOM_BUF) 86 /* OSX 10.7 introducd arc4random_buf, so if you build your program 87 * there, you'll get surprised when older versions of OSX fail to run. 88 * To solve this, we can check whether the function pointer is set, 89 * and fall back otherwise. (OSX does this using some linker 90 * trickery.) 91 */ 92 { 93 void (*tptr)(void *,size_t) = 94 (void (*)(void*,size_t))arc4random_buf; 95 if (tptr != NULL) { 96 arc4random_buf(buf, n); 97 return; 98 } 99 } 100 #endif 101 /* Make sure that we start out with b at a 4-byte alignment; plenty 102 * of CPUs care about this for 32-bit access. */ 103 if (n >= 4 && ((ev_uintptr_t)b) & 3) { 104 ev_uint32_t u = arc4random(); 105 int n_bytes = 4 - (((ev_uintptr_t)b) & 3); 106 memcpy(b, &u, n_bytes); 107 b += n_bytes; 108 n -= n_bytes; 109 } 110 while (n >= 4) { 111 *(ev_uint32_t*)b = arc4random(); 112 b += 4; 113 n -= 4; 114 } 115 if (n) { 116 ev_uint32_t u = arc4random(); 117 memcpy(b, &u, n); 118 } 119 #endif 120 } 121 122 #else /* !EVENT__HAVE_ARC4RANDOM { */ 123 124 #ifdef EVENT__ssize_t 125 #define ssize_t EVENT__ssize_t 126 #endif 127 #define ARC4RANDOM_EXPORT static 128 #define ARC4_LOCK_() EVLOCK_LOCK(arc4rand_lock, 0) 129 #define ARC4_UNLOCK_() EVLOCK_UNLOCK(arc4rand_lock, 0) 130 #ifndef EVENT__DISABLE_THREAD_SUPPORT 131 static void *arc4rand_lock; 132 #endif 133 134 #define ARC4RANDOM_UINT32 ev_uint32_t 135 #define ARC4RANDOM_NOSTIR 136 #define ARC4RANDOM_NORANDOM 137 #define ARC4RANDOM_NOUNIFORM 138 139 #include "./arc4random.c" 140 141 #ifndef EVENT__DISABLE_THREAD_SUPPORT 142 int 143 evutil_secure_rng_global_setup_locks_(const int enable_locks) 144 { 145 EVTHREAD_SETUP_GLOBAL_LOCK(arc4rand_lock, 0); 146 return 0; 147 } 148 #endif 149 150 static void 151 evutil_free_secure_rng_globals_locks(void) 152 { 153 #ifndef EVENT__DISABLE_THREAD_SUPPORT 154 if (arc4rand_lock != NULL) { 155 EVTHREAD_FREE_LOCK(arc4rand_lock, 0); 156 arc4rand_lock = NULL; 157 } 158 #endif 159 return; 160 } 161 162 int 163 /*ARGSUSED*/ 164 evutil_secure_rng_set_urandom_device_file(char *fname) 165 { 166 #ifdef TRY_SEED_URANDOM 167 ARC4_LOCK_(); 168 arc4random_urandom_filename = fname; 169 ARC4_UNLOCK_(); 170 #endif 171 return 0; 172 } 173 174 int 175 evutil_secure_rng_init(void) 176 { 177 int val; 178 179 ARC4_LOCK_(); 180 if (!arc4_seeded_ok) 181 arc4_stir(); 182 val = arc4_seeded_ok ? 0 : -1; 183 ARC4_UNLOCK_(); 184 return val; 185 } 186 187 static void 188 ev_arc4random_buf(void *buf, size_t n) 189 { 190 arc4random_buf(buf, n); 191 } 192 193 #endif /* } !EVENT__HAVE_ARC4RANDOM */ 194 195 void 196 evutil_secure_rng_get_bytes(void *buf, size_t n) 197 { 198 ev_arc4random_buf(buf, n); 199 } 200 201 void 202 evutil_secure_rng_add_bytes(const char *buf, size_t n) 203 { 204 arc4random_addrandom(__UNCONST(buf), 205 n>(size_t)INT_MAX ? INT_MAX : (int)n); 206 } 207 208 void 209 evutil_free_secure_rng_globals_(void) 210 { 211 evutil_free_secure_rng_globals_locks(); 212 } 213