arc4random initialization

Conrad Meyer cem at freebsd.org
Tue Dec 8 02:52:17 UTC 2020


On Mon, Dec 7, 2020 at 12:37 AM Mark Murray <markm at freebsd.org> wrote:
>
> Hi
>
> > On 6 Dec 2020, at 23:36, Dave Hayes <dave at jetcafe.org> wrote:
> >
> > So security-wise, just how bad is it to be improperly seeded? If I cannot get
> > a valid entropy stash at boot time, can I delay the need for it until I can get
> > a writable filesystem up and running?
> >
> > Thanks in advance for any cogent replies.
>
> This means that the random(4) device and relevant infrastructure like
> arc4random starts up in an insecure state and is not to be trusted for e.g.
> generating SSH keys.
>
> After you have used the machine for a while (exactly how long "depends"),
> it will reseed itself and become secure.
>
> Essentially, expect every boot off a DVD on the same hardware to reuse
> cryptographic keys and therefore be insecure.
>
> Once you've installed on some R/W medium and rebooted, the necessary
> entropy will have been stashed for you, and the first SSH keys will be
> generated properly.

+1 to what Mark wrote.

To add a little bit more, in CURRENT we have some sysctls around
initial seeding: the kern.random.initial_seeding subtree.  There are
four keys there:

Admin-configured (configuration):
kern.random.initial_seeding.bypass_before_seeding: if disabled we will
potentially deadlock boot rather than provide bad random data to
kernel consumers and user applications.  If enabled, we will provide
bad entropy if we're unseeded.
kern.random.initial_seeding.disable_bypass_warnings: if enabled, we
log messages when the former situation occurred.

Read-only knobs that reflect random safety during the boot process (diagnostic):
kern.random.initial_seeding.arc4random_bypassed_before_seeding:
kern.random.initial_seeding.read_random_bypassed_before_seeding: If
these are non-zero, it means the corresponding operation
(arc4random(9), read_random(9)) was accessed when random(4) was
unseeded.  If these knobs are both zero, you know that all randomness
used during boot was high-quality (seeded).

To comment on some various other ideas / questions raised in the
thread (Hal, Dave):

> If I do a fresh install, when does the host's SSH key get generated and where does the entropy for that step come from?

The system /etc/rc.d/sshd script generates SSH host keys if they
aren't present already.  So that's well into multiuser, by which time
the system random device is usually well-seeded, even on extremely
limited platforms.  An installer might also write those host keys,
although I'm not aware of one that does so.

> I assume lots of entropy is generated during the install.  Does that get written to the new system's disk so it has some at first boot?

bsdinstall has a script which does so from the runtime environment of
the installer, which is probably well-seeded:
usr.sbin/bsdinstall/scripts/entropy.  Other installers may or may not
write the unique entropy file; I'm not familiar with all installers.
Ideally they would all do something like what bsdinstall is doing for
entropy.

> Does the on-disk entropy file get updated occasionally (as compared to only at shutdown) so it doesn't get reused if the system crashes?

Yes.  cron runs libexec/save-entropy/save-entropy.sh periodically.
Unfortunately, this entropy location (/var/db/entropy) is only
available after userspace has started (/etc/rc.d/random) — it is not
used to seed the kernel during the early boot process.  Only
bootloader entropy is loaded very early on (/boot/entropy), and that
location is only saved on clean shutdown (/etc/rc.d/random).

> If so, how often is "occasionally"?  Will that turn into a wear-out problem if running on a flash drive? (eg Raspberry Pi)

usr.sbin/cron/cron/crontab: once every 11 minutes, by default.  The
save-entropy default is 4kB, and each save is a new file (so you're
probably doing a directory entry write, an inode write, as well as a
data block write).  So call it 12kB/11min, or about 1.5 MB/day.

> Is there any indication as to when it has safely reseeded?

For the core random device, the message "random: unblocking device."
is printed in dmesg and logged to /var/log/messages.

RW wrote:

> The risk would be that kernel arc4random is initialized early and insecurely and there's no appropriate read_random() call to reseed it before something critical uses it.

arc4random(9) is integrated with random(4), so that arc4random is
immediately reseeded when the random device is seeded.  This logic can
be found in libkern/arc4random.c and dev/random/randomdev.c; look for
the variable 'arc4rand_iniseed_state' and the 'ARC4_ENTR_HAVE'
constant.  However, the concern still applies to userspace
arc4random(3), which is not integrated with core random(4) reseeds.

(And in CURRENT, the FXRNG random(4) mode *does* integrate userspace
arc4random(3) with random(4) reseeds, but that code isn't yet enabled
in GENERIC kernels.)

> IMO it would be better to eliminate that 0.7s period by getting enough entropy from the hardware generator instantaneously when Fortuna initializes. Whatever the paranoia over these generators they're better than no seeding at all.

Totally agree.  We actually do this on CURRENT if
kern.random.initial_seeding.bypass_before_seeding=0 and a fast random
source (e.g., RDRAND) is available.  Look for
randomdev_wait_until_seeded() (both function body and callers) in
sys/dev/random/randomdev.c.

Hope that helps,
Conrad


More information about the freebsd-hackers mailing list