Skip to content

Provide crypto.subtle through a vetted cross-platform provider #102

Description

@wieslawsoltes

Current implementation checkpoint — 19 September 2026

WebScene main is c9899a874d3cc448fb79b7f2ac4c334fe13e0d68. The existing pinned Mbed TLS 3.6.4 provider already supplies SHA-1/SHA-256 digest, AES-GCM/CBC/HMAC, bounded owner-queue settlement, cancellation, WPT-derived contracts and published vectors. Focused child #627 merged through PR #628 and now zeroizes malformed decoded JWK prefixes and transient Base64URL strings, rejects oversized AES/HMAC input before native allocation, and records provider/licensing/update policy.

No #102 branch remains active. The parent remains open only for configured unchanged-package MCP secret-input and browser connection-secret persistence/reopen acceptance across release RIDs; stock Code OSS has no VSDA and bundled Copilot HMAC executes in Node.

Problem

WebScene does not expose crypto.subtle. VS Code OSS 1.137 has reachable browser paths that depend on it:

  • SHA-256: webview/bootstrap URL derivation, GitHub and Microsoft authentication PKCE, extension-host authentication, chat/MCP identifiers, iframe worker bootstrap;
  • SHA-1: WebSocket handshake and legacy state verification;
  • AES-GCM: browser workbench connection-token protection and MCP input storage;
  • AES-CBC decrypt: browser signing-service WASM loading;
  • HMAC signing is also used by the bundled Copilot extension.

The V8 embedder does not include Blink Web Crypto, and WebScene has no pinned, audited cryptographic provider with a stable target across macOS, Windows, and Linux. The existing Mbed TLS fetch is Windows-only and private to IXWebSocket compatibility. Implementing algorithms directly, or composing different platform APIs behind loosely matched semantics, would create security and interoperability risk.

Proposed architecture

  1. Select and pin one vetted cross-platform provider after licensing, binary-size, update cadence, platform packaging, and FIPS requirements are documented. Do not hand-roll primitives.
  2. Implement an opaque native CryptoKey store with algorithm metadata, extractability, usages, realm ownership, and deterministic zeroization.
  3. Run operations asynchronously with bounded input/output sizes, cancellation during realm shutdown, and Promise settlement on the owning V8 task queue.
  4. Implement the smallest VS Code-driven algorithm slices in reviewable stages:
    • digest: SHA-256 and SHA-1;
    • AES-GCM: generate/import/export/encrypt/decrypt with raw and JWK formats;
    • AES-CBC decrypt;
    • HMAC import/sign only if bundled-extension support is in scope.
  5. Match Web Crypto normalization and exception behavior; do not expose crypto.subtle until its advertised methods and key semantics are complete for the accepted slice.
  6. Add official WPT-derived algorithm/error tests, published test vectors, cross-realm isolation tests, shutdown/cancellation tests, memory/zeroization review, and bounded throughput/latency gates on all release RIDs.

Acceptance criteria

  • The provider choice and upgrade policy are documented and approved.
  • No JavaScript or bespoke cryptographic primitive implementation is introduced.
  • Keys cannot be forged, crossed between incompatible realms, or exported when non-extractable.
  • Algorithm parameters, usages, JWK validation, error names, and Promise behavior match the Web Crypto specification for every exposed operation.
  • Required VS Code 1.137 paths have integration coverage in the unchanged production bundle.
  • All supported RID CI and security/performance gates pass before crypto.subtle becomes visible.

Until this is complete, feature detection must continue to observe crypto.subtle as absent rather than a partial or insecure object.

