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, ParseAvbInfo, 26 ReadApexKeysInfo, ReplaceCerts, RewriteAvbProps, RewriteProps, 27 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_ReplaceCerts(self): 158 cert1_path = os.path.join(self.testdata_dir, 'platform.x509.pem') 159 with open(cert1_path) as cert1_fp: 160 cert1 = cert1_fp.read() 161 cert2_path = os.path.join(self.testdata_dir, 'media.x509.pem') 162 with open(cert2_path) as cert2_fp: 163 cert2 = cert2_fp.read() 164 cert3_path = os.path.join(self.testdata_dir, 'testkey.x509.pem') 165 with open(cert3_path) as cert3_fp: 166 cert3 = cert3_fp.read() 167 168 # Replace cert1 with cert3. 169 input_xml = self.MAC_PERMISSIONS_XML.format( 170 base64.b16encode(common.ParseCertificate(cert1)).lower(), 171 base64.b16encode(common.ParseCertificate(cert2)).lower()) 172 173 output_xml = self.MAC_PERMISSIONS_XML.format( 174 base64.b16encode(common.ParseCertificate(cert3)).lower(), 175 base64.b16encode(common.ParseCertificate(cert2)).lower()) 176 177 common.OPTIONS.key_map = { 178 cert1_path[:-9] : cert3_path[:-9], 179 } 180 181 self.assertEqual(output_xml, ReplaceCerts(input_xml)) 182 183 def test_ReplaceCerts_duplicateEntries(self): 184 cert1_path = os.path.join(self.testdata_dir, 'platform.x509.pem') 185 with open(cert1_path) as cert1_fp: 186 cert1 = cert1_fp.read() 187 cert2_path = os.path.join(self.testdata_dir, 'media.x509.pem') 188 with open(cert2_path) as cert2_fp: 189 cert2 = cert2_fp.read() 190 191 # Replace cert1 with cert2, which leads to duplicate entries. 192 input_xml = self.MAC_PERMISSIONS_XML.format( 193 base64.b16encode(common.ParseCertificate(cert1)).lower(), 194 base64.b16encode(common.ParseCertificate(cert2)).lower()) 195 196 common.OPTIONS.key_map = { 197 cert1_path[:-9] : cert2_path[:-9], 198 } 199 self.assertRaises(AssertionError, ReplaceCerts, input_xml) 200 201 def test_ReplaceCerts_skipNonExistentCerts(self): 202 cert1_path = os.path.join(self.testdata_dir, 'platform.x509.pem') 203 with open(cert1_path) as cert1_fp: 204 cert1 = cert1_fp.read() 205 cert2_path = os.path.join(self.testdata_dir, 'media.x509.pem') 206 with open(cert2_path) as cert2_fp: 207 cert2 = cert2_fp.read() 208 cert3_path = os.path.join(self.testdata_dir, 'testkey.x509.pem') 209 with open(cert3_path) as cert3_fp: 210 cert3 = cert3_fp.read() 211 212 input_xml = self.MAC_PERMISSIONS_XML.format( 213 base64.b16encode(common.ParseCertificate(cert1)).lower(), 214 base64.b16encode(common.ParseCertificate(cert2)).lower()) 215 216 output_xml = self.MAC_PERMISSIONS_XML.format( 217 base64.b16encode(common.ParseCertificate(cert3)).lower(), 218 base64.b16encode(common.ParseCertificate(cert2)).lower()) 219 220 common.OPTIONS.key_map = { 221 cert1_path[:-9] : cert3_path[:-9], 222 'non-existent' : cert3_path[:-9], 223 cert2_path[:-9] : 'non-existent', 224 } 225 self.assertEqual(output_xml, ReplaceCerts(input_xml)) 226 227 def test_WriteOtacerts(self): 228 certs = [ 229 os.path.join(self.testdata_dir, 'platform.x509.pem'), 230 os.path.join(self.testdata_dir, 'media.x509.pem'), 231 os.path.join(self.testdata_dir, 'testkey.x509.pem'), 232 ] 233 entry_name = 'SYSTEM/etc/security/otacerts.zip' 234 output_file = common.MakeTempFile(suffix='.zip') 235 with zipfile.ZipFile(output_file, 'w', allowZip64=True) as output_zip: 236 WriteOtacerts(output_zip, entry_name, certs) 237 with zipfile.ZipFile(output_file) as input_zip: 238 self.assertIn(entry_name, input_zip.namelist()) 239 otacerts_file = io.BytesIO(input_zip.read(entry_name)) 240 with zipfile.ZipFile(otacerts_file) as otacerts_zip: 241 self.assertEqual(3, len(otacerts_zip.namelist())) 242 243 def test_CheckApkAndApexKeysAvailable(self): 244 input_file = common.MakeTempFile(suffix='.zip') 245 with zipfile.ZipFile(input_file, 'w', allowZip64=True) as input_zip: 246 input_zip.writestr('SYSTEM/app/App1.apk', "App1-content") 247 input_zip.writestr('SYSTEM/app/App2.apk.gz', "App2-content") 248 249 apk_key_map = { 250 'App1.apk' : 'key1', 251 'App2.apk' : 'key2', 252 'App3.apk' : 'key3', 253 } 254 with zipfile.ZipFile(input_file) as input_zip: 255 CheckApkAndApexKeysAvailable(input_zip, apk_key_map, None, {}) 256 CheckApkAndApexKeysAvailable(input_zip, apk_key_map, '.gz', {}) 257 258 # 'App2.apk.gz' won't be considered as an APK. 259 CheckApkAndApexKeysAvailable(input_zip, apk_key_map, None, {}) 260 CheckApkAndApexKeysAvailable(input_zip, apk_key_map, '.xz', {}) 261 262 del apk_key_map['App2.apk'] 263 self.assertRaises( 264 AssertionError, CheckApkAndApexKeysAvailable, input_zip, apk_key_map, 265 '.gz', {}) 266 267 def test_CheckApkAndApexKeysAvailable_invalidApexKeys(self): 268 input_file = common.MakeTempFile(suffix='.zip') 269 with zipfile.ZipFile(input_file, 'w', allowZip64=True) as input_zip: 270 input_zip.writestr('SYSTEM/apex/Apex1.apex', "Apex1-content") 271 input_zip.writestr('SYSTEM/apex/Apex2.apex', "Apex2-content") 272 273 apk_key_map = { 274 'Apex1.apex' : 'key1', 275 'Apex2.apex' : 'key2', 276 'Apex3.apex' : 'key3', 277 } 278 apex_keys = { 279 'Apex1.apex' : ('payload-key1', 'container-key1', None), 280 'Apex2.apex' : ('payload-key2', 'container-key2', None), 281 } 282 with zipfile.ZipFile(input_file) as input_zip: 283 CheckApkAndApexKeysAvailable(input_zip, apk_key_map, None, apex_keys) 284 285 # Fine to have both keys as PRESIGNED. 286 apex_keys['Apex2.apex'] = ('PRESIGNED', 'PRESIGNED', None) 287 CheckApkAndApexKeysAvailable(input_zip, apk_key_map, None, apex_keys) 288 289 # Having only one of them as PRESIGNED is not allowed. 290 apex_keys['Apex2.apex'] = ('payload-key2', 'PRESIGNED', None) 291 self.assertRaises( 292 AssertionError, CheckApkAndApexKeysAvailable, input_zip, apk_key_map, 293 None, apex_keys) 294 295 apex_keys['Apex2.apex'] = ('PRESIGNED', 'container-key1', None) 296 self.assertRaises( 297 AssertionError, CheckApkAndApexKeysAvailable, input_zip, apk_key_map, 298 None, apex_keys) 299 300 def test_GetApkFileInfo(self): 301 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo( 302 "PRODUCT/apps/Chats.apk", None, []) 303 self.assertTrue(is_apk) 304 self.assertFalse(is_compressed) 305 self.assertFalse(should_be_skipped) 306 307 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo( 308 "PRODUCT/apps/Chats.apk", None, []) 309 self.assertTrue(is_apk) 310 self.assertFalse(is_compressed) 311 self.assertFalse(should_be_skipped) 312 313 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo( 314 "PRODUCT/apps/Chats.dat", None, []) 315 self.assertFalse(is_apk) 316 self.assertFalse(is_compressed) 317 self.assertFalse(should_be_skipped) 318 319 def test_GetApkFileInfo_withCompressedApks(self): 320 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo( 321 "PRODUCT/apps/Chats.apk.gz", ".gz", []) 322 self.assertTrue(is_apk) 323 self.assertTrue(is_compressed) 324 self.assertFalse(should_be_skipped) 325 326 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo( 327 "PRODUCT/apps/Chats.apk.gz", ".xz", []) 328 self.assertFalse(is_apk) 329 self.assertFalse(is_compressed) 330 self.assertFalse(should_be_skipped) 331 332 self.assertRaises( 333 AssertionError, GetApkFileInfo, "PRODUCT/apps/Chats.apk", "", []) 334 335 self.assertRaises( 336 AssertionError, GetApkFileInfo, "PRODUCT/apps/Chats.apk", "apk", []) 337 338 def test_GetApkFileInfo_withSkippedPrefixes(self): 339 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo( 340 "PRODUCT/preloads/apps/Chats.apk", None, set()) 341 self.assertTrue(is_apk) 342 self.assertFalse(is_compressed) 343 self.assertFalse(should_be_skipped) 344 345 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo( 346 "PRODUCT/preloads/apps/Chats.apk", 347 None, 348 set(["PRODUCT/preloads/"])) 349 self.assertTrue(is_apk) 350 self.assertFalse(is_compressed) 351 self.assertTrue(should_be_skipped) 352 353 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo( 354 "SYSTEM_OTHER/preloads/apps/Chats.apk", 355 None, 356 set(["SYSTEM/preloads/", "SYSTEM_OTHER/preloads/"])) 357 self.assertTrue(is_apk) 358 self.assertFalse(is_compressed) 359 self.assertTrue(should_be_skipped) 360 361 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo( 362 "SYSTEM_OTHER/preloads/apps/Chats.apk.gz", 363 ".gz", 364 set(["PRODUCT/prebuilts/", "SYSTEM_OTHER/preloads/"])) 365 self.assertTrue(is_apk) 366 self.assertTrue(is_compressed) 367 self.assertTrue(should_be_skipped) 368 369 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo( 370 "SYSTEM_OTHER/preloads/apps/Chats.dat", 371 None, 372 set(["SYSTEM_OTHER/preloads/"])) 373 self.assertFalse(is_apk) 374 self.assertFalse(is_compressed) 375 self.assertFalse(should_be_skipped) 376 377 def test_GetApkFileInfo_checkSkippedPrefixesInput(self): 378 # set 379 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo( 380 "SYSTEM_OTHER/preloads/apps/Chats.apk", 381 None, 382 set(["SYSTEM_OTHER/preloads/"])) 383 self.assertTrue(is_apk) 384 self.assertFalse(is_compressed) 385 self.assertTrue(should_be_skipped) 386 387 # tuple 388 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo( 389 "SYSTEM_OTHER/preloads/apps/Chats.apk", 390 None, 391 ("SYSTEM_OTHER/preloads/",)) 392 self.assertTrue(is_apk) 393 self.assertFalse(is_compressed) 394 self.assertTrue(should_be_skipped) 395 396 # list 397 (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo( 398 "SYSTEM_OTHER/preloads/apps/Chats.apk", 399 None, 400 ["SYSTEM_OTHER/preloads/"]) 401 self.assertTrue(is_apk) 402 self.assertFalse(is_compressed) 403 self.assertTrue(should_be_skipped) 404 405 # str is invalid. 406 self.assertRaises( 407 AssertionError, GetApkFileInfo, "SYSTEM_OTHER/preloads/apps/Chats.apk", 408 None, "SYSTEM_OTHER/preloads/") 409 410 # None is invalid. 411 self.assertRaises( 412 AssertionError, GetApkFileInfo, "SYSTEM_OTHER/preloads/apps/Chats.apk", 413 None, None) 414 415 def test_ReadApexKeysInfo(self): 416 target_files = common.MakeTempFile(suffix='.zip') 417 with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip: 418 target_files_zip.writestr('META/apexkeys.txt', self.APEX_KEYS_TXT) 419 420 with zipfile.ZipFile(target_files, allowZip64=True) as target_files_zip: 421 keys_info = ReadApexKeysInfo(target_files_zip) 422 423 self.assertEqual({ 424 'apex.apexd_test.apex': ( 425 'system/apex/apexd/apexd_testdata/com.android.apex.test_package.pem', 426 'build/make/target/product/security/testkey', None), 427 'apex.apexd_test_different_app.apex': ( 428 'system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem', 429 'build/make/target/product/security/testkey', None), 430 }, keys_info) 431 432 def test_ReadApexKeysInfo_mismatchingContainerKeys(self): 433 # Mismatching payload public / private keys. 434 apex_keys = self.APEX_KEYS_TXT + ( 435 'name="apex.apexd_test_different_app2.apex" ' 436 'public_key="system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.avbpubkey" ' 437 'private_key="system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem" ' 438 'container_certificate="build/make/target/product/security/testkey.x509.pem" ' 439 'container_private_key="build/make/target/product/security/testkey2.pk8" ' 440 'partition="system"') 441 target_files = common.MakeTempFile(suffix='.zip') 442 with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip: 443 target_files_zip.writestr('META/apexkeys.txt', apex_keys) 444 445 with zipfile.ZipFile(target_files, allowZip64=True) as target_files_zip: 446 self.assertRaises(ValueError, ReadApexKeysInfo, target_files_zip) 447 448 def test_ReadApexKeysInfo_missingPayloadPrivateKey(self): 449 # Invalid lines will be skipped. 450 apex_keys = self.APEX_KEYS_TXT + ( 451 'name="apex.apexd_test_different_app2.apex" ' 452 'public_key="system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.avbpubkey" ' 453 'container_certificate="build/make/target/product/security/testkey.x509.pem" ' 454 'container_private_key="build/make/target/product/security/testkey.pk8"') 455 target_files = common.MakeTempFile(suffix='.zip') 456 with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip: 457 target_files_zip.writestr('META/apexkeys.txt', apex_keys) 458 459 with zipfile.ZipFile(target_files, allowZip64=True) as target_files_zip: 460 keys_info = ReadApexKeysInfo(target_files_zip) 461 462 self.assertEqual({ 463 'apex.apexd_test.apex': ( 464 'system/apex/apexd/apexd_testdata/com.android.apex.test_package.pem', 465 'build/make/target/product/security/testkey', None), 466 'apex.apexd_test_different_app.apex': ( 467 'system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem', 468 'build/make/target/product/security/testkey', None), 469 }, keys_info) 470 471 def test_ReadApexKeysInfo_missingPayloadPublicKey(self): 472 # Invalid lines will be skipped. 473 apex_keys = self.APEX_KEYS_TXT + ( 474 'name="apex.apexd_test_different_app2.apex" ' 475 'private_key="system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem" ' 476 'container_certificate="build/make/target/product/security/testkey.x509.pem" ' 477 'container_private_key="build/make/target/product/security/testkey.pk8"') 478 target_files = common.MakeTempFile(suffix='.zip') 479 with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip: 480 target_files_zip.writestr('META/apexkeys.txt', apex_keys) 481 482 with zipfile.ZipFile(target_files, allowZip64=True) as target_files_zip: 483 keys_info = ReadApexKeysInfo(target_files_zip) 484 485 self.assertEqual({ 486 'apex.apexd_test.apex': ( 487 'system/apex/apexd/apexd_testdata/com.android.apex.test_package.pem', 488 'build/make/target/product/security/testkey', None), 489 'apex.apexd_test_different_app.apex': ( 490 'system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem', 491 'build/make/target/product/security/testkey', None), 492 }, keys_info) 493 494 def test_ReadApexKeysInfo_presignedKeys(self): 495 apex_keys = self.APEX_KEYS_TXT + ( 496 'name="apex.apexd_test_different_app2.apex" ' 497 'private_key="PRESIGNED" ' 498 'public_key="PRESIGNED" ' 499 'container_certificate="PRESIGNED" ' 500 'container_private_key="PRESIGNED"') 501 target_files = common.MakeTempFile(suffix='.zip') 502 with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip: 503 target_files_zip.writestr('META/apexkeys.txt', apex_keys) 504 505 with zipfile.ZipFile(target_files, allowZip64=True) as target_files_zip: 506 keys_info = ReadApexKeysInfo(target_files_zip) 507 508 self.assertEqual({ 509 'apex.apexd_test.apex': ( 510 'system/apex/apexd/apexd_testdata/com.android.apex.test_package.pem', 511 'build/make/target/product/security/testkey', None), 512 'apex.apexd_test_different_app.apex': ( 513 'system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem', 514 'build/make/target/product/security/testkey', None), 515 }, keys_info) 516 517 def test_ReadApexKeysInfo_presignedKeys(self): 518 apex_keys = self.APEX_KEYS_TXT + ( 519 'name="apex.apexd_test_different_app2.apex" ' 520 'private_key="PRESIGNED" ' 521 'public_key="PRESIGNED" ' 522 'container_certificate="PRESIGNED" ' 523 'container_private_key="PRESIGNED"') 524 target_files = common.MakeTempFile(suffix='.zip') 525 with zipfile.ZipFile(target_files, 'w', allowZip64=True) as target_files_zip: 526 target_files_zip.writestr('META/apexkeys.txt', apex_keys) 527 528 with zipfile.ZipFile(target_files, allowZip64=True) as target_files_zip: 529 keys_info = ReadApexKeysInfo(target_files_zip) 530 531 self.assertEqual({ 532 'apex.apexd_test.apex': ( 533 'system/apex/apexd/apexd_testdata/com.android.apex.test_package.pem', 534 'build/make/target/product/security/testkey', None), 535 'apex.apexd_test_different_app.apex': ( 536 'system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem', 537 'build/make/target/product/security/testkey', None), 538 }, keys_info) 539 540 def test_ParseAvbInfo(self): 541 avb_info_string = """ 542 Footer version: 1.0 543 Image size: 9999999 bytes 544 Original image size: 8888888 bytes 545 VBMeta offset: 7777777 546 VBMeta size: 1111 bytes 547 -- 548 Minimum libavb version: 1.0 549 Header Block: 222 bytes 550 Authentication Block: 333 bytes 551 Auxiliary Block: 888 bytes 552 Public key (sha1): abababababababababababababababababababab 553 Algorithm: SHA256_RSA2048 554 Rollback Index: 0 555 Flags: 0 556 Rollback Index Location: 0 557 Release String: 'avbtool 1.3.0' 558 Descriptors: 559 Hashtree descriptor: 560 Version of dm-verity: 1 561 Image Size: 8888888 bytes 562 Tree Offset: 8888888 563 Tree Size: 44444 bytes 564 Data Block Size: 4444 bytes 565 Hash Block Size: 4444 bytes 566 FEC num roots: 0 567 FEC offset: 0 568 FEC size: 0 bytes 569 Hash Algorithm: sha1 570 Partition Name: partition-name 571 Salt: cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd 572 Root Digest: efefefefefefefefefefefefefefefefefef 573 Flags: 0 574 Prop: prop.key -> 'prop.value' 575 """ 576 577 self.assertEqual( 578 { 579 'Footer version': '1.0', 580 'Image size': '9999999 bytes', 581 'Original image size': '8888888 bytes', 582 'VBMeta offset': '7777777', 583 'VBMeta size': '1111 bytes', 584 'Minimum libavb version': '1.0', 585 'Header Block': '222 bytes', 586 'Authentication Block': '333 bytes', 587 'Auxiliary Block': '888 bytes', 588 'Public key (sha1)': 'abababababababababababababababababababab', 589 'Algorithm': 'SHA256_RSA2048', 590 'Rollback Index': '0', 591 'Flags': '0', 592 'Rollback Index Location': '0', 593 'Release String': "'avbtool 1.3.0'", 594 'Descriptors': [ 595 { 596 'Hashtree descriptor': { 597 'Version of dm-verity': '1', 598 'Image Size': '8888888 bytes', 599 'Tree Offset': '8888888', 600 'Tree Size': '44444 bytes', 601 'Data Block Size': '4444 bytes', 602 'Hash Block Size': '4444 bytes', 603 'FEC num roots': '0', 604 'FEC offset': '0', 605 'FEC size': '0 bytes', 606 'Hash Algorithm': 'sha1', 607 'Partition Name': 'partition-name', 608 'Salt': 'cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd', 609 'Root Digest': 'efefefefefefefefefefefefefefefefefef', 610 'Flags': '0', 611 } 612 }, 613 { 614 'Prop': { 615 'prop.key': 'prop.value', 616 } 617 }, 618 ], 619 }, 620 ParseAvbInfo(avb_info_string), 621 )