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 | | #if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) |
110 | | # warning Insecure PRNG is enabled |
111 | | ret = gnutls_crypto_rnd_register(100, &_gnutls_fuzz_rnd_ops); |
112 | | if (ret < 0) |
113 | | 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 = |
135 | 2 | gl_list_nx_create_empty(GL_LINKEDHASH_LIST, NULL, NULL, free_ctx, |
136 | 2 | false); |
137 | 2 | if (list == NULL) |
138 | 0 | return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); |
139 | | |
140 | 2 | return 0; |
141 | 2 | } |
142 | | |
143 | | void _gnutls_rnd_deinit(void) |
144 | 0 | { |
145 | 0 | gl_list_free(list); |
146 | 0 | glthread_tls_key_destroy(&ctx_key); |
147 | 0 | rnd_initialized = 0; |
148 | 0 | _rnd_system_entropy_deinit(); |
149 | 0 | } |
150 | | |
151 | | /** |
152 | | * gnutls_rnd: |
153 | | * @level: a security level |
154 | | * @data: place to store random bytes |
155 | | * @len: The requested size |
156 | | * |
157 | | * This function will generate random data and store it to output |
158 | | * buffer. The value of @level should be one of %GNUTLS_RND_NONCE, |
159 | | * %GNUTLS_RND_RANDOM and %GNUTLS_RND_KEY. See the manual and |
160 | | * %gnutls_rnd_level_t for detailed information. |
161 | | * |
162 | | * This function is thread-safe and also fork-safe. |
163 | | * |
164 | | * Returns: Zero on success, or a negative error code on error. |
165 | | * |
166 | | * Since: 2.12.0 |
167 | | **/ |
168 | | int gnutls_rnd(gnutls_rnd_level_t level, void *data, size_t len) |
169 | 0 | { |
170 | 0 | int ret; |
171 | 0 | FAIL_IF_LIB_ERROR; |
172 | | |
173 | 0 | ret = _gnutls_rnd_init(); |
174 | 0 | if (unlikely(ret < 0)) |
175 | 0 | return gnutls_assert_val(ret); |
176 | | |
177 | 0 | if (likely(len > 0)) |
178 | 0 | return _gnutls_rnd_ops.rnd(gl_tls_get(ctx_key), level, data, |
179 | 0 | len); |
180 | | |
181 | 0 | return 0; |
182 | 0 | } |
183 | | |
184 | | /** |
185 | | * gnutls_rnd_refresh: |
186 | | * |
187 | | * This function refreshes the random generator state. |
188 | | * That is the current precise time, CPU usage, and |
189 | | * other values are input into its state. |
190 | | * |
191 | | * On a slower rate input from /dev/urandom is mixed too. |
192 | | * |
193 | | * Since: 3.1.7 |
194 | | **/ |
195 | | void gnutls_rnd_refresh(void) |
196 | 0 | { |
197 | 0 | if (rnd_initialized && _gnutls_rnd_ops.rnd_refresh) |
198 | 0 | _gnutls_rnd_ops.rnd_refresh(gl_tls_get(ctx_key)); |
199 | 0 | } |