Bugzilla – Attachment 3609 Details for
Bug 3467
[upstream] arc4random: make rekey interval less predictable
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Resync arc4random with OpenBSD rev 1.58
openssh-arc4random-resync.patch (text/plain), 10.57 KB, created by
Darren Tucker
on 2022-08-05 14:54:16 AEST
(
hide
)
Description:
Resync arc4random with OpenBSD rev 1.58
Filename:
MIME Type:
Creator:
Darren Tucker
Created:
2022-08-05 14:54:16 AEST
Size:
10.57 KB
patch
obsolete
>diff --git a/openbsd-compat/arc4random.c b/openbsd-compat/arc4random.c >index c218a441..b0b68018 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@uun.org> > * Copyright (c) 2008, Damien Miller <djm@openbsd.org> > * Copyright (c) 2013, Markus Friedl <markus@openbsd.org> >+ * Copyright (c) 2014, Theo de Raadt <deraadt@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,44 +23,60 @@ > * ChaCha based random number generator for OpenBSD. > */ > >-#include "includes.h" >+/* OPENBSD ORIGINAL: lib/libc/crypt/arc4random.c */ > >-#include <sys/types.h> >+#include "includes.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 > >-#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) >- > #include "log.h" >+#define DEF_WEAK(x) > > #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); > >@@ -70,134 +85,125 @@ _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 >@@ -211,6 +217,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 */ > >@@ -233,24 +240,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@uun.org> >+ * Copyright (c) 2008, Damien Miller <djm@openbsd.org> >+ * Copyright (c) 2013, Markus Friedl <markus@openbsd.org> >+ * Copyright (c) 2014, Theo de Raadt <deraadt@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 1835a9a5..0fc3400f 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
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Flags:
djm
:
ok+
Actions:
View
|
Diff
Attachments on
bug 3467
:
3605
|
3606
|
3607
|
3608
| 3609