5151
5252from .. import VerifyResult , XMLSignatureProcessor , XMLSigner , XMLVerifier
5353from ..exceptions import InvalidDigest , InvalidInput
54- from ..util import SigningSettings , add_pem_header , ds_tag , namespaces , xades_tag
54+ from ..util import SigningSettings
55+ from ..util import XMLSecurityDigestAlgorithm as digest_algorithms
56+ from ..util import add_pem_header , ds_tag , namespaces , xades_tag
5557
5658# TODO: make this a dataclass
5759default_data_object_format = {"Description" : "Default XAdES payload description" , "MimeType" : "text/xml" }
@@ -69,7 +71,7 @@ class XAdESProcessor(XMLSignatureProcessor):
6971
7072class XAdESSigner (XAdESProcessor , XMLSigner ):
7173 """
72- - assert signature algorithm is not sha1
74+ TODO: docs and signature forwarding for autodocs
7375 """
7476
7577 def __init__ (
@@ -80,7 +82,7 @@ def __init__(
8082 ** kwargs ,
8183 ) -> None :
8284 super ().__init__ (** kwargs )
83- if self .sign_alg .startswith ("hmac- " ):
85+ if self .sign_alg .name . startswith ("HMAC_ " ):
8486 raise Exception ("HMAC signatures are not supported by XAdES" )
8587 self .signature_annotators .append (self ._build_xades_ds_object )
8688 self ._tokens_used : Dict [str , bool ] = {}
@@ -145,11 +147,10 @@ def _add_reference_to_signed_info(self, sig_root, node_to_reference):
145147 signed_info = self ._find (sig_root , "SignedInfo" )
146148 reference = SubElement (signed_info , ds_tag ("Reference" ), nsmap = self .namespaces )
147149 reference .set ("URI" , f"#{ node_to_reference .get ('Id' )} " )
148- digest_alg = self .known_digest_tags [self .digest_alg ]
149- SubElement (reference , ds_tag ("DigestMethod" ), nsmap = self .namespaces , Algorithm = digest_alg )
150+ SubElement (reference , ds_tag ("DigestMethod" ), nsmap = self .namespaces , Algorithm = self .digest_alg .value )
150151 digest_value_node = SubElement (reference , ds_tag ("DigestValue" ), nsmap = self .namespaces )
151152 node_to_reference_c14n = self ._c14n (node_to_reference , algorithm = self .c14n_alg )
152- digest = self ._get_digest (node_to_reference_c14n , self ._get_digest_method_by_tag ( self . digest_alg ) )
153+ digest = self ._get_digest (node_to_reference_c14n , algorithm = self .digest_alg )
153154 digest_value_node .text = b64encode (digest ).decode ()
154155
155156 def add_signing_time (self , signed_signature_properties , sig_root , signing_settings : SigningSettings ):
@@ -169,11 +170,10 @@ def add_signing_certificate(self, signed_signature_properties, sig_root, signing
169170 else :
170171 loaded_cert = load_certificate (FILETYPE_PEM , add_pem_header (cert ))
171172 der_encoded_cert = dump_certificate (FILETYPE_ASN1 , loaded_cert )
172- digest_alg = self .known_digest_tags [self .digest_alg ]
173- cert_digest_bytes = self ._get_digest (der_encoded_cert , self ._get_digest_method (digest_alg ))
173+ cert_digest_bytes = self ._get_digest (der_encoded_cert , algorithm = self .digest_alg )
174174 cert_node = SubElement (signing_cert_v2 , xades_tag ("Cert" ), nsmap = self .namespaces )
175175 cert_digest = SubElement (cert_node , xades_tag ("CertDigest" ), nsmap = self .namespaces )
176- SubElement (cert_digest , ds_tag ("DigestMethod" ), nsmap = self .namespaces , Algorithm = digest_alg )
176+ SubElement (cert_digest , ds_tag ("DigestMethod" ), nsmap = self .namespaces , Algorithm = self . digest_alg . value )
177177 digest_value_node = SubElement (cert_digest , ds_tag ("DigestValue" ), nsmap = self .namespaces )
178178 digest_value_node .text = b64encode (cert_digest_bytes ).decode ()
179179
@@ -196,10 +196,10 @@ def add_signature_policy_identifier(self, signed_signature_properties, sig_root,
196196 description = SubElement (sig_policy_id , xades_tag ("Description" ), nsmap = self .namespaces )
197197 description .text = self .signature_policy ["Description" ]
198198 sig_policy_hash = SubElement (signature_policy_id , xades_tag ("SigPolicyHash" ), nsmap = self .namespaces )
199- digest_alg = self .known_digest_tags [ self . signature_policy ["DigestMethod" ]]
200- SubElement (sig_policy_hash , ds_tag ("DigestMethod" ), nsmap = self .namespaces , Algorithm = digest_alg )
199+ digest_alg = digest_algorithms ( self .signature_policy ["DigestMethod" ])
200+ SubElement (sig_policy_hash , ds_tag ("DigestMethod" ), nsmap = self .namespaces , Algorithm = digest_alg . value )
201201 digest_value_node = SubElement (sig_policy_hash , ds_tag ("DigestValue" ), nsmap = self .namespaces )
202- digest_value_node .text = b64encode ( self .signature_policy ["DigestValue" ]). decode ()
202+ digest_value_node .text = self .signature_policy ["DigestValue" ]
203203
204204 def add_signature_production_place (self , signed_signature_properties , sig_root , signing_settings : SigningSettings ):
205205 # SignatureProductionPlace or SignatureProductionPlaceV2
@@ -234,19 +234,24 @@ def add_data_object_format(self, signed_data_object_properties, sig_root, signin
234234
235235class XAdESVerifier (XAdESProcessor , XMLVerifier ):
236236 """
237- - implement registry of assertion callbacks
238- - assert signature algorithm is not hmac
237+ FIXME: add docs
239238 """
240239
240+ # TODO: document/support SignatureTimeStamp / timestamp attestation
241+ # SignatureTimeStamp is required by certain profiles but is an unsigned property
242+
243+ def _verify_signing_time (self , verify_result : VerifyResult ):
244+ pass
245+
241246 def _verify_cert_digest (self , signing_cert_node , expect_cert ):
242247 for cert in self ._findall (signing_cert_node , "xades:Cert" ):
243248 cert_digest = self ._find (cert , "xades:CertDigest" )
244- digest_alg = self ._find (cert_digest , "DigestMethod" ).get ("Algorithm" )
249+ digest_alg = digest_algorithms ( self ._find (cert_digest , "DigestMethod" ).get ("Algorithm" ) )
245250 digest_value = self ._find (cert_digest , "DigestValue" )
246251 # check spec for specific method of retrieving cert
247252 der_encoded_cert = dump_certificate (FILETYPE_ASN1 , expect_cert )
248253
249- if b64decode (digest_value .text ) != self ._get_digest (der_encoded_cert , self . _get_digest_method ( digest_alg ) ):
254+ if b64decode (digest_value .text ) != self ._get_digest (der_encoded_cert , algorithm = digest_alg ):
250255 raise InvalidDigest ("Digest mismatch for certificate digest" )
251256
252257 def _verify_cert_digests (self , verify_result : VerifyResult ):
@@ -272,23 +277,35 @@ def _verify_signature_policy(self, verify_result: VerifyResult):
272277 "xades:SignaturePolicyIdentifier/xades:SignaturePolicyId" , namespaces = namespaces
273278 )
274279 if signature_policy_id is not None :
280+ # FIXME: assert on all elements of self.expect_signature_policy
281+ # FIXME: make signature policy into a dataclass
275282 sig_policy_id = self ._find (signature_policy_id , "xades:SigPolicyId" )
276283 identifier = self ._find (sig_policy_id , "xades:Identifier" )
284+ if identifier .text != self .expect_signature_policy ["Identifier" ]:
285+ raise InvalidInput (
286+ f"Expected to find signature policy identifier { self .expect_signature_policy ['Identifier' ]} , "
287+ f"but found { identifier .text } "
288+ )
277289 sig_policy_hash = self ._find (signature_policy_id , "xades:SigPolicyHash" )
278- digest_alg = self ._find (sig_policy_hash , "DigestMethod" ).get ("Algorithm" )
290+ digest_alg = digest_algorithms (self ._find (sig_policy_hash , "DigestMethod" ).get ("Algorithm" ))
291+ if digest_alg != self .expect_signature_policy ["DigestMethod" ]:
292+ raise InvalidInput (
293+ f"Expected to find signature digest algorithm { self .expect_signature_policy ['DigestMethod' ]} , "
294+ f"but found { digest_alg } "
295+ )
279296 digest_value = self ._find (sig_policy_hash , "DigestValue" )
280- if b64decode (digest_value .text ) != self ._get_digest (
281- identifier .text .encode (), self ._get_digest_method (digest_alg )
282- ):
283- pass # FIXME
284- # raise InvalidDigest("Digest mismatch for signature policy hash")
297+ if b64decode (digest_value .text ) != b64decode (self .expect_signature_policy ["DigestValue" ]):
298+ raise InvalidInput ("Digest mismatch for signature policy hash" )
285299
286300 def _verify_signed_properties (self , verify_result ):
301+ self ._verify_signing_time (verify_result )
287302 self ._verify_cert_digests (verify_result )
288- self ._verify_signature_policy (verify_result )
303+ if self .expect_signature_policy :
304+ self ._verify_signature_policy (verify_result )
289305 return self ._find (verify_result .signed_xml , "xades:SignedSignatureProperties" )
290306
291- def verify (self , data , expect_references = 3 , ** kwargs ):
307+ def verify (self , data , expect_signature_policy = None , expect_references = 3 , ** kwargs ):
308+ self .expect_signature_policy = expect_signature_policy
292309 verify_results = super ().verify (data , expect_references = expect_references , ** kwargs )
293310 for i , verify_result in enumerate (verify_results ):
294311 if verify_result .signed_xml is None :
@@ -302,5 +319,4 @@ def verify(self, data, expect_references=3, **kwargs):
302319 raise InvalidInput ("Expected to find a xades:SignedProperties element" )
303320
304321 # TODO: assert all mandatory signed properties are set
305- # TODO: add signed properties to verify_result
306322 return verify_results
0 commit comments