1c87c5fbaSopenharmony_ci/* 2c87c5fbaSopenharmony_ci * coap_prng.c -- random number generation 3c87c5fbaSopenharmony_ci * 4c87c5fbaSopenharmony_ci * Copyright (C) 2020-2023 Olaf Bergmann <bergmann@tzi.org> 5c87c5fbaSopenharmony_ci * 6c87c5fbaSopenharmony_ci * SPDX-License-Identifier: BSD-2-Clause 7c87c5fbaSopenharmony_ci * 8c87c5fbaSopenharmony_ci * This file is part of the CoAP library libcoap. Please see README 9c87c5fbaSopenharmony_ci * for terms of use. 10c87c5fbaSopenharmony_ci */ 11c87c5fbaSopenharmony_ci 12c87c5fbaSopenharmony_ci/** 13c87c5fbaSopenharmony_ci * @file coap_prng.c 14c87c5fbaSopenharmony_ci * @brief Pseudo Random Number functions 15c87c5fbaSopenharmony_ci */ 16c87c5fbaSopenharmony_ci 17c87c5fbaSopenharmony_ci#include "coap3/coap_internal.h" 18c87c5fbaSopenharmony_ci 19c87c5fbaSopenharmony_ci#ifdef HAVE_GETRANDOM 20c87c5fbaSopenharmony_ci#include <sys/random.h> 21c87c5fbaSopenharmony_ci#elif defined(WITH_CONTIKI) 22c87c5fbaSopenharmony_ci#include "lib/csprng.h" 23c87c5fbaSopenharmony_ci#else /* !WITH_CONTIKI */ 24c87c5fbaSopenharmony_ci#include <stdlib.h> 25c87c5fbaSopenharmony_ci#endif /* !WITH_CONTIKI */ 26c87c5fbaSopenharmony_ci 27c87c5fbaSopenharmony_ci#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) 28c87c5fbaSopenharmony_ci#include <entropy_poll.h> 29c87c5fbaSopenharmony_ci#endif /* MBEDTLS_ENTROPY_HARDWARE_ALT */ 30c87c5fbaSopenharmony_ci 31c87c5fbaSopenharmony_ci#if defined(_WIN32) 32c87c5fbaSopenharmony_ci 33c87c5fbaSopenharmony_cierrno_t __cdecl rand_s(_Out_ unsigned int *_RandomValue); 34c87c5fbaSopenharmony_ci/** 35c87c5fbaSopenharmony_ci * Fills \p buf with \p len random bytes. This is the default implementation for 36c87c5fbaSopenharmony_ci * coap_prng(). You might want to change coap_prng_impl() to use a better 37c87c5fbaSopenharmony_ci * PRNG on your specific platform. 38c87c5fbaSopenharmony_ci */ 39c87c5fbaSopenharmony_ciCOAP_STATIC_INLINE int 40c87c5fbaSopenharmony_cicoap_prng_impl(unsigned char *buf, size_t len) { 41c87c5fbaSopenharmony_ci while (len != 0) { 42c87c5fbaSopenharmony_ci uint32_t r = 0; 43c87c5fbaSopenharmony_ci size_t i; 44c87c5fbaSopenharmony_ci 45c87c5fbaSopenharmony_ci if (rand_s(&r) != 0) 46c87c5fbaSopenharmony_ci return 0; 47c87c5fbaSopenharmony_ci for (i = 0; i < len && i < 4; i++) { 48c87c5fbaSopenharmony_ci *buf++ = (uint8_t)r; 49c87c5fbaSopenharmony_ci r >>= 8; 50c87c5fbaSopenharmony_ci } 51c87c5fbaSopenharmony_ci len -= i; 52c87c5fbaSopenharmony_ci } 53c87c5fbaSopenharmony_ci return 1; 54c87c5fbaSopenharmony_ci} 55c87c5fbaSopenharmony_ci 56c87c5fbaSopenharmony_ci#endif /* _WIN32 */ 57c87c5fbaSopenharmony_ci 58c87c5fbaSopenharmony_ci/* 59c87c5fbaSopenharmony_ci * This, or any user provided alternative, function is expected to 60c87c5fbaSopenharmony_ci * return 0 on failure and 1 on success. 61c87c5fbaSopenharmony_ci */ 62c87c5fbaSopenharmony_cistatic int 63c87c5fbaSopenharmony_cicoap_prng_default(void *buf, size_t len) { 64c87c5fbaSopenharmony_ci#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) 65c87c5fbaSopenharmony_ci /* mbedtls_hardware_poll() returns 0 on success */ 66c87c5fbaSopenharmony_ci return (mbedtls_hardware_poll(NULL, buf, len, NULL) ? 0 : 1); 67c87c5fbaSopenharmony_ci 68c87c5fbaSopenharmony_ci#elif defined(HAVE_GETRANDOM) 69c87c5fbaSopenharmony_ci return (getrandom(buf, len, 0) > 0) ? 1 : 0; 70c87c5fbaSopenharmony_ci 71c87c5fbaSopenharmony_ci#elif defined(HAVE_RANDOM) 72c87c5fbaSopenharmony_ci#define RAND_BYTES (RAND_MAX >= 0xffffff ? 3 : (RAND_MAX >= 0xffff ? 2 : 1)) 73c87c5fbaSopenharmony_ci unsigned char *dst = (unsigned char *)buf; 74c87c5fbaSopenharmony_ci 75c87c5fbaSopenharmony_ci if (len) { 76c87c5fbaSopenharmony_ci uint8_t byte_counter = RAND_BYTES; 77c87c5fbaSopenharmony_ci uint32_t r_v = random(); 78c87c5fbaSopenharmony_ci 79c87c5fbaSopenharmony_ci while (1) { 80c87c5fbaSopenharmony_ci *dst++ = r_v & 0xFF; 81c87c5fbaSopenharmony_ci if (!--len) { 82c87c5fbaSopenharmony_ci break; 83c87c5fbaSopenharmony_ci } 84c87c5fbaSopenharmony_ci if (--byte_counter) { 85c87c5fbaSopenharmony_ci r_v >>= 8; 86c87c5fbaSopenharmony_ci } else { 87c87c5fbaSopenharmony_ci r_v = random(); 88c87c5fbaSopenharmony_ci byte_counter = RAND_BYTES; 89c87c5fbaSopenharmony_ci } 90c87c5fbaSopenharmony_ci } 91c87c5fbaSopenharmony_ci } 92c87c5fbaSopenharmony_ci return 1; 93c87c5fbaSopenharmony_ci#elif defined(RIOT_VERSION) 94c87c5fbaSopenharmony_ci#include <random.h> 95c87c5fbaSopenharmony_ci random_bytes(buf, len); 96c87c5fbaSopenharmony_ci return 1; 97c87c5fbaSopenharmony_ci 98c87c5fbaSopenharmony_ci#elif defined(WITH_CONTIKI) 99c87c5fbaSopenharmony_ci return csprng_rand(buf, len); 100c87c5fbaSopenharmony_ci 101c87c5fbaSopenharmony_ci#elif defined(_WIN32) 102c87c5fbaSopenharmony_ci return coap_prng_impl(buf,len); 103c87c5fbaSopenharmony_ci 104c87c5fbaSopenharmony_ci#else /* !MBEDTLS_ENTROPY_HARDWARE_ALT && !HAVE_GETRANDOM && 105c87c5fbaSopenharmony_ci !HAVE_RANDOM && !_WIN32 */ 106c87c5fbaSopenharmony_ci#error "CVE-2021-34430: using rand() for crypto randoms is not secure!" 107c87c5fbaSopenharmony_ci#error "Please update you C-library and rerun the auto-configuration." 108c87c5fbaSopenharmony_ci unsigned char *dst = (unsigned char *)buf; 109c87c5fbaSopenharmony_ci while (len--) 110c87c5fbaSopenharmony_ci *dst++ = rand() & 0xFF; 111c87c5fbaSopenharmony_ci return 1; 112c87c5fbaSopenharmony_ci#endif /* !MBEDTLS_ENTROPY_HARDWARE_ALT && !HAVE_GETRANDOM && 113c87c5fbaSopenharmony_ci !HAVE_RANDOM && !_WIN32 */ 114c87c5fbaSopenharmony_ci} 115c87c5fbaSopenharmony_ci 116c87c5fbaSopenharmony_cistatic coap_rand_func_t rand_func = coap_prng_default; 117c87c5fbaSopenharmony_ci 118c87c5fbaSopenharmony_ci#if defined(WITH_LWIP) && defined(LWIP_RAND) 119c87c5fbaSopenharmony_ci 120c87c5fbaSopenharmony_ci#else 121c87c5fbaSopenharmony_ci 122c87c5fbaSopenharmony_civoid 123c87c5fbaSopenharmony_cicoap_set_prng(coap_rand_func_t rng) { 124c87c5fbaSopenharmony_ci rand_func = rng; 125c87c5fbaSopenharmony_ci} 126c87c5fbaSopenharmony_ci 127c87c5fbaSopenharmony_civoid 128c87c5fbaSopenharmony_cicoap_prng_init(unsigned int seed) { 129c87c5fbaSopenharmony_ci#ifdef HAVE_GETRANDOM 130c87c5fbaSopenharmony_ci /* No seed to seed the random source if getrandom() is used */ 131c87c5fbaSopenharmony_ci (void)seed; 132c87c5fbaSopenharmony_ci#elif defined(HAVE_RANDOM) 133c87c5fbaSopenharmony_ci srandom(seed); 134c87c5fbaSopenharmony_ci#else /* !HAVE_GETRANDOM && !HAVE_RANDOM */ 135c87c5fbaSopenharmony_ci srand(seed); 136c87c5fbaSopenharmony_ci#endif /* !HAVE_GETRANDOM */ 137c87c5fbaSopenharmony_ci} 138c87c5fbaSopenharmony_ci 139c87c5fbaSopenharmony_ciint 140c87c5fbaSopenharmony_cicoap_prng(void *buf, size_t len) { 141c87c5fbaSopenharmony_ci if (!rand_func) { 142c87c5fbaSopenharmony_ci return 0; 143c87c5fbaSopenharmony_ci } 144c87c5fbaSopenharmony_ci 145c87c5fbaSopenharmony_ci return rand_func(buf, len); 146c87c5fbaSopenharmony_ci} 147c87c5fbaSopenharmony_ci 148c87c5fbaSopenharmony_ci#endif 149