xml-sec 0.1.21

Pure Rust XML Security: XMLDSig, XMLEnc, C14N. Drop-in replacement for libxmlsec1.
Documentation
[package]
name = "xml-sec"
version = "0.1.21"
edition = "2024"
rust-version = "1.92"
license = "Apache-2.0 AND MIT"
description = "Pure Rust XML Security: XMLDSig, XMLEnc, C14N. Drop-in replacement for libxmlsec1."
repository = "https://github.com/structured-world/xml-sec"
homepage = "https://github.com/structured-world/xml-sec"
documentation = "https://docs.rs/xml-sec"
keywords = ["xml", "xmldsig", "xmlenc", "c14n", "saml"]
categories = ["cryptography", "web-programming", "authentication"]
readme = "README.md"
include = [
    "/Cargo.toml",
    "/Cargo.lock",
    "/LICENSE",
    "/LICENSE-THIRD-PARTY",
    "/README.md",
    "/assets/usdt-qr.svg",
    "/docs/**",
    "/src/**",
    "/examples/**",
    "/tests/**",
    "/tools/xmlsec1/**",
    "/compatibility/**",
    "/scripts/**",
]

[workspace]
members = [
    ".",
    "crates/xml-sec-xml-input",
    "crates/xml-sec-xslt",
    "tools/capability-ledger",
    "vendor/sxd-document-no-unsafe",
    "vendor/sxd-xpath-no-unsafe",
]
resolver = "3"

# The complete libxslt oracle includes multi-megabyte DocBook transforms. Keep
# production-equivalent XSLT/XPath code generation in the test profile so the
# per-case watchdog measures algorithmic stalls rather than debug arithmetic.
[profile.dev.package.xml-sec-xslt]
opt-level = 2

[profile.dev.package.xml-sec-sxd-document]
opt-level = 2

[profile.dev.package.xml-sec-sxd-xpath]
opt-level = 2

[[bin]]
name = "xmlsec1"
path = "tools/xmlsec1/src/main.rs"
required-features = ["xmldsig", "xmlenc", "c14n"]

[[test]]
name = "cli_import_snapshot"
path = "tools/xmlsec1/tests/import_snapshot.rs"
required-features = ["xmldsig", "xmlenc", "c14n"]

[[test]]
name = "cli_process_contract"
path = "tools/xmlsec1/tests/process_contract.rs"
required-features = ["xmldsig", "xmlenc", "c14n"]

[[test]]
name = "cli_upstream_runner"
path = "tools/xmlsec1/tests/upstream_runner.rs"
required-features = ["xmldsig", "xmlenc", "c14n"]

[[example]]
name = "encrypt"
required-features = ["xmlenc"]

[dependencies]
# XML parsing
roxmltree = { version = "0.21", features = ["positions"], optional = true }
xmloxide = { version = "0.5", default-features = false, optional = true }
self_cell = "1.3"
encoding_rs = { version = "0.8", default-features = false, features = ["alloc"] }
xmlparser = { version = "0.13.6", default-features = false }
peresil = { version = "0.3", optional = true }
snafu = { version = "0.9", optional = true }

