1#!/usr/bin/env python 2# coding:utf-8 3 4# 5# Copyright (C) 2022 Huawei Technologies Co., Ltd. 6# Licensed under the Mulan PSL v2. 7# You can use this software according to the terms and conditions of the Mulan 8# PSL v2. 9# You may obtain a copy of Mulan PSL v2 at: 10# http://license.coscl.org.cn/MulanPSL2 11# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY 12# KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 13# NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 14# See the Mulan PSL v2 for more details. 15# 16 17import string 18import struct 19import uuid 20import os 21import re 22import stat 23import logging 24 25 26PRODUCT_TA_IMAGE = 1 27PRODUCT_DYN_LIB = 2 28PRODUCT_SERVICE_IMAGE = 3 29PRODUCT_CLIENT_IMAGE = 4 30PRODUCT_DRIVER_IMAGE = 5 31logging.basicConfig(level=logging.INFO) 32 33 34class PackUuid: 35 # Structure object to align and package the TEE_UUID 36 data = struct.Struct('IHH8b') 37 38 def __init__(self, data): 39 unpacked_data = (PackUuid.data).unpack(str.encode(data)) 40 self.unpacked_data = unpacked_data 41 self.time_low = unpacked_data[0] 42 self.time_mid = unpacked_data[1] 43 self.time_hi_version = unpacked_data[2] 44 self.clock_seq_node = unpacked_data[3] 45 46 def print_values(self): 47 logging.info("ATTRIBUTE / VALUE") 48 for attr, value in self.__dict__.items(): 49 logging.info(attr, value) 50 51 def get_pack_data(self): 52 values = [self.time_low, 53 self.time_mid, 54 self.time_hi_version, 55 self.clock_seq_node, 56 ] 57 58 return (PackUuid.data).pack(*values) 59 60 61#---------------------------------------------------------------------------- 62# Manifest 63#---------------------------------------------------------------------------- 64class Manifest: 65 66 # Structure object to align and package the Manifest 67 data = struct.Struct('I' * 6) 68 69 def __init__(self, data): 70 unpacked_data = (Manifest.data).unpack(str.encode(data)) 71 self.unpacked_data = unpacked_data 72 self.single_instance = unpacked_data[0] 73 self.multi_session = unpacked_data[1] 74 self.multi_command = unpacked_data[2] 75 self.heap_size = unpacked_data[3] 76 self.stack_size = unpacked_data[4] 77 self.instancekeepalive = unpacked_data[5] 78 79 def print_values(self): 80 logging.info("ATTRIBUTE / VALUE") 81 for attr, value in self.__dict__.items(): 82 logging.info(attr, value) 83 84 def get_pack_data(self): 85 values = [self.single_instance, 86 self.multi_session, 87 self.multi_command, 88 self.heap_size, 89 self.stack_size, 90 self.instancekeepalive, 91 ] 92 93 return (Manifest.data).pack(*values) 94 95 96#---------------------------------------------------------------------------- 97# verify property name in manifest file 98#---------------------------------------------------------------------------- 99def verify_property_name(str_line): 100 logging.info("verify property name") 101 alphas = string.ascii_letters + string.digits 102 cont = "".join([alphas, '-', '_', '.']) 103 if len(str_line) > 1: 104 if str_line[0] not in alphas: 105 logging.error("invalid first letter in property name") 106 return False 107 else: 108 for otherchar in str_line[1:]: 109 if otherchar not in cont: 110 logging.error("invalid char in property name") 111 return False 112 else: 113 logging.error("invalid property name") 114 return False 115 116 return True 117 118 119#---------------------------------------------------------------------------- 120# verify property value in manifest file 121#---------------------------------------------------------------------------- 122def verify_property_value(str_line): 123 logging.info("verify property value") 124 filt_letter = chr(0) + chr(10) + chr(13) 125 for thechar in str_line: 126 if thechar in filt_letter: 127 logging.error("invalid letter in prop value") 128 return False 129 return True 130 131 132#---------------------------------------------------------------------------- 133# remove tabs and space in property value 134#---------------------------------------------------------------------------- 135def trailing_space_tabs(str_line): 136 logging.info('trailing space tabs in value head and trail') 137 space_tabs = chr(9) + chr(32) + chr(160) 138 space_tabs_newlines = space_tabs + chr(10) + chr(13) 139 140 index = 0 141 for thechar in str_line: 142 if thechar in space_tabs: 143 index += 1 144 else: 145 break 146 headvalue = str_line[index:] 147 148 strlen = len(headvalue) 149 150 strlen -= 1 151 152 while strlen > 0: 153 if headvalue[strlen] in space_tabs_newlines: 154 strlen -= 1 155 else: 156 break 157 158 str_ret = headvalue[0:strlen + 1] + chr(10) 159 logging.info("str ret: %s", str_ret) 160 161 return str_ret 162 163 164def update_target_type(target_info): 165 # dyn_conf_target_type is 1 means that is drv 166 dyn_conf_target_type = target_info.dyn_conf_target_type 167 service_name = target_info.service_name 168 target_type = target_info.target_type 169 service_name_len = len(service_name) 170 logging.info("service name: %s", service_name) 171 logging.info("service name len: %d", service_name_len) 172 173 max_service_len = 36 174 if dyn_conf_target_type == 1: 175 target_type = PRODUCT_DRIVER_IMAGE 176 if dyn_conf_target_type == 3: 177 target_type = PRODUCT_SERVICE_IMAGE 178 if dyn_conf_target_type == 4: 179 target_type = PRODUCT_CLIENT_IMAGE 180 181 if not re.match(r"^[A-Za-z0-9_-]*$", service_name): 182 logging.error("service name only can use [A-Z] [a-z] [0-9] '-' and '_'") 183 return (False, 0) 184 185 if service_name_len > max_service_len: 186 logging.error("service name len cannot larger than %s", str(max_service_len)) 187 return (False, 0) 188 return (True, target_type) 189 190 191class TargetInfo: 192 def __init__(self, dyn_conf_target_type, service_name, target_type, uuid_val): 193 self.dyn_conf_target_type = dyn_conf_target_type 194 self.service_name = service_name 195 self.target_type = target_type 196 self.uuid_val = uuid_val 197 198 199def init_data_val(): 200 #manifest default 201 manifest_val = Manifest('\0'*24) 202 manifest_val.single_instance = 1 203 manifest_val.multi_session = 0 204 manifest_val.multi_command = 0 205 manifest_val.instancekeepalive = 0 206 manifest_val.heap_size = 16384 207 manifest_val.stack_size = 2048 208 209 uuid_val = PackUuid('\0' * 16) 210 target_type = PRODUCT_TA_IMAGE 211 service_name = 'external_service' 212 dyn_conf_target_type = 0 213 target_info = TargetInfo(dyn_conf_target_type, service_name, target_type, uuid_val) 214 return manifest_val, target_info 215 216 217def update_manifest_info(prop_value_v, val, prop_name_low): 218 prop_value_low = prop_value_v.lower() 219 if 'true' == prop_value_low: 220 val = 1 221 elif 'false' == prop_value_low: 222 val = 0 223 else: 224 logging.error("%s value error!", prop_name_low) 225 return val 226 227 228def check_prop_info(prop_name, prop_value_v): 229 if verify_property_name(prop_name) is False: 230 logging.error("manifest format invalid, please check it") 231 return False 232 233 if verify_property_value(prop_value_v) is False: 234 logging.error("manifest format invalid, please check it") 235 return False 236 return True 237 238 239class PropInfo: 240 def __init__(self, prop_name, prop_name_t, prop_value_t): 241 self.prop_name = prop_name 242 self.prop_name_t = prop_name_t 243 self.prop_value_t = prop_value_t 244 245 def get_prop_value(self): 246 prop_value_t = self.prop_value_t 247 prop_value = trailing_space_tabs(prop_value_t) 248 prop_len = len(prop_value) 249 prop_value_v = prop_value[0:prop_len - 1] 250 logging.info("prop value_v: %s", prop_value_v) 251 return prop_value, prop_value_v 252 253 254def parse_prop_info(manifest_val, prop_info, mani_ext_fp, target_info): 255 prop_value, prop_value_v = PropInfo.get_prop_value(prop_info) 256 prop_name = prop_info.prop_name 257 prop_name_t = prop_info.prop_name_t 258 259 if not check_prop_info(prop_name, prop_value_v): 260 return (False, 0, 0) 261 262 # name:value to lowcase, and parse manifest 263 prop_name_low = prop_name.lower() 264 logging.info("name lower: %s", prop_name_low) 265 if 'gpd.ta.appid' == prop_name_low: 266 logging.info("compare name is srv id") 267 target_info.uuid_val = uuid.UUID(prop_value_v) 268 logging.info("uuid str %s", target_info.uuid_val) 269 logging.info("val fields %s", target_info.uuid_val.fields) 270 271 elif 'gpd.ta.singleinstance' == prop_name_low: 272 manifest_val.single_instance = update_manifest_info(prop_value_v, manifest_val.single_instance, \ 273 prop_name_low) 274 elif 'gpd.ta.multisession' == prop_name_low: 275 manifest_val.multi_session = update_manifest_info(prop_value_v, manifest_val.multi_session, \ 276 prop_name_low) 277 elif 'gpd.ta.multicommand' == prop_name_low: 278 manifest_val.multi_command = update_manifest_info(prop_value_v, manifest_val.multi_command, \ 279 prop_name_low) 280 elif 'gpd.ta.instancekeepalive' == prop_name_low: 281 manifest_val.instancekeepalive = update_manifest_info(prop_value_v, manifest_val.instancekeepalive, \ 282 prop_name_low) 283 elif 'gpd.ta.datasize' == prop_name_low: 284 manifest_val.heap_size = int(prop_value_v) 285 logging.info('b') 286 elif 'gpd.ta.stacksize' == prop_name_low: 287 manifest_val.stack_size = int(prop_value_v) 288 logging.info('b') 289 elif 'gpd.ta.service_name' == prop_name_low: 290 target_info.service_name = prop_value_v 291 logging.info('b') 292 elif 'gpd.ta.dynconf' == prop_name_low: 293 logging.error("gpd.ta.dynConf is reserved, cannot set") 294 return (False, 0, 0) 295 else: 296 logging.info('b') 297 #write have not paresed manifest into sample.manifest file 298 mani_ext_fp.write(str.encode(prop_name_t)) 299 mani_ext_fp.write(str.encode(prop_value)) 300 if 'gpd.ta.is_lib' == prop_name_low: 301 if 'true' == prop_value_v.lower(): 302 target_info.target_type = PRODUCT_DYN_LIB 303 elif 'gpd.ta.target_type' == prop_name_low: 304 target_info.dyn_conf_target_type = int(prop_value_v) 305 if target_info.dyn_conf_target_type > 0xFFFF or target_info.dyn_conf_target_type < 0: 306 logging.error("gpd.ta.target_type must in range [0, 0xFFFF]") 307 return (False, 0, 0) 308 return (True, manifest_val, target_info) 309 310 311def gen_product_name(uuid_val, target_info): 312 service_name = target_info.service_name 313 target_type = target_info.target_type 314 uuid_str = str(uuid_val) 315 product_name = str(uuid_val) 316 if target_type == PRODUCT_TA_IMAGE: 317 logging.info("product type is ta image") 318 product_name = "".join([uuid_str, ".sec"]) 319 elif target_type == PRODUCT_DRIVER_IMAGE: 320 logging.info("product type is driver") 321 product_name = "".join([service_name, ".sec"]) 322 elif target_type == PRODUCT_SERVICE_IMAGE: 323 logging.info("product type is service") 324 product_name = "".join([service_name, ".sec"]) 325 elif target_type == PRODUCT_CLIENT_IMAGE: 326 logging.info("product type is client") 327 product_name = "".join([service_name, ".so.sec"]) 328 elif target_type == PRODUCT_DYN_LIB: 329 logging.info("product type is dyn lib") 330 product_name = "".join([uuid_str, service_name, ".so.sec"]) 331 else: 332 logging.error("invalid product type!") 333 return (False, 0, 0) 334 return (True, product_name, uuid_str) 335 336 337#---------------------------------------------------------------------------- 338# verify manifest file, parse manifest file, generate a new manfiest file 339#---------------------------------------------------------------------------- 340def parser_manifest(manifest, manifest_data_path, mani_ext): 341 logging.info("verify manifest") 342 manifest_val, target_info = init_data_val() 343 344 with open(manifest, 'r') as mani_fp: 345 fd_ext = os.open(mani_ext, os.O_WRONLY | os.O_CREAT, \ 346 stat.S_IWUSR | stat.S_IRUSR) 347 mani_ext_fp = os.fdopen(fd_ext, "wb") 348 for each_line in mani_fp: 349 logging.info(each_line) 350 if each_line.startswith("#") or not each_line.strip(): 351 continue 352 index = each_line.find(':', 1, len(each_line)) 353 354 prop_name = each_line[0:index] 355 prop_name_t = each_line[0:index + 1] 356 prop_value_t = each_line[index + 1:] 357 prop_info = PropInfo(prop_name, prop_name_t, prop_value_t) 358 logging.info("name is: %s; value is: %s", prop_name, prop_value_t) 359 360 result, manifest_val, target_info = parse_prop_info(manifest_val, prop_info, \ 361 mani_ext_fp, target_info) 362 if result is False: 363 mani_ext_fp.close() 364 return (False, 0, 0, None) 365 mani_ext_fp.close() 366 #write the whole parsed manifest into sample.manifest file 367 uuid_val = target_info.uuid_val 368 ret, target_info.target_type = update_target_type(target_info) 369 if ret is False: 370 return (False, 0, 0, None) 371 372 # get manifest string file len 373 manifest_str_size = os.path.getsize(mani_ext) 374 logging.info('manifest str size %d', manifest_str_size) 375 376 # 2> manifest + service_name 377 logging.info("bytes len %d", len(uuid_val.bytes_le)) 378 logging.info("bytes len %d", len(manifest_val.get_pack_data())) 379 logging.info("bytes len %d", len(target_info.service_name)) 380 381 # 3> unparsed manifest, string manifest 382 with open(mani_ext, 'rb') as string_mani_fp: 383 logging.info("read manifest string size %d", manifest_str_size) 384 manifest_string_buf = string_mani_fp.read(manifest_str_size) 385 logging.info("manifest strint: %s", manifest_string_buf) 386 387 #---- write manifest parse context to manifest file 388 fd_out = os.open(manifest_data_path, os.O_WRONLY | os.O_CREAT, \ 389 stat.S_IWUSR | stat.S_IRUSR) 390 out_manifest_fp = os.fdopen(fd_out, "wb") 391 out_manifest_fp.write(uuid_val.bytes_le) 392 out_manifest_fp.write(str.encode(target_info.service_name)) 393 out_manifest_fp.write(manifest_val.get_pack_data()) 394 out_manifest_fp.close() 395 ret, product_name, uuid_str = gen_product_name(uuid_val, target_info) 396 if ret is False: 397 return (False, 0, 0, None) 398 399 return (True, product_name, uuid_str, manifest_val) 400 401 402class ManifestInfo: 403 ''' get manifest info ''' 404 def __init__(self, ret, product_name, uuid_str, manifest_txt_exist): 405 self.ret = ret 406 self.product_name = product_name 407 self.uuid_str = uuid_str 408 self.manifest_txt_exist = manifest_txt_exist 409 410 411def process_manifest_file(xml_config_path, manifest_path, \ 412 manifest_data_path, mani_ext): 413 414 manifest_txt_exist = True 415 if not os.path.exists(manifest_path): 416 logging.info("xml trans manifest cfg") 417 manifest_txt_exist = False 418 from xml_trans_manifest import trans_xml_to_manifest 419 trans_xml_to_manifest(xml_config_path, manifest_path) 420 421 ret, product_name, uuid_str, manifest_val = parser_manifest(manifest_path, \ 422 manifest_data_path, mani_ext) 423 manifest_info = ManifestInfo(ret, product_name, uuid_str, manifest_txt_exist) 424 return manifest_info, manifest_val 425