Skip to content
Merged
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
58 changes: 47 additions & 11 deletions specs/ccdp-distribution.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ One CCDP Distribution is served from one canonical `ccdpOrigin` under the
and `127.0.0.1` hosts. It contains:

- every protocol resource for each supported CCDP version, including one
self-contained Callback artifact containing its supported implementations; and
self-contained Callback artifact containing its supported implementations;
- one [version list](#version-list) naming the platform ceremony versions it
bundles; and
- their bundled JavaScript, workers, WASM, circuits, and libID-owned assets.

The resource graph distinguishes distributed assets from external assets.
Expand All @@ -42,9 +44,9 @@ and proof generation.

One Distribution may serve any number of independently operated OAuth Bridges.
It does not enumerate or register them: each Bridge selects a `ccdpOrigin`,
which serves the same public resources to all of them. A Bridge advertises only
platform/version pairs present in its selected Distribution; no shared
deployment system is required.
which serves the same public resources to all of them. An Application runs only
platform/version pairs that Distribution's [version list](#version-list) names
and it implements; no shared deployment system is required.

## HTTP contract

Expand All @@ -63,7 +65,7 @@ The Distribution exposes the exact versioned
roles, and execution contexts remain CCDP rules.

Prefetch and Prover contain their clearing bootstrap and entry code directly,
with no browser-visible manifest or second entry-script request. They may load implementation-private immutable chunks.
with no browser-visible code manifest or second entry-script request. They may load implementation-private immutable chunks.

The aggregate [Callback artifact](#callback-artifact) is retrieved server-side
by OAuth Bridges; the contract below defines its configuration slot, embedded
Expand All @@ -85,8 +87,8 @@ executes CCDP code. Other methods execute no CCDP code.
The not-found response is static HTML containing no script, style, link, form,
redirect, or protocol data.

Versioned protocol resources and the aggregate Callback artifact use
`Cache-Control: no-cache` and an ETag so a path may receive compatible
Versioned protocol resources, the aggregate Callback artifact, and the version
list use `Cache-Control: no-cache` and an ETag so a path may receive compatible
implementation updates. A breaking protocol change publishes new versioned
routes and adds its implementation to the Callback artifact. The Bridge serves
its configured Callback response with `no-store`, independently of its own
Expand All @@ -105,6 +107,7 @@ markup, executable code, or styling input is part of this contract.
| Resource | Form | Additional response contract |
|---|---|---|
| [Callback artifact](#callback-artifact) | self-contained HTML template at `/ccdp/callback.html`, retrieved server-side by OAuth Bridges | `text/html; charset=utf-8`, `no-cache` and ETag, with exact executable hashes in CSP. No browser CORS permission is needed for this retrieval. The configured response follows [Served response](#served-response). |
| [Version list](#version-list) | JSON at `/ccdp/versions.json`, fetched cross-origin by the Application | `application/json; charset=utf-8`, `no-cache` and ETag, `Access-Control-Allow-Origin: *`, and `Cross-Origin-Resource-Policy: cross-origin`. No other Distribution resource sends a CORS header. |
| Prefetch | top-level non-isolated HTML | `Cross-Origin-Opener-Policy: unsafe-none` and no COEP. Script/worker sources remain same-origin; `connect-src` admits local assets and the pinned external asset origins. |
| Prover | top-level HTML | `Document-Isolation-Policy: isolate-and-require-corp`, `Cross-Origin-Opener-Policy: unsafe-none`, and no COEP. |
| Prover isolation fallback | top-level HTML at `/ccdp/v{CCDPVersion}/prover/fallback` | `Cross-Origin-Opener-Policy: same-origin` and `Cross-Origin-Embedder-Policy: require-corp`. Same Prover entrypoint, fragment contract, and non-isolation response rules. |
Expand Down Expand Up @@ -321,6 +324,32 @@ the decoded body and composes the final HTML and headers as one unit. Upstream
cache and transfer headers are not copied: the source artifact is revalidated,
while the configured browser response is non-cacheable.

### Version list

- REQ-DIST-06: The Distribution MUST publish the version list below, naming
exactly the platform/version pairs whose Prover implementation it bundles;
the Application MUST validate it by that contract. Necessity: an Application
must select only pairs its Distribution supports.

`GET /ccdp/versions.json` is one JSON object keyed by the exact platform
identifier of each bundled platform profile. Each value is the platform
ceremony versions bundled for that platform: a nonempty, duplicate-free,
ascending array of unsigned 16-bit integers. Key order carries no meaning.

```json
{"github":[1],"google":[1],"x":[1]}
```

The path is unversioned, beside `/ccdp/callback.html`: the set is a property of
the Distribution, not of one CCDP version. The Application fetches it
cross-origin without credentials or redirects; the
[Bridge contract](oauth-bridge.md#public-configuration) owns how it selects
versions and clients from the list and the public record. A reader holds every
value to this grammar and ignores a platform key it does not know. Any other
violation, including a non-object top level, a value that is not such an array,
an empty array, a duplicate, and a non-ascending array, refuses the whole
resource.

### Prover isolation

- REQ-DIST-03 (upholds SP-CCDP-01): The Prover and its host MUST preserve the
Expand Down Expand Up @@ -381,7 +410,8 @@ resources, including shared resources, so their downloads and caches are reusabl

Activation is asset-complete: every immutable resource referenced by an updated
protocol resource or Worker is retrievable with its final bytes and response
metadata before that update becomes reachable.
metadata before that update becomes reachable. The version list becomes
reachable no earlier than the resources of every pair it names.
The external Aztec request set is qualified before promotion; CDN availability
cannot be made atomic with local deployment, and a later outage still fails
proving if no usable cache is present.
Expand All @@ -406,6 +436,9 @@ Request-invariant Prover policy deliberately permits classes of secure network
origins; runtime destination checks, not CSP, bind a ceremony to its Bridge and
notary. Local HTTP exceptions are confined to the popup origin policy.

The version list gates which platform ceremony versions an Application runs; a
wrong list withholds or fails ceremonies and releases nothing.

Callback deployment inputs are non-executable trusted configuration. Their
insertion cannot depend on OAuth ingress, change script bytes, or introduce
markup. The Bridge keeps that configured response separate from its upstream
Expand All @@ -418,9 +451,10 @@ authority; this document selects no ledger verification keys.

## Conformance

Publishers, static hosts, and Bridge artifact consumers implement the roles
above. The package's build and deployment tests may qualify them with any
serving software that produces these observable responses.
Publishers, static hosts, Bridge artifact consumers, and Application
version-list readers implement the roles above. The package's build and
deployment tests may qualify them with any serving software that produces
these observable responses.

- TEST-DIST-01 (exercises REQ-DIST-01):
GET/HEAD serve invariant decoded bytes and policy; conditional/encoding responses preserve them. Protocol and asset resources never redirect; unknown paths are inert. Any directory slash redirect stays on the same origin and ends in an inert failure. Both isolation profiles support allowed local and external requests without admitting remote executable code.
Expand All @@ -432,3 +466,5 @@ serving software that produces these observable responses.
Empty-cache Prefetch and execution use the same declared resource graph; shared resources are reusable, and ranged external responses remain readable under both isolation profiles.
- TEST-DIST-05 (exercises REQ-DIST-05):
Unchanged assets keep URLs, changed bytes get new URLs, both remain retrievable, and no updated document or Worker becomes reachable before all its local dependencies. External availability is qualified, not reported as atomic.
- TEST-DIST-06 (exercises REQ-DIST-06):
GET and HEAD serve the version list as `application/json; charset=utf-8` with `no-cache`, an ETag, `nosniff`, `Access-Control-Allow-Origin: *`, and `Cross-Origin-Resource-Policy: cross-origin`, without redirect, and no other resource sends a CORS header; its pairs equal the bundled Prover implementations. A reader ignores an unknown platform key; a non-object body, a non-array or non-integer value under any key, and an empty, duplicate-bearing, or non-ascending array refuse the resource.
7 changes: 7 additions & 0 deletions specs/ccdp.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,13 @@ Worker. Authorization is an external document, not a CCDP resource.
| Location and context | CCDP origin; same-origin module Service Worker whose response sets `Service-Worker-Allowed: /` and which Prefetch registers with `scope: '/'` |
| Role | Supports selected-profile fetches and the popup transport's same-origin continuity mechanism. It remains compatible with every live CCDP version and does not intercept unrelated origin traffic. |

### Version list `GET /ccdp/versions.json`

| Property | Contract |
|---|---|
| Location and context | CCDP origin; unversioned JSON that the Application fetches cross-origin before Prefetch |
| Role | Names, per platform, the platform ceremony versions the Distribution bundles. The [Distribution](ccdp-distribution.md#version-list) owns its grammar and response policy; the [OAuth Bridge contract](oauth-bridge.md#public-configuration) owns how the Application selects a version and client from it. |

### Common

#### Paths and versioning
Expand Down
65 changes: 38 additions & 27 deletions specs/oauth-bridge.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ One bridge deployment has these inputs. Every origin follows the
|---|---|
| `allowedAppOrigins` | Nonempty, duplicate-free set of canonical application origins, [origin patterns](popup-transport.md#6-origin-allowlists-and-binding), and `*` |
| CCDP origin | One canonical origin selected by the operator; defaults to `https://lib.id` when omitted |
| Platform profiles | Public OAuth client ID, supported ceremony versions, and an optional public `clientCredential` for each enabled platform |
| Platform profiles | For each enabled platform, one public OAuth client ID and a public `clientCredential` exactly when the platform's ceremony sends one; no version list |
| Callback inputs | One unversioned list `[allowedOrigins, ccdpOrigin]` derived from the values above, plus deployment-policy sources required by the [artifact contract](ccdp-distribution.md#configuration-insertion); no separate input configuration or CCDP version list |

Every enabled platform's OAuth registration uses `/auth/callback` on the
Expand Down Expand Up @@ -121,9 +121,9 @@ bridge must not be configured with either until the Callback in its selected
Distribution reads that member kind.

The public profile entries match the OAuth registrations used by Callback.
The bridge advertises only platform/version pairs supported by its selected
CCDP Distribution. Selecting a shared Distribution requires no reciprocal
configuration.
The bridge enumerates no versions; the Application resolves the pairs that run
under [Public configuration](#public-configuration). Selecting a shared
Distribution requires no reciprocal configuration.

## Route surface

Expand Down Expand Up @@ -158,16 +158,15 @@ is no request-time version negotiation.

## Public configuration

- REQ-BRIDGE-03: The Bridge and Application MUST produce and validate the
configuration record and response policy below. Necessity: each ceremony
must freeze one mutually supported profile and Distribution.
- REQ-BRIDGE-03: The Bridge and Application MUST follow the configuration
record, response policy, and version resolution rules below. Necessity: each
ceremony must freeze one mutually supported profile and Distribution.

`GET /api/v1/ceremony/config` returns `application/json` with this exact record:

```ts
interface PlatformConfig {
clientId: string
ceremonyVersions: readonly number[] // unsigned 16-bit integers
clientCredential?: string
}

Expand All @@ -184,17 +183,17 @@ The response rules are:
[origin policy](ccdp.md#origin-policy), with no credentials, path, query, or
fragment. The Application accepts the localhost HTTP exception for this field
and the Bridge origin it uses.
- Each platform entry has one public client ID and a nonempty, duplicate-free
list of supported ceremony versions. List order has no meaning.
- `clientCredential`, when present, is a nonempty printable ASCII string
without whitespace. It is an intentionally public OAuth application credential,
not a user access token. GitHub requires it and uses it as `client_secret`;
other profiles omit it unless their token exchange needs one. Missing required
credentials, null, empty, or wrongly typed values are invalid. The selected
platform owns any additional constraints.
- Unknown fields, malformed URLs, and unsupported numeric representations are
invalid. A platform absent from the client's closed local catalog is ignored;
known entries remain exact-validated before use.
- Each platform entry has one public client ID; the record carries no version
list.
- `clientCredential` is present exactly when the platform's ceremony sends one,
as a nonempty printable ASCII string without whitespace. It is an
intentionally public OAuth application credential, not a user access token.
GitHub requires it and uses it as `client_secret`. A missing, unexpected,
null, empty, or wrongly typed credential is invalid. The selected platform
owns any additional constraints.
- Unknown fields and malformed URLs are invalid. A platform absent from the
client's closed local catalog is ignored; known entries remain
exact-validated before use.
- The record contains no redirect URI, confidential credential, user token,
allowlist, artifact URL, CSP source, notary setting, platform display metadata,
or application-specific value.
Expand All @@ -221,7 +220,14 @@ requests return no configuration. These browser admission checks do not make
the public record a secret from non-browser clients. Request values do not
alter the response record.

The Application fetches and validates this record without credentials. It derives `redirectUri` as
The Application fetches and validates this record without credentials, then
fetches `{ccdpOrigin}/ccdp/versions.json`, the Distribution's
[version list](ccdp-distribution.md#version-list), cross-origin without
credentials or redirects, and validates it by that contract. If either read
fails, no ceremony is available. The Application enables a platform only when
the record configures it and the list names a version the Application
implements; it enables exactly those versions, all under the platform's one
registration; an omitted version selects the highest. It derives `redirectUri` as
`new URL('/auth/callback', oauthBridge).href` from its validated canonical
OAuth Bridge origin, not from the response. It freezes the selected client ID,
public token-exchange credential when present, derived redirect URI, CCDP origin,
Expand All @@ -243,8 +249,9 @@ an HTTP redirect. Its [artifact contract](ccdp-distribution.md#callback-artifact
owns the HTML, configuration slot, response policy, browser startup, version
selection, and failure UI. The bridge only:

- retrieves `{ccdpOrigin}/ccdp/callback.html` at startup and revalidates it
independently of callback requests, rejecting upstream redirects;
- retrieves `{ccdpOrigin}/ccdp/callback.html`, its only Distribution request,
at startup and revalidates it independently of callback requests, rejecting
upstream redirects;
- sends no callback query, OAuth return, incoming request headers, cookies, or
credentials upstream; the configured source never depends on a request;
- validates and inserts its unversioned input list using the artifact contract,
Expand Down Expand Up @@ -335,11 +342,15 @@ cryptographic soundness.
or notary work, including on POST.
- TEST-BRIDGE-03 (exercises REQ-BRIDGE-03):
Exact public config includes GitHub's public token-exchange credential and has
no redirect field, user token, or notary selection. Missing required, empty,
null, wrongly typed, or whitespace/control-bearing credentials reject;
malformed known profiles reject and unknown platforms are ignored. Application
freezes the credential and forwards the same value to Prover despite later
configuration changes.
no version list, redirect field, user token, or notary selection. Missing
required, unexpected, empty, null, wrongly typed, or whitespace/control-bearing
credentials reject; malformed known profiles reject and unknown platforms are
ignored. The Application enables a platform only when the record configures it
and the version list names a version it implements, uses the platform's one
registration for every enabled version, selects the highest enabled version
when none is given, and enables nothing when the list fails to fetch or
validate. Application freezes the credential and forwards the same value to
Prover despite later configuration changes.
- TEST-BRIDGE-04 (exercises REQ-BRIDGE-04):
Callback queries/cookies/headers never reach the artifact request; failed refresh preserves the last valid HTML/policy pair, or serves inert unavailability.
- TEST-BRIDGE-05: Withdrawn.
Expand Down
Loading