'RSA', 'alg' => 'RS256', 'n' => 'abc123...'] * @param array|string $jwkOrKeyPath * @throws OidcInvalidKeyException */ public function __construct($jwkOrKeyPath) { if (is_array($jwkOrKeyPath)) { $this->loadFromJwkArray($jwkOrKeyPath); } else if (is_string($jwkOrKeyPath) && strpos($jwkOrKeyPath, 'file://') === 0) { $this->loadFromPath($jwkOrKeyPath); } else { throw new OidcInvalidKeyException('Unexpected type of key value provided'); } } /** * @throws OidcInvalidKeyException */ protected function loadFromPath(string $path) { try { $this->key = PublicKeyLoader::load( file_get_contents($path) )->withPadding(RSA::SIGNATURE_PKCS1); } catch (\Exception $exception) { throw new OidcInvalidKeyException("Failed to load key from file path with error: {$exception->getMessage()}"); } if (!($this->key instanceof RSA)) { throw new OidcInvalidKeyException("Key loaded from file path is not an RSA key as expected"); } } /** * @throws OidcInvalidKeyException */ protected function loadFromJwkArray(array $jwk) { if ($jwk['alg'] !== 'RS256') { throw new OidcInvalidKeyException("Only RS256 keys are currently supported. Found key using {$jwk['alg']}"); } if (empty($jwk['use'])) { throw new OidcInvalidKeyException('A "use" parameter on the provided key is expected'); } if ($jwk['use'] !== 'sig') { throw new OidcInvalidKeyException("Only signature keys are currently supported. Found key for use {$jwk['use']}"); } if (empty($jwk['e'])) { throw new OidcInvalidKeyException('An "e" parameter on the provided key is expected'); } if (empty($jwk['n'])) { throw new OidcInvalidKeyException('A "n" parameter on the provided key is expected'); } $n = strtr($jwk['n'] ?? '', '-_', '+/'); try { /** @var RSA $key */ $this->key = PublicKeyLoader::load([ 'e' => new BigInteger(base64_decode($jwk['e']), 256), 'n' => new BigInteger(base64_decode($n), 256), ])->withPadding(RSA::SIGNATURE_PKCS1); } catch (\Exception $exception) { throw new OidcInvalidKeyException("Failed to load key from JWK parameters with error: {$exception->getMessage()}"); } } /** * Use this key to sign the given content and return the signature. */ public function verify(string $content, string $signature): bool { return $this->key->verify($content, $signature); } /** * Convert the key to a PEM encoded key string. */ public function toPem(): string { return $this->key->toString('PKCS8'); } }