Activity

  1. wieslawsoltes commented on Sep 16, 2026

    @wieslawsoltes
    CollaboratorAuthor

    Native Stack #194 merged atomically at acae18e330f29697bfc82856b98642ebaeadbbf9:

    • Pin Mbed TLS for Web Crypto provider and key lifecycle #192 pins Mbed TLS 3.6.4 by archive SHA-256 for every RID, documents provider/update/FIPS policy, ships its license, and adds the cancellable digest provider plus opaque realm-owned, usage-checked, deterministically zeroized key storage.
    • Add bounded SHA-1 and SHA-256 SubtleCrypto digest #193 exposes bounded asynchronous SubtleCrypto.digest for SHA-1 and SHA-256 with illegal constructor/receiver checks, legitimate cross-realm use, owner-thread Promise settlement, input-copy semantics, navigation/iframe/worker/runtime cancellation, official vectors, and pinned WPT-derived coverage.

    The cumulative top passed the precompiled/V8 contracts and the original native document/compiler contracts. Focused local provider, window/iframe/worker digest, shutdown, secure-random compatibility, and WPT gates passed.

    Issue #102 remains open for:

    • AES-GCM generate/import/export/encrypt/decrypt with raw and JWK validation, extractability, usage, error, cancellation, vector, and throughput coverage;
    • AES-CBC decrypt with the same accepted key and error contracts;
    • HMAC import/sign if bundled Copilot support remains in scope;
    • unchanged packaged VS Code 1.137 workbench, webview, authentication, MCP, signing-service, and extension-host acceptance on the supported release RIDs;
    • cumulative security/performance gates for each additional exposed algorithm slice.
  2. wieslawsoltes commented on Sep 16, 2026

    @wieslawsoltes
    CollaboratorAuthor

    The next native Web Crypto stack merged atomically as #196 → #197 → #198 (Stack #199) at 1c18c70c06b10e994d28f428c5d1a7f095ff7ef8.

    Implemented in this stack:

    • AES-GCM 128/192/256 key generation, raw/JWK import/export, and authenticated encrypt/decrypt;
    • AES-CBC decrypt with raw/JWK imported keys and provider-side PKCS#7 validation;
    • HMAC raw/JWK import/export and SHA-1/SHA-256 signing;
    • opaque realm-owned keys, usage and extractability enforcement, deterministic zeroization, shutdown cancellation, 16 MiB input bounds, 64 MiB queued-work bound, 32-operation concurrency bound, and 256-key cap;
    • published NIST/RFC vectors and pinned WPT-derived contracts.

    Focused evidence on the cumulative top:

    • provider tests: PASS;
    • full hybrid V8 runtime: PASS;
    • registered Linux runtime CTests: AES-GCM PASS (0.23 s), AES-CBC PASS (0.02 s), HMAC PASS (0.06 s);
    • local cumulative Web Crypto contracts: 5/5 documents, 59/59 subtests PASS.

    The retained Linux runtime job failed only on unrelated broad checks: the known HostBridge.Services catalog failure and a cached-hover timing result of 30.824 ms against a 30 ms budget. All changed Web Crypto gates passed.

    Remaining acceptance: run the unchanged packaged VS Code 1.137 paths on the released RIDs for connection-token/MCP AES-GCM, signing-service AES-CBC WASM loading, and bundled Copilot HMAC signing. Keeping this issue open for that consolidated product gate.

  3. wieslawsoltes commented on Sep 17, 2026

    @wieslawsoltes
    CollaboratorAuthor

    Current exact-main/package audit (WebScene 24db1a2f2c6b1865977eb613598ab6932e61236d):

    The final package does not yet exercise the configured product consumers: MCP AES-GCM requires storing a secret MCP input, and browser secret-storage AES-GCM requires the vscode-secret-key-path cookie. Bundled Copilot has a Node main entry and no browser entry, so its HMAC runs in the Node extension host rather than WebScene. Stock Code OSS also omits vsda.js and vsda_bg.wasm; the package receives the 404 not found body for vsda.js and reports Unexpected identifier 'found', so its signing-service AES-CBC consumer cannot run in the unchanged OSS distribution.

    The runtime algorithm implementation is complete. This issue remains open while focused configured package probes and the OSS vsda exclusion are made explicit.

  4. wieslawsoltes commented on Sep 17, 2026

    @wieslawsoltes
    CollaboratorAuthor

    #224 is merged as e28cbe85a1a0f5973ae0ca323991a6cdde12dcf8 (authored commit d6e59d3506aaac9270db5cbde872a14de9d1e000).

    It closes a generic Web Crypto lifetime gap exposed by the Code OSS browser connection-key shape. WebScene keeps native key material outside the JS heap and caps each realm at 256 native CryptoKey records. Short-lived wrappers could remain uncollected long enough for real seal/reopen traffic to hit the cap even after the keys were unreachable. At capacity, key creation/import now removes released bindings, asks V8 for a low-memory collection, removes bindings released by weak callbacks, and fails only when 256 live records still remain. The weak callbacks retain the existing native destruction/zeroization path.

    Regression coverage now includes 96 persisted AES-GCM seal/reopen cycles, creating 288 short-lived keys. Each cycle generates and raw-exports a client half, derives and imports a nonextractable working key, encrypts, reconstructs nonzero-offset persisted subarrays, imports the reopened key, and decrypts the original bytes. This matches the key-lifetime and typed-array behavior used by Code OSS ServerKeyedAESCrypto. The existing HMAC capacity regression still retains 256 live keys and verifies that key 257 is rejected, proving the hard live-key bound is unchanged.

    Local focused evidence:

    • AES-GCM runtime runner: pass in 1.31 s.
    • HMAC runtime runner, including the retained-256 case: pass.
    • crypto provider tests: pass in 0.42 s.

    Directly related CI evidence from NuGet packages run https://github.com/SceneTech/WebScene/actions/runs/35191190512, macOS ARM64 job 105104012210:

    • webscene_crypto_provider_tests: pass, 0.31 s.
    • cumulative webscene_hybrid_v8_runtime_tests: pass, 2.21 s.
    • focused webscene_webcrypto_aes_gcm_tests: pass, 0.57 s.
    • focused AES-CBC: pass, 0.07 s.
    • focused HMAC: pass, 0.07 s.

    The same job's broad webscene_native_engine_tests failure is the previously documented unrelated HostBridge.Services catalog failure. Per the focused-runner policy, the unrelated matrix and post-merge runs were canceled after the direct crypto evidence passed.

    This issue should remain open. The current vscode-demo smoke injects consumer-shaped Web Crypto calls into the patched workbench; it does not prove an unchanged actual consumer. The remaining acceptance gap is concrete:

    • configure an MCP server whose unchanged UI stores an actual secret input, exercising McpRegistryInputStorage AES-GCM end to end;
    • run the unchanged browser connection/secret-storage path with a real vscode-secret-key-path cookie, exercising ServerKeyedAESCrypto persistence and reopen;
    • stock Code OSS does not ship proprietary vsda.js/vsda_bg.wasm, so its signing AES-CBC path cannot execute from the OSS package;
    • the bundled Copilot extension has only its Node main entry and no browser entry, so its HMAC code does not execute inside WebScene.

    Draft consolidation PR #76 was refreshed through e28cbe85 at branch commit 0dfe6728a8283464ec7fefc9ecf6f37b009452bd and remains draft/unmerged.

  5. wieslawsoltes commented on Sep 19, 2026

    @wieslawsoltes
    CollaboratorAuthor

    Implementation-first re-audit at WebScene 59d143e1 confirms the pinned Mbed TLS provider covers every audited unchanged Code OSS Web Crypto call with existing key ownership, zeroization, cancellation, caps, and reclamation. Remaining work is configured packaged MCP secret-input/browser-secret acceptance; stock OSS has no proprietary VSDA assets and Copilot HMAC executes in Node. No new code or validation was run.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    vscode-oss/plannedPlanned for the AppScene/WebScene VS Code OSS integration

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions