1#![cfg(target_os = "linux")]
8#![forbid(unsafe_code)]
9
10use hcl::ioctl::MshvHvcall;
11use hvdef::HypercallCode;
12use thiserror::Error;
13use zerocopy::IntoBytes;
14
15#[expect(missing_docs)] #[derive(Debug, Error)]
17pub enum Error {
18 #[error("failed to open /dev/sev-guest")]
19 OpenDevSevGuest(#[source] sev_guest_device::Error),
20 #[error("failed to get an SNP report via /dev/sev-guest")]
21 GetSnpReport(#[source] sev_guest_device::Error),
22 #[error("failed to get an SNP derived key via /dev/sev-guest")]
23 GetSnpDerivedKey(#[source] sev_guest_device::Error),
24 #[error("got all-zeros key")]
25 AllZeroKey,
26 #[error("failed to open /dev/tdx_guest")]
27 OpenDevTdxGuest(#[source] tdx_guest_device::Error),
28 #[error("failed to get a TDX report via /dev/tdx_guest")]
29 GetTdxReport(#[source] tdx_guest_device::Error),
30 #[error("failed to open VBS guest device")]
31 OpenDevVbsGuest(#[source] hcl::ioctl::Error),
32 #[error("failed to get a VBS report via VBS guest device")]
33 GetVbsReport(#[source] hvdef::HvError),
34}
35
36pub const HW_DERIVED_KEY_LENGTH: usize = x86defs::snp::SNP_DERIVED_KEY_SIZE;
38
39pub const REPORT_DATA_SIZE: usize = x86defs::snp::SNP_REPORT_DATA_SIZE;
42
43static_assertions::const_assert_eq!(
45 x86defs::snp::SNP_REPORT_DATA_SIZE,
46 x86defs::tdx::TDX_REPORT_DATA_SIZE
47);
48
49#[derive(Debug)]
51pub enum TeeType {
52 Snp,
54 Tdx,
56 Cca,
58 Vbs,
60}
61
62pub struct GetAttestationReportResult {
64 pub report: Vec<u8>,
66 pub tcb_version: Option<u64>,
68}
69
70pub trait TeeCall: Send + Sync {
73 fn get_attestation_report(
75 &self,
76 report_data: &[u8; REPORT_DATA_SIZE],
77 ) -> Result<GetAttestationReportResult, Error>;
78 fn supports_get_derived_key(&self) -> Option<&dyn TeeCallGetDerivedKey>;
80 fn tee_type(&self) -> TeeType;
82}
83
84pub trait TeeCallGetDerivedKey: TeeCall {
86 fn get_derived_key(&self, tcb_version: u64) -> Result<[u8; HW_DERIVED_KEY_LENGTH], Error>;
89}
90
91pub struct SnpCall;
93
94impl TeeCall for SnpCall {
95 fn get_attestation_report(
97 &self,
98 report_data: &[u8; REPORT_DATA_SIZE],
99 ) -> Result<GetAttestationReportResult, Error> {
100 let dev = sev_guest_device::SevGuestDevice::open().map_err(Error::OpenDevSevGuest)?;
101 let report = dev
102 .get_report(*report_data, 0)
103 .map_err(Error::GetSnpReport)?;
104
105 Ok(GetAttestationReportResult {
106 report: report.as_bytes().to_vec(),
107 tcb_version: Some(report.reported_tcb),
108 })
109 }
110
111 fn supports_get_derived_key(&self) -> Option<&dyn TeeCallGetDerivedKey> {
113 Some(self)
114 }
115
116 fn tee_type(&self) -> TeeType {
118 TeeType::Snp
119 }
120}
121
122impl TeeCallGetDerivedKey for SnpCall {
123 fn get_derived_key(&self, tcb_version: u64) -> Result<[u8; HW_DERIVED_KEY_LENGTH], Error> {
125 let dev = sev_guest_device::SevGuestDevice::open().map_err(Error::OpenDevSevGuest)?;
126
127 let guest_field_select = x86defs::snp::GuestFieldSelect::default()
132 .with_guest_policy(true)
133 .with_measurement(true)
134 .with_tcb_version(true);
135
136 let derived_key = dev
137 .get_derived_key(
138 0, guest_field_select.into(),
140 0, 0, tcb_version,
143 )
144 .map_err(Error::GetSnpDerivedKey)?;
145
146 if derived_key.iter().all(|&x| x == 0) {
147 Err(Error::AllZeroKey)?
148 }
149
150 Ok(derived_key)
151 }
152}
153
154pub struct TdxCall;
156
157impl TeeCall for TdxCall {
158 fn get_attestation_report(
159 &self,
160 report_data: &[u8; REPORT_DATA_SIZE],
161 ) -> Result<GetAttestationReportResult, Error> {
162 let dev = tdx_guest_device::TdxGuestDevice::open().map_err(Error::OpenDevTdxGuest)?;
163 let report = dev
164 .get_report(*report_data, 0)
165 .map_err(Error::GetTdxReport)?;
166
167 Ok(GetAttestationReportResult {
168 report: report.as_bytes().to_vec(),
169 tcb_version: None,
171 })
172 }
173
174 fn supports_get_derived_key(&self) -> Option<&dyn TeeCallGetDerivedKey> {
176 None
177 }
178
179 fn tee_type(&self) -> TeeType {
181 TeeType::Tdx
182 }
183}
184
185pub struct VbsCall;
187
188impl TeeCall for VbsCall {
189 fn get_attestation_report(
190 &self,
191 report_data: &[u8; REPORT_DATA_SIZE],
192 ) -> Result<GetAttestationReportResult, Error> {
193 let mshv_hvcall = MshvHvcall::new().map_err(Error::OpenDevVbsGuest)?;
194 mshv_hvcall.set_allowed_hypercalls(&[HypercallCode::HvCallVbsVmCallReport]);
195 let report = mshv_hvcall
196 .vbs_vm_call_report(report_data)
197 .map_err(Error::GetVbsReport)?;
198
199 Ok(GetAttestationReportResult {
200 report: report[..hvdef::vbs::VBS_REPORT_SIZE].to_vec(),
201 tcb_version: None,
203 })
204 }
205
206 fn supports_get_derived_key(&self) -> Option<&dyn TeeCallGetDerivedKey> {
208 None
209 }
210
211 fn tee_type(&self) -> TeeType {
213 TeeType::Vbs
214 }
215}