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