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 script_bindings::conversions::SafeToJSValConvertible;
11
12use crate::dom::bindings::cell::DomRefCell;
13use crate::dom::bindings::codegen::Bindings::CryptoKeyBinding::{
14    CryptoKeyMethods, KeyType, KeyUsage,
15};
16use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
17use crate::dom::bindings::root::DomRoot;
18use crate::dom::globalscope::GlobalScope;
19use crate::dom::subtlecrypto::KeyAlgorithmAndDerivatives;
20use crate::script_runtime::{CanGc, JSContext};
21
22pub(crate) enum CryptoKeyOrCryptoKeyPair {
23    CryptoKey(DomRoot<CryptoKey>),
24    // TODO: CryptoKeyPair(CryptoKeyPair),
25}
26
27/// The underlying cryptographic data this key represents
28#[allow(dead_code)]
29#[derive(MallocSizeOf)]
30pub(crate) enum Handle {
31    Aes128(Vec<u8>),
32    Aes192(Vec<u8>),
33    Aes256(Vec<u8>),
34    Pbkdf2(Vec<u8>),
35    Hkdf(Vec<u8>),
36    Hmac(Vec<u8>),
37}
38
39/// <https://w3c.github.io/webcrypto/#cryptokey-interface>
40#[dom_struct]
41pub(crate) struct CryptoKey {
42    reflector_: Reflector,
43
44    /// <https://w3c.github.io/webcrypto/#dfn-CryptoKey-slot-type>
45    key_type: KeyType,
46
47    /// <https://w3c.github.io/webcrypto/#dfn-CryptoKey-slot-extractable>
48    extractable: Cell<bool>,
49
50    /// <https://w3c.github.io/webcrypto/#dfn-CryptoKey-slot-algorithm>
51    ///
52    /// The contents of the [[algorithm]] internal slot shall be, or be derived from, a
53    /// KeyAlgorithm.
54    #[no_trace]
55    algorithm: KeyAlgorithmAndDerivatives,
56
57    /// <https://w3c.github.io/webcrypto/#dfn-CryptoKey-slot-algorithm_cached>
58    #[ignore_malloc_size_of = "Defined in mozjs"]
59    algorithm_cached: Heap<*mut JSObject>,
60
61    /// <https://w3c.github.io/webcrypto/#dfn-CryptoKey-slot-usages>
62    ///
63    /// The contents of the [[usages]] internal slot shall be of type Sequence<KeyUsage>.
64    usages: DomRefCell<Vec<KeyUsage>>,
65
66    /// <https://w3c.github.io/webcrypto/#dfn-CryptoKey-slot-usages_cached>
67    #[ignore_malloc_size_of = "Defined in mozjs"]
68    usages_cached: Heap<*mut JSObject>,
69
70    /// <https://w3c.github.io/webcrypto/#dfn-CryptoKey-slot-handle>
71    #[no_trace]
72    handle: Handle,
73}
74
75impl CryptoKey {
76    fn new_inherited(
77        key_type: KeyType,
78        extractable: bool,
79        algorithm: KeyAlgorithmAndDerivatives,
80        usages: Vec<KeyUsage>,
81        handle: Handle,
82    ) -> CryptoKey {
83        CryptoKey {
84            reflector_: Reflector::new(),
85            key_type,
86            extractable: Cell::new(extractable),
87            algorithm,
88            algorithm_cached: Heap::default(),
89            usages: DomRefCell::new(usages),
90            usages_cached: Heap::default(),
91            handle,
92        }
93    }
94
95    #[allow(clippy::too_many_arguments)]
96    pub(crate) fn new(
97        global: &GlobalScope,
98        key_type: KeyType,
99        extractable: bool,
100        algorithm: KeyAlgorithmAndDerivatives,
101        usages: Vec<KeyUsage>,
102        handle: Handle,
103        can_gc: CanGc,
104    ) -> DomRoot<CryptoKey> {
105        let crypto_key = reflect_dom_object(
106            Box::new(CryptoKey::new_inherited(
107                key_type,
108                extractable,
109                algorithm.clone(),
110                usages.clone(),
111                handle,
112            )),
113            global,
114            can_gc,
115        );
116
117        let cx = GlobalScope::get_cx();
118
119        // Create and store a cached object of algorithm
120        rooted!(in(*cx) let mut algorithm_object_value: Value);
121        algorithm.safe_to_jsval(cx, algorithm_object_value.handle_mut());
122        crypto_key
123            .algorithm_cached
124            .set(algorithm_object_value.to_object());
125
126        // Create and store a cached object of usages
127        rooted!(in(*cx) let mut usages_object_value: Value);
128        usages.safe_to_jsval(cx, usages_object_value.handle_mut());
129        crypto_key
130            .usages_cached
131            .set(usages_object_value.to_object());
132
133        crypto_key
134    }
135
136    pub(crate) fn algorithm(&self) -> &KeyAlgorithmAndDerivatives {
137        &self.algorithm
138    }
139
140    pub(crate) fn usages(&self) -> Vec<KeyUsage> {
141        self.usages.borrow().clone()
142    }
143
144    pub(crate) fn handle(&self) -> &Handle {
145        &self.handle
146    }
147
148    pub(crate) fn set_extractable(&self, extractable: bool) {
149        self.extractable.set(extractable);
150    }
151
152    pub(crate) fn set_usages(&self, usages: &[KeyUsage]) {
153        *self.usages.borrow_mut() = usages.to_owned();
154
155        // Create and store a cached object of usages
156        let cx = GlobalScope::get_cx();
157        rooted!(in(*cx) let mut usages_object_value: Value);
158        usages.safe_to_jsval(cx, usages_object_value.handle_mut());
159        self.usages_cached.set(usages_object_value.to_object());
160    }
161}
162
163impl CryptoKeyMethods<crate::DomTypeHolder> for CryptoKey {
164    /// <https://w3c.github.io/webcrypto/#dom-cryptokey-type>
165    fn Type(&self) -> KeyType {
166        // Reflects the [[type]] internal slot, which contains the type of the underlying key.
167        self.key_type
168    }
169
170    /// <https://w3c.github.io/webcrypto/#dom-cryptokey-extractable>
171    fn Extractable(&self) -> bool {
172        // Reflects the [[extractable]] internal slot, which indicates whether or not the raw
173        // keying material may be exported by the application.
174        self.extractable.get()
175    }
176
177    /// <https://w3c.github.io/webcrypto/#dom-cryptokey-algorithm>
178    fn Algorithm(&self, _cx: JSContext) -> NonNull<JSObject> {
179        // Returns the cached ECMAScript object associated with the [[algorithm]] internal slot.
180        NonNull::new(self.algorithm_cached.get()).unwrap()
181    }
182
183    /// <https://w3c.github.io/webcrypto/#dom-cryptokey-usages>
184    fn Usages(&self, _cx: JSContext) -> NonNull<JSObject> {
185        // Returns the cached ECMAScript object associated with the [[usages]] internal slot, which
186        // indicates which cryptographic operations are permissible to be used with this key.
187        NonNull::new(self.usages_cached.get()).unwrap()
188    }
189}
190
191impl Handle {
192    pub(crate) fn as_bytes(&self) -> &[u8] {
193        match self {
194            Self::Aes128(bytes) => bytes,
195            Self::Aes192(bytes) => bytes,
196            Self::Aes256(bytes) => bytes,
197            Self::Pbkdf2(bytes) => bytes,
198            Self::Hkdf(bytes) => bytes,
199            Self::Hmac(bytes) => bytes,
200        }
201    }
202}