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