script/dom/
subtlecrypto.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5mod aes_cbc_operation;
6mod aes_common;
7mod aes_ctr_operation;
8mod aes_gcm_operation;
9mod aes_kw_operation;
10mod aes_ocb_operation;
11mod argon2_operation;
12mod chacha20_poly1305_operation;
13mod cshake_operation;
14mod ec_common;
15mod ecdh_operation;
16mod ecdsa_operation;
17mod ed25519_operation;
18mod hkdf_operation;
19mod hmac_operation;
20mod ml_dsa_operation;
21mod ml_kem_operation;
22mod pbkdf2_operation;
23mod rsa_common;
24mod rsa_oaep_operation;
25mod rsa_pss_operation;
26mod rsassa_pkcs1_v1_5_operation;
27mod sha3_operation;
28mod sha_operation;
29mod x25519_operation;
30
31use std::fmt::Display;
32use std::ptr;
33use std::rc::Rc;
34use std::str::FromStr;
35
36use base64ct::{Base64UrlUnpadded, Encoding};
37use dom_struct::dom_struct;
38use js::conversions::ConversionResult;
39use js::jsapi::{Heap, JSObject};
40use js::jsval::{ObjectValue, UndefinedValue};
41use js::realm::CurrentRealm;
42use js::rust::wrappers2::JS_ParseJSON;
43use js::rust::{HandleValue, MutableHandleValue};
44use js::typedarray::ArrayBufferU8;
45use strum::{EnumString, IntoStaticStr, VariantArray};
46
47use crate::dom::bindings::buffer_source::create_buffer_source;
48use crate::dom::bindings::codegen::Bindings::CryptoKeyBinding::{
49    CryptoKeyMethods, CryptoKeyPair, KeyType, KeyUsage,
50};
51use crate::dom::bindings::codegen::Bindings::SubtleCryptoBinding::{
52    AeadParams, AesCbcParams, AesCtrParams, AesDerivedKeyParams, AesGcmParams, AesKeyAlgorithm,
53    AesKeyGenParams, Algorithm, AlgorithmIdentifier, Argon2Params, CShakeParams, ContextParams,
54    EcKeyAlgorithm, EcKeyGenParams, EcKeyImportParams, EcdhKeyDeriveParams, EcdsaParams,
55    EncapsulatedBits, EncapsulatedKey, HkdfParams, HmacImportParams, HmacKeyAlgorithm,
56    HmacKeyGenParams, JsonWebKey, KeyAlgorithm, KeyFormat, Pbkdf2Params, RsaHashedImportParams,
57    RsaHashedKeyAlgorithm, RsaHashedKeyGenParams, RsaKeyAlgorithm, RsaOaepParams, RsaPssParams,
58    SubtleCryptoMethods,
59};
60use crate::dom::bindings::codegen::UnionTypes::{
61    ArrayBufferViewOrArrayBuffer, ArrayBufferViewOrArrayBufferOrJsonWebKey, ObjectOrString,
62};
63use crate::dom::bindings::conversions::{SafeFromJSValConvertible, SafeToJSValConvertible};
64use crate::dom::bindings::error::{Error, Fallible};
65use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
66use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object_with_cx};
67use crate::dom::bindings::root::DomRoot;
68use crate::dom::bindings::str::{DOMString, serialize_jsval_to_json_utf8};
69use crate::dom::bindings::trace::RootedTraceableBox;
70use crate::dom::bindings::utils::set_dictionary_property;
71use crate::dom::cryptokey::{CryptoKey, CryptoKeyOrCryptoKeyPair};
72use crate::dom::globalscope::GlobalScope;
73use crate::dom::promise::Promise;
74use crate::script_runtime::{CanGc, JSContext};
75
76// Named elliptic curves
77const NAMED_CURVE_P256: &str = "P-256";
78const NAMED_CURVE_P384: &str = "P-384";
79const NAMED_CURVE_P521: &str = "P-521";
80
81static SUPPORTED_CURVES: &[&str] = &[NAMED_CURVE_P256, NAMED_CURVE_P384, NAMED_CURVE_P521];
82
83#[derive(EnumString, VariantArray, IntoStaticStr, PartialEq, Clone, Copy, MallocSizeOf)]
84enum CryptoAlgorithm {
85    #[strum(serialize = "RSASSA-PKCS1-v1_5")]
86    RsassaPkcs1V1_5,
87    #[strum(serialize = "RSA-PSS")]
88    RsaPss,
89    #[strum(serialize = "RSA-OAEP")]
90    RsaOaep,
91    #[strum(serialize = "ECDSA")]
92    Ecdsa,
93    #[strum(serialize = "ECDH")]
94    Ecdh,
95    #[strum(serialize = "Ed25519")]
96    Ed25519,
97    #[strum(serialize = "X25519")]
98    X25519,
99    #[strum(serialize = "AES-CTR")]
100    AesCtr,
101    #[strum(serialize = "AES-CBC")]
102    AesCbc,
103    #[strum(serialize = "AES-GCM")]
104    AesGcm,
105    #[strum(serialize = "AES-KW")]
106    AesKw,
107    #[strum(serialize = "HMAC")]
108    Hmac,
109    #[strum(serialize = "SHA-1")]
110    Sha1,
111    #[strum(serialize = "SHA-256")]
112    Sha256,
113    #[strum(serialize = "SHA-384")]
114    Sha384,
115    #[strum(serialize = "SHA-512")]
116    Sha512,
117    #[strum(serialize = "HKDF")]
118    Hkdf,
119    #[strum(serialize = "PBKDF2")]
120    Pbkdf2,
121    #[strum(serialize = "ML-KEM-512")]
122    MlKem512,
123    #[strum(serialize = "ML-KEM-768")]
124    MlKem768,
125    #[strum(serialize = "ML-KEM-1024")]
126    MlKem1024,
127    #[strum(serialize = "ML-DSA-44")]
128    MlDsa44,
129    #[strum(serialize = "ML-DSA-65")]
130    MlDsa65,
131    #[strum(serialize = "ML-DSA-87")]
132    MlDsa87,
133    #[strum(serialize = "AES-OCB")]
134    AesOcb,
135    #[strum(serialize = "ChaCha20-Poly1305")]
136    ChaCha20Poly1305,
137    #[strum(serialize = "SHA3-256")]
138    Sha3_256,
139    #[strum(serialize = "SHA3-384")]
140    Sha3_384,
141    #[strum(serialize = "SHA3-512")]
142    Sha3_512,
143    #[strum(serialize = "cSHAKE128")]
144    CShake128,
145    #[strum(serialize = "cSHAKE256")]
146    CShake256,
147    #[strum(serialize = "Argon2d")]
148    Argon2D,
149    #[strum(serialize = "Argon2i")]
150    Argon2I,
151    #[strum(serialize = "Argon2id")]
152    Argon2ID,
153}
154
155impl CryptoAlgorithm {
156    /// <https://w3c.github.io/webcrypto/#recognized-algorithm-name>
157    fn as_str(&self) -> &'static str {
158        (*self).into()
159    }
160
161    fn from_str_ignore_case(algorithm_name: &str) -> Fallible<CryptoAlgorithm> {
162        Self::VARIANTS
163            .iter()
164            .find(|algorithm| algorithm.as_str().eq_ignore_ascii_case(algorithm_name))
165            .cloned()
166            .ok_or(Error::NotSupported(Some(format!(
167                "Unsupported algorithm: {algorithm_name}"
168            ))))
169    }
170
171    fn from_domstring(name: &DOMString) -> Fallible<Self> {
172        CryptoAlgorithm::try_from(&*name.str()).map_err(|_| Error::NotSupported(None))
173    }
174}
175
176#[dom_struct]
177pub(crate) struct SubtleCrypto {
178    reflector_: Reflector,
179}
180
181impl SubtleCrypto {
182    fn new_inherited() -> SubtleCrypto {
183        SubtleCrypto {
184            reflector_: Reflector::new(),
185        }
186    }
187
188    pub(crate) fn new(
189        cx: &mut js::context::JSContext,
190        global: &GlobalScope,
191    ) -> DomRoot<SubtleCrypto> {
192        reflect_dom_object_with_cx(Box::new(SubtleCrypto::new_inherited()), global, cx)
193    }
194
195    /// Queue a global task on the crypto task source, given realm's global object, to resolve
196    /// promise with the result of creating an ArrayBuffer in realm, containing data. If it fails
197    /// to create buffer source, reject promise with a JSFailedError.
198    fn resolve_promise_with_data(&self, promise: Rc<Promise>, data: Vec<u8>) {
199        let trusted_promise = TrustedPromise::new(promise);
200        self.global()
201            .task_manager()
202            .crypto_task_source()
203            .queue(task!(resolve_data: move |cx| {
204                let promise = trusted_promise.root();
205
206                rooted!(&in(cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>());
207                match create_buffer_source::<ArrayBufferU8>(
208                    cx.into(),
209                    &data,
210                    array_buffer_ptr.handle_mut(),
211                    CanGc::from_cx(cx),
212                ) {
213                    Ok(_) => promise.resolve_native(&*array_buffer_ptr, CanGc::from_cx(cx)),
214                    Err(_) => promise.reject_error(Error::JSFailed, CanGc::from_cx(cx)),
215                }
216            }));
217    }
218
219    /// Queue a global task on the crypto task source, given realm's global object, to resolve
220    /// promise with the result of converting a JsonWebKey dictionary to an ECMAScript Object in
221    /// realm, as defined by [WebIDL].
222    fn resolve_promise_with_jwk(
223        &self,
224        cx: &mut js::context::JSContext,
225        promise: Rc<Promise>,
226        jwk: Box<JsonWebKey>,
227    ) {
228        // NOTE: Serialize the JsonWebKey dictionary by stringifying it, in order to pass it to
229        // other threads.
230        let stringified_jwk = match jwk.stringify(cx) {
231            Ok(stringified_jwk) => stringified_jwk.to_string(),
232            Err(error) => {
233                self.reject_promise_with_error(promise, error);
234                return;
235            },
236        };
237
238        let trusted_subtle = Trusted::new(self);
239        let trusted_promise = TrustedPromise::new(promise);
240        self.global()
241            .task_manager()
242            .crypto_task_source()
243            .queue(task!(resolve_jwk: move |cx| {
244                let subtle = trusted_subtle.root();
245                let promise = trusted_promise.root();
246
247                match JsonWebKey::parse(cx, stringified_jwk.as_bytes()) {
248                    Ok(jwk) => {
249                        rooted!(&in(cx) let mut rval = UndefinedValue());
250                        jwk.safe_to_jsval(cx.into(), rval.handle_mut(), CanGc::from_cx(cx));
251                        rooted!(&in(cx) let mut object = rval.to_object());
252                        promise.resolve_native(&*object, CanGc::from_cx(cx));
253                    },
254                    Err(error) => {
255                        subtle.reject_promise_with_error(promise, error);
256                        return;
257                    },
258                }
259            }));
260    }
261
262    /// Queue a global task on the crypto task source, given realm's global object, to resolve
263    /// promise with a CryptoKey.
264    fn resolve_promise_with_key(&self, promise: Rc<Promise>, key: DomRoot<CryptoKey>) {
265        let trusted_key = Trusted::new(&*key);
266        let trusted_promise = TrustedPromise::new(promise);
267        self.global()
268            .task_manager()
269            .crypto_task_source()
270            .queue(task!(resolve_key: move |cx| {
271                let key = trusted_key.root();
272                let promise = trusted_promise.root();
273                promise.resolve_native(&key, CanGc::from_cx(cx));
274            }));
275    }
276
277    /// Queue a global task on the crypto task source, given realm's global object, to resolve
278    /// promise with a CryptoKeyPair.
279    fn resolve_promise_with_key_pair(&self, promise: Rc<Promise>, key_pair: CryptoKeyPair) {
280        let trusted_private_key = key_pair.privateKey.map(|key| Trusted::new(&*key));
281        let trusted_public_key = key_pair.publicKey.map(|key| Trusted::new(&*key));
282        let trusted_promise = TrustedPromise::new(promise);
283        self.global()
284            .task_manager()
285            .crypto_task_source()
286            .queue(task!(resolve_key: move |cx| {
287                let key_pair = CryptoKeyPair {
288                    privateKey: trusted_private_key.map(|trusted_key| trusted_key.root()),
289                    publicKey: trusted_public_key.map(|trusted_key| trusted_key.root()),
290                };
291                let promise = trusted_promise.root();
292                promise.resolve_native(&key_pair, CanGc::from_cx(cx));
293            }));
294    }
295
296    /// Queue a global task on the crypto task source, given realm's global object, to resolve
297    /// promise with a bool value.
298    fn resolve_promise_with_bool(&self, promise: Rc<Promise>, result: bool) {
299        let trusted_promise = TrustedPromise::new(promise);
300        self.global()
301            .task_manager()
302            .crypto_task_source()
303            .queue(task!(resolve_bool: move |cx| {
304                let promise = trusted_promise.root();
305                promise.resolve_native(&result, CanGc::from_cx(cx));
306            }));
307    }
308
309    /// Queue a global task on the crypto task source, given realm's global object, to reject
310    /// promise with an error.
311    fn reject_promise_with_error(&self, promise: Rc<Promise>, error: Error) {
312        let trusted_promise = TrustedPromise::new(promise);
313        self.global()
314            .task_manager()
315            .crypto_task_source()
316            .queue(task!(reject_error: move |cx| {
317                let promise = trusted_promise.root();
318                promise.reject_error(error, CanGc::from_cx(cx));
319            }));
320    }
321
322    /// Queue a global task on the crypto task source, given realm's global object, to resolve
323    /// promise with the result of converting EncapsulatedKey to an ECMAScript Object in realm, as
324    /// defined by [WebIDL].
325    fn resolve_promise_with_encapsulated_key(
326        &self,
327        promise: Rc<Promise>,
328        encapsulated_key: SubtleEncapsulatedKey,
329    ) {
330        let trusted_promise = TrustedPromise::new(promise);
331        self.global().task_manager().crypto_task_source().queue(
332            task!(resolve_encapsulated_key: move |cx| {
333                let promise = trusted_promise.root();
334                promise.resolve_native(&encapsulated_key, CanGc::from_cx(cx));
335            }),
336        );
337    }
338
339    /// Queue a global task on the crypto task source, given realm's global object, to resolve
340    /// promise with the result of converting EncapsulateBits to an ECMAScript Object in realm, as
341    /// defined by [WebIDL].
342    fn resolve_promise_with_encapsulated_bits(
343        &self,
344        promise: Rc<Promise>,
345        encapsulated_bits: SubtleEncapsulatedBits,
346    ) {
347        let trusted_promise = TrustedPromise::new(promise);
348        self.global().task_manager().crypto_task_source().queue(
349            task!(resolve_encapsulated_bits: move |cx| {
350                let promise = trusted_promise.root();
351                promise.resolve_native(&encapsulated_bits, CanGc::from_cx(cx));
352            }),
353        );
354    }
355}
356
357impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
358    /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-encrypt>
359    fn Encrypt(
360        &self,
361        cx: &mut CurrentRealm,
362        algorithm: AlgorithmIdentifier,
363        key: &CryptoKey,
364        data: ArrayBufferViewOrArrayBuffer,
365    ) -> Rc<Promise> {
366        // Step 1. Let algorithm and key be the algorithm and key parameters passed to the
367        // encrypt() method, respectively.
368        // NOTE: We did that in method parameter.
369
370        // Step 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
371        // to algorithm and op set to "encrypt".
372        // Step 3. If an error occurred, return a Promise rejected with normalizedAlgorithm.
373        let normalized_algorithm = match normalize_algorithm::<EncryptOperation>(cx, &algorithm) {
374            Ok(normalized_algorithm) => normalized_algorithm,
375            Err(error) => {
376                let promise = Promise::new_in_realm(cx);
377                promise.reject_error(error, CanGc::from_cx(cx));
378                return promise;
379            },
380        };
381
382        // Step 4. Let data be the result of getting a copy of the bytes held by the data parameter
383        // passed to the encrypt() method.
384        let data = match data {
385            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
386            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
387        };
388
389        // Step 5. Let realm be the relevant realm of this.
390        // Step 6. Let promise be a new Promise.
391        let promise = Promise::new_in_realm(cx);
392
393        // Step 7. Return promise and perform the remaining steps in parallel.
394        let this = Trusted::new(self);
395        let trusted_promise = TrustedPromise::new(promise.clone());
396        let trusted_key = Trusted::new(key);
397        self.global()
398            .task_manager()
399            .dom_manipulation_task_source()
400            .queue(task!(encrypt: move || {
401                let subtle = this.root();
402                let promise = trusted_promise.root();
403                let key = trusted_key.root();
404
405                // Step 8. If the following steps or referenced procedures say to throw an error,
406                // queue a global task on the crypto task source, given realm's global object, to
407                // reject promise with the returned error; and then terminate the algorithm.
408
409                // Step 9. If the name member of normalizedAlgorithm is not equal to the name
410                // attribute of the [[algorithm]] internal slot of key then throw an
411                // InvalidAccessError.
412                if normalized_algorithm.name() != key.algorithm().name() {
413                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
414                    return;
415                }
416
417                // Step 10. If the [[usages]] internal slot of key does not contain an entry that
418                // is "encrypt", then throw an InvalidAccessError.
419                if !key.usages().contains(&KeyUsage::Encrypt) {
420                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
421                    return;
422                }
423
424                // Step 11. Let ciphertext be the result of performing the encrypt operation
425                // specified by normalizedAlgorithm using algorithm and key and with data as
426                // plaintext.
427                let ciphertext = match normalized_algorithm.encrypt(&key, &data) {
428                    Ok(ciphertext) => ciphertext,
429                    Err(error) => {
430                        subtle.reject_promise_with_error(promise, error);
431                        return;
432                    },
433                };
434
435                // Step 12. Queue a global task on the crypto task source, given realm's global
436                // object, to perform the remaining steps.
437                // Step 13. Let result be the result of creating an ArrayBuffer in realm,
438                // containing ciphertext.
439                // Step 14. Resolve promise with result.
440                subtle.resolve_promise_with_data(promise, ciphertext);
441            }));
442        promise
443    }
444
445    /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-decrypt>
446    fn Decrypt(
447        &self,
448        cx: &mut CurrentRealm,
449        algorithm: AlgorithmIdentifier,
450        key: &CryptoKey,
451        data: ArrayBufferViewOrArrayBuffer,
452    ) -> Rc<Promise> {
453        // Step 1. Let algorithm and key be the algorithm and key parameters passed to the
454        // decrypt() method, respectively.
455        // NOTE: We did that in method parameter.
456
457        // Step 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
458        // to algorithm and op set to "decrypt".
459        // Step 3. If an error occurred, return a Promise rejected with normalizedAlgorithm.
460        let normalized_algorithm = match normalize_algorithm::<DecryptOperation>(cx, &algorithm) {
461            Ok(normalized_algorithm) => normalized_algorithm,
462            Err(error) => {
463                let promise = Promise::new_in_realm(cx);
464                promise.reject_error(error, CanGc::from_cx(cx));
465                return promise;
466            },
467        };
468
469        // Step 4. Let data be the result of getting a copy of the bytes held by the data parameter
470        // passed to the decrypt() method.
471        let data = match data {
472            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
473            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
474        };
475
476        // Step 5. Let realm be the relevant realm of this.
477        // Step 6. Let promise be a new Promise.
478        let promise = Promise::new_in_realm(cx);
479
480        // Step 7. Return promise and perform the remaining steps in parallel.
481        let this = Trusted::new(self);
482        let trusted_promise = TrustedPromise::new(promise.clone());
483        let trusted_key = Trusted::new(key);
484        self.global()
485            .task_manager()
486            .dom_manipulation_task_source()
487            .queue(task!(decrypt: move || {
488                let subtle = this.root();
489                let promise = trusted_promise.root();
490                let key = trusted_key.root();
491
492                // Step 8. If the following steps or referenced procedures say to throw an error,
493                // queue a global task on the crypto task source, given realm's global object, to
494                // reject promise with the returned error; and then terminate the algorithm.
495
496                // Step 9. If the name member of normalizedAlgorithm is not equal to the name
497                // attribute of the [[algorithm]] internal slot of key then throw an
498                // InvalidAccessError.
499                if normalized_algorithm.name() != key.algorithm().name() {
500                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
501                    return;
502                }
503
504                // Step 10. If the [[usages]] internal slot of key does not contain an entry that
505                // is "decrypt", then throw an InvalidAccessError.
506                if !key.usages().contains(&KeyUsage::Decrypt) {
507                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
508                    return;
509                }
510
511                // Step 11. Let plaintext be the result of performing the decrypt operation
512                // specified by normalizedAlgorithm using key and algorithm and with data as
513                // ciphertext.
514                let plaintext = match normalized_algorithm.decrypt(&key, &data) {
515                    Ok(plaintext) => plaintext,
516                    Err(error) => {
517                        subtle.reject_promise_with_error(promise, error);
518                        return;
519                    },
520                };
521
522                // Step 12. Queue a global task on the crypto task source, given realm's global
523                // object, to perform the remaining steps.
524                // Step 13. Let result be the result of creating an ArrayBuffer in realm,
525                // containing plaintext.
526                // Step 14. Resolve promise with result.
527                subtle.resolve_promise_with_data(promise, plaintext);
528            }));
529        promise
530    }
531
532    /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-sign>
533    fn Sign(
534        &self,
535        cx: &mut CurrentRealm,
536        algorithm: AlgorithmIdentifier,
537        key: &CryptoKey,
538        data: ArrayBufferViewOrArrayBuffer,
539    ) -> Rc<Promise> {
540        // Step 1. Let algorithm and key be the algorithm and key parameters passed to the sign()
541        // method, respectively.
542        // NOTE: We did that in method parameter.
543
544        // Step 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
545        // to algorithm and op set to "sign".
546        // Step 3. If an error occurred, return a Promise rejected with normalizedAlgorithm.
547        let normalized_algorithm = match normalize_algorithm::<SignOperation>(cx, &algorithm) {
548            Ok(normalized_algorithm) => normalized_algorithm,
549            Err(error) => {
550                let promise = Promise::new_in_realm(cx);
551                promise.reject_error(error, CanGc::from_cx(cx));
552                return promise;
553            },
554        };
555
556        // Step 4. Let data be the result of getting a copy of the bytes held by the data parameter
557        // passed to the sign() method.
558        let data = match &data {
559            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
560            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
561        };
562
563        // Step 5. Let realm be the relevant realm of this.
564        // Step 6. Let promise be a new Promise.
565        let promise = Promise::new_in_realm(cx);
566
567        // Step 7. Return promise and perform the remaining steps in parallel.
568        let this = Trusted::new(self);
569        let trusted_promise = TrustedPromise::new(promise.clone());
570        let trusted_key = Trusted::new(key);
571        self.global()
572            .task_manager()
573            .dom_manipulation_task_source()
574            .queue(task!(sign: move || {
575                let subtle = this.root();
576                let promise = trusted_promise.root();
577                let key = trusted_key.root();
578
579                // Step 8. If the following steps or referenced procedures say to throw an error,
580                // queue a global task on the crypto task source, given realm's global object, to
581                // reject promise with the returned error; and then terminate the algorithm.
582
583                // Step 9. If the name member of normalizedAlgorithm is not equal to the name
584                // attribute of the [[algorithm]] internal slot of key then throw an
585                // InvalidAccessError.
586                if normalized_algorithm.name() != key.algorithm().name() {
587                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
588                    return;
589                }
590
591                // Step 10. If the [[usages]] internal slot of key does not contain an entry that
592                // is "sign", then throw an InvalidAccessError.
593                if !key.usages().contains(&KeyUsage::Sign) {
594                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
595                    return;
596                }
597
598                // Step 11. Let signature be the result of performing the sign operation specified
599                // by normalizedAlgorithm using key and algorithm and with data as message.
600                let signature = match normalized_algorithm.sign(&key, &data) {
601                    Ok(signature) => signature,
602                    Err(error) => {
603                        subtle.reject_promise_with_error(promise, error);
604                        return;
605                    },
606                };
607
608                // Step 12. Queue a global task on the crypto task source, given realm's global
609                // object, to perform the remaining steps.
610                // Step 13. Let result be the result of creating an ArrayBuffer in realm,
611                // containing signature.
612                // Step 14. Resolve promise with result.
613                subtle.resolve_promise_with_data(promise, signature);
614            }));
615        promise
616    }
617
618    /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-verify>
619    fn Verify(
620        &self,
621        cx: &mut CurrentRealm,
622        algorithm: AlgorithmIdentifier,
623        key: &CryptoKey,
624        signature: ArrayBufferViewOrArrayBuffer,
625        data: ArrayBufferViewOrArrayBuffer,
626    ) -> Rc<Promise> {
627        // Step 1. Let algorithm and key be the algorithm and key parameters passed to the verify()
628        // method, respectively.
629        // NOTE: We did that in method parameter.
630
631        // Step 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set to
632        // algorithm and op set to "verify".
633        // Step 3. If an error occurred, return a Promise rejected with normalizedAlgorithm.
634        let normalized_algorithm = match normalize_algorithm::<VerifyOperation>(cx, &algorithm) {
635            Ok(algorithm) => algorithm,
636            Err(error) => {
637                let promise = Promise::new_in_realm(cx);
638                promise.reject_error(error, CanGc::from_cx(cx));
639                return promise;
640            },
641        };
642
643        // Step 4. Let signature be the result of getting a copy of the bytes held by the signature
644        // parameter passed to the verify() method.
645        let signature = match &signature {
646            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
647            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
648        };
649
650        // Step 5. Let data be the result of getting a copy of the bytes held by the data parameter
651        // passed to the verify() method.
652        let data = match &data {
653            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
654            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
655        };
656
657        // Step 6. Let realm be the relevant realm of this.
658        // Step 7. Let promise be a new Promise.
659        let promise = Promise::new_in_realm(cx);
660
661        // Step 8. Return promise and perform the remaining steps in parallel.
662        let this = Trusted::new(self);
663        let trusted_promise = TrustedPromise::new(promise.clone());
664        let trusted_key = Trusted::new(key);
665        self.global()
666            .task_manager()
667            .dom_manipulation_task_source()
668            .queue(task!(sign: move || {
669                let subtle = this.root();
670                let promise = trusted_promise.root();
671                let key = trusted_key.root();
672
673                // Step 9. If the following steps or referenced procedures say to throw an error,
674                // queue a global task on the crypto task source, given realm's global object, to
675                // reject promise with the returned error; and then terminate the algorithm.
676
677                // Step 10. If the name member of normalizedAlgorithm is not equal to the name
678                // attribute of the [[algorithm]] internal slot of key then throw an
679                // InvalidAccessError.
680                if normalized_algorithm.name() != key.algorithm().name() {
681                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
682                    return;
683                }
684
685                // Step 11. If the [[usages]] internal slot of key does not contain an entry that
686                // is "verify", then throw an InvalidAccessError.
687                if !key.usages().contains(&KeyUsage::Verify) {
688                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
689                    return;
690                }
691
692                // Step 12. Let result be the result of performing the verify operation specified
693                // by normalizedAlgorithm using key, algorithm and signature and with data as
694                // message.
695                let result = match normalized_algorithm.verify(&key, &data, &signature) {
696                    Ok(result) => result,
697                    Err(error) => {
698                        subtle.reject_promise_with_error(promise, error);
699                        return;
700                    },
701                };
702
703                // Step 13. Queue a global task on the crypto task source, given realm's global
704                // object, to perform the remaining steps.
705                // Step 14. Resolve promise with result.
706                subtle.resolve_promise_with_bool(promise, result);
707            }));
708        promise
709    }
710
711    /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-digest>
712    fn Digest(
713        &self,
714        cx: &mut CurrentRealm,
715        algorithm: AlgorithmIdentifier,
716        data: ArrayBufferViewOrArrayBuffer,
717    ) -> Rc<Promise> {
718        // Step 1. Let algorithm be the algorithm parameter passed to the digest() method.
719        // NOTE: We did that in method parameter.
720
721        // Step 2. Let normalizedAlgorithm be the result of normalizing an algorithm,
722        // with alg set to algorithm and op set to "digest".
723        // Step 3. If an error occurred, return a Promise rejected with normalizedAlgorithm.
724        let normalized_algorithm = match normalize_algorithm::<DigestOperation>(cx, &algorithm) {
725            Ok(normalized_algorithm) => normalized_algorithm,
726            Err(error) => {
727                let promise = Promise::new_in_realm(cx);
728                promise.reject_error(error, CanGc::from_cx(cx));
729                return promise;
730            },
731        };
732
733        // Step 4. Let data be the result of getting a copy of the bytes held by the
734        // data parameter passed to the digest() method.
735        let data = match data {
736            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
737            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
738        };
739
740        // Step 5. Let realm be the relevant realm of this.
741        // Step 6. Let promise be a new Promise.
742        let promise = Promise::new_in_realm(cx);
743
744        // Step 7. Return promise and perform the remaining steps in parallel.
745        let this = Trusted::new(self);
746        let trusted_promise = TrustedPromise::new(promise.clone());
747        self.global()
748            .task_manager()
749            .dom_manipulation_task_source()
750            .queue(task!(digest_: move || {
751                let subtle = this.root();
752                let promise = trusted_promise.root();
753
754                // Step 8. If the following steps or referenced procedures say to throw an error,
755                // queue a global task on the crypto task source, given realm's global object, to
756                // reject promise with the returned error; and then terminate the algorithm.
757
758                // Step 9. Let digest be the result of performing the digest operation specified by
759                // normalizedAlgorithm using algorithm, with data as message.
760                let digest = match normalized_algorithm.digest(&data) {
761                    Ok(digest) => digest,
762                    Err(error) => {
763                        subtle.reject_promise_with_error(promise, error);
764                        return;
765                    }
766                };
767
768                // Step 10. Queue a global task on the crypto task source, given realm's global
769                // object, to perform the remaining steps.
770                // Step 11. Let result be the result of creating an ArrayBuffer in realm,
771                // containing digest.
772                // Step 12. Resolve promise with result.
773                subtle.resolve_promise_with_data(promise, digest);
774            }));
775        promise
776    }
777
778    /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-generateKey>
779    fn GenerateKey(
780        &self,
781        cx: &mut CurrentRealm,
782        algorithm: AlgorithmIdentifier,
783        extractable: bool,
784        key_usages: Vec<KeyUsage>,
785    ) -> Rc<Promise> {
786        // Step 1. Let algorithm, extractable and usages be the algorithm, extractable and
787        // keyUsages parameters passed to the generateKey() method, respectively.
788
789        // Step 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
790        // to algorithm and op set to "generateKey".
791        // Step 3. If an error occurred, return a Promise rejected with normalizedAlgorithm.
792        let promise = Promise::new_in_realm(cx);
793        let normalized_algorithm = match normalize_algorithm::<GenerateKeyOperation>(cx, &algorithm)
794        {
795            Ok(normalized_algorithm) => normalized_algorithm,
796            Err(error) => {
797                promise.reject_error(error, CanGc::from_cx(cx));
798                return promise;
799            },
800        };
801
802        // Step 4. Let realm be the relevant realm of this.
803        // Step 5. Let promise be a new Promise.
804        // NOTE: We did that in preparation of Step 3.
805
806        // Step 6. Return promise and perform the remaining steps in parallel.
807        let trusted_subtle = Trusted::new(self);
808        let trusted_promise = TrustedPromise::new(promise.clone());
809        self.global()
810            .task_manager()
811            .dom_manipulation_task_source()
812            .queue(task!(generate_key: move |cx| {
813                let subtle = trusted_subtle.root();
814                let promise = trusted_promise.root();
815
816                // Step 7. If the following steps or referenced procedures say to throw an error,
817                // queue a global task on the crypto task source, given realm's global object, to
818                // reject promise with the returned error; and then terminate the algorithm.
819
820                // Step 8. Let result be the result of performing the generate key operation
821                // specified by normalizedAlgorithm using algorithm, extractable and usages.
822                let result = match normalized_algorithm.generate_key(
823                    cx,
824                    &subtle.global(),
825                    extractable,
826                    key_usages,
827                ) {
828                    Ok(result) => result,
829                    Err(error) => {
830                        subtle.reject_promise_with_error(promise, error);
831                        return;
832                    }
833                };
834
835                // Step 9.
836                // If result is a CryptoKey object:
837                //     If the [[type]] internal slot of result is "secret" or "private" and usages
838                //     is empty, then throw a SyntaxError.
839                // If result is a CryptoKeyPair object:
840                //     If the [[usages]] internal slot of the privateKey attribute of result is the
841                //     empty sequence, then throw a SyntaxError.
842                match &result {
843                    CryptoKeyOrCryptoKeyPair::CryptoKey(crpyto_key) => {
844                        if matches!(crpyto_key.Type(), KeyType::Secret | KeyType::Private)
845                            && crpyto_key.usages().is_empty()
846                        {
847                            subtle.reject_promise_with_error(promise, Error::Syntax(None));
848                            return;
849                        }
850                    },
851                    CryptoKeyOrCryptoKeyPair::CryptoKeyPair(crypto_key_pair) => {
852                        if crypto_key_pair
853                            .privateKey
854                            .as_ref()
855                            .is_none_or(|private_key| private_key.usages().is_empty())
856                        {
857                            subtle.reject_promise_with_error(promise, Error::Syntax(None));
858                            return;
859                        }
860                    }
861                };
862
863                // Step 10. Queue a global task on the crypto task source, given realm's global
864                // object, to perform the remaining steps.
865                // Step 11. Let result be the result of converting result to an ECMAScript Object
866                // in realm, as defined by [WebIDL].
867                // Step 12. Resolve promise with result.
868                match result {
869                    CryptoKeyOrCryptoKeyPair::CryptoKey(key) => {
870                        subtle.resolve_promise_with_key(promise, key);
871                    },
872                    CryptoKeyOrCryptoKeyPair::CryptoKeyPair(key_pair) => {
873                        subtle.resolve_promise_with_key_pair(promise, key_pair);
874                    },
875                }
876            }));
877
878        promise
879    }
880
881    /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-deriveKey>
882    fn DeriveKey(
883        &self,
884        cx: &mut CurrentRealm,
885        algorithm: AlgorithmIdentifier,
886        base_key: &CryptoKey,
887        derived_key_type: AlgorithmIdentifier,
888        extractable: bool,
889        usages: Vec<KeyUsage>,
890    ) -> Rc<Promise> {
891        // Step 1. Let algorithm, baseKey, derivedKeyType, extractable and usages be the algorithm,
892        // baseKey, derivedKeyType, extractable and keyUsages parameters passed to the deriveKey()
893        // method, respectively.
894        // NOTE: We did that in method parameter.
895
896        // Step 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
897        // to algorithm and op set to "deriveBits".
898        // Step 3. If an error occurred, return a Promise rejected with normalizedAlgorithm.
899        let promise = Promise::new_in_realm(cx);
900        let normalized_algorithm = match normalize_algorithm::<DeriveBitsOperation>(cx, &algorithm)
901        {
902            Ok(normalized_algorithm) => normalized_algorithm,
903            Err(error) => {
904                promise.reject_error(error, CanGc::from_cx(cx));
905                return promise;
906            },
907        };
908
909        // Step 4. Let normalizedDerivedKeyAlgorithmImport be the result of normalizing an
910        // algorithm, with alg set to derivedKeyType and op set to "importKey".
911        // Step 5. If an error occurred, return a Promise rejected with
912        // normalizedDerivedKeyAlgorithmImport.
913        let normalized_derived_key_algorithm_import =
914            match normalize_algorithm::<ImportKeyOperation>(cx, &derived_key_type) {
915                Ok(normalized_algorithm) => normalized_algorithm,
916                Err(error) => {
917                    promise.reject_error(error, CanGc::from_cx(cx));
918                    return promise;
919                },
920            };
921
922        // Step 6. Let normalizedDerivedKeyAlgorithmLength be the result of normalizing an
923        // algorithm, with alg set to derivedKeyType and op set to "get key length".
924        // Step 7. If an error occurred, return a Promise rejected with
925        // normalizedDerivedKeyAlgorithmLength.
926        let normalized_derived_key_algorithm_length =
927            match normalize_algorithm::<GetKeyLengthOperation>(cx, &derived_key_type) {
928                Ok(normalized_algorithm) => normalized_algorithm,
929                Err(error) => {
930                    promise.reject_error(error, CanGc::from_cx(cx));
931                    return promise;
932                },
933            };
934
935        // Step 8. Let realm be the relevant realm of this.
936        // Step 9. Let promise be a new Promise.
937        // NOTE: We did that in preparation of Step 3.
938
939        // Step 10. Return promise and perform the remaining steps in parallel.
940        let trusted_subtle = Trusted::new(self);
941        let trusted_base_key = Trusted::new(base_key);
942        let trusted_promise = TrustedPromise::new(promise.clone());
943        self.global().task_manager().dom_manipulation_task_source().queue(
944            task!(derive_key: move |cx| {
945                let subtle = trusted_subtle.root();
946                let base_key = trusted_base_key.root();
947                let promise = trusted_promise.root();
948
949                // Step 11. If the following steps or referenced procedures say to throw an error,
950                // queue a global task on the crypto task source, given realm's global object, to
951                // reject promise with the returned error; and then terminate the algorithm.
952
953                // Step 12. If the name member of normalizedAlgorithm is not equal to the name
954                // attribute of the [[algorithm]] internal slot of baseKey then throw an
955                // InvalidAccessError.
956                if normalized_algorithm.name() != base_key.algorithm().name() {
957                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
958                    return;
959                }
960
961                // Step 13. If the [[usages]] internal slot of baseKey does not contain an entry
962                // that is "deriveKey", then throw an InvalidAccessError.
963                if !base_key.usages().contains(&KeyUsage::DeriveKey) {
964                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
965                    return;
966                }
967
968                // Step 14. Let length be the result of performing the get key length algorithm
969                // specified by normalizedDerivedKeyAlgorithmLength using derivedKeyType.
970                let length = match normalized_derived_key_algorithm_length.get_key_length() {
971                    Ok(length) => length,
972                    Err(error) => {
973                        subtle.reject_promise_with_error(promise, error);
974                        return;
975                    }
976                };
977
978                // Step 15. Let secret be the result of performing the derive bits operation
979                // specified by normalizedAlgorithm using key, algorithm and length.
980                let secret = match normalized_algorithm.derive_bits(&base_key, length) {
981                    Ok(secret) => secret,
982                    Err(error) => {
983                        subtle.reject_promise_with_error(promise, error);
984                        return;
985                    }
986                };
987
988                // Step 16. Let result be the result of performing the import key operation
989                // specified by normalizedDerivedKeyAlgorithmImport using "raw" as format, secret
990                // as keyData, derivedKeyType as algorithm and using extractable and usages.
991                // NOTE: Use "raw-secret" instead, according to
992                // <https://wicg.github.io/webcrypto-modern-algos/#subtlecrypto-interface-keyformat>.
993                let result = match normalized_derived_key_algorithm_import.import_key(
994                    cx,
995                    &subtle.global(),
996                    KeyFormat::Raw_secret,
997                    &secret,
998                    extractable,
999                    usages.clone(),
1000                ) {
1001                    Ok(algorithm) => algorithm,
1002                    Err(error) => {
1003                        subtle.reject_promise_with_error(promise, error);
1004                        return;
1005                    },
1006                };
1007
1008                // Step 17. If the [[type]] internal slot of result is "secret" or "private" and
1009                // usages is empty, then throw a SyntaxError.
1010                if matches!(result.Type(), KeyType::Secret | KeyType::Private) && usages.is_empty() {
1011                    subtle.reject_promise_with_error(promise, Error::Syntax(None));
1012                    return;
1013                }
1014
1015                // Step 18. Set the [[extractable]] internal slot of result to extractable.
1016                // Step 19. Set the [[usages]] internal slot of result to the normalized value of
1017                // usages.
1018                // NOTE: Done by normalized_derived_key_algorithm_import.import_key in Step 16.
1019
1020                // Step 20. Queue a global task on the crypto task source, given realm's global
1021                // object, to perform the remaining steps.
1022                // Step 20. Let result be the result of converting result to an ECMAScript Object
1023                // in realm, as defined by [WebIDL].
1024                // Step 20. Resolve promise with result.
1025                subtle.resolve_promise_with_key(promise, result);
1026            }),
1027        );
1028        promise
1029    }
1030
1031    /// <https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-deriveBits>
1032    fn DeriveBits(
1033        &self,
1034        cx: &mut CurrentRealm,
1035        algorithm: AlgorithmIdentifier,
1036        base_key: &CryptoKey,
1037        length: Option<u32>,
1038    ) -> Rc<Promise> {
1039        // Step 1. Let algorithm, baseKey and length, be the algorithm, baseKey and length
1040        // parameters passed to the deriveBits() method, respectively.
1041        // NOTE: We did that in method parameter.
1042
1043        // Step 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
1044        // to algorithm and op set to "deriveBits".
1045        // Step 3. If an error occurred, return a Promise rejected with normalizedAlgorithm.
1046        let promise = Promise::new_in_realm(cx);
1047        let normalized_algorithm = match normalize_algorithm::<DeriveBitsOperation>(cx, &algorithm)
1048        {
1049            Ok(normalized_algorithm) => normalized_algorithm,
1050            Err(error) => {
1051                promise.reject_error(error, CanGc::from_cx(cx));
1052                return promise;
1053            },
1054        };
1055
1056        // Step 4. Let realm be the relevant realm of this.
1057        // Step 5. Let promise be a new Promise.
1058        // NOTE: We did that in preparation of Step 3.
1059
1060        // Step 5. Return promise and perform the remaining steps in parallel.
1061        let trsuted_subtle = Trusted::new(self);
1062        let trusted_base_key = Trusted::new(base_key);
1063        let trusted_promise = TrustedPromise::new(promise.clone());
1064        self.global()
1065            .task_manager()
1066            .dom_manipulation_task_source()
1067            .queue(task!(import_key: move || {
1068                let subtle = trsuted_subtle.root();
1069                let base_key = trusted_base_key.root();
1070                let promise = trusted_promise.root();
1071
1072                // Step 7. If the following steps or referenced procedures say to throw an error,
1073                // queue a global task on the crypto task source, given realm's global object, to
1074                // reject promise with the returned error; and then terminate the algorithm.
1075
1076                // Step 8. If the name member of normalizedAlgorithm is not equal to the name
1077                // attribute of the [[algorithm]] internal slot of baseKey then throw an
1078                // InvalidAccessError.
1079                if normalized_algorithm.name() != base_key.algorithm().name() {
1080                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
1081                    return;
1082                }
1083
1084                // Step 9. If the [[usages]] internal slot of baseKey does not contain an entry
1085                // that is "deriveBits", then throw an InvalidAccessError.
1086                if !base_key.usages().contains(&KeyUsage::DeriveBits) {
1087                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
1088                    return;
1089                }
1090
1091                // Step 10. Let bits be the result of performing the derive bits operation
1092                // specified by normalizedAlgorithm using baseKey, algorithm and length.
1093                let bits = match normalized_algorithm.derive_bits(&base_key, length) {
1094                    Ok(bits) => bits,
1095                    Err(error) => {
1096                        subtle.reject_promise_with_error(promise, error);
1097                        return;
1098                    }
1099                };
1100
1101                // Step 11. Queue a global task on the crypto task source, given realm's global
1102                // object, to perform the remaining steps.
1103                // Step 12. Let result be the result of creating an ArrayBuffer in realm,
1104                // containing bits.
1105                // Step 13. Resolve promise with result.
1106                subtle.resolve_promise_with_data(promise, bits);
1107            }));
1108        promise
1109    }
1110
1111    /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-importKey>
1112    fn ImportKey(
1113        &self,
1114        cx: &mut CurrentRealm,
1115        format: KeyFormat,
1116        key_data: ArrayBufferViewOrArrayBufferOrJsonWebKey,
1117        algorithm: AlgorithmIdentifier,
1118        extractable: bool,
1119        key_usages: Vec<KeyUsage>,
1120    ) -> Rc<Promise> {
1121        // Step 1. Let format, algorithm, extractable and usages, be the format, algorithm,
1122        // extractable and keyUsages parameters passed to the importKey() method, respectively.
1123
1124        // Step 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
1125        // to algorithm and op set to "importKey".
1126        // Step 3. If an error occurred, return a Promise rejected with normalizedAlgorithm.
1127        let normalized_algorithm = match normalize_algorithm::<ImportKeyOperation>(cx, &algorithm) {
1128            Ok(algorithm) => algorithm,
1129            Err(error) => {
1130                let promise = Promise::new_in_realm(cx);
1131                promise.reject_error(error, CanGc::from_cx(cx));
1132                return promise;
1133            },
1134        };
1135
1136        // Step 4.
1137        let key_data = match format {
1138            // If format is equal to the string "jwk":
1139            KeyFormat::Jwk => {
1140                match key_data {
1141                    ArrayBufferViewOrArrayBufferOrJsonWebKey::ArrayBufferView(_) |
1142                    ArrayBufferViewOrArrayBufferOrJsonWebKey::ArrayBuffer(_) => {
1143                        // Step 4.1. If the keyData parameter passed to the importKey() method is
1144                        // not a JsonWebKey dictionary, throw a TypeError.
1145                        let promise = Promise::new_in_realm(cx);
1146                        promise.reject_error(
1147                            Error::Type(c"The keyData type does not match the format".to_owned()),
1148                            CanGc::from_cx(cx),
1149                        );
1150                        return promise;
1151                    },
1152
1153                    ArrayBufferViewOrArrayBufferOrJsonWebKey::JsonWebKey(jwk) => {
1154                        // Step 4.2. Let keyData be the keyData parameter passed to the importKey()
1155                        // method.
1156                        //
1157                        // NOTE: Serialize JsonWebKey throught stringifying it.
1158                        // JsonWebKey::stringify internally relies on ToJSON, so it will raise an
1159                        // exception when a JS error is thrown. When this happens, we report the
1160                        // error.
1161                        match jwk.stringify(cx) {
1162                            Ok(stringified) => stringified.as_bytes().to_vec(),
1163                            Err(error) => {
1164                                let promise = Promise::new_in_realm(cx);
1165                                promise.reject_error(error, CanGc::from_cx(cx));
1166                                return promise;
1167                            },
1168                        }
1169                    },
1170                }
1171            },
1172            // Otherwise:
1173            _ => {
1174                match key_data {
1175                    // Step 4.1. If the keyData parameter passed to the importKey() method is a
1176                    // JsonWebKey dictionary, throw a TypeError.
1177                    ArrayBufferViewOrArrayBufferOrJsonWebKey::JsonWebKey(_) => {
1178                        let promise = Promise::new_in_realm(cx);
1179                        promise.reject_error(
1180                            Error::Type(c"The keyData type does not match the format".to_owned()),
1181                            CanGc::from_cx(cx),
1182                        );
1183                        return promise;
1184                    },
1185
1186                    // Step 4.2. Let keyData be the result of getting a copy of the bytes held by
1187                    // the keyData parameter passed to the importKey() method.
1188                    ArrayBufferViewOrArrayBufferOrJsonWebKey::ArrayBufferView(view) => {
1189                        view.to_vec()
1190                    },
1191                    ArrayBufferViewOrArrayBufferOrJsonWebKey::ArrayBuffer(buffer) => {
1192                        buffer.to_vec()
1193                    },
1194                }
1195            },
1196        };
1197
1198        // Step 5. Let realm be the relevant realm of this.
1199        // Step 6. Let promise be a new Promise.
1200        let promise = Promise::new_in_realm(cx);
1201
1202        // Step 7. Return promise and perform the remaining steps in parallel.
1203        let this = Trusted::new(self);
1204        let trusted_promise = TrustedPromise::new(promise.clone());
1205        self.global()
1206            .task_manager()
1207            .dom_manipulation_task_source()
1208            .queue(task!(import_key: move |cx| {
1209                let subtle = this.root();
1210                let promise = trusted_promise.root();
1211
1212                // Step 8. If the following steps or referenced procedures say to throw an error,
1213                // queue a global task on the crypto task source, given realm's global object, to
1214                // reject promise with the returned error; and then terminate the algorithm.
1215
1216                // Step 9. Let result be the CryptoKey object that results from performing the
1217                // import key operation specified by normalizedAlgorithm using keyData, algorithm,
1218                // format, extractable and usages.
1219                let result = match normalized_algorithm.import_key(
1220                    cx,
1221                    &subtle.global(),
1222                    format,
1223                    &key_data,
1224                    extractable,
1225                    key_usages.clone(),
1226                ) {
1227                    Ok(key) => key,
1228                    Err(error) => {
1229                        subtle.reject_promise_with_error(promise, error);
1230                        return;
1231                    },
1232                };
1233
1234                // Step 10. If the [[type]] internal slot of result is "secret" or "private" and
1235                // usages is empty, then throw a SyntaxError.
1236                if matches!(result.Type(), KeyType::Secret | KeyType::Private) && key_usages.is_empty() {
1237                    subtle.reject_promise_with_error(promise, Error::Syntax(None));
1238                    return;
1239                }
1240
1241                // Step 11. Set the [[extractable]] internal slot of result to extractable.
1242                result.set_extractable(extractable);
1243
1244                // Step 12. Set the [[usages]] internal slot of result to the normalized value of usages.
1245                result.set_usages(cx, &key_usages);
1246
1247                // Step 13. Queue a global task on the crypto task source, given realm's global
1248                // object, to perform the remaining steps.
1249                // Step 14. Let result be the result of converting result to an ECMAScript Object
1250                // in realm, as defined by [WebIDL].
1251                // Step 15. Resolve promise with result.
1252                subtle.resolve_promise_with_key(promise, result);
1253            }));
1254
1255        promise
1256    }
1257
1258    /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-exportKey>
1259    fn ExportKey(&self, cx: &mut CurrentRealm, format: KeyFormat, key: &CryptoKey) -> Rc<Promise> {
1260        // Step 1. Let format and key be the format and key parameters passed to the exportKey()
1261        // method, respectively.
1262        // NOTE: We did that in method parameter.
1263
1264        // Step 2. Let realm be the relevant realm of this.
1265        // Step 3. Let promise be a new Promise.
1266        let promise = Promise::new_in_realm(cx);
1267
1268        // Step 4. Return promise and perform the remaining steps in parallel.
1269        let trusted_subtle = Trusted::new(self);
1270        let trusted_promise = TrustedPromise::new(promise.clone());
1271        let trusted_key = Trusted::new(key);
1272        self.global()
1273            .task_manager()
1274            .dom_manipulation_task_source()
1275            .queue(task!(export_key: move |cx| {
1276                let subtle = trusted_subtle.root();
1277                let promise = trusted_promise.root();
1278                let key = trusted_key.root();
1279
1280                // Step 5. If the following steps or referenced procedures say to throw an error,
1281                // queue a global task on the crypto task source, given realm's global object, to
1282                // reject promise with the returned error; and then terminate the algorithm.
1283
1284                // Step 6. If the name member of the [[algorithm]] internal slot of key does not
1285                // identify a registered algorithm that supports the export key operation, then
1286                // throw a NotSupportedError.
1287                //
1288                // NOTE: We rely on [`normalize_algorithm`] to check whether the algorithm supports
1289                // the export key operation.
1290                let export_key_algorithm = match normalize_algorithm::<ExportKeyOperation>(
1291                    cx,
1292                    &AlgorithmIdentifier::String(DOMString::from(key.algorithm().name().as_str())),
1293                ) {
1294                    Ok(normalized_algorithm) => normalized_algorithm,
1295                    Err(error) => {
1296                        subtle.reject_promise_with_error(promise, error);
1297                        return;
1298                    },
1299                };
1300
1301                // Step 7. If the [[extractable]] internal slot of key is false, then throw an
1302                // InvalidAccessError.
1303                if !key.Extractable() {
1304                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
1305                    return;
1306                }
1307
1308                // Step 8. Let result be the result of performing the export key operation
1309                // specified by the [[algorithm]] internal slot of key using key and format.
1310                let result = match export_key_algorithm.export_key(format, &key) {
1311                    Ok(exported_key) => exported_key,
1312                    Err(error) => {
1313                        subtle.reject_promise_with_error(promise, error);
1314                        return;
1315                    },
1316                };
1317
1318                // Step 9. Queue a global task on the crypto task source, given realm's global
1319                // object, to perform the remaining steps.
1320                // Step 10.
1321                // If format is equal to the string "jwk":
1322                //     Let result be the result of converting result to an ECMAScript Object in
1323                //     realm, as defined by [WebIDL].
1324                // Otherwise:
1325                //     Let result be the result of creating an ArrayBuffer in realm, containing
1326                //     result.
1327                // Step 11. Resolve promise with result.
1328                // NOTE: We determine the format by pattern matching on result, which is an
1329                // ExportedKey enum.
1330                match result {
1331                    ExportedKey::Bytes(bytes) => {
1332                        subtle.resolve_promise_with_data(promise, bytes);
1333                    },
1334                    ExportedKey::Jwk(jwk) => {
1335                        subtle.resolve_promise_with_jwk(cx, promise, jwk);
1336                    },
1337                }
1338            }));
1339        promise
1340    }
1341
1342    /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-wrapKey>
1343    fn WrapKey(
1344        &self,
1345        cx: &mut CurrentRealm,
1346        format: KeyFormat,
1347        key: &CryptoKey,
1348        wrapping_key: &CryptoKey,
1349        algorithm: AlgorithmIdentifier,
1350    ) -> Rc<Promise> {
1351        // Step 1. Let format, key, wrappingKey and algorithm be the format, key, wrappingKey and
1352        // wrapAlgorithm parameters passed to the wrapKey() method, respectively.
1353        // NOTE: We did that in method parameter.
1354
1355        // Step 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
1356        // to algorithm and op set to "wrapKey".
1357        // Step 3. If an error occurred, let normalizedAlgorithm be the result of normalizing an
1358        // algorithm, with alg set to algorithm and op set to "encrypt".
1359        // Step 4. If an error occurred, return a Promise rejected with normalizedAlgorithm.
1360        enum WrapKeyAlgorithmOrEncryptAlgorithm {
1361            WrapKeyAlgorithm(WrapKeyAlgorithm),
1362            EncryptAlgorithm(EncryptAlgorithm),
1363        }
1364        let normalized_algorithm = if let Ok(algorithm) =
1365            normalize_algorithm::<WrapKeyOperation>(cx, &algorithm)
1366        {
1367            WrapKeyAlgorithmOrEncryptAlgorithm::WrapKeyAlgorithm(algorithm)
1368        } else {
1369            match normalize_algorithm::<EncryptOperation>(cx, &algorithm) {
1370                Ok(algorithm) => WrapKeyAlgorithmOrEncryptAlgorithm::EncryptAlgorithm(algorithm),
1371                Err(error) => {
1372                    let promise = Promise::new_in_realm(cx);
1373                    promise.reject_error(error, CanGc::from_cx(cx));
1374                    return promise;
1375                },
1376            }
1377        };
1378
1379        // Step 5. Let realm be the relevant realm of this.
1380        // Step 6. Let promise be a new Promise.
1381        let promise = Promise::new_in_realm(cx);
1382
1383        // Step 7. Return promise and perform the remaining steps in parallel.
1384        let trusted_subtle = Trusted::new(self);
1385        let trusted_key = Trusted::new(key);
1386        let trusted_wrapping_key = Trusted::new(wrapping_key);
1387        let trusted_promise = TrustedPromise::new(promise.clone());
1388        self.global()
1389            .task_manager()
1390            .dom_manipulation_task_source()
1391            .queue(task!(wrap_key: move |cx| {
1392                let subtle = trusted_subtle.root();
1393                let key = trusted_key.root();
1394                let wrapping_key = trusted_wrapping_key.root();
1395                let promise = trusted_promise.root();
1396
1397                // Step 8. If the following steps or referenced procedures say to throw an error,
1398                // queue a global task on the crypto task source, given realm's global object, to
1399                // reject promise with the returned error; and then terminate the algorithm.
1400
1401                // Step 9. If the name member of normalizedAlgorithm is not equal to the name
1402                // attribute of the [[algorithm]] internal slot of wrappingKey then throw an
1403                // InvalidAccessError.
1404                let normalized_algorithm_name = match &normalized_algorithm {
1405                    WrapKeyAlgorithmOrEncryptAlgorithm::WrapKeyAlgorithm(algorithm) => {
1406                        algorithm.name()
1407                    },
1408                    WrapKeyAlgorithmOrEncryptAlgorithm::EncryptAlgorithm(algorithm) => {
1409                        algorithm.name()
1410                    },
1411                };
1412                if normalized_algorithm_name != wrapping_key.algorithm().name() {
1413                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
1414                    return;
1415                }
1416
1417                // Step 10. If the [[usages]] internal slot of wrappingKey does not contain an
1418                // entry that is "wrapKey", then throw an InvalidAccessError.
1419                if !wrapping_key.usages().contains(&KeyUsage::WrapKey) {
1420                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
1421                    return;
1422                }
1423
1424                // Step 11. If the algorithm identified by the [[algorithm]] internal slot of key
1425                // does not support the export key operation, then throw a NotSupportedError.
1426                //
1427                // NOTE: We rely on [`normalize_algorithm`] to check whether the algorithm supports
1428                // the export key operation.
1429                let export_key_algorithm = match normalize_algorithm::<ExportKeyOperation>(
1430                    cx,
1431                    &AlgorithmIdentifier::String(DOMString::from(key.algorithm().name().as_str())),
1432                ) {
1433                    Ok(normalized_algorithm) => normalized_algorithm,
1434                    Err(error) => {
1435                        subtle.reject_promise_with_error(promise, error);
1436                        return;
1437                    },
1438                };
1439
1440                // Step 12. If the [[extractable]] internal slot of key is false, then throw an
1441                // InvalidAccessError.
1442                if !key.Extractable() {
1443                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
1444                    return;
1445                }
1446
1447                // Step 13. Let exportedKey be the result of performing the export key operation
1448                // specified by the [[algorithm]] internal slot of key using key and format.
1449                let exported_key = match export_key_algorithm.export_key(format, &key) {
1450                    Ok(exported_key) => exported_key,
1451                    Err(error) => {
1452                        subtle.reject_promise_with_error(promise, error);
1453                        return;
1454                    },
1455                };
1456
1457                // Step 14.
1458                // If format is equal to the string "jwk":
1459                //     Step 14.1. Let json be the result of representing exportedKey as a UTF-16
1460                //     string conforming to the JSON grammar; for example, by executing the
1461                //     JSON.stringify algorithm specified in [ECMA-262] in the context of a new
1462                //     global object.
1463                //     Step 14.2. Let bytes be the result of UTF-8 encoding json.
1464                // Otherwise:
1465                //     Let bytes be exportedKey.
1466                // NOTE: We determine the format by pattern matching on result, which is an
1467                // ExportedKey enum.
1468                let bytes = match exported_key {
1469                    ExportedKey::Bytes(bytes) => bytes,
1470                    ExportedKey::Jwk(jwk) => match jwk.stringify(cx) {
1471                        Ok(stringified_jwk) => stringified_jwk.as_bytes().to_vec(),
1472                        Err(error) => {
1473                            subtle.reject_promise_with_error(promise, error);
1474                            return;
1475                        },
1476                    },
1477                };
1478
1479                // Step 15.
1480                // If normalizedAlgorithm supports the wrap key operation:
1481                //     Let result be the result of performing the wrap key operation specified by
1482                //     normalizedAlgorithm using algorithm, wrappingKey as key and bytes as
1483                //     plaintext.
1484                // Otherwise, if normalizedAlgorithm supports the encrypt operation:
1485                //     Let result be the result of performing the encrypt operation specified by
1486                //     normalizedAlgorithm using algorithm, wrappingKey as key and bytes as
1487                //     plaintext.
1488                // Otherwise:
1489                //     throw a NotSupportedError.
1490                let result = match normalized_algorithm {
1491                    WrapKeyAlgorithmOrEncryptAlgorithm::WrapKeyAlgorithm(algorithm) => {
1492                        algorithm.wrap_key(&wrapping_key, &bytes)
1493                    },
1494                    WrapKeyAlgorithmOrEncryptAlgorithm::EncryptAlgorithm(algorithm) => {
1495                        algorithm.encrypt(&wrapping_key, &bytes)
1496                    },
1497                };
1498                let result = match result {
1499                    Ok(result) => result,
1500                    Err(error) => {
1501                        subtle.reject_promise_with_error(promise, error);
1502                        return;
1503                    },
1504                };
1505
1506                // Step 16. Queue a global task on the crypto task source, given realm's global
1507                // object, to perform the remaining steps.
1508                // Step 17. Let result be the result of creating an ArrayBuffer in realm,
1509                // containing result.
1510                // Step 18. Resolve promise with result.
1511                subtle.resolve_promise_with_data(promise, result);
1512            }));
1513        promise
1514    }
1515
1516    /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-unwrapKey>
1517    fn UnwrapKey(
1518        &self,
1519        cx: &mut CurrentRealm,
1520        format: KeyFormat,
1521        wrapped_key: ArrayBufferViewOrArrayBuffer,
1522        unwrapping_key: &CryptoKey,
1523        algorithm: AlgorithmIdentifier,
1524        unwrapped_key_algorithm: AlgorithmIdentifier,
1525        extractable: bool,
1526        usages: Vec<KeyUsage>,
1527    ) -> Rc<Promise> {
1528        // Step 1. Let format, unwrappingKey, algorithm, unwrappedKeyAlgorithm, extractable and
1529        // usages, be the format, unwrappingKey, unwrapAlgorithm, unwrappedKeyAlgorithm,
1530        // extractable and keyUsages parameters passed to the unwrapKey() method, respectively.
1531        // NOTE: We did that in method parameter.
1532
1533        // Step 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
1534        // to algorithm and op set to "unwrapKey".
1535        // Step 3. If an error occurred, let normalizedAlgorithm be the result of normalizing an
1536        // algorithm, with alg set to algorithm and op set to "decrypt".
1537        // Step 4. If an error occurred, return a Promise rejected with normalizedAlgorithm.
1538        enum UnwrapKeyAlgorithmOrDecryptAlgorithm {
1539            UnwrapKeyAlgorithm(UnwrapKeyAlgorithm),
1540            DecryptAlgorithm(DecryptAlgorithm),
1541        }
1542        let normalized_algorithm = if let Ok(algorithm) =
1543            normalize_algorithm::<UnwrapKeyOperation>(cx, &algorithm)
1544        {
1545            UnwrapKeyAlgorithmOrDecryptAlgorithm::UnwrapKeyAlgorithm(algorithm)
1546        } else {
1547            match normalize_algorithm::<DecryptOperation>(cx, &algorithm) {
1548                Ok(algorithm) => UnwrapKeyAlgorithmOrDecryptAlgorithm::DecryptAlgorithm(algorithm),
1549                Err(error) => {
1550                    let promise = Promise::new_in_realm(cx);
1551                    promise.reject_error(error, CanGc::from_cx(cx));
1552                    return promise;
1553                },
1554            }
1555        };
1556
1557        // Step 5. Let normalizedKeyAlgorithm be the result of normalizing an algorithm, with alg
1558        // set to unwrappedKeyAlgorithm and op set to "importKey".
1559        // Step 6. If an error occurred, return a Promise rejected with normalizedKeyAlgorithm.
1560        let normalized_key_algorithm =
1561            match normalize_algorithm::<ImportKeyOperation>(cx, &unwrapped_key_algorithm) {
1562                Ok(algorithm) => algorithm,
1563                Err(error) => {
1564                    let promise = Promise::new_in_realm(cx);
1565                    promise.reject_error(error, CanGc::from_cx(cx));
1566                    return promise;
1567                },
1568            };
1569
1570        // Step 7. Let wrappedKey be the result of getting a copy of the bytes held by the
1571        // wrappedKey parameter passed to the unwrapKey() method.
1572        let wrapped_key = match wrapped_key {
1573            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
1574            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
1575        };
1576
1577        // Step 8. Let realm be the relevant realm of this.
1578        // Step 9. Let promise be a new Promise.
1579        let promise = Promise::new_in_realm(cx);
1580
1581        // Step 10. Return promise and perform the remaining steps in parallel.
1582        let trusted_subtle = Trusted::new(self);
1583        let trusted_unwrapping_key = Trusted::new(unwrapping_key);
1584        let trusted_promise = TrustedPromise::new(promise.clone());
1585        self.global().task_manager().dom_manipulation_task_source().queue(
1586            task!(unwrap_key: move |cx| {
1587                let subtle = trusted_subtle.root();
1588                let unwrapping_key = trusted_unwrapping_key.root();
1589                let promise = trusted_promise.root();
1590
1591                // Step 11. If the following steps or referenced procedures say to throw an error,
1592                // queue a global task on the crypto task source, given realm's global object, to
1593                // reject promise with the returned error; and then terminate the algorithm.
1594
1595                // Step 12. If the name member of normalizedAlgorithm is not equal to the name
1596                // attribute of the [[algorithm]] internal slot of unwrappingKey then throw an
1597                // InvalidAccessError.
1598                let normalized_algorithm_name = match &normalized_algorithm {
1599                    UnwrapKeyAlgorithmOrDecryptAlgorithm::UnwrapKeyAlgorithm(algorithm) => {
1600                        algorithm.name()
1601                    },
1602                    UnwrapKeyAlgorithmOrDecryptAlgorithm::DecryptAlgorithm(algorithm) => {
1603                        algorithm.name()
1604                    },
1605                };
1606                if normalized_algorithm_name != unwrapping_key.algorithm().name() {
1607                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
1608                    return;
1609                }
1610
1611                // Step 13. If the [[usages]] internal slot of unwrappingKey does not contain an
1612                // entry that is "unwrapKey", then throw an InvalidAccessError.
1613                if !unwrapping_key.usages().contains(&KeyUsage::UnwrapKey) {
1614                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
1615                    return;
1616                }
1617
1618                // Step 14.
1619                // If normalizedAlgorithm supports an unwrap key operation:
1620                //     Let bytes be the result of performing the unwrap key operation specified by
1621                //     normalizedAlgorithm using algorithm, unwrappingKey as key and wrappedKey as
1622                //     ciphertext.
1623                // Otherwise, if normalizedAlgorithm supports a decrypt operation:
1624                //     Let bytes be the result of performing the decrypt operation specified by
1625                //     normalizedAlgorithm using algorithm, unwrappingKey as key and wrappedKey as
1626                //     ciphertext.
1627                // Otherwise:
1628                //     throw a NotSupportedError.
1629                let bytes = match normalized_algorithm {
1630                    UnwrapKeyAlgorithmOrDecryptAlgorithm::UnwrapKeyAlgorithm(algorithm) => {
1631                        algorithm.unwrap_key(&unwrapping_key, &wrapped_key)
1632                    },
1633                    UnwrapKeyAlgorithmOrDecryptAlgorithm::DecryptAlgorithm(algorithm) => {
1634                        algorithm.decrypt(&unwrapping_key, &wrapped_key)
1635                    },
1636                };
1637                let bytes = match bytes {
1638                    Ok(bytes) => bytes,
1639                    Err(error) => {
1640                        subtle.reject_promise_with_error(promise, error);
1641                        return;
1642                    },
1643                };
1644
1645                // Step 15.
1646                // If format is equal to the string "jwk":
1647                //     Let key be the result of executing the parse a JWK algorithm, with bytes as
1648                //     the data to be parsed.
1649                //     NOTE: We only parse bytes by executing the parse a JWK algorithm, but keep
1650                //     it as raw bytes for later steps, instead of converting it to a JsonWebKey
1651                //     dictionary.
1652                //
1653                // Otherwise:
1654                //     Let key be bytes.
1655                if format == KeyFormat::Jwk {
1656                    if let Err(error) = JsonWebKey::parse(cx, &bytes) {
1657                        subtle.reject_promise_with_error(promise, error);
1658                        return;
1659                    }
1660                }
1661                let key = bytes;
1662
1663                // Step 16. Let result be the result of performing the import key operation
1664                // specified by normalizedKeyAlgorithm using unwrappedKeyAlgorithm as algorithm,
1665                // format, usages and extractable and with key as keyData.
1666                let result = match normalized_key_algorithm.import_key(
1667                    cx,
1668                    &subtle.global(),
1669                    format,
1670                    &key,
1671                    extractable,
1672                    usages.clone(),
1673                ) {
1674                    Ok(result) => result,
1675                    Err(error) => {
1676                        subtle.reject_promise_with_error(promise, error);
1677                        return;
1678                    },
1679                };
1680
1681                // Step 17. If the [[type]] internal slot of result is "secret" or "private" and
1682                // usages is empty, then throw a SyntaxError.
1683                if matches!(result.Type(), KeyType::Secret | KeyType::Private) && usages.is_empty() {
1684                    subtle.reject_promise_with_error(promise, Error::Syntax(None));
1685                    return;
1686                }
1687
1688                // Step 18. Set the [[extractable]] internal slot of result to extractable.
1689                // Step 19. Set the [[usages]] internal slot of result to the normalized value of
1690                // usages.
1691                // NOTE: Done by normalized_algorithm.import_key in Step 16.
1692
1693                // Step 20. Queue a global task on the crypto task source, given realm's global
1694                // object, to perform the remaining steps.
1695                // Step 21. Let result be the result of converting result to an ECMAScript Object
1696                // in realm, as defined by [WebIDL].
1697                // Step 22. Resolve promise with result.
1698                subtle.resolve_promise_with_key(promise, result);
1699            }),
1700        );
1701        promise
1702    }
1703
1704    /// <https://wicg.github.io/webcrypto-modern-algos/#SubtleCrypto-method-encapsulateKey>
1705    fn EncapsulateKey(
1706        &self,
1707        cx: &mut CurrentRealm,
1708        encapsulation_algorithm: AlgorithmIdentifier,
1709        encapsulation_key: &CryptoKey,
1710        shared_key_algorithm: AlgorithmIdentifier,
1711        extractable: bool,
1712        usages: Vec<KeyUsage>,
1713    ) -> Rc<Promise> {
1714        // Step 1. Let encapsulationAlgorithm, encapsulationKey, sharedKeyAlgorithm, extractable
1715        // and usages be the encapsulationAlgorithm, encapsulationKey, sharedKeyAlgorithm,
1716        // extractable and keyUsages parameters passed to the encapsulateKey() method,
1717        // respectively.
1718
1719        // Step 2. Let normalizedEncapsulationAlgorithm be the result of normalizing an algorithm,
1720        // with alg set to encapsulationAlgorithm and op set to "encapsulate".
1721        // Step 3. If an error occurred, return a Promise rejected with
1722        // normalizedEncapsulationAlgorithm.
1723        let promise = Promise::new_in_realm(cx);
1724        let normalized_encapsulation_algorithm =
1725            match normalize_algorithm::<EncapsulateOperation>(cx, &encapsulation_algorithm) {
1726                Ok(algorithm) => algorithm,
1727                Err(error) => {
1728                    promise.reject_error(error, CanGc::from_cx(cx));
1729                    return promise;
1730                },
1731            };
1732
1733        // Step 4. Let normalizedSharedKeyAlgorithm be the result of normalizing an algorithm, with
1734        // alg set to sharedKeyAlgorithm and op set to "importKey".
1735        // Step 5. If an error occurred, return a Promise rejected with
1736        // normalizedSharedKeyAlgorithm.
1737        let normalized_shared_key_algorithm =
1738            match normalize_algorithm::<ImportKeyOperation>(cx, &shared_key_algorithm) {
1739                Ok(algorithm) => algorithm,
1740                Err(error) => {
1741                    promise.reject_error(error, CanGc::from_cx(cx));
1742                    return promise;
1743                },
1744            };
1745
1746        // Step 6. Let realm be the relevant realm of this.
1747        // Step 7. Let promise be a new Promise.
1748        // NOTE: We did that in preparation of Step 3.
1749
1750        // Step 8. Return promise and perform the remaining steps in parallel.
1751        let trusted_subtle = Trusted::new(self);
1752        let trusted_encapsulated_key = Trusted::new(encapsulation_key);
1753        let trusted_promise = TrustedPromise::new(promise.clone());
1754        self.global().task_manager().dom_manipulation_task_source().queue(
1755            task!(encapsulate_keys: move |cx| {
1756                let subtle = trusted_subtle.root();
1757                let encapsulation_key = trusted_encapsulated_key.root();
1758                let promise = trusted_promise.root();
1759
1760                // Step 9. If the following steps or referenced procedures say to throw an error,
1761                // queue a global task on the crypto task source, given realm's global object, to
1762                // reject promise with the returned error; and then terminate the algorithm.
1763
1764                // Step 10. If the name member of normalizedEncapsulationAlgorithm is not equal to
1765                // the name attribute of the [[algorithm]] internal slot of encapsulationKey then
1766                // throw an InvalidAccessError.
1767                if normalized_encapsulation_algorithm.name() != encapsulation_key.algorithm().name() {
1768                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(Some(
1769                        "[[algorithm]] internal slot of encapsulationKey is not equal to \
1770                        normalizedEncapsulationAlgorithm".to_string(),
1771                    )));
1772                    return;
1773                }
1774
1775                // Step 11. If the [[usages]] internal slot of encapsulationKey does not contain an
1776                // entry that is "encapsulateKey", then throw an InvalidAccessError.
1777                if !encapsulation_key.usages().contains(&KeyUsage::EncapsulateKey) {
1778                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(Some(
1779                        "[[usages]] internal slot of encapsulationKey does not contain an \
1780                        entry that is \"encapsulateBits\"".to_string(),
1781                    )));
1782                    return;
1783                }
1784
1785                // Step 12. Let encapsulatedBits be the result of performing the encapsulate
1786                // operation specified by the [[algorithm]] internal slot of encapsulationKey using
1787                // encapsulationKey.
1788                // NOTE: Step 10 guarantees normalizedEncapsulationAlgorithm specifies the same
1789                // algorithm as the [[algorithm]] internal slot of encapsulationKey.
1790                let encapsulated_bits_result =
1791                    normalized_encapsulation_algorithm.encapsulate(&encapsulation_key);
1792                let encapsulated_bits = match encapsulated_bits_result {
1793                    Ok(encapsulated_bits) => encapsulated_bits,
1794                    Err(error) => {
1795                        subtle.reject_promise_with_error(promise, error);
1796                        return;
1797                    },
1798                };
1799
1800                // Step 13. Let sharedKey be the result of performing the import key operation
1801                // specified by normalizedSharedKeyAlgorithm using "raw-secret" as format, the
1802                // sharedKey field of encapsulatedBits as keyData, sharedKeyAlgorithm as algorithm
1803                // and using extractable and usages.
1804                // Step 14. Set the [[extractable]] internal slot of sharedKey to extractable.
1805                // Step 15. Set the [[usages]] internal slot of sharedKey to the normalized value
1806                // of usages.
1807                let encapsulated_shared_key = match &encapsulated_bits.shared_key {
1808                    Some(shared_key) => shared_key,
1809                    None => {
1810                        subtle.reject_promise_with_error(promise, Error::Operation(Some(
1811                            "Shared key is missing in the result of the encapsulate operation"
1812                                .to_string())));
1813                        return;
1814                    },
1815                };
1816                let shared_key_result = normalized_shared_key_algorithm.import_key(
1817                    cx,
1818                    &subtle.global(),
1819                    KeyFormat::Raw_secret,
1820                    encapsulated_shared_key,
1821                    extractable,
1822                    usages.clone(),
1823                );
1824                let shared_key = match shared_key_result {
1825                    Ok(shared_key) => shared_key,
1826                    Err(error) => {
1827                        subtle.reject_promise_with_error(promise, error);
1828                        return;
1829                    },
1830                };
1831
1832                // Step 16. Let encapsulatedKey be a new EncapsulatedKey dictionary with sharedKey
1833                // set to sharedKey and ciphertext set to the ciphertext field of encapsulatedBits.
1834                let encapsulated_key = SubtleEncapsulatedKey {
1835                    shared_key: Some(Trusted::new(&shared_key)),
1836                    ciphertext:encapsulated_bits.ciphertext,
1837                };
1838
1839                // Step 17. Queue a global task on the crypto task source, given realm's global
1840                // object, to perform the remaining steps.
1841                // Step 18. Let result be the result of converting encapsulatedKey to an ECMAScript
1842                // Object in realm, as defined by [WebIDL].
1843                // Step 19. Resolve promise with result.
1844                subtle.resolve_promise_with_encapsulated_key(promise, encapsulated_key);
1845            })
1846        );
1847        promise
1848    }
1849
1850    /// <https://wicg.github.io/webcrypto-modern-algos/#SubtleCrypto-method-encapsulateBits>
1851    fn EncapsulateBits(
1852        &self,
1853        cx: &mut CurrentRealm,
1854        encapsulation_algorithm: AlgorithmIdentifier,
1855        encapsulation_key: &CryptoKey,
1856    ) -> Rc<Promise> {
1857        // Step 1. Let encapsulationAlgorithm and encapsulationKey be the encapsulationAlgorithm
1858        // and encapsulationKey parameters passed to the encapsulateBits() method, respectively.
1859
1860        // Step 2. Let normalizedEncapsulationAlgorithm be the result of normalizing an algorithm,
1861        // with alg set to encapsulationAlgorithm and op set to "encapsulate".
1862        // Step 3. If an error occurred, return a Promise rejected with
1863        // normalizedEncapsulationAlgorithm.
1864        let promise = Promise::new_in_realm(cx);
1865        let normalized_encapsulation_algorithm =
1866            match normalize_algorithm::<EncapsulateOperation>(cx, &encapsulation_algorithm) {
1867                Ok(algorithm) => algorithm,
1868                Err(error) => {
1869                    promise.reject_error(error, CanGc::from_cx(cx));
1870                    return promise;
1871                },
1872            };
1873
1874        // Step 4. Let realm be the relevant realm of this.
1875        // Step 5. Let promise be a new Promise.
1876        // NOTE: We did that in preparation of Step 3.
1877
1878        // Step 6. Return promise and perform the remaining steps in parallel.
1879        let trusted_subtle = Trusted::new(self);
1880        let trusted_encapsulation_key = Trusted::new(encapsulation_key);
1881        let trusted_promise = TrustedPromise::new(promise.clone());
1882        self.global().task_manager().dom_manipulation_task_source().queue(
1883            task!(derive_key: move || {
1884                let subtle = trusted_subtle.root();
1885                let encapsulation_key = trusted_encapsulation_key.root();
1886                let promise = trusted_promise.root();
1887
1888                // Step 7. If the following steps or referenced procedures say to throw an error,
1889                // queue a global task on the crypto task source, given realm's global object, to
1890                // reject promise with the returned error; and then terminate the algorithm.
1891
1892                // Step 8. If the name member of normalizedEncapsulationAlgorithm is not equal to
1893                // the name attribute of the [[algorithm]] internal slot of encapsulationKey then
1894                // throw an InvalidAccessError.
1895                if normalized_encapsulation_algorithm.name() != encapsulation_key.algorithm().name() {
1896                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(Some(
1897                        "[[algorithm]] internal slot of encapsulationKey is not equal to \
1898                        normalizedEncapsulationAlgorithm".to_string(),
1899                    )));
1900                    return;
1901                }
1902
1903                // Step 9. If the [[usages]] internal slot of encapsulationKey does not contain an
1904                // entry that is "encapsulateBits", then throw an InvalidAccessError.
1905                if !encapsulation_key.usages().contains(&KeyUsage::EncapsulateBits) {
1906                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(Some(
1907                        "[[usages]] internal slot of encapsulationKey does not contain an \
1908                        entry that is \"encapsulateBits\"".to_string(),
1909                    )));
1910                    return;
1911                }
1912
1913                // Step 10. Let encapsulatedBits be the result of performing the encapsulate
1914                // operation specified by the [[algorithm]] internal slot of encapsulationKey using
1915                // encapsulationKey.
1916                // NOTE: Step 8 guarantees normalizedEncapsulationAlgorithm specifies the same
1917                // algorithm as the [[algorithm]] internal slot of encapsulationKey.
1918                let encapsulated_bits =
1919                    match normalized_encapsulation_algorithm.encapsulate(&encapsulation_key) {
1920                        Ok(encapsulated_bits) => encapsulated_bits,
1921                        Err(error) => {
1922                            subtle.reject_promise_with_error(promise, error);
1923                            return;
1924                        },
1925                    };
1926
1927                // Step 11. Queue a global task on the crypto task source, given realm's global
1928                // object, to perform the remaining steps.
1929                // Step 12. Let result be the result of converting encapsulatedBits to an
1930                // ECMAScript Object in realm, as defined by [WebIDL].
1931                // Step 13. Resolve promise with result.
1932                subtle.resolve_promise_with_encapsulated_bits(promise, encapsulated_bits);
1933            }),
1934        );
1935        promise
1936    }
1937
1938    /// <https://wicg.github.io/webcrypto-modern-algos/#SubtleCrypto-method-decapsulateKey>
1939    fn DecapsulateKey(
1940        &self,
1941        cx: &mut CurrentRealm,
1942        decapsulation_algorithm: AlgorithmIdentifier,
1943        decapsulation_key: &CryptoKey,
1944        ciphertext: ArrayBufferViewOrArrayBuffer,
1945        shared_key_algorithm: AlgorithmIdentifier,
1946        extractable: bool,
1947        usages: Vec<KeyUsage>,
1948    ) -> Rc<Promise> {
1949        // Step 1. Let decapsulationAlgorithm, decapsulationKey, sharedKeyAlgorithm, extractable
1950        // and usages be the decapsulationAlgorithm, decapsulationKey, sharedKeyAlgorithm,
1951        // extractable and keyUsages parameters passed to the decapsulateKey() method,
1952        // respectively.
1953
1954        // Step 2. Let normalizedDecapsulationAlgorithm be the result of normalizing an algorithm,
1955        // with alg set to decapsulationAlgorithm and op set to "decapsulate".
1956        // Step 3. If an error occurred, return a Promise rejected with
1957        // normalizedDecapsulationAlgorithm.
1958        let normalized_decapsulation_algorithm =
1959            match normalize_algorithm::<DecapsulateOperation>(cx, &decapsulation_algorithm) {
1960                Ok(normalized_algorithm) => normalized_algorithm,
1961                Err(error) => {
1962                    let promise = Promise::new_in_realm(cx);
1963                    promise.reject_error(error, CanGc::from_cx(cx));
1964                    return promise;
1965                },
1966            };
1967
1968        // Step 4. Let normalizedSharedKeyAlgorithm be the result of normalizing an algorithm, with
1969        // alg set to sharedKeyAlgorithm and op set to "importKey".
1970        // Step 5. If an error occurred, return a Promise rejected with
1971        // normalizedSharedKeyAlgorithm.
1972        let normalized_shared_key_algorithm =
1973            match normalize_algorithm::<ImportKeyOperation>(cx, &shared_key_algorithm) {
1974                Ok(normalized_algorithm) => normalized_algorithm,
1975                Err(error) => {
1976                    let promise = Promise::new_in_realm(cx);
1977                    promise.reject_error(error, CanGc::from_cx(cx));
1978                    return promise;
1979                },
1980            };
1981
1982        // Step 6. Let ciphertext be the result of getting a copy of the bytes held by the
1983        // ciphertext parameter passed to the decapsulateKey() method.
1984        let ciphertext = match ciphertext {
1985            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
1986            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
1987        };
1988
1989        // Step 7. Let realm be the relevant realm of this.
1990        // Step 8. Let promise be a new Promise.
1991        let promise = Promise::new_in_realm(cx);
1992
1993        // Step 9. Return promise and perform the remaining steps in parallel.
1994        let trusted_subtle = Trusted::new(self);
1995        let trusted_decapsulation_key = Trusted::new(decapsulation_key);
1996        let trusted_promise = TrustedPromise::new(promise.clone());
1997        self.global()
1998            .task_manager()
1999            .dom_manipulation_task_source()
2000            .queue(task!(decapsulate_key: move |cx| {
2001                let subtle = trusted_subtle.root();
2002                let promise = trusted_promise.root();
2003                let decapsulation_key = trusted_decapsulation_key.root();
2004
2005                // Step 10. If the following steps or referenced procedures say to throw an error,
2006                // queue a global task on the crypto task source, given realm's global object, to
2007                // reject promise with the returned error; and then terminate the algorithm.
2008
2009                // Step 11. If the name member of normalizedDecapsulationAlgorithm is not equal to
2010                // the name attribute of the [[algorithm]] internal slot of decapsulationKey then
2011                // throw an InvalidAccessError.
2012                if normalized_decapsulation_algorithm.name() != decapsulation_key.algorithm().name() {
2013                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(Some(
2014                        "[[algorithm]] internal slot of decapsulationKey is not equal to \
2015                        normalizedDecapsulationAlgorithm".to_string()
2016                    )));
2017                    return;
2018                }
2019
2020                // Step 12. If the [[usages]] internal slot of decapsulationKey does not contain an
2021                // entry that is "decapsulateKey", then throw an InvalidAccessError.
2022                if !decapsulation_key.usages().contains(&KeyUsage::DecapsulateKey) {
2023                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(Some(
2024                        "[[usages]] internal slot of decapsulationKey does not contain an \
2025                        entry that is \"decapsulateBits\"".to_string(),
2026                    )));
2027                    return;
2028                }
2029
2030                // Step 13. Let decapsulatedBits be the result of performing the decapsulate
2031                // operation specified by the [[algorithm]] internal slot of decapsulationKey using
2032                // decapsulationKey and ciphertext.
2033                // NOTE: Step 11 guarantees normalizedDecapsulationAlgorithm specifies the same
2034                // algorithm as the [[algorithm]] internal slot of decapsulationKey.
2035                let decapsulated_bits_result =
2036                    normalized_decapsulation_algorithm.decapsulate(&decapsulation_key, &ciphertext);
2037                let decapsulated_bits = match decapsulated_bits_result {
2038                    Ok(decapsulated_bits) => decapsulated_bits,
2039                    Err(error) => {
2040                        subtle.reject_promise_with_error(promise, error);
2041                        return;
2042                    },
2043                };
2044
2045
2046                // Step 14. Let sharedKey be the result of performing the import key operation
2047                // specified by normalizedSharedKeyAlgorithm using "raw-secret" as format, the
2048                // decapsulatedBits as keyData, sharedKeyAlgorithm as algorithm and using
2049                // extractable and usages.
2050                // Step 15. Set the [[extractable]] internal slot of sharedKey to extractable.
2051                // Step 16. Set the [[usages]] internal slot of sharedKey to the normalized value
2052                // of usages.
2053                let shared_key_result = normalized_shared_key_algorithm.import_key(
2054                    cx,
2055                    &subtle.global(),
2056                    KeyFormat::Raw_secret,
2057                    &decapsulated_bits,
2058                    extractable,
2059                    usages.clone(),
2060                );
2061                let shared_key = match shared_key_result {
2062                    Ok(shared_key) => shared_key,
2063                    Err(error) => {
2064                        subtle.reject_promise_with_error(promise, error);
2065                        return;
2066                    },
2067                };
2068
2069
2070                // Step 17. Queue a global task on the crypto task source, given realm's global
2071                // object, to perform the remaining steps.
2072                // Step 18. Let result be the result of converting sharedKey to an ECMAScript
2073                // Object in realm, as defined by [WebIDL].
2074                // Step 19. Resolve promise with result.
2075                subtle.resolve_promise_with_key(promise, shared_key);
2076            }));
2077        promise
2078    }
2079
2080    /// <https://wicg.github.io/webcrypto-modern-algos/#SubtleCrypto-method-decapsulateBits>
2081    fn DecapsulateBits(
2082        &self,
2083        cx: &mut CurrentRealm,
2084        decapsulation_algorithm: AlgorithmIdentifier,
2085        decapsulation_key: &CryptoKey,
2086        ciphertext: ArrayBufferViewOrArrayBuffer,
2087    ) -> Rc<Promise> {
2088        // Step 1. Let decapsulationAlgorithm and decapsulationKey be the decapsulationAlgorithm
2089        // and decapsulationKey parameters passed to the decapsulateBits() method, respectively.
2090
2091        // Step 2. Let normalizedDecapsulationAlgorithm be the result of normalizing an algorithm,
2092        // with alg set to decapsulationAlgorithm and op set to "decapsulate".
2093        // Step 3. If an error occurred, return a Promise rejected with
2094        // normalizedDecapsulationAlgorithm.
2095        let normalized_decapsulation_algorithm =
2096            match normalize_algorithm::<DecapsulateOperation>(cx, &decapsulation_algorithm) {
2097                Ok(normalized_algorithm) => normalized_algorithm,
2098                Err(error) => {
2099                    let promise = Promise::new_in_realm(cx);
2100                    promise.reject_error(error, CanGc::from_cx(cx));
2101                    return promise;
2102                },
2103            };
2104
2105        // Step 4. Let ciphertext be the result of getting a copy of the bytes held by the
2106        // ciphertext parameter passed to the decapsulateBits() method.
2107        let ciphertext = match ciphertext {
2108            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2109            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2110        };
2111
2112        // Step 5. Let realm be the relevant realm of this.
2113        // Step 6. Let promise be a new Promise.
2114        let promise = Promise::new_in_realm(cx);
2115
2116        // Step 7. Return promise and perform the remaining steps in parallel.
2117        let trusted_subtle = Trusted::new(self);
2118        let trusted_decapsulation_key = Trusted::new(decapsulation_key);
2119        let trusted_promise = TrustedPromise::new(promise.clone());
2120        self.global()
2121            .task_manager()
2122            .dom_manipulation_task_source()
2123            .queue(task!(decapsulate_bits: move || {
2124                let subtle = trusted_subtle.root();
2125                let promise = trusted_promise.root();
2126                let decapsulation_key = trusted_decapsulation_key.root();
2127
2128                // Step 8. If the following steps or referenced procedures say to throw an error,
2129                // queue a global task on the crypto task source, given realm's global object, to
2130                // reject promise with the returned error; and then terminate the algorithm.
2131
2132                // Step 9. If the name member of normalizedDecapsulationAlgorithm is not equal to
2133                // the name attribute of the [[algorithm]] internal slot of decapsulationKey then
2134                // throw an InvalidAccessError.
2135                if normalized_decapsulation_algorithm.name() != decapsulation_key.algorithm().name() {
2136                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(Some(
2137                        "[[algorithm]] internal slot of decapsulationKey is not equal to \
2138                        normalizedDecapsulationAlgorithm".to_string()
2139                    )));
2140                    return;
2141                }
2142
2143                // Step 10. If the [[usages]] internal slot of decapsulationKey does not contain an
2144                // entry that is "decapsulateBits", then throw an InvalidAccessError.
2145                if !decapsulation_key.usages().contains(&KeyUsage::DecapsulateBits) {
2146                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(Some(
2147                        "[[usages]] internal slot of decapsulationKey does not contain an \
2148                        entry that is \"decapsulateBits\"".to_string(),
2149                    )));
2150                    return;
2151                }
2152
2153                // Step 11. Let decapsulatedBits be the result of performing the decapsulate
2154                // operation specified by the [[algorithm]] internal slot of decapsulationKey using
2155                // decapsulationKey and ciphertext.
2156                // NOTE: Step 9 guarantees normalizedDecapsulationAlgorithm specifies the same
2157                // algorithm as the [[algorithm]] internal slot of decapsulationKey.
2158                let decapsulated_bits_result =
2159                    normalized_decapsulation_algorithm.decapsulate(&decapsulation_key, &ciphertext);
2160                let decapsulated_bits = match decapsulated_bits_result {
2161                    Ok(decapsulated_bits) => decapsulated_bits,
2162                    Err(error) => {
2163                        subtle.reject_promise_with_error(promise, error);
2164                        return;
2165                    },
2166                };
2167
2168                // Step 12. Queue a global task on the crypto task source, given realm's global
2169                // object, to perform the remaining steps.
2170                // Step 13. Let result be the result of creating an ArrayBuffer in realm,
2171                // containing decapsulatedBits.
2172                // Step 14. Resolve promise with result.
2173                subtle.resolve_promise_with_data(promise, decapsulated_bits);
2174            }));
2175        promise
2176    }
2177
2178    /// <https://wicg.github.io/webcrypto-modern-algos/#SubtleCrypto-method-getPublicKey>
2179    fn GetPublicKey(
2180        &self,
2181        cx: &mut CurrentRealm,
2182        key: &CryptoKey,
2183        usages: Vec<KeyUsage>,
2184    ) -> Rc<Promise> {
2185        // Step 1. Let key and usages be the key and keyUsages parameters passed to the
2186        // getPublicKey() method, respectively.
2187
2188        // Step 2. Let algorithm be the [[algorithm]] internal slot of key.
2189        let algorithm = key.algorithm();
2190
2191        // Step 3. If the cryptographic algorithm identified by algorithm does not support deriving
2192        // a public key from a private key, then return a Promise rejected with a
2193        // NotSupportedError.
2194        //
2195        // NOTE: We rely on [`normalize_algorithm`] to check whether the algorithm supports the
2196        // getPublicKey operation.
2197        let get_public_key_algorithm = match normalize_algorithm::<GetPublicKeyOperation>(
2198            cx,
2199            &AlgorithmIdentifier::String(DOMString::from(algorithm.name().as_str())),
2200        ) {
2201            Ok(normalized_algorithm) => normalized_algorithm,
2202            Err(error) => {
2203                let promise = Promise::new_in_realm(cx);
2204                promise.reject_error(error, CanGc::from_cx(cx));
2205                return promise;
2206            },
2207        };
2208
2209        // Step 4. Let realm be the relevant realm of this.
2210        // Step 5. Let promise be a new Promise.
2211        let promise = Promise::new_in_realm(cx);
2212
2213        // Step 6. Return promise and perform the remaining steps in parallel.
2214        let trusted_subtle = Trusted::new(self);
2215        let trusted_promise = TrustedPromise::new(promise.clone());
2216        let trusted_key = Trusted::new(key);
2217        self.global()
2218            .task_manager()
2219            .dom_manipulation_task_source()
2220            .queue(task!(get_public_key: move |cx| {
2221                let subtle = trusted_subtle.root();
2222                let promise = trusted_promise.root();
2223                let key = trusted_key.root();
2224
2225                // Step 7. If the following steps or referenced procedures say to throw an error,
2226                // queue a global task on the crypto task source, given realm's global object, to
2227                // reject promise with the returned error; and then terminate the algorithm.
2228
2229                // Step 8. If the [[type]] internal slot of key is not "private", then throw an
2230                // InvalidAccessError.
2231                if key.Type() != KeyType::Private {
2232                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(Some(
2233                        "[[type]] internal slot of key is not \"private\"".to_string()
2234                    )));
2235                    return;
2236                }
2237
2238                // Step 9. If usages contains an entry which is not supported for a public key by
2239                // the algorithm identified by algorithm, then throw a SyntaxError.
2240                // Step 10. Let publicKey be a new CryptoKey representing the public key
2241                // corresponding to the private key represented by the [[handle]] internal slot of
2242                // key.
2243                // Step 11. If an error occurred, then throw a OperationError.
2244                // Step 12. Set the [[type]] internal slot of publicKey to "public".
2245                // Step 13. Set the [[algorithm]] internal slot of publicKey to algorithm.
2246                // Step 14. Set the [[extractable]] internal slot of publicKey to true.
2247                // Step 15. Set the [[usages]] internal slot of publicKey to usages.
2248                //
2249                // NOTE: We run these steps in the "getPublicKey" operations of the supported
2250                // cryptographic algorithms.
2251                let result = match get_public_key_algorithm.get_public_key(
2252                    cx,
2253                    &subtle.global(),
2254                    &key,
2255                    key.algorithm(),
2256                    usages.clone(),
2257                ) {
2258                    Ok(public_key) => public_key,
2259                    Err(error) => {
2260                        subtle.reject_promise_with_error(promise, error);
2261                        return;
2262                    },
2263                };
2264
2265                // Step 16. Queue a global task on the crypto task source, given realm's global
2266                // object, to perform the remaining steps.
2267                // Step 17. Let result be the result of converting publicKey to an ECMAScript
2268                // Object in realm, as defined by [WebIDL].
2269                // Step 18. Resolve promise with result.
2270                subtle.resolve_promise_with_key(promise, result);
2271            }));
2272        promise
2273    }
2274}
2275
2276/// Alternative to std::convert::TryFrom, with `&mut js::context::JSContext`
2277trait TryFromWithCx<T>: Sized {
2278    type Error;
2279
2280    fn try_from_with_cx(value: T, cx: &mut js::context::JSContext) -> Result<Self, Self::Error>;
2281}
2282
2283/// Alternative to std::convert::TryInto, with `&mut js::context::JSContext`
2284trait TryIntoWithCx<T>: Sized {
2285    type Error;
2286
2287    fn try_into_with_cx(self, cx: &mut js::context::JSContext) -> Result<T, Self::Error>;
2288}
2289
2290impl<T, U> TryIntoWithCx<U> for T
2291where
2292    U: TryFromWithCx<T>,
2293{
2294    type Error = U::Error;
2295
2296    fn try_into_with_cx(self, cx: &mut js::context::JSContext) -> Result<U, Self::Error> {
2297        U::try_from_with_cx(self, cx)
2298    }
2299}
2300
2301// These "subtle" structs are proxies for the codegen'd dicts which don't hold a DOMString
2302// so they can be sent safely when running steps in parallel.
2303
2304/// <https://w3c.github.io/webcrypto/#dfn-Algorithm>
2305#[derive(Clone, MallocSizeOf)]
2306struct SubtleAlgorithm {
2307    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2308    name: CryptoAlgorithm,
2309}
2310
2311impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleAlgorithm {
2312    type Error = Error;
2313
2314    fn try_from_with_cx(
2315        value: HandleValue<'a>,
2316        cx: &mut js::context::JSContext,
2317    ) -> Result<Self, Self::Error> {
2318        let dictionary = dictionary_from_jsval::<Algorithm>(cx, value)?;
2319
2320        Ok(SubtleAlgorithm {
2321            name: CryptoAlgorithm::from_domstring(&dictionary.name)?,
2322        })
2323    }
2324}
2325
2326/// <https://w3c.github.io/webcrypto/#dfn-KeyAlgorithm>
2327#[derive(Clone, MallocSizeOf)]
2328pub(crate) struct SubtleKeyAlgorithm {
2329    /// <https://w3c.github.io/webcrypto/#dom-keyalgorithm-name>
2330    name: CryptoAlgorithm,
2331}
2332
2333impl SafeToJSValConvertible for SubtleKeyAlgorithm {
2334    fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
2335        let dictionary = KeyAlgorithm {
2336            name: self.name.as_str().into(),
2337        };
2338        dictionary.safe_to_jsval(cx, rval, can_gc);
2339    }
2340}
2341
2342/// <https://w3c.github.io/webcrypto/#dfn-RsaHashedKeyGenParams>
2343#[derive(Clone, MallocSizeOf)]
2344pub(crate) struct SubtleRsaHashedKeyGenParams {
2345    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2346    name: CryptoAlgorithm,
2347
2348    /// <https://w3c.github.io/webcrypto/#dfn-RsaKeyGenParams-modulusLength>
2349    modulus_length: u32,
2350
2351    /// <https://w3c.github.io/webcrypto/#dfn-RsaKeyGenParams-publicExponent>
2352    public_exponent: Vec<u8>,
2353
2354    /// <https://w3c.github.io/webcrypto/#dfn-RsaHashedKeyGenParams-hash>
2355    hash: DigestAlgorithm,
2356}
2357
2358impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleRsaHashedKeyGenParams {
2359    type Error = Error;
2360
2361    fn try_from_with_cx(
2362        value: HandleValue,
2363        cx: &mut js::context::JSContext,
2364    ) -> Result<Self, Self::Error> {
2365        let dictionary =
2366            dictionary_from_jsval::<RootedTraceableBox<RsaHashedKeyGenParams>>(cx, value)?;
2367
2368        Ok(SubtleRsaHashedKeyGenParams {
2369            name: CryptoAlgorithm::from_domstring(&dictionary.parent.parent.name)?,
2370            modulus_length: dictionary.parent.modulusLength,
2371            public_exponent: dictionary.parent.publicExponent.to_vec(),
2372            hash: normalize_algorithm::<DigestOperation>(cx, &dictionary.hash)?,
2373        })
2374    }
2375}
2376
2377/// <https://w3c.github.io/webcrypto/#dfn-RsaHashedKeyAlgorithm>
2378#[derive(Clone, MallocSizeOf)]
2379pub(crate) struct SubtleRsaHashedKeyAlgorithm {
2380    /// <https://w3c.github.io/webcrypto/#dom-keyalgorithm-name>
2381    name: CryptoAlgorithm,
2382
2383    /// <https://w3c.github.io/webcrypto/#dfn-RsaKeyAlgorithm-modulusLength>
2384    modulus_length: u32,
2385
2386    /// <https://w3c.github.io/webcrypto/#dfn-RsaKeyAlgorithm-publicExponent>
2387    public_exponent: Vec<u8>,
2388
2389    /// <https://w3c.github.io/webcrypto/#dfn-RsaHashedKeyAlgorithm-hash>
2390    hash: DigestAlgorithm,
2391}
2392
2393impl SafeToJSValConvertible for SubtleRsaHashedKeyAlgorithm {
2394    fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
2395        rooted!(in(*cx) let mut js_object = ptr::null_mut::<JSObject>());
2396        let public_exponent =
2397            create_buffer_source(cx, &self.public_exponent, js_object.handle_mut(), can_gc)
2398                .expect("Fail to convert publicExponent to Uint8Array");
2399        let key_algorithm = KeyAlgorithm {
2400            name: self.name.as_str().into(),
2401        };
2402        let rsa_key_algorithm = RootedTraceableBox::new(RsaKeyAlgorithm {
2403            parent: key_algorithm,
2404            modulusLength: self.modulus_length,
2405            publicExponent: public_exponent,
2406        });
2407        let rsa_hashed_key_algorithm = RootedTraceableBox::new(RsaHashedKeyAlgorithm {
2408            parent: rsa_key_algorithm,
2409            hash: KeyAlgorithm {
2410                name: self.hash.name().as_str().into(),
2411            },
2412        });
2413        rsa_hashed_key_algorithm.safe_to_jsval(cx, rval, can_gc);
2414    }
2415}
2416
2417/// <https://w3c.github.io/webcrypto/#dfn-RsaHashedImportParams>
2418#[derive(Clone, MallocSizeOf)]
2419struct SubtleRsaHashedImportParams {
2420    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2421    name: CryptoAlgorithm,
2422
2423    /// <https://w3c.github.io/webcrypto/#dfn-RsaHashedImportParams-hash>
2424    hash: DigestAlgorithm,
2425}
2426
2427impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleRsaHashedImportParams {
2428    type Error = Error;
2429
2430    fn try_from_with_cx(
2431        value: HandleValue,
2432        cx: &mut js::context::JSContext,
2433    ) -> Result<Self, Self::Error> {
2434        let dictionary =
2435            dictionary_from_jsval::<RootedTraceableBox<RsaHashedImportParams>>(cx, value)?;
2436
2437        Ok(SubtleRsaHashedImportParams {
2438            name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
2439            hash: normalize_algorithm::<DigestOperation>(cx, &dictionary.hash)?,
2440        })
2441    }
2442}
2443
2444/// <https://w3c.github.io/webcrypto/#dfn-RsaPssParams>
2445#[derive(Clone, MallocSizeOf)]
2446struct SubtleRsaPssParams {
2447    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2448    name: CryptoAlgorithm,
2449
2450    /// <https://w3c.github.io/webcrypto/#dfn-RsaPssParams-saltLength>
2451    salt_length: u32,
2452}
2453
2454impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleRsaPssParams {
2455    type Error = Error;
2456
2457    fn try_from_with_cx(
2458        value: HandleValue,
2459        cx: &mut js::context::JSContext,
2460    ) -> Result<Self, Self::Error> {
2461        let dictionary = dictionary_from_jsval::<RsaPssParams>(cx, value)?;
2462
2463        Ok(SubtleRsaPssParams {
2464            name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
2465            salt_length: dictionary.saltLength,
2466        })
2467    }
2468}
2469
2470/// <https://w3c.github.io/webcrypto/#dfn-RsaOaepParams>
2471#[derive(Clone, MallocSizeOf)]
2472struct SubtleRsaOaepParams {
2473    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2474    name: CryptoAlgorithm,
2475
2476    /// <https://w3c.github.io/webcrypto/#dfn-RsaOaepParams-label>
2477    label: Option<Vec<u8>>,
2478}
2479
2480impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleRsaOaepParams {
2481    type Error = Error;
2482
2483    fn try_from_with_cx(
2484        value: HandleValue<'a>,
2485        cx: &mut js::context::JSContext,
2486    ) -> Result<Self, Self::Error> {
2487        let dictionary = dictionary_from_jsval::<RootedTraceableBox<RsaOaepParams>>(cx, value)?;
2488
2489        let label = dictionary.label.as_ref().map(|label| match label {
2490            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2491            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2492        });
2493
2494        Ok(SubtleRsaOaepParams {
2495            name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
2496            label,
2497        })
2498    }
2499}
2500
2501/// <https://w3c.github.io/webcrypto/#dfn-EcdsaParams>
2502#[derive(Clone, MallocSizeOf)]
2503struct SubtleEcdsaParams {
2504    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2505    name: CryptoAlgorithm,
2506
2507    /// <https://w3c.github.io/webcrypto/#dfn-EcdsaParams-hash>
2508    hash: DigestAlgorithm,
2509}
2510
2511impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleEcdsaParams {
2512    type Error = Error;
2513
2514    fn try_from_with_cx(
2515        value: HandleValue<'a>,
2516        cx: &mut js::context::JSContext,
2517    ) -> Result<Self, Self::Error> {
2518        let dictionary = dictionary_from_jsval::<RootedTraceableBox<EcdsaParams>>(cx, value)?;
2519
2520        Ok(SubtleEcdsaParams {
2521            name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
2522            hash: normalize_algorithm::<DigestOperation>(cx, &dictionary.hash)?,
2523        })
2524    }
2525}
2526
2527/// <https://w3c.github.io/webcrypto/#dfn-EcKeyGenParams>
2528#[derive(Clone, MallocSizeOf)]
2529struct SubtleEcKeyGenParams {
2530    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2531    name: CryptoAlgorithm,
2532
2533    /// <https://w3c.github.io/webcrypto/#dfn-EcKeyGenParams-namedCurve>
2534    named_curve: String,
2535}
2536
2537impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleEcKeyGenParams {
2538    type Error = Error;
2539
2540    fn try_from_with_cx(
2541        value: HandleValue<'a>,
2542        cx: &mut js::context::JSContext,
2543    ) -> Result<Self, Self::Error> {
2544        let dictionary = dictionary_from_jsval::<EcKeyGenParams>(cx, value)?;
2545
2546        Ok(SubtleEcKeyGenParams {
2547            name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
2548            named_curve: dictionary.namedCurve.to_string(),
2549        })
2550    }
2551}
2552
2553/// <https://w3c.github.io/webcrypto/#dfn-EcKeyAlgorithm>
2554#[derive(Clone, MallocSizeOf)]
2555pub(crate) struct SubtleEcKeyAlgorithm {
2556    /// <https://w3c.github.io/webcrypto/#dom-keyalgorithm-name>
2557    name: CryptoAlgorithm,
2558
2559    /// <https://w3c.github.io/webcrypto/#dfn-EcKeyAlgorithm-namedCurve>
2560    named_curve: String,
2561}
2562
2563impl SafeToJSValConvertible for SubtleEcKeyAlgorithm {
2564    fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
2565        let parent = KeyAlgorithm {
2566            name: self.name.as_str().into(),
2567        };
2568        let dictionary = EcKeyAlgorithm {
2569            parent,
2570            namedCurve: self.named_curve.clone().into(),
2571        };
2572        dictionary.safe_to_jsval(cx, rval, can_gc);
2573    }
2574}
2575
2576/// <https://w3c.github.io/webcrypto/#dfn-EcKeyImportParams>
2577#[derive(Clone, MallocSizeOf)]
2578struct SubtleEcKeyImportParams {
2579    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2580    name: CryptoAlgorithm,
2581
2582    /// <https://w3c.github.io/webcrypto/#dfn-EcKeyImportParams-namedCurve>
2583    named_curve: String,
2584}
2585
2586impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleEcKeyImportParams {
2587    type Error = Error;
2588
2589    fn try_from_with_cx(
2590        value: HandleValue<'a>,
2591        cx: &mut js::context::JSContext,
2592    ) -> Result<Self, Self::Error> {
2593        let dictionary = dictionary_from_jsval::<EcKeyImportParams>(cx, value)?;
2594
2595        Ok(SubtleEcKeyImportParams {
2596            name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
2597            named_curve: dictionary.namedCurve.to_string(),
2598        })
2599    }
2600}
2601
2602/// <https://w3c.github.io/webcrypto/#dfn-EcdhKeyDeriveParams>
2603#[derive(Clone, MallocSizeOf)]
2604struct SubtleEcdhKeyDeriveParams {
2605    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2606    name: CryptoAlgorithm,
2607
2608    /// <https://w3c.github.io/webcrypto/#dfn-EcdhKeyDeriveParams-public>
2609    public: Trusted<CryptoKey>,
2610}
2611
2612impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleEcdhKeyDeriveParams {
2613    type Error = Error;
2614
2615    fn try_from_with_cx(
2616        value: HandleValue<'a>,
2617        cx: &mut js::context::JSContext,
2618    ) -> Result<Self, Self::Error> {
2619        let dictionary = dictionary_from_jsval::<EcdhKeyDeriveParams>(cx, value)?;
2620
2621        Ok(SubtleEcdhKeyDeriveParams {
2622            name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
2623            public: Trusted::new(&dictionary.public),
2624        })
2625    }
2626}
2627
2628/// <https://w3c.github.io/webcrypto/#dfn-AesCtrParams>
2629#[derive(Clone, MallocSizeOf)]
2630struct SubtleAesCtrParams {
2631    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2632    name: CryptoAlgorithm,
2633
2634    /// <https://w3c.github.io/webcrypto/#dfn-AesCtrParams-counter>
2635    counter: Vec<u8>,
2636
2637    /// <https://w3c.github.io/webcrypto/#dfn-AesCtrParams-length>
2638    length: u8,
2639}
2640
2641impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleAesCtrParams {
2642    type Error = Error;
2643
2644    fn try_from_with_cx(
2645        value: HandleValue<'a>,
2646        cx: &mut js::context::JSContext,
2647    ) -> Result<Self, Self::Error> {
2648        let dictionary = dictionary_from_jsval::<RootedTraceableBox<AesCtrParams>>(cx, value)?;
2649
2650        let counter = match &dictionary.counter {
2651            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2652            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2653        };
2654
2655        Ok(SubtleAesCtrParams {
2656            name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
2657            counter,
2658            length: dictionary.length,
2659        })
2660    }
2661}
2662
2663/// <https://w3c.github.io/webcrypto/#dfn-AesKeyAlgorithm>
2664#[derive(Clone, MallocSizeOf)]
2665pub(crate) struct SubtleAesKeyAlgorithm {
2666    /// <https://w3c.github.io/webcrypto/#dom-keyalgorithm-name>
2667    name: CryptoAlgorithm,
2668
2669    /// <https://w3c.github.io/webcrypto/#dfn-AesKeyAlgorithm-length>
2670    length: u16,
2671}
2672
2673impl SafeToJSValConvertible for SubtleAesKeyAlgorithm {
2674    fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
2675        let parent = KeyAlgorithm {
2676            name: self.name.as_str().into(),
2677        };
2678        let dictionary = AesKeyAlgorithm {
2679            parent,
2680            length: self.length,
2681        };
2682        dictionary.safe_to_jsval(cx, rval, can_gc);
2683    }
2684}
2685
2686/// <https://w3c.github.io/webcrypto/#dfn-AesKeyGenParams>
2687#[derive(Clone, MallocSizeOf)]
2688struct SubtleAesKeyGenParams {
2689    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2690    name: CryptoAlgorithm,
2691
2692    /// <https://w3c.github.io/webcrypto/#dfn-AesKeyGenParams-length>
2693    length: u16,
2694}
2695
2696impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleAesKeyGenParams {
2697    type Error = Error;
2698
2699    fn try_from_with_cx(
2700        value: HandleValue<'a>,
2701        cx: &mut js::context::JSContext,
2702    ) -> Result<Self, Self::Error> {
2703        let dictionary = dictionary_from_jsval::<AesKeyGenParams>(cx, value)?;
2704
2705        Ok(SubtleAesKeyGenParams {
2706            name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
2707            length: dictionary.length,
2708        })
2709    }
2710}
2711
2712/// <https://w3c.github.io/webcrypto/#dfn-AesDerivedKeyParams>
2713#[derive(Clone, MallocSizeOf)]
2714struct SubtleAesDerivedKeyParams {
2715    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2716    name: CryptoAlgorithm,
2717
2718    /// <https://w3c.github.io/webcrypto/#dfn-AesDerivedKeyParams-length>
2719    length: u16,
2720}
2721
2722impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleAesDerivedKeyParams {
2723    type Error = Error;
2724
2725    fn try_from_with_cx(
2726        value: HandleValue<'a>,
2727        cx: &mut js::context::JSContext,
2728    ) -> Result<Self, Self::Error> {
2729        let dictionary = dictionary_from_jsval::<AesDerivedKeyParams>(cx, value)?;
2730
2731        Ok(SubtleAesDerivedKeyParams {
2732            name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
2733            length: dictionary.length,
2734        })
2735    }
2736}
2737
2738/// <https://w3c.github.io/webcrypto/#dfn-AesCbcParams>
2739#[derive(Clone, MallocSizeOf)]
2740struct SubtleAesCbcParams {
2741    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2742    name: CryptoAlgorithm,
2743
2744    /// <https://w3c.github.io/webcrypto/#dfn-AesCbcParams-iv>
2745    iv: Vec<u8>,
2746}
2747
2748impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleAesCbcParams {
2749    type Error = Error;
2750
2751    fn try_from_with_cx(
2752        value: HandleValue<'a>,
2753        cx: &mut js::context::JSContext,
2754    ) -> Result<Self, Self::Error> {
2755        let dictionary = dictionary_from_jsval::<RootedTraceableBox<AesCbcParams>>(cx, value)?;
2756
2757        let iv = match &dictionary.iv {
2758            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2759            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2760        };
2761
2762        Ok(SubtleAesCbcParams {
2763            name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
2764            iv,
2765        })
2766    }
2767}
2768
2769/// <https://w3c.github.io/webcrypto/#dfn-AesGcmParams>
2770#[derive(Clone, MallocSizeOf)]
2771struct SubtleAesGcmParams {
2772    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2773    name: CryptoAlgorithm,
2774
2775    /// <https://w3c.github.io/webcrypto/#dfn-AesGcmParams-iv>
2776    iv: Vec<u8>,
2777
2778    /// <https://w3c.github.io/webcrypto/#dfn-AesGcmParams-additionalData>
2779    additional_data: Option<Vec<u8>>,
2780
2781    /// <https://w3c.github.io/webcrypto/#dfn-AesGcmParams-tagLength>
2782    tag_length: Option<u8>,
2783}
2784
2785impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleAesGcmParams {
2786    type Error = Error;
2787
2788    fn try_from_with_cx(
2789        value: HandleValue<'a>,
2790        cx: &mut js::context::JSContext,
2791    ) -> Result<Self, Self::Error> {
2792        let dictionary = dictionary_from_jsval::<RootedTraceableBox<AesGcmParams>>(cx, value)?;
2793
2794        let iv = match &dictionary.iv {
2795            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2796            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2797        };
2798        let additional_data = dictionary.additionalData.as_ref().map(|data| match data {
2799            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2800            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2801        });
2802
2803        Ok(SubtleAesGcmParams {
2804            name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
2805            iv,
2806            additional_data,
2807            tag_length: dictionary.tagLength,
2808        })
2809    }
2810}
2811
2812/// <https://w3c.github.io/webcrypto/#dfn-HmacImportParams>
2813#[derive(Clone, MallocSizeOf)]
2814struct SubtleHmacImportParams {
2815    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2816    name: CryptoAlgorithm,
2817
2818    /// <https://w3c.github.io/webcrypto/#dfn-HmacImportParams-hash>
2819    hash: DigestAlgorithm,
2820
2821    /// <https://w3c.github.io/webcrypto/#dfn-HmacImportParams-length>
2822    length: Option<u32>,
2823}
2824
2825impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleHmacImportParams {
2826    type Error = Error;
2827
2828    fn try_from_with_cx(
2829        value: HandleValue<'a>,
2830        cx: &mut js::context::JSContext,
2831    ) -> Result<Self, Self::Error> {
2832        let dictionary = dictionary_from_jsval::<RootedTraceableBox<HmacImportParams>>(cx, value)?;
2833
2834        Ok(SubtleHmacImportParams {
2835            name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
2836            hash: normalize_algorithm::<DigestOperation>(cx, &dictionary.hash)?,
2837            length: dictionary.length,
2838        })
2839    }
2840}
2841
2842/// <https://w3c.github.io/webcrypto/#dfn-HmacKeyAlgorithm>
2843#[derive(Clone, MallocSizeOf)]
2844pub(crate) struct SubtleHmacKeyAlgorithm {
2845    /// <https://w3c.github.io/webcrypto/#dom-keyalgorithm-name>
2846    name: CryptoAlgorithm,
2847
2848    /// <https://w3c.github.io/webcrypto/#dfn-HmacKeyAlgorithm-hash>
2849    hash: SubtleKeyAlgorithm,
2850
2851    /// <https://w3c.github.io/webcrypto/#dfn-HmacKeyGenParams-length>
2852    length: u32,
2853}
2854
2855impl SafeToJSValConvertible for SubtleHmacKeyAlgorithm {
2856    fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
2857        let parent = KeyAlgorithm {
2858            name: self.name.as_str().into(),
2859        };
2860        let hash = KeyAlgorithm {
2861            name: self.hash.name.as_str().into(),
2862        };
2863        let dictionary = HmacKeyAlgorithm {
2864            parent,
2865            hash,
2866            length: self.length,
2867        };
2868        dictionary.safe_to_jsval(cx, rval, can_gc);
2869    }
2870}
2871
2872/// <https://w3c.github.io/webcrypto/#dfn-HmacKeyGenParams>
2873#[derive(Clone, MallocSizeOf)]
2874struct SubtleHmacKeyGenParams {
2875    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2876    name: CryptoAlgorithm,
2877
2878    /// <https://w3c.github.io/webcrypto/#dfn-HmacKeyGenParams-hash>
2879    hash: DigestAlgorithm,
2880
2881    /// <https://w3c.github.io/webcrypto/#dfn-HmacKeyGenParams-length>
2882    length: Option<u32>,
2883}
2884
2885impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleHmacKeyGenParams {
2886    type Error = Error;
2887
2888    fn try_from_with_cx(
2889        value: HandleValue<'a>,
2890        cx: &mut js::context::JSContext,
2891    ) -> Result<Self, Self::Error> {
2892        let dictionary = dictionary_from_jsval::<RootedTraceableBox<HmacKeyGenParams>>(cx, value)?;
2893
2894        Ok(SubtleHmacKeyGenParams {
2895            name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
2896            hash: normalize_algorithm::<DigestOperation>(cx, &dictionary.hash)?,
2897            length: dictionary.length,
2898        })
2899    }
2900}
2901
2902/// <https://w3c.github.io/webcrypto/#dfn-HkdfParams>
2903#[derive(Clone, MallocSizeOf)]
2904pub(crate) struct SubtleHkdfParams {
2905    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2906    name: CryptoAlgorithm,
2907
2908    /// <https://w3c.github.io/webcrypto/#dfn-HkdfParams-hash>
2909    hash: DigestAlgorithm,
2910
2911    /// <https://w3c.github.io/webcrypto/#dfn-HkdfParams-salt>
2912    salt: Vec<u8>,
2913
2914    /// <https://w3c.github.io/webcrypto/#dfn-HkdfParams-info>
2915    info: Vec<u8>,
2916}
2917
2918impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleHkdfParams {
2919    type Error = Error;
2920
2921    fn try_from_with_cx(
2922        value: HandleValue<'a>,
2923        cx: &mut js::context::JSContext,
2924    ) -> Result<Self, Self::Error> {
2925        let dictionary = dictionary_from_jsval::<RootedTraceableBox<HkdfParams>>(cx, value)?;
2926
2927        let salt = match &dictionary.salt {
2928            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2929            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2930        };
2931        let info = match &dictionary.info {
2932            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2933            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2934        };
2935
2936        Ok(SubtleHkdfParams {
2937            name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
2938            hash: normalize_algorithm::<DigestOperation>(cx, &dictionary.hash)?,
2939            salt,
2940            info,
2941        })
2942    }
2943}
2944
2945/// <https://w3c.github.io/webcrypto/#dfn-Pbkdf2Params>
2946#[derive(Clone, MallocSizeOf)]
2947pub(crate) struct SubtlePbkdf2Params {
2948    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2949    name: CryptoAlgorithm,
2950
2951    /// <https://w3c.github.io/webcrypto/#dfn-Pbkdf2Params-salt>
2952    salt: Vec<u8>,
2953
2954    /// <https://w3c.github.io/webcrypto/#dfn-Pbkdf2Params-iterations>
2955    iterations: u32,
2956
2957    /// <https://w3c.github.io/webcrypto/#dfn-Pbkdf2Params-hash>
2958    hash: DigestAlgorithm,
2959}
2960
2961impl<'a> TryFromWithCx<HandleValue<'a>> for SubtlePbkdf2Params {
2962    type Error = Error;
2963
2964    fn try_from_with_cx(
2965        value: HandleValue<'a>,
2966        cx: &mut js::context::JSContext,
2967    ) -> Result<Self, Self::Error> {
2968        let dictionary = dictionary_from_jsval::<RootedTraceableBox<Pbkdf2Params>>(cx, value)?;
2969
2970        let salt = match &dictionary.salt {
2971            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2972            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2973        };
2974
2975        Ok(SubtlePbkdf2Params {
2976            name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
2977            salt,
2978            iterations: dictionary.iterations,
2979            hash: normalize_algorithm::<DigestOperation>(cx, &dictionary.hash)?,
2980        })
2981    }
2982}
2983
2984/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-ContextParams>
2985#[derive(Clone, MallocSizeOf)]
2986struct SubtleContextParams {
2987    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2988    name: CryptoAlgorithm,
2989
2990    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-ContextParams-context>
2991    context: Option<Vec<u8>>,
2992}
2993
2994impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleContextParams {
2995    type Error = Error;
2996
2997    fn try_from_with_cx(
2998        value: HandleValue<'a>,
2999        cx: &mut js::context::JSContext,
3000    ) -> Result<Self, Self::Error> {
3001        let dictionary = dictionary_from_jsval::<RootedTraceableBox<ContextParams>>(cx, value)?;
3002
3003        let context = dictionary.context.as_ref().map(|context| match context {
3004            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
3005            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
3006        });
3007
3008        Ok(SubtleContextParams {
3009            name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
3010            context,
3011        })
3012    }
3013}
3014
3015/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-AeadParams>
3016#[derive(Clone, MallocSizeOf)]
3017struct SubtleAeadParams {
3018    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
3019    name: CryptoAlgorithm,
3020
3021    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-AeadParams-iv>
3022    iv: Vec<u8>,
3023
3024    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-AeadParams-additionalData>
3025    additional_data: Option<Vec<u8>>,
3026
3027    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-AeadParams-tagLength>
3028    tag_length: Option<u8>,
3029}
3030
3031impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleAeadParams {
3032    type Error = Error;
3033
3034    fn try_from_with_cx(
3035        value: HandleValue<'a>,
3036        cx: &mut js::context::JSContext,
3037    ) -> Result<Self, Self::Error> {
3038        let dictionary = dictionary_from_jsval::<RootedTraceableBox<AeadParams>>(cx, value)?;
3039
3040        let iv = match &dictionary.iv {
3041            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
3042            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
3043        };
3044        let additional_data = dictionary.additionalData.as_ref().map(|data| match data {
3045            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
3046            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
3047        });
3048
3049        Ok(SubtleAeadParams {
3050            name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
3051            iv,
3052            additional_data,
3053            tag_length: dictionary.tagLength,
3054        })
3055    }
3056}
3057
3058/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-CShakeParams>
3059#[derive(Clone, MallocSizeOf)]
3060struct SubtleCShakeParams {
3061    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
3062    name: CryptoAlgorithm,
3063
3064    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-CShakeParams-length>
3065    length: u32,
3066
3067    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-CShakeParams-functionName>
3068    function_name: Option<Vec<u8>>,
3069
3070    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-CShakeParams-customization>
3071    customization: Option<Vec<u8>>,
3072}
3073
3074impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleCShakeParams {
3075    type Error = Error;
3076
3077    fn try_from_with_cx(
3078        value: HandleValue<'a>,
3079        cx: &mut js::context::JSContext,
3080    ) -> Result<Self, Self::Error> {
3081        let dictionary = dictionary_from_jsval::<RootedTraceableBox<CShakeParams>>(cx, value)?;
3082
3083        let function_name =
3084            dictionary
3085                .functionName
3086                .as_ref()
3087                .map(|function_name| match function_name {
3088                    ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
3089                    ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
3090                });
3091        let customization =
3092            dictionary
3093                .customization
3094                .as_ref()
3095                .map(|customization| match customization {
3096                    ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
3097                    ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
3098                });
3099
3100        Ok(SubtleCShakeParams {
3101            name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
3102            length: dictionary.length,
3103            function_name,
3104            customization,
3105        })
3106    }
3107}
3108
3109/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params>
3110#[derive(Clone, MallocSizeOf)]
3111struct SubtleArgon2Params {
3112    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
3113    name: CryptoAlgorithm,
3114
3115    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-nonce>
3116    nonce: Vec<u8>,
3117
3118    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-parallelism>
3119    parallelism: u32,
3120
3121    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-memory>
3122    memory: u32,
3123
3124    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-passes>
3125    passes: u32,
3126
3127    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-version>
3128    version: Option<u8>,
3129
3130    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-secretValue>
3131    secret_value: Option<Vec<u8>>,
3132
3133    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-associatedData>
3134    associated_data: Option<Vec<u8>>,
3135}
3136
3137impl<'a> TryFromWithCx<HandleValue<'a>> for SubtleArgon2Params {
3138    type Error = Error;
3139
3140    fn try_from_with_cx(
3141        value: HandleValue<'a>,
3142        cx: &mut js::context::JSContext,
3143    ) -> Result<Self, Self::Error> {
3144        let dictionary = dictionary_from_jsval::<RootedTraceableBox<Argon2Params>>(cx, value)?;
3145
3146        let nonce = match &dictionary.nonce {
3147            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
3148            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
3149        };
3150        let secret_value = dictionary
3151            .secretValue
3152            .as_ref()
3153            .map(|secret_value| match secret_value {
3154                ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
3155                ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
3156            });
3157        let associated_data =
3158            dictionary
3159                .associatedData
3160                .as_ref()
3161                .map(|associated_data| match associated_data {
3162                    ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
3163                    ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
3164                });
3165
3166        Ok(SubtleArgon2Params {
3167            name: CryptoAlgorithm::from_domstring(&dictionary.parent.name)?,
3168            nonce,
3169            parallelism: dictionary.parallelism,
3170            memory: dictionary.memory,
3171            passes: dictionary.passes,
3172            version: dictionary.version,
3173            secret_value,
3174            associated_data,
3175        })
3176    }
3177}
3178
3179/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-EncapsulatedKey>
3180struct SubtleEncapsulatedKey {
3181    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-EncapsulatedKey-sharedKey>
3182    shared_key: Option<Trusted<CryptoKey>>,
3183
3184    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-EncapsulatedKey-ciphertext>
3185    ciphertext: Option<Vec<u8>>,
3186}
3187
3188impl SafeToJSValConvertible for SubtleEncapsulatedKey {
3189    fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
3190        let shared_key = self.shared_key.as_ref().map(|shared_key| shared_key.root());
3191        let ciphertext = self.ciphertext.as_ref().map(|data| {
3192            rooted!(in(*cx) let mut ciphertext_ptr = ptr::null_mut::<JSObject>());
3193            create_buffer_source::<ArrayBufferU8>(cx, data, ciphertext_ptr.handle_mut(), can_gc)
3194                .expect("Failed to convert ciphertext to ArrayBufferU8")
3195        });
3196        let encapsulated_key = RootedTraceableBox::new(EncapsulatedKey {
3197            sharedKey: shared_key,
3198            ciphertext,
3199        });
3200        encapsulated_key.safe_to_jsval(cx, rval, can_gc);
3201    }
3202}
3203
3204/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-EncapsulatedBits>
3205struct SubtleEncapsulatedBits {
3206    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-EncapsulatedBits-sharedKey>
3207    shared_key: Option<Vec<u8>>,
3208
3209    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-EncapsulatedBits-ciphertext>
3210    ciphertext: Option<Vec<u8>>,
3211}
3212
3213impl SafeToJSValConvertible for SubtleEncapsulatedBits {
3214    fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
3215        let shared_key = self.shared_key.as_ref().map(|data| {
3216            rooted!(in(*cx) let mut shared_key_ptr = ptr::null_mut::<JSObject>());
3217            create_buffer_source::<ArrayBufferU8>(cx, data, shared_key_ptr.handle_mut(), can_gc)
3218                .expect("Failed to convert shared key to ArrayBufferU8")
3219        });
3220        let ciphertext = self.ciphertext.as_ref().map(|data| {
3221            rooted!(in(*cx) let mut ciphertext_ptr = ptr::null_mut::<JSObject>());
3222            create_buffer_source::<ArrayBufferU8>(cx, data, ciphertext_ptr.handle_mut(), can_gc)
3223                .expect("Failed to convert ciphertext to ArrayBufferU8")
3224        });
3225        let encapsulated_bits = RootedTraceableBox::new(EncapsulatedBits {
3226            sharedKey: shared_key,
3227            ciphertext,
3228        });
3229        encapsulated_bits.safe_to_jsval(cx, rval, can_gc);
3230    }
3231}
3232
3233/// Helper to abstract the conversion process of a JS value into many different WebIDL dictionaries.
3234fn dictionary_from_jsval<T>(cx: &mut js::context::JSContext, value: HandleValue) -> Fallible<T>
3235where
3236    T: SafeFromJSValConvertible<Config = ()>,
3237{
3238    let conversion = T::safe_from_jsval(cx.into(), value, (), CanGc::from_cx(cx))
3239        .map_err(|_| Error::JSFailed)?;
3240    match conversion {
3241        ConversionResult::Success(dictionary) => Ok(dictionary),
3242        ConversionResult::Failure(error) => Err(Error::Type(error.into_owned())),
3243    }
3244}
3245
3246/// The returned type of the successful export key operation. `Bytes` should be used when the key
3247/// is exported in "raw", "spki" or "pkcs8" format. `Jwk` should be used when the key is exported
3248/// in "jwk" format.
3249enum ExportedKey {
3250    Bytes(Vec<u8>),
3251    Jwk(Box<JsonWebKey>),
3252}
3253
3254/// Union type of KeyAlgorithm and IDL dictionary types derived from it. Note that we actually use
3255/// our "subtle" structs of the corresponding IDL dictionary types so that they can be easily
3256/// passed to another threads.
3257#[derive(Clone, MallocSizeOf)]
3258#[expect(clippy::enum_variant_names)]
3259pub(crate) enum KeyAlgorithmAndDerivatives {
3260    KeyAlgorithm(SubtleKeyAlgorithm),
3261    RsaHashedKeyAlgorithm(SubtleRsaHashedKeyAlgorithm),
3262    EcKeyAlgorithm(SubtleEcKeyAlgorithm),
3263    AesKeyAlgorithm(SubtleAesKeyAlgorithm),
3264    HmacKeyAlgorithm(SubtleHmacKeyAlgorithm),
3265}
3266
3267impl KeyAlgorithmAndDerivatives {
3268    fn name(&self) -> CryptoAlgorithm {
3269        match self {
3270            KeyAlgorithmAndDerivatives::KeyAlgorithm(algorithm) => algorithm.name,
3271            KeyAlgorithmAndDerivatives::RsaHashedKeyAlgorithm(algorithm) => algorithm.name,
3272            KeyAlgorithmAndDerivatives::EcKeyAlgorithm(algorithm) => algorithm.name,
3273            KeyAlgorithmAndDerivatives::AesKeyAlgorithm(algorithm) => algorithm.name,
3274            KeyAlgorithmAndDerivatives::HmacKeyAlgorithm(algorithm) => algorithm.name,
3275        }
3276    }
3277}
3278
3279impl SafeToJSValConvertible for KeyAlgorithmAndDerivatives {
3280    fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
3281        match self {
3282            KeyAlgorithmAndDerivatives::KeyAlgorithm(algo) => algo.safe_to_jsval(cx, rval, can_gc),
3283            KeyAlgorithmAndDerivatives::RsaHashedKeyAlgorithm(algo) => {
3284                algo.safe_to_jsval(cx, rval, can_gc)
3285            },
3286            KeyAlgorithmAndDerivatives::EcKeyAlgorithm(algo) => {
3287                algo.safe_to_jsval(cx, rval, can_gc)
3288            },
3289            KeyAlgorithmAndDerivatives::AesKeyAlgorithm(algo) => {
3290                algo.safe_to_jsval(cx, rval, can_gc)
3291            },
3292            KeyAlgorithmAndDerivatives::HmacKeyAlgorithm(algo) => {
3293                algo.safe_to_jsval(cx, rval, can_gc)
3294            },
3295        }
3296    }
3297}
3298
3299#[derive(Clone, Copy)]
3300enum JwkStringField {
3301    X,
3302    Y,
3303    D,
3304    N,
3305    E,
3306    P,
3307    Q,
3308    DP,
3309    DQ,
3310    QI,
3311    K,
3312    Priv,
3313    Pub,
3314}
3315
3316impl Display for JwkStringField {
3317    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3318        let field_name = match self {
3319            JwkStringField::X => "x",
3320            JwkStringField::Y => "y",
3321            JwkStringField::D => "d",
3322            JwkStringField::N => "n",
3323            JwkStringField::E => "e",
3324            JwkStringField::P => "q",
3325            JwkStringField::Q => "q",
3326            JwkStringField::DP => "dp",
3327            JwkStringField::DQ => "dq",
3328            JwkStringField::QI => "qi",
3329            JwkStringField::K => "k",
3330            JwkStringField::Priv => "priv",
3331            JwkStringField::Pub => "pub",
3332        };
3333        write!(f, "{}", field_name)
3334    }
3335}
3336
3337trait JsonWebKeyExt {
3338    fn parse(cx: &mut js::context::JSContext, data: &[u8]) -> Result<JsonWebKey, Error>;
3339    fn stringify(&self, cx: &mut js::context::JSContext) -> Result<DOMString, Error>;
3340    fn get_usages_from_key_ops(&self) -> Result<Vec<KeyUsage>, Error>;
3341    fn check_key_ops(&self, specified_usages: &[KeyUsage]) -> Result<(), Error>;
3342    fn set_key_ops(&mut self, usages: Vec<KeyUsage>);
3343    fn encode_string_field(&mut self, field: JwkStringField, data: &[u8]);
3344    fn decode_optional_string_field(&self, field: JwkStringField)
3345    -> Result<Option<Vec<u8>>, Error>;
3346    fn decode_required_string_field(&self, field: JwkStringField) -> Result<Vec<u8>, Error>;
3347    fn decode_primes_from_oth_field(&self, primes: &mut Vec<Vec<u8>>) -> Result<(), Error>;
3348}
3349
3350impl JsonWebKeyExt for JsonWebKey {
3351    /// <https://w3c.github.io/webcrypto/#concept-parse-a-jwk>
3352    #[expect(unsafe_code)]
3353    fn parse(cx: &mut js::context::JSContext, data: &[u8]) -> Result<JsonWebKey, Error> {
3354        // Step 1. Let data be the sequence of bytes to be parsed.
3355        // (It is given as a method paramter.)
3356
3357        // Step 2. Let json be the Unicode string that results from interpreting data according to UTF-8.
3358        let json = String::from_utf8_lossy(data);
3359
3360        // Step 3. Convert json to UTF-16.
3361        let json: Vec<_> = json.encode_utf16().collect();
3362
3363        // Step 4. Let result be the object literal that results from executing the JSON.parse
3364        // internal function in the context of a new global object, with text argument set to a
3365        // JavaScript String containing json.
3366        rooted!(&in(cx) let mut result = UndefinedValue());
3367        unsafe {
3368            if !JS_ParseJSON(cx, json.as_ptr(), json.len() as u32, result.handle_mut()) {
3369                return Err(Error::JSFailed);
3370            }
3371        }
3372
3373        // Step 5. Let key be the result of converting result to the IDL dictionary type of JsonWebKey.
3374        let key = match JsonWebKey::new(cx.into(), result.handle(), CanGc::from_cx(cx)) {
3375            Ok(ConversionResult::Success(key)) => key,
3376            Ok(ConversionResult::Failure(error)) => {
3377                return Err(Error::Type(error.into_owned()));
3378            },
3379            Err(()) => {
3380                return Err(Error::JSFailed);
3381            },
3382        };
3383
3384        // Step 6. If the kty field of key is not defined, then throw a DataError.
3385        if key.kty.is_none() {
3386            return Err(Error::Data(None));
3387        }
3388
3389        // Step 7. Result key.
3390        Ok(key)
3391    }
3392
3393    /// Convert a JsonWebKey value to DOMString. We first convert the JsonWebKey value to
3394    /// JavaScript value, and then serialize it by performing steps in
3395    /// <https://infra.spec.whatwg.org/#serialize-a-javascript-value-to-a-json-string>. This acts
3396    /// like the opposite of JsonWebKey::parse if you further convert the stringified result to
3397    /// bytes.
3398    fn stringify(&self, cx: &mut js::context::JSContext) -> Result<DOMString, Error> {
3399        rooted!(&in(cx) let mut data = UndefinedValue());
3400        self.safe_to_jsval(cx.into(), data.handle_mut(), CanGc::from_cx(cx));
3401        serialize_jsval_to_json_utf8(cx.into(), data.handle())
3402    }
3403
3404    fn get_usages_from_key_ops(&self) -> Result<Vec<KeyUsage>, Error> {
3405        let mut usages = vec![];
3406        for op in self.key_ops.as_ref().ok_or(Error::Data(None))? {
3407            usages.push(KeyUsage::from_str(&op.str()).map_err(|_| Error::Data(None))?);
3408        }
3409        Ok(usages)
3410    }
3411
3412    /// If the key_ops field of jwk is present, and is invalid according to the requirements of
3413    /// JSON Web Key [JWK] or does not contain all of the specified usages values, then throw a
3414    /// DataError.
3415    fn check_key_ops(&self, specified_usages: &[KeyUsage]) -> Result<(), Error> {
3416        // If the key_ops field of jwk is present,
3417        if let Some(ref key_ops) = self.key_ops {
3418            // and is invalid according to the requirements of JSON Web Key [JWK]:
3419            // 1. Duplicate key operation values MUST NOT be present in the array.
3420            if key_ops
3421                .iter()
3422                .collect::<std::collections::HashSet<_>>()
3423                .len() <
3424                key_ops.len()
3425            {
3426                return Err(Error::Data(None));
3427            }
3428            // 2. The "use" and "key_ops" JWK members SHOULD NOT be used together; however, if both
3429            //    are used, the information they convey MUST be consistent.
3430            if let Some(ref use_) = self.use_ {
3431                if key_ops.iter().any(|op| op != use_) {
3432                    return Err(Error::Data(None));
3433                }
3434            }
3435
3436            // or does not contain all of the specified usages values
3437            let key_ops_as_usages = self.get_usages_from_key_ops()?;
3438            if !specified_usages
3439                .iter()
3440                .all(|specified_usage| key_ops_as_usages.contains(specified_usage))
3441            {
3442                return Err(Error::Data(None));
3443            }
3444        }
3445
3446        Ok(())
3447    }
3448
3449    // Set the key_ops attribute of jwk to equal the given usages.
3450    fn set_key_ops(&mut self, usages: Vec<KeyUsage>) {
3451        self.key_ops = Some(
3452            usages
3453                .into_iter()
3454                .map(|usage| DOMString::from(usage.as_str()))
3455                .collect(),
3456        );
3457    }
3458
3459    // Encode a byte sequence to a base64url-encoded string, and set the field to the encoded
3460    // string.
3461    fn encode_string_field(&mut self, field: JwkStringField, data: &[u8]) {
3462        let encoded_data = DOMString::from(Base64UrlUnpadded::encode_string(data));
3463        match field {
3464            JwkStringField::X => self.x = Some(encoded_data),
3465            JwkStringField::Y => self.y = Some(encoded_data),
3466            JwkStringField::D => self.d = Some(encoded_data),
3467            JwkStringField::N => self.n = Some(encoded_data),
3468            JwkStringField::E => self.e = Some(encoded_data),
3469            JwkStringField::P => self.p = Some(encoded_data),
3470            JwkStringField::Q => self.q = Some(encoded_data),
3471            JwkStringField::DP => self.dp = Some(encoded_data),
3472            JwkStringField::DQ => self.dq = Some(encoded_data),
3473            JwkStringField::QI => self.qi = Some(encoded_data),
3474            JwkStringField::K => self.k = Some(encoded_data),
3475            JwkStringField::Priv => self.priv_ = Some(encoded_data),
3476            JwkStringField::Pub => self.pub_ = Some(encoded_data),
3477        }
3478    }
3479
3480    // Decode a field from a base64url-encoded string to a byte sequence. If the field is not a
3481    // valid base64url-encoded string, then throw a DataError.
3482    fn decode_optional_string_field(
3483        &self,
3484        field: JwkStringField,
3485    ) -> Result<Option<Vec<u8>>, Error> {
3486        let field_string = match field {
3487            JwkStringField::X => &self.x,
3488            JwkStringField::Y => &self.y,
3489            JwkStringField::D => &self.d,
3490            JwkStringField::N => &self.n,
3491            JwkStringField::E => &self.e,
3492            JwkStringField::P => &self.p,
3493            JwkStringField::Q => &self.q,
3494            JwkStringField::DP => &self.dp,
3495            JwkStringField::DQ => &self.dq,
3496            JwkStringField::QI => &self.qi,
3497            JwkStringField::K => &self.k,
3498            JwkStringField::Priv => &self.priv_,
3499            JwkStringField::Pub => &self.pub_,
3500        };
3501
3502        field_string
3503            .as_ref()
3504            .map(|field_string| Base64UrlUnpadded::decode_vec(&field_string.str()))
3505            .transpose()
3506            .map_err(|_| Error::Data(Some(format!("Failed to decode {} field in jwk", field))))
3507    }
3508
3509    // Decode a field from a base64url-encoded string to a byte sequence. If the field is not
3510    // present or it is not a valid base64url-encoded string, then throw a DataError.
3511    fn decode_required_string_field(&self, field: JwkStringField) -> Result<Vec<u8>, Error> {
3512        self.decode_optional_string_field(field)?
3513            .ok_or(Error::Data(Some(format!(
3514                "The {} field is not present in jwk",
3515                field
3516            ))))
3517    }
3518
3519    // Decode the "r", "d" and "t" field of each entry in the "oth" array, from a base64url-encoded
3520    // string to a byte sequence, and append the decoded "r" field to the `primes` list, in the
3521    // order of presence in the "oth" array.
3522    //
3523    // If the "oth" field is present and any of the "p", "q", "dp", "dq" or "qi" field is not
3524    // present, then throw a DataError. For each entry in the "oth" array, if any of the "r", "d"
3525    // and "t" field is not present or it is not a valid base64url-encoded string, then throw a
3526    // DataError.
3527    fn decode_primes_from_oth_field(&self, primes: &mut Vec<Vec<u8>>) -> Result<(), Error> {
3528        if self.oth.is_some() &&
3529            (self.p.is_none() ||
3530                self.q.is_none() ||
3531                self.dp.is_none() ||
3532                self.dq.is_none() ||
3533                self.qi.is_none())
3534        {
3535            return Err(Error::Data(Some(
3536                "The oth field is present while at least one of p, q, dp, dq, qi is missing, in jwk".to_string()
3537            )));
3538        }
3539
3540        for rsa_other_prime_info in self.oth.as_ref().unwrap_or(&Vec::new()) {
3541            let r = Base64UrlUnpadded::decode_vec(
3542                &rsa_other_prime_info
3543                    .r
3544                    .as_ref()
3545                    .ok_or(Error::Data(Some(
3546                        "The r field is not present in one of the entry of oth field in jwk"
3547                            .to_string(),
3548                    )))?
3549                    .str(),
3550            )
3551            .map_err(|_| {
3552                Error::Data(Some(
3553                    "Fail to decode r field in one of the entry of oth field in jwk".to_string(),
3554                ))
3555            })?;
3556            primes.push(r);
3557
3558            let _d = Base64UrlUnpadded::decode_vec(
3559                &rsa_other_prime_info
3560                    .d
3561                    .as_ref()
3562                    .ok_or(Error::Data(Some(
3563                        "The d field is not present in one of the entry of oth field in jwk"
3564                            .to_string(),
3565                    )))?
3566                    .str(),
3567            )
3568            .map_err(|_| {
3569                Error::Data(Some(
3570                    "Fail to decode d field in one of the entry of oth field in jwk".to_string(),
3571                ))
3572            })?;
3573
3574            let _t = Base64UrlUnpadded::decode_vec(
3575                &rsa_other_prime_info
3576                    .t
3577                    .as_ref()
3578                    .ok_or(Error::Data(Some(
3579                        "The t field is not present in one of the entry of oth field in jwk"
3580                            .to_string(),
3581                    )))?
3582                    .str(),
3583            )
3584            .map_err(|_| {
3585                Error::Data(Some(
3586                    "Fail to decode t field in one of the entry of oth field in jwk".to_string(),
3587                ))
3588            })?;
3589        }
3590
3591        Ok(())
3592    }
3593}
3594
3595/// <https://w3c.github.io/webcrypto/#algorithm-normalization-normalize-an-algorithm>
3596fn normalize_algorithm<Op: Operation>(
3597    cx: &mut js::context::JSContext,
3598    algorithm: &AlgorithmIdentifier,
3599) -> Result<Op::RegisteredAlgorithm, Error> {
3600    match algorithm {
3601        // If alg is an instance of a DOMString:
3602        ObjectOrString::String(name) => {
3603            // Return the result of running the normalize an algorithm algorithm, with the alg set
3604            // to a new Algorithm dictionary whose name attribute is alg, and with the op set to
3605            // op.
3606            let algorithm = Algorithm {
3607                name: name.to_owned(),
3608            };
3609            rooted!(&in(cx) let mut algorithm_value = UndefinedValue());
3610            algorithm.safe_to_jsval(cx.into(), algorithm_value.handle_mut(), CanGc::from_cx(cx));
3611            let algorithm_object = RootedTraceableBox::new(Heap::default());
3612            algorithm_object.set(algorithm_value.to_object());
3613            normalize_algorithm::<Op>(cx, &ObjectOrString::Object(algorithm_object))
3614        },
3615        // If alg is an object:
3616        ObjectOrString::Object(object) => {
3617            // Step 1. Let registeredAlgorithms be the associative container stored at the op key
3618            // of supportedAlgorithms.
3619
3620            // Stpe 2. Let initialAlg be the result of converting the ECMAScript object represented
3621            // by alg to the IDL dictionary type Algorithm, as defined by [WebIDL].
3622            // Step 3. If an error occurred, return the error and terminate this algorithm.
3623            rooted!(&in(cx) let value = ObjectValue(object.get()));
3624            let initial_algorithm = dictionary_from_jsval::<Algorithm>(cx, value.handle())?;
3625
3626            // Step 4. Let algName be the value of the name attribute of initialAlg.
3627            let algorithm_name =
3628                CryptoAlgorithm::from_str_ignore_case(&initial_algorithm.name.str())?;
3629
3630            // Step 5.
3631            //     If registeredAlgorithms contains a key that is a case-insensitive string match
3632            //     for algName:
3633            //         Step 5.1. Set algName to the value of the matching key.
3634            //         Step 5.2. Let desiredType be the IDL dictionary type stored at algName in
3635            //         registeredAlgorithms.
3636            //     Otherwise:
3637            //         Return a new NotSupportedError and terminate this algorithm.
3638            // Step 6. Let normalizedAlgorithm be the result of converting the ECMAScript object
3639            // represented by alg to the IDL dictionary type desiredType, as defined by [WebIDL].
3640            // Step 7. Set the name attribute of normalizedAlgorithm to algName.
3641            // Step 8. If an error occurred, return the error and terminate this algorithm.
3642            // Step 9. Let dictionaries be a list consisting of the IDL dictionary type desiredType
3643            // and all of desiredType's inherited dictionaries, in order from least to most
3644            // derived.
3645            // Step 10. For each dictionary dictionary in dictionaries:
3646            //     Step 10.1. For each dictionary member member declared on dictionary, in order:
3647            //         Step 10.1.1. Let key be the identifier of member.
3648            //         Step 10.1.2. Let idlValue be the value of the dictionary member with key
3649            //         name of key on normalizedAlgorithm.
3650            //         Step 10.1.3.
3651            //             If member is of the type BufferSource and is present:
3652            //                 Set the dictionary member on normalizedAlgorithm with key name key
3653            //                 to the result of getting a copy of the bytes held by idlValue,
3654            //                 replacing the current value.
3655            //             If member is of the type HashAlgorithmIdentifier:
3656            //                 Set the dictionary member on normalizedAlgorithm with key name key
3657            //                 to the result of normalizing an algorithm, with the alg set to
3658            //                 idlValue and the op set to "digest".
3659            //             If member is of the type AlgorithmIdentifier:
3660            //                 Set the dictionary member on normalizedAlgorithm with key name key
3661            //                 to the result of normalizing an algorithm, with the alg set to
3662            //                 idlValue and the op set to the operation defined by the
3663            //                 specification that defines the algorithm identified by algName.
3664            //
3665            // NOTE: Step 7 is done by writing algName back to the name attribute of the JS object
3666            // before dictionary conversion in Step 6, in order to streamline the conversion. Step
3667            // 9 and 10 are done by the calling `TryIntoWithCx::try_into_with_cx` within the trait
3668            // implementation of `Op::RegisteredAlgorithm::from_object_value`.
3669            rooted!(&in(cx) let mut algorithm_name_value = UndefinedValue());
3670            algorithm_name.as_str().safe_to_jsval(
3671                cx.into(),
3672                algorithm_name_value.handle_mut(),
3673                CanGc::from_cx(cx),
3674            );
3675            set_dictionary_property(
3676                cx.into(),
3677                object.handle(),
3678                c"name",
3679                algorithm_name_value.handle(),
3680            )
3681            .map_err(|_| Error::JSFailed)?;
3682            let normalized_algorithm =
3683                Op::RegisteredAlgorithm::from_object_value(cx, algorithm_name, value.handle())?;
3684
3685            // Step 11. Return normalizedAlgorithm.
3686            Ok(normalized_algorithm)
3687        },
3688    }
3689}
3690
3691// <https://w3c.github.io/webcrypto/#dfn-supportedAlgorithms>
3692//
3693// We implement the internal object
3694// [supportedAlgorithms](https://w3c.github.io/webcrypto/#dfn-supportedAlgorithms) for algorithm
3695// registration, in the following way.
3696//
3697// For each operation v in the list of [supported
3698// operations](https://w3c.github.io/webcrypto/#supported-operation), we define a struct to
3699// represent it, which acts a key of the internal object supportedAlgorithms.
3700//
3701// We then implement the [`Operation`] trait for these structs. When implementing the trait for
3702// each of these structs, we set the associated type [`RegisteredAlgorithm`] of [`Operation`] to an
3703// enum as the value of the operation v in supportedAlgorithms. The enum lists all algorithhms
3704// supporting the operation v as its variants.
3705//
3706// To [define an algorithm](https://w3c.github.io/webcrypto/#concept-define-an-algorithm), each
3707// variant in the enum has an inner type corresponding to the desired input IDL dictionary type for
3708// the supported algorithm represented by the variant. Moreover, the enum also need to implement
3709// the [`NormalizedAlgorithm`] trait since it is used as the output of
3710// [`normalize_algorithm`].
3711//
3712// For example, we define the [`EncryptOperation`] struct to represent the "encrypt" operation, and
3713// implement the [`Operation`] trait for it. The associated type [`RegisteredAlgorithm`] of
3714// [`Operation`]  is set to the [`EncryptAlgorithm`] enum, whose variants are cryptographic
3715// algorithms that support the "encrypt" operation. The variant [`EncryptAlgorithm::AesCtr`] has an
3716// inner type [`SubtleAesCtrParams`] since the desired input IDL dictionary type for "encrypt"
3717// operation of AES-CTR algorithm is the `AesCtrParams` dictionary. The [`EncryptAlgorithm`] enum
3718// also implements the [`NormalizedAlgorithm`] trait accordingly.
3719//
3720// The algorithm registrations are specified in:
3721// RSASSA-PKCS1-v1_5: <https://w3c.github.io/webcrypto/#rsassa-pkcs1-registration>
3722// RSA-PSS:           <https://w3c.github.io/webcrypto/#rsa-pss-registration>
3723// RSA-OAEP:          <https://w3c.github.io/webcrypto/#rsa-oaep-registration>
3724// ECDSA:             <https://w3c.github.io/webcrypto/#ecdsa-registration>
3725// ECDH:              <https://w3c.github.io/webcrypto/#ecdh-registration>
3726// Ed25519:           <https://w3c.github.io/webcrypto/#ed25519-registration>
3727// X25519:            <https://w3c.github.io/webcrypto/#x25519-registration>
3728// AES-CTR:           <https://w3c.github.io/webcrypto/#aes-ctr-registration>
3729// AES-CBC:           <https://w3c.github.io/webcrypto/#aes-cbc-registration>
3730// AES-GCM:           <https://w3c.github.io/webcrypto/#aes-gcm-registration>
3731// AES-KW:            <https://w3c.github.io/webcrypto/#aes-kw-registration>
3732// HMAC:              <https://w3c.github.io/webcrypto/#hmac-registration>
3733// SHA:               <https://w3c.github.io/webcrypto/#sha-registration>
3734// HKDF:              <https://w3c.github.io/webcrypto/#hkdf-registration>
3735// PBKDF2:            <https://w3c.github.io/webcrypto/#pbkdf2-registration>
3736// ML-KEM:            <https://wicg.github.io/webcrypto-modern-algos/#ml-kem-registration>
3737// ML-DSA:            <https://wicg.github.io/webcrypto-modern-algos/#ml-dsa-registration>
3738// AES-OCB:           <https://wicg.github.io/webcrypto-modern-algos/#aes-ocb-registration>
3739// ChaCha20-Poly1305: <https://wicg.github.io/webcrypto-modern-algos/#chacha20-poly1305-registration>
3740// SHA-3:             <https://wicg.github.io/webcrypto-modern-algos/#sha3-registration>
3741// cSHAKE:            <https://wicg.github.io/webcrypto-modern-algos/#cshake-registration>
3742// Argon2:            <https://wicg.github.io/webcrypto-modern-algos/#argon2-registration>
3743
3744trait Operation {
3745    type RegisteredAlgorithm: NormalizedAlgorithm;
3746}
3747
3748trait NormalizedAlgorithm: Sized {
3749    /// Step 4 - 10 of <https://w3c.github.io/webcrypto/#algorithm-normalization-normalize-an-algorithm>
3750    fn from_object_value(
3751        cx: &mut js::context::JSContext,
3752        algorithm_name: CryptoAlgorithm,
3753        value: HandleValue,
3754    ) -> Fallible<Self>;
3755    fn name(&self) -> CryptoAlgorithm;
3756}
3757
3758/// The value of the key "encrypt" in the internal object supportedAlgorithms
3759struct EncryptOperation {}
3760
3761impl Operation for EncryptOperation {
3762    type RegisteredAlgorithm = EncryptAlgorithm;
3763}
3764
3765/// Normalized algorithm for the "encrypt" operation, used as output of
3766/// <https://w3c.github.io/webcrypto/#dfn-normalize-an-algorithm>
3767enum EncryptAlgorithm {
3768    RsaOaep(SubtleRsaOaepParams),
3769    AesCtr(SubtleAesCtrParams),
3770    AesCbc(SubtleAesCbcParams),
3771    AesGcm(SubtleAesGcmParams),
3772    AesOcb(SubtleAeadParams),
3773    ChaCha20Poly1305(SubtleAeadParams),
3774}
3775
3776impl NormalizedAlgorithm for EncryptAlgorithm {
3777    fn from_object_value(
3778        cx: &mut js::context::JSContext,
3779        algorithm_name: CryptoAlgorithm,
3780        value: HandleValue,
3781    ) -> Fallible<Self> {
3782        match algorithm_name {
3783            CryptoAlgorithm::RsaOaep => Ok(EncryptAlgorithm::RsaOaep(value.try_into_with_cx(cx)?)),
3784            CryptoAlgorithm::AesCtr => Ok(EncryptAlgorithm::AesCtr(value.try_into_with_cx(cx)?)),
3785            CryptoAlgorithm::AesCbc => Ok(EncryptAlgorithm::AesCbc(value.try_into_with_cx(cx)?)),
3786            CryptoAlgorithm::AesGcm => Ok(EncryptAlgorithm::AesGcm(value.try_into_with_cx(cx)?)),
3787            CryptoAlgorithm::AesOcb => Ok(EncryptAlgorithm::AesOcb(value.try_into_with_cx(cx)?)),
3788            CryptoAlgorithm::ChaCha20Poly1305 => Ok(EncryptAlgorithm::ChaCha20Poly1305(
3789                value.try_into_with_cx(cx)?,
3790            )),
3791            _ => Err(Error::NotSupported(Some(format!(
3792                "{} does not support \"encrypt\" operation",
3793                algorithm_name.as_str()
3794            )))),
3795        }
3796    }
3797
3798    fn name(&self) -> CryptoAlgorithm {
3799        match self {
3800            EncryptAlgorithm::RsaOaep(algorithm) => algorithm.name,
3801            EncryptAlgorithm::AesCtr(algorithm) => algorithm.name,
3802            EncryptAlgorithm::AesCbc(algorithm) => algorithm.name,
3803            EncryptAlgorithm::AesGcm(algorithm) => algorithm.name,
3804            EncryptAlgorithm::AesOcb(algorithm) => algorithm.name,
3805            EncryptAlgorithm::ChaCha20Poly1305(algorithm) => algorithm.name,
3806        }
3807    }
3808}
3809
3810impl EncryptAlgorithm {
3811    fn encrypt(&self, key: &CryptoKey, plaintext: &[u8]) -> Result<Vec<u8>, Error> {
3812        match self {
3813            EncryptAlgorithm::RsaOaep(algorithm) => {
3814                rsa_oaep_operation::encrypt(algorithm, key, plaintext)
3815            },
3816            EncryptAlgorithm::AesCtr(algorithm) => {
3817                aes_ctr_operation::encrypt(algorithm, key, plaintext)
3818            },
3819            EncryptAlgorithm::AesCbc(algorithm) => {
3820                aes_cbc_operation::encrypt(algorithm, key, plaintext)
3821            },
3822            EncryptAlgorithm::AesGcm(algorithm) => {
3823                aes_gcm_operation::encrypt(algorithm, key, plaintext)
3824            },
3825            EncryptAlgorithm::AesOcb(algorithm) => {
3826                aes_ocb_operation::encrypt(algorithm, key, plaintext)
3827            },
3828            EncryptAlgorithm::ChaCha20Poly1305(algorithm) => {
3829                chacha20_poly1305_operation::encrypt(algorithm, key, plaintext)
3830            },
3831        }
3832    }
3833}
3834
3835/// The value of the key "decrypt" in the internal object supportedAlgorithms
3836struct DecryptOperation {}
3837
3838impl Operation for DecryptOperation {
3839    type RegisteredAlgorithm = DecryptAlgorithm;
3840}
3841
3842/// Normalized algorithm for the "decrypt" operation, used as output of
3843/// <https://w3c.github.io/webcrypto/#dfn-normalize-an-algorithm>
3844enum DecryptAlgorithm {
3845    RsaOaep(SubtleRsaOaepParams),
3846    AesCtr(SubtleAesCtrParams),
3847    AesCbc(SubtleAesCbcParams),
3848    AesGcm(SubtleAesGcmParams),
3849    AesOcb(SubtleAeadParams),
3850    ChaCha20Poly1305(SubtleAeadParams),
3851}
3852
3853impl NormalizedAlgorithm for DecryptAlgorithm {
3854    fn from_object_value(
3855        cx: &mut js::context::JSContext,
3856        algorithm_name: CryptoAlgorithm,
3857        value: HandleValue,
3858    ) -> Fallible<Self> {
3859        match algorithm_name {
3860            CryptoAlgorithm::RsaOaep => Ok(DecryptAlgorithm::RsaOaep(value.try_into_with_cx(cx)?)),
3861            CryptoAlgorithm::AesCtr => Ok(DecryptAlgorithm::AesCtr(value.try_into_with_cx(cx)?)),
3862            CryptoAlgorithm::AesCbc => Ok(DecryptAlgorithm::AesCbc(value.try_into_with_cx(cx)?)),
3863            CryptoAlgorithm::AesGcm => Ok(DecryptAlgorithm::AesGcm(value.try_into_with_cx(cx)?)),
3864            CryptoAlgorithm::AesOcb => Ok(DecryptAlgorithm::AesOcb(value.try_into_with_cx(cx)?)),
3865            CryptoAlgorithm::ChaCha20Poly1305 => Ok(DecryptAlgorithm::ChaCha20Poly1305(
3866                value.try_into_with_cx(cx)?,
3867            )),
3868            _ => Err(Error::NotSupported(Some(format!(
3869                "{} does not support \"decrypt\" operation",
3870                algorithm_name.as_str()
3871            )))),
3872        }
3873    }
3874
3875    fn name(&self) -> CryptoAlgorithm {
3876        match self {
3877            DecryptAlgorithm::RsaOaep(algorithm) => algorithm.name,
3878            DecryptAlgorithm::AesCtr(algorithm) => algorithm.name,
3879            DecryptAlgorithm::AesCbc(algorithm) => algorithm.name,
3880            DecryptAlgorithm::AesGcm(algorithm) => algorithm.name,
3881            DecryptAlgorithm::AesOcb(algorithm) => algorithm.name,
3882            DecryptAlgorithm::ChaCha20Poly1305(algorithm) => algorithm.name,
3883        }
3884    }
3885}
3886
3887impl DecryptAlgorithm {
3888    fn decrypt(&self, key: &CryptoKey, ciphertext: &[u8]) -> Result<Vec<u8>, Error> {
3889        match self {
3890            DecryptAlgorithm::RsaOaep(algorithm) => {
3891                rsa_oaep_operation::decrypt(algorithm, key, ciphertext)
3892            },
3893            DecryptAlgorithm::AesCtr(algorithm) => {
3894                aes_ctr_operation::decrypt(algorithm, key, ciphertext)
3895            },
3896            DecryptAlgorithm::AesCbc(algorithm) => {
3897                aes_cbc_operation::decrypt(algorithm, key, ciphertext)
3898            },
3899            DecryptAlgorithm::AesGcm(algorithm) => {
3900                aes_gcm_operation::decrypt(algorithm, key, ciphertext)
3901            },
3902            DecryptAlgorithm::AesOcb(algorithm) => {
3903                aes_ocb_operation::decrypt(algorithm, key, ciphertext)
3904            },
3905            DecryptAlgorithm::ChaCha20Poly1305(algorithm) => {
3906                chacha20_poly1305_operation::decrypt(algorithm, key, ciphertext)
3907            },
3908        }
3909    }
3910}
3911
3912/// The value of the key "sign" in the internal object supportedAlgorithms
3913struct SignOperation {}
3914
3915impl Operation for SignOperation {
3916    type RegisteredAlgorithm = SignAlgorithm;
3917}
3918
3919/// Normalized algorithm for the "sign" operation, used as output of
3920/// <https://w3c.github.io/webcrypto/#dfn-normalize-an-algorithm>
3921enum SignAlgorithm {
3922    RsassaPkcs1V1_5(SubtleAlgorithm),
3923    RsaPss(SubtleRsaPssParams),
3924    Ecdsa(SubtleEcdsaParams),
3925    Ed25519(SubtleAlgorithm),
3926    Hmac(SubtleAlgorithm),
3927    MlDsa(SubtleContextParams),
3928}
3929
3930impl NormalizedAlgorithm for SignAlgorithm {
3931    fn from_object_value(
3932        cx: &mut js::context::JSContext,
3933        algorithm_name: CryptoAlgorithm,
3934        value: HandleValue,
3935    ) -> Fallible<Self> {
3936        match algorithm_name {
3937            CryptoAlgorithm::RsassaPkcs1V1_5 => {
3938                Ok(SignAlgorithm::RsassaPkcs1V1_5(value.try_into_with_cx(cx)?))
3939            },
3940            CryptoAlgorithm::RsaPss => Ok(SignAlgorithm::RsaPss(value.try_into_with_cx(cx)?)),
3941            CryptoAlgorithm::Ecdsa => Ok(SignAlgorithm::Ecdsa(value.try_into_with_cx(cx)?)),
3942            CryptoAlgorithm::Ed25519 => Ok(SignAlgorithm::Ed25519(value.try_into_with_cx(cx)?)),
3943            CryptoAlgorithm::Hmac => Ok(SignAlgorithm::Hmac(value.try_into_with_cx(cx)?)),
3944            CryptoAlgorithm::MlDsa44 | CryptoAlgorithm::MlDsa65 | CryptoAlgorithm::MlDsa87 => {
3945                Ok(SignAlgorithm::MlDsa(value.try_into_with_cx(cx)?))
3946            },
3947            _ => Err(Error::NotSupported(Some(format!(
3948                "{} does not support \"sign\" operation",
3949                algorithm_name.as_str()
3950            )))),
3951        }
3952    }
3953
3954    fn name(&self) -> CryptoAlgorithm {
3955        match self {
3956            SignAlgorithm::RsassaPkcs1V1_5(algorithm) => algorithm.name,
3957            SignAlgorithm::RsaPss(algorithm) => algorithm.name,
3958            SignAlgorithm::Ecdsa(algorithm) => algorithm.name,
3959            SignAlgorithm::Ed25519(algorithm) => algorithm.name,
3960            SignAlgorithm::Hmac(algorithm) => algorithm.name,
3961            SignAlgorithm::MlDsa(algorithm) => algorithm.name,
3962        }
3963    }
3964}
3965
3966impl SignAlgorithm {
3967    fn sign(&self, key: &CryptoKey, message: &[u8]) -> Result<Vec<u8>, Error> {
3968        match self {
3969            SignAlgorithm::RsassaPkcs1V1_5(_algorithm) => {
3970                rsassa_pkcs1_v1_5_operation::sign(key, message)
3971            },
3972            SignAlgorithm::RsaPss(algorithm) => rsa_pss_operation::sign(algorithm, key, message),
3973            SignAlgorithm::Ecdsa(algorithm) => ecdsa_operation::sign(algorithm, key, message),
3974            SignAlgorithm::Ed25519(_algorithm) => ed25519_operation::sign(key, message),
3975            SignAlgorithm::Hmac(_algorithm) => hmac_operation::sign(key, message),
3976            SignAlgorithm::MlDsa(algorithm) => ml_dsa_operation::sign(algorithm, key, message),
3977        }
3978    }
3979}
3980
3981/// The value of the key "verify" in the internal object supportedAlgorithms
3982struct VerifyOperation {}
3983
3984impl Operation for VerifyOperation {
3985    type RegisteredAlgorithm = VerifyAlgorithm;
3986}
3987
3988/// Normalized algorithm for the "verify" operation, used as output of
3989/// <https://w3c.github.io/webcrypto/#dfn-normalize-an-algorithm>
3990enum VerifyAlgorithm {
3991    RsassaPkcs1V1_5(SubtleAlgorithm),
3992    RsaPss(SubtleRsaPssParams),
3993    Ecdsa(SubtleEcdsaParams),
3994    Ed25519(SubtleAlgorithm),
3995    Hmac(SubtleAlgorithm),
3996    MlDsa(SubtleContextParams),
3997}
3998
3999impl NormalizedAlgorithm for VerifyAlgorithm {
4000    fn from_object_value(
4001        cx: &mut js::context::JSContext,
4002        algorithm_name: CryptoAlgorithm,
4003        value: HandleValue,
4004    ) -> Fallible<Self> {
4005        match algorithm_name {
4006            CryptoAlgorithm::RsassaPkcs1V1_5 => Ok(VerifyAlgorithm::RsassaPkcs1V1_5(
4007                value.try_into_with_cx(cx)?,
4008            )),
4009            CryptoAlgorithm::RsaPss => Ok(VerifyAlgorithm::RsaPss(value.try_into_with_cx(cx)?)),
4010            CryptoAlgorithm::Ecdsa => Ok(VerifyAlgorithm::Ecdsa(value.try_into_with_cx(cx)?)),
4011            CryptoAlgorithm::Ed25519 => Ok(VerifyAlgorithm::Ed25519(value.try_into_with_cx(cx)?)),
4012            CryptoAlgorithm::Hmac => Ok(VerifyAlgorithm::Hmac(value.try_into_with_cx(cx)?)),
4013            CryptoAlgorithm::MlDsa44 | CryptoAlgorithm::MlDsa65 | CryptoAlgorithm::MlDsa87 => {
4014                Ok(VerifyAlgorithm::MlDsa(value.try_into_with_cx(cx)?))
4015            },
4016            _ => Err(Error::NotSupported(Some(format!(
4017                "{} does not support \"verify\" operation",
4018                algorithm_name.as_str()
4019            )))),
4020        }
4021    }
4022
4023    fn name(&self) -> CryptoAlgorithm {
4024        match self {
4025            VerifyAlgorithm::RsassaPkcs1V1_5(algorithm) => algorithm.name,
4026            VerifyAlgorithm::RsaPss(algorithm) => algorithm.name,
4027            VerifyAlgorithm::Ecdsa(algorithm) => algorithm.name,
4028            VerifyAlgorithm::Ed25519(algorithm) => algorithm.name,
4029            VerifyAlgorithm::Hmac(algorithm) => algorithm.name,
4030            VerifyAlgorithm::MlDsa(algorithm) => algorithm.name,
4031        }
4032    }
4033}
4034
4035impl VerifyAlgorithm {
4036    fn verify(&self, key: &CryptoKey, message: &[u8], signature: &[u8]) -> Result<bool, Error> {
4037        match self {
4038            VerifyAlgorithm::RsassaPkcs1V1_5(_algorithm) => {
4039                rsassa_pkcs1_v1_5_operation::verify(key, message, signature)
4040            },
4041            VerifyAlgorithm::RsaPss(algorithm) => {
4042                rsa_pss_operation::verify(algorithm, key, message, signature)
4043            },
4044            VerifyAlgorithm::Ecdsa(algorithm) => {
4045                ecdsa_operation::verify(algorithm, key, message, signature)
4046            },
4047            VerifyAlgorithm::Ed25519(_algorithm) => {
4048                ed25519_operation::verify(key, message, signature)
4049            },
4050            VerifyAlgorithm::Hmac(_algorithm) => hmac_operation::verify(key, message, signature),
4051            VerifyAlgorithm::MlDsa(algorithm) => {
4052                ml_dsa_operation::verify(algorithm, key, message, signature)
4053            },
4054        }
4055    }
4056}
4057
4058/// The value of the key "digest" in the internal object supportedAlgorithms
4059struct DigestOperation {}
4060
4061impl Operation for DigestOperation {
4062    type RegisteredAlgorithm = DigestAlgorithm;
4063}
4064
4065/// Normalized algorithm for the "digest" operation, used as output of
4066/// <https://w3c.github.io/webcrypto/#dfn-normalize-an-algorithm>
4067#[derive(Clone, MallocSizeOf)]
4068enum DigestAlgorithm {
4069    Sha(SubtleAlgorithm),
4070    Sha3(SubtleAlgorithm),
4071    CShake(SubtleCShakeParams),
4072}
4073
4074impl NormalizedAlgorithm for DigestAlgorithm {
4075    fn from_object_value(
4076        cx: &mut js::context::JSContext,
4077        algorithm_name: CryptoAlgorithm,
4078        value: HandleValue,
4079    ) -> Fallible<Self> {
4080        match algorithm_name {
4081            CryptoAlgorithm::Sha1 |
4082            CryptoAlgorithm::Sha256 |
4083            CryptoAlgorithm::Sha384 |
4084            CryptoAlgorithm::Sha512 => Ok(DigestAlgorithm::Sha(value.try_into_with_cx(cx)?)),
4085            CryptoAlgorithm::Sha3_256 | CryptoAlgorithm::Sha3_384 | CryptoAlgorithm::Sha3_512 => {
4086                Ok(DigestAlgorithm::Sha3(value.try_into_with_cx(cx)?))
4087            },
4088            CryptoAlgorithm::CShake128 | CryptoAlgorithm::CShake256 => {
4089                Ok(DigestAlgorithm::CShake(value.try_into_with_cx(cx)?))
4090            },
4091            _ => Err(Error::NotSupported(Some(format!(
4092                "{} does not support \"digest\" operation",
4093                algorithm_name.as_str()
4094            )))),
4095        }
4096    }
4097
4098    fn name(&self) -> CryptoAlgorithm {
4099        match self {
4100            DigestAlgorithm::Sha(algorithm) => algorithm.name,
4101            DigestAlgorithm::Sha3(algorithm) => algorithm.name,
4102            DigestAlgorithm::CShake(algorithm) => algorithm.name,
4103        }
4104    }
4105}
4106
4107impl DigestAlgorithm {
4108    fn digest(&self, message: &[u8]) -> Result<Vec<u8>, Error> {
4109        match self {
4110            DigestAlgorithm::Sha(algorithm) => sha_operation::digest(algorithm, message),
4111            DigestAlgorithm::Sha3(algorithm) => sha3_operation::digest(algorithm, message),
4112            DigestAlgorithm::CShake(algorithm) => cshake_operation::digest(algorithm, message),
4113        }
4114    }
4115}
4116
4117/// The value of the key "deriveBits" in the internal object supportedAlgorithms
4118struct DeriveBitsOperation {}
4119
4120impl Operation for DeriveBitsOperation {
4121    type RegisteredAlgorithm = DeriveBitsAlgorithm;
4122}
4123
4124/// Normalized algorithm for the "deriveBits" operation, used as output of
4125/// <https://w3c.github.io/webcrypto/#dfn-normalize-an-algorithm>
4126enum DeriveBitsAlgorithm {
4127    Ecdh(SubtleEcdhKeyDeriveParams),
4128    X25519(SubtleEcdhKeyDeriveParams),
4129    Hkdf(SubtleHkdfParams),
4130    Pbkdf2(SubtlePbkdf2Params),
4131    Argon2(SubtleArgon2Params),
4132}
4133
4134impl NormalizedAlgorithm for DeriveBitsAlgorithm {
4135    fn from_object_value(
4136        cx: &mut js::context::JSContext,
4137        algorithm_name: CryptoAlgorithm,
4138        value: HandleValue,
4139    ) -> Fallible<Self> {
4140        match algorithm_name {
4141            CryptoAlgorithm::Ecdh => Ok(DeriveBitsAlgorithm::Ecdh(value.try_into_with_cx(cx)?)),
4142            CryptoAlgorithm::X25519 => Ok(DeriveBitsAlgorithm::X25519(value.try_into_with_cx(cx)?)),
4143            CryptoAlgorithm::Hkdf => Ok(DeriveBitsAlgorithm::Hkdf(value.try_into_with_cx(cx)?)),
4144            CryptoAlgorithm::Pbkdf2 => Ok(DeriveBitsAlgorithm::Pbkdf2(value.try_into_with_cx(cx)?)),
4145            CryptoAlgorithm::Argon2D | CryptoAlgorithm::Argon2I | CryptoAlgorithm::Argon2ID => {
4146                Ok(DeriveBitsAlgorithm::Argon2(value.try_into_with_cx(cx)?))
4147            },
4148            _ => Err(Error::NotSupported(Some(format!(
4149                "{} does not support \"deriveBits\" operation",
4150                algorithm_name.as_str()
4151            )))),
4152        }
4153    }
4154
4155    fn name(&self) -> CryptoAlgorithm {
4156        match self {
4157            DeriveBitsAlgorithm::Ecdh(algorithm) => algorithm.name,
4158            DeriveBitsAlgorithm::X25519(algorithm) => algorithm.name,
4159            DeriveBitsAlgorithm::Hkdf(algorithm) => algorithm.name,
4160            DeriveBitsAlgorithm::Pbkdf2(algorithm) => algorithm.name,
4161            DeriveBitsAlgorithm::Argon2(algorithm) => algorithm.name,
4162        }
4163    }
4164}
4165
4166impl DeriveBitsAlgorithm {
4167    fn derive_bits(&self, key: &CryptoKey, length: Option<u32>) -> Result<Vec<u8>, Error> {
4168        match self {
4169            DeriveBitsAlgorithm::Ecdh(algorithm) => {
4170                ecdh_operation::derive_bits(algorithm, key, length)
4171            },
4172            DeriveBitsAlgorithm::X25519(algorithm) => {
4173                x25519_operation::derive_bits(algorithm, key, length)
4174            },
4175            DeriveBitsAlgorithm::Hkdf(algorithm) => {
4176                hkdf_operation::derive_bits(algorithm, key, length)
4177            },
4178            DeriveBitsAlgorithm::Pbkdf2(algorithm) => {
4179                pbkdf2_operation::derive_bits(algorithm, key, length)
4180            },
4181            DeriveBitsAlgorithm::Argon2(algorithm) => {
4182                argon2_operation::derive_bits(algorithm, key, length)
4183            },
4184        }
4185    }
4186}
4187
4188/// The value of the key "wrapKey" in the internal object supportedAlgorithms
4189struct WrapKeyOperation {}
4190
4191impl Operation for WrapKeyOperation {
4192    type RegisteredAlgorithm = WrapKeyAlgorithm;
4193}
4194
4195/// Normalized algorithm for the "wrapKey" operation, used as output of
4196/// <https://w3c.github.io/webcrypto/#dfn-normalize-an-algorithm>
4197enum WrapKeyAlgorithm {
4198    AesKw(SubtleAlgorithm),
4199}
4200
4201impl NormalizedAlgorithm for WrapKeyAlgorithm {
4202    fn from_object_value(
4203        cx: &mut js::context::JSContext,
4204        algorithm_name: CryptoAlgorithm,
4205        value: HandleValue,
4206    ) -> Fallible<Self> {
4207        match algorithm_name {
4208            CryptoAlgorithm::AesKw => Ok(WrapKeyAlgorithm::AesKw(value.try_into_with_cx(cx)?)),
4209            _ => Err(Error::NotSupported(Some(format!(
4210                "{} does not support \"wrapKey\" operation",
4211                algorithm_name.as_str()
4212            )))),
4213        }
4214    }
4215
4216    fn name(&self) -> CryptoAlgorithm {
4217        match self {
4218            WrapKeyAlgorithm::AesKw(algorithm) => algorithm.name,
4219        }
4220    }
4221}
4222
4223impl WrapKeyAlgorithm {
4224    fn wrap_key(&self, key: &CryptoKey, plaintext: &[u8]) -> Result<Vec<u8>, Error> {
4225        match self {
4226            WrapKeyAlgorithm::AesKw(_algorithm) => aes_kw_operation::wrap_key(key, plaintext),
4227        }
4228    }
4229}
4230
4231/// The value of the key "unwrapKey" in the internal object supportedAlgorithms
4232struct UnwrapKeyOperation {}
4233
4234impl Operation for UnwrapKeyOperation {
4235    type RegisteredAlgorithm = UnwrapKeyAlgorithm;
4236}
4237
4238/// Normalized algorithm for the "unwrapKey" operation, used as output of
4239/// <https://w3c.github.io/webcrypto/#dfn-normalize-an-algorithm>
4240enum UnwrapKeyAlgorithm {
4241    AesKw(SubtleAlgorithm),
4242}
4243
4244impl NormalizedAlgorithm for UnwrapKeyAlgorithm {
4245    fn from_object_value(
4246        cx: &mut js::context::JSContext,
4247        algorithm_name: CryptoAlgorithm,
4248        value: HandleValue,
4249    ) -> Fallible<Self> {
4250        match algorithm_name {
4251            CryptoAlgorithm::AesKw => Ok(UnwrapKeyAlgorithm::AesKw(value.try_into_with_cx(cx)?)),
4252            _ => Err(Error::NotSupported(Some(format!(
4253                "{} does not support \"unwrapKey\" operation",
4254                algorithm_name.as_str()
4255            )))),
4256        }
4257    }
4258
4259    fn name(&self) -> CryptoAlgorithm {
4260        match self {
4261            UnwrapKeyAlgorithm::AesKw(algorithm) => algorithm.name,
4262        }
4263    }
4264}
4265
4266impl UnwrapKeyAlgorithm {
4267    fn unwrap_key(&self, key: &CryptoKey, ciphertext: &[u8]) -> Result<Vec<u8>, Error> {
4268        match self {
4269            UnwrapKeyAlgorithm::AesKw(_algorithm) => aes_kw_operation::unwrap_key(key, ciphertext),
4270        }
4271    }
4272}
4273
4274/// The value of the key "unwrapKey" in the internal object supportedAlgorithms
4275struct GenerateKeyOperation {}
4276
4277impl Operation for GenerateKeyOperation {
4278    type RegisteredAlgorithm = GenerateKeyAlgorithm;
4279}
4280
4281/// Normalized algorithm for the "generateKey" operation, used as output of
4282/// <https://w3c.github.io/webcrypto/#dfn-normalize-an-algorithm>
4283enum GenerateKeyAlgorithm {
4284    RsassaPkcs1V1_5(SubtleRsaHashedKeyGenParams),
4285    RsaPss(SubtleRsaHashedKeyGenParams),
4286    RsaOaep(SubtleRsaHashedKeyGenParams),
4287    Ecdsa(SubtleEcKeyGenParams),
4288    Ecdh(SubtleEcKeyGenParams),
4289    Ed25519(SubtleAlgorithm),
4290    X25519(SubtleAlgorithm),
4291    AesCtr(SubtleAesKeyGenParams),
4292    AesCbc(SubtleAesKeyGenParams),
4293    AesGcm(SubtleAesKeyGenParams),
4294    AesKw(SubtleAesKeyGenParams),
4295    Hmac(SubtleHmacKeyGenParams),
4296    MlKem(SubtleAlgorithm),
4297    MlDsa(SubtleAlgorithm),
4298    AesOcb(SubtleAesKeyGenParams),
4299    ChaCha20Poly1305(SubtleAlgorithm),
4300}
4301
4302impl NormalizedAlgorithm for GenerateKeyAlgorithm {
4303    fn from_object_value(
4304        cx: &mut js::context::JSContext,
4305        algorithm_name: CryptoAlgorithm,
4306        value: HandleValue,
4307    ) -> Fallible<Self> {
4308        match algorithm_name {
4309            CryptoAlgorithm::RsassaPkcs1V1_5 => Ok(GenerateKeyAlgorithm::RsassaPkcs1V1_5(
4310                value.try_into_with_cx(cx)?,
4311            )),
4312            CryptoAlgorithm::RsaPss => {
4313                Ok(GenerateKeyAlgorithm::RsaPss(value.try_into_with_cx(cx)?))
4314            },
4315            CryptoAlgorithm::RsaOaep => {
4316                Ok(GenerateKeyAlgorithm::RsaOaep(value.try_into_with_cx(cx)?))
4317            },
4318            CryptoAlgorithm::Ecdsa => Ok(GenerateKeyAlgorithm::Ecdsa(value.try_into_with_cx(cx)?)),
4319            CryptoAlgorithm::Ecdh => Ok(GenerateKeyAlgorithm::Ecdh(value.try_into_with_cx(cx)?)),
4320            CryptoAlgorithm::Ed25519 => {
4321                Ok(GenerateKeyAlgorithm::Ed25519(value.try_into_with_cx(cx)?))
4322            },
4323            CryptoAlgorithm::X25519 => {
4324                Ok(GenerateKeyAlgorithm::X25519(value.try_into_with_cx(cx)?))
4325            },
4326            CryptoAlgorithm::AesCtr => {
4327                Ok(GenerateKeyAlgorithm::AesCtr(value.try_into_with_cx(cx)?))
4328            },
4329            CryptoAlgorithm::AesCbc => {
4330                Ok(GenerateKeyAlgorithm::AesCbc(value.try_into_with_cx(cx)?))
4331            },
4332            CryptoAlgorithm::AesGcm => {
4333                Ok(GenerateKeyAlgorithm::AesGcm(value.try_into_with_cx(cx)?))
4334            },
4335            CryptoAlgorithm::AesKw => Ok(GenerateKeyAlgorithm::AesKw(value.try_into_with_cx(cx)?)),
4336            CryptoAlgorithm::Hmac => Ok(GenerateKeyAlgorithm::Hmac(value.try_into_with_cx(cx)?)),
4337            CryptoAlgorithm::MlKem512 | CryptoAlgorithm::MlKem768 | CryptoAlgorithm::MlKem1024 => {
4338                Ok(GenerateKeyAlgorithm::MlKem(value.try_into_with_cx(cx)?))
4339            },
4340            CryptoAlgorithm::MlDsa44 | CryptoAlgorithm::MlDsa65 | CryptoAlgorithm::MlDsa87 => {
4341                Ok(GenerateKeyAlgorithm::MlDsa(value.try_into_with_cx(cx)?))
4342            },
4343            CryptoAlgorithm::AesOcb => {
4344                Ok(GenerateKeyAlgorithm::AesOcb(value.try_into_with_cx(cx)?))
4345            },
4346            CryptoAlgorithm::ChaCha20Poly1305 => Ok(GenerateKeyAlgorithm::ChaCha20Poly1305(
4347                value.try_into_with_cx(cx)?,
4348            )),
4349            _ => Err(Error::NotSupported(Some(format!(
4350                "{} does not support \"generateKey\" operation",
4351                algorithm_name.as_str()
4352            )))),
4353        }
4354    }
4355
4356    fn name(&self) -> CryptoAlgorithm {
4357        match self {
4358            GenerateKeyAlgorithm::RsassaPkcs1V1_5(algorithm) => algorithm.name,
4359            GenerateKeyAlgorithm::RsaPss(algorithm) => algorithm.name,
4360            GenerateKeyAlgorithm::RsaOaep(algorithm) => algorithm.name,
4361            GenerateKeyAlgorithm::Ecdsa(algorithm) => algorithm.name,
4362            GenerateKeyAlgorithm::Ecdh(algorithm) => algorithm.name,
4363            GenerateKeyAlgorithm::Ed25519(algorithm) => algorithm.name,
4364            GenerateKeyAlgorithm::X25519(algorithm) => algorithm.name,
4365            GenerateKeyAlgorithm::AesCtr(algorithm) => algorithm.name,
4366            GenerateKeyAlgorithm::AesCbc(algorithm) => algorithm.name,
4367            GenerateKeyAlgorithm::AesGcm(algorithm) => algorithm.name,
4368            GenerateKeyAlgorithm::AesKw(algorithm) => algorithm.name,
4369            GenerateKeyAlgorithm::Hmac(algorithm) => algorithm.name,
4370            GenerateKeyAlgorithm::MlKem(algorithm) => algorithm.name,
4371            GenerateKeyAlgorithm::MlDsa(algorithm) => algorithm.name,
4372            GenerateKeyAlgorithm::AesOcb(algorithm) => algorithm.name,
4373            GenerateKeyAlgorithm::ChaCha20Poly1305(algorithm) => algorithm.name,
4374        }
4375    }
4376}
4377
4378impl GenerateKeyAlgorithm {
4379    fn generate_key(
4380        &self,
4381        cx: &mut js::context::JSContext,
4382        global: &GlobalScope,
4383        extractable: bool,
4384        usages: Vec<KeyUsage>,
4385    ) -> Result<CryptoKeyOrCryptoKeyPair, Error> {
4386        match self {
4387            GenerateKeyAlgorithm::RsassaPkcs1V1_5(algorithm) => {
4388                rsassa_pkcs1_v1_5_operation::generate_key(
4389                    cx,
4390                    global,
4391                    algorithm,
4392                    extractable,
4393                    usages,
4394                )
4395                .map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
4396            },
4397            GenerateKeyAlgorithm::RsaPss(algorithm) => {
4398                rsa_pss_operation::generate_key(cx, global, algorithm, extractable, usages)
4399                    .map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
4400            },
4401            GenerateKeyAlgorithm::RsaOaep(algorithm) => {
4402                rsa_oaep_operation::generate_key(cx, global, algorithm, extractable, usages)
4403                    .map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
4404            },
4405            GenerateKeyAlgorithm::Ecdsa(algorithm) => {
4406                ecdsa_operation::generate_key(cx, global, algorithm, extractable, usages)
4407                    .map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
4408            },
4409            GenerateKeyAlgorithm::Ecdh(algorithm) => {
4410                ecdh_operation::generate_key(cx, global, algorithm, extractable, usages)
4411                    .map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
4412            },
4413            GenerateKeyAlgorithm::Ed25519(_algorithm) => {
4414                ed25519_operation::generate_key(cx, global, extractable, usages)
4415                    .map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
4416            },
4417            GenerateKeyAlgorithm::X25519(_algorithm) => {
4418                x25519_operation::generate_key(cx, global, extractable, usages)
4419                    .map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
4420            },
4421            GenerateKeyAlgorithm::AesCtr(algorithm) => {
4422                aes_ctr_operation::generate_key(cx, global, algorithm, extractable, usages)
4423                    .map(CryptoKeyOrCryptoKeyPair::CryptoKey)
4424            },
4425            GenerateKeyAlgorithm::AesCbc(algorithm) => {
4426                aes_cbc_operation::generate_key(cx, global, algorithm, extractable, usages)
4427                    .map(CryptoKeyOrCryptoKeyPair::CryptoKey)
4428            },
4429            GenerateKeyAlgorithm::AesGcm(algorithm) => {
4430                aes_gcm_operation::generate_key(cx, global, algorithm, extractable, usages)
4431                    .map(CryptoKeyOrCryptoKeyPair::CryptoKey)
4432            },
4433            GenerateKeyAlgorithm::AesKw(algorithm) => {
4434                aes_kw_operation::generate_key(cx, global, algorithm, extractable, usages)
4435                    .map(CryptoKeyOrCryptoKeyPair::CryptoKey)
4436            },
4437            GenerateKeyAlgorithm::Hmac(algorithm) => {
4438                hmac_operation::generate_key(cx, global, algorithm, extractable, usages)
4439                    .map(CryptoKeyOrCryptoKeyPair::CryptoKey)
4440            },
4441            GenerateKeyAlgorithm::MlKem(algorithm) => {
4442                ml_kem_operation::generate_key(cx, global, algorithm, extractable, usages)
4443                    .map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
4444            },
4445            GenerateKeyAlgorithm::MlDsa(algorithm) => {
4446                ml_dsa_operation::generate_key(cx, global, algorithm, extractable, usages)
4447                    .map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
4448            },
4449            GenerateKeyAlgorithm::AesOcb(algorithm) => {
4450                aes_ocb_operation::generate_key(cx, global, algorithm, extractable, usages)
4451                    .map(CryptoKeyOrCryptoKeyPair::CryptoKey)
4452            },
4453            GenerateKeyAlgorithm::ChaCha20Poly1305(_algorithm) => {
4454                chacha20_poly1305_operation::generate_key(cx, global, extractable, usages)
4455                    .map(CryptoKeyOrCryptoKeyPair::CryptoKey)
4456            },
4457        }
4458    }
4459}
4460
4461/// The value of the key "importKey" in the internal object supportedAlgorithms
4462struct ImportKeyOperation {}
4463
4464impl Operation for ImportKeyOperation {
4465    type RegisteredAlgorithm = ImportKeyAlgorithm;
4466}
4467
4468/// Normalized algorithm for the "importKey" operation, used as output of
4469/// <https://w3c.github.io/webcrypto/#dfn-normalize-an-algorithm>
4470enum ImportKeyAlgorithm {
4471    RsassaPkcs1V1_5(SubtleRsaHashedImportParams),
4472    RsaPss(SubtleRsaHashedImportParams),
4473    RsaOaep(SubtleRsaHashedImportParams),
4474    Ecdsa(SubtleEcKeyImportParams),
4475    Ecdh(SubtleEcKeyImportParams),
4476    Ed25519(SubtleAlgorithm),
4477    X25519(SubtleAlgorithm),
4478    AesCtr(SubtleAlgorithm),
4479    AesCbc(SubtleAlgorithm),
4480    AesGcm(SubtleAlgorithm),
4481    AesKw(SubtleAlgorithm),
4482    Hmac(SubtleHmacImportParams),
4483    Hkdf(SubtleAlgorithm),
4484    Pbkdf2(SubtleAlgorithm),
4485    MlKem(SubtleAlgorithm),
4486    MlDsa(SubtleAlgorithm),
4487    AesOcb(SubtleAlgorithm),
4488    ChaCha20Poly1305(SubtleAlgorithm),
4489    Argon2(SubtleAlgorithm),
4490}
4491
4492impl NormalizedAlgorithm for ImportKeyAlgorithm {
4493    fn from_object_value(
4494        cx: &mut js::context::JSContext,
4495        algorithm_name: CryptoAlgorithm,
4496        value: HandleValue,
4497    ) -> Fallible<Self> {
4498        match algorithm_name {
4499            CryptoAlgorithm::RsassaPkcs1V1_5 => Ok(ImportKeyAlgorithm::RsassaPkcs1V1_5(
4500                value.try_into_with_cx(cx)?,
4501            )),
4502            CryptoAlgorithm::RsaPss => Ok(ImportKeyAlgorithm::RsaPss(value.try_into_with_cx(cx)?)),
4503            CryptoAlgorithm::RsaOaep => {
4504                Ok(ImportKeyAlgorithm::RsaOaep(value.try_into_with_cx(cx)?))
4505            },
4506            CryptoAlgorithm::Ecdsa => Ok(ImportKeyAlgorithm::Ecdsa(value.try_into_with_cx(cx)?)),
4507            CryptoAlgorithm::Ecdh => Ok(ImportKeyAlgorithm::Ecdh(value.try_into_with_cx(cx)?)),
4508            CryptoAlgorithm::Ed25519 => {
4509                Ok(ImportKeyAlgorithm::Ed25519(value.try_into_with_cx(cx)?))
4510            },
4511            CryptoAlgorithm::X25519 => Ok(ImportKeyAlgorithm::X25519(value.try_into_with_cx(cx)?)),
4512            CryptoAlgorithm::AesCtr => Ok(ImportKeyAlgorithm::AesCtr(value.try_into_with_cx(cx)?)),
4513            CryptoAlgorithm::AesCbc => Ok(ImportKeyAlgorithm::AesCbc(value.try_into_with_cx(cx)?)),
4514            CryptoAlgorithm::AesGcm => Ok(ImportKeyAlgorithm::AesGcm(value.try_into_with_cx(cx)?)),
4515            CryptoAlgorithm::AesKw => Ok(ImportKeyAlgorithm::AesKw(value.try_into_with_cx(cx)?)),
4516            CryptoAlgorithm::Hmac => Ok(ImportKeyAlgorithm::Hmac(value.try_into_with_cx(cx)?)),
4517            CryptoAlgorithm::Hkdf => Ok(ImportKeyAlgorithm::Hkdf(value.try_into_with_cx(cx)?)),
4518            CryptoAlgorithm::Pbkdf2 => Ok(ImportKeyAlgorithm::Pbkdf2(value.try_into_with_cx(cx)?)),
4519            CryptoAlgorithm::MlKem512 | CryptoAlgorithm::MlKem768 | CryptoAlgorithm::MlKem1024 => {
4520                Ok(ImportKeyAlgorithm::MlKem(value.try_into_with_cx(cx)?))
4521            },
4522            CryptoAlgorithm::MlDsa44 | CryptoAlgorithm::MlDsa65 | CryptoAlgorithm::MlDsa87 => {
4523                Ok(ImportKeyAlgorithm::MlDsa(value.try_into_with_cx(cx)?))
4524            },
4525            CryptoAlgorithm::AesOcb => Ok(ImportKeyAlgorithm::AesOcb(value.try_into_with_cx(cx)?)),
4526            CryptoAlgorithm::ChaCha20Poly1305 => Ok(ImportKeyAlgorithm::ChaCha20Poly1305(
4527                value.try_into_with_cx(cx)?,
4528            )),
4529            CryptoAlgorithm::Argon2D | CryptoAlgorithm::Argon2I | CryptoAlgorithm::Argon2ID => {
4530                Ok(ImportKeyAlgorithm::Argon2(value.try_into_with_cx(cx)?))
4531            },
4532            _ => Err(Error::NotSupported(Some(format!(
4533                "{} does not support \"importKey\" operation",
4534                algorithm_name.as_str()
4535            )))),
4536        }
4537    }
4538
4539    fn name(&self) -> CryptoAlgorithm {
4540        match self {
4541            ImportKeyAlgorithm::RsassaPkcs1V1_5(algorithm) => algorithm.name,
4542            ImportKeyAlgorithm::RsaPss(algorithm) => algorithm.name,
4543            ImportKeyAlgorithm::RsaOaep(algorithm) => algorithm.name,
4544            ImportKeyAlgorithm::Ecdsa(algorithm) => algorithm.name,
4545            ImportKeyAlgorithm::Ecdh(algorithm) => algorithm.name,
4546            ImportKeyAlgorithm::Ed25519(algorithm) => algorithm.name,
4547            ImportKeyAlgorithm::X25519(algorithm) => algorithm.name,
4548            ImportKeyAlgorithm::AesCtr(algorithm) => algorithm.name,
4549            ImportKeyAlgorithm::AesCbc(algorithm) => algorithm.name,
4550            ImportKeyAlgorithm::AesGcm(algorithm) => algorithm.name,
4551            ImportKeyAlgorithm::AesKw(algorithm) => algorithm.name,
4552            ImportKeyAlgorithm::Hmac(algorithm) => algorithm.name,
4553            ImportKeyAlgorithm::Hkdf(algorithm) => algorithm.name,
4554            ImportKeyAlgorithm::Pbkdf2(algorithm) => algorithm.name,
4555            ImportKeyAlgorithm::MlKem(algorithm) => algorithm.name,
4556            ImportKeyAlgorithm::MlDsa(algorithm) => algorithm.name,
4557            ImportKeyAlgorithm::AesOcb(algorithm) => algorithm.name,
4558            ImportKeyAlgorithm::ChaCha20Poly1305(algorithm) => algorithm.name,
4559            ImportKeyAlgorithm::Argon2(algorithm) => algorithm.name,
4560        }
4561    }
4562}
4563
4564impl ImportKeyAlgorithm {
4565    fn import_key(
4566        &self,
4567        cx: &mut js::context::JSContext,
4568        global: &GlobalScope,
4569        format: KeyFormat,
4570        key_data: &[u8],
4571        extractable: bool,
4572        usages: Vec<KeyUsage>,
4573    ) -> Result<DomRoot<CryptoKey>, Error> {
4574        match self {
4575            ImportKeyAlgorithm::RsassaPkcs1V1_5(algorithm) => {
4576                rsassa_pkcs1_v1_5_operation::import_key(
4577                    cx,
4578                    global,
4579                    algorithm,
4580                    format,
4581                    key_data,
4582                    extractable,
4583                    usages,
4584                )
4585            },
4586            ImportKeyAlgorithm::RsaPss(algorithm) => rsa_pss_operation::import_key(
4587                cx,
4588                global,
4589                algorithm,
4590                format,
4591                key_data,
4592                extractable,
4593                usages,
4594            ),
4595            ImportKeyAlgorithm::RsaOaep(algorithm) => rsa_oaep_operation::import_key(
4596                cx,
4597                global,
4598                algorithm,
4599                format,
4600                key_data,
4601                extractable,
4602                usages,
4603            ),
4604            ImportKeyAlgorithm::Ecdsa(algorithm) => ecdsa_operation::import_key(
4605                cx,
4606                global,
4607                algorithm,
4608                format,
4609                key_data,
4610                extractable,
4611                usages,
4612            ),
4613            ImportKeyAlgorithm::Ecdh(algorithm) => ecdh_operation::import_key(
4614                cx,
4615                global,
4616                algorithm,
4617                format,
4618                key_data,
4619                extractable,
4620                usages,
4621            ),
4622            ImportKeyAlgorithm::Ed25519(_algorithm) => {
4623                ed25519_operation::import_key(cx, global, format, key_data, extractable, usages)
4624            },
4625            ImportKeyAlgorithm::X25519(_algorithm) => {
4626                x25519_operation::import_key(cx, global, format, key_data, extractable, usages)
4627            },
4628            ImportKeyAlgorithm::AesCtr(_algorithm) => {
4629                aes_ctr_operation::import_key(cx, global, format, key_data, extractable, usages)
4630            },
4631            ImportKeyAlgorithm::AesCbc(_algorithm) => {
4632                aes_cbc_operation::import_key(cx, global, format, key_data, extractable, usages)
4633            },
4634            ImportKeyAlgorithm::AesGcm(_algorithm) => {
4635                aes_gcm_operation::import_key(cx, global, format, key_data, extractable, usages)
4636            },
4637            ImportKeyAlgorithm::AesKw(_algorithm) => {
4638                aes_kw_operation::import_key(cx, global, format, key_data, extractable, usages)
4639            },
4640            ImportKeyAlgorithm::Hmac(algorithm) => hmac_operation::import_key(
4641                cx,
4642                global,
4643                algorithm,
4644                format,
4645                key_data,
4646                extractable,
4647                usages,
4648            ),
4649            ImportKeyAlgorithm::Hkdf(_algorithm) => {
4650                hkdf_operation::import_key(cx, global, format, key_data, extractable, usages)
4651            },
4652            ImportKeyAlgorithm::Pbkdf2(_algorithm) => {
4653                pbkdf2_operation::import_key(cx, global, format, key_data, extractable, usages)
4654            },
4655            ImportKeyAlgorithm::MlKem(algorithm) => ml_kem_operation::import_key(
4656                cx,
4657                global,
4658                algorithm,
4659                format,
4660                key_data,
4661                extractable,
4662                usages,
4663            ),
4664            ImportKeyAlgorithm::MlDsa(algorithm) => ml_dsa_operation::import_key(
4665                cx,
4666                global,
4667                algorithm,
4668                format,
4669                key_data,
4670                extractable,
4671                usages,
4672            ),
4673            ImportKeyAlgorithm::AesOcb(_algorithm) => {
4674                aes_ocb_operation::import_key(cx, global, format, key_data, extractable, usages)
4675            },
4676            ImportKeyAlgorithm::ChaCha20Poly1305(_algorithm) => {
4677                chacha20_poly1305_operation::import_key(
4678                    cx,
4679                    global,
4680                    format,
4681                    key_data,
4682                    extractable,
4683                    usages,
4684                )
4685            },
4686            ImportKeyAlgorithm::Argon2(algorithm) => argon2_operation::import_key(
4687                cx,
4688                global,
4689                algorithm,
4690                format,
4691                key_data,
4692                extractable,
4693                usages,
4694            ),
4695        }
4696    }
4697}
4698
4699/// The value of the key "exportKey" in the internal object supportedAlgorithms
4700struct ExportKeyOperation {}
4701
4702impl Operation for ExportKeyOperation {
4703    type RegisteredAlgorithm = ExportKeyAlgorithm;
4704}
4705
4706/// Normalized algorithm for the "exportKey" operation, used as output of
4707/// <https://w3c.github.io/webcrypto/#dfn-normalize-an-algorithm>
4708enum ExportKeyAlgorithm {
4709    RsassaPkcs1V1_5(SubtleAlgorithm),
4710    RsaPss(SubtleAlgorithm),
4711    RsaOaep(SubtleAlgorithm),
4712    Ecdsa(SubtleAlgorithm),
4713    Ecdh(SubtleAlgorithm),
4714    Ed25519(SubtleAlgorithm),
4715    X25519(SubtleAlgorithm),
4716    AesCtr(SubtleAlgorithm),
4717    AesCbc(SubtleAlgorithm),
4718    AesGcm(SubtleAlgorithm),
4719    AesKw(SubtleAlgorithm),
4720    Hmac(SubtleAlgorithm),
4721    MlKem(SubtleAlgorithm),
4722    MlDsa(SubtleAlgorithm),
4723    AesOcb(SubtleAlgorithm),
4724    ChaCha20Poly1305(SubtleAlgorithm),
4725}
4726
4727impl NormalizedAlgorithm for ExportKeyAlgorithm {
4728    fn from_object_value(
4729        cx: &mut js::context::JSContext,
4730        algorithm_name: CryptoAlgorithm,
4731        value: HandleValue,
4732    ) -> Fallible<Self> {
4733        match algorithm_name {
4734            CryptoAlgorithm::RsassaPkcs1V1_5 => Ok(ExportKeyAlgorithm::RsassaPkcs1V1_5(
4735                value.try_into_with_cx(cx)?,
4736            )),
4737            CryptoAlgorithm::RsaPss => Ok(ExportKeyAlgorithm::RsaPss(value.try_into_with_cx(cx)?)),
4738            CryptoAlgorithm::RsaOaep => {
4739                Ok(ExportKeyAlgorithm::RsaOaep(value.try_into_with_cx(cx)?))
4740            },
4741            CryptoAlgorithm::Ecdsa => Ok(ExportKeyAlgorithm::Ecdsa(value.try_into_with_cx(cx)?)),
4742            CryptoAlgorithm::Ecdh => Ok(ExportKeyAlgorithm::Ecdh(value.try_into_with_cx(cx)?)),
4743            CryptoAlgorithm::Ed25519 => {
4744                Ok(ExportKeyAlgorithm::Ed25519(value.try_into_with_cx(cx)?))
4745            },
4746            CryptoAlgorithm::X25519 => Ok(ExportKeyAlgorithm::X25519(value.try_into_with_cx(cx)?)),
4747            CryptoAlgorithm::AesCtr => Ok(ExportKeyAlgorithm::AesCtr(value.try_into_with_cx(cx)?)),
4748            CryptoAlgorithm::AesCbc => Ok(ExportKeyAlgorithm::AesCbc(value.try_into_with_cx(cx)?)),
4749            CryptoAlgorithm::AesGcm => Ok(ExportKeyAlgorithm::AesGcm(value.try_into_with_cx(cx)?)),
4750            CryptoAlgorithm::AesKw => Ok(ExportKeyAlgorithm::AesKw(value.try_into_with_cx(cx)?)),
4751            CryptoAlgorithm::Hmac => Ok(ExportKeyAlgorithm::Hmac(value.try_into_with_cx(cx)?)),
4752            CryptoAlgorithm::MlKem512 | CryptoAlgorithm::MlKem768 | CryptoAlgorithm::MlKem1024 => {
4753                Ok(ExportKeyAlgorithm::MlKem(value.try_into_with_cx(cx)?))
4754            },
4755            CryptoAlgorithm::MlDsa44 | CryptoAlgorithm::MlDsa65 | CryptoAlgorithm::MlDsa87 => {
4756                Ok(ExportKeyAlgorithm::MlDsa(value.try_into_with_cx(cx)?))
4757            },
4758            CryptoAlgorithm::AesOcb => Ok(ExportKeyAlgorithm::AesOcb(value.try_into_with_cx(cx)?)),
4759            CryptoAlgorithm::ChaCha20Poly1305 => Ok(ExportKeyAlgorithm::ChaCha20Poly1305(
4760                value.try_into_with_cx(cx)?,
4761            )),
4762            _ => Err(Error::NotSupported(Some(format!(
4763                "{} does not support \"exportKey\" operation",
4764                algorithm_name.as_str()
4765            )))),
4766        }
4767    }
4768
4769    fn name(&self) -> CryptoAlgorithm {
4770        match self {
4771            ExportKeyAlgorithm::RsassaPkcs1V1_5(algorithm) => algorithm.name,
4772            ExportKeyAlgorithm::RsaPss(algorithm) => algorithm.name,
4773            ExportKeyAlgorithm::RsaOaep(algorithm) => algorithm.name,
4774            ExportKeyAlgorithm::Ecdsa(algorithm) => algorithm.name,
4775            ExportKeyAlgorithm::Ecdh(algorithm) => algorithm.name,
4776            ExportKeyAlgorithm::Ed25519(algorithm) => algorithm.name,
4777            ExportKeyAlgorithm::X25519(algorithm) => algorithm.name,
4778            ExportKeyAlgorithm::AesCtr(algorithm) => algorithm.name,
4779            ExportKeyAlgorithm::AesCbc(algorithm) => algorithm.name,
4780            ExportKeyAlgorithm::AesGcm(algorithm) => algorithm.name,
4781            ExportKeyAlgorithm::AesKw(algorithm) => algorithm.name,
4782            ExportKeyAlgorithm::Hmac(algorithm) => algorithm.name,
4783            ExportKeyAlgorithm::MlKem(algorithm) => algorithm.name,
4784            ExportKeyAlgorithm::MlDsa(algorithm) => algorithm.name,
4785            ExportKeyAlgorithm::AesOcb(algorithm) => algorithm.name,
4786            ExportKeyAlgorithm::ChaCha20Poly1305(algorithm) => algorithm.name,
4787        }
4788    }
4789}
4790
4791impl ExportKeyAlgorithm {
4792    fn export_key(&self, format: KeyFormat, key: &CryptoKey) -> Result<ExportedKey, Error> {
4793        match self {
4794            ExportKeyAlgorithm::RsassaPkcs1V1_5(_algorithm) => {
4795                rsassa_pkcs1_v1_5_operation::export_key(format, key)
4796            },
4797            ExportKeyAlgorithm::RsaPss(_algorithm) => rsa_pss_operation::export_key(format, key),
4798            ExportKeyAlgorithm::RsaOaep(_algorithm) => rsa_oaep_operation::export_key(format, key),
4799            ExportKeyAlgorithm::Ecdsa(_algorithm) => ecdsa_operation::export_key(format, key),
4800            ExportKeyAlgorithm::Ecdh(_algorithm) => ecdh_operation::export_key(format, key),
4801            ExportKeyAlgorithm::Ed25519(_algorithm) => ed25519_operation::export_key(format, key),
4802            ExportKeyAlgorithm::X25519(_algorithm) => x25519_operation::export_key(format, key),
4803            ExportKeyAlgorithm::AesCtr(_algorithm) => aes_ctr_operation::export_key(format, key),
4804            ExportKeyAlgorithm::AesCbc(_algorithm) => aes_cbc_operation::export_key(format, key),
4805            ExportKeyAlgorithm::AesGcm(_algorithm) => aes_gcm_operation::export_key(format, key),
4806            ExportKeyAlgorithm::AesKw(_algorithm) => aes_kw_operation::export_key(format, key),
4807            ExportKeyAlgorithm::Hmac(_algorithm) => hmac_operation::export_key(format, key),
4808            ExportKeyAlgorithm::MlKem(_algorithm) => ml_kem_operation::export_key(format, key),
4809            ExportKeyAlgorithm::MlDsa(_algorithm) => ml_dsa_operation::export_key(format, key),
4810            ExportKeyAlgorithm::AesOcb(_algorithm) => aes_ocb_operation::export_key(format, key),
4811            ExportKeyAlgorithm::ChaCha20Poly1305(_algorithm) => {
4812                chacha20_poly1305_operation::export_key(format, key)
4813            },
4814        }
4815    }
4816}
4817
4818/// The value of the key "get key length" in the internal object supportedAlgorithms
4819struct GetKeyLengthOperation {}
4820
4821impl Operation for GetKeyLengthOperation {
4822    type RegisteredAlgorithm = GetKeyLengthAlgorithm;
4823}
4824
4825/// Normalized algorithm for the "get key length" operation, used as output of
4826/// <https://w3c.github.io/webcrypto/#dfn-normalize-an-algorithm>
4827enum GetKeyLengthAlgorithm {
4828    AesCtr(SubtleAesDerivedKeyParams),
4829    AesCbc(SubtleAesDerivedKeyParams),
4830    AesGcm(SubtleAesDerivedKeyParams),
4831    AesKw(SubtleAesDerivedKeyParams),
4832    Hmac(SubtleHmacImportParams),
4833    Hkdf(SubtleAlgorithm),
4834    Pbkdf2(SubtleAlgorithm),
4835    AesOcb(SubtleAesDerivedKeyParams),
4836    ChaCha20Poly1305(SubtleAlgorithm),
4837    Argon2(SubtleAlgorithm),
4838}
4839
4840impl NormalizedAlgorithm for GetKeyLengthAlgorithm {
4841    fn from_object_value(
4842        cx: &mut js::context::JSContext,
4843        algorithm_name: CryptoAlgorithm,
4844        value: HandleValue,
4845    ) -> Fallible<Self> {
4846        match algorithm_name {
4847            CryptoAlgorithm::AesCtr => {
4848                Ok(GetKeyLengthAlgorithm::AesCtr(value.try_into_with_cx(cx)?))
4849            },
4850            CryptoAlgorithm::AesCbc => {
4851                Ok(GetKeyLengthAlgorithm::AesCbc(value.try_into_with_cx(cx)?))
4852            },
4853            CryptoAlgorithm::AesGcm => {
4854                Ok(GetKeyLengthAlgorithm::AesGcm(value.try_into_with_cx(cx)?))
4855            },
4856            CryptoAlgorithm::AesKw => Ok(GetKeyLengthAlgorithm::AesKw(value.try_into_with_cx(cx)?)),
4857            CryptoAlgorithm::Hmac => Ok(GetKeyLengthAlgorithm::Hmac(value.try_into_with_cx(cx)?)),
4858            CryptoAlgorithm::Hkdf => Ok(GetKeyLengthAlgorithm::Hkdf(value.try_into_with_cx(cx)?)),
4859            CryptoAlgorithm::Pbkdf2 => {
4860                Ok(GetKeyLengthAlgorithm::Pbkdf2(value.try_into_with_cx(cx)?))
4861            },
4862            CryptoAlgorithm::AesOcb => {
4863                Ok(GetKeyLengthAlgorithm::AesOcb(value.try_into_with_cx(cx)?))
4864            },
4865            CryptoAlgorithm::ChaCha20Poly1305 => Ok(GetKeyLengthAlgorithm::ChaCha20Poly1305(
4866                value.try_into_with_cx(cx)?,
4867            )),
4868            CryptoAlgorithm::Argon2D | CryptoAlgorithm::Argon2I | CryptoAlgorithm::Argon2ID => {
4869                Ok(GetKeyLengthAlgorithm::Argon2(value.try_into_with_cx(cx)?))
4870            },
4871            _ => Err(Error::NotSupported(Some(format!(
4872                "{} does not support \"get key length\" operation",
4873                algorithm_name.as_str()
4874            )))),
4875        }
4876    }
4877
4878    fn name(&self) -> CryptoAlgorithm {
4879        match self {
4880            GetKeyLengthAlgorithm::AesCtr(algorithm) => algorithm.name,
4881            GetKeyLengthAlgorithm::AesCbc(algorithm) => algorithm.name,
4882            GetKeyLengthAlgorithm::AesGcm(algorithm) => algorithm.name,
4883            GetKeyLengthAlgorithm::AesKw(algorithm) => algorithm.name,
4884            GetKeyLengthAlgorithm::Hmac(algorithm) => algorithm.name,
4885            GetKeyLengthAlgorithm::Hkdf(algorithm) => algorithm.name,
4886            GetKeyLengthAlgorithm::Pbkdf2(algorithm) => algorithm.name,
4887            GetKeyLengthAlgorithm::AesOcb(algorithm) => algorithm.name,
4888            GetKeyLengthAlgorithm::ChaCha20Poly1305(algorithm) => algorithm.name,
4889            GetKeyLengthAlgorithm::Argon2(algorithm) => algorithm.name,
4890        }
4891    }
4892}
4893
4894impl GetKeyLengthAlgorithm {
4895    fn get_key_length(&self) -> Result<Option<u32>, Error> {
4896        match self {
4897            GetKeyLengthAlgorithm::AesCtr(algorithm) => {
4898                aes_ctr_operation::get_key_length(algorithm)
4899            },
4900            GetKeyLengthAlgorithm::AesCbc(algorithm) => {
4901                aes_cbc_operation::get_key_length(algorithm)
4902            },
4903            GetKeyLengthAlgorithm::AesGcm(algorithm) => {
4904                aes_gcm_operation::get_key_length(algorithm)
4905            },
4906            GetKeyLengthAlgorithm::AesKw(algorithm) => aes_kw_operation::get_key_length(algorithm),
4907            GetKeyLengthAlgorithm::Hmac(algorithm) => hmac_operation::get_key_length(algorithm),
4908            GetKeyLengthAlgorithm::Hkdf(_algorithm) => hkdf_operation::get_key_length(),
4909            GetKeyLengthAlgorithm::Pbkdf2(_algorithm) => pbkdf2_operation::get_key_length(),
4910            GetKeyLengthAlgorithm::AesOcb(algorithm) => {
4911                aes_ocb_operation::get_key_length(algorithm)
4912            },
4913            GetKeyLengthAlgorithm::ChaCha20Poly1305(_algorithm) => {
4914                chacha20_poly1305_operation::get_key_length()
4915            },
4916            GetKeyLengthAlgorithm::Argon2(_algorithm) => argon2_operation::get_key_length(),
4917        }
4918    }
4919}
4920
4921/// The value of the key "encapsulate" in the internal object supportedAlgorithms
4922struct EncapsulateOperation {}
4923
4924impl Operation for EncapsulateOperation {
4925    type RegisteredAlgorithm = EncapsulateAlgorithm;
4926}
4927
4928/// Normalized algorithm for the "encapsulate" operation, used as output of
4929/// <https://w3c.github.io/webcrypto/#dfn-normalize-an-algorithm>
4930enum EncapsulateAlgorithm {
4931    MlKem(SubtleAlgorithm),
4932}
4933
4934impl NormalizedAlgorithm for EncapsulateAlgorithm {
4935    fn from_object_value(
4936        cx: &mut js::context::JSContext,
4937        algorithm_name: CryptoAlgorithm,
4938        value: HandleValue,
4939    ) -> Fallible<Self> {
4940        match algorithm_name {
4941            CryptoAlgorithm::MlKem512 | CryptoAlgorithm::MlKem768 | CryptoAlgorithm::MlKem1024 => {
4942                Ok(EncapsulateAlgorithm::MlKem(value.try_into_with_cx(cx)?))
4943            },
4944            _ => Err(Error::NotSupported(Some(format!(
4945                "{} does not support \"encapsulate\" operation",
4946                algorithm_name.as_str()
4947            )))),
4948        }
4949    }
4950
4951    fn name(&self) -> CryptoAlgorithm {
4952        match self {
4953            EncapsulateAlgorithm::MlKem(algorithm) => algorithm.name,
4954        }
4955    }
4956}
4957
4958impl EncapsulateAlgorithm {
4959    fn encapsulate(&self, key: &CryptoKey) -> Result<SubtleEncapsulatedBits, Error> {
4960        match self {
4961            EncapsulateAlgorithm::MlKem(algorithm) => ml_kem_operation::encapsulate(algorithm, key),
4962        }
4963    }
4964}
4965
4966// The value of the key "decapsulate" in the internal object supportedAlgorithms
4967struct DecapsulateOperation {}
4968
4969impl Operation for DecapsulateOperation {
4970    type RegisteredAlgorithm = DecapsulateAlgorithm;
4971}
4972
4973/// Normalized algorithm for the "decapsulate" operation, used as output of
4974/// <https://w3c.github.io/webcrypto/#dfn-normalize-an-algorithm>
4975enum DecapsulateAlgorithm {
4976    MlKem(SubtleAlgorithm),
4977}
4978
4979impl NormalizedAlgorithm for DecapsulateAlgorithm {
4980    fn from_object_value(
4981        cx: &mut js::context::JSContext,
4982        algorithm_name: CryptoAlgorithm,
4983        value: HandleValue,
4984    ) -> Fallible<Self> {
4985        match algorithm_name {
4986            CryptoAlgorithm::MlKem512 | CryptoAlgorithm::MlKem768 | CryptoAlgorithm::MlKem1024 => {
4987                Ok(DecapsulateAlgorithm::MlKem(value.try_into_with_cx(cx)?))
4988            },
4989            _ => Err(Error::NotSupported(Some(format!(
4990                "{} does not support \"decapsulate\" operation",
4991                algorithm_name.as_str()
4992            )))),
4993        }
4994    }
4995
4996    fn name(&self) -> CryptoAlgorithm {
4997        match self {
4998            DecapsulateAlgorithm::MlKem(algorithm) => algorithm.name,
4999        }
5000    }
5001}
5002
5003impl DecapsulateAlgorithm {
5004    fn decapsulate(&self, key: &CryptoKey, ciphertext: &[u8]) -> Result<Vec<u8>, Error> {
5005        match self {
5006            DecapsulateAlgorithm::MlKem(algorithm) => {
5007                ml_kem_operation::decapsulate(algorithm, key, ciphertext)
5008            },
5009        }
5010    }
5011}
5012
5013// The value of the key "getPublicKey" in the internal object supportedAlgorithms
5014struct GetPublicKeyOperation {}
5015
5016impl Operation for GetPublicKeyOperation {
5017    type RegisteredAlgorithm = GetPublicKeyAlgorithm;
5018}
5019
5020/// Normalized algorithm for the "getPublicKey" operation, used as output of
5021/// <https://w3c.github.io/webcrypto/#dfn-normalize-an-algorithm>
5022enum GetPublicKeyAlgorithm {
5023    RsassaPkcs1v1_5(SubtleAlgorithm),
5024    RsaPss(SubtleAlgorithm),
5025    RsaOaep(SubtleAlgorithm),
5026    Ecdsa(SubtleAlgorithm),
5027    Ecdh(SubtleAlgorithm),
5028    Ed25519(SubtleAlgorithm),
5029    X25519(SubtleAlgorithm),
5030}
5031
5032impl NormalizedAlgorithm for GetPublicKeyAlgorithm {
5033    fn from_object_value(
5034        cx: &mut js::context::JSContext,
5035        algorithm_name: CryptoAlgorithm,
5036        value: HandleValue,
5037    ) -> Fallible<Self> {
5038        match algorithm_name {
5039            CryptoAlgorithm::RsassaPkcs1V1_5 => Ok(GetPublicKeyAlgorithm::RsassaPkcs1v1_5(
5040                value.try_into_with_cx(cx)?,
5041            )),
5042            CryptoAlgorithm::RsaPss => {
5043                Ok(GetPublicKeyAlgorithm::RsaPss(value.try_into_with_cx(cx)?))
5044            },
5045            CryptoAlgorithm::RsaOaep => {
5046                Ok(GetPublicKeyAlgorithm::RsaOaep(value.try_into_with_cx(cx)?))
5047            },
5048            CryptoAlgorithm::Ecdsa => Ok(GetPublicKeyAlgorithm::Ecdsa(value.try_into_with_cx(cx)?)),
5049            CryptoAlgorithm::Ecdh => Ok(GetPublicKeyAlgorithm::Ecdh(value.try_into_with_cx(cx)?)),
5050            CryptoAlgorithm::Ed25519 => {
5051                Ok(GetPublicKeyAlgorithm::Ed25519(value.try_into_with_cx(cx)?))
5052            },
5053            CryptoAlgorithm::X25519 => {
5054                Ok(GetPublicKeyAlgorithm::X25519(value.try_into_with_cx(cx)?))
5055            },
5056            _ => Err(Error::NotSupported(Some(format!(
5057                "{} does not support \"getPublicKey\" operation",
5058                algorithm_name.as_str()
5059            )))),
5060        }
5061    }
5062
5063    fn name(&self) -> CryptoAlgorithm {
5064        match self {
5065            GetPublicKeyAlgorithm::RsassaPkcs1v1_5(algorithm) => algorithm.name,
5066            GetPublicKeyAlgorithm::RsaPss(algorithm) => algorithm.name,
5067            GetPublicKeyAlgorithm::RsaOaep(algorithm) => algorithm.name,
5068            GetPublicKeyAlgorithm::Ecdsa(algorithm) => algorithm.name,
5069            GetPublicKeyAlgorithm::Ecdh(algorithm) => algorithm.name,
5070            GetPublicKeyAlgorithm::Ed25519(algorithm) => algorithm.name,
5071            GetPublicKeyAlgorithm::X25519(algorithm) => algorithm.name,
5072        }
5073    }
5074}
5075
5076impl GetPublicKeyAlgorithm {
5077    fn get_public_key(
5078        &self,
5079        cx: &mut js::context::JSContext,
5080        global: &GlobalScope,
5081        key: &CryptoKey,
5082        algorithm: &KeyAlgorithmAndDerivatives,
5083        usages: Vec<KeyUsage>,
5084    ) -> Result<DomRoot<CryptoKey>, Error> {
5085        match self {
5086            GetPublicKeyAlgorithm::RsassaPkcs1v1_5(_algorithm) => {
5087                rsassa_pkcs1_v1_5_operation::get_public_key(cx, global, key, algorithm, usages)
5088            },
5089            GetPublicKeyAlgorithm::RsaPss(_algorithm) => {
5090                rsa_pss_operation::get_public_key(cx, global, key, algorithm, usages)
5091            },
5092            GetPublicKeyAlgorithm::RsaOaep(_algorithm) => {
5093                rsa_oaep_operation::get_public_key(cx, global, key, algorithm, usages)
5094            },
5095            GetPublicKeyAlgorithm::Ecdsa(_algorithm) => {
5096                ecdsa_operation::get_public_key(cx, global, key, algorithm, usages)
5097            },
5098            GetPublicKeyAlgorithm::Ecdh(_algorithm) => {
5099                ecdh_operation::get_public_key(cx, global, key, algorithm, usages)
5100            },
5101            GetPublicKeyAlgorithm::Ed25519(_algorithm) => {
5102                ed25519_operation::get_public_key(cx, global, key, algorithm, usages)
5103            },
5104            GetPublicKeyAlgorithm::X25519(_algorithm) => {
5105                x25519_operation::get_public_key(cx, global, key, algorithm, usages)
5106            },
5107        }
5108    }
5109}