Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 5 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ jobs:
env:
PKCS11_MODULE: /usr/lib/softhsm/libsofthsm2.so
run: |
for profile in dom-xmloxide dom-roxmltree c14n-xmloxide c14n-roxmltree dsig-xmloxide dsig-roxmltree dsig-sign-xmloxide xmlenc-xmloxide xmlenc-roxmltree xslt legacy experimental fips-dsig pkcs11 no-backend; do
for profile in dom-xmloxide dom-roxmltree c14n-xmloxide c14n-roxmltree dsig-xmloxide dsig-roxmltree cms-xmloxide dsig-sign-xmloxide xmlenc-xmloxide xmlenc-roxmltree xslt legacy experimental fips-dsig pkcs11 no-backend; do
echo "::group::$profile"
cargo run --quiet -p xml-sec-tools -- check-features "$profile"
echo '::endgroup::'
Expand Down Expand Up @@ -281,6 +281,10 @@ jobs:
cargo clippy -p xml-sec --lib --no-default-features
--features xmldsig,xml-backend-roxmltree
--target thumbv7em-none-eabihf -- -D warnings
- run: >-
cargo clippy -p xml-sec --lib --no-default-features
--features cms,xml-backend-xmloxide
--target thumbv7em-none-eabihf -- -D warnings
- uses: taiki-e/install-action@nextest
- name: Target coverage on the build without std
run: |
Expand Down
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,7 @@ std = [
"xmlparser/std",
"structured-asn1?/std",
"structured-pkix?/std",
"structured-cms?/std",
"base64/std",
"snafu?/std",
"der?/std",
Expand Down Expand Up @@ -466,6 +467,8 @@ xmldsig = [ # XML Digital Signature verification and public-key inven
"dep:tinyvec",
"dep:zeroize",
]
# CMS SignedData and RFC 3161 timestamp signatures through the selected provider.
cms = ["xmldsig", "dep:structured-cms"]
# Signing, signing randomness and private-key import (PEM/PKCS#8, encrypted
# PKCS#8, PKCS#12) on top of verification.
xmldsig-sign = [
Expand Down
18 changes: 12 additions & 6 deletions docs/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ See [provider boundaries](crypto-providers.md) and [policy profiles](policy-prof
| Defaults | `std`, `c14n`, `xmldsig`, `xmldsig-sign`, `xmlenc`, `xml-backend-xmloxide` |
| `c14n` plus one XML backend | Canonicalization without signature/encryption dependencies; builds without `std` |
| `xmldsig` plus one XML backend | Signature verification, policy and the public-key inventory; builds without `std` |
| `cms` plus one XML backend | Adds the CMS `SignedData` and RFC 3161 timestamp signature provider over the selected crypto provider; implies `xmldsig`, not signing; builds without `std` |
| `xmldsig-sign` plus one XML backend | Adds signing, signature templates, private-key import (PEM, PKCS#8, encrypted PKCS#8, PKCS#12) and the bundled randomness source; implies `xmldsig` and `std` |
| `xmlenc` plus one XML backend | Encryption and its shared signature/key-inventory graph; implies `xmldsig-sign` and `std` |
| `xslt` plus one XML backend | XMLDSig XSLT support; implies `xmldsig` and `std` |
Expand Down Expand Up @@ -41,8 +42,8 @@ helpers remain available with an XML backend even without the `c14n` marker.

### Builds without `std`

Without the `std` feature the crate is `no_std` with `alloc`: C14N and XMLDSig
verification build for targets such as `thumbv7em-none-eabihf` and
Without the `std` feature the crate is `no_std` with `alloc`: C14N, XMLDSig
verification and the `cms` provider build for targets such as `thumbv7em-none-eabihf` and
`wasm32-unknown-unknown`. Host-only capabilities keep requiring `std`: signing
and its randomness (`xmldsig-sign`), `xmlenc`, native providers and PKCS#11.

Expand All @@ -69,8 +70,10 @@ public material, X.509 path and CRL validation and the public-key inventory.
It compiles no signing pipeline, signature templates, private-key import,
password-based key derivation or operating-system randomness: `pkcs12`,
`pkcs5`, `scrypt`, `pbkdf2`, `cms`, `x509-cert`, `x509-parser` and `getrandom`
are absent from its dependency graph. Certificates are read only through the
shared PKIX reader and PEM through one RFC 7468 decoder.
are absent from its dependency graph, and so is the `structured-cms` processor.
Certificates are read only through the shared PKIX reader and PEM through one
RFC 7468 decoder. The `cms` feature adds `structured-cms` for timestamp and
`SignedData` checks and nothing from that signing and import list.

`CryptoProvider` keeps one method set in every build, so an external provider
compiles unchanged whichever features another crate enables. The bundled
Expand Down Expand Up @@ -100,10 +103,13 @@ dependency/setup errors cannot satisfy it.
The `dsig-xmloxide` and `dsig-roxmltree` profiles are verification-only: before
linting they fail if any crate listed above enters the normal dependency graph,
and they run the library tests and `tests/verify_only_build.rs`. Tests that
create their fixtures by signing run in the signing profiles.
create their fixtures by signing run in the signing profiles. The
`cms-xmloxide` profile applies the same graph check, admitting only
`structured-cms`, and runs `tests/cms_timestamp.rs` over RFC 3161 tokens that
`scripts/generate-cms-timestamp-fixtures.sh` obtains from OpenSSL.

Other profiles are `dom-xmloxide`, `dom-roxmltree`, `c14n-xmloxide`,
`dsig-xmloxide`, `dsig-sign-xmloxide`, `xmlenc-roxmltree`, `xslt`, `legacy`,
`dsig-xmloxide`, `cms-xmloxide`, `dsig-sign-xmloxide`, `xmlenc-roxmltree`, `xslt`, `legacy`,
`experimental`, `fips-dsig` and `pkcs11`. Native FIPS requirements are documented by
[AWS](https://aws.github.io/aws-lc-rs/requirements/index.html).
For token execution supply an explicit test module:
Expand Down
96 changes: 96 additions & 0 deletions scripts/generate-cms-timestamp-fixtures.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#!/usr/bin/env bash
# Regenerate the RFC 3161 timestamp fixtures of tests/cms_timestamp.rs.
#
# OpenSSL acts as an independent time-stamping authority. For each key type it
# issues a self-signed TSA certificate with the critical timeStamping extended
# key usage (RFC 3161 §2.3). `openssl ts` stamps the payload with RSA and ECDSA
# keys. Its PKCS #7 signer supports neither Ed25519 nor RSA-PSS, so for those
# keys `openssl cms` signs the TSTInfo of the RSA token as id-ct-TSTInfo
# content, with the ESS signingCertificateV2 attribute (-cades). Trust in the
# TSA is outside these fixtures; they exercise CMS signature and imprint checks.
#
# Usage: scripts/generate-cms-timestamp-fixtures.sh
# CMS_FIXTURE_OUTPUT optionally selects an absolute output directory.
# Requires OpenSSL 3.4 or later for fixed certificate validity dates.
set -euo pipefail

repository="$(cd "$(dirname "$0")/.." && pwd)"
output="${CMS_FIXTURE_OUTPUT:-$repository/tests/fixtures/cms/timestamp}"
mkdir -p "$output"
work="$(mktemp -d)"
trap 'rm -rf "$work"' EXIT
cd "$work"

NOT_BEFORE=20260101000000Z
NOT_AFTER=20450101000000Z
TST_INFO=1.2.840.113549.1.9.16.1.4

printf 'Time-stamped payload\n' >payload.txt
cp payload.txt "$output/payload.txt"
openssl ts -query -data payload.txt -sha256 -cert -no_nonce -out payload.tsq 2>/dev/null

cat >ts.cnf <<'EOF'
[tsa]
default_tsa = tsa_config

[tsa_config]
serial = ./serial
crypto_device = builtin
signer_digest = sha256
default_policy = 1.3.6.1.4.1.55555.1
digests = sha256, sha384, sha512
accuracy = secs:1
ordering = no
tsa_name = no
ess_cert_id_chain = no
ess_cert_id_alg = sha256
EOF

# authority <name> <openssl genpkey arguments...>
authority() {
local name="$1"
shift
openssl genpkey "$@" -out "$name.key" 2>/dev/null
openssl req -x509 -new -key "$name.key" -out "$name.pem" \
-not_before "$NOT_BEFORE" -not_after "$NOT_AFTER" \
-subj "/CN=xml-sec Test TSA $name" \
-addext "basicConstraints=critical,CA:FALSE" \
-addext "keyUsage=critical,digitalSignature" \
-addext "extendedKeyUsage=critical,timeStamping" 2>/dev/null
openssl x509 -in "$name.pem" -outform DER -out "$output/$name.der"
}

# stamp <name>: an `openssl ts` token signed by that authority.
stamp() {
echo 01 >serial
openssl ts -reply -config ts.cnf -queryfile payload.tsq \
-signer "$1.pem" -inkey "$1.key" -token_out -out "$output/$1.tst" 2>/dev/null
}

# resign <name> <openssl cms -sign options...>: the RSA token's TSTInfo signed
# by that authority.
resign() {
local name="$1"
shift
openssl cms -sign -binary -nodetach -in tstinfo.der -econtent_type "$TST_INFO" \
-signer "$name.pem" -inkey "$name.key" -cades -nosmimecap "$@" \
-outform DER -out "$output/$name.tst"
}

authority rsa -algorithm RSA -pkeyopt rsa_keygen_bits:2048
stamp rsa
authority ecdsa-p256 -algorithm EC -pkeyopt ec_paramgen_curve:P-256
stamp ecdsa-p256

openssl cms -verify -noverify -inform DER -in "$output/rsa.tst" -out tstinfo.der 2>/dev/null
authority ed25519 -algorithm ED25519
resign ed25519 -md sha512
authority rsa-pss -algorithm RSA -pkeyopt rsa_keygen_bits:2048
resign rsa-pss -md sha256 -keyopt rsa_padding_mode:pss -keyopt rsa_pss_saltlen:32

# Certificates read only for their own signature identifiers.
authority ed448 -algorithm ED448
openssl req -x509 -new -key rsa-pss.key -outform DER -out "$output/rsa-pss-signed.der" \
-sha256 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:32 \
-not_before "$NOT_BEFORE" -not_after "$NOT_AFTER" \
-subj "/CN=xml-sec Test PSS signature" 2>/dev/null
Loading
Loading