Skip to content

feat: delegations can require calls to carry a signed sender_info#10452

Draft
aterga wants to merge 2 commits into
masterfrom
claude/fervent-mccarthy-tmfzpw-sender-info-required
Draft

feat: delegations can require calls to carry a signed sender_info#10452
aterga wants to merge 2 commits into
masterfrom
claude/fervent-mccarthy-tmfzpw-sender-info-required

Conversation

@aterga

@aterga aterga commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Delegations can require calls to carry a signed sender_info

This is step 1 of combining the two read-only-delegation experiments (#10447: sender_info attribute checking, #10449: delegation-level permissions): request delegations gain one bit — an optional sender_info_required field, covered by the delegation signature — that forces update calls authenticated through the chain to carry a (signed and verified) sender_info.

Why

The sender_info attribute mechanism of #10447 enforces implicit:permissions = "queries" when the attributes are present — but the party we want to constrain (the dapp holding the session key) decides whether to attach them, so it can lift the restriction by omitting the blob. This bit closes that hole while keeping all permission semantics in the certified attributes:

  • The delegation (which the dapp cannot alter — the field is part of the representation-independent hash, so stripping it invalidates the signature) says: "every update call must present the certified session attributes."
  • The attributes (sender_info, signed by the same issuer under ic-sender-info) say what the session may do, e.g. implicit:permissions = "queries" → update calls rejected per feat: reject update calls when sender_info restricts permissions to queries #10447.

Together: an issuer like Internet Identity signs a read-only delegation chain whose update calls must carry attributes that in turn forbid update calls — protocol-enforced, regardless of client cooperation. #10447 is being rebased on top of this PR so the stack forms the complete combined design.

Semantics

  • Field absent or false → today's behavior, byte-for-byte identical hashes for existing delegations; nothing in the ecosystem changes.
  • sender_info_required = true anywhere in the chain → update calls (/call path) without a sender_info are rejected with the new RequestValidationError::SenderInfoRequiredByDelegation; calls with one proceed through the existing signature verification of the blob. Requirements only accumulate along the chain (like targets).
  • Query and read_state requests are unaffected: read_state envelopes cannot carry a sender_info at all, and queries are not restricted by the permissions attribute anyway.
  • The presence check runs after envelope/delegation signature validation but before the (expensive) canister-signature verification of the sender_info itself.
  • Backward compatibility mirrors feat: reject update calls for delegations with queries-only permissions #10449's analysis: old replicas recompute the delegation hash without the unknown field, so restricted delegations fail closed on un-upgraded replicas (unusable rather than unrestricted); rollout is replicas first, issuers after.

Changes

  • ic-types: Delegation.sender_info_required (optional bool; hashed as nat 0/1 under the key sender_info_required), constructor, accessor; CBOR encoding tests.
  • ic-validator: DelegationRestrictions threaded through delegation-chain validation; presence enforcement on the call path; new error variant mirrored in ic-validator-ingress-message.
  • ic-validator-http-request-test-utils: delegate_to_with_sender_info_required chain-builder support.
  • Tests: signed-bytes golden test; e2e tests covering update-without-sender_info rejected / update-with-valid-sender_info accepted (chain rooted at the same canister signer that signed the attributes, mirroring the II setup) / query unaffected / false unrestricted / requirement in the middle of a chain.

Follow-ups

cargo test -p ic-types -p ic-validator -p ic-validator-ingress-message passes and clippy is clean. Bazel was not available in the development container, so CI should confirm the Bazel build.

https://claude.ai/code/session_01BQNgPJKgxWohrJ6owwJBzz


Generated by Claude Code

Adds an optional sender_info_required field to request delegations,
covered by the delegation signature. When a delegation in a request's
delegation chain sets it to true, update calls authenticated through
that chain must carry a (signed and verified) sender_info; calls
without one are rejected with the new SenderInfoRequiredByDelegation
error. Query and read_state requests are unaffected (read_state cannot
even carry a sender_info, and query responses cannot change state).

Since the field is part of the delegation's representation-independent
hash, the bearer of the delegation cannot lift the requirement by
stripping the field: doing so invalidates the delegation signature. For
the same reason, replicas that predate this change fail closed on such
delegations.

Combined with sender_info attribute checking (#10447), this lets
issuers like Internet Identity enforce read-only sessions end to end:
the delegation forces the certified session attributes to be present on
every update call, and the attributes' implicit:permissions = "queries"
then causes the call to be rejected. Without this bit, a dapp holding
the session key could lift the restriction by omitting the sender_info.

https://claude.ai/code/session_01BQNgPJKgxWohrJ6owwJBzz

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces an optional sender_info_required bit on request delegations (covered by the delegation signature / representation-independent hash) and enforces that update calls authenticated via a delegation chain must include a sender_info when any delegation in the chain requires it. This is part of combining the read-only delegation experiments by making “certified attributes must be present” protocol-enforceable.

Changes:

  • Add Delegation.sender_info_required: Option<bool> (hashes as nat 0/1 under sender_info_required) plus constructor/accessor and CBOR coverage.
  • Thread DelegationRestrictions through delegation validation and enforce sender_info presence on the update /call path (with a new SenderInfoRequiredByDelegation error).
  • Add test utilities and ingress-message e2e tests covering required/optional behavior and chain accumulation.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
rs/validator/src/ingress_validation.rs Introduces DelegationRestrictions, propagates sender_info_required through delegation validation, and enforces sender_info presence for update calls.
rs/types/types/src/messages/http.rs Adds sender_info_required to Delegation, constructor/accessor, and includes it in signed-bytes hashing when present.
rs/types/types/src/messages/http/tests.rs Updates Delegation CBOR serialization tests to include sender_info_required (null/bool).
rs/validator/tests/ingress_validation.rs Adds a signed-bytes golden test for delegations with sender_info_required.
rs/validator/src/ingress_validation/tests.rs Updates signature-validation unit tests to assert the returned restrictions include sender_info_required == false by default.
rs/validator/http_request_test_utils/src/lib.rs Extends delegation-chain builders to create delegations with sender_info_required.
rs/validator/ingress_message/tests/validate_request.rs Adds e2e tests for “required ⇒ reject missing sender_info”, “required ⇒ accept valid sender_info”, and “query unaffected”.
rs/validator/ingress_message/src/lib.rs Exposes the new error variant in the ingress-message wrapper crate and its Display text.
rs/validator/ingress_message/src/internal/mod.rs Maps the new ic_validator error variant into the wrapper crate’s error enum.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread rs/validator/src/ingress_validation.rs Outdated
Comment thread rs/validator/src/ingress_validation.rs
Avoid duplicating the shared request-content validation on the call
path by enforcing the sender_info_required restriction inside
validate_request_content behind a parameter, and fix a comment to say
query requests rather than query responses.

https://claude.ai/code/session_01BQNgPJKgxWohrJ6owwJBzz
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants