Skip to content

Commit 89d72c1

Browse files
committed
seeded_rng: Add some sanity code
- as we always obtain a time stamp for each generate request, mix it into the DRBG as additional info - zeroization call now simply reseeds the DRBG for obliterating any state, but leave the RNG ready for action - uninstantiation now is graceful such that any reuse of seeded_rng after uninstantiation triggers a full reinit of the seeded_rng instead of a segfault - such calling after uninstantiate, is a bug of the caller, but since RNGs are the pillar of crypto, they should work even in errorneous calling sequences. Signed-off-by: Stephan Mueller <smueller@chronox.de>
1 parent 66e170b commit 89d72c1

File tree

2 files changed

+90
-18
lines changed

2 files changed

+90
-18
lines changed

CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ Changes 1.7.0-prerelease
5151

5252
* ChaCha20 DRNG wrapped in common wrapper
5353

54+
* Seeded RNG: always insert the current time stamp as additional data during a generate operation - this is cheap as the time stamp is always gathered and the insertion of additional 8 bytes into the DRBG state requires minimal operations
55+
5456
Changes 1.6.0
5557
* ASN.1: use stack for small generator for small use cases
5658

drng/src/seeded_rng.c

Lines changed: 88 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,8 @@ static time64_t get_time(void)
201201

202202
#endif /* LINUX_KERNEL */
203203

204-
static int lc_seed_seeded_rng(struct lc_seeded_rng_ctx *rng, int init,
204+
static int lc_seed_seeded_rng(struct lc_seeded_rng_ctx *rng,
205+
const uint8_t *pers, size_t pers_len, int init,
205206
pid_t newpid)
206207
{
207208
/* We provide twice the buffer size for the kernel seed sources */
@@ -229,8 +230,8 @@ static int lc_seed_seeded_rng(struct lc_seeded_rng_ctx *rng, int init,
229230
(size_t)datasize > sizeof(seed))
230231
return -EFAULT;
231232

232-
CKINT(lc_rng_seed(rng->rng_ctx, seed, (size_t)datasize, NULL,
233-
0));
233+
CKINT(lc_rng_seed(rng->rng_ctx, seed, (size_t)datasize, pers,
234+
pers_len));
234235
}
235236

236237
rng->bytes = 0;
@@ -260,23 +261,41 @@ void lc_seeded_rng_zero_state(void)
260261
rng = seeded_rng.rng_ctx;
261262
if (!rng)
262263
return;
263-
seeded_rng.rng_ctx = NULL;
264+
265+
mutex_w_lock(&seeded_rng.lock);
264266

265267
if (seeded_rng.last_seeded)
266268
lc_rng_zero(rng);
267269

270+
/*
271+
* Set the state such that in case the seeded_rng is used after this
272+
* function, it is automatically newly instantiated. Surely any use
273+
* after this call of the seeded_rng is a programming bug, but
274+
* leancrypto tries to be as gracefully as possible especially in the
275+
* realm of random numbers - the pillar of all cryptography.
276+
*
277+
* seeded.rng does not need to be reinitialized as lc_rng_zero only
278+
* clears the state, but leaves the RNG handle fully in tact.
279+
*/
280+
seeded_rng.pid = 0;
281+
seeded_rng.last_seeded = 0;
282+
seeded_rng.bytes = LC_SEEDED_RNG_MAX_BYTES + 1,
283+
284+
mutex_w_unlock(&seeded_rng.lock);
285+
268286
seeded_rng_noise_fini();
269287
}
270288

271-
static time64_t time_after_now(time64_t base)
289+
static time64_t time_after_now(time64_t base, time64_t *curr_time)
272290
{
273291
time64_t curr = get_time();
274292

293+
*curr_time = curr;
275294
return time64_after(curr, base) ? (curr - base) : 0;
276295
}
277296

