Coverage Report

Created: 2026-01-10 06:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libcoap/src/coap_prng.c
Line
Count
Source
1
/*
2
 * coap_prng.c -- random number generation
3
 *
4
 * Copyright (C) 2020-2026 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_libcoap_build.h"
18
19
20
#if defined(__ZEPHYR__)
21
#include <zephyr/random/random.h>
22
#elif defined(HAVE_GETRANDOM)
23
#include <sys/random.h>
24
#elif defined(WITH_CONTIKI)
25
#include "lib/csprng.h"
26
#else /* !WITH_CONTIKI */
27
#include <stdlib.h>
28
#endif /* !WITH_CONTIKI */
29
30
#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT)
31
#include <entropy_poll.h>
32
#endif /* MBEDTLS_ENTROPY_HARDWARE_ALT */
33
34
#if defined(_WIN32)
35
36
errno_t __cdecl rand_s(_Out_ unsigned int *_RandomValue);
37
/**
38
 * Fills \p buf with \p len random bytes. This is the default implementation for
39
 * coap_prng(). You might want to change coap_prng_impl() to use a better
40
 * PRNG on your specific platform.
41
 */
42
COAP_STATIC_INLINE int
43
coap_prng_impl(unsigned char *buf, size_t len) {
44
  while (len != 0) {
45
    uint32_t r = 0;
46
    size_t i;
47
48
    if (rand_s(&r) != 0)
49
      return 0;
50
    for (i = 0; i < len && i < 4; i++) {
51
      *buf++ = (uint8_t)r;
52
      r >>= 8;
53
    }
54
    len -= i;
55
  }
56
  return 1;
57
}
58
59
#endif /* _WIN32 */
60
61
COAP_API void
62
0
coap_prng_init(unsigned int seed) {
63
0
  coap_lock_lock(return);
64
0
  coap_prng_init_lkd(seed);
65
0
  coap_lock_unlock();
66
0
}
67
68
COAP_API int
69
0
coap_prng(void *buf, size_t len) {
70
0
  int ret;
71
72
0
  coap_lock_lock(return 0);
73
0
  ret = coap_prng_lkd(buf, len);
74
0
  coap_lock_unlock();
75
0
  return ret;
76
0
}
77
78
#if defined(WITH_LWIP) && defined(LWIP_RAND)
79
80
void
81
coap_prng_init_lkd(unsigned int seed) {
82
  (void)seed;
83
}
84
85
int
86
coap_prng_lkd(void *bufp, size_t len) {
87
  unsigned char *buf = (unsigned char *)bufp;
88
  u32_t v = LWIP_RAND();
89
90
  while (len > sizeof(v)) {
91
    memcpy(buf, &v, sizeof(v));
92
    len -= sizeof(v);
93
    buf += sizeof(v);
94
    v = LWIP_RAND();
95
  }
96
97
  memcpy(buf, &v, len);
98
  return 1;
99
}
100
101
#else
102
103
/*
104
 * This, or any user provided alternative, function is expected to
105
 * return 0 on failure and 1 on success.
106
 */
107
static int
108
0
coap_prng_default(void *buf, size_t len) {
109
#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT)
110
  /* mbedtls_hardware_poll() returns 0 on success */
111
  return (mbedtls_hardware_poll(NULL, buf, len, NULL) ? 0 : 1);
112
113
#elif defined(__ZEPHYR__)
114
  /* Use Zephyr's cryptographically secure random number generator */
115
  if (!buf || len == 0) {
116
    return 0;
117
  }
118
119
  sys_rand_get(buf, len);
120
  return 1;
121
122
#elif defined(HAVE_GETRANDOM)
123
0
  return (getrandom(buf, len, 0) > 0) ? 1 : 0;
124
125
#elif defined(HAVE_RANDOM)
126
#define RAND_BYTES (RAND_MAX >= 0xffffff ? 3 : (RAND_MAX >= 0xffff ? 2 : 1))
127
  unsigned char *dst = (unsigned char *)buf;
128
129
  if (len) {
130
    uint8_t byte_counter = RAND_BYTES;
131
    uint32_t r_v = random();
132
133
    while (1) {
134
      *dst++ = r_v & 0xFF;
135
      if (!--len) {
136
        break;
137
      }
138
      if (--byte_counter) {
139
        r_v >>= 8;
140
      } else {
141
        r_v = random();
142
        byte_counter = RAND_BYTES;
143
      }
144
    }
145
  }
146
  return 1;
147
#elif defined(RIOT_VERSION)
148
#include <random.h>
149
  random_bytes(buf, len);
150
  return 1;
151
152
#elif defined(WITH_CONTIKI)
153
  return csprng_rand(buf, len);
154
155
#elif defined(_WIN32)
156
  return coap_prng_impl(buf,len);
157
158
#else /* !MBEDTLS_ENTROPY_HARDWARE_ALT && !HAVE_GETRANDOM &&
159
         !HAVE_RANDOM && !_WIN32 */
160
#error "CVE-2021-34430: using rand() for crypto randoms is not secure!"
161
#error "Please update you C-library and rerun the auto-configuration."
162
  unsigned char *dst = (unsigned char *)buf;
163
  while (len--)
164
    *dst++ = rand() & 0xFF;
165
  return 1;
166
#endif /* !MBEDTLS_ENTROPY_HARDWARE_ALT && !HAVE_GETRANDOM &&
167
          !HAVE_RANDOM && !_WIN32 */
168
0
}
169
170
static coap_rand_func_t rand_func = coap_prng_default;
171
172
void
173
0
coap_set_prng(coap_rand_func_t rng) {
174
0
  rand_func = rng;
175
0
}
176
177
void
178
0
coap_prng_init_lkd(unsigned int seed) {
179
0
#ifdef HAVE_GETRANDOM
180
  /* No seed to seed the random source if getrandom() is used */
181
0
  (void)seed;
182
#elif defined(HAVE_RANDOM)
183
  srandom(seed);
184
#else /* !HAVE_GETRANDOM  && !HAVE_RANDOM */
185
  srand(seed);
186
#endif /* !HAVE_GETRANDOM */
187
0
}
188
189
int
190
0
coap_prng_lkd(void *buf, size_t len) {
191
0
  if (!rand_func) {
192
0
    return 0;
193
0
  }
194
195
0
  return rand_func(buf, len);
196
0
}
197
198
#endif