1 /*
2 * Copyright (C) 2010-2012 Free Software Foundation, Inc.
3 * Copyright (C) 2016-2017 Red Hat, Inc.
4 *
5 * Author: Nikos Mavrogiannopoulos
6 *
7 * This file is part of GNUTLS.
8 *
9 * The GNUTLS library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1 of
12 * the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>
21 *
22 */
23
24 #include "gnutls_int.h"
25 #include "errors.h"
26 #include <locks.h>
27 #include <num.h>
28 #include <nettle/chacha.h>
29 #include <rnd-common.h>
30 #include <system.h>
31 #include <atfork.h>
32 #include <errno.h>
33 #include <minmax.h>
34
35 #define PRNG_KEY_SIZE CHACHA_KEY_SIZE
36
37 /* For a high level description see the documentation and
38 * the 'Random number generation' section of chapter
39 * 'Using GnuTLS as a cryptographic library'.
40 */
41
42 /* We have two "refresh" operations for the PRNG:
43 * re-seed: the random generator obtains a new key from the system or another PRNG
44 * (occurs when a time or data-based limit is reached for the GNUTLS_RND_RANDOM
45 * and GNUTLS_RND_KEY levels and data-based for the nonce level)
46 * re-key: the random generator obtains a new key by utilizing its own output.
47 * This only happens for the GNUTLS_RND_KEY level, on every operation.
48 */
49
50 /* after this number of bytes PRNG will rekey using the system RNG */
51 static const unsigned prng_reseed_limits[] = {
52 [GNUTLS_RND_NONCE] = 16*1024*1024, /* 16 MB - we re-seed using the GNUTLS_RND_RANDOM output */
53 [GNUTLS_RND_RANDOM] = 2*1024*1024, /* 2MB - we re-seed by time as well */
54 [GNUTLS_RND_KEY] = 2*1024*1024 /* same as GNUTLS_RND_RANDOM - but we re-key on every operation */
55 };
56
57 static const time_t prng_reseed_time[] = {
58 [GNUTLS_RND_NONCE] = 14400, /* 4 hours */
59 [GNUTLS_RND_RANDOM] = 7200, /* 2 hours */
60 [GNUTLS_RND_KEY] = 7200 /* same as RANDOM */
61 };
62
63 struct prng_ctx_st {
64 struct chacha_ctx ctx;
65 size_t counter;
66 unsigned int forkid;
67 time_t last_reseed;
68 };
69
70 struct generators_ctx_st {
71 struct prng_ctx_st nonce; /* GNUTLS_RND_NONCE */
72 struct prng_ctx_st normal; /* GNUTLS_RND_RANDOM, GNUTLS_RND_KEY */
73 };
74
75
wrap_nettle_rnd_deinit(void * _ctx)76 static void wrap_nettle_rnd_deinit(void *_ctx)
77 {
78 gnutls_free(_ctx);
79 }
80
81 /* Initializes the nonce level random generator.
82 *
83 * the @new_key must be provided.
84 *
85 * @init must be non zero on first initialization, and
86 * zero on any subsequent reinitializations.
87 */
single_prng_init(struct prng_ctx_st * ctx,uint8_t new_key[PRNG_KEY_SIZE],unsigned new_key_size,unsigned init)88 static int single_prng_init(struct prng_ctx_st *ctx,
89 uint8_t new_key[PRNG_KEY_SIZE],
90 unsigned new_key_size,
91 unsigned init)
92 {
93 uint8_t nonce[CHACHA_NONCE_SIZE];
94
95 memset(nonce, 0, sizeof(nonce)); /* to prevent valgrind from whinning */
96
97 if (init == 0) {
98 /* use the previous key to generate IV as well */
99 chacha_crypt(&ctx->ctx, sizeof(nonce), nonce, nonce);
100
101 /* Add key continuity by XORing the new key with data generated
102 * from the old key */
103 chacha_crypt(&ctx->ctx, new_key_size, new_key, new_key);
104 } else {
105 struct timespec now; /* current time */
106
107 ctx->forkid = _gnutls_get_forkid();
108
109 gnutls_gettime(&now);
110 memcpy(nonce, &now, MIN(sizeof(nonce), sizeof(now)));
111 ctx->last_reseed = now.tv_sec;
112 }
113
114 chacha_set_key(&ctx->ctx, new_key);
115 chacha_set_nonce(&ctx->ctx, nonce);
116
117 zeroize_key(new_key, new_key_size);
118
119 ctx->counter = 0;
120
121 return 0;
122 }
123
124 /* API functions */
125
wrap_nettle_rnd_init(void ** _ctx)126 static int wrap_nettle_rnd_init(void **_ctx)
127 {
128 int ret;
129 uint8_t new_key[PRNG_KEY_SIZE*2];
130 struct generators_ctx_st *ctx;
131
132 ctx = calloc(1, sizeof(*ctx));
133 if (ctx == NULL)
134 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
135
136 /* initialize the nonce RNG */
137 ret = _rnd_get_system_entropy(new_key, sizeof(new_key));
138 if (ret < 0) {
139 gnutls_assert();
140 goto fail;
141 }
142
143 ret = single_prng_init(&ctx->nonce, new_key, PRNG_KEY_SIZE, 1);
144 if (ret < 0) {
145 gnutls_assert();
146 goto fail;
147 }
148
149 /* initialize the random/key RNG */
150 ret = single_prng_init(&ctx->normal, new_key+PRNG_KEY_SIZE, PRNG_KEY_SIZE, 1);
151 if (ret < 0) {
152 gnutls_assert();
153 goto fail;
154 }
155
156 *_ctx = ctx;
157
158 return 0;
159 fail:
160 gnutls_free(ctx);
161 return ret;
162 }
163
164 static int
wrap_nettle_rnd(void * _ctx,int level,void * data,size_t datasize)165 wrap_nettle_rnd(void *_ctx, int level, void *data, size_t datasize)
166 {
167 struct generators_ctx_st *ctx = _ctx;
168 struct prng_ctx_st *prng_ctx;
169 int ret, reseed = 0;
170 uint8_t new_key[PRNG_KEY_SIZE];
171 time_t now;
172
173 if (level == GNUTLS_RND_RANDOM || level == GNUTLS_RND_KEY)
174 prng_ctx = &ctx->normal;
175 else if (level == GNUTLS_RND_NONCE)
176 prng_ctx = &ctx->nonce;
177 else
178 return gnutls_assert_val(GNUTLS_E_RANDOM_FAILED);
179
180 /* Two reasons for this memset():
181 * 1. avoid getting filled with valgrind warnings
182 * 2. avoid a cipher/PRNG failure to expose stack data
183 */
184 memset(data, 0, datasize);
185
186 now = gnutls_time(0);
187
188 /* We re-seed based on time in addition to output data. That is,
189 * to prevent a temporal state compromise to become permanent for low
190 * traffic sites */
191 if (unlikely(_gnutls_detect_fork(prng_ctx->forkid))) {
192 reseed = 1;
193 } else {
194 if (now > prng_ctx->last_reseed + prng_reseed_time[level])
195 reseed = 1;
196 }
197
198 if (reseed != 0 || prng_ctx->counter > prng_reseed_limits[level]) {
199 if (level == GNUTLS_RND_NONCE) {
200 ret = wrap_nettle_rnd(_ctx, GNUTLS_RND_RANDOM, new_key, sizeof(new_key));
201 } else {
202
203 /* we also use the system entropy to reduce the impact
204 * of a temporal state compromise for these two levels. */
205 ret = _rnd_get_system_entropy(new_key, sizeof(new_key));
206 }
207
208 if (ret < 0) {
209 gnutls_assert();
210 goto cleanup;
211 }
212
213 ret = single_prng_init(prng_ctx, new_key, sizeof(new_key), 0);
214 if (ret < 0) {
215 gnutls_assert();
216 goto cleanup;
217 }
218
219 prng_ctx->last_reseed = now;
220 prng_ctx->forkid = _gnutls_get_forkid();
221 }
222
223 chacha_crypt(&prng_ctx->ctx, datasize, data, data);
224 prng_ctx->counter += datasize;
225
226 if (level == GNUTLS_RND_KEY) { /* prevent backtracking */
227 ret = wrap_nettle_rnd(_ctx, GNUTLS_RND_RANDOM, new_key, sizeof(new_key));
228 if (ret < 0) {
229 gnutls_assert();
230 goto cleanup;
231 }
232
233 ret = single_prng_init(prng_ctx, new_key, sizeof(new_key), 0);
234 if (ret < 0) {
235 gnutls_assert();
236 goto cleanup;
237 }
238 }
239
240 ret = 0;
241
242 cleanup:
243 return ret;
244 }
245
wrap_nettle_rnd_refresh(void * _ctx)246 static void wrap_nettle_rnd_refresh(void *_ctx)
247 {
248 struct generators_ctx_st *ctx = _ctx;
249 char tmp;
250
251 /* force reseed */
252 ctx->nonce.counter = prng_reseed_limits[GNUTLS_RND_NONCE]+1;
253 ctx->normal.counter = prng_reseed_limits[GNUTLS_RND_RANDOM]+1;
254
255 wrap_nettle_rnd(_ctx, GNUTLS_RND_NONCE, &tmp, 1);
256 wrap_nettle_rnd(_ctx, GNUTLS_RND_RANDOM, &tmp, 1);
257
258 return;
259 }
260
261 int crypto_rnd_prio = INT_MAX;
262
263 gnutls_crypto_rnd_st _gnutls_rnd_ops = {
264 .init = wrap_nettle_rnd_init,
265 .deinit = wrap_nettle_rnd_deinit,
266 .rnd = wrap_nettle_rnd,
267 .rnd_refresh = wrap_nettle_rnd_refresh,
268 .self_test = NULL,
269 };
270