Skip to content

feat(xmlsec1): add keys, KeyInfo, templates and signature transforms on the owned tree - #461

Open
polaz wants to merge 1 commit into
mainfrom
feat/#451-xmlsec1-keys-tree
Open

polaz wants to merge 1 commit into
mainfrom
feat/#451-xmlsec1-keys-tree

Conversation

@polaz

@polaz polaz commented Nov 12, 2026

Copy link
Copy Markdown
Member

Summary

Changes

  • Core: key values, incremental digests and HMAC, private key import into a key inventory. The owned tree keeps an unlinked run of siblings (unlink_children), parses a fragment in the namespace context of an element or the document node under the policy (parse_in_context), replaces a node with such a run while handing over its IDs (replace_with_run), and copies a subtree from another tree with its ID registrations and the bindings it uses (copy_from). A fragment or copy linked away from its context declares the bindings it uses. An ID that two attached elements carry names neither, and a value a carrier still holds cannot be claimed again. The serializer writes a carriage return in text as 
 and namespace declarations before attributes, as libxml2 does.
  • Tree layer: xsFreeNodeList, xsParseInNodeContext, xsDocCopyNode, document::subtree, parsing under an explicit policy. The library policy is published there as one verification and signing pair, replaced as a whole by one republishing caller at a time.
  • One policy revision per operation: a KeyInfo read pins it in its context and hands it, with the read's resource budget and the URI classes admitted for each key reference, to the transform chains its references run; a run of a transform context pins its own. Key reads enforce the verification policy's key sources and key-retrieval URI classes and depth; digest, HMAC and signature transforms admit their method and key under the operation's policy before taking input. A verification with a caller-supplied key and no expected targets has one admission, VerificationPolicy::check_supplied_key_verification, shared by signature-value verification and the transforms.
  • xmltree.h, templates.h, keys.h, keysdata.h (binary value, symmetric and RSA/DSA/EC/DEREncodedKeyValue klasses), keyinfo.h (KeyName, KeyValue, RetrievalMethod, KeyInfoReference), keysmngr.h (manager, store protocol, simple store), digest/HMAC/signature klasses in the built-in crypto table, xmlSecCryptoAppKeyLoadMemory. MD5 and RIPEMD-160 klasses come with the legacy-algorithms feature.
  • Functions that read or write a file themselves are not offered: xmlSecKeyReadBinaryFile, xmlSecSimpleKeysStoreLoad, xmlSecSimpleKeysStoreLoad_ex, xmlSecSimpleKeysStoreSave; the headers say so and point to the memory entry points. Templates are built in the document they belong to.

Testing

Every C program under crates/xml-sec-xmlsec1/tests/c prints the same as the libxmlsec1 oracle, a 1.3.13 pre-release snapshot (capi --xmlsec1); tests (with the xmlsec1 oracle and SoftHSM), clippy with all features, formatting, the header check and the clean C API check pass locally on macOS; CI runs the full matrix.

Related

Part of #451

…on the owned tree

The libxmlsec1 keys, KeyInfo, keys managers, templates, xmltree helpers
and the digest, HMAC and signature transforms run over the owned document
tree through its handles; no C library is used.

- Core: key values, incremental digests and HMAC, private key import into
  a key inventory. The owned tree keeps an unlinked run of siblings,
  parses a fragment in the namespace context of an element or the
  document node under the policy, replaces a node with such a run while
  handing over its IDs, and copies a subtree from another tree with its
  ID registrations and the bindings it uses. A fragment or copy linked
  away from its context declares the bindings it uses. An ID that two
  attached elements carry names neither, and a value a carrier still
  holds cannot be claimed again. The serializer writes a carriage return
  in text as 
 and namespace declarations before attributes, as
  libxml2 does.
