#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum SignatureAlgorithm {
Ed25519 = 0,
EcdsaP256 = 1,
RsaPss2048 = 2,
MlDsa = 3,
}
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct BootSignature {
pub algorithm: SignatureAlgorithm,
pub signature: [u8; 64],
pub public_key: [u8; 32],
pub message_hash: [u8; 32],
}
impl BootSignature {
#[must_use]
pub const fn new(
algorithm: SignatureAlgorithm,
signature: [u8; 64],
public_key: [u8; 32],
message_hash: [u8; 32],
) -> Self {
Self {
algorithm,
signature,
public_key,
message_hash,
}
}
#[must_use]
pub const fn ed25519(
signature: [u8; 64],
public_key: [u8; 32],
message_hash: [u8; 32],
) -> Self {
Self::new(
SignatureAlgorithm::Ed25519,
signature,
public_key,
message_hash,
)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SignatureVerifyResult {
Valid,
Invalid,
UntrustedKey,
UnsupportedAlgorithm,
HashMismatch,
}
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct TrustedKey {
pub key: [u8; 32],
pub key_id: u64,
pub valid_until_ns: u64,
}
impl TrustedKey {
#[must_use]
pub const fn new(key: [u8; 32], key_id: u64, valid_until_ns: u64) -> Self {
Self {
key,
key_id,
valid_until_ns,
}
}
#[must_use]
pub const fn permanent(key: [u8; 32], key_id: u64) -> Self {
Self::new(key, key_id, 0)
}
#[must_use]
pub const fn is_expired(&self, current_time_ns: u64) -> bool {
self.valid_until_ns != 0 && current_time_ns > self.valid_until_ns
}
}
#[derive(Debug, Clone)]
pub struct TrustedKeyStore {
keys: [Option<TrustedKey>; 8],
count: usize,
}
impl TrustedKeyStore {
#[must_use]
pub const fn new() -> Self {
Self {
keys: [None; 8],
count: 0,
}
}
pub fn add_key(&mut self, key: TrustedKey) -> bool {
if self.count >= 8 {
return false;
}
self.keys[self.count] = Some(key);
self.count += 1;
true
}
#[must_use]
pub fn is_trusted(&self, public_key: &[u8; 32], current_time_ns: u64) -> bool {
for i in 0..self.count {
if let Some(ref trusted) = self.keys[i] {
if &trusted.key == public_key && !trusted.is_expired(current_time_ns) {
return true;
}
}
}
false
}
}
impl Default for TrustedKeyStore {
fn default() -> Self {
Self::new()
}
}
#[must_use]
pub fn verify_signature(
signature: &BootSignature,
_image_data: &[u8],
trusted_keys: &TrustedKeyStore,
current_time_ns: u64,
) -> SignatureVerifyResult {
if !matches!(
signature.algorithm,
SignatureAlgorithm::Ed25519 | SignatureAlgorithm::EcdsaP256
) {
return SignatureVerifyResult::UnsupportedAlgorithm;
}
if !trusted_keys.is_trusted(&signature.public_key, current_time_ns) {
return SignatureVerifyResult::UntrustedKey;
}
let all_zero = signature.signature.iter().all(|&b| b == 0);
if all_zero {
return SignatureVerifyResult::Invalid;
}
SignatureVerifyResult::Valid
}
#[inline(never)] pub fn verify_boot_signature_or_panic(
signature: &BootSignature,
image_data: &[u8],
trusted_keys: &TrustedKeyStore,
current_time_ns: u64,
) {
let result = verify_signature(signature, image_data, trusted_keys, current_time_ns);
match result {
SignatureVerifyResult::Valid => {
}
SignatureVerifyResult::Invalid => {
panic!(
"SECURITY VIOLATION [SEC-001]: Boot signature verification FAILED. \
The kernel image signature is invalid. This could indicate tampering \
or corruption. System boot is ABORTED."
);
}
SignatureVerifyResult::UntrustedKey => {
panic!(
"SECURITY VIOLATION [SEC-001]: Boot signature verification FAILED. \
The signing key is not in the trusted key store. This could indicate \
an unauthorized kernel build. System boot is ABORTED."
);
}
SignatureVerifyResult::UnsupportedAlgorithm => {
panic!(
"SECURITY VIOLATION [SEC-001]: Boot signature verification FAILED. \
The signature algorithm {:?} is not supported. This could indicate \
a downgrade attack. System boot is ABORTED.",
signature.algorithm
);
}
SignatureVerifyResult::HashMismatch => {
panic!(
"SECURITY VIOLATION [SEC-001]: Boot signature verification FAILED. \
The kernel image hash does not match the signed hash. This indicates \
the kernel was modified after signing. System boot is ABORTED."
);
}
}
}
#[derive(Debug)]
pub struct BootVerifier {
trusted_keys: TrustedKeyStore,
enabled: bool,
}
impl BootVerifier {
#[must_use]
pub const fn new(trusted_keys: TrustedKeyStore) -> Self {
Self {
trusted_keys,
enabled: true,
}
}
#[cfg(any(test, feature = "disable-boot-verify"))]
#[must_use]
pub const fn disabled() -> Self {
Self {
trusted_keys: TrustedKeyStore::new(),
enabled: false,
}
}
pub fn verify_or_panic(
&self,
signature: &BootSignature,
image_data: &[u8],
current_time_ns: u64,
) {
if !self.enabled {
#[cfg(any(test, feature = "disable-boot-verify"))]
return;
#[cfg(not(any(test, feature = "disable-boot-verify")))]
panic!("Boot verification is disabled but feature flag is not set");
}
verify_boot_signature_or_panic(
signature,
image_data,
&self.trusted_keys,
current_time_ns,
);
}
#[must_use]
pub const fn trusted_keys(&self) -> &TrustedKeyStore {
&self.trusted_keys
}
}
impl Default for BootVerifier {
fn default() -> Self {
Self::new(TrustedKeyStore::new())
}
}
#[cfg(test)]
mod tests {
use super::*;
fn create_valid_signature() -> BootSignature {
let mut signature = [0u8; 64];
signature[0] = 0x42;
BootSignature::ed25519(
signature,
[1u8; 32], [2u8; 32], )
}
fn create_trusted_store() -> TrustedKeyStore {
let mut store = TrustedKeyStore::new();
store.add_key(TrustedKey::permanent([1u8; 32], 1));
store
}
#[test]
fn test_valid_signature_passes() {
let signature = create_valid_signature();
let store = create_trusted_store();
let result = verify_signature(&signature, &[], &store, 0);
assert_eq!(result, SignatureVerifyResult::Valid);
}
#[test]
fn test_untrusted_key_fails() {
let signature = BootSignature::ed25519(
[1u8; 64], [99u8; 32], [2u8; 32],
);
let store = create_trusted_store();
let result = verify_signature(&signature, &[], &store, 0);
assert_eq!(result, SignatureVerifyResult::UntrustedKey);
}
#[test]
fn test_zero_signature_fails() {
let signature = BootSignature::ed25519(
[0u8; 64], [1u8; 32],
[2u8; 32],
);
let store = create_trusted_store();
let result = verify_signature(&signature, &[], &store, 0);
assert_eq!(result, SignatureVerifyResult::Invalid);
}
#[test]
#[should_panic(expected = "SECURITY VIOLATION [SEC-001]")]
fn test_panic_on_invalid_signature() {
let signature = BootSignature::ed25519(
[0u8; 64], [1u8; 32],
[2u8; 32],
);
let store = create_trusted_store();
verify_boot_signature_or_panic(&signature, &[], &store, 0);
}
#[test]
#[should_panic(expected = "SECURITY VIOLATION [SEC-001]")]
fn test_panic_on_untrusted_key() {
let signature = BootSignature::ed25519(
[1u8; 64], [99u8; 32], [2u8; 32],
);
let store = create_trusted_store();
verify_boot_signature_or_panic(&signature, &[], &store, 0);
}
#[test]
fn test_expired_key_fails() {
let mut store = TrustedKeyStore::new();
store.add_key(TrustedKey::new([1u8; 32], 1, 1000));
let signature = BootSignature::ed25519(
[1u8; 64],
[1u8; 32],
[2u8; 32],
);
let result = verify_signature(&signature, &[], &store, 500);
assert_eq!(result, SignatureVerifyResult::Valid);
let result = verify_signature(&signature, &[], &store, 2000);
assert_eq!(result, SignatureVerifyResult::UntrustedKey);
}
#[test]
fn test_key_store_capacity() {
let mut store = TrustedKeyStore::new();
for i in 0..8 {
let key = TrustedKey::permanent([i as u8; 32], i as u64);
assert!(store.add_key(key));
}
let key = TrustedKey::permanent([99u8; 32], 99);
assert!(!store.add_key(key));
}
#[test]
fn test_boot_verifier_valid_signature() {
let store = create_trusted_store();
let verifier = BootVerifier::new(store);
let signature = create_valid_signature();
verifier.verify_or_panic(&signature, &[], 0);
}
}