1*9e94795aSAndroid Build Coastguard Worker# 2*9e94795aSAndroid Build Coastguard Worker# Copyright (C) 2019 The Android Open Source Project 3*9e94795aSAndroid Build Coastguard Worker# 4*9e94795aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 5*9e94795aSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 6*9e94795aSAndroid Build Coastguard Worker# You may obtain a copy of the License at 7*9e94795aSAndroid Build Coastguard Worker# 8*9e94795aSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 9*9e94795aSAndroid Build Coastguard Worker# 10*9e94795aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 11*9e94795aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 12*9e94795aSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*9e94795aSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 14*9e94795aSAndroid Build Coastguard Worker# limitations under the License. 15*9e94795aSAndroid Build Coastguard Worker# 16*9e94795aSAndroid Build Coastguard Worker 17*9e94795aSAndroid Build Coastguard Workerimport re 18*9e94795aSAndroid Build Coastguard Workerimport os 19*9e94795aSAndroid Build Coastguard Workerimport os.path 20*9e94795aSAndroid Build Coastguard Workerimport shutil 21*9e94795aSAndroid Build Coastguard Workerimport zipfile 22*9e94795aSAndroid Build Coastguard Worker 23*9e94795aSAndroid Build Coastguard Workerimport apex_utils 24*9e94795aSAndroid Build Coastguard Workerimport common 25*9e94795aSAndroid Build Coastguard Workerimport test_utils 26*9e94795aSAndroid Build Coastguard Worker 27*9e94795aSAndroid Build Coastguard Worker 28*9e94795aSAndroid Build Coastguard Workerclass ApexUtilsTest(test_utils.ReleaseToolsTestCase): 29*9e94795aSAndroid Build Coastguard Worker 30*9e94795aSAndroid Build Coastguard Worker # echo "foo" | sha256sum 31*9e94795aSAndroid Build Coastguard Worker SALT = 'b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c' 32*9e94795aSAndroid Build Coastguard Worker 33*9e94795aSAndroid Build Coastguard Worker def setUp(self): 34*9e94795aSAndroid Build Coastguard Worker self.testdata_dir = test_utils.get_testdata_dir() 35*9e94795aSAndroid Build Coastguard Worker # The default payload signing key. 36*9e94795aSAndroid Build Coastguard Worker self.payload_key = os.path.join(self.testdata_dir, 'testkey.key') 37*9e94795aSAndroid Build Coastguard Worker self.apex_with_apk = os.path.join(self.testdata_dir, 'has_apk.apex') 38*9e94795aSAndroid Build Coastguard Worker 39*9e94795aSAndroid Build Coastguard Worker common.OPTIONS.search_path = test_utils.get_search_path() 40*9e94795aSAndroid Build Coastguard Worker 41*9e94795aSAndroid Build Coastguard Worker @staticmethod 42*9e94795aSAndroid Build Coastguard Worker def _GetTestPayload(): 43*9e94795aSAndroid Build Coastguard Worker payload_file = common.MakeTempFile(prefix='apex-', suffix='.img') 44*9e94795aSAndroid Build Coastguard Worker with open(payload_file, 'wb') as payload_fp: 45*9e94795aSAndroid Build Coastguard Worker payload_fp.write(os.urandom(8192)) 46*9e94795aSAndroid Build Coastguard Worker return payload_file 47*9e94795aSAndroid Build Coastguard Worker 48*9e94795aSAndroid Build Coastguard Worker @test_utils.SkipIfExternalToolsUnavailable() 49*9e94795aSAndroid Build Coastguard Worker def test_ParseApexPayloadInfo(self): 50*9e94795aSAndroid Build Coastguard Worker payload_file = self._GetTestPayload() 51*9e94795aSAndroid Build Coastguard Worker apex_utils.SignApexPayload( 52*9e94795aSAndroid Build Coastguard Worker 'avbtool', payload_file, self.payload_key, 'testkey', 'SHA256_RSA2048', 53*9e94795aSAndroid Build Coastguard Worker self.SALT, 'sha256', no_hashtree=True) 54*9e94795aSAndroid Build Coastguard Worker payload_info = apex_utils.ParseApexPayloadInfo('avbtool', payload_file) 55*9e94795aSAndroid Build Coastguard Worker self.assertEqual('SHA256_RSA2048', payload_info['Algorithm']) 56*9e94795aSAndroid Build Coastguard Worker self.assertEqual(self.SALT, payload_info['Salt']) 57*9e94795aSAndroid Build Coastguard Worker self.assertEqual('testkey', payload_info['apex.key']) 58*9e94795aSAndroid Build Coastguard Worker self.assertEqual('sha256', payload_info['Hash Algorithm']) 59*9e94795aSAndroid Build Coastguard Worker self.assertEqual('0 bytes', payload_info['Tree Size']) 60*9e94795aSAndroid Build Coastguard Worker 61*9e94795aSAndroid Build Coastguard Worker @test_utils.SkipIfExternalToolsUnavailable() 62*9e94795aSAndroid Build Coastguard Worker def test_SignApexPayload(self): 63*9e94795aSAndroid Build Coastguard Worker payload_file = self._GetTestPayload() 64*9e94795aSAndroid Build Coastguard Worker apex_utils.SignApexPayload( 65*9e94795aSAndroid Build Coastguard Worker 'avbtool', payload_file, self.payload_key, 'testkey', 'SHA256_RSA2048', 66*9e94795aSAndroid Build Coastguard Worker self.SALT, 'sha256', no_hashtree=True) 67*9e94795aSAndroid Build Coastguard Worker apex_utils.VerifyApexPayload( 68*9e94795aSAndroid Build Coastguard Worker 'avbtool', payload_file, self.payload_key, True) 69*9e94795aSAndroid Build Coastguard Worker 70*9e94795aSAndroid Build Coastguard Worker @test_utils.SkipIfExternalToolsUnavailable() 71*9e94795aSAndroid Build Coastguard Worker def test_SignApexPayload_withHashtree(self): 72*9e94795aSAndroid Build Coastguard Worker payload_file = self._GetTestPayload() 73*9e94795aSAndroid Build Coastguard Worker apex_utils.SignApexPayload( 74*9e94795aSAndroid Build Coastguard Worker 'avbtool', payload_file, self.payload_key, 'testkey', 'SHA256_RSA2048', 75*9e94795aSAndroid Build Coastguard Worker self.SALT, 'sha256', no_hashtree=False) 76*9e94795aSAndroid Build Coastguard Worker apex_utils.VerifyApexPayload('avbtool', payload_file, self.payload_key) 77*9e94795aSAndroid Build Coastguard Worker payload_info = apex_utils.ParseApexPayloadInfo('avbtool', payload_file) 78*9e94795aSAndroid Build Coastguard Worker self.assertEqual('4096 bytes', payload_info['Tree Size']) 79*9e94795aSAndroid Build Coastguard Worker 80*9e94795aSAndroid Build Coastguard Worker @test_utils.SkipIfExternalToolsUnavailable() 81*9e94795aSAndroid Build Coastguard Worker def test_SignApexPayload_noHashtree(self): 82*9e94795aSAndroid Build Coastguard Worker payload_file = self._GetTestPayload() 83*9e94795aSAndroid Build Coastguard Worker apex_utils.SignApexPayload( 84*9e94795aSAndroid Build Coastguard Worker 'avbtool', payload_file, self.payload_key, 'testkey', 'SHA256_RSA2048', 85*9e94795aSAndroid Build Coastguard Worker self.SALT, 'sha256', no_hashtree=True) 86*9e94795aSAndroid Build Coastguard Worker apex_utils.VerifyApexPayload('avbtool', payload_file, self.payload_key, 87*9e94795aSAndroid Build Coastguard Worker no_hashtree=True) 88*9e94795aSAndroid Build Coastguard Worker payload_info = apex_utils.ParseApexPayloadInfo('avbtool', payload_file) 89*9e94795aSAndroid Build Coastguard Worker self.assertEqual('0 bytes', payload_info['Tree Size']) 90*9e94795aSAndroid Build Coastguard Worker 91*9e94795aSAndroid Build Coastguard Worker @test_utils.SkipIfExternalToolsUnavailable() 92*9e94795aSAndroid Build Coastguard Worker def test_SignApexPayload_withSignerHelper(self): 93*9e94795aSAndroid Build Coastguard Worker payload_file = self._GetTestPayload() 94*9e94795aSAndroid Build Coastguard Worker signing_helper = os.path.join(self.testdata_dir, 'signing_helper.sh') 95*9e94795aSAndroid Build Coastguard Worker os.chmod(signing_helper, 0o700) 96*9e94795aSAndroid Build Coastguard Worker payload_signer_args = '--signing_helper_with_files {}'.format( 97*9e94795aSAndroid Build Coastguard Worker signing_helper) 98*9e94795aSAndroid Build Coastguard Worker apex_utils.SignApexPayload( 99*9e94795aSAndroid Build Coastguard Worker 'avbtool', 100*9e94795aSAndroid Build Coastguard Worker payload_file, 101*9e94795aSAndroid Build Coastguard Worker self.payload_key, 102*9e94795aSAndroid Build Coastguard Worker 'testkey', 'SHA256_RSA2048', self.SALT, 'sha256', 103*9e94795aSAndroid Build Coastguard Worker True, 104*9e94795aSAndroid Build Coastguard Worker payload_signer_args) 105*9e94795aSAndroid Build Coastguard Worker apex_utils.VerifyApexPayload( 106*9e94795aSAndroid Build Coastguard Worker 'avbtool', payload_file, self.payload_key, True) 107*9e94795aSAndroid Build Coastguard Worker 108*9e94795aSAndroid Build Coastguard Worker @test_utils.SkipIfExternalToolsUnavailable() 109*9e94795aSAndroid Build Coastguard Worker def test_SignApexPayload_invalidKey(self): 110*9e94795aSAndroid Build Coastguard Worker self.assertRaises( 111*9e94795aSAndroid Build Coastguard Worker apex_utils.ApexSigningError, 112*9e94795aSAndroid Build Coastguard Worker apex_utils.SignApexPayload, 113*9e94795aSAndroid Build Coastguard Worker 'avbtool', 114*9e94795aSAndroid Build Coastguard Worker self._GetTestPayload(), 115*9e94795aSAndroid Build Coastguard Worker os.path.join(self.testdata_dir, 'testkey.x509.pem'), 116*9e94795aSAndroid Build Coastguard Worker 'testkey', 117*9e94795aSAndroid Build Coastguard Worker 'SHA256_RSA2048', 118*9e94795aSAndroid Build Coastguard Worker self.SALT, 119*9e94795aSAndroid Build Coastguard Worker 'sha256', 120*9e94795aSAndroid Build Coastguard Worker no_hashtree=True) 121*9e94795aSAndroid Build Coastguard Worker 122*9e94795aSAndroid Build Coastguard Worker @test_utils.SkipIfExternalToolsUnavailable() 123*9e94795aSAndroid Build Coastguard Worker def test_VerifyApexPayload_wrongKey(self): 124*9e94795aSAndroid Build Coastguard Worker payload_file = self._GetTestPayload() 125*9e94795aSAndroid Build Coastguard Worker apex_utils.SignApexPayload( 126*9e94795aSAndroid Build Coastguard Worker 'avbtool', payload_file, self.payload_key, 'testkey', 'SHA256_RSA2048', 127*9e94795aSAndroid Build Coastguard Worker self.SALT, 'sha256', True) 128*9e94795aSAndroid Build Coastguard Worker apex_utils.VerifyApexPayload( 129*9e94795aSAndroid Build Coastguard Worker 'avbtool', payload_file, self.payload_key, True) 130*9e94795aSAndroid Build Coastguard Worker self.assertRaises( 131*9e94795aSAndroid Build Coastguard Worker apex_utils.ApexSigningError, 132*9e94795aSAndroid Build Coastguard Worker apex_utils.VerifyApexPayload, 133*9e94795aSAndroid Build Coastguard Worker 'avbtool', 134*9e94795aSAndroid Build Coastguard Worker payload_file, 135*9e94795aSAndroid Build Coastguard Worker os.path.join(self.testdata_dir, 'testkey_with_passwd.key'), 136*9e94795aSAndroid Build Coastguard Worker no_hashtree=True) 137*9e94795aSAndroid Build Coastguard Worker 138*9e94795aSAndroid Build Coastguard Worker @test_utils.SkipIfExternalToolsUnavailable() 139*9e94795aSAndroid Build Coastguard Worker def test_ApexApkSigner_noApkPresent(self): 140*9e94795aSAndroid Build Coastguard Worker apex_path = os.path.join(self.testdata_dir, 'foo.apex') 141*9e94795aSAndroid Build Coastguard Worker signer = apex_utils.ApexApkSigner(apex_path, None, None) 142*9e94795aSAndroid Build Coastguard Worker processed_apex = signer.ProcessApexFile({}, self.payload_key) 143*9e94795aSAndroid Build Coastguard Worker self.assertEqual(apex_path, processed_apex) 144*9e94795aSAndroid Build Coastguard Worker 145*9e94795aSAndroid Build Coastguard Worker @test_utils.SkipIfExternalToolsUnavailable() 146*9e94795aSAndroid Build Coastguard Worker def test_ApexApkSigner_apkKeyNotPresent(self): 147*9e94795aSAndroid Build Coastguard Worker apex_path = common.MakeTempFile(suffix='.apex') 148*9e94795aSAndroid Build Coastguard Worker shutil.copy(self.apex_with_apk, apex_path) 149*9e94795aSAndroid Build Coastguard Worker signer = apex_utils.ApexApkSigner(apex_path, None, None) 150*9e94795aSAndroid Build Coastguard Worker self.assertRaises(apex_utils.ApexSigningError, signer.ProcessApexFile, 151*9e94795aSAndroid Build Coastguard Worker {}, self.payload_key) 152*9e94795aSAndroid Build Coastguard Worker 153*9e94795aSAndroid Build Coastguard Worker @test_utils.SkipIfExternalToolsUnavailable() 154*9e94795aSAndroid Build Coastguard Worker def test_ApexApkSigner_signApk(self): 155*9e94795aSAndroid Build Coastguard Worker apex_path = common.MakeTempFile(suffix='.apex') 156*9e94795aSAndroid Build Coastguard Worker shutil.copy(self.apex_with_apk, apex_path) 157*9e94795aSAndroid Build Coastguard Worker signer = apex_utils.ApexApkSigner(apex_path, None, None) 158*9e94795aSAndroid Build Coastguard Worker apk_keys = {'wifi-service-resources.apk': os.path.join( 159*9e94795aSAndroid Build Coastguard Worker self.testdata_dir, 'testkey')} 160*9e94795aSAndroid Build Coastguard Worker 161*9e94795aSAndroid Build Coastguard Worker self.payload_key = os.path.join(self.testdata_dir, 'testkey_RSA4096.key') 162*9e94795aSAndroid Build Coastguard Worker apex_file = signer.ProcessApexFile(apk_keys, self.payload_key) 163*9e94795aSAndroid Build Coastguard Worker package_name_extract_cmd = ['aapt2', 'dump', 'badging', apex_file] 164*9e94795aSAndroid Build Coastguard Worker output = common.RunAndCheckOutput(package_name_extract_cmd) 165*9e94795aSAndroid Build Coastguard Worker for line in output.splitlines(): 166*9e94795aSAndroid Build Coastguard Worker # Sample output from aapt: "package: name='com.google.android.wifi' 167*9e94795aSAndroid Build Coastguard Worker # versionCode='1' versionName='' platformBuildVersionName='R' 168*9e94795aSAndroid Build Coastguard Worker # compileSdkVersion='29' compileSdkVersionCodename='R'" 169*9e94795aSAndroid Build Coastguard Worker match = re.search(r"^package:.* name='([\w|\.]+)'", line, re.IGNORECASE) 170*9e94795aSAndroid Build Coastguard Worker if match: 171*9e94795aSAndroid Build Coastguard Worker package_name = match.group(1) 172*9e94795aSAndroid Build Coastguard Worker self.assertEquals('com.google.android.wifi', package_name) 173*9e94795aSAndroid Build Coastguard Worker 174*9e94795aSAndroid Build Coastguard Worker @test_utils.SkipIfExternalToolsUnavailable() 175*9e94795aSAndroid Build Coastguard Worker def test_ApexApkSigner_noAssetDir(self): 176*9e94795aSAndroid Build Coastguard Worker no_asset = common.MakeTempFile(suffix='.apex') 177*9e94795aSAndroid Build Coastguard Worker with zipfile.ZipFile(no_asset, 'w', allowZip64=True) as output_zip: 178*9e94795aSAndroid Build Coastguard Worker with zipfile.ZipFile(self.apex_with_apk, 'r', allowZip64=True) as input_zip: 179*9e94795aSAndroid Build Coastguard Worker name_list = input_zip.namelist() 180*9e94795aSAndroid Build Coastguard Worker for name in name_list: 181*9e94795aSAndroid Build Coastguard Worker if not name.startswith('assets'): 182*9e94795aSAndroid Build Coastguard Worker output_zip.writestr(name, input_zip.read(name)) 183*9e94795aSAndroid Build Coastguard Worker 184*9e94795aSAndroid Build Coastguard Worker signer = apex_utils.ApexApkSigner(no_asset, None, None) 185*9e94795aSAndroid Build Coastguard Worker apk_keys = {'wifi-service-resources.apk': os.path.join( 186*9e94795aSAndroid Build Coastguard Worker self.testdata_dir, 'testkey')} 187*9e94795aSAndroid Build Coastguard Worker 188*9e94795aSAndroid Build Coastguard Worker self.payload_key = os.path.join(self.testdata_dir, 'testkey_RSA4096.key') 189*9e94795aSAndroid Build Coastguard Worker signer.ProcessApexFile(apk_keys, self.payload_key) 190*9e94795aSAndroid Build Coastguard Worker 191*9e94795aSAndroid Build Coastguard Worker @test_utils.SkipIfExternalToolsUnavailable() 192*9e94795aSAndroid Build Coastguard Worker def test_ApexApkSigner_invokesCustomSignTool(self): 193*9e94795aSAndroid Build Coastguard Worker apex_path = common.MakeTempFile(suffix='.apex') 194*9e94795aSAndroid Build Coastguard Worker shutil.copy(self.apex_with_apk, apex_path) 195*9e94795aSAndroid Build Coastguard Worker apk_keys = {'wifi-service-resources.apk': os.path.join( 196*9e94795aSAndroid Build Coastguard Worker self.testdata_dir, 'testkey')} 197*9e94795aSAndroid Build Coastguard Worker self.payload_key = os.path.join(self.testdata_dir, 'testkey_RSA4096.key') 198*9e94795aSAndroid Build Coastguard Worker 199*9e94795aSAndroid Build Coastguard Worker # pass `false` as a sign_tool to see the invocation error 200*9e94795aSAndroid Build Coastguard Worker with self.assertRaises(common.ExternalError) as cm: 201*9e94795aSAndroid Build Coastguard Worker signer = apex_utils.ApexApkSigner( 202*9e94795aSAndroid Build Coastguard Worker apex_path, None, None, sign_tool='false') 203*9e94795aSAndroid Build Coastguard Worker signer.ProcessApexFile(apk_keys, self.payload_key) 204*9e94795aSAndroid Build Coastguard Worker 205*9e94795aSAndroid Build Coastguard Worker the_exception = cm.exception 206*9e94795aSAndroid Build Coastguard Worker self.assertIn('Failed to run command \'[\'false\'', str(the_exception)) 207