Skip to content

Commit 3c66197

Browse files
committed
feat: Ed25519 jwks
1 parent c4f4e78 commit 3c66197

File tree

1 file changed

+71
-53
lines changed

1 file changed

+71
-53
lines changed

pymdoccbor/mdoc/issuer.py

Lines changed: 71 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from datetime import datetime, timezone
66
from cryptography.hazmat.primitives import serialization
77
from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey
8+
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
89
from pycose.keys import CoseKey, EC2Key
910
from typing import Union
1011

@@ -23,13 +24,13 @@ class MdocCborIssuer:
2324
"""
2425
def __init__(
2526
self,
26-
key_label: str = None,
27-
user_pin: str = None,
28-
lib_path: str = None,
29-
slot_id: int = None,
27+
key_label: str | None = None,
28+
user_pin: str | None = None,
29+
lib_path: str | None = None,
30+
slot_id: int | None = None,
3031
hsm: bool = False,
31-
alg: str = None,
32-
kid: str = None,
32+
alg: str | None = None,
33+
kid: str | None = None,
3334
private_key: Union[dict, CoseKey] = {},
3435
cert_info: dict | None = None,
3536
):
@@ -74,11 +75,11 @@ def new(
7475
self,
7576
data: dict,
7677
doctype: str,
77-
validity: dict = None,
78-
devicekeyinfo: Union[dict, CoseKey, str] = None,
79-
cert_path: str = None,
80-
revocation: dict = None,
81-
status: dict = None
78+
validity: dict | None = None,
79+
devicekeyinfo: dict | CoseKey | str | None = None,
80+
cert_path: str | None = None,
81+
revocation: dict | None = None,
82+
status: dict | None = None
8283
) -> dict:
8384
"""
8485
create a new mdoc with signed mso
@@ -95,49 +96,66 @@ def new(
9596
"""
9697
if isinstance(devicekeyinfo, dict):
9798
devicekeyinfoCoseKeyObject = CoseKey.from_dict(devicekeyinfo)
98-
devicekeyinfo = {
99-
1: devicekeyinfoCoseKeyObject.kty.identifier,
100-
-1: devicekeyinfoCoseKeyObject.crv.identifier,
101-
-2: devicekeyinfoCoseKeyObject.x,
102-
-3: devicekeyinfoCoseKeyObject.y,
103-
}
99+
if devicekeyinfoCoseKeyObject.kty.identifier == 2: # EC2Key
100+
devicekeyinfo = {
101+
1: devicekeyinfoCoseKeyObject.kty.identifier,
102+
-1: devicekeyinfoCoseKeyObject.crv.identifier,
103+
-2: devicekeyinfoCoseKeyObject.x,
104+
-3: devicekeyinfoCoseKeyObject.y,
105+
}
106+
elif devicekeyinfoCoseKeyObject.kty.identifier == 1: # OKPKey
107+
devicekeyinfo = {
108+
1: devicekeyinfoCoseKeyObject.kty.identifier,
109+
-1: devicekeyinfoCoseKeyObject.crv.identifier,
110+
-2: devicekeyinfoCoseKeyObject.x,
111+
}
104112
if isinstance(devicekeyinfo, str):
105113
device_key_bytes = base64.urlsafe_b64decode(devicekeyinfo.encode("utf-8"))
106-
public_key:EllipticCurvePublicKey = serialization.load_pem_public_key(device_key_bytes)
107-
curve_name = public_key.curve.name
108-
curve_map = {
109-
"secp256r1": 1, # NIST P-256
110-
"secp384r1": 2, # NIST P-384
111-
"secp521r1": 3, # NIST P-521
112-
"brainpoolP256r1": 8, # Brainpool P-256
113-
"brainpoolP384r1": 9, # Brainpool P-384
114-
"brainpoolP512r1": 10, # Brainpool P-512
115-
# Add more curve mappings as needed
116-
}
117-
curve_identifier = curve_map.get(curve_name)
118-
119-
# Extract the x and y coordinates from the public key
120-
x = public_key.public_numbers().x.to_bytes(
121-
(public_key.public_numbers().x.bit_length() + 7)
122-
// 8, # Number of bytes needed
123-
"big", # Byte order
124-
)
125-
126-
y = public_key.public_numbers().y.to_bytes(
127-
(public_key.public_numbers().y.bit_length() + 7)
128-
// 8, # Number of bytes needed
129-
"big", # Byte order
130-
)
131-
132-
devicekeyinfo = {
133-
1: 2,
134-
-1: curve_identifier,
135-
-2: x,
136-
-3: y,
137-
}
138-
139-
else:
140-
devicekeyinfo: CoseKey = devicekeyinfo
114+
public_key = serialization.load_pem_public_key(device_key_bytes)
115+
116+
if isinstance(public_key, EllipticCurvePublicKey):
117+
curve_name = public_key.curve.name
118+
curve_map = {
119+
"secp256r1": 1, # NIST P-256
120+
"secp384r1": 2, # NIST P-384
121+
"secp521r1": 3, # NIST P-521
122+
"brainpoolP256r1": 8, # Brainpool P-256
123+
"brainpoolP384r1": 9, # Brainpool P-384
124+
"brainpoolP512r1": 10, # Brainpool P-512
125+
# Add more curve mappings as needed
126+
}
127+
curve_identifier = curve_map.get(curve_name)
128+
129+
# Extract the x and y coordinates from the public key
130+
x = public_key.public_numbers().x.to_bytes(
131+
(public_key.public_numbers().x.bit_length() + 7)
132+
// 8, # Number of bytes needed
133+
"big", # Byte order
134+
)
135+
136+
y = public_key.public_numbers().y.to_bytes(
137+
(public_key.public_numbers().y.bit_length() + 7)
138+
// 8, # Number of bytes needed
139+
"big", # Byte order
140+
)
141+
142+
devicekeyinfo = {
143+
1: 2,
144+
-1: curve_identifier,
145+
-2: x,
146+
-3: y,
147+
}
148+
elif isinstance(public_key, Ed25519PublicKey):
149+
devicekeyinfo = {
150+
1: 1, # OKPKey
151+
-1: "Ed25519", # Curve identifier for Ed25519
152+
-2: public_key.public_bytes(
153+
encoding=serialization.Encoding.Raw,
154+
format=serialization.PublicFormat.Raw
155+
)
156+
}
157+
else:
158+
raise TypeError("Loaded public key is not an EllipticCurvePublicKey")
141159

142160
if self.hsm:
143161
msoi = MsoIssuer(
@@ -166,7 +184,7 @@ def new(
166184
cert_info=self.cert_info
167185
)
168186

169-
mso = msoi.sign(doctype=doctype, device_key=devicekeyinfo,valid_from=datetime.now(timezone.utc))
187+
mso = msoi.sign(doctype=doctype, device_key=devicekeyinfo, valid_from=datetime.now(timezone.utc))
170188

171189
mso_cbor = mso.encode(
172190
tag=False,

0 commit comments

Comments
 (0)