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