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
28 /// load hash signed data from buffer, then you can verify them by VerifyHashBySignedData
29 ///
30 /// # Safety
31 ///
32 /// signed_data must contain a valid nul terminator at the end
33 #[no_mangle]
LoadHashSignedData(signed_data: *const c_char) -> *const HashSignedData34 pub unsafe extern fn LoadHashSignedData(signed_data: *const c_char)
35 -> *const HashSignedData
36 {
37 if signed_data.is_null() {
38 updaterlog!(ERROR, "signed data is null");
39 return ptr::null();
40 }
41
42 let signed_data_str: &CStr = unsafe { CStr::from_ptr(signed_data) };
43 let hsd = signed_data_str.to_str();
44 if hsd.is_err() {
45 updaterlog!(ERROR, "hash signed data str format is invalid {:?}", signed_data_str);
46 return ptr::null();
47 }
48
49 match HashSignedData::try_from(hsd.unwrap()) {
50 Ok(hsd) => {
51 updaterlog!(INFO, "hash signed data parse successful!");
52 Box::into_raw(Box::new(hsd))
53 },
54 Err(err) => {
55 updaterlog!(ERROR, "hash signed data parse failed, err is {}", err);
56 ptr::null()
57 }
58 }
59 }
60
61 /// Get signature of file from hash signed data
62 ///
63 /// # Safety
64 ///
65 /// file_name should be a valid utf8 str, ended with a nul terminator
66 #[no_mangle]
GetSigFromHashData(signed_data: *const HashSignedData, out: *mut u8, out_len: usize, file_name: *const c_char) -> usize67 pub unsafe extern fn GetSigFromHashData(signed_data: *const HashSignedData,
68 out: *mut u8, out_len: usize, file_name: *const c_char) -> usize
69 {
70 if out.is_null() || file_name.is_null() || signed_data.is_null() {
71 updaterlog!(ERROR, "input invalid, null status hash:{} file_name:{} signed_data:{}",
72 out.is_null(), file_name.is_null(), signed_data.is_null());
73 return 0;
74 }
75 let signed_data = ManuallyDrop::new(unsafe { &*signed_data });
76 let file_name_c_str: &CStr = unsafe { CStr::from_ptr(file_name) };
77 let file_name = match file_name_c_str.to_str() {
78 Ok(file_name) => file_name,
79 Err(_) => {
80 updaterlog!(ERROR, "filename is invalid utf8 str");
81 return 0;
82 }
83 };
84 let sig = match signed_data.get_sig_for_file(file_name) {
85 Ok(sig) => sig,
86 Err(err) => {
87 unsafe { ffi::ERR_print_errors_cb(ffi::err_print_cb, ptr::null_mut()); }
88 updaterlog!(ERROR, "get sig for file {} failed, err is {}", file_name, err);
89 return 0;
90 }
91 };
92 if sig.len() > out_len {
93 updaterlog!(ERROR, "out is too small to hold signature");
94 return 0;
95 }
96 unsafe { ptr::copy_nonoverlapping(sig.as_ptr(), out, sig.len()); }
97 // hash is owned by a vector in c++, it's memory is allocated in c++, so need to forget it in rust
98 updaterlog!(INFO, "get sig succeed for {}", file_name);
99 sig.len()
100 }
101
102 /// release hash signed data when you no longer need it
103 ///
104 /// # Safety
105 ///
106 /// HashSignedData should be a return value of LoadHashSignedData
107 #[no_mangle]
ReleaseHashSignedData(signed_data: *const HashSignedData)108 pub unsafe extern fn ReleaseHashSignedData(signed_data: *const HashSignedData)
109 {
110 if signed_data.is_null() {
111 updaterlog!(ERROR, "signed data is null");
112 return;
113 }
114 unsafe { drop(Box::from_raw(signed_data as *mut HashSignedData)); }
115 updaterlog!(INFO, "release hash signed data");
116 }
117
118 /// load hash signed data from buffer, then you can verify them by VerifyHashBySignedData
119 ///
120 /// # Safety
121 ///
122 /// signed_data must contain a valid nul terminator at the end
123 #[no_mangle]
LoadImgHashData(hash_data: *const u8, len: usize) -> *const ImgHashData124 pub unsafe extern fn LoadImgHashData(hash_data: *const u8, len: usize)
125 -> *const ImgHashData
126 {
127 if hash_data.is_null() {
128 updaterlog!(ERROR, "hash data is null");
129 return ptr::null();
130 }
131
132 let hash_data_vec: Vec<u8> = unsafe {Vec::from_raw_parts(hash_data as *mut u8, len, len)};
133 match ImgHashData::load_img_hash_data(&hash_data_vec[..]) {
134 Ok(hash_data) => {
135 std::mem::forget(hash_data_vec);
136 updaterlog!(INFO, "hash data parse successful!");
137 Box::into_raw(Box::new(hash_data))
138 },
139 Err(err) => {
140 std::mem::forget(hash_data_vec);
141 updaterlog!(ERROR, "hash data parse failed, err is {}", err);
142 ptr::null()
143 }
144 }
145 }
146
147 /// check hash data from buffer, then you can verify them by VerifyHashBySignedData
148 ///
149 /// # Safety
150 ///
151 /// signed_data must contain a valid nul terminator at the end
152 #[no_mangle]
check_data_hash(img_hash_data: *const ImgHashData, img_name: *const c_char, start: u32, end: u32, hash_value: *const u8, len: usize) -> bool153 pub unsafe extern fn check_data_hash(img_hash_data: *const ImgHashData,
154 img_name: *const c_char, start: u32, end: u32, hash_value: *const u8, len: usize) -> bool
155 {
156 if img_hash_data.is_null() || img_name.is_null() || hash_value.is_null() {
157 updaterlog!(ERROR, "input invalid, null status img_hash_data:{} img_name:{} hash_value:{}",
158 img_hash_data.is_null(), img_name.is_null(), hash_value.is_null());
159 return false;
160 }
161
162 let hash_data = ManuallyDrop::new( unsafe { &*img_hash_data });
163 let img_name_c_str: &CStr = unsafe { CStr::from_ptr(img_name) };
164 let img_name = match img_name_c_str.to_str() {
165 Ok(img_name) => img_name.to_owned(),
166 Err(_) => {
167 updaterlog!(ERROR, "img_name is invalid utf8 str");
168 return false;
169 }
170 };
171
172 let hash_value_vec: Vec<u8> = unsafe {Vec::from_raw_parts(hash_value as *mut u8, len, len)};
173 updaterlog!(INFO, "check_data_hash, img_name: {}, start: {}, hash_value_vec: {:?}", img_name, start, hash_value_vec);
174 let is_valid = hash_data.check_img_hash(img_name, start, end, &hash_value_vec[..]);
175 std::mem::forget(hash_value_vec);
176 is_valid
177 }
178
179 /// release hash signed data when you no longer need it
180 ///
181 /// # Safety
182 ///
183 /// HashSignedData should be a return value of LoadHashSignedData
184 #[no_mangle]
ReleaseImgHashData(hash_data: *const ImgHashData)185 pub unsafe extern fn ReleaseImgHashData(hash_data: *const ImgHashData)
186 {
187 if hash_data.is_null() {
188 updaterlog!(ERROR, "image hash data is null");
189 return;
190 }
191 unsafe { drop(Box::from_raw(hash_data as *mut ImgHashData)); }
192 updaterlog!(INFO, "release image hash data");
193 }