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_with_cx};
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    RsaPrivateKey(rsa::RsaPrivateKey),
31    RsaPublicKey(rsa::RsaPublicKey),
32    P256PrivateKey(p256::SecretKey),
33    P384PrivateKey(p384::SecretKey),
34    P521PrivateKey(p521::SecretKey),
35    P256PublicKey(p256::PublicKey),
36    P384PublicKey(p384::PublicKey),
37    P521PublicKey(p521::PublicKey),
38    Ed25519PrivateKey(Vec<u8>),
39    Ed25519PublicKey(Vec<u8>),
40    X25519PrivateKey(x25519_dalek::StaticSecret),
41    X25519PublicKey(x25519_dalek::PublicKey),
42    Aes128Key(aes::cipher::crypto_common::Key<aes::Aes128>),
43    Aes192Key(aes::cipher::crypto_common::Key<aes::Aes192>),
44    Aes256Key(aes::cipher::crypto_common::Key<aes::Aes256>),
45    HkdfSecret(Vec<u8>),
46    Pbkdf2(Vec<u8>),
47    Hmac(Vec<u8>),
48    MlKem512PrivateKey((ml_kem::B32, ml_kem::B32)),
49    MlKem768PrivateKey((ml_kem::B32, ml_kem::B32)),
50    MlKem1024PrivateKey((ml_kem::B32, ml_kem::B32)),
51    MlKem512PublicKey(Box<ml_kem::Encoded<ml_kem::kem::EncapsulationKey<ml_kem::MlKem512Params>>>),
52    MlKem768PublicKey(Box<ml_kem::Encoded<ml_kem::kem::EncapsulationKey<ml_kem::MlKem768Params>>>),
53    MlKem1024PublicKey(
54        Box<ml_kem::Encoded<ml_kem::kem::EncapsulationKey<ml_kem::MlKem1024Params>>>,
55    ),
56    MlDsa44PrivateKey(ml_dsa::B32),
57    MlDsa65PrivateKey(ml_dsa::B32),
58    MlDsa87PrivateKey(ml_dsa::B32),
59    MlDsa44PublicKey(Box<ml_dsa::EncodedVerifyingKey<ml_dsa::MlDsa44>>),
60    MlDsa65PublicKey(Box<ml_dsa::EncodedVerifyingKey<ml_dsa::MlDsa65>>),
61    MlDsa87PublicKey(Box<ml_dsa::EncodedVerifyingKey<ml_dsa::MlDsa87>>),
62    ChaCha20Poly1305Key(chacha20poly1305::Key),
63    Argon2Password(Vec<u8>),
64}
65
66/// <https://w3c.github.io/webcrypto/#cryptokey-interface>
67#[dom_struct]
68pub(crate) struct CryptoKey {
69    reflector_: Reflector,
70
71    /// <https://w3c.github.io/webcrypto/#dfn-CryptoKey-slot-type>
72    key_type: KeyType,
73
74    /// <https://w3c.github.io/webcrypto/#dfn-CryptoKey-slot-extractable>
75    extractable: Cell<bool>,
76
77    /// <https://w3c.github.io/webcrypto/#dfn-CryptoKey-slot-algorithm>
78    ///
79    /// The contents of the [[algorithm]] internal slot shall be, or be derived from, a
80    /// KeyAlgorithm.
81    #[no_trace]
82    algorithm: KeyAlgorithmAndDerivatives,
83
84    /// <https://w3c.github.io/webcrypto/#dfn-CryptoKey-slot-algorithm_cached>
85    #[ignore_malloc_size_of = "Defined in mozjs"]
86    algorithm_cached: Heap<*mut JSObject>,
87
88    /// <https://w3c.github.io/webcrypto/#dfn-CryptoKey-slot-usages>
89    ///
90    /// The contents of the [[usages]] internal slot shall be of type Sequence<KeyUsage>.
91    usages: DomRefCell<Vec<KeyUsage>>,
92
93    /// <https://w3c.github.io/webcrypto/#dfn-CryptoKey-slot-usages_cached>
94    #[ignore_malloc_size_of = "Defined in mozjs"]
95    usages_cached: Heap<*mut JSObject>,
96
97    /// <https://w3c.github.io/webcrypto/#dfn-CryptoKey-slot-handle>
98    #[no_trace]
99    handle: Handle,
100}
101
102impl CryptoKey {
103    fn new_inherited(
104        key_type: KeyType,
105        extractable: bool,
106        algorithm: KeyAlgorithmAndDerivatives,
107        usages: Vec<KeyUsage>,
108        handle: Handle,
109    ) -> CryptoKey {
110        CryptoKey {
111            reflector_: Reflector::new(),
112            key_type,
113            extractable: Cell::new(extractable),
114            algorithm,
115            algorithm_cached: Heap::default(),
116            usages: DomRefCell::new(usages),
117            usages_cached: Heap::default(),
118            handle,
119        }
120    }
121
122    pub(crate) fn new(
123        cx: &mut js::context::JSContext,
124        global: &GlobalScope,
125        key_type: KeyType,
126        extractable: bool,
127        algorithm: KeyAlgorithmAndDerivatives,
128        usages: Vec<KeyUsage>,
129        handle: Handle,
130    ) -> DomRoot<CryptoKey> {
131        let crypto_key = reflect_dom_object_with_cx(
132            Box::new(CryptoKey::new_inherited(
133                key_type,
134                extractable,
135                algorithm.clone(),
136                usages.clone(),
137                handle,
138            )),
139            global,
140            cx,
141        );
142
143        // Create and store a cached object of algorithm
144        rooted!(&in(cx) let mut algorithm_object_value: Value);
145        algorithm.safe_to_jsval(
146            cx.into(),
147            algorithm_object_value.handle_mut(),
148            CanGc::from_cx(cx),
149        );
150        crypto_key
151            .algorithm_cached
152            .set(algorithm_object_value.to_object());
153
154        // Create and store a cached object of usages
155        rooted!(&in(cx) let mut usages_object_value: Value);
156        usages.safe_to_jsval(
157            cx.into(),
158            usages_object_value.handle_mut(),
159            CanGc::from_cx(cx),
160        );
161        crypto_key
162            .usages_cached
163            .set(usages_object_value.to_object());
164
165        crypto_key
166    }
167
168    pub(crate) fn algorithm(&self) -> &KeyAlgorithmAndDerivatives {
169        &self.algorithm
170    }
171
172    pub(crate) fn usages(&self) -> Vec<KeyUsage> {
173        self.usages.borrow().clone()
174    }
175
176    pub(crate) fn handle(&self) -> &Handle {
177        &self.handle
178    }
179
180    pub(crate) fn set_extractable(&self, extractable: bool) {
181        self.extractable.set(extractable);
182    }
183
184    pub(crate) fn set_usages(&self, cx: &mut js::context::JSContext, usages: &[KeyUsage]) {
185        *self.usages.borrow_mut() = usages.to_owned();
186
187        // Create and store a cached object of usages
188        rooted!(&in(cx) let mut usages_object_value: Value);
189        usages.safe_to_jsval(
190            cx.into(),
191            usages_object_value.handle_mut(),
192            CanGc::from_cx(cx),
193        );
194        self.usages_cached.set(usages_object_value.to_object());
195    }
196}
197
198impl CryptoKeyMethods<crate::DomTypeHolder> for CryptoKey {
199    /// <https://w3c.github.io/webcrypto/#dom-cryptokey-type>
200    fn Type(&self) -> KeyType {
201        // Reflects the [[type]] internal slot, which contains the type of the underlying key.
202        self.key_type
203    }
204
205    /// <https://w3c.github.io/webcrypto/#dom-cryptokey-extractable>
206    fn Extractable(&self) -> bool {
207        // Reflects the [[extractable]] internal slot, which indicates whether or not the raw
208        // keying material may be exported by the application.
209        self.extractable.get()
210    }
211
212    /// <https://w3c.github.io/webcrypto/#dom-cryptokey-algorithm>
213    fn Algorithm(&self, _cx: JSContext) -> NonNull<JSObject> {
214        // Returns the cached ECMAScript object associated with the [[algorithm]] internal slot.
215        NonNull::new(self.algorithm_cached.get()).unwrap()
216    }
217
218    /// <https://w3c.github.io/webcrypto/#dom-cryptokey-usages>
219    fn Usages(&self, _cx: JSContext) -> NonNull<JSObject> {
220        // Returns the cached ECMAScript object associated with the [[usages]] internal slot, which
221        // indicates which cryptographic operations are permissible to be used with this key.
222        NonNull::new(self.usages_cached.get()).unwrap()
223    }
224}
225
226impl Handle {
227    pub(crate) fn as_bytes(&self) -> &[u8] {
228        match self {
229            Self::Pbkdf2(bytes) => bytes,
230            Self::Hmac(bytes) => bytes,
231            Self::Ed25519PrivateKey(bytes) => bytes,
232            Self::Ed25519PublicKey(bytes) => bytes,
233            _ => unreachable!(),
234        }
235    }
236}
237
238impl MallocSizeOf for Handle {
239    fn size_of(&self, ops: &mut malloc_size_of::MallocSizeOfOps) -> usize {
240        match self {
241            Handle::RsaPrivateKey(private_key) => private_key.size_of(ops),
242            Handle::RsaPublicKey(public_key) => public_key.size_of(ops),
243            Handle::P256PrivateKey(private_key) => private_key.size_of(ops),
244            Handle::P384PrivateKey(private_key) => private_key.size_of(ops),
245            Handle::P521PrivateKey(private_key) => private_key.size_of(ops),
246            Handle::P256PublicKey(public_key) => public_key.size_of(ops),
247            Handle::P384PublicKey(public_key) => public_key.size_of(ops),
248            Handle::P521PublicKey(public_key) => public_key.size_of(ops),
249            Handle::Ed25519PrivateKey(bytes) => bytes.size_of(ops),
250            Handle::Ed25519PublicKey(bytes) => bytes.size_of(ops),
251            Handle::X25519PrivateKey(private_key) => private_key.size_of(ops),
252            Handle::X25519PublicKey(public_key) => public_key.size_of(ops),
253            Handle::Aes128Key(key) => key.size_of(ops),
254            Handle::Aes192Key(key) => key.size_of(ops),
255            Handle::Aes256Key(key) => key.size_of(ops),
256            Handle::HkdfSecret(secret) => secret.size_of(ops),
257            Handle::Pbkdf2(bytes) => bytes.size_of(ops),
258            Handle::Hmac(bytes) => bytes.size_of(ops),
259            Handle::MlKem512PrivateKey(seed) => seed.0.size_of(ops) + seed.1.size_of(ops),
260            Handle::MlKem768PrivateKey(seed) => seed.0.size_of(ops) + seed.1.size_of(ops),
261            Handle::MlKem1024PrivateKey(seed) => seed.0.size_of(ops) + seed.1.size_of(ops),
262            Handle::MlKem512PublicKey(public_key) => public_key.size_of(ops),
263            Handle::MlKem768PublicKey(public_key) => public_key.size_of(ops),
264            Handle::MlKem1024PublicKey(public_key) => public_key.size_of(ops),
265            Handle::MlDsa44PrivateKey(seed) => seed.size_of(ops),
266            Handle::MlDsa65PrivateKey(seed) => seed.size_of(ops),
267            Handle::MlDsa87PrivateKey(seed) => seed.size_of(ops),
268            Handle::MlDsa44PublicKey(public_key) => public_key.size_of(ops),
269            Handle::MlDsa65PublicKey(public_key) => public_key.size_of(ops),
270            Handle::MlDsa87PublicKey(public_key) => public_key.size_of(ops),
271            Handle::ChaCha20Poly1305Key(key) => key.size_of(ops),
272            Handle::Argon2Password(password) => password.size_of(ops),
273        }
274    }
275}