Skip to content

Commit 6e67bad

Browse files
Return false for hash_hmac/hash_hmac_file on invalid algorithm
1 parent d77bd87 commit 6e67bad

File tree

5 files changed

+145
-1
lines changed

5 files changed

+145
-1
lines changed

conf/config.neon

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -875,6 +875,10 @@ services:
875875
class: PHPStan\Type\Php\GettimeofdayDynamicFunctionReturnTypeExtension
876876
tags:
877877
- phpstan.broker.dynamicFunctionReturnTypeExtension
878+
-
879+
class: PHPStan\Type\Php\HashHmacFunctionsReturnTypeExtension
880+
tags:
881+
- phpstan.broker.dynamicFunctionReturnTypeExtension
878882

879883
-
880884
class: PHPStan\Type\Php\SimpleXMLElementClassPropertyReflectionExtension

resources/functionMap.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3915,7 +3915,7 @@
39153915
'hash_hkdf' => ['string', 'algo'=>'string', 'ikm'=>'string', 'length='=>'int', 'info='=>'string', 'salt='=>'string'],
39163916
'hash_hmac' => ['string', 'algo'=>'string', 'data'=>'string', 'key'=>'string', 'raw_output='=>'bool'],
39173917
'hash_hmac_algos' => ['array<int,string>'],
3918-
'hash_hmac_file' => ['string', 'algo'=>'string', 'filename'=>'string', 'key'=>'string', 'raw_output='=>'bool'],
3918+
'hash_hmac_file' => ['string|false', 'algo'=>'string', 'filename'=>'string', 'key'=>'string', 'raw_output='=>'bool'],
39193919
'hash_init' => ['HashContext', 'algo'=>'string', 'options='=>'int', 'key='=>'string'],
39203920
'hash_pbkdf2' => ['string', 'algo'=>'string', 'password'=>'string', 'salt'=>'string', 'iterations'=>'int', 'length='=>'int', 'raw_output='=>'bool'],
39213921
'hash_update' => ['bool', 'context'=>'HashContext', 'data'=>'string'],
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Type\Php;
4+
5+
use PhpParser\Node\Expr\FuncCall;
6+
use PHPStan\Analyser\Scope;
7+
use PHPStan\Reflection\FunctionReflection;
8+
use PHPStan\Reflection\ParametersAcceptorSelector;
9+
use PHPStan\Type\Constant\ConstantBooleanType;
10+
use PHPStan\Type\DynamicFunctionReturnTypeExtension;
11+
use PHPStan\Type\MixedType;
12+
use PHPStan\Type\Type;
13+
use PHPStan\Type\TypeUtils;
14+
15+
final class HashHmacFunctionsReturnTypeExtension implements DynamicFunctionReturnTypeExtension
16+
{
17+
18+
private const HMAC_ALGORITHMS = [
19+
'md2',
20+
'md4',
21+
'md5',
22+
'sha1',
23+
'sha224',
24+
'sha256',
25+
'sha384',
26+
'sha512/224',
27+
'sha512/256',
28+
'sha512',
29+
'sha3-224',
30+
'sha3-256',
31+
'sha3-384',
32+
'sha3-512',
33+
'ripemd128',
34+
'ripemd160',
35+
'ripemd256',
36+
'ripemd320',
37+
'whirlpool',
38+
'tiger128,3',
39+
'tiger160,3',
40+
'tiger192,3',
41+
'tiger128,4',
42+
'tiger160,4',
43+
'tiger192,4',
44+
'snefru',
45+
'snefru256',
46+
'gost',
47+
'gost-crypto',
48+
'haval128,3',
49+
'haval160,3',
50+
'haval192,3',
51+
'haval224,3',
52+
'haval256,3',
53+
'haval128,4',
54+
'haval160,4',
55+
'haval192,4',
56+
'haval224,4',
57+
'haval256,4',
58+
'haval128,5',
59+
'haval160,5',
60+
'haval192,5',
61+
'haval224,5',
62+
'haval256,5',
63+
];
64+
65+
public function isFunctionSupported(FunctionReflection $functionReflection): bool
66+
{
67+
return in_array($functionReflection->getName(), ['hash_hmac', 'hash_hmac_file'], true);
68+
}
69+
70+
public function getTypeFromFunctionCall(FunctionReflection $functionReflection, FuncCall $functionCall, Scope $scope): Type
71+
{
72+
$defaultReturnType = ParametersAcceptorSelector::selectSingle($functionReflection->getVariants())->getReturnType();
73+
74+
$argType = $scope->getType($functionCall->args[0]->value);
75+
if ($argType instanceof MixedType) {
76+
return TypeUtils::toBenevolentUnion($defaultReturnType);
77+
}
78+
79+
$values = TypeUtils::getConstantStrings($argType);
80+
if (count($values) !== 1) {
81+
return TypeUtils::toBenevolentUnion($defaultReturnType);
82+
}
83+
$string = $values[0];
84+
85+
return in_array($string->getValue(), self::HMAC_ALGORITHMS, true) ? $defaultReturnType : new ConstantBooleanType(false);
86+
}
87+
88+
}

tests/PHPStan/Analyser/NodeScopeResolverTest.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5905,6 +5905,46 @@ public function dataFunctions(): array
59055905
'array<int, string>|int|false',
59065906
'$strWordCountStrTypeIndeterminant',
59075907
],
5908+
[
5909+
'string',
5910+
'$hashHmacMd5',
5911+
],
5912+
[
5913+
'string',
5914+
'$hashHmacSha256',
5915+
],
5916+
[
5917+
'false',
5918+
'$hashHmacNonCryptographic',
5919+
],
5920+
[
5921+
'false',
5922+
'$hashHmacRandom',
5923+
],
5924+
[
5925+
'string',
5926+
'$hashHmacVariable',
5927+
],
5928+
[
5929+
'string|false',
5930+
'$hashHmacFileMd5',
5931+
],
5932+
[
5933+
'string|false',
5934+
'$hashHmacFileSha256',
5935+
],
5936+
[
5937+
'false',
5938+
'$hashHmacFileNonCryptographic',
5939+
],
5940+
[
5941+
'false',
5942+
'$hashHmacFileRandom',
5943+
],
5944+
[
5945+
'(string|false)',
5946+
'$hashHmacFileVariable',
5947+
],
59085948
];
59095949
}
59105950

tests/PHPStan/Analyser/data/functions.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,4 +123,16 @@
123123
$integer = doFoo();
124124
$strWordCountStrTypeIndeterminant = str_word_count('string', $integer);
125125

126+
$hashHmacMd5 = hash_hmac('md5', 'data', 'key');
127+
$hashHmacSha256 = hash_hmac('sha256', 'data', 'key');
128+
$hashHmacNonCryptographic = hash_hmac('crc32', 'data', 'key');
129+
$hashHmacRandom = hash_hmac('random', 'data', 'key');
130+
$hashHmacVariable = hash_hmac($string, 'data', 'key');
131+
132+
$hashHmacFileMd5 = hash_hmac_file('md5', 'data', 'key');
133+
$hashHmacFileSha256 = hash_hmac_file('sha256', 'data', 'key');
134+
$hashHmacFileNonCryptographic = hash_hmac_file('crc32', 'data', 'key');
135+
$hashHmacFileRandom = hash_hmac_file('random', 'data', 'key');
136+
$hashHmacFileVariable = hash_hmac_file($string, 'data', 'key');
137+
126138
die;

0 commit comments

Comments
 (0)