From 8527a3a919bb0dae2825c51bf5dbcfe5db1c5e37 Mon Sep 17 00:00:00 2001 From: Sam Davis Date: Fri, 10 Sep 2021 10:27:59 +0100 Subject: [PATCH] Added the changes required for the CanDoCrypto operation. Added new files cntaining the CanDoCrypto operation generated from the protobuf contract, the rust version of the operation and the conversion between the rust and the protobuf values. Also added changes to the relvent mod.rs files so that the new files are included. Signed-off-by: Sam Davis --- src/operations/can_do_crypto.rs | 33 ++++ src/operations/mod.rs | 19 ++ .../convert_can_do_crypto.rs | 186 ++++++++++++++++++ .../generated_ops/can_do_crypto.rs | 19 ++ src/operations_protobuf/generated_ops/mod.rs | 17 ++ src/operations_protobuf/mod.rs | 17 ++ src/requests/mod.rs | 8 +- 7 files changed, 297 insertions(+), 2 deletions(-) create mode 100644 src/operations/can_do_crypto.rs create mode 100644 src/operations_protobuf/convert_can_do_crypto.rs create mode 100644 src/operations_protobuf/generated_ops/can_do_crypto.rs diff --git a/src/operations/can_do_crypto.rs b/src/operations/can_do_crypto.rs new file mode 100644 index 0000000..67397d4 --- /dev/null +++ b/src/operations/can_do_crypto.rs @@ -0,0 +1,33 @@ +// Copyright 2021 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 +//! # CanDoCrypto operation +//! +//! Checks if the provider supports the input attributes for the operations of a given type + +use super::psa_key_attributes::Attributes; + +/// Public enum which stores the options for the types of check +#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)] +pub enum CheckType { + /// Using a specific algorithm with an existing key. + Use, + /// Generating a key and optionally using it for a specific algorithm. + Generate, + /// Importing a key and optionally using it for a specific algorithm. + Import, + /// Deriving a key and optionally using it for a specific algorithm (to be checked) + Derive, +} + +/// Native object for client deleting operation. +#[derive(Clone, Debug, Copy)] +pub struct Operation { + /// The type of check required + pub check_type: CheckType, + /// The attributes that are to be checked + pub attributes: Attributes, +} + +/// Native object for client deleting result. +#[derive(Copy, Clone, Debug)] +pub struct Result; diff --git a/src/operations/mod.rs b/src/operations/mod.rs index ee71779..31d237d 100644 --- a/src/operations/mod.rs +++ b/src/operations/mod.rs @@ -33,6 +33,7 @@ pub mod delete_client; pub mod list_clients; pub mod psa_generate_random; pub mod psa_raw_key_agreement; +pub mod can_do_crypto; pub use psa_crypto::types::algorithm as psa_algorithm; pub use psa_crypto::types::key as psa_key_attributes; @@ -91,6 +92,8 @@ pub enum NativeOperation { PsaSignMessage(psa_sign_message::Operation), /// PsaVerifyMessage operation PsaVerifyMessage(psa_verify_message::Operation), + /// CanDoCrypto operation + CanDoCrypto(can_do_crypto::Operation), } impl NativeOperation { @@ -121,6 +124,7 @@ impl NativeOperation { NativeOperation::PsaRawKeyAgreement(_) => Opcode::PsaRawKeyAgreement, NativeOperation::PsaSignMessage(_) => Opcode::PsaSignMessage, NativeOperation::PsaVerifyMessage(_) => Opcode::PsaVerifyMessage, + NativeOperation::CanDoCrypto(_) => Opcode::CanDoCrypto, } } } @@ -177,6 +181,8 @@ pub enum NativeResult { PsaSignMessage(psa_sign_message::Result), /// PsaVerifyMessage result PsaVerifyMessage(psa_verify_message::Result), + /// CanDoCrypto result + CanDoCrypto(can_do_crypto::Result), } impl NativeResult { @@ -207,6 +213,7 @@ impl NativeResult { NativeResult::PsaRawKeyAgreement(_) => Opcode::PsaRawKeyAgreement, NativeResult::PsaSignMessage(_) => Opcode::PsaSignMessage, NativeResult::PsaVerifyMessage(_) => Opcode::PsaVerifyMessage, + NativeResult::CanDoCrypto(_) => Opcode::CanDoCrypto, } } } @@ -383,6 +390,12 @@ impl From for NativeOperation { } } +impl From for NativeOperation { + fn from(op: can_do_crypto::Operation) -> Self { + NativeOperation::CanDoCrypto(op) + } +} + impl From for NativeResult { fn from(op: list_providers::Result) -> Self { NativeResult::ListProviders(op) @@ -526,3 +539,9 @@ impl From for NativeResult { NativeResult::PsaVerifyMessage(op) } } + +impl From for NativeResult { + fn from(op: can_do_crypto::Result) -> Self { + NativeResult::CanDoCrypto(op) + } +} diff --git a/src/operations_protobuf/convert_can_do_crypto.rs b/src/operations_protobuf/convert_can_do_crypto.rs new file mode 100644 index 0000000..0a10cb1 --- /dev/null +++ b/src/operations_protobuf/convert_can_do_crypto.rs @@ -0,0 +1,186 @@ +// Copyright 2021 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 +use super::generated_ops::can_do_crypto::{ + CheckType as CheckTypeProto, Operation as OperationProto, Result as ResultProto, +}; +use crate::operations::can_do_crypto::{CheckType, Operation, Result}; +use crate::requests::ResponseStatus; +use log::error; +use std::convert::{TryFrom, TryInto}; + +impl TryFrom for Operation { + type Error = ResponseStatus; + + fn try_from(proto_op: OperationProto) -> std::result::Result { + let key_attributes = proto_op.attributes.ok_or_else(|| { + error!("The attributes field of CanDoCrypto::Operation message is not set (mandatory field)."); + ResponseStatus::InvalidEncoding + })?; + Ok(Operation { + check_type: i32_to_check_type(proto_op.check_type)?, + attributes: key_attributes.try_into()?, + }) + } +} + +impl TryFrom for OperationProto { + type Error = ResponseStatus; + + fn try_from(op: Operation) -> std::result::Result { + Ok(OperationProto { + check_type: check_type_to_i32(op.check_type), + attributes: Some(op.attributes.try_into()?), + }) + } +} + +impl TryFrom for ResultProto { + type Error = ResponseStatus; + + fn try_from(_result: Result) -> std::result::Result { + Ok(ResultProto {}) + } +} + +impl TryFrom for Result { + type Error = ResponseStatus; + + fn try_from(_response: ResultProto) -> std::result::Result { + Ok(Result {}) + } +} + +// CheckType: from protobuf to native +impl TryFrom for CheckType { + type Error = ResponseStatus; + + fn try_from(check_type_proto_val: CheckTypeProto) -> std::result::Result { + match check_type_proto_val { + CheckTypeProto::ChecktypeNone => Err(ResponseStatus::InvalidEncoding), + CheckTypeProto::Use => Ok(CheckType::Use), + CheckTypeProto::Generate => Ok(CheckType::Generate), + CheckTypeProto::Import => Ok(CheckType::Import), + CheckTypeProto::Derive => Ok(CheckType::Derive), + } + } +} + +// CheckType: from native to protobuf +impl TryFrom for CheckTypeProto { + type Error = ResponseStatus; + + fn try_from(check_type_val: CheckType) -> std::result::Result { + match check_type_val { + CheckType::Use => Ok(CheckTypeProto::Use), + CheckType::Generate => Ok(CheckTypeProto::Generate), + CheckType::Import => Ok(CheckTypeProto::Import), + CheckType::Derive => Ok(CheckTypeProto::Derive), + } + } +} + +// CheckType from protobuf to native +pub fn i32_to_check_type(check_type_val: i32) -> std::result::Result { + let check_type_proto: CheckTypeProto = check_type_val.try_into()?; + check_type_proto.try_into() +} + +// CheckType from native to protobuf +pub fn check_type_to_i32(check_type: CheckType) -> i32 { + match check_type { + CheckType::Use => CheckTypeProto::Use.into(), + CheckType::Generate => CheckTypeProto::Generate.into(), + CheckType::Import => CheckTypeProto::Import.into(), + CheckType::Derive => CheckTypeProto::Derive.into(), + } +} + +#[cfg(test)] +mod test { + + use super::super::generated_ops::can_do_crypto::Operation as OperationProto; + use crate::operations::can_do_crypto::{CheckType, Operation}; + use crate::operations::psa_algorithm::{Algorithm, AsymmetricSignature, Hash}; + use crate::operations::psa_key_attributes::{self, Attributes, Lifetime, Policy, UsageFlags}; + use crate::operations_protobuf::convert_can_do_crypto::check_type_to_i32; + use std::convert::TryInto; + + #[test] + fn proto_to_resp() { + let mut usage_flags: UsageFlags = Default::default(); + let _ = usage_flags + .set_export() + .set_copy() + .set_cache() + .set_encrypt() + .set_decrypt() + .set_sign_message() + .set_verify_message() + .set_sign_hash() + .set_verify_hash() + .set_derive(); + let key_attrs = Attributes { + lifetime: Lifetime::Persistent, + key_type: psa_key_attributes::Type::RsaKeyPair, + bits: 1024, + policy: Policy { + usage_flags, + permitted_algorithms: Algorithm::AsymmetricSignature( + AsymmetricSignature::RsaPkcs1v15Sign { + hash_alg: Hash::Sha1.into(), + }, + ), + }, + }; + let proto = OperationProto { + check_type: check_type_to_i32(CheckType::Use), + attributes: Some(key_attrs.try_into().expect("Failed conversion")), + }; + + let resp: Operation = proto.try_into().expect("Failed conversion"); + + assert_eq!(resp.check_type, CheckType::Use); + assert_eq!(resp.attributes, key_attrs); + } + + #[test] + fn resp_to_proto() { + let mut usage_flags: UsageFlags = Default::default(); + let _ = usage_flags + .set_export() + .set_copy() + .set_cache() + .set_encrypt() + .set_decrypt() + .set_sign_message() + .set_verify_message() + .set_sign_hash() + .set_verify_hash() + .set_derive(); + let key_attrs = Attributes { + lifetime: Lifetime::Persistent, + key_type: psa_key_attributes::Type::RsaKeyPair, + bits: 1024, + policy: Policy { + usage_flags, + permitted_algorithms: Algorithm::AsymmetricSignature( + AsymmetricSignature::RsaPkcs1v15Sign { + hash_alg: Hash::Sha1.into(), + }, + ), + }, + }; + let resp: Operation = Operation { + check_type: CheckType::Use, + attributes: key_attrs, + }; + + let proto: OperationProto = resp.try_into().expect("Failed conversion"); + + assert_eq!(proto.check_type, check_type_to_i32(CheckType::Use)); + assert_eq!( + proto.attributes.expect("Failed conversion"), + key_attrs.try_into().expect("Failed conversion") + ); + } +} diff --git a/src/operations_protobuf/generated_ops/can_do_crypto.rs b/src/operations_protobuf/generated_ops/can_do_crypto.rs new file mode 100644 index 0000000..516d2e1 --- /dev/null +++ b/src/operations_protobuf/generated_ops/can_do_crypto.rs @@ -0,0 +1,19 @@ +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Operation { + #[prost(enumeration="CheckType", tag="1")] + pub check_type: i32, + #[prost(message, optional, tag="2")] + pub attributes: ::std::option::Option, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct Result { +} +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] +pub enum CheckType { + ChecktypeNone = 0, + Use = 1, + Generate = 2, + Import = 3, + Derive = 4, +} diff --git a/src/operations_protobuf/generated_ops/mod.rs b/src/operations_protobuf/generated_ops/mod.rs index 453d076..6015379 100644 --- a/src/operations_protobuf/generated_ops/mod.rs +++ b/src/operations_protobuf/generated_ops/mod.rs @@ -27,6 +27,7 @@ pub mod psa_generate_random; pub mod psa_hash_compute; pub mod psa_hash_compare; pub mod psa_raw_key_agreement; +pub mod can_do_crypto; use zeroize::Zeroize; @@ -34,6 +35,7 @@ use crate::requests::{ResponseStatus, Result}; use log::error; use psa_algorithm::algorithm::{aead::AeadWithDefaultLengthTag, key_agreement::Raw, Cipher, Hash}; use psa_key_attributes::key_type::{DhFamily, EccFamily}; +use can_do_crypto::CheckType; use std::convert::TryFrom; impl TryFrom for Cipher { @@ -114,6 +116,19 @@ impl TryFrom for DhFamily { } } +impl TryFrom for CheckType { + type Error = ResponseStatus; + fn try_from(check_type_val: i32) -> Result { + CheckType::from_i32(check_type_val).ok_or_else(|| { + error!( + "Value {} not supported as a check type.", + check_type_val + ); + ResponseStatus::InvalidEncoding + }) + } +} + pub(super) trait ClearProtoMessage { fn clear_message(&mut self) {} } @@ -152,6 +167,8 @@ empty_clear_message!(psa_verify_hash::Result); empty_clear_message!(psa_verify_message::Result); empty_clear_message!(psa_generate_random::Operation); empty_clear_message!(psa_hash_compare::Result); +empty_clear_message!(can_do_crypto::Operation); +empty_clear_message!(can_do_crypto::Result); impl ClearProtoMessage for psa_sign_hash::Operation { fn clear_message(&mut self) { diff --git a/src/operations_protobuf/mod.rs b/src/operations_protobuf/mod.rs index 6ba160c..c16ff45 100644 --- a/src/operations_protobuf/mod.rs +++ b/src/operations_protobuf/mod.rs @@ -29,6 +29,7 @@ mod convert_psa_aead_encrypt; mod convert_psa_aead_decrypt; mod convert_psa_generate_random; mod convert_psa_raw_key_agreement; +mod convert_can_do_crypto; #[rustfmt::skip] #[allow(unused_qualifications, missing_copy_implementations, clippy::pedantic, clippy::module_inception, clippy::upper_case_acronyms, clippy::enum_variant_names)] @@ -38,6 +39,7 @@ use crate::operations::{Convert, NativeOperation, NativeResult}; use crate::requests::{ request::RequestBody, response::ResponseBody, BodyType, Opcode, ResponseStatus, Result, }; +use generated_ops::can_do_crypto as can_do_crypto_proto; use generated_ops::delete_client as delete_client_proto; use generated_ops::list_authenticators as list_authenticators_proto; use generated_ops::list_clients as list_clients_proto; @@ -195,6 +197,10 @@ impl Convert for ProtobufConverter { body.bytes(), psa_raw_key_agreement_proto::Operation ))), + Opcode::CanDoCrypto => Ok(NativeOperation::CanDoCrypto(wire_to_native!( + body.bytes(), + can_do_crypto_proto::Operation + ))), } } @@ -274,6 +280,9 @@ impl Convert for ProtobufConverter { NativeOperation::PsaRawKeyAgreement(operation) => Ok(RequestBody::from_bytes( native_to_wire!(operation, psa_raw_key_agreement_proto::Operation), )), + NativeOperation::CanDoCrypto(operation) => Ok(RequestBody::from_bytes( + native_to_wire!(operation, can_do_crypto_proto::Operation), + )), } } @@ -373,6 +382,10 @@ impl Convert for ProtobufConverter { body.bytes(), psa_raw_key_agreement_proto::Result ))), + Opcode::CanDoCrypto => Ok(NativeResult::CanDoCrypto(wire_to_native!( + body.bytes(), + can_do_crypto_proto::Result + ))), } } @@ -467,6 +480,10 @@ impl Convert for ProtobufConverter { NativeResult::PsaRawKeyAgreement(result) => Ok(ResponseBody::from_bytes( native_to_wire!(result, psa_raw_key_agreement_proto::Result), )), + NativeResult::CanDoCrypto(result) => Ok(ResponseBody::from_bytes(native_to_wire!( + result, + can_do_crypto_proto::Result + ))), } } } diff --git a/src/requests/mod.rs b/src/requests/mod.rs index 67c8ed8..4f2acbb 100644 --- a/src/requests/mod.rs +++ b/src/requests/mod.rs @@ -133,6 +133,8 @@ pub enum Opcode { ListClients = 0x001B, /// DeleteClient operation (admin operation) DeleteClient = 0x001C, + /// CanDoCrypto operation + CanDoCrypto = 0x0020, } impl Opcode { @@ -163,7 +165,8 @@ impl Opcode { | Opcode::PsaHashCompare | Opcode::PsaAeadEncrypt | Opcode::PsaAeadDecrypt - | Opcode::PsaRawKeyAgreement => false, + | Opcode::PsaRawKeyAgreement + | Opcode::CanDoCrypto => false, } } @@ -193,7 +196,8 @@ impl Opcode { | Opcode::PsaHashCompare | Opcode::PsaAeadEncrypt | Opcode::PsaAeadDecrypt - | Opcode::PsaRawKeyAgreement => false, + | Opcode::PsaRawKeyAgreement + | Opcode::CanDoCrypto => false, } }