Skip to main content

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