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