blob: e5741ee1a384c8da284be829d544e2f0f5c91b52 [file] [log] [blame]
Song Panf93a39c2019-11-19 00:58:31 +00001/*
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
17package com.android.server.integrity;
18
Song Pan6e3677c2019-10-29 14:19:26 +000019import static android.content.integrity.AppIntegrityManager.EXTRA_STATUS;
20import static android.content.integrity.AppIntegrityManager.STATUS_FAILURE;
21import static android.content.integrity.AppIntegrityManager.STATUS_SUCCESS;
Song Pan6a0fd8b2020-02-06 13:48:04 +000022import static android.content.integrity.InstallerAllowedByManifestFormula.INSTALLER_CERTIFICATE_NOT_EVALUATED;
Song Pan6e3677c2019-10-29 14:19:26 +000023import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID;
24import static android.content.pm.PackageManager.EXTRA_VERIFICATION_INSTALLER_PACKAGE;
25import static android.content.pm.PackageManager.EXTRA_VERIFICATION_INSTALLER_UID;
26
Song Pan56044372020-02-03 13:39:45 +000027import static com.google.common.truth.Truth.assertThat;
28
Song Pan6e3677c2019-10-29 14:19:26 +000029import static org.junit.Assert.assertEquals;
30import static org.junit.Assert.assertFalse;
Khaled Abdelmohsenac7eed62020-03-12 19:57:19 +000031import static org.junit.Assert.assertNull;
Khaled Abdelmohsen02067c22020-02-28 11:09:57 +000032import static org.junit.Assert.assertTrue;
Song Pan6e3677c2019-10-29 14:19:26 +000033import static org.mockito.ArgumentMatchers.any;
34import static org.mockito.ArgumentMatchers.anyInt;
35import static org.mockito.ArgumentMatchers.anyLong;
36import static org.mockito.ArgumentMatchers.eq;
Song Pan7a9c4c22020-02-04 14:03:57 +000037import static org.mockito.Mockito.atLeastOnce;
Song Pan6e3677c2019-10-29 14:19:26 +000038import static org.mockito.Mockito.doReturn;
39import static org.mockito.Mockito.doThrow;
40import static org.mockito.Mockito.mock;
41import static org.mockito.Mockito.spy;
42import static org.mockito.Mockito.verify;
43import static org.mockito.Mockito.when;
Song Pan6e3677c2019-10-29 14:19:26 +000044
Song Pan90991d42020-02-11 17:39:09 +000045import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
46
Song Pan6e3677c2019-10-29 14:19:26 +000047import android.content.BroadcastReceiver;
48import android.content.Context;
49import android.content.Intent;
50import android.content.IntentFilter;
51import android.content.IntentSender;
52import android.content.integrity.AppInstallMetadata;
53import android.content.integrity.AtomicFormula;
Song Pan56044372020-02-03 13:39:45 +000054import android.content.integrity.IntegrityFormula;
Song Pan6e3677c2019-10-29 14:19:26 +000055import android.content.integrity.Rule;
56import android.content.pm.ApplicationInfo;
57import android.content.pm.PackageInfo;
58import android.content.pm.PackageManager;
Song Panf93a39c2019-11-19 00:58:31 +000059import android.content.pm.PackageManagerInternal;
Song Pan6e3677c2019-10-29 14:19:26 +000060import android.content.pm.ParceledListSlice;
61import android.content.res.Resources;
62import android.net.Uri;
63import android.os.Handler;
64import android.os.Message;
Song Pand39ec802020-02-25 16:34:49 +000065import android.provider.Settings;
Song Panf93a39c2019-11-19 00:58:31 +000066
67import androidx.test.InstrumentationRegistry;
Song Panf93a39c2019-11-19 00:58:31 +000068
Song Pan6e3677c2019-10-29 14:19:26 +000069import com.android.internal.R;
Winson727da642020-03-10 15:25:32 -070070import com.android.server.compat.PlatformCompat;
Song Pan6e3677c2019-10-29 14:19:26 +000071import com.android.server.integrity.engine.RuleEvaluationEngine;
72import com.android.server.integrity.model.IntegrityCheckResult;
Winson727da642020-03-10 15:25:32 -070073import com.android.server.pm.parsing.PackageParser2;
74import com.android.server.pm.parsing.TestPackageParser2;
Song Pan6e3677c2019-10-29 14:19:26 +000075import com.android.server.testutils.TestUtils;
Song Panf93a39c2019-11-19 00:58:31 +000076
Song Pan90991d42020-02-11 17:39:09 +000077import org.junit.After;
Song Panf93a39c2019-11-19 00:58:31 +000078import org.junit.Before;
Song Panf93a39c2019-11-19 00:58:31 +000079import org.junit.Test;
80import org.junit.runner.RunWith;
Omer Nebil Yaveroglu15395f52020-01-22 12:14:44 +000081import org.junit.runners.JUnit4;
Song Pan6e3677c2019-10-29 14:19:26 +000082import org.mockito.ArgumentCaptor;
Song Panf93a39c2019-11-19 00:58:31 +000083import org.mockito.Mock;
84import org.mockito.junit.MockitoJUnit;
85import org.mockito.junit.MockitoRule;
86
Song Pan6e3677c2019-10-29 14:19:26 +000087import java.io.File;
88import java.io.IOException;
Song Pan90991d42020-02-11 17:39:09 +000089import java.io.InputStream;
90import java.nio.file.Files;
Song Pan6e3677c2019-10-29 14:19:26 +000091import java.util.Arrays;
92import java.util.List;
Song Panf17fd092019-11-29 13:00:50 +000093import java.util.Map;
Winson727da642020-03-10 15:25:32 -070094import java.util.function.Supplier;
Song Pan6e3677c2019-10-29 14:19:26 +000095
Song Panf93a39c2019-11-19 00:58:31 +000096/** Unit test for {@link com.android.server.integrity.AppIntegrityManagerServiceImpl} */
Omer Nebil Yaveroglu15395f52020-01-22 12:14:44 +000097@RunWith(JUnit4.class)
Song Panf93a39c2019-11-19 00:58:31 +000098public class AppIntegrityManagerServiceImplTest {
Song Pane515e962020-01-03 15:06:11 +000099 private static final String TEST_APP_PATH =
Song Pan53007712020-01-16 13:57:31 +0000100 "AppIntegrityManagerServiceImplTest/AppIntegrityManagerServiceTestApp.apk";
Song Panf93a39c2019-11-19 00:58:31 +0000101
Song Pan90991d42020-02-11 17:39:09 +0000102 private static final String TEST_APP_TWO_CERT_PATH =
103 "AppIntegrityManagerServiceImplTest/DummyAppTwoCerts.apk";
104
Khaled Abdelmohsen02067c22020-02-28 11:09:57 +0000105 private static final String TEST_APP_SOURCE_STAMP_PATH =
106 "AppIntegrityManagerServiceImplTest/SourceStampTestApk.apk";
107
Song Pan6e3677c2019-10-29 14:19:26 +0000108 private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
109 private static final String VERSION = "version";
110 private static final String TEST_FRAMEWORK_PACKAGE = "com.android.frameworks.servicestests";
111
112 private static final String PACKAGE_NAME = "com.test.app";
Omer Nebil Yaveroglu15395f52020-01-22 12:14:44 +0000113
114 private static final long VERSION_CODE = 100;
Khaled Abdelmohsen73901612020-01-21 21:12:21 +0000115 private static final String INSTALLER = "com.long.random.test.installer.name";
Omer Nebil Yaveroglu15395f52020-01-22 12:14:44 +0000116
Song Pan6e3677c2019-10-29 14:19:26 +0000117 // These are obtained by running the test and checking logcat.
118 private static final String APP_CERT =
Song Pan53007712020-01-16 13:57:31 +0000119 "C8A2E9BCCF597C2FB6DC66BEE293FC13F2FC47EC77BC6B2B0D52C11F51192AB8";
Song Pan6e3677c2019-10-29 14:19:26 +0000120 // We use SHA256 for package names longer than 32 characters.
121 private static final String INSTALLER_SHA256 =
Khaled Abdelmohsen73901612020-01-21 21:12:21 +0000122 "30F41A7CBF96EE736A54DD6DF759B50ED3CC126ABCEF694E167C324F5976C227";
Khaled Abdelmohsen02067c22020-02-28 11:09:57 +0000123 private static final String SOURCE_STAMP_CERTIFICATE_HASH =
124 "681B0E56A796350C08647352A4DB800CC44B2ADC8F4C72FA350BD05D4D50264D";
Song Pan6e3677c2019-10-29 14:19:26 +0000125
Song Pan90991d42020-02-11 17:39:09 +0000126 private static final String DUMMY_APP_TWO_CERTS_CERT_1 =
127 "C0369C2A1096632429DFA8433068AECEAD00BAC337CA92A175036D39CC9AFE94";
128 private static final String DUMMY_APP_TWO_CERTS_CERT_2 =
129 "94366E0A80F3A3F0D8171A15760B88E228CD6E1101F0414C98878724FBE70147";
130
Song Pane515e962020-01-03 15:06:11 +0000131 private static final String PLAY_STORE_PKG = "com.android.vending";
132 private static final String ADB_INSTALLER = "adb";
Song Pan56044372020-02-03 13:39:45 +0000133 private static final String PLAY_STORE_CERT = "play_store_cert";
Song Pane515e962020-01-03 15:06:11 +0000134
Khaled Abdelmohsen02067c22020-02-28 11:09:57 +0000135 @org.junit.Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
Song Panf93a39c2019-11-19 00:58:31 +0000136
Khaled Abdelmohsen02067c22020-02-28 11:09:57 +0000137 @Mock PackageManagerInternal mPackageManagerInternal;
Winson727da642020-03-10 15:25:32 -0700138 @Mock PlatformCompat mPlatformCompat;
Khaled Abdelmohsen02067c22020-02-28 11:09:57 +0000139 @Mock Context mMockContext;
140 @Mock Resources mMockResources;
141 @Mock RuleEvaluationEngine mRuleEvaluationEngine;
142 @Mock IntegrityFileManager mIntegrityFileManager;
143 @Mock Handler mHandler;
Song Panf93a39c2019-11-19 00:58:31 +0000144
Winson727da642020-03-10 15:25:32 -0700145 private Supplier<PackageParser2> mParserSupplier = TestPackageParser2::new;
146
Song Pand39ec802020-02-25 16:34:49 +0000147 private final Context mRealContext = InstrumentationRegistry.getTargetContext();
148
Song Pan6e3677c2019-10-29 14:19:26 +0000149 private PackageManager mSpyPackageManager;
150 private File mTestApk;
Song Pan90991d42020-02-11 17:39:09 +0000151 private File mTestApkTwoCerts;
Khaled Abdelmohsen02067c22020-02-28 11:09:57 +0000152 private File mTestApkSourceStamp;
Song Pan6e3677c2019-10-29 14:19:26 +0000153
Song Panf93a39c2019-11-19 00:58:31 +0000154 // under test
155 private AppIntegrityManagerServiceImpl mService;
156
157 @Before
Song Pan6e3677c2019-10-29 14:19:26 +0000158 public void setup() throws Exception {
Song Pan53007712020-01-16 13:57:31 +0000159 mTestApk = File.createTempFile("AppIntegrity", ".apk");
160 try (InputStream inputStream = mRealContext.getAssets().open(TEST_APP_PATH)) {
161 Files.copy(inputStream, mTestApk.toPath(), REPLACE_EXISTING);
162 }
163
164 mTestApkTwoCerts = File.createTempFile("AppIntegrityTwoCerts", ".apk");
Song Pan90991d42020-02-11 17:39:09 +0000165 try (InputStream inputStream = mRealContext.getAssets().open(TEST_APP_TWO_CERT_PATH)) {
166 Files.copy(inputStream, mTestApkTwoCerts.toPath(), REPLACE_EXISTING);
167 }
Song Panf93a39c2019-11-19 00:58:31 +0000168
Khaled Abdelmohsen02067c22020-02-28 11:09:57 +0000169 mTestApkSourceStamp = File.createTempFile("AppIntegritySourceStamp", ".apk");
170 try (InputStream inputStream = mRealContext.getAssets().open(TEST_APP_SOURCE_STAMP_PATH)) {
171 Files.copy(inputStream, mTestApkSourceStamp.toPath(), REPLACE_EXISTING);
172 }
173
Song Pan6e3677c2019-10-29 14:19:26 +0000174 mService =
175 new AppIntegrityManagerServiceImpl(
176 mMockContext,
177 mPackageManagerInternal,
Winson727da642020-03-10 15:25:32 -0700178 mParserSupplier,
Song Pan6e3677c2019-10-29 14:19:26 +0000179 mRuleEvaluationEngine,
180 mIntegrityFileManager,
Song Pand39ec802020-02-25 16:34:49 +0000181 mHandler);
Song Pan6e3677c2019-10-29 14:19:26 +0000182
183 mSpyPackageManager = spy(mRealContext.getPackageManager());
184 // setup mocks to prevent NPE
185 when(mMockContext.getPackageManager()).thenReturn(mSpyPackageManager);
186 when(mMockContext.getResources()).thenReturn(mMockResources);
Khaled Abdelmohsen02067c22020-02-28 11:09:57 +0000187 when(mMockResources.getStringArray(anyInt())).thenReturn(new String[] {});
Song Pane515e962020-01-03 15:06:11 +0000188 when(mIntegrityFileManager.initialized()).thenReturn(true);
Song Pand39ec802020-02-25 16:34:49 +0000189 // These are needed to override the Settings.Global.get result.
190 when(mMockContext.getContentResolver()).thenReturn(mRealContext.getContentResolver());
191 setIntegrityCheckIncludesRuleProvider(true);
Song Pan6e3677c2019-10-29 14:19:26 +0000192 }
193
Song Pan90991d42020-02-11 17:39:09 +0000194 @After
195 public void tearDown() throws Exception {
Song Pan53007712020-01-16 13:57:31 +0000196 mTestApk.delete();
Song Pan90991d42020-02-11 17:39:09 +0000197 mTestApkTwoCerts.delete();
Khaled Abdelmohsen02067c22020-02-28 11:09:57 +0000198 mTestApkSourceStamp.delete();
Song Pan90991d42020-02-11 17:39:09 +0000199 }
200
Song Panf93a39c2019-11-19 00:58:31 +0000201 @Test
Song Pan6e3677c2019-10-29 14:19:26 +0000202 public void updateRuleSet_notAuthorized() throws Exception {
203 makeUsSystemApp();
204 Rule rule =
205 new Rule(
Song Pan56044372020-02-03 13:39:45 +0000206 new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true),
Song Pan6e3677c2019-10-29 14:19:26 +0000207 Rule.DENY);
208 TestUtils.assertExpectException(
209 SecurityException.class,
210 "Only system packages specified in config_integrityRuleProviderPackages are"
211 + " allowed to call this method.",
212 () ->
213 mService.updateRuleSet(
214 VERSION,
215 new ParceledListSlice<>(Arrays.asList(rule)),
216 /* statusReceiver= */ null));
217 }
218
219 @Test
220 public void updateRuleSet_notSystemApp() throws Exception {
221 whitelistUsAsRuleProvider();
Song Pand39ec802020-02-25 16:34:49 +0000222 makeUsSystemApp(false);
Song Pan6e3677c2019-10-29 14:19:26 +0000223 Rule rule =
224 new Rule(
Song Pan56044372020-02-03 13:39:45 +0000225 new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true),
Song Pan6e3677c2019-10-29 14:19:26 +0000226 Rule.DENY);
227 TestUtils.assertExpectException(
228 SecurityException.class,
229 "Only system packages specified in config_integrityRuleProviderPackages are"
230 + " allowed to call this method.",
231 () ->
232 mService.updateRuleSet(
233 VERSION,
234 new ParceledListSlice<>(Arrays.asList(rule)),
235 /* statusReceiver= */ null));
236 }
237
238 @Test
239 public void updateRuleSet_authorized() throws Exception {
240 whitelistUsAsRuleProvider();
241 makeUsSystemApp();
242 Rule rule =
243 new Rule(
Song Pan56044372020-02-03 13:39:45 +0000244 new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true),
Song Pan6e3677c2019-10-29 14:19:26 +0000245 Rule.DENY);
246
247 // no SecurityException
248 mService.updateRuleSet(
249 VERSION, new ParceledListSlice<>(Arrays.asList(rule)), mock(IntentSender.class));
250 }
251
252 @Test
253 public void updateRuleSet_correctMethodCall() throws Exception {
254 whitelistUsAsRuleProvider();
255 makeUsSystemApp();
256 IntentSender mockReceiver = mock(IntentSender.class);
257 List<Rule> rules =
258 Arrays.asList(
Khaled Abdelmohsen02067c22020-02-28 11:09:57 +0000259 new Rule(
260 IntegrityFormula.Application.packageNameEquals(PACKAGE_NAME),
Song Pan76a0bb82020-02-06 13:48:04 +0000261 Rule.DENY));
Song Pan6e3677c2019-10-29 14:19:26 +0000262
263 mService.updateRuleSet(VERSION, new ParceledListSlice<>(rules), mockReceiver);
264 runJobInHandler();
265
266 verify(mIntegrityFileManager).writeRules(VERSION, TEST_FRAMEWORK_PACKAGE, rules);
267 ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
268 verify(mockReceiver).sendIntent(any(), anyInt(), intentCaptor.capture(), any(), any());
269 assertEquals(STATUS_SUCCESS, intentCaptor.getValue().getIntExtra(EXTRA_STATUS, -1));
270 }
271
272 @Test
273 public void updateRuleSet_fail() throws Exception {
274 whitelistUsAsRuleProvider();
275 makeUsSystemApp();
276 doThrow(new IOException()).when(mIntegrityFileManager).writeRules(any(), any(), any());
277 IntentSender mockReceiver = mock(IntentSender.class);
278 List<Rule> rules =
279 Arrays.asList(
Khaled Abdelmohsen02067c22020-02-28 11:09:57 +0000280 new Rule(
281 IntegrityFormula.Application.packageNameEquals(PACKAGE_NAME),
Song Pan76a0bb82020-02-06 13:48:04 +0000282 Rule.DENY));
Song Pan6e3677c2019-10-29 14:19:26 +0000283
284 mService.updateRuleSet(VERSION, new ParceledListSlice<>(rules), mockReceiver);
285 runJobInHandler();
286
287 verify(mIntegrityFileManager).writeRules(VERSION, TEST_FRAMEWORK_PACKAGE, rules);
288 ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
289 verify(mockReceiver).sendIntent(any(), anyInt(), intentCaptor.capture(), any(), any());
290 assertEquals(STATUS_FAILURE, intentCaptor.getValue().getIntExtra(EXTRA_STATUS, -1));
291 }
292
293 @Test
294 public void broadcastReceiverRegistration() throws Exception {
Khaled Abdelmohsen73901612020-01-21 21:12:21 +0000295 whitelistUsAsRuleProvider();
296 makeUsSystemApp();
Song Pan6e3677c2019-10-29 14:19:26 +0000297 ArgumentCaptor<IntentFilter> intentFilterCaptor =
298 ArgumentCaptor.forClass(IntentFilter.class);
299
300 verify(mMockContext).registerReceiver(any(), intentFilterCaptor.capture(), any(), any());
301 assertEquals(1, intentFilterCaptor.getValue().countActions());
302 assertEquals(
303 Intent.ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION,
304 intentFilterCaptor.getValue().getAction(0));
305 assertEquals(1, intentFilterCaptor.getValue().countDataTypes());
306 assertEquals(PACKAGE_MIME_TYPE, intentFilterCaptor.getValue().getDataType(0));
307 }
308
309 @Test
310 public void handleBroadcast_correctArgs() throws Exception {
Khaled Abdelmohsen73901612020-01-21 21:12:21 +0000311 whitelistUsAsRuleProvider();
312 makeUsSystemApp();
Song Pan6e3677c2019-10-29 14:19:26 +0000313 ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
314 ArgumentCaptor.forClass(BroadcastReceiver.class);
315 verify(mMockContext)
316 .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
317 Intent intent = makeVerificationIntent();
Song Pan6a0fd8b2020-02-06 13:48:04 +0000318 when(mRuleEvaluationEngine.evaluate(any())).thenReturn(IntegrityCheckResult.allow());
Song Pan6e3677c2019-10-29 14:19:26 +0000319
320 broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent);
321 runJobInHandler();
322
323 ArgumentCaptor<AppInstallMetadata> metadataCaptor =
324 ArgumentCaptor.forClass(AppInstallMetadata.class);
Khaled Abdelmohsen02067c22020-02-28 11:09:57 +0000325 verify(mRuleEvaluationEngine).evaluate(metadataCaptor.capture());
Song Pan6e3677c2019-10-29 14:19:26 +0000326 AppInstallMetadata appInstallMetadata = metadataCaptor.getValue();
327 assertEquals(PACKAGE_NAME, appInstallMetadata.getPackageName());
Omer Nebil Yaveroglub9943722020-02-07 14:22:44 +0000328 assertThat(appInstallMetadata.getAppCertificates()).containsExactly(APP_CERT);
Song Pan6e3677c2019-10-29 14:19:26 +0000329 assertEquals(INSTALLER_SHA256, appInstallMetadata.getInstallerName());
Song Pan53007712020-01-16 13:57:31 +0000330 // we cannot check installer cert because it seems to be device specific.
Song Pan6e3677c2019-10-29 14:19:26 +0000331 assertEquals(VERSION_CODE, appInstallMetadata.getVersionCode());
332 assertFalse(appInstallMetadata.isPreInstalled());
Khaled Abdelmohsenac7eed62020-03-12 19:57:19 +0000333 // Asserting source stamp not present.
334 assertFalse(appInstallMetadata.isStampPresent());
335 assertFalse(appInstallMetadata.isStampVerified());
336 assertFalse(appInstallMetadata.isStampTrusted());
337 assertNull(appInstallMetadata.getStampCertificateHash());
Song Pane515e962020-01-03 15:06:11 +0000338 // These are hardcoded in the test apk android manifest
Song Pan6a0fd8b2020-02-06 13:48:04 +0000339 Map<String, String> allowedInstallers =
340 appInstallMetadata.getAllowedInstallersAndCertificates();
Song Panf17fd092019-11-29 13:00:50 +0000341 assertEquals(2, allowedInstallers.size());
Song Pane515e962020-01-03 15:06:11 +0000342 assertEquals(PLAY_STORE_CERT, allowedInstallers.get(PLAY_STORE_PKG));
Song Pan6a0fd8b2020-02-06 13:48:04 +0000343 assertEquals(INSTALLER_CERTIFICATE_NOT_EVALUATED, allowedInstallers.get(ADB_INSTALLER));
Song Pan6e3677c2019-10-29 14:19:26 +0000344 }
345
346 @Test
Song Pan90991d42020-02-11 17:39:09 +0000347 public void handleBroadcast_correctArgs_multipleCerts() throws Exception {
348 whitelistUsAsRuleProvider();
349 makeUsSystemApp();
350 ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
351 ArgumentCaptor.forClass(BroadcastReceiver.class);
352 verify(mMockContext)
353 .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
354 Intent intent = makeVerificationIntent();
355 intent.setDataAndType(Uri.fromFile(mTestApkTwoCerts), PACKAGE_MIME_TYPE);
356 when(mRuleEvaluationEngine.evaluate(any())).thenReturn(IntegrityCheckResult.allow());
357
358 broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent);
359 runJobInHandler();
360
361 ArgumentCaptor<AppInstallMetadata> metadataCaptor =
362 ArgumentCaptor.forClass(AppInstallMetadata.class);
363 verify(mRuleEvaluationEngine).evaluate(metadataCaptor.capture());
364 AppInstallMetadata appInstallMetadata = metadataCaptor.getValue();
Khaled Abdelmohsen02067c22020-02-28 11:09:57 +0000365 assertThat(appInstallMetadata.getAppCertificates())
366 .containsExactly(DUMMY_APP_TWO_CERTS_CERT_1, DUMMY_APP_TWO_CERTS_CERT_2);
367 }
368
369 @Test
370 public void handleBroadcast_correctArgs_sourceStamp() throws Exception {
371 whitelistUsAsRuleProvider();
372 makeUsSystemApp();
373 ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
374 ArgumentCaptor.forClass(BroadcastReceiver.class);
375 verify(mMockContext)
376 .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
377 Intent intent = makeVerificationIntent();
378 intent.setDataAndType(Uri.fromFile(mTestApkSourceStamp), PACKAGE_MIME_TYPE);
379 when(mRuleEvaluationEngine.evaluate(any())).thenReturn(IntegrityCheckResult.allow());
380
381 broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent);
382 runJobInHandler();
383
384 ArgumentCaptor<AppInstallMetadata> metadataCaptor =
385 ArgumentCaptor.forClass(AppInstallMetadata.class);
386 verify(mRuleEvaluationEngine).evaluate(metadataCaptor.capture());
387 AppInstallMetadata appInstallMetadata = metadataCaptor.getValue();
388 assertTrue(appInstallMetadata.isStampPresent());
389 assertTrue(appInstallMetadata.isStampVerified());
Khaled Abdelmohsen612ecd22020-03-09 12:02:49 +0000390 assertTrue(appInstallMetadata.isStampTrusted());
Khaled Abdelmohsen02067c22020-02-28 11:09:57 +0000391 assertEquals(SOURCE_STAMP_CERTIFICATE_HASH, appInstallMetadata.getStampCertificateHash());
Song Pan90991d42020-02-11 17:39:09 +0000392 }
393
394 @Test
Song Pan6e3677c2019-10-29 14:19:26 +0000395 public void handleBroadcast_allow() throws Exception {
Khaled Abdelmohsen73901612020-01-21 21:12:21 +0000396 whitelistUsAsRuleProvider();
397 makeUsSystemApp();
Song Pan6e3677c2019-10-29 14:19:26 +0000398 ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
399 ArgumentCaptor.forClass(BroadcastReceiver.class);
400 verify(mMockContext)
401 .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
402 Intent intent = makeVerificationIntent();
Song Pan6a0fd8b2020-02-06 13:48:04 +0000403 when(mRuleEvaluationEngine.evaluate(any())).thenReturn(IntegrityCheckResult.allow());
Song Pan6e3677c2019-10-29 14:19:26 +0000404
405 broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent);
406 runJobInHandler();
407
408 verify(mPackageManagerInternal)
409 .setIntegrityVerificationResult(
410 1, PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW);
411 }
412
413 @Test
414 public void handleBroadcast_reject() throws Exception {
Khaled Abdelmohsen73901612020-01-21 21:12:21 +0000415 whitelistUsAsRuleProvider();
416 makeUsSystemApp();
Song Pan6e3677c2019-10-29 14:19:26 +0000417 ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
418 ArgumentCaptor.forClass(BroadcastReceiver.class);
419 verify(mMockContext)
420 .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
Song Pan6a0fd8b2020-02-06 13:48:04 +0000421 when(mRuleEvaluationEngine.evaluate(any()))
Song Pan6e3677c2019-10-29 14:19:26 +0000422 .thenReturn(
423 IntegrityCheckResult.deny(
Omer Nebil Yaveroglu09e44f52020-01-28 15:48:36 +0000424 Arrays.asList(
425 new Rule(
426 new AtomicFormula.BooleanAtomicFormula(
427 AtomicFormula.PRE_INSTALLED, false),
428 Rule.DENY))));
Song Pan6e3677c2019-10-29 14:19:26 +0000429 Intent intent = makeVerificationIntent();
430
431 broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent);
432 runJobInHandler();
433
434 verify(mPackageManagerInternal)
435 .setIntegrityVerificationResult(
436 1, PackageManagerInternal.INTEGRITY_VERIFICATION_REJECT);
437 }
438
Song Pane515e962020-01-03 15:06:11 +0000439 @Test
440 public void handleBroadcast_notInitialized() throws Exception {
Khaled Abdelmohsen73901612020-01-21 21:12:21 +0000441 whitelistUsAsRuleProvider();
442 makeUsSystemApp();
Song Pane515e962020-01-03 15:06:11 +0000443 when(mIntegrityFileManager.initialized()).thenReturn(false);
444 ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
445 ArgumentCaptor.forClass(BroadcastReceiver.class);
446 verify(mMockContext)
447 .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
448 Intent intent = makeVerificationIntent();
Song Pan6a0fd8b2020-02-06 13:48:04 +0000449 when(mRuleEvaluationEngine.evaluate(any())).thenReturn(IntegrityCheckResult.allow());
Song Pane515e962020-01-03 15:06:11 +0000450
451 broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent);
452 runJobInHandler();
453
Omer Nebil Yaveroglud4c9af82020-01-24 19:36:02 +0000454 // The evaluation will still run since we still evaluate manifest based rules.
Song Pane515e962020-01-03 15:06:11 +0000455 verify(mPackageManagerInternal)
456 .setIntegrityVerificationResult(
457 1, PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW);
Song Pane515e962020-01-03 15:06:11 +0000458 }
459
Khaled Abdelmohsen73901612020-01-21 21:12:21 +0000460 @Test
461 public void verifierAsInstaller_skipIntegrityVerification() throws Exception {
462 whitelistUsAsRuleProvider();
463 makeUsSystemApp();
Song Pand39ec802020-02-25 16:34:49 +0000464 setIntegrityCheckIncludesRuleProvider(false);
Khaled Abdelmohsen73901612020-01-21 21:12:21 +0000465 ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
466 ArgumentCaptor.forClass(BroadcastReceiver.class);
Song Pan7a9c4c22020-02-04 14:03:57 +0000467 verify(mMockContext, atLeastOnce())
Khaled Abdelmohsen73901612020-01-21 21:12:21 +0000468 .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
469 Intent intent = makeVerificationIntent(TEST_FRAMEWORK_PACKAGE);
Song Pan6a0fd8b2020-02-06 13:48:04 +0000470 when(mRuleEvaluationEngine.evaluate(any()))
Song Pan56044372020-02-03 13:39:45 +0000471 .thenReturn(IntegrityCheckResult.deny(/* rule= */ null));
Khaled Abdelmohsen73901612020-01-21 21:12:21 +0000472
473 broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent);
474 runJobInHandler();
475
476 verify(mPackageManagerInternal)
477 .setIntegrityVerificationResult(
478 1, PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW);
479 }
480
Song Pan56044372020-02-03 13:39:45 +0000481 @Test
482 public void getCurrentRules() throws Exception {
483 whitelistUsAsRuleProvider();
484 makeUsSystemApp();
Song Pan76a0bb82020-02-06 13:48:04 +0000485 Rule rule = new Rule(IntegrityFormula.Application.packageNameEquals("package"), Rule.DENY);
Song Pan56044372020-02-03 13:39:45 +0000486 when(mIntegrityFileManager.readRules(any())).thenReturn(Arrays.asList(rule));
487
488 assertThat(mService.getCurrentRules().getList()).containsExactly(rule);
489 }
490
Song Pan4d374862020-03-04 15:30:45 +0000491 @Test
492 public void getWhitelistedRuleProviders() throws Exception {
493 whitelistUsAsRuleProvider();
494
495 assertThat(mService.getWhitelistedRuleProviders()).containsExactly(TEST_FRAMEWORK_PACKAGE);
496 }
497
Song Pan6e3677c2019-10-29 14:19:26 +0000498 private void whitelistUsAsRuleProvider() {
499 Resources mockResources = mock(Resources.class);
500 when(mockResources.getStringArray(R.array.config_integrityRuleProviderPackages))
Khaled Abdelmohsen02067c22020-02-28 11:09:57 +0000501 .thenReturn(new String[] {TEST_FRAMEWORK_PACKAGE});
Song Pan6e3677c2019-10-29 14:19:26 +0000502 when(mMockContext.getResources()).thenReturn(mockResources);
503 }
504
505 private void runJobInHandler() {
506 ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
507 // sendMessageAtTime is the first non-final method in the call chain when "post" is invoked.
508 verify(mHandler).sendMessageAtTime(messageCaptor.capture(), anyLong());
509 messageCaptor.getValue().getCallback().run();
510 }
511
512 private void makeUsSystemApp() throws Exception {
Song Pand39ec802020-02-25 16:34:49 +0000513 makeUsSystemApp(true);
514 }
515
516 private void makeUsSystemApp(boolean isSystemApp) throws Exception {
Song Pan6e3677c2019-10-29 14:19:26 +0000517 PackageInfo packageInfo =
518 mRealContext.getPackageManager().getPackageInfo(TEST_FRAMEWORK_PACKAGE, 0);
Song Pand39ec802020-02-25 16:34:49 +0000519 if (isSystemApp) {
520 packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
521 } else {
522 packageInfo.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;
523 }
Song Pan6e3677c2019-10-29 14:19:26 +0000524 doReturn(packageInfo)
525 .when(mSpyPackageManager)
526 .getPackageInfo(eq(TEST_FRAMEWORK_PACKAGE), anyInt());
Song Pand39ec802020-02-25 16:34:49 +0000527 when(mMockContext.getPackageManager()).thenReturn(mSpyPackageManager);
Song Pan6e3677c2019-10-29 14:19:26 +0000528 }
529
530 private Intent makeVerificationIntent() throws Exception {
Khaled Abdelmohsen73901612020-01-21 21:12:21 +0000531 PackageInfo packageInfo =
Song Pan56044372020-02-03 13:39:45 +0000532 mRealContext
533 .getPackageManager()
Khaled Abdelmohsen02067c22020-02-28 11:09:57 +0000534 .getPackageInfo(
535 TEST_FRAMEWORK_PACKAGE, PackageManager.GET_SIGNING_CERTIFICATES);
Song Pan56044372020-02-03 13:39:45 +0000536 doReturn(packageInfo).when(mSpyPackageManager).getPackageInfo(eq(INSTALLER), anyInt());
537 doReturn(1).when(mSpyPackageManager).getPackageUid(eq(INSTALLER), anyInt());
Khaled Abdelmohsen73901612020-01-21 21:12:21 +0000538 return makeVerificationIntent(INSTALLER);
539 }
540
541 private Intent makeVerificationIntent(String installer) throws Exception {
Song Pan6e3677c2019-10-29 14:19:26 +0000542 Intent intent = new Intent();
543 intent.setDataAndType(Uri.fromFile(mTestApk), PACKAGE_MIME_TYPE);
544 intent.setAction(Intent.ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION);
545 intent.putExtra(EXTRA_VERIFICATION_ID, 1);
546 intent.putExtra(Intent.EXTRA_PACKAGE_NAME, PACKAGE_NAME);
Khaled Abdelmohsen73901612020-01-21 21:12:21 +0000547 intent.putExtra(EXTRA_VERIFICATION_INSTALLER_PACKAGE, installer);
Song Pan6e3677c2019-10-29 14:19:26 +0000548 intent.putExtra(
549 EXTRA_VERIFICATION_INSTALLER_UID,
Khaled Abdelmohsen73901612020-01-21 21:12:21 +0000550 mMockContext.getPackageManager().getPackageUid(installer, /* flags= */ 0));
Omer Nebil Yaveroglu15395f52020-01-22 12:14:44 +0000551 intent.putExtra(Intent.EXTRA_LONG_VERSION_CODE, VERSION_CODE);
Song Pan6e3677c2019-10-29 14:19:26 +0000552 return intent;
Song Panf93a39c2019-11-19 00:58:31 +0000553 }
Song Pand39ec802020-02-25 16:34:49 +0000554
555 private void setIntegrityCheckIncludesRuleProvider(boolean shouldInclude) throws Exception {
556 int value = shouldInclude ? 1 : 0;
Khaled Abdelmohsen02067c22020-02-28 11:09:57 +0000557 Settings.Global.putInt(
558 mRealContext.getContentResolver(),
559 Settings.Global.INTEGRITY_CHECK_INCLUDES_RULE_PROVIDER,
560 value);
561 assertThat(
562 Settings.Global.getInt(
563 mRealContext.getContentResolver(),
564 Settings.Global.INTEGRITY_CHECK_INCLUDES_RULE_PROVIDER,
565 -1)
566 == 1)
567 .isEqualTo(shouldInclude);
Song Pand39ec802020-02-25 16:34:49 +0000568 }
Song Panf93a39c2019-11-19 00:58:31 +0000569}