libmicrohttpd2

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

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 }