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