Skip to content

Commit 04dd9e7

Browse files
committed
fix!: Use ECKey.binding.register_curve to register new supported curves.
1 parent 20e1575 commit 04dd9e7

3 files changed

Lines changed: 54 additions & 33 deletions

File tree

docs/changelog.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,15 @@ Changelog
1212
.. module:: joserfc
1313
:noindex:
1414

15+
Unreleased
16+
----------
17+
18+
- Use "import as" to prioritize the modules for editors.
19+
20+
**Breaking changes**:
21+
22+
- Use ``ECKey.binding.register_curve`` to register new supported curves.
23+
1524
1.0.4
1625
-----
1726

src/joserfc/rfc7518/ec_key.py

Lines changed: 43 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -21,31 +21,42 @@
2121
from ..util import base64_to_int, int_to_base64
2222
from ..registry import KeyParameter
2323

24+
__all__ = ['ECKey']
25+
2426
ECDictKey = t.TypedDict("ECDictKey", {
2527
"crv": str,
2628
"x": str,
2729
"y": str,
2830
"d": str, # optional
2931
}, total=False)
3032

31-
DSS_CURVES: t.Dict[str, t.Type[EllipticCurve]] = {
32-
"P-256": SECP256R1,
33-
"P-384": SECP384R1,
34-
"P-521": SECP521R1,
35-
}
36-
CURVES_DSS: t.Dict[str, str] = {
37-
SECP256R1.name: "P-256",
38-
SECP384R1.name: "P-384",
39-
SECP521R1.name: "P-521",
40-
}
41-
4233

4334
class ECBinding(CryptographyBinding):
4435
ssh_type = b"ecdsa-sha2-"
4536

46-
@staticmethod
47-
def import_private_key(obj: ECDictKey) -> EllipticCurvePrivateKey:
48-
curve = DSS_CURVES[obj["crv"]]()
37+
_dss_curves: t.Dict[str, t.Type[EllipticCurve]] = {}
38+
_curves_dss: t.Dict[str, str] = {}
39+
40+
@classmethod
41+
def register_curve(cls, name: str, curve: t.Type[EllipticCurve]) -> None:
42+
cls._dss_curves[name] = curve
43+
cls._curves_dss[str(curve.name)] = name
44+
45+
@classmethod
46+
def generate_private_key(cls, name: str) -> EllipticCurvePrivateKey:
47+
if name not in cls._dss_curves:
48+
raise ValueError('Invalid crv value: "{}"'.format(name))
49+
50+
curve = cls._dss_curves[name]()
51+
raw_key = generate_private_key(
52+
curve=curve,
53+
backend=default_backend(),
54+
)
55+
return raw_key
56+
57+
@classmethod
58+
def import_private_key(cls, obj: ECDictKey) -> EllipticCurvePrivateKey:
59+
curve = cls._dss_curves[obj["crv"]]()
4960
public_numbers = EllipticCurvePublicNumbers(
5061
base64_to_int(obj["x"]),
5162
base64_to_int(obj["y"]),
@@ -55,31 +66,31 @@ def import_private_key(obj: ECDictKey) -> EllipticCurvePrivateKey:
5566
private_numbers = EllipticCurvePrivateNumbers(d, public_numbers)
5667
return private_numbers.private_key(default_backend())
5768

58-
@staticmethod
59-
def export_private_key(key: EllipticCurvePrivateKey) -> ECDictKey:
69+
@classmethod
70+
def export_private_key(cls, key: EllipticCurvePrivateKey) -> ECDictKey:
6071
numbers = key.private_numbers()
6172
return {
62-
"crv": CURVES_DSS[key.curve.name],
73+
"crv": cls._curves_dss[key.curve.name],
6374
"x": int_to_base64(numbers.public_numbers.x),
6475
"y": int_to_base64(numbers.public_numbers.y),
6576
"d": int_to_base64(numbers.private_value),
6677
}
6778

68-
@staticmethod
69-
def import_public_key(obj: ECDictKey) -> EllipticCurvePublicKey:
70-
curve = DSS_CURVES[obj["crv"]]()
79+
@classmethod
80+
def import_public_key(cls, obj: ECDictKey) -> EllipticCurvePublicKey:
81+
curve = cls._dss_curves[obj["crv"]]()
7182
public_numbers = EllipticCurvePublicNumbers(
7283
base64_to_int(obj["x"]),
7384
base64_to_int(obj["y"]),
7485
curve,
7586
)
7687
return public_numbers.public_key(default_backend())
7788

78-
@staticmethod
79-
def export_public_key(key: EllipticCurvePublicKey) -> ECDictKey:
89+
@classmethod
90+
def export_public_key(cls, key: EllipticCurvePublicKey) -> ECDictKey:
8091
numbers = key.public_numbers()
8192
return {
82-
"crv": CURVES_DSS[numbers.curve.name],
93+
"crv": cls._curves_dss[numbers.curve.name],
8394
"x": int_to_base64(numbers.x),
8495
"y": int_to_base64(numbers.y),
8596
}
@@ -121,7 +132,7 @@ def exchange_derive_key(self, key: "ECKey") -> bytes:
121132

122133
@property
123134
def curve_name(self) -> str:
124-
return CURVES_DSS[self.raw_value.curve.name]
135+
return self.binding._curves_dss[self.raw_value.curve.name]
125136

126137
@property
127138
def curve_key_size(self) -> int:
@@ -141,12 +152,7 @@ def generate_key(
141152
:param private: generate a private key or public key
142153
:param auto_kid: add ``kid`` automatically
143154
"""
144-
if crv not in DSS_CURVES:
145-
raise ValueError('Invalid crv value: "{}"'.format(crv))
146-
raw_key = generate_private_key(
147-
curve=DSS_CURVES[crv](),
148-
backend=default_backend(),
149-
)
155+
raw_key = cls.binding.generate_private_key(crv)
150156
if private:
151157
key = cls(raw_key, raw_key, parameters)
152158
else:
@@ -155,3 +161,10 @@ def generate_key(
155161
if auto_kid:
156162
key.ensure_kid()
157163
return key
164+
165+
166+
# register default curves with their DSS (Digital Signature Standard) names
167+
# https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf
168+
ECBinding.register_curve("P-256", SECP256R1)
169+
ECBinding.register_curve("P-384", SECP384R1)
170+
ECBinding.register_curve("P-521", SECP521R1)

src/joserfc/rfc8812/__init__.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
from cryptography.hazmat.primitives.asymmetric.ec import SECP256K1
2-
from ..rfc7518.ec_key import DSS_CURVES, CURVES_DSS
2+
from ..rfc7518.ec_key import ECKey
33
from ..rfc7518.jws_algs import ECAlgModel
44

55
ES256K = ECAlgModel("ES256K", "secp256k1", 256)
66

77

88
def register_secp256k1() -> None:
99
# https://tools.ietf.org/html/rfc8812#section-3.1
10-
DSS_CURVES["secp256k1"] = SECP256K1
11-
CURVES_DSS[SECP256K1.name] = "secp256k1"
10+
ECKey.binding.register_curve("secp256k1", SECP256K1)
1211

1312

1413
__all__ = ["ES256K", "register_secp256k1"]

0 commit comments

Comments
 (0)