1 /*
2 * Copyright (C) 2025 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 //! Service library for implementing hwbcc servers in Rust
18
19 use crate::{
20 hwbcc_req_hdr, hwbcc_req_sign_data, BccCmd, BccMsg, HwBccError, HwBccMode, HwBccResponse,
21 SigningAlgorithm, HWBCC_MAX_AAD_SIZE, HWBCC_MAX_DATA_TO_SIGN_SIZE,
22 };
23 use alloc::rc::Rc;
24 use core::mem::size_of;
25 use num_traits::FromPrimitive;
26 use tipc::{ConnectResult, Deserialize, Handle, MessageResult, PortCfg, Service, TipcError, Uuid};
27 use trusty_std::alloc::TryAllocFrom;
28 use trusty_sys::Error;
29 use zerocopy::FromBytes;
30
31 const HWBCC_MAX_MESSAGE_SIZE: usize = size_of::<hwbcc_req_hdr>()
32 + size_of::<hwbcc_req_sign_data>()
33 + HWBCC_MAX_AAD_SIZE as usize
34 + HWBCC_MAX_DATA_TO_SIGN_SIZE as usize;
35
36 pub struct RequestContext {
37 pub peer: Uuid,
38 }
39
40 /// A raw buffer that holds a serialized `BccMsg` and allows
41 /// for extraction of a `BccMsg` after deserialization.
42 ///
43 /// Deserialization itself performs no validation and only
44 /// copies the input buffer into the `RawBccMsgBuffer`. All
45 /// validation occurs when calling `to_req_msg`.
46 ///
47 /// This approach is needed because `BccMsg` is implemented
48 /// to support serializing from borrowed data in the client.
49 /// As such, it specifies an explicit lifetime, which is not
50 /// supported by the `Message` type of the `Service` trait.
51 pub struct RawBccMsgBuffer(Vec<u8>);
52
53 impl RawBccMsgBuffer {
54 #[allow(dead_code)]
to_req_msg(&self) -> Result<BccMsg<'_>, HwBccError>55 fn to_req_msg(&self) -> Result<BccMsg<'_>, HwBccError> {
56 let msg_buffer = &self.0;
57
58 match hwbcc_req_hdr::read_from_prefix(msg_buffer) {
59 Ok((header, sign_data_msg)) => {
60 let mut req_msg = BccMsg::new(
61 BccCmd::from_u32(header.cmd).ok_or_else(|| HwBccError::TryFromIntError)?,
62 HwBccMode::from_u32(header.test_mode)
63 .ok_or_else(|| HwBccError::TryFromIntError)?,
64 header.context,
65 );
66
67 if sign_data_msg.len() > 0 {
68 let _ = deserialize_signing_msg(&sign_data_msg, &mut req_msg)?;
69 }
70
71 Ok(req_msg)
72 }
73 Err(_) => {
74 log::error!("hwbcc request too small. Smaller than required header.");
75 return Err(HwBccError::BadLen);
76 }
77 }
78 }
79 }
80
81 impl Deserialize for RawBccMsgBuffer {
82 type Error = TipcError;
83 const MAX_SERIALIZED_SIZE: usize = HWBCC_MAX_MESSAGE_SIZE;
84
deserialize(bytes: &[u8], _handles: &mut [Option<Handle>]) -> tipc::Result<Self>85 fn deserialize(bytes: &[u8], _handles: &mut [Option<Handle>]) -> tipc::Result<Self> {
86 Ok(RawBccMsgBuffer(Vec::try_alloc_from(bytes)?))
87 }
88 }
89
deserialize_signing_msg<'a>( sign_data_bytes: &'a [u8], msg: &mut BccMsg<'a>, ) -> Result<(), HwBccError>90 fn deserialize_signing_msg<'a>(
91 sign_data_bytes: &'a [u8],
92 msg: &mut BccMsg<'a>,
93 ) -> Result<(), HwBccError> {
94 match hwbcc_req_sign_data::read_from_prefix(sign_data_bytes) {
95 Ok((sign_header, rest)) => {
96 let algorithm = SigningAlgorithm::from_i16(sign_header.algorithm)
97 .ok_or_else(|| HwBccError::TryFromIntError)?;
98
99 if sign_header.aad_size > HWBCC_MAX_AAD_SIZE {
100 log::error!(
101 "Failed to deserialize. aad size {} is greater than max of {}",
102 sign_header.aad_size,
103 HWBCC_MAX_AAD_SIZE
104 );
105 return Err(HwBccError::BadLen);
106 }
107
108 if sign_header.data_size as u32 > HWBCC_MAX_DATA_TO_SIGN_SIZE {
109 log::error!(
110 "Failed to deserialize. data size {} is greater than max of {}",
111 sign_header.aad_size,
112 HWBCC_MAX_AAD_SIZE
113 );
114 return Err(HwBccError::BadLen);
115 }
116
117 // hwbcc defines sizes with different data types, and at the end of the
118 // day we need these as usize so we can use them to index into the remaining
119 // data. `data_size` is u16 so it infallibly converts. `aad_size` is unfortunately
120 // u32, but hwbcc defines `MAX_AAD_SIZE` as 512 bytes, which should always fit in
121 // rust's usize.
122 let data_size: usize = sign_header.data_size.into();
123 let aad_size: usize = sign_header.aad_size.try_into()?;
124
125 let required_rest_len = data_size + aad_size;
126
127 if rest.len() < required_rest_len {
128 log::error!("hwbcc_req_sign_data header sizes are larger than the provided buffer");
129 return Err(HwBccError::BadLen);
130 }
131
132 // We've checked above to ensure that these indices are not out of range.
133 // In the event that a larger buffer was sent than the configured sizes, this
134 // truncates to the sizes provided in the header.
135 let _ = msg.add_signing_req(
136 algorithm,
137 &rest[..data_size],
138 &rest[data_size..required_rest_len],
139 );
140
141 Ok(())
142 }
143 Err(_) => {
144 log::error!("hwbcc_req_sign_data request too small.");
145 Err(HwBccError::BadLen)
146 }
147 }
148 }
149
150 pub struct HwBccService {
151 ops: Rc<dyn HwBccOps>,
152 }
153
154 impl HwBccService {
new(ops: Rc<dyn HwBccOps>) -> Self155 pub fn new(ops: Rc<dyn HwBccOps>) -> Self {
156 Self { ops }
157 }
158 }
159
160 pub trait HwBccOps {
init(&self, session: &RequestContext) -> Result<(), HwBccError>161 fn init(&self, session: &RequestContext) -> Result<(), HwBccError>;
close(&self, session: &RequestContext)162 fn close(&self, session: &RequestContext);
get_bcc(&self, session: &RequestContext, mode: HwBccMode) -> Result<Vec<u8>, HwBccError>163 fn get_bcc(&self, session: &RequestContext, mode: HwBccMode) -> Result<Vec<u8>, HwBccError>;
sign_data<'a>( &self, session: &RequestContext, data: &'a [u8], aad: &'a [u8], mode: HwBccMode, ) -> Result<Vec<u8>, HwBccError>164 fn sign_data<'a>(
165 &self,
166 session: &RequestContext,
167 data: &'a [u8],
168 aad: &'a [u8],
169 mode: HwBccMode,
170 ) -> Result<Vec<u8>, HwBccError>;
171 }
172
173 impl Service for HwBccService {
174 type Connection = RequestContext;
175 type Message = RawBccMsgBuffer;
on_connect( &self, _: &PortCfg, _: &Handle, peer: &Uuid, ) -> Result<ConnectResult<<Self as Service>::Connection>, TipcError>176 fn on_connect(
177 &self,
178 _: &PortCfg,
179 _: &Handle,
180 peer: &Uuid,
181 ) -> Result<ConnectResult<<Self as Service>::Connection>, TipcError> {
182 log::debug!("Accepted connection from uuid {:?}.", peer);
183 let session = RequestContext { peer: peer.clone() };
184 match self.ops.init(&session) {
185 Ok(_) => Ok(ConnectResult::Accept(session)),
186 Err(e) => {
187 log::error!("Failed HwBccOps.init: {:?}", e);
188 Err(TipcError::UnknownError)
189 }
190 }
191 }
192
on_message( &self, connection: &<Self as Service>::Connection, handle: &Handle, message: RawBccMsgBuffer, ) -> Result<MessageResult, TipcError>193 fn on_message(
194 &self,
195 connection: &<Self as Service>::Connection,
196 handle: &Handle,
197 message: RawBccMsgBuffer,
198 ) -> Result<MessageResult, TipcError> {
199 let bcc_msg = match message.to_req_msg() {
200 Ok(m) => m,
201 Err(_) => {
202 log::error!("Failed to deserialize request");
203 return Err(TipcError::InvalidData);
204 }
205 };
206
207 let header = &bcc_msg.header;
208
209 let response = match header.cmd {
210 BccCmd::GetBcc => {
211 payload_to_response(BccCmd::GetBcc, self.ops.get_bcc(connection, header.test_mode))?
212 }
213 BccCmd::SignData => {
214 if let Some(sign_req) = bcc_msg.sign_req {
215 // Note that we ignore sign_req.algorithm because we always sign
216 // with an algorithm derived from the leaf dice cert subject public key.
217 // This makes external configuration impossible.
218 payload_to_response(
219 BccCmd::SignData,
220 self.ops.sign_data(
221 connection,
222 sign_req.data,
223 sign_req.aad,
224 header.test_mode,
225 ),
226 )?
227 } else {
228 HwBccResponse::new_without_payload(Error::InvalidArgs, BccCmd::SignData)
229 }
230 }
231 _ => HwBccResponse::new_without_payload(Error::NotSupported, header.cmd),
232 };
233
234 handle.send(&response)?;
235
236 Ok(MessageResult::MaintainConnection)
237 }
238
on_disconnect(&self, connection: &Self::Connection)239 fn on_disconnect(&self, connection: &Self::Connection) {
240 self.ops.close(connection);
241 }
242 }
243
payload_to_response( cmd: BccCmd, payload: Result<Vec<u8>, HwBccError>, ) -> Result<HwBccResponse, TipcError>244 fn payload_to_response(
245 cmd: BccCmd,
246 payload: Result<Vec<u8>, HwBccError>,
247 ) -> Result<HwBccResponse, TipcError> {
248 match payload {
249 Ok(p) => HwBccResponse::try_new_with_payload(Error::NoError, cmd, p).map_err(|e| {
250 log::error!("Failed to create HwBccResponse from payload. Error: {:?}", e);
251 TipcError::InvalidData
252 }),
253 Err(_) => Ok(HwBccResponse::new_without_payload(Error::Generic, cmd)),
254 }
255 }
256
257 #[cfg(test)]
258 mod tests {
259 use super::*;
260 use crate::test_serializer::TestSerializer;
261 use test::expect_eq;
262 use tipc::Serialize;
263
264 #[test]
deserialize_header_only()265 fn deserialize_header_only() {
266 let mut serializer = TestSerializer::default();
267 let msg = BccMsg::new(BccCmd::GetBcc, HwBccMode::Test, 5);
268 let _ = msg.serialize(&mut serializer).expect("serialization of BccMsg failed");
269
270 let deserialized =
271 &RawBccMsgBuffer::deserialize(&mut serializer.buffers, &mut serializer.handles)
272 .expect("deserialization failed");
273
274 expect_eq!(deserialized.to_req_msg().expect("failed to get deserialized BccMsg"), msg);
275 }
276
277 #[test]
deserialize_with_sign_data()278 fn deserialize_with_sign_data() {
279 let mut serializer = TestSerializer::default();
280 let mut msg = BccMsg::new(BccCmd::GetBcc, HwBccMode::Test, 5);
281 let data = vec![0xBB, 0xBB, 0xBB];
282 let aad = vec![0xCC, 0xCC, 0xCC];
283 msg.add_signing_req(SigningAlgorithm::ED25519, &data, &aad);
284 let _ = msg.serialize(&mut serializer).expect("serialization of BccMsg failed");
285
286 let deserialized =
287 &RawBccMsgBuffer::deserialize(&mut serializer.buffers, &mut serializer.handles)
288 .expect("deserialization failed");
289
290 expect_eq!(deserialized.to_req_msg().expect("failed to get deserialized BccMsg"), msg);
291 }
292
293 #[test]
deserialize_fail_if_main_header_too_small()294 fn deserialize_fail_if_main_header_too_small() {
295 let mut serializer = TestSerializer::default();
296 serializer.buffers.resize(size_of::<hwbcc_req_hdr>() - 1, 0xAA);
297 let deserialized =
298 &RawBccMsgBuffer::deserialize(&mut serializer.buffers, &mut serializer.handles)
299 .expect("deserialization failed");
300
301 expect_eq!(deserialized.to_req_msg().err(), Some(HwBccError::BadLen));
302 }
303
304 #[test]
deserialize_fail_if_sign_header_too_small()305 fn deserialize_fail_if_sign_header_too_small() {
306 let mut serializer = TestSerializer::default();
307 let msg = BccMsg::new(BccCmd::GetBcc, HwBccMode::Test, 5);
308 let _ = msg.serialize(&mut serializer).expect("serialization of BccMsg failed");
309
310 // The signing header is encoded directly after the main header so this results in
311 // a signing header of length 1.
312 serializer.buffers.push(0xAA);
313 let deserialized =
314 &RawBccMsgBuffer::deserialize(&mut serializer.buffers, &mut serializer.handles)
315 .expect("deserialization failed");
316
317 expect_eq!(deserialized.to_req_msg().err(), Some(HwBccError::BadLen));
318 }
319
320 #[test]
deserialize_with_sign_req_should_truncate_buffer()321 fn deserialize_with_sign_req_should_truncate_buffer() {
322 let mut serializer = TestSerializer::default();
323 let mut msg = BccMsg::new(BccCmd::GetBcc, HwBccMode::Test, 5);
324 msg.add_signing_req(SigningAlgorithm::ED25519, b"signing data", b"aad data");
325 let _ = msg.serialize(&mut serializer).expect("serialization of BccMsg failed");
326
327 // The end of a message is the AAD data. We're adding erroneous data on the end here
328 // and ensuring that when deserializing, it's ignored.
329 serializer.buffers.push(0xAA);
330 let deserialized =
331 &RawBccMsgBuffer::deserialize(&mut serializer.buffers, &mut serializer.handles)
332 .expect("deserialization failed");
333
334 expect_eq!(deserialized.to_req_msg().expect("failed to get deserialized BccMsg"), msg);
335 }
336 }
337