Skip to content

feat(xmldsig): complete Merlin interop - #106

Open
polaz wants to merge 42 commits into
mainfrom
feat/#105-merlin-interop
Open

feat(xmldsig): complete Merlin interop#106
polaz wants to merge 42 commits into
mainfrom
feat/#105-merlin-interop

Conversation

@polaz

@polaz polaz commented Aug 5, 2026

Copy link
Copy Markdown
Member

Summary

  • complete verification coverage for the tracked Merlin XMLDSig interoperability corpus, including document-level and reference-level assertions
  • add pure-Rust DSA-SHA1 and HMAC-SHA1 verification with strict legacy-algorithm policies and caller-bound HMAC output lengths
  • support bounded caller-provided external resources resolved against effective xml:base, including RFC 3986 normalization for scheme-bearing and network-path URIs and a consistent internal-DTD policy for root and detached XML
  • support namespace-aware X.509 RetrievalMethod resolution, authenticated CRL handling, and bounded manifest references
  • enumerate signature-valid X.509 paths through configured lookup intermediates, stop at explicit trust anchors, validate cross-signed alternatives, and keep unsupported branches from suppressing valid sibling paths
  • bind every X.509 selector category to one signature-valid selected path while preserving legitimate leaf/intermediate/root selector sets
  • enforce RFC 5280 path-length, self-issued rollover, NameConstraints, and critical-extension rules during certificate-path validation
  • enforce RFC 4055 RSASSA-PSS issuer-SPKI hash, MGF, minimum-salt, and trailer restrictions before certificate-signature verification
  • apply legacy RSA-SHA1 policy independently of named, DER, KeyValue, or X.509 key source while preserving backend interoperability capability
  • introduce immutable verify/sign/encrypt/decrypt policy snapshots with typed violations and fail-closed resolver trust composition
  • route digest, signature dispatch, typed X.509 algorithms with built-in RSA-PSS/Ed25519 authentication and custom-provider dispatch for modeled OIDs, AES-CBC/GCM, AES-KW, RSA-OAEP, and randomness through an explicit capability-queryable RustCrypto provider without fallback, with ECDSA hash selection independent of the P-256/P-384/P-521 SPKI curve
  • reject non-SHA1 MGF configuration for legacy rsa-oaep-mgf1p before custom-provider dispatch because the wire algorithm cannot represent another MGF
  • accept direct typed X509Data retrieval without a transform while requiring explicit XPath selection when the dereferenced root is a wrapper
  • separate signed-payload URI policy from key-retrieval URI policy so external key material always requires its own explicit opt-in
  • preserve failed or unsupported advisory RetrievalMethod sources so resolvers can continue to later usable key material while retaining the original failure when no source resolves
  • enforce transform allowlists from the complete terminal data type, share one Reference ceiling across SignedInfo and authenticated Manifests, bound external XML reparsing, and cap canonicalized SignedInfo plus retained pre-digest diagnostics across a signature
  • import the complete required Merlin fixture snapshot through a reproducible curated importer that preserves donor bytes while removing non-fixture prose and normalizing the historical HMAC filename
  • pin reciprocal interoperability to the exact xmlsec1 1.3.13 Git object with source-identity verification, transactional installer rollback, and strict version-output validation
  • enforce positive X.509 serial numbers, matching signed and outer signature algorithms, X.520-prepared RFC 4514 issuer/subject matching, and untrusted lookup/intermediate paths that terminate only at explicit trust anchors
  • add SHA-256 X509Digest coverage and a bounded XMLDSig verification fuzz target
  • harden CI with read-only permissions, credential-free checkouts, and an explicit fuzz runtime budget
  • update cryptographic dependency requirements and public documentation for the completed interoperability surface

Testing

  • cargo build
  • cargo build --no-default-features
  • cargo build --all-features
  • cargo clippy --all-targets --all-features -- -D warnings
  • cargo nextest run --all-features
  • cargo test --doc --all-features
  • cargo +nightly fuzz run xmldsig_verify -- -runs=256 -max_len=65536

Closes #105

- add DSA-SHA1 and HMAC-SHA1 verification paths
- resolve bounded external references and X.509 key retrieval
- cover all Merlin documents, references, and failure policies
- update dependency requirements and public support documentation

Closes #105
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added legacy DSA-SHA1 and HMAC-SHA1 verification, including truncated HMAC outputs.
    • Added configurable cryptographic providers and security policies for XML signatures and encryption.
    • Added controlled external resources, X.509 certificate retrieval, chain validation, and CRL checks.
    • Added policy-aware signing, encryption, and decryption controls.
  • Bug Fixes

    • Improved URI resolution, reference handling, namespace undeclarations, comment processing, and diagnostics.
    • Added safeguards for oversized XML, canonicalized data, external resources, and encrypted content.
  • Documentation

    • Updated XMLDSig and XMLEnc capabilities and security guidance.
  • Tests

    • Expanded interoperability coverage and added XMLDSig fuzz testing.

Walkthrough

This PR adds provider-based cryptography, typed security policies, bounded XMLDSig and XMLEnc processing, DSA-SHA1 and HMAC-SHA1 verification, X.509 resolution, Merlin interoperability coverage, XMLSec tooling, and fuzz coverage.

Changes

XMLDSig, XMLEnc, and provider foundations

Layer / File(s) Summary
Policy and provider foundations
src/policy.rs, src/provider.rs, src/hard_limits.rs, src/lib.rs
Adds typed policies, hard resource ceilings, provider-neutral cryptographic operations, and a default RustCrypto provider.
Provider-backed signing and encryption
src/xmldsig/sign.rs, src/xmldsig/digest.rs, src/xmlenc/encrypt.rs, src/xmlenc/decrypt.rs
Routes digesting, signing, encryption, decryption, key wrapping, and RSA-OAEP through configured providers.

XMLDSig verification and certificate processing

