diff --git a/src/operation/builtin/gatekeeper.md b/src/operation/builtin/gatekeeper.md index 57b060f..db1d2a5 100644 --- a/src/operation/builtin/gatekeeper.md +++ b/src/operation/builtin/gatekeeper.md @@ -1,7 +1,7 @@ # Gatekeeper When `syndicate-server` starts, it creates a *gatekeeper service entity*, which accepts -`resolve` assertions requesting conversion of a long-lived "sturdyref" to a [live +`resolve` assertions requesting conversion of a long-lived credential to a [live reference](../../glossary.md#reference). The gatekeeper is the [default object](../../glossary.md#initial-ref), available as [OID](../../glossary.md#oid) 0 to peers at the other end of [relay listener](./relay-listener.md) connections. @@ -11,19 +11,30 @@ the other end of [relay listener](./relay-listener.md) connections. - Relevant schema: [[syndicate-protocol]/schemas/gatekeeper.prs](https://git.syndicate-lang.org/syndicate-lang/syndicate-protocols/src/branch/main/schemas/gatekeeper.prs) ```preserves-schema -Resolve = . +Resolve = . +Resolved = / Rejected . +Step = < @stepType symbol [@detail any]> . +Rejected = . ``` -When a request to resolve a given `sturdyref` appears, the gatekeeper entity queries a +When a request to resolve a given credential, a `Step`, appears, the gatekeeper entity queries a dataspace (by default, the server's top-level `$config` dataspace) for `bind` assertions: ```preserves-schema -Bind = . +Bind = . +Description = < @stepType symbol [@detail any]> . +BindObserver = @present #!Bound / @absent #f . +Bound = / Rejected . ``` -Each `bind` assertion matching the requested `sturdyref` is checked against the credentials -provided in the sturdyref, and if the checks pass, the `target` entity from the `bind` is -asserted to the `observer` in the `resolve`. +A `bind` assertion specifies the reference that backs a long-lived credential, and gives +instructions for checking the validity of a presented credential. Each `bind` assertion +matching a requested `Step` is checked using the `stepType`-specific `detail` in the +`Description` combined with the `detail` from the `Step`. If the checks pass, the `target` +entity from the `bind` is asserted in an `accepted` record to the `observer` in the `resolve`. +If the checks fail, a `rejected` record is asserted to the `observer`. If no `bind` matching a +particular `Step` exists, the system just waits; this allows it to be relaxed about ordering of +events. ## Sturdyrefs @@ -34,20 +45,59 @@ upgraded by a gatekeeper entity to a live reference to the entity named in the s current sturdyref implementation is based on the design of [Macaroons][]. +**Example.** The sturdyref `` is valid +for the associated `Bind` assertion ` $ds #f>`. + The following definitions are taken from the [sturdy.prs](https://git.syndicate-lang.org/syndicate-lang/syndicate-protocols/src/branch/main/schemas/sturdy.prs) schema. For further detail, see the [reference](../../protocols/syndicate/gatekeeper.md). ```preserves-schema -SturdyRef = . +SturdyStepType = =ref . +SturdyStepDetail = Parameters . +SturdyRef = . ``` -Within a `ref` record, the `oid` field is a free-form value that the targeted service chooses -to name itself. The `sig` is an iterated keyed-HMAC construction, just as in [macaroons][]. -First, the service's secret key is used to key an HMAC of the `oid`. Then, the result is used -to key an HMAC of the ([canonical form](../../guide/preserves.md#canonical-form) of the) first -`Caveat` in `caveatChain`. Each `Caveat`'s HMAC becomes the key for the next in the -`caveatChain`. The final result is equal to the `sig` field in a valid sturdyref. +First, when used as a `Step`, a sturdyref uses `ref` as its `stepType` and `Parameters` as its +`detail`. A sturdyref as a whole, then, is just the combination of the type and parameters in a +record. + +```preserves-schema +Parameters = { + oid: any, + sig: bytes, +} & @caveats CaveatsField . + +CaveatsField = + / @present { caveats: [Caveat ...] } + / @invalid { caveats: any } + / @absent {} . +``` + +The `Parameters` of a sturdyref are the `oid` field, which is a free-form value that the +targeted service chooses to name itself, and the `sig`, which is an iterated keyed-HMAC +construction, just as in [macaroons][]. The `sig` is derived from the `oid` and the service's +secret `key`: + +```preserves-schema +SturdyDescriptionDetail = { + oid: any, + key: bytes, +} . +``` + +In a `Bind` with `stepType` of `ref`, the `detail` in the `Description` should be a +`SturdyDescriptionDetail` value. The `key` is the secret key used to compute `sig`s on +sturdyrefs; the `oid` connects references with their defining `Bind`s. + +To compute a `sig` for a sturdyref, the service's secret key is first used to key an HMAC of +the `oid`. Then, the result is used to key an HMAC of the ([canonical +form](../../guide/preserves.md#canonical-form) of the) first `Caveat` in the ref's `caveats`, +if any. Each `Caveat`'s HMAC becomes the key for the next in the `caveatChain`. The `sig` is +the final result. + +When validating sturdyrefs, compute the `sig` fresh, starting from the `key` and `oid`, and +compare the final result to the presented `sig`. ### Attenuation of authority diff --git a/src/protocol.md b/src/protocol.md index dc9d87e..58032a2 100644 --- a/src/protocol.md +++ b/src/protocol.md @@ -779,8 +779,6 @@ The authoritative version of this schema is ```preserves-schema version 1 . -Attenuation = [Caveat ...]. - Caveat = Rewrite / Alts / Reject / @unknown any . Rewrite = . Reject = . diff --git a/src/protocols/syndicate/gatekeeper.md b/src/protocols/syndicate/gatekeeper.md index 9fafddb..9e8ef56 100644 --- a/src/protocols/syndicate/gatekeeper.md +++ b/src/protocols/syndicate/gatekeeper.md @@ -5,7 +5,7 @@ ## Gatekeeper protocol -The Gatekeeper protocol allows a peer to "upgrade" a `SturdyRef` to a live reference to an +The Gatekeeper protocol allows a peer to "upgrade" a (relatively) long-lived certificate to a live reference to an entity. For details of the use of `Resolve` and `Bind` assertions, see the [guide to the built-in gatekeeper entity](../../operation/builtin/gatekeeper.md). @@ -13,8 +13,16 @@ built-in gatekeeper entity](../../operation/builtin/gatekeeper.md). [`syndicate-server`](../../operation/system-bus.md) program. ``` -Resolve = . -Bind = . +Resolve = . +Bind = . +BindObserver = @present #!Bound / @absent #f . + +Resolved = / Rejected . +Bound = / Rejected . +Rejected = . + +Step = < @stepType symbol [@detail any]> . +Description = < @stepType symbol [@detail any]> . ``` ## Sturdy-reference structures @@ -25,10 +33,26 @@ an overview of `SturdyRef`s, see the [guide to the built-in gatekeeper entity](../../operation/builtin/gatekeeper.md#sturdyrefs). ``` -SturdyRef = . +SturdyRef = . +Parameters = { + oid: any, + sig: bytes, +} & @caveats CaveatsField . + +CaveatsField = + / @present { caveats: [Caveat ...] } + / @invalid { caveats: any } + / @absent {} . + +SturdyStepType = =ref . +SturdyStepDetail = Parameters . +SturdyDescriptionDetail = { + oid: any, + key: bytes, +} . ``` -The `sig` in a `SturdyRef` is an iterated keyed-HMAC construction, starting from an HMAC of the +The `sig` in a `Parameters` is an iterated keyed-HMAC construction, starting from an HMAC of the ref's *secret key* and its `oid`, following [macaroons][]. The specific function chosen is [HMAC](https://www.rfc-editor.org/rfc/rfc2104) using [BLAKE2s-256](https://www.rfc-editor.org/rfc/rfc7693), truncating the output to the first 16