Skip to content

Commit 1d72dbc

Browse files
Support for ps_sign_ and ps_verify_message Parsec operations.
Signed-off-by: Robert Drazkowski <Robert.Drazkowski@globallogic.com>
1 parent 9d34265 commit 1d72dbc

File tree

2 files changed

+157
-0
lines changed

2 files changed

+157
-0
lines changed

src/core/basic_client.rs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ use parsec_interface::operations::psa_import_key::Operation as PsaImportKey;
3232
use parsec_interface::operations::psa_key_attributes::Attributes;
3333
use parsec_interface::operations::psa_raw_key_agreement::Operation as PsaRawKeyAgreement;
3434
use parsec_interface::operations::psa_sign_hash::Operation as PsaSignHash;
35+
use parsec_interface::operations::psa_sign_message::Operation as PsaSignMessage;
3536
use parsec_interface::operations::psa_verify_hash::Operation as PsaVerifyHash;
37+
use parsec_interface::operations::psa_verify_message::Operation as PsaVerifyMessage;
3638
use parsec_interface::operations::{NativeOperation, NativeResult};
3739
use parsec_interface::requests::AuthType;
3840
use parsec_interface::requests::{Opcode, ProviderId};
@@ -722,6 +724,95 @@ impl BasicClient {
722724
Ok(())
723725
}
724726

727+
/// **[Cryptographic Operation]** Create an asymmetric signature on a message.
728+
///
729+
/// The key intended for signing **must** have its `sign_hash` flag set
730+
/// to `true` in its [key policy](https://docs.rs/parsec-interface/*/parsec_interface/operations/psa_key_attributes/struct.Policy.html).
731+
///
732+
/// The signature will be created with the algorithm defined in
733+
/// `sign_algorithm`, but only after checking that the key policy
734+
/// and type conform with it.
735+
///
736+
/// # Errors
737+
///
738+
/// If the implicit client provider is `ProviderId::Core`, a client error
739+
/// of `InvalidProvider` type is returned.
740+
///
741+
/// See the operation-specific response codes returned by the service
742+
/// [here](https://parallaxsecond.github.io/parsec-book/parsec_client/operations/psa_sign_hash.html#specific-response-status-codes).
743+
pub fn psa_sign_message(
744+
&self,
745+
key_name: String,
746+
msg: &[u8],
747+
sign_algorithm: AsymmetricSignature,
748+
) -> Result<Vec<u8>> {
749+
let message = Zeroizing::new(msg.to_vec());
750+
let crypto_provider = self.can_provide_crypto()?;
751+
752+
let op = PsaSignMessage {
753+
key_name,
754+
alg: sign_algorithm,
755+
message,
756+
};
757+
758+
let res = self.op_client.process_operation(
759+
NativeOperation::PsaSignMessage(op),
760+
crypto_provider,
761+
&self.auth_data,
762+
)?;
763+
764+
if let NativeResult::PsaSignMessage(res) = res {
765+
Ok(res.signature.to_vec())
766+
} else {
767+
// Should really not be reached given the checks we do, but it's not impossible if some
768+
// changes happen in the interface
769+
Err(Error::Client(ClientErrorKind::InvalidServiceResponseType))
770+
}
771+
}
772+
773+
/// **[Cryptographic Operation]** Verify an existing asymmetric signature over a message.
774+
///
775+
/// The key intended for signing **must** have its `verify_hash` flag set
776+
/// to `true` in its [key policy](https://docs.rs/parsec-interface/*/parsec_interface/operations/psa_key_attributes/struct.Policy.html).
777+
///
778+
/// The signature will be verifyied with the algorithm defined in
779+
/// `sign_algorithm`, but only after checking that the key policy
780+
/// and type conform with it.
781+
///
782+
/// # Errors
783+
///
784+
/// If the implicit client provider is `ProviderId::Core`, a client error
785+
/// of `InvalidProvider` type is returned.
786+
///
787+
/// See the operation-specific response codes returned by the service
788+
/// [here](https://parallaxsecond.github.io/parsec-book/parsec_client/operations/psa_verify_hash.html#specific-response-status-codes).
789+
pub fn psa_verify_message(
790+
&self,
791+
key_name: String,
792+
msg: &[u8],
793+
sign_algorithm: AsymmetricSignature,
794+
signature: &[u8],
795+
) -> Result<()> {
796+
let message = Zeroizing::new(msg.to_vec());
797+
let signature = Zeroizing::new(signature.to_vec());
798+
let crypto_provider = self.can_provide_crypto()?;
799+
800+
let op = PsaVerifyMessage {
801+
key_name,
802+
alg: sign_algorithm,
803+
message,
804+
signature,
805+
};
806+
807+
let _ = self.op_client.process_operation(
808+
NativeOperation::PsaVerifyMessage(op),
809+
crypto_provider,
810+
&self.auth_data,
811+
)?;
812+
813+
Ok(())
814+
}
815+
725816
/// **[Cryptographic Operation]** Encrypt a short message.
726817
///
727818
/// The key intended for encrypting **must** have its `encrypt` flag set

