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 GetSecretkeeperIdentity,
41 }
42
43 impl PerformOpReq {
code(&self) -> OpCode44 pub fn code(&self) -> OpCode {
45 match self {
46 Self::SecretManagement(_) => OpCode::SecretManagement,
47 Self::DeleteIds(_) => OpCode::DeleteIds,
48 Self::DeleteAll => OpCode::DeleteAll,
49 Self::GetSecretkeeperIdentity => OpCode::GetSecretkeeperIdentity,
50 }
51 }
52 }
53
54 impl AsCborValue for PerformOpReq {
to_cbor_value(self) -> Result<Value, CoseError>55 fn to_cbor_value(self) -> Result<Value, CoseError> {
56 Ok(Value::Array(match self {
57 Self::SecretManagement(encrypt0) => {
58 vec![OpCode::SecretManagement.to_cbor_value()?, Value::Bytes(encrypt0)]
59 }
60 Self::DeleteIds(ids) => {
61 vec![
62 OpCode::DeleteIds.to_cbor_value()?,
63 Value::Array(
64 ids.into_iter().map(|id| Value::Bytes(id.to_vec())).collect::<Vec<Value>>(),
65 ),
66 ]
67 }
68 Self::DeleteAll => vec![OpCode::DeleteAll.to_cbor_value()?, Value::Null],
69 Self::GetSecretkeeperIdentity => {
70 vec![OpCode::GetSecretkeeperIdentity.to_cbor_value()?, Value::Null]
71 }
72 }))
73 }
74
from_cbor_value(value: Value) -> Result<Self, CoseError>75 fn from_cbor_value(value: Value) -> Result<Self, CoseError> {
76 let mut a = match value {
77 Value::Array(a) if a.len() == 2 => a,
78 _ => return cbor_type_error(&value, "arr len 2"),
79 };
80 let val = a.remove(1);
81 let code = OpCode::from_cbor_value(a.remove(0))?;
82 Ok(match code {
83 OpCode::SecretManagement => Self::SecretManagement(match val {
84 Value::Bytes(b) => b,
85 _ => return cbor_type_error(&val, "bstr"),
86 }),
87 OpCode::DeleteIds => {
88 let ids = match &val {
89 Value::Array(a) => a,
90 _ => return cbor_type_error(&val, "arr"),
91 };
92 let ids = ids
93 .iter()
94 .map(|id| match &id {
95 Value::Bytes(b) => SecretId::try_from(b.as_slice())
96 .map_err(|_e| CoseError::OutOfRangeIntegerValue),
97 _ => cbor_type_error(&val, "bstr"),
98 })
99 .collect::<Result<Vec<_>, _>>()?;
100 Self::DeleteIds(ids)
101 }
102 OpCode::DeleteAll => {
103 if !val.is_null() {
104 return cbor_type_error(&val, "nil");
105 }
106 Self::DeleteAll
107 }
108 OpCode::GetSecretkeeperIdentity => {
109 if !val.is_null() {
110 return cbor_type_error(&val, "nil");
111 }
112 Self::GetSecretkeeperIdentity
113 }
114 })
115 }
116 }
117
118 impl CborSerializable for PerformOpReq {}
119
120 /// Op code value to distinguish requests.
121 #[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, N)]
122 pub enum OpCode {
123 SecretManagement = 0x10,
124 DeleteIds = 0x11,
125 DeleteAll = 0x12,
126 GetSecretkeeperIdentity = 0x13,
127 }
128
129 impl AsCborValue for OpCode {
to_cbor_value(self) -> Result<Value, CoseError>130 fn to_cbor_value(self) -> Result<Value, CoseError> {
131 Ok(Value::Integer((self as i32).into()))
132 }
133
from_cbor_value(value: Value) -> Result<Self, CoseError>134 fn from_cbor_value(value: Value) -> Result<Self, CoseError> {
135 let i = match value {
136 Value::Integer(i) => i,
137 _ => return cbor_type_error(&value, "int"),
138 };
139 let code: i32 = i.try_into().map_err(|_| CoseError::OutOfRangeIntegerValue)?;
140 OpCode::n(code).ok_or(CoseError::OutOfRangeIntegerValue)
141 }
142 }
143
144 /// Wrapper type for communicating responses between the HAL service and the TA.
145 /// This is an internal implementation detail, and is not visible on the API.
146 #[derive(Debug, Clone, PartialEq, Eq)]
147 pub enum PerformOpResponse {
148 Success(PerformOpSuccessRsp),
149 Failure(ApiError),
150 }
151
152 impl PerformOpResponse {
err_code(&self) -> AidlErrorCode153 pub fn err_code(&self) -> AidlErrorCode {
154 match self {
155 Self::Success(_) => AidlErrorCode::Ok,
156 Self::Failure(err) => err.err_code,
157 }
158 }
159 }
160
161 impl AsCborValue for PerformOpResponse {
to_cbor_value(self) -> Result<Value, CoseError>162 fn to_cbor_value(self) -> Result<Value, CoseError> {
163 Ok(match self {
164 Self::Success(rsp) => {
165 Value::Array(vec![Value::Integer(0.into()), rsp.to_cbor_value()?])
166 }
167 Self::Failure(err) => Value::Array(vec![
168 Value::Integer((err.err_code as i32).into()),
169 Value::Text(err.msg),
170 ]),
171 })
172 }
173
from_cbor_value(value: Value) -> Result<Self, CoseError>174 fn from_cbor_value(value: Value) -> Result<Self, CoseError> {
175 let mut a = match value {
176 Value::Array(a) if a.len() == 2 => a,
177 _ => return cbor_type_error(&value, "arr len 2"),
178 };
179 let val = a.remove(1);
180 let err_code =
181 a.remove(0).as_integer().ok_or(CoseError::UnexpectedItem("non-int", "int"))?;
182 let err_code: i32 = err_code.try_into().map_err(|_| CoseError::OutOfRangeIntegerValue)?;
183 Ok(match err_code {
184 0 => Self::Success(PerformOpSuccessRsp::from_cbor_value(val)?),
185 err_code => {
186 let msg = match val {
187 Value::Text(t) => t,
188 _ => return cbor_type_error(&val, "tstr"),
189 };
190 let err_code = AidlErrorCode::n(err_code).unwrap_or(AidlErrorCode::InternalError);
191 Self::Failure(ApiError { err_code, msg })
192 }
193 })
194 }
195 }
196
197 impl CborSerializable for PerformOpResponse {}
198
199 /// Inner response type holding the result of a successful request.
200 #[derive(Debug, Clone, PartialEq, Eq)]
201 pub enum PerformOpSuccessRsp {
202 ProtectedResponse(Vec<u8>),
203 Empty,
204 }
205
206 impl AsCborValue for PerformOpSuccessRsp {
to_cbor_value(self) -> Result<Value, CoseError>207 fn to_cbor_value(self) -> Result<Value, CoseError> {
208 Ok(match self {
209 Self::ProtectedResponse(data) => Value::Bytes(data),
210 Self::Empty => Value::Null,
211 })
212 }
213
from_cbor_value(value: Value) -> Result<Self, CoseError>214 fn from_cbor_value(value: Value) -> Result<Self, CoseError> {
215 match value {
216 Value::Bytes(data) => Ok(Self::ProtectedResponse(data)),
217 Value::Null => Ok(Self::Empty),
218 _ => cbor_type_error(&value, "bstr/nil"),
219 }
220 }
221 }
222
223 impl CborSerializable for PerformOpSuccessRsp {}
224
225 /// Return an error indicating that an unexpected CBOR type was encountered.
cbor_type_error<T>(got: &Value, want: &'static str) -> Result<T, CoseError>226 pub fn cbor_type_error<T>(got: &Value, want: &'static str) -> Result<T, CoseError> {
227 let got = match got {
228 Value::Integer(_) => "int",
229 Value::Bytes(_) => "bstr",
230 Value::Text(_) => "tstr",
231 Value::Array(_) => "array",
232 Value::Map(_) => "map",
233 Value::Tag(_, _) => "tag",
234 Value::Float(_) => "float",
235 Value::Bool(_) => "bool",
236 Value::Null => "null",
237 _ => "unknown",
238 };
239 Err(CoseError::UnexpectedItem(got, want))
240 }
241
242 /// Identifier for a secret
243 pub type SecretId = [u8; 64];
244
245 /// Error information reported visibly on the external API.
246 #[derive(Debug, Clone, PartialEq, Eq)]
247 pub struct ApiError {
248 pub err_code: AidlErrorCode,
249 pub msg: String,
250 }
251
252 /// Error codes emitted as service specific errors at the HAL.
253 /// Keep in sync with the ERROR_ codes in:
254 /// hardware/interfaces/security/secretkeeper/aidl/
255 /// android/hardware/security/secretkeeper/ISecretkeeper.aidl
256 #[derive(Debug, Clone, Copy, PartialEq, Eq, N)]
257 pub enum AidlErrorCode {
258 Ok = 0,
259 UnknownKeyId = 1,
260 InternalError = 2,
261 RequestMalformed = 3,
262 }
263