[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 <?php 2 3 declare(strict_types=1); 4 5 /* 6 * The MIT License (MIT) 7 * 8 * Copyright (c) 2014-2020 Spomky-Labs 9 * 10 * This software may be modified and distributed under the terms 11 * of the MIT license. See the LICENSE file for details. 12 */ 13 14 namespace Jose\Component\Signature; 15 16 use Base64Url\Base64Url; 17 use InvalidArgumentException; 18 use Jose\Component\Core\Algorithm; 19 use Jose\Component\Core\AlgorithmManager; 20 use Jose\Component\Core\JWK; 21 use Jose\Component\Core\JWKSet; 22 use Jose\Component\Core\Util\KeyChecker; 23 use Jose\Component\Signature\Algorithm\MacAlgorithm; 24 use Jose\Component\Signature\Algorithm\SignatureAlgorithm; 25 use Throwable; 26 27 class JWSVerifier 28 { 29 /** 30 * @var AlgorithmManager 31 */ 32 private $signatureAlgorithmManager; 33 34 /** 35 * JWSVerifier constructor. 36 */ 37 public function __construct(AlgorithmManager $signatureAlgorithmManager) 38 { 39 $this->signatureAlgorithmManager = $signatureAlgorithmManager; 40 } 41 42 /** 43 * Returns the algorithm manager associated to the JWSVerifier. 44 */ 45 public function getSignatureAlgorithmManager(): AlgorithmManager 46 { 47 return $this->signatureAlgorithmManager; 48 } 49 50 /** 51 * This method will try to verify the JWS object using the given key and for the given signature. 52 * It returns true if the signature is verified, otherwise false. 53 * 54 * @return bool true if the verification of the signature succeeded, else false 55 */ 56 public function verifyWithKey(JWS $jws, JWK $jwk, int $signature, ?string $detachedPayload = null): bool 57 { 58 $jwkset = new JWKSet([$jwk]); 59 60 return $this->verifyWithKeySet($jws, $jwkset, $signature, $detachedPayload); 61 } 62 63 /** 64 * This method will try to verify the JWS object using the given key set and for the given signature. 65 * It returns true if the signature is verified, otherwise false. 66 * 67 * @param JWS $jws A JWS object 68 * @param JWKSet $jwkset The signature will be verified using keys in the key set 69 * @param JWK $jwk The key used to verify the signature in case of success 70 * @param null|string $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. 71 * 72 * @throws InvalidArgumentException if there is no key in the keyset 73 * @throws InvalidArgumentException if the token does not contain any signature 74 * 75 * @return bool true if the verification of the signature succeeded, else false 76 */ 77 public function verifyWithKeySet(JWS $jws, JWKSet $jwkset, int $signatureIndex, ?string $detachedPayload = null, JWK &$jwk = null): bool 78 { 79 if (0 === $jwkset->count()) { 80 throw new InvalidArgumentException('There is no key in the key set.'); 81 } 82 if (0 === $jws->countSignatures()) { 83 throw new InvalidArgumentException('The JWS does not contain any signature.'); 84 } 85 $this->checkPayload($jws, $detachedPayload); 86 $signature = $jws->getSignature($signatureIndex); 87 88 return $this->verifySignature($jws, $jwkset, $signature, $detachedPayload, $jwk); 89 } 90 91 private function verifySignature(JWS $jws, JWKSet $jwkset, Signature $signature, ?string $detachedPayload = null, JWK &$successJwk = null): bool 92 { 93 $input = $this->getInputToVerify($jws, $signature, $detachedPayload); 94 $algorithm = $this->getAlgorithm($signature); 95 foreach ($jwkset->all() as $jwk) { 96 try { 97 KeyChecker::checkKeyUsage($jwk, 'verification'); 98 KeyChecker::checkKeyAlgorithm($jwk, $algorithm->name()); 99 if (true === $algorithm->verify($jwk, $input, $signature->getSignature())) { 100 $successJwk = $jwk; 101 102 return true; 103 } 104 } catch (Throwable $e) { 105 //We do nothing, we continue with other keys 106 continue; 107 } 108 } 109 110 return false; 111 } 112 113 private function getInputToVerify(JWS $jws, Signature $signature, ?string $detachedPayload): string 114 { 115 $isPayloadEmpty = $this->isPayloadEmpty($jws->getPayload()); 116 $encodedProtectedHeader = $signature->getEncodedProtectedHeader(); 117 if (!$signature->hasProtectedHeaderParameter('b64') || true === $signature->getProtectedHeaderParameter('b64')) { 118 if (null !== $jws->getEncodedPayload()) { 119 return sprintf('%s.%s', $encodedProtectedHeader, $jws->getEncodedPayload()); 120 } 121 122 $payload = $isPayloadEmpty ? $detachedPayload : $jws->getPayload(); 123 124 return sprintf('%s.%s', $encodedProtectedHeader, Base64Url::encode($payload)); 125 } 126 127 $payload = $isPayloadEmpty ? $detachedPayload : $jws->getPayload(); 128 129 return sprintf('%s.%s', $encodedProtectedHeader, $payload); 130 } 131 132 /** 133 * @throws InvalidArgumentException if the payload is set when a detached payload is provided or no payload is defined 134 */ 135 private function checkPayload(JWS $jws, ?string $detachedPayload = null): void 136 { 137 $isPayloadEmpty = $this->isPayloadEmpty($jws->getPayload()); 138 if (null !== $detachedPayload && !$isPayloadEmpty) { 139 throw new InvalidArgumentException('A detached payload is set, but the JWS already has a payload.'); 140 } 141 if ($isPayloadEmpty && null === $detachedPayload) { 142 throw new InvalidArgumentException('The JWS has a detached payload, but no payload is provided.'); 143 } 144 } 145 146 /** 147 * @throws InvalidArgumentException if the header parameter "alg" is missing or invalid 148 * 149 * @return MacAlgorithm|SignatureAlgorithm 150 */ 151 private function getAlgorithm(Signature $signature): Algorithm 152 { 153 $completeHeader = array_merge($signature->getProtectedHeader(), $signature->getHeader()); 154 if (!isset($completeHeader['alg'])) { 155 throw new InvalidArgumentException('No "alg" parameter set in the header.'); 156 } 157 158 $algorithm = $this->signatureAlgorithmManager->get($completeHeader['alg']); 159 if (!$algorithm instanceof SignatureAlgorithm && !$algorithm instanceof MacAlgorithm) { 160 throw new InvalidArgumentException(sprintf('The algorithm "%s" is not supported or is not a signature or MAC algorithm.', $completeHeader['alg'])); 161 } 162 163 return $algorithm; 164 } 165 166 private function isPayloadEmpty(?string $payload): bool 167 { 168 return null === $payload || '' === $payload; 169 } 170 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |