• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }