Skip to main content

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