Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
164a9bb
feat(xmldsig): complete Merlin interop
polaz Aug 4, 2026
d9a013c
fix(xmldsig): address Merlin review findings
polaz Aug 5, 2026
e0ac4b2
fix(xmldsig): harden retrieval methods
polaz Aug 5, 2026
8fd4a48
fix(xmldsig): harden key retrieval
polaz Aug 5, 2026
155520b
fix(xmldsig): harden key source handling
polaz Aug 5, 2026
06f6749
fix(xmldsig): track xmlsec1 1.3.13
polaz Aug 5, 2026
fbfb5c7
fix(xmldsig): ignore CryptoBinary comments
polaz Aug 5, 2026
2304206
fix(xmldsig): harden external references
polaz Aug 5, 2026
fa4a088
ci: unpin stale cargo-fuzz lockfile
polaz Aug 5, 2026
9f3017b
fix(xmldsig): harden interop boundaries
polaz Aug 5, 2026
f9e1e5f
fix(ci): verify immutable interop inputs
polaz Aug 6, 2026
6905e49
fix(ci): use maintained action refs
polaz Aug 6, 2026
eb1840e
fix(xmldsig): harden interop setup
polaz Aug 6, 2026
3bc02d1
fix(xmldsig): honor matching context
polaz Aug 6, 2026
bcdccc4
fix(xmldsig): preserve resolution context
polaz Aug 6, 2026
3ec3a96
fix(xmldsig): harden resolution edge cases
polaz Aug 6, 2026
88541da
fix(xmldsig): close URI and trust edge cases
polaz Aug 6, 2026
c1d0bd7
fix(xmldsig): harden fallback resolution
polaz Aug 6, 2026
abd05ed
fix(xmldsig): unify detached parse policy
polaz Aug 6, 2026
1a8d77b
fix(xmldsig): enforce URI and X.509 invariants
polaz Aug 6, 2026
9c0cd48
fix(xmldsig): enforce signature-wide limits
polaz Aug 7, 2026
ddb8153
fix(xmldsig): harden bounded verification
polaz Aug 7, 2026
83f35c6
fix(xmldsig): defer malformed retrievals
polaz Aug 7, 2026
7b56c38
fix(security): unify policy and provider
polaz Aug 7, 2026
7cae909
fix(security): enforce policy invariants
polaz Aug 7, 2026
4fbc2be
fix(security): enforce operation policy bounds
polaz Aug 8, 2026
ab7abf8
fix(policy): enforce operation-wide limits
polaz Aug 8, 2026
9cb97ce
fix(policy): enforce operation resource limits
polaz Aug 8, 2026
219ca57
fix: enforce crypto operation boundaries
polaz Aug 8, 2026
c5891bb
fix(xmldsig): harden X.509 resolution
polaz Aug 8, 2026
173ccb3
fix(xmldsig): enforce transform policy
polaz Aug 8, 2026
88b185d
fix(policy): enforce resource invariants
polaz Aug 9, 2026
92bf93e
fix(xmldsig): enforce resolution budgets
polaz Aug 9, 2026
a470602
fix(xmldsig): close policy bypasses
polaz Aug 9, 2026
42a25e8
fix(xmldsig): decouple ECDSA curve and hash
polaz Aug 9, 2026
37ad953
fix(xmldsig): preserve provider invariants
polaz Aug 9, 2026
168b648
fix(xmldsig): preserve alternate X.509 paths
polaz Aug 9, 2026
2213a8d
fix(xmldsig): enforce X.509 constraints
polaz Aug 9, 2026
c1caa4c
fix(x509): harden name and CRL matching
polaz Aug 9, 2026
5f46334
docs(xmldsig): clarify legacy policy
polaz Aug 9, 2026
8ff5845
fix(xmlenc): enforce encryption invariants
polaz Aug 9, 2026
082534b
fix(validation): enforce typed invariants
polaz Aug 9, 2026
22d0184
fix(validation): reject malformed metadata
polaz Aug 10, 2026
7c59bab
fix(validation): reject malformed inputs
polaz Aug 10, 2026
e8958a1
docs(policy): clarify legacy algorithm gates
polaz Aug 10, 2026
f66e766
fix(x509): reject malformed parameter sets
polaz Aug 10, 2026
10c17c5
fix(x509): harden certificate validation
polaz Aug 10, 2026
83a76ad
fix(x509): validate certificate identities
polaz Aug 10, 2026
ab23ba6
fix(validation): enforce trust boundaries
polaz Aug 10, 2026
5d37a10
fix(validation): close trust boundary gaps
polaz Aug 10, 2026
18eb17c
fix(xmlenc): enforce facade wire contracts
polaz Aug 11, 2026
15e0a81
fix(validation): enforce structural bounds
polaz Aug 11, 2026
e4d6712
fix(xmlenc): validate provider key wrapping
polaz Aug 11, 2026
e42d418
fix(xmldsig): enforce validation invariants
polaz Aug 11, 2026
7fab10a
fix(validation): enforce trust invariants
polaz Aug 11, 2026
0448fb0
fix(crypto): validate provider framing
polaz Aug 11, 2026
6f8ee3e
fix(policy): enforce outbound RSA strength
polaz Aug 12, 2026
d8c8cf2
fix(policy): enforce exact output bounds
polaz Aug 12, 2026
3822b33
fix(xmlenc): validate exact cipher output
polaz Aug 12, 2026
765c6fa
fix(policy): harden provider trust boundaries
polaz Aug 12, 2026
34971e1
fix(policy): bound XML document processing
polaz Aug 12, 2026
f696d66
fix(xmldsig): validate crypto boundaries
polaz Aug 12, 2026
72e9a14
fix(validation): enforce facade boundaries
polaz Aug 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
tests/fixtures/xmlenc/aleksey-xmlenc-01/*.tmpl -text whitespace=-trailing-space,-space-before-tab
tests/fixtures/xmlenc/01-phaos-xmlenc-3/** -text whitespace=-trailing-space,-space-before-tab
tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/** -text whitespace=-blank-at-eof
45 changes: 32 additions & 13 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@ on:
pull_request:
branches: [main]

permissions:
contents: read

env:
CARGO_TERM_COLOR: always
RUSTFLAGS: -Dwarnings
XMLSEC1_VERSION: 1.3.12
XMLSEC1_SHA256: 24045199af12d93fe5fdbbbf7e386e823e4842071e9432e2b90ac108b889a923
XMLSEC1_PREFIX: ${{ github.workspace }}/.tools/xmlsec1-1.3.13-5fdd47dc3575
XMLSEC1_BIN: ${{ github.workspace }}/.tools/xmlsec1-1.3.13-5fdd47dc3575/bin/xmlsec1
LD_LIBRARY_PATH: ${{ github.workspace }}/.tools/xmlsec1-1.3.13-5fdd47dc3575/lib

jobs:
build-matrix:
Expand All @@ -21,6 +25,8 @@ jobs:
rust: [stable, "1.92.0"]
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@stable
with:
toolchain: ${{ matrix.rust }}
Expand All @@ -43,6 +49,8 @@ jobs:
rust: [stable, "1.92.0"]
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@stable
with:
toolchain: ${{ matrix.rust }}
Expand All @@ -51,17 +59,9 @@ jobs:
run: sudo apt-get update
- name: Build pinned xmlsec1 for XMLDSig interop tests
run: |
sudo apt-get install --yes build-essential libltdl-dev libssl-dev libxml2-dev pkg-config
curl --fail --location --retry 3 --output xmlsec1.tar.gz "https://github.com/lsh123/xmlsec/releases/download/${XMLSEC1_VERSION}/xmlsec1-${XMLSEC1_VERSION}.tar.gz"
echo "${XMLSEC1_SHA256} xmlsec1.tar.gz" | sha256sum --check --strict
tar --extract --file xmlsec1.tar.gz
pushd "xmlsec1-${XMLSEC1_VERSION}"
./configure --disable-static --with-openssl
make --jobs "$(nproc)"
sudo make install
popd
sudo ldconfig
xmlsec1 --version
sudo apt-get install --yes autoconf automake build-essential libltdl-dev libssl-dev libtool libxml2-dev pkg-config
scripts/install-xmlsec1.sh
"$XMLSEC1_BIN" --version
- uses: Swatinem/rust-cache@v2
- run: cargo nextest run --all-features
- run: cargo test --doc --all-features
Expand All @@ -77,6 +77,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy
Expand All @@ -87,7 +89,24 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
- run: cargo fmt --all -- --check
- run: cargo fmt --manifest-path fuzz/Cargo.toml -- --check

fuzz-smoke:
timeout-minutes: 20
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- uses: dtolnay/rust-toolchain@nightly
# cargo-fuzz 0.13.1's published lockfile pins rustix 0.36.5, which no
# longer compiles on current nightly. Keep the tool version pinned while
# allowing compatible patch-level transitive dependencies.
- run: cargo +nightly install cargo-fuzz --version 0.13.1
- run: cargo +nightly fuzz run xmldsig_verify -- -runs=256 -max_len=65536
Comment thread
coderabbitai[bot] marked this conversation as resolved.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
/target
/.tools
/fuzz/artifacts
/fuzz/corpus/*/*
!/fuzz/corpus/xmldsig_verify/signature.xml
/fuzz/target
Cargo.lock
*.swp
*.swo
Expand Down
16 changes: 13 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,38 +28,46 @@ sha2 = { version = "0.11", features = ["oid"], optional = true }
p256 = { version = "0.14", features = ["ecdsa"], optional = true }
p384 = { version = "0.14", features = ["ecdsa"], optional = true }
p521 = { version = "0.14", features = ["ecdsa"], optional = true }
dsa = { version = "0.7", optional = true }
ed25519-dalek = { version = "3", features = ["pkcs8"], optional = true }
hmac = { version = "0.13", optional = true }
signature = { version = "3", optional = true }
subtle = { version = "2", optional = true }
getrandom = { version = "0.4", features = ["sys_rng"], optional = true }
sxd-document-no-unsafe = { version = "0.4.1", default-features = false, features = ["no-unsafe"], optional = true }
sxd-xpath-no-unsafe = { version = "0.5.1", default-features = false, features = ["no-unsafe"], optional = true }
aes = { version = "0.9.1", optional = true }
aes = { version = "0.9.2", optional = true }
aes-gcm = { version = "0.11.0", optional = true }
aes-kw = { version = "0.3.1", optional = true }
cbc = { version = "0.2.1", optional = true }

