use tss_esapi::{
Context, TctiNameConf,
abstraction::{
AsymmetricAlgorithmSelection,
ak::{create_ak, load_ak},
ek::{create_ek_public_from_default_template, retrieve_ek_pubcert},
},
attributes::{ObjectAttributesBuilder, SessionAttributesBuilder},
constants::SessionType,
handles::{AuthHandle, KeyHandle, SessionHandle},
interface_types::{
algorithm::{HashingAlgorithm, PublicAlgorithm, SignatureSchemeAlgorithm},
ecc::EccCurve,
reserved_handles::Hierarchy,
session_handles::PolicySession,
},
structures::{
Data, Digest, EccPoint, EccScheme, HashScheme, MaxBuffer, PublicBuilder,
PublicEccParametersBuilder, SignatureScheme, SymmetricCipherParameters,
SymmetricDefinition, SymmetricDefinitionObject,
},
traits::Marshall,
};
use std::convert::{TryFrom, TryInto};
fn main() {
env_logger::init();
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 ek_alg = AsymmetricAlgorithmSelection::Ecc(EccCurve::NistP384);
let hash_alg = HashingAlgorithm::Sha384;
let sign_alg = SignatureSchemeAlgorithm::EcDsa;
let sig_scheme = SignatureScheme::EcDsa {
scheme: HashScheme::new(hash_alg),
};
let ek_pubcert = retrieve_ek_pubcert(&mut context_1, ek_alg).unwrap();
eprintln!("ek_pubcert der: {ek_pubcert:x?}");
let ek_template = create_ek_public_from_default_template(ek_alg, None).unwrap();
let ek_handle = context_1
.execute_with_nullauth_session(|ctx| {
ctx.create_primary(Hierarchy::Endorsement, ek_template, None, None, None, None)
})
.expect("Failed to load ek_template")
.key_handle;
let (ek_public, _name, _qualified_name) = context_1
.read_public(ek_handle)
.expect("Failed to read ek_public");
let ak_create_result = create_ak(
&mut context_1,
ek_handle,
hash_alg,
ek_alg,
sign_alg,
None,
None,
)
.expect("Failed to create attestation key");
let ak_public = ak_create_result.out_public.clone();
let ak_handle = load_ak(
&mut context_1,
ek_handle,
None,
ak_create_result.out_private,
ak_create_result.out_public,
)
.expect("Failed to load attestation key");
let ak_context = context_1
.execute_with_nullauth_session(|ctx| ctx.context_save(ak_handle.into()))
.expect("Failed to save ak context");
context_1
.flush_context(ak_handle.into())
.expect("Unable to flush ak_handle");
let ek_context = context_1
.execute_with_nullauth_session(|ctx| ctx.context_save(ek_handle.into()))
.expect("Failed to save ek context");
context_1
.flush_context(ek_handle.into())
.expect("Unable to flush ek_handle");
let (_public, ak_name, _qualified_name) = context_2
.execute_with_nullauth_session(|ctx| {
let ak_handle = ctx.load_external(None, ak_public.clone(), Hierarchy::Null)?;
let r = ctx.read_public(ak_handle);
ctx.flush_context(ak_handle.into())?;
r
})
.expect("Unable to read AIK public");
let ak_public_object_attributes = ak_public.object_attributes();
assert!(ak_public_object_attributes.fixed_tpm());
assert!(ak_public_object_attributes.fixed_parent());
assert!(ak_public_object_attributes.restricted());
let challenge = context_2
.get_random(16)
.expect("Unable to access random data.");
let (idobject, encrypted_secret) = context_2
.execute_with_nullauth_session(|ctx| {
let ek_handle = ctx.load_external(None, ek_public, Hierarchy::Null)?;
let r = ctx.make_credential(ek_handle, challenge.clone(), ak_name);
ctx.flush_context(ek_handle.into())?;
r
})
.expect("Unable to create encrypted challenge");
let ek_handle = context_1
.context_load(ek_context)
.expect("Failed to restore EK context");
let ak_handle = context_1
.context_load(ak_context)
.expect("Failed to restore AIK context");
let session = context_1
.start_auth_session(
None,
None,
None,
SessionType::Hmac,
SymmetricDefinition::AES_128_CFB,
HashingAlgorithm::Sha256,
)
.unwrap()
.unwrap();
let (session_attributes, session_attributes_mask) = SessionAttributesBuilder::new()
.with_decrypt(true)
.with_encrypt(true)
.build();
context_1
.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
.unwrap();
let (session_attributes, session_attributes_mask) = SessionAttributesBuilder::new().build();
let policy_auth_session = context_1
.start_auth_session(
None,
None,
None,
SessionType::Policy,
SymmetricDefinition::AES_128_CFB,
HashingAlgorithm::Sha256,
)
.expect("Invalid session attributes.")
.unwrap();
context_1
.tr_sess_set_attributes(
policy_auth_session,
session_attributes,
session_attributes_mask,
)
.unwrap();
let _ = context_1
.execute_with_nullauth_session(|ctx| {
ctx.policy_secret(
PolicySession::try_from(policy_auth_session).unwrap(),
AuthHandle::Endorsement,
Default::default(),
Default::default(),
Default::default(),
None,
)
})
.unwrap();
let response = context_1
.execute_with_sessions((Some(session), Some(policy_auth_session), None), |ctx| {
ctx.activate_credential(
ak_handle.into(),
ek_handle.into(),
idobject,
encrypted_secret,
)
})
.unwrap();
context_1.clear_sessions();
context_1
.flush_context(SessionHandle::from(session).into())
.expect("Failed to clear session");
context_1
.flush_context(SessionHandle::from(policy_auth_session).into())
.expect("Failed to clear policy_auth_session");
context_1
.flush_context(ek_handle)
.expect("Failed to unload EK");
context_1.clear_sessions();
assert_eq!(challenge, response);
let key_handle = create_key(&mut context_1);
context_1.clear_sessions();
let qualifying_data: Data = vec![1, 2, 3, 4, 5, 6, 7, 8].try_into().unwrap();
let session = context_1
.start_auth_session(
None,
None,
None,
SessionType::Hmac,
SymmetricDefinition::AES_128_CFB,
HashingAlgorithm::Sha256,
)
.unwrap()
.unwrap();
let (session_attributes, session_attributes_mask) = SessionAttributesBuilder::new()
.with_decrypt(true)
.with_encrypt(true)
.build();
context_1
.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
.unwrap();
let (session_attributes, session_attributes_mask) = SessionAttributesBuilder::new().build();
let aik_auth_session = context_1
.start_auth_session(
None,
None,
None,
SessionType::Hmac,
SymmetricDefinition::AES_128_CFB,
HashingAlgorithm::Sha256,
)
.expect("Invalid session attributes.")
.unwrap();
context_1
.tr_sess_set_attributes(
aik_auth_session,
session_attributes,
session_attributes_mask,
)
.unwrap();
let (attest, signature) = context_1
.execute_with_sessions(
(
Some(session),
Some(aik_auth_session),
None,
),
|ctx| {
ctx.certify(
key_handle.into(),
ak_handle.into(),
qualifying_data,
sig_scheme,
)
},
)
.unwrap();
context_1
.flush_context(SessionHandle::from(session).into())
.expect("Failed to clear session");
context_1
.flush_context(SessionHandle::from(aik_auth_session).into())
.expect("Failed to clear policy_auth_session");
println!("attest: {attest:?}");
println!("signature: {signature:?}");
let ak_handle = context_2
.execute_with_nullauth_session(|ctx| {
ctx.load_external(
None,
ak_public,
Hierarchy::Null,
)
})
.expect("Failed to load aik public");
let attest_data: MaxBuffer = attest
.marshall()
.expect("Unable to marshall")
.try_into()
.expect("Data too large");
let (attest_digest, _ticket) = context_2
.execute_with_nullauth_session(|ctx| {
ctx.hash(attest_data, hash_alg, Hierarchy::Null)
})
.expect("Failed to digest attestation output");
let verified_ticket = context_2
.execute_with_nullauth_session(|ctx| {
ctx.verify_signature(ak_handle, attest_digest, signature)
})
.expect("Failed to verify attestation");
println!("verification: {verified_ticket:?}");
}
fn create_key(context: &mut Context) -> KeyHandle {
let object_attributes = ObjectAttributesBuilder::new()
.with_fixed_tpm(true)
.with_fixed_parent(true)
.with_st_clear(false)
.with_sensitive_data_origin(true)
.with_user_with_auth(true)
.with_decrypt(true)
.with_restricted(true)
.build()
.expect("Failed to build object attributes");
let primary_pub = PublicBuilder::new()
.with_public_algorithm(PublicAlgorithm::SymCipher)
.with_name_hashing_algorithm(HashingAlgorithm::Sha256)
.with_object_attributes(object_attributes)
.with_symmetric_cipher_parameters(SymmetricCipherParameters::new(
SymmetricDefinitionObject::AES_128_CFB,
))
.with_symmetric_cipher_unique_identifier(Digest::default())
.build()
.unwrap();
let primary = context
.execute_with_nullauth_session(|ctx| {
ctx.create_primary(Hierarchy::Owner, primary_pub, None, None, None, None)
})
.unwrap();
let object_attributes = ObjectAttributesBuilder::new()
.with_fixed_tpm(true)
.with_fixed_parent(true)
.with_st_clear(false)
.with_sensitive_data_origin(true)
.with_user_with_auth(true)
.with_sign_encrypt(true)
.build()
.expect("Failed to build object attributes");
let ecc_params = PublicEccParametersBuilder::new_unrestricted_signing_key(
EccScheme::EcDsa(HashScheme::new(HashingAlgorithm::Sha256)),
EccCurve::NistP256,
)
.build()
.expect("Failed to build ecc params");
let key_pub = PublicBuilder::new()
.with_public_algorithm(PublicAlgorithm::Ecc)
.with_name_hashing_algorithm(HashingAlgorithm::Sha256)
.with_object_attributes(object_attributes)
.with_ecc_parameters(ecc_params)
.with_ecc_unique_identifier(EccPoint::default())
.build()
.unwrap();
context
.execute_with_nullauth_session(|ctx| {
let (private, public) = ctx
.create(primary.key_handle, key_pub, None, None, None, None)
.map(|key| (key.out_private, key.out_public))?;
let key_handle = ctx.load(primary.key_handle, private, public)?;
ctx.flush_context(primary.key_handle.into())
.map(|()| key_handle)
})
.unwrap()
}