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 }