154aa6d63Sopenharmony_ci#!/usr/bin/env python 254aa6d63Sopenharmony_ci# coding=utf-8 354aa6d63Sopenharmony_ci############################################## 454aa6d63Sopenharmony_ci# Copyright (c) 2021-2022 Huawei Device Co., Ltd. 554aa6d63Sopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License"); 654aa6d63Sopenharmony_ci# you may not use this file except in compliance with the License. 754aa6d63Sopenharmony_ci# You may obtain a copy of the License at 854aa6d63Sopenharmony_ci# 954aa6d63Sopenharmony_ci# http://www.apache.org/licenses/LICENSE-2.0 1054aa6d63Sopenharmony_ci# 1154aa6d63Sopenharmony_ci# Unless required by applicable law or agreed to in writing, software 1254aa6d63Sopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS, 1354aa6d63Sopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1454aa6d63Sopenharmony_ci# See the License for the specific language governing permissions and 1554aa6d63Sopenharmony_ci# limitations under the License. 1654aa6d63Sopenharmony_ci############################################## 1754aa6d63Sopenharmony_ciimport json 1854aa6d63Sopenharmony_ciimport os 1954aa6d63Sopenharmony_ciimport re 2054aa6d63Sopenharmony_ciimport stat 2154aa6d63Sopenharmony_ciimport sys 2254aa6d63Sopenharmony_cifrom subprocess import Popen 2354aa6d63Sopenharmony_cifrom subprocess import PIPE 2454aa6d63Sopenharmony_ci 2554aa6d63Sopenharmony_ciglobal_config = {} 2654aa6d63Sopenharmony_ci 2754aa6d63Sopenharmony_citemplates = { 2854aa6d63Sopenharmony_ci 'generate-keypair': { 2954aa6d63Sopenharmony_ci 'required': ['keyAlias', 'keyAlg', 'keySize', 'keystoreFile'], 3054aa6d63Sopenharmony_ci 'others': ['keyPwd', 'keystorePwd'] 3154aa6d63Sopenharmony_ci }, 3254aa6d63Sopenharmony_ci 'generate-csr': { 3354aa6d63Sopenharmony_ci 'required': ['keyAlias', 'signAlg', 'subject', 'keystoreFile', 'outFile'], 3454aa6d63Sopenharmony_ci 'others': ['keyPwd', 'keystorePwd'] 3554aa6d63Sopenharmony_ci }, 3654aa6d63Sopenharmony_ci 'generate-ca': { 3754aa6d63Sopenharmony_ci 'required': ['keyAlias', 'signAlg', 'keyAlg', 'keySize', 'subject', 'keystoreFile', 'outFile'], 3854aa6d63Sopenharmony_ci 'others': ['keyPwd', 'keystorePwd', 'issuer', 'issuerKeyAlias', 'issuerKeyPwd', 'validity', 3954aa6d63Sopenharmony_ci 'basicConstraintsPathLen'] 4054aa6d63Sopenharmony_ci }, 4154aa6d63Sopenharmony_ci 'generate-app-cert': { 4254aa6d63Sopenharmony_ci 'required': ['keyAlias', 'signAlg', 'issuer', 'issuerKeyAlias', 'subject', 'keystoreFile', 4354aa6d63Sopenharmony_ci 'subCaCertFile', 'rootCaCertFile', 'outForm', 'outFile'], 4454aa6d63Sopenharmony_ci 'others': ['keyPwd', 'keystorePwd', 'issuerKeyPwd', 'validity', 4554aa6d63Sopenharmony_ci 'basicConstraintsPathLen'] 4654aa6d63Sopenharmony_ci }, 4754aa6d63Sopenharmony_ci 'generate-profile-cert': { 4854aa6d63Sopenharmony_ci 'required': ['keyAlias', 'signAlg', 'issuer', 'issuerKeyAlias', 'subject', 'keystoreFile', 4954aa6d63Sopenharmony_ci 'subCaCertFile', 'rootCaCertFile', 'outForm', 'outFile'], 5054aa6d63Sopenharmony_ci 'others': ['keyPwd', 'keystorePwd', 'issuerKeyPwd', 'validity', 5154aa6d63Sopenharmony_ci 'basicConstraintsPathLen'] 5254aa6d63Sopenharmony_ci }, 5354aa6d63Sopenharmony_ci 'sign-profile': { 5454aa6d63Sopenharmony_ci 'required': ['keyAlias', 'signAlg', 'mode', 'profileCertFile', 'inFile', 'keystoreFile', 'outFile'], 5554aa6d63Sopenharmony_ci 'others': ['keyPwd', 'keystorePwd'] 5654aa6d63Sopenharmony_ci }, 5754aa6d63Sopenharmony_ci 'sign-app': { 5854aa6d63Sopenharmony_ci 'required': ['keyAlias', 'signAlg', 'mode', 'appCertFile', 'profileFile', 'inFile', 'keystoreFile', 'outFile'], 5954aa6d63Sopenharmony_ci 'others': ['keyPwd', 'keystorePwd', 'inForm', 'signCode'] 6054aa6d63Sopenharmony_ci }, 6154aa6d63Sopenharmony_ci} 6254aa6d63Sopenharmony_ci 6354aa6d63Sopenharmony_ci 6454aa6d63Sopenharmony_cidef print_help(): 6554aa6d63Sopenharmony_ci content = "\n" \ 6654aa6d63Sopenharmony_ci "Usage:python autosign.py <generate|sign> \n" \ 6754aa6d63Sopenharmony_ci " signtool.jar : Main progress jar file\n" \ 6854aa6d63Sopenharmony_ci "\n" \ 6954aa6d63Sopenharmony_ci "Example: \n" \ 7054aa6d63Sopenharmony_ci " python autosign.py createAppCertAndProfile \n" \ 7154aa6d63Sopenharmony_ci " python autosign.py signHap" \ 7254aa6d63Sopenharmony_ci "\n" 7354aa6d63Sopenharmony_ci print(content) 7454aa6d63Sopenharmony_ci 7554aa6d63Sopenharmony_ci 7654aa6d63Sopenharmony_cidef get_from_single_config(config_key, item_key, required=False): 7754aa6d63Sopenharmony_ci param = global_config.get(config_key, {}).get(item_key, None) 7854aa6d63Sopenharmony_ci if not param: 7954aa6d63Sopenharmony_ci param = global_config.get('common', {}).get(item_key, None) 8054aa6d63Sopenharmony_ci if not param: 8154aa6d63Sopenharmony_ci if required: 8254aa6d63Sopenharmony_ci print('Prepare loading: {}, config: {}'.format(config_key, global_config.get(config_key))) 8354aa6d63Sopenharmony_ci print("Params {} is required.".format(item_key)) 8454aa6d63Sopenharmony_ci exit(1) 8554aa6d63Sopenharmony_ci return param 8654aa6d63Sopenharmony_ci 8754aa6d63Sopenharmony_ci 8854aa6d63Sopenharmony_cidef prepare_dir(dir_name): 8954aa6d63Sopenharmony_ci if not os.path.exists(dir_name): 9054aa6d63Sopenharmony_ci os.mkdir(dir_name) 9154aa6d63Sopenharmony_ci 9254aa6d63Sopenharmony_ci 9354aa6d63Sopenharmony_cidef load_engine(engine_config): 9454aa6d63Sopenharmony_ci tar_dir = global_config.get('config', {}).get('targetDir') 9554aa6d63Sopenharmony_ci prepare_dir(tar_dir) 9654aa6d63Sopenharmony_ci 9754aa6d63Sopenharmony_ci cmds = [] 9854aa6d63Sopenharmony_ci for eng_k, eng_v in engine_config.items(): 9954aa6d63Sopenharmony_ci template = templates.get(eng_v) 10054aa6d63Sopenharmony_ci cmd = [eng_v] 10154aa6d63Sopenharmony_ci for required_key in template.get('required'): 10254aa6d63Sopenharmony_ci param = get_from_single_config(eng_k, required_key, True) 10354aa6d63Sopenharmony_ci if required_key.endswith('File') and required_key != 'inFile' and os.path.basename(param) == param: 10454aa6d63Sopenharmony_ci param = os.path.join(tar_dir, param) 10554aa6d63Sopenharmony_ci cmd.append('-{}'.format(required_key)) 10654aa6d63Sopenharmony_ci cmd.append(param) 10754aa6d63Sopenharmony_ci 10854aa6d63Sopenharmony_ci for others_key in template.get('others'): 10954aa6d63Sopenharmony_ci param = get_from_single_config(eng_k, others_key, False) 11054aa6d63Sopenharmony_ci if param: 11154aa6d63Sopenharmony_ci cmd.append('-{}'.format(others_key)) 11254aa6d63Sopenharmony_ci cmd.append(param) 11354aa6d63Sopenharmony_ci cmds.append(cmd) 11454aa6d63Sopenharmony_ci return cmds 11554aa6d63Sopenharmony_ci 11654aa6d63Sopenharmony_ci 11754aa6d63Sopenharmony_cidef run_target(cmd): 11854aa6d63Sopenharmony_ci command = Popen(cmd, stdout=PIPE, stderr=PIPE, stdin=PIPE, shell=False) 11954aa6d63Sopenharmony_ci out = command.stdout.readlines() 12054aa6d63Sopenharmony_ci with open("log.txt", mode='a+', encoding='utf-8') as f: 12154aa6d63Sopenharmony_ci if len(out) > 0: 12254aa6d63Sopenharmony_ci f.writelines(' '.join(cmd) + "\r\n") 12354aa6d63Sopenharmony_ci for line in out: 12454aa6d63Sopenharmony_ci f.writelines(str(line.strip()) + "\r\n") 12554aa6d63Sopenharmony_ci 12654aa6d63Sopenharmony_ci success = True 12754aa6d63Sopenharmony_ci error = command.stderr.readlines() 12854aa6d63Sopenharmony_ci with open("error.txt", mode='a+', encoding='utf-8') as f: 12954aa6d63Sopenharmony_ci if len(error) > 0: 13054aa6d63Sopenharmony_ci f.writelines(' '.join(cmd) + "\r\n") 13154aa6d63Sopenharmony_ci 13254aa6d63Sopenharmony_ci for line in error: 13354aa6d63Sopenharmony_ci success = False 13454aa6d63Sopenharmony_ci f.writelines(str(line.strip()) + "\r\n") 13554aa6d63Sopenharmony_ci 13654aa6d63Sopenharmony_ci command.wait() 13754aa6d63Sopenharmony_ci return success 13854aa6d63Sopenharmony_ci 13954aa6d63Sopenharmony_ci 14054aa6d63Sopenharmony_cidef run_with_engine(engine, jar): 14154aa6d63Sopenharmony_ci cmds = load_engine(engine) 14254aa6d63Sopenharmony_ci for cmd in cmds: 14354aa6d63Sopenharmony_ci cmd.insert(0, jar) 14454aa6d63Sopenharmony_ci cmd.insert(0, '-jar') 14554aa6d63Sopenharmony_ci cmd.insert(0, 'java') 14654aa6d63Sopenharmony_ci result = run_target(cmd) 14754aa6d63Sopenharmony_ci if not result: 14854aa6d63Sopenharmony_ci print("Command error on executing cmd, please check error.txt") 14954aa6d63Sopenharmony_ci print(' '.join(cmd)) 15054aa6d63Sopenharmony_ci exit(1) 15154aa6d63Sopenharmony_ci print("Success!") 15254aa6d63Sopenharmony_ci pass 15354aa6d63Sopenharmony_ci 15454aa6d63Sopenharmony_ci 15554aa6d63Sopenharmony_cidef do_sign(jar): 15654aa6d63Sopenharmony_ci sign_engine_config = { 15754aa6d63Sopenharmony_ci 'sign.profile': 'sign-profile', 15854aa6d63Sopenharmony_ci 'sign.app': 'sign-app' 15954aa6d63Sopenharmony_ci } 16054aa6d63Sopenharmony_ci run_with_engine(sign_engine_config, jar) 16154aa6d63Sopenharmony_ci 16254aa6d63Sopenharmony_ci 16354aa6d63Sopenharmony_cidef do_sign_hap(jar): 16454aa6d63Sopenharmony_ci sign_hap_engine_config = { 16554aa6d63Sopenharmony_ci 'sign.app': 'sign-app' 16654aa6d63Sopenharmony_ci } 16754aa6d63Sopenharmony_ci run_with_engine(sign_hap_engine_config, jar) 16854aa6d63Sopenharmony_ci 16954aa6d63Sopenharmony_ci 17054aa6d63Sopenharmony_cidef do_sign_elf(jar): 17154aa6d63Sopenharmony_ci sign_elf_engine_config = { 17254aa6d63Sopenharmony_ci 'sign.app': 'sign-app' 17354aa6d63Sopenharmony_ci } 17454aa6d63Sopenharmony_ci run_with_engine(sign_elf_engine_config, jar) 17554aa6d63Sopenharmony_ci 17654aa6d63Sopenharmony_ci 17754aa6d63Sopenharmony_cidef do_generate(jar): 17854aa6d63Sopenharmony_ci cert_engine_config = { 17954aa6d63Sopenharmony_ci 'app.keypair': 'generate-keypair', 18054aa6d63Sopenharmony_ci 'profile.keypair': 'generate-keypair', 18154aa6d63Sopenharmony_ci 'csr': 'generate-csr', 18254aa6d63Sopenharmony_ci 'root-ca': 'generate-ca', 18354aa6d63Sopenharmony_ci 'sub-ca.app': 'generate-ca', 18454aa6d63Sopenharmony_ci 'sub-ca.profile': 'generate-ca', 18554aa6d63Sopenharmony_ci 'cert.app': 'generate-app-cert', 18654aa6d63Sopenharmony_ci 'cert.profile': 'generate-profile-cert', 18754aa6d63Sopenharmony_ci } 18854aa6d63Sopenharmony_ci run_with_engine(cert_engine_config, jar) 18954aa6d63Sopenharmony_ci 19054aa6d63Sopenharmony_ci 19154aa6d63Sopenharmony_cidef do_generate_root_cert(jar): 19254aa6d63Sopenharmony_ci root_engine_config = { 19354aa6d63Sopenharmony_ci 'profile.keypair': 'generate-keypair', 19454aa6d63Sopenharmony_ci 'root-ca': 'generate-ca', 19554aa6d63Sopenharmony_ci 'sub-ca.app': 'generate-ca', 19654aa6d63Sopenharmony_ci 'sub-ca.profile': 'generate-ca', 19754aa6d63Sopenharmony_ci 'cert.profile': 'generate-profile-cert', 19854aa6d63Sopenharmony_ci } 19954aa6d63Sopenharmony_ci run_with_engine(root_engine_config, jar) 20054aa6d63Sopenharmony_ci 20154aa6d63Sopenharmony_ci 20254aa6d63Sopenharmony_cidef do_generate_app_cert(jar): 20354aa6d63Sopenharmony_ci app_cert_engine_config = { 20454aa6d63Sopenharmony_ci 'app.keypair': 'generate-keypair', 20554aa6d63Sopenharmony_ci 'cert.app': 'generate-app-cert', 20654aa6d63Sopenharmony_ci } 20754aa6d63Sopenharmony_ci run_with_engine(app_cert_engine_config, jar) 20854aa6d63Sopenharmony_ci 20954aa6d63Sopenharmony_ci 21054aa6d63Sopenharmony_cidef do_sign_profile(jar): 21154aa6d63Sopenharmony_ci app_cert_engine_config = { 21254aa6d63Sopenharmony_ci 'sign.profile': 'sign-profile', 21354aa6d63Sopenharmony_ci } 21454aa6d63Sopenharmony_ci run_with_engine(app_cert_engine_config, jar) 21554aa6d63Sopenharmony_ci 21654aa6d63Sopenharmony_ci 21754aa6d63Sopenharmony_cidef convert_to_map(line, temp_map): 21854aa6d63Sopenharmony_ci line = line.strip('\n') 21954aa6d63Sopenharmony_ci strs = line.split('=', 1) 22054aa6d63Sopenharmony_ci 22154aa6d63Sopenharmony_ci if len(strs) == 2: 22254aa6d63Sopenharmony_ci if strs[1].startswith('$'): 22354aa6d63Sopenharmony_ci temp_map[strs[0]] = temp_map[strs[1][1:]] 22454aa6d63Sopenharmony_ci else: 22554aa6d63Sopenharmony_ci temp_map[strs[0]] = strs[1] 22654aa6d63Sopenharmony_ci 22754aa6d63Sopenharmony_ci 22854aa6d63Sopenharmony_cidef load_config(config): 22954aa6d63Sopenharmony_ci config_file = config 23054aa6d63Sopenharmony_ci temp_map = {} 23154aa6d63Sopenharmony_ci with open(config_file, 'r', encoding='utf-8') as f: 23254aa6d63Sopenharmony_ci for line in f.readlines(): 23354aa6d63Sopenharmony_ci if not re.match(r'\s*//[\s\S]*', line): 23454aa6d63Sopenharmony_ci convert_to_map(line, temp_map) 23554aa6d63Sopenharmony_ci 23654aa6d63Sopenharmony_ci for mk, mv in temp_map.items(): 23754aa6d63Sopenharmony_ci strs = mk.rsplit('.', 1) 23854aa6d63Sopenharmony_ci if not global_config.get(strs[0]): 23954aa6d63Sopenharmony_ci global_config[strs[0]] = {} 24054aa6d63Sopenharmony_ci global_config[strs[0]][strs[-1]] = mv 24154aa6d63Sopenharmony_ci 24254aa6d63Sopenharmony_ci 24354aa6d63Sopenharmony_cidef process_cmd(): 24454aa6d63Sopenharmony_ci args = sys.argv 24554aa6d63Sopenharmony_ci if len(args) <= 1 or '--help' == args[1] or '-h' == args[1]: 24654aa6d63Sopenharmony_ci print_help() 24754aa6d63Sopenharmony_ci exit(0) 24854aa6d63Sopenharmony_ci 24954aa6d63Sopenharmony_ci action = args[1] 25054aa6d63Sopenharmony_ci if action not in ['createRootAndSubCert', 'createAppCertAndProfile', 'signHap', 'signElf']: 25154aa6d63Sopenharmony_ci print("Not support cmd") 25254aa6d63Sopenharmony_ci print_help() 25354aa6d63Sopenharmony_ci exit(1) 25454aa6d63Sopenharmony_ci return action 25554aa6d63Sopenharmony_ci 25654aa6d63Sopenharmony_ci 25754aa6d63Sopenharmony_cidef process_jar(): 25854aa6d63Sopenharmony_ci read_jar_file = global_config.get('config', {}).get('signtool') 25954aa6d63Sopenharmony_ci if not os.path.exists(read_jar_file): 26054aa6d63Sopenharmony_ci print("Jar file '{}' not found".format(read_jar_file)) 26154aa6d63Sopenharmony_ci exit(1) 26254aa6d63Sopenharmony_ci return read_jar_file 26354aa6d63Sopenharmony_ci 26454aa6d63Sopenharmony_ci 26554aa6d63Sopenharmony_cidef replace_cert_in_profile(): 26654aa6d63Sopenharmony_ci profile_file = global_config.get('sign.profile', {}).get('inFile') 26754aa6d63Sopenharmony_ci app_cert_file = global_config.get('cert.app', {}).get('outFile') 26854aa6d63Sopenharmony_ci tar_dir = global_config.get('config', {}).get('targetDir') 26954aa6d63Sopenharmony_ci app_cert_file = os.path.join(tar_dir, app_cert_file) 27054aa6d63Sopenharmony_ci if not os.path.exists(profile_file): 27154aa6d63Sopenharmony_ci print("profile file '{}' not found".format(jar_file)) 27254aa6d63Sopenharmony_ci exit(1) 27354aa6d63Sopenharmony_ci if not os.path.exists(app_cert_file): 27454aa6d63Sopenharmony_ci print("app cert file '{}' not found".format(jar_file)) 27554aa6d63Sopenharmony_ci exit(1) 27654aa6d63Sopenharmony_ci 27754aa6d63Sopenharmony_ci app_cert = '' 27854aa6d63Sopenharmony_ci # read app cert 27954aa6d63Sopenharmony_ci with open(app_cert_file, 'r', encoding='utf-8') as f: 28054aa6d63Sopenharmony_ci app_cert_temp = f.read() 28154aa6d63Sopenharmony_ci app_cert = app_cert_temp.split("-----END CERTIFICATE-----")[0] + "-----END CERTIFICATE-----\n" 28254aa6d63Sopenharmony_ci 28354aa6d63Sopenharmony_ci profile = {} 28454aa6d63Sopenharmony_ci # read profile 28554aa6d63Sopenharmony_ci with open(profile_file, 'r', encoding='utf-8') as f: 28654aa6d63Sopenharmony_ci profile = json.load(f) 28754aa6d63Sopenharmony_ci 28854aa6d63Sopenharmony_ci try: 28954aa6d63Sopenharmony_ci profile["bundle-info"]["distribution-certificate"] = app_cert 29054aa6d63Sopenharmony_ci except KeyError: 29154aa6d63Sopenharmony_ci print("could not find distribution-certificate key in profile") 29254aa6d63Sopenharmony_ci 29354aa6d63Sopenharmony_ci # save profile 29454aa6d63Sopenharmony_ci flags = os.O_WRONLY | os.O_TRUNC 29554aa6d63Sopenharmony_ci modes = stat.S_IWUSR 29654aa6d63Sopenharmony_ci with os.fdopen(os.open(profile_file, flags, modes), 'w') as profile_write: 29754aa6d63Sopenharmony_ci json.dump(profile, profile_write) 29854aa6d63Sopenharmony_ci 29954aa6d63Sopenharmony_ci 30054aa6d63Sopenharmony_ciif __name__ == '__main__': 30154aa6d63Sopenharmony_ci act = process_cmd() 30254aa6d63Sopenharmony_ci if act == 'createRootAndSubCert': 30354aa6d63Sopenharmony_ci load_config('createRootAndSubCert.config') 30454aa6d63Sopenharmony_ci jar_file = process_jar() 30554aa6d63Sopenharmony_ci do_generate_root_cert(jar_file) 30654aa6d63Sopenharmony_ci elif act == 'createAppCertAndProfile': 30754aa6d63Sopenharmony_ci load_config('createAppCertAndProfile.config') 30854aa6d63Sopenharmony_ci jar_file = process_jar() 30954aa6d63Sopenharmony_ci do_generate_app_cert(jar_file) 31054aa6d63Sopenharmony_ci replace_cert_in_profile() 31154aa6d63Sopenharmony_ci do_sign_profile(jar_file) 31254aa6d63Sopenharmony_ci elif act == 'signHap': 31354aa6d63Sopenharmony_ci load_config('signHap.config') 31454aa6d63Sopenharmony_ci jar_file = process_jar() 31554aa6d63Sopenharmony_ci do_sign_hap(jar_file) 31654aa6d63Sopenharmony_ci elif act == 'signElf': 31754aa6d63Sopenharmony_ci load_config('signElf.config') 31854aa6d63Sopenharmony_ci jar_file = process_jar() 31954aa6d63Sopenharmony_ci do_sign_elf(jar_file) 32054aa6d63Sopenharmony_ci