1 /* 2 * Copyright (C) 2022 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 18 package com.android.managedprovisioning.task; 19 20 import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE; 21 22 import static com.android.managedprovisioning.task.VerifyAdminPackageTask.ERROR_DEVICE_ADMIN_MISSING; 23 import static com.android.managedprovisioning.task.VerifyAdminPackageTask.ERROR_HASH_MISMATCH; 24 25 import static org.mockito.Matchers.any; 26 import static org.mockito.Mockito.mock; 27 import static org.mockito.Mockito.verify; 28 import static org.mockito.Mockito.verifyNoMoreInteractions; 29 import static org.mockito.Mockito.when; 30 31 import android.content.ComponentName; 32 import android.content.Context; 33 import android.content.pm.PackageInfo; 34 import android.content.pm.PackageManager; 35 import android.content.pm.Signature; 36 37 import androidx.test.filters.SmallTest; 38 import androidx.test.runner.AndroidJUnit4; 39 40 import com.android.managedprovisioning.analytics.ProvisioningAnalyticsTracker; 41 import com.android.managedprovisioning.common.Utils; 42 import com.android.managedprovisioning.model.PackageDownloadInfo; 43 import com.android.managedprovisioning.model.ProvisioningParams; 44 45 import org.junit.Before; 46 import org.junit.Test; 47 import org.junit.runner.RunWith; 48 import org.mockito.Mock; 49 import org.mockito.MockitoAnnotations; 50 51 import java.io.File; 52 53 /** 54 * Unit tests for {@link VerifyAdminPackageTask}. 55 */ 56 @RunWith(AndroidJUnit4.class) 57 @SmallTest 58 public class VerifyAdminPackageTaskTest { 59 60 private static final String TEST_PACKAGE_NAME = "sample.package.name"; 61 private static final String TEST_ADMIN_NAME = TEST_PACKAGE_NAME + ".DeviceAdmin"; 62 private static final String TEST_PACKAGE_LOCATION = "http://www.some.uri.com"; 63 private static final String TEST_LOCAL_FILENAME = "/local/filename"; 64 private static final File TEST_LOCAL_FILE = new File(TEST_LOCAL_FILENAME); 65 private static final int TEST_USER_ID = 123; 66 private static final byte[] TEST_BAD_HASH = new byte[] { 'b', 'a', 'd' }; 67 private static final byte[] TEST_PACKAGE_CHECKSUM_HASH = new byte[] { '1', '2', '3', '4', '5' }; 68 private static final byte[] TEST_SIGNATURE_HASH = new byte[] {'a', 'b', 'c', 'd'}; 69 private static final byte[] EMPTY_BYTE_ARRAY = new byte[] {}; 70 private static final Signature[] TEST_SIGNATURES = new Signature[] { new Signature("1986") }; 71 72 @Mock private Context mContext; 73 @Mock private DownloadPackageTask mDownloadPackageTask; 74 @Mock private AbstractProvisioningTask.Callback mCallback; 75 @Mock private PackageManager mPackageManager; 76 @Mock private Utils mUtils; 77 @Mock private PackageInfo mPackageInfo; 78 79 private ChecksumUtils mChecksumUtils; 80 81 private AbstractProvisioningTask mTask; 82 83 @Before setUp()84 public void setUp() throws Exception { 85 // This is necessary for mockito to work 86 MockitoAnnotations.initMocks(this); 87 88 when(mContext.getPackageManager()).thenReturn(mPackageManager); 89 90 mPackageInfo.packageName = TEST_PACKAGE_NAME; 91 mPackageInfo.signatures = TEST_SIGNATURES; 92 93 when(mPackageManager.getPackageArchiveInfo(TEST_LOCAL_FILENAME, 94 PackageManager.GET_SIGNATURES | PackageManager.GET_RECEIVERS)) 95 .thenReturn(mPackageInfo); 96 97 when(mDownloadPackageTask.getPackageLocation()).thenReturn(TEST_LOCAL_FILE); 98 99 when(mUtils.findDeviceAdminInPackageInfo(TEST_PACKAGE_NAME, null, mPackageInfo)) 100 .thenReturn(new ComponentName(TEST_PACKAGE_NAME, TEST_ADMIN_NAME)); 101 102 mChecksumUtils = new ChecksumUtils(mUtils); 103 } 104 105 @Test testDownloadLocationNull()106 public void testDownloadLocationNull() { 107 // GIVEN that the download package location is null 108 when(mDownloadPackageTask.getPackageLocation()).thenReturn(null); 109 110 // WHEN running the VerifyPackageTask 111 runWithDownloadInfo(TEST_PACKAGE_CHECKSUM_HASH, EMPTY_BYTE_ARRAY); 112 113 // THEN success should be called 114 verify(mCallback).onSuccess(mTask); 115 verifyNoMoreInteractions(mCallback); 116 } 117 118 @Test testMissingDeviceAdminComponent()119 public void testMissingDeviceAdminComponent() { 120 // GIVEN that the device admin component cannot be found 121 when(mUtils.findDeviceAdminInPackageInfo(TEST_PACKAGE_NAME, null, mPackageInfo)) 122 .thenReturn(null); 123 124 // WHEN running the VerifyPackageTask 125 runWithDownloadInfo(TEST_PACKAGE_CHECKSUM_HASH, EMPTY_BYTE_ARRAY); 126 127 // THEN an error should be reported 128 verify(mCallback).onError(mTask, ERROR_DEVICE_ADMIN_MISSING, /* errorMessage= */ null); 129 verifyNoMoreInteractions(mCallback); 130 } 131 132 @Test testPackageChecksumSha256_success()133 public void testPackageChecksumSha256_success() throws Exception { 134 // GIVEN the hash of the downloaded file matches the parameter value 135 when(mUtils.computeHashOfFile(TEST_LOCAL_FILENAME, Utils.SHA256_TYPE)) 136 .thenReturn(TEST_PACKAGE_CHECKSUM_HASH); 137 138 // WHEN running the VerifyPackageTask 139 runWithDownloadInfo(TEST_PACKAGE_CHECKSUM_HASH, EMPTY_BYTE_ARRAY); 140 141 // THEN success should be called 142 verify(mCallback).onSuccess(mTask); 143 verifyNoMoreInteractions(mCallback); 144 } 145 146 @Test testSignatureHash_success()147 public void testSignatureHash_success() throws Exception { 148 // GIVEN the hash of the signature matches the parameter value 149 when(mUtils.computeHashOfByteArray(TEST_SIGNATURES[0].toByteArray())) 150 .thenReturn(TEST_SIGNATURE_HASH); 151 152 // WHEN running the VerifyPackageTask 153 runWithDownloadInfo(EMPTY_BYTE_ARRAY, TEST_SIGNATURE_HASH); 154 155 // THEN success should be called 156 verify(mCallback).onSuccess(mTask); 157 verifyNoMoreInteractions(mCallback); 158 } 159 160 @Test testSignatureHash_failure()161 public void testSignatureHash_failure() throws Exception { 162 // GIVEN the hash of the signature does not match the parameter value 163 when(mUtils.computeHashOfByteArray(TEST_SIGNATURES[0].toByteArray())) 164 .thenReturn(TEST_BAD_HASH); 165 166 // WHEN running the VerifyPackageTask 167 runWithDownloadInfo(EMPTY_BYTE_ARRAY, TEST_SIGNATURE_HASH); 168 169 // THEN hash mismatch error should be called 170 verify(mCallback).onError(mTask, ERROR_HASH_MISMATCH, /* errorMessage= */ null); 171 verifyNoMoreInteractions(mCallback); 172 } 173 174 @Test testSignatureHash_noSignature()175 public void testSignatureHash_noSignature() throws Exception { 176 // GIVEN the package has no signature 177 mPackageInfo.signatures = null; 178 179 // WHEN running the VerifyPackageTask 180 runWithDownloadInfo(EMPTY_BYTE_ARRAY, TEST_SIGNATURE_HASH); 181 182 // THEN hash mismatch error should be called 183 verify(mCallback).onError(mTask, ERROR_HASH_MISMATCH, /* errorMessage= */ null); 184 verifyNoMoreInteractions(mCallback); 185 } 186 187 @Test testSignatureHash_digestFailure()188 public void testSignatureHash_digestFailure() throws Exception { 189 // GIVEN the package has no signature 190 when(mUtils.computeHashOfByteArray(any(byte[].class))).thenReturn(null); 191 192 // WHEN running the VerifyPackageTask 193 runWithDownloadInfo(EMPTY_BYTE_ARRAY, TEST_SIGNATURE_HASH); 194 195 // THEN hash mismatch error should be called 196 verify(mCallback).onError(mTask, ERROR_HASH_MISMATCH, /* errorMessage= */ null); 197 verifyNoMoreInteractions(mCallback); 198 } 199 runWithDownloadInfo(byte[] packageChecksum, byte[] signatureChecksum)200 private void runWithDownloadInfo(byte[] packageChecksum, byte[] signatureChecksum) { 201 PackageDownloadInfo downloadInfo = new PackageDownloadInfo.Builder() 202 .setLocation(TEST_PACKAGE_LOCATION) 203 .setPackageChecksum(packageChecksum) 204 .setSignatureChecksum(signatureChecksum) 205 .build(); 206 ProvisioningParams params = new ProvisioningParams.Builder() 207 .setProvisioningAction(ACTION_PROVISION_MANAGED_DEVICE) 208 .setDeviceAdminPackageName(TEST_PACKAGE_NAME) 209 .setDeviceAdminDownloadInfo(downloadInfo) 210 .build(); 211 mTask = new VerifyAdminPackageTask(mUtils, mDownloadPackageTask, mContext, params, 212 downloadInfo, mCallback, mock(ProvisioningAnalyticsTracker.class), 213 mChecksumUtils); 214 mTask.run(TEST_USER_ID); 215 } 216 } 217