Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ActivateCredential support for TKC #284

Merged
merged 9 commits into from
Nov 18, 2021
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ jobs:
run: docker build -t ubuntucontainer tss-esapi/tests/ --file tss-esapi/tests/Dockerfile-ubuntu
- name: Run the container
run: docker run -v $(pwd):/tmp/rust-tss-esapi -w /tmp/rust-tss-esapi/tss-esapi ubuntucontainer /tmp/rust-tss-esapi/tss-esapi/tests/all-ubuntu.sh
- name: Run the cross-compilation script
run: docker run -v $(pwd):/tmp/rust-tss-esapi -w /tmp/rust-tss-esapi/tss-esapi ubuntucontainer /tmp/rust-tss-esapi/tss-esapi/tests/cross-compile.sh

tests-ubuntu-v3:
name: Ubuntu tests on v3.x.y of tpm2-tss
Expand Down
2 changes: 0 additions & 2 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,3 @@ jobs:
run: docker run -v $(pwd):/tmp/rust-tss-esapi -w /tmp/rust-tss-esapi/tss-esapi --security-opt seccomp=unconfined ubuntucontainer /tmp/rust-tss-esapi/tss-esapi/tests/coverage.sh
- name: Collect coverage results
run: bash <(curl -s https://codecov.io/bash)
- name: Run the cross-compilation script
run: docker run -v $(pwd):/tmp/rust-tss-esapi -w /tmp/rust-tss-esapi/tss-esapi ubuntucontainer /tmp/rust-tss-esapi/tss-esapi/tests/cross-compile.sh
1 change: 1 addition & 0 deletions tss-esapi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ primal = "0.3.0"

[dev-dependencies]
env_logger = "0.7.1"
sha2 = "0.9.8"

[features]
generate-bindings = ["tss-esapi-sys/generate-bindings"]
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
208 changes: 208 additions & 0 deletions tss-esapi/src/abstraction/transient/key_attestation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
// 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, KeyHandle, SessionHandle},
interface_types::{
algorithm::{AsymmetricAlgorithm, HashingAlgorithm},
session_handles::{AuthSession, PolicySession},
},
structures::{EncryptedSecret, IDObject, SymmetricDefinition},
tss2_esys::{Tss2_MU_TPMT_PUBLIC_Marshal, TPM2B_PUBLIC, TPMT_PUBLIC},
utils::PublicKey,
Error, Result, WrapperErrorKind,
};
use log::error;
use std::convert::{TryFrom, TryInto};

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

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())?;

// Name of objects is derived from their publicArea, i.e. the marshaled TPMT_PUBLIC
let public = TPM2B_PUBLIC::from(object_public);
let mut pub_buf = [0u8; std::mem::size_of::<TPMT_PUBLIC>()];
let mut offset = 0;
let result = unsafe {
Tss2_MU_TPMT_PUBLIC_Marshal(
ionut-arm marked this conversation as resolved.
Show resolved Hide resolved
&public.publicArea,
&mut pub_buf as *mut u8,
std::mem::size_of::<TPMT_PUBLIC>()
.try_into()
.map_err(|_| Error::local_error(WrapperErrorKind::InternalError))?,
&mut offset,
)
};
let result = Error::from_tss_rc(result);
if !result.is_success() {
error!("Error in marshalling TPM2B");
return Err(result);
}
// `offset` will be small, so no risk in the conversion below
let public = pub_buf[..offset as usize].to_vec();

