tpm/
resolver.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use crate::Tpm;
5use crate::TpmError;
6use crate::ak_cert::TpmAkCertType;
7use async_trait::async_trait;
8use chipset_device_resources::ResolveChipsetDeviceHandleParams;
9use chipset_device_resources::ResolvedChipsetDevice;
10use thiserror::Error;
11use tpm_resources::TpmAkCertTypeResource;
12use tpm_resources::TpmDeviceHandle;
13use vm_resource::AsyncResolveResource;
14use vm_resource::ResolveError;
15use vm_resource::ResourceResolver;
16use vm_resource::declare_static_async_resolver;
17use vm_resource::kind::ChipsetDeviceHandleKind;
18
19pub struct TpmDeviceResolver;
20
21declare_static_async_resolver! {
22    TpmDeviceResolver,
23    (ChipsetDeviceHandleKind, TpmDeviceHandle),
24}
25
26#[derive(Debug, Error)]
27pub enum ResolveTpmError {
28    #[error("error resolving ppi store")]
29    ResolvePpiStore(#[source] ResolveError),
30    #[error("error resolving nvram store")]
31    ResolveNvramStore(#[source] ResolveError),
32    #[error("error resolving get attestation report")]
33    ResolveGetAttestationReport(#[source] ResolveError),
34    #[error("error resolving request ak cert")]
35    ResolveRequestAkCert(#[source] ResolveError),
36    #[error("error resolving request TPM logger")]
37    ResolveTpmLogger(#[source] ResolveError),
38    #[error("error creating tpm")]
39    Tpm(#[source] TpmError),
40    #[error(
41        "invalid AK cert type: `get_attestation_report` is `Some`, `request_ak_cert` is `None`"
42    )]
43    InvalidAkCertType,
44}
45
46#[async_trait]
47impl AsyncResolveResource<ChipsetDeviceHandleKind, TpmDeviceHandle> for TpmDeviceResolver {
48    type Error = ResolveTpmError;
49    type Output = ResolvedChipsetDevice;
50
51    async fn resolve(
52        &self,
53        resolver: &ResourceResolver,
54        resource: TpmDeviceHandle,
55        input: ResolveChipsetDeviceHandleParams<'_>,
56    ) -> Result<Self::Output, Self::Error> {
57        let ppi_store = resolver
58            .resolve(resource.ppi_store, ())
59            .await
60            .map_err(ResolveTpmError::ResolvePpiStore)?;
61
62        let nvram_store = resolver
63            .resolve(resource.nvram_store, ())
64            .await
65            .map_err(ResolveTpmError::ResolveNvramStore)?;
66
67        let ak_cert_type = match resource.ak_cert_type {
68            TpmAkCertTypeResource::HwAttested(request_ak_cert) => TpmAkCertType::HwAttested(
69                resolver
70                    .resolve(request_ak_cert, &())
71                    .await
72                    .map_err(ResolveTpmError::ResolveRequestAkCert)?
73                    .0,
74            ),
75            TpmAkCertTypeResource::Trusted(request_ak_cert) => TpmAkCertType::Trusted(
76                resolver
77                    .resolve(request_ak_cert, &())
78                    .await
79                    .map_err(ResolveTpmError::ResolveRequestAkCert)?
80                    .0,
81            ),
82            TpmAkCertTypeResource::None => TpmAkCertType::None,
83        };
84
85        // The TPM device doesn't need access to the entire API of `vmtime`, so
86        // to make it easier to unit test / fuzz, only pass the TPM a small
87        // callback it can use to obtain a monotonically increasing timestamp.
88        let monotonic_timer = Box::new({
89            let vmtime = input.vmtime.access("tpm");
90            move || {
91                const NUM_100NS_IN_SEC: u64 = 10 * 1000 * 1000;
92                let n = vmtime.now().as_100ns();
93                std::time::Duration::new(n / NUM_100NS_IN_SEC, (n % NUM_100NS_IN_SEC) as u32 * 100)
94            }
95        });
96
97        let logger = if let Some(r) = resource.logger {
98            Some(
99                resolver
100                    .resolve(r, &())
101                    .await
102                    .map_err(ResolveTpmError::ResolveTpmLogger)?
103                    .0,
104            )
105        } else {
106            None
107        };
108
109        let tpm = Tpm::new(
110            resource.register_layout,
111            input.encrypted_guest_memory.clone(),
112            ppi_store.0,
113            nvram_store.0,
114            monotonic_timer,
115            resource.refresh_tpm_seeds,
116            input.is_restoring,
117            ak_cert_type,
118            resource.guest_secret_key,
119            logger,
120        )
121        .await
122        .map_err(ResolveTpmError::Tpm)?;
123
124        Ok(tpm.into())
125    }
126}