diff options
author | Simon Wülker <simon.wuelker@arcor.de> | 2024-10-30 03:06:02 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-10-30 02:06:02 +0000 |
commit | 7fa548f555310cf4e60ad054f6577fabf57938e0 (patch) | |
tree | a2c69d16864d65ada6c599e55ee739a5aa7101b0 /components | |
parent | 01820e2a8a28bcf3b8e1b17863984d8f729ca79b (diff) | |
download | servo-7fa548f555310cf4e60ad054f6577fabf57938e0.tar.gz servo-7fa548f555310cf4e60ad054f6577fabf57938e0.zip |
Implement `SubtleCrypto.digest` (#34034)
* Implement SubtleCrypto.digest
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
* Update WPT expectations
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
---------
Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
Diffstat (limited to 'components')
-rw-r--r-- | components/script/Cargo.toml | 1 | ||||
-rw-r--r-- | components/script/dom/bindings/codegen/Bindings.conf | 4 | ||||
-rw-r--r-- | components/script/dom/subtlecrypto.rs | 110 | ||||
-rw-r--r-- | components/script/dom/webidls/SubtleCrypto.webidl | 4 |
4 files changed, 106 insertions, 13 deletions
diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml index 7e64b1d6449..d663f62c415 100644 --- a/components/script/Cargo.toml +++ b/components/script/Cargo.toml @@ -89,6 +89,7 @@ profile_traits = { workspace = true } range = { path = "../range" } ref_filter_map = "1.0.1" regex = { workspace = true } +ring = { workspace = true } script_layout_interface = { workspace = true } script_traits = { workspace = true } selectors = { workspace = true } diff --git a/components/script/dom/bindings/codegen/Bindings.conf b/components/script/dom/bindings/codegen/Bindings.conf index 1ea05480b88..c304d1180db 100644 --- a/components/script/dom/bindings/codegen/Bindings.conf +++ b/components/script/dom/bindings/codegen/Bindings.conf @@ -433,8 +433,8 @@ DOMInterfaces = { }, 'SubtleCrypto': { - 'inRealms': ['Encrypt', 'Decrypt', 'GenerateKey', 'ImportKey', 'ExportKey'], - 'canGc': ['Encrypt', 'Decrypt', 'GenerateKey', 'ImportKey', 'ExportKey'], + 'inRealms': ['Encrypt', 'Decrypt', 'GenerateKey', 'Digest', 'ImportKey', 'ExportKey'], + 'canGc': ['Encrypt', 'Decrypt', 'GenerateKey', 'Digest', 'ImportKey', 'ExportKey'], }, 'SVGElement': { diff --git a/components/script/dom/subtlecrypto.rs b/components/script/dom/subtlecrypto.rs index cc852a31276..63088b8c7af 100644 --- a/components/script/dom/subtlecrypto.rs +++ b/components/script/dom/subtlecrypto.rs @@ -16,6 +16,7 @@ use js::jsapi::JSObject; use js::jsval::ObjectValue; use js::rust::MutableHandleObject; use js::typedarray::ArrayBufferU8; +use ring::digest; use servo_rand::{RngCore, ServoRng}; use crate::dom::bindings::buffer_source::create_buffer_source; @@ -31,6 +32,7 @@ use crate::dom::bindings::codegen::UnionTypes::{ ArrayBufferViewOrArrayBuffer, ArrayBufferViewOrArrayBufferOrJsonWebKey, }; use crate::dom::bindings::error::Error; +use crate::dom::bindings::import::module::SafeJSContext; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::refcounted::{Trusted, TrustedPromise}; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; @@ -53,10 +55,10 @@ const ALG_AES_CBC: &str = "AES-CBC"; const ALG_AES_CTR: &str = "AES-CTR"; const ALG_AES_GCM: &str = "AES-GCM"; const ALG_AES_KW: &str = "AES-KW"; -const ALG_SHA1: &str = "SHA1"; -const ALG_SHA256: &str = "SHA256"; -const ALG_SHA384: &str = "SHA384"; -const ALG_SHA512: &str = "SHA512"; +const ALG_SHA1: &str = "SHA-1"; +const ALG_SHA256: &str = "SHA-256"; +const ALG_SHA384: &str = "SHA-384"; +const ALG_SHA512: &str = "SHA-512"; const ALG_HMAC: &str = "HMAC"; const ALG_HKDF: &str = "HKDF"; const ALG_PBKDF2: &str = "PBKDF2"; @@ -65,6 +67,7 @@ const ALG_RSA_OAEP: &str = "RSA-OAEP"; const ALG_RSA_PSS: &str = "RSA-PSS"; const ALG_ECDH: &str = "ECDH"; const ALG_ECDSA: &str = "ECDSA"; + #[allow(dead_code)] static SUPPORTED_ALGORITHMS: &[&str] = &[ ALG_AES_CBC, @@ -274,6 +277,79 @@ impl SubtleCryptoMethods for SubtleCrypto { promise } + /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-digest> + fn Digest( + &self, + cx: SafeJSContext, + algorithm: AlgorithmIdentifier, + data: ArrayBufferViewOrArrayBuffer, + comp: InRealm, + can_gc: CanGc, + ) -> Rc<Promise> { + // Step 1. Let algorithm be the algorithm parameter passed to the digest() method. + // NOTE I think this is a no-op? + + // Step 2. Let data be the result of getting a copy of the bytes held by the + // data parameter passed to the digest() method. + let data = match data { + ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(), + ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(), + }; + + // Step 3. Let normalizedAlgorithm be the result of normalizing an algorithm, + // 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(cx, algorithm, "digest") { + Ok(normalized_algorithm) => normalized_algorithm, + Err(e) => { + // Step 4. If an error occurred, return a Promise rejected with normalizedAlgorithm. + promise.reject_error(e); + return promise; + }, + }; + + // Step 5. Let promise be a new Promise. + // NOTE: We did that in preparation of Step 4. + + // Step 6. Return promise and perform the remaining steps in parallel. + let (task_source, canceller) = self.task_source_with_canceller(); + let trusted_promise = TrustedPromise::new(promise.clone()); + let alg = normalized_algorithm.clone(); + + let _ = task_source.queue_with_canceller( + task!(generate_key: move || { + // Step 7. If the following steps or referenced procedures say to throw an error, reject promise + // with the returned error and then terminate the algorithm. + let promise = trusted_promise.root(); + + // Step 8. Let result be the result of performing the digest operation specified by + // normalizedAlgorithm using algorithm, with data as message. + let algorithm = match alg { + NormalizedAlgorithm::Sha1 => &digest::SHA1_FOR_LEGACY_USE_ONLY, + NormalizedAlgorithm::Sha256 => &digest::SHA256, + NormalizedAlgorithm::Sha384 => &digest::SHA384, + NormalizedAlgorithm::Sha512 => &digest::SHA512, + _ => { + promise.reject_error(Error::NotSupported); + return; + }, + }; + let cx = GlobalScope::get_cx(); + rooted!(in(*cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>()); + let digest = digest::digest(algorithm, &data); + create_buffer_source::<ArrayBufferU8>(cx, digest.as_ref(), array_buffer_ptr.handle_mut()) + .expect("failed to create buffer source for exported key."); + + + // Step 9. Resolve promise with result. + promise.resolve_native(&*array_buffer_ptr); + }), + &canceller, + ); + + promise + } + /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-generateKey> fn GenerateKey( &self, @@ -450,19 +526,31 @@ impl SubtleCryptoMethods for SubtleCrypto { } } -#[derive(Clone)] +#[derive(Clone, Debug)] pub enum NormalizedAlgorithm { #[allow(dead_code)] Algorithm(SubtleAlgorithm), AesCbcParams(SubtleAesCbcParams), AesCtrParams(SubtleAesCtrParams), AesKeyGenParams(SubtleAesKeyGenParams), + + /// <https://w3c.github.io/webcrypto/#sha> + Sha1, + + /// <https://w3c.github.io/webcrypto/#sha> + Sha256, + + /// <https://w3c.github.io/webcrypto/#sha> + Sha384, + + /// <https://w3c.github.io/webcrypto/#sha> + Sha512, } // These "subtle" structs are proxies for the codegen'd dicts which don't hold a DOMString // so they can be sent safely when running steps in parallel. -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct SubtleAlgorithm { #[allow(dead_code)] pub name: String, @@ -476,7 +564,7 @@ impl From<DOMString> for SubtleAlgorithm { } } -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct SubtleAesCbcParams { #[allow(dead_code)] pub name: String, @@ -496,7 +584,7 @@ impl From<RootedTraceableBox<AesCbcParams>> for SubtleAesCbcParams { } } -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct SubtleAesCtrParams { pub name: String, pub counter: Vec<u8>, @@ -517,7 +605,7 @@ impl From<RootedTraceableBox<AesCtrParams>> for SubtleAesCtrParams { } } -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct SubtleAesKeyGenParams { pub name: String, pub length: u16, @@ -578,6 +666,10 @@ fn normalize_algorithm( (ALG_AES_CTR, "importKey") => Ok(NormalizedAlgorithm::Algorithm(SubtleAlgorithm { name: ALG_AES_CTR.to_string(), })), + (ALG_SHA1, "digest") => Ok(NormalizedAlgorithm::Sha1), + (ALG_SHA256, "digest") => Ok(NormalizedAlgorithm::Sha256), + (ALG_SHA384, "digest") => Ok(NormalizedAlgorithm::Sha384), + (ALG_SHA512, "digest") => Ok(NormalizedAlgorithm::Sha512), _ => Err(Error::NotSupported), } }, diff --git a/components/script/dom/webidls/SubtleCrypto.webidl b/components/script/dom/webidls/SubtleCrypto.webidl index 1842380c484..073dff346a9 100644 --- a/components/script/dom/webidls/SubtleCrypto.webidl +++ b/components/script/dom/webidls/SubtleCrypto.webidl @@ -33,8 +33,8 @@ interface SubtleCrypto { // CryptoKey key, // BufferSource signature, // BufferSource data); - // Promise<any> digest(AlgorithmIdentifier algorithm, - // BufferSource data); + Promise<any> digest(AlgorithmIdentifier algorithm, + BufferSource data); Promise<any> generateKey(AlgorithmIdentifier algorithm, boolean extractable, |