xref: /netbsd-src/external/bsd/ntp/dist/libntp/ntp_crypto_rnd.c (revision eabc0478de71e4e011a5b4e0392741e01d491794)
1*eabc0478Schristos /*	$NetBSD: ntp_crypto_rnd.c,v 1.7 2024/08/18 20:47:13 christos Exp $	*/
2b8ecfcfeSchristos 
3b8ecfcfeSchristos /*
4b8ecfcfeSchristos  * Crypto-quality random number functions
5b8ecfcfeSchristos  *
6b8ecfcfeSchristos  * Author: Harlan Stenn, 2014
7b8ecfcfeSchristos  *
8b8ecfcfeSchristos  * This file is Copyright (c) 2014 by Network Time Foundation.
9b8ecfcfeSchristos  * BSD terms apply: see the file COPYRIGHT in the distribution root for details.
10b8ecfcfeSchristos  */
11b8ecfcfeSchristos 
12b8ecfcfeSchristos #include "config.h"
13b8ecfcfeSchristos #include <sys/types.h>
14b8ecfcfeSchristos #ifdef HAVE_UNISTD_H
15b8ecfcfeSchristos # include <unistd.h>
16b8ecfcfeSchristos #endif
17b8ecfcfeSchristos #include <stdio.h>
18b8ecfcfeSchristos 
19*eabc0478Schristos #include <ntp_stdlib.h>
20b8ecfcfeSchristos #include <ntp_random.h>
218b8da087Schristos #include "safecast.h"
22b8ecfcfeSchristos 
23b8ecfcfeSchristos #ifdef USE_OPENSSL_CRYPTO_RAND
24b8ecfcfeSchristos #include <openssl/err.h>
25b8ecfcfeSchristos #include <openssl/rand.h>
26b8ecfcfeSchristos 
27b8ecfcfeSchristos int crypto_rand_init = 0;
28*eabc0478Schristos #elif !defined(HAVE_ARC4RANDOM_BUF)
29*eabc0478Schristos #include <event2/util.h>
307476e6e4Schristos #endif
31*eabc0478Schristos 
32*eabc0478Schristos int crypto_rand_ok = 0;
33b8ecfcfeSchristos 
34b8ecfcfeSchristos /*
35b8ecfcfeSchristos  * As of late 2014, here's how we plan to provide cryptographic-quality
36b8ecfcfeSchristos  * random numbers:
37b8ecfcfeSchristos  *
38b8ecfcfeSchristos  * - If we are building with OpenSSL, use RAND_poll() and RAND_bytes().
39b8ecfcfeSchristos  * - Otherwise, use arc4random().
40b8ecfcfeSchristos  *
41*eabc0478Schristos  * Use of arc4random() can be forced using configure options
42*eabc0478Schristos  * --disable-openssl-random or --without-crypto.
43b8ecfcfeSchristos  *
44b8ecfcfeSchristos  * We can count on arc4random existing, thru the OS or thru libevent.
45b8ecfcfeSchristos  * The quality of arc4random depends on the implementor.
46b8ecfcfeSchristos  *
47b8ecfcfeSchristos  * RAND_poll() doesn't show up until XXX.  If it's not present, we
48b8ecfcfeSchristos  * need to either provide our own or use arc4random().
49b8ecfcfeSchristos  */
50b8ecfcfeSchristos 
51b8ecfcfeSchristos  /*
52b8ecfcfeSchristos   * ntp_crypto_srandom:
53b8ecfcfeSchristos   *
54b8ecfcfeSchristos   * Initialize the random number generator, if needed by the underlying
55b8ecfcfeSchristos   * crypto random number generation mechanism.
56b8ecfcfeSchristos   */
57b8ecfcfeSchristos 
58b8ecfcfeSchristos void
59b8ecfcfeSchristos ntp_crypto_srandom(
60b8ecfcfeSchristos 	void
61b8ecfcfeSchristos )
62b8ecfcfeSchristos {
63b8ecfcfeSchristos #ifdef USE_OPENSSL_CRYPTO_RAND
64b8ecfcfeSchristos 	if (!crypto_rand_init) {
65*eabc0478Schristos 		if (RAND_poll())
66*eabc0478Schristos 			crypto_rand_ok = 1;
67b8ecfcfeSchristos 		crypto_rand_init = 1;
68b8ecfcfeSchristos 	}
69*eabc0478Schristos #elif HAVE_ARC4RANDOM_BUF
70*eabc0478Schristos 	/*
71*eabc0478Schristos 	 * arc4random_buf has no error return and needs no seeding nor reseeding.
72*eabc0478Schristos 	 */
73*eabc0478Schristos 	crypto_rand_ok = 1;
74b8ecfcfeSchristos #else
75*eabc0478Schristos 	/*
76*eabc0478Schristos 	 * Explicitly init libevent secure RNG to make sure it seeds.
77*eabc0478Schristos 	 * This is the only way we can tell if it can successfully get
78*eabc0478Schristos 	 * entropy from the system.
79*eabc0478Schristos 	 */
80*eabc0478Schristos 	if (!evutil_secure_rng_init())
81*eabc0478Schristos 		crypto_rand_ok = 1;
82b8ecfcfeSchristos #endif
83b8ecfcfeSchristos }
84b8ecfcfeSchristos 
85b8ecfcfeSchristos 
86b8ecfcfeSchristos /*
87*eabc0478Schristos  * ntp_crypto_random_buf:  Used by ntp-keygen
88b8ecfcfeSchristos  *
89b8ecfcfeSchristos  * Returns 0 on success, -1 on error.
90b8ecfcfeSchristos  */
91b8ecfcfeSchristos int
92b8ecfcfeSchristos ntp_crypto_random_buf(
93b8ecfcfeSchristos 	void *buf,
94b8ecfcfeSchristos 	size_t nbytes
95b8ecfcfeSchristos 	)
96b8ecfcfeSchristos {
97*eabc0478Schristos 	if (!crypto_rand_ok)
98*eabc0478Schristos 		return -1;
99b8ecfcfeSchristos 
100*eabc0478Schristos #if defined(USE_OPENSSL_CRYPTO_RAND)
101*eabc0478Schristos 	if (1 != RAND_bytes(buf, size2int_chk(nbytes))) {
102b8ecfcfeSchristos 		unsigned long err;
103b8ecfcfeSchristos 		char *err_str;
104b8ecfcfeSchristos 
105b8ecfcfeSchristos 		err = ERR_get_error();
106b8ecfcfeSchristos 		err_str = ERR_error_string(err, NULL);
107*eabc0478Schristos 		msyslog(LOG_ERR, "RAND_bytes failed: %s", err_str);
108b8ecfcfeSchristos 
109b8ecfcfeSchristos 		return -1;
110b8ecfcfeSchristos 	}
111*eabc0478Schristos #elif defined(HAVE_ARC4RANDOM_BUF)
112b8ecfcfeSchristos 	arc4random_buf(buf, nbytes);
113*eabc0478Schristos #else
114*eabc0478Schristos 	evutil_secure_rng_get_bytes(buf, nbytes);
115b8ecfcfeSchristos #endif
116*eabc0478Schristos 	return 0;
117b8ecfcfeSchristos }
118