From a8fc9a4c8c39d375f7a7adab6d88b3d7e90e5e99 Mon Sep 17 00:00:00 2001 From: Jakob Schlyter Date: Tue, 12 Sep 2023 10:04:50 +0200 Subject: [PATCH 1/6] add missing EdDSA --- src/cryptojwt/jwk/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/cryptojwt/jwk/__init__.py b/src/cryptojwt/jwk/__init__.py index d8fd480a..543e2369 100644 --- a/src/cryptojwt/jwk/__init__.py +++ b/src/cryptojwt/jwk/__init__.py @@ -75,6 +75,7 @@ def __init__( "PS256", "PS384", "PS512", + "EdDSA", "none", ]: raise UnsupportedAlgorithm("Unknown algorithm: {}".format(alg)) @@ -93,6 +94,7 @@ def __init__( "PS256", "PS384", "PS512", + "EdDSA", "none", "RSA1_5", "RSA-OAEP", From 737d868c6bb83a658416d592e41e215acbb48c00 Mon Sep 17 00:00:00 2001 From: Jakob Schlyter Date: Wed, 13 Sep 2023 09:34:35 +0200 Subject: [PATCH 2/6] support ES25519 and ES448 fully-specified algorithms per draft-jones-jose-fully-specified-algorithms --- src/cryptojwt/jwk/__init__.py | 4 ++++ src/cryptojwt/jws/eddsa.py | 21 +++++++++++++++++++++ src/cryptojwt/jws/jws.py | 2 ++ src/cryptojwt/jws/utils.py | 4 ++++ tests/test_04_key_jar.py | 31 +++++++++++++++++++++++++++++++ tests/test_06_jws.py | 18 ++++++++++++++++-- 6 files changed, 78 insertions(+), 2 deletions(-) diff --git a/src/cryptojwt/jwk/__init__.py b/src/cryptojwt/jwk/__init__.py index 543e2369..8f527455 100644 --- a/src/cryptojwt/jwk/__init__.py +++ b/src/cryptojwt/jwk/__init__.py @@ -76,6 +76,8 @@ def __init__( "PS384", "PS512", "EdDSA", + "ES25519", + "ES448", "none", ]: raise UnsupportedAlgorithm("Unknown algorithm: {}".format(alg)) @@ -95,6 +97,8 @@ def __init__( "PS384", "PS512", "EdDSA", + "ES25519", + "ES448", "none", "RSA1_5", "RSA-OAEP", diff --git a/src/cryptojwt/jws/eddsa.py b/src/cryptojwt/jws/eddsa.py index 983d93d2..aa6691c1 100644 --- a/src/cryptojwt/jws/eddsa.py +++ b/src/cryptojwt/jws/eddsa.py @@ -10,6 +10,9 @@ class EDDSASigner(Signer): + def __init__(self, algorithm=None): + self.algorithm = algorithm + def sign(self, msg, key): """ Create a signature over a message as defined in RFC7515 using an @@ -20,6 +23,17 @@ def sign(self, msg, key): :return: """ + if self.algorithm: + if self.algorithm == "ES25519" and not isinstance(key, ed25519.Ed25519PrivateKey): + raise TypeError("The private key must be an instance of Ed25519PrivateKey") + if self.algorithm == "ES448" and not isinstance(key, ed448.Ed448PrivateKey): + raise TypeError("The private key must be an instance of Ed448PrivateKey") + + if not isinstance(key, (ed25519.Ed25519PrivateKey, ed448.Ed448PrivateKey)): + raise TypeError( + "The private key must be an instance of Ed25519PrivateKey or Ed448PrivateKey" + ) + if not isinstance(key, (ed25519.Ed25519PrivateKey, ed448.Ed448PrivateKey)): raise TypeError( "The private key must be an instance of Ed25519PrivateKey or Ed448PrivateKey" @@ -37,6 +51,13 @@ def verify(self, msg, sig, key): :raises: BadSignature if the signature can't be verified. :return: True """ + + if self.algorithm: + if self.algorithm == "ES25519" and not isinstance(key, ed25519.Ed25519PublicKey): + raise TypeError("The public key must be an instance of Ed25519PublicKey") + if self.algorithm == "ES448" and not isinstance(key, ed448.Ed448PublicKey): + raise TypeError("The public key must be an instance of Ed448PublicKey") + if not isinstance(key, (ed25519.Ed25519PublicKey, ed448.Ed448PublicKey)): raise TypeError( "The public key must be an instance of Ed25519PublicKey or Ed448PublicKey" diff --git a/src/cryptojwt/jws/jws.py b/src/cryptojwt/jws/jws.py index 7da26fa3..a8b5637f 100644 --- a/src/cryptojwt/jws/jws.py +++ b/src/cryptojwt/jws/jws.py @@ -48,6 +48,8 @@ "PS384": PSSSigner("SHA384"), "PS512": PSSSigner("SHA512"), "EdDSA": EDDSASigner(), + "ES25519": EDDSASigner("ES25519"), + "ES448": EDDSASigner("ES448"), "none": None, } diff --git a/src/cryptojwt/jws/utils.py b/src/cryptojwt/jws/utils.py index 9ccf16ff..66e5e35a 100644 --- a/src/cryptojwt/jws/utils.py +++ b/src/cryptojwt/jws/utils.py @@ -47,6 +47,10 @@ def alg2keytype(alg): return "RSA" elif alg.startswith("HS") or alg.startswith("A"): return "oct" + elif alg == "ES25519": + return "OKP" + elif alg == "ES448": + return "OKP" elif alg.startswith("ES") or alg.startswith("ECDH-ES"): return "EC" elif alg == "EdDSA": diff --git a/tests/test_04_key_jar.py b/tests/test_04_key_jar.py index 9e73e9e1..a5f72dab 100755 --- a/tests/test_04_key_jar.py +++ b/tests/test_04_key_jar.py @@ -538,6 +538,11 @@ def test_load_missing_key_parameter(): "n": "68be-nJp46VLj4Ci1V36IrVGYqkuBfYNyjQTZD_7yRYcERZebowOnwr3w0DoIQpl8iL2X8OXUo7rUW_LMzLxKx2hEmdJfUn4LL2QqA3KPgjYz8hZJQPG92O14w9IZ-8bdDUgXrg9216H09yq6ZvJrn5Nwvap3MXgECEzsZ6zQLRKdb_R96KFFgCiI3bEiZKvZJRA7hM2ePyTm15D9En_Wzzfn_JLMYgE_DlVpoKR1MsTinfACOlwwdO9U5Dm-5elapovILTyVTgjN75i-wsPU2TqzdHFKA-4hJNiWGrYPiihlAFbA2eUSXuEYFkX43ahoQNpeaf0mc17Jt5kp7pM2w", "e": "AQAB", }, + ] +} + +JWKS_EDDSA = { + "keys": [ { "kid": "q-H9y8iuh3BIKZBbK6S0mH_isBlJsk" "-u6VtZ5rAdBo5fCjjy3LnkrsoK_QWrlKB08j_PcvwpAMfTEDHw5spepw", @@ -556,6 +561,22 @@ def test_load_missing_key_parameter(): "crv": "Ed25519", "x": "CS01DGXDBPV9cFmd8tgFu3E7eHn1UcP7N1UCgd_JgZo", }, + { + "kid": "OF9xVk9NWE5iQ2N6OGhILTVGcXg4RE1FRk5NWVVsaXZLcFNRNUxCYk9vQQ", + "use": "sig", + "alg": "ES25519", + "kty": "OKP", + "crv": "Ed25519", + "x": "M_D8nslNSecjPwiP6DwuNhWRdrgqp02U7f5xo4GhdlY", + }, + { + "kid": "RUpoaXktM1JwT0hON3lzNWNfN0RUbVpiWExwbnJnNDRfYWhZY3htaTZ1Zw", + "use": "sig", + "alg": "ES448", + "kty": "OKP", + "crv": "Ed448", + "x": "C3y5YN00IxyadHXm4NApPGAzv5w8s9e-fbGu2svYrrCuJDYDDZe-uEOPSobII6psCZCEvo2howmA", + }, ] } @@ -580,6 +601,16 @@ def test_get_ec_wrong_alg(): assert k == [] +def test_get_eddsa(): + kj = KeyJar() + kj.import_jwks(JWKS_EDDSA, "") + assert len(kj.get_issuer_keys("")) == 4 + k = kj.get("sig", "OKP", alg="ES25519") + assert k + k = kj.get("sig", "OKP", alg="ES448") + assert k + + def test_keyjar_eq(): kj1 = KeyJar() kj1.import_jwks(JWKS_SPO, "") diff --git a/tests/test_06_jws.py b/tests/test_06_jws.py index 8ce77c2d..7f30befd 100644 --- a/tests/test_06_jws.py +++ b/tests/test_06_jws.py @@ -609,6 +609,20 @@ def test_signer_ps512(): def test_signer_eddsa(): + payload = "Please take a moment to register today" + okp = ed25519.Ed25519PrivateKey.generate() + _key = OKPKey().load_key(okp) + keys = [_key] + _jws = JWS(payload, alg="ES25519") + _jwt = _jws.sign_compact(keys) + + _pubkey = OKPKey().load_key(okp.public_key()) + _rj = JWS(alg="ES25519") + info = _rj.verify_compact(_jwt, [_pubkey]) + assert info == payload + + +def test_signer_eddsa_polymorphic(): payload = "Please take a moment to register today" okp = ed25519.Ed25519PrivateKey.generate() _key = OKPKey().load_key(okp) @@ -627,12 +641,12 @@ def test_signer_eddsa_fail(): okp = ed25519.Ed25519PrivateKey.generate() _key = OKPKey().load_key(okp) keys = [_key] - _jws = JWS(payload, alg="EdDSA") + _jws = JWS(payload, alg="ES25519") _jwt = _jws.sign_compact(keys) okp2 = ed25519.Ed25519PrivateKey.generate() _pubkey = OKPKey().load_key(okp2.public_key()) - _rj = JWS(alg="EdDSA") + _rj = JWS(alg="ES25519") try: info = _rj.verify_compact(_jwt, [_pubkey]) except BadSignature: From 2630907bd7395dac5cb2f75ce63c6c241756daca Mon Sep 17 00:00:00 2001 From: Jakob Schlyter Date: Wed, 13 Sep 2023 09:38:05 +0200 Subject: [PATCH 3/6] rename ES25519/ES448 to Ed25519/Ed448 --- src/cryptojwt/jwk/__init__.py | 8 ++++---- src/cryptojwt/jws/eddsa.py | 8 ++++---- src/cryptojwt/jws/jws.py | 4 ++-- src/cryptojwt/jws/utils.py | 4 ++-- tests/test_04_key_jar.py | 8 ++++---- tests/test_06_jws.py | 8 ++++---- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/cryptojwt/jwk/__init__.py b/src/cryptojwt/jwk/__init__.py index 8f527455..fd4e9cb1 100644 --- a/src/cryptojwt/jwk/__init__.py +++ b/src/cryptojwt/jwk/__init__.py @@ -76,8 +76,8 @@ def __init__( "PS384", "PS512", "EdDSA", - "ES25519", - "ES448", + "Ed25519", + "Ed448", "none", ]: raise UnsupportedAlgorithm("Unknown algorithm: {}".format(alg)) @@ -97,8 +97,8 @@ def __init__( "PS384", "PS512", "EdDSA", - "ES25519", - "ES448", + "Ed25519", + "Ed448", "none", "RSA1_5", "RSA-OAEP", diff --git a/src/cryptojwt/jws/eddsa.py b/src/cryptojwt/jws/eddsa.py index aa6691c1..6a88f8e0 100644 --- a/src/cryptojwt/jws/eddsa.py +++ b/src/cryptojwt/jws/eddsa.py @@ -24,9 +24,9 @@ def sign(self, msg, key): """ if self.algorithm: - if self.algorithm == "ES25519" and not isinstance(key, ed25519.Ed25519PrivateKey): + if self.algorithm == "Ed25519" and not isinstance(key, ed25519.Ed25519PrivateKey): raise TypeError("The private key must be an instance of Ed25519PrivateKey") - if self.algorithm == "ES448" and not isinstance(key, ed448.Ed448PrivateKey): + if self.algorithm == "Ed448" and not isinstance(key, ed448.Ed448PrivateKey): raise TypeError("The private key must be an instance of Ed448PrivateKey") if not isinstance(key, (ed25519.Ed25519PrivateKey, ed448.Ed448PrivateKey)): @@ -53,9 +53,9 @@ def verify(self, msg, sig, key): """ if self.algorithm: - if self.algorithm == "ES25519" and not isinstance(key, ed25519.Ed25519PublicKey): + if self.algorithm == "Ed25519" and not isinstance(key, ed25519.Ed25519PublicKey): raise TypeError("The public key must be an instance of Ed25519PublicKey") - if self.algorithm == "ES448" and not isinstance(key, ed448.Ed448PublicKey): + if self.algorithm == "Ed448" and not isinstance(key, ed448.Ed448PublicKey): raise TypeError("The public key must be an instance of Ed448PublicKey") if not isinstance(key, (ed25519.Ed25519PublicKey, ed448.Ed448PublicKey)): diff --git a/src/cryptojwt/jws/jws.py b/src/cryptojwt/jws/jws.py index a8b5637f..7a93a843 100644 --- a/src/cryptojwt/jws/jws.py +++ b/src/cryptojwt/jws/jws.py @@ -48,8 +48,8 @@ "PS384": PSSSigner("SHA384"), "PS512": PSSSigner("SHA512"), "EdDSA": EDDSASigner(), - "ES25519": EDDSASigner("ES25519"), - "ES448": EDDSASigner("ES448"), + "Ed25519": EDDSASigner("Ed25519"), + "Ed448": EDDSASigner("Ed448"), "none": None, } diff --git a/src/cryptojwt/jws/utils.py b/src/cryptojwt/jws/utils.py index 66e5e35a..40ac46f2 100644 --- a/src/cryptojwt/jws/utils.py +++ b/src/cryptojwt/jws/utils.py @@ -47,9 +47,9 @@ def alg2keytype(alg): return "RSA" elif alg.startswith("HS") or alg.startswith("A"): return "oct" - elif alg == "ES25519": + elif alg == "Ed25519": return "OKP" - elif alg == "ES448": + elif alg == "Ed448": return "OKP" elif alg.startswith("ES") or alg.startswith("ECDH-ES"): return "EC" diff --git a/tests/test_04_key_jar.py b/tests/test_04_key_jar.py index a5f72dab..5f002430 100755 --- a/tests/test_04_key_jar.py +++ b/tests/test_04_key_jar.py @@ -564,7 +564,7 @@ def test_load_missing_key_parameter(): { "kid": "OF9xVk9NWE5iQ2N6OGhILTVGcXg4RE1FRk5NWVVsaXZLcFNRNUxCYk9vQQ", "use": "sig", - "alg": "ES25519", + "alg": "Ed25519", "kty": "OKP", "crv": "Ed25519", "x": "M_D8nslNSecjPwiP6DwuNhWRdrgqp02U7f5xo4GhdlY", @@ -572,7 +572,7 @@ def test_load_missing_key_parameter(): { "kid": "RUpoaXktM1JwT0hON3lzNWNfN0RUbVpiWExwbnJnNDRfYWhZY3htaTZ1Zw", "use": "sig", - "alg": "ES448", + "alg": "Ed448", "kty": "OKP", "crv": "Ed448", "x": "C3y5YN00IxyadHXm4NApPGAzv5w8s9e-fbGu2svYrrCuJDYDDZe-uEOPSobII6psCZCEvo2howmA", @@ -605,9 +605,9 @@ def test_get_eddsa(): kj = KeyJar() kj.import_jwks(JWKS_EDDSA, "") assert len(kj.get_issuer_keys("")) == 4 - k = kj.get("sig", "OKP", alg="ES25519") + k = kj.get("sig", "OKP", alg="Ed25519") assert k - k = kj.get("sig", "OKP", alg="ES448") + k = kj.get("sig", "OKP", alg="Ed448") assert k diff --git a/tests/test_06_jws.py b/tests/test_06_jws.py index 7f30befd..286e3b3a 100644 --- a/tests/test_06_jws.py +++ b/tests/test_06_jws.py @@ -613,11 +613,11 @@ def test_signer_eddsa(): okp = ed25519.Ed25519PrivateKey.generate() _key = OKPKey().load_key(okp) keys = [_key] - _jws = JWS(payload, alg="ES25519") + _jws = JWS(payload, alg="Ed25519") _jwt = _jws.sign_compact(keys) _pubkey = OKPKey().load_key(okp.public_key()) - _rj = JWS(alg="ES25519") + _rj = JWS(alg="Ed25519") info = _rj.verify_compact(_jwt, [_pubkey]) assert info == payload @@ -641,12 +641,12 @@ def test_signer_eddsa_fail(): okp = ed25519.Ed25519PrivateKey.generate() _key = OKPKey().load_key(okp) keys = [_key] - _jws = JWS(payload, alg="ES25519") + _jws = JWS(payload, alg="Ed25519") _jwt = _jws.sign_compact(keys) okp2 = ed25519.Ed25519PrivateKey.generate() _pubkey = OKPKey().load_key(okp2.public_key()) - _rj = JWS(alg="ES25519") + _rj = JWS(alg="Ed25519") try: info = _rj.verify_compact(_jwt, [_pubkey]) except BadSignature: From 5ada3f9795bf17c6874b1a10384528e6d755b6a0 Mon Sep 17 00:00:00 2001 From: Jakob Schlyter Date: Wed, 13 Sep 2023 09:43:35 +0200 Subject: [PATCH 4/6] use unknown kty --- tests/test_03_key_bundle.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_03_key_bundle.py b/tests/test_03_key_bundle.py index bd7353ba..e4841924 100755 --- a/tests/test_03_key_bundle.py +++ b/tests/test_03_key_bundle.py @@ -225,7 +225,7 @@ def test_ignore_unknown_types(): "-u6VtZ5rAdBo5fCjjy3LnkrsoK_QWrlKB08j_PcvwpAMfTEDHw5spepw", "use": "sig", "alg": "EdDSA", - "kty": "OKP", + "kty": "XXX", "crv": "Ed25519", "x": "FnbcUAXZ4ySvrmdXK1MrDuiqlqTXvGdAaE4RWZjmFIQ", } From 866a5f8911e6d3ca8cd63d48d0037dc7108c5dd0 Mon Sep 17 00:00:00 2001 From: Jakob Schlyter Date: Wed, 27 Sep 2023 14:27:50 +0200 Subject: [PATCH 5/6] remove unused keys --- tests/test_04_key_issuer.py | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/tests/test_04_key_issuer.py b/tests/test_04_key_issuer.py index e2d6f36d..8de86852 100755 --- a/tests/test_04_key_issuer.py +++ b/tests/test_04_key_issuer.py @@ -445,25 +445,7 @@ def test_load_missing_key_parameter(): "kty": "RSA", "n": "68be-nJp46VLj4Ci1V36IrVGYqkuBfYNyjQTZD_7yRYcERZebowOnwr3w0DoIQpl8iL2X8OXUo7rUW_LMzLxKx2hEmdJfUn4LL2QqA3KPgjYz8hZJQPG92O14w9IZ-8bdDUgXrg9216H09yq6ZvJrn5Nwvap3MXgECEzsZ6zQLRKdb_R96KFFgCiI3bEiZKvZJRA7hM2ePyTm15D9En_Wzzfn_JLMYgE_DlVpoKR1MsTinfACOlwwdO9U5Dm-5elapovILTyVTgjN75i-wsPU2TqzdHFKA-4hJNiWGrYPiihlAFbA2eUSXuEYFkX43ahoQNpeaf0mc17Jt5kp7pM2w", "e": "AQAB", - }, - { - "kid": "q-H9y8iuh3BIKZBbK6S0mH_isBlJsk" - "-u6VtZ5rAdBo5fCjjy3LnkrsoK_QWrlKB08j_PcvwpAMfTEDHw5spepw", - "use": "sig", - "alg": "EdDSA", - "kty": "OKP", - "crv": "Ed25519", - "x": "FnbcUAXZ4ySvrmdXK1MrDuiqlqTXvGdAaE4RWZjmFIQ", - }, - { - "kid": "bL33HthM3fWaYkY2_pDzUd7a65FV2R2LHAKCOsye8eNmAPDgRgpHWPYpWFVmeaujUUEXRyDLHN" - "-Up4QH_sFcmw", - "use": "sig", - "alg": "EdDSA", - "kty": "OKP", - "crv": "Ed25519", - "x": "CS01DGXDBPV9cFmd8tgFu3E7eHn1UcP7N1UCgd_JgZo", - }, + } ] } From 3253b86a6899f1911ad814542956806205172548 Mon Sep 17 00:00:00 2001 From: Jakob Schlyter Date: Wed, 27 Sep 2023 14:30:44 +0200 Subject: [PATCH 6/6] black --- tests/test_04_key_issuer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_04_key_issuer.py b/tests/test_04_key_issuer.py index 8de86852..6ff041f1 100755 --- a/tests/test_04_key_issuer.py +++ b/tests/test_04_key_issuer.py @@ -445,7 +445,7 @@ def test_load_missing_key_parameter(): "kty": "RSA", "n": "68be-nJp46VLj4Ci1V36IrVGYqkuBfYNyjQTZD_7yRYcERZebowOnwr3w0DoIQpl8iL2X8OXUo7rUW_LMzLxKx2hEmdJfUn4LL2QqA3KPgjYz8hZJQPG92O14w9IZ-8bdDUgXrg9216H09yq6ZvJrn5Nwvap3MXgECEzsZ6zQLRKdb_R96KFFgCiI3bEiZKvZJRA7hM2ePyTm15D9En_Wzzfn_JLMYgE_DlVpoKR1MsTinfACOlwwdO9U5Dm-5elapovILTyVTgjN75i-wsPU2TqzdHFKA-4hJNiWGrYPiihlAFbA2eUSXuEYFkX43ahoQNpeaf0mc17Jt5kp7pM2w", "e": "AQAB", - } + }, ] }