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