libmicrohttpd2

HTTP server C library (MHD 2.x, alpha)
Log | Files | Refs | README | LICENSE

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 }