> On Jun 22, 2016, at 10:40 PM, Tim Peters <tim.pet...@gmail.com> wrote:
> 
> [Guido]
>> Before I can possibly start thinking about what to do when the system's
>> CSPRNG is initialized, I need to understand more about how it works.
>> Apparently there's a possible transition from the "not ready yet" ("bad")
>> state to "ready" ("good"), and all it takes is usually waiting for a second
>> or two. But is this a wait that only gets incurred once, somewhere early
>> after a boot, or is this something that can happen at any time?
> 
> [Donald Stufft]
>> Once, only after boot. On most (all?) modern Linux systems there’s even part
>> of the boot process that attempts to seed the CSPRNG using random values
>> stored during a previous boot to shorten the time window between when it’s
>> ready and when it’s not yet initialized. However, once it is initialized it
>> will never block (or EAGAIN) again.
> 
> Donald, at the end you're talking about how getrandom() behaves -
> /dev/urandom on Linux never blocks, as I understand it (but there's no
> advertised way to tell when /dev/urandom enters the "good" state).

Yes sorry, Guido asked about the system CSPRNG, in Linux there are three
(previously two) basic interfaces to the same CSPRNG:

/dev/urandom
  - This will never block, but until it gathers enough entropy in the boot
    process it will silently return data that is not cryptographically secure.
    Essentially, predictably random, however to what degree it is predictable
    depends on a lot of factors. As far as I am aware, there is no practical
    way to determine “given a read of /dev/urandom did I get ‘good’ or ‘bad’
    data out of it”.

/dev/random
   - This will randomly block whenever the kernel thinks that the entropy is
     “running low”. All security experts I’m aware of with maybe the exception
     of Ted (I don’t know how he feels about this) believe that this action of
     counting entropy is pure bollocks and that /dev/random randomly blocking
     because it thinks the entropy is low achieves nothing except to hurt the
     performance of things that need randomness at runtime.

And on newer kernels there is the getrandom() sys call which has flags that
enable three different mode of operations:

getrandom(0)
   - This will block until the same “pool” of entropy that /dev/urandom uses
     has been initialized once, at boot, and then it will never block again.

getrandom(GRND_NONBLOCK)
   - This will return a -1 and set errno to EAGAIN if the same pool of entropy
     that /dev/urandom uses has not been initialized, and will otherwise always
     return data. This is essentially the same as getrandom(0) except instead
     of blocking it returns an error.

getrandom(GRND_RANDOM)
   - This is basically just a syscall interface to /dev/random and it doesn’t
     meaningfully deviate from what /dev/random does, except not require a file
     descriptor to use it.

This getrandom() interface is the newer way to access these two types of random
and I think it is important to notice that this newer interface does *not* have
a way to get “sometimes a CSPRNG, sometimes not” data out of it like 
/dev/urandom
does. This newer interface promises that you’ll always get cryptographically 
secure
random and it will either block until it can do that or will EAGAIN to let you
take some other action instead of relying on a CSPRNG if that suits your 
application.



> 
> 
> [Guido]
>> Then shouldn't it be the responsibility of the boot sequence rather than
>> of the Python stdlib to wait for that event? IIUC that's what OS X
>> does (I think someone described that it even kernel-panics when it can't
>> enter the "good" state).
> 
> The rub is that sometimes Python is running soooo early in the boot
> sequence in these rare Linux cases.  That's said to be impossible on
> OS X (or Windows).

Yes, once the system has booted and initialized then all forms of accessing the
/dev/urandom pool (/dev/urandom, getrandom(0), getrandom(GRND_NONBLOCK)) 
function
basically the same (plus or minus a file descriptor). The problem comes in a few
flavors but really they all boil down to the same thing: Code that is calling
os.urandom() prior to the /dev/urandom CSPRNG being initialized.

The primary case this will happen is code that is called early on in the boot
sequence prior to pid 0 initializing the urandom CSPRNG from random data saved
in the previous boot [1]. There are other cases this could happen though, like
embedded Linux systems or RaspberryPi’s or the like that don’t have great 
sources
of hardware entropy that will make it so the initialization of the CSPRNG will
take a longer period of time. This is particularly true on systems that don’t
(currently) have an active network connection since Networking is one of the 
better
sources of randomness that the kernel can use to seed these values with.

[1] This is basically what caused the initial report, systemd-cron was a Python
    script and the SipHash for the dictionary hash randomization was calling
    os.urandom to seed itself. However this particular thing isn’t being asked
    to be made blocking (or an error). As far as I know, most everyone agrees
    that for SipHash’s purpose it’s reasonable fine to fall back to an insecure
    source of random if a secure source isn’t available at the moment. What the
    security side wants is for people explicitly calling os.urandom (directly or
    indirectly) as part of the execute of their Python program to always get
    secure random if the platform we are on provides a reasonable interface to
    get access to it (e.g. /dev/random is not a reasonable interface, but
    getrandom() is).

—
Donald Stufft



_______________________________________________
Security-SIG mailing list
Security-SIG@python.org
https://mail.python.org/mailman/listinfo/security-sig

Reply via email to