Skip to content

Commit 15eebfb

Browse files
committed
Update attribute handling in PKCS11 provider
This commit brings several improvements to the PKCS11 provider. It updates the way we handle parameters for the PKCS11 provider, making the process of adding support for new key types more straight forward. It creates abstractions over PKCS11 types to safely handle some of the functionality that the pkcs11 crate requires. It adds asymmetric encryption and decryption support for the PKCS11 provider. It improves the way we handle test distribution, so each test is run only for the providers that support that functionality. Since SoftHSM does not support RSA OAEP with anything but SHA1, a new test was added for that. Co-authored-by: Ionut Mihalcea <ionut.mihalcea@arm.com> Co-authored-by: Hugues de Valon <hugues.devalon@arm.com> Signed-off-by: Ionut Mihalcea <ionut.mihalcea@arm.com>
1 parent 5cb7685 commit 15eebfb

File tree

13 files changed

+734
-173
lines changed

13 files changed

+734
-173
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ hex = "0.4.2"
4242
picky = "5.0.0"
4343
psa-crypto = { version = "0.5.0" , default-features = false, features = ["operations"], optional = true }
4444
zeroize = { version = "1.1.0", features = ["zeroize_derive"] }
45-
picky-asn1-x509 = { version = "0.1.0", optional = true }
45+
picky-asn1-x509 = { version = "0.3.0", optional = true }
4646
users = "0.10.0"
4747
libc = "0.2.72"
4848

ci.sh

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,10 @@ while [ "$#" -gt 0 ]; do
6868
cp $(pwd)/e2e_tests/provider_cfg/$1/config.toml $CONFIG_PATH
6969
if [ "$PROVIDER_NAME" = "all" ]; then
7070
FEATURES="--features=all-providers,no-parsec-user-and-clients-group"
71+
TEST_FEATURES="--features=all-providers"
7172
else
7273
FEATURES="--features=$1-provider,no-parsec-user-and-clients-group"
74+
TEST_FEATURES="--features=$1-provider"
7375
fi
7476
;;
7577
*)
@@ -134,15 +136,15 @@ pgrep -f target/debug/parsec >/dev/null
134136

135137
if [ "$PROVIDER_NAME" = "all" ]; then
136138
echo "Execute all-providers tests"
137-
RUST_BACKTRACE=1 cargo test --manifest-path ./e2e_tests/Cargo.toml all_providers
138-
RUST_BACKTRACE=1 cargo test --manifest-path ./e2e_tests/Cargo.toml config
139+
RUST_BACKTRACE=1 cargo test $TEST_FEATURES --manifest-path ./e2e_tests/Cargo.toml all_providers
140+
RUST_BACKTRACE=1 cargo test $TEST_FEATURES --manifest-path ./e2e_tests/Cargo.toml config
139141
else
140142
# Per provider tests
141143
echo "Execute normal tests"
142-
RUST_BACKTRACE=1 cargo test --manifest-path ./e2e_tests/Cargo.toml normal_tests
144+
RUST_BACKTRACE=1 cargo test $TEST_FEATURES --manifest-path ./e2e_tests/Cargo.toml normal_tests
143145

144146
echo "Execute persistent test, before the reload"
145-
RUST_BACKTRACE=1 cargo test --manifest-path ./e2e_tests/Cargo.toml persistent_before
147+
RUST_BACKTRACE=1 cargo test $TEST_FEATURES --manifest-path ./e2e_tests/Cargo.toml persistent_before
146148

147149
# Create a fake mapping file for the root application, the provider and a
148150
# key name of "Test Key". It contains a valid KeyInfo structure.
@@ -170,7 +172,7 @@ else
170172
sleep 5
171173

172174
echo "Execute persistent test, after the reload"
173-
RUST_BACKTRACE=1 cargo test --manifest-path ./e2e_tests/Cargo.toml persistent_after
175+
RUST_BACKTRACE=1 cargo test $TEST_FEATURES --manifest-path ./e2e_tests/Cargo.toml persistent_after
174176