# X.509 certificates
x509-parser = { version = "0.18", features = ["verify"], optional = true }
x509-cert = { version = "0.3", default-features = false, optional = true }
x520-stringprep = { version = "1", features = ["alloc"], optional = true }
der = { version = "0.8", optional = true }
crypto-bigint = { version = "0.7", optional = true }

# Base64 encoding/decoding
base64 = "0.22"
base64 = "0.23"

# Error handling
thiserror = "2"

[dev-dependencies]
rcgen = "0.14.6"
rand_chacha = "0.10"
time = "0.3.53"
time = "0.3.55"

[features]
default = ["xmldsig", "c14n"]
xmldsig = [ # XML Digital Signatures (sign + verify)
"dep:der",
"dep:crypto-bigint",
"dep:dsa",
"dep:ed25519-dalek",
"dep:getrandom",
"dep:hmac",
"dep:p256",
"dep:p384",
"dep:p521",
Expand All @@ -71,6 +79,8 @@ xmldsig = [ # XML Digital Signatures (sign + verify)
"dep:sxd-document-no-unsafe",
"dep:sxd-xpath-no-unsafe",
"dep:x509-parser",
"dep:x509-cert",
"dep:x520-stringprep",
]
xmlenc = [ # XML Encryption (encrypt + decrypt)
"dep:aes",
Expand Down
20 changes: 13 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,26 @@ Currently implemented (core paths):
- XMLDSig parsing, same-document URI dereference, enveloped/C14N/Base64/XPath 1.0/XPath Filter 2.0 transform chains, and digest verification
- XMLDSig full verify pipeline (`SignedInfo` canonicalization + `SignatureValue` verification)
- XMLDSig template signing pipeline (`DigestValue` fill + `SignedInfo` canonicalization + `SignatureValue` fill), including enveloped SAML Response templates
- Typed signing and verification policy covers XML parsing, explicit transforms, implicit reference canonicalization, `SignedInfo` canonicalization, and outbound RSA key strength under shared work limits
- XMLDSig signing KeyInfo writer for embedded X.509 certificates
- Built-in verification-key resolution from embedded X.509/DER/`KeyValue` sources and configured `KeyName`, X.509 subject, issuer/serial, SKI, or digest selectors
- RSA PKCS#1 v1.5 verification helpers for SHA-1 / SHA-256 / SHA-384 / SHA-512
- ECDSA verification helpers for P-256/SHA-256 and P-384/SHA-384
- RSA PKCS#1 v1.5 and ECDSA P-256/P-384 signing from PKCS#8 private keys
- Opt-in X.509 certificate-chain validation with explicit trust anchors, validity checks, CA constraints, and CRLs
- ECDSA SHA-256/SHA-384 verification for P-256, P-384, and P-521 keys
- Legacy DSA-SHA1 and HMAC-SHA1 verification, including truncated HMAC output
- RSA PKCS#1 v1.5 and ECDSA SHA-256/SHA-384 signing with P-256/P-384 PKCS#8 keys
- Opt-in X.509 certificate-chain validation with explicit trust anchors, validity and path-length checks, NameConstraints, authenticated CRLs, typed path-wide ExtendedKeyUsage policy, and RSA-PSS/Ed25519 certificate-signature support. Duplicate certificate, CRL, and CRL-entry extension OIDs, malformed SAN identities, unsupported delta CRLs, `removeFromCRL` entries in complete CRLs, and invalid name constraints are rejected; implemented critical extensions are processed and every other critical extension fails closed.
- Caller-supplied external references and X.509 `RetrievalMethod` resolution with bounded RFC 3986 `xml:base` processing and no implicit I/O
- XMLEnc AES-128/256-CBC and AES-128/256-GCM encryption/decryption with direct
keys, RSA-OAEP key transport, AES-128/256-KW, multiple recipients, and
Element/Content document replacement
Element/Content document replacement; document, node, and aggregate recipient
limits plus outbound RSA key-strength policy cover caller-constructed ciphertext and generated replacement output
before expensive work. CBC failures expose no decrypted
padding details, but CBC remains unauthenticated and can be excluded by policy

Still in progress:
- XMLDSig DSA, HMAC, and RSA-PSS signature algorithms
- XMLDSig DSA-SHA256, broader HMAC verification/signing, and RSA-PSS `SignatureMethod` algorithms
- Complete XMLDSig and XMLEnc conformance-suite classification
- Production hardening, fuzzing, benchmarks, and API stabilization
- Expanded fuzz coverage, benchmarks, production hardening, and API stabilization

## XMLDSig Usage

Expand Down Expand Up @@ -100,7 +106,7 @@ Current MSRV: Rust 1.92.
| [Canonical XML 1.0](https://www.w3.org/TR/xml-c14n/) | Implemented; full-document and document-subset vectors |
| [Canonical XML 1.1](https://www.w3.org/TR/xml-c14n11/) | Implemented; `xml:id` and `xml:base` subset rules |
| [Exclusive C14N](https://www.w3.org/TR/xml-exc-c14n/) | Implemented; `InclusiveNamespaces PrefixList` support |
| [XMLDSig](https://www.w3.org/TR/xmldsig-core1/) | Core sign/verify pipelines implemented; additional algorithms and conformance coverage in progress |
| [XMLDSig](https://www.w3.org/TR/xmldsig-core1/) | Core sign/verify pipelines and the complete Merlin corpus implemented; additional algorithms and conformance suites in progress |
| [XMLEnc](https://www.w3.org/TR/xmlenc-core1/) | Core AES-CBC/GCM encrypt/decrypt with RSA-OAEP and AES-KW implemented; broader conformance coverage in progress |

## License
Expand Down
Loading