script/dom/
subtlecrypto.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5mod aes_cbc_operation;
6mod aes_common;
7mod aes_ctr_operation;
8mod aes_gcm_operation;
9mod aes_kw_operation;
10mod aes_ocb_operation;
11mod argon2_operation;
12mod chacha20_poly1305_operation;
13mod cshake_operation;
14mod ecdh_operation;
15mod ecdsa_operation;
16mod ed25519_operation;
17mod hkdf_operation;
18mod hmac_operation;
19mod ml_dsa_operation;
20mod ml_kem_operation;
21mod pbkdf2_operation;
22mod rsa_common;
23mod rsa_oaep_operation;
24mod rsa_pss_operation;
25mod rsassa_pkcs1_v1_5_operation;
26mod sha3_operation;
27mod sha_operation;
28mod x25519_operation;
29
30use std::fmt::Display;
31use std::ptr;
32use std::rc::Rc;
33use std::str::FromStr;
34
35use base64ct::{Base64UrlUnpadded, Encoding};
36use dom_struct::dom_struct;
37use js::conversions::ConversionResult;
38use js::jsapi::{Heap, JSObject};
39use js::jsval::{ObjectValue, UndefinedValue};
40use js::rust::wrappers::JS_ParseJSON;
41use js::rust::{HandleValue, MutableHandleValue};
42use js::typedarray::ArrayBufferU8;
43
44use crate::dom::bindings::buffer_source::create_buffer_source;
45use crate::dom::bindings::codegen::Bindings::CryptoKeyBinding::{
46    CryptoKeyMethods, CryptoKeyPair, KeyType, KeyUsage,
47};
48use crate::dom::bindings::codegen::Bindings::SubtleCryptoBinding::{
49    AeadParams, AesCbcParams, AesCtrParams, AesDerivedKeyParams, AesGcmParams, AesKeyAlgorithm,
50    AesKeyGenParams, Algorithm, AlgorithmIdentifier, Argon2Params, CShakeParams, ContextParams,
51    EcKeyAlgorithm, EcKeyGenParams, EcKeyImportParams, EcdhKeyDeriveParams, EcdsaParams,
52    EncapsulatedBits, EncapsulatedKey, HkdfParams, HmacImportParams, HmacKeyAlgorithm,
53    HmacKeyGenParams, JsonWebKey, KeyAlgorithm, KeyFormat, Pbkdf2Params, RsaHashedImportParams,
54    RsaHashedKeyAlgorithm, RsaHashedKeyGenParams, RsaKeyAlgorithm, RsaOaepParams, RsaPssParams,
55    SubtleCryptoMethods,
56};
57use crate::dom::bindings::codegen::UnionTypes::{
58    ArrayBufferViewOrArrayBuffer, ArrayBufferViewOrArrayBufferOrJsonWebKey, ObjectOrString,
59};
60use crate::dom::bindings::conversions::{SafeFromJSValConvertible, SafeToJSValConvertible};
61use crate::dom::bindings::error::{Error, Fallible};
62use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
63use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
64use crate::dom::bindings::root::DomRoot;
65use crate::dom::bindings::str::{DOMString, serialize_jsval_to_json_utf8};
66use crate::dom::bindings::trace::RootedTraceableBox;
67use crate::dom::bindings::utils::set_dictionary_property;
68use crate::dom::cryptokey::{CryptoKey, CryptoKeyOrCryptoKeyPair};
69use crate::dom::globalscope::GlobalScope;
70use crate::dom::promise::Promise;
71use crate::realms::InRealm;
72use crate::script_runtime::{CanGc, JSContext};
73
74// Regconized algorithm name from <https://w3c.github.io/webcrypto/>
75const ALG_RSASSA_PKCS1_V1_5: &str = "RSASSA-PKCS1-v1_5";
76const ALG_RSA_PSS: &str = "RSA-PSS";
77const ALG_RSA_OAEP: &str = "RSA-OAEP";
78const ALG_ECDSA: &str = "ECDSA";
79const ALG_ECDH: &str = "ECDH";
80const ALG_ED25519: &str = "Ed25519";
81const ALG_X25519: &str = "X25519";
82const ALG_AES_CTR: &str = "AES-CTR";
83const ALG_AES_CBC: &str = "AES-CBC";
84const ALG_AES_GCM: &str = "AES-GCM";
85const ALG_AES_KW: &str = "AES-KW";
86const ALG_HMAC: &str = "HMAC";
87const ALG_SHA1: &str = "SHA-1";
88const ALG_SHA256: &str = "SHA-256";
89const ALG_SHA384: &str = "SHA-384";
90const ALG_SHA512: &str = "SHA-512";
91const ALG_HKDF: &str = "HKDF";
92const ALG_PBKDF2: &str = "PBKDF2";
93
94// Regconized algorithm name from <https://wicg.github.io/webcrypto-modern-algos/>
95const ALG_ML_KEM_512: &str = "ML-KEM-512";
96const ALG_ML_KEM_768: &str = "ML-KEM-768";
97const ALG_ML_KEM_1024: &str = "ML-KEM-1024";
98const ALG_ML_DSA_44: &str = "ML-DSA-44";
99const ALG_ML_DSA_65: &str = "ML-DSA-65";
100const ALG_ML_DSA_87: &str = "ML-DSA-87";
101const ALG_AES_OCB: &str = "AES-OCB";
102const ALG_CHACHA20_POLY1305: &str = "ChaCha20-Poly1305";
103const ALG_SHA3_256: &str = "SHA3-256";
104const ALG_SHA3_384: &str = "SHA3-384";
105const ALG_SHA3_512: &str = "SHA3-512";
106const ALG_CSHAKE_128: &str = "cSHAKE128";
107const ALG_CSHAKE_256: &str = "cSHAKE256";
108const ALG_ARGON2D: &str = "Argon2d";
109const ALG_ARGON2I: &str = "Argon2i";
110const ALG_ARGON2ID: &str = "Argon2id";
111
112static SUPPORTED_ALGORITHMS: &[&str] = &[
113    ALG_RSASSA_PKCS1_V1_5,
114    ALG_RSA_PSS,
115    ALG_RSA_OAEP,
116    ALG_ECDSA,
117    ALG_ECDH,
118    ALG_ED25519,
119    ALG_X25519,
120    ALG_AES_CTR,
121    ALG_AES_CBC,
122    ALG_AES_GCM,
123    ALG_AES_KW,
124    ALG_HMAC,
125    ALG_SHA1,
126    ALG_SHA256,
127    ALG_SHA384,
128    ALG_SHA512,
129    ALG_HKDF,
130    ALG_PBKDF2,
131    ALG_ML_KEM_512,
132    ALG_ML_KEM_768,
133    ALG_ML_KEM_1024,
134    ALG_ML_DSA_44,
135    ALG_ML_DSA_65,
136    ALG_ML_DSA_87,
137    ALG_AES_OCB,
138    ALG_CHACHA20_POLY1305,
139    ALG_SHA3_256,
140    ALG_SHA3_384,
141    ALG_SHA3_512,
142    ALG_CSHAKE_128,
143    ALG_CSHAKE_256,
144    ALG_ARGON2D,
145    ALG_ARGON2I,
146    ALG_ARGON2ID,
147];
148
149// Named elliptic curves
150const NAMED_CURVE_P256: &str = "P-256";
151const NAMED_CURVE_P384: &str = "P-384";
152const NAMED_CURVE_P521: &str = "P-521";
153
154static SUPPORTED_CURVES: &[&str] = &[NAMED_CURVE_P256, NAMED_CURVE_P384, NAMED_CURVE_P521];
155
156/// <https://w3c.github.io/webcrypto/#supported-operation>
157enum Operation {
158    Encrypt,
159    Decrypt,
160    Sign,
161    Verify,
162    Digest,
163    DeriveBits,
164    WrapKey,
165    UnwrapKey,
166    GenerateKey,
167    ImportKey,
168    ExportKey,
169    GetKeyLength,
170    Encapsulate,
171    Decapsulate,
172}
173
174impl Operation {
175    fn as_str(&self) -> &'static str {
176        match self {
177            Operation::Encrypt => "encrypt",
178            Operation::Decrypt => "decrypt",
179            Operation::Sign => "sign",
180            Operation::Verify => "verify",
181            Operation::Digest => "digest",
182            Operation::DeriveBits => "deriveBits",
183            Operation::WrapKey => "wrapKey",
184            Operation::UnwrapKey => "unwrapKey",
185            Operation::GenerateKey => "generateKey",
186            Operation::ImportKey => "importKey",
187            Operation::ExportKey => "exportKey",
188            Operation::GetKeyLength => "get key length",
189            Operation::Encapsulate => "encapsulate",
190            Operation::Decapsulate => "decapsulate",
191        }
192    }
193}
194
195#[dom_struct]
196pub(crate) struct SubtleCrypto {
197    reflector_: Reflector,
198}
199
200impl SubtleCrypto {
201    fn new_inherited() -> SubtleCrypto {
202        SubtleCrypto {
203            reflector_: Reflector::new(),
204        }
205    }
206
207    pub(crate) fn new(global: &GlobalScope, can_gc: CanGc) -> DomRoot<SubtleCrypto> {
208        reflect_dom_object(Box::new(SubtleCrypto::new_inherited()), global, can_gc)
209    }
210
211    /// Queue a global task on the crypto task source, given realm's global object, to resolve
212    /// promise with the result of creating an ArrayBuffer in realm, containing data. If it fails
213    /// to create buffer source, reject promise with a JSFailedError.
214    fn resolve_promise_with_data(&self, promise: Rc<Promise>, data: Vec<u8>) {
215        let trusted_promise = TrustedPromise::new(promise);
216        self.global().task_manager().crypto_task_source().queue(
217            task!(resolve_data: move || {
218                let promise = trusted_promise.root();
219
220                let cx = GlobalScope::get_cx();
221                rooted!(in(*cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>());
222                match create_buffer_source::<ArrayBufferU8>(cx, &data, array_buffer_ptr.handle_mut(), CanGc::note()) {
223                    Ok(_) => promise.resolve_native(&*array_buffer_ptr, CanGc::note()),
224                    Err(_) => promise.reject_error(Error::JSFailed, CanGc::note()),
225                }
226            }),
227        );
228    }
229
230    /// Queue a global task on the crypto task source, given realm's global object, to resolve
231    /// promise with the result of converting a JsonWebKey dictionary to an ECMAScript Object in
232    /// realm, as defined by [WebIDL].
233    fn resolve_promise_with_jwk(&self, promise: Rc<Promise>, jwk: Box<JsonWebKey>) {
234        // NOTE: Serialize the JsonWebKey dictionary by stringifying it, in order to pass it to
235        // other threads.
236        let cx = GlobalScope::get_cx();
237        let stringified_jwk = match jwk.stringify(cx) {
238            Ok(stringified_jwk) => stringified_jwk.to_string(),
239            Err(error) => {
240                self.reject_promise_with_error(promise, error);
241                return;
242            },
243        };
244
245        let trusted_subtle = Trusted::new(self);
246        let trusted_promise = TrustedPromise::new(promise);
247        self.global()
248            .task_manager()
249            .crypto_task_source()
250            .queue(task!(resolve_jwk: move || {
251                let subtle = trusted_subtle.root();
252                let promise = trusted_promise.root();
253
254                let cx = GlobalScope::get_cx();
255                match JsonWebKey::parse(cx, stringified_jwk.as_bytes()) {
256                    Ok(jwk) => {
257                        rooted!(in(*cx) let mut rval = UndefinedValue());
258                        jwk.safe_to_jsval(cx, rval.handle_mut(), CanGc::note());
259                        rooted!(in(*cx) let mut object = rval.to_object());
260                        promise.resolve_native(&*object, CanGc::note());
261                    },
262                    Err(error) => {
263                        subtle.reject_promise_with_error(promise, error);
264                        return;
265                    },
266                }
267            }));
268    }
269
270    /// Queue a global task on the crypto task source, given realm's global object, to resolve
271    /// promise with a CryptoKey.
272    fn resolve_promise_with_key(&self, promise: Rc<Promise>, key: DomRoot<CryptoKey>) {
273        let trusted_key = Trusted::new(&*key);
274        let trusted_promise = TrustedPromise::new(promise);
275        self.global()
276            .task_manager()
277            .crypto_task_source()
278            .queue(task!(resolve_key: move || {
279                let key = trusted_key.root();
280                let promise = trusted_promise.root();
281                promise.resolve_native(&key, CanGc::note());
282            }));
283    }
284
285    /// Queue a global task on the crypto task source, given realm's global object, to resolve
286    /// promise with a CryptoKeyPair.
287    fn resolve_promise_with_key_pair(&self, promise: Rc<Promise>, key_pair: CryptoKeyPair) {
288        let trusted_private_key = key_pair.privateKey.map(|key| Trusted::new(&*key));
289        let trusted_public_key = key_pair.publicKey.map(|key| Trusted::new(&*key));
290        let trusted_promise = TrustedPromise::new(promise);
291        self.global()
292            .task_manager()
293            .crypto_task_source()
294            .queue(task!(resolve_key: move || {
295                let key_pair = CryptoKeyPair {
296                    privateKey: trusted_private_key.map(|trusted_key| trusted_key.root()),
297                    publicKey: trusted_public_key.map(|trusted_key| trusted_key.root()),
298                };
299                let promise = trusted_promise.root();
300                promise.resolve_native(&key_pair, CanGc::note());
301            }));
302    }
303
304    /// Queue a global task on the crypto task source, given realm's global object, to resolve
305    /// promise with a bool value.
306    fn resolve_promise_with_bool(&self, promise: Rc<Promise>, result: bool) {
307        let trusted_promise = TrustedPromise::new(promise);
308        self.global().task_manager().crypto_task_source().queue(
309            task!(generate_key_result: move || {
310                let promise = trusted_promise.root();
311                promise.resolve_native(&result, CanGc::note());
312            }),
313        );
314    }
315
316    /// Queue a global task on the crypto task source, given realm's global object, to reject
317    /// promise with an error.
318    fn reject_promise_with_error(&self, promise: Rc<Promise>, error: Error) {
319        let trusted_promise = TrustedPromise::new(promise);
320        self.global()
321            .task_manager()
322            .crypto_task_source()
323            .queue(task!(reject_error: move || {
324                let promise = trusted_promise.root();
325                promise.reject_error(error, CanGc::note());
326            }));
327    }
328
329    /// Queue a global task on the crypto task source, given realm's global object, to resolve
330    /// promise with the result of converting EncapsulatedKey to an ECMAScript Object in realm, as
331    /// defined by [WebIDL].
332    fn resolve_promise_with_encapsulated_key(
333        &self,
334        promise: Rc<Promise>,
335        encapsulated_key: SubtleEncapsulatedKey,
336    ) {
337        let trusted_promise = TrustedPromise::new(promise);
338        self.global().task_manager().crypto_task_source().queue(
339            task!(resolve_encapsulated_key: move || {
340                let promise = trusted_promise.root();
341                promise.resolve_native(&encapsulated_key, CanGc::note());
342            }),
343        );
344    }
345
346    /// Queue a global task on the crypto task source, given realm's global object, to resolve
347    /// promise with the result of converting EncapsulateBits to an ECMAScript Object in realm, as
348    /// defined by [WebIDL].
349    fn resolve_promise_with_encapsulated_bits(
350        &self,
351        promise: Rc<Promise>,
352        encapsulated_bits: SubtleEncapsulatedBits,
353    ) {
354        let trusted_promise = TrustedPromise::new(promise);
355        self.global().task_manager().crypto_task_source().queue(
356            task!(resolve_encapsulated_bits: move || {
357                let promise = trusted_promise.root();
358                promise.resolve_native(&encapsulated_bits, CanGc::note());
359            }),
360        );
361    }
362}
363
364impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
365    /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-encrypt>
366    fn Encrypt(
367        &self,
368        cx: JSContext,
369        algorithm: AlgorithmIdentifier,
370        key: &CryptoKey,
371        data: ArrayBufferViewOrArrayBuffer,
372        comp: InRealm,
373        can_gc: CanGc,
374    ) -> Rc<Promise> {
375        // Step 1. Let algorithm and key be the algorithm and key parameters passed to the
376        // encrypt() method, respectively.
377        // NOTE: We did that in method parameter.
378
379        // Step 2. Let data be the result of getting a copy of the bytes held by the data parameter
380        // passed to the encrypt() method.
381        let data = match data {
382            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
383            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
384        };
385
386        // Step 3. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
387        // to algorithm and op set to "encrypt".
388        // Step 4. If an error occurred, return a Promise rejected with normalizedAlgorithm.
389        let promise = Promise::new_in_current_realm(comp, can_gc);
390        let normalized_algorithm =
391            match normalize_algorithm(cx, Operation::Encrypt, &algorithm, can_gc) {
392                Ok(normalized_algorithm) => normalized_algorithm,
393                Err(error) => {
394                    promise.reject_error(error, can_gc);
395                    return promise;
396                },
397            };
398
399        // Step 5. Let realm be the relevant realm of this.
400        // Step 6. Let promise be a new Promise.
401        // NOTE: We did that in preparation of Step 4.
402
403        // Step 7. Return promise and perform the remaining steps in parallel.
404        let this = Trusted::new(self);
405        let trusted_promise = TrustedPromise::new(promise.clone());
406        let trusted_key = Trusted::new(key);
407        self.global()
408            .task_manager()
409            .dom_manipulation_task_source()
410            .queue(task!(encrypt: move || {
411                let subtle = this.root();
412                let promise = trusted_promise.root();
413                let key = trusted_key.root();
414
415                // Step 8. If the following steps or referenced procedures say to throw an error,
416                // queue a global task on the crypto task source, given realm's global object, to
417                // reject promise with the returned error; and then terminate the algorithm.
418
419                // Step 9. If the name member of normalizedAlgorithm is not equal to the name
420                // attribute of the [[algorithm]] internal slot of key then throw an
421                // InvalidAccessError.
422                if normalized_algorithm.name() != key.algorithm().name() {
423                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
424                    return;
425                }
426
427                // Step 10. If the [[usages]] internal slot of key does not contain an entry that
428                // is "encrypt", then throw an InvalidAccessError.
429                if !key.usages().contains(&KeyUsage::Encrypt) {
430                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
431                    return;
432                }
433
434                // Step 11. Let ciphertext be the result of performing the encrypt operation
435                // specified by normalizedAlgorithm using algorithm and key and with data as
436                // plaintext.
437                let ciphertext = match normalized_algorithm.encrypt(&key, &data) {
438                    Ok(ciphertext) => ciphertext,
439                    Err(error) => {
440                        subtle.reject_promise_with_error(promise, error);
441                        return;
442                    },
443                };
444
445                // Step 12. Queue a global task on the crypto task source, given realm's global
446                // object, to perform the remaining steps.
447                // Step 13. Let result be the result of creating an ArrayBuffer in realm,
448                // containing ciphertext.
449                // Step 14. Resolve promise with result.
450                subtle.resolve_promise_with_data(promise, ciphertext);
451            }));
452        promise
453    }
454
455    /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-decrypt>
456    fn Decrypt(
457        &self,
458        cx: JSContext,
459        algorithm: AlgorithmIdentifier,
460        key: &CryptoKey,
461        data: ArrayBufferViewOrArrayBuffer,
462        comp: InRealm,
463        can_gc: CanGc,
464    ) -> Rc<Promise> {
465        // Step 1. Let algorithm and key be the algorithm and key parameters passed to the
466        // decrypt() method, respectively.
467        // NOTE: We did that in method parameter.
468
469        // Step 2. Let data be the result of getting a copy of the bytes held by the data parameter
470        // passed to the decrypt() method.
471        let data = match data {
472            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
473            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
474        };
475
476        // Step 3. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
477        // to algorithm and op set to "decrypt".
478        // Step 4. If an error occurred, return a Promise rejected with normalizedAlgorithm.
479        let promise = Promise::new_in_current_realm(comp, can_gc);
480        let normalized_algorithm =
481            match normalize_algorithm(cx, Operation::Decrypt, &algorithm, can_gc) {
482                Ok(normalized_algorithm) => normalized_algorithm,
483                Err(error) => {
484                    promise.reject_error(error, can_gc);
485                    return promise;
486                },
487            };
488
489        // Step 5. Let realm be the relevant realm of this.
490        // Step 6. Let promise be a new Promise.
491        // NOTE: We did that in preparation of Step 4.
492
493        // Step 7. Return promise and perform the remaining steps in parallel.
494        let this = Trusted::new(self);
495        let trusted_promise = TrustedPromise::new(promise.clone());
496        let trusted_key = Trusted::new(key);
497        self.global()
498            .task_manager()
499            .dom_manipulation_task_source()
500            .queue(task!(decrypt: move || {
501                let subtle = this.root();
502                let promise = trusted_promise.root();
503                let key = trusted_key.root();
504
505                // Step 8. If the following steps or referenced procedures say to throw an error,
506                // queue a global task on the crypto task source, given realm's global object, to
507                // reject promise with the returned error; and then terminate the algorithm.
508
509                // Step 9. If the name member of normalizedAlgorithm is not equal to the name
510                // attribute of the [[algorithm]] internal slot of key then throw an
511                // InvalidAccessError.
512                if normalized_algorithm.name() != key.algorithm().name() {
513                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
514                    return;
515                }
516
517                // Step 10. If the [[usages]] internal slot of key does not contain an entry that
518                // is "decrypt", then throw an InvalidAccessError.
519                if !key.usages().contains(&KeyUsage::Decrypt) {
520                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
521                    return;
522                }
523
524                // Step 11. Let plaintext be the result of performing the decrypt operation
525                // specified by normalizedAlgorithm using key and algorithm and with data as
526                // ciphertext.
527                let plaintext = match normalized_algorithm.decrypt(&key, &data) {
528                    Ok(plaintext) => plaintext,
529                    Err(error) => {
530                        subtle.reject_promise_with_error(promise, error);
531                        return;
532                    },
533                };
534
535                // Step 12. Queue a global task on the crypto task source, given realm's global
536                // object, to perform the remaining steps.
537                // Step 13. Let result be the result of creating an ArrayBuffer in realm,
538                // containing plaintext.
539                // Step 14. Resolve promise with result.
540                subtle.resolve_promise_with_data(promise, plaintext);
541            }));
542        promise
543    }
544
545    /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-sign>
546    fn Sign(
547        &self,
548        cx: JSContext,
549        algorithm: AlgorithmIdentifier,
550        key: &CryptoKey,
551        data: ArrayBufferViewOrArrayBuffer,
552        comp: InRealm,
553        can_gc: CanGc,
554    ) -> Rc<Promise> {
555        // Step 1. Let algorithm and key be the algorithm and key parameters passed to the sign()
556        // method, respectively.
557        // NOTE: We did that in method parameter.
558
559        // Step 2. Let data be the result of getting a copy of the bytes held by the data parameter
560        // passed to the sign() method.
561        let data = match &data {
562            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
563            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
564        };
565
566        // Step 3. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
567        // to algorithm and op set to "sign".
568        // Step 4. If an error occurred, return a Promise rejected with normalizedAlgorithm.
569        let promise = Promise::new_in_current_realm(comp, can_gc);
570        let normalized_algorithm =
571            match normalize_algorithm(cx, Operation::Sign, &algorithm, can_gc) {
572                Ok(normalized_algorithm) => normalized_algorithm,
573                Err(error) => {
574                    promise.reject_error(error, can_gc);
575                    return promise;
576                },
577            };
578
579        // Step 5. Let realm be the relevant realm of this.
580        // Step 6. Let promise be a new Promise.
581        // NOTE: We did that in preparation of Step 4.
582
583        // Step 7. Return promise and perform the remaining steps in parallel.
584        let this = Trusted::new(self);
585        let trusted_promise = TrustedPromise::new(promise.clone());
586        let trusted_key = Trusted::new(key);
587        self.global()
588            .task_manager()
589            .dom_manipulation_task_source()
590            .queue(task!(sign: move || {
591                let subtle = this.root();
592                let promise = trusted_promise.root();
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(None));
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(None));
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);
630            }));
631        promise
632    }
633
634    /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-verify>
635    fn Verify(
636        &self,
637        cx: JSContext,
638        algorithm: AlgorithmIdentifier,
639        key: &CryptoKey,
640        signature: ArrayBufferViewOrArrayBuffer,
641        data: ArrayBufferViewOrArrayBuffer,
642        comp: InRealm,
643        can_gc: CanGc,
644    ) -> Rc<Promise> {
645        // Step 1. Let algorithm and key be the algorithm and key parameters passed to the verify()
646        // method, respectively.
647        // NOTE: We did that in method parameter.
648
649        // Step 2. Let signature be the result of getting a copy of the bytes held by the signature
650        // parameter passed to the verify() method.
651        let signature = match &signature {
652            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
653            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
654        };
655
656        // Step 3. Let data be the result of getting a copy of the bytes held by the data parameter
657        // passed to the verify() method.
658        let data = match &data {
659            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
660            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
661        };
662
663        // Step 4. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set to
664        // algorithm and op set to "verify".
665        // Step 5. If an error occurred, return a Promise rejected with normalizedAlgorithm.
666        let promise = Promise::new_in_current_realm(comp, can_gc);
667        let normalized_algorithm =
668            match normalize_algorithm(cx, Operation::Verify, &algorithm, can_gc) {
669                Ok(algorithm) => algorithm,
670                Err(error) => {
671                    promise.reject_error(error, can_gc);
672                    return promise;
673                },
674            };
675
676        // Step 6. Let realm be the relevant realm of this.
677        // Step 7. Let promise be a new Promise.
678        // NOTE: We did that in preparation of Step 5.
679
680        // Step 8. Return promise and perform the remaining steps in parallel.
681        let this = Trusted::new(self);
682        let trusted_promise = TrustedPromise::new(promise.clone());
683        let trusted_key = Trusted::new(key);
684        self.global()
685            .task_manager()
686            .dom_manipulation_task_source()
687            .queue(task!(sign: move || {
688                let subtle = this.root();
689                let promise = trusted_promise.root();
690                let key = trusted_key.root();
691
692                // Step 9. If the following steps or referenced procedures say to throw an error,
693                // queue a global task on the crypto task source, given realm's global object, to
694                // reject promise with the returned error; and then terminate the algorithm.
695
696                // Step 10. If the name member of normalizedAlgorithm is not equal to the name
697                // attribute of the [[algorithm]] internal slot of key then throw an
698                // InvalidAccessError.
699                if normalized_algorithm.name() != key.algorithm().name() {
700                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
701                    return;
702                }
703
704                // Step 11. If the [[usages]] internal slot of key does not contain an entry that
705                // is "verify", then throw an InvalidAccessError.
706                if !key.usages().contains(&KeyUsage::Verify) {
707                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
708                    return;
709                }
710
711                // Step 12. Let result be the result of performing the verify operation specified
712                // by normalizedAlgorithm using key, algorithm and signature and with data as
713                // message.
714                let result = match normalized_algorithm.verify(&key, &data, &signature) {
715                    Ok(result) => result,
716                    Err(error) => {
717                        subtle.reject_promise_with_error(promise, error);
718                        return;
719                    },
720                };
721
722                // Step 13. Queue a global task on the crypto task source, given realm's global
723                // object, to perform the remaining steps.
724                // Step 14. Resolve promise with result.
725                subtle.resolve_promise_with_bool(promise, result);
726            }));
727        promise
728    }
729
730    /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-digest>
731    fn Digest(
732        &self,
733        cx: JSContext,
734        algorithm: AlgorithmIdentifier,
735        data: ArrayBufferViewOrArrayBuffer,
736        comp: InRealm,
737        can_gc: CanGc,
738    ) -> Rc<Promise> {
739        // Step 1. Let algorithm be the algorithm parameter passed to the digest() method.
740        // NOTE: We did that in method parameter.
741
742        // Step 2. Let data be the result of getting a copy of the bytes held by the
743        // data parameter passed to the digest() method.
744        let data = match data {
745            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
746            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
747        };
748
749        // Step 3. Let normalizedAlgorithm be the result of normalizing an algorithm,
750        // with alg set to algorithm and op set to "digest".
751        // Step 4. If an error occurred, return a Promise rejected with normalizedAlgorithm.
752        let promise = Promise::new_in_current_realm(comp, can_gc);
753        let normalized_algorithm =
754            match normalize_algorithm(cx, Operation::Digest, &algorithm, can_gc) {
755                Ok(normalized_algorithm) => normalized_algorithm,
756                Err(error) => {
757                    promise.reject_error(error, can_gc);
758                    return promise;
759                },
760            };
761
762        // Step 5. Let realm be the relevant realm of this.
763        // Step 6. Let promise be a new Promise.
764        // NOTE: We did that in preparation of Step 3.
765
766        // Step 7. Return promise and perform the remaining steps in parallel.
767        let this = Trusted::new(self);
768        let trusted_promise = TrustedPromise::new(promise.clone());
769        self.global()
770            .task_manager()
771            .dom_manipulation_task_source()
772            .queue(task!(generate_key: move || {
773                let subtle = this.root();
774                let promise = trusted_promise.root();
775
776                // Step 8. If the following steps or referenced procedures say to throw an error,
777                // queue a global task on the crypto task source, given realm's global object, to
778                // reject promise with the returned error; and then terminate the algorithm.
779
780                // Step 9. Let digest be the result of performing the digest operation specified by
781                // normalizedAlgorithm using algorithm, with data as message.
782                let digest = match normalized_algorithm.digest(&data) {
783                    Ok(digest) => digest,
784                    Err(error) => {
785                        subtle.reject_promise_with_error(promise, error);
786                        return;
787                    }
788                };
789
790                // Step 10. Queue a global task on the crypto task source, given realm's global
791                // object, to perform the remaining steps.
792                // Step 11. Let result be the result of creating an ArrayBuffer in realm,
793                // containing digest.
794                // Step 12. Resolve promise with result.
795                subtle.resolve_promise_with_data(promise, digest);
796            }));
797        promise
798    }
799
800    /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-generateKey>
801    fn GenerateKey(
802        &self,
803        cx: JSContext,
804        algorithm: AlgorithmIdentifier,
805        extractable: bool,
806        key_usages: Vec<KeyUsage>,
807        comp: InRealm,
808        can_gc: CanGc,
809    ) -> Rc<Promise> {
810        // Step 1. Let algorithm, extractable and usages be the algorithm, extractable and
811        // keyUsages parameters passed to the generateKey() method, respectively.
812
813        // Step 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
814        // to algorithm and op set to "generateKey".
815        // Step 3. If an error occurred, return a Promise rejected with normalizedAlgorithm.
816        let promise = Promise::new_in_current_realm(comp, can_gc);
817        let normalized_algorithm =
818            match normalize_algorithm(cx, Operation::GenerateKey, &algorithm, can_gc) {
819                Ok(normalized_algorithm) => normalized_algorithm,
820                Err(error) => {
821                    promise.reject_error(error, can_gc);
822                    return promise;
823                },
824            };
825
826        // Step 4. Let realm be the relevant realm of this.
827        // Step 5. Let promise be a new Promise.
828        // NOTE: We did that in preparation of Step 3.
829
830        // Step 6. Return promise and perform the remaining steps in parallel.
831        let trusted_subtle = Trusted::new(self);
832        let trusted_promise = TrustedPromise::new(promise.clone());
833        self.global()
834            .task_manager()
835            .dom_manipulation_task_source()
836            .queue(task!(generate_key: move || {
837                let subtle = trusted_subtle.root();
838                let promise = trusted_promise.root();
839
840                // Step 7. If the following steps or referenced procedures say to throw an error,
841                // queue a global task on the crypto task source, given realm's global object, to
842                // reject promise with the returned error; and then terminate the algorithm.
843
844                // Step 8. Let result be the result of performing the generate key operation
845                // specified by normalizedAlgorithm using algorithm, extractable and usages.
846                let result = match normalized_algorithm.generate_key(
847                    &subtle.global(),
848                    extractable,
849                    key_usages,
850                    CanGc::note(),
851                ) {
852                    Ok(result) => result,
853                    Err(error) => {
854                        subtle.reject_promise_with_error(promise, error);
855                        return;
856                    }
857                };
858
859                // Step 9.
860                // If result is a CryptoKey object:
861                //     If the [[type]] internal slot of result is "secret" or "private" and usages
862                //     is empty, then throw a SyntaxError.
863                // If result is a CryptoKeyPair object:
864                //     If the [[usages]] internal slot of the privateKey attribute of result is the
865                //     empty sequence, then throw a SyntaxError.
866                // TODO: Implement CryptoKeyPair case
867                match &result {
868                    CryptoKeyOrCryptoKeyPair::CryptoKey(crpyto_key) => {
869                        if matches!(crpyto_key.Type(), KeyType::Secret | KeyType::Private)
870                            && crpyto_key.usages().is_empty()
871                        {
872                            subtle.reject_promise_with_error(promise, Error::Syntax(None));
873                            return;
874                        }
875                    },
876                    CryptoKeyOrCryptoKeyPair::CryptoKeyPair(crypto_key_pair) => {
877                        if crypto_key_pair.privateKey.as_ref().is_none_or(|private_key| private_key.usages().is_empty()) {
878                            subtle.reject_promise_with_error(promise, Error::Syntax(None));
879                            return;
880                        }
881                    }
882                };
883
884                // Step 10. Queue a global task on the crypto task source, given realm's global
885                // object, to perform the remaining steps.
886                // Step 11. Let result be the result of converting result to an ECMAScript Object
887                // in realm, as defined by [WebIDL].
888                // Step 12. Resolve promise with result.
889                match result {
890                    CryptoKeyOrCryptoKeyPair::CryptoKey(key) => {
891                        subtle.resolve_promise_with_key(promise, key);
892                    },
893                    CryptoKeyOrCryptoKeyPair::CryptoKeyPair(key_pair) => {
894                        subtle.resolve_promise_with_key_pair(promise, key_pair);
895                    },
896                }
897            }));
898
899        promise
900    }
901
902    /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-deriveKey>
903    fn DeriveKey(
904        &self,
905        cx: JSContext,
906        algorithm: AlgorithmIdentifier,
907        base_key: &CryptoKey,
908        derived_key_type: AlgorithmIdentifier,
909        extractable: bool,
910        usages: Vec<KeyUsage>,
911        comp: InRealm,
912        can_gc: CanGc,
913    ) -> Rc<Promise> {
914        // Step 1. Let algorithm, baseKey, derivedKeyType, extractable and usages be the algorithm,
915        // baseKey, derivedKeyType, extractable and keyUsages parameters passed to the deriveKey()
916        // method, respectively.
917        // NOTE: We did that in method parameter.
918
919        // Step 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
920        // to algorithm and op set to "deriveBits".
921        // Step 3. If an error occurred, return a Promise rejected with normalizedAlgorithm.
922        let promise = Promise::new_in_current_realm(comp, can_gc);
923        let normalized_algorithm =
924            match normalize_algorithm(cx, Operation::DeriveBits, &algorithm, can_gc) {
925                Ok(normalized_algorithm) => normalized_algorithm,
926                Err(error) => {
927                    promise.reject_error(error, can_gc);
928                    return promise;
929                },
930            };
931
932        // Step 4. Let normalizedDerivedKeyAlgorithmImport be the result of normalizing an
933        // algorithm, with alg set to derivedKeyType and op set to "importKey".
934        // Step 5. If an error occurred, return a Promise rejected with
935        // normalizedDerivedKeyAlgorithmImport.
936        let normalized_derived_key_algorithm_import =
937            match normalize_algorithm(cx, Operation::ImportKey, &derived_key_type, can_gc) {
938                Ok(normalized_algorithm) => normalized_algorithm,
939                Err(error) => {
940                    promise.reject_error(error, can_gc);
941                    return promise;
942                },
943            };
944
945        // Step 6. Let normalizedDerivedKeyAlgorithmLength be the result of normalizing an
946        // algorithm, with alg set to derivedKeyType and op set to "get key length".
947        // Step 7. If an error occurred, return a Promise rejected with
948        // normalizedDerivedKeyAlgorithmLength.
949        let normalized_derived_key_algorithm_length =
950            match normalize_algorithm(cx, Operation::GetKeyLength, &derived_key_type, can_gc) {
951                Ok(normalized_algorithm) => normalized_algorithm,
952                Err(error) => {
953                    promise.reject_error(error, can_gc);
954                    return promise;
955                },
956            };
957
958        // Step 8. Let realm be the relevant realm of this.
959        // Step 9. Let promise be a new Promise.
960        // NOTE: We did that in preparation of Step 3.
961
962        // Step 10. Return promise and perform the remaining steps in parallel.
963        let trusted_subtle = Trusted::new(self);
964        let trusted_base_key = Trusted::new(base_key);
965        let trusted_promise = TrustedPromise::new(promise.clone());
966        self.global().task_manager().dom_manipulation_task_source().queue(
967            task!(derive_key: move || {
968                let subtle = trusted_subtle.root();
969                let base_key = trusted_base_key.root();
970                let promise = trusted_promise.root();
971
972                // Step 11. If the following steps or referenced procedures say to throw an error,
973                // queue a global task on the crypto task source, given realm's global object, to
974                // reject promise with the returned error; and then terminate the algorithm.
975
976                // Step 12. If the name member of normalizedAlgorithm is not equal to the name
977                // attribute of the [[algorithm]] internal slot of baseKey then throw an
978                // InvalidAccessError.
979                if normalized_algorithm.name() != base_key.algorithm().name() {
980                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
981                    return;
982                }
983
984                // Step 13. If the [[usages]] internal slot of baseKey does not contain an entry
985                // that is "deriveKey", then throw an InvalidAccessError.
986                if !base_key.usages().contains(&KeyUsage::DeriveKey) {
987                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
988                    return;
989                }
990
991                // Step 14. Let length be the result of performing the get key length algorithm
992                // specified by normalizedDerivedKeyAlgorithmLength using derivedKeyType.
993                let length = match normalized_derived_key_algorithm_length.get_key_length() {
994                    Ok(length) => length,
995                    Err(error) => {
996                        subtle.reject_promise_with_error(promise, error);
997                        return;
998                    }
999                };
1000
1001                // Step 15. Let secret be the result of performing the derive bits operation
1002                // specified by normalizedAlgorithm using key, algorithm and length.
1003                let secret = match normalized_algorithm.derive_bits(&base_key, length) {
1004                    Ok(secret) => secret,
1005                    Err(error) => {
1006                        subtle.reject_promise_with_error(promise, error);
1007                        return;
1008                    }
1009                };
1010
1011                // Step 16. Let result be the result of performing the import key operation
1012                // specified by normalizedDerivedKeyAlgorithmImport using "raw" as format, secret
1013                // as keyData, derivedKeyType as algorithm and using extractable and usages.
1014                // NOTE: Use "raw-secret" instead, according to
1015                // <https://wicg.github.io/webcrypto-modern-algos/#subtlecrypto-interface-keyformat>.
1016                let result = match normalized_derived_key_algorithm_import.import_key(
1017                    &subtle.global(),
1018                    KeyFormat::Raw_secret,
1019                    &secret,
1020                    extractable,
1021                    usages.clone(),
1022                    CanGc::note(),
1023                ) {
1024                    Ok(algorithm) => algorithm,
1025                    Err(error) => {
1026                        subtle.reject_promise_with_error(promise, error);
1027                        return;
1028                    },
1029                };
1030
1031                // Step 17. If the [[type]] internal slot of result is "secret" or "private" and
1032                // usages is empty, then throw a SyntaxError.
1033                if matches!(result.Type(), KeyType::Secret | KeyType::Private) && usages.is_empty() {
1034                    subtle.reject_promise_with_error(promise, Error::Syntax(None));
1035                    return;
1036                }
1037
1038                // Step 18. Set the [[extractable]] internal slot of result to extractable.
1039                // Step 19. Set the [[usages]] internal slot of result to the normalized value of
1040                // usages.
1041                // NOTE: Done by normalized_derived_key_algorithm_import.import_key in Step 16.
1042
1043                // Step 20. Queue a global task on the crypto task source, given realm's global
1044                // object, to perform the remaining steps.
1045                // Step 20. Let result be the result of converting result to an ECMAScript Object
1046                // in realm, as defined by [WebIDL].
1047                // Step 20. Resolve promise with result.
1048                subtle.resolve_promise_with_key(promise, result);
1049            }),
1050        );
1051        promise
1052    }
1053
1054    /// <https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-deriveBits>
1055    fn DeriveBits(
1056        &self,
1057        cx: JSContext,
1058        algorithm: AlgorithmIdentifier,
1059        base_key: &CryptoKey,
1060        length: Option<u32>,
1061        comp: InRealm,
1062        can_gc: CanGc,
1063    ) -> Rc<Promise> {
1064        // Step 1. Let algorithm, baseKey and length, be the algorithm, baseKey and length
1065        // parameters passed to the deriveBits() method, respectively.
1066        // NOTE: We did that in method parameter.
1067
1068        // Step 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
1069        // to algorithm and op set to "deriveBits".
1070        // Step 3. If an error occurred, return a Promise rejected with normalizedAlgorithm.
1071        let promise = Promise::new_in_current_realm(comp, can_gc);
1072        let normalized_algorithm =
1073            match normalize_algorithm(cx, Operation::DeriveBits, &algorithm, can_gc) {
1074                Ok(normalized_algorithm) => normalized_algorithm,
1075                Err(error) => {
1076                    promise.reject_error(error, can_gc);
1077                    return promise;
1078                },
1079            };
1080
1081        // Step 4. Let realm be the relevant realm of this.
1082        // Step 5. Let promise be a new Promise.
1083        // NOTE: We did that in preparation of Step 3.
1084
1085        // Step 5. Return promise and perform the remaining steps in parallel.
1086        let trsuted_subtle = Trusted::new(self);
1087        let trusted_base_key = Trusted::new(base_key);
1088        let trusted_promise = TrustedPromise::new(promise.clone());
1089        self.global()
1090            .task_manager()
1091            .dom_manipulation_task_source()
1092            .queue(task!(import_key: move || {
1093                let subtle = trsuted_subtle.root();
1094                let base_key = trusted_base_key.root();
1095                let promise = trusted_promise.root();
1096
1097                // Step 7. If the following steps or referenced procedures say to throw an error,
1098                // queue a global task on the crypto task source, given realm's global object, to
1099                // reject promise with the returned error; and then terminate the algorithm.
1100
1101                // Step 8. If the name member of normalizedAlgorithm is not equal to the name
1102                // attribute of the [[algorithm]] internal slot of baseKey then throw an
1103                // InvalidAccessError.
1104                if normalized_algorithm.name() != base_key.algorithm().name() {
1105                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
1106                    return;
1107                }
1108
1109                // Step 9. If the [[usages]] internal slot of baseKey does not contain an entry
1110                // that is "deriveBits", then throw an InvalidAccessError.
1111                if !base_key.usages().contains(&KeyUsage::DeriveBits) {
1112                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
1113                    return;
1114                }
1115
1116                // Step 10. Let bits be the result of performing the derive bits operation
1117                // specified by normalizedAlgorithm using baseKey, algorithm and length.
1118                let bits = match normalized_algorithm.derive_bits(&base_key, length) {
1119                    Ok(bits) => bits,
1120                    Err(error) => {
1121                        subtle.reject_promise_with_error(promise, error);
1122                        return;
1123                    }
1124                };
1125
1126                // Step 11. Queue a global task on the crypto task source, given realm's global
1127                // object, to perform the remaining steps.
1128                // Step 12. Let result be the result of creating an ArrayBuffer in realm,
1129                // containing bits.
1130                // Step 13. Resolve promise with result.
1131                subtle.resolve_promise_with_data(promise, bits);
1132            }));
1133        promise
1134    }
1135
1136    /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-importKey>
1137    fn ImportKey(
1138        &self,
1139        cx: JSContext,
1140        format: KeyFormat,
1141        key_data: ArrayBufferViewOrArrayBufferOrJsonWebKey,
1142        algorithm: AlgorithmIdentifier,
1143        extractable: bool,
1144        key_usages: Vec<KeyUsage>,
1145        comp: InRealm,
1146        can_gc: CanGc,
1147    ) -> Rc<Promise> {
1148        // Step 1. Let format, algorithm, extractable and usages, be the format, algorithm,
1149        // extractable and keyUsages parameters passed to the importKey() method, respectively.
1150
1151        // Step 5. Let realm be the relevant realm of this.
1152        // Step 6. Let promise be a new Promise.
1153        let promise = Promise::new_in_current_realm(comp, can_gc);
1154
1155        // Step 2.
1156        let key_data = match format {
1157            // If format is equal to the string "jwk":
1158            KeyFormat::Jwk => {
1159                match key_data {
1160                    ArrayBufferViewOrArrayBufferOrJsonWebKey::ArrayBufferView(_) |
1161                    ArrayBufferViewOrArrayBufferOrJsonWebKey::ArrayBuffer(_) => {
1162                        // Step 2.1. If the keyData parameter passed to the importKey() method is
1163                        // not a JsonWebKey dictionary, throw a TypeError.
1164                        promise.reject_error(
1165                            Error::Type("The keyData type does not match the format".to_string()),
1166                            can_gc,
1167                        );
1168                        return promise;
1169                    },
1170
1171                    ArrayBufferViewOrArrayBufferOrJsonWebKey::JsonWebKey(jwk) => {
1172                        // Step 2.2. Let keyData be the keyData parameter passed to the importKey() method.
1173                        //
1174                        // NOTE: Serialize JsonWebKey throught stringifying it.
1175                        // JsonWebKey::stringify internally relies on ToJSON, so it will raise an
1176                        // exception when a JS error is thrown. When this happens, we report the
1177                        // error.
1178                        match jwk.stringify(cx) {
1179                            Ok(stringified) => stringified.as_bytes().to_vec(),
1180                            Err(error) => {
1181                                promise.reject_error(error, can_gc);
1182                                return promise;
1183                            },
1184                        }
1185                    },
1186                }
1187            },
1188            // Otherwise:
1189            _ => {
1190                match key_data {
1191                    // Step 2.1. If the keyData parameter passed to the importKey() method is a
1192                    // JsonWebKey dictionary, throw a TypeError.
1193                    ArrayBufferViewOrArrayBufferOrJsonWebKey::JsonWebKey(_) => {
1194                        promise.reject_error(
1195                            Error::Type("The keyData type does not match the format".to_string()),
1196                            can_gc,
1197                        );
1198                        return promise;
1199                    },
1200
1201                    // Step 2.2. Let keyData be the result of getting a copy of the bytes held by
1202                    // the keyData parameter passed to the importKey() method.
1203                    ArrayBufferViewOrArrayBufferOrJsonWebKey::ArrayBufferView(view) => {
1204                        view.to_vec()
1205                    },
1206                    ArrayBufferViewOrArrayBufferOrJsonWebKey::ArrayBuffer(buffer) => {
1207                        buffer.to_vec()
1208                    },
1209                }
1210            },
1211        };
1212
1213        // Step 3. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
1214        // to algorithm and op set to "importKey".
1215        // Step 4. If an error occurred, return a Promise rejected with normalizedAlgorithm.
1216        let normalized_algorithm =
1217            match normalize_algorithm(cx, Operation::ImportKey, &algorithm, can_gc) {
1218                Ok(algorithm) => algorithm,
1219                Err(error) => {
1220                    promise.reject_error(error, can_gc);
1221                    return promise;
1222                },
1223            };
1224
1225        // Step 7. Return promise and perform the remaining steps in parallel.
1226        let this = Trusted::new(self);
1227        let trusted_promise = TrustedPromise::new(promise.clone());
1228        self.global()
1229            .task_manager()
1230            .dom_manipulation_task_source()
1231            .queue(task!(import_key: move || {
1232                let subtle = this.root();
1233                let promise = trusted_promise.root();
1234
1235                // Step 8. If the following steps or referenced procedures say to throw an error,
1236                // queue a global task on the crypto task source, given realm's global object, to
1237                // reject promise with the returned error; and then terminate the algorithm.
1238
1239                // Step 9. Let result be the CryptoKey object that results from performing the
1240                // import key operation specified by normalizedAlgorithm using keyData, algorithm,
1241                // format, extractable and usages.
1242                let result = match normalized_algorithm.import_key(
1243                    &subtle.global(),
1244                    format,
1245                    &key_data,
1246                    extractable,
1247                    key_usages.clone(),
1248                    CanGc::note()
1249                ) {
1250                    Ok(key) => key,
1251                    Err(error) => {
1252                        subtle.reject_promise_with_error(promise, error);
1253                        return;
1254                    },
1255                };
1256
1257                // Step 10. If the [[type]] internal slot of result is "secret" or "private" and
1258                // usages is empty, then throw a SyntaxError.
1259                if matches!(result.Type(), KeyType::Secret | KeyType::Private) && key_usages.is_empty() {
1260                    subtle.reject_promise_with_error(promise, Error::Syntax(None));
1261                    return;
1262                }
1263
1264                // Step 11. Set the [[extractable]] internal slot of result to extractable.
1265                result.set_extractable(extractable);
1266
1267                // Step 12. Set the [[usages]] internal slot of result to the normalized value of usages.
1268                result.set_usages(&key_usages);
1269
1270                // Step 13. Queue a global task on the crypto task source, given realm's global
1271                // object, to perform the remaining steps.
1272                // Step 14. Let result be the result of converting result to an ECMAScript Object
1273                // in realm, as defined by [WebIDL].
1274                // Step 15. Resolve promise with result.
1275                subtle.resolve_promise_with_key(promise, result);
1276            }));
1277
1278        promise
1279    }
1280
1281    /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-exportKey>
1282    fn ExportKey(
1283        &self,
1284        format: KeyFormat,
1285        key: &CryptoKey,
1286        comp: InRealm,
1287        can_gc: CanGc,
1288    ) -> Rc<Promise> {
1289        // Step 1. Let format and key be the format and key parameters passed to the exportKey()
1290        // method, respectively.
1291        // NOTE: We did that in method parameter.
1292
1293        // Step 2. Let realm be the relevant realm of this.
1294        // Step 3. Let promise be a new Promise.
1295        let promise = Promise::new_in_current_realm(comp, can_gc);
1296
1297        // Step 4. Return promise and perform the remaining steps in parallel.
1298        let trusted_subtle = Trusted::new(self);
1299        let trusted_promise = TrustedPromise::new(promise.clone());
1300        let trusted_key = Trusted::new(key);
1301        self.global()
1302            .task_manager()
1303            .dom_manipulation_task_source()
1304            .queue(task!(export_key: move || {
1305                let subtle = trusted_subtle.root();
1306                let promise = trusted_promise.root();
1307                let key = trusted_key.root();
1308
1309                // Step 5. If the following steps or referenced procedures say to throw an error,
1310                // queue a global task on the crypto task source, given realm's global object, to
1311                // reject promise with the returned error; and then terminate the algorithm.
1312
1313                // Step 6. If the name member of the [[algorithm]] internal slot of key does not
1314                // identify a registered algorithm that supports the export key operation, then
1315                // throw a NotSupportedError.
1316                let registered_algorithm = match SupportedAlgorithm::try_from(key.algorithm().name()) {
1317                    Ok(registered_algorithm) => registered_algorithm,
1318                    Err(error) => {
1319                        subtle.reject_promise_with_error(promise, error);
1320                        return;
1321                    },
1322                };
1323                if registered_algorithm.support(Operation::ExportKey).is_err() {
1324                    subtle.reject_promise_with_error(promise, Error::NotSupported(None));
1325                    return;
1326                }
1327
1328                // Step 7. If the [[extractable]] internal slot of key is false, then throw an
1329                // InvalidAccessError.
1330                if !key.Extractable() {
1331                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
1332                    return;
1333                }
1334
1335                // Step 8. Let result be the result of performing the export key operation
1336                // specified by the [[algorithm]] internal slot of key using key and format.
1337                let result = match perform_export_key_operation(format, &key) {
1338                    Ok(exported_key) => exported_key,
1339                    Err(error) => {
1340                        subtle.reject_promise_with_error(promise, error);
1341                        return;
1342                    },
1343                };
1344
1345                // Step 9. Queue a global task on the crypto task source, given realm's global
1346                // object, to perform the remaining steps.
1347                // Step 10.
1348                // If format is equal to the string "jwk":
1349                //     Let result be the result of converting result to an ECMAScript Object in
1350                //     realm, as defined by [WebIDL].
1351                // Otherwise:
1352                //     Let result be the result of creating an ArrayBuffer in realm, containing
1353                //     result.
1354                // Step 11. Resolve promise with result.
1355                // NOTE: We determine the format by pattern matching on result, which is an
1356                // ExportedKey enum.
1357                match result {
1358                    ExportedKey::Bytes(bytes) => {
1359                        subtle.resolve_promise_with_data(promise, bytes);
1360                    },
1361                    ExportedKey::Jwk(jwk) => {
1362                        subtle.resolve_promise_with_jwk(promise, jwk);
1363                    },
1364                }
1365            }));
1366        promise
1367    }
1368
1369    /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-wrapKey>
1370    fn WrapKey(
1371        &self,
1372        cx: JSContext,
1373        format: KeyFormat,
1374        key: &CryptoKey,
1375        wrapping_key: &CryptoKey,
1376        algorithm: AlgorithmIdentifier,
1377        comp: InRealm,
1378        can_gc: CanGc,
1379    ) -> Rc<Promise> {
1380        // Step 1. Let format, key, wrappingKey and algorithm be the format, key, wrappingKey and
1381        // wrapAlgorithm parameters passed to the wrapKey() method, respectively.
1382        // NOTE: We did that in method parameter.
1383
1384        // Step 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
1385        // to algorithm and op set to "wrapKey".
1386        let mut normalized_algorithm_result =
1387            normalize_algorithm(cx, Operation::WrapKey, &algorithm, can_gc);
1388
1389        // Step 3. If an error occurred, let normalizedAlgorithm be the result of normalizing an
1390        // algorithm, with alg set to algorithm and op set to "encrypt".
1391        if normalized_algorithm_result.is_err() {
1392            normalized_algorithm_result =
1393                normalize_algorithm(cx, Operation::Encrypt, &algorithm, can_gc);
1394        }
1395
1396        // Step 4. If an error occurred, return a Promise rejected with normalizedAlgorithm.
1397        let promise = Promise::new_in_current_realm(comp, can_gc);
1398        let normalized_algorithm = match normalized_algorithm_result {
1399            Ok(normalized_algorithm) => normalized_algorithm,
1400            Err(error) => {
1401                promise.reject_error(error, can_gc);
1402                return promise;
1403            },
1404        };
1405
1406        // Step 5. Let realm be the relevant realm of this.
1407        // Step 6. Let promise be a new Promise.
1408        // NOTE: We did that in preparation of Step 4.
1409
1410        // Step 7. Return promise and perform the remaining steps in parallel.
1411        let trusted_subtle = Trusted::new(self);
1412        let trusted_key = Trusted::new(key);
1413        let trusted_wrapping_key = Trusted::new(wrapping_key);
1414        let trusted_promise = TrustedPromise::new(promise.clone());
1415        self.global()
1416            .task_manager()
1417            .dom_manipulation_task_source()
1418            .queue(task!(wrap_key: move || {
1419                let subtle = trusted_subtle.root();
1420                let key = trusted_key.root();
1421                let wrapping_key = trusted_wrapping_key.root();
1422                let promise = trusted_promise.root();
1423
1424                // Step 8. If the following steps or referenced procedures say to throw an error,
1425                // queue a global task on the crypto task source, given realm's global object, to
1426                // reject promise with the returned error; and then terminate the algorithm.
1427
1428                // Step 9. If the name member of normalizedAlgorithm is not equal to the name
1429                // attribute of the [[algorithm]] internal slot of wrappingKey then throw an
1430                // InvalidAccessError.
1431                if normalized_algorithm.name() != wrapping_key.algorithm().name() {
1432                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
1433                    return;
1434                }
1435
1436                // Step 10. If the [[usages]] internal slot of wrappingKey does not contain an
1437                // entry that is "wrapKey", then throw an InvalidAccessError.
1438                if !wrapping_key.usages().contains(&KeyUsage::WrapKey) {
1439                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
1440                    return;
1441                }
1442
1443                // Step 11. If the algorithm identified by the [[algorithm]] internal slot of key
1444                // does not support the export key operation, then throw a NotSupportedError.
1445                let registered_algorithm = match SupportedAlgorithm::try_from(key.algorithm().name()) {
1446                    Ok(registered_algorithm) => registered_algorithm,
1447                    Err(error) => {
1448                        subtle.reject_promise_with_error(promise, error);
1449                        return;
1450                    },
1451                };
1452                if registered_algorithm.support(Operation::ExportKey).is_err() {
1453                    subtle.reject_promise_with_error(promise, Error::NotSupported(None));
1454                    return;
1455                }
1456
1457                // Step 12. If the [[extractable]] internal slot of key is false, then throw an
1458                // InvalidAccessError.
1459                if !key.Extractable() {
1460                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
1461                    return;
1462                }
1463
1464                // Step 13. Let exportedKey be the result of performing the export key operation
1465                // specified by the [[algorithm]] internal slot of key using key and format.
1466                let exported_key = match perform_export_key_operation(format, &key) {
1467                    Ok(exported_key) => exported_key,
1468                    Err(error) => {
1469                        subtle.reject_promise_with_error(promise, error);
1470                        return;
1471                    },
1472                };
1473
1474                // Step 14.
1475                // If format is equal to the string "jwk":
1476                //     Step 14.1. Let json be the result of representing exportedKey as a UTF-16
1477                //     string conforming to the JSON grammar; for example, by executing the
1478                //     JSON.stringify algorithm specified in [ECMA-262] in the context of a new
1479                //     global object.
1480                //     Step 14.2. Let bytes be the result of UTF-8 encoding json.
1481                // Otherwise:
1482                //     Let bytes be exportedKey.
1483                // NOTE: We determine the format by pattern matching on result, which is an
1484                // ExportedKey enum.
1485                let cx = GlobalScope::get_cx();
1486                let bytes = match exported_key {
1487                    ExportedKey::Bytes(bytes) => bytes,
1488                    ExportedKey::Jwk(jwk) => match jwk.stringify(cx) {
1489                        Ok(stringified_jwk) => stringified_jwk.as_bytes().to_vec(),
1490                        Err(error) => {
1491                            subtle.reject_promise_with_error(promise, error);
1492                            return;
1493                        },
1494                    },
1495                };
1496
1497                // Step 15.
1498                // If normalizedAlgorithm supports the wrap key operation:
1499                //     Let result be the result of performing the wrap key operation specified by
1500                //     normalizedAlgorithm using algorithm, wrappingKey as key and bytes as
1501                //     plaintext.
1502                // Otherwise, if normalizedAlgorithm supports the encrypt operation:
1503                //     Let result be the result of performing the encrypt operation specified by
1504                //     normalizedAlgorithm using algorithm, wrappingKey as key and bytes as
1505                //     plaintext.
1506                // Otherwise:
1507                //     throw a NotSupportedError.
1508                let mut result = normalized_algorithm.wrap_key(&wrapping_key, &bytes);
1509                if result.is_err() {
1510                    result = normalized_algorithm.encrypt(&wrapping_key, &bytes);
1511                }
1512                let result = match result {
1513                    Ok(result) => result,
1514                    Err(error) => {
1515                        subtle.reject_promise_with_error(promise, error);
1516                        return;
1517                    },
1518                };
1519
1520                // Step 16. Queue a global task on the crypto task source, given realm's global
1521                // object, to perform the remaining steps.
1522                // Step 17. Let result be the result of creating an ArrayBuffer in realm,
1523                // containing result.
1524                // Step 18. Resolve promise with result.
1525                subtle.resolve_promise_with_data(promise, result);
1526            }));
1527        promise
1528    }
1529
1530    /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-unwrapKey>
1531    fn UnwrapKey(
1532        &self,
1533        cx: JSContext,
1534        format: KeyFormat,
1535        wrapped_key: ArrayBufferViewOrArrayBuffer,
1536        unwrapping_key: &CryptoKey,
1537        algorithm: AlgorithmIdentifier,
1538        unwrapped_key_algorithm: AlgorithmIdentifier,
1539        extractable: bool,
1540        usages: Vec<KeyUsage>,
1541        comp: InRealm,
1542        can_gc: CanGc,
1543    ) -> Rc<Promise> {
1544        // Step 1. Let format, unwrappingKey, algorithm, unwrappedKeyAlgorithm, extractable and
1545        // usages, be the format, unwrappingKey, unwrapAlgorithm, unwrappedKeyAlgorithm,
1546        // extractable and keyUsages parameters passed to the unwrapKey() method, respectively.
1547        // NOTE: We did that in method parameter.
1548
1549        // Step 2. Let wrappedKey be the result of getting a copy of the bytes held by the
1550        // wrappedKey parameter passed to the unwrapKey() method.
1551        let wrapped_key = match wrapped_key {
1552            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
1553            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
1554        };
1555
1556        // Step 3. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
1557        // to algorithm and op set to "unwrapKey".
1558        let mut normalized_algorithm =
1559            normalize_algorithm(cx, Operation::UnwrapKey, &algorithm, can_gc);
1560
1561        // Step 4. If an error occurred, let normalizedAlgorithm be the result of normalizing an
1562        // algorithm, with alg set to algorithm and op set to "decrypt".
1563        if normalized_algorithm.is_err() {
1564            normalized_algorithm = normalize_algorithm(cx, Operation::Decrypt, &algorithm, can_gc);
1565        }
1566
1567        // Step 5. If an error occurred, return a Promise rejected with normalizedAlgorithm.
1568        let promise = Promise::new_in_current_realm(comp, can_gc);
1569        let normalized_algorithm = match normalized_algorithm {
1570            Ok(algorithm) => algorithm,
1571            Err(error) => {
1572                promise.reject_error(error, can_gc);
1573                return promise;
1574            },
1575        };
1576
1577        // Step 6. Let normalizedKeyAlgorithm be the result of normalizing an algorithm, with alg
1578        // set to unwrappedKeyAlgorithm and op set to "importKey".
1579        // Step 7. If an error occurred, return a Promise rejected with normalizedKeyAlgorithm.
1580        let normalized_key_algorithm =
1581            match normalize_algorithm(cx, Operation::ImportKey, &unwrapped_key_algorithm, can_gc) {
1582                Ok(algorithm) => algorithm,
1583                Err(error) => {
1584                    promise.reject_error(error, can_gc);
1585                    return promise;
1586                },
1587            };
1588
1589        // Step 8. Let realm be the relevant realm of this.
1590        // Step 9. Let promise be a new Promise.
1591        // NOTE: We did that in preparation of Step 5.
1592
1593        // Step 10. Return promise and perform the remaining steps in parallel.
1594        let trusted_subtle = Trusted::new(self);
1595        let trusted_unwrapping_key = Trusted::new(unwrapping_key);
1596        let trusted_promise = TrustedPromise::new(promise.clone());
1597        self.global().task_manager().dom_manipulation_task_source().queue(
1598            task!(unwrap_key: move || {
1599                let subtle = trusted_subtle.root();
1600                let unwrapping_key = trusted_unwrapping_key.root();
1601                let promise = trusted_promise.root();
1602
1603                // Step 11. If the following steps or referenced procedures say to throw an error,
1604                // queue a global task on the crypto task source, given realm's global object, to
1605                // reject promise with the returned error; and then terminate the algorithm.
1606
1607                // Step 12. If the name member of normalizedAlgorithm is not equal to the name
1608                // attribute of the [[algorithm]] internal slot of unwrappingKey then throw an
1609                // InvalidAccessError.
1610                if normalized_algorithm.name() != unwrapping_key.algorithm().name() {
1611                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
1612                    return;
1613                }
1614
1615                // Step 13. If the [[usages]] internal slot of unwrappingKey does not contain an
1616                // entry that is "unwrapKey", then throw an InvalidAccessError.
1617                if !unwrapping_key.usages().contains(&KeyUsage::UnwrapKey) {
1618                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
1619                    return;
1620                }
1621
1622                // Step 14.
1623                // If normalizedAlgorithm supports an unwrap key operation:
1624                //     Let bytes be the result of performing the unwrap key operation specified by
1625                //     normalizedAlgorithm using algorithm, unwrappingKey as key and wrappedKey as
1626                //     ciphertext.
1627                // Otherwise, if normalizedAlgorithm supports a decrypt operation:
1628                //     Let bytes be the result of performing the decrypt operation specified by
1629                //     normalizedAlgorithm using algorithm, unwrappingKey as key and wrappedKey as
1630                //     ciphertext.
1631                // Otherwise:
1632                //     throw a NotSupportedError.
1633                let mut bytes = normalized_algorithm.unwrap_key(&unwrapping_key, &wrapped_key);
1634                if bytes.is_err() {
1635                    bytes = normalized_algorithm.decrypt(&unwrapping_key, &wrapped_key);
1636                }
1637                let bytes = match bytes {
1638                    Ok(bytes) => bytes,
1639                    Err(error) => {
1640                        subtle.reject_promise_with_error(promise, error);
1641                        return;
1642                    },
1643                };
1644
1645                // Step 15.
1646                // If format is equal to the string "jwk":
1647                //     Let key be the result of executing the parse a JWK algorithm, with bytes as
1648                //     the data to be parsed.
1649                //     NOTE: We only parse bytes by executing the parse a JWK algorithm, but keep
1650                //     it as raw bytes for later steps, instead of converting it to a JsonWebKey
1651                //     dictionary.
1652                //
1653                // Otherwise:
1654                //     Let key be bytes.
1655                let cx = GlobalScope::get_cx();
1656                if format == KeyFormat::Jwk {
1657                    if let Err(error) = JsonWebKey::parse(cx, &bytes) {
1658                        subtle.reject_promise_with_error(promise, error);
1659                        return;
1660                    }
1661                }
1662                let key = bytes;
1663
1664                // Step 16. Let result be the result of performing the import key operation
1665                // specified by normalizedKeyAlgorithm using unwrappedKeyAlgorithm as algorithm,
1666                // format, usages and extractable and with key as keyData.
1667                let result = match normalized_key_algorithm.import_key(
1668                    &subtle.global(),
1669                    format,
1670                    &key,
1671                    extractable,
1672                    usages.clone(),
1673                    CanGc::note(),
1674                ) {
1675                    Ok(result) => result,
1676                    Err(error) => {
1677                        subtle.reject_promise_with_error(promise, error);
1678                        return;
1679                    },
1680                };
1681
1682                // Step 17. If the [[type]] internal slot of result is "secret" or "private" and
1683                // usages is empty, then throw a SyntaxError.
1684                if matches!(result.Type(), KeyType::Secret | KeyType::Private) && usages.is_empty() {
1685                    subtle.reject_promise_with_error(promise, Error::Syntax(None));
1686                    return;
1687                }
1688
1689                // Step 18. Set the [[extractable]] internal slot of result to extractable.
1690                // Step 19. Set the [[usages]] internal slot of result to the normalized value of
1691                // usages.
1692                // NOTE: Done by normalized_algorithm.import_key in Step 16.
1693
1694                // Step 20. Queue a global task on the crypto task source, given realm's global
1695                // object, to perform the remaining steps.
1696                // Step 21. Let result be the result of converting result to an ECMAScript Object
1697                // in realm, as defined by [WebIDL].
1698                // Step 22. Resolve promise with result.
1699                subtle.resolve_promise_with_key(promise, result);
1700            }),
1701        );
1702        promise
1703    }
1704
1705    /// <https://wicg.github.io/webcrypto-modern-algos/#SubtleCrypto-method-encapsulateKey>
1706    fn EncapsulateKey(
1707        &self,
1708        cx: JSContext,
1709        encapsulation_algorithm: AlgorithmIdentifier,
1710        encapsulation_key: &CryptoKey,
1711        shared_key_algorithm: AlgorithmIdentifier,
1712        extractable: bool,
1713        usages: Vec<KeyUsage>,
1714        comp: InRealm,
1715        can_gc: CanGc,
1716    ) -> Rc<Promise> {
1717        // Step 1. Let encapsulationAlgorithm, encapsulationKey, sharedKeyAlgorithm, extractable
1718        // and usages be the encapsulationAlgorithm, encapsulationKey, sharedKeyAlgorithm,
1719        // extractable and keyUsages parameters passed to the encapsulateKey() method,
1720        // respectively.
1721
1722        // Step 2. Let normalizedEncapsulationAlgorithm be the result of normalizing an algorithm,
1723        // with alg set to encapsulationAlgorithm and op set to "encapsulate".
1724        // Step 3. If an error occurred, return a Promise rejected with
1725        // normalizedEncapsulationAlgorithm.
1726        let promise = Promise::new_in_current_realm(comp, can_gc);
1727        let normalized_encapsulation_algorithm =
1728            match normalize_algorithm(cx, Operation::Encapsulate, &encapsulation_algorithm, can_gc)
1729            {
1730                Ok(algorithm) => algorithm,
1731                Err(error) => {
1732                    promise.reject_error(error, can_gc);
1733                    return promise;
1734                },
1735            };
1736
1737        // Step 4. Let normalizedSharedKeyAlgorithm be the result of normalizing an algorithm, with
1738        // alg set to sharedKeyAlgorithm and op set to "importKey".
1739        // Step 5. If an error occurred, return a Promise rejected with
1740        // normalizedSharedKeyAlgorithm.
1741        let normalized_shared_key_algorithm =
1742            match normalize_algorithm(cx, Operation::ImportKey, &shared_key_algorithm, can_gc) {
1743                Ok(algorithm) => algorithm,
1744                Err(error) => {
1745                    promise.reject_error(error, can_gc);
1746                    return promise;
1747                },
1748            };
1749
1750        // Step 6. Let realm be the relevant realm of this.
1751        // Step 7. Let promise be a new Promise.
1752        // NOTE: We did that in preparation of Step 3.
1753
1754        // Step 8. Return promise and perform the remaining steps in parallel.
1755        let trusted_subtle = Trusted::new(self);
1756        let trusted_encapsulated_key = Trusted::new(encapsulation_key);
1757        let trusted_promise = TrustedPromise::new(promise.clone());
1758        self.global().task_manager().dom_manipulation_task_source().queue(
1759            task!(encapsulate_keys: move || {
1760                let subtle = trusted_subtle.root();
1761                let encapsulation_key = trusted_encapsulated_key.root();
1762                let promise = trusted_promise.root();
1763
1764                // Step 9. If the following steps or referenced procedures say to throw an error,
1765                // queue a global task on the crypto task source, given realm's global object, to
1766                // reject promise with the returned error; and then terminate the algorithm.
1767
1768                // Step 10. If the name member of normalizedEncapsulationAlgorithm is not equal to
1769                // the name attribute of the [[algorithm]] internal slot of encapsulationKey then
1770                // throw an InvalidAccessError.
1771                if normalized_encapsulation_algorithm.name() != encapsulation_key.algorithm().name() {
1772                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(Some(
1773                        "[[algorithm]] internal slot of encapsulationKey is not equal to \
1774                        normalizedEncapsulationAlgorithm".to_string(),
1775                    )));
1776                    return;
1777                }
1778
1779                // Step 11. If the [[usages]] internal slot of encapsulationKey does not contain an
1780                // entry that is "encapsulateKey", then throw an InvalidAccessError.
1781                if !encapsulation_key.usages().contains(&KeyUsage::EncapsulateKey) {
1782                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(Some(
1783                        "[[usages]] internal slot of encapsulationKey does not contain an \
1784                        entry that is \"encapsulateBits\"".to_string(),
1785                    )));
1786                    return;
1787                }
1788
1789                // Step 12. Let encapsulatedBits be the result of performing the encapsulate
1790                // operation specified by the [[algorithm]] internal slot of encapsulationKey using
1791                // encapsulationKey.
1792                // NOTE: Step 10 guarantees normalizedEncapsulationAlgorithm specifies the same
1793                // algorithm as the [[algorithm]] internal slot of encapsulationKey.
1794                let encapsulated_bits_result =
1795                    normalized_encapsulation_algorithm.encapsulate(&encapsulation_key);
1796                let encapsulated_bits = match encapsulated_bits_result {
1797                    Ok(encapsulated_bits) => encapsulated_bits,
1798                    Err(error) => {
1799                        subtle.reject_promise_with_error(promise, error);
1800                        return;
1801                    },
1802                };
1803
1804                // Step 13. Let sharedKey be the result of performing the import key operation
1805                // specified by normalizedSharedKeyAlgorithm using "raw-secret" as format, the
1806                // sharedKey field of encapsulatedBits as keyData, sharedKeyAlgorithm as algorithm
1807                // and using extractable and usages.
1808                // Step 14. Set the [[extractable]] internal slot of sharedKey to extractable.
1809                // Step 15. Set the [[usages]] internal slot of sharedKey to the normalized value
1810                // of usages.
1811                let encapsulated_shared_key = match &encapsulated_bits.shared_key {
1812                    Some(shared_key) => shared_key,
1813                    None => {
1814                        subtle.reject_promise_with_error(promise, Error::Operation(Some(
1815                            "Shared key is missing in the result of the encapsulate operation"
1816                                .to_string())));
1817                        return;
1818                    },
1819                };
1820                let shared_key_result = normalized_shared_key_algorithm.import_key(
1821                    &subtle.global(),
1822                    KeyFormat::Raw_secret,
1823                    encapsulated_shared_key,
1824                    extractable,
1825                    usages.clone(),
1826                    CanGc::note(),
1827                );
1828                let shared_key = match shared_key_result {
1829                    Ok(shared_key) => shared_key,
1830                    Err(error) => {
1831                        subtle.reject_promise_with_error(promise, error);
1832                        return;
1833                    },
1834                };
1835
1836                // Step 16. Let encapsulatedKey be a new EncapsulatedKey dictionary with sharedKey
1837                // set to sharedKey and ciphertext set to the ciphertext field of encapsulatedBits.
1838                let encapsulated_key = SubtleEncapsulatedKey {
1839                    shared_key: Some(Trusted::new(&shared_key)),
1840                    ciphertext:encapsulated_bits.ciphertext,
1841                };
1842
1843                // Step 17. Queue a global task on the crypto task source, given realm's global
1844                // object, to perform the remaining steps.
1845                // Step 18. Let result be the result of converting encapsulatedKey to an ECMAScript
1846                // Object in realm, as defined by [WebIDL].
1847                // Step 19. Resolve promise with result.
1848                subtle.resolve_promise_with_encapsulated_key(promise, encapsulated_key);
1849            })
1850        );
1851        promise
1852    }
1853
1854    /// <https://wicg.github.io/webcrypto-modern-algos/#SubtleCrypto-method-encapsulateBits>
1855    fn EncapsulateBits(
1856        &self,
1857        cx: JSContext,
1858        encapsulation_algorithm: AlgorithmIdentifier,
1859        encapsulation_key: &CryptoKey,
1860        comp: InRealm,
1861        can_gc: CanGc,
1862    ) -> Rc<Promise> {
1863        // Step 1. Let encapsulationAlgorithm and encapsulationKey be the encapsulationAlgorithm
1864        // and encapsulationKey parameters passed to the encapsulateBits() method, respectively.
1865
1866        // Step 2. Let normalizedEncapsulationAlgorithm be the result of normalizing an algorithm,
1867        // with alg set to encapsulationAlgorithm and op set to "encapsulate".
1868        // Step 3. If an error occurred, return a Promise rejected with
1869        // normalizedEncapsulationAlgorithm.
1870        let promise = Promise::new_in_current_realm(comp, can_gc);
1871        let normalized_encapsulation_algorithm =
1872            match normalize_algorithm(cx, Operation::Encapsulate, &encapsulation_algorithm, can_gc)
1873            {
1874                Ok(algorithm) => algorithm,
1875                Err(error) => {
1876                    promise.reject_error(error, can_gc);
1877                    return promise;
1878                },
1879            };
1880
1881        // Step 4. Let realm be the relevant realm of this.
1882        // Step 5. Let promise be a new Promise.
1883        // NOTE: We did that in preparation of Step 3.
1884
1885        // Step 6. Return promise and perform the remaining steps in parallel.
1886        let trusted_subtle = Trusted::new(self);
1887        let trusted_encapsulation_key = Trusted::new(encapsulation_key);
1888        let trusted_promise = TrustedPromise::new(promise.clone());
1889        self.global().task_manager().dom_manipulation_task_source().queue(
1890            task!(derive_key: move || {
1891                let subtle = trusted_subtle.root();
1892                let encapsulation_key = trusted_encapsulation_key.root();
1893                let promise = trusted_promise.root();
1894
1895                // Step 7. If the following steps or referenced procedures say to throw an error,
1896                // queue a global task on the crypto task source, given realm's global object, to
1897                // reject promise with the returned error; and then terminate the algorithm.
1898
1899                // Step 8. If the name member of normalizedEncapsulationAlgorithm is not equal to
1900                // the name attribute of the [[algorithm]] internal slot of encapsulationKey then
1901                // throw an InvalidAccessError.
1902                if normalized_encapsulation_algorithm.name() != encapsulation_key.algorithm().name() {
1903                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(Some(
1904                        "[[algorithm]] internal slot of encapsulationKey is not equal to \
1905                        normalizedEncapsulationAlgorithm".to_string(),
1906                    )));
1907                    return;
1908                }
1909
1910                // Step 9. If the [[usages]] internal slot of encapsulationKey does not contain an
1911                // entry that is "encapsulateBits", then throw an InvalidAccessError.
1912                if !encapsulation_key.usages().contains(&KeyUsage::EncapsulateBits) {
1913                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(Some(
1914                        "[[usages]] internal slot of encapsulationKey does not contain an \
1915                        entry that is \"encapsulateBits\"".to_string(),
1916                    )));
1917                    return;
1918                }
1919
1920                // Step 10. Let encapsulatedBits be the result of performing the encapsulate
1921                // operation specified by the [[algorithm]] internal slot of encapsulationKey using
1922                // encapsulationKey.
1923                // NOTE: Step 8 guarantees normalizedEncapsulationAlgorithm specifies the same
1924                // algorithm as the [[algorithm]] internal slot of encapsulationKey.
1925                let encapsulated_bits = match normalized_encapsulation_algorithm.encapsulate(&encapsulation_key) {
1926                    Ok(encapsulated_bits) => encapsulated_bits,
1927                    Err(error) => {
1928                        subtle.reject_promise_with_error(promise, error);
1929                        return;
1930                    },
1931                };
1932
1933                // Step 11. Queue a global task on the crypto task source, given realm's global
1934                // object, to perform the remaining steps.
1935                // Step 12. Let result be the result of converting encapsulatedBits to an
1936                // ECMAScript Object in realm, as defined by [WebIDL].
1937                // Step 13. Resolve promise with result.
1938                subtle.resolve_promise_with_encapsulated_bits(promise, encapsulated_bits);
1939            }),
1940        );
1941        promise
1942    }
1943
1944    /// <https://wicg.github.io/webcrypto-modern-algos/#SubtleCrypto-method-decapsulateKey>
1945    fn DecapsulateKey(
1946        &self,
1947        cx: JSContext,
1948        decapsulation_algorithm: AlgorithmIdentifier,
1949        decapsulation_key: &CryptoKey,
1950        ciphertext: ArrayBufferViewOrArrayBuffer,
1951        shared_key_algorithm: AlgorithmIdentifier,
1952        extractable: bool,
1953        usages: Vec<KeyUsage>,
1954        comp: InRealm,
1955        can_gc: CanGc,
1956    ) -> Rc<Promise> {
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 ciphertext be the result of getting a copy of the bytes held by the
1963        // ciphertext parameter passed to the decapsulateKey() method.
1964        let ciphertext = match ciphertext {
1965            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
1966            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
1967        };
1968
1969        // Step 3. Let normalizedDecapsulationAlgorithm be the result of normalizing an algorithm,
1970        // with alg set to decapsulationAlgorithm and op set to "decapsulate".
1971        // Step 4. If an error occurred, return a Promise rejected with
1972        // normalizedDecapsulationAlgorithm.
1973        let promise = Promise::new_in_current_realm(comp, can_gc);
1974        let normalized_decapsulation_algorithm =
1975            match normalize_algorithm(cx, Operation::Decapsulate, &decapsulation_algorithm, can_gc)
1976            {
1977                Ok(normalized_algorithm) => normalized_algorithm,
1978                Err(error) => {
1979                    promise.reject_error(error, can_gc);
1980                    return promise;
1981                },
1982            };
1983
1984        // Step 5. Let normalizedSharedKeyAlgorithm be the result of normalizing an algorithm, with
1985        // alg set to sharedKeyAlgorithm and op set to "importKey".
1986        // Step 6. If an error occurred, return a Promise rejected with
1987        // normalizedSharedKeyAlgorithm.
1988        let normalized_shared_key_algorithm =
1989            match normalize_algorithm(cx, Operation::ImportKey, &shared_key_algorithm, can_gc) {
1990                Ok(normalized_algorithm) => normalized_algorithm,
1991                Err(error) => {
1992                    promise.reject_error(error, can_gc);
1993                    return promise;
1994                },
1995            };
1996
1997        // Step 7. Let realm be the relevant realm of this.
1998        // Step 8. Let promise be a new Promise.
1999        // NOTE: We did that in preparation of Step 4.
2000
2001        // Step 9. Return promise and perform the remaining steps in parallel.
2002        let trusted_subtle = Trusted::new(self);
2003        let trusted_decapsulation_key = Trusted::new(decapsulation_key);
2004        let trusted_promise = TrustedPromise::new(promise.clone());
2005        self.global()
2006            .task_manager()
2007            .dom_manipulation_task_source()
2008            .queue(task!(decapsulate_key: move || {
2009                let subtle = trusted_subtle.root();
2010                let promise = trusted_promise.root();
2011                let decapsulation_key = trusted_decapsulation_key.root();
2012
2013                // Step 10. If the following steps or referenced procedures say to throw an error,
2014                // queue a global task on the crypto task source, given realm's global object, to
2015                // reject promise with the returned error; and then terminate the algorithm.
2016
2017                // Step 11. If the name member of normalizedDecapsulationAlgorithm is not equal to
2018                // the name attribute of the [[algorithm]] internal slot of decapsulationKey then
2019                // throw an InvalidAccessError.
2020                if normalized_decapsulation_algorithm.name() != decapsulation_key.algorithm().name() {
2021                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(Some(
2022                        "[[algorithm]] internal slot of decapsulationKey is not equal to \
2023                        normalizedDecapsulationAlgorithm".to_string()
2024                    )));
2025                    return;
2026                }
2027
2028                // Step 12. If the [[usages]] internal slot of decapsulationKey does not contain an
2029                // entry that is "decapsulateKey", then throw an InvalidAccessError.
2030                if !decapsulation_key.usages().contains(&KeyUsage::DecapsulateKey) {
2031                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(Some(
2032                        "[[usages]] internal slot of decapsulationKey does not contain an \
2033                        entry that is \"decapsulateBits\"".to_string(),
2034                    )));
2035                    return;
2036                }
2037
2038                // Step 13. Let decapsulatedBits be the result of performing the decapsulate
2039                // operation specified by the [[algorithm]] internal slot of decapsulationKey using
2040                // decapsulationKey and ciphertext.
2041                // NOTE: Step 11 guarantees normalizedDecapsulationAlgorithm specifies the same
2042                // algorithm as the [[algorithm]] internal slot of decapsulationKey.
2043                let decapsulated_bits_result =
2044                    normalized_decapsulation_algorithm.decapsulate(&decapsulation_key, &ciphertext);
2045                let decapsulated_bits = match decapsulated_bits_result {
2046                    Ok(decapsulated_bits) => decapsulated_bits,
2047                    Err(error) => {
2048                        subtle.reject_promise_with_error(promise, error);
2049                        return;
2050                    },
2051                };
2052
2053
2054                // Step 14. Let sharedKey be the result of performing the import key operation
2055                // specified by normalizedSharedKeyAlgorithm using "raw-secret" as format, the
2056                // decapsulatedBits as keyData, sharedKeyAlgorithm as algorithm and using
2057                // extractable and usages.
2058                // Step 15. Set the [[extractable]] internal slot of sharedKey to extractable.
2059                // Step 16. Set the [[usages]] internal slot of sharedKey to the normalized value
2060                // of usages.
2061                let shared_key_result = normalized_shared_key_algorithm.import_key(
2062                    &subtle.global(),
2063                    KeyFormat::Raw_secret,
2064                    &decapsulated_bits,
2065                    extractable,
2066                    usages.clone(),
2067                    CanGc::note(),
2068                );
2069                let shared_key = match shared_key_result {
2070                    Ok(shared_key) => shared_key,
2071                    Err(error) => {
2072                        subtle.reject_promise_with_error(promise, error);
2073                        return;
2074                    },
2075                };
2076
2077
2078                // Step 17. Queue a global task on the crypto task source, given realm's global
2079                // object, to perform the remaining steps.
2080                // Step 18. Let result be the result of converting sharedKey to an ECMAScript
2081                // Object in realm, as defined by [WebIDL].
2082                // Step 19. Resolve promise with result.
2083                subtle.resolve_promise_with_key(promise, shared_key);
2084            }));
2085        promise
2086    }
2087
2088    /// <https://wicg.github.io/webcrypto-modern-algos/#SubtleCrypto-method-decapsulateBits>
2089    fn DecapsulateBits(
2090        &self,
2091        cx: JSContext,
2092        decapsulation_algorithm: AlgorithmIdentifier,
2093        decapsulation_key: &CryptoKey,
2094        ciphertext: ArrayBufferViewOrArrayBuffer,
2095        comp: InRealm,
2096        can_gc: CanGc,
2097    ) -> Rc<Promise> {
2098        // Step 1. Let decapsulationAlgorithm and decapsulationKey be the decapsulationAlgorithm
2099        // and decapsulationKey parameters passed to the decapsulateBits() method, respectively.
2100
2101        // Step 2. Let ciphertext be the result of getting a copy of the bytes held by the
2102        // ciphertext parameter passed to the decapsulateBits() method.
2103        let ciphertext = match ciphertext {
2104            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2105            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2106        };
2107
2108        // Step 3. Let normalizedDecapsulationAlgorithm be the result of normalizing an algorithm,
2109        // with alg set to decapsulationAlgorithm and op set to "decapsulate".
2110        // Step 4. If an error occurred, return a Promise rejected with
2111        // normalizedDecapsulationAlgorithm.
2112        let promise = Promise::new_in_current_realm(comp, can_gc);
2113        let normalized_decapsulation_algorithm =
2114            match normalize_algorithm(cx, Operation::Decapsulate, &decapsulation_algorithm, can_gc)
2115            {
2116                Ok(normalized_algorithm) => normalized_algorithm,
2117                Err(error) => {
2118                    promise.reject_error(error, can_gc);
2119                    return promise;
2120                },
2121            };
2122
2123        // Step 5. Let realm be the relevant realm of this.
2124        // Step 6. Let promise be a new Promise.
2125        // NOTE: We did that in preparation of Step 4.
2126
2127        // Step 7. Return promise and perform the remaining steps in parallel.
2128        let trusted_subtle = Trusted::new(self);
2129        let trusted_decapsulation_key = Trusted::new(decapsulation_key);
2130        let trusted_promise = TrustedPromise::new(promise.clone());
2131        self.global()
2132            .task_manager()
2133            .dom_manipulation_task_source()
2134            .queue(task!(decapsulate_bits: move || {
2135                let subtle = trusted_subtle.root();
2136                let promise = trusted_promise.root();
2137                let decapsulation_key = trusted_decapsulation_key.root();
2138
2139                // Step 8. If the following steps or referenced procedures say to throw an error,
2140                // queue a global task on the crypto task source, given realm's global object, to
2141                // reject promise with the returned error; and then terminate the algorithm.
2142
2143                // Step 9. If the name member of normalizedDecapsulationAlgorithm is not equal to
2144                // the name attribute of the [[algorithm]] internal slot of decapsulationKey then
2145                // throw an InvalidAccessError.
2146                if normalized_decapsulation_algorithm.name() != decapsulation_key.algorithm().name() {
2147                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(Some(
2148                        "[[algorithm]] internal slot of decapsulationKey is not equal to \
2149                        normalizedDecapsulationAlgorithm".to_string()
2150                    )));
2151                    return;
2152                }
2153
2154                // Step 10. If the [[usages]] internal slot of decapsulationKey does not contain an
2155                // entry that is "decapsulateBits", then throw an InvalidAccessError.
2156                if !decapsulation_key.usages().contains(&KeyUsage::DecapsulateBits) {
2157                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(Some(
2158                        "[[usages]] internal slot of decapsulationKey does not contain an \
2159                        entry that is \"decapsulateBits\"".to_string(),
2160                    )));
2161                    return;
2162                }
2163
2164                // Step 11. Let decapsulatedBits be the result of performing the decapsulate
2165                // operation specified by the [[algorithm]] internal slot of decapsulationKey using
2166                // decapsulationKey and ciphertext.
2167                // NOTE: Step 9 guarantees normalizedDecapsulationAlgorithm specifies the same
2168                // algorithm as the [[algorithm]] internal slot of decapsulationKey.
2169                let decapsulated_bits_result =
2170                    normalized_decapsulation_algorithm.decapsulate(&decapsulation_key, &ciphertext);
2171                let decapsulated_bits = match decapsulated_bits_result {
2172                    Ok(decapsulated_bits) => decapsulated_bits,
2173                    Err(error) => {
2174                        subtle.reject_promise_with_error(promise, error);
2175                        return;
2176                    },
2177                };
2178
2179                // Step 12. Queue a global task on the crypto task source, given realm's global
2180                // object, to perform the remaining steps.
2181                // Step 13. Let result be the result of creating an ArrayBuffer in realm,
2182                // containing decapsulatedBits.
2183                // Step 14. Resolve promise with result.
2184                subtle.resolve_promise_with_data(promise, decapsulated_bits);
2185            }));
2186        promise
2187    }
2188}
2189
2190// These "subtle" structs are proxies for the codegen'd dicts which don't hold a DOMString
2191// so they can be sent safely when running steps in parallel.
2192
2193/// <https://w3c.github.io/webcrypto/#dfn-Algorithm>
2194#[derive(Clone, Debug, MallocSizeOf)]
2195struct SubtleAlgorithm {
2196    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2197    name: String,
2198}
2199
2200impl From<Algorithm> for SubtleAlgorithm {
2201    fn from(params: Algorithm) -> Self {
2202        SubtleAlgorithm {
2203            name: params.name.to_string(),
2204        }
2205    }
2206}
2207
2208/// <https://w3c.github.io/webcrypto/#dfn-KeyAlgorithm>
2209#[derive(Clone, Debug, MallocSizeOf)]
2210pub(crate) struct SubtleKeyAlgorithm {
2211    /// <https://w3c.github.io/webcrypto/#dom-keyalgorithm-name>
2212    name: String,
2213}
2214
2215impl From<NormalizedAlgorithm> for SubtleKeyAlgorithm {
2216    fn from(value: NormalizedAlgorithm) -> Self {
2217        SubtleKeyAlgorithm {
2218            name: value.name().to_string(),
2219        }
2220    }
2221}
2222
2223impl SafeToJSValConvertible for SubtleKeyAlgorithm {
2224    fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
2225        let dictionary = KeyAlgorithm {
2226            name: self.name.clone().into(),
2227        };
2228        dictionary.safe_to_jsval(cx, rval, can_gc);
2229    }
2230}
2231
2232/// <https://w3c.github.io/webcrypto/#dfn-RsaHashedKeyGenParams>
2233#[derive(Clone, MallocSizeOf)]
2234pub(crate) struct SubtleRsaHashedKeyGenParams {
2235    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2236    name: String,
2237
2238    /// <https://w3c.github.io/webcrypto/#dfn-RsaKeyGenParams-modulusLength>
2239    modulus_length: u32,
2240
2241    /// <https://w3c.github.io/webcrypto/#dfn-RsaKeyGenParams-publicExponent>
2242    public_exponent: Vec<u8>,
2243
2244    /// <https://w3c.github.io/webcrypto/#dfn-RsaHashedKeyGenParams-hash>
2245    hash: Box<NormalizedAlgorithm>,
2246}
2247
2248impl TryFrom<RootedTraceableBox<RsaHashedKeyGenParams>> for SubtleRsaHashedKeyGenParams {
2249    type Error = Error;
2250
2251    fn try_from(value: RootedTraceableBox<RsaHashedKeyGenParams>) -> Result<Self, Self::Error> {
2252        let cx = GlobalScope::get_cx();
2253        Ok(SubtleRsaHashedKeyGenParams {
2254            name: value.parent.parent.name.to_string(),
2255            modulus_length: value.parent.modulusLength,
2256            public_exponent: value.parent.publicExponent.to_vec(),
2257            hash: Box::new(normalize_algorithm(
2258                cx,
2259                Operation::Digest,
2260                &value.hash,
2261                CanGc::note(),
2262            )?),
2263        })
2264    }
2265}
2266
2267/// <https://w3c.github.io/webcrypto/#dfn-RsaHashedKeyAlgorithm>
2268#[derive(Clone, MallocSizeOf)]
2269pub(crate) struct SubtleRsaHashedKeyAlgorithm {
2270    /// <https://w3c.github.io/webcrypto/#dom-keyalgorithm-name>
2271    name: String,
2272
2273    /// <https://w3c.github.io/webcrypto/#dfn-RsaKeyAlgorithm-modulusLength>
2274    modulus_length: u32,
2275
2276    /// <https://w3c.github.io/webcrypto/#dfn-RsaKeyAlgorithm-publicExponent>
2277    public_exponent: Vec<u8>,
2278
2279    /// <https://w3c.github.io/webcrypto/#dfn-RsaHashedKeyAlgorithm-hash>
2280    hash: Box<NormalizedAlgorithm>,
2281}
2282
2283impl SafeToJSValConvertible for SubtleRsaHashedKeyAlgorithm {
2284    fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
2285        rooted!(in(*cx) let mut js_object = ptr::null_mut::<JSObject>());
2286        let public_exponent =
2287            create_buffer_source(cx, &self.public_exponent, js_object.handle_mut(), can_gc)
2288                .expect("Fail to convert publicExponent to Uint8Array");
2289        let key_algorithm = KeyAlgorithm {
2290            name: self.name.clone().into(),
2291        };
2292        let rsa_key_algorithm = RootedTraceableBox::new(RsaKeyAlgorithm {
2293            parent: key_algorithm,
2294            modulusLength: self.modulus_length,
2295            publicExponent: public_exponent,
2296        });
2297        let rsa_hashed_key_algorithm = RootedTraceableBox::new(RsaHashedKeyAlgorithm {
2298            parent: rsa_key_algorithm,
2299            hash: KeyAlgorithm {
2300                name: self.hash.name().into(),
2301            },
2302        });
2303        rsa_hashed_key_algorithm.safe_to_jsval(cx, rval, can_gc);
2304    }
2305}
2306
2307/// <https://w3c.github.io/webcrypto/#dfn-RsaHashedImportParams>
2308#[derive(Clone, MallocSizeOf)]
2309struct SubtleRsaHashedImportParams {
2310    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2311    name: String,
2312
2313    /// <https://w3c.github.io/webcrypto/#dfn-RsaHashedImportParams-hash>
2314    hash: Box<NormalizedAlgorithm>,
2315}
2316
2317impl TryFrom<RootedTraceableBox<RsaHashedImportParams>> for SubtleRsaHashedImportParams {
2318    type Error = Error;
2319
2320    fn try_from(value: RootedTraceableBox<RsaHashedImportParams>) -> Result<Self, Self::Error> {
2321        let cx = GlobalScope::get_cx();
2322        Ok(SubtleRsaHashedImportParams {
2323            name: value.parent.name.to_string(),
2324            hash: Box::new(normalize_algorithm(
2325                cx,
2326                Operation::Digest,
2327                &value.hash,
2328                CanGc::note(),
2329            )?),
2330        })
2331    }
2332}
2333
2334/// <https://w3c.github.io/webcrypto/#dfn-RsaPssParams>
2335#[derive(Clone, Debug, MallocSizeOf)]
2336struct SubtleRsaPssParams {
2337    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2338    name: String,
2339
2340    /// <https://w3c.github.io/webcrypto/#dfn-RsaPssParams-saltLength>
2341    salt_length: u32,
2342}
2343
2344impl From<RsaPssParams> for SubtleRsaPssParams {
2345    fn from(value: RsaPssParams) -> Self {
2346        SubtleRsaPssParams {
2347            name: value.parent.name.to_string(),
2348            salt_length: value.saltLength,
2349        }
2350    }
2351}
2352
2353/// <https://w3c.github.io/webcrypto/#dfn-RsaOaepParams>
2354#[derive(Clone, Debug, MallocSizeOf)]
2355struct SubtleRsaOaepParams {
2356    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2357    name: String,
2358    /// <https://w3c.github.io/webcrypto/#dfn-RsaOaepParams-label>
2359    label: Option<Vec<u8>>,
2360}
2361
2362impl From<RootedTraceableBox<RsaOaepParams>> for SubtleRsaOaepParams {
2363    fn from(value: RootedTraceableBox<RsaOaepParams>) -> Self {
2364        let label = value.label.as_ref().map(|label| match label {
2365            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2366            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2367        });
2368        SubtleRsaOaepParams {
2369            name: value.parent.name.to_string(),
2370            label,
2371        }
2372    }
2373}
2374
2375/// <https://w3c.github.io/webcrypto/#dfn-EcdsaParams>
2376#[derive(Clone, MallocSizeOf)]
2377struct SubtleEcdsaParams {
2378    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2379    name: String,
2380
2381    /// <https://w3c.github.io/webcrypto/#dfn-EcdsaParams-hash>
2382    hash: Box<NormalizedAlgorithm>,
2383}
2384
2385impl TryFrom<RootedTraceableBox<EcdsaParams>> for SubtleEcdsaParams {
2386    type Error = Error;
2387
2388    fn try_from(value: RootedTraceableBox<EcdsaParams>) -> Result<Self, Error> {
2389        let cx = GlobalScope::get_cx();
2390        let hash = normalize_algorithm(cx, Operation::Digest, &value.hash, CanGc::note())?;
2391        Ok(SubtleEcdsaParams {
2392            name: value.parent.name.to_string(),
2393            hash: Box::new(hash),
2394        })
2395    }
2396}
2397
2398/// <https://w3c.github.io/webcrypto/#dfn-EcKeyGenParams>
2399#[derive(Clone, Debug, MallocSizeOf)]
2400struct SubtleEcKeyGenParams {
2401    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2402    name: String,
2403
2404    /// <https://w3c.github.io/webcrypto/#dfn-EcKeyGenParams-namedCurve>
2405    named_curve: String,
2406}
2407
2408impl From<EcKeyGenParams> for SubtleEcKeyGenParams {
2409    fn from(value: EcKeyGenParams) -> Self {
2410        SubtleEcKeyGenParams {
2411            name: value.parent.name.to_string(),
2412            named_curve: value.namedCurve.to_string(),
2413        }
2414    }
2415}
2416
2417/// <https://w3c.github.io/webcrypto/#dfn-EcKeyAlgorithm>
2418#[derive(Clone, Debug, MallocSizeOf)]
2419pub(crate) struct SubtleEcKeyAlgorithm {
2420    /// <https://w3c.github.io/webcrypto/#dom-keyalgorithm-name>
2421    name: String,
2422
2423    /// <https://w3c.github.io/webcrypto/#dfn-EcKeyAlgorithm-namedCurve>
2424    named_curve: String,
2425}
2426
2427impl SafeToJSValConvertible for SubtleEcKeyAlgorithm {
2428    fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
2429        let parent = KeyAlgorithm {
2430            name: self.name.clone().into(),
2431        };
2432        let dictionary = EcKeyAlgorithm {
2433            parent,
2434            namedCurve: self.named_curve.clone().into(),
2435        };
2436        dictionary.safe_to_jsval(cx, rval, can_gc);
2437    }
2438}
2439
2440/// <https://w3c.github.io/webcrypto/#dfn-EcKeyImportParams>
2441#[derive(Clone, Debug, MallocSizeOf)]
2442struct SubtleEcKeyImportParams {
2443    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2444    name: String,
2445
2446    /// <https://w3c.github.io/webcrypto/#dfn-EcKeyImportParams-namedCurve>
2447    named_curve: String,
2448}
2449
2450impl From<EcKeyImportParams> for SubtleEcKeyImportParams {
2451    fn from(value: EcKeyImportParams) -> Self {
2452        SubtleEcKeyImportParams {
2453            name: value.parent.name.to_string(),
2454            named_curve: value.namedCurve.to_string(),
2455        }
2456    }
2457}
2458
2459/// <https://w3c.github.io/webcrypto/#dfn-EcdhKeyDeriveParams>
2460#[derive(Clone, MallocSizeOf)]
2461struct SubtleEcdhKeyDeriveParams {
2462    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2463    name: String,
2464
2465    /// <https://w3c.github.io/webcrypto/#dfn-EcdhKeyDeriveParams-public>
2466    public: Trusted<CryptoKey>,
2467}
2468
2469impl From<EcdhKeyDeriveParams> for SubtleEcdhKeyDeriveParams {
2470    fn from(value: EcdhKeyDeriveParams) -> Self {
2471        SubtleEcdhKeyDeriveParams {
2472            name: value.parent.name.to_string(),
2473            public: Trusted::new(&value.public),
2474        }
2475    }
2476}
2477
2478/// <https://w3c.github.io/webcrypto/#dfn-AesCtrParams>
2479#[derive(Clone, Debug, MallocSizeOf)]
2480struct SubtleAesCtrParams {
2481    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2482    name: String,
2483
2484    /// <https://w3c.github.io/webcrypto/#dfn-AesCtrParams-counter>
2485    counter: Vec<u8>,
2486
2487    /// <https://w3c.github.io/webcrypto/#dfn-AesCtrParams-length>
2488    length: u8,
2489}
2490
2491impl From<RootedTraceableBox<AesCtrParams>> for SubtleAesCtrParams {
2492    fn from(params: RootedTraceableBox<AesCtrParams>) -> Self {
2493        let counter = match &params.counter {
2494            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2495            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2496        };
2497        SubtleAesCtrParams {
2498            name: params.parent.name.to_string(),
2499            counter,
2500            length: params.length,
2501        }
2502    }
2503}
2504
2505/// <https://w3c.github.io/webcrypto/#dfn-AesKeyAlgorithm>
2506#[derive(Clone, Debug, MallocSizeOf)]
2507pub(crate) struct SubtleAesKeyAlgorithm {
2508    /// <https://w3c.github.io/webcrypto/#dom-keyalgorithm-name>
2509    name: String,
2510
2511    /// <https://w3c.github.io/webcrypto/#dfn-AesKeyAlgorithm-length>
2512    length: u16,
2513}
2514
2515impl SafeToJSValConvertible for SubtleAesKeyAlgorithm {
2516    fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
2517        let parent = KeyAlgorithm {
2518            name: self.name.clone().into(),
2519        };
2520        let dictionary = AesKeyAlgorithm {
2521            parent,
2522            length: self.length,
2523        };
2524        dictionary.safe_to_jsval(cx, rval, can_gc);
2525    }
2526}
2527
2528/// <https://w3c.github.io/webcrypto/#dfn-AesKeyGenParams>
2529#[derive(Clone, Debug, MallocSizeOf)]
2530struct SubtleAesKeyGenParams {
2531    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2532    name: String,
2533
2534    /// <https://w3c.github.io/webcrypto/#dfn-AesKeyGenParams-length>
2535    length: u16,
2536}
2537
2538impl From<AesKeyGenParams> for SubtleAesKeyGenParams {
2539    fn from(params: AesKeyGenParams) -> Self {
2540        SubtleAesKeyGenParams {
2541            name: params.parent.name.to_string(),
2542            length: params.length,
2543        }
2544    }
2545}
2546
2547/// <https://w3c.github.io/webcrypto/#dfn-AesDerivedKeyParams>
2548#[derive(Clone, Debug, MallocSizeOf)]
2549struct SubtleAesDerivedKeyParams {
2550    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2551    name: String,
2552
2553    /// <https://w3c.github.io/webcrypto/#dfn-AesDerivedKeyParams-length>
2554    length: u16,
2555}
2556
2557impl From<AesDerivedKeyParams> for SubtleAesDerivedKeyParams {
2558    fn from(params: AesDerivedKeyParams) -> Self {
2559        SubtleAesDerivedKeyParams {
2560            name: params.parent.name.to_string(),
2561            length: params.length,
2562        }
2563    }
2564}
2565
2566/// <https://w3c.github.io/webcrypto/#dfn-AesCbcParams>
2567#[derive(Clone, Debug, MallocSizeOf)]
2568struct SubtleAesCbcParams {
2569    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2570    name: String,
2571
2572    /// <https://w3c.github.io/webcrypto/#dfn-AesCbcParams-iv>
2573    iv: Vec<u8>,
2574}
2575
2576impl From<RootedTraceableBox<AesCbcParams>> for SubtleAesCbcParams {
2577    fn from(params: RootedTraceableBox<AesCbcParams>) -> Self {
2578        let iv = match &params.iv {
2579            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2580            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2581        };
2582        SubtleAesCbcParams {
2583            name: params.parent.name.to_string(),
2584            iv,
2585        }
2586    }
2587}
2588
2589/// <https://w3c.github.io/webcrypto/#dfn-AesGcmParams>
2590#[derive(Clone, Debug, MallocSizeOf)]
2591struct SubtleAesGcmParams {
2592    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2593    name: String,
2594
2595    /// <https://w3c.github.io/webcrypto/#dfn-AesGcmParams-iv>
2596    iv: Vec<u8>,
2597
2598    /// <https://w3c.github.io/webcrypto/#dfn-AesGcmParams-additionalData>
2599    additional_data: Option<Vec<u8>>,
2600
2601    /// <https://w3c.github.io/webcrypto/#dfn-AesGcmParams-tagLength>
2602    tag_length: Option<u8>,
2603}
2604
2605impl From<RootedTraceableBox<AesGcmParams>> for SubtleAesGcmParams {
2606    fn from(params: RootedTraceableBox<AesGcmParams>) -> Self {
2607        let iv = match &params.iv {
2608            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2609            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2610        };
2611        let additional_data = params.additionalData.as_ref().map(|data| match data {
2612            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2613            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2614        });
2615
2616        SubtleAesGcmParams {
2617            name: params.parent.name.to_string(),
2618            iv,
2619            additional_data,
2620            tag_length: params.tagLength,
2621        }
2622    }
2623}
2624
2625/// <https://w3c.github.io/webcrypto/#dfn-HmacImportParams>
2626#[derive(Clone, MallocSizeOf)]
2627struct SubtleHmacImportParams {
2628    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2629    name: String,
2630
2631    /// <https://w3c.github.io/webcrypto/#dfn-HmacImportParams-hash>
2632    hash: Box<NormalizedAlgorithm>,
2633
2634    /// <https://w3c.github.io/webcrypto/#dfn-HmacImportParams-length>
2635    length: Option<u32>,
2636}
2637
2638impl TryFrom<RootedTraceableBox<HmacImportParams>> for SubtleHmacImportParams {
2639    type Error = Error;
2640
2641    fn try_from(params: RootedTraceableBox<HmacImportParams>) -> Result<Self, Error> {
2642        let cx = GlobalScope::get_cx();
2643        let hash = normalize_algorithm(cx, Operation::Digest, &params.hash, CanGc::note())?;
2644        Ok(SubtleHmacImportParams {
2645            name: params.parent.name.to_string(),
2646            hash: Box::new(hash),
2647            length: params.length,
2648        })
2649    }
2650}
2651
2652/// <https://w3c.github.io/webcrypto/#dfn-HmacKeyAlgorithm>
2653#[derive(Clone, Debug, MallocSizeOf)]
2654pub(crate) struct SubtleHmacKeyAlgorithm {
2655    /// <https://w3c.github.io/webcrypto/#dom-keyalgorithm-name>
2656    name: String,
2657
2658    /// <https://w3c.github.io/webcrypto/#dfn-HmacKeyAlgorithm-hash>
2659    hash: SubtleKeyAlgorithm,
2660
2661    /// <https://w3c.github.io/webcrypto/#dfn-HmacKeyGenParams-length>
2662    length: u32,
2663}
2664
2665impl SafeToJSValConvertible for SubtleHmacKeyAlgorithm {
2666    fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
2667        let parent = KeyAlgorithm {
2668            name: self.name.clone().into(),
2669        };
2670        let hash = KeyAlgorithm {
2671            name: self.hash.name.clone().into(),
2672        };
2673        let dictionary = HmacKeyAlgorithm {
2674            parent,
2675            hash,
2676            length: self.length,
2677        };
2678        dictionary.safe_to_jsval(cx, rval, can_gc);
2679    }
2680}
2681
2682/// <https://w3c.github.io/webcrypto/#dfn-HmacKeyGenParams>
2683#[derive(Clone, MallocSizeOf)]
2684struct SubtleHmacKeyGenParams {
2685    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2686    name: String,
2687
2688    /// <https://w3c.github.io/webcrypto/#dfn-HmacKeyGenParams-hash>
2689    hash: Box<NormalizedAlgorithm>,
2690
2691    /// <https://w3c.github.io/webcrypto/#dfn-HmacKeyGenParams-length>
2692    length: Option<u32>,
2693}
2694
2695impl TryFrom<RootedTraceableBox<HmacKeyGenParams>> for SubtleHmacKeyGenParams {
2696    type Error = Error;
2697
2698    fn try_from(params: RootedTraceableBox<HmacKeyGenParams>) -> Result<Self, Error> {
2699        let cx = GlobalScope::get_cx();
2700        let hash = normalize_algorithm(cx, Operation::Digest, &params.hash, CanGc::note())?;
2701        Ok(SubtleHmacKeyGenParams {
2702            name: params.parent.name.to_string(),
2703            hash: Box::new(hash),
2704            length: params.length,
2705        })
2706    }
2707}
2708
2709/// <https://w3c.github.io/webcrypto/#dfn-HkdfParams>
2710#[derive(Clone, MallocSizeOf)]
2711pub(crate) struct SubtleHkdfParams {
2712    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2713    name: String,
2714
2715    /// <https://w3c.github.io/webcrypto/#dfn-HkdfParams-hash>
2716    hash: Box<NormalizedAlgorithm>,
2717
2718    /// <https://w3c.github.io/webcrypto/#dfn-HkdfParams-salt>
2719    salt: Vec<u8>,
2720
2721    /// <https://w3c.github.io/webcrypto/#dfn-HkdfParams-info>
2722    info: Vec<u8>,
2723}
2724
2725impl TryFrom<RootedTraceableBox<HkdfParams>> for SubtleHkdfParams {
2726    type Error = Error;
2727
2728    fn try_from(params: RootedTraceableBox<HkdfParams>) -> Result<Self, Error> {
2729        let cx = GlobalScope::get_cx();
2730        let hash = normalize_algorithm(cx, Operation::Digest, &params.hash, CanGc::note())?;
2731        let salt = match &params.salt {
2732            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2733            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2734        };
2735        let info = match &params.info {
2736            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2737            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2738        };
2739        Ok(SubtleHkdfParams {
2740            name: params.parent.name.to_string(),
2741            hash: Box::new(hash),
2742            salt,
2743            info,
2744        })
2745    }
2746}
2747
2748/// <https://w3c.github.io/webcrypto/#dfn-Pbkdf2Params>
2749#[derive(Clone, MallocSizeOf)]
2750pub(crate) struct SubtlePbkdf2Params {
2751    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2752    name: String,
2753
2754    /// <https://w3c.github.io/webcrypto/#dfn-Pbkdf2Params-salt>
2755    salt: Vec<u8>,
2756
2757    /// <https://w3c.github.io/webcrypto/#dfn-Pbkdf2Params-iterations>
2758    iterations: u32,
2759
2760    /// <https://w3c.github.io/webcrypto/#dfn-Pbkdf2Params-hash>
2761    hash: Box<NormalizedAlgorithm>,
2762}
2763
2764impl TryFrom<RootedTraceableBox<Pbkdf2Params>> for SubtlePbkdf2Params {
2765    type Error = Error;
2766
2767    fn try_from(params: RootedTraceableBox<Pbkdf2Params>) -> Result<Self, Error> {
2768        let cx = GlobalScope::get_cx();
2769        let salt = match &params.salt {
2770            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2771            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2772        };
2773        let hash = normalize_algorithm(cx, Operation::Digest, &params.hash, CanGc::note())?;
2774        Ok(SubtlePbkdf2Params {
2775            name: params.parent.name.to_string(),
2776            salt,
2777            iterations: params.iterations,
2778            hash: Box::new(hash),
2779        })
2780    }
2781}
2782
2783/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-ContextParams>
2784#[derive(Clone, Debug, MallocSizeOf)]
2785struct SubtleContextParams {
2786    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2787    name: String,
2788
2789    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-ContextParams-context>
2790    context: Option<Vec<u8>>,
2791}
2792
2793impl From<RootedTraceableBox<ContextParams>> for SubtleContextParams {
2794    fn from(value: RootedTraceableBox<ContextParams>) -> Self {
2795        let context = value.context.as_ref().map(|context| match context {
2796            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2797            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2798        });
2799        SubtleContextParams {
2800            name: value.parent.name.to_string(),
2801            context,
2802        }
2803    }
2804}
2805
2806/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-AeadParams>
2807#[derive(Clone, Debug, MallocSizeOf)]
2808struct SubtleAeadParams {
2809    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2810    name: String,
2811
2812    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-AeadParams-iv>
2813    iv: Vec<u8>,
2814
2815    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-AeadParams-additionalData>
2816    additional_data: Option<Vec<u8>>,
2817
2818    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-AeadParams-tagLength>
2819    tag_length: Option<u8>,
2820}
2821
2822impl From<RootedTraceableBox<AeadParams>> for SubtleAeadParams {
2823    fn from(value: RootedTraceableBox<AeadParams>) -> Self {
2824        let iv = match &value.iv {
2825            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2826            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2827        };
2828        let additional_data = value.additionalData.as_ref().map(|data| match data {
2829            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2830            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2831        });
2832
2833        SubtleAeadParams {
2834            name: value.parent.name.to_string(),
2835            iv,
2836            additional_data,
2837            tag_length: value.tagLength,
2838        }
2839    }
2840}
2841
2842/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-CShakeParams>
2843#[derive(Clone, Debug, MallocSizeOf)]
2844struct SubtleCShakeParams {
2845    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2846    name: String,
2847
2848    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-CShakeParams-length>
2849    length: u32,
2850
2851    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-CShakeParams-functionName>
2852    function_name: Option<Vec<u8>>,
2853
2854    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-CShakeParams-customization>
2855    customization: Option<Vec<u8>>,
2856}
2857
2858impl From<RootedTraceableBox<CShakeParams>> for SubtleCShakeParams {
2859    fn from(value: RootedTraceableBox<CShakeParams>) -> Self {
2860        let function_name = value
2861            .functionName
2862            .as_ref()
2863            .map(|function_name| match function_name {
2864                ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2865                ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2866            });
2867        let customization = value
2868            .customization
2869            .as_ref()
2870            .map(|customization| match customization {
2871                ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2872                ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2873            });
2874        SubtleCShakeParams {
2875            name: value.parent.name.to_string(),
2876            length: value.length,
2877            function_name,
2878            customization,
2879        }
2880    }
2881}
2882
2883/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params>
2884#[derive(Clone, Debug, MallocSizeOf)]
2885struct SubtleArgon2Params {
2886    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2887    name: String,
2888
2889    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-nonce>
2890    nonce: Vec<u8>,
2891
2892    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-parallelism>
2893    parallelism: u32,
2894
2895    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-memory>
2896    memory: u32,
2897
2898    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-passes>
2899    passes: u32,
2900
2901    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-version>
2902    version: Option<u8>,
2903
2904    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-secretValue>
2905    secret_value: Option<Vec<u8>>,
2906
2907    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-associatedData>
2908    associated_data: Option<Vec<u8>>,
2909}
2910
2911impl From<RootedTraceableBox<Argon2Params>> for SubtleArgon2Params {
2912    fn from(value: RootedTraceableBox<Argon2Params>) -> Self {
2913        let nonce = match &value.nonce {
2914            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2915            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2916        };
2917        let secret_value = value
2918            .secretValue
2919            .as_ref()
2920            .map(|secret_value| match secret_value {
2921                ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2922                ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2923            });
2924        let associated_data =
2925            value
2926                .associatedData
2927                .as_ref()
2928                .map(|associated_data| match associated_data {
2929                    ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2930                    ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2931                });
2932        SubtleArgon2Params {
2933            name: value.parent.name.to_string(),
2934            nonce,
2935            parallelism: value.parallelism,
2936            memory: value.memory,
2937            passes: value.passes,
2938            version: value.version,
2939            secret_value,
2940            associated_data,
2941        }
2942    }
2943}
2944
2945/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-EncapsulatedKey>
2946struct SubtleEncapsulatedKey {
2947    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-EncapsulatedKey-sharedKey>
2948    shared_key: Option<Trusted<CryptoKey>>,
2949
2950    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-EncapsulatedKey-ciphertext>
2951    ciphertext: Option<Vec<u8>>,
2952}
2953
2954impl SafeToJSValConvertible for SubtleEncapsulatedKey {
2955    fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
2956        let shared_key = self.shared_key.as_ref().map(|shared_key| shared_key.root());
2957        let ciphertext = self.ciphertext.as_ref().map(|data| {
2958            rooted!(in(*cx) let mut ciphertext_ptr = ptr::null_mut::<JSObject>());
2959            create_buffer_source::<ArrayBufferU8>(cx, data, ciphertext_ptr.handle_mut(), can_gc)
2960                .expect("Failed to convert ciphertext to ArrayBufferU8")
2961        });
2962        let encapsulated_key = RootedTraceableBox::new(EncapsulatedKey {
2963            sharedKey: shared_key,
2964            ciphertext,
2965        });
2966        encapsulated_key.safe_to_jsval(cx, rval, can_gc);
2967    }
2968}
2969
2970/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-EncapsulatedBits>
2971struct SubtleEncapsulatedBits {
2972    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-EncapsulatedBits-sharedKey>
2973    shared_key: Option<Vec<u8>>,
2974
2975    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-EncapsulatedBits-ciphertext>
2976    ciphertext: Option<Vec<u8>>,
2977}
2978
2979impl SafeToJSValConvertible for SubtleEncapsulatedBits {
2980    fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
2981        let shared_key = self.shared_key.as_ref().map(|data| {
2982            rooted!(in(*cx) let mut shared_key_ptr = ptr::null_mut::<JSObject>());
2983            create_buffer_source::<ArrayBufferU8>(cx, data, shared_key_ptr.handle_mut(), can_gc)
2984                .expect("Failed to convert shared key to ArrayBufferU8")
2985        });
2986        let ciphertext = self.ciphertext.as_ref().map(|data| {
2987            rooted!(in(*cx) let mut ciphertext_ptr = ptr::null_mut::<JSObject>());
2988            create_buffer_source::<ArrayBufferU8>(cx, data, ciphertext_ptr.handle_mut(), can_gc)
2989                .expect("Failed to convert ciphertext to ArrayBufferU8")
2990        });
2991        let encapsulated_bits = RootedTraceableBox::new(EncapsulatedBits {
2992            sharedKey: shared_key,
2993            ciphertext,
2994        });
2995        encapsulated_bits.safe_to_jsval(cx, rval, can_gc);
2996    }
2997}
2998
2999/// Helper to abstract the conversion process of a JS value into many different WebIDL dictionaries.
3000fn dictionary_from_jsval<T>(cx: JSContext, value: HandleValue, can_gc: CanGc) -> Fallible<T>
3001where
3002    T: SafeFromJSValConvertible<Config = ()>,
3003{
3004    let conversion = T::safe_from_jsval(cx, value, (), can_gc).map_err(|_| Error::JSFailed)?;
3005    match conversion {
3006        ConversionResult::Success(dictionary) => Ok(dictionary),
3007        ConversionResult::Failure(error) => Err(Error::Type(error.into())),
3008    }
3009}
3010
3011/// The returned type of the successful export key operation. `Bytes` should be used when the key
3012/// is exported in "raw", "spki" or "pkcs8" format. `Jwk` should be used when the key is exported
3013/// in "jwk" format.
3014enum ExportedKey {
3015    Bytes(Vec<u8>),
3016    Jwk(Box<JsonWebKey>),
3017}
3018
3019/// Union type of KeyAlgorithm and IDL dictionary types derived from it. Note that we actually use
3020/// our "subtle" structs of the corresponding IDL dictionary types so that they can be easily
3021/// passed to another threads.
3022#[derive(Clone, MallocSizeOf)]
3023#[expect(clippy::enum_variant_names)]
3024pub(crate) enum KeyAlgorithmAndDerivatives {
3025    KeyAlgorithm(SubtleKeyAlgorithm),
3026    RsaHashedKeyAlgorithm(SubtleRsaHashedKeyAlgorithm),
3027    EcKeyAlgorithm(SubtleEcKeyAlgorithm),
3028    AesKeyAlgorithm(SubtleAesKeyAlgorithm),
3029    HmacKeyAlgorithm(SubtleHmacKeyAlgorithm),
3030}
3031
3032impl KeyAlgorithmAndDerivatives {
3033    fn name(&self) -> &str {
3034        match self {
3035            KeyAlgorithmAndDerivatives::KeyAlgorithm(algo) => &algo.name,
3036            KeyAlgorithmAndDerivatives::RsaHashedKeyAlgorithm(algo) => &algo.name,
3037            KeyAlgorithmAndDerivatives::EcKeyAlgorithm(algo) => &algo.name,
3038            KeyAlgorithmAndDerivatives::AesKeyAlgorithm(algo) => &algo.name,
3039            KeyAlgorithmAndDerivatives::HmacKeyAlgorithm(algo) => &algo.name,
3040        }
3041    }
3042}
3043
3044impl From<NormalizedAlgorithm> for KeyAlgorithmAndDerivatives {
3045    fn from(value: NormalizedAlgorithm) -> Self {
3046        KeyAlgorithmAndDerivatives::KeyAlgorithm(SubtleKeyAlgorithm {
3047            name: value.name().to_string(),
3048        })
3049    }
3050}
3051
3052impl SafeToJSValConvertible for KeyAlgorithmAndDerivatives {
3053    fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
3054        match self {
3055            KeyAlgorithmAndDerivatives::KeyAlgorithm(algo) => algo.safe_to_jsval(cx, rval, can_gc),
3056            KeyAlgorithmAndDerivatives::RsaHashedKeyAlgorithm(algo) => {
3057                algo.safe_to_jsval(cx, rval, can_gc)
3058            },
3059            KeyAlgorithmAndDerivatives::EcKeyAlgorithm(algo) => {
3060                algo.safe_to_jsval(cx, rval, can_gc)
3061            },
3062            KeyAlgorithmAndDerivatives::AesKeyAlgorithm(algo) => {
3063                algo.safe_to_jsval(cx, rval, can_gc)
3064            },
3065            KeyAlgorithmAndDerivatives::HmacKeyAlgorithm(algo) => {
3066                algo.safe_to_jsval(cx, rval, can_gc)
3067            },
3068        }
3069    }
3070}
3071
3072#[derive(Clone, Copy)]
3073enum JwkStringField {
3074    X,
3075    Y,
3076    D,
3077    N,
3078    E,
3079    P,
3080    Q,
3081    DP,
3082    DQ,
3083    QI,
3084    K,
3085    Priv,
3086    Pub,
3087}
3088
3089impl Display for JwkStringField {
3090    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3091        let field_name = match self {
3092            JwkStringField::X => "x",
3093            JwkStringField::Y => "y",
3094            JwkStringField::D => "d",
3095            JwkStringField::N => "n",
3096            JwkStringField::E => "e",
3097            JwkStringField::P => "q",
3098            JwkStringField::Q => "q",
3099            JwkStringField::DP => "dp",
3100            JwkStringField::DQ => "dq",
3101            JwkStringField::QI => "qi",
3102            JwkStringField::K => "k",
3103            JwkStringField::Priv => "priv",
3104            JwkStringField::Pub => "pub",
3105        };
3106        write!(f, "{}", field_name)
3107    }
3108}
3109
3110trait JsonWebKeyExt {
3111    fn parse(cx: JSContext, data: &[u8]) -> Result<JsonWebKey, Error>;
3112    fn stringify(&self, cx: JSContext) -> Result<DOMString, Error>;
3113    fn get_usages_from_key_ops(&self) -> Result<Vec<KeyUsage>, Error>;
3114    fn check_key_ops(&self, specified_usages: &[KeyUsage]) -> Result<(), Error>;
3115    fn set_key_ops(&mut self, usages: Vec<KeyUsage>);
3116    fn encode_string_field(&mut self, field: JwkStringField, data: &[u8]);
3117    fn decode_optional_string_field(&self, field: JwkStringField)
3118    -> Result<Option<Vec<u8>>, Error>;
3119    fn decode_required_string_field(&self, field: JwkStringField) -> Result<Vec<u8>, Error>;
3120    fn decode_primes_from_oth_field(&self, primes: &mut Vec<Vec<u8>>) -> Result<(), Error>;
3121}
3122
3123impl JsonWebKeyExt for JsonWebKey {
3124    /// <https://w3c.github.io/webcrypto/#concept-parse-a-jwk>
3125    #[expect(unsafe_code)]
3126    fn parse(cx: JSContext, data: &[u8]) -> Result<JsonWebKey, Error> {
3127        // Step 1. Let data be the sequence of bytes to be parsed.
3128        // (It is given as a method paramter.)
3129
3130        // Step 2. Let json be the Unicode string that results from interpreting data according to UTF-8.
3131        let json = String::from_utf8_lossy(data);
3132
3133        // Step 3. Convert json to UTF-16.
3134        let json: Vec<_> = json.encode_utf16().collect();
3135
3136        // Step 4. Let result be the object literal that results from executing the JSON.parse
3137        // internal function in the context of a new global object, with text argument set to a
3138        // JavaScript String containing json.
3139        rooted!(in(*cx) let mut result = UndefinedValue());
3140        unsafe {
3141            if !JS_ParseJSON(*cx, json.as_ptr(), json.len() as u32, result.handle_mut()) {
3142                return Err(Error::JSFailed);
3143            }
3144        }
3145
3146        // Step 5. Let key be the result of converting result to the IDL dictionary type of JsonWebKey.
3147        let key = match JsonWebKey::new(cx, result.handle(), CanGc::note()) {
3148            Ok(ConversionResult::Success(key)) => key,
3149            Ok(ConversionResult::Failure(error)) => {
3150                return Err(Error::Type(error.to_string()));
3151            },
3152            Err(()) => {
3153                return Err(Error::JSFailed);
3154            },
3155        };
3156
3157        // Step 6. If the kty field of key is not defined, then throw a DataError.
3158        if key.kty.is_none() {
3159            return Err(Error::Data(None));
3160        }
3161
3162        // Step 7. Result key.
3163        Ok(key)
3164    }
3165
3166    /// Convert a JsonWebKey value to DOMString. We first convert the JsonWebKey value to
3167    /// JavaScript value, and then serialize it by performing steps in
3168    /// <https://infra.spec.whatwg.org/#serialize-a-javascript-value-to-a-json-string>. This acts
3169    /// like the opposite of JsonWebKey::parse if you further convert the stringified result to
3170    /// bytes.
3171    fn stringify(&self, cx: JSContext) -> Result<DOMString, Error> {
3172        rooted!(in(*cx) let mut data = UndefinedValue());
3173        self.safe_to_jsval(cx, data.handle_mut(), CanGc::note());
3174        serialize_jsval_to_json_utf8(cx, data.handle())
3175    }
3176
3177    fn get_usages_from_key_ops(&self) -> Result<Vec<KeyUsage>, Error> {
3178        let mut usages = vec![];
3179        for op in self.key_ops.as_ref().ok_or(Error::Data(None))? {
3180            usages.push(KeyUsage::from_str(&op.str()).map_err(|_| Error::Data(None))?);
3181        }
3182        Ok(usages)
3183    }
3184
3185    /// If the key_ops field of jwk is present, and is invalid according to the requirements of
3186    /// JSON Web Key [JWK] or does not contain all of the specified usages values, then throw a
3187    /// DataError.
3188    fn check_key_ops(&self, specified_usages: &[KeyUsage]) -> Result<(), Error> {
3189        // If the key_ops field of jwk is present,
3190        if let Some(ref key_ops) = self.key_ops {
3191            // and is invalid according to the requirements of JSON Web Key [JWK]:
3192            // 1. Duplicate key operation values MUST NOT be present in the array.
3193            if key_ops
3194                .iter()
3195                .collect::<std::collections::HashSet<_>>()
3196                .len() <
3197                key_ops.len()
3198            {
3199                return Err(Error::Data(None));
3200            }
3201            // 2. The "use" and "key_ops" JWK members SHOULD NOT be used together; however, if both
3202            //    are used, the information they convey MUST be consistent.
3203            if let Some(ref use_) = self.use_ {
3204                if key_ops.iter().any(|op| op != use_) {
3205                    return Err(Error::Data(None));
3206                }
3207            }
3208
3209            // or does not contain all of the specified usages values
3210            let key_ops_as_usages = self.get_usages_from_key_ops()?;
3211            if !specified_usages
3212                .iter()
3213                .all(|specified_usage| key_ops_as_usages.contains(specified_usage))
3214            {
3215                return Err(Error::Data(None));
3216            }
3217        }
3218
3219        Ok(())
3220    }
3221
3222    // Set the key_ops attribute of jwk to equal the given usages.
3223    fn set_key_ops(&mut self, usages: Vec<KeyUsage>) {
3224        self.key_ops = Some(
3225            usages
3226                .into_iter()
3227                .map(|usage| DOMString::from(usage.as_str()))
3228                .collect(),
3229        );
3230    }
3231
3232    // Encode a byte sequence to a base64url-encoded string, and set the field to the encoded
3233    // string.
3234    fn encode_string_field(&mut self, field: JwkStringField, data: &[u8]) {
3235        let encoded_data = DOMString::from(Base64UrlUnpadded::encode_string(data));
3236        match field {
3237            JwkStringField::X => self.x = Some(encoded_data),
3238            JwkStringField::Y => self.y = Some(encoded_data),
3239            JwkStringField::D => self.d = Some(encoded_data),
3240            JwkStringField::N => self.n = Some(encoded_data),
3241            JwkStringField::E => self.e = Some(encoded_data),
3242            JwkStringField::P => self.p = Some(encoded_data),
3243            JwkStringField::Q => self.q = Some(encoded_data),
3244            JwkStringField::DP => self.dp = Some(encoded_data),
3245            JwkStringField::DQ => self.dq = Some(encoded_data),
3246            JwkStringField::QI => self.qi = Some(encoded_data),
3247            JwkStringField::K => self.k = Some(encoded_data),
3248            JwkStringField::Priv => self.priv_ = Some(encoded_data),
3249            JwkStringField::Pub => self.pub_ = Some(encoded_data),
3250        }
3251    }
3252
3253    // Decode a field from a base64url-encoded string to a byte sequence. If the field is not a
3254    // valid base64url-encoded string, then throw a DataError.
3255    fn decode_optional_string_field(
3256        &self,
3257        field: JwkStringField,
3258    ) -> Result<Option<Vec<u8>>, Error> {
3259        let field_string = match field {
3260            JwkStringField::X => &self.x,
3261            JwkStringField::Y => &self.y,
3262            JwkStringField::D => &self.d,
3263            JwkStringField::N => &self.n,
3264            JwkStringField::E => &self.e,
3265            JwkStringField::P => &self.p,
3266            JwkStringField::Q => &self.q,
3267            JwkStringField::DP => &self.dp,
3268            JwkStringField::DQ => &self.dq,
3269            JwkStringField::QI => &self.qi,
3270            JwkStringField::K => &self.k,
3271            JwkStringField::Priv => &self.priv_,
3272            JwkStringField::Pub => &self.pub_,
3273        };
3274
3275        field_string
3276            .as_ref()
3277            .map(|field_string| Base64UrlUnpadded::decode_vec(&field_string.str()))
3278            .transpose()
3279            .map_err(|_| Error::Data(Some(format!("Failed to decode {} field in jwk", field))))
3280    }
3281
3282    // Decode a field from a base64url-encoded string to a byte sequence. If the field is not
3283    // present or it is not a valid base64url-encoded string, then throw a DataError.
3284    fn decode_required_string_field(&self, field: JwkStringField) -> Result<Vec<u8>, Error> {
3285        self.decode_optional_string_field(field)?
3286            .ok_or(Error::Data(Some(format!(
3287                "The {} field is not present in jwk",
3288                field
3289            ))))
3290    }
3291
3292    // Decode the "r", "d" and "t" field of each entry in the "oth" array, from a base64url-encoded
3293    // string to a byte sequence, and append the decoded "r" field to the `primes` list, in the
3294    // order of presence in the "oth" array.
3295    //
3296    // If the "oth" field is present and any of the "p", "q", "dp", "dq" or "qi" field is not
3297    // present, then throw a DataError. For each entry in the "oth" array, if any of the "r", "d"
3298    // and "t" field is not present or it is not a valid base64url-encoded string, then throw a
3299    // DataError.
3300    fn decode_primes_from_oth_field(&self, primes: &mut Vec<Vec<u8>>) -> Result<(), Error> {
3301        if self.oth.is_some() &&
3302            (self.p.is_none() ||
3303                self.q.is_none() ||
3304                self.dp.is_none() ||
3305                self.dq.is_none() ||
3306                self.qi.is_none())
3307        {
3308            return Err(Error::Data(Some(
3309                "The oth field is present while at least one of p, q, dp, dq, qi is missing, in jwk".to_string()
3310            )));
3311        }
3312
3313        for rsa_other_prime_info in self.oth.as_ref().unwrap_or(&Vec::new()) {
3314            let r = Base64UrlUnpadded::decode_vec(
3315                &rsa_other_prime_info
3316                    .r
3317                    .as_ref()
3318                    .ok_or(Error::Data(Some(
3319                        "The r field is not present in one of the entry of oth field in jwk"
3320                            .to_string(),
3321                    )))?
3322                    .str(),
3323            )
3324            .map_err(|_| {
3325                Error::Data(Some(
3326                    "Fail to decode r field in one of the entry of oth field in jwk".to_string(),
3327                ))
3328            })?;
3329            primes.push(r);
3330
3331            let _d = Base64UrlUnpadded::decode_vec(
3332                &rsa_other_prime_info
3333                    .d
3334                    .as_ref()
3335                    .ok_or(Error::Data(Some(
3336                        "The d field is not present in one of the entry of oth field in jwk"
3337                            .to_string(),
3338                    )))?
3339                    .str(),
3340            )
3341            .map_err(|_| {
3342                Error::Data(Some(
3343                    "Fail to decode d field in one of the entry of oth field in jwk".to_string(),
3344                ))
3345            })?;
3346
3347            let _t = Base64UrlUnpadded::decode_vec(
3348                &rsa_other_prime_info
3349                    .t
3350                    .as_ref()
3351                    .ok_or(Error::Data(Some(
3352                        "The t field is not present in one of the entry of oth field in jwk"
3353                            .to_string(),
3354                    )))?
3355                    .str(),
3356            )
3357            .map_err(|_| {
3358                Error::Data(Some(
3359                    "Fail to decode t field in one of the entry of oth field in jwk".to_string(),
3360                ))
3361            })?;
3362        }
3363
3364        Ok(())
3365    }
3366}
3367
3368/// Inner type of <https://w3c.github.io/webcrypto/#dfn-supportedAlgorithms> for SHA
3369enum ShaAlgorithm {
3370    Sha1,
3371    Sha256,
3372    Sha384,
3373    Sha512,
3374}
3375
3376impl ShaAlgorithm {
3377    fn as_str(&self) -> &'static str {
3378        match self {
3379            ShaAlgorithm::Sha1 => ALG_SHA1,
3380            ShaAlgorithm::Sha256 => ALG_SHA256,
3381            ShaAlgorithm::Sha384 => ALG_SHA384,
3382            ShaAlgorithm::Sha512 => ALG_SHA512,
3383        }
3384    }
3385}
3386
3387/// Inner type of <https://w3c.github.io/webcrypto/#dfn-supportedAlgorithms> for ML-KEM
3388enum MlKemAlgorithm {
3389    MlKem512,
3390    MlKem768,
3391    MlKem1024,
3392}
3393
3394impl MlKemAlgorithm {
3395    fn as_str(&self) -> &'static str {
3396        match self {
3397            MlKemAlgorithm::MlKem512 => ALG_ML_KEM_512,
3398            MlKemAlgorithm::MlKem768 => ALG_ML_KEM_768,
3399            MlKemAlgorithm::MlKem1024 => ALG_ML_KEM_1024,
3400        }
3401    }
3402}
3403
3404/// Inner type of <https://w3c.github.io/webcrypto/#dfn-supportedAlgorithms> for ML-DSA
3405enum MlDsaAlgorithm {
3406    MlDsa44,
3407    MlDsa65,
3408    MlDsa87,
3409}
3410
3411impl MlDsaAlgorithm {
3412    fn as_str(&self) -> &'static str {
3413        match self {
3414            MlDsaAlgorithm::MlDsa44 => ALG_ML_DSA_44,
3415            MlDsaAlgorithm::MlDsa65 => ALG_ML_DSA_65,
3416            MlDsaAlgorithm::MlDsa87 => ALG_ML_DSA_87,
3417        }
3418    }
3419}
3420
3421/// Inner type of <https://w3c.github.io/webcrypto/#dfn-supportedAlgorithms> for SHA3
3422enum Sha3Algorithm {
3423    Sha3_256,
3424    Sha3_384,
3425    Sha3_512,
3426}
3427
3428impl Sha3Algorithm {
3429    fn as_str(&self) -> &'static str {
3430        match self {
3431            Sha3Algorithm::Sha3_256 => ALG_SHA3_256,
3432            Sha3Algorithm::Sha3_384 => ALG_SHA3_384,
3433            Sha3Algorithm::Sha3_512 => ALG_SHA3_512,
3434        }
3435    }
3436}
3437
3438/// Inner type of <https://w3c.github.io/webcrypto/#dfn-supportedAlgorithms> for cSHAKE
3439enum CShakeAlgorithm {
3440    CShake128,
3441    CShake256,
3442}
3443
3444impl CShakeAlgorithm {
3445    fn as_str(&self) -> &'static str {
3446        match self {
3447            CShakeAlgorithm::CShake128 => ALG_CSHAKE_128,
3448            CShakeAlgorithm::CShake256 => ALG_CSHAKE_256,
3449        }
3450    }
3451}
3452
3453/// Inner type of <https://w3c.github.io/webcrypto/#dfn-supportedAlgorithms> for Argon2
3454enum Argon2Algorithm {
3455    Argon2D,
3456    Argon2I,
3457    Argon2ID,
3458}
3459
3460impl Argon2Algorithm {
3461    fn as_str(&self) -> &'static str {
3462        match self {
3463            Argon2Algorithm::Argon2D => ALG_ARGON2D,
3464            Argon2Algorithm::Argon2I => ALG_ARGON2I,
3465            Argon2Algorithm::Argon2ID => ALG_ARGON2ID,
3466        }
3467    }
3468}
3469
3470/// <https://w3c.github.io/webcrypto/#dfn-supportedAlgorithms>
3471enum SupportedAlgorithm {
3472    RsassaPkcs1V1_5,
3473    RsaPss,
3474    RsaOaep,
3475    Ecdsa,
3476    Ecdh,
3477    Ed25519,
3478    X25519,
3479    AesCtr,
3480    AesCbc,
3481    AesGcm,
3482    AesKw,
3483    Hmac,
3484    Sha(ShaAlgorithm),
3485    Hkdf,
3486    Pbkdf2,
3487    MlKem(MlKemAlgorithm),
3488    MlDsa(MlDsaAlgorithm),
3489    AesOcb,
3490    ChaCha20Poly1305,
3491    Sha3(Sha3Algorithm),
3492    CShake(CShakeAlgorithm),
3493    Argon2(Argon2Algorithm),
3494}
3495
3496impl SupportedAlgorithm {
3497    fn as_str(&self) -> &'static str {
3498        match self {
3499            SupportedAlgorithm::RsassaPkcs1V1_5 => ALG_RSASSA_PKCS1_V1_5,
3500            SupportedAlgorithm::RsaPss => ALG_RSA_PSS,
3501            SupportedAlgorithm::RsaOaep => ALG_RSA_OAEP,
3502            SupportedAlgorithm::Ecdsa => ALG_ECDSA,
3503            SupportedAlgorithm::Ecdh => ALG_ECDH,
3504            SupportedAlgorithm::Ed25519 => ALG_ED25519,
3505            SupportedAlgorithm::X25519 => ALG_X25519,
3506            SupportedAlgorithm::AesCtr => ALG_AES_CTR,
3507            SupportedAlgorithm::AesCbc => ALG_AES_CBC,
3508            SupportedAlgorithm::AesGcm => ALG_AES_GCM,
3509            SupportedAlgorithm::AesKw => ALG_AES_KW,
3510            SupportedAlgorithm::Hmac => ALG_HMAC,
3511            SupportedAlgorithm::Sha(sha_algorithm) => sha_algorithm.as_str(),
3512            SupportedAlgorithm::Hkdf => ALG_HKDF,
3513            SupportedAlgorithm::Pbkdf2 => ALG_PBKDF2,
3514            SupportedAlgorithm::MlKem(ml_kem_algorithm) => ml_kem_algorithm.as_str(),
3515            SupportedAlgorithm::MlDsa(ml_dsa_algorithm) => ml_dsa_algorithm.as_str(),
3516            SupportedAlgorithm::AesOcb => ALG_AES_OCB,
3517            SupportedAlgorithm::ChaCha20Poly1305 => ALG_CHACHA20_POLY1305,
3518            SupportedAlgorithm::Sha3(sha3_algorithm) => sha3_algorithm.as_str(),
3519            SupportedAlgorithm::CShake(cshake_algorithm) => cshake_algorithm.as_str(),
3520            SupportedAlgorithm::Argon2(argon2_algorithm) => argon2_algorithm.as_str(),
3521        }
3522    }
3523
3524    fn from_ignore_case(alg_name: &str) -> Result<SupportedAlgorithm, Error> {
3525        let Some(&alg_name) = SUPPORTED_ALGORITHMS
3526            .iter()
3527            .find(|supported_algorithm| supported_algorithm.eq_ignore_ascii_case(alg_name))
3528        else {
3529            return Err(Error::NotSupported(Some(format!(
3530                "Unsupported algorithm: {}",
3531                alg_name
3532            ))));
3533        };
3534        SupportedAlgorithm::try_from(alg_name)
3535    }
3536
3537    /// Check whether the cryptographic algorithm supports the specified operation. If the
3538    /// algorithm supports the operation, then return the desired IDL dictionary type for the
3539    /// operation of the algorithm. Otherwise, throw a NotSupportedError.
3540    ///
3541    /// This function is also used as the "define an algorithm" algorithm, by adding algorithms,
3542    /// operations and desired IDL dictionary types, to the `match` block.
3543    /// <https://w3c.github.io/webcrypto/#concept-define-an-algorithm>
3544    fn support(&self, op: Operation) -> Result<ParameterType, Error> {
3545        let desired_type = match (self, &op) {
3546            // <https://w3c.github.io/webcrypto/#rsassa-pkcs1-registration>
3547            (Self::RsassaPkcs1V1_5, Operation::Sign) => ParameterType::None,
3548            (Self::RsassaPkcs1V1_5, Operation::Verify) => ParameterType::None,
3549            (Self::RsassaPkcs1V1_5, Operation::GenerateKey) => ParameterType::RsaHashedKeyGenParams,
3550            (Self::RsassaPkcs1V1_5, Operation::ImportKey) => ParameterType::RsaHashedImportParams,
3551            (Self::RsassaPkcs1V1_5, Operation::ExportKey) => ParameterType::None,
3552
3553            // <https://w3c.github.io/webcrypto/#rsa-pss-registration>
3554            (Self::RsaPss, Operation::Sign) => ParameterType::RsaPssParams,
3555            (Self::RsaPss, Operation::Verify) => ParameterType::RsaPssParams,
3556            (Self::RsaPss, Operation::GenerateKey) => ParameterType::RsaHashedKeyGenParams,
3557            (Self::RsaPss, Operation::ImportKey) => ParameterType::RsaHashedImportParams,
3558            (Self::RsaPss, Operation::ExportKey) => ParameterType::None,
3559
3560            // <https://w3c.github.io/webcrypto/#rsa-oaep-registration>
3561            (Self::RsaOaep, Operation::Encrypt) => ParameterType::RsaOaepParams,
3562            (Self::RsaOaep, Operation::Decrypt) => ParameterType::RsaOaepParams,
3563            (Self::RsaOaep, Operation::GenerateKey) => ParameterType::RsaHashedKeyGenParams,
3564            (Self::RsaOaep, Operation::ImportKey) => ParameterType::RsaHashedImportParams,
3565            (Self::RsaOaep, Operation::ExportKey) => ParameterType::None,
3566
3567            // <https://w3c.github.io/webcrypto/#ecdsa-registration>
3568            (Self::Ecdsa, Operation::Sign) => ParameterType::EcdsaParams,
3569            (Self::Ecdsa, Operation::Verify) => ParameterType::EcdsaParams,
3570            (Self::Ecdsa, Operation::GenerateKey) => ParameterType::EcKeyGenParams,
3571            (Self::Ecdsa, Operation::ImportKey) => ParameterType::EcKeyImportParams,
3572            (Self::Ecdsa, Operation::ExportKey) => ParameterType::None,
3573
3574            // <https://w3c.github.io/webcrypto/#ecdh-registration>
3575            (Self::Ecdh, Operation::GenerateKey) => ParameterType::EcKeyGenParams,
3576            (Self::Ecdh, Operation::DeriveBits) => ParameterType::EcdhKeyDeriveParams,
3577            (Self::Ecdh, Operation::ImportKey) => ParameterType::EcKeyImportParams,
3578            (Self::Ecdh, Operation::ExportKey) => ParameterType::None,
3579
3580            // <https://w3c.github.io/webcrypto/#ed25519-registration>
3581            (Self::Ed25519, Operation::Sign) => ParameterType::None,
3582            (Self::Ed25519, Operation::Verify) => ParameterType::None,
3583            (Self::Ed25519, Operation::GenerateKey) => ParameterType::None,
3584            (Self::Ed25519, Operation::ImportKey) => ParameterType::None,
3585            (Self::Ed25519, Operation::ExportKey) => ParameterType::None,
3586
3587            // <https://w3c.github.io/webcrypto/#x25519-registration>
3588            (Self::X25519, Operation::DeriveBits) => ParameterType::EcdhKeyDeriveParams,
3589            (Self::X25519, Operation::GenerateKey) => ParameterType::None,
3590            (Self::X25519, Operation::ImportKey) => ParameterType::None,
3591            (Self::X25519, Operation::ExportKey) => ParameterType::None,
3592
3593            // <https://w3c.github.io/webcrypto/#aes-ctr-registration>
3594            (Self::AesCtr, Operation::Encrypt) => ParameterType::AesCtrParams,
3595            (Self::AesCtr, Operation::Decrypt) => ParameterType::AesCtrParams,
3596            (Self::AesCtr, Operation::GenerateKey) => ParameterType::AesKeyGenParams,
3597            (Self::AesCtr, Operation::ImportKey) => ParameterType::None,
3598            (Self::AesCtr, Operation::ExportKey) => ParameterType::None,
3599            (Self::AesCtr, Operation::GetKeyLength) => ParameterType::AesDerivedKeyParams,
3600
3601            // <https://w3c.github.io/webcrypto/#aes-cbc-registration>
3602            (Self::AesCbc, Operation::Encrypt) => ParameterType::AesCbcParams,
3603            (Self::AesCbc, Operation::Decrypt) => ParameterType::AesCbcParams,
3604            (Self::AesCbc, Operation::GenerateKey) => ParameterType::AesKeyGenParams,
3605            (Self::AesCbc, Operation::ImportKey) => ParameterType::None,
3606            (Self::AesCbc, Operation::ExportKey) => ParameterType::None,
3607            (Self::AesCbc, Operation::GetKeyLength) => ParameterType::AesDerivedKeyParams,
3608
3609            // <https://w3c.github.io/webcrypto/#aes-gcm-registration>
3610            (Self::AesGcm, Operation::Encrypt) => ParameterType::AesGcmParams,
3611            (Self::AesGcm, Operation::Decrypt) => ParameterType::AesGcmParams,
3612            (Self::AesGcm, Operation::GenerateKey) => ParameterType::AesKeyGenParams,
3613            (Self::AesGcm, Operation::ImportKey) => ParameterType::None,
3614            (Self::AesGcm, Operation::ExportKey) => ParameterType::None,
3615            (Self::AesGcm, Operation::GetKeyLength) => ParameterType::AesDerivedKeyParams,
3616
3617            // <https://w3c.github.io/webcrypto/#aes-kw-registration>
3618            (Self::AesKw, Operation::WrapKey) => ParameterType::None,
3619            (Self::AesKw, Operation::UnwrapKey) => ParameterType::None,
3620            (Self::AesKw, Operation::GenerateKey) => ParameterType::AesKeyGenParams,
3621            (Self::AesKw, Operation::ImportKey) => ParameterType::None,
3622            (Self::AesKw, Operation::ExportKey) => ParameterType::None,
3623            (Self::AesKw, Operation::GetKeyLength) => ParameterType::AesDerivedKeyParams,
3624
3625            // <https://w3c.github.io/webcrypto/#hmac-registration>
3626            (Self::Hmac, Operation::Sign) => ParameterType::None,
3627            (Self::Hmac, Operation::Verify) => ParameterType::None,
3628            (Self::Hmac, Operation::GenerateKey) => ParameterType::HmacKeyGenParams,
3629            (Self::Hmac, Operation::ImportKey) => ParameterType::HmacImportParams,
3630            (Self::Hmac, Operation::ExportKey) => ParameterType::None,
3631            (Self::Hmac, Operation::GetKeyLength) => ParameterType::HmacImportParams,
3632
3633            // <https://w3c.github.io/webcrypto/#sha-registration>
3634            (Self::Sha(_), Operation::Digest) => ParameterType::None,
3635
3636            // <https://w3c.github.io/webcrypto/#hkdf-registration>
3637            (Self::Hkdf, Operation::DeriveBits) => ParameterType::HkdfParams,
3638            (Self::Hkdf, Operation::ImportKey) => ParameterType::None,
3639            (Self::Hkdf, Operation::GetKeyLength) => ParameterType::None,
3640
3641            // <https://w3c.github.io/webcrypto/#pbkdf2-registration>
3642            (Self::Pbkdf2, Operation::DeriveBits) => ParameterType::Pbkdf2Params,
3643            (Self::Pbkdf2, Operation::ImportKey) => ParameterType::None,
3644            (Self::Pbkdf2, Operation::GetKeyLength) => ParameterType::None,
3645
3646            // <https://wicg.github.io/webcrypto-modern-algos/#ml-kem-registration>
3647            (Self::MlKem(_), Operation::Encapsulate) => ParameterType::None,
3648            (Self::MlKem(_), Operation::Decapsulate) => ParameterType::None,
3649            (Self::MlKem(_), Operation::GenerateKey) => ParameterType::None,
3650            (Self::MlKem(_), Operation::ImportKey) => ParameterType::None,
3651            (Self::MlKem(_), Operation::ExportKey) => ParameterType::None,
3652
3653            // <https://wicg.github.io/webcrypto-modern-algos/#ml-dsa-registration>
3654            (Self::MlDsa(_), Operation::Sign) => ParameterType::ContextParams,
3655            (Self::MlDsa(_), Operation::Verify) => ParameterType::ContextParams,
3656            (Self::MlDsa(_), Operation::GenerateKey) => ParameterType::None,
3657            (Self::MlDsa(_), Operation::ImportKey) => ParameterType::None,
3658            (Self::MlDsa(_), Operation::ExportKey) => ParameterType::None,
3659
3660            // <https://wicg.github.io/webcrypto-modern-algos/#aes-ocb-registration>
3661            (Self::AesOcb, Operation::Encrypt) => ParameterType::AeadParams,
3662            (Self::AesOcb, Operation::Decrypt) => ParameterType::AeadParams,
3663            (Self::AesOcb, Operation::GenerateKey) => ParameterType::AesKeyGenParams,
3664            (Self::AesOcb, Operation::ImportKey) => ParameterType::None,
3665            (Self::AesOcb, Operation::ExportKey) => ParameterType::None,
3666            (Self::AesOcb, Operation::GetKeyLength) => ParameterType::AesDerivedKeyParams,
3667
3668            // <https://wicg.github.io/webcrypto-modern-algos/#chacha20-poly1305-registration>
3669            (Self::ChaCha20Poly1305, Operation::Encrypt) => ParameterType::AeadParams,
3670            (Self::ChaCha20Poly1305, Operation::Decrypt) => ParameterType::AeadParams,
3671            (Self::ChaCha20Poly1305, Operation::GenerateKey) => ParameterType::None,
3672            (Self::ChaCha20Poly1305, Operation::ImportKey) => ParameterType::None,
3673            (Self::ChaCha20Poly1305, Operation::ExportKey) => ParameterType::None,
3674            (Self::ChaCha20Poly1305, Operation::GetKeyLength) => ParameterType::None,
3675
3676            // <https://wicg.github.io/webcrypto-modern-algos/#sha3-registration>
3677            (Self::Sha3(_), Operation::Digest) => ParameterType::None,
3678
3679            // <https://wicg.github.io/webcrypto-modern-algos/#cshake-registration>
3680            (Self::CShake(_), Operation::Digest) => ParameterType::CShakeParams,
3681
3682            // <https://wicg.github.io/webcrypto-modern-algos/#argon2-registration>
3683            (Self::Argon2(_), Operation::DeriveBits) => ParameterType::Argon2Params,
3684            (Self::Argon2(_), Operation::ImportKey) => ParameterType::None,
3685            (Self::Argon2(_), Operation::GetKeyLength) => ParameterType::None,
3686
3687            _ => {
3688                return Err(Error::NotSupported(Some(format!(
3689                    "{} does not support {} operation",
3690                    self.as_str(),
3691                    op.as_str()
3692                ))));
3693            },
3694        };
3695
3696        Ok(desired_type)
3697    }
3698}
3699
3700impl TryFrom<&str> for SupportedAlgorithm {
3701    type Error = Error;
3702
3703    fn try_from(value: &str) -> Result<Self, Self::Error> {
3704        match value {
3705            ALG_RSASSA_PKCS1_V1_5 => Ok(SupportedAlgorithm::RsassaPkcs1V1_5),
3706            ALG_RSA_PSS => Ok(SupportedAlgorithm::RsaPss),
3707            ALG_RSA_OAEP => Ok(SupportedAlgorithm::RsaOaep),
3708            ALG_ECDSA => Ok(SupportedAlgorithm::Ecdsa),
3709            ALG_ECDH => Ok(SupportedAlgorithm::Ecdh),
3710            ALG_ED25519 => Ok(SupportedAlgorithm::Ed25519),
3711            ALG_X25519 => Ok(SupportedAlgorithm::X25519),
3712            ALG_AES_CTR => Ok(SupportedAlgorithm::AesCtr),
3713            ALG_AES_CBC => Ok(SupportedAlgorithm::AesCbc),
3714            ALG_AES_GCM => Ok(SupportedAlgorithm::AesGcm),
3715            ALG_AES_KW => Ok(SupportedAlgorithm::AesKw),
3716            ALG_HMAC => Ok(SupportedAlgorithm::Hmac),
3717            ALG_SHA1 => Ok(SupportedAlgorithm::Sha(ShaAlgorithm::Sha1)),
3718            ALG_SHA256 => Ok(SupportedAlgorithm::Sha(ShaAlgorithm::Sha256)),
3719            ALG_SHA384 => Ok(SupportedAlgorithm::Sha(ShaAlgorithm::Sha384)),
3720            ALG_SHA512 => Ok(SupportedAlgorithm::Sha(ShaAlgorithm::Sha512)),
3721            ALG_HKDF => Ok(SupportedAlgorithm::Hkdf),
3722            ALG_PBKDF2 => Ok(SupportedAlgorithm::Pbkdf2),
3723            ALG_ML_KEM_512 => Ok(SupportedAlgorithm::MlKem(MlKemAlgorithm::MlKem512)),
3724            ALG_ML_KEM_768 => Ok(SupportedAlgorithm::MlKem(MlKemAlgorithm::MlKem768)),
3725            ALG_ML_KEM_1024 => Ok(SupportedAlgorithm::MlKem(MlKemAlgorithm::MlKem1024)),
3726            ALG_ML_DSA_44 => Ok(SupportedAlgorithm::MlDsa(MlDsaAlgorithm::MlDsa44)),
3727            ALG_ML_DSA_65 => Ok(SupportedAlgorithm::MlDsa(MlDsaAlgorithm::MlDsa65)),
3728            ALG_ML_DSA_87 => Ok(SupportedAlgorithm::MlDsa(MlDsaAlgorithm::MlDsa87)),
3729            ALG_AES_OCB => Ok(SupportedAlgorithm::AesOcb),
3730            ALG_CHACHA20_POLY1305 => Ok(SupportedAlgorithm::ChaCha20Poly1305),
3731            ALG_SHA3_256 => Ok(SupportedAlgorithm::Sha3(Sha3Algorithm::Sha3_256)),
3732            ALG_SHA3_384 => Ok(SupportedAlgorithm::Sha3(Sha3Algorithm::Sha3_384)),
3733            ALG_SHA3_512 => Ok(SupportedAlgorithm::Sha3(Sha3Algorithm::Sha3_512)),
3734            ALG_CSHAKE_128 => Ok(SupportedAlgorithm::CShake(CShakeAlgorithm::CShake128)),
3735            ALG_CSHAKE_256 => Ok(SupportedAlgorithm::CShake(CShakeAlgorithm::CShake256)),
3736            ALG_ARGON2D => Ok(SupportedAlgorithm::Argon2(Argon2Algorithm::Argon2D)),
3737            ALG_ARGON2I => Ok(SupportedAlgorithm::Argon2(Argon2Algorithm::Argon2I)),
3738            ALG_ARGON2ID => Ok(SupportedAlgorithm::Argon2(Argon2Algorithm::Argon2ID)),
3739            _ => Err(Error::NotSupported(Some(format!(
3740                "Unsupported algorithm: {}",
3741                value
3742            )))),
3743        }
3744    }
3745}
3746
3747enum ParameterType {
3748    None,
3749    RsaHashedKeyGenParams,
3750    RsaHashedImportParams,
3751    RsaPssParams,
3752    RsaOaepParams,
3753    EcdsaParams,
3754    EcKeyGenParams,
3755    EcKeyImportParams,
3756    EcdhKeyDeriveParams,
3757    AesCtrParams,
3758    AesKeyGenParams,
3759    AesDerivedKeyParams,
3760    AesCbcParams,
3761    AesGcmParams,
3762    HmacImportParams,
3763    HmacKeyGenParams,
3764    HkdfParams,
3765    Pbkdf2Params,
3766    ContextParams,
3767    AeadParams,
3768    CShakeParams,
3769    Argon2Params,
3770}
3771
3772/// The successful output of [`normalize_algorithm`], in form of an union type of (our "subtle"
3773/// binding of) IDL dictionary types.
3774///
3775/// <https://w3c.github.io/webcrypto/#algorithm-normalization-normalize-an-algorithm>
3776#[derive(Clone, MallocSizeOf)]
3777enum NormalizedAlgorithm {
3778    Algorithm(SubtleAlgorithm),
3779    RsaHashedKeyGenParams(SubtleRsaHashedKeyGenParams),
3780    RsaHashedImportParams(SubtleRsaHashedImportParams),
3781    RsaPssParams(SubtleRsaPssParams),
3782    RsaOaepParams(SubtleRsaOaepParams),
3783    EcdsaParams(SubtleEcdsaParams),
3784    EcKeyGenParams(SubtleEcKeyGenParams),
3785    EcKeyImportParams(SubtleEcKeyImportParams),
3786    EcdhKeyDeriveParams(SubtleEcdhKeyDeriveParams),
3787    AesCtrParams(SubtleAesCtrParams),
3788    AesKeyGenParams(SubtleAesKeyGenParams),
3789    AesDerivedKeyParams(SubtleAesDerivedKeyParams),
3790    AesCbcParams(SubtleAesCbcParams),
3791    AesGcmParams(SubtleAesGcmParams),
3792    HmacImportParams(SubtleHmacImportParams),
3793    HmacKeyGenParams(SubtleHmacKeyGenParams),
3794    HkdfParams(SubtleHkdfParams),
3795    Pbkdf2Params(SubtlePbkdf2Params),
3796    ContextParams(SubtleContextParams),
3797    AeadParams(SubtleAeadParams),
3798    CShakeParams(SubtleCShakeParams),
3799    Argon2Params(SubtleArgon2Params),
3800}
3801
3802/// <https://w3c.github.io/webcrypto/#algorithm-normalization-normalize-an-algorithm>
3803fn normalize_algorithm(
3804    cx: JSContext,
3805    op: Operation,
3806    alg: &AlgorithmIdentifier,
3807    can_gc: CanGc,
3808) -> Result<NormalizedAlgorithm, Error> {
3809    match alg {
3810        // If alg is an instance of a DOMString:
3811        ObjectOrString::String(name) => {
3812            // Return the result of running the normalize an algorithm algorithm, with the alg set
3813            // to a new Algorithm dictionary whose name attribute is alg, and with the op set to
3814            // op.
3815            let alg = Algorithm {
3816                name: name.to_owned(),
3817            };
3818            rooted!(in(*cx) let mut alg_value = UndefinedValue());
3819            alg.safe_to_jsval(cx, alg_value.handle_mut(), CanGc::note());
3820            let alg_obj = RootedTraceableBox::new(Heap::default());
3821            alg_obj.set(alg_value.to_object());
3822            normalize_algorithm(cx, op, &ObjectOrString::Object(alg_obj), can_gc)
3823        },
3824        // If alg is an object:
3825        ObjectOrString::Object(obj) => {
3826            // Step 1. Let registeredAlgorithms be the associative container stored at the op key
3827            // of supportedAlgorithms.
3828            // NOTE: The supportedAlgorithms and registeredAlgorithms are expressed as match arms
3829            // in Step 5.2 - Step 10.
3830
3831            // Stpe 2. Let initialAlg be the result of converting the ECMAScript object represented
3832            // by alg to the IDL dictionary type Algorithm, as defined by [WebIDL].
3833            // Step 3. If an error occurred, return the error and terminate this algorithm.
3834            rooted!(in(*cx) let value = ObjectValue(obj.get()));
3835            let initial_alg = dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
3836
3837            // Step 4. Let algName be the value of the name attribute of initialAlg.
3838            // Step 5.
3839            //     If registeredAlgorithms contains a key that is a case-insensitive string match
3840            //     for algName:
3841            //         Step 5.1. Set algName to the value of the matching key.
3842            //         Step 5.2. Let desiredType be the IDL dictionary type stored at algName in
3843            //         registeredAlgorithms.
3844            //     Otherwise:
3845            //         Return a new NotSupportedError and terminate this algorithm.
3846            let alg_name = SupportedAlgorithm::from_ignore_case(&initial_alg.name.str())?;
3847            let desired_type = alg_name.support(op)?;
3848
3849            // Step 6. Let normalizedAlgorithm be the result of converting the ECMAScript object
3850            // represented by alg to the IDL dictionary type desiredType, as defined by [WebIDL].
3851            // Step 7. Set the name attribute of normalizedAlgorithm to algName.
3852            // Step 8. If an error occurred, return the error and terminate this algorithm.
3853            // Step 9. Let dictionaries be a list consisting of the IDL dictionary type desiredType
3854            // and all of desiredType's inherited dictionaries, in order from least to most
3855            // derived.
3856            // Step 10. For each dictionary dictionary in dictionaries:
3857            //     Step 10.1. For each dictionary member member declared on dictionary, in order:
3858            //         Step 10.1.1. Let key be the identifier of member.
3859            //         Step 10.1.2. Let idlValue be the value of the dictionary member with key
3860            //         name of key on normalizedAlgorithm.
3861            //         Step 10.1.3.
3862            //             If member is of the type BufferSource and is present:
3863            //                 Set the dictionary member on normalizedAlgorithm with key name key
3864            //                 to the result of getting a copy of the bytes held by idlValue,
3865            //                 replacing the current value.
3866            //             If member is of the type HashAlgorithmIdentifier:
3867            //                 Set the dictionary member on normalizedAlgorithm with key name key
3868            //                 to the result of normalizing an algorithm, with the alg set to
3869            //                 idlValue and the op set to "digest".
3870            //             If member is of the type AlgorithmIdentifier:
3871            //                 Set the dictionary member on normalizedAlgorithm with key name key
3872            //                 to the result of normalizing an algorithm, with the alg set to
3873            //                 idlValue and the op set to the operation defined by the
3874            //                 specification that defines the algorithm identified by algName.
3875            //
3876            // NOTE: We do Step 7 first, by setting algName to the name attribute of the JS object
3877            // before IDL dictionary conversion, in order to simplify our implementation.
3878            rooted!(in(*cx) let mut alg_name_ptr = UndefinedValue());
3879            alg_name
3880                .as_str()
3881                .safe_to_jsval(cx, alg_name_ptr.handle_mut(), can_gc);
3882            set_dictionary_property(cx, obj.handle(), c"name", alg_name_ptr.handle())
3883                .map_err(|_| Error::JSFailed)?;
3884            let normalized_algorithm =
3885                NormalizedAlgorithm::from_object_value(cx, value.handle(), desired_type, can_gc)?;
3886
3887            // Step 11. Return normalizedAlgorithm.
3888            Ok(normalized_algorithm)
3889        },
3890    }
3891}
3892
3893impl NormalizedAlgorithm {
3894    /// Step 6, 8-10 of the "normalize an algorithm" algorithm
3895    /// <https://w3c.github.io/webcrypto/#algorithm-normalization-normalize-an-algorithm>. This
3896    /// function converts the ECMAScript object represented to a normalized algorithm of the IDL
3897    /// dictionary type desiredType.
3898    ///
3899    /// Step 6 and Step 8 is done by `dictionary_from_jsval`.
3900    ///
3901    /// Step 9 and Step 10 is done by the `From` and `TryFrom` trait implementations of the inner
3902    /// types (the structs with prefix "Subtle" in their name) of NormalizedAlgorithm.
3903    fn from_object_value(
3904        cx: JSContext,
3905        value: HandleValue,
3906        desired_type: ParameterType,
3907        can_gc: CanGc,
3908    ) -> Result<NormalizedAlgorithm, Error> {
3909        let normalized_algorithm = match desired_type {
3910            ParameterType::None => NormalizedAlgorithm::Algorithm(
3911                dictionary_from_jsval::<Algorithm>(cx, value, can_gc)?.into(),
3912            ),
3913            ParameterType::RsaHashedKeyGenParams => NormalizedAlgorithm::RsaHashedKeyGenParams(
3914                dictionary_from_jsval::<RootedTraceableBox<RsaHashedKeyGenParams>>(
3915                    cx, value, can_gc,
3916                )?
3917                .try_into()?,
3918            ),
3919            ParameterType::RsaHashedImportParams => NormalizedAlgorithm::RsaHashedImportParams(
3920                dictionary_from_jsval::<RootedTraceableBox<RsaHashedImportParams>>(
3921                    cx, value, can_gc,
3922                )?
3923                .try_into()?,
3924            ),
3925            ParameterType::RsaPssParams => NormalizedAlgorithm::RsaPssParams(
3926                dictionary_from_jsval::<RsaPssParams>(cx, value, can_gc)?.into(),
3927            ),
3928            ParameterType::RsaOaepParams => NormalizedAlgorithm::RsaOaepParams(
3929                dictionary_from_jsval::<RootedTraceableBox<RsaOaepParams>>(cx, value, can_gc)?
3930                    .into(),
3931            ),
3932            ParameterType::EcdsaParams => NormalizedAlgorithm::EcdsaParams(
3933                dictionary_from_jsval::<RootedTraceableBox<EcdsaParams>>(cx, value, can_gc)?
3934                    .try_into()?,
3935            ),
3936            ParameterType::EcKeyGenParams => NormalizedAlgorithm::EcKeyGenParams(
3937                dictionary_from_jsval::<EcKeyGenParams>(cx, value, can_gc)?.into(),
3938            ),
3939            ParameterType::EcKeyImportParams => NormalizedAlgorithm::EcKeyImportParams(
3940                dictionary_from_jsval::<EcKeyImportParams>(cx, value, can_gc)?.into(),
3941            ),
3942            ParameterType::EcdhKeyDeriveParams => NormalizedAlgorithm::EcdhKeyDeriveParams(
3943                dictionary_from_jsval::<EcdhKeyDeriveParams>(cx, value, can_gc)?.into(),
3944            ),
3945            ParameterType::AesCtrParams => NormalizedAlgorithm::AesCtrParams(
3946                dictionary_from_jsval::<RootedTraceableBox<AesCtrParams>>(cx, value, can_gc)?
3947                    .into(),
3948            ),
3949            ParameterType::AesKeyGenParams => NormalizedAlgorithm::AesKeyGenParams(
3950                dictionary_from_jsval::<AesKeyGenParams>(cx, value, can_gc)?.into(),
3951            ),
3952            ParameterType::AesDerivedKeyParams => NormalizedAlgorithm::AesDerivedKeyParams(
3953                dictionary_from_jsval::<AesDerivedKeyParams>(cx, value, can_gc)?.into(),
3954            ),
3955            ParameterType::AesCbcParams => NormalizedAlgorithm::AesCbcParams(
3956                dictionary_from_jsval::<RootedTraceableBox<AesCbcParams>>(cx, value, can_gc)?
3957                    .into(),
3958            ),
3959            ParameterType::AesGcmParams => NormalizedAlgorithm::AesGcmParams(
3960                dictionary_from_jsval::<RootedTraceableBox<AesGcmParams>>(cx, value, can_gc)?
3961                    .into(),
3962            ),
3963            ParameterType::HmacImportParams => NormalizedAlgorithm::HmacImportParams(
3964                dictionary_from_jsval::<RootedTraceableBox<HmacImportParams>>(cx, value, can_gc)?
3965                    .try_into()?,
3966            ),
3967            ParameterType::HmacKeyGenParams => NormalizedAlgorithm::HmacKeyGenParams(
3968                dictionary_from_jsval::<RootedTraceableBox<HmacKeyGenParams>>(cx, value, can_gc)?
3969                    .try_into()?,
3970            ),
3971            ParameterType::HkdfParams => NormalizedAlgorithm::HkdfParams(
3972                dictionary_from_jsval::<RootedTraceableBox<HkdfParams>>(cx, value, can_gc)?
3973                    .try_into()?,
3974            ),
3975            ParameterType::Pbkdf2Params => NormalizedAlgorithm::Pbkdf2Params(
3976                dictionary_from_jsval::<RootedTraceableBox<Pbkdf2Params>>(cx, value, can_gc)?
3977                    .try_into()?,
3978            ),
3979            ParameterType::ContextParams => NormalizedAlgorithm::ContextParams(
3980                dictionary_from_jsval::<RootedTraceableBox<ContextParams>>(cx, value, can_gc)?
3981                    .into(),
3982            ),
3983            ParameterType::AeadParams => NormalizedAlgorithm::AeadParams(
3984                dictionary_from_jsval::<RootedTraceableBox<AeadParams>>(cx, value, can_gc)?.into(),
3985            ),
3986            ParameterType::CShakeParams => NormalizedAlgorithm::CShakeParams(
3987                dictionary_from_jsval::<RootedTraceableBox<CShakeParams>>(cx, value, can_gc)?
3988                    .into(),
3989            ),
3990            ParameterType::Argon2Params => NormalizedAlgorithm::Argon2Params(
3991                dictionary_from_jsval::<RootedTraceableBox<Argon2Params>>(cx, value, can_gc)?
3992                    .into(),
3993            ),
3994        };
3995
3996        Ok(normalized_algorithm)
3997    }
3998
3999    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
4000    fn name(&self) -> &str {
4001        match self {
4002            NormalizedAlgorithm::Algorithm(algo) => &algo.name,
4003            NormalizedAlgorithm::RsaHashedKeyGenParams(algo) => &algo.name,
4004            NormalizedAlgorithm::RsaHashedImportParams(algo) => &algo.name,
4005            NormalizedAlgorithm::RsaPssParams(algo) => &algo.name,
4006            NormalizedAlgorithm::RsaOaepParams(algo) => &algo.name,
4007            NormalizedAlgorithm::EcdsaParams(algo) => &algo.name,
4008            NormalizedAlgorithm::EcKeyGenParams(algo) => &algo.name,
4009            NormalizedAlgorithm::EcKeyImportParams(algo) => &algo.name,
4010            NormalizedAlgorithm::EcdhKeyDeriveParams(algo) => &algo.name,
4011            NormalizedAlgorithm::AesCtrParams(algo) => &algo.name,
4012            NormalizedAlgorithm::AesKeyGenParams(algo) => &algo.name,
4013            NormalizedAlgorithm::AesDerivedKeyParams(algo) => &algo.name,
4014            NormalizedAlgorithm::AesCbcParams(algo) => &algo.name,
4015            NormalizedAlgorithm::AesGcmParams(algo) => &algo.name,
4016            NormalizedAlgorithm::HmacImportParams(algo) => &algo.name,
4017            NormalizedAlgorithm::HmacKeyGenParams(algo) => &algo.name,
4018            NormalizedAlgorithm::HkdfParams(algo) => &algo.name,
4019            NormalizedAlgorithm::Pbkdf2Params(algo) => &algo.name,
4020            NormalizedAlgorithm::ContextParams(algo) => &algo.name,
4021            NormalizedAlgorithm::AeadParams(algo) => &algo.name,
4022            NormalizedAlgorithm::CShakeParams(algo) => &algo.name,
4023            NormalizedAlgorithm::Argon2Params(algo) => &algo.name,
4024        }
4025    }
4026
4027    fn encrypt(&self, key: &CryptoKey, plaintext: &[u8]) -> Result<Vec<u8>, Error> {
4028        match (self.name(), self) {
4029            (ALG_RSA_OAEP, NormalizedAlgorithm::RsaOaepParams(algo)) => {
4030                rsa_oaep_operation::encrypt(algo, key, plaintext)
4031            },
4032            (ALG_AES_CTR, NormalizedAlgorithm::AesCtrParams(algo)) => {
4033                aes_ctr_operation::encrypt(algo, key, plaintext)
4034            },
4035            (ALG_AES_CBC, NormalizedAlgorithm::AesCbcParams(algo)) => {
4036                aes_cbc_operation::encrypt(algo, key, plaintext)
4037            },
4038            (ALG_AES_GCM, NormalizedAlgorithm::AesGcmParams(algo)) => {
4039                aes_gcm_operation::encrypt(algo, key, plaintext)
4040            },
4041            (ALG_AES_OCB, NormalizedAlgorithm::AeadParams(algo)) => {
4042                aes_ocb_operation::encrypt(algo, key, plaintext)
4043            },
4044            (ALG_CHACHA20_POLY1305, NormalizedAlgorithm::AeadParams(algo)) => {
4045                chacha20_poly1305_operation::encrypt(algo, key, plaintext)
4046            },
4047            _ => Err(Error::NotSupported(None)),
4048        }
4049    }
4050
4051    fn decrypt(&self, key: &CryptoKey, ciphertext: &[u8]) -> Result<Vec<u8>, Error> {
4052        match (self.name(), self) {
4053            (ALG_RSA_OAEP, NormalizedAlgorithm::RsaOaepParams(algo)) => {
4054                rsa_oaep_operation::decrypt(algo, key, ciphertext)
4055            },
4056            (ALG_AES_CTR, NormalizedAlgorithm::AesCtrParams(algo)) => {
4057                aes_ctr_operation::decrypt(algo, key, ciphertext)
4058            },
4059            (ALG_AES_CBC, NormalizedAlgorithm::AesCbcParams(algo)) => {
4060                aes_cbc_operation::decrypt(algo, key, ciphertext)
4061            },
4062            (ALG_AES_GCM, NormalizedAlgorithm::AesGcmParams(algo)) => {
4063                aes_gcm_operation::decrypt(algo, key, ciphertext)
4064            },
4065            (ALG_AES_OCB, NormalizedAlgorithm::AeadParams(algo)) => {
4066                aes_ocb_operation::decrypt(algo, key, ciphertext)
4067            },
4068            (ALG_CHACHA20_POLY1305, NormalizedAlgorithm::AeadParams(algo)) => {
4069                chacha20_poly1305_operation::decrypt(algo, key, ciphertext)
4070            },
4071            _ => Err(Error::NotSupported(None)),
4072        }
4073    }
4074
4075    fn sign(&self, key: &CryptoKey, message: &[u8]) -> Result<Vec<u8>, Error> {
4076        match (self.name(), self) {
4077            (ALG_RSASSA_PKCS1_V1_5, NormalizedAlgorithm::Algorithm(_algo)) => {
4078                rsassa_pkcs1_v1_5_operation::sign(key, message)
4079            },
4080            (ALG_RSA_PSS, NormalizedAlgorithm::RsaPssParams(algo)) => {
4081                rsa_pss_operation::sign(algo, key, message)
4082            },
4083            (ALG_ECDSA, NormalizedAlgorithm::EcdsaParams(algo)) => {
4084                ecdsa_operation::sign(algo, key, message)
4085            },
4086            (ALG_ED25519, NormalizedAlgorithm::Algorithm(_algo)) => {
4087                ed25519_operation::sign(key, message)
4088            },
4089            (ALG_HMAC, NormalizedAlgorithm::Algorithm(_algo)) => hmac_operation::sign(key, message),
4090            (
4091                ALG_ML_DSA_44 | ALG_ML_DSA_65 | ALG_ML_DSA_87,
4092                NormalizedAlgorithm::ContextParams(algo),
4093            ) => ml_dsa_operation::sign(algo, key, message),
4094            _ => Err(Error::NotSupported(None)),
4095        }
4096    }
4097
4098    fn verify(&self, key: &CryptoKey, message: &[u8], signature: &[u8]) -> Result<bool, Error> {
4099        match (self.name(), self) {
4100            (ALG_RSASSA_PKCS1_V1_5, NormalizedAlgorithm::Algorithm(_algo)) => {
4101                rsassa_pkcs1_v1_5_operation::verify(key, message, signature)
4102            },
4103            (ALG_RSA_PSS, NormalizedAlgorithm::RsaPssParams(algo)) => {
4104                rsa_pss_operation::verify(algo, key, message, signature)
4105            },
4106            (ALG_ECDSA, NormalizedAlgorithm::EcdsaParams(algo)) => {
4107                ecdsa_operation::verify(algo, key, message, signature)
4108            },
4109            (ALG_ED25519, NormalizedAlgorithm::Algorithm(_algo)) => {
4110                ed25519_operation::verify(key, message, signature)
4111            },
4112            (ALG_HMAC, NormalizedAlgorithm::Algorithm(_algo)) => {
4113                hmac_operation::verify(key, message, signature)
4114            },
4115            (
4116                ALG_ML_DSA_44 | ALG_ML_DSA_65 | ALG_ML_DSA_87,
4117                NormalizedAlgorithm::ContextParams(algo),
4118            ) => ml_dsa_operation::verify(algo, key, message, signature),
4119            _ => Err(Error::NotSupported(None)),
4120        }
4121    }
4122
4123    fn digest(&self, message: &[u8]) -> Result<Vec<u8>, Error> {
4124        match (self.name(), self) {
4125            (ALG_SHA1, NormalizedAlgorithm::Algorithm(algo)) => {
4126                sha_operation::digest(algo, message)
4127            },
4128            (ALG_SHA256, NormalizedAlgorithm::Algorithm(algo)) => {
4129                sha_operation::digest(algo, message)
4130            },
4131            (ALG_SHA384, NormalizedAlgorithm::Algorithm(algo)) => {
4132                sha_operation::digest(algo, message)
4133            },
4134            (ALG_SHA512, NormalizedAlgorithm::Algorithm(algo)) => {
4135                sha_operation::digest(algo, message)
4136            },
4137            (ALG_SHA3_256, NormalizedAlgorithm::Algorithm(algo)) => {
4138                sha3_operation::digest(algo, message)
4139            },
4140            (ALG_SHA3_384, NormalizedAlgorithm::Algorithm(algo)) => {
4141                sha3_operation::digest(algo, message)
4142            },
4143            (ALG_SHA3_512, NormalizedAlgorithm::Algorithm(algo)) => {
4144                sha3_operation::digest(algo, message)
4145            },
4146            (ALG_CSHAKE_128, NormalizedAlgorithm::CShakeParams(algo)) => {
4147                cshake_operation::digest(algo, message)
4148            },
4149            (ALG_CSHAKE_256, NormalizedAlgorithm::CShakeParams(algo)) => {
4150                cshake_operation::digest(algo, message)
4151            },
4152            _ => Err(Error::NotSupported(None)),
4153        }
4154    }
4155
4156    fn generate_key(
4157        &self,
4158        global: &GlobalScope,
4159        extractable: bool,
4160        usages: Vec<KeyUsage>,
4161        can_gc: CanGc,
4162    ) -> Result<CryptoKeyOrCryptoKeyPair, Error> {
4163        match (self.name(), self) {
4164            (ALG_RSASSA_PKCS1_V1_5, NormalizedAlgorithm::RsaHashedKeyGenParams(algo)) => {
4165                rsassa_pkcs1_v1_5_operation::generate_key(global, algo, extractable, usages, can_gc)
4166                    .map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
4167            },
4168            (ALG_RSA_PSS, NormalizedAlgorithm::RsaHashedKeyGenParams(algo)) => {
4169                rsa_pss_operation::generate_key(global, algo, extractable, usages, can_gc)
4170                    .map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
4171            },
4172            (ALG_RSA_OAEP, NormalizedAlgorithm::RsaHashedKeyGenParams(algo)) => {
4173                rsa_oaep_operation::generate_key(global, algo, extractable, usages, can_gc)
4174                    .map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
4175            },
4176            (ALG_ECDSA, NormalizedAlgorithm::EcKeyGenParams(algo)) => {
4177                ecdsa_operation::generate_key(global, algo, extractable, usages, can_gc)
4178                    .map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
4179            },
4180            (ALG_ECDH, NormalizedAlgorithm::EcKeyGenParams(algo)) => {
4181                ecdh_operation::generate_key(global, algo, extractable, usages, can_gc)
4182                    .map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
4183            },
4184            (ALG_ED25519, NormalizedAlgorithm::Algorithm(_algo)) => {
4185                ed25519_operation::generate_key(global, extractable, usages, can_gc)
4186                    .map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
4187            },
4188            (ALG_X25519, NormalizedAlgorithm::Algorithm(_algo)) => {
4189                x25519_operation::generate_key(global, extractable, usages, can_gc)
4190                    .map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
4191            },
4192            (ALG_AES_CTR, NormalizedAlgorithm::AesKeyGenParams(algo)) => {
4193                aes_ctr_operation::generate_key(global, algo, extractable, usages, can_gc)
4194                    .map(CryptoKeyOrCryptoKeyPair::CryptoKey)
4195            },
4196            (ALG_AES_CBC, NormalizedAlgorithm::AesKeyGenParams(algo)) => {
4197                aes_cbc_operation::generate_key(global, algo, extractable, usages, can_gc)
4198                    .map(CryptoKeyOrCryptoKeyPair::CryptoKey)
4199            },
4200            (ALG_AES_GCM, NormalizedAlgorithm::AesKeyGenParams(algo)) => {
4201                aes_gcm_operation::generate_key(global, algo, extractable, usages, can_gc)
4202                    .map(CryptoKeyOrCryptoKeyPair::CryptoKey)
4203            },
4204            (ALG_AES_KW, NormalizedAlgorithm::AesKeyGenParams(algo)) => {
4205                aes_kw_operation::generate_key(global, algo, extractable, usages, can_gc)
4206                    .map(CryptoKeyOrCryptoKeyPair::CryptoKey)
4207            },
4208            (ALG_HMAC, NormalizedAlgorithm::HmacKeyGenParams(algo)) => {
4209                hmac_operation::generate_key(global, algo, extractable, usages, can_gc)
4210                    .map(CryptoKeyOrCryptoKeyPair::CryptoKey)
4211            },
4212            (
4213                ALG_ML_KEM_512 | ALG_ML_KEM_768 | ALG_ML_KEM_1024,
4214                NormalizedAlgorithm::Algorithm(algo),
4215            ) => ml_kem_operation::generate_key(global, algo, extractable, usages, can_gc)
4216                .map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair),
4217            (
4218                ALG_ML_DSA_44 | ALG_ML_DSA_65 | ALG_ML_DSA_87,
4219                NormalizedAlgorithm::Algorithm(algo),
4220            ) => ml_dsa_operation::generate_key(global, algo, extractable, usages, can_gc)
4221                .map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair),
4222            (ALG_AES_OCB, NormalizedAlgorithm::AesKeyGenParams(algo)) => {
4223                aes_ocb_operation::generate_key(global, algo, extractable, usages, can_gc)
4224                    .map(CryptoKeyOrCryptoKeyPair::CryptoKey)
4225            },
4226            (ALG_CHACHA20_POLY1305, NormalizedAlgorithm::Algorithm(_algo)) => {
4227                chacha20_poly1305_operation::generate_key(global, extractable, usages, can_gc)
4228                    .map(CryptoKeyOrCryptoKeyPair::CryptoKey)
4229            },
4230            _ => Err(Error::NotSupported(None)),
4231        }
4232    }
4233
4234    fn derive_bits(&self, key: &CryptoKey, length: Option<u32>) -> Result<Vec<u8>, Error> {
4235        match (self.name(), self) {
4236            (ALG_ECDH, NormalizedAlgorithm::EcdhKeyDeriveParams(algo)) => {
4237                ecdh_operation::derive_bits(algo, key, length)
4238            },
4239            (ALG_X25519, NormalizedAlgorithm::EcdhKeyDeriveParams(algo)) => {
4240                x25519_operation::derive_bits(algo, key, length)
4241            },
4242            (ALG_HKDF, NormalizedAlgorithm::HkdfParams(algo)) => {
4243                hkdf_operation::derive_bits(algo, key, length)
4244            },
4245            (ALG_PBKDF2, NormalizedAlgorithm::Pbkdf2Params(algo)) => {
4246                pbkdf2_operation::derive_bits(algo, key, length)
4247            },
4248            (ALG_ARGON2D, NormalizedAlgorithm::Argon2Params(algo)) => {
4249                argon2_operation::derive_bits(algo, key, length)
4250            },
4251            (ALG_ARGON2I, NormalizedAlgorithm::Argon2Params(algo)) => {
4252                argon2_operation::derive_bits(algo, key, length)
4253            },
4254            (ALG_ARGON2ID, NormalizedAlgorithm::Argon2Params(algo)) => {
4255                argon2_operation::derive_bits(algo, key, length)
4256            },
4257            _ => Err(Error::NotSupported(None)),
4258        }
4259    }
4260
4261    fn import_key(
4262        &self,
4263        global: &GlobalScope,
4264        format: KeyFormat,
4265        key_data: &[u8],
4266        extractable: bool,
4267        usages: Vec<KeyUsage>,
4268        can_gc: CanGc,
4269    ) -> Result<DomRoot<CryptoKey>, Error> {
4270        match (self.name(), self) {
4271            (ALG_RSASSA_PKCS1_V1_5, NormalizedAlgorithm::RsaHashedImportParams(algo)) => {
4272                rsassa_pkcs1_v1_5_operation::import_key(
4273                    global,
4274                    algo,
4275                    format,
4276                    key_data,
4277                    extractable,
4278                    usages,
4279                    can_gc,
4280                )
4281            },
4282            (ALG_RSA_PSS, NormalizedAlgorithm::RsaHashedImportParams(algo)) => {
4283                rsa_pss_operation::import_key(
4284                    global,
4285                    algo,
4286                    format,
4287                    key_data,
4288                    extractable,
4289                    usages,
4290                    can_gc,
4291                )
4292            },
4293            (ALG_RSA_OAEP, NormalizedAlgorithm::RsaHashedImportParams(algo)) => {
4294                rsa_oaep_operation::import_key(
4295                    global,
4296                    algo,
4297                    format,
4298                    key_data,
4299                    extractable,
4300                    usages,
4301                    can_gc,
4302                )
4303            },
4304            (ALG_ECDSA, NormalizedAlgorithm::EcKeyImportParams(algo)) => {
4305                ecdsa_operation::import_key(
4306                    global,
4307                    algo,
4308                    format,
4309                    key_data,
4310                    extractable,
4311                    usages,
4312                    can_gc,
4313                )
4314            },
4315            (ALG_ECDH, NormalizedAlgorithm::EcKeyImportParams(algo)) => ecdh_operation::import_key(
4316                global,
4317                algo,
4318                format,
4319                key_data,
4320                extractable,
4321                usages,
4322                can_gc,
4323            ),
4324            (ALG_ED25519, NormalizedAlgorithm::Algorithm(_algo)) => {
4325                ed25519_operation::import_key(global, format, key_data, extractable, usages, can_gc)
4326            },
4327            (ALG_X25519, NormalizedAlgorithm::Algorithm(_algo)) => {
4328                x25519_operation::import_key(global, format, key_data, extractable, usages, can_gc)
4329            },
4330            (ALG_AES_CTR, NormalizedAlgorithm::Algorithm(_algo)) => {
4331                aes_ctr_operation::import_key(global, format, key_data, extractable, usages, can_gc)
4332            },
4333            (ALG_AES_CBC, NormalizedAlgorithm::Algorithm(_algo)) => {
4334                aes_cbc_operation::import_key(global, format, key_data, extractable, usages, can_gc)
4335            },
4336            (ALG_AES_GCM, NormalizedAlgorithm::Algorithm(_algo)) => {
4337                aes_gcm_operation::import_key(global, format, key_data, extractable, usages, can_gc)
4338            },
4339            (ALG_AES_KW, NormalizedAlgorithm::Algorithm(_algo)) => {
4340                aes_kw_operation::import_key(global, format, key_data, extractable, usages, can_gc)
4341            },
4342            (ALG_HMAC, NormalizedAlgorithm::HmacImportParams(algo)) => hmac_operation::import_key(
4343                global,
4344                algo,
4345                format,
4346                key_data,
4347                extractable,
4348                usages,
4349                can_gc,
4350            ),
4351            (ALG_HKDF, NormalizedAlgorithm::Algorithm(_algo)) => {
4352                hkdf_operation::import_key(global, format, key_data, extractable, usages, can_gc)
4353            },
4354            (ALG_PBKDF2, NormalizedAlgorithm::Algorithm(_algo)) => {
4355                pbkdf2_operation::import_key(global, format, key_data, extractable, usages, can_gc)
4356            },
4357            (
4358                ALG_ML_KEM_512 | ALG_ML_KEM_768 | ALG_ML_KEM_1024,
4359                NormalizedAlgorithm::Algorithm(algo),
4360            ) => ml_kem_operation::import_key(
4361                global,
4362                algo,
4363                format,
4364                key_data,
4365                extractable,
4366                usages,
4367                can_gc,
4368            ),
4369            (
4370                ALG_ML_DSA_44 | ALG_ML_DSA_65 | ALG_ML_DSA_87,
4371                NormalizedAlgorithm::Algorithm(algo),
4372            ) => ml_dsa_operation::import_key(
4373                global,
4374                algo,
4375                format,
4376                key_data,
4377                extractable,
4378                usages,
4379                can_gc,
4380            ),
4381            (ALG_AES_OCB, NormalizedAlgorithm::Algorithm(_algo)) => {
4382                aes_ocb_operation::import_key(global, format, key_data, extractable, usages, can_gc)
4383            },
4384            (ALG_CHACHA20_POLY1305, NormalizedAlgorithm::Algorithm(_algo)) => {
4385                chacha20_poly1305_operation::import_key(
4386                    global,
4387                    format,
4388                    key_data,
4389                    extractable,
4390                    usages,
4391                    can_gc,
4392                )
4393            },
4394            (ALG_ARGON2D, NormalizedAlgorithm::Algorithm(algo)) => argon2_operation::import_key(
4395                global,
4396                algo,
4397                format,
4398                key_data,
4399                extractable,
4400                usages,
4401                can_gc,
4402            ),
4403            (ALG_ARGON2I, NormalizedAlgorithm::Algorithm(algo)) => argon2_operation::import_key(
4404                global,
4405                algo,
4406                format,
4407                key_data,
4408                extractable,
4409                usages,
4410                can_gc,
4411            ),
4412            (ALG_ARGON2ID, NormalizedAlgorithm::Algorithm(algo)) => argon2_operation::import_key(
4413                global,
4414                algo,
4415                format,
4416                key_data,
4417                extractable,
4418                usages,
4419                can_gc,
4420            ),
4421            _ => Err(Error::NotSupported(None)),
4422        }
4423    }
4424
4425    fn wrap_key(&self, key: &CryptoKey, plaintext: &[u8]) -> Result<Vec<u8>, Error> {
4426        match (self.name(), self) {
4427            (ALG_AES_KW, NormalizedAlgorithm::Algorithm(_algo)) => {
4428                aes_kw_operation::wrap_key(key, plaintext)
4429            },
4430            _ => Err(Error::NotSupported(None)),
4431        }
4432    }
4433
4434    fn unwrap_key(&self, key: &CryptoKey, ciphertext: &[u8]) -> Result<Vec<u8>, Error> {
4435        match (self.name(), self) {
4436            (ALG_AES_KW, NormalizedAlgorithm::Algorithm(_algo)) => {
4437                aes_kw_operation::unwrap_key(key, ciphertext)
4438            },
4439            _ => Err(Error::NotSupported(None)),
4440        }
4441    }
4442
4443    fn get_key_length(&self) -> Result<Option<u32>, Error> {
4444        match (self.name(), self) {
4445            (ALG_AES_CTR, NormalizedAlgorithm::AesDerivedKeyParams(algo)) => {
4446                aes_ctr_operation::get_key_length(algo)
4447            },
4448            (ALG_AES_CBC, NormalizedAlgorithm::AesDerivedKeyParams(algo)) => {
4449                aes_cbc_operation::get_key_length(algo)
4450            },
4451            (ALG_AES_GCM, NormalizedAlgorithm::AesDerivedKeyParams(algo)) => {
4452                aes_gcm_operation::get_key_length(algo)
4453            },
4454            (ALG_AES_KW, NormalizedAlgorithm::AesDerivedKeyParams(algo)) => {
4455                aes_kw_operation::get_key_length(algo)
4456            },
4457            (ALG_HMAC, NormalizedAlgorithm::HmacImportParams(algo)) => {
4458                hmac_operation::get_key_length(algo)
4459            },
4460            (ALG_HKDF, NormalizedAlgorithm::Algorithm(_algo)) => hkdf_operation::get_key_length(),
4461            (ALG_PBKDF2, NormalizedAlgorithm::Algorithm(_algo)) => {
4462                pbkdf2_operation::get_key_length()
4463            },
4464            (ALG_AES_OCB, NormalizedAlgorithm::AesDerivedKeyParams(algo)) => {
4465                aes_ocb_operation::get_key_length(algo)
4466            },
4467            (ALG_CHACHA20_POLY1305, NormalizedAlgorithm::Algorithm(_algo)) => {
4468                chacha20_poly1305_operation::get_key_length()
4469            },
4470            (ALG_ARGON2D, NormalizedAlgorithm::Algorithm(_algo)) => {
4471                argon2_operation::get_key_length()
4472            },
4473            (ALG_ARGON2I, NormalizedAlgorithm::Algorithm(_algo)) => {
4474                argon2_operation::get_key_length()
4475            },
4476            (ALG_ARGON2ID, NormalizedAlgorithm::Algorithm(_algo)) => {
4477                argon2_operation::get_key_length()
4478            },
4479            _ => Err(Error::NotSupported(None)),
4480        }
4481    }
4482
4483    fn encapsulate(&self, key: &CryptoKey) -> Result<SubtleEncapsulatedBits, Error> {
4484        match (self.name(), self) {
4485            (
4486                ALG_ML_KEM_512 | ALG_ML_KEM_768 | ALG_ML_KEM_1024,
4487                NormalizedAlgorithm::Algorithm(algo),
4488            ) => ml_kem_operation::encapsulate(algo, key),
4489            _ => Err(Error::NotSupported(None)),
4490        }
4491    }
4492
4493    fn decapsulate(&self, key: &CryptoKey, ciphertext: &[u8]) -> Result<Vec<u8>, Error> {
4494        match (self.name(), self) {
4495            (
4496                ALG_ML_KEM_512 | ALG_ML_KEM_768 | ALG_ML_KEM_1024,
4497                NormalizedAlgorithm::Algorithm(algo),
4498            ) => ml_kem_operation::decapsulate(algo, key, ciphertext),
4499            _ => Err(Error::NotSupported(None)),
4500        }
4501    }
4502}
4503
4504/// Return the result of performing the export key operation specified by the [[algorithm]]
4505/// internal slot of key using key and format.
4506///
4507/// According to the WebCrypto API spec, the export key operation does not rely on the algorithm
4508/// normalization, We create this helper function to minic the functions of NormalizedAlgorithm
4509/// for export key operation.
4510fn perform_export_key_operation(format: KeyFormat, key: &CryptoKey) -> Result<ExportedKey, Error> {
4511    match key.algorithm().name() {
4512        ALG_RSASSA_PKCS1_V1_5 => rsassa_pkcs1_v1_5_operation::export_key(format, key),
4513        ALG_RSA_PSS => rsa_pss_operation::export_key(format, key),
4514        ALG_RSA_OAEP => rsa_oaep_operation::export_key(format, key),
4515        ALG_ECDSA => ecdsa_operation::export_key(format, key),
4516        ALG_ECDH => ecdh_operation::export_key(format, key),
4517        ALG_ED25519 => ed25519_operation::export_key(format, key),
4518        ALG_X25519 => x25519_operation::export_key(format, key),
4519        ALG_AES_CTR => aes_ctr_operation::export_key(format, key),
4520        ALG_AES_CBC => aes_cbc_operation::export_key(format, key),
4521        ALG_AES_GCM => aes_gcm_operation::export_key(format, key),
4522        ALG_AES_KW => aes_kw_operation::export_key(format, key),
4523        ALG_HMAC => hmac_operation::export_key(format, key),
4524        ALG_ML_KEM_512 | ALG_ML_KEM_768 | ALG_ML_KEM_1024 => {
4525            ml_kem_operation::export_key(format, key)
4526        },
4527        ALG_ML_DSA_44 | ALG_ML_DSA_65 | ALG_ML_DSA_87 => ml_dsa_operation::export_key(format, key),
4528        ALG_AES_OCB => aes_ocb_operation::export_key(format, key),
4529        ALG_CHACHA20_POLY1305 => chacha20_poly1305_operation::export_key(format, key),
4530        _ => Err(Error::NotSupported(None)),
4531    }
4532}