1#[cfg(feature = "log")]
2use log::debug;
3use sha2::{Digest, Sha256};
4use twizzler_abi::object::{ObjID, Protections};
5
6use crate::{
7 flags::{CapFlags, HashingAlgo},
8 Gates, Revoc, SecurityError, Signature, SigningKey, VerifyingKey,
9};
10
11#[derive(Clone, Copy, PartialEq, Eq, Debug)]
38pub struct Cap {
39 pub target: ObjID,
41
42 pub accessor: ObjID,
44
45 pub protections: Protections,
47
48 flags: CapFlags,
50
51 gates: Gates,
53
54 pub revocation: Revoc,
56
57 sig: Signature,
59}
60
61const CAP_SERIALIZED_LEN: usize = 78;
62
63impl Cap {
64 pub fn new(
66 target: ObjID,
67 accessor: ObjID,
68 prots: Protections,
69 target_priv_key: &SigningKey,
70 revocation: Revoc,
71 gates: Gates,
72 hashing_algo: HashingAlgo,
73 ) -> Result<Self, SecurityError> {
74 let flags: CapFlags = hashing_algo.clone().into();
75
76 #[cfg(feature = "log")]
77 debug!(
78 "Using flags: {} to create capability for target: {:?}",
79 flags, target
80 );
81
82 let hash_arr = Cap::serialize(accessor, target, prots, flags, revocation, gates);
83
84 let sig = match hashing_algo {
85 HashingAlgo::Blake3 => {
86 let hash = blake3::hash(&hash_arr);
88 target_priv_key.sign(hash.as_bytes())?
89 }
90 HashingAlgo::Sha256 => {
91 let mut hasher = Sha256::new();
92 hasher.update(hash_arr);
93 let hash = hasher.finalize();
94 target_priv_key.sign(hash.as_slice())?
95 }
96 };
97
98 Ok(Cap {
99 accessor,
100 target,
101 protections: prots,
102 flags,
103 revocation,
104 gates,
105 sig,
106 })
107 }
108
109 pub fn verify_sig(&self, verifying_key: &VerifyingKey) -> Result<(), SecurityError> {
112 let hash_arr = Self::serialize(
113 self.accessor,
114 self.target,
115 self.protections,
116 self.flags,
117 self.revocation,
118 self.gates,
119 );
120
121 let hash_algo: HashingAlgo = self.flags.try_into()?;
122
123 match hash_algo {
124 HashingAlgo::Blake3 => {
125 let hash = blake3::hash(&hash_arr);
129 let bind = hash.as_bytes();
130 verifying_key.verify(bind.as_slice(), &self.sig)
131 }
132 HashingAlgo::Sha256 => {
133 #[cfg(feature = "log")]
134 debug!("Hashing via Sha256");
135 let mut hasher = sha2::Sha256::new();
136 hasher.update(&hash_arr);
137 let result = hasher.finalize();
138 verifying_key.verify(result.as_slice(), &self.sig)
139 }
140 }
141 }
142
143 pub fn check_gate(&self, ptr_offset: u64, align: u64) -> Result<(), SecurityError> {
145 if ptr_offset < self.gates.offset {
157 return Err(SecurityError::GateDenied);
158 }
159
160 if self.gates.offset + self.gates.length < ptr_offset {
162 return Err(SecurityError::GateDenied);
163 }
164
165 if self.gates.align != align {
167 return Err(SecurityError::GateDenied);
168 }
169
170 Ok(())
171 }
172
173 fn serialize(
175 accessor: ObjID,
176 target: ObjID,
177 prots: Protections,
178 flags: CapFlags,
179 revocation: Revoc,
180 gates: Gates,
181 ) -> [u8; CAP_SERIALIZED_LEN] {
182 let mut hash_arr: [u8; CAP_SERIALIZED_LEN] = [0; CAP_SERIALIZED_LEN];
183 hash_arr[0..16].copy_from_slice(&accessor.raw().to_le_bytes());
184 hash_arr[16..32].copy_from_slice(&target.raw().to_le_bytes());
185 hash_arr[32..34].copy_from_slice(&prots.bits().to_le_bytes());
186 hash_arr[34..36].copy_from_slice(&flags.bits().to_le_bytes());
187 hash_arr[36..52].copy_from_slice(&revocation.to_bytes());
188 hash_arr[52..60].copy_from_slice(&gates.offset.to_le_bytes());
189 hash_arr[60..68].copy_from_slice(&gates.length.to_le_bytes());
190 hash_arr[68..76].copy_from_slice(&gates.align.to_le_bytes());
191 hash_arr
192 }
193}
194
195#[cfg(feature = "user")]
196#[allow(unused_imports)]
197mod tests {
198
199 use crate::*;
200
201 extern crate test;
202
203 use twizzler::object::TypedObject;
204 use twizzler_abi::{object::Protections, syscall::ObjectCreate};
205 fn default_capability(s_key: &SigningKey) -> Cap {
206 Cap::new(
207 0x123.into(),
208 0x321.into(),
209 Protections::all(),
210 s_key,
211 Revoc::default(),
212 Gates::default(),
213 HashingAlgo::Sha256,
214 )
215 .expect("Capability should have been created.")
216 }
217
218 #[test]
219 fn test_capability_creation() {
220 let (s, _v) = SigningKey::new_keypair(&SigningScheme::Ecdsa, ObjectCreate::default())
221 .expect("keypair creation should not have errored!");
222 let _cap = default_capability(s.base());
223 }
224
225 #[test]
226 fn test_capability_verification() {
227 let (s, v) = SigningKey::new_keypair(&SigningScheme::Ecdsa, ObjectCreate::default())
228 .expect("keypair creation should not have errored!");
229
230 let cap = default_capability(s.base());
231
232 cap.verify_sig(v.base())
233 .expect("capability should have been verified.")
234 }
235
236 #[test]
237 fn test_capability_gates() {
238 struct Input {
239 capability_gates: Gates,
241 ptr_offset: u64,
243 align: u64,
244 }
245
246 #[derive(PartialEq, PartialOrd, Ord, Eq, Debug)]
249 enum Expected {
250 Fail,
251 Pass,
252 }
253
254 use Expected::*;
255
256 let table: [(Input, Expected); 7] = [
257 (
258 Input {
259 capability_gates: Gates::new(0, 100, 1),
260 ptr_offset: 3,
261 align: 1,
262 },
263 Pass,
264 ),
265 (
266 Input {
267 capability_gates: Gates::new(0, 100, 1),
268 ptr_offset: 100,
269 align: 1,
270 },
271 Pass,
272 ),
273 (
274 Input {
275 capability_gates: Gates::new(0, 10_000, 1),
276 ptr_offset: 5_000,
277 align: 1,
278 },
279 Pass,
280 ),
281 (
282 Input {
283 capability_gates: Gates::new(0, 100, 1),
284 ptr_offset: 50,
285 align: 1,
286 },
287 Pass,
288 ),
289 (
290 Input {
291 capability_gates: Gates::new(5, 10000, 1),
292 ptr_offset: 0, align: 1,
294 },
295 Fail,
296 ),
297 (
298 Input {
299 capability_gates: Gates::new(0, 100, 1),
300 ptr_offset: 105, align: 1,
302 },
303 Fail,
304 ),
305 (
306 Input {
307 capability_gates: Gates::new(0, 100, 1),
308 ptr_offset: 66,
309 align: 4, },
311 Fail,
312 ),
313 ];
314
315 let (s, _v) = SigningKey::new_keypair(&SigningScheme::Ecdsa, ObjectCreate::default())
316 .expect("keypair creation should not have errored!");
317
318 for (test_number, (input, expected)) in table.into_iter().enumerate() {
319 let cap = Cap::new(
320 0x123.into(),
321 0x321.into(),
322 Protections::all(),
323 s.base(),
324 Revoc::default(),
325 input.capability_gates,
326 HashingAlgo::Sha256,
327 )
328 .expect("Capability should have been created properly.");
329
330 let actual = match cap.check_gate(input.ptr_offset, input.align).is_ok() {
331 true => Pass,
332 false => Fail,
333 };
334
335 assert_eq!(
336 actual,
337 expected,
338 "
339 \n Test {:?}
340 expected: {:?}
341 actual: {:?},
342 Failed for capability gates = {:#?}, where
343 testing against: ptr_offset = {}, align = {})",
344 test_number,
345 expected,
346 actual,
347 input.capability_gates,
348 input.ptr_offset,
349 input.align
350 )
351 }
352 }
353}