quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

entropy_poll.c (6211B)


      1 /*
      2  *  Platform-specific and custom entropy polling functions
      3  *
      4  *  Copyright The Mbed TLS Contributors
      5  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
      6  */
      7 
      8 #if defined(__linux__) || defined(__midipix__)
      9 /* Ensure that syscall() is available even when compiling with -std=c99 */
     10 #if !defined(_GNU_SOURCE)
     11 #define _GNU_SOURCE
     12 #endif
     13 #endif
     14 
     15 #include "common.h"
     16 
     17 #include <string.h>
     18 
     19 #if defined(MBEDTLS_ENTROPY_C)
     20 
     21 #include "mbedtls/entropy.h"
     22 #include "entropy_poll.h"
     23 #include "mbedtls/error.h"
     24 
     25 #if defined(MBEDTLS_TIMING_C)
     26 #include "mbedtls/timing.h"
     27 #endif
     28 #include "mbedtls/platform.h"
     29 
     30 #if !defined(MBEDTLS_NO_PLATFORM_ENTROPY)
     31 
     32 #if !defined(unix) && !defined(__unix__) && !defined(__unix) && \
     33     !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \
     34     !defined(__HAIKU__) && !defined(__midipix__) && !defined(__MVS__)
     35 #error \
     36     "Platform entropy sources only work on Unix and Windows, see MBEDTLS_NO_PLATFORM_ENTROPY in mbedtls_config.h"
     37 #endif
     38 
     39 #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
     40 
     41 #include <windows.h>
     42 #include <bcrypt.h>
     43 #include <intsafe.h>
     44 
     45 int mbedtls_platform_entropy_poll(void *data, unsigned char *output, size_t len,
     46                                   size_t *olen)
     47 {
     48     ((void) data);
     49     *olen = 0;
     50 
     51     /*
     52      * BCryptGenRandom takes ULONG for size, which is smaller than size_t on
     53      * 64-bit Windows platforms. Extract entropy in chunks of len (dependent
     54      * on ULONG_MAX) size.
     55      */
     56     while (len != 0) {
     57         unsigned long ulong_bytes =
     58             (len > ULONG_MAX) ? ULONG_MAX : (unsigned long) len;
     59 
     60         if (!BCRYPT_SUCCESS(BCryptGenRandom(NULL, output, ulong_bytes,
     61                                             BCRYPT_USE_SYSTEM_PREFERRED_RNG))) {
     62             return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
     63         }
     64 
     65         *olen += ulong_bytes;
     66         len -= ulong_bytes;
     67     }
     68 
     69     return 0;
     70 }
     71 #else /* _WIN32 && !EFIX64 && !EFI32 */
     72 
     73 /*
     74  * Test for Linux getrandom() support.
     75  * Since there is no wrapper in the libc yet, use the generic syscall wrapper
     76  * available in GNU libc and compatible libc's (eg uClibc).
     77  */
     78 #if ((defined(__linux__) && defined(__GLIBC__)) || defined(__midipix__))
     79 #include <unistd.h>
     80 #include <sys/syscall.h>
     81 #if defined(SYS_getrandom)
     82 #define HAVE_GETRANDOM
     83 #include <errno.h>
     84 
     85 static int getrandom_wrapper(void *buf, size_t buflen, unsigned int flags)
     86 {
     87     /* MemSan cannot understand that the syscall writes to the buffer */
     88 #if defined(__has_feature)
     89 #if __has_feature(memory_sanitizer)
     90     memset(buf, 0, buflen);
     91 #endif
     92 #endif
     93     return (int) syscall(SYS_getrandom, buf, buflen, flags);
     94 }
     95 #endif /* SYS_getrandom */
     96 #endif /* __linux__ || __midipix__ */
     97 
     98 #if defined(__FreeBSD__) || defined(__DragonFly__)
     99 #include <sys/param.h>
    100 #if (defined(__FreeBSD__) && __FreeBSD_version >= 1200000) || \
    101     (defined(__DragonFly__) && __DragonFly_version >= 500700)
    102 #include <errno.h>
    103 #include <sys/random.h>
    104 #define HAVE_GETRANDOM
    105 static int getrandom_wrapper(void *buf, size_t buflen, unsigned int flags)
    106 {
    107     return (int) getrandom(buf, buflen, flags);
    108 }
    109 #endif /* (__FreeBSD__ && __FreeBSD_version >= 1200000) ||
    110           (__DragonFly__ && __DragonFly_version >= 500700) */
    111 #endif /* __FreeBSD__ || __DragonFly__ */
    112 
    113 /*
    114  * Some BSD systems provide KERN_ARND.
    115  * This is equivalent to reading from /dev/urandom, only it doesn't require an
    116  * open file descriptor, and provides up to 256 bytes per call (basically the
    117  * same as getentropy(), but with a longer history).
    118  *
    119  * Documentation: https://netbsd.gw.com/cgi-bin/man-cgi?sysctl+7
    120  */
    121 #if (defined(__FreeBSD__) || defined(__NetBSD__)) && !defined(HAVE_GETRANDOM)
    122 #include <sys/param.h>
    123 #include <sys/sysctl.h>
    124 #if defined(KERN_ARND)
    125 #define HAVE_SYSCTL_ARND
    126 
    127 static int sysctl_arnd_wrapper(unsigned char *buf, size_t buflen)
    128 {
    129     int name[2];
    130     size_t len;
    131 
    132     name[0] = CTL_KERN;
    133     name[1] = KERN_ARND;
    134 
    135     while (buflen > 0) {
    136         len = buflen > 256 ? 256 : buflen;
    137         if (sysctl(name, 2, buf, &len, NULL, 0) == -1) {
    138             return -1;
    139         }
    140         buflen -= len;
    141         buf += len;
    142     }
    143     return 0;
    144 }
    145 #endif /* KERN_ARND */
    146 #endif /* __FreeBSD__ || __NetBSD__ */
    147 
    148 #include <stdio.h>
    149 
    150 int mbedtls_platform_entropy_poll(void *data,
    151                                   unsigned char *output, size_t len, size_t *olen)
    152 {
    153     FILE *file;
    154     size_t read_len;
    155     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
    156     ((void) data);
    157 
    158 #if defined(HAVE_GETRANDOM)
    159     ret = getrandom_wrapper(output, len, 0);
    160     if (ret >= 0) {
    161         *olen = (size_t) ret;
    162         return 0;
    163     } else if (errno != ENOSYS) {
    164         return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
    165     }
    166     /* Fall through if the system call isn't known. */
    167 #else
    168     ((void) ret);
    169 #endif /* HAVE_GETRANDOM */
    170 
    171 #if defined(HAVE_SYSCTL_ARND)
    172     ((void) file);
    173     ((void) read_len);
    174     if (sysctl_arnd_wrapper(output, len) == -1) {
    175         return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
    176     }
    177     *olen = len;
    178     return 0;
    179 #else
    180 
    181     *olen = 0;
    182 
    183     file = fopen("/dev/urandom", "rb");
    184     if (file == NULL) {
    185         return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
    186     }
    187 
    188     /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
    189     mbedtls_setbuf(file, NULL);
    190 
    191     read_len = fread(output, 1, len, file);
    192     if (read_len != len) {
    193         fclose(file);
    194         return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
    195     }
    196 
    197     fclose(file);
    198     *olen = len;
    199 
    200     return 0;
    201 #endif /* HAVE_SYSCTL_ARND */
    202 }
    203 #endif /* _WIN32 && !EFIX64 && !EFI32 */
    204 #endif /* !MBEDTLS_NO_PLATFORM_ENTROPY */
    205 
    206 #if defined(MBEDTLS_ENTROPY_NV_SEED)
    207 int mbedtls_nv_seed_poll(void *data,
    208                          unsigned char *output, size_t len, size_t *olen)
    209 {
    210     unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE];
    211     size_t use_len = MBEDTLS_ENTROPY_BLOCK_SIZE;
    212     ((void) data);
    213 
    214     memset(buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE);
    215 
    216     if (mbedtls_nv_seed_read(buf, MBEDTLS_ENTROPY_BLOCK_SIZE) < 0) {
    217         return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
    218     }
    219 
    220     if (len < use_len) {
    221         use_len = len;
    222     }
    223 
    224     memcpy(output, buf, use_len);
    225     *olen = use_len;
    226 
    227     return 0;
    228 }
    229 #endif /* MBEDTLS_ENTROPY_NV_SEED */
    230 
    231 #endif /* MBEDTLS_ENTROPY_C */