Skip to content

Add options to exclude the C14N Transform element in signatures #274

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 26, 2025

Conversation

tjeb
Copy link
Contributor

@tjeb tjeb commented Jun 25, 2025

This patch adds a flag 'exclude_c14n_transform_element' (boolean, defaults to False) to XMLSigner.sign().

If set to True, the transform is still applied, but it is not added to the Transforms element in ds:SignedInfo/ds:Reference.

Conversely, this patch adds an option to XMLVerifier.verify() to specify a default canonicalization algorithm in the case where SignedInfo does not include the c14n Transform information.

Rationale:

In most cases, the Transforms element should indeed contain every modification made to the source data before creating or verifying the signature, and indeed, the necessity to add a default algorithm in verify() shows why. However, there are specifications that make use of XML Signatures, where the canonicalization algorithm is fixed, and which even go so far as to forbid naming the c14n algorithm in the Transforms element.

This patch aims to make it possible to support those specifications.

This patch adds a flag 'exclude_c14n_transform_element' (boolean, defaults to False) to XMLSigner.sign().

If set to True, the transform is still applied, but it is not added to the Transforms element in ds:SignedInfo/ds:Reference.

Conversely, this patch adds an option to XMLVerifier.verify() to specify a default canonicalization algorithm in the case where SignedInfo does not include the c14n Transform information.

Rationale:

In most cases, the Transforms element should indeed contain every modification made to the source data before creating or verifying the signature, and indeed, the necessity to add a default algorithm in verify() shows why. However, there are specifications that make use of XML Signatures, where the canonicalization algorithm is fixed, and which even go so far as to forbid naming the c14n algorithm in the Transforms element.

This patch aims to make it possible to support those specifications.
@tjeb
Copy link
Contributor Author

tjeb commented Jun 25, 2025

And while I had searched the open issues I failed to notice there was a similar (old) PR to do this already... my apologies.

My problem isn't with any implementation, though, but with a specification, namely this one:

https://docs.peppol.eu/edelivery/smp/Peppol-EDN-Service-Metadata-Publishing-1.4.0-2025-02-06.pdf

Which states (section 5.5.1):

And yes, I think the first one is a rather bad requirement, but as of right now, it is what is is, unfortunately.

Perhaps subclassing is indeed the way to go, though i'm generally weary of overriding _methods()...

@kislyuk
Copy link
Member

kislyuk commented Jun 25, 2025

@tjeb thanks for your contribution. This implementation is much better than #104 for many reasons. You produced the references I asked for, you limited your changes to the specific feature needed, you incorporated your changes into both the signer and the verifier, and you made new standalone test cases for both values of the new setting.

I'm happy to merge this, but I'd like to ask for a couple small tweaks:

  • ruff is failing, please fix
  • in the verifier, let's move the new setting to the SignatureConfiguration dataclass instead of passing it as another kwarg
  • in the verifier, can we change the behavior of the new setting to assert the absence of a c14n algorithm transform and set the specified algorithm? Verification is the most security critical step that this library provides, and it's much easier to analyze the security of it when it makes an assertion instead of just setting a default.

Rather than a named argument, the option which default c14n method should be used for references can now be set as a SignatureConfiguration value

Additional changes:
- ruff formatted the changes from the previous commit
- amended the test to also test for a scenario where verification would
  fail
@tjeb
Copy link
Contributor Author

tjeb commented Jun 25, 2025

Addressed the first 2 points; for the second, I have lifted the existing hard-coded _default_reference_c14n_method as a whole into SignatureConfiguration, and simply use that. Makes the resulting code more like the original one (but now with a configurable algorithm, and the copy-node-tree trick I copied from the code above).

I did change the default to CANONICAL_XML_1_1 (it was 1_0), because this PR surfaced a discrepancy between the defaults of the signer and that of the verifier. If it is important that this remains at 1_0 I have no problem changing that back.

I also amended the test a bit, to actually trigger a failed verification because of c14n.

The only issue I have is with the third point: I understand asserting this would be good, but I'm not sure how, and more importantly, what to do when that fails.

BTW, in the meantime I also had a discussion with one of the authors of the specification I'm implementing, and I may have convinced them that the spec is wrong. So at some point in the future there is a chance that my personal use-case for this PR will disappear. Though given that there was a similar PR there may be other use-cases.

@kislyuk
Copy link
Member

kislyuk commented Jun 26, 2025

This is great, thanks! Looking at the code, my point 3 was a bit incoherent, as there already is a default, so you're right that there is no guidance as to what to do when the c14n transform node is missing. Merging.

@kislyuk kislyuk merged commit f956538 into XML-Security:main Jun 26, 2025
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants