2002-06-13 22:14:37 +00:00
|
|
|
#!/bin/sh
|
|
|
|
#
|
|
|
|
# $FreeBSD$
|
|
|
|
#
|
|
|
|
|
|
|
|
# PROVIDE: random
|
This is the much-discussed major upgrade to the random(4) device, known to you all as /dev/random.
This code has had an extensive rewrite and a good series of reviews, both by the author and other parties. This means a lot of code has been simplified. Pluggable structures for high-rate entropy generators are available, and it is most definitely not the case that /dev/random can be driven by only a hardware souce any more. This has been designed out of the device. Hardware sources are stirred into the CSPRNG (Yarrow, Fortuna) like any other entropy source. Pluggable modules may be written by third parties for additional sources.
The harvesting structures and consequently the locking have been simplified. Entropy harvesting is done in a more general way (the documentation for this will follow). There is some GREAT entropy to be had in the UMA allocator, but it is disabled for now as messing with that is likely to annoy many people.
The venerable (but effective) Yarrow algorithm, which is no longer supported by its authors now has an alternative, Fortuna. For now, Yarrow is retained as the default algorithm, but this may be changed using a kernel option. It is intended to make Fortuna the default algorithm for 11.0. Interested parties are encouraged to read ISBN 978-0-470-47424-2 "Cryptography Engineering" By Ferguson, Schneier and Kohno for Fortuna's gory details. Heck, read it anyway.
Many thanks to Arthur Mesh who did early grunt work, and who got caught in the crossfire rather more than he deserved to.
My thanks also to folks who helped me thresh this out on whiteboards and in the odd "Hallway track", or otherwise.
My Nomex pants are on. Let the feedback commence!
Reviewed by: trasz,des(partial),imp(partial?),rwatson(partial?)
Approved by: so(des)
2014-10-30 21:21:53 +00:00
|
|
|
# REQUIRE: FILESYSTEMS
|
2003-04-18 17:55:05 +00:00
|
|
|
# BEFORE: netif
|
2004-10-07 13:55:26 +00:00
|
|
|
# KEYWORD: nojail shutdown
|
2002-06-13 22:14:37 +00:00
|
|
|
|
|
|
|
. /etc/rc.subr
|
|
|
|
|
|
|
|
name="random"
|
2016-04-23 16:10:54 +00:00
|
|
|
desc="Harvest and save entropy for random device"
|
2002-06-13 22:14:37 +00:00
|
|
|
start_cmd="random_start"
|
|
|
|
stop_cmd="random_stop"
|
|
|
|
|
2012-08-22 18:43:21 +00:00
|
|
|
extra_commands="saveseed"
|
|
|
|
saveseed_cmd="${name}_stop"
|
|
|
|
|
2014-11-02 01:47:27 +00:00
|
|
|
save_dev_random()
|
|
|
|
{
|
2017-05-27 06:24:06 +00:00
|
|
|
oumask=`umask`
|
|
|
|
umask 077
|
2014-11-02 01:47:27 +00:00
|
|
|
for f ; do
|
2017-05-27 06:24:06 +00:00
|
|
|
debug "saving entropy to $f"
|
|
|
|
dd if=/dev/random of="$f" bs=4096 count=1 status=none &&
|
2019-05-22 21:47:17 +00:00
|
|
|
( chflags nodump "$f" 2>/dev/null || : ) &&
|
random(4): Attempt to persist entropy promptly
The goal of saving entropy in Fortuna is two-fold: (1) to provide early
availability of the random device (unblocking) on next boot; and (2), to
have known, high-quality entropy available for that initial seed. We know
it is high quality because it's output taken from Fortuna.
The FS&K paper makes it clear that Fortuna unblocks when enough bits have
been input that the output //may// be safely seeded. But they emphasize
that the quality of various entropy sources is unknown, and a saved entropy
file is essential for both availability and ensuring initial
unpredictability.
In FreeBSD we persist entropy using two mechanisms:
1. The /etc/rc.d/random shutdown() function, which is used for ordinary
shutdowns and reboots; and,
2. A cron job that runs every dozen minutes or so to persist new entropy, in
case the system suffers from power loss or a crash (bypassing the
ordinary shutdown path).
Filesystems are free to cache dirty data indefinitely, with arbitrary flush
policy. Fsync must be used to ensure the data is persisted, especially for
the cron job save-entropy, whose entire goal is power loss and crash safe
entropy persistence.
Ordinary shutdown may not need the fsync because unmount should flush out
the dirty entropy file shortly afterwards. But it is always possible power
loss or crash occurs during the short window after rc.d/random shutdown runs
and before the filesystem is unmounted, so the additional fsync there seems
harmless.
PR: 230876
Reviewed by: delphij, markj, markm
Approved by: secteam (delphij)
Differential Revision: https://reviews.freebsd.org/D19742
2019-03-31 04:57:50 +00:00
|
|
|
chmod 600 "$f" &&
|
|
|
|
fsync "$f" "$(dirname "$f")"
|
2014-11-02 01:47:27 +00:00
|
|
|
done
|
2017-05-27 06:24:06 +00:00
|
|
|
umask ${oumask}
|
2014-11-02 01:47:27 +00:00
|
|
|
}
|
|
|
|
|
2002-06-13 22:14:37 +00:00
|
|
|
feed_dev_random()
|
|
|
|
{
|
2014-11-02 01:47:27 +00:00
|
|
|
for f ; do
|
|
|
|
if [ -f "$f" -a -r "$f" -a -s "$f" ] ; then
|
|
|
|
if dd if="$f" of=/dev/random bs=4096 2>/dev/null ; then
|
|
|
|
debug "entropy read from $f"
|
|
|
|
rm -f "$f"
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
done
|
2002-06-13 22:14:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
random_start()
|
|
|
|
{
|
2015-06-30 17:09:41 +00:00
|
|
|
|
|
|
|
if [ ${harvest_mask} -gt 0 ]; then
|
2016-05-31 08:31:34 +00:00
|
|
|
echo -n 'Setting up harvesting: '
|
2015-06-30 17:09:41 +00:00
|
|
|
${SYSCTL} kern.random.harvest.mask=${harvest_mask} > /dev/null
|
|
|
|
${SYSCTL_N} kern.random.harvest.mask_symbolic
|
|
|
|
fi
|
|
|
|
|
2016-05-31 08:31:34 +00:00
|
|
|
echo -n 'Feeding entropy: '
|
2014-11-02 01:47:27 +00:00
|
|
|
|
|
|
|
if [ ! -w /dev/random ] ; then
|
|
|
|
warn "/dev/random is not writeable"
|
|
|
|
return 1
|
|
|
|
fi
|
|
|
|
|
2002-06-13 22:14:37 +00:00
|
|
|
# Reseed /dev/random with previously stored entropy.
|
2014-11-02 01:47:27 +00:00
|
|
|
case ${entropy_dir:=/var/db/entropy} in
|
2002-06-13 22:14:37 +00:00
|
|
|
[Nn][Oo])
|
|
|
|
;;
|
|
|
|
*)
|
2014-11-02 01:47:27 +00:00
|
|
|
if [ -d "${entropy_dir}" ] ; then
|
|
|
|
feed_dev_random "${entropy_dir}"/*
|
2002-06-13 22:14:37 +00:00
|
|
|
fi
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
|
2014-11-02 01:47:27 +00:00
|
|
|
case ${entropy_file:=/entropy} in
|
2015-07-08 18:46:44 +00:00
|
|
|
[Nn][Oo])
|
2002-06-13 22:14:37 +00:00
|
|
|
;;
|
|
|
|
*)
|
2014-11-02 01:47:27 +00:00
|
|
|
feed_dev_random "${entropy_file}" /var/db/entropy-file
|
|
|
|
save_dev_random "${entropy_file}"
|
2002-06-13 22:14:37 +00:00
|
|
|
;;
|
|
|
|
esac
|
2014-11-02 01:47:27 +00:00
|
|
|
|
2015-06-30 17:09:41 +00:00
|
|
|
case ${entropy_boot_file:=/boot/entropy} in
|
2015-07-08 18:46:44 +00:00
|
|
|
[Nn][Oo])
|
2015-06-30 17:09:41 +00:00
|
|
|
;;
|
|
|
|
*)
|
|
|
|
save_dev_random "${entropy_boot_file}"
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
|
2014-11-02 01:47:27 +00:00
|
|
|
echo '.'
|
2002-06-13 22:14:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
random_stop()
|
|
|
|
{
|
2004-02-07 23:13:28 +00:00
|
|
|
# Write some entropy so when the machine reboots /dev/random
|
2002-06-13 22:14:37 +00:00
|
|
|
# can be reseeded
|
|
|
|
#
|
2014-11-02 01:47:27 +00:00
|
|
|
case ${entropy_file:=/entropy} in
|
2015-07-08 18:46:44 +00:00
|
|
|
[Nn][Oo])
|
2002-06-13 22:14:37 +00:00
|
|
|
;;
|
|
|
|
*)
|
2019-05-22 21:47:17 +00:00
|
|
|
echo -n 'Writing entropy file: '
|
2007-03-03 06:39:06 +00:00
|
|
|
rm -f ${entropy_file} 2> /dev/null
|
2002-06-13 22:14:37 +00:00
|
|
|
oumask=`umask`
|
|
|
|
umask 077
|
2007-03-03 06:39:06 +00:00
|
|
|
if touch ${entropy_file} 2> /dev/null; then
|
2002-06-13 22:14:37 +00:00
|
|
|
entropy_file_confirmed="${entropy_file}"
|
|
|
|
else
|
|
|
|
# Try this as a reasonable alternative for read-only
|
|
|
|
# roots, diskless workstations, etc.
|
2007-03-03 06:39:06 +00:00
|
|
|
rm -f /var/db/entropy-file 2> /dev/null
|
|
|
|
if touch /var/db/entropy-file 2> /dev/null; then
|
2005-04-11 02:45:05 +00:00
|
|
|
entropy_file_confirmed=/var/db/entropy-file
|
2002-06-13 22:14:37 +00:00
|
|
|
fi
|
|
|
|
fi
|
|
|
|
case ${entropy_file_confirmed} in
|
|
|
|
'')
|
2007-03-03 06:39:06 +00:00
|
|
|
warn 'write failed (read-only fs?)'
|
2002-06-13 22:14:37 +00:00
|
|
|
;;
|
|
|
|
*)
|
2019-05-22 21:47:17 +00:00
|
|
|
save_dev_random "${entropy_file_confirmed}"
|
2015-06-30 17:09:41 +00:00
|
|
|
echo '.'
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
umask ${oumask}
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
case ${entropy_boot_file:=/boot/entropy} in
|
2015-07-08 18:46:44 +00:00
|
|
|
[Nn][Oo])
|
2015-06-30 17:09:41 +00:00
|
|
|
;;
|
|
|
|
*)
|
2019-05-22 21:47:17 +00:00
|
|
|
echo -n 'Writing early boot entropy file: '
|
2015-06-30 17:09:41 +00:00
|
|
|
rm -f ${entropy_boot_file} 2> /dev/null
|
|
|
|
oumask=`umask`
|
|
|
|
umask 077
|
|
|
|
if touch ${entropy_boot_file} 2> /dev/null; then
|
|
|
|
entropy_boot_file_confirmed="${entropy_boot_file}"
|
|
|
|
fi
|
|
|
|
case ${entropy_boot_file_confirmed} in
|
|
|
|
'')
|
|
|
|
warn 'write failed (read-only fs?)'
|
|
|
|
;;
|
|
|
|
*)
|
2019-05-22 21:47:17 +00:00
|
|
|
save_dev_random "${entropy_boot_file_confirmed}"
|
2002-06-13 22:14:37 +00:00
|
|
|
echo '.'
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
umask ${oumask}
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
|
|
|
load_rc_config $name
|
|
|
|
run_rc_command "$1"
|