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