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(c"The keyData type does not match the format".to_owned()),
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(c"The keyData type does not match the format".to_owned()),
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 SafeToJSValConvertible for SubtleKeyAlgorithm {
2216    fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
2217        let dictionary = KeyAlgorithm {
2218            name: self.name.clone().into(),
2219        };
2220        dictionary.safe_to_jsval(cx, rval, can_gc);
2221    }
2222}
2223
2224/// <https://w3c.github.io/webcrypto/#dfn-RsaHashedKeyGenParams>
2225#[derive(Clone, MallocSizeOf)]
2226pub(crate) struct SubtleRsaHashedKeyGenParams {
2227    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2228    name: String,
2229
2230    /// <https://w3c.github.io/webcrypto/#dfn-RsaKeyGenParams-modulusLength>
2231    modulus_length: u32,
2232
2233    /// <https://w3c.github.io/webcrypto/#dfn-RsaKeyGenParams-publicExponent>
2234    public_exponent: Vec<u8>,
2235
2236    /// <https://w3c.github.io/webcrypto/#dfn-RsaHashedKeyGenParams-hash>
2237    hash: Box<NormalizedAlgorithm>,
2238}
2239
2240impl TryFrom<RootedTraceableBox<RsaHashedKeyGenParams>> for SubtleRsaHashedKeyGenParams {
2241    type Error = Error;
2242
2243    fn try_from(value: RootedTraceableBox<RsaHashedKeyGenParams>) -> Result<Self, Self::Error> {
2244        let cx = GlobalScope::get_cx();
2245        Ok(SubtleRsaHashedKeyGenParams {
2246            name: value.parent.parent.name.to_string(),
2247            modulus_length: value.parent.modulusLength,
2248            public_exponent: value.parent.publicExponent.to_vec(),
2249            hash: Box::new(normalize_algorithm(
2250                cx,
2251                Operation::Digest,
2252                &value.hash,
2253                CanGc::note(),
2254            )?),
2255        })
2256    }
2257}
2258
2259/// <https://w3c.github.io/webcrypto/#dfn-RsaHashedKeyAlgorithm>
2260#[derive(Clone, MallocSizeOf)]
2261pub(crate) struct SubtleRsaHashedKeyAlgorithm {
2262    /// <https://w3c.github.io/webcrypto/#dom-keyalgorithm-name>
2263    name: String,
2264
2265    /// <https://w3c.github.io/webcrypto/#dfn-RsaKeyAlgorithm-modulusLength>
2266    modulus_length: u32,
2267
2268    /// <https://w3c.github.io/webcrypto/#dfn-RsaKeyAlgorithm-publicExponent>
2269    public_exponent: Vec<u8>,
2270
2271    /// <https://w3c.github.io/webcrypto/#dfn-RsaHashedKeyAlgorithm-hash>
2272    hash: Box<NormalizedAlgorithm>,
2273}
2274
2275impl SafeToJSValConvertible for SubtleRsaHashedKeyAlgorithm {
2276    fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
2277        rooted!(in(*cx) let mut js_object = ptr::null_mut::<JSObject>());
2278        let public_exponent =
2279            create_buffer_source(cx, &self.public_exponent, js_object.handle_mut(), can_gc)
2280                .expect("Fail to convert publicExponent to Uint8Array");
2281        let key_algorithm = KeyAlgorithm {
2282            name: self.name.clone().into(),
2283        };
2284        let rsa_key_algorithm = RootedTraceableBox::new(RsaKeyAlgorithm {
2285            parent: key_algorithm,
2286            modulusLength: self.modulus_length,
2287            publicExponent: public_exponent,
2288        });
2289        let rsa_hashed_key_algorithm = RootedTraceableBox::new(RsaHashedKeyAlgorithm {
2290            parent: rsa_key_algorithm,
2291            hash: KeyAlgorithm {
2292                name: self.hash.name().into(),
2293            },
2294        });
2295        rsa_hashed_key_algorithm.safe_to_jsval(cx, rval, can_gc);
2296    }
2297}
2298
2299/// <https://w3c.github.io/webcrypto/#dfn-RsaHashedImportParams>
2300#[derive(Clone, MallocSizeOf)]
2301struct SubtleRsaHashedImportParams {
2302    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2303    name: String,
2304
2305    /// <https://w3c.github.io/webcrypto/#dfn-RsaHashedImportParams-hash>
2306    hash: Box<NormalizedAlgorithm>,
2307}
2308
2309impl TryFrom<RootedTraceableBox<RsaHashedImportParams>> for SubtleRsaHashedImportParams {
2310    type Error = Error;
2311
2312    fn try_from(value: RootedTraceableBox<RsaHashedImportParams>) -> Result<Self, Self::Error> {
2313        let cx = GlobalScope::get_cx();
2314        Ok(SubtleRsaHashedImportParams {
2315            name: value.parent.name.to_string(),
2316            hash: Box::new(normalize_algorithm(
2317                cx,
2318                Operation::Digest,
2319                &value.hash,
2320                CanGc::note(),
2321            )?),
2322        })
2323    }
2324}
2325
2326/// <https://w3c.github.io/webcrypto/#dfn-RsaPssParams>
2327#[derive(Clone, Debug, MallocSizeOf)]
2328struct SubtleRsaPssParams {
2329    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2330    name: String,
2331
2332    /// <https://w3c.github.io/webcrypto/#dfn-RsaPssParams-saltLength>
2333    salt_length: u32,
2334}
2335
2336impl From<RsaPssParams> for SubtleRsaPssParams {
2337    fn from(value: RsaPssParams) -> Self {
2338        SubtleRsaPssParams {
2339            name: value.parent.name.to_string(),
2340            salt_length: value.saltLength,
2341        }
2342    }
2343}
2344
2345/// <https://w3c.github.io/webcrypto/#dfn-RsaOaepParams>
2346#[derive(Clone, Debug, MallocSizeOf)]
2347struct SubtleRsaOaepParams {
2348    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2349    name: String,
2350    /// <https://w3c.github.io/webcrypto/#dfn-RsaOaepParams-label>
2351    label: Option<Vec<u8>>,
2352}
2353
2354impl From<RootedTraceableBox<RsaOaepParams>> for SubtleRsaOaepParams {
2355    fn from(value: RootedTraceableBox<RsaOaepParams>) -> Self {
2356        let label = value.label.as_ref().map(|label| match label {
2357            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2358            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2359        });
2360        SubtleRsaOaepParams {
2361            name: value.parent.name.to_string(),
2362            label,
2363        }
2364    }
2365}
2366
2367/// <https://w3c.github.io/webcrypto/#dfn-EcdsaParams>
2368#[derive(Clone, MallocSizeOf)]
2369struct SubtleEcdsaParams {
2370    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2371    name: String,
2372
2373    /// <https://w3c.github.io/webcrypto/#dfn-EcdsaParams-hash>
2374    hash: Box<NormalizedAlgorithm>,
2375}
2376
2377impl TryFrom<RootedTraceableBox<EcdsaParams>> for SubtleEcdsaParams {
2378    type Error = Error;
2379
2380    fn try_from(value: RootedTraceableBox<EcdsaParams>) -> Result<Self, Error> {
2381        let cx = GlobalScope::get_cx();
2382        let hash = normalize_algorithm(cx, Operation::Digest, &value.hash, CanGc::note())?;
2383        Ok(SubtleEcdsaParams {
2384            name: value.parent.name.to_string(),
2385            hash: Box::new(hash),
2386        })
2387    }
2388}
2389
2390/// <https://w3c.github.io/webcrypto/#dfn-EcKeyGenParams>
2391#[derive(Clone, Debug, MallocSizeOf)]
2392struct SubtleEcKeyGenParams {
2393    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2394    name: String,
2395
2396    /// <https://w3c.github.io/webcrypto/#dfn-EcKeyGenParams-namedCurve>
2397    named_curve: String,
2398}
2399
2400impl From<EcKeyGenParams> for SubtleEcKeyGenParams {
2401    fn from(value: EcKeyGenParams) -> Self {
2402        SubtleEcKeyGenParams {
2403            name: value.parent.name.to_string(),
2404            named_curve: value.namedCurve.to_string(),
2405        }
2406    }
2407}
2408
2409/// <https://w3c.github.io/webcrypto/#dfn-EcKeyAlgorithm>
2410#[derive(Clone, Debug, MallocSizeOf)]
2411pub(crate) struct SubtleEcKeyAlgorithm {
2412    /// <https://w3c.github.io/webcrypto/#dom-keyalgorithm-name>
2413    name: String,
2414
2415    /// <https://w3c.github.io/webcrypto/#dfn-EcKeyAlgorithm-namedCurve>
2416    named_curve: String,
2417}
2418
2419impl SafeToJSValConvertible for SubtleEcKeyAlgorithm {
2420    fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
2421        let parent = KeyAlgorithm {
2422            name: self.name.clone().into(),
2423        };
2424        let dictionary = EcKeyAlgorithm {
2425            parent,
2426            namedCurve: self.named_curve.clone().into(),
2427        };
2428        dictionary.safe_to_jsval(cx, rval, can_gc);
2429    }
2430}
2431
2432/// <https://w3c.github.io/webcrypto/#dfn-EcKeyImportParams>
2433#[derive(Clone, Debug, MallocSizeOf)]
2434struct SubtleEcKeyImportParams {
2435    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2436    name: String,
2437
2438    /// <https://w3c.github.io/webcrypto/#dfn-EcKeyImportParams-namedCurve>
2439    named_curve: String,
2440}
2441
2442impl From<EcKeyImportParams> for SubtleEcKeyImportParams {
2443    fn from(value: EcKeyImportParams) -> Self {
2444        SubtleEcKeyImportParams {
2445            name: value.parent.name.to_string(),
2446            named_curve: value.namedCurve.to_string(),
2447        }
2448    }
2449}
2450
2451/// <https://w3c.github.io/webcrypto/#dfn-EcdhKeyDeriveParams>
2452#[derive(Clone, MallocSizeOf)]
2453struct SubtleEcdhKeyDeriveParams {
2454    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2455    name: String,
2456
2457    /// <https://w3c.github.io/webcrypto/#dfn-EcdhKeyDeriveParams-public>
2458    public: Trusted<CryptoKey>,
2459}
2460
2461impl From<EcdhKeyDeriveParams> for SubtleEcdhKeyDeriveParams {
2462    fn from(value: EcdhKeyDeriveParams) -> Self {
2463        SubtleEcdhKeyDeriveParams {
2464            name: value.parent.name.to_string(),
2465            public: Trusted::new(&value.public),
2466        }
2467    }
2468}
2469
2470/// <https://w3c.github.io/webcrypto/#dfn-AesCtrParams>
2471#[derive(Clone, Debug, MallocSizeOf)]
2472struct SubtleAesCtrParams {
2473    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2474    name: String,
2475
2476    /// <https://w3c.github.io/webcrypto/#dfn-AesCtrParams-counter>
2477    counter: Vec<u8>,
2478
2479    /// <https://w3c.github.io/webcrypto/#dfn-AesCtrParams-length>
2480    length: u8,
2481}
2482
2483impl From<RootedTraceableBox<AesCtrParams>> for SubtleAesCtrParams {
2484    fn from(params: RootedTraceableBox<AesCtrParams>) -> Self {
2485        let counter = match &params.counter {
2486            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2487            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2488        };
2489        SubtleAesCtrParams {
2490            name: params.parent.name.to_string(),
2491            counter,
2492            length: params.length,
2493        }
2494    }
2495}
2496
2497/// <https://w3c.github.io/webcrypto/#dfn-AesKeyAlgorithm>
2498#[derive(Clone, Debug, MallocSizeOf)]
2499pub(crate) struct SubtleAesKeyAlgorithm {
2500    /// <https://w3c.github.io/webcrypto/#dom-keyalgorithm-name>
2501    name: String,
2502
2503    /// <https://w3c.github.io/webcrypto/#dfn-AesKeyAlgorithm-length>
2504    length: u16,
2505}
2506
2507impl SafeToJSValConvertible for SubtleAesKeyAlgorithm {
2508    fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
2509        let parent = KeyAlgorithm {
2510            name: self.name.clone().into(),
2511        };
2512        let dictionary = AesKeyAlgorithm {
2513            parent,
2514            length: self.length,
2515        };
2516        dictionary.safe_to_jsval(cx, rval, can_gc);
2517    }
2518}
2519
2520/// <https://w3c.github.io/webcrypto/#dfn-AesKeyGenParams>
2521#[derive(Clone, Debug, MallocSizeOf)]
2522struct SubtleAesKeyGenParams {
2523    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2524    name: String,
2525
2526    /// <https://w3c.github.io/webcrypto/#dfn-AesKeyGenParams-length>
2527    length: u16,
2528}
2529
2530impl From<AesKeyGenParams> for SubtleAesKeyGenParams {
2531    fn from(params: AesKeyGenParams) -> Self {
2532        SubtleAesKeyGenParams {
2533            name: params.parent.name.to_string(),
2534            length: params.length,
2535        }
2536    }
2537}
2538
2539/// <https://w3c.github.io/webcrypto/#dfn-AesDerivedKeyParams>
2540#[derive(Clone, Debug, MallocSizeOf)]
2541struct SubtleAesDerivedKeyParams {
2542    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2543    name: String,
2544
2545    /// <https://w3c.github.io/webcrypto/#dfn-AesDerivedKeyParams-length>
2546    length: u16,
2547}
2548
2549impl From<AesDerivedKeyParams> for SubtleAesDerivedKeyParams {
2550    fn from(params: AesDerivedKeyParams) -> Self {
2551        SubtleAesDerivedKeyParams {
2552            name: params.parent.name.to_string(),
2553            length: params.length,
2554        }
2555    }
2556}
2557
2558/// <https://w3c.github.io/webcrypto/#dfn-AesCbcParams>
2559#[derive(Clone, Debug, MallocSizeOf)]
2560struct SubtleAesCbcParams {
2561    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2562    name: String,
2563
2564    /// <https://w3c.github.io/webcrypto/#dfn-AesCbcParams-iv>
2565    iv: Vec<u8>,
2566}
2567
2568impl From<RootedTraceableBox<AesCbcParams>> for SubtleAesCbcParams {
2569    fn from(params: RootedTraceableBox<AesCbcParams>) -> Self {
2570        let iv = match &params.iv {
2571            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2572            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2573        };
2574        SubtleAesCbcParams {
2575            name: params.parent.name.to_string(),
2576            iv,
2577        }
2578    }
2579}
2580
2581/// <https://w3c.github.io/webcrypto/#dfn-AesGcmParams>
2582#[derive(Clone, Debug, MallocSizeOf)]
2583struct SubtleAesGcmParams {
2584    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2585    name: String,
2586
2587    /// <https://w3c.github.io/webcrypto/#dfn-AesGcmParams-iv>
2588    iv: Vec<u8>,
2589
2590    /// <https://w3c.github.io/webcrypto/#dfn-AesGcmParams-additionalData>
2591    additional_data: Option<Vec<u8>>,
2592
2593    /// <https://w3c.github.io/webcrypto/#dfn-AesGcmParams-tagLength>
2594    tag_length: Option<u8>,
2595}
2596
2597impl From<RootedTraceableBox<AesGcmParams>> for SubtleAesGcmParams {
2598    fn from(params: RootedTraceableBox<AesGcmParams>) -> Self {
2599        let iv = match &params.iv {
2600            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2601            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2602        };
2603        let additional_data = params.additionalData.as_ref().map(|data| match data {
2604            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2605            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2606        });
2607
2608        SubtleAesGcmParams {
2609            name: params.parent.name.to_string(),
2610            iv,
2611            additional_data,
2612            tag_length: params.tagLength,
2613        }
2614    }
2615}
2616
2617/// <https://w3c.github.io/webcrypto/#dfn-HmacImportParams>
2618#[derive(Clone, MallocSizeOf)]
2619struct SubtleHmacImportParams {
2620    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2621    name: String,
2622
2623    /// <https://w3c.github.io/webcrypto/#dfn-HmacImportParams-hash>
2624    hash: Box<NormalizedAlgorithm>,
2625
2626    /// <https://w3c.github.io/webcrypto/#dfn-HmacImportParams-length>
2627    length: Option<u32>,
2628}
2629
2630impl TryFrom<RootedTraceableBox<HmacImportParams>> for SubtleHmacImportParams {
2631    type Error = Error;
2632
2633    fn try_from(params: RootedTraceableBox<HmacImportParams>) -> Result<Self, Error> {
2634        let cx = GlobalScope::get_cx();
2635        let hash = normalize_algorithm(cx, Operation::Digest, &params.hash, CanGc::note())?;
2636        Ok(SubtleHmacImportParams {
2637            name: params.parent.name.to_string(),
2638            hash: Box::new(hash),
2639            length: params.length,
2640        })
2641    }
2642}
2643
2644/// <https://w3c.github.io/webcrypto/#dfn-HmacKeyAlgorithm>
2645#[derive(Clone, Debug, MallocSizeOf)]
2646pub(crate) struct SubtleHmacKeyAlgorithm {
2647    /// <https://w3c.github.io/webcrypto/#dom-keyalgorithm-name>
2648    name: String,
2649
2650    /// <https://w3c.github.io/webcrypto/#dfn-HmacKeyAlgorithm-hash>
2651    hash: SubtleKeyAlgorithm,
2652
2653    /// <https://w3c.github.io/webcrypto/#dfn-HmacKeyGenParams-length>
2654    length: u32,
2655}
2656
2657impl SafeToJSValConvertible for SubtleHmacKeyAlgorithm {
2658    fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
2659        let parent = KeyAlgorithm {
2660            name: self.name.clone().into(),
2661        };
2662        let hash = KeyAlgorithm {
2663            name: self.hash.name.clone().into(),
2664        };
2665        let dictionary = HmacKeyAlgorithm {
2666            parent,
2667            hash,
2668            length: self.length,
2669        };
2670        dictionary.safe_to_jsval(cx, rval, can_gc);
2671    }
2672}
2673
2674/// <https://w3c.github.io/webcrypto/#dfn-HmacKeyGenParams>
2675#[derive(Clone, MallocSizeOf)]
2676struct SubtleHmacKeyGenParams {
2677    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2678    name: String,
2679
2680    /// <https://w3c.github.io/webcrypto/#dfn-HmacKeyGenParams-hash>
2681    hash: Box<NormalizedAlgorithm>,
2682
2683    /// <https://w3c.github.io/webcrypto/#dfn-HmacKeyGenParams-length>
2684    length: Option<u32>,
2685}
2686
2687impl TryFrom<RootedTraceableBox<HmacKeyGenParams>> for SubtleHmacKeyGenParams {
2688    type Error = Error;
2689
2690    fn try_from(params: RootedTraceableBox<HmacKeyGenParams>) -> Result<Self, Error> {
2691        let cx = GlobalScope::get_cx();
2692        let hash = normalize_algorithm(cx, Operation::Digest, &params.hash, CanGc::note())?;
2693        Ok(SubtleHmacKeyGenParams {
2694            name: params.parent.name.to_string(),
2695            hash: Box::new(hash),
2696            length: params.length,
2697        })
2698    }
2699}
2700
2701/// <https://w3c.github.io/webcrypto/#dfn-HkdfParams>
2702#[derive(Clone, MallocSizeOf)]
2703pub(crate) struct SubtleHkdfParams {
2704    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2705    name: String,
2706
2707    /// <https://w3c.github.io/webcrypto/#dfn-HkdfParams-hash>
2708    hash: Box<NormalizedAlgorithm>,
2709
2710    /// <https://w3c.github.io/webcrypto/#dfn-HkdfParams-salt>
2711    salt: Vec<u8>,
2712
2713    /// <https://w3c.github.io/webcrypto/#dfn-HkdfParams-info>
2714    info: Vec<u8>,
2715}
2716
2717impl TryFrom<RootedTraceableBox<HkdfParams>> for SubtleHkdfParams {
2718    type Error = Error;
2719
2720    fn try_from(params: RootedTraceableBox<HkdfParams>) -> Result<Self, Error> {
2721        let cx = GlobalScope::get_cx();
2722        let hash = normalize_algorithm(cx, Operation::Digest, &params.hash, CanGc::note())?;
2723        let salt = match &params.salt {
2724            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2725            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2726        };
2727        let info = match &params.info {
2728            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2729            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2730        };
2731        Ok(SubtleHkdfParams {
2732            name: params.parent.name.to_string(),
2733            hash: Box::new(hash),
2734            salt,
2735            info,
2736        })
2737    }
2738}
2739
2740/// <https://w3c.github.io/webcrypto/#dfn-Pbkdf2Params>
2741#[derive(Clone, MallocSizeOf)]
2742pub(crate) struct SubtlePbkdf2Params {
2743    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2744    name: String,
2745
2746    /// <https://w3c.github.io/webcrypto/#dfn-Pbkdf2Params-salt>
2747    salt: Vec<u8>,
2748
2749    /// <https://w3c.github.io/webcrypto/#dfn-Pbkdf2Params-iterations>
2750    iterations: u32,
2751
2752    /// <https://w3c.github.io/webcrypto/#dfn-Pbkdf2Params-hash>
2753    hash: Box<NormalizedAlgorithm>,
2754}
2755
2756impl TryFrom<RootedTraceableBox<Pbkdf2Params>> for SubtlePbkdf2Params {
2757    type Error = Error;
2758
2759    fn try_from(params: RootedTraceableBox<Pbkdf2Params>) -> Result<Self, Error> {
2760        let cx = GlobalScope::get_cx();
2761        let salt = match &params.salt {
2762            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2763            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2764        };
2765        let hash = normalize_algorithm(cx, Operation::Digest, &params.hash, CanGc::note())?;
2766        Ok(SubtlePbkdf2Params {
2767            name: params.parent.name.to_string(),
2768            salt,
2769            iterations: params.iterations,
2770            hash: Box::new(hash),
2771        })
2772    }
2773}
2774
2775/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-ContextParams>
2776#[derive(Clone, Debug, MallocSizeOf)]
2777struct SubtleContextParams {
2778    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2779    name: String,
2780
2781    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-ContextParams-context>
2782    context: Option<Vec<u8>>,
2783}
2784
2785impl From<RootedTraceableBox<ContextParams>> for SubtleContextParams {
2786    fn from(value: RootedTraceableBox<ContextParams>) -> Self {
2787        let context = value.context.as_ref().map(|context| match context {
2788            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2789            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2790        });
2791        SubtleContextParams {
2792            name: value.parent.name.to_string(),
2793            context,
2794        }
2795    }
2796}
2797
2798/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-AeadParams>
2799#[derive(Clone, Debug, MallocSizeOf)]
2800struct SubtleAeadParams {
2801    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2802    name: String,
2803
2804    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-AeadParams-iv>
2805    iv: Vec<u8>,
2806
2807    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-AeadParams-additionalData>
2808    additional_data: Option<Vec<u8>>,
2809
2810    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-AeadParams-tagLength>
2811    tag_length: Option<u8>,
2812}
2813
2814impl From<RootedTraceableBox<AeadParams>> for SubtleAeadParams {
2815    fn from(value: RootedTraceableBox<AeadParams>) -> Self {
2816        let iv = match &value.iv {
2817            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2818            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2819        };
2820        let additional_data = value.additionalData.as_ref().map(|data| match data {
2821            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2822            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2823        });
2824
2825        SubtleAeadParams {
2826            name: value.parent.name.to_string(),
2827            iv,
2828            additional_data,
2829            tag_length: value.tagLength,
2830        }
2831    }
2832}
2833
2834/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-CShakeParams>
2835#[derive(Clone, Debug, MallocSizeOf)]
2836struct SubtleCShakeParams {
2837    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2838    name: String,
2839
2840    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-CShakeParams-length>
2841    length: u32,
2842
2843    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-CShakeParams-functionName>
2844    function_name: Option<Vec<u8>>,
2845
2846    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-CShakeParams-customization>
2847    customization: Option<Vec<u8>>,
2848}
2849
2850impl From<RootedTraceableBox<CShakeParams>> for SubtleCShakeParams {
2851    fn from(value: RootedTraceableBox<CShakeParams>) -> Self {
2852        let function_name = value
2853            .functionName
2854            .as_ref()
2855            .map(|function_name| match function_name {
2856                ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2857                ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2858            });
2859        let customization = value
2860            .customization
2861            .as_ref()
2862            .map(|customization| match customization {
2863                ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2864                ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2865            });
2866        SubtleCShakeParams {
2867            name: value.parent.name.to_string(),
2868            length: value.length,
2869            function_name,
2870            customization,
2871        }
2872    }
2873}
2874
2875/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params>
2876#[derive(Clone, Debug, MallocSizeOf)]
2877struct SubtleArgon2Params {
2878    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2879    name: String,
2880
2881    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-nonce>
2882    nonce: Vec<u8>,
2883
2884    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-parallelism>
2885    parallelism: u32,
2886
2887    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-memory>
2888    memory: u32,
2889
2890    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-passes>
2891    passes: u32,
2892
2893    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-version>
2894    version: Option<u8>,
2895
2896    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-secretValue>
2897    secret_value: Option<Vec<u8>>,
2898
2899    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-associatedData>
2900    associated_data: Option<Vec<u8>>,
2901}
2902
2903impl From<RootedTraceableBox<Argon2Params>> for SubtleArgon2Params {
2904    fn from(value: RootedTraceableBox<Argon2Params>) -> Self {
2905        let nonce = match &value.nonce {
2906            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2907            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2908        };
2909        let secret_value = value
2910            .secretValue
2911            .as_ref()
2912            .map(|secret_value| match secret_value {
2913                ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2914                ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2915            });
2916        let associated_data =
2917            value
2918                .associatedData
2919                .as_ref()
2920                .map(|associated_data| match associated_data {
2921                    ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2922                    ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2923                });
2924        SubtleArgon2Params {
2925            name: value.parent.name.to_string(),
2926            nonce,
2927            parallelism: value.parallelism,
2928            memory: value.memory,
2929            passes: value.passes,
2930            version: value.version,
2931            secret_value,
2932            associated_data,
2933        }
2934    }
2935}
2936
2937/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-EncapsulatedKey>
2938struct SubtleEncapsulatedKey {
2939    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-EncapsulatedKey-sharedKey>
2940    shared_key: Option<Trusted<CryptoKey>>,
2941
2942    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-EncapsulatedKey-ciphertext>
2943    ciphertext: Option<Vec<u8>>,
2944}
2945
2946impl SafeToJSValConvertible for SubtleEncapsulatedKey {
2947    fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
2948        let shared_key = self.shared_key.as_ref().map(|shared_key| shared_key.root());
2949        let ciphertext = self.ciphertext.as_ref().map(|data| {
2950            rooted!(in(*cx) let mut ciphertext_ptr = ptr::null_mut::<JSObject>());
2951            create_buffer_source::<ArrayBufferU8>(cx, data, ciphertext_ptr.handle_mut(), can_gc)
2952                .expect("Failed to convert ciphertext to ArrayBufferU8")
2953        });
2954        let encapsulated_key = RootedTraceableBox::new(EncapsulatedKey {
2955            sharedKey: shared_key,
2956            ciphertext,
2957        });
2958        encapsulated_key.safe_to_jsval(cx, rval, can_gc);
2959    }
2960}
2961
2962/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-EncapsulatedBits>
2963struct SubtleEncapsulatedBits {
2964    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-EncapsulatedBits-sharedKey>
2965    shared_key: Option<Vec<u8>>,
2966
2967    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-EncapsulatedBits-ciphertext>
2968    ciphertext: Option<Vec<u8>>,
2969}
2970
2971impl SafeToJSValConvertible for SubtleEncapsulatedBits {
2972    fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
2973        let shared_key = self.shared_key.as_ref().map(|data| {
2974            rooted!(in(*cx) let mut shared_key_ptr = ptr::null_mut::<JSObject>());
2975            create_buffer_source::<ArrayBufferU8>(cx, data, shared_key_ptr.handle_mut(), can_gc)
2976                .expect("Failed to convert shared key to ArrayBufferU8")
2977        });
2978        let ciphertext = self.ciphertext.as_ref().map(|data| {
2979            rooted!(in(*cx) let mut ciphertext_ptr = ptr::null_mut::<JSObject>());
2980            create_buffer_source::<ArrayBufferU8>(cx, data, ciphertext_ptr.handle_mut(), can_gc)
2981                .expect("Failed to convert ciphertext to ArrayBufferU8")
2982        });
2983        let encapsulated_bits = RootedTraceableBox::new(EncapsulatedBits {
2984            sharedKey: shared_key,
2985            ciphertext,
2986        });
2987        encapsulated_bits.safe_to_jsval(cx, rval, can_gc);
2988    }
2989}
2990
2991/// Helper to abstract the conversion process of a JS value into many different WebIDL dictionaries.
2992fn dictionary_from_jsval<T>(cx: JSContext, value: HandleValue, can_gc: CanGc) -> Fallible<T>
2993where
2994    T: SafeFromJSValConvertible<Config = ()>,
2995{
2996    let conversion = T::safe_from_jsval(cx, value, (), can_gc).map_err(|_| Error::JSFailed)?;
2997    match conversion {
2998        ConversionResult::Success(dictionary) => Ok(dictionary),
2999        ConversionResult::Failure(error) => Err(Error::Type(error.into_owned())),
3000    }
3001}
3002
3003/// The returned type of the successful export key operation. `Bytes` should be used when the key
3004/// is exported in "raw", "spki" or "pkcs8" format. `Jwk` should be used when the key is exported
3005/// in "jwk" format.
3006enum ExportedKey {
3007    Bytes(Vec<u8>),
3008    Jwk(Box<JsonWebKey>),
3009}
3010
3011/// Union type of KeyAlgorithm and IDL dictionary types derived from it. Note that we actually use
3012/// our "subtle" structs of the corresponding IDL dictionary types so that they can be easily
3013/// passed to another threads.
3014#[derive(Clone, MallocSizeOf)]
3015#[expect(clippy::enum_variant_names)]
3016pub(crate) enum KeyAlgorithmAndDerivatives {
3017    KeyAlgorithm(SubtleKeyAlgorithm),
3018    RsaHashedKeyAlgorithm(SubtleRsaHashedKeyAlgorithm),
3019    EcKeyAlgorithm(SubtleEcKeyAlgorithm),
3020    AesKeyAlgorithm(SubtleAesKeyAlgorithm),
3021    HmacKeyAlgorithm(SubtleHmacKeyAlgorithm),
3022}
3023
3024impl KeyAlgorithmAndDerivatives {
3025    fn name(&self) -> &str {
3026        match self {
3027            KeyAlgorithmAndDerivatives::KeyAlgorithm(algo) => &algo.name,
3028            KeyAlgorithmAndDerivatives::RsaHashedKeyAlgorithm(algo) => &algo.name,
3029            KeyAlgorithmAndDerivatives::EcKeyAlgorithm(algo) => &algo.name,
3030            KeyAlgorithmAndDerivatives::AesKeyAlgorithm(algo) => &algo.name,
3031            KeyAlgorithmAndDerivatives::HmacKeyAlgorithm(algo) => &algo.name,
3032        }
3033    }
3034}
3035
3036impl SafeToJSValConvertible for KeyAlgorithmAndDerivatives {
3037    fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
3038        match self {
3039            KeyAlgorithmAndDerivatives::KeyAlgorithm(algo) => algo.safe_to_jsval(cx, rval, can_gc),
3040            KeyAlgorithmAndDerivatives::RsaHashedKeyAlgorithm(algo) => {
3041                algo.safe_to_jsval(cx, rval, can_gc)
3042            },
3043            KeyAlgorithmAndDerivatives::EcKeyAlgorithm(algo) => {
3044                algo.safe_to_jsval(cx, rval, can_gc)
3045            },
3046            KeyAlgorithmAndDerivatives::AesKeyAlgorithm(algo) => {
3047                algo.safe_to_jsval(cx, rval, can_gc)
3048            },
3049            KeyAlgorithmAndDerivatives::HmacKeyAlgorithm(algo) => {
3050                algo.safe_to_jsval(cx, rval, can_gc)
3051            },
3052        }
3053    }
3054}
3055
3056#[derive(Clone, Copy)]
3057enum JwkStringField {
3058    X,
3059    Y,
3060    D,
3061    N,
3062    E,
3063    P,
3064    Q,
3065    DP,
3066    DQ,
3067    QI,
3068    K,
3069    Priv,
3070    Pub,
3071}
3072
3073impl Display for JwkStringField {
3074    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3075        let field_name = match self {
3076            JwkStringField::X => "x",
3077            JwkStringField::Y => "y",
3078            JwkStringField::D => "d",
3079            JwkStringField::N => "n",
3080            JwkStringField::E => "e",
3081            JwkStringField::P => "q",
3082            JwkStringField::Q => "q",
3083            JwkStringField::DP => "dp",
3084            JwkStringField::DQ => "dq",
3085            JwkStringField::QI => "qi",
3086            JwkStringField::K => "k",
3087            JwkStringField::Priv => "priv",
3088            JwkStringField::Pub => "pub",
3089        };
3090        write!(f, "{}", field_name)
3091    }
3092}
3093
3094trait JsonWebKeyExt {
3095    fn parse(cx: JSContext, data: &[u8]) -> Result<JsonWebKey, Error>;
3096    fn stringify(&self, cx: JSContext) -> Result<DOMString, Error>;
3097    fn get_usages_from_key_ops(&self) -> Result<Vec<KeyUsage>, Error>;
3098    fn check_key_ops(&self, specified_usages: &[KeyUsage]) -> Result<(), Error>;
3099    fn set_key_ops(&mut self, usages: Vec<KeyUsage>);
3100    fn encode_string_field(&mut self, field: JwkStringField, data: &[u8]);
3101    fn decode_optional_string_field(&self, field: JwkStringField)
3102    -> Result<Option<Vec<u8>>, Error>;
3103    fn decode_required_string_field(&self, field: JwkStringField) -> Result<Vec<u8>, Error>;
3104    fn decode_primes_from_oth_field(&self, primes: &mut Vec<Vec<u8>>) -> Result<(), Error>;
3105}
3106
3107impl JsonWebKeyExt for JsonWebKey {
3108    /// <https://w3c.github.io/webcrypto/#concept-parse-a-jwk>
3109    #[expect(unsafe_code)]
3110    fn parse(cx: JSContext, data: &[u8]) -> Result<JsonWebKey, Error> {
3111        // Step 1. Let data be the sequence of bytes to be parsed.
3112        // (It is given as a method paramter.)
3113
3114        // Step 2. Let json be the Unicode string that results from interpreting data according to UTF-8.
3115        let json = String::from_utf8_lossy(data);
3116
3117        // Step 3. Convert json to UTF-16.
3118        let json: Vec<_> = json.encode_utf16().collect();
3119
3120        // Step 4. Let result be the object literal that results from executing the JSON.parse
3121        // internal function in the context of a new global object, with text argument set to a
3122        // JavaScript String containing json.
3123        rooted!(in(*cx) let mut result = UndefinedValue());
3124        unsafe {
3125            if !JS_ParseJSON(*cx, json.as_ptr(), json.len() as u32, result.handle_mut()) {
3126                return Err(Error::JSFailed);
3127            }
3128        }
3129
3130        // Step 5. Let key be the result of converting result to the IDL dictionary type of JsonWebKey.
3131        let key = match JsonWebKey::new(cx, result.handle(), CanGc::note()) {
3132            Ok(ConversionResult::Success(key)) => key,
3133            Ok(ConversionResult::Failure(error)) => {
3134                return Err(Error::Type(error.into_owned()));
3135            },
3136            Err(()) => {
3137                return Err(Error::JSFailed);
3138            },
3139        };
3140
3141        // Step 6. If the kty field of key is not defined, then throw a DataError.
3142        if key.kty.is_none() {
3143            return Err(Error::Data(None));
3144        }
3145
3146        // Step 7. Result key.
3147        Ok(key)
3148    }
3149
3150    /// Convert a JsonWebKey value to DOMString. We first convert the JsonWebKey value to
3151    /// JavaScript value, and then serialize it by performing steps in
3152    /// <https://infra.spec.whatwg.org/#serialize-a-javascript-value-to-a-json-string>. This acts
3153    /// like the opposite of JsonWebKey::parse if you further convert the stringified result to
3154    /// bytes.
3155    fn stringify(&self, cx: JSContext) -> Result<DOMString, Error> {
3156        rooted!(in(*cx) let mut data = UndefinedValue());
3157        self.safe_to_jsval(cx, data.handle_mut(), CanGc::note());
3158        serialize_jsval_to_json_utf8(cx, data.handle())
3159    }
3160
3161    fn get_usages_from_key_ops(&self) -> Result<Vec<KeyUsage>, Error> {
3162        let mut usages = vec![];
3163        for op in self.key_ops.as_ref().ok_or(Error::Data(None))? {
3164            usages.push(KeyUsage::from_str(&op.str()).map_err(|_| Error::Data(None))?);
3165        }
3166        Ok(usages)
3167    }
3168
3169    /// If the key_ops field of jwk is present, and is invalid according to the requirements of
3170    /// JSON Web Key [JWK] or does not contain all of the specified usages values, then throw a
3171    /// DataError.
3172    fn check_key_ops(&self, specified_usages: &[KeyUsage]) -> Result<(), Error> {
3173        // If the key_ops field of jwk is present,
3174        if let Some(ref key_ops) = self.key_ops {
3175            // and is invalid according to the requirements of JSON Web Key [JWK]:
3176            // 1. Duplicate key operation values MUST NOT be present in the array.
3177            if key_ops
3178                .iter()
3179                .collect::<std::collections::HashSet<_>>()
3180                .len() <
3181                key_ops.len()
3182            {
3183                return Err(Error::Data(None));
3184            }
3185            // 2. The "use" and "key_ops" JWK members SHOULD NOT be used together; however, if both
3186            //    are used, the information they convey MUST be consistent.
3187            if let Some(ref use_) = self.use_ {
3188                if key_ops.iter().any(|op| op != use_) {
3189                    return Err(Error::Data(None));
3190                }
3191            }
3192
3193            // or does not contain all of the specified usages values
3194            let key_ops_as_usages = self.get_usages_from_key_ops()?;
3195            if !specified_usages
3196                .iter()
3197                .all(|specified_usage| key_ops_as_usages.contains(specified_usage))
3198            {
3199                return Err(Error::Data(None));
3200            }
3201        }
3202
3203        Ok(())
3204    }
3205
3206    // Set the key_ops attribute of jwk to equal the given usages.
3207    fn set_key_ops(&mut self, usages: Vec<KeyUsage>) {
3208        self.key_ops = Some(
3209            usages
3210                .into_iter()
3211                .map(|usage| DOMString::from(usage.as_str()))
3212                .collect(),
3213        );
3214    }
3215
3216    // Encode a byte sequence to a base64url-encoded string, and set the field to the encoded
3217    // string.
3218    fn encode_string_field(&mut self, field: JwkStringField, data: &[u8]) {
3219        let encoded_data = DOMString::from(Base64UrlUnpadded::encode_string(data));
3220        match field {
3221            JwkStringField::X => self.x = Some(encoded_data),
3222            JwkStringField::Y => self.y = Some(encoded_data),
3223            JwkStringField::D => self.d = Some(encoded_data),
3224            JwkStringField::N => self.n = Some(encoded_data),
3225            JwkStringField::E => self.e = Some(encoded_data),
3226            JwkStringField::P => self.p = Some(encoded_data),
3227            JwkStringField::Q => self.q = Some(encoded_data),
3228            JwkStringField::DP => self.dp = Some(encoded_data),
3229            JwkStringField::DQ => self.dq = Some(encoded_data),
3230            JwkStringField::QI => self.qi = Some(encoded_data),
3231            JwkStringField::K => self.k = Some(encoded_data),
3232            JwkStringField::Priv => self.priv_ = Some(encoded_data),
3233            JwkStringField::Pub => self.pub_ = Some(encoded_data),
3234        }
3235    }
3236
3237    // Decode a field from a base64url-encoded string to a byte sequence. If the field is not a
3238    // valid base64url-encoded string, then throw a DataError.
3239    fn decode_optional_string_field(
3240        &self,
3241        field: JwkStringField,
3242    ) -> Result<Option<Vec<u8>>, Error> {
3243        let field_string = match field {
3244            JwkStringField::X => &self.x,
3245            JwkStringField::Y => &self.y,
3246            JwkStringField::D => &self.d,
3247            JwkStringField::N => &self.n,
3248            JwkStringField::E => &self.e,
3249            JwkStringField::P => &self.p,
3250            JwkStringField::Q => &self.q,
3251            JwkStringField::DP => &self.dp,
3252            JwkStringField::DQ => &self.dq,
3253            JwkStringField::QI => &self.qi,
3254            JwkStringField::K => &self.k,
3255            JwkStringField::Priv => &self.priv_,
3256            JwkStringField::Pub => &self.pub_,
3257        };
3258
3259        field_string
3260            .as_ref()
3261            .map(|field_string| Base64UrlUnpadded::decode_vec(&field_string.str()))
3262            .transpose()
3263            .map_err(|_| Error::Data(Some(format!("Failed to decode {} field in jwk", field))))
3264    }
3265
3266    // Decode a field from a base64url-encoded string to a byte sequence. If the field is not
3267    // present or it is not a valid base64url-encoded string, then throw a DataError.
3268    fn decode_required_string_field(&self, field: JwkStringField) -> Result<Vec<u8>, Error> {
3269        self.decode_optional_string_field(field)?
3270            .ok_or(Error::Data(Some(format!(
3271                "The {} field is not present in jwk",
3272                field
3273            ))))
3274    }
3275
3276    // Decode the "r", "d" and "t" field of each entry in the "oth" array, from a base64url-encoded
3277    // string to a byte sequence, and append the decoded "r" field to the `primes` list, in the
3278    // order of presence in the "oth" array.
3279    //
3280    // If the "oth" field is present and any of the "p", "q", "dp", "dq" or "qi" field is not
3281    // present, then throw a DataError. For each entry in the "oth" array, if any of the "r", "d"
3282    // and "t" field is not present or it is not a valid base64url-encoded string, then throw a
3283    // DataError.
3284    fn decode_primes_from_oth_field(&self, primes: &mut Vec<Vec<u8>>) -> Result<(), Error> {
3285        if self.oth.is_some() &&
3286            (self.p.is_none() ||
3287                self.q.is_none() ||
3288                self.dp.is_none() ||
3289                self.dq.is_none() ||
3290                self.qi.is_none())
3291        {
3292            return Err(Error::Data(Some(
3293                "The oth field is present while at least one of p, q, dp, dq, qi is missing, in jwk".to_string()
3294            )));
3295        }
3296
3297        for rsa_other_prime_info in self.oth.as_ref().unwrap_or(&Vec::new()) {
3298            let r = Base64UrlUnpadded::decode_vec(
3299                &rsa_other_prime_info
3300                    .r
3301                    .as_ref()
3302                    .ok_or(Error::Data(Some(
3303                        "The r field is not present in one of the entry of oth field in jwk"
3304                            .to_string(),
3305                    )))?
3306                    .str(),
3307            )
3308            .map_err(|_| {
3309                Error::Data(Some(
3310                    "Fail to decode r field in one of the entry of oth field in jwk".to_string(),
3311                ))
3312            })?;
3313            primes.push(r);
3314
3315            let _d = Base64UrlUnpadded::decode_vec(
3316                &rsa_other_prime_info
3317                    .d
3318                    .as_ref()
3319                    .ok_or(Error::Data(Some(
3320                        "The d field is not present in one of the entry of oth field in jwk"
3321                            .to_string(),
3322                    )))?
3323                    .str(),
3324            )
3325            .map_err(|_| {
3326                Error::Data(Some(
3327                    "Fail to decode d field in one of the entry of oth field in jwk".to_string(),
3328                ))
3329            })?;
3330
3331            let _t = Base64UrlUnpadded::decode_vec(
3332                &rsa_other_prime_info
3333                    .t
3334                    .as_ref()
3335                    .ok_or(Error::Data(Some(
3336                        "The t 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 t field in one of the entry of oth field in jwk".to_string(),
3344                ))
3345            })?;
3346        }
3347
3348        Ok(())
3349    }
3350}
3351
3352/// Inner type of <https://w3c.github.io/webcrypto/#dfn-supportedAlgorithms> for SHA
3353enum ShaAlgorithm {
3354    Sha1,
3355    Sha256,
3356    Sha384,
3357    Sha512,
3358}
3359
3360impl ShaAlgorithm {
3361    fn as_str(&self) -> &'static str {
3362        match self {
3363            ShaAlgorithm::Sha1 => ALG_SHA1,
3364            ShaAlgorithm::Sha256 => ALG_SHA256,
3365            ShaAlgorithm::Sha384 => ALG_SHA384,
3366            ShaAlgorithm::Sha512 => ALG_SHA512,
3367        }
3368    }
3369}
3370
3371/// Inner type of <https://w3c.github.io/webcrypto/#dfn-supportedAlgorithms> for ML-KEM
3372enum MlKemAlgorithm {
3373    MlKem512,
3374    MlKem768,
3375    MlKem1024,
3376}
3377
3378impl MlKemAlgorithm {
3379    fn as_str(&self) -> &'static str {
3380        match self {
3381            MlKemAlgorithm::MlKem512 => ALG_ML_KEM_512,
3382            MlKemAlgorithm::MlKem768 => ALG_ML_KEM_768,
3383            MlKemAlgorithm::MlKem1024 => ALG_ML_KEM_1024,
3384        }
3385    }
3386}
3387
3388/// Inner type of <https://w3c.github.io/webcrypto/#dfn-supportedAlgorithms> for ML-DSA
3389enum MlDsaAlgorithm {
3390    MlDsa44,
3391    MlDsa65,
3392    MlDsa87,
3393}
3394
3395impl MlDsaAlgorithm {
3396    fn as_str(&self) -> &'static str {
3397        match self {
3398            MlDsaAlgorithm::MlDsa44 => ALG_ML_DSA_44,
3399            MlDsaAlgorithm::MlDsa65 => ALG_ML_DSA_65,
3400            MlDsaAlgorithm::MlDsa87 => ALG_ML_DSA_87,
3401        }
3402    }
3403}
3404
3405/// Inner type of <https://w3c.github.io/webcrypto/#dfn-supportedAlgorithms> for SHA3
3406enum Sha3Algorithm {
3407    Sha3_256,
3408    Sha3_384,
3409    Sha3_512,
3410}
3411
3412impl Sha3Algorithm {
3413    fn as_str(&self) -> &'static str {
3414        match self {
3415            Sha3Algorithm::Sha3_256 => ALG_SHA3_256,
3416            Sha3Algorithm::Sha3_384 => ALG_SHA3_384,
3417            Sha3Algorithm::Sha3_512 => ALG_SHA3_512,
3418        }
3419    }
3420}
3421
3422/// Inner type of <https://w3c.github.io/webcrypto/#dfn-supportedAlgorithms> for cSHAKE
3423enum CShakeAlgorithm {
3424    CShake128,
3425    CShake256,
3426}
3427
3428impl CShakeAlgorithm {
3429    fn as_str(&self) -> &'static str {
3430        match self {
3431            CShakeAlgorithm::CShake128 => ALG_CSHAKE_128,
3432            CShakeAlgorithm::CShake256 => ALG_CSHAKE_256,
3433        }
3434    }
3435}
3436
3437/// Inner type of <https://w3c.github.io/webcrypto/#dfn-supportedAlgorithms> for Argon2
3438enum Argon2Algorithm {
3439    Argon2D,
3440    Argon2I,
3441    Argon2ID,
3442}
3443
3444impl Argon2Algorithm {
3445    fn as_str(&self) -> &'static str {
3446        match self {
3447            Argon2Algorithm::Argon2D => ALG_ARGON2D,
3448            Argon2Algorithm::Argon2I => ALG_ARGON2I,
3449            Argon2Algorithm::Argon2ID => ALG_ARGON2ID,
3450        }
3451    }
3452}
3453
3454/// <https://w3c.github.io/webcrypto/#dfn-supportedAlgorithms>
3455enum SupportedAlgorithm {
3456    RsassaPkcs1V1_5,
3457    RsaPss,
3458    RsaOaep,
3459    Ecdsa,
3460    Ecdh,
3461    Ed25519,
3462    X25519,
3463    AesCtr,
3464    AesCbc,
3465    AesGcm,
3466    AesKw,
3467    Hmac,
3468    Sha(ShaAlgorithm),
3469    Hkdf,
3470    Pbkdf2,
3471    MlKem(MlKemAlgorithm),
3472    MlDsa(MlDsaAlgorithm),
3473    AesOcb,
3474    ChaCha20Poly1305,
3475    Sha3(Sha3Algorithm),
3476    CShake(CShakeAlgorithm),
3477    Argon2(Argon2Algorithm),
3478}
3479
3480impl SupportedAlgorithm {
3481    fn as_str(&self) -> &'static str {
3482        match self {
3483            SupportedAlgorithm::RsassaPkcs1V1_5 => ALG_RSASSA_PKCS1_V1_5,
3484            SupportedAlgorithm::RsaPss => ALG_RSA_PSS,
3485            SupportedAlgorithm::RsaOaep => ALG_RSA_OAEP,
3486            SupportedAlgorithm::Ecdsa => ALG_ECDSA,
3487            SupportedAlgorithm::Ecdh => ALG_ECDH,
3488            SupportedAlgorithm::Ed25519 => ALG_ED25519,
3489            SupportedAlgorithm::X25519 => ALG_X25519,
3490            SupportedAlgorithm::AesCtr => ALG_AES_CTR,
3491            SupportedAlgorithm::AesCbc => ALG_AES_CBC,
3492            SupportedAlgorithm::AesGcm => ALG_AES_GCM,
3493            SupportedAlgorithm::AesKw => ALG_AES_KW,
3494            SupportedAlgorithm::Hmac => ALG_HMAC,
3495            SupportedAlgorithm::Sha(sha_algorithm) => sha_algorithm.as_str(),
3496            SupportedAlgorithm::Hkdf => ALG_HKDF,
3497            SupportedAlgorithm::Pbkdf2 => ALG_PBKDF2,
3498            SupportedAlgorithm::MlKem(ml_kem_algorithm) => ml_kem_algorithm.as_str(),
3499            SupportedAlgorithm::MlDsa(ml_dsa_algorithm) => ml_dsa_algorithm.as_str(),
3500            SupportedAlgorithm::AesOcb => ALG_AES_OCB,
3501            SupportedAlgorithm::ChaCha20Poly1305 => ALG_CHACHA20_POLY1305,
3502            SupportedAlgorithm::Sha3(sha3_algorithm) => sha3_algorithm.as_str(),
3503            SupportedAlgorithm::CShake(cshake_algorithm) => cshake_algorithm.as_str(),
3504            SupportedAlgorithm::Argon2(argon2_algorithm) => argon2_algorithm.as_str(),
3505        }
3506    }
3507
3508    fn from_ignore_case(alg_name: &str) -> Result<SupportedAlgorithm, Error> {
3509        let Some(&alg_name) = SUPPORTED_ALGORITHMS
3510            .iter()
3511            .find(|supported_algorithm| supported_algorithm.eq_ignore_ascii_case(alg_name))
3512        else {
3513            return Err(Error::NotSupported(Some(format!(
3514                "Unsupported algorithm: {}",
3515                alg_name
3516            ))));
3517        };
3518        SupportedAlgorithm::try_from(alg_name)
3519    }
3520
3521    /// Check whether the cryptographic algorithm supports the specified operation. If the
3522    /// algorithm supports the operation, then return the desired IDL dictionary type for the
3523    /// operation of the algorithm. Otherwise, throw a NotSupportedError.
3524    ///
3525    /// This function is also used as the "define an algorithm" algorithm, by adding algorithms,
3526    /// operations and desired IDL dictionary types, to the `match` block.
3527    /// <https://w3c.github.io/webcrypto/#concept-define-an-algorithm>
3528    fn support(&self, op: Operation) -> Result<ParameterType, Error> {
3529        let desired_type = match (self, &op) {
3530            // <https://w3c.github.io/webcrypto/#rsassa-pkcs1-registration>
3531            (Self::RsassaPkcs1V1_5, Operation::Sign) => ParameterType::None,
3532            (Self::RsassaPkcs1V1_5, Operation::Verify) => ParameterType::None,
3533            (Self::RsassaPkcs1V1_5, Operation::GenerateKey) => ParameterType::RsaHashedKeyGenParams,
3534            (Self::RsassaPkcs1V1_5, Operation::ImportKey) => ParameterType::RsaHashedImportParams,
3535            (Self::RsassaPkcs1V1_5, Operation::ExportKey) => ParameterType::None,
3536
3537            // <https://w3c.github.io/webcrypto/#rsa-pss-registration>
3538            (Self::RsaPss, Operation::Sign) => ParameterType::RsaPssParams,
3539            (Self::RsaPss, Operation::Verify) => ParameterType::RsaPssParams,
3540            (Self::RsaPss, Operation::GenerateKey) => ParameterType::RsaHashedKeyGenParams,
3541            (Self::RsaPss, Operation::ImportKey) => ParameterType::RsaHashedImportParams,
3542            (Self::RsaPss, Operation::ExportKey) => ParameterType::None,
3543
3544            // <https://w3c.github.io/webcrypto/#rsa-oaep-registration>
3545            (Self::RsaOaep, Operation::Encrypt) => ParameterType::RsaOaepParams,
3546            (Self::RsaOaep, Operation::Decrypt) => ParameterType::RsaOaepParams,
3547            (Self::RsaOaep, Operation::GenerateKey) => ParameterType::RsaHashedKeyGenParams,
3548            (Self::RsaOaep, Operation::ImportKey) => ParameterType::RsaHashedImportParams,
3549            (Self::RsaOaep, Operation::ExportKey) => ParameterType::None,
3550
3551            // <https://w3c.github.io/webcrypto/#ecdsa-registration>
3552            (Self::Ecdsa, Operation::Sign) => ParameterType::EcdsaParams,
3553            (Self::Ecdsa, Operation::Verify) => ParameterType::EcdsaParams,
3554            (Self::Ecdsa, Operation::GenerateKey) => ParameterType::EcKeyGenParams,
3555            (Self::Ecdsa, Operation::ImportKey) => ParameterType::EcKeyImportParams,
3556            (Self::Ecdsa, Operation::ExportKey) => ParameterType::None,
3557
3558            // <https://w3c.github.io/webcrypto/#ecdh-registration>
3559            (Self::Ecdh, Operation::GenerateKey) => ParameterType::EcKeyGenParams,
3560            (Self::Ecdh, Operation::DeriveBits) => ParameterType::EcdhKeyDeriveParams,
3561            (Self::Ecdh, Operation::ImportKey) => ParameterType::EcKeyImportParams,
3562            (Self::Ecdh, Operation::ExportKey) => ParameterType::None,
3563
3564            // <https://w3c.github.io/webcrypto/#ed25519-registration>
3565            (Self::Ed25519, Operation::Sign) => ParameterType::None,
3566            (Self::Ed25519, Operation::Verify) => ParameterType::None,
3567            (Self::Ed25519, Operation::GenerateKey) => ParameterType::None,
3568            (Self::Ed25519, Operation::ImportKey) => ParameterType::None,
3569            (Self::Ed25519, Operation::ExportKey) => ParameterType::None,
3570
3571            // <https://w3c.github.io/webcrypto/#x25519-registration>
3572            (Self::X25519, Operation::DeriveBits) => ParameterType::EcdhKeyDeriveParams,
3573            (Self::X25519, Operation::GenerateKey) => ParameterType::None,
3574            (Self::X25519, Operation::ImportKey) => ParameterType::None,
3575            (Self::X25519, Operation::ExportKey) => ParameterType::None,
3576
3577            // <https://w3c.github.io/webcrypto/#aes-ctr-registration>
3578            (Self::AesCtr, Operation::Encrypt) => ParameterType::AesCtrParams,
3579            (Self::AesCtr, Operation::Decrypt) => ParameterType::AesCtrParams,
3580            (Self::AesCtr, Operation::GenerateKey) => ParameterType::AesKeyGenParams,
3581            (Self::AesCtr, Operation::ImportKey) => ParameterType::None,
3582            (Self::AesCtr, Operation::ExportKey) => ParameterType::None,
3583            (Self::AesCtr, Operation::GetKeyLength) => ParameterType::AesDerivedKeyParams,
3584
3585            // <https://w3c.github.io/webcrypto/#aes-cbc-registration>
3586            (Self::AesCbc, Operation::Encrypt) => ParameterType::AesCbcParams,
3587            (Self::AesCbc, Operation::Decrypt) => ParameterType::AesCbcParams,
3588            (Self::AesCbc, Operation::GenerateKey) => ParameterType::AesKeyGenParams,
3589            (Self::AesCbc, Operation::ImportKey) => ParameterType::None,
3590            (Self::AesCbc, Operation::ExportKey) => ParameterType::None,
3591            (Self::AesCbc, Operation::GetKeyLength) => ParameterType::AesDerivedKeyParams,
3592
3593            // <https://w3c.github.io/webcrypto/#aes-gcm-registration>
3594            (Self::AesGcm, Operation::Encrypt) => ParameterType::AesGcmParams,
3595            (Self::AesGcm, Operation::Decrypt) => ParameterType::AesGcmParams,
3596            (Self::AesGcm, Operation::GenerateKey) => ParameterType::AesKeyGenParams,
3597            (Self::AesGcm, Operation::ImportKey) => ParameterType::None,
3598            (Self::AesGcm, Operation::ExportKey) => ParameterType::None,
3599            (Self::AesGcm, Operation::GetKeyLength) => ParameterType::AesDerivedKeyParams,
3600
3601            // <https://w3c.github.io/webcrypto/#aes-kw-registration>
3602            (Self::AesKw, Operation::WrapKey) => ParameterType::None,
3603            (Self::AesKw, Operation::UnwrapKey) => ParameterType::None,
3604            (Self::AesKw, Operation::GenerateKey) => ParameterType::AesKeyGenParams,
3605            (Self::AesKw, Operation::ImportKey) => ParameterType::None,
3606            (Self::AesKw, Operation::ExportKey) => ParameterType::None,
3607            (Self::AesKw, Operation::GetKeyLength) => ParameterType::AesDerivedKeyParams,
3608
3609            // <https://w3c.github.io/webcrypto/#hmac-registration>
3610            (Self::Hmac, Operation::Sign) => ParameterType::None,
3611            (Self::Hmac, Operation::Verify) => ParameterType::None,
3612            (Self::Hmac, Operation::GenerateKey) => ParameterType::HmacKeyGenParams,
3613            (Self::Hmac, Operation::ImportKey) => ParameterType::HmacImportParams,
3614            (Self::Hmac, Operation::ExportKey) => ParameterType::None,
3615            (Self::Hmac, Operation::GetKeyLength) => ParameterType::HmacImportParams,
3616
3617            // <https://w3c.github.io/webcrypto/#sha-registration>
3618            (Self::Sha(_), Operation::Digest) => ParameterType::None,
3619
3620            // <https://w3c.github.io/webcrypto/#hkdf-registration>
3621            (Self::Hkdf, Operation::DeriveBits) => ParameterType::HkdfParams,
3622            (Self::Hkdf, Operation::ImportKey) => ParameterType::None,
3623            (Self::Hkdf, Operation::GetKeyLength) => ParameterType::None,
3624
3625            // <https://w3c.github.io/webcrypto/#pbkdf2-registration>
3626            (Self::Pbkdf2, Operation::DeriveBits) => ParameterType::Pbkdf2Params,
3627            (Self::Pbkdf2, Operation::ImportKey) => ParameterType::None,
3628            (Self::Pbkdf2, Operation::GetKeyLength) => ParameterType::None,
3629
3630            // <https://wicg.github.io/webcrypto-modern-algos/#ml-kem-registration>
3631            (Self::MlKem(_), Operation::Encapsulate) => ParameterType::None,
3632            (Self::MlKem(_), Operation::Decapsulate) => ParameterType::None,
3633            (Self::MlKem(_), Operation::GenerateKey) => ParameterType::None,
3634            (Self::MlKem(_), Operation::ImportKey) => ParameterType::None,
3635            (Self::MlKem(_), Operation::ExportKey) => ParameterType::None,
3636
3637            // <https://wicg.github.io/webcrypto-modern-algos/#ml-dsa-registration>
3638            (Self::MlDsa(_), Operation::Sign) => ParameterType::ContextParams,
3639            (Self::MlDsa(_), Operation::Verify) => ParameterType::ContextParams,
3640            (Self::MlDsa(_), Operation::GenerateKey) => ParameterType::None,
3641            (Self::MlDsa(_), Operation::ImportKey) => ParameterType::None,
3642            (Self::MlDsa(_), Operation::ExportKey) => ParameterType::None,
3643
3644            // <https://wicg.github.io/webcrypto-modern-algos/#aes-ocb-registration>
3645            (Self::AesOcb, Operation::Encrypt) => ParameterType::AeadParams,
3646            (Self::AesOcb, Operation::Decrypt) => ParameterType::AeadParams,
3647            (Self::AesOcb, Operation::GenerateKey) => ParameterType::AesKeyGenParams,
3648            (Self::AesOcb, Operation::ImportKey) => ParameterType::None,
3649            (Self::AesOcb, Operation::ExportKey) => ParameterType::None,
3650            (Self::AesOcb, Operation::GetKeyLength) => ParameterType::AesDerivedKeyParams,
3651
3652            // <https://wicg.github.io/webcrypto-modern-algos/#chacha20-poly1305-registration>
3653            (Self::ChaCha20Poly1305, Operation::Encrypt) => ParameterType::AeadParams,
3654            (Self::ChaCha20Poly1305, Operation::Decrypt) => ParameterType::AeadParams,
3655            (Self::ChaCha20Poly1305, Operation::GenerateKey) => ParameterType::None,
3656            (Self::ChaCha20Poly1305, Operation::ImportKey) => ParameterType::None,
3657            (Self::ChaCha20Poly1305, Operation::ExportKey) => ParameterType::None,
3658            (Self::ChaCha20Poly1305, Operation::GetKeyLength) => ParameterType::None,
3659
3660            // <https://wicg.github.io/webcrypto-modern-algos/#sha3-registration>
3661            (Self::Sha3(_), Operation::Digest) => ParameterType::None,
3662
3663            // <https://wicg.github.io/webcrypto-modern-algos/#cshake-registration>
3664            (Self::CShake(_), Operation::Digest) => ParameterType::CShakeParams,
3665
3666            // <https://wicg.github.io/webcrypto-modern-algos/#argon2-registration>
3667            (Self::Argon2(_), Operation::DeriveBits) => ParameterType::Argon2Params,
3668            (Self::Argon2(_), Operation::ImportKey) => ParameterType::None,
3669            (Self::Argon2(_), Operation::GetKeyLength) => ParameterType::None,
3670
3671            _ => {
3672                return Err(Error::NotSupported(Some(format!(
3673                    "{} does not support {} operation",
3674                    self.as_str(),
3675                    op.as_str()
3676                ))));
3677            },
3678        };
3679
3680        Ok(desired_type)
3681    }
3682}
3683
3684impl TryFrom<&str> for SupportedAlgorithm {
3685    type Error = Error;
3686
3687    fn try_from(value: &str) -> Result<Self, Self::Error> {
3688        match value {
3689            ALG_RSASSA_PKCS1_V1_5 => Ok(SupportedAlgorithm::RsassaPkcs1V1_5),
3690            ALG_RSA_PSS => Ok(SupportedAlgorithm::RsaPss),
3691            ALG_RSA_OAEP => Ok(SupportedAlgorithm::RsaOaep),
3692            ALG_ECDSA => Ok(SupportedAlgorithm::Ecdsa),
3693            ALG_ECDH => Ok(SupportedAlgorithm::Ecdh),
3694            ALG_ED25519 => Ok(SupportedAlgorithm::Ed25519),
3695            ALG_X25519 => Ok(SupportedAlgorithm::X25519),
3696            ALG_AES_CTR => Ok(SupportedAlgorithm::AesCtr),
3697            ALG_AES_CBC => Ok(SupportedAlgorithm::AesCbc),
3698            ALG_AES_GCM => Ok(SupportedAlgorithm::AesGcm),
3699            ALG_AES_KW => Ok(SupportedAlgorithm::AesKw),
3700            ALG_HMAC => Ok(SupportedAlgorithm::Hmac),
3701            ALG_SHA1 => Ok(SupportedAlgorithm::Sha(ShaAlgorithm::Sha1)),
3702            ALG_SHA256 => Ok(SupportedAlgorithm::Sha(ShaAlgorithm::Sha256)),
3703            ALG_SHA384 => Ok(SupportedAlgorithm::Sha(ShaAlgorithm::Sha384)),
3704            ALG_SHA512 => Ok(SupportedAlgorithm::Sha(ShaAlgorithm::Sha512)),
3705            ALG_HKDF => Ok(SupportedAlgorithm::Hkdf),
3706            ALG_PBKDF2 => Ok(SupportedAlgorithm::Pbkdf2),
3707            ALG_ML_KEM_512 => Ok(SupportedAlgorithm::MlKem(MlKemAlgorithm::MlKem512)),
3708            ALG_ML_KEM_768 => Ok(SupportedAlgorithm::MlKem(MlKemAlgorithm::MlKem768)),
3709            ALG_ML_KEM_1024 => Ok(SupportedAlgorithm::MlKem(MlKemAlgorithm::MlKem1024)),
3710            ALG_ML_DSA_44 => Ok(SupportedAlgorithm::MlDsa(MlDsaAlgorithm::MlDsa44)),
3711            ALG_ML_DSA_65 => Ok(SupportedAlgorithm::MlDsa(MlDsaAlgorithm::MlDsa65)),
3712            ALG_ML_DSA_87 => Ok(SupportedAlgorithm::MlDsa(MlDsaAlgorithm::MlDsa87)),
3713            ALG_AES_OCB => Ok(SupportedAlgorithm::AesOcb),
3714            ALG_CHACHA20_POLY1305 => Ok(SupportedAlgorithm::ChaCha20Poly1305),
3715            ALG_SHA3_256 => Ok(SupportedAlgorithm::Sha3(Sha3Algorithm::Sha3_256)),
3716            ALG_SHA3_384 => Ok(SupportedAlgorithm::Sha3(Sha3Algorithm::Sha3_384)),
3717            ALG_SHA3_512 => Ok(SupportedAlgorithm::Sha3(Sha3Algorithm::Sha3_512)),
3718            ALG_CSHAKE_128 => Ok(SupportedAlgorithm::CShake(CShakeAlgorithm::CShake128)),
3719            ALG_CSHAKE_256 => Ok(SupportedAlgorithm::CShake(CShakeAlgorithm::CShake256)),
3720            ALG_ARGON2D => Ok(SupportedAlgorithm::Argon2(Argon2Algorithm::Argon2D)),
3721            ALG_ARGON2I => Ok(SupportedAlgorithm::Argon2(Argon2Algorithm::Argon2I)),
3722            ALG_ARGON2ID => Ok(SupportedAlgorithm::Argon2(Argon2Algorithm::Argon2ID)),
3723            _ => Err(Error::NotSupported(Some(format!(
3724                "Unsupported algorithm: {}",
3725                value
3726            )))),
3727        }
3728    }
3729}
3730
3731enum ParameterType {
3732    None,
3733    RsaHashedKeyGenParams,
3734    RsaHashedImportParams,
3735    RsaPssParams,
3736    RsaOaepParams,
3737    EcdsaParams,
3738    EcKeyGenParams,
3739    EcKeyImportParams,
3740    EcdhKeyDeriveParams,
3741    AesCtrParams,
3742    AesKeyGenParams,
3743    AesDerivedKeyParams,
3744    AesCbcParams,
3745    AesGcmParams,
3746    HmacImportParams,
3747    HmacKeyGenParams,
3748    HkdfParams,
3749    Pbkdf2Params,
3750    ContextParams,
3751    AeadParams,
3752    CShakeParams,
3753    Argon2Params,
3754}
3755
3756/// The successful output of [`normalize_algorithm`], in form of an union type of (our "subtle"
3757/// binding of) IDL dictionary types.
3758///
3759/// <https://w3c.github.io/webcrypto/#algorithm-normalization-normalize-an-algorithm>
3760#[derive(Clone, MallocSizeOf)]
3761enum NormalizedAlgorithm {
3762    Algorithm(SubtleAlgorithm),
3763    RsaHashedKeyGenParams(SubtleRsaHashedKeyGenParams),
3764    RsaHashedImportParams(SubtleRsaHashedImportParams),
3765    RsaPssParams(SubtleRsaPssParams),
3766    RsaOaepParams(SubtleRsaOaepParams),
3767    EcdsaParams(SubtleEcdsaParams),
3768    EcKeyGenParams(SubtleEcKeyGenParams),
3769    EcKeyImportParams(SubtleEcKeyImportParams),
3770    EcdhKeyDeriveParams(SubtleEcdhKeyDeriveParams),
3771    AesCtrParams(SubtleAesCtrParams),
3772    AesKeyGenParams(SubtleAesKeyGenParams),
3773    AesDerivedKeyParams(SubtleAesDerivedKeyParams),
3774    AesCbcParams(SubtleAesCbcParams),
3775    AesGcmParams(SubtleAesGcmParams),
3776    HmacImportParams(SubtleHmacImportParams),
3777    HmacKeyGenParams(SubtleHmacKeyGenParams),
3778    HkdfParams(SubtleHkdfParams),
3779    Pbkdf2Params(SubtlePbkdf2Params),
3780    ContextParams(SubtleContextParams),
3781    AeadParams(SubtleAeadParams),
3782    CShakeParams(SubtleCShakeParams),
3783    Argon2Params(SubtleArgon2Params),
3784}
3785
3786/// <https://w3c.github.io/webcrypto/#algorithm-normalization-normalize-an-algorithm>
3787fn normalize_algorithm(
3788    cx: JSContext,
3789    op: Operation,
3790    alg: &AlgorithmIdentifier,
3791    can_gc: CanGc,
3792) -> Result<NormalizedAlgorithm, Error> {
3793    match alg {
3794        // If alg is an instance of a DOMString:
3795        ObjectOrString::String(name) => {
3796            // Return the result of running the normalize an algorithm algorithm, with the alg set
3797            // to a new Algorithm dictionary whose name attribute is alg, and with the op set to
3798            // op.
3799            let alg = Algorithm {
3800                name: name.to_owned(),
3801            };
3802            rooted!(in(*cx) let mut alg_value = UndefinedValue());
3803            alg.safe_to_jsval(cx, alg_value.handle_mut(), CanGc::note());
3804            let alg_obj = RootedTraceableBox::new(Heap::default());
3805            alg_obj.set(alg_value.to_object());
3806            normalize_algorithm(cx, op, &ObjectOrString::Object(alg_obj), can_gc)
3807        },
3808        // If alg is an object:
3809        ObjectOrString::Object(obj) => {
3810            // Step 1. Let registeredAlgorithms be the associative container stored at the op key
3811            // of supportedAlgorithms.
3812            // NOTE: The supportedAlgorithms and registeredAlgorithms are expressed as match arms
3813            // in Step 5.2 - Step 10.
3814
3815            // Stpe 2. Let initialAlg be the result of converting the ECMAScript object represented
3816            // by alg to the IDL dictionary type Algorithm, as defined by [WebIDL].
3817            // Step 3. If an error occurred, return the error and terminate this algorithm.
3818            rooted!(in(*cx) let value = ObjectValue(obj.get()));
3819            let initial_alg = dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
3820
3821            // Step 4. Let algName be the value of the name attribute of initialAlg.
3822            // Step 5.
3823            //     If registeredAlgorithms contains a key that is a case-insensitive string match
3824            //     for algName:
3825            //         Step 5.1. Set algName to the value of the matching key.
3826            //         Step 5.2. Let desiredType be the IDL dictionary type stored at algName in
3827            //         registeredAlgorithms.
3828            //     Otherwise:
3829            //         Return a new NotSupportedError and terminate this algorithm.
3830            let alg_name = SupportedAlgorithm::from_ignore_case(&initial_alg.name.str())?;
3831            let desired_type = alg_name.support(op)?;
3832
3833            // Step 6. Let normalizedAlgorithm be the result of converting the ECMAScript object
3834            // represented by alg to the IDL dictionary type desiredType, as defined by [WebIDL].
3835            // Step 7. Set the name attribute of normalizedAlgorithm to algName.
3836            // Step 8. If an error occurred, return the error and terminate this algorithm.
3837            // Step 9. Let dictionaries be a list consisting of the IDL dictionary type desiredType
3838            // and all of desiredType's inherited dictionaries, in order from least to most
3839            // derived.
3840            // Step 10. For each dictionary dictionary in dictionaries:
3841            //     Step 10.1. For each dictionary member member declared on dictionary, in order:
3842            //         Step 10.1.1. Let key be the identifier of member.
3843            //         Step 10.1.2. Let idlValue be the value of the dictionary member with key
3844            //         name of key on normalizedAlgorithm.
3845            //         Step 10.1.3.
3846            //             If member is of the type BufferSource and is present:
3847            //                 Set the dictionary member on normalizedAlgorithm with key name key
3848            //                 to the result of getting a copy of the bytes held by idlValue,
3849            //                 replacing the current value.
3850            //             If member is of the type HashAlgorithmIdentifier:
3851            //                 Set the dictionary member on normalizedAlgorithm with key name key
3852            //                 to the result of normalizing an algorithm, with the alg set to
3853            //                 idlValue and the op set to "digest".
3854            //             If member is of the type AlgorithmIdentifier:
3855            //                 Set the dictionary member on normalizedAlgorithm with key name key
3856            //                 to the result of normalizing an algorithm, with the alg set to
3857            //                 idlValue and the op set to the operation defined by the
3858            //                 specification that defines the algorithm identified by algName.
3859            //
3860            // NOTE: We do Step 7 first, by setting algName to the name attribute of the JS object
3861            // before IDL dictionary conversion, in order to simplify our implementation.
3862            rooted!(in(*cx) let mut alg_name_ptr = UndefinedValue());
3863            alg_name
3864                .as_str()
3865                .safe_to_jsval(cx, alg_name_ptr.handle_mut(), can_gc);
3866            set_dictionary_property(cx, obj.handle(), c"name", alg_name_ptr.handle())
3867                .map_err(|_| Error::JSFailed)?;
3868            let normalized_algorithm =
3869                NormalizedAlgorithm::from_object_value(cx, value.handle(), desired_type, can_gc)?;
3870
3871            // Step 11. Return normalizedAlgorithm.
3872            Ok(normalized_algorithm)
3873        },
3874    }
3875}
3876
3877impl NormalizedAlgorithm {
3878    /// Step 6, 8-10 of the "normalize an algorithm" algorithm
3879    /// <https://w3c.github.io/webcrypto/#algorithm-normalization-normalize-an-algorithm>. This
3880    /// function converts the ECMAScript object represented to a normalized algorithm of the IDL
3881    /// dictionary type desiredType.
3882    ///
3883    /// Step 6 and Step 8 is done by `dictionary_from_jsval`.
3884    ///
3885    /// Step 9 and Step 10 is done by the `From` and `TryFrom` trait implementations of the inner
3886    /// types (the structs with prefix "Subtle" in their name) of NormalizedAlgorithm.
3887    fn from_object_value(
3888        cx: JSContext,
3889        value: HandleValue,
3890        desired_type: ParameterType,
3891        can_gc: CanGc,
3892    ) -> Result<NormalizedAlgorithm, Error> {
3893        let normalized_algorithm = match desired_type {
3894            ParameterType::None => NormalizedAlgorithm::Algorithm(
3895                dictionary_from_jsval::<Algorithm>(cx, value, can_gc)?.into(),
3896            ),
3897            ParameterType::RsaHashedKeyGenParams => NormalizedAlgorithm::RsaHashedKeyGenParams(
3898                dictionary_from_jsval::<RootedTraceableBox<RsaHashedKeyGenParams>>(
3899                    cx, value, can_gc,
3900                )?
3901                .try_into()?,
3902            ),
3903            ParameterType::RsaHashedImportParams => NormalizedAlgorithm::RsaHashedImportParams(
3904                dictionary_from_jsval::<RootedTraceableBox<RsaHashedImportParams>>(
3905                    cx, value, can_gc,
3906                )?
3907                .try_into()?,
3908            ),
3909            ParameterType::RsaPssParams => NormalizedAlgorithm::RsaPssParams(
3910                dictionary_from_jsval::<RsaPssParams>(cx, value, can_gc)?.into(),
3911            ),
3912            ParameterType::RsaOaepParams => NormalizedAlgorithm::RsaOaepParams(
3913                dictionary_from_jsval::<RootedTraceableBox<RsaOaepParams>>(cx, value, can_gc)?
3914                    .into(),
3915            ),
3916            ParameterType::EcdsaParams => NormalizedAlgorithm::EcdsaParams(
3917                dictionary_from_jsval::<RootedTraceableBox<EcdsaParams>>(cx, value, can_gc)?
3918                    .try_into()?,
3919            ),
3920            ParameterType::EcKeyGenParams => NormalizedAlgorithm::EcKeyGenParams(
3921                dictionary_from_jsval::<EcKeyGenParams>(cx, value, can_gc)?.into(),
3922            ),
3923            ParameterType::EcKeyImportParams => NormalizedAlgorithm::EcKeyImportParams(
3924                dictionary_from_jsval::<EcKeyImportParams>(cx, value, can_gc)?.into(),
3925            ),
3926            ParameterType::EcdhKeyDeriveParams => NormalizedAlgorithm::EcdhKeyDeriveParams(
3927                dictionary_from_jsval::<EcdhKeyDeriveParams>(cx, value, can_gc)?.into(),
3928            ),
3929            ParameterType::AesCtrParams => NormalizedAlgorithm::AesCtrParams(
3930                dictionary_from_jsval::<RootedTraceableBox<AesCtrParams>>(cx, value, can_gc)?
3931                    .into(),
3932            ),
3933            ParameterType::AesKeyGenParams => NormalizedAlgorithm::AesKeyGenParams(
3934                dictionary_from_jsval::<AesKeyGenParams>(cx, value, can_gc)?.into(),
3935            ),
3936            ParameterType::AesDerivedKeyParams => NormalizedAlgorithm::AesDerivedKeyParams(
3937                dictionary_from_jsval::<AesDerivedKeyParams>(cx, value, can_gc)?.into(),
3938            ),
3939            ParameterType::AesCbcParams => NormalizedAlgorithm::AesCbcParams(
3940                dictionary_from_jsval::<RootedTraceableBox<AesCbcParams>>(cx, value, can_gc)?
3941                    .into(),
3942            ),
3943            ParameterType::AesGcmParams => NormalizedAlgorithm::AesGcmParams(
3944                dictionary_from_jsval::<RootedTraceableBox<AesGcmParams>>(cx, value, can_gc)?
3945                    .into(),
3946            ),
3947            ParameterType::HmacImportParams => NormalizedAlgorithm::HmacImportParams(
3948                dictionary_from_jsval::<RootedTraceableBox<HmacImportParams>>(cx, value, can_gc)?
3949                    .try_into()?,
3950            ),
3951            ParameterType::HmacKeyGenParams => NormalizedAlgorithm::HmacKeyGenParams(
3952                dictionary_from_jsval::<RootedTraceableBox<HmacKeyGenParams>>(cx, value, can_gc)?
3953                    .try_into()?,
3954            ),
3955            ParameterType::HkdfParams => NormalizedAlgorithm::HkdfParams(
3956                dictionary_from_jsval::<RootedTraceableBox<HkdfParams>>(cx, value, can_gc)?
3957                    .try_into()?,
3958            ),
3959            ParameterType::Pbkdf2Params => NormalizedAlgorithm::Pbkdf2Params(
3960                dictionary_from_jsval::<RootedTraceableBox<Pbkdf2Params>>(cx, value, can_gc)?
3961                    .try_into()?,
3962            ),
3963            ParameterType::ContextParams => NormalizedAlgorithm::ContextParams(
3964                dictionary_from_jsval::<RootedTraceableBox<ContextParams>>(cx, value, can_gc)?
3965                    .into(),
3966            ),
3967            ParameterType::AeadParams => NormalizedAlgorithm::AeadParams(
3968                dictionary_from_jsval::<RootedTraceableBox<AeadParams>>(cx, value, can_gc)?.into(),
3969            ),
3970            ParameterType::CShakeParams => NormalizedAlgorithm::CShakeParams(
3971                dictionary_from_jsval::<RootedTraceableBox<CShakeParams>>(cx, value, can_gc)?
3972                    .into(),
3973            ),
3974            ParameterType::Argon2Params => NormalizedAlgorithm::Argon2Params(
3975                dictionary_from_jsval::<RootedTraceableBox<Argon2Params>>(cx, value, can_gc)?
3976                    .into(),
3977            ),
3978        };
3979
3980        Ok(normalized_algorithm)
3981    }
3982
3983    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
3984    fn name(&self) -> &str {
3985        match self {
3986            NormalizedAlgorithm::Algorithm(algo) => &algo.name,
3987            NormalizedAlgorithm::RsaHashedKeyGenParams(algo) => &algo.name,
3988            NormalizedAlgorithm::RsaHashedImportParams(algo) => &algo.name,
3989            NormalizedAlgorithm::RsaPssParams(algo) => &algo.name,
3990            NormalizedAlgorithm::RsaOaepParams(algo) => &algo.name,
3991            NormalizedAlgorithm::EcdsaParams(algo) => &algo.name,
3992            NormalizedAlgorithm::EcKeyGenParams(algo) => &algo.name,
3993            NormalizedAlgorithm::EcKeyImportParams(algo) => &algo.name,
3994            NormalizedAlgorithm::EcdhKeyDeriveParams(algo) => &algo.name,
3995            NormalizedAlgorithm::AesCtrParams(algo) => &algo.name,
3996            NormalizedAlgorithm::AesKeyGenParams(algo) => &algo.name,
3997            NormalizedAlgorithm::AesDerivedKeyParams(algo) => &algo.name,
3998            NormalizedAlgorithm::AesCbcParams(algo) => &algo.name,
3999            NormalizedAlgorithm::AesGcmParams(algo) => &algo.name,
4000            NormalizedAlgorithm::HmacImportParams(algo) => &algo.name,
4001            NormalizedAlgorithm::HmacKeyGenParams(algo) => &algo.name,
4002            NormalizedAlgorithm::HkdfParams(algo) => &algo.name,
4003            NormalizedAlgorithm::Pbkdf2Params(algo) => &algo.name,
4004            NormalizedAlgorithm::ContextParams(algo) => &algo.name,
4005            NormalizedAlgorithm::AeadParams(algo) => &algo.name,
4006            NormalizedAlgorithm::CShakeParams(algo) => &algo.name,
4007            NormalizedAlgorithm::Argon2Params(algo) => &algo.name,
4008        }
4009    }
4010
4011    fn encrypt(&self, key: &CryptoKey, plaintext: &[u8]) -> Result<Vec<u8>, Error> {
4012        match (self.name(), self) {
4013            (ALG_RSA_OAEP, NormalizedAlgorithm::RsaOaepParams(algo)) => {
4014                rsa_oaep_operation::encrypt(algo, key, plaintext)
4015            },
4016            (ALG_AES_CTR, NormalizedAlgorithm::AesCtrParams(algo)) => {
4017                aes_ctr_operation::encrypt(algo, key, plaintext)
4018            },
4019            (ALG_AES_CBC, NormalizedAlgorithm::AesCbcParams(algo)) => {
4020                aes_cbc_operation::encrypt(algo, key, plaintext)
4021            },
4022            (ALG_AES_GCM, NormalizedAlgorithm::AesGcmParams(algo)) => {
4023                aes_gcm_operation::encrypt(algo, key, plaintext)
4024            },
4025            (ALG_AES_OCB, NormalizedAlgorithm::AeadParams(algo)) => {
4026                aes_ocb_operation::encrypt(algo, key, plaintext)
4027            },
4028            (ALG_CHACHA20_POLY1305, NormalizedAlgorithm::AeadParams(algo)) => {
4029                chacha20_poly1305_operation::encrypt(algo, key, plaintext)
4030            },
4031            _ => Err(Error::NotSupported(None)),
4032        }
4033    }
4034
4035    fn decrypt(&self, key: &CryptoKey, ciphertext: &[u8]) -> Result<Vec<u8>, Error> {
4036        match (self.name(), self) {
4037            (ALG_RSA_OAEP, NormalizedAlgorithm::RsaOaepParams(algo)) => {
4038                rsa_oaep_operation::decrypt(algo, key, ciphertext)
4039            },
4040            (ALG_AES_CTR, NormalizedAlgorithm::AesCtrParams(algo)) => {
4041                aes_ctr_operation::decrypt(algo, key, ciphertext)
4042            },
4043            (ALG_AES_CBC, NormalizedAlgorithm::AesCbcParams(algo)) => {
4044                aes_cbc_operation::decrypt(algo, key, ciphertext)
4045            },
4046            (ALG_AES_GCM, NormalizedAlgorithm::AesGcmParams(algo)) => {
4047                aes_gcm_operation::decrypt(algo, key, ciphertext)
4048            },
4049            (ALG_AES_OCB, NormalizedAlgorithm::AeadParams(algo)) => {
4050                aes_ocb_operation::decrypt(algo, key, ciphertext)
4051            },
4052            (ALG_CHACHA20_POLY1305, NormalizedAlgorithm::AeadParams(algo)) => {
4053                chacha20_poly1305_operation::decrypt(algo, key, ciphertext)
4054            },
4055            _ => Err(Error::NotSupported(None)),
4056        }
4057    }
4058
4059    fn sign(&self, key: &CryptoKey, message: &[u8]) -> Result<Vec<u8>, Error> {
4060        match (self.name(), self) {
4061            (ALG_RSASSA_PKCS1_V1_5, NormalizedAlgorithm::Algorithm(_algo)) => {
4062                rsassa_pkcs1_v1_5_operation::sign(key, message)
4063            },
4064            (ALG_RSA_PSS, NormalizedAlgorithm::RsaPssParams(algo)) => {
4065                rsa_pss_operation::sign(algo, key, message)
4066            },
4067            (ALG_ECDSA, NormalizedAlgorithm::EcdsaParams(algo)) => {
4068                ecdsa_operation::sign(algo, key, message)
4069            },
4070            (ALG_ED25519, NormalizedAlgorithm::Algorithm(_algo)) => {
4071                ed25519_operation::sign(key, message)
4072            },
4073            (ALG_HMAC, NormalizedAlgorithm::Algorithm(_algo)) => hmac_operation::sign(key, message),
4074            (
4075                ALG_ML_DSA_44 | ALG_ML_DSA_65 | ALG_ML_DSA_87,
4076                NormalizedAlgorithm::ContextParams(algo),
4077            ) => ml_dsa_operation::sign(algo, key, message),
4078            _ => Err(Error::NotSupported(None)),
4079        }
4080    }
4081
4082    fn verify(&self, key: &CryptoKey, message: &[u8], signature: &[u8]) -> Result<bool, Error> {
4083        match (self.name(), self) {
4084            (ALG_RSASSA_PKCS1_V1_5, NormalizedAlgorithm::Algorithm(_algo)) => {
4085                rsassa_pkcs1_v1_5_operation::verify(key, message, signature)
4086            },
4087            (ALG_RSA_PSS, NormalizedAlgorithm::RsaPssParams(algo)) => {
4088                rsa_pss_operation::verify(algo, key, message, signature)
4089            },
4090            (ALG_ECDSA, NormalizedAlgorithm::EcdsaParams(algo)) => {
4091                ecdsa_operation::verify(algo, key, message, signature)
4092            },
4093            (ALG_ED25519, NormalizedAlgorithm::Algorithm(_algo)) => {
4094                ed25519_operation::verify(key, message, signature)
4095            },
4096            (ALG_HMAC, NormalizedAlgorithm::Algorithm(_algo)) => {
4097                hmac_operation::verify(key, message, signature)
4098            },
4099            (
4100                ALG_ML_DSA_44 | ALG_ML_DSA_65 | ALG_ML_DSA_87,
4101                NormalizedAlgorithm::ContextParams(algo),
4102            ) => ml_dsa_operation::verify(algo, key, message, signature),
4103            _ => Err(Error::NotSupported(None)),
4104        }
4105    }
4106
4107    fn digest(&self, message: &[u8]) -> Result<Vec<u8>, Error> {
4108        match (self.name(), self) {
4109            (ALG_SHA1, NormalizedAlgorithm::Algorithm(algo)) => {
4110                sha_operation::digest(algo, message)
4111            },
4112            (ALG_SHA256, NormalizedAlgorithm::Algorithm(algo)) => {
4113                sha_operation::digest(algo, message)
4114            },
4115            (ALG_SHA384, NormalizedAlgorithm::Algorithm(algo)) => {
4116                sha_operation::digest(algo, message)
4117            },
4118            (ALG_SHA512, NormalizedAlgorithm::Algorithm(algo)) => {
4119                sha_operation::digest(algo, message)
4120            },
4121            (ALG_SHA3_256, NormalizedAlgorithm::Algorithm(algo)) => {
4122                sha3_operation::digest(algo, message)
4123            },
4124            (ALG_SHA3_384, NormalizedAlgorithm::Algorithm(algo)) => {
4125                sha3_operation::digest(algo, message)
4126            },
4127            (ALG_SHA3_512, NormalizedAlgorithm::Algorithm(algo)) => {
4128                sha3_operation::digest(algo, message)
4129            },
4130            (ALG_CSHAKE_128, NormalizedAlgorithm::CShakeParams(algo)) => {
4131                cshake_operation::digest(algo, message)
4132            },
4133            (ALG_CSHAKE_256, NormalizedAlgorithm::CShakeParams(algo)) => {
4134                cshake_operation::digest(algo, message)
4135            },
4136            _ => Err(Error::NotSupported(None)),
4137        }
4138    }
4139
4140    fn generate_key(
4141        &self,
4142        global: &GlobalScope,
4143        extractable: bool,
4144        usages: Vec<KeyUsage>,
4145        can_gc: CanGc,
4146    ) -> Result<CryptoKeyOrCryptoKeyPair, Error> {
4147        match (self.name(), self) {
4148            (ALG_RSASSA_PKCS1_V1_5, NormalizedAlgorithm::RsaHashedKeyGenParams(algo)) => {
4149                rsassa_pkcs1_v1_5_operation::generate_key(global, algo, extractable, usages, can_gc)
4150                    .map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
4151            },
4152            (ALG_RSA_PSS, NormalizedAlgorithm::RsaHashedKeyGenParams(algo)) => {
4153                rsa_pss_operation::generate_key(global, algo, extractable, usages, can_gc)
4154                    .map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
4155            },
4156            (ALG_RSA_OAEP, NormalizedAlgorithm::RsaHashedKeyGenParams(algo)) => {
4157                rsa_oaep_operation::generate_key(global, algo, extractable, usages, can_gc)
4158                    .map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
4159            },
4160            (ALG_ECDSA, NormalizedAlgorithm::EcKeyGenParams(algo)) => {
4161                ecdsa_operation::generate_key(global, algo, extractable, usages, can_gc)
4162                    .map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
4163            },
4164            (ALG_ECDH, NormalizedAlgorithm::EcKeyGenParams(algo)) => {
4165                ecdh_operation::generate_key(global, algo, extractable, usages, can_gc)
4166                    .map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
4167            },
4168            (ALG_ED25519, NormalizedAlgorithm::Algorithm(_algo)) => {
4169                ed25519_operation::generate_key(global, extractable, usages, can_gc)
4170                    .map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
4171            },
4172            (ALG_X25519, NormalizedAlgorithm::Algorithm(_algo)) => {
4173                x25519_operation::generate_key(global, extractable, usages, can_gc)
4174                    .map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
4175            },
4176            (ALG_AES_CTR, NormalizedAlgorithm::AesKeyGenParams(algo)) => {
4177                aes_ctr_operation::generate_key(global, algo, extractable, usages, can_gc)
4178                    .map(CryptoKeyOrCryptoKeyPair::CryptoKey)
4179            },
4180            (ALG_AES_CBC, NormalizedAlgorithm::AesKeyGenParams(algo)) => {
4181                aes_cbc_operation::generate_key(global, algo, extractable, usages, can_gc)
4182                    .map(CryptoKeyOrCryptoKeyPair::CryptoKey)
4183            },
4184            (ALG_AES_GCM, NormalizedAlgorithm::AesKeyGenParams(algo)) => {
4185                aes_gcm_operation::generate_key(global, algo, extractable, usages, can_gc)
4186                    .map(CryptoKeyOrCryptoKeyPair::CryptoKey)
4187            },
4188            (ALG_AES_KW, NormalizedAlgorithm::AesKeyGenParams(algo)) => {
4189                aes_kw_operation::generate_key(global, algo, extractable, usages, can_gc)
4190                    .map(CryptoKeyOrCryptoKeyPair::CryptoKey)
4191            },
4192            (ALG_HMAC, NormalizedAlgorithm::HmacKeyGenParams(algo)) => {
4193                hmac_operation::generate_key(global, algo, extractable, usages, can_gc)
4194                    .map(CryptoKeyOrCryptoKeyPair::CryptoKey)
4195            },
4196            (
4197                ALG_ML_KEM_512 | ALG_ML_KEM_768 | ALG_ML_KEM_1024,
4198                NormalizedAlgorithm::Algorithm(algo),
4199            ) => ml_kem_operation::generate_key(global, algo, extractable, usages, can_gc)
4200                .map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair),
4201            (
4202                ALG_ML_DSA_44 | ALG_ML_DSA_65 | ALG_ML_DSA_87,
4203                NormalizedAlgorithm::Algorithm(algo),
4204            ) => ml_dsa_operation::generate_key(global, algo, extractable, usages, can_gc)
4205                .map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair),
4206            (ALG_AES_OCB, NormalizedAlgorithm::AesKeyGenParams(algo)) => {
4207                aes_ocb_operation::generate_key(global, algo, extractable, usages, can_gc)
4208                    .map(CryptoKeyOrCryptoKeyPair::CryptoKey)
4209            },
4210            (ALG_CHACHA20_POLY1305, NormalizedAlgorithm::Algorithm(_algo)) => {
4211                chacha20_poly1305_operation::generate_key(global, extractable, usages, can_gc)
4212                    .map(CryptoKeyOrCryptoKeyPair::CryptoKey)
4213            },
4214            _ => Err(Error::NotSupported(None)),
4215        }
4216    }
4217
4218    fn derive_bits(&self, key: &CryptoKey, length: Option<u32>) -> Result<Vec<u8>, Error> {
4219        match (self.name(), self) {
4220            (ALG_ECDH, NormalizedAlgorithm::EcdhKeyDeriveParams(algo)) => {
4221                ecdh_operation::derive_bits(algo, key, length)
4222            },
4223            (ALG_X25519, NormalizedAlgorithm::EcdhKeyDeriveParams(algo)) => {
4224                x25519_operation::derive_bits(algo, key, length)
4225            },
4226            (ALG_HKDF, NormalizedAlgorithm::HkdfParams(algo)) => {
4227                hkdf_operation::derive_bits(algo, key, length)
4228            },
4229            (ALG_PBKDF2, NormalizedAlgorithm::Pbkdf2Params(algo)) => {
4230                pbkdf2_operation::derive_bits(algo, key, length)
4231            },
4232            (ALG_ARGON2D, NormalizedAlgorithm::Argon2Params(algo)) => {
4233                argon2_operation::derive_bits(algo, key, length)
4234            },
4235            (ALG_ARGON2I, NormalizedAlgorithm::Argon2Params(algo)) => {
4236                argon2_operation::derive_bits(algo, key, length)
4237            },
4238            (ALG_ARGON2ID, NormalizedAlgorithm::Argon2Params(algo)) => {
4239                argon2_operation::derive_bits(algo, key, length)
4240            },
4241            _ => Err(Error::NotSupported(None)),
4242        }
4243    }
4244
4245    fn import_key(
4246        &self,
4247        global: &GlobalScope,
4248        format: KeyFormat,
4249        key_data: &[u8],
4250        extractable: bool,
4251        usages: Vec<KeyUsage>,
4252        can_gc: CanGc,
4253    ) -> Result<DomRoot<CryptoKey>, Error> {
4254        match (self.name(), self) {
4255            (ALG_RSASSA_PKCS1_V1_5, NormalizedAlgorithm::RsaHashedImportParams(algo)) => {
4256                rsassa_pkcs1_v1_5_operation::import_key(
4257                    global,
4258                    algo,
4259                    format,
4260                    key_data,
4261                    extractable,
4262                    usages,
4263                    can_gc,
4264                )
4265            },
4266            (ALG_RSA_PSS, NormalizedAlgorithm::RsaHashedImportParams(algo)) => {
4267                rsa_pss_operation::import_key(
4268                    global,
4269                    algo,
4270                    format,
4271                    key_data,
4272                    extractable,
4273                    usages,
4274                    can_gc,
4275                )
4276            },
4277            (ALG_RSA_OAEP, NormalizedAlgorithm::RsaHashedImportParams(algo)) => {
4278                rsa_oaep_operation::import_key(
4279                    global,
4280                    algo,
4281                    format,
4282                    key_data,
4283                    extractable,
4284                    usages,
4285                    can_gc,
4286                )
4287            },
4288            (ALG_ECDSA, NormalizedAlgorithm::EcKeyImportParams(algo)) => {
4289                ecdsa_operation::import_key(
4290                    global,
4291                    algo,
4292                    format,
4293                    key_data,
4294                    extractable,
4295                    usages,
4296                    can_gc,
4297                )
4298            },
4299            (ALG_ECDH, NormalizedAlgorithm::EcKeyImportParams(algo)) => ecdh_operation::import_key(
4300                global,
4301                algo,
4302                format,
4303                key_data,
4304                extractable,
4305                usages,
4306                can_gc,
4307            ),
4308            (ALG_ED25519, NormalizedAlgorithm::Algorithm(_algo)) => {
4309                ed25519_operation::import_key(global, format, key_data, extractable, usages, can_gc)
4310            },
4311            (ALG_X25519, NormalizedAlgorithm::Algorithm(_algo)) => {
4312                x25519_operation::import_key(global, format, key_data, extractable, usages, can_gc)
4313            },
4314            (ALG_AES_CTR, NormalizedAlgorithm::Algorithm(_algo)) => {
4315                aes_ctr_operation::import_key(global, format, key_data, extractable, usages, can_gc)
4316            },
4317            (ALG_AES_CBC, NormalizedAlgorithm::Algorithm(_algo)) => {
4318                aes_cbc_operation::import_key(global, format, key_data, extractable, usages, can_gc)
4319            },
4320            (ALG_AES_GCM, NormalizedAlgorithm::Algorithm(_algo)) => {
4321                aes_gcm_operation::import_key(global, format, key_data, extractable, usages, can_gc)
4322            },
4323            (ALG_AES_KW, NormalizedAlgorithm::Algorithm(_algo)) => {
4324                aes_kw_operation::import_key(global, format, key_data, extractable, usages, can_gc)
4325            },
4326            (ALG_HMAC, NormalizedAlgorithm::HmacImportParams(algo)) => hmac_operation::import_key(
4327                global,
4328                algo,
4329                format,
4330                key_data,
4331                extractable,
4332                usages,
4333                can_gc,
4334            ),
4335            (ALG_HKDF, NormalizedAlgorithm::Algorithm(_algo)) => {
4336                hkdf_operation::import_key(global, format, key_data, extractable, usages, can_gc)
4337            },
4338            (ALG_PBKDF2, NormalizedAlgorithm::Algorithm(_algo)) => {
4339                pbkdf2_operation::import_key(global, format, key_data, extractable, usages, can_gc)
4340            },
4341            (
4342                ALG_ML_KEM_512 | ALG_ML_KEM_768 | ALG_ML_KEM_1024,
4343                NormalizedAlgorithm::Algorithm(algo),
4344            ) => ml_kem_operation::import_key(
4345                global,
4346                algo,
4347                format,
4348                key_data,
4349                extractable,
4350                usages,
4351                can_gc,
4352            ),
4353            (
4354                ALG_ML_DSA_44 | ALG_ML_DSA_65 | ALG_ML_DSA_87,
4355                NormalizedAlgorithm::Algorithm(algo),
4356            ) => ml_dsa_operation::import_key(
4357                global,
4358                algo,
4359                format,
4360                key_data,
4361                extractable,
4362                usages,
4363                can_gc,
4364            ),
4365            (ALG_AES_OCB, NormalizedAlgorithm::Algorithm(_algo)) => {
4366                aes_ocb_operation::import_key(global, format, key_data, extractable, usages, can_gc)
4367            },
4368            (ALG_CHACHA20_POLY1305, NormalizedAlgorithm::Algorithm(_algo)) => {
4369                chacha20_poly1305_operation::import_key(
4370                    global,
4371                    format,
4372                    key_data,
4373                    extractable,
4374                    usages,
4375                    can_gc,
4376                )
4377            },
4378            (ALG_ARGON2D, NormalizedAlgorithm::Algorithm(algo)) => argon2_operation::import_key(
4379                global,
4380                algo,
4381                format,
4382                key_data,
4383                extractable,
4384                usages,
4385                can_gc,
4386            ),
4387            (ALG_ARGON2I, NormalizedAlgorithm::Algorithm(algo)) => argon2_operation::import_key(
4388                global,
4389                algo,
4390                format,
4391                key_data,
4392                extractable,
4393                usages,
4394                can_gc,
4395            ),
4396            (ALG_ARGON2ID, NormalizedAlgorithm::Algorithm(algo)) => argon2_operation::import_key(
4397                global,
4398                algo,
4399                format,
4400                key_data,
4401                extractable,
4402                usages,
4403                can_gc,
4404            ),
4405            _ => Err(Error::NotSupported(None)),
4406        }
4407    }
4408
4409    fn wrap_key(&self, key: &CryptoKey, plaintext: &[u8]) -> Result<Vec<u8>, Error> {
4410        match (self.name(), self) {
4411            (ALG_AES_KW, NormalizedAlgorithm::Algorithm(_algo)) => {
4412                aes_kw_operation::wrap_key(key, plaintext)
4413            },
4414            _ => Err(Error::NotSupported(None)),
4415        }
4416    }
4417
4418    fn unwrap_key(&self, key: &CryptoKey, ciphertext: &[u8]) -> Result<Vec<u8>, Error> {
4419        match (self.name(), self) {
4420            (ALG_AES_KW, NormalizedAlgorithm::Algorithm(_algo)) => {
4421                aes_kw_operation::unwrap_key(key, ciphertext)
4422            },
4423            _ => Err(Error::NotSupported(None)),
4424        }
4425    }
4426
4427    fn get_key_length(&self) -> Result<Option<u32>, Error> {
4428        match (self.name(), self) {
4429            (ALG_AES_CTR, NormalizedAlgorithm::AesDerivedKeyParams(algo)) => {
4430                aes_ctr_operation::get_key_length(algo)
4431            },
4432            (ALG_AES_CBC, NormalizedAlgorithm::AesDerivedKeyParams(algo)) => {
4433                aes_cbc_operation::get_key_length(algo)
4434            },
4435            (ALG_AES_GCM, NormalizedAlgorithm::AesDerivedKeyParams(algo)) => {
4436                aes_gcm_operation::get_key_length(algo)
4437            },
4438            (ALG_AES_KW, NormalizedAlgorithm::AesDerivedKeyParams(algo)) => {
4439                aes_kw_operation::get_key_length(algo)
4440            },
4441            (ALG_HMAC, NormalizedAlgorithm::HmacImportParams(algo)) => {
4442                hmac_operation::get_key_length(algo)
4443            },
4444            (ALG_HKDF, NormalizedAlgorithm::Algorithm(_algo)) => hkdf_operation::get_key_length(),
4445            (ALG_PBKDF2, NormalizedAlgorithm::Algorithm(_algo)) => {
4446                pbkdf2_operation::get_key_length()
4447            },
4448            (ALG_AES_OCB, NormalizedAlgorithm::AesDerivedKeyParams(algo)) => {
4449                aes_ocb_operation::get_key_length(algo)
4450            },
4451            (ALG_CHACHA20_POLY1305, NormalizedAlgorithm::Algorithm(_algo)) => {
4452                chacha20_poly1305_operation::get_key_length()
4453            },
4454            (ALG_ARGON2D, NormalizedAlgorithm::Algorithm(_algo)) => {
4455                argon2_operation::get_key_length()
4456            },
4457            (ALG_ARGON2I, NormalizedAlgorithm::Algorithm(_algo)) => {
4458                argon2_operation::get_key_length()
4459            },
4460            (ALG_ARGON2ID, NormalizedAlgorithm::Algorithm(_algo)) => {
4461                argon2_operation::get_key_length()
4462            },
4463            _ => Err(Error::NotSupported(None)),
4464        }
4465    }
4466
4467    fn encapsulate(&self, key: &CryptoKey) -> Result<SubtleEncapsulatedBits, Error> {
4468        match (self.name(), self) {
4469            (
4470                ALG_ML_KEM_512 | ALG_ML_KEM_768 | ALG_ML_KEM_1024,
4471                NormalizedAlgorithm::Algorithm(algo),
4472            ) => ml_kem_operation::encapsulate(algo, key),
4473            _ => Err(Error::NotSupported(None)),
4474        }
4475    }
4476
4477    fn decapsulate(&self, key: &CryptoKey, ciphertext: &[u8]) -> Result<Vec<u8>, Error> {
4478        match (self.name(), self) {
4479            (
4480                ALG_ML_KEM_512 | ALG_ML_KEM_768 | ALG_ML_KEM_1024,
4481                NormalizedAlgorithm::Algorithm(algo),
4482            ) => ml_kem_operation::decapsulate(algo, key, ciphertext),
4483            _ => Err(Error::NotSupported(None)),
4484        }
4485    }
4486}
4487
4488/// Return the result of performing the export key operation specified by the [[algorithm]]
4489/// internal slot of key using key and format.
4490///
4491/// According to the WebCrypto API spec, the export key operation does not rely on the algorithm
4492/// normalization, We create this helper function to minic the functions of NormalizedAlgorithm
4493/// for export key operation.
4494fn perform_export_key_operation(format: KeyFormat, key: &CryptoKey) -> Result<ExportedKey, Error> {
4495    match key.algorithm().name() {
4496        ALG_RSASSA_PKCS1_V1_5 => rsassa_pkcs1_v1_5_operation::export_key(format, key),
4497        ALG_RSA_PSS => rsa_pss_operation::export_key(format, key),
4498        ALG_RSA_OAEP => rsa_oaep_operation::export_key(format, key),
4499        ALG_ECDSA => ecdsa_operation::export_key(format, key),
4500        ALG_ECDH => ecdh_operation::export_key(format, key),
4501        ALG_ED25519 => ed25519_operation::export_key(format, key),
4502        ALG_X25519 => x25519_operation::export_key(format, key),
4503        ALG_AES_CTR => aes_ctr_operation::export_key(format, key),
4504        ALG_AES_CBC => aes_cbc_operation::export_key(format, key),
4505        ALG_AES_GCM => aes_gcm_operation::export_key(format, key),
4506        ALG_AES_KW => aes_kw_operation::export_key(format, key),
4507        ALG_HMAC => hmac_operation::export_key(format, key),
4508        ALG_ML_KEM_512 | ALG_ML_KEM_768 | ALG_ML_KEM_1024 => {
4509            ml_kem_operation::export_key(format, key)
4510        },
4511        ALG_ML_DSA_44 | ALG_ML_DSA_65 | ALG_ML_DSA_87 => ml_dsa_operation::export_key(format, key),
4512        ALG_AES_OCB => aes_ocb_operation::export_key(format, key),
4513        ALG_CHACHA20_POLY1305 => chacha20_poly1305_operation::export_key(format, key),
4514        _ => Err(Error::NotSupported(None)),
4515    }
4516}