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