@@ -38,7 +38,7 @@ class JWT
3838 *
3939 * @var int
4040 */
41- public static $ leeway = 0 ;
41+ public static int $ leeway = 0 ;
4242
4343 /**
4444 * Allow the current timestamp to be specified.
@@ -47,15 +47,16 @@ class JWT
4747 *
4848 * @var ?int
4949 */
50- public static $ timestamp = null ;
50+ public static ? int $ timestamp = null ;
5151
5252 /**
5353 * @var array<string, string[]>
5454 */
55- public static $ supported_algs = [
56- 'ES384 ' => ['openssl ' , 'SHA384 ' ],
55+ public static array $ supported_algs = [
5756 'ES256 ' => ['openssl ' , 'SHA256 ' ],
5857 'ES256K ' => ['openssl ' , 'SHA256 ' ],
58+ 'ES384 ' => ['openssl ' , 'SHA384 ' ],
59+ 'ES512 ' => ['openssl ' , 'SHA512 ' ],
5960 'HS256 ' => ['hash_hmac ' , 'SHA256 ' ],
6061 'HS384 ' => ['hash_hmac ' , 'SHA384 ' ],
6162 'HS512 ' => ['hash_hmac ' , 'SHA512 ' ],
@@ -75,10 +76,10 @@ class JWT
7576 * the public key.
7677 * Each Key object contains an algorithm and
7778 * matching key.
78- * Supported algorithms are 'ES384','ES256 ',
79+ * Supported algorithms are 'ES256', 'ES256K', ' ES384', 'ES512 ',
7980 * 'HS256', 'HS384', 'HS512', 'RS256', 'RS384'
8081 * and 'RS512'.
81- * @param stdClass $headers Optional. Populates stdClass with headers.
82+ * @param stdClass|null $headers Optional. Populates stdClass with headers.
8283 *
8384 * @return stdClass The JWT's payload as a PHP object
8485 *
@@ -95,7 +96,7 @@ class JWT
9596 */
9697 public static function decode (
9798 string $ jwt ,
98- $ keyOrKeyArray ,
99+ Key | ArrayAccess | array $ keyOrKeyArray ,
99100 ?stdClass &$ headers = null
100101 ): stdClass {
101102 // Validate JWT
@@ -142,9 +143,9 @@ public static function decode(
142143 // See issue #351
143144 throw new UnexpectedValueException ('Incorrect key for this algorithm ' );
144145 }
145- if (\in_array ($ header ->alg , ['ES256 ' , 'ES256K ' , 'ES384 ' ], true )) {
146- // OpenSSL expects an ASN.1 DER sequence for ES256/ES256K/ES384 signatures
147- $ sig = self ::signatureToDER ($ sig );
146+ if (\in_array ($ header ->alg , ['ES256 ' , 'ES256K ' , 'ES384 ' , ' ES512 ' ], true )) {
147+ // OpenSSL expects an ASN.1 DER sequence for ES256/ES256K/ES384/ES512 signatures
148+ $ sig = self ::signatureToDER ($ sig, $ header -> alg );
148149 }
149150 if (!self ::verify ("{$ headb64 }. {$ bodyb64 }" , $ sig , $ key ->getKeyMaterial (), $ header ->alg )) {
150151 throw new SignatureInvalidException ('Signature verification failed ' );
@@ -184,12 +185,12 @@ public static function decode(
184185 /**
185186 * Converts and signs a PHP array into a JWT string.
186187 *
187- * @param array<mixed> $payload PHP array
188+ * @param array<mixed> $payload PHP array
188189 * @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key.
189- * @param string $alg Supported algorithms are 'ES384','ES256 ', 'ES256K ', 'HS256 ',
190- * 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512'
191- * @param string $keyId
192- * @param array<string, string> $head An array with header elements to attach
190+ * @param string $alg Supported algorithms are 'ES256', 'ES256K ', 'ES384 ', 'ES512 ',
191+ * 'HS256', 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512'
192+ * @param string|null $keyId
193+ * @param array<string, string>|null $head An array with header elements to attach
193194 *
194195 * @return string A signed JWT
195196 *
@@ -198,7 +199,7 @@ public static function decode(
198199 */
199200 public static function encode (
200201 array $ payload ,
201- $ key ,
202+ mixed $ key ,
202203 string $ alg ,
203204 ?string $ keyId = null ,
204205 ?array $ head = null
@@ -227,16 +228,16 @@ public static function encode(
227228 *
228229 * @param string $msg The message to sign
229230 * @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key.
230- * @param string $alg Supported algorithms are 'EdDSA', 'ES384 ', 'ES256 ', 'ES256K ', 'HS256 ',
231- * 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512'
231+ * @param string $alg Supported algorithms are 'EdDSA', 'ES256 ', 'ES256K ', 'ES384 ', 'ES512 ',
232+ * 'HS256', 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512'
232233 *
233234 * @return string An encrypted message
234235 *
235236 * @throws DomainException Unsupported algorithm or bad key was specified
236237 */
237238 public static function sign (
238239 string $ msg ,
239- $ key ,
240+ mixed $ key ,
240241 string $ alg
241242 ): string {
242243 if (empty (static ::$ supported_algs [$ alg ])) {
@@ -259,9 +260,11 @@ public static function sign(
259260 throw new DomainException ('OpenSSL unable to sign data ' );
260261 }
261262 if ($ alg === 'ES256 ' || $ alg === 'ES256K ' ) {
262- $ signature = self ::signatureFromDER ($ signature , 256 );
263+ $ signature = self ::signatureFromDER ($ signature , 256 , $ alg );
263264 } elseif ($ alg === 'ES384 ' ) {
264- $ signature = self ::signatureFromDER ($ signature , 384 );
265+ $ signature = self ::signatureFromDER ($ signature , 384 , $ alg );
266+ } elseif ($ alg === 'ES512 ' ) {
267+ $ signature = self ::signatureFromDER ($ signature , 521 , $ alg );
265268 }
266269 return $ signature ;
267270 case 'sodium_crypto ' :
@@ -303,7 +306,7 @@ public static function sign(
303306 private static function verify (
304307 string $ msg ,
305308 string $ signature ,
306- $ keyMaterial ,
309+ mixed $ keyMaterial ,
307310 string $ alg
308311 ): bool {
309312 if (empty (static ::$ supported_algs [$ alg ])) {
@@ -364,7 +367,7 @@ private static function verify(
364367 *
365368 * @throws DomainException Provided string was invalid JSON
366369 */
367- public static function jsonDecode (string $ input )
370+ public static function jsonDecode (string $ input ): mixed
368371 {
369372 $ obj = \json_decode ($ input , false , 512 , JSON_BIGINT_AS_STRING );
370373
@@ -457,7 +460,7 @@ public static function urlsafeB64Encode(string $input): string
457460 * @return Key
458461 */
459462 private static function getKey (
460- $ keyOrKeyArray ,
463+ Key | ArrayAccess | array $ keyOrKeyArray ,
461464 ?string $ kid
462465 ): Key {
463466 if ($ keyOrKeyArray instanceof Key) {
@@ -519,11 +522,7 @@ private static function handleJsonError(int $errno): void
519522 JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON ' ,
520523 JSON_ERROR_UTF8 => 'Malformed UTF-8 characters ' //PHP >= 5.3.3
521524 ];
522- throw new DomainException (
523- isset ($ messages [$ errno ])
524- ? $ messages [$ errno ]
525- : 'Unknown JSON error: ' . $ errno
526- );
525+ throw new DomainException ($ messages [$ errno ] ?? 'Unknown JSON error: ' . $ errno );
527526 }
528527
529528 /**
@@ -545,12 +544,16 @@ private static function safeStrlen(string $str): int
545544 * Convert an ECDSA signature to an ASN.1 DER sequence
546545 *
547546 * @param string $sig The ECDSA signature to convert
547+ * @param string $alg The algorithm
548548 * @return string The encoded DER object
549549 */
550- private static function signatureToDER (string $ sig ): string
550+ private static function signatureToDER (string $ sig, string $ alg ): string
551551 {
552552 // Separate the signature into r-value and s-value
553- $ length = max (1 , (int ) (\strlen ($ sig ) / 2 ));
553+ $ length = match ($ alg ) {
554+ 'ES512 ' => 66 ,
555+ default => max (1 , (int ) (\strlen ($ sig ) / 2 )),
556+ };
554557 list ($ r , $ s ) = \str_split ($ sig , $ length );
555558
556559 // Trim leading zeros
@@ -602,10 +605,11 @@ private static function encodeDER(int $type, string $value): string
602605 *
603606 * @param string $der binary signature in DER format
604607 * @param int $keySize the number of bits in the key
608+ * @param string $alg The algorithm
605609 *
606610 * @return string the signature
607611 */
608- private static function signatureFromDER (string $ der , int $ keySize ): string
612+ private static function signatureFromDER (string $ der , int $ keySize, string $ alg ): string
609613 {
610614 // OpenSSL returns the ECDSA signatures as a binary ASN.1 DER SEQUENCE
611615 list ($ offset , $ _ ) = self ::readDER ($ der );
@@ -618,8 +622,9 @@ private static function signatureFromDER(string $der, int $keySize): string
618622 $ s = \ltrim ($ s , "\x00" );
619623
620624 // Pad out r and s so that they are $keySize bits long
621- $ r = \str_pad ($ r , $ keySize / 8 , "\x00" , STR_PAD_LEFT );
622- $ s = \str_pad ($ s , $ keySize / 8 , "\x00" , STR_PAD_LEFT );
625+ $ length = \ceil ($ keySize / 8 );
626+ $ r = \str_pad ($ r , $ length , "\x00" , STR_PAD_LEFT );
627+ $ s = \str_pad ($ s , $ length , "\x00" , STR_PAD_LEFT );
623628
624629 return $ r . $ s ;
625630 }
0 commit comments