src/core/testing/core_tests.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,72 @@ fn verify_hash_test() {
480480
// VerifyHash response is empty so no checking to be done
481481
}
482482

483+
#[test]
484+
fn psa_sign_message_test() {
485+
let mut client: TestBasicClient = Default::default();
486+
let msg = vec![0x77_u8; 100];
487+
let key_name = String::from("key_name");
488+
let sign_algorithm = AsymmetricSignature::Ecdsa {
489+
hash_alg: Hash::Sha256.into(),
490+
};
491+
let signature = vec![0x33_u8; 128];
492+
client.set_mock_read(&get_response_bytes_from_result(
493+
NativeResult::PsaSignMessage(operations::psa_sign_message::Result {
494+
signature: signature.clone().into(),
495+
}),
496+
));
497+
498+
// Check response:
499+
assert_eq!(
500+
client
501+
.psa_sign_message(key_name.clone(), &msg, sign_algorithm)
502+
.expect("Failed to sign message"),
503+
signature
504+
);
505+
506+
// Check request:
507+
let op = get_operation_from_req_bytes(client.get_mock_write());
508+
if let NativeOperation::PsaSignMessage(op) = op {
509+
assert_eq!(op.key_name, key_name);
510+
assert_eq!(op.message.to_vec(), msg);
511+
assert_eq!(op.alg, sign_algorithm);
512+
} else {
513+
panic!("Got wrong operation type: {:?}", op);
514+
}
515+
}
516+
517+
#[test]
518+
fn verify_message_test() {
519+
let mut client: TestBasicClient = Default::default();
520+
let msg = vec![0x77_u8; 100];
521+
let key_name = String::from("key_name");
522+
let sign_algorithm = AsymmetricSignature::Ecdsa {
523+
hash_alg: Hash::Sha256.into(),
524+
};
525+
let signature = vec![0x33_u8; 128];
526+
client.set_mock_read(&get_response_bytes_from_result(
527+
NativeResult::PsaVerifyMessage(operations::psa_verify_message::Result {}),
528+
));
529+
530+
client
531+
.psa_verify_message(key_name.clone(), &msg, sign_algorithm, &signature)
532+
.expect("Failed to sign hash");
533+
534+
// Check request:
535+
let op = get_operation_from_req_bytes(client.get_mock_write());
536+
if let NativeOperation::PsaVerifyMessage(op) = op {
537+
assert_eq!(op.key_name, key_name);
538+
assert_eq!(op.message.to_vec(), msg);
539+
assert_eq!(op.alg, sign_algorithm);
540+
assert_eq!(op.signature.to_vec(), signature);
541+
} else {
542+
panic!("Got wrong operation type: {:?}", op);
543+
}
544+
545+
// Check response:
546+
// VerifyMessage response is empty so no checking to be done
547+
}
548+
483549
#[test]
484550
fn asymmetric_encrypt_test() {
485551
let mut client: TestBasicClient = Default::default();

0 commit comments

Comments
 (0)