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