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::collections::HashMap; 17 use crate::updaterlog; 18 19 const TLV_SIZE:usize = 6; 20 const HASH_INFO_SIZE: usize = 16; 21 const HASH_HEADER_SIZE: usize = 38; 22 23 #[derive(Debug)] 24 struct HashInfo { 25 tlv_type: u16, 26 tlv_len: u32, 27 algorithm: u16, 28 algo_size: u16, 29 component_count: u16, 30 block_size: u32 31 } 32 33 #[derive(Debug)] 34 struct HashHeader { 35 image_name: String, 36 hash_num: u16, 37 img_size: u32 38 } 39 40 #[repr(C)] 41 #[derive(Debug)] 42 struct HashData { 43 addr_star: u32, 44 addr_end: u32, 45 hash_data: Vec<u8> 46 } 47 48 #[derive(Debug)] 49 struct HashSign { 50 tlv_type: u16, 51 tlv_len: u32, 52 sign_data: Vec<u8> 53 } 54 55 #[derive(Debug, PartialEq)] 56 pub struct ImgHashData { 57 data: HashMap<String, HashMap<(u32, u32), Vec<u8>>> 58 } 59 60 trait TLVStruct { new() -> Self61 fn new() -> Self; 62 read_from_le_bytes(&mut self, buffer: &[u8]) -> bool63 fn read_from_le_bytes(&mut self, buffer: &[u8]) -> bool; 64 } 65 66 impl TLVStruct for HashInfo { new() -> HashInfo67 fn new() -> HashInfo { 68 HashInfo {tlv_type: 0, tlv_len: 0, algorithm: 0, algo_size: 0, component_count: 0, block_size: 0} 69 } 70 read_from_le_bytes(&mut self, buffer: &[u8]) -> bool71 fn read_from_le_bytes(&mut self, buffer: &[u8]) -> bool { 72 if buffer.len() < HASH_INFO_SIZE { 73 updaterlog!(ERROR, "{} buffer is too small. {}", line!(), buffer.len()); 74 return false; 75 } 76 77 self.tlv_type = u16::from_le_bytes(buffer[0..2].try_into().unwrap()); 78 self.tlv_len = u32::from_le_bytes(buffer[2..6].try_into().unwrap()); 79 self.algorithm = u16::from_le_bytes(buffer[6..8].try_into().unwrap()); 80 self.algo_size = u16::from_le_bytes(buffer[8..10].try_into().unwrap()); 81 self.component_count = u16::from_le_bytes(buffer[10..12].try_into().unwrap()); 82 self.block_size = u32::from_le_bytes(buffer[12..16].try_into().unwrap()); 83 true 84 } 85 } 86 87 impl TLVStruct for HashHeader { new() -> HashHeader88 fn new() -> HashHeader { 89 HashHeader {image_name: String::new(), hash_num: 0, img_size: 0} 90 } 91 read_from_le_bytes(&mut self, buffer: &[u8]) -> bool92 fn read_from_le_bytes(&mut self, buffer: &[u8]) -> bool { 93 if buffer.len() < TLV_SIZE { 94 updaterlog!(ERROR, "{} buffer is too small. {}", line!(), buffer.len()); 95 return false; 96 } 97 98 self.image_name = String::from_utf8(Vec::from(&buffer[0..32])).unwrap().trim_end_matches('\0').to_owned(); 99 updaterlog!(INFO, "HashHeader read_from_le_bytes image_name {}", self.image_name); 100 self.hash_num = u16::from_le_bytes(buffer[32..34].try_into().unwrap()); 101 self.img_size = u32::from_le_bytes(buffer[34..].try_into().unwrap()); 102 true 103 } 104 } 105 106 impl TLVStruct for HashData { new() -> HashData107 fn new() -> HashData { 108 HashData {addr_star: 0, addr_end: 0, hash_data: vec![]} 109 } 110 read_from_le_bytes(&mut self, buffer: &[u8]) -> bool111 fn read_from_le_bytes(&mut self, buffer: &[u8]) -> bool { 112 if buffer.len() < TLV_SIZE { 113 updaterlog!(ERROR, "{} buffer is too small. {}", line!(), buffer.len()); 114 return false; 115 } 116 117 self.addr_star = u32::from_le_bytes(buffer[0..4].try_into().unwrap()); 118 self.addr_end = u32::from_le_bytes(buffer[4..8].try_into().unwrap()); 119 self.hash_data = Vec::from(&buffer[8..]); 120 true 121 } 122 } 123 124 impl TLVStruct for HashSign { new() -> HashSign125 fn new() -> HashSign { 126 HashSign {tlv_type: 0, tlv_len: 0, sign_data: vec![]} 127 } 128 read_from_le_bytes(&mut self, buffer: &[u8]) -> bool129 fn read_from_le_bytes(&mut self, buffer: &[u8]) -> bool { 130 if buffer.len() < TLV_SIZE { 131 updaterlog!(ERROR, "{} buffer is too small. {}", line!(), buffer.len()); 132 return false; 133 } 134 135 self.tlv_type = u16::from_le_bytes(buffer[0..2].try_into().unwrap()); 136 self.tlv_len = u32::from_le_bytes(buffer[2..6].try_into().unwrap()); 137 self.sign_data = Vec::from(&buffer[6..]); 138 true 139 } 140 } 141 142 #[allow(unused)] 143 impl ImgHashData { load_img_hash_data(buffer: &[u8]) -> Result<Self, String>144 pub fn load_img_hash_data(buffer: &[u8]) -> Result<Self, String> { 145 let mut offset = 0usize; 146 let mut hash_info = HashInfo::new(); 147 hash_info.read_from_le_bytes( &buffer[..HASH_INFO_SIZE]); 148 149 offset = HASH_INFO_SIZE + 2; 150 let hash_data_len = u32::from_le_bytes(buffer[offset..4 + offset].try_into().unwrap()); 151 152 offset += 4; 153 if buffer.len() < hash_data_len as usize { 154 return Err(format!("{} buffer is too small. {}", line!(), buffer.len())); 155 } 156 157 let mut hash_data_map: HashMap<String, HashMap<(u32, u32), Vec<u8>>> = HashMap::new(); 158 while offset < hash_data_len as usize { 159 let mut hash_header = HashHeader::new(); 160 hash_header.read_from_le_bytes(&buffer[offset..(HASH_HEADER_SIZE + offset)]); 161 offset += HASH_HEADER_SIZE; 162 163 let mut single_data: HashMap<(u32, u32), Vec<u8>> = HashMap::new(); 164 for i in 0..hash_header.hash_num { 165 let mut hash_data = HashData::new(); 166 hash_data.read_from_le_bytes(&buffer[offset.. (offset + 8 + hash_info.algo_size as usize)]); 167 single_data.insert((hash_data.addr_star, hash_data.addr_end), hash_data.hash_data); 168 offset += (8 + hash_info.algo_size) as usize; 169 } 170 hash_data_map.insert(hash_header.image_name, single_data); 171 } 172 Ok(ImgHashData { data: hash_data_map }) 173 } 174 check_img_hash(&self, img_name: String, start: u32, end: u32, hash_value: &[u8]) -> bool175 pub fn check_img_hash(&self, img_name: String, start: u32, end: u32, hash_value: &[u8]) -> bool 176 { 177 let img_hash_map = match self.data.get(&img_name) { 178 Some(img_hash_map)=> img_hash_map, 179 _ => { 180 updaterlog!(ERROR, "nothing found {}", img_name); 181 return false; 182 } 183 }; 184 185 let hash_data = match img_hash_map.get(&(start, end)) { 186 Some(hash_data)=> hash_data, 187 _ => { 188 updaterlog!(ERROR, "nothing found start: {}, end: {}", start, end); 189 return false; 190 } 191 }; 192 193 if hash_data.len() != hash_value.len() { 194 updaterlog!(ERROR, "hash value len is invalid {}", hash_value.len()); 195 return false; 196 } 197 198 for i in 0..hash_data.len() { 199 if hash_data[i] != hash_value[i] { 200 updaterlog!(ERROR, "hash value check fail"); 201 return false; 202 } 203 } 204 true 205 } 206 } 207