From fadd17dbdb2f7ba50ed8d4d58c2934f888846895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Tue, 10 Dec 2024 17:07:02 +0100 Subject: [PATCH] wip --- ext/node/lib.rs | 1 + ext/node/ops/crypto/keys.rs | 66 ++++++++++++++++++++++ ext/node/polyfills/internal/crypto/keys.ts | 3 +- jwk.js | 15 +++++ 4 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 jwk.js diff --git a/ext/node/lib.rs b/ext/node/lib.rs index bf593ad43218ec..e41b33029ace89 100644 --- a/ext/node/lib.rs +++ b/ext/node/lib.rs @@ -260,6 +260,7 @@ deno_core::extension!(deno_node, ops::crypto::keys::op_node_derive_public_key_from_private_key, ops::crypto::keys::op_node_dh_keys_generate_and_export, ops::crypto::keys::op_node_export_private_key_der, + ops::crypto::keys::op_node_export_private_key_jwk, ops::crypto::keys::op_node_export_private_key_pem, ops::crypto::keys::op_node_export_public_key_der, ops::crypto::keys::op_node_export_public_key_pem, diff --git a/ext/node/ops/crypto/keys.rs b/ext/node/ops/crypto/keys.rs index f164972d48afc6..ca629e24e11343 100644 --- a/ext/node/ops/crypto/keys.rs +++ b/ext/node/ops/crypto/keys.rs @@ -26,6 +26,7 @@ use rsa::pkcs1::DecodeRsaPrivateKey as _; use rsa::pkcs1::DecodeRsaPublicKey; use rsa::pkcs1::EncodeRsaPrivateKey as _; use rsa::pkcs1::EncodeRsaPublicKey; +use rsa::traits::PrivateKeyParts; use rsa::traits::PublicKeyParts; use rsa::RsaPrivateKey; use rsa::RsaPublicKey; @@ -2329,6 +2330,71 @@ pub fn op_node_export_private_key_pem( Ok(String::from_utf8(out).expect("invalid pem is not possible")) } +#[derive(Debug, thiserror::Error)] +pub enum ExportPrivateKeyJwkError { + #[error(transparent)] + AsymmetricPublicKeyDer(#[from] AsymmetricPrivateKeyDerError), + #[error("very large data")] + VeryLargeData, + #[error(transparent)] + Der(#[from] der::Error), +} + +#[op2] +#[serde] +pub fn op_node_export_private_key_jwk( + #[cppgc] handle: &KeyObjectHandle, +) -> Result { + let private_key = handle + .as_private_key() + .ok_or(AsymmetricPrivateKeyDerError::KeyIsNotAsymmetricPrivateKey)?; + + match private_key { + AsymmetricPrivateKey::Rsa(key) => { + let n = key.n(); + let e = key.e(); + let d = key.d(); + let p = key.primes()[0]; + let q = key.primes()[1]; + let dp = key.dp(); + let dq = key.dq(); + let qi = key.crt_coefficient().unwrap(); + let oth = &key.primes()[2..]; + + let mut obj = deno_core::serde_json::json!({ + "kty": "RSA", + "n": bytes_to_b64(&n.to_bytes_be()), + "e": bytes_to_b64(&e.to_bytes_be()), + "d": bytes_to_b64(&d.to_bytes_be()), + "p": bytes_to_b64(&p.to_bytes_be()), + "q": bytes_to_b64(&q.to_bytes_be()), + "dp": bytes_to_b64(&p.to_bytes_be()), + "dq": bytes_to_b64(&p.to_bytes_be()), + "qi": bytes_to_b64(&p.to_bytes_be()), + }); + + if !oth.is_empty() { + obj["oth"] = deno_core::serde_json::json!(oth + .iter() + .map(|o| &o.to_bytes_be()) + .collect::>()); + } + + return Ok(obj); + } + AsymmetricPrivateKey::RsaPss(key) => Ok(deno_core::serde_json::json!({})), + AsymmetricPrivateKey::Dsa(key) => Ok(deno_core::serde_json::json!({})), + AsymmetricPrivateKey::Ec(key) => Ok(deno_core::serde_json::json!({})), + AsymmetricPrivateKey::X25519(static_secret) => { + Ok(deno_core::serde_json::json!({})) + } + AsymmetricPrivateKey::Ed25519(key) => Ok(deno_core::serde_json::json!({})), + AsymmetricPrivateKey::Dh(key) => Ok(deno_core::serde_json::json!({})), + }; + + todo!() +} + #[op2] #[buffer] pub fn op_node_export_private_key_der( diff --git a/ext/node/polyfills/internal/crypto/keys.ts b/ext/node/polyfills/internal/crypto/keys.ts index c91c23cc3dd931..932856df0e88d5 100644 --- a/ext/node/polyfills/internal/crypto/keys.ts +++ b/ext/node/polyfills/internal/crypto/keys.ts @@ -20,6 +20,7 @@ import { op_node_create_secret_key, op_node_derive_public_key_from_private_key, op_node_export_private_key_der, + op_node_export_private_key_jwk, op_node_export_private_key_pem, op_node_export_public_key_der, op_node_export_public_key_jwk, @@ -791,7 +792,7 @@ export class PrivateKeyObject extends AsymmetricKeyObject { export(options: JwkKeyExportOptions | KeyExportOptions) { if (options && options.format === "jwk") { - notImplemented("jwk private key export not implemented"); + return op_node_export_private_key_jwk(this[kHandle]); } const { format, diff --git a/jwk.js b/jwk.js new file mode 100644 index 00000000000000..307e0dea47acc4 --- /dev/null +++ b/jwk.js @@ -0,0 +1,15 @@ +import { generateKeyPairSync } from "node:crypto"; + +const modulusLength = 4096; + +const key = generateKeyPairSync("rsa", { + modulusLength, + publicKeyEncoding: { + format: "jwk", + }, + privateKeyEncoding: { + format: "jwk", + }, +}); + +console.log(key);