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