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