From 53073dfb7fc2dd06c572e303fcae164cabdd4ba2 Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Thu, 26 May 2016 09:26:09 +0100 Subject: [PATCH] rand/: Secure `rand' generator against fork problems. This is fiddlier than it really ought to be. * Make the `i' and `irot' members be `unsigned short' to make space for a new member. These members have well-constrained ranges, so this is safe. * Insert a new `gen' member to keep track of the pool's `generation number'. Arrange that the global generator's generation number is initially zero. * Invent a new system-specific function `rand_generation' which returns a nonzero `generation number', which changes across forks and such things. * Have the output functions `rand_get' and `rand_getgood' check the generation number and force a `rand_gate' if it changes. * Arrange for `rand_gate' and `rand_stretch' to feed the generation number into the hashing, so that generators with different generations behave computationally independently. --- rand/Makefile.am | 1 + rand/rand.c | 16 +++++++++++++--- rand/rand.h | 19 +++++++++++++++++-- rand/randgen.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 81 insertions(+), 5 deletions(-) create mode 100644 rand/randgen.c diff --git a/rand/Makefile.am b/rand/Makefile.am index a60125be..d97749e9 100644 --- a/rand/Makefile.am +++ b/rand/Makefile.am @@ -67,6 +67,7 @@ librand_la_SOURCES += noise.c ## Cryptographic laundering for true random data generation. pkginclude_HEADERS += rand.h librand_la_SOURCES += rand.c +librand_la_SOURCES += randgen.c ## The SSL v3 pseudorandom function. pkginclude_HEADERS += sslprf.h diff --git a/rand/rand.c b/rand/rand.c index 6fcdf439..8de66079 100644 --- a/rand/rand.c +++ b/rand/rand.c @@ -68,7 +68,7 @@ typedef struct rand__gctx { gctx rand_global = { { &gops }, - { { 0 }, 0, 0, 0, + { { 0 }, 0, 0, 0, 0, { 0 }, RAND_SECSZ, 0, { "Catacomb global random byte pool" }, &noise_source } @@ -79,6 +79,11 @@ gctx rand_global = { #define RAND_RESOLVE(r) \ do { if ((r) == RAND_GLOBAL) r = &rand_global.p; } while (0) +#define GENCHECK(r) do { \ + unsigned gen = rand_generation(); \ + if (r->gen != gen) { r->gen = gen; rand_gate(r); } \ +} while (0) + #define TIMER(r) do { \ if ((r)->s && (r)->s->timer) \ (r)->s->timer(r); \ @@ -103,6 +108,7 @@ void rand_init(rand_pool *r) RAND_RESOLVE(r); memset(r->pool, 0, sizeof(r->pool)); memset(r->buf, 0, sizeof(r->buf)); + r->gen = rand_generation(); r->i = 0; r->irot = 0; r->ibits = r->obits = 0; @@ -261,7 +267,7 @@ unsigned rand_goodbits(rand_pool *r) void rand_gate(rand_pool *r) { - octet h[HASH_SZ]; + octet h[HASH_SZ], g[4]; HASH_CTX hc; CIPHER_CTX cc; @@ -271,6 +277,7 @@ void rand_gate(rand_pool *r) /* --- Hash up all the data in the pool --- */ HASH_INIT(&hc); + STORE32(g, r->gen); HASH(&hc, g, sizeof(g)); HASH(&hc, r->pool, RAND_POOLSZ); HASH(&hc, r->buf, RAND_BUFSZ); HASH_DONE(&hc, h); @@ -310,7 +317,7 @@ void rand_gate(rand_pool *r) void rand_stretch(rand_pool *r) { - octet h[HASH_SZ]; + octet h[HASH_SZ], g[4]; HASH_CTX hc; CIPHER_CTX cc; @@ -320,6 +327,7 @@ void rand_stretch(rand_pool *r) /* --- Hash up all the data in the buffer --- */ HASH_INIT(&hc); + STORE32(g, r->gen); HASH(&hc, g, sizeof(g)); HASH(&hc, r->pool, RAND_POOLSZ); HASH(&hc, r->buf, RAND_BUFSZ); HASH_DONE(&hc, h); @@ -359,6 +367,7 @@ void rand_get(rand_pool *r, void *p, size_t sz) octet *o = p; RAND_RESOLVE(r); + GENCHECK(r); TIMER(r); if (!sz) @@ -412,6 +421,7 @@ void rand_getgood(rand_pool *r, void *p, size_t sz) rand_get(r, p, sz); return; } + GENCHECK(r); TIMER(r); while (sz) { diff --git a/rand/rand.h b/rand/rand.h index 3c2fa738..ab1c4a8b 100644 --- a/rand/rand.h +++ b/rand/rand.h @@ -99,8 +99,9 @@ typedef struct rand_pool { octet pool[RAND_POOLSZ]; /* Actual contents of the pool */ - unsigned i; /* Current index into pool */ - unsigned irot; /* Current rotation applied */ + unsigned gen; /* Generation number */ + unsigned short i; /* Current index into pool */ + unsigned short irot; /* Current rotation applied */ unsigned ibits; /* Number of good bits in pool */ octet buf[RAND_BUFSZ]; /* Random octet output buffer */ unsigned o; /* Current index into buffer */ @@ -132,6 +133,20 @@ typedef struct rand_source { extern void rand_init(rand_pool */*r*/); +/* --- @rand_generation@ --- * + * + * Arguments: --- + * + * Returns: A nonzero generation number. + * + * Use: Returns a generation number for the current process. Each + * pool has its own number. If this matches the process number + * then all is well. If it doesn't match, then the pool needs + * to be cleaned before its next use. + */ + +extern unsigned rand_generation(void); + /* --- @rand_noisesrc@ --- * * * Arguments: @rand_pool *r@ = pointer to a randomness pool diff --git a/rand/randgen.c b/rand/randgen.c new file mode 100644 index 00000000..7cd2f354 --- /dev/null +++ b/rand/randgen.c @@ -0,0 +1,50 @@ +/* -*-c-*- + * + * Pool-generation boundary machinery (Unix-specific) + * + * (c) 2016 Straylight/Edgeware + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of Catacomb. + * + * Catacomb is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * Catacomb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with Catacomb; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +/*----- Header files ------------------------------------------------------*/ + +#include + +#include "rand.h" + +/*----- Main code ---------------------------------------------------------*/ + +/* --- @rand_generation@ --- * + * + * Arguments: --- + * + * Returns: A nonzero generation number. + * + * Use: Returns a generation number for the current process. Each + * pool has its own number. If this matches the process number + * then all is well. If it doesn't match, then the pool needs + * to be cleaned before its next use. + */ + +unsigned rand_generation(void) { return (getpid()); } + +/*----- That's all, folks -------------------------------------------------*/ -- 2.11.0