diff options
Diffstat (limited to 'vendor/macgirvin/http-message-signer/src/HttpMessageSigner.php')
-rw-r--r-- | vendor/macgirvin/http-message-signer/src/HttpMessageSigner.php | 94 |
1 files changed, 74 insertions, 20 deletions
diff --git a/vendor/macgirvin/http-message-signer/src/HttpMessageSigner.php b/vendor/macgirvin/http-message-signer/src/HttpMessageSigner.php index 69b47c65a..31c481f22 100644 --- a/vendor/macgirvin/http-message-signer/src/HttpMessageSigner.php +++ b/vendor/macgirvin/http-message-signer/src/HttpMessageSigner.php @@ -2,6 +2,7 @@ namespace HttpSignature; +use Bakame\Http\StructuredFields\Dictionary; use Bakame\Http\StructuredFields\InnerList; use Bakame\Http\StructuredFields\Item; use Bakame\Http\StructuredFields\OuterList; @@ -9,7 +10,7 @@ use Bakame\Http\StructuredFields\Parameters; use Psr\Http\Message\MessageInterface; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; -use Bakame\Http\StructuredFields\Dictionary; +use phpseclib\Crypt\RSA; class HttpMessageSigner { @@ -45,6 +46,13 @@ class HttpMessageSigner /* PSR-7 interface to signing function */ + /** + * @param string $coveredFields + * @param MessageInterface $interface + * @param RequestInterface|null $originalRequest + * @return MessageInterface + * @throws UnProcessableSignatureException + */ public function signRequest(string $coveredFields, MessageInterface $interface, RequestInterface $originalRequest = null): MessageInterface { @@ -66,6 +74,13 @@ class HttpMessageSigner } /* PSR-7 verify interface and also check body digest if included */ + /** + * @param MessageInterface $interface + * @param RequestInterface|null $originalRequest + * @return bool + * + * @throws UnProcessableSignatureException + */ public function verifyRequest(MessageInterface $interface, RequestInterface $originalRequest = null): bool { @@ -263,21 +278,6 @@ class HttpMessageSigner } $sigDict = $this->parseStructuredDict($headers['signature']); - if ($sigDict->isNotEmpty()) { - $indices = $sigDict->indices(); - foreach ($indices as $index) { - [$dictName, $members] = $sigDict->getByIndex($index); - if ($members instanceof Item) { - $signatures[$dictName] = $members->value(); - } - if ($members instanceof InnerList) { - $innerIndices = $members->indices(); - foreach ($innerIndices as $innerIndex) { - $signatures[$dictName][] = $members->getByIndex($innerIndex); - } - } - } - } foreach ($signatureComponents as $dictName => $dictComponents) { $namedSignatureComponents = $signatureComponents[$dictName]; @@ -289,7 +289,7 @@ class HttpMessageSigner } $decodedSig = base64_decode(trim($sigDict[$dictName]->__toString(), ':')); - return $this->verifySignature($signatureBase, $decodedSig, $params['alg'] ?? $this->algorithm); + return $this->verifySignature($signatureBase, $decodedSig, $parameters['alg'] ?? $this->algorithm); } return false; } @@ -364,12 +364,17 @@ class HttpMessageSigner private function getFieldValue($fieldName, MessageInterface $interface, $headers, $parameters ): array { + // The $interface has no single method to extract this, so build it from + // the avilable components. + $targetUri = $interface->getUri()->getScheme() . '://' . $interface->getUri()->getAuthority() + . $interface->getUri()->getPath() . $interface->getUri()->getQuery(); + $value = match ($fieldName) { '@signature-params' => ['', ''], '@method' => ['"@method"', strtoupper($interface->getMethod())], '@authority' => ['"@authority"', $interface->getUri()->getAuthority()], '@scheme' => ['"@scheme"', strtolower($interface->getUri()->getScheme())], - '@target-uri' => ['"target-uri"', $interface->getUri()->__toString()], + '@target-uri' => ['"@target-uri"', $targetUri], '@request-target' => ['"@request-target"', $interface->getRequestTarget()], '@path' => ['"@path"', $interface->getUri()->getPath()], '@query' => ['"@query"', $interface->getUri()->getQuery()], @@ -486,7 +491,10 @@ class HttpMessageSigner private function createSignature(string $data): string { return match ($this->algorithm) { + 'rsa-v1_5-sha256' => $this->rsaSign($data), + 'rsa-v1_5-sha512' => $this->rsa512Sign($data), 'rsa-sha256' => $this->rsaSign($data), + 'rsa-pss-sha512' => $this->pssSign($data), 'ed25519' => $this->ed25519Sign($data), 'hmac-sha256' => base64_encode(hash_hmac('sha256', $data, $this->privateKey, true)), default => throw new UnProcessableSignatureException("Unsupported algorithm: $this->algorithm") @@ -496,8 +504,13 @@ class HttpMessageSigner private function verifySignature(string $data, string $signature, string $alg): bool { return match ($alg) { - 'rsa-sha256' => openssl_verify($data, $signature, $this->publicKey, - OPENSSL_ALGO_SHA256) === 1, + 'rsa-v1_5-sha256' => openssl_verify($data, $signature, $this->publicKey, + OPENSSL_ALGO_SHA256) === 1, + 'rsa-v1_5-sha512' => openssl_verify($data, $signature, $this->publicKey, + OPENSSL_ALGO_SHA512) === 1, + 'rsa-sha256' => openssl_verify($data, $signature, $this->publicKey, + OPENSSL_ALGO_SHA256) === 1, + 'rsa-pss-sha512' => $this->pssVerify($data, $signature), 'ed25519' => openssl_verify($data, $signature, $this->publicKey, "Ed25519") === 1, 'hmac-sha256' => hash_equals( base64_encode(hash_hmac('sha256', $data, $this->privateKey, true)), @@ -516,6 +529,30 @@ class HttpMessageSigner } return base64_encode($signature); } + private function rsa512Sign(string $data): string + { + if (!openssl_sign($data, $signature, $this->privateKey, OPENSSL_ALGO_SHA512)) { + throw new UnProcessableSignatureException("RSA signing failed"); + } + return base64_encode($signature); + } + + private function pssSign(string $data): string + { + $rsa = new RSA(); + if ($rsa->loadKey($this->privateKey) !== true) { + throw new UnprocessableSignatureException("PSS loadkey failure"); + }; + $rsa->setHash('sha512'); + $rsa->setMGFHash('sha512'); + $rsa->setSignatureMode(RSA::SIGNATURE_PSS); + try { + $signatureBytes = $rsa->sign($data); + } catch (\Exception $exception) { + throw new UnprocessableSignatureException($exception->getMessage()); + } + return base64_encode($signatureBytes); + } private function ed25519Sign(string $data): string { @@ -525,6 +562,23 @@ class HttpMessageSigner return base64_encode($signature); } + private function pssVerify(string $data, $signature): bool + { + $rsa = new RSA(); + if (!$rsa->loadKey($this->publicKey)) { + throw new UnprocessableSignatureException("PSS loadkey failure"); + }; + $rsa->setHash('sha512'); + $rsa->setMGFHash('sha512'); + $rsa->setSignatureMode(RSA::SIGNATURE_PSS); + try { + $verified = $rsa->verify($data, $signature); + } catch (\Exception $exception) { + $verified = false; + } + return $verified; + } + /* parse a structed dict */ private function parseStructuredDict(string $headerValue) |