175177
if [ -z "$NO_STRESS_TEST" ]; then
176178
echo "Shutdown Parsec"
@@ -186,6 +188,6 @@ else
186188
sleep 5
187189

188190
echo "Execute stress tests"
189-
RUST_BACKTRACE=1 cargo test --manifest-path ./e2e_tests/Cargo.toml stress_test
191+
RUST_BACKTRACE=1 cargo test $TEST_FEATURES --manifest-path ./e2e_tests/Cargo.toml stress_test
190192
fi
191193
fi

e2e_tests/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,9 @@ uuid = "0.7.4"
2828
rsa = "0.3.0"
2929
picky-asn1-x509 = "0.1.0"
3030
base64 = "0.12.3"
31+
32+
[features]
33+
mbed-crypto-provider = []
34+
tpm-provider = []
35+
pkcs11-provider = []
36+
all-providers = ["pkcs11-provider","tpm-provider","mbed-crypto-provider"]

e2e_tests/src/lib.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,36 @@ impl TestClient {
252252
)
253253
}
254254

255+
#[allow(deprecated)]
256+
pub fn generate_rsa_encryption_keys_rsaoaep_sha1(&mut self, key_name: String) -> Result<()> {
257+
self.generate_key(
258+
key_name,
259+
Attributes {
260+
lifetime: Lifetime::Persistent,
261+
key_type: Type::RsaKeyPair,
262+
bits: 1024,
263+
policy: Policy {
264+
usage_flags: UsageFlags {
265+
sign_hash: false,
266+
verify_hash: false,
267+
sign_message: false,
268+
verify_message: false,
269+
export: true,
270+
encrypt: true,
271+
decrypt: true,
272+
cache: false,
273+
copy: false,
274+
derive: false,
275+
},
276+
permitted_algorithms: AsymmetricEncryption::RsaOaep {
277+
hash_alg: Hash::Sha1,
278+
}
279+
.into(),
280+
},
281+
},
282+
)
283+
}
284+
255285
pub fn generate_ecc_key_pair_secpk1_deterministic_ecdsa_sha256(
256286
&mut self,
257287
key_name: String,
@@ -610,6 +640,40 @@ impl TestClient {
610640
)
611641
}
612642

