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