Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions vicephp/Virtue-JWT/src/JWT/Algorithms/OpenSSLSign.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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])) {
Expand Down Expand Up @@ -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;
}
Expand Down
25 changes: 21 additions & 4 deletions vicephp/Virtue-JWT/src/JWT/Algorithms/OpenSSLVerify.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand All @@ -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
);
}
}
42 changes: 42 additions & 0 deletions vicephp/Virtue-JWT/src/JWT/OpenSslException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

namespace Virtue\JWT;

class OpenSslException extends \RuntimeException
{
/** @var string[] */
private $errors;

/**
* @param string[] $errors
*/
private function __construct(array $errors, int $code = 0, ?\Throwable $previous = null)
{
if (empty($errors)) {
$errors = ['Unknown OpenSSL error'];
}
$this->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);
}
}
63 changes: 63 additions & 0 deletions vicephp/Virtue-JWT/tests/JWT/OpenSslExceptionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

namespace Virtue\JWT;

use PHPUnit\Framework\TestCase;

class OpenSslExceptionTest extends TestCase
{
protected function setUp(): void
{
parent::setUp();

// Drain the OpenSSL error queue before each test
while (\openssl_error_string() !== false) {
// Intentionally empty
}
}

public function testCollectErrorsWithNoErrors(): void
{
$exception = OpenSslException::collectErrors();

$this->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());
}
}