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