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 --sign_tool <sign_tool> 44 Optional flag that specifies a custom signing tool for the contents of the apex. 45 46 --container_pw <name1=passwd,name2=passwd> 47 A mapping of key_name to password 48""" 49 50import logging 51import shutil 52import re 53import sys 54 55import apex_utils 56import common 57 58logger = logging.getLogger(__name__) 59 60 61def SignApexFile(avbtool, apex_file, payload_key, container_key, no_hashtree, 62 apk_keys=None, signing_args=None, codename_to_api_level_map=None, sign_tool=None, container_pw=None): 63 """Signs the given apex file.""" 64 with open(apex_file, 'rb') as input_fp: 65 apex_data = input_fp.read() 66 67 return apex_utils.SignApex( 68 avbtool, 69 apex_data, 70 payload_key=payload_key, 71 container_key=container_key, 72 container_pw=container_pw, 73 codename_to_api_level_map=codename_to_api_level_map, 74 no_hashtree=no_hashtree, 75 apk_keys=apk_keys, 76 signing_args=signing_args, 77 sign_tool=sign_tool) 78 79 80def main(argv): 81 82 options = {} 83 84 def option_handler(o, a): 85 if o == '--avbtool': 86 options['avbtool'] = a 87 elif o == '--container_key': 88 # Strip the suffix if any, as common.SignFile expects no suffix. 89 DEFAULT_CONTAINER_KEY_SUFFIX = '.x509.pem' 90 if a.endswith(DEFAULT_CONTAINER_KEY_SUFFIX): 91 a = a[:-len(DEFAULT_CONTAINER_KEY_SUFFIX)] 92 options['container_key'] = a 93 elif o == '--payload_key': 94 options['payload_key'] = a 95 elif o == '--payload_extra_args': 96 options['payload_extra_args'] = a 97 elif o == '--codename_to_api_level_map': 98 versions = a.split(",") 99 for v in versions: 100 key, value = v.split(":") 101 if 'codename_to_api_level_map' not in options: 102 options['codename_to_api_level_map'] = {} 103 options['codename_to_api_level_map'].update({key: value}) 104 elif o in ("-e", "--extra_apks"): 105 names, key = a.split("=") 106 names = names.split(",") 107 for n in names: 108 if 'extra_apks' not in options: 109 options['extra_apks'] = {} 110 options['extra_apks'].update({n: key}) 111 elif o == '--sign_tool': 112 options['sign_tool'] = a 113 elif o == '--container_pw': 114 passwords = {} 115 pairs = a.split() 116 for pair in pairs: 117 if "=" not in pair: 118 continue 119 tokens = pair.split("=", maxsplit=1) 120 passwords[tokens[0].strip()] = tokens[1].strip() 121 options['container_pw'] = passwords 122 else: 123 return False 124 return True 125 126 args = common.ParseOptions( 127 argv, __doc__, 128 extra_opts='e:', 129 extra_long_opts=[ 130 'avbtool=', 131 'codename_to_api_level_map=', 132 'container_key=', 133 'payload_extra_args=', 134 'payload_key=', 135 'extra_apks=', 136 'sign_tool=', 137 'container_pw=', 138 ], 139 extra_option_handler=option_handler) 140 141 if (len(args) != 2 or 'container_key' not in options or 142 'payload_key' not in options): 143 common.Usage(__doc__) 144 sys.exit(1) 145 146 common.InitLogging() 147 148 signed_apex = SignApexFile( 149 options.get('avbtool', 'avbtool'), 150 args[0], 151 options['payload_key'], 152 options['container_key'], 153 no_hashtree=False, 154 apk_keys=options.get('extra_apks', {}), 155 signing_args=options.get('payload_extra_args'), 156 codename_to_api_level_map=options.get( 157 'codename_to_api_level_map', {}), 158 sign_tool=options.get('sign_tool', None), 159 container_pw=options.get('container_pw'), 160 ) 161 shutil.copyfile(signed_apex, args[1]) 162 logger.info("done.") 163 164 165if __name__ == '__main__': 166 try: 167 main(sys.argv[1:]) 168 finally: 169 common.Cleanup() 170