Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
11 changes: 8 additions & 3 deletions src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@
// 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)]
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<String>),
}

impl AuthenticationData {
Expand All @@ -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())
}
}
}
Expand Down
35 changes: 23 additions & 12 deletions src/core/basic_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
///
Expand All @@ -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);
///```
///
Expand All @@ -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 {
Expand All @@ -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)
Expand All @@ -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;
Expand All @@ -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};
///
Expand Down Expand Up @@ -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)]
Expand Down Expand Up @@ -356,9 +363,10 @@ impl BasicClient {
pub fn psa_import_key(
&self,
key_name: String,
key_material: Vec<u8>,
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 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -438,9 +446,10 @@ impl BasicClient {
pub fn psa_sign_hash(
&self,
key_name: String,
hash: Vec<u8>,
hash: &[u8],
sign_algorithm: AsymmetricSignature,
) -> Result<Vec<u8>> {
let hash = Zeroizing::new(hash.to_vec());
let crypto_provider = self.can_provide_crypto()?;

let op = PsaSignHash {
Expand All @@ -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
Expand Down Expand Up @@ -489,10 +498,12 @@ impl BasicClient {
pub fn psa_verify_hash(
&self,
key_name: String,
hash: Vec<u8>,
hash: &[u8],
sign_algorithm: AsymmetricSignature,
signature: Vec<u8>,
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 {
Expand Down
3 changes: 3 additions & 0 deletions src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
36 changes: 18 additions & 18 deletions src/core/testing/core_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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"))
Expand All @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -236,15 +241,15 @@ 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:
let op = get_operation_from_req_bytes(client.get_mock_write());
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);
}
Expand All @@ -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(),
}),
));

Expand Down Expand Up @@ -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
);
Expand All @@ -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);
Expand All @@ -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);
}
Expand Down Expand Up @@ -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)
);
}
Expand Down
5 changes: 3 additions & 2 deletions src/core/testing/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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(),
};
Expand Down