veridian_kernel/security/
boot.rs1use spin::Mutex;
21
22use crate::{crypto::hash::sha256, error::KernelError};
23
24const MAX_BOOT_MEASUREMENTS: usize = 32;
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
29pub enum BootStatus {
30 Verified,
32 NotSupported,
34 Failed,
36 Disabled,
38 HashOnly,
40}
41
42pub struct SecureBootConfig {
44 pub enabled: bool,
46 pub enforce: bool,
48 pub kernel_hash: Option<[u8; 32]>,
50 pub signature: Option<BootSignature>,
52 pub signer_public_key: Option<[u8; 32]>,
54}
55
56impl SecureBootConfig {
57 pub const fn default() -> Self {
59 Self {
60 enabled: false,
61 enforce: false,
62 kernel_hash: None,
63 signature: None,
64 signer_public_key: None,
65 }
66 }
67}
68
69#[derive(Clone)]
71pub struct BootSignature {
72 pub signature_bytes: [u8; 64],
74 pub signer: &'static str,
76 pub algorithm: SignatureAlgorithm,
78}
79
80#[derive(Debug, Clone, Copy, PartialEq, Eq)]
82pub enum SignatureAlgorithm {
83 Ed25519,
85}
86
87#[derive(Clone)]
89pub struct BootMeasurement {
90 pub stage: &'static str,
92 pub hash: [u8; 32],
94 pub timestamp: u64,
96 pub pcr_index: Option<u8>,
98}
99
100pub struct BootMeasurementLog {
106 entries: [Option<BootMeasurement>; MAX_BOOT_MEASUREMENTS],
107 count: usize,
108}
109
110impl BootMeasurementLog {
111 const fn new() -> Self {
112 const NONE: Option<BootMeasurement> = None;
114 Self {
115 entries: [NONE; MAX_BOOT_MEASUREMENTS],
116 count: 0,
117 }
118 }
119
120 fn record(
124 &mut self,
125 stage: &'static str,
126 hash: [u8; 32],
127 timestamp: u64,
128 pcr_index: Option<u8>,
129 ) -> Option<usize> {
130 if self.count >= MAX_BOOT_MEASUREMENTS {
131 return None;
132 }
133 let idx = self.count;
134 self.entries[idx] = Some(BootMeasurement {
135 stage,
136 hash,
137 timestamp,
138 pcr_index,
139 });
140 self.count += 1;
141 Some(idx)
142 }
143
144 pub fn len(&self) -> usize {
146 self.count
147 }
148
149 pub fn is_empty(&self) -> bool {
151 self.count == 0
152 }
153
154 pub fn get(&self, index: usize) -> Option<&BootMeasurement> {
156 if index < self.count {
157 self.entries[index].as_ref()
158 } else {
159 None
160 }
161 }
162
163 pub fn measurements(&self) -> &[Option<BootMeasurement>] {
165 &self.entries[..self.count]
166 }
167}
168
169struct SecureBootState {
171 config: SecureBootConfig,
172 measurement_log: BootMeasurementLog,
173 last_status: BootStatus,
174}
175
176impl SecureBootState {
177 const fn new() -> Self {
178 Self {
179 config: SecureBootConfig::default(),
180 measurement_log: BootMeasurementLog::new(),
181 last_status: BootStatus::Disabled,
182 }
183 }
184}
185
186static STATE: Mutex<SecureBootState> = Mutex::new(SecureBootState::new());
187
188pub fn compute_kernel_hash() -> Result<[u8; 32], KernelError> {
201 let (start, size) = get_kernel_extent();
203
204 println!(
205 "[SECBOOT] Hashing kernel image: start=0x{:X}, size={} bytes",
206 start, size
207 );
208
209 let kernel_bytes = unsafe { core::slice::from_raw_parts(start as *const u8, size) };
214
215 let hash = sha256(kernel_bytes);
216 let result = *hash.as_bytes();
217
218 println!(
219 "[SECBOOT] Kernel SHA-256: {:02X}{:02X}{:02X}{:02X}...{:02X}{:02X}{:02X}{:02X}",
220 result[0], result[1], result[2], result[3], result[28], result[29], result[30], result[31],
221 );
222
223 Ok(result)
224}
225
226fn get_kernel_extent() -> (usize, usize) {
235 #[cfg(target_arch = "x86_64")]
237 let kernel_start: usize = 0xFFFFFFFF80100000;
238
239 #[cfg(target_arch = "aarch64")]
240 let kernel_start: usize = 0x40080000; #[cfg(target_arch = "riscv64")]
243 let kernel_start: usize = 0x80200000; (kernel_start, 64 * 1024)
249}
250
251fn verify_kernel_signature(
262 kernel_hash: &[u8; 32],
263 config: &SecureBootConfig,
264) -> Result<bool, KernelError> {
265 let signature = match &config.signature {
267 Some(sig) => sig,
268 None => {
269 println!("[SECBOOT] No boot signature configured -- skipping signature check");
270 return Ok(false);
271 }
272 };
273
274 let public_key = match &config.signer_public_key {
275 Some(pk) => pk,
276 None => {
277 println!("[SECBOOT] No signer public key configured -- skipping signature check");
278 return Ok(false);
279 }
280 };
281
282 println!(
283 "[SECBOOT] Verifying {:?} signature from '{}'",
284 signature.algorithm, signature.signer
285 );
286
287 match signature.algorithm {
289 SignatureAlgorithm::Ed25519 => {
290 use crate::crypto::asymmetric::{Signature, VerifyingKey};
291
292 let verifying_key = match VerifyingKey::from_bytes(public_key) {
293 Ok(vk) => vk,
294 Err(_e) => {
295 println!("[SECBOOT] Invalid verifying key: {:?}", _e);
296 return Ok(false);
297 }
298 };
299
300 let sig = match Signature::from_bytes(&signature.signature_bytes) {
301 Ok(s) => s,
302 Err(_e) => {
303 println!("[SECBOOT] Invalid signature format: {:?}", _e);
304 return Ok(false);
305 }
306 };
307
308 match verifying_key.verify(kernel_hash, &sig) {
310 Ok(valid) => {
311 let _status = if valid { "VALID" } else { "INVALID" };
315 println!("[SECBOOT] Ed25519 signature {}", _status);
316 Ok(valid)
317 }
318 Err(_e) => {
319 println!("[SECBOOT] Signature verification error: {:?}", _e);
320 Ok(false)
321 }
322 }
323 }
324 }
325}
326
327fn verify_hash_only(computed_hash: &[u8; 32], config: &SecureBootConfig) -> bool {
329 match &config.kernel_hash {
330 Some(expected) => {
331 let matches = computed_hash == expected;
332 if matches {
333 println!("[SECBOOT] Kernel hash matches expected value");
334 } else {
335 println!("[SECBOOT] Kernel hash MISMATCH");
336 println!(
337 "[SECBOOT] Expected: {:02X}{:02X}{:02X}{:02X}...",
338 expected[0], expected[1], expected[2], expected[3]
339 );
340 println!(
341 "[SECBOOT] Computed: {:02X}{:02X}{:02X}{:02X}...",
342 computed_hash[0], computed_hash[1], computed_hash[2], computed_hash[3]
343 );
344 }
345 matches
346 }
347 None => {
348 println!("[SECBOOT] No expected kernel hash configured");
349 false
350 }
351 }
352}
353
354fn extend_pcr(pcr_index: u8, measurement: &[u8; 32]) {
363 match super::tpm::pcr_extend(pcr_index, measurement) {
364 Ok(()) => {
365 println!("[SECBOOT] Extended TPM PCR {} with measurement", pcr_index);
366 }
367 Err(_e) => {
368 println!(
369 "[SECBOOT] TPM PCR extend failed for PCR {}: {:?} (continuing)",
370 pcr_index, _e
371 );
372 }
373 }
374}
375
376pub fn measure_boot_stage(
385 stage: &'static str,
386 data: &[u8],
387 pcr_index: Option<u8>,
388) -> Result<[u8; 32], KernelError> {
389 let hash = sha256(data);
390 let hash_bytes = *hash.as_bytes();
391
392 let timestamp = get_boot_timestamp();
394
395 let mut state = STATE.lock();
396 if let Some(_idx) = state
397 .measurement_log
398 .record(stage, hash_bytes, timestamp, pcr_index)
399 {
400 println!(
401 "[SECBOOT] Measurement #{}: '{}' hash={:02X}{:02X}{:02X}{:02X}...",
402 _idx, stage, hash_bytes[0], hash_bytes[1], hash_bytes[2], hash_bytes[3]
403 );
404 } else {
405 println!(
406 "[SECBOOT] Warning: measurement log full, could not record '{}'",
407 stage
408 );
409 }
410 drop(state);
411
412 if let Some(pcr) = pcr_index {
414 extend_pcr(pcr, &hash_bytes);
415 }
416
417 Ok(hash_bytes)
418}
419
420fn get_boot_timestamp() -> u64 {
424 use core::sync::atomic::{AtomicU64, Ordering};
425 static COUNTER: AtomicU64 = AtomicU64::new(0);
426 COUNTER.fetch_add(1, Ordering::Relaxed)
427}
428
429pub fn verify() -> Result<(), KernelError> {
446 let state = STATE.lock();
447 let enabled = state.config.enabled;
448 let enforce = state.config.enforce;
449 drop(state);
450
451 if !enabled {
452 println!("[SECBOOT] Secure boot disabled");
453 let mut state = STATE.lock();
457 state.last_status = BootStatus::Disabled;
458 drop(state);
459 return Ok(());
460 }
461
462 println!("[SECBOOT] Verifying secure boot chain...");
463
464 let kernel_hash = compute_kernel_hash()?;
466
467 {
469 let mut state = STATE.lock();
470 let ts = get_boot_timestamp();
471 state
472 .measurement_log
473 .record("kernel_image", kernel_hash, ts, Some(0));
474 }
475 extend_pcr(0, &kernel_hash);
476
477 let state_guard = STATE.lock();
479 let sig_valid = verify_kernel_signature(&kernel_hash, &state_guard.config)?;
480 let hash_valid = verify_hash_only(&kernel_hash, &state_guard.config);
481 let has_signature = state_guard.config.signature.is_some();
482 drop(state_guard);
483
484 let status = if has_signature && sig_valid {
486 BootStatus::Verified
487 } else if hash_valid {
488 BootStatus::HashOnly
489 } else if !has_signature && !state_guard_has_expected_hash() {
490 println!("[SECBOOT] No verification material configured");
492 BootStatus::NotSupported
493 } else {
494 BootStatus::Failed
495 };
496
497 {
499 let mut state = STATE.lock();
500 state.last_status = status;
501 }
502
503 match status {
504 BootStatus::Verified => {
505 println!("[SECBOOT] Secure boot verification PASSED (signature valid)");
506 Ok(())
507 }
508 BootStatus::HashOnly => {
509 println!("[SECBOOT] Secure boot verification PASSED (hash match, no signature)");
510 Ok(())
511 }
512 BootStatus::NotSupported => {
513 println!("[SECBOOT] Secure boot: no verification material configured");
514 if enforce {
515 Err(KernelError::NotImplemented {
516 feature: "secure boot verification material",
517 })
518 } else {
519 Ok(())
520 }
521 }
522 BootStatus::Failed => {
523 println!("[SECBOOT] Secure boot verification FAILED");
524 if enforce {
525 Err(KernelError::PermissionDenied {
526 operation: "secure boot enforcement",
527 })
528 } else {
529 println!("[SECBOOT] Non-enforcing mode -- continuing despite failure");
530 Ok(())
531 }
532 }
533 BootStatus::Disabled => {
534 Ok(())
536 }
537 }
538}
539
540fn state_guard_has_expected_hash() -> bool {
543 let state = STATE.lock();
544 state.config.kernel_hash.is_some()
545}
546
547pub fn enable(enforce: bool) {
553 let mut state = STATE.lock();
554 state.config.enabled = true;
555 state.config.enforce = enforce;
556 println!("[SECBOOT] Secure boot enabled (enforce={})", enforce);
557}
558
559pub fn disable() {
561 let mut state = STATE.lock();
562 state.config.enabled = false;
563 state.config.enforce = false;
564 state.last_status = BootStatus::Disabled;
565 println!("[SECBOOT] Secure boot disabled");
566}
567
568pub fn set_expected_hash(hash: [u8; 32]) {
570 let mut state = STATE.lock();
571 state.config.kernel_hash = Some(hash);
572}
573
574pub fn set_signature(signature: BootSignature, public_key: [u8; 32]) {
576 let mut state = STATE.lock();
577 state.config.signature = Some(signature);
578 state.config.signer_public_key = Some(public_key);
579}
580
581pub fn get_status() -> BootStatus {
583 let state = STATE.lock();
584 state.last_status
585}
586
587pub fn measurement_count() -> usize {
589 let state = STATE.lock();
590 state.measurement_log.len()
591}
592
593pub fn get_measurement(index: usize) -> Option<(&'static str, [u8; 32], u64, Option<u8>)> {
598 let state = STATE.lock();
599 state
600 .measurement_log
601 .get(index)
602 .map(|m| (m.stage, m.hash, m.timestamp, m.pcr_index))
603}
604
605pub fn print_measurement_log() {
607 let state = STATE.lock();
608 println!(
609 "[SECBOOT] Boot Measurement Log ({} entries):",
610 state.measurement_log.len()
611 );
612 for i in 0..state.measurement_log.len() {
613 if let Some(_m) = state.measurement_log.get(i) {
614 println!(
615 "[SECBOOT] #{}: stage='{}' hash={:02X}{:02X}{:02X}{:02X}... pcr={:?} ts={}",
616 i,
617 _m.stage,
618 _m.hash[0],
619 _m.hash[1],
620 _m.hash[2],
621 _m.hash[3],
622 _m.pcr_index,
623 _m.timestamp
624 );
625 }
626 }
627}
628
629#[cfg(test)]
630mod tests {
631 use super::*;
632
633 #[cfg(target_os = "none")]
636 #[test]
637 fn test_kernel_hash() {
638 let hash = compute_kernel_hash();
639 assert!(hash.is_ok());
640 let h = hash.unwrap();
641 assert_ne!(h, [0u8; 32]);
643 }
644
645 #[test]
646 fn test_verify_disabled() {
647 assert!(verify().is_ok());
649 }
650
651 #[test]
652 fn test_boot_measurement_log() {
653 let mut log = BootMeasurementLog::new();
654 assert!(log.is_empty());
655
656 let hash = [0x42u8; 32];
657 let idx = log.record("test_stage", hash, 100, Some(0));
658 assert_eq!(idx, Some(0));
659 assert_eq!(log.len(), 1);
660 assert!(!log.is_empty());
661
662 let m = log.get(0).unwrap();
663 assert_eq!(m.stage, "test_stage");
664 assert_eq!(m.hash, hash);
665 assert_eq!(m.timestamp, 100);
666 assert_eq!(m.pcr_index, Some(0));
667 }
668
669 #[test]
670 fn test_measure_boot_stage() {
671 let data = b"test boot stage data";
672 let result = measure_boot_stage("test_boot", data, None);
673 assert!(result.is_ok());
674 let hash = result.unwrap();
675 let expected = sha256(data);
677 assert_eq!(&hash, expected.as_bytes());
678 }
679}