Skip to content

Commit 36cf057

Browse files
committed
fat: implemented RSA support
1 parent 8989f0c commit 36cf057

File tree

3 files changed

+74
-1
lines changed

3 files changed

+74
-1
lines changed

pymdoccbor/mdoc/issuer.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from cryptography.hazmat.primitives import serialization
77
from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey
88
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
9+
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey
910
from pycose.keys import CoseKey, EC2Key
1011
from typing import Union
1112

@@ -109,6 +110,14 @@ def new(
109110
-1: devicekeyinfoCoseKeyObject.crv.identifier,
110111
-2: devicekeyinfoCoseKeyObject.x,
111112
}
113+
elif devicekeyinfoCoseKeyObject.kty.identifier == 3: # RSAKey
114+
devicekeyinfo = {
115+
1: devicekeyinfoCoseKeyObject.kty.identifier,
116+
-1: devicekeyinfoCoseKeyObject.n,
117+
-2: devicekeyinfoCoseKeyObject.e,
118+
}
119+
else:
120+
raise TypeError("Unsupported key type in devicekeyinfo")
112121
if isinstance(devicekeyinfo, str):
113122
device_key_bytes = base64.urlsafe_b64decode(devicekeyinfo.encode("utf-8"))
114123
public_key = serialization.load_pem_public_key(device_key_bytes)
@@ -154,6 +163,18 @@ def new(
154163
format=serialization.PublicFormat.Raw
155164
)
156165
}
166+
elif isinstance(public_key, RSAPublicKey):
167+
devicekeyinfo = {
168+
1: 3, # RSAKey
169+
-1: public_key.public_numbers().n.to_bytes(
170+
(public_key.public_numbers().n.bit_length() + 7) // 8,
171+
"big"
172+
),
173+
-2: public_key.public_numbers().e.to_bytes(
174+
(public_key.public_numbers().e.bit_length() + 7) // 8,
175+
"big"
176+
)
177+
}
157178
else:
158179
raise TypeError("Loaded public key is not an EllipticCurvePublicKey")
159180

pymdoccbor/tests/pkey.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import os
22
import base64
33

4+
from pycose.keys import RSAKey
5+
46
PKEY = {
57
'KTY': 'EC2',
68
'CURVE': 'P_256',
@@ -29,4 +31,11 @@ def base64_urldecode(v: str) -> bytes:
2931
'D': decoded_d,
3032
'X': decoded_x,
3133
'KID': b"demo-kid-ed25519"
34+
}
35+
36+
PKEY_RSA = {
37+
'KTY': 'RSA',
38+
'E': b'\xd4\xf1\xf2o',
39+
'N': b'[_\x81\\6y3\xbf\x01\xad\xba\xe26&\xcb\xa2g\xff\x97\xa1rv\xa7\x9a{\xfb\x01r^S\xfb\xefY\xb4\x14\xcesz\x99H\x02\xaf\xf5\xab\x18_\xac\xaaR\x13Q\xe6\xa0\x9a\x8c\x8a\x1f\x13\x0b9\xf3\xbb\xe1\x0b\xb9<\xe7\xc0\xffU\xa0\xcb\x1aw\xf2/\x11\x0e\xea^\x98:cp\x1f3\xc9\x81\x93e\x81\xb4\xb20s\xa6\xaaV\xf3\x03y\xb3\xd9\x93i\x14\xa7\xafi.\x08\xdey\x15s-V\x10\xf0\x0f+:E\x10\xec\xca\x93\x17\xecg\xaf!\x11\xe7\x91\xcdG7)\x83\xc3\xdd\xc2xp\xb2v_\xf2l\xc9\xc7\x15r\xf9\xa1U\xe9`\xde\xf1\xa9\xc2\xb6\xde\xebc|\xef\xb0s,\x10\xa1l\x81&\xcc\xb9\xfa\xb6\xffs\x1a9\x0c[7\xafJ\x1c\xd5\xb6\xc7?\x1c\x8fN\x1a\xde\x7f\xa4\x8f\xf6,\xed\x89b\x87\xcaXL\x8e}\xa5K\x0b\x9a\x8c\xb2\xd2\x91\x0f\xedI\x8e\x8fYq#\x8c\xd1\x02\xe2B\xff\xf1\x1dT\x15\xb1I\xe8\xd8\xfc[\xd5Y\x9ab\xcc\xe3\xff\xac\xfa\x85',
40+
'KEY_OPS': ['SIGN']
3241
}

pymdoccbor/tests/test_02_mdoc_issuer.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from pymdoccbor.mso.issuer import MsoIssuer
1313
from pymdoccbor.tests.pid_data import PID_DATA
1414
from pymdoccbor.tests.cert_data import CERT_DATA
15-
from pymdoccbor.tests.pkey import PKEY, PKEY_ED25519
15+
from pymdoccbor.tests.pkey import PKEY, PKEY_ED25519, PKEY_RSA
1616

1717

1818
def extract_mso(mdoc:dict):
@@ -121,6 +121,49 @@ def test_mdoc_issuer_EdDSA():
121121
mdoci.dump()
122122
mdoci.dumps()
123123

124+
# check mso content for status list
125+
mso = extract_mso(mdoc)
126+
status_list = mso["status"]["status_list"]
127+
assert status_list["idx"] == 0
128+
assert status_list["uri"] == "https://issuer.com/statuslists"
129+
cert_bytes = status_list["certificate"]
130+
cert:Certificate = load_der_x509_certificate(cert_bytes)
131+
assert "Test ASL Issuer" in cert.subject.rfc4514_string(), "ASL is not signed with the expected certificate"
132+
133+
def test_mdoc_issuer_RSA():
134+
validity = {"issuance_date": "2025-01-17", "expiry_date": "2025-11-13" }
135+
mdoci = MdocCborIssuer(
136+
private_key=PKEY,
137+
alg = "ES256",
138+
cert_info=CERT_DATA
139+
)
140+
with open("pymdoccbor/tests/certs/fake-cert.pem", "rb") as file:
141+
fake_cert_file = file.read()
142+
asl_signing_cert = x509.load_pem_x509_certificate(fake_cert_file)
143+
_asl_signing_cert = asl_signing_cert.public_bytes(getattr(serialization.Encoding, "DER"))
144+
status_list = {
145+
"status_list": {
146+
"idx": 0,
147+
"uri": "https://issuer.com/statuslists",
148+
"certificate": _asl_signing_cert,
149+
}
150+
}
151+
mdoc = mdoci.new(
152+
doctype="eu.europa.ec.eudiw.pid.1",
153+
data=PID_DATA,
154+
devicekeyinfo=PKEY_RSA,
155+
validity=validity,
156+
revocation=status_list
157+
)
158+
159+
mdocp = MdocCbor()
160+
aa = cbor2.dumps(mdoc)
161+
mdocp.loads(aa)
162+
assert mdocp.verify() is True
163+
164+
mdoci.dump()
165+
mdoci.dumps()
166+
124167
# check mso content for status list
125168
mso = extract_mso(mdoc)
126169
status_list = mso["status"]["status_list"]

0 commit comments

Comments
 (0)