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
91 changes: 91 additions & 0 deletions src/core/basic_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ use parsec_interface::operations::psa_import_key::Operation as PsaImportKey;
use parsec_interface::operations::psa_key_attributes::Attributes;
use parsec_interface::operations::psa_raw_key_agreement::Operation as PsaRawKeyAgreement;
use parsec_interface::operations::psa_sign_hash::Operation as PsaSignHash;
use parsec_interface::operations::psa_sign_message::Operation as PsaSignMessage;
use parsec_interface::operations::psa_verify_hash::Operation as PsaVerifyHash;
use parsec_interface::operations::psa_verify_message::Operation as PsaVerifyMessage;
use parsec_interface::operations::{NativeOperation, NativeResult};
use parsec_interface::requests::AuthType;
use parsec_interface::requests::{Opcode, ProviderId};
Expand Down Expand Up @@ -722,6 +724,95 @@ impl BasicClient {
Ok(())
}

/// **[Cryptographic Operation]** Create an asymmetric signature on a message.
///
/// The key intended for signing **must** have its `sign_message` flag set
/// to `true` in its [key policy](https://docs.rs/parsec-interface/*/parsec_interface/operations/psa_key_attributes/struct.Policy.html).
///
/// The signature will be created with the algorithm defined in
/// `sign_algorithm`, but only after checking that the key policy
/// and type conform with it.
///
/// # Errors
///
/// If the implicit client provider is `ProviderId::Core`, a client error
/// of `InvalidProvider` type is returned.
///
/// See the operation-specific response codes returned by the service
/// [here](https://parallaxsecond.github.io/parsec-book/parsec_client/operations/psa_sign_message.html#specific-response-status-codes).
pub fn psa_sign_message(
&self,
key_name: String,
msg: &[u8],
sign_algorithm: AsymmetricSignature,
) -> Result<Vec<u8>> {
let message = Zeroizing::new(msg.to_vec());
let crypto_provider = self.can_provide_crypto()?;

let op = PsaSignMessage {
key_name,
alg: sign_algorithm,
message,
};

let res = self.op_client.process_operation(
NativeOperation::PsaSignMessage(op),
crypto_provider,
&self.auth_data,
)?;

if let NativeResult::PsaSignMessage(res) = res {
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
Err(Error::Client(ClientErrorKind::InvalidServiceResponseType))
}
}

/// **[Cryptographic Operation]** Verify an existing asymmetric signature over a message.
///
/// The key intended for signing **must** have its `verify_message` flag set
/// to `true` in its [key policy](https://docs.rs/parsec-interface/*/parsec_interface/operations/psa_key_attributes/struct.Policy.html).
///
/// The signature will be verifyied with the algorithm defined in
/// `sign_algorithm`, but only after checking that the key policy
/// and type conform with it.
///
/// # Errors
///
/// If the implicit client provider is `ProviderId::Core`, a client error
/// of `InvalidProvider` type is returned.
///
/// See the operation-specific response codes returned by the service
/// [here](https://parallaxsecond.github.io/parsec-book/parsec_client/operations/psa_verify_message.html#specific-response-status-codes).
pub fn psa_verify_message(
&self,
key_name: String,
msg: &[u8],
sign_algorithm: AsymmetricSignature,
signature: &[u8],
) -> Result<()> {
let message = Zeroizing::new(msg.to_vec());
let signature = Zeroizing::new(signature.to_vec());
let crypto_provider = self.can_provide_crypto()?;

let op = PsaVerifyMessage {
key_name,
alg: sign_algorithm,
message,
signature,
};

let _ = self.op_client.process_operation(
NativeOperation::PsaVerifyMessage(op),
crypto_provider,
&self.auth_data,
)?;

Ok(())
}

/// **[Cryptographic Operation]** Encrypt a short message.
///
/// The key intended for encrypting **must** have its `encrypt` flag set
Expand Down
66 changes: 66 additions & 0 deletions src/core/testing/core_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,72 @@ fn verify_hash_test() {
// VerifyHash response is empty so no checking to be done
}

#[test]
fn psa_sign_message_test() {
let mut client: TestBasicClient = Default::default();
let msg = vec![0x77_u8; 100];
let key_name = String::from("key_name");
let sign_algorithm = AsymmetricSignature::Ecdsa {
hash_alg: Hash::Sha256.into(),
};
let signature = vec![0x33_u8; 128];
client.set_mock_read(&get_response_bytes_from_result(
NativeResult::PsaSignMessage(operations::psa_sign_message::Result {
signature: signature.clone().into(),
}),
));

// Check response:
assert_eq!(
client
.psa_sign_message(key_name.clone(), &msg, sign_algorithm)
.expect("Failed to sign message"),
signature
);

// Check request:
let op = get_operation_from_req_bytes(client.get_mock_write());
if let NativeOperation::PsaSignMessage(op) = op {
assert_eq!(op.key_name, key_name);
assert_eq!(op.message.to_vec(), msg);
assert_eq!(op.alg, sign_algorithm);
} else {
panic!("Got wrong operation type: {:?}", op);
}
}

#[test]
fn verify_message_test() {
let mut client: TestBasicClient = Default::default();
let msg = vec![0x77_u8; 100];
let key_name = String::from("key_name");
let sign_algorithm = AsymmetricSignature::Ecdsa {
hash_alg: Hash::Sha256.into(),
};
let signature = vec![0x33_u8; 128];
client.set_mock_read(&get_response_bytes_from_result(
NativeResult::PsaVerifyMessage(operations::psa_verify_message::Result {}),
));

client
.psa_verify_message(key_name.clone(), &msg, sign_algorithm, &signature)
.expect("Failed to sign hash");

// Check request:
let op = get_operation_from_req_bytes(client.get_mock_write());
if let NativeOperation::PsaVerifyMessage(op) = op {
assert_eq!(op.key_name, key_name);
assert_eq!(op.message.to_vec(), msg);
assert_eq!(op.alg, sign_algorithm);
assert_eq!(op.signature.to_vec(), signature);
} else {
panic!("Got wrong operation type: {:?}", op);
}

// Check response:
// VerifyMessage response is empty so no checking to be done
}

#[test]
fn asymmetric_encrypt_test() {
let mut client: TestBasicClient = Default::default();
Expand Down