Summary
crypto.KeyObject.from() returns undefined — silently, with no throw — for two shapes Node handles:
- an asymmetric
CryptoKey (public/private)
- a secret
CryptoKey whose backing buffer is not runtime-registered (e.g. imported from Buffer.from(hex) rather than from secretKey.export())
Behaviour
| input |
node 26 |
perry main |
KeyObject.from(<asymmetric CryptoKey>) |
public |
undefined |
KeyObject.from(<HMAC CryptoKey from Buffer.from(hex)>) |
secret |
undefined |
Root cause
crates/perry-runtime/src/object/native_module_crypto_key_object.rs:20-28 — key_object_from requires kind == 1 and is_registered_buffer(addr); anything else falls through to invalid_key(value) and yields undefined instead of throwing or constructing a KeyObject.
The checked-in fixture test-parity/node-suite/crypto/key-object/keyobject-class-from.ts only passes because it imports from secret.export(), which is an already-registered buffer — so this gap is not covered.
Split out of #2565 (whose three headline deliverables did ship and are byte-identical to Node).
Summary
crypto.KeyObject.from()returnsundefined— silently, with no throw — for two shapes Node handles:CryptoKey(public/private)CryptoKeywhose backing buffer is not runtime-registered (e.g. imported fromBuffer.from(hex)rather than fromsecretKey.export())Behaviour
mainKeyObject.from(<asymmetric CryptoKey>)publicundefinedKeyObject.from(<HMAC CryptoKey from Buffer.from(hex)>)secretundefinedRoot cause
crates/perry-runtime/src/object/native_module_crypto_key_object.rs:20-28—key_object_fromrequireskind == 1andis_registered_buffer(addr); anything else falls through toinvalid_key(value)and yieldsundefinedinstead of throwing or constructing a KeyObject.The checked-in fixture
test-parity/node-suite/crypto/key-object/keyobject-class-from.tsonly passes because it imports fromsecret.export(), which is an already-registered buffer — so this gap is not covered.Split out of #2565 (whose three headline deliverables did ship and are byte-identical to Node).