• 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 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 }