2022-02-11 09:48:49 +00:00
|
|
|
# Gatekeeper
|
2022-03-07 16:57:02 +00:00
|
|
|
|
|
|
|
When `syndicate-server` starts, it creates a *gatekeeper service entity*, which accepts
|
2023-02-10 15:40:32 +00:00
|
|
|
`resolve` assertions requesting conversion of a long-lived credential to a [live
|
2022-03-07 16:57:02 +00:00
|
|
|
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.
|
|
|
|
|
2022-03-08 05:58:12 +00:00
|
|
|
## Gatekeeper protocol
|
|
|
|
|
|
|
|
- Relevant schema: [[syndicate-protocol]/schemas/gatekeeper.prs](https://git.syndicate-lang.org/syndicate-lang/syndicate-protocols/src/branch/main/schemas/gatekeeper.prs)
|
|
|
|
|
2022-03-07 16:57:02 +00:00
|
|
|
```preserves-schema
|
2023-02-10 15:40:32 +00:00
|
|
|
Resolve = <resolve @step Step @observer #!Resolved> .
|
|
|
|
Resolved = <accepted @responderSession #!any> / Rejected .
|
|
|
|
Step = <<rec> @stepType symbol [@detail any]> .
|
|
|
|
Rejected = <rejected @detail any> .
|
2022-03-07 16:57:02 +00:00
|
|
|
```
|
|
|
|
|
2023-02-10 15:40:32 +00:00
|
|
|
When a request to resolve a given credential, a `Step`, appears, the gatekeeper entity queries a
|
2022-03-07 16:57:02 +00:00
|
|
|
dataspace (by default, the server's top-level `$config` dataspace) for `bind` assertions:
|
|
|
|
|
|
|
|
```preserves-schema
|
2023-02-10 15:40:32 +00:00
|
|
|
Bind = <bind @description Description @target #!any @observer BindObserver> .
|
|
|
|
Description = <<rec> @stepType symbol [@detail any]> .
|
|
|
|
BindObserver = @present #!Bound / @absent #f .
|
|
|
|
Bound = <bound @pathStep PathStep> / Rejected .
|
2022-03-07 16:57:02 +00:00
|
|
|
```
|
|
|
|
|
2023-02-10 15:40:32 +00:00
|
|
|
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.
|
2022-03-07 16:57:02 +00:00
|
|
|
|
|
|
|
## Sturdyrefs
|
|
|
|
|
2022-03-08 05:58:12 +00:00
|
|
|
- Relevant schema: [[syndicate-protocol]/schemas/sturdy.prs](https://git.syndicate-lang.org/syndicate-lang/syndicate-protocols/src/branch/main/schemas/sturdy.prs)
|
|
|
|
|
2022-03-07 16:57:02 +00:00
|
|
|
A "sturdyref" is a long-lived certificate including a cryptographic signature that can be
|
|
|
|
upgraded by a gatekeeper entity to a live reference to the entity named in the sturdyref. The
|
|
|
|
current sturdyref implementation is based on the design of
|
|
|
|
[Macaroons][].
|
|
|
|
|
2023-02-10 15:40:32 +00:00
|
|
|
**Example.** The sturdyref `<ref {oid: "syndicate" sig: #[acowDB2/oI+6aSEC3YIxGg==]}>` is valid
|
|
|
|
for the associated `Bind` assertion `<bind <ref {oid: "syndicate" key: #[]}> $ds #f>`.
|
|
|
|
|
2022-03-07 16:57:02 +00:00
|
|
|
The following definitions are taken from the
|
|
|
|
[sturdy.prs](https://git.syndicate-lang.org/syndicate-lang/syndicate-protocols/src/branch/main/schemas/sturdy.prs)
|
2022-10-13 08:37:06 +00:00
|
|
|
schema. For further detail, see the [reference](../../protocols/syndicate/gatekeeper.md).
|
2022-03-07 16:57:02 +00:00
|
|
|
|
|
|
|
```preserves-schema
|
2023-02-10 15:40:32 +00:00
|
|
|
SturdyStepType = =ref .
|
|
|
|
SturdyStepDetail = Parameters .
|
|
|
|
SturdyRef = <ref @parameters Parameters> .
|
|
|
|
```
|
|
|
|
|
|
|
|
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,
|
|
|
|
} .
|
2022-03-07 16:57:02 +00:00
|
|
|
```
|
|
|
|
|
2023-02-10 15:40:32 +00:00
|
|
|
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`.
|
2022-03-07 16:57:02 +00:00
|
|
|
|
|
|
|
### Attenuation of authority
|
|
|
|
|
|
|
|
When it comes to publishing assertions or sending messages to the entity denoted by a
|
|
|
|
sturdyref, the `caveatChain` is used to [attenuate](../../glossary.md#attenuation) the
|
|
|
|
authority denoted by the sturdyref by filtering and/or rewriting assertion and message bodies.
|
|
|
|
The `caveatChain` is run *right to left*, with newer rewrites-and-filters at the right-hand end
|
|
|
|
of the chain and older ones at the left-hand end. Of course, an empty `caveatChain` is an
|
2023-02-07 12:30:13 +00:00
|
|
|
unattenuated reference. The structure and interpretation of `Caveat`s is described fully in
|
|
|
|
[the relevant section of the Syndicate network protocol
|
|
|
|
specification](../../protocol.md#attenuation-of-authority).
|
|
|
|
|
|
|
|
The term "caveat" is shamelessly taken from [macaroons][], though our caveats presently embody
|
|
|
|
only what in the Macaroons paper are called "first-party caveats" over assertion structure;
|
|
|
|
future versions of the server may add "third-party caveats" and other, richer, predicates over
|
|
|
|
assertions.
|
2022-03-07 16:57:02 +00:00
|
|
|
|
|
|
|
[Macaroons]: ../../glossary.md#macaroon
|