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
ntp_crypto_srandom(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
ntp_crypto_random_buf(void * buf,size_t nbytes)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