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