mhd_rng.c (6039B)
1 /* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */ 2 /* 3 This file is part of GNU libmicrohttpd. 4 Copyright (C) 2025 Christian Grothoff 5 6 GNU libmicrohttpd is free software; you can redistribute it and/or 7 modify it under the terms of the GNU Lesser General Public 8 License as published by the Free Software Foundation; either 9 version 2.1 of the License, or (at your option) any later version. 10 11 GNU libmicrohttpd is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 Lesser General Public License for more details. 15 16 Alternatively, you can redistribute GNU libmicrohttpd and/or 17 modify it under the terms of the GNU General Public License as 18 published by the Free Software Foundation; either version 2 of 19 the License, or (at your option) any later version, together 20 with the eCos exception, as follows: 21 22 As a special exception, if other files instantiate templates or 23 use macros or inline functions from this file, or you compile this 24 file and link it with other works to produce a work based on this 25 file, this file does not by itself cause the resulting work to be 26 covered by the GNU General Public License. However the source code 27 for this file must still be made available in accordance with 28 section (3) of the GNU General Public License v2. 29 30 This exception does not invalidate any other reasons why a work 31 based on this file might be covered by the GNU General Public 32 License. 33 34 You should have received copies of the GNU Lesser General Public 35 License and the GNU General Public License along with this library; 36 if not, see <https://www.gnu.org/licenses/>. 37 */ 38 39 /** 40 * @file src/mhd2/mhd_rng.c 41 * @brief generate random numbers using the best available method; 42 * we begin by trying the TLS libraries, then common operating-system 43 * specific methods, then fall back to /dev/urandom or /dev/random 44 * and if nothing works hash our entropy pool mixing in data from 45 * the context 46 * @author Christian Grothoff 47 */ 48 49 #include "mhd_sys_options.h" 50 #include "mhd_digest_auth_data.h" 51 52 #include "mhd_assert.h" 53 54 #include <string.h> 55 #include "sys_errno.h" 56 57 #if defined(MHD_SUPPORT_OPENSSL) 58 # include <openssl/rand.h> 59 #endif 60 #if defined(MHD_SUPPORT_GNUTLS) 61 # include <gnutls/crypto.h> 62 #endif 63 #if defined(MHD_SUPPORT_MBEDTLS) 64 # include <mbedtls/entropy.h> 65 # include <mbedtls/ctr_drbg.h> 66 #endif 67 #if defined(__linux__) 68 # include <sys/random.h> 69 # include <unistd.h> 70 #elif defined(_WIN32) || defined(_WIN64) 71 # include <windows.h> 72 # include <bcrypt.h> 73 # pragma comment(lib, "bcrypt.lib") 74 #elif defined(__FreeBSD__) 75 # include <sys/random.h> 76 #else 77 # include <stdio.h> 78 # include <unistd.h> 79 #endif 80 81 #include "mhd_mono_clock.h" 82 #include "mhd_atomic_counter.h" 83 84 #include "mhd_rng.h" 85 86 87 MHD_INTERNAL bool 88 mhd_rng (size_t buf_size, 89 uint8_t buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)]) 90 { 91 #if defined(MHD_SUPPORT_OPENSSL) 92 /* OpenSSL - RAND_bytes() */ 93 mhd_assert (buf_size == (size_t)(int)buf_size); 94 mhd_assert (0 < (int)buf_size); 95 if (1 == RAND_bytes ((unsigned char *)buf, 96 (int)buf_size)) 97 return true; 98 #endif 99 #if defined(MHD_SUPPORT_GNUTLS) 100 /* GnuTLS - gnutls_rnd() */ 101 if (0 == 102 gnutls_rnd (GNUTLS_RND_RANDOM, buf, 103 buf_size)) 104 return true; 105 #endif 106 #if defined(MHD_SUPPORT_MBEDTLS) 107 { 108 /* mbedTLS - requires entropy context and DRBG */ 109 static mbedtls_entropy_context entropy; 110 static mbedtls_ctr_drbg_context ctr_drbg; 111 static int initialized = 0; 112 113 if (0 == initialized) 114 { 115 mbedtls_entropy_init (&entropy); 116 mbedtls_ctr_drbg_init (&ctr_drbg); 117 118 if (0 != 119 mbedtls_ctr_drbg_seed (&ctr_drbg, 120 mbedtls_entropy_func, 121 &entropy, 122 NULL, 123 0)) 124 { 125 initialized = -1; 126 } 127 else 128 { 129 initialized = 1; 130 } 131 } 132 133 if ((1 == initialized) 134 && (0 == 135 mbedtls_ctr_drbg_random (&ctr_drbg, 136 (unsigned char *)buf, 137 buf_size))) 138 return true; 139 } 140 #endif 141 #if defined(__linux__) && defined(__GLIBC__) && \ 142 (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25)) 143 { 144 /* Modern Linux with glibc >= 2.25 - getrandom() syscall */ 145 size_t offset = 0; 146 unsigned char *ptr = (unsigned char *)buf; 147 148 while (1) 149 { 150 ssize_t ret; 151 152 ret = getrandom (ptr + offset, 153 buf_size - offset, 154 0); 155 if (ret < 0) 156 { 157 if (EINTR == errno) 158 { 159 continue; 160 } 161 break; /* failure */ 162 } 163 offset += (size_t)ret; 164 if (offset == buf_size) 165 return true; 166 } 167 } 168 #elif defined(_WIN32) || defined(_WIN64) 169 /* Windows - BCryptGenRandom() */ 170 if (STATUS_SUCCESS == 171 BCryptGenRandom (NULL, 172 (PUCHAR)buf, 173 (ULONG)buf_size, 174 BCRYPT_USE_SYSTEM_PREFERRED_RNG)) 175 return true; 176 #elif defined(__FreeBSD__) 177 /* FreeBSD - arc4random_buf() */ 178 arc4random_buf (buf, 179 buf_size); 180 return true; 181 #else 182 /* Generic UNIX fallback - read from /dev/urandom */ 183 { 184 static int tried = 0; 185 static FILE *fp = NULL; 186 187 if ((0 == tried) 188 && (NULL == fp)) 189 { 190 tried = 1; 191 fp = fopen ("/dev/urandom", 192 "rb"); 193 if (NULL == fp) 194 { 195 /* Try /dev/random as last resort */ 196 fp = fopen ("/dev/random", 197 "rb"); 198 } 199 } 200 if (NULL != fp) 201 { 202 size_t bytes_read; 203 204 bytes_read = fread (buf, 205 1, 206 buf_size, 207 fp); 208 if (bytes_read == buf_size) 209 return true; 210 } 211 } 212 #endif 213 return false; 214 }