mirror of
https://github.com/moodle/moodle.git
synced 2025-04-20 16:04:25 +02:00
MDL-71712 lib: Upgrade PHP-JWT to 6.0.0
This commit is contained in:
parent
4f9a539600
commit
af1401bc76
@ -13,7 +13,7 @@ modification, are permitted provided that the following conditions are met:
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
* Neither the name of Neuman Vong nor the names of other
|
||||
* Neither the name of the copyright holder nor the names of other
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
[](https://travis-ci.org/firebase/php-jwt)
|
||||

|
||||
[](https://packagist.org/packages/firebase/php-jwt)
|
||||
[](https://packagist.org/packages/firebase/php-jwt)
|
||||
[](https://packagist.org/packages/firebase/php-jwt)
|
||||
@ -16,11 +16,18 @@ Use composer to manage your dependencies and download PHP-JWT:
|
||||
composer require firebase/php-jwt
|
||||
```
|
||||
|
||||
Optionally, install the `paragonie/sodium_compat` package from composer if your
|
||||
php is < 7.2 or does not have libsodium installed:
|
||||
|
||||
```bash
|
||||
composer require paragonie/sodium_compat
|
||||
```
|
||||
|
||||
Example
|
||||
-------
|
||||
```php
|
||||
<?php
|
||||
use \Firebase\JWT\JWT;
|
||||
use Firebase\JWT\JWT;
|
||||
use Firebase\JWT\Key;
|
||||
|
||||
$key = "example_key";
|
||||
$payload = array(
|
||||
@ -36,8 +43,8 @@ $payload = array(
|
||||
* https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40
|
||||
* for a list of spec-compliant algorithms.
|
||||
*/
|
||||
$jwt = JWT::encode($payload, $key);
|
||||
$decoded = JWT::decode($jwt, $key, array('HS256'));
|
||||
$jwt = JWT::encode($payload, $key, 'HS256');
|
||||
$decoded = JWT::decode($jwt, new Key($key, 'HS256'));
|
||||
|
||||
print_r($decoded);
|
||||
|
||||
@ -56,15 +63,13 @@ $decoded_array = (array) $decoded;
|
||||
* Source: http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#nbfDef
|
||||
*/
|
||||
JWT::$leeway = 60; // $leeway in seconds
|
||||
$decoded = JWT::decode($jwt, $key, array('HS256'));
|
||||
|
||||
?>
|
||||
$decoded = JWT::decode($jwt, new Key($key, 'HS256'));
|
||||
```
|
||||
Example with RS256 (openssl)
|
||||
----------------------------
|
||||
```php
|
||||
<?php
|
||||
use \Firebase\JWT\JWT;
|
||||
use Firebase\JWT\JWT;
|
||||
use Firebase\JWT\Key;
|
||||
|
||||
$privateKey = <<<EOD
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
@ -103,7 +108,7 @@ $payload = array(
|
||||
$jwt = JWT::encode($payload, $privateKey, 'RS256');
|
||||
echo "Encode:\n" . print_r($jwt, true) . "\n";
|
||||
|
||||
$decoded = JWT::decode($jwt, $publicKey, array('RS256'));
|
||||
$decoded = JWT::decode($jwt, new Key($publicKey, 'RS256'));
|
||||
|
||||
/*
|
||||
NOTE: This will now be an object instead of an associative array. To get
|
||||
@ -112,12 +117,104 @@ $decoded = JWT::decode($jwt, $publicKey, array('RS256'));
|
||||
|
||||
$decoded_array = (array) $decoded;
|
||||
echo "Decode:\n" . print_r($decoded_array, true) . "\n";
|
||||
?>
|
||||
```
|
||||
|
||||
Example with a passphrase
|
||||
-------------------------
|
||||
|
||||
```php
|
||||
use Firebase\JWT\JWT;
|
||||
use Firebase\JWT\Key;
|
||||
|
||||
// Your passphrase
|
||||
$passphrase = '[YOUR_PASSPHRASE]';
|
||||
|
||||
// Your private key file with passphrase
|
||||
// Can be generated with "ssh-keygen -t rsa -m pem"
|
||||
$privateKeyFile = '/path/to/key-with-passphrase.pem';
|
||||
|
||||
// Create a private key of type "resource"
|
||||
$privateKey = openssl_pkey_get_private(
|
||||
file_get_contents($privateKeyFile),
|
||||
$passphrase
|
||||
);
|
||||
|
||||
$payload = array(
|
||||
"iss" => "example.org",
|
||||
"aud" => "example.com",
|
||||
"iat" => 1356999524,
|
||||
"nbf" => 1357000000
|
||||
);
|
||||
|
||||
$jwt = JWT::encode($payload, $privateKey, 'RS256');
|
||||
echo "Encode:\n" . print_r($jwt, true) . "\n";
|
||||
|
||||
// Get public key from the private key, or pull from from a file.
|
||||
$publicKey = openssl_pkey_get_details($privateKey)['key'];
|
||||
|
||||
$decoded = JWT::decode($jwt, new Key($publicKey, 'RS256'));
|
||||
echo "Decode:\n" . print_r((array) $decoded, true) . "\n";
|
||||
```
|
||||
|
||||
Example with EdDSA (libsodium and Ed25519 signature)
|
||||
----------------------------
|
||||
```php
|
||||
use Firebase\JWT\JWT;
|
||||
use Firebase\JWT\Key;
|
||||
|
||||
// Public and private keys are expected to be Base64 encoded. The last
|
||||
// non-empty line is used so that keys can be generated with
|
||||
// sodium_crypto_sign_keypair(). The secret keys generated by other tools may
|
||||
// need to be adjusted to match the input expected by libsodium.
|
||||
|
||||
$keyPair = sodium_crypto_sign_keypair();
|
||||
|
||||
$privateKey = base64_encode(sodium_crypto_sign_secretkey($keyPair));
|
||||
|
||||
$publicKey = base64_encode(sodium_crypto_sign_publickey($keyPair));
|
||||
|
||||
$payload = array(
|
||||
"iss" => "example.org",
|
||||
"aud" => "example.com",
|
||||
"iat" => 1356999524,
|
||||
"nbf" => 1357000000
|
||||
);
|
||||
|
||||
$jwt = JWT::encode($payload, $privateKey, 'EdDSA');
|
||||
echo "Encode:\n" . print_r($jwt, true) . "\n";
|
||||
|
||||
$decoded = JWT::decode($jwt, new Key($publicKey, 'EdDSA'));
|
||||
echo "Decode:\n" . print_r((array) $decoded, true) . "\n";
|
||||
````
|
||||
|
||||
Using JWKs
|
||||
----------
|
||||
|
||||
```php
|
||||
use Firebase\JWT\JWK;
|
||||
use Firebase\JWT\JWT;
|
||||
|
||||
// Set of keys. The "keys" key is required. For example, the JSON response to
|
||||
// this endpoint: https://www.gstatic.com/iap/verify/public_key-jwk
|
||||
$jwks = ['keys' => []];
|
||||
|
||||
// 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($payload, JWK::parseKeySet($jwks));
|
||||
```
|
||||
|
||||
Changelog
|
||||
---------
|
||||
|
||||
#### 6.0.0 / 2022-01-24
|
||||
|
||||
- **Backwards-Compatibility Breaking Changes**: See the [Release Notes](https://github.com/firebase/php-jwt/releases/tag/v5.5.1) for more information.
|
||||
- New Key object to prevent key/algorithm type confusion (#365)
|
||||
- Add JWK support (#273)
|
||||
- Add ES256 support (#256)
|
||||
- Add ES384 support (#324)
|
||||
- Add Ed25519 support (#343)
|
||||
|
||||
#### 5.0.0 / 2017-06-26
|
||||
- Support RS384 and RS512.
|
||||
See [#117](https://github.com/firebase/php-jwt/pull/117). Thanks [@joostfaassen](https://github.com/joostfaassen)!
|
||||
|
@ -22,6 +22,9 @@
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"suggest": {
|
||||
"paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Firebase\\JWT\\": "src"
|
||||
|
@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Firebase\JWT;
|
||||
|
||||
class BeforeValidException extends \UnexpectedValueException
|
||||
|
@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Firebase\JWT;
|
||||
|
||||
class ExpiredException extends \UnexpectedValueException
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace Firebase\JWT;
|
||||
|
||||
use DomainException;
|
||||
use InvalidArgumentException;
|
||||
use UnexpectedValueException;
|
||||
|
||||
/**
|
||||
@ -24,7 +25,7 @@ class JWK
|
||||
*
|
||||
* @param array $jwks The JSON Web Key Set as an associative array
|
||||
*
|
||||
* @return array An associative array that represents the set of keys
|
||||
* @return array<string, Key> An associative array of key IDs (kid) to Key objects
|
||||
*
|
||||
* @throws InvalidArgumentException Provided JWK Set is empty
|
||||
* @throws UnexpectedValueException Provided JWK Set was invalid
|
||||
@ -62,7 +63,7 @@ class JWK
|
||||
*
|
||||
* @param array $jwk An individual JWK
|
||||
*
|
||||
* @return resource|array An associative array that represents the key
|
||||
* @return Key The key object for the JWK
|
||||
*
|
||||
* @throws InvalidArgumentException Provided JWK is empty
|
||||
* @throws UnexpectedValueException Provided JWK was invalid
|
||||
@ -70,7 +71,7 @@ class JWK
|
||||
*
|
||||
* @uses createPemFromModulusAndExponent
|
||||
*/
|
||||
private static function parseKey(array $jwk)
|
||||
public static function parseKey(array $jwk)
|
||||
{
|
||||
if (empty($jwk)) {
|
||||
throw new InvalidArgumentException('JWK must not be empty');
|
||||
@ -78,10 +79,16 @@ class JWK
|
||||
if (!isset($jwk['kty'])) {
|
||||
throw new UnexpectedValueException('JWK must contain a "kty" parameter');
|
||||
}
|
||||
if (!isset($jwk['alg'])) {
|
||||
// The "alg" parameter is optional in a KTY, but is required for parsing in
|
||||
// this library. Add it manually to your JWK array if it doesn't already exist.
|
||||
// @see https://datatracker.ietf.org/doc/html/rfc7517#section-4.4
|
||||
throw new UnexpectedValueException('JWK must contain an "alg" parameter');
|
||||
}
|
||||
|
||||
switch ($jwk['kty']) {
|
||||
case 'RSA':
|
||||
if (\array_key_exists('d', $jwk)) {
|
||||
if (!empty($jwk['d'])) {
|
||||
throw new UnexpectedValueException('RSA private keys are not supported');
|
||||
}
|
||||
if (!isset($jwk['n']) || !isset($jwk['e'])) {
|
||||
@ -95,7 +102,7 @@ class JWK
|
||||
'OpenSSL error: ' . \openssl_error_string()
|
||||
);
|
||||
}
|
||||
return $publicKey;
|
||||
return new Key($publicKey, $jwk['alg']);
|
||||
default:
|
||||
// Currently only RSA is supported
|
||||
break;
|
||||
|
@ -2,10 +2,13 @@
|
||||
|
||||
namespace Firebase\JWT;
|
||||
|
||||
use \DomainException;
|
||||
use \InvalidArgumentException;
|
||||
use \UnexpectedValueException;
|
||||
use \DateTime;
|
||||
use ArrayAccess;
|
||||
use DomainException;
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use OpenSSLAsymmetricKey;
|
||||
use UnexpectedValueException;
|
||||
use DateTime;
|
||||
|
||||
/**
|
||||
* JSON Web Token implementation, based on this spec:
|
||||
@ -22,16 +25,19 @@ use \DateTime;
|
||||
*/
|
||||
class JWT
|
||||
{
|
||||
const ASN1_INTEGER = 0x02;
|
||||
const ASN1_SEQUENCE = 0x10;
|
||||
const ASN1_BIT_STRING = 0x03;
|
||||
// const ASN1_INTEGER = 0x02;
|
||||
// const ASN1_SEQUENCE = 0x10;
|
||||
// const ASN1_BIT_STRING = 0x03;
|
||||
private static $asn1Integer = 0x02;
|
||||
private static $asn1Sequence = 0x10;
|
||||
private static $asn1BitString = 0x03;
|
||||
|
||||
/**
|
||||
* When checking nbf, iat or expiration times,
|
||||
* we want to provide some extra leeway time to
|
||||
* account for clock skew.
|
||||
*/
|
||||
public static $leeway = 180;
|
||||
public static $leeway = 0;
|
||||
|
||||
/**
|
||||
* Allow the current timestamp to be specified.
|
||||
@ -42,6 +48,7 @@ class JWT
|
||||
public static $timestamp = null;
|
||||
|
||||
public static $supported_algs = array(
|
||||
'ES384' => array('openssl', 'SHA384'),
|
||||
'ES256' => array('openssl', 'SHA256'),
|
||||
'HS256' => array('hash_hmac', 'SHA256'),
|
||||
'HS384' => array('hash_hmac', 'SHA384'),
|
||||
@ -49,19 +56,23 @@ class JWT
|
||||
'RS256' => array('openssl', 'SHA256'),
|
||||
'RS384' => array('openssl', 'SHA384'),
|
||||
'RS512' => array('openssl', 'SHA512'),
|
||||
'EdDSA' => array('sodium_crypto', 'EdDSA'),
|
||||
);
|
||||
|
||||
/**
|
||||
* Decodes a JWT string into a PHP object.
|
||||
*
|
||||
* @param string $jwt The JWT
|
||||
* @param string|array|resource $key The key, or map of keys.
|
||||
* @param Key|array<string, Key> $keyOrKeyArray The Key or associative array of key IDs (kid) to Key objects.
|
||||
* If the algorithm used is asymmetric, this is the public key
|
||||
* @param array $allowed_algs List of supported verification algorithms
|
||||
* Supported algorithms are 'ES256', 'HS256', 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512'
|
||||
* Each Key object contains an algorithm and matching key.
|
||||
* Supported algorithms are 'ES384','ES256', 'HS256', 'HS384',
|
||||
* 'HS512', 'RS256', 'RS384', and 'RS512'
|
||||
*
|
||||
* @return object The JWT's payload as a PHP object
|
||||
*
|
||||
* @throws InvalidArgumentException Provided key/key-array was empty
|
||||
* @throws DomainException Provided JWT is malformed
|
||||
* @throws UnexpectedValueException Provided JWT was invalid
|
||||
* @throws SignatureInvalidException Provided JWT was invalid because the signature verification failed
|
||||
* @throws BeforeValidException Provided JWT is trying to be used before it's eligible as defined by 'nbf'
|
||||
@ -71,11 +82,12 @@ class JWT
|
||||
* @uses jsonDecode
|
||||
* @uses urlsafeB64Decode
|
||||
*/
|
||||
public static function decode($jwt, $key, array $allowed_algs = array())
|
||||
public static function decode($jwt, $keyOrKeyArray)
|
||||
{
|
||||
// Validate JWT
|
||||
$timestamp = \is_null(static::$timestamp) ? \time() : static::$timestamp;
|
||||
|
||||
if (empty($key)) {
|
||||
if (empty($keyOrKeyArray)) {
|
||||
throw new InvalidArgumentException('Key may not be empty');
|
||||
}
|
||||
$tks = \explode('.', $jwt);
|
||||
@ -98,27 +110,19 @@ class JWT
|
||||
if (empty(static::$supported_algs[$header->alg])) {
|
||||
throw new UnexpectedValueException('Algorithm not supported');
|
||||
}
|
||||
if (!\in_array($header->alg, $allowed_algs)) {
|
||||
throw new UnexpectedValueException('Algorithm not allowed');
|
||||
|
||||
$key = self::getKey($keyOrKeyArray, empty($header->kid) ? null : $header->kid);
|
||||
|
||||
// Check the algorithm
|
||||
if (!self::constantTimeEquals($key->getAlgorithm(), $header->alg)) {
|
||||
// See issue #351
|
||||
throw new UnexpectedValueException('Incorrect key for this algorithm');
|
||||
}
|
||||
if ($header->alg === 'ES256') {
|
||||
// OpenSSL expects an ASN.1 DER sequence for ES256 signatures
|
||||
if ($header->alg === 'ES256' || $header->alg === 'ES384') {
|
||||
// OpenSSL expects an ASN.1 DER sequence for ES256/ES384 signatures
|
||||
$sig = self::signatureToDER($sig);
|
||||
}
|
||||
|
||||
if (\is_array($key) || $key instanceof \ArrayAccess) {
|
||||
if (isset($header->kid)) {
|
||||
if (!isset($key[$header->kid])) {
|
||||
throw new UnexpectedValueException('"kid" invalid, unable to lookup correct key');
|
||||
}
|
||||
$key = $key[$header->kid];
|
||||
} else {
|
||||
throw new UnexpectedValueException('"kid" empty, unable to lookup correct key');
|
||||
}
|
||||
}
|
||||
|
||||
// Check the signature
|
||||
if (!static::verify("$headb64.$bodyb64", $sig, $key, $header->alg)) {
|
||||
if (!static::verify("$headb64.$bodyb64", $sig, $key->getKeyMaterial(), $header->alg)) {
|
||||
throw new SignatureInvalidException('Signature verification failed');
|
||||
}
|
||||
|
||||
@ -150,20 +154,21 @@ class JWT
|
||||
/**
|
||||
* Converts and signs a PHP object or array into a JWT string.
|
||||
*
|
||||
* @param object|array $payload PHP object or array
|
||||
* @param string $key The secret key.
|
||||
* If the algorithm used is asymmetric, this is the private key
|
||||
* @param string $alg The signing algorithm.
|
||||
* Supported algorithms are 'ES256', 'HS256', 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512'
|
||||
* @param mixed $keyId
|
||||
* @param array $head An array with header elements to attach
|
||||
* @param object|array $payload PHP object or array
|
||||
* @param string|resource $key The secret key.
|
||||
* If the algorithm used is asymmetric, this is the private key
|
||||
* @param string $alg The signing algorithm.
|
||||
* Supported algorithms are 'ES384','ES256', 'HS256', 'HS384',
|
||||
* 'HS512', 'RS256', 'RS384', and 'RS512'
|
||||
* @param mixed $keyId
|
||||
* @param array $head An array with header elements to attach
|
||||
*
|
||||
* @return string A signed JWT
|
||||
*
|
||||
* @uses jsonEncode
|
||||
* @uses urlsafeB64Encode
|
||||
*/
|
||||
public static function encode($payload, $key, $alg = 'HS256', $keyId = null, $head = null)
|
||||
public static function encode($payload, $key, $alg, $keyId = null, $head = null)
|
||||
{
|
||||
$header = array('typ' => 'JWT', 'alg' => $alg);
|
||||
if ($keyId !== null) {
|
||||
@ -189,13 +194,14 @@ class JWT
|
||||
* @param string $msg The message to sign
|
||||
* @param string|resource $key The secret key
|
||||
* @param string $alg The signing algorithm.
|
||||
* Supported algorithms are 'ES256', 'HS256', 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512'
|
||||
* Supported algorithms are 'ES384','ES256', 'HS256', 'HS384',
|
||||
* 'HS512', 'RS256', 'RS384', and 'RS512'
|
||||
*
|
||||
* @return string An encrypted message
|
||||
*
|
||||
* @throws DomainException Unsupported algorithm was specified
|
||||
* @throws DomainException Unsupported algorithm or bad key was specified
|
||||
*/
|
||||
public static function sign($msg, $key, $alg = 'HS256')
|
||||
public static function sign($msg, $key, $alg)
|
||||
{
|
||||
if (empty(static::$supported_algs[$alg])) {
|
||||
throw new DomainException('Algorithm not supported');
|
||||
@ -209,11 +215,24 @@ class JWT
|
||||
$success = \openssl_sign($msg, $signature, $key, $algorithm);
|
||||
if (!$success) {
|
||||
throw new DomainException("OpenSSL unable to sign data");
|
||||
} else {
|
||||
if ($alg === 'ES256') {
|
||||
$signature = self::signatureFromDER($signature, 256);
|
||||
}
|
||||
return $signature;
|
||||
}
|
||||
if ($alg === 'ES256') {
|
||||
$signature = self::signatureFromDER($signature, 256);
|
||||
} elseif ($alg === 'ES384') {
|
||||
$signature = self::signatureFromDER($signature, 384);
|
||||
}
|
||||
return $signature;
|
||||
case 'sodium_crypto':
|
||||
if (!function_exists('sodium_crypto_sign_detached')) {
|
||||
throw new DomainException('libsodium is not available');
|
||||
}
|
||||
try {
|
||||
// The last non-empty line is used as the key.
|
||||
$lines = array_filter(explode("\n", $key));
|
||||
$key = base64_decode(end($lines));
|
||||
return sodium_crypto_sign_detached($msg, $key);
|
||||
} catch (Exception $e) {
|
||||
throw new DomainException($e->getMessage(), 0, $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -229,7 +248,7 @@ class JWT
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @throws DomainException Invalid Algorithm or OpenSSL failure
|
||||
* @throws DomainException Invalid Algorithm, bad key, or OpenSSL failure
|
||||
*/
|
||||
private static function verify($msg, $signature, $key, $alg)
|
||||
{
|
||||
@ -250,21 +269,22 @@ class JWT
|
||||
throw new DomainException(
|
||||
'OpenSSL error: ' . \openssl_error_string()
|
||||
);
|
||||
case 'sodium_crypto':
|
||||
if (!function_exists('sodium_crypto_sign_verify_detached')) {
|
||||
throw new DomainException('libsodium is not available');
|
||||
}
|
||||
try {
|
||||
// The last non-empty line is used as the key.
|
||||
$lines = array_filter(explode("\n", $key));
|
||||
$key = base64_decode(end($lines));
|
||||
return sodium_crypto_sign_verify_detached($signature, $msg, $key);
|
||||
} catch (Exception $e) {
|
||||
throw new DomainException($e->getMessage(), 0, $e);
|
||||
}
|
||||
case 'hash_hmac':
|
||||
default:
|
||||
$hash = \hash_hmac($algorithm, $msg, $key, true);
|
||||
if (\function_exists('hash_equals')) {
|
||||
return \hash_equals($signature, $hash);
|
||||
}
|
||||
$len = \min(static::safeStrlen($signature), static::safeStrlen($hash));
|
||||
|
||||
$status = 0;
|
||||
for ($i = 0; $i < $len; $i++) {
|
||||
$status |= (\ord($signature[$i]) ^ \ord($hash[$i]));
|
||||
}
|
||||
$status |= (static::safeStrlen($signature) ^ static::safeStrlen($hash));
|
||||
|
||||
return ($status === 0);
|
||||
return self::constantTimeEquals($signature, $hash);
|
||||
}
|
||||
}
|
||||
|
||||
@ -314,7 +334,12 @@ class JWT
|
||||
*/
|
||||
public static function jsonEncode($input)
|
||||
{
|
||||
$json = \json_encode($input);
|
||||
if (PHP_VERSION_ID >= 50400) {
|
||||
$json = \json_encode($input, \JSON_UNESCAPED_SLASHES);
|
||||
} else {
|
||||
// PHP 5.3 only
|
||||
$json = \json_encode($input);
|
||||
}
|
||||
if ($errno = \json_last_error()) {
|
||||
static::handleJsonError($errno);
|
||||
} elseif ($json === 'null' && $input !== null) {
|
||||
@ -352,6 +377,69 @@ class JWT
|
||||
return \str_replace('=', '', \strtr(\base64_encode($input), '+/', '-_'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine if an algorithm has been provided for each Key
|
||||
*
|
||||
* @param Key|array<string, Key> $keyOrKeyArray
|
||||
* @param string|null $kid
|
||||
*
|
||||
* @throws UnexpectedValueException
|
||||
*
|
||||
* @return array containing the keyMaterial and algorithm
|
||||
*/
|
||||
private static function getKey($keyOrKeyArray, $kid = null)
|
||||
{
|
||||
if ($keyOrKeyArray instanceof Key) {
|
||||
return $keyOrKeyArray;
|
||||
}
|
||||
|
||||
if (is_array($keyOrKeyArray) || $keyOrKeyArray instanceof ArrayAccess) {
|
||||
foreach ($keyOrKeyArray as $keyId => $key) {
|
||||
if (!$key instanceof Key) {
|
||||
throw new UnexpectedValueException(
|
||||
'$keyOrKeyArray must be an instance of Firebase\JWT\Key key or an '
|
||||
. 'array of Firebase\JWT\Key keys'
|
||||
);
|
||||
}
|
||||
}
|
||||
if (!isset($kid)) {
|
||||
throw new UnexpectedValueException('"kid" empty, unable to lookup correct key');
|
||||
}
|
||||
if (!isset($keyOrKeyArray[$kid])) {
|
||||
throw new UnexpectedValueException('"kid" invalid, unable to lookup correct key');
|
||||
}
|
||||
|
||||
return $keyOrKeyArray[$kid];
|
||||
}
|
||||
|
||||
throw new UnexpectedValueException(
|
||||
'$keyOrKeyArray must be an instance of Firebase\JWT\Key key or an '
|
||||
. 'array of Firebase\JWT\Key keys'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $left
|
||||
* @param string $right
|
||||
* @return bool
|
||||
*/
|
||||
public static function constantTimeEquals($left, $right)
|
||||
{
|
||||
if (\function_exists('hash_equals')) {
|
||||
return \hash_equals($left, $right);
|
||||
}
|
||||
$len = \min(static::safeStrlen($left), static::safeStrlen($right));
|
||||
|
||||
$status = 0;
|
||||
for ($i = 0; $i < $len; $i++) {
|
||||
$status |= (\ord($left[$i]) ^ \ord($right[$i]));
|
||||
}
|
||||
$status |= (static::safeStrlen($left) ^ static::safeStrlen($right));
|
||||
|
||||
return ($status === 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to create a JSON error.
|
||||
*
|
||||
@ -415,9 +503,9 @@ class JWT
|
||||
}
|
||||
|
||||
return self::encodeDER(
|
||||
self::ASN1_SEQUENCE,
|
||||
self::encodeDER(self::ASN1_INTEGER, $r) .
|
||||
self::encodeDER(self::ASN1_INTEGER, $s)
|
||||
self::$asn1Sequence,
|
||||
self::encodeDER(self::$asn1Integer, $r) .
|
||||
self::encodeDER(self::$asn1Integer, $s)
|
||||
);
|
||||
}
|
||||
|
||||
@ -431,7 +519,7 @@ class JWT
|
||||
private static function encodeDER($type, $value)
|
||||
{
|
||||
$tag_header = 0;
|
||||
if ($type === self::ASN1_SEQUENCE) {
|
||||
if ($type === self::$asn1Sequence) {
|
||||
$tag_header |= 0x20;
|
||||
}
|
||||
|
||||
@ -496,7 +584,7 @@ class JWT
|
||||
}
|
||||
|
||||
// Value
|
||||
if ($type == self::ASN1_BIT_STRING) {
|
||||
if ($type == self::$asn1BitString) {
|
||||
$pos++; // Skip the first contents octet (padding indicator)
|
||||
$data = \substr($der, $pos, $len - 1);
|
||||
$pos += $len - 1;
|
||||
|
59
lib/php-jwt/src/Key.php
Normal file
59
lib/php-jwt/src/Key.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace Firebase\JWT;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use OpenSSLAsymmetricKey;
|
||||
|
||||
class Key
|
||||
{
|
||||
/** @var string $algorithm */
|
||||
private $algorithm;
|
||||
|
||||
/** @var string|resource|OpenSSLAsymmetricKey $keyMaterial */
|
||||
private $keyMaterial;
|
||||
|
||||
/**
|
||||
* @param string|resource|OpenSSLAsymmetricKey $keyMaterial
|
||||
* @param string $algorithm
|
||||
*/
|
||||
public function __construct($keyMaterial, $algorithm)
|
||||
{
|
||||
if (
|
||||
!is_string($keyMaterial)
|
||||
&& !is_resource($keyMaterial)
|
||||
&& !$keyMaterial instanceof OpenSSLAsymmetricKey
|
||||
) {
|
||||
throw new InvalidArgumentException('Type error: $keyMaterial must be a string, resource, or OpenSSLAsymmetricKey');
|
||||
}
|
||||
|
||||
if (empty($keyMaterial)) {
|
||||
throw new InvalidArgumentException('Type error: $keyMaterial must not be empty');
|
||||
}
|
||||
|
||||
if (!is_string($algorithm)|| empty($keyMaterial)) {
|
||||
throw new InvalidArgumentException('Type error: $algorithm must be a string');
|
||||
}
|
||||
|
||||
$this->keyMaterial = $keyMaterial;
|
||||
$this->algorithm = $algorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the algorithm valid for this key
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAlgorithm()
|
||||
{
|
||||
return $this->algorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|resource|OpenSSLAsymmetricKey
|
||||
*/
|
||||
public function getKeyMaterial()
|
||||
{
|
||||
return $this->keyMaterial;
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Firebase\JWT;
|
||||
|
||||
class SignatureInvalidException extends \UnexpectedValueException
|
||||
|
Loading…
x
Reference in New Issue
Block a user