[openssh-commits] [openssh] 03/03: Resync arc4random with OpenBSD.

git+noreply at mindrot.org git+noreply at mindrot.org
Fri Sep 2 14:31:25 AEST 2022


This is an automated email from the git hooks/post-receive script.

dtucker pushed a commit to branch master
in repository openssh.

commit ce39e7d8b70c4726defde5d3bc4cb7d40d131153
Author: Darren Tucker <dtucker at dtucker.net>
Date:   Fri Sep 2 14:28:14 2022 +1000

    Resync arc4random with OpenBSD.
    
    This brings us up to current, including djm's random-reseeding change,
    as prompted by logan at cyberstorm.mu in bz#3467.  It brings the
    platform-specific hooks from LibreSSL Portable, simplified to match our
    use case.  ok djm at .
---
 openbsd-compat/arc4random.c     | 191 +++++++++++++++++++---------------------
 openbsd-compat/arc4random.h     |  79 +++++++++++++++++
 openbsd-compat/openbsd-compat.h |  13 ++-
 3 files changed, 175 insertions(+), 108 deletions(-)

diff --git a/openbsd-compat/arc4random.c b/openbsd-compat/arc4random.c
index 2751fb83..ae48cce9 100644
--- a/openbsd-compat/arc4random.c
+++ b/openbsd-compat/arc4random.c
@@ -1,11 +1,10 @@
-/* OPENBSD ORIGINAL: lib/libc/crypto/arc4random.c */
-
-/*	$OpenBSD: arc4random.c,v 1.25 2013/10/01 18:34:57 markus Exp $	*/
+/*	$OpenBSD: arc4random.c,v 1.58 2022/07/31 13:41:45 tb Exp $	*/
 
 /*
  * Copyright (c) 1996, David Mazieres <dm at uun.org>
  * Copyright (c) 2008, Damien Miller <djm at openbsd.org>
  * Copyright (c) 2013, Markus Friedl <markus at openbsd.org>
+ * Copyright (c) 2014, Theo de Raadt <deraadt at openbsd.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -24,14 +23,23 @@
  * ChaCha based random number generator for OpenBSD.
  */
 
+/* OPENBSD ORIGINAL: lib/libc/crypt/arc4random.c */
+
 #include "includes.h"
 
 #include <sys/types.h>
 
 #include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
 
 #ifndef HAVE_ARC4RANDOM
 
@@ -44,33 +52,43 @@
 # define getentropy(x, y) (_ssh_compat_getentropy((x), (y)))
 #endif
 
-#define MINIMUM(a, b)    (((a) < (b)) ? (a) : (b))
+#define DEF_WEAK(x)
 
 #include "log.h"
 
 #define KEYSTREAM_ONLY
 #include "chacha_private.h"
 
-#ifdef __GNUC__
+#define minimum(a, b) ((a) < (b) ? (a) : (b))
+
+#if defined(__GNUC__) || defined(_MSC_VER)
 #define inline __inline
-#else				/* !__GNUC__ */
+#else				/* __GNUC__ || _MSC_VER */
 #define inline
-#endif				/* !__GNUC__ */
-
-/* OpenSSH isn't multithreaded */
-#define _ARC4_LOCK()
-#define _ARC4_UNLOCK()
+#endif				/* !__GNUC__ && !_MSC_VER */
 
 #define KEYSZ	32
 #define IVSZ	8
 #define BLOCKSZ	64
 #define RSBUFSZ	(16*BLOCKSZ)
-static int rs_initialized;
-static pid_t rs_stir_pid;
-static chacha_ctx rs;		/* chacha context for random keystream */
-static u_char rs_buf[RSBUFSZ];	/* keystream blocks */
-static size_t rs_have;		/* valid bytes at end of rs_buf */
-static size_t rs_count;		/* bytes till reseed */
+
+#define REKEY_BASE	(1024*1024) /* NB. should be a power of 2 */
+
+/* Marked MAP_INHERIT_ZERO, so zero'd out in fork children. */
+static struct _rs {
+	size_t		rs_have;	/* valid bytes at end of rs_buf */
+	size_t		rs_count;	/* bytes till reseed */
+} *rs;
+
+/* Maybe be preserved in fork children, if _rs_allocate() decides. */
+static struct _rsx {
+	chacha_ctx	rs_chacha;	/* chacha context for random keystream */
+	u_char		rs_buf[RSBUFSZ];	/* keystream blocks */
+} *rsx;
+
+static inline int _rs_allocate(struct _rs **, struct _rsx **);
+static inline void _rs_forkdetect(void);
+#include "arc4random.h"
 
 static inline void _rs_rekey(u_char *dat, size_t datlen);
 
