update lock clucknut
All checks were successful
All checks were successful
This commit is contained in:
46
vendor/firebase/php-jwt/CHANGELOG.md
vendored
46
vendor/firebase/php-jwt/CHANGELOG.md
vendored
@@ -1,5 +1,51 @@
|
||||
# Changelog
|
||||
|
||||
## [7.0.5](https://github.com/firebase/php-jwt/compare/v7.0.4...v7.0.5) (2026-03-31)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* RSA from JWK sometimes returns empty Instance ([#628](https://github.com/firebase/php-jwt/issues/628)) ([b4c78aa](https://github.com/firebase/php-jwt/commit/b4c78aa731664122198ad36c0033aa29e807397a))
|
||||
|
||||
## [7.0.4](https://github.com/firebase/php-jwt/compare/v7.0.3...v7.0.4) (2026-03-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* readme examples, add tests for all examples ([#626](https://github.com/firebase/php-jwt/issues/626)) ([510a00c](https://github.com/firebase/php-jwt/commit/510a00c0e6353bc7d68412fab67e57a13954cb46))
|
||||
* use urlsafeB64Decode everywhere ([#627](https://github.com/firebase/php-jwt/issues/627)) ([b889495](https://github.com/firebase/php-jwt/commit/b889495c83ddc3f3885ca3f0b65b41b1cb37a3b1))
|
||||
|
||||
## [7.0.3](https://github.com/firebase/php-jwt/compare/v7.0.2...v7.0.3) (2026-02-18)
|
||||
|
||||
|
||||
### Miscellaneous Chores
|
||||
|
||||
* add environment for Release Please job ([#619](https://github.com/firebase/php-jwt/issues/619)) ([300fd02](https://github.com/firebase/php-jwt/commit/300fd02c883f096c9067df652dbd23f62cb5e2a7))
|
||||
|
||||
## [7.0.2](https://github.com/firebase/php-jwt/compare/v7.0.1...v7.0.2) (2025-12-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add key length validation for ec keys ([#615](https://github.com/firebase/php-jwt/issues/615)) ([7044f9a](https://github.com/firebase/php-jwt/commit/7044f9ae7e7d175d28cca71714feb236f1c0e252))
|
||||
|
||||
## [7.0.0](https://github.com/firebase/php-jwt/compare/v6.11.1...v7.0.0) (2025-12-15)
|
||||
|
||||
|
||||
### ⚠️ ⚠️ ⚠️ Security Fixes ⚠️ ⚠️ ⚠️
|
||||
* add key size validation ([#613](https://github.com/firebase/php-jwt/issues/613)) ([6b80341](https://github.com/firebase/php-jwt/commit/6b80341bf57838ea2d011487917337901cd71576))
|
||||
**NOTE**: This fix will cause keys with a size below the minimally allowed size to break.
|
||||
|
||||
### Features
|
||||
|
||||
* add SensitiveParameter attribute to security-critical parameters ([#603](https://github.com/firebase/php-jwt/issues/603)) ([4dbfac0](https://github.com/firebase/php-jwt/commit/4dbfac0260eeb0e9e643063c99998e3219cc539b))
|
||||
* store timestamp in `ExpiredException` ([#604](https://github.com/firebase/php-jwt/issues/604)) ([f174826](https://github.com/firebase/php-jwt/commit/f1748260d218a856b6a0c23715ac7fae1d7ca95b))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* validate iat and nbf on payload ([#568](https://github.com/firebase/php-jwt/issues/568)) ([953b2c8](https://github.com/firebase/php-jwt/commit/953b2c88bb445b7e3bb82a5141928f13d7343afd))
|
||||
|
||||
## [6.11.1](https://github.com/firebase/php-jwt/compare/v6.11.0...v6.11.1) (2025-04-09)
|
||||
|
||||
|
||||
|
||||
72
vendor/firebase/php-jwt/README.md
vendored
72
vendor/firebase/php-jwt/README.md
vendored
@@ -23,16 +23,16 @@
|
||||
composer require paragonie/sodium_compat
|
||||
```
|
||||
|
||||
Example
|
||||
-------
|
||||
## Example
|
||||
|
||||
```php
|
||||
use Firebase\JWT\JWT;
|
||||
use Firebase\JWT\Key;
|
||||
|
||||
$key = 'example_key';
|
||||
$key = 'example_key_of_sufficient_length';
|
||||
$payload = [
|
||||
'iss' => 'http://example.org',
|
||||
'aud' => 'http://example.com',
|
||||
'iss' => 'example.org',
|
||||
'aud' => 'example.com',
|
||||
'iat' => 1356999524,
|
||||
'nbf' => 1357000000
|
||||
];
|
||||
@@ -69,8 +69,9 @@
|
||||
JWT::$leeway = 60; // $leeway in seconds
|
||||
$decoded = JWT::decode($jwt, new Key($key, 'HS256'));
|
||||
```
|
||||
Example encode/decode headers
|
||||
-------
|
||||
|
||||
## Example encode/decode headers
|
||||
|
||||
Decoding the JWT headers without verifying the JWT first is NOT recommended, and is not supported by
|
||||
this library. This is because without verifying the JWT, the header values could have been tampered with.
|
||||
Any value pulled from an unverified header should be treated as if it could be any string sent in from an
|
||||
@@ -80,10 +81,10 @@
|
||||
```php
|
||||
use Firebase\JWT\JWT;
|
||||
|
||||
$key = 'example_key';
|
||||
$key = 'example_key_of_sufficient_length';
|
||||
$payload = [
|
||||
'iss' => 'http://example.org',
|
||||
'aud' => 'http://example.com',
|
||||
'iss' => 'example.org',
|
||||
'aud' => 'example.com',
|
||||
'iat' => 1356999524,
|
||||
'nbf' => 1357000000
|
||||
];
|
||||
@@ -103,8 +104,9 @@
|
||||
|
||||
print_r($decoded);
|
||||
```
|
||||
Example with RS256 (openssl)
|
||||
----------------------------
|
||||
|
||||
## Example with RS256 (openssl)
|
||||
|
||||
```php
|
||||
use Firebase\JWT\JWT;
|
||||
use Firebase\JWT\Key;
|
||||
@@ -172,8 +174,7 @@
|
||||
echo "Decode:\n" . print_r($decoded_array, true) . "\n";
|
||||
```
|
||||
|
||||
Example with a passphrase
|
||||
-------------------------
|
||||
## Example with a passphrase
|
||||
|
||||
```php
|
||||
use Firebase\JWT\JWT;
|
||||
@@ -186,7 +187,7 @@
|
||||
// Can be generated with "ssh-keygen -t rsa -m pem"
|
||||
$privateKeyFile = '/path/to/key-with-passphrase.pem';
|
||||
|
||||
// Create a private key of type "resource"
|
||||
/** @var OpenSSLAsymmetricKey $privateKey */
|
||||
$privateKey = openssl_pkey_get_private(
|
||||
file_get_contents($privateKeyFile),
|
||||
$passphrase
|
||||
@@ -209,8 +210,8 @@
|
||||
echo "Decode:\n" . print_r((array) $decoded, true) . "\n";
|
||||
```
|
||||
|
||||
Example with EdDSA (libsodium and Ed25519 signature)
|
||||
----------------------------
|
||||
## Example with EdDSA (libsodium and Ed25519 signature)
|
||||
|
||||
```php
|
||||
use Firebase\JWT\JWT;
|
||||
use Firebase\JWT\Key;
|
||||
@@ -238,21 +239,21 @@
|
||||
|
||||
$decoded = JWT::decode($jwt, new Key($publicKey, 'EdDSA'));
|
||||
echo "Decode:\n" . print_r((array) $decoded, true) . "\n";
|
||||
````
|
||||
```
|
||||
|
||||
## Example with multiple keys
|
||||
|
||||
Example with multiple keys
|
||||
--------------------------
|
||||
```php
|
||||
use Firebase\JWT\JWT;
|
||||
use Firebase\JWT\Key;
|
||||
|
||||
// Example RSA keys from previous example
|
||||
// $privateKey1 = '...';
|
||||
// $publicKey1 = '...';
|
||||
// $privateRsKey = '...';
|
||||
// $publicRsKey = '...';
|
||||
|
||||
// Example EdDSA keys from previous example
|
||||
// $privateKey2 = '...';
|
||||
// $publicKey2 = '...';
|
||||
// $privateEcKey = '...';
|
||||
// $publicEcKey = '...';
|
||||
|
||||
$payload = [
|
||||
'iss' => 'example.org',
|
||||
@@ -261,14 +262,14 @@
|
||||
'nbf' => 1357000000
|
||||
];
|
||||
|
||||
$jwt1 = JWT::encode($payload, $privateKey1, 'RS256', 'kid1');
|
||||
$jwt2 = JWT::encode($payload, $privateKey2, 'EdDSA', 'kid2');
|
||||
$jwt1 = JWT::encode($payload, $privateRsKey, 'RS256', 'kid1');
|
||||
$jwt2 = JWT::encode($payload, $privateEcKey, 'EdDSA', 'kid2');
|
||||
echo "Encode 1:\n" . print_r($jwt1, true) . "\n";
|
||||
echo "Encode 2:\n" . print_r($jwt2, true) . "\n";
|
||||
|
||||
$keys = [
|
||||
'kid1' => new Key($publicKey1, 'RS256'),
|
||||
'kid2' => new Key($publicKey2, 'EdDSA'),
|
||||
'kid1' => new Key($publicRsKey, 'RS256'),
|
||||
'kid2' => new Key($publicEcKey, 'EdDSA'),
|
||||
];
|
||||
|
||||
$decoded1 = JWT::decode($jwt1, $keys);
|
||||
@@ -278,8 +279,7 @@
|
||||
echo "Decode 2:\n" . print_r((array) $decoded2, true) . "\n";
|
||||
```
|
||||
|
||||
Using JWKs
|
||||
----------
|
||||
## Using JWKs
|
||||
|
||||
```php
|
||||
use Firebase\JWT\JWK;
|
||||
@@ -291,11 +291,11 @@
|
||||
|
||||
// JWK::parseKeySet($jwks) returns an associative array of **kid** to Firebase\JWT\Key
|
||||
// objects. Pass this as the second parameter to JWT::decode.
|
||||
JWT::decode($jwt, JWK::parseKeySet($jwks));
|
||||
$decoded = JWT::decode($jwt, JWK::parseKeySet($jwks));
|
||||
print_r($decoded);
|
||||
```
|
||||
|
||||
Using Cached Key Sets
|
||||
---------------------
|
||||
## Using Cached Key Sets
|
||||
|
||||
The `CachedKeySet` class can be used to fetch and cache JWKS (JSON Web Key Sets) from a public URI.
|
||||
This has the following advantages:
|
||||
@@ -315,7 +315,7 @@
|
||||
$httpClient = new GuzzleHttp\Client();
|
||||
|
||||
// Create an HTTP request factory (can be any PSR-17 compatible HTTP request factory)
|
||||
$httpFactory = new GuzzleHttp\Psr\HttpFactory();
|
||||
$httpFactory = new GuzzleHttp\Psr7\HttpFactory();
|
||||
|
||||
// Create a cache item pool (can be any PSR-6 compatible cache item pool)
|
||||
$cacheItemPool = Phpfastcache\CacheManager::getInstance('files');
|
||||
@@ -406,8 +406,8 @@ #### Casting to array
|
||||
Run the tests using phpunit:
|
||||
|
||||
```bash
|
||||
$ pear install PHPUnit
|
||||
$ phpunit --configuration phpunit.xml.dist
|
||||
$ composer update
|
||||
$ vendor/bin/phpunit -c phpunit.xml.dist
|
||||
PHPUnit 3.7.10 by Sebastian Bergmann.
|
||||
.....
|
||||
Time: 0 seconds, Memory: 2.50Mb
|
||||
|
||||
3
vendor/firebase/php-jwt/composer.json
vendored
3
vendor/firebase/php-jwt/composer.json
vendored
@@ -37,6 +37,7 @@
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"psr/cache": "^2.0||^3.0",
|
||||
"psr/http-client": "^1.0",
|
||||
"psr/http-factory": "^1.0"
|
||||
"psr/http-factory": "^1.0",
|
||||
"phpfastcache/phpfastcache": "^9.2"
|
||||
}
|
||||
}
|
||||
|
||||
3
vendor/firebase/php-jwt/src/CachedKeySet.php
vendored
3
vendor/firebase/php-jwt/src/CachedKeySet.php
vendored
@@ -180,7 +180,8 @@ private function keyIdExists(string $keyId): bool
|
||||
$jwksResponse = $this->httpClient->sendRequest($request);
|
||||
if ($jwksResponse->getStatusCode() !== 200) {
|
||||
throw new UnexpectedValueException(
|
||||
\sprintf('HTTP Error: %d %s for URI "%s"',
|
||||
\sprintf(
|
||||
'HTTP Error: %d %s for URI "%s"',
|
||||
$jwksResponse->getStatusCode(),
|
||||
$jwksResponse->getReasonPhrase(),
|
||||
$this->jwksUri,
|
||||
|
||||
12
vendor/firebase/php-jwt/src/ExpiredException.php
vendored
12
vendor/firebase/php-jwt/src/ExpiredException.php
vendored
@@ -6,6 +6,8 @@ class ExpiredException extends \UnexpectedValueException implements JWTException
|
||||
{
|
||||
private object $payload;
|
||||
|
||||
private ?int $timestamp = null;
|
||||
|
||||
public function setPayload(object $payload): void
|
||||
{
|
||||
$this->payload = $payload;
|
||||
@@ -15,4 +17,14 @@ public function getPayload(): object
|
||||
{
|
||||
return $this->payload;
|
||||
}
|
||||
|
||||
public function setTimestamp(int $timestamp): void
|
||||
{
|
||||
$this->timestamp = $timestamp;
|
||||
}
|
||||
|
||||
public function getTimestamp(): ?int
|
||||
{
|
||||
return $this->timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
12
vendor/firebase/php-jwt/src/JWK.php
vendored
12
vendor/firebase/php-jwt/src/JWK.php
vendored
@@ -52,7 +52,7 @@ class JWK
|
||||
*
|
||||
* @uses parseKey
|
||||
*/
|
||||
public static function parseKeySet(array $jwks, ?string $defaultAlg = null): array
|
||||
public static function parseKeySet(#[\SensitiveParameter] array $jwks, ?string $defaultAlg = null): array
|
||||
{
|
||||
$keys = [];
|
||||
|
||||
@@ -93,7 +93,7 @@ public static function parseKeySet(array $jwks, ?string $defaultAlg = null): arr
|
||||
*
|
||||
* @uses createPemFromModulusAndExponent
|
||||
*/
|
||||
public static function parseKey(array $jwk, ?string $defaultAlg = null): ?Key
|
||||
public static function parseKey(#[\SensitiveParameter] array $jwk, ?string $defaultAlg = null): ?Key
|
||||
{
|
||||
if (empty($jwk)) {
|
||||
throw new InvalidArgumentException('JWK must not be empty');
|
||||
@@ -240,6 +240,14 @@ private static function createPemFromModulusAndExponent(
|
||||
): string {
|
||||
$mod = JWT::urlsafeB64Decode($n);
|
||||
$exp = JWT::urlsafeB64Decode($e);
|
||||
// Correct encoding for ASN1, as ints are represented as unsigned in jwk
|
||||
// but signed in ASN1. Prepending null byte makes it unsigned.
|
||||
if (\strlen($mod) > 0 && \ord($mod[0]) >= 128) {
|
||||
$mod = \chr(0) . $mod;
|
||||
}
|
||||
if (\strlen($exp) > 0 && \ord($exp[0]) >= 128) {
|
||||
$exp = \chr(0) . $exp;
|
||||
}
|
||||
|
||||
$modulus = \pack('Ca*a*', 2, self::encodeLength(\strlen($mod)), $mod);
|
||||
$publicExponent = \pack('Ca*a*', 2, self::encodeLength(\strlen($exp)), $exp);
|
||||
|
||||
158
vendor/firebase/php-jwt/src/JWT.php
vendored
158
vendor/firebase/php-jwt/src/JWT.php
vendored
@@ -31,6 +31,8 @@ class JWT
|
||||
private const ASN1_SEQUENCE = 0x10;
|
||||
private const ASN1_BIT_STRING = 0x03;
|
||||
|
||||
private const RSA_KEY_MIN_LENGTH = 2048;
|
||||
|
||||
/**
|
||||
* When checking nbf, iat or expiration times,
|
||||
* we want to provide some extra leeway time to
|
||||
@@ -95,7 +97,7 @@ class JWT
|
||||
*/
|
||||
public static function decode(
|
||||
string $jwt,
|
||||
$keyOrKeyArray,
|
||||
#[\SensitiveParameter] $keyOrKeyArray,
|
||||
?stdClass &$headers = null
|
||||
): stdClass {
|
||||
// Validate JWT
|
||||
@@ -127,6 +129,16 @@ public static function decode(
|
||||
if (!$payload instanceof stdClass) {
|
||||
throw new UnexpectedValueException('Payload must be a JSON object');
|
||||
}
|
||||
if (isset($payload->iat) && !\is_numeric($payload->iat)) {
|
||||
throw new UnexpectedValueException('Payload iat must be a number');
|
||||
}
|
||||
if (isset($payload->nbf) && !\is_numeric($payload->nbf)) {
|
||||
throw new UnexpectedValueException('Payload nbf must be a number');
|
||||
}
|
||||
if (isset($payload->exp) && !\is_numeric($payload->exp)) {
|
||||
throw new UnexpectedValueException('Payload exp must be a number');
|
||||
}
|
||||
|
||||
$sig = static::urlsafeB64Decode($cryptob64);
|
||||
if (empty($header->alg)) {
|
||||
throw new UnexpectedValueException('Empty algorithm');
|
||||
@@ -154,7 +166,7 @@ public static function decode(
|
||||
// token can actually be used. If it's not yet that time, abort.
|
||||
if (isset($payload->nbf) && floor($payload->nbf) > ($timestamp + static::$leeway)) {
|
||||
$ex = new BeforeValidException(
|
||||
'Cannot handle token with nbf prior to ' . \date(DateTime::ISO8601, (int) floor($payload->nbf))
|
||||
'Cannot handle token with nbf prior to ' . \date(DateTime::ATOM, (int) floor($payload->nbf))
|
||||
);
|
||||
$ex->setPayload($payload);
|
||||
throw $ex;
|
||||
@@ -165,7 +177,7 @@ public static function decode(
|
||||
// correctly used the nbf claim).
|
||||
if (!isset($payload->nbf) && isset($payload->iat) && floor($payload->iat) > ($timestamp + static::$leeway)) {
|
||||
$ex = new BeforeValidException(
|
||||
'Cannot handle token with iat prior to ' . \date(DateTime::ISO8601, (int) floor($payload->iat))
|
||||
'Cannot handle token with iat prior to ' . \date(DateTime::ATOM, (int) floor($payload->iat))
|
||||
);
|
||||
$ex->setPayload($payload);
|
||||
throw $ex;
|
||||
@@ -175,6 +187,7 @@ public static function decode(
|
||||
if (isset($payload->exp) && ($timestamp - static::$leeway) >= $payload->exp) {
|
||||
$ex = new ExpiredException('Expired token');
|
||||
$ex->setPayload($payload);
|
||||
$ex->setTimestamp($timestamp);
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
@@ -185,11 +198,11 @@ public static function decode(
|
||||
* Converts and signs a PHP array into a JWT string.
|
||||
*
|
||||
* @param array<mixed> $payload PHP array
|
||||
* @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key.
|
||||
* @param string|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key.
|
||||
* @param string $alg Supported algorithms are 'ES384','ES256', 'ES256K', 'HS256',
|
||||
* 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512'
|
||||
* @param string $keyId
|
||||
* @param array<string, string> $head An array with header elements to attach
|
||||
* @param array<string, string|string[]> $head An array with header elements to attach
|
||||
*
|
||||
* @return string A signed JWT
|
||||
*
|
||||
@@ -198,7 +211,7 @@ public static function decode(
|
||||
*/
|
||||
public static function encode(
|
||||
array $payload,
|
||||
$key,
|
||||
#[\SensitiveParameter] $key,
|
||||
string $alg,
|
||||
?string $keyId = null,
|
||||
?array $head = null
|
||||
@@ -226,7 +239,7 @@ 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|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key.
|
||||
* @param string $alg Supported algorithms are 'EdDSA', 'ES384', 'ES256', 'ES256K', 'HS256',
|
||||
* 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512'
|
||||
*
|
||||
@@ -236,7 +249,7 @@ public static function encode(
|
||||
*/
|
||||
public static function sign(
|
||||
string $msg,
|
||||
$key,
|
||||
#[\SensitiveParameter] $key,
|
||||
string $alg
|
||||
): string {
|
||||
if (empty(static::$supported_algs[$alg])) {
|
||||
@@ -248,13 +261,19 @@ public static function sign(
|
||||
if (!\is_string($key)) {
|
||||
throw new InvalidArgumentException('key must be a string when using hmac');
|
||||
}
|
||||
self::validateHmacKeyLength($key, $algorithm);
|
||||
return \hash_hmac($algorithm, $msg, $key, true);
|
||||
case 'openssl':
|
||||
$signature = '';
|
||||
if (!\is_resource($key) && !openssl_pkey_get_private($key)) {
|
||||
if (!$key = openssl_pkey_get_private($key)) {
|
||||
throw new DomainException('OpenSSL unable to validate key');
|
||||
}
|
||||
$success = \openssl_sign($msg, $signature, $key, $algorithm); // @phpstan-ignore-line
|
||||
if (str_starts_with($alg, 'RS')) {
|
||||
self::validateRsaKeyLength($key);
|
||||
} elseif (str_starts_with($alg, 'ES')) {
|
||||
self::validateEcKeyLength($key, $alg);
|
||||
}
|
||||
$success = \openssl_sign($msg, $signature, $key, $algorithm);
|
||||
if (!$success) {
|
||||
throw new DomainException('OpenSSL unable to sign data');
|
||||
}
|
||||
@@ -265,20 +284,8 @@ public static function sign(
|
||||
}
|
||||
return $signature;
|
||||
case 'sodium_crypto':
|
||||
if (!\function_exists('sodium_crypto_sign_detached')) {
|
||||
throw new DomainException('libsodium is not available');
|
||||
}
|
||||
if (!\is_string($key)) {
|
||||
throw new InvalidArgumentException('key must be a string when using EdDSA');
|
||||
}
|
||||
try {
|
||||
// The last non-empty line is used as the key.
|
||||
$lines = array_filter(explode("\n", $key));
|
||||
$key = base64_decode((string) end($lines));
|
||||
if (\strlen($key) === 0) {
|
||||
throw new DomainException('Key cannot be empty string');
|
||||
}
|
||||
return sodium_crypto_sign_detached($msg, $key);
|
||||
return sodium_crypto_sign_detached($msg, self::validateEdDSAKey($key));
|
||||
} catch (Exception $e) {
|
||||
throw new DomainException($e->getMessage(), 0, $e);
|
||||
}
|
||||
@@ -293,7 +300,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|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
|
||||
@@ -303,7 +310,7 @@ public static function sign(
|
||||
private static function verify(
|
||||
string $msg,
|
||||
string $signature,
|
||||
$keyMaterial,
|
||||
#[\SensitiveParameter] $keyMaterial,
|
||||
string $alg
|
||||
): bool {
|
||||
if (empty(static::$supported_algs[$alg])) {
|
||||
@@ -313,7 +320,15 @@ private static function verify(
|
||||
list($function, $algorithm) = static::$supported_algs[$alg];
|
||||
switch ($function) {
|
||||
case 'openssl':
|
||||
$success = \openssl_verify($msg, $signature, $keyMaterial, $algorithm); // @phpstan-ignore-line
|
||||
if (!$key = openssl_pkey_get_public($keyMaterial)) {
|
||||
throw new DomainException('OpenSSL unable to validate key');
|
||||
}
|
||||
if (str_starts_with($alg, 'RS')) {
|
||||
self::validateRsaKeyLength($key);
|
||||
} elseif (str_starts_with($alg, 'ES')) {
|
||||
self::validateEcKeyLength($key, $alg);
|
||||
}
|
||||
$success = \openssl_verify($msg, $signature, $keyMaterial, $algorithm);
|
||||
if ($success === 1) {
|
||||
return true;
|
||||
}
|
||||
@@ -325,19 +340,8 @@ private static function verify(
|
||||
'OpenSSL error: ' . \openssl_error_string()
|
||||
);
|
||||
case 'sodium_crypto':
|
||||
if (!\function_exists('sodium_crypto_sign_verify_detached')) {
|
||||
throw new DomainException('libsodium is not available');
|
||||
}
|
||||
if (!\is_string($keyMaterial)) {
|
||||
throw new InvalidArgumentException('key must be a string when using EdDSA');
|
||||
}
|
||||
try {
|
||||
// The last non-empty line is used as the key.
|
||||
$lines = array_filter(explode("\n", $keyMaterial));
|
||||
$key = base64_decode((string) end($lines));
|
||||
if (\strlen($key) === 0) {
|
||||
throw new DomainException('Key cannot be empty string');
|
||||
}
|
||||
$key = self::validateEdDSAKey($keyMaterial);
|
||||
if (\strlen($signature) === 0) {
|
||||
throw new DomainException('Signature cannot be empty string');
|
||||
}
|
||||
@@ -350,6 +354,7 @@ private static function verify(
|
||||
if (!\is_string($keyMaterial)) {
|
||||
throw new InvalidArgumentException('key must be a string when using hmac');
|
||||
}
|
||||
self::validateHmacKeyLength($keyMaterial, $algorithm);
|
||||
$hash = \hash_hmac($algorithm, $msg, $keyMaterial, true);
|
||||
return self::constantTimeEquals($hash, $signature);
|
||||
}
|
||||
@@ -445,7 +450,6 @@ public static function urlsafeB64Encode(string $input): string
|
||||
return \str_replace('=', '', \strtr(\base64_encode($input), '+/', '-_'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine if an algorithm has been provided for each Key
|
||||
*
|
||||
@@ -457,7 +461,7 @@ public static function urlsafeB64Encode(string $input): string
|
||||
* @return Key
|
||||
*/
|
||||
private static function getKey(
|
||||
$keyOrKeyArray,
|
||||
#[\SensitiveParameter] $keyOrKeyArray,
|
||||
?string $kid
|
||||
): Key {
|
||||
if ($keyOrKeyArray instanceof Key) {
|
||||
@@ -664,4 +668,78 @@ private static function readDER(string $der, int $offset = 0): array
|
||||
|
||||
return [$pos, $data];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate HMAC key length
|
||||
*
|
||||
* @param string $key HMAC key material
|
||||
* @param string $algorithm The algorithm
|
||||
*
|
||||
* @throws DomainException Provided key is too short
|
||||
*/
|
||||
private static function validateHmacKeyLength(string $key, string $algorithm): void
|
||||
{
|
||||
$keyLength = \strlen($key) * 8;
|
||||
$minKeyLength = (int) \str_replace('SHA', '', $algorithm);
|
||||
if ($keyLength < $minKeyLength) {
|
||||
throw new DomainException('Provided key is too short');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate RSA key length
|
||||
*
|
||||
* @param OpenSSLAsymmetricKey $key RSA key material
|
||||
* @throws DomainException Provided key is too short
|
||||
*/
|
||||
private static function validateRsaKeyLength(#[\SensitiveParameter] OpenSSLAsymmetricKey $key): void
|
||||
{
|
||||
if (!$keyDetails = openssl_pkey_get_details($key)) {
|
||||
throw new DomainException('Unable to validate key');
|
||||
}
|
||||
if ($keyDetails['bits'] < self::RSA_KEY_MIN_LENGTH) {
|
||||
throw new DomainException('Provided key is too short');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate RSA key length
|
||||
*
|
||||
* @param OpenSSLAsymmetricKey $key RSA key material
|
||||
* @param string $algorithm The algorithm
|
||||
* @throws DomainException Provided key is too short
|
||||
*/
|
||||
private static function validateEcKeyLength(
|
||||
#[\SensitiveParameter] OpenSSLAsymmetricKey $key,
|
||||
string $algorithm
|
||||
): void {
|
||||
if (!$keyDetails = openssl_pkey_get_details($key)) {
|
||||
throw new DomainException('Unable to validate key');
|
||||
}
|
||||
$minKeyLength = (int) \str_replace('ES', '', $algorithm);
|
||||
if ($keyDetails['bits'] < $minKeyLength) {
|
||||
throw new DomainException('Provided key is too short');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|OpenSSLAsymmetricKey|OpenSSLCertificate $keyMaterial
|
||||
* @return non-empty-string
|
||||
*/
|
||||
private static function validateEdDSAKey(#[\SensitiveParameter] $keyMaterial): string
|
||||
{
|
||||
if (!\function_exists('sodium_crypto_sign_verify_detached')) {
|
||||
throw new DomainException('libsodium is not available');
|
||||
}
|
||||
if (!\is_string($keyMaterial)) {
|
||||
throw new InvalidArgumentException('key must be a string when using EdDSA');
|
||||
}
|
||||
// The last non-empty line is used as the key.
|
||||
$lines = array_filter(explode("\n", $keyMaterial));
|
||||
$key = self::urlsafeB64Decode((string) end($lines));
|
||||
if (\strlen($key) === 0) {
|
||||
throw new DomainException('Key cannot be empty string');
|
||||
}
|
||||
return $key;
|
||||
}
|
||||
}
|
||||
|
||||
9
vendor/firebase/php-jwt/src/Key.php
vendored
9
vendor/firebase/php-jwt/src/Key.php
vendored
@@ -10,20 +10,19 @@
|
||||
class Key
|
||||
{
|
||||
/**
|
||||
* @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $keyMaterial
|
||||
* @param string|OpenSSLAsymmetricKey|OpenSSLCertificate $keyMaterial
|
||||
* @param string $algorithm
|
||||
*/
|
||||
public function __construct(
|
||||
private $keyMaterial,
|
||||
#[\SensitiveParameter] private $keyMaterial,
|
||||
private string $algorithm
|
||||
) {
|
||||
if (
|
||||
!\is_string($keyMaterial)
|
||||
&& !$keyMaterial instanceof OpenSSLAsymmetricKey
|
||||
&& !$keyMaterial instanceof OpenSSLCertificate
|
||||
&& !\is_resource($keyMaterial)
|
||||
) {
|
||||
throw new TypeError('Key material must be a string, resource, or OpenSSLAsymmetricKey');
|
||||
throw new TypeError('Key material must be a string, OpenSSLCertificate, or OpenSSLAsymmetricKey');
|
||||
}
|
||||
|
||||
if (empty($keyMaterial)) {
|
||||
@@ -46,7 +45,7 @@ public function getAlgorithm(): string
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate
|
||||
* @return string|OpenSSLAsymmetricKey|OpenSSLCertificate
|
||||
*/
|
||||
public function getKeyMaterial()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user