libmicrohttpd2

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

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 }