Problem
A Reference whose transforms put enveloped-signature after a canonicalization, such as [exc-c14n, enveloped-signature], signs and verifies. The canonicalization returns octets, the library parses them into a new document for the next transform (src/signed-xml.ts#L1452-L1474), and enveloped-signature removes the Signature it finds there by its SignatureValue.
XMLDSig doesn't allow that for this transform:
- §6.6.4: the transform "may only be applied to a node-set from its parent XML document", and it must produce the output of an XPath transform that uses
here().
- §6.6.3:
here() "results in an error if the containing XPath expression does not appear in the same XML document against which the XPath expression is being evaluated".
§4.4.3.2 says to parse octets when the next transform needs a node-set. That rule is general, and §6.6.4 excludes this transform from it. #585 added support for the order on the strength of §4.4.3.2 alone.
Other implementations
I signed <root><x>1</x></root> with master (fe2d091), URI="", in both orders:
| Verifier |
[enveloped-signature, exc-c14n] |
[exc-c14n, enveloped-signature] |
xml-crypto master |
valid |
valid |
.NET System.Security.Cryptography.Xml 6.0.1 |
valid |
valid |
JDK 21 javax.xml.crypto.dsig |
valid |
invalid: the reference digest doesn't match |
| xmlsec |
not run |
not run; its source returns XMLSEC_ERRORS_R_TRANSFORM_SAME_DOCUMENT_REQUIRED |
A signature this library creates in that order verifies with .NET and with xml-crypto 6.2.0 or later, and nowhere else I checked. Since 6.2.0 the library's own round trip passes, so the signer gets no sign that anything is wrong. Before 6.2.0 the round trip failed, which is how #111 was reported. That reporter fixed their code by listing enveloped-signature first, and asked for an error if the order is standardized.
This is a conformance problem, not a bypass. #585 removes only the Signature being verified and refuses a document that carries its SignatureValue twice.
In 6.x
#649 deprecates the order in 6.4 (#648). Applying enveloped-signature after octets were parsed prints the DeprecationWarning XML_CRYPTO_ENVELOPED_SIGNATURE_AFTER_CANONICALIZATION, when signing and when verifying, and the README says to list enveloped-signature first.
Proposal
In 7.0, throw when enveloped-signature is applied after an earlier transform of the same Reference returned octets. That covers computeSignature(), checkSignature() and getCanonXml(). The error should name the transform order and §6.6.4.
Then remove what only that order needs:
- the lookup of the loaded signature in a re-parsed document, in
canonicalize()
- the deprecation warning, and the README paragraph that describes the order
- the tests that sign or verify it, and the fixtures
dotnet_enveloped_signature_after_exc_c14n.xml, dotnet_enveloped_signature_after_c14n.xml and inclusive_namespaces_enveloped_signature_after_exc_c14n.xml
inclusive_namespaces_on_second_of_two_exc_c14n.xml, which uses the order to cover per-transform PrefixLists and needs a replacement signed as [enveloped-signature, exc-c14n, exc-c14n PrefixList="b"]
Parsing octets for other transforms stays: a canonicalization followed by another canonicalization or by a custom transform is the §4.4.3.2 case.
Signatures in this order stop verifying, whether a .NET caller or xml-crypto 6.2.0–6.3.x created them, so this belongs in 7.0.
Problem
A
Referencewhose transforms putenveloped-signatureafter a canonicalization, such as[exc-c14n, enveloped-signature], signs and verifies. The canonicalization returns octets, the library parses them into a new document for the next transform (src/signed-xml.ts#L1452-L1474), andenveloped-signatureremoves theSignatureit finds there by itsSignatureValue.XMLDSig doesn't allow that for this transform:
here().here()"results in an error if the containing XPath expression does not appear in the same XML document against which the XPath expression is being evaluated".§4.4.3.2 says to parse octets when the next transform needs a node-set. That rule is general, and §6.6.4 excludes this transform from it. #585 added support for the order on the strength of §4.4.3.2 alone.
Other implementations
I signed
<root><x>1</x></root>withmaster(fe2d091),URI="", in both orders:[enveloped-signature, exc-c14n][exc-c14n, enveloped-signature]masterSystem.Security.Cryptography.Xml6.0.1javax.xml.crypto.dsigXMLSEC_ERRORS_R_TRANSFORM_SAME_DOCUMENT_REQUIREDA signature this library creates in that order verifies with .NET and with xml-crypto 6.2.0 or later, and nowhere else I checked. Since 6.2.0 the library's own round trip passes, so the signer gets no sign that anything is wrong. Before 6.2.0 the round trip failed, which is how #111 was reported. That reporter fixed their code by listing
enveloped-signaturefirst, and asked for an error if the order is standardized.This is a conformance problem, not a bypass. #585 removes only the
Signaturebeing verified and refuses a document that carries itsSignatureValuetwice.In 6.x
#649 deprecates the order in 6.4 (#648). Applying
enveloped-signatureafter octets were parsed prints theDeprecationWarningXML_CRYPTO_ENVELOPED_SIGNATURE_AFTER_CANONICALIZATION, when signing and when verifying, and the README says to listenveloped-signaturefirst.Proposal
In 7.0, throw when
enveloped-signatureis applied after an earlier transform of the sameReferencereturned octets. That coverscomputeSignature(),checkSignature()andgetCanonXml(). The error should name the transform order and §6.6.4.Then remove what only that order needs:
canonicalize()dotnet_enveloped_signature_after_exc_c14n.xml,dotnet_enveloped_signature_after_c14n.xmlandinclusive_namespaces_enveloped_signature_after_exc_c14n.xmlinclusive_namespaces_on_second_of_two_exc_c14n.xml, which uses the order to cover per-transformPrefixLists and needs a replacement signed as[enveloped-signature, exc-c14n, exc-c14n PrefixList="b"]Parsing octets for other transforms stays: a canonicalization followed by another canonicalization or by a custom transform is the §4.4.3.2 case.
Signatures in this order stop verifying, whether a .NET caller or xml-crypto 6.2.0–6.3.x created them, so this belongs in 7.0.