diff --git a/build.rs b/build.rs index 15f3e3a..f126669 100644 --- a/build.rs +++ b/build.rs @@ -17,11 +17,11 @@ fn generate_proto_sources() -> Result<()> { .path() .into_os_string() .into_string() - .or_else(|_| { - Err(Error::new( + .map_err(|_| { + Error::new( ErrorKind::InvalidData, "conversion from OsString to String failed", - )) + ) }) }) // Fail the entire operation if there was an error. diff --git a/parsec-operations b/parsec-operations index 16f064f..8eee3fb 160000 --- a/parsec-operations +++ b/parsec-operations @@ -1 +1 @@ -Subproject commit 16f064f500c2a524625481c693ef712952508622 +Subproject commit 8eee3fb280525a671bf4f2a35646011e047ba844 diff --git a/src/operations/delete_client.rs b/src/operations/delete_client.rs new file mode 100644 index 0000000..b2a2ac7 --- /dev/null +++ b/src/operations/delete_client.rs @@ -0,0 +1,16 @@ +// Copyright 2021 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 +//! # DeleteClient operation +//! +//! Delete all data a client own in Parsec. + +/// Native object for client deleting operation. +#[derive(Clone, Debug)] +pub struct Operation { + /// A client application name. + pub client: String, +} + +/// Native object for client deleting result. +#[derive(Copy, Clone, Debug)] +pub struct Result; diff --git a/src/operations/list_clients.rs b/src/operations/list_clients.rs new file mode 100644 index 0000000..2350288 --- /dev/null +++ b/src/operations/list_clients.rs @@ -0,0 +1,16 @@ +// Copyright 2021 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 +//! # ListClients operation +//! +//! Lists all clients owning data in Parsec. + +/// Native object for client listing operation. +#[derive(Copy, Clone, Debug)] +pub struct Operation; + +/// Native object for client listing result. +#[derive(Debug)] +pub struct Result { + /// A list of client application names. + pub clients: Vec, +} diff --git a/src/operations/mod.rs b/src/operations/mod.rs index 946eb5b..dcc055a 100644 --- a/src/operations/mod.rs +++ b/src/operations/mod.rs @@ -27,6 +27,8 @@ pub mod list_opcodes; pub mod list_providers; pub mod list_authenticators; pub mod list_keys; +pub mod delete_client; +pub mod list_clients; pub mod psa_generate_random; pub mod psa_raw_key_agreement; @@ -47,6 +49,10 @@ pub enum NativeOperation { ListAuthenticators(list_authenticators::Operation), /// ListKeys operation ListKeys(list_keys::Operation), + /// ListClients operation + ListClients(list_clients::Operation), + /// DeleteClient operation + DeleteClient(delete_client::Operation), /// Ping operation Ping(ping::Operation), /// PsaGenerateKey operation @@ -99,6 +105,8 @@ impl NativeOperation { NativeOperation::ListProviders(_) => Opcode::ListProviders, NativeOperation::ListAuthenticators(_) => Opcode::ListAuthenticators, NativeOperation::ListKeys(_) => Opcode::ListKeys, + NativeOperation::ListClients(_) => Opcode::ListClients, + NativeOperation::DeleteClient(_) => Opcode::DeleteClient, NativeOperation::PsaAsymmetricEncrypt(_) => Opcode::PsaAsymmetricEncrypt, NativeOperation::PsaAsymmetricDecrypt(_) => Opcode::PsaAsymmetricDecrypt, NativeOperation::PsaAeadEncrypt(_) => Opcode::PsaAeadEncrypt, @@ -121,6 +129,10 @@ pub enum NativeResult { ListAuthenticators(list_authenticators::Result), /// ListKeys result ListKeys(list_keys::Result), + /// ListClients result + ListClients(list_clients::Result), + /// DeleteClient result + DeleteClient(delete_client::Result), /// Ping result Ping(ping::Result), /// PsaGenerateKey result @@ -173,6 +185,8 @@ impl NativeResult { NativeResult::ListProviders(_) => Opcode::ListProviders, NativeResult::ListAuthenticators(_) => Opcode::ListAuthenticators, NativeResult::ListKeys(_) => Opcode::ListKeys, + NativeResult::ListClients(_) => Opcode::ListClients, + NativeResult::DeleteClient(_) => Opcode::DeleteClient, NativeResult::PsaAsymmetricEncrypt(_) => Opcode::PsaAsymmetricEncrypt, NativeResult::PsaAsymmetricDecrypt(_) => Opcode::PsaAsymmetricDecrypt, NativeResult::PsaAeadEncrypt(_) => Opcode::PsaAeadEncrypt, @@ -238,6 +252,18 @@ impl From for NativeOperation { } } +impl From for NativeOperation { + fn from(op: list_clients::Operation) -> Self { + NativeOperation::ListClients(op) + } +} + +impl From for NativeOperation { + fn from(op: delete_client::Operation) -> Self { + NativeOperation::DeleteClient(op) + } +} + impl From for NativeOperation { fn from(op: ping::Operation) -> Self { NativeOperation::Ping(op) @@ -357,6 +383,18 @@ impl From for NativeResult { } } +impl From for NativeResult { + fn from(op: list_clients::Result) -> Self { + NativeResult::ListClients(op) + } +} + +impl From for NativeResult { + fn from(op: delete_client::Result) -> Self { + NativeResult::DeleteClient(op) + } +} + impl From for NativeResult { fn from(op: ping::Result) -> Self { NativeResult::Ping(op) diff --git a/src/operations_protobuf/convert_delete_client.rs b/src/operations_protobuf/convert_delete_client.rs new file mode 100644 index 0000000..1986412 --- /dev/null +++ b/src/operations_protobuf/convert_delete_client.rs @@ -0,0 +1,58 @@ +// Copyright 2021 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 +use super::generated_ops::delete_client::{Operation as OperationProto, Result as ResultProto}; +use crate::operations::delete_client::{Operation, Result}; + +impl From for Operation { + fn from(proto_op: OperationProto) -> Self { + Operation { + client: proto_op.client, + } + } +} + +impl From for OperationProto { + fn from(op: Operation) -> Self { + OperationProto { client: op.client } + } +} + +impl From for Result { + fn from(_proto_op: ResultProto) -> Self { + Result {} + } +} + +impl From for ResultProto { + fn from(_op: Result) -> Self { + ResultProto {} + } +} + +#[cfg(test)] +mod test { + use super::super::generated_ops::delete_client::Operation as OperationProto; + use crate::operations::delete_client::Operation; + + #[test] + fn proto_to_resp() { + let mut proto: OperationProto = Default::default(); + + proto.client = String::from("toto"); + + let resp: Operation = proto.into(); + + assert_eq!(resp.client, String::from("toto")); + } + + #[test] + fn resp_to_proto() { + let resp: Operation = Operation { + client: String::from("toto"), + }; + + let proto: OperationProto = resp.into(); + + assert_eq!(proto.client, String::from("toto")); + } +} diff --git a/src/operations_protobuf/convert_list_clients.rs b/src/operations_protobuf/convert_list_clients.rs new file mode 100644 index 0000000..fbe29e5 --- /dev/null +++ b/src/operations_protobuf/convert_list_clients.rs @@ -0,0 +1,62 @@ +// Copyright 2021 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 +use super::generated_ops::list_clients::{Operation as OperationProto, Result as ResultProto}; +use crate::operations::list_clients::{Operation, Result}; + +impl From for Operation { + fn from(_proto_op: OperationProto) -> Self { + Operation {} + } +} + +impl From for OperationProto { + fn from(_op: Operation) -> Self { + Default::default() + } +} + +impl From for Result { + fn from(proto_op: ResultProto) -> Self { + Result { + clients: proto_op.clients, + } + } +} + +impl From for ResultProto { + fn from(op: Result) -> Self { + ResultProto { + clients: op.clients, + } + } +} + +#[cfg(test)] +mod test { + use super::super::generated_ops::list_clients::Result as ResultProto; + use crate::operations::list_clients::Result; + + #[test] + fn proto_to_resp() { + let mut proto: ResultProto = Default::default(); + + proto.clients.push(String::from("toto")); + + let resp: Result = proto.into(); + + assert_eq!(resp.clients.len(), 1); + assert_eq!(resp.clients[0], String::from("toto")); + } + + #[test] + fn resp_to_proto() { + let resp: Result = Result { + clients: vec![String::from("toto")], + }; + + let proto: ResultProto = resp.into(); + + assert_eq!(proto.clients.len(), 1); + assert_eq!(proto.clients[0], String::from("toto")); + } +} diff --git a/src/operations_protobuf/generated_ops.rs b/src/operations_protobuf/generated_ops.rs index 1672218..7778b89 100644 --- a/src/operations_protobuf/generated_ops.rs +++ b/src/operations_protobuf/generated_ops.rs @@ -30,6 +30,8 @@ include_protobuf_as_module!(list_opcodes); include_protobuf_as_module!(list_providers); include_protobuf_as_module!(list_authenticators); include_protobuf_as_module!(list_keys); +include_protobuf_as_module!(list_clients); +include_protobuf_as_module!(delete_client); include_protobuf_as_module!(ping); include_protobuf_as_module!(psa_key_attributes); include_protobuf_as_module!(psa_algorithm); @@ -143,6 +145,10 @@ empty_clear_message!(list_authenticators::Operation); empty_clear_message!(list_authenticators::Result); empty_clear_message!(list_keys::Operation); empty_clear_message!(list_keys::Result); +empty_clear_message!(list_clients::Operation); +empty_clear_message!(list_clients::Result); +empty_clear_message!(delete_client::Operation); +empty_clear_message!(delete_client::Result); empty_clear_message!(ping::Operation); empty_clear_message!(ping::Result); empty_clear_message!(psa_destroy_key::Operation); @@ -270,4 +276,4 @@ impl ClearProtoMessage for psa_raw_key_agreement::Result { fn clear_message(&mut self) { self.shared_secret.zeroize(); } -} \ No newline at end of file +} diff --git a/src/operations_protobuf/mod.rs b/src/operations_protobuf/mod.rs index 3d0ac2f..965ee81 100644 --- a/src/operations_protobuf/mod.rs +++ b/src/operations_protobuf/mod.rs @@ -19,6 +19,8 @@ mod convert_list_providers; mod convert_list_opcodes; mod convert_list_authenticators; mod convert_list_keys; +mod convert_list_clients; +mod convert_delete_client; mod convert_psa_asymmetric_encrypt; mod convert_psa_asymmetric_decrypt; mod convert_psa_aead_encrypt; @@ -34,7 +36,9 @@ use crate::operations::{Convert, NativeOperation, NativeResult}; use crate::requests::{ request::RequestBody, response::ResponseBody, BodyType, Opcode, ResponseStatus, Result, }; +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; use generated_ops::list_keys as list_keys_proto; use generated_ops::list_opcodes as list_opcodes_proto; use generated_ops::list_providers as list_providers_proto; @@ -109,6 +113,14 @@ impl Convert for ProtobufConverter { body.bytes(), list_keys_proto::Operation ))), + Opcode::ListClients => Ok(NativeOperation::ListClients(wire_to_native!( + body.bytes(), + list_clients_proto::Operation + ))), + Opcode::DeleteClient => Ok(NativeOperation::DeleteClient(wire_to_native!( + body.bytes(), + delete_client_proto::Operation + ))), Opcode::Ping => Ok(NativeOperation::Ping(wire_to_native!( body.bytes(), ping_proto::Operation @@ -189,6 +201,12 @@ impl Convert for ProtobufConverter { operation, list_keys_proto::Operation ))), + NativeOperation::ListClients(operation) => Ok(RequestBody::from_bytes( + native_to_wire!(operation, list_clients_proto::Operation), + )), + NativeOperation::DeleteClient(operation) => Ok(RequestBody::from_bytes( + native_to_wire!(operation, delete_client_proto::Operation), + )), NativeOperation::Ping(operation) => Ok(RequestBody::from_bytes(native_to_wire!( operation, ping_proto::Operation @@ -259,6 +277,14 @@ impl Convert for ProtobufConverter { body.bytes(), list_keys_proto::Result ))), + Opcode::ListClients => Ok(NativeResult::ListClients(wire_to_native!( + body.bytes(), + list_clients_proto::Result + ))), + Opcode::DeleteClient => Ok(NativeResult::DeleteClient(wire_to_native!( + body.bytes(), + delete_client_proto::Result + ))), Opcode::Ping => Ok(NativeResult::Ping(wire_to_native!( body.bytes(), ping_proto::Result @@ -341,6 +367,14 @@ impl Convert for ProtobufConverter { result, list_keys_proto::Result ))), + NativeResult::ListClients(result) => Ok(ResponseBody::from_bytes(native_to_wire!( + result, + list_clients_proto::Result + ))), + NativeResult::DeleteClient(result) => Ok(ResponseBody::from_bytes(native_to_wire!( + result, + delete_client_proto::Result + ))), NativeResult::Ping(result) => Ok(ResponseBody::from_bytes(native_to_wire!( result, ping_proto::Result diff --git a/src/requests/mod.rs b/src/requests/mod.rs index f9c14b7..9678007 100644 --- a/src/requests/mod.rs +++ b/src/requests/mod.rs @@ -115,8 +115,12 @@ pub enum Opcode { PsaAeadDecrypt = 0x0012, /// PsaRawKeyAgreement operation PsaRawKeyAgreement = 0x0013, - /// ListKeys operations + /// ListKeys operation ListKeys = 0x001A, + /// ListClients operation (admin operation) + ListClients = 0x001B, + /// DeleteClient operation (admin operation) + DeleteClient = 0x001C, } impl Opcode { @@ -124,26 +128,56 @@ impl Opcode { pub fn is_core(&self) -> bool { // match to ensure exhaustivity when a new opcode is added match self { - Opcode::Ping => true, - Opcode::ListProviders => true, - Opcode::ListOpcodes => true, - Opcode::ListAuthenticators => true, - Opcode::ListKeys => true, - Opcode::PsaGenerateKey => false, - Opcode::PsaDestroyKey => false, - Opcode::PsaSignHash => false, - Opcode::PsaVerifyHash => false, - Opcode::PsaImportKey => false, - Opcode::PsaExportPublicKey => false, - Opcode::PsaAsymmetricEncrypt => false, - Opcode::PsaAsymmetricDecrypt => false, - Opcode::PsaExportKey => false, - Opcode::PsaGenerateRandom => false, - Opcode::PsaHashCompute => false, - Opcode::PsaHashCompare => false, - Opcode::PsaAeadEncrypt => false, - Opcode::PsaAeadDecrypt => false, - Opcode::PsaRawKeyAgreement => false, + Opcode::Ping + | Opcode::ListProviders + | Opcode::ListOpcodes + | Opcode::ListAuthenticators + | Opcode::ListKeys + | Opcode::ListClients + | Opcode::DeleteClient => true, + Opcode::PsaGenerateKey + | Opcode::PsaDestroyKey + | Opcode::PsaSignHash + | Opcode::PsaVerifyHash + | Opcode::PsaImportKey + | Opcode::PsaExportPublicKey + | Opcode::PsaAsymmetricEncrypt + | Opcode::PsaAsymmetricDecrypt + | Opcode::PsaExportKey + | Opcode::PsaGenerateRandom + | Opcode::PsaHashCompute + | Opcode::PsaHashCompare + | Opcode::PsaAeadEncrypt + | Opcode::PsaAeadDecrypt + | Opcode::PsaRawKeyAgreement => false, + } + } + + /// Check if an opcode is an admin operation + pub fn is_admin(&self) -> bool { + // match to ensure exhaustivity when a new opcode is added + match self { + Opcode::ListClients | Opcode::DeleteClient => true, + Opcode::Ping + | Opcode::ListProviders + | Opcode::ListOpcodes + | Opcode::ListAuthenticators + | Opcode::ListKeys + | Opcode::PsaGenerateKey + | Opcode::PsaDestroyKey + | Opcode::PsaSignHash + | Opcode::PsaVerifyHash + | Opcode::PsaImportKey + | Opcode::PsaExportPublicKey + | Opcode::PsaAsymmetricEncrypt + | Opcode::PsaAsymmetricDecrypt + | Opcode::PsaExportKey + | Opcode::PsaGenerateRandom + | Opcode::PsaHashCompute + | Opcode::PsaHashCompare + | Opcode::PsaAeadEncrypt + | Opcode::PsaAeadDecrypt + | Opcode::PsaRawKeyAgreement => false, } } @@ -177,4 +211,6 @@ fn check_opcode_nature() { assert!(Opcode::ListKeys.is_core()); assert!(!Opcode::ListKeys.is_crypto()); assert!(Opcode::PsaGenerateKey.is_crypto()); + assert!(Opcode::ListClients.is_admin()); + assert!(!Opcode::PsaGenerateKey.is_admin()); } diff --git a/src/requests/response_status.rs b/src/requests/response_status.rs index ed02eb1..c504ae6 100644 --- a/src/requests/response_status.rs +++ b/src/requests/response_status.rs @@ -56,6 +56,8 @@ pub enum ResponseStatus { NotAuthenticated = 19, /// Request length specified in the header is above defined limit BodySizeExceedsLimit = 20, + /// The operation requires admin privilege + AdminOperation = 21, /// An error occurred that does not correspond to any defined failure cause PsaErrorGenericError = 1132, /// The requested operation or a parameter is not supported by this implementation @@ -178,6 +180,9 @@ impl fmt::Display for ResponseStatus { "request length specified in the header is above defined limit" ) } + ResponseStatus::AdminOperation => { + write!(f, "the operation requires admin privilege") + } ResponseStatus::PsaErrorGenericError => { write!( f,