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,
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 extern "C" {
InitLocalCertificate(cert_data: *mut u8, cert_size: *mut usize) -> i3252 fn InitLocalCertificate(cert_data: *mut u8, cert_size: *mut usize) -> i32;
AddKey( type_name: *const u8, description: *const u8, payload: *const u8, plen: usize, ring_id: KeySerial, ) -> KeySerial53 fn AddKey(
54 type_name: *const u8,
55 description: *const u8,
56 payload: *const u8,
57 plen: usize,
58 ring_id: KeySerial,
59 ) -> KeySerial;
KeyctlRestrictKeyring( ring_id: KeySerial, type_name: *const u8, restriction: *const u8, ) -> KeySerial60 fn KeyctlRestrictKeyring(
61 ring_id: KeySerial,
62 type_name: *const u8,
63 restriction: *const u8,
64 ) -> KeySerial;
CheckUserUnlock() -> bool65 fn CheckUserUnlock() -> bool;
66 }
67
print_openssl_error_stack(error_stack: ErrorStack)68 fn 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
get_local_key() -> Option<Vec<u8>>74 fn 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
parse_key_info(line: String) -> Option<KeySerial>94 fn 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
enable_key(key_id: KeySerial, key_name: &str, cert_data: &Vec<u8>) -> i32112 fn 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
enable_key_list(key_id: KeySerial, certs: Vec<Vec<u8>>, key_name_prefix: &str) -> i32127 fn 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
get_keyring_id() -> Result<KeySerial, ()>140 fn 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
enable_trusted_keys(key_id: KeySerial, root_cert: &PemCollection)155 fn 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
check_and_add_cert_path(root_cert: &PemCollection, cert_paths: &TrustCertPath) -> bool172 fn 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
add_profile_cert_path_thread( root_cert: PemCollection, cert_paths: TrustCertPath, ) -> std::thread::JoinHandle<()>185 fn 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
enable_local_key(key_id: KeySerial)207 fn 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
restrict_keys(key_id: KeySerial)218 fn 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
enable_keys_after_user_unlock(key_id: KeySerial)226 fn 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
enable_all_keys()238 pub 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