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-signature | |
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-signature')
20 files changed, 1945 insertions, 0 deletions
diff --git a/vendor/web-token/jwt-signature/Algorithm/SignatureAlgorithm.php b/vendor/web-token/jwt-signature/Algorithm/SignatureAlgorithm.php new file mode 100644 index 0000000..4f982e7 --- /dev/null +++ b/vendor/web-token/jwt-signature/Algorithm/SignatureAlgorithm.php @@ -0,0 +1,41 @@ +<?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\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 + * + * @throws \Exception If key does not support the algorithm or if the key usage does not authorize the operation + */ + 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 string $input The input + * @param string $signature The signature to verify + * + * @throws \Exception If key does not support the algorithm or if the key usage does not authorize the operation + */ + public function verify(JWK $key, string $input, string $signature): bool; +} diff --git a/vendor/web-token/jwt-signature/JWS.php b/vendor/web-token/jwt-signature/JWS.php new file mode 100644 index 0000000..fe94f33 --- /dev/null +++ b/vendor/web-token/jwt-signature/JWS.php @@ -0,0 +1,159 @@ +<?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\Signature; + +use Jose\Component\Core\JWT; + +class JWS implements JWT +{ + /** + * @var bool + */ + private $isPayloadDetached = false; + + /** + * @var string|null + */ + private $encodedPayload = null; + + /** + * @var Signature[] + */ + private $signatures = []; + + /** + * @var string|null + */ + private $payload = null; + + /** + * JWS constructor. + */ + private function __construct(?string $payload, ?string $encodedPayload = null, bool $isPayloadDetached = false) + { + $this->payload = $payload; + $this->encodedPayload = $encodedPayload; + $this->isPayloadDetached = $isPayloadDetached; + } + + /** + * Creates a JWS object. + * + * @return JWS + */ + public static function create(?string $payload, ?string $encodedPayload = null, bool $isPayloadDetached = false): self + { + return new self($payload, $encodedPayload, $isPayloadDetached); + } + + 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 (true === $this->isPayloadDetached()) { + 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 + * + * @return JWS + */ + public function addSignature(string $signature, array $protectedHeader, ?string $encodedProtectedHeader, array $header = []): self + { + $jws = clone $this; + $jws->signatures[] = Signature::create($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 = self::create( + $this->payload, + $this->encodedPayload, + $this->isPayloadDetached + ); + $jws = $jws->addSignature( + $signature->getSignature(), + $signature->getProtectedHeader(), + $signature->getEncodedProtectedHeader(), + $signature->getHeader() + ); + + $result[] = $jws; + } + + return $result; + } +} diff --git a/vendor/web-token/jwt-signature/JWSBuilder.php b/vendor/web-token/jwt-signature/JWSBuilder.php new file mode 100644 index 0000000..7d8bf43 --- /dev/null +++ b/vendor/web-token/jwt-signature/JWSBuilder.php @@ -0,0 +1,213 @@ +<?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\Signature; + +use Base64Url\Base64Url; +use Jose\Component\Core\AlgorithmManager; +use Jose\Component\Core\Converter\JsonConverter; +use Jose\Component\Core\JWK; +use Jose\Component\Core\Util\KeyChecker; +use Jose\Component\Signature\Algorithm\SignatureAlgorithm; + +class JWSBuilder +{ + /** + * @var JsonConverter + */ + private $jsonConverter; + + /** + * @var string|null + */ + private $payload; + + /** + * @var bool + */ + private $isPayloadDetached; + + /** + * @var array + */ + private $signatures = []; + + /** + * @var AlgorithmManager + */ + private $signatureAlgorithmManager; + + /** + * @var bool|null + */ + private $isPayloadEncoded = null; + + /** + * JWSBuilder constructor. + */ + public function __construct(?JsonConverter $jsonConverter, AlgorithmManager $signatureAlgorithmManager) + { + $this->jsonConverter = $jsonConverter ?? new \Jose\Component\Core\Util\JsonConverter(); + $this->signatureAlgorithmManager = $signatureAlgorithmManager; + } + + /** + * Returns the algorithm manager associated to the builder. + */ + public function getSignatureAlgorithmManager(): AlgorithmManager + { + return $this->signatureAlgorithmManager; + } + + /** + * Reset the current data. + * + * @return JWSBuilder + */ + 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. + * + * @return JWSBuilder + */ + public function withPayload(string $payload, bool $isPayloadDetached = false): self + { + if (false === \mb_detect_encoding($payload, 'UTF-8', true)) { + 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. + * + * @return JWSBuilder + */ + public function addSignature(JWK $signatureKey, array $protectedHeader, array $header = []): self + { + $this->checkB64AndCriticalHeader($protectedHeader); + $isPayloadEncoded = $this->checkIfPayloadIsEncoded($protectedHeader); + if (null === $this->isPayloadEncoded) { + $this->isPayloadEncoded = $isPayloadEncoded; + } elseif ($this->isPayloadEncoded !== $isPayloadEncoded) { + throw new \InvalidArgumentException('Foreign payload encoding detected.'); + } + $this->checkDuplicatedHeaderParameters($protectedHeader, $header); + KeyChecker::checkKeyUsage($signatureKey, 'signature'); + $signatureAlgorithm = $this->findSignatureAlgorithm($signatureKey, $protectedHeader, $header); + KeyChecker::checkKeyAlgorithm($signatureKey, $signatureAlgorithm->name()); + $clone = clone $this; + $clone->signatures[] = [ + 'signature_algorithm' => $signatureAlgorithm, + 'signature_key' => $signatureKey, + 'protected_header' => $protectedHeader, + 'header' => $header, + ]; + + return $clone; + } + + /** + * Computes all signatures and return the expected JWS object. + */ + public function build(): JWS + { + if (null === $this->payload) { + throw new \RuntimeException('The payload is not set.'); + } + if (0 === \count($this->signatures)) { + throw new \RuntimeException('At least one signature must be set.'); + } + + $encodedPayload = false === $this->isPayloadEncoded ? $this->payload : Base64Url::encode($this->payload); + $jws = JWS::create($this->payload, $encodedPayload, $this->isPayloadDetached); + foreach ($this->signatures as $signature) { + /** @var SignatureAlgorithm $signatureAlgorithm */ + $signatureAlgorithm = $signature['signature_algorithm']; + /** @var JWK $signatureKey */ + $signatureKey = $signature['signature_key']; + /** @var array $protectedHeader */ + $protectedHeader = $signature['protected_header']; + /** @var array $header */ + $header = $signature['header']; + $encodedProtectedHeader = empty($protectedHeader) ? null : Base64Url::encode($this->jsonConverter->encode($protectedHeader)); + $input = \sprintf('%s.%s', $encodedProtectedHeader, $encodedPayload); + $s = $signatureAlgorithm->sign($signatureKey, $input); + $jws = $jws->addSignature($s, $protectedHeader, $encodedProtectedHeader, $header); + } + + return $jws; + } + + private function checkIfPayloadIsEncoded(array $protectedHeader): bool + { + return !\array_key_exists('b64', $protectedHeader) || true === $protectedHeader['b64']; + } + + private function checkB64AndCriticalHeader(array $protectedHeader) + { + 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.'); + } + } + + private function findSignatureAlgorithm(JWK $key, array $protectedHeader, array $header): SignatureAlgorithm + { + $completeHeader = \array_merge($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'])); + } + + $signatureAlgorithm = $this->signatureAlgorithmManager->get($completeHeader['alg']); + if (!$signatureAlgorithm instanceof SignatureAlgorithm) { + throw new \InvalidArgumentException(\sprintf('The algorithm "%s" is not supported.', $completeHeader['alg'])); + } + + return $signatureAlgorithm; + } + + private function checkDuplicatedHeaderParameters(array $header1, array $header2) + { + $inter = \array_intersect_key($header1, $header2); + if (!empty($inter)) { + throw new \InvalidArgumentException(\sprintf('The header contains duplicated entries: %s.', \implode(', ', \array_keys($inter)))); + } + } +} diff --git a/vendor/web-token/jwt-signature/JWSBuilderFactory.php b/vendor/web-token/jwt-signature/JWSBuilderFactory.php new file mode 100644 index 0000000..1c0e6c9 --- /dev/null +++ b/vendor/web-token/jwt-signature/JWSBuilderFactory.php @@ -0,0 +1,51 @@ +<?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\Signature; + +use Jose\Component\Core\AlgorithmManagerFactory; +use Jose\Component\Core\Converter\JsonConverter; + +class JWSBuilderFactory +{ + /** + * @var JsonConverter|null + */ + private $jsonConverter; + + /** + * @var AlgorithmManagerFactory + */ + private $signatureAlgorithmManagerFactory; + + /** + * JWSBuilderFactory constructor. + */ + public function __construct(?JsonConverter $jsonConverter, AlgorithmManagerFactory $signatureAlgorithmManagerFactory) + { + $this->jsonConverter = $jsonConverter; + $this->signatureAlgorithmManagerFactory = $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($this->jsonConverter, $algorithmManager); + } +} diff --git a/vendor/web-token/jwt-signature/JWSLoader.php b/vendor/web-token/jwt-signature/JWSLoader.php new file mode 100644 index 0000000..b7eb8dd --- /dev/null +++ b/vendor/web-token/jwt-signature/JWSLoader.php @@ -0,0 +1,122 @@ +<?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\Signature; + +use Jose\Component\Checker\HeaderCheckerManager; +use Jose\Component\Core\JWK; +use Jose\Component\Core\JWKSet; +use Jose\Component\Signature\Serializer\JWSSerializerManager; + +class JWSLoader +{ + /** + * @var JWSVerifier + */ + private $jwsVerifier; + + /** + * @var HeaderCheckerManager|null + */ + private $headerCheckerManager; + + /** + * @var JWSSerializerManager + */ + private $serializerManager; + + /** + * JWSLoader constructor. + */ + public function __construct(JWSSerializerManager $serializerManager, JWSVerifier $jwsVerifier, ?HeaderCheckerManager $headerCheckerManager) + { + $this->serializerManager = $serializerManager; + $this->jwsVerifier = $jwsVerifier; + $this->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. + * + * @throws \Exception + */ + 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. + * + * @throws \Exception + */ + 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 (\Exception $e) { + // 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 (null !== $this->headerCheckerManager) { + $this->headerCheckerManager->check($jws, $signature); + } + + return $this->jwsVerifier->verifyWithKeySet($jws, $keyset, $signature, $payload); + } catch (\Exception $e) { + return false; + } + } +} diff --git a/vendor/web-token/jwt-signature/JWSLoaderFactory.php b/vendor/web-token/jwt-signature/JWSLoaderFactory.php new file mode 100644 index 0000000..3517cd5 --- /dev/null +++ b/vendor/web-token/jwt-signature/JWSLoaderFactory.php @@ -0,0 +1,62 @@ +<?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\Signature; + +use Jose\Component\Checker\HeaderCheckerManagerFactory; +use Jose\Component\Signature\Serializer\JWSSerializerManagerFactory; + +class JWSLoaderFactory +{ + /** + * @var JWSVerifierFactory + */ + private $jwsVerifierFactory; + + /** + * @var JWSSerializerManagerFactory + */ + private $jwsSerializerManagerFactory; + + /** + * @var HeaderCheckerManagerFactory|null + */ + private $headerCheckerManagerFactory = null; + + /** + * JWSLoaderFactory constructor. + */ + public function __construct(JWSSerializerManagerFactory $jwsSerializerManagerFactory, JWSVerifierFactory $jwsVerifierFactory, ?HeaderCheckerManagerFactory $headerCheckerManagerFactory) + { + $this->jwsSerializerManagerFactory = $jwsSerializerManagerFactory; + $this->jwsVerifierFactory = $jwsVerifierFactory; + $this->headerCheckerManagerFactory = $headerCheckerManagerFactory; + } + + /** + * Creates a JWSLoader using the given serializer aliases, signature algorithm aliases and (optionally) + * the header checker aliases. + */ + public function create(array $serializers, array $algorithms, array $headerCheckers = []): JWSLoader + { + $serializerManager = $this->jwsSerializerManagerFactory->create($serializers); + $jwsVerifier = $this->jwsVerifierFactory->create($algorithms); + if (null !== $this->headerCheckerManagerFactory) { + $headerCheckerManager = $this->headerCheckerManagerFactory->create($headerCheckers); + } else { + $headerCheckerManager = null; + } + + return new JWSLoader($serializerManager, $jwsVerifier, $headerCheckerManager); + } +} diff --git a/vendor/web-token/jwt-signature/JWSTokenSupport.php b/vendor/web-token/jwt-signature/JWSTokenSupport.php new file mode 100644 index 0000000..667f3fc --- /dev/null +++ b/vendor/web-token/jwt-signature/JWSTokenSupport.php @@ -0,0 +1,38 @@ +<?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\Signature; + +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; + } + + 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(); + } +} diff --git a/vendor/web-token/jwt-signature/JWSVerifier.php b/vendor/web-token/jwt-signature/JWSVerifier.php new file mode 100644 index 0000000..bf49150 --- /dev/null +++ b/vendor/web-token/jwt-signature/JWSVerifier.php @@ -0,0 +1,160 @@ +<?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\Signature; + +use Base64Url\Base64Url; +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\SignatureAlgorithm; + +class JWSVerifier +{ + /** + * @var AlgorithmManager + */ + private $signatureAlgorithmManager; + + /** + * JWSVerifier constructor. + */ + public function __construct(AlgorithmManager $signatureAlgorithmManager) + { + $this->signatureAlgorithmManager = $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 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 $signature, ?string $detachedPayload = null): bool + { + $this->checkJWKSet($jwkset); + $this->checkSignatures($jws); + $this->checkPayload($jws, $detachedPayload); + + $signature = $jws->getSignature($signature); + + return $this->verifySignature($jws, $jwkset, $signature, $detachedPayload); + } + + private function verifySignature(JWS $jws, JWKSet $jwkset, Signature $signature, ?string $detachedPayload = null): bool + { + $input = $this->getInputToVerify($jws, $signature, $detachedPayload); + foreach ($jwkset->all() as $jwk) { + $algorithm = $this->getAlgorithm($signature); + + try { + KeyChecker::checkKeyUsage($jwk, 'verification'); + KeyChecker::checkKeyAlgorithm($jwk, $algorithm->name()); + if (!\in_array($jwk->get('kty'), $algorithm->allowedKeyTypes(), true)) { + throw new \InvalidArgumentException('Wrong key type.'); + } + if (true === $algorithm->verify($jwk, $input, $signature->getSignature())) { + return true; + } + } catch (\Exception $e) { + //We do nothing, we continue with other keys + continue; + } + } + + return false; + } + + private function getInputToVerify(JWS $jws, Signature $signature, ?string $detachedPayload): string + { + $encodedProtectedHeader = $signature->getEncodedProtectedHeader(); + if (!$signature->hasProtectedHeaderParameter('b64') || true === $signature->getProtectedHeaderParameter('b64')) { + if (null !== $jws->getEncodedPayload()) { + return \sprintf('%s.%s', $encodedProtectedHeader, $jws->getEncodedPayload()); + } + + $payload = empty($jws->getPayload()) ? $detachedPayload : $jws->getPayload(); + + return \sprintf('%s.%s', $encodedProtectedHeader, Base64Url::encode($payload)); + } + + $payload = empty($jws->getPayload()) ? $detachedPayload : $jws->getPayload(); + + return \sprintf('%s.%s', $encodedProtectedHeader, $payload); + } + + private function checkSignatures(JWS $jws) + { + if (0 === $jws->countSignatures()) { + throw new \InvalidArgumentException('The JWS does not contain any signature.'); + } + } + + private function checkJWKSet(JWKSet $jwkset) + { + if (0 === \count($jwkset)) { + throw new \InvalidArgumentException('There is no key in the key set.'); + } + } + + private function checkPayload(JWS $jws, ?string $detachedPayload = null) + { + if (null !== $detachedPayload && !empty($jws->getPayload())) { + throw new \InvalidArgumentException('A detached payload is set, but the JWS already has a payload.'); + } + if (empty($jws->getPayload()) && null === $detachedPayload) { + throw new \InvalidArgumentException('The JWS has a detached payload, but no payload is provided.'); + } + } + + private function getAlgorithm(Signature $signature): SignatureAlgorithm + { + $completeHeader = \array_merge($signature->getProtectedHeader(), $signature->getHeader()); + if (!\array_key_exists('alg', $completeHeader)) { + throw new \InvalidArgumentException('No "alg" parameter set in the header.'); + } + + $algorithm = $this->signatureAlgorithmManager->get($completeHeader['alg']); + if (!$algorithm instanceof SignatureAlgorithm) { + throw new \InvalidArgumentException(\sprintf('The algorithm "%s" is not supported or is not a signature algorithm.', $completeHeader['alg'])); + } + + return $algorithm; + } +} diff --git a/vendor/web-token/jwt-signature/JWSVerifierFactory.php b/vendor/web-token/jwt-signature/JWSVerifierFactory.php new file mode 100644 index 0000000..49bb868 --- /dev/null +++ b/vendor/web-token/jwt-signature/JWSVerifierFactory.php @@ -0,0 +1,44 @@ +<?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\Signature; + +use Jose\Component\Core\AlgorithmManagerFactory; + +class JWSVerifierFactory +{ + /** + * @var AlgorithmManagerFactory + */ + private $algorithmManagerFactory; + + /** + * JWSVerifierFactory constructor. + */ + public function __construct(AlgorithmManagerFactory $algorithmManagerFactory) + { + $this->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); + } +} diff --git a/vendor/web-token/jwt-signature/LICENSE b/vendor/web-token/jwt-signature/LICENSE new file mode 100644 index 0000000..a098645 --- /dev/null +++ b/vendor/web-token/jwt-signature/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-signature/Serializer/CompactSerializer.php b/vendor/web-token/jwt-signature/Serializer/CompactSerializer.php new file mode 100644 index 0000000..7e26d79 --- /dev/null +++ b/vendor/web-token/jwt-signature/Serializer/CompactSerializer.php @@ -0,0 +1,97 @@ +<?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\Signature\Serializer; + +use Base64Url\Base64Url; +use Jose\Component\Core\Converter\JsonConverter; +use Jose\Component\Signature\JWS; + +final class CompactSerializer extends Serializer +{ + public const NAME = 'jws_compact'; + + /** + * @var JsonConverter + */ + private $jsonConverter; + + /** + * JSONFlattenedSerializer constructor. + */ + public function __construct(?JsonConverter $jsonConverter = null) + { + $this->jsonConverter = $jsonConverter ?? new \Jose\Component\Core\Util\JsonConverter(); + } + + public function displayName(): string + { + return 'JWS Compact'; + } + + public function name(): string + { + return self::NAME; + } + + public function serialize(JWS $jws, ?int $signatureIndex = null): string + { + if (null === $signatureIndex) { + $signatureIndex = 0; + } + $signature = $jws->getSignature($signatureIndex); + if (!empty($signature->getHeader())) { + throw new \LogicException('The signature contains unprotected header parameters and cannot be converted into compact JSON.'); + } + if (!$this->isPayloadEncoded($signature->getProtectedHeader()) && !empty($jws->getEncodedPayload())) { + if (1 !== \preg_match('/^[\x{20}-\x{2d}|\x{2f}-\x{7e}]*$/u', $jws->getPayload())) { + throw new \LogicException('Unable to convert the JWS with non-encoded payload.'); + } + } + + return \sprintf( + '%s.%s.%s', + $signature->getEncodedProtectedHeader(), + $jws->getEncodedPayload(), + Base64Url::encode($signature->getSignature()) + ); + } + + public function unserialize(string $input): JWS + { + $parts = \explode('.', $input); + if (3 !== \count($parts)) { + throw new \InvalidArgumentException('Unsupported input'); + } + + try { + $encodedProtectedHeader = $parts[0]; + $protectedHeader = $this->jsonConverter->decode(Base64Url::decode($parts[0])); + if (empty($parts[1])) { + $payload = null; + $encodedPayload = null; + } else { + $encodedPayload = $parts[1]; + $payload = $this->isPayloadEncoded($protectedHeader) ? Base64Url::decode($encodedPayload) : $encodedPayload; + } + $signature = Base64Url::decode($parts[2]); + + $jws = JWS::create($payload, $encodedPayload, empty($parts[1])); + $jws = $jws->addSignature($signature, $protectedHeader, $encodedProtectedHeader); + + return $jws; + } catch (\Error | \Exception $e) { + throw new \InvalidArgumentException('Unsupported input'); + } + } +} diff --git a/vendor/web-token/jwt-signature/Serializer/JSONFlattenedSerializer.php b/vendor/web-token/jwt-signature/Serializer/JSONFlattenedSerializer.php new file mode 100644 index 0000000..82b79ab --- /dev/null +++ b/vendor/web-token/jwt-signature/Serializer/JSONFlattenedSerializer.php @@ -0,0 +1,109 @@ +<?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\Signature\Serializer; + +use Base64Url\Base64Url; +use Jose\Component\Core\Converter\JsonConverter; +use Jose\Component\Signature\JWS; + +final class JSONFlattenedSerializer extends Serializer +{ + public const NAME = 'jws_json_flattened'; + + /** + * @var JsonConverter|\Jose\Component\Core\Util\JsonConverter|null + */ + private $jsonConverter; + + /** + * JSONFlattenedSerializer constructor. + */ + public function __construct(?JsonConverter $jsonConverter = null) + { + $this->jsonConverter = $jsonConverter ?? new \Jose\Component\Core\Util\JsonConverter(); + } + + 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 (null === $signatureIndex) { + $signatureIndex = 0; + } + $signature = $jws->getSignature($signatureIndex); + + $data = []; + $values = [ + 'payload' => $jws->getEncodedPayload(), + 'protected' => $signature->getEncodedProtectedHeader(), + 'header' => $signature->getHeader(), + ]; + + foreach ($values as $key => $value) { + if (!empty($value)) { + $data[$key] = $value; + } + } + $data['signature'] = Base64Url::encode($signature->getSignature()); + + return $this->jsonConverter->encode($data); + } + + public function unserialize(string $input): JWS + { + $data = $this->jsonConverter->decode($input); + if (!\is_array($data) || !\array_key_exists('signature', $data)) { + throw new \InvalidArgumentException('Unsupported input.'); + } + + $signature = Base64Url::decode($data['signature']); + + if (\array_key_exists('protected', $data)) { + $encodedProtectedHeader = $data['protected']; + $protectedHeader = $this->jsonConverter->decode(Base64Url::decode($data['protected'])); + } else { + $encodedProtectedHeader = null; + $protectedHeader = []; + } + if (\array_key_exists('header', $data)) { + if (!\is_array($data['header'])) { + throw new \InvalidArgumentException('Bad header.'); + } + $header = $data['header']; + } else { + $header = []; + } + + if (\array_key_exists('payload', $data)) { + $encodedPayload = $data['payload']; + $payload = $this->isPayloadEncoded($protectedHeader) ? Base64Url::decode($encodedPayload) : $encodedPayload; + } else { + $payload = null; + $encodedPayload = null; + } + + $jws = JWS::create($payload, $encodedPayload, null === $encodedPayload); + $jws = $jws->addSignature($signature, $protectedHeader, $encodedProtectedHeader, $header); + + return $jws; + } +} diff --git a/vendor/web-token/jwt-signature/Serializer/JSONGeneralSerializer.php b/vendor/web-token/jwt-signature/Serializer/JSONGeneralSerializer.php new file mode 100644 index 0000000..35958c6 --- /dev/null +++ b/vendor/web-token/jwt-signature/Serializer/JSONGeneralSerializer.php @@ -0,0 +1,174 @@ +<?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\Signature\Serializer; + +use Base64Url\Base64Url; +use Jose\Component\Core\Converter\JsonConverter; +use Jose\Component\Signature\JWS; + +final class JSONGeneralSerializer extends Serializer +{ + public const NAME = 'jws_json_general'; + + /** + * @var \Jose\Component\Core\Util\JsonConverter + */ + private $jsonConverter; + + /** + * JSONFlattenedSerializer constructor. + */ + public function __construct(?JsonConverter $jsonConverter = null) + { + $this->jsonConverter = $jsonConverter ?? new \Jose\Component\Core\Util\JsonConverter(); + } + + 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 (0 === $jws->countSignatures()) { + throw new \LogicException('No signature.'); + } + + $data = []; + $this->checkPayloadEncoding($jws); + + if (false === $jws->isPayloadDetached()) { + $data['payload'] = $jws->getEncodedPayload(); + } + + $data['signatures'] = []; + foreach ($jws->getSignatures() as $signature) { + $tmp = ['signature' => Base64Url::encode($signature->getSignature())]; + $values = [ + 'protected' => $signature->getEncodedProtectedHeader(), + 'header' => $signature->getHeader(), + ]; + + foreach ($values as $key => $value) { + if (!empty($value)) { + $tmp[$key] = $value; + } + } + $data['signatures'][] = $tmp; + } + + return $this->jsonConverter->encode($data); + } + + private function checkData($data) + { + if (!\is_array($data) || !\array_key_exists('signatures', $data)) { + throw new \InvalidArgumentException('Unsupported input.'); + } + } + + private function checkSignature($signature) + { + if (!\is_array($signature) || !\array_key_exists('signature', $signature)) { + throw new \InvalidArgumentException('Unsupported input.'); + } + } + + public function unserialize(string $input): JWS + { + $data = $this->jsonConverter->decode($input); + $this->checkData($data); + + $isPayloadEncoded = null; + $rawPayload = \array_key_exists('payload', $data) ? $data['payload'] : null; + $signatures = []; + foreach ($data['signatures'] as $signature) { + $this->checkSignature($signature); + list($encodedProtectedHeader, $protectedHeader, $header) = $this->processHeaders($signature); + $signatures[] = [ + 'signature' => Base64Url::decode($signature['signature']), + 'protected' => $protectedHeader, + 'encoded_protected' => $encodedProtectedHeader, + 'header' => $header, + ]; + $isPayloadEncoded = $this->processIsPayloadEncoded($isPayloadEncoded, $protectedHeader); + } + + $payload = $this->processPayload($rawPayload, $isPayloadEncoded); + $jws = JWS::create($payload, $rawPayload); + foreach ($signatures as $signature) { + $jws = $jws->addSignature( + $signature['signature'], + $signature['protected'], + $signature['encoded_protected'], + $signature['header'] + ); + } + + return $jws; + } + + private function processIsPayloadEncoded(?bool $isPayloadEncoded, array $protectedHeader): bool + { + if (null === $isPayloadEncoded) { + return self::isPayloadEncoded($protectedHeader); + } + if ($this->isPayloadEncoded($protectedHeader) !== $isPayloadEncoded) { + throw new \InvalidArgumentException('Foreign payload encoding detected.'); + } + + return $isPayloadEncoded; + } + + private function processHeaders(array $signature): array + { + $encodedProtectedHeader = \array_key_exists('protected', $signature) ? $signature['protected'] : null; + $protectedHeader = null !== $encodedProtectedHeader ? $this->jsonConverter->decode(Base64Url::decode($encodedProtectedHeader)) : []; + $header = \array_key_exists('header', $signature) ? $signature['header'] : []; + + return [$encodedProtectedHeader, $protectedHeader, $header]; + } + + private function processPayload(?string $rawPayload, ?bool $isPayloadEncoded): ?string + { + if (null === $rawPayload) { + return null; + } + + return false === $isPayloadEncoded ? $rawPayload : Base64Url::decode($rawPayload); + } + + private function checkPayloadEncoding(JWS $jws) + { + if ($jws->isPayloadDetached()) { + return; + } + $is_encoded = null; + foreach ($jws->getSignatures() as $signature) { + if (null === $is_encoded) { + $is_encoded = $this->isPayloadEncoded($signature->getProtectedHeader()); + } + if (false === $jws->isPayloadDetached()) { + if ($is_encoded !== $this->isPayloadEncoded($signature->getProtectedHeader())) { + throw new \LogicException('Foreign payload encoding detected.'); + } + } + } + } +} diff --git a/vendor/web-token/jwt-signature/Serializer/JWSSerializer.php b/vendor/web-token/jwt-signature/Serializer/JWSSerializer.php new file mode 100644 index 0000000..285aef4 --- /dev/null +++ b/vendor/web-token/jwt-signature/Serializer/JWSSerializer.php @@ -0,0 +1,42 @@ +<?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\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. + * + * @throws \Exception + */ + 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 + * + * @throws \Exception + */ + public function unserialize(string $input): JWS; +} diff --git a/vendor/web-token/jwt-signature/Serializer/JWSSerializerManager.php b/vendor/web-token/jwt-signature/Serializer/JWSSerializerManager.php new file mode 100644 index 0000000..198dfd1 --- /dev/null +++ b/vendor/web-token/jwt-signature/Serializer/JWSSerializerManager.php @@ -0,0 +1,104 @@ +<?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\Signature\Serializer; + +use Jose\Component\Signature\JWS; + +class JWSSerializerManager +{ + /** + * @var JWSSerializer[] + */ + private $serializers = []; + + /** + * JWSSerializerManager constructor. + * + * @param JWSSerializer[] $serializers + */ + public function __construct(array $serializers) + { + foreach ($serializers as $serializer) { + $this->add($serializer); + } + } + + /** + * @deprecated Will be removed in v2.0. Please use constructor instead + * + * @param JWSSerializer[] $serializers + * + * @return JWSSerializerManager + */ + public static function create(array $serializers): self + { + return new self($serializers); + } + + /** + * @return JWSSerializerManager + */ + private function add(JWSSerializer $serializer): self + { + $this->serializers[$serializer->name()] = $serializer; + + return $this; + } + + /** + * @return string[] + */ + public function list(): array + { + return \array_keys($this->serializers); + } + + /** + * Converts a JWS into a string. + * + * @throws \Exception + */ + public function serialize(string $name, JWS $jws, ?int $signatureIndex = null): string + { + if (!\array_key_exists($name, $this->serializers)) { + 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 + * + * @throws \Exception + */ + 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 $e) { + continue; + } + } + + throw new \InvalidArgumentException('Unsupported input.'); + } +} diff --git a/vendor/web-token/jwt-signature/Serializer/JWSSerializerManagerFactory.php b/vendor/web-token/jwt-signature/Serializer/JWSSerializerManagerFactory.php new file mode 100644 index 0000000..1b2c234 --- /dev/null +++ b/vendor/web-token/jwt-signature/Serializer/JWSSerializerManagerFactory.php @@ -0,0 +1,64 @@ +<?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\Signature\Serializer; + +class JWSSerializerManagerFactory +{ + /** + * @var JWSSerializer[] + */ + private $serializers = []; + + /** + * @param string[] $names + */ + public function create(array $names): JWSSerializerManager + { + $serializers = []; + foreach ($names as $name) { + if (!\array_key_exists($name, $this->serializers)) { + throw new \InvalidArgumentException(\sprintf('Unsupported serialiser "%s".', $name)); + } + $serializers[] = $this->serializers[$name]; + } + + return JWSSerializerManager::create($serializers); + } + + /** + * @return string[] + */ + public function names(): array + { + return \array_keys($this->serializers); + } + + /** + * @return JWSSerializer[] + */ + public function all(): array + { + return $this->serializers; + } + + /** + * @return JWSSerializerManagerFactory + */ + public function add(JWSSerializer $serializer): self + { + $this->serializers[$serializer->name()] = $serializer; + + return $this; + } +} diff --git a/vendor/web-token/jwt-signature/Serializer/Serializer.php b/vendor/web-token/jwt-signature/Serializer/Serializer.php new file mode 100644 index 0000000..85636b6 --- /dev/null +++ b/vendor/web-token/jwt-signature/Serializer/Serializer.php @@ -0,0 +1,22 @@ +<?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\Signature\Serializer; + +abstract class Serializer implements JWSSerializer +{ + protected function isPayloadEncoded(array $protectedHeader): bool + { + return !\array_key_exists('b64', $protectedHeader) || true === $protectedHeader['b64']; + } +} diff --git a/vendor/web-token/jwt-signature/Signature.php b/vendor/web-token/jwt-signature/Signature.php new file mode 100644 index 0000000..9b2ef20 --- /dev/null +++ b/vendor/web-token/jwt-signature/Signature.php @@ -0,0 +1,144 @@ +<?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\Signature; + +class Signature +{ + /** + * @var string|null + */ + private $encodedProtectedHeader; + + /** + * @var array + */ + private $protectedHeader; + + /** + * @var array + */ + private $header; + + /** + * @var string + */ + private $signature; + + /** + * Signature constructor. + */ + private function __construct(string $signature, array $protectedHeader, ?string $encodedProtectedHeader, array $header) + { + $this->protectedHeader = null === $encodedProtectedHeader ? [] : $protectedHeader; + $this->encodedProtectedHeader = $encodedProtectedHeader; + $this->signature = $signature; + $this->header = $header; + } + + /** + * Creates a new signature. + * + * @internal + * + * @return Signature + */ + public static function create(string $signature, array $protectedHeader, ?string $encodedProtectedHeader, array $header = []): self + { + return new self($signature, $protectedHeader, $encodedProtectedHeader, $header); + } + + /** + * The protected header associated with the signature. + */ + public function getProtectedHeader(): array + { + return $this->protectedHeader; + } + + /** + * The unprotected header associated with the signature. + */ + 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 ($this->hasHeaderParameter($key)) { + 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; + } +} diff --git a/vendor/web-token/jwt-signature/Util/RSA.php b/vendor/web-token/jwt-signature/Util/RSA.php new file mode 100644 index 0000000..e71e6da --- /dev/null +++ b/vendor/web-token/jwt-signature/Util/RSA.php @@ -0,0 +1,229 @@ +<?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\Signature\Util; + +use Jose\Component\Core\Util\BigInteger; +use Jose\Component\Core\Util\Hash; +use Jose\Component\Core\Util\RSAKey; + +/** + * @internal + */ +class RSA +{ + /** + * Probabilistic Signature Scheme. + */ + public const SIGNATURE_PSS = 1; + + /** + * Use the PKCS#1. + */ + public const SIGNATURE_PKCS1 = 2; + + 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]; + $em = $maskedDB.$h.\chr(0xBC); + + return $em; + } + + /** + * 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 (1 !== \ord($db[$temp])) { + 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); + } + + private static function encodeEMSA15(string $m, int $emBits, Hash $hash): string + { + $h = $hash->hash($m); + switch ($hash->name()) { + case 'sha256': + $t = "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20"; + + break; + case 'sha384': + $t = "\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02\x05\x00\x04\x30"; + + break; + case 'sha512': + $t = "\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03\x05\x00\x04\x40"; + + break; + default: + throw new \InvalidArgumentException(); + } + $t .= $h; + $tLen = \mb_strlen($t, '8bit'); + if ($emBits < $tLen + 11) { + throw new \RuntimeException(); + } + $ps = \str_repeat(\chr(0xFF), $emBits - $tLen - 3); + $em2 = "\0\1$ps\0$t"; + + return $em2; + } + + 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: + return self::signWithPKCS15($key, $message, $hash); + default: + throw new \InvalidArgumentException('Unsupported mode.'); + } + } + + /** + * Create a signature. + */ + 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); + + return self::convertIntegerToOctetString($signature, $key->getModulusLength()); + } + + /** + * Create a signature. + */ + public static function signWithPKCS15(RSAKey $key, string $message, string $hash): string + { + $em = self::encodeEMSA15($message, $key->getModulusLength(), Hash::$hash()); + $message = BigInteger::createFromBinaryString($em); + $signature = RSAKey::exponentiate($key, $message); + + return self::convertIntegerToOctetString($signature, $key->getModulusLength()); + } + + public static function verify(RSAKey $key, string $message, string $signature, string $hash, int $mode): bool + { + switch ($mode) { + case self::SIGNATURE_PSS: + return self::verifyWithPSS($key, $message, $signature, $hash); + case self::SIGNATURE_PKCS1: + return self::verifyWithPKCS15($key, $message, $signature, $hash); + 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 \InvalidArgumentException(); + } + $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()); + } + + /** + * Verifies a signature. + */ + public static function verifyWithPKCS15(RSAKey $key, string $message, string $signature, string $hash): bool + { + if (\mb_strlen($signature, '8bit') !== $key->getModulusLength()) { + throw new \InvalidArgumentException(); + } + $signature = BigInteger::createFromBinaryString($signature); + $m2 = RSAKey::exponentiate($key, $signature); + $em = self::convertIntegerToOctetString($m2, $key->getModulusLength()); + + return \hash_equals($em, self::encodeEMSA15($message, $key->getModulusLength(), Hash::$hash())); + } +} diff --git a/vendor/web-token/jwt-signature/composer.json b/vendor/web-token/jwt-signature/composer.json new file mode 100644 index 0000000..e0ceab9 --- /dev/null +++ b/vendor/web-token/jwt-signature/composer.json @@ -0,0 +1,49 @@ +{ + "name": "web-token/jwt-signature", + "description": "Signature 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-signature/contributors" + } + ], + "autoload": { + "psr-4": { + "Jose\\Component\\Signature\\": "" + } + }, + "require": { + "web-token/jwt-core": "^1.3", + "web-token/jwt-signature-algorithm-ecdsa": "^1.3", + "web-token/jwt-signature-algorithm-eddsa": "^1.3", + "web-token/jwt-signature-algorithm-hmac": "^1.3", + "web-token/jwt-signature-algorithm-none": "^1.3", + "web-token/jwt-signature-algorithm-rsa": "^1.3" + }, + "require-dev": { + "phpunit/phpunit": "^6.0|^7.0" + }, + "suggest": { + "web-token/jwt-signature-algorithm-ecdsa": "ECDSA Based Signature Algorithms", + "web-token/jwt-signature-algorithm-eddsa": "EdDSA Based Signature Algorithms", + "web-token/jwt-signature-algorithm-hmac": "HMAC Based Signature Algorithms", + "web-token/jwt-signature-algorithm-none": "None Signature Algorithm", + "web-token/jwt-signature-algorithm-rsa": "RSA Based Signature Algorithms", + "web-token/jwt-signature-algorithm-experimental": "Experimental Signature Algorithms" + }, + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "config": { + "sort-packages": true + } +} |