1use std::num::NonZero;
6use std::ptr;
7use std::rc::Rc;
8use std::str::FromStr;
9
10use aes::cipher::block_padding::Pkcs7;
11use aes::cipher::generic_array::GenericArray;
12use aes::cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit, StreamCipher};
13use aes::{Aes128, Aes192, Aes256};
14use aes_gcm::{AeadInPlace, AesGcm, KeyInit};
15use aes_kw::{KekAes128, KekAes192, KekAes256};
16use aws_lc_rs::{digest, hkdf, hmac, pbkdf2};
17use base64::prelude::*;
18use cipher::consts::{U12, U16, U32};
19use dom_struct::dom_struct;
20use js::conversions::ConversionResult;
21use js::jsapi::{JS_NewObject, JSObject};
22use js::jsval::{ObjectValue, UndefinedValue};
23use js::rust::wrappers::JS_ParseJSON;
24use js::rust::{HandleValue, MutableHandleObject};
25use js::typedarray::ArrayBufferU8;
26use servo_rand::{RngCore, ServoRng};
27
28use crate::dom::bindings::buffer_source::create_buffer_source;
29use crate::dom::bindings::cell::DomRefCell;
30use crate::dom::bindings::codegen::Bindings::CryptoKeyBinding::{
31 CryptoKeyMethods, KeyType, KeyUsage,
32};
33use crate::dom::bindings::codegen::Bindings::SubtleCryptoBinding::{
34 AesCbcParams, AesCtrParams, AesDerivedKeyParams, AesGcmParams, AesKeyAlgorithm,
35 AesKeyGenParams, Algorithm, AlgorithmIdentifier, HkdfParams, HmacImportParams,
36 HmacKeyAlgorithm, HmacKeyGenParams, JsonWebKey, KeyAlgorithm, KeyFormat, Pbkdf2Params,
37 RsaOtherPrimesInfo, SubtleCryptoMethods,
38};
39use crate::dom::bindings::codegen::UnionTypes::{
40 ArrayBufferViewOrArrayBuffer, ArrayBufferViewOrArrayBufferOrJsonWebKey,
41};
42use crate::dom::bindings::conversions::SafeToJSValConvertible;
43use crate::dom::bindings::error::{Error, Fallible};
44use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
45use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
46use crate::dom::bindings::root::DomRoot;
47use crate::dom::bindings::str::{DOMString, serialize_jsval_to_json_utf8};
48use crate::dom::bindings::trace::RootedTraceableBox;
49use crate::dom::cryptokey::{CryptoKey, CryptoKeyOrCryptoKeyPair, Handle};
50use crate::dom::globalscope::GlobalScope;
51use crate::dom::promise::Promise;
52use crate::realms::InRealm;
53use crate::script_runtime::{CanGc, JSContext};
54
55const ALG_AES_CBC: &str = "AES-CBC";
57const ALG_AES_CTR: &str = "AES-CTR";
58const ALG_AES_GCM: &str = "AES-GCM";
59const ALG_AES_KW: &str = "AES-KW";
60const ALG_SHA1: &str = "SHA-1";
61const ALG_SHA256: &str = "SHA-256";
62const ALG_SHA384: &str = "SHA-384";
63const ALG_SHA512: &str = "SHA-512";
64const ALG_HMAC: &str = "HMAC";
65const ALG_HKDF: &str = "HKDF";
66const ALG_PBKDF2: &str = "PBKDF2";
67const ALG_RSASSA_PKCS1: &str = "RSASSA-PKCS1-v1_5";
68const ALG_RSA_OAEP: &str = "RSA-OAEP";
69const ALG_RSA_PSS: &str = "RSA-PSS";
70const ALG_ECDH: &str = "ECDH";
71const ALG_ECDSA: &str = "ECDSA";
72
73#[allow(dead_code)]
74static SUPPORTED_ALGORITHMS: &[&str] = &[
75 ALG_AES_CBC,
76 ALG_AES_CTR,
77 ALG_AES_GCM,
78 ALG_AES_KW,
79 ALG_SHA1,
80 ALG_SHA256,
81 ALG_SHA384,
82 ALG_SHA512,
83 ALG_HMAC,
84 ALG_HKDF,
85 ALG_PBKDF2,
86 ALG_RSASSA_PKCS1,
87 ALG_RSA_OAEP,
88 ALG_RSA_PSS,
89 ALG_ECDH,
90 ALG_ECDSA,
91];
92
93const NAMED_CURVE_P256: &str = "P-256";
94const NAMED_CURVE_P384: &str = "P-384";
95const NAMED_CURVE_P521: &str = "P-521";
96#[allow(dead_code)]
97static SUPPORTED_CURVES: &[&str] = &[NAMED_CURVE_P256, NAMED_CURVE_P384, NAMED_CURVE_P521];
98
99type Aes128CbcEnc = cbc::Encryptor<Aes128>;
100type Aes128CbcDec = cbc::Decryptor<Aes128>;
101type Aes192CbcEnc = cbc::Encryptor<Aes192>;
102type Aes192CbcDec = cbc::Decryptor<Aes192>;
103type Aes256CbcEnc = cbc::Encryptor<Aes256>;
104type Aes256CbcDec = cbc::Decryptor<Aes256>;
105type Aes128Ctr = ctr::Ctr64BE<Aes128>;
106type Aes192Ctr = ctr::Ctr64BE<Aes192>;
107type Aes256Ctr = ctr::Ctr64BE<Aes256>;
108
109type Aes128Gcm96Iv = AesGcm<Aes128, U12>;
110type Aes128Gcm128Iv = AesGcm<Aes128, U16>;
111type Aes192Gcm96Iv = AesGcm<Aes192, U12>;
112type Aes256Gcm96Iv = AesGcm<Aes256, U12>;
113type Aes128Gcm256Iv = AesGcm<Aes128, U32>;
114type Aes192Gcm256Iv = AesGcm<Aes192, U32>;
115type Aes256Gcm256Iv = AesGcm<Aes256, U32>;
116
117#[dom_struct]
118pub(crate) struct SubtleCrypto {
119 reflector_: Reflector,
120 #[no_trace]
121 rng: DomRefCell<ServoRng>,
122}
123
124impl SubtleCrypto {
125 fn new_inherited() -> SubtleCrypto {
126 SubtleCrypto {
127 reflector_: Reflector::new(),
128 rng: DomRefCell::new(ServoRng::default()),
129 }
130 }
131
132 pub(crate) fn new(global: &GlobalScope, can_gc: CanGc) -> DomRoot<SubtleCrypto> {
133 reflect_dom_object(Box::new(SubtleCrypto::new_inherited()), global, can_gc)
134 }
135}
136
137impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
138 fn Encrypt(
140 &self,
141 cx: JSContext,
142 algorithm: AlgorithmIdentifier,
143 key: &CryptoKey,
144 data: ArrayBufferViewOrArrayBuffer,
145 comp: InRealm,
146 can_gc: CanGc,
147 ) -> Rc<Promise> {
148 let promise = Promise::new_in_current_realm(comp, can_gc);
149 let normalized_algorithm =
150 match normalize_algorithm_for_encrypt_or_decrypt(cx, &algorithm, can_gc) {
151 Ok(algorithm) => algorithm,
152 Err(e) => {
153 promise.reject_error(e, can_gc);
154 return promise;
155 },
156 };
157 let data = match data {
158 ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
159 ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
160 };
161
162 let this = Trusted::new(self);
163 let trusted_promise = TrustedPromise::new(promise.clone());
164 let trusted_key = Trusted::new(key);
165 let key_alg = key.algorithm();
166 let valid_usage = key.usages().contains(&KeyUsage::Encrypt);
167 self.global()
168 .task_manager()
169 .dom_manipulation_task_source()
170 .queue(task!(encrypt: move || {
171 let subtle = this.root();
172 let promise = trusted_promise.root();
173 let key = trusted_key.root();
174
175 if !valid_usage || normalized_algorithm.name() != key_alg {
176 promise.reject_error(Error::InvalidAccess, CanGc::note());
177 return;
178 }
179
180 let cx = GlobalScope::get_cx();
181 rooted!(in(*cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>());
182
183 if let Err(e) = normalized_algorithm.encrypt(
184 &subtle,
185 &key,
186 &data,
187 cx,
188 array_buffer_ptr.handle_mut(),
189 CanGc::note(),
190 ) {
191 promise.reject_error(e, CanGc::note());
192 return;
193 }
194 promise.resolve_native(&*array_buffer_ptr.handle(), CanGc::note());
195 }));
196 promise
197 }
198
199 fn Decrypt(
201 &self,
202 cx: JSContext,
203 algorithm: AlgorithmIdentifier,
204 key: &CryptoKey,
205 data: ArrayBufferViewOrArrayBuffer,
206 comp: InRealm,
207 can_gc: CanGc,
208 ) -> Rc<Promise> {
209 let promise = Promise::new_in_current_realm(comp, can_gc);
210 let normalized_algorithm =
211 match normalize_algorithm_for_encrypt_or_decrypt(cx, &algorithm, can_gc) {
212 Ok(algorithm) => algorithm,
213 Err(e) => {
214 promise.reject_error(e, can_gc);
215 return promise;
216 },
217 };
218 let data = match data {
219 ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
220 ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
221 };
222
223 let this = Trusted::new(self);
224 let trusted_promise = TrustedPromise::new(promise.clone());
225 let trusted_key = Trusted::new(key);
226 let key_alg = key.algorithm();
227 let valid_usage = key.usages().contains(&KeyUsage::Decrypt);
228 self.global()
229 .task_manager()
230 .dom_manipulation_task_source()
231 .queue(task!(decrypt: move || {
232 let subtle = this.root();
233 let promise = trusted_promise.root();
234 let key = trusted_key.root();
235 let cx = GlobalScope::get_cx();
236 rooted!(in(*cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>());
237
238 if !valid_usage || normalized_algorithm.name() != key_alg {
239 promise.reject_error(Error::InvalidAccess, CanGc::note());
240 return;
241 }
242
243 if let Err(e) = normalized_algorithm.decrypt(
244 &subtle,
245 &key,
246 &data,
247 cx,
248 array_buffer_ptr.handle_mut(),
249 CanGc::note(),
250 ) {
251 promise.reject_error(e, CanGc::note());
252 return;
253 }
254
255 promise.resolve_native(&*array_buffer_ptr.handle(), CanGc::note());
256 }));
257 promise
258 }
259
260 fn Sign(
262 &self,
263 cx: JSContext,
264 algorithm: AlgorithmIdentifier,
265 key: &CryptoKey,
266 data: ArrayBufferViewOrArrayBuffer,
267 comp: InRealm,
268 can_gc: CanGc,
269 ) -> Rc<Promise> {
270 let data = match &data {
275 ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
276 ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
277 };
278
279 let promise = Promise::new_in_current_realm(comp, can_gc);
282 let normalized_algorithm =
283 match normalize_algorithm_for_sign_or_verify(cx, &algorithm, can_gc) {
284 Ok(algorithm) => algorithm,
285 Err(e) => {
286 promise.reject_error(e, can_gc);
288 return promise;
289 },
290 };
291
292 let trusted_promise = TrustedPromise::new(promise.clone());
297 let trusted_key = Trusted::new(key);
298
299 self.global()
300 .task_manager()
301 .dom_manipulation_task_source()
302 .queue(task!(sign: move || {
303 let promise = trusted_promise.root();
306 let key = trusted_key.root();
307
308 if normalized_algorithm.name() != key.algorithm() {
311 promise.reject_error(Error::InvalidAccess, CanGc::note());
312 return;
313 }
314
315 if !key.usages().contains(&KeyUsage::Sign) {
318 promise.reject_error(Error::InvalidAccess, CanGc::note());
319 return;
320 }
321
322 let cx = GlobalScope::get_cx();
325 let result = match normalized_algorithm.sign(cx, &key, &data, CanGc::note()) {
326 Ok(signature) => signature,
327 Err(e) => {
328 promise.reject_error(e, CanGc::note());
329 return;
330 }
331 };
332
333 rooted!(in(*cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>());
334 create_buffer_source::<ArrayBufferU8>(cx, &result, array_buffer_ptr.handle_mut(), CanGc::note())
335 .expect("failed to create buffer source for exported key.");
336
337 promise.resolve_native(&*array_buffer_ptr, CanGc::note());
339 }));
340
341 promise
342 }
343
344 fn Verify(
346 &self,
347 cx: JSContext,
348 algorithm: AlgorithmIdentifier,
349 key: &CryptoKey,
350 signature: ArrayBufferViewOrArrayBuffer,
351 data: ArrayBufferViewOrArrayBuffer,
352 comp: InRealm,
353 can_gc: CanGc,
354 ) -> Rc<Promise> {
355 let signature = match &signature {
361 ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
362 ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
363 };
364
365 let data = match &data {
368 ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
369 ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
370 };
371
372 let promise = Promise::new_in_current_realm(comp, can_gc);
375 let normalized_algorithm =
376 match normalize_algorithm_for_sign_or_verify(cx, &algorithm, can_gc) {
377 Ok(algorithm) => algorithm,
378 Err(e) => {
379 promise.reject_error(e, can_gc);
381 return promise;
382 },
383 };
384
385 let trusted_promise = TrustedPromise::new(promise.clone());
390 let trusted_key = Trusted::new(key);
391
392 self.global()
393 .task_manager()
394 .dom_manipulation_task_source()
395 .queue(task!(sign: move || {
396 let promise = trusted_promise.root();
399 let key = trusted_key.root();
400
401 if normalized_algorithm.name() != key.algorithm() {
404 promise.reject_error(Error::InvalidAccess, CanGc::note());
405 return;
406 }
407
408 if !key.usages().contains(&KeyUsage::Verify) {
411 promise.reject_error(Error::InvalidAccess, CanGc::note());
412 return;
413 }
414
415 let cx = GlobalScope::get_cx();
418 let result = match normalized_algorithm.verify(cx, &key, &data, &signature, CanGc::note()) {
419 Ok(result) => result,
420 Err(e) => {
421 promise.reject_error(e, CanGc::note());
422 return;
423 }
424 };
425
426 promise.resolve_native(&result, CanGc::note());
428 }));
429
430 promise
431 }
432
433 fn Digest(
435 &self,
436 cx: JSContext,
437 algorithm: AlgorithmIdentifier,
438 data: ArrayBufferViewOrArrayBuffer,
439 comp: InRealm,
440 can_gc: CanGc,
441 ) -> Rc<Promise> {
442 let data = match data {
447 ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
448 ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
449 };
450
451 let promise = Promise::new_in_current_realm(comp, can_gc);
454 let normalized_algorithm = match normalize_algorithm_for_digest(cx, &algorithm, can_gc) {
455 Ok(normalized_algorithm) => normalized_algorithm,
456 Err(e) => {
457 promise.reject_error(e, can_gc);
459 return promise;
460 },
461 };
462
463 let trusted_promise = TrustedPromise::new(promise.clone());
468
469 self.global().task_manager().dom_manipulation_task_source().queue(
470 task!(generate_key: move || {
471 let promise = trusted_promise.root();
474
475 let digest = match normalized_algorithm.digest(&data) {
478 Ok(digest) => digest,
479 Err(e) => {
480 promise.reject_error(e, CanGc::note());
481 return;
482 }
483 };
484
485 let cx = GlobalScope::get_cx();
486 rooted!(in(*cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>());
487 create_buffer_source::<ArrayBufferU8>(cx, digest.as_ref(), array_buffer_ptr.handle_mut(), CanGc::note())
488 .expect("failed to create buffer source for exported key.");
489
490
491 promise.resolve_native(&*array_buffer_ptr, CanGc::note());
493 })
494 );
495
496 promise
497 }
498
499 fn GenerateKey(
501 &self,
502 cx: JSContext,
503 algorithm: AlgorithmIdentifier,
504 extractable: bool,
505 key_usages: Vec<KeyUsage>,
506 comp: InRealm,
507 can_gc: CanGc,
508 ) -> Rc<Promise> {
509 let promise = Promise::new_in_current_realm(comp, can_gc);
510 let normalized_algorithm =
511 match normalize_algorithm_for_generate_key(cx, &algorithm, can_gc) {
512 Ok(algorithm) => algorithm,
513 Err(e) => {
514 promise.reject_error(e, can_gc);
515 return promise;
516 },
517 };
518
519 let this = Trusted::new(self);
520 let trusted_promise = TrustedPromise::new(promise.clone());
521 self.global()
522 .task_manager()
523 .dom_manipulation_task_source()
524 .queue(task!(generate_key: move || {
525 let subtle = this.root();
526 let promise = trusted_promise.root();
527
528 let key = match normalized_algorithm
531 .generate_key(&subtle, key_usages, extractable, CanGc::note())
532 {
533 Ok(key) => key,
534 Err(error) => {
535 promise.reject_error(error, CanGc::note());
536 return;
537 }
538 };
539
540 match &key {
549 CryptoKeyOrCryptoKeyPair::CryptoKey(crpyto_key) => {
550 if matches!(crpyto_key.Type(), KeyType::Secret | KeyType::Private)
551 && crpyto_key.usages().is_empty()
552 {
553 promise.reject_error(Error::Syntax(None), CanGc::note());
554 return;
555 }
556 },
557 };
558
559 match key {
567 CryptoKeyOrCryptoKeyPair::CryptoKey(crypto_key) =>
568 promise.resolve_native(&crypto_key, CanGc::note()),
569 };
570 }));
571
572 promise
573 }
574
575 fn DeriveKey(
577 &self,
578 cx: JSContext,
579 algorithm: AlgorithmIdentifier,
580 base_key: &CryptoKey,
581 derived_key_type: AlgorithmIdentifier,
582 extractable: bool,
583 key_usages: Vec<KeyUsage>,
584 comp: InRealm,
585 can_gc: CanGc,
586 ) -> Rc<Promise> {
587 let promise = Promise::new_in_current_realm(comp, can_gc);
593 let normalized_algorithm = match normalize_algorithm_for_derive_bits(cx, &algorithm, can_gc)
594 {
595 Ok(algorithm) => algorithm,
596 Err(e) => {
597 promise.reject_error(e, can_gc);
599 return promise;
600 },
601 };
602
603 let normalized_derived_key_algorithm_import =
606 match normalize_algorithm_for_import_key(cx, &derived_key_type, can_gc) {
607 Ok(algorithm) => algorithm,
608 Err(e) => {
609 promise.reject_error(e, can_gc);
611 return promise;
612 },
613 };
614
615 let normalized_derived_key_algorithm_length =
618 match normalize_algorithm_for_get_key_length(cx, &derived_key_type, can_gc) {
619 Ok(algorithm) => algorithm,
620 Err(e) => {
621 promise.reject_error(e, can_gc);
623 return promise;
624 },
625 };
626
627 let trusted_promise = TrustedPromise::new(promise.clone());
632 let trusted_base_key = Trusted::new(base_key);
633 let this = Trusted::new(self);
634 self.global().task_manager().dom_manipulation_task_source().queue(
635 task!(derive_key: move || {
636 let promise = trusted_promise.root();
642 let base_key = trusted_base_key.root();
643 let subtle = this.root();
644
645 if !base_key.usages().contains(&KeyUsage::DeriveKey) {
648 promise.reject_error(Error::InvalidAccess, CanGc::note());
649 return;
650 }
651
652 let length = match normalized_derived_key_algorithm_length.get_key_length() {
655 Ok(length) => length,
656 Err(e) => {
657 promise.reject_error(e, CanGc::note());
658 return;
659 }
660 };
661
662 let secret = match normalized_algorithm.derive_bits(&base_key, Some(length)){
665 Ok(secret) => secret,
666 Err(e) => {
667 promise.reject_error(e, CanGc::note());
668 return;
669 }
670 };
671
672 let result = normalized_derived_key_algorithm_import.import_key(
676 &subtle,
677 KeyFormat::Raw,
678 &secret,
679 extractable,
680 key_usages,
681 CanGc::note()
682 );
683 let result = match result {
684 Ok(key) => key,
685 Err(e) => {
686 promise.reject_error(e, CanGc::note());
687 return;
688 }
689 };
690
691 if matches!(result.Type(), KeyType::Secret | KeyType::Private) && result.usages().is_empty() {
694 promise.reject_error(Error::Syntax(None), CanGc::note());
695 return;
696 }
697
698 promise.resolve_native(&*result, CanGc::note());
700 }),
701 );
702
703 promise
704 }
705
706 fn DeriveBits(
708 &self,
709 cx: JSContext,
710 algorithm: AlgorithmIdentifier,
711 base_key: &CryptoKey,
712 length: Option<u32>,
713 comp: InRealm,
714 can_gc: CanGc,
715 ) -> Rc<Promise> {
716 let promise = Promise::new_in_current_realm(comp, can_gc);
722 let normalized_algorithm = match normalize_algorithm_for_derive_bits(cx, &algorithm, can_gc)
723 {
724 Ok(algorithm) => algorithm,
725 Err(e) => {
726 promise.reject_error(e, can_gc);
728 return promise;
729 },
730 };
731
732 let trusted_promise = TrustedPromise::new(promise.clone());
737 let trusted_base_key = Trusted::new(base_key);
738
739 self.global()
740 .task_manager()
741 .dom_manipulation_task_source()
742 .queue(task!(import_key: move || {
743 let promise = trusted_promise.root();
749 let base_key = trusted_base_key.root();
750
751 if !base_key.usages().contains(&KeyUsage::DeriveBits) {
754 promise.reject_error(Error::InvalidAccess, CanGc::note());
755 return;
756 }
757
758 let cx = GlobalScope::get_cx();
761 rooted!(in(*cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>());
762 let result = match normalized_algorithm.derive_bits(&base_key, length) {
763 Ok(derived_bits) => derived_bits,
764 Err(e) => {
765 promise.reject_error(e, CanGc::note());
766 return;
767 }
768 };
769
770 create_buffer_source::<ArrayBufferU8>(cx, &result, array_buffer_ptr.handle_mut(), CanGc::note())
771 .expect("failed to create buffer source for derived bits.");
772
773 promise.resolve_native(&*array_buffer_ptr, CanGc::note());
775 }));
776
777 promise
778 }
779
780 fn ImportKey(
782 &self,
783 cx: JSContext,
784 format: KeyFormat,
785 key_data: ArrayBufferViewOrArrayBufferOrJsonWebKey,
786 algorithm: AlgorithmIdentifier,
787 extractable: bool,
788 key_usages: Vec<KeyUsage>,
789 comp: InRealm,
790 can_gc: CanGc,
791 ) -> Rc<Promise> {
792 let promise = Promise::new_in_current_realm(comp, can_gc);
798
799 let key_data = match format {
801 KeyFormat::Raw | KeyFormat::Pkcs8 | KeyFormat::Spki => {
803 match key_data {
804 ArrayBufferViewOrArrayBufferOrJsonWebKey::JsonWebKey(_) => {
807 promise.reject_error(
808 Error::Type("The keyData type does not match the format".to_string()),
809 can_gc,
810 );
811 return promise;
812 },
813
814 ArrayBufferViewOrArrayBufferOrJsonWebKey::ArrayBufferView(view) => {
817 view.to_vec()
818 },
819 ArrayBufferViewOrArrayBufferOrJsonWebKey::ArrayBuffer(buffer) => {
820 buffer.to_vec()
821 },
822 }
823 },
824 KeyFormat::Jwk => {
826 match key_data {
827 ArrayBufferViewOrArrayBufferOrJsonWebKey::ArrayBufferView(_) |
828 ArrayBufferViewOrArrayBufferOrJsonWebKey::ArrayBuffer(_) => {
829 promise.reject_error(
832 Error::Type("The keyData type does not match the format".to_string()),
833 can_gc,
834 );
835 return promise;
836 },
837
838 ArrayBufferViewOrArrayBufferOrJsonWebKey::JsonWebKey(jwk) => {
839 match jwk.stringify(cx) {
846 Ok(stringified) => stringified.as_bytes().to_vec(),
847 Err(error) => {
848 promise.reject_error(error, can_gc);
849 return promise;
850 },
851 }
852 },
853 }
854 },
855 };
856
857 let normalized_algorithm = match normalize_algorithm_for_import_key(cx, &algorithm, can_gc)
860 {
861 Ok(algorithm) => algorithm,
862 Err(error) => {
863 promise.reject_error(error, can_gc);
865 return promise;
866 },
867 };
868
869 let this = Trusted::new(self);
871 let trusted_promise = TrustedPromise::new(promise.clone());
872 self.global()
873 .task_manager()
874 .dom_manipulation_task_source()
875 .queue(task!(import_key: move || {
876 let subtle = this.root();
877 let promise = trusted_promise.root();
878
879 let result = match normalized_algorithm.import_key(
888 &subtle,
889 format,
890 &key_data,
891 extractable,
892 key_usages.clone(),
893 CanGc::note()
894 ) {
895 Ok(key) => key,
896 Err(error) => {
897 promise.reject_error(error, CanGc::note());
898 return;
899 },
900 };
901
902 if matches!(result.Type(), KeyType::Secret | KeyType::Private) && key_usages.is_empty() {
905 promise.reject_error(Error::Syntax(None), CanGc::note());
906 return;
907 }
908
909 result.set_extractable(extractable);
911
912 result.set_usages(&key_usages);
914
915 promise.resolve_native(&result, CanGc::note());
922 }));
923
924 promise
925 }
926
927 fn ExportKey(
929 &self,
930 format: KeyFormat,
931 key: &CryptoKey,
932 comp: InRealm,
933 can_gc: CanGc,
934 ) -> Rc<Promise> {
935 let promise = Promise::new_in_current_realm(comp, can_gc);
936
937 let this = Trusted::new(self);
938 let trusted_key = Trusted::new(key);
939 let trusted_promise = TrustedPromise::new(promise.clone());
940 self.global().task_manager().dom_manipulation_task_source().queue(
941 task!(export_key: move || {
942 let subtle = this.root();
943 let promise = trusted_promise.root();
944 let key = trusted_key.root();
945 let alg_name = key.algorithm();
946 if matches!(
947 alg_name.as_str(), ALG_SHA1 | ALG_SHA256 | ALG_SHA384 | ALG_SHA512 | ALG_HKDF | ALG_PBKDF2
948 ) {
949 promise.reject_error(Error::NotSupported, CanGc::note());
950 return;
951 }
952 if !key.Extractable() {
953 promise.reject_error(Error::InvalidAccess, CanGc::note());
954 return;
955 }
956 let exported_key = match alg_name.as_str() {
957 ALG_AES_CBC | ALG_AES_CTR | ALG_AES_KW | ALG_AES_GCM => subtle.export_key_aes(format, &key),
958 ALG_HMAC => subtle.export_key_hmac(format, &key),
959 _ => Err(Error::NotSupported),
960 };
961 match exported_key {
962 Ok(k) => {
963 match k {
964 ExportedKey::Raw(k) => {
965 let cx = GlobalScope::get_cx();
966 rooted!(in(*cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>());
967 create_buffer_source::<ArrayBufferU8>(cx, &k, array_buffer_ptr.handle_mut(),
968 CanGc::note())
969 .expect("failed to create buffer source for exported key.");
970 promise.resolve_native(&array_buffer_ptr.get(), CanGc::note())
971 },
972 ExportedKey::Jwk(k) => {
973 promise.resolve_native(&k, CanGc::note())
974 },
975 }
976 },
977 Err(e) => promise.reject_error(e, CanGc::note()),
978 }
979 }),
980 );
981
982 promise
983 }
984
985 fn WrapKey(
987 &self,
988 cx: JSContext,
989 format: KeyFormat,
990 key: &CryptoKey,
991 wrapping_key: &CryptoKey,
992 wrap_algorithm: AlgorithmIdentifier,
993 comp: InRealm,
994 can_gc: CanGc,
995 ) -> Rc<Promise> {
996 let promise = Promise::new_in_current_realm(comp, can_gc);
997 let normalized_algorithm =
998 match normalize_algorithm_for_key_wrap(cx, &wrap_algorithm, can_gc) {
999 Ok(algorithm) => algorithm,
1000 Err(e) => {
1001 promise.reject_error(e, can_gc);
1002 return promise;
1003 },
1004 };
1005
1006 let this = Trusted::new(self);
1007 let trusted_key = Trusted::new(key);
1008 let trusted_wrapping_key = Trusted::new(wrapping_key);
1009 let trusted_promise = TrustedPromise::new(promise.clone());
1010 self.global().task_manager().dom_manipulation_task_source().queue(
1011 task!(wrap_key: move || {
1012 let subtle = this.root();
1013 let promise = trusted_promise.root();
1014 let key = trusted_key.root();
1015 let wrapping_key = trusted_wrapping_key.root();
1016 let alg_name = key.algorithm();
1017 let wrapping_alg_name = wrapping_key.algorithm();
1018 let valid_wrap_usage = wrapping_key.usages().contains(&KeyUsage::WrapKey);
1019 let names_match = normalized_algorithm.name() == wrapping_alg_name.as_str();
1020
1021 if !valid_wrap_usage || !names_match || !key.Extractable() {
1022 promise.reject_error(Error::InvalidAccess, CanGc::note());
1023 return;
1024 }
1025
1026 if matches!(
1027 alg_name.as_str(), ALG_SHA1 | ALG_SHA256 | ALG_SHA384 | ALG_SHA512 | ALG_HKDF | ALG_PBKDF2
1028 ) {
1029 promise.reject_error(Error::NotSupported, CanGc::note());
1030 return;
1031 }
1032
1033 let exported_key = match subtle.export_key_aes(format, &key) {
1034 Ok(k) => k,
1035 Err(e) => {
1036 promise.reject_error(e, CanGc::note());
1037 return;
1038 },
1039 };
1040
1041 let bytes = match exported_key {
1042 ExportedKey::Raw(k) => k,
1043 ExportedKey::Jwk(key) => {
1044 let Some(k) = key.k else {
1049 promise.reject_error(Error::Syntax(None), CanGc::note());
1050 return;
1051 };
1052 let Some(alg) = key.alg else {
1053 promise.reject_error(Error::Syntax(None), CanGc::note());
1054 return;
1055 };
1056 let Some(ext) = key.ext else {
1057 promise.reject_error(Error::Syntax(None), CanGc::note());
1058 return;
1059 };
1060 let Some(key_ops) = key.key_ops else {
1061 promise.reject_error(Error::Syntax(None), CanGc::note());
1062 return;
1063 };
1064 let key_ops_str = key_ops.iter().map(|op| op.to_string()).collect::<Vec<String>>();
1065 format!("{{
1066 \"kty\": \"oct\",
1067 \"k\": \"{}\",
1068 \"alg\": \"{}\",
1069 \"ext\": {},
1070 \"key_ops\": {:?}
1071 }}", k, alg, ext, key_ops_str)
1072 .into_bytes()
1073 },
1074 };
1075
1076 let cx = GlobalScope::get_cx();
1077 rooted!(in(*cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>());
1078
1079 let result = match normalized_algorithm {
1080 KeyWrapAlgorithm::AesKw => {
1081 subtle.wrap_key_aes_kw(&wrapping_key, &bytes, cx, array_buffer_ptr.handle_mut(), CanGc::note())
1082 },
1083 KeyWrapAlgorithm::AesCbc(params) => {
1084 subtle.encrypt_aes_cbc(¶ms, &wrapping_key, &bytes, cx, array_buffer_ptr.handle_mut(),
1085 CanGc::note())
1086 },
1087 KeyWrapAlgorithm::AesCtr(params) => {
1088 subtle.encrypt_decrypt_aes_ctr(
1089 ¶ms, &wrapping_key, &bytes, cx, array_buffer_ptr.handle_mut(), CanGc::note()
1090 )
1091 },
1092 KeyWrapAlgorithm::AesGcm(params) => {
1093 subtle.encrypt_aes_gcm(
1094 ¶ms, &wrapping_key, &bytes, cx, array_buffer_ptr.handle_mut(), CanGc::note()
1095 )
1096 },
1097 };
1098
1099 match result {
1100 Ok(_) => promise.resolve_native(&*array_buffer_ptr, CanGc::note()),
1101 Err(e) => promise.reject_error(e, CanGc::note()),
1102 }
1103 }),
1104 );
1105
1106 promise
1107 }
1108
1109 fn UnwrapKey(
1111 &self,
1112 cx: JSContext,
1113 format: KeyFormat,
1114 wrapped_key: ArrayBufferViewOrArrayBuffer,
1115 unwrapping_key: &CryptoKey,
1116 unwrap_algorithm: AlgorithmIdentifier,
1117 unwrapped_key_algorithm: AlgorithmIdentifier,
1118 extractable: bool,
1119 key_usages: Vec<KeyUsage>,
1120 comp: InRealm,
1121 can_gc: CanGc,
1122 ) -> Rc<Promise> {
1123 let promise = Promise::new_in_current_realm(comp, can_gc);
1124 let wrapped_key_bytes = match wrapped_key {
1125 ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
1126 ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
1127 };
1128 let normalized_algorithm =
1129 match normalize_algorithm_for_key_wrap(cx, &unwrap_algorithm, can_gc) {
1130 Ok(algorithm) => algorithm,
1131 Err(e) => {
1132 promise.reject_error(e, can_gc);
1133 return promise;
1134 },
1135 };
1136 let normalized_key_algorithm =
1137 match normalize_algorithm_for_import_key(cx, &unwrapped_key_algorithm, can_gc) {
1138 Ok(algorithm) => algorithm,
1139 Err(e) => {
1140 promise.reject_error(e, can_gc);
1141 return promise;
1142 },
1143 };
1144
1145 let this = Trusted::new(self);
1146 let trusted_key = Trusted::new(unwrapping_key);
1147 let trusted_promise = TrustedPromise::new(promise.clone());
1148 self.global().task_manager().dom_manipulation_task_source().queue(
1149 task!(unwrap_key: move || {
1150 let subtle = this.root();
1151 let promise = trusted_promise.root();
1152 let unwrapping_key = trusted_key.root();
1153 let alg_name = unwrapping_key.algorithm();
1154 let valid_usage = unwrapping_key.usages().contains(&KeyUsage::UnwrapKey);
1155
1156 if !valid_usage || normalized_algorithm.name() != alg_name.as_str() {
1157 promise.reject_error(Error::InvalidAccess, CanGc::note());
1158 return;
1159 }
1160
1161 let cx = GlobalScope::get_cx();
1162 rooted!(in(*cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>());
1163
1164 let result = match normalized_algorithm {
1165 KeyWrapAlgorithm::AesKw => {
1166 subtle.unwrap_key_aes_kw(&unwrapping_key, &wrapped_key_bytes, cx, array_buffer_ptr.handle_mut(),
1167 CanGc::note())
1168 },
1169 KeyWrapAlgorithm::AesCbc(params) => {
1170 subtle.decrypt_aes_cbc(
1171 ¶ms, &unwrapping_key, &wrapped_key_bytes, cx, array_buffer_ptr.handle_mut(),
1172 CanGc::note()
1173 )
1174 },
1175 KeyWrapAlgorithm::AesCtr(params) => {
1176 subtle.encrypt_decrypt_aes_ctr(
1177 ¶ms, &unwrapping_key, &wrapped_key_bytes, cx, array_buffer_ptr.handle_mut(),
1178 CanGc::note()
1179 )
1180 },
1181 KeyWrapAlgorithm::AesGcm(params) => {
1182 subtle.decrypt_aes_gcm(
1183 ¶ms, &unwrapping_key, &wrapped_key_bytes, cx, array_buffer_ptr.handle_mut(),
1184 CanGc::note()
1185 )
1186 },
1187 };
1188
1189 let bytes = match result {
1190 Ok(bytes) => bytes,
1191 Err(e) => {
1192 promise.reject_error(e, CanGc::note());
1193 return;
1194 },
1195 };
1196
1197 let import_key_bytes = match format {
1199 KeyFormat::Raw | KeyFormat::Pkcs8 | KeyFormat::Spki => {
1201 bytes
1203 },
1204 KeyFormat::Jwk => {
1206 if let Err(error) = JsonWebKey::parse(cx, &bytes) {
1209 promise.reject_error(error, CanGc::note());
1210 return;
1211 }
1212 bytes
1216 },
1217 };
1218
1219 match normalized_key_algorithm.import_key(&subtle, format, &import_key_bytes,
1220 extractable, key_usages, CanGc::note()) {
1221 Ok(imported_key) => promise.resolve_native(&imported_key, CanGc::note()),
1222 Err(e) => promise.reject_error(e, CanGc::note()),
1223 }
1224 }),
1225 );
1226
1227 promise
1228 }
1229}
1230
1231#[allow(dead_code)]
1235#[derive(Clone, Debug)]
1236pub(crate) struct SubtleAlgorithm {
1237 #[allow(dead_code)]
1238 pub(crate) name: String,
1239}
1240
1241impl From<DOMString> for SubtleAlgorithm {
1242 fn from(name: DOMString) -> Self {
1243 SubtleAlgorithm {
1244 name: name.to_string(),
1245 }
1246 }
1247}
1248
1249#[derive(Clone, Debug)]
1250pub(crate) struct SubtleAesCbcParams {
1251 #[allow(dead_code)]
1252 pub(crate) name: String,
1253 pub(crate) iv: Vec<u8>,
1254}
1255
1256impl From<RootedTraceableBox<AesCbcParams>> for SubtleAesCbcParams {
1257 fn from(params: RootedTraceableBox<AesCbcParams>) -> Self {
1258 let iv = match ¶ms.iv {
1259 ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
1260 ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
1261 };
1262 SubtleAesCbcParams {
1263 name: params.parent.name.to_string(),
1264 iv,
1265 }
1266 }
1267}
1268
1269#[derive(Clone, Debug)]
1270pub(crate) struct SubtleAesCtrParams {
1271 pub(crate) name: String,
1272 pub(crate) counter: Vec<u8>,
1273 pub(crate) length: u8,
1274}
1275
1276impl From<RootedTraceableBox<AesCtrParams>> for SubtleAesCtrParams {
1277 fn from(params: RootedTraceableBox<AesCtrParams>) -> Self {
1278 let counter = match ¶ms.counter {
1279 ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
1280 ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
1281 };
1282 SubtleAesCtrParams {
1283 name: params.parent.name.to_string(),
1284 counter,
1285 length: params.length,
1286 }
1287 }
1288}
1289
1290#[derive(Clone, Debug)]
1291pub(crate) struct SubtleAesGcmParams {
1292 pub(crate) name: String,
1293 pub(crate) iv: Vec<u8>,
1294 pub(crate) additional_data: Option<Vec<u8>>,
1295 pub(crate) tag_length: Option<u8>,
1296}
1297
1298impl From<RootedTraceableBox<AesGcmParams>> for SubtleAesGcmParams {
1299 fn from(params: RootedTraceableBox<AesGcmParams>) -> Self {
1300 let iv = match ¶ms.iv {
1301 ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
1302 ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
1303 };
1304 let additional_data = params.additionalData.as_ref().map(|data| match data {
1305 ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
1306 ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
1307 });
1308
1309 SubtleAesGcmParams {
1310 name: params.parent.name.to_string(),
1311 iv,
1312 additional_data,
1313 tag_length: params.tagLength,
1314 }
1315 }
1316}
1317
1318#[derive(Clone, Debug)]
1319pub(crate) struct SubtleAesKeyGenParams {
1320 pub(crate) name: String,
1321 pub(crate) length: u16,
1322}
1323
1324impl From<AesKeyGenParams> for SubtleAesKeyGenParams {
1325 fn from(params: AesKeyGenParams) -> Self {
1326 SubtleAesKeyGenParams {
1327 name: params.parent.name.to_string().to_uppercase(),
1328 length: params.length,
1329 }
1330 }
1331}
1332
1333#[derive(Clone)]
1335struct SubtleHmacImportParams {
1336 hash: DigestAlgorithm,
1338
1339 length: Option<u32>,
1341}
1342
1343impl SubtleHmacImportParams {
1344 fn new(
1345 cx: JSContext,
1346 params: RootedTraceableBox<HmacImportParams>,
1347 can_gc: CanGc,
1348 ) -> Fallible<Self> {
1349 let hash = normalize_algorithm_for_digest(cx, ¶ms.hash, can_gc)?;
1350 let params = Self {
1351 hash,
1352 length: params.length,
1353 };
1354 Ok(params)
1355 }
1356
1357 fn get_key_length(&self) -> Result<u32, Error> {
1359 let length = match self.length {
1361 None => {
1363 match self.hash {
1366 DigestAlgorithm::Sha1 => 160,
1367 DigestAlgorithm::Sha256 => 256,
1368 DigestAlgorithm::Sha384 => 384,
1369 DigestAlgorithm::Sha512 => 512,
1370 }
1371 },
1372 Some(length) if length != 0 => {
1374 length
1376 },
1377 _ => {
1379 return Err(Error::Type("[[length]] must not be zero".to_string()));
1381 },
1382 };
1383
1384 Ok(length)
1386 }
1387}
1388
1389struct SubtleHmacKeyGenParams {
1390 hash: DigestAlgorithm,
1392
1393 length: Option<u32>,
1395}
1396
1397impl SubtleHmacKeyGenParams {
1398 fn new(
1399 cx: JSContext,
1400 params: RootedTraceableBox<HmacKeyGenParams>,
1401 can_gc: CanGc,
1402 ) -> Fallible<Self> {
1403 let hash = normalize_algorithm_for_digest(cx, ¶ms.hash, can_gc)?;
1404 let params = Self {
1405 hash,
1406 length: params.length,
1407 };
1408 Ok(params)
1409 }
1410}
1411#[derive(Clone, Debug)]
1413pub(crate) struct SubtleHkdfParams {
1414 hash: DigestAlgorithm,
1416
1417 salt: Vec<u8>,
1419
1420 info: Vec<u8>,
1422}
1423
1424impl SubtleHkdfParams {
1425 fn new(cx: JSContext, params: RootedTraceableBox<HkdfParams>, can_gc: CanGc) -> Fallible<Self> {
1426 let hash = normalize_algorithm_for_digest(cx, ¶ms.hash, can_gc)?;
1427 let salt = match ¶ms.salt {
1428 ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
1429 ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
1430 };
1431 let info = match ¶ms.info {
1432 ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
1433 ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
1434 };
1435
1436 let params = Self { hash, salt, info };
1437
1438 Ok(params)
1439 }
1440}
1441
1442#[derive(Clone, Debug)]
1444pub(crate) struct SubtlePbkdf2Params {
1445 salt: Vec<u8>,
1447
1448 iterations: u32,
1450
1451 hash: DigestAlgorithm,
1453}
1454
1455impl SubtlePbkdf2Params {
1456 fn new(
1457 cx: JSContext,
1458 params: RootedTraceableBox<Pbkdf2Params>,
1459 can_gc: CanGc,
1460 ) -> Fallible<Self> {
1461 let salt = match ¶ms.salt {
1462 ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
1463 ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
1464 };
1465
1466 let params = Self {
1467 salt,
1468 iterations: params.iterations,
1469 hash: normalize_algorithm_for_digest(cx, ¶ms.hash, can_gc)?,
1470 };
1471
1472 Ok(params)
1473 }
1474}
1475
1476enum GetKeyLengthAlgorithm {
1477 Aes(u16),
1478 Hmac(SubtleHmacImportParams),
1479}
1480
1481#[derive(Clone, Copy, Debug)]
1482enum DigestAlgorithm {
1483 Sha1,
1485
1486 Sha256,
1488
1489 Sha384,
1491
1492 Sha512,
1494}
1495
1496#[derive(Clone)]
1500enum ImportKeyAlgorithm {
1501 AesCbc,
1502 AesCtr,
1503 AesKw,
1504 AesGcm,
1505 Hmac(SubtleHmacImportParams),
1506 Pbkdf2,
1507 Hkdf,
1508}
1509
1510enum DeriveBitsAlgorithm {
1514 Pbkdf2(SubtlePbkdf2Params),
1515 Hkdf(SubtleHkdfParams),
1516}
1517
1518#[allow(clippy::enum_variant_names)]
1522enum EncryptionAlgorithm {
1523 AesCbc(SubtleAesCbcParams),
1524 AesCtr(SubtleAesCtrParams),
1525 AesGcm(SubtleAesGcmParams),
1526}
1527
1528enum SignatureAlgorithm {
1532 Hmac,
1533}
1534
1535enum KeyGenerationAlgorithm {
1539 Aes(SubtleAesKeyGenParams),
1540 Hmac(SubtleHmacKeyGenParams),
1541}
1542
1543#[allow(clippy::enum_variant_names)]
1547enum KeyWrapAlgorithm {
1548 AesKw,
1549 AesCbc(SubtleAesCbcParams),
1550 AesCtr(SubtleAesCtrParams),
1551 AesGcm(SubtleAesGcmParams),
1552}
1553
1554trait DictionaryFromJSVal: Sized {
1556 fn create(
1557 cx: JSContext,
1558 value: HandleValue,
1559 can_gc: CanGc,
1560 ) -> Result<ConversionResult<Self>, ()>;
1561}
1562
1563impl DictionaryFromJSVal for Algorithm {
1564 fn create(
1565 cx: JSContext,
1566 value: HandleValue,
1567 can_gc: CanGc,
1568 ) -> Result<ConversionResult<Self>, ()> {
1569 Self::new(cx, value, can_gc)
1570 }
1571}
1572
1573impl DictionaryFromJSVal for AesDerivedKeyParams {
1574 fn create(
1575 cx: JSContext,
1576 value: HandleValue,
1577 can_gc: CanGc,
1578 ) -> Result<ConversionResult<Self>, ()> {
1579 Self::new(cx, value, can_gc)
1580 }
1581}
1582
1583impl DictionaryFromJSVal for AesKeyGenParams {
1584 fn create(
1585 cx: JSContext,
1586 value: HandleValue,
1587 can_gc: CanGc,
1588 ) -> Result<ConversionResult<Self>, ()> {
1589 Self::new(cx, value, can_gc)
1590 }
1591}
1592
1593impl DictionaryFromJSVal for RootedTraceableBox<HmacImportParams> {
1594 fn create(
1595 cx: JSContext,
1596 value: HandleValue,
1597 can_gc: CanGc,
1598 ) -> Result<ConversionResult<Self>, ()> {
1599 HmacImportParams::new(cx, value, can_gc)
1600 }
1601}
1602
1603impl DictionaryFromJSVal for RootedTraceableBox<HmacKeyGenParams> {
1604 fn create(
1605 cx: JSContext,
1606 value: HandleValue,
1607 can_gc: CanGc,
1608 ) -> Result<ConversionResult<Self>, ()> {
1609 HmacKeyGenParams::new(cx, value, can_gc)
1610 }
1611}
1612
1613impl DictionaryFromJSVal for HmacKeyAlgorithm {
1614 fn create(
1615 cx: JSContext,
1616 value: HandleValue,
1617 can_gc: CanGc,
1618 ) -> Result<ConversionResult<Self>, ()> {
1619 Self::new(cx, value, can_gc)
1620 }
1621}
1622
1623impl DictionaryFromJSVal for RootedTraceableBox<AesCbcParams> {
1624 fn create(
1625 cx: JSContext,
1626 value: HandleValue,
1627 can_gc: CanGc,
1628 ) -> Result<ConversionResult<Self>, ()> {
1629 AesCbcParams::new(cx, value, can_gc)
1630 }
1631}
1632
1633impl DictionaryFromJSVal for RootedTraceableBox<AesCtrParams> {
1634 fn create(
1635 cx: JSContext,
1636 value: HandleValue,
1637 can_gc: CanGc,
1638 ) -> Result<ConversionResult<Self>, ()> {
1639 AesCtrParams::new(cx, value, can_gc)
1640 }
1641}
1642
1643impl DictionaryFromJSVal for RootedTraceableBox<AesGcmParams> {
1644 fn create(
1645 cx: JSContext,
1646 value: HandleValue,
1647 can_gc: CanGc,
1648 ) -> Result<ConversionResult<Self>, ()> {
1649 AesGcmParams::new(cx, value, can_gc)
1650 }
1651}
1652
1653impl DictionaryFromJSVal for RootedTraceableBox<Pbkdf2Params> {
1654 fn create(
1655 cx: JSContext,
1656 value: HandleValue,
1657 can_gc: CanGc,
1658 ) -> Result<ConversionResult<Self>, ()> {
1659 Pbkdf2Params::new(cx, value, can_gc)
1660 }
1661}
1662
1663impl DictionaryFromJSVal for RootedTraceableBox<HkdfParams> {
1664 fn create(
1665 cx: JSContext,
1666 value: HandleValue,
1667 can_gc: CanGc,
1668 ) -> Result<ConversionResult<Self>, ()> {
1669 HkdfParams::new(cx, value, can_gc)
1670 }
1671}
1672
1673fn extract_native_dict<T>(converted: Result<ConversionResult<T>, ()>) -> Fallible<T> {
1674 let params_result = converted.map_err(|_| Error::JSFailed)?;
1675 let ConversionResult::Success(params) = params_result else {
1676 return Err(Error::Syntax(None));
1677 };
1678 Ok(params)
1679}
1680
1681fn value_from_js_object<T: DictionaryFromJSVal>(
1682 cx: JSContext,
1683 value: HandleValue,
1684 can_gc: CanGc,
1685) -> Fallible<T> {
1686 extract_native_dict(T::create(cx, value, can_gc))
1687}
1688
1689trait DictionaryFromJSValType: crate::JSTraceable {}
1690impl<T: crate::JSTraceable + 'static> DictionaryFromJSValType for T where
1691 RootedTraceableBox<T>: DictionaryFromJSVal
1692{
1693}
1694
1695fn boxed_value_from_js_object<T: DictionaryFromJSValType>(
1696 cx: JSContext,
1697 value: HandleValue,
1698 can_gc: CanGc,
1699) -> Fallible<RootedTraceableBox<T>>
1700where
1701 RootedTraceableBox<T>: DictionaryFromJSVal,
1702{
1703 extract_native_dict(<RootedTraceableBox<T>>::create(cx, value, can_gc))
1704}
1705
1706fn normalize_algorithm_for_get_key_length(
1708 cx: JSContext,
1709 algorithm: &AlgorithmIdentifier,
1710 can_gc: CanGc,
1711) -> Result<GetKeyLengthAlgorithm, Error> {
1712 match algorithm {
1713 AlgorithmIdentifier::Object(obj) => {
1714 rooted!(in(*cx) let value = ObjectValue(obj.get()));
1715 let algorithm = value_from_js_object::<Algorithm>(cx, value.handle(), can_gc)?;
1716
1717 let name = algorithm.name.str();
1718 let normalized_algorithm = if name.eq_ignore_ascii_case(ALG_AES_CBC) ||
1719 name.eq_ignore_ascii_case(ALG_AES_CTR) ||
1720 name.eq_ignore_ascii_case(ALG_AES_GCM)
1721 {
1722 let params =
1723 value_from_js_object::<AesDerivedKeyParams>(cx, value.handle(), can_gc)?;
1724 GetKeyLengthAlgorithm::Aes(params.length)
1725 } else if name.eq_ignore_ascii_case(ALG_HMAC) {
1726 let params =
1727 boxed_value_from_js_object::<HmacImportParams>(cx, value.handle(), can_gc)?;
1728 let subtle_params = SubtleHmacImportParams::new(cx, params, can_gc)?;
1729 return Ok(GetKeyLengthAlgorithm::Hmac(subtle_params));
1730 } else {
1731 return Err(Error::NotSupported);
1732 };
1733
1734 Ok(normalized_algorithm)
1735 },
1736 AlgorithmIdentifier::String(_) => {
1737 Err(Error::NotSupported)
1739 },
1740 }
1741}
1742
1743fn normalize_algorithm_for_digest(
1745 cx: JSContext,
1746 algorithm: &AlgorithmIdentifier,
1747 can_gc: CanGc,
1748) -> Result<DigestAlgorithm, Error> {
1749 let name = match algorithm {
1750 AlgorithmIdentifier::Object(obj) => {
1751 rooted!(in(*cx) let value = ObjectValue(obj.get()));
1752 let algorithm = value_from_js_object::<Algorithm>(cx, value.handle(), can_gc)?;
1753
1754 algorithm.name.str().to_uppercase()
1755 },
1756 AlgorithmIdentifier::String(name) => name.str().to_uppercase(),
1757 };
1758
1759 let normalized_algorithm = match name.as_str() {
1760 ALG_SHA1 => DigestAlgorithm::Sha1,
1761 ALG_SHA256 => DigestAlgorithm::Sha256,
1762 ALG_SHA384 => DigestAlgorithm::Sha384,
1763 ALG_SHA512 => DigestAlgorithm::Sha512,
1764 _ => return Err(Error::NotSupported),
1765 };
1766
1767 Ok(normalized_algorithm)
1768}
1769
1770fn normalize_algorithm_for_import_key(
1772 cx: JSContext,
1773 algorithm: &AlgorithmIdentifier,
1774 can_gc: CanGc,
1775) -> Result<ImportKeyAlgorithm, Error> {
1776 let name = match algorithm {
1777 AlgorithmIdentifier::Object(obj) => {
1778 rooted!(in(*cx) let value = ObjectValue(obj.get()));
1779 let algorithm = value_from_js_object::<Algorithm>(cx, value.handle(), can_gc)?;
1780
1781 let name = algorithm.name.str().to_uppercase();
1782 if name == ALG_HMAC {
1783 let params =
1784 boxed_value_from_js_object::<HmacImportParams>(cx, value.handle(), can_gc)?;
1785 let subtle_params = SubtleHmacImportParams::new(cx, params, can_gc)?;
1786 return Ok(ImportKeyAlgorithm::Hmac(subtle_params));
1787 }
1788
1789 name
1790 },
1791 AlgorithmIdentifier::String(name) => name.str().to_uppercase(),
1792 };
1793
1794 let normalized_algorithm = match name.as_str() {
1795 ALG_AES_CBC => ImportKeyAlgorithm::AesCbc,
1796 ALG_AES_CTR => ImportKeyAlgorithm::AesCtr,
1797 ALG_AES_KW => ImportKeyAlgorithm::AesKw,
1798 ALG_AES_GCM => ImportKeyAlgorithm::AesGcm,
1799 ALG_PBKDF2 => ImportKeyAlgorithm::Pbkdf2,
1800 ALG_HKDF => ImportKeyAlgorithm::Hkdf,
1801 _ => return Err(Error::NotSupported),
1802 };
1803
1804 Ok(normalized_algorithm)
1805}
1806
1807fn normalize_algorithm_for_derive_bits(
1809 cx: JSContext,
1810 algorithm: &AlgorithmIdentifier,
1811 can_gc: CanGc,
1812) -> Result<DeriveBitsAlgorithm, Error> {
1813 let AlgorithmIdentifier::Object(obj) = algorithm else {
1814 return Err(Error::NotSupported);
1816 };
1817
1818 rooted!(in(*cx) let value = ObjectValue(obj.get()));
1819 let algorithm = value_from_js_object::<Algorithm>(cx, value.handle(), can_gc)?;
1820
1821 let normalized_algorithm = if algorithm.name.str().eq_ignore_ascii_case(ALG_PBKDF2) {
1822 let params = boxed_value_from_js_object::<Pbkdf2Params>(cx, value.handle(), can_gc)?;
1823 let subtle_params = SubtlePbkdf2Params::new(cx, params, can_gc)?;
1824 DeriveBitsAlgorithm::Pbkdf2(subtle_params)
1825 } else if algorithm.name.str().eq_ignore_ascii_case(ALG_HKDF) {
1826 let params = boxed_value_from_js_object::<HkdfParams>(cx, value.handle(), can_gc)?;
1827 let subtle_params = SubtleHkdfParams::new(cx, params, can_gc)?;
1828 DeriveBitsAlgorithm::Hkdf(subtle_params)
1829 } else {
1830 return Err(Error::NotSupported);
1831 };
1832
1833 Ok(normalized_algorithm)
1834}
1835
1836fn normalize_algorithm_for_encrypt_or_decrypt(
1838 cx: JSContext,
1839 algorithm: &AlgorithmIdentifier,
1840 can_gc: CanGc,
1841) -> Result<EncryptionAlgorithm, Error> {
1842 let AlgorithmIdentifier::Object(obj) = algorithm else {
1843 return Err(Error::NotSupported);
1845 };
1846
1847 rooted!(in(*cx) let value = ObjectValue(obj.get()));
1848 let algorithm = value_from_js_object::<Algorithm>(cx, value.handle(), can_gc)?;
1849
1850 let name = algorithm.name.str();
1851 let normalized_algorithm = if name.eq_ignore_ascii_case(ALG_AES_CBC) {
1852 let params = boxed_value_from_js_object::<AesCbcParams>(cx, value.handle(), can_gc)?;
1853 EncryptionAlgorithm::AesCbc(params.into())
1854 } else if name.eq_ignore_ascii_case(ALG_AES_CTR) {
1855 let params = boxed_value_from_js_object::<AesCtrParams>(cx, value.handle(), can_gc)?;
1856 EncryptionAlgorithm::AesCtr(params.into())
1857 } else if name.eq_ignore_ascii_case(ALG_AES_GCM) {
1858 let params = boxed_value_from_js_object::<AesGcmParams>(cx, value.handle(), can_gc)?;
1859 EncryptionAlgorithm::AesGcm(params.into())
1860 } else {
1861 return Err(Error::NotSupported);
1862 };
1863
1864 Ok(normalized_algorithm)
1865}
1866
1867fn normalize_algorithm_for_sign_or_verify(
1870 cx: JSContext,
1871 algorithm: &AlgorithmIdentifier,
1872 can_gc: CanGc,
1873) -> Result<SignatureAlgorithm, Error> {
1874 let name = match algorithm {
1875 AlgorithmIdentifier::Object(obj) => {
1876 rooted!(in(*cx) let value = ObjectValue(obj.get()));
1877 let algorithm = value_from_js_object::<Algorithm>(cx, value.handle(), can_gc)?;
1878
1879 algorithm.name.str().to_uppercase()
1880 },
1881 AlgorithmIdentifier::String(name) => name.str().to_uppercase(),
1882 };
1883
1884 let normalized_algorithm = match name.as_str() {
1885 ALG_HMAC => SignatureAlgorithm::Hmac,
1886 _ => return Err(Error::NotSupported),
1887 };
1888
1889 Ok(normalized_algorithm)
1890}
1891
1892fn normalize_algorithm_for_generate_key(
1894 cx: JSContext,
1895 algorithm: &AlgorithmIdentifier,
1896 can_gc: CanGc,
1897) -> Result<KeyGenerationAlgorithm, Error> {
1898 let AlgorithmIdentifier::Object(obj) = algorithm else {
1899 return Err(Error::NotSupported);
1901 };
1902
1903 rooted!(in(*cx) let value = ObjectValue(obj.get()));
1904 let algorithm = value_from_js_object::<Algorithm>(cx, value.handle(), can_gc)?;
1905
1906 let name = algorithm.name.str();
1907 let normalized_algorithm = if name.eq_ignore_ascii_case(ALG_AES_CBC) ||
1908 name.eq_ignore_ascii_case(ALG_AES_CTR) ||
1909 name.eq_ignore_ascii_case(ALG_AES_KW) ||
1910 name.eq_ignore_ascii_case(ALG_AES_GCM)
1911 {
1912 let params = value_from_js_object::<AesKeyGenParams>(cx, value.handle(), can_gc)?;
1913 KeyGenerationAlgorithm::Aes(params.into())
1914 } else if name.eq_ignore_ascii_case(ALG_HMAC) {
1915 let params = boxed_value_from_js_object::<HmacKeyGenParams>(cx, value.handle(), can_gc)?;
1916 let subtle_params = SubtleHmacKeyGenParams::new(cx, params, can_gc)?;
1917 KeyGenerationAlgorithm::Hmac(subtle_params)
1918 } else {
1919 return Err(Error::NotSupported);
1920 };
1921
1922 Ok(normalized_algorithm)
1923}
1924
1925fn normalize_algorithm_for_key_wrap(
1927 cx: JSContext,
1928 algorithm: &AlgorithmIdentifier,
1929 can_gc: CanGc,
1930) -> Result<KeyWrapAlgorithm, Error> {
1931 let name = match algorithm {
1932 AlgorithmIdentifier::Object(obj) => {
1933 rooted!(in(*cx) let value = ObjectValue(obj.get()));
1934 let algorithm = value_from_js_object::<Algorithm>(cx, value.handle(), can_gc)?;
1935
1936 algorithm.name.str().to_uppercase()
1937 },
1938 AlgorithmIdentifier::String(name) => name.str().to_uppercase(),
1939 };
1940
1941 let normalized_algorithm = match name.as_str() {
1942 ALG_AES_KW => KeyWrapAlgorithm::AesKw,
1943 ALG_AES_CBC => {
1944 let AlgorithmIdentifier::Object(obj) = algorithm else {
1945 return Err(Error::Syntax(None));
1946 };
1947 rooted!(in(*cx) let value = ObjectValue(obj.get()));
1948 KeyWrapAlgorithm::AesCbc(
1949 boxed_value_from_js_object::<AesCbcParams>(cx, value.handle(), can_gc)?.into(),
1950 )
1951 },
1952 ALG_AES_CTR => {
1953 let AlgorithmIdentifier::Object(obj) = algorithm else {
1954 return Err(Error::Syntax(None));
1955 };
1956 rooted!(in(*cx) let value = ObjectValue(obj.get()));
1957 KeyWrapAlgorithm::AesCtr(
1958 boxed_value_from_js_object::<AesCtrParams>(cx, value.handle(), can_gc)?.into(),
1959 )
1960 },
1961 ALG_AES_GCM => {
1962 let AlgorithmIdentifier::Object(obj) = algorithm else {
1963 return Err(Error::Syntax(None));
1964 };
1965 rooted!(in(*cx) let value = ObjectValue(obj.get()));
1966 KeyWrapAlgorithm::AesGcm(
1967 boxed_value_from_js_object::<AesGcmParams>(cx, value.handle(), can_gc)?.into(),
1968 )
1969 },
1970 _ => return Err(Error::NotSupported),
1971 };
1972
1973 Ok(normalized_algorithm)
1974}
1975
1976impl SubtleCrypto {
1977 fn encrypt_aes_cbc(
1979 &self,
1980 params: &SubtleAesCbcParams,
1981 key: &CryptoKey,
1982 data: &[u8],
1983 cx: JSContext,
1984 handle: MutableHandleObject,
1985 can_gc: CanGc,
1986 ) -> Result<Vec<u8>, Error> {
1987 if params.iv.len() != 16 {
1988 return Err(Error::Operation);
1989 }
1990
1991 let plaintext = Vec::from(data);
1992 let iv = GenericArray::from_slice(¶ms.iv);
1993
1994 let ct = match key.handle() {
1995 Handle::Aes128(data) => {
1996 let key_data = GenericArray::from_slice(data);
1997 Aes128CbcEnc::new(key_data, iv).encrypt_padded_vec_mut::<Pkcs7>(&plaintext)
1998 },
1999 Handle::Aes192(data) => {
2000 let key_data = GenericArray::from_slice(data);
2001 Aes192CbcEnc::new(key_data, iv).encrypt_padded_vec_mut::<Pkcs7>(&plaintext)
2002 },
2003 Handle::Aes256(data) => {
2004 let key_data = GenericArray::from_slice(data);
2005 Aes256CbcEnc::new(key_data, iv).encrypt_padded_vec_mut::<Pkcs7>(&plaintext)
2006 },
2007 _ => return Err(Error::Data),
2008 };
2009
2010 create_buffer_source::<ArrayBufferU8>(cx, &ct, handle, can_gc)
2011 .expect("failed to create buffer source for exported key.");
2012
2013 Ok(ct)
2014 }
2015
2016 fn decrypt_aes_cbc(
2018 &self,
2019 params: &SubtleAesCbcParams,
2020 key: &CryptoKey,
2021 data: &[u8],
2022 cx: JSContext,
2023 handle: MutableHandleObject,
2024 can_gc: CanGc,
2025 ) -> Result<Vec<u8>, Error> {
2026 if params.iv.len() != 16 {
2027 return Err(Error::Operation);
2028 }
2029
2030 let mut ciphertext = Vec::from(data);
2031 let iv = GenericArray::from_slice(¶ms.iv);
2032
2033 let plaintext = match key.handle() {
2034 Handle::Aes128(data) => {
2035 let key_data = GenericArray::from_slice(data);
2036 Aes128CbcDec::new(key_data, iv)
2037 .decrypt_padded_mut::<Pkcs7>(ciphertext.as_mut_slice())
2038 .map_err(|_| Error::Operation)?
2039 },
2040 Handle::Aes192(data) => {
2041 let key_data = GenericArray::from_slice(data);
2042 Aes192CbcDec::new(key_data, iv)
2043 .decrypt_padded_mut::<Pkcs7>(ciphertext.as_mut_slice())
2044 .map_err(|_| Error::Operation)?
2045 },
2046 Handle::Aes256(data) => {
2047 let key_data = GenericArray::from_slice(data);
2048 Aes256CbcDec::new(key_data, iv)
2049 .decrypt_padded_mut::<Pkcs7>(ciphertext.as_mut_slice())
2050 .map_err(|_| Error::Operation)?
2051 },
2052 _ => return Err(Error::Data),
2053 };
2054
2055 create_buffer_source::<ArrayBufferU8>(cx, plaintext, handle, can_gc)
2056 .expect("failed to create buffer source for exported key.");
2057
2058 Ok(plaintext.to_vec())
2059 }
2060
2061 fn encrypt_decrypt_aes_ctr(
2063 &self,
2064 params: &SubtleAesCtrParams,
2065 key: &CryptoKey,
2066 data: &[u8],
2067 cx: JSContext,
2068 handle: MutableHandleObject,
2069 can_gc: CanGc,
2070 ) -> Result<Vec<u8>, Error> {
2071 if params.counter.len() != 16 || params.length == 0 || params.length > 128 {
2072 return Err(Error::Operation);
2073 }
2074
2075 let mut ciphertext = Vec::from(data);
2076 let counter = GenericArray::from_slice(¶ms.counter);
2077
2078 match key.handle() {
2079 Handle::Aes128(data) => {
2080 let key_data = GenericArray::from_slice(data);
2081 Aes128Ctr::new(key_data, counter).apply_keystream(&mut ciphertext)
2082 },
2083 Handle::Aes192(data) => {
2084 let key_data = GenericArray::from_slice(data);
2085 Aes192Ctr::new(key_data, counter).apply_keystream(&mut ciphertext)
2086 },
2087 Handle::Aes256(data) => {
2088 let key_data = GenericArray::from_slice(data);
2089 Aes256Ctr::new(key_data, counter).apply_keystream(&mut ciphertext)
2090 },
2091 _ => return Err(Error::Data),
2092 };
2093
2094 create_buffer_source::<ArrayBufferU8>(cx, &ciphertext, handle, can_gc)
2095 .expect("failed to create buffer source for exported key.");
2096
2097 Ok(ciphertext)
2098 }
2099
2100 fn encrypt_aes_gcm(
2102 &self,
2103 params: &SubtleAesGcmParams,
2104 key: &CryptoKey,
2105 plaintext: &[u8],
2106 cx: JSContext,
2107 handle: MutableHandleObject,
2108 can_gc: CanGc,
2109 ) -> Result<Vec<u8>, Error> {
2110 if plaintext.len() as u64 > (2 << 39) - 256 {
2112 return Err(Error::Operation);
2113 }
2114
2115 if params
2122 .additional_data
2123 .as_ref()
2124 .is_some_and(|data| data.len() > u64::MAX as usize)
2125 {
2126 return Err(Error::Operation);
2127 }
2128
2129 let tag_length = match params.tag_length {
2131 None => {
2133 128
2135 },
2136 Some(length) if matches!(length, 32 | 64 | 96 | 104 | 112 | 120 | 128) => {
2138 length
2140 },
2141 _ => {
2143 return Err(Error::Operation);
2145 },
2146 };
2147
2148 let additional_data = params.additional_data.as_deref().unwrap_or_default();
2151
2152 let key_length = key.handle().as_bytes().len();
2157 let iv_length = params.iv.len();
2158 let mut ciphertext = plaintext.to_vec();
2159 let key_bytes = key.handle().as_bytes();
2160 let tag = match (key_length, iv_length) {
2161 (16, 12) => {
2162 let nonce = GenericArray::from_slice(¶ms.iv);
2163 <Aes128Gcm96Iv>::new_from_slice(key_bytes)
2164 .expect("key length did not match")
2165 .encrypt_in_place_detached(nonce, additional_data, &mut ciphertext)
2166 },
2167 (16, 16) => {
2168 let nonce = GenericArray::from_slice(¶ms.iv);
2169 <Aes128Gcm128Iv>::new_from_slice(key_bytes)
2170 .expect("key length did not match")
2171 .encrypt_in_place_detached(nonce, additional_data, &mut ciphertext)
2172 },
2173 (24, 12) => {
2174 let nonce = GenericArray::from_slice(¶ms.iv);
2175 <Aes192Gcm96Iv>::new_from_slice(key_bytes)
2176 .expect("key length did not match")
2177 .encrypt_in_place_detached(nonce, additional_data, &mut ciphertext)
2178 },
2179 (32, 12) => {
2180 let nonce = GenericArray::from_slice(¶ms.iv);
2181 <Aes256Gcm96Iv>::new_from_slice(key_bytes)
2182 .expect("key length did not match")
2183 .encrypt_in_place_detached(nonce, additional_data, &mut ciphertext)
2184 },
2185 (16, 32) => {
2186 let nonce = GenericArray::from_slice(¶ms.iv);
2187 <Aes128Gcm256Iv>::new_from_slice(key_bytes)
2188 .expect("key length did not match")
2189 .encrypt_in_place_detached(nonce, additional_data, &mut ciphertext)
2190 },
2191 (24, 32) => {
2192 let nonce = GenericArray::from_slice(¶ms.iv);
2193 <Aes192Gcm256Iv>::new_from_slice(key_bytes)
2194 .expect("key length did not match")
2195 .encrypt_in_place_detached(nonce, additional_data, &mut ciphertext)
2196 },
2197 (32, 32) => {
2198 let nonce = GenericArray::from_slice(¶ms.iv);
2199 <Aes256Gcm256Iv>::new_from_slice(key_bytes)
2200 .expect("key length did not match")
2201 .encrypt_in_place_detached(nonce, additional_data, &mut ciphertext)
2202 },
2203 _ => {
2204 log::warn!(
2205 "Missing AES-GCM encryption implementation with {key_length}-byte key and {iv_length}-byte IV"
2206 );
2207 return Err(Error::NotSupported);
2208 },
2209 };
2210
2211 ciphertext.extend_from_slice(&tag.unwrap()[..tag_length as usize / 8]);
2213
2214 create_buffer_source::<ArrayBufferU8>(cx, &ciphertext, handle, can_gc)
2216 .expect("failed to create buffer source for encrypted ciphertext");
2217
2218 Ok(ciphertext)
2219 }
2220
2221 fn decrypt_aes_gcm(
2223 &self,
2224 params: &SubtleAesGcmParams,
2225 key: &CryptoKey,
2226 ciphertext: &[u8],
2227 cx: JSContext,
2228 handle: MutableHandleObject,
2229 can_gc: CanGc,
2230 ) -> Result<Vec<u8>, Error> {
2231 let tag_length = match params.tag_length {
2234 None => {
2236 128
2238 },
2239 Some(length) if matches!(length, 32 | 64 | 96 | 104 | 112 | 120 | 128) => {
2241 length as usize
2243 },
2244 _ => {
2246 return Err(Error::Operation);
2248 },
2249 };
2250
2251 if ciphertext.len() < tag_length / 8 {
2253 return Err(Error::Operation);
2254 }
2255
2256 let additional_data = params.additional_data.as_deref().unwrap_or_default();
2271
2272 let mut plaintext = ciphertext.to_vec();
2277 let key_length = key.handle().as_bytes().len();
2278 let iv_length = params.iv.len();
2279 let key_bytes = key.handle().as_bytes();
2280 let result = match (key_length, iv_length) {
2281 (16, 12) => {
2282 let nonce = GenericArray::from_slice(¶ms.iv);
2283 <Aes128Gcm96Iv>::new_from_slice(key_bytes)
2284 .expect("key length did not match")
2285 .decrypt_in_place(nonce, additional_data, &mut plaintext)
2286 },
2287 (16, 16) => {
2288 let nonce = GenericArray::from_slice(¶ms.iv);
2289 <Aes128Gcm128Iv>::new_from_slice(key_bytes)
2290 .expect("key length did not match")
2291 .decrypt_in_place(nonce, additional_data, &mut plaintext)
2292 },
2293 (24, 12) => {
2294 let nonce = GenericArray::from_slice(¶ms.iv);
2295 <Aes192Gcm96Iv>::new_from_slice(key_bytes)
2296 .expect("key length did not match")
2297 .decrypt_in_place(nonce, additional_data, &mut plaintext)
2298 },
2299 (32, 12) => {
2300 let nonce = GenericArray::from_slice(¶ms.iv);
2301 <Aes256Gcm96Iv>::new_from_slice(key_bytes)
2302 .expect("key length did not match")
2303 .decrypt_in_place(nonce, additional_data, &mut plaintext)
2304 },
2305 (16, 32) => {
2306 let nonce = GenericArray::from_slice(¶ms.iv);
2307 <Aes128Gcm256Iv>::new_from_slice(key_bytes)
2308 .expect("key length did not match")
2309 .decrypt_in_place(nonce, additional_data, &mut plaintext)
2310 },
2311 (24, 32) => {
2312 let nonce = GenericArray::from_slice(¶ms.iv);
2313 <Aes192Gcm256Iv>::new_from_slice(key_bytes)
2314 .expect("key length did not match")
2315 .decrypt_in_place(nonce, additional_data, &mut plaintext)
2316 },
2317 (32, 32) => {
2318 let nonce = GenericArray::from_slice(¶ms.iv);
2319 <Aes256Gcm256Iv>::new_from_slice(key_bytes)
2320 .expect("key length did not match")
2321 .decrypt_in_place(nonce, additional_data, &mut plaintext)
2322 },
2323 _ => {
2324 log::warn!(
2325 "Missing AES-GCM decryption implementation with {key_length}-byte key and {iv_length}-byte IV"
2326 );
2327 return Err(Error::NotSupported);
2328 },
2329 };
2330
2331 if result.is_err() {
2333 return Err(Error::Operation);
2335 }
2336 create_buffer_source::<ArrayBufferU8>(cx, &plaintext, handle, can_gc)
2341 .expect("failed to create buffer source for decrypted plaintext");
2342
2343 Ok(plaintext)
2344 }
2345
2346 #[allow(unsafe_code)]
2350 fn generate_key_aes(
2351 &self,
2352 usages: Vec<KeyUsage>,
2353 key_gen_params: &SubtleAesKeyGenParams,
2354 extractable: bool,
2355 can_gc: CanGc,
2356 ) -> Result<DomRoot<CryptoKey>, Error> {
2357 let mut rand = vec![0; key_gen_params.length as usize / 8];
2358 self.rng.borrow_mut().fill_bytes(&mut rand);
2359 let handle = match key_gen_params.length {
2360 128 => Handle::Aes128(rand),
2361 192 => Handle::Aes192(rand),
2362 256 => Handle::Aes256(rand),
2363 _ => return Err(Error::Operation),
2364 };
2365
2366 match key_gen_params.name.as_str() {
2367 ALG_AES_CBC | ALG_AES_CTR | ALG_AES_GCM => {
2368 if usages.iter().any(|usage| {
2369 !matches!(
2370 usage,
2371 KeyUsage::Encrypt |
2372 KeyUsage::Decrypt |
2373 KeyUsage::WrapKey |
2374 KeyUsage::UnwrapKey
2375 )
2376 }) || usages.is_empty()
2377 {
2378 return Err(Error::Syntax(None));
2379 }
2380 },
2381 ALG_AES_KW => {
2382 if usages
2383 .iter()
2384 .any(|usage| !matches!(usage, KeyUsage::WrapKey | KeyUsage::UnwrapKey)) ||
2385 usages.is_empty()
2386 {
2387 return Err(Error::Syntax(None));
2388 }
2389 },
2390 _ => return Err(Error::NotSupported),
2391 }
2392
2393 let name = match key_gen_params.name.as_str() {
2394 ALG_AES_CBC => DOMString::from(ALG_AES_CBC),
2395 ALG_AES_CTR => DOMString::from(ALG_AES_CTR),
2396 ALG_AES_KW => DOMString::from(ALG_AES_KW),
2397 ALG_AES_GCM => DOMString::from(ALG_AES_GCM),
2398 _ => return Err(Error::NotSupported),
2399 };
2400
2401 let cx = GlobalScope::get_cx();
2402 rooted!(in(*cx) let mut algorithm_object = unsafe {JS_NewObject(*cx, ptr::null()) });
2403 assert!(!algorithm_object.is_null());
2404
2405 AesKeyAlgorithm::from_name_and_size(
2406 name.clone(),
2407 key_gen_params.length,
2408 algorithm_object.handle_mut(),
2409 cx,
2410 );
2411
2412 let crypto_key = CryptoKey::new(
2413 &self.global(),
2414 KeyType::Secret,
2415 extractable,
2416 name,
2417 algorithm_object.handle(),
2418 usages,
2419 handle,
2420 can_gc,
2421 );
2422
2423 Ok(crypto_key)
2424 }
2425
2426 #[allow(unsafe_code)]
2428 fn generate_key_hmac(
2429 &self,
2430 usages: Vec<KeyUsage>,
2431 params: &SubtleHmacKeyGenParams,
2432 extractable: bool,
2433 can_gc: CanGc,
2434 ) -> Result<DomRoot<CryptoKey>, Error> {
2435 if usages
2437 .iter()
2438 .any(|usage| !matches!(usage, KeyUsage::Sign | KeyUsage::Verify))
2439 {
2440 return Err(Error::Syntax(None));
2441 }
2442
2443 let length = match params.length {
2445 None => {
2447 params.hash.block_size_in_bits() as u32
2450 },
2451 Some(length) if length != 0 => {
2453 length
2455 },
2456 _ => {
2458 return Err(Error::Operation);
2460 },
2461 };
2462
2463 let mut key_data = vec![0; length as usize];
2465 self.rng.borrow_mut().fill_bytes(&mut key_data);
2466
2467 let name = DOMString::from(ALG_HMAC);
2481 let cx = GlobalScope::get_cx();
2482 rooted!(in(*cx) let mut algorithm_object = unsafe {JS_NewObject(*cx, ptr::null()) });
2483 assert!(!algorithm_object.is_null());
2484 HmacKeyAlgorithm::from_length_and_hash(
2485 length,
2486 params.hash,
2487 algorithm_object.handle_mut(),
2488 cx,
2489 );
2490
2491 let key = CryptoKey::new(
2492 &self.global(),
2493 KeyType::Secret,
2494 extractable,
2495 name,
2496 algorithm_object.handle(),
2497 usages,
2498 Handle::Hmac(key_data),
2499 can_gc,
2500 );
2501
2502 Ok(key)
2504 }
2505
2506 #[allow(unsafe_code)]
2511 fn import_key_aes(
2512 &self,
2513 format: KeyFormat,
2514 key_data: &[u8],
2515 extractable: bool,
2516 usages: Vec<KeyUsage>,
2517 alg_name: &str,
2518 can_gc: CanGc,
2519 ) -> Result<DomRoot<CryptoKey>, Error> {
2520 if usages.iter().any(|usage| {
2523 !matches!(
2524 usage,
2525 KeyUsage::Encrypt | KeyUsage::Decrypt | KeyUsage::WrapKey | KeyUsage::UnwrapKey
2526 )
2527 }) || usages.is_empty()
2528 {
2529 return Err(Error::Syntax(None));
2530 }
2531
2532 let data;
2534 match format {
2535 KeyFormat::Raw => {
2537 data = key_data.to_vec();
2539
2540 if !matches!(data.len() * 8, 128 | 192 | 256) {
2542 return Err(Error::Data);
2543 }
2544 },
2545 KeyFormat::Jwk => {
2547 let jwk = JsonWebKey::parse(GlobalScope::get_cx(), key_data)?;
2551
2552 if jwk.kty.as_ref().is_none_or(|kty| kty != "oct") {
2554 return Err(Error::Data);
2555 }
2556
2557 data = base64::engine::general_purpose::STANDARD_NO_PAD
2563 .decode(jwk.k.as_ref().ok_or(Error::Data)?.as_bytes())
2564 .map_err(|_| Error::Data)?;
2565
2566 let alg_matching = match alg_name {
2569 ALG_AES_CBC => ["A128CBC", "A192CBC", "A256CBC"],
2570 ALG_AES_CTR => ["A128CTR", "A192CTR", "A256CTR"],
2571 ALG_AES_GCM => ["A128GCM", "A192GCM", "A256GCM"],
2572 ALG_AES_KW => ["A128KW", "A192KW", "A256KW"],
2573 _ => unreachable!(),
2574 };
2575
2576 match data.len() * 8 {
2578 128 => {
2580 if jwk.alg.as_ref().is_some_and(|alg| alg != alg_matching[0]) {
2586 return Err(Error::Data);
2587 }
2588 },
2589 192 => {
2591 if jwk.alg.as_ref().is_some_and(|alg| alg != alg_matching[1]) {
2597 return Err(Error::Data);
2598 }
2599 },
2600 256 => {
2602 if jwk.alg.as_ref().is_some_and(|alg| alg != alg_matching[2]) {
2608 return Err(Error::Data);
2609 }
2610 },
2611 _ => {
2613 return Err(Error::Data);
2615 },
2616 }
2617
2618 if !usages.is_empty() && jwk.use_.as_ref().is_some_and(|use_| use_ != "enc") {
2621 return Err(Error::Data);
2622 }
2623
2624 jwk.check_key_ops(&usages)?;
2628
2629 if jwk.ext.is_some_and(|ext| !ext) && extractable {
2632 return Err(Error::Data);
2633 }
2634 },
2635 _ => {
2637 return Err(Error::NotSupported);
2639 },
2640 };
2641
2642 let name = DOMString::from(alg_name.to_string());
2646 let cx = GlobalScope::get_cx();
2647 rooted!(in(*cx) let mut algorithm_object = unsafe { JS_NewObject(*cx, ptr::null()) });
2648 assert!(!algorithm_object.is_null());
2649 AesKeyAlgorithm::from_name_and_size(
2650 name.clone(),
2651 (data.len() * 8) as u16,
2652 algorithm_object.handle_mut(),
2653 cx,
2654 );
2655
2656 let handle = match data.len() * 8 {
2660 128 => Handle::Aes128(data.to_vec()),
2661 192 => Handle::Aes192(data.to_vec()),
2662 256 => Handle::Aes256(data.to_vec()),
2663 _ => {
2664 return Err(Error::Data);
2665 },
2666 };
2667 let key = CryptoKey::new(
2668 &self.global(),
2669 KeyType::Secret,
2670 extractable,
2671 name,
2672 algorithm_object.handle(),
2673 usages,
2674 handle,
2675 can_gc,
2676 );
2677
2678 Ok(key)
2680 }
2681
2682 fn export_key_aes(&self, format: KeyFormat, key: &CryptoKey) -> Result<ExportedKey, Error> {
2687 let result;
2693 match format {
2694 KeyFormat::Raw => match key.handle() {
2696 Handle::Aes128(key_data) => {
2700 result = ExportedKey::Raw(key_data.clone());
2701 },
2702 Handle::Aes192(key_data) => {
2703 result = ExportedKey::Raw(key_data.clone());
2704 },
2705 Handle::Aes256(key_data) => {
2706 result = ExportedKey::Raw(key_data.clone());
2707 },
2708 _ => unreachable!(),
2709 },
2710 KeyFormat::Jwk => {
2712 let k = match key.handle() {
2716 Handle::Aes128(key) => {
2717 base64::engine::general_purpose::STANDARD_NO_PAD.encode(key)
2718 },
2719 Handle::Aes192(key) => {
2720 base64::engine::general_purpose::STANDARD_NO_PAD.encode(key)
2721 },
2722 Handle::Aes256(key) => {
2723 base64::engine::general_purpose::STANDARD_NO_PAD.encode(key)
2724 },
2725 _ => unreachable!(),
2726 };
2727
2728 let alg = match (key.handle(), key.algorithm().as_str()) {
2747 (Handle::Aes128(_), ALG_AES_CTR) => "A128CTR",
2748 (Handle::Aes192(_), ALG_AES_CTR) => "A192CTR",
2749 (Handle::Aes256(_), ALG_AES_CTR) => "A256CTR",
2750 (Handle::Aes128(_), ALG_AES_CBC) => "A128CBC",
2751 (Handle::Aes192(_), ALG_AES_CBC) => "A192CBC",
2752 (Handle::Aes256(_), ALG_AES_CBC) => "A256CBC",
2753 (Handle::Aes128(_), ALG_AES_GCM) => "A128GCM",
2754 (Handle::Aes192(_), ALG_AES_GCM) => "A192GCM",
2755 (Handle::Aes256(_), ALG_AES_GCM) => "A256GCM",
2756 (Handle::Aes128(_), ALG_AES_KW) => "A128KW",
2757 (Handle::Aes192(_), ALG_AES_KW) => "A192KW",
2758 (Handle::Aes256(_), ALG_AES_KW) => "A256KW",
2759 _ => unreachable!(),
2760 };
2761
2762 let key_ops = key
2764 .usages()
2765 .iter()
2766 .map(|usage| DOMString::from(usage.as_str()))
2767 .collect::<Vec<DOMString>>();
2768
2769 let jwk = JsonWebKey {
2773 kty: Some(DOMString::from("oct")),
2774 k: Some(DOMString::from(k)),
2775 alg: Some(DOMString::from(alg)),
2776 key_ops: Some(key_ops),
2777 ext: Some(key.Extractable()),
2778 ..Default::default()
2779 };
2780
2781 result = ExportedKey::Jwk(Box::new(jwk));
2783 },
2784 _ => {
2786 return Err(Error::NotSupported);
2788 },
2789 };
2790
2791 Ok(result)
2793 }
2794
2795 #[allow(unsafe_code)]
2797 fn import_key_hkdf(
2798 &self,
2799 format: KeyFormat,
2800 data: &[u8],
2801 extractable: bool,
2802 usages: Vec<KeyUsage>,
2803 can_gc: CanGc,
2804 ) -> Result<DomRoot<CryptoKey>, Error> {
2805 if format == KeyFormat::Raw {
2808 if usages
2810 .iter()
2811 .any(|usage| !matches!(usage, KeyUsage::DeriveKey | KeyUsage::DeriveBits)) ||
2812 usages.is_empty()
2813 {
2814 return Err(Error::Syntax(None));
2815 }
2816
2817 if extractable {
2819 return Err(Error::Syntax(None));
2820 }
2821
2822 let name = DOMString::from(ALG_HKDF);
2828 let cx = GlobalScope::get_cx();
2829 rooted!(in(*cx) let mut algorithm_object = unsafe {JS_NewObject(*cx, ptr::null()) });
2830 assert!(!algorithm_object.is_null());
2831 KeyAlgorithm::from_name(name.clone(), algorithm_object.handle_mut(), cx);
2832
2833 let key = CryptoKey::new(
2834 &self.global(),
2835 KeyType::Secret,
2836 extractable,
2837 name,
2838 algorithm_object.handle(),
2839 usages,
2840 Handle::Hkdf(data.to_vec()),
2841 can_gc,
2842 );
2843
2844 Ok(key)
2846 } else {
2847 Err(Error::NotSupported)
2849 }
2850 }
2851
2852 #[allow(unsafe_code)]
2854 fn import_key_hmac(
2855 &self,
2856 normalized_algorithm: &SubtleHmacImportParams,
2857 format: KeyFormat,
2858 key_data: &[u8],
2859 extractable: bool,
2860 usages: Vec<KeyUsage>,
2861 can_gc: CanGc,
2862 ) -> Result<DomRoot<CryptoKey>, Error> {
2863 if usages
2867 .iter()
2868 .any(|usage| !matches!(usage, KeyUsage::Sign | KeyUsage::Verify)) ||
2869 usages.is_empty()
2870 {
2871 return Err(Error::Syntax(None));
2872 }
2873
2874 let hash;
2876
2877 let data;
2879 match format {
2880 KeyFormat::Raw => {
2882 data = key_data.to_vec();
2884
2885 hash = normalized_algorithm.hash;
2887 },
2888 KeyFormat::Jwk => {
2890 let jwk = JsonWebKey::parse(GlobalScope::get_cx(), key_data)?;
2894
2895 if jwk.kty.as_ref().is_none_or(|kty| kty != "oct") {
2897 return Err(Error::Data);
2898 }
2899
2900 data = base64::engine::general_purpose::STANDARD_NO_PAD
2906 .decode(jwk.k.as_ref().ok_or(Error::Data)?.as_bytes())
2907 .map_err(|_| Error::Data)?;
2908
2909 hash = normalized_algorithm.hash;
2911
2912 match hash.name().to_string().as_str() {
2914 ALG_SHA1 => {
2916 if jwk.alg.as_ref().is_some_and(|alg| alg != "HS1") {
2918 return Err(Error::Data);
2919 }
2920 },
2921 ALG_SHA256 => {
2923 if jwk.alg.as_ref().is_some_and(|alg| alg != "HS256") {
2925 return Err(Error::Data);
2926 }
2927 },
2928 ALG_SHA384 => {
2930 if jwk.alg.as_ref().is_some_and(|alg| alg != "HS384") {
2932 return Err(Error::Data);
2933 }
2934 },
2935 ALG_SHA512 => {
2937 if jwk.alg.as_ref().is_some_and(|alg| alg != "HS512") {
2939 return Err(Error::Data);
2940 }
2941 },
2942 _name => {
2944 return Err(Error::NotSupported);
2949 },
2950 }
2951
2952 if !usages.is_empty() && jwk.use_.as_ref().is_some_and(|use_| use_ != "sig") {
2955 return Err(Error::Data);
2956 }
2957
2958 jwk.check_key_ops(&usages)?;
2962
2963 if jwk.ext.is_some_and(|ext| !ext) && extractable {
2966 return Err(Error::Data);
2967 }
2968 },
2969 _ => {
2971 return Err(Error::NotSupported);
2973 },
2974 }
2975
2976 let mut length = data.len() as u32 * 8;
2978
2979 if length == 0 {
2981 return Err(Error::Data);
2982 }
2983
2984 if let Some(given_length) = normalized_algorithm.length {
2986 if given_length > length {
2988 return Err(Error::Data);
2990 }
2991 else {
2993 length = given_length;
2995 }
2996 }
2997
2998 let truncated_data = data[..length as usize / 8].to_vec();
3006 let name = DOMString::from(ALG_HMAC);
3007 let cx = GlobalScope::get_cx();
3008 rooted!(in(*cx) let mut algorithm_object = unsafe { JS_NewObject(*cx, ptr::null()) });
3009 assert!(!algorithm_object.is_null());
3010 HmacKeyAlgorithm::from_length_and_hash(length, hash, algorithm_object.handle_mut(), cx);
3011
3012 let key = CryptoKey::new(
3013 &self.global(),
3014 KeyType::Secret,
3015 extractable,
3016 name,
3017 algorithm_object.handle(),
3018 usages,
3019 Handle::Hmac(truncated_data),
3020 can_gc,
3021 );
3022
3023 Ok(key)
3025 }
3026
3027 fn export_key_hmac(&self, format: KeyFormat, key: &CryptoKey) -> Result<ExportedKey, Error> {
3029 match format {
3030 KeyFormat::Raw => match key.handle() {
3031 Handle::Hmac(key_data) => Ok(ExportedKey::Raw(key_data.as_slice().to_vec())),
3032 _ => Err(Error::Operation),
3033 },
3034 _ => Err(Error::NotSupported),
3036 }
3037 }
3038
3039 fn wrap_key_aes_kw(
3041 &self,
3042 wrapping_key: &CryptoKey,
3043 bytes: &[u8],
3044 cx: JSContext,
3045 handle: MutableHandleObject,
3046 can_gc: CanGc,
3047 ) -> Result<Vec<u8>, Error> {
3048 if bytes.len() % 8 != 0 {
3050 return Err(Error::Operation);
3051 }
3052
3053 let wrapped_key = match wrapping_key.handle() {
3057 Handle::Aes128(key_data) => {
3058 let key_array = GenericArray::from_slice(key_data.as_slice());
3059 let kek = KekAes128::new(key_array);
3060 match kek.wrap_vec(bytes) {
3061 Ok(key) => key,
3062 Err(_) => return Err(Error::Operation),
3063 }
3064 },
3065 Handle::Aes192(key_data) => {
3066 let key_array = GenericArray::from_slice(key_data.as_slice());
3067 let kek = KekAes192::new(key_array);
3068 match kek.wrap_vec(bytes) {
3069 Ok(key) => key,
3070 Err(_) => return Err(Error::Operation),
3071 }
3072 },
3073 Handle::Aes256(key_data) => {
3074 let key_array = GenericArray::from_slice(key_data.as_slice());
3075 let kek = KekAes256::new(key_array);
3076 match kek.wrap_vec(bytes) {
3077 Ok(key) => key,
3078 Err(_) => return Err(Error::Operation),
3079 }
3080 },
3081 _ => return Err(Error::Operation),
3082 };
3083
3084 create_buffer_source::<ArrayBufferU8>(cx, &wrapped_key, handle, can_gc)
3085 .expect("failed to create buffer source for wrapped key.");
3086
3087 Ok(wrapped_key)
3089 }
3090
3091 fn unwrap_key_aes_kw(
3093 &self,
3094 wrapping_key: &CryptoKey,
3095 bytes: &[u8],
3096 cx: JSContext,
3097 handle: MutableHandleObject,
3098 can_gc: CanGc,
3099 ) -> Result<Vec<u8>, Error> {
3100 let unwrapped_key = match wrapping_key.handle() {
3105 Handle::Aes128(key_data) => {
3106 let key_array = GenericArray::from_slice(key_data.as_slice());
3107 let kek = KekAes128::new(key_array);
3108 match kek.unwrap_vec(bytes) {
3109 Ok(key) => key,
3110 Err(_) => return Err(Error::Operation),
3111 }
3112 },
3113 Handle::Aes192(key_data) => {
3114 let key_array = GenericArray::from_slice(key_data.as_slice());
3115 let kek = KekAes192::new(key_array);
3116 match kek.unwrap_vec(bytes) {
3117 Ok(key) => key,
3118 Err(_) => return Err(Error::Operation),
3119 }
3120 },
3121 Handle::Aes256(key_data) => {
3122 let key_array = GenericArray::from_slice(key_data.as_slice());
3123 let kek = KekAes256::new(key_array);
3124 match kek.unwrap_vec(bytes) {
3125 Ok(key) => key,
3126 Err(_) => return Err(Error::Operation),
3127 }
3128 },
3129 _ => return Err(Error::Operation),
3130 };
3131
3132 create_buffer_source::<ArrayBufferU8>(cx, &unwrapped_key, handle, can_gc)
3133 .expect("failed to create buffer source for unwrapped key.");
3134
3135 Ok(unwrapped_key)
3137 }
3138
3139 #[allow(unsafe_code)]
3141 fn import_key_pbkdf2(
3142 &self,
3143 format: KeyFormat,
3144 data: &[u8],
3145 extractable: bool,
3146 usages: Vec<KeyUsage>,
3147 can_gc: CanGc,
3148 ) -> Result<DomRoot<CryptoKey>, Error> {
3149 if format != KeyFormat::Raw {
3151 return Err(Error::NotSupported);
3152 }
3153
3154 if usages
3156 .iter()
3157 .any(|usage| !matches!(usage, KeyUsage::DeriveKey | KeyUsage::DeriveBits)) ||
3158 usages.is_empty()
3159 {
3160 return Err(Error::Syntax(None));
3161 }
3162
3163 if extractable {
3165 return Err(Error::Syntax(None));
3166 }
3167
3168 let name = DOMString::from(ALG_PBKDF2);
3174 let cx = GlobalScope::get_cx();
3175 rooted!(in(*cx) let mut algorithm_object = unsafe {JS_NewObject(*cx, ptr::null()) });
3176 assert!(!algorithm_object.is_null());
3177 KeyAlgorithm::from_name(name.clone(), algorithm_object.handle_mut(), cx);
3178
3179 let key = CryptoKey::new(
3180 &self.global(),
3181 KeyType::Secret,
3182 extractable,
3183 name,
3184 algorithm_object.handle(),
3185 usages,
3186 Handle::Pbkdf2(data.to_vec()),
3187 can_gc,
3188 );
3189
3190 Ok(key)
3192 }
3193}
3194
3195pub(crate) enum ExportedKey {
3196 Raw(Vec<u8>),
3197 Jwk(Box<JsonWebKey>),
3198}
3199
3200trait AlgorithmFromName {
3201 fn from_name(name: DOMString, out: MutableHandleObject, cx: JSContext);
3202}
3203
3204impl AlgorithmFromName for KeyAlgorithm {
3205 #[allow(unsafe_code)]
3208 fn from_name(name: DOMString, out: MutableHandleObject, cx: JSContext) {
3209 let key_algorithm = Self { name };
3210
3211 unsafe {
3212 key_algorithm.to_jsobject(*cx, out);
3213 }
3214 }
3215}
3216
3217trait AlgorithmFromLengthAndHash {
3218 fn from_length_and_hash(
3219 length: u32,
3220 hash: DigestAlgorithm,
3221 out: MutableHandleObject,
3222 cx: JSContext,
3223 );
3224}
3225
3226impl AlgorithmFromLengthAndHash for HmacKeyAlgorithm {
3227 #[allow(unsafe_code)]
3228 fn from_length_and_hash(
3229 length: u32,
3230 hash: DigestAlgorithm,
3231 out: MutableHandleObject,
3232 cx: JSContext,
3233 ) {
3234 let hmac_key_algorithm = Self {
3235 parent: KeyAlgorithm {
3236 name: ALG_HMAC.into(),
3237 },
3238 length,
3239 hash: KeyAlgorithm { name: hash.name() },
3240 };
3241
3242 unsafe {
3243 hmac_key_algorithm.to_jsobject(*cx, out);
3244 }
3245 }
3246}
3247
3248trait AlgorithmFromNameAndSize {
3249 fn from_name_and_size(name: DOMString, size: u16, out: MutableHandleObject, cx: JSContext);
3250}
3251
3252impl AlgorithmFromNameAndSize for AesKeyAlgorithm {
3253 #[allow(unsafe_code)]
3256 fn from_name_and_size(name: DOMString, size: u16, out: MutableHandleObject, cx: JSContext) {
3257 let key_algorithm = Self {
3258 parent: KeyAlgorithm { name },
3259 length: size,
3260 };
3261
3262 unsafe {
3263 key_algorithm.to_jsobject(*cx, out);
3264 }
3265 }
3266}
3267
3268impl SubtleHkdfParams {
3269 fn derive_bits(&self, key: &CryptoKey, length: Option<u32>) -> Result<Vec<u8>, Error> {
3271 let Some(length) = length else {
3273 return Err(Error::Operation);
3274 };
3275 if length == 0 || length % 8 != 0 {
3276 return Err(Error::Operation);
3277 };
3278
3279 let key_derivation_key = key.handle().as_bytes();
3281
3282 let mut result = vec![0; length as usize / 8];
3290 let algorithm = match self.hash {
3291 DigestAlgorithm::Sha1 => hkdf::HKDF_SHA1_FOR_LEGACY_USE_ONLY,
3292 DigestAlgorithm::Sha256 => hkdf::HKDF_SHA256,
3293 DigestAlgorithm::Sha384 => hkdf::HKDF_SHA384,
3294 DigestAlgorithm::Sha512 => hkdf::HKDF_SHA512,
3295 };
3296 let salt = hkdf::Salt::new(algorithm, &self.salt);
3297 let info = self.info.as_slice();
3298 let pseudo_random_key = salt.extract(key_derivation_key);
3299
3300 let Ok(output_key_material) =
3301 pseudo_random_key.expand(std::slice::from_ref(&info), algorithm)
3302 else {
3303 return Err(Error::Operation);
3305 };
3306
3307 if output_key_material.fill(&mut result).is_err() {
3308 return Err(Error::Operation);
3309 };
3310
3311 Ok(result)
3314 }
3315}
3316
3317impl SubtlePbkdf2Params {
3318 fn derive_bits(&self, key: &CryptoKey, length: Option<u32>) -> Result<Vec<u8>, Error> {
3320 let Some(length) = length else {
3322 return Err(Error::Operation);
3323 };
3324 if length == 0 || length % 8 != 0 {
3325 return Err(Error::Operation);
3326 };
3327
3328 let Ok(iterations) = NonZero::<u32>::try_from(self.iterations) else {
3330 return Err(Error::Operation);
3331 };
3332
3333 let prf = match self.hash {
3336 DigestAlgorithm::Sha1 => pbkdf2::PBKDF2_HMAC_SHA1,
3337 DigestAlgorithm::Sha256 => pbkdf2::PBKDF2_HMAC_SHA256,
3338 DigestAlgorithm::Sha384 => pbkdf2::PBKDF2_HMAC_SHA384,
3339 DigestAlgorithm::Sha512 => pbkdf2::PBKDF2_HMAC_SHA512,
3340 };
3341
3342 let mut result = vec![0; length as usize / 8];
3348 pbkdf2::derive(
3349 prf,
3350 iterations,
3351 &self.salt,
3352 key.handle().as_bytes(),
3353 &mut result,
3354 );
3355
3356 Ok(result)
3362 }
3363}
3364
3365fn get_key_length_for_aes(length: u16) -> Result<u32, Error> {
3367 if !matches!(length, 128 | 192 | 256) {
3370 return Err(Error::Operation);
3371 }
3372
3373 Ok(length as u32)
3375}
3376
3377impl GetKeyLengthAlgorithm {
3378 fn get_key_length(&self) -> Result<u32, Error> {
3379 match self {
3380 Self::Aes(length) => get_key_length_for_aes(*length),
3381 Self::Hmac(params) => params.get_key_length(),
3382 }
3383 }
3384}
3385
3386impl DigestAlgorithm {
3387 fn name(&self) -> DOMString {
3389 match self {
3390 Self::Sha1 => ALG_SHA1,
3391 Self::Sha256 => ALG_SHA256,
3392 Self::Sha384 => ALG_SHA384,
3393 Self::Sha512 => ALG_SHA512,
3394 }
3395 .into()
3396 }
3397
3398 fn digest(&self, data: &[u8]) -> Result<impl AsRef<[u8]>, Error> {
3399 let algorithm = match self {
3400 Self::Sha1 => &digest::SHA1_FOR_LEGACY_USE_ONLY,
3401 Self::Sha256 => &digest::SHA256,
3402 Self::Sha384 => &digest::SHA384,
3403 Self::Sha512 => &digest::SHA512,
3404 };
3405 Ok(digest::digest(algorithm, data))
3406 }
3407
3408 fn block_size_in_bits(&self) -> usize {
3409 match self {
3410 Self::Sha1 => 160,
3411 Self::Sha256 => 256,
3412 Self::Sha384 => 384,
3413 Self::Sha512 => 512,
3414 }
3415 }
3416}
3417
3418impl ImportKeyAlgorithm {
3419 fn import_key(
3420 &self,
3421 subtle: &SubtleCrypto,
3422 format: KeyFormat,
3423 key_data: &[u8],
3424 extractable: bool,
3425 key_usages: Vec<KeyUsage>,
3426 can_gc: CanGc,
3427 ) -> Result<DomRoot<CryptoKey>, Error> {
3428 match self {
3429 Self::AesCbc => subtle.import_key_aes(
3430 format,
3431 key_data,
3432 extractable,
3433 key_usages,
3434 ALG_AES_CBC,
3435 can_gc,
3436 ),
3437 Self::AesCtr => subtle.import_key_aes(
3438 format,
3439 key_data,
3440 extractable,
3441 key_usages,
3442 ALG_AES_CTR,
3443 can_gc,
3444 ),
3445 Self::AesKw => subtle.import_key_aes(
3446 format,
3447 key_data,
3448 extractable,
3449 key_usages,
3450 ALG_AES_KW,
3451 can_gc,
3452 ),
3453 Self::AesGcm => subtle.import_key_aes(
3454 format,
3455 key_data,
3456 extractable,
3457 key_usages,
3458 ALG_AES_GCM,
3459 can_gc,
3460 ),
3461 Self::Hmac(params) => {
3462 subtle.import_key_hmac(params, format, key_data, extractable, key_usages, can_gc)
3463 },
3464 Self::Pbkdf2 => {
3465 subtle.import_key_pbkdf2(format, key_data, extractable, key_usages, can_gc)
3466 },
3467 Self::Hkdf => subtle.import_key_hkdf(format, key_data, extractable, key_usages, can_gc),
3468 }
3469 }
3470}
3471
3472impl DeriveBitsAlgorithm {
3473 fn derive_bits(&self, key: &CryptoKey, length: Option<u32>) -> Result<Vec<u8>, Error> {
3474 match self {
3475 Self::Pbkdf2(pbkdf2_params) => pbkdf2_params.derive_bits(key, length),
3476 Self::Hkdf(hkdf_params) => hkdf_params.derive_bits(key, length),
3477 }
3478 }
3479}
3480
3481impl EncryptionAlgorithm {
3482 fn name(&self) -> &str {
3484 match self {
3485 Self::AesCbc(params) => ¶ms.name,
3486 Self::AesCtr(params) => ¶ms.name,
3487 Self::AesGcm(params) => ¶ms.name,
3488 }
3489 }
3490
3491 fn encrypt(
3493 &self,
3494 subtle: &SubtleCrypto,
3495 key: &CryptoKey,
3496 data: &[u8],
3497 cx: JSContext,
3498 result: MutableHandleObject,
3499 can_gc: CanGc,
3500 ) -> Result<Vec<u8>, Error> {
3501 match self {
3502 Self::AesCbc(params) => subtle.encrypt_aes_cbc(params, key, data, cx, result, can_gc),
3503 Self::AesCtr(params) => {
3504 subtle.encrypt_decrypt_aes_ctr(params, key, data, cx, result, can_gc)
3505 },
3506 Self::AesGcm(params) => subtle.encrypt_aes_gcm(params, key, data, cx, result, can_gc),
3507 }
3508 }
3509
3510 fn decrypt(
3512 &self,
3513 subtle: &SubtleCrypto,
3514 key: &CryptoKey,
3515 data: &[u8],
3516 cx: JSContext,
3517 result: MutableHandleObject,
3518 can_gc: CanGc,
3519 ) -> Result<Vec<u8>, Error> {
3520 match self {
3521 Self::AesCbc(params) => subtle.decrypt_aes_cbc(params, key, data, cx, result, can_gc),
3522 Self::AesCtr(params) => {
3523 subtle.encrypt_decrypt_aes_ctr(params, key, data, cx, result, can_gc)
3524 },
3525 Self::AesGcm(params) => subtle.decrypt_aes_gcm(params, key, data, cx, result, can_gc),
3526 }
3527 }
3528}
3529
3530impl SignatureAlgorithm {
3531 fn name(&self) -> &str {
3532 match self {
3533 Self::Hmac => ALG_HMAC,
3534 }
3535 }
3536
3537 fn sign(
3538 &self,
3539 cx: JSContext,
3540 key: &CryptoKey,
3541 data: &[u8],
3542 can_gc: CanGc,
3543 ) -> Result<Vec<u8>, Error> {
3544 match self {
3545 Self::Hmac => sign_hmac(cx, key, data, can_gc).map(|s| s.as_ref().to_vec()),
3546 }
3547 }
3548
3549 fn verify(
3550 &self,
3551 cx: JSContext,
3552 key: &CryptoKey,
3553 data: &[u8],
3554 signature: &[u8],
3555 can_gc: CanGc,
3556 ) -> Result<bool, Error> {
3557 match self {
3558 Self::Hmac => verify_hmac(cx, key, data, signature, can_gc),
3559 }
3560 }
3561}
3562
3563impl KeyGenerationAlgorithm {
3564 fn generate_key(
3566 &self,
3567 subtle: &SubtleCrypto,
3568 usages: Vec<KeyUsage>,
3569 extractable: bool,
3570 can_gc: CanGc,
3571 ) -> Result<CryptoKeyOrCryptoKeyPair, Error> {
3572 let key_or_key_pair =
3573 match self {
3574 Self::Aes(params) => CryptoKeyOrCryptoKeyPair::CryptoKey(subtle.generate_key_aes(
3575 usages,
3576 params,
3577 extractable,
3578 can_gc,
3579 )?),
3580 Self::Hmac(params) => CryptoKeyOrCryptoKeyPair::CryptoKey(
3581 subtle.generate_key_hmac(usages, params, extractable, can_gc)?,
3582 ),
3583 };
3584
3585 Ok(key_or_key_pair)
3586 }
3587}
3588
3589fn sign_hmac(
3591 cx: JSContext,
3592 key: &CryptoKey,
3593 data: &[u8],
3594 can_gc: CanGc,
3595) -> Result<impl AsRef<[u8]>, Error> {
3596 rooted!(in(*cx) let mut algorithm_slot = ObjectValue(key.Algorithm(cx).as_ptr()));
3600 let params = value_from_js_object::<HmacKeyAlgorithm>(cx, algorithm_slot.handle(), can_gc)?;
3601
3602 let hash_algorithm = match params.hash.name.str() {
3603 ALG_SHA1 => hmac::HMAC_SHA1_FOR_LEGACY_USE_ONLY,
3604 ALG_SHA256 => hmac::HMAC_SHA256,
3605 ALG_SHA384 => hmac::HMAC_SHA384,
3606 ALG_SHA512 => hmac::HMAC_SHA512,
3607 _ => return Err(Error::NotSupported),
3608 };
3609
3610 let sign_key = hmac::Key::new(hash_algorithm, key.handle().as_bytes());
3611 let mac = hmac::sign(&sign_key, data);
3612
3613 Ok(mac)
3616}
3617
3618fn verify_hmac(
3620 cx: JSContext,
3621 key: &CryptoKey,
3622 data: &[u8],
3623 signature: &[u8],
3624 can_gc: CanGc,
3625) -> Result<bool, Error> {
3626 let mac = sign_hmac(cx, key, data, can_gc)?;
3630
3631 let is_valid = mac.as_ref() == signature;
3633 Ok(is_valid)
3634}
3635
3636impl KeyWrapAlgorithm {
3637 fn name(&self) -> &str {
3639 match self {
3640 Self::AesKw => ALG_AES_KW,
3641 Self::AesCbc(key_gen_params) => &key_gen_params.name,
3642 Self::AesCtr(key_gen_params) => &key_gen_params.name,
3643 Self::AesGcm(_) => ALG_AES_GCM,
3644 }
3645 }
3646}
3647
3648#[expect(unused)]
3649trait RsaOtherPrimesInfoExt {
3650 fn from_value(value: &serde_json::Value) -> Result<RsaOtherPrimesInfo, Error>;
3651}
3652
3653impl RsaOtherPrimesInfoExt for RsaOtherPrimesInfo {
3654 fn from_value(value: &serde_json::Value) -> Result<RsaOtherPrimesInfo, Error> {
3655 let serde_json::Value::Object(object) = value else {
3656 return Err(Error::Data);
3657 };
3658
3659 let mut rsa_other_primes_info: RsaOtherPrimesInfo = Default::default();
3660 for (key, value) in object {
3661 match key.as_str() {
3662 "r" => {
3663 rsa_other_primes_info.r =
3664 Some(DOMString::from(value.as_str().ok_or(Error::Data)?))
3665 },
3666 "d" => {
3667 rsa_other_primes_info.d =
3668 Some(DOMString::from(value.as_str().ok_or(Error::Data)?))
3669 },
3670 "t" => {
3671 rsa_other_primes_info.t =
3672 Some(DOMString::from(value.as_str().ok_or(Error::Data)?))
3673 },
3674 _ => {
3675 },
3678 }
3679 }
3680
3681 Ok(rsa_other_primes_info)
3682 }
3683}
3684
3685trait JsonWebKeyExt {
3686 fn parse(cx: JSContext, data: &[u8]) -> Result<JsonWebKey, Error>;
3687 fn stringify(&self, cx: JSContext) -> Result<DOMString, Error>;
3688 fn get_usages_from_key_ops(&self) -> Result<Vec<KeyUsage>, Error>;
3689 #[expect(unused)]
3690 fn get_rsa_other_primes_info_from_oth(&self) -> Result<&[RsaOtherPrimesInfo], Error>;
3691 fn check_key_ops(&self, specified_usages: &[KeyUsage]) -> Result<(), Error>;
3692}
3693
3694impl JsonWebKeyExt for JsonWebKey {
3695 #[allow(unsafe_code)]
3697 fn parse(cx: JSContext, data: &[u8]) -> Result<JsonWebKey, Error> {
3698 let json = String::from_utf8_lossy(data);
3703
3704 let json: Vec<_> = json.encode_utf16().collect();
3706
3707 rooted!(in(*cx) let mut result = UndefinedValue());
3711 unsafe {
3712 if !JS_ParseJSON(*cx, json.as_ptr(), json.len() as u32, result.handle_mut()) {
3713 return Err(Error::JSFailed);
3714 }
3715 }
3716
3717 let key = match JsonWebKey::new(cx, result.handle(), CanGc::note()) {
3719 Ok(ConversionResult::Success(key)) => key,
3720 Ok(ConversionResult::Failure(error)) => {
3721 return Err(Error::Type(error.to_string()));
3722 },
3723 Err(()) => {
3724 return Err(Error::JSFailed);
3725 },
3726 };
3727
3728 if key.kty.is_none() {
3730 return Err(Error::Data);
3731 }
3732
3733 Ok(key)
3735 }
3736
3737 fn stringify(&self, cx: JSContext) -> Result<DOMString, Error> {
3743 rooted!(in(*cx) let mut data = UndefinedValue());
3744 self.safe_to_jsval(cx, data.handle_mut());
3745 serialize_jsval_to_json_utf8(cx, data.handle())
3746 }
3747
3748 fn get_usages_from_key_ops(&self) -> Result<Vec<KeyUsage>, Error> {
3749 let mut usages = vec![];
3750 for op in self.key_ops.as_ref().ok_or(Error::Data)? {
3751 usages.push(KeyUsage::from_str(op).map_err(|_| Error::Data)?);
3752 }
3753 Ok(usages)
3754 }
3755
3756 fn get_rsa_other_primes_info_from_oth(&self) -> Result<&[RsaOtherPrimesInfo], Error> {
3757 self.oth.as_deref().ok_or(Error::Data)
3758 }
3759
3760 fn check_key_ops(&self, specified_usages: &[KeyUsage]) -> Result<(), Error> {
3764 if let Some(ref key_ops) = self.key_ops {
3766 if key_ops
3769 .iter()
3770 .collect::<std::collections::HashSet<_>>()
3771 .len() <
3772 key_ops.len()
3773 {
3774 return Err(Error::Data);
3775 }
3776 if let Some(ref use_) = self.use_ {
3779 if key_ops.iter().any(|op| op != use_) {
3780 return Err(Error::Data);
3781 }
3782 }
3783
3784 let key_ops_as_usages = self.get_usages_from_key_ops()?;
3786 if !specified_usages
3787 .iter()
3788 .all(|specified_usage| key_ops_as_usages.contains(specified_usage))
3789 {
3790 return Err(Error::Data);
3791 }
3792 }
3793
3794 Ok(())
3795 }
3796}