first commit
This commit is contained in:
20
libraries/vendor/web-token/jwt-core/Algorithm.php
vendored
Normal file
20
libraries/vendor/web-token/jwt-core/Algorithm.php
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Core;
|
||||
|
||||
interface Algorithm
|
||||
{
|
||||
/**
|
||||
* Returns the name of the algorithm.
|
||||
*/
|
||||
public function name(): string;
|
||||
|
||||
/**
|
||||
* Returns the key types suitable for this algorithm (e.g. "oct", "RSA"...).
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function allowedKeyTypes(): array;
|
||||
}
|
||||
66
libraries/vendor/web-token/jwt-core/AlgorithmManager.php
vendored
Normal file
66
libraries/vendor/web-token/jwt-core/AlgorithmManager.php
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Core;
|
||||
|
||||
use function array_key_exists;
|
||||
use InvalidArgumentException;
|
||||
|
||||
class AlgorithmManager
|
||||
{
|
||||
private array $algorithms = [];
|
||||
|
||||
/**
|
||||
* @param Algorithm[] $algorithms
|
||||
*/
|
||||
public function __construct(array $algorithms)
|
||||
{
|
||||
foreach ($algorithms as $algorithm) {
|
||||
$this->add($algorithm);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the algorithm is supported.
|
||||
*
|
||||
* @param string $algorithm The algorithm
|
||||
*/
|
||||
public function has(string $algorithm): bool
|
||||
{
|
||||
return array_key_exists($algorithm, $this->algorithms);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of names of supported algorithms.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function list(): array
|
||||
{
|
||||
return array_keys($this->algorithms);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the algorithm if supported, otherwise throw an exception.
|
||||
*
|
||||
* @param string $algorithm The algorithm
|
||||
*/
|
||||
public function get(string $algorithm): Algorithm
|
||||
{
|
||||
if (! $this->has($algorithm)) {
|
||||
throw new InvalidArgumentException(sprintf('The algorithm "%s" is not supported.', $algorithm));
|
||||
}
|
||||
|
||||
return $this->algorithms[$algorithm];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an algorithm to the manager.
|
||||
*/
|
||||
public function add(Algorithm $algorithm): void
|
||||
{
|
||||
$name = $algorithm->name();
|
||||
$this->algorithms[$name] = $algorithm;
|
||||
}
|
||||
}
|
||||
72
libraries/vendor/web-token/jwt-core/AlgorithmManagerFactory.php
vendored
Normal file
72
libraries/vendor/web-token/jwt-core/AlgorithmManagerFactory.php
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Core;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use function is_string;
|
||||
|
||||
/**
|
||||
* @see \Jose\Tests\Component\Core\AlgorithmManagerFactoryTest
|
||||
*/
|
||||
class AlgorithmManagerFactory
|
||||
{
|
||||
private array $algorithms = [];
|
||||
|
||||
/**
|
||||
* Adds an algorithm.
|
||||
*
|
||||
* Each algorithm is identified by an alias hence it is allowed to have the same algorithm twice (or more). This can
|
||||
* be helpful when an algorithm have several configuration options.
|
||||
*/
|
||||
public function add(string $alias, Algorithm $algorithm): void
|
||||
{
|
||||
$this->algorithms[$alias] = $algorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of aliases.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function aliases(): array
|
||||
{
|
||||
return array_keys($this->algorithms);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all algorithms supported by this factory. This is an associative array. Keys are the aliases of the
|
||||
* algorithms.
|
||||
*
|
||||
* @return Algorithm[]
|
||||
*/
|
||||
public function all(): array
|
||||
{
|
||||
return $this->algorithms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an algorithm manager using the given aliases.
|
||||
*
|
||||
* @param string[] $aliases
|
||||
*/
|
||||
public function create(array $aliases): AlgorithmManager
|
||||
{
|
||||
$algorithms = [];
|
||||
foreach ($aliases as $alias) {
|
||||
if (! is_string($alias)) {
|
||||
throw new InvalidArgumentException('Invalid alias');
|
||||
}
|
||||
if (! isset($this->algorithms[$alias])) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'The algorithm with the alias "%s" is not supported.',
|
||||
$alias
|
||||
));
|
||||
}
|
||||
$algorithms[] = $this->algorithms[$alias];
|
||||
}
|
||||
|
||||
return new AlgorithmManager($algorithms);
|
||||
}
|
||||
}
|
||||
127
libraries/vendor/web-token/jwt-core/JWK.php
vendored
Normal file
127
libraries/vendor/web-token/jwt-core/JWK.php
vendored
Normal file
@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Core;
|
||||
|
||||
use function array_key_exists;
|
||||
use function in_array;
|
||||
use InvalidArgumentException;
|
||||
use function is_array;
|
||||
use const JSON_THROW_ON_ERROR;
|
||||
use const JSON_UNESCAPED_SLASHES;
|
||||
use const JSON_UNESCAPED_UNICODE;
|
||||
use JsonSerializable;
|
||||
use ParagonIE\ConstantTime\Base64UrlSafe;
|
||||
|
||||
/**
|
||||
* @see \Jose\Tests\Component\Core\JWKTest
|
||||
*/
|
||||
class JWK implements JsonSerializable
|
||||
{
|
||||
private array $values = [];
|
||||
|
||||
/**
|
||||
* Creates a JWK object using the given values. The member "kty" is mandatory. Other members are NOT checked.
|
||||
*/
|
||||
public function __construct(array $values)
|
||||
{
|
||||
if (! isset($values['kty'])) {
|
||||
throw new InvalidArgumentException('The parameter "kty" is mandatory.');
|
||||
}
|
||||
$this->values = $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JWK object using the given Json string.
|
||||
*/
|
||||
public static function createFromJson(string $json): self
|
||||
{
|
||||
$data = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
|
||||
if (! is_array($data)) {
|
||||
throw new InvalidArgumentException('Invalid argument.');
|
||||
}
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the values to be serialized.
|
||||
*/
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return $this->values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value with a specific key.
|
||||
*
|
||||
* @param string $key The key
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function get(string $key)
|
||||
{
|
||||
if (! $this->has($key)) {
|
||||
throw new InvalidArgumentException(sprintf('The value identified by "%s" does not exist.', $key));
|
||||
}
|
||||
|
||||
return $this->values[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the JWK has the value identified by.
|
||||
*
|
||||
* @param string $key The key
|
||||
*/
|
||||
public function has(string $key): bool
|
||||
{
|
||||
return array_key_exists($key, $this->values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all values stored in the JWK object.
|
||||
*
|
||||
* @return array Values of the JWK object
|
||||
*/
|
||||
public function all(): array
|
||||
{
|
||||
return $this->values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the thumbprint of the key.
|
||||
*
|
||||
* @see https://tools.ietf.org/html/rfc7638
|
||||
*/
|
||||
public function thumbprint(string $hash_algorithm): string
|
||||
{
|
||||
if (! in_array($hash_algorithm, hash_algos(), true)) {
|
||||
throw new InvalidArgumentException(sprintf('The hash algorithm "%s" is not supported.', $hash_algorithm));
|
||||
}
|
||||
$values = array_intersect_key($this->values, array_flip(['kty', 'n', 'e', 'crv', 'x', 'y', 'k']));
|
||||
ksort($values);
|
||||
$input = json_encode($values, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
if ($input === false) {
|
||||
throw new InvalidArgumentException('Unable to compute the key thumbprint');
|
||||
}
|
||||
|
||||
return Base64UrlSafe::encodeUnpadded(hash($hash_algorithm, $input, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the associated public key.
|
||||
* This method has no effect for:
|
||||
* - public keys
|
||||
* - shared keys
|
||||
* - unknown keys.
|
||||
*
|
||||
* Known keys are "oct", "RSA", "EC" and "OKP".
|
||||
*/
|
||||
public function toPublic(): self
|
||||
{
|
||||
$values = array_diff_key($this->values, array_flip(['p', 'd', 'q', 'dp', 'dq', 'qi']));
|
||||
|
||||
return new self($values);
|
||||
}
|
||||
}
|
||||
296
libraries/vendor/web-token/jwt-core/JWKSet.php
vendored
Normal file
296
libraries/vendor/web-token/jwt-core/JWKSet.php
vendored
Normal file
@ -0,0 +1,296 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Core;
|
||||
|
||||
use function array_key_exists;
|
||||
use ArrayIterator;
|
||||
use function count;
|
||||
use const COUNT_NORMAL;
|
||||
use Countable;
|
||||
use function in_array;
|
||||
use InvalidArgumentException;
|
||||
use function is_array;
|
||||
use IteratorAggregate;
|
||||
use const JSON_THROW_ON_ERROR;
|
||||
use JsonSerializable;
|
||||
use Traversable;
|
||||
|
||||
class JWKSet implements Countable, IteratorAggregate, JsonSerializable
|
||||
{
|
||||
private array $keys = [];
|
||||
|
||||
/**
|
||||
* @param JWK[] $keys
|
||||
*/
|
||||
public function __construct(array $keys)
|
||||
{
|
||||
foreach ($keys as $k => $key) {
|
||||
if (! $key instanceof JWK) {
|
||||
throw new InvalidArgumentException('Invalid list. Should only contains JWK objects');
|
||||
}
|
||||
|
||||
if ($key->has('kid')) {
|
||||
unset($keys[$k]);
|
||||
$this->keys[$key->get('kid')] = $key;
|
||||
} else {
|
||||
$this->keys[] = $key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JWKSet object using the given values.
|
||||
*/
|
||||
public static function createFromKeyData(array $data): self
|
||||
{
|
||||
if (! isset($data['keys'])) {
|
||||
throw new InvalidArgumentException('Invalid data.');
|
||||
}
|
||||
if (! is_array($data['keys'])) {
|
||||
throw new InvalidArgumentException('Invalid data.');
|
||||
}
|
||||
|
||||
$jwkset = new self([]);
|
||||
foreach ($data['keys'] as $key) {
|
||||
$jwk = new JWK($key);
|
||||
if ($jwk->has('kid')) {
|
||||
$jwkset->keys[$jwk->get('kid')] = $jwk;
|
||||
} else {
|
||||
$jwkset->keys[] = $jwk;
|
||||
}
|
||||
}
|
||||
|
||||
return $jwkset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JWKSet object using the given Json string.
|
||||
*/
|
||||
public static function createFromJson(string $json): self
|
||||
{
|
||||
$data = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
|
||||
if (! is_array($data)) {
|
||||
throw new InvalidArgumentException('Invalid argument.');
|
||||
}
|
||||
|
||||
return self::createFromKeyData($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of keys stored in the key set.
|
||||
*
|
||||
* @return JWK[]
|
||||
*/
|
||||
public function all(): array
|
||||
{
|
||||
return $this->keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add key to store in the key set. This method is immutable and will return a new object.
|
||||
*/
|
||||
public function with(JWK $jwk): self
|
||||
{
|
||||
$clone = clone $this;
|
||||
|
||||
if ($jwk->has('kid')) {
|
||||
$clone->keys[$jwk->get('kid')] = $jwk;
|
||||
} else {
|
||||
$clone->keys[] = $jwk;
|
||||
}
|
||||
|
||||
return $clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove key from the key set. This method is immutable and will return a new object.
|
||||
*
|
||||
* @param int|string $key Key to remove from the key set
|
||||
*/
|
||||
public function without(int|string $key): self
|
||||
{
|
||||
if (! $this->has($key)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$clone = clone $this;
|
||||
unset($clone->keys[$key]);
|
||||
|
||||
return $clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the key set contains a key with the given index.
|
||||
*/
|
||||
public function has(int|string $index): bool
|
||||
{
|
||||
return array_key_exists($index, $this->keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key with the given index. Throws an exception if the index is not present in the key store.
|
||||
*/
|
||||
public function get(int|string $index): JWK
|
||||
{
|
||||
if (! $this->has($index)) {
|
||||
throw new InvalidArgumentException('Undefined index.');
|
||||
}
|
||||
|
||||
return $this->keys[$index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the values to be serialized.
|
||||
*/
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return [
|
||||
'keys' => array_values($this->keys),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of keys in the key set.
|
||||
*
|
||||
* @param int $mode
|
||||
*/
|
||||
public function count($mode = COUNT_NORMAL): int
|
||||
{
|
||||
return count($this->keys, $mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to find a key that fits on the selected requirements. Returns null if not found.
|
||||
*
|
||||
* @param string $type Must be 'sig' (signature) or 'enc' (encryption)
|
||||
* @param Algorithm|null $algorithm Specifies the algorithm to be used
|
||||
* @param array<string, mixed> $restrictions More restrictions such as 'kid' or 'kty'
|
||||
*/
|
||||
public function selectKey(string $type, ?Algorithm $algorithm = null, array $restrictions = []): ?JWK
|
||||
{
|
||||
if (! in_array($type, ['enc', 'sig'], true)) {
|
||||
throw new InvalidArgumentException('Allowed key types are "sig" or "enc".');
|
||||
}
|
||||
|
||||
$result = [];
|
||||
foreach ($this->keys as $key) {
|
||||
$ind = 0;
|
||||
|
||||
$can_use = $this->canKeyBeUsedFor($type, $key);
|
||||
if ($can_use === false) {
|
||||
continue;
|
||||
}
|
||||
$ind += $can_use;
|
||||
|
||||
$alg = $this->canKeyBeUsedWithAlgorithm($algorithm, $key);
|
||||
if ($alg === false) {
|
||||
continue;
|
||||
}
|
||||
$ind += $alg;
|
||||
|
||||
if ($this->doesKeySatisfyRestrictions($restrictions, $key) === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$result[] = [
|
||||
'key' => $key,
|
||||
'ind' => $ind,
|
||||
];
|
||||
}
|
||||
|
||||
if (count($result) === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
usort($result, [$this, 'sortKeys']);
|
||||
|
||||
return $result[0]['key'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method only. Should not be used.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public static function sortKeys(array $a, array $b): int
|
||||
{
|
||||
return $b['ind'] <=> $a['ind'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method only. Should not be used.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function getIterator(): Traversable
|
||||
{
|
||||
return new ArrayIterator($this->keys);
|
||||
}
|
||||
|
||||
private function canKeyBeUsedFor(string $type, JWK $key): bool|int
|
||||
{
|
||||
if ($key->has('use')) {
|
||||
return $type === $key->get('use') ? 1 : false;
|
||||
}
|
||||
if ($key->has('key_ops')) {
|
||||
$key_ops = $key->get('key_ops');
|
||||
if (! is_array($key_ops)) {
|
||||
throw new InvalidArgumentException(
|
||||
'Invalid key parameter "key_ops". Should be a list of key operations'
|
||||
);
|
||||
}
|
||||
|
||||
return $type === self::convertKeyOpsToKeyUse($key_ops) ? 1 : false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function canKeyBeUsedWithAlgorithm(?Algorithm $algorithm, JWK $key): bool|int
|
||||
{
|
||||
if ($algorithm === null) {
|
||||
return 0;
|
||||
}
|
||||
if (! in_array($key->get('kty'), $algorithm->allowedKeyTypes(), true)) {
|
||||
return false;
|
||||
}
|
||||
if ($key->has('alg')) {
|
||||
return $algorithm->name() === $key->get('alg') ? 2 : false;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private function doesKeySatisfyRestrictions(array $restrictions, JWK $key): bool
|
||||
{
|
||||
foreach ($restrictions as $k => $v) {
|
||||
if (! $key->has($k) || $v !== $key->get($k)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static function convertKeyOpsToKeyUse(array $key_ops): string
|
||||
{
|
||||
return match (true) {
|
||||
in_array('verify', $key_ops, true), in_array('sign', $key_ops, true) => 'sig',
|
||||
in_array('encrypt', $key_ops, true), in_array('decrypt', $key_ops, true), in_array(
|
||||
'wrapKey',
|
||||
$key_ops,
|
||||
true
|
||||
), in_array(
|
||||
'unwrapKey',
|
||||
$key_ops,
|
||||
true
|
||||
), in_array('deriveKey', $key_ops, true), in_array('deriveBits', $key_ops, true) => 'enc',
|
||||
default => throw new InvalidArgumentException(sprintf(
|
||||
'Unsupported key operation value "%s"',
|
||||
implode(', ', $key_ops)
|
||||
)),
|
||||
};
|
||||
}
|
||||
}
|
||||
13
libraries/vendor/web-token/jwt-core/JWT.php
vendored
Normal file
13
libraries/vendor/web-token/jwt-core/JWT.php
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Core;
|
||||
|
||||
interface JWT
|
||||
{
|
||||
/**
|
||||
* Returns the payload of the JWT. null is a valid payload (e.g. JWS with detached payload).
|
||||
*/
|
||||
public function getPayload(): ?string;
|
||||
}
|
||||
21
libraries/vendor/web-token/jwt-core/LICENSE
vendored
Normal file
21
libraries/vendor/web-token/jwt-core/LICENSE
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2019 Spomky-Labs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
163
libraries/vendor/web-token/jwt-core/Util/BigInteger.php
vendored
Normal file
163
libraries/vendor/web-token/jwt-core/Util/BigInteger.php
vendored
Normal file
@ -0,0 +1,163 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Core\Util;
|
||||
|
||||
use Brick\Math\BigInteger as BrickBigInteger;
|
||||
use function chr;
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class BigInteger
|
||||
{
|
||||
private function __construct(
|
||||
private readonly BrickBigInteger $value
|
||||
) {
|
||||
}
|
||||
|
||||
public static function createFromBinaryString(string $value): self
|
||||
{
|
||||
$res = unpack('H*', $value);
|
||||
if ($res === false) {
|
||||
throw new InvalidArgumentException('Unable to convert the value');
|
||||
}
|
||||
$data = current($res);
|
||||
|
||||
return new self(BrickBigInteger::fromBase($data, 16));
|
||||
}
|
||||
|
||||
public static function createFromDecimal(int $value): self
|
||||
{
|
||||
return new self(BrickBigInteger::of($value));
|
||||
}
|
||||
|
||||
public static function createFromBigInteger(BrickBigInteger $value): self
|
||||
{
|
||||
return new self($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a BigInteger to a binary string.
|
||||
*/
|
||||
public function toBytes(): string
|
||||
{
|
||||
if ($this->value->isEqualTo(BrickBigInteger::zero())) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$temp = $this->value->toBase(16);
|
||||
$temp = 0 !== (mb_strlen($temp, '8bit') & 1) ? '0' . $temp : $temp;
|
||||
$temp = hex2bin($temp);
|
||||
if ($temp === false) {
|
||||
throw new InvalidArgumentException('Unable to convert the value into bytes');
|
||||
}
|
||||
|
||||
return ltrim($temp, chr(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds two BigIntegers.
|
||||
*/
|
||||
public function add(self $y): self
|
||||
{
|
||||
$value = $this->value->plus($y->value);
|
||||
|
||||
return new self($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts two BigIntegers.
|
||||
*/
|
||||
public function subtract(self $y): self
|
||||
{
|
||||
$value = $this->value->minus($y->value);
|
||||
|
||||
return new self($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies two BigIntegers.
|
||||
*/
|
||||
public function multiply(self $x): self
|
||||
{
|
||||
$value = $this->value->multipliedBy($x->value);
|
||||
|
||||
return new self($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Divides two BigIntegers.
|
||||
*/
|
||||
public function divide(self $x): self
|
||||
{
|
||||
$value = $this->value->dividedBy($x->value);
|
||||
|
||||
return new self($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs modular exponentiation.
|
||||
*/
|
||||
public function modPow(self $e, self $n): self
|
||||
{
|
||||
$value = $this->value->modPow($e->value, $n->value);
|
||||
|
||||
return new self($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs modular exponentiation.
|
||||
*/
|
||||
public function mod(self $d): self
|
||||
{
|
||||
$value = $this->value->mod($d->value);
|
||||
|
||||
return new self($value);
|
||||
}
|
||||
|
||||
public function modInverse(self $m): self
|
||||
{
|
||||
return new self($this->value->modInverse($m->value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two numbers.
|
||||
*/
|
||||
public function compare(self $y): int
|
||||
{
|
||||
return $this->value->compareTo($y->value);
|
||||
}
|
||||
|
||||
public function equals(self $y): bool
|
||||
{
|
||||
return $this->value->isEqualTo($y->value);
|
||||
}
|
||||
|
||||
public static function random(self $y): self
|
||||
{
|
||||
return new self(BrickBigInteger::randomRange(0, $y->value));
|
||||
}
|
||||
|
||||
public function gcd(self $y): self
|
||||
{
|
||||
return new self($this->value->gcd($y->value));
|
||||
}
|
||||
|
||||
public function lowerThan(self $y): bool
|
||||
{
|
||||
return $this->value->isLessThan($y->value);
|
||||
}
|
||||
|
||||
public function isEven(): bool
|
||||
{
|
||||
return $this->value->isEven();
|
||||
}
|
||||
|
||||
public function get(): BrickBigInteger
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
}
|
||||
328
libraries/vendor/web-token/jwt-core/Util/ECKey.php
vendored
Normal file
328
libraries/vendor/web-token/jwt-core/Util/ECKey.php
vendored
Normal file
@ -0,0 +1,328 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Core\Util;
|
||||
|
||||
use function extension_loaded;
|
||||
use InvalidArgumentException;
|
||||
use function is_array;
|
||||
use function is_string;
|
||||
use Jose\Component\Core\JWK;
|
||||
use const OPENSSL_KEYTYPE_EC;
|
||||
use ParagonIE\ConstantTime\Base64UrlSafe;
|
||||
use const PHP_EOL;
|
||||
use RuntimeException;
|
||||
use const STR_PAD_LEFT;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class ECKey
|
||||
{
|
||||
public static function convertToPEM(JWK $jwk): string
|
||||
{
|
||||
if ($jwk->has('d')) {
|
||||
return self::convertPrivateKeyToPEM($jwk);
|
||||
}
|
||||
|
||||
return self::convertPublicKeyToPEM($jwk);
|
||||
}
|
||||
|
||||
public static function convertPublicKeyToPEM(JWK $jwk): string
|
||||
{
|
||||
$der = match ($jwk->get('crv')) {
|
||||
'P-256' => self::p256PublicKey(),
|
||||
'secp256k1' => self::p256KPublicKey(),
|
||||
'P-384' => self::p384PublicKey(),
|
||||
'P-521' => self::p521PublicKey(),
|
||||
default => throw new InvalidArgumentException('Unsupported curve.'),
|
||||
};
|
||||
$der .= self::getKey($jwk);
|
||||
$pem = '-----BEGIN PUBLIC KEY-----' . PHP_EOL;
|
||||
$pem .= chunk_split(base64_encode($der), 64, PHP_EOL);
|
||||
|
||||
return $pem . ('-----END PUBLIC KEY-----' . PHP_EOL);
|
||||
}
|
||||
|
||||
public static function convertPrivateKeyToPEM(JWK $jwk): string
|
||||
{
|
||||
$der = match ($jwk->get('crv')) {
|
||||
'P-256' => self::p256PrivateKey($jwk),
|
||||
'secp256k1' => self::p256KPrivateKey($jwk),
|
||||
'P-384' => self::p384PrivateKey($jwk),
|
||||
'P-521' => self::p521PrivateKey($jwk),
|
||||
default => throw new InvalidArgumentException('Unsupported curve.'),
|
||||
};
|
||||
$der .= self::getKey($jwk);
|
||||
$pem = '-----BEGIN EC PRIVATE KEY-----' . PHP_EOL;
|
||||
$pem .= chunk_split(base64_encode($der), 64, PHP_EOL);
|
||||
|
||||
return $pem . ('-----END EC PRIVATE KEY-----' . PHP_EOL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a EC key with the given curve and additional values.
|
||||
*
|
||||
* @param string $curve The curve
|
||||
* @param array $values values to configure the key
|
||||
*/
|
||||
public static function createECKey(string $curve, array $values = []): JWK
|
||||
{
|
||||
$jwk = self::createECKeyUsingOpenSSL($curve);
|
||||
$values = array_merge($values, $jwk);
|
||||
|
||||
return new JWK($values);
|
||||
}
|
||||
|
||||
private static function getNistCurveSize(string $curve): int
|
||||
{
|
||||
return match ($curve) {
|
||||
'P-256', 'secp256k1' => 256,
|
||||
'P-384' => 384,
|
||||
'P-521' => 521,
|
||||
default => throw new InvalidArgumentException(sprintf('The curve "%s" is not supported.', $curve)),
|
||||
};
|
||||
}
|
||||
|
||||
private static function createECKeyUsingOpenSSL(string $curve): array
|
||||
{
|
||||
if (! extension_loaded('openssl')) {
|
||||
throw new RuntimeException('Please install the OpenSSL extension');
|
||||
}
|
||||
$key = openssl_pkey_new([
|
||||
'curve_name' => self::getOpensslCurveName($curve),
|
||||
'private_key_type' => OPENSSL_KEYTYPE_EC,
|
||||
]);
|
||||
if ($key === false) {
|
||||
throw new RuntimeException('Unable to create the key');
|
||||
}
|
||||
$result = openssl_pkey_export($key, $out);
|
||||
if ($result === false) {
|
||||
throw new RuntimeException('Unable to create the key');
|
||||
}
|
||||
$res = openssl_pkey_get_private($out);
|
||||
if ($res === false) {
|
||||
throw new RuntimeException('Unable to create the key');
|
||||
}
|
||||
$details = openssl_pkey_get_details($res);
|
||||
if ($details === false) {
|
||||
throw new InvalidArgumentException('Unable to get the key details');
|
||||
}
|
||||
$nistCurveSize = self::getNistCurveSize($curve);
|
||||
|
||||
return [
|
||||
'kty' => 'EC',
|
||||
'crv' => $curve,
|
||||
'd' => Base64UrlSafe::encodeUnpadded(
|
||||
str_pad((string) $details['ec']['d'], (int) ceil($nistCurveSize / 8), "\0", STR_PAD_LEFT)
|
||||
),
|
||||
'x' => Base64UrlSafe::encodeUnpadded(
|
||||
str_pad((string) $details['ec']['x'], (int) ceil($nistCurveSize / 8), "\0", STR_PAD_LEFT)
|
||||
),
|
||||
'y' => Base64UrlSafe::encodeUnpadded(
|
||||
str_pad((string) $details['ec']['y'], (int) ceil($nistCurveSize / 8), "\0", STR_PAD_LEFT)
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
private static function getOpensslCurveName(string $curve): string
|
||||
{
|
||||
return match ($curve) {
|
||||
'P-256' => 'prime256v1',
|
||||
'secp256k1' => 'secp256k1',
|
||||
'P-384' => 'secp384r1',
|
||||
'P-521' => 'secp521r1',
|
||||
default => throw new InvalidArgumentException(sprintf('The curve "%s" is not supported.', $curve)),
|
||||
};
|
||||
}
|
||||
|
||||
private static function p256PublicKey(): string
|
||||
{
|
||||
return pack(
|
||||
'H*',
|
||||
'3059' // SEQUENCE, length 89
|
||||
. '3013' // SEQUENCE, length 19
|
||||
. '0607' // OID, length 7
|
||||
. '2a8648ce3d0201' // 1.2.840.10045.2.1 = EC Public Key
|
||||
. '0608' // OID, length 8
|
||||
. '2a8648ce3d030107' // 1.2.840.10045.3.1.7 = P-256 Curve
|
||||
. '0342' // BIT STRING, length 66
|
||||
. '00' // prepend with NUL - pubkey will follow
|
||||
);
|
||||
}
|
||||
|
||||
private static function p256KPublicKey(): string
|
||||
{
|
||||
return pack(
|
||||
'H*',
|
||||
'3056' // SEQUENCE, length 86
|
||||
. '3010' // SEQUENCE, length 16
|
||||
. '0607' // OID, length 7
|
||||
. '2a8648ce3d0201' // 1.2.840.10045.2.1 = EC Public Key
|
||||
. '0605' // OID, length 8
|
||||
. '2B8104000A' // 1.3.132.0.10 secp256k1
|
||||
. '0342' // BIT STRING, length 66
|
||||
. '00' // prepend with NUL - pubkey will follow
|
||||
);
|
||||
}
|
||||
|
||||
private static function p384PublicKey(): string
|
||||
{
|
||||
return pack(
|
||||
'H*',
|
||||
'3076' // SEQUENCE, length 118
|
||||
. '3010' // SEQUENCE, length 16
|
||||
. '0607' // OID, length 7
|
||||
. '2a8648ce3d0201' // 1.2.840.10045.2.1 = EC Public Key
|
||||
. '0605' // OID, length 5
|
||||
. '2b81040022' // 1.3.132.0.34 = P-384 Curve
|
||||
. '0362' // BIT STRING, length 98
|
||||
. '00' // prepend with NUL - pubkey will follow
|
||||
);
|
||||
}
|
||||
|
||||
private static function p521PublicKey(): string
|
||||
{
|
||||
return pack(
|
||||
'H*',
|
||||
'30819b' // SEQUENCE, length 154
|
||||
. '3010' // SEQUENCE, length 16
|
||||
. '0607' // OID, length 7
|
||||
. '2a8648ce3d0201' // 1.2.840.10045.2.1 = EC Public Key
|
||||
. '0605' // OID, length 5
|
||||
. '2b81040023' // 1.3.132.0.35 = P-521 Curve
|
||||
. '038186' // BIT STRING, length 134
|
||||
. '00' // prepend with NUL - pubkey will follow
|
||||
);
|
||||
}
|
||||
|
||||
private static function p256PrivateKey(JWK $jwk): string
|
||||
{
|
||||
$d = $jwk->get('d');
|
||||
if (! is_string($d)) {
|
||||
throw new InvalidArgumentException('Unable to get the private key');
|
||||
}
|
||||
$d = unpack('H*', str_pad(Base64UrlSafe::decode($d), 32, "\0", STR_PAD_LEFT));
|
||||
if (! is_array($d) || ! isset($d[1])) {
|
||||
throw new InvalidArgumentException('Unable to get the private key');
|
||||
}
|
||||
|
||||
return pack(
|
||||
'H*',
|
||||
'3077' // SEQUENCE, length 87+length($d)=32
|
||||
. '020101' // INTEGER, 1
|
||||
. '0420' // OCTET STRING, length($d) = 32
|
||||
. $d[1]
|
||||
. 'a00a' // TAGGED OBJECT #0, length 10
|
||||
. '0608' // OID, length 8
|
||||
. '2a8648ce3d030107' // 1.3.132.0.34 = P-256 Curve
|
||||
. 'a144' // TAGGED OBJECT #1, length 68
|
||||
. '0342' // BIT STRING, length 66
|
||||
. '00' // prepend with NUL - pubkey will follow
|
||||
);
|
||||
}
|
||||
|
||||
private static function p256KPrivateKey(JWK $jwk): string
|
||||
{
|
||||
$d = $jwk->get('d');
|
||||
if (! is_string($d)) {
|
||||
throw new InvalidArgumentException('Unable to get the private key');
|
||||
}
|
||||
$d = unpack('H*', str_pad(Base64UrlSafe::decode($d), 32, "\0", STR_PAD_LEFT));
|
||||
if (! is_array($d) || ! isset($d[1])) {
|
||||
throw new InvalidArgumentException('Unable to get the private key');
|
||||
}
|
||||
|
||||
return pack(
|
||||
'H*',
|
||||
'3074' // SEQUENCE, length 84+length($d)=32
|
||||
. '020101' // INTEGER, 1
|
||||
. '0420' // OCTET STRING, length($d) = 32
|
||||
. $d[1]
|
||||
. 'a007' // TAGGED OBJECT #0, length 7
|
||||
. '0605' // OID, length 5
|
||||
. '2b8104000a' // 1.3.132.0.10 secp256k1
|
||||
. 'a144' // TAGGED OBJECT #1, length 68
|
||||
. '0342' // BIT STRING, length 66
|
||||
. '00' // prepend with NUL - pubkey will follow
|
||||
);
|
||||
}
|
||||
|
||||
private static function p384PrivateKey(JWK $jwk): string
|
||||
{
|
||||
$d = $jwk->get('d');
|
||||
if (! is_string($d)) {
|
||||
throw new InvalidArgumentException('Unable to get the private key');
|
||||
}
|
||||
$d = unpack('H*', str_pad(Base64UrlSafe::decode($d), 48, "\0", STR_PAD_LEFT));
|
||||
if (! is_array($d) || ! isset($d[1])) {
|
||||
throw new InvalidArgumentException('Unable to get the private key');
|
||||
}
|
||||
|
||||
return pack(
|
||||
'H*',
|
||||
'3081a4' // SEQUENCE, length 116 + length($d)=48
|
||||
. '020101' // INTEGER, 1
|
||||
. '0430' // OCTET STRING, length($d) = 30
|
||||
. $d[1]
|
||||
. 'a007' // TAGGED OBJECT #0, length 7
|
||||
. '0605' // OID, length 5
|
||||
. '2b81040022' // 1.3.132.0.34 = P-384 Curve
|
||||
. 'a164' // TAGGED OBJECT #1, length 100
|
||||
. '0362' // BIT STRING, length 98
|
||||
. '00' // prepend with NUL - pubkey will follow
|
||||
);
|
||||
}
|
||||
|
||||
private static function p521PrivateKey(JWK $jwk): string
|
||||
{
|
||||
$d = $jwk->get('d');
|
||||
if (! is_string($d)) {
|
||||
throw new InvalidArgumentException('Unable to get the private key');
|
||||
}
|
||||
$d = unpack('H*', str_pad(Base64UrlSafe::decode($d), 66, "\0", STR_PAD_LEFT));
|
||||
if (! is_array($d) || ! isset($d[1])) {
|
||||
throw new InvalidArgumentException('Unable to get the private key');
|
||||
}
|
||||
|
||||
return pack(
|
||||
'H*',
|
||||
'3081dc' // SEQUENCE, length 154 + length($d)=66
|
||||
. '020101' // INTEGER, 1
|
||||
. '0442' // OCTET STRING, length(d) = 66
|
||||
. $d[1]
|
||||
. 'a007' // TAGGED OBJECT #0, length 7
|
||||
. '0605' // OID, length 5
|
||||
. '2b81040023' // 1.3.132.0.35 = P-521 Curve
|
||||
. 'a18189' // TAGGED OBJECT #1, length 137
|
||||
. '038186' // BIT STRING, length 134
|
||||
. '00' // prepend with NUL - pubkey will follow
|
||||
);
|
||||
}
|
||||
|
||||
private static function getKey(JWK $jwk): string
|
||||
{
|
||||
$crv = $jwk->get('crv');
|
||||
if (! is_string($crv)) {
|
||||
throw new InvalidArgumentException('Unable to get the curve');
|
||||
}
|
||||
$nistCurveSize = self::getNistCurveSize($crv);
|
||||
$length = (int) ceil($nistCurveSize / 8);
|
||||
$x = $jwk->get('x');
|
||||
if (! is_string($x)) {
|
||||
throw new InvalidArgumentException('Unable to get the public key');
|
||||
}
|
||||
$y = $jwk->get('y');
|
||||
if (! is_string($y)) {
|
||||
throw new InvalidArgumentException('Unable to get the public key');
|
||||
}
|
||||
$binX = ltrim(Base64UrlSafe::decode($x), "\0");
|
||||
$binY = ltrim(Base64UrlSafe::decode($y), "\0");
|
||||
|
||||
return "\04"
|
||||
. str_pad($binX, $length, "\0", STR_PAD_LEFT)
|
||||
. str_pad($binY, $length, "\0", STR_PAD_LEFT)
|
||||
;
|
||||
}
|
||||
}
|
||||
131
libraries/vendor/web-token/jwt-core/Util/ECSignature.php
vendored
Normal file
131
libraries/vendor/web-token/jwt-core/Util/ECSignature.php
vendored
Normal file
@ -0,0 +1,131 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Core\Util;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use function is_string;
|
||||
use const STR_PAD_LEFT;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class ECSignature
|
||||
{
|
||||
private const ASN1_SEQUENCE = '30';
|
||||
|
||||
private const ASN1_INTEGER = '02';
|
||||
|
||||
private const ASN1_MAX_SINGLE_BYTE = 128;
|
||||
|
||||
private const ASN1_LENGTH_2BYTES = '81';
|
||||
|
||||
private const ASN1_BIG_INTEGER_LIMIT = '7f';
|
||||
|
||||
private const ASN1_NEGATIVE_INTEGER = '00';
|
||||
|
||||
private const BYTE_SIZE = 2;
|
||||
|
||||
public static function toAsn1(string $signature, int $length): string
|
||||
{
|
||||
$signature = bin2hex($signature);
|
||||
|
||||
if (self::octetLength($signature) !== $length) {
|
||||
throw new InvalidArgumentException('Invalid signature length.');
|
||||
}
|
||||
|
||||
$pointR = self::preparePositiveInteger(mb_substr($signature, 0, $length, '8bit'));
|
||||
$pointS = self::preparePositiveInteger(mb_substr($signature, $length, null, '8bit'));
|
||||
|
||||
$lengthR = self::octetLength($pointR);
|
||||
$lengthS = self::octetLength($pointS);
|
||||
|
||||
$totalLength = $lengthR + $lengthS + self::BYTE_SIZE + self::BYTE_SIZE;
|
||||
$lengthPrefix = $totalLength > self::ASN1_MAX_SINGLE_BYTE ? self::ASN1_LENGTH_2BYTES : '';
|
||||
|
||||
$bin = hex2bin(
|
||||
self::ASN1_SEQUENCE
|
||||
. $lengthPrefix . dechex($totalLength)
|
||||
. self::ASN1_INTEGER . dechex($lengthR) . $pointR
|
||||
. self::ASN1_INTEGER . dechex($lengthS) . $pointS
|
||||
);
|
||||
if (! is_string($bin)) {
|
||||
throw new InvalidArgumentException('Unable to parse the data');
|
||||
}
|
||||
|
||||
return $bin;
|
||||
}
|
||||
|
||||
public static function fromAsn1(string $signature, int $length): string
|
||||
{
|
||||
$message = bin2hex($signature);
|
||||
$position = 0;
|
||||
|
||||
if (self::readAsn1Content($message, $position, self::BYTE_SIZE) !== self::ASN1_SEQUENCE) {
|
||||
throw new InvalidArgumentException('Invalid data. Should start with a sequence.');
|
||||
}
|
||||
|
||||
if (self::readAsn1Content($message, $position, self::BYTE_SIZE) === self::ASN1_LENGTH_2BYTES) {
|
||||
$position += self::BYTE_SIZE;
|
||||
}
|
||||
|
||||
$pointR = self::retrievePositiveInteger(self::readAsn1Integer($message, $position));
|
||||
$pointS = self::retrievePositiveInteger(self::readAsn1Integer($message, $position));
|
||||
|
||||
$bin = hex2bin(str_pad($pointR, $length, '0', STR_PAD_LEFT) . str_pad($pointS, $length, '0', STR_PAD_LEFT));
|
||||
if (! is_string($bin)) {
|
||||
throw new InvalidArgumentException('Unable to parse the data');
|
||||
}
|
||||
|
||||
return $bin;
|
||||
}
|
||||
|
||||
private static function octetLength(string $data): int
|
||||
{
|
||||
return (int) (mb_strlen($data, '8bit') / self::BYTE_SIZE);
|
||||
}
|
||||
|
||||
private static function preparePositiveInteger(string $data): string
|
||||
{
|
||||
if (mb_substr($data, 0, self::BYTE_SIZE, '8bit') > self::ASN1_BIG_INTEGER_LIMIT) {
|
||||
return self::ASN1_NEGATIVE_INTEGER . $data;
|
||||
}
|
||||
|
||||
while (mb_strpos($data, self::ASN1_NEGATIVE_INTEGER, 0, '8bit') === 0
|
||||
&& mb_substr($data, 2, self::BYTE_SIZE, '8bit') <= self::ASN1_BIG_INTEGER_LIMIT) {
|
||||
$data = mb_substr($data, 2, null, '8bit');
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
private static function readAsn1Content(string $message, int &$position, int $length): string
|
||||
{
|
||||
$content = mb_substr($message, $position, $length, '8bit');
|
||||
$position += $length;
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
private static function readAsn1Integer(string $message, int &$position): string
|
||||
{
|
||||
if (self::readAsn1Content($message, $position, self::BYTE_SIZE) !== self::ASN1_INTEGER) {
|
||||
throw new InvalidArgumentException('Invalid data. Should contain an integer.');
|
||||
}
|
||||
|
||||
$length = (int) hexdec(self::readAsn1Content($message, $position, self::BYTE_SIZE));
|
||||
|
||||
return self::readAsn1Content($message, $position, $length * self::BYTE_SIZE);
|
||||
}
|
||||
|
||||
private static function retrievePositiveInteger(string $data): string
|
||||
{
|
||||
while (mb_strpos($data, self::ASN1_NEGATIVE_INTEGER, 0, '8bit') === 0
|
||||
&& mb_substr($data, 2, self::BYTE_SIZE, '8bit') > self::ASN1_BIG_INTEGER_LIMIT) {
|
||||
$data = mb_substr($data, 2, null, '8bit');
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
61
libraries/vendor/web-token/jwt-core/Util/Hash.php
vendored
Normal file
61
libraries/vendor/web-token/jwt-core/Util/Hash.php
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Core\Util;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class Hash
|
||||
{
|
||||
private function __construct(
|
||||
private readonly string $hash,
|
||||
private readonly int $length,
|
||||
private readonly string $t
|
||||
) {
|
||||
}
|
||||
|
||||
public static function sha1(): self
|
||||
{
|
||||
return new self('sha1', 20, "\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14");
|
||||
}
|
||||
|
||||
public static function sha256(): self
|
||||
{
|
||||
return new self('sha256', 32, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20");
|
||||
}
|
||||
|
||||
public static function sha384(): self
|
||||
{
|
||||
return new self('sha384', 48, "\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02\x05\x00\x04\x30");
|
||||
}
|
||||
|
||||
public static function sha512(): self
|
||||
{
|
||||
return new self('sha512', 64, "\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03\x05\x00\x04\x40");
|
||||
}
|
||||
|
||||
public function getLength(): int
|
||||
{
|
||||
return $this->length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the HMAC.
|
||||
*/
|
||||
public function hash(string $text): string
|
||||
{
|
||||
return hash($this->hash, $text, true);
|
||||
}
|
||||
|
||||
public function name(): string
|
||||
{
|
||||
return $this->hash;
|
||||
}
|
||||
|
||||
public function t(): string
|
||||
{
|
||||
return $this->t;
|
||||
}
|
||||
}
|
||||
28
libraries/vendor/web-token/jwt-core/Util/JsonConverter.php
vendored
Normal file
28
libraries/vendor/web-token/jwt-core/Util/JsonConverter.php
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Core\Util;
|
||||
|
||||
use const JSON_THROW_ON_ERROR;
|
||||
use const JSON_UNESCAPED_SLASHES;
|
||||
use const JSON_UNESCAPED_UNICODE;
|
||||
use RuntimeException;
|
||||
use Throwable;
|
||||
|
||||
final class JsonConverter
|
||||
{
|
||||
public static function encode(mixed $payload): string
|
||||
{
|
||||
try {
|
||||
return json_encode($payload, JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
} catch (Throwable $throwable) {
|
||||
throw new RuntimeException('Invalid content.', $throwable->getCode(), $throwable);
|
||||
}
|
||||
}
|
||||
|
||||
public static function decode(string $payload): mixed
|
||||
{
|
||||
return json_decode($payload, true, 512, JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
}
|
||||
116
libraries/vendor/web-token/jwt-core/Util/KeyChecker.php
vendored
Normal file
116
libraries/vendor/web-token/jwt-core/Util/KeyChecker.php
vendored
Normal file
@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Core\Util;
|
||||
|
||||
use function in_array;
|
||||
use InvalidArgumentException;
|
||||
use function is_array;
|
||||
use function is_string;
|
||||
use Jose\Component\Core\JWK;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class KeyChecker
|
||||
{
|
||||
public static function checkKeyUsage(JWK $key, string $usage): void
|
||||
{
|
||||
if ($key->has('use')) {
|
||||
self::checkUsage($key, $usage);
|
||||
}
|
||||
if ($key->has('key_ops')) {
|
||||
self::checkOperation($key, $usage);
|
||||
}
|
||||
}
|
||||
|
||||
public static function checkKeyAlgorithm(JWK $key, string $algorithm): void
|
||||
{
|
||||
if (! $key->has('alg')) {
|
||||
return;
|
||||
}
|
||||
$alg = $key->get('alg');
|
||||
if (! is_string($alg)) {
|
||||
throw new InvalidArgumentException('Invalid algorithm.');
|
||||
}
|
||||
if ($alg !== $algorithm) {
|
||||
throw new InvalidArgumentException(sprintf('Key is only allowed for algorithm "%s".', $alg));
|
||||
}
|
||||
}
|
||||
|
||||
private static function checkOperation(JWK $key, string $usage): void
|
||||
{
|
||||
$ops = $key->get('key_ops');
|
||||
if (! is_array($ops)) {
|
||||
throw new InvalidArgumentException('Invalid key parameter "key_ops". Should be a list of key operations');
|
||||
}
|
||||
|
||||
switch ($usage) {
|
||||
case 'verification':
|
||||
if (! in_array('verify', $ops, true)) {
|
||||
throw new InvalidArgumentException('Key cannot be used to verify a signature');
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'signature':
|
||||
if (! in_array('sign', $ops, true)) {
|
||||
throw new InvalidArgumentException('Key cannot be used to sign');
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'encryption':
|
||||
if (! in_array('encrypt', $ops, true) && ! in_array('wrapKey', $ops, true) && ! in_array(
|
||||
'deriveKey',
|
||||
$ops,
|
||||
true
|
||||
)) {
|
||||
throw new InvalidArgumentException('Key cannot be used to encrypt');
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'decryption':
|
||||
if (! in_array('decrypt', $ops, true) && ! in_array('unwrapKey', $ops, true) && ! in_array(
|
||||
'deriveBits',
|
||||
$ops,
|
||||
true
|
||||
)) {
|
||||
throw new InvalidArgumentException('Key cannot be used to decrypt');
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidArgumentException('Unsupported key usage.');
|
||||
}
|
||||
}
|
||||
|
||||
private static function checkUsage(JWK $key, string $usage): void
|
||||
{
|
||||
$use = $key->get('use');
|
||||
|
||||
switch ($usage) {
|
||||
case 'verification':
|
||||
case 'signature':
|
||||
if ($use !== 'sig') {
|
||||
throw new InvalidArgumentException('Key cannot be used to sign or verify a signature.');
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'encryption':
|
||||
case 'decryption':
|
||||
if ($use !== 'enc') {
|
||||
throw new InvalidArgumentException('Key cannot be used to encrypt or decrypt.');
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidArgumentException('Unsupported key usage.');
|
||||
}
|
||||
}
|
||||
}
|
||||
244
libraries/vendor/web-token/jwt-core/Util/RSAKey.php
vendored
Normal file
244
libraries/vendor/web-token/jwt-core/Util/RSAKey.php
vendored
Normal file
@ -0,0 +1,244 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Core\Util;
|
||||
|
||||
use function array_key_exists;
|
||||
use function count;
|
||||
use InvalidArgumentException;
|
||||
use function is_array;
|
||||
use Jose\Component\Core\JWK;
|
||||
use ParagonIE\ConstantTime\Base64UrlSafe;
|
||||
use RuntimeException;
|
||||
use SpomkyLabs\Pki\ASN1\Type\Constructed\Sequence;
|
||||
use SpomkyLabs\Pki\ASN1\Type\Primitive\BitString;
|
||||
use SpomkyLabs\Pki\ASN1\Type\Primitive\Integer;
|
||||
use SpomkyLabs\Pki\ASN1\Type\Primitive\OctetString;
|
||||
use SpomkyLabs\Pki\CryptoEncoding\PEM;
|
||||
use SpomkyLabs\Pki\CryptoTypes\AlgorithmIdentifier\Asymmetric\RSAEncryptionAlgorithmIdentifier;
|
||||
use SpomkyLabs\Pki\CryptoTypes\Asymmetric\RSA\RSAPrivateKey;
|
||||
use SpomkyLabs\Pki\CryptoTypes\Asymmetric\RSA\RSAPublicKey;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class RSAKey
|
||||
{
|
||||
private null|Sequence $sequence = null;
|
||||
|
||||
private readonly array $values;
|
||||
|
||||
private BigInteger $modulus;
|
||||
|
||||
private int $modulus_length;
|
||||
|
||||
private BigInteger $public_exponent;
|
||||
|
||||
private ?BigInteger $private_exponent = null;
|
||||
|
||||
/**
|
||||
* @var BigInteger[]
|
||||
*/
|
||||
private array $primes = [];
|
||||
|
||||
/**
|
||||
* @var BigInteger[]
|
||||
*/
|
||||
private array $exponents = [];
|
||||
|
||||
private ?BigInteger $coefficient = null;
|
||||
|
||||
private function __construct(JWK $data)
|
||||
{
|
||||
$this->values = $data->all();
|
||||
$this->populateBigIntegers();
|
||||
}
|
||||
|
||||
public static function createFromJWK(JWK $jwk): self
|
||||
{
|
||||
return new self($jwk);
|
||||
}
|
||||
|
||||
public function getModulus(): BigInteger
|
||||
{
|
||||
return $this->modulus;
|
||||
}
|
||||
|
||||
public function getModulusLength(): int
|
||||
{
|
||||
return $this->modulus_length;
|
||||
}
|
||||
|
||||
public function getExponent(): BigInteger
|
||||
{
|
||||
$d = $this->getPrivateExponent();
|
||||
if ($d !== null) {
|
||||
return $d;
|
||||
}
|
||||
|
||||
return $this->getPublicExponent();
|
||||
}
|
||||
|
||||
public function getPublicExponent(): BigInteger
|
||||
{
|
||||
return $this->public_exponent;
|
||||
}
|
||||
|
||||
public function getPrivateExponent(): ?BigInteger
|
||||
{
|
||||
return $this->private_exponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BigInteger[]
|
||||
*/
|
||||
public function getPrimes(): array
|
||||
{
|
||||
return $this->primes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BigInteger[]
|
||||
*/
|
||||
public function getExponents(): array
|
||||
{
|
||||
return $this->exponents;
|
||||
}
|
||||
|
||||
public function getCoefficient(): ?BigInteger
|
||||
{
|
||||
return $this->coefficient;
|
||||
}
|
||||
|
||||
public function isPublic(): bool
|
||||
{
|
||||
return ! array_key_exists('d', $this->values);
|
||||
}
|
||||
|
||||
public static function toPublic(self $private): self
|
||||
{
|
||||
$data = $private->toArray();
|
||||
$keys = ['p', 'd', 'q', 'dp', 'dq', 'qi'];
|
||||
foreach ($keys as $key) {
|
||||
if (array_key_exists($key, $data)) {
|
||||
unset($data[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
return new self(new JWK($data));
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
return $this->values;
|
||||
}
|
||||
|
||||
public function toPEM(): string
|
||||
{
|
||||
if (array_key_exists('d', $this->values)) {
|
||||
$this->sequence = Sequence::create(
|
||||
Integer::create(0),
|
||||
RSAEncryptionAlgorithmIdentifier::create()->toASN1(),
|
||||
OctetString::create(
|
||||
RSAPrivateKey::create(
|
||||
$this->fromBase64ToInteger($this->values['n']),
|
||||
$this->fromBase64ToInteger($this->values['e']),
|
||||
$this->fromBase64ToInteger($this->values['d']),
|
||||
isset($this->values['p']) ? $this->fromBase64ToInteger($this->values['p']) : '0',
|
||||
isset($this->values['q']) ? $this->fromBase64ToInteger($this->values['q']) : '0',
|
||||
isset($this->values['dp']) ? $this->fromBase64ToInteger($this->values['dp']) : '0',
|
||||
isset($this->values['dq']) ? $this->fromBase64ToInteger($this->values['dq']) : '0',
|
||||
isset($this->values['qi']) ? $this->fromBase64ToInteger($this->values['qi']) : '0',
|
||||
)->toDER()
|
||||
)
|
||||
);
|
||||
|
||||
return PEM::create(PEM::TYPE_PRIVATE_KEY, $this->sequence->toDER())
|
||||
->string();
|
||||
}
|
||||
$this->sequence = Sequence::create(
|
||||
RSAEncryptionAlgorithmIdentifier::create()->toASN1(),
|
||||
BitString::create(
|
||||
RSAPublicKey::create(
|
||||
$this->fromBase64ToInteger($this->values['n']),
|
||||
$this->fromBase64ToInteger($this->values['e'])
|
||||
)->toDER()
|
||||
)
|
||||
);
|
||||
|
||||
return PEM::create(PEM::TYPE_PUBLIC_KEY, $this->sequence->toDER())
|
||||
->string();
|
||||
}
|
||||
|
||||
/**
|
||||
* Exponentiate with or without Chinese Remainder Theorem. Operation with primes 'p' and 'q' is appox. 2x faster.
|
||||
*/
|
||||
public static function exponentiate(self $key, BigInteger $c): BigInteger
|
||||
{
|
||||
if ($c->compare(BigInteger::createFromDecimal(0)) < 0 || $c->compare($key->getModulus()) > 0) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
if ($key->isPublic() || $key->getCoefficient() === null || count($key->getPrimes()) === 0 || count(
|
||||
$key->getExponents()
|
||||
) === 0) {
|
||||
return $c->modPow($key->getExponent(), $key->getModulus());
|
||||
}
|
||||
|
||||
$p = $key->getPrimes()[0];
|
||||
$q = $key->getPrimes()[1];
|
||||
$dP = $key->getExponents()[0];
|
||||
$dQ = $key->getExponents()[1];
|
||||
$qInv = $key->getCoefficient();
|
||||
|
||||
$m1 = $c->modPow($dP, $p);
|
||||
$m2 = $c->modPow($dQ, $q);
|
||||
$h = $qInv->multiply($m1->subtract($m2)->add($p))
|
||||
->mod($p);
|
||||
|
||||
return $m2->add($h->multiply($q));
|
||||
}
|
||||
|
||||
private function populateBigIntegers(): void
|
||||
{
|
||||
$this->modulus = $this->convertBase64StringToBigInteger($this->values['n']);
|
||||
$this->modulus_length = mb_strlen($this->getModulus()->toBytes(), '8bit');
|
||||
$this->public_exponent = $this->convertBase64StringToBigInteger($this->values['e']);
|
||||
|
||||
if (! $this->isPublic()) {
|
||||
$this->private_exponent = $this->convertBase64StringToBigInteger($this->values['d']);
|
||||
|
||||
if (array_key_exists('p', $this->values) && array_key_exists('q', $this->values)) {
|
||||
$this->primes = [
|
||||
$this->convertBase64StringToBigInteger($this->values['p']),
|
||||
$this->convertBase64StringToBigInteger($this->values['q']),
|
||||
];
|
||||
if (array_key_exists('dp', $this->values) && array_key_exists('dq', $this->values) && array_key_exists(
|
||||
'qi',
|
||||
$this->values
|
||||
)) {
|
||||
$this->exponents = [
|
||||
$this->convertBase64StringToBigInteger($this->values['dp']),
|
||||
$this->convertBase64StringToBigInteger($this->values['dq']),
|
||||
];
|
||||
$this->coefficient = $this->convertBase64StringToBigInteger($this->values['qi']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function convertBase64StringToBigInteger(string $value): BigInteger
|
||||
{
|
||||
return BigInteger::createFromBinaryString(Base64UrlSafe::decode($value));
|
||||
}
|
||||
|
||||
private function fromBase64ToInteger(string $value): string
|
||||
{
|
||||
$unpacked = unpack('H*', Base64UrlSafe::decode($value));
|
||||
if (! is_array($unpacked) || count($unpacked) === 0) {
|
||||
throw new InvalidArgumentException('Unable to get the private key');
|
||||
}
|
||||
|
||||
return \Brick\Math\BigInteger::fromBase(current($unpacked), 16)->toBase(10);
|
||||
}
|
||||
}
|
||||
71
libraries/vendor/web-token/jwt-signature-algorithm-ecdsa/ECDSA.php
vendored
Normal file
71
libraries/vendor/web-token/jwt-signature-algorithm-ecdsa/ECDSA.php
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature\Algorithm;
|
||||
|
||||
use function defined;
|
||||
use function in_array;
|
||||
use InvalidArgumentException;
|
||||
use Jose\Component\Core\JWK;
|
||||
use Jose\Component\Core\Util\ECKey;
|
||||
use Jose\Component\Core\Util\ECSignature;
|
||||
use LogicException;
|
||||
use Throwable;
|
||||
|
||||
abstract class ECDSA implements SignatureAlgorithm
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
if (! defined('OPENSSL_KEYTYPE_EC')) {
|
||||
throw new LogicException('Elliptic Curve key type not supported by your environment.');
|
||||
}
|
||||
}
|
||||
|
||||
public function allowedKeyTypes(): array
|
||||
{
|
||||
return ['EC'];
|
||||
}
|
||||
|
||||
public function sign(JWK $key, string $input): string
|
||||
{
|
||||
$this->checkKey($key);
|
||||
if (! $key->has('d')) {
|
||||
throw new InvalidArgumentException('The EC key is not private');
|
||||
}
|
||||
$pem = ECKey::convertPrivateKeyToPEM($key);
|
||||
openssl_sign($input, $signature, $pem, $this->getHashAlgorithm());
|
||||
|
||||
return ECSignature::fromAsn1($signature, $this->getSignaturePartLength());
|
||||
}
|
||||
|
||||
public function verify(JWK $key, string $input, string $signature): bool
|
||||
{
|
||||
$this->checkKey($key);
|
||||
|
||||
try {
|
||||
$der = ECSignature::toAsn1($signature, $this->getSignaturePartLength());
|
||||
$pem = ECKey::convertPublicKeyToPEM($key);
|
||||
|
||||
return openssl_verify($input, $der, $pem, $this->getHashAlgorithm()) === 1;
|
||||
} catch (Throwable) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
abstract protected function getHashAlgorithm(): string;
|
||||
|
||||
abstract protected function getSignaturePartLength(): int;
|
||||
|
||||
private function checkKey(JWK $key): void
|
||||
{
|
||||
if (! in_array($key->get('kty'), $this->allowedKeyTypes(), true)) {
|
||||
throw new InvalidArgumentException('Wrong key type.');
|
||||
}
|
||||
foreach (['x', 'y', 'crv'] as $k) {
|
||||
if (! $key->has($k)) {
|
||||
throw new InvalidArgumentException(sprintf('The key parameter "%s" is missing.', $k));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
23
libraries/vendor/web-token/jwt-signature-algorithm-ecdsa/ES256.php
vendored
Normal file
23
libraries/vendor/web-token/jwt-signature-algorithm-ecdsa/ES256.php
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature\Algorithm;
|
||||
|
||||
final class ES256 extends ECDSA
|
||||
{
|
||||
public function name(): string
|
||||
{
|
||||
return 'ES256';
|
||||
}
|
||||
|
||||
protected function getHashAlgorithm(): string
|
||||
{
|
||||
return 'sha256';
|
||||
}
|
||||
|
||||
protected function getSignaturePartLength(): int
|
||||
{
|
||||
return 64;
|
||||
}
|
||||
}
|
||||
23
libraries/vendor/web-token/jwt-signature-algorithm-ecdsa/ES384.php
vendored
Normal file
23
libraries/vendor/web-token/jwt-signature-algorithm-ecdsa/ES384.php
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature\Algorithm;
|
||||
|
||||
final class ES384 extends ECDSA
|
||||
{
|
||||
public function name(): string
|
||||
{
|
||||
return 'ES384';
|
||||
}
|
||||
|
||||
protected function getHashAlgorithm(): string
|
||||
{
|
||||
return 'sha384';
|
||||
}
|
||||
|
||||
protected function getSignaturePartLength(): int
|
||||
{
|
||||
return 96;
|
||||
}
|
||||
}
|
||||
23
libraries/vendor/web-token/jwt-signature-algorithm-ecdsa/ES512.php
vendored
Normal file
23
libraries/vendor/web-token/jwt-signature-algorithm-ecdsa/ES512.php
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature\Algorithm;
|
||||
|
||||
final class ES512 extends ECDSA
|
||||
{
|
||||
public function name(): string
|
||||
{
|
||||
return 'ES512';
|
||||
}
|
||||
|
||||
protected function getHashAlgorithm(): string
|
||||
{
|
||||
return 'sha512';
|
||||
}
|
||||
|
||||
protected function getSignaturePartLength(): int
|
||||
{
|
||||
return 132;
|
||||
}
|
||||
}
|
||||
21
libraries/vendor/web-token/jwt-signature-algorithm-ecdsa/LICENSE
vendored
Normal file
21
libraries/vendor/web-token/jwt-signature-algorithm-ecdsa/LICENSE
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2019 Spomky-Labs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
101
libraries/vendor/web-token/jwt-signature-algorithm-eddsa/EdDSA.php
vendored
Normal file
101
libraries/vendor/web-token/jwt-signature-algorithm-eddsa/EdDSA.php
vendored
Normal file
@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature\Algorithm;
|
||||
|
||||
use function extension_loaded;
|
||||
use function in_array;
|
||||
use InvalidArgumentException;
|
||||
use function is_string;
|
||||
use Jose\Component\Core\JWK;
|
||||
use ParagonIE\ConstantTime\Base64UrlSafe;
|
||||
use RuntimeException;
|
||||
|
||||
final class EdDSA implements SignatureAlgorithm
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
if (! extension_loaded('sodium')) {
|
||||
throw new RuntimeException('The extension "sodium" is not available. Please install it to use this method');
|
||||
}
|
||||
}
|
||||
|
||||
public function allowedKeyTypes(): array
|
||||
{
|
||||
return ['OKP'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function sign(JWK $key, string $input): string
|
||||
{
|
||||
$this->checkKey($key);
|
||||
if (! $key->has('d')) {
|
||||
throw new InvalidArgumentException('The EC key is not private');
|
||||
}
|
||||
$d = $key->get('d');
|
||||
if (! is_string($d) || $d === '') {
|
||||
throw new InvalidArgumentException('Invalid "d" parameter.');
|
||||
}
|
||||
if (! $key->has('x')) {
|
||||
$x = sodium_crypto_sign_publickey_from_secretkey($d);
|
||||
} else {
|
||||
$x = $key->get('x');
|
||||
}
|
||||
if (! is_string($x) || $x === '') {
|
||||
throw new InvalidArgumentException('Invalid "x" parameter.');
|
||||
}
|
||||
/** @var non-empty-string $x */
|
||||
$x = Base64UrlSafe::decode($x);
|
||||
/** @var non-empty-string $d */
|
||||
$d = Base64UrlSafe::decode($d);
|
||||
$secret = $d . $x;
|
||||
|
||||
return match ($key->get('crv')) {
|
||||
'Ed25519' => sodium_crypto_sign_detached($input, $secret),
|
||||
default => throw new InvalidArgumentException('Unsupported curve'),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param non-empty-string $signature
|
||||
*/
|
||||
public function verify(JWK $key, string $input, string $signature): bool
|
||||
{
|
||||
$this->checkKey($key);
|
||||
$x = $key->get('x');
|
||||
if (! is_string($x)) {
|
||||
throw new InvalidArgumentException('Invalid "x" parameter.');
|
||||
}
|
||||
|
||||
/** @var non-empty-string $public */
|
||||
$public = Base64UrlSafe::decode($x);
|
||||
|
||||
return match ($key->get('crv')) {
|
||||
'Ed25519' => sodium_crypto_sign_verify_detached($signature, $input, $public),
|
||||
default => throw new InvalidArgumentException('Unsupported curve'),
|
||||
};
|
||||
}
|
||||
|
||||
public function name(): string
|
||||
{
|
||||
return 'EdDSA';
|
||||
}
|
||||
|
||||
private function checkKey(JWK $key): void
|
||||
{
|
||||
if (! in_array($key->get('kty'), $this->allowedKeyTypes(), true)) {
|
||||
throw new InvalidArgumentException('Wrong key type.');
|
||||
}
|
||||
foreach (['x', 'crv'] as $k) {
|
||||
if (! $key->has($k)) {
|
||||
throw new InvalidArgumentException(sprintf('The key parameter "%s" is missing.', $k));
|
||||
}
|
||||
}
|
||||
if ($key->get('crv') !== 'Ed25519') {
|
||||
throw new InvalidArgumentException('Unsupported curve.');
|
||||
}
|
||||
}
|
||||
}
|
||||
21
libraries/vendor/web-token/jwt-signature-algorithm-eddsa/LICENSE
vendored
Normal file
21
libraries/vendor/web-token/jwt-signature-algorithm-eddsa/LICENSE
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2019 Spomky-Labs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
61
libraries/vendor/web-token/jwt-signature-algorithm-experimental/Blake2b.php
vendored
Normal file
61
libraries/vendor/web-token/jwt-signature-algorithm-experimental/Blake2b.php
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature\Algorithm;
|
||||
|
||||
use function in_array;
|
||||
use InvalidArgumentException;
|
||||
use function is_string;
|
||||
use Jose\Component\Core\JWK;
|
||||
use ParagonIE\ConstantTime\Base64UrlSafe;
|
||||
|
||||
/**
|
||||
* @see \Jose\Tests\Component\Signature\Algorithm\Blake2bTest
|
||||
*/
|
||||
final class Blake2b implements MacAlgorithm
|
||||
{
|
||||
private const MINIMUM_KEY_LENGTH = 32;
|
||||
|
||||
public function allowedKeyTypes(): array
|
||||
{
|
||||
return ['oct'];
|
||||
}
|
||||
|
||||
public function name(): string
|
||||
{
|
||||
return 'BLAKE2B';
|
||||
}
|
||||
|
||||
public function verify(JWK $key, string $input, string $signature): bool
|
||||
{
|
||||
return hash_equals($this->hash($key, $input), $signature);
|
||||
}
|
||||
|
||||
public function hash(JWK $key, string $input): string
|
||||
{
|
||||
$k = $this->getKey($key);
|
||||
|
||||
return sodium_crypto_generichash($input, $k);
|
||||
}
|
||||
|
||||
private function getKey(JWK $key): string
|
||||
{
|
||||
if (! in_array($key->get('kty'), $this->allowedKeyTypes(), true)) {
|
||||
throw new InvalidArgumentException('Wrong key type.');
|
||||
}
|
||||
if (! $key->has('k')) {
|
||||
throw new InvalidArgumentException('The key parameter "k" is missing.');
|
||||
}
|
||||
$k = $key->get('k');
|
||||
if (! is_string($k)) {
|
||||
throw new InvalidArgumentException('The key parameter "k" is invalid.');
|
||||
}
|
||||
$key = Base64UrlSafe::decode($k);
|
||||
if (mb_strlen($key, '8bit') < self::MINIMUM_KEY_LENGTH) {
|
||||
throw new InvalidArgumentException('Key provided is shorter than 256 bits.');
|
||||
}
|
||||
|
||||
return $key;
|
||||
}
|
||||
}
|
||||
23
libraries/vendor/web-token/jwt-signature-algorithm-experimental/ES256K.php
vendored
Normal file
23
libraries/vendor/web-token/jwt-signature-algorithm-experimental/ES256K.php
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature\Algorithm;
|
||||
|
||||
final class ES256K extends ECDSA
|
||||
{
|
||||
public function name(): string
|
||||
{
|
||||
return 'ES256K';
|
||||
}
|
||||
|
||||
protected function getHashAlgorithm(): string
|
||||
{
|
||||
return 'sha256';
|
||||
}
|
||||
|
||||
protected function getSignaturePartLength(): int
|
||||
{
|
||||
return 64;
|
||||
}
|
||||
}
|
||||
18
libraries/vendor/web-token/jwt-signature-algorithm-experimental/HS1.php
vendored
Normal file
18
libraries/vendor/web-token/jwt-signature-algorithm-experimental/HS1.php
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature\Algorithm;
|
||||
|
||||
final class HS1 extends HMAC
|
||||
{
|
||||
public function name(): string
|
||||
{
|
||||
return 'HS1';
|
||||
}
|
||||
|
||||
protected function getHashAlgorithm(): string
|
||||
{
|
||||
return 'sha1';
|
||||
}
|
||||
}
|
||||
27
libraries/vendor/web-token/jwt-signature-algorithm-experimental/HS256_64.php
vendored
Normal file
27
libraries/vendor/web-token/jwt-signature-algorithm-experimental/HS256_64.php
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature\Algorithm;
|
||||
|
||||
use Jose\Component\Core\JWK;
|
||||
|
||||
final class HS256_64 extends HMAC
|
||||
{
|
||||
public function hash(JWK $key, string $input): string
|
||||
{
|
||||
$signature = parent::hash($key, $input);
|
||||
|
||||
return mb_substr($signature, 0, 8, '8bit');
|
||||
}
|
||||
|
||||
public function name(): string
|
||||
{
|
||||
return 'HS256/64';
|
||||
}
|
||||
|
||||
protected function getHashAlgorithm(): string
|
||||
{
|
||||
return 'sha256';
|
||||
}
|
||||
}
|
||||
21
libraries/vendor/web-token/jwt-signature-algorithm-experimental/LICENSE
vendored
Normal file
21
libraries/vendor/web-token/jwt-signature-algorithm-experimental/LICENSE
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2019 Spomky-Labs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
18
libraries/vendor/web-token/jwt-signature-algorithm-experimental/RS1.php
vendored
Normal file
18
libraries/vendor/web-token/jwt-signature-algorithm-experimental/RS1.php
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature\Algorithm;
|
||||
|
||||
final class RS1 extends RSAPKCS1
|
||||
{
|
||||
public function name(): string
|
||||
{
|
||||
return 'RS1';
|
||||
}
|
||||
|
||||
protected function getAlgorithm(): string
|
||||
{
|
||||
return 'sha1';
|
||||
}
|
||||
}
|
||||
49
libraries/vendor/web-token/jwt-signature-algorithm-hmac/HMAC.php
vendored
Normal file
49
libraries/vendor/web-token/jwt-signature-algorithm-hmac/HMAC.php
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature\Algorithm;
|
||||
|
||||
use function in_array;
|
||||
use InvalidArgumentException;
|
||||
use function is_string;
|
||||
use Jose\Component\Core\JWK;
|
||||
use ParagonIE\ConstantTime\Base64UrlSafe;
|
||||
|
||||
abstract class HMAC implements MacAlgorithm
|
||||
{
|
||||
public function allowedKeyTypes(): array
|
||||
{
|
||||
return ['oct'];
|
||||
}
|
||||
|
||||
public function verify(JWK $key, string $input, string $signature): bool
|
||||
{
|
||||
return hash_equals($this->hash($key, $input), $signature);
|
||||
}
|
||||
|
||||
public function hash(JWK $key, string $input): string
|
||||
{
|
||||
$k = $this->getKey($key);
|
||||
|
||||
return hash_hmac($this->getHashAlgorithm(), $input, $k, true);
|
||||
}
|
||||
|
||||
protected function getKey(JWK $key): string
|
||||
{
|
||||
if (! in_array($key->get('kty'), $this->allowedKeyTypes(), true)) {
|
||||
throw new InvalidArgumentException('Wrong key type.');
|
||||
}
|
||||
if (! $key->has('k')) {
|
||||
throw new InvalidArgumentException('The key parameter "k" is missing.');
|
||||
}
|
||||
$k = $key->get('k');
|
||||
if (! is_string($k)) {
|
||||
throw new InvalidArgumentException('The key parameter "k" is invalid.');
|
||||
}
|
||||
|
||||
return Base64UrlSafe::decode($k);
|
||||
}
|
||||
|
||||
abstract protected function getHashAlgorithm(): string;
|
||||
}
|
||||
31
libraries/vendor/web-token/jwt-signature-algorithm-hmac/HS256.php
vendored
Normal file
31
libraries/vendor/web-token/jwt-signature-algorithm-hmac/HS256.php
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature\Algorithm;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Jose\Component\Core\JWK;
|
||||
|
||||
final class HS256 extends HMAC
|
||||
{
|
||||
public function name(): string
|
||||
{
|
||||
return 'HS256';
|
||||
}
|
||||
|
||||
protected function getHashAlgorithm(): string
|
||||
{
|
||||
return 'sha256';
|
||||
}
|
||||
|
||||
protected function getKey(JWK $key): string
|
||||
{
|
||||
$k = parent::getKey($key);
|
||||
if (mb_strlen($k, '8bit') < 32) {
|
||||
throw new InvalidArgumentException('Invalid key length.');
|
||||
}
|
||||
|
||||
return $k;
|
||||
}
|
||||
}
|
||||
31
libraries/vendor/web-token/jwt-signature-algorithm-hmac/HS384.php
vendored
Normal file
31
libraries/vendor/web-token/jwt-signature-algorithm-hmac/HS384.php
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature\Algorithm;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Jose\Component\Core\JWK;
|
||||
|
||||
final class HS384 extends HMAC
|
||||
{
|
||||
public function name(): string
|
||||
{
|
||||
return 'HS384';
|
||||
}
|
||||
|
||||
protected function getHashAlgorithm(): string
|
||||
{
|
||||
return 'sha384';
|
||||
}
|
||||
|
||||
protected function getKey(JWK $key): string
|
||||
{
|
||||
$k = parent::getKey($key);
|
||||
if (mb_strlen($k, '8bit') < 48) {
|
||||
throw new InvalidArgumentException('Invalid key length.');
|
||||
}
|
||||
|
||||
return $k;
|
||||
}
|
||||
}
|
||||
31
libraries/vendor/web-token/jwt-signature-algorithm-hmac/HS512.php
vendored
Normal file
31
libraries/vendor/web-token/jwt-signature-algorithm-hmac/HS512.php
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature\Algorithm;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Jose\Component\Core\JWK;
|
||||
|
||||
final class HS512 extends HMAC
|
||||
{
|
||||
public function name(): string
|
||||
{
|
||||
return 'HS512';
|
||||
}
|
||||
|
||||
protected function getHashAlgorithm(): string
|
||||
{
|
||||
return 'sha512';
|
||||
}
|
||||
|
||||
protected function getKey(JWK $key): string
|
||||
{
|
||||
$k = parent::getKey($key);
|
||||
if (mb_strlen($k, '8bit') < 64) {
|
||||
throw new InvalidArgumentException('Invalid key length.');
|
||||
}
|
||||
|
||||
return $k;
|
||||
}
|
||||
}
|
||||
21
libraries/vendor/web-token/jwt-signature-algorithm-hmac/LICENSE
vendored
Normal file
21
libraries/vendor/web-token/jwt-signature-algorithm-hmac/LICENSE
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2019 Spomky-Labs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
21
libraries/vendor/web-token/jwt-signature-algorithm-none/LICENSE
vendored
Normal file
21
libraries/vendor/web-token/jwt-signature-algorithm-none/LICENSE
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2019 Spomky-Labs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
41
libraries/vendor/web-token/jwt-signature-algorithm-none/None.php
vendored
Normal file
41
libraries/vendor/web-token/jwt-signature-algorithm-none/None.php
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature\Algorithm;
|
||||
|
||||
use function in_array;
|
||||
use InvalidArgumentException;
|
||||
use Jose\Component\Core\JWK;
|
||||
|
||||
final class None implements SignatureAlgorithm
|
||||
{
|
||||
public function allowedKeyTypes(): array
|
||||
{
|
||||
return ['none'];
|
||||
}
|
||||
|
||||
public function sign(JWK $key, string $input): string
|
||||
{
|
||||
$this->checkKey($key);
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
public function verify(JWK $key, string $input, string $signature): bool
|
||||
{
|
||||
return $signature === '';
|
||||
}
|
||||
|
||||
public function name(): string
|
||||
{
|
||||
return 'none';
|
||||
}
|
||||
|
||||
private function checkKey(JWK $key): void
|
||||
{
|
||||
if (! in_array($key->get('kty'), $this->allowedKeyTypes(), true)) {
|
||||
throw new InvalidArgumentException('Wrong key type.');
|
||||
}
|
||||
}
|
||||
}
|
||||
21
libraries/vendor/web-token/jwt-signature-algorithm-rsa/LICENSE
vendored
Normal file
21
libraries/vendor/web-token/jwt-signature-algorithm-rsa/LICENSE
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2019 Spomky-Labs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
18
libraries/vendor/web-token/jwt-signature-algorithm-rsa/PS256.php
vendored
Normal file
18
libraries/vendor/web-token/jwt-signature-algorithm-rsa/PS256.php
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature\Algorithm;
|
||||
|
||||
final class PS256 extends RSAPSS
|
||||
{
|
||||
public function name(): string
|
||||
{
|
||||
return 'PS256';
|
||||
}
|
||||
|
||||
protected function getAlgorithm(): string
|
||||
{
|
||||
return 'sha256';
|
||||
}
|
||||
}
|
||||
18
libraries/vendor/web-token/jwt-signature-algorithm-rsa/PS384.php
vendored
Normal file
18
libraries/vendor/web-token/jwt-signature-algorithm-rsa/PS384.php
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature\Algorithm;
|
||||
|
||||
final class PS384 extends RSAPSS
|
||||
{
|
||||
public function name(): string
|
||||
{
|
||||
return 'PS384';
|
||||
}
|
||||
|
||||
protected function getAlgorithm(): string
|
||||
{
|
||||
return 'sha384';
|
||||
}
|
||||
}
|
||||
18
libraries/vendor/web-token/jwt-signature-algorithm-rsa/PS512.php
vendored
Normal file
18
libraries/vendor/web-token/jwt-signature-algorithm-rsa/PS512.php
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature\Algorithm;
|
||||
|
||||
final class PS512 extends RSAPSS
|
||||
{
|
||||
public function name(): string
|
||||
{
|
||||
return 'PS512';
|
||||
}
|
||||
|
||||
protected function getAlgorithm(): string
|
||||
{
|
||||
return 'sha512';
|
||||
}
|
||||
}
|
||||
18
libraries/vendor/web-token/jwt-signature-algorithm-rsa/RS256.php
vendored
Normal file
18
libraries/vendor/web-token/jwt-signature-algorithm-rsa/RS256.php
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature\Algorithm;
|
||||
|
||||
final class RS256 extends RSAPKCS1
|
||||
{
|
||||
public function name(): string
|
||||
{
|
||||
return 'RS256';
|
||||
}
|
||||
|
||||
protected function getAlgorithm(): string
|
||||
{
|
||||
return 'sha256';
|
||||
}
|
||||
}
|
||||
18
libraries/vendor/web-token/jwt-signature-algorithm-rsa/RS384.php
vendored
Normal file
18
libraries/vendor/web-token/jwt-signature-algorithm-rsa/RS384.php
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature\Algorithm;
|
||||
|
||||
final class RS384 extends RSAPKCS1
|
||||
{
|
||||
public function name(): string
|
||||
{
|
||||
return 'RS384';
|
||||
}
|
||||
|
||||
protected function getAlgorithm(): string
|
||||
{
|
||||
return 'sha384';
|
||||
}
|
||||
}
|
||||
18
libraries/vendor/web-token/jwt-signature-algorithm-rsa/RS512.php
vendored
Normal file
18
libraries/vendor/web-token/jwt-signature-algorithm-rsa/RS512.php
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature\Algorithm;
|
||||
|
||||
final class RS512 extends RSAPKCS1
|
||||
{
|
||||
public function name(): string
|
||||
{
|
||||
return 'RS512';
|
||||
}
|
||||
|
||||
protected function getAlgorithm(): string
|
||||
{
|
||||
return 'sha512';
|
||||
}
|
||||
}
|
||||
58
libraries/vendor/web-token/jwt-signature-algorithm-rsa/RSAPKCS1.php
vendored
Normal file
58
libraries/vendor/web-token/jwt-signature-algorithm-rsa/RSAPKCS1.php
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature\Algorithm;
|
||||
|
||||
use function in_array;
|
||||
use InvalidArgumentException;
|
||||
use Jose\Component\Core\JWK;
|
||||
use Jose\Component\Core\Util\RSAKey;
|
||||
use RuntimeException;
|
||||
|
||||
abstract class RSAPKCS1 implements SignatureAlgorithm
|
||||
{
|
||||
public function allowedKeyTypes(): array
|
||||
{
|
||||
return ['RSA'];
|
||||
}
|
||||
|
||||
public function verify(JWK $key, string $input, string $signature): bool
|
||||
{
|
||||
$this->checkKey($key);
|
||||
$pub = RSAKey::createFromJWK($key->toPublic());
|
||||
|
||||
return openssl_verify($input, $signature, $pub->toPEM(), $this->getAlgorithm()) === 1;
|
||||
}
|
||||
|
||||
public function sign(JWK $key, string $input): string
|
||||
{
|
||||
$this->checkKey($key);
|
||||
if (! $key->has('d')) {
|
||||
throw new InvalidArgumentException('The key is not a private key.');
|
||||
}
|
||||
|
||||
$priv = RSAKey::createFromJWK($key);
|
||||
|
||||
$result = openssl_sign($input, $signature, $priv->toPEM(), $this->getAlgorithm());
|
||||
if ($result !== true) {
|
||||
throw new RuntimeException('Unable to sign');
|
||||
}
|
||||
|
||||
return $signature;
|
||||
}
|
||||
|
||||
abstract protected function getAlgorithm(): string;
|
||||
|
||||
private function checkKey(JWK $key): void
|
||||
{
|
||||
if (! in_array($key->get('kty'), $this->allowedKeyTypes(), true)) {
|
||||
throw new InvalidArgumentException('Wrong key type.');
|
||||
}
|
||||
foreach (['n', 'e'] as $k) {
|
||||
if (! $key->has($k)) {
|
||||
throw new InvalidArgumentException(sprintf('The key parameter "%s" is missing.', $k));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
56
libraries/vendor/web-token/jwt-signature-algorithm-rsa/RSAPSS.php
vendored
Normal file
56
libraries/vendor/web-token/jwt-signature-algorithm-rsa/RSAPSS.php
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature\Algorithm;
|
||||
|
||||
use function in_array;
|
||||
use InvalidArgumentException;
|
||||
use Jose\Component\Core\JWK;
|
||||
use Jose\Component\Core\Util\RSAKey;
|
||||
use Jose\Component\Signature\Algorithm\Util\RSA as JoseRSA;
|
||||
|
||||
abstract class RSAPSS implements SignatureAlgorithm
|
||||
{
|
||||
public function allowedKeyTypes(): array
|
||||
{
|
||||
return ['RSA'];
|
||||
}
|
||||
|
||||
public function verify(JWK $key, string $input, string $signature): bool
|
||||
{
|
||||
$this->checkKey($key);
|
||||
$pub = RSAKey::createFromJWK($key->toPublic());
|
||||
|
||||
return JoseRSA::verify($pub, $input, $signature, $this->getAlgorithm(), JoseRSA::SIGNATURE_PSS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function sign(JWK $key, string $input): string
|
||||
{
|
||||
$this->checkKey($key);
|
||||
if (! $key->has('d')) {
|
||||
throw new InvalidArgumentException('The key is not a private key.');
|
||||
}
|
||||
|
||||
$priv = RSAKey::createFromJWK($key);
|
||||
|
||||
return JoseRSA::sign($priv, $input, $this->getAlgorithm(), JoseRSA::SIGNATURE_PSS);
|
||||
}
|
||||
|
||||
abstract protected function getAlgorithm(): string;
|
||||
|
||||
private function checkKey(JWK $key): void
|
||||
{
|
||||
if (! in_array($key->get('kty'), $this->allowedKeyTypes(), true)) {
|
||||
throw new InvalidArgumentException('Wrong key type.');
|
||||
}
|
||||
foreach (['n', 'e'] as $k) {
|
||||
if (! $key->has($k)) {
|
||||
throw new InvalidArgumentException(sprintf('The key parameter "%s" is missing.', $k));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
180
libraries/vendor/web-token/jwt-signature-algorithm-rsa/Util/RSA.php
vendored
Normal file
180
libraries/vendor/web-token/jwt-signature-algorithm-rsa/Util/RSA.php
vendored
Normal file
@ -0,0 +1,180 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature\Algorithm\Util;
|
||||
|
||||
use function chr;
|
||||
use InvalidArgumentException;
|
||||
use Jose\Component\Core\Util\BigInteger;
|
||||
use Jose\Component\Core\Util\Hash;
|
||||
use Jose\Component\Core\Util\RSAKey;
|
||||
use function ord;
|
||||
use RuntimeException;
|
||||
use const STR_PAD_LEFT;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class RSA
|
||||
{
|
||||
/**
|
||||
* Probabilistic Signature Scheme.
|
||||
*/
|
||||
public const SIGNATURE_PSS = 1;
|
||||
|
||||
/**
|
||||
* Use the PKCS#1.
|
||||
*/
|
||||
public const SIGNATURE_PKCS1 = 2;
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public static function sign(RSAKey $key, string $message, string $hash, int $mode): string
|
||||
{
|
||||
switch ($mode) {
|
||||
case self::SIGNATURE_PSS:
|
||||
return self::signWithPSS($key, $message, $hash);
|
||||
|
||||
case self::SIGNATURE_PKCS1:
|
||||
$result = openssl_sign($message, $signature, $key->toPEM(), $hash);
|
||||
if ($result !== true) {
|
||||
throw new RuntimeException('Unable to sign the data');
|
||||
}
|
||||
|
||||
return $signature;
|
||||
|
||||
default:
|
||||
throw new InvalidArgumentException('Unsupported mode.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a signature.
|
||||
*
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public static function signWithPSS(RSAKey $key, string $message, string $hash): string
|
||||
{
|
||||
$em = self::encodeEMSAPSS($message, 8 * $key->getModulusLength() - 1, Hash::$hash());
|
||||
$message = BigInteger::createFromBinaryString($em);
|
||||
$signature = RSAKey::exponentiate($key, $message);
|
||||
$result = self::convertIntegerToOctetString($signature, $key->getModulusLength());
|
||||
if ($result === '') {
|
||||
throw new InvalidArgumentException('Invalid signature.');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function verify(RSAKey $key, string $message, string $signature, string $hash, int $mode): bool
|
||||
{
|
||||
return match ($mode) {
|
||||
self::SIGNATURE_PSS => self::verifyWithPSS($key, $message, $signature, $hash),
|
||||
self::SIGNATURE_PKCS1 => openssl_verify($message, $signature, $key->toPEM(), $hash) === 1,
|
||||
default => throw new InvalidArgumentException('Unsupported mode.'),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies a signature.
|
||||
*/
|
||||
public static function verifyWithPSS(RSAKey $key, string $message, string $signature, string $hash): bool
|
||||
{
|
||||
if (mb_strlen($signature, '8bit') !== $key->getModulusLength()) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
$s2 = BigInteger::createFromBinaryString($signature);
|
||||
$m2 = RSAKey::exponentiate($key, $s2);
|
||||
$em = self::convertIntegerToOctetString($m2, $key->getModulusLength());
|
||||
$modBits = 8 * $key->getModulusLength();
|
||||
|
||||
return self::verifyEMSAPSS($message, $em, $modBits - 1, Hash::$hash());
|
||||
}
|
||||
|
||||
private static function convertIntegerToOctetString(BigInteger $x, int $xLen): string
|
||||
{
|
||||
$x = $x->toBytes();
|
||||
if (mb_strlen($x, '8bit') > $xLen) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
return str_pad($x, $xLen, chr(0), STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* MGF1.
|
||||
*/
|
||||
private static function getMGF1(string $mgfSeed, int $maskLen, Hash $mgfHash): string
|
||||
{
|
||||
$t = '';
|
||||
$count = ceil($maskLen / $mgfHash->getLength());
|
||||
for ($i = 0; $i < $count; ++$i) {
|
||||
$c = pack('N', $i);
|
||||
$t .= $mgfHash->hash($mgfSeed . $c);
|
||||
}
|
||||
|
||||
return mb_substr($t, 0, $maskLen, '8bit');
|
||||
}
|
||||
|
||||
/**
|
||||
* EMSA-PSS-ENCODE.
|
||||
*/
|
||||
private static function encodeEMSAPSS(string $message, int $modulusLength, Hash $hash): string
|
||||
{
|
||||
$emLen = ($modulusLength + 1) >> 3;
|
||||
$sLen = $hash->getLength();
|
||||
$mHash = $hash->hash($message);
|
||||
if ($emLen <= $hash->getLength() + $sLen + 2) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
$salt = random_bytes($sLen);
|
||||
$m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
|
||||
$h = $hash->hash($m2);
|
||||
$ps = str_repeat(chr(0), $emLen - $sLen - $hash->getLength() - 2);
|
||||
$db = $ps . chr(1) . $salt;
|
||||
$dbMask = self::getMGF1($h, $emLen - $hash->getLength() - 1, $hash);
|
||||
$maskedDB = $db ^ $dbMask;
|
||||
$maskedDB[0] = ~chr(0xFF << ($modulusLength & 7)) & $maskedDB[0];
|
||||
|
||||
return $maskedDB . $h . chr(0xBC);
|
||||
}
|
||||
|
||||
/**
|
||||
* EMSA-PSS-VERIFY.
|
||||
*/
|
||||
private static function verifyEMSAPSS(string $m, string $em, int $emBits, Hash $hash): bool
|
||||
{
|
||||
$emLen = ($emBits + 1) >> 3;
|
||||
$sLen = $hash->getLength();
|
||||
$mHash = $hash->hash($m);
|
||||
if ($emLen < $hash->getLength() + $sLen + 2) {
|
||||
throw new InvalidArgumentException();
|
||||
}
|
||||
if ($em[mb_strlen($em, '8bit') - 1] !== chr(0xBC)) {
|
||||
throw new InvalidArgumentException();
|
||||
}
|
||||
$maskedDB = mb_substr($em, 0, -$hash->getLength() - 1, '8bit');
|
||||
$h = mb_substr($em, -$hash->getLength() - 1, $hash->getLength(), '8bit');
|
||||
$temp = chr(0xFF << ($emBits & 7));
|
||||
if ((~$maskedDB[0] & $temp) !== $temp) {
|
||||
throw new InvalidArgumentException();
|
||||
}
|
||||
$dbMask = self::getMGF1($h, $emLen - $hash->getLength() - 1, $hash/*MGF*/);
|
||||
$db = $maskedDB ^ $dbMask;
|
||||
$db[0] = ~chr(0xFF << ($emBits & 7)) & $db[0];
|
||||
$temp = $emLen - $hash->getLength() - $sLen - 2;
|
||||
if (mb_substr($db, 0, $temp, '8bit') !== str_repeat(chr(0), $temp)) {
|
||||
throw new InvalidArgumentException();
|
||||
}
|
||||
if (ord($db[$temp]) !== 1) {
|
||||
throw new InvalidArgumentException();
|
||||
}
|
||||
$salt = mb_substr($db, $temp + 1, null, '8bit'); // should be $sLen long
|
||||
$m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
|
||||
$h2 = $hash->hash($m2);
|
||||
|
||||
return hash_equals($h, $h2);
|
||||
}
|
||||
}
|
||||
28
libraries/vendor/web-token/jwt-signature/Algorithm/MacAlgorithm.php
vendored
Normal file
28
libraries/vendor/web-token/jwt-signature/Algorithm/MacAlgorithm.php
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature\Algorithm;
|
||||
|
||||
use Jose\Component\Core\Algorithm;
|
||||
use Jose\Component\Core\JWK;
|
||||
|
||||
interface MacAlgorithm extends Algorithm
|
||||
{
|
||||
/**
|
||||
* Sign the input.
|
||||
*
|
||||
* @param JWK $key The private key used to hash the data
|
||||
* @param string $input The input
|
||||
*/
|
||||
public function hash(JWK $key, string $input): string;
|
||||
|
||||
/**
|
||||
* Verify the signature of data.
|
||||
*
|
||||
* @param JWK $key The private key used to hash the data
|
||||
* @param string $input The input
|
||||
* @param string $signature The signature to verify
|
||||
*/
|
||||
public function verify(JWK $key, string $input, string $signature): bool;
|
||||
}
|
||||
28
libraries/vendor/web-token/jwt-signature/Algorithm/SignatureAlgorithm.php
vendored
Normal file
28
libraries/vendor/web-token/jwt-signature/Algorithm/SignatureAlgorithm.php
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature\Algorithm;
|
||||
|
||||
use Jose\Component\Core\Algorithm;
|
||||
use Jose\Component\Core\JWK;
|
||||
|
||||
interface SignatureAlgorithm extends Algorithm
|
||||
{
|
||||
/**
|
||||
* Sign the input.
|
||||
*
|
||||
* @param JWK $key The private key used to sign the data
|
||||
* @param string $input The input
|
||||
*/
|
||||
public function sign(JWK $key, string $input): string;
|
||||
|
||||
/**
|
||||
* Verify the signature of data.
|
||||
*
|
||||
* @param JWK $key The private key used to sign the data
|
||||
* @param non-empty-string $input The input
|
||||
* @param non-empty-string $signature The signature to verify
|
||||
*/
|
||||
public function verify(JWK $key, string $input, string $signature): bool;
|
||||
}
|
||||
123
libraries/vendor/web-token/jwt-signature/JWS.php
vendored
Normal file
123
libraries/vendor/web-token/jwt-signature/JWS.php
vendored
Normal file
@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature;
|
||||
|
||||
use function count;
|
||||
use InvalidArgumentException;
|
||||
use Jose\Component\Core\JWT;
|
||||
|
||||
class JWS implements JWT
|
||||
{
|
||||
/**
|
||||
* @var Signature[]
|
||||
*/
|
||||
private array $signatures = [];
|
||||
|
||||
public function __construct(
|
||||
private readonly ?string $payload,
|
||||
private readonly ?string $encodedPayload = null,
|
||||
private readonly bool $isPayloadDetached = false
|
||||
) {
|
||||
}
|
||||
|
||||
public function getPayload(): ?string
|
||||
{
|
||||
return $this->payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the payload is detached.
|
||||
*/
|
||||
public function isPayloadDetached(): bool
|
||||
{
|
||||
return $this->isPayloadDetached;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Base64Url encoded payload. If the payload is detached, this method returns null.
|
||||
*/
|
||||
public function getEncodedPayload(): ?string
|
||||
{
|
||||
if ($this->isPayloadDetached() === true) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->encodedPayload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the signatures associated with the JWS.
|
||||
*
|
||||
* @return Signature[]
|
||||
*/
|
||||
public function getSignatures(): array
|
||||
{
|
||||
return $this->signatures;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the signature at the given index.
|
||||
*/
|
||||
public function getSignature(int $id): Signature
|
||||
{
|
||||
if (isset($this->signatures[$id])) {
|
||||
return $this->signatures[$id];
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException('The signature does not exist.');
|
||||
}
|
||||
|
||||
/**
|
||||
* This method adds a signature to the JWS object. Its returns a new JWS object.
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param array{alg?: string, string?: mixed} $protectedHeader
|
||||
* @param array{alg?: string, string?: mixed} $header
|
||||
*/
|
||||
public function addSignature(
|
||||
string $signature,
|
||||
array $protectedHeader,
|
||||
?string $encodedProtectedHeader,
|
||||
array $header = []
|
||||
): self {
|
||||
$jws = clone $this;
|
||||
$jws->signatures[] = new Signature($signature, $protectedHeader, $encodedProtectedHeader, $header);
|
||||
|
||||
return $jws;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of signature associated with the JWS.
|
||||
*/
|
||||
public function countSignatures(): int
|
||||
{
|
||||
return count($this->signatures);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method splits the JWS into a list of JWSs. It is only useful when the JWS contains more than one signature
|
||||
* (JSON General Serialization).
|
||||
*
|
||||
* @return JWS[]
|
||||
*/
|
||||
public function split(): array
|
||||
{
|
||||
$result = [];
|
||||
foreach ($this->signatures as $signature) {
|
||||
$jws = new self($this->payload, $this->encodedPayload, $this->isPayloadDetached);
|
||||
$jws = $jws->addSignature(
|
||||
$signature->getSignature(),
|
||||
$signature->getProtectedHeader(),
|
||||
$signature->getEncodedProtectedHeader(),
|
||||
$signature->getHeader()
|
||||
);
|
||||
|
||||
$result[] = $jws;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
223
libraries/vendor/web-token/jwt-signature/JWSBuilder.php
vendored
Normal file
223
libraries/vendor/web-token/jwt-signature/JWSBuilder.php
vendored
Normal file
@ -0,0 +1,223 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature;
|
||||
|
||||
use function array_key_exists;
|
||||
use function count;
|
||||
use function in_array;
|
||||
use InvalidArgumentException;
|
||||
use function is_array;
|
||||
use Jose\Component\Core\Algorithm;
|
||||
use Jose\Component\Core\AlgorithmManager;
|
||||
use Jose\Component\Core\JWK;
|
||||
use Jose\Component\Core\Util\JsonConverter;
|
||||
use Jose\Component\Core\Util\KeyChecker;
|
||||
use Jose\Component\Signature\Algorithm\MacAlgorithm;
|
||||
use Jose\Component\Signature\Algorithm\SignatureAlgorithm;
|
||||
use LogicException;
|
||||
use ParagonIE\ConstantTime\Base64UrlSafe;
|
||||
use RuntimeException;
|
||||
|
||||
class JWSBuilder
|
||||
{
|
||||
protected ?string $payload = null;
|
||||
|
||||
protected bool $isPayloadDetached = false;
|
||||
|
||||
/**
|
||||
* @var array<array{
|
||||
* header: array<string, mixed>,
|
||||
* protected_header: array<string, mixed>,
|
||||
* signature_key: JWK,
|
||||
* signature_algorithm: Algorithm
|
||||
* }>
|
||||
*/
|
||||
protected array $signatures = [];
|
||||
|
||||
protected ?bool $isPayloadEncoded = null;
|
||||
|
||||
public function __construct(
|
||||
private readonly AlgorithmManager $signatureAlgorithmManager
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the algorithm manager associated to the builder.
|
||||
*/
|
||||
public function getSignatureAlgorithmManager(): AlgorithmManager
|
||||
{
|
||||
return $this->signatureAlgorithmManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the current data.
|
||||
*/
|
||||
public function create(): self
|
||||
{
|
||||
$this->payload = null;
|
||||
$this->isPayloadDetached = false;
|
||||
$this->signatures = [];
|
||||
$this->isPayloadEncoded = null;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the payload. This method will return a new JWSBuilder object.
|
||||
*/
|
||||
public function withPayload(string $payload, bool $isPayloadDetached = false): self
|
||||
{
|
||||
if (mb_detect_encoding($payload, 'UTF-8', true) === false) {
|
||||
throw new InvalidArgumentException('The payload must be encoded in UTF-8');
|
||||
}
|
||||
$clone = clone $this;
|
||||
$clone->payload = $payload;
|
||||
$clone->isPayloadDetached = $isPayloadDetached;
|
||||
|
||||
return $clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the information needed to compute the signature. This method will return a new JWSBuilder object.
|
||||
*
|
||||
* @param array{alg?: string, string?: mixed} $protectedHeader
|
||||
* @param array{alg?: string, string?: mixed} $header
|
||||
*/
|
||||
public function addSignature(JWK $signatureKey, array $protectedHeader, array $header = []): self
|
||||
{
|
||||
$this->checkB64AndCriticalHeader($protectedHeader);
|
||||
$isPayloadEncoded = $this->checkIfPayloadIsEncoded($protectedHeader);
|
||||
if ($this->isPayloadEncoded === null) {
|
||||
$this->isPayloadEncoded = $isPayloadEncoded;
|
||||
} elseif ($this->isPayloadEncoded !== $isPayloadEncoded) {
|
||||
throw new InvalidArgumentException('Foreign payload encoding detected.');
|
||||
}
|
||||
$this->checkDuplicatedHeaderParameters($protectedHeader, $header);
|
||||
KeyChecker::checkKeyUsage($signatureKey, 'signature');
|
||||
$algorithm = $this->findSignatureAlgorithm($signatureKey, $protectedHeader, $header);
|
||||
KeyChecker::checkKeyAlgorithm($signatureKey, $algorithm->name());
|
||||
$clone = clone $this;
|
||||
$clone->signatures[] = [
|
||||
'signature_algorithm' => $algorithm,
|
||||
'signature_key' => $signatureKey,
|
||||
'protected_header' => $protectedHeader,
|
||||
'header' => $header,
|
||||
];
|
||||
|
||||
return $clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes all signatures and return the expected JWS object.
|
||||
*/
|
||||
public function build(): JWS
|
||||
{
|
||||
if ($this->payload === null) {
|
||||
throw new RuntimeException('The payload is not set.');
|
||||
}
|
||||
if (count($this->signatures) === 0) {
|
||||
throw new RuntimeException('At least one signature must be set.');
|
||||
}
|
||||
|
||||
$encodedPayload = $this->isPayloadEncoded === false ? $this->payload : Base64UrlSafe::encodeUnpadded(
|
||||
$this->payload
|
||||
);
|
||||
$jws = new JWS($this->payload, $encodedPayload, $this->isPayloadDetached);
|
||||
foreach ($this->signatures as $signature) {
|
||||
/** @var MacAlgorithm|SignatureAlgorithm $algorithm */
|
||||
$algorithm = $signature['signature_algorithm'];
|
||||
/** @var JWK $signatureKey */
|
||||
$signatureKey = $signature['signature_key'];
|
||||
/** @var array<string, mixed> $protectedHeader */
|
||||
$protectedHeader = $signature['protected_header'];
|
||||
/** @var array<string, mixed> $header */
|
||||
$header = $signature['header'];
|
||||
$encodedProtectedHeader = count($protectedHeader) === 0 ? null : Base64UrlSafe::encodeUnpadded(
|
||||
JsonConverter::encode($protectedHeader)
|
||||
);
|
||||
$input = sprintf('%s.%s', $encodedProtectedHeader, $encodedPayload);
|
||||
if ($algorithm instanceof SignatureAlgorithm) {
|
||||
$s = $algorithm->sign($signatureKey, $input);
|
||||
} else {
|
||||
$s = $algorithm->hash($signatureKey, $input);
|
||||
}
|
||||
$jws = $jws->addSignature($s, $protectedHeader, $encodedProtectedHeader, $header);
|
||||
}
|
||||
|
||||
return $jws;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $protectedHeader
|
||||
*/
|
||||
private function checkIfPayloadIsEncoded(array $protectedHeader): bool
|
||||
{
|
||||
return ! array_key_exists('b64', $protectedHeader) || $protectedHeader['b64'] === true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $protectedHeader
|
||||
*/
|
||||
private function checkB64AndCriticalHeader(array $protectedHeader): void
|
||||
{
|
||||
if (! array_key_exists('b64', $protectedHeader)) {
|
||||
return;
|
||||
}
|
||||
if (! array_key_exists('crit', $protectedHeader)) {
|
||||
throw new LogicException(
|
||||
'The protected header parameter "crit" is mandatory when protected header parameter "b64" is set.'
|
||||
);
|
||||
}
|
||||
if (! is_array($protectedHeader['crit'])) {
|
||||
throw new LogicException('The protected header parameter "crit" must be an array.');
|
||||
}
|
||||
if (! in_array('b64', $protectedHeader['crit'], true)) {
|
||||
throw new LogicException(
|
||||
'The protected header parameter "crit" must contain "b64" when protected header parameter "b64" is set.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array{alg?: string, string?: mixed} $protectedHeader
|
||||
* @param array{alg?: string, string?: mixed} $header
|
||||
* @return MacAlgorithm|SignatureAlgorithm
|
||||
*/
|
||||
private function findSignatureAlgorithm(JWK $key, array $protectedHeader, array $header): Algorithm
|
||||
{
|
||||
$completeHeader = [...$header, ...$protectedHeader];
|
||||
if (! array_key_exists('alg', $completeHeader)) {
|
||||
throw new InvalidArgumentException('No "alg" parameter set in the header.');
|
||||
}
|
||||
if ($key->has('alg') && $key->get('alg') !== $completeHeader['alg']) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'The algorithm "%s" is not allowed with this key.',
|
||||
$completeHeader['alg']
|
||||
));
|
||||
}
|
||||
|
||||
$algorithm = $this->signatureAlgorithmManager->get($completeHeader['alg']);
|
||||
if (! $algorithm instanceof SignatureAlgorithm && ! $algorithm instanceof MacAlgorithm) {
|
||||
throw new InvalidArgumentException(sprintf('The algorithm "%s" is not supported.', $completeHeader['alg']));
|
||||
}
|
||||
|
||||
return $algorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $header1
|
||||
* @param array<string, mixed> $header2
|
||||
*/
|
||||
private function checkDuplicatedHeaderParameters(array $header1, array $header2): void
|
||||
{
|
||||
$inter = array_intersect_key($header1, $header2);
|
||||
if (count($inter) !== 0) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'The header contains duplicated entries: %s.',
|
||||
implode(', ', array_keys($inter))
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
27
libraries/vendor/web-token/jwt-signature/JWSBuilderFactory.php
vendored
Normal file
27
libraries/vendor/web-token/jwt-signature/JWSBuilderFactory.php
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature;
|
||||
|
||||
use Jose\Component\Core\AlgorithmManagerFactory;
|
||||
|
||||
class JWSBuilderFactory
|
||||
{
|
||||
public function __construct(
|
||||
private readonly AlgorithmManagerFactory $signatureAlgorithmManagerFactory
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates a JWSBuilder using the given algorithm aliases.
|
||||
*
|
||||
* @param string[] $algorithms
|
||||
*/
|
||||
public function create(array $algorithms): JWSBuilder
|
||||
{
|
||||
$algorithmManager = $this->signatureAlgorithmManagerFactory->create($algorithms);
|
||||
|
||||
return new JWSBuilder($algorithmManager);
|
||||
}
|
||||
}
|
||||
97
libraries/vendor/web-token/jwt-signature/JWSLoader.php
vendored
Normal file
97
libraries/vendor/web-token/jwt-signature/JWSLoader.php
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature;
|
||||
|
||||
use Exception;
|
||||
use Jose\Component\Checker\HeaderCheckerManager;
|
||||
use Jose\Component\Core\JWK;
|
||||
use Jose\Component\Core\JWKSet;
|
||||
use Jose\Component\Signature\Serializer\JWSSerializerManager;
|
||||
use Throwable;
|
||||
|
||||
class JWSLoader
|
||||
{
|
||||
public function __construct(
|
||||
private readonly JWSSerializerManager $serializerManager,
|
||||
private readonly JWSVerifier $jwsVerifier,
|
||||
private readonly ?HeaderCheckerManager $headerCheckerManager
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the JWSVerifier associated to the JWSLoader.
|
||||
*/
|
||||
public function getJwsVerifier(): JWSVerifier
|
||||
{
|
||||
return $this->jwsVerifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Header Checker Manager associated to the JWSLoader.
|
||||
*/
|
||||
public function getHeaderCheckerManager(): ?HeaderCheckerManager
|
||||
{
|
||||
return $this->headerCheckerManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the JWSSerializer associated to the JWSLoader.
|
||||
*/
|
||||
public function getSerializerManager(): JWSSerializerManager
|
||||
{
|
||||
return $this->serializerManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will try to load and verify the token using the given key. It returns a JWS and will populate the
|
||||
* $signature variable in case of success, otherwise an exception is thrown.
|
||||
*/
|
||||
public function loadAndVerifyWithKey(string $token, JWK $key, ?int &$signature, ?string $payload = null): JWS
|
||||
{
|
||||
$keyset = new JWKSet([$key]);
|
||||
|
||||
return $this->loadAndVerifyWithKeySet($token, $keyset, $signature, $payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will try to load and verify the token using the given key set. It returns a JWS and will populate the
|
||||
* $signature variable in case of success, otherwise an exception is thrown.
|
||||
*/
|
||||
public function loadAndVerifyWithKeySet(
|
||||
string $token,
|
||||
JWKSet $keyset,
|
||||
?int &$signature,
|
||||
?string $payload = null
|
||||
): JWS {
|
||||
try {
|
||||
$jws = $this->serializerManager->unserialize($token);
|
||||
$nbSignatures = $jws->countSignatures();
|
||||
for ($i = 0; $i < $nbSignatures; ++$i) {
|
||||
if ($this->processSignature($jws, $keyset, $i, $payload)) {
|
||||
$signature = $i;
|
||||
|
||||
return $jws;
|
||||
}
|
||||
}
|
||||
} catch (Throwable) {
|
||||
// Nothing to do. Exception thrown just after
|
||||
}
|
||||
|
||||
throw new Exception('Unable to load and verify the token.');
|
||||
}
|
||||
|
||||
private function processSignature(JWS $jws, JWKSet $keyset, int $signature, ?string $payload): bool
|
||||
{
|
||||
try {
|
||||
if ($this->headerCheckerManager !== null) {
|
||||
$this->headerCheckerManager->check($jws, $signature);
|
||||
}
|
||||
|
||||
return $this->jwsVerifier->verifyWithKeySet($jws, $keyset, $signature, $payload);
|
||||
} catch (Throwable) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
40
libraries/vendor/web-token/jwt-signature/JWSLoaderFactory.php
vendored
Normal file
40
libraries/vendor/web-token/jwt-signature/JWSLoaderFactory.php
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature;
|
||||
|
||||
use Jose\Component\Checker\HeaderCheckerManagerFactory;
|
||||
use Jose\Component\Signature\Serializer\JWSSerializerManagerFactory;
|
||||
|
||||
class JWSLoaderFactory
|
||||
{
|
||||
public function __construct(
|
||||
private readonly JWSSerializerManagerFactory $jwsSerializerManagerFactory,
|
||||
private readonly JWSVerifierFactory $jwsVerifierFactory,
|
||||
private readonly ?HeaderCheckerManagerFactory $headerCheckerManagerFactory
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JWSLoader using the given serializer aliases, signature algorithm aliases and (optionally) the header
|
||||
* checker aliases.
|
||||
*/
|
||||
/**
|
||||
* @param array<string> $serializers
|
||||
* @param array<string> $algorithms
|
||||
* @param array<string> $headerCheckers
|
||||
*/
|
||||
public function create(array $serializers, array $algorithms, array $headerCheckers = []): JWSLoader
|
||||
{
|
||||
$serializerManager = $this->jwsSerializerManagerFactory->create($serializers);
|
||||
$jwsVerifier = $this->jwsVerifierFactory->create($algorithms);
|
||||
if ($this->headerCheckerManagerFactory !== null) {
|
||||
$headerCheckerManager = $this->headerCheckerManagerFactory->create($headerCheckers);
|
||||
} else {
|
||||
$headerCheckerManager = null;
|
||||
}
|
||||
|
||||
return new JWSLoader($serializerManager, $jwsVerifier, $headerCheckerManager);
|
||||
}
|
||||
}
|
||||
36
libraries/vendor/web-token/jwt-signature/JWSTokenSupport.php
vendored
Normal file
36
libraries/vendor/web-token/jwt-signature/JWSTokenSupport.php
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Jose\Component\Checker\TokenTypeSupport;
|
||||
use Jose\Component\Core\JWT;
|
||||
|
||||
final class JWSTokenSupport implements TokenTypeSupport
|
||||
{
|
||||
public function supports(JWT $jwt): bool
|
||||
{
|
||||
return $jwt instanceof JWS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $protectedHeader
|
||||
* @param array<string, mixed> $unprotectedHeader
|
||||
*/
|
||||
public function retrieveTokenHeaders(JWT $jwt, int $index, array &$protectedHeader, array &$unprotectedHeader): void
|
||||
{
|
||||
if (! $jwt instanceof JWS) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($index > $jwt->countSignatures()) {
|
||||
throw new InvalidArgumentException('Unknown signature index.');
|
||||
}
|
||||
$protectedHeader = $jwt->getSignature($index)
|
||||
->getProtectedHeader();
|
||||
$unprotectedHeader = $jwt->getSignature($index)
|
||||
->getHeader();
|
||||
}
|
||||
}
|
||||
163
libraries/vendor/web-token/jwt-signature/JWSVerifier.php
vendored
Normal file
163
libraries/vendor/web-token/jwt-signature/JWSVerifier.php
vendored
Normal file
@ -0,0 +1,163 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Jose\Component\Core\Algorithm;
|
||||
use Jose\Component\Core\AlgorithmManager;
|
||||
use Jose\Component\Core\JWK;
|
||||
use Jose\Component\Core\JWKSet;
|
||||
use Jose\Component\Core\Util\KeyChecker;
|
||||
use Jose\Component\Signature\Algorithm\MacAlgorithm;
|
||||
use Jose\Component\Signature\Algorithm\SignatureAlgorithm;
|
||||
use ParagonIE\ConstantTime\Base64UrlSafe;
|
||||
use Throwable;
|
||||
|
||||
class JWSVerifier
|
||||
{
|
||||
public function __construct(
|
||||
private readonly AlgorithmManager $signatureAlgorithmManager
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the algorithm manager associated to the JWSVerifier.
|
||||
*/
|
||||
public function getSignatureAlgorithmManager(): AlgorithmManager
|
||||
{
|
||||
return $this->signatureAlgorithmManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will try to verify the JWS object using the given key and for the given signature. It returns true if
|
||||
* the signature is verified, otherwise false.
|
||||
*
|
||||
* @return bool true if the verification of the signature succeeded, else false
|
||||
*/
|
||||
public function verifyWithKey(JWS $jws, JWK $jwk, int $signature, ?string $detachedPayload = null): bool
|
||||
{
|
||||
$jwkset = new JWKSet([$jwk]);
|
||||
|
||||
return $this->verifyWithKeySet($jws, $jwkset, $signature, $detachedPayload);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will try to verify the JWS object using the given key set and for the given signature. It returns
|
||||
* true if the signature is verified, otherwise false.
|
||||
*
|
||||
* @param JWS $jws A JWS object
|
||||
* @param JWKSet $jwkset The signature will be verified using keys in the key set
|
||||
* @param JWK $jwk The key used to verify the signature in case of success
|
||||
* @param string|null $detachedPayload If not null, the value must be the detached payload encoded in Base64 URL safe. If the input contains a payload, throws an exception.
|
||||
*
|
||||
* @return bool true if the verification of the signature succeeded, else false
|
||||
*/
|
||||
public function verifyWithKeySet(
|
||||
JWS $jws,
|
||||
JWKSet $jwkset,
|
||||
int $signatureIndex,
|
||||
?string $detachedPayload = null,
|
||||
JWK &$jwk = null
|
||||
): bool {
|
||||
if ($jwkset->count() === 0) {
|
||||
throw new InvalidArgumentException('There is no key in the key set.');
|
||||
}
|
||||
if ($jws->countSignatures() === 0) {
|
||||
throw new InvalidArgumentException('The JWS does not contain any signature.');
|
||||
}
|
||||
$this->checkPayload($jws, $detachedPayload);
|
||||
$signature = $jws->getSignature($signatureIndex);
|
||||
|
||||
return $this->verifySignature($jws, $jwkset, $signature, $detachedPayload, $jwk);
|
||||
}
|
||||
|
||||
private function verifySignature(
|
||||
JWS $jws,
|
||||
JWKSet $jwkset,
|
||||
Signature $signature,
|
||||
?string $detachedPayload = null,
|
||||
JWK &$successJwk = null
|
||||
): bool {
|
||||
$input = $this->getInputToVerify($jws, $signature, $detachedPayload);
|
||||
$algorithm = $this->getAlgorithm($signature);
|
||||
foreach ($jwkset->all() as $jwk) {
|
||||
try {
|
||||
KeyChecker::checkKeyUsage($jwk, 'verification');
|
||||
KeyChecker::checkKeyAlgorithm($jwk, $algorithm->name());
|
||||
if ($algorithm->verify($jwk, $input, $signature->getSignature()) === true) {
|
||||
$successJwk = $jwk;
|
||||
|
||||
return true;
|
||||
}
|
||||
} catch (Throwable) {
|
||||
//We do nothing, we continue with other keys
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function getInputToVerify(JWS $jws, Signature $signature, ?string $detachedPayload): string
|
||||
{
|
||||
$payload = $jws->getPayload();
|
||||
$isPayloadEmpty = $payload === null || $payload === '';
|
||||
$encodedProtectedHeader = $signature->getEncodedProtectedHeader() ?? '';
|
||||
$isPayloadBase64Encoded = ! $signature->hasProtectedHeaderParameter(
|
||||
'b64'
|
||||
) || $signature->getProtectedHeaderParameter('b64') === true;
|
||||
$encodedPayload = $jws->getEncodedPayload();
|
||||
|
||||
if ($isPayloadBase64Encoded && $encodedPayload !== null) {
|
||||
return sprintf('%s.%s', $encodedProtectedHeader, $encodedPayload);
|
||||
}
|
||||
|
||||
$callable = $isPayloadBase64Encoded === true ? static fn (?string $p): string => Base64UrlSafe::encodeUnpadded(
|
||||
$p ?? ''
|
||||
)
|
||||
: static fn (?string $p): string => $p ?? '';
|
||||
|
||||
$payloadToUse = $callable($isPayloadEmpty ? $detachedPayload : $payload);
|
||||
|
||||
return sprintf('%s.%s', $encodedProtectedHeader, $payloadToUse);
|
||||
}
|
||||
|
||||
private function checkPayload(JWS $jws, ?string $detachedPayload = null): void
|
||||
{
|
||||
$isPayloadEmpty = $this->isPayloadEmpty($jws->getPayload());
|
||||
if ($detachedPayload !== null && ! $isPayloadEmpty) {
|
||||
throw new InvalidArgumentException('A detached payload is set, but the JWS already has a payload.');
|
||||
}
|
||||
if ($isPayloadEmpty && $detachedPayload === null) {
|
||||
throw new InvalidArgumentException('The JWS has a detached payload, but no payload is provided.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return MacAlgorithm|SignatureAlgorithm
|
||||
*/
|
||||
private function getAlgorithm(Signature $signature): Algorithm
|
||||
{
|
||||
$completeHeader = [...$signature->getProtectedHeader(), ...$signature->getHeader()];
|
||||
if (! isset($completeHeader['alg'])) {
|
||||
throw new InvalidArgumentException('No "alg" parameter set in the header.');
|
||||
}
|
||||
|
||||
$algorithm = $this->signatureAlgorithmManager->get($completeHeader['alg']);
|
||||
if (! $algorithm instanceof SignatureAlgorithm && ! $algorithm instanceof MacAlgorithm) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'The algorithm "%s" is not supported or is not a signature or MAC algorithm.',
|
||||
$completeHeader['alg']
|
||||
));
|
||||
}
|
||||
|
||||
return $algorithm;
|
||||
}
|
||||
|
||||
private function isPayloadEmpty(?string $payload): bool
|
||||
{
|
||||
return $payload === null || $payload === '';
|
||||
}
|
||||
}
|
||||
27
libraries/vendor/web-token/jwt-signature/JWSVerifierFactory.php
vendored
Normal file
27
libraries/vendor/web-token/jwt-signature/JWSVerifierFactory.php
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature;
|
||||
|
||||
use Jose\Component\Core\AlgorithmManagerFactory;
|
||||
|
||||
class JWSVerifierFactory
|
||||
{
|
||||
public function __construct(
|
||||
private readonly AlgorithmManagerFactory $algorithmManagerFactory
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JWSVerifier using the given signature algorithm aliases.
|
||||
*
|
||||
* @param string[] $algorithms
|
||||
*/
|
||||
public function create(array $algorithms): JWSVerifier
|
||||
{
|
||||
$algorithmManager = $this->algorithmManagerFactory->create($algorithms);
|
||||
|
||||
return new JWSVerifier($algorithmManager);
|
||||
}
|
||||
}
|
||||
21
libraries/vendor/web-token/jwt-signature/LICENSE
vendored
Normal file
21
libraries/vendor/web-token/jwt-signature/LICENSE
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2019 Spomky-Labs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
88
libraries/vendor/web-token/jwt-signature/Serializer/CompactSerializer.php
vendored
Normal file
88
libraries/vendor/web-token/jwt-signature/Serializer/CompactSerializer.php
vendored
Normal file
@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature\Serializer;
|
||||
|
||||
use function count;
|
||||
use InvalidArgumentException;
|
||||
use function is_array;
|
||||
use Jose\Component\Core\Util\JsonConverter;
|
||||
use Jose\Component\Signature\JWS;
|
||||
use LogicException;
|
||||
use ParagonIE\ConstantTime\Base64UrlSafe;
|
||||
use Throwable;
|
||||
|
||||
final class CompactSerializer extends Serializer
|
||||
{
|
||||
public const NAME = 'jws_compact';
|
||||
|
||||
public function displayName(): string
|
||||
{
|
||||
return 'JWS Compact';
|
||||
}
|
||||
|
||||
public function name(): string
|
||||
{
|
||||
return self::NAME;
|
||||
}
|
||||
|
||||
public function serialize(JWS $jws, ?int $signatureIndex = null): string
|
||||
{
|
||||
if ($signatureIndex === null) {
|
||||
$signatureIndex = 0;
|
||||
}
|
||||
$signature = $jws->getSignature($signatureIndex);
|
||||
if (count($signature->getHeader()) !== 0) {
|
||||
throw new LogicException(
|
||||
'The signature contains unprotected header parameters and cannot be converted into compact JSON.'
|
||||
);
|
||||
}
|
||||
$isEmptyPayload = $jws->getEncodedPayload() === null || $jws->getEncodedPayload() === '';
|
||||
if (! $isEmptyPayload && ! $this->isPayloadEncoded($signature->getProtectedHeader())) {
|
||||
if (preg_match('/^[\x{20}-\x{2d}|\x{2f}-\x{7e}]*$/u', $jws->getPayload() ?? '') !== 1) {
|
||||
throw new LogicException('Unable to convert the JWS with non-encoded payload.');
|
||||
}
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
'%s.%s.%s',
|
||||
$signature->getEncodedProtectedHeader(),
|
||||
$jws->getEncodedPayload(),
|
||||
Base64UrlSafe::encodeUnpadded($signature->getSignature())
|
||||
);
|
||||
}
|
||||
|
||||
public function unserialize(string $input): JWS
|
||||
{
|
||||
$parts = explode('.', $input);
|
||||
if (count($parts) !== 3) {
|
||||
throw new InvalidArgumentException('Unsupported input');
|
||||
}
|
||||
|
||||
try {
|
||||
$encodedProtectedHeader = $parts[0];
|
||||
$protectedHeader = JsonConverter::decode(Base64UrlSafe::decode($parts[0]));
|
||||
if (! is_array($protectedHeader)) {
|
||||
throw new InvalidArgumentException('Bad protected header.');
|
||||
}
|
||||
$hasPayload = $parts[1] !== '';
|
||||
if (! $hasPayload) {
|
||||
$payload = null;
|
||||
$encodedPayload = null;
|
||||
} else {
|
||||
$encodedPayload = $parts[1];
|
||||
$payload = $this->isPayloadEncoded($protectedHeader) ? Base64UrlSafe::decode(
|
||||
$encodedPayload
|
||||
) : $encodedPayload;
|
||||
}
|
||||
$signature = Base64UrlSafe::decode($parts[2]);
|
||||
|
||||
$jws = new JWS($payload, $encodedPayload, ! $hasPayload);
|
||||
|
||||
return $jws->addSignature($signature, $protectedHeader, $encodedProtectedHeader);
|
||||
} catch (Throwable $throwable) {
|
||||
throw new InvalidArgumentException('Unsupported input', $throwable->getCode(), $throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
97
libraries/vendor/web-token/jwt-signature/Serializer/JSONFlattenedSerializer.php
vendored
Normal file
97
libraries/vendor/web-token/jwt-signature/Serializer/JSONFlattenedSerializer.php
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature\Serializer;
|
||||
|
||||
use function count;
|
||||
use InvalidArgumentException;
|
||||
use function is_array;
|
||||
use Jose\Component\Core\Util\JsonConverter;
|
||||
use Jose\Component\Signature\JWS;
|
||||
use ParagonIE\ConstantTime\Base64UrlSafe;
|
||||
|
||||
final class JSONFlattenedSerializer extends Serializer
|
||||
{
|
||||
public const NAME = 'jws_json_flattened';
|
||||
|
||||
public function displayName(): string
|
||||
{
|
||||
return 'JWS JSON Flattened';
|
||||
}
|
||||
|
||||
public function name(): string
|
||||
{
|
||||
return self::NAME;
|
||||
}
|
||||
|
||||
public function serialize(JWS $jws, ?int $signatureIndex = null): string
|
||||
{
|
||||
if ($signatureIndex === null) {
|
||||
$signatureIndex = 0;
|
||||
}
|
||||
$signature = $jws->getSignature($signatureIndex);
|
||||
|
||||
$data = [];
|
||||
$encodedPayload = $jws->getEncodedPayload();
|
||||
if ($encodedPayload !== null && $encodedPayload !== '') {
|
||||
$data['payload'] = $encodedPayload;
|
||||
}
|
||||
$encodedProtectedHeader = $signature->getEncodedProtectedHeader();
|
||||
if ($encodedProtectedHeader !== null && $encodedProtectedHeader !== '') {
|
||||
$data['protected'] = $encodedProtectedHeader;
|
||||
}
|
||||
$header = $signature->getHeader();
|
||||
if (count($header) !== 0) {
|
||||
$data['header'] = $header;
|
||||
}
|
||||
$data['signature'] = Base64UrlSafe::encodeUnpadded($signature->getSignature());
|
||||
|
||||
return JsonConverter::encode($data);
|
||||
}
|
||||
|
||||
public function unserialize(string $input): JWS
|
||||
{
|
||||
$data = JsonConverter::decode($input);
|
||||
if (! is_array($data)) {
|
||||
throw new InvalidArgumentException('Unsupported input.');
|
||||
}
|
||||
if (! isset($data['signature'])) {
|
||||
throw new InvalidArgumentException('Unsupported input.');
|
||||
}
|
||||
$signature = Base64UrlSafe::decode($data['signature']);
|
||||
|
||||
if (isset($data['protected'])) {
|
||||
$encodedProtectedHeader = $data['protected'];
|
||||
$protectedHeader = JsonConverter::decode(Base64UrlSafe::decode($data['protected']));
|
||||
if (! is_array($protectedHeader)) {
|
||||
throw new InvalidArgumentException('Bad protected header.');
|
||||
}
|
||||
} else {
|
||||
$encodedProtectedHeader = null;
|
||||
$protectedHeader = [];
|
||||
}
|
||||
if (isset($data['header'])) {
|
||||
if (! is_array($data['header'])) {
|
||||
throw new InvalidArgumentException('Bad header.');
|
||||
}
|
||||
$header = $data['header'];
|
||||
} else {
|
||||
$header = [];
|
||||
}
|
||||
|
||||
if (isset($data['payload'])) {
|
||||
$encodedPayload = $data['payload'];
|
||||
$payload = $this->isPayloadEncoded($protectedHeader) ? Base64UrlSafe::decode(
|
||||
$encodedPayload
|
||||
) : $encodedPayload;
|
||||
} else {
|
||||
$payload = null;
|
||||
$encodedPayload = null;
|
||||
}
|
||||
|
||||
$jws = new JWS($payload, $encodedPayload, $encodedPayload === null);
|
||||
|
||||
return $jws->addSignature($signature, $protectedHeader, $encodedProtectedHeader, $header);
|
||||
}
|
||||
}
|
||||
160
libraries/vendor/web-token/jwt-signature/Serializer/JSONGeneralSerializer.php
vendored
Normal file
160
libraries/vendor/web-token/jwt-signature/Serializer/JSONGeneralSerializer.php
vendored
Normal file
@ -0,0 +1,160 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature\Serializer;
|
||||
|
||||
use function array_key_exists;
|
||||
use function count;
|
||||
use InvalidArgumentException;
|
||||
use function is_array;
|
||||
use function is_string;
|
||||
use Jose\Component\Core\Util\JsonConverter;
|
||||
use Jose\Component\Signature\JWS;
|
||||
use LogicException;
|
||||
use ParagonIE\ConstantTime\Base64UrlSafe;
|
||||
|
||||
final class JSONGeneralSerializer extends Serializer
|
||||
{
|
||||
public const NAME = 'jws_json_general';
|
||||
|
||||
public function displayName(): string
|
||||
{
|
||||
return 'JWS JSON General';
|
||||
}
|
||||
|
||||
public function name(): string
|
||||
{
|
||||
return self::NAME;
|
||||
}
|
||||
|
||||
public function serialize(JWS $jws, ?int $signatureIndex = null): string
|
||||
{
|
||||
if ($jws->countSignatures() === 0) {
|
||||
throw new LogicException('No signature.');
|
||||
}
|
||||
|
||||
$data = [];
|
||||
$this->checkPayloadEncoding($jws);
|
||||
|
||||
if ($jws->isPayloadDetached() === false) {
|
||||
$data['payload'] = $jws->getEncodedPayload();
|
||||
}
|
||||
|
||||
$data['signatures'] = [];
|
||||
foreach ($jws->getSignatures() as $signature) {
|
||||
$tmp = [
|
||||
'signature' => Base64UrlSafe::encodeUnpadded($signature->getSignature()),
|
||||
];
|
||||
$values = [
|
||||
'protected' => $signature->getEncodedProtectedHeader(),
|
||||
'header' => $signature->getHeader(),
|
||||
];
|
||||
|
||||
foreach ($values as $key => $value) {
|
||||
if ((is_string($value) && $value !== '') || (is_array($value) && count($value) !== 0)) {
|
||||
$tmp[$key] = $value;
|
||||
}
|
||||
}
|
||||
$data['signatures'][] = $tmp;
|
||||
}
|
||||
|
||||
return JsonConverter::encode($data);
|
||||
}
|
||||
|
||||
public function unserialize(string $input): JWS
|
||||
{
|
||||
$data = JsonConverter::decode($input);
|
||||
if (! is_array($data)) {
|
||||
throw new InvalidArgumentException('Unsupported input.');
|
||||
}
|
||||
if (! isset($data['signatures'])) {
|
||||
throw new InvalidArgumentException('Unsupported input.');
|
||||
}
|
||||
|
||||
$isPayloadEncoded = null;
|
||||
$rawPayload = $data['payload'] ?? null;
|
||||
$signatures = [];
|
||||
foreach ($data['signatures'] as $signature) {
|
||||
if (! isset($signature['signature'])) {
|
||||
throw new InvalidArgumentException('Unsupported input.');
|
||||
}
|
||||
[$encodedProtectedHeader, $protectedHeader, $header] = $this->processHeaders($signature);
|
||||
$signatures[] = [
|
||||
'signature' => Base64UrlSafe::decode($signature['signature']),
|
||||
'protected' => $protectedHeader,
|
||||
'encoded_protected' => $encodedProtectedHeader,
|
||||
'header' => $header,
|
||||
];
|
||||
$isPayloadEncoded = $this->processIsPayloadEncoded($isPayloadEncoded, $protectedHeader);
|
||||
}
|
||||
|
||||
$payload = $this->processPayload($rawPayload, $isPayloadEncoded);
|
||||
$jws = new JWS($payload, $rawPayload);
|
||||
foreach ($signatures as $signature) {
|
||||
$jws = $jws->addSignature(
|
||||
$signature['signature'],
|
||||
$signature['protected'],
|
||||
$signature['encoded_protected'],
|
||||
$signature['header']
|
||||
);
|
||||
}
|
||||
|
||||
return $jws;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $protectedHeader
|
||||
*/
|
||||
private function processIsPayloadEncoded(?bool $isPayloadEncoded, array $protectedHeader): bool
|
||||
{
|
||||
if ($isPayloadEncoded === null) {
|
||||
return $this->isPayloadEncoded($protectedHeader);
|
||||
}
|
||||
if ($this->isPayloadEncoded($protectedHeader) !== $isPayloadEncoded) {
|
||||
throw new InvalidArgumentException('Foreign payload encoding detected.');
|
||||
}
|
||||
|
||||
return $isPayloadEncoded;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array{protected?: string, header?: array<string, mixed>} $signature
|
||||
* @return array<mixed>
|
||||
*/
|
||||
private function processHeaders(array $signature): array
|
||||
{
|
||||
$encodedProtectedHeader = $signature['protected'] ?? null;
|
||||
$protectedHeader = $encodedProtectedHeader === null ? [] : JsonConverter::decode(
|
||||
Base64UrlSafe::decode($encodedProtectedHeader)
|
||||
);
|
||||
$header = array_key_exists('header', $signature) ? $signature['header'] : [];
|
||||
|
||||
return [$encodedProtectedHeader, $protectedHeader, $header];
|
||||
}
|
||||
|
||||
private function processPayload(?string $rawPayload, ?bool $isPayloadEncoded): ?string
|
||||
{
|
||||
if ($rawPayload === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $isPayloadEncoded === false ? $rawPayload : Base64UrlSafe::decode($rawPayload);
|
||||
}
|
||||
|
||||
private function checkPayloadEncoding(JWS $jws): void
|
||||
{
|
||||
if ($jws->isPayloadDetached()) {
|
||||
return;
|
||||
}
|
||||
$is_encoded = null;
|
||||
foreach ($jws->getSignatures() as $signature) {
|
||||
if ($is_encoded === null) {
|
||||
$is_encoded = $this->isPayloadEncoded($signature->getProtectedHeader());
|
||||
}
|
||||
if ($is_encoded !== $this->isPayloadEncoded($signature->getProtectedHeader())) {
|
||||
throw new LogicException('Foreign payload encoding detected.');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
29
libraries/vendor/web-token/jwt-signature/Serializer/JWSSerializer.php
vendored
Normal file
29
libraries/vendor/web-token/jwt-signature/Serializer/JWSSerializer.php
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature\Serializer;
|
||||
|
||||
use Jose\Component\Signature\JWS;
|
||||
|
||||
interface JWSSerializer
|
||||
{
|
||||
/**
|
||||
* The name of the serialization.
|
||||
*/
|
||||
public function name(): string;
|
||||
|
||||
public function displayName(): string;
|
||||
|
||||
/**
|
||||
* Converts a JWS into a string.
|
||||
*/
|
||||
public function serialize(JWS $jws, ?int $signatureIndex = null): string;
|
||||
|
||||
/**
|
||||
* Loads data and return a JWS object.
|
||||
*
|
||||
* @param string $input A string that represents a JWS
|
||||
*/
|
||||
public function unserialize(string $input): JWS;
|
||||
}
|
||||
73
libraries/vendor/web-token/jwt-signature/Serializer/JWSSerializerManager.php
vendored
Normal file
73
libraries/vendor/web-token/jwt-signature/Serializer/JWSSerializerManager.php
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature\Serializer;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Jose\Component\Signature\JWS;
|
||||
|
||||
class JWSSerializerManager
|
||||
{
|
||||
/**
|
||||
* @var JWSSerializer[]
|
||||
*/
|
||||
private array $serializers = [];
|
||||
|
||||
/**
|
||||
* @param JWSSerializer[] $serializers
|
||||
*/
|
||||
public function __construct(array $serializers)
|
||||
{
|
||||
foreach ($serializers as $serializer) {
|
||||
$this->add($serializer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function list(): array
|
||||
{
|
||||
return array_keys($this->serializers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a JWS into a string.
|
||||
*/
|
||||
public function serialize(string $name, JWS $jws, ?int $signatureIndex = null): string
|
||||
{
|
||||
if (! isset($this->serializers[$name])) {
|
||||
throw new InvalidArgumentException(sprintf('Unsupported serializer "%s".', $name));
|
||||
}
|
||||
|
||||
return $this->serializers[$name]->serialize($jws, $signatureIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads data and return a JWS object.
|
||||
*
|
||||
* @param string $input A string that represents a JWS
|
||||
* @param string|null $name the name of the serializer if the input is unserialized
|
||||
*/
|
||||
public function unserialize(string $input, ?string &$name = null): JWS
|
||||
{
|
||||
foreach ($this->serializers as $serializer) {
|
||||
try {
|
||||
$jws = $serializer->unserialize($input);
|
||||
$name = $serializer->name();
|
||||
|
||||
return $jws;
|
||||
} catch (InvalidArgumentException) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException('Unsupported input.');
|
||||
}
|
||||
|
||||
private function add(JWSSerializer $serializer): void
|
||||
{
|
||||
$this->serializers[$serializer->name()] = $serializer;
|
||||
}
|
||||
}
|
||||
52
libraries/vendor/web-token/jwt-signature/Serializer/JWSSerializerManagerFactory.php
vendored
Normal file
52
libraries/vendor/web-token/jwt-signature/Serializer/JWSSerializerManagerFactory.php
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature\Serializer;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
class JWSSerializerManagerFactory
|
||||
{
|
||||
/**
|
||||
* @var JWSSerializer[]
|
||||
*/
|
||||
private array $serializers = [];
|
||||
|
||||
/**
|
||||
* @param string[] $names
|
||||
*/
|
||||
public function create(array $names): JWSSerializerManager
|
||||
{
|
||||
$serializers = [];
|
||||
foreach ($names as $name) {
|
||||
if (! isset($this->serializers[$name])) {
|
||||
throw new InvalidArgumentException(sprintf('Unsupported serializer "%s".', $name));
|
||||
}
|
||||
$serializers[] = $this->serializers[$name];
|
||||
}
|
||||
|
||||
return new JWSSerializerManager($serializers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function names(): array
|
||||
{
|
||||
return array_keys($this->serializers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return JWSSerializer[]
|
||||
*/
|
||||
public function all(): array
|
||||
{
|
||||
return $this->serializers;
|
||||
}
|
||||
|
||||
public function add(JWSSerializer $serializer): void
|
||||
{
|
||||
$this->serializers[$serializer->name()] = $serializer;
|
||||
}
|
||||
}
|
||||
18
libraries/vendor/web-token/jwt-signature/Serializer/Serializer.php
vendored
Normal file
18
libraries/vendor/web-token/jwt-signature/Serializer/Serializer.php
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature\Serializer;
|
||||
|
||||
use function array_key_exists;
|
||||
|
||||
abstract class Serializer implements JWSSerializer
|
||||
{
|
||||
/**
|
||||
* @param array<string, mixed> $protectedHeader
|
||||
*/
|
||||
protected function isPayloadEncoded(array $protectedHeader): bool
|
||||
{
|
||||
return ! array_key_exists('b64', $protectedHeader) || $protectedHeader['b64'] === true;
|
||||
}
|
||||
}
|
||||
120
libraries/vendor/web-token/jwt-signature/Signature.php
vendored
Normal file
120
libraries/vendor/web-token/jwt-signature/Signature.php
vendored
Normal file
@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Jose\Component\Signature;
|
||||
|
||||
use function array_key_exists;
|
||||
use InvalidArgumentException;
|
||||
|
||||
class Signature
|
||||
{
|
||||
private readonly ?string $encodedProtectedHeader;
|
||||
|
||||
/**
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
private readonly array $protectedHeader;
|
||||
|
||||
/**
|
||||
* @param array{alg?: string, string?: mixed} $protectedHeader
|
||||
* @param array{alg?: string, string?: mixed} $header
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly string $signature,
|
||||
array $protectedHeader,
|
||||
?string $encodedProtectedHeader,
|
||||
private readonly array $header
|
||||
) {
|
||||
$this->protectedHeader = $encodedProtectedHeader === null ? [] : $protectedHeader;
|
||||
$this->encodedProtectedHeader = $encodedProtectedHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* The protected header associated with the signature.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function getProtectedHeader(): array
|
||||
{
|
||||
return $this->protectedHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* The unprotected header associated with the signature.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function getHeader(): array
|
||||
{
|
||||
return $this->header;
|
||||
}
|
||||
|
||||
/**
|
||||
* The protected header associated with the signature.
|
||||
*/
|
||||
public function getEncodedProtectedHeader(): ?string
|
||||
{
|
||||
return $this->encodedProtectedHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the protected header of the specified key.
|
||||
*
|
||||
* @param string $key The key
|
||||
*
|
||||
* @return mixed|null Header value
|
||||
*/
|
||||
public function getProtectedHeaderParameter(string $key)
|
||||
{
|
||||
if ($this->hasProtectedHeaderParameter($key)) {
|
||||
return $this->getProtectedHeader()[$key];
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException(sprintf('The protected header "%s" does not exist', $key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the protected header has the given parameter.
|
||||
*
|
||||
* @param string $key The key
|
||||
*/
|
||||
public function hasProtectedHeaderParameter(string $key): bool
|
||||
{
|
||||
return array_key_exists($key, $this->getProtectedHeader());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the unprotected header of the specified key.
|
||||
*
|
||||
* @param string $key The key
|
||||
*
|
||||
* @return mixed|null Header value
|
||||
*/
|
||||
public function getHeaderParameter(string $key)
|
||||
{
|
||||
if (array_key_exists($key, $this->header)) {
|
||||
return $this->header[$key];
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException(sprintf('The header "%s" does not exist', $key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the unprotected header has the given parameter.
|
||||
*
|
||||
* @param string $key The key
|
||||
*/
|
||||
public function hasHeaderParameter(string $key): bool
|
||||
{
|
||||
return array_key_exists($key, $this->header);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the signature.
|
||||
*/
|
||||
public function getSignature(): string
|
||||
{
|
||||
return $this->signature;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user