# Crypto
cryptoki = { version = "0.12.1", optional = true }
aws-lc-rs = { version = "1.18.1", default-features = false, features = ["fips"], optional = true }
rsa = { package = "sad-rsa", version = "0.10.2", default-features = false, features = ["sha1", "sha2", "hazmat"], optional = true }
sha1 = { version = "0.11", features = ["oid", "zeroize"], optional = true }
sha2 = { version = "0.11", features = ["oid", "zeroize"], optional = true }
sha3 = { version = "0.12", default-features = false, features = ["oid"], optional = true }
ed448-goldilocks = { version = "=0.14.0-pre.15", default-features = false, features = ["alloc", "signing", "pkcs8"], optional = true }
# Dependencies of the embedded, patched RustCrypto ML-DSA implementation.
common = { package = "crypto-common", version = "0.2", default-features = false, features = ["rand_core"], optional = true }
ctutils = { version = "0.4", default-features = false, optional = true }
hybrid-array = { version = "0.4", default-features = false, features = ["extra-sizes", "alloc", "zeroize"], optional = true }
module-lattice = { version = "0.2.3", default-features = false, features = ["ctutils", "alloc", "zeroize"], optional = true }
shake = { version = "0.1", default-features = false, optional = true }
const-oid = { version = "0.10", default-features = false, features = ["db"], optional = true }
slh-dsa = { version = "=0.2.0-rc.5", default-features = false, features = ["alloc", "zeroize"], optional = true }
ml-kem = { version = "0.3.2", default-features = false, features = ["alloc", "zeroize"], 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", features = ["hazmat"], optional = true }
pkcs8 = { version = "0.11", features = ["encryption", "pem"], optional = true }
pkcs1 = { version = "0.8.0-rc.5", default-features = false, features = ["alloc", "pem"], optional = true }
ed25519-dalek = { version = "3", default-features = false, features = ["alloc", "digest", "fast", "hazmat", "pkcs8", "zeroize"], optional = true }
# Expose the same curve primitive already used by dalek for RFC 8032 Ed25519ctx.
curve25519-dalek = { version = "5", default-features = false, features = ["alloc", "precomputed-tables", "zeroize"], optional = true }
hmac = { version = "0.13", features = ["zeroize"], optional = true }
hkdf = { version = "0.13", default-features = false, optional = true }
x25519-dalek = { version = "3", default-features = false, features = ["static_secrets", "zeroize"], optional = true }
signature = { version = "3", optional = true }
subtle = { version = "2", optional = true }
getrandom = { version = "0.4", features = ["sys_rng"], optional = true }
zeroize = { version = "1", optional = true }
aes = { version = "0.9.2", optional = true }
aes-gcm = { version = "0.11.1", optional = true }
aes-kw = { version = "0.3.1", optional = true }
cbc = { version = "0.2.1", optional = true }
des = { version = "0.9", optional = true }
md-5 = { version = "0.11", features = ["oid"], optional = true }
ripemd = { version = "0.2.0", default-features = false, features = ["oid"], optional = true }
pem = { version = "4", optional = true }
pkcs12 = { version = "=0.2.0-pre.0", default-features = false, features = ["kdf"], optional = true }
pbkdf2 = { version = "0.13", default-features = false, features = ["hmac"], 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 }
tinyvec = { version = "1.13", optional = true }
der = { version = "0.8", optional = true }
crypto-bigint = { version = "0.7", features = ["zeroize"], optional = true }
crypto-primes = { version = "0.7.2", default-features = false, optional = true }

# Base64 encoding/decoding
base64 = "0.23"

# Error handling
thiserror = "2"

[dev-dependencies]
ml-dsa = { version = "0.1.1", default-features = false, features = ["alloc", "pkcs8", "rand_core", "zeroize"] }
hex-literal = "1"
roxmltree = { version = "0.21", features = ["positions"] }
rcgen = "0.14.6"
rand_chacha = "0.10"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
time = "0.3.55"
tempfile = "3"

[features]
legacy-algorithms = ["dep:ripemd", "dep:md-5", "dep:des"]
default = ["std", "xmldsig", "xmlenc", "c14n", "xml-backend-xmloxide"]
std = ["thiserror/std", "xmlparser/std"]
aws-lc-fips = ["std", "xmldsig", "dep:aws-lc-rs"]
pkcs11 = ["std", "xmlenc", "dep:cryptoki"]
xml-backend-xmloxide = ["dep:xmloxide"]
xml-backend-roxmltree = ["dep:roxmltree"]
xml-backends-all = ["xml-backend-xmloxide", "xml-backend-roxmltree"]
# Compatibility alias for existing CI/fuzz builds. Unlike `xml-backends-all`,
# this also selects differential parsing as the default runtime mode.
xml-backend-differential = ["xml-backends-all"]
xmldsig = [            # XML Digital Signatures (sign + verify)
    "std",
    "no-unsafe",
    "embedded",
    "dep:der",
    "dep:crypto-bigint",
    "dep:dsa",
    "dep:des",
    "dep:ed25519-dalek",
    "dep:curve25519-dalek",
    "dep:ed448-goldilocks",
    "dep:getrandom",
    "dep:hmac",
    "dep:md-5",
    "dep:pem",
    "dep:pkcs12",
    "dep:pbkdf2",
    "dep:aes",
    "dep:cbc",
    "dep:peresil",
    "dep:p256",
    "dep:p384",
    "dep:p521",
    "dep:pkcs8",
    "dep:pkcs1",
    "dep:rsa",
    "dep:sha1",
    "dep:sha2",
    "dep:sha3",
    "dep:signature",
    "dep:snafu",
    "dep:subtle",
    "dep:x509-parser",
    "dep:x509-cert",
    "dep:x520-stringprep",
    "dep:tinyvec",
    "dep:zeroize",
]
xmlenc = [             # XML Encryption (encrypt + decrypt)
    "std",
    # The shared key inventory stores XMLDSig KeyInfo for named RSA recipients.
    "xmldsig",
    "dep:aes",
    "dep:aes-gcm",
    "dep:aes-kw",
    "dep:cbc",
    "dep:getrandom",
    "dep:rsa",
    "dep:sha1",
    "dep:sha2",
    "dep:hkdf",
    "dep:x25519-dalek",
    "dep:crypto-primes",
    "p256/ecdh",
    "p384/ecdh",
    "p521/ecdh",
]
c14n = []              # XML Canonicalization (inclusive + exclusive)
# Experimental libxmlsec1 algorithm identifiers; build capability is not policy permission.
experimental-pq = ["xmldsig", "dep:slh-dsa", "dep:ml-kem", "dep:common", "dep:ctutils", "dep:hybrid-array", "dep:module-lattice", "dep:shake", "dep:const-oid", "signature/digest", "signature/alloc", "signature/rand_core"]
no-unsafe = []
embedded = []

[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(feature, values("raw-pointer-backend", "__internal_expose_string_pool"))'] }