-
Notifications
You must be signed in to change notification settings - Fork 34
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
jwe: Support overriding the algorithm when supplying a JWK #99
Conversation
2191d7d
to
98d6bfd
Compare
Can you update your patch description with the problem the patch solves? |
98d6bfd
to
42928e3
Compare
Sure; apologies for the delay. |
Can you format it to 75 characters-per-line, please. |
Could you perhaps link to a document outlining the commit message format guidelines/requirements? I feel I'd be much simpler than this back-and-forth. |
case *ecdsa.PublicKey: | ||
alg = jose.ECDH_ES_A256KW | ||
case *jose.JSONWebKey: | ||
if key.Algorithm != "" { | ||
alg = jose.KeyAlgorithm(key.Algorithm) |
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 now opens up usage also for symmetric keys that the rest of the code cannot handle: https://github.com/go-jose/go-jose/blob/v3/shared.go#L90
I think we need another switch statement here that only accepts algorithms that we know we can handle which probably (subject to testing) are: ED25519, RSA_OAEP*, and ECDH_ES_*
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.
ECDH_ES is not accepted in multi-recipient modes it seem, so this cannot be used, and it has to be ECDH_ES_A*
It's better to only use OAEP with RSA, so no RSA1_5.
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.
Actually, parseJWKPublicKey
will never return a non-asymmetric key, because it checks for IsPublic
on the JWK.
Lines 53 to 55 in a24b477
if !jwk.IsPublic() { | |
return nil, fmt.Errorf("%s: JWK is not a public key", prefix) | |
} |
Fair point about multi-recipient mode, I had not considered that..
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 think this here would resolve the issue:
diff --git a/keywrap/jwe/keywrapper_jwe.go b/keywrap/jwe/keywrapper_jwe.go
index 62e03b5..f281b08 100644
--- a/keywrap/jwe/keywrapper_jwe.go
+++ b/keywrap/jwe/keywrapper_jwe.go
@@ -129,6 +129,18 @@ func addPubKeys(joseRecipients *[]jose.Recipient, pubKeys [][]byte) error {
case *jose.JSONWebKey:
if key.Algorithm != "" {
alg = jose.KeyAlgorithm(key.Algorithm)
+ switch alg {
+ /* accepted algorithms */
+ case jose.RSA_OAEP:
+ case jose.RSA_OAEP_256:
+ case jose.ECDH_ES_A128KW:
+ case jose.ECDH_ES_A192KW:
+ case jose.ECDH_ES_A256KW:
+ /* all others are rejected */
+ default:
+ return fmt.Errorf("%s is an unsupported JWE key algorithm", alg);
+ }
}
}
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.
Actually,
parseJWKPublicKey
will never return a non-asymmetric key, because it checks forIsPublic
on the JWK.Lines 53 to 55 in a24b477
if !jwk.IsPublic() { return nil, fmt.Errorf("%s: JWK is not a public key", prefix) } Fair point about multi-recipient mode, I had not considered that..
Yes, I have seen that but it will then go to try to parse it as a pkcs11 key and one gets odd error messages about a pkcs11 key that cannot be parsed:
Lines 150 to 153 in a24b477
key, err = parseJWKPublicKey(pubKey, prefix) | |
if err != nil { | |
key, err = parsePkcs11PublicKeyYaml(pubKey, prefix) | |
} |
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 wasn't successful with ED25519 key - it seems to get rejected by the MultiEcnrypter, so I had to take this out from the supported algorithms.
Sorry, but we don't have such a document here. |
Thanks for the review! Do you think it might be better to just change
Fair. Bad UX, but fair 😅 Will fix the commit message format along with the code changes. |
The problem with this is that ParsePublicKey is part of the public interface and existing callers may expect certain types of objects to be returned by this function when and I don't think we can change this so easily. Besides that a JWK would then end up looking like a plain rsa.PublicKey or ecsdsa.PublicKey etc. I'd rather keep the JSONWebKey wrapper around it. |
8660773
to
ee97523
Compare
Apologies for the huge delay; changes have been implemented as requested. Let me know if there is anything else I should do (: |
You need to reformat:
|
ee97523
to
5ec2fff
Compare
Now, passing a JWK (via EncryptWithJwe / JSONWebKey.MarshalJSON) will allow for ECDSA keys and for customizing the algorithm used with a particular key. Previously, the code made it impossible to supply a JWK-encoded ECDSA public key in the encryption config, as all keys passed as JSONWebKey-s were treated as RSA_OAEP keys, since utils.ParsePublicKey delegates to parseJWKPublicKey which returns the JWK itself; and hence the switch in the JWE keywrap failed to detect those as an ecdsa public key. A simpler patch here would have been to change parseJWKPublicKey to return the key contained inside the JWK directly, however, as pointed out by stefanberger, this would have broken backwards compatibility of the public API. Plus, using the algorithm encoded in the JWK allows us to more easily extend the JWE encoder to new algorithms. Risks: JWK-s containing RSA keys but with .Algorithm not set to "" (the default value) or string(jose.RSA_OLAP) will end up erroring or producing different encryptions than before. However, such keys would have failed to decrypt the contents regardless, so it should be fine to consider this a correction rather than breakage of old behavior. (Hyrum's law notwithstanding) Signed-off-by: Bojidar Marinov <bojidar.marinov.bg@gmail.com>
Ah, whoops, that shouldn't have slipped through. 😅 Good catch! |
Otherwise, the current code makes it impossible to supply a JWK-encoded ECDSA public key in the encryption config. (
ParsePublicKey
returnsparseJWKPublicKey
which returns the JWK itself; hence the switch-case fails to notice the ECDSA key inside the JWK)The code in
keywrapper_jwe.go
finding the right value foralg
could probably be structured better; something such as the following pseudocode might capture intent better:Or well, for the purposes of the issue I was facing, just having the initial
if key is JWK: continue with JWK.key
, without allowing for customizing the algorithm, would also be sufficient.