• 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 //! 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,
24 };
25 use kmr_ta::device::{BootloaderDone, Implementation, TrustedPresenceUnsupported};
26 use kmr_ta::{HardwareInfo, KeyMintTa, RpcInfo, RpcInfoV3};
27 use kmr_wire::keymint::SecurityLevel;
28 use kmr_wire::rpc::MINIMUM_SUPPORTED_KEYS_IN_CSR;
29 use libc::c_int;
30 use log::{error, info, trace};
31 use std::ffi::CString;
32 use std::io::{Read, Write};
33 use std::os::unix::{ffi::OsStrExt, io::FromRawFd};
34 
35 pub mod attest;
36 mod clock;
37 pub mod rpc;
38 mod soft;
39 mod tpm;
40 
41 #[cfg(test)]
42 mod tests;
43 
44 /// Main routine for the KeyMint TA. Only returns if there is a fatal error.
ta_main(fd_in: c_int, fd_out: c_int, security_level: SecurityLevel, trm: *mut libc::c_void)45 pub fn ta_main(fd_in: c_int, fd_out: c_int, security_level: SecurityLevel, trm: *mut libc::c_void) {
46     log::set_logger(&AndroidCppLogger).unwrap();
47     log::set_max_level(log::LevelFilter::Debug); // Filtering happens elsewhere
48     info!(
49         "KeyMint Rust TA running with fd_in={}, fd_out={}, security_level={:?}",
50         fd_in, fd_out, security_level,
51     );
52 
53     // Safety: the following calls rely on this code being the sole owner of the file descriptors.
54     let mut infile = unsafe { std::fs::File::from_raw_fd(fd_in) };
55     let mut outfile = unsafe { std::fs::File::from_raw_fd(fd_out) };
56 
57     let hw_info = HardwareInfo {
58         version_number: 1,
59         security_level,
60         impl_name: "Rust reference implementation for Cuttlefish",
61         author_name: "Google",
62         unique_id: "Cuttlefish KeyMint TA",
63     };
64 
65     let rpc_info_v3 = RpcInfoV3 {
66         author_name: "Google",
67         unique_id: "Cuttlefish KeyMint TA",
68         fused: false,
69         supported_num_of_keys_in_csr: MINIMUM_SUPPORTED_KEYS_IN_CSR,
70     };
71 
72     let mut rng = BoringRng::default();
73     let clock = clock::StdClock::default();
74     let rsa = BoringRsa::default();
75     let ec = BoringEc::default();
76     let tpm_hkdf = tpm::KeyDerivation::new(trm);
77     let soft_hkdf = BoringHmac;
78     let hkdf: &dyn kmr_common::crypto::Hkdf =
79         if security_level == SecurityLevel::TrustedEnvironment { &tpm_hkdf } else { &soft_hkdf };
80     let imp = crypto::Implementation {
81         rng: &mut rng,
82         clock: Some(&clock),
83         compare: &BoringEq,
84         aes: &BoringAes,
85         des: &BoringDes,
86         hmac: &BoringHmac,
87         rsa: &rsa,
88         ec: &ec,
89         ckdf: &BoringAesCmac,
90         hkdf,
91     };
92     let sign_info = attest::CertSignInfo::new();
93 
94     let tpm_keys = tpm::Keys::new(trm);
95     let soft_keys = soft::Keys;
96     let keys: &dyn kmr_ta::device::RetrieveKeyMaterial =
97         if security_level == SecurityLevel::TrustedEnvironment { &tpm_keys } else { &soft_keys };
98     let tpm_rpc = tpm::RpcArtifacts::new(tpm::TpmHmac::new(trm));
99     let soft_rpc = soft::RpcArtifacts::new(soft::Derive::default());
100     let rpc: &dyn kmr_ta::device::RetrieveRpcArtifacts =
101         if security_level == SecurityLevel::TrustedEnvironment { &tpm_rpc } else { &soft_rpc };
102     let dev = Implementation {
103         keys,
104         sign_info: &sign_info,
105         // HAL populates attestation IDs from properties.
106         attest_ids: None,
107         // No secure storage.
108         sdd_mgr: None,
109         // `BOOTLOADER_ONLY` keys not supported.
110         bootloader: &BootloaderDone,
111         // `STORAGE_KEY` keys not supported.
112         sk_wrapper: None,
113         // `TRUSTED_USER_PRESENCE_REQUIRED` keys not supported
114         tup: &TrustedPresenceUnsupported,
115         // No support for converting previous implementation's keyblobs.
116         legacy_key: None,
117         rpc,
118     };
119     let mut ta = KeyMintTa::new(hw_info, RpcInfo::V3(rpc_info_v3), imp, dev);
120 
121     let mut buf = [0; kmr_wire::DEFAULT_MAX_SIZE];
122     loop {
123         // Read a request message from the pipe, as a 4-byte BE length followed by the message.
124         let mut req_len_data = [0u8; 4];
125         if let Err(e) = infile.read_exact(&mut req_len_data) {
126             error!("FATAL: Failed to read request length from connection: {:?}", e);
127             return;
128         }
129         let req_len = u32::from_be_bytes(req_len_data) as usize;
130         if req_len > kmr_wire::DEFAULT_MAX_SIZE {
131             error!("FATAL: Request too long ({})", req_len);
132             return;
133         }
134         let req_data = &mut buf[..req_len];
135         if let Err(e) = infile.read_exact(req_data) {
136             error!(
137                 "FATAL: Failed to read request data of length {} from connection: {:?}",
138                 req_len, e
139             );
140             return;
141         }
142 
143         // Pass to the TA to process.
144         trace!("-> TA: received data: (len={})", req_data.len());
145         let rsp = ta.process(req_data);
146         trace!("<- TA: send data: (len={})", rsp.len());
147 
148         // Send the response message down the pipe, as a 4-byte BE length followed by the message.
149         let rsp_len: u32 = match rsp.len().try_into() {
150             Ok(l) => l,
151             Err(_e) => {
152                 error!("FATAL: Response too long (len={})", rsp.len());
153                 return;
154             }
155         };
156         let rsp_len_data = rsp_len.to_be_bytes();
157         if let Err(e) = outfile.write_all(&rsp_len_data[..]) {
158             error!("FATAL: Failed to write response length to connection: {:?}", e);
159             return;
160         }
161         if let Err(e) = outfile.write_all(&rsp) {
162             error!(
163                 "FATAL: Failed to write response data of length {} to connection: {:?}",
164                 rsp_len, e
165             );
166             return;
167         }
168         let _ = outfile.flush();
169     }
170 }
171 
172 // TODO(schuffelen): Use android_logger when rust works with host glibc, see aosp/1415969
173 struct AndroidCppLogger;
174 
175 impl log::Log for AndroidCppLogger {
enabled(&self, _metadata: &log::Metadata) -> bool176     fn enabled(&self, _metadata: &log::Metadata) -> bool {
177         // Filtering is done in the underlying C++ logger, so indicate to the Rust code that all
178         // logs should be included
179         true
180     }
181 
log(&self, record: &log::Record)182     fn log(&self, record: &log::Record) {
183         let file = record.file().unwrap_or("(no file)");
184         let file_basename =
185             std::path::Path::new(file).file_name().unwrap_or(std::ffi::OsStr::new("(no file)"));
186         let file = CString::new(file_basename.as_bytes())
187             .unwrap_or_else(|_| CString::new("(invalid file)").unwrap());
188         let line = record.line().unwrap_or(0);
189         let severity = match record.level() {
190             log::Level::Trace => 0,
191             log::Level::Debug => 1,
192             log::Level::Info => 2,
193             log::Level::Warn => 3,
194             log::Level::Error => 4,
195         };
196         let tag = CString::new("secure_env::".to_owned() + record.target())
197             .unwrap_or_else(|_| CString::new("(invalid tag)").unwrap());
198         let msg = CString::new(format!("{}", record.args()))
199             .unwrap_or_else(|_| CString::new("(invalid msg)").unwrap());
200         unsafe {
201             // Safety: All pointer arguments are generated from valid owned CString instances
202             secure_env_tpm::secure_env_log(
203                 file.as_ptr(),
204                 line,
205                 severity,
206                 tag.as_ptr(),
207                 msg.as_ptr(),
208             );
209         }
210     }
211 
flush(&self)212     fn flush(&self) {}
213 }
214