Skip to content

Commit 6d61880

Browse files
committed
feat: add ed25519 support to JWK (public keys)
Reference documentation: https://datatracker.ietf.org/doc/html/rfc8037
1 parent f9322a3 commit 6d61880

File tree

4 files changed

+43
-6
lines changed

4 files changed

+43
-6
lines changed

src/JWK.php

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ class JWK
3131
// 'P-521' => '1.3.132.0.35', // Len: 132 (not supported)
3232
];
3333

34+
// 'crv' identifier => JWT 'alg'
35+
private const OKP_CURVES = [
36+
'Ed25519' => 'EdDSA',
37+
];
38+
3439
/**
3540
* Parse a set of JWK keys
3641
*
@@ -93,9 +98,10 @@ public static function parseKey(array $jwk): ?Key
9398
throw new UnexpectedValueException('JWK must contain a "kty" parameter');
9499
}
95100

96-
if (!isset($jwk['alg'])) {
97-
// The "alg" parameter is optional in a KTY, but is required for parsing in
98-
// this library. Add it manually to your JWK array if it doesn't already exist.
101+
$ktyRequiringAlg = ['RSA', 'EC'];
102+
if (!isset($jwk['alg']) && \in_array($jwk['kty'], $ktyRequiringAlg, true)) {
103+
// The "alg" parameter is optional in a KTY, but is required for parsing certain key
104+
// types in this library. Add it manually to your JWK array if it doesn't already exist.
99105
// @see https://datatracker.ietf.org/doc/html/rfc7517#section-4.4
100106
throw new UnexpectedValueException('JWK must contain an "alg" parameter');
101107
}
@@ -137,8 +143,28 @@ public static function parseKey(array $jwk): ?Key
137143

138144
$publicKey = self::createPemFromCrvAndXYCoordinates($jwk['crv'], $jwk['x'], $jwk['y']);
139145
return new Key($publicKey, $jwk['alg']);
146+
case 'OKP':
147+
if (isset($jwk['d'])) {
148+
// The key is actually a private key
149+
throw new UnexpectedValueException('Key data must be for a public key');
150+
}
151+
152+
if (! isset($jwk['crv'])) {
153+
throw new UnexpectedValueException('crv not set');
154+
}
155+
156+
if (!isset(self::OKP_CURVES[$jwk['crv']])) {
157+
throw new DomainException('Unrecognised or unsupported OKP curve');
158+
}
159+
160+
if (empty($jwk['x'])) {
161+
throw new UnexpectedValueException('x not set');
162+
}
163+
164+
$publicKey = \base64_encode(JWT::urlsafeB64Decode($jwk['x']));
165+
$alg = self::OKP_CURVES[$jwk['crv']];
166+
return new Key($publicKey, $alg);
140167
default:
141-
// Currently only RSA is supported
142168
break;
143169
}
144170

src/JWT.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ public static function encode(
198198
*
199199
* @param string $msg The message to sign
200200
* @param string|OpenSSLAsymmetricKey|OpenSSLCertificate|array<mixed> $key The secret key.
201-
* @param string $alg Supported algorithms are 'ES384','ES256', 'HS256', 'HS384',
201+
* @param string $alg Supported algorithms are 'EdDSA', 'ES384', 'ES256', 'HS256', 'HS384',
202202
* 'HS512', 'RS256', 'RS384', and 'RS512'
203203
*
204204
* @return string An encrypted message
@@ -258,7 +258,7 @@ public static function sign(
258258
*
259259
* @param string $msg The original message (header and body)
260260
* @param string $signature The original signature
261-
* @param string|OpenSSLAsymmetricKey|OpenSSLCertificate|array<mixed> $keyMaterial For HS*, a string key works. for RS*, must be an instance of OpenSSLAsymmetricKey
261+
* @param string|OpenSSLAsymmetricKey|OpenSSLCertificate|array<mixed> $keyMaterial For Ed*, ES*, HS*, a string key works. for RS*, must be an instance of OpenSSLAsymmetricKey
262262
* @param string $alg The algorithm
263263
*
264264
* @return bool

tests/JWKTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ public function provideDecodeByJwkKeySet()
139139
return [
140140
['rsa1-private.pem', 'rsa-jwkset.json', 'RS256'],
141141
['ecdsa256-private.pem', 'ec-jwkset.json', 'ES256'],
142+
['ed25519-1.sec', 'ed25519-jwkset.json', 'EdDSA'],
142143
];
143144
}
144145

tests/data/ed25519-jwkset.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"keys": [
3+
{
4+
"kid": "jwk1",
5+
"kty": "OKP",
6+
"crv": "Ed25519",
7+
"x": "uOSJMhbKSG4V5xUHS7B9YHmVg_1yVd-G-Io6oBFhSfY"
8+
}
9+
]
10+
}

0 commit comments

Comments
 (0)