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, } }