Skip to content

Commit

Permalink
feat(ext/crypto): initial support for p521 in generateKey and `impo…
Browse files Browse the repository at this point in the history
…rtKey` (#21815)

Part 1 of a potential 3 part series. Ref #13449 

The current implementation passes key material back and forth RustCrypto
group of crates and ring. ring does not implement p521 yet.

This PR adds support for P521 named curve in `generateKey` and
`importKey` where we use RustCrypto. Other parts should be moved over to
the RustGroup group of crates for consistency.
  • Loading branch information
littledivy authored Jan 6, 2024
1 parent 1d46ee5 commit bfd5f15
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 158 deletions.
15 changes: 15 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

39 changes: 39 additions & 0 deletions cli/tests/unit/webcrypto_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2006,3 +2006,42 @@ Deno.test(async function testHmacJwkImport() {
["sign", "verify"],
);
});

Deno.test(async function p521Import() {
const jwk = {
"crv": "P-521",
"ext": true,
"key_ops": [
"verify",
],
"kty": "EC",
"x":
"AXkSI8nfkc6bu3fifXGuKKbu08g5LKPfxUNQJJYzzPgmN8XLDzx0C9Sdeejl1XoWGrheKPHl0k4tUmHw0cdInpfj",
"y":
"AT4vjsO0bzVRlN3Wthv9DewncDXS2tlTob5QojV8WX1GzOAikRfWFEP3nspoSv88U447acZAsk5IvgGJuVjgMDlx",
};
const algorithm = { name: "ECDSA", namedCurve: "P-521" };

const key = await crypto.subtle.importKey(
"jwk",
jwk,
algorithm,
true,
["verify"],
);

assert(key instanceof CryptoKey);
});

Deno.test(async function p521Generate() {
const algorithm = { name: "ECDSA", namedCurve: "P-521" };

const key = await crypto.subtle.generateKey(
algorithm,
true,
["sign", "verify"],
);

assert(key.privateKey instanceof CryptoKey);
assert(key.publicKey instanceof CryptoKey);
});
3 changes: 1 addition & 2 deletions ext/crypto/00_crypto.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,7 @@ const {
isDataView,
} = core;

// P-521 is not yet supported.
const supportedNamedCurves = ["P-256", "P-384"];
const supportedNamedCurves = ["P-256", "P-384", "P-521"];
const recognisedUsages = [
"encrypt",
"decrypt",
Expand Down
1 change: 1 addition & 0 deletions ext/crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ num-traits = "0.2.14"
once_cell.workspace = true
p256 = { version = "0.13.2", features = ["ecdh"] }
p384 = "0.13.0"
p521 = "0.13.3"
rand.workspace = true
ring = { workspace = true, features = ["std"] }
rsa.workspace = true
Expand Down
8 changes: 7 additions & 1 deletion ext/crypto/generate_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,17 @@ fn generate_key_rsa(
Ok(private_key.as_bytes().to_vec())
}

fn generate_key_ec_p521() -> Vec<u8> {
let mut rng = OsRng;
let key = p521::SecretKey::random(&mut rng);
key.to_nonzero_scalar().to_bytes().to_vec()
}

fn generate_key_ec(named_curve: EcNamedCurve) -> Result<Vec<u8>, AnyError> {
let curve = match named_curve {
EcNamedCurve::P256 => &ring::signature::ECDSA_P256_SHA256_FIXED_SIGNING,
EcNamedCurve::P384 => &ring::signature::ECDSA_P384_SHA384_FIXED_SIGNING,
_ => return Err(not_supported_error("Unsupported named curve")),
EcNamedCurve::P521 => return Ok(generate_key_ec_p521()),
};

let rng = ring::rand::SystemRandom::new();
Expand Down
30 changes: 27 additions & 3 deletions ext/crypto/import_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,12 @@ fn import_key_ec_jwk_to_point(

p384::EncodedPoint::from_affine_coordinates(&x, &y, false).to_bytes()
}
_ => return Err(not_supported_error("Unsupported named curve")),
EcNamedCurve::P521 => {
let x = decode_b64url_to_field_bytes::<p521::NistP521>(&x)?;
let y = decode_b64url_to_field_bytes::<p521::NistP521>(&y)?;

p521::EncodedPoint::from_affine_coordinates(&x, &y, false).to_bytes()
}
};

Ok(point_bytes.to_vec())
Expand Down Expand Up @@ -629,7 +634,15 @@ fn import_key_ec(
return Err(data_error("invalid P-384 elliptic curve point"));
}
}
_ => return Err(not_supported_error("Unsupported named curve")),
EcNamedCurve::P521 => {
// 1-2.
let point = p521::EncodedPoint::from_bytes(&data)
.map_err(|_| data_error("invalid P-521 elliptic curve point"))?;
// 3.
if point.is_identity() {
return Err(data_error("invalid P-521 elliptic curve point"));
}
}
};
Ok(ImportKeyResult::Ec {
raw_data: RustRawKeyData::Public(data.to_vec().into()),
Expand Down Expand Up @@ -755,7 +768,18 @@ fn import_key_ec(

point.as_bytes().len()
}
_ => return Err(not_supported_error("Unsupported named curve")),
EcNamedCurve::P521 => {
let point =
p521::EncodedPoint::from_bytes(&*encoded_key).map_err(|_| {
data_error("invalid P-521 elliptic curve SPKI data")
})?;

if point.is_identity() {
return Err(data_error("invalid P-521 elliptic curve point"));
}

point.as_bytes().len()
}
};

if bytes_consumed != pk_info.subject_public_key.raw_bytes().len() {
Expand Down
Loading

0 comments on commit bfd5f15

Please sign in to comment.