Skip to content

Commit 1a5c96c

Browse files
committed
Add ctx.certify_creation
Signed-off-by: Kevin King <[email protected]>
1 parent 4af8249 commit 1a5c96c

File tree

2 files changed

+185
-2
lines changed

2 files changed

+185
-2
lines changed

tss-esapi/src/context/tpm_commands/attestation_commands.rs

Lines changed: 131 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@
22
// SPDX-License-Identifier: Apache-2.0
33
use crate::{
44
handles::{KeyHandle, ObjectHandle},
5-
structures::{Attest, AttestBuffer, Data, PcrSelectionList, Signature, SignatureScheme},
5+
structures::{
6+
Attest, AttestBuffer, CreationTicket, Data, Digest, PcrSelectionList, Signature,
7+
SignatureScheme,
8+
},
69
tss2_esys::{Esys_Certify, Esys_Quote},
710
Context, Result, ReturnCode,
811
};
912
use log::error;
1013
use std::convert::TryFrom;
1114
use std::ptr::null_mut;
15+
use tss_esapi_sys::Esys_CertifyCreation;
1216

1317
impl Context {
1418
/// Prove that an object is loaded in the TPM
@@ -152,7 +156,132 @@ impl Context {
152156
))
153157
}
154158

155-
// Missing function: CertifyCreation
159+
/// Prove the association between an object and its creation data
160+
///
161+
/// # Arguments
162+
/// * `signing_key_handle` - Handle of the key used to sign the attestation buffer
163+
/// * `object_handle` - Handle of the object to be certified
164+
/// * `qualifying_data` - Qualifying data
165+
/// * `creation_hash` - Digest of the creation data
166+
/// * `signing_scheme` - Signing scheme to use if the scheme for `signing_key_handle` is `Null`.
167+
/// * `creation_ticket` - CreationTicket returned at object creation time.
168+
///
169+
/// The object may be any object that is loaded with [Self::load()] or [Self::create_primary()]. An object that
170+
/// only has its public area loaded may not be certified.
171+
///
172+
/// The `signing_key_handle` must be usable for signing.
173+
///
174+
/// If `signing_key_handle` has the Restricted attribute set to `true` then `signing_scheme` must be
175+
/// [SignatureScheme::Null].
176+
///
177+
/// # Returns
178+
/// The command returns a tuple consisting of:
179+
/// * `attest_data` - TPM-generated attestation data.
180+
/// * `signature` - Signature for the attestation data.
181+
///
182+
/// # Errors
183+
/// * if the qualifying data provided is too long, a `WrongParamSize` wrapper error will be returned
184+
///
185+
/// # Examples
186+
///
187+
/// ```rust
188+
/// # use tss_esapi::{Context, TctiNameConf};
189+
/// # use std::convert::TryFrom;
190+
/// # use tss_esapi::{
191+
/// # abstraction::cipher::Cipher,
192+
/// # handles::KeyHandle,
193+
/// # interface_types::{
194+
/// # algorithm::{HashingAlgorithm, EccSchemeAlgorithm, SignatureSchemeAlgorithm},
195+
/// # ecc::EccCurve,
196+
/// # resource_handles::Hierarchy,
197+
/// # },
198+
/// # structures::{
199+
/// # EccScheme
200+
/// # },
201+
/// # utils::create_unrestricted_signing_ecc_public,
202+
/// # };
203+
/// use std::convert::TryInto;
204+
/// use tss_esapi::{
205+
/// structures::{Data, SignatureScheme},
206+
/// interface_types::session_handles::AuthSession,
207+
/// };
208+
/// # let mut context =
209+
/// # Context::new(
210+
/// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
211+
/// # ).expect("Failed to create Context");
212+
/// let qualifying_data = vec![0xff; 16];
213+
/// # let signing_key_pub = create_unrestricted_signing_ecc_public(
214+
/// # EccScheme::create(EccSchemeAlgorithm::EcDsa, Some(HashingAlgorithm::Sha256), None)
215+
/// # .expect("Failed to create ECC scheme"),
216+
/// # EccCurve::NistP256,
217+
/// # )
218+
/// # .expect("Failed to create an unrestricted signing ecc public structure");
219+
/// # let create_result = context
220+
/// # .execute_with_nullauth_session(|ctx| {
221+
/// # ctx.create_primary(Hierarchy::Owner, signing_key_pub, None, None, None, None)
222+
/// # }).unwrap();
223+
/// let (attest, signature) = context
224+
/// .execute_with_sessions(
225+
/// (
226+
/// Some(AuthSession::Password),
227+
/// None,
228+
/// None,
229+
/// ),
230+
/// |ctx| {
231+
/// ctx.certify_creation(
232+
/// create_result.key_handle,
233+
/// create_result.key_handle.into(),
234+
/// qualifying_data.try_into()?,
235+
/// create_result.creation_hash,
236+
/// SignatureScheme::Null,
237+
/// create_result.creation_ticket,
238+
/// )
239+
/// },
240+
/// )
241+
/// .expect("Failed to certify creation");
242+
/// ```
243+
pub fn certify_creation(
244+
&mut self,
245+
signing_key_handle: KeyHandle,
246+
created_object: ObjectHandle,
247+
qualifying_data: Data,
248+
creation_hash: Digest,
249+
signing_scheme: SignatureScheme,
250+
creation_ticket: CreationTicket,
251+
) -> Result<(Attest, Signature)> {
252+
use std::convert::TryInto;
253+
254+
let mut certify_info_ptr = null_mut();
255+
let mut signature_ptr = null_mut();
256+
ReturnCode::ensure_success(
257+
unsafe {
258+
Esys_CertifyCreation(
259+
self.mut_context(),
260+
signing_key_handle.into(),
261+
created_object.into(),
262+
self.required_session_1()?,
263+
self.optional_session_2(),
264+
self.optional_session_3(),
265+
&qualifying_data.into(),
266+
&creation_hash.into(),
267+
&signing_scheme.into(),
268+
&creation_ticket.try_into()?,
269+
&mut certify_info_ptr,
270+
&mut signature_ptr,
271+
)
272+
},
273+
|ret| {
274+
error!("Error in certifying creation: {:#010X}", ret);
275+
},
276+
)?;
277+
278+
let certify_info = Context::ffi_data_to_owned(certify_info_ptr);
279+
let signature = Context::ffi_data_to_owned(signature_ptr);
280+
Ok((
281+
Attest::try_from(AttestBuffer::try_from(certify_info)?)?,
282+
Signature::try_from(signature)?,
283+
))
284+
}
156285

