underhill_core/emuplat/
tpm.rs1use guest_emulation_transport::GuestEmulationTransportClient;
5use guest_emulation_transport::api::EventLogId;
6use openhcl_attestation_protocol::igvm_attest::get::AK_CERT_RESPONSE_BUFFER_SIZE;
7use openhcl_attestation_protocol::igvm_attest::get::runtime_claims::AttestationVmConfig;
8use std::sync::Arc;
9use thiserror::Error;
10use tpm::ak_cert::RequestAkCert;
11use tpm::logger::TpmLogEvent;
12use tpm::logger::TpmLogger;
13use underhill_attestation::AttestationType;
14
15#[derive(Debug, Error)]
16pub enum TpmAttestationError {
17 #[error("failed to get a hardware attestation report")]
18 GetAttestationReport(#[source] tee_call::Error),
19 #[error("failed to create the IgvmAttest AK_CERT request")]
20 CreateAkCertRequest(#[source] underhill_attestation::IgvmAttestError),
21}
22
23pub struct TpmRequestAkCertHelper {
25 get_client: GuestEmulationTransportClient,
26 tee_call: Option<Arc<dyn tee_call::TeeCall>>,
27 attestation_type: AttestationType,
28 attestation_vm_config: AttestationVmConfig,
29 attestation_agent_data: Option<Vec<u8>>,
30}
31
32impl TpmRequestAkCertHelper {
33 pub fn new(
34 get_client: GuestEmulationTransportClient,
35 tee_call: Option<Arc<dyn tee_call::TeeCall>>,
36 attestation_type: AttestationType,
37 attestation_vm_config: AttestationVmConfig,
38 attestation_agent_data: Option<Vec<u8>>,
39 ) -> Self {
40 Self {
41 get_client,
42 tee_call,
43 attestation_type,
44 attestation_vm_config,
45 attestation_agent_data,
46 }
47 }
48}
49
50#[async_trait::async_trait]
51impl RequestAkCert for TpmRequestAkCertHelper {
52 fn create_ak_cert_request(
53 &self,
54 ak_pub_modulus: &[u8],
55 ak_pub_exponent: &[u8],
56 ek_pub_modulus: &[u8],
57 ek_pub_exponent: &[u8],
58 guest_input: &[u8],
59 ) -> Result<Vec<u8>, Box<dyn std::error::Error + Send + Sync>> {
60 let tee_type = match self.attestation_type {
61 AttestationType::Snp => Some(tee_call::TeeType::Snp),
62 AttestationType::Tdx => Some(tee_call::TeeType::Tdx),
63 AttestationType::Host => None,
64 };
65 let ak_cert_request_helper =
66 underhill_attestation::IgvmAttestRequestHelper::prepare_ak_cert_request(
67 tee_type,
68 ak_pub_exponent,
69 ak_pub_modulus,
70 ek_pub_exponent,
71 ek_pub_modulus,
72 &self.attestation_vm_config,
73 guest_input,
74 );
75
76 let attestation_report = if let Some(tee_call) = &self.tee_call {
77 tee_call
78 .get_attestation_report(ak_cert_request_helper.get_runtime_claims_hash())
79 .map_err(TpmAttestationError::GetAttestationReport)?
80 .report
81 } else {
82 vec![]
83 };
84
85 let request = ak_cert_request_helper
86 .create_request(&attestation_report)
87 .map_err(TpmAttestationError::CreateAkCertRequest)?;
88
89 Ok(request)
91 }
92
93 async fn request_ak_cert(
94 &self,
95 request: Vec<u8>,
96 ) -> Result<Vec<u8>, Box<dyn std::error::Error + Send + Sync + 'static>> {
97 let agent_data = self.attestation_agent_data.clone().unwrap_or_default();
98 let result = self
99 .get_client
100 .igvm_attest(agent_data, request, AK_CERT_RESPONSE_BUFFER_SIZE)
101 .await?;
102 let payload = if !result.response.is_empty() {
103 underhill_attestation::parse_ak_cert_response(&result.response)?
104 } else {
105 vec![]
107 };
108
109 Ok(payload)
110 }
111}
112
113pub struct GetTpmLogger {
115 get_client: GuestEmulationTransportClient,
116}
117
118impl GetTpmLogger {
119 pub fn new(get_client: GuestEmulationTransportClient) -> Self {
120 Self { get_client }
121 }
122}
123
124fn convert_to_get_event_id(event: TpmLogEvent) -> EventLogId {
125 match event {
126 TpmLogEvent::AkCertRenewalFailed => EventLogId::CERTIFICATE_RENEWAL_FAILED,
127 TpmLogEvent::IdentityChangeFailed => EventLogId::TPM_IDENTITY_CHANGE_FAILED,
128 TpmLogEvent::InvalidState => EventLogId::TPM_INVALID_STATE,
129 }
130}
131
132#[async_trait::async_trait]
133impl TpmLogger for GetTpmLogger {
134 async fn log_event_and_flush(&self, event: TpmLogEvent) {
135 self.get_client
136 .event_log_fatal(convert_to_get_event_id(event))
137 .await
138 }
139
140 fn log_event(&self, event: TpmLogEvent) {
141 self.get_client.event_log(convert_to_get_event_id(event));
142 }
143}
144
145pub mod resources {
146 use super::GetTpmLogger;
147 use super::TpmRequestAkCertHelper;
148 use async_trait::async_trait;
149 use guest_emulation_transport::resolver::GetClientKind;
150 use mesh::MeshPayload;
151 use openhcl_attestation_protocol::igvm_attest::get::runtime_claims::AttestationVmConfig;
152 use std::sync::Arc;
153 use tpm::ak_cert::ResolvedRequestAkCert;
154 use tpm::logger::ResolvedTpmLogger;
155 use tpm_resources::RequestAkCertKind;
156 use tpm_resources::TpmLoggerKind;
157 use underhill_attestation::AttestationType;
158 use vm_resource::AsyncResolveResource;
159 use vm_resource::IntoResource;
160 use vm_resource::PlatformResource;
161 use vm_resource::ResolveError;
162 use vm_resource::ResourceId;
163 use vm_resource::ResourceResolver;
164 use vm_resource::declare_static_async_resolver;
165
166 #[derive(MeshPayload)]
167 pub struct GetTpmRequestAkCertHelperHandle {
168 attestation_type: AttestationType,
169 attestation_vm_config: AttestationVmConfig,
170 attestation_agent_data: Option<Vec<u8>>,
171 }
172
173 impl GetTpmRequestAkCertHelperHandle {
174 pub fn new(
175 attestation_type: AttestationType,
176 attestation_vm_config: AttestationVmConfig,
177 attestation_agent_data: Option<Vec<u8>>,
178 ) -> Self {
179 Self {
180 attestation_type,
181 attestation_vm_config,
182 attestation_agent_data,
183 }
184 }
185 }
186
187 impl ResourceId<RequestAkCertKind> for GetTpmRequestAkCertHelperHandle {
188 const ID: &'static str = "request_ak_cert";
189 }
190
191 pub struct GetTpmRequestAkCertHelperResolver;
192
193 declare_static_async_resolver! {
194 GetTpmRequestAkCertHelperResolver,
195 (RequestAkCertKind, GetTpmRequestAkCertHelperHandle)
196 }
197
198 #[async_trait]
199 impl AsyncResolveResource<RequestAkCertKind, GetTpmRequestAkCertHelperHandle>
200 for GetTpmRequestAkCertHelperResolver
201 {
202 type Output = ResolvedRequestAkCert;
203 type Error = ResolveError;
204
205 async fn resolve(
206 &self,
207 resolver: &ResourceResolver,
208 handle: GetTpmRequestAkCertHelperHandle,
209 _: &(),
210 ) -> Result<Self::Output, Self::Error> {
211 let get = resolver
212 .resolve::<GetClientKind, _>(PlatformResource.into_resource(), ())
213 .await?;
214
215 let tee_call: Option<Arc<dyn tee_call::TeeCall>> = match handle.attestation_type {
216 AttestationType::Snp => Some(Arc::new(tee_call::SnpCall)),
217 AttestationType::Tdx => Some(Arc::new(tee_call::TdxCall)),
218 AttestationType::Host => None,
219 };
220
221 Ok(TpmRequestAkCertHelper::new(
222 get,
223 tee_call,
224 handle.attestation_type,
225 handle.attestation_vm_config,
226 handle.attestation_agent_data,
227 )
228 .into())
229 }
230 }
231
232 #[derive(MeshPayload)]
233 pub struct GetTpmLoggerHandle;
234
235 impl ResourceId<TpmLoggerKind> for GetTpmLoggerHandle {
236 const ID: &'static str = "tpm_logger";
237 }
238
239 pub struct GetTpmLoggerResolver;
240
241 declare_static_async_resolver! {
242 GetTpmLoggerResolver,
243 (TpmLoggerKind, GetTpmLoggerHandle)
244 }
245
246 #[async_trait]
247 impl AsyncResolveResource<TpmLoggerKind, GetTpmLoggerHandle> for GetTpmLoggerResolver {
248 type Output = ResolvedTpmLogger;
249 type Error = ResolveError;
250
251 async fn resolve(
252 &self,
253 resolver: &ResourceResolver,
254 GetTpmLoggerHandle: GetTpmLoggerHandle,
255 _: &(),
256 ) -> Result<Self::Output, Self::Error> {
257 let get = resolver
258 .resolve::<GetClientKind, _>(PlatformResource.into_resource(), ())
259 .await?;
260
261 Ok(GetTpmLogger::new(get).into())
262 }
263 }
264}