278297
static int lc_seeded_rng_must_reseed(struct lc_seeded_rng_ctx *rng,
279-
pid_t *newpid)
298+
pid_t *newpid, time64_t *curr_time)
280299
{
281300
pid_t pid;
282301

@@ -287,7 +306,8 @@ static int lc_seeded_rng_must_reseed(struct lc_seeded_rng_ctx *rng,
287306
return 1;
288307

289308
/* ... or our seeding was too long ago ... */
290-
if (time_after_now(rng->last_seeded + LC_SEEDED_RNG_MAX_TIME))
309+
if (time_after_now(rng->last_seeded + LC_SEEDED_RNG_MAX_TIME,
310+
curr_time))
291311
return 1;
292312

293313
/*
@@ -303,7 +323,8 @@ static int lc_seeded_rng_must_reseed(struct lc_seeded_rng_ctx *rng,
303323
return 0;
304324
}
305325

306-
static int lc_get_seeded_rng(struct lc_seeded_rng_ctx **rng_ret)
326+
static int lc_get_seeded_rng(struct lc_seeded_rng_ctx **rng_ret,
327+
time64_t *curr_time)
307328
{
308329
pid_t newpid = 0;
309330
int ret = 0, init = 0;
@@ -317,9 +338,11 @@ static int lc_get_seeded_rng(struct lc_seeded_rng_ctx **rng_ret)
317338
init = 1;
318339
}
319340

320-
/* Force reseed if needed */
321-
if (lc_seeded_rng_must_reseed(&seeded_rng, &newpid))
322-
CKINT(lc_seed_seeded_rng(&seeded_rng, init, newpid));
341+
/* Force reseed if needed using the time stamp as additional data. */
342+
if (lc_seeded_rng_must_reseed(&seeded_rng, &newpid, curr_time)) {
343+
CKINT(lc_seed_seeded_rng(&seeded_rng, (uint8_t *)&curr_time,
344+
sizeof(curr_time), init, newpid));
345+
}
323346

324347
*rng_ret = &seeded_rng;
325348

@@ -335,19 +358,39 @@ static int lc_seeded_rng_generate(void *_state, const uint8_t *addtl_input,
335358
{
336359
struct lc_seeded_rng_ctx *rng = NULL;
337360
size_t updated_len;
361+
time64_t curr_time;
338362
int ret;
339363

340364
if (_state)
341365
return -EINVAL;
342366

343367
/* Get the DRNG state that is fully seeded */
344-
CKINT(lc_get_seeded_rng(&rng));
368+
CKINT(lc_get_seeded_rng(&rng, &curr_time));
345369

346370
mutex_w_lock(&rng->lock);
347371

348-
/* Generate random numbers */
349-
CKINT(lc_rng_generate(rng->rng_ctx, addtl_input, addtl_input_len, out,
350-
outlen));
372+
/*
373+
* Generate random numbers
374+
*
375+
* Always insert the gathered time as additional input into the DRBG.
376+
* This is intended to ensure different DRBG states in case there
377+
* was any address space duplication that the getpid() operation did
378+
* not detect (which we hope does not occur).
379+
*/
380+
if (addtl_input) {
381+
/*
382+
* Insert the current time as a reseed operation - this
383+
* operation is not considered to add entropy, but shall just
384+
* mix the state.
385+
*/
386+
CKINT(lc_rng_seed(rng->rng_ctx, (uint8_t *)&curr_time,
387+
sizeof(curr_time), NULL, 0));
388+
CKINT(lc_rng_generate(rng->rng_ctx, addtl_input,
389+
addtl_input_len, out, outlen));
390+
} else {
391+
CKINT(lc_rng_generate(rng->rng_ctx, (uint8_t *)&curr_time,
392+
sizeof(curr_time), out, outlen));
393+
}
351394

352395
/* Check wrap around and avoid a wrap for the rng->bytes state */
353396
updated_len = rng->bytes + outlen;
@@ -366,15 +409,26 @@ static int lc_seeded_rng_seed(void *_state, const uint8_t *seed, size_t seedlen,
366409
const uint8_t *persbuf, size_t perslen)
367410
{
368411
struct lc_seeded_rng_ctx *rng = NULL;
412+
time64_t curr_time;
369413
int ret;
370414

371415
if (_state)
372416
return -EINVAL;
373417

374-
CKINT(lc_get_seeded_rng(&rng));
418+
CKINT(lc_get_seeded_rng(&rng, &curr_time));
375419

376420
mutex_w_lock(&rng->lock);
377-
CKINT(lc_seed_seeded_rng(rng, 0, 0));
421+
422+
/*
423+
* Use the time stamp as additional data to seed the DRBG with the
424+
* internal entropy sources to ensure proper seeding with all required
425+
* entropy. The use of internal entropy sources is unconditional to
426+
* not rely on the caller-provided data.
427+
*/
428+
CKINT(lc_seed_seeded_rng(rng, (uint8_t *)&curr_time, sizeof(curr_time),
429+
0, 0));
430+
431+
/* Now insert the caller-provided data. */
378432
CKINT(lc_rng_seed(rng->rng_ctx, seed, seedlen, persbuf, perslen));
379433

380434
out:
@@ -385,9 +439,25 @@ static int lc_seeded_rng_seed(void *_state, const uint8_t *seed, size_t seedlen,
385439

386440
static void lc_seeded_rng_zero(void *_state)
387441
{
442+
struct lc_seeded_rng_ctx *rng = NULL;
443+
time64_t curr_time;
444+
388445
(void)_state;
389446

390-
/* Do nothing */
447+
/*
448+
* Instead of zeroizing the state, we simply reseed the state to
449+
* obliterate any potential information an adversay may have about
450+
* the current state. This implies that the seeded_rng is always ready
451+
* for action in case there is a programming error in the caller and
452+
* he calls zeroize by immediately following a generate operation.
453+
*/
454+
455+
if (lc_get_seeded_rng(&rng, &curr_time))
456+
return;
457+
458+
mutex_w_lock(&rng->lock);
459+
lc_seed_seeded_rng(rng, (uint8_t *)&curr_time, sizeof(curr_time), 0, 0);
460+
mutex_w_unlock(&rng->lock);
391461
}
392462

393463
static const struct lc_rng _lc_seeded_rng = {

0 commit comments

Comments
 (0)