diff --git a/FIREFOX_INTEGRATION.md b/FIREFOX_INTEGRATION.md new file mode 100644 index 0000000..d2da973 --- /dev/null +++ b/FIREFOX_INTEGRATION.md @@ -0,0 +1,268 @@ +# Firefox integration spike + +Status: active design and source reconnaissance +Date: 2026-08-17 + +## First running prototype + +The adjacent Firefox checkout now has branch `codex/browsec-spike` with commit +`5ec348b0f1` (*Add Velvet Hammer certificate investigation prototype*). + +The prototype adds a visibly distinct, browser-owned Velvet Hammer frame to +`about:certerror`. Its investigation action reads Firefox's protected +`FailedCertSecurityInfo`, displays the requested host, original NSS error, +failure category, conventional override eligibility, HSTS state, and the number +of handshake certificates, then computes and displays SHA-256 fingerprints from +the original DER certificate strings. + +It deliberately remains read-only and displays `NOT TRUSTED`; no prototype UI +action silently changes Firefox trust. The dedicated browser test +`browser_aboutCertError_velvetHammer.js` passes all seven assertions, including +the complete DER-derived fingerprint and unchanged terminal trust state. + +This first visible surface uses data already exposed to Firefox's trusted +certificate-error document. It does not yet provide the richer immutable +`TlsFacts`, append-only journal, plugin chain, policy broker, or fresh retry +required by the architecture below. + +## Pinned reconnaissance baseline + +The first source inspection uses an adjacent, shallow Firefox checkout: + +```text +Checkout: /home/sergeych/dev/browsec-firefox +Upstream: https://github.com/mozilla-firefox/firefox.git +Branch: main +Depth: 1 +Commit: b462c13f11417e13461f1202d71b14e2784f5db0 +Commit date: 2026-08-17T09:27:35Z +Version: 156.0a1 +``` + +This is a reconnaissance baseline, not the release baseline. Browsec will +select an ESR only after the integration seam has been proven. The exact +commit, rather than the moving branch name, defines all source references in +this document. + +The Firefox checkout is deliberately not nested in this repository. Git +history can be added only when needed: + +```sh +git fetch --deepen=50 origin main +# Or, only if full history becomes necessary: +git fetch --unshallow origin +``` + +## Architectural boundary + +An ordinary WebExtension cannot enforce Browsec trust semantics. Firefox core +must remain the reference monitor. It alone may: + +- receive authoritative results and certificate bytes from PSM/NSS; +- pause or terminate a TLS connection; +- validate a plugin verdict against identity, capabilities, scope, lifetime, + policy version, connection identity, and overridable error classes; +- make a stored policy visible to later certificate verification; +- require a genuinely fresh connection after a new decision; and +- host browser chrome that content and ordinary extensions cannot imitate. + +Velvet Hammer and other security extensions remain JavaScript/TypeScript. They +receive immutable facts, append attributed journal entries, and return the +strict API's Boolean verdicts. They never receive an NSS handle, arbitrary +XPCOM access, or direct access to another extension's data. + +## Confirmed certificate-verification path + +At the pinned Firefox revision, the ordinary TLS path is: + +1. `AuthCertificateHookInternal` in + `security/manager/ssl/SSLServerCertVerification.cpp` captures the peer DER + chain and dispatches an `SSLServerCertVerificationJob`. +2. `SSLServerCertVerificationJob::Run()` executes on a certificate-verification + thread in the parent process. +3. `AuthCertificate()` calls `CertVerifier::VerifySSLServerCert()` and obtains + the constructed DER chain, validation result, EV state, CT information, + issuer-source information, and related facts. +4. `AuthCertificateParseResults()` categorizes a failed result and consults + Firefox's existing `nsICertOverrideService` for eligible exact-certificate + overrides. +5. Both successful and failed results are moved through + `BaseSSLServerCertVerificationResult::Dispatch()`. +6. `SSLServerCertVerificationResult::Run()` executes on the socket transport + thread, populates `CommonSocketControl`, and finally calls + `SetCertVerificationResult(mFinalError)`. + +The result object already carries both the constructed chain and peer-presented +chain as original DER byte arrays. This makes it the narrowest promising seam +for producing `TlsFacts` without reparsing lossy display objects. + +HTTP/3 has an additional path in `netwerk/protocol/http/Http3Session.cpp`, which +uses `AuthCertificateHookWithInfo()`. It reaches the same verification +machinery, but must receive explicit integration tests; shared implementation +does not by itself prove equivalent pause, retry, and connection-reuse +semantics. + +## Proposed native seam + +Add a browser-internal `BrowsecTrustHost` continuation between receipt of the +PSM result and the final call to `SetCertVerificationResult`: + +```text +NSS/PSM verification + | + v +SSLServerCertVerificationResult::Run + | + v +freeze Browsec TLS observation + | + +---- conventional success ---> bounded pre-accept chain + | + `---- conventional failure ---> normal failure + investigation record + | + v + protected Velvet Hammer UI +``` + +This should be an asynchronous native state machine, not a thread-blocking call +from C++ into JavaScript. On conventional success, the socket remains in its +existing certificate-authentication wait state while the request is dispatched +to the privileged extension host. Each JavaScript `onBeforeTlsAccept` callback +must return synchronously once invoked, but delivery and continuation across +Firefox threads are naturally asynchronous. A short browser-enforced deadline +fails closed. + +Heavy work, network access, and interactive UI are forbidden in that hook. +Extensions perform such work in the background and consult prepared local state +when the hook arrives. + +On conventional failure, the first slice need not retain the failed socket. +Core freezes an investigation record, completes the failure normally, and +correlates the resulting navigation with a protected investigation page. If the +user creates a valid exception, Browsec stores the policy and starts a fresh +navigation on a fresh connection. + +## Why the existing override service is only a bootstrap adapter + +`nsICertOverrideService` already stores host, port, origin attributes, exact +certificate, and session-or-persistent lifetime. PSM consults it only for +errors Firefox categorizes as overridable and rejects overrides where policy +such as HSTS forbids them. This is useful for the first exact-leaf prototype. + +It cannot represent Browsec's complete policy model: + +- exact DER authority trust restricted to a namespace; +- explicit distrust of otherwise accepted authorities; +- arbitrary timed lifetime; +- plugin identity and decision provenance; +- journal references and the exact set of errors authorized by a verdict; +- independent extension evidence storage; or +- user-inspectable policy history. + +Therefore the adapter must be named and documented as provisional. Browsec's +durable policy overlay remains the source of truth even while an exact-leaf +rule is mirrored into the Firefox service for the first demonstration. + +## Privileged extension host + +The initial host should be a built-in Firefox WebExtension API namespace, not a +legacy external Experiment loaded from an arbitrary path. Current Firefox +implements parent-process extension APIs under +`toolkit/components/extensions/parent/`, with schemas and explicit manifest +permissions controlling exposure. + +The Browsec API is available only to packages that pass all of these checks: + +1. Browsec security-extension package type; +2. verified package identity; +3. requested capability in the package manifest; +4. local capability grant; +5. permitted execution mode for the current profile/context; and +6. API-version compatibility. + +The built-in Velvet Hammer package is compiled into the product, always enabled, +and always ordered last. Its irremovability is enforced by the host, not by an +ordinary extension preference. + +## First vertical slice + +The spike is complete when an automated browser test demonstrates: + +1. Navigate a clean Browsec profile to a local HTTPS server with an unknown + self-signed certificate. +2. Capture original DER, host, port, origin attributes, Firefox error, and both + available chain representations. +3. Display them in a browser-owned Velvet Hammer investigation page. +4. Obtain an explicit exact-certificate, exact-host, exact-port, session-scoped + user decision. +5. Validate and append the verdict to the audit journal. +6. Persist the Browsec policy rule and provisionally mirror it through + `nsICertOverrideService`. +7. Abandon the failed connection and start a fresh navigation. +8. Load the site and display a persistent Browsec-controlled indication that + conventional validation failed and named local policy permitted it. +9. Revoke the rule and prove that another fresh navigation fails again. + +No page content, cookie, credential, authorization header, private key, or TLS +session secret is included in the investigation record. + +## Patch sequence + +### Patch 1: built-in UI and exact-leaf prototype + +- add the built-in Velvet Hammer package and protected `about:` surface; +- expose immutable failed-connection facts through a minimal internal API; +- implement the browser-owned **Record security concern** chrome action; +- execute the existing TrustLab failure chain; +- use the provisional exact-leaf override adapter; and +- add browser and xpcshell tests. + +This patch can begin in artifact-build mode if it changes only packaged +JavaScript, HTML, CSS, and existing scriptable interfaces. + +### Patch 2: native pre-accept continuation + +- add the `BrowsecTrustHost` continuation before + `SetCertVerificationResult(0)`; +- bind every observation and verdict to a unique connection attempt; +- enforce deadline, cancellation, and fail-closed behavior; +- ensure that plugin failure never becomes implicit trust; and +- test ordinary TLS and HTTP/3 paths. + +This requires a full compiled Firefox build. + +### Patch 3: native Browsec policy overlay + +- stop depending on Firefox's override store as the source of truth; +- enforce certificate and authority rules with precise error substitution; +- implement explicit distrust on conventional-success paths; +- add timed and persistent policy lifetimes; and +- make policy snapshots auditable and atomically replaceable. + +### Patch 4: network-path audit + +Cover top-level navigation, redirects, subresources, WebSocket, workers, +service workers, speculative connections, proxy `CONNECT`, TLS resumption, +HTTP/2 and HTTP/3 coalescing, private browsing, containers, and client +certificate interactions. A path is not considered covered merely because it +eventually calls a shared verifier; its connection reuse and enforcement +behavior must be tested. + +## Immediate implementation questions + +The spike should resolve these from code and tests rather than policy intuition: + +- which identifier safely binds the UI investigation to one network attempt; +- where a fresh-retry flag can prohibit reuse and coalescing; +- how much constructed-chain material remains available for every failure; +- which process owns the immutable investigation registry; +- whether the first built-in API can remain JS-only or requires new WebIDL; +- how the protected page proves to the user that it is browser chrome; and +- which Firefox error classes can safely use the provisional override adapter. + +## Maintenance rule + +Every Firefox rebase must rerun the integration tests and re-audit the call path +from `VerifySSLServerCert` through `SetCertVerificationResult`, including the +HTTP/3 entry point. Silent upstream movement of this boundary is a release +blocker, not an implementation detail. diff --git a/ROADMAP.md b/ROADMAP.md index 315d839..a82d8ac 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -74,6 +74,10 @@ The primary product is a Firefox downstream that hosts full-fledged security extensions. TrustLab and Velvet Hammer are the proven reference implementation, not the final delivery environment. +The first reconnaissance baseline and proposed patch sequence are recorded in +[`FIREFOX_INTEGRATION.md`](FIREFOX_INTEGRATION.md). It pins the inspected +Firefox commit and must be updated whenever that baseline changes. + The next milestone should establish the smallest real Firefox integration: 1. Map NSS/PSM validation and certificate data into immutable `TlsFacts`. diff --git a/SESSION_NOTES.md b/SESSION_NOTES.md index ea0e715..df2c4b4 100644 --- a/SESSION_NOTES.md +++ b/SESSION_NOTES.md @@ -348,3 +348,29 @@ Do not implement distributed trust next. Continue from the Firefox host seam: 4. Define the browser-produced manual security-concern capture record. 5. Connect Velvet Hammer and demonstrate failed navigation, informed decision, durable scoped policy, and a fresh enforced retry. + +### Firefox integration reconnaissance (2026-08-17) + +- A depth-1 Firefox checkout now exists beside this repository at + `/home/sergeych/dev/browsec-firefox`. +- It is pinned for reconnaissance to Firefox `156.0a1`, commit + `b462c13f11417e13461f1202d71b14e2784f5db0` from + `https://github.com/mozilla-firefox/firefox.git`. +- [`FIREFOX_INTEGRATION.md`](FIREFOX_INTEGRATION.md) records the confirmed PSM + path, proposed native continuation seam, limitations of + `nsICertOverrideService`, patch sequence, and first end-to-end acceptance + test. +- The promising seam is `SSLServerCertVerificationResult::Run()` immediately + before `CommonSocketControl::SetCertVerificationResult()`: both constructed + and peer-presented DER chains are still present there. +- The JavaScript success hook remains synchronously returning, but its native + cross-thread bridge must be continuation-based and bounded rather than + blocking a verifier or socket thread while calling JavaScript. +- Firefox artifact mode was bootstrapped without system changes and the pinned + baseline built successfully. The absent optional `watchman` and repository- + wide `cargo-audit` setup do not affect the frontend artifact build. +- Branch `codex/browsec-spike`, commit `5ec348b0f1`, contains the first running + browser-owned Velvet Hammer certificate investigation surface and its browser + test. The test passes 7/7 assertions. The surface exposes protected Firefox + failure facts and DER-derived SHA-256 fingerprints but intentionally cannot + alter trust yet.