157286
/// Generate a quote on the selected PCRs
158287
///

tss-esapi/tests/integration_tests/context_tests/tpm_commands/attestation_commands_tests.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,4 +166,58 @@ mod test_quote {
166166

167167
assert_eq!(signature.algorithm(), SignatureSchemeAlgorithm::Null);
168168
}
169+
170+
#[test]
171+
fn certify_creation() {
172+
let mut context = create_ctx_with_session();
173+
let qualifying_data = vec![0xff; 16];
174+
175+
let sign_key_handle = context
176+
.create_primary(Hierarchy::Owner, signing_key_pub(), None, None, None, None)
177+
.unwrap()
178+
.key_handle;
179+
180+
let create_result = context
181+
.create_primary(
182+
Hierarchy::Owner,
183+
decryption_key_pub(),
184+
None,
185+
None,
186+
None,
187+
None,
188+
)
189+
.unwrap();
190+
191+
use std::convert::TryInto;
192+
193+
let (attest, signature) = context
194+
.execute_with_sessions((Some(AuthSession::Password), None, None), |ctx| {
195+
ctx.certify_creation(
196+
sign_key_handle,
197+
create_result.key_handle.into(),
198+
qualifying_data.try_into()?,
199+
create_result.creation_hash,
200+
SignatureScheme::Null,
201+
create_result.creation_ticket,
202+
)
203+
})
204+
.expect("Failed to certify object handle creation");
205+
206+
let data = MaxBuffer::try_from(attest.marshall().unwrap())
207+
.expect("Failed to get data buffer from attestation data");
208+
let (digest, _) = context
209+
.hash(data, HashingAlgorithm::Sha256, Hierarchy::Null)
210+
.expect("Failed to hash data");
211+
212+
let ticket = context
213+
.execute_with_nullauth_session(|ctx| {
214+
ctx.verify_signature(sign_key_handle, digest, signature)
215+
})
216+
.expect("Failed to verify signature");
217+
assert_eq!(ticket.tag(), StructureTag::Verified);
218+
219+
// Verify the attestation data is as expected
220+
assert_eq!(attest.attestation_type(), AttestationType::Creation);
221+
assert!(matches!(attest.attested(), AttestInfo::Creation { .. }));
222+
}
169223
}

0 commit comments

Comments
 (0)