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