@@ -79,137 +97,128 @@ _rs_init(u_char *buf, size_t n)
 {
 	if (n < KEYSZ + IVSZ)
 		return;
-	chacha_keysetup(&rs, buf, KEYSZ * 8);
-	chacha_ivsetup(&rs, buf + KEYSZ);
+
+	if (rs == NULL) {
+		if (_rs_allocate(&rs, &rsx) == -1)
+			_exit(1);
+	}
+
+	chacha_keysetup(&rsx->rs_chacha, buf, KEYSZ * 8);
+	chacha_ivsetup(&rsx->rs_chacha, buf + KEYSZ);
 }
 
 static void
 _rs_stir(void)
 {
 	u_char rnd[KEYSZ + IVSZ];
+	uint32_t rekey_fuzz = 0;
 
 	if (getentropy(rnd, sizeof rnd) == -1)
-		fatal("getentropy failed");
+		_getentropy_fail();
 
-	if (!rs_initialized) {
-		rs_initialized = 1;
+	if (!rs)
 		_rs_init(rnd, sizeof(rnd));
-	} else
+	else
 		_rs_rekey(rnd, sizeof(rnd));
-	explicit_bzero(rnd, sizeof(rnd));
+	explicit_bzero(rnd, sizeof(rnd));	/* discard source seed */
 
 	/* invalidate rs_buf */
-	rs_have = 0;
-	memset(rs_buf, 0, RSBUFSZ);
+	rs->rs_have = 0;
+	memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf));
 
-	rs_count = 1600000;
+	/* rekey interval should not be predictable */
+	chacha_encrypt_bytes(&rsx->rs_chacha, (uint8_t *)&rekey_fuzz,
+	    (uint8_t *)&rekey_fuzz, sizeof(rekey_fuzz));
+	rs->rs_count = REKEY_BASE + (rekey_fuzz % REKEY_BASE);
 }
 
 static inline void
 _rs_stir_if_needed(size_t len)
 {
-	pid_t pid = getpid();
-
-	if (rs_count <= len || !rs_initialized || rs_stir_pid != pid) {
-		rs_stir_pid = pid;
+	_rs_forkdetect();
+	if (!rs || rs->rs_count <= len)
 		_rs_stir();
-	} else
-		rs_count -= len;
+	if (rs->rs_count <= len)
+		rs->rs_count = 0;
+	else
+		rs->rs_count -= len;
 }
 
 static inline void
 _rs_rekey(u_char *dat, size_t datlen)
 {
 #ifndef KEYSTREAM_ONLY
-	memset(rs_buf, 0,RSBUFSZ);
+	memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf));
 #endif
 	/* fill rs_buf with the keystream */
-	chacha_encrypt_bytes(&rs, rs_buf, rs_buf, RSBUFSZ);
+	chacha_encrypt_bytes(&rsx->rs_chacha, rsx->rs_buf,
+	    rsx->rs_buf, sizeof(rsx->rs_buf));
 	/* mix in optional user provided data */
 	if (dat) {
 		size_t i, m;
 
-		m = MINIMUM(datlen, KEYSZ + IVSZ);
+		m = minimum(datlen, KEYSZ + IVSZ);
 		for (i = 0; i < m; i++)
-			rs_buf[i] ^= dat[i];
+			rsx->rs_buf[i] ^= dat[i];
 	}
 	/* immediately reinit for backtracking resistance */
