Skip to main content

script/dom/webcrypto/
subtlecrypto.rs

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