Skip to content

[SANTUARIO-615] xades extension implementation - #617

Open
jrihtarsic wants to merge 7 commits into
apache:mainfrom
jrihtarsic:feature/SANTUARIO-615-XADES-extension
Open

jrihtarsic wants to merge 7 commits into
apache:mainfrom
jrihtarsic:feature/SANTUARIO-615-XADES-extension

Conversation

@jrihtarsic

Copy link
Copy Markdown
Contributor

The purpose of this PR is to implement XAdES support using the pre/post‑processing mechanism for XML signatures introduced in the previous PR 616. This work addresses the XAdES requirements described in SANTUARIO‑402 and SANTUARIO‑416, and currently covers the Basic Signatures profile.

For composing the XAdES structures, the implementation uses JAXB‑generated classes based on the XAdES schema versions 1.4.1 and 1.3.2, combined with Santuario’s internal ElementProxy model.

@jrihtarsic jrihtarsic changed the title Feature/santuario 615 xades extension [SANTUARIO-615] xades extension implementation Jun 16, 2026
@jrihtarsic

Copy link
Copy Markdown
Contributor Author

Hi @coheigea

Is it possible
To review the following two PRs regarding XAdES-B
First this one:
#616 - adds the feature to be able to implement pre/post processors to the signature

And then this:
#617 - This PR builds on the feature introduced in PR 616 and provides an implementation of the XAdES‑B profile.

In the second M 617 R I also added a tool
src/test/java/org/apache/xml/security/testutils/SelfSignedCertGenerator.java

which generates simple test certificates on the fly so that there is no need to add new keystore/truststore binaries for new key types. The tool is intentionally minimal, has no external dependencies, and is reusable for future work, including for the future contributions on Post‑Quantum Cryptography.
I created it because Mr. @seanjmullan previously raised concerns when I added keystores for the X25519/X448 and EdDSA use-cases, and this now serves as the alternative.

@coheigea

Copy link
Copy Markdown
Contributor

@jrihtarsic Please resolve the conflicts

@jrihtarsic

Copy link
Copy Markdown
Contributor Author

@coheigea the conflict is resolved now.

ffang added a commit to ffang/santuario-xml-security-java that referenced this pull request Aug 21, 2026
Adds ML-DSA-44/65/87 XML digital signature support via the JSR-105
API (DOM) and the STAX signature path, wired through JCEMapper and
the JSR-105 provider's algorithm URI registrations. Part of the
post-quantum work tracked under SANTUARIO-634 (originally proposed
in SANTUARIO-633 / apache#645), split
out here as the signature-only half per community request.

- The ML-DSA test keystore is generated on the fly per test run
  instead of a committed PKCS12 binary, avoiding the maintenance
  burden of binary test fixtures. Uses SelfSignedCertGenerator,
  originally authored by Joze Rihtarsic (unmerged PR apache#617), copied
  in and extended here with ML-DSA-44/65/87 AlgorithmIdentifier
  support per his suggestion on apache#645.
- Adds negative-test coverage on both the DOM/JSR-105 and STAX
  paths: a tampered SignatureValue is rejected, and verification
  against the wrong public key fails. Added per Arpan0995's review
  feedback on apache#645.
@jrihtarsic

Copy link
Copy Markdown
Contributor Author

Hi @coheigea is Can this PR be merged or is there any open requirements i should tackle to finish this task?

@coheigea

Copy link
Copy Markdown
Contributor

@jrihtarsic Can you review if this analysis is valid or not please?

XAdES Qualifying-Properties Spoofing via Unsigned ds:Object Injection — XAdESBBValidator.java:749 and XAdESBBValidator.java:808
Severity: High
Category: signature_validation_bypass (XML Signature Wrapping variant)
Description: XAdESBBValidator.validate() locates the xades132:QualifyingProperties element to validate via findQualifyingProperties() (XAdESBBValidator.java:749-763), which simply returns the first QualifyingProperties found inside the first ds:Object child of the signature, in document order — with no check that this specific element is the one actually bound to the signature by a digested ds:Reference. Separately, validateSignedPropertiesReference() (XAdESBBValidator.java:808-825) only checks that some ds:Reference in SignedInfo has @type equal to the XAdES SignedProperties type — it never verifies that reference's URI actually points at the SignedProperties element located by findQualifyingProperties(). Because Target (self-declared, unsigned) and CertDigest (computable from the publicly available signing certificate, e.g. from KeyInfo) are both checked only against attacker-controlled content with no secret material required, all four checks (validateSchema, validateTarget, validateSignedPropertiesReference, validateCertDigest) can be satisfied by a forged, completely unsigned XAdES block.
Exploit Scenario: Take a document that is already legitimately XAdES-B-B signed (has a real, digest-covered SignedProperties referenced via a ds:Reference[@type=".../SignedProperties"]). Without any signing key, insert an additional ds:Object — placed before the legitimate one in document order — containing a forged xades132:QualifyingProperties/SignedProperties subtree with attacker-chosen SigningTime, SignatureProductionPlace, SignaturePolicyIdentifier, a self-consistent Target="#"+signatureId, and a CertDigest computed from the real (public) signing certificate. Core XMLSignature verification still succeeds (the real, referenced SignedProperties is untouched). But XAdESBBValidator.validate() picks up the forged, uncovered element instead, all checks pass trivially, and isValid() returns true — reporting the attacker's fabricated signing time/place/policy as validated XAdES data bound to the signature, when it isn't covered by any digest at all.
Recommendation: After locating the reference with @type == REFERENCE_TYPE_SIGNEDPROPERTIES in SignedInfo, resolve its URI (same-document ID reference) and require the resulting element to be the specific SignedProperties child of the QualifyingProperties under validation. Reject (add a violation) if no digest-covered reference points at that exact element — don't accept existence of a correctly-typed reference anywhere in SignedInfo as sufficient. Also worth confirming there's exactly one QualifyingProperties per signature, or explicitly reject multiples.

@jrihtarsic

Copy link
Copy Markdown
Contributor Author

Hi @coheigea
This is a good/smart catch. Many thanks for pointing it out. I will implement additional checks of the QualifyingProperties and let you know when is ready.

@jrihtarsic

Copy link
Copy Markdown
Contributor Author

Hi @coheigea,
I have implemented the enhanced verification of the XAdES data as suggested in your comment:
Presence is now decided from ds:SignedInfo, not from ds:Object, the location of the QualifyingProperties and SignedProperties are exactly one and hash of the element must match the one from signature Reference, I added also the validation that canonicalization transforms are only the one allowed from the specs...

The fix/ (the PR) is now ready for new review.

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.

3 participants