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