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