xref: /netbsd-src/external/bsd/ntp/dist/sntp/libevent/evutil_rand.c (revision eabc0478de71e4e011a5b4e0392741e01d491794)
1*eabc0478Schristos /*	$NetBSD: evutil_rand.c,v 1.6 2024/08/18 20:47:21 christos Exp $	*/
28585484eSchristos 
38585484eSchristos /*
48585484eSchristos  * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
58585484eSchristos  *
68585484eSchristos  * Redistribution and use in source and binary forms, with or without
78585484eSchristos  * modification, are permitted provided that the following conditions
88585484eSchristos  * are met:
98585484eSchristos  * 1. Redistributions of source code must retain the above copyright
108585484eSchristos  *    notice, this list of conditions and the following disclaimer.
118585484eSchristos  * 2. Redistributions in binary form must reproduce the above copyright
128585484eSchristos  *    notice, this list of conditions and the following disclaimer in the
138585484eSchristos  *    documentation and/or other materials provided with the distribution.
148585484eSchristos  * 3. The name of the author may not be used to endorse or promote products
158585484eSchristos  *    derived from this software without specific prior written permission.
168585484eSchristos  *
178585484eSchristos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
188585484eSchristos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
198585484eSchristos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
208585484eSchristos  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
218585484eSchristos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
228585484eSchristos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
238585484eSchristos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
248585484eSchristos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
258585484eSchristos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
268585484eSchristos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
278585484eSchristos  */
288585484eSchristos 
298585484eSchristos /* This file has our secure PRNG code.  On platforms that have arc4random(),
308585484eSchristos  * we just use that.  Otherwise, we include arc4random.c as a bunch of static
318585484eSchristos  * functions, and wrap it lightly.  We don't expose the arc4random*() APIs
328585484eSchristos  * because A) they aren't in our namespace, and B) it's not nice to name your
338585484eSchristos  * APIs after their implementations.  We keep them in a separate file
348585484eSchristos  * so that other people can rip it out and use it for whatever.
358585484eSchristos  */
368585484eSchristos 
378585484eSchristos #include "event2/event-config.h"
388585484eSchristos #include "evconfig-private.h"
398585484eSchristos 
408585484eSchristos #include <limits.h>
418585484eSchristos 
428585484eSchristos #include "util-internal.h"
438585484eSchristos #include "evthread-internal.h"
448585484eSchristos 
458585484eSchristos #ifdef EVENT__HAVE_ARC4RANDOM
468585484eSchristos #include <stdlib.h>
478585484eSchristos #include <string.h>
488585484eSchristos int
49b8ecfcfeSchristos evutil_secure_rng_set_urandom_device_file(char *fname)
50b8ecfcfeSchristos {
51b8ecfcfeSchristos 	(void) fname;
52b8ecfcfeSchristos 	return -1;
53b8ecfcfeSchristos }
54b8ecfcfeSchristos int
558585484eSchristos evutil_secure_rng_init(void)
568585484eSchristos {
578585484eSchristos 	/* call arc4random() now to force it to self-initialize */
588585484eSchristos 	(void) arc4random();
598585484eSchristos 	return 0;
608585484eSchristos }
618585484eSchristos #ifndef EVENT__DISABLE_THREAD_SUPPORT
628585484eSchristos int
638585484eSchristos evutil_secure_rng_global_setup_locks_(const int enable_locks)
648585484eSchristos {
658585484eSchristos 	return 0;
668585484eSchristos }
678585484eSchristos #endif
688585484eSchristos static void
698585484eSchristos evutil_free_secure_rng_globals_locks(void)
708585484eSchristos {
718585484eSchristos }
728585484eSchristos 
738585484eSchristos static void
748585484eSchristos ev_arc4random_buf(void *buf, size_t n)
758585484eSchristos {
768585484eSchristos #if defined(EVENT__HAVE_ARC4RANDOM_BUF) && !defined(__APPLE__)
77b8ecfcfeSchristos 	arc4random_buf(buf, n);
78b8ecfcfeSchristos 	return;
798585484eSchristos #else
808585484eSchristos 	unsigned char *b = buf;
818585484eSchristos 
828585484eSchristos #if defined(EVENT__HAVE_ARC4RANDOM_BUF)
838585484eSchristos 	/* OSX 10.7 introducd arc4random_buf, so if you build your program
848585484eSchristos 	 * there, you'll get surprised when older versions of OSX fail to run.
858585484eSchristos 	 * To solve this, we can check whether the function pointer is set,
868585484eSchristos 	 * and fall back otherwise.  (OSX does this using some linker
878585484eSchristos 	 * trickery.)
888585484eSchristos 	 */
89b8ecfcfeSchristos 	{
90b8ecfcfeSchristos 		void (*tptr)(void *,size_t) =
91b8ecfcfeSchristos 		    (void (*)(void*,size_t))arc4random_buf;
92b8ecfcfeSchristos 		if (tptr != NULL) {
93b8ecfcfeSchristos 			arc4random_buf(buf, n);
94b8ecfcfeSchristos 			return;
95b8ecfcfeSchristos 		}
968585484eSchristos 	}
978585484eSchristos #endif
988585484eSchristos 	/* Make sure that we start out with b at a 4-byte alignment; plenty
998585484eSchristos 	 * of CPUs care about this for 32-bit access. */
1008585484eSchristos 	if (n >= 4 && ((ev_uintptr_t)b) & 3) {
1018585484eSchristos 		ev_uint32_t u = arc4random();
1028585484eSchristos 		int n_bytes = 4 - (((ev_uintptr_t)b) & 3);
1038585484eSchristos 		memcpy(b, &u, n_bytes);
1048585484eSchristos 		b += n_bytes;
1058585484eSchristos 		n -= n_bytes;
1068585484eSchristos 	}
1078585484eSchristos 	while (n >= 4) {
1088585484eSchristos 		*(ev_uint32_t*)b = arc4random();
1098585484eSchristos 		b += 4;
1108585484eSchristos 		n -= 4;
1118585484eSchristos 	}
1128585484eSchristos 	if (n) {
1138585484eSchristos 		ev_uint32_t u = arc4random();
1148585484eSchristos 		memcpy(b, &u, n);
1158585484eSchristos 	}
1168585484eSchristos #endif
1178585484eSchristos }
1188585484eSchristos 
1198585484eSchristos #else /* !EVENT__HAVE_ARC4RANDOM { */
1208585484eSchristos 
1218585484eSchristos #ifdef EVENT__ssize_t
1228585484eSchristos #define ssize_t EVENT__ssize_t
1238585484eSchristos #endif
1248585484eSchristos #define ARC4RANDOM_EXPORT static
1258585484eSchristos #define ARC4_LOCK_() EVLOCK_LOCK(arc4rand_lock, 0)
1268585484eSchristos #define ARC4_UNLOCK_() EVLOCK_UNLOCK(arc4rand_lock, 0)
1278585484eSchristos #ifndef EVENT__DISABLE_THREAD_SUPPORT
1288585484eSchristos static void *arc4rand_lock;
1298585484eSchristos #endif
1308585484eSchristos 
1318585484eSchristos #define ARC4RANDOM_UINT32 ev_uint32_t
1328585484eSchristos #define ARC4RANDOM_NOSTIR
1338585484eSchristos #define ARC4RANDOM_NORANDOM
1348585484eSchristos #define ARC4RANDOM_NOUNIFORM
1358585484eSchristos 
1368585484eSchristos #include "./arc4random.c"
1378585484eSchristos 
1388585484eSchristos #ifndef EVENT__DISABLE_THREAD_SUPPORT
1398585484eSchristos int
1408585484eSchristos evutil_secure_rng_global_setup_locks_(const int enable_locks)
1418585484eSchristos {
1428585484eSchristos 	EVTHREAD_SETUP_GLOBAL_LOCK(arc4rand_lock, 0);
1438585484eSchristos 	return 0;
1448585484eSchristos }
1458585484eSchristos #endif
1468585484eSchristos 
1478585484eSchristos static void
1488585484eSchristos evutil_free_secure_rng_globals_locks(void)
1498585484eSchristos {
1508585484eSchristos #ifndef EVENT__DISABLE_THREAD_SUPPORT
1518585484eSchristos 	if (arc4rand_lock != NULL) {
1528585484eSchristos 		EVTHREAD_FREE_LOCK(arc4rand_lock, 0);
1538585484eSchristos 		arc4rand_lock = NULL;
1548585484eSchristos 	}
1558585484eSchristos #endif
1568585484eSchristos 	return;
1578585484eSchristos }
1588585484eSchristos 
1598585484eSchristos int
160b8ecfcfeSchristos evutil_secure_rng_set_urandom_device_file(char *fname)
161b8ecfcfeSchristos {
162b8ecfcfeSchristos #ifdef TRY_SEED_URANDOM
163b8ecfcfeSchristos 	ARC4_LOCK_();
164b8ecfcfeSchristos 	arc4random_urandom_filename = fname;
165b8ecfcfeSchristos 	ARC4_UNLOCK_();
166b8ecfcfeSchristos #endif
167b8ecfcfeSchristos 	return 0;
168b8ecfcfeSchristos }
169b8ecfcfeSchristos 
170b8ecfcfeSchristos int
1718585484eSchristos evutil_secure_rng_init(void)
1728585484eSchristos {
1738585484eSchristos 	int val;
1748585484eSchristos 
1758585484eSchristos 	ARC4_LOCK_();
176*eabc0478Schristos 	val = (!arc4_stir()) ? 0 : -1;
1778585484eSchristos 	ARC4_UNLOCK_();
1788585484eSchristos 	return val;
1798585484eSchristos }
1808585484eSchristos 
1818585484eSchristos static void
1828585484eSchristos ev_arc4random_buf(void *buf, size_t n)
1838585484eSchristos {
1848585484eSchristos 	arc4random_buf(buf, n);
1858585484eSchristos }
1868585484eSchristos 
1878585484eSchristos #endif /* } !EVENT__HAVE_ARC4RANDOM */
1888585484eSchristos 
1898585484eSchristos void
1908585484eSchristos evutil_secure_rng_get_bytes(void *buf, size_t n)
1918585484eSchristos {
1928585484eSchristos 	ev_arc4random_buf(buf, n);
1938585484eSchristos }
1948585484eSchristos 
195*eabc0478Schristos #if !defined(EVENT__HAVE_ARC4RANDOM) || defined(EVENT__HAVE_ARC4RANDOM_ADDRANDOM)
1968585484eSchristos void
1978585484eSchristos evutil_secure_rng_add_bytes(const char *buf, size_t n)
1988585484eSchristos {
1998585484eSchristos 	arc4random_addrandom((unsigned char*)buf,
2008585484eSchristos 	    n>(size_t)INT_MAX ? INT_MAX : (int)n);
2018585484eSchristos }
202*eabc0478Schristos #endif
2038585484eSchristos 
2048585484eSchristos void
2058585484eSchristos evutil_free_secure_rng_globals_(void)
2068585484eSchristos {
2078585484eSchristos     evutil_free_secure_rng_globals_locks();
2088585484eSchristos }
209