1# 2# Copyright (C) 2019 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 re 18import os 19import os.path 20import shutil 21import zipfile 22 23import apex_utils 24import common 25import test_utils 26 27 28class ApexUtilsTest(test_utils.ReleaseToolsTestCase): 29 30 # echo "foo" | sha256sum 31 SALT = 'b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c' 32 33 def setUp(self): 34 self.testdata_dir = test_utils.get_testdata_dir() 35 # The default payload signing key. 36 self.payload_key = os.path.join(self.testdata_dir, 'testkey.key') 37 self.apex_with_apk = os.path.join(self.testdata_dir, 'has_apk.apex') 38 39 common.OPTIONS.search_path = test_utils.get_search_path() 40 41 @staticmethod 42 def _GetTestPayload(): 43 payload_file = common.MakeTempFile(prefix='apex-', suffix='.img') 44 with open(payload_file, 'wb') as payload_fp: 45 payload_fp.write(os.urandom(8192)) 46 return payload_file 47 48 @test_utils.SkipIfExternalToolsUnavailable() 49 def test_ParseApexPayloadInfo(self): 50 payload_file = self._GetTestPayload() 51 apex_utils.SignApexPayload( 52 'avbtool', payload_file, self.payload_key, 'testkey', 'SHA256_RSA2048', 53 self.SALT, 'sha256', no_hashtree=True) 54 payload_info = apex_utils.ParseApexPayloadInfo('avbtool', payload_file) 55 self.assertEqual('SHA256_RSA2048', payload_info['Algorithm']) 56 self.assertEqual(self.SALT, payload_info['Salt']) 57 self.assertEqual('testkey', payload_info['apex.key']) 58 self.assertEqual('sha256', payload_info['Hash Algorithm']) 59 self.assertEqual('0 bytes', payload_info['Tree Size']) 60 61 @test_utils.SkipIfExternalToolsUnavailable() 62 def test_SignApexPayload(self): 63 payload_file = self._GetTestPayload() 64 apex_utils.SignApexPayload( 65 'avbtool', payload_file, self.payload_key, 'testkey', 'SHA256_RSA2048', 66 self.SALT, 'sha256', no_hashtree=True) 67 apex_utils.VerifyApexPayload( 68 'avbtool', payload_file, self.payload_key, True) 69 70 @test_utils.SkipIfExternalToolsUnavailable() 71 def test_SignApexPayload_withHashtree(self): 72 payload_file = self._GetTestPayload() 73 apex_utils.SignApexPayload( 74 'avbtool', payload_file, self.payload_key, 'testkey', 'SHA256_RSA2048', 75 self.SALT, 'sha256', no_hashtree=False) 76 apex_utils.VerifyApexPayload('avbtool', payload_file, self.payload_key) 77 payload_info = apex_utils.ParseApexPayloadInfo('avbtool', payload_file) 78 self.assertEqual('4096 bytes', payload_info['Tree Size']) 79 80 @test_utils.SkipIfExternalToolsUnavailable() 81 def test_SignApexPayload_noHashtree(self): 82 payload_file = self._GetTestPayload() 83 apex_utils.SignApexPayload( 84 'avbtool', payload_file, self.payload_key, 'testkey', 'SHA256_RSA2048', 85 self.SALT, 'sha256', no_hashtree=True) 86 apex_utils.VerifyApexPayload('avbtool', payload_file, self.payload_key, 87 no_hashtree=True) 88 payload_info = apex_utils.ParseApexPayloadInfo('avbtool', payload_file) 89 self.assertEqual('0 bytes', payload_info['Tree Size']) 90 91 @test_utils.SkipIfExternalToolsUnavailable() 92 def test_SignApexPayload_withSignerHelper(self): 93 payload_file = self._GetTestPayload() 94 signing_helper = os.path.join(self.testdata_dir, 'signing_helper.sh') 95 os.chmod(signing_helper, 0o700) 96 payload_signer_args = '--signing_helper_with_files {}'.format( 97 signing_helper) 98 apex_utils.SignApexPayload( 99 'avbtool', 100 payload_file, 101 self.payload_key, 102 'testkey', 'SHA256_RSA2048', self.SALT, 'sha256', 103 True, 104 payload_signer_args) 105 apex_utils.VerifyApexPayload( 106 'avbtool', payload_file, self.payload_key, True) 107 108 @test_utils.SkipIfExternalToolsUnavailable() 109 def test_SignApexPayload_invalidKey(self): 110 self.assertRaises( 111 apex_utils.ApexSigningError, 112 apex_utils.SignApexPayload, 113 'avbtool', 114 self._GetTestPayload(), 115 os.path.join(self.testdata_dir, 'testkey.x509.pem'), 116 'testkey', 117 'SHA256_RSA2048', 118 self.SALT, 119 'sha256', 120 no_hashtree=True) 121 122 @test_utils.SkipIfExternalToolsUnavailable() 123 def test_VerifyApexPayload_wrongKey(self): 124 payload_file = self._GetTestPayload() 125 apex_utils.SignApexPayload( 126 'avbtool', payload_file, self.payload_key, 'testkey', 'SHA256_RSA2048', 127 self.SALT, 'sha256', True) 128 apex_utils.VerifyApexPayload( 129 'avbtool', payload_file, self.payload_key, True) 130 self.assertRaises( 131 apex_utils.ApexSigningError, 132 apex_utils.VerifyApexPayload, 133 'avbtool', 134 payload_file, 135 os.path.join(self.testdata_dir, 'testkey_with_passwd.key'), 136 no_hashtree=True) 137 138 @test_utils.SkipIfExternalToolsUnavailable() 139 def test_ApexApkSigner_noApkPresent(self): 140 apex_path = os.path.join(self.testdata_dir, 'foo.apex') 141 signer = apex_utils.ApexApkSigner(apex_path, None, None) 142 processed_apex = signer.ProcessApexFile({}, self.payload_key) 143 self.assertEqual(apex_path, processed_apex) 144 145 @test_utils.SkipIfExternalToolsUnavailable() 146 def test_ApexApkSigner_apkKeyNotPresent(self): 147 apex_path = common.MakeTempFile(suffix='.apex') 148 shutil.copy(self.apex_with_apk, apex_path) 149 signer = apex_utils.ApexApkSigner(apex_path, None, None) 150 self.assertRaises(apex_utils.ApexSigningError, signer.ProcessApexFile, 151 {}, self.payload_key) 152 153 @test_utils.SkipIfExternalToolsUnavailable() 154 def test_ApexApkSigner_signApk(self): 155 apex_path = common.MakeTempFile(suffix='.apex') 156 shutil.copy(self.apex_with_apk, apex_path) 157 signer = apex_utils.ApexApkSigner(apex_path, None, None) 158 apk_keys = {'wifi-service-resources.apk': os.path.join( 159 self.testdata_dir, 'testkey')} 160 161 self.payload_key = os.path.join(self.testdata_dir, 'testkey_RSA4096.key') 162 apex_file = signer.ProcessApexFile(apk_keys, self.payload_key) 163 package_name_extract_cmd = ['aapt2', 'dump', 'badging', apex_file] 164 output = common.RunAndCheckOutput(package_name_extract_cmd) 165 for line in output.splitlines(): 166 # Sample output from aapt: "package: name='com.google.android.wifi' 167 # versionCode='1' versionName='' platformBuildVersionName='R' 168 # compileSdkVersion='29' compileSdkVersionCodename='R'" 169 match = re.search(r"^package:.* name='([\w|\.]+)'", line, re.IGNORECASE) 170 if match: 171 package_name = match.group(1) 172 self.assertEquals('com.google.android.wifi', package_name) 173 174 @test_utils.SkipIfExternalToolsUnavailable() 175 def test_ApexApkSigner_noAssetDir(self): 176 no_asset = common.MakeTempFile(suffix='.apex') 177 with zipfile.ZipFile(no_asset, 'w', allowZip64=True) as output_zip: 178 with zipfile.ZipFile(self.apex_with_apk, 'r', allowZip64=True) as input_zip: 179 name_list = input_zip.namelist() 180 for name in name_list: 181 if not name.startswith('assets'): 182 output_zip.writestr(name, input_zip.read(name)) 183 184 signer = apex_utils.ApexApkSigner(no_asset, None, None) 185 apk_keys = {'wifi-service-resources.apk': os.path.join( 186 self.testdata_dir, 'testkey')} 187 188 self.payload_key = os.path.join(self.testdata_dir, 'testkey_RSA4096.key') 189 signer.ProcessApexFile(apk_keys, self.payload_key) 190