- Tree layer: xsFreeNodeList, xsParseInNodeContext, xsDocCopyNode,
  document::subtree, parsing under an explicit policy. The library policy
  is published there as one verification and signing pair, which
  republishing replaces as a whole, one caller at a time, with the edits
  run outside the snapshot lock.
- Every libxmlsec1 operation reads one policy revision: a KeyInfo read
  pins it in its context and hands it, with the read's resource budget
  and the URI classes admitted for each key reference, to the transform
  chains its references run; a run of a transform context pins its own.
  Key reads enforce the verification policy's key sources and
  key-retrieval URI classes and depth; digest, HMAC and signature
  transforms admit their method and key under the operation's policy
  before taking input. A verification with a caller-supplied key and no
  expected targets has one admission,
  VerificationPolicy::check_supplied_key_verification, which
  signature-value verification and the transforms share.
- xmltree.h, templates.h, keys.h, keysdata.h (binary value, symmetric and
  RSA/DSA/EC/DEREncodedKeyValue klasses), keyinfo.h (KeyName, KeyValue,
  RetrievalMethod, KeyInfoReference), keysmngr.h (manager, store
  protocol, simple store), digest/HMAC/signature klasses in the built-in
  crypto table, xmlSecCryptoAppKeyLoadMemory. MD5 and RIPEMD-160 klasses
  come with the legacy-algorithms feature. Tree edits report the failed
  libxml2-shaped call and return an error instead of leaving a
  half-written node; setters and adopt calls keep objects the caller
  passes back to them alive.
- Functions that read or write a file themselves are not offered
  (xmlSecKeyReadBinaryFile, xmlSecSimpleKeysStoreLoad,
  xmlSecSimpleKeysStoreLoad_ex, xmlSecSimpleKeysStoreSave); the headers
  say so and point to the memory entry points. Templates are built in the
  document they belong to. A KeyValue writer asked for the private key
  fails rather than writing only the public part.
- OpenSSL-compatible key import resizes a DSA generator to the modulus
  precision, wipes the private exponent and budgets against retained
  inventory material; a decrypted key of the wrong usage stays a
  candidate miss. Standalone signature-value verification checks the
  HMAC output minimum before any key hook, charges the supplied key and
  passes the certificate session to the provider. The CLI preflights
  signing keys against the remaining resource budget, and resource,
  policy and protected-container refusals stop lax key search.
- Every C program under crates/xml-sec-xmlsec1/tests/c prints the same as
  the libxmlsec1 oracle, a 1.3.13 pre-release snapshot.

Part of #451
@coderabbitai

coderabbitai Bot commented Nov 12, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 15 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration

Commits

Reviewing files that changed from the base of the PR and between f1c9a92 and fc7c03b.

