Load entropy at system boot (only works at securelevel < 1); save

at system shutdown.  Disable with random_seed=NO in rc.conf if desired.

Goes to some trouble to never load or save to network filesystems.

Entropy should really be loaded by the boot loader but I am still
sorting out how to pass it to the kernel.
This commit is contained in:
tls 2011-11-23 10:47:48 +00:00
parent 95925fc068
commit 4924aa205a
11 changed files with 336 additions and 24 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: mi,v 1.225 2011/09/06 21:32:30 riz Exp $
# $NetBSD: mi,v 1.226 2011/11/23 10:47:49 tls Exp $
#
# Note: end-user configuration files that are moved to another location
# should not be marked "obsolete"; they should just be removed from
@ -254,6 +254,7 @@
./etc/rc.d/racoon etc-net-rc
./etc/rc.d/raidframe etc-sys-rc
./etc/rc.d/raidframeparity etc-sys-rc
./etc/rc.d/random_seed etc-sys-rc
./etc/rc.d/rarpd etc-bootserver-rc
./etc/rc.d/rbootd etc-bootserver-rc
./etc/rc.d/rndctl etc-sys-rc

View File

@ -1,4 +1,4 @@
# $NetBSD: rc.conf,v 1.116 2011/11/21 20:56:21 darcy Exp $
# $NetBSD: rc.conf,v 1.117 2011/11/23 10:47:48 tls Exp $
#
# /etc/defaults/rc.conf --
# default configuration of /etc/rc.conf
@ -362,3 +362,6 @@ veriexec_strict=0
veriexec_verbose=0
veriexec_flags="-k"
# Entropy load/save to/from /dev/random at startup/shutdown
#
random_seed=YES

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.85 2011/09/06 21:32:29 riz Exp $
# $NetBSD: Makefile,v 1.86 2011/11/23 10:47:48 tls Exp $
.include <bsd.own.mk>
@ -31,8 +31,9 @@ CONFIGFILES=\
named ndbootd network newsyslog nfsd nfslocking npf ntpd ntpdate \
perusertmp pf pf_boot pflogd postfix powerd ppp pwcheck \
quota \
racoon rpcbind raidframe raidframeparity rarpd rbootd rndctl \
root route6d routed rtadvd rtclocaltime rtsold rwho \
racoon rpcbind raidframe raidframeparity random_seed rarpd \
rbootd rndctl root route6d routed rtadvd rtclocaltime \
rtsold rwho \
savecore screenblank securelevel sshd \
staticroute swap1 swap2 sysctl sysdb syslogd \
timed tpctl ttys \

91
etc/rc.d/random_seed Executable file
View File

@ -0,0 +1,91 @@
#!/bin/sh
#
# $NetBSD: random_seed,v 1.1 2011/11/23 10:47:48 tls Exp $
#
# PROVIDE: random_seed
# REQUIRE: mountcritlocal
# BEFORE: securelevel
# KEYWORD: shutdown
$_rc_subr_loaded . /etc/rc.subr
name="random_seed"
rcvar=$name
start_cmd="random_load"
stop_cmd="random_save"
random_file=${random_file:-/var/db/entropy-file}
fs_safe()
{
#
# Enforce that the file's on a local filesystem.
# Include only the types we can actually write.
#
fstype=$(df -G $1 | awk '$2 == "fstype" {print $1}')
case $fstype in
ffs)
return 0
;;
lfs)
return 0
;;
ext2fs)
return 0;
;;
msdosfs)
return 0;
;;
v7fs)
return 0;
;;
esac
return 1
}
random_load()
{
if [ -f $random_file ]; then
if ! fs_safe $(dirname ${random_file}); then
return 1
fi
eval $(stat -s ${random_file})
# The file must be owned by root,
if [ "$st_uid" != "0" ]; then
return 1
fi
# and root read/write only.
if [ "$(echo $st_mode | tail -c4)" != "600" ]; then
return 1
fi
if rndctl -L ${random_file}; then
echo "Loaded entropy from disk."
fi
fi
}
random_save()
{
oum=$(umask)
umask 077
rm -Pf ${random_file}
if ! fs_safe $(dirname ${random_file}); then
return 1
fi
if rndctl -S ${random_file}; then
echo "Saved entropy to disk."
fi
}
load_rc_config $name
run_rc_command "$1"

