Skip to content

Commit b169b11

Browse files
authored
Merge pull request #558 from ionut-arm/activate-cred
Activate credential
2 parents 8a178b5 + b5d57c4 commit b169b11

File tree

17 files changed

+428
-35
lines changed

17 files changed

+428
-35
lines changed

Cargo.lock

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ log = { version = "0.4.14", features = ["serde"] }
2929
cryptoki = { version = "0.2.0", optional = true, features = ["psa-crypto-conversions"] }
3030
picky-asn1-der = { version = "<=0.2.4", optional = true }
3131
picky-asn1 = { version = ">=0.3.1, <=0.3.1", optional = true }
32-
tss-esapi = { git = "https://github.com/parallaxsecond/rust-tss-esapi.git", revision = "714fe81e4a9b1964b878dee9ed5e974d6891092e", optional = true }
32+
tss-esapi = { git = "https://github.com/parallaxsecond/rust-tss-esapi.git", rev = "62fb9b7b05b1e607518ae127406f3b85991205b9", optional = true }
3333
bincode = "1.3.1"
3434
structopt = "0.3.21"
3535
derivative = "2.2.0"

ci.sh

+11
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ cleanup () {
1212
stop_service
1313
# Stop tpm_server if running
1414
if [ -n "$TPM_SRV_PID" ]; then kill $TPM_SRV_PID || true; fi
15+
if [ -n "$TPM_MC_SRV_PID" ]; then kill $TPM_MC_SRV_PID || true; fi
1516
# Remove the slot_number line added earlier
1617
find e2e_tests -name "*toml" -not -name "Cargo.toml" -exec sed -i 's/^slot_number =.*/# slot_number/' {} \;
1718
# Remove fake mapping and temp files
@@ -163,6 +164,16 @@ if [ "$PROVIDER_NAME" = "tpm" ] || [ "$PROVIDER_NAME" = "all" ] || [ "$PROVIDER_
163164
# The -c flag is not used because some keys were created in the TPM via the generate-keys.sh
164165
# script. Ownership has already been taken with "tpm_pass".
165166
tpm2_startup -T mssim
167+
168+
# Start and configure TPM server for MakeCredential
169+
TPM_MC_PORT=4321
170+
mkdir -p /tmp/mc_tpm
171+
pushd /tmp/mc_tpm
172+
tpm_server -port $TPM_MC_PORT &
173+
TPM_MC_SRV_PID=$!
174+
sleep 5
175+
tpm2_startup -c -T mssim:port=$TPM_MC_PORT
176+
popd
166177
fi
167178

168179
if [ "$PROVIDER_NAME" = "pkcs11" ] || [ "$PROVIDER_NAME" = "all" ] || [ "$PROVIDER_NAME" = "coverage" ]; then

config.toml

+8
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,14 @@ key_info_manager = "on-disk-manager"
154154
# e.g. "str:password", or to represent a string version of a hex value, e.g. "hex:1a2b3c". If no prefix is
155155
# provided, the value is considered to be a string.
156156
#owner_hierarchy_auth = "password"
157+
# (Optional) Authentication value for performing operations on the TPM Endorsement Hierarchy. The string can
158+
# be empty, however we strongly suggest that you use a secure passcode.
159+
# This authentication value is used for operations that rely on keys stored in the Endorsement Hierarchy, e.g.
160+
# key attestation using the default Endorsement Key.
161+
# To align with TPM tooling, PARSEC allows "endorsement_hierarchy_auth" to have a prefix indicating a string value,
162+
# e.g. "str:password", or to represent a string version of a hex value, e.g. "hex:1a2b3c". If no prefix is
163+
# provided, the value is considered to be a string.
164+
#endorsement_hierarchy_auth = "password"
157165
# (Optional) Allows the service to still start without this provider if there is no TPM on the system. The priority list of providers will be as if this provider was commented out.
158166
#skip_if_no_tpm = false
159167

e2e_tests/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ publish = false
1111

1212
[dependencies]
1313
serde = { version = "1.0.123", features = ["derive"] }
14-
parsec-client = { git = "https://github.com/parallaxsecond/parsec-client-rust", rev = "9e7dd111e77afa9168c1bff84963125057568b6f", features = ["testing", "spiffe-auth"] }
14+
parsec-client = { git = "https://github.com/parallaxsecond/parsec-client-rust", rev = "119664eac501c7f1d207f03905311a0634db13a6", features = ["testing", "spiffe-auth"] }
1515
log = "0.4.14"
1616
# Compatible version with crate rsa
1717
rand = "0.7.3"
@@ -27,6 +27,7 @@ num_cpus = "1.13.0"
2727
picky-asn1-der = "0.2.4"
2828
picky-asn1 = "0.3.1"
2929
sha2 = "0.9.3"
30+
tss-esapi = { git = "https://github.com/parallaxsecond/rust-tss-esapi.git", rev = "62fb9b7b05b1e607518ae127406f3b85991205b9" }
3031

3132
[features]
3233
mbed-crypto-provider = []

e2e_tests/docker_image/generate-keys.sh

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ sleep 5
2222
tpm2_startup -c -T mssim
2323
sleep 2
2424
tpm2_changeauth -c owner tpm_pass -T mssim
25+
tpm2_changeauth -c endorsement endorsement_pass -T mssim
2526
cd /tmp/create_keys/parsec/e2e_tests
2627
SLOT_NUMBER=`softhsm2-util --show-slots | head -n2 | tail -n1 | cut -d " " -f 2`
2728
find . -name "*toml" -not -name "Cargo.toml" -exec sed -i "s/^# slot_number.*$/slot_number = $SLOT_NUMBER/" {} \;

e2e_tests/provider_cfg/tpm/config.toml

+1
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,4 @@ provider_type = "Tpm"
2727
key_info_manager = "on-disk-manager"
2828
tcti = "mssim:host=127.0.0.1,port=2321"
2929
owner_hierarchy_auth = "hex:74706d5f70617373" # "tpm_pass" in hex
30+
endorsement_hierarchy_auth = "str:endorsement_pass"

e2e_tests/src/lib.rs

+21
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ pub mod stress;
66

77
pub use raw_request::RawRequestClient;
88

9+
pub use parsec_client;
910
pub use parsec_client::core::request_client::RequestClient;
1011
pub use parsec_client::error;
1112

@@ -805,6 +806,26 @@ impl TestClient {
805806
.can_do_crypto(check_type, attributes)
806807
.map_err(convert_error)
807808
}
809+
810+
pub fn prepare_activate_credential(
811+
&self,
812+
key_name: String,
813+
) -> Result<parsec_client::core::basic_client::PrepareActivateCredential> {
814+
self.basic_client
815+
.prepare_activate_credential(key_name, None)
816+
.map_err(convert_error)
817+
}
818+
819+
pub fn activate_credential(
820+
&self,
821+
key_name: String,
822+
credential: Vec<u8>,
823+
secret: Vec<u8>,
824+
) -> Result<Vec<u8>> {
825+
self.basic_client
826+
.activate_credential_attestation(key_name, None, credential, secret)
827+
.map_err(convert_error)
828+
}
808829
}
809830

810831
impl Default for TestClient {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// Copyright 2021 Contributors to the Parsec project.
2+
// SPDX-License-Identifier: Apache-2.0
3+
#![cfg(feature = "tpm-provider")]
4+
use e2e_tests::auto_test_keyname;
5+
use e2e_tests::parsec_client::core::basic_client::PrepareActivateCredential;
6+
use e2e_tests::TestClient;
7+
use parsec_client::core::interface::requests::Opcode;
8+
use std::{
9+
convert::{TryFrom, TryInto},
10+
env,
11+
str::FromStr,
12+
};
13+
use tss_esapi::{
14+
abstraction::ek,
15+
abstraction::transient::MakeCredParams,
16+
interface_types::{algorithm::AsymmetricAlgorithm, resource_handles::Hierarchy},
17+
structures::{Public, PublicKeyRsa},
18+
tcti_ldr::{NetworkTPMConfig, TctiNameConf},
19+
utils::PublicKey,
20+
Context,
21+
};
22+
23+
const DEFAULT_HELPER_TPM_CONF: &str = "port=4321";
24+
const CREDENTIAL: [u8; 16] = [0x11; 16];
25+
26+
fn create_tcti() -> TctiNameConf {
27+
match env::var("TEST_TCTI") {
28+
Err(_) => TctiNameConf::Mssim(
29+
NetworkTPMConfig::from_str(DEFAULT_HELPER_TPM_CONF)
30+
.expect("Failed to parse default TPM config"),
31+
),
32+
Ok(tctistr) => TctiNameConf::from_str(&tctistr).expect("Error parsing TEST_TCTI"),
33+
}
34+
}
35+
36+
fn make_credential(prep_activ_cred: PrepareActivateCredential) -> (Vec<u8>, Vec<u8>) {
37+
let make_cred_params = MakeCredParams {
38+
name: prep_activ_cred.name,
39+
public: prep_activ_cred.public,
40+
attesting_key_pub: PublicKey::Rsa(prep_activ_cred.attesting_key_pub),
41+
};
42+
let mut basic_ctx = Context::new(create_tcti()).expect("Failed to start TPM context");
43+
// the public part of the EK is used, so we retrieve the parameters
44+
let key_pub =
45+
ek::create_ek_public_from_default_template(AsymmetricAlgorithm::Rsa, None).unwrap();
46+
let key_pub = if let Public::Rsa {
47+
object_attributes,
48+
name_hashing_algorithm,
49+
auth_policy,
50+
parameters,
51+
..
52+
} = key_pub
53+
{
54+
Public::Rsa {
55+
object_attributes,
56+
name_hashing_algorithm,
57+
auth_policy,
58+
parameters,
59+
unique: if let PublicKey::Rsa(val) = make_cred_params.attesting_key_pub {
60+
PublicKeyRsa::try_from(val).unwrap()
61+
} else {
62+
panic!("Wrong public key type");
63+
},
64+
}
65+
} else {
66+
panic!("Wrong Public type");
67+
};
68+
let pub_handle = basic_ctx
69+
.load_external_public(&key_pub, Hierarchy::Owner)
70+
.unwrap();
71+
72+
let (cred, secret) = basic_ctx
73+
.make_credential(
74+
pub_handle,
75+
CREDENTIAL.to_vec().try_into().unwrap(),
76+
make_cred_params.name.to_vec().try_into().unwrap(),
77+
)
78+
.unwrap();
79+
(cred.value().to_vec(), secret.value().to_vec())
80+
}
81+
82+
#[test]
83+
fn activate_credential() {
84+
let key_name = auto_test_keyname!();
85+
let mut client = TestClient::new();
86+
if !client.is_operation_supported(Opcode::PrepareKeyAttestation) {
87+
return;
88+
}
89+
client
90+
.generate_rsa_sign_key(key_name.clone())
91+
.expect("Failed to generate key");
92+
let prep_activ_cred = client
93+
.prepare_activate_credential(key_name.clone())
94+
.expect("Failed to get parameters for MakeCredential");
95+
96+
let (cred, secret) = make_credential(prep_activ_cred);
97+
98+
let cred_out = client
99+
.activate_credential(key_name, cred, secret)
100+
.expect("Failed to activate credential");
101+
102+
assert_eq!(cred_out, CREDENTIAL.to_vec());
103+
}

e2e_tests/tests/per_provider/normal_tests/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,6 @@ mod generate_random;
1313
mod hash;
1414
mod import_key;
1515
mod key_agreement;
16+
mod key_attestation;
1617
mod key_attributes;
1718
mod ping;

src/back/backend_handler.rs

+15
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,21 @@ impl BackEndHandler {
286286
trace!("can_do_crypto egress");
287287
self.result_to_response(NativeResult::CanDoCrypto(result), header)
288288
}
289+
NativeOperation::PrepareKeyAttestation(op_prepare_key_attestation) => {
290+
let app = unwrap_or_else_return!(app.ok_or(ResponseStatus::NotAuthenticated));
291+
let result = unwrap_or_else_return!(self
292+
.provider
293+
.prepare_key_attestation(app.into(), op_prepare_key_attestation));
294+
trace!("prepare_key_attestation egress");
295+
self.result_to_response(NativeResult::PrepareKeyAttestation(result), header)
296+
}
297+
NativeOperation::AttestKey(op_attest_key) => {
298+
let app = unwrap_or_else_return!(app.ok_or(ResponseStatus::NotAuthenticated));
299+
let result =
300+
unwrap_or_else_return!(self.provider.attest_key(app.into(), op_attest_key));
301+
trace!("attest_key egress");
302+
self.result_to_response(NativeResult::AttestKey(result), header)
303+
}
289304
_ => {
290305
// This default arm should be removed
291306
// when all operation defind in Parsec-interface are implemented in the match.

src/providers/mod.rs

+26-5
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,12 @@ pub mod trusted_service;
3333

3434
use crate::authenticators::ApplicationName;
3535
use parsec_interface::operations::{
36-
can_do_crypto, delete_client, list_authenticators, list_clients, list_keys, list_opcodes,
37-
list_providers, ping, psa_aead_decrypt, psa_aead_encrypt, psa_asymmetric_decrypt,
38-
psa_asymmetric_encrypt, psa_destroy_key, psa_export_key, psa_export_public_key,
39-
psa_generate_key, psa_generate_random, psa_hash_compare, psa_hash_compute, psa_import_key,
40-
psa_raw_key_agreement, psa_sign_hash, psa_sign_message, psa_verify_hash, psa_verify_message,
36+
attest_key, can_do_crypto, delete_client, list_authenticators, list_clients, list_keys,
37+
list_opcodes, list_providers, ping, prepare_key_attestation, psa_aead_decrypt,
38+
psa_aead_encrypt, psa_asymmetric_decrypt, psa_asymmetric_encrypt, psa_destroy_key,
39+
psa_export_key, psa_export_public_key, psa_generate_key, psa_generate_random, psa_hash_compare,
40+
psa_hash_compute, psa_import_key, psa_raw_key_agreement, psa_sign_hash, psa_sign_message,
41+
psa_verify_hash, psa_verify_message,
4142
};
4243
use parsec_interface::requests::{ResponseStatus, Result};
4344

@@ -308,4 +309,24 @@ pub trait Provide {
308309
trace!("can_do_crypto main ingress");
309310
Err(ResponseStatus::PsaErrorNotSupported)
310311
}
312+
313+
/// Prepare a key attestation operation.
314+
fn prepare_key_attestation(
315+
&self,
316+
_app_name: ApplicationName,
317+
_op: prepare_key_attestation::Operation,
318+
) -> Result<prepare_key_attestation::Result> {
319+
trace!("prepare_key_attestation ingress");
320+
Err(ResponseStatus::PsaErrorNotSupported)
321+
}
322+
323+
/// Attest a key.
324+
fn attest_key(
325+
&self,
326+
_app_name: ApplicationName,
327+
_op: attest_key::Operation,
328+
) -> Result<attest_key::Result> {
329+
trace!("attest_key ingress");
330+
Err(ResponseStatus::PsaErrorNotSupported)
331+
}
311332
}

0 commit comments

Comments
 (0)