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