1use std::num::NonZero;
6use std::ptr;
7use std::rc::Rc;
8
9use aes::cipher::block_padding::Pkcs7;
10use aes::cipher::generic_array::GenericArray;
11use aes::cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit, StreamCipher};
12use aes::{Aes128, Aes192, Aes256};
13use aes_gcm::{AeadInPlace, AesGcm, KeyInit};
14use aes_kw::{KekAes128, KekAes192, KekAes256};
15use aws_lc_rs::{digest, hkdf, hmac, pbkdf2};
16use base64::prelude::*;
17use cipher::consts::{U12, U16, U32};
18use dom_struct::dom_struct;
19use js::conversions::ConversionResult;
20use js::jsapi::{JS_NewObject, JSObject};
21use js::jsval::ObjectValue;
22use js::rust::MutableHandleObject;
23use js::typedarray::ArrayBufferU8;
24use servo_rand::{RngCore, ServoRng};
25
26use crate::dom::bindings::buffer_source::create_buffer_source;
27use crate::dom::bindings::cell::DomRefCell;
28use crate::dom::bindings::codegen::Bindings::CryptoKeyBinding::{
29 CryptoKeyMethods, KeyType, KeyUsage,
30};
31use crate::dom::bindings::codegen::Bindings::SubtleCryptoBinding::{
32 AesCbcParams, AesCtrParams, AesDerivedKeyParams, AesGcmParams, AesKeyAlgorithm,
33 AesKeyGenParams, Algorithm, AlgorithmIdentifier, HkdfParams, HmacImportParams,
34 HmacKeyAlgorithm, HmacKeyGenParams, JsonWebKey, KeyAlgorithm, KeyFormat, Pbkdf2Params,
35 SubtleCryptoMethods,
36};
37use crate::dom::bindings::codegen::UnionTypes::{
38 ArrayBufferViewOrArrayBuffer, ArrayBufferViewOrArrayBufferOrJsonWebKey,
39};
40use crate::dom::bindings::error::{Error, Fallible};
41use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
42use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
43use crate::dom::bindings::root::DomRoot;
44use crate::dom::bindings::str::DOMString;
45use crate::dom::bindings::trace::RootedTraceableBox;
46use crate::dom::cryptokey::{CryptoKey, Handle};
47use crate::dom::globalscope::GlobalScope;
48use crate::dom::promise::Promise;
49use crate::realms::InRealm;
50use crate::script_runtime::{CanGc, JSContext};
51
52const ALG_AES_CBC: &str = "AES-CBC";
54const ALG_AES_CTR: &str = "AES-CTR";
55const ALG_AES_GCM: &str = "AES-GCM";
56const ALG_AES_KW: &str = "AES-KW";
57const ALG_SHA1: &str = "SHA-1";
58const ALG_SHA256: &str = "SHA-256";
59const ALG_SHA384: &str = "SHA-384";
60const ALG_SHA512: &str = "SHA-512";
61const ALG_HMAC: &str = "HMAC";
62const ALG_HKDF: &str = "HKDF";
63const ALG_PBKDF2: &str = "PBKDF2";
64const ALG_RSASSA_PKCS1: &str = "RSASSA-PKCS1-v1_5";
65const ALG_RSA_OAEP: &str = "RSA-OAEP";
66const ALG_RSA_PSS: &str = "RSA-PSS";
67const ALG_ECDH: &str = "ECDH";
68const ALG_ECDSA: &str = "ECDSA";
69
70#[allow(dead_code)]
71static SUPPORTED_ALGORITHMS: &[&str] = &[
72 ALG_AES_CBC,
73 ALG_AES_CTR,
74 ALG_AES_GCM,
75 ALG_AES_KW,
76 ALG_SHA1,
77 ALG_SHA256,
78 ALG_SHA384,
79 ALG_SHA512,
80 ALG_HMAC,
81 ALG_HKDF,
82 ALG_PBKDF2,
83 ALG_RSASSA_PKCS1,
84 ALG_RSA_OAEP,
85 ALG_RSA_PSS,
86 ALG_ECDH,
87 ALG_ECDSA,
88];
89
90const NAMED_CURVE_P256: &str = "P-256";
91const NAMED_CURVE_P384: &str = "P-384";
92const NAMED_CURVE_P521: &str = "P-521";
93#[allow(dead_code)]
94static SUPPORTED_CURVES: &[&str] = &[NAMED_CURVE_P256, NAMED_CURVE_P384, NAMED_CURVE_P521];
95
96type Aes128CbcEnc = cbc::Encryptor<Aes128>;
97type Aes128CbcDec = cbc::Decryptor<Aes128>;
98type Aes192CbcEnc = cbc::Encryptor<Aes192>;
99type Aes192CbcDec = cbc::Decryptor<Aes192>;
100type Aes256CbcEnc = cbc::Encryptor<Aes256>;
101type Aes256CbcDec = cbc::Decryptor<Aes256>;
102type Aes128Ctr = ctr::Ctr64BE<Aes128>;
103type Aes192Ctr = ctr::Ctr64BE<Aes192>;
104type Aes256Ctr = ctr::Ctr64BE<Aes256>;
105
106type Aes128Gcm96Iv = AesGcm<Aes128, U12>;
107type Aes128Gcm128Iv = AesGcm<Aes128, U16>;
108type Aes192Gcm96Iv = AesGcm<Aes192, U12>;
109type Aes256Gcm96Iv = AesGcm<Aes256, U12>;
110type Aes128Gcm256Iv = AesGcm<Aes128, U32>;
111type Aes192Gcm256Iv = AesGcm<Aes192, U32>;
112type Aes256Gcm256Iv = AesGcm<Aes256, U32>;
113
114#[dom_struct]
115pub(crate) struct SubtleCrypto {
116 reflector_: Reflector,
117 #[no_trace]
118 rng: DomRefCell<ServoRng>,
119}
120
121impl SubtleCrypto {
122 fn new_inherited() -> SubtleCrypto {
123 SubtleCrypto {
124 reflector_: Reflector::new(),
125 rng: DomRefCell::new(ServoRng::default()),
126 }
127 }
128
129 pub(crate) fn new(global: &GlobalScope, can_gc: CanGc) -> DomRoot<SubtleCrypto> {
130 reflect_dom_object(Box::new(SubtleCrypto::new_inherited()), global, can_gc)
131 }
132}
133
134impl SubtleCryptoMethods<crate::DomTypeHolder> for SubtleCrypto {
135 fn Encrypt(
137 &self,
138 cx: JSContext,
139 algorithm: AlgorithmIdentifier,
140 key: &CryptoKey,
141 data: ArrayBufferViewOrArrayBuffer,
142 comp: InRealm,
143 can_gc: CanGc,
144 ) -> Rc<Promise> {
145 let promise = Promise::new_in_current_realm(comp, can_gc);
146 let normalized_algorithm = match normalize_algorithm_for_encrypt_or_decrypt(cx, &algorithm)
147 {
148 Ok(algorithm) => algorithm,
149 Err(e) => {
150 promise.reject_error(e, can_gc);
151 return promise;
152 },
153 };
154 let data = match data {
155 ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
156 ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
157 };
158
159 let this = Trusted::new(self);
160 let trusted_promise = TrustedPromise::new(promise.clone());
161 let trusted_key = Trusted::new(key);
162 let key_alg = key.algorithm();
163 let valid_usage = key.usages().contains(&KeyUsage::Encrypt);
164 self.global()
165 .task_manager()
166 .dom_manipulation_task_source()
167 .queue(task!(encrypt: move || {
168 let subtle = this.root();
169 let promise = trusted_promise.root();
170 let key = trusted_key.root();
171
172 if !valid_usage || normalized_algorithm.name() != key_alg {
173 promise.reject_error(Error::InvalidAccess, CanGc::note());
174 return;
175 }
176
177 let cx = GlobalScope::get_cx();
178 rooted!(in(*cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>());
179
180 if let Err(e) = normalized_algorithm.encrypt(
181 &subtle,
182 &key,
183 &data,
184 cx,
185 array_buffer_ptr.handle_mut(),
186 CanGc::note(),
187 ) {
188 promise.reject_error(e, CanGc::note());
189 return;
190 }
191 promise.resolve_native(&*array_buffer_ptr.handle(), CanGc::note());
192 }));
193 promise
194 }
195
196 fn Decrypt(
198 &self,
199 cx: JSContext,
200 algorithm: AlgorithmIdentifier,
201 key: &CryptoKey,
202 data: ArrayBufferViewOrArrayBuffer,
203 comp: InRealm,
204 can_gc: CanGc,
205 ) -> Rc<Promise> {
206 let promise = Promise::new_in_current_realm(comp, can_gc);
207 let normalized_algorithm = match normalize_algorithm_for_encrypt_or_decrypt(cx, &algorithm)
208 {
209 Ok(algorithm) => algorithm,
210 Err(e) => {
211 promise.reject_error(e, can_gc);
212 return promise;
213 },
214 };
215 let data = match data {
216 ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
217 ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
218 };
219
220 let this = Trusted::new(self);
221 let trusted_promise = TrustedPromise::new(promise.clone());
222 let trusted_key = Trusted::new(key);
223 let key_alg = key.algorithm();
224 let valid_usage = key.usages().contains(&KeyUsage::Decrypt);
225 self.global()
226 .task_manager()
227 .dom_manipulation_task_source()
228 .queue(task!(decrypt: move || {
229 let subtle = this.root();
230 let promise = trusted_promise.root();
231 let key = trusted_key.root();
232 let cx = GlobalScope::get_cx();
233 rooted!(in(*cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>());
234
235 if !valid_usage || normalized_algorithm.name() != key_alg {
236 promise.reject_error(Error::InvalidAccess, CanGc::note());
237 return;
238 }
239
240 if let Err(e) = normalized_algorithm.decrypt(
241 &subtle,
242 &key,
243 &data,
244 cx,
245 array_buffer_ptr.handle_mut(),
246 CanGc::note(),
247 ) {
248 promise.reject_error(e, CanGc::note());
249 return;
250 }
251
252 promise.resolve_native(&*array_buffer_ptr.handle(), CanGc::note());
253 }));
254 promise
255 }
256
257 fn Sign(
259 &self,
260 cx: JSContext,
261 algorithm: AlgorithmIdentifier,
262 key: &CryptoKey,
263 data: ArrayBufferViewOrArrayBuffer,
264 comp: InRealm,
265 can_gc: CanGc,
266 ) -> Rc<Promise> {
267 let data = match &data {
272 ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
273 ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
274 };
275
276 let promise = Promise::new_in_current_realm(comp, can_gc);
279 let normalized_algorithm = match normalize_algorithm_for_sign_or_verify(cx, &algorithm) {
280 Ok(algorithm) => algorithm,
281 Err(e) => {
282 promise.reject_error(e, can_gc);
284 return promise;
285 },
286 };
287
288 let trusted_promise = TrustedPromise::new(promise.clone());
293 let trusted_key = Trusted::new(key);
294
295 self.global()
296 .task_manager()
297 .dom_manipulation_task_source()
298 .queue(task!(sign: move || {
299 let promise = trusted_promise.root();
302 let key = trusted_key.root();
303
304 if normalized_algorithm.name() != key.algorithm() {
307 promise.reject_error(Error::InvalidAccess, CanGc::note());
308 return;
309 }
310
311 if !key.usages().contains(&KeyUsage::Sign) {
314 promise.reject_error(Error::InvalidAccess, CanGc::note());
315 return;
316 }
317
318 let cx = GlobalScope::get_cx();
321 let result = match normalized_algorithm.sign(cx, &key, &data) {
322 Ok(signature) => signature,
323 Err(e) => {
324 promise.reject_error(e, CanGc::note());
325 return;
326 }
327 };
328
329 rooted!(in(*cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>());
330 create_buffer_source::<ArrayBufferU8>(cx, &result, array_buffer_ptr.handle_mut(), CanGc::note())
331 .expect("failed to create buffer source for exported key.");
332
333 promise.resolve_native(&*array_buffer_ptr, CanGc::note());
335 }));
336
337 promise
338 }
339
340 fn Verify(
342 &self,
343 cx: JSContext,
344 algorithm: AlgorithmIdentifier,
345 key: &CryptoKey,
346 signature: ArrayBufferViewOrArrayBuffer,
347 data: ArrayBufferViewOrArrayBuffer,
348 comp: InRealm,
349 can_gc: CanGc,
350 ) -> Rc<Promise> {
351 let signature = match &signature {
357 ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
358 ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
359 };
360
361 let data = match &data {
364 ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
365 ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
366 };
367
368 let promise = Promise::new_in_current_realm(comp, can_gc);
371 let normalized_algorithm = match normalize_algorithm_for_sign_or_verify(cx, &algorithm) {
372 Ok(algorithm) => algorithm,
373 Err(e) => {
374 promise.reject_error(e, can_gc);
376 return promise;
377 },
378 };
379
380 let trusted_promise = TrustedPromise::new(promise.clone());
385 let trusted_key = Trusted::new(key);
386
387 self.global()
388 .task_manager()
389 .dom_manipulation_task_source()
390 .queue(task!(sign: move || {
391 let promise = trusted_promise.root();
394 let key = trusted_key.root();
395
396 if normalized_algorithm.name() != key.algorithm() {
399 promise.reject_error(Error::InvalidAccess, CanGc::note());
400 return;
401 }
402
403 if !key.usages().contains(&KeyUsage::Verify) {
406 promise.reject_error(Error::InvalidAccess, CanGc::note());
407 return;
408 }
409
410 let cx = GlobalScope::get_cx();
413 let result = match normalized_algorithm.verify(cx, &key, &data, &signature) {
414 Ok(result) => result,
415 Err(e) => {
416 promise.reject_error(e, CanGc::note());
417 return;
418 }
419 };
420
421 promise.resolve_native(&result, CanGc::note());
423 }));
424
425 promise
426 }
427
428 fn Digest(
430 &self,
431 cx: JSContext,
432 algorithm: AlgorithmIdentifier,
433 data: ArrayBufferViewOrArrayBuffer,
434 comp: InRealm,
435 can_gc: CanGc,
436 ) -> Rc<Promise> {
437 let data = match data {
442 ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
443 ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
444 };
445
446 let promise = Promise::new_in_current_realm(comp, can_gc);
449 let normalized_algorithm = match normalize_algorithm_for_digest(cx, &algorithm) {
450 Ok(normalized_algorithm) => normalized_algorithm,
451 Err(e) => {
452 promise.reject_error(e, can_gc);
454 return promise;
455 },
456 };
457
458 let trusted_promise = TrustedPromise::new(promise.clone());
463
464 self.global().task_manager().dom_manipulation_task_source().queue(
465 task!(generate_key: move || {
466 let promise = trusted_promise.root();
469
470 let digest = match normalized_algorithm.digest(&data) {
473 Ok(digest) => digest,
474 Err(e) => {
475 promise.reject_error(e, CanGc::note());
476 return;
477 }
478 };
479
480 let cx = GlobalScope::get_cx();
481 rooted!(in(*cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>());
482 create_buffer_source::<ArrayBufferU8>(cx, digest.as_ref(), array_buffer_ptr.handle_mut(), CanGc::note())
483 .expect("failed to create buffer source for exported key.");
484
485
486 promise.resolve_native(&*array_buffer_ptr, CanGc::note());
488 })
489 );
490
491 promise
492 }
493
494 fn GenerateKey(
496 &self,
497 cx: JSContext,
498 algorithm: AlgorithmIdentifier,
499 extractable: bool,
500 key_usages: Vec<KeyUsage>,
501 comp: InRealm,
502 can_gc: CanGc,
503 ) -> Rc<Promise> {
504 let promise = Promise::new_in_current_realm(comp, can_gc);
505 let normalized_algorithm = match normalize_algorithm_for_generate_key(cx, &algorithm) {
506 Ok(algorithm) => algorithm,
507 Err(e) => {
508 promise.reject_error(e, can_gc);
509 return promise;
510 },
511 };
512
513 let this = Trusted::new(self);
514 let trusted_promise = TrustedPromise::new(promise.clone());
515 self.global()
516 .task_manager()
517 .dom_manipulation_task_source()
518 .queue(task!(generate_key: move || {
519 let subtle = this.root();
520 let promise = trusted_promise.root();
521 let key = normalized_algorithm.generate_key(&subtle, key_usages, extractable, CanGc::note());
522
523 match key {
524 Ok(key) => promise.resolve_native(&key, CanGc::note()),
525 Err(e) => promise.reject_error(e, CanGc::note()),
526 }
527 }));
528
529 promise
530 }
531
532 fn DeriveKey(
534 &self,
535 cx: JSContext,
536 algorithm: AlgorithmIdentifier,
537 base_key: &CryptoKey,
538 derived_key_type: AlgorithmIdentifier,
539 extractable: bool,
540 key_usages: Vec<KeyUsage>,
541 comp: InRealm,
542 can_gc: CanGc,
543 ) -> Rc<Promise> {
544 let promise = Promise::new_in_current_realm(comp, can_gc);
550 let normalized_algorithm = match normalize_algorithm_for_derive_bits(cx, &algorithm) {
551 Ok(algorithm) => algorithm,
552 Err(e) => {
553 promise.reject_error(e, can_gc);
555 return promise;
556 },
557 };
558
559 let normalized_derived_key_algorithm_import =
562 match normalize_algorithm_for_import_key(cx, &derived_key_type) {
563 Ok(algorithm) => algorithm,
564 Err(e) => {
565 promise.reject_error(e, can_gc);
567 return promise;
568 },
569 };
570
571 let normalized_derived_key_algorithm_length =
574 match normalize_algorithm_for_get_key_length(cx, &derived_key_type) {
575 Ok(algorithm) => algorithm,
576 Err(e) => {
577 promise.reject_error(e, can_gc);
579 return promise;
580 },
581 };
582
583 let trusted_promise = TrustedPromise::new(promise.clone());
588 let trusted_base_key = Trusted::new(base_key);
589 let this = Trusted::new(self);
590 self.global().task_manager().dom_manipulation_task_source().queue(
591 task!(derive_key: move || {
592 let promise = trusted_promise.root();
598 let base_key = trusted_base_key.root();
599 let subtle = this.root();
600
601 if !base_key.usages().contains(&KeyUsage::DeriveKey) {
604 promise.reject_error(Error::InvalidAccess, CanGc::note());
605 return;
606 }
607
608 let length = match normalized_derived_key_algorithm_length.get_key_length() {
611 Ok(length) => length,
612 Err(e) => {
613 promise.reject_error(e, CanGc::note());
614 return;
615 }
616 };
617
618 let secret = match normalized_algorithm.derive_bits(&base_key, Some(length)){
621 Ok(secret) => secret,
622 Err(e) => {
623 promise.reject_error(e, CanGc::note());
624 return;
625 }
626 };
627
628 let result = normalized_derived_key_algorithm_import.import_key(
632 &subtle,
633 KeyFormat::Raw,
634 &secret,
635 extractable,
636 key_usages,
637 CanGc::note()
638 );
639 let result = match result {
640 Ok(key) => key,
641 Err(e) => {
642 promise.reject_error(e, CanGc::note());
643 return;
644 }
645 };
646
647 if matches!(result.Type(), KeyType::Secret | KeyType::Private) && result.usages().is_empty() {
650 promise.reject_error(Error::Syntax, CanGc::note());
651 return;
652 }
653
654 promise.resolve_native(&*result, CanGc::note());
656 }),
657 );
658
659 promise
660 }
661
662 fn DeriveBits(
664 &self,
665 cx: JSContext,
666 algorithm: AlgorithmIdentifier,
667 base_key: &CryptoKey,
668 length: Option<u32>,
669 comp: InRealm,
670 can_gc: CanGc,
671 ) -> Rc<Promise> {
672 let promise = Promise::new_in_current_realm(comp, can_gc);
678 let normalized_algorithm = match normalize_algorithm_for_derive_bits(cx, &algorithm) {
679 Ok(algorithm) => algorithm,
680 Err(e) => {
681 promise.reject_error(e, can_gc);
683 return promise;
684 },
685 };
686
687 let trusted_promise = TrustedPromise::new(promise.clone());
692 let trusted_base_key = Trusted::new(base_key);
693
694 self.global()
695 .task_manager()
696 .dom_manipulation_task_source()
697 .queue(task!(import_key: move || {
698 let promise = trusted_promise.root();
704 let base_key = trusted_base_key.root();
705
706 if !base_key.usages().contains(&KeyUsage::DeriveBits) {
709 promise.reject_error(Error::InvalidAccess, CanGc::note());
710 return;
711 }
712
713 let cx = GlobalScope::get_cx();
716 rooted!(in(*cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>());
717 let result = match normalized_algorithm.derive_bits(&base_key, length) {
718 Ok(derived_bits) => derived_bits,
719 Err(e) => {
720 promise.reject_error(e, CanGc::note());
721 return;
722 }
723 };
724
725 create_buffer_source::<ArrayBufferU8>(cx, &result, array_buffer_ptr.handle_mut(), CanGc::note())
726 .expect("failed to create buffer source for derived bits.");
727
728 promise.resolve_native(&*array_buffer_ptr, CanGc::note());
730 }));
731
732 promise
733 }
734
735 fn ImportKey(
737 &self,
738 cx: JSContext,
739 format: KeyFormat,
740 key_data: ArrayBufferViewOrArrayBufferOrJsonWebKey,
741 algorithm: AlgorithmIdentifier,
742 extractable: bool,
743 key_usages: Vec<KeyUsage>,
744 comp: InRealm,
745 can_gc: CanGc,
746 ) -> Rc<Promise> {
747 let promise = Promise::new_in_current_realm(comp, can_gc);
748 let normalized_algorithm = match normalize_algorithm_for_import_key(cx, &algorithm) {
749 Ok(algorithm) => algorithm,
750 Err(e) => {
751 promise.reject_error(e, can_gc);
752 return promise;
753 },
754 };
755
756 let data = match key_data {
757 ArrayBufferViewOrArrayBufferOrJsonWebKey::ArrayBufferView(view) => view.to_vec(),
758 ArrayBufferViewOrArrayBufferOrJsonWebKey::JsonWebKey(json_web_key) => {
759 let data_string = match json_web_key.k {
760 Some(s) => s.to_string(),
761 None => {
762 promise.reject_error(Error::Syntax, can_gc);
763 return promise;
764 },
765 };
766
767 match base64::engine::general_purpose::STANDARD_NO_PAD
768 .decode(data_string.as_bytes())
769 {
770 Ok(data) => data,
771 Err(_) => {
772 promise.reject_error(Error::Syntax, can_gc);
773 return promise;
774 },
775 }
776 },
777 ArrayBufferViewOrArrayBufferOrJsonWebKey::ArrayBuffer(array_buffer) => {
778 array_buffer.to_vec()
779 },
780 };
781
782 let this = Trusted::new(self);
783 let trusted_promise = TrustedPromise::new(promise.clone());
784 self.global()
785 .task_manager()
786 .dom_manipulation_task_source()
787 .queue(task!(import_key: move || {
788 let subtle = this.root();
789 let promise = trusted_promise.root();
790 let imported_key = normalized_algorithm.import_key(&subtle,
791 format, &data, extractable, key_usages, CanGc::note());
792 match imported_key {
793 Ok(k) => promise.resolve_native(&k, CanGc::note()),
794 Err(e) => promise.reject_error(e, CanGc::note()),
795 };
796 }));
797
798 promise
799 }
800
801 fn ExportKey(
803 &self,
804 format: KeyFormat,
805 key: &CryptoKey,
806 comp: InRealm,
807 can_gc: CanGc,
808 ) -> Rc<Promise> {
809 let promise = Promise::new_in_current_realm(comp, can_gc);
810
811 let this = Trusted::new(self);
812 let trusted_key = Trusted::new(key);
813 let trusted_promise = TrustedPromise::new(promise.clone());
814 self.global().task_manager().dom_manipulation_task_source().queue(
815 task!(export_key: move || {
816 let subtle = this.root();
817 let promise = trusted_promise.root();
818 let key = trusted_key.root();
819 let alg_name = key.algorithm();
820 if matches!(
821 alg_name.as_str(), ALG_SHA1 | ALG_SHA256 | ALG_SHA384 | ALG_SHA512 | ALG_HKDF | ALG_PBKDF2
822 ) {
823 promise.reject_error(Error::NotSupported, CanGc::note());
824 return;
825 }
826 if !key.Extractable() {
827 promise.reject_error(Error::InvalidAccess, CanGc::note());
828 return;
829 }
830 let exported_key = match alg_name.as_str() {
831 ALG_AES_CBC | ALG_AES_CTR | ALG_AES_KW | ALG_AES_GCM => subtle.export_key_aes(format, &key),
832 _ => Err(Error::NotSupported),
833 };
834 match exported_key {
835 Ok(k) => {
836 match k {
837 AesExportedKey::Raw(k) => {
838 let cx = GlobalScope::get_cx();
839 rooted!(in(*cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>());
840 create_buffer_source::<ArrayBufferU8>(cx, &k, array_buffer_ptr.handle_mut(),
841 CanGc::note())
842 .expect("failed to create buffer source for exported key.");
843 promise.resolve_native(&array_buffer_ptr.get(), CanGc::note())
844 },
845 AesExportedKey::Jwk(k) => {
846 promise.resolve_native(&k, CanGc::note())
847 },
848 }
849 },
850 Err(e) => promise.reject_error(e, CanGc::note()),
851 }
852 }),
853 );
854
855 promise
856 }
857
858 fn WrapKey(
860 &self,
861 cx: JSContext,
862 format: KeyFormat,
863 key: &CryptoKey,
864 wrapping_key: &CryptoKey,
865 wrap_algorithm: AlgorithmIdentifier,
866 comp: InRealm,
867 can_gc: CanGc,
868 ) -> Rc<Promise> {
869 let promise = Promise::new_in_current_realm(comp, can_gc);
870 let normalized_algorithm = match normalize_algorithm_for_key_wrap(cx, &wrap_algorithm) {
871 Ok(algorithm) => algorithm,
872 Err(e) => {
873 promise.reject_error(e, can_gc);
874 return promise;
875 },
876 };
877
878 let this = Trusted::new(self);
879 let trusted_key = Trusted::new(key);
880 let trusted_wrapping_key = Trusted::new(wrapping_key);
881 let trusted_promise = TrustedPromise::new(promise.clone());
882 self.global().task_manager().dom_manipulation_task_source().queue(
883 task!(wrap_key: move || {
884 let subtle = this.root();
885 let promise = trusted_promise.root();
886 let key = trusted_key.root();
887 let wrapping_key = trusted_wrapping_key.root();
888 let alg_name = key.algorithm();
889 let wrapping_alg_name = wrapping_key.algorithm();
890 let valid_wrap_usage = wrapping_key.usages().contains(&KeyUsage::WrapKey);
891 let names_match = normalized_algorithm.name() == wrapping_alg_name.as_str();
892
893 if !valid_wrap_usage || !names_match || !key.Extractable() {
894 promise.reject_error(Error::InvalidAccess, CanGc::note());
895 return;
896 }
897
898 if matches!(
899 alg_name.as_str(), ALG_SHA1 | ALG_SHA256 | ALG_SHA384 | ALG_SHA512 | ALG_HKDF | ALG_PBKDF2
900 ) {
901 promise.reject_error(Error::NotSupported, CanGc::note());
902 return;
903 }
904
905 let exported_key = match subtle.export_key_aes(format, &key) {
906 Ok(k) => k,
907 Err(e) => {
908 promise.reject_error(e, CanGc::note());
909 return;
910 },
911 };
912
913 let bytes = match exported_key {
914 AesExportedKey::Raw(k) => k,
915 AesExportedKey::Jwk(key) => {
916 let Some(k) = key.k else {
921 promise.reject_error(Error::Syntax, CanGc::note());
922 return;
923 };
924 let Some(alg) = key.alg else {
925 promise.reject_error(Error::Syntax, CanGc::note());
926 return;
927 };
928 let Some(ext) = key.ext else {
929 promise.reject_error(Error::Syntax, CanGc::note());
930 return;
931 };
932 let Some(key_ops) = key.key_ops else {
933 promise.reject_error(Error::Syntax, CanGc::note());
934 return;
935 };
936 let key_ops_str = key_ops.iter().map(|op| op.to_string()).collect::<Vec<String>>();
937 format!("{{
938 \"kty\": \"oct\",
939 \"k\": \"{}\",
940 \"alg\": \"{}\",
941 \"ext\": {},
942 \"key_ops\": {:?}
943 }}", k, alg, ext, key_ops_str)
944 .into_bytes()
945 },
946 };
947
948 let cx = GlobalScope::get_cx();
949 rooted!(in(*cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>());
950
951 let result = match normalized_algorithm {
952 KeyWrapAlgorithm::AesKw => {
953 subtle.wrap_key_aes_kw(&wrapping_key, &bytes, cx, array_buffer_ptr.handle_mut(), CanGc::note())
954 },
955 KeyWrapAlgorithm::AesCbc(params) => {
956 subtle.encrypt_aes_cbc(¶ms, &wrapping_key, &bytes, cx, array_buffer_ptr.handle_mut(),
957 CanGc::note())
958 },
959 KeyWrapAlgorithm::AesCtr(params) => {
960 subtle.encrypt_decrypt_aes_ctr(
961 ¶ms, &wrapping_key, &bytes, cx, array_buffer_ptr.handle_mut(), CanGc::note()
962 )
963 },
964 KeyWrapAlgorithm::AesGcm(params) => {
965 subtle.encrypt_aes_gcm(
966 ¶ms, &wrapping_key, &bytes, cx, array_buffer_ptr.handle_mut(), CanGc::note()
967 )
968 },
969 };
970
971 match result {
972 Ok(_) => promise.resolve_native(&*array_buffer_ptr, CanGc::note()),
973 Err(e) => promise.reject_error(e, CanGc::note()),
974 }
975 }),
976 );
977
978 promise
979 }
980
981 fn UnwrapKey(
983 &self,
984 cx: JSContext,
985 format: KeyFormat,
986 wrapped_key: ArrayBufferViewOrArrayBuffer,
987 unwrapping_key: &CryptoKey,
988 unwrap_algorithm: AlgorithmIdentifier,
989 unwrapped_key_algorithm: AlgorithmIdentifier,
990 extractable: bool,
991 key_usages: Vec<KeyUsage>,
992 comp: InRealm,
993 can_gc: CanGc,
994 ) -> Rc<Promise> {
995 let promise = Promise::new_in_current_realm(comp, can_gc);
996 let wrapped_key_bytes = match wrapped_key {
997 ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
998 ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
999 };
1000 let normalized_algorithm = match normalize_algorithm_for_key_wrap(cx, &unwrap_algorithm) {
1001 Ok(algorithm) => algorithm,
1002 Err(e) => {
1003 promise.reject_error(e, can_gc);
1004 return promise;
1005 },
1006 };
1007 let normalized_key_algorithm =
1008 match normalize_algorithm_for_import_key(cx, &unwrapped_key_algorithm) {
1009 Ok(algorithm) => algorithm,
1010 Err(e) => {
1011 promise.reject_error(e, can_gc);
1012 return promise;
1013 },
1014 };
1015
1016 let this = Trusted::new(self);
1017 let trusted_key = Trusted::new(unwrapping_key);
1018 let trusted_promise = TrustedPromise::new(promise.clone());
1019 self.global().task_manager().dom_manipulation_task_source().queue(
1020 task!(unwrap_key: move || {
1021 let subtle = this.root();
1022 let promise = trusted_promise.root();
1023 let unwrapping_key = trusted_key.root();
1024 let alg_name = unwrapping_key.algorithm();
1025 let valid_usage = unwrapping_key.usages().contains(&KeyUsage::UnwrapKey);
1026
1027 if !valid_usage || normalized_algorithm.name() != alg_name.as_str() {
1028 promise.reject_error(Error::InvalidAccess, CanGc::note());
1029 return;
1030 }
1031
1032 let cx = GlobalScope::get_cx();
1033 rooted!(in(*cx) let mut array_buffer_ptr = ptr::null_mut::<JSObject>());
1034
1035 let result = match normalized_algorithm {
1036 KeyWrapAlgorithm::AesKw => {
1037 subtle.unwrap_key_aes_kw(&unwrapping_key, &wrapped_key_bytes, cx, array_buffer_ptr.handle_mut(),
1038 CanGc::note())
1039 },
1040 KeyWrapAlgorithm::AesCbc(params) => {
1041 subtle.decrypt_aes_cbc(
1042 ¶ms, &unwrapping_key, &wrapped_key_bytes, cx, array_buffer_ptr.handle_mut(),
1043 CanGc::note()
1044 )
1045 },
1046 KeyWrapAlgorithm::AesCtr(params) => {
1047 subtle.encrypt_decrypt_aes_ctr(
1048 ¶ms, &unwrapping_key, &wrapped_key_bytes, cx, array_buffer_ptr.handle_mut(),
1049 CanGc::note()
1050 )
1051 },
1052 KeyWrapAlgorithm::AesGcm(params) => {
1053 subtle.decrypt_aes_gcm(
1054 ¶ms, &unwrapping_key, &wrapped_key_bytes, cx, array_buffer_ptr.handle_mut(),
1055 CanGc::note()
1056 )
1057 },
1058 };
1059
1060 let bytes = match result {
1061 Ok(bytes) => bytes,
1062 Err(e) => {
1063 promise.reject_error(e, CanGc::note());
1064 return;
1065 },
1066 };
1067
1068 let import_key_bytes = match format {
1069 KeyFormat::Raw | KeyFormat::Spki | KeyFormat::Pkcs8 => bytes,
1070 KeyFormat::Jwk => {
1071 match parse_jwk(&bytes, normalized_key_algorithm.clone(), extractable, &key_usages) {
1072 Ok(bytes) => bytes,
1073 Err(e) => {
1074 promise.reject_error(e, CanGc::note());
1075 return;
1076 }
1077 }
1078 },
1079 };
1080 match normalized_key_algorithm.import_key(&subtle, format, &import_key_bytes,
1081 extractable, key_usages, CanGc::note()) {
1082 Ok(imported_key) => promise.resolve_native(&imported_key, CanGc::note()),
1083 Err(e) => promise.reject_error(e, CanGc::note()),
1084 }
1085 }),
1086 );
1087
1088 promise
1089 }
1090}
1091
1092#[allow(dead_code)]
1096#[derive(Clone, Debug)]
1097pub(crate) struct SubtleAlgorithm {
1098 #[allow(dead_code)]
1099 pub(crate) name: String,
1100}
1101
1102impl From<DOMString> for SubtleAlgorithm {
1103 fn from(name: DOMString) -> Self {
1104 SubtleAlgorithm {
1105 name: name.to_string(),
1106 }
1107 }
1108}
1109
1110#[derive(Clone, Debug)]
1111pub(crate) struct SubtleAesCbcParams {
1112 #[allow(dead_code)]
1113 pub(crate) name: String,
1114 pub(crate) iv: Vec<u8>,
1115}
1116
1117impl From<RootedTraceableBox<AesCbcParams>> for SubtleAesCbcParams {
1118 fn from(params: RootedTraceableBox<AesCbcParams>) -> Self {
1119 let iv = match ¶ms.iv {
1120 ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
1121 ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
1122 };
1123 SubtleAesCbcParams {
1124 name: params.parent.name.to_string(),
1125 iv,
1126 }
1127 }
1128}
1129
1130#[derive(Clone, Debug)]
1131pub(crate) struct SubtleAesCtrParams {
1132 pub(crate) name: String,
1133 pub(crate) counter: Vec<u8>,
1134 pub(crate) length: u8,
1135}
1136
1137impl From<RootedTraceableBox<AesCtrParams>> for SubtleAesCtrParams {
1138 fn from(params: RootedTraceableBox<AesCtrParams>) -> Self {
1139 let counter = match ¶ms.counter {
1140 ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
1141 ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
1142 };
1143 SubtleAesCtrParams {
1144 name: params.parent.name.to_string(),
1145 counter,
1146 length: params.length,
1147 }
1148 }
1149}
1150
1151#[derive(Clone, Debug)]
1152pub(crate) struct SubtleAesGcmParams {
1153 pub(crate) name: String,
1154 pub(crate) iv: Vec<u8>,
1155 pub(crate) additional_data: Option<Vec<u8>>,
1156 pub(crate) tag_length: Option<u8>,
1157}
1158
1159impl From<RootedTraceableBox<AesGcmParams>> for SubtleAesGcmParams {
1160 fn from(params: RootedTraceableBox<AesGcmParams>) -> Self {
1161 let iv = match ¶ms.iv {
1162 ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
1163 ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
1164 };
1165 let additional_data = params.additionalData.as_ref().map(|data| match data {
1166 ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
1167 ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
1168 });
1169
1170 SubtleAesGcmParams {
1171 name: params.parent.name.to_string(),
1172 iv,
1173 additional_data,
1174 tag_length: params.tagLength,
1175 }
1176 }
1177}
1178
1179#[derive(Clone, Debug)]
1180pub(crate) struct SubtleAesKeyGenParams {
1181 pub(crate) name: String,
1182 pub(crate) length: u16,
1183}
1184
1185impl From<AesKeyGenParams> for SubtleAesKeyGenParams {
1186 fn from(params: AesKeyGenParams) -> Self {
1187 SubtleAesKeyGenParams {
1188 name: params.parent.name.to_string().to_uppercase(),
1189 length: params.length,
1190 }
1191 }
1192}
1193
1194#[derive(Clone)]
1196struct SubtleHmacImportParams {
1197 hash: DigestAlgorithm,
1199
1200 length: Option<u32>,
1202}
1203
1204impl SubtleHmacImportParams {
1205 fn new(cx: JSContext, params: RootedTraceableBox<HmacImportParams>) -> Fallible<Self> {
1206 let hash = normalize_algorithm_for_digest(cx, ¶ms.hash)?;
1207 let params = Self {
1208 hash,
1209 length: params.length,
1210 };
1211 Ok(params)
1212 }
1213
1214 fn get_key_length(&self) -> Result<u32, Error> {
1216 let length = match self.length {
1218 None => {
1220 match self.hash {
1223 DigestAlgorithm::Sha1 => 160,
1224 DigestAlgorithm::Sha256 => 256,
1225 DigestAlgorithm::Sha384 => 384,
1226 DigestAlgorithm::Sha512 => 512,
1227 }
1228 },
1229 Some(length) if length != 0 => {
1231 length
1233 },
1234 _ => {
1236 return Err(Error::Type("[[length]] must not be zero".to_string()));
1238 },
1239 };
1240
1241 Ok(length)
1243 }
1244}
1245
1246struct SubtleHmacKeyGenParams {
1247 hash: DigestAlgorithm,
1249
1250 length: Option<u32>,
1252}
1253
1254impl SubtleHmacKeyGenParams {
1255 fn new(cx: JSContext, params: RootedTraceableBox<HmacKeyGenParams>) -> Fallible<Self> {
1256 let hash = normalize_algorithm_for_digest(cx, ¶ms.hash)?;
1257 let params = Self {
1258 hash,
1259 length: params.length,
1260 };
1261 Ok(params)
1262 }
1263}
1264#[derive(Clone, Debug)]
1266pub(crate) struct SubtleHkdfParams {
1267 hash: DigestAlgorithm,
1269
1270 salt: Vec<u8>,
1272
1273 info: Vec<u8>,
1275}
1276
1277impl SubtleHkdfParams {
1278 fn new(cx: JSContext, params: RootedTraceableBox<HkdfParams>) -> Fallible<Self> {
1279 let hash = normalize_algorithm_for_digest(cx, ¶ms.hash)?;
1280 let salt = match ¶ms.salt {
1281 ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
1282 ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
1283 };
1284 let info = match ¶ms.info {
1285 ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
1286 ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
1287 };
1288
1289 let params = Self { hash, salt, info };
1290
1291 Ok(params)
1292 }
1293}
1294
1295#[derive(Clone, Debug)]
1297pub(crate) struct SubtlePbkdf2Params {
1298 salt: Vec<u8>,
1300
1301 iterations: u32,
1303
1304 hash: DigestAlgorithm,
1306}
1307
1308impl SubtlePbkdf2Params {
1309 fn new(cx: JSContext, params: RootedTraceableBox<Pbkdf2Params>) -> Fallible<Self> {
1310 let salt = match ¶ms.salt {
1311 ArrayBufferViewOrArrayBuffer::ArrayBufferView(view) => view.to_vec(),
1312 ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(),
1313 };
1314
1315 let params = Self {
1316 salt,
1317 iterations: params.iterations,
1318 hash: normalize_algorithm_for_digest(cx, ¶ms.hash)?,
1319 };
1320
1321 Ok(params)
1322 }
1323}
1324
1325enum GetKeyLengthAlgorithm {
1326 Aes(u16),
1327 Hmac(SubtleHmacImportParams),
1328}
1329
1330#[derive(Clone, Copy, Debug)]
1331enum DigestAlgorithm {
1332 Sha1,
1334
1335 Sha256,
1337
1338 Sha384,
1340
1341 Sha512,
1343}
1344
1345#[derive(Clone)]
1349enum ImportKeyAlgorithm {
1350 AesCbc,
1351 AesCtr,
1352 AesKw,
1353 AesGcm,
1354 Hmac(SubtleHmacImportParams),
1355 Pbkdf2,
1356 Hkdf,
1357}
1358
1359enum DeriveBitsAlgorithm {
1363 Pbkdf2(SubtlePbkdf2Params),
1364 Hkdf(SubtleHkdfParams),
1365}
1366
1367#[allow(clippy::enum_variant_names)]
1371enum EncryptionAlgorithm {
1372 AesCbc(SubtleAesCbcParams),
1373 AesCtr(SubtleAesCtrParams),
1374 AesGcm(SubtleAesGcmParams),
1375}
1376
1377enum SignatureAlgorithm {
1381 Hmac,
1382}
1383
1384enum KeyGenerationAlgorithm {
1388 Aes(SubtleAesKeyGenParams),
1389 Hmac(SubtleHmacKeyGenParams),
1390}
1391
1392#[allow(clippy::enum_variant_names)]
1396enum KeyWrapAlgorithm {
1397 AesKw,
1398 AesCbc(SubtleAesCbcParams),
1399 AesCtr(SubtleAesCtrParams),
1400 AesGcm(SubtleAesGcmParams),
1401}
1402
1403macro_rules! value_from_js_object {
1404 ($t: ty, $cx: ident, $value: ident) => {{
1405 let params_result = <$t>::new($cx, $value.handle()).map_err(|_| Error::JSFailed)?;
1406 let ConversionResult::Success(params) = params_result else {
1407 return Err(Error::Syntax);
1408 };
1409 params
1410 }};
1411}
1412
1413fn normalize_algorithm_for_get_key_length(
1415 cx: JSContext,
1416 algorithm: &AlgorithmIdentifier,
1417) -> Result<GetKeyLengthAlgorithm, Error> {
1418 match algorithm {
1419 AlgorithmIdentifier::Object(obj) => {
1420 rooted!(in(*cx) let value = ObjectValue(obj.get()));
1421 let algorithm = value_from_js_object!(Algorithm, cx, value);
1422
1423 let name = algorithm.name.str();
1424 let normalized_algorithm = if name.eq_ignore_ascii_case(ALG_AES_CBC) ||
1425 name.eq_ignore_ascii_case(ALG_AES_CTR) ||
1426 name.eq_ignore_ascii_case(ALG_AES_GCM)
1427 {
1428 let params = value_from_js_object!(AesDerivedKeyParams, cx, value);
1429 GetKeyLengthAlgorithm::Aes(params.length)
1430 } else if name.eq_ignore_ascii_case(ALG_HMAC) {
1431 let params = value_from_js_object!(HmacImportParams, cx, value);
1432 let subtle_params = SubtleHmacImportParams::new(cx, params)?;
1433 return Ok(GetKeyLengthAlgorithm::Hmac(subtle_params));
1434 } else {
1435 return Err(Error::NotSupported);
1436 };
1437
1438 Ok(normalized_algorithm)
1439 },
1440 AlgorithmIdentifier::String(_) => {
1441 Err(Error::NotSupported)
1443 },
1444 }
1445}
1446
1447fn normalize_algorithm_for_digest(
1449 cx: JSContext,
1450 algorithm: &AlgorithmIdentifier,
1451) -> Result<DigestAlgorithm, Error> {
1452 let name = match algorithm {
1453 AlgorithmIdentifier::Object(obj) => {
1454 rooted!(in(*cx) let value = ObjectValue(obj.get()));
1455 let algorithm = value_from_js_object!(Algorithm, cx, value);
1456
1457 algorithm.name.str().to_uppercase()
1458 },
1459 AlgorithmIdentifier::String(name) => name.str().to_uppercase(),
1460 };
1461
1462 let normalized_algorithm = match name.as_str() {
1463 ALG_SHA1 => DigestAlgorithm::Sha1,
1464 ALG_SHA256 => DigestAlgorithm::Sha256,
1465 ALG_SHA384 => DigestAlgorithm::Sha384,
1466 ALG_SHA512 => DigestAlgorithm::Sha512,
1467 _ => return Err(Error::NotSupported),
1468 };
1469
1470 Ok(normalized_algorithm)
1471}
1472
1473fn normalize_algorithm_for_import_key(
1475 cx: JSContext,
1476 algorithm: &AlgorithmIdentifier,
1477) -> Result<ImportKeyAlgorithm, Error> {
1478 let name = match algorithm {
1479 AlgorithmIdentifier::Object(obj) => {
1480 rooted!(in(*cx) let value = ObjectValue(obj.get()));
1481 let algorithm = value_from_js_object!(Algorithm, cx, value);
1482
1483 let name = algorithm.name.str().to_uppercase();
1484 if name == ALG_HMAC {
1485 let params = value_from_js_object!(HmacImportParams, cx, value);
1486 let subtle_params = SubtleHmacImportParams::new(cx, params)?;
1487 return Ok(ImportKeyAlgorithm::Hmac(subtle_params));
1488 }
1489
1490 name
1491 },
1492 AlgorithmIdentifier::String(name) => name.str().to_uppercase(),
1493 };
1494
1495 let normalized_algorithm = match name.as_str() {
1496 ALG_AES_CBC => ImportKeyAlgorithm::AesCbc,
1497 ALG_AES_CTR => ImportKeyAlgorithm::AesCtr,
1498 ALG_AES_KW => ImportKeyAlgorithm::AesKw,
1499 ALG_AES_GCM => ImportKeyAlgorithm::AesGcm,
1500 ALG_PBKDF2 => ImportKeyAlgorithm::Pbkdf2,
1501 ALG_HKDF => ImportKeyAlgorithm::Hkdf,
1502 _ => return Err(Error::NotSupported),
1503 };
1504
1505 Ok(normalized_algorithm)
1506}
1507
1508fn normalize_algorithm_for_derive_bits(
1510 cx: JSContext,
1511 algorithm: &AlgorithmIdentifier,
1512) -> Result<DeriveBitsAlgorithm, Error> {
1513 let AlgorithmIdentifier::Object(obj) = algorithm else {
1514 return Err(Error::NotSupported);
1516 };
1517
1518 rooted!(in(*cx) let value = ObjectValue(obj.get()));
1519 let algorithm = value_from_js_object!(Algorithm, cx, value);
1520
1521 let normalized_algorithm = if algorithm.name.str().eq_ignore_ascii_case(ALG_PBKDF2) {
1522 let params = value_from_js_object!(Pbkdf2Params, cx, value);
1523 let subtle_params = SubtlePbkdf2Params::new(cx, params)?;
1524 DeriveBitsAlgorithm::Pbkdf2(subtle_params)
1525 } else if algorithm.name.str().eq_ignore_ascii_case(ALG_HKDF) {
1526 let params = value_from_js_object!(HkdfParams, cx, value);
1527 let subtle_params = SubtleHkdfParams::new(cx, params)?;
1528 DeriveBitsAlgorithm::Hkdf(subtle_params)
1529 } else {
1530 return Err(Error::NotSupported);
1531 };
1532
1533 Ok(normalized_algorithm)
1534}
1535
1536fn normalize_algorithm_for_encrypt_or_decrypt(
1538 cx: JSContext,
1539 algorithm: &AlgorithmIdentifier,
1540) -> Result<EncryptionAlgorithm, Error> {
1541 let AlgorithmIdentifier::Object(obj) = algorithm else {
1542 return Err(Error::NotSupported);
1544 };
1545
1546 rooted!(in(*cx) let value = ObjectValue(obj.get()));
1547 let algorithm = value_from_js_object!(Algorithm, cx, value);
1548
1549 let name = algorithm.name.str();
1550 let normalized_algorithm = if name.eq_ignore_ascii_case(ALG_AES_CBC) {
1551 let params = value_from_js_object!(AesCbcParams, cx, value);
1552 EncryptionAlgorithm::AesCbc(params.into())
1553 } else if name.eq_ignore_ascii_case(ALG_AES_CTR) {
1554 let params = value_from_js_object!(AesCtrParams, cx, value);
1555 EncryptionAlgorithm::AesCtr(params.into())
1556 } else if name.eq_ignore_ascii_case(ALG_AES_GCM) {
1557 let params = value_from_js_object!(AesGcmParams, cx, value);
1558 EncryptionAlgorithm::AesGcm(params.into())
1559 } else {
1560 return Err(Error::NotSupported);
1561 };
1562
1563 Ok(normalized_algorithm)
1564}
1565
1566fn normalize_algorithm_for_sign_or_verify(
1569 cx: JSContext,
1570 algorithm: &AlgorithmIdentifier,
1571) -> Result<SignatureAlgorithm, Error> {
1572 let name = match algorithm {
1573 AlgorithmIdentifier::Object(obj) => {
1574 rooted!(in(*cx) let value = ObjectValue(obj.get()));
1575 let algorithm = value_from_js_object!(Algorithm, cx, value);
1576
1577 algorithm.name.str().to_uppercase()
1578 },
1579 AlgorithmIdentifier::String(name) => name.str().to_uppercase(),
1580 };
1581
1582 let normalized_algorithm = match name.as_str() {
1583 ALG_HMAC => SignatureAlgorithm::Hmac,
1584 _ => return Err(Error::NotSupported),
1585 };
1586
1587 Ok(normalized_algorithm)
1588}
1589
1590fn normalize_algorithm_for_generate_key(
1592 cx: JSContext,
1593 algorithm: &AlgorithmIdentifier,
1594) -> Result<KeyGenerationAlgorithm, Error> {
1595 let AlgorithmIdentifier::Object(obj) = algorithm else {
1596 return Err(Error::NotSupported);
1598 };
1599
1600 rooted!(in(*cx) let value = ObjectValue(obj.get()));
1601 let algorithm = value_from_js_object!(Algorithm, cx, value);
1602
1603 let name = algorithm.name.str();
1604 let normalized_algorithm = if name.eq_ignore_ascii_case(ALG_AES_CBC) ||
1605 name.eq_ignore_ascii_case(ALG_AES_CTR) ||
1606 name.eq_ignore_ascii_case(ALG_AES_KW) ||
1607 name.eq_ignore_ascii_case(ALG_AES_GCM)
1608 {
1609 let params = value_from_js_object!(AesKeyGenParams, cx, value);
1610 KeyGenerationAlgorithm::Aes(params.into())
1611 } else if name.eq_ignore_ascii_case(ALG_HMAC) {
1612 let params = value_from_js_object!(HmacKeyGenParams, cx, value);
1613 let subtle_params = SubtleHmacKeyGenParams::new(cx, params)?;
1614 KeyGenerationAlgorithm::Hmac(subtle_params)
1615 } else {
1616 return Err(Error::NotSupported);
1617 };
1618
1619 Ok(normalized_algorithm)
1620}
1621
1622fn normalize_algorithm_for_key_wrap(
1624 cx: JSContext,
1625 algorithm: &AlgorithmIdentifier,
1626) -> Result<KeyWrapAlgorithm, Error> {
1627 let name = match algorithm {
1628 AlgorithmIdentifier::Object(obj) => {
1629 rooted!(in(*cx) let value = ObjectValue(obj.get()));
1630 let algorithm = value_from_js_object!(Algorithm, cx, value);
1631
1632 algorithm.name.str().to_uppercase()
1633 },
1634 AlgorithmIdentifier::String(name) => name.str().to_uppercase(),
1635 };
1636
1637 let normalized_algorithm = match name.as_str() {
1638 ALG_AES_KW => KeyWrapAlgorithm::AesKw,
1639 ALG_AES_CBC => {
1640 let AlgorithmIdentifier::Object(obj) = algorithm else {
1641 return Err(Error::Syntax);
1642 };
1643 rooted!(in(*cx) let value = ObjectValue(obj.get()));
1644 KeyWrapAlgorithm::AesCbc(value_from_js_object!(AesCbcParams, cx, value).into())
1645 },
1646 ALG_AES_CTR => {
1647 let AlgorithmIdentifier::Object(obj) = algorithm else {
1648 return Err(Error::Syntax);
1649 };
1650 rooted!(in(*cx) let value = ObjectValue(obj.get()));
1651 KeyWrapAlgorithm::AesCtr(value_from_js_object!(AesCtrParams, cx, value).into())
1652 },
1653 ALG_AES_GCM => {
1654 let AlgorithmIdentifier::Object(obj) = algorithm else {
1655 return Err(Error::Syntax);
1656 };
1657 rooted!(in(*cx) let value = ObjectValue(obj.get()));
1658 KeyWrapAlgorithm::AesGcm(value_from_js_object!(AesGcmParams, cx, value).into())
1659 },
1660 _ => return Err(Error::NotSupported),
1661 };
1662
1663 Ok(normalized_algorithm)
1664}
1665
1666impl SubtleCrypto {
1667 fn encrypt_aes_cbc(
1669 &self,
1670 params: &SubtleAesCbcParams,
1671 key: &CryptoKey,
1672 data: &[u8],
1673 cx: JSContext,
1674 handle: MutableHandleObject,
1675 can_gc: CanGc,
1676 ) -> Result<Vec<u8>, Error> {
1677 if params.iv.len() != 16 {
1678 return Err(Error::Operation);
1679 }
1680
1681 let plaintext = Vec::from(data);
1682 let iv = GenericArray::from_slice(¶ms.iv);
1683
1684 let ct = match key.handle() {
1685 Handle::Aes128(data) => {
1686 let key_data = GenericArray::from_slice(data);
1687 Aes128CbcEnc::new(key_data, iv).encrypt_padded_vec_mut::<Pkcs7>(&plaintext)
1688 },
1689 Handle::Aes192(data) => {
1690 let key_data = GenericArray::from_slice(data);
1691 Aes192CbcEnc::new(key_data, iv).encrypt_padded_vec_mut::<Pkcs7>(&plaintext)
1692 },
1693 Handle::Aes256(data) => {
1694 let key_data = GenericArray::from_slice(data);
1695 Aes256CbcEnc::new(key_data, iv).encrypt_padded_vec_mut::<Pkcs7>(&plaintext)
1696 },
1697 _ => return Err(Error::Data),
1698 };
1699
1700 create_buffer_source::<ArrayBufferU8>(cx, &ct, handle, can_gc)
1701 .expect("failed to create buffer source for exported key.");
1702
1703 Ok(ct)
1704 }
1705
1706 fn decrypt_aes_cbc(
1708 &self,
1709 params: &SubtleAesCbcParams,
1710 key: &CryptoKey,
1711 data: &[u8],
1712 cx: JSContext,
1713 handle: MutableHandleObject,
1714 can_gc: CanGc,
1715 ) -> Result<Vec<u8>, Error> {
1716 if params.iv.len() != 16 {
1717 return Err(Error::Operation);
1718 }
1719
1720 let mut ciphertext = Vec::from(data);
1721 let iv = GenericArray::from_slice(¶ms.iv);
1722
1723 let plaintext = match key.handle() {
1724 Handle::Aes128(data) => {
1725 let key_data = GenericArray::from_slice(data);
1726 Aes128CbcDec::new(key_data, iv)
1727 .decrypt_padded_mut::<Pkcs7>(ciphertext.as_mut_slice())
1728 .map_err(|_| Error::Operation)?
1729 },
1730 Handle::Aes192(data) => {
1731 let key_data = GenericArray::from_slice(data);
1732 Aes192CbcDec::new(key_data, iv)
1733 .decrypt_padded_mut::<Pkcs7>(ciphertext.as_mut_slice())
1734 .map_err(|_| Error::Operation)?
1735 },
1736 Handle::Aes256(data) => {
1737 let key_data = GenericArray::from_slice(data);
1738 Aes256CbcDec::new(key_data, iv)
1739 .decrypt_padded_mut::<Pkcs7>(ciphertext.as_mut_slice())
1740 .map_err(|_| Error::Operation)?
1741 },
1742 _ => return Err(Error::Data),
1743 };
1744
1745 create_buffer_source::<ArrayBufferU8>(cx, plaintext, handle, can_gc)
1746 .expect("failed to create buffer source for exported key.");
1747
1748 Ok(plaintext.to_vec())
1749 }
1750
1751 fn encrypt_decrypt_aes_ctr(
1753 &self,
1754 params: &SubtleAesCtrParams,
1755 key: &CryptoKey,
1756 data: &[u8],
1757 cx: JSContext,
1758 handle: MutableHandleObject,
1759 can_gc: CanGc,
1760 ) -> Result<Vec<u8>, Error> {
1761 if params.counter.len() != 16 || params.length == 0 || params.length > 128 {
1762 return Err(Error::Operation);
1763 }
1764
1765 let mut ciphertext = Vec::from(data);
1766 let counter = GenericArray::from_slice(¶ms.counter);
1767
1768 match key.handle() {
1769 Handle::Aes128(data) => {
1770 let key_data = GenericArray::from_slice(data);
1771 Aes128Ctr::new(key_data, counter).apply_keystream(&mut ciphertext)
1772 },
1773 Handle::Aes192(data) => {
1774 let key_data = GenericArray::from_slice(data);
1775 Aes192Ctr::new(key_data, counter).apply_keystream(&mut ciphertext)
1776 },
1777 Handle::Aes256(data) => {
1778 let key_data = GenericArray::from_slice(data);
1779 Aes256Ctr::new(key_data, counter).apply_keystream(&mut ciphertext)
1780 },
1781 _ => return Err(Error::Data),
1782 };
1783
1784 create_buffer_source::<ArrayBufferU8>(cx, &ciphertext, handle, can_gc)
1785 .expect("failed to create buffer source for exported key.");
1786
1787 Ok(ciphertext)
1788 }
1789
1790 fn encrypt_aes_gcm(
1792 &self,
1793 params: &SubtleAesGcmParams,
1794 key: &CryptoKey,
1795 plaintext: &[u8],
1796 cx: JSContext,
1797 handle: MutableHandleObject,
1798 can_gc: CanGc,
1799 ) -> Result<Vec<u8>, Error> {
1800 if plaintext.len() as u64 > (2 << 39) - 256 {
1802 return Err(Error::Operation);
1803 }
1804
1805 if params
1812 .additional_data
1813 .as_ref()
1814 .is_some_and(|data| data.len() > u64::MAX as usize)
1815 {
1816 return Err(Error::Operation);
1817 }
1818
1819 let tag_length = match params.tag_length {
1821 None => {
1823 128
1825 },
1826 Some(length) if matches!(length, 32 | 64 | 96 | 104 | 112 | 120 | 128) => {
1828 length
1830 },
1831 _ => {
1833 return Err(Error::Operation);
1835 },
1836 };
1837
1838 let additional_data = params.additional_data.as_deref().unwrap_or_default();
1841
1842 let key_length = key.handle().as_bytes().len();
1847 let iv_length = params.iv.len();
1848 let mut ciphertext = plaintext.to_vec();
1849 let key_bytes = key.handle().as_bytes();
1850 let tag = match (key_length, iv_length) {
1851 (16, 12) => {
1852 let nonce = GenericArray::from_slice(¶ms.iv);
1853 <Aes128Gcm96Iv>::new_from_slice(key_bytes)
1854 .expect("key length did not match")
1855 .encrypt_in_place_detached(nonce, additional_data, &mut ciphertext)
1856 },
1857 (16, 16) => {
1858 let nonce = GenericArray::from_slice(¶ms.iv);
1859 <Aes128Gcm128Iv>::new_from_slice(key_bytes)
1860 .expect("key length did not match")
1861 .encrypt_in_place_detached(nonce, additional_data, &mut ciphertext)
1862 },
1863 (24, 12) => {
1864 let nonce = GenericArray::from_slice(¶ms.iv);
1865 <Aes192Gcm96Iv>::new_from_slice(key_bytes)
1866 .expect("key length did not match")
1867 .encrypt_in_place_detached(nonce, additional_data, &mut ciphertext)
1868 },
1869 (32, 12) => {
1870 let nonce = GenericArray::from_slice(¶ms.iv);
1871 <Aes256Gcm96Iv>::new_from_slice(key_bytes)
1872 .expect("key length did not match")
1873 .encrypt_in_place_detached(nonce, additional_data, &mut ciphertext)
1874 },
1875 (16, 32) => {
1876 let nonce = GenericArray::from_slice(¶ms.iv);
1877 <Aes128Gcm256Iv>::new_from_slice(key_bytes)
1878 .expect("key length did not match")
1879 .encrypt_in_place_detached(nonce, additional_data, &mut ciphertext)
1880 },
1881 (24, 32) => {
1882 let nonce = GenericArray::from_slice(¶ms.iv);
1883 <Aes192Gcm256Iv>::new_from_slice(key_bytes)
1884 .expect("key length did not match")
1885 .encrypt_in_place_detached(nonce, additional_data, &mut ciphertext)
1886 },
1887 (32, 32) => {
1888 let nonce = GenericArray::from_slice(¶ms.iv);
1889 <Aes256Gcm256Iv>::new_from_slice(key_bytes)
1890 .expect("key length did not match")
1891 .encrypt_in_place_detached(nonce, additional_data, &mut ciphertext)
1892 },
1893 _ => {
1894 log::warn!(
1895 "Missing AES-GCM encryption implementation with {key_length}-byte key and {iv_length}-byte IV"
1896 );
1897 return Err(Error::NotSupported);
1898 },
1899 };
1900
1901 ciphertext.extend_from_slice(&tag.unwrap()[..tag_length as usize / 8]);
1903
1904 create_buffer_source::<ArrayBufferU8>(cx, &ciphertext, handle, can_gc)
1906 .expect("failed to create buffer source for encrypted ciphertext");
1907
1908 Ok(ciphertext)
1909 }
1910
1911 fn decrypt_aes_gcm(
1913 &self,
1914 params: &SubtleAesGcmParams,
1915 key: &CryptoKey,
1916 ciphertext: &[u8],
1917 cx: JSContext,
1918 handle: MutableHandleObject,
1919 can_gc: CanGc,
1920 ) -> Result<Vec<u8>, Error> {
1921 let tag_length = match params.tag_length {
1924 None => {
1926 128
1928 },
1929 Some(length) if matches!(length, 32 | 64 | 96 | 104 | 112 | 120 | 128) => {
1931 length as usize
1933 },
1934 _ => {
1936 return Err(Error::Operation);
1938 },
1939 };
1940
1941 if ciphertext.len() < tag_length / 8 {
1943 return Err(Error::Operation);
1944 }
1945
1946 let additional_data = params.additional_data.as_deref().unwrap_or_default();
1961
1962 let mut plaintext = ciphertext.to_vec();
1967 let key_length = key.handle().as_bytes().len();
1968 let iv_length = params.iv.len();
1969 let key_bytes = key.handle().as_bytes();
1970 let result = match (key_length, iv_length) {
1971 (16, 12) => {
1972 let nonce = GenericArray::from_slice(¶ms.iv);
1973 <Aes128Gcm96Iv>::new_from_slice(key_bytes)
1974 .expect("key length did not match")
1975 .decrypt_in_place(nonce, additional_data, &mut plaintext)
1976 },
1977 (16, 16) => {
1978 let nonce = GenericArray::from_slice(¶ms.iv);
1979 <Aes128Gcm128Iv>::new_from_slice(key_bytes)
1980 .expect("key length did not match")
1981 .decrypt_in_place(nonce, additional_data, &mut plaintext)
1982 },
1983 (24, 12) => {
1984 let nonce = GenericArray::from_slice(¶ms.iv);
1985 <Aes192Gcm96Iv>::new_from_slice(key_bytes)
1986 .expect("key length did not match")
1987 .decrypt_in_place(nonce, additional_data, &mut plaintext)
1988 },
1989 (32, 12) => {
1990 let nonce = GenericArray::from_slice(¶ms.iv);
1991 <Aes256Gcm96Iv>::new_from_slice(key_bytes)
1992 .expect("key length did not match")
1993 .decrypt_in_place(nonce, additional_data, &mut plaintext)
1994 },
1995 (16, 32) => {
1996 let nonce = GenericArray::from_slice(¶ms.iv);
1997 <Aes128Gcm256Iv>::new_from_slice(key_bytes)
1998 .expect("key length did not match")
1999 .decrypt_in_place(nonce, additional_data, &mut plaintext)
2000 },
2001 (24, 32) => {
2002 let nonce = GenericArray::from_slice(¶ms.iv);
2003 <Aes192Gcm256Iv>::new_from_slice(key_bytes)
2004 .expect("key length did not match")
2005 .decrypt_in_place(nonce, additional_data, &mut plaintext)
2006 },
2007 (32, 32) => {
2008 let nonce = GenericArray::from_slice(¶ms.iv);
2009 <Aes256Gcm256Iv>::new_from_slice(key_bytes)
2010 .expect("key length did not match")
2011 .decrypt_in_place(nonce, additional_data, &mut plaintext)
2012 },
2013 _ => {
2014 log::warn!(
2015 "Missing AES-GCM decryption implementation with {key_length}-byte key and {iv_length}-byte IV"
2016 );
2017 return Err(Error::NotSupported);
2018 },
2019 };
2020
2021 if result.is_err() {
2023 return Err(Error::Operation);
2025 }
2026 create_buffer_source::<ArrayBufferU8>(cx, &plaintext, handle, can_gc)
2031 .expect("failed to create buffer source for decrypted plaintext");
2032
2033 Ok(plaintext)
2034 }
2035
2036 #[allow(unsafe_code)]
2040 fn generate_key_aes(
2041 &self,
2042 usages: Vec<KeyUsage>,
2043 key_gen_params: &SubtleAesKeyGenParams,
2044 extractable: bool,
2045 can_gc: CanGc,
2046 ) -> Result<DomRoot<CryptoKey>, Error> {
2047 let mut rand = vec![0; key_gen_params.length as usize / 8];
2048 self.rng.borrow_mut().fill_bytes(&mut rand);
2049 let handle = match key_gen_params.length {
2050 128 => Handle::Aes128(rand),
2051 192 => Handle::Aes192(rand),
2052 256 => Handle::Aes256(rand),
2053 _ => return Err(Error::Operation),
2054 };
2055
2056 match key_gen_params.name.as_str() {
2057 ALG_AES_CBC | ALG_AES_CTR | ALG_AES_GCM => {
2058 if usages.iter().any(|usage| {
2059 !matches!(
2060 usage,
2061 KeyUsage::Encrypt |
2062 KeyUsage::Decrypt |
2063 KeyUsage::WrapKey |
2064 KeyUsage::UnwrapKey
2065 )
2066 }) || usages.is_empty()
2067 {
2068 return Err(Error::Syntax);
2069 }
2070 },
2071 ALG_AES_KW => {
2072 if usages
2073 .iter()
2074 .any(|usage| !matches!(usage, KeyUsage::WrapKey | KeyUsage::UnwrapKey)) ||
2075 usages.is_empty()
2076 {
2077 return Err(Error::Syntax);
2078 }
2079 },
2080 _ => return Err(Error::NotSupported),
2081 }
2082
2083 let name = match key_gen_params.name.as_str() {
2084 ALG_AES_CBC => DOMString::from(ALG_AES_CBC),
2085 ALG_AES_CTR => DOMString::from(ALG_AES_CTR),
2086 ALG_AES_KW => DOMString::from(ALG_AES_KW),
2087 ALG_AES_GCM => DOMString::from(ALG_AES_GCM),
2088 _ => return Err(Error::NotSupported),
2089 };
2090
2091 let cx = GlobalScope::get_cx();
2092 rooted!(in(*cx) let mut algorithm_object = unsafe {JS_NewObject(*cx, ptr::null()) });
2093 assert!(!algorithm_object.is_null());
2094
2095 AesKeyAlgorithm::from_name_and_size(
2096 name.clone(),
2097 key_gen_params.length,
2098 algorithm_object.handle_mut(),
2099 cx,
2100 );
2101
2102 let crypto_key = CryptoKey::new(
2103 &self.global(),
2104 KeyType::Secret,
2105 extractable,
2106 name,
2107 algorithm_object.handle(),
2108 usages,
2109 handle,
2110 can_gc,
2111 );
2112
2113 Ok(crypto_key)
2114 }
2115
2116 #[allow(unsafe_code)]
2118 fn generate_key_hmac(
2119 &self,
2120 usages: Vec<KeyUsage>,
2121 params: &SubtleHmacKeyGenParams,
2122 extractable: bool,
2123 can_gc: CanGc,
2124 ) -> Result<DomRoot<CryptoKey>, Error> {
2125 if usages
2127 .iter()
2128 .any(|usage| !matches!(usage, KeyUsage::Sign | KeyUsage::Verify))
2129 {
2130 return Err(Error::Syntax);
2131 }
2132
2133 let length = match params.length {
2135 None => {
2137 params.hash.block_size_in_bits() as u32
2140 },
2141 Some(length) if length != 0 => {
2143 length
2145 },
2146 _ => {
2148 return Err(Error::Operation);
2150 },
2151 };
2152
2153 let mut key_data = vec![0; length as usize];
2155 self.rng.borrow_mut().fill_bytes(&mut key_data);
2156
2157 let name = DOMString::from(ALG_HMAC);
2171 let cx = GlobalScope::get_cx();
2172 rooted!(in(*cx) let mut algorithm_object = unsafe {JS_NewObject(*cx, ptr::null()) });
2173 assert!(!algorithm_object.is_null());
2174 HmacKeyAlgorithm::from_length_and_hash(
2175 length,
2176 params.hash,
2177 algorithm_object.handle_mut(),
2178 cx,
2179 );
2180
2181 let key = CryptoKey::new(
2182 &self.global(),
2183 KeyType::Secret,
2184 extractable,
2185 name,
2186 algorithm_object.handle(),
2187 usages,
2188 Handle::Hmac(key_data),
2189 can_gc,
2190 );
2191
2192 Ok(key)
2194 }
2195
2196 #[allow(unsafe_code)]
2199 fn import_key_aes(
2200 &self,
2201 format: KeyFormat,
2202 data: &[u8],
2203 extractable: bool,
2204 usages: Vec<KeyUsage>,
2205 alg_name: &str,
2206 can_gc: CanGc,
2207 ) -> Result<DomRoot<CryptoKey>, Error> {
2208 if usages.iter().any(|usage| {
2209 !matches!(
2210 usage,
2211 KeyUsage::Encrypt | KeyUsage::Decrypt | KeyUsage::WrapKey | KeyUsage::UnwrapKey
2212 )
2213 }) || usages.is_empty()
2214 {
2215 return Err(Error::Syntax);
2216 }
2217 if !matches!(format, KeyFormat::Raw | KeyFormat::Jwk) {
2218 return Err(Error::NotSupported);
2219 }
2220 let handle = match data.len() * 8 {
2221 128 => Handle::Aes128(data.to_vec()),
2222 192 => Handle::Aes192(data.to_vec()),
2223 256 => Handle::Aes256(data.to_vec()),
2224 _ => {
2225 return Err(Error::Data);
2226 },
2227 };
2228
2229 let name = DOMString::from(alg_name.to_string());
2230
2231 let cx = GlobalScope::get_cx();
2232 rooted!(in(*cx) let mut algorithm_object = unsafe { JS_NewObject(*cx, ptr::null()) });
2233 assert!(!algorithm_object.is_null());
2234
2235 AesKeyAlgorithm::from_name_and_size(
2236 name.clone(),
2237 (data.len() * 8) as u16,
2238 algorithm_object.handle_mut(),
2239 cx,
2240 );
2241 let crypto_key = CryptoKey::new(
2242 &self.global(),
2243 KeyType::Secret,
2244 extractable,
2245 name,
2246 algorithm_object.handle(),
2247 usages,
2248 handle,
2249 can_gc,
2250 );
2251
2252 Ok(crypto_key)
2253 }
2254
2255 fn export_key_aes(&self, format: KeyFormat, key: &CryptoKey) -> Result<AesExportedKey, Error> {
2258 match format {
2259 KeyFormat::Raw => match key.handle() {
2260 Handle::Aes128(key_data) => Ok(AesExportedKey::Raw(key_data.as_slice().to_vec())),
2261 Handle::Aes192(key_data) => Ok(AesExportedKey::Raw(key_data.as_slice().to_vec())),
2262 Handle::Aes256(key_data) => Ok(AesExportedKey::Raw(key_data.as_slice().to_vec())),
2263 _ => Err(Error::Data),
2264 },
2265 KeyFormat::Jwk => {
2266 let (alg, k) = match key.handle() {
2267 Handle::Aes128(key_data) => {
2268 data_to_jwk_params(key.algorithm().as_str(), "128", key_data.as_slice())
2269 },
2270 Handle::Aes192(key_data) => {
2271 data_to_jwk_params(key.algorithm().as_str(), "192", key_data.as_slice())
2272 },
2273 Handle::Aes256(key_data) => {
2274 data_to_jwk_params(key.algorithm().as_str(), "256", key_data.as_slice())
2275 },
2276 _ => return Err(Error::Data),
2277 };
2278 let key_ops = key
2279 .usages()
2280 .iter()
2281 .map(|usage| DOMString::from(usage.as_str()))
2282 .collect::<Vec<DOMString>>();
2283 let jwk = JsonWebKey {
2284 alg: Some(alg),
2285 crv: None,
2286 d: None,
2287 dp: None,
2288 dq: None,
2289 e: None,
2290 ext: Some(key.Extractable()),
2291 k: Some(k),
2292 key_ops: Some(key_ops),
2293 kty: Some(DOMString::from("oct")),
2294 n: None,
2295 oth: None,
2296 p: None,
2297 q: None,
2298 qi: None,
2299 use_: None,
2300 x: None,
2301 y: None,
2302 };
2303 Ok(AesExportedKey::Jwk(Box::new(jwk)))
2304 },
2305 _ => Err(Error::NotSupported),
2306 }
2307 }
2308
2309 #[allow(unsafe_code)]
2311 fn import_key_hkdf(
2312 &self,
2313 format: KeyFormat,
2314 data: &[u8],
2315 extractable: bool,
2316 usages: Vec<KeyUsage>,
2317 can_gc: CanGc,
2318 ) -> Result<DomRoot<CryptoKey>, Error> {
2319 if format == KeyFormat::Raw {
2322 if usages
2324 .iter()
2325 .any(|usage| !matches!(usage, KeyUsage::DeriveKey | KeyUsage::DeriveBits)) ||
2326 usages.is_empty()
2327 {
2328 return Err(Error::Syntax);
2329 }
2330
2331 if extractable {
2333 return Err(Error::Syntax);
2334 }
2335
2336 let name = DOMString::from(ALG_HKDF);
2342 let cx = GlobalScope::get_cx();
2343 rooted!(in(*cx) let mut algorithm_object = unsafe {JS_NewObject(*cx, ptr::null()) });
2344 assert!(!algorithm_object.is_null());
2345 KeyAlgorithm::from_name(name.clone(), algorithm_object.handle_mut(), cx);
2346
2347 let key = CryptoKey::new(
2348 &self.global(),
2349 KeyType::Secret,
2350 extractable,
2351 name,
2352 algorithm_object.handle(),
2353 usages,
2354 Handle::Hkdf(data.to_vec()),
2355 can_gc,
2356 );
2357
2358 Ok(key)
2360 } else {
2361 Err(Error::NotSupported)
2363 }
2364 }
2365
2366 #[allow(unsafe_code)]
2368 fn import_key_hmac(
2369 &self,
2370 normalized_algorithm: &SubtleHmacImportParams,
2371 format: KeyFormat,
2372 key_data: &[u8],
2373 extractable: bool,
2374 usages: Vec<KeyUsage>,
2375 can_gc: CanGc,
2376 ) -> Result<DomRoot<CryptoKey>, Error> {
2377 if usages
2381 .iter()
2382 .any(|usage| !matches!(usage, KeyUsage::Sign | KeyUsage::Verify)) ||
2383 usages.is_empty()
2384 {
2385 return Err(Error::Syntax);
2386 }
2387
2388 let hash;
2390
2391 let data;
2393 match format {
2394 KeyFormat::Raw | KeyFormat::Jwk => {
2397 data = key_data.to_vec();
2399
2400 hash = normalized_algorithm.hash;
2402 },
2403 _ => {
2405 return Err(Error::NotSupported);
2407 },
2408 }
2409
2410 let mut length = data.len() as u32 * 8;
2412
2413 if length == 0 {
2415 return Err(Error::Data);
2416 }
2417
2418 if let Some(given_length) = normalized_algorithm.length {
2420 if given_length > length {
2422 return Err(Error::Data);
2424 }
2425 else {
2427 length = given_length;
2429 }
2430 }
2431
2432 let truncated_data = data[..length as usize / 8].to_vec();
2440 let name = DOMString::from(ALG_HMAC);
2441 let cx = GlobalScope::get_cx();
2442 rooted!(in(*cx) let mut algorithm_object = unsafe { JS_NewObject(*cx, ptr::null()) });
2443 assert!(!algorithm_object.is_null());
2444 HmacKeyAlgorithm::from_length_and_hash(length, hash, algorithm_object.handle_mut(), cx);
2445
2446 let key = CryptoKey::new(
2447 &self.global(),
2448 KeyType::Secret,
2449 extractable,
2450 name,
2451 algorithm_object.handle(),
2452 usages,
2453 Handle::Hmac(truncated_data),
2454 can_gc,
2455 );
2456
2457 Ok(key)
2459 }
2460
2461 fn wrap_key_aes_kw(
2463 &self,
2464 wrapping_key: &CryptoKey,
2465 bytes: &[u8],
2466 cx: JSContext,
2467 handle: MutableHandleObject,
2468 can_gc: CanGc,
2469 ) -> Result<Vec<u8>, Error> {
2470 if bytes.len() % 8 != 0 {
2472 return Err(Error::Operation);
2473 }
2474
2475 let wrapped_key = match wrapping_key.handle() {
2479 Handle::Aes128(key_data) => {
2480 let key_array = GenericArray::from_slice(key_data.as_slice());
2481 let kek = KekAes128::new(key_array);
2482 match kek.wrap_vec(bytes) {
2483 Ok(key) => key,
2484 Err(_) => return Err(Error::Operation),
2485 }
2486 },
2487 Handle::Aes192(key_data) => {
2488 let key_array = GenericArray::from_slice(key_data.as_slice());
2489 let kek = KekAes192::new(key_array);
2490 match kek.wrap_vec(bytes) {
2491 Ok(key) => key,
2492 Err(_) => return Err(Error::Operation),
2493 }
2494 },
2495 Handle::Aes256(key_data) => {
2496 let key_array = GenericArray::from_slice(key_data.as_slice());
2497 let kek = KekAes256::new(key_array);
2498 match kek.wrap_vec(bytes) {
2499 Ok(key) => key,
2500 Err(_) => return Err(Error::Operation),
2501 }
2502 },
2503 _ => return Err(Error::Operation),
2504 };
2505
2506 create_buffer_source::<ArrayBufferU8>(cx, &wrapped_key, handle, can_gc)
2507 .expect("failed to create buffer source for wrapped key.");
2508
2509 Ok(wrapped_key)
2511 }
2512
2513 fn unwrap_key_aes_kw(
2515 &self,
2516 wrapping_key: &CryptoKey,
2517 bytes: &[u8],
2518 cx: JSContext,
2519 handle: MutableHandleObject,
2520 can_gc: CanGc,
2521 ) -> Result<Vec<u8>, Error> {
2522 let unwrapped_key = match wrapping_key.handle() {
2527 Handle::Aes128(key_data) => {
2528 let key_array = GenericArray::from_slice(key_data.as_slice());
2529 let kek = KekAes128::new(key_array);
2530 match kek.unwrap_vec(bytes) {
2531 Ok(key) => key,
2532 Err(_) => return Err(Error::Operation),
2533 }
2534 },
2535 Handle::Aes192(key_data) => {
2536 let key_array = GenericArray::from_slice(key_data.as_slice());
2537 let kek = KekAes192::new(key_array);
2538 match kek.unwrap_vec(bytes) {
2539 Ok(key) => key,
2540 Err(_) => return Err(Error::Operation),
2541 }
2542 },
2543 Handle::Aes256(key_data) => {
2544 let key_array = GenericArray::from_slice(key_data.as_slice());
2545 let kek = KekAes256::new(key_array);
2546 match kek.unwrap_vec(bytes) {
2547 Ok(key) => key,
2548 Err(_) => return Err(Error::Operation),
2549 }
2550 },
2551 _ => return Err(Error::Operation),
2552 };
2553
2554 create_buffer_source::<ArrayBufferU8>(cx, &unwrapped_key, handle, can_gc)
2555 .expect("failed to create buffer source for unwrapped key.");
2556
2557 Ok(unwrapped_key)
2559 }
2560
2561 #[allow(unsafe_code)]
2563 fn import_key_pbkdf2(
2564 &self,
2565 format: KeyFormat,
2566 data: &[u8],
2567 extractable: bool,
2568 usages: Vec<KeyUsage>,
2569 can_gc: CanGc,
2570 ) -> Result<DomRoot<CryptoKey>, Error> {
2571 if format != KeyFormat::Raw {
2573 return Err(Error::NotSupported);
2574 }
2575
2576 if usages
2578 .iter()
2579 .any(|usage| !matches!(usage, KeyUsage::DeriveKey | KeyUsage::DeriveBits)) ||
2580 usages.is_empty()
2581 {
2582 return Err(Error::Syntax);
2583 }
2584
2585 if extractable {
2587 return Err(Error::Syntax);
2588 }
2589
2590 let name = DOMString::from(ALG_PBKDF2);
2596 let cx = GlobalScope::get_cx();
2597 rooted!(in(*cx) let mut algorithm_object = unsafe {JS_NewObject(*cx, ptr::null()) });
2598 assert!(!algorithm_object.is_null());
2599 KeyAlgorithm::from_name(name.clone(), algorithm_object.handle_mut(), cx);
2600
2601 let key = CryptoKey::new(
2602 &self.global(),
2603 KeyType::Secret,
2604 extractable,
2605 name,
2606 algorithm_object.handle(),
2607 usages,
2608 Handle::Pbkdf2(data.to_vec()),
2609 can_gc,
2610 );
2611
2612 Ok(key)
2614 }
2615}
2616
2617pub(crate) enum AesExportedKey {
2618 Raw(Vec<u8>),
2619 Jwk(Box<JsonWebKey>),
2620}
2621
2622fn data_to_jwk_params(alg: &str, size: &str, key: &[u8]) -> (DOMString, DOMString) {
2623 let jwk_alg = match alg {
2624 ALG_AES_CBC => DOMString::from(format!("A{}CBC", size)),
2625 ALG_AES_CTR => DOMString::from(format!("A{}CTR", size)),
2626 ALG_AES_KW => DOMString::from(format!("A{}KW", size)),
2627 ALG_AES_GCM => DOMString::from(format!("A{}GCM", size)),
2628 _ => unreachable!(),
2629 };
2630 let data = base64::engine::general_purpose::STANDARD_NO_PAD.encode(key);
2631 (jwk_alg, DOMString::from(data))
2632}
2633
2634trait AlgorithmFromName {
2635 fn from_name(name: DOMString, out: MutableHandleObject, cx: JSContext);
2636}
2637
2638impl AlgorithmFromName for KeyAlgorithm {
2639 #[allow(unsafe_code)]
2642 fn from_name(name: DOMString, out: MutableHandleObject, cx: JSContext) {
2643 let key_algorithm = Self { name };
2644
2645 unsafe {
2646 key_algorithm.to_jsobject(*cx, out);
2647 }
2648 }
2649}
2650
2651trait AlgorithmFromLengthAndHash {
2652 fn from_length_and_hash(
2653 length: u32,
2654 hash: DigestAlgorithm,
2655 out: MutableHandleObject,
2656 cx: JSContext,
2657 );
2658}
2659
2660impl AlgorithmFromLengthAndHash for HmacKeyAlgorithm {
2661 #[allow(unsafe_code)]
2662 fn from_length_and_hash(
2663 length: u32,
2664 hash: DigestAlgorithm,
2665 out: MutableHandleObject,
2666 cx: JSContext,
2667 ) {
2668 let hmac_key_algorithm = Self {
2669 parent: KeyAlgorithm {
2670 name: ALG_HMAC.into(),
2671 },
2672 length,
2673 hash: KeyAlgorithm { name: hash.name() },
2674 };
2675
2676 unsafe {
2677 hmac_key_algorithm.to_jsobject(*cx, out);
2678 }
2679 }
2680}
2681
2682trait AlgorithmFromNameAndSize {
2683 fn from_name_and_size(name: DOMString, size: u16, out: MutableHandleObject, cx: JSContext);
2684}
2685
2686impl AlgorithmFromNameAndSize for AesKeyAlgorithm {
2687 #[allow(unsafe_code)]
2690 fn from_name_and_size(name: DOMString, size: u16, out: MutableHandleObject, cx: JSContext) {
2691 let key_algorithm = Self {
2692 parent: KeyAlgorithm { name },
2693 length: size,
2694 };
2695
2696 unsafe {
2697 key_algorithm.to_jsobject(*cx, out);
2698 }
2699 }
2700}
2701
2702impl SubtleHkdfParams {
2703 fn derive_bits(&self, key: &CryptoKey, length: Option<u32>) -> Result<Vec<u8>, Error> {
2705 let Some(length) = length else {
2707 return Err(Error::Operation);
2708 };
2709 if length == 0 || length % 8 != 0 {
2710 return Err(Error::Operation);
2711 };
2712
2713 let key_derivation_key = key.handle().as_bytes();
2715
2716 let mut result = vec![0; length as usize / 8];
2724 let algorithm = match self.hash {
2725 DigestAlgorithm::Sha1 => hkdf::HKDF_SHA1_FOR_LEGACY_USE_ONLY,
2726 DigestAlgorithm::Sha256 => hkdf::HKDF_SHA256,
2727 DigestAlgorithm::Sha384 => hkdf::HKDF_SHA384,
2728 DigestAlgorithm::Sha512 => hkdf::HKDF_SHA512,
2729 };
2730 let salt = hkdf::Salt::new(algorithm, &self.salt);
2731 let info = self.info.as_slice();
2732 let pseudo_random_key = salt.extract(key_derivation_key);
2733
2734 let Ok(output_key_material) =
2735 pseudo_random_key.expand(std::slice::from_ref(&info), algorithm)
2736 else {
2737 return Err(Error::Operation);
2739 };
2740
2741 if output_key_material.fill(&mut result).is_err() {
2742 return Err(Error::Operation);
2743 };
2744
2745 Ok(result)
2748 }
2749}
2750
2751impl SubtlePbkdf2Params {
2752 fn derive_bits(&self, key: &CryptoKey, length: Option<u32>) -> Result<Vec<u8>, Error> {
2754 let Some(length) = length else {
2756 return Err(Error::Operation);
2757 };
2758 if length == 0 || length % 8 != 0 {
2759 return Err(Error::Operation);
2760 };
2761
2762 let Ok(iterations) = NonZero::<u32>::try_from(self.iterations) else {
2764 return Err(Error::Operation);
2765 };
2766
2767 let prf = match self.hash {
2770 DigestAlgorithm::Sha1 => pbkdf2::PBKDF2_HMAC_SHA1,
2771 DigestAlgorithm::Sha256 => pbkdf2::PBKDF2_HMAC_SHA256,
2772 DigestAlgorithm::Sha384 => pbkdf2::PBKDF2_HMAC_SHA384,
2773 DigestAlgorithm::Sha512 => pbkdf2::PBKDF2_HMAC_SHA512,
2774 };
2775
2776 let mut result = vec![0; length as usize / 8];
2782 pbkdf2::derive(
2783 prf,
2784 iterations,
2785 &self.salt,
2786 key.handle().as_bytes(),
2787 &mut result,
2788 );
2789
2790 Ok(result)
2796 }
2797}
2798
2799fn get_key_length_for_aes(length: u16) -> Result<u32, Error> {
2801 if !matches!(length, 128 | 192 | 256) {
2804 return Err(Error::Operation);
2805 }
2806
2807 Ok(length as u32)
2809}
2810
2811impl GetKeyLengthAlgorithm {
2812 fn get_key_length(&self) -> Result<u32, Error> {
2813 match self {
2814 Self::Aes(length) => get_key_length_for_aes(*length),
2815 Self::Hmac(params) => params.get_key_length(),
2816 }
2817 }
2818}
2819
2820impl DigestAlgorithm {
2821 fn name(&self) -> DOMString {
2823 match self {
2824 Self::Sha1 => ALG_SHA1,
2825 Self::Sha256 => ALG_SHA256,
2826 Self::Sha384 => ALG_SHA384,
2827 Self::Sha512 => ALG_SHA512,
2828 }
2829 .into()
2830 }
2831
2832 fn digest(&self, data: &[u8]) -> Result<impl AsRef<[u8]>, Error> {
2833 let algorithm = match self {
2834 Self::Sha1 => &digest::SHA1_FOR_LEGACY_USE_ONLY,
2835 Self::Sha256 => &digest::SHA256,
2836 Self::Sha384 => &digest::SHA384,
2837 Self::Sha512 => &digest::SHA512,
2838 };
2839 Ok(digest::digest(algorithm, data))
2840 }
2841
2842 fn block_size_in_bits(&self) -> usize {
2843 match self {
2844 Self::Sha1 => 160,
2845 Self::Sha256 => 256,
2846 Self::Sha384 => 384,
2847 Self::Sha512 => 512,
2848 }
2849 }
2850}
2851
2852impl ImportKeyAlgorithm {
2853 fn import_key(
2854 &self,
2855 subtle: &SubtleCrypto,
2856 format: KeyFormat,
2857 secret: &[u8],
2858 extractable: bool,
2859 key_usages: Vec<KeyUsage>,
2860 can_gc: CanGc,
2861 ) -> Result<DomRoot<CryptoKey>, Error> {
2862 match self {
2863 Self::AesCbc => {
2864 subtle.import_key_aes(format, secret, extractable, key_usages, ALG_AES_CBC, can_gc)
2865 },
2866 Self::AesCtr => {
2867 subtle.import_key_aes(format, secret, extractable, key_usages, ALG_AES_CTR, can_gc)
2868 },
2869 Self::AesKw => {
2870 subtle.import_key_aes(format, secret, extractable, key_usages, ALG_AES_KW, can_gc)
2871 },
2872 Self::AesGcm => {
2873 subtle.import_key_aes(format, secret, extractable, key_usages, ALG_AES_GCM, can_gc)
2874 },
2875 Self::Hmac(params) => {
2876 subtle.import_key_hmac(params, format, secret, extractable, key_usages, can_gc)
2877 },
2878 Self::Pbkdf2 => {
2879 subtle.import_key_pbkdf2(format, secret, extractable, key_usages, can_gc)
2880 },
2881 Self::Hkdf => subtle.import_key_hkdf(format, secret, extractable, key_usages, can_gc),
2882 }
2883 }
2884}
2885
2886impl DeriveBitsAlgorithm {
2887 fn derive_bits(&self, key: &CryptoKey, length: Option<u32>) -> Result<Vec<u8>, Error> {
2888 match self {
2889 Self::Pbkdf2(pbkdf2_params) => pbkdf2_params.derive_bits(key, length),
2890 Self::Hkdf(hkdf_params) => hkdf_params.derive_bits(key, length),
2891 }
2892 }
2893}
2894
2895impl EncryptionAlgorithm {
2896 fn name(&self) -> &str {
2898 match self {
2899 Self::AesCbc(params) => ¶ms.name,
2900 Self::AesCtr(params) => ¶ms.name,
2901 Self::AesGcm(params) => ¶ms.name,
2902 }
2903 }
2904
2905 fn encrypt(
2907 &self,
2908 subtle: &SubtleCrypto,
2909 key: &CryptoKey,
2910 data: &[u8],
2911 cx: JSContext,
2912 result: MutableHandleObject,
2913 can_gc: CanGc,
2914 ) -> Result<Vec<u8>, Error> {
2915 match self {
2916 Self::AesCbc(params) => subtle.encrypt_aes_cbc(params, key, data, cx, result, can_gc),
2917 Self::AesCtr(params) => {
2918 subtle.encrypt_decrypt_aes_ctr(params, key, data, cx, result, can_gc)
2919 },
2920 Self::AesGcm(params) => subtle.encrypt_aes_gcm(params, key, data, cx, result, can_gc),
2921 }
2922 }
2923
2924 fn decrypt(
2926 &self,
2927 subtle: &SubtleCrypto,
2928 key: &CryptoKey,
2929 data: &[u8],
2930 cx: JSContext,
2931 result: MutableHandleObject,
2932 can_gc: CanGc,
2933 ) -> Result<Vec<u8>, Error> {
2934 match self {
2935 Self::AesCbc(params) => subtle.decrypt_aes_cbc(params, key, data, cx, result, can_gc),
2936 Self::AesCtr(params) => {
2937 subtle.encrypt_decrypt_aes_ctr(params, key, data, cx, result, can_gc)
2938 },
2939 Self::AesGcm(params) => subtle.decrypt_aes_gcm(params, key, data, cx, result, can_gc),
2940 }
2941 }
2942}
2943
2944impl SignatureAlgorithm {
2945 fn name(&self) -> &str {
2946 match self {
2947 Self::Hmac => ALG_HMAC,
2948 }
2949 }
2950
2951 fn sign(&self, cx: JSContext, key: &CryptoKey, data: &[u8]) -> Result<Vec<u8>, Error> {
2952 match self {
2953 Self::Hmac => sign_hmac(cx, key, data).map(|s| s.as_ref().to_vec()),
2954 }
2955 }
2956
2957 fn verify(
2958 &self,
2959 cx: JSContext,
2960 key: &CryptoKey,
2961 data: &[u8],
2962 signature: &[u8],
2963 ) -> Result<bool, Error> {
2964 match self {
2965 Self::Hmac => verify_hmac(cx, key, data, signature),
2966 }
2967 }
2968}
2969
2970impl KeyGenerationAlgorithm {
2971 fn generate_key(
2973 &self,
2974 subtle: &SubtleCrypto,
2975 usages: Vec<KeyUsage>,
2976 extractable: bool,
2977 can_gc: CanGc,
2978 ) -> Result<DomRoot<CryptoKey>, Error> {
2979 match self {
2980 Self::Aes(params) => subtle.generate_key_aes(usages, params, extractable, can_gc),
2981 Self::Hmac(params) => subtle.generate_key_hmac(usages, params, extractable, can_gc),
2982 }
2983 }
2984}
2985
2986fn sign_hmac(cx: JSContext, key: &CryptoKey, data: &[u8]) -> Result<impl AsRef<[u8]>, Error> {
2988 rooted!(in(*cx) let mut algorithm_slot = ObjectValue(key.Algorithm(cx).as_ptr()));
2992 let params = value_from_js_object!(HmacKeyAlgorithm, cx, algorithm_slot);
2993
2994 let hash_algorithm = match params.hash.name.str() {
2995 ALG_SHA1 => hmac::HMAC_SHA1_FOR_LEGACY_USE_ONLY,
2996 ALG_SHA256 => hmac::HMAC_SHA256,
2997 ALG_SHA384 => hmac::HMAC_SHA384,
2998 ALG_SHA512 => hmac::HMAC_SHA512,
2999 _ => return Err(Error::NotSupported),
3000 };
3001
3002 let sign_key = hmac::Key::new(hash_algorithm, key.handle().as_bytes());
3003 let mac = hmac::sign(&sign_key, data);
3004
3005 Ok(mac)
3008}
3009
3010fn verify_hmac(
3012 cx: JSContext,
3013 key: &CryptoKey,
3014 data: &[u8],
3015 signature: &[u8],
3016) -> Result<bool, Error> {
3017 let mac = sign_hmac(cx, key, data)?;
3021
3022 let is_valid = mac.as_ref() == signature;
3024 Ok(is_valid)
3025}
3026
3027impl KeyWrapAlgorithm {
3028 fn name(&self) -> &str {
3030 match self {
3031 Self::AesKw => ALG_AES_KW,
3032 Self::AesCbc(key_gen_params) => &key_gen_params.name,
3033 Self::AesCtr(key_gen_params) => &key_gen_params.name,
3034 Self::AesGcm(_) => ALG_AES_GCM,
3035 }
3036 }
3037}
3038
3039fn parse_jwk(
3041 bytes: &[u8],
3042 import_alg: ImportKeyAlgorithm,
3043 extractable: bool,
3044 key_usages: &[KeyUsage],
3045) -> Result<Vec<u8>, Error> {
3046 let value = serde_json::from_slice(bytes)
3047 .map_err(|_| Error::Type("Failed to parse JWK string".into()))?;
3048 let serde_json::Value::Object(obj) = value else {
3049 return Err(Error::Data);
3050 };
3051
3052 let kty = get_jwk_string(&obj, "kty")?;
3053 let ext = get_jwk_bool(&obj, "ext")?;
3054 if !ext && extractable {
3055 return Err(Error::Data);
3056 }
3057
3058 if let Some(serde_json::Value::Array(key_ops)) = obj.get("key_ops") {
3061 if key_ops.iter().any(|op| {
3062 let op_string = match op {
3063 serde_json::Value::String(op_string) => op_string,
3064 _ => return true,
3065 };
3066 let usage = match usage_from_str(op_string) {
3067 Ok(usage) => usage,
3068 Err(_) => {
3069 return true;
3070 },
3071 };
3072 !key_usages.contains(&usage)
3073 }) {
3074 return Err(Error::Data);
3075 }
3076 }
3077
3078 match import_alg {
3079 ImportKeyAlgorithm::AesCbc |
3080 ImportKeyAlgorithm::AesCtr |
3081 ImportKeyAlgorithm::AesKw |
3082 ImportKeyAlgorithm::AesGcm => {
3083 if kty != "oct" {
3084 return Err(Error::Data);
3085 }
3086 let k = get_jwk_string(&obj, "k")?;
3087 let alg = get_jwk_string(&obj, "alg")?;
3088
3089 let data = base64::engine::general_purpose::STANDARD_NO_PAD
3090 .decode(k.as_bytes())
3091 .map_err(|_| Error::Data)?;
3092
3093 let expected_alg = match (data.len() * 8, &import_alg) {
3094 (128, ImportKeyAlgorithm::AesCbc) => "A128CBC",
3095 (128, ImportKeyAlgorithm::AesCtr) => "A128CTR",
3096 (128, ImportKeyAlgorithm::AesKw) => "A128KW",
3097 (128, ImportKeyAlgorithm::AesGcm) => "A128GCM",
3098 (192, ImportKeyAlgorithm::AesCbc) => "A192CBC",
3099 (192, ImportKeyAlgorithm::AesCtr) => "A192CTR",
3100 (192, ImportKeyAlgorithm::AesKw) => "A192KW",
3101 (192, ImportKeyAlgorithm::AesGcm) => "A192GCM",
3102 (256, ImportKeyAlgorithm::AesCbc) => "A256CBC",
3103 (256, ImportKeyAlgorithm::AesCtr) => "A256CTR",
3104 (256, ImportKeyAlgorithm::AesKw) => "A256KW",
3105 (256, ImportKeyAlgorithm::AesGcm) => "A256GCM",
3106 _ => return Err(Error::Data),
3107 };
3108
3109 if alg != expected_alg {
3110 return Err(Error::Data);
3111 }
3112
3113 if let Some(serde_json::Value::String(use_)) = obj.get("use") {
3114 if use_ != "enc" {
3115 return Err(Error::Data);
3116 }
3117 }
3118
3119 Ok(data)
3120 },
3121 ImportKeyAlgorithm::Hmac(params) => {
3122 if kty != "oct" {
3123 return Err(Error::Data);
3124 }
3125 let k = get_jwk_string(&obj, "k")?;
3126 let alg = get_jwk_string(&obj, "alg")?;
3127
3128 let expected_alg = match params.hash {
3129 DigestAlgorithm::Sha1 => "HS1",
3130 DigestAlgorithm::Sha256 => "HS256",
3131 DigestAlgorithm::Sha384 => "HS384",
3132 DigestAlgorithm::Sha512 => "HS512",
3133 };
3134
3135 if alg != expected_alg {
3136 return Err(Error::Data);
3137 }
3138
3139 if let Some(serde_json::Value::String(use_)) = obj.get("use") {
3140 if use_ != "sign" {
3141 return Err(Error::Data);
3142 }
3143 }
3144
3145 base64::engine::general_purpose::STANDARD_NO_PAD
3146 .decode(k.as_bytes())
3147 .map_err(|_| Error::Data)
3148 },
3149 _ => Err(Error::NotSupported),
3150 }
3151}
3152
3153fn get_jwk_string(
3154 value: &serde_json::Map<String, serde_json::Value>,
3155 key: &str,
3156) -> Result<String, Error> {
3157 let s = value
3158 .get(key)
3159 .ok_or(Error::Data)?
3160 .as_str()
3161 .ok_or(Error::Data)?;
3162 Ok(s.to_string())
3163}
3164
3165fn get_jwk_bool(
3166 value: &serde_json::Map<String, serde_json::Value>,
3167 key: &str,
3168) -> Result<bool, Error> {
3169 let b = value
3170 .get(key)
3171 .ok_or(Error::Data)?
3172 .as_bool()
3173 .ok_or(Error::Data)?;
3174 Ok(b)
3175}
3176
3177fn usage_from_str(op: &str) -> Result<KeyUsage, Error> {
3178 let usage = match op {
3179 "encrypt" => KeyUsage::Encrypt,
3180 "decrypt" => KeyUsage::Decrypt,
3181 "sign" => KeyUsage::Sign,
3182 "verify" => KeyUsage::Verify,
3183 "deriveKey" => KeyUsage::DeriveKey,
3184 "deriveBits" => KeyUsage::DeriveBits,
3185 "wrapKey" => KeyUsage::WrapKey,
3186 "unwrapKey" => KeyUsage::UnwrapKey,
3187 _ => {
3188 return Err(Error::Data);
3189 },
3190 };
3191 Ok(usage)
3192}