diff --git a/app/Access/Oidc/OidcJwtSigningKey.php b/app/Access/Oidc/OidcJwtSigningKey.php index 3dab3e44275..dab94d59da0 100644 --- a/app/Access/Oidc/OidcJwtSigningKey.php +++ b/app/Access/Oidc/OidcJwtSigningKey.php @@ -2,6 +2,7 @@ namespace BookStack\Access\Oidc; +use Illuminate\Support\Facades\Log; use phpseclib3\Crypt\Common\PublicKey; use phpseclib3\Crypt\PublicKeyLoader; use phpseclib3\Crypt\RSA; @@ -63,8 +64,9 @@ protected function loadFromJwkArray(array $jwk) // 'alg' is optional for a JWK, but we will still attempt to validate if // it exists otherwise presume it will be compatible. $alg = $jwk['alg'] ?? null; - if ($jwk['kty'] !== 'RSA' || !(is_null($alg) || $alg === 'RS256')) { - throw new OidcInvalidKeyException("Only RS256 keys are currently supported. Found key using {$alg}"); + $algorithm = OidcJwtSigningKeyAlgorithm::tryFrom($alg ?? OidcJwtSigningKeyAlgorithm::RS256->value); + if ($jwk['kty'] !== 'RSA' || $algorithm === null) { + throw new OidcInvalidKeyException("Only " . OidcJwtSigningKeyAlgorithm::getSupportedAlgorithms() . " keys are currently supported. Found key using {$alg}"); } // 'use' is optional for a JWK but we assume 'sig' where no value exists since that's what @@ -97,7 +99,16 @@ protected function loadFromJwkArray(array $jwk) throw new OidcInvalidKeyException('Key loaded from file path is not an RSA key as expected'); } - $this->key = $key->withPadding(RSA::SIGNATURE_PKCS1); + // apply key-algorithm depending hash + $key = match ($algorithm) { + OidcJwtSigningKeyAlgorithm::RS256 => $key->withHash('sha256'), + OidcJwtSigningKeyAlgorithm::RS512 => $key->withHash('sha512'), + }; + // apply key-algorithm depending padding + $this->key = match ($algorithm) { + OidcJwtSigningKeyAlgorithm::RS256, + OidcJwtSigningKeyAlgorithm::RS512 => $key->withPadding(RSA::SIGNATURE_PKCS1), + }; } /** diff --git a/app/Access/Oidc/OidcJwtSigningKeyAlgorithm.php b/app/Access/Oidc/OidcJwtSigningKeyAlgorithm.php new file mode 100644 index 00000000000..25059ce04a7 --- /dev/null +++ b/app/Access/Oidc/OidcJwtSigningKeyAlgorithm.php @@ -0,0 +1,16 @@ + $enum->value, self::cases())); + } +} diff --git a/app/Access/Oidc/OidcJwtWithClaims.php b/app/Access/Oidc/OidcJwtWithClaims.php index 06c04d81eb7..220c44ce1f8 100644 --- a/app/Access/Oidc/OidcJwtWithClaims.php +++ b/app/Access/Oidc/OidcJwtWithClaims.php @@ -119,8 +119,8 @@ protected function validateTokenStructure(): void */ protected function validateTokenSignature(): void { - if ($this->header['alg'] !== 'RS256') { - throw new OidcInvalidTokenException("Only RS256 signature validation is supported. Token reports using {$this->header['alg']}"); + if (OidcJwtSigningKeyAlgorithm::tryFrom($this->header['alg']) === null) { + throw new OidcInvalidTokenException("Only " . OidcJwtSigningKeyAlgorithm::getSupportedAlgorithms() . " signature validation is supported. Token reports using {$this->header['alg']}"); } $parsedKeys = array_map(function ($key) { diff --git a/app/Access/Oidc/OidcProviderSettings.php b/app/Access/Oidc/OidcProviderSettings.php index 71c3b573421..fc122158961 100644 --- a/app/Access/Oidc/OidcProviderSettings.php +++ b/app/Access/Oidc/OidcProviderSettings.php @@ -158,10 +158,10 @@ protected function loadSettingsFromIssuerDiscovery(ClientInterface $httpClient): protected function filterKeys(array $keys): array { return array_filter($keys, function (array $key) { - $alg = $key['alg'] ?? 'RS256'; + $alg = $key['alg'] ?? OidcJwtSigningKeyAlgorithm::RS256->value; $use = $key['use'] ?? 'sig'; - return $key['kty'] === 'RSA' && $use === 'sig' && $alg === 'RS256'; + return $key['kty'] === 'RSA' && $use === 'sig' && OidcJwtSigningKeyAlgorithm::tryFrom($alg) !== null; }); }