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