Coverage Report

Created: 2025-03-06 07:58

/src/gnutls/lib/random.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2008-2012 Free Software Foundation, Inc.
3
 *
4
 * Author: Nikos Mavrogiannopoulos
5
 *
6
 * This file is part of GnuTLS.
7
 *
8
 * The GnuTLS is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public License
10
 * as published by the Free Software Foundation; either version 2.1 of
11
 * the License, or (at your option) any later version.
12
 *
13
 * This library is distributed in the hope that it will be useful, but
14
 * WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
20
 *
21
 */
22
23
/* This file handles all the internal functions that cope with random data
24
 */
25
26
#include "gnutls_int.h"
27
#include "errors.h"
28
#include "random.h"
29
#include "locks.h"
30
#include "fips.h"
31
32
#include "gl_linkedhash_list.h"
33
#include "gl_list.h"
34
#include "glthread/tls.h"
35
#include "gthreads.h"
36
37
#ifdef HAVE_LEANCRYPTO
38
#include <leancrypto.h>
39
#endif
40
41
#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
42
extern gnutls_crypto_rnd_st _gnutls_fuzz_rnd_ops;
43
#endif
44
45
/* A global list of all allocated contexts.
46
 * A safety measure in case thread specific
47
 * context cannot be freed on thread exit
48
 */
49
GNUTLS_STATIC_MUTEX(gnutls_rnd_list_mutex);
50
static gl_list_t list;
51
52
/* Key used to locate and manage thread specific random generator context
53
 */
54
static gl_tls_key_t ctx_key;
55
56
/* Flag to indicate initialization
57
 */
58
static _Thread_local unsigned rnd_initialized = 0;
59
60
static void free_ctx(const void *ctx)
61
0
{
62
0
  if (ctx && _gnutls_rnd_ops.deinit)
63
0
    _gnutls_rnd_ops.deinit((void *)ctx);
64
0
}
65
66
static void delete_ctx(void *ctx)
67
0
{
68
0
  (void)gnutls_static_mutex_lock(&gnutls_rnd_list_mutex);
69
0
  gl_list_remove(list, ctx);
70
0
  gnutls_static_mutex_unlock(&gnutls_rnd_list_mutex);
71
0
}
72
73
#ifdef HAVE_LEANCRYPTO
74
static inline int seeded_rng_generate(void *state MAYBE_UNUSED,
75
              const uint8_t *addtl_input MAYBE_UNUSED,
76
              size_t addtl_input_len MAYBE_UNUSED,
77
              uint8_t *out, size_t outlen)
78
{
79
  if (gnutls_rnd(GNUTLS_RND_KEY, out, outlen) < 0) {
80
    _gnutls_switch_lib_state(LIB_STATE_ERROR);
81
    return -EFAULT;
82
  }
83
  return 0;
84
}
85
86
static inline int seeded_rng_seed(void *state MAYBE_UNUSED,
87
          const uint8_t *seed MAYBE_UNUSED,
88
          size_t seedlen MAYBE_UNUSED,
89
          const uint8_t *persbuf MAYBE_UNUSED,
90
          size_t perslen MAYBE_UNUSED)
