Skip to content

Commit c53ea27

Browse files
committed
Improve openssl_random_pseudo_bytes()
CSPRNG implementations should always fail closed. Now openssl_random_pseudo_bytes() will fail closed by throwing an `\Exception` if it is unable to return crypto-strong bytes. The second `$crypto_strong` parameter doesn't do anything despite the docs stating otherwise. This unnecessarily confusing parameter is now deprecated and will be removed in PHP 8.0. In addition to removing the second parameter in 8.0, the ZPP macros will be updated to `ZEND_PARSE_PARAMS_THROW` so passing a second argument will cause a fatal error.
1 parent 3fe698b commit c53ea27

File tree

3 files changed

+34
-21
lines changed

3 files changed

+34
-21
lines changed

ext/openssl/openssl.c

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "php.h"
2929
#include "php_ini.h"
3030
#include "php_openssl.h"
31+
#include "zend_exceptions.h"
3132

3233
/* PHP Includes */
3334
#include "ext/standard/file.h"
@@ -6801,32 +6802,34 @@ PHP_FUNCTION(openssl_random_pseudo_bytes)
68016802
zend_string *buffer = NULL;
68026803
zval *zstrong_result_returned = NULL;
68036804

6804-
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|z/", &buffer_length, &zstrong_result_returned) == FAILURE) {
6805-
return;
6806-
}
6805+
ZEND_PARSE_PARAMETERS_START(1, 2)
6806+
Z_PARAM_LONG(buffer_length)
6807+
Z_PARAM_OPTIONAL
6808+
Z_PARAM_ZVAL_DEREF(zstrong_result_returned)
6809+
ZEND_PARSE_PARAMETERS_END();
68076810

68086811
if (zstrong_result_returned) {
68096812
zval_ptr_dtor(zstrong_result_returned);
6810-
ZVAL_FALSE(zstrong_result_returned);
6813+
ZVAL_TRUE(zstrong_result_returned);
6814+
php_error_docref(NULL, E_DEPRECATED, "Calling openssl_random_pseudo_bytes() with the second argument is deprecated");
68116815
}
68126816

68136817
if (buffer_length <= 0
68146818
#ifndef PHP_WIN32
68156819
|| ZEND_LONG_INT_OVFL(buffer_length)
68166820
#endif
68176821
) {
6818-
RETURN_FALSE;
6822+
zend_throw_exception(zend_ce_error, "Length must be greater than 0", 0);
6823+
return;
68196824
}
68206825
buffer = zend_string_alloc(buffer_length, 0);
68216826

68226827
#ifdef PHP_WIN32
68236828
/* random/urandom equivalent on Windows */
68246829
if (php_win32_get_random_bytes((unsigned char*)buffer->val, (size_t) buffer_length) == FAILURE){
68256830
zend_string_release_ex(buffer, 0);
6826-
if (zstrong_result_returned) {
6827-
ZVAL_FALSE(zstrong_result_returned);
6828-
}
6829-
RETURN_FALSE;
6831+
zend_throw_exception(zend_ce_exception, "Error reading from source device", 0);
6832+
return;
68306833
}
68316834
#else
68326835

@@ -6835,21 +6838,15 @@ PHP_FUNCTION(openssl_random_pseudo_bytes)
68356838
/* FIXME loop if requested size > INT_MAX */
68366839
if (RAND_bytes((unsigned char*)ZSTR_VAL(buffer), (int)buffer_length) <= 0) {
68376840
zend_string_release_ex(buffer, 0);
6838-
if (zstrong_result_returned) {
6839-
ZVAL_FALSE(zstrong_result_returned);
6840-
}
6841-
RETURN_FALSE;
6841+
zend_throw_exception(zend_ce_exception, "Error reading from source device", 0);
6842+
return;
68426843
} else {
68436844
php_openssl_store_errors();
68446845
}
68456846
#endif
68466847

68476848
ZSTR_VAL(buffer)[buffer_length] = 0;
68486849
RETVAL_NEW_STR(buffer);
6849-
6850-
if (zstrong_result_returned) {
6851-
ZVAL_BOOL(zstrong_result_returned, 1);
6852-
}
68536850
}
68546851
/* }}} */
68556852

ext/openssl/tests/openssl_random_pseudo_bytes_basic.phpt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,11 @@ openssl_random_pseudo_bytes() tests
44
<?php if (!extension_loaded("openssl")) print "skip"; ?>
55
--FILE--
66
<?php
7-
for ($i = 0; $i < 10; $i++) {
8-
var_dump(bin2hex(openssl_random_pseudo_bytes($i, $strong)));
7+
for ($i = 1; $i < 10; $i++) {
8+
var_dump(bin2hex(openssl_random_pseudo_bytes($i)));
99
}
10-
1110
?>
1211
--EXPECTF--
13-
string(0) ""
1412
string(2) "%s"
1513
string(4) "%s"
1614
string(6) "%s"
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
Test error operation of openssl_random_pseudo_bytes()
3+
--SKIPIF--
4+
<?php if (!extension_loaded("openssl")) print "skip"; ?>
5+
--FILE--
6+
<?php
7+
try {
8+
openssl_random_pseudo_bytes(0);
9+
} catch (Error $e) {
10+
echo $e->getMessage().PHP_EOL;
11+
}
12+
13+
openssl_random_pseudo_bytes(1, $strong);
14+
?>
15+
--EXPECTF--
16+
Length must be greater than 0
17+
18+
Deprecated: openssl_random_pseudo_bytes(): Calling openssl_random_pseudo_bytes() with the second argument is deprecated in %s on line %d

0 commit comments

Comments
 (0)