* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
mod hsd;
mod evp;
mod ffi;
mod img_hash_check;
mod macros;
use core::{ffi::{c_char, CStr}, mem::ManuallyDrop, ptr};
use hsd::HashSignedData;
use img_hash_check::ImgHashData;
use img_hash_check::ReadLeBytes;
#[no_mangle]
pub unsafe extern fn LoadHashSignedData(signed_data: *const c_char)
-> *const HashSignedData
{
if signed_data.is_null() {
updaterlog!(ERROR, "signed data is null");
return ptr::null();
}
let signed_data_str: &CStr = unsafe { CStr::from_ptr(signed_data) };
let hsd = signed_data_str.to_str();
if hsd.is_err() {
updaterlog!(ERROR, "hash signed data str format is invalid {:?}", signed_data_str);
return ptr::null();
}
match HashSignedData::try_from(hsd.unwrap()) {
Ok(hsd) => {
updaterlog!(INFO, "hash signed data parse successful!");
Box::into_raw(Box::new(hsd))
},
Err(err) => {
updaterlog!(ERROR, "hash signed data parse failed, err is {}", err);
ptr::null()
}
}
}
#[no_mangle]
pub unsafe extern fn GetSigFromHashData(signed_data: *const HashSignedData,
out: *mut u8, out_len: usize, file_name: *const c_char) -> usize
{
if out.is_null() || file_name.is_null() || signed_data.is_null() {
updaterlog!(ERROR, "input invalid, null status hash:{} file_name:{} signed_data:{}",
out.is_null(), file_name.is_null(), signed_data.is_null());
return 0;
}
let signed_data = ManuallyDrop::new(unsafe { &*signed_data });
let file_name_c_str: &CStr = unsafe { CStr::from_ptr(file_name) };
let file_name = match file_name_c_str.to_str() {
Ok(file_name) => file_name,
Err(_) => {
updaterlog!(ERROR, "filename is invalid utf8 str");
return 0;
}
};
let sig = match signed_data.get_sig_for_file(file_name) {
Ok(sig) => sig,
Err(err) => {
unsafe { ffi::ERR_print_errors_cb(ffi::err_print_cb, ptr::null_mut()); }
updaterlog!(ERROR, "get sig for file {} failed, err is {}", file_name, err);
return 0;
}
};
if sig.len() > out_len {
updaterlog!(ERROR, "out is too small to hold signature");
return 0;
}
unsafe { ptr::copy_nonoverlapping(sig.as_ptr(), out, sig.len()); }
updaterlog!(INFO, "get sig succeed for {}", file_name);
sig.len()
}
#[no_mangle]
pub unsafe extern fn ReleaseHashSignedData(signed_data: *const HashSignedData)
{
if signed_data.is_null() {
updaterlog!(ERROR, "signed data is null");
return;
}
unsafe { drop(Box::from_raw(signed_data as *mut HashSignedData)); }
updaterlog!(INFO, "release hash signed data");
}
#[no_mangle]
pub unsafe extern fn LoadImgHashData(hash_data: *const u8, len: usize)
-> *const ImgHashData<u32>
{
if hash_data.is_null() {
updaterlog!(ERROR, "hash data is null");
return ptr::null();
}
let hash_data_vec: Vec<u8> = unsafe {Vec::from_raw_parts(hash_data as *mut u8, len, len)};
match ImgHashData::load_img_hash_data(&hash_data_vec[..]) {
Ok(hash_data) => {
std::mem::forget(hash_data_vec);
updaterlog!(INFO, "hash data parse successful!");
Box::into_raw(Box::new(hash_data))
},
Err(err) => {
std::mem::forget(hash_data_vec);
updaterlog!(ERROR, "hash data parse failed, err is {}", err);
ptr::null()
}
}
}
#[no_mangle]
pub unsafe extern fn LoadImgHashDataNew(hash_data: *const u8, len: usize)
-> *const ImgHashData<u64>
{
if hash_data.is_null() {
updaterlog!(ERROR, "hash data is null");
return ptr::null();
}
let hash_data_vec: Vec<u8> = unsafe {Vec::from_raw_parts(hash_data as *mut u8, len, len)};
match ImgHashData::load_img_hash_data(&hash_data_vec[..]) {
Ok(hash_data) => {
std::mem::forget(hash_data_vec);
updaterlog!(INFO, "hash data parse successful!");
Box::into_raw(Box::new(hash_data))
},
Err(err) => {
std::mem::forget(hash_data_vec);
updaterlog!(ERROR, "hash data parse failed, err is {}", err);
ptr::null()
}
}
}
pub unsafe extern fn check_data_hash_template<T>(img_hash_data: *const ImgHashData<T>,
img_name: *const c_char, start: T, end: T, hash_value: *const u8, len: usize) -> bool
where T: ReadLeBytes + std::hash::Hash + std::cmp::Eq + std::fmt::Display + std::default::Default
{
if img_hash_data.is_null() || img_name.is_null() || hash_value.is_null() {
updaterlog!(ERROR, "input invalid, null status img_hash_data:{} img_name:{} hash_value:{}",
img_hash_data.is_null(), img_name.is_null(), hash_value.is_null());
return false;
}
let hash_data = ManuallyDrop::new( unsafe { &*img_hash_data });
let img_name_c_str: &CStr = unsafe { CStr::from_ptr(img_name) };
let img_name = match img_name_c_str.to_str() {
Ok(img_name) => img_name.to_owned(),
Err(_) => {
updaterlog!(ERROR, "img_name is invalid utf8 str");
return false;
}
};
let hash_value_vec: Vec<u8> = unsafe {Vec::from_raw_parts(hash_value as *mut u8, len, len)};
updaterlog!(DEBUG, "check_data_hash, img_name: {}, start: {}, hash_value_vec: {:?}", img_name, start, hash_value_vec);
let is_valid = hash_data.check_img_hash(img_name, start, end, &hash_value_vec[..]);
std::mem::forget(hash_value_vec);
is_valid
}
#[no_mangle]
pub unsafe extern fn check_data_hash(img_hash_data: *const ImgHashData<u32>,
img_name: *const c_char, start: u32, end: u32, hash_value: *const u8, len: usize) -> bool
{
check_data_hash_template(img_hash_data, img_name, start, end, hash_value, len)
}
#[no_mangle]
pub unsafe extern fn CheckDataHashNew(img_hash_data: *const ImgHashData<u64>,
img_name: *const c_char, start: u64, end: u64, hash_value: *const u8, len: usize) -> bool
{
check_data_hash_template(img_hash_data, img_name, start, end, hash_value, len)
}
#[no_mangle]
pub unsafe extern fn ReleaseImgHashData(hash_data: *const ImgHashData<u32>)
{
if hash_data.is_null() {
updaterlog!(ERROR, "image hash data is null");
return;
}
unsafe { drop(Box::from_raw(hash_data as *mut ImgHashData<u32>)); }
updaterlog!(INFO, "release image hash data");
}
#[no_mangle]
pub unsafe extern fn ReleaseImgHashDataNew(hash_data: *const ImgHashData<u64>)
{
if hash_data.is_null() {
updaterlog!(ERROR, "image hash data is null");
return;
}
unsafe { drop(Box::from_raw(hash_data as *mut ImgHashData<u64>)); }
updaterlog!(INFO, "release image hash data");
}