Layer / File(s) Summary
Parsing and signature algorithms
src/xmldsig/parse.rs, src/xmldsig/signature.rs, src/xmldsig/keys.rs, src/xmldsig/mod.rs
Adds verify-only DSA-SHA1 and HMAC-SHA1, HMAC output-length validation, DSA key parsing, generic ECDSA hash handling, and public verification exports.
Bounded references and canonicalization
src/xmldsig/verify.rs, src/xmldsig/uri.rs, src/xmldsig/types.rs, src/xmldsig/transforms.rs, src/c14n/*, src/xmldsig/xpath.rs
Adds caller-supplied external resources, RetrievalMethod handling, XML Base budgets, canonicalization limits, controlled DTD parsing, XML node limits, and comment-aware dereferencing.
X.509 trust and path validation
src/xmldsig/keys.rs, src/xmldsig/parse.rs, src/xmldsig/x509.rs
Separates lookup certificates from trust anchors, validates certificate paths and CRLs, normalizes distinguished names, and supports provider-backed certificate algorithms.

Interoperability and validation tooling

Layer / File(s) Summary
Merlin corpus and XMLDSig tests
tests/merlin_interop.rs, tests/donor_full_verification_suite.rs, tests/donor_negative_vectors.rs, tests/fixtures/xmldsig/*, tests/fixtures_smoke.rs
Adds Merlin fixtures and positive and negative coverage for DSA, HMAC, external resources, RetrievalMethod, X.509, CRLs, manifests, and policy failures.
XMLSec installation and CI
scripts/install-xmlsec1.sh, tests/install_xmlsec1.rs, tests/common/xmlsec1.rs, tests/xmlsec1_interop.rs, tests/xmlenc_encrypt_xmlsec1.rs, .github/workflows/ci.yml
Adds pinned XMLSec installation, rollback tests, shared version checks, interoperability commands, and nightly fuzz smoke tests.
Fuzzing, documentation, and repository support
fuzz/*, Cargo.toml, README.md, docs/*, .gitattributes, .gitignore, scripts/import-donor-fixtures.sh
Adds the fuzz package and corpus, updates feature dependencies and documentation, and normalizes imported Merlin fixtures.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant VerifyContext
  participant UriReferenceResolver
  participant KeyResolver
  participant X509Chain
  participant CryptoProvider
  VerifyContext->>UriReferenceResolver: Resolve bounded same-document or caller-supplied external data
  VerifyContext->>KeyResolver: Resolve KeyInfo and RetrievalMethod sources
  KeyResolver->>X509Chain: Build and validate certificate path
  VerifyContext->>CryptoProvider: Digest and verify the signature
  CryptoProvider-->>VerifyContext: Return verification result
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning Most acceptance criteria are addressed, but the reported RFC 4514 name-matching fix is not confirmed on the PR head. Include and verify the RFC 4514 certificate-name matching fix, with regression tests for escaped characters, spaces, XML whitespace, and RDN order.
Out of Scope Changes check ⚠️ Warning The PR includes substantial XML encryption changes and installer work that are not required by issue #105's XMLDSig interoperability scope. Move unrelated XML encryption, generic provider, and installer changes to separate pull requests unless they are required dependencies for issue #105.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main change: completing Merlin XMLDSig interoperability.
Description check ✅ Passed The description directly explains the Merlin interoperability work, implementation changes, testing, and linked issue.
Docstring Coverage ✅ Passed Docstring coverage is 89.47% which is sufficient. The required threshold is 80.00%.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/#105-merlin-interop

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 164a9bb4e9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tests/merlin_interop.rs Outdated
Comment thread src/xmldsig/uri.rs Outdated
Comment thread src/xmldsig/verify.rs
Comment thread src/xmldsig/verify.rs Outdated
Comment thread src/xmldsig/keys.rs Outdated
Comment thread src/xmldsig/keys.rs Outdated
Comment thread src/xmldsig/keys.rs Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/xmldsig/verify.rs (1)

1168-1172: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

The per-signature Reference cap no longer counts unsupported-transform Manifest references.

Line 1168 compares references.len() against MAX_REFERENCES_PER_SIGNATURE. After this change, a reference whose transform chain is unsupported is pushed to invalid at lines 1179-1190 and never to references. A Manifest that contains only such references therefore leaves references empty while invalid grows for every entry, and each entry allocates a ReferenceResult with an owned URI String.

The cap intends to bound the total references one signature may process, as its own message states. Count both collections.

Reachability is limited: Manifest parsing runs only after every SignedInfo reference digest and the SignatureValue validate, so the attacker must already hold a valid signature over the enclosing Object or Manifest. nodes_limit: 100_000 also caps total growth. The check is still wrong relative to its stated intent.

🐛 Proposed fix: apply the cap to parsed and invalid references together
-                if references.len() == MAX_REFERENCES_PER_SIGNATURE {
+                if references.len() + invalid.len() == MAX_REFERENCES_PER_SIGNATURE {
                     return Err(SignatureVerificationPipelineError::InvalidStructure {
                         reason: "signed Manifests exceed the per-signature Reference limit",
                     });
                 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/xmldsig/verify.rs` around lines 1168 - 1172, Update the per-signature
limit check in the Manifest reference-processing logic to count both supported
references in references and unsupported-transform entries in invalid. Enforce
MAX_REFERENCES_PER_SIGNATURE against their combined count before accepting
another entry, while preserving the existing InvalidStructure error and
collection behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/xmldsig.md`:
- Around line 6-7: Update the lead sentence in the XMLDSIG documentation to
remove the outdated “same-document” limitation, aligning its stated scope with
the caller-supplied external references documented later. Preserve the existing
feature list and wording otherwise.

In `@src/xmldsig/keys.rs`:
- Around line 44-66: Update HmacSha1VerificationKey and its VerifyingKey::verify
implementation to bind and enforce a configured expected HMAC-SHA1 output
length, rejecting signature_value lengths that differ before comparison. Remove
the caller-controlled prefix-length behavior while preserving the algorithm
mismatch and invalid-length failure paths.

In `@src/xmldsig/parse.rs`:
- Around line 495-504: Extract the shared “first element child after optional
XMLDSIG Transforms” traversal into a helper near the parsing logic, preserving
the existing missing-element and namespace checks. Update both
parse_reference_with_xpath_budget and reference_digest_method to call this
helper so their Transforms-then-DigestMethod walks remain identical, while
keeping each function’s subsequent parsing and error handling unchanged.
- Around line 796-819: Update parse_dsa_key_value to accept and ignore the
schema-defined optional children J, Seed, and PgenCounter after Y, while
retaining the required P, Q, G, and Y validation and ordering. Consume only
valid trailing elements, including the required Seed/PgenCounter pairing, and
return KeyValueInfo::Dsa for supported inputs instead of rejecting them as extra
children; preserve ParseError handling for malformed required structure.
- Around line 632-679: Update parse_retrieval_method_transforms to validate the
XPath expression by its namespace-resolved QName rather than requiring the
literal dsig prefix. Accept any prefix bound to XMLDSIG_NS while preserving the
ancestor-or-self::X509Data selection requirement, and retain the existing
namespace binding validation behavior.

In `@src/xmldsig/signature.rs`:
- Around line 298-303: Rename minimum_rsa_modulus_bits to reflect that it only
validates or enforces the algorithm in validate_rsa_public_key, and discard its
return value explicitly since minimum_modulus_bits remains the caller-provided
policy. Update the direct call in
ecdsa_algorithms_are_rejected_for_rsa_verification to use the renamed helper.
- Around line 219-228: Update DSA signature handling in VerificationKey::verify
and the DSA arm of verify_with_algorithm so Signature::from_components failures
are treated as a verification miss, returning Ok(false) and ultimately
DsigStatus::Invalid(SignatureMismatch) rather than propagating
InvalidSignatureFormat as DsigError::Crypto. Preserve the existing wrong-length
behavior and ensure malformed r or s components follow the same path.

In `@tests/merlin_interop.rs`:
- Around line 403-414: Replace the bare negative assertions with exact
error-variant matches and remove earlier competing failures: in
tests/merlin_interop.rs lines 403-414, configure UriTypeSet::ALL, provide
external_resources(&resources), and match the ambiguous-ID error; at lines
332-342, build the aggregate map from external_resources() and match the
total-size bound error; at lines 428-446, match the internal-DTD error for the
first assertion, then allow the URI class and provide resources for the
unsupported RetrievalMethod case so it matches the transform-compatibility
error.

---

Outside diff comments:
In `@src/xmldsig/verify.rs`:
- Around line 1168-1172: Update the per-signature limit check in the Manifest
reference-processing logic to count both supported references in references and
unsupported-transform entries in invalid. Enforce MAX_REFERENCES_PER_SIGNATURE
against their combined count before accepting another entry, while preserving
the existing InvalidStructure error and collection behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 4f956903-ad41-42c5-bd61-327533d316e1

📥 Commits

Reviewing files that changed from the base of the PR and between 0bf4812 and 164a9bb.

📒 Files selected for processing (15)
  • Cargo.toml
  • README.md
  • docs/xmldsig.md
  • src/xmldsig/keys.rs
  • src/xmldsig/mod.rs
  • src/xmldsig/parse.rs
  • src/xmldsig/signature.rs
  • src/xmldsig/types.rs
  • src/xmldsig/uri.rs
  • src/xmldsig/verify.rs
  • src/xmldsig/x509.rs
  • src/xmldsig/xpath.rs
  • tests/donor_full_verification_suite.rs
  • tests/merlin_interop.rs
  • tests/uri_integration.rs

Comment thread docs/xmldsig.md
Comment thread src/xmldsig/keys.rs
Comment thread src/xmldsig/parse.rs
Comment thread src/xmldsig/parse.rs
Comment thread src/xmldsig/parse.rs
Comment thread src/xmldsig/signature.rs Outdated
Comment thread src/xmldsig/signature.rs Outdated
Comment thread tests/merlin_interop.rs
- track the complete Merlin fixture snapshot for hermetic CI\n- harden HMAC, legacy RSA, X509, RetrievalMethod, and Manifest paths\n- add regression coverage for every reviewed failure mode
@polaz

polaz commented Aug 5, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai Re: outside-diff Manifest reference cap finding — fixed in d9a013c. The aggregate guard now counts both successfully parsed references and unsupported-transform results before accepting another entry. manifest_reference_limit_counts_unsupported_entries covers a Manifest made entirely of unsupported references and proves the shared cap.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

git show --stat --oneline --decorate --no-renames d9a013c
git show --format=fuller --find-renames --find-copies -- src/xmldsig/verify.rs tests/merlin_interop.rs d9a013c

printf '\n--- Manifest limit guard contexts on the PR branch ---\n'
rg -n -C 8 'manifest_reference_limit_counts_unsupported_entries|unsupported.*transform|reference.*limit|Manifest' \
  src/xmldsig/verify.rs tests/merlin_interop.rs

Length of output: 83253


@polaz Confirmed. In src/xmldsig/verify.rs, the guard now counts references and invalid entries before it parses the next Manifest reference. Unsupported-transform references therefore consume the shared per-signature limit.

manifest_reference_limit_counts_unsupported_entries creates one entry beyond MAX_REFERENCES_PER_SIGNATURE using only unsupported transforms. It asserts the expected structural-limit error.


If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

You are interacting with an AI system.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/merlin_interop.rs (1)

480-486: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Negative assertions in rejects_dtd_and_unsupported_retrieval_defaults do not pin the intended failure. Both assertions match an outer error variant only. In each case a different code path can satisfy the match, so the rule under test is not proven. Pin the exact failure at each site.

  • tests/merlin_interop.rs#L480-L486: bind the error and assert DsigError::DisallowedUri { uri } where uri == "http://www.w3.org/TR/xml-stylesheet", because enforce_reference_policies rejects the SignedInfo reference before materialize_retrieval_methods evaluates the RetrievalMethod URI. Add a second case that allows the reference URI class but not the RetrievalMethod URI class to prove that policy.
  • tests/merlin_interop.rs#L458-L472: match the inner ParseKeyInfo error for the unsupported RetrievalMethod transform shape instead of ParseKeyInfo(_).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/merlin_interop.rs` around lines 480 - 486, The negative assertions in
rejects_dtd_and_unsupported_retrieval_defaults must pin the intended failures:
at tests/merlin_interop.rs:480-486, bind DsigError::DisallowedUri and assert uri
equals "http://www.w3.org/TR/xml-stylesheet", then add a case permitting the
reference URI class while rejecting the RetrievalMethod URI class; at
tests/merlin_interop.rs:458-472, match the specific inner ParseKeyInfo error for
the unsupported RetrievalMethod transform rather than accepting any ParseKeyInfo
variant.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/xmldsig/verify.rs`:
- Around line 2429-2459: Extend retrieval-method test coverage for the ambiguous
`(Some, Some)` relation by adding a fixture with an `X509Data` target containing
a descendant `X509Data`, then add a separate test named
`retrieval_method_rejects_ambiguous_x509_data_relation` that expects
`materialize_retrieval_methods` to return `InvalidStructure` with reason
`"X509Data RetrievalMethod selected multiple X509Data elements"`.

In `@tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/Readme.txt`:
- Around line 36-40: Update the key-resolution instructions in the README to
replace the placeholder common name “Xxx” with “Lugh” and replace
“certs/xxx.crt” with the actual certificate filename under certs/ that contains
Lugh’s subject common name.

In
`@tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-enveloping-hmac-sha1-40.tmpl`:
- Line 6: Restore the 40-bit negative HMAC test vector by changing
HMACOutputLength to 40 in both
tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-enveloping-hmac-sha1-40.tmpl:6-6
and
tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-enveloping-hmac-sha1-40.xml:6-14,
then regenerate the XML fixture’s matching SignatureValue to reflect the updated
SignedInfo.

In `@tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature.xml`:
- Around line 143-152: Add a concise code comment at the descendant-selection
branch in materialize_retrieval_methods documenting that this fixture declares
ancestor-or-self::dsig:X509Data while `#object-4` contains X509Data as a
descendant, so the deliberate relaxation must be preserved. Do not alter the
selection behavior.

---

Outside diff comments:
In `@tests/merlin_interop.rs`:
- Around line 480-486: The negative assertions in
rejects_dtd_and_unsupported_retrieval_defaults must pin the intended failures:
at tests/merlin_interop.rs:480-486, bind DsigError::DisallowedUri and assert uri
equals "http://www.w3.org/TR/xml-stylesheet", then add a case permitting the
reference URI class while rejecting the RetrievalMethod URI class; at
tests/merlin_interop.rs:458-472, match the specific inner ParseKeyInfo error for
the unsupported RetrievalMethod transform rather than accepting any ParseKeyInfo
variant.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e72f5e14-8e41-4653-aa57-4fb1e380a5d8

📥 Commits

Reviewing files that changed from the base of the PR and between 164a9bb and d9a013c.

⛔ Files ignored due to path filters (10)
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/certs/badb.pem is excluded by !**/*.pem
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/certs/balor.pem is excluded by !**/*.pem
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/certs/bres.pem is excluded by !**/*.pem
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/certs/ca.pem is excluded by !**/*.pem
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/certs/lugh-cert.pem is excluded by !**/*.pem
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/certs/lugh.pem is excluded by !**/*.pem
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/certs/macha.pem is excluded by !**/*.pem
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/certs/merlin.pem is excluded by !**/*.pem
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/certs/morigu.pem is excluded by !**/*.pem
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/certs/nemain.pem is excluded by !**/*.pem
📒 Files selected for processing (46)
  • .gitattributes
  • docs/xmldsig.md
  • scripts/import-donor-fixtures.sh
  • src/xmldsig/keys.rs
  • src/xmldsig/parse.rs
  • src/xmldsig/signature.rs
  • src/xmldsig/verify.rs
  • src/xmldsig/x509.rs
  • tests/fixtures/xmldsig/external-data/xml-stylesheet-2005
  • tests/fixtures/xmldsig/external-data/xml-stylesheet-2005.b64
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/Readme.txt
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/certs/badb.der
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/certs/balor.der
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/certs/ca.der
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/certs/lugh-cert.der
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/certs/lugh.der
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/certs/macha.der
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/certs/merlin.der
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/certs/nemain.der
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-enveloped-dsa.tmpl
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-enveloping-b64-dsa.tmpl
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-enveloping-b64-dsa.xml
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-enveloping-dsa.tmpl
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-enveloping-dsa.xml
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-enveloping-hmac-sha1-40.tmpl
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-enveloping-hmac-sha1-40.xml
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-enveloping-hmac-sha1.tmpl
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-enveloping-hmac-sha1.xml
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-enveloping-rsa.tmpl
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-external-b64-dsa.tmpl
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-external-b64-dsa.xml
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-external-dsa.tmpl
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-external-dsa.xml
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-keyname.tmpl
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-keyname.xml
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-retrievalmethod-rawx509crt.tmpl
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-retrievalmethod-rawx509crt.xml
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-x509-crt-crl.tmpl
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-x509-crt.tmpl
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-x509-is.tmpl
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-x509-ski.tmpl
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-x509-sn.tmpl
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature.tmpl
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature.xml
  • tests/fixtures_smoke.rs
  • tests/merlin_interop.rs

Comment thread src/xmldsig/verify.rs
Comment thread tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/Readme.txt Outdated
Comment thread tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature.xml

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d9a013c335

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/xmldsig/verify.rs Outdated
Comment thread src/xmldsig/verify.rs Outdated
Comment thread src/xmldsig/parse.rs Outdated
Comment thread src/xmldsig/parse.rs Outdated
- Preserve KeyInfo source order and bound X.509 materialization
- Parse complete simple-content text across XML node splits
- Separate reference and key-retrieval URI policies
- Normalize misleading Merlin donor artifacts reproducibly
@polaz

polaz commented Aug 5, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai Re: the outside-diff negative-assertion finding — fixed. The tests now match the exact unsupported-XPath ParseError and exact disallowed URI, and VerifyContext now separates signed-payload URI policy from RetrievalMethod URI policy so the second test isolates external key retrieval.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- Recent commits ---'
git log -8 --oneline --decorate

printf '%s\n' '--- Candidate files ---'
fd -t f '^(verify|merlin_interop)\.rs$' src tests

printf '%s\n' '--- Module outline ---'
ast-grep outline src/xmldsig/verify.rs --items all --type function,struct,impl --match 'VerifyContext|RetrievalMethod|Uri|URI|verify'

printf '%s\n' '--- Exact assertion and URI policy contexts ---'
rg -n -C 10 -i \
  'unsupported.*xpath|xpath.*unsupported|disallowed.*uri|uri.*disallowed|retrieval.*uri|external.*uri|VerifyContext|RetrievalMethod' \
  src/xmldsig/verify.rs tests/merlin_interop.rs

Length of output: 1584


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- e0ac4b2 patch for relevant files ---'
git show --format=fuller --find-renames --find-copies e0ac4b2 -- \
  src/xmldsig/verify.rs tests/merlin_interop.rs

printf '%s\n' '--- VerifyContext and verification function map ---'
ast-grep outline src/xmldsig/verify.rs --items all --type struct,function --match 'VerifyContext|verify|retrieval|uri|Uri'

printf '%s\n' '--- Relevant implementation and test contexts ---'
rg -n -i -C 12 \
  'unsupported.*xpath|xpath.*unsupported|disallowed.*uri|uri.*disallowed|retrieval.*uri|external.*uri|VerifyContext|RetrievalMethod' \
  src/xmldsig/verify.rs tests/merlin_interop.rs

Length of output: 163989


@polaz Confirmed on e0ac4b2.

tests/merlin_interop.rs now asserts the exact unsupported XPath error:

DsigError::ParseKeyInfo(ParseError::InvalidStructure("unsupported RetrievalMethod XPath selection"))

The test also separates the URI cases. It first asserts rejection of the signed-payload URI. It then allows signed-payload URIs and asserts rejection of the external RetrievalMethod URI.

VerifyContext::allowed_retrieval_method_uri_types is independent from VerifyContext::allowed_uri_types. materialize_retrieval_methods uses the retrieval-method policy. This isolates external key retrieval as required.


✏️ Learnings added
Learnt from: polaz
URL: https://github.com/structured-world/xml-sec/pull/106

Timestamp: 2026-08-05T09:18:02.390Z
Learning: In `src/xmldsig/verify.rs`, `VerifyContext::allowed_uri_types` controls signed-payload `<Reference>` URI classes, while `VerifyContext::allowed_retrieval_method_uri_types` independently controls `<KeyInfo>` `RetrievalMethod` URI classes. External signed payload permission must not implicitly enable external key retrieval.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

You are interacting with an AI system.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e0ac4b2ccf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/xmldsig/verify.rs Outdated
Comment thread src/xmldsig/x509.rs Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/import-donor-fixtures.sh`:
- Around line 51-55: Update the HMAC rename loop in normalize_imported_snapshot
to verify each signature-enveloping-hmac-sha1-40 source file exists before
calling mv, and fail with an actionable message identifying the changed or
missing donor fixture. Because this function may now return non-zero, update its
caller to propagate the status so cleanup occurs and replace_target is not run
on an incomplete snapshot.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3397fad8-dd2c-426c-a530-5be96c22bd3d

📥 Commits

Reviewing files that changed from the base of the PR and between d9a013c and e0ac4b2.

📒 Files selected for processing (8)
  • docs/xmldsig.md
  • scripts/import-donor-fixtures.sh
  • src/xmldsig/parse.rs
  • src/xmldsig/verify.rs
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-enveloping-hmac-sha1-80.tmpl
  • tests/fixtures/xmldsig/merlin-xmldsig-twenty-three/signature-enveloping-hmac-sha1-80.xml
  • tests/fixtures_smoke.rs
  • tests/merlin_interop.rs

Comment thread scripts/import-donor-fixtures.sh
- Require external URIs for raw X509 retrieval
- Preserve DSA fallback during rollover validation
- Fail donor fixture normalization without partial installs

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8fd4a488d9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/xmldsig/parse.rs Outdated
Comment thread src/xmldsig/verify.rs Outdated
Comment thread src/xmldsig/keys.rs Outdated
- accept schema-valid partial DSAKeyValue sources without aborting ordered fallback
- share same-document ID parsing across retrieval and manifest paths
- redact HMAC secret material from Debug output

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 155520bf3f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/xmldsig/parse.rs
polaz added 2 commits August 5, 2026 14:05
- Pin the unreleased upstream snapshot by commit and checksum
- Enforce RFC 5280 X.509 serial bounds and XML whitespace rules
- Add SHA-256 X509Digest coverage and a verification fuzz target
- Decode only XML text nodes in CryptoBinary simple content
- Cover comment-split DSA and RSA key parameters

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fbfb5c76af

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/xmldsig/verify.rs Outdated
Comment thread src/xmldsig/parse.rs Outdated
Comment thread src/xmldsig/verify.rs Outdated
Comment thread src/xmldsig/verify.rs Outdated
polaz added 2 commits August 5, 2026 15:25
- enforce transform policy from the terminal data type
- preserve unsupported advisory retrieval methods
- bound external XML parsing and retained diagnostics
- run fuzz smoke explicitly on nightly
Keep cargo-fuzz 0.13.1 pinned while allowing compatible transitive patch releases on current nightly.
@polaz

polaz commented Aug 5, 2026

Copy link
Copy Markdown
Member Author

@codex review

@polaz

polaz commented Aug 5, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/install-xmlsec1.sh`:
- Around line 63-66: Update the installation replacement flow around the
staged-prefix mv to restore work_dir/previous-install to prefix if that move
fails, before the EXIT trap removes the working installation. Preserve the
existing backup move and successful staged installation behavior.

In `@src/xmldsig/parse.rs`:
- Around line 1531-1557: Update the serial conversion logic before
format_x509_serial_value_hex to reject a bytes buffer containing only zeroes,
while preserving existing validation and overflow checks. Extend the relevant
rejection tests to cover zero-valued inputs such as "0" and "000".

In `@tests/common/xmlsec1.rs`:
- Around line 11-22: Update version_supports_interop to locate the xmlsec1
prefix, parse only the immediately following token as the version, and reject
inputs without that prefix or with non-numeric, missing, or extra version
components. Preserve the REQUIRED_VERSION comparison using exactly three numeric
components.

In `@tests/fixtures/xmldsig/README.md`:
- Around line 29-30: Update the README’s algorithm support statements to reflect
that DSA-SHA1 and HMAC-SHA1 verification are supported, while documenting only
the remaining unsupported DSA and HMAC variants as fail-closed. Keep the
surrounding X.509 and signing support descriptions unchanged.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 6cc7e228-8650-48c2-83a5-bac724cb8751

📥 Commits

Reviewing files that changed from the base of the PR and between 155520b and fa4a088.

📒 Files selected for processing (21)
  • .github/workflows/ci.yml
  • .gitignore
  • README.md
  • fuzz/Cargo.toml
  • fuzz/corpus/xmldsig_verify/signature.xml
  • fuzz/fuzz_targets/xmldsig_verify.rs
  • scripts/import-donor-fixtures.sh
  • scripts/install-xmlsec1.sh
  • src/hard_limits.rs
  • src/lib.rs
  • src/xmldsig/keys.rs
  • src/xmldsig/parse.rs
  • src/xmldsig/transforms.rs
  • src/xmldsig/verify.rs
  • tests/common/xmlsec1.rs
  • tests/fixtures/xmldsig/README.md
  • tests/fixtures/xmldsig/aleksey-xmldsig-01/enveloped-x509-digest-sha256.xml
  • tests/fixtures/xmlenc/README.md
  • tests/fixtures_smoke.rs
  • tests/xmlenc_encrypt_xmlsec1.rs
  • tests/xmlsec1_interop.rs

Comment thread scripts/install-xmlsec1.sh
Comment thread src/xmldsig/parse.rs Outdated
Comment thread tests/common/xmlsec1.rs Outdated
Comment thread tests/fixtures/xmldsig/README.md

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fa4a088110

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/xmldsig/parse.rs Outdated
Comment thread src/xmldsig/verify.rs Outdated
Comment thread src/xmldsig/parse.rs Outdated
- make xmlsec1 replacement transactional through validation
- enforce ordered X.509 names and positive serials
- support direct typed X509Data retrieval safely
- tighten interop version parsing and fixture documentation
@polaz

polaz commented Aug 6, 2026

Copy link
Copy Markdown
Member Author

@codex review

@polaz

polaz commented Aug 8, 2026

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 173ccb388b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/policy.rs Outdated
Comment thread src/xmldsig/keys.rs Outdated
Comment thread src/xmldsig/uri.rs Outdated
- Allow zero-valued deny-all resource ceilings while retaining nonzero X.509 path bounds
- Reject CRL checking without certificate-chain validation
- Share bounded XML Base resolution across references, key retrieval, and C14N

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/c14n/xml_base.rs (2)

98-134: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Delete the test-only duplicate of the XML Base walk.

compute_effective_xml_base is now #[cfg(test)]. Every production caller uses compute_effective_xml_base_with_budget. Two implementations of the same ancestor walk now exist, and only the budgeted one is exercised outside tests.

The two functions must stay in agreement, but nothing enforces that. A change to the boundary rule or the resolution order in one function would not fail the other. Tests that call the unbudgeted function would then assert behavior that production does not have.

Remove compute_effective_xml_base and call compute_effective_xml_base_with_budget with XmlBaseResolutionBudget::default() from the tests, or keep a thin #[cfg(test)] wrapper that delegates to the budgeted function.

♻️ Proposed refactor
 #[cfg(test)]
 pub(crate) fn compute_effective_xml_base(
     start: Node<'_, '_>,
     visibility: Option<&dyn NodeVisibility>,
 ) -> Option<String> {
-    let mut bases: Vec<&str> = Vec::new();
-    let mut current = Some(start);
-    while let Some(n) = current {
-        // ... duplicated walk ...
-    }
-    Some(effective)
+    // Tests exercise the same algorithm production uses; the default budget
+    // never triggers for the small fixtures in this module.
+    compute_effective_xml_base_with_budget(start, visibility, &XmlBaseResolutionBudget::default())
+        .expect("test fixtures stay within the default XML Base budget")
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/c14n/xml_base.rs` around lines 98 - 134, Remove the duplicated test-only
ancestor walk in compute_effective_xml_base and update its test callers to use
compute_effective_xml_base_with_budget with XmlBaseResolutionBudget::default().
Alternatively, retain only a thin test wrapper that delegates to the budgeted
implementation, ensuring tests exercise the same production logic.

239-295: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Document the external resource key contract.

external_resources and the resolver API only say callers provide external URI payloads, but external references resolve xml:base and lookup payload with resources.get(&resolved). Add one sentence stating that these keys should match the RFC 3986 resolved identity, including dot-segment removal and retained query/fragment suffixes, so callers do not use pre-normalization keys and miss payloads.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/c14n/xml_base.rs` around lines 239 - 295, Document the external resource
key contract near the external_resources/resolver API: state that keys must
match the RFC 3986 resolved URI identity, including dot-segment removal and
retained query or fragment suffixes. Do not alter the resolution logic; clarify
that callers must use the normalized resolved value rather than a
pre-normalization reference.
src/c14n/mod.rs (1)

425-456: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

The unbounded dispatch arm discards the supplied XML Base budget.

serialize_canonical_visible_with_position_dispatch accepts xml_base_resolution and forwards it only in the Some(max_output_bytes) arm. The None arm calls serialize_canonical_visible_with_position, which allocates a fresh XmlBaseResolutionBudget::default() in src/c14n/serialize.rs (line 201) and ignores the argument.

No caller reaches this today: the only caller that supplies a budget is canonicalize_with_visibility_and_position_bounded_with_xml_base_budget, and it always supplies Some(max_output_bytes). The signature nonetheless promises to honor the budget on both arms. A later unbounded caller would silently fall back to the hard-limit default instead of the operation policy, with no compile error.

Forward the budget through the unbounded arm.

♻️ Proposed refactor

Add a budget-aware unbounded entry point in src/c14n/serialize.rs:

pub(crate) fn serialize_canonical_visible_with_position_with_xml_base_budget(
    doc: &Document,
    visibility: Option<&dyn NodeVisibility>,
    with_comments: bool,
    ns_renderer: &dyn NsRenderer,
    config: C14nConfig,
    tracked_element: Option<NodeId>,
    xml_base_resolution: &XmlBaseResolutionBudget,
    output: &mut Vec<u8>,
) -> Result<Option<usize>, C14nError> {
    serialize_canonical_visible_with_position_bounded(
        doc,
        visibility,
        with_comments,
        ns_renderer,
        config,
        CanonicalOutputOptions::unbounded(tracked_element, xml_base_resolution),
        output,
    )
}

Then call it from the None arm:

-        None => serialize_canonical_visible_with_position(
+        None => serialize_canonical_visible_with_position_with_xml_base_budget(
             doc,
             visibility,
             with_comments,
             renderer,
             config,
             tracked_element,
+            xml_base_resolution,
             output,
         ),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/c14n/mod.rs` around lines 425 - 456, Update
serialize_canonical_visible_with_position_dispatch so the None(max_output_bytes)
arm preserves the supplied xml_base_resolution budget. Add a budget-aware
unbounded entry point alongside serialize_canonical_visible_with_position that
constructs CanonicalOutputOptions::unbounded with the provided budget, then call
it from the dispatch function while leaving the bounded arm unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/policy.rs`:
- Around line 180-193: Update the zero-value branch in nonzero_within so it
reports an accurate nonzero-violation reason instead of claiming the value
exceeds the configured ceiling; use ResourceLimit with maximum set to selected,
or the existing PolicyViolation::KeyTrust variant with wording that requires a
nonzero value. Preserve Self::within for positive values and keep actual set to
selected.

In `@src/xmldsig/uri.rs`:
- Around line 178-184: Update the None branch of the resolved URI match in the
URI resolution flow to normalize non-fragment URIs before returning them,
matching the behavior used when an xml:base exists while preserving fragment
handling. Add a regression test covering an external URI containing path
segments such as “..” with no xml:base, and verify it matches the normalized
caller-map key.

In `@src/xmlenc/encrypt.rs`:
- Around line 1139-1157: Extend
zero_resource_ceilings_allow_operations_that_consume_none with a second
assertion using a non-empty binary payload, and verify encryption fails under
the zero plaintext ceiling. Keep the existing empty-payload success assertion
unchanged so the test covers both zero consumption being allowed and any
positive consumption being denied.

---

Outside diff comments:
In `@src/c14n/mod.rs`:
- Around line 425-456: Update serialize_canonical_visible_with_position_dispatch
so the None(max_output_bytes) arm preserves the supplied xml_base_resolution
budget. Add a budget-aware unbounded entry point alongside
serialize_canonical_visible_with_position that constructs
CanonicalOutputOptions::unbounded with the provided budget, then call it from
the dispatch function while leaving the bounded arm unchanged.

In `@src/c14n/xml_base.rs`:
- Around line 98-134: Remove the duplicated test-only ancestor walk in
compute_effective_xml_base and update its test callers to use
compute_effective_xml_base_with_budget with XmlBaseResolutionBudget::default().
Alternatively, retain only a thin test wrapper that delegates to the budgeted
implementation, ensuring tests exercise the same production logic.
- Around line 239-295: Document the external resource key contract near the
external_resources/resolver API: state that keys must match the RFC 3986
resolved URI identity, including dot-segment removal and retained query or
fragment suffixes. Do not alter the resolution logic; clarify that callers must
use the normalized resolved value rather than a pre-normalization reference.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 7bc16b7f-9341-4b84-b332-6604b056fee3

📥 Commits

Reviewing files that changed from the base of the PR and between 173ccb3 and 88b185d.

📒 Files selected for processing (15)
  • README.md
  • docs/xmldsig.md
  • src/c14n/mod.rs
  • src/c14n/serialize.rs
  • src/c14n/xml_base.rs
  • src/hard_limits.rs
  • src/lib.rs
  • src/policy.rs
  • src/xmldsig/keys.rs
  • src/xmldsig/parse.rs
  • src/xmldsig/transforms.rs
  • src/xmldsig/types.rs
  • src/xmldsig/uri.rs
  • src/xmldsig/verify.rs
  • src/xmlenc/encrypt.rs
💤 Files with no reviewable changes (1)
  • src/lib.rs

Comment thread src/policy.rs
Comment thread src/xmldsig/uri.rs
Comment thread src/xmlenc/encrypt.rs

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 88b185dd3f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/xmldsig/verify.rs
- Meter repeated external dereferences through one resolver budget
- Preserve URI normalization and XML Base limits across all paths
- Report invalid lower-bound policy limits accurately

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 92bf93e66f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/xmldsig/verify.rs Outdated
Comment thread src/xmldsig/keys.rs Outdated
- share the operation XML Base budget with SignedInfo C14N

- route X.509 path and CRL authentication through the selected provider

- cover verification, signing, path-building, and CRL regressions

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a470602823

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/xmldsig/x509.rs Outdated
- select ECDSA digest from SignatureMethod or X.509 OID

- select P-256, P-384, or P-521 exclusively from SPKI

- cover cross-pair signing, verification, and donor vectors

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/xmldsig/sign.rs`:
- Around line 16-19: Override sign_with_provider on EcdsaP256SigningKey and
EcdsaP384SigningKey to obtain the digest through provider.digest for the
requested DigestAlgorithm, then pass the result to sign_prehash; retain sign as
the default-provider wrapper. Add regression coverage showing signing fails when
a custom CryptoProvider rejects each ECDSA digest.

In `@src/xmldsig/signature.rs`:
- Around line 374-381: Remove the unreachable 521 alternative from the P-521 arm
in the curve_oid/point_len match, keeping only point_len 528 mapped to
EcCurve::P521 with a 66-byte coordinate size.

In `@src/xmldsig/x509.rs`:
- Around line 357-368: Update x509_signature_algorithm to explicitly handle the
omitted ECDSA-SHA512, RSASSA-PSS, and SHA-2 DSA OIDs, either by mapping
supported algorithms or returning a distinct unsupported-algorithm result that
callers preserve as a diagnosable X509ChainError. Ensure unknown and
intentionally unsupported algorithms are not silently converted into an ordinary
InvalidSignature outcome.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d2ef2442-3a8b-4718-a3bc-ef5f9782f453

📥 Commits

Reviewing files that changed from the base of the PR and between 92bf93e and 42a25e8.

📒 Files selected for processing (15)
  • README.md
  • docs/xmldsig.md
  • src/c14n/mod.rs
  • src/xmldsig/keys.rs
  • src/xmldsig/parse.rs
  • src/xmldsig/sign.rs
  • src/xmldsig/signature.rs
  • src/xmldsig/verify.rs
  • src/xmldsig/x509.rs
  • tests/donor_full_verification_suite.rs
  • tests/donor_interop_suite.rs
  • tests/ecdsa_signature_integration.rs
  • tests/signature_builder.rs
  • tests/signing_digest.rs
  • tests/xmlsec1_interop.rs

Comment thread src/xmldsig/sign.rs
Comment thread src/xmldsig/signature.rs
Comment thread src/xmldsig/x509.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 42a25e8b5d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/xmldsig/verify.rs Outdated
Comment thread src/xmldsig/x509.rs Outdated
- route ECDSA prehashing through the selected provider\n- preserve typed X.509 RSA-PSS and Ed25519 verification\n- share canonicalization work across the verification pipeline

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/xmldsig/parse.rs`:
- Around line 1288-1290: Defer unsupported-signature failures in both builders:
in src/xmldsig/parse.rs#L1288-L1290 within build_x509_certificate_chain_from,
record the OID and continue candidate evaluation, returning the error only when
verified is empty and an OID was recorded; apply the same change at
src/xmldsig/parse.rs#L1369-L1371 within
build_x509_certificate_paths_to_trusted_prefix, reporting the recorded OID only
when completed is empty.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 7bd7ce92-3b27-4241-9120-5d78ea04a71f

📥 Commits

Reviewing files that changed from the base of the PR and between 42a25e8 and 37ad953.

📒 Files selected for processing (10)
  • Cargo.toml
  • README.md
  • docs/xmldsig.md
  • src/provider.rs
  • src/xmldsig/keys.rs
  • src/xmldsig/parse.rs
  • src/xmldsig/sign.rs
  • src/xmldsig/signature.rs
  • src/xmldsig/verify.rs
  • src/xmldsig/x509.rs

Comment thread src/xmldsig/parse.rs

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 37ad953fbb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/xmldsig/x509.rs
- defer unsupported certificate branches during bounded path search\n- route every modeled certificate OID to the selected provider\n- retain typed diagnostics when no supported path completes

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
docs/xmldsig.md (2)

85-88: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Scope the processing-error rule to core references.

Manifest processing records disallowed URIs and unsupported transforms as independent per-reference statuses. Lines 85-88 currently classify all such cases as processing errors. Limit this sentence to core <SignedInfo> processing and state the Manifest exception.

Proposed documentation fix
-Malformed XMLDSig structure, unsupported algorithms, disallowed reference URIs, and
-inconsistent `KeyInfo` metadata are processing errors rather than validity statuses.
+Malformed XMLDSig structure, unsupported algorithms in core signature processing,
+disallowed URIs in `<SignedInfo>` references, and inconsistent `KeyInfo` metadata are
+processing errors rather than validity statuses. Manifest policy violations and unsupported
+transforms remain independent per-reference statuses as described above.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/xmldsig.md` around lines 85 - 88, Update the processing-error statement
in the XMLDSig documentation to apply only to core `<SignedInfo>` processing,
and explicitly exclude Manifest per-reference statuses, including disallowed
URIs and unsupported transforms, from that classification.

115-119: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Document both internal-DTD gates.

VerifyContext::allow_internal_dtd(true) is only the per-call opt-in. Verification and detached XML parsing also require the applicable policy permission. State both requirements so readers do not assume that the per-call flag overrides policy.

Proposed documentation fix
-Internal DTD declarations are disabled by default and require
-`VerifyContext::allow_internal_dtd(true)`. The policy applies consistently to the signed document
+Internal DTD declarations are disabled by default. Verification requires both the applicable
+policy permission and `VerifyContext::allow_internal_dtd(true)`. The policy applies consistently
+to the signed document
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/xmldsig.md` around lines 115 - 119, Update the internal DTD
documentation around VerifyContext::allow_internal_dtd and detached XML parsing
to state that both the per-call opt-in and the applicable verification policy
permission are required; clarify that the per-call flag does not override
policy, while preserving the existing TransformOptions and SigningPolicy
descriptions.
♻️ Duplicate comments (1)
src/xmldsig/parse.rs (1)

1381-1392: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Continue evaluating same-DN issuers after a provider capability failure.

Line 1391 stops at the first unsupported issuer. Provider support can depend on the issuer SPKI, including the ECDSA curve. A later same-DN issuer can still verify the child certificate.

Record the OID, then continue the issuer loop. Return the unsupported-algorithm diagnostic only after all issuer candidates and DFS paths fail. Add a regression with an unsupported issuer candidate before a usable same-DN issuer.

Proposed fix
                         // Unsupported is an algorithm capability, so changing
-                        // the issuer key cannot make this child verifiable.
-                        // Prune this DFS branch but retain sibling paths.
+                        // the current candidate cannot verify this child.
+                        // Continue with other same-DN issuer candidates.
                         unsupported_oid.get_or_insert(oid);
-                        break;
+                        continue;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/xmldsig/parse.rs` around lines 1381 - 1392, In the issuer-evaluation loop
of the certificate-chain DFS, update the ProviderError::Unsupported handling to
record the OID in unsupported_oid but continue checking remaining same-DN
issuers instead of breaking. Preserve the unsupported-algorithm diagnostic only
after all issuer candidates and DFS paths fail, and add a regression covering an
unsupported issuer preceding a usable same-DN issuer.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@docs/xmldsig.md`:
- Around line 85-88: Update the processing-error statement in the XMLDSig
documentation to apply only to core `<SignedInfo>` processing, and explicitly
exclude Manifest per-reference statuses, including disallowed URIs and
unsupported transforms, from that classification.
- Around line 115-119: Update the internal DTD documentation around
VerifyContext::allow_internal_dtd and detached XML parsing to state that both
the per-call opt-in and the applicable verification policy permission are
required; clarify that the per-call flag does not override policy, while
preserving the existing TransformOptions and SigningPolicy descriptions.

---

Duplicate comments:
In `@src/xmldsig/parse.rs`:
- Around line 1381-1392: In the issuer-evaluation loop of the certificate-chain
DFS, update the ProviderError::Unsupported handling to record the OID in
unsupported_oid but continue checking remaining same-DN issuers instead of
breaking. Preserve the unsupported-algorithm diagnostic only after all issuer
candidates and DFS paths fail, and add a regression covering an unsupported
issuer preceding a usable same-DN issuer.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 92c7f864-365a-4f9e-9441-4221fa4a91bb

📥 Commits

Reviewing files that changed from the base of the PR and between 37ad953 and 168b648.

📒 Files selected for processing (4)
  • docs/xmldsig.md
  • src/xmldsig/keys.rs
  • src/xmldsig/parse.rs
  • src/xmldsig/x509.rs

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

xml-sec/src/xmldsig/x509.rs

Lines 498 to 500 in 168b648

if let Some(limit) = constraints.path_len_constraint {
let subordinate_ca_count = position.saturating_sub(1);
if subordinate_ca_count > limit as usize {

P2 Badge Exclude self-issued CAs from path-length counting

When a valid path contains a self-issued rollover CA below an anchor with pathLenConstraint = 0, this positional calculation counts the rollover certificate as a subordinate CA and rejects the path, although self-issued intermediates are excluded from the path-length count. Fresh evidence beyond the earlier path-construction issue is that construction now preserves these rollover paths, but this later constraint check still rejects them; compute the count from the actual lower path certificates while skipping self-issued CAs.


xml-sec/src/xmldsig/x509.rs

Lines 202 to 205 in 168b648

if position == 0 {
validate_leaf_key_usage(cert)?;
} else {
validate_ca_constraints(cert, position)?;

P1 Badge Enforce CA name constraints during path validation

When a validated intermediate contains a critical NameConstraints extension, this loop checks only validity, leaf key usage, and CA constraints, so a cryptographically valid leaf outside the CA's permitted namespace is still accepted. This can bypass restrictions imposed by a configured trust path; process NameConstraints against every subordinate certificate, and reject any other critical extension the validator does not implement.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/provider.rs Outdated
Comment thread src/xmlenc/encrypt.rs
Comment thread src/xmldsig/keys.rs
- Enforce RFC 4055 and RFC 5280 certificate restrictions
- Bind selector categories to one signature-valid path
- Reject unrepresentable legacy OAEP MGF parameters
- Clarify public validation and Manifest semantics

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
docs/xmldsig.md (1)

136-144: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Document the legacy-algorithm policy gate.

This section lists RSA-SHA1, DSA-SHA1, and HMAC-SHA1 as implemented but does not state the policy required to use them. Document the default and explicit opt-in behavior, including that RSA-SHA1 enforcement occurs before key resolution.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/xmldsig.md` around lines 136 - 144, Update the implemented-algorithms
section to document the legacy-algorithm policy gate: state that RSA-SHA1,
DSA-SHA1, and HMAC-SHA1 are disabled by default and require explicit opt-in, and
note that RSA-SHA1 policy enforcement occurs before key resolution.
src/xmlenc/encrypt.rs (2)

1116-1141: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Add the policy-denied DTD assertion.

The test covers policy permission with per-call opt-in and per-call denial when policy permission is enabled. It does not cover per-call opt-in when policy permission is disabled. A regression that checks only DocumentEncryptionOptions::allow_dtd would pass the current assertions.

Add an assertion that uses the default policy, sets allow_dtd: true, and expects Err(XmlEncError::XmlParse(_)).

Proposed test addition
         assert!(matches!(
             EncryptedDataBuilder::new(DataEncryptionAlgorithm::Aes128Gcm)
                 .direct_key([0_u8; 16])
                 .policy(policy)
                 .encrypt_document(document, DocumentEncryptionOptions::default()),
             Err(XmlEncError::XmlParse(_))
         ));
+
+        assert!(matches!(
+            EncryptedDataBuilder::new(DataEncryptionAlgorithm::Aes128Gcm)
+                .direct_key([0_u8; 16])
+                .encrypt_document(
+                    document,
+                    DocumentEncryptionOptions {
+                        element_id: None,
+                        allow_dtd: true,
+                    },
+                ),
+            Err(XmlEncError::XmlParse(_))
+        ));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/xmlenc/encrypt.rs` around lines 1116 - 1141, Add a third assertion to
document_dtd_requires_policy_and_per_call_opt_in using the default
EncryptionPolicy with DocumentEncryptionOptions.allow_dtd set to true, and
assert encrypt_document returns Err(XmlEncError::XmlParse(_)).

1170-1200: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Test rejection at the zero-recipient ceiling.

The test sets max_encryption_recipients to zero but only runs an operation with zero recipients. It does not prove that one configured recipient is rejected. Add an empty-payload AES Key Wrap case and assert TooManyRecipients { maximum: 0, actual: 1 }.

Proposed test addition
         assert!(matches!(
             EncryptedDataBuilder::new(DataEncryptionAlgorithm::Aes128Gcm)
                 .direct_key([0_u8; 16])
-                .policy(policy)
+                .policy(policy.clone())
                 .encrypt_binary(b"x"),
             Err(XmlEncError::PlaintextTooLarge {
                 maximum: 0,
                 actual: 1
             })
         ));
+
+        assert!(matches!(
+            EncryptedDataBuilder::new(DataEncryptionAlgorithm::Aes128Gcm)
+                .add_recipient(EncryptionRecipient::aes_key_wrap(
+                    [0_u8; 16],
+                    KeyWrapAlgorithm::AesKw128,
+                ))
+                .policy(policy)
+                .encrypt_binary(&[]),
+            Err(XmlEncError::TooManyRecipients {
+                maximum: 0,
+                actual: 1
+            })
+        ));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/xmlenc/encrypt.rs` around lines 1170 - 1200, Extend
zero_resource_ceilings_allow_operations_that_consume_none with an empty-payload
AES Key Wrap encryption using one configured recipient, and assert it returns
XmlEncError::TooManyRecipients { maximum: 0, actual: 1 }. Keep the existing
direct-key empty and non-empty plaintext assertions unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/xmldsig.md`:
- Around line 89-90: Update the Manifest reference policy documentation near the
existing transform-limit statement to describe the aggregate
ResourcePolicy::max_references budget: parsed Manifest references and
unsupported-transform results must consume the shared limit, including when
every reference is unsupported.

In `@src/provider.rs`:
- Around line 1569-1592: Add a short comment immediately before the
incompatible-case assertions explaining that each case must return Ok(false)
because rsa_pss_key_parameters_allow rejects the SPKI before verify_signature
can report unsupported, particularly for the Sha256/Sha384 digest mismatch;
record that this behavior depends on the current validation order and must be
preserved.

In `@src/xmldsig/parse.rs`:
- Around line 1659-1687: Document the intentional strict fallback in the `_ =>
left.value == right.value` arm of `x509_attribute_values_equal`: note that raw
`Any` equality requires identical ASN.1 tags and bytes, including for
`emailAddress`, `domainComponent`, and values that are not `DirectoryString`. Do
not alter the comparison behavior unless adding explicit IA5String handling.

In `@src/xmldsig/x509.rs`:
- Around line 562-588: Document the intentional rejection of critical
extendedKeyUsage (2.5.29.37) and certificatePolicies (2.5.29.32) alongside the
X.509 validation policy and support matrix. Explain that only the extensions
allowlisted by validate_critical_extensions are processed, so certificates
marking these extensions critical may fail with UnsupportedCriticalExtension,
while preserving the existing validation behavior.
- Around line 760-762: Update the URI handling in general_name_within_subtree
and its callers in validate_general_name to distinguish a non-matching URI from
one whose host cannot be parsed by uri_host. For excluded_subtrees, treat an
unevaluable URI constraint as excluded rather than allowing the certificate;
preserve fail-closed rejection for permitted_subtrees and normal matching
behavior for parseable hosts. Apply the same behavior to the related handling
around the additional URI cases.
- Around line 654-661: Update validate_certificate_names to call
validate_general_name for the subject DirectoryName only when
certificate.subject() contains at least one RDN; skip this check for an empty
subject DN while preserving the existing validation flow for non-empty subjects.
- Around line 1363-1370: Update the assertion in the test around
verify_generated_path to match the exact
X509ChainError::UnsupportedCriticalExtension variant and verify it contains OID
1.2.3.4, rather than accepting any error via is_err(). Preserve the test’s
rejection expectation while ensuring the failure is specifically caused by the
unprocessed critical extension allowlist.

---

Outside diff comments:
In `@docs/xmldsig.md`:
- Around line 136-144: Update the implemented-algorithms section to document the
legacy-algorithm policy gate: state that RSA-SHA1, DSA-SHA1, and HMAC-SHA1 are
disabled by default and require explicit opt-in, and note that RSA-SHA1 policy
enforcement occurs before key resolution.

In `@src/xmlenc/encrypt.rs`:
- Around line 1116-1141: Add a third assertion to
document_dtd_requires_policy_and_per_call_opt_in using the default
EncryptionPolicy with DocumentEncryptionOptions.allow_dtd set to true, and
assert encrypt_document returns Err(XmlEncError::XmlParse(_)).
- Around line 1170-1200: Extend
zero_resource_ceilings_allow_operations_that_consume_none with an empty-payload
AES Key Wrap encryption using one configured recipient, and assert it returns
XmlEncError::TooManyRecipients { maximum: 0, actual: 1 }. Keep the existing
direct-key empty and non-empty plaintext assertions unchanged.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: f1a59e62-6595-48b0-a560-0a3a62fa8d3b

📥 Commits

Reviewing files that changed from the base of the PR and between 168b648 and 2213a8d.

📒 Files selected for processing (8)
  • README.md
  • docs/xmldsig.md
  • docs/xmlenc.md
  • src/provider.rs
  • src/xmldsig/keys.rs
  • src/xmldsig/parse.rs
  • src/xmldsig/x509.rs
  • src/xmlenc/encrypt.rs

Comment thread docs/xmldsig.md
Comment thread src/provider.rs
Comment thread src/xmldsig/parse.rs
Comment thread src/xmldsig/x509.rs
Comment thread src/xmldsig/x509.rs Outdated
Comment thread src/xmldsig/x509.rs Outdated
Comment thread src/xmldsig/x509.rs Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2213a8d51f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/xmldsig/x509.rs
- distinguish unevaluable URI constraints from ordinary non-matches
- match IA5 distinguished-name values using RFC 5280 rules
- select rollover CRLs by key identity and authenticated applicability
- document policy budgets and critical-extension support
@greptile-apps

greptile-apps Bot commented Aug 9, 2026

Copy link
Copy Markdown

Too many files changed for review (101 files, 100 file limit).

Bypass the limit by tagging @greptile-apps to review.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5f46334b41

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/xmlenc/encrypt.rs
Comment thread src/xmlenc/decrypt.rs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/xmlenc/types.rs`:
- Around line 415-425: Update fixed_aes_key_size to derive sizes through the
existing DataEncryptionAlgorithm and KeyWrapAlgorithm typed parsers and their
key_len methods, rather than matching URI literals directly. Preserve None for
unsupported algorithms and ensure all supported AES variants continue returning
the parser-defined key length.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1d3d5a8f-800f-4102-80d4-4420abeeb635

📥 Commits

Reviewing files that changed from the base of the PR and between 2213a8d and 8ff5845.

📒 Files selected for processing (11)
  • README.md
  • docs/xmldsig.md
  • docs/xmlenc.md
  • src/provider.rs
  • src/xmldsig/parse.rs
  • src/xmldsig/x509.rs
  • src/xmlenc/decrypt.rs
  • src/xmlenc/encrypt.rs
  • src/xmlenc/parse.rs
  • src/xmlenc/types.rs
  • tests/x509_chain_integration.rs

Comment thread src/xmlenc/types.rs

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8ff58453ae

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/xmldsig/x509.rs
Comment thread src/xmldsig/x509.rs Outdated
Comment thread src/xmldsig/x509.rs
Comment thread src/xmlenc/decrypt.rs

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 082534bf14

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/xmldsig/x509.rs
Comment on lines +691 to +695
.extensions()
.iter()
.find_map(|extension| match extension.parsed_extension() {
ParsedExtension::NameConstraints(value) => Some(value),
_ => None,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject duplicate certificate-extension OIDs

When chain validation receives a CA certificate containing two critical NameConstraints extensions, this first-match lookup applies only the first one, while validate_critical_extensions accepts both as recognized extensions. A permissive first constraint followed by a restrictive second constraint can therefore allow an out-of-scope leaf to validate even though RFC 5280 forbids duplicate extension OIDs; reject duplicates before interpreting any extension.

Useful? React with 👍 / 👎.

Comment thread src/xmlenc/types.rs
Comment on lines +402 to +404
if let (Some(actual), Some(expected)) =
(self.key_size_bits, fixed_aes_key_size(&self.algorithm))
&& actual != expected

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject zero KeySize on typed RSA methods

When callers construct an RSA-OAEP EncryptionMethod with key_size_bits: Some(0), fixed_aes_key_size returns None, so this condition skips validation and decrypt_data can proceed through key resolution successfully. The XML parser rejects the identical zero KeySize, so typed input still bypasses the structural invariant this method is intended to share with parsed input; validate that every supplied KeySize is positive before applying algorithm-specific equality checks.

Useful? React with 👍 / 👎.

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.

feat(xmldsig): complete Merlin interoperability

1 participant