Skip to content

Commit 62fb9b7

Browse files
authored
Merge pull request #284 from ionut-arm/tkc-activate-cred
Add ActivateCredential support for TKC
2 parents e8cd513 + d523ce2 commit 62fb9b7

File tree

9 files changed

+524
-27
lines changed

9 files changed

+524
-27
lines changed

.github/workflows/ci.yml

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ jobs:
2222
run: docker build -t ubuntucontainer tss-esapi/tests/ --file tss-esapi/tests/Dockerfile-ubuntu
2323
- name: Run the container
2424
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
25+
- name: Run the cross-compilation script
26+
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
2527

2628
tests-ubuntu-v3:
2729
name: Ubuntu tests on v3.x.y of tpm2-tss

.github/workflows/nightly.yml

-2
Original file line numberDiff line numberDiff line change
@@ -51,5 +51,3 @@ jobs:
5151
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
5252
- name: Collect coverage results
5353
run: bash <(curl -s https://codecov.io/bash)
54-
- name: Run the cross-compilation script
55-
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

tss-esapi/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ primal = "0.3.0"
2727

2828
[dev-dependencies]
2929
env_logger = "0.7.1"
30+
sha2 = "0.9.8"
3031

3132
[features]
3233
generate-bindings = ["tss-esapi-sys/generate-bindings"]

tss-esapi/src/abstraction/ek.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ use std::convert::TryFrom;
2424
const RSA_2048_EK_CERTIFICATE_NV_INDEX: u32 = 0x01c00002;
2525
const ECC_P256_EK_CERTIFICATE_NV_INDEX: u32 = 0x01c0000a;
2626

27-
// Source: TCG EK Credential Profile for TPM Family 2.0; Level 0 Version 2.3 Revision 2
28-
// Appendix B.3.3 and B.3.4
29-
fn create_ek_public_from_default_template<IKC: IntoKeyCustomization>(
27+
/// Get the [`Public`] representing a default Endorsement Key
28+
///
29+
/// Source: TCG EK Credential Profile for TPM Family 2.0; Level 0 Version 2.3 Revision 2
30+
/// Appendix B.3.3 and B.3.4
31+
pub fn create_ek_public_from_default_template<IKC: IntoKeyCustomization>(
3032
alg: AsymmetricAlgorithm,
3133
key_customization: IKC,
3234
) -> Result<Public> {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
// Copyright 2021 Contributors to the Parsec project.
2+
// SPDX-License-Identifier: Apache-2.0
3+
use super::{ObjectWrapper, TransientKeyContext};
4+
use crate::{
5+
abstraction::ek,
6+
constants::SessionType,
7+
handles::{AuthHandle, KeyHandle, SessionHandle},
8+
interface_types::{
9+
algorithm::{AsymmetricAlgorithm, HashingAlgorithm},
10+
session_handles::{AuthSession, PolicySession},
11+
},
12+
structures::{EncryptedSecret, IDObject, SymmetricDefinition},
13+
tss2_esys::{Tss2_MU_TPMT_PUBLIC_Marshal, TPM2B_PUBLIC, TPMT_PUBLIC},
14+
utils::PublicKey,
15+
Error, Result, WrapperErrorKind,
16+
};
17+
use log::error;
18+
use std::convert::{TryFrom, TryInto};
19+
20+
#[derive(Debug)]
21+
/// Wrapper for the parameters needed by MakeCredential
22+
///
23+
/// The 3rd party requesting proof that the key is indeed backed
24+
/// by a TPM would perform a MakeCredential and would thus require
25+
/// `name` and `attesting_key_pub` as inputs for that operation.
26+
///
27+
/// `public` is not strictly needed, however it is returned as a
28+
/// convenience block of data. Since the MakeCredential operation
29+
/// bakes into the encrypted credential the identity of the key to
30+
/// be attested via its `name`, the correctness of the `name` must
31+
/// be verifiable by the said 3rd party. `public` bridges this gap:
32+
///
33+
/// * it includes all the public parameters of the attested key
34+
/// * can be hashed (in its marshaled form) with the name hash
35+
/// (found by unmarshaling it) to obtain `name`
36+
pub struct MakeCredParams {
37+
/// TPM name of the object being attested
38+
pub name: Vec<u8>,
39+
/// Encoding of the public parameters of the object whose name
40+
/// will be included in the credential computations
41+
pub public: Vec<u8>,
42+
/// Public part of the key used to protect the credential
43+
pub attesting_key_pub: PublicKey,
44+
}
45+
46+
impl TransientKeyContext {
47+
/// Get the data required to perform a MakeCredential
48+
///
49+
/// # Parameters
50+
///
51+
/// * `object` - the object whose TPM name will be included in
52+
/// the credential
53+
/// * `key` - the key to be used to encrypt the secret that wraps
54+
/// the credential
55+
///
56+
/// **Note**: If no `key` is given, the default Endorsement Key
57+
/// will be used.
58+
pub fn get_make_cred_params(
59+
&mut self,
60+
object: ObjectWrapper,
61+
key: Option<ObjectWrapper>,
62+
) -> Result<MakeCredParams> {
63+
let object_handle = self.load_key(object.params, object.material, None)?;
64+
let (object_public, object_name, _) =
65+
self.context.read_public(object_handle).or_else(|e| {
66+
self.context.flush_context(object_handle.into())?;
67+
Err(e)
68+
})?;
69+
self.context.flush_context(object_handle.into())?;
70+
71+
// Name of objects is derived from their publicArea, i.e. the marshaled TPMT_PUBLIC
72+
let public = TPM2B_PUBLIC::from(object_public);
73+
let mut pub_buf = [0u8; std::mem::size_of::<TPMT_PUBLIC>()];
74+
let mut offset = 0;
75+
let result = unsafe {
76+
Tss2_MU_TPMT_PUBLIC_Marshal(
77+
&public.publicArea,
78+
&mut pub_buf as *mut u8,
79+
std::mem::size_of::<TPMT_PUBLIC>()
80+
.try_into()
81+
.map_err(|_| Error::local_error(WrapperErrorKind::InternalError))?,
82+
&mut offset,
83+
)
84+
};
85+
let result = Error::from_tss_rc(result);
86+
if !result.is_success() {
87+
error!("Error in marshalling TPM2B");
88+
return Err(result);
89+
}
90+
// `offset` will be small, so no risk in the conversion below
91+
let public = pub_buf[..offset as usize].to_vec();
92+
93+
let attesting_key_pub = match key {
94+
None => get_ek_object_public(&mut self.context)?,
95+
Some(key) => key.material.public,
96+
};
97+
Ok(MakeCredParams {
98+
name: object_name.value().to_vec(),
99+
public,
100+
attesting_key_pub,
101+
})
102+
}
103+
104+
/// Perform an ActivateCredential operation for the given object
105+
///
106+
/// # Parameters
107+
///
108+
/// * `object` - the object whose TPM name is included in the credential
109+
/// * `key` - the key used to encrypt the secret that wraps the credential
110+
/// * `credential_blob` - encrypted credential that will be returned by the
111+
/// TPM
112+
/// * `secret` - encrypted secret that was used to encrypt the credential
113+
///
114+
/// **Note**: if no `key` is given, the default Endorsement Key
115+
/// will be used. You can find more information about the default Endorsement
116+
/// Key in the [ek] module.
117+
pub fn activate_credential(
118+
&mut self,
119+
object: ObjectWrapper,
120+
key: Option<ObjectWrapper>,
121+
credential_blob: Vec<u8>,
122+
secret: Vec<u8>,
123+
) -> Result<Vec<u8>> {
124+
let credential_blob = IDObject::try_from(credential_blob)?;
125+
let secret = EncryptedSecret::try_from(secret)?;
126+
let object_handle = self.load_key(object.params, object.material, object.auth)?;
127+
let (key_handle, session_2) = match key {
128+
Some(key) => self.prepare_key_activate_cred(key),
129+
None => self.prepare_ek_activate_cred(),
130+
}
131+
.or_else(|e| {
132+
self.context.flush_context(object_handle.into())?;
133+
Err(e)
134+
})?;
135+
136+
let (session_1, _, _) = self.context.sessions();
137+
let credential = self
138+
.context
139+
.execute_with_sessions((session_1, session_2, None), |ctx| {
140+
ctx.activate_credential(object_handle, key_handle, credential_blob, secret)
141+
})
142+
.or_else(|e| {
143+
self.context.flush_context(object_handle.into())?;
144+
self.context.flush_context(key_handle.into())?;
145+
self.context
146+
.flush_context(SessionHandle::from(session_2).into())?;
147+
Err(e)
148+
})?;
149+
150+
self.context.flush_context(object_handle.into())?;
151+
self.context.flush_context(key_handle.into())?;
152+
self.context
153+
.flush_context(SessionHandle::from(session_2).into())?;
154+
Ok(credential.value().to_vec())
155+
}
156+
157+
// No key was given, use the EK. This requires using a Policy session
158+
fn prepare_ek_activate_cred(&mut self) -> Result<(KeyHandle, Option<AuthSession>)> {
159+
let session = self.context.start_auth_session(
160+
None,
161+
None,
162+
None,
163+
SessionType::Policy,
164+
SymmetricDefinition::AES_128_CFB,
165+
HashingAlgorithm::Sha256,
166+
)?;
167+
let _ = self.context.policy_secret(
168+
PolicySession::try_from(session.unwrap())
169+
.expect("Failed to convert auth session to policy session"),
170+
AuthHandle::Endorsement,
171+
Default::default(),
172+
Default::default(),
173+
Default::default(),
174+
None,
175+
);
176+
Ok((
177+
ek::create_ek_object(&mut self.context, AsymmetricAlgorithm::Rsa, None).or_else(
178+
|e| {
179+
self.context
180+
.flush_context(SessionHandle::from(session).into())?;
181+
Err(e)
182+
},
183+
)?,
184+
session,
185+
))
186+
}
187+
188+
// Load key and create a HMAC session for it
189+
fn prepare_key_activate_cred(
190+
&mut self,
191+
key: ObjectWrapper,
192+
) -> Result<(KeyHandle, Option<AuthSession>)> {
193+
let session = self.context.start_auth_session(
194+
None,
195+
None,
196+
None,
197+
SessionType::Hmac,
198+
SymmetricDefinition::AES_128_CFB,
199+
HashingAlgorithm::Sha256,
200+
)?;
201+
Ok((
202+
self.load_key(key.params, key.material, key.auth)
203+
.or_else(|e| {
204+
self.context
205+
.flush_context(SessionHandle::from(session).into())?;
206+
Err(e)
207+
})?,
208+
session,
209+
))
210+
}
211+
}
212+
213+
fn get_ek_object_public(context: &mut crate::Context) -> Result<PublicKey> {
214+
let key_handle = ek::create_ek_object(context, AsymmetricAlgorithm::Rsa, None)?;
215+
let (attesting_key_pub, _, _) = context.read_public(key_handle).or_else(|e| {
216+
context.flush_context(key_handle.into())?;
217+
Err(e)
218+
})?;
219+
context.flush_context(key_handle.into())?;
220+
221+
PublicKey::try_from(attesting_key_pub)
222+
}

tss-esapi/src/abstraction/transient.rs tss-esapi/src/abstraction/transient/mod.rs

+29-17
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,14 @@ use crate::{
3636

3737
use log::error;
3838
use serde::{Deserialize, Serialize};
39+
use std::collections::HashMap;
3940
use std::convert::{TryFrom, TryInto};
4041
use zeroize::Zeroize;
4142

43+
mod key_attestation;
44+
45+
pub use key_attestation::MakeCredParams;
46+
4247
/// Parameters for the kinds of keys supported by the context
4348
#[derive(Debug, Clone, Copy)]
4449
pub enum KeyParams {
@@ -89,6 +94,13 @@ impl KeyMaterial {
8994
}
9095
}
9196

97+
#[derive(Debug, Clone)]
98+
pub struct ObjectWrapper {
99+
pub material: KeyMaterial,
100+
pub params: KeyParams,
101+
pub auth: Option<Auth>,
102+
}
103+
92104
/// Structure offering an abstracted programming experience.
93105
///
94106
/// The `TransientKeyContext` makes use of a root key from which the other, client-controlled
@@ -523,10 +535,10 @@ impl TransientKeyContext {
523535
#[derive(Debug)]
524536
pub struct TransientKeyContextBuilder {
525537
tcti_name_conf: TctiNameConf,
526-
hierarchy: Hierarchy,
527538
root_key_size: u16, // TODO: replace with root key PUBLIC definition
528539
root_key_auth_size: usize,
529-
hierarchy_auth: Vec<u8>,
540+
root_hierarchy: Hierarchy,
541+
hierarchy_auth: HashMap<Hierarchy, Vec<u8>>,
530542
default_context_cipher: SymmetricDefinitionObject,
531543
session_hash_alg: HashingAlgorithm,
532544
}
@@ -536,10 +548,10 @@ impl TransientKeyContextBuilder {
536548
pub fn new() -> Self {
537549
TransientKeyContextBuilder {
538550
tcti_name_conf: TctiNameConf::Device(Default::default()),
539-
hierarchy: Hierarchy::Owner,
551+
root_hierarchy: Hierarchy::Owner,
540552
root_key_size: 2048,
541553
root_key_auth_size: 32,
542-
hierarchy_auth: Vec::new(),
554+
hierarchy_auth: HashMap::new(),
543555
default_context_cipher: SymmetricDefinitionObject::AES_256_CFB,
544556
session_hash_alg: HashingAlgorithm::Sha256,
545557
}
@@ -551,9 +563,15 @@ impl TransientKeyContextBuilder {
551563
self
552564
}
553565

566+
/// Set the auth values for any hierarchies that will be used
567+
pub fn with_hierarchy_auth(mut self, hierarchy: Hierarchy, auth: Vec<u8>) -> Self {
568+
let _ = self.hierarchy_auth.insert(hierarchy, auth);
569+
self
570+
}
571+
554572
/// Define which hierarchy will be used for the keys being managed.
555-
pub fn with_hierarchy(mut self, hierarchy: Hierarchy) -> Self {
556-
self.hierarchy = hierarchy;
573+
pub fn with_root_hierarchy(mut self, hierarchy: Hierarchy) -> Self {
574+
self.root_hierarchy = hierarchy;
557575
self
558576
}
559577

@@ -569,12 +587,6 @@ impl TransientKeyContextBuilder {
569587
self
570588
}
571589

572-
/// Input the authentication value of the working hierarchy.
573-
pub fn with_hierarchy_auth(mut self, hierarchy_auth: Vec<u8>) -> Self {
574-
self.hierarchy_auth = hierarchy_auth;
575-
self
576-
}
577-
578590
/// Define the cipher to be used within this context as a default.
579591
///
580592
/// Currently this default is used for:
@@ -615,7 +627,7 @@ impl TransientKeyContextBuilder {
615627
/// `Context::set_handle_auth`
616628
/// * if the root key authentication size is given greater than 32 or if the root key size is
617629
/// not 1024, 2048, 3072 or 4096, a `InvalidParam` wrapper error is returned
618-
pub fn build(self) -> Result<TransientKeyContext> {
630+
pub fn build(mut self) -> Result<TransientKeyContext> {
619631
if self.root_key_auth_size > 32 {
620632
return Err(Error::local_error(ErrorKind::WrongParamSize));
621633
}
@@ -631,9 +643,9 @@ impl TransientKeyContextBuilder {
631643
None
632644
};
633645

634-
if !self.hierarchy_auth.is_empty() {
635-
let auth_hierarchy = Auth::try_from(self.hierarchy_auth)?;
636-
context.tr_set_auth(self.hierarchy.into(), &auth_hierarchy)?;
646+
for (hierarchy, auth) in self.hierarchy_auth.drain() {
647+
let auth_hierarchy = Auth::try_from(auth)?;
648+
context.tr_set_auth(hierarchy.into(), &auth_hierarchy)?;
637649
}
638650

639651
let session = context
@@ -660,7 +672,7 @@ impl TransientKeyContextBuilder {
660672

661673
let root_key_handle = context
662674
.create_primary(
663-
self.hierarchy,
675+
self.root_hierarchy,
664676
&create_restricted_decryption_rsa_public(
665677
self.default_context_cipher,
666678
root_key_rsa_key_bits,

0 commit comments

Comments
 (0)