summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuca Casonato <hello@lcas.dev>2024-08-08 11:35:29 +0200
committerGitHub <noreply@github.com>2024-08-08 15:05:29 +0530
commit93d479252b5a18e6e782c74b808240bd3ef036bd (patch)
tree4c8b83797fb0e30d1ce3fcebad3fbde6cf33ef1d
parent507e5b74ff21161ba8bd947d7d9cee317c0af379 (diff)
fix(ext/node): add crypto.diffieHellman (#24938)
Co-authored-by: Divy Srivastava <dj.srivastava23@gmail.com> Closes #21806
-rw-r--r--Cargo.lock13
-rw-r--r--ext/node/Cargo.toml1
-rw-r--r--ext/node/lib.rs57
-rw-r--r--ext/node/ops/crypto/keys.rs156
-rw-r--r--ext/node/ops/crypto/mod.rs86
-rw-r--r--ext/node/ops/crypto/pkcs3.rs20
-rw-r--r--ext/node/ops/crypto/primes.rs1
-rw-r--r--ext/node/polyfills/internal/crypto/diffiehellman.ts15
-rw-r--r--ext/node/polyfills/internal/crypto/keys.ts2
9 files changed, 286 insertions, 65 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 761ce1df4..386329a19 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1776,6 +1776,7 @@ dependencies = [
"deno_package_json",
"deno_permissions",
"deno_whoami",
+ "der",
"digest",
"dsa",
"ecb",
@@ -2204,6 +2205,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0"
dependencies = [
"const-oid",
+ "der_derive",
"pem-rfc7468",
"zeroize",
]
@@ -2223,6 +2225,17 @@ dependencies = [
]
[[package]]
+name = "der_derive"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.72",
+]
+
+[[package]]
name = "deranged"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/ext/node/Cargo.toml b/ext/node/Cargo.toml
index 70d8f70cf..a0191b025 100644
--- a/ext/node/Cargo.toml
+++ b/ext/node/Cargo.toml
@@ -36,6 +36,7 @@ deno_net.workspace = true
deno_package_json.workspace = true
deno_permissions.workspace = true
deno_whoami = "0.1.0"
+der = { version = "0.7.9", features = ["derive"] }
digest = { version = "0.10.5", features = ["core-api", "std"] }
dsa = "0.6.1"
ecb.workspace = true
diff --git a/ext/node/lib.rs b/ext/node/lib.rs
index 3de6ddce6..51b22cefb 100644
--- a/ext/node/lib.rs
+++ b/ext/node/lib.rs
@@ -219,46 +219,47 @@ deno_core::extension!(deno_node,
ops::buffer::op_is_ascii,
ops::buffer::op_is_utf8,
- ops::crypto::op_node_create_decipheriv,
+ ops::crypto::op_node_check_prime_async,
+ ops::crypto::op_node_check_prime_bytes_async,
+ ops::crypto::op_node_check_prime_bytes,
+ ops::crypto::op_node_check_prime,
ops::crypto::op_node_cipheriv_encrypt,
ops::crypto::op_node_cipheriv_final,
ops::crypto::op_node_cipheriv_set_aad,
- ops::crypto::op_node_decipheriv_set_aad,
ops::crypto::op_node_create_cipheriv,
+ ops::crypto::op_node_create_decipheriv,
ops::crypto::op_node_create_hash,
- ops::crypto::op_node_get_hashes,
ops::crypto::op_node_decipheriv_decrypt,
ops::crypto::op_node_decipheriv_final,
- ops::crypto::op_node_hash_update,
- ops::crypto::op_node_hash_update_str,
- ops::crypto::op_node_hash_digest,
- ops::crypto::op_node_hash_digest_hex,
+ ops::crypto::op_node_decipheriv_set_aad,
+ ops::crypto::op_node_dh_compute_secret,
+ ops::crypto::op_node_diffie_hellman,
+ ops::crypto::op_node_ecdh_compute_public_key,
+ ops::crypto::op_node_ecdh_compute_secret,
+ ops::crypto::op_node_ecdh_encode_pubkey,
+ ops::crypto::op_node_ecdh_generate_keys,
+ ops::crypto::op_node_fill_random_async,
+ ops::crypto::op_node_fill_random,
+ ops::crypto::op_node_gen_prime_async,
+ ops::crypto::op_node_gen_prime,
+ ops::crypto::op_node_get_hashes,
ops::crypto::op_node_hash_clone,
- ops::crypto::op_node_private_encrypt,
+ ops::crypto::op_node_hash_digest_hex,
+ ops::crypto::op_node_hash_digest,
+ ops::crypto::op_node_hash_update_str,
+ ops::crypto::op_node_hash_update,
+ ops::crypto::op_node_hkdf_async,
+ ops::crypto::op_node_hkdf,
+ ops::crypto::op_node_pbkdf2_async,
+ ops::crypto::op_node_pbkdf2,
ops::crypto::op_node_private_decrypt,
+ ops::crypto::op_node_private_encrypt,
ops::crypto::op_node_public_encrypt,
- ops::crypto::op_node_check_prime,
- ops::crypto::op_node_check_prime_async,
- ops::crypto::op_node_check_prime_bytes,
- ops::crypto::op_node_check_prime_bytes_async,
- ops::crypto::op_node_gen_prime,
- ops::crypto::op_node_gen_prime_async,
- ops::crypto::op_node_pbkdf2,
- ops::crypto::op_node_pbkdf2_async,
- ops::crypto::op_node_hkdf,
- ops::crypto::op_node_hkdf_async,
- ops::crypto::op_node_fill_random,
- ops::crypto::op_node_fill_random_async,
- ops::crypto::op_node_sign,
- ops::crypto::op_node_dh_compute_secret,
- ops::crypto::op_node_verify,
ops::crypto::op_node_random_int,
- ops::crypto::op_node_scrypt_sync,
ops::crypto::op_node_scrypt_async,
- ops::crypto::op_node_ecdh_generate_keys,
- ops::crypto::op_node_ecdh_compute_secret,
- ops::crypto::op_node_ecdh_compute_public_key,
- ops::crypto::op_node_ecdh_encode_pubkey,
+ ops::crypto::op_node_scrypt_sync,
+ ops::crypto::op_node_sign,
+ ops::crypto::op_node_verify,
ops::crypto::keys::op_node_create_private_key,
ops::crypto::keys::op_node_create_public_key,
ops::crypto::keys::op_node_create_secret_key,
diff --git a/ext/node/ops/crypto/keys.rs b/ext/node/ops/crypto/keys.rs
index 86280c11a..5f634b35f 100644
--- a/ext/node/ops/crypto/keys.rs
+++ b/ext/node/ops/crypto/keys.rs
@@ -30,6 +30,7 @@ use rsa::pkcs1::EncodeRsaPublicKey;
use rsa::traits::PublicKeyParts;
use rsa::RsaPrivateKey;
use rsa::RsaPublicKey;
+use sec1::der::Tag;
use sec1::der::Writer as _;
use sec1::pem::PemLabel as _;
use sec1::DecodeEcPrivateKey as _;
@@ -46,7 +47,10 @@ use spki::EncodePublicKey as _;
use spki::SubjectPublicKeyInfoRef;
use super::dh;
+use super::dh::DiffieHellmanGroup;
use super::digest::match_fixed_digest_with_oid;
+use super::pkcs3;
+use super::pkcs3::DhParameter;
use super::primes::Prime;
#[derive(Clone)]
@@ -66,8 +70,7 @@ pub enum AsymmetricPrivateKey {
Ec(EcPrivateKey),
X25519(x25519_dalek::StaticSecret),
Ed25519(ed25519_dalek::SigningKey),
- #[allow(unused)]
- Dh(dh::PrivateKey),
+ Dh(DhPrivateKey),
}
#[derive(Clone)]
@@ -126,16 +129,20 @@ pub enum EcPrivateKey {
}
#[derive(Clone)]
+pub struct DhPrivateKey {
+ pub key: dh::PrivateKey,
+ pub params: DhParameter,
+}
+
+#[derive(Clone)]
pub enum AsymmetricPublicKey {
Rsa(rsa::RsaPublicKey),
RsaPss(RsaPssPublicKey),
Dsa(dsa::VerifyingKey),
Ec(EcPublicKey),
- #[allow(unused)]
X25519(x25519_dalek::PublicKey),
Ed25519(ed25519_dalek::VerifyingKey),
- #[allow(unused)]
- Dh(dh::PublicKey),
+ Dh(DhPublicKey),
}
#[derive(Clone)]
@@ -151,6 +158,12 @@ pub enum EcPublicKey {
P384(p384::PublicKey),
}
+#[derive(Clone)]
+pub struct DhPublicKey {
+ pub key: dh::PublicKey,
+ pub params: DhParameter,
+}
+
impl KeyObjectHandle {
/// Returns the private key if the handle is an asymmetric private key.
pub fn as_private_key(&self) -> Option<&AsymmetricPrivateKey> {
@@ -492,9 +505,18 @@ impl KeyObjectHandle {
bytes.copy_from_slice(string_ref.as_bytes());
AsymmetricPrivateKey::Ed25519(ed25519_dalek::SigningKey::from(bytes))
}
- DH_KEY_AGREEMENT_OID => AsymmetricPrivateKey::Dh(
- dh::PrivateKey::from_bytes(pk_info.private_key),
- ),
+ DH_KEY_AGREEMENT_OID => {
+ let params = pk_info
+ .algorithm
+ .parameters
+ .ok_or_else(|| type_error("missing dh parameters"))?;
+ let params = pkcs3::DhParameter::from_der(&params.to_der().unwrap())
+ .map_err(|_| type_error("malformed dh parameters"))?;
+ AsymmetricPrivateKey::Dh(DhPrivateKey {
+ key: dh::PrivateKey::from_bytes(pk_info.private_key),
+ params,
+ })
+ }
_ => return Err(type_error("unsupported private key oid")),
};
@@ -634,11 +656,20 @@ impl KeyObjectHandle {
AsymmetricPublicKey::Ed25519(verifying_key)
}
DH_KEY_AGREEMENT_OID => {
+ let params = spki
+ .algorithm
+ .parameters
+ .ok_or_else(|| type_error("missing dh parameters"))?;
+ let params = pkcs3::DhParameter::from_der(&params.to_der().unwrap())
+ .map_err(|_| type_error("malformed dh parameters"))?;
let Some(subject_public_key) = spki.subject_public_key.as_bytes()
else {
return Err(type_error("malformed or missing public key in dh spki"));
};
- AsymmetricPublicKey::Dh(dh::PublicKey::from_bytes(subject_public_key))
+ AsymmetricPublicKey::Dh(DhPublicKey {
+ key: dh::PublicKey::from_bytes(subject_public_key),
+ params,
+ })
}
_ => return Err(type_error("unsupported public key oid")),
};
@@ -788,16 +819,18 @@ impl AsymmetricPublicKey {
.into_boxed_slice()
}
AsymmetricPublicKey::Dh(key) => {
- let public_key_bytes = key.clone().into_vec();
- let spki =
- SubjectPublicKeyInfoRef {
- algorithm: rsa::pkcs8::AlgorithmIdentifierRef {
- oid: DH_KEY_AGREEMENT_OID,
- parameters: None,
- },
- subject_public_key: BitStringRef::from_bytes(&public_key_bytes)
- .map_err(|_| type_error("invalid DH public key"))?,
- };
+ let public_key_bytes = key.key.clone().into_vec();
+ let params = key.params.to_der().unwrap();
+ let spki = SubjectPublicKeyInfoRef {
+ algorithm: rsa::pkcs8::AlgorithmIdentifierRef {
+ oid: DH_KEY_AGREEMENT_OID,
+ parameters: Some(AnyRef::new(Tag::Sequence, &params).unwrap()),
+ },
+ subject_public_key: BitStringRef::from_bytes(&public_key_bytes)
+ .map_err(|_| {
+ type_error("invalid DH public key")
+ })?,
+ };
spki
.to_der()
.map_err(|_| type_error("invalid DH public key"))?
@@ -917,11 +950,12 @@ impl AsymmetricPrivateKey {
.into_boxed_slice()
}
AsymmetricPrivateKey::Dh(key) => {
- let private_key = key.clone().into_vec();
+ let private_key = key.key.clone().into_vec();
+ let params = key.params.to_der().unwrap();
let private_key = PrivateKeyInfo {
algorithm: rsa::pkcs8::AlgorithmIdentifierRef {
oid: DH_KEY_AGREEMENT_OID,
- parameters: None,
+ parameters: Some(AnyRef::new(Tag::Sequence, &params).unwrap()),
},
private_key: &private_key,
public_key: None,
@@ -1514,21 +1548,66 @@ pub async fn op_node_generate_ed25519_key_async() -> KeyObjectHandlePair {
spawn_blocking(ed25519_generate).await.unwrap()
}
+fn u32_slice_to_u8_slice(slice: &[u32]) -> &[u8] {
+ // SAFETY: just reinterpreting the slice as u8
+ unsafe {
+ std::slice::from_raw_parts(
+ slice.as_ptr() as *const u8,
+ std::mem::size_of_val(slice),
+ )
+ }
+}
+
fn dh_group_generate(
group_name: &str,
) -> Result<KeyObjectHandlePair, AnyError> {
- let dh = match group_name {
- "modp5" => dh::DiffieHellman::group::<dh::Modp1536>(),
- "modp14" => dh::DiffieHellman::group::<dh::Modp2048>(),
- "modp15" => dh::DiffieHellman::group::<dh::Modp3072>(),
- "modp16" => dh::DiffieHellman::group::<dh::Modp4096>(),
- "modp17" => dh::DiffieHellman::group::<dh::Modp6144>(),
- "modp18" => dh::DiffieHellman::group::<dh::Modp8192>(),
+ let (dh, prime, generator) = match group_name {
+ "modp5" => (
+ dh::DiffieHellman::group::<dh::Modp1536>(),
+ dh::Modp1536::MODULUS,
+ dh::Modp1536::GENERATOR,
+ ),
+ "modp14" => (
+ dh::DiffieHellman::group::<dh::Modp2048>(),
+ dh::Modp2048::MODULUS,
+ dh::Modp2048::GENERATOR,
+ ),
+ "modp15" => (
+ dh::DiffieHellman::group::<dh::Modp3072>(),
+ dh::Modp3072::MODULUS,
+ dh::Modp3072::GENERATOR,
+ ),
+ "modp16" => (
+ dh::DiffieHellman::group::<dh::Modp4096>(),
+ dh::Modp4096::MODULUS,
+ dh::Modp4096::GENERATOR,
+ ),
+ "modp17" => (
+ dh::DiffieHellman::group::<dh::Modp6144>(),
+ dh::Modp6144::MODULUS,
+ dh::Modp6144::GENERATOR,
+ ),
+ "modp18" => (
+ dh::DiffieHellman::group::<dh::Modp8192>(),
+ dh::Modp8192::MODULUS,
+ dh::Modp8192::GENERATOR,
+ ),
_ => return Err(type_error("Unsupported group name")),
};
+ let params = DhParameter {
+ prime: asn1::Int::new(u32_slice_to_u8_slice(prime)).unwrap(),
+ base: asn1::Int::new(generator.to_be_bytes().as_slice()).unwrap(),
+ private_value_length: None,
+ };
Ok(KeyObjectHandlePair::new(
- AsymmetricPrivateKey::Dh(dh.private_key),
- AsymmetricPublicKey::Dh(dh.public_key),
+ AsymmetricPrivateKey::Dh(DhPrivateKey {
+ key: dh.private_key,
+ params: params.clone(),
+ }),
+ AsymmetricPublicKey::Dh(DhPublicKey {
+ key: dh.public_key,
+ params,
+ }),
))
}
@@ -1558,10 +1637,21 @@ fn dh_generate(
let prime = prime
.map(|p| p.into())
.unwrap_or_else(|| Prime::generate(prime_len));
- let dh = dh::DiffieHellman::new(prime, generator);
+ let dh = dh::DiffieHellman::new(prime.clone(), generator);
+ let params = DhParameter {
+ prime: asn1::Int::new(&prime.0.to_bytes_be()).unwrap(),
+ base: asn1::Int::new(generator.to_be_bytes().as_slice()).unwrap(),
+ private_value_length: None,
+ };
Ok(KeyObjectHandlePair::new(
- AsymmetricPrivateKey::Dh(dh.private_key),
- AsymmetricPublicKey::Dh(dh.public_key),
+ AsymmetricPrivateKey::Dh(DhPrivateKey {
+ key: dh.private_key,
+ params: params.clone(),
+ }),
+ AsymmetricPublicKey::Dh(DhPublicKey {
+ key: dh.public_key,
+ params,
+ }),
))
}
diff --git a/ext/node/ops/crypto/mod.rs b/ext/node/ops/crypto/mod.rs
index 07d901cbc..567affd52 100644
--- a/ext/node/ops/crypto/mod.rs
+++ b/ext/node/ops/crypto/mod.rs
@@ -10,6 +10,10 @@ use deno_core::StringOrBuffer;
use deno_core::ToJsBuffer;
use elliptic_curve::sec1::ToEncodedPoint;
use hkdf::Hkdf;
+use keys::AsymmetricPrivateKey;
+use keys::AsymmetricPublicKey;
+use keys::EcPrivateKey;
+use keys::EcPublicKey;
use keys::KeyObjectHandle;
use num_bigint::BigInt;
use num_bigint_dig::BigUint;
@@ -34,6 +38,7 @@ mod dh;
mod digest;
pub mod keys;
mod md5_sha1;
+mod pkcs3;
mod primes;
mod sign;
pub mod x509;
@@ -839,3 +844,84 @@ pub async fn op_node_gen_prime_async(
) -> Result<ToJsBuffer, AnyError> {
Ok(spawn_blocking(move || gen_prime(size)).await?)
}
+
+#[op2]
+#[buffer]
+pub fn op_node_diffie_hellman(
+ #[cppgc] private: &KeyObjectHandle,
+ #[cppgc] public: &KeyObjectHandle,
+) -> Result<Box<[u8]>, AnyError> {
+ let private = private
+ .as_private_key()
+ .ok_or_else(|| type_error("Expected private key"))?;
+ let public = public
+ .as_public_key()
+ .ok_or_else(|| type_error("Expected public key"))?;
+
+ let res = match (private, &*public) {
+ (
+ AsymmetricPrivateKey::Ec(EcPrivateKey::P224(private)),
+ AsymmetricPublicKey::Ec(EcPublicKey::P224(public)),
+ ) => p224::ecdh::diffie_hellman(
+ private.to_nonzero_scalar(),
+ public.as_affine(),
+ )
+ .raw_secret_bytes()
+ .to_vec()
+ .into_boxed_slice(),
+ (
+ AsymmetricPrivateKey::Ec(EcPrivateKey::P256(private)),
+ AsymmetricPublicKey::Ec(EcPublicKey::P256(public)),
+ ) => p256::ecdh::diffie_hellman(
+ private.to_nonzero_scalar(),
+ public.as_affine(),
+ )
+ .raw_secret_bytes()
+ .to_vec()
+ .into_boxed_slice(),
+ (
+ AsymmetricPrivateKey::Ec(EcPrivateKey::P384(private)),
+ AsymmetricPublicKey::Ec(EcPublicKey::P384(public)),
+ ) => p384::ecdh::diffie_hellman(
+ private.to_nonzero_scalar(),
+ public.as_affine(),
+ )
+ .raw_secret_bytes()
+ .to_vec()
+ .into_boxed_slice(),
+ (
+ AsymmetricPrivateKey::X25519(private),
+ AsymmetricPublicKey::X25519(public),
+ ) => private
+ .diffie_hellman(public)
+ .to_bytes()
+ .into_iter()
+ .collect(),
+ (AsymmetricPrivateKey::Dh(private), AsymmetricPublicKey::Dh(public)) => {
+ if private.params.prime != public.params.prime
+ || private.params.base != public.params.base
+ {
+ return Err(type_error("DH parameters mismatch"));
+ }
+
+ // OSIP - Octet-String-to-Integer primitive
+ let public_key = public.key.clone().into_vec();
+ let pubkey = BigUint::from_bytes_be(&public_key);
+
+ // Exponentiation (z = y^x mod p)
+ let prime = BigUint::from_bytes_be(private.params.prime.as_bytes());
+ let private_key = private.key.clone().into_vec();
+ let private_key = BigUint::from_bytes_be(&private_key);
+ let shared_secret = pubkey.modpow(&private_key, &prime);
+
+ shared_secret.to_bytes_be().into()
+ }
+ _ => {
+ return Err(type_error(
+ "Unsupported key type for diffie hellman, or key type mismatch",
+ ))
+ }
+ };
+
+ Ok(res)
+}
diff --git a/ext/node/ops/crypto/pkcs3.rs b/ext/node/ops/crypto/pkcs3.rs
new file mode 100644
index 000000000..577251460
--- /dev/null
+++ b/ext/node/ops/crypto/pkcs3.rs
@@ -0,0 +1,20 @@
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+//
+// PKCS #3: Diffie-Hellman Key Agreement Standard
+
+use der::Sequence;
+use spki::der;
+use spki::der::asn1;
+
+// The parameters fields associated with OID dhKeyAgreement
+//
+// DHParameter ::= SEQUENCE {
+// prime INTEGER, -- p
+// base INTEGER, -- g
+// privateValueLength INTEGER OPTIONAL }
+#[derive(Clone, Sequence)]
+pub struct DhParameter {
+ pub prime: asn1::Int,
+ pub base: asn1::Int,
+ pub private_value_length: Option<asn1::Int>,
+}
diff --git a/ext/node/ops/crypto/primes.rs b/ext/node/ops/crypto/primes.rs
index 5c9f4c768..2e5d1ff63 100644
--- a/ext/node/ops/crypto/primes.rs
+++ b/ext/node/ops/crypto/primes.rs
@@ -8,6 +8,7 @@ use num_traits::Zero;
use rand::Rng;
use std::ops::Deref;
+#[derive(Clone)]
pub struct Prime(pub num_bigint_dig::BigUint);
impl Prime {
diff --git a/ext/node/polyfills/internal/crypto/diffiehellman.ts b/ext/node/polyfills/internal/crypto/diffiehellman.ts
index 16a1f2498..a439306a9 100644
--- a/ext/node/polyfills/internal/crypto/diffiehellman.ts
+++ b/ext/node/polyfills/internal/crypto/diffiehellman.ts
@@ -7,6 +7,7 @@
import {
op_node_dh_compute_secret,
op_node_dh_keys_generate_and_export,
+ op_node_diffie_hellman,
op_node_ecdh_compute_public_key,
op_node_ecdh_compute_secret,
op_node_ecdh_encode_pubkey,
@@ -40,7 +41,12 @@ import type {
BinaryToTextEncoding,
ECDHKeyFormat,
} from "ext:deno_node/internal/crypto/types.ts";
-import { KeyObject } from "ext:deno_node/internal/crypto/keys.ts";
+import {
+ getKeyObjectHandle,
+ kConsumePrivate,
+ kConsumePublic,
+ KeyObject,
+} from "ext:deno_node/internal/crypto/keys.ts";
import type { BufferEncoding } from "ext:deno_node/_global.d.ts";
const DH_GENERATOR = 2;
@@ -1305,11 +1311,14 @@ export class ECDH {
}
}
-export function diffieHellman(_options: {
+export function diffieHellman(options: {
privateKey: KeyObject;
publicKey: KeyObject;
}): Buffer {
- notImplemented("crypto.diffieHellman");
+ const privateKey = getKeyObjectHandle(options.privateKey, kConsumePrivate);
+ const publicKey = getKeyObjectHandle(options.publicKey, kConsumePublic);
+ const bytes = op_node_diffie_hellman(privateKey, publicKey);
+ return Buffer.from(bytes);
}
export default {
diff --git a/ext/node/polyfills/internal/crypto/keys.ts b/ext/node/polyfills/internal/crypto/keys.ts
index 31d674e67..62cec47d6 100644
--- a/ext/node/polyfills/internal/crypto/keys.ts
+++ b/ext/node/polyfills/internal/crypto/keys.ts
@@ -232,7 +232,7 @@ export interface JsonWebKeyInput {
format: "jwk";
}
-function getKeyObjectHandle(key: KeyObject, ctx: KeyHandleContext) {
+export function getKeyObjectHandle(key: KeyObject, ctx: KeyHandleContext) {
if (ctx === kCreatePrivate) {
throw new ERR_INVALID_ARG_TYPE(
"key",