Skip to content

Commit

Permalink
Add ActivateCredential support for TKC
Browse files Browse the repository at this point in the history
This commit adds support for two operations, enabling key attestation
via the ActivateCredential call. A test has also been added to verify
attestation using the Endorsement Key.

Signed-off-by: Ionut Mihalcea <[email protected]>
  • Loading branch information
ionut-arm committed Oct 28, 2021
1 parent 714fe81 commit 3849337
Show file tree
Hide file tree
Showing 4 changed files with 301 additions and 6 deletions.
8 changes: 5 additions & 3 deletions tss-esapi/src/abstraction/ek.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ use std::convert::TryFrom;
const RSA_2048_EK_CERTIFICATE_NV_INDEX: u32 = 0x01c00002;
const ECC_P256_EK_CERTIFICATE_NV_INDEX: u32 = 0x01c0000a;

// Source: TCG EK Credential Profile for TPM Family 2.0; Level 0 Version 2.3 Revision 2
// Appendix B.3.3 and B.3.4
fn create_ek_public_from_default_template<IKC: IntoKeyCustomization>(
/// Get the [`Public`] representing a default Endorsement Key
///
/// Source: TCG EK Credential Profile for TPM Family 2.0; Level 0 Version 2.3 Revision 2
/// Appendix B.3.3 and B.3.4
pub fn create_ek_public_from_default_template<IKC: IntoKeyCustomization>(
alg: AsymmetricAlgorithm,
key_customization: IKC,
) -> Result<Public> {
Expand Down
203 changes: 203 additions & 0 deletions tss-esapi/src/abstraction/transient/key_attestation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
// Copyright 2021 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
use super::{ObjectWrapper, TransientKeyContext};
use crate::{
abstraction::ek,
constants::SessionType,
handles::{AuthHandle, SessionHandle},
interface_types::{
algorithm::{AsymmetricAlgorithm, HashingAlgorithm},
session_handles::PolicySession,
},
structures::{EncryptedSecret, IDObject, SymmetricDefinition},
tss2_esys::{TPM2B_PUBLIC, TPMT_PUBLIC},
utils::PublicKey,
Result,
};
use std::convert::{TryFrom, TryInto};

#[derive(Debug)]
/// Wrapper for the parameters needed by MakeCredential
pub struct MakeCredParams {
/// TPM name of the object
name: Vec<u8>,
/// Encoding of the public parameters of the object whose name
/// will be included in the credential computations
public: Vec<u8>,
/// Public part of the key used to protect the credential
attesting_key_pub: PublicKey,
}

impl MakeCredParams {
pub fn name(&self) -> &[u8] {
&self.name
}

pub fn public(&self) -> &[u8] {
&self.public
}

pub fn attesting_key_pub(&self) -> &PublicKey {
&self.attesting_key_pub
}
}

impl TransientKeyContext {
/// Get the data required to perform a MakeCredential
///
/// # Parameters
///
/// * `object` - the object whose TPM name will be included in
/// the credential
/// * `key` - the key to be used to encrypt the secret that wraps
/// the credential
///
/// **Note**: If no `key` is given, the default Endorsement Key
/// will be used.
pub fn get_make_cred_params(
&mut self,
object: ObjectWrapper,
key: Option<ObjectWrapper>,
) -> Result<MakeCredParams> {
let object_handle = self.load_key(object.params, object.material, None)?;
let (object_public, object_name, _) =
self.context.read_public(object_handle).or_else(|e| {
self.context.flush_context(object_handle.into())?;
Err(e)
})?;
self.context.flush_context(object_handle.into())?;

let public = TPM2B_PUBLIC::from(object_public);
let public = unsafe {
std::mem::transmute::<TPMT_PUBLIC, [u8; std::mem::size_of::<TPMT_PUBLIC>()]>(
public.publicArea,
)
};
let attesting_key_pub = match key {
None => {
let key_handle =
ek::create_ek_object(&mut self.context, AsymmetricAlgorithm::Rsa, None)?;
let (attesting_key_pub, _, _) =
self.context.read_public(key_handle).or_else(|e| {
self.context.flush_context(key_handle.into())?;
Err(e)
})?;
self.context.flush_context(key_handle.into())?;

attesting_key_pub.try_into()?
}
Some(key) => key.material.public,
};
Ok(MakeCredParams {
name: object_name.value().to_vec(),
public: public.to_vec(),
attesting_key_pub,
})
}

/// Perform an ActivateCredential operation for the given object
///
/// # Parameters
///
/// * `object` - the object whose TPM name is included in the credential
/// * `key` - the key used to encrypt the secret that wraps the credential
/// * `credential_blob` - encrypted credential that will be returned by the
/// TPM
/// * `secret` - encrypted secret that was used to encrypt the credential
///
/// **Note**: if no `key` is given, the default Endorsement Key
/// will be used. You can find more information about the default Endorsement
/// Key in the [ek] module.
pub fn activate_credential(
&mut self,
object: ObjectWrapper,
key: Option<ObjectWrapper>,
credential_blob: Vec<u8>,
secret: Vec<u8>,
) -> Result<Vec<u8>> {
let credential_blob = IDObject::try_from(credential_blob)?;
let secret = EncryptedSecret::try_from(secret)?;
let object_handle = self.load_key(object.params, object.material, object.auth)?;
let session_2;
let key_handle = match key {
None => {
// No key was given, use the EK. This requires using a Policy session
session_2 = self
.context
.start_auth_session(
None,
None,
None,
SessionType::Policy,
SymmetricDefinition::AES_128_CFB,
HashingAlgorithm::Sha256,
)
.or_else(|e| {
self.context.flush_context(object_handle.into())?;
Err(e)
})?;
let _ = self.context.policy_secret(
PolicySession::try_from(session_2.unwrap())
.expect("Failed to convert auth session to policy session"),
AuthHandle::Endorsement,
Default::default(),
Default::default(),
Default::default(),
None,
);
ek::create_ek_object(&mut self.context, AsymmetricAlgorithm::Rsa, None).or_else(
|e| {
self.context.flush_context(object_handle.into())?;
self.context
.flush_context(SessionHandle::from(session_2).into())?;
Err(e)
},
)?
}
Some(key) => {
// Load key and create a HMAC session for it
session_2 = self
.context
.start_auth_session(
None,
None,
None,
SessionType::Hmac,
SymmetricDefinition::AES_128_CFB,
HashingAlgorithm::Sha256,
)
.or_else(|e| {
self.context.flush_context(object_handle.into())?;
Err(e)
})?;
self.load_key(key.params, key.material, key.auth)
.or_else(|e| {
self.context.flush_context(object_handle.into())?;
self.context
.flush_context(SessionHandle::from(session_2).into())?;
Err(e)
})?
}
};

let (session_1, _, _) = self.context.sessions();
let credential = self
.context
.execute_with_sessions((session_1, session_2, None), |ctx| {
ctx.activate_credential(object_handle, key_handle, credential_blob, secret)
})
.or_else(|e| {
self.context.flush_context(object_handle.into())?;
self.context.flush_context(key_handle.into())?;
self.context
.flush_context(SessionHandle::from(session_2).into())?;
Err(e)
})?;

self.context.flush_context(object_handle.into())?;
self.context.flush_context(key_handle.into())?;
self.context
.flush_context(SessionHandle::from(session_2).into())?;
Ok(credential.value().to_vec())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ use serde::{Deserialize, Serialize};
use std::convert::{TryFrom, TryInto};
use zeroize::Zeroize;

mod key_attestation;

/// Parameters for the kinds of keys supported by the context
#[derive(Debug, Clone, Copy)]
pub enum KeyParams {
Expand Down Expand Up @@ -89,6 +91,13 @@ impl KeyMaterial {
}
}

#[derive(Debug, Clone)]
pub struct ObjectWrapper {
pub material: KeyMaterial,
pub params: KeyParams,
pub auth: Option<Auth>,
}

/// Structure offering an abstracted programming experience.
///
/// The `TransientKeyContext` makes use of a root key from which the other, client-controlled
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
// Copyright 2020 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
use std::convert::TryFrom;
use std::convert::{TryFrom, TryInto};
use tss_esapi::{
abstraction::transient::{KeyParams, TransientKeyContextBuilder},
abstraction::ek,
abstraction::transient::{KeyParams, ObjectWrapper, TransientKeyContextBuilder},
constants::response_code::Tss2ResponseCodeKind,
interface_types::{
algorithm::{EccSchemeAlgorithm, HashingAlgorithm, RsaSchemeAlgorithm},
algorithm::{
AsymmetricAlgorithm, EccSchemeAlgorithm, HashingAlgorithm, RsaSchemeAlgorithm,
},
ecc::EccCurve,
key_bits::RsaKeyBits,
resource_handles::Hierarchy,
Expand Down Expand Up @@ -597,3 +600,81 @@ fn ctx_migration_test() {
panic!("Got wrong type of key from TPM");
}
}

#[test]
fn activate_credential() {
// create a Transient key context, generate a key and
// obtain the Make Credential parameters
let mut ctx = create_ctx();
let params = KeyParams::Ecc {
curve: EccCurve::NistP256,
scheme: EccScheme::create(
EccSchemeAlgorithm::EcDsa,
Some(HashingAlgorithm::Sha256),
None,
)
.expect("Failed to create ecc scheme"),
};
let (material, auth) = ctx.create_key(params, 16).unwrap();
let obj = ObjectWrapper {
material,
auth,
params,
};
let make_cred_params = ctx.get_make_cred_params(obj.clone(), None).unwrap();

drop(ctx);

// create a normal Context and make the credential
let mut basic_ctx = crate::common::create_ctx_with_session();

// the public part of the EK is used, so we retrieve the parameters
let key_pub =
ek::create_ek_public_from_default_template(AsymmetricAlgorithm::Rsa, None).unwrap();
let key_pub = if let Public::Rsa {
object_attributes,
name_hashing_algorithm,
auth_policy,
parameters,
..
} = key_pub
{
Public::Rsa {
object_attributes,
name_hashing_algorithm,
auth_policy,
parameters,
unique: if let PublicKey::Rsa(val) = make_cred_params.attesting_key_pub().clone() {
PublicKeyRsa::try_from(val).unwrap()
} else {
panic!("Wrong public key type");
},
}
} else {
panic!("Wrong Public type");
};
let pub_handle = basic_ctx
.load_external_public(&key_pub, Hierarchy::Owner)
.unwrap();

// Credential to expect back as proof for attestation
let credential = vec![0x53; 16];

let (cred, secret) = basic_ctx
.make_credential(
pub_handle,
credential.clone().try_into().unwrap(),
make_cred_params.name().to_vec().try_into().unwrap(),
)
.unwrap();

drop(basic_ctx);

// Create a new Transient key context and activate the credential
let mut ctx = create_ctx();
let cred_back = ctx
.activate_credential(obj, None, cred.value().to_vec(), secret.value().to_vec())
.unwrap();

assert_eq!(cred_back, credential);
}

0 comments on commit 3849337

Please sign in to comment.