let attesting_key_pub = match key {
None => get_ek_object_public(&mut self.context)?,
Some(key) => key.material.public,
};
Ok(MakeCredParams {
name: object_name.value().to_vec(),
public,
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(
ionut-arm marked this conversation as resolved.
Show resolved Hide resolved
&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 (key_handle, session_2) = match key {
Some(key) => self.prepare_key_activate_cred(key),
None => self.prepare_ek_activate_cred(),
}
.or_else(|e| {
self.context.flush_context(object_handle.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())
}

// No key was given, use the EK. This requires using a Policy session
fn prepare_ek_activate_cred(&mut self) -> Result<(KeyHandle, Option<AuthSession>)> {
let session = self.context.start_auth_session(
None,
None,
None,
SessionType::Policy,
SymmetricDefinition::AES_128_CFB,
HashingAlgorithm::Sha256,
)?;
let _ = self.context.policy_secret(
PolicySession::try_from(session.unwrap())
.expect("Failed to convert auth session to policy session"),
AuthHandle::Endorsement,
Default::default(),
Default::default(),
Default::default(),
None,
);
Ok((
ek::create_ek_object(&mut self.context, AsymmetricAlgorithm::Rsa, None).or_else(
|e| {
self.context
.flush_context(SessionHandle::from(session).into())?;
Err(e)
},
)?,
session,
))
}

// Load key and create a HMAC session for it
fn prepare_key_activate_cred(
&mut self,
key: ObjectWrapper,
) -> Result<(KeyHandle, Option<AuthSession>)> {
let session = self.context.start_auth_session(
None,
None,
None,
SessionType::Hmac,
SymmetricDefinition::AES_128_CFB,
HashingAlgorithm::Sha256,
)?;
Ok((
self.load_key(key.params, key.material, key.auth)
.or_else(|e| {
self.context
.flush_context(SessionHandle::from(session).into())?;
Err(e)
})?,
session,
))
}
}

fn get_ek_object_public(context: &mut crate::Context) -> Result<PublicKey> {
let key_handle = ek::create_ek_object(context, AsymmetricAlgorithm::Rsa, None)?;
let (attesting_key_pub, _, _) = context.read_public(key_handle).or_else(|e| {
context.flush_context(key_handle.into())?;
Err(e)
})?;
context.flush_context(key_handle.into())?;

PublicKey::try_from(attesting_key_pub)
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,14 @@ use crate::{

use log::error;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::convert::{TryFrom, TryInto};
use zeroize::Zeroize;

mod key_attestation;

pub use key_attestation::MakeCredParams;

/// Parameters for the kinds of keys supported by the context
#[derive(Debug, Clone, Copy)]
pub enum KeyParams {
Expand Down Expand Up @@ -89,6 +94,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 Expand Up @@ -523,10 +535,10 @@ impl TransientKeyContext {
#[derive(Debug)]
pub struct TransientKeyContextBuilder {
tcti_name_conf: TctiNameConf,
hierarchy: Hierarchy,
root_key_size: u16, // TODO: replace with root key PUBLIC definition
root_key_auth_size: usize,
hierarchy_auth: Vec<u8>,
root_hierarchy: Hierarchy,
hierarchy_auth: HashMap<Hierarchy, Vec<u8>>,
default_context_cipher: SymmetricDefinitionObject,
session_hash_alg: HashingAlgorithm,
}
Expand All @@ -536,10 +548,10 @@ impl TransientKeyContextBuilder {
pub fn new() -> Self {
TransientKeyContextBuilder {
tcti_name_conf: TctiNameConf::Device(Default::default()),
hierarchy: Hierarchy::Owner,
root_hierarchy: Hierarchy::Owner,
root_key_size: 2048,
root_key_auth_size: 32,
hierarchy_auth: Vec::new(),
hierarchy_auth: HashMap::new(),
default_context_cipher: SymmetricDefinitionObject::AES_256_CFB,
session_hash_alg: HashingAlgorithm::Sha256,
}
Expand All @@ -551,9 +563,15 @@ impl TransientKeyContextBuilder {
self
}

/// Set the auth values for any hierarchies that will be used
pub fn with_hierarchy_auth(mut self, hierarchy: Hierarchy, auth: Vec<u8>) -> Self {
let _ = self.hierarchy_auth.insert(hierarchy, auth);
self
}

/// Define which hierarchy will be used for the keys being managed.
pub fn with_hierarchy(mut self, hierarchy: Hierarchy) -> Self {
self.hierarchy = hierarchy;
pub fn with_root_hierarchy(mut self, hierarchy: Hierarchy) -> Self {
self.root_hierarchy = hierarchy;
self
}

Expand All @@ -569,12 +587,6 @@ impl TransientKeyContextBuilder {
self
}

/// Input the authentication value of the working hierarchy.
pub fn with_hierarchy_auth(mut self, hierarchy_auth: Vec<u8>) -> Self {
self.hierarchy_auth = hierarchy_auth;
self
}

/// Define the cipher to be used within this context as a default.
///
/// Currently this default is used for:
Expand Down Expand Up @@ -615,7 +627,7 @@ impl TransientKeyContextBuilder {
/// `Context::set_handle_auth`
/// * if the root key authentication size is given greater than 32 or if the root key size is
/// not 1024, 2048, 3072 or 4096, a `InvalidParam` wrapper error is returned
pub fn build(self) -> Result<TransientKeyContext> {
pub fn build(mut self) -> Result<TransientKeyContext> {
if self.root_key_auth_size > 32 {
return Err(Error::local_error(ErrorKind::WrongParamSize));
}
Expand All @@ -631,9 +643,9 @@ impl TransientKeyContextBuilder {
None
};

if !self.hierarchy_auth.is_empty() {
let auth_hierarchy = Auth::try_from(self.hierarchy_auth)?;
context.tr_set_auth(self.hierarchy.into(), &auth_hierarchy)?;
for (hierarchy, auth) in self.hierarchy_auth.drain() {
let auth_hierarchy = Auth::try_from(auth)?;
context.tr_set_auth(hierarchy.into(), &auth_hierarchy)?;
}

let session = context
Expand All @@ -660,7 +672,7 @@ impl TransientKeyContextBuilder {

let root_key_handle = context
.create_primary(
self.hierarchy,
self.root_hierarchy,
&create_restricted_decryption_rsa_public(
self.default_context_cipher,
root_key_rsa_key_bits,
Expand Down
7 changes: 6 additions & 1 deletion tss-esapi/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ pub enum WrapperErrorKind {
InconsistentParams,
/// Returned when the value of a parameter is not yet supported.
UnsupportedParam,
/// Returend when the value of a parameter is invalid for that type.
/// Returned when the value of a parameter is invalid for that type.
InvalidParam,
/// Returned when the TPM returns an invalid value from a call.
WrongValueFromTpm,
Expand All @@ -72,6 +72,8 @@ pub enum WrapperErrorKind {
/// Returned when a handle is required to be in a specific state
/// (i.g. Open, Flushed, Closed) but it is not.
InvalidHandleState,
/// An unexpected internal error occurred.
InternalError,
}

impl std::fmt::Display for WrapperErrorKind {
Expand All @@ -97,6 +99,9 @@ impl std::fmt::Display for WrapperErrorKind {
WrapperErrorKind::WrongValueFromTpm => write!(f, "the TPM returned an invalid value."),
WrapperErrorKind::MissingAuthSession => write!(f, "Missing authorization session"),
WrapperErrorKind::InvalidHandleState => write!(f, "Invalid handle state"),
WrapperErrorKind::InternalError => {
write!(f, "an unexpected error occurred within the crate")
}
}
}
}
Expand Down
Loading