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