1 /* 2 * Copyright (C) 2020 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 android.content.pm; 17 18 import static android.content.pm.PackageParser.SigningDetails.CertCapabilities.AUTH; 19 import static android.content.pm.PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA; 20 import static android.content.pm.PackageParser.SigningDetails.CertCapabilities.PERMISSION; 21 import static android.content.pm.PackageParser.SigningDetails.CertCapabilities.ROLLBACK; 22 import static android.content.pm.PackageParser.SigningDetails.CertCapabilities.SHARED_USER_ID; 23 import static android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3; 24 25 import static org.junit.Assert.assertEquals; 26 import static org.junit.Assert.assertFalse; 27 import static org.junit.Assert.assertTrue; 28 import static org.junit.Assert.fail; 29 30 import android.content.pm.PackageParser.SigningDetails; 31 import android.util.ArraySet; 32 import android.util.PackageUtils; 33 34 import androidx.test.ext.junit.runners.AndroidJUnit4; 35 import androidx.test.filters.SmallTest; 36 37 import org.junit.Test; 38 import org.junit.runner.RunWith; 39 40 import java.util.Set; 41 42 @RunWith(AndroidJUnit4.class) 43 @SmallTest 44 public class SigningDetailsTest { 45 private static final int DEFAULT_CAPABILITIES = 46 INSTALLED_DATA | SHARED_USER_ID | PERMISSION | AUTH; 47 48 // Some of the tests in this class require valid certificate encodings from which to pull the 49 // public key for the SigningDetails; the following are all DER encoded EC X.509 certificates. 50 private static final String FIRST_SIGNATURE = 51 "3082016c30820111a003020102020900ca0fb64dfb66e772300a06082a86" 52 + "48ce3d04030230123110300e06035504030c0765632d70323536301e170d" 53 + "3136303333313134353830365a170d3433303831373134353830365a3012" 54 + "3110300e06035504030c0765632d703235363059301306072a8648ce3d02" 55 + "0106082a8648ce3d03010703420004a65f113d22cb4913908307ac31ee2b" 56 + "a0e9138b785fac6536d14ea2ce90d2b4bfe194b50cdc8e169f54a73a991e" 57 + "f0fa76329825be078cc782740703da44b4d7eba350304e301d0603551d0e" 58 + "04160414d4133568b95b30158b322071ea8c43ff5b05ccc8301f0603551d" 59 + "23041830168014d4133568b95b30158b322071ea8c43ff5b05ccc8300c06" 60 + "03551d13040530030101ff300a06082a8648ce3d04030203490030460221" 61 + "00f504a0866caef029f417142c5cb71354c79ffcd1d640618dfca4f19e16" 62 + "db78d6022100f8eea4829799c06cad08c6d3d2d2ec05e0574154e747ea0f" 63 + "dbb8042cb655aadd"; 64 private static final String SECOND_SIGNATURE = 65 "3082016d30820113a0030201020209008855bd1dd2b2b225300a06082a86" 66 + "48ce3d04030230123110300e06035504030c0765632d70323536301e170d" 67 + "3138303731333137343135315a170d3238303731303137343135315a3014" 68 + "3112301006035504030c0965632d703235365f323059301306072a8648ce" 69 + "3d020106082a8648ce3d030107034200041d4cca0472ad97ee3cecef0da9" 70 + "3d62b450c6788333b36e7553cde9f74ab5df00bbba6ba950e68461d70bbc" 71 + "271b62151dad2de2bf6203cd2076801c7a9d4422e1a350304e301d060355" 72 + "1d0e041604147991d92b0208fc448bf506d4efc9fff428cb5e5f301f0603" 73 + "551d23041830168014d4133568b95b30158b322071ea8c43ff5b05ccc830" 74 + "0c0603551d13040530030101ff300a06082a8648ce3d0403020348003045" 75 + "02202769abb1b49fc2f53479c4ae92a6631dabfd522c9acb0bba2b43ebeb" 76 + "99c63011022100d260fb1d1f176cf9b7fa60098bfd24319f4905a3e5fda1" 77 + "00a6fe1a2ab19ff09e"; 78 private static final String THIRD_SIGNATURE = 79 "3082016e30820115a0030201020209008394f5cad16a89a7300a06082a86" 80 + "48ce3d04030230143112301006035504030c0965632d703235365f32301e" 81 + "170d3138303731343030303532365a170d3238303731313030303532365a" 82 + "30143112301006035504030c0965632d703235365f333059301306072a86" 83 + "48ce3d020106082a8648ce3d03010703420004f31e62430e9db6fc5928d9" 84 + "75fc4e47419bacfcb2e07c89299e6cd7e344dd21adfd308d58cb49a1a2a3" 85 + "fecacceea4862069f30be1643bcc255040d8089dfb3743a350304e301d06" 86 + "03551d0e041604146f8d0828b13efaf577fc86b0e99fa3e54bcbcff0301f" 87 + "0603551d230418301680147991d92b0208fc448bf506d4efc9fff428cb5e" 88 + "5f300c0603551d13040530030101ff300a06082a8648ce3d040302034700" 89 + "30440220256bdaa2784c273e4cc291a595a46779dee9de9044dc9f7ab820" 90 + "309567df9fe902201a4ad8c69891b5a8c47434fe9540ed1f4979b5fad348" 91 + "3f3fa04d5677355a579e"; 92 private static final String FOURTH_SIGNATURE = 93 "3082017b30820120a00302010202146c8cb8a818433c1e6431fb16fb3ae0" 94 + "fb5ad60aa7300a06082a8648ce3d04030230143112301006035504030c09" 95 + "65632d703235365f33301e170d3230303531333139313532385a170d3330" 96 + "303531313139313532385a30143112301006035504030c0965632d703235" 97 + "365f343059301306072a8648ce3d020106082a8648ce3d03010703420004" 98 + "db4a60031e79ad49cb759007d6855d4469b91c8bab065434f2fba971ade7" 99 + "e4d19599a0f67b5e708cfda7543e5630c3769d37e093640d7c768a15144c" 100 + "d0e5dcf4a350304e301d0603551d0e041604146e78970332554336b6ee89" 101 + "24eaa70230e393f678301f0603551d230418301680146f8d0828b13efaf5" 102 + "77fc86b0e99fa3e54bcbcff0300c0603551d13040530030101ff300a0608" 103 + "2a8648ce3d0403020349003046022100ce786e79ec7547446082e9caf910" 104 + "614ff80758f9819fb0f148695067abe0fcd4022100a4881e332ddec2116a" 105 + "d2b59cf891d0f331ff7e27e77b7c6206c7988d9b539330"; 106 107 @Test hasAncestor_multipleSignersInLineageWithAncestor_returnsTrue()108 public void hasAncestor_multipleSignersInLineageWithAncestor_returnsTrue() throws Exception { 109 SigningDetails twoSignersInLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 110 SECOND_SIGNATURE, THIRD_SIGNATURE); 111 SigningDetails oneSignerInLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 112 SECOND_SIGNATURE); 113 114 boolean result = twoSignersInLineageDetails.hasAncestor(oneSignerInLineageDetails); 115 116 assertTrue(result); 117 } 118 119 @Test hasAncestor_oneSignerInLineageAgainstMultipleSignersInLineage_returnsFalse()120 public void hasAncestor_oneSignerInLineageAgainstMultipleSignersInLineage_returnsFalse() 121 throws Exception { 122 SigningDetails twoSignersInLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 123 SECOND_SIGNATURE, THIRD_SIGNATURE); 124 SigningDetails oneSignerInLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 125 SECOND_SIGNATURE); 126 127 boolean result = oneSignerInLineageDetails.hasAncestor(twoSignersInLineageDetails); 128 129 assertFalse(result); 130 } 131 132 @Test hasAncestor_multipleSignersInLineageAgainstSelf_returnsFalse()133 public void hasAncestor_multipleSignersInLineageAgainstSelf_returnsFalse() throws Exception { 134 SigningDetails twoSignersInLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 135 SECOND_SIGNATURE, THIRD_SIGNATURE); 136 137 boolean result = twoSignersInLineageDetails.hasAncestor(twoSignersInLineageDetails); 138 139 assertFalse(result); 140 } 141 142 @Test hasAncestor_oneSignerInLineageWithAncestor_returnsTrue()143 public void hasAncestor_oneSignerInLineageWithAncestor_returnsTrue() throws Exception { 144 SigningDetails twoSignersInLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 145 SECOND_SIGNATURE, THIRD_SIGNATURE); 146 SigningDetails oneSignerDetails = createSigningDetails(FIRST_SIGNATURE); 147 148 boolean result = twoSignersInLineageDetails.hasAncestor(oneSignerDetails); 149 150 assertTrue(result); 151 } 152 153 @Test hasAncestor_singleSignerAgainstLineage_returnsFalse()154 public void hasAncestor_singleSignerAgainstLineage_returnsFalse() throws Exception { 155 SigningDetails oneSignerDetails = createSigningDetails(FIRST_SIGNATURE); 156 SigningDetails twoSignersInLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 157 SECOND_SIGNATURE, THIRD_SIGNATURE); 158 159 boolean result = oneSignerDetails.hasAncestor(twoSignersInLineageDetails); 160 161 assertFalse(result); 162 } 163 164 @Test hasAncestor_multipleSigners_returnsFalse()165 public void hasAncestor_multipleSigners_returnsFalse() throws Exception { 166 SigningDetails twoSignersDetails = createSigningDetails(FIRST_SIGNATURE, SECOND_SIGNATURE); 167 SigningDetails twoSignersInLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 168 SECOND_SIGNATURE, THIRD_SIGNATURE); 169 170 boolean result1 = twoSignersInLineageDetails.hasAncestor(twoSignersDetails); 171 boolean result2 = twoSignersDetails.hasAncestor(twoSignersInLineageDetails); 172 173 assertFalse(result1); 174 assertFalse(result2); 175 } 176 177 @Test hasAncestor_unknownDetails_returnsFalse()178 public void hasAncestor_unknownDetails_returnsFalse() throws Exception { 179 SigningDetails unknownDetails = SigningDetails.UNKNOWN; 180 SigningDetails twoSignersInLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 181 SECOND_SIGNATURE, THIRD_SIGNATURE); 182 183 boolean result1 = twoSignersInLineageDetails.hasAncestor(unknownDetails); 184 boolean result2 = unknownDetails.hasAncestor(twoSignersInLineageDetails); 185 186 assertFalse(result1); 187 assertFalse(result2); 188 } 189 190 @Test mergeLineageWith_neitherHasLineage_returnsOriginal()191 public void mergeLineageWith_neitherHasLineage_returnsOriginal() throws Exception { 192 // When attempting to merge two instances of SigningDetails that do not have a lineage the 193 // initial object should be returned to indicate no changes were made. 194 SigningDetails noLineageDetails = createSigningDetails(FIRST_SIGNATURE); 195 SigningDetails otherNoLineageDetails = createSigningDetails(FIRST_SIGNATURE); 196 197 SigningDetails result1 = noLineageDetails.mergeLineageWith(otherNoLineageDetails); 198 SigningDetails result2 = otherNoLineageDetails.mergeLineageWith(noLineageDetails); 199 200 assertTrue(result1 == noLineageDetails); 201 assertTrue(result2 == otherNoLineageDetails); 202 } 203 204 @Test mergeLineageWith_oneHasNoLineage_returnsOther()205 public void mergeLineageWith_oneHasNoLineage_returnsOther() throws Exception { 206 // When attempting to merge a SigningDetails with no lineage with another that has a 207 // lineage and is a descendant the descendant SigningDetails with lineage should be returned 208 SigningDetails noLineageDetails = createSigningDetails(FIRST_SIGNATURE); 209 SigningDetails lineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 210 SECOND_SIGNATURE); 211 212 SigningDetails result1 = noLineageDetails.mergeLineageWith(lineageDetails); 213 SigningDetails result2 = lineageDetails.mergeLineageWith(noLineageDetails); 214 215 assertSigningDetailsContainsLineage(result1, FIRST_SIGNATURE, SECOND_SIGNATURE); 216 assertSigningDetailsContainsLineage(result2, FIRST_SIGNATURE, SECOND_SIGNATURE); 217 } 218 219 @Test mergeLineageWith_bothHaveSameLineage_returnsOriginal()220 public void mergeLineageWith_bothHaveSameLineage_returnsOriginal() throws Exception { 221 // If twoSigningDetails instances have the exact same lineage with the same capabilities 222 // then the original instance should be returned without modification. 223 SigningDetails firstLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 224 SECOND_SIGNATURE); 225 SigningDetails secondLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 226 SECOND_SIGNATURE); 227 228 SigningDetails result1 = firstLineageDetails.mergeLineageWith(secondLineageDetails); 229 SigningDetails result2 = secondLineageDetails.mergeLineageWith(firstLineageDetails); 230 231 assertTrue(result1 == firstLineageDetails); 232 assertTrue(result2 == secondLineageDetails); 233 } 234 235 @Test mergeLineageWith_oneIsAncestorWithoutLineage_returnsDescendant()236 public void mergeLineageWith_oneIsAncestorWithoutLineage_returnsDescendant() throws Exception { 237 // If one instance without a lineage is an ancestor of the other then the descendant should 238 // be returned. 239 SigningDetails ancestorDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE); 240 SigningDetails descendantDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 241 SECOND_SIGNATURE); 242 243 SigningDetails result1 = ancestorDetails.mergeLineageWith(descendantDetails); 244 SigningDetails result2 = descendantDetails.mergeLineageWith(ancestorDetails); 245 246 assertEquals(descendantDetails, result1); 247 assertTrue(result2 == descendantDetails); 248 } 249 250 @Test mergeLineageWith_oneIsAncestorWithLineage_returnsDescendant()251 public void mergeLineageWith_oneIsAncestorWithLineage_returnsDescendant() throws Exception { 252 // Similar to the above test if one instance with a lineage is an ancestor of the other then 253 // the descendant should be returned. 254 SigningDetails ancestorDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 255 SECOND_SIGNATURE); 256 SigningDetails descendantDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 257 SECOND_SIGNATURE, THIRD_SIGNATURE); 258 259 SigningDetails result1 = ancestorDetails.mergeLineageWith(descendantDetails); 260 SigningDetails result2 = descendantDetails.mergeLineageWith(ancestorDetails); 261 262 assertEquals(descendantDetails, result1); 263 assertTrue(result2 == descendantDetails); 264 } 265 266 @Test mergeLineageWith_singleSignerInMiddleOfLineage_returnsFullLineage()267 public void mergeLineageWith_singleSignerInMiddleOfLineage_returnsFullLineage() 268 throws Exception { 269 // If one instance without a lineage is an ancestor in the middle of the lineage for the 270 // descendant the descendant should be returned. 271 SigningDetails singleSignerDetails = createSigningDetails(SECOND_SIGNATURE); 272 SigningDetails fullLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 273 SECOND_SIGNATURE, THIRD_SIGNATURE); 274 275 SigningDetails result1 = singleSignerDetails.mergeLineageWith(fullLineageDetails); 276 SigningDetails result2 = fullLineageDetails.mergeLineageWith(singleSignerDetails); 277 278 assertSigningDetailsContainsLineage(result1, FIRST_SIGNATURE, SECOND_SIGNATURE, 279 THIRD_SIGNATURE); 280 assertSigningDetailsContainsLineage(result2, FIRST_SIGNATURE, SECOND_SIGNATURE, 281 THIRD_SIGNATURE); 282 } 283 284 @Test mergeLineageWith_noCommonLineage_returnsOriginal()285 public void mergeLineageWith_noCommonLineage_returnsOriginal() throws Exception { 286 // While a call should never be made to merge two lineages without a common ancestor if it 287 // is attempted the original lineage should be returned. 288 SigningDetails firstLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 289 SECOND_SIGNATURE); 290 SigningDetails secondLineageDetails = createSigningDetailsWithLineage(THIRD_SIGNATURE, 291 FOURTH_SIGNATURE); 292 293 SigningDetails result1 = firstLineageDetails.mergeLineageWith(secondLineageDetails); 294 SigningDetails result2 = secondLineageDetails.mergeLineageWith(firstLineageDetails); 295 296 assertTrue(result1 == firstLineageDetails); 297 assertTrue(result2 == secondLineageDetails); 298 } 299 300 @Test mergeLineageWith_bothPartialLineages_returnsFullLineage()301 public void mergeLineageWith_bothPartialLineages_returnsFullLineage() throws Exception { 302 // This test verifies the following scenario: 303 // - One package is signed with a rotated key B and linage A -> B 304 // - The other package is signed with a rotated key C and lineage B -> C 305 // Merging the lineage of these two should return the full lineage A -> B -> C 306 SigningDetails firstLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 307 SECOND_SIGNATURE); 308 SigningDetails secondLineageDetails = createSigningDetailsWithLineage(SECOND_SIGNATURE, 309 THIRD_SIGNATURE); 310 SigningDetails expectedDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 311 SECOND_SIGNATURE, THIRD_SIGNATURE); 312 313 SigningDetails result1 = firstLineageDetails.mergeLineageWith(secondLineageDetails); 314 SigningDetails result2 = secondLineageDetails.mergeLineageWith(firstLineageDetails); 315 316 assertEquals(expectedDetails, result1); 317 assertEquals(expectedDetails, result2); 318 } 319 320 @Test mergeLineageWith_oneSubsetLineage_returnsFullLineage()321 public void mergeLineageWith_oneSubsetLineage_returnsFullLineage() throws Exception { 322 // This test verifies when one lineage is a subset of the other the full lineage is 323 // returned. 324 SigningDetails subsetLineageDetails = createSigningDetailsWithLineage(SECOND_SIGNATURE, 325 THIRD_SIGNATURE); 326 SigningDetails fullLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 327 SECOND_SIGNATURE, THIRD_SIGNATURE, FOURTH_SIGNATURE); 328 329 SigningDetails result1 = subsetLineageDetails.mergeLineageWith(fullLineageDetails); 330 SigningDetails result2 = fullLineageDetails.mergeLineageWith(subsetLineageDetails); 331 332 assertEquals(fullLineageDetails, result1); 333 assertTrue(result2 == fullLineageDetails); 334 } 335 336 @Test mergeLineageWith_differentRootsOfTrust_returnsOriginal()337 public void mergeLineageWith_differentRootsOfTrust_returnsOriginal() throws Exception { 338 // If two SigningDetails share a common lineage but diverge at one of the ancestors then the 339 // merge should return the invoking instance since this is not supported. 340 SigningDetails firstLineageDetails = createSigningDetailsWithLineage("1234", 341 FIRST_SIGNATURE, SECOND_SIGNATURE); 342 SigningDetails secondLineageDetails = createSigningDetailsWithLineage("5678", 343 FIRST_SIGNATURE, SECOND_SIGNATURE, THIRD_SIGNATURE); 344 345 SigningDetails result1 = firstLineageDetails.mergeLineageWith(secondLineageDetails); 346 SigningDetails result2 = secondLineageDetails.mergeLineageWith(firstLineageDetails); 347 348 assertTrue(result1 == firstLineageDetails); 349 assertTrue(result2 == secondLineageDetails); 350 } 351 352 @Test mergeLineageWith_divergedSignerInLineage_returnsOriginal()353 public void mergeLineageWith_divergedSignerInLineage_returnsOriginal() throws Exception { 354 // Similar to the test above if two lineages diverge at any point then the merge should 355 // return the original since the signers in a sharedUserId must always be either the same, 356 // a subset, or a superset of the existing lineage. 357 SigningDetails firstLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 358 "1234", SECOND_SIGNATURE, THIRD_SIGNATURE); 359 SigningDetails secondLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 360 "5678", SECOND_SIGNATURE, THIRD_SIGNATURE); 361 362 SigningDetails result1 = firstLineageDetails.mergeLineageWith(secondLineageDetails); 363 SigningDetails result2 = secondLineageDetails.mergeLineageWith(firstLineageDetails); 364 365 assertTrue(result1 == firstLineageDetails); 366 assertTrue(result2 == secondLineageDetails); 367 } 368 369 @Test mergeLineageWith_sameLineageDifferentCaps_returnsLineageWithModifiedCaps()370 public void mergeLineageWith_sameLineageDifferentCaps_returnsLineageWithModifiedCaps() 371 throws Exception { 372 // This test verifies when two lineages consist of the same signers but have different 373 // capabilities the more restrictive capabilities are returned. 374 SigningDetails defaultCapabilitiesDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 375 SECOND_SIGNATURE, THIRD_SIGNATURE); 376 SigningDetails modifiedCapabilitiesDetails = createSigningDetailsWithLineageAndCapabilities( 377 new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE, THIRD_SIGNATURE}, 378 new int[]{INSTALLED_DATA, INSTALLED_DATA, INSTALLED_DATA}); 379 380 SigningDetails result1 = defaultCapabilitiesDetails.mergeLineageWith( 381 modifiedCapabilitiesDetails); 382 SigningDetails result2 = modifiedCapabilitiesDetails.mergeLineageWith( 383 defaultCapabilitiesDetails); 384 385 assertEquals(modifiedCapabilitiesDetails, result1); 386 assertTrue(result2 == modifiedCapabilitiesDetails); 387 } 388 389 @Test mergeLineageWith_overlappingLineageDiffCaps_returnsFullLineageWithModifiedCaps()390 public void mergeLineageWith_overlappingLineageDiffCaps_returnsFullLineageWithModifiedCaps() 391 throws Exception { 392 // This test verifies the following scenario: 393 // - First lineage has signers A -> B with modified capabilities for A and B 394 // - Second lineage has signers B -> C with modified capabilities for B and C 395 // The merged lineage should be A -> B -> C with the most restrictive capabilities for B 396 // since it is in both lineages. 397 int[] firstCapabilities = 398 new int[]{INSTALLED_DATA | AUTH, INSTALLED_DATA | SHARED_USER_ID | PERMISSION}; 399 int[] secondCapabilities = new int[]{INSTALLED_DATA | SHARED_USER_ID | AUTH, 400 INSTALLED_DATA | SHARED_USER_ID | AUTH}; 401 int[] expectedCapabilities = 402 new int[]{firstCapabilities[0], firstCapabilities[1] & secondCapabilities[0], 403 secondCapabilities[1]}; 404 SigningDetails firstDetails = createSigningDetailsWithLineageAndCapabilities( 405 new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE}, firstCapabilities); 406 SigningDetails secondDetails = createSigningDetailsWithLineageAndCapabilities( 407 new String[]{SECOND_SIGNATURE, THIRD_SIGNATURE}, secondCapabilities); 408 SigningDetails expectedDetails = createSigningDetailsWithLineageAndCapabilities( 409 new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE, THIRD_SIGNATURE}, 410 expectedCapabilities); 411 412 SigningDetails result1 = firstDetails.mergeLineageWith(secondDetails); 413 SigningDetails result2 = secondDetails.mergeLineageWith(firstDetails); 414 415 assertEquals(expectedDetails, result1); 416 assertEquals(expectedDetails, result2); 417 } 418 419 @Test mergeLineageWith_subLineageModifiedCaps_returnsFullLineageWithModifiedCaps()420 public void mergeLineageWith_subLineageModifiedCaps_returnsFullLineageWithModifiedCaps() 421 throws Exception { 422 // This test verifies the following scenario: 423 // - First lineage has signers B -> C with modified capabilities 424 // - Second lineage has signers A -> B -> C -> D with modified capabilities 425 // The merged lineage should be A -> B -> C -> D with the most restrictive capabilities for 426 // B and C since they are in both lineages. 427 int[] subCapabilities = new int[]{INSTALLED_DATA | SHARED_USER_ID | PERMISSION, 428 DEFAULT_CAPABILITIES | ROLLBACK}; 429 int[] fullCapabilities = 430 new int[]{0, SHARED_USER_ID, DEFAULT_CAPABILITIES, DEFAULT_CAPABILITIES}; 431 int[] expectedCapabilities = 432 new int[]{fullCapabilities[0], subCapabilities[0] & fullCapabilities[1], 433 subCapabilities[1] & fullCapabilities[2], fullCapabilities[3]}; 434 SigningDetails subLineageDetails = createSigningDetailsWithLineageAndCapabilities( 435 new String[]{SECOND_SIGNATURE, THIRD_SIGNATURE}, subCapabilities); 436 SigningDetails fullLineageDetails = createSigningDetailsWithLineageAndCapabilities( 437 new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE, THIRD_SIGNATURE, FOURTH_SIGNATURE}, 438 fullCapabilities); 439 SigningDetails expectedDetails = createSigningDetailsWithLineageAndCapabilities( 440 new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE, THIRD_SIGNATURE, FOURTH_SIGNATURE}, 441 expectedCapabilities); 442 443 SigningDetails result1 = subLineageDetails.mergeLineageWith(fullLineageDetails); 444 SigningDetails result2 = fullLineageDetails.mergeLineageWith(subLineageDetails); 445 446 assertEquals(expectedDetails, result1); 447 assertEquals(expectedDetails, result2); 448 } 449 450 @Test mergeLineageWith_commonLineageDivergedSigners_returnsOriginal()451 public void mergeLineageWith_commonLineageDivergedSigners_returnsOriginal() throws Exception { 452 // When mergeWithLineage is invoked with SigningDetails instances that have a common lineage 453 // but diverged signers the calling instance should be returned since the current signer 454 // is not in the ancestry of the other's lineage. 455 SigningDetails firstLineageDetails = createSigningDetails(FIRST_SIGNATURE, SECOND_SIGNATURE, 456 THIRD_SIGNATURE); 457 SigningDetails secondLineageDetails = createSigningDetails(FIRST_SIGNATURE, 458 SECOND_SIGNATURE, FOURTH_SIGNATURE); 459 460 SigningDetails result1 = firstLineageDetails.mergeLineageWith(secondLineageDetails); 461 SigningDetails result2 = secondLineageDetails.mergeLineageWith(firstLineageDetails); 462 463 assertTrue(result1 == firstLineageDetails); 464 assertTrue(result2 == secondLineageDetails); 465 } 466 467 @Test hasCommonAncestor_noLineageSameSingleSigner_returnsTrue()468 public void hasCommonAncestor_noLineageSameSingleSigner_returnsTrue() throws Exception { 469 // If neither SigningDetails have a lineage but they have the same single signer then 470 // hasCommonAncestor should return true. 471 SigningDetails firstDetails = createSigningDetails(FIRST_SIGNATURE); 472 SigningDetails secondDetails = createSigningDetails(FIRST_SIGNATURE); 473 474 assertTrue(firstDetails.hasCommonAncestor(secondDetails)); 475 assertTrue(secondDetails.hasCommonAncestor(firstDetails)); 476 } 477 478 @Test hasCommonAncestor_noLineageSameMultipleSigners_returnsTrue()479 public void hasCommonAncestor_noLineageSameMultipleSigners_returnsTrue() throws Exception { 480 // Similar to above if neither SigningDetails have a lineage but they have the same multiple 481 // signers then hasCommonAncestor should return true. 482 SigningDetails firstDetails = createSigningDetails(FIRST_SIGNATURE, SECOND_SIGNATURE); 483 SigningDetails secondDetails = createSigningDetails(SECOND_SIGNATURE, FIRST_SIGNATURE); 484 485 assertTrue(firstDetails.hasCommonAncestor(secondDetails)); 486 assertTrue(secondDetails.hasCommonAncestor(firstDetails)); 487 } 488 489 @Test hasCommonAncestor_noLineageDifferentSigners_returnsFalse()490 public void hasCommonAncestor_noLineageDifferentSigners_returnsFalse() throws Exception { 491 // If neither SigningDetails have a lineage and they have different signers then 492 // hasCommonAncestor should return false. 493 SigningDetails firstDetails = createSigningDetails(FIRST_SIGNATURE); 494 SigningDetails secondDetails = createSigningDetails(SECOND_SIGNATURE); 495 SigningDetails thirdDetails = createSigningDetails(FIRST_SIGNATURE, SECOND_SIGNATURE); 496 SigningDetails fourthDetails = createSigningDetails(SECOND_SIGNATURE, THIRD_SIGNATURE); 497 498 assertFalse(firstDetails.hasCommonAncestor(secondDetails)); 499 assertFalse(firstDetails.hasCommonAncestor(thirdDetails)); 500 assertFalse(firstDetails.hasCommonAncestor(fourthDetails)); 501 assertFalse(secondDetails.hasCommonAncestor(firstDetails)); 502 assertFalse(secondDetails.hasCommonAncestor(thirdDetails)); 503 assertFalse(secondDetails.hasCommonAncestor(fourthDetails)); 504 assertFalse(thirdDetails.hasCommonAncestor(firstDetails)); 505 assertFalse(thirdDetails.hasCommonAncestor(secondDetails)); 506 assertFalse(thirdDetails.hasCommonAncestor(fourthDetails)); 507 assertFalse(fourthDetails.hasCommonAncestor(firstDetails)); 508 assertFalse(fourthDetails.hasCommonAncestor(secondDetails)); 509 assertFalse(fourthDetails.hasCommonAncestor(thirdDetails)); 510 } 511 512 @Test hasCommonAncestor_oneWithOthersSignerInLineage_returnsTrue()513 public void hasCommonAncestor_oneWithOthersSignerInLineage_returnsTrue() throws Exception { 514 // If only one of the SigningDetails has a lineage and the current signer of the other is in 515 // the lineage then hasCommonAncestor should return true. 516 SigningDetails noLineageDetails = createSigningDetails(FIRST_SIGNATURE); 517 SigningDetails lineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 518 SECOND_SIGNATURE); 519 520 assertTrue(noLineageDetails.hasCommonAncestor(lineageDetails)); 521 assertTrue(lineageDetails.hasCommonAncestor(noLineageDetails)); 522 } 523 524 @Test hasCommonAncestor_oneWithSameSignerWithoutLineage_returnsTrue()525 public void hasCommonAncestor_oneWithSameSignerWithoutLineage_returnsTrue() throws Exception { 526 // If only one of the SigningDetails has a lineage and both have the same current signer 527 // then hasCommonAncestor should return true. 528 SigningDetails noLineageDetails = createSigningDetails(SECOND_SIGNATURE); 529 SigningDetails lineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 530 SECOND_SIGNATURE); 531 532 assertTrue(noLineageDetails.hasCommonAncestor(lineageDetails)); 533 assertTrue(lineageDetails.hasCommonAncestor(noLineageDetails)); 534 } 535 536 @Test hasCommonAncestor_bothHaveSameLineage_returnsTrue()537 public void hasCommonAncestor_bothHaveSameLineage_returnsTrue() throws Exception { 538 // If both SigningDetails have the exact same lineage then hasCommonAncestor should return 539 // true. 540 SigningDetails firstDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 541 SECOND_SIGNATURE); 542 SigningDetails secondDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 543 SECOND_SIGNATURE); 544 545 assertTrue(firstDetails.hasCommonAncestor(secondDetails)); 546 assertTrue(secondDetails.hasCommonAncestor(firstDetails)); 547 } 548 549 @Test hasCommonAncestor_oneLineageIsAncestor_returnsTrue()550 public void hasCommonAncestor_oneLineageIsAncestor_returnsTrue() throws Exception { 551 // If one SigningDetails has a lineage that is an ancestor of the other then 552 // hasCommonAncestor should return true. 553 SigningDetails ancestorDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 554 SECOND_SIGNATURE); 555 SigningDetails descendantDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 556 SECOND_SIGNATURE, THIRD_SIGNATURE); 557 558 assertTrue(ancestorDetails.hasCommonAncestor(descendantDetails)); 559 assertTrue(descendantDetails.hasCommonAncestor(ancestorDetails)); 560 } 561 562 @Test hasCommonAncestor_oneLineageIsSubset_returnsTrue()563 public void hasCommonAncestor_oneLineageIsSubset_returnsTrue() throws Exception { 564 // If one SigningDetails has a lineage that is a subset of the other then hasCommonAncestor 565 // should return true. 566 SigningDetails subsetDetails = createSigningDetailsWithLineage(SECOND_SIGNATURE, 567 THIRD_SIGNATURE); 568 SigningDetails fullDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 569 SECOND_SIGNATURE, THIRD_SIGNATURE, FOURTH_SIGNATURE); 570 571 assertTrue(subsetDetails.hasCommonAncestor(fullDetails)); 572 assertTrue(fullDetails.hasCommonAncestor(subsetDetails)); 573 } 574 575 @Test hasCommonAncestor_differentRootOfTrustInLineage_returnsFalse()576 public void hasCommonAncestor_differentRootOfTrustInLineage_returnsFalse() throws Exception { 577 // if the two SigningDetails have a different root of trust then hasCommonAncestor should 578 // return false. 579 SigningDetails firstDetails = createSigningDetailsWithLineage(THIRD_SIGNATURE, 580 FIRST_SIGNATURE, SECOND_SIGNATURE); 581 SigningDetails secondDetails = createSigningDetailsWithLineage(FOURTH_SIGNATURE, 582 FIRST_SIGNATURE, SECOND_SIGNATURE); 583 584 assertFalse(firstDetails.hasCommonAncestor(secondDetails)); 585 assertFalse(secondDetails.hasCommonAncestor(firstDetails)); 586 } 587 588 @Test hasCommonAncestor_differentSignerInMiddleOfLineage_returnsFalse()589 public void hasCommonAncestor_differentSignerInMiddleOfLineage_returnsFalse() throws Exception { 590 // if the two SigningDetails have a different signer in the middle of a common lineage then 591 // hasCommonAncestor should return false. 592 SigningDetails firstDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, "1234", 593 SECOND_SIGNATURE, THIRD_SIGNATURE); 594 SigningDetails secondDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, "5678", 595 SECOND_SIGNATURE, THIRD_SIGNATURE); 596 597 assertFalse(firstDetails.hasCommonAncestor(secondDetails)); 598 assertFalse(secondDetails.hasCommonAncestor(firstDetails)); 599 } 600 601 @Test hasCommonAncestor_overlappingLineages_returnsTrue()602 public void hasCommonAncestor_overlappingLineages_returnsTrue() throws Exception { 603 // if the two SigningDetails have overlapping lineages then hasCommonAncestor should return 604 // true. 605 SigningDetails firstLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 606 SECOND_SIGNATURE); 607 SigningDetails secondLineageDetails = createSigningDetailsWithLineage(SECOND_SIGNATURE, 608 THIRD_SIGNATURE); 609 610 assertTrue(firstLineageDetails.hasCommonAncestor(secondLineageDetails)); 611 assertTrue(secondLineageDetails.hasCommonAncestor(firstLineageDetails)); 612 } 613 614 @Test hasCommonSignerWithCapabilities_singleMatchingSigner_returnsTrue()615 public void hasCommonSignerWithCapabilities_singleMatchingSigner_returnsTrue() 616 throws Exception { 617 // The hasCommonSignerWithCapabilities method is intended to grant the specified 618 // capabilities to a requesting package that has a common signer in the lineage (or as the 619 // current signer) even if their signing identities have diverged. This test verifies if the 620 // two SigningDetails have the same single signer then the requested capability can be 621 // granted since the current signer always has all capabilities granted. 622 SigningDetails firstDetails = createSigningDetails(FIRST_SIGNATURE); 623 SigningDetails secondSignerDetails = createSigningDetails(FIRST_SIGNATURE); 624 625 assertTrue(firstDetails.hasCommonSignerWithCapability(secondSignerDetails, PERMISSION)); 626 } 627 628 @Test hasCommonSignerWithCapabilities_singleDifferentSigners_returnsFalse()629 public void hasCommonSignerWithCapabilities_singleDifferentSigners_returnsFalse() 630 throws Exception { 631 // If each package is signed by a single different signer then the method should return 632 // false since there is no shared signer. 633 SigningDetails firstDetails = createSigningDetails(FIRST_SIGNATURE); 634 SigningDetails secondDetails = createSigningDetails(SECOND_SIGNATURE); 635 636 assertFalse(firstDetails.hasCommonSignerWithCapability(secondDetails, PERMISSION)); 637 assertFalse(secondDetails.hasCommonSignerWithCapability(firstDetails, PERMISSION)); 638 } 639 640 @Test hasCommonSignerWithCapabilities_oneWithMultipleSigners_returnsFalse()641 public void hasCommonSignerWithCapabilities_oneWithMultipleSigners_returnsFalse() 642 throws Exception { 643 // If one of the packages is signed with multiple signers and the other only a single signer 644 // this method should return false since all signers must match exactly for multiple signer 645 // cases. 646 SigningDetails firstDetails = createSigningDetails(FIRST_SIGNATURE, SECOND_SIGNATURE); 647 SigningDetails secondDetails = createSigningDetails(FIRST_SIGNATURE); 648 649 assertFalse(firstDetails.hasCommonSignerWithCapability(secondDetails, PERMISSION)); 650 assertFalse(secondDetails.hasCommonSignerWithCapability(firstDetails, PERMISSION)); 651 } 652 653 @Test hasCommonSignerWithCapabilities_multipleMatchingSigners_returnsTrue()654 public void hasCommonSignerWithCapabilities_multipleMatchingSigners_returnsTrue() 655 throws Exception { 656 // if both packages are signed by the same multiple signers then this method should return 657 // true since the current signer is granted all capabilities. 658 SigningDetails firstDetails = createSigningDetails(FIRST_SIGNATURE, SECOND_SIGNATURE); 659 SigningDetails secondDetails = createSigningDetails(SECOND_SIGNATURE, FIRST_SIGNATURE); 660 661 assertTrue(firstDetails.hasCommonSignerWithCapability(secondDetails, PERMISSION)); 662 assertTrue(secondDetails.hasCommonSignerWithCapability(firstDetails, PERMISSION)); 663 } 664 665 @Test hasCommonSignerWithCapabilities_singleSignerInLineage_returnsTrue()666 public void hasCommonSignerWithCapabilities_singleSignerInLineage_returnsTrue() 667 throws Exception { 668 // if a single signer is in the lineage and that previous signer has the requested 669 // capability then this method should return true. 670 SigningDetails lineageDetails = createSigningDetailsWithLineageAndCapabilities( 671 new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE}, 672 new int[]{DEFAULT_CAPABILITIES, DEFAULT_CAPABILITIES}); 673 SigningDetails singleSignerDetails = createSigningDetails(FIRST_SIGNATURE); 674 675 assertTrue(lineageDetails.hasCommonSignerWithCapability(singleSignerDetails, PERMISSION)); 676 } 677 678 @Test hasCommonSignerWithCapabilities_singleSignerInLineageWOCapability_returnsFalse()679 public void hasCommonSignerWithCapabilities_singleSignerInLineageWOCapability_returnsFalse() 680 throws Exception { 681 // If a single signer is in the lineage and that previous signer does not have the requested 682 // capability then this method should return false. 683 SigningDetails lineageDetails = createSigningDetailsWithLineageAndCapabilities( 684 new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE}, 685 new int[]{SHARED_USER_ID, DEFAULT_CAPABILITIES}); 686 SigningDetails singleSignerDetails = createSigningDetails(FIRST_SIGNATURE); 687 688 assertFalse(lineageDetails.hasCommonSignerWithCapability(singleSignerDetails, PERMISSION)); 689 } 690 691 @Test hasCommonSignerWithCapabilities_singleSignerMatchesCurrentSigner_returnsTrue()692 public void hasCommonSignerWithCapabilities_singleSignerMatchesCurrentSigner_returnsTrue() 693 throws Exception { 694 // If a requesting app is signed by the same current signer as an app with a lineage the 695 // method should return true since the current signer is granted all capabilities. 696 SigningDetails lineageDetails = createSigningDetailsWithLineageAndCapabilities( 697 new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE}, 698 new int[]{SHARED_USER_ID, DEFAULT_CAPABILITIES}); 699 SigningDetails singleSignerDetails = createSigningDetails(SECOND_SIGNATURE); 700 701 assertTrue(lineageDetails.hasCommonSignerWithCapability(singleSignerDetails, PERMISSION)); 702 } 703 704 @Test hasCommonSignerWithCapabilities_divergingSignersWithCommonSigner_returnsTrue()705 public void hasCommonSignerWithCapabilities_divergingSignersWithCommonSigner_returnsTrue() 706 throws Exception { 707 // This method is intended to allow granting a capability to another app that has a common 708 // signer in the lineage with the capability still granted; this test verifies when the 709 // current signers diverge but a common ancestor has the requested capability this method 710 // returns true. 711 SigningDetails firstLineageDetails = createSigningDetailsWithLineageAndCapabilities( 712 new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE, THIRD_SIGNATURE}, 713 new int[]{DEFAULT_CAPABILITIES, DEFAULT_CAPABILITIES, DEFAULT_CAPABILITIES}); 714 SigningDetails secondLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 715 SECOND_SIGNATURE, FOURTH_SIGNATURE); 716 717 assertTrue(firstLineageDetails.hasCommonSignerWithCapability(secondLineageDetails, 718 PERMISSION)); 719 } 720 721 @Test hasCommonSignerWithCapabilities_divergingSignersOneGrantsCapability_returnsTrue()722 public void hasCommonSignerWithCapabilities_divergingSignersOneGrantsCapability_returnsTrue() 723 throws Exception { 724 // If apps have multiple common signers in the lineage with one denying the requested 725 // capability but the other granting it this method should return true. 726 SigningDetails firstLineageDetails = createSigningDetailsWithLineageAndCapabilities( 727 new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE, THIRD_SIGNATURE}, 728 new int[]{SHARED_USER_ID, DEFAULT_CAPABILITIES, DEFAULT_CAPABILITIES}); 729 SigningDetails secondLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 730 SECOND_SIGNATURE, FOURTH_SIGNATURE); 731 732 assertTrue(firstLineageDetails.hasCommonSignerWithCapability(secondLineageDetails, 733 PERMISSION)); 734 } 735 736 @Test hasCommonSignerWithCapabilities_divergingSignersNoneGrantCapability_returnsFalse()737 public void hasCommonSignerWithCapabilities_divergingSignersNoneGrantCapability_returnsFalse() 738 throws Exception { 739 // If apps have multiple common signers in the lineage with all denying the requested 740 // capability this method should return false. 741 SigningDetails firstLineageDetails = createSigningDetailsWithLineageAndCapabilities( 742 new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE, THIRD_SIGNATURE}, 743 new int[]{SHARED_USER_ID, AUTH, DEFAULT_CAPABILITIES}); 744 SigningDetails secondLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 745 SECOND_SIGNATURE, FOURTH_SIGNATURE); 746 747 assertFalse(firstLineageDetails.hasCommonSignerWithCapability(secondLineageDetails, 748 PERMISSION)); 749 } 750 751 @Test 752 public void hasCommonSignerWithCapabilities_divergingSignersNoneGrantsAllCapabilities_returnsTrue()753 hasCommonSignerWithCapabilities_divergingSignersNoneGrantsAllCapabilities_returnsTrue() 754 throws Exception { 755 // If an app has multiple common signers in the lineage, each granting one of the requested 756 // capabilities but neither granting all this method should return false since a single 757 // common ancestor must grant all requested capabilities. 758 SigningDetails firstLineageDetails = createSigningDetailsWithLineageAndCapabilities( 759 new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE, THIRD_SIGNATURE}, 760 new int[]{SHARED_USER_ID, PERMISSION, DEFAULT_CAPABILITIES}); 761 SigningDetails secondLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 762 SECOND_SIGNATURE, FOURTH_SIGNATURE); 763 764 assertFalse(firstLineageDetails.hasCommonSignerWithCapability(secondLineageDetails, 765 PERMISSION | SHARED_USER_ID)); 766 } 767 768 @Test hasCommonSignerWithCapabilities_currentSignerInLineageOfRequestingApp_returnsTrue()769 public void hasCommonSignerWithCapabilities_currentSignerInLineageOfRequestingApp_returnsTrue() 770 throws Exception { 771 // If the current signer of an app is in the lineage of the requesting app then this method 772 // should return true since the current signer is granted all capabilities. 773 SigningDetails firstLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 774 SECOND_SIGNATURE); 775 SigningDetails secondLineageDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 776 SECOND_SIGNATURE, THIRD_SIGNATURE); 777 778 assertTrue(firstLineageDetails.hasCommonSignerWithCapability(secondLineageDetails, 779 PERMISSION)); 780 } 781 782 @Test hasCommonSignerWithCapabilities_currentSignerInLineageOfDeclaringApp_returnsTrue()783 public void hasCommonSignerWithCapabilities_currentSignerInLineageOfDeclaringApp_returnsTrue() 784 throws Exception { 785 // If the current signer of a requesting app with a lineage is in the lineage of the 786 // declaring app and that previous signature is granted the requested capability the method 787 // should return true. 788 SigningDetails declaringDetails = createSigningDetailsWithLineageAndCapabilities( 789 new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE, THIRD_SIGNATURE}, 790 new int[]{SHARED_USER_ID, DEFAULT_CAPABILITIES, DEFAULT_CAPABILITIES}); 791 SigningDetails requestingDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE, 792 SECOND_SIGNATURE); 793 794 assertTrue(declaringDetails.hasCommonSignerWithCapability(requestingDetails, PERMISSION)); 795 } 796 797 @Test hasCommonSignerWithCapabilities_oneSignerNullLineage_returns()798 public void hasCommonSignerWithCapabilities_oneSignerNullLineage_returns() throws Exception { 799 // While the pastSigningCertificates should only be null in the case of multiple current 800 // signers there are instances where this can be null with a single signer; verify that a 801 // null pastSigningCertificates array in either SigningDetails does not result in a 802 // NullPointerException. 803 SigningDetails firstDetails = createSigningDetails(true, FIRST_SIGNATURE); 804 SigningDetails secondDetails = createSigningDetails(SECOND_SIGNATURE); 805 806 assertFalse(firstDetails.hasCommonSignerWithCapability(secondDetails, PERMISSION)); 807 assertFalse(secondDetails.hasCommonSignerWithCapability(firstDetails, PERMISSION)); 808 } 809 810 @Test hasCommonSignerWithCapabilities_unknownSigner_returnsFalse()811 public void hasCommonSignerWithCapabilities_unknownSigner_returnsFalse() throws Exception { 812 // An unknown SigningDetails for either instance should immediately result in false being 813 // returned. 814 SigningDetails firstDetails = SigningDetails.UNKNOWN; 815 SigningDetails secondDetails = createSigningDetails(FIRST_SIGNATURE); 816 817 assertFalse(firstDetails.hasCommonSignerWithCapability(secondDetails, PERMISSION)); 818 assertFalse(secondDetails.hasCommonSignerWithCapability(firstDetails, PERMISSION)); 819 } 820 821 @Test hasAncestorOrSelfWithDigest_nullSet_returnsFalse()822 public void hasAncestorOrSelfWithDigest_nullSet_returnsFalse() throws Exception { 823 // The hasAncestorOrSelfWithDigest method is intended to verify whether the SigningDetails 824 // is currently signed, or has previously been signed, by any of the certificate digests 825 // in the provided Set. This test verifies if a null Set is provided then false is returned. 826 SigningDetails details = createSigningDetails(FIRST_SIGNATURE); 827 828 assertFalse(details.hasAncestorOrSelfWithDigest(null)); 829 } 830 831 @Test hasAncestorOrSelfWithDigest_unknownDetails_returnsFalse()832 public void hasAncestorOrSelfWithDigest_unknownDetails_returnsFalse() throws Exception { 833 // If hasAncestorOrSelfWithDigest is invoked against an UNKNOWN 834 // instance of the SigningDetails then false is returned. 835 SigningDetails details = SigningDetails.UNKNOWN; 836 Set<String> digests = createDigestSet(FIRST_SIGNATURE); 837 838 assertFalse(details.hasAncestorOrSelfWithDigest(digests)); 839 } 840 841 @Test hasAncestorOrSelfWithDigest_singleSignerInSet_returnsTrue()842 public void hasAncestorOrSelfWithDigest_singleSignerInSet_returnsTrue() throws Exception { 843 // If the single signer of an app is in the provided digest Set then 844 // the method should return true. 845 SigningDetails details = createSigningDetails(FIRST_SIGNATURE); 846 Set<String> digests = createDigestSet(FIRST_SIGNATURE, SECOND_SIGNATURE); 847 848 assertTrue(details.hasAncestorOrSelfWithDigest(digests)); 849 } 850 851 @Test hasAncestorOrSelfWithDigest_singleSignerNotInSet_returnsFalse()852 public void hasAncestorOrSelfWithDigest_singleSignerNotInSet_returnsFalse() throws Exception { 853 // If the single signer of an app is not in the provided digest Set then 854 // the method should return false. 855 SigningDetails details = createSigningDetails(FIRST_SIGNATURE); 856 Set<String> digests = createDigestSet(SECOND_SIGNATURE, THIRD_SIGNATURE); 857 858 assertFalse(details.hasAncestorOrSelfWithDigest(digests)); 859 } 860 861 @Test hasAncestorOrSelfWithDigest_multipleSignersInSet_returnsTrue()862 public void hasAncestorOrSelfWithDigest_multipleSignersInSet_returnsTrue() throws Exception { 863 // If an app is signed by multiple signers and all of the signers are in 864 // the digest Set then the method should return true. 865 SigningDetails details = createSigningDetails(FIRST_SIGNATURE, SECOND_SIGNATURE); 866 Set<String> digests = createDigestSet(FIRST_SIGNATURE, SECOND_SIGNATURE, THIRD_SIGNATURE); 867 868 assertTrue(details.hasAncestorOrSelfWithDigest(digests)); 869 } 870 871 @Test hasAncestorOrSelfWithDigest_multipleSignersNotInSet_returnsFalse()872 public void hasAncestorOrSelfWithDigest_multipleSignersNotInSet_returnsFalse() 873 throws Exception { 874 // If an app is signed by multiple signers then all signers must be in the digest Set; if 875 // only a subset of the signers are in the Set then the method should return false. 876 SigningDetails details = createSigningDetails(FIRST_SIGNATURE, SECOND_SIGNATURE); 877 Set<String> digests = createDigestSet(FIRST_SIGNATURE, THIRD_SIGNATURE); 878 879 assertFalse(details.hasAncestorOrSelfWithDigest(digests)); 880 } 881 882 @Test hasAncestorOrSelfWithDigest_multipleSignersOneInSet_returnsFalse()883 public void hasAncestorOrSelfWithDigest_multipleSignersOneInSet_returnsFalse() 884 throws Exception { 885 // If an app is signed by multiple signers and the Set size is smaller than the number of 886 // signers then the method should immediately return false since there's no way for the 887 // requirement of all signers in the Set to be met. 888 SigningDetails details = createSigningDetails(FIRST_SIGNATURE, SECOND_SIGNATURE); 889 Set<String> digests = createDigestSet(FIRST_SIGNATURE); 890 891 assertFalse(details.hasAncestorOrSelfWithDigest(digests)); 892 } 893 894 @Test hasAncestorOrSelfWithDigest_lineageSignerInSet_returnsTrue()895 public void hasAncestorOrSelfWithDigest_lineageSignerInSet_returnsTrue() throws Exception { 896 // If an app has a rotated signing key and a previous key in the lineage is in the digest 897 // Set then this method should return true. 898 SigningDetails details = createSigningDetailsWithLineage(FIRST_SIGNATURE, SECOND_SIGNATURE); 899 Set<String> digests = createDigestSet(FIRST_SIGNATURE, THIRD_SIGNATURE); 900 901 assertTrue(details.hasAncestorOrSelfWithDigest(digests)); 902 } 903 904 @Test hasAncestorOrSelfWithDigest_lineageSignerNotInSet_returnsFalse()905 public void hasAncestorOrSelfWithDigest_lineageSignerNotInSet_returnsFalse() throws Exception { 906 // If an app has a rotated signing key, but neither the current key nor any of the signers 907 // in the lineage are in the digest set then the method should return false. 908 SigningDetails details = createSigningDetailsWithLineage(FIRST_SIGNATURE, SECOND_SIGNATURE); 909 Set<String> digests = createDigestSet(THIRD_SIGNATURE, FOURTH_SIGNATURE); 910 911 assertFalse(details.hasAncestorOrSelfWithDigest(digests)); 912 } 913 914 @Test hasAncestorOrSelfWithDigest_lastSignerInLineageInSet_returnsTrue()915 public void hasAncestorOrSelfWithDigest_lastSignerInLineageInSet_returnsTrue() 916 throws Exception { 917 // If an app has multiple signers in the lineage only one of those signers must be in the 918 // Set for this method to return true. This test verifies if the last signer in the lineage 919 // is in the set then the method returns true. 920 SigningDetails details = createSigningDetailsWithLineage(FIRST_SIGNATURE, SECOND_SIGNATURE, 921 THIRD_SIGNATURE); 922 Set<String> digests = createDigestSet(SECOND_SIGNATURE); 923 924 assertTrue(details.hasAncestorOrSelfWithDigest(digests)); 925 } 926 927 @Test hasAncestorOrSelfWithDigest_nullLineageSingleSIgner_returnsFalse()928 public void hasAncestorOrSelfWithDigest_nullLineageSingleSIgner_returnsFalse() 929 throws Exception { 930 // Under some instances an app with only a single signer can have a null lineage; this 931 // test verifies that null lineage does not result in a NullPointerException and instead the 932 // method returns false if the single signer is not in the Set. 933 SigningDetails details = createSigningDetails(true, FIRST_SIGNATURE); 934 Set<String> digests = createDigestSet(SECOND_SIGNATURE, THIRD_SIGNATURE); 935 936 assertFalse(details.hasAncestorOrSelfWithDigest(digests)); 937 } 938 createSigningDetailsWithLineage(String... signers)939 private SigningDetails createSigningDetailsWithLineage(String... signers) throws Exception { 940 int[] capabilities = new int[signers.length]; 941 for (int i = 0; i < capabilities.length; i++) { 942 capabilities[i] = DEFAULT_CAPABILITIES; 943 } 944 return createSigningDetailsWithLineageAndCapabilities(signers, capabilities); 945 } 946 createSigningDetailsWithLineageAndCapabilities(String[] signers, int[] capabilities)947 private SigningDetails createSigningDetailsWithLineageAndCapabilities(String[] signers, 948 int[] capabilities) throws Exception { 949 if (capabilities.length != signers.length) { 950 fail("The capabilities array must contain the same number of elements as the signers " 951 + "array"); 952 } 953 Signature[] signingHistory = new Signature[signers.length]; 954 for (int i = 0; i < signers.length; i++) { 955 signingHistory[i] = new Signature(signers[i]); 956 signingHistory[i].setFlags(capabilities[i]); 957 } 958 Signature[] currentSignature = new Signature[]{signingHistory[signers.length - 1]}; 959 return new SigningDetails(currentSignature, SIGNING_BLOCK_V3, signingHistory); 960 } 961 createSigningDetails(String... signers)962 private SigningDetails createSigningDetails(String... signers) throws Exception { 963 return createSigningDetails(false, signers); 964 } 965 createSigningDetails(boolean useNullPastSigners, String... signers)966 private SigningDetails createSigningDetails(boolean useNullPastSigners, String... signers) 967 throws Exception { 968 Signature[] currentSignatures = new Signature[signers.length]; 969 for (int i = 0; i < signers.length; i++) { 970 currentSignatures[i] = new Signature(signers[i]); 971 } 972 // If there are multiple signers then the pastSigningCertificates should be set to null, but 973 // if there is only a single signer both the current signer and the past signers should be 974 // set to that one signer. 975 if (signers.length > 1 || useNullPastSigners) { 976 return new SigningDetails(currentSignatures, SIGNING_BLOCK_V3, null); 977 } 978 return new SigningDetails(currentSignatures, SIGNING_BLOCK_V3, currentSignatures); 979 } 980 createDigestSet(String... signers)981 private Set<String> createDigestSet(String... signers) { 982 Set<String> digests = new ArraySet<>(); 983 for (String signer : signers) { 984 String digest = PackageUtils.computeSha256Digest(new Signature(signer).toByteArray()); 985 digests.add(digest); 986 } 987 return digests; 988 } 989 assertSigningDetailsContainsLineage(SigningDetails details, String... pastSigners)990 private void assertSigningDetailsContainsLineage(SigningDetails details, 991 String... pastSigners) { 992 // This method should only be invoked for results that contain a single signer. 993 assertEquals(1, details.signatures.length); 994 assertTrue(details.signatures[0].toCharsString().equalsIgnoreCase( 995 pastSigners[pastSigners.length - 1])); 996 Set<String> signatures = new ArraySet<>(pastSigners); 997 for (Signature pastSignature : details.pastSigningCertificates) { 998 assertTrue(signatures.remove(pastSignature.toCharsString())); 999 } 1000 assertEquals(0, signatures.size()); 1001 } 1002 } 1003