rust-random / getrandom

A small cross-platform library for retrieving random data from (operating) system source
Apache License 2.0
264 stars 166 forks source link

Unconditionally use `libc::getrandom` on Illumos and `libc::geentropy` on Solaris #417

Closed josephlr closed 2 months ago

josephlr commented 2 months ago

Fixes #413

Also removes the use of GRND_RANDOM, which appears to be based on outdated staements about the RNGs. For Solaris, see this blog post. For Illumos, the algorithms are less clear, but I don't see a clear reason to continue using GRND_RANDOM.

I updated the documentation in getrandom.rs to full document this decision and to have a common place listing when getrandom(2) became avalible on each platform. I also updated the main lib.rs docs to point to the correct man pages.

Note that Solaris 11.3 has a maximum buffer length of 1024 bytes, while Illumos doesn't have this sort of issue.

jclulow commented 2 months ago

Seems reasonable from an illumos perspective, with a small nit: we don't capitalise the "i" in illumos when it appears in print. Thanks!

newpavlov commented 2 months ago

@josephlr I've switched Soalris to the getentropy backend and tweaked some docs. If you do not have any other changes in mind, I think we can merge this PR.

josephlr commented 2 months ago

Thanks for merging this (and sorry for not being responsive).

Per Solaris docs:

This means this is not an acceptable calling sequence: (void) getrandom(&buf, sizeof (buf), 0);

Maybe keep Solaris code in a separate module for now, since it's the only target with MAX_BYTES and zero flag idiosyncrasies? IIUC we will need to use GRND_NONBLOCK and if it returns EAGAIN wait on GRND_RANDOM.

@newpavlov after rereading the solaris documentation, I think we misread things. That comment isn't saying "passing 0 for flags can be insecure during early boot". It's saying "you need to check the return value to make sure the buffer actually got filled with random bytes" (which we obviously do). Furthermore, the following line from the man page seems to suggest that this function behaves correctly during early boot:

If no entropy is available in the pool, the getrandom() function will block

There's also the following comment from the blog post introducing getrandom() and getentropy()

On Solaris the output of getentropy(2) is entropy and should not be used where randomness is needed, in particular it must not be used where an IV or nonce is needed when calling a cryptographic operation. It is intended only for seeding a user space RBG (Random Bit Generator) system. More specifically the data returned by getentropy(2) has not had the required FIPS 140-2 processing for the DRBG applied to it.

Given this, should we use getrandom(2) on Solaris (with the additional max buffer logic)?

newpavlov commented 2 months ago

@josephlr It looks you are right, though it's a bit concerning that all "correct" examples use GRND_RANDOM.

Given this, should we use getrandom(2) on Solaris (with the additional max buffer logic)?

Probably, yes. But we may want to keep it in a separate module. In addition to the max buffer logic, Solaris also guarantees that input buffer will be fully filled:

The other difference is that on Solaris getrandom(2) will either fail completely or will return a buffer filled with the requested size, where as the Linux implementation can return partial buffers.

So we do not need to call sys_fill_exact. IIUC number of bytes can be smaller only if the GRND_NONBLOCK flag is used.