• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2# coding=utf-8
3##############################################
4# Copyright (c) 2021-2022 Huawei Device Co., Ltd.
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#     http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16##############################################
17import json
18import os
19import re
20import stat
21import sys
22from subprocess import Popen
23from subprocess import PIPE
24
25global_config = {}
26
27templates = {
28    'generate-keypair': {
29        'required': ['keyAlias', 'keyAlg', 'keySize', 'keystoreFile'],
30        'others': ['keyPwd', 'keystorePwd']
31    },
32    'generate-csr': {
33        'required': ['keyAlias', 'signAlg', 'subject', 'keystoreFile', 'outFile'],
34        'others': ['keyPwd', 'keystorePwd']
35    },
36    'generate-ca': {
37        'required': ['keyAlias', 'signAlg', 'keyAlg', 'keySize', 'subject', 'keystoreFile', 'outFile'],
38        'others': ['keyPwd', 'keystorePwd', 'issuer', 'issuerKeyAlias', 'issuerKeyPwd', 'validity',
39                   'basicConstraintsPathLen']
40    },
41    'generate-app-cert': {
42        'required': ['keyAlias', 'signAlg', 'issuer', 'issuerKeyAlias', 'subject', 'keystoreFile',
43                     'subCaCertFile', 'rootCaCertFile', 'outForm', 'outFile'],
44        'others': ['keyPwd', 'keystorePwd', 'issuerKeyPwd', 'validity',
45                   'basicConstraintsPathLen']
46    },
47    'generate-profile-cert': {
48        'required': ['keyAlias', 'signAlg', 'issuer', 'issuerKeyAlias', 'subject', 'keystoreFile',
49                     'subCaCertFile', 'rootCaCertFile', 'outForm', 'outFile'],
50        'others': ['keyPwd', 'keystorePwd', 'issuerKeyPwd', 'validity',
51                   'basicConstraintsPathLen']
52    },
53    'sign-profile': {
54        'required': ['keyAlias', 'signAlg', 'mode', 'profileCertFile', 'inFile', 'keystoreFile', 'outFile'],
55        'others': ['keyPwd', 'keystorePwd']
56    },
57    'sign-app': {
58        'required': ['keyAlias', 'signAlg', 'mode', 'appCertFile', 'profileFile', 'inFile', 'keystoreFile', 'outFile'],
59        'others': ['keyPwd', 'keystorePwd', 'inForm', 'signCode']
60    },
61}
62
63
64def print_help():
65    content = "\n" \
66              "Usage:python autosign.py <generate|sign> \n" \
67              "    signtool.jar : Main progress jar file\n" \
68              "\n" \
69              "Example: \n" \
70              "    python autosign.py createAppCertAndProfile \n" \
71              "    python autosign.py signHap" \
72              "\n"
73    print(content)
74
75
76def get_from_single_config(config_key, item_key, required=False):
77    param = global_config.get(config_key, {}).get(item_key, None)
78    if not param:
79        param = global_config.get('common', {}).get(item_key, None)
80    if not param:
81        if required:
82            print('Prepare loading: {}, config: {}'.format(config_key, global_config.get(config_key)))
83            print("Params {} is required.".format(item_key))
84            exit(1)
85    return param
86
87
88def prepare_dir(dir_name):
89    if not os.path.exists(dir_name):
90        os.mkdir(dir_name)
91
92
93def load_engine(engine_config):
94    tar_dir = global_config.get('config', {}).get('targetDir')
95    prepare_dir(tar_dir)
96
97    cmds = []
98    for eng_k, eng_v in engine_config.items():
99        template = templates.get(eng_v)
100        cmd = [eng_v]
101        for required_key in template.get('required'):
102            param = get_from_single_config(eng_k, required_key, True)
103            if required_key.endswith('File') and required_key != 'inFile' and os.path.basename(param) == param:
104                param = os.path.join(tar_dir, param)
105            cmd.append('-{}'.format(required_key))
106            cmd.append(param)
107
108        for others_key in template.get('others'):
109            param = get_from_single_config(eng_k, others_key, False)
110            if param:
111                cmd.append('-{}'.format(others_key))
112                cmd.append(param)
113        cmds.append(cmd)
114    return cmds
115
116
117def run_target(cmd):
118    command = Popen(cmd, stdout=PIPE, stderr=PIPE, stdin=PIPE, shell=False)
119    out = command.stdout.readlines()
120    with open("log.txt", mode='a+', encoding='utf-8') as f:
121        if len(out) > 0:
122            f.writelines(' '.join(cmd) + "\r\n")
123        for line in out:
124            f.writelines(str(line.strip()) + "\r\n")
125
126    success = True
127    error = command.stderr.readlines()
128    with open("error.txt", mode='a+', encoding='utf-8') as f:
129        if len(error) > 0:
130            f.writelines(' '.join(cmd) + "\r\n")
131
132        for line in error:
133            success = False
134            f.writelines(str(line.strip()) + "\r\n")
135
136    command.wait()
137    return success
138
139
140def run_with_engine(engine, jar):
141    cmds = load_engine(engine)
142    for cmd in cmds:
143        cmd.insert(0, jar)
144        cmd.insert(0, '-jar')
145        cmd.insert(0, 'java')
146        result = run_target(cmd)
147        if not result:
148            print("Command error on executing cmd, please check error.txt")
149            print(' '.join(cmd))
150            exit(1)
151    print("Success!")
152    pass
153
154
155def do_sign(jar):
156    sign_engine_config = {
157        'sign.profile': 'sign-profile',
158        'sign.app': 'sign-app'
159    }
160    run_with_engine(sign_engine_config, jar)
161
162
163def do_sign_hap(jar):
164    sign_hap_engine_config = {
165        'sign.app': 'sign-app'
166    }
167    run_with_engine(sign_hap_engine_config, jar)
168
169
170def do_sign_elf(jar):
171    sign_elf_engine_config = {
172        'sign.app': 'sign-app'
173    }
174    run_with_engine(sign_elf_engine_config, jar)
175
176
177def do_generate(jar):
178    cert_engine_config = {
179        'app.keypair': 'generate-keypair',
180        'profile.keypair': 'generate-keypair',
181        'csr': 'generate-csr',
182        'root-ca': 'generate-ca',
183        'sub-ca.app': 'generate-ca',
184        'sub-ca.profile': 'generate-ca',
185        'cert.app': 'generate-app-cert',
186        'cert.profile': 'generate-profile-cert',
187    }
188    run_with_engine(cert_engine_config, jar)
189
190
191def do_generate_root_cert(jar):
192    root_engine_config = {
193        'profile.keypair': 'generate-keypair',
194        'root-ca': 'generate-ca',
195        'sub-ca.app': 'generate-ca',
196        'sub-ca.profile': 'generate-ca',
197        'cert.profile': 'generate-profile-cert',
198    }
199    run_with_engine(root_engine_config, jar)
200
201
202def do_generate_app_cert(jar):
203    app_cert_engine_config = {
204        'app.keypair': 'generate-keypair',
205        'cert.app': 'generate-app-cert',
206    }
207    run_with_engine(app_cert_engine_config, jar)
208
209
210def do_sign_profile(jar):
211    app_cert_engine_config = {
212        'sign.profile': 'sign-profile',
213    }
214    run_with_engine(app_cert_engine_config, jar)
215
216
217def convert_to_map(line, temp_map):
218    line = line.strip('\n')
219    strs = line.split('=', 1)
220
221    if len(strs) == 2:
222        if strs[1].startswith('$'):
223            temp_map[strs[0]] = temp_map[strs[1][1:]]
224        else:
225            temp_map[strs[0]] = strs[1]
226
227
228def load_config(config):
229    config_file = config
230    temp_map = {}
231    with open(config_file, 'r', encoding='utf-8') as f:
232        for line in f.readlines():
233            if not re.match(r'\s*//[\s\S]*', line):
234                convert_to_map(line, temp_map)
235
236    for mk, mv in temp_map.items():
237        strs = mk.rsplit('.', 1)
238        if not global_config.get(strs[0]):
239            global_config[strs[0]] = {}
240        global_config[strs[0]][strs[-1]] = mv
241
242
243def process_cmd():
244    args = sys.argv
245    if len(args) <= 1 or '--help' == args[1] or '-h' == args[1]:
246        print_help()
247        exit(0)
248
249    action = args[1]
250    if action not in ['createRootAndSubCert', 'createAppCertAndProfile', 'signHap', 'signElf']:
251        print("Not support cmd")
252        print_help()
253        exit(1)
254    return action
255
256
257def process_jar():
258    read_jar_file = global_config.get('config', {}).get('signtool')
259    if not os.path.exists(read_jar_file):
260        print("Jar file '{}' not found".format(read_jar_file))
261        exit(1)
262    return read_jar_file
263
264
265def replace_cert_in_profile():
266    profile_file = global_config.get('sign.profile', {}).get('inFile')
267    app_cert_file = global_config.get('cert.app', {}).get('outFile')
268    tar_dir = global_config.get('config', {}).get('targetDir')
269    app_cert_file = os.path.join(tar_dir, app_cert_file)
270    if not os.path.exists(profile_file):
271        print("profile file '{}' not found".format(jar_file))
272        exit(1)
273    if not os.path.exists(app_cert_file):
274        print("app cert file '{}' not found".format(jar_file))
275        exit(1)
276
277    app_cert = ''
278    # read app cert
279    with open(app_cert_file, 'r', encoding='utf-8') as f:
280        app_cert_temp = f.read()
281        app_cert = app_cert_temp.split("-----END CERTIFICATE-----")[0] + "-----END CERTIFICATE-----\n"
282
283    profile = {}
284    # read profile
285    with open(profile_file, 'r', encoding='utf-8') as f:
286        profile = json.load(f)
287
288    profile["bundle-info"]["distribution-certificate"] = app_cert
289
290    # save profile
291    flags = os.O_WRONLY | os.O_TRUNC
292    modes = stat.S_IWUSR
293    with os.fdopen(os.open(profile_file, flags, modes), 'w') as profile_write:
294        json.dump(profile, profile_write)
295
296
297if __name__ == '__main__':
298    act = process_cmd()
299    if act == 'createRootAndSubCert':
300        load_config('createRootAndSubCert.config')
301        jar_file = process_jar()
302        do_generate_root_cert(jar_file)
303    elif act == 'createAppCertAndProfile':
304        load_config('createAppCertAndProfile.config')
305        jar_file = process_jar()
306        do_generate_app_cert(jar_file)
307        replace_cert_in_profile()
308        do_sign_profile(jar_file)
309    elif act == 'signHap':
310        load_config('signHap.config')
311        jar_file = process_jar()
312        do_sign_hap(jar_file)
313    elif act == 'signElf':
314        load_config('signElf.config')
315        jar_file = process_jar()
316        do_sign_elf(jar_file)
317