-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add ed25519 support to JWK (public keys) #452
Conversation
54c6024
to
9914472
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for submitting this! I have some technical questions, as well as some issues with the implementation here. Hopefully we can get this feature merged!
src/JWT.php
Outdated
* @return string A Base64 encoded string with standard characters (+/) and padding (=), when | ||
* needed. | ||
*/ | ||
public static function urlsafeToStandardB64(string $input): string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This naming is confusing to me. For key type OKP, the spec says
The parameter "x" MUST be present and contain the public key
encoded using the base64url [RFC4648] encoding.
This links to another spec which says
This encoding may be referred to as "base64url". This encoding
should not be regarded as the same as the "base64" encoding and
should not be referred to as only "base64"
I think it would be better to call this base64UrlDecode
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've renamed the function to convertBase64urlToBase64
. Do you think it's clearer?
It doesn't actually decode base64 data, it just translates from base64url
to base64
so that the PHP base64_decode
function can be used.
src/JWK.php
Outdated
$ktyNotRequiringAlg = [ | ||
// In Octet Key Pair (OKP) keys, the signing algorithm (alg) will not be read from the | ||
// JWK, as it can be inferred directly from the curve type (crv). | ||
// @see https://datatracker.ietf.org/doc/html/rfc8037#section-3.1 | ||
'OKP', | ||
]; | ||
if (!isset($jwk['alg']) && !\in_array($jwk['kty'], $ktyNotRequiringAlg, true)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am unfamiliar with OKPs, but by looking at this example, those values contain an "alg" of EdDSA
instead of using the clunky mapping. I'd prefer to keep the algorithm explicit, and require it like we do everywhere else.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've reverted to the original version where the algorithm is always required. I see that the library opted for always requiring an explicit algorithm.
src/JWK.php
Outdated
@@ -30,6 +30,11 @@ class JWK | |||
// 'P-521' => '1.3.132.0.35', // Len: 132 (not supported) | |||
]; | |||
|
|||
// 'crv' identifier => JWT 'alg' | |||
private const OKP_CURVES = [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is strange to me, as the values here aren't curves, but algorithms. I am not convinced this is the correct implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've rephrased the concepts to call these "key subtypes", as section 2 of RFC 8037 calls it.
src/JWK.php
Outdated
$publicKey = JWT::urlsafeToStandardB64($jwk['x']); | ||
$alg = self::OKP_CURVES[$jwk['crv']]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am confused because there is no action taken as far as implementing decoding a key with ed25519. The JWK
class is base64url
-decoding the key, and (I am assuming) relying on the to default behavior of sodium_crypto
to accept this as ed25519
. There are other possible values here, however, so I think at the very least this needs to throw an exception if crv
is not ed25519
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the sodium_crypto
functions that are used by the library work specifically with ed25519.
If an unsupported crv
is provided, an exception will be thrown a few lines above with the message Unrecognised or unsupported OKP key subtype
.
This PR would be really useful for us. @edudobay - do you have time to get this updated and the questions responded to, or instead would you be happy if I took it forward? I've tested the branch with our code bases and everything looks to work correctly. Thank you! |
Reference documentation: https://datatracker.ietf.org/doc/html/rfc8037
43c3860
to
c55b88d
Compare
Hi! Sorry for the delay, I've addressed the issues you commented, and I think it's clearer and cleaner now. I was wondering if it would be useful to throw an exception if the provided In that case, the mismatch would fall down to the crypto function layer — it would either give an error because the given key is invalid for the given algorithm, or encrypt with the wrong algorithm if by chance the same key is valid for different algorithms. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great! Just one minor change and we can merge this!
Thanks again for your contribution.
"kid": "jwk1", | ||
"kty": "OKP", | ||
"crv": "Ed25519", | ||
"x": "uOSJMhbKSG4V5xUHS7B9YHmVg_1yVd-G-Io6oBFhSfY" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tests say this needs to contain an "alg" parameter! Either that or you can refactor the tests to use the $defaultAlg
argument
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the parameter.
@bshaffer I've addressed the final comments, so I think this is ready now :) |
Ed25519 key support has been added in #343 for the "standard" key format, but not yet for JWKs. (I'm opening a new PR, as I had previously opened #414 against a different base branch.)
Reference documentation: RFC8037