1use std::cell::Cell;
6use std::ptr::NonNull;
7
8use dom_struct::dom_struct;
9use js::jsapi::{Heap, JSObject, Value};
10use malloc_size_of::MallocSizeOf;
11use script_bindings::conversions::SafeToJSValConvertible;
12
13use crate::dom::bindings::cell::DomRefCell;
14use crate::dom::bindings::codegen::Bindings::CryptoKeyBinding::{
15 CryptoKeyMethods, CryptoKeyPair, KeyType, KeyUsage,
16};
17use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
18use crate::dom::bindings::root::DomRoot;
19use crate::dom::globalscope::GlobalScope;
20use crate::dom::subtlecrypto::KeyAlgorithmAndDerivatives;
21use crate::script_runtime::{CanGc, JSContext};
22
23pub(crate) enum CryptoKeyOrCryptoKeyPair {
24 CryptoKey(DomRoot<CryptoKey>),
25 CryptoKeyPair(CryptoKeyPair),
26}
27
28pub(crate) enum Handle {
30 P256PrivateKey(p256::SecretKey),
31 P384PrivateKey(p384::SecretKey),
32 P521PrivateKey(p521::SecretKey),
33 P256PublicKey(p256::PublicKey),
34 P384PublicKey(p384::PublicKey),
35 P521PublicKey(p521::PublicKey),
36 X25519PrivateKey(x25519_dalek::StaticSecret),
37 X25519PublicKey(x25519_dalek::PublicKey),
38 Aes128(Vec<u8>),
39 Aes192(Vec<u8>),
40 Aes256(Vec<u8>),
41 HkdfSecret(Vec<u8>),
42 Pbkdf2(Vec<u8>),
43 Hmac(Vec<u8>),
44 Ed25519(Vec<u8>),
45 ChaCha20Poly1305Key(chacha20poly1305::Key),
46 Argon2Password(Vec<u8>),
47}
48
49#[dom_struct]
51pub(crate) struct CryptoKey {
52 reflector_: Reflector,
53
54 key_type: KeyType,
56
57 extractable: Cell<bool>,
59
60 #[no_trace]
65 algorithm: KeyAlgorithmAndDerivatives,
66
67 #[ignore_malloc_size_of = "Defined in mozjs"]
69 algorithm_cached: Heap<*mut JSObject>,
70
71 usages: DomRefCell<Vec<KeyUsage>>,
75
76 #[ignore_malloc_size_of = "Defined in mozjs"]
78 usages_cached: Heap<*mut JSObject>,
79
80 #[no_trace]
82 handle: Handle,
83}
84
85impl CryptoKey {
86 fn new_inherited(
87 key_type: KeyType,
88 extractable: bool,
89 algorithm: KeyAlgorithmAndDerivatives,
90 usages: Vec<KeyUsage>,
91 handle: Handle,
92 ) -> CryptoKey {
93 CryptoKey {
94 reflector_: Reflector::new(),
95 key_type,
96 extractable: Cell::new(extractable),
97 algorithm,
98 algorithm_cached: Heap::default(),
99 usages: DomRefCell::new(usages),
100 usages_cached: Heap::default(),
101 handle,
102 }
103 }
104
105 pub(crate) fn new(
106 global: &GlobalScope,
107 key_type: KeyType,
108 extractable: bool,
109 algorithm: KeyAlgorithmAndDerivatives,
110 usages: Vec<KeyUsage>,
111 handle: Handle,
112 can_gc: CanGc,
113 ) -> DomRoot<CryptoKey> {
114 let crypto_key = reflect_dom_object(
115 Box::new(CryptoKey::new_inherited(
116 key_type,
117 extractable,
118 algorithm.clone(),
119 usages.clone(),
120 handle,
121 )),
122 global,
123 can_gc,
124 );
125
126 let cx = GlobalScope::get_cx();
127
128 rooted!(in(*cx) let mut algorithm_object_value: Value);
130 algorithm.safe_to_jsval(cx, algorithm_object_value.handle_mut(), can_gc);
131 crypto_key
132 .algorithm_cached
133 .set(algorithm_object_value.to_object());
134
135 rooted!(in(*cx) let mut usages_object_value: Value);
137 usages.safe_to_jsval(cx, usages_object_value.handle_mut(), can_gc);
138 crypto_key
139 .usages_cached
140 .set(usages_object_value.to_object());
141
142 crypto_key
143 }
144
145 pub(crate) fn algorithm(&self) -> &KeyAlgorithmAndDerivatives {
146 &self.algorithm
147 }
148
149 pub(crate) fn usages(&self) -> Vec<KeyUsage> {
150 self.usages.borrow().clone()
151 }
152
153 pub(crate) fn handle(&self) -> &Handle {
154 &self.handle
155 }
156
157 pub(crate) fn set_extractable(&self, extractable: bool) {
158 self.extractable.set(extractable);
159 }
160
161 pub(crate) fn set_usages(&self, usages: &[KeyUsage]) {
162 *self.usages.borrow_mut() = usages.to_owned();
163
164 let cx = GlobalScope::get_cx();
166 rooted!(in(*cx) let mut usages_object_value: Value);
167 usages.safe_to_jsval(cx, usages_object_value.handle_mut(), CanGc::note());
168 self.usages_cached.set(usages_object_value.to_object());
169 }
170}
171
172impl CryptoKeyMethods<crate::DomTypeHolder> for CryptoKey {
173 fn Type(&self) -> KeyType {
175 self.key_type
177 }
178
179 fn Extractable(&self) -> bool {
181 self.extractable.get()
184 }
185
186 fn Algorithm(&self, _cx: JSContext) -> NonNull<JSObject> {
188 NonNull::new(self.algorithm_cached.get()).unwrap()
190 }
191
192 fn Usages(&self, _cx: JSContext) -> NonNull<JSObject> {
194 NonNull::new(self.usages_cached.get()).unwrap()
197 }
198}
199
200impl Handle {
201 pub(crate) fn as_bytes(&self) -> &[u8] {
202 match self {
203 Self::Aes128(bytes) => bytes,
204 Self::Aes192(bytes) => bytes,
205 Self::Aes256(bytes) => bytes,
206 Self::Pbkdf2(bytes) => bytes,
207 Self::Hmac(bytes) => bytes,
208 Self::Ed25519(bytes) => bytes,
209 _ => unreachable!(),
210 }
211 }
212}
213
214impl MallocSizeOf for Handle {
215 fn size_of(&self, ops: &mut malloc_size_of::MallocSizeOfOps) -> usize {
216 match self {
217 Handle::P256PrivateKey(private_key) => private_key.size_of(ops),
218 Handle::P384PrivateKey(private_key) => private_key.size_of(ops),
219 Handle::P521PrivateKey(private_key) => private_key.size_of(ops),
220 Handle::P256PublicKey(public_key) => public_key.size_of(ops),
221 Handle::P384PublicKey(public_key) => public_key.size_of(ops),
222 Handle::P521PublicKey(public_key) => public_key.size_of(ops),
223 Handle::X25519PrivateKey(private_key) => private_key.size_of(ops),
224 Handle::X25519PublicKey(public_key) => public_key.size_of(ops),
225 Handle::Aes128(bytes) => bytes.size_of(ops),
226 Handle::Aes192(bytes) => bytes.size_of(ops),
227 Handle::Aes256(bytes) => bytes.size_of(ops),
228 Handle::HkdfSecret(secret) => secret.size_of(ops),
229 Handle::Pbkdf2(bytes) => bytes.size_of(ops),
230 Handle::Hmac(bytes) => bytes.size_of(ops),
231 Handle::Ed25519(bytes) => bytes.size_of(ops),
232 Handle::ChaCha20Poly1305Key(key) => key.size_of(ops),
233 Handle::Argon2Password(password) => password.size_of(ops),
234 }
235 }
236}