summaryrefslogtreecommitdiff
path: root/ext/node
diff options
context:
space:
mode:
Diffstat (limited to 'ext/node')
-rw-r--r--ext/node/lib.rs1
-rw-r--r--ext/node/ops/crypto/keys.rs54
-rw-r--r--ext/node/polyfills/internal/crypto/keys.ts68
-rw-r--r--ext/node/polyfills/internal/errors.ts7
4 files changed, 129 insertions, 1 deletions
diff --git a/ext/node/lib.rs b/ext/node/lib.rs
index 39b380b99..ed6713eed 100644
--- a/ext/node/lib.rs
+++ b/ext/node/lib.rs
@@ -232,6 +232,7 @@ deno_core::extension!(deno_node,
ops::crypto::op_node_verify,
ops::crypto::op_node_verify_ed25519,
ops::crypto::keys::op_node_create_private_key,
+ ops::crypto::keys::op_node_create_ed_raw,
ops::crypto::keys::op_node_create_public_key,
ops::crypto::keys::op_node_create_secret_key,
ops::crypto::keys::op_node_derive_public_key_from_private_key,
diff --git a/ext/node/ops/crypto/keys.rs b/ext/node/ops/crypto/keys.rs
index 45849cbd9..7d7ec140e 100644
--- a/ext/node/ops/crypto/keys.rs
+++ b/ext/node/ops/crypto/keys.rs
@@ -571,6 +571,50 @@ impl KeyObjectHandle {
Ok(KeyObjectHandle::AsymmetricPublic(key))
}
+ pub fn new_ed_raw(
+ curve: &str,
+ data: &[u8],
+ is_public: bool,
+ ) -> Result<KeyObjectHandle, AnyError> {
+ match curve {
+ "Ed25519" => {
+ let data = data
+ .try_into()
+ .map_err(|_| type_error("invalid Ed25519 key"))?;
+ if !is_public {
+ Ok(KeyObjectHandle::AsymmetricPrivate(
+ AsymmetricPrivateKey::Ed25519(
+ ed25519_dalek::SigningKey::from_bytes(data),
+ ),
+ ))
+ } else {
+ Ok(KeyObjectHandle::AsymmetricPublic(
+ AsymmetricPublicKey::Ed25519(
+ ed25519_dalek::VerifyingKey::from_bytes(data)?,
+ ),
+ ))
+ }
+ }
+ "X25519" => {
+ let data: [u8; 32] = data
+ .try_into()
+ .map_err(|_| type_error("invalid x25519 key"))?;
+ if !is_public {
+ Ok(KeyObjectHandle::AsymmetricPrivate(
+ AsymmetricPrivateKey::X25519(x25519_dalek::StaticSecret::from(
+ data,
+ )),
+ ))
+ } else {
+ Ok(KeyObjectHandle::AsymmetricPublic(
+ AsymmetricPublicKey::X25519(x25519_dalek::PublicKey::from(data)),
+ ))
+ }
+ }
+ _ => Err(type_error("unsupported curve")),
+ }
+ }
+
pub fn new_asymmetric_public_key_from_js(
key: &[u8],
format: &str,
@@ -1029,6 +1073,16 @@ pub fn op_node_create_private_key(
#[op2]
#[cppgc]
+pub fn op_node_create_ed_raw(
+ #[string] curve: &str,
+ #[buffer] key: &[u8],
+ is_public: bool,
+) -> Result<KeyObjectHandle, AnyError> {
+ KeyObjectHandle::new_ed_raw(curve, key, is_public)
+}
+
+#[op2]
+#[cppgc]
pub fn op_node_create_public_key(
#[buffer] key: &[u8],
#[string] format: &str,
diff --git a/ext/node/polyfills/internal/crypto/keys.ts b/ext/node/polyfills/internal/crypto/keys.ts
index 62cec47d6..97e565023 100644
--- a/ext/node/polyfills/internal/crypto/keys.ts
+++ b/ext/node/polyfills/internal/crypto/keys.ts
@@ -12,6 +12,7 @@ const {
} = primordials;
import {
+ op_node_create_ed_raw,
op_node_create_private_key,
op_node_create_public_key,
op_node_create_secret_key,
@@ -32,6 +33,7 @@ import { kHandle } from "ext:deno_node/internal/crypto/constants.ts";
import { isStringOrBuffer } from "ext:deno_node/internal/crypto/cipher.ts";
import {
ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS,
+ ERR_CRYPTO_INVALID_JWK,
ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE,
ERR_INVALID_ARG_TYPE,
ERR_INVALID_ARG_VALUE,
@@ -56,6 +58,7 @@ import {
import {
validateObject,
validateOneOf,
+ validateString,
} from "ext:deno_node/internal/validators.mjs";
import { BufferEncoding } from "ext:deno_node/_global.d.ts";
@@ -256,6 +259,64 @@ export function getKeyObjectHandle(key: KeyObject, ctx: KeyHandleContext) {
return key[kHandle];
}
+function getKeyObjectHandleFromJwk(key, ctx) {
+ validateObject(key, "key");
+ validateOneOf(
+ key.kty,
+ "key.kty",
+ ["RSA", "EC", "OKP"],
+ );
+ const isPublic = ctx === kConsumePublic || ctx === kCreatePublic;
+
+ if (key.kty === "OKP") {
+ validateString(key.crv, "key.crv");
+ validateOneOf(
+ key.crv,
+ "key.crv",
+ ["Ed25519", "Ed448", "X25519", "X448"],
+ );
+ validateString(key.x, "key.x");
+
+ if (!isPublic) {
+ validateString(key.d, "key.d");
+ }
+
+ let keyData;
+ if (isPublic) {
+ keyData = Buffer.from(key.x, "base64");
+ } else {
+ keyData = Buffer.from(key.d, "base64");
+ }
+
+ switch (key.crv) {
+ case "Ed25519":
+ case "X25519":
+ if (keyData.byteLength !== 32) {
+ throw new ERR_CRYPTO_INVALID_JWK();
+ }
+ break;
+ case "Ed448":
+ if (keyData.byteLength !== 57) {
+ throw new ERR_CRYPTO_INVALID_JWK();
+ }
+ break;
+ case "X448":
+ if (keyData.byteLength !== 56) {
+ throw new ERR_CRYPTO_INVALID_JWK();
+ }
+ break;
+ }
+
+ return op_node_create_ed_raw(key.crv, keyData, isPublic);
+ }
+
+ if (key.kty === "EC") {
+ throw new TypeError("ec jwk imports not implemented");
+ }
+
+ throw new TypeError("rsa jwk imports not implemented");
+}
+
export function prepareAsymmetricKey(
key:
| string
@@ -306,7 +367,12 @@ export function prepareAsymmetricKey(
} else if (isCryptoKey(data)) {
notImplemented("using CryptoKey as input");
} else if (isJwk(data) && format === "jwk") {
- notImplemented("using JWK as input");
+ return {
+ // @ts-ignore __proto__ is magic
+ __proto__: null,
+ handle: getKeyObjectHandleFromJwk(data, ctx),
+ format,
+ };
}
// Either PEM or DER using PKCS#1 or SPKI.
if (!isStringOrBuffer(data)) {
diff --git a/ext/node/polyfills/internal/errors.ts b/ext/node/polyfills/internal/errors.ts
index 9ec9f9949..9e0905ef4 100644
--- a/ext/node/polyfills/internal/errors.ts
+++ b/ext/node/polyfills/internal/errors.ts
@@ -927,6 +927,12 @@ export class ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE extends NodeTypeError {
}
}
+export class ERR_CRYPTO_INVALID_JWK extends NodeError {
+ constructor() {
+ super("ERR_CRYPTO_INVALID_JWK", "Invalid JWK");
+ }
+}
+
export class ERR_CRYPTO_INVALID_STATE extends NodeError {
constructor(x: string) {
super("ERR_CRYPTO_INVALID_STATE", `Invalid state for operation ${x}`);
@@ -2733,6 +2739,7 @@ export default {
ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS,
ERR_CRYPTO_INVALID_DIGEST,
ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE,
+ ERR_CRYPTO_INVALID_JWK,
ERR_CRYPTO_INVALID_STATE,
ERR_CRYPTO_PBKDF2_ERROR,
ERR_CRYPTO_SCRYPT_INVALID_PARAMETER,