diff options
Diffstat (limited to 'ext/libressl/crypto/compat')
26 files changed, 3680 insertions, 0 deletions
| diff --git a/ext/libressl/crypto/compat/Makefile b/ext/libressl/crypto/compat/Makefile new file mode 100644 index 0000000..00e3a67 --- /dev/null +++ b/ext/libressl/crypto/compat/Makefile @@ -0,0 +1,13 @@ +include ../../ssl_common.mk + +obj = arc4random.o explicit_bzero.o timingsafe_bcmp.o timingsafe_memcmp.o + + +all: $(obj) +dep: all + +%.o: %.c +	$(CC) $(CFLAGS) -c $< + +clean: +	rm -f *.o *.a diff --git a/ext/libressl/crypto/compat/arc4random.c b/ext/libressl/crypto/compat/arc4random.c new file mode 100644 index 0000000..67a47f6 --- /dev/null +++ b/ext/libressl/crypto/compat/arc4random.c @@ -0,0 +1,216 @@ +/*	$OpenBSD: arc4random.c,v 1.55 2019/03/24 17:56:54 deraadt 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. + */ + +/* + * ChaCha based random number generator for OpenBSD. + */ + +#include <fcntl.h> +#include <limits.h> +#include <signal.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/time.h> + +#define KEYSTREAM_ONLY +#include "chacha_private.h" + +#define minimum(a, b) ((a) < (b) ? (a) : (b)) + +#if defined(__GNUC__) || defined(_MSC_VER) +#define inline __inline +#else				/* __GNUC__ || _MSC_VER */ +#define inline +#endif				/* !__GNUC__ && !_MSC_VER */ + +#define KEYSZ	32 +#define IVSZ	8 +#define BLOCKSZ	64 +#if defined(__FE310__) +#define RSBLKS	16 +#define RSBUFSZ	(BLOCKSZ) +#else +#define RSBUFSZ	(16*BLOCKSZ) +#endif + +/* 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 */ +#if defined(__FE310__) +	size_t		rs_blocks;	/* blocks till rekey */ +#endif +} *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); + +static inline void +_rs_init(u_char *buf, size_t n) +{ +	if (n < KEYSZ + IVSZ) +		return; + +	if (rs == NULL) { +		if (_rs_allocate(&rs, &rsx) == -1) +			_exit(1); +#if defined(__FE310__) +		rs->rs_blocks = (RSBLKS - 1); +#endif +	} + +	chacha_keysetup(&rsx->rs_chacha, buf, KEYSZ * 8, 0); +	chacha_ivsetup(&rsx->rs_chacha, buf + KEYSZ); +} + +static void +_rs_stir(void) +{ +	u_char rnd[KEYSZ + IVSZ]; + +	if (getentropy(rnd, sizeof rnd) == -1) +		_getentropy_fail(); + +	if (!rs) +		_rs_init(rnd, sizeof(rnd)); +	else +		_rs_rekey(rnd, sizeof(rnd)); +	explicit_bzero(rnd, sizeof(rnd));	/* discard source seed */ + +	/* invalidate rs_buf */ +	rs->rs_have = 0; +	memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf)); + +	rs->rs_count = 1600000; +} + +static inline void +_rs_stir_if_needed(size_t len) +{ +	_rs_forkdetect(); +	if (!rs || rs->rs_count <= len) +		_rs_stir(); +	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(rsx->rs_buf, 0, sizeof(rsx->rs_buf)); +#endif +	/* fill rs_buf with the keystream */ +	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); +		for (i = 0; i < m; i++) +			rsx->rs_buf[i] ^= dat[i]; +	} +#if defined(__FE310__) +	if (dat || (rs->rs_blocks == 0)) { +		rs->rs_blocks = (RSBLKS - 1); +	} else { +		rs->rs_blocks--; +		rs->rs_have = sizeof(rsx->rs_buf); +		return; +	} +#endif +	/* immediately reinit for backtracking resistance */ +	_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->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->rs_have -= m; +		} +		if (rs->rs_have == 0) +			_rs_rekey(NULL, 0); +	} +} + +static inline void +_rs_random_u32(uint32_t *val) +{ +	u_char *keystream; + +	_rs_stir_if_needed(sizeof(*val)); +	if (rs->rs_have < sizeof(*val)) +		_rs_rekey(NULL, 0); +	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); +} + +uint32_t +arc4random(void) +{ +	uint32_t val; + +	_ARC4_LOCK(); +	_rs_random_u32(&val); +	_ARC4_UNLOCK(); +	return val; +} + +void +arc4random_buf(void *buf, size_t n) +{ +	_ARC4_LOCK(); +	_rs_random_buf(buf, n); +	_ARC4_UNLOCK(); +} diff --git a/ext/libressl/crypto/compat/arc4random.h b/ext/libressl/crypto/compat/arc4random.h new file mode 100644 index 0000000..8a308a9 --- /dev/null +++ b/ext/libressl/crypto/compat/arc4random.h @@ -0,0 +1,41 @@ +#ifndef LIBCRYPTOCOMPAT_ARC4RANDOM_H +#define LIBCRYPTOCOMPAT_ARC4RANDOM_H + +#include <sys/param.h> + +#if defined(_AIX) +#include "arc4random_aix.h" + +#elif defined(__FreeBSD__) +#include "arc4random_freebsd.h" + +#elif defined(__hpux) +#include "arc4random_hpux.h" + +#elif defined(__linux__) +#include "arc4random_linux.h" + +#elif defined(__midipix__) +#include "arc4random_linux.h" + +#elif defined(__NetBSD__) +#include "arc4random_netbsd.h" + +#elif defined(__APPLE__) +#include "arc4random_osx.h" + +#elif defined(__sun) +#include "arc4random_solaris.h" + +#elif defined(_WIN32) +#include "arc4random_win.h" + +#elif defined(__FE310__) +#include "arc4random_fe310.h" + +#else +#error "No arc4random hooks defined for this platform." + +#endif + +#endif diff --git a/ext/libressl/crypto/compat/arc4random_aix.h b/ext/libressl/crypto/compat/arc4random_aix.h new file mode 100644 index 0000000..3142a1f --- /dev/null +++ b/ext/libressl/crypto/compat/arc4random_aix.h @@ -0,0 +1,81 @@ +/*	$OpenBSD: arc4random_aix.h,v 1.2 2016/06/30 12:19:51 bcook 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. + */ + +#include <sys/mman.h> + +#include <pthread.h> +#include <signal.h> + +static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER; +#define _ARC4_LOCK()   pthread_mutex_lock(&arc4random_mtx) +#define _ARC4_UNLOCK() pthread_mutex_unlock(&arc4random_mtx) + +#define _ARC4_ATFORK(f) pthread_atfork(NULL, NULL, (f)) + +static inline void +_getentropy_fail(void) +{ +	raise(SIGKILL); +} + +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 != 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/ext/libressl/crypto/compat/arc4random_fe310.h b/ext/libressl/crypto/compat/arc4random_fe310.h new file mode 100644 index 0000000..131b0d3 --- /dev/null +++ b/ext/libressl/crypto/compat/arc4random_fe310.h @@ -0,0 +1,27 @@ +#define _ARC4_LOCK() ; +#define _ARC4_UNLOCK() ; + +static inline void +_getentropy_fail(void) +{ +	_exit(1); +} + +static inline void +_rs_forkdetect(void) +{ +} + +int arc4random_alloc(void **rsp, size_t rsp_size, void **rsxp, size_t rsxp_size); + +static inline int +_rs_allocate(struct _rs **rsp, struct _rsx **rsxp) +{ +	return arc4random_alloc((void **)rsp, sizeof(**rsp), (void **)rsxp, sizeof(**rsxp)); +} + +void arc4random_close(void) +{ +	rs = NULL; +	rsx = NULL; +}
\ No newline at end of file diff --git a/ext/libressl/crypto/compat/arc4random_freebsd.h b/ext/libressl/crypto/compat/arc4random_freebsd.h new file mode 100644 index 0000000..3faa5e4 --- /dev/null +++ b/ext/libressl/crypto/compat/arc4random_freebsd.h @@ -0,0 +1,87 @@ +/*	$OpenBSD: arc4random_freebsd.h,v 1.4 2016/06/30 12:19:51 bcook 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. + */ + +#include <sys/mman.h> + +#include <pthread.h> +#include <signal.h> + +static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER; +#define _ARC4_LOCK()   pthread_mutex_lock(&arc4random_mtx) +#define _ARC4_UNLOCK() pthread_mutex_unlock(&arc4random_mtx) + +/* + * Unfortunately, pthread_atfork() is broken on FreeBSD (at least 9 and 10) if + * a program does not link to -lthr. Callbacks registered with pthread_atfork() + * appear to fail silently. So, it is not always possible to detect a PID + * wraparound. + */ +#define _ARC4_ATFORK(f) pthread_atfork(NULL, NULL, (f)) + +static inline void +_getentropy_fail(void) +{ +	raise(SIGKILL); +} + +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 != 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/ext/libressl/crypto/compat/arc4random_hpux.h b/ext/libressl/crypto/compat/arc4random_hpux.h new file mode 100644 index 0000000..2a3fe8c --- /dev/null +++ b/ext/libressl/crypto/compat/arc4random_hpux.h @@ -0,0 +1,81 @@ +/*	$OpenBSD: arc4random_hpux.h,v 1.3 2016/06/30 12:19:51 bcook 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. + */ + +#include <sys/mman.h> + +#include <pthread.h> +#include <signal.h> + +static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER; +#define _ARC4_LOCK()   pthread_mutex_lock(&arc4random_mtx) +#define _ARC4_UNLOCK() pthread_mutex_unlock(&arc4random_mtx) + +#define _ARC4_ATFORK(f) pthread_atfork(NULL, NULL, (f)) + +static inline void +_getentropy_fail(void) +{ +	raise(SIGKILL); +} + +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 != 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/ext/libressl/crypto/compat/arc4random_linux.h b/ext/libressl/crypto/compat/arc4random_linux.h new file mode 100644 index 0000000..5e1cf34 --- /dev/null +++ b/ext/libressl/crypto/compat/arc4random_linux.h @@ -0,0 +1,88 @@ +/*	$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. + */ + +#include <sys/mman.h> + +#include <pthread.h> +#include <signal.h> + +static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER; +#define _ARC4_LOCK()   pthread_mutex_lock(&arc4random_mtx) +#define _ARC4_UNLOCK() pthread_mutex_unlock(&arc4random_mtx) + +#if defined(__GLIBC__) && !(defined(__UCLIBC__) && !defined(__ARCH_USE_MMU__)) +extern void *__dso_handle; +extern int __register_atfork(void (*)(void), void(*)(void), void (*)(void), void *); +#define _ARC4_ATFORK(f) __register_atfork(NULL, NULL, (f), __dso_handle) +#else +#define _ARC4_ATFORK(f) pthread_atfork(NULL, NULL, (f)) +#endif + +static inline void +_getentropy_fail(void) +{ +	raise(SIGKILL); +} + +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(); + +        /* XXX unusual calls to clone() can bypass checks */ +	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/ext/libressl/crypto/compat/arc4random_netbsd.h b/ext/libressl/crypto/compat/arc4random_netbsd.h new file mode 100644 index 0000000..611997d --- /dev/null +++ b/ext/libressl/crypto/compat/arc4random_netbsd.h @@ -0,0 +1,87 @@ +/*	$OpenBSD: arc4random_netbsd.h,v 1.3 2016/06/30 12:19:51 bcook 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. + */ + +#include <sys/mman.h> + +#include <pthread.h> +#include <signal.h> + +static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER; +#define _ARC4_LOCK()   pthread_mutex_lock(&arc4random_mtx) +#define _ARC4_UNLOCK() pthread_mutex_unlock(&arc4random_mtx) + +/* + * Unfortunately, pthread_atfork() is broken on FreeBSD (at least 9 and 10) if + * a program does not link to -lthr. Callbacks registered with pthread_atfork() + * appear to fail silently. So, it is not always possible to detect a PID + * wraparound. + */ +#define _ARC4_ATFORK(f) pthread_atfork(NULL, NULL, (f)) + +static inline void +_getentropy_fail(void) +{ +	raise(SIGKILL); +} + +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 != 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/ext/libressl/crypto/compat/arc4random_osx.h b/ext/libressl/crypto/compat/arc4random_osx.h new file mode 100644 index 0000000..818ae6b --- /dev/null +++ b/ext/libressl/crypto/compat/arc4random_osx.h @@ -0,0 +1,81 @@ +/*	$OpenBSD: arc4random_osx.h,v 1.11 2016/06/30 12:19:51 bcook 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. + */ + +#include <sys/mman.h> + +#include <pthread.h> +#include <signal.h> + +static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER; +#define _ARC4_LOCK()   pthread_mutex_lock(&arc4random_mtx) +#define _ARC4_UNLOCK() pthread_mutex_unlock(&arc4random_mtx) + +#define _ARC4_ATFORK(f) pthread_atfork(NULL, NULL, (f)) + +static inline void +_getentropy_fail(void) +{ +	raise(SIGKILL); +} + +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 != 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/ext/libressl/crypto/compat/arc4random_solaris.h b/ext/libressl/crypto/compat/arc4random_solaris.h new file mode 100644 index 0000000..b1084cd --- /dev/null +++ b/ext/libressl/crypto/compat/arc4random_solaris.h @@ -0,0 +1,81 @@ +/*	$OpenBSD: arc4random_solaris.h,v 1.10 2016/06/30 12:19:51 bcook 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. + */ + +#include <sys/mman.h> + +#include <pthread.h> +#include <signal.h> + +static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER; +#define _ARC4_LOCK()   pthread_mutex_lock(&arc4random_mtx) +#define _ARC4_UNLOCK() pthread_mutex_unlock(&arc4random_mtx) + +#define _ARC4_ATFORK(f) pthread_atfork(NULL, NULL, (f)) + +static inline void +_getentropy_fail(void) +{ +	raise(SIGKILL); +} + +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 != 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/ext/libressl/crypto/compat/arc4random_uniform.c b/ext/libressl/crypto/compat/arc4random_uniform.c new file mode 100644 index 0000000..06cd29c --- /dev/null +++ b/ext/libressl/crypto/compat/arc4random_uniform.c @@ -0,0 +1,56 @@ +/*	$OpenBSD: arc4random_uniform.c,v 1.3 2019/01/20 02:59:07 bcook Exp $	*/ + +/* + * Copyright (c) 2008, Damien Miller <djm@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. + */ + +#include <stdint.h> +#include <stdlib.h> + +/* + * 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. + */ +uint32_t +arc4random_uniform(uint32_t upper_bound) +{ +	uint32_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; +} diff --git a/ext/libressl/crypto/compat/arc4random_win.h b/ext/libressl/crypto/compat/arc4random_win.h new file mode 100644 index 0000000..deec8a1 --- /dev/null +++ b/ext/libressl/crypto/compat/arc4random_win.h @@ -0,0 +1,78 @@ +/*	$OpenBSD: arc4random_win.h,v 1.6 2016/06/30 12:17:29 bcook 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. + */ + +#include <windows.h> + +static volatile HANDLE arc4random_mtx = NULL; + +/* + * Initialize the mutex on the first lock attempt. On collision, each thread + * will attempt to allocate a mutex and compare-and-swap it into place as the + * global mutex. On failure to swap in the global mutex, the mutex is closed. + */ +#define _ARC4_LOCK() { \ +	if (!arc4random_mtx) { \ +		HANDLE p = CreateMutex(NULL, FALSE, NULL); \ +		if (InterlockedCompareExchangePointer((void **)&arc4random_mtx, (void *)p, NULL)) \ +			CloseHandle(p); \ +	} \ +	WaitForSingleObject(arc4random_mtx, INFINITE); \ +} \ + +#define _ARC4_UNLOCK() ReleaseMutex(arc4random_mtx) + +static inline void +_getentropy_fail(void) +{ +	TerminateProcess(GetCurrentProcess(), 0); +} + +static inline int +_rs_allocate(struct _rs **rsp, struct _rsx **rsxp) +{ +	*rsp = VirtualAlloc(NULL, sizeof(**rsp), +	    MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); +	if (*rsp == NULL) +		return (-1); + +	*rsxp = VirtualAlloc(NULL, sizeof(**rsxp), +	    MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); +	if (*rsxp == NULL) { +		VirtualFree(*rsp, 0, MEM_RELEASE); +		*rsp = NULL; +		return (-1); +	} +	return (0); +} + +static inline void +_rs_forkhandler(void) +{ +} + +static inline void +_rs_forkdetect(void) +{ +} diff --git a/ext/libressl/crypto/compat/chacha_private.h b/ext/libressl/crypto/compat/chacha_private.h new file mode 100644 index 0000000..7c3680f --- /dev/null +++ b/ext/libressl/crypto/compat/chacha_private.h @@ -0,0 +1,222 @@ +/* +chacha-merged.c version 20080118 +D. J. Bernstein +Public domain. +*/ + +/* $OpenBSD: chacha_private.h,v 1.2 2013/10/04 07:02:27 djm Exp $ */ + +typedef unsigned char u8; +typedef unsigned int u32; + +typedef struct +{ +  u32 input[16]; /* could be compressed */ +} chacha_ctx; + +#define U8C(v) (v##U) +#define U32C(v) (v##U) + +#define U8V(v) ((u8)(v) & U8C(0xFF)) +#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF)) + +#define ROTL32(v, n) \ +  (U32V((v) << (n)) | ((v) >> (32 - (n)))) + +#define U8TO32_LITTLE(p) \ +  (((u32)((p)[0])      ) | \ +   ((u32)((p)[1]) <<  8) | \ +   ((u32)((p)[2]) << 16) | \ +   ((u32)((p)[3]) << 24)) + +#define U32TO8_LITTLE(p, v) \ +  do { \ +    (p)[0] = U8V((v)      ); \ +    (p)[1] = U8V((v) >>  8); \ +    (p)[2] = U8V((v) >> 16); \ +    (p)[3] = U8V((v) >> 24); \ +  } while (0) + +#define ROTATE(v,c) (ROTL32(v,c)) +#define XOR(v,w) ((v) ^ (w)) +#define PLUS(v,w) (U32V((v) + (w))) +#define PLUSONE(v) (PLUS((v),1)) + +#define QUARTERROUND(a,b,c,d) \ +  a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \ +  c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \ +  a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \ +  c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); + +static const char sigma[16] = "expand 32-byte k"; +static const char tau[16] = "expand 16-byte k"; + +static void +chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits,u32 ivbits) +{ +  const char *constants; + +  x->input[4] = U8TO32_LITTLE(k + 0); +  x->input[5] = U8TO32_LITTLE(k + 4); +  x->input[6] = U8TO32_LITTLE(k + 8); +  x->input[7] = U8TO32_LITTLE(k + 12); +  if (kbits == 256) { /* recommended */ +    k += 16; +    constants = sigma; +  } else { /* kbits == 128 */ +    constants = tau; +  } +  x->input[8] = U8TO32_LITTLE(k + 0); +  x->input[9] = U8TO32_LITTLE(k + 4); +  x->input[10] = U8TO32_LITTLE(k + 8); +  x->input[11] = U8TO32_LITTLE(k + 12); +  x->input[0] = U8TO32_LITTLE(constants + 0); +  x->input[1] = U8TO32_LITTLE(constants + 4); +  x->input[2] = U8TO32_LITTLE(constants + 8); +  x->input[3] = U8TO32_LITTLE(constants + 12); +} + +static void +chacha_ivsetup(chacha_ctx *x,const u8 *iv) +{ +  x->input[12] = 0; +  x->input[13] = 0; +  x->input[14] = U8TO32_LITTLE(iv + 0); +  x->input[15] = U8TO32_LITTLE(iv + 4); +} + +static void +chacha_encrypt_bytes(chacha_ctx *x,const u8 *m,u8 *c,u32 bytes) +{ +  u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; +  u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15; +  u8 *ctarget = NULL; +  u8 tmp[64]; +  u_int i; + +  if (!bytes) return; + +  j0 = x->input[0]; +  j1 = x->input[1]; +  j2 = x->input[2]; +  j3 = x->input[3]; +  j4 = x->input[4]; +  j5 = x->input[5]; +  j6 = x->input[6]; +  j7 = x->input[7]; +  j8 = x->input[8]; +  j9 = x->input[9]; +  j10 = x->input[10]; +  j11 = x->input[11]; +  j12 = x->input[12]; +  j13 = x->input[13]; +  j14 = x->input[14]; +  j15 = x->input[15]; + +  for (;;) { +    if (bytes < 64) { +      for (i = 0;i < bytes;++i) tmp[i] = m[i]; +      m = tmp; +      ctarget = c; +      c = tmp; +    } +    x0 = j0; +    x1 = j1; +    x2 = j2; +    x3 = j3; +    x4 = j4; +    x5 = j5; +    x6 = j6; +    x7 = j7; +    x8 = j8; +    x9 = j9; +    x10 = j10; +    x11 = j11; +    x12 = j12; +    x13 = j13; +    x14 = j14; +    x15 = j15; +    for (i = 20;i > 0;i -= 2) { +      QUARTERROUND( x0, x4, x8,x12) +      QUARTERROUND( x1, x5, x9,x13) +      QUARTERROUND( x2, x6,x10,x14) +      QUARTERROUND( x3, x7,x11,x15) +      QUARTERROUND( x0, x5,x10,x15) +      QUARTERROUND( x1, x6,x11,x12) +      QUARTERROUND( x2, x7, x8,x13) +      QUARTERROUND( x3, x4, x9,x14) +    } +    x0 = PLUS(x0,j0); +    x1 = PLUS(x1,j1); +    x2 = PLUS(x2,j2); +    x3 = PLUS(x3,j3); +    x4 = PLUS(x4,j4); +    x5 = PLUS(x5,j5); +    x6 = PLUS(x6,j6); +    x7 = PLUS(x7,j7); +    x8 = PLUS(x8,j8); +    x9 = PLUS(x9,j9); +    x10 = PLUS(x10,j10); +    x11 = PLUS(x11,j11); +    x12 = PLUS(x12,j12); +    x13 = PLUS(x13,j13); +    x14 = PLUS(x14,j14); +    x15 = PLUS(x15,j15); + +#ifndef KEYSTREAM_ONLY +    x0 = XOR(x0,U8TO32_LITTLE(m + 0)); +    x1 = XOR(x1,U8TO32_LITTLE(m + 4)); +    x2 = XOR(x2,U8TO32_LITTLE(m + 8)); +    x3 = XOR(x3,U8TO32_LITTLE(m + 12)); +    x4 = XOR(x4,U8TO32_LITTLE(m + 16)); +    x5 = XOR(x5,U8TO32_LITTLE(m + 20)); +    x6 = XOR(x6,U8TO32_LITTLE(m + 24)); +    x7 = XOR(x7,U8TO32_LITTLE(m + 28)); +    x8 = XOR(x8,U8TO32_LITTLE(m + 32)); +    x9 = XOR(x9,U8TO32_LITTLE(m + 36)); +    x10 = XOR(x10,U8TO32_LITTLE(m + 40)); +    x11 = XOR(x11,U8TO32_LITTLE(m + 44)); +    x12 = XOR(x12,U8TO32_LITTLE(m + 48)); +    x13 = XOR(x13,U8TO32_LITTLE(m + 52)); +    x14 = XOR(x14,U8TO32_LITTLE(m + 56)); +    x15 = XOR(x15,U8TO32_LITTLE(m + 60)); +#endif + +    j12 = PLUSONE(j12); +    if (!j12) { +      j13 = PLUSONE(j13); +      /* stopping at 2^70 bytes per nonce is user's responsibility */ +    } + +    U32TO8_LITTLE(c + 0,x0); +    U32TO8_LITTLE(c + 4,x1); +    U32TO8_LITTLE(c + 8,x2); +    U32TO8_LITTLE(c + 12,x3); +    U32TO8_LITTLE(c + 16,x4); +    U32TO8_LITTLE(c + 20,x5); +    U32TO8_LITTLE(c + 24,x6); +    U32TO8_LITTLE(c + 28,x7); +    U32TO8_LITTLE(c + 32,x8); +    U32TO8_LITTLE(c + 36,x9); +    U32TO8_LITTLE(c + 40,x10); +    U32TO8_LITTLE(c + 44,x11); +    U32TO8_LITTLE(c + 48,x12); +    U32TO8_LITTLE(c + 52,x13); +    U32TO8_LITTLE(c + 56,x14); +    U32TO8_LITTLE(c + 60,x15); + +    if (bytes <= 64) { +      if (bytes < 64) { +        for (i = 0;i < bytes;++i) ctarget[i] = c[i]; +      } +      x->input[12] = j12; +      x->input[13] = j13; +      return; +    } +    bytes -= 64; +    c += 64; +#ifndef KEYSTREAM_ONLY +    m += 64; +#endif +  } +} diff --git a/ext/libressl/crypto/compat/explicit_bzero.c b/ext/libressl/crypto/compat/explicit_bzero.c new file mode 100644 index 0000000..5dd0103 --- /dev/null +++ b/ext/libressl/crypto/compat/explicit_bzero.c @@ -0,0 +1,19 @@ +/*	$OpenBSD: explicit_bzero.c,v 1.4 2015/08/31 02:53:57 guenther Exp $ */ +/* + * Public domain. + * Written by Matthew Dempsky. + */ + +#include <string.h> + +__attribute__((weak)) void +__explicit_bzero_hook(void *buf, size_t len) +{ +} + +void +explicit_bzero(void *buf, size_t len) +{ +	memset(buf, 0, len); +	__explicit_bzero_hook(buf, len); +} diff --git a/ext/libressl/crypto/compat/explicit_bzero_win.c b/ext/libressl/crypto/compat/explicit_bzero_win.c new file mode 100644 index 0000000..0d09d90 --- /dev/null +++ b/ext/libressl/crypto/compat/explicit_bzero_win.c @@ -0,0 +1,13 @@ +/* + * Public domain. + * Win32 explicit_bzero compatibility shim. + */ + +#include <windows.h> +#include <string.h> + +void +explicit_bzero(void *buf, size_t len) +{ +	SecureZeroMemory(buf, len); +} diff --git a/ext/libressl/crypto/compat/getentropy_aix.c b/ext/libressl/crypto/compat/getentropy_aix.c new file mode 100644 index 0000000..422e685 --- /dev/null +++ b/ext/libressl/crypto/compat/getentropy_aix.c @@ -0,0 +1,402 @@ +/*	$OpenBSD: getentropy_aix.c,v 1.7 2020/05/17 14:44:20 deraadt Exp $	*/ + +/* + * Copyright (c) 2015 Michael Felt <aixtools@gmail.com> + * Copyright (c) 2014 Theo de Raadt <deraadt@openbsd.org> + * Copyright (c) 2014 Bob Beck <beck@obtuse.com> + * + * 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. + * + * Emulation of getentropy(2) as documented at: + * http://man.openbsd.org/getentropy.2 + */ +/* + * -lperfstat is needed for the psuedo entropy data + */ + +#include <sys/mman.h> +#include <sys/procfs.h> +#include <sys/protosw.h> +#include <sys/resource.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/statvfs.h> +#include <sys/timers.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <termios.h> + +#include <openssl/sha.h> + +#include <libperfstat.h> + +#define REPEAT 5 +#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) + +#define HX(a, b) \ +	do { \ +		if ((a)) \ +			HD(errno); \ +		else \ +			HD(b); \ +	} while (0) + +#define HR(x, l) (SHA512_Update(&ctx, (char *)(x), (l))) +#define HD(x)	 (SHA512_Update(&ctx, (char *)&(x), sizeof (x))) +#define HF(x)    (SHA512_Update(&ctx, (char *)&(x), sizeof (void*))) + +int	getentropy(void *buf, size_t len); + +static int getentropy_urandom(void *buf, size_t len, const char *path, +    int devfscheck); +static int getentropy_fallback(void *buf, size_t len); + +int +getentropy(void *buf, size_t len) +{ +	int ret = -1; + +	if (len > 256) { +		errno = EIO; +		return (-1); +	} + +	/* +	 * Try to get entropy with /dev/urandom +	 */ +	ret = getentropy_urandom(buf, len, "/dev/urandom", 0); +	if (ret != -1) +		return (ret); + +	/* +	 * Entropy collection via /dev/urandom has failed. +	 * +	 * No other API exists for collecting entropy, and we have +	 * no failsafe way to get it on AIX that is not sensitive +	 * to resource exhaustion. +	 * +	 * We have very few options: +	 *     - Even syslog_r is unsafe to call at this low level, so +	 *	 there is no way to alert the user or program. +	 *     - Cannot call abort() because some systems have unsafe +	 *	 corefiles. +	 *     - Could raise(SIGKILL) resulting in silent program termination. +	 *     - Return EIO, to hint that arc4random's stir function +	 *       should raise(SIGKILL) +	 *     - Do the best under the circumstances.... +	 * +	 * This code path exists to bring light to the issue that AIX +	 * does not provide a failsafe API for entropy collection. +	 * +	 * We hope this demonstrates that AIX should consider +	 * providing a new failsafe API which works in a chroot or +	 * when file descriptors are exhausted. +	 */ +#undef FAIL_INSTEAD_OF_TRYING_FALLBACK +#ifdef FAIL_INSTEAD_OF_TRYING_FALLBACK +	raise(SIGKILL); +#endif +	ret = getentropy_fallback(buf, len); +	if (ret != -1) +		return (ret); + +	errno = EIO; +	return (ret); +} + +static int +getentropy_urandom(void *buf, size_t len, const char *path, int devfscheck) +{ +	struct stat st; +	size_t i; +	int fd, flags; +	int save_errno = errno; + +start: + +	flags = O_RDONLY; +#ifdef O_NOFOLLOW +	flags |= O_NOFOLLOW; +#endif +#ifdef O_CLOEXEC +	flags |= O_CLOEXEC; +#endif +	fd = open(path, flags, 0); +	if (fd == -1) { +		if (errno == EINTR) +			goto start; +		goto nodevrandom; +	} +#ifndef O_CLOEXEC +	fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); +#endif + +	/* Lightly verify that the device node looks sane */ +	if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode)) { +		close(fd); +		goto nodevrandom; +	} +	for (i = 0; i < len; ) { +		size_t wanted = len - i; +		ssize_t ret = read(fd, (char *)buf + i, wanted); + +		if (ret == -1) { +			if (errno == EAGAIN || errno == EINTR) +				continue; +			close(fd); +			goto nodevrandom; +		} +		i += ret; +	} +	close(fd); +	errno = save_errno; +	return (0);		/* satisfied */ +nodevrandom: +	errno = EIO; +	return (-1); +} + +static const int cl[] = { +	CLOCK_REALTIME, +#ifdef CLOCK_MONOTONIC +	CLOCK_MONOTONIC, +#endif +#ifdef CLOCK_MONOTONIC_RAW +	CLOCK_MONOTONIC_RAW, +#endif +#ifdef CLOCK_TAI +	CLOCK_TAI, +#endif +#ifdef CLOCK_VIRTUAL +	CLOCK_VIRTUAL, +#endif +#ifdef CLOCK_UPTIME +	CLOCK_UPTIME, +#endif +#ifdef CLOCK_PROCESS_CPUTIME_ID +	CLOCK_PROCESS_CPUTIME_ID, +#endif +#ifdef CLOCK_THREAD_CPUTIME_ID +	CLOCK_THREAD_CPUTIME_ID, +#endif +}; + +static int +getentropy_fallback(void *buf, size_t len) +{ +	uint8_t results[SHA512_DIGEST_LENGTH]; +	int save_errno = errno, e, pgs = sysconf(_SC_PAGESIZE), faster = 0, repeat; +	static int cnt; +	struct timespec ts; +	struct timeval tv; +	perfstat_cpu_total_t cpustats; +#ifdef _AIX61 +	perfstat_cpu_total_wpar_t cpustats_wpar; +#endif +	perfstat_partition_total_t lparstats; +	perfstat_disk_total_t diskinfo; +	perfstat_netinterface_total_t netinfo; +	struct rusage ru; +	sigset_t sigset; +	struct stat st; +	SHA512_CTX ctx; +	static pid_t lastpid; +	pid_t pid; +	size_t i, ii, m; +	char *p; + +	pid = getpid(); +	if (lastpid == pid) { +		faster = 1; +		repeat = 2; +	} else { +		faster = 0; +		lastpid = pid; +		repeat = REPEAT; +	} +	for (i = 0; i < len; ) { +		int j; +		SHA512_Init(&ctx); +		for (j = 0; j < repeat; j++) { +			HX((e = gettimeofday(&tv, NULL)) == -1, tv); +			if (e != -1) { +				cnt += (int)tv.tv_sec; +				cnt += (int)tv.tv_usec; +			} + +			HX(perfstat_cpu_total(NULL, &cpustats, +			    sizeof(cpustats), 1) == -1, cpustats); + +#ifdef _AIX61 +			HX(perfstat_cpu_total_wpar(NULL, &cpustats_wpar, +			    sizeof(cpustats_wpar), 1) == -1, cpustats_wpar); +#endif + +			HX(perfstat_partition_total(NULL, &lparstats, +			    sizeof(lparstats), 1) == -1, lparstats); + +			HX(perfstat_disk_total(NULL, &diskinfo, +			    sizeof(diskinfo), 1) == -1, diskinfo); + +			HX(perfstat_netinterface_total(NULL, &netinfo, +			    sizeof(netinfo), 1) == -1, netinfo); + +			for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]); ii++) +				HX(clock_gettime(cl[ii], &ts) == -1, ts); + +			HX((pid = getpid()) == -1, pid); +			HX((pid = getsid(pid)) == -1, pid); +			HX((pid = getppid()) == -1, pid); +			HX((pid = getpgid(0)) == -1, pid); +			HX((e = getpriority(0, 0)) == -1, e); + +			if (!faster) { +				ts.tv_sec = 0; +				ts.tv_nsec = 1; +				(void) nanosleep(&ts, NULL); +			} + +			HX(sigpending(&sigset) == -1, sigset); +			HX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1, +			    sigset); + +			HF(getentropy);	/* an addr in this library */ +			HF(printf);		/* an addr in libc */ +			p = (char *)&p; +			HD(p);		/* an addr on stack */ +			p = (char *)&errno; +			HD(p);		/* the addr of errno */ + +			if (i == 0) { +				struct sockaddr_storage ss; +				struct statvfs stvfs; +				struct termios tios; +				socklen_t ssl; +				off_t off; + +				/* +				 * Prime-sized mappings encourage fragmentation; +				 * thus exposing some address entropy. +				 */ +				struct mm { +					size_t	npg; +					void	*p; +				} mm[] =	 { +					{ 17, MAP_FAILED }, { 3, MAP_FAILED }, +					{ 11, MAP_FAILED }, { 2, MAP_FAILED }, +					{ 5, MAP_FAILED }, { 3, MAP_FAILED }, +					{ 7, MAP_FAILED }, { 1, MAP_FAILED }, +					{ 57, MAP_FAILED }, { 3, MAP_FAILED }, +					{ 131, MAP_FAILED }, { 1, MAP_FAILED }, +				}; + +				for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) { +					HX(mm[m].p = mmap(NULL, +					    mm[m].npg * pgs, +					    PROT_READ|PROT_WRITE, +					    MAP_PRIVATE|MAP_ANON, -1, +					    (off_t)0), mm[m].p); +					if (mm[m].p != MAP_FAILED) { +						size_t mo; + +						/* Touch some memory... */ +						p = mm[m].p; +						mo = cnt % +						    (mm[m].npg * pgs - 1); +						p[mo] = 1; +						cnt += (int)((long)(mm[m].p) +						    / pgs); +					} + +					/* Check cnts and times... */ +					for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]); +					    ii++) { +						HX((e = clock_gettime(cl[ii], +						    &ts)) == -1, ts); +						if (e != -1) +							cnt += (int)ts.tv_nsec; +					} + +					HX((e = getrusage(RUSAGE_SELF, +					    &ru)) == -1, ru); +					if (e != -1) { +						cnt += (int)ru.ru_utime.tv_sec; +						cnt += (int)ru.ru_utime.tv_usec; +					} +				} + +				for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) { +					if (mm[m].p != MAP_FAILED) +						munmap(mm[m].p, mm[m].npg * pgs); +					mm[m].p = MAP_FAILED; +				} + +				HX(stat(".", &st) == -1, st); +				HX(statvfs(".", &stvfs) == -1, stvfs); + +				HX(stat("/", &st) == -1, st); +				HX(statvfs("/", &stvfs) == -1, stvfs); + +				HX((e = fstat(0, &st)) == -1, st); +				if (e == -1) { +					if (S_ISREG(st.st_mode) || +					    S_ISFIFO(st.st_mode) || +					    S_ISSOCK(st.st_mode)) { +						HX(fstatvfs(0, &stvfs) == -1, +						    stvfs); +						HX((off = lseek(0, (off_t)0, +						    SEEK_CUR)) < 0, off); +					} +					if (S_ISCHR(st.st_mode)) { +						HX(tcgetattr(0, &tios) == -1, +						    tios); +					} else if (S_ISSOCK(st.st_mode)) { +						memset(&ss, 0, sizeof ss); +						ssl = sizeof(ss); +						HX(getpeername(0, +						    (void *)&ss, &ssl) == -1, +						    ss); +					} +				} + +				HX((e = getrusage(RUSAGE_CHILDREN, +				    &ru)) == -1, ru); +				if (e != -1) { +					cnt += (int)ru.ru_utime.tv_sec; +					cnt += (int)ru.ru_utime.tv_usec; +				} +			} else { +				/* Subsequent hashes absorb previous result */ +				HD(results); +			} + +			HX((e = gettimeofday(&tv, NULL)) == -1, tv); +			if (e != -1) { +				cnt += (int)tv.tv_sec; +				cnt += (int)tv.tv_usec; +			} + +			HD(cnt); +		} +		SHA512_Final(results, &ctx); +		memcpy((char *)buf + i, results, MINIMUM(sizeof(results), len - i)); +		i += MINIMUM(sizeof(results), len - i); +	} +	explicit_bzero(&ctx, sizeof ctx); +	explicit_bzero(results, sizeof results); +	errno = save_errno; +	return (0);		/* satisfied */ +} diff --git a/ext/libressl/crypto/compat/getentropy_freebsd.c b/ext/libressl/crypto/compat/getentropy_freebsd.c new file mode 100644 index 0000000..ea90ffe --- /dev/null +++ b/ext/libressl/crypto/compat/getentropy_freebsd.c @@ -0,0 +1,60 @@ +/*	$OpenBSD: getentropy_freebsd.c,v 1.4 2020/10/12 22:08:33 deraadt Exp $	*/ + +/* + * Copyright (c) 2014 Pawel Jakub Dawidek <pjd@FreeBSD.org> + * Copyright (c) 2014 Brent Cook <bcook@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. + * + * Emulation of getentropy(2) as documented at: + * http://man.openbsd.org/getentropy.2 + */ + +#include <sys/types.h> +#include <sys/sysctl.h> + +#include <errno.h> +#include <stddef.h> + +/* + * Derived from lib/libc/gen/arc4random.c from FreeBSD. + */ +static size_t +getentropy_sysctl(u_char *buf, size_t size) +{ +	const int mib[2] = { CTL_KERN, KERN_ARND }; +	size_t len, done; + +	done = 0; + +	do { +		len = size; +		if (sysctl(mib, 2, buf, &len, NULL, 0) == -1) +			return (done); +		done += len; +		buf += len; +		size -= len; +	} while (size > 0); + +	return (done); +} + +int +getentropy(void *buf, size_t len) +{ +	if (len <= 256 && getentropy_sysctl(buf, len) == len) +		return (0); + +	errno = EIO; +	return (-1); +} diff --git a/ext/libressl/crypto/compat/getentropy_hpux.c b/ext/libressl/crypto/compat/getentropy_hpux.c new file mode 100644 index 0000000..c981880 --- /dev/null +++ b/ext/libressl/crypto/compat/getentropy_hpux.c @@ -0,0 +1,396 @@ +/*	$OpenBSD: getentropy_hpux.c,v 1.7 2020/05/17 14:44:20 deraadt Exp $	*/ + +/* + * Copyright (c) 2014 Theo de Raadt <deraadt@openbsd.org> + * Copyright (c) 2014 Bob Beck <beck@obtuse.com> + * + * 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. + * + * Emulation of getentropy(2) as documented at: + * http://man.openbsd.org/getentropy.2 + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/ioctl.h> +#include <sys/resource.h> +#include <sys/syscall.h> +#include <sys/statvfs.h> +#include <sys/socket.h> +#include <sys/mount.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> +#include <termios.h> +#include <fcntl.h> +#include <signal.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <time.h> +#include <openssl/sha.h> + +#include <sys/vfs.h> + +#include <sys/pstat.h> + +#define REPEAT 5 +#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) + +#define HX(a, b) \ +	do { \ +		if ((a)) \ +			HD(errno); \ +		else \ +			HD(b); \ +	} while (0) + +#define HR(x, l) (SHA512_Update(&ctx, (char *)(x), (l))) +#define HD(x)	 (SHA512_Update(&ctx, (char *)&(x), sizeof (x))) +#define HF(x)    (SHA512_Update(&ctx, (char *)&(x), sizeof (void*))) + +int	getentropy(void *buf, size_t len); + +static int getentropy_urandom(void *buf, size_t len, const char *path, +    int devfscheck); +static int getentropy_fallback(void *buf, size_t len); + +int +getentropy(void *buf, size_t len) +{ +	int ret = -1; + +	if (len > 256) { +		errno = EIO; +		return (-1); +	} + +	/* +	 * Try to get entropy with /dev/urandom +	 */ +	ret = getentropy_urandom(buf, len, "/dev/urandom", 0); +	if (ret != -1) +		return (ret); + +	/* +	 * Entropy collection via /dev/urandom has failed. +	 * +	 * No other API exists for collecting entropy, and we have +	 * no failsafe way to get it on hpux that is not sensitive +	 * to resource exhaustion. +	 * +	 * We have very few options: +	 *     - Even syslog_r is unsafe to call at this low level, so +	 *	 there is no way to alert the user or program. +	 *     - Cannot call abort() because some systems have unsafe +	 *	 corefiles. +	 *     - Could raise(SIGKILL) resulting in silent program termination. +	 *     - Return EIO, to hint that arc4random's stir function +	 *       should raise(SIGKILL) +	 *     - Do the best under the circumstances.... +	 * +	 * This code path exists to bring light to the issue that hpux  +	 * does not provide a failsafe API for entropy collection. +	 * +	 * We hope this demonstrates that hpux should consider +	 * providing a new failsafe API which works in a chroot or +	 * when file descriptors are exhausted. +	 */ +#undef FAIL_INSTEAD_OF_TRYING_FALLBACK +#ifdef FAIL_INSTEAD_OF_TRYING_FALLBACK +	raise(SIGKILL); +#endif +	ret = getentropy_fallback(buf, len); +	if (ret != -1) +		return (ret); + +	errno = EIO; +	return (ret); +} + +static int +getentropy_urandom(void *buf, size_t len, const char *path, int devfscheck) +{ +	struct stat st; +	size_t i; +	int fd, flags; +	int save_errno = errno; + +start: + +	flags = O_RDONLY; +#ifdef O_NOFOLLOW +	flags |= O_NOFOLLOW; +#endif +#ifdef O_CLOEXEC +	flags |= O_CLOEXEC; +#endif +	fd = open(path, flags, 0); +	if (fd == -1) { +		if (errno == EINTR) +			goto start; +		goto nodevrandom; +	} +#ifndef O_CLOEXEC +	fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); +#endif + +	/* Lightly verify that the device node looks sane */ +	if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode)) { +		close(fd); +		goto nodevrandom; +	} +	for (i = 0; i < len; ) { +		size_t wanted = len - i; +		ssize_t ret = read(fd, (char *)buf + i, wanted); + +		if (ret == -1) { +			if (errno == EAGAIN || errno == EINTR) +				continue; +			close(fd); +			goto nodevrandom; +		} +		i += ret; +	} +	close(fd); +	errno = save_errno; +	return (0);		/* satisfied */ +nodevrandom: +	errno = EIO; +	return (-1); +} + +static const int cl[] = { +	CLOCK_REALTIME, +#ifdef CLOCK_MONOTONIC +	CLOCK_MONOTONIC, +#endif +#ifdef CLOCK_MONOTONIC_RAW +	CLOCK_MONOTONIC_RAW, +#endif +#ifdef CLOCK_TAI +	CLOCK_TAI, +#endif +#ifdef CLOCK_VIRTUAL +	CLOCK_VIRTUAL, +#endif +#ifdef CLOCK_UPTIME +	CLOCK_UPTIME, +#endif +#ifdef CLOCK_PROCESS_CPUTIME_ID +	CLOCK_PROCESS_CPUTIME_ID, +#endif +#ifdef CLOCK_THREAD_CPUTIME_ID +	CLOCK_THREAD_CPUTIME_ID, +#endif +}; + +static int +getentropy_fallback(void *buf, size_t len) +{ +	uint8_t results[SHA512_DIGEST_LENGTH]; +	int save_errno = errno, e, pgs = sysconf(_SC_PAGESIZE), faster = 0, repeat; +	static int cnt; +	struct timespec ts; +	struct timeval tv; +	struct pst_vminfo pvi; +	struct pst_vm_status pvs; +	struct pst_dynamic pdy; +	struct rusage ru; +	sigset_t sigset; +	struct stat st; +	SHA512_CTX ctx; +	static pid_t lastpid; +	pid_t pid; +	size_t i, ii, m; +	char *p; + +	pid = getpid(); +	if (lastpid == pid) { +		faster = 1; +		repeat = 2; +	} else { +		faster = 0; +		lastpid = pid; +		repeat = REPEAT; +	} +	for (i = 0; i < len; ) { +		int j; +		SHA512_Init(&ctx); +		for (j = 0; j < repeat; j++) { +			HX((e = gettimeofday(&tv, NULL)) == -1, tv); +			if (e != -1) { +				cnt += (int)tv.tv_sec; +				cnt += (int)tv.tv_usec; +			} + +			HX(pstat_getvminfo(&pvi, sizeof(pvi), 1, 0) != 1, pvi); +			HX(pstat_getprocvm(&pvs, sizeof(pvs), 0, 0) != 1, pvs); + +			for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]); ii++) +				HX(clock_gettime(cl[ii], &ts) == -1, ts); + +			HX((pid = getpid()) == -1, pid); +			HX((pid = getsid(pid)) == -1, pid); +			HX((pid = getppid()) == -1, pid); +			HX((pid = getpgid(0)) == -1, pid); +			HX((e = getpriority(0, 0)) == -1, e); + +			if(pstat_getdynamic(&pdy, sizeof(pdy), 1, 0) != 1) { +				HD(errno); +			} else { +				HD(pdy.psd_avg_1_min); +				HD(pdy.psd_avg_5_min); +				HD(pdy.psd_avg_15_min); +			} + +			if (!faster) { +				ts.tv_sec = 0; +				ts.tv_nsec = 1; +				(void) nanosleep(&ts, NULL); +			} + +			HX(sigpending(&sigset) == -1, sigset); +			HX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1, +			    sigset); + +			HF(getentropy);	/* an addr in this library */ +			HF(printf);		/* an addr in libc */ +			p = (char *)&p; +			HD(p);		/* an addr on stack */ +			p = (char *)&errno; +			HD(p);		/* the addr of errno */ + +			if (i == 0) { +				struct sockaddr_storage ss; +				struct statvfs stvfs; +				struct termios tios; +				socklen_t ssl; +				off_t off; + +				/* +				 * Prime-sized mappings encourage fragmentation; +				 * thus exposing some address entropy. +				 */ +				struct mm { +					size_t	npg; +					void	*p; +				} mm[] =	 { +					{ 17, MAP_FAILED }, { 3, MAP_FAILED }, +					{ 11, MAP_FAILED }, { 2, MAP_FAILED }, +					{ 5, MAP_FAILED }, { 3, MAP_FAILED }, +					{ 7, MAP_FAILED }, { 1, MAP_FAILED }, +					{ 57, MAP_FAILED }, { 3, MAP_FAILED }, +					{ 131, MAP_FAILED }, { 1, MAP_FAILED }, +				}; + +				for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) { +					HX(mm[m].p = mmap(NULL, +					    mm[m].npg * pgs, +					    PROT_READ|PROT_WRITE, +					    MAP_PRIVATE|MAP_ANON, -1, +					    (off_t)0), mm[m].p); +					if (mm[m].p != MAP_FAILED) { +						size_t mo; + +						/* Touch some memory... */ +						p = mm[m].p; +						mo = cnt % +						    (mm[m].npg * pgs - 1); +						p[mo] = 1; +						cnt += (int)((long)(mm[m].p) +						    / pgs); +					} + +					/* Check cnts and times... */ +					for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]); +					    ii++) { +						HX((e = clock_gettime(cl[ii], +						    &ts)) == -1, ts); +						if (e != -1) +							cnt += (int)ts.tv_nsec; +					} + +					HX((e = getrusage(RUSAGE_SELF, +					    &ru)) == -1, ru); +					if (e != -1) { +						cnt += (int)ru.ru_utime.tv_sec; +						cnt += (int)ru.ru_utime.tv_usec; +					} +				} + +				for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) { +					if (mm[m].p != MAP_FAILED) +						munmap(mm[m].p, mm[m].npg * pgs); +					mm[m].p = MAP_FAILED; +				} + +				HX(stat(".", &st) == -1, st); +				HX(statvfs(".", &stvfs) == -1, stvfs); + +				HX(stat("/", &st) == -1, st); +				HX(statvfs("/", &stvfs) == -1, stvfs); + +				HX((e = fstat(0, &st)) == -1, st); +				if (e == -1) { +					if (S_ISREG(st.st_mode) || +					    S_ISFIFO(st.st_mode) || +					    S_ISSOCK(st.st_mode)) { +						HX(fstatvfs(0, &stvfs) == -1, +						    stvfs); +						HX((off = lseek(0, (off_t)0, +						    SEEK_CUR)) < 0, off); +					} +					if (S_ISCHR(st.st_mode)) { +						HX(tcgetattr(0, &tios) == -1, +						    tios); +					} else if (S_ISSOCK(st.st_mode)) { +						memset(&ss, 0, sizeof ss); +						ssl = sizeof(ss); +						HX(getpeername(0, +						    (void *)&ss, &ssl) == -1, +						    ss); +					} +				} + +				HX((e = getrusage(RUSAGE_CHILDREN, +				    &ru)) == -1, ru); +				if (e != -1) { +					cnt += (int)ru.ru_utime.tv_sec; +					cnt += (int)ru.ru_utime.tv_usec; +				} +			} else { +				/* Subsequent hashes absorb previous result */ +				HD(results); +			} + +			HX((e = gettimeofday(&tv, NULL)) == -1, tv); +			if (e != -1) { +				cnt += (int)tv.tv_sec; +				cnt += (int)tv.tv_usec; +			} + +			HD(cnt); +		} +		SHA512_Final(results, &ctx); +		memcpy((char *)buf + i, results, MINIMUM(sizeof(results), len - i)); +		i += MINIMUM(sizeof(results), len - i); +	} +	explicit_bzero(&ctx, sizeof ctx); +	explicit_bzero(results, sizeof results); +	errno = save_errno; +	return (0);		/* satisfied */ +} diff --git a/ext/libressl/crypto/compat/getentropy_linux.c b/ext/libressl/crypto/compat/getentropy_linux.c new file mode 100644 index 0000000..bc7a6be --- /dev/null +++ b/ext/libressl/crypto/compat/getentropy_linux.c @@ -0,0 +1,525 @@ +/*	$OpenBSD: getentropy_linux.c,v 1.47 2020/05/17 14:44:20 deraadt Exp $	*/ + +/* + * Copyright (c) 2014 Theo de Raadt <deraadt@openbsd.org> + * Copyright (c) 2014 Bob Beck <beck@obtuse.com> + * + * 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. + * + * Emulation of getentropy(2) as documented at: + * http://man.openbsd.org/getentropy.2 + */ + +#define	_POSIX_C_SOURCE	199309L +#define	_GNU_SOURCE	1 +#include <sys/types.h> +#include <sys/param.h> +#include <sys/ioctl.h> +#include <sys/resource.h> +#include <sys/syscall.h> +#ifdef SYS__sysctl +#include <linux/sysctl.h> +#endif +#include <sys/statvfs.h> +#include <sys/socket.h> +#include <sys/mount.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> +#include <link.h> +#include <termios.h> +#include <fcntl.h> +#include <signal.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <time.h> +#include <openssl/sha.h> + +#include <linux/types.h> +#include <linux/random.h> +#ifdef HAVE_GETAUXVAL +#include <sys/auxv.h> +#endif +#include <sys/vfs.h> + +#define REPEAT 5 +#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) + +#define HX(a, b) \ +	do { \ +		if ((a)) \ +			HD(errno); \ +		else \ +			HD(b); \ +	} while (0) + +#define HR(x, l) (SHA512_Update(&ctx, (char *)(x), (l))) +#define HD(x)	 (SHA512_Update(&ctx, (char *)&(x), sizeof (x))) +#define HF(x)    (SHA512_Update(&ctx, (char *)&(x), sizeof (void*))) + +int	getentropy(void *buf, size_t len); + +#if defined(SYS_getrandom) && defined(GRND_NONBLOCK) +static int getentropy_getrandom(void *buf, size_t len); +#endif +static int getentropy_urandom(void *buf, size_t len); +#ifdef SYS__sysctl +static int getentropy_sysctl(void *buf, size_t len); +#endif +static int getentropy_fallback(void *buf, size_t len); +static int getentropy_phdr(struct dl_phdr_info *info, size_t size, void *data); + +int +getentropy(void *buf, size_t len) +{ +	int ret = -1; + +	if (len > 256) { +		errno = EIO; +		return (-1); +	} + +#if defined(SYS_getrandom) && defined(GRND_NONBLOCK) +	/* +	 * Try descriptor-less getrandom(), in non-blocking mode. +	 * +	 * The design of Linux getrandom is broken.  It has an +	 * uninitialized phase coupled with blocking behaviour, which +	 * is unacceptable from within a library at boot time without +	 * possible recovery. See http://bugs.python.org/issue26839#msg267745 +	 */ +	ret = getentropy_getrandom(buf, len); +	if (ret != -1) +		return (ret); +#endif + +	/* +	 * Try to get entropy with /dev/urandom +	 * +	 * This can fail if the process is inside a chroot or if file +	 * descriptors are exhausted. +	 */ +	ret = getentropy_urandom(buf, len); +	if (ret != -1) +		return (ret); + +#ifdef SYS__sysctl +	/* +	 * Try to use sysctl CTL_KERN, KERN_RANDOM, RANDOM_UUID. +	 * sysctl is a failsafe API, so it guarantees a result.  This +	 * should work inside a chroot, or when file descriptors are +	 * exhausted. +	 * +	 * However this can fail if the Linux kernel removes support +	 * for sysctl.  Starting in 2007, there have been efforts to +	 * deprecate the sysctl API/ABI, and push callers towards use +	 * of the chroot-unavailable fd-using /proc mechanism -- +	 * essentially the same problems as /dev/urandom. +	 * +	 * Numerous setbacks have been encountered in their deprecation +	 * schedule, so as of June 2014 the kernel ABI still exists on +	 * most Linux architectures. The sysctl() stub in libc is missing +	 * on some systems.  There are also reports that some kernels +	 * spew messages to the console. +	 */ +	ret = getentropy_sysctl(buf, len); +	if (ret != -1) +		return (ret); +#endif /* SYS__sysctl */ + +	/* +	 * Entropy collection via /dev/urandom and sysctl have failed. +	 * +	 * No other API exists for collecting entropy.  See the large +	 * comment block above. +	 * +	 * We have very few options: +	 *     - Even syslog_r is unsafe to call at this low level, so +	 *	 there is no way to alert the user or program. +	 *     - Cannot call abort() because some systems have unsafe +	 *	 corefiles. +	 *     - Could raise(SIGKILL) resulting in silent program termination. +	 *     - Return EIO, to hint that arc4random's stir function +	 *       should raise(SIGKILL) +	 *     - Do the best under the circumstances.... +	 * +	 * This code path exists to bring light to the issue that Linux +	 * still does not provide a failsafe API for entropy collection. +	 * +	 * We hope this demonstrates that Linux should either retain their +	 * sysctl ABI, or consider providing a new failsafe API which +	 * works in a chroot or when file descriptors are exhausted. +	 */ +#undef FAIL_INSTEAD_OF_TRYING_FALLBACK +#ifdef FAIL_INSTEAD_OF_TRYING_FALLBACK +	raise(SIGKILL); +#endif +	ret = getentropy_fallback(buf, len); +	if (ret != -1) +		return (ret); + +	errno = EIO; +	return (ret); +} + +#if defined(SYS_getrandom) && defined(GRND_NONBLOCK) +static int +getentropy_getrandom(void *buf, size_t len) +{ +	int pre_errno = errno; +	int ret; +	if (len > 256) +		return (-1); +	do { +		ret = syscall(SYS_getrandom, buf, len, GRND_NONBLOCK); +	} while (ret == -1 && errno == EINTR); + +	if (ret != len) +		return (-1); +	errno = pre_errno; +	return (0); +} +#endif + +static int +getentropy_urandom(void *buf, size_t len) +{ +	struct stat st; +	size_t i; +	int fd, cnt, flags; +	int save_errno = errno; + +start: + +	flags = O_RDONLY; +#ifdef O_NOFOLLOW +	flags |= O_NOFOLLOW; +#endif +#ifdef O_CLOEXEC +	flags |= O_CLOEXEC; +#endif +	fd = open("/dev/urandom", flags, 0); +	if (fd == -1) { +		if (errno == EINTR) +			goto start; +		goto nodevrandom; +	} +#ifndef O_CLOEXEC +	fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); +#endif + +	/* Lightly verify that the device node looks sane */ +	if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode)) { +		close(fd); +		goto nodevrandom; +	} +	if (ioctl(fd, RNDGETENTCNT, &cnt) == -1) { +		close(fd); +		goto nodevrandom; +	} +	for (i = 0; i < len; ) { +		size_t wanted = len - i; +		ssize_t ret = read(fd, (char *)buf + i, wanted); + +		if (ret == -1) { +			if (errno == EAGAIN || errno == EINTR) +				continue; +			close(fd); +			goto nodevrandom; +		} +		i += ret; +	} +	close(fd); +	errno = save_errno; +	return (0);		/* satisfied */ +nodevrandom: +	errno = EIO; +	return (-1); +} + +#ifdef SYS__sysctl +static int +getentropy_sysctl(void *buf, size_t len) +{ +	static int mib[] = { CTL_KERN, KERN_RANDOM, RANDOM_UUID }; +	size_t i; +	int save_errno = errno; + +	for (i = 0; i < len; ) { +		size_t chunk = MINIMUM(len - i, 16); + +		/* SYS__sysctl because some systems already removed sysctl() */ +		struct __sysctl_args args = { +			.name = mib, +			.nlen = 3, +			.oldval = (char *)buf + i, +			.oldlenp = &chunk, +		}; +		if (syscall(SYS__sysctl, &args) != 0) +			goto sysctlfailed; +		i += chunk; +	} +	errno = save_errno; +	return (0);			/* satisfied */ +sysctlfailed: +	errno = EIO; +	return (-1); +} +#endif /* SYS__sysctl */ + +static const int cl[] = { +	CLOCK_REALTIME, +#ifdef CLOCK_MONOTONIC +	CLOCK_MONOTONIC, +#endif +#ifdef CLOCK_MONOTONIC_RAW +	CLOCK_MONOTONIC_RAW, +#endif +#ifdef CLOCK_TAI +	CLOCK_TAI, +#endif +#ifdef CLOCK_VIRTUAL +	CLOCK_VIRTUAL, +#endif +#ifdef CLOCK_UPTIME +	CLOCK_UPTIME, +#endif +#ifdef CLOCK_PROCESS_CPUTIME_ID +	CLOCK_PROCESS_CPUTIME_ID, +#endif +#ifdef CLOCK_THREAD_CPUTIME_ID +	CLOCK_THREAD_CPUTIME_ID, +#endif +}; + +static int +getentropy_phdr(struct dl_phdr_info *info, size_t size, void *data) +{ +	SHA512_CTX *ctx = data; + +	SHA512_Update(ctx, &info->dlpi_addr, sizeof (info->dlpi_addr)); +	return (0); +} + +static int +getentropy_fallback(void *buf, size_t len) +{ +	uint8_t results[SHA512_DIGEST_LENGTH]; +	int save_errno = errno, e, pgs = getpagesize(), faster = 0, repeat; +	static int cnt; +	struct timespec ts; +	struct timeval tv; +	struct rusage ru; +	sigset_t sigset; +	struct stat st; +	SHA512_CTX ctx; +	static pid_t lastpid; +	pid_t pid; +	size_t i, ii, m; +	char *p; + +	pid = getpid(); +	if (lastpid == pid) { +		faster = 1; +		repeat = 2; +	} else { +		faster = 0; +		lastpid = pid; +		repeat = REPEAT; +	} +	for (i = 0; i < len; ) { +		int j; +		SHA512_Init(&ctx); +		for (j = 0; j < repeat; j++) { +			HX((e = gettimeofday(&tv, NULL)) == -1, tv); +			if (e != -1) { +				cnt += (int)tv.tv_sec; +				cnt += (int)tv.tv_usec; +			} + +			dl_iterate_phdr(getentropy_phdr, &ctx); + +			for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]); ii++) +				HX(clock_gettime(cl[ii], &ts) == -1, ts); + +			HX((pid = getpid()) == -1, pid); +			HX((pid = getsid(pid)) == -1, pid); +			HX((pid = getppid()) == -1, pid); +			HX((pid = getpgid(0)) == -1, pid); +			HX((e = getpriority(0, 0)) == -1, e); + +			if (!faster) { +				ts.tv_sec = 0; +				ts.tv_nsec = 1; +				(void) nanosleep(&ts, NULL); +			} + +			HX(sigpending(&sigset) == -1, sigset); +			HX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1, +			    sigset); + +			HF(getentropy);	/* an addr in this library */ +			HF(printf);		/* an addr in libc */ +			p = (char *)&p; +			HD(p);		/* an addr on stack */ +			p = (char *)&errno; +			HD(p);		/* the addr of errno */ + +			if (i == 0) { +				struct sockaddr_storage ss; +				struct statvfs stvfs; +				struct termios tios; +				struct statfs stfs; +				socklen_t ssl; +				off_t off; + +				/* +				 * Prime-sized mappings encourage fragmentation; +				 * thus exposing some address entropy. +				 */ +				struct mm { +					size_t	npg; +					void	*p; +				} mm[] =	 { +					{ 17, MAP_FAILED }, { 3, MAP_FAILED }, +					{ 11, MAP_FAILED }, { 2, MAP_FAILED }, +					{ 5, MAP_FAILED }, { 3, MAP_FAILED }, +					{ 7, MAP_FAILED }, { 1, MAP_FAILED }, +					{ 57, MAP_FAILED }, { 3, MAP_FAILED }, +					{ 131, MAP_FAILED }, { 1, MAP_FAILED }, +				}; + +				for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) { +					HX(mm[m].p = mmap(NULL, +					    mm[m].npg * pgs, +					    PROT_READ|PROT_WRITE, +					    MAP_PRIVATE|MAP_ANON, -1, +					    (off_t)0), mm[m].p); +					if (mm[m].p != MAP_FAILED) { +						size_t mo; + +						/* Touch some memory... */ +						p = mm[m].p; +						mo = cnt % +						    (mm[m].npg * pgs - 1); +						p[mo] = 1; +						cnt += (int)((long)(mm[m].p) +						    / pgs); +					} + +					/* Check cnts and times... */ +					for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]); +					    ii++) { +						HX((e = clock_gettime(cl[ii], +						    &ts)) == -1, ts); +						if (e != -1) +							cnt += (int)ts.tv_nsec; +					} + +					HX((e = getrusage(RUSAGE_SELF, +					    &ru)) == -1, ru); +					if (e != -1) { +						cnt += (int)ru.ru_utime.tv_sec; +						cnt += (int)ru.ru_utime.tv_usec; +					} +				} + +				for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) { +					if (mm[m].p != MAP_FAILED) +						munmap(mm[m].p, mm[m].npg * pgs); +					mm[m].p = MAP_FAILED; +				} + +				HX(stat(".", &st) == -1, st); +				HX(statvfs(".", &stvfs) == -1, stvfs); +				HX(statfs(".", &stfs) == -1, stfs); + +				HX(stat("/", &st) == -1, st); +				HX(statvfs("/", &stvfs) == -1, stvfs); +				HX(statfs("/", &stfs) == -1, stfs); + +				HX((e = fstat(0, &st)) == -1, st); +				if (e == -1) { +					if (S_ISREG(st.st_mode) || +					    S_ISFIFO(st.st_mode) || +					    S_ISSOCK(st.st_mode)) { +						HX(fstatvfs(0, &stvfs) == -1, +						    stvfs); +						HX(fstatfs(0, &stfs) == -1, +						    stfs); +						HX((off = lseek(0, (off_t)0, +						    SEEK_CUR)) < 0, off); +					} +					if (S_ISCHR(st.st_mode)) { +						HX(tcgetattr(0, &tios) == -1, +						    tios); +					} else if (S_ISSOCK(st.st_mode)) { +						memset(&ss, 0, sizeof ss); +						ssl = sizeof(ss); +						HX(getpeername(0, +						    (void *)&ss, &ssl) == -1, +						    ss); +					} +				} + +				HX((e = getrusage(RUSAGE_CHILDREN, +				    &ru)) == -1, ru); +				if (e != -1) { +					cnt += (int)ru.ru_utime.tv_sec; +					cnt += (int)ru.ru_utime.tv_usec; +				} +			} else { +				/* Subsequent hashes absorb previous result */ +				HD(results); +			} + +			HX((e = gettimeofday(&tv, NULL)) == -1, tv); +			if (e != -1) { +				cnt += (int)tv.tv_sec; +				cnt += (int)tv.tv_usec; +			} + +			HD(cnt); +		} +#ifdef HAVE_GETAUXVAL +#ifdef AT_RANDOM +		/* Not as random as you think but we take what we are given */ +		p = (char *) getauxval(AT_RANDOM); +		if (p) +			HR(p, 16); +#endif +#ifdef AT_SYSINFO_EHDR +		p = (char *) getauxval(AT_SYSINFO_EHDR); +		if (p) +			HR(p, pgs); +#endif +#ifdef AT_BASE +		p = (char *) getauxval(AT_BASE); +		if (p) +			HD(p); +#endif +#endif + +		SHA512_Final(results, &ctx); +		memcpy((char *)buf + i, results, MINIMUM(sizeof(results), len - i)); +		i += MINIMUM(sizeof(results), len - i); +	} +	explicit_bzero(&ctx, sizeof ctx); +	explicit_bzero(results, sizeof results); +	errno = save_errno; +	return (0);		/* satisfied */ +} diff --git a/ext/libressl/crypto/compat/getentropy_netbsd.c b/ext/libressl/crypto/compat/getentropy_netbsd.c new file mode 100644 index 0000000..5dc8959 --- /dev/null +++ b/ext/libressl/crypto/compat/getentropy_netbsd.c @@ -0,0 +1,62 @@ +/*	$OpenBSD: getentropy_netbsd.c,v 1.4 2020/10/12 22:08:33 deraadt Exp $	*/ + +/* + * Copyright (c) 2014 Pawel Jakub Dawidek <pjd@FreeBSD.org> + * Copyright (c) 2014 Brent Cook <bcook@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. + * + * Emulation of getentropy(2) as documented at: + * http://man.openbsd.org/getentropy.2 + */ + +#include <sys/types.h> +#include <sys/sysctl.h> + +#include <errno.h> +#include <stddef.h> + +/* + * Derived from lib/libc/gen/arc4random.c from FreeBSD. + */ +static size_t +getentropy_sysctl(u_char *buf, size_t size) +{ +	const int mib[2] = { CTL_KERN, KERN_ARND }; +	size_t len, done; + +	done = 0; + +	do { +		len = size; +		if (sysctl(mib, 2, buf, &len, NULL, 0) == -1) +			return (done); +		done += len; +		buf += len; +		size -= len; +	} while (size > 0); + +	return (done); +} + +int +getentropy(void *buf, size_t len) +{ +	if (len <= 256 && +	    getentropy_sysctl(buf, len) == len) { +		return (0); +	} + +	errno = EIO; +	return (-1); +} diff --git a/ext/libressl/crypto/compat/getentropy_osx.c b/ext/libressl/crypto/compat/getentropy_osx.c new file mode 100644 index 0000000..5d4067b --- /dev/null +++ b/ext/libressl/crypto/compat/getentropy_osx.c @@ -0,0 +1,417 @@ +/*	$OpenBSD: getentropy_osx.c,v 1.13 2020/05/17 14:44:20 deraadt Exp $	*/ + +/* + * Copyright (c) 2014 Theo de Raadt <deraadt@openbsd.org> + * Copyright (c) 2014 Bob Beck <beck@obtuse.com> + * + * 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. + * + * Emulation of getentropy(2) as documented at: + * http://man.openbsd.org/getentropy.2 + */ + +#include <TargetConditionals.h> +#include <sys/types.h> +#include <sys/param.h> +#include <sys/ioctl.h> +#include <sys/resource.h> +#include <sys/syscall.h> +#include <sys/sysctl.h> +#include <sys/statvfs.h> +#include <sys/socket.h> +#include <sys/mount.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> +#include <termios.h> +#include <fcntl.h> +#include <signal.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <time.h> +#include <mach/mach_time.h> +#include <mach/mach_host.h> +#include <mach/host_info.h> +#if TARGET_OS_OSX +#include <sys/socketvar.h> +#include <sys/vmmeter.h> +#endif +#include <netinet/in.h> +#include <netinet/tcp.h> +#if TARGET_OS_OSX +#include <netinet/udp.h> +#include <netinet/ip_var.h> +#include <netinet/tcp_var.h> +#include <netinet/udp_var.h> +#endif +#include <CommonCrypto/CommonDigest.h> +#define SHA512_Update(a, b, c)	(CC_SHA512_Update((a), (b), (c))) +#define SHA512_Init(xxx) (CC_SHA512_Init((xxx))) +#define SHA512_Final(xxx, yyy) (CC_SHA512_Final((xxx), (yyy))) +#define SHA512_CTX CC_SHA512_CTX +#define SHA512_DIGEST_LENGTH CC_SHA512_DIGEST_LENGTH + +#define REPEAT 5 +#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) + +#define HX(a, b) \ +	do { \ +		if ((a)) \ +			HD(errno); \ +		else \ +			HD(b); \ +	} while (0) + +#define HR(x, l) (SHA512_Update(&ctx, (char *)(x), (l))) +#define HD(x)	 (SHA512_Update(&ctx, (char *)&(x), sizeof (x))) +#define HF(x)    (SHA512_Update(&ctx, (char *)&(x), sizeof (void*))) + +int	getentropy(void *buf, size_t len); + +static int getentropy_urandom(void *buf, size_t len); +static int getentropy_fallback(void *buf, size_t len); + +int +getentropy(void *buf, size_t len) +{ +	int ret = -1; + +	if (len > 256) { +		errno = EIO; +		return (-1); +	} + +	/* +	 * Try to get entropy with /dev/urandom +	 * +	 * This can fail if the process is inside a chroot or if file +	 * descriptors are exhausted. +	 */ +	ret = getentropy_urandom(buf, len); +	if (ret != -1) +		return (ret); + +	/* +	 * Entropy collection via /dev/urandom and sysctl have failed. +	 * +	 * No other API exists for collecting entropy, and we have +	 * no failsafe way to get it on OSX that is not sensitive +	 * to resource exhaustion. +	 * +	 * We have very few options: +	 *     - Even syslog_r is unsafe to call at this low level, so +	 *	 there is no way to alert the user or program. +	 *     - Cannot call abort() because some systems have unsafe +	 *	 corefiles. +	 *     - Could raise(SIGKILL) resulting in silent program termination. +	 *     - Return EIO, to hint that arc4random's stir function +	 *       should raise(SIGKILL) +	 *     - Do the best under the circumstances.... +	 * +	 * This code path exists to bring light to the issue that OSX +	 * does not provide a failsafe API for entropy collection. +	 * +	 * We hope this demonstrates that OSX should consider +	 * providing a new failsafe API which works in a chroot or +	 * when file descriptors are exhausted. +	 */ +#undef FAIL_INSTEAD_OF_TRYING_FALLBACK +#ifdef FAIL_INSTEAD_OF_TRYING_FALLBACK +	raise(SIGKILL); +#endif +	ret = getentropy_fallback(buf, len); +	if (ret != -1) +		return (ret); + +	errno = EIO; +	return (ret); +} + +static int +getentropy_urandom(void *buf, size_t len) +{ +	struct stat st; +	size_t i; +	int fd, flags; +	int save_errno = errno; + +start: + +	flags = O_RDONLY; +#ifdef O_NOFOLLOW +	flags |= O_NOFOLLOW; +#endif +#ifdef O_CLOEXEC +	flags |= O_CLOEXEC; +#endif +	fd = open("/dev/urandom", flags, 0); +	if (fd == -1) { +		if (errno == EINTR) +			goto start; +		goto nodevrandom; +	} +#ifndef O_CLOEXEC +	fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); +#endif + +	/* Lightly verify that the device node looks sane */ +	if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode)) { +		close(fd); +		goto nodevrandom; +	} +	for (i = 0; i < len; ) { +		size_t wanted = len - i; +		ssize_t ret = read(fd, (char *)buf + i, wanted); + +		if (ret == -1) { +			if (errno == EAGAIN || errno == EINTR) +				continue; +			close(fd); +			goto nodevrandom; +		} +		i += ret; +	} +	close(fd); +	errno = save_errno; +	return (0);		/* satisfied */ +nodevrandom: +	errno = EIO; +	return (-1); +} + +#if TARGET_OS_OSX +static int tcpmib[] = { CTL_NET, AF_INET, IPPROTO_TCP, TCPCTL_STATS }; +static int udpmib[] = { CTL_NET, AF_INET, IPPROTO_UDP, UDPCTL_STATS }; +static int ipmib[] = { CTL_NET, AF_INET, IPPROTO_IP, IPCTL_STATS }; +#endif +static int kmib[] = { CTL_KERN, KERN_USRSTACK }; +static int hwmib[] = { CTL_HW, HW_USERMEM }; + +static int +getentropy_fallback(void *buf, size_t len) +{ +	uint8_t results[SHA512_DIGEST_LENGTH]; +	int save_errno = errno, e, pgs = getpagesize(), faster = 0, repeat; +	static int cnt; +	struct timespec ts; +	struct timeval tv; +	struct rusage ru; +	sigset_t sigset; +	struct stat st; +	SHA512_CTX ctx; +	static pid_t lastpid; +	pid_t pid; +	size_t i, ii, m; +	char *p; +#if TARGET_OS_OSX +	struct tcpstat tcpstat; +	struct udpstat udpstat; +	struct ipstat ipstat; +#endif +	u_int64_t mach_time; +	unsigned int idata; +	void *addr; + +	pid = getpid(); +	if (lastpid == pid) { +		faster = 1; +		repeat = 2; +	} else { +		faster = 0; +		lastpid = pid; +		repeat = REPEAT; +	} +	for (i = 0; i < len; ) { +		int j; +		SHA512_Init(&ctx); +		for (j = 0; j < repeat; j++) { +			HX((e = gettimeofday(&tv, NULL)) == -1, tv); +			if (e != -1) { +				cnt += (int)tv.tv_sec; +				cnt += (int)tv.tv_usec; +			} + +			mach_time = mach_absolute_time(); +			HD(mach_time); + +			ii = sizeof(addr); +			HX(sysctl(kmib, sizeof(kmib) / sizeof(kmib[0]), +			    &addr, &ii, NULL, 0) == -1, addr); + +			ii = sizeof(idata); +			HX(sysctl(hwmib, sizeof(hwmib) / sizeof(hwmib[0]), +			    &idata, &ii, NULL, 0) == -1, idata); + +#if TARGET_OS_OSX +			ii = sizeof(tcpstat); +			HX(sysctl(tcpmib, sizeof(tcpmib) / sizeof(tcpmib[0]), +			    &tcpstat, &ii, NULL, 0) == -1, tcpstat); + +			ii = sizeof(udpstat); +			HX(sysctl(udpmib, sizeof(udpmib) / sizeof(udpmib[0]), +			    &udpstat, &ii, NULL, 0) == -1, udpstat); + +			ii = sizeof(ipstat); +			HX(sysctl(ipmib, sizeof(ipmib) / sizeof(ipmib[0]), +			    &ipstat, &ii, NULL, 0) == -1, ipstat); +#endif + +			HX((pid = getpid()) == -1, pid); +			HX((pid = getsid(pid)) == -1, pid); +			HX((pid = getppid()) == -1, pid); +			HX((pid = getpgid(0)) == -1, pid); +			HX((e = getpriority(0, 0)) == -1, e); + +			if (!faster) { +				ts.tv_sec = 0; +				ts.tv_nsec = 1; +				(void) nanosleep(&ts, NULL); +			} + +			HX(sigpending(&sigset) == -1, sigset); +			HX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1, +			    sigset); + +			HF(getentropy);	/* an addr in this library */ +			HF(printf);		/* an addr in libc */ +			p = (char *)&p; +			HD(p);		/* an addr on stack */ +			p = (char *)&errno; +			HD(p);		/* the addr of errno */ + +			if (i == 0) { +				struct sockaddr_storage ss; +				struct statvfs stvfs; +				struct termios tios; +				struct statfs stfs; +				socklen_t ssl; +				off_t off; + +				/* +				 * Prime-sized mappings encourage fragmentation; +				 * thus exposing some address entropy. +				 */ +				struct mm { +					size_t	npg; +					void	*p; +				} mm[] =	 { +					{ 17, MAP_FAILED }, { 3, MAP_FAILED }, +					{ 11, MAP_FAILED }, { 2, MAP_FAILED }, +					{ 5, MAP_FAILED }, { 3, MAP_FAILED }, +					{ 7, MAP_FAILED }, { 1, MAP_FAILED }, +					{ 57, MAP_FAILED }, { 3, MAP_FAILED }, +					{ 131, MAP_FAILED }, { 1, MAP_FAILED }, +				}; + +				for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) { +					HX(mm[m].p = mmap(NULL, +					    mm[m].npg * pgs, +					    PROT_READ|PROT_WRITE, +					    MAP_PRIVATE|MAP_ANON, -1, +					    (off_t)0), mm[m].p); +					if (mm[m].p != MAP_FAILED) { +						size_t mo; + +						/* Touch some memory... */ +						p = mm[m].p; +						mo = cnt % +						    (mm[m].npg * pgs - 1); +						p[mo] = 1; +						cnt += (int)((long)(mm[m].p) +						    / pgs); +					} + +					/* Check cnts and times... */ +					mach_time = mach_absolute_time(); +					HD(mach_time); +					cnt += (int)mach_time; + +					HX((e = getrusage(RUSAGE_SELF, +					    &ru)) == -1, ru); +					if (e != -1) { +						cnt += (int)ru.ru_utime.tv_sec; +						cnt += (int)ru.ru_utime.tv_usec; +					} +				} + +				for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) { +					if (mm[m].p != MAP_FAILED) +						munmap(mm[m].p, mm[m].npg * pgs); +					mm[m].p = MAP_FAILED; +				} + +				HX(stat(".", &st) == -1, st); +				HX(statvfs(".", &stvfs) == -1, stvfs); +				HX(statfs(".", &stfs) == -1, stfs); + +				HX(stat("/", &st) == -1, st); +				HX(statvfs("/", &stvfs) == -1, stvfs); +				HX(statfs("/", &stfs) == -1, stfs); + +				HX((e = fstat(0, &st)) == -1, st); +				if (e == -1) { +					if (S_ISREG(st.st_mode) || +					    S_ISFIFO(st.st_mode) || +					    S_ISSOCK(st.st_mode)) { +						HX(fstatvfs(0, &stvfs) == -1, +						    stvfs); +						HX(fstatfs(0, &stfs) == -1, +						    stfs); +						HX((off = lseek(0, (off_t)0, +						    SEEK_CUR)) < 0, off); +					} +					if (S_ISCHR(st.st_mode)) { +						HX(tcgetattr(0, &tios) == -1, +						    tios); +					} else if (S_ISSOCK(st.st_mode)) { +						memset(&ss, 0, sizeof ss); +						ssl = sizeof(ss); +						HX(getpeername(0, +						    (void *)&ss, &ssl) == -1, +						    ss); +					} +				} + +				HX((e = getrusage(RUSAGE_CHILDREN, +				    &ru)) == -1, ru); +				if (e != -1) { +					cnt += (int)ru.ru_utime.tv_sec; +					cnt += (int)ru.ru_utime.tv_usec; +				} +			} else { +				/* Subsequent hashes absorb previous result */ +				HD(results); +			} + +			HX((e = gettimeofday(&tv, NULL)) == -1, tv); +			if (e != -1) { +				cnt += (int)tv.tv_sec; +				cnt += (int)tv.tv_usec; +			} + +			HD(cnt); +		} + +		SHA512_Final(results, &ctx); +		memcpy((char *)buf + i, results, MINIMUM(sizeof(results), len - i)); +		i += MINIMUM(sizeof(results), len - i); +	} +	explicit_bzero(&ctx, sizeof ctx); +	explicit_bzero(results, sizeof results); +	errno = save_errno; +	return (0);		/* satisfied */ +} diff --git a/ext/libressl/crypto/compat/getentropy_solaris.c b/ext/libressl/crypto/compat/getentropy_solaris.c new file mode 100644 index 0000000..cf5b9bf --- /dev/null +++ b/ext/libressl/crypto/compat/getentropy_solaris.c @@ -0,0 +1,422 @@ +/*	$OpenBSD: getentropy_solaris.c,v 1.14 2020/05/17 14:44:20 deraadt Exp $	*/ + +/* + * Copyright (c) 2014 Theo de Raadt <deraadt@openbsd.org> + * Copyright (c) 2014 Bob Beck <beck@obtuse.com> + * + * 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. + * + * Emulation of getentropy(2) as documented at: + * http://man.openbsd.org/getentropy.2 + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/ioctl.h> +#include <sys/resource.h> +#include <sys/syscall.h> +#include <sys/statvfs.h> +#include <sys/socket.h> +#include <sys/mount.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> +#include <link.h> +#include <termios.h> +#include <fcntl.h> +#include <signal.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <time.h> +#include <sys/sha2.h> +#define SHA512_Init SHA512Init +#define SHA512_Update SHA512Update +#define SHA512_Final SHA512Final + +#include <sys/vfs.h> +#include <sys/statfs.h> +#include <sys/loadavg.h> + +#define REPEAT 5 +#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) + +#define HX(a, b) \ +	do { \ +		if ((a)) \ +			HD(errno); \ +		else \ +			HD(b); \ +	} while (0) + +#define HR(x, l) (SHA512_Update(&ctx, (char *)(x), (l))) +#define HD(x)	 (SHA512_Update(&ctx, (char *)&(x), sizeof (x))) +#define HF(x)    (SHA512_Update(&ctx, (char *)&(x), sizeof (void*))) + +int	getentropy(void *buf, size_t len); + +static int getentropy_urandom(void *buf, size_t len, const char *path, +    int devfscheck); +static int getentropy_fallback(void *buf, size_t len); +static int getentropy_phdr(struct dl_phdr_info *info, size_t size, void *data); + +int +getentropy(void *buf, size_t len) +{ +	int ret = -1; + +	if (len > 256) { +		errno = EIO; +		return (-1); +	} + +	/* +	 * Try to get entropy with /dev/urandom +	 * +	 * Solaris provides /dev/urandom as a symbolic link to +	 * /devices/pseudo/random@0:urandom which is provided by +	 * a devfs filesystem.  Best practice is to use O_NOFOLLOW, +	 * so we must try the unpublished name directly. +	 * +	 * This can fail if the process is inside a chroot which lacks +	 * the devfs mount, or if file descriptors are exhausted. +	 */ +	ret = getentropy_urandom(buf, len, +	    "/devices/pseudo/random@0:urandom", 1); +	if (ret != -1) +		return (ret); + +	/* +	 * Unfortunately, chroot spaces on Solaris are sometimes setup +	 * with direct device node of the well-known /dev/urandom name +	 * (perhaps to avoid dragging all of devfs into the space). +	 * +	 * This can fail if the process is inside a chroot or if file +	 * descriptors are exhausted. +	 */ +	ret = getentropy_urandom(buf, len, "/dev/urandom", 0); +	if (ret != -1) +		return (ret); + +	/* +	 * Entropy collection via /dev/urandom has failed. +	 * +	 * No other API exists for collecting entropy, and we have +	 * no failsafe way to get it on Solaris that is not sensitive +	 * to resource exhaustion. +	 * +	 * We have very few options: +	 *     - Even syslog_r is unsafe to call at this low level, so +	 *	 there is no way to alert the user or program. +	 *     - Cannot call abort() because some systems have unsafe +	 *	 corefiles. +	 *     - Could raise(SIGKILL) resulting in silent program termination. +	 *     - Return EIO, to hint that arc4random's stir function +	 *       should raise(SIGKILL) +	 *     - Do the best under the circumstances.... +	 * +	 * This code path exists to bring light to the issue that Solaris +	 * does not provide a failsafe API for entropy collection. +	 * +	 * We hope this demonstrates that Solaris should consider +	 * providing a new failsafe API which works in a chroot or +	 * when file descriptors are exhausted. +	 */ +#undef FAIL_INSTEAD_OF_TRYING_FALLBACK +#ifdef FAIL_INSTEAD_OF_TRYING_FALLBACK +	raise(SIGKILL); +#endif +	ret = getentropy_fallback(buf, len); +	if (ret != -1) +		return (ret); + +	errno = EIO; +	return (ret); +} + +static int +getentropy_urandom(void *buf, size_t len, const char *path, int devfscheck) +{ +	struct stat st; +	size_t i; +	int fd, flags; +	int save_errno = errno; + +start: + +	flags = O_RDONLY; +#ifdef O_NOFOLLOW +	flags |= O_NOFOLLOW; +#endif +#ifdef O_CLOEXEC +	flags |= O_CLOEXEC; +#endif +	fd = open(path, flags, 0); +	if (fd == -1) { +		if (errno == EINTR) +			goto start; +		goto nodevrandom; +	} +#ifndef O_CLOEXEC +	fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); +#endif + +	/* Lightly verify that the device node looks sane */ +	if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode) || +	    (devfscheck && (strcmp(st.st_fstype, "devfs") != 0))) { +		close(fd); +		goto nodevrandom; +	} +	for (i = 0; i < len; ) { +		size_t wanted = len - i; +		ssize_t ret = read(fd, (char *)buf + i, wanted); + +		if (ret == -1) { +			if (errno == EAGAIN || errno == EINTR) +				continue; +			close(fd); +			goto nodevrandom; +		} +		i += ret; +	} +	close(fd); +	errno = save_errno; +	return (0);		/* satisfied */ +nodevrandom: +	errno = EIO; +	return (-1); +} + +static const int cl[] = { +	CLOCK_REALTIME, +#ifdef CLOCK_MONOTONIC +	CLOCK_MONOTONIC, +#endif +#ifdef CLOCK_MONOTONIC_RAW +	CLOCK_MONOTONIC_RAW, +#endif +#ifdef CLOCK_TAI +	CLOCK_TAI, +#endif +#ifdef CLOCK_VIRTUAL +	CLOCK_VIRTUAL, +#endif +#ifdef CLOCK_UPTIME +	CLOCK_UPTIME, +#endif +#ifdef CLOCK_PROCESS_CPUTIME_ID +	CLOCK_PROCESS_CPUTIME_ID, +#endif +#ifdef CLOCK_THREAD_CPUTIME_ID +	CLOCK_THREAD_CPUTIME_ID, +#endif +}; + +static int +getentropy_phdr(struct dl_phdr_info *info, size_t size, void *data) +{ +	SHA512_CTX *ctx = data; + +	SHA512_Update(ctx, &info->dlpi_addr, sizeof (info->dlpi_addr)); +	return (0); +} + +static int +getentropy_fallback(void *buf, size_t len) +{ +	uint8_t results[SHA512_DIGEST_LENGTH]; +	int save_errno = errno, e, pgs = getpagesize(), faster = 0, repeat; +	static int cnt; +	struct timespec ts; +	struct timeval tv; +	double loadavg[3]; +	struct rusage ru; +	sigset_t sigset; +	struct stat st; +	SHA512_CTX ctx; +	static pid_t lastpid; +	pid_t pid; +	size_t i, ii, m; +	char *p; + +	pid = getpid(); +	if (lastpid == pid) { +		faster = 1; +		repeat = 2; +	} else { +		faster = 0; +		lastpid = pid; +		repeat = REPEAT; +	} +	for (i = 0; i < len; ) { +		int j; +		SHA512_Init(&ctx); +		for (j = 0; j < repeat; j++) { +			HX((e = gettimeofday(&tv, NULL)) == -1, tv); +			if (e != -1) { +				cnt += (int)tv.tv_sec; +				cnt += (int)tv.tv_usec; +			} + +			dl_iterate_phdr(getentropy_phdr, &ctx); + +			for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]); ii++) +				HX(clock_gettime(cl[ii], &ts) == -1, ts); + +			HX((pid = getpid()) == -1, pid); +			HX((pid = getsid(pid)) == -1, pid); +			HX((pid = getppid()) == -1, pid); +			HX((pid = getpgid(0)) == -1, pid); +			HX((e = getpriority(0, 0)) == -1, e); +			HX((getloadavg(loadavg, 3) == -1), loadavg); + +			if (!faster) { +				ts.tv_sec = 0; +				ts.tv_nsec = 1; +				(void) nanosleep(&ts, NULL); +			} + +			HX(sigpending(&sigset) == -1, sigset); +			HX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1, +			    sigset); + +			HF(getentropy);	/* an addr in this library */ +			HF(printf);		/* an addr in libc */ +			p = (char *)&p; +			HD(p);		/* an addr on stack */ +			p = (char *)&errno; +			HD(p);		/* the addr of errno */ + +			if (i == 0) { +				struct sockaddr_storage ss; +				struct statvfs stvfs; +				struct termios tios; +				socklen_t ssl; +				off_t off; + +				/* +				 * Prime-sized mappings encourage fragmentation; +				 * thus exposing some address entropy. +				 */ +				struct mm { +					size_t	npg; +					void	*p; +				} mm[] =	 { +					{ 17, MAP_FAILED }, { 3, MAP_FAILED }, +					{ 11, MAP_FAILED }, { 2, MAP_FAILED }, +					{ 5, MAP_FAILED }, { 3, MAP_FAILED }, +					{ 7, MAP_FAILED }, { 1, MAP_FAILED }, +					{ 57, MAP_FAILED }, { 3, MAP_FAILED }, +					{ 131, MAP_FAILED }, { 1, MAP_FAILED }, +				}; + +				for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) { +					HX(mm[m].p = mmap(NULL, +					    mm[m].npg * pgs, +					    PROT_READ|PROT_WRITE, +					    MAP_PRIVATE|MAP_ANON, -1, +					    (off_t)0), mm[m].p); +					if (mm[m].p != MAP_FAILED) { +						size_t mo; + +						/* Touch some memory... */ +						p = mm[m].p; +						mo = cnt % +						    (mm[m].npg * pgs - 1); +						p[mo] = 1; +						cnt += (int)((long)(mm[m].p) +						    / pgs); +					} + +					/* Check cnts and times... */ +					for (ii = 0; ii < sizeof(cl)/sizeof(cl[0]); +					    ii++) { +						HX((e = clock_gettime(cl[ii], +						    &ts)) == -1, ts); +						if (e != -1) +							cnt += (int)ts.tv_nsec; +					} + +					HX((e = getrusage(RUSAGE_SELF, +					    &ru)) == -1, ru); +					if (e != -1) { +						cnt += (int)ru.ru_utime.tv_sec; +						cnt += (int)ru.ru_utime.tv_usec; +					} +				} + +				for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) { +					if (mm[m].p != MAP_FAILED) +						munmap(mm[m].p, mm[m].npg * pgs); +					mm[m].p = MAP_FAILED; +				} + +				HX(stat(".", &st) == -1, st); +				HX(statvfs(".", &stvfs) == -1, stvfs); + +				HX(stat("/", &st) == -1, st); +				HX(statvfs("/", &stvfs) == -1, stvfs); + +				HX((e = fstat(0, &st)) == -1, st); +				if (e == -1) { +					if (S_ISREG(st.st_mode) || +					    S_ISFIFO(st.st_mode) || +					    S_ISSOCK(st.st_mode)) { +						HX(fstatvfs(0, &stvfs) == -1, +						    stvfs); +						HX((off = lseek(0, (off_t)0, +						    SEEK_CUR)) < 0, off); +					} +					if (S_ISCHR(st.st_mode)) { +						HX(tcgetattr(0, &tios) == -1, +						    tios); +					} else if (S_ISSOCK(st.st_mode)) { +						memset(&ss, 0, sizeof ss); +						ssl = sizeof(ss); +						HX(getpeername(0, +						    (void *)&ss, &ssl) == -1, +						    ss); +					} +				} + +				HX((e = getrusage(RUSAGE_CHILDREN, +				    &ru)) == -1, ru); +				if (e != -1) { +					cnt += (int)ru.ru_utime.tv_sec; +					cnt += (int)ru.ru_utime.tv_usec; +				} +			} else { +				/* Subsequent hashes absorb previous result */ +				HD(results); +			} + +			HX((e = gettimeofday(&tv, NULL)) == -1, tv); +			if (e != -1) { +				cnt += (int)tv.tv_sec; +				cnt += (int)tv.tv_usec; +			} + +			HD(cnt); +		} +		SHA512_Final(results, &ctx); +		memcpy((char *)buf + i, results, MINIMUM(sizeof(results), len - i)); +		i += MINIMUM(sizeof(results), len - i); +	} +	explicit_bzero(&ctx, sizeof ctx); +	explicit_bzero(results, sizeof results); +	errno = save_errno; +	return (0);		/* satisfied */ +} diff --git a/ext/libressl/crypto/compat/getentropy_win.c b/ext/libressl/crypto/compat/getentropy_win.c new file mode 100644 index 0000000..64514b3 --- /dev/null +++ b/ext/libressl/crypto/compat/getentropy_win.c @@ -0,0 +1,50 @@ +/*	$OpenBSD: getentropy_win.c,v 1.6 2020/11/11 10:41:24 bcook Exp $	*/ + +/* + * Copyright (c) 2014, Theo de Raadt <deraadt@openbsd.org>  + * Copyright (c) 2014, Bob Beck <beck@obtuse.com> + * + * 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. + * + * Emulation of getentropy(2) as documented at: + * http://man.openbsd.org/getentropy.2 + */ + +#include <windows.h> +#include <bcrypt.h> +#include <errno.h> +#include <stdint.h> +#include <sys/types.h> + +int	getentropy(void *buf, size_t len); + +/* + * On Windows, BCryptGenRandom with BCRYPT_USE_SYSTEM_PREFERRED_RNG is supposed + * to be a well-seeded, cryptographically strong random number generator. + * https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom + */ +int +getentropy(void *buf, size_t len) +{ +	if (len > 256) { +		errno = EIO; +		return (-1); +	} + +	if (FAILED(BCryptGenRandom(NULL, buf, len, BCRYPT_USE_SYSTEM_PREFERRED_RNG))) { +		errno = EIO; +		return (-1); +	} + +	return (0); +} diff --git a/ext/libressl/crypto/compat/timingsafe_bcmp.c b/ext/libressl/crypto/compat/timingsafe_bcmp.c new file mode 100644 index 0000000..552e844 --- /dev/null +++ b/ext/libressl/crypto/compat/timingsafe_bcmp.c @@ -0,0 +1,29 @@ +/*	$OpenBSD: timingsafe_bcmp.c,v 1.3 2015/08/31 02:53:57 guenther Exp $	*/ +/* + * Copyright (c) 2010 Damien Miller.  All rights reserved. + * + * 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. + */ + +#include <string.h> + +int +timingsafe_bcmp(const void *b1, const void *b2, size_t n) +{ +	const unsigned char *p1 = b1, *p2 = b2; +	int ret = 0; + +	for (; n > 0; n--) +		ret |= *p1++ ^ *p2++; +	return (ret != 0); +} diff --git a/ext/libressl/crypto/compat/timingsafe_memcmp.c b/ext/libressl/crypto/compat/timingsafe_memcmp.c new file mode 100644 index 0000000..bb210a3 --- /dev/null +++ b/ext/libressl/crypto/compat/timingsafe_memcmp.c @@ -0,0 +1,46 @@ +/*	$OpenBSD: timingsafe_memcmp.c,v 1.2 2015/08/31 02:53:57 guenther Exp $	*/ +/* + * Copyright (c) 2014 Google Inc. + * + * 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. + */ + +#include <limits.h> +#include <string.h> + +int +timingsafe_memcmp(const void *b1, const void *b2, size_t len) +{ +        const unsigned char *p1 = b1, *p2 = b2; +        size_t i; +        int res = 0, done = 0; + +        for (i = 0; i < len; i++) { +                /* lt is -1 if p1[i] < p2[i]; else 0. */ +                int lt = (p1[i] - p2[i]) >> CHAR_BIT; + +                /* gt is -1 if p1[i] > p2[i]; else 0. */ +                int gt = (p2[i] - p1[i]) >> CHAR_BIT; + +                /* cmp is 1 if p1[i] > p2[i]; -1 if p1[i] < p2[i]; else 0. */ +                int cmp = lt - gt; + +                /* set res = cmp if !done. */ +                res |= cmp & ~done; + +                /* set done if p1[i] != p2[i]. */ +                done |= lt | gt; +        } + +        return (res); +} | 
