18e920a95Sopenharmony_ci/* 28e920a95Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd. 38e920a95Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 48e920a95Sopenharmony_ci * you may not use this file except in compliance with the License. 58e920a95Sopenharmony_ci * You may obtain a copy of the License at 68e920a95Sopenharmony_ci * 78e920a95Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 88e920a95Sopenharmony_ci * 98e920a95Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 108e920a95Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 118e920a95Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 128e920a95Sopenharmony_ci * See the License for the specific language governing permissions and 138e920a95Sopenharmony_ci * limitations under the License. 148e920a95Sopenharmony_ci */ 158e920a95Sopenharmony_ci 168e920a95Sopenharmony_ciuse super::cert_chain_utils::PemCollection; 178e920a95Sopenharmony_ciuse super::cert_path_utils::TrustCertPath; 188e920a95Sopenharmony_ciuse super::cert_utils::{get_cert_path, get_trusted_certs}; 198e920a95Sopenharmony_ciuse super::cs_hisysevent; 208e920a95Sopenharmony_ciuse super::profile_utils::add_profile_cert_path; 218e920a95Sopenharmony_ciuse hilog_rust::{error, hilog, info, HiLogLabel, LogType}; 228e920a95Sopenharmony_ciuse openssl::error::ErrorStack; 238e920a95Sopenharmony_ciuse std::ffi::{c_char, CString}; 248e920a95Sopenharmony_ciuse std::fs::File; 258e920a95Sopenharmony_ciuse std::io::{BufRead, BufReader}; 268e920a95Sopenharmony_ciuse std::option::Option; 278e920a95Sopenharmony_ciuse std::ptr; 288e920a95Sopenharmony_ciuse std::thread; 298e920a95Sopenharmony_ciuse std::time::{Duration, Instant}; 308e920a95Sopenharmony_ciuse std::path::Path; 318e920a95Sopenharmony_ci 328e920a95Sopenharmony_ciconst LOG_LABEL: HiLogLabel = HiLogLabel { 338e920a95Sopenharmony_ci log_type: LogType::LogCore, 348e920a95Sopenharmony_ci domain: 0xd005a06, // security domain 358e920a95Sopenharmony_ci tag: "CODE_SIGN", 368e920a95Sopenharmony_ci}; 378e920a95Sopenharmony_ci 388e920a95Sopenharmony_ciconst CERT_DATA_MAX_SIZE: usize = 8192; 398e920a95Sopenharmony_ciconst PROC_KEY_FILE_PATH: &str = "/proc/keys"; 408e920a95Sopenharmony_ciconst KEYRING_TYPE: &str = "keyring"; 418e920a95Sopenharmony_ciconst FSVERITY_KEYRING_NAME: &str = ".fs-verity"; 428e920a95Sopenharmony_ciconst LOCAL_KEY_NAME: &str = "local_key"; 438e920a95Sopenharmony_ciconst CODE_SIGN_KEY_NAME_PREFIX: &str = "fs_verity_key"; 448e920a95Sopenharmony_ciconst PROFILE_STORE_EL1: &str = "/data/service/el1/public/profiles"; 458e920a95Sopenharmony_ciconst PROFILE_SEARCH_SLEEP_TIME: u64 = 200; 468e920a95Sopenharmony_ciconst PROFILE_SEARCH_SLEEP_OUT_TIME: u64 = 600; 478e920a95Sopenharmony_ciconst SUCCESS: i32 = 0; 488e920a95Sopenharmony_ci 498e920a95Sopenharmony_citype KeySerial = i32; 508e920a95Sopenharmony_ci 518e920a95Sopenharmony_ciextern "C" { 528e920a95Sopenharmony_ci fn InitLocalCertificate(cert_data: *mut u8, cert_size: *mut usize) -> i32; 538e920a95Sopenharmony_ci fn AddKey( 548e920a95Sopenharmony_ci type_name: *const u8, 558e920a95Sopenharmony_ci description: *const u8, 568e920a95Sopenharmony_ci payload: *const u8, 578e920a95Sopenharmony_ci plen: usize, 588e920a95Sopenharmony_ci ring_id: KeySerial, 598e920a95Sopenharmony_ci ) -> KeySerial; 608e920a95Sopenharmony_ci fn KeyctlRestrictKeyring( 618e920a95Sopenharmony_ci ring_id: KeySerial, 628e920a95Sopenharmony_ci type_name: *const u8, 638e920a95Sopenharmony_ci restriction: *const u8, 648e920a95Sopenharmony_ci ) -> KeySerial; 658e920a95Sopenharmony_ci fn CheckUserUnlock() -> bool; 668e920a95Sopenharmony_ci} 678e920a95Sopenharmony_ci 688e920a95Sopenharmony_cifn print_openssl_error_stack(error_stack: ErrorStack) { 698e920a95Sopenharmony_ci for error in error_stack.errors() { 708e920a95Sopenharmony_ci error!(LOG_LABEL, "{}", @public(error.to_string())); 718e920a95Sopenharmony_ci } 728e920a95Sopenharmony_ci} 738e920a95Sopenharmony_ci 748e920a95Sopenharmony_cifn get_local_key() -> Option<Vec<u8>> { 758e920a95Sopenharmony_ci let mut cert_size = CERT_DATA_MAX_SIZE; 768e920a95Sopenharmony_ci let mut cert_data = Vec::with_capacity(cert_size); 778e920a95Sopenharmony_ci let pcert = cert_data.as_mut_ptr(); 788e920a95Sopenharmony_ci 798e920a95Sopenharmony_ci unsafe { 808e920a95Sopenharmony_ci let ret = InitLocalCertificate(pcert, &mut cert_size); 818e920a95Sopenharmony_ci if ret == 0 { 828e920a95Sopenharmony_ci cert_data.set_len(cert_size); 838e920a95Sopenharmony_ci Some(cert_data) 848e920a95Sopenharmony_ci } else { 858e920a95Sopenharmony_ci None 868e920a95Sopenharmony_ci } 878e920a95Sopenharmony_ci } 888e920a95Sopenharmony_ci} 898e920a95Sopenharmony_ci 908e920a95Sopenharmony_ci/// parse key info 918e920a95Sopenharmony_ci/// [Serial][Flags][Usage][Expiry][Permissions][UID][GID][TypeName][Description]: [Summary] 928e920a95Sopenharmony_ci/// [0] [1] [2] [3] [4] [5] [6] [7] [8] [9] 938e920a95Sopenharmony_ci/// 3985ad4c I------ 1 perm 082f0000 0 0 keyring .fs-verity: empty 948e920a95Sopenharmony_cifn parse_key_info(line: String) -> Option<KeySerial> { 958e920a95Sopenharmony_ci let attrs: Vec<&str> = line.split_whitespace().collect(); 968e920a95Sopenharmony_ci if attrs.len() != 10 { 978e920a95Sopenharmony_ci return None; 988e920a95Sopenharmony_ci } 998e920a95Sopenharmony_ci if attrs[7] == KEYRING_TYPE && attrs[8].strip_suffix(':') == Some(FSVERITY_KEYRING_NAME) { 1008e920a95Sopenharmony_ci match KeySerial::from_str_radix(attrs[0], 16) { 1018e920a95Sopenharmony_ci Ok(x) => Some(x), 1028e920a95Sopenharmony_ci Err(error) => { 1038e920a95Sopenharmony_ci error!(LOG_LABEL, "Convert KeySerial failed: {}", error); 1048e920a95Sopenharmony_ci None 1058e920a95Sopenharmony_ci } 1068e920a95Sopenharmony_ci } 1078e920a95Sopenharmony_ci } else { 1088e920a95Sopenharmony_ci None 1098e920a95Sopenharmony_ci } 1108e920a95Sopenharmony_ci} 1118e920a95Sopenharmony_ci 1128e920a95Sopenharmony_cifn enable_key(key_id: KeySerial, key_name: &str, cert_data: &Vec<u8>) -> i32 { 1138e920a95Sopenharmony_ci let type_name = CString::new("asymmetric").expect("type name is invalid"); 1148e920a95Sopenharmony_ci let keyname = CString::new(key_name).expect("keyname is invalid"); 1158e920a95Sopenharmony_ci unsafe { 1168e920a95Sopenharmony_ci let ret: i32 = AddKey( 1178e920a95Sopenharmony_ci type_name.as_ptr(), 1188e920a95Sopenharmony_ci keyname.as_ptr(), 1198e920a95Sopenharmony_ci cert_data.as_ptr(), 1208e920a95Sopenharmony_ci cert_data.len(), 1218e920a95Sopenharmony_ci key_id, 1228e920a95Sopenharmony_ci ); 1238e920a95Sopenharmony_ci ret 1248e920a95Sopenharmony_ci } 1258e920a95Sopenharmony_ci} 1268e920a95Sopenharmony_ci 1278e920a95Sopenharmony_cifn enable_key_list(key_id: KeySerial, certs: Vec<Vec<u8>>, key_name_prefix: &str) -> i32 { 1288e920a95Sopenharmony_ci let prefix = String::from(key_name_prefix); 1298e920a95Sopenharmony_ci for (i, cert_data) in certs.iter().enumerate() { 1308e920a95Sopenharmony_ci let key_name = prefix.clone() + &i.to_string(); 1318e920a95Sopenharmony_ci let ret = enable_key(key_id, key_name.as_str(), cert_data); 1328e920a95Sopenharmony_ci if ret < 0 { 1338e920a95Sopenharmony_ci return ret; 1348e920a95Sopenharmony_ci } 1358e920a95Sopenharmony_ci } 1368e920a95Sopenharmony_ci SUCCESS 1378e920a95Sopenharmony_ci} 1388e920a95Sopenharmony_ci 1398e920a95Sopenharmony_ci/// parse proc_key_file to get keyring id 1408e920a95Sopenharmony_cifn get_keyring_id() -> Result<KeySerial, ()> { 1418e920a95Sopenharmony_ci let file = File::open(PROC_KEY_FILE_PATH).expect("Open /proc/keys failed"); 1428e920a95Sopenharmony_ci let lines = BufReader::new(file).lines(); 1438e920a95Sopenharmony_ci for line in lines.flatten() { 1448e920a95Sopenharmony_ci if line.contains(KEYRING_TYPE) && line.contains(FSVERITY_KEYRING_NAME) { 1458e920a95Sopenharmony_ci if let Some(keyid) = parse_key_info(line) { 1468e920a95Sopenharmony_ci return Ok(keyid); 1478e920a95Sopenharmony_ci } 1488e920a95Sopenharmony_ci } 1498e920a95Sopenharmony_ci } 1508e920a95Sopenharmony_ci error!(LOG_LABEL, "Get .fs-verity keyring id failed."); 1518e920a95Sopenharmony_ci Err(()) 1528e920a95Sopenharmony_ci} 1538e920a95Sopenharmony_ci 1548e920a95Sopenharmony_ci// enable all trusted keys 1558e920a95Sopenharmony_cifn enable_trusted_keys(key_id: KeySerial, root_cert: &PemCollection) { 1568e920a95Sopenharmony_ci let certs = match root_cert.to_der() { 1578e920a95Sopenharmony_ci Ok(der) => der, 1588e920a95Sopenharmony_ci Err(e) => { 1598e920a95Sopenharmony_ci print_openssl_error_stack(e); 1608e920a95Sopenharmony_ci Vec::new() 1618e920a95Sopenharmony_ci } 1628e920a95Sopenharmony_ci }; 1638e920a95Sopenharmony_ci if certs.is_empty() { 1648e920a95Sopenharmony_ci error!(LOG_LABEL, "empty trusted certs!"); 1658e920a95Sopenharmony_ci } 1668e920a95Sopenharmony_ci let ret = enable_key_list(key_id, certs, CODE_SIGN_KEY_NAME_PREFIX); 1678e920a95Sopenharmony_ci if ret < 0 { 1688e920a95Sopenharmony_ci cs_hisysevent::report_add_key_err("code_sign_keys", ret); 1698e920a95Sopenharmony_ci } 1708e920a95Sopenharmony_ci} 1718e920a95Sopenharmony_ci 1728e920a95Sopenharmony_cifn check_and_add_cert_path(root_cert: &PemCollection, cert_paths: &TrustCertPath) -> bool { 1738e920a95Sopenharmony_ci if Path::new(PROFILE_STORE_EL1).exists() { 1748e920a95Sopenharmony_ci if add_profile_cert_path(root_cert, cert_paths).is_err() { 1758e920a95Sopenharmony_ci error!(LOG_LABEL, "Add cert path from local profile err."); 1768e920a95Sopenharmony_ci } 1778e920a95Sopenharmony_ci info!(LOG_LABEL, "Finished cert path adding."); 1788e920a95Sopenharmony_ci true 1798e920a95Sopenharmony_ci } else { 1808e920a95Sopenharmony_ci false 1818e920a95Sopenharmony_ci } 1828e920a95Sopenharmony_ci} 1838e920a95Sopenharmony_ci 1848e920a95Sopenharmony_ci// start cert path ops thread add trusted cert & developer cert 1858e920a95Sopenharmony_cifn add_profile_cert_path_thread( 1868e920a95Sopenharmony_ci root_cert: PemCollection, 1878e920a95Sopenharmony_ci cert_paths: TrustCertPath, 1888e920a95Sopenharmony_ci) -> std::thread::JoinHandle<()> { 1898e920a95Sopenharmony_ci thread::spawn(move || { 1908e920a95Sopenharmony_ci // enable developer certs 1918e920a95Sopenharmony_ci info!(LOG_LABEL, "Starting enable developer cert."); 1928e920a95Sopenharmony_ci let start_time = Instant::now(); 1938e920a95Sopenharmony_ci loop { 1948e920a95Sopenharmony_ci if check_and_add_cert_path(&root_cert, &cert_paths) { 1958e920a95Sopenharmony_ci break; 1968e920a95Sopenharmony_ci } else if start_time.elapsed() >= Duration::from_secs(PROFILE_SEARCH_SLEEP_OUT_TIME) { 1978e920a95Sopenharmony_ci error!(LOG_LABEL, "Timeout while waiting for PROFILE_STORE_EL1."); 1988e920a95Sopenharmony_ci break; 1998e920a95Sopenharmony_ci } else { 2008e920a95Sopenharmony_ci thread::sleep(Duration::from_millis(PROFILE_SEARCH_SLEEP_TIME)); 2018e920a95Sopenharmony_ci } 2028e920a95Sopenharmony_ci } 2038e920a95Sopenharmony_ci }) 2048e920a95Sopenharmony_ci} 2058e920a95Sopenharmony_ci 2068e920a95Sopenharmony_ci// enable local key from local code sign SA 2078e920a95Sopenharmony_cifn enable_local_key(key_id: KeySerial) { 2088e920a95Sopenharmony_ci if let Some(cert_data) = get_local_key() { 2098e920a95Sopenharmony_ci let ret = enable_key(key_id, LOCAL_KEY_NAME, &cert_data); 2108e920a95Sopenharmony_ci if ret < 0 { 2118e920a95Sopenharmony_ci cs_hisysevent::report_add_key_err("local_key", ret); 2128e920a95Sopenharmony_ci error!(LOG_LABEL, "Enable local key failed"); 2138e920a95Sopenharmony_ci } 2148e920a95Sopenharmony_ci } 2158e920a95Sopenharmony_ci} 2168e920a95Sopenharmony_ci 2178e920a95Sopenharmony_ci// restrict fs-verity keyring, don't allow to add more keys 2188e920a95Sopenharmony_cifn restrict_keys(key_id: KeySerial) { 2198e920a95Sopenharmony_ci unsafe { 2208e920a95Sopenharmony_ci if KeyctlRestrictKeyring(key_id, ptr::null(), ptr::null()) < 0 { 2218e920a95Sopenharmony_ci error!(LOG_LABEL, "Restrict keyring err"); 2228e920a95Sopenharmony_ci } 2238e920a95Sopenharmony_ci } 2248e920a95Sopenharmony_ci} 2258e920a95Sopenharmony_ci 2268e920a95Sopenharmony_cifn enable_keys_after_user_unlock(key_id: KeySerial) { 2278e920a95Sopenharmony_ci if !unsafe { CheckUserUnlock() } { 2288e920a95Sopenharmony_ci restrict_keys(key_id); 2298e920a95Sopenharmony_ci return; 2308e920a95Sopenharmony_ci } 2318e920a95Sopenharmony_ci 2328e920a95Sopenharmony_ci // enable local code sign key 2338e920a95Sopenharmony_ci enable_local_key(key_id); 2348e920a95Sopenharmony_ci restrict_keys(key_id); 2358e920a95Sopenharmony_ci} 2368e920a95Sopenharmony_ci 2378e920a95Sopenharmony_ci/// enable trusted and local keys, and then restrict keyring 2388e920a95Sopenharmony_cipub fn enable_all_keys() { 2398e920a95Sopenharmony_ci let key_id = match get_keyring_id() { 2408e920a95Sopenharmony_ci Ok(id) => id, 2418e920a95Sopenharmony_ci Err(_) => { 2428e920a95Sopenharmony_ci error!(LOG_LABEL, "Failed to get keyring ID."); 2438e920a95Sopenharmony_ci return; 2448e920a95Sopenharmony_ci }, 2458e920a95Sopenharmony_ci }; 2468e920a95Sopenharmony_ci let root_cert = get_trusted_certs(); 2478e920a95Sopenharmony_ci // enable device keys and authed source 2488e920a95Sopenharmony_ci enable_trusted_keys(key_id, &root_cert); 2498e920a95Sopenharmony_ci 2508e920a95Sopenharmony_ci let cert_paths = get_cert_path(); 2518e920a95Sopenharmony_ci // enable trusted cert in prebuilt config 2528e920a95Sopenharmony_ci if cert_paths.add_cert_paths().is_err() { 2538e920a95Sopenharmony_ci error!(LOG_LABEL, "Add trusted cert path err."); 2548e920a95Sopenharmony_ci } 2558e920a95Sopenharmony_ci 2568e920a95Sopenharmony_ci let cert_thread = add_profile_cert_path_thread(root_cert, cert_paths); 2578e920a95Sopenharmony_ci enable_keys_after_user_unlock(key_id); 2588e920a95Sopenharmony_ci 2598e920a95Sopenharmony_ci if let Err(e) = cert_thread.join() { 2608e920a95Sopenharmony_ci error!(LOG_LABEL, "add cert path thread panicked: {:?}", e); 2618e920a95Sopenharmony_ci } 2628e920a95Sopenharmony_ci info!(LOG_LABEL, "Fnished enable all keys."); 2638e920a95Sopenharmony_ci} 264