use tss_esapi::{
Context, TctiNameConf,
attributes::{ObjectAttributesBuilder, SessionAttributesBuilder},
constants::SessionType,
handles::SessionHandle,
interface_types::{
algorithm::{HashingAlgorithm, PublicAlgorithm},
ecc::EccCurve,
reserved_handles::Hierarchy,
session_handles::PolicySession,
},
structures::{
CreatePrimaryKeyResult, Digest, EccPoint, KeyedHashScheme, MaxBuffer, PublicBuilder,
PublicEccParametersBuilder, PublicKeyedHashParameters, SymmetricDefinition,
SymmetricDefinitionObject,
},
};
use std::convert::{TryFrom, TryInto};
fn main() {
let input_data = MaxBuffer::try_from("Duplicating keys is fun ...".as_bytes().to_vec())
.expect("Failed to create buffer for input data.");
let mut context_1 = Context::new(
TctiNameConf::from_environment_variable()
.expect("Failed to get TCTI / TPM2TOOLS_TCTI from environment. Try `export TCTI=device:/dev/tpmrm0`"),
)
.expect("Failed to create Context");
let mut context_2 = Context::new(
TctiNameConf::from_environment_variable()
.expect("Failed to get TCTI / TPM2TOOLS_TCTI from environment. Try `export TCTI=device:/dev/tpmrm0`"),
)
.expect("Failed to create Context");
let primary_key_1 = create_primary_key(&mut context_1);
let primary_key_2 = create_primary_key(&mut context_2);
let (_, target_parent_name, _) = context_2
.execute_with_nullauth_session(|ctx| ctx.read_public(primary_key_2.key_handle))
.unwrap();
let primary_key_2_public = primary_key_2.out_public.clone();
let primary_key_2_context = context_2
.execute_with_nullauth_session(|ctx| ctx.context_save(primary_key_2.key_handle.into()))
.unwrap();
let policy_digest = context_1
.execute_without_session(|ctx| {
let trial_session = ctx
.start_auth_session(
None,
None,
None,
SessionType::Trial,
SymmetricDefinition::AES_128_CFB,
HashingAlgorithm::Sha256,
)
.expect("Start auth session failed")
.expect("Start auth session returned a NONE handle");
let (policy_auth_session_attributes, policy_auth_session_attributes_mask) =
SessionAttributesBuilder::new()
.with_decrypt(true)
.with_encrypt(true)
.build();
ctx.tr_sess_set_attributes(
trial_session,
policy_auth_session_attributes,
policy_auth_session_attributes_mask,
)
.expect("tr_sess_set_attributes call failed");
let policy_session = PolicySession::try_from(trial_session)
.expect("Failed to convert auth session into policy session");
ctx.policy_duplication_select(
policy_session,
Vec::<u8>::new().try_into().unwrap(),
target_parent_name.clone(),
false,
)
.expect("Policy duplication select");
let digest = ctx.policy_get_digest(policy_session);
ctx.flush_context(SessionHandle::from(trial_session).into())
.expect("Failed to clear session");
digest
})
.unwrap();
let object_attributes = ObjectAttributesBuilder::new()
.with_fixed_tpm(false)
.with_fixed_parent(false)
.with_sensitive_data_origin(true)
.with_user_with_auth(true)
.with_decrypt(true)
.with_sign_encrypt(false)
.with_restricted(true)
.with_encrypted_duplication(true)
.build()
.expect("Attributes to be valid");
let storage_public = PublicBuilder::new()
.with_public_algorithm(PublicAlgorithm::Ecc)
.with_name_hashing_algorithm(HashingAlgorithm::Sha256)
.with_object_attributes(object_attributes)
.with_auth_policy(policy_digest)
.with_ecc_parameters(
PublicEccParametersBuilder::new_restricted_decryption_key(
SymmetricDefinitionObject::AES_128_CFB,
EccCurve::NistP256,
)
.build()
.unwrap(),
)
.with_ecc_unique_identifier(EccPoint::default())
.build()
.expect("storage public to be valid");
let storage_key = context_1
.execute_with_nullauth_session(|ctx| {
ctx.create(
primary_key_1.key_handle,
storage_public,
None,
None,
None,
None,
)
})
.inspect_err(|err| {
eprintln!("⚠️ {err}");
})
.unwrap();
let loaded_storage_key = context_1
.execute_with_nullauth_session(|ctx| {
ctx.load(
primary_key_1.key_handle,
storage_key.out_private.clone(),
storage_key.out_public.clone(),
)
})
.unwrap();
context_1
.flush_context(primary_key_1.key_handle.into())
.unwrap();
let object_attributes = ObjectAttributesBuilder::new()
.with_fixed_tpm(false)
.with_fixed_parent(true)
.with_sensitive_data_origin(true)
.with_user_with_auth(true)
.with_sign_encrypt(true)
.with_restricted(false)
.with_encrypted_duplication(true)
.build()
.expect("Failed to build object attributes");
let hmac_public = PublicBuilder::new()
.with_public_algorithm(PublicAlgorithm::KeyedHash)
.with_name_hashing_algorithm(HashingAlgorithm::Sha256)
.with_object_attributes(object_attributes)
.with_keyed_hash_parameters(PublicKeyedHashParameters::new(
KeyedHashScheme::HMAC_SHA_256,
))
.with_keyed_hash_unique_identifier(Digest::default())
.build()
.unwrap();
let hmac_key = context_1
.execute_with_nullauth_session(|ctx| {
ctx.create(loaded_storage_key, hmac_public, None, None, None, None)
})
.inspect_err(|err| {
eprintln!("⚠️ {err}");
})
.unwrap();
let hmac1 = context_1
.execute_with_nullauth_session(|ctx| {
let loaded_hmackey = ctx
.load(
loaded_storage_key,
hmac_key.out_private.clone(),
hmac_key.out_public.clone(),
)
.unwrap();
ctx.execute_with_temporary_object(loaded_hmackey.into(), |ctx, handle| {
ctx.hmac(handle, input_data.clone(), HashingAlgorithm::Sha256)
})
})
.unwrap();
let (_, object_to_duplicate_name, _) = context_1.read_public(loaded_storage_key).unwrap();
let public = storage_key.out_public.clone();
let (data, duplicate, secret) = context_1
.execute_without_session(|ctx| {
let new_parent_handle = ctx
.load_external(None, primary_key_2_public, Hierarchy::Null)
.unwrap();
let policy_auth_session = ctx
.start_auth_session(
None,
None,
None,
SessionType::Policy,
SymmetricDefinition::AES_128_CFB,
HashingAlgorithm::Sha256,
)
.expect("Start auth session failed")
.expect("Start auth session returned a NONE handle");
let (policy_auth_session_attributes, policy_auth_session_attributes_mask) =
SessionAttributesBuilder::new()
.with_decrypt(true)
.with_encrypt(true)
.build();
ctx.tr_sess_set_attributes(
policy_auth_session,
policy_auth_session_attributes,
policy_auth_session_attributes_mask,
)
.expect("tr_sess_set_attributes call failed");
let policy_session = PolicySession::try_from(policy_auth_session)
.expect("Failed to convert auth session into policy session");
ctx.policy_duplication_select(
policy_session,
object_to_duplicate_name,
target_parent_name,
false,
)
.expect("Policy duplication select");
ctx.set_sessions((Some(policy_auth_session), None, None));
let result = ctx.execute_with_temporary_object(
new_parent_handle.into(),
|ctx, new_parent_handle| {
ctx.duplicate(
loaded_storage_key.into(),
new_parent_handle,
None,
SymmetricDefinitionObject::AES_128_CFB,
)
},
);
ctx.flush_context(SessionHandle::from(policy_auth_session).into())
.expect("Failed to clear session");
result
})
.inspect_err(|err| {
eprintln!("⚠️ {err}");
})
.unwrap();
context_1.flush_context(loaded_storage_key.into()).unwrap();
let primary_key_2_key_handle = context_2
.execute_with_nullauth_session(|ctx| ctx.context_load(primary_key_2_context))
.unwrap();
let private_storage_key_2 = context_2
.execute_with_nullauth_session(|ctx| {
ctx.import(
primary_key_2_key_handle,
Some(data),
public.clone(),
duplicate,
secret,
SymmetricDefinitionObject::AES_128_CFB,
)
})
.unwrap();
let loaded_storage_key_2 = context_2
.execute_with_nullauth_session(|ctx| {
ctx.load(
primary_key_2_key_handle.into(),
private_storage_key_2,
public,
)
})
.unwrap();
context_2.flush_context(primary_key_2_key_handle).unwrap();
let hmac2 = context_2
.execute_with_nullauth_session(|ctx| {
let loaded_hmackey = ctx
.load(
loaded_storage_key_2,
hmac_key.out_private.clone(),
hmac_key.out_public.clone(),
)
.unwrap();
ctx.execute_with_temporary_object(loaded_hmackey.into(), |ctx, handle| {
ctx.hmac(handle, input_data.clone(), HashingAlgorithm::Sha256)
})
})
.unwrap();
println!("hmac1 = {hmac1:?}");
println!("hmac2 = {hmac2:?}");
assert_eq!(hmac1, hmac2);
}
fn create_primary_key(context: &mut Context) -> CreatePrimaryKeyResult {
context
.execute_with_nullauth_session(|ctx| {
let object_attributes = ObjectAttributesBuilder::new()
.with_fixed_tpm(true)
.with_fixed_parent(true)
.with_sensitive_data_origin(true)
.with_user_with_auth(true)
.with_decrypt(true)
.with_sign_encrypt(false)
.with_restricted(true)
.build()
.expect("Attributes to be valid");
let public = PublicBuilder::new()
.with_public_algorithm(PublicAlgorithm::Ecc)
.with_name_hashing_algorithm(HashingAlgorithm::Sha256)
.with_object_attributes(object_attributes)
.with_ecc_parameters(
PublicEccParametersBuilder::new_restricted_decryption_key(
SymmetricDefinitionObject::AES_128_CFB,
EccCurve::NistP256,
)
.build()
.expect("Params to be valid"),
)
.with_ecc_unique_identifier(EccPoint::default())
.build()
.expect("public to be valid");
ctx.create_primary(Hierarchy::Owner, public, None, None, None, None)
})
.unwrap()
}