91
{
92
  /* Do nothing */
93
  return 0;
94
}
95
96
static inline void seeded_rng_zero(void *state MAYBE_UNUSED)
97
{
98
  /* Do nothing */
99
}
100
101
static const struct lc_rng seeded_rng = {
102
  .generate = seeded_rng_generate,
103
  .seed = seeded_rng_seed,
104
  .zero = seeded_rng_zero,
105
};
106
107
struct lc_rng_ctx seeded_rng_ctx = {
108
  .rng = &seeded_rng,
109
};
110
#endif
111
112
static inline int _gnutls_rnd_init(void)
113
0
{
114
0
  int ret;
115
0
  void *ctx;
116
0
  gl_list_node_t node;
117
118
0
  if (likely(rnd_initialized))
119
0
    return 0;
120
121
0
  if (_gnutls_rnd_ops.init == NULL) {
122
0
    rnd_initialized = 1;
123
0
    return 0;
124
0
  }
125
126
0
  if (_gnutls_rnd_ops.init(&ctx) < 0)
127
0
    return gnutls_assert_val(GNUTLS_E_RANDOM_FAILED);
128
129
0
  if (glthread_tls_set(&ctx_key, ctx)) {
130
0
    _gnutls_rnd_ops.deinit(ctx);
131
0
    return gnutls_assert_val(GNUTLS_E_RANDOM_FAILED);
132
0
  }
133
134
0
  ret = gnutls_static_mutex_lock(&gnutls_rnd_list_mutex);
135
0
  if (ret < 0)
136
0
    return gnutls_assert_val(ret);
137
0
  node = gl_list_nx_add_last(list, ctx);
138
0
  gnutls_static_mutex_unlock(&gnutls_rnd_list_mutex);
139
0
  if (node == NULL) {
140
0
    _gnutls_rnd_ops.deinit(ctx);
141
0
    return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
142
0
  }
143
144
0
  rnd_initialized = 1;
145
0
  return 0;
146
0
}
147
148
int _gnutls_rnd_preinit(void)
149
20
{
150
20
  int ret;
151
152
#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
153
#warning Insecure PRNG is enabled
154
  ret = gnutls_crypto_rnd_register(100, &_gnutls_fuzz_rnd_ops);
155
  if (ret < 0)
156
    return ret;
157
158
#elif defined(ENABLE_FIPS140)
159
  /* The FIPS140 random generator is only enabled when we are compiled
160
   * with FIPS support, _and_ the system is in FIPS installed state.
161
   */
162
  if (_gnutls_fips_mode_enabled()) {
163
    ret = gnutls_crypto_rnd_register(100, &_gnutls_fips_rnd_ops);
164
    if (ret < 0)
165
      return ret;
166
  }
167
#endif
168
169
#ifdef HAVE_LEANCRYPTO
170
  /* Some leancrypto functions need a seeded RNG either given
171
   * explicitly as a parameter, or implicitly through the
172
   * lc_seeded_rng global variable. */
173
  ret = lc_rng_set_seeded(&seeded_rng_ctx);
174
  if (ret < 0)
175
    return gnutls_assert_val(GNUTLS_E_RANDOM_FAILED);
176
#endif
177
178
20
  ret = _rnd_system_entropy_init();
179
20
  if (ret < 0)
180
0
    return gnutls_assert_val(GNUTLS_E_RANDOM_FAILED);
181
182
20
  ret = glthread_tls_key_init(&ctx_key, delete_ctx);
183
20
  if (ret)
184
0
    return gnutls_assert_val(GNUTLS_E_RANDOM_FAILED);
185
186
20
  list = gl_list_nx_create_empty(GL_LINKEDHASH_LIST, NULL, NULL, free_ctx,
187
20
               false);
188
20
  if (list == NULL)
189
0
    return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
190
191
20
  return 0;
192
20
}
193
194
void _gnutls_rnd_deinit(void)
195
0
{
196
0
  gl_list_free(list);
197
0
  glthread_tls_key_destroy(&ctx_key);
198
0
  rnd_initialized = 0;
199
0
  _rnd_system_entropy_deinit();
200
0
}
201
202
/**
203
 * gnutls_rnd:
204
 * @level: a security level
205
 * @data: place to store random bytes
206
 * @len: The requested size
207
 *
208
 * This function will generate random data and store it to output
209
 * buffer. The value of @level should be one of %GNUTLS_RND_NONCE,
210
 * %GNUTLS_RND_RANDOM and %GNUTLS_RND_KEY. See the manual and
211
 * %gnutls_rnd_level_t for detailed information.
212
 *
213
 * This function is thread-safe and also fork-safe.
214
 *
215
 * Returns: Zero on success, or a negative error code on error.
216
 *
217
 * Since: 2.12.0
218
 **/
219
int gnutls_rnd(gnutls_rnd_level_t level, void *data, size_t len)
220
0
{
221
0
  int ret;
222
0
  FAIL_IF_LIB_ERROR;
223
224
0
  ret = _gnutls_rnd_init();
225
0
  if (unlikely(ret < 0))
226
0
    return gnutls_assert_val(ret);
227
228
0
  if (likely(len > 0))
229
0
    return _gnutls_rnd_ops.rnd(gl_tls_get(ctx_key), level, data,
230
0
             len);
231
232
0
  return 0;
233
0
}
234
235
/**
236
 * gnutls_rnd_refresh:
237
 *
238
 * This function refreshes the random generator state.
239
 * That is the current precise time, CPU usage, and
240
 * other values are input into its state.
241
 *
242
 * On a slower rate input from /dev/urandom is mixed too.
243
 *
244
 * Since: 3.1.7
245
 **/
246
void gnutls_rnd_refresh(void)
247
0
{
248
0
  if (rnd_initialized && _gnutls_rnd_ops.rnd_refresh)
249
0
    _gnutls_rnd_ops.rnd_refresh(gl_tls_get(ctx_key));
250
0
}