-	_rs_init(rs_buf, KEYSZ + IVSZ);
-	memset(rs_buf, 0, KEYSZ + IVSZ);
-	rs_have = RSBUFSZ - KEYSZ - IVSZ;
+	_rs_init(rsx->rs_buf, KEYSZ + IVSZ);
+	memset(rsx->rs_buf, 0, KEYSZ + IVSZ);
+	rs->rs_have = sizeof(rsx->rs_buf) - KEYSZ - IVSZ;
 }
 
 static inline void
 _rs_random_buf(void *_buf, size_t n)
 {
 	u_char *buf = (u_char *)_buf;
+	u_char *keystream;
 	size_t m;
 
 	_rs_stir_if_needed(n);
 	while (n > 0) {
-		if (rs_have > 0) {
-			m = MINIMUM(n, rs_have);
-			memcpy(buf, rs_buf + RSBUFSZ - rs_have, m);
-			memset(rs_buf + RSBUFSZ - rs_have, 0, m);
+		if (rs->rs_have > 0) {
+			m = minimum(n, rs->rs_have);
+			keystream = rsx->rs_buf + sizeof(rsx->rs_buf)
+			    - rs->rs_have;
+			memcpy(buf, keystream, m);
+			memset(keystream, 0, m);
 			buf += m;
 			n -= m;
-			rs_have -= m;
+			rs->rs_have -= m;
 		}
-		if (rs_have == 0)
+		if (rs->rs_have == 0)
 			_rs_rekey(NULL, 0);
 	}
 }
 
 static inline void
-_rs_random_u32(u_int32_t *val)
+_rs_random_u32(uint32_t *val)
 {
+	u_char *keystream;
+
 	_rs_stir_if_needed(sizeof(*val));
-	if (rs_have < sizeof(*val))
+	if (rs->rs_have < sizeof(*val))
 		_rs_rekey(NULL, 0);
-	memcpy(val, rs_buf + RSBUFSZ - rs_have, sizeof(*val));
-	memset(rs_buf + RSBUFSZ - rs_have, 0, sizeof(*val));
-	rs_have -= sizeof(*val);
-	return;
+	keystream = rsx->rs_buf + sizeof(rsx->rs_buf) - rs->rs_have;
+	memcpy(val, keystream, sizeof(*val));
+	memset(keystream, 0, sizeof(*val));
+	rs->rs_have -= sizeof(*val);
 }
 
-void
-arc4random_stir(void)
-{
-	_ARC4_LOCK();
-	_rs_stir();
-	_ARC4_UNLOCK();
-}
-
-void
-arc4random_addrandom(u_char *dat, int datlen)
-{
-	int m;
-
-	_ARC4_LOCK();
-	if (!rs_initialized)
-		_rs_stir();
-	while (datlen > 0) {
-		m = MINIMUM(datlen, KEYSZ + IVSZ);
-		_rs_rekey(dat, m);
-		dat += m;
-		datlen -= m;
-	}
-	_ARC4_UNLOCK();
-}
-
-u_int32_t
+uint32_t
 arc4random(void)
 {
-	u_int32_t val;
+	uint32_t val;
 
 	_ARC4_LOCK();
 	_rs_random_u32(&val);
 	_ARC4_UNLOCK();
 	return val;
 }
+DEF_WEAK(arc4random);
 
 /*
- * If we are providing arc4random, then we can provide a more efficient 
+ * If we are providing arc4random, then we can provide a more efficient
  * arc4random_buf().
  */
 # ifndef HAVE_ARC4RANDOM_BUF
@@ -220,6 +229,7 @@ arc4random_buf(void *buf, size_t n)
 	_rs_random_buf(buf, n);
 	_ARC4_UNLOCK();
 }
+DEF_WEAK(arc4random_buf);
 # endif /* !HAVE_ARC4RANDOM_BUF */
 #endif /* !HAVE_ARC4RANDOM */
 
@@ -242,24 +252,3 @@ arc4random_buf(void *_buf, size_t n)
 }
 #endif /* !defined(HAVE_ARC4RANDOM_BUF) && defined(HAVE_ARC4RANDOM) */
 
