1 // Copyright 2022, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! Implementation of a HAL service for KeyMint.
16 //!
17 //! This implementation relies on a `SerializedChannel` abstraction for a communication channel to
18 //! the trusted application (TA).  Incoming method invocations for the HAL service are converted
19 //! into corresponding request structures, which are then serialized (using CBOR) and send down the
20 //! channel.  A serialized response is then read from the channel, which is deserialized into a
21 //! response structure.  The contents of this response structure are then used to populate the
22 //! return values of the HAL service method.
23 
24 #![allow(non_snake_case)]
25 
26 use core::{convert::TryInto, fmt::Debug};
27 use kmr_wire::{
28     cbor, cbor_type_error, keymint::ErrorCode, keymint::NEXT_MESSAGE_SIGNAL_TRUE, AsCborValue,
29     CborError, Code, KeyMintOperation,
30 };
31 use log::{error, info, warn};
32 use std::{
33     ffi::CString,
34     io::{Read, Write},
35     ops::DerefMut,
36     sync::MutexGuard,
37 };
38 
39 pub use binder;
40 
41 pub mod env;
42 pub mod hal;
43 pub mod keymint;
44 pub mod rpc;
45 pub mod secureclock;
46 pub mod sharedsecret;
47 #[cfg(test)]
48 mod tests;
49 
50 /// Emit a failure for a failed CBOR conversion.
51 #[inline]
failed_cbor(err: CborError) -> binder::Status52 pub fn failed_cbor(err: CborError) -> binder::Status {
53     binder::Status::new_service_specific_error(
54         ErrorCode::EncodingError as i32,
55         Some(&CString::new(format!("CBOR conversion failed: {:?}", err)).unwrap()),
56     )
57 }
58 
59 /// Abstraction of a channel to a secure world TA implementation.
60 pub trait SerializedChannel: Debug + Send {
61     /// Maximum supported size for the channel in bytes.
62     const MAX_SIZE: usize;
63 
64     /// Accepts serialized request messages and returns serialized return values
65     /// (or an error if communication via the channel is lost).
execute(&mut self, serialized_req: &[u8]) -> binder::Result<Vec<u8>>66     fn execute(&mut self, serialized_req: &[u8]) -> binder::Result<Vec<u8>>;
67 }
68 
69 /// A helper method to be used in the [`execute`] method above, in order to handle
70 /// responses received from the TA, especially those which are larger than the capacity of the
71 /// channel between the HAL and the TA.
72 /// This inspects the message, checks the first byte to see if the response arrives in multiple
73 /// messages. A boolean indicating whether or not to wait for the next message and the
74 /// response content (with the first byte stripped off) are returned to
75 /// the HAL service . Implementation of this method must be in sync with its counterpart
76 /// in the `kmr-ta` crate.
extract_rsp(rsp: &[u8]) -> binder::Result<(bool, &[u8])>77 pub fn extract_rsp(rsp: &[u8]) -> binder::Result<(bool, &[u8])> {
78     if rsp.len() < 2 {
79         return Err(binder::Status::new_exception(
80             binder::ExceptionCode::ILLEGAL_ARGUMENT,
81             Some(&CString::new("message is too small to extract the response data").unwrap()),
82         ));
83     }
84     Ok((rsp[0] == NEXT_MESSAGE_SIGNAL_TRUE, &rsp[1..]))
85 }
86 
87 /// Write a message to a stream-oriented [`Write`] item, with length framing.
write_msg<W: Write>(w: &mut W, data: &[u8]) -> binder::Result<()>88 pub fn write_msg<W: Write>(w: &mut W, data: &[u8]) -> binder::Result<()> {
89     // The underlying `Write` item does not guarantee delivery of complete messages.
90     // Make this possible by adding framing in the form of a big-endian `u32` holding
91     // the message length.
92     let data_len: u32 = data.len().try_into().map_err(|_e| {
93         binder::Status::new_exception(
94             binder::ExceptionCode::BAD_PARCELABLE,
95             Some(&CString::new("encoded request message too large").unwrap()),
96         )
97     })?;
98     let data_len_data = data_len.to_be_bytes();
99     w.write_all(&data_len_data[..]).map_err(|e| {
100         error!("Failed to write length to stream: {}", e);
101         binder::Status::new_exception(
102             binder::ExceptionCode::BAD_PARCELABLE,
103             Some(&CString::new("failed to write framing length").unwrap()),
104         )
105     })?;
106     w.write_all(data).map_err(|e| {
107         error!("Failed to write data to stream: {}", e);
108         binder::Status::new_exception(
109             binder::ExceptionCode::BAD_PARCELABLE,
110             Some(&CString::new("failed to write data").unwrap()),
111         )
112     })?;
113     Ok(())
114 }
115 
116 /// Read a message from a stream-oriented [`Read`] item, with length framing.
read_msg<R: Read>(r: &mut R) -> binder::Result<Vec<u8>>117 pub fn read_msg<R: Read>(r: &mut R) -> binder::Result<Vec<u8>> {
118     // The data read from the `Read` item has a 4-byte big-endian length prefix.
119     let mut len_data = [0u8; 4];
120     r.read_exact(&mut len_data).map_err(|e| {
121         error!("Failed to read length from stream: {}", e);
122         binder::Status::new_exception(binder::ExceptionCode::TRANSACTION_FAILED, None)
123     })?;
124     let len = u32::from_be_bytes(len_data);
125     let mut data = vec![0; len as usize];
126     r.read_exact(&mut data).map_err(|e| {
127         error!("Failed to read data from stream: {}", e);
128         binder::Status::new_exception(binder::ExceptionCode::TRANSACTION_FAILED, None)
129     })?;
130     Ok(data)
131 }
132 
133 /// Message-oriented wrapper around a pair of stream-oriented channels.  This allows a pair of
134 /// uni-directional channels that don't necessarily preserve message boundaries to appear as a
135 /// single bi-directional channel that does preserve message boundaries.
136 #[derive(Debug)]
137 pub struct MessageChannel<R: Read, W: Write> {
138     r: R,
139     w: W,
140 }
141 
142 impl<R: Read + Debug + Send, W: Write + Debug + Send> SerializedChannel for MessageChannel<R, W> {
143     const MAX_SIZE: usize = 4096;
144 
execute(&mut self, serialized_req: &[u8]) -> binder::Result<Vec<u8>>145     fn execute(&mut self, serialized_req: &[u8]) -> binder::Result<Vec<u8>> {
146         write_msg(&mut self.w, serialized_req)?;
147         read_msg(&mut self.r)
148     }
149 }
150 
151 /// Execute an operation by serializing and sending a request structure down a channel, and
152 /// deserializing and returning the response.
153 ///
154 /// This implementation relies on the internal serialization format for `PerformOpReq` and
155 /// `PerformOpRsp` to allow direct use of the specific request/response types.
channel_execute<T, R, S>(channel: &mut T, req: R) -> binder::Result<S> where T: SerializedChannel, R: AsCborValue + Code<KeyMintOperation>, S: AsCborValue + Code<KeyMintOperation>,156 fn channel_execute<T, R, S>(channel: &mut T, req: R) -> binder::Result<S>
157 where
158     T: SerializedChannel,
159     R: AsCborValue + Code<KeyMintOperation>,
160     S: AsCborValue + Code<KeyMintOperation>,
161 {
162     // Manually build an array that includes the opcode and the encoded request and encode it.
163     // This is equivalent to `PerformOpReq::to_vec()`.
164     let req_arr = cbor::value::Value::Array(vec![
165         <R>::CODE.to_cbor_value().map_err(failed_cbor)?,
166         req.to_cbor_value().map_err(failed_cbor)?,
167     ]);
168     let mut req_data = Vec::new();
169     cbor::ser::into_writer(&req_arr, &mut req_data).map_err(|e| {
170         binder::Status::new_service_specific_error(
171             ErrorCode::EncodingError as i32,
172             Some(
173                 &CString::new(format!("failed to write CBOR request to buffer: {:?}", e)).unwrap(),
174             ),
175         )
176     })?;
177 
178     if req_data.len() > T::MAX_SIZE {
179         error!(
180             "HAL operation {:?} encodes bigger {} than max size {}",
181             <R>::CODE,
182             req_data.len(),
183             T::MAX_SIZE
184         );
185         return Err(binder::Status::new_service_specific_error(
186             ErrorCode::InvalidInputLength as i32,
187             Some(&CString::new("encoded request message too large").unwrap()),
188         ));
189     }
190 
191     // Send in request bytes, get back response bytes.
192     let rsp_data = channel.execute(&req_data)?;
193 
194     // Convert the raw response data to an array of [error code, opt_response].
195     let rsp_value = kmr_wire::read_to_value(&rsp_data).map_err(failed_cbor)?;
196     let mut rsp_array = match rsp_value {
197         cbor::value::Value::Array(a) if a.len() == 2 => a,
198         _ => {
199             error!("HAL: failed to parse response data 2-array!");
200             return cbor_type_error(&rsp_value, "arr of len 2").map_err(failed_cbor);
201         }
202     };
203     let opt_response = rsp_array.remove(1);
204     let error_code = <i32>::from_cbor_value(rsp_array.remove(0)).map_err(failed_cbor)?;
205     // The error code is in a numbering space that depends on the specific HAL being
206     // invoked (IRemotelyProvisionedComponent vs. the rest). However, the OK value is
207     // the same in all spaces.
208     if error_code != ErrorCode::Ok as i32 {
209         warn!("HAL: command {:?} failed: {:?}", <R>::CODE, error_code);
210         return Err(binder::Status::new_service_specific_error(error_code, None));
211     }
212 
213     // The optional response should be an array of exactly 1 element (because the 0-element case
214     // corresponds to a non-OK error code, which has just been dealt with).
215     let rsp = match opt_response {
216         cbor::value::Value::Array(mut a) if a.len() == 1 => a.remove(0),
217         _ => {
218             error!("HAL: failed to parse response data structure!");
219             return cbor_type_error(&opt_response, "arr of len 1").map_err(failed_cbor);
220         }
221     };
222 
223     // The response is expected to be an array of 2 elements: a op_type code and an encoded response
224     // structure.  The op_type code indicates the type of response structure, which should be what
225     // we expect.
226     let mut inner_rsp_array = match rsp {
227         cbor::value::Value::Array(a) if a.len() == 2 => a,
228         _ => {
229             error!("HAL: failed to parse inner response data structure!");
230             return cbor_type_error(&rsp, "arr of len 2").map_err(failed_cbor);
231         }
232     };
233     let inner_rsp = inner_rsp_array.remove(1);
234     let op_type =
235         <KeyMintOperation>::from_cbor_value(inner_rsp_array.remove(0)).map_err(failed_cbor)?;
236     if op_type != <S>::CODE {
237         error!("HAL: inner response data for unexpected opcode {:?}!", op_type);
238         return Err(failed_cbor(CborError::UnexpectedItem("wrong ret code", "rsp ret code")));
239     }
240 
241     <S>::from_cbor_value(inner_rsp).map_err(failed_cbor)
242 }
243 
244 /// Abstraction of a HAL service that uses an underlying [`SerializedChannel`] to communicate with
245 /// an associated TA.
246 trait ChannelHalService<T: SerializedChannel> {
247     /// Return the underlying channel.
channel(&self) -> MutexGuard<T>248     fn channel(&self) -> MutexGuard<T>;
249 
250     /// Execute the given request, by serializing it and sending it down the internal channel.  Then
251     /// read and deserialize the response.
execute<R, S>(&self, req: R) -> binder::Result<S> where R: AsCborValue + Code<KeyMintOperation>, S: AsCborValue + Code<KeyMintOperation>,252     fn execute<R, S>(&self, req: R) -> binder::Result<S>
253     where
254         R: AsCborValue + Code<KeyMintOperation>,
255         S: AsCborValue + Code<KeyMintOperation>,
256     {
257         channel_execute(self.channel().deref_mut(), req)
258     }
259 }
260 
261 /// Let the TA know information about the userspace environment.
send_hal_info<T: SerializedChannel>(channel: &mut T) -> binder::Result<()>262 pub fn send_hal_info<T: SerializedChannel>(channel: &mut T) -> binder::Result<()> {
263     let req = env::populate_hal_info().map_err(|e| {
264         binder::Status::new_exception(
265             binder::ExceptionCode::BAD_PARCELABLE,
266             Some(&CString::new(format!("failed to determine HAL environment: {}", e)).unwrap()),
267         )
268     })?;
269     info!("HAL->TA: environment info is {:?}", req);
270     let _rsp: kmr_wire::SetHalInfoResponse = channel_execute(channel, req)?;
271 
272     let aidl_version = if cfg!(feature = "hal_v3") {
273         300
274     } else if cfg!(feature = "hal_v2") {
275         200
276     } else {
277         100
278     };
279     let req = kmr_wire::SetHalVersionRequest { aidl_version };
280     info!("HAL->TA: setting KeyMint HAL version to {}", aidl_version);
281     let result: binder::Result<kmr_wire::SetHalVersionResponse> = channel_execute(channel, req);
282     if let Err(e) = result {
283         // The SetHalVersionRequest message was added later; an earlier TA may not recognize it.
284         warn!("Setting KeyMint HAL version failed: {:?}", e);
285     }
286     Ok(())
287 }
288 
289 /// Let the TA know information about the boot environment.
send_boot_info<T: SerializedChannel>( channel: &mut T, req: kmr_wire::SetBootInfoRequest, ) -> binder::Result<()>290 pub fn send_boot_info<T: SerializedChannel>(
291     channel: &mut T,
292     req: kmr_wire::SetBootInfoRequest,
293 ) -> binder::Result<()> {
294     info!("boot->TA: boot info is {:?}", req);
295     let _rsp: kmr_wire::SetBootInfoResponse = channel_execute(channel, req)?;
296     Ok(())
297 }
298 
299 /// Provision the TA with attestation ID information.
send_attest_ids<T: SerializedChannel>( channel: &mut T, ids: kmr_wire::AttestationIdInfo, ) -> binder::Result<()>300 pub fn send_attest_ids<T: SerializedChannel>(
301     channel: &mut T,
302     ids: kmr_wire::AttestationIdInfo,
303 ) -> binder::Result<()> {
304     let req = kmr_wire::SetAttestationIdsRequest { ids };
305     info!("provision->attestation IDs are {:?}", req);
306     let _rsp: kmr_wire::SetAttestationIdsResponse = channel_execute(channel, req)?;
307     Ok(())
308 }
309 
310 /// Let the TA know that early boot has ended
early_boot_ended<T: SerializedChannel>(channel: &mut T) -> binder::Result<()>311 pub fn early_boot_ended<T: SerializedChannel>(channel: &mut T) -> binder::Result<()> {
312     info!("boot->TA: early boot ended");
313     let req = kmr_wire::EarlyBootEndedRequest {};
314     let _rsp: kmr_wire::EarlyBootEndedResponse = channel_execute(channel, req)?;
315     Ok(())
316 }
317