643+
#[allow(deprecated)]
644+
pub fn asymmetric_encrypt_message_with_rsaoaep_sha1(
645+
&mut self,
646+
key_name: String,
647+
plaintext: Vec<u8>,
648+
salt: Vec<u8>,
649+
) -> Result<Vec<u8>> {
650+
self.asymmetric_encrypt_message(
651+
key_name,
652+
AsymmetricEncryption::RsaOaep {
653+
hash_alg: Hash::Sha1,
654+
},
655+
&plaintext,
656+
Some(&salt),
657+
)
658+
}
659+
660+
#[allow(deprecated)]
661+
pub fn asymmetric_decrypt_message_with_rsaoaep_sha1(
662+
&mut self,
663+
key_name: String,
664+
ciphertext: Vec<u8>,
665+
salt: Vec<u8>,
666+
) -> Result<Vec<u8>> {
667+
self.asymmetric_decrypt_message(
668+
key_name,
669+
AsymmetricEncryption::RsaOaep {
670+
hash_alg: Hash::Sha1,
671+
},
672+
&ciphertext,
673+
Some(&salt),
674+
)
675+
}
676+
613677
pub fn asymmetric_encrypt_message(
614678
&mut self,
615679
key_name: String,

e2e_tests/tests/all_providers/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,10 @@ fn list_opcodes() {
3333
let _ = crypto_providers_hsm.insert(Opcode::PsaVerifyHash);
3434
let _ = crypto_providers_hsm.insert(Opcode::PsaImportKey);
3535
let _ = crypto_providers_hsm.insert(Opcode::PsaExportPublicKey);
36+
let _ = crypto_providers_hsm.insert(Opcode::PsaAsymmetricDecrypt);
37+
let _ = crypto_providers_hsm.insert(Opcode::PsaAsymmetricEncrypt);
3638

37-
let mut crypto_providers_tpm = crypto_providers_hsm.clone();
38-
let _ = crypto_providers_tpm.insert(Opcode::PsaAsymmetricDecrypt);
39-
let _ = crypto_providers_tpm.insert(Opcode::PsaAsymmetricEncrypt);
39+
let crypto_providers_tpm = crypto_providers_hsm.clone();
4040

4141
let mut crypto_providers_mbed_crypto = crypto_providers_tpm.clone();
4242
let _ = crypto_providers_mbed_crypto.insert(Opcode::PsaHashCompute);

e2e_tests/tests/per_provider/normal_tests/asym_encryption.rs

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
// Copyright 2020 Contributors to the Parsec project.
22
// SPDX-License-Identifier: Apache-2.0
3+
#![allow(unused, dead_code)]
4+
35
use e2e_tests::TestClient;
4-
use parsec_client::core::interface::requests::{Opcode, ProviderID, ResponseStatus};
6+
use parsec_client::core::interface::requests::{Opcode, ResponseStatus};
57
use rand::rngs::OsRng;
68
use rsa::{PaddingScheme, PublicKey, RSAPublicKey};
79

@@ -52,6 +54,10 @@ fn simple_asym_encrypt_rsa_pkcs() {
5254
.unwrap();
5355
}
5456

57+
// Test is ignored for PKCS11 because the library we use for testing does not support
58+
// other hash algorithms to be used with OAEP apart from SHA1.
59+
// See: https://github.com/opendnssec/SoftHSMv2/issues/474
60+
#[cfg(not(feature = "pkcs11-provider"))]
5561
#[test]
5662
fn simple_asym_encrypt_rsa_oaep() {
5763
let key_name = String::from("simple_asym_encrypt_rsa_oaep");
@@ -73,10 +79,41 @@ fn simple_asym_encrypt_rsa_oaep() {
7379
.unwrap();
7480
}
7581

76-
// Test is ignored as TPMs do not support labels that don't end in a 0 byte
82+
#[cfg(feature = "pkcs11-provider")]
83+
#[test]
84+
fn simple_asym_encrypt_rsa_oaep_pkcs11() {
85+
let key_name = String::from("simple_asym_encrypt_rsa_oaep_pkcs11");
86+
let mut client = TestClient::new();
87+
88+
if !client.is_operation_supported(Opcode::PsaAsymmetricEncrypt) {
89+
return;
90+
}
91+
92+
client
93+
.generate_rsa_encryption_keys_rsaoaep_sha1(key_name.clone())
94+
.unwrap();
95+
let ciphertext = client
96+
.asymmetric_encrypt_message_with_rsaoaep_sha1(
97+
key_name.clone(),
98+
PLAINTEXT_MESSAGE.to_vec(),
99+
vec![],
100+
)
101+
.unwrap();
102+
103+
let plaintext = client
104+
.asymmetric_decrypt_message_with_rsaoaep_sha1(key_name, ciphertext, vec![])
105+
.unwrap();
106+
107+
assert_eq!(&PLAINTEXT_MESSAGE[..], &plaintext[..]);
108+
}
109+
110+
// Test is ignored for TPMs as they do not support labels that don't end in a 0 byte
77111
// A resolution for this has not been reached yet, so keeping as is
78112
// See: https://github.com/parallaxsecond/parsec/issues/217
79-
#[ignore]
113+
// Test is ignored for PKCS11 because the library we use for testing does not support
114+
// other hash algorithms to be used with OAEP apart from SHA1.
115+
// See: https://github.com/opendnssec/SoftHSMv2/issues/474
116+
#[cfg(not(any(feature = "pkcs11-provider", feature = "tpm-provider")))]
80117
#[test]
81118
fn simple_asym_decrypt_oaep_with_salt() {
82119
let key_name = String::from("simple_asym_decrypt_oaep_with_salt");
@@ -232,10 +269,13 @@ fn asym_encrypt_verify_decrypt_with_rsa_crate() {
232269
assert_eq!(&PLAINTEXT_MESSAGE[..], &plaintext[..]);
233270
}
234271

235-
// Test is ignored as TPMs do not support labels that don't end in a 0 byte
272+
// Test is ignored for TPMs as they do not support labels that don't end in a 0 byte
236273
// A resolution for this has not been reached yet, so keeping as is
237274
// See: https://github.com/parallaxsecond/parsec/issues/217
238-
#[ignore]
275+
// Test is ignored for PKCS11 because the library we use for testing does not support
276+
// other hash algorithms to be used with OAEP apart from SHA1.
277+
// See: https://github.com/opendnssec/SoftHSMv2/issues/474
278+
#[cfg(not(any(feature = "pkcs11-provider", feature = "tpm-provider")))]
239279
#[test]
240280
fn asym_encrypt_verify_decrypt_with_rsa_crate_oaep() {
241281
let key_name = String::from("asym_encrypt_verify_decrypt_with_rsa_crate_oaep");
@@ -269,16 +309,16 @@ fn asym_encrypt_verify_decrypt_with_rsa_crate_oaep() {
269309
}
270310

271311
/// Uses key pair generated online to decrypt a message that has been pre-encrypted
312+
// PKCS 11 does not support important key pairs
313+
// TPM does not support importing "general use keys"
314+
#[cfg(not(any(feature = "pkcs11-provider", feature = "tpm-provider")))]
272315
#[test]
273316
fn asym_verify_decrypt_with_internet() {
274317
let key_name = String::from("asym_derify_decrypt_with_pick");
275318
let mut client = TestClient::new();
276319

277320
// Check if decrypt is supported
278-
// TPM does not support importing "general use keys"
279-
if !client.is_operation_supported(Opcode::PsaAsymmetricDecrypt)
280-
|| client.provider().unwrap() == ProviderID::Tpm
281-
{
321+
if !client.is_operation_supported(Opcode::PsaAsymmetricDecrypt) {
282322
return;
283323
}
284324

e2e_tests/tests/per_provider/normal_tests/asym_sign_verify.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use parsec_client::core::interface::operations::psa_algorithm::*;
55
use parsec_client::core::interface::operations::psa_key_attributes::*;
66
use parsec_client::core::interface::requests::ResponseStatus;
77
use parsec_client::core::interface::requests::Result;
8+
use rsa::{PaddingScheme, PublicKey, RSAPublicKey};
89
use sha2::{Digest, Sha256};
910

1011
const HASH: [u8; 32] = [
@@ -312,3 +313,27 @@ fn fail_verify_hash2() -> Result<()> {
312313
assert_eq!(status, ResponseStatus::PsaErrorInvalidSignature);
313314
Ok(())
314315
}
316+
317+
#[test]
318+
fn asym_verify_with_rsa_crate() {
319+
let key_name = String::from("asym_verify_with_rsa_crate");
320+
let mut client = TestClient::new();
321+
322+
client.generate_rsa_sign_key(key_name.clone()).unwrap();
323+
let pub_key = client.export_public_key(key_name.clone()).unwrap();
324+
325+
let rsa_pub_key = RSAPublicKey::from_pkcs1(&pub_key).unwrap();
326+
327+
let mut hasher = Sha256::new();
328+
hasher.update(b"Bob wrote this message.");
329+
let hash = hasher.finalize().to_vec();
330+
let signature = client.sign_with_rsa_sha256(key_name, hash.clone()).unwrap();
331+
332+
rsa_pub_key
333+
.verify(
334+
PaddingScheme::new_pkcs1v15_sign(Some(rsa::Hash::SHA2_256)),
335+
&hash,
336+
&signature,
337+
)
338+
.unwrap();
339+
}

0 commit comments

Comments
 (0)