• 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 use std::default::Default;
17 use std::collections::HashMap;
18 use std::hash::Hash;
19 use std::cmp::Eq;
20 use std::cmp::PartialEq;
21 use std::mem::size_of;
22 use crate::updaterlog;
23 
24 const TLV_SIZE: usize = 6;
25 const HASH_INFO_SIZE: usize = 16;
26 const IMG_NAME_SIZE: usize = 32;
27 
28 #[derive(Debug)]
29 struct HashInfo {
30     tlv_type: u16,
31     tlv_len: u32,
32     algorithm: u16,
33     algo_size: u16,
34     component_count: u16,
35     block_size: u32
36 }
37 
38 pub trait ReadLeBytes {
read_le_bytes(buffer: &[u8]) -> Self39     fn read_le_bytes(buffer: &[u8]) -> Self;
40 }
41 
42 impl ReadLeBytes for u32 {
read_le_bytes(buffer: &[u8]) -> Self43     fn read_le_bytes(buffer: &[u8]) -> Self {
44         u32::from_le_bytes(buffer[..].try_into().unwrap())
45     }
46 }
47 
48 impl ReadLeBytes for u64 {
read_le_bytes(buffer: &[u8]) -> Self49     fn read_le_bytes(buffer: &[u8]) -> Self {
50         u64::from_le_bytes(buffer[..].try_into().unwrap())
51     }
52 }
53 
54 #[derive(Debug)]
55 struct HashHeader<T: ReadLeBytes> {
56     image_name: String,
57     hash_num: u16,
58     img_size: T
59 }
60 
61 #[repr(C)]
62 #[derive(Debug)]
63 struct HashData<T: ReadLeBytes> {
64     addr_star: T,
65     addr_end: T,
66     hash_data: Vec<u8>
67 }
68 
69 #[derive(Debug)]
70 struct HashSign {
71     tlv_type: u16,
72     tlv_len: u32,
73     sign_data: Vec<u8>
74 }
75 
76 #[derive(Hash, Eq, PartialEq, Debug)]
77 struct Tuple<T> (T,  T);
78 
79 /// PartialEq
80 #[derive(Debug)]
81 pub struct ImgHashData<T: Hash + Eq + PartialEq> {
82     data: HashMap<String, HashMap<Tuple<T>, Vec<u8>>>
83 }
84 
85 trait TLVStruct {
new() -> Self86     fn new() -> Self;
87 
read_from_le_bytes(&mut self, buffer: &[u8]) -> bool88     fn read_from_le_bytes(&mut self, buffer: &[u8]) -> bool;
89 }
90 
91 impl TLVStruct for HashInfo {
new() -> HashInfo92     fn new() -> HashInfo {
93         HashInfo {tlv_type: 0, tlv_len: 0, algorithm: 0, algo_size: 0, component_count: 0, block_size: 0}
94     }
95 
read_from_le_bytes(&mut self, buffer: &[u8]) -> bool96     fn read_from_le_bytes(&mut self, buffer: &[u8]) -> bool {
97         if buffer.len() < HASH_INFO_SIZE {
98             updaterlog!(ERROR, "{} buffer is too small. {}", line!(), buffer.len());
99             return false;
100         }
101 
102         self.tlv_type = u16::from_le_bytes(buffer[0..2].try_into().unwrap());
103         self.tlv_len = u32::from_le_bytes(buffer[2..6].try_into().unwrap());
104         self.algorithm = u16::from_le_bytes(buffer[6..8].try_into().unwrap());
105         self.algo_size = u16::from_le_bytes(buffer[8..10].try_into().unwrap());
106         self.component_count = u16::from_le_bytes(buffer[10..12].try_into().unwrap());
107         self.block_size = u32::from_le_bytes(buffer[12..16].try_into().unwrap());
108         true
109     }
110 }
111 
112 impl<T: Default + ReadLeBytes> TLVStruct for HashHeader<T> {
new() -> HashHeader<T>113     fn new() -> HashHeader<T> {
114         HashHeader {image_name: String::new(), hash_num: 0, img_size: Default::default()}
115     }
116 
read_from_le_bytes(&mut self, buffer: &[u8]) -> bool117     fn read_from_le_bytes(&mut self, buffer: &[u8]) -> bool {
118         if buffer.len() < TLV_SIZE {
119             updaterlog!(ERROR, "{} buffer is too small. {}", line!(), buffer.len());
120             return false;
121         }
122 
123         self.image_name = String::from_utf8(Vec::from(&buffer[0..32])).unwrap().trim_end_matches('\0').to_owned();
124         updaterlog!(INFO, "HashHeader  read_from_le_bytes image_name {}", self.image_name);
125         self.hash_num = u16::from_le_bytes(buffer[32..34].try_into().unwrap());
126         self.img_size =  T::read_le_bytes(&buffer[34..]);
127         true
128     }
129 }
130 
131 impl<T: Default + ReadLeBytes> TLVStruct for HashData<T> {
new() -> HashData<T>132     fn new() -> HashData<T> {
133         HashData {addr_star: Default::default(), addr_end: Default::default(), hash_data: vec![]}
134     }
135 
read_from_le_bytes(&mut self, buffer: &[u8]) -> bool136     fn read_from_le_bytes(&mut self, buffer: &[u8]) -> bool {
137         if buffer.len() < TLV_SIZE {
138             updaterlog!(ERROR, "{} buffer is too small. {}", line!(), buffer.len());
139             return false;
140         }
141 
142         self.addr_star = T::read_le_bytes(&buffer[0..size_of::<T>()]);
143         self.addr_end = T::read_le_bytes(&buffer[size_of::<T>()..(2*size_of::<T>())]);
144         self.hash_data = Vec::from(&buffer[(2*size_of::<T>())..]);
145         true
146     }
147 }
148 
149 impl TLVStruct for HashSign {
new() -> HashSign150     fn new() -> HashSign {
151         HashSign {tlv_type: 0, tlv_len: 0, sign_data: vec![]}
152     }
153 
read_from_le_bytes(&mut self, buffer: &[u8]) -> bool154     fn read_from_le_bytes(&mut self, buffer: &[u8]) -> bool {
155         if buffer.len() < TLV_SIZE {
156             updaterlog!(ERROR, "{} buffer is too small. {}", line!(), buffer.len());
157             return false;
158         }
159 
160         self.tlv_type = u16::from_le_bytes(buffer[0..2].try_into().unwrap());
161         self.tlv_len = u32::from_le_bytes(buffer[2..6].try_into().unwrap());
162         self.sign_data = Vec::from(&buffer[6..]);
163         true
164     }
165 }
166 
167 #[allow(unused)]
168 impl<T: Default + ReadLeBytes + Hash + Eq + PartialEq> ImgHashData<T> {
load_img_hash_data(buffer: &[u8]) -> Result<Self, String>169     pub fn load_img_hash_data(buffer: &[u8]) -> Result<Self, String> {
170         let mut offset = 0usize;
171         let mut hash_info = HashInfo::new();
172         hash_info.read_from_le_bytes( &buffer[..HASH_INFO_SIZE]);
173 
174         offset = HASH_INFO_SIZE + 2;
175         let hash_data_len = u32::from_le_bytes(buffer[offset..4 + offset].try_into().unwrap());
176 
177         offset += 4;
178         if buffer.len() < hash_data_len as usize {
179             return Err(format!("{} buffer is too small. {}", line!(), buffer.len()));
180         }
181 
182         let mut hash_data_map: HashMap<String, HashMap<Tuple<T>, Vec<u8>>> = HashMap::new();
183         let hash_header_size: usize = IMG_NAME_SIZE + size_of::<u16>() + size_of::<T>();
184         updaterlog!(INFO, "HashHeader  read_from_le_bytes hash_header_size {}", hash_header_size);
185         while offset < hash_data_len as usize {
186             let mut hash_header: HashHeader<T> = HashHeader::new();
187             hash_header.read_from_le_bytes(&buffer[offset..(hash_header_size + offset)]);
188             offset += hash_header_size;
189 
190             let mut single_data: HashMap<Tuple<T>, Vec<u8>> = HashMap::new();
191             for i in 0..hash_header.hash_num {
192                 let mut hash_data = HashData::new();
193                 hash_data.read_from_le_bytes(&buffer[offset.. (offset + (2*size_of::<T>()) + hash_info.algo_size as usize)]);
194                 let mut addr_tuple = Tuple(hash_data.addr_star, hash_data.addr_end);
195                 single_data.insert(addr_tuple, hash_data.hash_data);
196                 offset += 2*size_of::<T>() + (hash_info.algo_size) as usize;
197             }
198             hash_data_map.insert(hash_header.image_name, single_data);
199         }
200         Ok(ImgHashData { data: hash_data_map })
201     }
202 
check_img_hash(&self, img_name: String, start: T, end: T, hash_value: &[u8]) -> bool where T: std::cmp::Eq, T: std::cmp::PartialEq, T: std::fmt::Display203     pub fn check_img_hash(&self, img_name: String, start: T, end: T, hash_value: &[u8]) -> bool
204         where T: std::cmp::Eq, T: std::cmp::PartialEq, T: std::fmt::Display
205     {
206         let img_hash_map = match self.data.get(&img_name) {
207             Some(img_hash_map)=> img_hash_map,
208             _ => {
209                 updaterlog!(ERROR, "nothing found {}", img_name);
210                 return false;
211             }
212         };
213 
214         let mut addr_tuple = Tuple(start, end);
215         let hash_data = match img_hash_map.get(&addr_tuple) {
216             Some(hash_data)=> hash_data,
217             _ => {
218                 updaterlog!(ERROR, "nothing found start: {}, end: {}", addr_tuple.0, addr_tuple.1);
219                 return false;
220             }
221         };
222 
223         if hash_data.len() != hash_value.len() {
224             updaterlog!(ERROR, "hash value len is invalid {}", hash_value.len());
225             return false;
226         }
227 
228         for i in 0..hash_data.len() {
229             if hash_data[i] != hash_value[i] {
230                 updaterlog!(ERROR, "hash value check fail");
231                 return false;
232             }
233         }
234         true
235     }
236 }
237