Skip to content

Commit 9bd6e9e

Browse files
committed
Use distinct default for payload c14n. Fixes #217
1 parent 18f5129 commit 9bd6e9e

File tree

3 files changed

+32
-14
lines changed

3 files changed

+32
-14
lines changed

signxml/signer.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,17 @@ def _unpack(self, data, references: List[SignatureReference]):
374374
references = [SignatureReference(URI="#object")]
375375
return sig_root, doc_root, c14n_inputs, references
376376

377+
def _build_transforms_for_reference(self, *, transforms_node: _Element, reference: SignatureReference):
378+
if self.construction_method == SignatureConstructionMethod.enveloped:
379+
SubElement(transforms_node, ds_tag("Transform"), Algorithm=SignatureConstructionMethod.enveloped.value)
380+
SubElement(transforms_node, ds_tag("Transform"), Algorithm=reference.c14n_method.value)
381+
else:
382+
c14n_xform = SubElement(transforms_node, ds_tag("Transform"), Algorithm=reference.c14n_method.value)
383+
if reference.inclusive_ns_prefixes:
384+
SubElement(
385+
c14n_xform, ec_tag("InclusiveNamespaces"), PrefixList=" ".join(reference.inclusive_ns_prefixes)
386+
)
387+
377388
def _build_sig(self, sig_root, references, c14n_inputs, inclusive_ns_prefixes):
378389
signed_info = SubElement(sig_root, ds_tag("SignedInfo"), nsmap=self.namespaces)
379390
sig_c14n_method = SubElement(signed_info, ds_tag("CanonicalizationMethod"), Algorithm=self.c14n_alg.value)
@@ -388,16 +399,7 @@ def _build_sig(self, sig_root, references, c14n_inputs, inclusive_ns_prefixes):
388399
reference = replace(reference, inclusive_ns_prefixes=inclusive_ns_prefixes)
389400
reference_node = SubElement(signed_info, ds_tag("Reference"), URI=reference.URI)
390401
transforms = SubElement(reference_node, ds_tag("Transforms"))
391-
if self.construction_method == SignatureConstructionMethod.enveloped:
392-
SubElement(transforms, ds_tag("Transform"), Algorithm=SignatureConstructionMethod.enveloped.value)
393-
SubElement(transforms, ds_tag("Transform"), Algorithm=reference.c14n_method.value)
394-
else:
395-
c14n_xform = SubElement(transforms, ds_tag("Transform"), Algorithm=reference.c14n_method.value)
396-
if reference.inclusive_ns_prefixes:
397-
SubElement(
398-
c14n_xform, ec_tag("InclusiveNamespaces"), PrefixList=" ".join(reference.inclusive_ns_prefixes)
399-
)
400-
402+
self._build_transforms_for_reference(transforms_node=transforms, reference=reference)
401403
SubElement(reference_node, ds_tag("DigestMethod"), Algorithm=self.digest_alg.value)
402404
digest_value = SubElement(reference_node, ds_tag("DigestValue"))
403405
payload_c14n = self._c14n(

signxml/verifier.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ class XMLVerifier(XMLSignatureProcessor):
107107
Create a new XML Signature Verifier object, which can be used to verify multiple pieces of data.
108108
"""
109109

110+
_default_reference_c14n_method = CanonicalizationMethod.CANONICAL_XML_1_0
111+
110112
def _get_signature(self, root):
111113
if root.tag == ds_tag("Signature"):
112114
return root
@@ -188,7 +190,7 @@ def _get_inclusive_ns_prefixes(self, transform_node):
188190
else:
189191
return inclusive_namespaces.get("PrefixList").split(" ")
190192

191-
def _apply_transforms(self, payload, transforms_node, signature, c14n_algorithm: CanonicalizationMethod):
193+
def _apply_transforms(self, payload, *, transforms_node: etree._Element, signature: etree._Element):
192194
transforms, c14n_applied = [], False
193195
if transforms_node is not None:
194196
transforms = self._findall(transforms_node, "Transform")
@@ -214,7 +216,7 @@ def _apply_transforms(self, payload, transforms_node, signature, c14n_algorithm:
214216
c14n_applied = True
215217

216218
if not c14n_applied and not isinstance(payload, (str, bytes)):
217-
payload = self._c14n(payload, algorithm=c14n_algorithm)
219+
payload = self._c14n(payload, algorithm=self._default_reference_c14n_method)
218220

219221
return payload
220222

@@ -464,8 +466,7 @@ def _verify_reference(self, reference, index, root, uri_resolver, c14n_algorithm
464466
digest_method_alg_name = self._find(reference, "DigestMethod").get("Algorithm")
465467
digest_value = self._find(reference, "DigestValue")
466468
payload = self._resolve_reference(copied_root, reference, uri_resolver=uri_resolver)
467-
# TODO: payload-specific c14n alg
468-
payload_c14n = self._apply_transforms(payload, transforms, copied_signature_ref, c14n_algorithm)
469+
payload_c14n = self._apply_transforms(payload, transforms_node=transforms, signature=copied_signature_ref)
469470
digest_alg = DigestAlgorithm(digest_method_alg_name)
470471
if digest_alg not in self.config.digest_algorithms:
471472
raise InvalidInput(f"Digest algorithm {digest_alg.name} forbidden by configuration")

test/test.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
methods,
3535
namespaces,
3636
)
37+
from signxml.util import ds_tag # noqa:E402
3738
from signxml.xades import ( # noqa:E402
3839
XAdESDataObjectFormat,
3940
XAdESSignatureConfiguration,
@@ -557,6 +558,20 @@ def test_inclusive_namespaces_signing(self):
557558
"8GPAVJstDxHyuoJqec8C0ssji4zfdXanu1YHGlWbfx0=",
558559
)
559560

561+
# Test correct default c14n method for payload when c14n transform metadata is omitted
562+
def _build_transforms_for_reference(transforms_node, reference):
563+
etree.SubElement(
564+
transforms_node, ds_tag("Transform"), Algorithm=SignatureConstructionMethod.enveloped.value
565+
)
566+
567+
signer._build_transforms_for_reference = _build_transforms_for_reference
568+
signed3 = signer.sign(**sign_args)
569+
self.assertEqual(
570+
signed3.find(".//ds:SignatureValue", namespaces=namespaces).text,
571+
"/iezjApGBVMMUspj5WyZwIOEw30qLX3Gv576vwFMAbQ=",
572+
)
573+
XMLVerifier().verify(signed3, hmac_key=b"secret", require_x509=False, validate_schema=False)
574+
560575
def test_excision_of_untrusted_comments(self):
561576
pass # TODO: test comments excision
562577

0 commit comments

Comments
 (0)