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 from __future__ import print_function
     18 
     19 import base64
     20 import os.path
     21 import unittest
     22 import zipfile
     23 
     24 import common
     25 import test_utils
     26 from sign_target_files_apks import (
     27     EditTags, ReplaceCerts, ReplaceVerityKeyId, RewriteProps)
     28 
     29 
     30 class SignTargetFilesApksTest(unittest.TestCase):
     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   def setUp(self):
     39     self.testdata_dir = test_utils.get_testdata_dir()
     40 
     41   def tearDown(self):
     42     common.Cleanup()
     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         ('', '\n'),
     57         ('ro.build.fingerprint=foo/bar/dev-keys',
     58          'ro.build.fingerprint=foo/bar/release-keys\n'),
     59         ('ro.build.thumbprint=foo/bar/dev-keys',
     60          'ro.build.thumbprint=foo/bar/release-keys\n'),
     61         ('ro.vendor.build.fingerprint=foo/bar/dev-keys',
     62          'ro.vendor.build.fingerprint=foo/bar/release-keys\n'),
     63         ('ro.vendor.build.thumbprint=foo/bar/dev-keys',
     64          'ro.vendor.build.thumbprint=foo/bar/release-keys\n'),
     65         ('# comment line 1', '# comment line 1\n'),
     66         ('ro.bootimage.build.fingerprint=foo/bar/dev-keys',
     67          'ro.bootimage.build.fingerprint=foo/bar/release-keys\n'),
     68         ('ro.build.description='
     69          'sailfish-user 8.0.0 OPR6.170623.012 4283428 dev-keys',
     70          'ro.build.description='
     71          'sailfish-user 8.0.0 OPR6.170623.012 4283428 release-keys\n'),
     72         ('ro.build.tags=dev-keys', 'ro.build.tags=release-keys\n'),
     73         ('# comment line 2', '# comment line 2\n'),
     74         ('ro.build.display.id=OPR6.170623.012 dev-keys',
     75          'ro.build.display.id=OPR6.170623.012\n'),
     76         ('# comment line 3', '# comment line 3\n'),
     77     )
     78 
     79     # Assert the case for each individual line.
     80     for prop, output in props:
     81       self.assertEqual(RewriteProps(prop), output)
     82 
     83     # Concatenate all the input lines.
     84     self.assertEqual(RewriteProps('\n'.join([prop[0] for prop in props])),
     85                      ''.join([prop[1] for prop in props]))
     86 
     87   def test_ReplaceVerityKeyId(self):
     88     BOOT_CMDLINE1 = (
     89         "console=ttyHSL0,115200,n8 androidboot.console=ttyHSL0 "
     90         "androidboot.hardware=marlin user_debug=31 ehci-hcd.park=3 "
     91         "lpm_levels.sleep_disabled=1 cma=32M@0-0xffffffff loop.max_part=7 "
     92         "buildvariant=userdebug "
     93         "veritykeyid=id:7e4333f9bba00adfe0ede979e28ed1920492b40f\n")
     94 
     95     BOOT_CMDLINE2 = (
     96         "console=ttyHSL0,115200,n8 androidboot.console=ttyHSL0 "
     97         "androidboot.hardware=marlin user_debug=31 ehci-hcd.park=3 "
     98         "lpm_levels.sleep_disabled=1 cma=32M@0-0xffffffff loop.max_part=7 "
     99         "buildvariant=userdebug "
    100         "veritykeyid=id:d24f2590e9abab5cff5f59da4c4f0366e3f43e94\n")
    101 
    102     input_file = common.MakeTempFile(suffix='.zip')
    103     with zipfile.ZipFile(input_file, 'w') as input_zip:
    104       input_zip.writestr('BOOT/cmdline', BOOT_CMDLINE1)
    105 
    106     # Test with the first certificate.
    107     cert_file = os.path.join(self.testdata_dir, 'verity.x509.pem')
    108 
    109     output_file = common.MakeTempFile(suffix='.zip')
    110     with zipfile.ZipFile(input_file, 'r') as input_zip, \
    111          zipfile.ZipFile(output_file, 'w') as output_zip:
    112       ReplaceVerityKeyId(input_zip, output_zip, cert_file)
    113 
    114     with zipfile.ZipFile(output_file) as output_zip:
    115       self.assertEqual(BOOT_CMDLINE1, output_zip.read('BOOT/cmdline'))
    116 
    117     # Test with the second certificate.
    118     cert_file = os.path.join(self.testdata_dir, 'testkey.x509.pem')
    119 
    120     with zipfile.ZipFile(input_file, 'r') as input_zip, \
    121          zipfile.ZipFile(output_file, 'w') as output_zip:
    122       ReplaceVerityKeyId(input_zip, output_zip, cert_file)
    123 
    124     with zipfile.ZipFile(output_file) as output_zip:
    125       self.assertEqual(BOOT_CMDLINE2, output_zip.read('BOOT/cmdline'))
    126 
    127   def test_ReplaceVerityKeyId_no_veritykeyid(self):
    128     BOOT_CMDLINE = (
    129         "console=ttyHSL0,115200,n8 androidboot.hardware=bullhead boot_cpus=0-5 "
    130         "lpm_levels.sleep_disabled=1 msm_poweroff.download_mode=0 "
    131         "loop.max_part=7\n")
    132 
    133     input_file = common.MakeTempFile(suffix='.zip')
    134     with zipfile.ZipFile(input_file, 'w') as input_zip:
    135       input_zip.writestr('BOOT/cmdline', BOOT_CMDLINE)
    136 
    137     output_file = common.MakeTempFile(suffix='.zip')
    138     with zipfile.ZipFile(input_file, 'r') as input_zip, \
    139          zipfile.ZipFile(output_file, 'w') as output_zip:
    140       ReplaceVerityKeyId(input_zip, output_zip, None)
    141 
    142     with zipfile.ZipFile(output_file) as output_zip:
    143       self.assertEqual(BOOT_CMDLINE, output_zip.read('BOOT/cmdline'))
    144 
    145   def test_ReplaceCerts(self):
    146     cert1_path = os.path.join(self.testdata_dir, 'platform.x509.pem')
    147     with open(cert1_path) as cert1_fp:
    148       cert1 = cert1_fp.read()
    149     cert2_path = os.path.join(self.testdata_dir, 'media.x509.pem')
    150     with open(cert2_path) as cert2_fp:
    151       cert2 = cert2_fp.read()
    152     cert3_path = os.path.join(self.testdata_dir, 'testkey.x509.pem')
    153     with open(cert3_path) as cert3_fp:
    154       cert3 = cert3_fp.read()
    155 
    156     # Replace cert1 with cert3.
    157     input_xml = self.MAC_PERMISSIONS_XML.format(
    158         base64.b16encode(common.ParseCertificate(cert1)).lower(),
    159         base64.b16encode(common.ParseCertificate(cert2)).lower())
    160 
    161     output_xml = self.MAC_PERMISSIONS_XML.format(
    162         base64.b16encode(common.ParseCertificate(cert3)).lower(),
    163         base64.b16encode(common.ParseCertificate(cert2)).lower())
    164 
    165     common.OPTIONS.key_map = {
    166         cert1_path[:-9] : cert3_path[:-9],
    167     }
    168 
    169     self.assertEqual(output_xml, ReplaceCerts(input_xml))
    170 
    171   def test_ReplaceCerts_duplicateEntries(self):
    172     cert1_path = os.path.join(self.testdata_dir, 'platform.x509.pem')
    173     with open(cert1_path) as cert1_fp:
    174       cert1 = cert1_fp.read()
    175     cert2_path = os.path.join(self.testdata_dir, 'media.x509.pem')
    176     with open(cert2_path) as cert2_fp:
    177       cert2 = cert2_fp.read()
    178 
    179     # Replace cert1 with cert2, which leads to duplicate entries.
    180     input_xml = self.MAC_PERMISSIONS_XML.format(
    181         base64.b16encode(common.ParseCertificate(cert1)).lower(),
    182         base64.b16encode(common.ParseCertificate(cert2)).lower())
    183 
    184     common.OPTIONS.key_map = {
    185         cert1_path[:-9] : cert2_path[:-9],
    186     }
    187     self.assertRaises(AssertionError, ReplaceCerts, input_xml)
    188 
    189   def test_ReplaceCerts_skipNonExistentCerts(self):
    190     cert1_path = os.path.join(self.testdata_dir, 'platform.x509.pem')
    191     with open(cert1_path) as cert1_fp:
    192       cert1 = cert1_fp.read()
    193     cert2_path = os.path.join(self.testdata_dir, 'media.x509.pem')
    194     with open(cert2_path) as cert2_fp:
    195       cert2 = cert2_fp.read()
    196     cert3_path = os.path.join(self.testdata_dir, 'testkey.x509.pem')
    197     with open(cert3_path) as cert3_fp:
    198       cert3 = cert3_fp.read()
    199 
    200     input_xml = self.MAC_PERMISSIONS_XML.format(
    201         base64.b16encode(common.ParseCertificate(cert1)).lower(),
    202         base64.b16encode(common.ParseCertificate(cert2)).lower())
    203 
    204     output_xml = self.MAC_PERMISSIONS_XML.format(
    205         base64.b16encode(common.ParseCertificate(cert3)).lower(),
    206         base64.b16encode(common.ParseCertificate(cert2)).lower())
    207 
    208     common.OPTIONS.key_map = {
    209         cert1_path[:-9] : cert3_path[:-9],
    210         'non-existent' : cert3_path[:-9],
    211         cert2_path[:-9] : 'non-existent',
    212     }
    213     self.assertEqual(output_xml, ReplaceCerts(input_xml))
    214