diff options
author | Anton Luka Šijanec <anton@sijanec.eu> | 2022-01-11 12:35:47 +0100 |
---|---|---|
committer | Anton Luka Šijanec <anton@sijanec.eu> | 2022-01-11 12:35:47 +0100 |
commit | 19985dbb8c0aa66dc4bf7905abc1148de909097d (patch) | |
tree | 2cd5a5d20d7e80fc2a51adf60d838d8a2c40999e /vendor/web-token/jwt-core | |
download | 1ka-19985dbb8c0aa66dc4bf7905abc1148de909097d.tar 1ka-19985dbb8c0aa66dc4bf7905abc1148de909097d.tar.gz 1ka-19985dbb8c0aa66dc4bf7905abc1148de909097d.tar.bz2 1ka-19985dbb8c0aa66dc4bf7905abc1148de909097d.tar.lz 1ka-19985dbb8c0aa66dc4bf7905abc1148de909097d.tar.xz 1ka-19985dbb8c0aa66dc4bf7905abc1148de909097d.tar.zst 1ka-19985dbb8c0aa66dc4bf7905abc1148de909097d.zip |
Diffstat (limited to 'vendor/web-token/jwt-core')
-rw-r--r-- | vendor/web-token/jwt-core/Algorithm.php | 29 | ||||
-rw-r--r-- | vendor/web-token/jwt-core/AlgorithmManager.php | 95 | ||||
-rw-r--r-- | vendor/web-token/jwt-core/AlgorithmManagerFactory.php | 77 | ||||
-rw-r--r-- | vendor/web-token/jwt-core/Converter/JsonConverter.php | 30 | ||||
-rw-r--r-- | vendor/web-token/jwt-core/Converter/StandardConverter.php | 50 | ||||
-rw-r--r-- | vendor/web-token/jwt-core/JWK.php | 148 | ||||
-rw-r--r-- | vendor/web-token/jwt-core/JWKSet.php | 321 | ||||
-rw-r--r-- | vendor/web-token/jwt-core/JWT.php | 23 | ||||
-rw-r--r-- | vendor/web-token/jwt-core/LICENSE | 21 | ||||
-rw-r--r-- | vendor/web-token/jwt-core/Util/BigInteger.php | 232 | ||||
-rw-r--r-- | vendor/web-token/jwt-core/Util/ECKey.php | 306 | ||||
-rw-r--r-- | vendor/web-token/jwt-core/Util/ECSignature.php | 93 | ||||
-rw-r--r-- | vendor/web-token/jwt-core/Util/Hash.php | 90 | ||||
-rw-r--r-- | vendor/web-token/jwt-core/Util/JsonConverter.php | 27 | ||||
-rw-r--r-- | vendor/web-token/jwt-core/Util/KeyChecker.php | 107 | ||||
-rw-r--r-- | vendor/web-token/jwt-core/Util/RSAKey.php | 322 | ||||
-rw-r--r-- | vendor/web-token/jwt-core/composer.json | 44 |
17 files changed, 2015 insertions, 0 deletions
diff --git a/vendor/web-token/jwt-core/Algorithm.php b/vendor/web-token/jwt-core/Algorithm.php new file mode 100644 index 0000000..7ae0f15 --- /dev/null +++ b/vendor/web-token/jwt-core/Algorithm.php @@ -0,0 +1,29 @@ +<?php + +declare(strict_types=1); + +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2018 Spomky-Labs + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + */ + +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; +} diff --git a/vendor/web-token/jwt-core/AlgorithmManager.php b/vendor/web-token/jwt-core/AlgorithmManager.php new file mode 100644 index 0000000..88beee4 --- /dev/null +++ b/vendor/web-token/jwt-core/AlgorithmManager.php @@ -0,0 +1,95 @@ +<?php + +declare(strict_types=1); + +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2018 Spomky-Labs + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + */ + +namespace Jose\Component\Core; + +class AlgorithmManager +{ + /** + * @var array + */ + private $algorithms = []; + + /** + * AlgorithmManager constructor. + * + * @param Algorithm[] $algorithms + */ + public function __construct(array $algorithms) + { + foreach ($algorithms as $algorithm) { + $this->add($algorithm); + } + } + + /** + * This method creates an alogithm manager using the given algorithms. + * + * @deprecated Will be removed in v2.0. Please use constructor instead + * + * @param Algorithm[] $algorithms + * + * @return AlgorithmManager + */ + public static function create(array $algorithms): self + { + return new self($algorithms); + } + + /** + * 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. + * + * @return AlgorithmManager + */ + private function add(Algorithm $algorithm): self + { + $name = $algorithm->name(); + $this->algorithms[$name] = $algorithm; + + return $this; + } +} diff --git a/vendor/web-token/jwt-core/AlgorithmManagerFactory.php b/vendor/web-token/jwt-core/AlgorithmManagerFactory.php new file mode 100644 index 0000000..0526374 --- /dev/null +++ b/vendor/web-token/jwt-core/AlgorithmManagerFactory.php @@ -0,0 +1,77 @@ +<?php + +declare(strict_types=1); + +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2018 Spomky-Labs + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + */ + +namespace Jose\Component\Core; + +class AlgorithmManagerFactory +{ + /** + * @var array + */ + private $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. + * + * @return AlgorithmManagerFactory + */ + public function add(string $alias, Algorithm $algorithm): self + { + $this->algorithms[$alias] = $algorithm; + + return $this; + } + + /** + * 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 (\array_key_exists($alias, $this->algorithms)) { + $algorithms[] = $this->algorithms[$alias]; + } else { + throw new \InvalidArgumentException(\sprintf('The algorithm with the alias "%s" is not supported.', $alias)); + } + } + + return AlgorithmManager::create($algorithms); + } +} diff --git a/vendor/web-token/jwt-core/Converter/JsonConverter.php b/vendor/web-token/jwt-core/Converter/JsonConverter.php new file mode 100644 index 0000000..97fe176 --- /dev/null +++ b/vendor/web-token/jwt-core/Converter/JsonConverter.php @@ -0,0 +1,30 @@ +<?php + +declare(strict_types=1); + +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2018 Spomky-Labs + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + */ + +namespace Jose\Component\Core\Converter; + +/** + * @deprecated This interface is deprecated in v1.3 and will be removed in v2.0. + */ +interface JsonConverter +{ + /** + * Convert the payload into a string. + */ + public function encode($payload): string; + + /** + * Convert a string into payload. + */ + public function decode(string $payload, bool $associativeArray = true); +} diff --git a/vendor/web-token/jwt-core/Converter/StandardConverter.php b/vendor/web-token/jwt-core/Converter/StandardConverter.php new file mode 100644 index 0000000..87a45e1 --- /dev/null +++ b/vendor/web-token/jwt-core/Converter/StandardConverter.php @@ -0,0 +1,50 @@ +<?php + +declare(strict_types=1); + +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2018 Spomky-Labs + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + */ + +namespace Jose\Component\Core\Converter; + +/** + * @deprecated This class is deprecated in v1.3 and will be removed in v2.0 + */ +final class StandardConverter implements JsonConverter +{ + /** + * @var int + */ + private $options; + + /** + * @var int + */ + private $depth; + + /** + * StandardJsonEncoder constructor. + * See also json_encode and json_decode parameters. + */ + public function __construct(int $options = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE, int $depth = 512) + { + $this->options = $options; + $this->depth = $depth; + } + + public function encode($payload): string + { + return \json_encode($payload, $this->options, $this->depth); + } + + public function decode(string $payload, bool $associativeArray = true) + { + return \json_decode($payload, $associativeArray, $this->depth, $this->options); + } +} diff --git a/vendor/web-token/jwt-core/JWK.php b/vendor/web-token/jwt-core/JWK.php new file mode 100644 index 0000000..c1ff481 --- /dev/null +++ b/vendor/web-token/jwt-core/JWK.php @@ -0,0 +1,148 @@ +<?php + +declare(strict_types=1); + +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2018 Spomky-Labs + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + */ + +namespace Jose\Component\Core; + +use Base64Url\Base64Url; + +class JWK implements \JsonSerializable +{ + /** + * @var array + */ + private $values = []; + + /** + * JWK constructor. + */ + public function __construct(array $values) + { + if (!\array_key_exists('kty', $values)) { + throw new \InvalidArgumentException('The parameter "kty" is mandatory.'); + } + + $this->values = $values; + } + + /** + * Creates a JWK object using the given values. + * The member "kty" is mandatory. Other members are NOT checked. + * + * @deprecated Will be removed in v2.0. Please use constructor instead + * + * @return JWK + */ + public static function create(array $values): self + { + return new self($values); + } + + /** + * Creates a JWK object using the given Json string. + * + * @return JWK + */ + public static function createFromJson(string $json): self + { + $data = \json_decode($json, true); + if (!\is_array($data)) { + throw new \InvalidArgumentException('Invalid argument.'); + } + + return self::create($data); + } + + /** + * Returns the values to be serialized. + */ + public function jsonSerialize() + { + return $this->values; + } + + /** + * Get the value with a specific key. + * + * @param string $key The key + * + * @throws \InvalidArgumentException + * + * @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 + * + * @throws \InvalidArgumentException + */ + 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); + + return Base64Url::encode(\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". + * + * @return JWK + */ + public function toPublic(): self + { + $values = \array_diff_key($this->values, \array_flip(['p', 'd', 'q', 'dp', 'dq', 'qi'])); + + return new self($values); + } +} diff --git a/vendor/web-token/jwt-core/JWKSet.php b/vendor/web-token/jwt-core/JWKSet.php new file mode 100644 index 0000000..efcd417 --- /dev/null +++ b/vendor/web-token/jwt-core/JWKSet.php @@ -0,0 +1,321 @@ +<?php + +declare(strict_types=1); + +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2018 Spomky-Labs + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + */ + +namespace Jose\Component\Core; + +use InvalidArgumentException; + +class JWKSet implements \Countable, \IteratorAggregate, \JsonSerializable +{ + /** + * @var array + */ + private $keys = []; + + /** + * JWKSet constructor. + * + * @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. + * + * @return JWKSet + */ + 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 JWK objects. + * + * @deprecated Will be removed in v2.0. Please use constructor instead. + * + * @param JWK[] $keys + * + * @return JWKSet + */ + public static function createFromKeys(array $keys): self + { + return new self($keys); + } + + /** + * Creates a JWKSet object using the given Json string. + * + * @return JWKSet + */ + public static function createFromJson(string $json): self + { + $data = \json_decode($json, true); + 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. + * + * @return JWKSet + */ + 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 + * + * @return JWKSet + */ + public function without($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. + * + * @param int|string $index + */ + public function has($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. + * + * @param int|string $index + */ + public function get($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 $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 (false === $can_use) { + continue; + } + $ind += $can_use; + + $alg = $this->canKeyBeUsedWithAlgorithm($algorithm, $key); + if (false === $alg) { + continue; + } + $ind += $alg; + + if (false === $this->doesKeySatisfyRestrictions($restrictions, $key)) { + continue; + } + + $result[] = ['key' => $key, 'ind' => $ind]; + } + + if (empty($result)) { + return null; + } + + \usort($result, [$this, 'sortKeys']); + + return $result[0]['key']; + } + + /** + * @return bool|int + */ + private function canKeyBeUsedFor(string $type, JWK $key) + { + if ($key->has('use')) { + return $type === $key->get('use') ? 1 : false; + } + if ($key->has('key_ops')) { + return $type === self::convertKeyOpsToKeyUse($key->get('use')) ? 1 : false; + } + + return 0; + } + + /** + * @return bool|int + */ + private function canKeyBeUsedWithAlgorithm(?Algorithm $algorithm, JWK $key) + { + if (null === $algorithm) { + 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(string $key_ops): string + { + switch ($key_ops) { + case 'verify': + case 'sign': + return 'sig'; + case 'encrypt': + case 'decrypt': + case 'wrapKey': + case 'unwrapKey': + return 'enc'; + default: + throw new InvalidArgumentException(\sprintf('Unsupported key operation value "%s"', $key_ops)); + } + } + + /** + * Internal method only. Should not be used. + * + * @internal + * @internal + */ + public static function sortKeys(array $a, array $b): int + { + if ($a['ind'] === $b['ind']) { + return 0; + } + + return ($a['ind'] > $b['ind']) ? -1 : 1; + } + + /** + * Internal method only. Should not be used. + * + * @internal + */ + public function getIterator() + { + return new \ArrayIterator($this->keys); + } +} diff --git a/vendor/web-token/jwt-core/JWT.php b/vendor/web-token/jwt-core/JWT.php new file mode 100644 index 0000000..b2cecf1 --- /dev/null +++ b/vendor/web-token/jwt-core/JWT.php @@ -0,0 +1,23 @@ +<?php + +declare(strict_types=1); + +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2018 Spomky-Labs + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + */ + +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; +} diff --git a/vendor/web-token/jwt-core/LICENSE b/vendor/web-token/jwt-core/LICENSE new file mode 100644 index 0000000..a098645 --- /dev/null +++ b/vendor/web-token/jwt-core/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014-2018 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. diff --git a/vendor/web-token/jwt-core/Util/BigInteger.php b/vendor/web-token/jwt-core/Util/BigInteger.php new file mode 100644 index 0000000..2513670 --- /dev/null +++ b/vendor/web-token/jwt-core/Util/BigInteger.php @@ -0,0 +1,232 @@ +<?php + +declare(strict_types=1); + +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2018 Spomky-Labs + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + */ + +namespace Jose\Component\Core\Util; + +/** + * @internal + */ +class BigInteger +{ + /** + * Holds the BigInteger's value. + * + * @var \GMP + */ + private $value; + + private function __construct(\GMP $value) + { + $this->value = $value; + } + + /** + * @return BigInteger + */ + public static function createFromGMPResource(\GMP $value): self + { + return new self($value); + } + + /** + * @return BigInteger + */ + public static function createFromBinaryString(string $value): self + { + $value = '0x'.\unpack('H*', $value)[1]; + $value = \gmp_init($value, 16); + + return new self($value); + } + + /** + * @return BigInteger + */ + public static function createFromDecimal(int $value): self + { + $value = \gmp_init($value, 10); + + return new self($value); + } + + /** + * Converts a BigInteger to a binary string. + */ + public function toBytes(): string + { + if (0 === \gmp_cmp($this->value, \gmp_init(0))) { + return ''; + } + + $temp = \gmp_strval(\gmp_abs($this->value), 16); + $temp = \mb_strlen($temp, '8bit') & 1 ? '0'.$temp : $temp; + $temp = \hex2bin($temp); + + return \ltrim($temp, \chr(0)); + } + + /** + * Adds two BigIntegers. + * + * @param BigInteger $y + * + * @return BigInteger + */ + public function add(self $y): self + { + $value = \gmp_add($this->value, $y->value); + + return self::createFromGMPResource($value); + } + + /** + * Subtracts two BigIntegers. + * + * @param BigInteger $y + * + * @return BigInteger + */ + public function subtract(self $y): self + { + $value = \gmp_sub($this->value, $y->value); + + return self::createFromGMPResource($value); + } + + /** + * Multiplies two BigIntegers. + * + * @param BigInteger $x + * + * @return BigInteger + */ + public function multiply(self $x): self + { + $value = \gmp_mul($this->value, $x->value); + + return self::createFromGMPResource($value); + } + + /** + * Divides two BigIntegers. + * + * @param BigInteger $x + * + * @return BigInteger + */ + public function divide(self $x): self + { + $value = \gmp_div($this->value, $x->value); + + return self::createFromGMPResource($value); + } + + /** + * Performs modular exponentiation. + * + * @param BigInteger $e + * @param BigInteger $n + * + * @return BigInteger + */ + public function modPow(self $e, self $n): self + { + $value = \gmp_powm($this->value, $e->value, $n->value); + + return self::createFromGMPResource($value); + } + + /** + * Performs modular exponentiation. + * + * @param BigInteger $d + * + * @return BigInteger + */ + public function mod(self $d): self + { + $value = \gmp_mod($this->value, $d->value); + + return self::createFromGMPResource($value); + } + + /** + * Calculates modular inverses. + * + * @param BigInteger $n + * + * @return BigInteger + */ + public function modInverse(self $n): self + { + $value = \gmp_invert($this->value, $n->value); + + return self::createFromGMPResource($value); + } + + /** + * Compares two numbers. + * + * @param BigInteger $y + */ + public function compare(self $y): int + { + return \gmp_cmp($this->value, $y->value); + } + + /** + * @param BigInteger $y + */ + public function equals(self $y): bool + { + return 0 === $this->compare($y); + } + + /** + * @param BigInteger $y + * + * @return BigInteger + */ + public static function random(self $y): self + { + $zero = self::createFromDecimal(0); + + return self::createFromGMPResource(\gmp_random_range($zero->value, $y->value)); + } + + /** + * @param BigInteger $y + * + * @return BigInteger + */ + public function gcd(self $y): self + { + return self::createFromGMPResource(\gmp_gcd($this->value, $y->value)); + } + + /** + * @param BigInteger $y + */ + public function lowerThan(self $y): bool + { + return 0 > $this->compare($y); + } + + public function isEven(): bool + { + $zero = self::createFromDecimal(0); + $two = self::createFromDecimal(2); + + return $this->mod($two)->equals($zero); + } +} diff --git a/vendor/web-token/jwt-core/Util/ECKey.php b/vendor/web-token/jwt-core/Util/ECKey.php new file mode 100644 index 0000000..da409ba --- /dev/null +++ b/vendor/web-token/jwt-core/Util/ECKey.php @@ -0,0 +1,306 @@ +<?php + +declare(strict_types=1); + +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2018 Spomky-Labs + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + */ + +namespace Jose\Component\Core\Util; + +use Base64Url\Base64Url; +use InvalidArgumentException; +use Jose\Component\Core\JWK; +use Jose\Component\Core\Util\Ecc\Curve; +use Jose\Component\Core\Util\Ecc\NistCurve; +use RuntimeException; +use Throwable; + +/** + * @internal + */ +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 + { + switch ($jwk->get('crv')) { + case 'P-256': + $der = self::p256PublicKey(); + + break; + case 'P-384': + $der = self::p384PublicKey(); + + break; + case 'P-521': + $der = self::p521PublicKey(); + + break; + 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); + $pem .= '-----END PUBLIC KEY-----'.PHP_EOL; + + return $pem; + } + + public static function convertPrivateKeyToPEM(JWK $jwk): string + { + switch ($jwk->get('crv')) { + case 'P-256': + $der = self::p256PrivateKey($jwk); + + break; + case 'P-384': + $der = self::p384PrivateKey($jwk); + + break; + case 'P-521': + $der = self::p521PrivateKey($jwk); + + break; + 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); + $pem .= '-----END EC PRIVATE KEY-----'.PHP_EOL; + + return $pem; + } + + /** + * 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 + { + try { + $jwk = self::createECKeyUsingOpenSSL($curve); + } catch (Throwable $e) { + $jwk = self::createECKeyUsingPurePhp($curve); + } + $values = array_merge($values, $jwk); + + return new JWK($values); + } + + private static function getNistCurve(string $curve): Curve + { + switch ($curve) { + case 'P-256': + return NistCurve::curve256(); + case 'P-384': + return NistCurve::curve384(); + case 'P-521': + return NistCurve::curve521(); + default: + throw new InvalidArgumentException(sprintf('The curve "%s" is not supported.', $curve)); + } + } + + private static function getNistCurveSize(string $curve): int + { + switch ($curve) { + case 'P-256': + return 256; + case 'P-384': + return 384; + case 'P-521': + return 521; + default: + throw new InvalidArgumentException(sprintf('The curve "%s" is not supported.', $curve)); + } + } + + private static function createECKeyUsingPurePhp(string $curve): array + { + $nistCurve = self::getNistCurve($curve); + $privateKey = $nistCurve->createPrivateKey(); + $publicKey = $nistCurve->createPublicKey($privateKey); + + return [ + 'kty' => 'EC', + 'crv' => $curve, + 'x' => Base64Url::encode(str_pad(gmp_export($publicKey->getPoint()->getX()), (int) ceil($nistCurve->getSize() / 8), "\0", STR_PAD_LEFT)), + 'y' => Base64Url::encode(str_pad(gmp_export($publicKey->getPoint()->getY()), (int) ceil($nistCurve->getSize() / 8), "\0", STR_PAD_LEFT)), + 'd' => Base64Url::encode(str_pad(gmp_export($privateKey->getSecret()), (int) ceil($nistCurve->getSize() / 8), "\0", STR_PAD_LEFT)), + ]; + } + + private static function createECKeyUsingOpenSSL(string $curve): array + { + $key = openssl_pkey_new([ + 'curve_name' => self::getOpensslCurveName($curve), + 'private_key_type' => OPENSSL_KEYTYPE_EC, + ]); + if (false === $key) { + throw new RuntimeException('Unable to create the key'); + } + $result = openssl_pkey_export($key, $out); + if (false === $result) { + throw new RuntimeException('Unable to create the key'); + } + $res = openssl_pkey_get_private($out); + if (false === $res) { + throw new RuntimeException('Unable to create the key'); + } + $details = openssl_pkey_get_details($res); + $nistCurveSize = self::getNistCurveSize($curve); + + return [ + 'kty' => 'EC', + 'crv' => $curve, + 'd' => Base64Url::encode(str_pad($details['ec']['d'], (int) ceil($nistCurveSize / 8), "\0", STR_PAD_LEFT)), + 'x' => Base64Url::encode(str_pad($details['ec']['x'], (int) ceil($nistCurveSize / 8), "\0", STR_PAD_LEFT)), + 'y' => Base64Url::encode(str_pad($details['ec']['y'], (int) ceil($nistCurveSize / 8), "\0", STR_PAD_LEFT)), + ]; + } + + private static function getOpensslCurveName(string $curve): string + { + switch ($curve) { + case 'P-256': + return 'prime256v1'; + case 'P-384': + return 'secp384r1'; + case 'P-521': + return '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 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 = unpack('H*', str_pad(Base64Url::decode($jwk->get('d')), 32, "\0", STR_PAD_LEFT))[1]; + + return pack( + 'H*', + '3077' // SEQUENCE, length 87+length($d)=32 + .'020101' // INTEGER, 1 + .'0420' // OCTET STRING, length($d) = 32 + .$d + .'a00a' // TAGGED OBJECT #0, length 10 + .'0608' // OID, length 8 + .'2a8648ce3d030107' // 1.3.132.0.34 = P-384 Curve + .'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 = unpack('H*', str_pad(Base64Url::decode($jwk->get('d')), 48, "\0", STR_PAD_LEFT))[1]; + + return pack( + 'H*', + '3081a4' // SEQUENCE, length 116 + length($d)=48 + .'020101' // INTEGER, 1 + .'0430' // OCTET STRING, length($d) = 30 + .$d + .'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 = unpack('H*', str_pad(Base64Url::decode($jwk->get('d')), 66, "\0", STR_PAD_LEFT))[1]; + + return pack( + 'H*', + '3081dc' // SEQUENCE, length 154 + length($d)=66 + .'020101' // INTEGER, 1 + .'0442' // OCTET STRING, length(d) = 66 + .$d + .'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 + { + $nistCurveSize = self::getNistCurveSize($jwk->get('crv')); + $length = (int) ceil($nistCurveSize / 8); + + return + "\04" + .str_pad(Base64Url::decode($jwk->get('x')), $length, "\0", STR_PAD_LEFT) + .str_pad(Base64Url::decode($jwk->get('y')), $length, "\0", STR_PAD_LEFT); + } +} diff --git a/vendor/web-token/jwt-core/Util/ECSignature.php b/vendor/web-token/jwt-core/Util/ECSignature.php new file mode 100644 index 0000000..5bfa5b0 --- /dev/null +++ b/vendor/web-token/jwt-core/Util/ECSignature.php @@ -0,0 +1,93 @@ +<?php + +declare(strict_types=1); + +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2018 Spomky-Labs + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + */ + +namespace Jose\Component\Core\Util; + +/** + * @internal + */ +class ECSignature +{ + public static function toDER(string $signature, int $partLength): string + { + $signature = \unpack('H*', $signature)[1]; + if (\mb_strlen($signature, '8bit') !== 2 * $partLength) { + throw new \InvalidArgumentException('Invalid length.'); + } + $R = \mb_substr($signature, 0, $partLength, '8bit'); + $S = \mb_substr($signature, $partLength, null, '8bit'); + + $R = self::preparePositiveInteger($R); + $Rl = \mb_strlen($R, '8bit') / 2; + $S = self::preparePositiveInteger($S); + $Sl = \mb_strlen($S, '8bit') / 2; + $der = \pack('H*', + '30'.($Rl + $Sl + 4 > 128 ? '81' : '').\dechex($Rl + $Sl + 4) + .'02'.\dechex($Rl).$R + .'02'.\dechex($Sl).$S + ); + + return $der; + } + + public static function fromDER(string $der, int $partLength): string + { + $hex = \unpack('H*', $der)[1]; + if ('30' !== \mb_substr($hex, 0, 2, '8bit')) { // SEQUENCE + throw new \RuntimeException(); + } + if ('81' === \mb_substr($hex, 2, 2, '8bit')) { // LENGTH > 128 + $hex = \mb_substr($hex, 6, null, '8bit'); + } else { + $hex = \mb_substr($hex, 4, null, '8bit'); + } + if ('02' !== \mb_substr($hex, 0, 2, '8bit')) { // INTEGER + throw new \RuntimeException(); + } + + $Rl = \hexdec(\mb_substr($hex, 2, 2, '8bit')); + $R = self::retrievePositiveInteger(\mb_substr($hex, 4, $Rl * 2, '8bit')); + $R = \str_pad($R, $partLength, '0', STR_PAD_LEFT); + + $hex = \mb_substr($hex, 4 + $Rl * 2, null, '8bit'); + if ('02' !== \mb_substr($hex, 0, 2, '8bit')) { // INTEGER + throw new \RuntimeException(); + } + $Sl = \hexdec(\mb_substr($hex, 2, 2, '8bit')); + $S = self::retrievePositiveInteger(\mb_substr($hex, 4, $Sl * 2, '8bit')); + $S = \str_pad($S, $partLength, '0', STR_PAD_LEFT); + + return \pack('H*', $R.$S); + } + + private static function preparePositiveInteger(string $data): string + { + if (\mb_substr($data, 0, 2, '8bit') > '7f') { + return '00'.$data; + } + while ('00' === \mb_substr($data, 0, 2, '8bit') && \mb_substr($data, 2, 2, '8bit') <= '7f') { + $data = \mb_substr($data, 2, null, '8bit'); + } + + return $data; + } + + private static function retrievePositiveInteger(string $data): string + { + while ('00' === \mb_substr($data, 0, 2, '8bit') && \mb_substr($data, 2, 2, '8bit') > '7f') { + $data = \mb_substr($data, 2, null, '8bit'); + } + + return $data; + } +} diff --git a/vendor/web-token/jwt-core/Util/Hash.php b/vendor/web-token/jwt-core/Util/Hash.php new file mode 100644 index 0000000..105c865 --- /dev/null +++ b/vendor/web-token/jwt-core/Util/Hash.php @@ -0,0 +1,90 @@ +<?php + +declare(strict_types=1); + +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2018 Spomky-Labs + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + */ + +namespace Jose\Component\Core\Util; + +/** + * @internal + */ +class Hash +{ + /** + * Hash Parameter. + * + * @var string + */ + private $hash; + + /** + * Hash Length. + * + * @var int + */ + private $length; + + /** + * @return Hash + */ + public static function sha1(): self + { + return new self('sha1', 20); + } + + /** + * @return Hash + */ + public static function sha256(): self + { + return new self('sha256', 32); + } + + /** + * @return Hash + */ + public static function sha384(): self + { + return new self('sha384', 48); + } + + /** + * @return Hash + */ + public static function sha512(): self + { + return new self('sha512', 64); + } + + private function __construct(string $hash, int $length) + { + $this->hash = $hash; + $this->length = $length; + } + + 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; + } +} diff --git a/vendor/web-token/jwt-core/Util/JsonConverter.php b/vendor/web-token/jwt-core/Util/JsonConverter.php new file mode 100644 index 0000000..ef95126 --- /dev/null +++ b/vendor/web-token/jwt-core/Util/JsonConverter.php @@ -0,0 +1,27 @@ +<?php + +declare(strict_types=1); + +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2018 Spomky-Labs + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + */ + +namespace Jose\Component\Core\Util; + +final class JsonConverter +{ + public static function encode($payload): string + { + return \json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); + } + + public static function decode(string $payload) + { + return \json_decode($payload, true, 512, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); + } +} diff --git a/vendor/web-token/jwt-core/Util/KeyChecker.php b/vendor/web-token/jwt-core/Util/KeyChecker.php new file mode 100644 index 0000000..09385a4 --- /dev/null +++ b/vendor/web-token/jwt-core/Util/KeyChecker.php @@ -0,0 +1,107 @@ +<?php + +declare(strict_types=1); + +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2018 Spomky-Labs + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + */ + +namespace Jose\Component\Core\Util; + +use Jose\Component\Core\JWK; + +/** + * @internal + */ +class KeyChecker +{ + /** + * @throws \InvalidArgumentException + */ + public static function checkKeyUsage(JWK $key, string $usage): bool + { + if ($key->has('use')) { + return self::checkUsage($key, $usage); + } + if ($key->has('key_ops')) { + return self::checkOperation($key, $usage); + } + + return true; + } + + private static function checkOperation(JWK $key, string $usage): bool + { + $ops = $key->get('key_ops'); + if (!\is_array($ops)) { + $ops = [$ops]; + } + switch ($usage) { + case 'verification': + if (!\in_array('verify', $ops, true)) { + throw new \InvalidArgumentException('Key cannot be used to verify a signature'); + } + + return true; + case 'signature': + if (!\in_array('sign', $ops, true)) { + throw new \InvalidArgumentException('Key cannot be used to sign'); + } + + return true; + case 'encryption': + if (!\in_array('encrypt', $ops, true) && !\in_array('wrapKey', $ops, true)) { + throw new \InvalidArgumentException('Key cannot be used to encrypt'); + } + + return true; + case 'decryption': + if (!\in_array('decrypt', $ops, true) && !\in_array('unwrapKey', $ops, true)) { + throw new \InvalidArgumentException('Key cannot be used to decrypt'); + } + + return true; + default: + throw new \InvalidArgumentException('Unsupported key usage.'); + } + } + + private static function checkUsage(JWK $key, string $usage): bool + { + $use = $key->get('use'); + switch ($usage) { + case 'verification': + case 'signature': + if ('sig' !== $use) { + throw new \InvalidArgumentException('Key cannot be used to sign or verify a signature.'); + } + + return true; + case 'encryption': + case 'decryption': + if ('enc' !== $use) { + throw new \InvalidArgumentException('Key cannot be used to encrypt or decrypt.'); + } + + return true; + default: + throw new \InvalidArgumentException('Unsupported key usage.'); + } + } + + public static function checkKeyAlgorithm(JWK $key, string $algorithm) + { + if (!$key->has('alg')) { + return; + } + + if ($key->get('alg') !== $algorithm) { + throw new \InvalidArgumentException(\sprintf('Key is only allowed for algorithm "%s".', $key->get('alg'))); + } + } +} diff --git a/vendor/web-token/jwt-core/Util/RSAKey.php b/vendor/web-token/jwt-core/Util/RSAKey.php new file mode 100644 index 0000000..3670034 --- /dev/null +++ b/vendor/web-token/jwt-core/Util/RSAKey.php @@ -0,0 +1,322 @@ +<?php + +declare(strict_types=1); + +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2018 Spomky-Labs + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + */ + +namespace Jose\Component\Core\Util; + +use Base64Url\Base64Url; +use FG\ASN1\Universal\BitString; +use FG\ASN1\Universal\Integer; +use FG\ASN1\Universal\NullObject; +use FG\ASN1\Universal\ObjectIdentifier; +use FG\ASN1\Universal\OctetString; +use FG\ASN1\Universal\Sequence; +use Jose\Component\Core\JWK; + +/** + * @internal + */ +class RSAKey +{ + /** + * @var Sequence + */ + private $sequence; + + /** + * @var bool + */ + private $private = false; + + /** + * @var array + */ + private $values = []; + + /** + * @var BigInteger + */ + private $modulus; + + /** + * @var int + */ + private $modulus_length; + + /** + * @var BigInteger + */ + private $public_exponent; + + /** + * @var BigInteger|null + */ + private $private_exponent = null; + + /** + * @var BigInteger[] + */ + private $primes = []; + + /** + * @var BigInteger[] + */ + private $exponents = []; + + /** + * @var BigInteger|null + */ + private $coefficient = null; + + private function __construct(JWK $data) + { + $this->loadJWK($data->all()); + $this->populateBigIntegers(); + $this->private = \array_key_exists('d', $this->values); + } + + /** + * @return RSAKey + */ + 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 (null !== $d) { + 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); + } + + /** + * @param RSAKey $private + * + * @return RSAKey + */ + 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; + } + + private function loadJWK(array $jwk) + { + if (!\array_key_exists('kty', $jwk)) { + throw new \InvalidArgumentException('The key parameter "kty" is missing.'); + } + if ('RSA' !== $jwk['kty']) { + throw new \InvalidArgumentException('The JWK is not a RSA key.'); + } + + $this->values = $jwk; + } + + private function populateBigIntegers() + { + $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(Base64Url::decode($value)); + } + + /** + * @throws \Exception + */ + public function toPEM(): string + { + if (null === $this->sequence) { + $this->sequence = new Sequence(); + if (\array_key_exists('d', $this->values)) { + $this->initPrivateKey(); + } else { + $this->initPublicKey(); + } + } + $result = '-----BEGIN '.($this->private ? 'RSA PRIVATE' : 'PUBLIC').' KEY-----'.PHP_EOL; + $result .= \chunk_split(\base64_encode($this->sequence->getBinary()), 64, PHP_EOL); + $result .= '-----END '.($this->private ? 'RSA PRIVATE' : 'PUBLIC').' KEY-----'.PHP_EOL; + + return $result; + } + + /** + * @throws \Exception + */ + private function initPublicKey() + { + $oid_sequence = new Sequence(); + $oid_sequence->addChild(new ObjectIdentifier('1.2.840.113549.1.1.1')); + $oid_sequence->addChild(new NullObject()); + $this->sequence->addChild($oid_sequence); + $n = new Integer($this->fromBase64ToInteger($this->values['n'])); + $e = new Integer($this->fromBase64ToInteger($this->values['e'])); + $key_sequence = new Sequence(); + $key_sequence->addChild($n); + $key_sequence->addChild($e); + $key_bit_string = new BitString(\bin2hex($key_sequence->getBinary())); + $this->sequence->addChild($key_bit_string); + } + + private function initPrivateKey() + { + $this->sequence->addChild(new Integer(0)); + $oid_sequence = new Sequence(); + $oid_sequence->addChild(new ObjectIdentifier('1.2.840.113549.1.1.1')); + $oid_sequence->addChild(new NullObject()); + $this->sequence->addChild($oid_sequence); + $v = new Integer(0); + $n = new Integer($this->fromBase64ToInteger($this->values['n'])); + $e = new Integer($this->fromBase64ToInteger($this->values['e'])); + $d = new Integer($this->fromBase64ToInteger($this->values['d'])); + $p = new Integer($this->fromBase64ToInteger($this->values['p'])); + $q = new Integer($this->fromBase64ToInteger($this->values['q'])); + $dp = \array_key_exists('dp', $this->values) ? new Integer($this->fromBase64ToInteger($this->values['dp'])) : new Integer(0); + $dq = \array_key_exists('dq', $this->values) ? new Integer($this->fromBase64ToInteger($this->values['dq'])) : new Integer(0); + $qi = \array_key_exists('qi', $this->values) ? new Integer($this->fromBase64ToInteger($this->values['qi'])) : new Integer(0); + $key_sequence = new Sequence(); + $key_sequence->addChild($v); + $key_sequence->addChild($n); + $key_sequence->addChild($e); + $key_sequence->addChild($d); + $key_sequence->addChild($p); + $key_sequence->addChild($q); + $key_sequence->addChild($dp); + $key_sequence->addChild($dq); + $key_sequence->addChild($qi); + $key_octet_string = new OctetString(\bin2hex($key_sequence->getBinary())); + $this->sequence->addChild($key_octet_string); + } + + /** + * @param string $value + * + * @return string + */ + private function fromBase64ToInteger($value) + { + return \gmp_strval(\gmp_init(\current(\unpack('H*', Base64Url::decode($value))), 16), 10); + } + + /** + * Exponentiate with or without Chinese Remainder Theorem. + * Operation with primes 'p' and 'q' is appox. 2x faster. + * + * @param RSAKey $key + */ + 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() || empty($key->getPrimes()) || empty($key->getExponents()) || null === $key->getCoefficient()) { + 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); + $m = $m2->add($h->multiply($q)); + + return $m; + } +} diff --git a/vendor/web-token/jwt-core/composer.json b/vendor/web-token/jwt-core/composer.json new file mode 100644 index 0000000..37c4ce0 --- /dev/null +++ b/vendor/web-token/jwt-core/composer.json @@ -0,0 +1,44 @@ +{ + "name": "web-token/jwt-core", + "description": "Core component of the JWT Framework.", + "type": "library", + "license": "MIT", + "keywords": ["JWS", "JWT", "JWE", "JWA", "JWK", "JWKSet", "Jot", "Jose", "RFC7515", "RFC7516", "RFC7517", "RFC7518", "RFC7519", "RFC7520", "Bundle", "Symfony"], + "homepage": "https://github.com/web-token", + "authors": [ + { + "name": "Florent Morselli", + "homepage": "https://github.com/Spomky" + },{ + "name": "All contributors", + "homepage": "https://github.com/web-token/jwt-core/contributors" + } + ], + "autoload": { + "psr-4": { + "Jose\\Component\\Core\\": "" + } + }, + "require": { + "php": "^7.1", + "ext-gmp": "*", + "ext-mbstring": "*", + "fgrosse/phpasn1": "^2.0", + "spomky-labs/base64url": "^1.0|^2.0", + "web-token/jwt-util-ecc": "^1.3" + }, + "require-dev": { + "phpunit/phpunit": "^6.0|^7.0" + }, + "conflict": { + "spomky-labs/jose": "*" + }, + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "config": { + "sort-packages": true + } +} |