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 android.content.pm.KeySet; 20 import android.content.pm.PackageParser; 21 import android.os.Binder; 22 import android.util.Base64; 23 import android.util.Log; 24 import android.util.LongSparseArray; 25 26 import java.io.IOException; 27 import java.io.PrintWriter; 28 import java.security.PublicKey; 29 import java.util.HashMap; 30 import java.util.HashSet; 31 import java.util.Map; 32 import java.util.Set; 33 34 import org.xmlpull.v1.XmlPullParser; 35 import org.xmlpull.v1.XmlPullParserException; 36 import org.xmlpull.v1.XmlSerializer; 37 38 /* 39 * Manages system-wide KeySet state. 40 */ 41 public class KeySetManager { 42 43 static final String TAG = "KeySetManager"; 44 45 /** Sentinel value returned when a {@code KeySet} is not found. */ 46 public static final long KEYSET_NOT_FOUND = -1; 47 48 /** Sentinel value returned when public key is not found. */ 49 private static final long PUBLIC_KEY_NOT_FOUND = -1; 50 51 private final Object mLockObject = new Object(); 52 53 private final LongSparseArray<KeySet> mKeySets; 54 55 private final LongSparseArray<PublicKey> mPublicKeys; 56 57 private final LongSparseArray<Set<Long>> mKeySetMapping; 58 59 private final Map<String, PackageSetting> mPackages; 60 61 private static long lastIssuedKeySetId = 0; 62 63 private static long lastIssuedKeyId = 0; 64 65 public KeySetManager(Map<String, PackageSetting> packages) { 66 mKeySets = new LongSparseArray<KeySet>(); 67 mPublicKeys = new LongSparseArray<PublicKey>(); 68 mKeySetMapping = new LongSparseArray<Set<Long>>(); 69 mPackages = packages; 70 } 71 72 /** 73 * Determine if a package is signed by the given KeySet. 74 * 75 * Returns false if the package was not signed by all the 76 * keys in the KeySet. 77 * 78 * Returns true if the package was signed by at least the 79 * keys in the given KeySet. 80 * 81 * Note that this can return true for multiple KeySets. 82 */ 83 public boolean packageIsSignedBy(String packageName, KeySet ks) { 84 synchronized (mLockObject) { 85 PackageSetting pkg = mPackages.get(packageName); 86 if (pkg == null) { 87 throw new NullPointerException("Invalid package name"); 88 } 89 if (pkg.keySetData == null) { 90 throw new NullPointerException("Package has no KeySet data"); 91 } 92 long id = getIdByKeySetLocked(ks); 93 return pkg.keySetData.packageIsSignedBy(id); 94 } 95 } 96 97 /** 98 * This informs the system that the given package has defined a KeySet 99 * in its manifest that a) contains the given keys and b) is named 100 * alias by that package. 101 */ 102 public void addDefinedKeySetToPackage(String packageName, 103 Set<PublicKey> keys, String alias) { 104 if ((packageName == null) || (keys == null) || (alias == null)) { 105 //Log.d(TAG, "Got null argument for a defined keyset, ignoring!"); 106 return; 107 } 108 synchronized (mLockObject) { 109 KeySet ks = addKeySetLocked(keys); 110 PackageSetting pkg = mPackages.get(packageName); 111 if (pkg == null) { 112 throw new NullPointerException("Unknown package"); 113 } 114 long id = getIdByKeySetLocked(ks); 115 pkg.keySetData.addDefinedKeySet(id, alias); 116 } 117 } 118 119 /** 120 * Similar to the above, this informs the system that the given package 121 * was signed by the provided KeySet. 122 */ 123 public void addSigningKeySetToPackage(String packageName, 124 Set<PublicKey> signingKeys) { 125 if ((packageName == null) || (signingKeys == null)) { 126 //Log.d(TAG, "Got null argument for a signing keyset, ignoring!"); 127 return; 128 } 129 synchronized (mLockObject) { 130 // add the signing KeySet 131 KeySet ks = addKeySetLocked(signingKeys); 132 long id = getIdByKeySetLocked(ks); 133 Set<Long> publicKeyIds = mKeySetMapping.get(id); 134 if (publicKeyIds == null) { 135 throw new NullPointerException("Got invalid KeySet id"); 136 } 137 138 // attach it to the package 139 PackageSetting pkg = mPackages.get(packageName); 140 if (pkg == null) { 141 throw new NullPointerException("No such package!"); 142 } 143 pkg.keySetData.addSigningKeySet(id); 144 145 // for each KeySet the package defines which is a subset of 146 // the one above, add the KeySet id to the package's signing KeySets 147 for (Long keySetID : pkg.keySetData.getDefinedKeySets()) { 148 Set<Long> definedKeys = mKeySetMapping.get(keySetID); 149 if (publicKeyIds.contains(definedKeys)) { 150 pkg.keySetData.addSigningKeySet(keySetID); 151 } 152 } 153 } 154 } 155 156 /** 157 * Fetches the stable identifier associated with the given KeySet. Returns 158 * {@link #KEYSET_NOT_FOUND} if the KeySet... wasn't found. 159 */ 160 public long getIdByKeySet(KeySet ks) { 161 synchronized (mLockObject) { 162 return getIdByKeySetLocked(ks); 163 } 164 } 165 166 private long getIdByKeySetLocked(KeySet ks) { 167 for (int keySetIndex = 0; keySetIndex < mKeySets.size(); keySetIndex++) { 168 KeySet value = mKeySets.valueAt(keySetIndex); 169 if (ks.equals(value)) { 170 return mKeySets.keyAt(keySetIndex); 171 } 172 } 173 return KEYSET_NOT_FOUND; 174 } 175 176 /** 177 * Fetches the KeySet corresponding to the given stable identifier. 178 * 179 * Returns {@link #KEYSET_NOT_FOUND} if the identifier doesn't 180 * identify a {@link KeySet}. 181 */ 182 public KeySet getKeySetById(long id) { 183 synchronized (mLockObject) { 184 return mKeySets.get(id); 185 } 186 } 187 188 /** 189 * Fetches the KeySet that a given package refers to by the provided alias. 190 * 191 * If the package isn't known to us, throws an IllegalArgumentException. 192 * Returns null if the alias isn't known to us. 193 */ 194 public KeySet getKeySetByAliasAndPackageName(String packageName, String alias) { 195 synchronized (mLockObject) { 196 PackageSetting p = mPackages.get(packageName); 197 if (p == null) { 198 throw new NullPointerException("Unknown package"); 199 } 200 if (p.keySetData == null) { 201 throw new IllegalArgumentException("Package has no keySet data"); 202 } 203 long keySetId = p.keySetData.getAliases().get(alias); 204 return mKeySets.get(keySetId); 205 } 206 } 207 208 /** 209 * Fetches all the known {@link KeySet KeySets} that signed the given 210 * package. Returns {@code null} if package is unknown. 211 */ 212 public Set<KeySet> getSigningKeySetsByPackageName(String packageName) { 213 synchronized (mLockObject) { 214 Set<KeySet> signingKeySets = new HashSet<KeySet>(); 215 PackageSetting p = mPackages.get(packageName); 216 if (p == null) { 217 throw new NullPointerException("Unknown package"); 218 } 219 if (p.keySetData == null) { 220 throw new IllegalArgumentException("Package has no keySet data"); 221 } 222 for (long l : p.keySetData.getSigningKeySets()) { 223 signingKeySets.add(mKeySets.get(l)); 224 } 225 return signingKeySets; 226 } 227 } 228 229 /** 230 * Creates a new KeySet corresponding to the given keys. 231 * 232 * If the {@link PublicKey PublicKeys} aren't known to the system, this 233 * adds them. Otherwise, they're deduped. 234 * 235 * If the KeySet isn't known to the system, this adds that and creates the 236 * mapping to the PublicKeys. If it is known, then it's deduped. 237 * 238 * Throws if the provided set is {@code null}. 239 */ 240 private KeySet addKeySetLocked(Set<PublicKey> keys) { 241 if (keys == null) { 242 throw new NullPointerException("Provided keys cannot be null"); 243 } 244 // add each of the keys in the provided set 245 Set<Long> addedKeyIds = new HashSet<Long>(keys.size()); 246 for (PublicKey k : keys) { 247 long id = addPublicKeyLocked(k); 248 addedKeyIds.add(id); 249 } 250 251 // check to see if the resulting keyset is new 252 long existingKeySetId = getIdFromKeyIdsLocked(addedKeyIds); 253 if (existingKeySetId != KEYSET_NOT_FOUND) { 254 return mKeySets.get(existingKeySetId); 255 } 256 257 // create the KeySet object 258 KeySet ks = new KeySet(new Binder()); 259 // get the first unoccupied slot in mKeySets 260 long id = getFreeKeySetIDLocked(); 261 // add the KeySet object to it 262 mKeySets.put(id, ks); 263 // add the stable key ids to the mapping 264 mKeySetMapping.put(id, addedKeyIds); 265 // go home 266 return ks; 267 } 268 269 /** 270 * Adds the given PublicKey to the system, deduping as it goes. 271 */ 272 private long addPublicKeyLocked(PublicKey key) { 273 // check if the public key is new 274 long existingKeyId = getIdForPublicKeyLocked(key); 275 if (existingKeyId != PUBLIC_KEY_NOT_FOUND) { 276 return existingKeyId; 277 } 278 // if it's new find the first unoccupied slot in the public keys 279 long id = getFreePublicKeyIdLocked(); 280 // add the public key to it 281 mPublicKeys.put(id, key); 282 // return the stable identifier 283 return id; 284 } 285 286 /** 287 * Finds the stable identifier for a KeySet based on a set of PublicKey stable IDs. 288 * 289 * Returns KEYSET_NOT_FOUND if there isn't one. 290 */ 291 private long getIdFromKeyIdsLocked(Set<Long> publicKeyIds) { 292 for (int keyMapIndex = 0; keyMapIndex < mKeySetMapping.size(); keyMapIndex++) { 293 Set<Long> value = mKeySetMapping.valueAt(keyMapIndex); 294 if (value.equals(publicKeyIds)) { 295 return mKeySetMapping.keyAt(keyMapIndex); 296 } 297 } 298 return KEYSET_NOT_FOUND; 299 } 300 301 /** 302 * Finds the stable identifier for a PublicKey or PUBLIC_KEY_NOT_FOUND. 303 */ 304 private long getIdForPublicKeyLocked(PublicKey k) { 305 String encodedPublicKey = new String(k.getEncoded()); 306 for (int publicKeyIndex = 0; publicKeyIndex < mPublicKeys.size(); publicKeyIndex++) { 307 PublicKey value = mPublicKeys.valueAt(publicKeyIndex); 308 String encodedExistingKey = new String(value.getEncoded()); 309 if (encodedPublicKey.equals(encodedExistingKey)) { 310 return mPublicKeys.keyAt(publicKeyIndex); 311 } 312 } 313 return PUBLIC_KEY_NOT_FOUND; 314 } 315 316 /** 317 * Gets an unused stable identifier for a KeySet. 318 */ 319 private long getFreeKeySetIDLocked() { 320 lastIssuedKeySetId += 1; 321 return lastIssuedKeySetId; 322 } 323 324 /** 325 * Same as above, but for public keys. 326 */ 327 private long getFreePublicKeyIdLocked() { 328 lastIssuedKeyId += 1; 329 return lastIssuedKeyId; 330 } 331 332 public void removeAppKeySetData(String packageName) { 333 synchronized (mLockObject) { 334 // Get the package's known keys and KeySets 335 Set<Long> deletableKeySets = getKnownKeySetsByPackageNameLocked(packageName); 336 Set<Long> deletableKeys = new HashSet<Long>(); 337 Set<Long> knownKeys = null; 338 for (Long ks : deletableKeySets) { 339 knownKeys = mKeySetMapping.get(ks); 340 if (knownKeys != null) { 341 deletableKeys.addAll(knownKeys); 342 } 343 } 344 345 // Now remove the keys and KeySets known to any other package 346 for (String pkgName : mPackages.keySet()) { 347 if (pkgName.equals(packageName)) { 348 continue; 349 } 350 Set<Long> knownKeySets = getKnownKeySetsByPackageNameLocked(pkgName); 351 deletableKeySets.removeAll(knownKeySets); 352 knownKeys = new HashSet<Long>(); 353 for (Long ks : knownKeySets) { 354 knownKeys = mKeySetMapping.get(ks); 355 if (knownKeys != null) { 356 deletableKeys.removeAll(knownKeys); 357 } 358 } 359 } 360 361 // The remaining keys and KeySets are not known to any other 362 // application and so can be safely deleted. 363 for (Long ks : deletableKeySets) { 364 mKeySets.delete(ks); 365 mKeySetMapping.delete(ks); 366 } 367 for (Long keyId : deletableKeys) { 368 mPublicKeys.delete(keyId); 369 } 370 371 // Now remove them from the KeySets known to each package 372 for (String pkgName : mPackages.keySet()) { 373 PackageSetting p = mPackages.get(pkgName); 374 for (Long ks : deletableKeySets) { 375 p.keySetData.removeSigningKeySet(ks); 376 p.keySetData.removeDefinedKeySet(ks); 377 } 378 } 379 } 380 } 381 382 private Set<Long> getKnownKeySetsByPackageNameLocked(String packageName) { 383 PackageSetting p = mPackages.get(packageName); 384 if (p == null) { 385 throw new NullPointerException("Unknown package"); 386 } 387 if (p.keySetData == null) { 388 throw new IllegalArgumentException("Package has no keySet data"); 389 } 390 Set<Long> knownKeySets = new HashSet<Long>(); 391 for (long ks : p.keySetData.getSigningKeySets()) { 392 knownKeySets.add(ks); 393 } 394 for (long ks : p.keySetData.getDefinedKeySets()) { 395 knownKeySets.add(ks); 396 } 397 return knownKeySets; 398 } 399 400 public String encodePublicKey(PublicKey k) throws IOException { 401 return new String(Base64.encode(k.getEncoded(), 0)); 402 } 403 404 public void dump(PrintWriter pw, String packageName, 405 PackageManagerService.DumpState dumpState) { 406 synchronized (mLockObject) { 407 boolean printedHeader = false; 408 for (Map.Entry<String, PackageSetting> e : mPackages.entrySet()) { 409 String keySetPackage = e.getKey(); 410 if (packageName != null && !packageName.equals(keySetPackage)) { 411 continue; 412 } 413 if (!printedHeader) { 414 if (dumpState.onTitlePrinted()) 415 pw.println(); 416 pw.println("Key Set Manager:"); 417 printedHeader = true; 418 } 419 PackageSetting pkg = e.getValue(); 420 pw.print(" ["); pw.print(keySetPackage); pw.println("]"); 421 if (pkg.keySetData != null) { 422 boolean printedLabel = false; 423 for (Map.Entry<String, Long> entry : pkg.keySetData.getAliases().entrySet()) { 424 if (!printedLabel) { 425 pw.print(" KeySets Aliases: "); 426 printedLabel = true; 427 } else { 428 pw.print(", "); 429 } 430 pw.print(entry.getKey()); 431 pw.print('='); 432 pw.print(Long.toString(entry.getValue())); 433 } 434 if (printedLabel) { 435 pw.println(""); 436 } 437 printedLabel = false; 438 for (long keySetId : pkg.keySetData.getDefinedKeySets()) { 439 if (!printedLabel) { 440 pw.print(" Defined KeySets: "); 441 printedLabel = true; 442 } else { 443 pw.print(", "); 444 } 445 pw.print(Long.toString(keySetId)); 446 } 447 if (printedLabel) { 448 pw.println(""); 449 } 450 printedLabel = false; 451 for (long keySetId : pkg.keySetData.getSigningKeySets()) { 452 if (!printedLabel) { 453 pw.print(" Signing KeySets: "); 454 printedLabel = true; 455 } else { 456 pw.print(", "); 457 } 458 pw.print(Long.toString(keySetId)); 459 } 460 if (printedLabel) { 461 pw.println(""); 462 } 463 } 464 } 465 } 466 } 467 468 void writeKeySetManagerLPr(XmlSerializer serializer) throws IOException { 469 serializer.startTag(null, "keyset-settings"); 470 writePublicKeysLPr(serializer); 471 writeKeySetsLPr(serializer); 472 serializer.startTag(null, "lastIssuedKeyId"); 473 serializer.attribute(null, "value", Long.toString(lastIssuedKeyId)); 474 serializer.endTag(null, "lastIssuedKeyId"); 475 serializer.startTag(null, "lastIssuedKeySetId"); 476 serializer.attribute(null, "value", Long.toString(lastIssuedKeySetId)); 477 serializer.endTag(null, "lastIssuedKeySetId"); 478 serializer.endTag(null, "keyset-settings"); 479 } 480 481 void writePublicKeysLPr(XmlSerializer serializer) throws IOException { 482 serializer.startTag(null, "keys"); 483 for (int pKeyIndex = 0; pKeyIndex < mPublicKeys.size(); pKeyIndex++) { 484 long id = mPublicKeys.keyAt(pKeyIndex); 485 PublicKey key = mPublicKeys.valueAt(pKeyIndex); 486 String encodedKey = encodePublicKey(key); 487 serializer.startTag(null, "public-key"); 488 serializer.attribute(null, "identifier", Long.toString(id)); 489 serializer.attribute(null, "value", encodedKey); 490 serializer.endTag(null, "public-key"); 491 } 492 serializer.endTag(null, "keys"); 493 } 494 495 void writeKeySetsLPr(XmlSerializer serializer) throws IOException { 496 serializer.startTag(null, "keysets"); 497 for (int keySetIndex = 0; keySetIndex < mKeySetMapping.size(); keySetIndex++) { 498 long id = mKeySetMapping.keyAt(keySetIndex); 499 Set<Long> keys = mKeySetMapping.valueAt(keySetIndex); 500 serializer.startTag(null, "keyset"); 501 serializer.attribute(null, "identifier", Long.toString(id)); 502 for (long keyId : keys) { 503 serializer.startTag(null, "key-id"); 504 serializer.attribute(null, "identifier", Long.toString(keyId)); 505 serializer.endTag(null, "key-id"); 506 } 507 serializer.endTag(null, "keyset"); 508 } 509 serializer.endTag(null, "keysets"); 510 } 511 512 void readKeySetsLPw(XmlPullParser parser) 513 throws XmlPullParserException, IOException { 514 int type; 515 long currentKeySetId = 0; 516 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { 517 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 518 continue; 519 } 520 final String tagName = parser.getName(); 521 if (tagName.equals("keys")) { 522 readKeysLPw(parser); 523 } else if (tagName.equals("keysets")) { 524 readKeySetListLPw(parser); 525 } 526 } 527 } 528 529 void readKeysLPw(XmlPullParser parser) 530 throws XmlPullParserException, IOException { 531 int outerDepth = parser.getDepth(); 532 int type; 533 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 534 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 535 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 536 continue; 537 } 538 final String tagName = parser.getName(); 539 if (tagName.equals("public-key")) { 540 readPublicKeyLPw(parser); 541 } else if (tagName.equals("lastIssuedKeyId")) { 542 lastIssuedKeyId = Long.parseLong(parser.getAttributeValue(null, "value")); 543 } else if (tagName.equals("lastIssuedKeySetId")) { 544 lastIssuedKeySetId = Long.parseLong(parser.getAttributeValue(null, "value")); 545 } 546 } 547 } 548 549 void readKeySetListLPw(XmlPullParser parser) 550 throws XmlPullParserException, IOException { 551 int outerDepth = parser.getDepth(); 552 int type; 553 long currentKeySetId = 0; 554 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 555 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 556 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 557 continue; 558 } 559 final String tagName = parser.getName(); 560 if (tagName.equals("keyset")) { 561 currentKeySetId = readIdentifierLPw(parser); 562 mKeySets.put(currentKeySetId, new KeySet(new Binder())); 563 mKeySetMapping.put(currentKeySetId, new HashSet<Long>()); 564 } else if (tagName.equals("key-id")) { 565 long id = readIdentifierLPw(parser); 566 mKeySetMapping.get(currentKeySetId).add(id); 567 } 568 } 569 } 570 571 long readIdentifierLPw(XmlPullParser parser) 572 throws XmlPullParserException { 573 return Long.parseLong(parser.getAttributeValue(null, "identifier")); 574 } 575 576 void readPublicKeyLPw(XmlPullParser parser) 577 throws XmlPullParserException { 578 String encodedID = parser.getAttributeValue(null, "identifier"); 579 long identifier = Long.parseLong(encodedID); 580 String encodedPublicKey = parser.getAttributeValue(null, "value"); 581 PublicKey pub = PackageParser.parsePublicKey(encodedPublicKey); 582 if (pub != null) { 583 mPublicKeys.put(identifier, pub); 584 } 585 } 586 } 587