tss_esapi/context/tpm_commands/
attestation_commands.rs

1// Copyright 2021 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3use crate::{
4    handles::{KeyHandle, ObjectHandle},
5    structures::{Attest, AttestBuffer, Data, PcrSelectionList, Signature, SignatureScheme},
6    tss2_esys::{Esys_Certify, Esys_GetTime, Esys_Quote},
7    Context, Error, Result,
8};
9use log::error;
10use std::convert::TryFrom;
11use std::ptr::null_mut;
12
13impl Context {
14    /// Prove that an object is loaded in the TPM
15    ///
16    /// # Arguments
17    /// * `object_handle` - Handle of the object to be certified
18    /// * `signing_key_handle` - Handle of the key used to sign the attestation buffer
19    /// * `qualifying_data` - Qualifying data
20    /// * `signing_scheme` - Signing scheme to use if the scheme for `signing_key_handle` is `Null`.
21    ///
22    /// The object may be any object that is loaded with [Self::load()] or [Self::create_primary()]. An object that
23    /// only has its public area loaded may not be certified.
24    ///
25    /// The `signing_key_handle` must be usable for signing.
26    ///
27    /// If `signing_key_handle` has the Restricted attribute set to `true` then `signing_scheme` must be
28    /// [SignatureScheme::Null].
29    ///
30    /// # Returns
31    /// The command returns a tuple consisting of:
32    /// * `attest_data` - TPM-generated attestation data.
33    /// * `signature` - Signature for the attestation data.
34    ///
35    /// # Errors
36    /// * if the qualifying data provided is too long, a `WrongParamSize` wrapper error will be returned
37    ///
38    /// # Examples
39    ///
40    /// ```rust
41    /// # use tss_esapi::{Context, TctiNameConf};
42    /// # use std::convert::TryFrom;
43    /// # use tss_esapi::{
44    /// #     abstraction::cipher::Cipher,
45    /// #     handles::KeyHandle,
46    /// #     interface_types::{
47    /// #         algorithm::{HashingAlgorithm, RsaSchemeAlgorithm, SignatureSchemeAlgorithm},
48    /// #         key_bits::RsaKeyBits,
49    /// #         resource_handles::Hierarchy,
50    /// #     },
51    /// #     structures::{
52    /// #         RsaExponent, RsaScheme, SymmetricDefinition,
53    /// #     },
54    /// #     utils::{create_unrestricted_signing_rsa_public, create_restricted_decryption_rsa_public},
55    /// # };
56    /// use std::convert::TryInto;
57    /// use tss_esapi::{
58    ///     structures::{Data, SignatureScheme},
59    ///     interface_types::session_handles::AuthSession,
60    /// };
61    /// # let mut context =
62    /// #     Context::new(
63    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
64    /// #     ).expect("Failed to create Context");
65    /// let qualifying_data = vec![0xff; 16];
66    /// # let signing_key_pub = create_unrestricted_signing_rsa_public(
67    /// #         RsaScheme::create(RsaSchemeAlgorithm::RsaSsa, Some(HashingAlgorithm::Sha256))
68    /// #         .expect("Failed to create RSA scheme"),
69    /// #     RsaKeyBits::Rsa2048,
70    /// #     RsaExponent::default(),
71    /// # )
72    /// # .expect("Failed to create an unrestricted signing rsa public structure");
73    /// # let sign_key_handle = context
74    /// #     .execute_with_nullauth_session(|ctx| {
75    /// #         ctx.create_primary(Hierarchy::Owner, signing_key_pub, None, None, None, None)
76    /// #     })
77    /// #     .unwrap()
78    /// #     .key_handle;
79    /// # let decryption_key_pub = create_restricted_decryption_rsa_public(
80    /// #         Cipher::aes_256_cfb()
81    /// #         .try_into()
82    /// #         .expect("Failed to create symmetric object"),
83    /// #     RsaKeyBits::Rsa2048,
84    /// #     RsaExponent::default(),
85    /// # )
86    /// # .expect("Failed to create a restricted decryption rsa public structure");
87    /// # let obj_key_handle = context
88    /// #     .execute_with_nullauth_session(|ctx| {
89    /// #         ctx.create_primary(
90    /// #             Hierarchy::Owner,
91    /// #             decryption_key_pub,
92    /// #             None,
93    /// #             None,
94    /// #             None,
95    /// #             None,
96    /// #         )
97    /// #     })
98    /// #     .unwrap()
99    /// #     .key_handle;
100    /// let (attest, signature) = context
101    ///     .execute_with_sessions(
102    ///         (
103    ///             Some(AuthSession::Password),
104    ///             Some(AuthSession::Password),
105    ///             None,
106    ///         ),
107    ///         |ctx| {
108    ///             ctx.certify(
109    ///                 obj_key_handle.into(),
110    ///                 sign_key_handle,
111    ///                 Data::try_from(qualifying_data).unwrap(),
112    ///                 SignatureScheme::Null,
113    ///             )
114    ///         },
115    ///     )
116    ///     .expect("Failed to certify object handle");
117    /// ```
118    pub fn certify(
119        &mut self,
120        object_handle: ObjectHandle,
121        signing_key_handle: KeyHandle,
122        qualifying_data: Data,
123        signing_scheme: SignatureScheme,
124    ) -> Result<(Attest, Signature)> {
125        let mut certify_info_ptr = null_mut();
126        let mut signature_ptr = null_mut();
127        let ret = unsafe {
128            Esys_Certify(
129                self.mut_context(),
130                object_handle.into(),
131                signing_key_handle.into(),
132                self.required_session_1()?,
133                self.required_session_2()?,
134                self.optional_session_3(),
135                &qualifying_data.into(),
136                &signing_scheme.into(),
137                &mut certify_info_ptr,
138                &mut signature_ptr,
139            )
140        };
141        let ret = Error::from_tss_rc(ret);
142
143        if ret.is_success() {
144            let certify_info = Context::ffi_data_to_owned(certify_info_ptr);
145            let signature = Context::ffi_data_to_owned(signature_ptr);
146            Ok((
147                Attest::try_from(AttestBuffer::try_from(certify_info)?)?,
148                Signature::try_from(signature)?,
149            ))
150        } else {
151            error!("Error in certifying: {}", ret);
152            Err(ret)
153        }
154    }
155
156    // Missing function: CertifyCreation
157
158    /// Generate a quote on the selected PCRs
159    ///
160    /// # Errors
161    /// * if the qualifying data provided is too long, a `WrongParamSize` wrapper error will be returned
162    pub fn quote(
163        &mut self,
164        signing_key_handle: KeyHandle,
165        qualifying_data: Data,
166        signing_scheme: SignatureScheme,
167        pcr_selection_list: PcrSelectionList,
168    ) -> Result<(Attest, Signature)> {
169        let mut quoted_ptr = null_mut();
170        let mut signature_ptr = null_mut();
171        let ret = unsafe {
172            Esys_Quote(
173                self.mut_context(),
174                signing_key_handle.into(),
175                self.optional_session_1(),
176                self.optional_session_2(),
177                self.optional_session_3(),
178                &qualifying_data.into(),
179                &signing_scheme.into(),
180                &pcr_selection_list.into(),
181                &mut quoted_ptr,
182                &mut signature_ptr,
183            )
184        };
185        let ret = Error::from_tss_rc(ret);
186
187        if ret.is_success() {
188            let quoted = Context::ffi_data_to_owned(quoted_ptr);
189            let signature = Context::ffi_data_to_owned(signature_ptr);
190            Ok((
191                Attest::try_from(AttestBuffer::try_from(quoted)?)?,
192                Signature::try_from(signature)?,
193            ))
194        } else {
195            error!("Error in quoting PCR: {}", ret);
196            Err(ret)
197        }
198    }
199
200    /// Get the current time and clock from the TPM
201    ///
202    /// # Arguments
203    /// * `signing_key_handle` - Handle of the key used to sign the attestation buffer
204    /// * `qualifying_data` - Qualifying data
205    /// * `signing_scheme` - Signing scheme to use if the scheme for `signing_key_handle` is `Null`.
206    ///
207    /// The `signing_key_handle` must be usable for signing.
208    ///
209    /// If `signing_key_handle` has the Restricted attribute set to `true` then `signing_scheme` must be
210    /// [SignatureScheme::Null].
211    ///
212    /// # Returns
213    /// The command returns a tuple consisting of:
214    /// * `attest_data` - TPM-generated attestation data.
215    /// * `signature` - Signature for the attestation data.
216    ///
217    /// # Errors
218    /// * if the qualifying data provided is too long, a `WrongParamSize` wrapper error will be returned
219    ///
220    /// # Examples
221    ///
222    /// ```rust
223    /// # use tss_esapi::{Context, TctiNameConf};
224    /// # use std::convert::TryFrom;
225    /// # use tss_esapi::{
226    /// #     abstraction::cipher::Cipher,
227    /// #     interface_types::{
228    /// #         algorithm::{HashingAlgorithm, RsaSchemeAlgorithm},
229    /// #         key_bits::RsaKeyBits,
230    /// #         resource_handles::Hierarchy,
231    /// #     },
232    /// #     structures::{
233    /// #         RsaExponent, RsaScheme,
234    /// #     },
235    /// #     utils::{create_unrestricted_signing_rsa_public, create_restricted_decryption_rsa_public},
236    /// # };
237    /// use std::convert::TryInto;
238    /// use tss_esapi::{
239    ///     structures::{Data, SignatureScheme},
240    ///     interface_types::session_handles::AuthSession,
241    /// };
242    /// # let mut context =
243    /// #     Context::new(
244    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
245    /// #     ).expect("Failed to create Context");
246    /// let qualifying_data = vec![0xff; 16];
247    /// # let signing_key_pub = create_unrestricted_signing_rsa_public(
248    /// #         RsaScheme::create(RsaSchemeAlgorithm::RsaSsa, Some(HashingAlgorithm::Sha256))
249    /// #         .expect("Failed to create RSA scheme"),
250    /// #     RsaKeyBits::Rsa2048,
251    /// #     RsaExponent::default(),
252    /// # )
253    /// # .expect("Failed to create an unrestricted signing rsa public structure");
254    /// # let sign_key_handle = context
255    /// #     .execute_with_nullauth_session(|ctx| {
256    /// #         ctx.create_primary(Hierarchy::Owner, signing_key_pub, None, None, None, None)
257    /// #     })
258    /// #     .unwrap()
259    /// #     .key_handle;
260    /// let (attest, signature) = context
261    ///     .execute_with_sessions(
262    ///         (
263    ///             Some(AuthSession::Password),
264    ///             Some(AuthSession::Password),
265    ///             None,
266    ///         ),
267    ///         |ctx| {
268    ///             ctx.get_time(
269    ///                 sign_key_handle,
270    ///                 Data::try_from(qualifying_data).unwrap(),
271    ///                 SignatureScheme::Null,
272    ///             )
273    ///         },
274    ///     )
275    ///     .expect("Failed to get tpm time");
276    /// ```
277    pub fn get_time(
278        &mut self,
279        signing_key_handle: KeyHandle,
280        qualifying_data: Data,
281        signing_scheme: SignatureScheme,
282    ) -> Result<(Attest, Signature)> {
283        let mut timeinfo_ptr = null_mut();
284        let mut signature_ptr = null_mut();
285        let ret = unsafe {
286            Esys_GetTime(
287                self.mut_context(),
288                ObjectHandle::Endorsement.into(),
289                signing_key_handle.into(),
290                self.required_session_1()?,
291                self.required_session_2()?,
292                self.optional_session_3(),
293                &qualifying_data.into(),
294                &signing_scheme.into(),
295                &mut timeinfo_ptr,
296                &mut signature_ptr,
297            )
298        };
299
300        let ret = Error::from_tss_rc(ret);
301
302        if ret.is_success() {
303            let timeinfo = Context::ffi_data_to_owned(timeinfo_ptr);
304            let signature = Context::ffi_data_to_owned(signature_ptr);
305            Ok((
306                Attest::try_from(AttestBuffer::try_from(timeinfo)?)?,
307                Signature::try_from(signature)?,
308            ))
309        } else {
310            error!("Error in Get Time: {}", ret);
311            Err(ret)
312        }
313    }
314
315    // Missing function: GetSessionAuditDigest
316    // Missing function: GestCommandAuditDigest
317    // Missing function: CertifyX509
318}