wellknown.id's pages run in the holder's browser, inside wellknown.id's origin, and they come from wellknown.id's server. Whoever controls what that server serves controls those pages. So the code itself is made checkable: every release is built reproducibly, listed file by file in a signed manifest, published in a log that only grows, and served under Subresource Integrity. This site's own pages are in it too.
The release log
Each release's manifest lists every file wellknown.id serves that touches keys, by origin and path, with its SHA-256: the IdP's pages and the web SDK, the website, kivi on the web and these docs. It also names the commit and its date, the image the build ran in, the hashes of the sources a sign-in's proof depends on, everything the server runs (each image by content digest, and the deploy files), and the previous release's manifest hash, so the manifests form a chain.
It's signed with an offline release key (Ed25519) as a detached JWS over the file's exact bytes (typ: wellknown-release+jws). All of it is published at https://wellknown.id/.well-known/releases/:
| File | |
|---|---|
log.json | every release's number, manifest hash, commit and date, in order |
<n>.json, <n>.jws | release n's manifest, and its signature |
latest.json, latest.jws | the newest |
release-key.jwk | the release key's public half; and release-key-next.jwk, its successor, once one is pinned |
Checking it yourself
From a clone of the repository:
node scripts/release/release.ts verify-live
It fetches the log and the newest manifest, checks the signature against the pinned release key, that the manifest is the log's newest and links to the one before, that the log extends the repository's copy, and then that every file and page on every origin hashes as listed, and carries Integrity-Policy.
To rebuild a release and compare:
scripts/release/reproduce.sh # two clean builds of this commit: byte for byte the same node scripts/release/release.ts compare --web <dir> <n> # a build against release n's manifest, file for file
In the browser
- Subresource Integrity on every script and stylesheet: each names its
sha384, and is fetched with CORS. Integrity-Policy: blocked-destinations=(script)on wellknown.id, kivi.wellknown.id and this site: a browser that supports it refuses any script without integrity.- Signature-based SRI on the IdP's page scripts: they name the release key beside their hash, and the IdP serves each script's signature, so Chrome refuses a script the release key didn't sign (Firefox checks the hash).
- A strict CSP: scripts from the page's own origin only, nothing inline.
kivi checks too
kivi, from a signed app that doesn't come from the server it checks, fetches the log and every page itself, with the release key pinned in the app. Where they differ it warns the holder on every screen and refuses to bond or to sign in for another device until they match. It sees what the server serves kivi, not what it serves one browser; a public mirror of the log, to compare with, is planned.
On the server
Before anything of a release starts, the server checks it against the signed manifest, with release keys it pins itself: each image that will run by its content digest, the deploy files, and every file of kivi on the web and of these docs. A release that isn't the one signed, or an older one shipped again, is refused and nothing changes.