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]
LoadHashSignedData(signed_data: *const c_char) -> *const HashSignedData35 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]
GetSigFromHashData(signed_data: *const HashSignedData, out: *mut u8, out_len: usize, file_name: *const c_char) -> usize68 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]
ReleaseHashSignedData(signed_data: *const HashSignedData)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]
LoadImgHashData(hash_data: *const u8, len: usize) -> *const ImgHashData<u32>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]
LoadImgHashDataNew(hash_data: *const u8, len: usize) -> *const ImgHashData<u64>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]
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::Default183 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]
check_data_hash(img_hash_data: *const ImgHashData<u32>, img_name: *const c_char, start: u32, end: u32, hash_value: *const u8, len: usize) -> bool216 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]
CheckDataHashNew(img_hash_data: *const ImgHashData<u64>, img_name: *const c_char, start: u64, end: u64, hash_value: *const u8, len: usize) -> bool228 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]
ReleaseImgHashData(hash_data: *const ImgHashData<u32>)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]
ReleaseImgHashDataNew(hash_data: *const ImgHashData<u64>)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 }