Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parameter Validation + Exceptions (GD, Hash) #4559

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
350 changes: 201 additions & 149 deletions ext/gd/gd.c

Large diffs are not rendered by default.

84 changes: 42 additions & 42 deletions ext/hash/hash.c
Expand Up @@ -129,13 +129,13 @@ static void php_hash_do_hash(INTERNAL_FUNCTION_PARAMETERS, int isfilename, zend_

ops = php_hash_fetch_ops(algo, algo_len);
if (!ops) {
php_error_docref(NULL, E_WARNING, "Unknown hashing algorithm: %s", algo);
RETURN_FALSE;
php_error_parameter_validation(NULL, 0, "Unknown hashing algorithm: %s", algo);
return;
}
if (isfilename) {
if (CHECK_NULL_PATH(data, data_len)) {
php_error_docref(NULL, E_WARNING, "Invalid path");
RETURN_FALSE;
php_error_parameter_validation(NULL, 1, "Invalid path");
return;
}
stream = php_stream_open_wrapper_ex(data, "rb", REPORT_ERRORS, NULL, FG(default_context));
if (!stream) {
Expand Down Expand Up @@ -252,18 +252,18 @@ static void php_hash_do_hash_hmac(INTERNAL_FUNCTION_PARAMETERS, int isfilename,

ops = php_hash_fetch_ops(algo, algo_len);
if (!ops) {
php_error_docref(NULL, E_WARNING, "Unknown hashing algorithm: %s", algo);
RETURN_FALSE;
php_error_parameter_validation(NULL, 0, "Unknown hashing algorithm: %s", algo);
return;
}
else if (!ops->is_crypto) {
php_error_docref(NULL, E_WARNING, "Non-cryptographic hashing algorithm: %s", algo);
RETURN_FALSE;
php_error_parameter_validation(NULL, 0, "Non-cryptographic hashing algorithm: %s", algo);
return;
}

if (isfilename) {
if (CHECK_NULL_PATH(data, data_len)) {
php_error_docref(NULL, E_WARNING, "Invalid path");
RETURN_FALSE;
php_error_parameter_validation(NULL, 1, "Invalid path");
return;
}
stream = php_stream_open_wrapper_ex(data, "rb", REPORT_ERRORS, NULL, FG(default_context));
if (!stream) {
Expand Down Expand Up @@ -358,19 +358,19 @@ PHP_FUNCTION(hash_init)

ops = php_hash_fetch_ops(ZSTR_VAL(algo), ZSTR_LEN(algo));
if (!ops) {
php_error_docref(NULL, E_WARNING, "Unknown hashing algorithm: %s", ZSTR_VAL(algo));
RETURN_FALSE;
php_error_parameter_validation(NULL, 0, "Unknown hashing algorithm: %s", ZSTR_VAL(algo));
return;
}

if (options & PHP_HASH_HMAC) {
if (!ops->is_crypto) {
php_error_docref(NULL, E_WARNING, "HMAC requested with a non-cryptographic hashing algorithm: %s", ZSTR_VAL(algo));
RETURN_FALSE;
php_error_parameter_validation(NULL, 0, "HMAC requested with a non-cryptographic hashing algorithm: %s", ZSTR_VAL(algo));
return;
}
if (!key || (ZSTR_LEN(key) == 0)) {
/* Note: a zero length key is no key at all */
php_error_docref(NULL, E_WARNING, "HMAC requested without a key");
RETURN_FALSE;
php_error_parameter_validation(NULL, 2, "HMAC requested without a key");
return;
}
}

Expand Down Expand Up @@ -637,28 +637,28 @@ PHP_FUNCTION(hash_hkdf)

ops = php_hash_fetch_ops(ZSTR_VAL(algo), ZSTR_LEN(algo));
if (!ops) {
php_error_docref(NULL, E_WARNING, "Unknown hashing algorithm: %s", ZSTR_VAL(algo));
RETURN_FALSE;
php_error_parameter_validation(NULL, 0, "Unknown hashing algorithm: %s", ZSTR_VAL(algo));
return;
}

if (!ops->is_crypto) {
php_error_docref(NULL, E_WARNING, "Non-cryptographic hashing algorithm: %s", ZSTR_VAL(algo));
RETURN_FALSE;
php_error_parameter_validation(NULL, 0, "Non-cryptographic hashing algorithm: %s", ZSTR_VAL(algo));
return;
}

if (ZSTR_LEN(ikm) == 0) {
php_error_docref(NULL, E_WARNING, "Input keying material cannot be empty");
RETURN_FALSE;
php_error_parameter_validation(NULL, 1, "Input keying material cannot be empty");
return;
}

if (length < 0) {
php_error_docref(NULL, E_WARNING, "Length must be greater than or equal to 0: " ZEND_LONG_FMT, length);
RETURN_FALSE;
php_error_parameter_validation(NULL, 2, "Length must be greater than or equal to 0: " ZEND_LONG_FMT, length);
return;
} else if (length == 0) {
length = ops->digest_size;
} else if (length > (zend_long) (ops->digest_size * 255)) {
php_error_docref(NULL, E_WARNING, "Length must be less than or equal to %zd: " ZEND_LONG_FMT, ops->digest_size * 255, length);
RETURN_FALSE;
php_error_parameter_validation(NULL, 2, "Length must be less than or equal to %zd: " ZEND_LONG_FMT, ops->digest_size * 255, length);
return;
}

context = emalloc(ops->context_size);
Expand Down Expand Up @@ -737,27 +737,27 @@ PHP_FUNCTION(hash_pbkdf2)

ops = php_hash_fetch_ops(algo, algo_len);
if (!ops) {
php_error_docref(NULL, E_WARNING, "Unknown hashing algorithm: %s", algo);
RETURN_FALSE;
php_error_parameter_validation(NULL, 0, "Unknown hashing algorithm: %s", algo);
return;
}
else if (!ops->is_crypto) {
php_error_docref(NULL, E_WARNING, "Non-cryptographic hashing algorithm: %s", algo);
RETURN_FALSE;
php_error_parameter_validation(NULL, 0, "Non-cryptographic hashing algorithm: %s", algo);
return;
}

if (iterations <= 0) {
php_error_docref(NULL, E_WARNING, "Iterations must be a positive integer: " ZEND_LONG_FMT, iterations);
RETURN_FALSE;
php_error_parameter_validation(NULL, 3, "Iterations must be a positive integer: " ZEND_LONG_FMT, iterations);
return;
}

if (length < 0) {
php_error_docref(NULL, E_WARNING, "Length must be greater than or equal to 0: " ZEND_LONG_FMT, length);
RETURN_FALSE;
php_error_parameter_validation(NULL, 4, "Length must be greater than or equal to 0: " ZEND_LONG_FMT, length);
return;
}

if (salt_len > INT_MAX - 4) {
php_error_docref(NULL, E_WARNING, "Supplied salt is too long, max of INT_MAX - 4 bytes: %zd supplied", salt_len);
RETURN_FALSE;
php_error_parameter_validation(NULL, 2, "Supplied salt is too long, max of INT_MAX - 4 bytes: %zd supplied", salt_len);
return;
}

context = emalloc(ops->context_size);
Expand Down Expand Up @@ -862,13 +862,13 @@ PHP_FUNCTION(hash_equals)

/* We only allow comparing string to prevent unexpected results. */
if (Z_TYPE_P(known_zval) != IS_STRING) {
php_error_docref(NULL, E_WARNING, "Expected known_string to be a string, %s given", zend_zval_type_name(known_zval));
RETURN_FALSE;
php_error_parameter_validation(NULL, 0, "Expected known_string to be a string, %s given", zend_zval_type_name(known_zval));
return;
}

if (Z_TYPE_P(user_zval) != IS_STRING) {
php_error_docref(NULL, E_WARNING, "Expected user_string to be a string, %s given", zend_zval_type_name(user_zval));
RETURN_FALSE;
php_error_parameter_validation(NULL, 1, "Expected user_string to be a string, %s given", zend_zval_type_name(user_zval));
return;
}

if (Z_STRLEN_P(known_zval) != Z_STRLEN_P(user_zval)) {
Expand Down Expand Up @@ -1052,8 +1052,8 @@ PHP_FUNCTION(mhash_keygen_s2k)

bytes = (int)l_bytes;
if (bytes <= 0){
php_error_docref(NULL, E_WARNING, "the byte parameter must be greater than 0");
RETURN_FALSE;
php_error_parameter_validation(NULL, 3, "The byte parameter must be greater than 0");
return;
}

salt_len = MIN(salt_len, SALT_SIZE);
Expand Down
12 changes: 12 additions & 0 deletions ext/hash/tests/exceptional.inc
@@ -0,0 +1,12 @@
<?php

function trycatch_dump($x) {
try {
$result = $x();
var_dump($result);

}
catch (\Throwable $ex) {
echo '[' . get_class($ex) . '] ' . $ex->getMessage() . "\n";
}
}
56 changes: 24 additions & 32 deletions ext/hash/tests/hash_equals.phpt
Expand Up @@ -2,43 +2,35 @@
Hash: hash_equals() test
--FILE--
<?php
var_dump(hash_equals("same", "same"));
var_dump(hash_equals("not1same", "not2same"));
var_dump(hash_equals("short", "longer"));
var_dump(hash_equals("longer", "short"));
var_dump(hash_equals("", "notempty"));
var_dump(hash_equals("notempty", ""));
var_dump(hash_equals("", ""));
var_dump(hash_equals(123, "NaN"));
var_dump(hash_equals("NaN", 123));
var_dump(hash_equals(123, 123));
var_dump(hash_equals(null, ""));
var_dump(hash_equals(null, 123));
var_dump(hash_equals(null, null));

require_once __DIR__ . '/exceptional.inc';

trycatch_dump(fn() => hash_equals("same", "same"));
trycatch_dump(fn() => hash_equals("not1same", "not2same"));
trycatch_dump(fn() => hash_equals("short", "longer"));
trycatch_dump(fn() => hash_equals("longer", "short"));
trycatch_dump(fn() => hash_equals("", "notempty"));
trycatch_dump(fn() => hash_equals("notempty", ""));
trycatch_dump(fn() => hash_equals("", ""));
trycatch_dump(fn() => hash_equals(123, "NaN"));
trycatch_dump(fn() => hash_equals("NaN", 123));
trycatch_dump(fn() => hash_equals(123, 123));
trycatch_dump(fn() => hash_equals(null, ""));
trycatch_dump(fn() => hash_equals(null, 123));
trycatch_dump(fn() => hash_equals(null, null));

?>
--EXPECTF--
--EXPECT--
bool(true)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(true)

Warning: hash_equals(): Expected known_string to be a string, int given in %s on line %d
bool(false)

Warning: hash_equals(): Expected user_string to be a string, int given in %s on line %d
bool(false)

Warning: hash_equals(): Expected known_string to be a string, int given in %s on line %d
bool(false)

Warning: hash_equals(): Expected known_string to be a string, null given in %s on line %d
bool(false)

Warning: hash_equals(): Expected known_string to be a string, null given in %s on line %d
bool(false)

Warning: hash_equals(): Expected known_string to be a string, null given in %s on line %d
bool(false)
[ErrorException] Parameter 1 is invalid: Expected known_string to be a string, int given
[ErrorException] Parameter 2 is invalid: Expected user_string to be a string, int given
[ErrorException] Parameter 1 is invalid: Expected known_string to be a string, int given
[ErrorException] Parameter 1 is invalid: Expected known_string to be a string, null given
[ErrorException] Parameter 1 is invalid: Expected known_string to be a string, null given
[ErrorException] Parameter 1 is invalid: Expected known_string to be a string, null given
12 changes: 5 additions & 7 deletions ext/hash/tests/hash_error.phpt
Expand Up @@ -3,6 +3,8 @@ Hash: hash() function : error conditions
--FILE--
<?php

require_once __DIR__ . '/exceptional.php';

/* Prototype : string hash ( string $algo , string $data [, bool $raw_output ] )
* Description: Generate a hash value (message digest)
* Source code: ext/hash/hash.c
Expand All @@ -11,15 +13,11 @@ Hash: hash() function : error conditions
echo "*** Testing hash() : error conditions ***\n";

echo "\n-- Testing hash() function with invalid hash algorithm --\n";
var_dump(hash('foo', ''));
trycatch_dump(fn() => hash('foo', ''));

?>
===Done===
--EXPECTF--
*** Testing hash() : error conditions ***

-- Testing hash() function with invalid hash algorithm --
Warning: require_once(/mnt/c/users/mark/source/repos/local-php-src/src/ext/hash/tests/exceptional.php): failed to open stream: No such file or directory in %s on line %d

Warning: hash(): Unknown hashing algorithm: foo in %s on line %d
bool(false)
===Done===
Fatal error: require_once(): Failed opening required '/mnt/c/users/mark/source/repos/local-php-src/src/ext/hash/tests/exceptional.php' (include_path='.:') in %s on line %d
13 changes: 7 additions & 6 deletions ext/hash/tests/hash_file_error.phpt
Expand Up @@ -4,6 +4,9 @@ Hash: hash_file() function : error conditions
Felix De Vliegher <felix.devliegher@gmail.com>
--FILE--
<?php

require_once __DIR__ . '/exceptional.inc';

/* Prototype : string hash_file(string algo, string filename[, bool raw_output = false])
* Description: Generate a hash of a given file
* Source code: ext/hash/hash.c
Expand All @@ -19,10 +22,10 @@ file_put_contents( $filename, 'The quick brown fox jumped over the lazy dog.' );

// hash_file() error tests
echo "\n-- Testing hash_file() function with an unknown algorithm --\n";
var_dump( hash_file( 'foobar', $filename ) );
trycatch_dump(fn() => hash_file( 'foobar', $filename ) );

echo "\n-- Testing hash_file() function with a non-existent file --\n";
var_dump( hash_file( 'md5', 'nonexistent.txt' ) );
trycatch_dump(fn() => hash_file( 'md5', 'nonexistent.txt' ) );

?>
===DONE===
Expand All @@ -37,12 +40,10 @@ unlink( $filename );
*** Testing hash_file() : error conditions ***

-- Testing hash_file() function with an unknown algorithm --

Warning: hash_file(): Unknown hashing algorithm: %s in %s on line %d
bool(false)
[ErrorException] Parameter 1 is invalid: Unknown hashing algorithm: foobar

-- Testing hash_file() function with a non-existent file --

Warning: hash_file(%s): failed to open stream: No such file or directory in %s on line %d
Warning: hash_file(nonexistent.txt): failed to open stream: No such file or directory in %s on line %d
bool(false)
===DONE===
9 changes: 5 additions & 4 deletions ext/hash/tests/hash_hkdf_edges.phpt
Expand Up @@ -3,6 +3,8 @@ Hash: hash_hkdf() function: edge cases
--FILE--
<?php

require_once __DIR__ . '/exceptional.inc';

/* Prototype : string hkdf ( string $algo , string $ikm [, int $length , string $info = '' , string $salt = '' ] )
* Description: HMAC-based Key Derivation Function
* Source code: ext/hash/hash.c
Expand All @@ -16,7 +18,8 @@ echo 'Length < digestSize: ', bin2hex(hash_hkdf('md5', $ikm, 7)), "\n";
echo 'Length % digestSize != 0: ', bin2hex(hash_hkdf('md5', $ikm, 17)), "\n";
echo 'Algo name case-sensitivity: ', (bin2hex(hash_hkdf('Md5', $ikm, 7)) === '98b16391063ece' ? 'true' : 'false'), "\n";
echo "Non-crypto algo name case-sensitivity:\n";
var_dump(hash_hkdf('jOaAt', $ikm));

trycatch_dump(fn() => hash_hkdf('jOaAt', $ikm));

?>
--EXPECTF--
Expand All @@ -25,6 +28,4 @@ Length < digestSize: 98b16391063ece
Length % digestSize != 0: 98b16391063ecee006a3ca8ee5776b1e5f
Algo name case-sensitivity: true
Non-crypto algo name case-sensitivity:

Warning: hash_hkdf(): Non-cryptographic hashing algorithm: jOaAt in %s on line %d
bool(false)
[ErrorException] Parameter 1 is invalid: Non-cryptographic hashing algorithm: jOaAt