Sign and verify FundsXML with enveloped XML Digital Signatures. All stacks use the same profile so signed files cross-verify between them:
| Property | Value |
|---|---|
| Signature method | RSA-SHA256 |
| Digest | SHA-256 |
| Canonicalization | Exclusive C14N (xml-exc-c14n#) |
| Transform | enveloped-signature + exclusive C14N |
| Reference | URI="" (whole document) |
| KeyInfo | signer X.509 certificate embedded |
| Placement | ds:Signature is the last child of <FundsXML4> — exactly where the 4.2.9 schema allows it (xmldsig-core-schema.xsd import) |
A signed file stays XSD-valid (verified) and matches the structure of the
committed FundsXML_Files/4.2.9/signed/Signed_Fund_Skeleton.xml
placeholder.
./mvnw -q -pl XML_Signature/java compile exec:java -Dexec.mainClass=GenerateTestKey
# -> XML_Signature/keys/ (gitignored). Windows: use mvnw.cmdGenerateTestKey uses the JDK's own keytool (no openssl, so it works on
Windows too) to write a throwaway self-signed RSA-2048 keystore
test-signing.p12 (alias fundsxml, pass changeit) and the PEM certificate
test-signing-cert.pem. Demo only — never commit private keys.
| Stack | Entry point | Status |
|---|---|---|
| Java — Apache Santuario | java/SignFundsXml.java / java/VerifyFundsXml.java |
✅ verified (sign, verify, tamper-detect) |
CLI — xmlsec1 |
cli/sign-verify-xmlsec1.sh |
✅ verified (xmlsec1 1.2.33, in CI): sign, verify, tamper; cross-verifies with Java and .NET both ways |
Python — signxml |
python/sign_verify_signxml.py |
reference (pip install -e ".[signature]" adds signxml) |
.NET — SignedXml |
dotnet/SignVerify.cs |
verified (.NET SDK 8): sign, verify, tamper; cross-verifies with Java both ways |
Standalone & cross-platform via the committed Maven Wrapper (./mvnw, or
mvnw.cmd on Windows), from the repo root — xmlsec comes from Maven Central:
M="./mvnw -q -pl XML_Signature/java compile exec:java"
# one-off: throwaway key (JDK keytool, no openssl)
$M -Dexec.mainClass=GenerateTestKey
# sign
$M -Dexec.mainClass=SignFundsXml \
-Dexec.args="FundsXML_Files/4.2.9/positions/Mixed-Fund_Positions.xml signed.xml \
XML_Signature/keys/test-signing.p12 changeit fundsxml"
# verify — pin the signer cert (don't trust only the embedded key)
$M -Dexec.mainClass=VerifyFundsXml \
-Dexec.args="signed.xml XML_Signature/keys/test-signing-cert.pem"VerifyFundsXml exits 0 on a valid signature, 1 on tamper/failure (verified:
flipping one digit in a signed file → INVALID). Santuario verification runs
with secure validation enabled.
Note on
xmlsec1: it signs an existingds:Signaturetemplate, so it pairs naturally with the committed signed skeleton (FundsXML_Files/4.2.9/signed/Signed_Fund_Skeleton.xml); the Java/.NET/Python examples instead build and append theds:Signaturethemselves. The skeleton's template carries exactly the profile above (exclusive C14N, enveloped + exc-C14N transforms, RSA-SHA256, emptyX509Certificateplaceholder that xmlsec1 fills), so the signed result verifies in Java and .NET both pinned and from the embedded certificate, and xmlsec1 verifies the Java/.NET output.
A real signed file is not committed — the signature is bound to the throwaway key, which is regenerated per run. CI signs → verifies as a roundtrip.