Skip to main content

oasis_core_runtime/common/sgx/pcs/
policy.rs

1//! Quote policy.
2use super::{constants::*, report::TdReport, Error};
3
4/// Quote validity policy.
5#[derive(Clone, Debug, PartialEq, Eq, cbor::Encode, cbor::Decode)]
6pub struct QuotePolicy {
7    /// Whether PCS quotes are disabled and will always be rejected.
8    #[cbor(optional)]
9    pub disabled: bool,
10
11    /// Validity (in days) of the TCB collateral.
12    pub tcb_validity_period: u16,
13
14    /// Minimum TCB evaluation data number that is considered to be valid. TCB bundles containing
15    /// smaller values will be invalid.
16    pub min_tcb_evaluation_data_number: u32,
17
18    /// A list of hexadecimal encoded FMSPCs specifying which processor packages and platform
19    /// instances are allowed.
20    #[cbor(optional)]
21    pub fmspc_whitelist: Vec<String>,
22
23    /// A list of hexadecimal encoded FMSPCs specifying which processor packages and platform
24    /// instances are blocked.
25    #[cbor(optional)]
26    pub fmspc_blacklist: Vec<String>,
27
28    /// Optional TDX-specific policy. In case this is `None`, TDX quotes are disallowed.
29    #[cbor(optional)]
30    pub tdx: Option<TdxQuotePolicy>,
31}
32
33impl Default for QuotePolicy {
34    fn default() -> Self {
35        Self {
36            disabled: false,
37            tcb_validity_period: 30,
38            min_tcb_evaluation_data_number: DEFAULT_MIN_TCB_EVALUATION_DATA_NUMBER,
39            fmspc_whitelist: Vec::new(),
40            fmspc_blacklist: Vec::new(),
41            tdx: None,
42        }
43    }
44}
45
46impl QuotePolicy {
47    /// Whether the quote with timestamp `ts` is expired.
48    pub fn is_expired(&self, now: i64, ts: i64) -> bool {
49        if self.disabled {
50            return true;
51        }
52
53        now.checked_sub(ts)
54            .map(|d| d > 60 * 60 * 24 * (self.tcb_validity_period as i64))
55            .expect("quote timestamp is in the future") // This should never happen.
56    }
57}
58
59/// TDX-specific quote policy.
60#[derive(Clone, Debug, Default, PartialEq, Eq, cbor::Encode, cbor::Decode)]
61pub struct TdxQuotePolicy {
62    /// Allowed TDX modules. Empty to allow ANY Intel-signed module.
63    pub allowed_tdx_modules: Vec<TdxModulePolicy>,
64}
65
66impl TdxQuotePolicy {
67    /// Verify whether the TDX policy is satisfied for the given report.
68    pub fn verify(&self, report: &TdReport) -> Result<(), Error> {
69        self.verify_tdx_module(report)?;
70        Ok(())
71    }
72
73    fn verify_tdx_module(&self, report: &TdReport) -> Result<(), Error> {
74        // If at least one TDX Module matches, then we are good.
75        for allowed_module in &self.allowed_tdx_modules {
76            if allowed_module.matches(report) {
77                return Ok(());
78            }
79        }
80
81        // No module matched. Iff the list of modules is empty, allow ANY Intel-signed module.
82        // As per the TDX specifications, MRSIGNER is all-zero for Intel.
83        if self.allowed_tdx_modules.is_empty() && report.mr_signer_seam == TDX_MRSIGNER_INTEL {
84            return Ok(());
85        }
86
87        Err(Error::TdxModuleNotAllowed)
88    }
89}
90
91/// TDX module policy.
92#[derive(Clone, Debug, PartialEq, Eq, cbor::Encode, cbor::Decode)]
93#[cbor(no_default)]
94pub struct TdxModulePolicy {
95    /// Optional allowed measurement of the TDX Module. In case it is `None`, ANY measurement is
96    /// allowed and only the signer is checked.
97    pub mr_seam: Option<[u8; 48]>,
98
99    /// Allowed signer of the TDX Module (zero for Intel).
100    pub mr_signer_seam: [u8; 48],
101}
102
103impl TdxModulePolicy {
104    /// Returns true iff the TDX module in the given report matches this module policy.
105    pub fn matches(&self, report: &TdReport) -> bool {
106        // Check MRSEAM if set.
107        if let Some(mr_seam) = self.mr_seam {
108            if mr_seam != report.mr_seam {
109                return false;
110            }
111        }
112
113        // Check MRSIGNER.
114        if self.mr_signer_seam != report.mr_signer_seam {
115            return false;
116        }
117
118        true
119    }
120}