Skip to content

Commit 44a9236

Browse files
author
Gasper Zejn
committed
Fix cryptography EC backend to take curve from the key itself instead of deducing it from desired algorithm. This matches behavior of ecdsa backend, which allows signing different digests with same key (provided they are shorter than the key).
1 parent 4b59bb7 commit 44a9236

File tree

6 files changed

+38
-20
lines changed

6 files changed

+38
-20
lines changed

jose/backends/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55
from jose.backends.cryptography_backend import CryptographyRSAKey as RSAKey
66

77
try:
8-
from jose.backends.ecdsa_backend import ECKey
9-
except ImportError:
108
from jose.backends.cryptography_backend import CryptographyECKey as ECKey
9+
except ImportError:
10+
from jose.backends.ecdsa_backend import ECDSAECKey as ECKey

jose/backends/cryptography_backend.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,6 @@ class CryptographyECKey(Key):
1919
SHA384 = hashes.SHA384
2020
SHA512 = hashes.SHA512
2121

22-
CURVE_MAP = {
23-
SHA256: ec.SECP256R1,
24-
SHA384: ec.SECP384R1,
25-
SHA512: ec.SECP521R1,
26-
}
27-
2822
def __init__(self, key, algorithm, cryptography_backend=default_backend):
2923
if algorithm not in ALGORITHMS.EC:
3024
raise JWKError('hash_alg: %s is not a valid hash algorithm' % algorithm)
@@ -36,7 +30,6 @@ def __init__(self, key, algorithm, cryptography_backend=default_backend):
3630
}.get(algorithm)
3731
self._algorithm = algorithm
3832

39-
self.curve = self.CURVE_MAP.get(self.hash_alg)
4033
self.cryptography_backend = cryptography_backend
4134

4235
if hasattr(key, 'public_bytes') or hasattr(key, 'private_bytes'):
@@ -78,18 +71,28 @@ def _process_jwk(self, jwk_dict):
7871
x = base64_to_long(jwk_dict.get('x'))
7972
y = base64_to_long(jwk_dict.get('y'))
8073

81-
ec_pn = ec.EllipticCurvePublicNumbers(x, y, self.curve())
74+
curve = {
75+
'P-256': ec.SECP256R1,
76+
'P-384': ec.SECP384R1,
77+
'P-521': ec.SECP521R1,
78+
}[jwk_dict['crv']]
79+
80+
ec_pn = ec.EllipticCurvePublicNumbers(x, y, curve())
8281
verifying_key = ec_pn.public_key(self.cryptography_backend())
8382

8483
return verifying_key
8584

8685
def sign(self, msg):
86+
if self.hash_alg.digest_size * 8 > self.prepared_key.curve.key_size:
87+
raise TypeError("this curve (%s) is too short "
88+
"for your digest (%d)" % (self.prepared_key.curve.name,
89+
8*self.hash_alg.digest_size))
8790
signature = self.prepared_key.sign(msg, ec.ECDSA(self.hash_alg()))
88-
order = (2 ** self.curve.key_size) - 1
91+
order = (2 ** self.prepared_key.curve.key_size) - 1
8992
return sigencode_string(*sigdecode_der(signature, order), order=order)
9093

9194
def verify(self, msg, sig):
92-
order = (2 ** self.curve.key_size) - 1
95+
order = (2 ** self.prepared_key.curve.key_size) - 1
9396
signature = sigencode_der(*sigdecode_string(sig, order), order=order)
9497
verifier = self.prepared_key.verifier(signature, ec.ECDSA(self.hash_alg()))
9598
verifier.update(msg)

jose/backends/ecdsa_backend.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from jose.utils import base64_to_long
1010

1111

12-
class ECKey(Key):
12+
class ECDSAECKey(Key):
1313
"""
1414
Performs signing and verification operations using
1515
ECDSA and the specified hash function

tests/algorithms/test_EC.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11

22
from jose.constants import ALGORITHMS
33
from jose.exceptions import JOSEError
4-
from jose.jwk import ECKey
4+
5+
from jose.backends.ecdsa_backend import ECDSAECKey
6+
from jose.backends.cryptography_backend import CryptographyECKey
57

68
import ecdsa
79
import pytest
@@ -17,14 +19,24 @@ class TestECAlgorithm:
1719

1820
def test_EC_key(self):
1921
key = ecdsa.SigningKey.from_pem(private_key)
20-
ECKey(key, ALGORITHMS.ES256)
22+
ECDSAECKey(key, ALGORITHMS.ES256)
23+
CryptographyECKey(key, ALGORITHMS.ES256)
24+
25+
ECDSAECKey(private_key, ALGORITHMS.ES256)
26+
CryptographyECKey(private_key, ALGORITHMS.ES256)
2127

2228
def test_string_secret(self):
2329
key = 'secret'
2430
with pytest.raises(JOSEError):
25-
ECKey(key, ALGORITHMS.ES256)
31+
ECDSAECKey(key, ALGORITHMS.ES256)
32+
33+
with pytest.raises(JOSEError):
34+
CryptographyECKey(key, ALGORITHMS.ES256)
2635

2736
def test_object(self):
2837
key = object()
2938
with pytest.raises(JOSEError):
30-
ECKey(key, ALGORITHMS.ES256)
39+
ECDSAECKey(key, ALGORITHMS.ES256)
40+
41+
with pytest.raises(JOSEError):
42+
CryptographyECKey(key, ALGORITHMS.ES256)

tests/algorithms/test_cryptography_EC.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from jose.constants import ALGORITHMS
33
from jose.exceptions import JOSEError
44
from jose.backends.cryptography_backend import CryptographyECKey
5-
from jose.jwk import ECKey
5+
from jose.backends.ecdsa_backend import ECDSAECKey
66

77
import ecdsa
88
import pytest
@@ -39,9 +39,9 @@ def test_cryptography_EC_key(self):
3939
CryptographyECKey(key, ALGORITHMS.ES256)
4040

4141
def test_signing_parity(self):
42-
key1 = ECKey(private_key, ALGORITHMS.ES256)
42+
key1 = ECDSAECKey(private_key, ALGORITHMS.ES256)
4343
public_key = key1.public_key().to_pem()
44-
vkey1 = ECKey(public_key, ALGORITHMS.ES256)
44+
vkey1 = ECDSAECKey(public_key, ALGORITHMS.ES256)
4545
key2 = CryptographyECKey(private_key, ALGORITHMS.ES256)
4646
vkey2 = CryptographyECKey(public_key, ALGORITHMS.ES256)
4747

tests/test_jwk.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from jose import jwk
22
from jose.exceptions import JWKError
33
from jose.backends.cryptography_backend import CryptographyECKey
4+
from jose.backends.ecdsa_backend import ECDSAECKey
45

56
import pytest
67

@@ -103,6 +104,8 @@ def test_construct_from_jwk(self):
103104
def test_construct_EC_from_jwk(self):
104105
key = CryptographyECKey(ec_key, algorithm='ES512')
105106
assert isinstance(key, jwk.Key)
107+
key = ECDSAECKey(ec_key, algorithm='ES512')
108+
assert isinstance(key, jwk.Key)
106109

107110
def test_construct_from_jwk_missing_alg(self):
108111

0 commit comments

Comments
 (0)