25
25
*/
26
26
class JWT
27
27
{
28
- const ASN1_INTEGER = 0x02 ;
29
- const ASN1_SEQUENCE = 0x10 ;
30
- const ASN1_BIT_STRING = 0x03 ;
28
+ // const ASN1_INTEGER = 0x02;
29
+ // const ASN1_SEQUENCE = 0x10;
30
+ // const ASN1_BIT_STRING = 0x03;
31
+ private static $ asn1Integer = 0x02 ;
32
+ private static $ asn1Sequence = 0x10 ;
33
+ private static $ asn1BitString = 0x03 ;
31
34
32
35
/**
33
36
* When checking nbf, iat or expiration times,
@@ -60,13 +63,11 @@ class JWT
60
63
* Decodes a JWT string into a PHP object.
61
64
*
62
65
* @param string $jwt The JWT
63
- * @param Key|array<Key>|mixed $keyOrKeyArray The Key or array of Key objects.
66
+ * @param Key|array<Key> $keyOrKeyArray The Key or array of Key objects.
64
67
* If the algorithm used is asymmetric, this is the public key
65
68
* Each Key object contains an algorithm and matching key.
66
69
* Supported algorithms are 'ES384','ES256', 'HS256', 'HS384',
67
70
* 'HS512', 'RS256', 'RS384', and 'RS512'
68
- * @param array $allowed_algs [DEPRECATED] List of supported verification algorithms. Only
69
- * should be used for backwards compatibility.
70
71
*
71
72
* @return object The JWT's payload as a PHP object
72
73
*
@@ -81,8 +82,9 @@ class JWT
81
82
* @uses jsonDecode
82
83
* @uses urlsafeB64Decode
83
84
*/
84
- public static function decode ($ jwt , $ keyOrKeyArray, array $ allowed_algs = array () )
85
+ public static function decode ($ jwt , $ keyOrKeyArray )
85
86
{
87
+ // Validate JWT
86
88
$ timestamp = \is_null (static ::$ timestamp ) ? \time () : static ::$ timestamp ;
87
89
88
90
if (empty ($ keyOrKeyArray )) {
@@ -109,31 +111,18 @@ public static function decode($jwt, $keyOrKeyArray, array $allowed_algs = array(
109
111
throw new UnexpectedValueException ('Algorithm not supported ' );
110
112
}
111
113
112
- list ($ keyMaterial , $ algorithm ) = self ::getKeyMaterialAndAlgorithm (
113
- $ keyOrKeyArray ,
114
- empty ($ header ->kid ) ? null : $ header ->kid
115
- );
114
+ $ key = self ::getKey ($ keyOrKeyArray , empty ($ header ->kid ) ? null : $ header ->kid );
116
115
117
- if (empty ($ algorithm )) {
118
- // Use deprecated "allowed_algs" to determine if the algorithm is supported.
119
- // This opens up the possibility of an attack in some implementations.
120
- // @see https://github.com/firebase/php-jwt/issues/351
121
- if (!\in_array ($ header ->alg , $ allowed_algs )) {
122
- throw new UnexpectedValueException ('Algorithm not allowed ' );
123
- }
124
- } else {
125
- // Check the algorithm
126
- if (!self ::constantTimeEquals ($ algorithm , $ header ->alg )) {
127
- // See issue #351
128
- throw new UnexpectedValueException ('Incorrect key for this algorithm ' );
129
- }
116
+ // Check the algorithm
117
+ if (!self ::constantTimeEquals ($ key ->getAlgorithm (), $ header ->alg )) {
118
+ // See issue #351
119
+ throw new UnexpectedValueException ('Incorrect key for this algorithm ' );
130
120
}
131
121
if ($ header ->alg === 'ES256 ' || $ header ->alg === 'ES384 ' ) {
132
122
// OpenSSL expects an ASN.1 DER sequence for ES256/ES384 signatures
133
123
$ sig = self ::signatureToDER ($ sig );
134
124
}
135
-
136
- if (!static ::verify ("$ headb64. $ bodyb64 " , $ sig , $ keyMaterial , $ header ->alg )) {
125
+ if (!static ::verify ("$ headb64. $ bodyb64 " , $ sig , $ key ->getKeyMaterial (), $ header ->alg )) {
137
126
throw new SignatureInvalidException ('Signature verification failed ' );
138
127
}
139
128
@@ -179,7 +168,7 @@ public static function decode($jwt, $keyOrKeyArray, array $allowed_algs = array(
179
168
* @uses jsonEncode
180
169
* @uses urlsafeB64Encode
181
170
*/
182
- public static function encode ($ payload , $ key , $ alg = ' HS256 ' , $ keyId = null , $ head = null )
171
+ public static function encode ($ payload , $ key , $ alg , $ keyId = null , $ head = null )
183
172
{
184
173
$ header = array ('typ ' => 'JWT ' , 'alg ' => $ alg );
185
174
if ($ keyId !== null ) {
@@ -212,7 +201,7 @@ public static function encode($payload, $key, $alg = 'HS256', $keyId = null, $he
212
201
*
213
202
* @throws DomainException Unsupported algorithm or bad key was specified
214
203
*/
215
- public static function sign ($ msg , $ key , $ alg = ' HS256 ' )
204
+ public static function sign ($ msg , $ key , $ alg )
216
205
{
217
206
if (empty (static ::$ supported_algs [$ alg ])) {
218
207
throw new DomainException ('Algorithm not supported ' );
@@ -345,7 +334,12 @@ public static function jsonDecode($input)
345
334
*/
346
335
public static function jsonEncode ($ input )
347
336
{
348
- $ json = \json_encode ($ input );
337
+ if (PHP_VERSION_ID >= 50400 ) {
338
+ $ json = \json_encode ($ input , \JSON_UNESCAPED_SLASHES );
339
+ } else {
340
+ // PHP 5.3 only
341
+ $ json = \json_encode ($ input );
342
+ }
349
343
if ($ errno = \json_last_error ()) {
350
344
static ::handleJsonError ($ errno );
351
345
} elseif ($ json === 'null ' && $ input !== null ) {
@@ -394,40 +388,34 @@ public static function urlsafeB64Encode($input)
394
388
*
395
389
* @return array containing the keyMaterial and algorithm
396
390
*/
397
- private static function getKeyMaterialAndAlgorithm ($ keyOrKeyArray , $ kid = null )
391
+ private static function getKey ($ keyOrKeyArray , $ kid = null )
398
392
{
399
- if (
400
- is_string ($ keyOrKeyArray )
401
- || is_resource ($ keyOrKeyArray )
402
- || $ keyOrKeyArray instanceof OpenSSLAsymmetricKey
403
- ) {
404
- return array ($ keyOrKeyArray , null );
405
- }
406
-
407
393
if ($ keyOrKeyArray instanceof Key) {
408
- return array ( $ keyOrKeyArray-> getKeyMaterial (), $ keyOrKeyArray -> getAlgorithm ()) ;
394
+ return $ keyOrKeyArray ;
409
395
}
410
396
411
397
if (is_array ($ keyOrKeyArray ) || $ keyOrKeyArray instanceof ArrayAccess) {
398
+ foreach ($ keyOrKeyArray as $ keyId => $ key ) {
399
+ if (!$ key instanceof Key) {
400
+ throw new UnexpectedValueException (
401
+ '$keyOrKeyArray must be an instance of Firebase\JWT\Key key or an '
402
+ . 'array of Firebase\JWT\Key keys '
403
+ );
404
+ }
405
+ }
412
406
if (!isset ($ kid )) {
413
407
throw new UnexpectedValueException ('"kid" empty, unable to lookup correct key ' );
414
408
}
415
409
if (!isset ($ keyOrKeyArray [$ kid ])) {
416
410
throw new UnexpectedValueException ('"kid" invalid, unable to lookup correct key ' );
417
411
}
418
412
419
- $ key = $ keyOrKeyArray [$ kid ];
420
-
421
- if ($ key instanceof Key) {
422
- return array ($ key ->getKeyMaterial (), $ key ->getAlgorithm ());
423
- }
424
-
425
- return array ($ key , null );
413
+ return $ keyOrKeyArray [$ kid ];
426
414
}
427
415
428
416
throw new UnexpectedValueException (
429
- '$keyOrKeyArray must be a string|resource key, an array of string|resource keys, '
430
- . 'an instance of Firebase\JWT\Key key or an array of Firebase\JWT\Key keys '
417
+ '$keyOrKeyArray must be an instance of Firebase\JWT\Key key or an '
418
+ . 'array of Firebase\JWT\Key keys '
431
419
);
432
420
}
433
421
@@ -515,9 +503,9 @@ private static function signatureToDER($sig)
515
503
}
516
504
517
505
return self ::encodeDER (
518
- self ::ASN1_SEQUENCE ,
519
- self ::encodeDER (self ::ASN1_INTEGER , $ r ) .
520
- self ::encodeDER (self ::ASN1_INTEGER , $ s )
506
+ self ::$ asn1Sequence ,
507
+ self ::encodeDER (self ::$ asn1Integer , $ r ) .
508
+ self ::encodeDER (self ::$ asn1Integer , $ s )
521
509
);
522
510
}
523
511
@@ -531,7 +519,7 @@ private static function signatureToDER($sig)
531
519
private static function encodeDER ($ type , $ value )
532
520
{
533
521
$ tag_header = 0 ;
534
- if ($ type === self ::ASN1_SEQUENCE ) {
522
+ if ($ type === self ::$ asn1Sequence ) {
535
523
$ tag_header |= 0x20 ;
536
524
}
537
525
@@ -596,7 +584,7 @@ private static function readDER($der, $offset = 0)
596
584
}
597
585
598
586
// Value
599
- if ($ type == self ::ASN1_BIT_STRING ) {
587
+ if ($ type == self ::$ asn1BitString ) {
600
588
$ pos ++; // Skip the first contents octet (padding indicator)
601
589
$ data = \substr ($ der , $ pos , $ len - 1 );
602
590
$ pos += $ len - 1 ;
0 commit comments