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 | } |