diff options
-rw-r--r-- | Cargo.lock | 1 | ||||
-rw-r--r-- | Cargo.toml | 1 | ||||
-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 | ||||
-rw-r--r-- | tests/wpt/meta/WebCryptoAPI/algorithm-discards-context.https.window.js.ini | 3 | ||||
-rw-r--r-- | tests/wpt/meta/WebCryptoAPI/digest/digest.https.any.js.ini | 482 | ||||
-rw-r--r-- | tests/wpt/meta/WebCryptoAPI/idlharness.https.any.js.ini | 18 |
9 files changed, 108 insertions, 516 deletions
diff --git a/Cargo.lock b/Cargo.lock index 59c51fc115a..060343ecebd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6120,6 +6120,7 @@ dependencies = [ "range", "ref_filter_map", "regex", + "ring", "script_layout_interface", "script_traits", "selectors", diff --git a/Cargo.toml b/Cargo.toml index f712e394ab2..ca1a6002012 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -100,6 +100,7 @@ rand_core = "0.6" rand_isaac = "0.3" rayon = "1" regex = "1.11" +ring = "0.17.8" rustls = { version = "0.21.12", features = ["dangerous_configuration"] } rustls-pemfile = "1.0.4" script_layout_interface = { path = "components/shared/script_layout" } 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, diff --git a/tests/wpt/meta/WebCryptoAPI/algorithm-discards-context.https.window.js.ini b/tests/wpt/meta/WebCryptoAPI/algorithm-discards-context.https.window.js.ini index dbc41bb26ca..d144503a7d2 100644 --- a/tests/wpt/meta/WebCryptoAPI/algorithm-discards-context.https.window.js.ini +++ b/tests/wpt/meta/WebCryptoAPI/algorithm-discards-context.https.window.js.ini @@ -6,9 +6,6 @@ [Context is discarded in decrypt] expected: TIMEOUT - [Context is discarded in digest] - expected: TIMEOUT - [Context is discarded in sign] expected: TIMEOUT diff --git a/tests/wpt/meta/WebCryptoAPI/digest/digest.https.any.js.ini b/tests/wpt/meta/WebCryptoAPI/digest/digest.https.any.js.ini deleted file mode 100644 index 15e0258b42b..00000000000 --- a/tests/wpt/meta/WebCryptoAPI/digest/digest.https.any.js.ini +++ /dev/null @@ -1,482 +0,0 @@ -[digest.https.any.worker.html] - [SHA-1 with empty source data] - expected: FAIL - - [sha-1 with empty source data] - expected: FAIL - - [Sha-1 with empty source data] - expected: FAIL - - [SHA-1 with empty source data and altered buffer after call] - expected: FAIL - - [SHA-256 with empty source data] - expected: FAIL - - [sha-256 with empty source data] - expected: FAIL - - [Sha-256 with empty source data] - expected: FAIL - - [SHA-256 with empty source data and altered buffer after call] - expected: FAIL - - [SHA-384 with empty source data] - expected: FAIL - - [sha-384 with empty source data] - expected: FAIL - - [Sha-384 with empty source data] - expected: FAIL - - [SHA-384 with empty source data and altered buffer after call] - expected: FAIL - - [SHA-512 with empty source data] - expected: FAIL - - [sha-512 with empty source data] - expected: FAIL - - [Sha-512 with empty source data] - expected: FAIL - - [SHA-512 with empty source data and altered buffer after call] - expected: FAIL - - [SHA-1 with short source data] - expected: FAIL - - [sha-1 with short source data] - expected: FAIL - - [Sha-1 with short source data] - expected: FAIL - - [SHA-1 with short source data and altered buffer after call] - expected: FAIL - - [SHA-256 with short source data] - expected: FAIL - - [sha-256 with short source data] - expected: FAIL - - [Sha-256 with short source data] - expected: FAIL - - [SHA-256 with short source data and altered buffer after call] - expected: FAIL - - [SHA-384 with short source data] - expected: FAIL - - [sha-384 with short source data] - expected: FAIL - - [Sha-384 with short source data] - expected: FAIL - - [SHA-384 with short source data and altered buffer after call] - expected: FAIL - - [SHA-512 with short source data] - expected: FAIL - - [sha-512 with short source data] - expected: FAIL - - [Sha-512 with short source data] - expected: FAIL - - [SHA-512 with short source data and altered buffer after call] - expected: FAIL - - [SHA-1 with medium source data] - expected: FAIL - - [sha-1 with medium source data] - expected: FAIL - - [Sha-1 with medium source data] - expected: FAIL - - [SHA-1 with medium source data and altered buffer after call] - expected: FAIL - - [SHA-256 with medium source data] - expected: FAIL - - [sha-256 with medium source data] - expected: FAIL - - [Sha-256 with medium source data] - expected: FAIL - - [SHA-256 with medium source data and altered buffer after call] - expected: FAIL - - [SHA-384 with medium source data] - expected: FAIL - - [sha-384 with medium source data] - expected: FAIL - - [Sha-384 with medium source data] - expected: FAIL - - [SHA-384 with medium source data and altered buffer after call] - expected: FAIL - - [SHA-512 with medium source data] - expected: FAIL - - [sha-512 with medium source data] - expected: FAIL - - [Sha-512 with medium source data] - expected: FAIL - - [SHA-512 with medium source data and altered buffer after call] - expected: FAIL - - [SHA-1 with long source data] - expected: FAIL - - [sha-1 with long source data] - expected: FAIL - - [Sha-1 with long source data] - expected: FAIL - - [SHA-1 with long source data and altered buffer after call] - expected: FAIL - - [SHA-256 with long source data] - expected: FAIL - - [sha-256 with long source data] - expected: FAIL - - [Sha-256 with long source data] - expected: FAIL - - [SHA-256 with long source data and altered buffer after call] - expected: FAIL - - [SHA-384 with long source data] - expected: FAIL - - [sha-384 with long source data] - expected: FAIL - - [Sha-384 with long source data] - expected: FAIL - - [SHA-384 with long source data and altered buffer after call] - expected: FAIL - - [SHA-512 with long source data] - expected: FAIL - - [sha-512 with long source data] - expected: FAIL - - [Sha-512 with long source data] - expected: FAIL - - [SHA-512 with long source data and altered buffer after call] - expected: FAIL - - [AES-GCM with empty] - expected: FAIL - - [RSA-OAEP with empty] - expected: FAIL - - [PBKDF2 with empty] - expected: FAIL - - [AES-KW with empty] - expected: FAIL - - [AES-GCM with short] - expected: FAIL - - [RSA-OAEP with short] - expected: FAIL - - [PBKDF2 with short] - expected: FAIL - - [AES-KW with short] - expected: FAIL - - [AES-GCM with medium] - expected: FAIL - - [RSA-OAEP with medium] - expected: FAIL - - [PBKDF2 with medium] - expected: FAIL - - [AES-KW with medium] - expected: FAIL - - [AES-GCM with long] - expected: FAIL - - [RSA-OAEP with long] - expected: FAIL - - [PBKDF2 with long] - expected: FAIL - - [AES-KW with long] - expected: FAIL - - -[digest.https.any.html] - [SHA-1 with empty source data] - expected: FAIL - - [sha-1 with empty source data] - expected: FAIL - - [Sha-1 with empty source data] - expected: FAIL - - [SHA-1 with empty source data and altered buffer after call] - expected: FAIL - - [SHA-256 with empty source data] - expected: FAIL - - [sha-256 with empty source data] - expected: FAIL - - [Sha-256 with empty source data] - expected: FAIL - - [SHA-256 with empty source data and altered buffer after call] - expected: FAIL - - [SHA-384 with empty source data] - expected: FAIL - - [sha-384 with empty source data] - expected: FAIL - - [Sha-384 with empty source data] - expected: FAIL - - [SHA-384 with empty source data and altered buffer after call] - expected: FAIL - - [SHA-512 with empty source data] - expected: FAIL - - [sha-512 with empty source data] - expected: FAIL - - [Sha-512 with empty source data] - expected: FAIL - - [SHA-512 with empty source data and altered buffer after call] - expected: FAIL - - [SHA-1 with short source data] - expected: FAIL - - [sha-1 with short source data] - expected: FAIL - - [Sha-1 with short source data] - expected: FAIL - - [SHA-1 with short source data and altered buffer after call] - expected: FAIL - - [SHA-256 with short source data] - expected: FAIL - - [sha-256 with short source data] - expected: FAIL - - [Sha-256 with short source data] - expected: FAIL - - [SHA-256 with short source data and altered buffer after call] - expected: FAIL - - [SHA-384 with short source data] - expected: FAIL - - [sha-384 with short source data] - expected: FAIL - - [Sha-384 with short source data] - expected: FAIL - - [SHA-384 with short source data and altered buffer after call] - expected: FAIL - - [SHA-512 with short source data] - expected: FAIL - - [sha-512 with short source data] - expected: FAIL - - [Sha-512 with short source data] - expected: FAIL - - [SHA-512 with short source data and altered buffer after call] - expected: FAIL - - [SHA-1 with medium source data] - expected: FAIL - - [sha-1 with medium source data] - expected: FAIL - - [Sha-1 with medium source data] - expected: FAIL - - [SHA-1 with medium source data and altered buffer after call] - expected: FAIL - - [SHA-256 with medium source data] - expected: FAIL - - [sha-256 with medium source data] - expected: FAIL - - [Sha-256 with medium source data] - expected: FAIL - - [SHA-256 with medium source data and altered buffer after call] - expected: FAIL - - [SHA-384 with medium source data] - expected: FAIL - - [sha-384 with medium source data] - expected: FAIL - - [Sha-384 with medium source data] - expected: FAIL - - [SHA-384 with medium source data and altered buffer after call] - expected: FAIL - - [SHA-512 with medium source data] - expected: FAIL - - [sha-512 with medium source data] - expected: FAIL - - [Sha-512 with medium source data] - expected: FAIL - - [SHA-512 with medium source data and altered buffer after call] - expected: FAIL - - [SHA-1 with long source data] - expected: FAIL - - [sha-1 with long source data] - expected: FAIL - - [Sha-1 with long source data] - expected: FAIL - - [SHA-1 with long source data and altered buffer after call] - expected: FAIL - - [SHA-256 with long source data] - expected: FAIL - - [sha-256 with long source data] - expected: FAIL - - [Sha-256 with long source data] - expected: FAIL - - [SHA-256 with long source data and altered buffer after call] - expected: FAIL - - [SHA-384 with long source data] - expected: FAIL - - [sha-384 with long source data] - expected: FAIL - - [Sha-384 with long source data] - expected: FAIL - - [SHA-384 with long source data and altered buffer after call] - expected: FAIL - - [SHA-512 with long source data] - expected: FAIL - - [sha-512 with long source data] - expected: FAIL - - [Sha-512 with long source data] - expected: FAIL - - [SHA-512 with long source data and altered buffer after call] - expected: FAIL - - [AES-GCM with empty] - expected: FAIL - - [RSA-OAEP with empty] - expected: FAIL - - [PBKDF2 with empty] - expected: FAIL - - [AES-KW with empty] - expected: FAIL - - [AES-GCM with short] - expected: FAIL - - [RSA-OAEP with short] - expected: FAIL - - [PBKDF2 with short] - expected: FAIL - - [AES-KW with short] - expected: FAIL - - [AES-GCM with medium] - expected: FAIL - - [RSA-OAEP with medium] - expected: FAIL - - [PBKDF2 with medium] - expected: FAIL - - [AES-KW with medium] - expected: FAIL - - [AES-GCM with long] - expected: FAIL - - [RSA-OAEP with long] - expected: FAIL - - [PBKDF2 with long] - expected: FAIL - - [AES-KW with long] - expected: FAIL diff --git a/tests/wpt/meta/WebCryptoAPI/idlharness.https.any.js.ini b/tests/wpt/meta/WebCryptoAPI/idlharness.https.any.js.ini index 58c35f4cf78..05d85614c6b 100644 --- a/tests/wpt/meta/WebCryptoAPI/idlharness.https.any.js.ini +++ b/tests/wpt/meta/WebCryptoAPI/idlharness.https.any.js.ini @@ -5,9 +5,6 @@ [SubtleCrypto interface: operation verify(AlgorithmIdentifier, CryptoKey, BufferSource, BufferSource)] expected: FAIL - [SubtleCrypto interface: operation digest(AlgorithmIdentifier, BufferSource)] - expected: FAIL - [SubtleCrypto interface: operation deriveKey(AlgorithmIdentifier, CryptoKey, AlgorithmIdentifier, boolean, sequence<KeyUsage>)] expected: FAIL @@ -32,12 +29,6 @@ [SubtleCrypto interface: calling verify(AlgorithmIdentifier, CryptoKey, BufferSource, BufferSource) on crypto.subtle with too few arguments must throw TypeError] expected: FAIL - [SubtleCrypto interface: crypto.subtle must inherit property "digest(AlgorithmIdentifier, BufferSource)" with the proper type] - expected: FAIL - - [SubtleCrypto interface: calling digest(AlgorithmIdentifier, BufferSource) on crypto.subtle with too few arguments must throw TypeError] - expected: FAIL - [SubtleCrypto interface: crypto.subtle must inherit property "deriveKey(AlgorithmIdentifier, CryptoKey, AlgorithmIdentifier, boolean, sequence<KeyUsage>)" with the proper type] expected: FAIL @@ -79,9 +70,6 @@ [SubtleCrypto interface: operation verify(AlgorithmIdentifier, CryptoKey, BufferSource, BufferSource)] expected: FAIL - [SubtleCrypto interface: operation digest(AlgorithmIdentifier, BufferSource)] - expected: FAIL - [SubtleCrypto interface: operation deriveKey(AlgorithmIdentifier, CryptoKey, AlgorithmIdentifier, boolean, sequence<KeyUsage>)] expected: FAIL @@ -106,12 +94,6 @@ [SubtleCrypto interface: calling verify(AlgorithmIdentifier, CryptoKey, BufferSource, BufferSource) on crypto.subtle with too few arguments must throw TypeError] expected: FAIL - [SubtleCrypto interface: crypto.subtle must inherit property "digest(AlgorithmIdentifier, BufferSource)" with the proper type] - expected: FAIL - - [SubtleCrypto interface: calling digest(AlgorithmIdentifier, BufferSource) on crypto.subtle with too few arguments must throw TypeError] - expected: FAIL - [SubtleCrypto interface: crypto.subtle must inherit property "deriveKey(AlgorithmIdentifier, CryptoKey, AlgorithmIdentifier, boolean, sequence<KeyUsage>)" with the proper type] expected: FAIL |