1# 2# Copyright (C) 2017 The Android Open Source Project 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15# 16 17import base64 18import io 19import os.path 20import zipfile 21 22import common 23import test_utils 24from sign_target_files_apks import ( 25 CheckApkAndApexKeysAvailable, EditTags, GetApkFileInfo, ReadApexKeysInfo, 26 ReplaceCerts, ReplaceGkiSigningKey, ReplaceVerityKeyId, RewriteAvbProps, 27 RewriteProps, WriteOtacerts) 28 29 30class SignTargetFilesApksTest(test_utils.ReleaseToolsTestCase): 31 32 MAC_PERMISSIONS_XML = """<?xml version="1.0" encoding="iso-8859-1"?> 33<policy> 34 <signer signature="{}"><seinfo value="platform"/></signer> 35 <signer signature="{}"><seinfo value="media"/></signer> 36</policy>""" 37 38 # Note that we test one apex with the partition tag, and another without to 39 # make sure that new OTA tools can process an older target files package that 40 # does not include the partition tag. 41 42 # pylint: disable=line-too-long 43 APEX_KEYS_TXT = """name="apex.apexd_test.apex" public_key="system/apex/apexd/apexd_testdata/com.android.apex.test_package.avbpubkey" private_key="system/apex/apexd/apexd_testdata/com.android.apex.test_package.pem" container_certificate="build/make/target/product/security/testkey.x509.pem" container_private_key="build/make/target/product/security/testkey.pk8" partition="system" 44name="apex.apexd_test_different_app.apex" public_key="system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.avbpubkey" private_key="system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem" container_certificate="build/make/target/product/security/testkey.x509.pem" container_private_key="build/make/target/product/security/testkey.pk8" 45""" 46 47 def setUp(self): 48 self.testdata_dir = test_utils.get_testdata_dir() 49 50 def test_EditTags(self): 51 self.assertEqual(EditTags('dev-keys'), ('release-keys')) 52 self.assertEqual(EditTags('test-keys'), ('release-keys')) 53 54 # Multiple tags. 55 self.assertEqual(EditTags('abc,dev-keys,xyz'), ('abc,release-keys,xyz')) 56 57 # Tags are sorted. 58 self.assertEqual(EditTags('xyz,abc,dev-keys,xyz'), ('abc,release-keys,xyz')) 59 60 def test_RewriteAvbProps(self): 61 misc_info = { 62 'avb_boot_add_hash_footer_args': 63 ('--prop com.android.build.boot.os_version:R ' 64 '--prop com.android.build.boot.security_patch:2019-09-05'), 65 'avb_init_boot_add_hash_footer_args': 66 ('--prop com.android.build.boot.os_version:R ' 67 '--prop com.android.build.boot.security_patch:2019-09-05'), 68 'avb_system_add_hashtree_footer_args': 69 ('--prop com.android.build.system.os_version:R ' 70 '--prop com.android.build.system.security_patch:2019-09-05 ' 71 '--prop com.android.build.system.fingerprint:' 72 'Android/aosp_taimen/taimen:R/QT/foo:userdebug/test-keys'), 73 'avb_vendor_add_hashtree_footer_args': 74 ('--prop com.android.build.vendor.os_version:R ' 75 '--prop com.android.build.vendor.security_patch:2019-09-05 ' 76 '--prop com.android.build.vendor.fingerprint:' 77 'Android/aosp_taimen/taimen:R/QT/foo:userdebug/dev-keys'), 78 } 79 expected_dict = { 80 'avb_boot_add_hash_footer_args': 81 ('--prop com.android.build.boot.os_version:R ' 82 '--prop com.android.build.boot.security_patch:2019-09-05'), 83 'avb_init_boot_add_hash_footer_args': 84 ('--prop com.android.build.boot.os_version:R ' 85 '--prop com.android.build.boot.security_patch:2019-09-05'), 86 'avb_system_add_hashtree_footer_args': 87 ('--prop com.android.build.system.os_version:R ' 88 '--prop com.android.build.system.security_patch:2019-09-05 ' 89 '--prop com.android.build.system.fingerprint:' 90 'Android/aosp_taimen/taimen:R/QT/foo:userdebug/release-keys'), 91 'avb_vendor_add_hashtree_footer_args': 92 ('--prop com.android.build.vendor.os_version:R ' 93 '--prop com.android.build.vendor.security_patch:2019-09-05 ' 94 '--prop com.android.build.vendor.fingerprint:' 95 'Android/aosp_taimen/taimen:R/QT/foo:userdebug/release-keys'), 96 } 97 RewriteAvbProps(misc_info) 98 self.assertDictEqual(expected_dict, misc_info) 99 100 def test_RewriteProps(self): 101 props = ( 102 ('', ''), 103 ('ro.build.fingerprint=foo/bar/dev-keys', 104 'ro.build.fingerprint=foo/bar/release-keys'), 105 ('ro.build.thumbprint=foo/bar/dev-keys', 106 'ro.build.thumbprint=foo/bar/release-keys'), 107 ('ro.vendor.build.fingerprint=foo/bar/dev-keys', 108 'ro.vendor.build.fingerprint=foo/bar/release-keys'), 109 ('ro.vendor.build.thumbprint=foo/bar/dev-keys', 110 'ro.vendor.build.thumbprint=foo/bar/release-keys'), 111 ('ro.odm.build.fingerprint=foo/bar/test-keys', 112 'ro.odm.build.fingerprint=foo/bar/release-keys'), 113 ('ro.odm.build.thumbprint=foo/bar/test-keys', 114 'ro.odm.build.thumbprint=foo/bar/release-keys'), 115 ('ro.product.build.fingerprint=foo/bar/dev-keys', 116 'ro.product.build.fingerprint=foo/bar/release-keys'), 117 ('ro.product.build.thumbprint=foo/bar/dev-keys', 118 'ro.product.build.thumbprint=foo/bar/release-keys'), 119 ('ro.system_ext.build.fingerprint=foo/bar/test-keys', 120 'ro.system_ext.build.fingerprint=foo/bar/release-keys'), 121 ('ro.system_ext.build.thumbprint=foo/bar/test-keys', 122 'ro.system_ext.build.thumbprint=foo/bar/release-keys'), 123 ('# comment line 1', '# comment line 1'), 124 ('ro.bootimage.build.fingerprint=foo/bar/dev-keys', 125 'ro.bootimage.build.fingerprint=foo/bar/release-keys'), 126 ('ro.build.description=' 127 'sailfish-user 8.0.0 OPR6.170623.012 4283428 dev-keys', 128 'ro.build.description=' 129 'sailfish-user 8.0.0 OPR6.170623.012 4283428 release-keys'), 130 ('ro.build.tags=dev-keys', 'ro.build.tags=release-keys'), 131 ('ro.build.tags=test-keys', 'ro.build.tags=release-keys'), 132 ('ro.system.build.tags=dev-keys', 133 'ro.system.build.tags=release-keys'), 134 ('ro.vendor.build.tags=dev-keys', 135 'ro.vendor.build.tags=release-keys'), 136 ('ro.odm.build.tags=dev-keys', 137 'ro.odm.build.tags=release-keys'), 138 ('ro.product.build.tags=dev-keys', 139 'ro.product.build.tags=release-keys'), 140 ('ro.system_ext.build.tags=dev-keys', 141 'ro.system_ext.build.tags=release-keys'), 142 ('# comment line 2', '# comment line 2'), 143 ('ro.build.display.id=OPR6.170623.012 dev-keys', 144 'ro.build.display.id=OPR6.170623.012'), 145 ('# comment line 3', '# comment line 3'), 146 ) 147 148 # Assert the case for each individual line. 149 for prop, expected in props: 150 self.assertEqual(expected + '\n', RewriteProps(prop)) 151 152 # Concatenate all the input lines. 153 self.assertEqual( 154 '\n'.join([prop[1] for prop in props]) + '\n', 155 RewriteProps('\n'.join([prop[0] for prop in props]))) 156 157 def test_ReplaceVerityKeyId(self): 158 BOOT_CMDLINE1 = ( 159 "console=ttyHSL0,115200,n8 androidboot.console=ttyHSL0 " 160 "androidboot.hardware=marlin user_debug=31 ehci-hcd.park=3 " 161 "lpm_levels.sleep_disabled=1 cma=32M@0-0xffffffff loop.max_part=7 " 162 "buildvariant=userdebug " 163 "veritykeyid=id:7e4333f9bba00adfe0ede979e28ed1920492b40f\n") 164 165 BOOT_CMDLINE2 = ( 166 "console=ttyHSL0,115200,n8 androidboot.console=ttyHSL0 " 167 "androidboot.hardware=marlin user_debug=31 ehci-hcd.park=3 " 168 "lpm_levels.sleep_disabled=1 cma=32M@0-0xffffffff loop.max_part=7 " 169 "buildvariant=userdebug " 170 "veritykeyid=id:d24f2590e9abab5cff5f59da4c4f0366e3f43e94\n") 171 172 input_file = common.MakeTempFile(suffix='.zip') 173 with zipfile.ZipFile(input_file, 'w', allowZip64=True) as input_zip: 174 input_zip.writestr('BOOT/cmdline', BOOT_CMDLINE1) 175 176 # Test with the first certificate. 177 cert_file = os.path.join(self.testdata_dir, 'verity.x509.pem') 178 179 output_file = common.MakeTempFile(suffix='.zip') 180 with zipfile.ZipFile(input_file, 'r', allowZip64=True) as input_zip, \ 181 zipfile.ZipFile(output_file, 'w', allowZip64=True) as output_zip: 182 ReplaceVerityKeyId(input_zip, output_zip, cert_file) 183 184 with zipfile.ZipFile(output_file) as output_zip: 185 self.assertEqual(BOOT_CMDLINE1, output_zip.read('BOOT/cmdline').decode()) 186 187 # Test with the second certificate. 188 cert_file = os.path.join(self.testdata_dir, 'testkey.x509.pem') 189 190 with zipfile.ZipFile(input_file, 'r', allowZip64=True) as input_zip, \ 191 zipfile.ZipFile(output_file, 'w', allowZip64=True) as output_zip: 192 ReplaceVerityKeyId(input_zip, output_zip, cert_file) 193 194 with zipfile.ZipFile(output_file) as output_zip: 195 self.assertEqual(BOOT_CMDLINE2, output_zip.read('BOOT/cmdline').decode()) 196 197 def test_ReplaceVerityKeyId_no_veritykeyid(self): 198 BOOT_CMDLINE = ( 199 "console=ttyHSL0,115200,n8 androidboot.hardware=bullhead boot_cpus=0-5 " 200 "lpm_levels.sleep_disabled=1 msm_poweroff.download_mode=0 " 201 "loop.max_part=7\n") 202 203 input_file = common.MakeTempFile(suffix='.zip') 204 with zipfile.ZipFile(input_file, 'w', allowZip64=True) as input_zip: 205 input_zip.writestr('BOOT/cmdline', BOOT_CMDLINE) 206 207 output_file = common.MakeTempFile(suffix='.zip') 208 with zipfile.ZipFile(input_file, 'r', allowZip64=True) as input_zip, \ 209 zipfile.ZipFile(output_file, 'w', allowZip64=True) as output_zip: 210 ReplaceVerityKeyId(input_zip, output_zip, None) 211 212 with zipfile.ZipFile(output_file) as output_zip: 213 self.assertEqual(BOOT_CMDLINE, output_zip.read('BOOT/cmdline').decode()) 214 215 def test_ReplaceCerts(self): 216 cert1_path = os.path.join(self.testdata_dir, 'platform.x509.pem') 217 with open(cert1_path) as cert1_fp: 218 cert1 = cert1_fp.read() 219 cert2_path = os.path.join(self.testdata_dir, 'media.x509.pem') 220 with open(cert2_path) as cert2_fp: 221 cert2 = cert2_fp.read() 222 cert3_path = os.path.join(self.testdata_dir, 'testkey.x509.pem') 223 with open(cert3_path) as cert3_fp: 224 cert3 = cert3_fp.read() 225 226 # Replace cert1 with cert3. 227 input_xml = self.MAC_PERMISSIONS_XML.format( 228 base64.b16encode(common.ParseCertificate(cert1)).lower(), 229 base64.b16encode(common.ParseCertificate(cert2)).lower()) 230 231 output_xml = self.MAC_PERMISSIONS_XML.format( 232 base64.b16encode(common.ParseCertificate(cert3)).lower(), 233 base64.b16encode(common.ParseCertificate(cert2)).lower()) 234 235 common.OPTIONS.key_map = { 236 cert1_path[:-9] : cert3_path[:-9], 237 } 238 239 self.assertEqual(output_xml, ReplaceCerts(input_xml)) 240 241 def test_ReplaceCerts_duplicateEntries(self): 242 cert1_path = os.path.join(self.testdata_dir, 'platform.x509.pem') 243 with open(cert1_path) as cert1_fp: 244 cert1 = cert1_fp.read() 245 cert2_path = os.path.join(self.testdata_dir, 'media.x509.pem') 246 with open(cert2_path) as cert2_fp: 247 cert2 = cert2_fp.read() 248 249 # Replace cert1 with cert2, which leads to duplicate entries. 250 input_xml = self.MAC_PERMISSIONS_XML.format( 251 base64.b16encode(common.ParseCertificate(cert1)).lower(), 252 base64.b16encode(common.ParseCertificate(cert2)).lower()) 253 254 common.OPTIONS.key_map = { 255 cert1_path[:-9] : cert2_path[:-9], 256 } 257 self.assertRaises(AssertionError, ReplaceCerts, input_xml) 258 259 def test_ReplaceCerts_skipNonExistentCerts(self): 260 cert1_path = os.path.join(self.testdata_dir, 'platform.x509.pem') 261 with open(cert1_path) as cert1_fp: 262 cert1 = cert1_fp.read() 263 cert2_path = os.path.join(self.testdata_dir, 'media.x509.pem') 264 with open(cert2_path) as cert2_fp: 265 cert2 = cert2_fp.read() 266 cert3_path = os.path.join(self.testdata_dir, 'testkey.x509.pem') 267 with open(cert3_path) as cert3_fp: 268 cert3 = cert3_fp.read() 269 270 input_xml = self.MAC_PERMISSIONS_XML.format( 271 base64.b16encode(common.ParseCertificate(cert1)).lower(), 272 base64.b16encode(common.ParseCertificate(cert2)).lower()) 273 274 output_xml = self.MAC_PERMISSIONS_XML.format( 275 base64.b16encode(common.ParseCertificate(cert3)).lower(), 276 base64.b16encode(common.ParseCertificate(cert2)).lower()) 277 278 common.OPTIONS.key_map = { 279 cert1_path[:-9] : cert3_path[:-9], 280 'non-existent' : cert3_path[:-9], 281 cert2_path[:-9] : 'non-existent', 282 } 283 self.assertEqual(output_xml, ReplaceCerts(input_xml)) 284 285 def test_WriteOtacerts(self): 286 certs = [ 287 os.path.join(self.testdata_dir, 'platform.x509.pem'), 288 os.path.join(self.testdata_dir, 'media.x509.pem'), 289 os.path.join(self.testdata_dir, 'testkey.x509.pem'), 290 ] 291 entry_name = 'SYSTEM/etc/security/otacerts.zip' 292 output_file = common.MakeTempFile(suffix='.zip') 293 with zipfile.ZipFile(output_file, 'w', allowZip64=True) as output_zip: 294 WriteOtacerts(output_zip, entry_name, certs) 295 with zipfile.ZipFile(output_file) as input_zip: 296 self.assertIn(entry_name, input_zip.namelist()) 297 otacerts_file = io.BytesIO(input_zip.read(entry_name)) 298 with zipfile.ZipFile(otacerts_file) as otacerts_zip: 299 self.assertEqual(3, len(otacerts_zip.namelist())) 300 301 def test_CheckApkAndApexKeysAvailable(self): 302 input_file = common.MakeTempFile(suffix='.zip') 303 with zipfile.ZipFile(input_file, 'w', allowZip64=True) as input_zip: 304 input_zip.writestr('SYSTEM/app/App1.apk', "App1-content") 305 input_zip.writestr('SYSTEM/app/App2.apk.gz', "App2-content") 306 307 apk_key_map = { 308 'App1.apk' : 'key1', 309 'App2.apk' : 'key2', 310 'App3.apk' : 'key3', 311 } 312 with zipfile.ZipFile(input_file) as input_zip: 313 CheckApkAndApexKeysAvailable(input_zip, apk_key_map, None, {}) 314 CheckApkAndApexKeysAvailable(input_zip, apk_key_map, '.gz', {}) 315 316 # 'App2.apk.gz' won't be considered as an APK. 317 CheckApkAndApexKeysAvailable(input_zip, apk_key_map, None, {}) 318 CheckApkAndApexKeysAvailable(input_zip, apk_key_map, '.xz', {}) 319 320 del apk_key_map['App2.apk'] 321 self.assertRaises( 322 AssertionError, CheckApkAndApexKeysAvailable, input_zip, apk_key_map, 323 '.gz', {}) 324 325 def test_CheckApkAndApexKeysAvailable_invalidApexKeys(self): 326 input_file = common.MakeTempFile(suffix='.zip') 327 with zipfile.ZipFile(input_file, 'w', allowZip64=True) as input_zip: 328 input_zip.writestr('SYSTEM/apex/Apex1.apex', "Apex1-content") 329 input_zip.writestr('SYSTEM/apex/Apex2.apex', "Apex2-content") 330 331 apk_key_map = { 332 'Apex1.apex' : 'key1', 333 'Apex2.apex' : 'key2', 334 'Apex3.apex' : 'key3', 335 } 336 apex_keys = { 337 'Apex1.apex' : ('payload-key1', 'container-key1', None), 338 'Apex2.apex' : ('payload-key2', 'container-key2', None), 339 } 340 with zipfile.ZipFile(input_file) as input_zip: 341 CheckApkAndApexKeysAvailable(input_zip, apk_key_map, None, apex_keys) 342 343 # Fine to have both keys as PRESIGNED. 344 apex_keys['Apex2.apex'] = ('PRESIGNED', 'PRESIGNED', None) 345 CheckApkAndApexKeysAvailable(input_zip, apk_key_map, None, apex_keys) 346 347 # Having only one of them as PRESIGNED is not allowed. 348 apex_keys['Apex2.apex'] = ('payload-key2', 'PRESIGNED', None) 349 self.assertRaises( 350 AssertionError, CheckApkAndApexKeysAvailable, input_zip, apk_key_map, 351 None, apex_keys) 352 353 apex_keys['Apex2.apex'] = ('PRESIGNED', 'container-key1', None) 354 self.assertRaises( 355 AssertionError, CheckApkAndApexKeysAvailable, input_zip, apk_key_map, 356 None, apex_keys) 357 358 def test_GetApkFileInfo(self): 359 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo( 360 "PRODUCT/apps/Chats.apk", None, []) 361 self.assertTrue(is_apk) 362 self.assertFalse(is_compressed) 363 self.assertFalse(should_be_skipped) 364 365 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo( 366 "PRODUCT/apps/Chats.apk", None, []) 367 self.assertTrue(is_apk) 368 self.assertFalse(is_compressed) 369 self.assertFalse(should_be_skipped) 370 371 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo( 372 "PRODUCT/apps/Chats.dat", None, []) 373 self.assertFalse(is_apk) 374 self.assertFalse(is_compressed) 375 self.assertFalse(should_be_skipped) 376 377 def test_GetApkFileInfo_withCompressedApks(self): 378 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo( 379 "PRODUCT/apps/Chats.apk.gz", ".gz", []) 380 self.assertTrue(is_apk) 381 self.assertTrue(is_compressed) 382 self.assertFalse(should_be_skipped) 383 384 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo( 385 "PRODUCT/apps/Chats.apk.gz", ".xz", []) 386 self.assertFalse(is_apk) 387 self.assertFalse(is_compressed) 388 self.assertFalse(should_be_skipped) 389 390 self.assertRaises( 391 AssertionError, GetApkFileInfo, "PRODUCT/apps/Chats.apk", "", []) 392 393 self.assertRaises( 394 AssertionError, GetApkFileInfo, "PRODUCT/apps/Chats.apk", "apk", []) 395 396 def test_GetApkFileInfo_withSkippedPrefixes(self): 397 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo( 398 "PRODUCT/preloads/apps/Chats.apk", None, set()) 399 self.assertTrue(is_apk) 400 self.assertFalse(is_compressed) 401 self.assertFalse(should_be_skipped) 402 403 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo( 404 "PRODUCT/preloads/apps/Chats.apk", 405 None, 406 set(["PRODUCT/preloads/"])) 407 self.assertTrue(is_apk) 408 self.assertFalse(is_compressed) 409 self.assertTrue(should_be_skipped) 410 411 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo( 412 "SYSTEM_OTHER/preloads/apps/Chats.apk", 413 None, 414 set(["SYSTEM/preloads/", "SYSTEM_OTHER/preloads/"])) 415 self.assertTrue(is_apk) 416 self.assertFalse(is_compressed) 417 self.assertTrue(should_be_skipped) 418 419 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo( 420 "SYSTEM_OTHER/preloads/apps/Chats.apk.gz", 421 ".gz", 422 set(["PRODUCT/prebuilts/", "SYSTEM_OTHER/preloads/"])) 423 self.assertTrue(is_apk) 424 self.assertTrue(is_compressed) 425 self.assertTrue(should_be_skipped) 426 427 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo( 428 "SYSTEM_OTHER/preloads/apps/Chats.dat", 429 None, 430 set(["SYSTEM_OTHER/preloads/"])) 431 self.assertFalse(is_apk) 432 self.assertFalse(is_compressed) 433 self.assertFalse(should_be_skipped) 434 435 def test_GetApkFileInfo_checkSkippedPrefixesInput(self): 436 # set 437 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo( 438 "SYSTEM_OTHER/preloads/apps/Chats.apk", 439 None, 440 set(["SYSTEM_OTHER/preloads/"])) 441 self.assertTrue(is_apk) 442 self.assertFalse(is_compressed) 443 self.assertTrue(should_be_skipped) 444 445 # tuple 446 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo( 447 "SYSTEM_OTHER/preloads/apps/Chats.apk", 448 None, 449 ("SYSTEM_OTHER/preloads/",)) 450 self.assertTrue(is_apk) 451 self.assertFalse(is_compressed) 452 self.assertTrue(should_be_skipped) 453 454 # list 455 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo( 456 "SYSTEM_OTHER/preloads/apps/Chats.apk", 457 None, 458 ["SYSTEM_OTHER/preloads/"]) 459 self.assertTrue(is_apk) 460 self.assertFalse(is_compressed) 461 self.assertTrue(should_be_skipped) 462 463 # str is invalid. 464 self.assertRaises( 465 AssertionError, GetApkFileInfo, "SYSTEM_OTHER/preloads/apps/Chats.apk", 466 None, "SYSTEM_OTHER/preloads/") 467 468 # None is invalid. 469 self.assertRaises( 470 AssertionError, GetApkFileInfo, "SYSTEM_OTHER/preloads/apps/Chats.apk", 471 None, None) 472 473 def test_ReadApexKeysInfo(self): 474 target_files = common.MakeTempFile(suffix='.zip') 475 with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip: 476 target_files_zip.writestr('META/apexkeys.txt', self.APEX_KEYS_TXT) 477 478 with zipfile.ZipFile(target_files, allowZip64=True) as target_files_zip: 479 keys_info = ReadApexKeysInfo(target_files_zip) 480 481 self.assertEqual({ 482 'apex.apexd_test.apex': ( 483 'system/apex/apexd/apexd_testdata/com.android.apex.test_package.pem', 484 'build/make/target/product/security/testkey', None), 485 'apex.apexd_test_different_app.apex': ( 486 'system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem', 487 'build/make/target/product/security/testkey', None), 488 }, keys_info) 489 490 def test_ReadApexKeysInfo_mismatchingContainerKeys(self): 491 # Mismatching payload public / private keys. 492 apex_keys = self.APEX_KEYS_TXT + ( 493 'name="apex.apexd_test_different_app2.apex" ' 494 'public_key="system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.avbpubkey" ' 495 'private_key="system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem" ' 496 'container_certificate="build/make/target/product/security/testkey.x509.pem" ' 497 'container_private_key="build/make/target/product/security/testkey2.pk8" ' 498 'partition="system"') 499 target_files = common.MakeTempFile(suffix='.zip') 500 with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip: 501 target_files_zip.writestr('META/apexkeys.txt', apex_keys) 502 503 with zipfile.ZipFile(target_files, allowZip64=True) as target_files_zip: 504 self.assertRaises(ValueError, ReadApexKeysInfo, target_files_zip) 505 506 def test_ReadApexKeysInfo_missingPayloadPrivateKey(self): 507 # Invalid lines will be skipped. 508 apex_keys = self.APEX_KEYS_TXT + ( 509 'name="apex.apexd_test_different_app2.apex" ' 510 'public_key="system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.avbpubkey" ' 511 'container_certificate="build/make/target/product/security/testkey.x509.pem" ' 512 'container_private_key="build/make/target/product/security/testkey.pk8"') 513 target_files = common.MakeTempFile(suffix='.zip') 514 with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip: 515 target_files_zip.writestr('META/apexkeys.txt', apex_keys) 516 517 with zipfile.ZipFile(target_files, allowZip64=True) as target_files_zip: 518 keys_info = ReadApexKeysInfo(target_files_zip) 519 520 self.assertEqual({ 521 'apex.apexd_test.apex': ( 522 'system/apex/apexd/apexd_testdata/com.android.apex.test_package.pem', 523 'build/make/target/product/security/testkey', None), 524 'apex.apexd_test_different_app.apex': ( 525 'system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem', 526 'build/make/target/product/security/testkey', None), 527 }, keys_info) 528 529 def test_ReadApexKeysInfo_missingPayloadPublicKey(self): 530 # Invalid lines will be skipped. 531 apex_keys = self.APEX_KEYS_TXT + ( 532 'name="apex.apexd_test_different_app2.apex" ' 533 'private_key="system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem" ' 534 'container_certificate="build/make/target/product/security/testkey.x509.pem" ' 535 'container_private_key="build/make/target/product/security/testkey.pk8"') 536 target_files = common.MakeTempFile(suffix='.zip') 537 with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip: 538 target_files_zip.writestr('META/apexkeys.txt', apex_keys) 539 540 with zipfile.ZipFile(target_files, allowZip64=True) as target_files_zip: 541 keys_info = ReadApexKeysInfo(target_files_zip) 542 543 self.assertEqual({ 544 'apex.apexd_test.apex': ( 545 'system/apex/apexd/apexd_testdata/com.android.apex.test_package.pem', 546 'build/make/target/product/security/testkey', None), 547 'apex.apexd_test_different_app.apex': ( 548 'system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem', 549 'build/make/target/product/security/testkey', None), 550 }, keys_info) 551 552 def test_ReadApexKeysInfo_presignedKeys(self): 553 apex_keys = self.APEX_KEYS_TXT + ( 554 'name="apex.apexd_test_different_app2.apex" ' 555 'private_key="PRESIGNED" ' 556 'public_key="PRESIGNED" ' 557 'container_certificate="PRESIGNED" ' 558 'container_private_key="PRESIGNED"') 559 target_files = common.MakeTempFile(suffix='.zip') 560 with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip: 561 target_files_zip.writestr('META/apexkeys.txt', apex_keys) 562 563 with zipfile.ZipFile(target_files, allowZip64=True) as target_files_zip: 564 keys_info = ReadApexKeysInfo(target_files_zip) 565 566 self.assertEqual({ 567 'apex.apexd_test.apex': ( 568 'system/apex/apexd/apexd_testdata/com.android.apex.test_package.pem', 569 'build/make/target/product/security/testkey', None), 570 'apex.apexd_test_different_app.apex': ( 571 'system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem', 572 'build/make/target/product/security/testkey', None), 573 }, keys_info) 574 575 def test_ReadApexKeysInfo_presignedKeys(self): 576 apex_keys = self.APEX_KEYS_TXT + ( 577 'name="apex.apexd_test_different_app2.apex" ' 578 'private_key="PRESIGNED" ' 579 'public_key="PRESIGNED" ' 580 'container_certificate="PRESIGNED" ' 581 'container_private_key="PRESIGNED"') 582 target_files = common.MakeTempFile(suffix='.zip') 583 with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip: 584 target_files_zip.writestr('META/apexkeys.txt', apex_keys) 585 586 with zipfile.ZipFile(target_files, allowZip64=True) as target_files_zip: 587 keys_info = ReadApexKeysInfo(target_files_zip) 588 589 self.assertEqual({ 590 'apex.apexd_test.apex': ( 591 'system/apex/apexd/apexd_testdata/com.android.apex.test_package.pem', 592 'build/make/target/product/security/testkey', None), 593 'apex.apexd_test_different_app.apex': ( 594 'system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem', 595 'build/make/target/product/security/testkey', None), 596 }, keys_info) 597 598 def test_ReplaceGkiSigningKey(self): 599 common.OPTIONS.gki_signing_key = 'release_gki_key' 600 common.OPTIONS.gki_signing_algorithm = 'release_gki_algorithm' 601 common.OPTIONS.gki_signing_extra_args = 'release_gki_signature_extra_args' 602 603 misc_info = { 604 'gki_signing_key_path': 'default_gki_key', 605 'gki_signing_algorithm': 'default_gki_algorithm', 606 'gki_signing_signature_args': 'default_gki_signature_args', 607 } 608 expected_dict = { 609 'gki_signing_key_path': 'release_gki_key', 610 'gki_signing_algorithm': 'release_gki_algorithm', 611 'gki_signing_signature_args': 'release_gki_signature_extra_args', 612 } 613 ReplaceGkiSigningKey(misc_info) 614 self.assertDictEqual(expected_dict, misc_info) 615 616 def test_ReplaceGkiSigningKey_MissingSigningAlgorithm(self): 617 common.OPTIONS.gki_signing_key = 'release_gki_key' 618 common.OPTIONS.gki_signing_algorithm = None 619 common.OPTIONS.gki_signing_extra_args = 'release_gki_signature_extra_args' 620 621 misc_info = { 622 'gki_signing_key_path': 'default_gki_key', 623 'gki_signing_algorithm': 'default_gki_algorithm', 624 'gki_signing_signature_args': 'default_gki_signature_args', 625 } 626 self.assertRaises(ValueError, ReplaceGkiSigningKey, misc_info) 627 628 def test_ReplaceGkiSigningKey_MissingSigningKeyNop(self): 629 common.OPTIONS.gki_signing_key = None 630 common.OPTIONS.gki_signing_algorithm = 'release_gki_algorithm' 631 common.OPTIONS.gki_signing_extra_args = 'release_gki_signature_extra_args' 632 633 # No change to misc_info if common.OPTIONS.gki_signing_key is missing. 634 misc_info = { 635 'gki_signing_key_path': 'default_gki_key', 636 'gki_signing_algorithm': 'default_gki_algorithm', 637 'gki_signing_signature_args': 'default_gki_signature_args', 638 } 639 expected_dict = { 640 'gki_signing_key_path': 'default_gki_key', 641 'gki_signing_algorithm': 'default_gki_algorithm', 642 'gki_signing_signature_args': 'default_gki_signature_args', 643 } 644 ReplaceGkiSigningKey(misc_info) 645 self.assertDictEqual(expected_dict, misc_info) 646