Hello internals friends!

I wanted to propose aliasing openssl_random_pseudo_bytes() to
php_random_bytes_throw() in PHP 7.4 for the following reasons:

1) OpenSSL's CSPRNG isn't fork safe:
https://wiki.openssl.org/index.php/Random_fork-safety

This did get fixed last month with the release of v1.1.1 with a
complete rewrite of their CSPRNG, but my guess is it'll be a while
before we see that version landing in a LTS distro.

2) The openssl_random_pseudo_bytes() function fails open which means
code like this:

function genCsrfToken(): string
{
    return bin2hex(openssl_random_pseudo_bytes(32));
}

...could return an empty string. This forces the developer to do their
own checks and fail closed in userland.

function genCsrfToken(): string
{
    $bytes = openssl_random_pseudo_bytes(32);
    if (false === $bytes) {
        throw new \Exception('CSPRNG error');
    }
    return bin2hex($bytes);
}

A quick search in GitHub reveals very little checking of the return
value of openssl_random_pseudo_bytes() in the wild.

CSPRNG implementations should always fail closed.

3) It gets worse: there's that confusing pass-by-reference param
zstrong_result_returned that forces yet another check in userland to
determine if the bytes are strong enough for crypto. To be honest, in
checking the implementation, I can't even tell how the function would
ever return a string of bytes and also set the zstrong_result_returned
param to false.

The API is unnecessarily confusing making it easy to get it wrong. The
above userland example isn't even correct, the correct usage in
userland would actually be:

function genCsrfToken(): string
{
    $strong = false;
    $bytes = openssl_random_pseudo_bytes(32, $strong);
    if (false === $bytes || false === $strong) {
        throw new \Exception('CSPRNG error');
    }
    return bin2hex($bytes);
}

4) We get to consolidate our CSPRNG code in one place. This would make
it nice to be able to upgrade all the CSPRNG code to libsodium's
CSPRNG if we choose to in the future for example.

The change I'm proposing would be to:

1) Make openssl_random_pseudo_bytes() return bytes from
php_random_bytes_throw() causing the function to fail closed and never
returning false.
2) Deprecate the usage of the second pass-by-reference parameter and
remove in PHP 8.0. Until then, it always sets the value to true.

Do you think this kind of change would warrant an RFC?

Thanks,
Sammy Kaye Powers
sammyk.me

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to