script/dom/
cryptokey.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use 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
28/// The underlying cryptographic data this key represents
29pub(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/// <https://w3c.github.io/webcrypto/#cryptokey-interface>
50#[dom_struct]
51pub(crate) struct CryptoKey {
52    reflector_: Reflector,
53
54    /// <https://w3c.github.io/webcrypto/#dfn-CryptoKey-slot-type>
55    key_type: KeyType,
56
57    /// <https://w3c.github.io/webcrypto/#dfn-CryptoKey-slot-extractable>
58    extractable: Cell<bool>,
59
60    /// <https://w3c.github.io/webcrypto/#dfn-CryptoKey-slot-algorithm>
61    ///
62    /// The contents of the [[algorithm]] internal slot shall be, or be derived from, a
63    /// KeyAlgorithm.
64    #[no_trace]
65    algorithm: KeyAlgorithmAndDerivatives,
66
67    /// <https://w3c.github.io/webcrypto/#dfn-CryptoKey-slot-algorithm_cached>
68    #[ignore_malloc_size_of = "Defined in mozjs"]
69    algorithm_cached: Heap<*mut JSObject>,
70
71    /// <https://w3c.github.io/webcrypto/#dfn-CryptoKey-slot-usages>
72    ///
73    /// The contents of the [[usages]] internal slot shall be of type Sequence<KeyUsage>.
74    usages: DomRefCell<Vec<KeyUsage>>,
75
76    /// <https://w3c.github.io/webcrypto/#dfn-CryptoKey-slot-usages_cached>
77    #[ignore_malloc_size_of = "Defined in mozjs"]
78    usages_cached: Heap<*mut JSObject>,
79
80    /// <https://w3c.github.io/webcrypto/#dfn-CryptoKey-slot-handle>
81    #[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        // Create and store a cached object of algorithm
129        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        // Create and store a cached object of usages
136        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        // Create and store a cached object of usages
165        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    /// <https://w3c.github.io/webcrypto/#dom-cryptokey-type>
174    fn Type(&self) -> KeyType {
175        // Reflects the [[type]] internal slot, which contains the type of the underlying key.
176        self.key_type
177    }
178
179    /// <https://w3c.github.io/webcrypto/#dom-cryptokey-extractable>
180    fn Extractable(&self) -> bool {
181        // Reflects the [[extractable]] internal slot, which indicates whether or not the raw
182        // keying material may be exported by the application.
183        self.extractable.get()
184    }
185
186    /// <https://w3c.github.io/webcrypto/#dom-cryptokey-algorithm>
187    fn Algorithm(&self, _cx: JSContext) -> NonNull<JSObject> {
188        // Returns the cached ECMAScript object associated with the [[algorithm]] internal slot.
189        NonNull::new(self.algorithm_cached.get()).unwrap()
190    }
191
192    /// <https://w3c.github.io/webcrypto/#dom-cryptokey-usages>
193    fn Usages(&self, _cx: JSContext) -> NonNull<JSObject> {
194        // Returns the cached ECMAScript object associated with the [[usages]] internal slot, which
195        // indicates which cryptographic operations are permissible to be used with this key.
196        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}