55from datetime import datetime , timezone
66from cryptography .hazmat .primitives import serialization
77from cryptography .hazmat .primitives .asymmetric .ec import EllipticCurvePublicKey
8+ from cryptography .hazmat .primitives .asymmetric .ed25519 import Ed25519PublicKey
9+ from cryptography .hazmat .primitives .asymmetric .rsa import RSAPublicKey
810from pycose .keys import CoseKey , EC2Key
911from typing import Union
1012
@@ -23,14 +25,15 @@ class MdocCborIssuer:
2325 """
2426 def __init__ (
2527 self ,
26- key_label : str = None ,
27- user_pin : str = None ,
28- lib_path : str = None ,
29- slot_id : int = None ,
28+ key_label : str | None = None ,
29+ user_pin : str | None = None ,
30+ lib_path : str | None = None ,
31+ slot_id : int | None = None ,
3032 hsm : bool = False ,
31- alg : str = None ,
32- kid : str = None ,
33+ alg : str | None = None ,
34+ kid : str | None = None ,
3335 private_key : Union [dict , CoseKey ] = {},
36+ cert_info : dict | None = None ,
3437 ):
3538 """
3639 Initialize a new MdocCborIssuer
@@ -67,16 +70,17 @@ def __init__(
6770 self .hsm = hsm
6871 self .alg = alg
6972 self .kid = kid
73+ self .cert_info = cert_info
7074
7175 def new (
7276 self ,
7377 data : dict ,
7478 doctype : str ,
75- validity : dict = None ,
76- devicekeyinfo : Union [ dict , CoseKey , str ] = None ,
77- cert_path : str = None ,
78- revocation : dict = None ,
79- status : dict = None
79+ validity : dict | None = None ,
80+ devicekeyinfo : dict | CoseKey | str | None = None ,
81+ cert_path : str | None = None ,
82+ revocation : dict | None = None ,
83+ status : dict | None = None
8084 ) -> dict :
8185 """
8286 create a new mdoc with signed mso
@@ -93,49 +97,86 @@ def new(
9397 """
9498 if isinstance (devicekeyinfo , dict ):
9599 devicekeyinfoCoseKeyObject = CoseKey .from_dict (devicekeyinfo )
96- devicekeyinfo = {
97- 1 : devicekeyinfoCoseKeyObject .kty .identifier ,
98- - 1 : devicekeyinfoCoseKeyObject .crv .identifier ,
99- - 2 : devicekeyinfoCoseKeyObject .x ,
100- - 3 : devicekeyinfoCoseKeyObject .y ,
101- }
100+ if devicekeyinfoCoseKeyObject .kty .identifier == 2 : # EC2Key
101+ devicekeyinfo = {
102+ 1 : devicekeyinfoCoseKeyObject .kty .identifier ,
103+ - 1 : devicekeyinfoCoseKeyObject .crv .identifier ,
104+ - 2 : devicekeyinfoCoseKeyObject .x ,
105+ - 3 : devicekeyinfoCoseKeyObject .y ,
106+ }
107+ elif devicekeyinfoCoseKeyObject .kty .identifier == 1 : # OKPKey
108+ devicekeyinfo = {
109+ 1 : devicekeyinfoCoseKeyObject .kty .identifier ,
110+ - 1 : devicekeyinfoCoseKeyObject .crv .identifier ,
111+ - 2 : devicekeyinfoCoseKeyObject .x ,
112+ }
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" )
102121 if isinstance (devicekeyinfo , str ):
103122 device_key_bytes = base64 .urlsafe_b64decode (devicekeyinfo .encode ("utf-8" ))
104- public_key :EllipticCurvePublicKey = serialization .load_pem_public_key (device_key_bytes )
105- curve_name = public_key .curve .name
106- curve_map = {
107- "secp256r1" : 1 , # NIST P-256
108- "secp384r1" : 2 , # NIST P-384
109- "secp521r1" : 3 , # NIST P-521
110- "brainpoolP256r1" : 8 , # Brainpool P-256
111- "brainpoolP384r1" : 9 , # Brainpool P-384
112- "brainpoolP512r1" : 10 , # Brainpool P-512
113- # Add more curve mappings as needed
114- }
115- curve_identifier = curve_map .get (curve_name )
116-
117- # Extract the x and y coordinates from the public key
118- x = public_key .public_numbers ().x .to_bytes (
119- (public_key .public_numbers ().x .bit_length () + 7 )
120- // 8 , # Number of bytes needed
121- "big" , # Byte order
122- )
123+ public_key = serialization .load_pem_public_key (device_key_bytes )
124+
125+ if isinstance (public_key , EllipticCurvePublicKey ):
126+ curve_name = public_key .curve .name
127+ curve_map = {
128+ "secp256r1" : 1 , # NIST P-256
129+ "secp384r1" : 2 , # NIST P-384
130+ "secp521r1" : 3 , # NIST P-521
131+ "brainpoolP256r1" : 8 , # Brainpool P-256
132+ "brainpoolP384r1" : 9 , # Brainpool P-384
133+ "brainpoolP512r1" : 10 , # Brainpool P-512
134+ # Add more curve mappings as needed
135+ }
136+ curve_identifier = curve_map .get (curve_name )
123137
124- y = public_key .public_numbers ().y .to_bytes (
125- (public_key .public_numbers ().y .bit_length () + 7 )
126- // 8 , # Number of bytes needed
127- "big" , # Byte order
128- )
138+ # Extract the x and y coordinates from the public key
139+ x = public_key .public_numbers ().x .to_bytes (
140+ (public_key .public_numbers ().x .bit_length () + 7 )
141+ // 8 , # Number of bytes needed
142+ "big" , # Byte order
143+ )
129144
130- devicekeyinfo = {
131- 1 : 2 ,
132- - 1 : curve_identifier ,
133- - 2 : x ,
134- - 3 : y ,
135- }
145+ y = public_key .public_numbers ().y .to_bytes (
146+ (public_key .public_numbers ().y .bit_length () + 7 )
147+ // 8 , # Number of bytes needed
148+ "big" , # Byte order
149+ )
136150
137- else :
138- devicekeyinfo : CoseKey = devicekeyinfo
151+ devicekeyinfo = {
152+ 1 : 2 ,
153+ - 1 : curve_identifier ,
154+ - 2 : x ,
155+ - 3 : y ,
156+ }
157+ elif isinstance (public_key , Ed25519PublicKey ):
158+ devicekeyinfo = {
159+ 1 : 1 , # OKPKey
160+ - 1 : "Ed25519" , # Curve identifier for Ed25519
161+ - 2 : public_key .public_bytes (
162+ encoding = serialization .Encoding .Raw ,
163+ format = serialization .PublicFormat .Raw
164+ )
165+ }
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+ }
178+ else :
179+ raise TypeError ("Loaded public key is not an EllipticCurvePublicKey" )
139180
140181 if self .hsm :
141182 msoi = MsoIssuer (
@@ -149,7 +190,8 @@ def new(
149190 alg = self .alg ,
150191 kid = self .kid ,
151192 validity = validity ,
152- revocation = revocation
193+ revocation = revocation ,
194+ cert_info = self .cert_info
153195 )
154196
155197 else :
@@ -159,10 +201,11 @@ def new(
159201 alg = self .alg ,
160202 cert_path = cert_path ,
161203 validity = validity ,
162- revocation = revocation
204+ revocation = revocation ,
205+ cert_info = self .cert_info
163206 )
164207
165- mso = msoi .sign (doctype = doctype , device_key = devicekeyinfo ,valid_from = datetime .now (timezone .utc ))
208+ mso = msoi .sign (doctype = doctype , device_key = devicekeyinfo , valid_from = datetime .now (timezone .utc ))
166209
167210 mso_cbor = mso .encode (
168211 tag = False ,
0 commit comments