xref: /aosp_15_r20/system/secretkeeper/comm/src/wire.rs (revision 3f8e9d82f4020c68ad19a99fc5fdc1fc90b79379)
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