1 /* 2 * Copyright (C) 2013 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 package com.android.server.pm; 18 19 import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK; 20 21 import static com.android.server.pm.PackageManagerService.SCAN_INITIAL; 22 23 import com.android.internal.util.Preconditions; 24 import android.content.pm.PackageParser; 25 import android.util.ArrayMap; 26 import android.util.ArraySet; 27 import android.util.Base64; 28 import android.util.Slog; 29 import android.util.LongSparseArray; 30 31 import java.io.IOException; 32 import java.io.PrintWriter; 33 import java.security.PublicKey; 34 import java.util.Set; 35 36 import org.xmlpull.v1.XmlPullParser; 37 import org.xmlpull.v1.XmlPullParserException; 38 import org.xmlpull.v1.XmlSerializer; 39 40 /* 41 * Manages system-wide KeySet state. 42 */ 43 public class KeySetManagerService { 44 45 static final String TAG = "KeySetManagerService"; 46 47 /* original keysets implementation had no versioning info, so this is the first */ 48 public static final int FIRST_VERSION = 1; 49 50 public static final int CURRENT_VERSION = FIRST_VERSION; 51 52 /** Sentinel value returned when a {@code KeySet} is not found. */ 53 public static final long KEYSET_NOT_FOUND = -1; 54 55 /** Sentinel value returned when public key is not found. */ 56 protected static final long PUBLIC_KEY_NOT_FOUND = -1; 57 58 private final LongSparseArray<KeySetHandle> mKeySets; 59 60 private final LongSparseArray<PublicKeyHandle> mPublicKeys; 61 62 protected final LongSparseArray<ArraySet<Long>> mKeySetMapping; 63 64 private final ArrayMap<String, PackageSetting> mPackages; 65 66 private long lastIssuedKeySetId = 0; 67 68 private long lastIssuedKeyId = 0; 69 70 class PublicKeyHandle { 71 private final PublicKey mKey; 72 private final long mId; 73 private int mRefCount; 74 75 public PublicKeyHandle(long id, PublicKey key) { 76 mId = id; 77 mRefCount = 1; 78 mKey = key; 79 } 80 81 /* 82 * Only used when reading state from packages.xml 83 */ 84 private PublicKeyHandle(long id, int refCount, PublicKey key) { 85 mId = id; 86 mRefCount = refCount; 87 mKey = key; 88 } 89 90 public long getId() { 91 return mId; 92 } 93 94 public PublicKey getKey() { 95 return mKey; 96 } 97 98 public int getRefCountLPr() { 99 return mRefCount; 100 } 101 102 public void incrRefCountLPw() { 103 mRefCount++; 104 return; 105 } 106 107 public long decrRefCountLPw() { 108 mRefCount--; 109 return mRefCount; 110 } 111 } 112 113 public KeySetManagerService(ArrayMap<String, PackageSetting> packages) { 114 mKeySets = new LongSparseArray<KeySetHandle>(); 115 mPublicKeys = new LongSparseArray<PublicKeyHandle>(); 116 mKeySetMapping = new LongSparseArray<ArraySet<Long>>(); 117 mPackages = packages; 118 } 119 120 /** 121 * Determine if a package is signed by the given KeySet. 122 * 123 * Returns false if the package was not signed by all the 124 * keys in the KeySet. 125 * 126 * Returns true if the package was signed by at least the 127 * keys in the given KeySet. 128 * 129 * Note that this can return true for multiple KeySets. 130 */ 131 public boolean packageIsSignedByLPr(String packageName, KeySetHandle ks) { 132 PackageSetting pkg = mPackages.get(packageName); 133 if (pkg == null) { 134 throw new NullPointerException("Invalid package name"); 135 } 136 if (pkg.keySetData == null) { 137 throw new NullPointerException("Package has no KeySet data"); 138 } 139 long id = getIdByKeySetLPr(ks); 140 if (id == KEYSET_NOT_FOUND) { 141 return false; 142 } 143 ArraySet<Long> pkgKeys = mKeySetMapping.get(pkg.keySetData.getProperSigningKeySet()); 144 ArraySet<Long> testKeys = mKeySetMapping.get(id); 145 return pkgKeys.containsAll(testKeys); 146 } 147 148 /** 149 * Determine if a package is signed by the given KeySet. 150 * 151 * Returns false if the package was not signed by all the 152 * keys in the KeySet, or if the package was signed by keys 153 * not in the KeySet. 154 * 155 * Note that this can return only for one KeySet. 156 */ 157 public boolean packageIsSignedByExactlyLPr(String packageName, KeySetHandle ks) { 158 PackageSetting pkg = mPackages.get(packageName); 159 if (pkg == null) { 160 throw new NullPointerException("Invalid package name"); 161 } 162 if (pkg.keySetData == null 163 || pkg.keySetData.getProperSigningKeySet() 164 == PackageKeySetData.KEYSET_UNASSIGNED) { 165 throw new NullPointerException("Package has no KeySet data"); 166 } 167 long id = getIdByKeySetLPr(ks); 168 if (id == KEYSET_NOT_FOUND) { 169 return false; 170 } 171 ArraySet<Long> pkgKeys = mKeySetMapping.get(pkg.keySetData.getProperSigningKeySet()); 172 ArraySet<Long> testKeys = mKeySetMapping.get(id); 173 return pkgKeys.equals(testKeys); 174 } 175 176 /** 177 * addScannedPackageLPw directly modifies the package metadata in pm.Settings 178 * at a point of no-return. We need to make sure that the scanned package does 179 * not contain bad keyset meta-data that could generate an incorrect 180 * PackageSetting. Verify that there is a signing keyset, there are no issues 181 * with null objects, and the upgrade and defined keysets match. 182 * 183 * Returns true if the package can safely be added to the keyset metadata. 184 */ 185 public void assertScannedPackageValid(PackageParser.Package pkg) 186 throws PackageManagerException { 187 if (pkg == null || pkg.packageName == null) { 188 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, 189 "Passed invalid package to keyset validation."); 190 } 191 ArraySet<PublicKey> signingKeys = pkg.mSigningDetails.publicKeys; 192 if (signingKeys == null || !(signingKeys.size() > 0) || signingKeys.contains(null)) { 193 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, 194 "Package has invalid signing-key-set."); 195 } 196 ArrayMap<String, ArraySet<PublicKey>> definedMapping = pkg.mKeySetMapping; 197 if (definedMapping != null) { 198 if (definedMapping.containsKey(null) || definedMapping.containsValue(null)) { 199 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, 200 "Package has null defined key set."); 201 } 202 int defMapSize = definedMapping.size(); 203 for (int i = 0; i < defMapSize; i++) { 204 if (!(definedMapping.valueAt(i).size() > 0) 205 || definedMapping.valueAt(i).contains(null)) { 206 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, 207 "Package has null/no public keys for defined key-sets."); 208 } 209 } 210 } 211 ArraySet<String> upgradeAliases = pkg.mUpgradeKeySets; 212 if (upgradeAliases != null) { 213 if (definedMapping == null || !(definedMapping.keySet().containsAll(upgradeAliases))) { 214 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, 215 "Package has upgrade-key-sets without corresponding definitions."); 216 } 217 } 218 } 219 220 public void addScannedPackageLPw(PackageParser.Package pkg) { 221 Preconditions.checkNotNull(pkg, "Attempted to add null pkg to ksms."); 222 Preconditions.checkNotNull(pkg.packageName, "Attempted to add null pkg to ksms."); 223 PackageSetting ps = mPackages.get(pkg.packageName); 224 Preconditions.checkNotNull(ps, "pkg: " + pkg.packageName 225 + "does not have a corresponding entry in mPackages."); 226 addSigningKeySetToPackageLPw(ps, pkg.mSigningDetails.publicKeys); 227 if (pkg.mKeySetMapping != null) { 228 addDefinedKeySetsToPackageLPw(ps, pkg.mKeySetMapping); 229 if (pkg.mUpgradeKeySets != null) { 230 addUpgradeKeySetsToPackageLPw(ps, pkg.mUpgradeKeySets); 231 } 232 } 233 } 234 235 /** 236 * Informs the system that the given package was signed by the provided KeySet. 237 */ 238 void addSigningKeySetToPackageLPw(PackageSetting pkg, 239 ArraySet<PublicKey> signingKeys) { 240 241 /* check existing keyset for reuse or removal */ 242 long signingKeySetId = pkg.keySetData.getProperSigningKeySet(); 243 244 if (signingKeySetId != PackageKeySetData.KEYSET_UNASSIGNED) { 245 ArraySet<PublicKey> existingKeys = getPublicKeysFromKeySetLPr(signingKeySetId); 246 if (existingKeys != null && existingKeys.equals(signingKeys)) { 247 248 /* no change in signing keys, leave PackageSetting alone */ 249 return; 250 } else { 251 252 /* old keyset no longer valid, remove ref */ 253 decrementKeySetLPw(signingKeySetId); 254 } 255 } 256 257 /* create and add a new keyset */ 258 KeySetHandle ks = addKeySetLPw(signingKeys); 259 long id = ks.getId(); 260 pkg.keySetData.setProperSigningKeySet(id); 261 return; 262 } 263 264 /** 265 * Fetches the stable identifier associated with the given KeySet. Returns 266 * {@link #KEYSET_NOT_FOUND} if the KeySet... wasn't found. 267 */ 268 private long getIdByKeySetLPr(KeySetHandle ks) { 269 for (int keySetIndex = 0; keySetIndex < mKeySets.size(); keySetIndex++) { 270 KeySetHandle value = mKeySets.valueAt(keySetIndex); 271 if (ks.equals(value)) { 272 return mKeySets.keyAt(keySetIndex); 273 } 274 } 275 return KEYSET_NOT_FOUND; 276 } 277 278 /** 279 * Inform the system that the given package defines the given KeySets. 280 * Remove any KeySets the package no longer defines. 281 */ 282 void addDefinedKeySetsToPackageLPw(PackageSetting pkg, 283 ArrayMap<String, ArraySet<PublicKey>> definedMapping) { 284 ArrayMap<String, Long> prevDefinedKeySets = pkg.keySetData.getAliases(); 285 286 /* add all of the newly defined KeySets */ 287 ArrayMap<String, Long> newKeySetAliases = new ArrayMap<String, Long>(); 288 final int defMapSize = definedMapping.size(); 289 for (int i = 0; i < defMapSize; i++) { 290 String alias = definedMapping.keyAt(i); 291 ArraySet<PublicKey> pubKeys = definedMapping.valueAt(i); 292 if (alias != null && pubKeys != null && pubKeys.size() > 0) { 293 KeySetHandle ks = addKeySetLPw(pubKeys); 294 newKeySetAliases.put(alias, ks.getId()); 295 } 296 } 297 298 /* remove each of the old references */ 299 final int prevDefSize = prevDefinedKeySets.size(); 300 for (int i = 0; i < prevDefSize; i++) { 301 decrementKeySetLPw(prevDefinedKeySets.valueAt(i)); 302 } 303 pkg.keySetData.removeAllUpgradeKeySets(); 304 305 /* switch to the just-added */ 306 pkg.keySetData.setAliases(newKeySetAliases); 307 return; 308 } 309 310 /** 311 * This informs the system that the given package has defined a KeySet 312 * alias in its manifest to be an upgradeKeySet. This must be called 313 * after all of the defined KeySets have been added. 314 */ 315 void addUpgradeKeySetsToPackageLPw(PackageSetting pkg, 316 ArraySet<String> upgradeAliases) { 317 final int uaSize = upgradeAliases.size(); 318 for (int i = 0; i < uaSize; i++) { 319 pkg.keySetData.addUpgradeKeySet(upgradeAliases.valueAt(i)); 320 } 321 return; 322 } 323 324 /** 325 * Fetched the {@link KeySetHandle} that a given package refers to by the 326 * provided alias. Returns null if the package is unknown or does not have a 327 * KeySet corresponding to that alias. 328 */ 329 public KeySetHandle getKeySetByAliasAndPackageNameLPr(String packageName, String alias) { 330 PackageSetting p = mPackages.get(packageName); 331 if (p == null || p.keySetData == null) { 332 return null; 333 } 334 Long keySetId = p.keySetData.getAliases().get(alias); 335 if (keySetId == null) { 336 throw new IllegalArgumentException("Unknown KeySet alias: " + alias); 337 } 338 return mKeySets.get(keySetId); 339 } 340 341 /* Checks if an identifier refers to a known keyset */ 342 public boolean isIdValidKeySetId(long id) { 343 return mKeySets.get(id) != null; 344 } 345 346 public boolean shouldCheckUpgradeKeySetLocked(PackageSettingBase oldPs, int scanFlags) { 347 // Can't rotate keys during boot or if sharedUser. 348 if (oldPs == null || (scanFlags&SCAN_INITIAL) != 0 || oldPs.isSharedUser() 349 || !oldPs.keySetData.isUsingUpgradeKeySets()) { 350 return false; 351 } 352 // app is using upgradeKeySets; make sure all are valid 353 long[] upgradeKeySets = oldPs.keySetData.getUpgradeKeySets(); 354 for (int i = 0; i < upgradeKeySets.length; i++) { 355 if (!isIdValidKeySetId(upgradeKeySets[i])) { 356 Slog.wtf(TAG, "Package " 357 + (oldPs.name != null ? oldPs.name : "<null>") 358 + " contains upgrade-key-set reference to unknown key-set: " 359 + upgradeKeySets[i] 360 + " reverting to signatures check."); 361 return false; 362 } 363 } 364 return true; 365 } 366 367 public boolean checkUpgradeKeySetLocked(PackageSettingBase oldPS, 368 PackageParser.Package newPkg) { 369 // Upgrade keysets are being used. Determine if new package has a superset of the 370 // required keys. 371 long[] upgradeKeySets = oldPS.keySetData.getUpgradeKeySets(); 372 for (int i = 0; i < upgradeKeySets.length; i++) { 373 Set<PublicKey> upgradeSet = getPublicKeysFromKeySetLPr(upgradeKeySets[i]); 374 if (upgradeSet != null && newPkg.mSigningDetails.publicKeys.containsAll(upgradeSet)) { 375 return true; 376 } 377 } 378 return false; 379 } 380 381 /** 382 * Fetches the {@link PublicKey public keys} which belong to the specified 383 * KeySet id. 384 * 385 * Returns {@code null} if the identifier doesn't 386 * identify a {@link KeySetHandle}. 387 */ 388 public ArraySet<PublicKey> getPublicKeysFromKeySetLPr(long id) { 389 ArraySet<Long> pkIds = mKeySetMapping.get(id); 390 if (pkIds == null) { 391 return null; 392 } 393 ArraySet<PublicKey> mPubKeys = new ArraySet<PublicKey>(); 394 final int pkSize = pkIds.size(); 395 for (int i = 0; i < pkSize; i++) { 396 mPubKeys.add(mPublicKeys.get(pkIds.valueAt(i)).getKey()); 397 } 398 return mPubKeys; 399 } 400 401 /** 402 * Fetches the proper {@link KeySetHandle KeySet} that signed the given 403 * package. 404 * 405 * @throws IllegalArgumentException if the package has no keyset data. 406 * @throws NullPointerException if the packgae is unknown. 407 */ 408 public KeySetHandle getSigningKeySetByPackageNameLPr(String packageName) { 409 PackageSetting p = mPackages.get(packageName); 410 if (p == null 411 || p.keySetData == null 412 || p.keySetData.getProperSigningKeySet() 413 == PackageKeySetData.KEYSET_UNASSIGNED) { 414 return null; 415 } 416 return mKeySets.get(p.keySetData.getProperSigningKeySet()); 417 } 418 419 /** 420 * Creates a new KeySet corresponding to the given keys. 421 * 422 * If the {@link PublicKey PublicKeys} aren't known to the system, this 423 * adds them. Otherwise, they're deduped and the reference count 424 * incremented. 425 * 426 * If the KeySet isn't known to the system, this adds that and creates the 427 * mapping to the PublicKeys. If it is known, then it's deduped and the 428 * reference count is incremented. 429 * 430 * Throws if the provided set is {@code null}. 431 */ 432 private KeySetHandle addKeySetLPw(ArraySet<PublicKey> keys) { 433 if (keys == null || keys.size() == 0) { 434 throw new IllegalArgumentException("Cannot add an empty set of keys!"); 435 } 436 437 /* add each of the keys in the provided set */ 438 ArraySet<Long> addedKeyIds = new ArraySet<Long>(keys.size()); 439 final int kSize = keys.size(); 440 for (int i = 0; i < kSize; i++) { 441 long id = addPublicKeyLPw(keys.valueAt(i)); 442 addedKeyIds.add(id); 443 } 444 445 /* check to see if the resulting keyset is new */ 446 long existingKeySetId = getIdFromKeyIdsLPr(addedKeyIds); 447 if (existingKeySetId != KEYSET_NOT_FOUND) { 448 449 /* public keys were incremented, but we aren't adding a new keyset: undo */ 450 for (int i = 0; i < kSize; i++) { 451 decrementPublicKeyLPw(addedKeyIds.valueAt(i)); 452 } 453 KeySetHandle ks = mKeySets.get(existingKeySetId); 454 ks.incrRefCountLPw(); 455 return ks; 456 } 457 458 // get the next keyset id 459 long id = getFreeKeySetIDLPw(); 460 461 // create the KeySet object and add to mKeySets and mapping 462 KeySetHandle ks = new KeySetHandle(id); 463 mKeySets.put(id, ks); 464 mKeySetMapping.put(id, addedKeyIds); 465 return ks; 466 } 467 468 /* 469 * Decrements the reference to KeySet represented by the given id. If this 470 * drops to zero, then also decrement the reference to each public key it 471 * contains and remove the KeySet. 472 */ 473 private void decrementKeySetLPw(long id) { 474 KeySetHandle ks = mKeySets.get(id); 475 if (ks == null) { 476 /* nothing to do */ 477 return; 478 } 479 if (ks.decrRefCountLPw() <= 0) { 480 ArraySet<Long> pubKeys = mKeySetMapping.get(id); 481 final int pkSize = pubKeys.size(); 482 for (int i = 0; i < pkSize; i++) { 483 decrementPublicKeyLPw(pubKeys.valueAt(i)); 484 } 485 mKeySets.delete(id); 486 mKeySetMapping.delete(id); 487 } 488 } 489 490 /* 491 * Decrements the reference to PublicKey represented by the given id. If 492 * this drops to zero, then remove it. 493 */ 494 private void decrementPublicKeyLPw(long id) { 495 PublicKeyHandle pk = mPublicKeys.get(id); 496 if (pk == null) { 497 /* nothing to do */ 498 return; 499 } 500 if (pk.decrRefCountLPw() <= 0) { 501 mPublicKeys.delete(id); 502 } 503 } 504 505 /** 506 * Adds the given PublicKey to the system, deduping as it goes. 507 */ 508 private long addPublicKeyLPw(PublicKey key) { 509 Preconditions.checkNotNull(key, "Cannot add null public key!"); 510 long id = getIdForPublicKeyLPr(key); 511 if (id != PUBLIC_KEY_NOT_FOUND) { 512 513 /* We already know about this key, increment its ref count and ret */ 514 mPublicKeys.get(id).incrRefCountLPw(); 515 return id; 516 } 517 518 /* if it's new find the first unoccupied slot in the public keys */ 519 id = getFreePublicKeyIdLPw(); 520 mPublicKeys.put(id, new PublicKeyHandle(id, key)); 521 return id; 522 } 523 524 /** 525 * Finds the stable identifier for a KeySet based on a set of PublicKey stable IDs. 526 * 527 * Returns KEYSET_NOT_FOUND if there isn't one. 528 */ 529 private long getIdFromKeyIdsLPr(Set<Long> publicKeyIds) { 530 for (int keyMapIndex = 0; keyMapIndex < mKeySetMapping.size(); keyMapIndex++) { 531 ArraySet<Long> value = mKeySetMapping.valueAt(keyMapIndex); 532 if (value.equals(publicKeyIds)) { 533 return mKeySetMapping.keyAt(keyMapIndex); 534 } 535 } 536 return KEYSET_NOT_FOUND; 537 } 538 539 /** 540 * Finds the stable identifier for a PublicKey or PUBLIC_KEY_NOT_FOUND. 541 */ 542 private long getIdForPublicKeyLPr(PublicKey k) { 543 String encodedPublicKey = new String(k.getEncoded()); 544 for (int publicKeyIndex = 0; publicKeyIndex < mPublicKeys.size(); publicKeyIndex++) { 545 PublicKey value = mPublicKeys.valueAt(publicKeyIndex).getKey(); 546 String encodedExistingKey = new String(value.getEncoded()); 547 if (encodedPublicKey.equals(encodedExistingKey)) { 548 return mPublicKeys.keyAt(publicKeyIndex); 549 } 550 } 551 return PUBLIC_KEY_NOT_FOUND; 552 } 553 554 /** 555 * Gets an unused stable identifier for a KeySet. 556 */ 557 private long getFreeKeySetIDLPw() { 558 lastIssuedKeySetId += 1; 559 return lastIssuedKeySetId; 560 } 561 562 /** 563 * Same as above, but for public keys. 564 */ 565 private long getFreePublicKeyIdLPw() { 566 lastIssuedKeyId += 1; 567 return lastIssuedKeyId; 568 } 569 570 /* 571 * This package is being removed from the system, so we need to 572 * remove its keyset and public key references, then remove its 573 * keyset data. 574 */ 575 public void removeAppKeySetDataLPw(String packageName) { 576 577 /* remove refs from common keysets and public keys */ 578 PackageSetting pkg = mPackages.get(packageName); 579 Preconditions.checkNotNull(pkg, "pkg name: " + packageName 580 + "does not have a corresponding entry in mPackages."); 581 long signingKeySetId = pkg.keySetData.getProperSigningKeySet(); 582 decrementKeySetLPw(signingKeySetId); 583 ArrayMap<String, Long> definedKeySets = pkg.keySetData.getAliases(); 584 for (int i = 0; i < definedKeySets.size(); i++) { 585 decrementKeySetLPw(definedKeySets.valueAt(i)); 586 } 587 588 /* remove from package */ 589 clearPackageKeySetDataLPw(pkg); 590 return; 591 } 592 593 private void clearPackageKeySetDataLPw(PackageSetting pkg) { 594 pkg.keySetData.setProperSigningKeySet(PackageKeySetData.KEYSET_UNASSIGNED); 595 pkg.keySetData.removeAllDefinedKeySets(); 596 pkg.keySetData.removeAllUpgradeKeySets(); 597 return; 598 } 599 600 public String encodePublicKey(PublicKey k) throws IOException { 601 return new String(Base64.encode(k.getEncoded(), Base64.NO_WRAP)); 602 } 603 604 public void dumpLPr(PrintWriter pw, String packageName, 605 DumpState dumpState) { 606 boolean printedHeader = false; 607 for (ArrayMap.Entry<String, PackageSetting> e : mPackages.entrySet()) { 608 String keySetPackage = e.getKey(); 609 if (packageName != null && !packageName.equals(keySetPackage)) { 610 continue; 611 } 612 if (!printedHeader) { 613 if (dumpState.onTitlePrinted()) 614 pw.println(); 615 pw.println("Key Set Manager:"); 616 printedHeader = true; 617 } 618 PackageSetting pkg = e.getValue(); 619 pw.print(" ["); pw.print(keySetPackage); pw.println("]"); 620 if (pkg.keySetData != null) { 621 boolean printedLabel = false; 622 for (ArrayMap.Entry<String, Long> entry : pkg.keySetData.getAliases().entrySet()) { 623 if (!printedLabel) { 624 pw.print(" KeySets Aliases: "); 625 printedLabel = true; 626 } else { 627 pw.print(", "); 628 } 629 pw.print(entry.getKey()); 630 pw.print('='); 631 pw.print(Long.toString(entry.getValue())); 632 } 633 if (printedLabel) { 634 pw.println(""); 635 } 636 printedLabel = false; 637 if (pkg.keySetData.isUsingDefinedKeySets()) { 638 ArrayMap<String, Long> definedKeySets = pkg.keySetData.getAliases(); 639 final int dksSize = definedKeySets.size(); 640 for (int i = 0; i < dksSize; i++) { 641 if (!printedLabel) { 642 pw.print(" Defined KeySets: "); 643 printedLabel = true; 644 } else { 645 pw.print(", "); 646 } 647 pw.print(Long.toString(definedKeySets.valueAt(i))); 648 } 649 } 650 if (printedLabel) { 651 pw.println(""); 652 } 653 printedLabel = false; 654 final long signingKeySet = pkg.keySetData.getProperSigningKeySet(); 655 pw.print(" Signing KeySets: "); 656 pw.print(Long.toString(signingKeySet)); 657 pw.println(""); 658 if (pkg.keySetData.isUsingUpgradeKeySets()) { 659 for (long keySetId : pkg.keySetData.getUpgradeKeySets()) { 660 if (!printedLabel) { 661 pw.print(" Upgrade KeySets: "); 662 printedLabel = true; 663 } else { 664 pw.print(", "); 665 } 666 pw.print(Long.toString(keySetId)); 667 } 668 } 669 if (printedLabel) { 670 pw.println(""); 671 } 672 } 673 } 674 } 675 676 void writeKeySetManagerServiceLPr(XmlSerializer serializer) throws IOException { 677 serializer.startTag(null, "keyset-settings"); 678 serializer.attribute(null, "version", Integer.toString(CURRENT_VERSION)); 679 writePublicKeysLPr(serializer); 680 writeKeySetsLPr(serializer); 681 serializer.startTag(null, "lastIssuedKeyId"); 682 serializer.attribute(null, "value", Long.toString(lastIssuedKeyId)); 683 serializer.endTag(null, "lastIssuedKeyId"); 684 serializer.startTag(null, "lastIssuedKeySetId"); 685 serializer.attribute(null, "value", Long.toString(lastIssuedKeySetId)); 686 serializer.endTag(null, "lastIssuedKeySetId"); 687 serializer.endTag(null, "keyset-settings"); 688 } 689 690 void writePublicKeysLPr(XmlSerializer serializer) throws IOException { 691 serializer.startTag(null, "keys"); 692 for (int pKeyIndex = 0; pKeyIndex < mPublicKeys.size(); pKeyIndex++) { 693 long id = mPublicKeys.keyAt(pKeyIndex); 694 PublicKeyHandle pkh = mPublicKeys.valueAt(pKeyIndex); 695 String encodedKey = encodePublicKey(pkh.getKey()); 696 serializer.startTag(null, "public-key"); 697 serializer.attribute(null, "identifier", Long.toString(id)); 698 serializer.attribute(null, "value", encodedKey); 699 serializer.endTag(null, "public-key"); 700 } 701 serializer.endTag(null, "keys"); 702 } 703 704 void writeKeySetsLPr(XmlSerializer serializer) throws IOException { 705 serializer.startTag(null, "keysets"); 706 for (int keySetIndex = 0; keySetIndex < mKeySetMapping.size(); keySetIndex++) { 707 long id = mKeySetMapping.keyAt(keySetIndex); 708 ArraySet<Long> keys = mKeySetMapping.valueAt(keySetIndex); 709 serializer.startTag(null, "keyset"); 710 serializer.attribute(null, "identifier", Long.toString(id)); 711 for (long keyId : keys) { 712 serializer.startTag(null, "key-id"); 713 serializer.attribute(null, "identifier", Long.toString(keyId)); 714 serializer.endTag(null, "key-id"); 715 } 716 serializer.endTag(null, "keyset"); 717 } 718 serializer.endTag(null, "keysets"); 719 } 720 721 void readKeySetsLPw(XmlPullParser parser, ArrayMap<Long, Integer> keySetRefCounts) 722 throws XmlPullParserException, IOException { 723 int type; 724 long currentKeySetId = 0; 725 int outerDepth = parser.getDepth(); 726 String recordedVersionStr = parser.getAttributeValue(null, "version"); 727 if (recordedVersionStr == null) { 728 // The keyset information comes from pre-versioned devices, and 729 // is inaccurate, don't collect any of it. 730 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 731 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 732 continue; 733 } 734 // The KeySet information read previously from packages.xml is invalid. 735 // Destroy it all. 736 for (PackageSetting p : mPackages.values()) { 737 clearPackageKeySetDataLPw(p); 738 } 739 return; 740 } 741 int recordedVersion = Integer.parseInt(recordedVersionStr); 742 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 743 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 744 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 745 continue; 746 } 747 final String tagName = parser.getName(); 748 if (tagName.equals("keys")) { 749 readKeysLPw(parser); 750 } else if (tagName.equals("keysets")) { 751 readKeySetListLPw(parser); 752 } else if (tagName.equals("lastIssuedKeyId")) { 753 lastIssuedKeyId = Long.parseLong(parser.getAttributeValue(null, "value")); 754 } else if (tagName.equals("lastIssuedKeySetId")) { 755 lastIssuedKeySetId = Long.parseLong(parser.getAttributeValue(null, "value")); 756 } 757 } 758 759 addRefCountsFromSavedPackagesLPw(keySetRefCounts); 760 } 761 762 void readKeysLPw(XmlPullParser parser) 763 throws XmlPullParserException, IOException { 764 int outerDepth = parser.getDepth(); 765 int type; 766 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 767 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 768 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 769 continue; 770 } 771 final String tagName = parser.getName(); 772 if (tagName.equals("public-key")) { 773 readPublicKeyLPw(parser); 774 } 775 } 776 } 777 778 void readKeySetListLPw(XmlPullParser parser) 779 throws XmlPullParserException, IOException { 780 int outerDepth = parser.getDepth(); 781 int type; 782 long currentKeySetId = 0; 783 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 784 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 785 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 786 continue; 787 } 788 final String tagName = parser.getName(); 789 if (tagName.equals("keyset")) { 790 String encodedID = parser.getAttributeValue(null, "identifier"); 791 currentKeySetId = Long.parseLong(encodedID); 792 int refCount = 0; 793 mKeySets.put(currentKeySetId, new KeySetHandle(currentKeySetId, refCount)); 794 mKeySetMapping.put(currentKeySetId, new ArraySet<Long>()); 795 } else if (tagName.equals("key-id")) { 796 String encodedID = parser.getAttributeValue(null, "identifier"); 797 long id = Long.parseLong(encodedID); 798 mKeySetMapping.get(currentKeySetId).add(id); 799 } 800 } 801 } 802 803 void readPublicKeyLPw(XmlPullParser parser) 804 throws XmlPullParserException { 805 String encodedID = parser.getAttributeValue(null, "identifier"); 806 long identifier = Long.parseLong(encodedID); 807 int refCount = 0; 808 String encodedPublicKey = parser.getAttributeValue(null, "value"); 809 PublicKey pub = PackageParser.parsePublicKey(encodedPublicKey); 810 if (pub != null) { 811 PublicKeyHandle pkh = new PublicKeyHandle(identifier, refCount, pub); 812 mPublicKeys.put(identifier, pkh); 813 } 814 } 815 816 /* 817 * Set each KeySet ref count. Also increment all public keys in each keyset. 818 */ 819 private void addRefCountsFromSavedPackagesLPw(ArrayMap<Long, Integer> keySetRefCounts) { 820 final int numRefCounts = keySetRefCounts.size(); 821 for (int i = 0; i < numRefCounts; i++) { 822 KeySetHandle ks = mKeySets.get(keySetRefCounts.keyAt(i)); 823 if (ks == null) { 824 /* something went terribly wrong and we have references to a non-existent key-set */ 825 Slog.wtf(TAG, "Encountered non-existent key-set reference when reading settings"); 826 continue; 827 } 828 ks.setRefCountLPw(keySetRefCounts.valueAt(i)); 829 } 830 831 /* 832 * In case something went terribly wrong and we have keysets with no associated packges 833 * that refer to them, record the orphaned keyset ids, and remove them using 834 * decrementKeySetLPw() after all keyset references have been set so that the associtaed 835 * public keys have the appropriate references from all keysets. 836 */ 837 ArraySet<Long> orphanedKeySets = new ArraySet<Long>(); 838 final int numKeySets = mKeySets.size(); 839 for (int i = 0; i < numKeySets; i++) { 840 if (mKeySets.valueAt(i).getRefCountLPr() == 0) { 841 Slog.wtf(TAG, "Encountered key-set w/out package references when reading settings"); 842 orphanedKeySets.add(mKeySets.keyAt(i)); 843 } 844 ArraySet<Long> pubKeys = mKeySetMapping.valueAt(i); 845 final int pkSize = pubKeys.size(); 846 for (int j = 0; j < pkSize; j++) { 847 mPublicKeys.get(pubKeys.valueAt(j)).incrRefCountLPw(); 848 } 849 } 850 final int numOrphans = orphanedKeySets.size(); 851 for (int i = 0; i < numOrphans; i++) { 852 decrementKeySetLPw(orphanedKeySets.valueAt(i)); 853 } 854 } 855 } 856