mirror of
https://gitlab.alpinelinux.org/alpine/aports.git
synced 2026-01-18 07:02:29 +01:00
420 lines
10 KiB
Diff
420 lines
10 KiB
Diff
From 87c9d4de14d6d97b08db95ff4fcd7611508d3018 Mon Sep 17 00:00:00 2001
|
|
From: Jonathan Curran <jonathan@curran.in>
|
|
Date: Fri, 4 Sep 2015 12:54:21 +0000
|
|
Subject: [PATCH] Use arc4random instead of res_randomid.
|
|
|
|
arc4random implementation was copied from opensmtpd/openbsd-compat
|
|
---
|
|
configure.ac | 4 +
|
|
openbsd-compat/NOTES | 1 +
|
|
openbsd-compat/arc4random.c | 294 ++++++++++++++++++++++++++++++++
|
|
openbsd-compat/defines.h | 9 +
|
|
openbsd-compat/openbsd-compat.h | 19 ++-
|
|
src/res_mkquery.c | 2 +-
|
|
src/res_send_async.c | 2 +-
|
|
7 files changed, 328 insertions(+), 3 deletions(-)
|
|
create mode 100644 openbsd-compat/arc4random.c
|
|
|
|
diff --git a/configure.ac b/configure.ac
|
|
index 10aff04..a5e2681 100644
|
|
--- a/configure.ac
|
|
+++ b/configure.ac
|
|
@@ -442,6 +442,10 @@ fi
|
|
#l1572 (customized)
|
|
dnl Checks for library functions. Please keep in alphabetical order
|
|
AC_CHECK_FUNCS([ \
|
|
+ arc4random \
|
|
+ arc4random_buf \
|
|
+ arc4random_stir \
|
|
+ arc4random_uniform \
|
|
asprintf \
|
|
bcopy \
|
|
explicit_bzero \
|
|
diff --git a/openbsd-compat/NOTES b/openbsd-compat/NOTES
|
|
index baa60ec..869b045 100644
|
|
--- a/openbsd-compat/NOTES
|
|
+++ b/openbsd-compat/NOTES
|
|
@@ -1,5 +1,6 @@
|
|
List of files and where they come from
|
|
|
|
+arc4random.c portable openssh
|
|
clock_gettime.c handmade
|
|
defines.h portable openssh
|
|
fgetln.c part of /usr/src/usr.bin/make/util.c
|
|
diff --git a/openbsd-compat/arc4random.c b/openbsd-compat/arc4random.c
|
|
new file mode 100644
|
|
index 0000000..fa0d630
|
|
--- /dev/null
|
|
+++ b/openbsd-compat/arc4random.c
|
|
@@ -0,0 +1,294 @@
|
|
+/* OPENBSD ORIGINAL: lib/libc/crypto/arc4random.c */
|
|
+
|
|
+/* $OpenBSD: arc4random.c,v 1.25 2013/10/01 18:34:57 markus 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>
|
|
+ *
|
|
+ * 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.
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * ChaCha based random number generator for OpenBSD.
|
|
+ */
|
|
+
|
|
+#include "includes.h"
|
|
+
|
|
+#include <stdlib.h>
|
|
+#include <string.h>
|
|
+#include <unistd.h>
|
|
+#include <sys/types.h>
|
|
+
|
|
+#ifndef HAVE_ARC4RANDOM
|
|
+
|
|
+#include <openssl/rand.h>
|
|
+#include <openssl/err.h>
|
|
+
|
|
+#include "log.h"
|
|
+
|
|
+#define KEYSTREAM_ONLY
|
|
+#include "chacha_private.h"
|
|
+
|
|
+#ifdef __GNUC__
|
|
+#define inline __inline
|
|
+#else /* !__GNUC__ */
|
|
+#define inline
|
|
+#endif /* !__GNUC__ */
|
|
+
|
|
+/* OpenSSH isn't multithreaded */
|
|
+#define _ARC4_LOCK()
|
|
+#define _ARC4_UNLOCK()
|
|
+
|
|
+#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 */
|
|
+
|
|
+static inline void _rs_rekey(u_char *dat, size_t datlen);
|
|
+
|
|
+static inline void
|
|
+_rs_init(u_char *buf, size_t n)
|
|
+{
|
|
+ if (n < KEYSZ + IVSZ)
|
|
+ return;
|
|
+ chacha_keysetup(&rs, buf, KEYSZ * 8, 0);
|
|
+ chacha_ivsetup(&rs, buf + KEYSZ);
|
|
+}
|
|
+
|
|
+static void
|
|
+_rs_stir(void)
|
|
+{
|
|
+ u_char rnd[KEYSZ + IVSZ];
|
|
+
|
|
+ if (RAND_bytes(rnd, sizeof(rnd)) <= 0)
|
|
+ fatal("Couldn't obtain random bytes (error %ld)",
|
|
+ ERR_get_error());
|
|
+
|
|
+ if (!rs_initialized) {
|
|
+ rs_initialized = 1;
|
|
+ _rs_init(rnd, sizeof(rnd));
|
|
+ } else
|
|
+ _rs_rekey(rnd, sizeof(rnd));
|
|
+ memset(rnd, 0, sizeof(rnd));
|
|
+
|
|
+ /* invalidate rs_buf */
|
|
+ rs_have = 0;
|
|
+ memset(rs_buf, 0, RSBUFSZ);
|
|
+
|
|
+ rs_count = 1600000;
|
|
+}
|
|
+
|
|
+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_stir();
|
|
+ } else
|
|
+ rs_count -= len;
|
|
+}
|
|
+
|
|
+static inline void
|
|
+_rs_rekey(u_char *dat, size_t datlen)
|
|
+{
|
|
+#ifndef KEYSTREAM_ONLY
|
|
+ memset(rs_buf, 0,RSBUFSZ);
|
|
+#endif
|
|
+ /* fill rs_buf with the keystream */
|
|
+ chacha_encrypt_bytes(&rs, rs_buf, rs_buf, RSBUFSZ);
|
|
+ /* mix in optional user provided data */
|
|
+ if (dat) {
|
|
+ size_t i, m;
|
|
+
|
|
+ m = MIN(datlen, KEYSZ + IVSZ);
|
|
+ for (i = 0; i < m; i++)
|
|
+ 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;
|
|
+}
|
|
+
|
|
+static inline void
|
|
+_rs_random_buf(void *_buf, size_t n)
|
|
+{
|
|
+ u_char *buf = (u_char *)_buf;
|
|
+ size_t m;
|
|
+
|
|
+ _rs_stir_if_needed(n);
|
|
+ while (n > 0) {
|
|
+ if (rs_have > 0) {
|
|
+ m = MIN(n, rs_have);
|
|
+ memcpy(buf, rs_buf + RSBUFSZ - rs_have, m);
|
|
+ memset(rs_buf + RSBUFSZ - rs_have, 0, m);
|
|
+ buf += m;
|
|
+ n -= m;
|
|
+ rs_have -= m;
|
|
+ }
|
|
+ if (rs_have == 0)
|
|
+ _rs_rekey(NULL, 0);
|
|
+ }
|
|
+}
|
|
+
|
|
+static inline void
|
|
+_rs_random_u32(u_int32_t *val)
|
|
+{
|
|
+ _rs_stir_if_needed(sizeof(*val));
|
|
+ if (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;
|
|
+}
|
|
+
|
|
+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 = MIN(datlen, KEYSZ + IVSZ);
|
|
+ _rs_rekey(dat, m);
|
|
+ dat += m;
|
|
+ datlen -= m;
|
|
+ }
|
|
+ _ARC4_UNLOCK();
|
|
+}
|
|
+
|
|
+u_int32_t
|
|
+arc4random(void)
|
|
+{
|
|
+ u_int32_t val;
|
|
+
|
|
+ _ARC4_LOCK();
|
|
+ _rs_random_u32(&val);
|
|
+ _ARC4_UNLOCK();
|
|
+ return val;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * If we are providing arc4random, then we can provide a more efficient
|
|
+ * arc4random_buf().
|
|
+ */
|
|
+# ifndef HAVE_ARC4RANDOM_BUF
|
|
+void
|
|
+arc4random_buf(void *buf, size_t n)
|
|
+{
|
|
+ _ARC4_LOCK();
|
|
+ _rs_random_buf(buf, n);
|
|
+ _ARC4_UNLOCK();
|
|
+}
|
|
+# endif /* !HAVE_ARC4RANDOM_BUF */
|
|
+#endif /* !HAVE_ARC4RANDOM */
|
|
+
|
|
+/* arc4random_buf() that uses platform arc4random() */
|
|
+#if !defined(HAVE_ARC4RANDOM_BUF) && defined(HAVE_ARC4RANDOM)
|
|
+void
|
|
+arc4random_buf(void *_buf, size_t n)
|
|
+{
|
|
+ size_t i;
|
|
+ u_int32_t r = 0;
|
|
+ char *buf = (char *)_buf;
|
|
+
|
|
+ for (i = 0; i < n; i++) {
|
|
+ if (i % 4 == 0)
|
|
+ r = arc4random();
|
|
+ buf[i] = r & 0xff;
|
|
+ r >>= 8;
|
|
+ }
|
|
+ explicit_bzero(&r, sizeof(r));
|
|
+}
|
|
+#endif /* !defined(HAVE_ARC4RANDOM_BUF) && defined(HAVE_ARC4RANDOM) */
|
|
+
|
|
+#ifndef HAVE_ARC4RANDOM_UNIFORM
|
|
+/*
|
|
+ * Calculate a uniformly distributed random number less than upper_bound
|
|
+ * avoiding "modulo bias".
|
|
+ *
|
|
+ * Uniformity is achieved by generating new random numbers until the one
|
|
+ * returned is outside the range [0, 2**32 % upper_bound). This
|
|
+ * guarantees the selected random number will be inside
|
|
+ * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
|
|
+ * after reduction modulo upper_bound.
|
|
+ */
|
|
+u_int32_t
|
|
+arc4random_uniform(u_int32_t upper_bound)
|
|
+{
|
|
+ u_int32_t r, min;
|
|
+
|
|
+ if (upper_bound < 2)
|
|
+ return 0;
|
|
+
|
|
+ /* 2**32 % x == (2**32 - x) % x */
|
|
+ min = -upper_bound % upper_bound;
|
|
+
|
|
+ /*
|
|
+ * This could theoretically loop forever but each retry has
|
|
+ * p > 0.5 (worst case, usually far better) of selecting a
|
|
+ * number inside the range we need, so it should rarely need
|
|
+ * to re-roll.
|
|
+ */
|
|
+ for (;;) {
|
|
+ r = arc4random();
|
|
+ if (r >= min)
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return r % upper_bound;
|
|
+}
|
|
+#endif /* !HAVE_ARC4RANDOM_UNIFORM */
|
|
+
|
|
+#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/defines.h b/openbsd-compat/defines.h
|
|
index da7a42c..e79ef51 100644
|
|
--- a/openbsd-compat/defines.h
|
|
+++ b/openbsd-compat/defines.h
|
|
@@ -745,6 +745,15 @@ struct winsize {
|
|
#define INET6_ADDRSTRLEN 46
|
|
#endif
|
|
|
|
+/*
|
|
+ * Platforms that have arc4random_uniform() and not arc4random_stir()
|
|
+ * shouldn't need the latter.
|
|
+ */
|
|
+#if defined(HAVE_ARC4RANDOM) && defined(HAVE_ARC4RANDOM_UNIFORM) && \
|
|
+ !defined(HAVE_ARC4RANDOM_STIR)
|
|
+# define arc4random_stir()
|
|
+#endif
|
|
+
|
|
#ifndef HAVE_VA_COPY
|
|
# ifdef HAVE___VA_COPY
|
|
# define va_copy(dest, src) __va_copy(dest, src)
|
|
diff --git a/openbsd-compat/openbsd-compat.h b/openbsd-compat/openbsd-compat.h
|
|
index c30591c..a08502d 100644
|
|
--- a/openbsd-compat/openbsd-compat.h
|
|
+++ b/openbsd-compat/openbsd-compat.h
|
|
@@ -63,7 +63,24 @@ char *strsep(char **stringp, const char *delim);
|
|
|
|
#ifndef HAVE_ASPRINTF
|
|
int asprintf(char **, const char *, ...);
|
|
-#endif
|
|
+#endif
|
|
+
|
|
+#ifdef HAVE_ARC4RANDOM
|
|
+# ifndef HAVE_ARC4RANDOM_STIR
|
|
+# define arc4random_stir()
|
|
+# endif
|
|
+#else
|
|
+unsigned int arc4random(void);
|
|
+void arc4random_stir(void);
|
|
+#endif /* !HAVE_ARC4RANDOM */
|
|
+
|
|
+#ifndef HAVE_ARC4RANDOM_BUF
|
|
+void arc4random_buf(void *, size_t);
|
|
+#endif
|
|
+
|
|
+#ifndef HAVE_ARC4RANDOM_UNIFORM
|
|
+u_int32_t arc4random_uniform(u_int32_t);
|
|
+#endif
|
|
|
|
/* #include <sys/types.h> XXX needed? For size_t */
|
|
|
|
diff --git a/src/res_mkquery.c b/src/res_mkquery.c
|
|
index 27ed21e..cce4029 100644
|
|
--- a/src/res_mkquery.c
|
|
+++ b/src/res_mkquery.c
|
|
@@ -57,7 +57,7 @@ res_mkquery(int op, const char *dname, int class, int type,
|
|
ac = asr_use_resolver(NULL);
|
|
|
|
memset(&h, 0, sizeof h);
|
|
- h.id = res_randomid();
|
|
+ h.id = arc4random();
|
|
if (ac->ac_options & RES_RECURSE)
|
|
h.flags |= RD_MASK;
|
|
h.qdcount = 1;
|
|
diff --git a/src/res_send_async.c b/src/res_send_async.c
|
|
index a60aa0d..a0f4704 100644
|
|
--- a/src/res_send_async.c
|
|
+++ b/src/res_send_async.c
|
|
@@ -380,7 +380,7 @@ setup_query(struct asr_query *as, const char *name, const char *dom,
|
|
as->as.dns.obuflen = 0;
|
|
|
|
memset(&h, 0, sizeof h);
|
|
- h.id = res_randomid();
|
|
+ h.id = arc4random();
|
|
if (as->as_ctx->ac_options & RES_RECURSE)
|
|
h.flags |= RD_MASK;
|
|
h.qdcount = 1;
|