1/*	$NetBSD: ntp_crypto_rnd.c,v 1.6 2020/05/25 20:47:24 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 <l_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
27int crypto_rand_init = 0;
28#else
29
30# ifndef HAVE_ARC4RANDOM_BUF
31static void
32arc4random_buf(void *buf, size_t nbytes);
33
34void
35evutil_secure_rng_get_bytes(void *buf, size_t nbytes);
36
37static void
38arc4random_buf(void *buf, size_t nbytes)
39{
40	evutil_secure_rng_get_bytes(buf, nbytes);
41	return;
42}
43# endif
44#endif
45
46/*
47 * As of late 2014, here's how we plan to provide cryptographic-quality
48 * random numbers:
49 *
50 * - If we are building with OpenSSL, use RAND_poll() and RAND_bytes().
51 * - Otherwise, use arc4random().
52 *
53 * Use of arc4random() can be forced using configure --disable-openssl-random
54 *
55 * We can count on arc4random existing, thru the OS or thru libevent.
56 * The quality of arc4random depends on the implementor.
57 *
58 * RAND_poll() doesn't show up until XXX.  If it's not present, we
59 * need to either provide our own or use arc4random().
60 */
61
62/*
63 * ntp_crypto_srandom:
64 *
65 * Initialize the random number generator, if needed by the underlying
66 * crypto random number generation mechanism.
67 */
68
69void
70ntp_crypto_srandom(
71	void
72	)
73{
74#ifdef USE_OPENSSL_CRYPTO_RAND
75	if (!crypto_rand_init) {
76		RAND_poll();
77		crypto_rand_init = 1;
78	}
79#else
80	/* No initialization needed for arc4random() */
81#endif
82}
83
84
85/*
86 * ntp_crypto_random_buf:
87 *
88 * Returns 0 on success, -1 on error.
89 */
90int
91ntp_crypto_random_buf(
92	void *buf,
93	size_t nbytes
94	)
95{
96#ifdef USE_OPENSSL_CRYPTO_RAND
97	int rc;
98
99	rc = RAND_bytes(buf, size2int_chk(nbytes));
100	if (1 != rc) {
101		unsigned long err;
102		char *err_str;
103
104		err = ERR_get_error();
105		err_str = ERR_error_string(err, NULL);
106		/* XXX: Log the error */
107		(void)&err_str;
108
109		return -1;
110	}
111	return 0;
112#else
113	arc4random_buf(buf, nbytes);
114	return 0;
115#endif
116}
117