Skip to main content

script/dom/webcrypto/
subtlecrypto.rs

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