1#!/usr/bin/env python 2# 3# Copyright (C) 2019 The Android Open Source Project 4# 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 17""" 18Signs a standalone APEX file. 19 20Usage: sign_apex [flags] input_apex_file output_apex_file 21 22 --avbtool <avbtool> 23 Optional flag that specifies the AVB tool to use. Defaults to `avbtool`. 24 25 --container_key <key> 26 Mandatory flag that specifies the container signing key. 27 28 --payload_key <key> 29 Mandatory flag that specifies the payload signing key. 30 31 --payload_extra_args <args> 32 Optional flag that specifies any extra args to be passed to payload signer 33 (e.g. --payload_extra_args="--signing_helper_with_files /path/to/helper"). 34 35 -e (--extra_apks) <name,name,...=key> 36 Add extra APK name/key pairs. This is useful to sign the apk files in the 37 apex payload image. 38 39 --codename_to_api_level_map Q:29,R:30,... 40 A Mapping of codename to api level. This is useful to provide sdk targeting 41 information to APK Signer. 42""" 43 44import logging 45import shutil 46import sys 47 48import apex_utils 49import common 50 51logger = logging.getLogger(__name__) 52 53 54def SignApexFile(avbtool, apex_file, payload_key, container_key, no_hashtree, 55 apk_keys=None, signing_args=None, codename_to_api_level_map=None): 56 """Signs the given apex file.""" 57 with open(apex_file, 'rb') as input_fp: 58 apex_data = input_fp.read() 59 60 return apex_utils.SignApex( 61 avbtool, 62 apex_data, 63 payload_key=payload_key, 64 container_key=container_key, 65 container_pw=None, 66 codename_to_api_level_map=codename_to_api_level_map, 67 no_hashtree=no_hashtree, 68 apk_keys=apk_keys, 69 signing_args=signing_args) 70 71 72def main(argv): 73 74 options = {} 75 76 def option_handler(o, a): 77 if o == '--avbtool': 78 options['avbtool'] = a 79 elif o == '--container_key': 80 # Strip the suffix if any, as common.SignFile expects no suffix. 81 DEFAULT_CONTAINER_KEY_SUFFIX = '.x509.pem' 82 if a.endswith(DEFAULT_CONTAINER_KEY_SUFFIX): 83 a = a[:-len(DEFAULT_CONTAINER_KEY_SUFFIX)] 84 options['container_key'] = a 85 elif o == '--payload_key': 86 options['payload_key'] = a 87 elif o == '--payload_extra_args': 88 options['payload_extra_args'] = a 89 elif o == '--codename_to_api_level_map': 90 versions = a.split(",") 91 for v in versions: 92 key, value = v.split(":") 93 if 'codename_to_api_level_map' not in options: 94 options['codename_to_api_level_map'] = {} 95 options['codename_to_api_level_map'].update({key: value}) 96 elif o in ("-e", "--extra_apks"): 97 names, key = a.split("=") 98 names = names.split(",") 99 for n in names: 100 if 'extra_apks' not in options: 101 options['extra_apks'] = {} 102 options['extra_apks'].update({n: key}) 103 else: 104 return False 105 return True 106 107 args = common.ParseOptions( 108 argv, __doc__, 109 extra_opts='e:', 110 extra_long_opts=[ 111 'avbtool=', 112 'codename_to_api_level_map=', 113 'container_key=', 114 'payload_extra_args=', 115 'payload_key=', 116 'extra_apks=', 117 ], 118 extra_option_handler=option_handler) 119 120 if (len(args) != 2 or 'container_key' not in options or 121 'payload_key' not in options): 122 common.Usage(__doc__) 123 sys.exit(1) 124 125 common.InitLogging() 126 127 signed_apex = SignApexFile( 128 options.get('avbtool', 'avbtool'), 129 args[0], 130 options['payload_key'], 131 options['container_key'], 132 no_hashtree=False, 133 apk_keys=options.get('extra_apks', {}), 134 signing_args=options.get('payload_extra_args'), 135 codename_to_api_level_map=options.get( 136 'codename_to_api_level_map', {})) 137 shutil.copyfile(signed_apex, args[1]) 138 logger.info("done.") 139 140 141if __name__ == '__main__': 142 try: 143 main(sys.argv[1:]) 144 except common.ExternalError: 145 logger.exception("\n ERROR:\n") 146 sys.exit(1) 147 finally: 148 common.Cleanup() 149