Home | History | Annotate | Line # | Download | only in libntp
      1 /*	$NetBSD: ntp_crypto_rnd.c,v 1.7 2024/08/18 20:47:13 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 <ntp_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 
     27 int crypto_rand_init = 0;
     28 #elif !defined(HAVE_ARC4RANDOM_BUF)
     29 #include <event2/util.h>
     30 #endif
     31 
     32 int crypto_rand_ok = 0;
     33 
     34 /*
     35  * As of late 2014, here's how we plan to provide cryptographic-quality
     36  * random numbers:
     37  *
     38  * - If we are building with OpenSSL, use RAND_poll() and RAND_bytes().
     39  * - Otherwise, use arc4random().
     40  *
     41  * Use of arc4random() can be forced using configure options
     42  * --disable-openssl-random or --without-crypto.
     43  *
     44  * We can count on arc4random existing, thru the OS or thru libevent.
     45  * The quality of arc4random depends on the implementor.
     46  *
     47  * RAND_poll() doesn't show up until XXX.  If it's not present, we
     48  * need to either provide our own or use arc4random().
     49  */
     50 
     51  /*
     52   * ntp_crypto_srandom:
     53   *
     54   * Initialize the random number generator, if needed by the underlying
     55   * crypto random number generation mechanism.
     56   */
     57 
     58 void
     59 ntp_crypto_srandom(
     60 	void
     61 )
     62 {
     63 #ifdef USE_OPENSSL_CRYPTO_RAND
     64 	if (!crypto_rand_init) {
     65 		if (RAND_poll())
     66 			crypto_rand_ok = 1;
     67 		crypto_rand_init = 1;
     68 	}
     69 #elif HAVE_ARC4RANDOM_BUF
     70 	/*
     71 	 * arc4random_buf has no error return and needs no seeding nor reseeding.
     72 	 */
     73 	crypto_rand_ok = 1;
     74 #else
     75 	/*
     76 	 * Explicitly init libevent secure RNG to make sure it seeds.
     77 	 * This is the only way we can tell if it can successfully get
     78 	 * entropy from the system.
     79 	 */
     80 	if (!evutil_secure_rng_init())
     81 		crypto_rand_ok = 1;
     82 #endif
     83 }
     84 
     85 
     86 /*
     87  * ntp_crypto_random_buf:  Used by ntp-keygen
     88  *
     89  * Returns 0 on success, -1 on error.
     90  */
     91 int
     92 ntp_crypto_random_buf(
     93 	void *buf,
     94 	size_t nbytes
     95 	)
     96 {
     97 	if (!crypto_rand_ok)
     98 		return -1;
     99 
    100 #if defined(USE_OPENSSL_CRYPTO_RAND)
    101 	if (1 != RAND_bytes(buf, size2int_chk(nbytes))) {
    102 		unsigned long err;
    103 		char *err_str;
    104 
    105 		err = ERR_get_error();
    106 		err_str = ERR_error_string(err, NULL);
    107 		msyslog(LOG_ERR, "RAND_bytes failed: %s", err_str);
    108 
    109 		return -1;
    110 	}
    111 #elif defined(HAVE_ARC4RANDOM_BUF)
    112 	arc4random_buf(buf, nbytes);
    113 #else
    114 	evutil_secure_rng_get_bytes(buf, nbytes);
    115 #endif
    116 	return 0;
    117 }
    118