ReviewOS

home-lang/home

Native RSA DER/JWK import, export, and key generation

#587
Open chris opened this 9 days ago ·
9 days ago

Scope

Complete the remaining Node/Bun RSA key pipeline on the real BoringSSL backend.

  • Generate RSA and RSA-PSS keys with EVP instead of corpus placeholder material.
  • Import and export PKCS#1, PKCS#8, and SPKI in PEM and DER forms.
  • Import and export public/private RSA JWK material.
  • Preserve encrypted-key passphrase behavior and BoringSSL error contracts across every representation.
  • Remove the synthetic RSA operation-record bridge once all key representations interoperate natively.
  • Convert the relevant Node crypto TODO coverage into ordinary passing tests.

Acceptance

  • Cross-format encrypt/decrypt and sign/verify matrices use cryptographic output, including PEM ↔ DER ↔ JWK combinations.
  • Wrong keys, wrong passphrases, OAEP hash/label mismatches, and invalid encodings fail through the backend with Bun-compatible errors.
  • No fixture-specific output tables or plaintext/signature acceptance shortcuts.
  • The full js/node/crypto Home corpus remains green.
9 days ago

Progress landed on main in 8798af312:

  • Home now owns and compiles both Node crypto unity objects, so mirrored crypto changes are present in the executable.
  • generateKeyPairSync() and generateKeyPair() now create native RSA-PSS key objects on BoringSSL while retaining PSS digest, MGF1 digest and minimum salt-length restrictions.
  • One-shot and streaming sign/verify enforce PSS padding and the stored restrictions; ordinary RSA, EC and existing JWK behavior remain intact.
  • PKCS#1 and JWK export reject logical RSA-PSS keys with the expected compatibility errors.
  • The native binding compiler now uses Bun's pinned LLVM 21.1.8 when available, preventing C++ ABI corruption when Home-owned objects call Bun-owned code.
  • The remaining pinned Bun crypto corrections for XOF hashing, cipher authentication state, ECDH output length, invalid HMAC receivers and invalid P1363 signatures were ported in the same ownership batch.

Validation on the exact pushed checkout:

  • ReleaseFast JSC build: 48/48 steps, bounded peak tree footprint 14,345 MB.
  • Home-owned native RSA-PSS regression: pass, including sync/async generation, one-shot and streaming signing/verifying, wrong-message rejection, and restriction errors.
  • Exact upstream crypto.key-objects.test.ts: 83 pass / 22 upstream skips / 1 upstream TODO / 0 fail / 905 assertions.
  • Full upstream js/node/crypto: 851 pass / 22 upstream skips / 1 upstream TODO / 0 fail / 2,416 assertions across 17 files.

This issue remains open: typed RSA-PSS DER parameter import/export and the remaining cross-format/bridge-removal acceptance work are still outstanding.

9 days ago

Typed RSA-PSS key encoding is now on main in afa901f15.

This batch adds real RFC 4055 key interoperability on the pinned BoringSSL backend:

  • PKCS#8 private-key and SPKI public-key import/export in PEM and DER, including unrestricted keys and independent digest, MGF1-digest, and minimum-salt restrictions.
  • Encrypted PKCS#8 PEM/DER through BoringSSL PBES2, preserving correct missing-passphrase and bad-decrypt failures.
  • Public-key derivation from plaintext or encrypted PKCS#8, typed rsa-pss identity, restriction details, and signing/verification after every round trip.
  • Import coverage against Bun's existing rsa_pss_*_sha512_sha256_20.pem fixtures, plus generated unrestricted, SHA-256-restricted, and explicit SHA-1-default keys.

Validation for the RSA-PSS patch:

  • Required ReleaseFast JSC build: 48/48 steps.
  • Dedicated native RSA-PSS regression: pass.
  • crypto.key-objects.test.ts: 83 pass / 22 skip / 1 existing TODO / 0 fail / 905 assertions.
  • Full js/node/crypto: 851 pass / 22 skip / 1 existing TODO / 0 fail / 2,416 assertions across 17 files.
  • Pickier and git diff --check: pass.

The issue stays open: RSA JWK/remaining PKCS#1 cross-format work, removal of the synthetic RSA operation-record bridge, and conversion of the upstream RSA-PSS TODO still remain before the full acceptance matrix is complete.

9 days ago

Landed and pushed d03df5f407751bac2483bd11c9786ec4a7c030f9 (fix(runtime): own RSA-PSS metadata on keys).

This removes the provisional encoding of RSA-PSS restrictions inside KeyObjectData::symmetricKey. Digest, MGF1 digest, and minimum salt length now live on the real BoringSSL RSA backend through its supported ex-data API, with backend-owned cleanup. Generated, imported, copied, and private-derived public KeyObjects therefore share metadata with the key they actually operate on. KeyObjectData's ABI layout and destructor remain unchanged for prebuilt Bun translation units.

