diff options
author | Alex Klyubin | 2016-01-13 12:32:47 -0600 |
---|---|---|
committer | Alex Klyubin | 2016-01-29 12:17:02 -0600 |
commit | c2a36afd6772d9286e8071693f80648beef763a3 (patch) | |
tree | 00347526394018525a69f65c4e0fca2965c45854 /tools/releasetools/sign_target_files_apks.py | |
parent | 4a97cde443829f1a3bf40fe6e820ba5b01e3bf87 (diff) | |
download | platform-build-c2a36afd6772d9286e8071693f80648beef763a3.tar.gz platform-build-c2a36afd6772d9286e8071693f80648beef763a3.tar.xz platform-build-c2a36afd6772d9286e8071693f80648beef763a3.zip |
Sign APKs using SHA-256 instead of SHA-1 when possible.
This changes the build system to provide the signapk tool with the
minSdkVersion of the APK being signed. signapk in turn will then use
SHA-256 instead of SHA-1 if minSdkVersion is 18 (JB MR2) or higher
(see c2c49ed0c13846f7f96249c7419971dfcddc9215).
To avoid increasing incremental OTA update package sizes for already
released platforms, release build scripts disable the above logic when
signing target files ZIPs for pre-N platforms.
Bug: 25643280
(cherry picked from commit de5bc04717505ad0e5b55605bccf43974f4c5c7a)
Change-Id: I4b100750e47788ab6ed897a0a5abfd33542e8676
Diffstat (limited to 'tools/releasetools/sign_target_files_apks.py')
-rwxr-xr-x | tools/releasetools/sign_target_files_apks.py | 92 |
1 files changed, 87 insertions, 5 deletions
diff --git a/tools/releasetools/sign_target_files_apks.py b/tools/releasetools/sign_target_files_apks.py index baf60f5c6..8941e3569 100755 --- a/tools/releasetools/sign_target_files_apks.py +++ b/tools/releasetools/sign_target_files_apks.py | |||
@@ -127,14 +127,34 @@ def CheckAllApksSigned(input_tf_zip, apk_key_map): | |||
127 | sys.exit(1) | 127 | sys.exit(1) |
128 | 128 | ||
129 | 129 | ||
130 | def SignApk(data, keyname, pw): | 130 | def SignApk(data, keyname, pw, platform_api_level, codename_to_api_level_map): |
131 | unsigned = tempfile.NamedTemporaryFile() | 131 | unsigned = tempfile.NamedTemporaryFile() |
132 | unsigned.write(data) | 132 | unsigned.write(data) |
133 | unsigned.flush() | 133 | unsigned.flush() |
134 | 134 | ||
135 | signed = tempfile.NamedTemporaryFile() | 135 | signed = tempfile.NamedTemporaryFile() |
136 | 136 | ||
137 | common.SignFile(unsigned.name, signed.name, keyname, pw) | 137 | # For pre-N builds, don't upgrade to SHA-256 JAR signatures based on the APK's |
138 | # minSdkVersion to avoid increasing incremental OTA update sizes. If an APK | ||
139 | # didn't change, we don't want its signature to change due to the switch | ||
140 | # from SHA-1 to SHA-256. | ||
141 | # By default, APK signer chooses SHA-256 signatures if the APK's minSdkVersion | ||
142 | # is 18 or higher. For pre-N builds we disable this mechanism by pretending | ||
143 | # that the APK's minSdkVersion is 1. | ||
144 | # For N+ builds, we let APK signer rely on the APK's minSdkVersion to | ||
145 | # determine whether to use SHA-256. | ||
146 | min_api_level = None | ||
147 | if platform_api_level > 23: | ||
148 | # Let APK signer choose whether to use SHA-1 or SHA-256, based on the APK's | ||
149 | # minSdkVersion attribute | ||
150 | min_api_level = None | ||
151 | else: | ||
152 | # Force APK signer to use SHA-1 | ||
153 | min_api_level = 1 | ||
154 | |||
155 | common.SignFile(unsigned.name, signed.name, keyname, pw, | ||
156 | min_api_level=min_api_level, | ||
157 | codename_to_api_level_map=codename_to_api_level_map) | ||
138 | 158 | ||
139 | data = signed.read() | 159 | data = signed.read() |
140 | unsigned.close() | 160 | unsigned.close() |
@@ -144,7 +164,8 @@ def SignApk(data, keyname, pw): | |||
144 | 164 | ||
145 | 165 | ||
146 | def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info, | 166 | def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info, |
147 | apk_key_map, key_passwords): | 167 | apk_key_map, key_passwords, platform_api_level, |
168 | codename_to_api_level_map): | ||
148 | 169 | ||
149 | maxsize = max([len(os.path.basename(i.filename)) | 170 | maxsize = max([len(os.path.basename(i.filename)) |
150 | for i in input_tf_zip.infolist() | 171 | for i in input_tf_zip.infolist() |
@@ -200,7 +221,8 @@ def ProcessTargetFiles(input_tf_zip, output_tf_zip, misc_info, | |||
200 | key = apk_key_map[name] | 221 | key = apk_key_map[name] |
201 | if key not in common.SPECIAL_CERT_STRINGS: | 222 | if key not in common.SPECIAL_CERT_STRINGS: |
202 | print " signing: %-*s (%s)" % (maxsize, name, key) | 223 | print " signing: %-*s (%s)" % (maxsize, name, key) |
203 | signed_data = SignApk(data, key, key_passwords[key]) | 224 | signed_data = SignApk(data, key, key_passwords[key], platform_api_level, |
225 | codename_to_api_level_map) | ||
204 | common.ZipWriteStr(output_tf_zip, out_info, signed_data) | 226 | common.ZipWriteStr(output_tf_zip, out_info, signed_data) |
205 | else: | 227 | else: |
206 | # an APK we're not supposed to sign. | 228 | # an APK we're not supposed to sign. |
@@ -440,6 +462,57 @@ def BuildKeyMap(misc_info, key_mapping_options): | |||
440 | OPTIONS.key_map[s] = d | 462 | OPTIONS.key_map[s] = d |
441 | 463 | ||
442 | 464 | ||
465 | def GetApiLevelAndCodename(input_tf_zip): | ||
466 | data = input_tf_zip.read("SYSTEM/build.prop") | ||
467 | api_level = None | ||
468 | codename = None | ||
469 | for line in data.split("\n"): | ||
470 | line = line.strip() | ||
471 | original_line = line | ||
472 | if line and line[0] != '#' and "=" in line: | ||
473 | key, value = line.split("=", 1) | ||
474 | key = key.strip() | ||
475 | if key == "ro.build.version.sdk": | ||
476 | api_level = int(value.strip()) | ||
477 | elif key == "ro.build.version.codename": | ||
478 | codename = value.strip() | ||
479 | |||
480 | if api_level is None: | ||
481 | raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop") | ||
482 | if codename is None: | ||
483 | raise ValueError("No ro.build.version.codename in SYSTEM/build.prop") | ||
484 | |||
485 | return (api_level, codename) | ||
486 | |||
487 | |||
488 | def GetCodenameToApiLevelMap(input_tf_zip): | ||
489 | data = input_tf_zip.read("SYSTEM/build.prop") | ||
490 | api_level = None | ||
491 | codenames = None | ||
492 | for line in data.split("\n"): | ||
493 | line = line.strip() | ||
494 | original_line = line | ||
495 | if line and line[0] != '#' and "=" in line: | ||
496 | key, value = line.split("=", 1) | ||
497 | key = key.strip() | ||
498 | if key == "ro.build.version.sdk": | ||
499 | api_level = int(value.strip()) | ||
500 | elif key == "ro.build.version.all_codenames": | ||
501 | codenames = value.strip().split(",") | ||
502 | |||
503 | if api_level is None: | ||
504 | raise ValueError("No ro.build.version.sdk in SYSTEM/build.prop") | ||
505 | if codenames is None: | ||
506 | raise ValueError("No ro.build.version.all_codenames in SYSTEM/build.prop") | ||
507 | |||
508 | result = dict() | ||
509 | for codename in codenames: | ||
510 | codename = codename.strip() | ||
511 | if len(codename) > 0: | ||
512 | result[codename] = api_level | ||
513 | return result | ||
514 | |||
515 | |||
443 | def main(argv): | 516 | def main(argv): |
444 | 517 | ||
445 | key_mapping_options = [] | 518 | key_mapping_options = [] |
@@ -498,8 +571,17 @@ def main(argv): | |||
498 | CheckAllApksSigned(input_zip, apk_key_map) | 571 | CheckAllApksSigned(input_zip, apk_key_map) |
499 | 572 | ||
500 | key_passwords = common.GetKeyPasswords(set(apk_key_map.values())) | 573 | key_passwords = common.GetKeyPasswords(set(apk_key_map.values())) |
574 | platform_api_level, platform_codename = GetApiLevelAndCodename(input_zip) | ||
575 | codename_to_api_level_map = GetCodenameToApiLevelMap(input_zip) | ||
576 | # Android N will be API Level 24, but isn't yet. | ||
577 | # TODO: Remove this workaround once Android N is officially API Level 24. | ||
578 | if platform_api_level == 23 and platform_codename == "N": | ||
579 | platform_api_level = 24 | ||
580 | |||
501 | ProcessTargetFiles(input_zip, output_zip, misc_info, | 581 | ProcessTargetFiles(input_zip, output_zip, misc_info, |
502 | apk_key_map, key_passwords) | 582 | apk_key_map, key_passwords, |
583 | platform_api_level, | ||
584 | codename_to_api_level_map) | ||
503 | 585 | ||
504 | common.ZipClose(input_zip) | 586 | common.ZipClose(input_zip) |
505 | common.ZipClose(output_zip) | 587 | common.ZipClose(output_zip) |