Skip to content

Commit 8c426b1

Browse files
Fix key info matching behavior (#287)
Co-authored-by: Andrey Kislyuk <kislyuk@openai.com>
1 parent 3551f61 commit 8c426b1

2 files changed

Lines changed: 24 additions & 4 deletions

File tree

signxml/verifier.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,9 @@ class SignatureConfiguration:
8282
Ignore the presence of a KeyValue element when X509Data is present in the signature and used for verifying.
8383
The presence of both elements is an ambiguity and a security hazard. The public key used to sign the
8484
document is already encoded in the certificate (which is in X509Data), so the verifier must either ignore
85-
KeyValue or make sure it matches what's in the certificate. SignXML does not implement the functionality
86-
necessary to match the keys, and throws an InvalidInput error instead. Set this to True to bypass the error
87-
and validate the signature using X509Data only.
85+
KeyValue or make sure it matches what's in the certificate. When set to ``False``, SignXML compares KeyValue
86+
(and DEREncodedKeyValue) against the X.509 certificate and raises InvalidInput on mismatch. Set this to
87+
``True`` to bypass the check and validate the signature using X509Data only.
8888
"""
8989

9090
default_reference_c14n_method: CanonicalizationMethod = CanonicalizationMethod.CANONICAL_XML_1_1
@@ -261,7 +261,7 @@ def get_cert_chain_verifier(self, ca_pem_file):
261261
return X509CertChainVerifier(ca_pem_file=ca_pem_file)
262262

263263
def _match_key_values(self, key_value, der_encoded_key_value, signing_cert, signature_alg):
264-
if self.config.ignore_ambiguous_key_info is False:
264+
if self.config.ignore_ambiguous_key_info is True:
265265
return
266266
cert_pub_key = signing_cert.public_key()
267267
# If both X509Data and KeyValue are present, match one against the other and raise an error on mismatch

test/test.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,26 @@ def _build_transforms_for_reference(transforms_node, reference, exclude_c14n_tra
648648
def test_excision_of_untrusted_comments(self):
649649
pass # TODO: test comments excision
650650

651+
def test_mismatched_key_value_with_x509_data(self):
652+
crt, key = self.load_example_keys()
653+
data = etree.parse(os.path.join(os.path.dirname(__file__), "example.xml")).getroot()
654+
signer = XMLSigner()
655+
signed = signer.sign(data, key=key, cert=crt, always_add_key_value=True)
656+
key_info = signed.find(".//ds:KeyInfo", namespaces=namespaces)
657+
key_value = key_info.find("ds:KeyValue", namespaces=namespaces)
658+
key_info.remove(key_value)
659+
mismatched_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
660+
signer._serialize_key_value(mismatched_key, key_info)
661+
signed_xml = etree.tostring(signed)
662+
663+
with self.assertRaisesRegex(
664+
InvalidInput,
665+
"Both X509Data and KeyValue found and they represent different public keys",
666+
):
667+
XMLVerifier().verify(signed_xml, x509_cert=crt)
668+
669+
XMLVerifier().verify(signed_xml, x509_cert=crt, ignore_ambiguous_key_info=True)
670+
651671
def test_ws_security(self):
652672
wsse_dir = os.path.join(interop_dir, "ws-security", "ws.js")
653673
with open(os.path.join(wsse_dir, "examples", "server_public.pem"), "rb") as fh:

0 commit comments

Comments
 (0)