View File

@ -1,4 +1,4 @@
.\" $NetBSD: rndctl.8,v 1.18 2011/10/01 02:55:00 pgoyette Exp $
.\" $NetBSD: rndctl.8,v 1.19 2011/11/23 10:47:49 tls Exp $
.\"
.\" Copyright (c) 1997 Michael Graff
.\" All rights reserved.
@ -39,6 +39,10 @@
.Nm
.Fl ls
.Op Fl d Ar devname | Fl t Ar devtype
.Nm
.Fl L Ar save-file
.Nm
.Fl S Ar save-file
.Sh DESCRIPTION
The
.Nm
@ -104,6 +108,17 @@ Terminal, mouse, or other user input devices.
.It Ic rng
Random number generators.
.El
.It Fl L
Load saved entropy from file
.Ar save-file ,
which will be overwritten and deleted before the entropy is loaded into
the kernel.
.It Fl S
Save entropy pool to file
.Ar save-file .
The file format is specific to
.Nm
and includes an estimate of the amount of saved entropy and a checksum.
.El
.Sh FILES
.Bl -tag -width /dev/urandomx -compact

View File

@ -1,4 +1,4 @@
/* $NetBSD: rndctl.c,v 1.20 2011/08/27 18:48:59 joerg Exp $ */
/* $NetBSD: rndctl.c,v 1.21 2011/11/23 10:47:49 tls Exp $ */
/*-
* Copyright (c) 1997 Michael Graff.
@ -29,14 +29,17 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#include <sys/types.h>
#include <sha1.h>
#ifndef lint
__RCSID("$NetBSD: rndctl.c,v 1.20 2011/08/27 18:48:59 joerg Exp $");
__RCSID("$NetBSD: rndctl.c,v 1.21 2011/11/23 10:47:49 tls Exp $");
#endif
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/rnd.h>
#include <stdio.h>
@ -47,6 +50,12 @@ __RCSID("$NetBSD: rndctl.c,v 1.20 2011/08/27 18:48:59 joerg Exp $");
#include <err.h>
#include <string.h>
typedef struct {
uint32_t entropy;
uint8_t data[RND_POOLWORDS * sizeof(uint32_t)];
uint8_t digest[SHA1_DIGEST_LENGTH];
} rndsave_t;
typedef struct {
const char *a_name;
u_int32_t a_type;
@ -78,6 +87,7 @@ usage(void)
getprogname());
fprintf(stderr, " %s -ls [-d devname | -t devtype]\n",
getprogname());
fprintf(stderr, " %s -[L|S] save-file\n", getprogname());
exit(1);
}
@ -115,6 +125,114 @@ find_name(u_int32_t type)
return ("???");
}
static void
do_save(const char *const filename)
{
int est1, est2;
rndpoolstat_t rp;
rndsave_t rs;
SHA1_CTX s;
int fd;
fd = open("/dev/urandom", O_RDONLY, 0644);
if (fd < 0) {
err(1, "device open");
}
if (ioctl(fd, RNDGETPOOLSTAT, &rp) < 0) {
err(1, "ioctl(RNDGETPOOLSTAT)");
}
est1 = rp.curentropy;
if (read(fd, rs.data, sizeof(rs.data)) != sizeof(rs.data)) {
err(1, "entropy read");
}
if (ioctl(fd, RNDGETPOOLSTAT, &rp) < 0) {
err(1, "ioctl(RNDGETPOOLSTAT)");
}
est2 = rp.curentropy;
if (est1 - est2 < 0) {
rs.entropy = 0;
} else {
rs.entropy = est1 - est2;
}
SHA1Init(&s);
SHA1Update(&s, (uint8_t *)&rs.entropy, sizeof(rs.entropy));
SHA1Update(&s, rs.data, sizeof(rs.data));
SHA1Final(rs.digest, &s);
close(fd);
unlink(filename);
fd = open(filename, O_CREAT|O_EXCL|O_WRONLY, 0600);
if (fd < 0) {
err(1, "output open");
}
if (write(fd, &rs, sizeof(rs)) != sizeof(rs)) {
unlink(filename);
fsync_range(fd, FDATASYNC|FDISKSYNC, (off_t)0, (off_t)0);
err(1, "write");
}
fsync_range(fd, FDATASYNC|FDISKSYNC, (off_t)0, (off_t)0);
close(fd);
}
static void
do_load(const char *const filename)
{
int fd;
rndsave_t rs;
rnddata_t rd;
SHA1_CTX s;
uint8_t digest[SHA1_DIGEST_LENGTH];
fd = open(filename, O_RDWR, 0600);
if (fd < 0) {
err(1, "input open");
}
unlink(filename);
if (read(fd, &rs, sizeof(rs)) != sizeof(rs)) {
err(1, "read");
}
if (write(fd, &rs, sizeof(rs) != sizeof(rs))) {
err(1, "overwrite");
}
fsync_range(fd, FDATASYNC|FDISKSYNC, (off_t)0, (off_t)0);
close(fd);
SHA1Init(&s);
SHA1Update(&s, (uint8_t *)&rs.entropy, sizeof(rs.entropy));
SHA1Update(&s, rs.data, sizeof(rs.data));
SHA1Final(digest, &s);
if (memcmp(digest, rs.digest, sizeof(digest))) {
errx(1, "bad digest");
}
rd.len = MIN(sizeof(rd.data), sizeof(rs.data));
rd.entropy = rs.entropy;
memcpy(rd.data, rs.data, MIN(sizeof(rd.data), sizeof(rs.data)));
fd = open("/dev/urandom", O_RDWR, 0644);
if (fd < 0) {
err(1, "device open");
}
if (ioctl(fd, RNDADDDATA, &rd) < 0) {
err(1, "ioctl");
}
close(fd);
}
static void
do_ioctl(rndctl_t *rctl)
{
@ -247,6 +365,7 @@ main(int argc, char **argv)
int ch, cmd, lflag, mflag, sflag;
u_int32_t type;
char name[16];
const char *filename = NULL;
rctl.mask = 0;
rctl.flags = 0;
@ -257,7 +376,7 @@ main(int argc, char **argv)
sflag = 0;
type = 0xff;
while ((ch = getopt(argc, argv, "CEcelt:d:s")) != -1) {
while ((ch = getopt(argc, argv, "CES:L:celt:d:s")) != -1) {
switch (ch) {
case 'C':
rctl.flags |= RND_FLAG_NO_COLLECT;
@ -269,6 +388,18 @@ main(int argc, char **argv)
rctl.mask |= RND_FLAG_NO_ESTIMATE;
mflag++;
break;
case 'L':
if (cmd != 0)
usage();
cmd = 'L';
filename = optarg;
break;
case 'S':
if (cmd != 0)
usage();
cmd = 'S';
filename = optarg;
break;
case 'c':
rctl.flags &= ~RND_FLAG_NO_COLLECT;
rctl.mask |= RND_FLAG_NO_COLLECT;
@ -314,6 +445,22 @@ main(int argc, char **argv)
if (argc > 0)
usage();
/*
* Save.
*/
if (cmd == 'S') {
do_save(filename);
exit(0);
}
/*
* Load.
*/
if (cmd == 'L') {
do_load(filename);
exit(0);
}
/*
* Cannot list and modify at the same time.
*/

