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 18mod hsd; 19mod evp; 20mod ffi; 21mod img_hash_check; 22mod macros; 23 24use core::{ffi::{c_char, CStr}, mem::ManuallyDrop, ptr}; 25use hsd::HashSignedData; 26use img_hash_check::ImgHashData; 27use 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] 35pub 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] 68pub 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] 109pub 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] 125pub 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] 154pub 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] 183pub 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] 216pub 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] 228pub 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] 240pub 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] 256pub 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}