fix(keys): support passphrase-encrypted PEM/DER in createPrivateKey/createPublicKey#1050
Merged
Conversation
The JS layer of createPrivateKey/createPublicKey advertised a `passphrase` field on KeyInputObject and the native Nitro spec/C++ already supported it, but the TS plumbing dropped the value before reaching handle.init(). Encrypted PEM keys surfaced OpenSSL's "interrupted or cancelled" error and DER keys gave a generic "Failed to read DER private key", matching the report in #1048. - forward passphrase through prepareAsymmetricKey - accept passphrase in KeyObject.createKeyObject and always pass format/encoding/passphrase to handle.init (previously the undefined-format branch dropped them) - surface NEED_PASSPHRASE in the DER private-key path so users get "Passphrase required for encrypted key" instead of the generic error Fixes #1048
ncrypto::DataPointer is an owning RAII wrapper whose destructor calls OPENSSL_clear_free on the pointer it holds. The createPrivateKey / createPublicKey / exportKey paths were constructing it directly from the JS-owned ArrayBuffer's data pointer, so destruction zeroed and freed memory it did not own. In the "passphrase as Buffer (PEM)" test the same Buffer was reused across export and import — export cleared the bytes, so import saw zeros and OpenSSL surfaced bad decrypt. Use DataPointer::Copy at all 7 sites (KeyObjectData.cpp x6, HybridKeyObjectHandle.cpp x1). This mirrors Node.js's ByteSource::ToDataPointer helper (Alloc + memcpy), giving DataPointer ownership of memory it can safely OPENSSL_clear_free. Adds a DER variant of the createPublicKey passphrase-encrypted test and tightens expected error messages on the throws-on-bad-input cases.
…n parse attempts Two related issues exposed by the new createPrivateKey/createPublicKey passphrase tests under OpenSSL 3.6: 1. Encrypted PEM without passphrase reported "interrupted or cancelled" instead of "Passphrase required". ncrypto's keyOrError only maps ERR_LIB_PEM/PEM_R_BAD_PASSWORD_READ to NEED_PASSPHRASE, but PEM_read_bio_PrivateKey in OpenSSL 3.6 surfaces a missing-passphrase callback as ERR_R_INTERRUPTED_OR_CANCELLED on ERR_LIB_CRYPTO. Detect that reason code in the rnqc wrapper when no passphrase was supplied. 2. createPublicKey on an encrypted PKCS8 DER buffer failed with "Failed to read DER asymmetric key" even though the parse succeeded. The no-type DER branch tries SPKI first; d2i_PUBKEY fails and leaves an error on OpenSSL's queue, then the follow-up TryParsePrivateKey parses the key correctly but ncrypto's keyOrError peeks the stale error and downgrades the result to FAILED. Clear the OpenSSL error queue between attempts.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
🤖 End-to-End Test Results - AndroidStatus: ✅ Passed 📸 Final Test ScreenshotScreenshot automatically captured from End-to-End tests and will expire in 30 days This comment is automatically updated on each test run. |
Contributor
🤖 End-to-End Test Results - iOSStatus: ✅ Passed 📸 Final Test ScreenshotScreenshot automatically captured from End-to-End tests and will expire in 30 days This comment is automatically updated on each test run. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Summary
passphrasefield throughcreatePrivateKey/createPublicKey(TS layer was dropping it) and surfaces a clear "Passphrase required" error path on both encoding sidesncrypto::DataPointerwas constructed over JS-ownedArrayBuffermemory and thenOPENSSL_clear_free'd it on destruction — corrupting the JS Buffer (the "passphrase as Buffer" reuse case) and causing latent heap damage on every passphrased callERR_R_INTERRUPTED_OR_CANCELLEDonERR_LIB_CRYPTO) and stale entries in OpenSSL's error queue tripping ncrypto's post-parseERR_peek_error()check when multiple parse strategies are attemptedChanges
src/keys/index.ts+src/keys/classes.ts: forwardpassphrasethroughprepareAsymmetricKeyandKeyObject.createKeyObject, always passformat/encoding/passphrasetohandle.initcpp/keys/KeyObjectData.cpp+cpp/keys/HybridKeyObjectHandle.cpp: replacencrypto::DataPointer(ptr, len)withDataPointer::Copy(...)at all 7 sites so the wrapper owns memory it can safely free (mirrors Node.js'sByteSource::ToDataPointer)cpp/keys/KeyObjectData.cpp: detectERR_R_INTERRUPTED_OR_CANCELLEDand translate to "Passphrase required" when no passphrase was supplied;ERR_clear_error()between SPKI/PKCS8 attempts in the no-type DER branchexample/src/tests/keys/create_keys.ts: new tests for PEM/DER passphrase round-trips, Buffer-typed passphrase, encrypted-without-passphrase error message, wrong-passphrase error, andcreatePublicKeyextraction from a passphrase-encrypted DER private keyTest plan
bun ios, keys suite — all passphrase tests pass, no app crashbun androidsmoke-test of the keys suiteFixes #1048