• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 use alloc::{rc::Rc, vec::Vec};
18 use authgraph_boringssl as boring;
19 use authgraph_core::{
20     keyexchange::{AuthGraphParticipant, MAX_OPENED_SESSIONS},
21     ta::{AuthGraphTa, Role},
22 };
23 use authgraph_wire::fragmentation::{Fragmenter, Reassembler, PLACEHOLDER_MORE_TO_COME};
24 use core::cell::RefCell;
25 use log::{debug, error, info};
26 use secretkeeper_core::ta::SecretkeeperTa;
27 use tipc::{
28     service_dispatcher, ConnectResult, Deserialize, Handle, Manager, MessageResult, PortCfg,
29     Serialize, Serializer, TipcError, Uuid,
30 };
31 use trusty_std::alloc::TryAllocFrom;
32 
33 mod store;
34 #[cfg(test)]
35 mod tests;
36 
37 /// Port for Secretkeeper communication with userspace.
38 const SK_PORT_NAME: &str = "com.android.trusty.secretkeeper";
39 
40 /// Port for AuthGraph communication with userspace.
41 const AG_PORT_NAME: &str = "com.android.trusty.secretkeeper.authgraph";
42 
43 /// Port for bootloader to communicate with Secretkeeper.
44 const BL_PORT_NAME: &str = "com.android.trusty.secretkeeper.bootloader";
45 
46 /// Port count for this TA (as above).
47 const PORT_COUNT: usize = 3;
48 
49 /// Maximum connection count for this TA:
50 /// - AuthGraph
51 /// - Secretkeeper
52 /// - bootloader
53 const MAX_CONNECTION_COUNT: usize = 3;
54 
55 /// Maximum message size.
56 const MAX_MSG_SIZE: usize = 4000;
57 
log_formatter(record: &log::Record) -> String58 fn log_formatter(record: &log::Record) -> String {
59     // line number should be present, so keeping it simple by just returning a 0.
60     let line = record.line().unwrap_or(0);
61     let file = record.file().unwrap_or("unknown file");
62     format!("{}: {}:{} {}\n", record.level(), file, line, record.args())
63 }
64 
65 /// Newtype wrapper for opaque messages.
66 struct SkMessage(Vec<u8>);
67 
68 impl Deserialize for SkMessage {
69     type Error = TipcError;
70     const MAX_SERIALIZED_SIZE: usize = MAX_MSG_SIZE;
71 
deserialize(bytes: &[u8], _handles: &mut [Option<Handle>]) -> tipc::Result<Self>72     fn deserialize(bytes: &[u8], _handles: &mut [Option<Handle>]) -> tipc::Result<Self> {
73         Ok(SkMessage(Vec::try_alloc_from(bytes)?))
74     }
75 }
76 
77 impl<'s> Serialize<'s> for SkMessage {
serialize<'a: 's, S: Serializer<'s>>( &'a self, serializer: &mut S, ) -> Result<S::Ok, S::Error>78     fn serialize<'a: 's, S: Serializer<'s>>(
79         &'a self,
80         serializer: &mut S,
81     ) -> Result<S::Ok, S::Error> {
82         serializer.serialize_bytes(self.0.as_slice())
83     }
84 }
85 
86 /// Break a response into fragments and send back to HAL service.
fragmented_send(handle: &Handle, full_rsp: Vec<u8>) -> tipc::Result<()>87 fn fragmented_send(handle: &Handle, full_rsp: Vec<u8>) -> tipc::Result<()> {
88     for rsp_frag in Fragmenter::new(&full_rsp, MAX_MSG_SIZE) {
89         handle.send(&SkMessage(rsp_frag))?;
90     }
91     Ok(())
92 }
93 
94 /// Process an incoming request that may arrive in fragments.
fragmented_process<T>( handle: &Handle, msg: &[u8], pending: &mut Reassembler, process: T, ) -> tipc::Result<MessageResult> where T: Fn(&[u8]) -> Vec<u8>,95 fn fragmented_process<T>(
96     handle: &Handle,
97     msg: &[u8],
98     pending: &mut Reassembler,
99     process: T,
100 ) -> tipc::Result<MessageResult>
101 where
102     T: Fn(&[u8]) -> Vec<u8>,
103 {
104     // Accumulate request fragments until able to feed complete request to `process`.
105     if let Some(full_req) = pending.accumulate(msg) {
106         let full_rsp = process(&full_req);
107         fragmented_send(handle, full_rsp)?;
108     } else {
109         handle.send(&SkMessage(PLACEHOLDER_MORE_TO_COME.to_vec()))?;
110     }
111     Ok(MessageResult::MaintainConnection)
112 }
113 
114 /// Implementation of the TIPC service for AuthGraph.
115 struct AuthGraphService {
116     ta: Rc<RefCell<AuthGraphTa>>,
117     pending_req: RefCell<Reassembler>,
118 }
119 
120 impl tipc::Service for AuthGraphService {
121     type Connection = ();
122     type Message = SkMessage;
123 
on_connect( &self, _port: &PortCfg, _handle: &Handle, peer: &Uuid, ) -> tipc::Result<ConnectResult<Self::Connection>>124     fn on_connect(
125         &self,
126         _port: &PortCfg,
127         _handle: &Handle,
128         peer: &Uuid,
129     ) -> tipc::Result<ConnectResult<Self::Connection>> {
130         info!("Accepted AuthGraph connection from uuid {peer:?}");
131         Ok(ConnectResult::Accept(()))
132     }
133 
on_message( &self, _connection: &Self::Connection, handle: &Handle, msg: Self::Message, ) -> tipc::Result<MessageResult>134     fn on_message(
135         &self,
136         _connection: &Self::Connection,
137         handle: &Handle,
138         msg: Self::Message,
139     ) -> tipc::Result<MessageResult> {
140         debug!("Received an AuthGraph message");
141 
142         fragmented_process(handle, &msg.0, &mut self.pending_req.borrow_mut(), |req| {
143             self.ta.borrow_mut().process(req)
144         })
145     }
146 }
147 
148 /// Implementation of the TIPC service for Secretkeeper.
149 struct SecretkeeperService {
150     ta: Rc<RefCell<SecretkeeperTa>>,
151     pending_req: RefCell<Reassembler>,
152 }
153 
154 impl tipc::Service for SecretkeeperService {
155     type Connection = ();
156     type Message = SkMessage;
157 
on_connect( &self, _port: &PortCfg, _handle: &Handle, peer: &Uuid, ) -> tipc::Result<ConnectResult<Self::Connection>>158     fn on_connect(
159         &self,
160         _port: &PortCfg,
161         _handle: &Handle,
162         peer: &Uuid,
163     ) -> tipc::Result<ConnectResult<Self::Connection>> {
164         info!("Accepted Secretkeeper connection from uuid {peer:?}");
165         Ok(ConnectResult::Accept(()))
166     }
167 
on_message( &self, _connection: &Self::Connection, handle: &Handle, msg: Self::Message, ) -> tipc::Result<MessageResult>168     fn on_message(
169         &self,
170         _connection: &Self::Connection,
171         handle: &Handle,
172         msg: Self::Message,
173     ) -> tipc::Result<MessageResult> {
174         debug!("Received a SecretKeeper message");
175 
176         fragmented_process(handle, &msg.0, &mut self.pending_req.borrow_mut(), |req| {
177             self.ta.borrow_mut().process(req)
178         })
179     }
180 }
181 
182 /// Implementation of the TIPC service for bootloader comms.
183 struct BootloaderService {
184     ta: Rc<RefCell<SecretkeeperTa>>,
185 }
186 
187 impl tipc::Service for BootloaderService {
188     type Connection = ();
189     type Message = SkMessage;
190 
on_connect( &self, _port: &PortCfg, _handle: &Handle, peer: &Uuid, ) -> tipc::Result<ConnectResult<Self::Connection>>191     fn on_connect(
192         &self,
193         _port: &PortCfg,
194         _handle: &Handle,
195         peer: &Uuid,
196     ) -> tipc::Result<ConnectResult<Self::Connection>> {
197         info!("Accepted bootloader connection from uuid {peer:?}");
198         Ok(ConnectResult::Accept(()))
199     }
200 
on_message( &self, _connection: &Self::Connection, handle: &Handle, msg: Self::Message, ) -> tipc::Result<MessageResult>201     fn on_message(
202         &self,
203         _connection: &Self::Connection,
204         handle: &Handle,
205         msg: Self::Message,
206     ) -> tipc::Result<MessageResult> {
207         debug!("Received a bootloader message");
208 
209         let rsp = self.ta.borrow().process_bootloader(&msg.0);
210         handle.send(&SkMessage(rsp))?;
211         Ok(MessageResult::MaintainConnection)
212     }
213 }
214 
215 service_dispatcher! {
216     enum SkServiceDispatcher {
217         AuthGraphService,
218         SecretkeeperService,
219         BootloaderService,
220     }
221 }
222 
223 #[derive(Debug)]
224 struct SecureConnections(bool);
225 
add_service_port<const PORT_COUNT: usize, T>( dispatcher: &mut SkServiceDispatcher<PORT_COUNT>, service: T, port_name: &str, secure: SecureConnections, ) -> Result<(), TipcError> where ServiceKind: From<Rc<T>>,226 fn add_service_port<const PORT_COUNT: usize, T>(
227     dispatcher: &mut SkServiceDispatcher<PORT_COUNT>,
228     service: T,
229     port_name: &str,
230     secure: SecureConnections,
231 ) -> Result<(), TipcError>
232 where
233     ServiceKind: From<Rc<T>>,
234 {
235     let cfg = PortCfg::new(port_name)
236         .map_err(|e| {
237             error!("Could not create port config for '{port_name}': {e:?}");
238             TipcError::UnknownError
239         })?
240         .msg_max_size(MAX_MSG_SIZE as u32)
241         .allow_ns_connect();
242     // All ports support non-secure connections (from either Android userspace or the bootloader,
243     // both of which are outside Trusty), but may also allow secure connections.
244     let cfg = if secure.0 { cfg.allow_ta_connect() } else { cfg };
245 
246     dispatcher.add_service(Rc::new(service), cfg).map_err(|e| {
247         error!("Could not add service for '{port_name}' to dispatcher: {e:?}");
248         e
249     })
250 }
251 
252 /// Internal main function.
inner_main() -> Result<(), TipcError>253 pub fn inner_main() -> Result<(), TipcError> {
254     let config = trusty_log::TrustyLoggerConfig::default()
255         .with_min_level(log::Level::Info)
256         .format(log_formatter);
257     trusty_log::init_with_config(config);
258     info!("Secretkeeper TA startup, on: '{AG_PORT_NAME}', '{SK_PORT_NAME}', '{BL_PORT_NAME}'");
259 
260     let mut crypto_impls = boring::crypto_trait_impls();
261     let storage_impl = Box::<store::SecureStore>::default();
262     let sk_ta = Rc::new(RefCell::new(
263         SecretkeeperTa::new(&mut crypto_impls, storage_impl, coset::iana::EllipticCurve::Ed25519)
264             .expect("Failed to create local Secretkeeper TA"),
265     ));
266     let ag_ta = Rc::new(RefCell::new(AuthGraphTa::new(
267         AuthGraphParticipant::new(crypto_impls, sk_ta.clone(), MAX_OPENED_SESSIONS)
268             .expect("Failed to create local AuthGraph TA"),
269         Role::Sink,
270     )));
271 
272     let ag_service = AuthGraphService { ta: ag_ta, pending_req: Default::default() };
273     let sk_service = SecretkeeperService { ta: sk_ta.clone(), pending_req: Default::default() };
274     let bl_service = BootloaderService { ta: sk_ta };
275 
276     // Handle multiple TIPC services, one service per port.
277     let mut dispatcher = SkServiceDispatcher::<PORT_COUNT>::new().map_err(|e| {
278         error!("could not create multi-service dispatcher: {e:?}");
279         e
280     })?;
281 
282     // Add the TIPC services into the dispatcher.
283     add_service_port(&mut dispatcher, ag_service, AG_PORT_NAME, SecureConnections(false))?;
284     add_service_port(&mut dispatcher, sk_service, SK_PORT_NAME, SecureConnections(false))?;
285     // Allow secure connections to the bootloader service for testing (as the Trusty
286     // test app uses a secure connection).
287     add_service_port(&mut dispatcher, bl_service, BL_PORT_NAME, SecureConnections(true))?;
288 
289     let buffer = [0u8; MAX_MSG_SIZE];
290     let manager =
291         Manager::<_, _, PORT_COUNT, MAX_CONNECTION_COUNT>::new_with_dispatcher(dispatcher, buffer)
292             .map_err(|e| {
293                 error!("Could not create service manager: {e:?}");
294                 e
295             })?;
296     manager.run_event_loop()
297 }
298