• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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