diff options
-rw-r--r-- | components/script/dom/cryptokey.rs | 73 | ||||
-rw-r--r-- | components/script/dom/subtlecrypto.rs | 69 | ||||
-rw-r--r-- | tests/wpt/meta/MANIFEST.json | 25 | ||||
-rw-r--r-- | tests/wpt/tests/WebCryptoAPI/cryptokey_algorithm_returns_cached_object.https.any.js | 24 |
4 files changed, 142 insertions, 49 deletions
diff --git a/components/script/dom/cryptokey.rs b/components/script/dom/cryptokey.rs index 88c189feb81..cf0e287e518 100644 --- a/components/script/dom/cryptokey.rs +++ b/components/script/dom/cryptokey.rs @@ -6,13 +6,12 @@ use std::cell::Cell; use std::ptr::NonNull; use dom_struct::dom_struct; -use js::jsapi::{JSObject, Value}; +use js::jsapi::{Heap, JSObject, Value}; +use js::rust::HandleObject; -use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::CryptoKeyBinding::{ CryptoKeyMethods, KeyType, KeyUsage, }; -use crate::dom::bindings::codegen::Bindings::SubtleCryptoBinding::{AesKeyAlgorithm, KeyAlgorithm}; use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::str::DOMString; @@ -22,6 +21,7 @@ use crate::script_runtime::JSContext; /// The underlying cryptographic data this key represents #[allow(dead_code)] +#[derive(MallocSizeOf)] pub enum Handle { Aes128(Vec<u8>), Aes192(Vec<u8>), @@ -32,13 +32,26 @@ pub enum Handle { #[dom_struct] pub struct CryptoKey { reflector_: Reflector, + + /// <https://w3c.github.io/webcrypto/#dom-cryptokey-type> key_type: KeyType, + + /// <https://w3c.github.io/webcrypto/#dom-cryptokey-extractable> extractable: Cell<bool>, - // This would normally be KeyAlgorithm but we cannot Send DOMString, which - // is a member of Algorithm - algorithm: DomRefCell<String>, + + /// The name of the algorithm used + /// + /// This is always the same as the `name` of the + /// [`[[algorithm]]`](https://w3c.github.io/webcrypto/#dom-cryptokey-algorithm) + /// internal slot, but we store it here again for convenience + algorithm: DOMString, + + /// <https://w3c.github.io/webcrypto/#dom-cryptokey-algorithm> + #[ignore_malloc_size_of = "Defined in mozjs"] + algorithm_object: Heap<*mut JSObject>, + + /// <https://w3c.github.io/webcrypto/#dom-cryptokey-usages> usages: Vec<KeyUsage>, - #[ignore_malloc_size_of = "Defined in external cryptography crates"] #[no_trace] handle: Handle, } @@ -47,15 +60,16 @@ impl CryptoKey { fn new_inherited( key_type: KeyType, extractable: bool, - algorithm: KeyAlgorithm, usages: Vec<KeyUsage>, + algorithm: DOMString, handle: Handle, ) -> CryptoKey { CryptoKey { reflector_: Reflector::new(), key_type, extractable: Cell::new(extractable), - algorithm: DomRefCell::new(algorithm.name.to_string()), + algorithm, + algorithm_object: Heap::default(), usages, handle, } @@ -65,24 +79,29 @@ impl CryptoKey { global: &GlobalScope, key_type: KeyType, extractable: bool, - algorithm: KeyAlgorithm, + algorithm: DOMString, + algorithm_object: HandleObject, usages: Vec<KeyUsage>, handle: Handle, ) -> DomRoot<CryptoKey> { - reflect_dom_object( + let object = reflect_dom_object( Box::new(CryptoKey::new_inherited( key_type, extractable, - algorithm, usages, + algorithm, handle, )), global, - ) + ); + + object.algorithm_object.set(algorithm_object.get()); + + object } pub fn algorithm(&self) -> String { - self.algorithm.borrow().to_string() + self.algorithm.to_string() } pub fn usages(&self) -> &[KeyUsage] { @@ -105,31 +124,9 @@ impl CryptoKeyMethods for CryptoKey { self.extractable.get() } - #[allow(unsafe_code)] /// <https://w3c.github.io/webcrypto/#cryptokey-interface-members> - fn Algorithm(&self, cx: JSContext) -> NonNull<JSObject> { - let parent = KeyAlgorithm { - name: DOMString::from_string(self.algorithm()), - }; - let algorithm = match self.handle() { - Handle::Aes128(_) => AesKeyAlgorithm { - parent, - length: 128, - }, - Handle::Aes192(_) => AesKeyAlgorithm { - parent, - length: 192, - }, - Handle::Aes256(_) => AesKeyAlgorithm { - parent, - length: 256, - }, - }; - unsafe { - rooted!(in(*cx) let mut alg: Value); - algorithm.to_jsval(*cx, alg.handle_mut()); - NonNull::new(alg.to_object()).unwrap() - } + fn Algorithm(&self, _cx: JSContext) -> NonNull<JSObject> { + NonNull::new(self.algorithm_object.get()).unwrap() } #[allow(unsafe_code)] diff --git a/components/script/dom/subtlecrypto.rs b/components/script/dom/subtlecrypto.rs index 63088b8c7af..cb86981d30d 100644 --- a/components/script/dom/subtlecrypto.rs +++ b/components/script/dom/subtlecrypto.rs @@ -12,7 +12,7 @@ use aes::{Aes128, Aes192, Aes256}; use base64::prelude::*; use dom_struct::dom_struct; use js::conversions::ConversionResult; -use js::jsapi::JSObject; +use js::jsapi::{JSObject, JS_NewObject}; use js::jsval::ObjectValue; use js::rust::MutableHandleObject; use js::typedarray::ArrayBufferU8; @@ -25,8 +25,8 @@ use crate::dom::bindings::codegen::Bindings::CryptoKeyBinding::{ CryptoKeyMethods, KeyType, KeyUsage, }; use crate::dom::bindings::codegen::Bindings::SubtleCryptoBinding::{ - AesCbcParams, AesCtrParams, AesKeyGenParams, Algorithm, AlgorithmIdentifier, JsonWebKey, - KeyAlgorithm, KeyFormat, SubtleCryptoMethods, + AesCbcParams, AesCtrParams, AesKeyAlgorithm, AesKeyGenParams, Algorithm, AlgorithmIdentifier, + JsonWebKey, KeyAlgorithm, KeyFormat, SubtleCryptoMethods, }; use crate::dom::bindings::codegen::UnionTypes::{ ArrayBufferViewOrArrayBuffer, ArrayBufferViewOrArrayBufferOrJsonWebKey, @@ -796,6 +796,7 @@ impl SubtleCrypto { /// <https://w3c.github.io/webcrypto/#aes-cbc-operations> /// <https://w3c.github.io/webcrypto/#aes-ctr-operations> + #[allow(unsafe_code)] fn generate_key_aes( &self, usages: Vec<KeyUsage>, @@ -827,25 +828,40 @@ impl SubtleCrypto { _ => return Err(Error::NotSupported), }; - Ok(CryptoKey::new( + let cx = GlobalScope::get_cx(); + rooted!(in(*cx) let mut algorithm_object = unsafe {JS_NewObject(*cx, ptr::null()) }); + assert!(!algorithm_object.is_null()); + + AesKeyAlgorithm::from_name_and_size( + name.clone(), + key_gen_params.length, + algorithm_object.handle_mut(), + cx, + ); + + let crypto_key = CryptoKey::new( &self.global(), KeyType::Secret, extractable, - KeyAlgorithm { name }, + name, + algorithm_object.handle(), usages, handle, - )) + ); + + Ok(crypto_key) } /// <https://w3c.github.io/webcrypto/#aes-cbc-operations> /// <https://w3c.github.io/webcrypto/#aes-ctr-operations> + #[allow(unsafe_code)] fn import_key_aes( &self, format: KeyFormat, data: &[u8], extractable: bool, usages: Vec<KeyUsage>, - alg: &str, + alg_name: &str, ) -> Result<DomRoot<CryptoKey>, Error> { if usages.iter().any(|usage| { !matches!( @@ -865,15 +881,30 @@ impl SubtleCrypto { 256 => Handle::Aes256(data.to_vec()), _ => return Err(Error::Data), }; - let name = DOMString::from(alg); - Ok(CryptoKey::new( + + let name = DOMString::from(alg_name.to_string()); + + let cx = GlobalScope::get_cx(); + rooted!(in(*cx) let mut algorithm_object = unsafe {JS_NewObject(*cx, ptr::null()) }); + assert!(!algorithm_object.is_null()); + + AesKeyAlgorithm::from_name_and_size( + name.clone(), + (data.len() * 8) as u16, + algorithm_object.handle_mut(), + cx, + ); + let crypto_key = CryptoKey::new( &self.global(), KeyType::Secret, extractable, - KeyAlgorithm { name }, + name, + algorithm_object.handle(), usages, handle, - )) + ); + + Ok(crypto_key) } /// <https://w3c.github.io/webcrypto/#aes-cbc-operations> @@ -939,3 +970,19 @@ fn data_to_jwk_params(alg: &str, size: &str, key: &[u8]) -> (DOMString, DOMStrin data.retain(|c| c != '='); (jwk_alg, DOMString::from(data)) } + +impl AesKeyAlgorithm { + /// Fill the object referenced by `out` with an [AesKeyAlgorithm] + /// of the specified name and size. + #[allow(unsafe_code)] + fn from_name_and_size(name: DOMString, size: u16, out: MutableHandleObject, cx: JSContext) { + let key_algorithm = Self { + parent: KeyAlgorithm { name: name.clone() }, + length: size, + }; + + unsafe { + key_algorithm.to_jsobject(*cx, out); + } + } +} diff --git a/tests/wpt/meta/MANIFEST.json b/tests/wpt/meta/MANIFEST.json index ed260c8f6db..d47a92c7313 100644 --- a/tests/wpt/meta/MANIFEST.json +++ b/tests/wpt/meta/MANIFEST.json @@ -514622,6 +514622,31 @@ } ] ], + "cryptokey_algorithm_returns_cached_object.https.any.js": [ + "b2d73fbab78d64fa7e523adb579636d6295ee81a", + [ + "WebCryptoAPI/cryptokey_algorithm_returns_cached_object.https.any.html", + { + "script_metadata": [ + [ + "title", + "WebCryptoAPI: CryptoKey.algorithm getter returns cached object" + ] + ] + } + ], + [ + "WebCryptoAPI/cryptokey_algorithm_returns_cached_object.https.any.worker.html", + { + "script_metadata": [ + [ + "title", + "WebCryptoAPI: CryptoKey.algorithm getter returns cached object" + ] + ] + } + ] + ], "derive_bits_keys": { "cfrg_curves_bits_curve25519.https.any.js": [ "866192e0193bc18953c224647ac51f2bb373746f", diff --git a/tests/wpt/tests/WebCryptoAPI/cryptokey_algorithm_returns_cached_object.https.any.js b/tests/wpt/tests/WebCryptoAPI/cryptokey_algorithm_returns_cached_object.https.any.js new file mode 100644 index 00000000000..b2d73fbab78 --- /dev/null +++ b/tests/wpt/tests/WebCryptoAPI/cryptokey_algorithm_returns_cached_object.https.any.js @@ -0,0 +1,24 @@ +// META: title=WebCryptoAPI: CryptoKey.algorithm getter returns cached object + +// https://w3c.github.io/webcrypto/#dom-cryptokey-algorithm +// https://github.com/servo/servo/issues/33908 + +promise_test(function() { + return self.crypto.subtle.generateKey( + { + name: "AES-CTR", + length: 256, + }, + true, + ["encrypt"], + ).then( + function(key) { + let a = key.algorithm; + let b = key.algorithm; + assert_true(a === b); + }, + function(err) { + assert_unreached("generateKey threw an unexpected error: " + err.toString()); + } + ); +}, "CryptoKey.algorithm getter returns cached object");
\ No newline at end of file |