• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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