Skip to content

Commit 10918f2

Browse files
committed
Updates to JWT decode() / verify() path
1 parent 8049f19 commit 10918f2

File tree

3 files changed

+30
-50
lines changed

3 files changed

+30
-50
lines changed

Authentication/JWT.php

+27-48
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,7 @@
1515
*/
1616
class JWT
1717
{
18-
public static $only_method = 'HS256';
19-
20-
public static $methods = array(
18+
public static $supported_algs = array(
2119
'HS256' => array('hash_hmac', 'SHA256'),
2220
'HS512' => array('hash_hmac', 'SHA512'),
2321
'HS384' => array('hash_hmac', 'SHA384'),
@@ -27,9 +25,9 @@ class JWT
2725
/**
2826
* Decodes a JWT string into a PHP object.
2927
*
30-
* @param string $jwt The JWT
31-
* @param string|Array|null $key The secret key, or map of keys
32-
* @param bool $verify Don't skip verification process
28+
* @param string $jwt The JWT
29+
* @param string|Array|null $key The secret key, or map of keys
30+
* @param bool $algs List of supported verification algorithms
3331
*
3432
* @return object The JWT's payload as a PHP object
3533
*
@@ -43,7 +41,7 @@ class JWT
4341
* @uses jsonDecode
4442
* @uses urlsafeB64Decode
4543
*/
46-
public static function decode($jwt, $key = null, $verify = true)
44+
public static function decode($jwt, $key = null, $algs = array())
4745
{
4846
$tks = explode('.', $jwt);
4947
if (count($tks) != 3) {
@@ -57,10 +55,13 @@ public static function decode($jwt, $key = null, $verify = true)
5755
throw new UnexpectedValueException('Invalid claims encoding');
5856
}
5957
$sig = JWT::urlsafeB64Decode($cryptob64);
60-
if ($verify) {
58+
if (!empty($key)) {
6159
if (empty($header->alg)) {
6260
throw new DomainException('Empty algorithm');
6361
}
62+
if (empty(self::$supported_algs[$header->alg])) {
63+
throw new DomainException('Algorithm not supported');
64+
}
6465
if (is_array($key)) {
6566
if (isset($header->kid)) {
6667
$key = $key[$header->kid];
@@ -105,16 +106,16 @@ public static function decode($jwt, $key = null, $verify = true)
105106
*
106107
* @param object|array $payload PHP object or array
107108
* @param string $key The secret key
108-
* @param string $algo The signing algorithm. Supported
109+
* @param string $alg The signing algorithm. Supported
109110
* algorithms are 'HS256', 'HS384' and 'HS512'
110111
*
111112
* @return string A signed JWT
112113
* @uses jsonEncode
113114
* @uses urlsafeB64Encode
114115
*/
115-
public static function encode($payload, $key, $algo = 'HS256', $keyId = null)
116+
public static function encode($payload, $key, $alg = 'HS256', $keyId = null)
116117
{
117-
$header = array('typ' => 'JWT', 'alg' => $algo);
118+
$header = array('typ' => 'JWT', 'alg' => $alg);
118119
if ($keyId !== null) {
119120
$header['kid'] = $keyId;
120121
}
@@ -123,7 +124,7 @@ public static function encode($payload, $key, $algo = 'HS256', $keyId = null)
123124
$segments[] = JWT::urlsafeB64Encode(JWT::jsonEncode($payload));
124125
$signing_input = implode('.', $segments);
125126

126-
$signature = JWT::sign($signing_input, $key, $algo);
127+
$signature = JWT::sign($signing_input, $key, $alg);
127128
$segments[] = JWT::urlsafeB64Encode($signature);
128129

129130
return implode('.', $segments);
@@ -134,24 +135,24 @@ public static function encode($payload, $key, $algo = 'HS256', $keyId = null)
134135
*
135136
* @param string $msg The message to sign
136137
* @param string|resource $key The secret key
137-
* @param string $method The signing algorithm. Supported algorithms
138+
* @param string $alg The signing algorithm. Supported algorithms
138139
* are 'HS256', 'HS384', 'HS512' and 'RS256'
139140
*
140141
* @return string An encrypted message
141142
* @throws DomainException Unsupported algorithm was specified
142143
*/
143-
public static function sign($msg, $key, $method = 'HS256')
144+
public static function sign($msg, $key, $alg = 'HS256')
144145
{
145-
if (empty(self::$methods[$method])) {
146+
if (empty(self::$supported_algs[$alg])) {
146147
throw new DomainException('Algorithm not supported');
147148
}
148-
list($function, $algo) = self::$methods[$method];
149+
list($function, $algorithm) = self::$supported_algs[$alg];
149150
switch($function) {
150151
case 'hash_hmac':
151-
return hash_hmac($algo, $msg, $key, true);
152+
return hash_hmac($algorithm, $msg, $key, true);
152153
case 'openssl':
153154
$signature = '';
154-
$success = openssl_sign($msg, $signature, $key, $algo);
155+
$success = openssl_sign($msg, $signature, $key, $algorithm);
155156
if (!$success) {
156157
throw new DomainException("OpenSSL unable to sign data");
157158
} else {
@@ -166,32 +167,28 @@ public static function sign($msg, $key, $method = 'HS256')
166167
* @param string $msg the original message
167168
* @param string $signature
168169
* @param string|resource $key for HS*, a string key works. for RS*, must be a resource of an openssl public key
169-
* @param string $method
170+
* @param string $algorithms
170171
* @return bool
171172
* @throws DomainException Invalid Algorithm or OpenSSL failure
172173
*/
173-
public static function verify($msg, $signature, $key, $method = 'HS256')
174+
private static function verify($msg, $signature, $key, $alg)
174175
{
175-
if (empty(self::$methods[$method])) {
176+
if (empty(self::$supported_algs[$alg])) {
176177
throw new DomainException('Algorithm not supported');
177178
}
178-
if (self::$only_method === null) {
179-
throw new DomainException('Algorithm not specified');
180-
} elseif ($method !== self::$only_method) {
181-
throw new DomainException('Incorrect algorithm error');
182-
}
183-
list($function, $algo) = self::$methods[$method];
179+
180+
list($function, $algorithm) = self::$supported_algs[$alg];
184181
switch($function) {
185182
case 'openssl':
186-
$success = openssl_verify($msg, $signature, $key, $algo);
183+
$success = openssl_verify($msg, $signature, $key, $algorithm);
187184
if (!$success) {
188185
throw new DomainException("OpenSSL unable to verify data: " . openssl_error_string());
189186
} else {
190187
return $signature;
191188
}
192189
case 'hash_hmac':
193190
default:
194-
$hash = hash_hmac($algo, $msg, $key, true);
191+
$hash = hash_hmac($algorithm, $msg, $key, true);
195192
if (function_exists('hash_equals')) {
196193
return hash_equals($signature, $hash);
197194
}
@@ -309,7 +306,7 @@ private static function handleJsonError($errno)
309306
: 'Unknown JSON error: ' . $errno
310307
);
311308
}
312-
309+
313310
/**
314311
* Get the number of bytes in cryptographic strings.
315312
*
@@ -323,22 +320,4 @@ private static function safeStrlen($str)
323320
}
324321
return strlen($str);
325322
}
326-
327-
/**
328-
* Set the only allowed method for this server.
329-
*
330-
* @ref https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/
331-
*
332-
* @param string $method array index in self::$methods
333-
*
334-
* @return boolean
335-
*/
336-
public static function setOnlyAllowedMethod($method)
337-
{
338-
if (!empty(self::$methods[$method])) {
339-
self::$only_method = $method;
340-
return true;
341-
}
342-
return false;
343-
}
344323
}

run-tests.sh

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ if [ $? -eq 0 ]; then
2626
echo
2727
echo -e "\033[33mBegin Unit Testing\033[0m"
2828
# Run the testing suite
29+
php --version
2930
php phpunit.phar --configuration phpunit.xml.dist
3031
else
3132
echo

tests/JWTTest.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ public function testRSEncodeDecode()
102102
$privKey = openssl_pkey_new(array('digest_alg' => 'sha256',
103103
'private_key_bits' => 1024,
104104
'private_key_type' => OPENSSL_KEYTYPE_RSA));
105-
JWT::setOnlyAllowedMethod('RS256');
105+
//JWT::setOnlyAllowedMethod('RS256');
106106
$msg = JWT::encode('abc', $privKey, 'RS256');
107107
$pubKey = openssl_pkey_get_details($privKey);
108108
$pubKey = $pubKey['key'];
@@ -113,7 +113,7 @@ public function testRSEncodeDecode()
113113
public function testKIDChooser()
114114
{
115115
$keys = array('1' => 'my_key', '2' => 'my_key2');
116-
JWT::setOnlyAllowedMethod('HS256');
116+
//JWT::setOnlyAllowedMethod('HS256');
117117
$msg = JWT::encode('abc', $keys['1'], 'HS256', '1');
118118
$decoded = JWT::decode($msg, $keys, true);
119119
$this->assertEquals($decoded, 'abc');

0 commit comments

Comments
 (0)