Files selected for processing: 90

  • crates/xml-sec-libxml2/include/xs_tree.h
  • crates/xml-sec-libxml2/src/document.rs
  • crates/xml-sec-libxml2/src/document/tests.rs
  • crates/xml-sec-libxml2/src/ffi/tree.rs
  • crates/xml-sec-libxml2/src/ffi/tree/tests.rs
  • crates/xml-sec-libxml2/src/nodes.rs
  • crates/xml-sec-libxml2/src/policy.rs
  • crates/xml-sec-libxml2/src/policy/tests.rs
  • crates/xml-sec-xmlsec1/Cargo.toml
  • crates/xml-sec-xmlsec1/include/xmlsec/keys.h
  • crates/xml-sec-xmlsec1/include/xmlsec/keysmngr.h
  • crates/xml-sec-xmlsec1/src/ffi.rs
  • crates/xml-sec-xmlsec1/src/ffi/app.rs
  • crates/xml-sec-xmlsec1/src/ffi/app/tests.rs
  • crates/xml-sec-xmlsec1/src/ffi/asymkeys.rs
  • crates/xml-sec-xmlsec1/src/ffi/base64.rs
  • crates/xml-sec-xmlsec1/src/ffi/crypto.rs
  • crates/xml-sec-xmlsec1/src/ffi/errors.rs
  • crates/xml-sec-xmlsec1/src/ffi/keyinfo.rs
  • crates/xml-sec-xmlsec1/src/ffi/keyinfo/references.rs
  • crates/xml-sec-xmlsec1/src/ffi/keyinfo/tests.rs
  • crates/xml-sec-xmlsec1/src/ffi/keys.rs
  • crates/xml-sec-xmlsec1/src/ffi/keys/tests.rs
  • crates/xml-sec-xmlsec1/src/ffi/keysdata.rs
  • crates/xml-sec-xmlsec1/src/ffi/keysdata/binary.rs
  • crates/xml-sec-xmlsec1/src/ffi/keysmngr.rs
  • crates/xml-sec-xmlsec1/src/ffi/library/tests.rs
  • crates/xml-sec-xmlsec1/src/ffi/parser.rs
  • crates/xml-sec-xmlsec1/src/ffi/policy.rs
  • crates/xml-sec-xmlsec1/src/ffi/symkeys.rs
  • crates/xml-sec-xmlsec1/src/ffi/templates.rs
  • crates/xml-sec-xmlsec1/src/ffi/transforms.rs
  • crates/xml-sec-xmlsec1/src/ffi/transforms/builtin.rs
  • crates/xml-sec-xmlsec1/src/ffi/transforms/ctx.rs
  • crates/xml-sec-xmlsec1/src/ffi/transforms/digests.rs
  • crates/xml-sec-xmlsec1/src/ffi/transforms/digests/tests.rs
  • crates/xml-sec-xmlsec1/src/ffi/transforms/hmac.rs
  • crates/xml-sec-xmlsec1/src/ffi/transforms/hmac/tests.rs
  • crates/xml-sec-xmlsec1/src/ffi/transforms/io.rs
  • crates/xml-sec-xmlsec1/src/ffi/transforms/parser.rs
  • crates/xml-sec-xmlsec1/src/ffi/transforms/relationship.rs
  • crates/xml-sec-xmlsec1/src/ffi/transforms/signatures.rs
  • crates/xml-sec-xmlsec1/src/ffi/transforms/signatures/tests.rs
  • crates/xml-sec-xmlsec1/src/ffi/transforms/tests.rs
  • crates/xml-sec-xmlsec1/src/ffi/transforms/xpath.rs
  • crates/xml-sec-xmlsec1/src/ffi/xmltree.rs
  • crates/xml-sec-xmlsec1/src/ffi/xmltree/content.rs
  • crates/xml-sec-xmlsec1/src/ffi/xmltree/edit.rs
  • crates/xml-sec-xmlsec1/src/ffi/xmltree/edit/tests.rs
  • crates/xml-sec-xmlsec1/src/ffi/xmltree/qname.rs
  • crates/xml-sec-xmlsec1/tests/c/app.c
  • crates/xml-sec-xmlsec1/tests/c/asymkeys.c
  • crates/xml-sec-xmlsec1/tests/c/digests.c
  • crates/xml-sec-xmlsec1/tests/c/hmac.c
  • crates/xml-sec-xmlsec1/tests/c/keyinfo.c
  • crates/xml-sec-xmlsec1/tests/c/keys.c
  • crates/xml-sec-xmlsec1/tests/c/signatures.c
  • crates/xml-sec-xmlsec1/tests/c/symkeys.c
  • crates/xml-sec-xmlsec1/tests/c/templates.c
  • crates/xml-sec-xmlsec1/tests/c/tree.h
  • crates/xml-sec-xmlsec1/tests/c/xmltree.c
  • scripts/patches/xmloxide-0.5.0.patch
  • src/document/owned_tree.rs
  • src/document/owned_tree/ids.rs
  • src/document/owned_tree/tests.rs
  • src/key_manager.rs
  • src/key_manager/openssl.rs
  • src/key_manager/openssl/tests.rs
  • src/key_manager/public_key_tests.rs
  • src/parser_xmloxide/serial/xml.rs
  • src/policy.rs
  • src/xmldsig/digest.rs
  • src/xmldsig/keys.rs
  • src/xmldsig/keys/key_value_tests.rs
  • src/xmldsig/mac.rs
  • src/xmldsig/mod.rs
  • src/xmldsig/parse.rs
  • src/xmldsig/verify.rs
  • src/xmldsig/verify/capture.rs
  • src/xmldsig/verify/signature_value.rs
  • src/xmldsig/verify/signature_value/tests.rs
  • tools/xml-sec-tools/src/capi.rs
  • tools/xml-sec-tools/src/hardening.rs
  • tools/xml-sec-tools/src/hardening/tests.rs
  • tools/xml-sec-tools/src/xmlsec1_headers.rs
  • tools/xmlsec1/Cargo.toml
  • tools/xmlsec1/src/commands.rs
  • tools/xmlsec1/src/key_material.rs
  • tools/xmlsec1/src/key_material/modern_import_tests.rs
  • tools/xmlsec1/src/key_material/tests.rs
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 12, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-12T15:15:19.305305Z fc7c03b PR opened
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@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: fc7c03b52e

