From ff8912ba3b85f7d117d1885341a9f98e0a514fa3 Mon Sep 17 00:00:00 2001 From: Ninos Ego Date: Sat, 25 May 2024 08:18:09 +0200 Subject: [PATCH 1/2] feat(alg): Add ES512 support --- src/JWT.php | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/JWT.php b/src/JWT.php index dd9292a4..498fd82d 100644 --- a/src/JWT.php +++ b/src/JWT.php @@ -53,9 +53,10 @@ class JWT * @var array */ public static $supported_algs = [ - 'ES384' => ['openssl', 'SHA384'], 'ES256' => ['openssl', 'SHA256'], 'ES256K' => ['openssl', 'SHA256'], + 'ES384' => ['openssl', 'SHA384'], + 'ES512' => ['openssl', 'SHA512'], 'HS256' => ['hash_hmac', 'SHA256'], 'HS384' => ['hash_hmac', 'SHA384'], 'HS512' => ['hash_hmac', 'SHA512'], @@ -75,7 +76,7 @@ class JWT * the public key. * Each Key object contains an algorithm and * matching key. - * Supported algorithms are 'ES384','ES256', + * Supported algorithms are 'ES256', 'ES256K', 'ES384', 'ES512', * 'HS256', 'HS384', 'HS512', 'RS256', 'RS384' * and 'RS512'. * @param stdClass $headers Optional. Populates stdClass with headers. @@ -142,8 +143,8 @@ public static function decode( // See issue #351 throw new UnexpectedValueException('Incorrect key for this algorithm'); } - if (\in_array($header->alg, ['ES256', 'ES256K', 'ES384'], true)) { - // OpenSSL expects an ASN.1 DER sequence for ES256/ES256K/ES384 signatures + if (\in_array($header->alg, ['ES256', 'ES256K', 'ES384', 'ES512'], true)) { + // OpenSSL expects an ASN.1 DER sequence for ES256/ES256K/ES384/ES512 signatures $sig = self::signatureToDER($sig); } if (!self::verify("{$headb64}.{$bodyb64}", $sig, $key->getKeyMaterial(), $header->alg)) { @@ -186,8 +187,8 @@ public static function decode( * * @param array $payload PHP array * @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key. - * @param string $alg Supported algorithms are 'ES384','ES256', 'ES256K', 'HS256', - * 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512' + * @param string $alg Supported algorithms are 'ES256', 'ES256K', 'ES384', 'ES512', + * 'HS256', 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512' * @param string $keyId * @param array $head An array with header elements to attach * @@ -227,8 +228,8 @@ public static function encode( * * @param string $msg The message to sign * @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key. - * @param string $alg Supported algorithms are 'EdDSA', 'ES384', 'ES256', 'ES256K', 'HS256', - * 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512' + * @param string $alg Supported algorithms are 'EdDSA', 'ES256', 'ES256K', 'ES384', 'ES512', + * 'HS256', 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512' * * @return string An encrypted message * @@ -262,6 +263,8 @@ public static function sign( $signature = self::signatureFromDER($signature, 256); } elseif ($alg === 'ES384') { $signature = self::signatureFromDER($signature, 384); + } elseif ($alg === 'ES512') { + $signature = self::signatureFromDER($signature, 512); } return $signature; case 'sodium_crypto': From 1e2c7929bd3c4b965f9fe80a6188d074d700f85f Mon Sep 17 00:00:00 2001 From: Ninos Ego Date: Sat, 25 May 2024 08:44:33 +0200 Subject: [PATCH 2/2] style(types): Strict types + phpdoc --- composer.json | 3 ++- src/JWT.php | 46 +++++++++++++++++++++------------------------- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/composer.json b/composer.json index 816cfd0b..f390a019 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,8 @@ ], "license": "BSD-3-Clause", "require": { - "php": "^8.0" + "php": "^8.0", + "ext-openssl": "*" }, "suggest": { "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present", diff --git a/src/JWT.php b/src/JWT.php index 498fd82d..bd0823e1 100644 --- a/src/JWT.php +++ b/src/JWT.php @@ -38,7 +38,7 @@ class JWT * * @var int */ - public static $leeway = 0; + public static int $leeway = 0; /** * Allow the current timestamp to be specified. @@ -47,12 +47,12 @@ class JWT * * @var ?int */ - public static $timestamp = null; + public static ?int $timestamp = null; /** * @var array */ - public static $supported_algs = [ + public static array $supported_algs = [ 'ES256' => ['openssl', 'SHA256'], 'ES256K' => ['openssl', 'SHA256'], 'ES384' => ['openssl', 'SHA384'], @@ -79,7 +79,7 @@ class JWT * Supported algorithms are 'ES256', 'ES256K', 'ES384', 'ES512', * 'HS256', 'HS384', 'HS512', 'RS256', 'RS384' * and 'RS512'. - * @param stdClass $headers Optional. Populates stdClass with headers. + * @param stdClass|null $headers Optional. Populates stdClass with headers. * * @return stdClass The JWT's payload as a PHP object * @@ -96,7 +96,7 @@ class JWT */ public static function decode( string $jwt, - $keyOrKeyArray, + Key|ArrayAccess|array $keyOrKeyArray, ?stdClass &$headers = null ): stdClass { // Validate JWT @@ -185,12 +185,12 @@ public static function decode( /** * Converts and signs a PHP array into a JWT string. * - * @param array $payload PHP array - * @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key. - * @param string $alg Supported algorithms are 'ES256', 'ES256K', 'ES384', 'ES512', - * 'HS256', 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512' - * @param string $keyId - * @param array $head An array with header elements to attach + * @param array $payload PHP array + * @param string|array|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key. + * @param string $alg Supported algorithms are 'ES256', 'ES256K', 'ES384', 'ES512', + * 'HS256', 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512' + * @param string|null $keyId + * @param array|null $head An array with header elements to attach * * @return string A signed JWT * @@ -199,7 +199,7 @@ public static function decode( */ public static function encode( array $payload, - $key, + string|array|OpenSSLAsymmetricKey|OpenSSLCertificate $key, string $alg, ?string $keyId = null, ?array $head = null @@ -227,9 +227,9 @@ public static function encode( * Sign a string with a given key and algorithm. * * @param string $msg The message to sign - * @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key. + * @param string|array|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key. * @param string $alg Supported algorithms are 'EdDSA', 'ES256', 'ES256K', 'ES384', 'ES512', - * 'HS256', 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512' + * 'HS256', 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512' * * @return string An encrypted message * @@ -237,7 +237,7 @@ public static function encode( */ public static function sign( string $msg, - $key, + string|array|OpenSSLAsymmetricKey|OpenSSLCertificate $key, string $alg ): string { if (empty(static::$supported_algs[$alg])) { @@ -296,7 +296,7 @@ public static function sign( * * @param string $msg The original message (header and body) * @param string $signature The original signature - * @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $keyMaterial For Ed*, ES*, HS*, a string key works. for RS*, must be an instance of OpenSSLAsymmetricKey + * @param string|array|OpenSSLAsymmetricKey|OpenSSLCertificate $keyMaterial For Ed*, ES*, HS*, a string key works. for RS*, must be an instance of OpenSSLAsymmetricKey * @param string $alg The algorithm * * @return bool @@ -306,7 +306,7 @@ public static function sign( private static function verify( string $msg, string $signature, - $keyMaterial, + string|array|OpenSSLAsymmetricKey|OpenSSLCertificate $keyMaterial, string $alg ): bool { if (empty(static::$supported_algs[$alg])) { @@ -367,7 +367,7 @@ private static function verify( * * @throws DomainException Provided string was invalid JSON */ - public static function jsonDecode(string $input) + public static function jsonDecode(string $input): mixed { $obj = \json_decode($input, false, 512, JSON_BIGINT_AS_STRING); @@ -382,7 +382,7 @@ public static function jsonDecode(string $input) /** * Encode a PHP array into a JSON string. * - * @param array $input A PHP array + * @param array $input A PHP array * * @return string JSON representation of the PHP array * @@ -460,7 +460,7 @@ public static function urlsafeB64Encode(string $input): string * @return Key */ private static function getKey( - $keyOrKeyArray, + Key|ArrayAccess|array $keyOrKeyArray, ?string $kid ): Key { if ($keyOrKeyArray instanceof Key) { @@ -522,11 +522,7 @@ private static function handleJsonError(int $errno): void JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON', JSON_ERROR_UTF8 => 'Malformed UTF-8 characters' //PHP >= 5.3.3 ]; - throw new DomainException( - isset($messages[$errno]) - ? $messages[$errno] - : 'Unknown JSON error: ' . $errno - ); + throw new DomainException($messages[$errno] ?? 'Unknown JSON error: ' . $errno); } /**