Skip to content

Commit 61d207b

Browse files
committed
Allow software operations in PKCS11 provider
This commit adds functionality to the PKCS11 provider to allow it to handle public key operations in software, using a PSA Crypto-compatible library. The functionality is enabled via a config flag. Signed-off-by: Ionut Mihalcea <ionut.mihalcea@arm.com>
1 parent 30c8162 commit 61d207b

File tree

14 files changed

+244
-15
lines changed

14 files changed

+244
-15
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ features = ["docs"]
6666
default = []
6767
no-parsec-user-and-clients-group = []
6868
mbed-crypto-provider = ["psa-crypto"]
69-
pkcs11-provider = ["pkcs11", "picky-asn1-der", "picky-asn1", "picky-asn1-x509"]
69+
pkcs11-provider = ["pkcs11", "picky-asn1-der", "picky-asn1", "picky-asn1-x509", "psa-crypto"]
7070
tpm-provider = ["tss-esapi", "picky-asn1-der", "picky-asn1", "picky-asn1-x509"]
7171
all-providers = ["tpm-provider", "pkcs11-provider", "mbed-crypto-provider"]
7272
docs = ["pkcs11-provider", "tpm-provider", "tss-esapi/docs", "mbed-crypto-provider"]

ci.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ pgrep -f target/debug/parsec >/dev/null
137137
if [ "$PROVIDER_NAME" = "all" ]; then
138138
echo "Execute all-providers tests"
139139
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
140+
RUST_BACKTRACE=1 cargo test $TEST_FEATURES --manifest-path ./e2e_tests/Cargo.toml config -- --test-threads=1
141141
else
142142
# Per provider tests
143143
echo "Execute normal tests"

config.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ key_info_manager = "on-disk-manager"
8080
# (Optional) User pin for authentication with the specific slot. If not set, no authentication will
8181
# be used.
8282
#user_pin = "123456"
83+
# (Optional) Control whether missing public key operation (such as verifying signatures or asymmetric
84+
# encryption) are fully performed in software.
85+
#software_public_operations = false
8386

8487
# Example of a TPM provider configuration
8588
#[[provider]]

e2e_tests/provider_cfg/pkcs11/Dockerfile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@ FROM ubuntu:18.04
22

33
RUN apt-get update && \
44
apt-get install -y wget automake autoconf libtool pkg-config && \
5-
apt-get install -y curl libssl-dev libgcc1
5+
apt-get install -y curl libssl-dev libgcc1 && \
6+
apt-get install -y git make gcc python3 python curl wget libgcc1 cmake && \
7+
# These libraries are needed for bindgen as it uses libclang.so
8+
apt-get install -y clang libclang-dev && \
9+
# Needed for Open SSL
10+
apt-get install -y pkg-config libssl-dev
611

712
WORKDIR /tmp
813
RUN wget https://github.com/opendnssec/SoftHSMv2/archive/2.5.0.tar.gz

e2e_tests/provider_cfg/pkcs11/config.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,6 @@ provider_type = "Pkcs11"
2222
key_info_manager = "on-disk-manager"
2323
library_path = "/usr/local/lib/softhsm/libsofthsm2.so"
2424
user_pin = "123456"
25+
software_public_operations = false
2526
# The slot_number mandatory field is going to replace the following line with a valid number
2627
# slot_number

