Skip to content

fix(ext/node): support encrypted PEM export and deprecated hash option in crypto keygen#32703

Merged
bartlomieju merged 3 commits intodenoland:mainfrom
bartlomieju:fix/crypto
Mar 14, 2026
Merged

fix(ext/node): support encrypted PEM export and deprecated hash option in crypto keygen#32703
bartlomieju merged 3 commits intodenoland:mainfrom
bartlomieju:fix/crypto

Conversation

@bartlomieju
Copy link
Copy Markdown
Member

Summary

  • Fix generateKeyPair for rsa-pss to fall back to deprecated hash option when hashAlgorithm is not provided, matching Node.js behavior
  • Implement encrypted PEM private key export with legacy OpenSSL format (Proc-Type/DEK-Info headers) using EVP_BytesToKey key derivation
  • Support AES-128-CBC, AES-192-CBC, AES-256-CBC, and DES-EDE3-CBC ciphers for PEM encryption
  • Wire up cipher/passphrase options from KeyObject.export() through to the Rust op
  • Add node_compat test entries for test-crypto-keygen-deprecation, test-crypto-keygen-bit-length (ignored: Rust dsa crate limitation), and test-crypto-keygen-async-rsa (ignored: legacy PEM decryption not yet supported)

Test plan

  • test-crypto-keygen-deprecation.js passes (was failing due to missing hashhashAlgorithm fallback)
  • test-crypto-keygen-bit-length.js ignored with reason (dsa crate only supports fixed key sizes)
  • test-crypto-keygen-async-rsa.js ignored with reason (legacy PEM decryption not yet implemented)
  • Encrypted PEM output matches expected format (Proc-Type/DEK-Info headers, correct base64 line wrapping)

🤖 Generated with Claude Code

…n in crypto keygen

- Fix `generateKeyPair` for `rsa-pss` to fall back to deprecated `hash`
  option when `hashAlgorithm` is not provided (matching Node.js behavior)
- Implement encrypted PEM private key export with legacy OpenSSL format
  (Proc-Type/DEK-Info headers) for PKCS#1, PKCS#8, and SEC1 key types
- Support AES-128-CBC, AES-192-CBC, AES-256-CBC, and DES-EDE3-CBC ciphers
  for PEM encryption using EVP_BytesToKey key derivation
- Pass cipher/passphrase from KeyObject.export() to the Rust op
- Add node_compat test entries for crypto keygen tests

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Member

@littledivy littledivy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PEM export path introduces a high-severity security/compatibility bug: if callers provide only one of cipher or passphrase, the code silently falls back to exporting an unencrypted private key. This can leak key material unexpectedly and does not match expected option validation behavior. The export API must reject partial encryption configuration rather than downgrading to plaintext output.


if let (Some(cipher), Some(passphrase)) = (cipher, passphrase) {
return encrypt_private_key_pem(
label,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[high] PEM encryption is applied only when both cipher and passphrase are Some; if only one is provided, the function silently exports an unencrypted key. This is a dangerous implicit downgrade and behavior mismatch. Add explicit validation: if exactly one of cipher/passphrase is set, return an error (TypeError/validation error) instead of exporting plaintext.

bartlomieju and others added 2 commits March 14, 2026 10:35
Return a TypeError if only one of cipher/passphrase is provided
instead of silently exporting an unencrypted key.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@bartlomieju bartlomieju requested a review from littledivy March 14, 2026 13:52
@bartlomieju bartlomieju merged commit 2c3b295 into denoland:main Mar 14, 2026
112 checks passed
@bartlomieju bartlomieju deleted the fix/crypto branch March 14, 2026 13:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants