Home | History | Annotate | Download | only in releasetools
      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 
     17 import base64
     18 import os.path
     19 import zipfile
     20 
     21 import common
     22 import test_utils
     23 from sign_target_files_apks import (
     24     CheckApkAndApexKeysAvailable, EditTags, GetApkFileInfo, ReadApexKeysInfo,
     25     ReplaceCerts, ReplaceVerityKeyId, RewriteProps)
     26 
     27 
     28 class SignTargetFilesApksTest(test_utils.ReleaseToolsTestCase):
     29 
     30   MAC_PERMISSIONS_XML = """<?xml version="1.0" encoding="iso-8859-1"?>
     31 <policy>
     32   <signer signature="{}"><seinfo value="platform"/></signer>
     33   <signer signature="{}"><seinfo value="media"/></signer>
     34 </policy>"""
     35 
     36   # pylint: disable=line-too-long
     37   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/target/product/security/testkey.x509.pem" container_private_key="build/target/product/security/testkey.pk8"
     38 name="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/target/product/security/testkey.x509.pem" container_private_key="build/target/product/security/testkey.pk8"
     39 """
     40 
     41   def setUp(self):
     42     self.testdata_dir = test_utils.get_testdata_dir()
     43 
     44   def test_EditTags(self):
     45     self.assertEqual(EditTags('dev-keys'), ('release-keys'))
     46     self.assertEqual(EditTags('test-keys'), ('release-keys'))
     47 
     48     # Multiple tags.
     49     self.assertEqual(EditTags('abc,dev-keys,xyz'), ('abc,release-keys,xyz'))
     50 
     51     # Tags are sorted.
     52     self.assertEqual(EditTags('xyz,abc,dev-keys,xyz'), ('abc,release-keys,xyz'))
     53 
     54   def test_RewriteProps(self):
     55     props = (
     56         ('', ''),
     57         ('ro.build.fingerprint=foo/bar/dev-keys',
     58          'ro.build.fingerprint=foo/bar/release-keys'),
     59         ('ro.build.thumbprint=foo/bar/dev-keys',
     60          'ro.build.thumbprint=foo/bar/release-keys'),
     61         ('ro.vendor.build.fingerprint=foo/bar/dev-keys',
     62          'ro.vendor.build.fingerprint=foo/bar/release-keys'),
     63         ('ro.vendor.build.thumbprint=foo/bar/dev-keys',
     64          'ro.vendor.build.thumbprint=foo/bar/release-keys'),
     65         ('ro.odm.build.fingerprint=foo/bar/test-keys',
     66          'ro.odm.build.fingerprint=foo/bar/release-keys'),
     67         ('ro.odm.build.thumbprint=foo/bar/test-keys',
     68          'ro.odm.build.thumbprint=foo/bar/release-keys'),
     69         ('ro.product.build.fingerprint=foo/bar/dev-keys',
     70          'ro.product.build.fingerprint=foo/bar/release-keys'),
     71         ('ro.product.build.thumbprint=foo/bar/dev-keys',
     72          'ro.product.build.thumbprint=foo/bar/release-keys'),
     73         ('ro.product_services.build.fingerprint=foo/bar/test-keys',
     74          'ro.product_services.build.fingerprint=foo/bar/release-keys'),
     75         ('ro.product_services.build.thumbprint=foo/bar/test-keys',
     76          'ro.product_services.build.thumbprint=foo/bar/release-keys'),
     77         ('# comment line 1', '# comment line 1'),
     78         ('ro.bootimage.build.fingerprint=foo/bar/dev-keys',
     79          'ro.bootimage.build.fingerprint=foo/bar/release-keys'),
     80         ('ro.build.description='
     81          'sailfish-user 8.0.0 OPR6.170623.012 4283428 dev-keys',
     82          'ro.build.description='
     83          'sailfish-user 8.0.0 OPR6.170623.012 4283428 release-keys'),
     84         ('ro.build.tags=dev-keys', 'ro.build.tags=release-keys'),
     85         ('ro.build.tags=test-keys', 'ro.build.tags=release-keys'),
     86         ('ro.system.build.tags=dev-keys',
     87          'ro.system.build.tags=release-keys'),
     88         ('ro.vendor.build.tags=dev-keys',
     89          'ro.vendor.build.tags=release-keys'),
     90         ('ro.odm.build.tags=dev-keys',
     91          'ro.odm.build.tags=release-keys'),
     92         ('ro.product.build.tags=dev-keys',
     93          'ro.product.build.tags=release-keys'),
     94         ('ro.product_services.build.tags=dev-keys',
     95          'ro.product_services.build.tags=release-keys'),
     96         ('# comment line 2', '# comment line 2'),
     97         ('ro.build.display.id=OPR6.170623.012 dev-keys',
     98          'ro.build.display.id=OPR6.170623.012'),
     99         ('# comment line 3', '# comment line 3'),
    100     )
    101 
    102     # Assert the case for each individual line.
    103     for prop, expected in props:
    104       self.assertEqual(expected + '\n', RewriteProps(prop))
    105 
    106     # Concatenate all the input lines.
    107     self.assertEqual(
    108         '\n'.join([prop[1] for prop in props]) + '\n',
    109         RewriteProps('\n'.join([prop[0] for prop in props])))
    110 
    111   def test_ReplaceVerityKeyId(self):
    112     BOOT_CMDLINE1 = (
    113         "console=ttyHSL0,115200,n8 androidboot.console=ttyHSL0 "
    114         "androidboot.hardware=marlin user_debug=31 ehci-hcd.park=3 "
    115         "lpm_levels.sleep_disabled=1 cma=32M@0-0xffffffff loop.max_part=7 "
    116         "buildvariant=userdebug "
    117         "veritykeyid=id:7e4333f9bba00adfe0ede979e28ed1920492b40f\n")
    118 
    119     BOOT_CMDLINE2 = (
    120         "console=ttyHSL0,115200,n8 androidboot.console=ttyHSL0 "
    121         "androidboot.hardware=marlin user_debug=31 ehci-hcd.park=3 "
    122         "lpm_levels.sleep_disabled=1 cma=32M@0-0xffffffff loop.max_part=7 "
    123         "buildvariant=userdebug "
    124         "veritykeyid=id:d24f2590e9abab5cff5f59da4c4f0366e3f43e94\n")
    125 
    126     input_file = common.MakeTempFile(suffix='.zip')
    127     with zipfile.ZipFile(input_file, 'w') as input_zip:
    128       input_zip.writestr('BOOT/cmdline', BOOT_CMDLINE1)
    129 
    130     # Test with the first certificate.
    131     cert_file = os.path.join(self.testdata_dir, 'verity.x509.pem')
    132 
    133     output_file = common.MakeTempFile(suffix='.zip')
    134     with zipfile.ZipFile(input_file, 'r') as input_zip, \
    135          zipfile.ZipFile(output_file, 'w') as output_zip:
    136       ReplaceVerityKeyId(input_zip, output_zip, cert_file)
    137 
    138     with zipfile.ZipFile(output_file) as output_zip:
    139       self.assertEqual(BOOT_CMDLINE1, output_zip.read('BOOT/cmdline'))
    140 
    141     # Test with the second certificate.
    142     cert_file = os.path.join(self.testdata_dir, 'testkey.x509.pem')
    143 
    144     with zipfile.ZipFile(input_file, 'r') as input_zip, \
    145          zipfile.ZipFile(output_file, 'w') as output_zip:
    146       ReplaceVerityKeyId(input_zip, output_zip, cert_file)
    147 
    148     with zipfile.ZipFile(output_file) as output_zip:
    149       self.assertEqual(BOOT_CMDLINE2, output_zip.read('BOOT/cmdline'))
    150 
    151   def test_ReplaceVerityKeyId_no_veritykeyid(self):
    152     BOOT_CMDLINE = (
    153         "console=ttyHSL0,115200,n8 androidboot.hardware=bullhead boot_cpus=0-5 "
    154         "lpm_levels.sleep_disabled=1 msm_poweroff.download_mode=0 "
    155         "loop.max_part=7\n")
    156 
    157     input_file = common.MakeTempFile(suffix='.zip')
    158     with zipfile.ZipFile(input_file, 'w') as input_zip:
    159       input_zip.writestr('BOOT/cmdline', BOOT_CMDLINE)
    160 
    161     output_file = common.MakeTempFile(suffix='.zip')
    162     with zipfile.ZipFile(input_file, 'r') as input_zip, \
    163          zipfile.ZipFile(output_file, 'w') as output_zip:
    164       ReplaceVerityKeyId(input_zip, output_zip, None)
    165 
    166     with zipfile.ZipFile(output_file) as output_zip:
    167       self.assertEqual(BOOT_CMDLINE, output_zip.read('BOOT/cmdline'))
    168 
    169   def test_ReplaceCerts(self):
    170     cert1_path = os.path.join(self.testdata_dir, 'platform.x509.pem')
    171     with open(cert1_path) as cert1_fp:
    172       cert1 = cert1_fp.read()
    173     cert2_path = os.path.join(self.testdata_dir, 'media.x509.pem')
    174     with open(cert2_path) as cert2_fp:
    175       cert2 = cert2_fp.read()
    176     cert3_path = os.path.join(self.testdata_dir, 'testkey.x509.pem')
    177     with open(cert3_path) as cert3_fp:
    178       cert3 = cert3_fp.read()
    179 
    180     # Replace cert1 with cert3.
    181     input_xml = self.MAC_PERMISSIONS_XML.format(
    182         base64.b16encode(common.ParseCertificate(cert1)).lower(),
    183         base64.b16encode(common.ParseCertificate(cert2)).lower())
    184 
    185     output_xml = self.MAC_PERMISSIONS_XML.format(
    186         base64.b16encode(common.ParseCertificate(cert3)).lower(),
    187         base64.b16encode(common.ParseCertificate(cert2)).lower())
    188 
    189     common.OPTIONS.key_map = {
    190         cert1_path[:-9] : cert3_path[:-9],
    191     }
    192 
    193     self.assertEqual(output_xml, ReplaceCerts(input_xml))
    194 
    195   def test_ReplaceCerts_duplicateEntries(self):
    196     cert1_path = os.path.join(self.testdata_dir, 'platform.x509.pem')
    197     with open(cert1_path) as cert1_fp:
    198       cert1 = cert1_fp.read()
    199     cert2_path = os.path.join(self.testdata_dir, 'media.x509.pem')
    200     with open(cert2_path) as cert2_fp:
    201       cert2 = cert2_fp.read()
    202 
    203     # Replace cert1 with cert2, which leads to duplicate entries.
    204     input_xml = self.MAC_PERMISSIONS_XML.format(
    205         base64.b16encode(common.ParseCertificate(cert1)).lower(),
    206         base64.b16encode(common.ParseCertificate(cert2)).lower())
    207 
    208     common.OPTIONS.key_map = {
    209         cert1_path[:-9] : cert2_path[:-9],
    210     }
    211     self.assertRaises(AssertionError, ReplaceCerts, input_xml)
    212 
    213   def test_ReplaceCerts_skipNonExistentCerts(self):
    214     cert1_path = os.path.join(self.testdata_dir, 'platform.x509.pem')
    215     with open(cert1_path) as cert1_fp:
    216       cert1 = cert1_fp.read()
    217     cert2_path = os.path.join(self.testdata_dir, 'media.x509.pem')
    218     with open(cert2_path) as cert2_fp:
    219       cert2 = cert2_fp.read()
    220     cert3_path = os.path.join(self.testdata_dir, 'testkey.x509.pem')
    221     with open(cert3_path) as cert3_fp:
    222       cert3 = cert3_fp.read()
    223 
    224     input_xml = self.MAC_PERMISSIONS_XML.format(
    225         base64.b16encode(common.ParseCertificate(cert1)).lower(),
    226         base64.b16encode(common.ParseCertificate(cert2)).lower())
    227 
    228     output_xml = self.MAC_PERMISSIONS_XML.format(
    229         base64.b16encode(common.ParseCertificate(cert3)).lower(),
    230         base64.b16encode(common.ParseCertificate(cert2)).lower())
    231 
    232     common.OPTIONS.key_map = {
    233         cert1_path[:-9] : cert3_path[:-9],
    234         'non-existent' : cert3_path[:-9],
    235         cert2_path[:-9] : 'non-existent',
    236     }
    237     self.assertEqual(output_xml, ReplaceCerts(input_xml))
    238 
    239   def test_CheckApkAndApexKeysAvailable(self):
    240     input_file = common.MakeTempFile(suffix='.zip')
    241     with zipfile.ZipFile(input_file, 'w') as input_zip:
    242       input_zip.writestr('SYSTEM/app/App1.apk', "App1-content")
    243       input_zip.writestr('SYSTEM/app/App2.apk.gz', "App2-content")
    244 
    245     apk_key_map = {
    246         'App1.apk' : 'key1',
    247         'App2.apk' : 'key2',
    248         'App3.apk' : 'key3',
    249     }
    250     with zipfile.ZipFile(input_file) as input_zip:
    251       CheckApkAndApexKeysAvailable(input_zip, apk_key_map, None, {})
    252       CheckApkAndApexKeysAvailable(input_zip, apk_key_map, '.gz', {})
    253 
    254       # 'App2.apk.gz' won't be considered as an APK.
    255       CheckApkAndApexKeysAvailable(input_zip, apk_key_map, None, {})
    256       CheckApkAndApexKeysAvailable(input_zip, apk_key_map, '.xz', {})
    257 
    258       del apk_key_map['App2.apk']
    259       self.assertRaises(
    260           AssertionError, CheckApkAndApexKeysAvailable, input_zip, apk_key_map,
    261           '.gz', {})
    262 
    263   def test_CheckApkAndApexKeysAvailable_invalidApexKeys(self):
    264     input_file = common.MakeTempFile(suffix='.zip')
    265     with zipfile.ZipFile(input_file, 'w') as input_zip:
    266       input_zip.writestr('SYSTEM/apex/Apex1.apex', "Apex1-content")
    267       input_zip.writestr('SYSTEM/apex/Apex2.apex', "Apex2-content")
    268 
    269     apk_key_map = {
    270         'Apex1.apex' : 'key1',
    271         'Apex2.apex' : 'key2',
    272         'Apex3.apex' : 'key3',
    273     }
    274     apex_keys = {
    275         'Apex1.apex' : ('payload-key1', 'container-key1'),
    276         'Apex2.apex' : ('payload-key2', 'container-key2'),
    277     }
    278     with zipfile.ZipFile(input_file) as input_zip:
    279       CheckApkAndApexKeysAvailable(input_zip, apk_key_map, None, apex_keys)
    280 
    281       # Fine to have both keys as PRESIGNED.
    282       apex_keys['Apex2.apex'] = ('PRESIGNED', 'PRESIGNED')
    283       CheckApkAndApexKeysAvailable(input_zip, apk_key_map, None, apex_keys)
    284 
    285       # Having only one of them as PRESIGNED is not allowed.
    286       apex_keys['Apex2.apex'] = ('payload-key2', 'PRESIGNED')
    287       self.assertRaises(
    288           AssertionError, CheckApkAndApexKeysAvailable, input_zip, apk_key_map,
    289           None, apex_keys)
    290 
    291       apex_keys['Apex2.apex'] = ('PRESIGNED', 'container-key1')
    292       self.assertRaises(
    293           AssertionError, CheckApkAndApexKeysAvailable, input_zip, apk_key_map,
    294           None, apex_keys)
    295 
    296   def test_GetApkFileInfo(self):
    297     (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
    298         "PRODUCT/apps/Chats.apk", None, [])
    299     self.assertTrue(is_apk)
    300     self.assertFalse(is_compressed)
    301     self.assertFalse(should_be_skipped)
    302 
    303     (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
    304         "PRODUCT/apps/Chats.apk", None, [])
    305     self.assertTrue(is_apk)
    306     self.assertFalse(is_compressed)
    307     self.assertFalse(should_be_skipped)
    308 
    309     (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
    310         "PRODUCT/apps/Chats.dat", None, [])
    311     self.assertFalse(is_apk)
    312     self.assertFalse(is_compressed)
    313     self.assertFalse(should_be_skipped)
    314 
    315   def test_GetApkFileInfo_withCompressedApks(self):
    316     (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
    317         "PRODUCT/apps/Chats.apk.gz", ".gz", [])
    318     self.assertTrue(is_apk)
    319     self.assertTrue(is_compressed)
    320     self.assertFalse(should_be_skipped)
    321 
    322     (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
    323         "PRODUCT/apps/Chats.apk.gz", ".xz", [])
    324     self.assertFalse(is_apk)
    325     self.assertFalse(is_compressed)
    326     self.assertFalse(should_be_skipped)
    327 
    328     self.assertRaises(
    329         AssertionError, GetApkFileInfo, "PRODUCT/apps/Chats.apk", "", [])
    330 
    331     self.assertRaises(
    332         AssertionError, GetApkFileInfo, "PRODUCT/apps/Chats.apk", "apk", [])
    333 
    334   def test_GetApkFileInfo_withSkippedPrefixes(self):
    335     (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
    336         "PRODUCT/preloads/apps/Chats.apk", None, set())
    337     self.assertTrue(is_apk)
    338     self.assertFalse(is_compressed)
    339     self.assertFalse(should_be_skipped)
    340 
    341     (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
    342         "PRODUCT/preloads/apps/Chats.apk",
    343         None,
    344         set(["PRODUCT/preloads/"]))
    345     self.assertTrue(is_apk)
    346     self.assertFalse(is_compressed)
    347     self.assertTrue(should_be_skipped)
    348 
    349     (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
    350         "SYSTEM_OTHER/preloads/apps/Chats.apk",
    351         None,
    352         set(["SYSTEM/preloads/", "SYSTEM_OTHER/preloads/"]))
    353     self.assertTrue(is_apk)
    354     self.assertFalse(is_compressed)
    355     self.assertTrue(should_be_skipped)
    356 
    357     (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
    358         "SYSTEM_OTHER/preloads/apps/Chats.apk.gz",
    359         ".gz",
    360         set(["PRODUCT/prebuilts/", "SYSTEM_OTHER/preloads/"]))
    361     self.assertTrue(is_apk)
    362     self.assertTrue(is_compressed)
    363     self.assertTrue(should_be_skipped)
    364 
    365     (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
    366         "SYSTEM_OTHER/preloads/apps/Chats.dat",
    367         None,
    368         set(["SYSTEM_OTHER/preloads/"]))
    369     self.assertFalse(is_apk)
    370     self.assertFalse(is_compressed)
    371     self.assertFalse(should_be_skipped)
    372 
    373   def test_GetApkFileInfo_checkSkippedPrefixesInput(self):
    374     # set
    375     (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
    376         "SYSTEM_OTHER/preloads/apps/Chats.apk",
    377         None,
    378         set(["SYSTEM_OTHER/preloads/"]))
    379     self.assertTrue(is_apk)
    380     self.assertFalse(is_compressed)
    381     self.assertTrue(should_be_skipped)
    382 
    383     # tuple
    384     (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
    385         "SYSTEM_OTHER/preloads/apps/Chats.apk",
    386         None,
    387         ("SYSTEM_OTHER/preloads/",))
    388     self.assertTrue(is_apk)
    389     self.assertFalse(is_compressed)
    390     self.assertTrue(should_be_skipped)
    391 
    392     # list
    393     (is_apk, is_compressed, should_be_skipped) = GetApkFileInfo(
    394         "SYSTEM_OTHER/preloads/apps/Chats.apk",
    395         None,
    396         ["SYSTEM_OTHER/preloads/"])
    397     self.assertTrue(is_apk)
    398     self.assertFalse(is_compressed)
    399     self.assertTrue(should_be_skipped)
    400 
    401     # str is invalid.
    402     self.assertRaises(
    403         AssertionError, GetApkFileInfo, "SYSTEM_OTHER/preloads/apps/Chats.apk",
    404         None, "SYSTEM_OTHER/preloads/")
    405 
    406     # None is invalid.
    407     self.assertRaises(
    408         AssertionError, GetApkFileInfo, "SYSTEM_OTHER/preloads/apps/Chats.apk",
    409         None, None)
    410 
    411   def test_ReadApexKeysInfo(self):
    412     target_files = common.MakeTempFile(suffix='.zip')
    413     with zipfile.ZipFile(target_files, 'w') as target_files_zip:
    414       target_files_zip.writestr('META/apexkeys.txt', self.APEX_KEYS_TXT)
    415 
    416     with zipfile.ZipFile(target_files) as target_files_zip:
    417       keys_info = ReadApexKeysInfo(target_files_zip)
    418 
    419     self.assertEqual({
    420         'apex.apexd_test.apex': (
    421             'system/apex/apexd/apexd_testdata/com.android.apex.test_package.pem',
    422             'build/target/product/security/testkey'),
    423         'apex.apexd_test_different_app.apex': (
    424             'system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem',
    425             'build/target/product/security/testkey'),
    426         }, keys_info)
    427 
    428   def test_ReadApexKeysInfo_mismatchingContainerKeys(self):
    429     # Mismatching payload public / private keys.
    430     apex_keys = self.APEX_KEYS_TXT + (
    431         'name="apex.apexd_test_different_app2.apex" '
    432         'public_key="system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.avbpubkey" '
    433         'private_key="system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem" '
    434         'container_certificate="build/target/product/security/testkey.x509.pem" '
    435         'container_private_key="build/target/product/security/testkey2.pk8"')
    436     target_files = common.MakeTempFile(suffix='.zip')
    437     with zipfile.ZipFile(target_files, 'w') as target_files_zip:
    438       target_files_zip.writestr('META/apexkeys.txt', apex_keys)
    439 
    440     with zipfile.ZipFile(target_files) as target_files_zip:
    441       self.assertRaises(ValueError, ReadApexKeysInfo, target_files_zip)
    442 
    443   def test_ReadApexKeysInfo_missingPayloadPrivateKey(self):
    444     # Invalid lines will be skipped.
    445     apex_keys = self.APEX_KEYS_TXT + (
    446         'name="apex.apexd_test_different_app2.apex" '
    447         'public_key="system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.avbpubkey" '
    448         'container_certificate="build/target/product/security/testkey.x509.pem" '
    449         'container_private_key="build/target/product/security/testkey.pk8"')
    450     target_files = common.MakeTempFile(suffix='.zip')
    451     with zipfile.ZipFile(target_files, 'w') as target_files_zip:
    452       target_files_zip.writestr('META/apexkeys.txt', apex_keys)
    453 
    454     with zipfile.ZipFile(target_files) as target_files_zip:
    455       keys_info = ReadApexKeysInfo(target_files_zip)
    456 
    457     self.assertEqual({
    458         'apex.apexd_test.apex': (
    459             'system/apex/apexd/apexd_testdata/com.android.apex.test_package.pem',
    460             'build/target/product/security/testkey'),
    461         'apex.apexd_test_different_app.apex': (
    462             'system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem',
    463             'build/target/product/security/testkey'),
    464         }, keys_info)
    465 
    466   def test_ReadApexKeysInfo_missingPayloadPublicKey(self):
    467     # Invalid lines will be skipped.
    468     apex_keys = self.APEX_KEYS_TXT + (
    469         'name="apex.apexd_test_different_app2.apex" '
    470         'private_key="system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem" '
    471         'container_certificate="build/target/product/security/testkey.x509.pem" '
    472         'container_private_key="build/target/product/security/testkey.pk8"')
    473     target_files = common.MakeTempFile(suffix='.zip')
    474     with zipfile.ZipFile(target_files, 'w') as target_files_zip:
    475       target_files_zip.writestr('META/apexkeys.txt', apex_keys)
    476 
    477     with zipfile.ZipFile(target_files) as target_files_zip:
    478       keys_info = ReadApexKeysInfo(target_files_zip)
    479 
    480     self.assertEqual({
    481         'apex.apexd_test.apex': (
    482             'system/apex/apexd/apexd_testdata/com.android.apex.test_package.pem',
    483             'build/target/product/security/testkey'),
    484         'apex.apexd_test_different_app.apex': (
    485             'system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem',
    486             'build/target/product/security/testkey'),
    487         }, keys_info)
    488 
    489   def test_ReadApexKeysInfo_presignedKeys(self):
    490     apex_keys = self.APEX_KEYS_TXT + (
    491         'name="apex.apexd_test_different_app2.apex" '
    492         'private_key="PRESIGNED" '
    493         'public_key="PRESIGNED" '
    494         'container_certificate="PRESIGNED" '
    495         'container_private_key="PRESIGNED"')
    496     target_files = common.MakeTempFile(suffix='.zip')
    497     with zipfile.ZipFile(target_files, 'w') as target_files_zip:
    498       target_files_zip.writestr('META/apexkeys.txt', apex_keys)
    499 
    500     with zipfile.ZipFile(target_files) as target_files_zip:
    501       keys_info = ReadApexKeysInfo(target_files_zip)
    502 
    503     self.assertEqual({
    504         'apex.apexd_test.apex': (
    505             'system/apex/apexd/apexd_testdata/com.android.apex.test_package.pem',
    506             'build/make/target/product/security/testkey'),
    507         'apex.apexd_test_different_app.apex': (
    508             'system/apex/apexd/apexd_testdata/com.android.apex.test_package_2.pem',
    509             'build/make/target/product/security/testkey'),
    510         }, keys_info)
    511