5
5
use ArrayAccess ;
6
6
use DomainException ;
7
7
use Exception ;
8
- use Firebase \JWT \Keys \JWTKey ;
9
- use Firebase \JWT \Keys \Keyring ;
10
8
use InvalidArgumentException ;
11
9
use UnexpectedValueException ;
12
10
use DateTime ;
@@ -61,9 +59,9 @@ class JWT
61
59
* Decodes a JWT string into a PHP object.
62
60
*
63
61
* @param string $jwt The JWT
64
- * @param string |array|resource $key The key, or map of keys .
62
+ * @param Key |array<Key> $key The Key or array of Key objects .
65
63
* If the algorithm used is asymmetric, this is the public key
66
- * @param array $allowed_algs List of supported verification algorithms
64
+ * Each Key object contains an algorithm and matching key.
67
65
* Supported algorithms are 'ES384','ES256', 'HS256', 'HS384',
68
66
* 'HS512', 'RS256', 'RS384', and 'RS512'
69
67
*
@@ -79,13 +77,10 @@ class JWT
79
77
* @uses jsonDecode
80
78
* @uses urlsafeB64Decode
81
79
*/
82
- public static function decode ($ jwt , $ key , array $ allowed_algs = array () )
80
+ public static function decode ($ jwt , $ keyOrArrayOfKeys )
83
81
{
82
+ // Validate JWT
84
83
$ timestamp = \is_null (static ::$ timestamp ) ? \time () : static ::$ timestamp ;
85
-
86
- if (empty ($ key )) {
87
- throw new InvalidArgumentException ('Key may not be empty ' );
88
- }
89
84
$ tks = \explode ('. ' , $ jwt );
90
85
if (\count ($ tks ) != 3 ) {
91
86
throw new UnexpectedValueException ('Wrong number of segments ' );
@@ -106,35 +101,45 @@ public static function decode($jwt, $key, array $allowed_algs = array())
106
101
if (empty (static ::$ supported_algs [$ header ->alg ])) {
107
102
throw new UnexpectedValueException ('Algorithm not supported ' );
108
103
}
109
- if (!\in_array ($ header ->alg , $ allowed_algs )) {
110
- throw new UnexpectedValueException ('Algorithm not allowed ' );
111
- }
112
- if ($ header ->alg === 'ES256 ' || $ header ->alg === 'ES384 ' ) {
113
- // OpenSSL expects an ASN.1 DER sequence for ES256/ES384 signatures
114
- $ sig = self ::signatureToDER ($ sig );
104
+
105
+ // Validate the key
106
+ if (empty ($ keyOrArrayOfKeys )) {
107
+ throw new InvalidArgumentException ('$keyOrArrayOfKeys may not be empty ' );
115
108
}
116
109
117
- /** @var Keyring|JWTKey $key */
118
- $ key = self :: getKeyType ( $ key , $ allowed_algs ) ;
119
- if ( $ key instanceof Keyring ) {
120
- if ( isset ( $ header -> kid ) ) {
121
- if (!isset ( $ key[ $ header -> kid ]) ) {
122
- throw new UnexpectedValueException ( ' "kid" invalid, unable to lookup correct key ' );
110
+ if ( $ keyOrArrayOfKeys instanceof Key) {
111
+ $ key = $ keyOrArrayOfKeys ;
112
+ } elseif ( is_array ( $ keyOrArrayOfKeys ) || $ keyOrArrayOfKeys instanceof ArrayAccess ) {
113
+ foreach ( $ keyOrArrayOfKeys as $ kid => $ key ) {
114
+ if (!$ key instanceof Key ) {
115
+ throw new InvalidArgumentException ( ' Type error: array values in $keyOrArrayOfKeys must be instances of Key ' );
123
116
}
124
- $ key = $ key [$ header ->kid ];
125
- } else {
117
+ }
118
+
119
+ if (!isset ($ header ->kid )) {
126
120
throw new UnexpectedValueException ('"kid" empty, unable to lookup correct key ' );
127
121
}
128
- }
129
- if (!($ key instanceof JWTKey)) {
130
- throw new UnexpectedValueException ('$key should be an instance of JWTKey ' );
122
+ if (!isset ($ keyOrArrayOfKeys [$ header ->kid ])) {
123
+ throw new UnexpectedValueException ('"kid" invalid, unable to lookup correct key ' );
124
+ }
125
+ $ key = $ keyOrArrayOfKeys [$ header ->kid ];
126
+ } else {
127
+ throw new UnexpectedValueException (
128
+ '$keyOrArrayOfKeys must be an instance of Firebase\JWT\Key or an array of Firebase\JWT\Key objects '
129
+ );
131
130
}
132
131
133
- // Check the signature
134
- if (!$ key ->isValidForAlg ( $ header ->alg )) {
132
+ // Check the algorithm
133
+ if (!self :: constantTimeEquals ( $ key ->getAlgorithm (), $ header ->alg )) {
135
134
// See issue #351
136
135
throw new UnexpectedValueException ('Incorrect key for this algorithm ' );
137
136
}
137
+
138
+ // Check the signature
139
+ if ($ header ->alg === 'ES256 ' || $ header ->alg === 'ES384 ' ) {
140
+ // OpenSSL expects an ASN.1 DER sequence for ES256/ES384 signatures
141
+ $ sig = self ::signatureToDER ($ sig );
142
+ }
138
143
if (!static ::verify ("$ headb64. $ bodyb64 " , $ sig , $ key ->getKeyMaterial (), $ header ->alg )) {
139
144
throw new SignatureInvalidException ('Signature verification failed ' );
140
145
}
@@ -406,29 +411,6 @@ public static function constantTimeEquals($left, $right)
406
411
return ($ status === 0 );
407
412
}
408
413
409
- /**
410
- * @param string|array|ArrayAccess $oldType
411
- * @param string[] $algs
412
- * @return KeyInterface
413
- */
414
- public static function getKeyType ($ oldType , $ algs )
415
- {
416
- if ($ oldType instanceof KeyInterface) {
417
- return $ oldType ;
418
- }
419
- if (is_string ($ oldType )) {
420
- return new JWTKey ($ oldType , $ algs );
421
- }
422
- if (is_array ($ oldType ) || $ oldType instanceof ArrayAccess) {
423
- $ keyring = new Keyring (array ());
424
- foreach ($ oldType as $ kid => $ key ) {
425
- $ keyring [$ kid ] = new JWTKey ($ key , $ algs );
426
- }
427
- return $ keyring ;
428
- }
429
- throw new InvalidArgumentException ('Invalid type: Must be string or array ' );
430
- }
431
-
432
414
/**
433
415
* Helper method to create a JSON error.
434
416
*
@@ -459,7 +441,7 @@ private static function handleJsonError($errno)
459
441
*
460
442
* @return int
461
443
*/
462
- public static function safeStrlen ($ str )
444
+ private static function safeStrlen ($ str )
463
445
{
464
446
if (\function_exists ('mb_strlen ' )) {
465
447
return \mb_strlen ($ str , '8bit ' );
0 commit comments