1/* 2 * Copyright (c) 2023 Huawei Device Co., Ltd. 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 16use super::cert_chain_utils::PemCollection; 17use super::cert_path_utils::TrustCertPath; 18use super::cert_utils::{get_cert_path, get_trusted_certs}; 19use super::cs_hisysevent; 20use super::profile_utils::add_profile_cert_path; 21use hilog_rust::{error, hilog, info, HiLogLabel, LogType}; 22use openssl::error::ErrorStack; 23use std::ffi::{c_char, CString}; 24use std::fs::File; 25use std::io::{BufRead, BufReader}; 26use std::option::Option; 27use std::ptr; 28use std::thread; 29use std::time::{Duration, Instant}; 30use std::path::Path; 31 32const LOG_LABEL: HiLogLabel = HiLogLabel { 33 log_type: LogType::LogCore, 34 domain: 0xd005a06, // security domain 35 tag: "CODE_SIGN", 36}; 37 38const CERT_DATA_MAX_SIZE: usize = 8192; 39const PROC_KEY_FILE_PATH: &str = "/proc/keys"; 40const KEYRING_TYPE: &str = "keyring"; 41const FSVERITY_KEYRING_NAME: &str = ".fs-verity"; 42const LOCAL_KEY_NAME: &str = "local_key"; 43const CODE_SIGN_KEY_NAME_PREFIX: &str = "fs_verity_key"; 44const PROFILE_STORE_EL1: &str = "/data/service/el1/public/profiles"; 45const PROFILE_SEARCH_SLEEP_TIME: u64 = 200; 46const PROFILE_SEARCH_SLEEP_OUT_TIME: u64 = 600; 47const SUCCESS: i32 = 0; 48 49type KeySerial = i32; 50 51extern "C" { 52 fn InitLocalCertificate(cert_data: *mut u8, cert_size: *mut usize) -> i32; 53 fn AddKey( 54 type_name: *const u8, 55 description: *const u8, 56 payload: *const u8, 57 plen: usize, 58 ring_id: KeySerial, 59 ) -> KeySerial; 60 fn KeyctlRestrictKeyring( 61 ring_id: KeySerial, 62 type_name: *const u8, 63 restriction: *const u8, 64 ) -> KeySerial; 65 fn CheckUserUnlock() -> bool; 66} 67 68fn print_openssl_error_stack(error_stack: ErrorStack) { 69 for error in error_stack.errors() { 70 error!(LOG_LABEL, "{}", @public(error.to_string())); 71 } 72} 73 74fn get_local_key() -> Option<Vec<u8>> { 75 let mut cert_size = CERT_DATA_MAX_SIZE; 76 let mut cert_data = Vec::with_capacity(cert_size); 77 let pcert = cert_data.as_mut_ptr(); 78 79 unsafe { 80 let ret = InitLocalCertificate(pcert, &mut cert_size); 81 if ret == 0 { 82 cert_data.set_len(cert_size); 83 Some(cert_data) 84 } else { 85 None 86 } 87 } 88} 89 90/// parse key info 91/// [Serial][Flags][Usage][Expiry][Permissions][UID][GID][TypeName][Description]: [Summary] 92/// [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] 93/// 3985ad4c I------ 1 perm 082f0000 0 0 keyring .fs-verity: empty 94fn parse_key_info(line: String) -> Option<KeySerial> { 95 let attrs: Vec<&str> = line.split_whitespace().collect(); 96 if attrs.len() != 10 { 97 return None; 98 } 99 if attrs[7] == KEYRING_TYPE && attrs[8].strip_suffix(':') == Some(FSVERITY_KEYRING_NAME) { 100 match KeySerial::from_str_radix(attrs[0], 16) { 101 Ok(x) => Some(x), 102 Err(error) => { 103 error!(LOG_LABEL, "Convert KeySerial failed: {}", error); 104 None 105 } 106 } 107 } else { 108 None 109 } 110} 111 112fn enable_key(key_id: KeySerial, key_name: &str, cert_data: &Vec<u8>) -> i32 { 113 let type_name = CString::new("asymmetric").expect("type name is invalid"); 114 let keyname = CString::new(key_name).expect("keyname is invalid"); 115 unsafe { 116 let ret: i32 = AddKey( 117 type_name.as_ptr(), 118 keyname.as_ptr(), 119 cert_data.as_ptr(), 120 cert_data.len(), 121 key_id, 122 ); 123 ret 124 } 125} 126 127fn enable_key_list(key_id: KeySerial, certs: Vec<Vec<u8>>, key_name_prefix: &str) -> i32 { 128 let prefix = String::from(key_name_prefix); 129 for (i, cert_data) in certs.iter().enumerate() { 130 let key_name = prefix.clone() + &i.to_string(); 131 let ret = enable_key(key_id, key_name.as_str(), cert_data); 132 if ret < 0 { 133 return ret; 134 } 135 } 136 SUCCESS 137} 138 139/// parse proc_key_file to get keyring id 140fn get_keyring_id() -> Result<KeySerial, ()> { 141 let file = File::open(PROC_KEY_FILE_PATH).expect("Open /proc/keys failed"); 142 let lines = BufReader::new(file).lines(); 143 for line in lines.flatten() { 144 if line.contains(KEYRING_TYPE) && line.contains(FSVERITY_KEYRING_NAME) { 145 if let Some(keyid) = parse_key_info(line) { 146 return Ok(keyid); 147 } 148 } 149 } 150 error!(LOG_LABEL, "Get .fs-verity keyring id failed."); 151 Err(()) 152} 153 154// enable all trusted keys 155fn enable_trusted_keys(key_id: KeySerial, root_cert: &PemCollection) { 156 let certs = match root_cert.to_der() { 157 Ok(der) => der, 158 Err(e) => { 159 print_openssl_error_stack(e); 160 Vec::new() 161 } 162 }; 163 if certs.is_empty() { 164 error!(LOG_LABEL, "empty trusted certs!"); 165 } 166 let ret = enable_key_list(key_id, certs, CODE_SIGN_KEY_NAME_PREFIX); 167 if ret < 0 { 168 cs_hisysevent::report_add_key_err("code_sign_keys", ret); 169 } 170} 171 172fn check_and_add_cert_path(root_cert: &PemCollection, cert_paths: &TrustCertPath) -> bool { 173 if Path::new(PROFILE_STORE_EL1).exists() { 174 if add_profile_cert_path(root_cert, cert_paths).is_err() { 175 error!(LOG_LABEL, "Add cert path from local profile err."); 176 } 177 info!(LOG_LABEL, "Finished cert path adding."); 178 true 179 } else { 180 false 181 } 182} 183 184// start cert path ops thread add trusted cert & developer cert 185fn add_profile_cert_path_thread( 186 root_cert: PemCollection, 187 cert_paths: TrustCertPath, 188) -> std::thread::JoinHandle<()> { 189 thread::spawn(move || { 190 // enable developer certs 191 info!(LOG_LABEL, "Starting enable developer cert."); 192 let start_time = Instant::now(); 193 loop { 194 if check_and_add_cert_path(&root_cert, &cert_paths) { 195 break; 196 } else if start_time.elapsed() >= Duration::from_secs(PROFILE_SEARCH_SLEEP_OUT_TIME) { 197 error!(LOG_LABEL, "Timeout while waiting for PROFILE_STORE_EL1."); 198 break; 199 } else { 200 thread::sleep(Duration::from_millis(PROFILE_SEARCH_SLEEP_TIME)); 201 } 202 } 203 }) 204} 205 206// enable local key from local code sign SA 207fn enable_local_key(key_id: KeySerial) { 208 if let Some(cert_data) = get_local_key() { 209 let ret = enable_key(key_id, LOCAL_KEY_NAME, &cert_data); 210 if ret < 0 { 211 cs_hisysevent::report_add_key_err("local_key", ret); 212 error!(LOG_LABEL, "Enable local key failed"); 213 } 214 } 215} 216 217// restrict fs-verity keyring, don't allow to add more keys 218fn restrict_keys(key_id: KeySerial) { 219 unsafe { 220 if KeyctlRestrictKeyring(key_id, ptr::null(), ptr::null()) < 0 { 221 error!(LOG_LABEL, "Restrict keyring err"); 222 } 223 } 224} 225 226fn enable_keys_after_user_unlock(key_id: KeySerial) { 227 if !unsafe { CheckUserUnlock() } { 228 restrict_keys(key_id); 229 return; 230 } 231 232 // enable local code sign key 233 enable_local_key(key_id); 234 restrict_keys(key_id); 235} 236 237/// enable trusted and local keys, and then restrict keyring 238pub fn enable_all_keys() { 239 let key_id = match get_keyring_id() { 240 Ok(id) => id, 241 Err(_) => { 242 error!(LOG_LABEL, "Failed to get keyring ID."); 243 return; 244 }, 245 }; 246 let root_cert = get_trusted_certs(); 247 // enable device keys and authed source 248 enable_trusted_keys(key_id, &root_cert); 249 250 let cert_paths = get_cert_path(); 251 // enable trusted cert in prebuilt config 252 if cert_paths.add_cert_paths().is_err() { 253 error!(LOG_LABEL, "Add trusted cert path err."); 254 } 255 256 let cert_thread = add_profile_cert_path_thread(root_cert, cert_paths); 257 enable_keys_after_user_unlock(key_id); 258 259 if let Err(e) = cert_thread.join() { 260 error!(LOG_LABEL, "add cert path thread panicked: {:?}", e); 261 } 262 info!(LOG_LABEL, "Fnished enable all keys."); 263} 264