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 std::fs::File;
17 use std::ffi::{c_char, CString};
18 use std::io::{BufRead, BufReader};
19 use std::option::Option;
20 use std::ptr;
21 use std::thread::sleep_ms;
22 use std::vec::Vec;
23
24 use hilog_rust::{error, hilog, HiLogLabel, LogType};
25 use super::cs_hisysevent;
26 use super::cert_utils;
27
28 const LOG_LABEL: HiLogLabel = HiLogLabel {
29 log_type: LogType::LogCore,
30 domain: 0xd002f00, // security domain
31 tag: "CODE_SIGN"
32 };
33
34 const CERT_DATA_MAX_SIZE: usize = 8192;
35 const PROC_KEY_FILE_PATH: &str = "/proc/keys";
36 const KEYRING_TYPE: &str = "keyring";
37 const FSVERITY_KEYRING_NAME: &str = ".fs-verity";
38 const LOCAL_KEY_NAME: &str = "local_key";
39 const CODE_SIGN_KEY_NAME_PREFIX: &str = "fs_verity_key";
40 const SUCCESS: i32 = 0;
41
42 // retry to get local cert
43 const LOCAL_CERT_MAX_RETRY_TIMES: i32 = 5;
44 const SLEEP_MILLI_SECONDS: u32 = 50;
45
46 type KeySerial = i32;
47
48 extern "C" {
InitLocalCertificate(cert_data: *mut u8, cert_size: *mut usize) -> i3249 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) -> KeySerial50 fn AddKey(type_name: *const u8, description: *const u8, payload: *const u8,
51 plen: usize, ring_id: KeySerial) -> KeySerial;
KeyctlRestrictKeyring(ring_id: KeySerial, type_name: *const u8, restriction: *const u8) -> KeySerial52 fn KeyctlRestrictKeyring(ring_id: KeySerial, type_name: *const u8,
53 restriction: *const u8) -> KeySerial;
54 }
55
get_local_key() -> Option<Vec<u8>>56 fn get_local_key() -> Option<Vec<u8>>
57 {
58 let mut cert_size = CERT_DATA_MAX_SIZE;
59 let mut cert_data = Vec::with_capacity(cert_size);
60 let pcert = cert_data.as_mut_ptr();
61 unsafe {
62 if InitLocalCertificate(pcert, &mut cert_size) == 0 {
63 cert_data.set_len(cert_size);
64 Some(cert_data)
65 } else {
66 None
67 }
68 }
69 }
70
71 /// parse key info
72 /// [Serial][Flags][Usage][Expiry][Permissions][UID][GID][TypeName][Description]: [Summary]
73 /// [0] [1] [2] [3] [4] [5] [6] [7] [8] [9]
74 /// 3985ad4c I------ 1 perm 082f0000 0 0 keyring .fs-verity: empty
parse_key_info(line: String) -> Option<KeySerial>75 fn parse_key_info(line: String) -> Option<KeySerial>
76 {
77 let attrs: Vec<&str> = line.split_whitespace().collect();
78 if attrs.len() != 10 {
79 return None;
80 }
81 if attrs[7] == KEYRING_TYPE && attrs[8].strip_suffix(':') == Some(FSVERITY_KEYRING_NAME) {
82 match KeySerial::from_str_radix(attrs[0], 16) {
83 Ok(x) => Some(x),
84 Err(error) => {
85 error!(LOG_LABEL, "Convert KeySerial failed: {}", error);
86 None
87 }
88 }
89 } else {
90 None
91 }
92 }
93
enable_key(key_id: KeySerial, key_name: &str, cert_data: &Vec<u8>) -> i3294 fn enable_key(key_id: KeySerial, key_name: &str, cert_data: &Vec<u8>) -> i32
95 {
96 let type_name = CString::new("asymmetric").expect("type name is invalid");
97 let keyname = CString::new(key_name).expect("keyname is invalid");
98 unsafe {
99 let ret: i32 = AddKey(type_name.as_ptr(), keyname.as_ptr(), cert_data.as_ptr(), cert_data.len(), key_id);
100 ret
101 }
102 }
103
enable_key_list(key_id: KeySerial, certs: Vec<Vec<u8>>) -> i32104 fn enable_key_list(key_id: KeySerial, certs: Vec<Vec<u8>>) -> i32
105 {
106 let prefix = String::from(CODE_SIGN_KEY_NAME_PREFIX);
107 for (i, cert_data) in certs.iter().enumerate() {
108 let key_name = prefix.clone() + &i.to_string();
109 let ret = enable_key(key_id, key_name.as_str(), cert_data);
110 if ret < 0 {
111 return ret;
112 }
113 }
114 SUCCESS
115 }
116
117 /// parse proc_key_file to get keyring id
get_keyring_id() -> Result<KeySerial, ()>118 fn get_keyring_id() -> Result<KeySerial, ()>
119 {
120 let file = File::open(PROC_KEY_FILE_PATH).expect("Open /proc/keys failed");
121 let lines = BufReader::new(file).lines();
122 for line in lines.flatten() {
123 if line.contains(KEYRING_TYPE) && line.contains(FSVERITY_KEYRING_NAME) {
124 if let Some(keyid) = parse_key_info(line) {
125 return Ok(keyid);
126 }
127 }
128 }
129 error!(LOG_LABEL, "Get .fs-verity keyring id failed.");
130 Err(())
131 }
132
133 // enable all trusted keys
enable_trusted_keys(key_id: KeySerial) -> Result<(), ()>134 fn enable_trusted_keys(key_id: KeySerial) -> Result<(), ()>
135 {
136 let certs = cert_utils::get_trusted_certs();
137 let ret = enable_key_list(key_id, certs);
138 if ret < 0 {
139 cs_hisysevent::report_add_key_err("code_sign_keys", ret);
140 return Err(());
141 }
142 Ok(())
143 }
144
145 // enable local key from local code sign SA
enable_local_key(key_id: KeySerial) -> Result<(), ()>146 fn enable_local_key(key_id: KeySerial) -> Result<(), ()>
147 {
148 let mut times = 0;
149 let cert_data = loop {
150 match get_local_key() {
151 Some(key) => {
152 break key;
153 },
154 None => {
155 error!(LOG_LABEL, "Get local key failed, may try again.");
156 }
157 }
158 times += 1;
159 if times == LOCAL_CERT_MAX_RETRY_TIMES {
160 error!(LOG_LABEL, "Local key is not avaliable.");
161 return Err(());
162 }
163 sleep_ms(SLEEP_MILLI_SECONDS);
164 };
165 let ret = enable_key(key_id, LOCAL_KEY_NAME, &cert_data);
166 if ret < 0 {
167 cs_hisysevent::report_add_key_err("local_key", ret);
168 error!(LOG_LABEL, "Enable local key failed");
169 return Err(());
170 }
171 Ok(())
172 }
173
174 // restrict fs-verity keyring, don't allow to add more keys
restrict_keys(key_id: KeySerial) -> Result<(), ()>175 fn restrict_keys(key_id: KeySerial) -> Result<(), ()>
176 {
177 unsafe {
178 if KeyctlRestrictKeyring(key_id, ptr::null(), ptr::null()) < 0 {
179 error!(LOG_LABEL, "Restrict keyring err");
180 return Err(());
181 }
182 }
183 Ok(())
184 }
185
186 /// enable trusted and local keys, and then restrict keyring
enable_all_keys() -> Result<(), ()>187 pub fn enable_all_keys() -> Result<(), ()>
188 {
189 let key_id = get_keyring_id()?;
190 enable_trusted_keys(key_id)?;
191 enable_local_key(key_id)?;
192 restrict_keys(key_id)?;
193 Ok(())
194 }