117 lines
5.3 KiB
Markdown
117 lines
5.3 KiB
Markdown
# TrustLab
|
|
|
|
TrustLab is the browser-neutral executable model of Browsec's trust-plugin
|
|
protocol. It currently runs under Node.js without external dependencies, but
|
|
plugins receive only portable JavaScript values and TrustLab capabilities.
|
|
|
|
The initial runner separates two phases:
|
|
|
|
1. Evidence plugins independently inspect the same immutable TLS facts. Their
|
|
attributed results are appended deterministically to the journal.
|
|
2. Decision plugins inspect the sealed evidence view in configured order. The
|
|
first authorized Boolean verdict is terminal. Browsec's immutable built-in
|
|
handler finalizes that result or supplies the safe fallback.
|
|
|
|
Run:
|
|
|
|
```sh
|
|
npm test
|
|
npm run check
|
|
npm run build
|
|
npm run demo
|
|
npm run ui
|
|
```
|
|
|
|
`npm run ui` serves the browser-hosted testbed at `http://127.0.0.1:4173`.
|
|
The page uses synthetic TLS records and the same portable TrustLab runner used
|
|
by the tests. It does not make real TLS decisions.
|
|
|
|
## Current protocol boundary
|
|
|
|
Plugins may return evidence, warnings, and a scoped Boolean trust verdict. They
|
|
cannot access Node.js facilities through the protocol, mutate TLS facts or
|
|
journal entries, or perform browser actions.
|
|
|
|
This first slice intentionally omits persistence, package signatures, community
|
|
identities, networking, and real X.509 parsing. The included interactive UI is a
|
|
security-surface prototype, not browser integration.
|
|
|
|
## TLS-only plugin API
|
|
|
|
The strict TypeScript contract is defined in [`sdk/plugin-api.ts`](sdk/plugin-api.ts).
|
|
A plugin exports one object created with `defineTrustPlugin`; local configuration
|
|
separately grants its active mode and scope.
|
|
|
|
The initial API intentionally exposes only:
|
|
|
|
- `collectEvidence` for attributed evidence, warnings, and advisory votes;
|
|
- `onBeforeTlsAccept` for a fast synchronous decision after normal validation;
|
|
- `onTlsFailure` for asynchronous investigation of a failed validation.
|
|
|
|
Every terminal result is Boolean and must include a discriminated certificate or
|
|
authority scope, an explicit lifetime, and the journal entries supporting it.
|
|
See [`examples/strict-plugin.ts`](examples/strict-plugin.ts) for a compiler-checked
|
|
registration example.
|
|
|
|
## Probe a real server
|
|
|
|
The read-only probe turns a live TLS connection into the same immutable facts
|
|
used by the simulator:
|
|
|
|
```sh
|
|
npm run probe -- example.com
|
|
npm run probe -- broken.example:8443 --json
|
|
```
|
|
|
|
It records DER and SPKI SHA-256 fingerprints and independently checks hostname,
|
|
validity periods, and adjacent certificate signatures. It never installs trust
|
|
or changes the operating system. The report labels its current chain-source
|
|
limitation rather than claiming that OpenSSL's peer chain is exactly what the
|
|
server transmitted.
|
|
|
|
Run `npm run ui`, open the displayed loopback URL, and use **Live TLS target**
|
|
to inspect a host in the diagnostic interface. The local endpoint accepts only
|
|
small JSON `POST` requests from its own browser origin and applies a ten-second
|
|
probe timeout.
|
|
|
|
Each live certificate includes an expandable, byte-offset-aware DER explorer.
|
|
It preserves the original certificate for offline export, lists every extension
|
|
(including undecoded bytes), flags unknown critical extensions, and derives CA
|
|
status and Key Usage directly from the signed certificate encoding. Parsing is
|
|
dependency-free and guarded by input-size, node-count, and nesting limits.
|
|
|
|
The deeper explorer synchronizes the ASN.1 structure with a hexadecimal view:
|
|
selecting a field highlights its complete encoded byte range, while selecting a
|
|
byte resolves to the narrowest enclosing ASN.1 node.
|
|
|
|
Live investigations can be exported as versioned
|
|
`.browsec-investigation.json` bundles and reopened offline. A bundle contains
|
|
the original public DER certificates, normalized facts, findings, journal,
|
|
verdict, and policy snapshot, together with an explicit no-private-keys and
|
|
no-session-secrets declaration. Import is limited to 10 MiB; it reparses every
|
|
certificate, recomputes every DER SHA-256 fingerprint, and rejects inconsistent
|
|
CA, Key Usage, critical-extension, or fingerprint claims. Recorded decisions
|
|
remain evidence in the bundle and are not silently installed into local policy.
|
|
|
|
## Explainable path construction
|
|
|
|
Live probes build a candidate issuer graph independently of the order in which
|
|
OpenSSL returned certificates. Every possible certificate pair records issuer
|
|
and subject matching, signature verification, and AKI/SKI continuity. An edge
|
|
is accepted only when the issuer is a DER-confirmed CA, Key Usage permits
|
|
certificate signing, and no unsupported critical extension blocks its use.
|
|
|
|
TrustLab enumerates every acyclic candidate path and labels it `trusted`,
|
|
`untrusted`, `incomplete`, or `invalid`. Terminal explanations retain both the
|
|
structural outcome and validation failures, including validity periods and CA
|
|
path-length constraints. Trust anchors name their provider; a path is never
|
|
presented as simply “trusted” without attribution.
|
|
|
|
Authority scopes identify the exact DER-encoded CA certificate with
|
|
`authorityCertificateSha256`. TrustLab verifies that it appears in the active
|
|
chain, has CA Basic Constraints in the supplied facts, and permits
|
|
`keyCertSign`. The in-memory policy overlay applies that authority only to the
|
|
declared host namespace and participates in retries as an ordinary trust plugin.
|
|
An authority rule may override trust-anchor failures only; it cannot excuse an
|
|
expired certificate, a hostname mismatch, or another independent TLS failure.
|