|
29 | 29 |
|
30 | 30 | from lxml.etree import SubElement, _Element
|
31 | 31 | from OpenSSL.crypto import FILETYPE_ASN1, FILETYPE_PEM, X509, dump_certificate, load_certificate
|
| 32 | +from tsp_client import TSPVerifier |
32 | 33 |
|
33 | 34 | from .. import SignatureConfiguration, VerifyResult, XMLSignatureProcessor, XMLSigner, XMLVerifier
|
34 | 35 | from ..algorithms import DigestAlgorithm
|
@@ -264,9 +265,31 @@ class XAdESVerifier(XAdESProcessor, XMLVerifier):
|
264 | 265 | """
|
265 | 266 |
|
266 | 267 | # TODO: document/support SignatureTimeStamp / timestamp attestation
|
| 268 | + # TODO: allow setting required attributes, including timestamp |
267 | 269 | # SignatureTimeStamp is required by certain profiles but is an unsigned property
|
268 |
| - def _verify_signing_time(self, verify_result: VerifyResult): |
269 |
| - pass |
| 270 | + |
| 271 | + def _verify_signing_time(self, verify_result: VerifyResult, all_verify_results: List[VerifyResult]): |
| 272 | + """ |
| 273 | + The Implicit mechanism (see clause 5.1.4.4.1) shall be used for generating this qualifying property. |
| 274 | + The input to the computation of the message imprint shall be the result of processing all the ds:Reference |
| 275 | + elements within the ds:SignedInfo except the one referencing the SignedProperties element, in their order of |
| 276 | + appearance, as follows: |
| 277 | + 1) process the retrieved ds:Reference element according to the reference-processing model of XMLDSIG [1] |
| 278 | + clause 4.4.3.2; |
| 279 | + 2) if the result is a XML node set, canonicalize it as specified in clause 4.5; and |
| 280 | + 3) concatenate the resulting octets to those resulting from previously processed ds:Reference elements in |
| 281 | + ds:SignedInfo. |
| 282 | + """ |
| 283 | + ts_path = "xades:SignedDataObjectProperties/xades:AllDataObjectsTimeStamp/xades:EncapsulatedTimeStamp" |
| 284 | + if verify_result.signed_xml is None: |
| 285 | + return |
| 286 | + all_data_objs_ts = verify_result.signed_xml.find(ts_path, namespaces=namespaces) |
| 287 | + if all_data_objs_ts is None: |
| 288 | + return |
| 289 | + print("Will verify", all_data_objs_ts.text) |
| 290 | + ts = b64decode(all_data_objs_ts.text) # type: ignore |
| 291 | + tsp_message = b"".join(r.signed_data for r in all_verify_results if r != verify_result) |
| 292 | + TSPVerifier().verify(ts, message=tsp_message) |
270 | 293 |
|
271 | 294 | def _verify_cert_digest(self, signing_cert_node, expect_cert):
|
272 | 295 | for cert in self._findall(signing_cert_node, "xades:Cert"):
|
@@ -320,8 +343,8 @@ def _verify_signature_policy(self, verify_result: VerifyResult, expect_signature
|
320 | 343 | if b64decode(digest_value.text) != b64decode(expect_signature_policy.DigestValue):
|
321 | 344 | raise InvalidInput("Digest mismatch for signature policy hash")
|
322 | 345 |
|
323 |
| - def _verify_signed_properties(self, verify_result): |
324 |
| - self._verify_signing_time(verify_result) |
| 346 | + def _verify_signed_properties(self, verify_result, *, all_verify_results): |
| 347 | + self._verify_signing_time(verify_result, all_verify_results=all_verify_results) |
325 | 348 | self._verify_cert_digests(verify_result)
|
326 | 349 | if self.expect_signature_policy:
|
327 | 350 | self._verify_signature_policy(
|
@@ -364,7 +387,8 @@ def verify( # type: ignore
|
364 | 387 | continue
|
365 | 388 | if verify_result.signed_xml.tag == xades_tag("SignedProperties"):
|
366 | 389 | verify_results[i] = XAdESVerifyResult( # type: ignore
|
367 |
| - *astuple(verify_result), signed_properties=self._verify_signed_properties(verify_result) |
| 390 | + *astuple(verify_result), |
| 391 | + signed_properties=self._verify_signed_properties(verify_result, all_verify_results=verify_results), |
368 | 392 | )
|
369 | 393 | break
|
370 | 394 | else:
|
|
0 commit comments