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