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 //! This lib is used by updater to parse and get sig from hash signe data file: 17 18 mod hsd; 19 mod evp; 20 mod ffi; 21 mod img_hash_check; 22 mod macros; 23 24 use core::{ffi::{c_char, CStr}, mem::ManuallyDrop, ptr}; 25 use hsd::HashSignedData; 26 use img_hash_check::ImgHashData; 27 use img_hash_check::ReadLeBytes; 28 29 /// load hash signed data from buffer, then you can verify them by VerifyHashBySignedData 30 /// 31 /// # Safety 32 /// 33 /// signed_data must contain a valid nul terminator at the end 34 #[no_mangle] 35 pub unsafe extern fn LoadHashSignedData(signed_data: *const c_char) 36 -> *const HashSignedData 37 { 38 if signed_data.is_null() { 39 updaterlog!(ERROR, "signed data is null"); 40 return ptr::null(); 41 } 42 43 let signed_data_str: &CStr = unsafe { CStr::from_ptr(signed_data) }; 44 let hsd = signed_data_str.to_str(); 45 if hsd.is_err() { 46 updaterlog!(ERROR, "hash signed data str format is invalid {:?}", signed_data_str); 47 return ptr::null(); 48 } 49 50 match HashSignedData::try_from(hsd.unwrap()) { 51 Ok(hsd) => { 52 updaterlog!(INFO, "hash signed data parse successful!"); 53 Box::into_raw(Box::new(hsd)) 54 }, 55 Err(err) => { 56 updaterlog!(ERROR, "hash signed data parse failed, err is {}", err); 57 ptr::null() 58 } 59 } 60 } 61 62 /// Get signature of file from hash signed data 63 /// 64 /// # Safety 65 /// 66 /// file_name should be a valid utf8 str, ended with a nul terminator 67 #[no_mangle] 68 pub unsafe extern fn GetSigFromHashData(signed_data: *const HashSignedData, 69 out: *mut u8, out_len: usize, file_name: *const c_char) -> usize 70 { 71 if out.is_null() || file_name.is_null() || signed_data.is_null() { 72 updaterlog!(ERROR, "input invalid, null status hash:{} file_name:{} signed_data:{}", 73 out.is_null(), file_name.is_null(), signed_data.is_null()); 74 return 0; 75 } 76 let signed_data = ManuallyDrop::new(unsafe { &*signed_data }); 77 let file_name_c_str: &CStr = unsafe { CStr::from_ptr(file_name) }; 78 let file_name = match file_name_c_str.to_str() { 79 Ok(file_name) => file_name, 80 Err(_) => { 81 updaterlog!(ERROR, "filename is invalid utf8 str"); 82 return 0; 83 } 84 }; 85 let sig = match signed_data.get_sig_for_file(file_name) { 86 Ok(sig) => sig, 87 Err(err) => { 88 unsafe { ffi::ERR_print_errors_cb(ffi::err_print_cb, ptr::null_mut()); } 89 updaterlog!(ERROR, "get sig for file {} failed, err is {}", file_name, err); 90 return 0; 91 } 92 }; 93 if sig.len() > out_len { 94 updaterlog!(ERROR, "out is too small to hold signature"); 95 return 0; 96 } 97 unsafe { ptr::copy_nonoverlapping(sig.as_ptr(), out, sig.len()); } 98 // hash is owned by a vector in c++, it's memory is allocated in c++, so need to forget it in rust 99 updaterlog!(INFO, "get sig succeed for {}", file_name); 100 sig.len() 101 } 102 103 /// release hash signed data when you no longer need it 104 /// 105 /// # Safety 106 /// 107 /// HashSignedData should be a return value of LoadHashSignedData 108 #[no_mangle] 109 pub unsafe extern fn ReleaseHashSignedData(signed_data: *const HashSignedData) 110 { 111 if signed_data.is_null() { 112 updaterlog!(ERROR, "signed data is null"); 113 return; 114 } 115 unsafe { drop(Box::from_raw(signed_data as *mut HashSignedData)); } 116 updaterlog!(INFO, "release hash signed data"); 117 } 118 119 /// load hash signed data from buffer, then you can verify them by check_data_hash 120 /// 121 /// # Safety 122 /// 123 /// hash_data must contain a valid nul terminator at the end 124 #[no_mangle] 125 pub unsafe extern fn LoadImgHashData(hash_data: *const u8, len: usize) 126 -> *const ImgHashData<u32> 127 { 128 if hash_data.is_null() { 129 updaterlog!(ERROR, "hash data is null"); 130 return ptr::null(); 131 } 132 133 let hash_data_vec: Vec<u8> = unsafe {Vec::from_raw_parts(hash_data as *mut u8, len, len)}; 134 match ImgHashData::load_img_hash_data(&hash_data_vec[..]) { 135 Ok(hash_data) => { 136 std::mem::forget(hash_data_vec); 137 updaterlog!(INFO, "hash data parse successful!"); 138 Box::into_raw(Box::new(hash_data)) 139 }, 140 Err(err) => { 141 std::mem::forget(hash_data_vec); 142 updaterlog!(ERROR, "hash data parse failed, err is {}", err); 143 ptr::null() 144 } 145 } 146 } 147 148 /// load hash signed data from buffer, then you can verify them by check_data_hash 149 /// 150 /// # Safety 151 /// 152 /// hash_data must contain a valid nul terminator at the end 153 #[no_mangle] 154 pub unsafe extern fn LoadImgHashDataNew(hash_data: *const u8, len: usize) 155 -> *const ImgHashData<u64> 156 { 157 if hash_data.is_null() { 158 updaterlog!(ERROR, "hash data is null"); 159 return ptr::null(); 160 } 161 162 let hash_data_vec: Vec<u8> = unsafe {Vec::from_raw_parts(hash_data as *mut u8, len, len)}; 163 match ImgHashData::load_img_hash_data(&hash_data_vec[..]) { 164 Ok(hash_data) => { 165 std::mem::forget(hash_data_vec); 166 updaterlog!(INFO, "hash data parse successful!"); 167 Box::into_raw(Box::new(hash_data)) 168 }, 169 Err(err) => { 170 std::mem::forget(hash_data_vec); 171 updaterlog!(ERROR, "hash data parse failed, err is {}", err); 172 ptr::null() 173 } 174 } 175 } 176 177 /// check hash data from buffer 178 /// 179 /// # Safety 180 /// 181 /// signed_data must contain a valid nul terminator at the end 182 // #[no_mangle] 183 pub unsafe extern fn check_data_hash_template<T>(img_hash_data: *const ImgHashData<T>, 184 img_name: *const c_char, start: T, end: T, hash_value: *const u8, len: usize) -> bool 185 where T: ReadLeBytes + std::hash::Hash + std::cmp::Eq + std::fmt::Display + std::default::Default 186 { 187 if img_hash_data.is_null() || img_name.is_null() || hash_value.is_null() { 188 updaterlog!(ERROR, "input invalid, null status img_hash_data:{} img_name:{} hash_value:{}", 189 img_hash_data.is_null(), img_name.is_null(), hash_value.is_null()); 190 return false; 191 } 192 193 let hash_data = ManuallyDrop::new( unsafe { &*img_hash_data }); 194 let img_name_c_str: &CStr = unsafe { CStr::from_ptr(img_name) }; 195 let img_name = match img_name_c_str.to_str() { 196 Ok(img_name) => img_name.to_owned(), 197 Err(_) => { 198 updaterlog!(ERROR, "img_name is invalid utf8 str"); 199 return false; 200 } 201 }; 202 203 let hash_value_vec: Vec<u8> = unsafe {Vec::from_raw_parts(hash_value as *mut u8, len, len)}; 204 updaterlog!(INFO, "check_data_hash, img_name: {}, start: {}, hash_value_vec: {:?}", img_name, start, hash_value_vec); 205 let is_valid = hash_data.check_img_hash(img_name, start, end, &hash_value_vec[..]); 206 std::mem::forget(hash_value_vec); 207 is_valid 208 } 209 210 /// check hash data from buffer 211 /// 212 /// # Safety 213 /// 214 /// signed_data must contain a valid nul terminator at the end 215 #[no_mangle] 216 pub unsafe extern fn check_data_hash(img_hash_data: *const ImgHashData<u32>, 217 img_name: *const c_char, start: u32, end: u32, hash_value: *const u8, len: usize) -> bool 218 { 219 check_data_hash_template(img_hash_data, img_name, start, end, hash_value, len) 220 } 221 222 /// check hash data from buffer 223 /// 224 /// # Safety 225 /// 226 /// signed_data must contain a valid nul terminator at the end 227 #[no_mangle] 228 pub unsafe extern fn CheckDataHashNew(img_hash_data: *const ImgHashData<u64>, 229 img_name: *const c_char, start: u64, end: u64, hash_value: *const u8, len: usize) -> bool 230 { 231 check_data_hash_template(img_hash_data, img_name, start, end, hash_value, len) 232 } 233 234 /// release hash signed data when you no longer need it 235 /// 236 /// # Safety 237 /// 238 /// HashSignedData should be a return value of LoadHashSignedData 239 #[no_mangle] 240 pub unsafe extern fn ReleaseImgHashData(hash_data: *const ImgHashData<u32>) 241 { 242 if hash_data.is_null() { 243 updaterlog!(ERROR, "image hash data is null"); 244 return; 245 } 246 unsafe { drop(Box::from_raw(hash_data as *mut ImgHashData<u32>)); } 247 updaterlog!(INFO, "release image hash data"); 248 } 249 250 /// release hash signed data when you no longer need it 251 /// 252 /// # Safety 253 /// 254 /// HashSignedData should be a return value of LoadHashSignedData 255 #[no_mangle] 256 pub unsafe extern fn ReleaseImgHashDataNew(hash_data: *const ImgHashData<u64>) 257 { 258 if hash_data.is_null() { 259 updaterlog!(ERROR, "image hash data is null"); 260 return; 261 } 262 unsafe { drop(Box::from_raw(hash_data as *mut ImgHashData<u64>)); } 263 updaterlog!(INFO, "release image hash data"); 264 }