Skip to content

Instantly share code, notes, and snippets.

@THS-on
Last active October 12, 2023 06:22
Show Gist options
  • Save THS-on/c24764c306d11c3da9469d94bb9a48bb to your computer and use it in GitHub Desktop.
Save THS-on/c24764c306d11c3da9469d94bb9a48bb to your computer and use it in GitHub Desktop.
Example on how to protect a key using pcr policy using TSS rust bindings
use std::str::FromStr;
pub use tss_esapi::Error;
use tss_esapi::{
attributes::ObjectAttributesBuilder,
handles::PcrHandle,
interface_types::{
algorithm::{PublicAlgorithm, SymmetricMode},
ecc::EccCurve,
key_bits::AesKeyBits,
resource_handles::Hierarchy,
session_handles::AuthSession,
},
structures::{
CreateKeyResult, CreatePrimaryKeyResult, Digest, DigestValues, EccPoint, EccScheme,
HashScheme, KeyDerivationFunctionScheme, MaxBuffer, PcrSelectionListBuilder, PublicBuilder,
PublicEccParametersBuilder, SignatureScheme, SymmetricDefinitionObject,
},
tcti_ldr::DeviceConfig,
};
use tss_esapi::{
constants::SessionType,
interface_types::algorithm::HashingAlgorithm,
structures::{PcrSlot, SymmetricDefinition},
Context, TctiNameConf,
};
fn create_primary(context: &mut Context) -> Result<CreatePrimaryKeyResult, Error> {
let ecc_params = PublicEccParametersBuilder::new()
.with_ecc_scheme(EccScheme::Null)
.with_curve(EccCurve::NistP256)
.with_is_decryption_key(true)
.with_restricted(true)
.with_symmetric(SymmetricDefinitionObject::Aes {
key_bits: AesKeyBits::Aes128,
mode: SymmetricMode::Cfb,
})
.with_key_derivation_function_scheme(KeyDerivationFunctionScheme::Null)
.build()?;
let primary_object_attributes = ObjectAttributesBuilder::new()
.with_fixed_tpm(true)
.with_fixed_parent(true)
.with_sensitive_data_origin(true)
.with_user_with_auth(true)
.with_restricted(true)
.with_decrypt(true)
.build()?;
let primary_public = PublicBuilder::new()
.with_public_algorithm(PublicAlgorithm::Ecc)
.with_name_hashing_algorithm(HashingAlgorithm::Sha256)
.with_object_attributes(primary_object_attributes)
.with_ecc_parameters(ecc_params)
.with_ecc_unique_identifier(EccPoint::default())
.build()?;
context.execute_with_nullauth_session(|ctx| {
ctx.create_primary(
Hierarchy::Endorsement,
primary_public.clone(),
None,
None,
None,
None,
)
})
}
fn create_policy(context: &mut Context) -> Result<AuthSession, Error> {
let session = context
.start_auth_session(
None,
None,
None,
SessionType::Policy,
SymmetricDefinition::AES_128_CFB,
HashingAlgorithm::Sha256,
)?
.unwrap();
let pcr_selection_list = PcrSelectionListBuilder::new()
.with_selection(HashingAlgorithm::Sha256, vec![PcrSlot::Slot7].as_slice())
.build()?;
let (_update_counter, pcr_sel, pcr_data) =
context.execute_without_session(|ctx| ctx.pcr_read(pcr_selection_list))?;
let concatenated_pcr_values = pcr_data
.value()
.iter()
.map(|x| x.value())
.collect::<Vec<&[u8]>>()
.concat();
let concatenated_pcr_values = MaxBuffer::try_from(concatenated_pcr_values)?;
let (hashed_data, _ticket) = context.execute_without_session(|ctx| {
ctx.hash(
concatenated_pcr_values,
HashingAlgorithm::Sha256,
Hierarchy::Endorsement,
)
})?;
context.policy_pcr(session.try_into()?, hashed_data.clone(), pcr_sel.clone())?;
Ok(session)
}
fn create_key_with_policy(
context: &mut Context,
policy: Digest,
primary: &CreatePrimaryKeyResult,
) -> Result<CreateKeyResult, Error> {
let ecc_params = PublicEccParametersBuilder::new()
.with_ecc_scheme(EccScheme::Null)
.with_curve(EccCurve::NistP256)
.with_restricted(true)
.with_symmetric(SymmetricDefinitionObject::Null)
.with_key_derivation_function_scheme(KeyDerivationFunctionScheme::Null)
.build()?;
let key_object_attributes = ObjectAttributesBuilder::new()
.with_fixed_tpm(true)
.with_fixed_parent(true)
.with_sensitive_data_origin(true)
.with_decrypt(true)
.with_sign_encrypt(true)
.build()?;
let key_public = PublicBuilder::new()
.with_public_algorithm(PublicAlgorithm::Ecc)
.with_name_hashing_algorithm(HashingAlgorithm::Sha256)
.with_object_attributes(key_object_attributes)
.with_ecc_parameters(ecc_params)
.with_ecc_unique_identifier(EccPoint::default())
.with_auth_policy(policy)
.build()?;
context.execute_with_nullauth_session(|ctx| {
ctx.create(primary.key_handle, key_public, None, None, None, None)
})
}
fn extend_pcr7(context: &mut Context) -> Result<(), Error> {
let mut digests = DigestValues::new();
let data = MaxBuffer::try_from(vec![0])?;
let (digest, _) = context.execute_without_session(|ctx| {
ctx.hash(data, HashingAlgorithm::Sha256, Hierarchy::Endorsement)
})?;
digests.set(HashingAlgorithm::Sha256, digest);
context.execute_with_nullauth_session(|ctx| ctx.pcr_extend(PcrHandle::Pcr7, digests))
}
fn run() -> Result<(), Error> {
let device = TctiNameConf::Device(DeviceConfig::from_str("/dev/tpmrm0")?);
let mut context = Context::new(device)?;
let primary = create_primary(&mut context)?;
println!("Created primary key");
let session = create_policy(&mut context)?;
let session_digest = context.policy_get_digest(session.try_into()?)?;
println!("Created session digest for policy");
let key: CreateKeyResult = create_key_with_policy(&mut context, session_digest, &primary)?;
println!("Created Key");
let key_handle = context.execute_with_nullauth_session(|ctx| {
ctx.load(primary.key_handle, key.out_private, key.out_public)
})?;
println!("Loaded key");
// Create digest to sign
let data = MaxBuffer::try_from(vec![0])?;
let (digest, ticket) = context.execute_without_session(|ctx| {
ctx.hash(data, HashingAlgorithm::Sha256, Hierarchy::Endorsement)
})?;
println!("Hashed data");
// Create fresh session
let session = create_policy(&mut context)?;
// Uncomment to check if the policy actually works
//extend_pcr7(&mut context)?;
let signature = context.execute_with_session(Some(session), |ctx| {
ctx.sign(
key_handle,
digest,
SignatureScheme::EcDsa {
hash_scheme: HashScheme::new(HashingAlgorithm::Sha256),
},
ticket,
)
})?;
println!("Generated signature");
println!("Signature {:?}", signature);
Ok(())
}
fn main() {
let res = run();
match res {
Ok(_) => {}
Err(e) => {
println!("{}\n\n", e);
Err::<(), tss_esapi::Error>(e).unwrap();
}
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment