1290001Sglebius/*
2290001Sglebius * Crypto-quality random number functions
3290001Sglebius *
4290001Sglebius * Author: Harlan Stenn, 2014
5290001Sglebius *
6290001Sglebius * This file is Copyright (c) 2014 by Network Time Foundation.
7290001Sglebius * BSD terms apply: see the file COPYRIGHT in the distribution root for details.
8290001Sglebius */
9290001Sglebius
10290001Sglebius#include "config.h"
11290001Sglebius#include <sys/types.h>
12290001Sglebius#ifdef HAVE_UNISTD_H
13290001Sglebius# include <unistd.h>
14290001Sglebius#endif
15290001Sglebius#include <stdio.h>
16290001Sglebius
17290001Sglebius#include <l_stdlib.h>
18290001Sglebius#include <ntp_random.h>
19293896Sglebius#include "safecast.h"
20290001Sglebius
21290001Sglebius#ifdef USE_OPENSSL_CRYPTO_RAND
22290001Sglebius#include <openssl/err.h>
23290001Sglebius#include <openssl/rand.h>
24290001Sglebius
25290001Sglebiusint crypto_rand_init = 0;
26290001Sglebius#else
27290001Sglebius
28290001Sglebius# ifndef HAVE_ARC4RANDOM_BUF
29290001Sglebiusstatic void
30290001Sglebiusarc4random_buf(void *buf, size_t nbytes);
31290001Sglebius
32290001Sglebiusvoid
33290001Sglebiusevutil_secure_rng_get_bytes(void *buf, size_t nbytes);
34290001Sglebius
35290001Sglebiusstatic void
36290001Sglebiusarc4random_buf(void *buf, size_t nbytes)
37290001Sglebius{
38290001Sglebius	evutil_secure_rng_get_bytes(buf, nbytes);
39290001Sglebius	return;
40290001Sglebius}
41290001Sglebius# endif
42290001Sglebius#endif
43290001Sglebius
44290001Sglebius/*
45290001Sglebius * As of late 2014, here's how we plan to provide cryptographic-quality
46290001Sglebius * random numbers:
47290001Sglebius *
48290001Sglebius * - If we are building with OpenSSL, use RAND_poll() and RAND_bytes().
49290001Sglebius * - Otherwise, use arc4random().
50290001Sglebius *
51290001Sglebius * Use of arc4random() can be forced using configure --disable-openssl-random
52290001Sglebius *
53290001Sglebius * We can count on arc4random existing, thru the OS or thru libevent.
54290001Sglebius * The quality of arc4random depends on the implementor.
55290001Sglebius *
56290001Sglebius * RAND_poll() doesn't show up until XXX.  If it's not present, we
57290001Sglebius * need to either provide our own or use arc4random().
58290001Sglebius */
59290001Sglebius
60290001Sglebius/*
61290001Sglebius * ntp_crypto_srandom:
62290001Sglebius *
63290001Sglebius * Initialize the random number generator, if needed by the underlying
64290001Sglebius * crypto random number generation mechanism.
65290001Sglebius */
66290001Sglebius
67290001Sglebiusvoid
68290001Sglebiusntp_crypto_srandom(
69290001Sglebius	void
70290001Sglebius	)
71290001Sglebius{
72290001Sglebius#ifdef USE_OPENSSL_CRYPTO_RAND
73290001Sglebius	if (!crypto_rand_init) {
74290001Sglebius		RAND_poll();
75290001Sglebius		crypto_rand_init = 1;
76290001Sglebius	}
77290001Sglebius#else
78290001Sglebius	/* No initialization needed for arc4random() */
79290001Sglebius#endif
80290001Sglebius}
81290001Sglebius
82290001Sglebius
83290001Sglebius/*
84290001Sglebius * ntp_crypto_random_buf:
85290001Sglebius *
86290001Sglebius * Returns 0 on success, -1 on error.
87290001Sglebius */
88290001Sglebiusint
89290001Sglebiusntp_crypto_random_buf(
90290001Sglebius	void *buf,
91290001Sglebius	size_t nbytes
92290001Sglebius	)
93290001Sglebius{
94290001Sglebius#ifdef USE_OPENSSL_CRYPTO_RAND
95290001Sglebius	int rc;
96290001Sglebius
97293896Sglebius	rc = RAND_bytes(buf, size2int_chk(nbytes));
98290001Sglebius	if (1 != rc) {
99290001Sglebius		unsigned long err;
100290001Sglebius		char *err_str;
101290001Sglebius
102290001Sglebius		err = ERR_get_error();
103290001Sglebius		err_str = ERR_error_string(err, NULL);
104290001Sglebius		/* XXX: Log the error */
105290001Sglebius		(void)&err_str;
106290001Sglebius
107290001Sglebius		return -1;
108290001Sglebius	}
109290001Sglebius	return 0;
110290001Sglebius#else
111290001Sglebius	arc4random_buf(buf, nbytes);
112290001Sglebius	return 0;
113290001Sglebius#endif
114290001Sglebius}
115