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 //! KeyMint TA core for Cuttlefish.
17 
18 extern crate alloc;
19 
20 use kmr_common::crypto;
21 use kmr_crypto_boring::{
22     aes::BoringAes, aes_cmac::BoringAesCmac, des::BoringDes, ec::BoringEc, eq::BoringEq,
23     hmac::BoringHmac, rng::BoringRng, rsa::BoringRsa, sha256::BoringSha256,
24 };
25 use kmr_ta::device::{
26     BootloaderDone, CsrSigningAlgorithm, Implementation, TrustedPresenceUnsupported,
27 };
28 use kmr_ta::{HardwareInfo, KeyMintTa, RpcInfo, RpcInfoV3};
29 use kmr_ta_nonsecure::{rpc, soft};
30 use kmr_wire::keymint::SecurityLevel;
31 use kmr_wire::rpc::MINIMUM_SUPPORTED_KEYS_IN_CSR;
32 use log::{error, info, trace};
33 use std::ffi::CString;
34 use std::io::{Read, Write};
35 use std::os::fd::AsFd;
36 use std::os::fd::AsRawFd;
37 use std::os::unix::ffi::OsStrExt;
38 
39 mod clock;
40 mod sdd;
41 mod tpm;
42 
43 #[cfg(test)]
44 mod tests;
45 
46 // See `SnapshotSocketMessage` in suspend_resume_handler.h for docs.
47 const SNAPSHOT_SOCKET_MESSAGE_SUSPEND: u8 = 1;
48 const SNAPSHOT_SOCKET_MESSAGE_SUSPEND_ACK: u8 = 2;
49 const SNAPSHOT_SOCKET_MESSAGE_RESUME: u8 = 3;
50 
51 /// Main routine for the KeyMint TA. Only returns if there is a fatal error.
52 ///
53 /// # Safety
54 ///
55 /// TODO: What are the preconditions for `trm`?
ta_main( mut infile: std::fs::File, mut outfile: std::fs::File, security_level: SecurityLevel, trm: *mut libc::c_void, mut snapshot_socket: std::os::unix::net::UnixStream, )56 pub unsafe fn ta_main(
57     mut infile: std::fs::File,
58     mut outfile: std::fs::File,
59     security_level: SecurityLevel,
60     trm: *mut libc::c_void,
61     mut snapshot_socket: std::os::unix::net::UnixStream,
62 ) {
63     log::set_logger(&AndroidCppLogger).unwrap();
64     log::set_max_level(log::LevelFilter::Debug); // Filtering happens elsewhere
65     info!(
66         "KeyMint Rust TA running with infile={}, outfile={}, security_level={:?}",
67         infile.as_raw_fd(),
68         outfile.as_raw_fd(),
69         security_level,
70     );
71 
72     let hw_info = HardwareInfo {
73         version_number: 1,
74         security_level,
75         impl_name: "Rust reference implementation for Cuttlefish",
76         author_name: "Google",
77         unique_id: "Cuttlefish KeyMint TA",
78     };
79 
80     let rpc_sign_algo = CsrSigningAlgorithm::EdDSA;
81     let rpc_info_v3 = RpcInfoV3 {
82         author_name: "Google",
83         unique_id: "Cuttlefish KeyMint TA",
84         fused: false,
85         supported_num_of_keys_in_csr: MINIMUM_SUPPORTED_KEYS_IN_CSR,
86     };
87 
88     let mut rng = BoringRng;
89     let sdd_mgr: Option<Box<dyn kmr_common::keyblob::SecureDeletionSecretManager>> =
90         match sdd::HostSddManager::new(&mut rng) {
91             Ok(v) => Some(Box::new(v)),
92             Err(e) => {
93                 error!("Failed to initialize secure deletion data manager: {:?}", e);
94                 None
95             }
96         };
97     let clock = clock::StdClock;
98     let rsa = BoringRsa::default();
99     let ec = BoringEc::default();
100     let hkdf: Box<dyn kmr_common::crypto::Hkdf> =
101         if security_level == SecurityLevel::TrustedEnvironment {
102             Box::new(tpm::KeyDerivation::new(trm))
103         } else {
104             Box::new(BoringHmac)
105         };
106     let imp = crypto::Implementation {
107         rng: Box::new(rng),
108         clock: Some(Box::new(clock)),
109         compare: Box::new(BoringEq),
110         aes: Box::new(BoringAes),
111         des: Box::new(BoringDes),
112         hmac: Box::new(BoringHmac),
113         rsa: Box::new(rsa),
114         ec: Box::new(ec),
115         ckdf: Box::new(BoringAesCmac),
116         hkdf,
117         sha256: Box::new(BoringSha256),
118     };
119 
120     let keys: Box<dyn kmr_ta::device::RetrieveKeyMaterial> =
121         if security_level == SecurityLevel::TrustedEnvironment {
122             Box::new(tpm::Keys::new(trm))
123         } else {
124             Box::new(soft::Keys)
125         };
126     let rpc: Box<dyn kmr_ta::device::RetrieveRpcArtifacts> =
127         if security_level == SecurityLevel::TrustedEnvironment {
128             Box::new(tpm::RpcArtifacts::new(tpm::TpmHmac::new(trm), rpc_sign_algo))
129         } else {
130             Box::new(soft::RpcArtifacts::new(soft::Derive::default(), rpc_sign_algo))
131         };
132     let dev = Implementation {
133         keys,
134         // Cuttlefish has `remote_provisioning.tee.rkp_only=1` so don't support batch signing
135         // of keys.  This can be reinstated with:
136         // ```
137         // sign_info: Some(kmr_ta_nonsecure::attest::CertSignInfo::new()),
138         // ```
139         sign_info: None,
140         // HAL populates attestation IDs from properties.
141         attest_ids: None,
142         sdd_mgr,
143         // `BOOTLOADER_ONLY` keys not supported.
144         bootloader: Box::new(BootloaderDone),
145         // `STORAGE_KEY` keys not supported.
146         sk_wrapper: None,
147         // `TRUSTED_USER_PRESENCE_REQUIRED` keys not supported
148         tup: Box::new(TrustedPresenceUnsupported),
149         // No support for converting previous implementation's keyblobs.
150         legacy_key: None,
151         rpc,
152     };
153     let mut ta = KeyMintTa::new(hw_info, RpcInfo::V3(rpc_info_v3), imp, dev);
154 
155     let mut buf = [0; kmr_wire::DEFAULT_MAX_SIZE];
156     loop {
157         // Wait for data from either `infile` or `snapshot_socket`. If both have data, we prioritize
158         // processing only `infile` until it is empty so that there is no pending state when we
159         // suspend the loop.
160         let mut fd_set = nix::sys::select::FdSet::new();
161         fd_set.insert(infile.as_fd());
162         fd_set.insert(snapshot_socket.as_fd());
163         if let Err(e) = nix::sys::select::select(
164             None,
165             /*readfds=*/ Some(&mut fd_set),
166             None,
167             None,
168             /*timeout=*/ None,
169         ) {
170             error!("FATAL: Failed to select on input FDs: {:?}", e);
171             return;
172         }
173 
174         if fd_set.contains(infile.as_fd()) {
175             // Read a request message from the pipe, as a 4-byte BE length followed by the message.
176             let mut req_len_data = [0u8; 4];
177             if let Err(e) = infile.read_exact(&mut req_len_data) {
178                 error!("FATAL: Failed to read request length from connection: {:?}", e);
179                 return;
180             }
181             let req_len = u32::from_be_bytes(req_len_data) as usize;
182             if req_len > kmr_wire::DEFAULT_MAX_SIZE {
183                 error!("FATAL: Request too long ({})", req_len);
184                 return;
185             }
186             let req_data = &mut buf[..req_len];
187             if let Err(e) = infile.read_exact(req_data) {
188                 error!(
189                     "FATAL: Failed to read request data of length {} from connection: {:?}",
190                     req_len, e
191                 );
192                 return;
193             }
194 
195             // Pass to the TA to process.
196             trace!("-> TA: received data: (len={})", req_data.len());
197             let rsp = ta.process(req_data);
198             trace!("<- TA: send data: (len={})", rsp.len());
199 
200             // Send the response message down the pipe, as a 4-byte BE length followed by the message.
201             let rsp_len: u32 = match rsp.len().try_into() {
202                 Ok(l) => l,
203                 Err(_e) => {
204                     error!("FATAL: Response too long (len={})", rsp.len());
205                     return;
206                 }
207             };
208             let rsp_len_data = rsp_len.to_be_bytes();
209             if let Err(e) = outfile.write_all(&rsp_len_data[..]) {
210                 error!("FATAL: Failed to write response length to connection: {:?}", e);
211                 return;
212             }
213             if let Err(e) = outfile.write_all(&rsp) {
214                 error!(
215                     "FATAL: Failed to write response data of length {} to connection: {:?}",
216                     rsp_len, e
217                 );
218                 return;
219             }
220             let _ = outfile.flush();
221 
222             continue;
223         }
224 
225         if fd_set.contains(snapshot_socket.as_fd()) {
226             // Read suspend request.
227             let mut suspend_request = 0u8;
228             if let Err(e) = snapshot_socket.read_exact(std::slice::from_mut(&mut suspend_request)) {
229                 error!("FATAL: Failed to read suspend request: {:?}", e);
230                 return;
231             }
232             if suspend_request != SNAPSHOT_SOCKET_MESSAGE_SUSPEND {
233                 error!(
234                     "FATAL: Unexpected value from snapshot socket: got {}, expected {}",
235                     suspend_request, SNAPSHOT_SOCKET_MESSAGE_SUSPEND
236                 );
237                 return;
238             }
239             // Write ACK.
240             if let Err(e) = snapshot_socket.write_all(&[SNAPSHOT_SOCKET_MESSAGE_SUSPEND_ACK]) {
241                 error!("FATAL: Failed to write suspend ACK request: {:?}", e);
242                 return;
243             }
244             // Block until we get a resume request.
245             let mut resume_request = 0u8;
246             if let Err(e) = snapshot_socket.read_exact(std::slice::from_mut(&mut resume_request)) {
247                 error!("FATAL: Failed to read resume request: {:?}", e);
248                 return;
249             }
250             if resume_request != SNAPSHOT_SOCKET_MESSAGE_RESUME {
251                 error!(
252                     "FATAL: Unexpected value from snapshot socket: got {}, expected {}",
253                     resume_request, SNAPSHOT_SOCKET_MESSAGE_RESUME
254                 );
255                 return;
256             }
257         }
258     }
259 }
260 
261 // TODO(schuffelen): Use android_logger when rust works with host glibc, see aosp/1415969
262 struct AndroidCppLogger;
263 
264 impl log::Log for AndroidCppLogger {
enabled(&self, _metadata: &log::Metadata) -> bool265     fn enabled(&self, _metadata: &log::Metadata) -> bool {
266         // Filtering is done in the underlying C++ logger, so indicate to the Rust code that all
267         // logs should be included
268         true
269     }
270 
log(&self, record: &log::Record)271     fn log(&self, record: &log::Record) {
272         let file = record.file().unwrap_or("(no file)");
273         let file_basename =
274             std::path::Path::new(file).file_name().unwrap_or(std::ffi::OsStr::new("(no file)"));
275         let file = CString::new(file_basename.as_bytes())
276             .unwrap_or_else(|_| CString::new("(invalid file)").unwrap());
277         let line = record.line().unwrap_or(0);
278         let severity = match record.level() {
279             log::Level::Trace => 0,
280             log::Level::Debug => 1,
281             log::Level::Info => 2,
282             log::Level::Warn => 3,
283             log::Level::Error => 4,
284         };
285         let tag = CString::new("secure_env::".to_owned() + record.target())
286             .unwrap_or_else(|_| CString::new("(invalid tag)").unwrap());
287         let msg = CString::new(format!("{}", record.args()))
288             .unwrap_or_else(|_| CString::new("(invalid msg)").unwrap());
289         // SAFETY: All pointer arguments are generated from valid owned CString instances.
290         unsafe {
291             secure_env_tpm::secure_env_log(
292                 file.as_ptr(),
293                 line,
294                 severity,
295                 tag.as_ptr(),
296                 msg.as_ptr(),
297             );
298         }
299     }
300 
flush(&self)301     fn flush(&self) {}
302 }
303