Skip to content

Commit 7c379a3

Browse files
committed
Add memory wiping functionality
This commit improves the security of the library by wiping out all sensitive data before it is dropped. Signed-off-by: Ionut Mihalcea <ionut.mihalcea@arm.com>
1 parent d2ba219 commit 7c379a3

File tree

6 files changed

+57
-36
lines changed

6 files changed

+57
-36
lines changed

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@ edition = "2018"
1313
documentation = "https://docs.rs/crate/parsec-client"
1414

1515
[dependencies]
16-
parsec-interface = "0.15.0"
16+
parsec-interface = "0.17.0"
1717
num = "0.2.1"
1818
rand = "0.7.3"
1919
log = "0.4.8"
2020
derivative = "2.1.1"
2121
uuid = "0.7.4"
22+
zeroize = "1.1.0"
2223

2324
[dev-dependencies]
2425
mockstream = "0.0.3"

src/auth.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,19 @@
22
// SPDX-License-Identifier: Apache-2.0
33
//! Client app authentication data
44
use parsec_interface::requests::{request::RequestAuth, AuthType};
5+
use parsec_interface::secrecy::{ExposeSecret, Secret};
56

67
/// Authentication data used in Parsec requests
78
#[derive(Clone, Debug)]
89
pub enum AuthenticationData {
910
/// Used in cases where no authentication is desired or required
1011
None,
1112
/// Data used for direct, identity-based authentication
12-
AppIdentity(String),
13+
///
14+
/// The app name is wrapped in a [`Secret`](https://docs.rs/secrecy/*/secrecy/struct.Secret.html).
15+
/// The `Secret` struct can be imported from
16+
/// `parsec_client::core::secrecy::Secret`.
17+
AppIdentity(Secret<String>),
1318
}
1419

