pub const DEFAULT_MIN_SLSA_LEVEL: u8 = 1;
pub const DEFAULT_MAX_QUOTE_AGE_SECS: u64 = 300;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct PolicyConfig {
pub min_slsa_level: u8,
pub max_quote_age_secs: u64,
pub require_firmware_hash: bool,
pub require_event_counter: bool,
}
impl Default for PolicyConfig {
fn default() -> Self {
Self {
min_slsa_level: DEFAULT_MIN_SLSA_LEVEL,
max_quote_age_secs: DEFAULT_MAX_QUOTE_AGE_SECS,
require_firmware_hash: true,
require_event_counter: false,
}
}
}
impl PolicyConfig {
pub fn evaluate(
&self,
slsa_level: u8,
firmware_hash: &[u8; 32],
event_counter: u64,
quote_timestamp: u64,
now_secs: u64,
) -> Result<(), crate::error::PqRascvError> {
use crate::error::PqRascvError;
if slsa_level < self.min_slsa_level {
return Err(PqRascvError::PolicyViolation);
}
if self.require_firmware_hash && firmware_hash == &[0u8; 32] {
return Err(PqRascvError::PolicyViolation);
}
if self.require_event_counter && event_counter == 0 {
return Err(PqRascvError::PolicyViolation);
}
if self.max_quote_age_secs > 0 {
let age = now_secs.saturating_sub(quote_timestamp);
if age > self.max_quote_age_secs {
return Err(PqRascvError::PolicyViolation);
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_policy_accepts_valid_quote() {
let policy = PolicyConfig::default();
let result = policy.evaluate(
1,
&[0xabu8; 32],
0,
1_000,
1_100,
);
assert!(result.is_ok());
}
#[test]
fn policy_rejects_low_slsa_level() {
let policy = PolicyConfig {
min_slsa_level: 3,
..Default::default()
};
assert!(policy.evaluate(2, &[0xabu8; 32], 0, 1_000, 1_100).is_err());
}
#[test]
fn policy_rejects_zero_firmware_hash() {
let policy = PolicyConfig {
require_firmware_hash: true,
..Default::default()
};
assert!(policy.evaluate(1, &[0u8; 32], 0, 1_000, 1_100).is_err());
}
#[test]
fn policy_rejects_stale_quote() {
let policy = PolicyConfig {
max_quote_age_secs: 60,
..Default::default()
};
assert!(policy.evaluate(1, &[0xabu8; 32], 0, 1_000, 1_120).is_err());
}
#[test]
fn policy_accepts_zero_age_check() {
let policy = PolicyConfig {
max_quote_age_secs: 0,
..Default::default()
};
assert!(policy.evaluate(1, &[0xabu8; 32], 0, 1_000, 11_000).is_ok());
}
}