e2e_tests/tests/config/mod.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,56 @@ fn list_providers() {
7474
]
7575
);
7676
}
77+
78+
#[cfg(feature = "pkcs11-provider")]
79+
#[test]
80+
fn pkcs11_verify_software() {
81+
use sha2::{Digest, Sha256};
82+
set_config("pkcs11_software.toml");
83+
reload_service();
84+
85+
let mut client = TestClient::new();
86+
let key_name = String::from("pkcs11_verify_software");
87+
88+
let mut hasher = Sha256::new();
89+
hasher.update(b"Bob wrote this message.");
90+
let hash = hasher.finalize().to_vec();
91+
92+
client.generate_rsa_sign_key(key_name.clone()).unwrap();
93+
94+
let signature = client
95+
.sign_with_rsa_sha256(key_name.clone(), hash.clone())
96+
.unwrap();
97+
client
98+
.verify_with_rsa_sha256(key_name, hash, signature)
99+
.unwrap();
100+
}
101+
102+
#[cfg(feature = "pkcs11-provider")]
103+
#[test]
104+
fn pkcs11_encrypt_software() {
105+
set_config("pkcs11_software.toml");
106+
reload_service();
107+
108+
let mut client = TestClient::new();
109+
let key_name = String::from("pkcs11_verify_software");
110+
let plaintext_msg = [
111+
0x69, 0x3E, 0xDB, 0x1B, 0x22, 0x79, 0x03, 0xF4, 0xC0, 0xBF, 0xD6, 0x91, 0x76, 0x37, 0x84,
112+
0xA2, 0x94, 0x8E, 0x92, 0x50, 0x35, 0xC2, 0x8C, 0x5C, 0x3C, 0xCA, 0xFE, 0x18, 0xE8, 0x81,
113+
0x37, 0x78,
114+
];
115+
client
116+
.generate_rsa_encryption_keys_rsaoaep_sha1(key_name.clone())
117+
.unwrap();
118+
let ciphertext = client
119+
.asymmetric_encrypt_message_with_rsaoaep_sha1(
120+
key_name.clone(),
121+
plaintext_msg.to_vec(),
122+
vec![],
123+
)
124+
.unwrap();
125+
let plaintext = client
126+
.asymmetric_decrypt_message_with_rsaoaep_sha1(key_name, ciphertext, vec![])
127+
.unwrap();
128+
assert_eq!(&plaintext_msg[..], &plaintext[..]);
129+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
[core_settings]
2+
# The CI already timestamps the logs
3+
log_timestamp = false
4+
log_error_details = true
5+
6+
# The container runs the Parsec service as root, so make sure we disable root
7+
# checks.
8+
allow_root = true
9+
10+
[listener]
11+
listener_type = "DomainSocket"
12+
# The timeout needs to be smaller than the test client timeout (five seconds) as it is testing
13+
# that the service does not hang for very big values of body or authentication length.
14+
timeout = 3000 # in milliseconds
15+
16+
[[key_manager]]
17+
name = "on-disk-manager"
18+
manager_type = "OnDisk"
19+
20+
[[provider]]
21+
provider_type = "Pkcs11"
22+
key_info_manager = "on-disk-manager"
23+
library_path = "/usr/local/lib/softhsm/libsofthsm2.so"
24+
user_pin = "123456"
25+
software_public_operations = true
26+
# The slot_number mandatory field is going to replace the following line with a valid number
27+
# slot_number

e2e_tests/tests/per_provider/normal_tests/asym_encryption.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,6 @@ fn simple_asym_encrypt_rsa_oaep_pkcs11() {
8585
let key_name = String::from("simple_asym_encrypt_rsa_oaep_pkcs11");
8686
let mut client = TestClient::new();
8787

88-
if !client.is_operation_supported(Opcode::PsaAsymmetricEncrypt) {
89-
return;
90-
}
91-
9288
client
9389
.generate_rsa_encryption_keys_rsaoaep_sha1(key_name.clone())
9490
.unwrap();

src/providers/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ pub enum ProviderConfig {
4747
slot_number: usize,
4848
/// User Pin
4949
user_pin: Option<String>,
50+
/// Control whether public key operations are performed in software
51+
software_public_operations: Option<bool>,
5052
},
5153
/// TPM provider configuration
5254
Tpm {

src/providers/pkcs11_provider/asym_encryption.rs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::key_info_managers::KeyTriple;
77
use log::{info, trace};
88
use parsec_interface::operations::psa_algorithm::Algorithm;
99
use parsec_interface::operations::{psa_asymmetric_decrypt, psa_asymmetric_encrypt};
10-
use parsec_interface::requests::{ProviderID, Result};
10+
use parsec_interface::requests::{ProviderID, ResponseStatus, Result};
1111
use std::convert::TryFrom;
1212
use utils::CkMechanism;
1313

@@ -108,4 +108,45 @@ impl Pkcs11Provider {
108108
}
109109
}
110110
}
111+
112+
pub(super) fn software_psa_asymmetric_encrypt_internal(
113+
&self,
114+
app_name: ApplicationName,
115+
op: psa_asymmetric_encrypt::Operation,
116+
) -> Result<psa_asymmetric_encrypt::Result> {
117+
let key_triple = KeyTriple::new(app_name, ProviderID::Pkcs11, op.key_name.clone());
118+
let (_, key_attributes) = self.get_key_info(&key_triple)?;
119+
120+
op.validate(key_attributes)?;
121+
122+
let alg = op.alg;
123+
let salt_buff = op.salt.as_ref().map(|salt| salt.as_slice());
124+
let buffer_size = key_attributes.asymmetric_encrypt_output_size(alg)?;
125+
let mut ciphertext = vec![0u8; buffer_size];
126+
let pub_key_id = self.move_pub_key_to_psa_crypto(&key_triple)?;
127+
128+
info!("Encrypting plaintext with PSA Crypto");
129+
let res = match psa_crypto::operations::asym_encryption::encrypt(
130+
pub_key_id,
131+
alg,
132+
&op.plaintext,
133+
salt_buff,
134+
&mut ciphertext,
135+
) {
136+
Ok(output_size) => {
137+
ciphertext.resize(output_size, 0);
138+
Ok(psa_asymmetric_encrypt::Result {
139+
ciphertext: ciphertext.into(),
140+
})
141+
}
142+
Err(error) => {
143+
let error = ResponseStatus::from(error);
144+
format_error!("Asymmetric encryption failed", error);
145+
Err(error)
146+
}
147+
};
148+
149+
let _ = self.remove_psa_crypto_pub_key(pub_key_id);
150+
res
151+
}
111152
}

0 commit comments

Comments
 (0)