mirror of
https://github.com/servo/servo.git
synced 2025-10-03 01:59:14 +01:00
script: Migrate digest
operation to use new normalization (#39477)
Refactoring of the algorithm normalization in #39431 introduces a new algorithm normalization procedure to replace the existing one. This patch migrates the `digest` operation from using existing `normalize_algorithm_for_digest` function to using the new `normalize_algorithm` function. Note that the custom type `DigestAlgorithm` has not yet completely removed since other operations like `get key length` (not migrated yet) depend on it. It will be removed when those operations are also migrated. A minor bug (missing a step) in `normalize_algorithm` is also fixed. Testing: Refactoring. Existing WPT tests are enough. Fixes: Part of #39368 --------- Signed-off-by: Kingsley Yung <kingsley@kkoyung.dev>
This commit is contained in:
parent
5687be385e
commit
19c498af16
1 changed files with 73 additions and 58 deletions
|
@ -16,7 +16,7 @@ use aes::cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit, StreamCipher};
|
||||||
use aes::{Aes128, Aes192, Aes256};
|
use aes::{Aes128, Aes192, Aes256};
|
||||||
use aes_gcm::{AeadInPlace, AesGcm, KeyInit};
|
use aes_gcm::{AeadInPlace, AesGcm, KeyInit};
|
||||||
use aes_kw::{KekAes128, KekAes192, KekAes256};
|
use aes_kw::{KekAes128, KekAes192, KekAes256};
|
||||||
use aws_lc_rs::{digest, hkdf, hmac, pbkdf2};
|
use aws_lc_rs::{hkdf, hmac, pbkdf2};
|
||||||
use base64::prelude::*;
|
use base64::prelude::*;
|
||||||
use cipher::consts::{U12, U16, U32};
|
use cipher::consts::{U12, U16, U32};
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
|
@ -73,7 +73,6 @@ const ALG_RSA_PSS: &str = "RSA-PSS";
|
||||||
const ALG_ECDH: &str = "ECDH";
|
const ALG_ECDH: &str = "ECDH";
|
||||||
const ALG_ECDSA: &str = "ECDSA";
|
const ALG_ECDSA: &str = "ECDSA";
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
static SUPPORTED_ALGORITHMS: &[&str] = &[
|
static SUPPORTED_ALGORITHMS: &[&str] = &[
|
||||||
ALG_AES_CBC,
|
ALG_AES_CBC,
|
||||||
ALG_AES_CTR,
|
ALG_AES_CTR,
|
||||||
|
@ -100,7 +99,7 @@ const NAMED_CURVE_P521: &str = "P-521";
|
||||||
static SUPPORTED_CURVES: &[&str] = &[NAMED_CURVE_P256, NAMED_CURVE_P384, NAMED_CURVE_P521];
|
static SUPPORTED_CURVES: &[&str] = &[NAMED_CURVE_P256, NAMED_CURVE_P384, NAMED_CURVE_P521];
|
||||||
|
|
||||||
/// <https://w3c.github.io/webcrypto/#supported-operation>
|
/// <https://w3c.github.io/webcrypto/#supported-operation>
|
||||||
#[allow(unused)]
|
#[allow(dead_code)]
|
||||||
enum Operation {
|
enum Operation {
|
||||||
Encrypt,
|
Encrypt,
|
||||||
Decrypt,
|
Decrypt,
|
||||||
|
@ -154,30 +153,51 @@ impl SubtleCrypto {
|
||||||
reflect_dom_object(Box::new(SubtleCrypto::new_inherited()), global, can_gc)
|
reflect_dom_object(Box::new(SubtleCrypto::new_inherited()), global, can_gc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Queue a global task on the crypto task source, given realm's global object, to resolve
|
||||||
|
/// promise with the result of creating an ArrayBuffer in realm, containing data. If it fails
|
||||||
|
/// to create buffer source, reject promise with a JSFailedError.
|
||||||
|
fn resolve_promise_with_data(&self, promise: Rc<Promise>, data: Vec<u8>) {
|
||||||
|
let trusted_promise = TrustedPromise::new(promise);
|
||||||
|
self.global().task_manager().crypto_task_source().queue(
|
||||||
|
task!(resolve_data: move || {
|
||||||
|
let promise = trusted_promise.root();
|
||||||
|
|
||||||
|
let cx = GlobalScope::get_cx();
|
||||||
|
rooted!(in(*cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>());
|
||||||
|
match create_buffer_source::<ArrayBufferU8>(cx, &data, array_buffer_ptr.handle_mut(), CanGc::note()) {
|
||||||
|
Ok(_) => promise.resolve_native(&*array_buffer_ptr, CanGc::note()),
|
||||||
|
Err(_) => promise.reject_error(Error::JSFailed, CanGc::note()),
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// Queue a global task on the crypto task source, given realm's global object, to resolve
|
/// Queue a global task on the crypto task source, given realm's global object, to resolve
|
||||||
/// promise with a CryptoKey.
|
/// promise with a CryptoKey.
|
||||||
fn resolve_promise_with_key(&self, promise: Rc<Promise>, key: DomRoot<CryptoKey>) {
|
fn resolve_promise_with_key(&self, promise: Rc<Promise>, key: DomRoot<CryptoKey>) {
|
||||||
let trusted_key = Trusted::new(&*key);
|
let trusted_key = Trusted::new(&*key);
|
||||||
let trusted_promise = TrustedPromise::new(promise);
|
let trusted_promise = TrustedPromise::new(promise);
|
||||||
self.global().task_manager().crypto_task_source().queue(
|
self.global()
|
||||||
task!(generate_key_result: move || {
|
.task_manager()
|
||||||
|
.crypto_task_source()
|
||||||
|
.queue(task!(resolve_key: move || {
|
||||||
let key = trusted_key.root();
|
let key = trusted_key.root();
|
||||||
let promise = trusted_promise.root();
|
let promise = trusted_promise.root();
|
||||||
promise.resolve_native(&key, CanGc::note());
|
promise.resolve_native(&key, CanGc::note());
|
||||||
}),
|
}));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Queue a global task on the crypto task source, given realm's global object, to reject
|
/// Queue a global task on the crypto task source, given realm's global object, to reject
|
||||||
/// promise with an error.
|
/// promise with an error.
|
||||||
fn reject_promise_with_error(&self, promise: Rc<Promise>, error: Error) {
|
fn reject_promise_with_error(&self, promise: Rc<Promise>, error: Error) {
|
||||||
let trusted_promise = TrustedPromise::new(promise);
|
let trusted_promise = TrustedPromise::new(promise);
|
||||||
self.global().task_manager().crypto_task_source().queue(
|
self.global()
|
||||||
task!(generate_key_result: move || {
|
.task_manager()
|
||||||
|
.crypto_task_source()
|
||||||
|
.queue(task!(reject_error: move || {
|
||||||
let promise = trusted_promise.root();
|
let promise = trusted_promise.root();
|
||||||
promise.reject_error(error, CanGc::note());
|
promise.reject_error(error, CanGc::note());
|
||||||
}),
|
}));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,6 +507,7 @@ impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
|
||||||
can_gc: CanGc,
|
can_gc: CanGc,
|
||||||
) -> Rc<Promise> {
|
) -> Rc<Promise> {
|
||||||
// Step 1. Let algorithm be the algorithm parameter passed to the digest() method.
|
// Step 1. Let algorithm be the algorithm parameter passed to the digest() method.
|
||||||
|
// NOTE: We did that in method parameter.
|
||||||
|
|
||||||
// Step 2. Let data be the result of getting a copy of the bytes held by the
|
// Step 2. Let data be the result of getting a copy of the bytes held by the
|
||||||
// data parameter passed to the digest() method.
|
// data parameter passed to the digest() method.
|
||||||
|
@ -497,49 +518,52 @@ impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
|
||||||
|
|
||||||
// Step 3. Let normalizedAlgorithm be the result of normalizing an algorithm,
|
// Step 3. Let normalizedAlgorithm be the result of normalizing an algorithm,
|
||||||
// with alg set to algorithm and op set to "digest".
|
// with alg set to algorithm and op set to "digest".
|
||||||
let promise = Promise::new_in_current_realm(comp, can_gc);
|
|
||||||
let normalized_algorithm = match normalize_algorithm_for_digest(cx, &algorithm, can_gc) {
|
|
||||||
Ok(normalized_algorithm) => normalized_algorithm,
|
|
||||||
Err(e) => {
|
|
||||||
// Step 4. If an error occurred, return a Promise rejected with normalizedAlgorithm.
|
// Step 4. If an error occurred, return a Promise rejected with normalizedAlgorithm.
|
||||||
promise.reject_error(e, can_gc);
|
let promise = Promise::new_in_current_realm(comp, can_gc);
|
||||||
|
let normalized_algorithm =
|
||||||
|
match normalize_algorithm(cx, &Operation::Digest, &algorithm, can_gc) {
|
||||||
|
Ok(normalized_algorithm) => normalized_algorithm,
|
||||||
|
Err(error) => {
|
||||||
|
promise.reject_error(error, can_gc);
|
||||||
return promise;
|
return promise;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Step 5. Let promise be a new Promise.
|
// Step 5. Let realm be the relevant realm of this.
|
||||||
// NOTE: We did that in preparation of Step 4.
|
// Step 6. Let promise be a new Promise.
|
||||||
|
// NOTE: We did that in preparation of Step 3.
|
||||||
|
|
||||||
// Step 6. Return promise and perform the remaining steps in parallel.
|
// Step 7. Return promise and perform the remaining steps in parallel.
|
||||||
|
let this = Trusted::new(self);
|
||||||
let trusted_promise = TrustedPromise::new(promise.clone());
|
let trusted_promise = TrustedPromise::new(promise.clone());
|
||||||
|
self.global()
|
||||||
self.global().task_manager().dom_manipulation_task_source().queue(
|
.task_manager()
|
||||||
task!(generate_key: move || {
|
.dom_manipulation_task_source()
|
||||||
// Step 7. If the following steps or referenced procedures say to throw an error, reject promise
|
.queue(task!(generate_key: move || {
|
||||||
// with the returned error and then terminate the algorithm.
|
let subtle = this.root();
|
||||||
let promise = trusted_promise.root();
|
let promise = trusted_promise.root();
|
||||||
|
|
||||||
// Step 8. Let result be the result of performing the digest operation specified by
|
// Step 8. If the following steps or referenced procedures say to throw an error,
|
||||||
|
// queue a global task on the crypto task source, given realm's global object, to
|
||||||
|
// reject promise with the returned error; and then terminate the algorithm.
|
||||||
|
|
||||||
|
// Step 9. Let digest be the result of performing the digest operation specified by
|
||||||
// normalizedAlgorithm using algorithm, with data as message.
|
// normalizedAlgorithm using algorithm, with data as message.
|
||||||
let digest = match normalized_algorithm.digest(&data) {
|
let digest = match normalized_algorithm.digest(&data) {
|
||||||
Ok(digest) => digest,
|
Ok(digest) => digest,
|
||||||
Err(e) => {
|
Err(error) => {
|
||||||
promise.reject_error(e, CanGc::note());
|
subtle.reject_promise_with_error(promise, error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let cx = GlobalScope::get_cx();
|
// Step 10. Queue a global task on the crypto task source, given realm's global
|
||||||
rooted!(in(*cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>());
|
// object, to perform the remaining steps.
|
||||||
create_buffer_source::<ArrayBufferU8>(cx, digest.as_ref(), array_buffer_ptr.handle_mut(), CanGc::note())
|
// Step 11. Let result be the result of creating an ArrayBuffer in realm,
|
||||||
.expect("failed to create buffer source for exported key.");
|
// containing digest.
|
||||||
|
// Step 12. Resolve promise with result.
|
||||||
|
subtle.resolve_promise_with_data(promise, digest);
|
||||||
// Step 9. Resolve promise with result.
|
}));
|
||||||
promise.resolve_native(&*array_buffer_ptr, CanGc::note());
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
promise
|
promise
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3438,16 +3462,6 @@ impl DigestAlgorithm {
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn digest(&self, data: &[u8]) -> Result<impl AsRef<[u8]>, Error> {
|
|
||||||
let algorithm = match self {
|
|
||||||
Self::Sha1 => &digest::SHA1_FOR_LEGACY_USE_ONLY,
|
|
||||||
Self::Sha256 => &digest::SHA256,
|
|
||||||
Self::Sha384 => &digest::SHA384,
|
|
||||||
Self::Sha512 => &digest::SHA512,
|
|
||||||
};
|
|
||||||
Ok(digest::digest(algorithm, data))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn block_size_in_bits(&self) -> usize {
|
fn block_size_in_bits(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
Self::Sha1 => 160,
|
Self::Sha1 => 160,
|
||||||
|
@ -3842,14 +3856,12 @@ impl JsonWebKeyExt for JsonWebKey {
|
||||||
/// binding of) IDL dictionary types.
|
/// binding of) IDL dictionary types.
|
||||||
///
|
///
|
||||||
/// <https://w3c.github.io/webcrypto/#algorithm-normalization-normalize-an-algorithm>
|
/// <https://w3c.github.io/webcrypto/#algorithm-normalization-normalize-an-algorithm>
|
||||||
#[allow(unused)]
|
|
||||||
enum NormalizedAlgorithm {
|
enum NormalizedAlgorithm {
|
||||||
Algorithm(SubtleAlgorithm),
|
Algorithm(SubtleAlgorithm),
|
||||||
AesCtrParams(SubtleAesCtrParams),
|
AesCtrParams(SubtleAesCtrParams),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <https://w3c.github.io/webcrypto/#algorithm-normalization-normalize-an-algorithm>
|
/// <https://w3c.github.io/webcrypto/#algorithm-normalization-normalize-an-algorithm>
|
||||||
#[allow(unused)]
|
|
||||||
fn normalize_algorithm(
|
fn normalize_algorithm(
|
||||||
cx: JSContext,
|
cx: JSContext,
|
||||||
op: &Operation,
|
op: &Operation,
|
||||||
|
@ -3939,19 +3951,23 @@ fn normalize_algorithm(
|
||||||
|
|
||||||
// <https://w3c.github.io/webcrypto/#sha-registration>
|
// <https://w3c.github.io/webcrypto/#sha-registration>
|
||||||
(ALG_SHA1, Operation::Digest) => {
|
(ALG_SHA1, Operation::Digest) => {
|
||||||
let params = value_from_js_object::<Algorithm>(cx, value.handle(), can_gc)?;
|
let mut params = value_from_js_object::<Algorithm>(cx, value.handle(), can_gc)?;
|
||||||
|
params.name = DOMString::from(alg_name);
|
||||||
NormalizedAlgorithm::Algorithm(params.into())
|
NormalizedAlgorithm::Algorithm(params.into())
|
||||||
},
|
},
|
||||||
(ALG_SHA256, Operation::Digest) => {
|
(ALG_SHA256, Operation::Digest) => {
|
||||||
let params = value_from_js_object::<Algorithm>(cx, value.handle(), can_gc)?;
|
let mut params = value_from_js_object::<Algorithm>(cx, value.handle(), can_gc)?;
|
||||||
|
params.name = DOMString::from(alg_name);
|
||||||
NormalizedAlgorithm::Algorithm(params.into())
|
NormalizedAlgorithm::Algorithm(params.into())
|
||||||
},
|
},
|
||||||
(ALG_SHA384, Operation::Digest) => {
|
(ALG_SHA384, Operation::Digest) => {
|
||||||
let params = value_from_js_object::<Algorithm>(cx, value.handle(), can_gc)?;
|
let mut params = value_from_js_object::<Algorithm>(cx, value.handle(), can_gc)?;
|
||||||
|
params.name = DOMString::from(alg_name);
|
||||||
NormalizedAlgorithm::Algorithm(params.into())
|
NormalizedAlgorithm::Algorithm(params.into())
|
||||||
},
|
},
|
||||||
(ALG_SHA512, Operation::Digest) => {
|
(ALG_SHA512, Operation::Digest) => {
|
||||||
let params = value_from_js_object::<Algorithm>(cx, value.handle(), can_gc)?;
|
let mut params = value_from_js_object::<Algorithm>(cx, value.handle(), can_gc)?;
|
||||||
|
params.name = DOMString::from(alg_name);
|
||||||
NormalizedAlgorithm::Algorithm(params.into())
|
NormalizedAlgorithm::Algorithm(params.into())
|
||||||
},
|
},
|
||||||
_ => return Err(Error::NotSupported),
|
_ => return Err(Error::NotSupported),
|
||||||
|
@ -3979,7 +3995,6 @@ impl NormalizedAlgorithm {
|
||||||
// sign
|
// sign
|
||||||
// verify
|
// verify
|
||||||
|
|
||||||
#[allow(unused)]
|
|
||||||
fn digest(&self, message: &[u8]) -> Result<Vec<u8>, Error> {
|
fn digest(&self, message: &[u8]) -> Result<Vec<u8>, Error> {
|
||||||
match self {
|
match self {
|
||||||
NormalizedAlgorithm::Algorithm(algo) => match algo.name.as_str() {
|
NormalizedAlgorithm::Algorithm(algo) => match algo.name.as_str() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue