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