View File

@ -1,4 +1,4 @@
/* $NetBSD: rnd.c,v 1.85 2011/11/20 00:45:15 tls Exp $ */
/* $NetBSD: rnd.c,v 1.86 2011/11/23 10:47:48 tls Exp $ */
/*-
* Copyright (c) 1997-2011 The NetBSD Foundation, Inc.
@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: rnd.c,v 1.85 2011/11/20 00:45:15 tls Exp $");
__KERNEL_RCSID(0, "$NetBSD: rnd.c,v 1.86 2011/11/23 10:47:48 tls Exp $");
#include <sys/param.h>
#include <sys/ioctl.h>
@ -509,7 +509,15 @@ int
rndwrite(dev_t dev, struct uio *uio, int ioflag)
{
u_int8_t *bf;
int n, ret;
int n, ret = 0, estimate_ok = 0, estimate = 0, added = 0;
ret = kauth_authorize_device(curlwp->l_cred,
KAUTH_DEVICE_RND_ADDDATA, NULL, NULL, NULL, NULL);
if (ret) {
return (ret);
}
estimate_ok = !kauth_authorize_device(curlwp->l_cred,
KAUTH_DEVICE_RND_ADDDATA_ESTIMATE, NULL, NULL, NULL, NULL);
DPRINTF(RND_DEBUG_WRITE,
("Random: Write of %zu requested\n", uio->uio_resid));
@ -519,19 +527,43 @@ rndwrite(dev_t dev, struct uio *uio, int ioflag)
ret = 0;
bf = kmem_alloc(RND_TEMP_BUFFER_SIZE, KM_SLEEP);
while (uio->uio_resid > 0) {
/*
* Don't flood the pool.
*/
if (added > RND_POOLWORDS * sizeof(int)) {
printf("rnd: added %d already, adding no more.\n",
added);
break;
}
n = min(RND_TEMP_BUFFER_SIZE, uio->uio_resid);
ret = uiomove((void *)bf, n, uio);
if (ret != 0)
break;
if (estimate_ok) {
/*
* Don't cause samples to be discarded by taking
* the pool's entropy estimate to the max.
*/
if (added > RND_POOLWORDS / 2)
estimate = 0;
else
estimate = n * NBBY / 2;
printf("rnd: adding on write, %d bytes, estimate %d\n",
n, estimate);
} else {
printf("rnd: kauth says no entropy.\n");
}
/*
* Mix in the bytes.
*/
mutex_spin_enter(&rndpool_mtx);
rndpool_add_data(&rnd_pool, bf, n, 0);
rndpool_add_data(&rnd_pool, bf, n, estimate);
mutex_spin_exit(&rndpool_mtx);
added += n;
DPRINTF(RND_DEBUG_WRITE, ("Random: Copied in %d bytes\n", n));
}
kmem_free(bf, RND_TEMP_BUFFER_SIZE);
@ -558,9 +590,8 @@ rndioctl(dev_t dev, u_long cmd, void *addr, int flag,
rndctl_t *rctl;
rnddata_t *rnddata;
u_int32_t count, start;
int ret;
ret = 0;
int ret = 0;
int estimate_ok = 0, estimate = 0;
switch (cmd) {
case FIONBIO:
@ -589,6 +620,8 @@ rndioctl(dev_t dev, u_long cmd, void *addr, int flag,
KAUTH_DEVICE_RND_ADDDATA, NULL, NULL, NULL, NULL);
if (ret)
return (ret);
estimate_ok = !kauth_authorize_device(l->l_cred,
KAUTH_DEVICE_RND_ADDDATA_ESTIMATE, NULL, NULL, NULL, NULL);
break;
default:
@ -720,9 +753,23 @@ rndioctl(dev_t dev, u_long cmd, void *addr, int flag,
if (rnddata->len > sizeof(rnddata->data))
return EINVAL;
if (estimate_ok) {
/*
* Do not accept absurd entropy estimates, and
* do not flood the pool with entropy such that
* new samples are discarded henceforth.
*/
estimate = MIN((rnddata->len * NBBY) / 2,
MIN(rnddata->entropy,
RND_POOLWORDS * sizeof(int) *
NBBY / 2));
} else {
estimate = 0;
}
mutex_spin_enter(&rndpool_mtx);
rndpool_add_data(&rnd_pool, rnddata->data, rnddata->len,
rnddata->entropy);
estimate);
mutex_spin_exit(&rndpool_mtx);
rnd_wakeup_readers();

View File

@ -1,4 +1,4 @@
/* $NetBSD: secmodel_securelevel.c,v 1.20 2009/10/07 01:06:57 elad Exp $ */
/* $NetBSD: secmodel_securelevel.c,v 1.21 2011/11/23 10:47:48 tls Exp $ */
/*-
* Copyright (c) 2006 Elad Efrat <elad@NetBSD.org>
* All rights reserved.
@ -35,7 +35,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: secmodel_securelevel.c,v 1.20 2009/10/07 01:06:57 elad Exp $");
__KERNEL_RCSID(0, "$NetBSD: secmodel_securelevel.c,v 1.21 2011/11/23 10:47:48 tls Exp $");
#ifdef _KERNEL_OPT
#include "opt_insecure.h"
@ -553,6 +553,11 @@ secmodel_securelevel_device_cb(kauth_cred_t cred, kauth_action_t action,
result = KAUTH_RESULT_DENY;
break;
case KAUTH_DEVICE_RND_ADDDATA_ESTIMATE:
if (securelevel > 0)
result = KAUTH_RESULT_DENY;
break;
default:
break;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: secmodel_suser.c,v 1.34 2009/12/29 04:25:30 elad Exp $ */
/* $NetBSD: secmodel_suser.c,v 1.35 2011/11/23 10:47:49 tls Exp $ */
/*-
* Copyright (c) 2006 Elad Efrat <elad@NetBSD.org>
* All rights reserved.
@ -38,7 +38,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: secmodel_suser.c,v 1.34 2009/12/29 04:25:30 elad Exp $");
__KERNEL_RCSID(0, "$NetBSD: secmodel_suser.c,v 1.35 2011/11/23 10:47:49 tls Exp $");
#include <sys/types.h>
#include <sys/param.h>
@ -838,6 +838,7 @@ secmodel_suser_device_cb(kauth_cred_t cred, kauth_action_t action,
case KAUTH_DEVICE_TTY_PRIVSET:
case KAUTH_DEVICE_TTY_STI:
case KAUTH_DEVICE_RND_ADDDATA:
case KAUTH_DEVICE_RND_ADDDATA_ESTIMATE:
case KAUTH_DEVICE_RND_GETPRIV:
case KAUTH_DEVICE_RND_SETPRIV:
if (isroot)

View File

@ -1,4 +1,4 @@
/* $NetBSD: kauth.h,v 1.64 2009/12/24 19:02:07 elad Exp $ */
/* $NetBSD: kauth.h,v 1.65 2011/11/23 10:47:49 tls Exp $ */
/*-
* Copyright (c) 2005, 2006 Elad Efrat <elad@NetBSD.org>
@ -255,6 +255,7 @@ enum {
KAUTH_DEVICE_RAWIO_PASSTHRU,
KAUTH_DEVICE_BLUETOOTH_SETPRIV,
KAUTH_DEVICE_RND_ADDDATA,
KAUTH_DEVICE_RND_ADDDATA_ESTIMATE,
KAUTH_DEVICE_RND_GETPRIV,
KAUTH_DEVICE_RND_SETPRIV,
KAUTH_DEVICE_BLUETOOTH_BCSP,

View File

@ -1,4 +1,4 @@
/* $NetBSD: rnd.h,v 1.22 2011/11/19 22:51:31 tls Exp $ */
/* $NetBSD: rnd.h,v 1.23 2011/11/23 10:47:49 tls Exp $ */
/*-
* Copyright (c) 1997 The NetBSD Foundation, Inc.
@ -209,7 +209,7 @@ typedef struct {
typedef struct {
uint32_t len;
uint32_t entropy;
u_char data[RND_POOLWORDS * 4];
u_char data[RND_POOLWORDS * sizeof(uint32_t)];
} rnddata_t;
#define RNDGETENTCNT _IOR('R', 101, uint32_t) /* get entropy count */