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