From 7433b08260e2e9c487f14f0770985af6a3b22ecb Mon Sep 17 00:00:00 2001 From: msetina Date: Sat, 16 Mar 2024 16:32:26 +0100 Subject: [PATCH 01/10] Update verifier.py for public_key overwrite --- signxml/verifier.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/signxml/verifier.py b/signxml/verifier.py index 7f43c5a..41a88f9 100644 --- a/signxml/verifier.py +++ b/signxml/verifier.py @@ -503,8 +503,8 @@ def _check_key_value_matches_cert_public_key(self, key_value, public_key, signat ): ec_key_value = self._find(key_value, "dsig11:ECKeyValue") named_curve = self._find(ec_key_value, "dsig11:NamedCurve") - public_key = self._find(ec_key_value, "dsig11:PublicKey") - key_data = b64decode(public_key.text)[1:] + pub_key = self._find(ec_key_value, "dsig11:PublicKey") + key_data = b64decode(pub_key.text)[1:] x = bytes_to_long(key_data[: len(key_data) // 2]) y = bytes_to_long(key_data[len(key_data) // 2 :]) curve_class = self.known_ecdsa_curves[named_curve.get("URI")] From 7bd46d07b8bed474bf2a94c67861e25a1f90b499 Mon Sep 17 00:00:00 2001 From: msetina Date: Mon, 18 Mar 2024 17:48:09 +0100 Subject: [PATCH 02/10] certDigest verification by list number --- signxml/xades/xades.py | 47 +++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/signxml/xades/xades.py b/signxml/xades/xades.py index 1149a61..363340b 100644 --- a/signxml/xades/xades.py +++ b/signxml/xades/xades.py @@ -272,33 +272,34 @@ class XAdESVerifier(XAdESProcessor, XMLVerifier): def _verify_signing_time(self, verify_result: VerifyResult): pass - def _verify_cert_digest(self, signing_cert_node, expect_cert): - for cert in self._findall(signing_cert_node, "xades:Cert"): - cert_digest = self._find(cert, "xades:CertDigest") - digest_alg = DigestAlgorithm(self._find(cert_digest, "DigestMethod").get("Algorithm")) - digest_value = self._find(cert_digest, "DigestValue") - # check spec for specific method of retrieving cert - der_encoded_cert = dump_certificate(FILETYPE_ASN1, expect_cert) + def _verify_cert_digest(self, signing_cert_node, expect_cert,idx): + cert = self._find(signing_cert_node, "xades:Cert[{0}]".format(idx): + cert_digest = self._find(cert, "xades:CertDigest") + digest_alg = DigestAlgorithm(self._find(cert_digest, "DigestMethod").get("Algorithm")) + digest_value = self._find(cert_digest, "DigestValue") + # check spec for specific method of retrieving cert + der_encoded_cert = dump_certificate(FILETYPE_ASN1, expect_cert) - if b64decode(digest_value.text) != self._get_digest(der_encoded_cert, algorithm=digest_alg): - raise InvalidDigest("Digest mismatch for certificate digest") + if b64decode(digest_value.text) != self._get_digest(der_encoded_cert, algorithm=digest_alg): + raise InvalidDigest("Digest mismatch for certificate digest") def _verify_cert_digests(self, verify_result: VerifyResult): x509_data = verify_result.signature_xml.find("ds:KeyInfo/ds:X509Data", namespaces=namespaces) - cert_from_key_info = load_certificate( - FILETYPE_PEM, add_pem_header(self._find(x509_data, "X509Certificate").text) - ) - signed_signature_props = self._find(verify_result.signed_xml, "xades:SignedSignatureProperties") - signing_cert = self._find(signed_signature_props, "xades:SigningCertificate", require=False) - signing_cert_v2 = self._find(signed_signature_props, "xades:SigningCertificateV2", require=False) - if signing_cert is None and signing_cert_v2 is None: - raise InvalidInput("Expected to find XML element xades:SigningCertificate or xades:SigningCertificateV2") - if signing_cert is not None and signing_cert_v2 is not None: - raise InvalidInput("Expected to find exactly one of xades:SigningCertificate or xades:SigningCertificateV2") - if signing_cert is not None: - self._verify_cert_digest(signing_cert, expect_cert=cert_from_key_info) - elif signing_cert_v2 is not None: - self._verify_cert_digest(signing_cert_v2, expect_cert=cert_from_key_info) + for idx,x_cert in enumerate(self._findall(x509_data, "X509Certificate")): + cert_from_key_info = load_certificate( + FILETYPE_PEM, add_pem_header(x_cert.text) + ) + signed_signature_props = self._find(verify_result.signed_xml, "xades:SignedSignatureProperties") + signing_cert = self._find(signed_signature_props, "xades:SigningCertificate", require=False) + signing_cert_v2 = self._find(signed_signature_props, "xades:SigningCertificateV2", require=False) + if signing_cert is None and signing_cert_v2 is None: + raise InvalidInput("Expected to find XML element xades:SigningCertificate or xades:SigningCertificateV2") + if signing_cert is not None and signing_cert_v2 is not None: + raise InvalidInput("Expected to find exactly one of xades:SigningCertificate or xades:SigningCertificateV2") + if signing_cert is not None: + self._verify_cert_digest(signing_cert, expect_cert=cert_from_key_info,idx=idx) + elif signing_cert_v2 is not None: + self._verify_cert_digest(signing_cert_v2, expect_cert=cert_from_key_info,idx=idx) def _verify_signature_policy(self, verify_result: VerifyResult, expect_signature_policy: XAdESSignaturePolicy): signed_signature_props = self._find(verify_result.signed_xml, "xades:SignedSignatureProperties") From a1be6d939db436ca583ed806806e822118bd31d8 Mon Sep 17 00:00:00 2001 From: msetina Date: Mon, 18 Mar 2024 17:51:04 +0100 Subject: [PATCH 03/10] fix spelling --- signxml/xades/xades.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/signxml/xades/xades.py b/signxml/xades/xades.py index 363340b..b8b7848 100644 --- a/signxml/xades/xades.py +++ b/signxml/xades/xades.py @@ -273,7 +273,7 @@ def _verify_signing_time(self, verify_result: VerifyResult): pass def _verify_cert_digest(self, signing_cert_node, expect_cert,idx): - cert = self._find(signing_cert_node, "xades:Cert[{0}]".format(idx): + cert = self._find(signing_cert_node, "xades:Cert[{0}]".format(idx)) cert_digest = self._find(cert, "xades:CertDigest") digest_alg = DigestAlgorithm(self._find(cert_digest, "DigestMethod").get("Algorithm")) digest_value = self._find(cert_digest, "DigestValue") From badc8a86e4a386b53399093b452b238d3ffaf186 Mon Sep 17 00:00:00 2001 From: msetina Date: Mon, 18 Mar 2024 17:54:40 +0100 Subject: [PATCH 04/10] one based index --- signxml/xades/xades.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/signxml/xades/xades.py b/signxml/xades/xades.py index b8b7848..030abc0 100644 --- a/signxml/xades/xades.py +++ b/signxml/xades/xades.py @@ -297,9 +297,9 @@ def _verify_cert_digests(self, verify_result: VerifyResult): if signing_cert is not None and signing_cert_v2 is not None: raise InvalidInput("Expected to find exactly one of xades:SigningCertificate or xades:SigningCertificateV2") if signing_cert is not None: - self._verify_cert_digest(signing_cert, expect_cert=cert_from_key_info,idx=idx) + self._verify_cert_digest(signing_cert, expect_cert=cert_from_key_info,idx=idx+1) elif signing_cert_v2 is not None: - self._verify_cert_digest(signing_cert_v2, expect_cert=cert_from_key_info,idx=idx) + self._verify_cert_digest(signing_cert_v2, expect_cert=cert_from_key_info,idx=idx+1) def _verify_signature_policy(self, verify_result: VerifyResult, expect_signature_policy: XAdESSignaturePolicy): signed_signature_props = self._find(verify_result.signed_xml, "xades:SignedSignatureProperties") From 42665f0f7ec3f9aa72d1e3186a97265f6d6e7d1c Mon Sep 17 00:00:00 2001 From: msetina Date: Mon, 18 Mar 2024 19:47:19 +0100 Subject: [PATCH 05/10] make black happier --- signxml/xades/xades.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/signxml/xades/xades.py b/signxml/xades/xades.py index 030abc0..5632b2e 100644 --- a/signxml/xades/xades.py +++ b/signxml/xades/xades.py @@ -272,7 +272,7 @@ class XAdESVerifier(XAdESProcessor, XMLVerifier): def _verify_signing_time(self, verify_result: VerifyResult): pass - def _verify_cert_digest(self, signing_cert_node, expect_cert,idx): + def _verify_cert_digest(self, signing_cert_node, expect_cert, idx): cert = self._find(signing_cert_node, "xades:Cert[{0}]".format(idx)) cert_digest = self._find(cert, "xades:CertDigest") digest_alg = DigestAlgorithm(self._find(cert_digest, "DigestMethod").get("Algorithm")) @@ -285,21 +285,23 @@ def _verify_cert_digest(self, signing_cert_node, expect_cert,idx): def _verify_cert_digests(self, verify_result: VerifyResult): x509_data = verify_result.signature_xml.find("ds:KeyInfo/ds:X509Data", namespaces=namespaces) - for idx,x_cert in enumerate(self._findall(x509_data, "X509Certificate")): - cert_from_key_info = load_certificate( - FILETYPE_PEM, add_pem_header(x_cert.text) - ) + for idx, x_cert in enumerate(self._findall(x509_data, "X509Certificate")): + cert_from_key_info = load_certificate(FILETYPE_PEM, add_pem_header(x_cert.text)) signed_signature_props = self._find(verify_result.signed_xml, "xades:SignedSignatureProperties") signing_cert = self._find(signed_signature_props, "xades:SigningCertificate", require=False) signing_cert_v2 = self._find(signed_signature_props, "xades:SigningCertificateV2", require=False) if signing_cert is None and signing_cert_v2 is None: - raise InvalidInput("Expected to find XML element xades:SigningCertificate or xades:SigningCertificateV2") + raise InvalidInput( + "Expected to find XML element xades:SigningCertificate or xades:SigningCertificateV2" + ) if signing_cert is not None and signing_cert_v2 is not None: - raise InvalidInput("Expected to find exactly one of xades:SigningCertificate or xades:SigningCertificateV2") + raise InvalidInput( + "Expected to find exactly one of xades:SigningCertificate or xades:SigningCertificateV2" + ) if signing_cert is not None: - self._verify_cert_digest(signing_cert, expect_cert=cert_from_key_info,idx=idx+1) + self._verify_cert_digest(signing_cert, expect_cert=cert_from_key_info, idx=(idx+1)) elif signing_cert_v2 is not None: - self._verify_cert_digest(signing_cert_v2, expect_cert=cert_from_key_info,idx=idx+1) + self._verify_cert_digest(signing_cert_v2, expect_cert=cert_from_key_info, idx=(idx+1)) def _verify_signature_policy(self, verify_result: VerifyResult, expect_signature_policy: XAdESSignaturePolicy): signed_signature_props = self._find(verify_result.signed_xml, "xades:SignedSignatureProperties") From 079ab592ae300d1729b2c4d5a285d93abd3c0e6e Mon Sep 17 00:00:00 2001 From: msetina Date: Mon, 18 Mar 2024 19:49:59 +0100 Subject: [PATCH 06/10] make black happy --- signxml/xades/xades.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/signxml/xades/xades.py b/signxml/xades/xades.py index 5632b2e..89e452e 100644 --- a/signxml/xades/xades.py +++ b/signxml/xades/xades.py @@ -299,9 +299,9 @@ def _verify_cert_digests(self, verify_result: VerifyResult): "Expected to find exactly one of xades:SigningCertificate or xades:SigningCertificateV2" ) if signing_cert is not None: - self._verify_cert_digest(signing_cert, expect_cert=cert_from_key_info, idx=(idx+1)) + self._verify_cert_digest(signing_cert, expect_cert=cert_from_key_info, idx=(idx + 1)) elif signing_cert_v2 is not None: - self._verify_cert_digest(signing_cert_v2, expect_cert=cert_from_key_info, idx=(idx+1)) + self._verify_cert_digest(signing_cert_v2, expect_cert=cert_from_key_info, idx=(idx + 1)) def _verify_signature_policy(self, verify_result: VerifyResult, expect_signature_policy: XAdESSignaturePolicy): signed_signature_props = self._find(verify_result.signed_xml, "xades:SignedSignatureProperties") From 6352c7861e076c999c3431990b8926b4927ee986 Mon Sep 17 00:00:00 2001 From: msetina Date: Mon, 18 Mar 2024 22:30:18 +0100 Subject: [PATCH 07/10] Ignore if missing CertDigest --- signxml/xades/xades.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/signxml/xades/xades.py b/signxml/xades/xades.py index 89e452e..efa3ec1 100644 --- a/signxml/xades/xades.py +++ b/signxml/xades/xades.py @@ -273,15 +273,16 @@ def _verify_signing_time(self, verify_result: VerifyResult): pass def _verify_cert_digest(self, signing_cert_node, expect_cert, idx): - cert = self._find(signing_cert_node, "xades:Cert[{0}]".format(idx)) - cert_digest = self._find(cert, "xades:CertDigest") - digest_alg = DigestAlgorithm(self._find(cert_digest, "DigestMethod").get("Algorithm")) - digest_value = self._find(cert_digest, "DigestValue") - # check spec for specific method of retrieving cert - der_encoded_cert = dump_certificate(FILETYPE_ASN1, expect_cert) - - if b64decode(digest_value.text) != self._get_digest(der_encoded_cert, algorithm=digest_alg): - raise InvalidDigest("Digest mismatch for certificate digest") + cert = self._find(signing_cert_node, "xades:Cert[{0}]".format(idx), False) + if cert != None: + cert_digest = self._find(cert, "xades:CertDigest") + digest_alg = DigestAlgorithm(self._find(cert_digest, "DigestMethod").get("Algorithm")) + digest_value = self._find(cert_digest, "DigestValue") + # check spec for specific method of retrieving cert + der_encoded_cert = dump_certificate(FILETYPE_ASN1, expect_cert) + + if b64decode(digest_value.text) != self._get_digest(der_encoded_cert, algorithm=digest_alg): + raise InvalidDigest("Digest mismatch for certificate digest") def _verify_cert_digests(self, verify_result: VerifyResult): x509_data = verify_result.signature_xml.find("ds:KeyInfo/ds:X509Data", namespaces=namespaces) From 3132e15e542e219c6ce67b6b6123b59f053d694d Mon Sep 17 00:00:00 2001 From: msetina Date: Tue, 19 Mar 2024 08:39:12 +0100 Subject: [PATCH 08/10] Removed error_condition that is no longer error --- test/test.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/test.py b/test/test.py index 69782d1..d178792 100755 --- a/test/test.py +++ b/test/test.py @@ -739,8 +739,7 @@ def test_xades_interop_examples(self): "unsupported-signature-algorithm": InvalidInput, "corrupted-cert": etree.DocumentInvalid, # FIXME - flaky validation "cert-v2-wrong-digest": InvalidDigest, - "wrong-sign-cert-digest": InvalidDigest, - "nonconformant-X_BE_CONN_10": InvalidDigest, + "wrong-sign-cert-digest": InvalidDigest, "sigPolStore-noDigest": InvalidInput, } for sig_file in glob(os.path.join(os.path.dirname(__file__), "xades", "*.xml")): From 05004621d62e5073d8c95fca8615e72931e2c8ea Mon Sep 17 00:00:00 2001 From: msetina Date: Tue, 19 Mar 2024 08:43:47 +0100 Subject: [PATCH 09/10] making black happy --- test/test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test.py b/test/test.py index d178792..2992101 100755 --- a/test/test.py +++ b/test/test.py @@ -739,7 +739,7 @@ def test_xades_interop_examples(self): "unsupported-signature-algorithm": InvalidInput, "corrupted-cert": etree.DocumentInvalid, # FIXME - flaky validation "cert-v2-wrong-digest": InvalidDigest, - "wrong-sign-cert-digest": InvalidDigest, + "wrong-sign-cert-digest": InvalidDigest, "sigPolStore-noDigest": InvalidInput, } for sig_file in glob(os.path.join(os.path.dirname(__file__), "xades", "*.xml")): From a34ee6eda4aa538ab768e28a3f7d9a31ed0e5a58 Mon Sep 17 00:00:00 2001 From: msetina Date: Tue, 19 Mar 2024 08:47:06 +0100 Subject: [PATCH 10/10] helping lint to better place --- signxml/xades/xades.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/signxml/xades/xades.py b/signxml/xades/xades.py index efa3ec1..6ffcb63 100644 --- a/signxml/xades/xades.py +++ b/signxml/xades/xades.py @@ -274,7 +274,7 @@ def _verify_signing_time(self, verify_result: VerifyResult): def _verify_cert_digest(self, signing_cert_node, expect_cert, idx): cert = self._find(signing_cert_node, "xades:Cert[{0}]".format(idx), False) - if cert != None: + if cert is not None: cert_digest = self._find(cert, "xades:CertDigest") digest_alg = DigestAlgorithm(self._find(cert_digest, "DigestMethod").get("Algorithm")) digest_value = self._find(cert_digest, "DigestValue")