ℹ️ 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 on lines +732 to +735
for pos in 0..xmlSecPtrListGetSize(list) {
let key = xmlSecPtrListGetItem(list, pos).cast::<XmlSecKey>();
if !key.is_null() && xmlSecKeyMatch(key, name, &raw mut (*ctx).key_req) == 1 {
return xmlSecKeyDuplicate(key);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Enforce the compiled candidate budget during key-store searches

When a simple store contains more keys than ResourcePolicy::max_key_candidates, a document-controlled KeyName can make this loop inspect the entire store without charging or checking that allowance. Multiple unresolved names repeat the unbounded search, and the later signature-value verifier only charges its supplied key, so it cannot account for this earlier work. Unlike the core's find_named_entry, this lookup bypasses the operation's configured candidate limit. Charge each inspected entry against a budget shared by the pinned KeyInfo operation and propagate budget exhaustion rather than treating it as an ordinary missing key.

AGENTS.md reference: AGENTS.md:L25-L28

Useful? React with 👍 / 👎.

Comment thread src/xmldsig/mac.rs
Comment on lines +74 to +76
pub struct IncrementalHmac {
state: State,
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Move the incremental HMAC mechanism to signature-primitives

This introduces a new general-purpose incremental HMAC mechanism inside xml-sec: its state initialization, update and finalization operate on arbitrary bytes and contain no XML-specific behavior. That mechanism can serve the other signature consumers, so implementing it here violates the root AGENTS.md Shared Primitive Ownership requirement and creates another locally maintained crypto-dispatch implementation alongside the existing HMAC paths. Coordinate and link a signature-primitives dependency for the mechanism, keeping only the XMLDSig algorithm mapping and policy/transform integration here.

AGENTS.md reference: AGENTS.md:L9-L13

Useful? React with 👍 / 👎.

private: None,
},
);
if xmlSecKeySetValue(key, data) < 0 {

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 Check key requirements before adopting an asymmetric value

When a KeyInfo contains multiple key candidates and the first asymmetric value does not meet ctx.key_req (for example, an RSA value before the EC value requested by an ECDSA transform), this reader nevertheless installs that first value. xmlSecKeyInfoNodeRead then continues because the key does not match, but the next asymmetric reader fails with "key already has a value"; a subsequent KeyName also skips manager lookup because the value is non-null. Consequently, an unusable first candidate prevents selection of a later matching key. Check the newly constructed value against the context's requirements before installing it, and leave the destination empty when the candidate is inapplicable; apply the same handling to DEREncodedKeyValue.

Useful? React with 👍 / 👎.

This branch has not been deployed

No deployments
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.

1 participant