-#if 0
-/*-------- Test code for i386 --------*/
-#include <stdio.h>
-#include <machine/pctr.h>
-int
-main(int argc, char **argv)
-{
-	const int iter = 1000000;
-	int     i;
-	pctrval v;
-
-	v = rdtsc();
-	for (i = 0; i < iter; i++)
-		arc4random();
-	v = rdtsc() - v;
-	v /= iter;
-
-	printf("%qd cycles\n", v);
-	exit(0);
-}
-#endif
diff --git a/openbsd-compat/arc4random.h b/openbsd-compat/arc4random.h
new file mode 100644
index 00000000..2b57611f
--- /dev/null
+++ b/openbsd-compat/arc4random.h
@@ -0,0 +1,79 @@
+/*	$OpenBSD: arc4random_linux.h,v 1.12 2019/07/11 10:37:28 inoguchi Exp $	*/
+
+/*
+ * Copyright (c) 1996, David Mazieres <dm at uun.org>
+ * Copyright (c) 2008, Damien Miller <djm at openbsd.org>
+ * Copyright (c) 2013, Markus Friedl <markus at openbsd.org>
+ * Copyright (c) 2014, Theo de Raadt <deraadt at openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Stub functions for portability.  From LibreSSL with some adaptations.
+ */
+
+#include <sys/mman.h>
+
+#include <signal.h>
+
+/* OpenSSH isn't multithreaded */
+#define _ARC4_LOCK()
+#define _ARC4_UNLOCK()
+#define _ARC4_ATFORK(f)
+
+static inline void
+_getentropy_fail(void)
+{
+	fatal("getentropy failed");
+}
+
+static volatile sig_atomic_t _rs_forked;
+
+static inline void
+_rs_forkhandler(void)
+{
+	_rs_forked = 1;
+}
+
+static inline void
+_rs_forkdetect(void)
+{
+	static pid_t _rs_pid = 0;
+	pid_t pid = getpid();
+
+	if (_rs_pid == 0 || _rs_pid == 1 || _rs_pid != pid || _rs_forked) {
+		_rs_pid = pid;
+		_rs_forked = 0;
+		if (rs)
+			memset(rs, 0, sizeof(*rs));
+	}
+}
+
+static inline int
+_rs_allocate(struct _rs **rsp, struct _rsx **rsxp)
+{
+	if ((*rsp = mmap(NULL, sizeof(**rsp), PROT_READ|PROT_WRITE,
+	    MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED)
+		return (-1);
+
+	if ((*rsxp = mmap(NULL, sizeof(**rsxp), PROT_READ|PROT_WRITE,
+	    MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED) {
+		munmap(*rsp, sizeof(**rsp));
+		*rsp = NULL;
+		return (-1);
+	}
+
+	_ARC4_ATFORK(_rs_forkhandler);
+	return (0);
+}
diff --git a/openbsd-compat/openbsd-compat.h b/openbsd-compat/openbsd-compat.h
index bbf89825..4af207cd 100644
--- a/openbsd-compat/openbsd-compat.h
+++ b/openbsd-compat/openbsd-compat.h
@@ -218,19 +218,18 @@ int writev(int, struct iovec *, int);
 int getpeereid(int , uid_t *, gid_t *);
 #endif
 
-#ifdef HAVE_ARC4RANDOM
-# ifndef HAVE_ARC4RANDOM_STIR
-#  define arc4random_stir()
-# endif
-#else
-unsigned int arc4random(void);
-void arc4random_stir(void);
+#ifndef HAVE_ARC4RANDOM
+uint32_t arc4random(void);
 #endif /* !HAVE_ARC4RANDOM */
 
 #ifndef HAVE_ARC4RANDOM_BUF
 void arc4random_buf(void *, size_t);
 #endif
 
+#ifndef HAVE_ARC4RANDOM_STIR
+# define arc4random_stir()
+#endif
+
 #ifndef HAVE_ARC4RANDOM_UNIFORM
 uint32_t arc4random_uniform(uint32_t);
 #endif

-- 
To stop receiving notification emails like this one, please contact
djm at mindrot.org.


More information about the openssh-commits mailing list