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_operation;
6mod argon2_operation;
7mod chacha20_poly1305_operation;
8mod cshake_operation;
9mod ecdh_operation;
10mod ecdsa_operation;
11mod ed25519_operation;
12mod hkdf_operation;
13mod hmac_operation;
14mod pbkdf2_operation;
15mod sha3_operation;
16mod sha_operation;
17mod x25519_operation;
18
19use std::ptr;
20use std::rc::Rc;
21use std::str::FromStr;
22
23use dom_struct::dom_struct;
24use js::conversions::ConversionResult;
25use js::jsapi::{Heap, JSObject};
26use js::jsval::{ObjectValue, UndefinedValue};
27use js::rust::wrappers::JS_ParseJSON;
28use js::rust::{HandleValue, MutableHandleValue};
29use js::typedarray::ArrayBufferU8;
30
31use crate::dom::bindings::buffer_source::create_buffer_source;
32use crate::dom::bindings::codegen::Bindings::CryptoKeyBinding::{
33    CryptoKeyMethods, CryptoKeyPair, KeyType, KeyUsage,
34};
35use crate::dom::bindings::codegen::Bindings::SubtleCryptoBinding::{
36    AeadParams, AesCbcParams, AesCtrParams, AesDerivedKeyParams, AesGcmParams, AesKeyAlgorithm,
37    AesKeyGenParams, Algorithm, AlgorithmIdentifier, Argon2Params, CShakeParams, EcKeyAlgorithm,
38    EcKeyGenParams, EcKeyImportParams, EcdhKeyDeriveParams, EcdsaParams, HkdfParams,
39    HmacImportParams, HmacKeyAlgorithm, HmacKeyGenParams, JsonWebKey, KeyAlgorithm, KeyFormat,
40    Pbkdf2Params, RsaOtherPrimesInfo, SubtleCryptoMethods,
41};
42use crate::dom::bindings::codegen::UnionTypes::{
43    ArrayBufferViewOrArrayBuffer, ArrayBufferViewOrArrayBufferOrJsonWebKey, ObjectOrString,
44};
45use crate::dom::bindings::conversions::{SafeFromJSValConvertible, SafeToJSValConvertible};
46use crate::dom::bindings::error::{Error, Fallible};
47use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
48use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
49use crate::dom::bindings::root::DomRoot;
50use crate::dom::bindings::str::{DOMString, serialize_jsval_to_json_utf8};
51use crate::dom::bindings::trace::RootedTraceableBox;
52use crate::dom::cryptokey::{CryptoKey, CryptoKeyOrCryptoKeyPair};
53use crate::dom::globalscope::GlobalScope;
54use crate::dom::promise::Promise;
55use crate::realms::InRealm;
56use crate::script_runtime::{CanGc, JSContext};
57
58// Regconized algorithm name from <https://w3c.github.io/webcrypto/>
59const ALG_RSASSA_PKCS1: &str = "RSASSA-PKCS1-v1_5";
60const ALG_RSA_PSS: &str = "RSA-PSS";
61const ALG_RSA_OAEP: &str = "RSA-OAEP";
62const ALG_ECDSA: &str = "ECDSA";
63const ALG_ECDH: &str = "ECDH";
64const ALG_ED25519: &str = "Ed25519";
65const ALG_X25519: &str = "X25519";
66const ALG_AES_CTR: &str = "AES-CTR";
67const ALG_AES_CBC: &str = "AES-CBC";
68const ALG_AES_GCM: &str = "AES-GCM";
69const ALG_AES_KW: &str = "AES-KW";
70const ALG_HMAC: &str = "HMAC";
71const ALG_SHA1: &str = "SHA-1";
72const ALG_SHA256: &str = "SHA-256";
73const ALG_SHA384: &str = "SHA-384";
74const ALG_SHA512: &str = "SHA-512";
75const ALG_HKDF: &str = "HKDF";
76const ALG_PBKDF2: &str = "PBKDF2";
77
78// Regconized algorithm name from <https://wicg.github.io/webcrypto-modern-algos/>
79const ALG_CHACHA20_POLY1305: &str = "ChaCha20-Poly1305";
80const ALG_SHA3_256: &str = "SHA3-256";
81const ALG_SHA3_384: &str = "SHA3-384";
82const ALG_SHA3_512: &str = "SHA3-512";
83const ALG_CSHAKE_128: &str = "cSHAKE128";
84const ALG_CSHAKE_256: &str = "cSHAKE256";
85const ALG_ARGON2D: &str = "Argon2d";
86const ALG_ARGON2I: &str = "Argon2i";
87const ALG_ARGON2ID: &str = "Argon2id";
88
89static SUPPORTED_ALGORITHMS: &[&str] = &[
90    ALG_RSASSA_PKCS1,
91    ALG_RSA_PSS,
92    ALG_RSA_OAEP,
93    ALG_ECDSA,
94    ALG_ECDH,
95    ALG_ED25519,
96    ALG_X25519,
97    ALG_AES_CTR,
98    ALG_AES_CBC,
99    ALG_AES_GCM,
100    ALG_AES_KW,
101    ALG_HMAC,
102    ALG_SHA1,
103    ALG_SHA256,
104    ALG_SHA384,
105    ALG_SHA512,
106    ALG_HKDF,
107    ALG_PBKDF2,
108    ALG_CHACHA20_POLY1305,
109    ALG_SHA3_256,
110    ALG_SHA3_384,
111    ALG_SHA3_512,
112    ALG_CSHAKE_128,
113    ALG_CSHAKE_256,
114    ALG_ARGON2D,
115    ALG_ARGON2I,
116    ALG_ARGON2ID,
117];
118
119// Named elliptic curves
120const NAMED_CURVE_P256: &str = "P-256";
121const NAMED_CURVE_P384: &str = "P-384";
122const NAMED_CURVE_P521: &str = "P-521";
123
124static SUPPORTED_CURVES: &[&str] = &[NAMED_CURVE_P256, NAMED_CURVE_P384, NAMED_CURVE_P521];
125
126/// <https://w3c.github.io/webcrypto/#supported-operation>
127#[expect(dead_code)]
128enum Operation {
129    Encrypt,
130    Decrypt,
131    Sign,
132    Verify,
133    Digest,
134    GenerateKey,
135    DeriveKey,
136    DeriveBits,
137    ImportKey,
138    ExportKey,
139    WrapKey,
140    UnwrapKey,
141    GetKeyLength,
142}
143
144#[dom_struct]
145pub(crate) struct SubtleCrypto {
146    reflector_: Reflector,
147}
148
149impl SubtleCrypto {
150    fn new_inherited() -> SubtleCrypto {
151        SubtleCrypto {
152            reflector_: Reflector::new(),
153        }
154    }
155
156    pub(crate) fn new(global: &GlobalScope, can_gc: CanGc) -> DomRoot<SubtleCrypto> {
157        reflect_dom_object(Box::new(SubtleCrypto::new_inherited()), global, can_gc)
158    }
159
160    /// Queue a global task on the crypto task source, given realm's global object, to resolve
161    /// promise with the result of creating an ArrayBuffer in realm, containing data. If it fails
162    /// to create buffer source, reject promise with a JSFailedError.
163    fn resolve_promise_with_data(&self, promise: Rc<Promise>, data: Vec<u8>) {
164        let trusted_promise = TrustedPromise::new(promise);
165        self.global().task_manager().crypto_task_source().queue(
166            task!(resolve_data: move || {
167                let promise = trusted_promise.root();
168
169                let cx = GlobalScope::get_cx();
170                rooted!(in(*cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>());
171                match create_buffer_source::<ArrayBufferU8>(cx, &data, array_buffer_ptr.handle_mut(), CanGc::note()) {
172                    Ok(_) => promise.resolve_native(&*array_buffer_ptr, CanGc::note()),
173                    Err(_) => promise.reject_error(Error::JSFailed, CanGc::note()),
174                }
175            }),
176        );
177    }
178
179    /// Queue a global task on the crypto task source, given realm's global object, to resolve
180    /// promise with the result of converting a JsonWebKey dictionary to an ECMAScript Object in
181    /// realm, as defined by [WebIDL].
182    fn resolve_promise_with_jwk(&self, promise: Rc<Promise>, jwk: Box<JsonWebKey>) {
183        // NOTE: Serialize the JsonWebKey dictionary by stringifying it, in order to pass it to
184        // other threads.
185        let cx = GlobalScope::get_cx();
186        let stringified_jwk = match jwk.stringify(cx) {
187            Ok(stringified_jwk) => stringified_jwk.to_string(),
188            Err(error) => {
189                self.reject_promise_with_error(promise, error);
190                return;
191            },
192        };
193
194        let trusted_subtle = Trusted::new(self);
195        let trusted_promise = TrustedPromise::new(promise);
196        self.global()
197            .task_manager()
198            .crypto_task_source()
199            .queue(task!(resolve_jwk: move || {
200                let subtle = trusted_subtle.root();
201                let promise = trusted_promise.root();
202
203                let cx = GlobalScope::get_cx();
204                match JsonWebKey::parse(cx, stringified_jwk.as_bytes()) {
205                    Ok(jwk) => {
206                        rooted!(in(*cx) let mut rval = UndefinedValue());
207                        jwk.safe_to_jsval(cx, rval.handle_mut(), CanGc::note());
208                        rooted!(in(*cx) let mut object = rval.to_object());
209                        promise.resolve_native(&*object, CanGc::note());
210                    },
211                    Err(error) => {
212                        subtle.reject_promise_with_error(promise, error);
213                        return;
214                    },
215                }
216            }));
217    }
218
219    /// Queue a global task on the crypto task source, given realm's global object, to resolve
220    /// promise with a CryptoKey.
221    fn resolve_promise_with_key(&self, promise: Rc<Promise>, key: DomRoot<CryptoKey>) {
222        let trusted_key = Trusted::new(&*key);
223        let trusted_promise = TrustedPromise::new(promise);
224        self.global()
225            .task_manager()
226            .crypto_task_source()
227            .queue(task!(resolve_key: move || {
228                let key = trusted_key.root();
229                let promise = trusted_promise.root();
230                promise.resolve_native(&key, CanGc::note());
231            }));
232    }
233
234    /// Queue a global task on the crypto task source, given realm's global object, to resolve
235    /// promise with a CryptoKeyPair.
236    fn resolve_promise_with_key_pair(&self, promise: Rc<Promise>, key_pair: CryptoKeyPair) {
237        let trusted_private_key = key_pair.privateKey.map(|key| Trusted::new(&*key));
238        let trusted_public_key = key_pair.publicKey.map(|key| Trusted::new(&*key));
239        let trusted_promise = TrustedPromise::new(promise);
240        self.global()
241            .task_manager()
242            .crypto_task_source()
243            .queue(task!(resolve_key: move || {
244                let key_pair = CryptoKeyPair {
245                    privateKey: trusted_private_key.map(|trusted_key| trusted_key.root()),
246                    publicKey: trusted_public_key.map(|trusted_key| trusted_key.root()),
247                };
248                let promise = trusted_promise.root();
249                promise.resolve_native(&key_pair, CanGc::note());
250            }));
251    }
252
253    /// Queue a global task on the crypto task source, given realm's global object, to resolve
254    /// promise with a bool value.
255    fn resolve_promise_with_bool(&self, promise: Rc<Promise>, result: bool) {
256        let trusted_promise = TrustedPromise::new(promise);
257        self.global().task_manager().crypto_task_source().queue(
258            task!(generate_key_result: move || {
259                let promise = trusted_promise.root();
260                promise.resolve_native(&result, CanGc::note());
261            }),
262        );
263    }
264
265    /// Queue a global task on the crypto task source, given realm's global object, to reject
266    /// promise with an error.
267    fn reject_promise_with_error(&self, promise: Rc<Promise>, error: Error) {
268        let trusted_promise = TrustedPromise::new(promise);
269        self.global()
270            .task_manager()
271            .crypto_task_source()
272            .queue(task!(reject_error: move || {
273                let promise = trusted_promise.root();
274                promise.reject_error(error, CanGc::note());
275            }));
276    }
277}
278
279impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
280    /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-encrypt>
281    fn Encrypt(
282        &self,
283        cx: JSContext,
284        algorithm: AlgorithmIdentifier,
285        key: &CryptoKey,
286        data: ArrayBufferViewOrArrayBuffer,
287        comp: InRealm,
288        can_gc: CanGc,
289    ) -> Rc<Promise> {
290        // Step 1. Let algorithm and key be the algorithm and key parameters passed to the
291        // encrypt() method, respectively.
292        // NOTE: We did that in method parameter.
293
294        // Step 2. Let data be the result of getting a copy of the bytes held by the data parameter
295        // passed to the encrypt() method.
296        let data = match data {
297            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
298            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
299        };
300
301        // Step 3. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
302        // to algorithm and op set to "encrypt".
303        // Step 4. If an error occurred, return a Promise rejected with normalizedAlgorithm.
304        let promise = Promise::new_in_current_realm(comp, can_gc);
305        let normalized_algorithm =
306            match normalize_algorithm(cx, &Operation::Encrypt, &algorithm, can_gc) {
307                Ok(normalized_algorithm) => normalized_algorithm,
308                Err(error) => {
309                    promise.reject_error(error, can_gc);
310                    return promise;
311                },
312            };
313
314        // Step 5. Let realm be the relevant realm of this.
315        // Step 6. Let promise be a new Promise.
316        // NOTE: We did that in preparation of Step 4.
317
318        // Step 7. Return promise and perform the remaining steps in parallel.
319        let this = Trusted::new(self);
320        let trusted_promise = TrustedPromise::new(promise.clone());
321        let trusted_key = Trusted::new(key);
322        self.global()
323            .task_manager()
324            .dom_manipulation_task_source()
325            .queue(task!(encrypt: move || {
326                let subtle = this.root();
327                let promise = trusted_promise.root();
328                let key = trusted_key.root();
329
330                // Step 8. If the following steps or referenced procedures say to throw an error,
331                // queue a global task on the crypto task source, given realm's global object, to
332                // reject promise with the returned error; and then terminate the algorithm.
333
334                // Step 9. If the name member of normalizedAlgorithm is not equal to the name
335                // attribute of the [[algorithm]] internal slot of key then throw an
336                // InvalidAccessError.
337                if normalized_algorithm.name() != key.algorithm().name() {
338                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
339                    return;
340                }
341
342                // Step 10. If the [[usages]] internal slot of key does not contain an entry that
343                // is "encrypt", then throw an InvalidAccessError.
344                if !key.usages().contains(&KeyUsage::Encrypt) {
345                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
346                    return;
347                }
348
349                // Step 11. Let ciphertext be the result of performing the encrypt operation
350                // specified by normalizedAlgorithm using algorithm and key and with data as
351                // plaintext.
352                let ciphertext = match normalized_algorithm.encrypt(&key, &data) {
353                    Ok(ciphertext) => ciphertext,
354                    Err(error) => {
355                        subtle.reject_promise_with_error(promise, error);
356                        return;
357                    },
358                };
359
360                // Step 12. Queue a global task on the crypto task source, given realm's global
361                // object, to perform the remaining steps.
362                // Step 13. Let result be the result of creating an ArrayBuffer in realm,
363                // containing ciphertext.
364                // Step 14. Resolve promise with result.
365                subtle.resolve_promise_with_data(promise, ciphertext);
366            }));
367        promise
368    }
369
370    /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-decrypt>
371    fn Decrypt(
372        &self,
373        cx: JSContext,
374        algorithm: AlgorithmIdentifier,
375        key: &CryptoKey,
376        data: ArrayBufferViewOrArrayBuffer,
377        comp: InRealm,
378        can_gc: CanGc,
379    ) -> Rc<Promise> {
380        // Step 1. Let algorithm and key be the algorithm and key parameters passed to the
381        // decrypt() method, respectively.
382        // NOTE: We did that in method parameter.
383
384        // Step 2. Let data be the result of getting a copy of the bytes held by the data parameter
385        // passed to the decrypt() method.
386        let data = match data {
387            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
388            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
389        };
390
391        // Step 3. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
392        // to algorithm and op set to "decrypt".
393        // Step 4. If an error occurred, return a Promise rejected with normalizedAlgorithm.
394        let promise = Promise::new_in_current_realm(comp, can_gc);
395        let normalized_algorithm =
396            match normalize_algorithm(cx, &Operation::Decrypt, &algorithm, can_gc) {
397                Ok(normalized_algorithm) => normalized_algorithm,
398                Err(error) => {
399                    promise.reject_error(error, can_gc);
400                    return promise;
401                },
402            };
403
404        // Step 5. Let realm be the relevant realm of this.
405        // Step 6. Let promise be a new Promise.
406        // NOTE: We did that in preparation of Step 4.
407
408        // Step 7. Return promise and perform the remaining steps in parallel.
409        let this = Trusted::new(self);
410        let trusted_promise = TrustedPromise::new(promise.clone());
411        let trusted_key = Trusted::new(key);
412        self.global()
413            .task_manager()
414            .dom_manipulation_task_source()
415            .queue(task!(decrypt: move || {
416                let subtle = this.root();
417                let promise = trusted_promise.root();
418                let key = trusted_key.root();
419
420                // Step 8. If the following steps or referenced procedures say to throw an error,
421                // queue a global task on the crypto task source, given realm's global object, to
422                // reject promise with the returned error; and then terminate the algorithm.
423
424                // Step 9. If the name member of normalizedAlgorithm is not equal to the name
425                // attribute of the [[algorithm]] internal slot of key then throw an
426                // InvalidAccessError.
427                if normalized_algorithm.name() != key.algorithm().name() {
428                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
429                    return;
430                }
431
432                // Step 10. If the [[usages]] internal slot of key does not contain an entry that
433                // is "decrypt", then throw an InvalidAccessError.
434                if !key.usages().contains(&KeyUsage::Decrypt) {
435                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
436                    return;
437                }
438
439                // Step 11. Let plaintext be the result of performing the decrypt operation
440                // specified by normalizedAlgorithm using key and algorithm and with data as
441                // ciphertext.
442                let plaintext = match normalized_algorithm.decrypt(&key, &data) {
443                    Ok(plaintext) => plaintext,
444                    Err(error) => {
445                        subtle.reject_promise_with_error(promise, error);
446                        return;
447                    },
448                };
449
450                // Step 12. Queue a global task on the crypto task source, given realm's global
451                // object, to perform the remaining steps.
452                // Step 13. Let result be the result of creating an ArrayBuffer in realm,
453                // containing plaintext.
454                // Step 14. Resolve promise with result.
455                subtle.resolve_promise_with_data(promise, plaintext);
456            }));
457        promise
458    }
459
460    /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-sign>
461    fn Sign(
462        &self,
463        cx: JSContext,
464        algorithm: AlgorithmIdentifier,
465        key: &CryptoKey,
466        data: ArrayBufferViewOrArrayBuffer,
467        comp: InRealm,
468        can_gc: CanGc,
469    ) -> Rc<Promise> {
470        // Step 1. Let algorithm and key be the algorithm and key parameters passed to the sign()
471        // method, respectively.
472        // NOTE: We did that in method parameter.
473
474        // Step 2. Let data be the result of getting a copy of the bytes held by the data parameter
475        // passed to the sign() method.
476        let data = match &data {
477            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
478            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
479        };
480
481        // Step 3. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
482        // to algorithm and op set to "sign".
483        // Step 4. If an error occurred, return a Promise rejected with normalizedAlgorithm.
484        let promise = Promise::new_in_current_realm(comp, can_gc);
485        let normalized_algorithm =
486            match normalize_algorithm(cx, &Operation::Sign, &algorithm, can_gc) {
487                Ok(normalized_algorithm) => normalized_algorithm,
488                Err(error) => {
489                    promise.reject_error(error, can_gc);
490                    return promise;
491                },
492            };
493
494        // Step 5. Let realm be the relevant realm of this.
495        // Step 6. Let promise be a new Promise.
496        // NOTE: We did that in preparation of Step 4.
497
498        // Step 7. Return promise and perform the remaining steps in parallel.
499        let this = Trusted::new(self);
500        let trusted_promise = TrustedPromise::new(promise.clone());
501        let trusted_key = Trusted::new(key);
502        self.global()
503            .task_manager()
504            .dom_manipulation_task_source()
505            .queue(task!(sign: move || {
506                let subtle = this.root();
507                let promise = trusted_promise.root();
508                let key = trusted_key.root();
509
510                // Step 8. If the following steps or referenced procedures say to throw an error,
511                // queue a global task on the crypto task source, given realm's global object, to
512                // reject promise with the returned error; and then terminate the algorithm.
513
514                // Step 9. If the name member of normalizedAlgorithm is not equal to the name
515                // attribute of the [[algorithm]] internal slot of key then throw an
516                // InvalidAccessError.
517                if normalized_algorithm.name() != key.algorithm().name() {
518                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
519                    return;
520                }
521
522                // Step 10. If the [[usages]] internal slot of key does not contain an entry that
523                // is "sign", then throw an InvalidAccessError.
524                if !key.usages().contains(&KeyUsage::Sign) {
525                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
526                    return;
527                }
528
529                // Step 11. Let signature be the result of performing the sign operation specified
530                // by normalizedAlgorithm using key and algorithm and with data as message.
531                let signature = match normalized_algorithm.sign(&key, &data) {
532                    Ok(signature) => signature,
533                    Err(error) => {
534                        subtle.reject_promise_with_error(promise, error);
535                        return;
536                    },
537                };
538
539                // Step 12. Queue a global task on the crypto task source, given realm's global
540                // object, to perform the remaining steps.
541                // Step 13. Let result be the result of creating an ArrayBuffer in realm,
542                // containing signature.
543                // Step 14. Resolve promise with result.
544                subtle.resolve_promise_with_data(promise, signature);
545            }));
546        promise
547    }
548
549    /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-verify>
550    fn Verify(
551        &self,
552        cx: JSContext,
553        algorithm: AlgorithmIdentifier,
554        key: &CryptoKey,
555        signature: ArrayBufferViewOrArrayBuffer,
556        data: ArrayBufferViewOrArrayBuffer,
557        comp: InRealm,
558        can_gc: CanGc,
559    ) -> Rc<Promise> {
560        // Step 1. Let algorithm and key be the algorithm and key parameters passed to the verify()
561        // method, respectively.
562        // NOTE: We did that in method parameter.
563
564        // Step 2. Let signature be the result of getting a copy of the bytes held by the signature
565        // parameter passed to the verify() method.
566        let signature = match &signature {
567            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
568            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
569        };
570
571        // Step 3. Let data be the result of getting a copy of the bytes held by the data parameter
572        // passed to the verify() method.
573        let data = match &data {
574            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
575            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
576        };
577
578        // Step 4. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set to
579        // algorithm and op set to "verify".
580        // Step 5. If an error occurred, return a Promise rejected with normalizedAlgorithm.
581        let promise = Promise::new_in_current_realm(comp, can_gc);
582        let normalized_algorithm =
583            match normalize_algorithm(cx, &Operation::Verify, &algorithm, can_gc) {
584                Ok(algorithm) => algorithm,
585                Err(error) => {
586                    promise.reject_error(error, can_gc);
587                    return promise;
588                },
589            };
590
591        // Step 6. Let realm be the relevant realm of this.
592        // Step 7. Let promise be a new Promise.
593        // NOTE: We did that in preparation of Step 5.
594
595        // Step 8. Return promise and perform the remaining steps in parallel.
596        let this = Trusted::new(self);
597        let trusted_promise = TrustedPromise::new(promise.clone());
598        let trusted_key = Trusted::new(key);
599        self.global()
600            .task_manager()
601            .dom_manipulation_task_source()
602            .queue(task!(sign: move || {
603                let subtle = this.root();
604                let promise = trusted_promise.root();
605                let key = trusted_key.root();
606
607                // Step 9. If the following steps or referenced procedures say to throw an error,
608                // queue a global task on the crypto task source, given realm's global object, to
609                // reject promise with the returned error; and then terminate the algorithm.
610
611                // Step 10. If the name member of normalizedAlgorithm is not equal to the name
612                // attribute of the [[algorithm]] internal slot of key then throw an
613                // InvalidAccessError.
614                if normalized_algorithm.name() != key.algorithm().name() {
615                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
616                    return;
617                }
618
619                // Step 11. If the [[usages]] internal slot of key does not contain an entry that
620                // is "verify", then throw an InvalidAccessError.
621                if !key.usages().contains(&KeyUsage::Verify) {
622                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
623                    return;
624                }
625
626                // Step 12. Let result be the result of performing the verify operation specified
627                // by normalizedAlgorithm using key, algorithm and signature and with data as
628                // message.
629                let result = match normalized_algorithm.verify(&key, &data, &signature) {
630                    Ok(result) => result,
631                    Err(error) => {
632                        subtle.reject_promise_with_error(promise, error);
633                        return;
634                    },
635                };
636
637                // Step 13. Queue a global task on the crypto task source, given realm's global
638                // object, to perform the remaining steps.
639                // Step 14. Resolve promise with result.
640                subtle.resolve_promise_with_bool(promise, result);
641            }));
642        promise
643    }
644
645    /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-digest>
646    fn Digest(
647        &self,
648        cx: JSContext,
649        algorithm: AlgorithmIdentifier,
650        data: ArrayBufferViewOrArrayBuffer,
651        comp: InRealm,
652        can_gc: CanGc,
653    ) -> Rc<Promise> {
654        // Step 1. Let algorithm be the algorithm parameter passed to the digest() method.
655        // NOTE: We did that in method parameter.
656
657        // Step 2. Let data be the result of getting a copy of the bytes held by the
658        // data parameter passed to the digest() method.
659        let data = match data {
660            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
661            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
662        };
663
664        // Step 3. Let normalizedAlgorithm be the result of normalizing an algorithm,
665        // with alg set to algorithm and op set to "digest".
666        // Step 4. If an error occurred, return a Promise rejected with normalizedAlgorithm.
667        let promise = Promise::new_in_current_realm(comp, can_gc);
668        let normalized_algorithm =
669            match normalize_algorithm(cx, &Operation::Digest, &algorithm, can_gc) {
670                Ok(normalized_algorithm) => normalized_algorithm,
671                Err(error) => {
672                    promise.reject_error(error, can_gc);
673                    return promise;
674                },
675            };
676
677        // Step 5. Let realm be the relevant realm of this.
678        // Step 6. Let promise be a new Promise.
679        // NOTE: We did that in preparation of Step 3.
680
681        // Step 7. Return promise and perform the remaining steps in parallel.
682        let this = Trusted::new(self);
683        let trusted_promise = TrustedPromise::new(promise.clone());
684        self.global()
685            .task_manager()
686            .dom_manipulation_task_source()
687            .queue(task!(generate_key: move || {
688                let subtle = this.root();
689                let promise = trusted_promise.root();
690
691                // Step 8. If the following steps or referenced procedures say to throw an error,
692                // queue a global task on the crypto task source, given realm's global object, to
693                // reject promise with the returned error; and then terminate the algorithm.
694
695                // Step 9. Let digest be the result of performing the digest operation specified by
696                // normalizedAlgorithm using algorithm, with data as message.
697                let digest = match normalized_algorithm.digest(&data) {
698                    Ok(digest) => digest,
699                    Err(error) => {
700                        subtle.reject_promise_with_error(promise, error);
701                        return;
702                    }
703                };
704
705                // Step 10. Queue a global task on the crypto task source, given realm's global
706                // object, to perform the remaining steps.
707                // Step 11. Let result be the result of creating an ArrayBuffer in realm,
708                // containing digest.
709                // Step 12. Resolve promise with result.
710                subtle.resolve_promise_with_data(promise, digest);
711            }));
712        promise
713    }
714
715    /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-generateKey>
716    fn GenerateKey(
717        &self,
718        cx: JSContext,
719        algorithm: AlgorithmIdentifier,
720        extractable: bool,
721        key_usages: Vec<KeyUsage>,
722        comp: InRealm,
723        can_gc: CanGc,
724    ) -> Rc<Promise> {
725        // Step 1. Let algorithm, extractable and usages be the algorithm, extractable and
726        // keyUsages parameters passed to the generateKey() method, respectively.
727
728        // Step 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
729        // to algorithm and op set to "generateKey".
730        // Step 3. If an error occurred, return a Promise rejected with normalizedAlgorithm.
731        let promise = Promise::new_in_current_realm(comp, can_gc);
732        let normalized_algorithm =
733            match normalize_algorithm(cx, &Operation::GenerateKey, &algorithm, can_gc) {
734                Ok(normalized_algorithm) => normalized_algorithm,
735                Err(error) => {
736                    promise.reject_error(error, can_gc);
737                    return promise;
738                },
739            };
740
741        // Step 4. Let realm be the relevant realm of this.
742        // Step 5. Let promise be a new Promise.
743        // NOTE: We did that in preparation of Step 3.
744
745        // Step 6. Return promise and perform the remaining steps in parallel.
746        let trusted_subtle = Trusted::new(self);
747        let trusted_promise = TrustedPromise::new(promise.clone());
748        self.global()
749            .task_manager()
750            .dom_manipulation_task_source()
751            .queue(task!(generate_key: move || {
752                let subtle = trusted_subtle.root();
753                let promise = trusted_promise.root();
754
755                // Step 7. If the following steps or referenced procedures say to throw an error,
756                // queue a global task on the crypto task source, given realm's global object, to
757                // reject promise with the returned error; and then terminate the algorithm.
758
759                // Step 8. Let result be the result of performing the generate key operation
760                // specified by normalizedAlgorithm using algorithm, extractable and usages.
761                let result = match normalized_algorithm.generate_key(
762                    &subtle.global(),
763                    extractable,
764                    key_usages,
765                    CanGc::note(),
766                ) {
767                    Ok(result) => result,
768                    Err(error) => {
769                        subtle.reject_promise_with_error(promise, error);
770                        return;
771                    }
772                };
773
774                // Step 9.
775                // If result is a CryptoKey object:
776                //     If the [[type]] internal slot of result is "secret" or "private" and usages
777                //     is empty, then throw a SyntaxError.
778                // If result is a CryptoKeyPair object:
779                //     If the [[usages]] internal slot of the privateKey attribute of result is the
780                //     empty sequence, then throw a SyntaxError.
781                // TODO: Implement CryptoKeyPair case
782                match &result {
783                    CryptoKeyOrCryptoKeyPair::CryptoKey(crpyto_key) => {
784                        if matches!(crpyto_key.Type(), KeyType::Secret | KeyType::Private)
785                            && crpyto_key.usages().is_empty()
786                        {
787                            subtle.reject_promise_with_error(promise, Error::Syntax(None));
788                            return;
789                        }
790                    },
791                    CryptoKeyOrCryptoKeyPair::CryptoKeyPair(crypto_key_pair) => {
792                        if crypto_key_pair.privateKey.as_ref().is_none_or(|private_key| private_key.usages().is_empty()) {
793                            subtle.reject_promise_with_error(promise, Error::Syntax(None));
794                            return;
795                        }
796                    }
797                };
798
799                // Step 10. Queue a global task on the crypto task source, given realm's global
800                // object, to perform the remaining steps.
801                // Step 11. Let result be the result of converting result to an ECMAScript Object
802                // in realm, as defined by [WebIDL].
803                // Step 12. Resolve promise with result.
804                match result {
805                    CryptoKeyOrCryptoKeyPair::CryptoKey(key) => {
806                        subtle.resolve_promise_with_key(promise, key);
807                    },
808                    CryptoKeyOrCryptoKeyPair::CryptoKeyPair(key_pair) => {
809                        subtle.resolve_promise_with_key_pair(promise, key_pair);
810                    },
811                }
812            }));
813
814        promise
815    }
816
817    /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-deriveKey>
818    fn DeriveKey(
819        &self,
820        cx: JSContext,
821        algorithm: AlgorithmIdentifier,
822        base_key: &CryptoKey,
823        derived_key_type: AlgorithmIdentifier,
824        extractable: bool,
825        usages: Vec<KeyUsage>,
826        comp: InRealm,
827        can_gc: CanGc,
828    ) -> Rc<Promise> {
829        // Step 1. Let algorithm, baseKey, derivedKeyType, extractable and usages be the algorithm,
830        // baseKey, derivedKeyType, extractable and keyUsages parameters passed to the deriveKey()
831        // method, respectively.
832        // NOTE: We did that in method parameter.
833
834        // Step 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
835        // to algorithm and op set to "deriveBits".
836        // Step 3. If an error occurred, return a Promise rejected with normalizedAlgorithm.
837        let promise = Promise::new_in_current_realm(comp, can_gc);
838        let normalized_algorithm =
839            match normalize_algorithm(cx, &Operation::DeriveBits, &algorithm, can_gc) {
840                Ok(normalized_algorithm) => normalized_algorithm,
841                Err(error) => {
842                    promise.reject_error(error, can_gc);
843                    return promise;
844                },
845            };
846
847        // Step 4. Let normalizedDerivedKeyAlgorithmImport be the result of normalizing an
848        // algorithm, with alg set to derivedKeyType and op set to "importKey".
849        // Step 5. If an error occurred, return a Promise rejected with
850        // normalizedDerivedKeyAlgorithmImport.
851        let normalized_derived_key_algorithm_import =
852            match normalize_algorithm(cx, &Operation::ImportKey, &derived_key_type, can_gc) {
853                Ok(normalized_algorithm) => normalized_algorithm,
854                Err(error) => {
855                    promise.reject_error(error, can_gc);
856                    return promise;
857                },
858            };
859
860        // Step 6. Let normalizedDerivedKeyAlgorithmLength be the result of normalizing an
861        // algorithm, with alg set to derivedKeyType and op set to "get key length".
862        // Step 7. If an error occurred, return a Promise rejected with
863        // normalizedDerivedKeyAlgorithmLength.
864        let normalized_derived_key_algorithm_length =
865            match normalize_algorithm(cx, &Operation::GetKeyLength, &derived_key_type, can_gc) {
866                Ok(normalized_algorithm) => normalized_algorithm,
867                Err(error) => {
868                    promise.reject_error(error, can_gc);
869                    return promise;
870                },
871            };
872
873        // Step 8. Let realm be the relevant realm of this.
874        // Step 9. Let promise be a new Promise.
875        // NOTE: We did that in preparation of Step 3.
876
877        // Step 10. Return promise and perform the remaining steps in parallel.
878        let trusted_subtle = Trusted::new(self);
879        let trusted_base_key = Trusted::new(base_key);
880        let trusted_promise = TrustedPromise::new(promise.clone());
881        self.global().task_manager().dom_manipulation_task_source().queue(
882            task!(derive_key: move || {
883                let subtle = trusted_subtle.root();
884                let base_key = trusted_base_key.root();
885                let promise = trusted_promise.root();
886
887                // Step 11. If the following steps or referenced procedures say to throw an error,
888                // queue a global task on the crypto task source, given realm's global object, to
889                // reject promise with the returned error; and then terminate the algorithm.
890
891                // Step 12. If the name member of normalizedAlgorithm is not equal to the name
892                // attribute of the [[algorithm]] internal slot of baseKey then throw an
893                // InvalidAccessError.
894                if normalized_algorithm.name() != base_key.algorithm().name() {
895                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
896                    return;
897                }
898
899                // Step 13. If the [[usages]] internal slot of baseKey does not contain an entry
900                // that is "deriveKey", then throw an InvalidAccessError.
901                if !base_key.usages().contains(&KeyUsage::DeriveKey) {
902                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
903                    return;
904                }
905
906                // Step 14. Let length be the result of performing the get key length algorithm
907                // specified by normalizedDerivedKeyAlgorithmLength using derivedKeyType.
908                let length = match normalized_derived_key_algorithm_length.get_key_length() {
909                    Ok(length) => length,
910                    Err(error) => {
911                        subtle.reject_promise_with_error(promise, error);
912                        return;
913                    }
914                };
915
916                // Step 15. Let secret be the result of performing the derive bits operation
917                // specified by normalizedAlgorithm using key, algorithm and length.
918                let secret = match normalized_algorithm.derive_bits(&base_key, length) {
919                    Ok(secret) => secret,
920                    Err(error) => {
921                        subtle.reject_promise_with_error(promise, error);
922                        return;
923                    }
924                };
925
926                // Step 16. Let result be the result of performing the import key operation
927                // specified by normalizedDerivedKeyAlgorithmImport using "raw" as format, secret
928                // as keyData, derivedKeyType as algorithm and using extractable and usages.
929                // NOTE: Use "raw-secret" instead, according to
930                // <https://wicg.github.io/webcrypto-modern-algos/#subtlecrypto-interface-keyformat>.
931                let result = match normalized_derived_key_algorithm_import.import_key(
932                    &subtle.global(),
933                    KeyFormat::Raw_secret,
934                    &secret,
935                    extractable,
936                    usages.clone(),
937                    CanGc::note(),
938                ) {
939                    Ok(algorithm) => algorithm,
940                    Err(error) => {
941                        subtle.reject_promise_with_error(promise, error);
942                        return;
943                    },
944                };
945
946                // Step 17. If the [[type]] internal slot of result is "secret" or "private" and
947                // usages is empty, then throw a SyntaxError.
948                if matches!(result.Type(), KeyType::Secret | KeyType::Private) && usages.is_empty() {
949                    subtle.reject_promise_with_error(promise, Error::Syntax(None));
950                    return;
951                }
952
953                // Step 18. Set the [[extractable]] internal slot of result to extractable.
954                // Step 19. Set the [[usages]] internal slot of result to the normalized value of
955                // usages.
956                // NOTE: Done by normalized_derived_key_algorithm_import.import_key in Step 16.
957
958                // Step 20. Queue a global task on the crypto task source, given realm's global
959                // object, to perform the remaining steps.
960                // Step 20. Let result be the result of converting result to an ECMAScript Object
961                // in realm, as defined by [WebIDL].
962                // Step 20. Resolve promise with result.
963                subtle.resolve_promise_with_key(promise, result);
964            }),
965        );
966        promise
967    }
968
969    /// <https://w3c.github.io/webcrypto/#dfn-SubtleCrypto-method-deriveBits>
970    fn DeriveBits(
971        &self,
972        cx: JSContext,
973        algorithm: AlgorithmIdentifier,
974        base_key: &CryptoKey,
975        length: Option<u32>,
976        comp: InRealm,
977        can_gc: CanGc,
978    ) -> Rc<Promise> {
979        // Step 1. Let algorithm, baseKey and length, be the algorithm, baseKey and length
980        // parameters passed to the deriveBits() method, respectively.
981        // NOTE: We did that in method parameter.
982
983        // Step 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
984        // to algorithm and op set to "deriveBits".
985        // Step 3. If an error occurred, return a Promise rejected with normalizedAlgorithm.
986        let promise = Promise::new_in_current_realm(comp, can_gc);
987        let normalized_algorithm =
988            match normalize_algorithm(cx, &Operation::DeriveBits, &algorithm, can_gc) {
989                Ok(normalized_algorithm) => normalized_algorithm,
990                Err(error) => {
991                    promise.reject_error(error, can_gc);
992                    return promise;
993                },
994            };
995
996        // Step 4. Let realm be the relevant realm of this.
997        // Step 5. Let promise be a new Promise.
998        // NOTE: We did that in preparation of Step 3.
999
1000        // Step 5. Return promise and perform the remaining steps in parallel.
1001        let trsuted_subtle = Trusted::new(self);
1002        let trusted_base_key = Trusted::new(base_key);
1003        let trusted_promise = TrustedPromise::new(promise.clone());
1004        self.global()
1005            .task_manager()
1006            .dom_manipulation_task_source()
1007            .queue(task!(import_key: move || {
1008                let subtle = trsuted_subtle.root();
1009                let base_key = trusted_base_key.root();
1010                let promise = trusted_promise.root();
1011
1012                // Step 7. If the following steps or referenced procedures say to throw an error,
1013                // queue a global task on the crypto task source, given realm's global object, to
1014                // reject promise with the returned error; and then terminate the algorithm.
1015
1016                // Step 8. If the name member of normalizedAlgorithm is not equal to the name
1017                // attribute of the [[algorithm]] internal slot of baseKey then throw an
1018                // InvalidAccessError.
1019                if normalized_algorithm.name() != base_key.algorithm().name() {
1020                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
1021                    return;
1022                }
1023
1024                // Step 9. If the [[usages]] internal slot of baseKey does not contain an entry
1025                // that is "deriveBits", then throw an InvalidAccessError.
1026                if !base_key.usages().contains(&KeyUsage::DeriveBits) {
1027                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
1028                    return;
1029                }
1030
1031                // Step 10. Let bits be the result of performing the derive bits operation
1032                // specified by normalizedAlgorithm using baseKey, algorithm and length.
1033                let bits = match normalized_algorithm.derive_bits(&base_key, length) {
1034                    Ok(bits) => bits,
1035                    Err(error) => {
1036                        subtle.reject_promise_with_error(promise, error);
1037                        return;
1038                    }
1039                };
1040
1041                // Step 11. Queue a global task on the crypto task source, given realm's global
1042                // object, to perform the remaining steps.
1043                // Step 12. Let result be the result of creating an ArrayBuffer in realm,
1044                // containing bits.
1045                // Step 13. Resolve promise with result.
1046                subtle.resolve_promise_with_data(promise, bits);
1047            }));
1048        promise
1049    }
1050
1051    /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-importKey>
1052    fn ImportKey(
1053        &self,
1054        cx: JSContext,
1055        format: KeyFormat,
1056        key_data: ArrayBufferViewOrArrayBufferOrJsonWebKey,
1057        algorithm: AlgorithmIdentifier,
1058        extractable: bool,
1059        key_usages: Vec<KeyUsage>,
1060        comp: InRealm,
1061        can_gc: CanGc,
1062    ) -> Rc<Promise> {
1063        // Step 1. Let format, algorithm, extractable and usages, be the format, algorithm,
1064        // extractable and keyUsages parameters passed to the importKey() method, respectively.
1065
1066        // Step 5. Let realm be the relevant realm of this.
1067        // Step 6. Let promise be a new Promise.
1068        let promise = Promise::new_in_current_realm(comp, can_gc);
1069
1070        // Step 2.
1071        let key_data = match format {
1072            // If format is equal to the string "raw", "pkcs8", or "spki":
1073            // NOTE: Including other raw formats.
1074            KeyFormat::Raw |
1075            KeyFormat::Pkcs8 |
1076            KeyFormat::Spki |
1077            KeyFormat::Raw_public |
1078            KeyFormat::Raw_private |
1079            KeyFormat::Raw_seed |
1080            KeyFormat::Raw_secret => {
1081                match key_data {
1082                    // Step 2.1. If the keyData parameter passed to the importKey() method is a
1083                    // JsonWebKey dictionary, throw a TypeError.
1084                    ArrayBufferViewOrArrayBufferOrJsonWebKey::JsonWebKey(_) => {
1085                        promise.reject_error(
1086                            Error::Type("The keyData type does not match the format".to_string()),
1087                            can_gc,
1088                        );
1089                        return promise;
1090                    },
1091
1092                    // Step 2.2. Let keyData be the result of getting a copy of the bytes held by
1093                    // the keyData parameter passed to the importKey() method.
1094                    ArrayBufferViewOrArrayBufferOrJsonWebKey::ArrayBufferView(view) => {
1095                        view.to_vec()
1096                    },
1097                    ArrayBufferViewOrArrayBufferOrJsonWebKey::ArrayBuffer(buffer) => {
1098                        buffer.to_vec()
1099                    },
1100                }
1101            },
1102            // If format is equal to the string "jwk":
1103            KeyFormat::Jwk => {
1104                match key_data {
1105                    ArrayBufferViewOrArrayBufferOrJsonWebKey::ArrayBufferView(_) |
1106                    ArrayBufferViewOrArrayBufferOrJsonWebKey::ArrayBuffer(_) => {
1107                        // Step 2.1. If the keyData parameter passed to the importKey() method is
1108                        // not a JsonWebKey dictionary, throw a TypeError.
1109                        promise.reject_error(
1110                            Error::Type("The keyData type does not match the format".to_string()),
1111                            can_gc,
1112                        );
1113                        return promise;
1114                    },
1115
1116                    ArrayBufferViewOrArrayBufferOrJsonWebKey::JsonWebKey(jwk) => {
1117                        // Step 2.2. Let keyData be the keyData parameter passed to the importKey() method.
1118                        //
1119                        // NOTE: Serialize JsonWebKey throught stringifying it.
1120                        // JsonWebKey::stringify internally relies on ToJSON, so it will raise an
1121                        // exception when a JS error is thrown. When this happens, we report the
1122                        // error.
1123                        match jwk.stringify(cx) {
1124                            Ok(stringified) => stringified.as_bytes().to_vec(),
1125                            Err(error) => {
1126                                promise.reject_error(error, can_gc);
1127                                return promise;
1128                            },
1129                        }
1130                    },
1131                }
1132            },
1133        };
1134
1135        // Step 3. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
1136        // to algorithm and op set to "importKey".
1137        // Step 4. If an error occurred, return a Promise rejected with normalizedAlgorithm.
1138        let normalized_algorithm =
1139            match normalize_algorithm(cx, &Operation::ImportKey, &algorithm, can_gc) {
1140                Ok(algorithm) => algorithm,
1141                Err(error) => {
1142                    promise.reject_error(error, can_gc);
1143                    return promise;
1144                },
1145            };
1146
1147        // Step 7. Return promise and perform the remaining steps in parallel.
1148        let this = Trusted::new(self);
1149        let trusted_promise = TrustedPromise::new(promise.clone());
1150        self.global()
1151            .task_manager()
1152            .dom_manipulation_task_source()
1153            .queue(task!(import_key: move || {
1154                let subtle = this.root();
1155                let promise = trusted_promise.root();
1156
1157                // Step 8. If the following steps or referenced procedures say to throw an error,
1158                // queue a global task on the crypto task source, given realm's global object, to
1159                // reject promise with the returned error; and then terminate the algorithm.
1160
1161                // Step 9. Let result be the CryptoKey object that results from performing the
1162                // import key operation specified by normalizedAlgorithm using keyData, algorithm,
1163                // format, extractable and usages.
1164                let result = match normalized_algorithm.import_key(
1165                    &subtle.global(),
1166                    format,
1167                    &key_data,
1168                    extractable,
1169                    key_usages.clone(),
1170                    CanGc::note()
1171                ) {
1172                    Ok(key) => key,
1173                    Err(error) => {
1174                        subtle.reject_promise_with_error(promise, error);
1175                        return;
1176                    },
1177                };
1178
1179                // Step 10. If the [[type]] internal slot of result is "secret" or "private" and
1180                // usages is empty, then throw a SyntaxError.
1181                if matches!(result.Type(), KeyType::Secret | KeyType::Private) && key_usages.is_empty() {
1182                    subtle.reject_promise_with_error(promise, Error::Syntax(None));
1183                    return;
1184                }
1185
1186                // Step 11. Set the [[extractable]] internal slot of result to extractable.
1187                result.set_extractable(extractable);
1188
1189                // Step 12. Set the [[usages]] internal slot of result to the normalized value of usages.
1190                result.set_usages(&key_usages);
1191
1192                // Step 13. Queue a global task on the crypto task source, given realm's global
1193                // object, to perform the remaining steps.
1194                // Step 14. Let result be the result of converting result to an ECMAScript Object
1195                // in realm, as defined by [WebIDL].
1196                // Step 15. Resolve promise with result.
1197                subtle.resolve_promise_with_key(promise, result);
1198            }));
1199
1200        promise
1201    }
1202
1203    /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-exportKey>
1204    fn ExportKey(
1205        &self,
1206        format: KeyFormat,
1207        key: &CryptoKey,
1208        comp: InRealm,
1209        can_gc: CanGc,
1210    ) -> Rc<Promise> {
1211        // Step 1. Let format and key be the format and key parameters passed to the exportKey()
1212        // method, respectively.
1213        // NOTE: We did that in method parameter.
1214
1215        // Step 2. Let realm be the relevant realm of this.
1216        // Step 3. Let promise be a new Promise.
1217        let promise = Promise::new_in_current_realm(comp, can_gc);
1218
1219        // Step 4. Return promise and perform the remaining steps in parallel.
1220        let trusted_subtle = Trusted::new(self);
1221        let trusted_promise = TrustedPromise::new(promise.clone());
1222        let trusted_key = Trusted::new(key);
1223        self.global()
1224            .task_manager()
1225            .dom_manipulation_task_source()
1226            .queue(task!(export_key: move || {
1227                let subtle = trusted_subtle.root();
1228                let promise = trusted_promise.root();
1229                let key = trusted_key.root();
1230
1231                // Step 5. If the following steps or referenced procedures say to throw an error,
1232                // queue a global task on the crypto task source, given realm's global object, to
1233                // reject promise with the returned error; and then terminate the algorithm.
1234
1235                // Step 6. If the name member of the [[algorithm]] internal slot of key does not
1236                // identify a registered algorithm that supports the export key operation, then
1237                // throw a NotSupportedError.
1238                if matches!(
1239                    key.algorithm().name(),
1240                    ALG_SHA1 | ALG_SHA256 | ALG_SHA384 | ALG_SHA512 | ALG_HKDF | ALG_PBKDF2
1241                ) {
1242                    subtle.reject_promise_with_error(promise, Error::NotSupported(None));
1243                    return;
1244                }
1245
1246                // Step 7. If the [[extractable]] internal slot of key is false, then throw an
1247                // InvalidAccessError.
1248                if !key.Extractable() {
1249                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
1250                    return;
1251                }
1252
1253                // Step 8. Let result be the result of performing the export key operation
1254                // specified by the [[algorithm]] internal slot of key using key and format.
1255                let result = match perform_export_key_operation(format, &key) {
1256                    Ok(exported_key) => exported_key,
1257                    Err(error) => {
1258                        subtle.reject_promise_with_error(promise, error);
1259                        return;
1260                    },
1261                };
1262
1263                // Step 9. Queue a global task on the crypto task source, given realm's global
1264                // object, to perform the remaining steps.
1265                // Step 10.
1266                // If format is equal to the strings "raw", "pkcs8", or "spki":
1267                //     Let result be the result of creating an ArrayBuffer in realm, containing
1268                //     result.
1269                // If format is equal to the string "jwk":
1270                //     Let result be the result of converting result to an ECMAScript Object in
1271                //     realm, as defined by [WebIDL].
1272                // Step 11. Resolve promise with result.
1273                // NOTE: We determine the format by pattern matching on result, which is an
1274                // ExportedKey enum.
1275                match result {
1276                    ExportedKey::Bytes(bytes) => {
1277                        subtle.resolve_promise_with_data(promise, bytes);
1278                    },
1279                    ExportedKey::Jwk(jwk) => {
1280                        subtle.resolve_promise_with_jwk(promise, jwk);
1281                    },
1282                }
1283            }));
1284        promise
1285    }
1286
1287    /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-wrapKey>
1288    fn WrapKey(
1289        &self,
1290        cx: JSContext,
1291        format: KeyFormat,
1292        key: &CryptoKey,
1293        wrapping_key: &CryptoKey,
1294        algorithm: AlgorithmIdentifier,
1295        comp: InRealm,
1296        can_gc: CanGc,
1297    ) -> Rc<Promise> {
1298        // Step 1. Let format, key, wrappingKey and algorithm be the format, key, wrappingKey and
1299        // wrapAlgorithm parameters passed to the wrapKey() method, respectively.
1300        // NOTE: We did that in method parameter.
1301
1302        // Step 2. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
1303        // to algorithm and op set to "wrapKey".
1304        let mut normalized_algorithm_result =
1305            normalize_algorithm(cx, &Operation::WrapKey, &algorithm, can_gc);
1306
1307        // Step 3. If an error occurred, let normalizedAlgorithm be the result of normalizing an
1308        // algorithm, with alg set to algorithm and op set to "encrypt".
1309        if normalized_algorithm_result.is_err() {
1310            normalized_algorithm_result =
1311                normalize_algorithm(cx, &Operation::Encrypt, &algorithm, can_gc);
1312        }
1313
1314        // Step 4. If an error occurred, return a Promise rejected with normalizedAlgorithm.
1315        let promise = Promise::new_in_current_realm(comp, can_gc);
1316        let normalized_algorithm = match normalized_algorithm_result {
1317            Ok(normalized_algorithm) => normalized_algorithm,
1318            Err(error) => {
1319                promise.reject_error(error, can_gc);
1320                return promise;
1321            },
1322        };
1323
1324        // Step 5. Let realm be the relevant realm of this.
1325        // Step 6. Let promise be a new Promise.
1326        // NOTE: We did that in preparation of Step 4.
1327
1328        // Step 7. Return promise and perform the remaining steps in parallel.
1329        let trusted_subtle = Trusted::new(self);
1330        let trusted_key = Trusted::new(key);
1331        let trusted_wrapping_key = Trusted::new(wrapping_key);
1332        let trusted_promise = TrustedPromise::new(promise.clone());
1333        self.global()
1334            .task_manager()
1335            .dom_manipulation_task_source()
1336            .queue(task!(wrap_key: move || {
1337                let subtle = trusted_subtle.root();
1338                let key = trusted_key.root();
1339                let wrapping_key = trusted_wrapping_key.root();
1340                let promise = trusted_promise.root();
1341
1342                // Step 8. If the following steps or referenced procedures say to throw an error,
1343                // queue a global task on the crypto task source, given realm's global object, to
1344                // reject promise with the returned error; and then terminate the algorithm.
1345
1346                // Step 9. If the name member of normalizedAlgorithm is not equal to the name
1347                // attribute of the [[algorithm]] internal slot of wrappingKey then throw an
1348                // InvalidAccessError.
1349                if normalized_algorithm.name() != wrapping_key.algorithm().name() {
1350                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
1351                    return;
1352                }
1353
1354                // Step 10. If the [[usages]] internal slot of wrappingKey does not contain an
1355                // entry that is "wrapKey", then throw an InvalidAccessError.
1356                if !wrapping_key.usages().contains(&KeyUsage::WrapKey) {
1357                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
1358                    return;
1359                }
1360
1361                // Step 11. If the algorithm identified by the [[algorithm]] internal slot of key
1362                // does not support the export key operation, then throw a NotSupportedError.
1363
1364                if matches!(
1365                    key.algorithm().name(),
1366                    ALG_SHA1 | ALG_SHA256 | ALG_SHA384 | ALG_SHA512 | ALG_HKDF | ALG_PBKDF2
1367                ) {
1368                    subtle.reject_promise_with_error(promise, Error::NotSupported(None));
1369                    return;
1370                }
1371
1372
1373                // Step 12. If the [[extractable]] internal slot of key is false, then throw an
1374                // InvalidAccessError.
1375                if !key.Extractable() {
1376                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
1377                    return;
1378                }
1379
1380                // Step 13. Let exportedKey be the result of performing the export key operation
1381                // specified by the [[algorithm]] internal slot of key using key and format.
1382                let exported_key = match perform_export_key_operation(format, &key) {
1383                    Ok(exported_key) => exported_key,
1384                    Err(error) => {
1385                        subtle.reject_promise_with_error(promise, error);
1386                        return;
1387                    },
1388                };
1389
1390                // Step 14.
1391                // If format is equal to the strings "raw", "pkcs8", or "spki":
1392                //     Let bytes be exportedKey.
1393                // If format is equal to the string "jwk":
1394                //     Step 14.1. Let json be the result of representing exportedKey as a UTF-16
1395                //     string conforming to the JSON grammar; for example, by executing the
1396                //     JSON.stringify algorithm specified in [ECMA-262] in the context of a new
1397                //     global object.
1398                //     Step 14.2. Let bytes be the result of UTF-8 encoding json.
1399                // NOTE: We determine the format by pattern matching on result, which is an
1400                // ExportedKey enum.
1401                let cx = GlobalScope::get_cx();
1402                let bytes = match exported_key {
1403                    ExportedKey::Bytes(bytes) => bytes,
1404                    ExportedKey::Jwk(jwk) => match jwk.stringify(cx) {
1405                        Ok(stringified_jwk) => stringified_jwk.as_bytes().to_vec(),
1406                        Err(error) => {
1407                            subtle.reject_promise_with_error(promise, error);
1408                            return;
1409                        },
1410                    },
1411                };
1412
1413                // Step 15.
1414                // If normalizedAlgorithm supports the wrap key operation:
1415                //     Let result be the result of performing the wrap key operation specified by
1416                //     normalizedAlgorithm using algorithm, wrappingKey as key and bytes as
1417                //     plaintext.
1418                // Otherwise, if normalizedAlgorithm supports the encrypt operation:
1419                //     Let result be the result of performing the encrypt operation specified by
1420                //     normalizedAlgorithm using algorithm, wrappingKey as key and bytes as
1421                //     plaintext.
1422                // Otherwise:
1423                //     throw a NotSupportedError.
1424                let mut result = normalized_algorithm.wrap_key(&wrapping_key, &bytes);
1425                if result.is_err() {
1426                    result = normalized_algorithm.encrypt(&wrapping_key, &bytes);
1427                }
1428                let result = match result {
1429                    Ok(result) => result,
1430                    Err(error) => {
1431                        subtle.reject_promise_with_error(promise, error);
1432                        return;
1433                    },
1434                };
1435
1436                // Step 16. Queue a global task on the crypto task source, given realm's global
1437                // object, to perform the remaining steps.
1438                // Step 17. Let result be the result of creating an ArrayBuffer in realm,
1439                // containing result.
1440                // Step 18. Resolve promise with result.
1441                subtle.resolve_promise_with_data(promise, result);
1442            }));
1443        promise
1444    }
1445
1446    /// <https://w3c.github.io/webcrypto/#SubtleCrypto-method-unwrapKey>
1447    fn UnwrapKey(
1448        &self,
1449        cx: JSContext,
1450        format: KeyFormat,
1451        wrapped_key: ArrayBufferViewOrArrayBuffer,
1452        unwrapping_key: &CryptoKey,
1453        algorithm: AlgorithmIdentifier,
1454        unwrapped_key_algorithm: AlgorithmIdentifier,
1455        extractable: bool,
1456        usages: Vec<KeyUsage>,
1457        comp: InRealm,
1458        can_gc: CanGc,
1459    ) -> Rc<Promise> {
1460        // Step 1. Let format, unwrappingKey, algorithm, unwrappedKeyAlgorithm, extractable and
1461        // usages, be the format, unwrappingKey, unwrapAlgorithm, unwrappedKeyAlgorithm,
1462        // extractable and keyUsages parameters passed to the unwrapKey() method, respectively.
1463        // NOTE: We did that in method parameter.
1464
1465        // Step 2. Let wrappedKey be the result of getting a copy of the bytes held by the
1466        // wrappedKey parameter passed to the unwrapKey() method.
1467        let wrapped_key = match wrapped_key {
1468            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
1469            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
1470        };
1471
1472        // Step 3. Let normalizedAlgorithm be the result of normalizing an algorithm, with alg set
1473        // to algorithm and op set to "unwrapKey".
1474        let mut normalized_algorithm =
1475            normalize_algorithm(cx, &Operation::UnwrapKey, &algorithm, can_gc);
1476
1477        // Step 4. If an error occurred, let normalizedAlgorithm be the result of normalizing an
1478        // algorithm, with alg set to algorithm and op set to "decrypt".
1479        if normalized_algorithm.is_err() {
1480            normalized_algorithm = normalize_algorithm(cx, &Operation::Decrypt, &algorithm, can_gc);
1481        }
1482
1483        // Step 5. If an error occurred, return a Promise rejected with normalizedAlgorithm.
1484        let promise = Promise::new_in_current_realm(comp, can_gc);
1485        let normalized_algorithm = match normalized_algorithm {
1486            Ok(algorithm) => algorithm,
1487            Err(error) => {
1488                promise.reject_error(error, can_gc);
1489                return promise;
1490            },
1491        };
1492
1493        // Step 6. Let normalizedKeyAlgorithm be the result of normalizing an algorithm, with alg
1494        // set to unwrappedKeyAlgorithm and op set to "importKey".
1495        // Step 7. If an error occurred, return a Promise rejected with normalizedKeyAlgorithm.
1496        let normalized_key_algorithm = match normalize_algorithm(
1497            cx,
1498            &Operation::ImportKey,
1499            &unwrapped_key_algorithm,
1500            can_gc,
1501        ) {
1502            Ok(algorithm) => algorithm,
1503            Err(error) => {
1504                promise.reject_error(error, can_gc);
1505                return promise;
1506            },
1507        };
1508
1509        // Step 8. Let realm be the relevant realm of this.
1510        // Step 9. Let promise be a new Promise.
1511        // NOTE: We did that in preparation of Step 5.
1512
1513        // Step 10. Return promise and perform the remaining steps in parallel.
1514        let trusted_subtle = Trusted::new(self);
1515        let trusted_unwrapping_key = Trusted::new(unwrapping_key);
1516        let trusted_promise = TrustedPromise::new(promise.clone());
1517        self.global().task_manager().dom_manipulation_task_source().queue(
1518            task!(unwrap_key: move || {
1519                let subtle = trusted_subtle.root();
1520                let unwrapping_key = trusted_unwrapping_key.root();
1521                let promise = trusted_promise.root();
1522
1523                // Step 11. If the following steps or referenced procedures say to throw an error,
1524                // queue a global task on the crypto task source, given realm's global object, to
1525                // reject promise with the returned error; and then terminate the algorithm.
1526
1527                // Step 12. If the name member of normalizedAlgorithm is not equal to the name
1528                // attribute of the [[algorithm]] internal slot of unwrappingKey then throw an
1529                // InvalidAccessError.
1530                if normalized_algorithm.name() != unwrapping_key.algorithm().name() {
1531                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
1532                    return;
1533                }
1534
1535                // Step 13. If the [[usages]] internal slot of unwrappingKey does not contain an
1536                // entry that is "unwrapKey", then throw an InvalidAccessError.
1537                if !unwrapping_key.usages().contains(&KeyUsage::UnwrapKey) {
1538                    subtle.reject_promise_with_error(promise, Error::InvalidAccess(None));
1539                    return;
1540                }
1541
1542                // Step 14.
1543                // If normalizedAlgorithm supports an unwrap key operation:
1544                //     Let bytes be the result of performing the unwrap key operation specified by
1545                //     normalizedAlgorithm using algorithm, unwrappingKey as key and wrappedKey as
1546                //     ciphertext.
1547                // Otherwise, if normalizedAlgorithm supports a decrypt operation:
1548                //     Let bytes be the result of performing the decrypt operation specified by
1549                //     normalizedAlgorithm using algorithm, unwrappingKey as key and wrappedKey as
1550                //     ciphertext.
1551                // Otherwise:
1552                //     throw a NotSupportedError.
1553                let mut bytes = normalized_algorithm.unwrap_key(&unwrapping_key, &wrapped_key);
1554                if bytes.is_err() {
1555                    bytes = normalized_algorithm.decrypt(&unwrapping_key, &wrapped_key);
1556                }
1557                let bytes = match bytes {
1558                    Ok(bytes) => bytes,
1559                    Err(error) => {
1560                        subtle.reject_promise_with_error(promise, error);
1561                        return;
1562                    },
1563                };
1564
1565                // Step 15.
1566                // If format is equal to the strings "raw", "pkcs8", or "spki":
1567                //     Let key be bytes.
1568                // If format is equal to the string "jwk":
1569                //     Let key be the result of executing the parse a JWK algorithm, with bytes as
1570                //     the data to be parsed.
1571                //     NOTE: We only parse bytes by executing the parse a JWK algorithm, but keep
1572                //     it as raw bytes for later steps, instead of converting it to a JsonWebKey
1573                //     dictionary.
1574                let cx = GlobalScope::get_cx();
1575                if format == KeyFormat::Jwk {
1576                    if let Err(error) = JsonWebKey::parse(cx, &bytes) {
1577                        subtle.reject_promise_with_error(promise, error);
1578                        return;
1579                    }
1580                }
1581                let key = bytes;
1582
1583                // Step 16. Let result be the result of performing the import key operation
1584                // specified by normalizedKeyAlgorithm using unwrappedKeyAlgorithm as algorithm,
1585                // format, usages and extractable and with key as keyData.
1586                let result = match normalized_key_algorithm.import_key(
1587                    &subtle.global(),
1588                    format,
1589                    &key,
1590                    extractable,
1591                    usages.clone(),
1592                    CanGc::note(),
1593                ) {
1594                    Ok(result) => result,
1595                    Err(error) => {
1596                        subtle.reject_promise_with_error(promise, error);
1597                        return;
1598                    },
1599                };
1600
1601                // Step 17. If the [[type]] internal slot of result is "secret" or "private" and
1602                // usages is empty, then throw a SyntaxError.
1603                if matches!(result.Type(), KeyType::Secret | KeyType::Private) && usages.is_empty() {
1604                    subtle.reject_promise_with_error(promise, Error::Syntax(None));
1605                    return;
1606                }
1607
1608                // Step 18. Set the [[extractable]] internal slot of result to extractable.
1609                // Step 19. Set the [[usages]] internal slot of result to the normalized value of
1610                // usages.
1611                // NOTE: Done by normalized_algorithm.import_key in Step 16.
1612
1613                // Step 20. Queue a global task on the crypto task source, given realm's global
1614                // object, to perform the remaining steps.
1615                // Step 21. Let result be the result of converting result to an ECMAScript Object
1616                // in realm, as defined by [WebIDL].
1617                // Step 22. Resolve promise with result.
1618                subtle.resolve_promise_with_key(promise, result);
1619            }),
1620        );
1621        promise
1622    }
1623}
1624
1625// These "subtle" structs are proxies for the codegen'd dicts which don't hold a DOMString
1626// so they can be sent safely when running steps in parallel.
1627
1628/// <https://w3c.github.io/webcrypto/#dfn-Algorithm>
1629#[derive(Clone, Debug, MallocSizeOf)]
1630struct SubtleAlgorithm {
1631    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
1632    name: String,
1633}
1634
1635impl From<Algorithm> for SubtleAlgorithm {
1636    fn from(params: Algorithm) -> Self {
1637        SubtleAlgorithm {
1638            name: params.name.to_string(),
1639        }
1640    }
1641}
1642
1643/// <https://w3c.github.io/webcrypto/#dfn-KeyAlgorithm>
1644#[derive(Clone, Debug, MallocSizeOf)]
1645pub(crate) struct SubtleKeyAlgorithm {
1646    /// <https://w3c.github.io/webcrypto/#dom-keyalgorithm-name>
1647    name: String,
1648}
1649
1650impl SubtleKeyAlgorithm {
1651    fn block_size_in_bits(&self) -> Result<u32, Error> {
1652        let size = match self.name.as_str() {
1653            ALG_SHA1 => 512,
1654            ALG_SHA256 => 512,
1655            ALG_SHA384 => 1024,
1656            ALG_SHA512 => 1024,
1657            _ => {
1658                return Err(Error::NotSupported(None));
1659            },
1660        };
1661
1662        Ok(size)
1663    }
1664}
1665
1666impl From<NormalizedAlgorithm> for SubtleKeyAlgorithm {
1667    fn from(value: NormalizedAlgorithm) -> Self {
1668        SubtleKeyAlgorithm {
1669            name: value.name().to_string(),
1670        }
1671    }
1672}
1673
1674impl SafeToJSValConvertible for SubtleKeyAlgorithm {
1675    fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
1676        let dictionary = KeyAlgorithm {
1677            name: self.name.clone().into(),
1678        };
1679        dictionary.safe_to_jsval(cx, rval, can_gc);
1680    }
1681}
1682
1683/// <https://w3c.github.io/webcrypto/#dfn-EcdsaParams>
1684#[derive(Clone, Debug, MallocSizeOf)]
1685struct SubtleEcdsaParams {
1686    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
1687    name: String,
1688
1689    /// <https://w3c.github.io/webcrypto/#dfn-EcdsaParams-hash>
1690    hash: SubtleKeyAlgorithm,
1691}
1692
1693impl TryFrom<RootedTraceableBox<EcdsaParams>> for SubtleEcdsaParams {
1694    type Error = Error;
1695
1696    fn try_from(value: RootedTraceableBox<EcdsaParams>) -> Result<Self, Error> {
1697        let cx = GlobalScope::get_cx();
1698        let hash = normalize_algorithm(cx, &Operation::Digest, &value.hash, CanGc::note())?;
1699        Ok(SubtleEcdsaParams {
1700            name: value.parent.name.to_string(),
1701            hash: hash.into(),
1702        })
1703    }
1704}
1705
1706/// <https://w3c.github.io/webcrypto/#dfn-EcKeyGenParams>
1707#[derive(Clone, Debug, MallocSizeOf)]
1708struct SubtleEcKeyGenParams {
1709    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
1710    name: String,
1711
1712    /// <https://w3c.github.io/webcrypto/#dfn-EcKeyGenParams-namedCurve>
1713    named_curve: String,
1714}
1715
1716impl From<EcKeyGenParams> for SubtleEcKeyGenParams {
1717    fn from(value: EcKeyGenParams) -> Self {
1718        SubtleEcKeyGenParams {
1719            name: value.parent.name.to_string(),
1720            named_curve: value.namedCurve.to_string(),
1721        }
1722    }
1723}
1724
1725/// <https://w3c.github.io/webcrypto/#dfn-EcKeyAlgorithm>
1726#[derive(Clone, Debug, MallocSizeOf)]
1727pub(crate) struct SubtleEcKeyAlgorithm {
1728    /// <https://w3c.github.io/webcrypto/#dom-keyalgorithm-name>
1729    name: String,
1730
1731    /// <https://w3c.github.io/webcrypto/#dfn-EcKeyAlgorithm-namedCurve>
1732    named_curve: String,
1733}
1734
1735impl SafeToJSValConvertible for SubtleEcKeyAlgorithm {
1736    fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
1737        let parent = KeyAlgorithm {
1738            name: self.name.clone().into(),
1739        };
1740        let dictionary = EcKeyAlgorithm {
1741            parent,
1742            namedCurve: self.named_curve.clone().into(),
1743        };
1744        dictionary.safe_to_jsval(cx, rval, can_gc);
1745    }
1746}
1747
1748/// <https://w3c.github.io/webcrypto/#dfn-EcKeyImportParams>
1749#[derive(Clone, Debug, MallocSizeOf)]
1750struct SubtleEcKeyImportParams {
1751    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
1752    name: String,
1753
1754    /// <https://w3c.github.io/webcrypto/#dfn-EcKeyImportParams-namedCurve>
1755    named_curve: String,
1756}
1757
1758impl From<EcKeyImportParams> for SubtleEcKeyImportParams {
1759    fn from(value: EcKeyImportParams) -> Self {
1760        SubtleEcKeyImportParams {
1761            name: value.parent.name.to_string(),
1762            named_curve: value.namedCurve.to_string(),
1763        }
1764    }
1765}
1766
1767/// <https://w3c.github.io/webcrypto/#dfn-EcdhKeyDeriveParams>
1768#[derive(Clone, MallocSizeOf)]
1769struct SubtleEcdhKeyDeriveParams {
1770    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
1771    name: String,
1772
1773    /// <https://w3c.github.io/webcrypto/#dfn-EcdhKeyDeriveParams-public>
1774    public: Trusted<CryptoKey>,
1775}
1776
1777impl From<EcdhKeyDeriveParams> for SubtleEcdhKeyDeriveParams {
1778    fn from(value: EcdhKeyDeriveParams) -> Self {
1779        SubtleEcdhKeyDeriveParams {
1780            name: value.parent.name.to_string(),
1781            public: Trusted::new(&value.public),
1782        }
1783    }
1784}
1785
1786/// <https://w3c.github.io/webcrypto/#dfn-AesCtrParams>
1787#[derive(Clone, Debug, MallocSizeOf)]
1788struct SubtleAesCtrParams {
1789    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
1790    name: String,
1791
1792    /// <https://w3c.github.io/webcrypto/#dfn-AesCtrParams-counter>
1793    counter: Vec<u8>,
1794
1795    /// <https://w3c.github.io/webcrypto/#dfn-AesCtrParams-length>
1796    length: u8,
1797}
1798
1799impl From<RootedTraceableBox<AesCtrParams>> for SubtleAesCtrParams {
1800    fn from(params: RootedTraceableBox<AesCtrParams>) -> Self {
1801        let counter = match &params.counter {
1802            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
1803            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
1804        };
1805        SubtleAesCtrParams {
1806            name: params.parent.name.to_string(),
1807            counter,
1808            length: params.length,
1809        }
1810    }
1811}
1812
1813/// <https://w3c.github.io/webcrypto/#dfn-AesKeyAlgorithm>
1814#[derive(Clone, Debug, MallocSizeOf)]
1815pub(crate) struct SubtleAesKeyAlgorithm {
1816    /// <https://w3c.github.io/webcrypto/#dom-keyalgorithm-name>
1817    name: String,
1818
1819    /// <https://w3c.github.io/webcrypto/#dfn-AesKeyAlgorithm-length>
1820    length: u16,
1821}
1822
1823impl SafeToJSValConvertible for SubtleAesKeyAlgorithm {
1824    fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
1825        let parent = KeyAlgorithm {
1826            name: self.name.clone().into(),
1827        };
1828        let dictionary = AesKeyAlgorithm {
1829            parent,
1830            length: self.length,
1831        };
1832        dictionary.safe_to_jsval(cx, rval, can_gc);
1833    }
1834}
1835
1836/// <https://w3c.github.io/webcrypto/#dfn-AesKeyGenParams>
1837#[derive(Clone, Debug, MallocSizeOf)]
1838struct SubtleAesKeyGenParams {
1839    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
1840    name: String,
1841
1842    /// <https://w3c.github.io/webcrypto/#dfn-AesKeyGenParams-length>
1843    length: u16,
1844}
1845
1846impl From<AesKeyGenParams> for SubtleAesKeyGenParams {
1847    fn from(params: AesKeyGenParams) -> Self {
1848        SubtleAesKeyGenParams {
1849            name: params.parent.name.to_string(),
1850            length: params.length,
1851        }
1852    }
1853}
1854
1855/// <https://w3c.github.io/webcrypto/#dfn-AesDerivedKeyParams>
1856#[derive(Clone, Debug, MallocSizeOf)]
1857struct SubtleAesDerivedKeyParams {
1858    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
1859    name: String,
1860
1861    /// <https://w3c.github.io/webcrypto/#dfn-AesDerivedKeyParams-length>
1862    length: u16,
1863}
1864
1865impl From<AesDerivedKeyParams> for SubtleAesDerivedKeyParams {
1866    fn from(params: AesDerivedKeyParams) -> Self {
1867        SubtleAesDerivedKeyParams {
1868            name: params.parent.name.to_string(),
1869            length: params.length,
1870        }
1871    }
1872}
1873
1874/// <https://w3c.github.io/webcrypto/#dfn-AesCbcParams>
1875#[derive(Clone, Debug, MallocSizeOf)]
1876struct SubtleAesCbcParams {
1877    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
1878    name: String,
1879
1880    /// <https://w3c.github.io/webcrypto/#dfn-AesCbcParams-iv>
1881    iv: Vec<u8>,
1882}
1883
1884impl From<RootedTraceableBox<AesCbcParams>> for SubtleAesCbcParams {
1885    fn from(params: RootedTraceableBox<AesCbcParams>) -> Self {
1886        let iv = match &params.iv {
1887            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
1888            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
1889        };
1890        SubtleAesCbcParams {
1891            name: params.parent.name.to_string(),
1892            iv,
1893        }
1894    }
1895}
1896
1897/// <https://w3c.github.io/webcrypto/#dfn-AesGcmParams>
1898#[derive(Clone, Debug, MallocSizeOf)]
1899struct SubtleAesGcmParams {
1900    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
1901    name: String,
1902
1903    /// <https://w3c.github.io/webcrypto/#dfn-AesGcmParams-iv>
1904    iv: Vec<u8>,
1905
1906    /// <https://w3c.github.io/webcrypto/#dfn-AesGcmParams-additionalData>
1907    additional_data: Option<Vec<u8>>,
1908
1909    /// <https://w3c.github.io/webcrypto/#dfn-AesGcmParams-tagLength>
1910    tag_length: Option<u8>,
1911}
1912
1913impl From<RootedTraceableBox<AesGcmParams>> for SubtleAesGcmParams {
1914    fn from(params: RootedTraceableBox<AesGcmParams>) -> Self {
1915        let iv = match &params.iv {
1916            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
1917            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
1918        };
1919        let additional_data = params.additionalData.as_ref().map(|data| match data {
1920            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
1921            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
1922        });
1923
1924        SubtleAesGcmParams {
1925            name: params.parent.name.to_string(),
1926            iv,
1927            additional_data,
1928            tag_length: params.tagLength,
1929        }
1930    }
1931}
1932
1933/// <https://w3c.github.io/webcrypto/#dfn-HmacImportParams>
1934#[derive(Clone, Debug, MallocSizeOf)]
1935struct SubtleHmacImportParams {
1936    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
1937    name: String,
1938
1939    /// <https://w3c.github.io/webcrypto/#dfn-HmacImportParams-hash>
1940    hash: SubtleKeyAlgorithm,
1941
1942    /// <https://w3c.github.io/webcrypto/#dfn-HmacImportParams-length>
1943    length: Option<u32>,
1944}
1945
1946impl TryFrom<RootedTraceableBox<HmacImportParams>> for SubtleHmacImportParams {
1947    type Error = Error;
1948
1949    fn try_from(params: RootedTraceableBox<HmacImportParams>) -> Result<Self, Error> {
1950        let cx = GlobalScope::get_cx();
1951        let hash = normalize_algorithm(cx, &Operation::Digest, &params.hash, CanGc::note())?;
1952        Ok(SubtleHmacImportParams {
1953            name: params.parent.name.to_string(),
1954            hash: hash.into(),
1955            length: params.length,
1956        })
1957    }
1958}
1959
1960/// <https://w3c.github.io/webcrypto/#dfn-HmacKeyAlgorithm>
1961#[derive(Clone, Debug, MallocSizeOf)]
1962pub(crate) struct SubtleHmacKeyAlgorithm {
1963    /// <https://w3c.github.io/webcrypto/#dom-keyalgorithm-name>
1964    name: String,
1965
1966    /// <https://w3c.github.io/webcrypto/#dfn-HmacKeyAlgorithm-hash>
1967    hash: SubtleKeyAlgorithm,
1968
1969    /// <https://w3c.github.io/webcrypto/#dfn-HmacKeyGenParams-length>
1970    length: u32,
1971}
1972
1973impl SafeToJSValConvertible for SubtleHmacKeyAlgorithm {
1974    fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
1975        let parent = KeyAlgorithm {
1976            name: self.name.clone().into(),
1977        };
1978        let hash = KeyAlgorithm {
1979            name: self.hash.name.clone().into(),
1980        };
1981        let dictionary = HmacKeyAlgorithm {
1982            parent,
1983            hash,
1984            length: self.length,
1985        };
1986        dictionary.safe_to_jsval(cx, rval, can_gc);
1987    }
1988}
1989
1990/// <https://w3c.github.io/webcrypto/#dfn-HmacKeyGenParams>
1991#[derive(Clone, Debug, MallocSizeOf)]
1992struct SubtleHmacKeyGenParams {
1993    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
1994    name: String,
1995
1996    /// <https://w3c.github.io/webcrypto/#dfn-HmacKeyGenParams-hash>
1997    hash: SubtleKeyAlgorithm,
1998
1999    /// <https://w3c.github.io/webcrypto/#dfn-HmacKeyGenParams-length>
2000    length: Option<u32>,
2001}
2002
2003impl TryFrom<RootedTraceableBox<HmacKeyGenParams>> for SubtleHmacKeyGenParams {
2004    type Error = Error;
2005
2006    fn try_from(params: RootedTraceableBox<HmacKeyGenParams>) -> Result<Self, Error> {
2007        let cx = GlobalScope::get_cx();
2008        let hash = normalize_algorithm(cx, &Operation::Digest, &params.hash, CanGc::note())?;
2009        Ok(SubtleHmacKeyGenParams {
2010            name: params.parent.name.to_string(),
2011            hash: hash.into(),
2012            length: params.length,
2013        })
2014    }
2015}
2016
2017/// <https://w3c.github.io/webcrypto/#dfn-HkdfParams>
2018#[derive(Clone, Debug, MallocSizeOf)]
2019pub(crate) struct SubtleHkdfParams {
2020    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2021    name: String,
2022
2023    /// <https://w3c.github.io/webcrypto/#dfn-HkdfParams-hash>
2024    hash: SubtleKeyAlgorithm,
2025
2026    /// <https://w3c.github.io/webcrypto/#dfn-HkdfParams-salt>
2027    salt: Vec<u8>,
2028
2029    /// <https://w3c.github.io/webcrypto/#dfn-HkdfParams-info>
2030    info: Vec<u8>,
2031}
2032
2033impl TryFrom<RootedTraceableBox<HkdfParams>> for SubtleHkdfParams {
2034    type Error = Error;
2035
2036    fn try_from(params: RootedTraceableBox<HkdfParams>) -> Result<Self, Error> {
2037        let cx = GlobalScope::get_cx();
2038        let hash = normalize_algorithm(cx, &Operation::Digest, &params.hash, CanGc::note())?;
2039        let salt = match &params.salt {
2040            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2041            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2042        };
2043        let info = match &params.info {
2044            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2045            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2046        };
2047        Ok(SubtleHkdfParams {
2048            name: params.parent.name.to_string(),
2049            hash: hash.into(),
2050            salt,
2051            info,
2052        })
2053    }
2054}
2055
2056/// <https://w3c.github.io/webcrypto/#dfn-Pbkdf2Params>
2057#[derive(Clone, Debug, MallocSizeOf)]
2058pub(crate) struct SubtlePbkdf2Params {
2059    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2060    name: String,
2061
2062    /// <https://w3c.github.io/webcrypto/#dfn-Pbkdf2Params-salt>
2063    salt: Vec<u8>,
2064
2065    /// <https://w3c.github.io/webcrypto/#dfn-Pbkdf2Params-iterations>
2066    iterations: u32,
2067
2068    /// <https://w3c.github.io/webcrypto/#dfn-Pbkdf2Params-hash>
2069    hash: SubtleKeyAlgorithm,
2070}
2071
2072impl TryFrom<RootedTraceableBox<Pbkdf2Params>> for SubtlePbkdf2Params {
2073    type Error = Error;
2074
2075    fn try_from(params: RootedTraceableBox<Pbkdf2Params>) -> Result<Self, Error> {
2076        let cx = GlobalScope::get_cx();
2077        let salt = match &params.salt {
2078            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2079            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2080        };
2081        let hash = normalize_algorithm(cx, &Operation::Digest, &params.hash, CanGc::note())?;
2082        Ok(SubtlePbkdf2Params {
2083            name: params.parent.name.to_string(),
2084            salt,
2085            iterations: params.iterations,
2086            hash: hash.into(),
2087        })
2088    }
2089}
2090
2091/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-AeadParams>
2092#[derive(Clone, Debug, MallocSizeOf)]
2093struct SubtleAeadParams {
2094    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2095    name: String,
2096
2097    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-AeadParams-iv>
2098    iv: Vec<u8>,
2099
2100    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-AeadParams-additionalData>
2101    additional_data: Option<Vec<u8>>,
2102
2103    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-AeadParams-tagLength>
2104    tag_length: Option<u8>,
2105}
2106
2107impl From<RootedTraceableBox<AeadParams>> for SubtleAeadParams {
2108    fn from(value: RootedTraceableBox<AeadParams>) -> Self {
2109        let iv = match &value.iv {
2110            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2111            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2112        };
2113        let additional_data = value.additionalData.as_ref().map(|data| match data {
2114            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2115            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2116        });
2117
2118        SubtleAeadParams {
2119            name: value.parent.name.to_string(),
2120            iv,
2121            additional_data,
2122            tag_length: value.tagLength,
2123        }
2124    }
2125}
2126
2127/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-CShakeParams>
2128#[derive(Clone, Debug, MallocSizeOf)]
2129struct SubtleCShakeParams {
2130    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2131    name: String,
2132
2133    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-CShakeParams-length>
2134    length: u32,
2135
2136    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-CShakeParams-functionName>
2137    function_name: Option<Vec<u8>>,
2138
2139    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-CShakeParams-customization>
2140    customization: Option<Vec<u8>>,
2141}
2142
2143impl From<RootedTraceableBox<CShakeParams>> for SubtleCShakeParams {
2144    fn from(value: RootedTraceableBox<CShakeParams>) -> Self {
2145        let function_name = value
2146            .functionName
2147            .as_ref()
2148            .map(|function_name| match function_name {
2149                ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2150                ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2151            });
2152        let customization = value
2153            .customization
2154            .as_ref()
2155            .map(|customization| match customization {
2156                ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2157                ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2158            });
2159        SubtleCShakeParams {
2160            name: value.parent.name.to_string(),
2161            length: value.length,
2162            function_name,
2163            customization,
2164        }
2165    }
2166}
2167
2168/// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params>
2169#[derive(Clone, Debug, MallocSizeOf)]
2170struct SubtleArgon2Params {
2171    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
2172    name: String,
2173
2174    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-nonce>
2175    nonce: Vec<u8>,
2176
2177    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-parallelism>
2178    parallelism: u32,
2179
2180    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-memory>
2181    memory: u32,
2182
2183    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-passes>
2184    passes: u32,
2185
2186    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-version>
2187    version: Option<u8>,
2188
2189    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-secretValue>
2190    secret_value: Option<Vec<u8>>,
2191
2192    /// <https://wicg.github.io/webcrypto-modern-algos/#dfn-Argon2Params-associatedData>
2193    associated_data: Option<Vec<u8>>,
2194}
2195
2196impl From<RootedTraceableBox<Argon2Params>> for SubtleArgon2Params {
2197    fn from(value: RootedTraceableBox<Argon2Params>) -> Self {
2198        let nonce = match &value.nonce {
2199            ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2200            ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2201        };
2202        let secret_value = value
2203            .secretValue
2204            .as_ref()
2205            .map(|secret_value| match secret_value {
2206                ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2207                ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2208            });
2209        let associated_data =
2210            value
2211                .associatedData
2212                .as_ref()
2213                .map(|associated_data| match associated_data {
2214                    ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
2215                    ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
2216                });
2217        SubtleArgon2Params {
2218            name: value.parent.name.to_string(),
2219            nonce,
2220            parallelism: value.parallelism,
2221            memory: value.memory,
2222            passes: value.passes,
2223            version: value.version,
2224            secret_value,
2225            associated_data,
2226        }
2227    }
2228}
2229
2230/// Helper to abstract the conversion process of a JS value into many different WebIDL dictionaries.
2231fn dictionary_from_jsval<T>(cx: JSContext, value: HandleValue, can_gc: CanGc) -> Fallible<T>
2232where
2233    T: SafeFromJSValConvertible<Config = ()>,
2234{
2235    let conversion = T::safe_from_jsval(cx, value, (), can_gc).map_err(|_| Error::JSFailed)?;
2236    match conversion {
2237        ConversionResult::Success(dictionary) => Ok(dictionary),
2238        ConversionResult::Failure(error) => Err(Error::Type(error.into())),
2239    }
2240}
2241
2242/// The returned type of the successful export key operation. `Bytes` should be used when the key
2243/// is exported in "raw", "spki" or "pkcs8" format. `Jwk` should be used when the key is exported
2244/// in "jwk" format.
2245enum ExportedKey {
2246    Bytes(Vec<u8>),
2247    Jwk(Box<JsonWebKey>),
2248}
2249
2250/// Union type of KeyAlgorithm and IDL dictionary types derived from it. Note that we actually use
2251/// our "subtle" structs of the corresponding IDL dictionary types so that they can be easily
2252/// passed to another threads.
2253#[derive(Clone, Debug, MallocSizeOf)]
2254#[expect(clippy::enum_variant_names)]
2255pub(crate) enum KeyAlgorithmAndDerivatives {
2256    KeyAlgorithm(SubtleKeyAlgorithm),
2257    EcKeyAlgorithm(SubtleEcKeyAlgorithm),
2258    AesKeyAlgorithm(SubtleAesKeyAlgorithm),
2259    HmacKeyAlgorithm(SubtleHmacKeyAlgorithm),
2260}
2261
2262impl KeyAlgorithmAndDerivatives {
2263    fn name(&self) -> &str {
2264        match self {
2265            KeyAlgorithmAndDerivatives::KeyAlgorithm(algo) => &algo.name,
2266            KeyAlgorithmAndDerivatives::EcKeyAlgorithm(algo) => &algo.name,
2267            KeyAlgorithmAndDerivatives::AesKeyAlgorithm(algo) => &algo.name,
2268            KeyAlgorithmAndDerivatives::HmacKeyAlgorithm(algo) => &algo.name,
2269        }
2270    }
2271}
2272
2273impl From<NormalizedAlgorithm> for KeyAlgorithmAndDerivatives {
2274    fn from(value: NormalizedAlgorithm) -> Self {
2275        KeyAlgorithmAndDerivatives::KeyAlgorithm(SubtleKeyAlgorithm {
2276            name: value.name().to_string(),
2277        })
2278    }
2279}
2280
2281impl SafeToJSValConvertible for KeyAlgorithmAndDerivatives {
2282    fn safe_to_jsval(&self, cx: JSContext, rval: MutableHandleValue, can_gc: CanGc) {
2283        match self {
2284            KeyAlgorithmAndDerivatives::KeyAlgorithm(algo) => algo.safe_to_jsval(cx, rval, can_gc),
2285            KeyAlgorithmAndDerivatives::EcKeyAlgorithm(algo) => {
2286                algo.safe_to_jsval(cx, rval, can_gc)
2287            },
2288            KeyAlgorithmAndDerivatives::AesKeyAlgorithm(algo) => {
2289                algo.safe_to_jsval(cx, rval, can_gc)
2290            },
2291            KeyAlgorithmAndDerivatives::HmacKeyAlgorithm(algo) => {
2292                algo.safe_to_jsval(cx, rval, can_gc)
2293            },
2294        }
2295    }
2296}
2297
2298#[expect(unused)]
2299trait RsaOtherPrimesInfoExt {
2300    fn from_value(value: &serde_json::Value) -> Result<RsaOtherPrimesInfo, Error>;
2301}
2302
2303impl RsaOtherPrimesInfoExt for RsaOtherPrimesInfo {
2304    fn from_value(value: &serde_json::Value) -> Result<RsaOtherPrimesInfo, Error> {
2305        let serde_json::Value::Object(object) = value else {
2306            return Err(Error::Data(None));
2307        };
2308
2309        let mut rsa_other_primes_info: RsaOtherPrimesInfo = Default::default();
2310        for (key, value) in object {
2311            match key.as_str() {
2312                "r" => {
2313                    rsa_other_primes_info.r =
2314                        Some(DOMString::from(value.as_str().ok_or(Error::Data(None))?))
2315                },
2316                "d" => {
2317                    rsa_other_primes_info.d =
2318                        Some(DOMString::from(value.as_str().ok_or(Error::Data(None))?))
2319                },
2320                "t" => {
2321                    rsa_other_primes_info.t =
2322                        Some(DOMString::from(value.as_str().ok_or(Error::Data(None))?))
2323                },
2324                _ => {
2325                    // Additional members can be present in the JWK; if not understood by
2326                    // implementations encountering them, they MUST be ignored.
2327                },
2328            }
2329        }
2330
2331        Ok(rsa_other_primes_info)
2332    }
2333}
2334
2335trait JsonWebKeyExt {
2336    fn parse(cx: JSContext, data: &[u8]) -> Result<JsonWebKey, Error>;
2337    fn stringify(&self, cx: JSContext) -> Result<DOMString, Error>;
2338    fn get_usages_from_key_ops(&self) -> Result<Vec<KeyUsage>, Error>;
2339    #[expect(unused)]
2340    fn get_rsa_other_primes_info_from_oth(&self) -> Result<&[RsaOtherPrimesInfo], Error>;
2341    fn check_key_ops(&self, specified_usages: &[KeyUsage]) -> Result<(), Error>;
2342}
2343
2344impl JsonWebKeyExt for JsonWebKey {
2345    /// <https://w3c.github.io/webcrypto/#concept-parse-a-jwk>
2346    #[expect(unsafe_code)]
2347    fn parse(cx: JSContext, data: &[u8]) -> Result<JsonWebKey, Error> {
2348        // Step 1. Let data be the sequence of bytes to be parsed.
2349        // (It is given as a method paramter.)
2350
2351        // Step 2. Let json be the Unicode string that results from interpreting data according to UTF-8.
2352        let json = String::from_utf8_lossy(data);
2353
2354        // Step 3. Convert json to UTF-16.
2355        let json: Vec<_> = json.encode_utf16().collect();
2356
2357        // Step 4. Let result be the object literal that results from executing the JSON.parse
2358        // internal function in the context of a new global object, with text argument set to a
2359        // JavaScript String containing json.
2360        rooted!(in(*cx) let mut result = UndefinedValue());
2361        unsafe {
2362            if !JS_ParseJSON(*cx, json.as_ptr(), json.len() as u32, result.handle_mut()) {
2363                return Err(Error::JSFailed);
2364            }
2365        }
2366
2367        // Step 5. Let key be the result of converting result to the IDL dictionary type of JsonWebKey.
2368        let key = match JsonWebKey::new(cx, result.handle(), CanGc::note()) {
2369            Ok(ConversionResult::Success(key)) => key,
2370            Ok(ConversionResult::Failure(error)) => {
2371                return Err(Error::Type(error.to_string()));
2372            },
2373            Err(()) => {
2374                return Err(Error::JSFailed);
2375            },
2376        };
2377
2378        // Step 6. If the kty field of key is not defined, then throw a DataError.
2379        if key.kty.is_none() {
2380            return Err(Error::Data(None));
2381        }
2382
2383        // Step 7. Result key.
2384        Ok(key)
2385    }
2386
2387    /// Convert a JsonWebKey value to DOMString. We first convert the JsonWebKey value to
2388    /// JavaScript value, and then serialize it by performing steps in
2389    /// <https://infra.spec.whatwg.org/#serialize-a-javascript-value-to-a-json-string>. This acts
2390    /// like the opposite of JsonWebKey::parse if you further convert the stringified result to
2391    /// bytes.
2392    fn stringify(&self, cx: JSContext) -> Result<DOMString, Error> {
2393        rooted!(in(*cx) let mut data = UndefinedValue());
2394        self.safe_to_jsval(cx, data.handle_mut(), CanGc::note());
2395        serialize_jsval_to_json_utf8(cx, data.handle())
2396    }
2397
2398    fn get_usages_from_key_ops(&self) -> Result<Vec<KeyUsage>, Error> {
2399        let mut usages = vec![];
2400        for op in self.key_ops.as_ref().ok_or(Error::Data(None))? {
2401            usages.push(KeyUsage::from_str(&op.str()).map_err(|_| Error::Data(None))?);
2402        }
2403        Ok(usages)
2404    }
2405
2406    fn get_rsa_other_primes_info_from_oth(&self) -> Result<&[RsaOtherPrimesInfo], Error> {
2407        self.oth.as_deref().ok_or(Error::Data(None))
2408    }
2409
2410    /// If the key_ops field of jwk is present, and is invalid according to the requirements of
2411    /// JSON Web Key [JWK] or does not contain all of the specified usages values, then throw a
2412    /// DataError.
2413    fn check_key_ops(&self, specified_usages: &[KeyUsage]) -> Result<(), Error> {
2414        // If the key_ops field of jwk is present,
2415        if let Some(ref key_ops) = self.key_ops {
2416            // and is invalid according to the requirements of JSON Web Key [JWK]:
2417            // 1. Duplicate key operation values MUST NOT be present in the array.
2418            if key_ops
2419                .iter()
2420                .collect::<std::collections::HashSet<_>>()
2421                .len() <
2422                key_ops.len()
2423            {
2424                return Err(Error::Data(None));
2425            }
2426            // 2. The "use" and "key_ops" JWK members SHOULD NOT be used together; however, if both
2427            //    are used, the information they convey MUST be consistent.
2428            if let Some(ref use_) = self.use_ {
2429                if key_ops.iter().any(|op| op != use_) {
2430                    return Err(Error::Data(None));
2431                }
2432            }
2433
2434            // or does not contain all of the specified usages values
2435            let key_ops_as_usages = self.get_usages_from_key_ops()?;
2436            if !specified_usages
2437                .iter()
2438                .all(|specified_usage| key_ops_as_usages.contains(specified_usage))
2439            {
2440                return Err(Error::Data(None));
2441            }
2442        }
2443
2444        Ok(())
2445    }
2446}
2447
2448/// The successful output of [`normalize_algorithm`], in form of an union type of (our "subtle"
2449/// binding of) IDL dictionary types.
2450///
2451/// <https://w3c.github.io/webcrypto/#algorithm-normalization-normalize-an-algorithm>
2452#[derive(Clone, MallocSizeOf)]
2453enum NormalizedAlgorithm {
2454    Algorithm(SubtleAlgorithm),
2455    EcdsaParams(SubtleEcdsaParams),
2456    EcKeyGenParams(SubtleEcKeyGenParams),
2457    EcKeyImportParams(SubtleEcKeyImportParams),
2458    EcdhKeyDeriveParams(SubtleEcdhKeyDeriveParams),
2459    AesCtrParams(SubtleAesCtrParams),
2460    AesKeyGenParams(SubtleAesKeyGenParams),
2461    AesDerivedKeyParams(SubtleAesDerivedKeyParams),
2462    AesCbcParams(SubtleAesCbcParams),
2463    AesGcmParams(SubtleAesGcmParams),
2464    HmacImportParams(SubtleHmacImportParams),
2465    HmacKeyGenParams(SubtleHmacKeyGenParams),
2466    HkdfParams(SubtleHkdfParams),
2467    Pbkdf2Params(SubtlePbkdf2Params),
2468    AeadParams(SubtleAeadParams),
2469    CShakeParams(SubtleCShakeParams),
2470    Argon2Params(SubtleArgon2Params),
2471}
2472
2473/// <https://w3c.github.io/webcrypto/#algorithm-normalization-normalize-an-algorithm>
2474fn normalize_algorithm(
2475    cx: JSContext,
2476    op: &Operation,
2477    alg: &AlgorithmIdentifier,
2478    can_gc: CanGc,
2479) -> Result<NormalizedAlgorithm, Error> {
2480    match alg {
2481        // If alg is an instance of a DOMString:
2482        ObjectOrString::String(name) => {
2483            // Return the result of running the normalize an algorithm algorithm, with the alg set
2484            // to a new Algorithm dictionary whose name attribute is alg, and with the op set to
2485            // op.
2486            let alg = Algorithm {
2487                name: name.to_owned(),
2488            };
2489            rooted!(in(*cx) let mut alg_value = UndefinedValue());
2490            alg.safe_to_jsval(cx, alg_value.handle_mut(), CanGc::note());
2491            let alg_obj = RootedTraceableBox::new(Heap::default());
2492            alg_obj.set(alg_value.to_object());
2493            normalize_algorithm(cx, op, &ObjectOrString::Object(alg_obj), can_gc)
2494        },
2495        // If alg is an object:
2496        ObjectOrString::Object(obj) => {
2497            // Step 1. Let registeredAlgorithms be the associative container stored at the op key
2498            // of supportedAlgorithms.
2499            // NOTE: The supportedAlgorithms and registeredAlgorithms are expressed as match arms
2500            // in Step 5.2 - Step 10.
2501
2502            // Stpe 2. Let initialAlg be the result of converting the ECMAScript object represented
2503            // by alg to the IDL dictionary type Algorithm, as defined by [WebIDL].
2504            // Step 3. If an error occurred, return the error and terminate this algorithm.
2505            rooted!(in(*cx) let value = ObjectValue(obj.get()));
2506            let initial_alg = dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2507
2508            // Step 4. Let algName be the value of the name attribute of initialAlg.
2509            // Step 5.
2510            //     If registeredAlgorithms contains a key that is a case-insensitive string match
2511            //     for algName:
2512            //         Step 5.1. Set algName to the value of the matching key.
2513            //     Otherwise:
2514            //         Return a new NotSupportedError and terminate this algorithm.
2515            let Some(&alg_name) = SUPPORTED_ALGORITHMS.iter().find(|supported_algorithm| {
2516                supported_algorithm.eq_ignore_ascii_case(&initial_alg.name.str())
2517            }) else {
2518                return Err(Error::NotSupported(None));
2519            };
2520
2521            // Step 5.2. Let desiredType be the IDL dictionary type stored at algName in
2522            // registeredAlgorithms.
2523            // Step 6. Let normalizedAlgorithm be the result of converting the ECMAScript object
2524            // represented by alg to the IDL dictionary type desiredType, as defined by [WebIDL].
2525            // Step 7. Set the name attribute of normalizedAlgorithm to algName.
2526            // Step 8. If an error occurred, return the error and terminate this algorithm.
2527            // Step 9. Let dictionaries be a list consisting of the IDL dictionary type desiredType
2528            // and all of desiredType's inherited dictionaries, in order from least to most
2529            // derived.
2530            // Step 10. For each dictionary dictionary in dictionaries:
2531            //     Step 10.1. For each dictionary member member declared on dictionary, in order:
2532            //         Step 10.1.1. Let key be the identifier of member.
2533            //         Step 10.1.2. Let idlValue be the value of the dictionary member with key
2534            //         name of key on normalizedAlgorithm.
2535            //         Step 10.1.3.
2536            //             If member is of the type BufferSource and is present:
2537            //                 Set the dictionary member on normalizedAlgorithm with key name key
2538            //                 to the result of getting a copy of the bytes held by idlValue,
2539            //                 replacing the current value.
2540            //             If member is of the type HashAlgorithmIdentifier:
2541            //                 Set the dictionary member on normalizedAlgorithm with key name key
2542            //                 to the result of normalizing an algorithm, with the alg set to
2543            //                 idlValue and the op set to "digest".
2544            //             If member is of the type AlgorithmIdentifier:
2545            //                 Set the dictionary member on normalizedAlgorithm with key name key
2546            //                 to the result of normalizing an algorithm, with the alg set to
2547            //                 idlValue and the op set to the operation defined by the
2548            //                 specification that defines the algorithm identified by algName.
2549            //
2550            // NOTE: Instead of calculating the desiredType in Step 5.2 and filling in the IDL
2551            // dictionary in Step 7-10, we directly convert the JS object to our "subtle" binding
2552            // structs to complete Step 6, and put it in the NormalizedAlgorithm enum.
2553            //
2554            // NOTE: Step 10.1.3 is done by the `From` and `TryFrom` trait implementation of
2555            // "subtle" binding structs.
2556            let normalized_algorithm = match (alg_name, op) {
2557                // <https://w3c.github.io/webcrypto/#ecdsa-registration>
2558                (ALG_ECDSA, Operation::Sign) => {
2559                    let mut params = dictionary_from_jsval::<RootedTraceableBox<EcdsaParams>>(
2560                        cx,
2561                        value.handle(),
2562                        can_gc,
2563                    )?;
2564                    params.parent.name = DOMString::from(alg_name);
2565                    NormalizedAlgorithm::EcdsaParams(params.try_into()?)
2566                },
2567                (ALG_ECDSA, Operation::Verify) => {
2568                    let mut params = dictionary_from_jsval::<RootedTraceableBox<EcdsaParams>>(
2569                        cx,
2570                        value.handle(),
2571                        can_gc,
2572                    )?;
2573                    params.parent.name = DOMString::from(alg_name);
2574                    NormalizedAlgorithm::EcdsaParams(params.try_into()?)
2575                },
2576                (ALG_ECDSA, Operation::GenerateKey) => {
2577                    let mut params =
2578                        dictionary_from_jsval::<EcKeyGenParams>(cx, value.handle(), can_gc)?;
2579                    params.parent.name = DOMString::from(alg_name);
2580                    NormalizedAlgorithm::EcKeyGenParams(params.into())
2581                },
2582                (ALG_ECDSA, Operation::ImportKey) => {
2583                    let mut params =
2584                        dictionary_from_jsval::<EcKeyImportParams>(cx, value.handle(), can_gc)?;
2585                    params.parent.name = DOMString::from(alg_name);
2586                    NormalizedAlgorithm::EcKeyImportParams(params.into())
2587                },
2588                (ALG_ECDSA, Operation::ExportKey) => {
2589                    let mut params =
2590                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2591                    params.name = DOMString::from(alg_name);
2592                    NormalizedAlgorithm::Algorithm(params.into())
2593                },
2594
2595                // <https://w3c.github.io/webcrypto/#ecdh-registration>
2596                (ALG_ECDH, Operation::GenerateKey) => {
2597                    let mut params =
2598                        dictionary_from_jsval::<EcKeyGenParams>(cx, value.handle(), can_gc)?;
2599                    params.parent.name = DOMString::from(alg_name);
2600                    NormalizedAlgorithm::EcKeyGenParams(params.into())
2601                },
2602                (ALG_ECDH, Operation::DeriveBits) => {
2603                    let mut params =
2604                        dictionary_from_jsval::<EcdhKeyDeriveParams>(cx, value.handle(), can_gc)?;
2605                    params.parent.name = DOMString::from(alg_name);
2606                    NormalizedAlgorithm::EcdhKeyDeriveParams(params.into())
2607                },
2608                (ALG_ECDH, Operation::ImportKey) => {
2609                    let mut params =
2610                        dictionary_from_jsval::<EcKeyImportParams>(cx, value.handle(), can_gc)?;
2611                    params.parent.name = DOMString::from(alg_name);
2612                    NormalizedAlgorithm::EcKeyImportParams(params.into())
2613                },
2614                (ALG_ECDH, Operation::ExportKey) => {
2615                    let mut params =
2616                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2617                    params.name = DOMString::from(alg_name);
2618                    NormalizedAlgorithm::Algorithm(params.into())
2619                },
2620
2621                // <https://w3c.github.io/webcrypto/#ed25519-registration>
2622                (ALG_ED25519, Operation::Sign) => {
2623                    let mut params =
2624                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2625                    params.name = DOMString::from(alg_name);
2626                    NormalizedAlgorithm::Algorithm(params.into())
2627                },
2628                (ALG_ED25519, Operation::Verify) => {
2629                    let mut params =
2630                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2631                    params.name = DOMString::from(alg_name);
2632                    NormalizedAlgorithm::Algorithm(params.into())
2633                },
2634                (ALG_ED25519, Operation::GenerateKey) => {
2635                    let mut params =
2636                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2637                    params.name = DOMString::from(alg_name);
2638                    NormalizedAlgorithm::Algorithm(params.into())
2639                },
2640                (ALG_ED25519, Operation::ImportKey) => {
2641                    let mut params =
2642                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2643                    params.name = DOMString::from(alg_name);
2644                    NormalizedAlgorithm::Algorithm(params.into())
2645                },
2646                (ALG_ED25519, Operation::ExportKey) => {
2647                    let mut params =
2648                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2649                    params.name = DOMString::from(alg_name);
2650                    NormalizedAlgorithm::Algorithm(params.into())
2651                },
2652
2653                // <https://w3c.github.io/webcrypto/#x25519-registration>
2654                (ALG_X25519, Operation::DeriveBits) => {
2655                    let mut params =
2656                        dictionary_from_jsval::<EcdhKeyDeriveParams>(cx, value.handle(), can_gc)?;
2657                    params.parent.name = DOMString::from(alg_name);
2658                    NormalizedAlgorithm::EcdhKeyDeriveParams(params.into())
2659                },
2660                (ALG_X25519, Operation::GenerateKey) => {
2661                    let mut params =
2662                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2663                    params.name = DOMString::from(alg_name);
2664                    NormalizedAlgorithm::Algorithm(params.into())
2665                },
2666                (ALG_X25519, Operation::ImportKey) => {
2667                    let mut params =
2668                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2669                    params.name = DOMString::from(alg_name);
2670                    NormalizedAlgorithm::Algorithm(params.into())
2671                },
2672                (ALG_X25519, Operation::ExportKey) => {
2673                    let mut params =
2674                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2675                    params.name = DOMString::from(alg_name);
2676                    NormalizedAlgorithm::Algorithm(params.into())
2677                },
2678
2679                // <https://w3c.github.io/webcrypto/#aes-ctr-registration>
2680                (ALG_AES_CTR, Operation::Encrypt) => {
2681                    let mut params = dictionary_from_jsval::<RootedTraceableBox<AesCtrParams>>(
2682                        cx,
2683                        value.handle(),
2684                        can_gc,
2685                    )?;
2686                    params.parent.name = DOMString::from(alg_name);
2687                    NormalizedAlgorithm::AesCtrParams(params.into())
2688                },
2689                (ALG_AES_CTR, Operation::Decrypt) => {
2690                    let mut params = dictionary_from_jsval::<RootedTraceableBox<AesCtrParams>>(
2691                        cx,
2692                        value.handle(),
2693                        can_gc,
2694                    )?;
2695                    params.parent.name = DOMString::from(alg_name);
2696                    NormalizedAlgorithm::AesCtrParams(params.into())
2697                },
2698                (ALG_AES_CTR, Operation::GenerateKey) => {
2699                    let mut params =
2700                        dictionary_from_jsval::<AesKeyGenParams>(cx, value.handle(), can_gc)?;
2701                    params.parent.name = DOMString::from(alg_name);
2702                    NormalizedAlgorithm::AesKeyGenParams(params.into())
2703                },
2704                (ALG_AES_CTR, Operation::ImportKey) => {
2705                    let mut params =
2706                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2707                    params.name = DOMString::from(alg_name);
2708                    NormalizedAlgorithm::Algorithm(params.into())
2709                },
2710                (ALG_AES_CTR, Operation::ExportKey) => {
2711                    let mut params =
2712                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2713                    params.name = DOMString::from(alg_name);
2714                    NormalizedAlgorithm::Algorithm(params.into())
2715                },
2716                (ALG_AES_CTR, Operation::GetKeyLength) => {
2717                    let mut params =
2718                        dictionary_from_jsval::<AesDerivedKeyParams>(cx, value.handle(), can_gc)?;
2719                    params.parent.name = DOMString::from(alg_name);
2720                    NormalizedAlgorithm::AesDerivedKeyParams(params.into())
2721                },
2722
2723                // <https://w3c.github.io/webcrypto/#aes-cbc-registration>
2724                (ALG_AES_CBC, Operation::Encrypt) => {
2725                    let mut params = dictionary_from_jsval::<RootedTraceableBox<AesCbcParams>>(
2726                        cx,
2727                        value.handle(),
2728                        can_gc,
2729                    )?;
2730                    params.parent.name = DOMString::from(alg_name);
2731                    NormalizedAlgorithm::AesCbcParams(params.into())
2732                },
2733                (ALG_AES_CBC, Operation::Decrypt) => {
2734                    let mut params = dictionary_from_jsval::<RootedTraceableBox<AesCbcParams>>(
2735                        cx,
2736                        value.handle(),
2737                        can_gc,
2738                    )?;
2739                    params.parent.name = DOMString::from(alg_name);
2740                    NormalizedAlgorithm::AesCbcParams(params.into())
2741                },
2742                (ALG_AES_CBC, Operation::GenerateKey) => {
2743                    let mut params =
2744                        dictionary_from_jsval::<AesKeyGenParams>(cx, value.handle(), can_gc)?;
2745                    params.parent.name = DOMString::from(alg_name);
2746                    NormalizedAlgorithm::AesKeyGenParams(params.into())
2747                },
2748                (ALG_AES_CBC, Operation::ImportKey) => {
2749                    let mut params =
2750                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2751                    params.name = DOMString::from(alg_name);
2752                    NormalizedAlgorithm::Algorithm(params.into())
2753                },
2754                (ALG_AES_CBC, Operation::ExportKey) => {
2755                    let mut params =
2756                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2757                    params.name = DOMString::from(alg_name);
2758                    NormalizedAlgorithm::Algorithm(params.into())
2759                },
2760                (ALG_AES_CBC, Operation::GetKeyLength) => {
2761                    let mut params =
2762                        dictionary_from_jsval::<AesDerivedKeyParams>(cx, value.handle(), can_gc)?;
2763                    params.parent.name = DOMString::from(alg_name);
2764                    NormalizedAlgorithm::AesDerivedKeyParams(params.into())
2765                },
2766
2767                // <https://w3c.github.io/webcrypto/#aes-gcm-registration>
2768                (ALG_AES_GCM, Operation::Encrypt) => {
2769                    let mut params = dictionary_from_jsval::<RootedTraceableBox<AesGcmParams>>(
2770                        cx,
2771                        value.handle(),
2772                        can_gc,
2773                    )?;
2774                    params.parent.name = DOMString::from(alg_name);
2775                    NormalizedAlgorithm::AesGcmParams(params.into())
2776                },
2777                (ALG_AES_GCM, Operation::Decrypt) => {
2778                    let mut params = dictionary_from_jsval::<RootedTraceableBox<AesGcmParams>>(
2779                        cx,
2780                        value.handle(),
2781                        can_gc,
2782                    )?;
2783                    params.parent.name = DOMString::from(alg_name);
2784                    NormalizedAlgorithm::AesGcmParams(params.into())
2785                },
2786                (ALG_AES_GCM, Operation::GenerateKey) => {
2787                    let mut params =
2788                        dictionary_from_jsval::<AesKeyGenParams>(cx, value.handle(), can_gc)?;
2789                    params.parent.name = DOMString::from(alg_name);
2790                    NormalizedAlgorithm::AesKeyGenParams(params.into())
2791                },
2792                (ALG_AES_GCM, Operation::ImportKey) => {
2793                    let mut params =
2794                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2795                    params.name = DOMString::from(alg_name);
2796                    NormalizedAlgorithm::Algorithm(params.into())
2797                },
2798                (ALG_AES_GCM, Operation::ExportKey) => {
2799                    let mut params =
2800                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2801                    params.name = DOMString::from(alg_name);
2802                    NormalizedAlgorithm::Algorithm(params.into())
2803                },
2804                (ALG_AES_GCM, Operation::GetKeyLength) => {
2805                    let mut params =
2806                        dictionary_from_jsval::<AesDerivedKeyParams>(cx, value.handle(), can_gc)?;
2807                    params.parent.name = DOMString::from(alg_name);
2808                    NormalizedAlgorithm::AesDerivedKeyParams(params.into())
2809                },
2810
2811                // <https://w3c.github.io/webcrypto/#aes-kw-registration>
2812                (ALG_AES_KW, Operation::WrapKey) => {
2813                    let mut params =
2814                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2815                    params.name = DOMString::from(alg_name);
2816                    NormalizedAlgorithm::Algorithm(params.into())
2817                },
2818                (ALG_AES_KW, Operation::UnwrapKey) => {
2819                    let mut params =
2820                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2821                    params.name = DOMString::from(alg_name);
2822                    NormalizedAlgorithm::Algorithm(params.into())
2823                },
2824                (ALG_AES_KW, Operation::GenerateKey) => {
2825                    let mut params =
2826                        dictionary_from_jsval::<AesKeyGenParams>(cx, value.handle(), can_gc)?;
2827                    params.parent.name = DOMString::from(alg_name);
2828                    NormalizedAlgorithm::AesKeyGenParams(params.into())
2829                },
2830                (ALG_AES_KW, Operation::ImportKey) => {
2831                    let mut params =
2832                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2833                    params.name = DOMString::from(alg_name);
2834                    NormalizedAlgorithm::Algorithm(params.into())
2835                },
2836                (ALG_AES_KW, Operation::ExportKey) => {
2837                    let mut params =
2838                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2839                    params.name = DOMString::from(alg_name);
2840                    NormalizedAlgorithm::Algorithm(params.into())
2841                },
2842                (ALG_AES_KW, Operation::GetKeyLength) => {
2843                    let mut params =
2844                        dictionary_from_jsval::<AesDerivedKeyParams>(cx, value.handle(), can_gc)?;
2845                    params.parent.name = DOMString::from(alg_name);
2846                    NormalizedAlgorithm::AesDerivedKeyParams(params.into())
2847                },
2848
2849                // <https://w3c.github.io/webcrypto/#hmac-registration>
2850                (ALG_HMAC, Operation::Sign) => {
2851                    let mut params =
2852                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2853                    params.name = DOMString::from(alg_name);
2854                    NormalizedAlgorithm::Algorithm(params.into())
2855                },
2856                (ALG_HMAC, Operation::Verify) => {
2857                    let mut params =
2858                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2859                    params.name = DOMString::from(alg_name);
2860                    NormalizedAlgorithm::Algorithm(params.into())
2861                },
2862                (ALG_HMAC, Operation::GenerateKey) => {
2863                    let mut params = dictionary_from_jsval::<RootedTraceableBox<HmacKeyGenParams>>(
2864                        cx,
2865                        value.handle(),
2866                        can_gc,
2867                    )?;
2868                    params.parent.name = DOMString::from(alg_name);
2869                    NormalizedAlgorithm::HmacKeyGenParams(params.try_into()?)
2870                },
2871                (ALG_HMAC, Operation::ImportKey) => {
2872                    let mut params = dictionary_from_jsval::<RootedTraceableBox<HmacImportParams>>(
2873                        cx,
2874                        value.handle(),
2875                        can_gc,
2876                    )?;
2877                    params.parent.name = DOMString::from(alg_name);
2878                    NormalizedAlgorithm::HmacImportParams(params.try_into()?)
2879                },
2880                (ALG_HMAC, Operation::ExportKey) => {
2881                    let mut params =
2882                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2883                    params.name = DOMString::from(alg_name);
2884                    NormalizedAlgorithm::Algorithm(params.into())
2885                },
2886                (ALG_HMAC, Operation::GetKeyLength) => {
2887                    let mut params = dictionary_from_jsval::<RootedTraceableBox<HmacImportParams>>(
2888                        cx,
2889                        value.handle(),
2890                        can_gc,
2891                    )?;
2892                    params.parent.name = DOMString::from(alg_name);
2893                    NormalizedAlgorithm::HmacImportParams(params.try_into()?)
2894                },
2895
2896                // <https://w3c.github.io/webcrypto/#sha-registration>
2897                (ALG_SHA1, Operation::Digest) => {
2898                    let mut params =
2899                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2900                    params.name = DOMString::from(alg_name);
2901                    NormalizedAlgorithm::Algorithm(params.into())
2902                },
2903                (ALG_SHA256, Operation::Digest) => {
2904                    let mut params =
2905                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2906                    params.name = DOMString::from(alg_name);
2907                    NormalizedAlgorithm::Algorithm(params.into())
2908                },
2909                (ALG_SHA384, Operation::Digest) => {
2910                    let mut params =
2911                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2912                    params.name = DOMString::from(alg_name);
2913                    NormalizedAlgorithm::Algorithm(params.into())
2914                },
2915                (ALG_SHA512, Operation::Digest) => {
2916                    let mut params =
2917                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2918                    params.name = DOMString::from(alg_name);
2919                    NormalizedAlgorithm::Algorithm(params.into())
2920                },
2921
2922                // <https://w3c.github.io/webcrypto/#hkdf-registration>
2923                (ALG_HKDF, Operation::DeriveBits) => {
2924                    let mut params = dictionary_from_jsval::<RootedTraceableBox<HkdfParams>>(
2925                        cx,
2926                        value.handle(),
2927                        can_gc,
2928                    )?;
2929                    params.parent.name = DOMString::from(alg_name);
2930                    NormalizedAlgorithm::HkdfParams(params.try_into()?)
2931                },
2932                (ALG_HKDF, Operation::ImportKey) => {
2933                    let mut params =
2934                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2935                    params.name = DOMString::from(alg_name);
2936                    NormalizedAlgorithm::Algorithm(params.into())
2937                },
2938                (ALG_HKDF, Operation::GetKeyLength) => {
2939                    let mut params =
2940                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2941                    params.name = DOMString::from(alg_name);
2942                    NormalizedAlgorithm::Algorithm(params.into())
2943                },
2944
2945                // <https://w3c.github.io/webcrypto/#pbkdf2-registration>
2946                (ALG_PBKDF2, Operation::DeriveBits) => {
2947                    let mut params = dictionary_from_jsval::<RootedTraceableBox<Pbkdf2Params>>(
2948                        cx,
2949                        value.handle(),
2950                        can_gc,
2951                    )?;
2952                    params.parent.name = DOMString::from(alg_name);
2953                    NormalizedAlgorithm::Pbkdf2Params(params.try_into()?)
2954                },
2955                (ALG_PBKDF2, Operation::ImportKey) => {
2956                    let mut params =
2957                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2958                    params.name = DOMString::from(alg_name);
2959                    NormalizedAlgorithm::Algorithm(params.into())
2960                },
2961                (ALG_PBKDF2, Operation::GetKeyLength) => {
2962                    let mut params =
2963                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2964                    params.name = DOMString::from(alg_name);
2965                    NormalizedAlgorithm::Algorithm(params.into())
2966                },
2967
2968                // <https://wicg.github.io/webcrypto-modern-algos/#chacha20-poly1305-registration>
2969                (ALG_CHACHA20_POLY1305, Operation::Encrypt) => {
2970                    let mut params = dictionary_from_jsval::<RootedTraceableBox<AeadParams>>(
2971                        cx,
2972                        value.handle(),
2973                        can_gc,
2974                    )?;
2975                    params.parent.name = DOMString::from(alg_name);
2976                    NormalizedAlgorithm::AeadParams(params.into())
2977                },
2978                (ALG_CHACHA20_POLY1305, Operation::Decrypt) => {
2979                    let mut params = dictionary_from_jsval::<RootedTraceableBox<AeadParams>>(
2980                        cx,
2981                        value.handle(),
2982                        can_gc,
2983                    )?;
2984                    params.parent.name = DOMString::from(alg_name);
2985                    NormalizedAlgorithm::AeadParams(params.into())
2986                },
2987                (ALG_CHACHA20_POLY1305, Operation::GenerateKey) => {
2988                    let mut params =
2989                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2990                    params.name = DOMString::from(alg_name);
2991                    NormalizedAlgorithm::Algorithm(params.into())
2992                },
2993                (ALG_CHACHA20_POLY1305, Operation::ImportKey) => {
2994                    let mut params =
2995                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
2996                    params.name = DOMString::from(alg_name);
2997                    NormalizedAlgorithm::Algorithm(params.into())
2998                },
2999                (ALG_CHACHA20_POLY1305, Operation::ExportKey) => {
3000                    let mut params =
3001                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
3002                    params.name = DOMString::from(alg_name);
3003                    NormalizedAlgorithm::Algorithm(params.into())
3004                },
3005                (ALG_CHACHA20_POLY1305, Operation::GetKeyLength) => {
3006                    let mut params =
3007                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
3008                    params.name = DOMString::from(alg_name);
3009                    NormalizedAlgorithm::Algorithm(params.into())
3010                },
3011
3012                // <https://wicg.github.io/webcrypto-modern-algos/#sha3-registration>
3013                (ALG_SHA3_256, Operation::Digest) => {
3014                    let mut params =
3015                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
3016                    params.name = DOMString::from(alg_name);
3017                    NormalizedAlgorithm::Algorithm(params.into())
3018                },
3019                (ALG_SHA3_384, Operation::Digest) => {
3020                    let mut params =
3021                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
3022                    params.name = DOMString::from(alg_name);
3023                    NormalizedAlgorithm::Algorithm(params.into())
3024                },
3025                (ALG_SHA3_512, Operation::Digest) => {
3026                    let mut params =
3027                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
3028                    params.name = DOMString::from(alg_name);
3029                    NormalizedAlgorithm::Algorithm(params.into())
3030                },
3031
3032                // <https://wicg.github.io/webcrypto-modern-algos/#cshake-registration>
3033                (ALG_CSHAKE_128, Operation::Digest) => {
3034                    let mut params = dictionary_from_jsval::<RootedTraceableBox<CShakeParams>>(
3035                        cx,
3036                        value.handle(),
3037                        can_gc,
3038                    )?;
3039                    params.parent.name = DOMString::from(alg_name);
3040                    NormalizedAlgorithm::CShakeParams(params.into())
3041                },
3042                (ALG_CSHAKE_256, Operation::Digest) => {
3043                    let mut params = dictionary_from_jsval::<RootedTraceableBox<CShakeParams>>(
3044                        cx,
3045                        value.handle(),
3046                        can_gc,
3047                    )?;
3048                    params.parent.name = DOMString::from(alg_name);
3049                    NormalizedAlgorithm::CShakeParams(params.into())
3050                },
3051
3052                // <https://wicg.github.io/webcrypto-modern-algos/#argon2-registration>
3053                (ALG_ARGON2D | ALG_ARGON2I | ALG_ARGON2ID, Operation::DeriveBits) => {
3054                    let mut params = dictionary_from_jsval::<RootedTraceableBox<Argon2Params>>(
3055                        cx,
3056                        value.handle(),
3057                        can_gc,
3058                    )?;
3059                    params.parent.name = DOMString::from(alg_name);
3060                    NormalizedAlgorithm::Argon2Params(params.into())
3061                },
3062                (ALG_ARGON2D | ALG_ARGON2I | ALG_ARGON2ID, Operation::ImportKey) => {
3063                    let mut params =
3064                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
3065                    params.name = DOMString::from(alg_name);
3066                    NormalizedAlgorithm::Algorithm(params.into())
3067                },
3068                (ALG_ARGON2D | ALG_ARGON2I | ALG_ARGON2ID, Operation::GetKeyLength) => {
3069                    let mut params =
3070                        dictionary_from_jsval::<Algorithm>(cx, value.handle(), can_gc)?;
3071                    params.name = DOMString::from(alg_name);
3072                    NormalizedAlgorithm::Algorithm(params.into())
3073                },
3074
3075                _ => return Err(Error::NotSupported(None)),
3076            };
3077
3078            // Step 11. Return normalizedAlgorithm.
3079            Ok(normalized_algorithm)
3080        },
3081    }
3082}
3083
3084impl NormalizedAlgorithm {
3085    /// <https://w3c.github.io/webcrypto/#dom-algorithm-name>
3086    fn name(&self) -> &str {
3087        match self {
3088            NormalizedAlgorithm::Algorithm(algo) => &algo.name,
3089            NormalizedAlgorithm::EcdsaParams(algo) => &algo.name,
3090            NormalizedAlgorithm::EcKeyGenParams(algo) => &algo.name,
3091            NormalizedAlgorithm::EcKeyImportParams(algo) => &algo.name,
3092            NormalizedAlgorithm::EcdhKeyDeriveParams(algo) => &algo.name,
3093            NormalizedAlgorithm::AesCtrParams(algo) => &algo.name,
3094            NormalizedAlgorithm::AesKeyGenParams(algo) => &algo.name,
3095            NormalizedAlgorithm::AesDerivedKeyParams(algo) => &algo.name,
3096            NormalizedAlgorithm::AesCbcParams(algo) => &algo.name,
3097            NormalizedAlgorithm::AesGcmParams(algo) => &algo.name,
3098            NormalizedAlgorithm::HmacImportParams(algo) => &algo.name,
3099            NormalizedAlgorithm::HmacKeyGenParams(algo) => &algo.name,
3100            NormalizedAlgorithm::HkdfParams(algo) => &algo.name,
3101            NormalizedAlgorithm::Pbkdf2Params(algo) => &algo.name,
3102            NormalizedAlgorithm::AeadParams(algo) => &algo.name,
3103            NormalizedAlgorithm::CShakeParams(algo) => &algo.name,
3104            NormalizedAlgorithm::Argon2Params(algo) => &algo.name,
3105        }
3106    }
3107
3108    fn encrypt(&self, key: &CryptoKey, plaintext: &[u8]) -> Result<Vec<u8>, Error> {
3109        match (self.name(), self) {
3110            (ALG_AES_CTR, NormalizedAlgorithm::AesCtrParams(algo)) => {
3111                aes_operation::encrypt_aes_ctr(algo, key, plaintext)
3112            },
3113            (ALG_AES_CBC, NormalizedAlgorithm::AesCbcParams(algo)) => {
3114                aes_operation::encrypt_aes_cbc(algo, key, plaintext)
3115            },
3116            (ALG_AES_GCM, NormalizedAlgorithm::AesGcmParams(algo)) => {
3117                aes_operation::encrypt_aes_gcm(algo, key, plaintext)
3118            },
3119            (ALG_CHACHA20_POLY1305, NormalizedAlgorithm::AeadParams(algo)) => {
3120                chacha20_poly1305_operation::encrypt(algo, key, plaintext)
3121            },
3122            _ => Err(Error::NotSupported(None)),
3123        }
3124    }
3125
3126    fn decrypt(&self, key: &CryptoKey, ciphertext: &[u8]) -> Result<Vec<u8>, Error> {
3127        match (self.name(), self) {
3128            (ALG_AES_CTR, NormalizedAlgorithm::AesCtrParams(algo)) => {
3129                aes_operation::decrypt_aes_ctr(algo, key, ciphertext)
3130            },
3131            (ALG_AES_CBC, NormalizedAlgorithm::AesCbcParams(algo)) => {
3132                aes_operation::decrypt_aes_cbc(algo, key, ciphertext)
3133            },
3134            (ALG_AES_GCM, NormalizedAlgorithm::AesGcmParams(algo)) => {
3135                aes_operation::decrypt_aes_gcm(algo, key, ciphertext)
3136            },
3137            (ALG_CHACHA20_POLY1305, NormalizedAlgorithm::AeadParams(algo)) => {
3138                chacha20_poly1305_operation::decrypt(algo, key, ciphertext)
3139            },
3140            _ => Err(Error::NotSupported(None)),
3141        }
3142    }
3143
3144    fn sign(&self, key: &CryptoKey, message: &[u8]) -> Result<Vec<u8>, Error> {
3145        match (self.name(), self) {
3146            (ALG_ECDSA, NormalizedAlgorithm::EcdsaParams(algo)) => {
3147                ecdsa_operation::sign(algo, key, message)
3148            },
3149            (ALG_ED25519, NormalizedAlgorithm::Algorithm(_algo)) => {
3150                ed25519_operation::sign(key, message)
3151            },
3152            (ALG_HMAC, NormalizedAlgorithm::Algorithm(_algo)) => hmac_operation::sign(key, message),
3153            _ => Err(Error::NotSupported(None)),
3154        }
3155    }
3156
3157    fn verify(&self, key: &CryptoKey, message: &[u8], signature: &[u8]) -> Result<bool, Error> {
3158        match (self.name(), self) {
3159            (ALG_ECDSA, NormalizedAlgorithm::EcdsaParams(algo)) => {
3160                ecdsa_operation::verify(algo, key, message, signature)
3161            },
3162            (ALG_ED25519, NormalizedAlgorithm::Algorithm(_algo)) => {
3163                ed25519_operation::verify(key, message, signature)
3164            },
3165            (ALG_HMAC, NormalizedAlgorithm::Algorithm(_algo)) => {
3166                hmac_operation::verify(key, message, signature)
3167            },
3168            _ => Err(Error::NotSupported(None)),
3169        }
3170    }
3171
3172    fn digest(&self, message: &[u8]) -> Result<Vec<u8>, Error> {
3173        match (self.name(), self) {
3174            (ALG_SHA1, NormalizedAlgorithm::Algorithm(algo)) => {
3175                sha_operation::digest(algo, message)
3176            },
3177            (ALG_SHA256, NormalizedAlgorithm::Algorithm(algo)) => {
3178                sha_operation::digest(algo, message)
3179            },
3180            (ALG_SHA384, NormalizedAlgorithm::Algorithm(algo)) => {
3181                sha_operation::digest(algo, message)
3182            },
3183            (ALG_SHA512, NormalizedAlgorithm::Algorithm(algo)) => {
3184                sha_operation::digest(algo, message)
3185            },
3186            (ALG_SHA3_256, NormalizedAlgorithm::Algorithm(algo)) => {
3187                sha3_operation::digest(algo, message)
3188            },
3189            (ALG_SHA3_384, NormalizedAlgorithm::Algorithm(algo)) => {
3190                sha3_operation::digest(algo, message)
3191            },
3192            (ALG_SHA3_512, NormalizedAlgorithm::Algorithm(algo)) => {
3193                sha3_operation::digest(algo, message)
3194            },
3195            (ALG_CSHAKE_128, NormalizedAlgorithm::CShakeParams(algo)) => {
3196                cshake_operation::digest(algo, message)
3197            },
3198            (ALG_CSHAKE_256, NormalizedAlgorithm::CShakeParams(algo)) => {
3199                cshake_operation::digest(algo, message)
3200            },
3201            _ => Err(Error::NotSupported(None)),
3202        }
3203    }
3204
3205    fn generate_key(
3206        &self,
3207        global: &GlobalScope,
3208        extractable: bool,
3209        usages: Vec<KeyUsage>,
3210        can_gc: CanGc,
3211    ) -> Result<CryptoKeyOrCryptoKeyPair, Error> {
3212        match (self.name(), self) {
3213            (ALG_ECDSA, NormalizedAlgorithm::EcKeyGenParams(algo)) => {
3214                ecdsa_operation::generate_key(global, algo, extractable, usages, can_gc)
3215                    .map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
3216            },
3217            (ALG_ECDH, NormalizedAlgorithm::EcKeyGenParams(algo)) => {
3218                ecdh_operation::generate_key(global, algo, extractable, usages, can_gc)
3219                    .map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
3220            },
3221            (ALG_ED25519, NormalizedAlgorithm::Algorithm(_algo)) => {
3222                ed25519_operation::generate_key(global, extractable, usages, can_gc)
3223                    .map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
3224            },
3225            (ALG_X25519, NormalizedAlgorithm::Algorithm(_algo)) => {
3226                x25519_operation::generate_key(global, extractable, usages, can_gc)
3227                    .map(CryptoKeyOrCryptoKeyPair::CryptoKeyPair)
3228            },
3229            (ALG_AES_CTR, NormalizedAlgorithm::AesKeyGenParams(algo)) => {
3230                aes_operation::generate_key_aes_ctr(global, algo, extractable, usages, can_gc)
3231                    .map(CryptoKeyOrCryptoKeyPair::CryptoKey)
3232            },
3233            (ALG_AES_CBC, NormalizedAlgorithm::AesKeyGenParams(algo)) => {
3234                aes_operation::generate_key_aes_cbc(global, algo, extractable, usages, can_gc)
3235                    .map(CryptoKeyOrCryptoKeyPair::CryptoKey)
3236            },
3237            (ALG_AES_GCM, NormalizedAlgorithm::AesKeyGenParams(algo)) => {
3238                aes_operation::generate_key_aes_gcm(global, algo, extractable, usages, can_gc)
3239                    .map(CryptoKeyOrCryptoKeyPair::CryptoKey)
3240            },
3241            (ALG_AES_KW, NormalizedAlgorithm::AesKeyGenParams(algo)) => {
3242                aes_operation::generate_key_aes_kw(global, algo, extractable, usages, can_gc)
3243                    .map(CryptoKeyOrCryptoKeyPair::CryptoKey)
3244            },
3245            (ALG_HMAC, NormalizedAlgorithm::HmacKeyGenParams(algo)) => {
3246                hmac_operation::generate_key(global, algo, extractable, usages, can_gc)
3247                    .map(CryptoKeyOrCryptoKeyPair::CryptoKey)
3248            },
3249            (ALG_CHACHA20_POLY1305, NormalizedAlgorithm::Algorithm(_algo)) => {
3250                chacha20_poly1305_operation::generate_key(global, extractable, usages, can_gc)
3251                    .map(CryptoKeyOrCryptoKeyPair::CryptoKey)
3252            },
3253            _ => Err(Error::NotSupported(None)),
3254        }
3255    }
3256
3257    fn derive_bits(&self, key: &CryptoKey, length: Option<u32>) -> Result<Vec<u8>, Error> {
3258        match (self.name(), self) {
3259            (ALG_ECDH, NormalizedAlgorithm::EcdhKeyDeriveParams(algo)) => {
3260                ecdh_operation::derive_bits(algo, key, length)
3261            },
3262            (ALG_X25519, NormalizedAlgorithm::EcdhKeyDeriveParams(algo)) => {
3263                x25519_operation::derive_bits(algo, key, length)
3264            },
3265            (ALG_HKDF, NormalizedAlgorithm::HkdfParams(algo)) => {
3266                hkdf_operation::derive_bits(algo, key, length)
3267            },
3268            (ALG_PBKDF2, NormalizedAlgorithm::Pbkdf2Params(algo)) => {
3269                pbkdf2_operation::derive_bits(algo, key, length)
3270            },
3271            (ALG_ARGON2D, NormalizedAlgorithm::Argon2Params(algo)) => {
3272                argon2_operation::derive_bits(algo, key, length)
3273            },
3274            (ALG_ARGON2I, NormalizedAlgorithm::Argon2Params(algo)) => {
3275                argon2_operation::derive_bits(algo, key, length)
3276            },
3277            (ALG_ARGON2ID, NormalizedAlgorithm::Argon2Params(algo)) => {
3278                argon2_operation::derive_bits(algo, key, length)
3279            },
3280            _ => Err(Error::NotSupported(None)),
3281        }
3282    }
3283
3284    fn import_key(
3285        &self,
3286        global: &GlobalScope,
3287        format: KeyFormat,
3288        key_data: &[u8],
3289        extractable: bool,
3290        usages: Vec<KeyUsage>,
3291        can_gc: CanGc,
3292    ) -> Result<DomRoot<CryptoKey>, Error> {
3293        match (self.name(), self) {
3294            (ALG_ECDSA, NormalizedAlgorithm::EcKeyImportParams(algo)) => {
3295                ecdsa_operation::import_key(
3296                    global,
3297                    algo,
3298                    format,
3299                    key_data,
3300                    extractable,
3301                    usages,
3302                    can_gc,
3303                )
3304            },
3305            (ALG_ECDH, NormalizedAlgorithm::EcKeyImportParams(algo)) => ecdh_operation::import_key(
3306                global,
3307                algo,
3308                format,
3309                key_data,
3310                extractable,
3311                usages,
3312                can_gc,
3313            ),
3314            (ALG_ED25519, NormalizedAlgorithm::Algorithm(_algo)) => {
3315                ed25519_operation::import_key(global, format, key_data, extractable, usages, can_gc)
3316            },
3317            (ALG_X25519, NormalizedAlgorithm::Algorithm(_algo)) => {
3318                x25519_operation::import_key(global, format, key_data, extractable, usages, can_gc)
3319            },
3320            (ALG_AES_CTR, NormalizedAlgorithm::Algorithm(_algo)) => {
3321                aes_operation::import_key_aes_ctr(
3322                    global,
3323                    format,
3324                    key_data,
3325                    extractable,
3326                    usages,
3327                    can_gc,
3328                )
3329            },
3330            (ALG_AES_CBC, NormalizedAlgorithm::Algorithm(_algo)) => {
3331                aes_operation::import_key_aes_cbc(
3332                    global,
3333                    format,
3334                    key_data,
3335                    extractable,
3336                    usages,
3337                    can_gc,
3338                )
3339            },
3340            (ALG_AES_GCM, NormalizedAlgorithm::Algorithm(_algo)) => {
3341                aes_operation::import_key_aes_gcm(
3342                    global,
3343                    format,
3344                    key_data,
3345                    extractable,
3346                    usages,
3347                    can_gc,
3348                )
3349            },
3350            (ALG_AES_KW, NormalizedAlgorithm::Algorithm(_algo)) => {
3351                aes_operation::import_key_aes_kw(
3352                    global,
3353                    format,
3354                    key_data,
3355                    extractable,
3356                    usages,
3357                    can_gc,
3358                )
3359            },
3360            (ALG_HMAC, NormalizedAlgorithm::HmacImportParams(algo)) => hmac_operation::import_key(
3361                global,
3362                algo,
3363                format,
3364                key_data,
3365                extractable,
3366                usages,
3367                can_gc,
3368            ),
3369            (ALG_HKDF, NormalizedAlgorithm::Algorithm(_algo)) => {
3370                hkdf_operation::import_key(global, format, key_data, extractable, usages, can_gc)
3371            },
3372            (ALG_PBKDF2, NormalizedAlgorithm::Algorithm(_algo)) => {
3373                pbkdf2_operation::import_key(global, format, key_data, extractable, usages, can_gc)
3374            },
3375            (ALG_CHACHA20_POLY1305, NormalizedAlgorithm::Algorithm(_algo)) => {
3376                chacha20_poly1305_operation::import_key(
3377                    global,
3378                    format,
3379                    key_data,
3380                    extractable,
3381                    usages,
3382                    can_gc,
3383                )
3384            },
3385            (ALG_ARGON2D, NormalizedAlgorithm::Algorithm(algo)) => argon2_operation::import_key(
3386                global,
3387                algo,
3388                format,
3389                key_data,
3390                extractable,
3391                usages,
3392                can_gc,
3393            ),
3394            (ALG_ARGON2I, NormalizedAlgorithm::Algorithm(algo)) => argon2_operation::import_key(
3395                global,
3396                algo,
3397                format,
3398                key_data,
3399                extractable,
3400                usages,
3401                can_gc,
3402            ),
3403            (ALG_ARGON2ID, NormalizedAlgorithm::Algorithm(algo)) => argon2_operation::import_key(
3404                global,
3405                algo,
3406                format,
3407                key_data,
3408                extractable,
3409                usages,
3410                can_gc,
3411            ),
3412            _ => Err(Error::NotSupported(None)),
3413        }
3414    }
3415
3416    fn wrap_key(&self, key: &CryptoKey, plaintext: &[u8]) -> Result<Vec<u8>, Error> {
3417        match (self.name(), self) {
3418            (ALG_AES_KW, NormalizedAlgorithm::Algorithm(_algo)) => {
3419                aes_operation::wrap_key_aes_kw(key, plaintext)
3420            },
3421            _ => Err(Error::NotSupported(None)),
3422        }
3423    }
3424
3425    fn unwrap_key(&self, key: &CryptoKey, ciphertext: &[u8]) -> Result<Vec<u8>, Error> {
3426        match (self.name(), self) {
3427            (ALG_AES_KW, NormalizedAlgorithm::Algorithm(_algo)) => {
3428                aes_operation::unwrap_key_aes_kw(key, ciphertext)
3429            },
3430            _ => Err(Error::NotSupported(None)),
3431        }
3432    }
3433
3434    fn get_key_length(&self) -> Result<Option<u32>, Error> {
3435        match (self.name(), self) {
3436            (ALG_AES_CTR, NormalizedAlgorithm::AesDerivedKeyParams(algo)) => {
3437                aes_operation::get_key_length_aes_ctr(algo)
3438            },
3439            (ALG_AES_CBC, NormalizedAlgorithm::AesDerivedKeyParams(algo)) => {
3440                aes_operation::get_key_length_aes_cbc(algo)
3441            },
3442            (ALG_AES_GCM, NormalizedAlgorithm::AesDerivedKeyParams(algo)) => {
3443                aes_operation::get_key_length_aes_gcm(algo)
3444            },
3445            (ALG_AES_KW, NormalizedAlgorithm::AesDerivedKeyParams(algo)) => {
3446                aes_operation::get_key_length_aes_kw(algo)
3447            },
3448            (ALG_HMAC, NormalizedAlgorithm::HmacImportParams(algo)) => {
3449                hmac_operation::get_key_length(algo)
3450            },
3451            (ALG_HKDF, NormalizedAlgorithm::Algorithm(_algo)) => hkdf_operation::get_key_length(),
3452            (ALG_PBKDF2, NormalizedAlgorithm::Algorithm(_algo)) => {
3453                pbkdf2_operation::get_key_length()
3454            },
3455            (ALG_CHACHA20_POLY1305, NormalizedAlgorithm::Algorithm(_algo)) => {
3456                chacha20_poly1305_operation::get_key_length()
3457            },
3458            (ALG_ARGON2D, NormalizedAlgorithm::Algorithm(_algo)) => {
3459                argon2_operation::get_key_length()
3460            },
3461            (ALG_ARGON2I, NormalizedAlgorithm::Algorithm(_algo)) => {
3462                argon2_operation::get_key_length()
3463            },
3464            (ALG_ARGON2ID, NormalizedAlgorithm::Algorithm(_algo)) => {
3465                argon2_operation::get_key_length()
3466            },
3467            _ => Err(Error::NotSupported(None)),
3468        }
3469    }
3470}
3471
3472/// Return the result of performing the export key operation specified by the [[algorithm]]
3473/// internal slot of key using key and format.
3474///
3475/// According to the WebCrypto API spec, the export key operation does not rely on the algorithm
3476/// normalization, We create this helper function to minic the functions of NormalizedAlgorithm
3477/// for export key operation.
3478fn perform_export_key_operation(format: KeyFormat, key: &CryptoKey) -> Result<ExportedKey, Error> {
3479    match key.algorithm().name() {
3480        ALG_ECDSA => ecdsa_operation::export_key(format, key),
3481        ALG_ECDH => ecdh_operation::export_key(format, key),
3482        ALG_ED25519 => ed25519_operation::export_key(format, key),
3483        ALG_X25519 => x25519_operation::export_key(format, key),
3484        ALG_AES_CTR => aes_operation::export_key_aes_ctr(format, key),
3485        ALG_AES_CBC => aes_operation::export_key_aes_cbc(format, key),
3486        ALG_AES_GCM => aes_operation::export_key_aes_gcm(format, key),
3487        ALG_AES_KW => aes_operation::export_key_aes_kw(format, key),
3488        ALG_HMAC => hmac_operation::export_key(format, key),
3489        ALG_CHACHA20_POLY1305 => chacha20_poly1305_operation::export_key(format, key),
3490        _ => Err(Error::NotSupported(None)),
3491    }
3492}