Coverage Report

Created: 2026-08-14 07:12

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
static unsigned int random_seed;
81
82
void
83
coap_prng_init_lkd(unsigned int seed) {
84
  random_seed = seed;
85
}
86
87
int
88
coap_prng_lkd(void *bufp, size_t len) {
89
  unsigned char *buf = (unsigned char *)bufp;
90
  u32_t v = LWIP_RAND() + random_seed;
91
92
  while (len > sizeof(v)) {
93
    memcpy(buf, &v, sizeof(v));
94
    len -= sizeof(v);
95
    buf += sizeof(v);
96
    v = LWIP_RAND();
97
  }
98
99
  memcpy(buf, &v, len);
100
  return 1;
101
}
102
103
#else
104
105
/*
106
 * This, or any user provided alternative, function is expected to
107
 * return 0 on failure and 1 on success.
108
 */
109
static int
110
131
coap_prng_default(void *buf, size_t len) {
111
#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT)
112
  /* mbedtls_hardware_poll() returns 0 on success */
113
  return (mbedtls_hardware_poll(NULL, buf, len, NULL) ? 0 : 1);
114
115
#elif defined(__ZEPHYR__)
116
  /* Use Zephyr's cryptographically secure random number generator */
117
  if (!buf || len == 0) {
118
    return 0;
119
  }
120
121
  sys_rand_get(buf, len);
122
  return 1;
123
124
#elif defined(HAVE_GETRANDOM)
125
131
  return (getrandom(buf, len, 0) > 0) ? 1 : 0;
126
127
#elif defined(HAVE_RANDOM)
128
#define RAND_BYTES (RAND_MAX >= 0xffffff ? 3 : (RAND_MAX >= 0xffff ? 2 : 1))
129
  unsigned char *dst = (unsigned char *)buf;
130
131
  if (len) {
132
    uint8_t byte_counter = RAND_BYTES;
133
    uint32_t r_v = random();
134
135
    while (1) {
136
      *dst++ = r_v & 0xFF;
137
      if (!--len) {
138
        break;
139
      }
140
      if (--byte_counter) {
141
        r_v >>= 8;
142
      } else {
143
        r_v = random();
144
        byte_counter = RAND_BYTES;
145
      }
146
    }
147
  }
148
  return 1;
149
#elif defined(RIOT_VERSION)
150
#include <random.h>
151
  random_bytes(buf, len);
152
  return 1;
153
154
#elif defined(WITH_CONTIKI)
155
  return csprng_rand(buf, len);
156
157
#elif defined(_WIN32)
158
  return coap_prng_impl(buf,len);
159
160
#else /* !MBEDTLS_ENTROPY_HARDWARE_ALT && !HAVE_GETRANDOM &&
161
         !HAVE_RANDOM && !_WIN32 */
162
#error "CVE-2021-34430: using rand() for crypto randoms is not secure!"
163
#error "Please update you C-library and rerun the auto-configuration."
164
  unsigned char *dst = (unsigned char *)buf;
165
  while (len--)
166
    *dst++ = rand() & 0xFF;
167
  return 1;
168
#endif /* !MBEDTLS_ENTROPY_HARDWARE_ALT && !HAVE_GETRANDOM &&
169
          !HAVE_RANDOM && !_WIN32 */
170
131
}
171
172
static coap_rand_func_t rand_func = coap_prng_default;
173
174
void
175
0
coap_set_prng(coap_rand_func_t rng) {
176
0
  rand_func = rng;
177
0
}
178
179
void
180
28
coap_prng_init_lkd(unsigned int seed) {
181
28
#ifdef HAVE_GETRANDOM
182
  /* No seed to seed the random source if getrandom() is used */
183
28
  (void)seed;
184
#elif defined(HAVE_RANDOM)
185
  srandom(seed);
186
#else /* !HAVE_GETRANDOM  && !HAVE_RANDOM */
187
  srand(seed);
188
#endif /* !HAVE_GETRANDOM */
189
28
}
190
191
int
192
131
coap_prng_lkd(void *buf, size_t len) {
193
131
  if (!rand_func) {
194
0
    return 0;
195
0
  }
196
197
131
  return rand_func(buf, len);
198
131
}
199
200
#endif