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 hashlib 18from ctypes import sizeof 19from ctypes import c_uint32 20from ctypes import create_string_buffer 21from ctypes import memmove 22from ctypes import byref 23import binascii 24import struct 25import logging 26import os 27import xml.etree.ElementTree as ET 28 29logging.basicConfig(level=logging.INFO, 30 format='%(asctime)s line:%(lineno)d %(levelname)s:%(name)s:%(message)s', 31 datefmt='%H:%M:%S' 32 ) 33 34MAX_PKGNAME_LEN = 256 35MAX_USERNAME_LEN = 256 36MAX_MODULUS_LEN = 1024 37MAX_PUB_EXP_LEN = 256 38 39 40def print_hash(byte_buf): 41 buf = [hex(int(i)) for i in byte_buf] 42 output = " ".join(buf) 43 logging.info("caller hash: %s", output) 44 45 46def check_native_ca_item(item): 47 if item.tag != "item" or len(item.attrib) != 2: 48 raise RuntimeError("invalid item attrib", item.tag, item.attrib, len(item.attrib)) 49 50 51def check_app_ca_item(item): 52 if item.tag != "item" or len(item.attrib) != 3: 53 raise RuntimeError("invalid item attrib", item.tag, item.attrib, len(item.attrib)) 54 55 56def check_pkgname_type(value): 57 if len(value) == 0 or len(value) > MAX_PKGNAME_LEN: 58 raise RuntimeError("invalid pkgname, the pkgname length must be in range (0, {}]".format(MAX_PKGNAME_LEN), \ 59 value, len(value)) 60 61 62def check_uid_type(value): 63 if int(value, 10) > 0xffffffff or int(value, 10) < 0: 64 raise RuntimeError("invalid uid, the uid value must be in [0, 0xffffffff]", value) 65 66 67def check_username_type(value): 68 if len(value) == 0 or len(value) > MAX_USERNAME_LEN: 69 raise RuntimeError("invalid username, the username length must be in range (0, {}]".format(MAX_USERNAME_LEN), \ 70 value, len(value)) 71 72 73def check_modulue_type(value): 74 if len(value) == 0 or (len(value) / 2) > MAX_MODULUS_LEN: 75 raise RuntimeError("invalid module, the module length must be in range (0, {}]".format(MAX_MODULUS_LEN * 2), \ 76 value, len(value)) 77 78 79def check_exponent_type(value): 80 if len(value) == 0 or (len(value) / 2) > MAX_PUB_EXP_LEN: 81 raise RuntimeError( \ 82 "invalid exponent, the exponent length must be in range (0, {}]".format(MAX_PUB_EXP_LEN * 2), \ 83 value, len(value)) 84 85 86def calc_sha256(buf): 87 hash_op = hashlib.sha256() 88 hash_op.update(buf) 89 return hash_op.digest() 90 91 92def calc_cmdline_uid_hash(cmdline, uid): 93 c_uid = c_uint32(uid) 94 c_str = create_string_buffer(cmdline.encode('utf-8'), len(cmdline) + sizeof(c_uid)) 95 memmove(byref(c_str, len(c_str.value)), byref(c_uid), sizeof(c_uid)) 96 return calc_sha256(c_str) 97 98 99def calc_cmdline_username_hash(cmdline, username): 100 c_str = create_string_buffer((cmdline + username).encode('utf-8'), len(cmdline) + MAX_USERNAME_LEN) 101 return calc_sha256(c_str) 102 103 104def calc_app_caller_hash(app_pkg_name, app_modulus, app_public_exponent): 105 hex_modulus = binascii.a2b_hex(app_modulus) 106 hex_exponent = binascii.a2b_hex(app_public_exponent) 107 pub_key_format = "{}s{}s".format(len(hex_modulus), len(hex_exponent)) 108 hex_pub_key = struct.pack(pub_key_format, hex_modulus, hex_exponent) 109 c_str = create_string_buffer((app_pkg_name).encode('utf-8'), \ 110 len(app_pkg_name) + len(hex_pub_key)) 111 memmove(byref(c_str, len(c_str.value)), bytes(hex_pub_key), len(hex_pub_key)) 112 return calc_sha256(c_str) 113 114 115def handle_cmdline_uid_item_hash(item): 116 cmdline = "" 117 uid = 0 118 for attr in item.attrib: 119 value = item.attrib[attr] 120 if attr == "cmdline": 121 check_pkgname_type(value) 122 cmdline = value 123 elif attr == "uid": 124 check_uid_type(value) 125 uid = int(value, 10) 126 else: 127 raise RuntimeError("invalid item attr", attr) 128 caller_hash = calc_cmdline_uid_hash(cmdline, uid) 129 logging.info("cmdline: %s, uid: %s", cmdline, uid) 130 print_hash(caller_hash) 131 132 133def handle_cmdline_uid(child): 134 for item in child: 135 check_native_ca_item(item) 136 handle_cmdline_uid_item_hash(item) 137 138 139def handle_cmdline_username_item_hash(item): 140 cmdline = "" 141 username = "" 142 for attr in item.attrib: 143 value = item.attrib[attr] 144 if attr == "cmdline": 145 check_pkgname_type(value) 146 cmdline = value 147 elif attr == "username": 148 check_username_type(value) 149 username = value 150 else: 151 raise RuntimeError("invalid item attr", attr) 152 caller_hash = calc_cmdline_username_hash(cmdline, username) 153 logging.info("cmdline: %s, username: %s", cmdline, username) 154 print_hash(caller_hash) 155 156 157def handle_cmdline_username(child): 158 for item in child: 159 check_native_ca_item(item) 160 handle_cmdline_username_item_hash(item) 161 162 163def handle_app_item_hash(item): 164 pkg_name = "" 165 modulue = "" 166 exponent = "" 167 for attr in item.attrib: 168 value = item.attrib[attr] 169 if attr == "pkg_name": 170 check_pkgname_type(value) 171 pkg_name = value 172 elif attr == "modulue": 173 check_modulue_type(value) 174 modulue = value 175 elif attr == "exponent": 176 check_exponent_type(value) 177 exponent = value 178 else: 179 raise RuntimeError("invalid item attr", attr) 180 caller_hash = calc_app_caller_hash(pkg_name, modulue, exponent) 181 logging.info("pkg_name: %s, modulue:%s, exponent: %s", pkg_name, modulue, exponent) 182 print_hash(caller_hash) 183 184 185def handle_app(child): 186 for item in child: 187 check_app_ca_item(item) 188 handle_app_item_hash(item) 189 190 191def do_calc_caller_info_hash(ca_caller_info_root): 192 for child in ca_caller_info_root: 193 if child.tag == "cmdline_uid": 194 handle_cmdline_uid(child) 195 elif child.tag == "cmdline_username": 196 handle_cmdline_username(child) 197 elif child.tag == "app": 198 handle_app(child) 199 else: 200 raise RuntimeError("not support xml tag", child.tag) 201 202 203def main(): 204 ca_caller_info_xml = "ca_caller_info.xml" 205 if not os.path.exists(ca_caller_info_xml): 206 raise RuntimeError("caller_info.xml file doesn't exist.") 207 208 tree = ET.parse(ca_caller_info_xml) 209 ca_caller_info_root = tree.getroot() 210 211 do_calc_caller_info_hash(ca_caller_info_root) 212 213 214if __name__ == "__main__": 215 main()