diff --git a/Cargo.toml b/Cargo.toml index 2974580..afb97af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,12 +13,13 @@ edition = "2018" documentation = "https://docs.rs/crate/parsec-client" [dependencies] -parsec-interface = "0.15.0" +parsec-interface = "0.17.0" num = "0.2.1" rand = "0.7.3" log = "0.4.8" derivative = "2.1.1" uuid = "0.7.4" +zeroize = "1.1.0" [dev-dependencies] mockstream = "0.0.3" diff --git a/src/auth.rs b/src/auth.rs index 5415e03..392ebe6 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 //! Client app authentication data use parsec_interface::requests::{request::RequestAuth, AuthType}; +use parsec_interface::secrecy::{ExposeSecret, Secret}; /// Authentication data used in Parsec requests #[derive(Clone, Debug)] @@ -9,7 +10,11 @@ pub enum AuthenticationData { /// Used in cases where no authentication is desired or required None, /// Data used for direct, identity-based authentication - AppIdentity(String), + /// + /// The app name is wrapped in a [`Secret`](https://docs.rs/secrecy/*/secrecy/struct.Secret.html). + /// The `Secret` struct can be imported from + /// `parsec_client::core::secrecy::Secret`. + AppIdentity(Secret), } impl AuthenticationData { @@ -25,9 +30,9 @@ impl AuthenticationData { impl From<&AuthenticationData> for RequestAuth { fn from(data: &AuthenticationData) -> Self { match data { - AuthenticationData::None => Default::default(), + AuthenticationData::None => RequestAuth::new(Vec::new()), AuthenticationData::AppIdentity(name) => { - RequestAuth::from_bytes(name.bytes().collect()) + RequestAuth::new(name.expose_secret().bytes().collect()) } } } diff --git a/src/core/basic_client.rs b/src/core/basic_client.rs index ccde164..0ebd90d 100644 --- a/src/core/basic_client.rs +++ b/src/core/basic_client.rs @@ -17,7 +17,9 @@ use parsec_interface::operations::psa_sign_hash::Operation as PsaSignHash; use parsec_interface::operations::psa_verify_hash::Operation as PsaVerifyHash; use parsec_interface::operations::{NativeOperation, NativeResult}; use parsec_interface::requests::{Opcode, ProviderID}; +use parsec_interface::secrecy::Secret; use std::collections::HashSet; +use zeroize::Zeroizing; /// Core client for Parsec service /// @@ -37,9 +39,10 @@ use std::collections::HashSet; ///```no_run ///use parsec_client::auth::AuthenticationData; ///use parsec_client::BasicClient; +///use parsec_client::core::secrecy::Secret; /// ///let app_name = String::from("app-name"); -///let app_auth_data = AuthenticationData::AppIdentity(app_name); +///let app_auth_data = AuthenticationData::AppIdentity(Secret::new(app_name)); ///let client: BasicClient = BasicClient::new(app_auth_data); ///``` /// @@ -49,8 +52,9 @@ use std::collections::HashSet; ///```no_run ///# use parsec_client::auth::AuthenticationData; ///# use parsec_client::BasicClient; +///# use parsec_client::core::secrecy::Secret; ///# use parsec_client::core::interface::requests::ProviderID; -///# let client: BasicClient = BasicClient::new(AuthenticationData::AppIdentity(String::from("app-name"))); +///# let client: BasicClient = BasicClient::new(AuthenticationData::AppIdentity(Secret::new(String::from("app-name")))); ///let res = client.ping(); /// ///if let Ok((wire_prot_v_maj, wire_prot_v_min)) = res { @@ -71,8 +75,9 @@ use std::collections::HashSet; ///```no_run ///# use parsec_client::auth::AuthenticationData; ///# use parsec_client::BasicClient; +///# use parsec_client::core::secrecy::Secret; ///# use parsec_client::core::interface::requests::ProviderID; -///# let client: BasicClient = BasicClient::new(AuthenticationData::AppIdentity(String::from("app-name"))); +///# let client: BasicClient = BasicClient::new(AuthenticationData::AppIdentity(Secret::new(String::from("app-name")))); ///use uuid::Uuid; /// ///// Identify provider by its UUID (in this case, the PKCS11 provider) @@ -94,7 +99,8 @@ use std::collections::HashSet; ///# use parsec_client::auth::AuthenticationData; ///# use parsec_client::BasicClient; ///# use parsec_client::core::interface::requests::ProviderID; -///# let mut client: BasicClient = BasicClient::new(AuthenticationData::AppIdentity(String::from("app-name"))); +///# use parsec_client::core::secrecy::Secret; +///# let mut client: BasicClient = BasicClient::new(AuthenticationData::AppIdentity(Secret::new(String::from("app-name")))); ///use parsec_client::core::interface::requests::Opcode; /// ///let desired_provider = ProviderID::Pkcs11; @@ -114,8 +120,9 @@ use std::collections::HashSet; ///```no_run ///# use parsec_client::auth::AuthenticationData; ///# use parsec_client::BasicClient; +///# use parsec_client::core::secrecy::Secret; ///# use parsec_client::core::interface::requests::ProviderID; -///# let client: BasicClient = BasicClient::new(AuthenticationData::AppIdentity(String::from("app-name"))); +///# let client: BasicClient = BasicClient::new(AuthenticationData::AppIdentity(Secret::new(String::from("app-name")))); ///use parsec_client::core::interface::operations::psa_algorithm::{Algorithm, AsymmetricSignature, Hash}; ///use parsec_client::core::interface::operations::psa_key_attributes::{Attributes, Lifetime, Policy, Type, UsageFlags}; /// @@ -151,7 +158,7 @@ use std::collections::HashSet; ///}; /// ///client -/// .psa_generate_key(key_name, key_attrs) +/// .psa_generate_key(key_name.clone(), key_attrs) /// .expect("Failed to create key!"); ///``` #[derive(Debug)] @@ -356,9 +363,10 @@ impl BasicClient { pub fn psa_import_key( &self, key_name: String, - key_material: Vec, + key_material: &[u8], key_attributes: Attributes, ) -> Result<()> { + let key_material = Secret::new(key_material.to_vec()); let crypto_provider = self.can_provide_crypto()?; let op = PsaImportKey { @@ -405,7 +413,7 @@ impl BasicClient { )?; if let NativeResult::PsaExportPublicKey(res) = res { - Ok(res.data) + Ok(res.data.to_vec()) } else { // Should really not be reached given the checks we do, but it's not impossible if some // changes happen in the interface @@ -438,9 +446,10 @@ impl BasicClient { pub fn psa_sign_hash( &self, key_name: String, - hash: Vec, + hash: &[u8], sign_algorithm: AsymmetricSignature, ) -> Result> { + let hash = Zeroizing::new(hash.to_vec()); let crypto_provider = self.can_provide_crypto()?; let op = PsaSignHash { @@ -456,7 +465,7 @@ impl BasicClient { )?; if let NativeResult::PsaSignHash(res) = res { - Ok(res.signature) + Ok(res.signature.to_vec()) } else { // Should really not be reached given the checks we do, but it's not impossible if some // changes happen in the interface @@ -489,10 +498,12 @@ impl BasicClient { pub fn psa_verify_hash( &self, key_name: String, - hash: Vec, + hash: &[u8], sign_algorithm: AsymmetricSignature, - signature: Vec, + signature: &[u8], ) -> Result<()> { + let hash = Zeroizing::new(hash.to_vec()); + let signature = Zeroizing::new(signature.to_vec()); let crypto_provider = self.can_provide_crypto()?; let op = PsaVerifyHash { diff --git a/src/core/mod.rs b/src/core/mod.rs index 9507f96..48b6320 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -12,4 +12,7 @@ pub mod operation_client; pub mod request_client; mod testing; +/// Resurfacing of the Secrecy library used by the client. +pub use interface::secrecy; +/// Resurfacing of the Parsec interface library used by the client. pub use parsec_interface as interface; diff --git a/src/core/testing/core_tests.rs b/src/core/testing/core_tests.rs index 76970ae..da22922 100644 --- a/src/core/testing/core_tests.rs +++ b/src/core/testing/core_tests.rs @@ -17,6 +17,7 @@ use parsec_interface::requests::Response; use parsec_interface::requests::ResponseStatus; use parsec_interface::requests::{request::RequestHeader, Request}; use parsec_interface::requests::{AuthType, BodyType, Opcode}; +use parsec_interface::secrecy::{ExposeSecret, Secret}; use std::collections::HashSet; use std::io::ErrorKind; @@ -118,7 +119,9 @@ fn list_opcodes_test() { #[test] fn no_crypto_provider_test() { - let client = BasicClient::new(AuthenticationData::AppIdentity(String::from("oops"))); + let client = BasicClient::new(AuthenticationData::AppIdentity(Secret::new(String::from( + "oops", + )))); let res = client .psa_destroy_key(String::from("random key")) @@ -129,7 +132,9 @@ fn no_crypto_provider_test() { #[test] fn core_provider_for_crypto_test() { - let mut client = BasicClient::new(AuthenticationData::AppIdentity(String::from("oops"))); + let mut client = BasicClient::new(AuthenticationData::AppIdentity(Secret::new(String::from( + "oops", + )))); client.set_implicit_provider(ProviderID::Core); let res = client @@ -168,7 +173,7 @@ fn psa_generate_key_test() { }; client - .psa_generate_key(key_name.clone(), key_attrs.clone()) + .psa_generate_key(key_name.clone(), key_attrs) .expect("failed to generate key"); // Check request: @@ -236,7 +241,7 @@ fn psa_import_key_test() { }; let key_data = vec![0xff_u8; 128]; client - .psa_import_key(key_name.clone(), key_data.clone(), key_attrs.clone()) + .psa_import_key(key_name.clone(), &key_data, key_attrs) .unwrap(); // Check request: @@ -244,7 +249,7 @@ fn psa_import_key_test() { if let NativeOperation::PsaImportKey(op) = op { assert_eq!(op.attributes, key_attrs); assert_eq!(op.key_name, key_name); - assert_eq!(op.data, key_data); + assert_eq!(op.data.expose_secret(), &key_data); } else { panic!("Got wrong operation type: {:?}", op); } @@ -259,7 +264,7 @@ fn psa_export_public_key_test() { let key_data = vec![0xa5; 128]; client.set_mock_read(&get_response_bytes_from_result( NativeResult::PsaExportPublicKey(operations::psa_export_public_key::Result { - data: key_data.clone(), + data: key_data.clone().into(), }), )); @@ -292,14 +297,14 @@ fn psa_sign_hash_test() { let signature = vec![0x33_u8; 128]; client.set_mock_read(&get_response_bytes_from_result(NativeResult::PsaSignHash( operations::psa_sign_hash::Result { - signature: signature.clone(), + signature: signature.clone().into(), }, ))); // Check response: assert_eq!( client - .psa_sign_hash(key_name.clone(), hash.clone(), sign_algorithm.clone()) + .psa_sign_hash(key_name.clone(), &hash, sign_algorithm) .expect("Failed to sign hash"), signature ); @@ -308,7 +313,7 @@ fn psa_sign_hash_test() { let op = get_operation_from_req_bytes(client.get_mock_write()); if let NativeOperation::PsaSignHash(op) = op { assert_eq!(op.key_name, key_name); - assert_eq!(op.hash, hash); + assert_eq!(op.hash.to_vec(), hash); assert_eq!(op.alg, sign_algorithm); } else { panic!("Got wrong operation type: {:?}", op); @@ -329,21 +334,16 @@ fn verify_hash_test() { )); client - .psa_verify_hash( - key_name.clone(), - hash.clone(), - sign_algorithm.clone(), - signature.clone(), - ) + .psa_verify_hash(key_name.clone(), &hash, sign_algorithm, &signature) .expect("Failed to sign hash"); // Check request: let op = get_operation_from_req_bytes(client.get_mock_write()); if let NativeOperation::PsaVerifyHash(op) = op { assert_eq!(op.key_name, key_name); - assert_eq!(op.hash, hash); + assert_eq!(op.hash.to_vec(), hash); assert_eq!(op.alg, sign_algorithm); - assert_eq!(op.signature, signature); + assert_eq!(op.signature.to_vec(), signature); } else { panic!("Got wrong operation type: {:?}", op); } @@ -423,7 +423,7 @@ fn auth_value_test() { let req = get_req_from_bytes(client.get_mock_write()); assert_eq!( - String::from_utf8(req.auth.bytes().to_owned()).unwrap(), + String::from_utf8(req.auth.buffer.expose_secret().to_owned()).unwrap(), String::from(DEFAULT_APP_NAME) ); } diff --git a/src/core/testing/mod.rs b/src/core/testing/mod.rs index 797e281..a69109c 100644 --- a/src/core/testing/mod.rs +++ b/src/core/testing/mod.rs @@ -7,6 +7,7 @@ use crate::auth::AuthenticationData; use crate::error::Result; use mockstream::{FailingMockStream, SyncMockStream}; use parsec_interface::requests::ProviderID; +use parsec_interface::secrecy::Secret; use std::ops::{Deref, DerefMut}; use std::time::Duration; @@ -66,8 +67,8 @@ impl DerefMut for TestBasicClient { impl Default for TestBasicClient { fn default() -> Self { let mut client = TestBasicClient { - core_client: BasicClient::new(AuthenticationData::AppIdentity(String::from( - DEFAULT_APP_NAME, + core_client: BasicClient::new(AuthenticationData::AppIdentity(Secret::new( + String::from(DEFAULT_APP_NAME), ))), mock_stream: SyncMockStream::new(), };