Skip to content

Commit 5db39c4

Browse files
committed
feat: US-004 - Implement crypto.subtle WebCrypto bridge (basic operations)
1 parent d7f1e83 commit 5db39c4

10 files changed

Lines changed: 575 additions & 94 deletions

File tree

.agent/contracts/node-bridge.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,19 @@ Bridge-provided randomness for global `crypto` APIs MUST delegate to host `node:
9494
- **WHEN** host `node:crypto` randomness primitives are unavailable or fail
9595
- **THEN** the bridge MUST throw a deterministic error matching the unsupported API format (`"<module>.<api> is not supported in sandbox"`) for the invoked randomness API and MUST NOT fall back to non-cryptographic randomness
9696

97+
### Requirement: Global WebCrypto Surface Matches The `crypto.webcrypto` Bridge
98+
The bridge SHALL expose a single WebCrypto surface so global `crypto` APIs and `require('crypto').webcrypto` share the same object graph and constructor semantics.
99+
100+
#### Scenario: Sandboxed code compares global and module WebCrypto objects
101+
- **WHEN** sandboxed code reads both `globalThis.crypto` and `require('crypto').webcrypto`
102+
- **THEN** those references MUST point at the same WebCrypto object
103+
- **AND** `crypto.subtle` MUST expose the same `SubtleCrypto` instance through both paths
104+
105+
#### Scenario: WebCrypto constructors stay non-user-constructible
106+
- **WHEN** sandboxed code calls `new Crypto()`, `new SubtleCrypto()`, or `new CryptoKey()`
107+
- **THEN** the bridge MUST throw a Node-compatible illegal-constructor `TypeError`
108+
- **AND** prototype method receiver validation MUST reject detached calls with `ERR_INVALID_THIS`
109+
97110
### Requirement: Diffie-Hellman And ECDH Bridge Uses Host Node Crypto Objects
98111
Bridge-provided `crypto` Diffie-Hellman and ECDH APIs SHALL delegate to host `node:crypto` objects so constructor validation, session state, encodings, and shared-secret derivation match Node.js semantics.
99112

docs/nodejs-conformance-report.mdx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,18 @@ description: Node.js v22 test/parallel/ conformance results for the secure-exec
1212
| Node.js version | 22.14.0 |
1313
| Source | v22.14.0 (test/parallel/) |
1414
| Total tests | 3532 |
15-
| Passing (genuine) | 738 (20.9%) |
15+
| Passing (genuine) | 741 (21.0%) |
1616
| Passing (vacuous self-skip) | 34 |
17-
| Passing (total) | 772 (21.9%) |
18-
| Expected fail | 2689 |
17+
| Passing (total) | 775 (21.9%) |
18+
| Expected fail | 2686 |
1919
| Skip | 71 |
2020
| Last updated | 2026-03-25 |
2121

2222
## Failure Categories
2323

2424
| Category | Tests |
2525
| --- | --- |
26-
| implementation-gap | 1388 |
26+
| implementation-gap | 1385 |
2727
| unsupported-module | 737 |
2828
| requires-v8-flags | 239 |
2929
| requires-exec-path | 200 |
@@ -116,7 +116,7 @@ description: Node.js v22 test/parallel/ conformance results for the secure-exec
116116
| freeze | 1 | 0 | 1 | 0 | 0.0% |
117117
| fs | 232 | 69 (8 vacuous) | 129 | 34 | 34.8% |
118118
| gc | 3 | 0 | 3 | 0 | 0.0% |
119-
| global | 11 | 2 | 9 | 0 | 18.2% |
119+
| global | 11 | 3 | 8 | 0 | 27.3% |
120120
| h2 | 1 | 0 | 1 | 0 | 0.0% |
121121
| h2leak | 1 | 0 | 1 | 0 | 0.0% |
122122
| handle | 2 | 1 | 1 | 0 | 50.0% |
@@ -234,7 +234,7 @@ description: Node.js v22 test/parallel/ conformance results for the secure-exec
234234
| vm | 79 | 11 | 67 | 1 | 14.1% |
235235
| warn | 2 | 0 | 2 | 0 | 0.0% |
236236
| weakref | 1 | 1 | 0 | 0 | 100.0% |
237-
| webcrypto | 28 | 15 | 13 | 0 | 53.6% |
237+
| webcrypto | 28 | 17 | 11 | 0 | 60.7% |
238238
| websocket | 2 | 1 | 1 | 0 | 50.0% |
239239
| webstorage | 1 | 0 | 1 | 0 | 0.0% |
240240
| webstream | 4 | 0 | 4 | 0 | 0.0% |
@@ -245,11 +245,11 @@ description: Node.js v22 test/parallel/ conformance results for the secure-exec
245245
| wrap | 4 | 0 | 4 | 0 | 0.0% |
246246
| x509 | 1 | 0 | 1 | 0 | 0.0% |
247247
| zlib | 53 | 17 | 33 | 3 | 34.0% |
248-
| **Total** | **3532** | **772** | **2689** | **71** | **22.3%** |
248+
| **Total** | **3532** | **775** | **2686** | **71** | **22.4%** |
249249

250250
## Expectations Detail
251251

252-
### implementation-gap (707 entries)
252+
### implementation-gap (704 entries)
253253

254254
**Glob patterns:**
255255

@@ -260,7 +260,7 @@ description: Node.js v22 test/parallel/ conformance results for the secure-exec
260260
- `test-https-*.js` — https depends on tls — most tests fail on missing TLS fixture files or crypto API gaps
261261
- `test-http2-*.js` — http2 module bridged via kernel — most tests fail on API gaps, missing fixtures, or protocol handling
262262

263-
*701 individual tests — see expectations.json for full list.*
263+
*698 individual tests — see expectations.json for full list.*
264264

265265
### unsupported-module (190 entries)
266266

packages/core/isolate-runtime/src/inject/require-setup.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1859,8 +1859,17 @@
18591859
});
18601860
};
18611861

1862-
result.subtle = SandboxSubtle;
1863-
result.webcrypto = { subtle: SandboxSubtle, getRandomValues: result.randomFillSync };
1862+
if (
1863+
globalThis.crypto &&
1864+
globalThis.crypto.subtle &&
1865+
typeof globalThis.crypto.subtle.importKey === 'function'
1866+
) {
1867+
result.subtle = globalThis.crypto.subtle;
1868+
result.webcrypto = globalThis.crypto;
1869+
} else {
1870+
result.subtle = SandboxSubtle;
1871+
result.webcrypto = { subtle: SandboxSubtle, getRandomValues: result.randomFillSync };
1872+
}
18641873
}
18651874

18661875
// Enumeration functions: getCurves, getCiphers, getHashes.

packages/core/src/generated/isolate-runtime.ts

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)