diff --git a/docs/configuration.md b/docs/configuration.md index 2bcd806e..00a2ad44 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -71,18 +71,18 @@ $configuration = Configuration::forSymmetricSigner( Currently supported symmetric algorithms: | Name | Description | Class | Key length req. | -| --------- | ------------------ | ---------------------------------------- | --------------- | -| `HS256` | HMAC using SHA-256 | `\Lcobucci\JWT\Signer\Hmac\Sha256` | 32 bytes | -| `HS384` | HMAC using SHA-384 | `\Lcobucci\JWT\Signer\Hmac\Sha384` | 48 bytes | -| `HS512` | HMAC using SHA-512 | `\Lcobucci\JWT\Signer\Hmac\Sha512` | 64 bytes | +| --------- | ------------------ | ---------------------------------------- |-----------------| +| `HS256` | HMAC using SHA-256 | `\Lcobucci\JWT\Signer\Hmac\Sha256` | 256 bits | +| `HS384` | HMAC using SHA-384 | `\Lcobucci\JWT\Signer\Hmac\Sha384` | 384 bits | +| `HS512` | HMAC using SHA-512 | `\Lcobucci\JWT\Signer\Hmac\Sha512` | 512 bits | Deprecated symmetric algorithms in `v4`: | Name | Description | Class | Key length req. | -| --------- | ------------------ | ---------------------------------------- | --------------- | -| `HS256` | HMAC using SHA-256 | `\Lcobucci\JWT\Signer\Hmac\UnsafeSha256` | 1 byte | -| `HS384` | HMAC using SHA-384 | `\Lcobucci\JWT\Signer\Hmac\UnsafeSha384` | 1 byte | -| `HS512` | HMAC using SHA-512 | `\Lcobucci\JWT\Signer\Hmac\UnsafeSha512` | 1 byte | +| --------- | ------------------ | ---------------------------------------- |-----------------| +| `HS256` | HMAC using SHA-256 | `\Lcobucci\JWT\Signer\Hmac\UnsafeSha256` | 1 bit | +| `HS384` | HMAC using SHA-384 | `\Lcobucci\JWT\Signer\Hmac\UnsafeSha384` | 1 bit | +| `HS512` | HMAC using SHA-512 | `\Lcobucci\JWT\Signer\Hmac\UnsafeSha512` | 1 bit | #### For asymmetric algorithms @@ -109,15 +109,26 @@ $configuration = Configuration::forAsymmetricSigner( Currently supported asymmetric algorithms: -| Name | Description | Class | -| ------- | ------------------------------- | ----------------------------------- | -| `ES256` | ECDSA using P-256 and SHA-256 | `\Lcobucci\JWT\Signer\Ecdsa\Sha256` | -| `ES384` | ECDSA using P-384 and SHA-384 | `\Lcobucci\JWT\Signer\Ecdsa\Sha384` | -| `ES512` | ECDSA using P-521 and SHA-512 | `\Lcobucci\JWT\Signer\Ecdsa\Sha512` | -| `RS256` | RSASSA-PKCS1-v1_5 using SHA-256 | `\Lcobucci\JWT\Signer\Rsa\Sha256` | -| `RS384` | RSASSA-PKCS1-v1_5 using SHA-384 | `\Lcobucci\JWT\Signer\Rsa\Sha384` | -| `RS512` | RSASSA-PKCS1-v1_5 using SHA-512 | `\Lcobucci\JWT\Signer\Rsa\Sha512` | -| `EdDSA` | EdDSA signature algorithms | `\Lcobucci\JWT\Signer\Eddsa` | +| Name | Description | Class | Key length req. | +| ------- | ------------------------------- | ----------------------------------- |-----------------| +| `ES256` | ECDSA using P-256 and SHA-256 | `\Lcobucci\JWT\Signer\Ecdsa\Sha256` | 224 bits | +| `ES384` | ECDSA using P-384 and SHA-384 | `\Lcobucci\JWT\Signer\Ecdsa\Sha384` | 224 bits | +| `ES512` | ECDSA using P-521 and SHA-512 | `\Lcobucci\JWT\Signer\Ecdsa\Sha512` | 224 bits | +| `RS256` | RSASSA-PKCS1-v1_5 using SHA-256 | `\Lcobucci\JWT\Signer\Rsa\Sha256` | 2048 bits | +| `RS384` | RSASSA-PKCS1-v1_5 using SHA-384 | `\Lcobucci\JWT\Signer\Rsa\Sha384` | 2048 bits | +| `RS512` | RSASSA-PKCS1-v1_5 using SHA-512 | `\Lcobucci\JWT\Signer\Rsa\Sha512` | 2048 bits | +| `EdDSA` | EdDSA signature algorithms | `\Lcobucci\JWT\Signer\Eddsa` | 256 bits | + +Deprecated asymmetric algorithms in `v4`: + +| Name | Description | Class | Key length req. | +| ------- | ------------------------------- |-------------------------------------------|-----------------| +| `ES256` | ECDSA using P-256 and SHA-256 | `\Lcobucci\JWT\Signer\Ecdsa\UnsafeSha256` | 1 bit | +| `ES384` | ECDSA using P-384 and SHA-384 | `\Lcobucci\JWT\Signer\Ecdsa\UnsafeSha384` | 1 bit | +| `ES512` | ECDSA using P-521 and SHA-512 | `\Lcobucci\JWT\Signer\Ecdsa\UnsafeSha512` | 1 bit | +| `RS256` | RSASSA-PKCS1-v1_5 using SHA-256 | `\Lcobucci\JWT\Signer\Rsa\UnsafeSha256` | 1 bit | +| `RS384` | RSASSA-PKCS1-v1_5 using SHA-384 | `\Lcobucci\JWT\Signer\Rsa\UnsafeSha384` | 1 bit | +| `RS512` | RSASSA-PKCS1-v1_5 using SHA-512 | `\Lcobucci\JWT\Signer\Rsa\UnsafeSha512` | 1 bit | #### For no algorithm diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 87a778a7..17b65901 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -8,6 +8,6 @@ parameters: - '#.*OpenSSLAsymmetricKey.*#' - '#Call to method .* of deprecated class Lcobucci\\JWT\\Signer\\Key\\LocalFileReference#' - """ - #^Instantiation of deprecated class Lcobucci\\\\JWT\\\\Signer\\\\Hmac\\\\UnsafeSha\\d\\d\\d\\: + #^.+ deprecated class Lcobucci\\\\JWT\\\\Signer\\\\.+: Deprecated since v4\\.2$# """ diff --git a/src/Signer/Ecdsa.php b/src/Signer/Ecdsa.php index f8ada157..efaec676 100644 --- a/src/Signer/Ecdsa.php +++ b/src/Signer/Ecdsa.php @@ -44,6 +44,11 @@ final public function keyType(): int return OPENSSL_KEYTYPE_EC; } + final public function minimumBitsLengthForKey(): int + { + return 224; + } + /** * Returns the length of each point in the signature, so that we can calculate and verify R and S points properly * diff --git a/src/Signer/Ecdsa/UnsafeSha256.php b/src/Signer/Ecdsa/UnsafeSha256.php new file mode 100644 index 00000000..0fadd845 --- /dev/null +++ b/src/Signer/Ecdsa/UnsafeSha256.php @@ -0,0 +1,27 @@ +contents()); - $expectedKeyLength = $this->minimumBytesLengthForKey(); + $actualKeyLength = 8 * strlen($key->contents()); + $expectedKeyLength = $this->minimumBitsLengthForKey(); if ($actualKeyLength < $expectedKeyLength) { throw InvalidKeyProvided::tooShort($expectedKeyLength, $actualKeyLength); } @@ -30,5 +30,5 @@ final public function verify(string $expected, string $payload, Key $key): bool abstract public function algorithm(): string; /** @return positive-int */ - abstract public function minimumBytesLengthForKey(): int; + abstract public function minimumBitsLengthForKey(): int; } diff --git a/src/Signer/Hmac/Sha256.php b/src/Signer/Hmac/Sha256.php index a25b224d..e19992ec 100644 --- a/src/Signer/Hmac/Sha256.php +++ b/src/Signer/Hmac/Sha256.php @@ -17,8 +17,8 @@ public function algorithm(): string return 'sha256'; } - public function minimumBytesLengthForKey(): int + public function minimumBitsLengthForKey(): int { - return 32; + return 256; } } diff --git a/src/Signer/Hmac/Sha384.php b/src/Signer/Hmac/Sha384.php index 393aa5b5..ab795bc3 100644 --- a/src/Signer/Hmac/Sha384.php +++ b/src/Signer/Hmac/Sha384.php @@ -17,8 +17,8 @@ public function algorithm(): string return 'sha384'; } - public function minimumBytesLengthForKey(): int + public function minimumBitsLengthForKey(): int { - return 48; + return 384; } } diff --git a/src/Signer/Hmac/Sha512.php b/src/Signer/Hmac/Sha512.php index 07da8403..69716122 100644 --- a/src/Signer/Hmac/Sha512.php +++ b/src/Signer/Hmac/Sha512.php @@ -17,8 +17,8 @@ public function algorithm(): string return 'sha512'; } - public function minimumBytesLengthForKey(): int + public function minimumBitsLengthForKey(): int { - return 64; + return 512; } } diff --git a/src/Signer/Hmac/UnsafeSha256.php b/src/Signer/Hmac/UnsafeSha256.php index 034f436d..3b66132d 100644 --- a/src/Signer/Hmac/UnsafeSha256.php +++ b/src/Signer/Hmac/UnsafeSha256.php @@ -18,7 +18,7 @@ public function algorithm(): string return 'sha256'; } - public function minimumBytesLengthForKey(): int + public function minimumBitsLengthForKey(): int { return 1; } diff --git a/src/Signer/Hmac/UnsafeSha384.php b/src/Signer/Hmac/UnsafeSha384.php index a1b65317..b6ccf948 100644 --- a/src/Signer/Hmac/UnsafeSha384.php +++ b/src/Signer/Hmac/UnsafeSha384.php @@ -18,7 +18,7 @@ public function algorithm(): string return 'sha384'; } - public function minimumBytesLengthForKey(): int + public function minimumBitsLengthForKey(): int { return 1; } diff --git a/src/Signer/Hmac/UnsafeSha512.php b/src/Signer/Hmac/UnsafeSha512.php index 5acca837..34e86dcb 100644 --- a/src/Signer/Hmac/UnsafeSha512.php +++ b/src/Signer/Hmac/UnsafeSha512.php @@ -18,7 +18,7 @@ public function algorithm(): string return 'sha512'; } - public function minimumBytesLengthForKey(): int + public function minimumBitsLengthForKey(): int { return 1; } diff --git a/src/Signer/InvalidKeyProvided.php b/src/Signer/InvalidKeyProvided.php index da279d62..a7e904f4 100644 --- a/src/Signer/InvalidKeyProvided.php +++ b/src/Signer/InvalidKeyProvided.php @@ -25,7 +25,7 @@ public static function cannotBeEmpty(): self public static function tooShort(int $expectedLength, int $actualLength): self { - return new self('Key provided is shorter than ' . $expectedLength . ' bytes,' - . ' only ' . $actualLength . ' bytes provided'); + return new self('Key provided is shorter than ' . $expectedLength . ' bits,' + . ' only ' . $actualLength . ' bits provided'); } } diff --git a/src/Signer/OpenSSL.php b/src/Signer/OpenSSL.php index b030e75a..78cc7190 100644 --- a/src/Signer/OpenSSL.php +++ b/src/Signer/OpenSSL.php @@ -10,6 +10,7 @@ use function assert; use function is_array; use function is_bool; +use function is_int; use function is_string; use function openssl_error_string; use function openssl_free_key; @@ -48,6 +49,9 @@ final protected function createSignature( } } + /** @return positive-int */ + abstract public function minimumBitsLengthForKey(): int; + /** * @return resource|OpenSSLAsymmetricKey * @@ -109,6 +113,12 @@ private function validateKey($key): void if (! array_key_exists('key', $details) || $details['type'] !== $this->keyType()) { throw InvalidKeyProvided::incompatibleKey(); } + + assert(array_key_exists('bits', $details)); + assert(is_int($details['bits'])); + if ($details['bits'] < $this->minimumBitsLengthForKey()) { + throw InvalidKeyProvided::tooShort($this->minimumBitsLengthForKey(), $details['bits']); + } } /** @param resource|OpenSSLAsymmetricKey $key */ diff --git a/src/Signer/Rsa.php b/src/Signer/Rsa.php index ff54dd32..3af57bd8 100644 --- a/src/Signer/Rsa.php +++ b/src/Signer/Rsa.php @@ -21,4 +21,9 @@ final public function keyType(): int { return OPENSSL_KEYTYPE_RSA; } + + final public function minimumBitsLengthForKey(): int + { + return 2048; + } } diff --git a/src/Signer/Rsa/UnsafeSha256.php b/src/Signer/Rsa/UnsafeSha256.php new file mode 100644 index 00000000..e6e67f29 --- /dev/null +++ b/src/Signer/Rsa/UnsafeSha256.php @@ -0,0 +1,22 @@ +converter = $converter; + } + + public static function create(): UnsafeEcdsa + { + return new static(new MultibyteStringConverter()); // @phpstan-ignore-line + } + + final public function sign(string $payload, Key $key): string + { + return $this->converter->fromAsn1( + $this->createSignature($key->contents(), $key->passphrase(), $payload), + $this->keyLength() + ); + } + + final public function verify(string $expected, string $payload, Key $key): bool + { + return $this->verifySignature( + $this->converter->toAsn1($expected, $this->keyLength()), + $payload, + $key->contents() + ); + } + + final public function keyType(): int + { + return OPENSSL_KEYTYPE_EC; + } + + final public function minimumBitsLengthForKey(): int + { + return 1; + } + + /** + * Returns the length of each point in the signature, so that we can calculate and verify R and S points properly + * + * @internal + */ + abstract public function keyLength(): int; +} diff --git a/src/Signer/UnsafeRsa.php b/src/Signer/UnsafeRsa.php new file mode 100644 index 00000000..0075381f --- /dev/null +++ b/src/Signer/UnsafeRsa.php @@ -0,0 +1,30 @@ +createSignature($key->contents(), $key->passphrase(), $payload); + } + + final public function verify(string $expected, string $payload, Key $key): bool + { + return $this->verifySignature($expected, $payload, $key->contents()); + } + + final public function keyType(): int + { + return OPENSSL_KEYTYPE_RSA; + } + + final public function minimumBitsLengthForKey(): int + { + return 1; + } +} diff --git a/test/_keys/Keys.php b/test/_keys/Keys.php index 93db8224..15b1bf8a 100644 --- a/test/_keys/Keys.php +++ b/test/_keys/Keys.php @@ -4,7 +4,6 @@ namespace Lcobucci\JWT; use Lcobucci\JWT\Signer\Key; -use Lcobucci\JWT\Signer\Key\LocalFileReference; trait Keys { @@ -21,10 +20,12 @@ trait Keys public static function createRsaKeys(): void { static::$rsaKeys = [ - 'private' => LocalFileReference::file(__DIR__ . '/rsa/private.key'), - 'public' => LocalFileReference::file(__DIR__ . '/rsa/public.key'), - 'encrypted-private' => LocalFileReference::file(__DIR__ . '/rsa/encrypted-private.key', 'testing'), - 'encrypted-public' => LocalFileReference::file(__DIR__ . '/rsa/encrypted-public.key'), + 'private' => Key\InMemory::file(__DIR__ . '/rsa/private.key'), + 'public' => Key\InMemory::file(__DIR__ . '/rsa/public.key'), + 'encrypted-private' => Key\InMemory::file(__DIR__ . '/rsa/encrypted-private.key', 'testing'), + 'encrypted-public' => Key\InMemory::file(__DIR__ . '/rsa/encrypted-public.key'), + 'private_short' => Key\InMemory::file(__DIR__ . '/rsa/private_512.key'), + 'public_short' => Key\InMemory::file(__DIR__ . '/rsa/public_512.key'), ]; } @@ -32,14 +33,16 @@ public static function createRsaKeys(): void public static function createEcdsaKeys(): void { static::$ecdsaKeys = [ - 'private' => LocalFileReference::file(__DIR__ . '/ecdsa/private.key'), - 'private-params' => LocalFileReference::file(__DIR__ . '/ecdsa/private2.key'), - 'public1' => LocalFileReference::file(__DIR__ . '/ecdsa/public1.key'), - 'public2' => LocalFileReference::file(__DIR__ . '/ecdsa/public2.key'), - 'public-params' => LocalFileReference::file(__DIR__ . '/ecdsa/public3.key'), - 'private_ec512' => LocalFileReference::file(__DIR__ . '/ecdsa/private_ec512.key'), - 'public_ec512' => LocalFileReference::file(__DIR__ . '/ecdsa/public_ec512.key'), - 'public2_ec512' => LocalFileReference::file(__DIR__ . '/ecdsa/public2_ec512.key'), + 'private' => Key\InMemory::file(__DIR__ . '/ecdsa/private.key'), + 'private-params' => Key\InMemory::file(__DIR__ . '/ecdsa/private2.key'), + 'public1' => Key\InMemory::file(__DIR__ . '/ecdsa/public1.key'), + 'public2' => Key\InMemory::file(__DIR__ . '/ecdsa/public2.key'), + 'public-params' => Key\InMemory::file(__DIR__ . '/ecdsa/public3.key'), + 'private_ec512' => Key\InMemory::file(__DIR__ . '/ecdsa/private_ec512.key'), + 'public_ec512' => Key\InMemory::file(__DIR__ . '/ecdsa/public_ec512.key'), + 'public2_ec512' => Key\InMemory::file(__DIR__ . '/ecdsa/public2_ec512.key'), + 'private_short' => Key\InMemory::file(__DIR__ . '/ecdsa/private_ec160.key'), + 'public_short' => Key\InMemory::file(__DIR__ . '/ecdsa/public_ec160.key'), ]; } diff --git a/test/_keys/ecdsa/private_ec160.key b/test/_keys/ecdsa/private_ec160.key new file mode 100644 index 00000000..b60b08ed --- /dev/null +++ b/test/_keys/ecdsa/private_ec160.key @@ -0,0 +1,4 @@ +-----BEGIN EC PRIVATE KEY----- +MFECAQEEFQBpEH+FRU6SRYbQP0Z6ewKcRaTB7qAHBgUrgQQAHqEsAyoABGBELmbR +K6CARY03gdIWUIQMoWRVKSrdbFjIb/ewb9m7aD1hWTKqUE0= +-----END EC PRIVATE KEY----- diff --git a/test/_keys/ecdsa/public_ec160.key b/test/_keys/ecdsa/public_ec160.key new file mode 100644 index 00000000..34184052 --- /dev/null +++ b/test/_keys/ecdsa/public_ec160.key @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MD4wEAYHKoZIzj0CAQYFK4EEAB4DKgAEYEQuZtEroIBFjTeB0hZQhAyhZFUpKt1s +WMhv97Bv2btoPWFZMqpQTQ== +-----END PUBLIC KEY----- diff --git a/test/_keys/rsa/private_512.key b/test/_keys/rsa/private_512.key new file mode 100644 index 00000000..297b4f16 --- /dev/null +++ b/test/_keys/rsa/private_512.key @@ -0,0 +1,10 @@ +-----BEGIN PRIVATE KEY----- +MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAxZT4cHZXf5QfGX1m +oiSKKSC6AeFO8tGIn9C+4x/bEaQAq6f+V5/0+lFG6uboGC7eItPNWfOMmLnrI162 +cOnB1QIDAQABAkBn4OKdfhqSoLWZGS0UolFhPiuNQX/YegFyxLUXhHAQ3VQdUAHs +4jFT2tviDI1uREdCooKyIQIYOVILrikkc8QBAiEA67ch0VSQvH6A2YO8mKiAUz40 +aB3S4bUKdgj9FoLO/OECIQDWlb/G65w4nfXBplhChGm7SKTS+4zfe6SuqVQYsF8P +dQIgYlCtC0mxYN2G0rLOzAGkHJRaeX7PAZNofJj9LxF6UiECIEMPX3SJ8zNaYhAX +rSN0gBpwVFo/FMJOwKN49XgVvk91AiEAk/DSNPKv1djAz5nzd4t9I4tOqrbPwWr1 +QOxSsGdKfBg= +-----END PRIVATE KEY----- diff --git a/test/_keys/rsa/public_512.key b/test/_keys/rsa/public_512.key new file mode 100644 index 00000000..7cd5a736 --- /dev/null +++ b/test/_keys/rsa/public_512.key @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMWU+HB2V3+UHxl9ZqIkiikgugHhTvLR +iJ/QvuMf2xGkAKun/lef9PpRRurm6Bgu3iLTzVnzjJi56yNetnDpwdUCAwEAAQ== +-----END PUBLIC KEY----- diff --git a/test/functional/HmacTokenTest.php b/test/functional/HmacTokenTest.php index c88d3817..8020f4f1 100644 --- a/test/functional/HmacTokenTest.php +++ b/test/functional/HmacTokenTest.php @@ -8,7 +8,6 @@ use Lcobucci\JWT\Signer\Hmac\Sha512; use Lcobucci\JWT\Signer\Hmac\UnsafeSha256; use Lcobucci\JWT\Signer\Key\InMemory; -use Lcobucci\JWT\Signer\Key\LocalFileReference; use Lcobucci\JWT\Token; use Lcobucci\JWT\Validation\Constraint\SignedWith; use Lcobucci\JWT\Validation\RequiredConstraintsViolated; @@ -158,7 +157,7 @@ public function signatureValidationWithLocalFileKeyReferenceWillOperateWithKeyCo file_put_contents($key, 'just a dummy key'); - $validKey = LocalFileReference::file($key); + $validKey = InMemory::file($key); $invalidKey = InMemory::plainText('file://' . $key); $signer = new UnsafeSha256(); $configuration = Configuration::forSymmetricSigner($signer, $validKey); diff --git a/test/performance/Ecdsa/EcdsaBench.php b/test/performance/Ecdsa/EcdsaBench.php index de74f42a..6583e935 100644 --- a/test/performance/Ecdsa/EcdsaBench.php +++ b/test/performance/Ecdsa/EcdsaBench.php @@ -4,7 +4,6 @@ namespace Lcobucci\JWT\Ecdsa; use Lcobucci\JWT\Signer\Key; -use Lcobucci\JWT\Signer\Key\LocalFileReference; use Lcobucci\JWT\SignerBench; use PhpBench\Benchmark\Metadata\Annotations\Groups; @@ -13,11 +12,11 @@ abstract class EcdsaBench extends SignerBench { protected function signingKey(): Key { - return LocalFileReference::file(__DIR__ . '/private.key'); + return Key\InMemory::file(__DIR__ . '/private.key'); } protected function verificationKey(): Key { - return LocalFileReference::file(__DIR__ . '/public.key'); + return Key\InMemory::file(__DIR__ . '/public.key'); } } diff --git a/test/performance/Rsa/RsaBench.php b/test/performance/Rsa/RsaBench.php index 4121fd4c..55c3db7a 100644 --- a/test/performance/Rsa/RsaBench.php +++ b/test/performance/Rsa/RsaBench.php @@ -4,7 +4,6 @@ namespace Lcobucci\JWT\Rsa; use Lcobucci\JWT\Signer\Key; -use Lcobucci\JWT\Signer\Key\LocalFileReference; use Lcobucci\JWT\SignerBench; use PhpBench\Benchmark\Metadata\Annotations\Groups; @@ -13,11 +12,11 @@ abstract class RsaBench extends SignerBench { protected function signingKey(): Key { - return LocalFileReference::file(__DIR__ . '/private.key'); + return Key\InMemory::file(__DIR__ . '/private.key'); } protected function verificationKey(): Key { - return LocalFileReference::file(__DIR__ . '/public.key'); + return Key\InMemory::file(__DIR__ . '/public.key'); } } diff --git a/test/unit/Signer/Ecdsa/Sha256Test.php b/test/unit/Signer/Ecdsa/Sha256Test.php index 72c5b5d1..9f01e1d3 100644 --- a/test/unit/Signer/Ecdsa/Sha256Test.php +++ b/test/unit/Signer/Ecdsa/Sha256Test.php @@ -61,6 +61,18 @@ public function keyLengthMustBeCorrect(): void self::assertSame(64, $this->getSigner()->keyLength()); } + /** + * @test + * + * @covers ::minimumBitsLengthForKey + * + * @uses \Lcobucci\JWT\Signer\Ecdsa::__construct + */ + public function minimumBitsLengthForKeyMustBeCorrect(): void + { + self::assertSame(224, $this->getSigner()->minimumBitsLengthForKey()); + } + private function getSigner(): Sha256 { return new Sha256($this->createMock(SignatureConverter::class)); diff --git a/test/unit/Signer/Ecdsa/Sha384Test.php b/test/unit/Signer/Ecdsa/Sha384Test.php index 43cc100b..26ef3e2a 100644 --- a/test/unit/Signer/Ecdsa/Sha384Test.php +++ b/test/unit/Signer/Ecdsa/Sha384Test.php @@ -61,6 +61,18 @@ public function keyLengthMustBeCorrect(): void self::assertSame(96, $this->getSigner()->keyLength()); } + /** + * @test + * + * @covers ::minimumBitsLengthForKey + * + * @uses \Lcobucci\JWT\Signer\Ecdsa::__construct + */ + public function minimumBitsLengthForKeyMustBeCorrect(): void + { + self::assertSame(224, $this->getSigner()->minimumBitsLengthForKey()); + } + private function getSigner(): Sha384 { return new Sha384($this->createMock(SignatureConverter::class)); diff --git a/test/unit/Signer/Ecdsa/Sha512Test.php b/test/unit/Signer/Ecdsa/Sha512Test.php index 87bb000a..967d433f 100644 --- a/test/unit/Signer/Ecdsa/Sha512Test.php +++ b/test/unit/Signer/Ecdsa/Sha512Test.php @@ -61,6 +61,18 @@ public function keyLengthMustBeCorrect(): void self::assertSame(132, $this->getSigner()->keyLength()); } + /** + * @test + * + * @covers ::minimumBitsLengthForKey + * + * @uses \Lcobucci\JWT\Signer\Ecdsa::__construct + */ + public function minimumBitsLengthForKeyMustBeCorrect(): void + { + self::assertSame(224, $this->getSigner()->minimumBitsLengthForKey()); + } + private function getSigner(): Sha512 { return new Sha512($this->createMock(SignatureConverter::class)); diff --git a/test/unit/Signer/Ecdsa/UnsafeSha256Test.php b/test/unit/Signer/Ecdsa/UnsafeSha256Test.php new file mode 100644 index 00000000..fc65ff0b --- /dev/null +++ b/test/unit/Signer/Ecdsa/UnsafeSha256Test.php @@ -0,0 +1,80 @@ +getSigner()->algorithmId()); + } + + /** + * @test + * + * @covers ::algorithm + * + * @uses \Lcobucci\JWT\Signer\UnsafeEcdsa + */ + public function algorithmMustBeCorrect(): void + { + self::assertSame(OPENSSL_ALGO_SHA256, $this->getSigner()->algorithm()); + } + + /** + * @test + * + * @covers ::keyLength + * + * @uses \Lcobucci\JWT\Signer\UnsafeEcdsa + */ + public function keyLengthMustBeCorrect(): void + { + self::assertSame(64, $this->getSigner()->keyLength()); + } + + /** + * @test + * + * @covers ::minimumBitsLengthForKey + * + * @uses \Lcobucci\JWT\Signer\UnsafeEcdsa::__construct + */ + public function minimumBitsLengthForKeyMustBeCorrect(): void + { + self::assertSame(1, $this->getSigner()->minimumBitsLengthForKey()); + } + + private function getSigner(): UnsafeSha256 + { + return new UnsafeSha256($this->createMock(SignatureConverter::class)); + } +} diff --git a/test/unit/Signer/Ecdsa/UnsafeSha384Test.php b/test/unit/Signer/Ecdsa/UnsafeSha384Test.php new file mode 100644 index 00000000..8dd86a26 --- /dev/null +++ b/test/unit/Signer/Ecdsa/UnsafeSha384Test.php @@ -0,0 +1,80 @@ +getSigner()->algorithmId()); + } + + /** + * @test + * + * @covers ::algorithm + * + * @uses \Lcobucci\JWT\Signer\UnsafeEcdsa + */ + public function algorithmMustBeCorrect(): void + { + self::assertSame(OPENSSL_ALGO_SHA384, $this->getSigner()->algorithm()); + } + + /** + * @test + * + * @covers ::keyLength + * + * @uses \Lcobucci\JWT\Signer\UnsafeEcdsa + */ + public function keyLengthMustBeCorrect(): void + { + self::assertSame(96, $this->getSigner()->keyLength()); + } + + /** + * @test + * + * @covers ::minimumBitsLengthForKey + * + * @uses \Lcobucci\JWT\Signer\UnsafeEcdsa::__construct + */ + public function minimumBitsLengthForKeyMustBeCorrect(): void + { + self::assertSame(1, $this->getSigner()->minimumBitsLengthForKey()); + } + + private function getSigner(): UnsafeSha384 + { + return new UnsafeSha384($this->createMock(SignatureConverter::class)); + } +} diff --git a/test/unit/Signer/Ecdsa/UnsafeSha512Test.php b/test/unit/Signer/Ecdsa/UnsafeSha512Test.php new file mode 100644 index 00000000..947a6de1 --- /dev/null +++ b/test/unit/Signer/Ecdsa/UnsafeSha512Test.php @@ -0,0 +1,80 @@ +getSigner()->algorithmId()); + } + + /** + * @test + * + * @covers ::algorithm + * + * @uses \Lcobucci\JWT\Signer\UnsafeEcdsa + */ + public function algorithmMustBeCorrect(): void + { + self::assertSame(OPENSSL_ALGO_SHA512, $this->getSigner()->algorithm()); + } + + /** + * @test + * + * @covers ::keyLength + * + * @uses \Lcobucci\JWT\Signer\UnsafeEcdsa + */ + public function keyLengthMustBeCorrect(): void + { + self::assertSame(132, $this->getSigner()->keyLength()); + } + + /** + * @test + * + * @covers ::minimumBitsLengthForKey + * + * @uses \Lcobucci\JWT\Signer\UnsafeEcdsa::__construct + */ + public function minimumBitsLengthForKeyMustBeCorrect(): void + { + self::assertSame(1, $this->getSigner()->minimumBitsLengthForKey()); + } + + private function getSigner(): UnsafeSha512 + { + return new UnsafeSha512($this->createMock(SignatureConverter::class)); + } +} diff --git a/test/unit/Signer/EcdsaTest.php b/test/unit/Signer/EcdsaTest.php index eb9c9580..e65942a2 100644 --- a/test/unit/Signer/EcdsaTest.php +++ b/test/unit/Signer/EcdsaTest.php @@ -51,11 +51,11 @@ private function getSigner(): Ecdsa * * @covers ::sign * @covers ::keyType + * @covers \Lcobucci\JWT\Signer\Ecdsa::minimumBitsLengthForKey * @covers \Lcobucci\JWT\Signer\Ecdsa\MultibyteStringConverter * @covers \Lcobucci\JWT\Signer\OpenSSL * * @uses \Lcobucci\JWT\Signer\Ecdsa::__construct - * @uses \Lcobucci\JWT\Signer\Key\LocalFileReference * @uses \Lcobucci\JWT\Signer\Key\InMemory */ public function signShouldReturnTheAHashBasedOnTheOpenSslSignature(): void @@ -79,6 +79,30 @@ public function signShouldReturnTheAHashBasedOnTheOpenSslSignature(): void ); } + /** + * @test + * + * @requires extension openssl < 3.0 + * + * @covers ::sign + * @covers ::keyType + * @covers \Lcobucci\JWT\Signer\Ecdsa::minimumBitsLengthForKey + * @covers \Lcobucci\JWT\Signer\OpenSSL + * @covers \Lcobucci\JWT\Signer\InvalidKeyProvided + * + * @uses \Lcobucci\JWT\Signer\Ecdsa::__construct + * @uses \Lcobucci\JWT\Signer\Key\InMemory + */ + public function signShouldRaiseAnExceptionWhenKeyLengthIsBelowMinimum(): void + { + $signer = $this->getSigner(); + + $this->expectException(InvalidKeyProvided::class); + $this->expectExceptionMessage('Key provided is shorter than 224 bits, only 161 bits provided'); + + $signer->sign('testing', self::$ecdsaKeys['private_short']); + } + /** * @test * @@ -88,7 +112,7 @@ public function signShouldReturnTheAHashBasedOnTheOpenSslSignature(): void * @covers \Lcobucci\JWT\Signer\OpenSSL * * @uses \Lcobucci\JWT\Signer\Ecdsa::__construct - * @uses \Lcobucci\JWT\Signer\Key\LocalFileReference + * @uses \Lcobucci\JWT\Signer\Ecdsa::minimumBitsLengthForKey * @uses \Lcobucci\JWT\Signer\Key\InMemory */ public function verifyShouldDelegateToEcdsaSignerUsingPublicKey(): void diff --git a/test/unit/Signer/Hmac/Sha256Test.php b/test/unit/Signer/Hmac/Sha256Test.php index 51d84e8d..80362160 100644 --- a/test/unit/Signer/Hmac/Sha256Test.php +++ b/test/unit/Signer/Hmac/Sha256Test.php @@ -35,12 +35,12 @@ public function algorithmMustBeCorrect(): void /** * @test * - * @covers ::minimumBytesLengthForKey + * @covers ::minimumBitsLengthForKey */ - public function minimumBytesLengthForKeyMustBeCorrect(): void + public function minimumBitsLengthForKeyMustBeCorrect(): void { $signer = new Sha256(); - self::assertSame(32, $signer->minimumBytesLengthForKey()); + self::assertSame(256, $signer->minimumBitsLengthForKey()); } } diff --git a/test/unit/Signer/Hmac/Sha384Test.php b/test/unit/Signer/Hmac/Sha384Test.php index 9bc01805..9c47f459 100644 --- a/test/unit/Signer/Hmac/Sha384Test.php +++ b/test/unit/Signer/Hmac/Sha384Test.php @@ -35,12 +35,12 @@ public function algorithmMustBeCorrect(): void /** * @test * - * @covers ::minimumBytesLengthForKey + * @covers ::minimumBitsLengthForKey */ - public function minimumBytesLengthForKeyMustBeCorrect(): void + public function minimumBitsLengthForKeyMustBeCorrect(): void { $signer = new Sha384(); - self::assertSame(48, $signer->minimumBytesLengthForKey()); + self::assertSame(384, $signer->minimumBitsLengthForKey()); } } diff --git a/test/unit/Signer/Hmac/Sha512Test.php b/test/unit/Signer/Hmac/Sha512Test.php index d0bf3ad2..3ccdcc1f 100644 --- a/test/unit/Signer/Hmac/Sha512Test.php +++ b/test/unit/Signer/Hmac/Sha512Test.php @@ -35,12 +35,12 @@ public function algorithmMustBeCorrect(): void /** * @test * - * @covers ::minimumBytesLengthForKey + * @covers ::minimumBitsLengthForKey */ - public function minimumBytesLengthForKeyMustBeCorrect(): void + public function minimumBitsLengthForKeyMustBeCorrect(): void { $signer = new Sha512(); - self::assertSame(64, $signer->minimumBytesLengthForKey()); + self::assertSame(512, $signer->minimumBitsLengthForKey()); } } diff --git a/test/unit/Signer/Hmac/UnsafeSha256Test.php b/test/unit/Signer/Hmac/UnsafeSha256Test.php index f1af75a9..010e4dd2 100644 --- a/test/unit/Signer/Hmac/UnsafeSha256Test.php +++ b/test/unit/Signer/Hmac/UnsafeSha256Test.php @@ -35,12 +35,12 @@ public function algorithmMustBeCorrect(): void /** * @test * - * @covers ::minimumBytesLengthForKey + * @covers ::minimumBitsLengthForKey */ - public function minimumBytesLengthForKeyIsWhatItIs(): void + public function minimumBitsLengthForKeyIsWhatItIs(): void { $signer = new UnsafeSha256(); - self::assertSame(1, $signer->minimumBytesLengthForKey()); + self::assertSame(1, $signer->minimumBitsLengthForKey()); } } diff --git a/test/unit/Signer/Hmac/UnsafeSha384Test.php b/test/unit/Signer/Hmac/UnsafeSha384Test.php index b75a76f7..c1a62b62 100644 --- a/test/unit/Signer/Hmac/UnsafeSha384Test.php +++ b/test/unit/Signer/Hmac/UnsafeSha384Test.php @@ -35,12 +35,12 @@ public function algorithmMustBeCorrect(): void /** * @test * - * @covers ::minimumBytesLengthForKey + * @covers ::minimumBitsLengthForKey */ - public function minimumBytesLengthForKeyIsWhatItIs(): void + public function minimumBitsLengthForKeyIsWhatItIs(): void { $signer = new UnsafeSha384(); - self::assertSame(1, $signer->minimumBytesLengthForKey()); + self::assertSame(1, $signer->minimumBitsLengthForKey()); } } diff --git a/test/unit/Signer/Hmac/UnsafeSha512Test.php b/test/unit/Signer/Hmac/UnsafeSha512Test.php index f92d1796..5c2c867a 100644 --- a/test/unit/Signer/Hmac/UnsafeSha512Test.php +++ b/test/unit/Signer/Hmac/UnsafeSha512Test.php @@ -35,12 +35,12 @@ public function algorithmMustBeCorrect(): void /** * @test * - * @covers ::minimumBytesLengthForKey + * @covers ::minimumBitsLengthForKey */ - public function minimumBytesLengthForKeyIsWhatItIs(): void + public function minimumBitsLengthForKeyIsWhatItIs(): void { $signer = new UnsafeSha512(); - self::assertSame(1, $signer->minimumBytesLengthForKey()); + self::assertSame(1, $signer->minimumBitsLengthForKey()); } } diff --git a/test/unit/Signer/HmacTest.php b/test/unit/Signer/HmacTest.php index d170a621..f84ce782 100644 --- a/test/unit/Signer/HmacTest.php +++ b/test/unit/Signer/HmacTest.php @@ -29,8 +29,8 @@ public function initializeDependencies(): void ->willReturn('sha256'); $this->signer->expects(self::any()) - ->method('minimumBytesLengthForKey') - ->willReturn(3); + ->method('minimumBitsLengthForKey') + ->willReturn(24); } /** @@ -88,7 +88,7 @@ public function verifyShouldReturnFalseWhenExpectedHashWasNotCreatedWithSameInfo public function keyMustFulfillMinimumLengthRequirement(): void { $this->expectException(InvalidKeyProvided::class); - $this->expectExceptionMessage('Key provided is shorter than 3 bytes, only 2 bytes provided'); + $this->expectExceptionMessage('Key provided is shorter than 24 bits, only 16 bits provided'); $this->signer->sign('test', InMemory::plainText('12')); } diff --git a/test/unit/Signer/Rsa/Sha256Test.php b/test/unit/Signer/Rsa/Sha256Test.php index 78911ad4..b84774f8 100644 --- a/test/unit/Signer/Rsa/Sha256Test.php +++ b/test/unit/Signer/Rsa/Sha256Test.php @@ -33,4 +33,16 @@ public function algorithmMustBeCorrect(): void self::assertEquals(OPENSSL_ALGO_SHA256, $signer->algorithm()); } + + /** + * @test + * + * @covers ::minimumBitsLengthForKey + */ + public function minimumBitsLengthForKeyMustBeCorrect(): void + { + $signer = new Sha256(); + + self::assertSame(2048, $signer->minimumBitsLengthForKey()); + } } diff --git a/test/unit/Signer/Rsa/Sha384Test.php b/test/unit/Signer/Rsa/Sha384Test.php index 41ea82be..ba4a292a 100644 --- a/test/unit/Signer/Rsa/Sha384Test.php +++ b/test/unit/Signer/Rsa/Sha384Test.php @@ -33,4 +33,16 @@ public function algorithmMustBeCorrect(): void self::assertEquals(OPENSSL_ALGO_SHA384, $signer->algorithm()); } + + /** + * @test + * + * @covers ::minimumBitsLengthForKey + */ + public function minimumBitsLengthForKeyMustBeCorrect(): void + { + $signer = new Sha384(); + + self::assertSame(2048, $signer->minimumBitsLengthForKey()); + } } diff --git a/test/unit/Signer/Rsa/Sha512Test.php b/test/unit/Signer/Rsa/Sha512Test.php index 76594576..d26530a5 100644 --- a/test/unit/Signer/Rsa/Sha512Test.php +++ b/test/unit/Signer/Rsa/Sha512Test.php @@ -33,4 +33,16 @@ public function algorithmMustBeCorrect(): void self::assertEquals(OPENSSL_ALGO_SHA512, $signer->algorithm()); } + + /** + * @test + * + * @covers ::minimumBitsLengthForKey + */ + public function minimumBitsLengthForKeyMustBeCorrect(): void + { + $signer = new Sha512(); + + self::assertSame(2048, $signer->minimumBitsLengthForKey()); + } } diff --git a/test/unit/Signer/Rsa/UnsafeSha256Test.php b/test/unit/Signer/Rsa/UnsafeSha256Test.php new file mode 100644 index 00000000..71320292 --- /dev/null +++ b/test/unit/Signer/Rsa/UnsafeSha256Test.php @@ -0,0 +1,48 @@ +algorithmId()); + } + + /** + * @test + * + * @covers ::algorithm + */ + public function algorithmMustBeCorrect(): void + { + $signer = new UnsafeSha256(); + + self::assertEquals(OPENSSL_ALGO_SHA256, $signer->algorithm()); + } + + /** + * @test + * + * @covers ::minimumBitsLengthForKey + */ + public function minimumBitsLengthForKeyMustBeCorrect(): void + { + $signer = new UnsafeSha256(); + + self::assertSame(1, $signer->minimumBitsLengthForKey()); + } +} diff --git a/test/unit/Signer/Rsa/UnsafeSha384Test.php b/test/unit/Signer/Rsa/UnsafeSha384Test.php new file mode 100644 index 00000000..6e3f0e55 --- /dev/null +++ b/test/unit/Signer/Rsa/UnsafeSha384Test.php @@ -0,0 +1,48 @@ +algorithmId()); + } + + /** + * @test + * + * @covers ::algorithm + */ + public function algorithmMustBeCorrect(): void + { + $signer = new UnsafeSha384(); + + self::assertEquals(OPENSSL_ALGO_SHA384, $signer->algorithm()); + } + + /** + * @test + * + * @covers ::minimumBitsLengthForKey + */ + public function minimumBitsLengthForKeyMustBeCorrect(): void + { + $signer = new UnsafeSha384(); + + self::assertSame(1, $signer->minimumBitsLengthForKey()); + } +} diff --git a/test/unit/Signer/Rsa/UnsafeSha512Test.php b/test/unit/Signer/Rsa/UnsafeSha512Test.php new file mode 100644 index 00000000..f80ca802 --- /dev/null +++ b/test/unit/Signer/Rsa/UnsafeSha512Test.php @@ -0,0 +1,48 @@ +algorithmId()); + } + + /** + * @test + * + * @covers ::algorithm + */ + public function algorithmMustBeCorrect(): void + { + $signer = new UnsafeSha512(); + + self::assertEquals(OPENSSL_ALGO_SHA512, $signer->algorithm()); + } + + /** + * @test + * + * @covers ::minimumBitsLengthForKey + */ + public function minimumBitsLengthForKeyMustBeCorrect(): void + { + $signer = new UnsafeSha512(); + + self::assertSame(1, $signer->minimumBitsLengthForKey()); + } +} diff --git a/test/unit/Signer/RsaTest.php b/test/unit/Signer/RsaTest.php index f9bda038..20ba8990 100644 --- a/test/unit/Signer/RsaTest.php +++ b/test/unit/Signer/RsaTest.php @@ -29,7 +29,7 @@ final class RsaTest extends TestCase * @covers ::keyType * @covers \Lcobucci\JWT\Signer\OpenSSL * - * @uses \Lcobucci\JWT\Signer\Key\LocalFileReference + * @uses \Lcobucci\JWT\Signer\Rsa::minimumBitsLengthForKey * @uses \Lcobucci\JWT\Signer\Key\InMemory */ public function signShouldReturnAValidOpensslSignature(): void @@ -49,47 +49,39 @@ public function signShouldReturnAValidOpensslSignature(): void * @test * * @covers ::sign - * @covers ::keyType * @covers \Lcobucci\JWT\Signer\OpenSSL - * @covers \Lcobucci\JWT\Signer\CannotSignPayload + * @covers \Lcobucci\JWT\Signer\InvalidKeyProvided * * @uses \Lcobucci\JWT\Signer\Key\InMemory */ - public function signShouldRaiseAnExceptionWhenKeyIsInvalid(): void + public function signShouldRaiseAnExceptionWhenKeyIsNotParseable(): void { - $key = <<getSigner(); - $this->expectException(CannotSignPayload::class); - $this->expectExceptionMessage('There was an error while creating the signature: error:'); + $this->expectException(InvalidKeyProvided::class); + $this->expectExceptionMessage('It was not possible to parse your key, reason: error:'); - $signer->sign('testing', InMemory::plainText($key)); + $signer->sign('testing', InMemory::plainText('blablabla')); } /** * @test * * @covers ::sign + * @covers ::keyType * @covers \Lcobucci\JWT\Signer\OpenSSL * @covers \Lcobucci\JWT\Signer\InvalidKeyProvided * * @uses \Lcobucci\JWT\Signer\Key\InMemory */ - public function signShouldRaiseAnExceptionWhenKeyIsNotParseable(): void + public function signShouldRaiseAnExceptionWhenKeyTypeIsNotRsa(): void { $signer = $this->getSigner(); $this->expectException(InvalidKeyProvided::class); - $this->expectExceptionMessage('It was not possible to parse your key, reason: error:'); + $this->expectExceptionMessage('This key is not compatible with this signer'); - $signer->sign('testing', InMemory::plainText('blablabla')); + $signer->sign('testing', self::$ecdsaKeys['private']); } /** @@ -97,20 +89,20 @@ public function signShouldRaiseAnExceptionWhenKeyIsNotParseable(): void * * @covers ::sign * @covers ::keyType + * @covers \Lcobucci\JWT\Signer\Rsa::minimumBitsLengthForKey * @covers \Lcobucci\JWT\Signer\OpenSSL * @covers \Lcobucci\JWT\Signer\InvalidKeyProvided * - * @uses \Lcobucci\JWT\Signer\Key\LocalFileReference * @uses \Lcobucci\JWT\Signer\Key\InMemory */ - public function signShouldRaiseAnExceptionWhenKeyTypeIsNotRsa(): void + public function signShouldRaiseAnExceptionWhenKeyLengthIsBelowMinimum(): void { $signer = $this->getSigner(); $this->expectException(InvalidKeyProvided::class); - $this->expectExceptionMessage('This key is not compatible with this signer'); + $this->expectExceptionMessage('Key provided is shorter than 2048 bits, only 512 bits provided'); - $signer->sign('testing', self::$ecdsaKeys['private']); + $signer->sign('testing', self::$rsaKeys['private_short']); } /** @@ -120,7 +112,7 @@ public function signShouldRaiseAnExceptionWhenKeyTypeIsNotRsa(): void * @covers ::keyType * @covers \Lcobucci\JWT\Signer\OpenSSL * - * @uses \Lcobucci\JWT\Signer\Key\LocalFileReference + * @uses \Lcobucci\JWT\Signer\Rsa::minimumBitsLengthForKey * @uses \Lcobucci\JWT\Signer\Key\InMemory */ public function verifyShouldReturnTrueWhenSignatureIsValid(): void @@ -163,7 +155,6 @@ public function verifyShouldRaiseAnExceptionWhenKeyIsNotParseable(): void * @covers \Lcobucci\JWT\Signer\OpenSSL * @covers \Lcobucci\JWT\Signer\InvalidKeyProvided * - * @uses \Lcobucci\JWT\Signer\Key\LocalFileReference * @uses \Lcobucci\JWT\Signer\Key\InMemory */ public function verifyShouldRaiseAnExceptionWhenKeyTypeIsNotRsa(): void diff --git a/test/unit/Signer/UnsafeEcdsaTest.php b/test/unit/Signer/UnsafeEcdsaTest.php new file mode 100644 index 00000000..eabaefb3 --- /dev/null +++ b/test/unit/Signer/UnsafeEcdsaTest.php @@ -0,0 +1,139 @@ +pointsManipulator = new MultibyteStringConverter(); + } + + private function getSigner(): UnsafeEcdsa + { + $signer = $this->getMockForAbstractClass(UnsafeEcdsa::class, [$this->pointsManipulator]); + + $signer->method('algorithm') + ->willReturn(OPENSSL_ALGO_SHA256); + + $signer->method('algorithmId') + ->willReturn('ES256'); + + $signer->method('keyLength') + ->willReturn(64); + + return $signer; + } + + /** + * @test + * + * @covers ::sign + * @covers ::keyType + * @covers \Lcobucci\JWT\Signer\UnsafeEcdsa::minimumBitsLengthForKey + * @covers \Lcobucci\JWT\Signer\Ecdsa\MultibyteStringConverter + * @covers \Lcobucci\JWT\Signer\OpenSSL + * + * @uses \Lcobucci\JWT\Signer\UnsafeEcdsa::__construct + * @uses \Lcobucci\JWT\Signer\Key\InMemory + */ + public function signShouldReturnTheAHashBasedOnTheOpenSslSignature(): void + { + $payload = 'testing'; + + $signer = $this->getSigner(); + $signature = $signer->sign($payload, self::$ecdsaKeys['private']); + + $publicKey = openssl_pkey_get_public(self::$ecdsaKeys['public1']->contents()); + assert(is_resource($publicKey) || $publicKey instanceof OpenSSLAsymmetricKey); + + self::assertSame( + 1, + openssl_verify( + $payload, + $this->pointsManipulator->toAsn1($signature, $signer->keyLength()), + $publicKey, + OPENSSL_ALGO_SHA256 + ) + ); + } + + /** + * @test + * + * @requires extension openssl < 3.0 + * + * @covers ::sign + * @covers ::keyType + * @covers \Lcobucci\JWT\Signer\UnsafeEcdsa::minimumBitsLengthForKey + * @covers \Lcobucci\JWT\Signer\OpenSSL + * @covers \Lcobucci\JWT\Signer\InvalidKeyProvided + * + * @uses \Lcobucci\JWT\Signer\Ecdsa\MultibyteStringConverter + * @uses \Lcobucci\JWT\Signer\UnsafeEcdsa::__construct + * @uses \Lcobucci\JWT\Signer\UnsafeEcdsa::verify + * @uses \Lcobucci\JWT\Signer\Key\InMemory + */ + public function signShouldAcceptAKeyLengthBelowMinimum(): void + { + $signer = $this->getSigner(); + + $payload = 'testing'; + $signature = $signer->sign($payload, self::$ecdsaKeys['private_short']); + + self::assertTrue($signer->verify($signature, $payload, self::$ecdsaKeys['public_short'])); + } + + /** + * @test + * + * @covers ::verify + * @covers ::keyType + * @covers \Lcobucci\JWT\Signer\Ecdsa\MultibyteStringConverter + * @covers \Lcobucci\JWT\Signer\OpenSSL + * + * @uses \Lcobucci\JWT\Signer\UnsafeEcdsa::__construct + * @uses \Lcobucci\JWT\Signer\UnsafeEcdsa::minimumBitsLengthForKey + * @uses \Lcobucci\JWT\Signer\Key\InMemory + */ + public function verifyShouldDelegateToEcdsaSignerUsingPublicKey(): void + { + $payload = 'testing'; + $privateKey = openssl_pkey_get_private(self::$ecdsaKeys['private']->contents()); + assert(is_resource($privateKey) || $privateKey instanceof OpenSSLAsymmetricKey); + + $signature = ''; + openssl_sign($payload, $signature, $privateKey, OPENSSL_ALGO_SHA256); + + $signer = $this->getSigner(); + + self::assertTrue( + $signer->verify( + $this->pointsManipulator->fromAsn1($signature, $signer->keyLength()), + $payload, + self::$ecdsaKeys['public1'] + ) + ); + } +} diff --git a/test/unit/Signer/UnsafeRsaTest.php b/test/unit/Signer/UnsafeRsaTest.php new file mode 100644 index 00000000..a99e9b06 --- /dev/null +++ b/test/unit/Signer/UnsafeRsaTest.php @@ -0,0 +1,212 @@ +getSigner(); + $signature = $signer->sign($payload, self::$rsaKeys['private']); + + $publicKey = openssl_pkey_get_public(self::$rsaKeys['public']->contents()); + assert(is_resource($publicKey) || $publicKey instanceof OpenSSLAsymmetricKey); + + self::assertSame(1, openssl_verify($payload, $signature, $publicKey, OPENSSL_ALGO_SHA256)); + } + + /** + * @test + * + * @covers ::sign + * @covers ::keyType + * @covers \Lcobucci\JWT\Signer\OpenSSL + * @covers \Lcobucci\JWT\Signer\CannotSignPayload + * + * @uses \Lcobucci\JWT\Signer\UnsafeRsa::minimumBitsLengthForKey + * @uses \Lcobucci\JWT\Signer\Key\InMemory + */ + public function signShouldRaiseAnExceptionWhenKeyIsInvalid(): void + { + $key = <<getSigner(); + + $this->expectException(CannotSignPayload::class); + $this->expectExceptionMessage('There was an error while creating the signature: error:'); + + $signer->sign('testing', InMemory::plainText($key)); + } + + /** + * @test + * + * @covers ::sign + * @covers \Lcobucci\JWT\Signer\OpenSSL + * @covers \Lcobucci\JWT\Signer\InvalidKeyProvided + * + * @uses \Lcobucci\JWT\Signer\Key\InMemory + */ + public function signShouldRaiseAnExceptionWhenKeyIsNotParseable(): void + { + $signer = $this->getSigner(); + + $this->expectException(InvalidKeyProvided::class); + $this->expectExceptionMessage('It was not possible to parse your key, reason: error:'); + + $signer->sign('testing', InMemory::plainText('blablabla')); + } + + /** + * @test + * + * @covers ::sign + * @covers ::keyType + * @covers \Lcobucci\JWT\Signer\OpenSSL + * @covers \Lcobucci\JWT\Signer\InvalidKeyProvided + * + * @uses \Lcobucci\JWT\Signer\Key\InMemory + */ + public function signShouldRaiseAnExceptionWhenKeyTypeIsNotRsa(): void + { + $signer = $this->getSigner(); + + $this->expectException(InvalidKeyProvided::class); + $this->expectExceptionMessage('This key is not compatible with this signer'); + + $signer->sign('testing', self::$ecdsaKeys['private']); + } + + /** + * @test + * + * @covers ::sign + * @covers ::keyType + * @covers \Lcobucci\JWT\Signer\UnsafeRsa::minimumBitsLengthForKey + * @covers \Lcobucci\JWT\Signer\OpenSSL + * @covers \Lcobucci\JWT\Signer\InvalidKeyProvided + * + * @uses \Lcobucci\JWT\Signer\Key\InMemory + * @uses \Lcobucci\JWT\Signer\UnsafeRsa::verify + */ + public function signShouldAcceptAKeyLengthBelowMinimum(): void + { + $signer = $this->getSigner(); + + $payload = 'testing'; + $signature = $signer->sign($payload, self::$rsaKeys['private_short']); + + self::assertTrue($signer->verify($signature, $payload, self::$rsaKeys['public_short'])); + } + + /** + * @test + * + * @covers ::verify + * @covers ::keyType + * @covers \Lcobucci\JWT\Signer\OpenSSL + * + * @uses \Lcobucci\JWT\Signer\UnsafeRsa::minimumBitsLengthForKey + * @uses \Lcobucci\JWT\Signer\Key\InMemory + */ + public function verifyShouldReturnTrueWhenSignatureIsValid(): void + { + $payload = 'testing'; + $privateKey = openssl_pkey_get_private(self::$rsaKeys['private']->contents()); + assert(is_resource($privateKey) || $privateKey instanceof OpenSSLAsymmetricKey); + + $signature = ''; + openssl_sign($payload, $signature, $privateKey, OPENSSL_ALGO_SHA256); + + $signer = $this->getSigner(); + + self::assertTrue($signer->verify($signature, $payload, self::$rsaKeys['public'])); + } + + /** + * @test + * + * @covers ::verify + * @covers \Lcobucci\JWT\Signer\OpenSSL + * @covers \Lcobucci\JWT\Signer\InvalidKeyProvided + * + * @uses \Lcobucci\JWT\Signer\Key\InMemory + */ + public function verifyShouldRaiseAnExceptionWhenKeyIsNotParseable(): void + { + $signer = $this->getSigner(); + + $this->expectException(InvalidKeyProvided::class); + $this->expectExceptionMessage('It was not possible to parse your key'); + + $signer->verify('testing', 'testing', InMemory::plainText('blablabla')); + } + + /** + * @test + * + * @covers ::verify + * @covers \Lcobucci\JWT\Signer\OpenSSL + * @covers \Lcobucci\JWT\Signer\InvalidKeyProvided + * + * @uses \Lcobucci\JWT\Signer\Key\InMemory + */ + public function verifyShouldRaiseAnExceptionWhenKeyTypeIsNotRsa(): void + { + $signer = $this->getSigner(); + + $this->expectException(InvalidKeyProvided::class); + $this->expectExceptionMessage('It was not possible to parse your key'); + + $signer->verify('testing', 'testing', self::$ecdsaKeys['private']); + } + + private function getSigner(): UnsafeRsa + { + $signer = $this->getMockForAbstractClass(UnsafeRsa::class); + + $signer->method('algorithm') + ->willReturn(OPENSSL_ALGO_SHA256); + + $signer->method('algorithmId') + ->willReturn('RS256'); + + return $signer; + } +}