Skip to main content

script/dom/webcrypto/
subtlecrypto.rs

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