1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
|
<?php
declare(strict_types=1);
namespace Lcobucci\JWT\Tests\Signer\Ecdsa;
use Lcobucci\JWT\Signer\Ecdsa;
use Lcobucci\JWT\Signer\Ecdsa\MultibyteStringConverter;
use Lcobucci\JWT\Signer\InvalidKeyProvided;
use Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\Tests\Keys;
use OpenSSLAsymmetricKey;
use PHPUnit\Framework\Attributes as PHPUnit;
use PHPUnit\Framework\TestCase;
use function assert;
use function openssl_error_string;
use function openssl_pkey_get_private;
use function openssl_pkey_get_public;
use function openssl_sign;
use function openssl_verify;
abstract class EcdsaTestCase extends TestCase
{
use Keys;
protected MultibyteStringConverter $pointsManipulator;
#[PHPUnit\After]
final public function clearOpenSSLErrors(): void
{
// phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedWhile
while (openssl_error_string()) {
}
}
#[PHPUnit\Before]
final public function createDependencies(): void
{
$this->pointsManipulator = new MultibyteStringConverter();
}
abstract protected function algorithm(): Ecdsa;
abstract protected function algorithmId(): string;
abstract protected function signatureAlgorithm(): int;
abstract protected function pointLength(): int;
abstract protected function keyLength(): int;
abstract protected function verificationKey(): Key;
abstract protected function signingKey(): Key;
#[PHPUnit\Test]
final public function algorithmIdMustBeCorrect(): void
{
self::assertSame($this->algorithmId(), $this->algorithm()->algorithmId());
}
#[PHPUnit\Test]
final public function signatureAlgorithmMustBeCorrect(): void
{
self::assertSame($this->signatureAlgorithm(), $this->algorithm()->algorithm());
}
#[PHPUnit\Test]
final public function pointLengthMustBeCorrect(): void
{
self::assertSame($this->pointLength(), $this->algorithm()->pointLength());
}
#[PHPUnit\Test]
final public function expectedKeyLengthMustBeCorrect(): void
{
self::assertSame($this->keyLength(), $this->algorithm()->expectedKeyLength());
}
#[PHPUnit\Test]
public function signShouldReturnTheAHashBasedOnTheOpenSslSignature(): void
{
$payload = 'testing';
$signer = $this->algorithm();
$signature = $signer->sign($payload, $this->signingKey());
$publicKey = openssl_pkey_get_public($this->verificationKey()->contents());
assert($publicKey instanceof OpenSSLAsymmetricKey);
self::assertSame(
1,
openssl_verify(
$payload,
$this->pointsManipulator->toAsn1($signature, $signer->pointLength()),
$publicKey,
$this->signatureAlgorithm(),
),
);
}
#[PHPUnit\Test]
#[PHPUnit\DataProvider('incompatibleKeys')]
public function signShouldRaiseAnExceptionWhenKeyLengthIsNotTheExpectedOne(
string $keyId,
int $keyLength,
): void {
self::assertArrayHasKey($keyId, self::$ecdsaKeys);
$this->expectException(InvalidKeyProvided::class);
$this->expectExceptionMessage(
'The length of the provided key is different than ' . $this->keyLength()
. ' bits, ' . $keyLength . ' bits provided',
);
$this->algorithm()->sign('testing', self::$ecdsaKeys[$keyId]);
}
/** @return iterable<string, array{string, int}> */
abstract public static function incompatibleKeys(): iterable;
#[PHPUnit\Test]
public function signShouldRaiseAnExceptionWhenKeyTypeIsNotEC(): void
{
$this->expectException(InvalidKeyProvided::class);
$this->expectExceptionMessage('The type of the provided key is not "EC", "RSA" provided');
$this->algorithm()->sign('testing', self::$rsaKeys['private']);
}
#[PHPUnit\Test]
public function verifyShouldDelegateToEcdsaSignerUsingPublicKey(): void
{
$payload = 'testing';
$privateKey = openssl_pkey_get_private($this->signingKey()->contents());
assert($privateKey instanceof OpenSSLAsymmetricKey);
$signature = '';
openssl_sign($payload, $signature, $privateKey, $this->signatureAlgorithm());
$signer = $this->algorithm();
self::assertTrue(
$signer->verify(
$this->pointsManipulator->fromAsn1($signature, $signer->pointLength()),
$payload,
$this->verificationKey(),
),
);
}
}
|