1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 //! Rust types used for CBOR-encoded communication between HAL and TA,
18 //! corresponding to the schema in `comm/InternalHalTaMessages.cddl`.
19
20 #![allow(missing_docs)] // needed for `enumn::N`, sadly
21
22 use alloc::{string::String, vec, vec::Vec};
23 use ciborium::value::Value;
24 use coset::{AsCborValue, CborSerializable, CoseError};
25 use enumn::N;
26
27 /// Wrapper type for communicating requests between the HAL service and the TA.
28 /// This is an internal implementation detail, and is not visible on the API.
29 #[derive(Debug, Clone, PartialEq, Eq)]
30 pub enum PerformOpReq {
31 /// A secret management request holds a CBOR-encoded `COSE_Encrypt0`.
32 SecretManagement(Vec<u8>),
33
34 /// A (plaintext) request to delete some `SecretId`s.
35 DeleteIds(Vec<SecretId>),
36
37 /// A (plaintext) request to delete all data.
38 DeleteAll,
39 }
40
41 impl PerformOpReq {
code(&self) -> OpCode42 pub fn code(&self) -> OpCode {
43 match self {
44 Self::SecretManagement(_) => OpCode::SecretManagement,
45 Self::DeleteIds(_) => OpCode::DeleteIds,
46 Self::DeleteAll => OpCode::DeleteAll,
47 }
48 }
49 }
50
51 impl AsCborValue for PerformOpReq {
to_cbor_value(self) -> Result<Value, CoseError>52 fn to_cbor_value(self) -> Result<Value, CoseError> {
53 Ok(Value::Array(match self {
54 Self::SecretManagement(encrypt0) => {
55 vec![OpCode::SecretManagement.to_cbor_value()?, Value::Bytes(encrypt0)]
56 }
57 Self::DeleteIds(ids) => {
58 vec![
59 OpCode::DeleteIds.to_cbor_value()?,
60 Value::Array(
61 ids.into_iter().map(|id| Value::Bytes(id.to_vec())).collect::<Vec<Value>>(),
62 ),
63 ]
64 }
65 Self::DeleteAll => vec![OpCode::DeleteAll.to_cbor_value()?, Value::Null],
66 }))
67 }
68
from_cbor_value(value: Value) -> Result<Self, CoseError>69 fn from_cbor_value(value: Value) -> Result<Self, CoseError> {
70 let mut a = match value {
71 Value::Array(a) if a.len() == 2 => a,
72 _ => return cbor_type_error(&value, "arr len 2"),
73 };
74 let val = a.remove(1);
75 let code = OpCode::from_cbor_value(a.remove(0))?;
76 Ok(match code {
77 OpCode::SecretManagement => Self::SecretManagement(match val {
78 Value::Bytes(b) => b,
79 _ => return cbor_type_error(&val, "bstr"),
80 }),
81 OpCode::DeleteIds => {
82 let ids = match &val {
83 Value::Array(a) => a,
84 _ => return cbor_type_error(&val, "arr"),
85 };
86 let ids = ids
87 .iter()
88 .map(|id| match &id {
89 Value::Bytes(b) => SecretId::try_from(b.as_slice())
90 .map_err(|_e| CoseError::OutOfRangeIntegerValue),
91 _ => cbor_type_error(&val, "bstr"),
92 })
93 .collect::<Result<Vec<_>, _>>()?;
94 Self::DeleteIds(ids)
95 }
96 OpCode::DeleteAll => {
97 if !val.is_null() {
98 return cbor_type_error(&val, "nil");
99 }
100 Self::DeleteAll
101 }
102 })
103 }
104 }
105
106 impl CborSerializable for PerformOpReq {}
107
108 /// Op code value to distinguish requests.
109 #[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, N)]
110 pub enum OpCode {
111 SecretManagement = 0x10,
112 DeleteIds = 0x11,
113 DeleteAll = 0x12,
114 }
115
116 impl AsCborValue for OpCode {
to_cbor_value(self) -> Result<Value, CoseError>117 fn to_cbor_value(self) -> Result<Value, CoseError> {
118 Ok(Value::Integer((self as i32).into()))
119 }
120
from_cbor_value(value: Value) -> Result<Self, CoseError>121 fn from_cbor_value(value: Value) -> Result<Self, CoseError> {
122 let i = match value {
123 Value::Integer(i) => i,
124 _ => return cbor_type_error(&value, "int"),
125 };
126 let code: i32 = i.try_into().map_err(|_| CoseError::OutOfRangeIntegerValue)?;
127 OpCode::n(code).ok_or(CoseError::OutOfRangeIntegerValue)
128 }
129 }
130
131 /// Wrapper type for communicating responses between the HAL service and the TA.
132 /// This is an internal implementation detail, and is not visible on the API.
133 #[derive(Debug, Clone, PartialEq, Eq)]
134 pub enum PerformOpResponse {
135 Success(PerformOpSuccessRsp),
136 Failure(ApiError),
137 }
138
139 impl PerformOpResponse {
err_code(&self) -> AidlErrorCode140 pub fn err_code(&self) -> AidlErrorCode {
141 match self {
142 Self::Success(_) => AidlErrorCode::Ok,
143 Self::Failure(err) => err.err_code,
144 }
145 }
146 }
147
148 impl AsCborValue for PerformOpResponse {
to_cbor_value(self) -> Result<Value, CoseError>149 fn to_cbor_value(self) -> Result<Value, CoseError> {
150 Ok(match self {
151 Self::Success(rsp) => {
152 Value::Array(vec![Value::Integer(0.into()), rsp.to_cbor_value()?])
153 }
154 Self::Failure(err) => Value::Array(vec![
155 Value::Integer((err.err_code as i32).into()),
156 Value::Text(err.msg),
157 ]),
158 })
159 }
160
from_cbor_value(value: Value) -> Result<Self, CoseError>161 fn from_cbor_value(value: Value) -> Result<Self, CoseError> {
162 let mut a = match value {
163 Value::Array(a) if a.len() == 2 => a,
164 _ => return cbor_type_error(&value, "arr len 2"),
165 };
166 let val = a.remove(1);
167 let err_code =
168 a.remove(0).as_integer().ok_or(CoseError::UnexpectedItem("non-int", "int"))?;
169 let err_code: i32 = err_code.try_into().map_err(|_| CoseError::OutOfRangeIntegerValue)?;
170 Ok(match err_code {
171 0 => Self::Success(PerformOpSuccessRsp::from_cbor_value(val)?),
172 err_code => {
173 let msg = match val {
174 Value::Text(t) => t,
175 _ => return cbor_type_error(&val, "tstr"),
176 };
177 let err_code = AidlErrorCode::n(err_code).unwrap_or(AidlErrorCode::InternalError);
178 Self::Failure(ApiError { err_code, msg })
179 }
180 })
181 }
182 }
183
184 impl CborSerializable for PerformOpResponse {}
185
186 /// Inner response type holding the result of a successful request.
187 #[derive(Debug, Clone, PartialEq, Eq)]
188 pub enum PerformOpSuccessRsp {
189 ProtectedResponse(Vec<u8>),
190 Empty,
191 }
192
193 impl AsCborValue for PerformOpSuccessRsp {
to_cbor_value(self) -> Result<Value, CoseError>194 fn to_cbor_value(self) -> Result<Value, CoseError> {
195 Ok(match self {
196 Self::ProtectedResponse(data) => Value::Bytes(data),
197 Self::Empty => Value::Null,
198 })
199 }
200
from_cbor_value(value: Value) -> Result<Self, CoseError>201 fn from_cbor_value(value: Value) -> Result<Self, CoseError> {
202 match value {
203 Value::Bytes(data) => Ok(Self::ProtectedResponse(data)),
204 Value::Null => Ok(Self::Empty),
205 _ => cbor_type_error(&value, "bstr/nil"),
206 }
207 }
208 }
209
210 impl CborSerializable for PerformOpSuccessRsp {}
211
212 /// Return an error indicating that an unexpected CBOR type was encountered.
cbor_type_error<T>(got: &Value, want: &'static str) -> Result<T, CoseError>213 pub fn cbor_type_error<T>(got: &Value, want: &'static str) -> Result<T, CoseError> {
214 let got = match got {
215 Value::Integer(_) => "int",
216 Value::Bytes(_) => "bstr",
217 Value::Text(_) => "tstr",
218 Value::Array(_) => "array",
219 Value::Map(_) => "map",
220 Value::Tag(_, _) => "tag",
221 Value::Float(_) => "float",
222 Value::Bool(_) => "bool",
223 Value::Null => "null",
224 _ => "unknown",
225 };
226 Err(CoseError::UnexpectedItem(got, want))
227 }
228
229 /// Identifier for a secret
230 pub type SecretId = [u8; 64];
231
232 /// Error information reported visibly on the external API.
233 #[derive(Debug, Clone, PartialEq, Eq)]
234 pub struct ApiError {
235 pub err_code: AidlErrorCode,
236 pub msg: String,
237 }
238
239 /// Error codes emitted as service specific errors at the HAL.
240 /// Keep in sync with the ERROR_ codes in:
241 /// hardware/interfaces/security/secretkeeper/aidl/
242 /// android/hardware/security/secretkeeper/ISecretkeeper.aidl
243 #[derive(Debug, Clone, Copy, PartialEq, Eq, N)]
244 pub enum AidlErrorCode {
245 Ok = 0,
246 UnknownKeyId = 1,
247 InternalError = 2,
248 RequestMalformed = 3,
249 }
250