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 Gate, Revoc, SecurityError, Signature, SigningKey, VerifyingKey,
9};
10
11#[derive(Clone, 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 gate: Gate,
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: Gate,
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 gate: 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.gate,
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.gate.offset {
157 return Err(SecurityError::GateDenied);
158 }
159
160 if self.gate.offset + self.gate.length < ptr_offset {
162 return Err(SecurityError::GateDenied);
163 }
164
165 if self.gate.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: Gate,
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(test)]
196#[cfg(feature = "user")]
197#[allow(unused_imports)]
198mod tests {
199
200 use crate::*;
201
202 extern crate test;
203
204 use twizzler::object::TypedObject;
205 use twizzler_abi::{object::Protections, syscall::ObjectCreate};
206 fn default_capability(s_key: &SigningKey) -> Cap {
208 Cap::new(
209 0x123.into(),
210 0x321.into(),
211 Protections::all(),
212 s_key,
213 Revoc::default(),
214 Gate::default(),
215 HashingAlgo::Sha256,
216 )
217 .expect("Capability should have been created.")
218 }
219
220 #[test]
221 fn test_capability_creation() {
222 let (s, _v) = SigningKey::new_keypair(&SigningScheme::Ecdsa, ObjectCreate::default())
223 .expect("keypair creation should not have errored!");
224 let _cap = default_capability(s.base());
225 }
226
227 #[test]
228 fn test_capability_verification() {
229 let (s, v) = SigningKey::new_keypair(&SigningScheme::Ecdsa, ObjectCreate::default())
230 .expect("keypair creation should not have errored!");
231
232 let cap = default_capability(s.base());
233
234 cap.verify_sig(v.base())
235 .expect("capability should have been verified.")
236 }
237
238 #[test]
239 fn test_capability_gates() {
240 struct Input {
241 capability_gates: Gate,
243 ptr_offset: u64,
245 align: u64,
246 }
247
248 #[derive(PartialEq, PartialOrd, Ord, Eq, Debug)]
251 enum Expected {
252 Fail,
253 Pass,
254 }
255
256 use Expected::*;
257
258 let table: [(Input, Expected); 7] = [
259 (
260 Input {
261 capability_gates: Gate::new(0, 100, 1),
262 ptr_offset: 3,
263 align: 1,
264 },
265 Pass,
266 ),
267 (
268 Input {
269 capability_gates: Gate::new(0, 100, 1),
270 ptr_offset: 100,
271 align: 1,
272 },
273 Pass,
274 ),
275 (
276 Input {
277 capability_gates: Gate::new(0, 10_000, 1),
278 ptr_offset: 5_000,
279 align: 1,
280 },
281 Pass,
282 ),
283 (
284 Input {
285 capability_gates: Gate::new(0, 100, 1),
286 ptr_offset: 50,
287 align: 1,
288 },
289 Pass,
290 ),
291 (
292 Input {
293 capability_gates: Gate::new(5, 10000, 1),
294 ptr_offset: 0, align: 1,
296 },
297 Fail,
298 ),
299 (
300 Input {
301 capability_gates: Gate::new(0, 100, 1),
302 ptr_offset: 105, align: 1,
304 },
305 Fail,
306 ),
307 (
308 Input {
309 capability_gates: Gate::new(0, 100, 1),
310 ptr_offset: 66,
311 align: 4, },
313 Fail,
314 ),
315 ];
316
317 let (s, _v) = SigningKey::new_keypair(&SigningScheme::Ecdsa, ObjectCreate::default())
318 .expect("keypair creation should not have errored!");
319
320 for (test_number, (input, expected)) in table.into_iter().enumerate() {
321 let cap = Cap::new(
322 0x123.into(),
323 0x321.into(),
324 Protections::all(),
325 s.base(),
326 Revoc::default(),
327 input.capability_gates,
328 HashingAlgo::Sha256,
329 )
330 .expect("Capability should have been created properly.");
331
332 let actual = match cap.check_gate(input.ptr_offset, input.align).is_ok() {
333 true => Pass,
334 false => Fail,
335 };
336
337 assert_eq!(
338 actual,
339 expected,
340 "
341 \n Test {:?}
342 expected: {:?}
343 actual: {:?},
344 Failed for capability gates = {:#?}, where
345 testing against: ptr_offset = {}, align = {})",
346 test_number,
347 expected,
348 actual,
349 input.capability_gates,
350 input.ptr_offset,
351 input.align
352 )
353 }
354 }
355}