Skip to content

Commit

Permalink
feat: add ed25519 support to JWK (public keys) (#452)
Browse files Browse the repository at this point in the history
  • Loading branch information
edudobay committed Jun 14, 2023
1 parent 5a9cf79 commit e53979a
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 4 deletions.
28 changes: 27 additions & 1 deletion src/JWK.php
Expand Up @@ -31,6 +31,12 @@ class JWK
// 'P-521' => '1.3.132.0.35', // Len: 132 (not supported)
];

// For keys with "kty" equal to "OKP" (Octet Key Pair), the "crv" parameter must contain the key subtype.
// This library supports the following subtypes:
private const OKP_SUBTYPES = [
'Ed25519' => true, // RFC 8037
];

/**
* Parse a set of JWK keys
*
Expand Down Expand Up @@ -145,8 +151,28 @@ public static function parseKey(array $jwk, string $defaultAlg = null): ?Key

$publicKey = self::createPemFromCrvAndXYCoordinates($jwk['crv'], $jwk['x'], $jwk['y']);
return new Key($publicKey, $jwk['alg']);
case 'OKP':
if (isset($jwk['d'])) {
// The key is actually a private key
throw new UnexpectedValueException('Key data must be for a public key');
}

if (!isset($jwk['crv'])) {
throw new UnexpectedValueException('crv not set');
}

if (empty(self::OKP_SUBTYPES[$jwk['crv']])) {
throw new DomainException('Unrecognised or unsupported OKP key subtype');
}

if (empty($jwk['x'])) {
throw new UnexpectedValueException('x not set');
}

// This library works internally with EdDSA keys (Ed25519) encoded in standard base64.
$publicKey = JWT::convertBase64urlToBase64($jwk['x']);
return new Key($publicKey, $jwk['alg']);
default:
// Currently only RSA is supported
break;
}

Expand Down
21 changes: 18 additions & 3 deletions src/JWT.php
Expand Up @@ -220,7 +220,7 @@ public static function encode(
*
* @param string $msg The message to sign
* @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key.
* @param string $alg Supported algorithms are 'ES384','ES256', 'ES256K', 'HS256',
* @param string $alg Supported algorithms are 'EdDSA', 'ES384', 'ES256', 'ES256K', 'HS256',
* 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512'
*
* @return string An encrypted message
Expand Down Expand Up @@ -283,7 +283,7 @@ public static function sign(
*
* @param string $msg The original message (header and body)
* @param string $signature The original signature
* @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $keyMaterial For HS*, a string key works. for RS*, must be an instance of OpenSSLAsymmetricKey
* @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $keyMaterial For Ed*, ES*, HS*, a string key works. for RS*, must be an instance of OpenSSLAsymmetricKey
* @param string $alg The algorithm
*
* @return bool
Expand Down Expand Up @@ -404,13 +404,28 @@ public static function jsonEncode(array $input): string
* @throws InvalidArgumentException invalid base64 characters
*/
public static function urlsafeB64Decode(string $input): string
{
return \base64_decode(self::convertBase64UrlToBase64($input));
}

/**
* Convert a string in the base64url (URL-safe Base64) encoding to standard base64.
*
* @param string $input A Base64 encoded string with URL-safe characters (-_ and no padding)
*
* @return string A Base64 encoded string with standard characters (+/) and padding (=), when
* needed.
*
* @see https://www.rfc-editor.org/rfc/rfc4648
*/
public static function convertBase64UrlToBase64(string $input): string
{
$remainder = \strlen($input) % 4;
if ($remainder) {
$padlen = 4 - $remainder;
$input .= \str_repeat('=', $padlen);
}
return \base64_decode(\strtr($input, '-_', '+/'));
return \strtr($input, '-_', '+/');
}

/**
Expand Down
1 change: 1 addition & 0 deletions tests/JWKTest.php
Expand Up @@ -151,6 +151,7 @@ public function provideDecodeByJwkKeySet()
return [
['rsa1-private.pem', 'rsa-jwkset.json', 'RS256'],
['ecdsa256-private.pem', 'ec-jwkset.json', 'ES256'],
['ed25519-1.sec', 'ed25519-jwkset.json', 'EdDSA'],
];
}

Expand Down
11 changes: 11 additions & 0 deletions tests/data/ed25519-jwkset.json
@@ -0,0 +1,11 @@
{
"keys": [
{
"kid": "jwk1",
"alg": "EdDSA",
"kty": "OKP",
"crv": "Ed25519",
"x": "uOSJMhbKSG4V5xUHS7B9YHmVg_1yVd-G-Io6oBFhSfY"
}
]
}

0 comments on commit e53979a

Please sign in to comment.