mhd_rng.c (6158B)
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 <string.h> 53 #include "sys_errno.h" 54 55 #if defined(MHD_SUPPORT_OPENSSL) 56 #include <openssl/rand.h> 57 #endif 58 #if defined(MHD_SUPPORT_GNUTLS) 59 #include <gnutls/crypto.h> 60 #endif 61 #if defined(MHD_SUPPORT_MBEDTLS) 62 #include <mbedtls/entropy.h> 63 #include <mbedtls/ctr_drbg.h> 64 #endif 65 #if defined(__linux__) 66 #include <sys/random.h> 67 #include <unistd.h> 68 #elif defined(_WIN32) || defined(_WIN64) 69 #include <windows.h> 70 #include <bcrypt.h> 71 #pragma comment(lib, "bcrypt.lib") 72 #elif defined(__FreeBSD__) 73 #include <sys/random.h> 74 #else 75 #include <stdio.h> 76 #include <unistd.h> 77 #endif 78 79 #ifdef MHD_SUPPORT_SHA512_256 80 # include "mhd_sha512_256.h" 81 #endif /* MHD_SUPPORT_SHA512_256 */ 82 #ifdef MHD_SUPPORT_SHA256 83 # include "mhd_sha256.h" 84 #endif 85 #ifdef MHD_SUPPORT_MD5 86 # include "mhd_md5.h" 87 #endif 88 89 #include "mhd_mono_clock.h" 90 #include "mhd_atomic_counter.h" 91 92 #include "mhd_rng.h" 93 94 95 MHD_INTERNAL bool 96 mhd_rng (size_t buf_size, 97 uint8_t buf[MHD_FN_PAR_DYN_ARR_SIZE_ (buf_size)]) 98 { 99 #if defined(MHD_SUPPORT_OPENSSL) 100 /* OpenSSL - RAND_bytes() */ 101 mhd_assert (buf_size < INT_MAX); 102 if (1 == RAND_bytes ((unsigned char *) buf, 103 (int) buf_size)) 104 return true; 105 #endif 106 #if defined(MHD_SUPPORT_GNUTLS) 107 /* GnuTLS - gnutls_rnd() */ 108 if (0 == 109 gnutls_rnd (GNUTLS_RND_RANDOM, buf, 110 buf_size)) 111 return true; 112 #endif 113 #if defined(MHD_SUPPORT_MBEDTLS) 114 { 115 /* mbedTLS - requires entropy context and DRBG */ 116 static mbedtls_entropy_context entropy; 117 static mbedtls_ctr_drbg_context ctr_drbg; 118 static int initialized = 0; 119 120 if (0 == initialized) 121 { 122 mbedtls_entropy_init (&entropy); 123 mbedtls_ctr_drbg_init (&ctr_drbg); 124 125 if (0 != 126 mbedtls_ctr_drbg_seed (&ctr_drbg, 127 mbedtls_entropy_func, 128 &entropy, 129 NULL, 130 0)) 131 { 132 initialized = -1; 133 } 134 else 135 { 136 initialized = 1; 137 } 138 } 139 140 if ( (1 == initialized) && 141 (0 == 142 mbedtls_ctr_drbg_random (&ctr_drbg, 143 (unsigned char *) buf, 144 buf_size)) ) 145 return true; 146 } 147 #endif 148 #if defined(__linux__) && defined(__GLIBC__) && \ 149 (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25)) 150 { 151 /* Modern Linux with glibc >= 2.25 - getrandom() syscall */ 152 size_t offset = 0; 153 unsigned char *ptr = (unsigned char *) buf; 154 155 while (1) 156 { 157 ssize_t ret; 158 159 ret = getrandom (ptr + offset, 160 buf_size - offset, 161 0); 162 if (ret < 0) 163 { 164 if (EINTR == errno) 165 { 166 continue; 167 } 168 break; /* failure */ 169 } 170 offset += (size_t) ret; 171 if (offset == buf_size) 172 return true; 173 } 174 } 175 #elif defined(_WIN32) || defined(_WIN64) 176 /* Windows - BCryptGenRandom() */ 177 if (STATUS_SUCCESS == 178 BCryptGenRandom (NULL, 179 (PUCHAR) buf, 180 (ULONG) buf_size, 181 BCRYPT_USE_SYSTEM_PREFERRED_RNG)) 182 return true; 183 #elif defined(__FreeBSD__) 184 /* FreeBSD - arc4random_buf() */ 185 arc4random_buf (buf, 186 buf_size); 187 return true; 188 #else 189 /* Generic UNIX fallback - read from /dev/urandom */ 190 { 191 static int tried = 0; 192 static FILE *fp = NULL; 193 194 if ( (0 == tried) && 195 (NULL == fp) ) 196 { 197 tried = 1; 198 fp = fopen ("/dev/urandom", 199 "rb"); 200 if (NULL == fp) 201 { 202 /* Try /dev/random as last resort */ 203 fp = fopen ("/dev/random", 204 "rb"); 205 } 206 } 207 if (NULL != fp) 208 { 209 size_t bytes_read; 210 211 bytes_read = fread (buf, 212 1, 213 buf_size, 214 fp); 215 if (bytes_read == buf_size) 216 return true; 217 } 218 } 219 #endif 220 return false; 221 }