Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions docs/references/ic-interface-spec/abstract-behavior.md
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,8 @@ SignedDelegation = {
delegation : {
pubkey : PublicKey;
targets : [CanisterId] | Unrestricted;
expiration : Timestamp
expiration : Timestamp;
permissions : Text | Unrestricted

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.

We could consider using an enumeration type here, but a text type is probably easier to handle.

};
signature : Signature
}
Expand Down Expand Up @@ -692,14 +693,15 @@ that represents Candid encoding; this is implicitly taking the method types, as

#### Envelope Authentication

The following predicate describes when an envelope `E` correctly signs the enclosed request with a key belonging to a user `U`, at time `T`: It returns which canister ids this envelope may be used at (as a set of principals).
The following predicate describes when an envelope `E` correctly signs the enclosed request with a key belonging to a user `U`, at time `T`: It returns which canister ids this envelope may be used at (as a set of principals). Every delegation whose `permissions` field is set must hold a supported value (`"queries"` or `"all"`); otherwise, the predicate fails for requests of any kind. Moreover, the predicate fails for update calls (requests of type `Request`) if any delegation in the chain restricts the sender to query calls and `read_state` requests (`permissions` field set to `"queries"`).
```
verify_envelope({ content = C }, U, T)
= { p : p is CanisterID } if U = anonymous_id
∧ C.sender_info = null
verify_envelope({ content = C, sender_pubkey = PK, sender_sig = Sig, sender_delegation = DS}, U, T)
= TS if U = mk_self_authenticating_id PK
∧ (PK', TS) = verify_delegations(DS, PK, T, { p : p is CanisterId })
∧ (C is Request ⇒ ∀ D ∈ DS. D.delegation.permissions ≠ "queries")
∧ verify_signature PK' Sig ("\x0Aic-request" · hash_of_map(C))
∧ (if PK = canister_signature_pk Signing_canister_id _:
C.sender_info = null
Expand All @@ -711,6 +713,7 @@ verify_delegations([D] · DS, PK, T, TS)
= verify_delegations(DS, D.pubkey, T, TS ∩ delegation_targets(D))
if verify_signature PK D.signature ("\x1Aic-request-auth-delegation" · hash_of_map(D.delegation))
∧ D.delegation.expiration ≥ T
∧ D.delegation.permissions ∈ { Unrestricted, "all", "queries" }
delegation_targets(D)
= if D.targets = Unrestricted
then { p : p is CanisterId }
Expand Down
9 changes: 9 additions & 0 deletions docs/references/ic-interface-spec/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@ sidebar:

## Changelog {#changelog}

<!-- Needs human verification: assign the final version number and replace "unreleased" with the release date when the permissions feature ships -->
### 0.63.0 (unreleased) {$0_63_0}
* New optional `permissions` field in request delegations restricting the kinds of requests
the delegation applies for: the value `"queries"` restricts the delegation to query calls
and `read_state` requests, so update calls carrying such a delegation in their chain of
delegations are not accepted; the value `"all"` permits all kinds of requests, same as
omitting the field. Requests of any kind carrying a delegation with any other value of
the `permissions` field are not accepted.

### 0.62.0 (2025-05-26) {$0_62_0}
* Inter-canister response callback messages might still be executed after the condition for `canister_on_low_wasm_memory` is triggered
and before the function `canister_on_low_wasm_memory` is executed.
Expand Down
10 changes: 9 additions & 1 deletion docs/references/ic-interface-spec/https-interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,14 @@ Signing transactions can be delegated from one key to another one. If delegation

- `targets` (`array` of `CanisterId`, optional): If this field is set, the delegation only applies for requests sent to the canisters in the list. The list must contain no more than 1000 elements; otherwise, the request will not be accepted by the IC.

- `permissions` (`text`, optional): If this field is set, the delegation only applies for the kinds of requests permitted by its value. The following values are supported:

- `"queries"`: the delegation only applies for query calls and `read_state` requests. Requests to `/call` endpoints (i.e., update calls, including calls to query methods submitted as update calls) are not accepted by the IC if any delegation in the chain carries this value: a subsequent delegation cannot lift the restriction imposed by a previous one.

- `"all"`: the delegation applies for all kinds of requests; this is the same as omitting the field.

If this field is set to any other value, then the delegation is invalid and requests of any kind whose chain of delegations contains the delegation will not be accepted by the IC.

- `signature` (`blob`): Signature on the 32-byte [representation-independent hash](#hash-of-map) of the map contained in the `delegation` field as described in [Signatures](./index.md#signatures), using the 27 bytes `\x1Aic-request-auth-delegation` as the domain separator.

For the first delegation in the array, this signature is created with the key corresponding to the public key from the `sender_pubkey` field, all subsequent delegations are signed with the key corresponding to the public key contained in the preceding delegation.
Expand All @@ -571,7 +579,7 @@ Field values are hashed as follows:

- Binary blobs (`canister_id`, `arg`, `nonce`, `module`) are hashed as-is.

- Strings (`request_type`, `method_name`) are hashed by hashing their binary encoding in UTF-8, without a terminal `\x00`.
- Strings (`request_type`, `method_name`, `permissions`) are hashed by hashing their binary encoding in UTF-8, without a terminal `\x00`.

- Natural numbers (`compute_allocation`, `memory_allocation`, `ingress_expiry`) are hashed by hashing their binary encoding using the shortest form [Unsigned LEB128](https://en.wikipedia.org/wiki/LEB128#Unsigned_LEB128) encoding. For example, `0` should be encoded as a single zero byte `[0x00]` and `624485` should be encoded as byte sequence `[0xE5, 0x8E, 0x26]`.

Expand Down
Loading