mirror of
https://github.com/denoland/deno.git
synced 2024-12-24 08:09:08 -05:00
fix(ext/node): import EC JWK keys (#25266)
This commit is contained in:
parent
5dbf1af591
commit
567b4967a9
6 changed files with 116 additions and 7 deletions
14
Cargo.lock
generated
14
Cargo.lock
generated
|
@ -2694,6 +2694,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47"
|
||||
dependencies = [
|
||||
"base16ct",
|
||||
"base64ct",
|
||||
"crypto-bigint",
|
||||
"digest",
|
||||
"ff",
|
||||
|
@ -2704,6 +2705,8 @@ dependencies = [
|
|||
"pkcs8",
|
||||
"rand_core",
|
||||
"sec1",
|
||||
"serde_json",
|
||||
"serdect",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
@ -6169,6 +6172,7 @@ dependencies = [
|
|||
"der",
|
||||
"generic-array",
|
||||
"pkcs8",
|
||||
"serdect",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
@ -6314,6 +6318,16 @@ dependencies = [
|
|||
"v8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serdect"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a84f14a19e9a014bb9f4512488d9829a68e04ecabffb0f9904cd1ace94598177"
|
||||
dependencies = [
|
||||
"base16ct",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.10.6"
|
||||
|
|
|
@ -106,7 +106,7 @@ deno_cache_dir = "=0.10.2"
|
|||
deno_package_json = { version = "=0.1.1", default-features = false }
|
||||
dlopen2 = "0.6.1"
|
||||
ecb = "=0.1.2"
|
||||
elliptic-curve = { version = "0.13.4", features = ["alloc", "arithmetic", "ecdh", "std", "pem"] }
|
||||
elliptic-curve = { version = "0.13.4", features = ["alloc", "arithmetic", "ecdh", "std", "pem", "jwk"] }
|
||||
encoding_rs = "=0.8.33"
|
||||
fast-socks5 = "0.9.6"
|
||||
faster-hex = "0.9"
|
||||
|
@ -141,8 +141,8 @@ num-bigint = { version = "0.4", features = ["rand"] }
|
|||
once_cell = "1.17.1"
|
||||
os_pipe = { version = "=1.1.5", features = ["io_safety"] }
|
||||
p224 = { version = "0.13.0", features = ["ecdh"] }
|
||||
p256 = { version = "0.13.2", features = ["ecdh"] }
|
||||
p384 = { version = "0.13.0", features = ["ecdh"] }
|
||||
p256 = { version = "0.13.2", features = ["ecdh", "jwk"] }
|
||||
p384 = { version = "0.13.0", features = ["ecdh", "jwk"] }
|
||||
parking_lot = "0.12.0"
|
||||
percent-encoding = "2.3.0"
|
||||
phf = { version = "0.11", features = ["macros"] }
|
||||
|
|
|
@ -233,6 +233,7 @@ deno_core::extension!(deno_node,
|
|||
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_ec_jwk,
|
||||
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,
|
||||
|
|
|
@ -13,6 +13,7 @@ use deno_core::unsync::spawn_blocking;
|
|||
use deno_core::GarbageCollected;
|
||||
use deno_core::ToJsBuffer;
|
||||
use ed25519_dalek::pkcs8::BitStringRef;
|
||||
use elliptic_curve::JwkEcKey;
|
||||
use num_bigint::BigInt;
|
||||
use num_traits::FromPrimitive as _;
|
||||
use pkcs8::DecodePrivateKey as _;
|
||||
|
@ -571,6 +572,36 @@ impl KeyObjectHandle {
|
|||
Ok(KeyObjectHandle::AsymmetricPublic(key))
|
||||
}
|
||||
|
||||
pub fn new_ec_jwk(
|
||||
jwk: &JwkEcKey,
|
||||
is_public: bool,
|
||||
) -> Result<KeyObjectHandle, AnyError> {
|
||||
// https://datatracker.ietf.org/doc/html/rfc7518#section-6.2.1.1
|
||||
let handle = match jwk.crv() {
|
||||
"P-256" if is_public => {
|
||||
KeyObjectHandle::AsymmetricPublic(AsymmetricPublicKey::Ec(
|
||||
EcPublicKey::P256(p256::PublicKey::from_jwk(jwk)?),
|
||||
))
|
||||
}
|
||||
"P-256" => KeyObjectHandle::AsymmetricPrivate(AsymmetricPrivateKey::Ec(
|
||||
EcPrivateKey::P256(p256::SecretKey::from_jwk(jwk)?),
|
||||
)),
|
||||
"P-384" if is_public => {
|
||||
KeyObjectHandle::AsymmetricPublic(AsymmetricPublicKey::Ec(
|
||||
EcPublicKey::P384(p384::PublicKey::from_jwk(jwk)?),
|
||||
))
|
||||
}
|
||||
"P-384" => KeyObjectHandle::AsymmetricPrivate(AsymmetricPrivateKey::Ec(
|
||||
EcPrivateKey::P384(p384::SecretKey::from_jwk(jwk)?),
|
||||
)),
|
||||
_ => {
|
||||
return Err(type_error(format!("unsupported curve: {}", jwk.crv())));
|
||||
}
|
||||
};
|
||||
|
||||
Ok(handle)
|
||||
}
|
||||
|
||||
pub fn new_ed_raw(
|
||||
curve: &str,
|
||||
data: &[u8],
|
||||
|
@ -1081,6 +1112,15 @@ pub fn op_node_create_ed_raw(
|
|||
KeyObjectHandle::new_ed_raw(curve, key, is_public)
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[cppgc]
|
||||
pub fn op_node_create_ec_jwk(
|
||||
#[serde] jwk: elliptic_curve::JwkEcKey,
|
||||
is_public: bool,
|
||||
) -> Result<KeyObjectHandle, AnyError> {
|
||||
KeyObjectHandle::new_ec_jwk(&jwk, is_public)
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[cppgc]
|
||||
pub fn op_node_create_public_key(
|
||||
|
|
|
@ -12,6 +12,7 @@ const {
|
|||
} = primordials;
|
||||
|
||||
import {
|
||||
op_node_create_ec_jwk,
|
||||
op_node_create_ed_raw,
|
||||
op_node_create_private_key,
|
||||
op_node_create_public_key,
|
||||
|
@ -311,7 +312,15 @@ function getKeyObjectHandleFromJwk(key, ctx) {
|
|||
}
|
||||
|
||||
if (key.kty === "EC") {
|
||||
throw new TypeError("ec jwk imports not implemented");
|
||||
validateString(key.crv, "key.crv");
|
||||
validateString(key.x, "key.x");
|
||||
validateString(key.y, "key.y");
|
||||
|
||||
if (!isPublic) {
|
||||
validateString(key.d, "key.d");
|
||||
}
|
||||
|
||||
return op_node_create_ec_jwk(key, isPublic);
|
||||
}
|
||||
|
||||
throw new TypeError("rsa jwk imports not implemented");
|
||||
|
|
|
@ -440,7 +440,7 @@ Deno.test("create private key with invalid utf-8 string", function () {
|
|||
);
|
||||
});
|
||||
|
||||
Deno.test("Ed25519 jwk public key #1", function () {
|
||||
Deno.test("Ed25519 import jwk public key #1", function () {
|
||||
const key = {
|
||||
"kty": "OKP",
|
||||
"crv": "Ed25519",
|
||||
|
@ -460,7 +460,7 @@ MCowBQYDK2VwAyEA11qYAYKxCrfVS/7TyWQHOg7hcvPapiMlrwIaaPcHURo=
|
|||
assertEquals(spkiActual, spkiExpected);
|
||||
});
|
||||
|
||||
Deno.test("Ed25519 jwk public key #2", function () {
|
||||
Deno.test("Ed25519 import jwk public key #2", function () {
|
||||
const key = {
|
||||
"kty": "OKP",
|
||||
"crv": "Ed25519",
|
||||
|
@ -478,7 +478,7 @@ MCowBQYDK2VwAyEA11qYAYKxCrfVS/7TyWQHOg7hcvPapiMlrwIaaPcHURo=
|
|||
assertEquals(spki, spkiExpected);
|
||||
});
|
||||
|
||||
Deno.test("Ed25519 jwk private key", function () {
|
||||
Deno.test("Ed25519 import jwk private key", function () {
|
||||
const key = {
|
||||
"kty": "OKP",
|
||||
"crv": "Ed25519",
|
||||
|
@ -497,3 +497,48 @@ MC4CAQAwBQYDK2VwBCIEIJ1hsZ3v/VpguoRK9JLsLMREScVpezJpGXA7rAMcrn9g
|
|||
|
||||
assertEquals(pkcs8Actual, pkcs8Expected);
|
||||
});
|
||||
|
||||
Deno.test("EC import jwk public key", function () {
|
||||
const publicKey = createPublicKey({
|
||||
key: {
|
||||
kty: "EC",
|
||||
x: "_GGuz19zab5J70zyiUK6sAM5mHqUbsY8H6U2TnVlt-k",
|
||||
y: "TcZG5efXZDIhNGDp6XuujoJqOEJU2D2ckjG9nOnSPIQ",
|
||||
crv: "P-256",
|
||||
},
|
||||
format: "jwk",
|
||||
});
|
||||
|
||||
const publicSpki = publicKey.export({ type: "spki", format: "pem" });
|
||||
const spkiExpected = `-----BEGIN PUBLIC KEY-----
|
||||
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE/GGuz19zab5J70zyiUK6sAM5mHqU
|
||||
bsY8H6U2TnVlt+lNxkbl59dkMiE0YOnpe66Ogmo4QlTYPZySMb2c6dI8hA==
|
||||
-----END PUBLIC KEY-----
|
||||
`;
|
||||
|
||||
assertEquals(publicSpki, spkiExpected);
|
||||
});
|
||||
|
||||
Deno.test("EC import jwk private key", function () {
|
||||
const privateKey = createPrivateKey({
|
||||
key: {
|
||||
kty: "EC",
|
||||
x: "_GGuz19zab5J70zyiUK6sAM5mHqUbsY8H6U2TnVlt-k",
|
||||
y: "TcZG5efXZDIhNGDp6XuujoJqOEJU2D2ckjG9nOnSPIQ",
|
||||
crv: "P-256",
|
||||
d: "Wobjne0GqlB_1NynKu19rsw7zBHa94tKcWIxwIb88m8",
|
||||
},
|
||||
format: "jwk",
|
||||
});
|
||||
|
||||
const privatePkcs8 = privateKey.export({ type: "pkcs8", format: "pem" });
|
||||
|
||||
const pkcs8Expected = `-----BEGIN PRIVATE KEY-----
|
||||
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgWobjne0GqlB/1Nyn
|
||||
Ku19rsw7zBHa94tKcWIxwIb88m+hRANCAAT8Ya7PX3NpvknvTPKJQrqwAzmYepRu
|
||||
xjwfpTZOdWW36U3GRuXn12QyITRg6el7ro6CajhCVNg9nJIxvZzp0jyE
|
||||
-----END PRIVATE KEY-----
|
||||
`;
|
||||
|
||||
assertEquals(privatePkcs8, pkcs8Expected);
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue