Skip to content

Commit 19fdc72

Browse files
committed
Add ECDSA support for TPM provider
This commit expands the supported algorithms for the TPM provider to include ECDSA key creation, as well as signing, verification and public key export for them. Signed-off-by: Ionut Mihalcea <ionut.mihalcea@arm.com>
1 parent 578d6d5 commit 19fdc72

File tree

7 files changed

+318
-103
lines changed

7 files changed

+318
-103
lines changed

Cargo.lock

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ name = "parsec"
1818
path = "src/bin/main.rs"
1919

2020
[dependencies]
21-
parsec-interface = "0.14.0"
21+
parsec-interface = "0.14.1"
2222
rand = "0.7.2"
2323
base64 = "0.10.1"
2424
uuid = "0.7.4"
@@ -33,7 +33,7 @@ log = { version = "0.4.8", features = ["serde"] }
3333
pkcs11 = { version = "0.4.0", optional = true }
3434
picky-asn1-der = { version = "0.2.2", optional = true }
3535
picky-asn1 = { version = "0.2.1", optional = true }
36-
tss-esapi = { version = "4.0.0-alpha.1", optional = true }
36+
tss-esapi = { version = "4.0.2-alpha.1", optional = true }
3737
bincode = "1.1.4"
3838
structopt = "0.3.5"
3939
derivative = "2.1.1"

e2e_tests/tests/per_provider/normal_tests/key_attributes.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// SPDX-License-Identifier: Apache-2.0
33
use e2e_tests::TestClient;
44
use parsec_client::core::interface::operations::psa_algorithm::{
5-
Algorithm, AsymmetricSignature, Cipher, Hash,
5+
Algorithm, AsymmetricSignature, Hash,
66
};
77
use parsec_client::core::interface::operations::psa_key_attributes::{
88
KeyAttributes, KeyPolicy, KeyType, UsageFlags,
@@ -100,7 +100,10 @@ fn wrong_permitted_algorithm() {
100100

101101
let key_type = KeyType::RsaKeyPair;
102102
// Do not permit RSA PKCS 1v15 signing algorithm with SHA-256.
103-
let permitted_algorithm = Algorithm::Cipher(Cipher::Ctr);
103+
let permitted_algorithm =
104+
Algorithm::AsymmetricSignature(AsymmetricSignature::RsaPkcs1v15Sign {
105+
hash_alg: Hash::Sha512,
106+
});
104107
let key_attributes = KeyAttributes {
105108
key_type,
106109
key_bits: 1024,

src/providers/tpm_provider/asym_sign.rs

Lines changed: 24 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -7,71 +7,51 @@ use log::error;
77
use parsec_interface::operations::psa_algorithm::*;
88
use parsec_interface::operations::{psa_sign_hash, psa_verify_hash};
99
use parsec_interface::requests::{ProviderID, ResponseStatus, Result};
10-
use tss_esapi::{constants::TPM2_ALG_SHA256, utils::AsymSchemeUnion, utils::Signature};
1110

1211
impl TpmProvider {
1312
pub(super) fn psa_sign_hash_internal(
1413
&self,
1514
app_name: ApplicationName,
1615
op: psa_sign_hash::Operation,
1716
) -> Result<psa_sign_hash::Result> {
18-
let key_name = op.key_name;
19-
let hash = op.hash;
20-
let alg = op.alg;
21-
let key_triple = KeyTriple::new(app_name, ProviderID::Tpm, key_name);
17+
let key_triple = KeyTriple::new(app_name, ProviderID::Tpm, op.key_name.clone());
2218

2319
let store_handle = self.key_info_store.read().expect("Key store lock poisoned");
2420
let mut esapi_context = self
2521
.esapi_context
2622
.lock()
2723
.expect("ESAPI Context lock poisoned");
2824

29-
if alg
30-
!= (AsymmetricSignature::RsaPkcs1v15Sign {
31-
hash_alg: Hash::Sha256,
32-
})
33-
{
34-
error!(
35-
"The TPM provider currently only supports signature algorithm to be RSA PKCS#1 v1.5 and the text hashed with SHA-256.");
36-
return Err(ResponseStatus::PsaErrorNotSupported);
37-
}
38-
39-
if hash.len() != 32 {
40-
error!("The SHA-256 hash must be 32 bytes long.");
41-
return Err(ResponseStatus::PsaErrorInvalidArgument);
42-
}
43-
4425
let (password_context, key_attributes) =
4526
key_management::get_password_context(&*store_handle, key_triple)?;
4627

47-
key_attributes.can_sign_hash()?;
48-
key_attributes.permits_alg(alg.into())?;
49-
key_attributes.compatible_with_alg(alg.into())?;
50-
51-
match alg {
52-
AsymmetricSignature::RsaPkcs1v15Sign {
53-
hash_alg: Hash::Sha256,
54-
} => (),
28+
match op.alg {
29+
AsymmetricSignature::RsaPkcs1v15Sign { .. } => (),
30+
AsymmetricSignature::Ecdsa { .. } => (),
5531
_ => {
5632
error!(
57-
"The TPM provider currently only supports \"RSA PKCS#1 v1.5 signature with hashing\" algorithm with SHA-256 as hashing algorithm for the PsaSignHash operation.");
33+
"Requested algorithm is not supported by the TPM provider: {:?}",
34+
op.alg
35+
);
5836
return Err(ResponseStatus::PsaErrorNotSupported);
5937
}
6038
}
6139

40+
op.validate(key_attributes)?;
41+
6242
let signature = esapi_context
6343
.sign(
6444
password_context.context,
6545
&password_context.auth_value,
66-
&hash,
46+
&op.hash,
6747
)
6848
.or_else(|e| {
6949
error!("Error signing: {}.", e);
7050
Err(utils::to_response_status(e))
7151
})?;
7252

7353
Ok(psa_sign_hash::Result {
74-
signature: signature.signature,
54+
signature: utils::signature_data_to_bytes(signature.signature, key_attributes)?,
7555
})
7656
}
7757

@@ -80,59 +60,36 @@ impl TpmProvider {
8060
app_name: ApplicationName,
8161
op: psa_verify_hash::Operation,
8262
) -> Result<psa_verify_hash::Result> {
83-
let key_name = op.key_name;
84-
let hash = op.hash;
85-
let alg = op.alg;
86-
let signature = op.signature;
87-
let key_triple = KeyTriple::new(app_name, ProviderID::Tpm, key_name);
63+
let key_triple = KeyTriple::new(app_name, ProviderID::Tpm, op.key_name.clone());
8864

8965
let store_handle = self.key_info_store.read().expect("Key store lock poisoned");
9066
let mut esapi_context = self
9167
.esapi_context
9268
.lock()
9369
.expect("ESAPI Context lock poisoned");
9470

95-
if alg
96-
!= (AsymmetricSignature::RsaPkcs1v15Sign {
97-
hash_alg: Hash::Sha256,
98-
})
99-
{
100-
error!(
101-
"The TPM provider currently only supports signature algorithm to be RSA PKCS#1 v1.5 and the text hashed with SHA-256.");
102-
return Err(ResponseStatus::PsaErrorNotSupported);
103-
}
104-
105-
if hash.len() != 32 {
106-
error!("The SHA-256 hash must be 32 bytes long.");
107-
return Err(ResponseStatus::PsaErrorInvalidArgument);
108-
}
109-
110-
let signature = Signature {
111-
scheme: AsymSchemeUnion::RSASSA(TPM2_ALG_SHA256),
112-
signature,
113-
};
114-
11571
let (password_context, key_attributes) =
11672
key_management::get_password_context(&*store_handle, key_triple)?;
11773

118-
key_attributes.can_verify_hash()?;
119-
key_attributes.permits_alg(alg.into())?;
120-
key_attributes.compatible_with_alg(alg.into())?;
121-
122-
match alg {
123-
AsymmetricSignature::RsaPkcs1v15Sign {
124-
hash_alg: Hash::Sha256,
125-
} => (),
74+
match op.alg {
75+
AsymmetricSignature::RsaPkcs1v15Sign { .. } => (),
76+
AsymmetricSignature::Ecdsa { .. } => (),
12677
_ => {
12778
error!(
128-
"The TPM provider currently only supports \"RSA PKCS#1 v1.5 signature with hashing\" algorithm with SHA-256 as hashing algorithm for the PsaVerifyHash operation.");
79+
"Requested algorithm is not supported by the TPM provider: {:?}",
80+
op.alg
81+
);
12982
return Err(ResponseStatus::PsaErrorNotSupported);
13083
}
13184
}
13285

86+
op.validate(key_attributes)?;
87+
88+
let signature = utils::parsec_to_tpm_signature(op.signature, key_attributes, op.alg)?;
89+
13390
let _ = esapi_context
134-
.verify_signature(password_context.context, &hash, signature)
135-
.or_else(|e| Err(utils::to_response_status(e)))?;
91+
.verify_signature(password_context.context, &op.hash, signature)
92+
.map_err(utils::to_response_status)?;
13693

13794
Ok(psa_verify_hash::Result {})
13895
}

src/providers/tpm_provider/key_management.rs

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ use parsec_interface::operations::{
1313
psa_destroy_key, psa_export_public_key, psa_generate_key, psa_import_key,
1414
};
1515
use parsec_interface::requests::{ProviderID, ResponseStatus, Result};
16-
use picky_asn1::wrapper::IntegerAsn1;
1716

1817
// Public exponent value for all RSA keys.
1918
const PUBLIC_EXPONENT: [u8; 3] = [0x01, 0x00, 0x01];
@@ -69,17 +68,9 @@ impl TpmProvider {
6968
app_name: ApplicationName,
7069
op: psa_generate_key::Operation,
7170
) -> Result<psa_generate_key::Result> {
72-
if op.attributes.key_type != KeyType::RsaKeyPair {
73-
error!("The TPM provider currently only supports creating RSA key pairs.");
74-
return Err(ResponseStatus::PsaErrorNotSupported);
75-
}
76-
7771
let key_name = op.key_name;
7872
let attributes = op.attributes;
7973
let key_triple = KeyTriple::new(app_name, ProviderID::Tpm, key_name);
80-
// This should never panic on 32 bits or more machines.
81-
let key_size = std::convert::TryFrom::try_from(op.attributes.key_bits)
82-
.expect("Conversion to usize failed.");
8374

8475
let mut store_handle = self
8576
.key_info_store
@@ -91,7 +82,7 @@ impl TpmProvider {
9182
.expect("ESAPI Context lock poisoned");
9283

9384
let (key_context, auth_value) = esapi_context
94-
.create_rsa_signing_key(key_size, AUTH_VAL_LEN)
85+
.create_signing_key(utils::parsec_to_tpm_params(attributes)?, AUTH_VAL_LEN)
9586
.or_else(|e| {
9687
error!("Error creating a RSA signing key: {}.", e);
9788
Err(utils::to_response_status(e))
@@ -199,7 +190,7 @@ impl TpmProvider {
199190
.lock()
200191
.expect("ESAPI Context lock poisoned");
201192

202-
let (password_context, _key_attributes) = get_password_context(&*store_handle, key_triple)?;
193+
let (password_context, key_attributes) = get_password_context(&*store_handle, key_triple)?;
203194

204195
let pub_key_data = esapi_context
205196
.read_public_key(password_context.context)
@@ -208,18 +199,9 @@ impl TpmProvider {
208199
Err(utils::to_response_status(e))
209200
})?;
210201

211-
let key = RsaPublicKey {
212-
// To produce a valid ASN.1 RSAPublicKey structure, 0x00 is put in front of the positive
213-
// modulus if highest significant bit is one, to differentiate it from a negative number.
214-
modulus: IntegerAsn1::from_unsigned_bytes_be(pub_key_data),
215-
public_exponent: IntegerAsn1::from_signed_bytes_be(PUBLIC_EXPONENT.to_vec()),
216-
};
217-
let key_data = picky_asn1_der::to_vec(&key).or_else(|err| {
218-
error!("Could not serialise key elements: {}.", err);
219-
Err(ResponseStatus::PsaErrorCommunicationFailure)
220-
})?;
221-
222-
Ok(psa_export_public_key::Result { data: key_data })
202+
Ok(psa_export_public_key::Result {
203+
data: utils::pub_key_to_bytes(pub_key_data, key_attributes)?,
204+
})
223205
}
224206

225207
pub(super) fn psa_destroy_key_internal(
@@ -234,10 +216,9 @@ impl TpmProvider {
234216
.write()
235217
.expect("Key store lock poisoned");
236218

237-
let error_closure = |e| Err(key_info_managers::to_response_status(e));
238219
if store_handle
239220
.remove(&key_triple)
240-
.or_else(error_closure)?
221+
.map_err(key_info_managers::to_response_status)?
241222
.is_none()
242223
{
243224
error!(

0 commit comments

Comments
 (0)