diff --git a/vicephp/Virtue-JWT/src/JWT/Algorithms/OpenSSLSign.php b/vicephp/Virtue-JWT/src/JWT/Algorithms/OpenSSLSign.php index 9fba788..92d0b0c 100644 --- a/vicephp/Virtue-JWT/src/JWT/Algorithms/OpenSSLSign.php +++ b/vicephp/Virtue-JWT/src/JWT/Algorithms/OpenSSLSign.php @@ -3,9 +3,9 @@ namespace Virtue\JWT\Algorithms; use Virtue\Encoding\ASN1; -use Virtue\JWK\AsymmetricKey; use Virtue\JWK\Key\OpenSSL\Exportable; use Virtue\JWT\Algorithm; +use Virtue\JWT\OpenSslException; use Virtue\JWT\SignFailed; use Virtue\JWT\SignsToken; use Webmozart\Assert\Assert; @@ -50,7 +50,7 @@ public function sign(string $msg): string } if (!$private = \openssl_pkey_get_private($this->private->asPem(), $this->private->passphrase())) { - throw new SignFailed('Key or passphrase are invalid.'); + throw new SignFailed('Key or passphrase are invalid.', 0, OpenSslException::collectErrors()); } if (!isset($this->supported[$this->name])) { @@ -85,7 +85,7 @@ public function sign(string $msg): string \openssl_pkey_free($private); } if (!$success) { - throw new SignFailed('OpenSSL error: ' . \openssl_error_string()); + throw new SignFailed('OpenSSL error occurred during signing.', 0, OpenSslException::collectErrors()); } else { return $signature; } diff --git a/vicephp/Virtue-JWT/src/JWT/Algorithms/OpenSSLVerify.php b/vicephp/Virtue-JWT/src/JWT/Algorithms/OpenSSLVerify.php index 3080eca..721973e 100644 --- a/vicephp/Virtue-JWT/src/JWT/Algorithms/OpenSSLVerify.php +++ b/vicephp/Virtue-JWT/src/JWT/Algorithms/OpenSSLVerify.php @@ -7,6 +7,7 @@ use Virtue\JWK\Key\EdDSA; use Virtue\JWT\Algorithm; use Virtue\JWT\Base64Url; +use Virtue\JWT\OpenSslException; use Virtue\JWT\Token; use Virtue\JWT\VerificationFailed; use Virtue\JWT\VerifiesToken; @@ -62,7 +63,11 @@ public function verify(Token $token): void } if (!$public = \openssl_pkey_get_public($this->public->asPem())) { - throw new VerificationFailed('Key is invalid.', VerificationFailed::ON_SIGNATURE); + throw new VerificationFailed( + 'Key is invalid.', + VerificationFailed::ON_SIGNATURE, + OpenSslException::collectErrors() + ); } $ecPadding = [ 'ES256' => 32, @@ -84,10 +89,22 @@ public function verify(Token $token): void } if ($success === 1) { return; - } elseif ($success === 0) { - throw new VerificationFailed('Could not verify signature.', VerificationFailed::ON_SIGNATURE); } - throw new VerificationFailed('OpenSSL error: ' . \openssl_error_string(), VerificationFailed::ON_SIGNATURE); + $opensslException = OpenSslException::collectErrors(); + + if ($success === 0) { + throw new VerificationFailed( + 'Could not verify signature.', + VerificationFailed::ON_SIGNATURE, + $opensslException + ); + } + + throw new VerificationFailed( + 'OpenSSL error occurred during signature verification.', + VerificationFailed::ON_SIGNATURE, + $opensslException + ); } } diff --git a/vicephp/Virtue-JWT/src/JWT/OpenSslException.php b/vicephp/Virtue-JWT/src/JWT/OpenSslException.php new file mode 100644 index 0000000..0574642 --- /dev/null +++ b/vicephp/Virtue-JWT/src/JWT/OpenSslException.php @@ -0,0 +1,42 @@ +errors = $errors; + $message = 'OpenSSL error(s): ' . implode('; ', $errors); + parent::__construct($message, $code, $previous); + } + + /** + * @return string[] + */ + public function getErrors(): array + { + return $this->errors; + } + + /** + * @return self + */ + public static function collectErrors(): self + { + $errors = []; + while ($error = \openssl_error_string()) { + $errors[] = $error; + } + return new self($errors); + } +} diff --git a/vicephp/Virtue-JWT/tests/JWT/OpenSslExceptionTest.php b/vicephp/Virtue-JWT/tests/JWT/OpenSslExceptionTest.php new file mode 100644 index 0000000..084bbf0 --- /dev/null +++ b/vicephp/Virtue-JWT/tests/JWT/OpenSslExceptionTest.php @@ -0,0 +1,63 @@ +assertEquals(['Unknown OpenSSL error'], $exception->getErrors()); + $this->assertEquals('OpenSSL error(s): Unknown OpenSSL error', $exception->getMessage()); + } + + public function testCollectErrorsWithMultipleErrors(): void + { + @\openssl_pkey_get_private('invalid-key-data'); + + $exception = OpenSslException::collectErrors(); + + $errors = $exception->getErrors(); + $this->assertNotEmpty($errors); + $this->assertIsArray($errors); + + $expectedMessage = 'OpenSSL error(s): ' . implode('; ', $errors); + $this->assertEquals($expectedMessage, $exception->getMessage()); + } + + public function testGetErrors(): void + { + @\openssl_pkey_get_private('invalid-key'); + + $exception = OpenSslException::collectErrors(); + $errors = $exception->getErrors(); + + $this->assertIsArray($errors); + $this->assertNotEmpty($errors); + foreach ($errors as $error) { + $this->assertIsString($error); + } + } + + public function testExceptionCanBeUsedAsPrevious(): void + { + $opensslException = OpenSslException::collectErrors(); + $wrappedException = new \RuntimeException('Wrapper exception', 0, $opensslException); + + $this->assertSame($opensslException, $wrappedException->getPrevious()); + $this->assertEquals('OpenSSL error(s): Unknown OpenSSL error', $opensslException->getMessage()); + } +}