23 private const OID =
'1.2.840.10045.2.1';
28 'P-256' =>
'1.2.840.10045.3.1.7',
29 'secp256k1' =>
'1.3.132.0.10',
30 'P-384' =>
'1.3.132.0.34',
55 public static function parseKeySet(array $jwks,
string $defaultAlg = null): array
59 if (!isset($jwks[
'keys'])) {
63 if (empty($jwks[
'keys'])) {
67 foreach ($jwks[
'keys'] as $k => $v) {
68 $kid = isset($v[
'kid']) ? $v[
'kid'] : $k;
69 if (
$key = self::parseKey($v, $defaultAlg)) {
74 if (0 === \count(
$keys)) {
96 public static function parseKey(array $jwk,
string $defaultAlg = null): ?
Key 102 if (!isset($jwk[
'kty'])) {
106 if (!isset($jwk[
'alg'])) {
107 if (\is_null($defaultAlg)) {
114 $jwk[
'alg'] = $defaultAlg;
117 switch ($jwk[
'kty']) {
119 if (!empty($jwk[
'd'])) {
122 if (!isset($jwk[
'n']) || !isset($jwk[
'e'])) {
126 $pem = self::createPemFromModulusAndExponent($jwk[
'n'], $jwk[
'e']);
127 $publicKey = \openssl_pkey_get_public($pem);
128 if (
false === $publicKey) {
130 'OpenSSL error: ' . \openssl_error_string()
133 return new Key($publicKey, $jwk[
'alg']);
135 if (isset($jwk[
'd'])) {
140 if (empty($jwk[
'crv'])) {
144 if (!isset(self::EC_CURVES[$jwk[
'crv']])) {
148 if (empty($jwk[
'x']) || empty($jwk[
'y'])) {
152 $publicKey = self::createPemFromCrvAndXYCoordinates($jwk[
'crv'], $jwk[
'x'], $jwk[
'y']);
153 return new Key($publicKey, $jwk[
'alg']);
155 if (isset($jwk[
'd'])) {
160 if (!isset($jwk[
'crv'])) {
164 if (empty(self::OKP_SUBTYPES[$jwk[
'crv']])) {
165 throw new DomainException(
'Unrecognised or unsupported OKP key subtype');
168 if (empty($jwk[
'x'])) {
173 $publicKey = JWT::convertBase64urlToBase64($jwk[
'x']);
174 return new Key($publicKey, $jwk[
'alg']);
199 self::ASN1_OBJECT_IDENTIFIER,
200 self::encodeOID(self::OID)
203 self::ASN1_OBJECT_IDENTIFIER,
204 self::encodeOID(self::EC_CURVES[$crv])
208 self::ASN1_BIT_STRING,
209 \chr(0x00) . \chr(0x04)
216 "-----BEGIN PUBLIC KEY-----\n%s\n-----END PUBLIC KEY-----\n",
217 wordwrap(base64_encode($pem), 64,
"\n",
true)
238 $modulus = \pack(
'Ca*a*', 2, self::encodeLength(\strlen($mod)), $mod);
239 $publicExponent = \pack(
'Ca*a*', 2, self::encodeLength(\strlen($exp)), $exp);
241 $rsaPublicKey = \pack(
244 self::encodeLength(\strlen($modulus) + \strlen($publicExponent)),
250 $rsaOID = \pack(
'H*',
'300d06092a864886f70d0101010500');
251 $rsaPublicKey = \chr(0) . $rsaPublicKey;
252 $rsaPublicKey = \chr(3) . self::encodeLength(\strlen($rsaPublicKey)) . $rsaPublicKey;
254 $rsaPublicKey = \pack(
257 self::encodeLength(\strlen($rsaOID . $rsaPublicKey)),
258 $rsaOID . $rsaPublicKey
261 return "-----BEGIN PUBLIC KEY-----\r\n" .
262 \chunk_split(\base64_encode($rsaPublicKey), 64) .
263 '-----END PUBLIC KEY-----';
277 if ($length <= 0x7F) {
278 return \chr($length);
281 $temp = \ltrim(\pack(
'N', $length), \chr(0));
283 return \pack(
'Ca*', 0x80 | \strlen($temp), $temp);
297 if ($type === self::ASN1_SEQUENCE) {
302 $der = \chr($tag_header | $type);
305 $der .= \chr(\strlen($value));
307 return $der . $value;
318 $octets = explode(
'.', $oid);
321 $first = (
int) array_shift($octets);
322 $second = (
int) array_shift($octets);
323 $oid = \chr($first * 40 + $second);
326 foreach ($octets as $octet) {
334 $bin .= \chr(0x80 | ($octet & 0x7f));
337 $bin[0] = $bin[0] & \chr(0x7f);
340 if (pack(
'V', 65534) == pack(
'L', 65534)) {
341 $oid .= strrev($bin);
static parseKey(array $jwk, string $defaultAlg=null)
Parse a JWK key.
static encodeLength(int $length)
DER-encode the length.
static createPemFromModulusAndExponent(string $n, string $e)
Create a public key represented in PEM format from RSA modulus and exponent information.
static encodeOID(string $oid)
Encodes a string into a DER-encoded OID.
const ASN1_OBJECT_IDENTIFIER
static createPemFromCrvAndXYCoordinates(string $crv, string $x, string $y)
Converts the EC JWK values to pem format.
const const static parseKeySet(array $jwks, string $defaultAlg=null)
Parse a set of JWK keys.
static encodeDER(int $type, string $value)
Encodes a value into a DER object.
static urlsafeB64Decode(string $input)
Decode a string with URL-safe Base64.