• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* MIT License
2  *
3  * Copyright (c) 2023 Brad House
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to deal
7  * in the Software without restriction, including without limitation the rights
8  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9  * copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  *
24  * SPDX-License-Identifier: MIT
25  */
26 
27 #include "ares_setup.h"
28 #include "ares.h"
29 #include "ares_private.h"
30 #include <stdlib.h>
31 
32 /* Older MacOS versions require including AvailabilityMacros.h before
33  * sys/random.h */
34 #ifdef HAVE_AVAILABILITYMACROS_H
35 #  include <AvailabilityMacros.h>
36 #endif
37 
38 #ifdef HAVE_SYS_RANDOM_H
39 #  include <sys/random.h>
40 #endif
41 
42 
43 typedef enum {
44   ARES_RAND_OS   = 1 << 0, /* OS-provided such as RtlGenRandom or arc4random */
45   ARES_RAND_FILE = 1 << 1, /* OS file-backed random number generator */
46   ARES_RAND_RC4  = 1 << 2, /* Internal RC4 based PRNG */
47 } ares_rand_backend;
48 
49 #define ARES_RC4_KEY_LEN 32 /* 256 bits */
50 
51 typedef struct ares_rand_rc4 {
52   unsigned char S[256];
53   size_t        i;
54   size_t        j;
55 } ares_rand_rc4;
56 
ares_u32_from_ptr(void * addr)57 static unsigned int ares_u32_from_ptr(void *addr)
58 {
59   if (sizeof(void *) == 8) {
60     return (unsigned int)((((ares_uint64_t)addr >> 32) & 0xFFFFFFFF) |
61                           ((ares_uint64_t)addr & 0xFFFFFFFF));
62   }
63   return (unsigned int)((size_t)addr & 0xFFFFFFFF);
64 }
65 
66 /* initialize an rc4 key as the last possible fallback. */
ares_rc4_generate_key(ares_rand_rc4 * rc4_state,unsigned char * key,size_t key_len)67 static void ares_rc4_generate_key(ares_rand_rc4 *rc4_state, unsigned char *key,
68                                   size_t key_len)
69 {
70   size_t         i;
71   size_t         len = 0;
72   unsigned int   data;
73   struct timeval tv;
74 
75   if (key_len != ARES_RC4_KEY_LEN) {
76     return;
77   }
78 
79   /* Randomness is hard to come by.  Maybe the system randomizes heap and stack
80    * addresses. Maybe the current timestamp give us some randomness. Use
81    * rc4_state (heap), &i (stack), and ares__tvnow()
82    */
83   data = ares_u32_from_ptr(rc4_state);
84   memcpy(key + len, &data, sizeof(data));
85   len += sizeof(data);
86 
87   data = ares_u32_from_ptr(&i);
88   memcpy(key + len, &data, sizeof(data));
89   len += sizeof(data);
90 
91   tv   = ares__tvnow();
92   data = (unsigned int)((tv.tv_sec | tv.tv_usec) & 0xFFFFFFFF);
93   memcpy(key + len, &data, sizeof(data));
94   len += sizeof(data);
95 
96   srand(ares_u32_from_ptr(rc4_state) | ares_u32_from_ptr(&i) |
97         (unsigned int)((tv.tv_sec | tv.tv_usec) & 0xFFFFFFFF));
98 
99   for (i = len; i < key_len; i++) {
100     key[i] = (unsigned char)(rand() % 256); /* LCOV_EXCL_LINE */
101   }
102 }
103 
ares_rc4_init(ares_rand_rc4 * rc4_state)104 static void ares_rc4_init(ares_rand_rc4 *rc4_state)
105 {
106   unsigned char key[ARES_RC4_KEY_LEN];
107   size_t        i;
108   size_t        j;
109 
110   ares_rc4_generate_key(rc4_state, key, sizeof(key));
111 
112   for (i = 0; i < sizeof(rc4_state->S); i++) {
113     rc4_state->S[i] = i & 0xFF;
114   }
115 
116   for (i = 0, j = 0; i < 256; i++) {
117     j = (j + rc4_state->S[i] + key[i % sizeof(key)]) % 256;
118     ARES_SWAP_BYTE(&rc4_state->S[i], &rc4_state->S[j]);
119   }
120 
121   rc4_state->i = 0;
122   rc4_state->j = 0;
123 }
124 
125 /* Just outputs the key schedule, no need to XOR with any data since we have
126  * none */
ares_rc4_prng(ares_rand_rc4 * rc4_state,unsigned char * buf,size_t len)127 static void ares_rc4_prng(ares_rand_rc4 *rc4_state, unsigned char *buf,
128                           size_t len)
129 {
130   unsigned char *S = rc4_state->S;
131   size_t         i = rc4_state->i;
132   size_t         j = rc4_state->j;
133   size_t         cnt;
134 
135   for (cnt = 0; cnt < len; cnt++) {
136     i = (i + 1) % 256;
137     j = (j + S[i]) % 256;
138 
139     ARES_SWAP_BYTE(&S[i], &S[j]);
140     buf[cnt] = S[(S[i] + S[j]) % 256];
141   }
142 
143   rc4_state->i = i;
144   rc4_state->j = j;
145 }
146 
147 struct ares_rand_state {
148   ares_rand_backend type;
149   ares_rand_backend bad_backends;
150 
151   union {
152     FILE         *rand_file;
153     ares_rand_rc4 rc4;
154   } state;
155 
156   /* Since except for RC4, random data will likely result in a syscall, lets
157    * pre-pull 256 bytes at a time.  Every query will pull 2 bytes off this so
158    * that means we should only need a syscall every 128 queries. 256bytes
159    * appears to be a sweet spot that may be able to be served without
160    * interruption */
161   unsigned char cache[256];
162   size_t        cache_remaining;
163 };
164 
165 /* Define RtlGenRandom = SystemFunction036.  This is in advapi32.dll.  There is
166  * no need to dynamically load this, other software used widely does not.
167  * http://blogs.msdn.com/michael_howard/archive/2005/01/14/353379.aspx
168  * https://docs.microsoft.com/en-us/windows/win32/api/ntsecapi/nf-ntsecapi-rtlgenrandom
169  */
170 #ifdef _WIN32
171 BOOLEAN WINAPI SystemFunction036(PVOID RandomBuffer, ULONG RandomBufferLength);
172 #  ifndef RtlGenRandom
173 #    define RtlGenRandom(a, b) SystemFunction036(a, b)
174 #  endif
175 #endif
176 
177 
ares__init_rand_engine(ares_rand_state * state)178 static ares_bool_t ares__init_rand_engine(ares_rand_state *state)
179 {
180   state->cache_remaining = 0;
181 
182 #if defined(HAVE_ARC4RANDOM_BUF) || defined(HAVE_GETRANDOM) || defined(_WIN32)
183   if (!(state->bad_backends & ARES_RAND_OS)) {
184     state->type = ARES_RAND_OS;
185     return ARES_TRUE;
186   }
187 #endif
188 
189 #if defined(CARES_RANDOM_FILE)
190   if (!(state->bad_backends & ARES_RAND_FILE)) {
191     state->type            = ARES_RAND_FILE;
192     state->state.rand_file = fopen(CARES_RANDOM_FILE, "rb");
193     if (state->state.rand_file) {
194       setvbuf(state->state.rand_file, NULL, _IONBF, 0);
195       return ARES_TRUE;
196     }
197   }
198   /* Fall-Thru on failure to RC4 */
199 #endif
200 
201   state->type = ARES_RAND_RC4;
202   ares_rc4_init(&state->state.rc4);
203 
204   /* Currently cannot fail */
205   return ARES_TRUE;
206 }
207 
ares__init_rand_state(void)208 ares_rand_state *ares__init_rand_state(void)
209 {
210   ares_rand_state *state = NULL;
211 
212   state = ares_malloc_zero(sizeof(*state));
213   if (!state) {
214     return NULL;
215   }
216 
217   if (!ares__init_rand_engine(state)) {
218     ares_free(state);
219     return NULL;
220   }
221 
222   return state;
223 }
224 
ares__clear_rand_state(ares_rand_state * state)225 static void ares__clear_rand_state(ares_rand_state *state)
226 {
227   if (!state) {
228     return;
229   }
230 
231   switch (state->type) {
232     case ARES_RAND_OS:
233       break;
234     case ARES_RAND_FILE:
235       fclose(state->state.rand_file);
236       break;
237     case ARES_RAND_RC4:
238       break;
239   }
240 }
241 
ares__reinit_rand(ares_rand_state * state)242 static void ares__reinit_rand(ares_rand_state *state)
243 {
244   ares__clear_rand_state(state);
245   ares__init_rand_engine(state);
246 }
247 
ares__destroy_rand_state(ares_rand_state * state)248 void ares__destroy_rand_state(ares_rand_state *state)
249 {
250   if (!state) {
251     return;
252   }
253 
254   ares__clear_rand_state(state);
255   ares_free(state);
256 }
257 
ares__rand_bytes_fetch(ares_rand_state * state,unsigned char * buf,size_t len)258 static void ares__rand_bytes_fetch(ares_rand_state *state, unsigned char *buf,
259                                    size_t len)
260 {
261   while (1) {
262     size_t bytes_read = 0;
263 
264     switch (state->type) {
265       case ARES_RAND_OS:
266 #ifdef _WIN32
267         RtlGenRandom(buf, (ULONG)len);
268         return;
269 #elif defined(HAVE_ARC4RANDOM_BUF)
270         arc4random_buf(buf, len);
271         return;
272 #elif defined(HAVE_GETRANDOM)
273         while (1) {
274           size_t  n = len - bytes_read;
275           /* getrandom() on Linux always succeeds and is never
276            * interrupted by a signal when requesting <= 256 bytes.
277            */
278           ssize_t rv = getrandom(buf + bytes_read, n > 256 ? 256 : n, 0);
279           if (rv <= 0) {
280             /* We need to fall back to another backend */
281             if (errno == ENOSYS) {
282               state->bad_backends |= ARES_RAND_OS;
283               break;
284             }
285             continue; /* Just retry. */
286           }
287 
288           bytes_read += (size_t)rv;
289           if (bytes_read == len) {
290             return;
291           }
292         }
293         break;
294 #else
295         /* Shouldn't be possible to be here */
296         break;
297 #endif
298 
299       case ARES_RAND_FILE:
300         while (1) {
301           size_t rv = fread(buf + bytes_read, 1, len - bytes_read,
302                             state->state.rand_file);
303           if (rv == 0) {
304             break; /* critical error, will reinit rand state */
305           }
306 
307           bytes_read += rv;
308           if (bytes_read == len) {
309             return;
310           }
311         }
312         break;
313 
314       case ARES_RAND_RC4:
315         ares_rc4_prng(&state->state.rc4, buf, len);
316         return;
317     }
318 
319     /* If we didn't return before we got here, that means we had a critical rand
320      * failure and need to reinitialized */
321     ares__reinit_rand(state);
322   }
323 }
324 
ares__rand_bytes(ares_rand_state * state,unsigned char * buf,size_t len)325 void ares__rand_bytes(ares_rand_state *state, unsigned char *buf, size_t len)
326 {
327   /* See if we need to refill the cache to serve the request, but if len is
328    * excessive, we're not going to update our cache or serve from cache */
329   if (len > state->cache_remaining && len < sizeof(state->cache)) {
330     size_t fetch_size = sizeof(state->cache) - state->cache_remaining;
331     ares__rand_bytes_fetch(state, state->cache, fetch_size);
332     state->cache_remaining = sizeof(state->cache);
333   }
334 
335   /* Serve from cache */
336   if (len <= state->cache_remaining) {
337     size_t offset = sizeof(state->cache) - state->cache_remaining;
338     memcpy(buf, state->cache + offset, len);
339     state->cache_remaining -= len;
340     return;
341   }
342 
343   /* Serve direct due to excess size of request */
344   ares__rand_bytes_fetch(state, buf, len);
345 }
346 
ares__generate_new_id(ares_rand_state * state)347 unsigned short ares__generate_new_id(ares_rand_state *state)
348 {
349   unsigned short r = 0;
350 
351   ares__rand_bytes(state, (unsigned char *)&r, sizeof(r));
352   return r;
353 }
354