1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-31 11:34:15 -05:00

feat(ext/crypto): verify ECDSA signatures (#11739)

This commit is contained in:
Divy Srivastava 2021-09-12 02:19:53 +05:30 committed by GitHub
parent d236f432b8
commit 40c63d1255
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 98 additions and 2 deletions

View file

@ -189,7 +189,7 @@ unitTest(async function testGenerateHMACKey() {
assert(key.usages.includes("sign"));
});
unitTest(async function testSignECDSA() {
unitTest(async function testECDSASignVerify() {
const key = await window.crypto.subtle.generateKey(
{
name: "ECDSA",
@ -208,6 +208,56 @@ unitTest(async function testSignECDSA() {
);
assert(signature);
assert(signature instanceof ArrayBuffer);
const verified = await window.crypto.subtle.verify(
{ hash: { name: "SHA-384" }, name: "ECDSA" },
key.publicKey,
signature,
encoded,
);
assert(verified);
});
// Tests the "bad paths" as a temporary replacement for sign_verify/ecdsa WPT.
unitTest(async function testECDSASignVerifyFail() {
const key = await window.crypto.subtle.generateKey(
{
name: "ECDSA",
namedCurve: "P-384",
},
true,
["sign", "verify"],
);
const encoded = new Uint8Array([1]);
// Signing with a public key (InvalidAccessError)
await assertThrowsAsync(async () => {
await window.crypto.subtle.sign(
{ name: "ECDSA", hash: "SHA-384" },
key.publicKey,
new Uint8Array([1]),
);
throw new TypeError("unreachable");
}, DOMException);
// Do a valid sign for later verifying.
const signature = await window.crypto.subtle.sign(
{ name: "ECDSA", hash: "SHA-384" },
key.privateKey,
encoded,
);
// Verifying with a private key (InvalidAccessError)
await assertThrowsAsync(async () => {
await window.crypto.subtle.verify(
{ hash: { name: "SHA-384" }, name: "ECDSA" },
key.privateKey,
signature,
encoded,
);
throw new TypeError("unreachable");
}, DOMException);
});
// https://github.com/denoland/deno/issues/11313

View file

@ -92,6 +92,7 @@
"verify": {
"RSASSA-PKCS1-v1_5": null,
"RSA-PSS": "RsaPssParams",
"ECDSA": "EcdsaParams",
"HMAC": null,
},
"importKey": {
@ -1185,6 +1186,25 @@
signature,
}, data);
}
case "ECDSA": {
// 1.
if (key[_type] !== "public") {
throw new DOMException(
"Key type not supported",
"InvalidAccessError",
);
}
// 2.
const hash = normalizedAlgorithm.hash.name;
// 3-8.
return await core.opAsync("op_crypto_verify_key", {
key: keyData,
algorithm: "ECDSA",
hash,
signature,
namedCurve: key[_algorithm].namedCurve,
}, data);
}
}
throw new TypeError("unreachable");

View file

@ -4,6 +4,7 @@ use ring::agreement::Algorithm as RingAlgorithm;
use ring::digest;
use ring::hmac::Algorithm as HmacAlgorithm;
use ring::signature::EcdsaSigningAlgorithm;
use ring::signature::EcdsaVerificationAlgorithm;
use serde::Deserialize;
use serde::Serialize;
@ -57,6 +58,15 @@ impl From<CryptoNamedCurve> for &EcdsaSigningAlgorithm {
}
}
impl From<CryptoNamedCurve> for &EcdsaVerificationAlgorithm {
fn from(curve: CryptoNamedCurve) -> &'static EcdsaVerificationAlgorithm {
match curve {
CryptoNamedCurve::P256 => &ring::signature::ECDSA_P256_SHA256_FIXED,
CryptoNamedCurve::P384 => &ring::signature::ECDSA_P384_SHA384_FIXED,
}
}
}
impl From<CryptoHash> for HmacAlgorithm {
fn from(hash: CryptoHash) -> HmacAlgorithm {
match hash {

View file

@ -175,7 +175,7 @@ interface SubtleCrypto {
data: BufferSource,
): Promise<ArrayBuffer>;
verify(
algorithm: AlgorithmIdentifier | RsaPssParams,
algorithm: AlgorithmIdentifier | RsaPssParams | EcdsaParams,
key: CryptoKey,
signature: BufferSource,
data: BufferSource,

View file

@ -33,6 +33,8 @@ use ring::rand as RingRand;
use ring::rand::SecureRandom;
use ring::signature::EcdsaKeyPair;
use ring::signature::EcdsaSigningAlgorithm;
use ring::signature::EcdsaVerificationAlgorithm;
use ring::signature::KeyPair;
use rsa::padding::PaddingScheme;
use rsa::pkcs8::FromPrivateKey;
use rsa::pkcs8::ToPrivateKey;
@ -407,6 +409,7 @@ pub struct VerifyArg {
salt_length: Option<u32>,
hash: Option<CryptoHash>,
signature: ZeroCopyBuf,
named_curve: Option<CryptoNamedCurve>,
}
pub async fn op_crypto_verify_key(
@ -528,6 +531,19 @@ pub async fn op_crypto_verify_key(
let key = HmacKey::new(hash, &*args.key.data);
ring::hmac::verify(&key, data, &*args.signature).is_ok()
}
Algorithm::Ecdsa => {
let signing_alg: &EcdsaSigningAlgorithm =
args.named_curve.ok_or_else(not_supported)?.try_into()?;
let verify_alg: &EcdsaVerificationAlgorithm =
args.named_curve.ok_or_else(not_supported)?.try_into()?;
let private_key = EcdsaKeyPair::from_pkcs8(signing_alg, &*args.key.data)?;
let public_key_bytes = private_key.public_key().as_ref();
let public_key =
ring::signature::UnparsedPublicKey::new(verify_alg, public_key_bytes);
public_key.verify(data, &*args.signature).is_ok()
}
_ => return Err(type_error("Unsupported algorithm".to_string())),
};