Skip to content

Commit

Permalink
Add fallback verification method to the HMAC implementation
Browse files Browse the repository at this point in the history
Since we've moved away from hash() signing in favor of hash_hmac() we should (for now) support the hash verification method to keep older implementations valid

Remove unused import
  • Loading branch information
kjansenpay committed Feb 1, 2024
1 parent 2e1d10b commit 2b6003b
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 3 deletions.
42 changes: 39 additions & 3 deletions src/Methods/HmacSignature.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public function __construct(HmacSignatureKeyRepositoryInterface $signatureKeyRep
*/
public function sign(RequestInterface $request, string $keyId, string $algorithm): RequestInterface
{
$signatureData = $this->generateSignature((string) $request->getBody(), $keyId, $algorithm);
$signatureData = $this->generateSignature((string)$request->getBody(), $keyId, $algorithm);

return $request
->withHeader(RequestSigningMethodInterface::SIGNATURE_HEADER, $signatureData->getSignature())
Expand Down Expand Up @@ -90,10 +90,10 @@ public function verify(RequestInterface $request): bool
$algorithm = $request->getHeaderLine(RequestSigningMethodInterface::SIGNATURE_ALGORITHM_HEADER);

$generatedSignature = $this
->generateSignature((string) $request->getBody(), $keyId, $algorithm)
->generateSignature((string)$request->getBody(), $keyId, $algorithm)
->getSignature();

return hash_equals($signature, $generatedSignature);
return hash_equals($signature, $generatedSignature) || $this->doFallbackVerification($request);
} catch (Throwable $throwable) {
// We do nothing with the exception. The request stays marked as "invalid".
}
Expand All @@ -105,4 +105,40 @@ public function supports(string $method): bool
{
return strtolower(self::METHOD_NAME) === strtolower($method);
}

/**
* Since we've moved away from hash() signing in favor of hash_hmac we should (for now) support the
* hash verification method to keep older implementations valid
*
* @throws UnsupportedHashingAlgorithmException
* @throws SignatureKeyNotFoundException
*/
private function doFallbackVerification(RequestInterface $request): bool
{
$keyId = $request->getHeaderLine(RequestSigningMethodInterface::SIGNATURE_KEY_ID_HEADER);
$signature = $request->getHeaderLine(RequestSigningMethodInterface::SIGNATURE_HEADER);
$algorithm = $request->getHeaderLine(RequestSigningMethodInterface::SIGNATURE_ALGORITHM_HEADER);

$key = $this->signatureKeyRepository->findOneById($keyId);

$algorithm = strtolower($algorithm);

if (in_array($algorithm, hash_algos()) === false) {
throw UnsupportedHashingAlgorithmException::forAlgorithm($algorithm);
}

$generatedSignature = hash(
$algorithm,
implode(
':',
[
$key->getId(),
$key->getSecret(),
(string)$request->getBody(),
]
)
);

return hash_equals($signature, $generatedSignature);
}
}
15 changes: 15 additions & 0 deletions tests/Unit/Methods/HmacSignatureTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,21 @@ public function testItReturnsFalseForAnHashingAlgorithm(): void
$this->assertFalse($hmacSignature->verify($request));
}

public function testItCanVerifyUsingTheFallbackMethod(): void
{
// First, we'll create a dummy request
$request = $this->getSignedDummyRequest()->withHeader(
RequestSigningMethodInterface::SIGNATURE_HEADER,
'6086a395c7fe9b47f47cee4623b76cc4cc79cb3f44e968091edc447cfe7e7533dc2564f49b22bc1f225c24f172be0d2a5b5893e0825c6fde782a63f3e43ce7d1'
);

// Next, we'll instantiate the HmacSignature class
$hmacSignature = new HmacSignature($this->getKeyRepository($this->getDummySignatureKey()));

// Next, we'll verify that this request passes its verification
$this->assertTrue($hmacSignature->verify($request));
}

private function getDummyRequest(): RequestInterface
{
return new Request('POST', 'https://pay.nl');
Expand Down

0 comments on commit 2b6003b

Please sign in to comment.