1520
impl AuthenticationData {
@@ -25,9 +30,9 @@ impl AuthenticationData {
2530
impl From<&AuthenticationData> for RequestAuth {
2631
fn from(data: &AuthenticationData) -> Self {
2732
match data {
28-
AuthenticationData::None => Default::default(),
33+
AuthenticationData::None => RequestAuth::new(Vec::new()),
2934
AuthenticationData::AppIdentity(name) => {
30-
RequestAuth::from_bytes(name.bytes().collect())
35+
RequestAuth::new(name.expose_secret().bytes().collect())
3136
}
3237
}
3338
}

src/core/basic_client.rs

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ use parsec_interface::operations::psa_sign_hash::Operation as PsaSignHash;
1717
use parsec_interface::operations::psa_verify_hash::Operation as PsaVerifyHash;
1818
use parsec_interface::operations::{NativeOperation, NativeResult};
1919
use parsec_interface::requests::{Opcode, ProviderID};
20+
use parsec_interface::secrecy::Secret;
2021
use std::collections::HashSet;
22+
use zeroize::Zeroizing;
2123

2224
/// Core client for Parsec service
2325
///
@@ -37,9 +39,10 @@ use std::collections::HashSet;
3739
///```no_run
3840
///use parsec_client::auth::AuthenticationData;
3941
///use parsec_client::BasicClient;
42+
///use parsec_client::core::secrecy::Secret;
4043
///
4144
///let app_name = String::from("app-name");
42-
///let app_auth_data = AuthenticationData::AppIdentity(app_name);
45+
///let app_auth_data = AuthenticationData::AppIdentity(Secret::new(app_name));
4346
///let client: BasicClient = BasicClient::new(app_auth_data);
4447
///```
4548
///
@@ -49,8 +52,9 @@ use std::collections::HashSet;
4952
///```no_run
5053
///# use parsec_client::auth::AuthenticationData;
5154
///# use parsec_client::BasicClient;
55+
///# use parsec_client::core::secrecy::Secret;
5256
///# use parsec_client::core::interface::requests::ProviderID;
53-
///# let client: BasicClient = BasicClient::new(AuthenticationData::AppIdentity(String::from("app-name")));
57+
///# let client: BasicClient = BasicClient::new(AuthenticationData::AppIdentity(Secret::new(String::from("app-name"))));
5458
///let res = client.ping();
5559
///
5660
///if let Ok((wire_prot_v_maj, wire_prot_v_min)) = res {
@@ -71,8 +75,9 @@ use std::collections::HashSet;
7175
///```no_run
7276
///# use parsec_client::auth::AuthenticationData;
7377
///# use parsec_client::BasicClient;
78+
///# use parsec_client::core::secrecy::Secret;
7479
///# use parsec_client::core::interface::requests::ProviderID;
75-
///# let client: BasicClient = BasicClient::new(AuthenticationData::AppIdentity(String::from("app-name")));
80+
///# let client: BasicClient = BasicClient::new(AuthenticationData::AppIdentity(Secret::new(String::from("app-name"))));
7681
///use uuid::Uuid;
7782
///
7883
///// Identify provider by its UUID (in this case, the PKCS11 provider)
@@ -94,7 +99,8 @@ use std::collections::HashSet;
9499
///# use parsec_client::auth::AuthenticationData;
95100
///# use parsec_client::BasicClient;
96101
///# use parsec_client::core::interface::requests::ProviderID;
97-
///# let mut client: BasicClient = BasicClient::new(AuthenticationData::AppIdentity(String::from("app-name")));
102+
///# use parsec_client::core::secrecy::Secret;
103+
///# let mut client: BasicClient = BasicClient::new(AuthenticationData::AppIdentity(Secret::new(String::from("app-name"))));
98104
///use parsec_client::core::interface::requests::Opcode;
99105
///
100106
///let desired_provider = ProviderID::Pkcs11;
@@ -114,8 +120,9 @@ use std::collections::HashSet;
114120
///```no_run
115121
///# use parsec_client::auth::AuthenticationData;
116122
///# use parsec_client::BasicClient;
123+
///# use parsec_client::core::secrecy::Secret;
117124
///# use parsec_client::core::interface::requests::ProviderID;
118-
///# let client: BasicClient = BasicClient::new(AuthenticationData::AppIdentity(String::from("app-name")));
125+
///# let client: BasicClient = BasicClient::new(AuthenticationData::AppIdentity(Secret::new(String::from("app-name"))));
119126
///use parsec_client::core::interface::operations::psa_algorithm::{Algorithm, AsymmetricSignature, Hash};
120127
///use parsec_client::core::interface::operations::psa_key_attributes::{Attributes, Lifetime, Policy, Type, UsageFlags};
121128
///
@@ -151,7 +158,7 @@ use std::collections::HashSet;
151158
///};
152159
///
153160
///client
154-
/// .psa_generate_key(key_name, key_attrs)
161+
/// .psa_generate_key(key_name.clone(), key_attrs)
155162
/// .expect("Failed to create key!");
156163
///```
157164
#[derive(Debug)]
@@ -356,9 +363,10 @@ impl BasicClient {
356363
pub fn psa_import_key(
357364
&self,
358365
key_name: String,
359-
key_material: Vec<u8>,
366+
key_material: &[u8],
360367
key_attributes: Attributes,
361368
) -> Result<()> {
369+
let key_material = Secret::new(key_material.to_vec());
362370
let crypto_provider = self.can_provide_crypto()?;
363371

364372
let op = PsaImportKey {
@@ -405,7 +413,7 @@ impl BasicClient {
405413
)?;
406414

407415
if let NativeResult::PsaExportPublicKey(res) = res {
408-
Ok(res.data)
416+
Ok(res.data.to_vec())
409417
} else {
410418
// Should really not be reached given the checks we do, but it's not impossible if some
411419
// changes happen in the interface
@@ -438,9 +446,10 @@ impl BasicClient {
438446
pub fn psa_sign_hash(
439447
&self,
440448
key_name: String,
441-
hash: Vec<u8>,
449+
hash: &[u8],
442450
sign_algorithm: AsymmetricSignature,
443451
) -> Result<Vec<u8>> {
452+
let hash = Zeroizing::new(hash.to_vec());
444453
let crypto_provider = self.can_provide_crypto()?;
445454

446455
let op = PsaSignHash {
@@ -456,7 +465,7 @@ impl BasicClient {
456465
)?;
457466

458467
if let NativeResult::PsaSignHash(res) = res {
459-
Ok(res.signature)
468+
Ok(res.signature.to_vec())
460469
} else {
461470
// Should really not be reached given the checks we do, but it's not impossible if some
462471
// changes happen in the interface
@@ -489,10 +498,12 @@ impl BasicClient {
489498
pub fn psa_verify_hash(
490499
&self,
491500
key_name: String,
492-
hash: Vec<u8>,
501+
hash: &[u8],
493502
sign_algorithm: AsymmetricSignature,
494-
signature: Vec<u8>,
503+
signature: &[u8],
495504
) -> Result<()> {
505+
let hash = Zeroizing::new(hash.to_vec());
506+
let signature = Zeroizing::new(signature.to_vec());
496507
let crypto_provider = self.can_provide_crypto()?;
497508

498509
let op = PsaVerifyHash {

src/core/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,7 @@ pub mod operation_client;
1212
pub mod request_client;
1313
mod testing;
1414

15+
/// Resurfacing of the Secrecy library used by the client.
16+
pub use interface::secrecy;
17+
/// Resurfacing of the Parsec interface library used by the client.
1518
pub use parsec_interface as interface;

src/core/testing/core_tests.rs

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use parsec_interface::requests::Response;
1717
use parsec_interface::requests::ResponseStatus;
1818
use parsec_interface::requests::{request::RequestHeader, Request};
1919
use parsec_interface::requests::{AuthType, BodyType, Opcode};
20+
use parsec_interface::secrecy::{ExposeSecret, Secret};
2021
use std::collections::HashSet;
2122
use std::io::ErrorKind;
2223

@@ -118,7 +119,9 @@ fn list_opcodes_test() {
118119

119120
#[test]
120121
fn no_crypto_provider_test() {
121-
let client = BasicClient::new(AuthenticationData::AppIdentity(String::from("oops")));
122+
let client = BasicClient::new(AuthenticationData::AppIdentity(Secret::new(String::from(
123+
"oops",
124+
))));
122125

123126
let res = client
124127
.psa_destroy_key(String::from("random key"))
@@ -129,7 +132,9 @@ fn no_crypto_provider_test() {
129132

130133
#[test]
131134
fn core_provider_for_crypto_test() {
132-
let mut client = BasicClient::new(AuthenticationData::AppIdentity(String::from("oops")));
135+
let mut client = BasicClient::new(AuthenticationData::AppIdentity(Secret::new(String::from(
136+
"oops",
137+
))));
133138

134139
client.set_implicit_provider(ProviderID::Core);
135140
let res = client
@@ -168,7 +173,7 @@ fn psa_generate_key_test() {
168173
};
169174

170175
client
171-
.psa_generate_key(key_name.clone(), key_attrs.clone())
176+
.psa_generate_key(key_name.clone(), key_attrs)
172177
.expect("failed to generate key");
173178

174179
// Check request:
@@ -236,15 +241,15 @@ fn psa_import_key_test() {
236241
};
237242
let key_data = vec![0xff_u8; 128];
238243
client
239-
.psa_import_key(key_name.clone(), key_data.clone(), key_attrs.clone())
244+
.psa_import_key(key_name.clone(), &key_data, key_attrs)
240245
.unwrap();
241246

242247
// Check request:
243248
let op = get_operation_from_req_bytes(client.get_mock_write());
244249
if let NativeOperation::PsaImportKey(op) = op {
245250
assert_eq!(op.attributes, key_attrs);
246251
assert_eq!(op.key_name, key_name);
247-
assert_eq!(op.data, key_data);
252+
assert_eq!(op.data.expose_secret(), &key_data);
248253
} else {
249254
panic!("Got wrong operation type: {:?}", op);
250255
}
@@ -259,7 +264,7 @@ fn psa_export_public_key_test() {
259264
let key_data = vec![0xa5; 128];
260265
client.set_mock_read(&get_response_bytes_from_result(
261266
NativeResult::PsaExportPublicKey(operations::psa_export_public_key::Result {
262-
data: key_data.clone(),
267+
data: key_data.clone().into(),
263268
}),
264269
));
265270

@@ -292,14 +297,14 @@ fn psa_sign_hash_test() {
292297
let signature = vec![0x33_u8; 128];
293298
client.set_mock_read(&get_response_bytes_from_result(NativeResult::PsaSignHash(
294299
operations::psa_sign_hash::Result {
295-
signature: signature.clone(),
300+
signature: signature.clone().into(),
296301
},
297302
)));
298303

299304
// Check response:
300305
assert_eq!(
301306
client
302-
.psa_sign_hash(key_name.clone(), hash.clone(), sign_algorithm.clone())
307+
.psa_sign_hash(key_name.clone(), &hash, sign_algorithm)
303308
.expect("Failed to sign hash"),
304309
signature
305310
);
@@ -308,7 +313,7 @@ fn psa_sign_hash_test() {
308313
let op = get_operation_from_req_bytes(client.get_mock_write());
309314
if let NativeOperation::PsaSignHash(op) = op {
310315
assert_eq!(op.key_name, key_name);
311-
assert_eq!(op.hash, hash);
316+
assert_eq!(op.hash.to_vec(), hash);
312317
assert_eq!(op.alg, sign_algorithm);
313318
} else {
314319
panic!("Got wrong operation type: {:?}", op);
@@ -329,21 +334,16 @@ fn verify_hash_test() {
329334
));
330335

331336
client
332-
.psa_verify_hash(
333-
key_name.clone(),
334-
hash.clone(),
335-
sign_algorithm.clone(),
336-
signature.clone(),
337-
)
337+
.psa_verify_hash(key_name.clone(), &hash, sign_algorithm, &signature)
338338
.expect("Failed to sign hash");
339339

340340
// Check request:
341341
let op = get_operation_from_req_bytes(client.get_mock_write());
342342
if let NativeOperation::PsaVerifyHash(op) = op {
343343
assert_eq!(op.key_name, key_name);
344-
assert_eq!(op.hash, hash);
344+
assert_eq!(op.hash.to_vec(), hash);
345345
assert_eq!(op.alg, sign_algorithm);
346-
assert_eq!(op.signature, signature);
346+
assert_eq!(op.signature.to_vec(), signature);
347347
} else {
348348
panic!("Got wrong operation type: {:?}", op);
349349
}
@@ -423,7 +423,7 @@ fn auth_value_test() {
423423

424424
let req = get_req_from_bytes(client.get_mock_write());
425425
assert_eq!(
426-
String::from_utf8(req.auth.bytes().to_owned()).unwrap(),
426+
String::from_utf8(req.auth.buffer.expose_secret().to_owned()).unwrap(),
427427
String::from(DEFAULT_APP_NAME)
428428
);
429429
}

src/core/testing/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::auth::AuthenticationData;
77
use crate::error::Result;
88
use mockstream::{FailingMockStream, SyncMockStream};
99
use parsec_interface::requests::ProviderID;
10+
use parsec_interface::secrecy::Secret;
1011
use std::ops::{Deref, DerefMut};
1112
use std::time::Duration;
1213

@@ -66,8 +67,8 @@ impl DerefMut for TestBasicClient {
6667
impl Default for TestBasicClient {
6768
fn default() -> Self {
6869
let mut client = TestBasicClient {
69-
core_client: BasicClient::new(AuthenticationData::AppIdentity(String::from(
70-
DEFAULT_APP_NAME,
70+
core_client: BasicClient::new(AuthenticationData::AppIdentity(Secret::new(
71+
String::from(DEFAULT_APP_NAME),
7172
))),
7273
mock_stream: SyncMockStream::new(),
7374
};

0 commit comments

Comments
 (0)