Validation on the exact pushed source:

  • required ReleaseFast JSC build: 48/48 steps;
  • both crypto unity translation units: direct pinned-LLVM compilation passed;
  • dedicated native RSA-PSS generation/import/export/restriction/sign/verify regression passed;
  • exact crypto.key-objects.test.ts: 83 pass / 22 existing skips / 1 existing TODO / 0 fail / 905 assertions;
  • all 17 js/node/crypto files: 851 pass / 22 existing skips / 1 existing TODO / 0 fail / 2,416 assertions;
  • focused Pickier and git diff --check passed.

No corpus assertion, fixture, deadline, skip, TODO, or expected result changed. This issue remains open while the remaining acceptance items are audited; the upstream RSA-PSS TODO still describes older BoringSSL limitations and cannot be activated unchanged without replacing stale expectations.

9 days ago

Landed and pushed 0e3f4a72f35f2bea3dc659aef99d8e1cb103bf0b (feat(runtime): preserve RSA-PSS structured clones).

RSA-PSS KeyObjects now retain their algorithm identity, digest/MGF1/salt restrictions, and cryptographic interoperability through structuredClone() and workerData. Serialization uses the same RFC 4055 SPKI/PKCS#8 implementation as normal export/import; the clone no longer degrades to unrestricted plain RSA or produces signatures the original public key rejects.

Home now owns the standalone SerializedScriptValue.cpp.o instead of editing dead mirrored source. Before adding the key hooks, its mirror was synced exactly to pinned Bun source 4982b91e3702094330f3be3883354c52b8c01323, retaining Bun's safe near-2 GiB vector growth, non-extractable CryptoKey storage guard, BlockList backing lifetime, BIO ownership, and other current serializer behavior.

Validation on the exact pushed source:

  • required ReleaseFast JSC build: 50/50 steps;
  • exact 1.6 GB nested ArrayBuffer control: OK;
  • four unchanged structured-clone files: 313 pass / 0 fail / 1,550 assertions, including all five near-2 GiB subprocess cases;
  • expanded native RSA-PSS regression: unrestricted, restricted, imported fixture, ordinary RSA, and secret key clones; worker transfer and cross-thread signing all passed;
  • exact crypto.key-objects.test.ts: 83 pass / 0 fail;
  • all 17 Node crypto files: 851 pass / 0 fail;
  • native-binding units: 4/4; focused Pickier, Zig format, and diff checks passed.

No upstream corpus assertion, fixture, workload, deadline, skip, TODO, snapshot, or expected result changed. #587 remains open for the remaining acceptance audit and the stale upstream RSA-PSS TODO boundary.

9 days ago

Source d1843551a now owns ten additional registry modules: crypto, zlib, zlib/iter, promisification and six legacy stream entry points. The explicit ownership list is 90 modules plus the internal test adapter. Home compiles the StringDecoder implementation and factory with an exact linked class-header ABI. Generation rejects duplicate/missing factory includes and source ownership before output.

The original corpus exposed real missing behavior: the generator's keepNames option was in the wrong object; SHAKE's capability export was a false-returning stub; streaming signature requests needed one-shot/key-agreement capability validation. These are fixed. Forced-drain callbacks enter an event-loop scope and nested Debug scopes restore parent state correctly. Pinned zlib getter values survive close/allocation paths. Valid cryptographic operations still execute through the backend.

The complete 193 unchanged original entries validate 1,357 registered passes + 147 process checks, zero failures. 24 registered skips, one TODO, three skipped files and 16 comment-only entries receive no passing credit. All ten native groups pass, including compression buffer lifetime and crypto/compression worker shutdown. ABI 74 tests / 1,220 assertions; Debug 34/34, peak 5,658 MB under 8,192 MB; complete tests 2,383 MB under 3,840 MB. Pickier and scoped formatting/whitespace checks pass.

All 3,785 committed archives verify; all 193 completed reports restore and validate. Initial four-file failures and the repair's remaining key-agreement failure are retained. A direct zlib diagnostic passed before the callback-scope fix; the initial panic is not claimed to reproduce in every context. Every selected test matches the pin. Four pre-existing URL/ICU fixture differences outside this selection are recorded. Unsupported/unapplied Node/V8 metadata flags receive no feature-parity credit. Source bytes remain unchanged across main integration.

This advances #66, #513, #516 and #587. Remaining registry/native dependencies, original pending outcomes, whole-suite and Release/ASAN/all-platform verification stay open.

This is native Node crypto corpus evidence. It does not establish removal of every separate language-level RSA bridge or finish the full acceptance scope of #587.

Sign in to comment on this issue.