Merge "secretkeeper_comm library: for Sk & client impl" into main
diff --git a/TEST_MAPPING b/TEST_MAPPING
index a9193d7..6983fde 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -34,6 +34,9 @@
     },
     {
       "name": "libapkzip.test"
+    },
+    {
+      "name": "libsecretkeeper_comm.test"
     }
   ],
   "avf-postsubmit": [
diff --git a/secretkeeper/comm/Android.bp b/secretkeeper/comm/Android.bp
new file mode 100644
index 0000000..cb3e713
--- /dev/null
+++ b/secretkeeper/comm/Android.bp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_defaults {
+    name: "libsecretkeeper_comm.defaults",
+    crate_name: "secretkeeper_comm",
+    defaults: ["avf_build_flags_rust"],
+    edition: "2021",
+    lints: "android",
+    rustlibs: [
+        "libciborium",
+        "libcoset",
+    ],
+    proc_macros: ["libenumn"],
+    vendor_available: true,
+}
+
+rust_library {
+    name: "libsecretkeeper_comm_nostd",
+    defaults: ["libsecretkeeper_comm.defaults"],
+    srcs: ["src/lib.rs"],
+}
+
+rust_test {
+    name: "libsecretkeeper_comm.test",
+    defaults: [
+        "libsecretkeeper_comm.defaults",
+        "rdroidtest.defaults",
+    ],
+    srcs: ["tests/*.rs"],
+    test_suites: ["general-tests"],
+    rustlibs: [
+        "libsecretkeeper_comm_nostd",
+    ],
+}
diff --git a/secretkeeper/comm/src/cbor_convert.rs b/secretkeeper/comm/src/cbor_convert.rs
new file mode 100644
index 0000000..ab6ca3f
--- /dev/null
+++ b/secretkeeper/comm/src/cbor_convert.rs
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Implements various useful CBOR conversion method.
+
+use crate::data_types::error::Error;
+use alloc::vec::Vec;
+use ciborium::Value;
+
+/// Decodes the provided binary CBOR-encoded value and returns a
+/// [`ciborium::Value`] struct wrapped in Result.
+pub fn value_from_bytes(mut bytes: &[u8]) -> Result<Value, Error> {
+    let value = ciborium::de::from_reader(&mut bytes).map_err(|_| Error::ConversionError)?;
+    // Ciborium tries to read one Value, but doesn't care if there is trailing data after it. We do
+    if !bytes.is_empty() {
+        return Err(Error::ConversionError);
+    }
+    Ok(value)
+}
+
+/// Encodes a [`ciborium::Value`] into bytes.
+pub fn value_to_bytes(value: &Value) -> Result<Vec<u8>, Error> {
+    let mut bytes: Vec<u8> = Vec::new();
+    ciborium::ser::into_writer(&value, &mut bytes).map_err(|_| Error::UnexpectedError)?;
+    Ok(bytes)
+}
+
+// Useful to convert [`ciborium::Value`] to integer, we return largest integer range for
+// convenience, callers should downcast into appropriate type.
+pub fn value_to_integer(value: &Value) -> Result<i128, Error> {
+    let num = value.as_integer().ok_or(Error::ConversionError)?.into();
+    Ok(num)
+}
diff --git a/secretkeeper/comm/src/data_types/error.rs b/secretkeeper/comm/src/data_types/error.rs
new file mode 100644
index 0000000..6a5e24f
--- /dev/null
+++ b/secretkeeper/comm/src/data_types/error.rs
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Error-like data structures. See `ResponsePacketError` in the CDDL
+
+// derive(N) generates a method that is missing a docstring.
+#![allow(missing_docs)]
+
+use crate::cbor_convert::value_to_integer;
+use crate::data_types::response::Response;
+use alloc::boxed::Box;
+use alloc::vec::Vec;
+use ciborium::Value;
+use enumn::N;
+
+/// 'Error code' corresponding to successful response.
+pub const ERROR_OK: u16 = 0; // All real errors must have non-zero error_codes
+
+/// Errors from Secretkeeper API. Keep in sync with `ErrorCode` defined for Secretkeeper HAL
+/// at SecretManagement.cddl
+#[derive(Clone, Copy, Debug, Eq, N, PartialEq)]
+pub enum SecretkeeperError {
+    // This is the Error code used if no other error codes explains the issue.
+    UnexpectedServerError = 1,
+    // Indicates the Request was malformed & hence couldn't be served.
+    RequestMalformed = 2,
+    // TODO(b/291228655): Add other errors such as DicePolicyError.
+}
+
+// [`SecretkeeperError`] is a valid [`Response`] type.
+// For more information see `ErrorCode` in SecretManagement.cddl alongside ISecretkeeper.aidl
+impl Response for SecretkeeperError {
+    fn new(response_cbor: Vec<Value>) -> Result<Box<Self>, Error> {
+        // TODO(b/291228655): This method currently discards the second value in response_cbor,
+        // which contains additional human-readable context in error. Include it!
+        if response_cbor.is_empty() || response_cbor.len() > 2 {
+            return Err(Error::ResponseMalformed);
+        }
+        let error_code: u16 = value_to_integer(&response_cbor[0])?.try_into()?;
+        SecretkeeperError::n(error_code)
+            .map_or_else(|| Err(Error::ResponseMalformed), |sk_err| Ok(Box::new(sk_err)))
+    }
+
+    fn error_code(&self) -> u16 {
+        *self as u16
+    }
+}
+
+/// Errors thrown internally by the library.
+#[derive(Debug, PartialEq)]
+pub enum Error {
+    /// Request was malformed.
+    RequestMalformed,
+    /// Response received from the server was malformed.
+    ResponseMalformed,
+    /// An error happened when serializing to/from a [`Value`].
+    CborValueError,
+    /// An error happened while casting a type to different type,
+    /// including one [`Value`] type to another.
+    ConversionError,
+    /// These are unexpected errors, which should never really happen.
+    UnexpectedError,
+}
+
+impl From<ciborium::value::Error> for Error {
+    fn from(_e: ciborium::value::Error) -> Self {
+        Self::CborValueError
+    }
+}
+
+impl From<ciborium::Value> for Error {
+    fn from(_e: ciborium::Value) -> Self {
+        Self::ConversionError
+    }
+}
+
+impl From<core::num::TryFromIntError> for Error {
+    fn from(_e: core::num::TryFromIntError) -> Self {
+        Self::ConversionError
+    }
+}
diff --git a/secretkeeper/comm/src/data_types/mod.rs b/secretkeeper/comm/src/data_types/mod.rs
new file mode 100644
index 0000000..096777f
--- /dev/null
+++ b/secretkeeper/comm/src/data_types/mod.rs
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Implements the data structures specified by SecretManagement.cddl in Secretkeeper HAL.
+//!  Data structures specified by SecretManagement.cddl in Secretkeeper HAL.
+//!  Note this library must stay in sync with:
+//!      platform/hardware/interfaces/security/\
+//!      secretkeeper/aidl/android/hardware/security/secretkeeper/SecretManagement.cddl
+
+pub mod error;
+pub mod packet;
+pub mod request;
+pub mod request_response_impl;
+pub mod response;
diff --git a/secretkeeper/comm/src/data_types/packet.rs b/secretkeeper/comm/src/data_types/packet.rs
new file mode 100644
index 0000000..7a1e575
--- /dev/null
+++ b/secretkeeper/comm/src/data_types/packet.rs
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Defines the packet structures passed between functional layer & the layer below.
+
+pub use ciborium::Value;
+
+use crate::cbor_convert::{value_from_bytes, value_to_bytes, value_to_integer};
+use crate::data_types::error::Error;
+use crate::data_types::error::ERROR_OK;
+use crate::data_types::request_response_impl::Opcode;
+use alloc::vec::Vec;
+
+/// Encapsulate Request-like data that functional layer operates on. All structures
+/// that implements `data_types::request::Request` can be serialized to [`ResponsePacket`].
+/// Similarly all [`RequestPacket`] can be deserialized to concrete Requests.
+/// Keep in sync with HAL spec (in particular RequestPacket):
+///     security/secretkeeper/aidl/android/hardware/security/secretkeeper/SecretManagement.cddl
+#[derive(Clone, Debug, PartialEq)]
+pub struct RequestPacket(Vec<Value>);
+
+impl RequestPacket {
+    /// Construct a [`RequestPacket`] from array of `ciborium::Value`
+    pub fn from(request_cbor: Vec<Value>) -> Self {
+        Self(request_cbor)
+    }
+
+    /// Get the containing CBOR. This can be used for getting concrete response objects.
+    /// Keep in sync with [`crate::data_types::request::Request::serialize_to_packet()`]
+    pub fn into_inner(self) -> Vec<Value> {
+        self.0
+    }
+
+    /// Extract [`Opcode`] corresponding to this packet. As defined in by the spec, this is
+    /// the first value in the CBOR array.
+    pub fn opcode(&self) -> Result<Opcode, Error> {
+        if self.0.is_empty() {
+            return Err(Error::RequestMalformed);
+        }
+        let num: u16 = value_to_integer(&self.0[0])?.try_into()?;
+
+        Opcode::n(num).ok_or(Error::RequestMalformed)
+    }
+
+    /// Serialize the [`ResponsePacket`] to bytes
+    pub fn into_bytes(self) -> Result<Vec<u8>, Error> {
+        value_to_bytes(&Value::Array(self.0))
+    }
+
+    /// Deserialize the bytes into [`ResponsePacket`]
+    pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
+        Ok(RequestPacket(value_from_bytes(bytes)?.into_array()?))
+    }
+}
+
+/// Encapsulate Response like data that the functional layer operates on. All structures
+/// that implements `data_types::response::Response` can be serialized to [`ResponsePacket`].
+/// Similarly all [`ResponsePacket`] can be deserialized to concrete Response.
+#[derive(Clone, Debug, PartialEq)]
+pub struct ResponsePacket(Vec<Value>);
+
+impl ResponsePacket {
+    /// Construct a [`ResponsePacket`] from array of `ciborium::Value`
+    pub fn from(response_cbor: Vec<Value>) -> Self {
+        Self(response_cbor)
+    }
+
+    /// Get raw content. This can be used for getting concrete response objects.
+    /// Keep in sync with `crate::data_types::response::Response::serialize_to_packet`
+    pub fn into_inner(self) -> Vec<Value> {
+        self.0
+    }
+
+    /// A [`ResponsePacket`] encapsulates different types of responses, find which one!
+    pub fn response_type(&self) -> Result<ResponseType, Error> {
+        if self.0.is_empty() {
+            return Err(Error::ResponseMalformed);
+        }
+        let error_code: u16 = value_to_integer(&self.0[0])?.try_into()?;
+        if error_code == ERROR_OK {
+            Ok(ResponseType::Success)
+        } else {
+            Ok(ResponseType::Error)
+        }
+    }
+
+    /// Serialize the [`ResponsePacket`] to bytes
+    pub fn into_bytes(self) -> Result<Vec<u8>, Error> {
+        value_to_bytes(&Value::Array(self.0))
+    }
+
+    /// Deserialize the bytes into [`ResponsePacket`]
+    pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
+        Ok(ResponsePacket(value_from_bytes(bytes)?.into_array()?))
+    }
+}
+
+/// Responses can be different type - `Success`-like or `Error`-like.
+#[derive(Debug, Eq, PartialEq)]
+pub enum ResponseType {
+    /// Indicates successful operation. See `ResponsePacketSuccess` in SecretManagement.cddl
+    Success,
+    /// Indicate failed operation. See `ResponsePacketError` in SecretManagement.cddl
+    Error,
+}
diff --git a/secretkeeper/comm/src/data_types/request.rs b/secretkeeper/comm/src/data_types/request.rs
new file mode 100644
index 0000000..0d54bcd
--- /dev/null
+++ b/secretkeeper/comm/src/data_types/request.rs
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Defines the shared behaviour of all request like data structures.
+
+use crate::data_types::error::Error;
+use crate::data_types::packet::RequestPacket;
+use crate::data_types::request_response_impl::Opcode;
+use alloc::boxed::Box;
+use alloc::vec::Vec;
+use ciborium::Value;
+
+/// Collection of methods defined for Secretkeeper's request-like data structures,
+/// e.g. `GetVersionRequestPacket` in the HAL spec.
+///
+/// Keep in sync with SecretManagement.cddl, in particular `RequestPacket` type.
+pub trait Request {
+    /// [`Opcode`] of the request: Each Request type is associated with an opcode. See `Opcode` in
+    /// SecretManagement.cddl.
+    const OPCODE: Opcode;
+
+    /// Constructor of the [`Request`] object. Implementation of this constructor should check
+    /// the args' type adheres to the HAL spec.
+    ///
+    /// # Arguments
+    /// * `args` - The vector of arguments associated with this request. Each argument is a
+    ///   `ciborium::Value` type. See `Params` in `RequestPacket` in SecretManagement.cddl
+    fn new(args: Vec<Value>) -> Result<Box<Self>, Error>;
+
+    /// Get the 'arguments' of this request.
+    fn args(&self) -> Vec<Value>;
+
+    /// Serialize the request to a [`RequestPacket`], which, as per SecretManagement.cddl is:
+    /// ```
+    ///      RequestPacket<Opcode, Params> = [
+    ///         Opcode,
+    ///         Params
+    ///      ]
+    /// ```
+    fn serialize_to_packet(&self) -> RequestPacket {
+        let mut res = self.args();
+        res.insert(0, Value::from(Self::OPCODE as u16));
+        RequestPacket::from(res)
+    }
+
+    /// Construct the [`Request`] struct from given [`RequestPacket`].
+    fn deserialize_from_packet(packet: RequestPacket) -> Result<Box<Self>, Error> {
+        let mut req = packet.into_inner();
+        if req.get(0) != Some(&Value::from(Self::OPCODE as u16)) {
+            return Err(Error::RequestMalformed);
+        }
+        req.remove(0);
+        Self::new(req)
+    }
+}
diff --git a/secretkeeper/comm/src/data_types/request_response_impl.rs b/secretkeeper/comm/src/data_types/request_response_impl.rs
new file mode 100644
index 0000000..a7d29cc
--- /dev/null
+++ b/secretkeeper/comm/src/data_types/request_response_impl.rs
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Implementation of request & response like data structures.
+
+// derive(N) generates a method that is missing a docstring.
+#![allow(missing_docs)]
+
+use crate::cbor_convert::value_to_integer;
+use crate::data_types::error::Error;
+use crate::data_types::error::ERROR_OK;
+use crate::data_types::request::Request;
+use crate::data_types::response::Response;
+use alloc::boxed::Box;
+use alloc::vec;
+use alloc::vec::Vec;
+use ciborium::Value;
+use enumn::N;
+
+/// Set of all possible `Opcode` supported by SecretManagement API of the HAL.
+/// See `Opcode` in SecretManagement.cddl
+#[derive(Clone, Copy, Debug, N, PartialEq)]
+#[non_exhaustive]
+pub enum Opcode {
+    /// Get version of the SecretManagement API.
+    GetVersion = 1,
+    /// Store a secret
+    StoreSecret = 2,
+    /// Get the secret
+    GetSecret = 3,
+}
+
+/// Corresponds to `GetVersionRequestPacket` defined in SecretManagement.cddl
+#[derive(Debug, Eq, PartialEq)]
+pub struct GetVersionRequest;
+
+impl Request for GetVersionRequest {
+    const OPCODE: Opcode = Opcode::GetVersion;
+
+    fn new(args: Vec<Value>) -> Result<Box<Self>, Error> {
+        if !args.is_empty() {
+            return Err(Error::RequestMalformed);
+        }
+        Ok(Box::new(Self))
+    }
+
+    fn args(&self) -> Vec<Value> {
+        Vec::new()
+    }
+}
+
+/// Success response corresponding to `GetVersionResponsePacket`.
+#[derive(Debug, Eq, PartialEq)]
+pub struct GetVersionResponse {
+    /// Version of SecretManagement API
+    version: u64,
+}
+
+impl GetVersionResponse {
+    pub fn new(version: u64) -> Self {
+        Self { version }
+    }
+    pub fn version(&self) -> u64 {
+        self.version
+    }
+}
+
+impl Response for GetVersionResponse {
+    fn new(res: Vec<Value>) -> Result<Box<Self>, Error> {
+        if res.len() != 2 {
+            return Err(Error::ResponseMalformed);
+        }
+        let error_code: u16 = value_to_integer(&res[0])?.try_into()?;
+        if error_code != ERROR_OK {
+            return Err(Error::ResponseMalformed);
+        }
+        let version: u64 = value_to_integer(&res[1])?.try_into()?;
+        Ok(Box::new(Self::new(version)))
+    }
+
+    fn result(&self) -> Vec<Value> {
+        vec![self.version.into()]
+    }
+}
diff --git a/secretkeeper/comm/src/data_types/response.rs b/secretkeeper/comm/src/data_types/response.rs
new file mode 100644
index 0000000..e975ebc
--- /dev/null
+++ b/secretkeeper/comm/src/data_types/response.rs
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Defines the shared behaviour of all response like data structures.
+
+use crate::data_types::error::{Error, ERROR_OK};
+use crate::data_types::packet::ResponsePacket;
+use alloc::boxed::Box;
+use alloc::vec::Vec;
+use ciborium::Value;
+
+/// Shared behaviour of all Secretkeeper's response-like data structures,
+/// e.g. `GetVersionResponsePacket`. Note - A valid [`Response`] can be error as well, like
+/// `SecretkeeperError::RequestMalformed`.
+///
+/// Keep in sync with SecretManagement.cddl, in particular `ResponsePacket` type.
+pub trait Response {
+    /// Constructor of the Response object.
+    /// # Arguments
+    /// * `response_cbor`: A vector of `[ciborium::Value]` such that:
+    /// ```
+    ///     For success-like responses:
+    ///         ResponsePacketSuccess = [
+    ///             0,                          ; Indicates successful Response
+    ///             result : Result
+    ///         ]
+    ///     For error responses:
+    ///         ResponsePacketError = [
+    ///             error_code: ErrorCode,      ; Indicate the error
+    ///             error_message: tstr         ; Additional human-readable context
+    ///         ]
+    /// ```
+    /// See ResponsePacket<Result> in SecretManagement.cddl alongside ISecretkeeper.aidl
+    fn new(response_cbor: Vec<Value>) -> Result<Box<Self>, Error>;
+
+    /// The result in the `Response`. By default this is empty, but [`Response`] structures like
+    /// `GetVersionResponse` must overwrite these to return the expected non-empty result.
+    fn result(&self) -> Vec<Value> {
+        Vec::new()
+    }
+
+    /// Error code corresponding to the response. The default value is 0 but that will work only
+    /// for successful responses. Error-like response structures must overwrite this method.
+    fn error_code(&self) -> u16 {
+        ERROR_OK // Indicates success
+    }
+
+    /// Serialize the response to a [`ResponsePacket`].
+    fn serialize_to_packet(&self) -> ResponsePacket {
+        let mut res = self.result();
+        res.insert(0, Value::from(self.error_code()));
+        ResponsePacket::from(res)
+    }
+
+    /// Construct the response struct from given [`ResponsePacket`].
+    fn deserialize_from_packet(packet: ResponsePacket) -> Result<Box<Self>, Error> {
+        let res = packet.into_inner();
+        // Empty response packet is not allowed, all responses in Secretkeeper HAL at least
+        // have `error_code` or '0'; so throw an error!
+        if res.is_empty() {
+            return Err(Error::ResponseMalformed);
+        }
+        Self::new(res)
+    }
+}
diff --git a/secretkeeper/comm/src/lib.rs b/secretkeeper/comm/src/lib.rs
new file mode 100644
index 0000000..9a10ac0
--- /dev/null
+++ b/secretkeeper/comm/src/lib.rs
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! This library exposes data structures and methods that can be used by Secretkeeper HAL & client
+//! implementation. This is compatible with Secretkeeper HAL specification.
+
+#![no_std]
+extern crate alloc;
+
+mod cbor_convert;
+pub mod data_types;
diff --git a/secretkeeper/comm/tests/data_types.rs b/secretkeeper/comm/tests/data_types.rs
new file mode 100644
index 0000000..68964fd
--- /dev/null
+++ b/secretkeeper/comm/tests/data_types.rs
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//! Unit tests for testing serialization & deserialization of exported data_types.
+
+use ciborium::Value;
+use secretkeeper_comm::data_types::error::{Error, SecretkeeperError, ERROR_OK};
+use secretkeeper_comm::data_types::packet::{RequestPacket, ResponsePacket, ResponseType};
+use secretkeeper_comm::data_types::request::Request;
+use secretkeeper_comm::data_types::request_response_impl::Opcode;
+use secretkeeper_comm::data_types::request_response_impl::{GetVersionRequest, GetVersionResponse};
+use secretkeeper_comm::data_types::response::Response;
+
+#[cfg(test)]
+rdroidtest::test_main!();
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use rdroidtest::test;
+
+    test!(request_serialization_deserialization);
+    fn request_serialization_deserialization() {
+        let req = GetVersionRequest {};
+        let packet = req.serialize_to_packet();
+        assert_eq!(packet.opcode().unwrap(), Opcode::GetVersion);
+        assert_eq!(
+            RequestPacket::from_bytes(&packet.clone().into_bytes().unwrap()).unwrap(),
+            packet
+        );
+        let req_deserialized = *GetVersionRequest::deserialize_from_packet(packet).unwrap();
+        assert_eq!(req, req_deserialized);
+    }
+
+    test!(success_response_serialization_deserialization);
+    fn success_response_serialization_deserialization() {
+        let response = GetVersionResponse::new(1);
+        let packet = response.serialize_to_packet();
+        assert_eq!(packet.response_type().unwrap(), ResponseType::Success);
+        assert_eq!(
+            ResponsePacket::from_bytes(&packet.clone().into_bytes().unwrap()).unwrap(),
+            packet
+        );
+        let response_deserialized = *GetVersionResponse::deserialize_from_packet(packet).unwrap();
+        assert_eq!(response, response_deserialized);
+    }
+
+    test!(error_response_serialization_deserialization);
+    fn error_response_serialization_deserialization() {
+        let response = SecretkeeperError::RequestMalformed;
+        let packet = response.serialize_to_packet();
+        assert_eq!(packet.response_type().unwrap(), ResponseType::Error);
+        assert_eq!(
+            ResponsePacket::from_bytes(&packet.clone().into_bytes().unwrap()).unwrap(),
+            packet
+        );
+        let response_deserialized = *SecretkeeperError::deserialize_from_packet(packet).unwrap();
+        assert_eq!(response, response_deserialized);
+    }
+
+    test!(request_creation);
+    fn request_creation() {
+        let req: GetVersionRequest = *Request::new(vec![]).unwrap();
+        assert_eq!(req, GetVersionRequest {});
+    }
+
+    test!(response_creation);
+    fn response_creation() {
+        let res: GetVersionResponse =
+            *Response::new(vec![Value::from(ERROR_OK), Value::from(5)]).unwrap();
+        assert_eq!(res.version(), 5);
+    }
+
+    test!(invalid_get_version_request_creation);
+    fn invalid_get_version_request_creation() {
+        // A request with non-zero arg is considered invalid.
+        assert_eq!(
+            <GetVersionRequest as Request>::new(vec![Value::Null]).unwrap_err(),
+            Error::RequestMalformed
+        );
+    }
+
+    test!(invalid_get_version_response_creation);
+    fn invalid_get_version_response_creation() {
+        // A response with non-zero error_code is an invalid success response.
+        assert_eq!(
+            <GetVersionResponse as Response>::new(vec![
+                Value::from(SecretkeeperError::RequestMalformed as u16),
+                Value::from(5)
+            ])
+            .unwrap_err(),
+            Error::ResponseMalformed
+        );
+
+        // A response with incorrect size of array is invalid.
+        assert_eq!(
+            <GetVersionResponse as Response>::new(vec![
+                Value::from(ERROR_OK),
+                Value::from(5),
+                Value::from(7)
+            ])
+            .unwrap_err(),
+            Error::ResponseMalformed
+        );
+
+        // A response with incorrect type is invalid.
+        <GetVersionResponse as Response>::new(vec![Value::from(ERROR_OK), Value::from("a tstr")])
+            .unwrap_err();
+    }
+
+    test!(invalid_error_response_creation);
+    fn invalid_error_response_creation() {
+        // A response with ERROR_OK(0) as the error_code is an invalid error response.
+        assert_eq!(
+            <SecretkeeperError as Response>::new(vec![Value::from(ERROR_OK)]).unwrap_err(),
+            Error::ResponseMalformed
+        );
+    }
+}
diff --git a/secretkeeper/dice_policy/src/lib.rs b/secretkeeper/dice_policy/src/lib.rs
index 2e91305..076ba3b 100644
--- a/secretkeeper/dice_policy/src/lib.rs
+++ b/secretkeeper/dice_policy/src/lib.rs
@@ -213,10 +213,10 @@
         ConstraintType::GreaterOrEqual => {
             let value_in_node = value_in_node
                 .as_integer()
-                .ok_or(anyhow!("Mismatch type: expected a cbor integer"))?;
+                .ok_or(anyhow!("Mismatch type: expected a CBOR integer"))?;
             let value_min = value_in_constraint
                 .as_integer()
-                .ok_or(anyhow!("Mismatch type: expected a cbor integer"))?;
+                .ok_or(anyhow!("Mismatch type: expected a CBOR integer"))?;
             ensure!(value_in_node >= value_min);
         }
     };
@@ -260,9 +260,9 @@
         Value::Bytes(b) => value_from_bytes(b)?
             .into_map()
             .map(Cow::Owned)
-            .map_err(|e| anyhow!("Expected a cbor map: {:?}", e)),
+            .map_err(|e| anyhow!("Expected a CBOR map: {:?}", e)),
         Value::Map(map) => Ok(Cow::Borrowed(map)),
-        _ => bail!("/Expected a cbor map {:?}", cbor_map),
+        _ => bail!("Expected a CBOR map {:?}", cbor_map),
     }
 }