tss_esapi/structures/attestation/
attest.rs

1// Copyright 2021 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::{
5    constants::tss::TPM2_GENERATED_VALUE,
6    interface_types::structure_tags::AttestationType,
7    structures::{AttestInfo, ClockInfo, Data, Name},
8    traits::{Marshall, UnMarshall},
9    tss2_esys::TPMS_ATTEST,
10    Error, Result, WrapperErrorKind,
11};
12use log::error;
13use std::{
14    convert::{TryFrom, TryInto},
15    mem::size_of,
16};
17
18/// Type for holding attestation data
19///
20/// # Details
21/// Corresponds to `TPMS_ATTEST`.
22#[derive(Debug, Clone)]
23pub struct Attest {
24    attestation_type: AttestationType,
25    qualified_signer: Name,
26    extra_data: Data,
27    clock_info: ClockInfo,
28    firmware_version: u64,
29    attested: AttestInfo,
30}
31
32impl Attest {
33    /// Returns attestation type
34    pub const fn attestation_type(&self) -> AttestationType {
35        self.attestation_type
36    }
37
38    /// Returns the qualified name of the signing object.
39    pub const fn qualified_signer(&self) -> &Name {
40        &self.qualified_signer
41    }
42
43    /// Returns the extra data specified by the caller.
44    pub const fn extra_data(&self) -> &Data {
45        &self.extra_data
46    }
47
48    /// Returns the internal TPM clock data.
49    pub const fn clock_info(&self) -> &ClockInfo {
50        &self.clock_info
51    }
52
53    /// Returns TPM firmware version number.
54    pub const fn firmware_version(&self) -> u64 {
55        self.firmware_version
56    }
57
58    /// Returns types specific attestation information
59    pub const fn attested(&self) -> &AttestInfo {
60        &self.attested
61    }
62}
63
64impl From<Attest> for TPMS_ATTEST {
65    fn from(attest: Attest) -> Self {
66        TPMS_ATTEST {
67            magic: TPM2_GENERATED_VALUE,
68            type_: attest.attestation_type.into(),
69            qualifiedSigner: attest.qualified_signer.into(),
70            extraData: attest.extra_data.into(),
71            clockInfo: attest.clock_info.into(),
72            firmwareVersion: attest.firmware_version,
73            attested: attest.attested.into(),
74        }
75    }
76}
77
78impl TryFrom<TPMS_ATTEST> for Attest {
79    type Error = Error;
80
81    fn try_from(tpms_attest: TPMS_ATTEST) -> Result<Self> {
82        if tpms_attest.magic != TPM2_GENERATED_VALUE {
83            return Err(Error::local_error(WrapperErrorKind::InvalidParam));
84        }
85
86        let attestation_type = AttestationType::try_from(tpms_attest.type_)?;
87        Ok(Attest {
88            attestation_type,
89            qualified_signer: Name::try_from(tpms_attest.qualifiedSigner)?,
90            extra_data: Data::try_from(tpms_attest.extraData)?,
91            clock_info: ClockInfo::try_from(tpms_attest.clockInfo)?,
92            firmware_version: tpms_attest.firmwareVersion,
93            attested: match attestation_type {
94                AttestationType::Certify => AttestInfo::Certify {
95                    info: unsafe { tpms_attest.attested.certify }.try_into()?,
96                },
97                AttestationType::Quote => AttestInfo::Quote {
98                    info: unsafe { tpms_attest.attested.quote }.try_into()?,
99                },
100                AttestationType::SessionAudit => AttestInfo::SessionAudit {
101                    info: unsafe { tpms_attest.attested.sessionAudit }.try_into()?,
102                },
103                AttestationType::CommandAudit => AttestInfo::CommandAudit {
104                    info: unsafe { tpms_attest.attested.commandAudit }.try_into()?,
105                },
106                AttestationType::Time => AttestInfo::Time {
107                    info: unsafe { tpms_attest.attested.time }.try_into()?,
108                },
109                AttestationType::Creation => AttestInfo::Creation {
110                    info: unsafe { tpms_attest.attested.creation }.try_into()?,
111                },
112                AttestationType::Nv => AttestInfo::Nv {
113                    info: unsafe { tpms_attest.attested.nv }.try_into()?,
114                },
115                AttestationType::NvDigest => {
116                    error!("NvDigest attestation type is currently not supported");
117                    return Err(Error::local_error(WrapperErrorKind::UnsupportedParam));
118                }
119            },
120        })
121    }
122}
123
124impl Marshall for Attest {
125    const BUFFER_SIZE: usize = size_of::<TPMS_ATTEST>();
126
127    /// Produce a marshalled [`TPMS_ATTEST`]
128    fn marshall(&self) -> Result<Vec<u8>> {
129        let mut buffer = vec![0; Self::BUFFER_SIZE];
130        let mut offset = 0;
131
132        let ret = Error::from_tss_rc(unsafe {
133            crate::tss2_esys::Tss2_MU_TPMS_ATTEST_Marshal(
134                &self.clone().into(),
135                buffer.as_mut_ptr(),
136                Self::BUFFER_SIZE.try_into().map_err(|e| {
137                    error!("Failed to convert size of buffer to TSS size_t type: {}", e);
138                    Error::local_error(WrapperErrorKind::InvalidParam)
139                })?,
140                &mut offset,
141            )
142        });
143
144        if !ret.is_success() {
145            return Err(ret);
146        }
147
148        let checked_offset = usize::try_from(offset).map_err(|e| {
149            error!("Failed to parse offset as usize: {}", e);
150            Error::local_error(WrapperErrorKind::InvalidParam)
151        })?;
152
153        buffer.truncate(checked_offset);
154
155        Ok(buffer)
156    }
157}
158
159impl UnMarshall for Attest {
160    /// Unmarshall the structure from [`TPMS_ATTEST`]
161    fn unmarshall(marshalled_data: &[u8]) -> Result<Self> {
162        let mut dest = TPMS_ATTEST::default();
163        let mut offset = 0;
164
165        let ret = Error::from_tss_rc(unsafe {
166            crate::tss2_esys::Tss2_MU_TPMS_ATTEST_Unmarshal(
167                marshalled_data.as_ptr(),
168                marshalled_data.len().try_into().map_err(|e| {
169                    error!("Failed to convert length of marshalled data: {}", e);
170                    Error::local_error(WrapperErrorKind::InvalidParam)
171                })?,
172                &mut offset,
173                &mut dest,
174            )
175        });
176
177        if !ret.is_success() {
178            return Err(ret);
179        }
180
181        Attest::try_from(dest)
182    }
183}