1 /* 2 * Copyright (C) 2016 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 package com.android.server.pm.backup; 17 18 import static com.google.common.truth.Truth.assertThat; 19 20 import static org.junit.Assert.assertFalse; 21 import static org.junit.Assert.assertTrue; 22 import static org.junit.Assert.assertEquals; 23 import static org.mockito.Mockito.doReturn; 24 import static org.mockito.Mockito.mock; 25 import static org.mockito.Mockito.when; 26 27 import android.content.pm.ApplicationInfo; 28 import android.content.pm.PackageInfo; 29 import android.content.pm.PackageManagerInternal; 30 import android.content.pm.PackageParser; 31 import android.content.pm.PackageParser.Package; 32 import android.content.pm.Signature; 33 import android.content.pm.SigningInfo; 34 import android.test.MoreAsserts; 35 import android.platform.test.annotations.Presubmit; 36 import android.support.test.filters.SmallTest; 37 import android.support.test.runner.AndroidJUnit4; 38 39 import com.android.server.backup.BackupUtils; 40 41 import org.junit.Before; 42 import org.junit.Test; 43 import org.junit.runner.RunWith; 44 45 import java.util.ArrayList; 46 import java.util.Arrays; 47 48 @SmallTest 49 @Presubmit 50 @RunWith(AndroidJUnit4.class) 51 public class BackupUtilsTest { 52 53 private static final Signature SIGNATURE_1 = generateSignature((byte) 1); 54 private static final Signature SIGNATURE_2 = generateSignature((byte) 2); 55 private static final Signature SIGNATURE_3 = generateSignature((byte) 3); 56 private static final Signature SIGNATURE_4 = generateSignature((byte) 4); 57 private static final byte[] SIGNATURE_HASH_1 = BackupUtils.hashSignature(SIGNATURE_1); 58 private static final byte[] SIGNATURE_HASH_2 = BackupUtils.hashSignature(SIGNATURE_2); 59 private static final byte[] SIGNATURE_HASH_3 = BackupUtils.hashSignature(SIGNATURE_3); 60 private static final byte[] SIGNATURE_HASH_4 = BackupUtils.hashSignature(SIGNATURE_4); 61 62 private PackageManagerInternal mMockPackageManagerInternal; 63 64 @Before 65 public void setUp() throws Exception { 66 mMockPackageManagerInternal = mock(PackageManagerInternal.class); 67 } 68 69 @Test 70 public void signaturesMatch_targetIsNull_returnsFalse() throws Exception { 71 ArrayList<byte[]> storedSigHashes = new ArrayList<>(); 72 storedSigHashes.add(SIGNATURE_HASH_1); 73 boolean result = BackupUtils.signaturesMatch(storedSigHashes, null, 74 mMockPackageManagerInternal); 75 76 assertThat(result).isFalse(); 77 } 78 79 @Test 80 public void signaturesMatch_systemApplication_returnsTrue() throws Exception { 81 PackageInfo packageInfo = new PackageInfo(); 82 packageInfo.packageName = "test"; 83 packageInfo.applicationInfo = new ApplicationInfo(); 84 packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM; 85 86 ArrayList<byte[]> storedSigHashes = new ArrayList<>(); 87 storedSigHashes.add(SIGNATURE_HASH_1); 88 boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, 89 mMockPackageManagerInternal); 90 91 assertThat(result).isTrue(); 92 } 93 94 @Test 95 public void signaturesMatch_disallowsUnsignedApps_storedSignatureNull_returnsFalse() 96 throws Exception { 97 PackageInfo packageInfo = new PackageInfo(); 98 packageInfo.packageName = "test"; 99 packageInfo.signingInfo = new SigningInfo( 100 new PackageParser.SigningDetails( 101 new Signature[] {SIGNATURE_1}, 102 PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3, 103 null, 104 null, 105 null)); 106 packageInfo.applicationInfo = new ApplicationInfo(); 107 108 boolean result = BackupUtils.signaturesMatch(null, packageInfo, 109 mMockPackageManagerInternal); 110 111 assertThat(result).isFalse(); 112 } 113 114 @Test 115 public void signaturesMatch_disallowsUnsignedApps_storedSignatureEmpty_returnsFalse() 116 throws Exception { 117 PackageInfo packageInfo = new PackageInfo(); 118 packageInfo.packageName = "test"; 119 packageInfo.signingInfo = new SigningInfo( 120 new PackageParser.SigningDetails( 121 new Signature[] {SIGNATURE_1}, 122 PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3, 123 null, 124 null, 125 null)); 126 packageInfo.applicationInfo = new ApplicationInfo(); 127 128 ArrayList<byte[]> storedSigHashes = new ArrayList<>(); 129 boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, 130 mMockPackageManagerInternal); 131 132 assertThat(result).isFalse(); 133 } 134 135 136 @Test 137 public void 138 signaturesMatch_disallowsUnsignedApps_targetSignatureEmpty_returnsFalse() 139 throws Exception { 140 PackageInfo packageInfo = new PackageInfo(); 141 packageInfo.packageName = "test"; 142 packageInfo.signingInfo = null; 143 packageInfo.applicationInfo = new ApplicationInfo(); 144 145 ArrayList<byte[]> storedSigHashes = new ArrayList<>(); 146 storedSigHashes.add(SIGNATURE_HASH_1); 147 boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, 148 mMockPackageManagerInternal); 149 150 assertThat(result).isFalse(); 151 } 152 153 @Test 154 public void 155 signaturesMatch_disallowsUnsignedApps_targetSignatureNull_returnsFalse() 156 throws Exception { 157 PackageInfo packageInfo = new PackageInfo(); 158 packageInfo.packageName = "test"; 159 packageInfo.signingInfo = null; 160 packageInfo.applicationInfo = new ApplicationInfo(); 161 162 ArrayList<byte[]> storedSigHashes = new ArrayList<>(); 163 storedSigHashes.add(SIGNATURE_HASH_1); 164 boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, 165 mMockPackageManagerInternal); 166 167 assertThat(result).isFalse(); 168 } 169 170 @Test 171 public void signaturesMatch_disallowsUnsignedApps_bothSignaturesNull_returnsFalse() 172 throws Exception { 173 PackageInfo packageInfo = new PackageInfo(); 174 packageInfo.packageName = "test"; 175 packageInfo.signingInfo = null; 176 packageInfo.applicationInfo = new ApplicationInfo(); 177 178 boolean result = BackupUtils.signaturesMatch(null, packageInfo, 179 mMockPackageManagerInternal); 180 181 assertThat(result).isFalse(); 182 } 183 184 @Test 185 public void signaturesMatch_disallowsUnsignedApps_bothSignaturesEmpty_returnsFalse() 186 throws Exception { 187 PackageInfo packageInfo = new PackageInfo(); 188 packageInfo.packageName = "test"; 189 packageInfo.signingInfo = null; 190 packageInfo.applicationInfo = new ApplicationInfo(); 191 192 ArrayList<byte[]> storedSigHashes = new ArrayList<>(); 193 boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, 194 mMockPackageManagerInternal); 195 196 assertThat(result).isFalse(); 197 } 198 199 @Test 200 public void signaturesMatch_equalSignatures_returnsTrue() throws Exception { 201 PackageInfo packageInfo = new PackageInfo(); 202 packageInfo.packageName = "test"; 203 packageInfo.signingInfo = new SigningInfo( 204 new PackageParser.SigningDetails( 205 new Signature[] {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}, 206 PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3, 207 null, 208 null, 209 null)); 210 packageInfo.applicationInfo = new ApplicationInfo(); 211 212 ArrayList<byte[]> storedSigHashes = new ArrayList<>(); 213 storedSigHashes.add(SIGNATURE_HASH_1); 214 storedSigHashes.add(SIGNATURE_HASH_2); 215 storedSigHashes.add(SIGNATURE_HASH_3); 216 boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, 217 mMockPackageManagerInternal); 218 219 assertThat(result).isTrue(); 220 } 221 222 @Test 223 public void signaturesMatch_extraSignatureInTarget_returnsTrue() throws Exception { 224 PackageInfo packageInfo = new PackageInfo(); 225 packageInfo.packageName = "test"; 226 packageInfo.signingInfo = new SigningInfo( 227 new PackageParser.SigningDetails( 228 new Signature[] {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}, 229 PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3, 230 null, 231 null, 232 null)); 233 packageInfo.applicationInfo = new ApplicationInfo(); 234 235 ArrayList<byte[]> storedSigHashes = new ArrayList<>(); 236 storedSigHashes.add(SIGNATURE_HASH_1); 237 storedSigHashes.add(SIGNATURE_HASH_2); 238 boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, 239 mMockPackageManagerInternal); 240 241 assertThat(result).isTrue(); 242 } 243 244 @Test 245 public void signaturesMatch_extraSignatureInStored_returnsFalse() throws Exception { 246 PackageInfo packageInfo = new PackageInfo(); 247 packageInfo.packageName = "test"; 248 packageInfo.signingInfo = new SigningInfo( 249 new PackageParser.SigningDetails( 250 new Signature[] {SIGNATURE_1, SIGNATURE_2}, 251 PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3, 252 null, 253 null, 254 null)); 255 packageInfo.applicationInfo = new ApplicationInfo(); 256 257 ArrayList<byte[]> storedSigHashes = new ArrayList<>(); 258 storedSigHashes.add(SIGNATURE_HASH_1); 259 storedSigHashes.add(SIGNATURE_HASH_2); 260 storedSigHashes.add(SIGNATURE_HASH_3); 261 boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, 262 mMockPackageManagerInternal); 263 264 assertThat(result).isFalse(); 265 } 266 267 @Test 268 public void signaturesMatch_oneNonMatchingSignature_returnsFalse() throws Exception { 269 PackageInfo packageInfo = new PackageInfo(); 270 packageInfo.packageName = "test"; 271 packageInfo.signingInfo = new SigningInfo( 272 new PackageParser.SigningDetails( 273 new Signature[] {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}, 274 PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3, 275 null, 276 null, 277 null)); 278 packageInfo.applicationInfo = new ApplicationInfo(); 279 280 ArrayList<byte[]> storedSigHashes = new ArrayList<>(); 281 storedSigHashes.add(SIGNATURE_HASH_1); 282 storedSigHashes.add(SIGNATURE_HASH_2); 283 storedSigHashes.add(SIGNATURE_HASH_4); 284 boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, 285 mMockPackageManagerInternal); 286 287 assertThat(result).isFalse(); 288 } 289 290 @Test 291 public void signaturesMatch_singleStoredSignatureNoRotation_returnsTrue() 292 throws Exception { 293 PackageInfo packageInfo = new PackageInfo(); 294 packageInfo.packageName = "test"; 295 packageInfo.signingInfo = new SigningInfo( 296 new PackageParser.SigningDetails( 297 new Signature[] {SIGNATURE_1}, 298 PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3, 299 null, 300 null, 301 null)); 302 packageInfo.applicationInfo = new ApplicationInfo(); 303 304 doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(SIGNATURE_HASH_1, 305 packageInfo.packageName); 306 307 ArrayList<byte[]> storedSigHashes = new ArrayList<>(); 308 storedSigHashes.add(SIGNATURE_HASH_1); 309 boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, 310 mMockPackageManagerInternal); 311 312 assertThat(result).isTrue(); 313 } 314 315 @Test 316 public void signaturesMatch_singleStoredSignatureWithRotationAssumeDataCapability_returnsTrue() 317 throws Exception { 318 PackageInfo packageInfo = new PackageInfo(); 319 packageInfo.packageName = "test"; 320 packageInfo.signingInfo = new SigningInfo( 321 new PackageParser.SigningDetails( 322 new Signature[] {SIGNATURE_1, SIGNATURE_2}, 323 PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3, 324 null, 325 null, 326 null)); 327 packageInfo.applicationInfo = new ApplicationInfo(); 328 329 // we know SIGNATURE_1 is in history, and we want to assume it has 330 // SigningDetails.CertCapabilities.INSTALLED_DATA capability 331 doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(SIGNATURE_HASH_1, 332 packageInfo.packageName); 333 334 ArrayList<byte[]> storedSigHashes = new ArrayList<>(); 335 storedSigHashes.add(SIGNATURE_HASH_1); 336 boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, 337 mMockPackageManagerInternal); 338 339 assertThat(result).isTrue(); 340 } 341 342 @Test 343 public void 344 signaturesMatch_singleStoredSignatureWithRotationAssumeNoDataCapability_returnsFalse() 345 throws Exception { 346 PackageInfo packageInfo = new PackageInfo(); 347 packageInfo.packageName = "test"; 348 packageInfo.signingInfo = new SigningInfo( 349 new PackageParser.SigningDetails( 350 new Signature[] {SIGNATURE_1, SIGNATURE_2}, 351 PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3, 352 null, 353 null, 354 null)); 355 packageInfo.applicationInfo = new ApplicationInfo(); 356 357 // we know SIGNATURE_1 is in history, but we want to assume it does not have 358 // SigningDetails.CertCapabilities.INSTALLED_DATA capability 359 doReturn(false).when(mMockPackageManagerInternal).isDataRestoreSafe(SIGNATURE_HASH_1, 360 packageInfo.packageName); 361 362 ArrayList<byte[]> storedSigHashes = new ArrayList<>(); 363 storedSigHashes.add(SIGNATURE_HASH_1); 364 boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, 365 mMockPackageManagerInternal); 366 367 assertThat(result).isFalse(); 368 } 369 370 @Test 371 public void testHashSignature() { 372 final byte[] sig1 = "abc".getBytes(); 373 final byte[] sig2 = "def".getBytes(); 374 375 final byte[] hash1a = BackupUtils.hashSignature(sig1); 376 final byte[] hash1b = BackupUtils.hashSignature(new Signature(sig1)); 377 378 final byte[] hash2a = BackupUtils.hashSignature(sig2); 379 final byte[] hash2b = BackupUtils.hashSignature(new Signature(sig2)); 380 381 assertEquals(32, hash1a.length); 382 MoreAsserts.assertEquals(hash1a, hash1b); 383 384 assertEquals(32, hash2a.length); 385 MoreAsserts.assertEquals(hash2a, hash2b); 386 387 assertFalse(Arrays.equals(hash1a, hash2a)); 388 389 final ArrayList<byte[]> listA = BackupUtils.hashSignatureArray(Arrays.asList( 390 "abc".getBytes(), "def".getBytes())); 391 392 final ArrayList<byte[]> listB = BackupUtils.hashSignatureArray(new Signature[]{ 393 new Signature("abc".getBytes()), new Signature("def".getBytes())}); 394 395 assertEquals(2, listA.size()); 396 assertEquals(2, listB.size()); 397 398 MoreAsserts.assertEquals(hash1a, listA.get(0)); 399 MoreAsserts.assertEquals(hash1a, listB.get(0)); 400 401 MoreAsserts.assertEquals(hash2a, listA.get(1)); 402 MoreAsserts.assertEquals(hash2a, listB.get(1)); 403 } 404 405 private static Signature generateSignature(byte i) { 406 byte[] signatureBytes = new byte[256]; 407 signatureBytes[0] = i; 408 return new Signature(signatureBytes); 409 } 410 } 411