Coverage Report

Created: 2024-06-20 06:28

/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
#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
38
extern gnutls_crypto_rnd_st _gnutls_fuzz_rnd_ops;
39
#endif
40
41
/* A global list of all allocated contexts.
42
 * A safety measure in case thread specific
43
 * context cannot be freed on thread exit
44
 */
45
GNUTLS_STATIC_MUTEX(gnutls_rnd_list_mutex);
46
static gl_list_t list;
47
48
/* Key used to locate and manage thread specific random generator context
49
 */
50
static gl_tls_key_t ctx_key;
51
52
/* Flag to indicate initialization
53
 */
54
static _Thread_local unsigned rnd_initialized = 0;
55
56
static void free_ctx(const void *ctx)
57
0
{
58
0
  if (ctx && _gnutls_rnd_ops.deinit)
59
0
    _gnutls_rnd_ops.deinit((void *)ctx);
60
0
}
61
62
static void delete_ctx(void *ctx)
63
0
{
64
0
  (void)gnutls_static_mutex_lock(&gnutls_rnd_list_mutex);
65
0
  gl_list_remove(list, ctx);
66
0
  gnutls_static_mutex_unlock(&gnutls_rnd_list_mutex);
67
0
}
68
69
static inline int _gnutls_rnd_init(void)
70
0
{
71
0
  int ret;
72
0
  void *ctx;
73
0
  gl_list_node_t node;
74
75
0
  if (likely(rnd_initialized))
76
0
    return 0;
77
78
0
  if (_gnutls_rnd_ops.init == NULL) {
79
0
    rnd_initialized = 1;
80
0
    return 0;
81
0
  }
82
83
0
  if (_gnutls_rnd_ops.init(&ctx) < 0)
84
0
    return gnutls_assert_val(GNUTLS_E_RANDOM_FAILED);
85
86
0
  if (glthread_tls_set(&ctx_key, ctx)) {
87
0
    _gnutls_rnd_ops.deinit(ctx);
88
0
    return gnutls_assert_val(GNUTLS_E_RANDOM_FAILED);
89
0
  }
90
91
0
  ret = gnutls_static_mutex_lock(&gnutls_rnd_list_mutex);
92
0
  if (ret < 0)
93
0
    return gnutls_assert_val(ret);
94
0
  node = gl_list_nx_add_last(list, ctx);
95
0
  gnutls_static_mutex_unlock(&gnutls_rnd_list_mutex);
96
0
  if (node == NULL) {
97
0
    _gnutls_rnd_ops.deinit(ctx);
98
0
    return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
99
0
  }
100
101
0
  rnd_initialized = 1;
102
0
  return 0;
103
0
}
104
105
int _gnutls_rnd_preinit(void)
106
2
{
107
2
  int ret;
108
109
2
#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
110
2
#warning Insecure PRNG is enabled
111
2
  ret = gnutls_crypto_rnd_register(100, &_gnutls_fuzz_rnd_ops);
112
2
  if (ret < 0)
113
0
    return ret;
114
115
#elif defined(ENABLE_FIPS140)
116
  /* The FIPS140 random generator is only enabled when we are compiled
117
   * with FIPS support, _and_ the system is in FIPS installed state.
118
   */
119
  if (_gnutls_fips_mode_enabled()) {
120
    ret = gnutls_crypto_rnd_register(100, &_gnutls_fips_rnd_ops);
121
    if (ret < 0)
122
      return ret;
123
  }
124
#endif
125
126
2
  ret = _rnd_system_entropy_init();
127
2
  if (ret < 0)
128
0
    return gnutls_assert_val(GNUTLS_E_RANDOM_FAILED);
129
130
2
  ret = glthread_tls_key_init(&ctx_key, delete_ctx);
131
2
  if (ret)
132
0
    return gnutls_assert_val(GNUTLS_E_RANDOM_FAILED);
133
134
2
  list = gl_list_nx_create_empty(GL_LINKEDHASH_LIST, NULL, NULL, free_ctx,
135
2
               false);
136
2
  if (list == NULL)
137
0
    return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
138
139
2
  return 0;
140
2
}
141
142
void _gnutls_rnd_deinit(void)
143
0
{
144
0
  gl_list_free(list);
145
0
  glthread_tls_key_destroy(&ctx_key);
146
0
  rnd_initialized = 0;
147
0
  _rnd_system_entropy_deinit();
148
0
}
149
150
/**
151
 * gnutls_rnd:
152
 * @level: a security level
153
 * @data: place to store random bytes
154
 * @len: The requested size
155
 *
156
 * This function will generate random data and store it to output
157
 * buffer. The value of @level should be one of %GNUTLS_RND_NONCE,
158
 * %GNUTLS_RND_RANDOM and %GNUTLS_RND_KEY. See the manual and
159
 * %gnutls_rnd_level_t for detailed information.
160
 *
161
 * This function is thread-safe and also fork-safe.
162
 *
163
 * Returns: Zero on success, or a negative error code on error.
164
 *
165
 * Since: 2.12.0
166
 **/
167
int gnutls_rnd(gnutls_rnd_level_t level, void *data, size_t len)
168
0
{
169
0
  int ret;
170
0
  FAIL_IF_LIB_ERROR;
171
172
0
  ret = _gnutls_rnd_init();
173
0
  if (unlikely(ret < 0))
174
0
    return gnutls_assert_val(ret);
175
176
0
  if (likely(len > 0))
177
0
    return _gnutls_rnd_ops.rnd(gl_tls_get(ctx_key), level, data,
178
0
             len);
179
180
0
  return 0;
181
0
}
182
183
/**
184
 * gnutls_rnd_refresh:
185
 *
186
 * This function refreshes the random generator state.
187
 * That is the current precise time, CPU usage, and
188
 * other values are input into its state.
189
 *
190
 * On a slower rate input from /dev/urandom is mixed too.
191
 *
192
 * Since: 3.1.7
193
 **/
194
void gnutls_rnd_refresh(void)
195
0
{
196
0
  if (rnd_initialized && _gnutls_rnd_ops.rnd_refresh)
197
0
    _gnutls_rnd_ops.rnd_refresh(gl_tls_get(ctx_key));
198
0
}