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