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 com.android.internal.util.Preconditions;
24 import android.content.pm.PackageParser;
25 import android.util.ArrayMap;
26 import android.util.ArraySet;
27 import android.util.Base64;
28 import android.util.Slog;
29 import android.util.LongSparseArray;
30 
31 import java.io.IOException;
32 import java.io.PrintWriter;
33 import java.security.PublicKey;
34 import java.util.Set;
35 
36 import org.xmlpull.v1.XmlPullParser;
37 import org.xmlpull.v1.XmlPullParserException;
38 import org.xmlpull.v1.XmlSerializer;
39 
40 /*
41  * Manages system-wide KeySet state.
42  */
43 public class KeySetManagerService {
44 
45     static final String TAG = "KeySetManagerService";
46 
47     /* original keysets implementation had no versioning info, so this is the first */
48     public static final int FIRST_VERSION = 1;
49 
50     public static final int CURRENT_VERSION = FIRST_VERSION;
51 
52     /** Sentinel value returned when a {@code KeySet} is not found. */
53     public static final long KEYSET_NOT_FOUND = -1;
54 
55     /** Sentinel value returned when public key is not found. */
56     protected static final long PUBLIC_KEY_NOT_FOUND = -1;
57 
58     private final LongSparseArray<KeySetHandle> mKeySets;
59 
60     private final LongSparseArray<PublicKeyHandle> mPublicKeys;
61 
62     protected final LongSparseArray<ArraySet<Long>> mKeySetMapping;
63 
64     private final ArrayMap<String, PackageSetting> mPackages;
65 
66     private long lastIssuedKeySetId = 0;
67 
68     private long lastIssuedKeyId = 0;
69 
70     class PublicKeyHandle {
71         private final PublicKey mKey;
72         private final long mId;
73         private int mRefCount;
74 
PublicKeyHandle(long id, PublicKey key)75         public PublicKeyHandle(long id, PublicKey key) {
76             mId = id;
77             mRefCount = 1;
78             mKey = key;
79         }
80 
81         /*
82          * Only used when reading state from packages.xml
83          */
PublicKeyHandle(long id, int refCount, PublicKey key)84         private PublicKeyHandle(long id, int refCount, PublicKey key) {
85             mId = id;
86             mRefCount = refCount;
87             mKey = key;
88         }
89 
getId()90         public long getId() {
91             return mId;
92         }
93 
getKey()94         public PublicKey getKey() {
95             return mKey;
96         }
97 
getRefCountLPr()98         public int getRefCountLPr() {
99             return mRefCount;
100         }
101 
incrRefCountLPw()102         public void incrRefCountLPw() {
103             mRefCount++;
104             return;
105         }
106 
decrRefCountLPw()107         public long decrRefCountLPw() {
108             mRefCount--;
109             return mRefCount;
110         }
111     }
112 
KeySetManagerService(ArrayMap<String, PackageSetting> packages)113     public KeySetManagerService(ArrayMap<String, PackageSetting> packages) {
114         mKeySets = new LongSparseArray<KeySetHandle>();
115         mPublicKeys = new LongSparseArray<PublicKeyHandle>();
116         mKeySetMapping = new LongSparseArray<ArraySet<Long>>();
117         mPackages = packages;
118     }
119 
120     /**
121      * Determine if a package is signed by the given KeySet.
122      *
123      * Returns false if the package was not signed by all the
124      * keys in the KeySet.
125      *
126      * Returns true if the package was signed by at least the
127      * keys in the given KeySet.
128      *
129      * Note that this can return true for multiple KeySets.
130      */
packageIsSignedByLPr(String packageName, KeySetHandle ks)131     public boolean packageIsSignedByLPr(String packageName, KeySetHandle ks) {
132         PackageSetting pkg = mPackages.get(packageName);
133         if (pkg == null) {
134             throw new NullPointerException("Invalid package name");
135         }
136         if (pkg.keySetData == null) {
137             throw new NullPointerException("Package has no KeySet data");
138         }
139         long id = getIdByKeySetLPr(ks);
140         if (id == KEYSET_NOT_FOUND) {
141                 return false;
142         }
143         ArraySet<Long> pkgKeys = mKeySetMapping.get(pkg.keySetData.getProperSigningKeySet());
144         ArraySet<Long> testKeys = mKeySetMapping.get(id);
145         return pkgKeys.containsAll(testKeys);
146     }
147 
148     /**
149      * Determine if a package is signed by the given KeySet.
150      *
151      * Returns false if the package was not signed by all the
152      * keys in the KeySet, or if the package was signed by keys
153      * not in the KeySet.
154      *
155      * Note that this can return only for one KeySet.
156      */
packageIsSignedByExactlyLPr(String packageName, KeySetHandle ks)157     public boolean packageIsSignedByExactlyLPr(String packageName, KeySetHandle ks) {
158         PackageSetting pkg = mPackages.get(packageName);
159         if (pkg == null) {
160             throw new NullPointerException("Invalid package name");
161         }
162         if (pkg.keySetData == null
163             || pkg.keySetData.getProperSigningKeySet()
164             == PackageKeySetData.KEYSET_UNASSIGNED) {
165             throw new NullPointerException("Package has no KeySet data");
166          }
167         long id = getIdByKeySetLPr(ks);
168         if (id == KEYSET_NOT_FOUND) {
169                 return false;
170         }
171         ArraySet<Long> pkgKeys = mKeySetMapping.get(pkg.keySetData.getProperSigningKeySet());
172         ArraySet<Long> testKeys = mKeySetMapping.get(id);
173         return pkgKeys.equals(testKeys);
174     }
175 
176     /**
177      * addScannedPackageLPw directly modifies the package metadata in  pm.Settings
178      * at a point of no-return.  We need to make sure that the scanned package does
179      * not contain bad keyset meta-data that could generate an incorrect
180      * PackageSetting. Verify that there is a signing keyset, there are no issues
181      * with null objects, and the upgrade and defined keysets match.
182      *
183      * Returns true if the package can safely be added to the keyset metadata.
184      */
assertScannedPackageValid(PackageParser.Package pkg)185     public void assertScannedPackageValid(PackageParser.Package pkg)
186             throws PackageManagerException {
187         if (pkg == null || pkg.packageName == null) {
188             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
189                     "Passed invalid package to keyset validation.");
190         }
191         ArraySet<PublicKey> signingKeys = pkg.mSigningDetails.publicKeys;
192         if (signingKeys == null || !(signingKeys.size() > 0) || signingKeys.contains(null)) {
193             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
194                     "Package has invalid signing-key-set.");
195         }
196         ArrayMap<String, ArraySet<PublicKey>> definedMapping = pkg.mKeySetMapping;
197         if (definedMapping != null) {
198             if (definedMapping.containsKey(null) || definedMapping.containsValue(null)) {
199                 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
200                         "Package has null defined key set.");
201             }
202             int defMapSize = definedMapping.size();
203             for (int i = 0; i < defMapSize; i++) {
204                 if (!(definedMapping.valueAt(i).size() > 0)
205                         || definedMapping.valueAt(i).contains(null)) {
206                     throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
207                             "Package has null/no public keys for defined key-sets.");
208                 }
209             }
210         }
211         ArraySet<String> upgradeAliases = pkg.mUpgradeKeySets;
212         if (upgradeAliases != null) {
213             if (definedMapping == null || !(definedMapping.keySet().containsAll(upgradeAliases))) {
214                 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
215                         "Package has upgrade-key-sets without corresponding definitions.");
216             }
217         }
218     }
219 
addScannedPackageLPw(PackageParser.Package pkg)220     public void addScannedPackageLPw(PackageParser.Package pkg) {
221         Preconditions.checkNotNull(pkg, "Attempted to add null pkg to ksms.");
222         Preconditions.checkNotNull(pkg.packageName, "Attempted to add null pkg to ksms.");
223         PackageSetting ps = mPackages.get(pkg.packageName);
224         Preconditions.checkNotNull(ps, "pkg: " + pkg.packageName
225                     + "does not have a corresponding entry in mPackages.");
226         addSigningKeySetToPackageLPw(ps, pkg.mSigningDetails.publicKeys);
227         if (pkg.mKeySetMapping != null) {
228             addDefinedKeySetsToPackageLPw(ps, pkg.mKeySetMapping);
229             if (pkg.mUpgradeKeySets != null) {
230                 addUpgradeKeySetsToPackageLPw(ps, pkg.mUpgradeKeySets);
231             }
232         }
233     }
234 
235     /**
236      * Informs the system that the given package was signed by the provided KeySet.
237      */
addSigningKeySetToPackageLPw(PackageSetting pkg, ArraySet<PublicKey> signingKeys)238     void addSigningKeySetToPackageLPw(PackageSetting pkg,
239             ArraySet<PublicKey> signingKeys) {
240 
241         /* check existing keyset for reuse or removal */
242         long signingKeySetId = pkg.keySetData.getProperSigningKeySet();
243 
244         if (signingKeySetId != PackageKeySetData.KEYSET_UNASSIGNED) {
245             ArraySet<PublicKey> existingKeys = getPublicKeysFromKeySetLPr(signingKeySetId);
246             if (existingKeys != null && existingKeys.equals(signingKeys)) {
247 
248                 /* no change in signing keys, leave PackageSetting alone */
249                 return;
250             } else {
251 
252                 /* old keyset no longer valid, remove ref */
253                 decrementKeySetLPw(signingKeySetId);
254             }
255         }
256 
257         /* create and add a new keyset */
258         KeySetHandle ks = addKeySetLPw(signingKeys);
259         long id = ks.getId();
260         pkg.keySetData.setProperSigningKeySet(id);
261         return;
262     }
263 
264     /**
265      * Fetches the stable identifier associated with the given KeySet. Returns
266      * {@link #KEYSET_NOT_FOUND} if the KeySet... wasn't found.
267      */
getIdByKeySetLPr(KeySetHandle ks)268     private long getIdByKeySetLPr(KeySetHandle ks) {
269         for (int keySetIndex = 0; keySetIndex < mKeySets.size(); keySetIndex++) {
270             KeySetHandle value = mKeySets.valueAt(keySetIndex);
271             if (ks.equals(value)) {
272                 return mKeySets.keyAt(keySetIndex);
273             }
274         }
275         return KEYSET_NOT_FOUND;
276     }
277 
278     /**
279      * Inform the system that the given package defines the given KeySets.
280      * Remove any KeySets the package no longer defines.
281      */
addDefinedKeySetsToPackageLPw(PackageSetting pkg, ArrayMap<String, ArraySet<PublicKey>> definedMapping)282     void addDefinedKeySetsToPackageLPw(PackageSetting pkg,
283             ArrayMap<String, ArraySet<PublicKey>> definedMapping) {
284         ArrayMap<String, Long> prevDefinedKeySets = pkg.keySetData.getAliases();
285 
286         /* add all of the newly defined KeySets */
287         ArrayMap<String, Long> newKeySetAliases = new ArrayMap<String, Long>();
288         final int defMapSize = definedMapping.size();
289         for (int i = 0; i < defMapSize; i++) {
290             String alias = definedMapping.keyAt(i);
291             ArraySet<PublicKey> pubKeys = definedMapping.valueAt(i);
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, ArraySet<String> upgradeAliases)315     void addUpgradeKeySetsToPackageLPw(PackageSetting pkg,
316             ArraySet<String> upgradeAliases) {
317         final int uaSize = upgradeAliases.size();
318         for (int i = 0; i < uaSize; i++) {
319             pkg.keySetData.addUpgradeKeySet(upgradeAliases.valueAt(i));
320         }
321         return;
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, PackageParser.Package newPkg)367     public boolean checkUpgradeKeySetLocked(PackageSettingBase oldPS,
368             PackageParser.Package newPkg) {
369         // Upgrade keysets are being used.  Determine if new package has a superset of the
370         // required keys.
371         long[] upgradeKeySets = oldPS.keySetData.getUpgradeKeySets();
372         for (int i = 0; i < upgradeKeySets.length; i++) {
373             Set<PublicKey> upgradeSet = getPublicKeysFromKeySetLPr(upgradeKeySets[i]);
374             if (upgradeSet != null && newPkg.mSigningDetails.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         Preconditions.checkNotNull(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         Preconditions.checkNotNull(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 
encodePublicKey(PublicKey k)600     public String encodePublicKey(PublicKey k) throws IOException {
601         return new String(Base64.encode(k.getEncoded(), Base64.NO_WRAP));
602     }
603 
dumpLPr(PrintWriter pw, String packageName, DumpState dumpState)604     public void dumpLPr(PrintWriter pw, String packageName,
605                         DumpState dumpState) {
606         boolean printedHeader = false;
607         for (ArrayMap.Entry<String, PackageSetting> e : mPackages.entrySet()) {
608             String keySetPackage = e.getKey();
609             if (packageName != null && !packageName.equals(keySetPackage)) {
610                 continue;
611             }
612             if (!printedHeader) {
613                 if (dumpState.onTitlePrinted())
614                     pw.println();
615                 pw.println("Key Set Manager:");
616                 printedHeader = true;
617             }
618             PackageSetting pkg = e.getValue();
619             pw.print("  ["); pw.print(keySetPackage); pw.println("]");
620             if (pkg.keySetData != null) {
621                 boolean printedLabel = false;
622                 for (ArrayMap.Entry<String, Long> entry : pkg.keySetData.getAliases().entrySet()) {
623                     if (!printedLabel) {
624                         pw.print("      KeySets Aliases: ");
625                         printedLabel = true;
626                     } else {
627                         pw.print(", ");
628                     }
629                     pw.print(entry.getKey());
630                     pw.print('=');
631                     pw.print(Long.toString(entry.getValue()));
632                 }
633                 if (printedLabel) {
634                     pw.println("");
635                 }
636                 printedLabel = false;
637                 if (pkg.keySetData.isUsingDefinedKeySets()) {
638                     ArrayMap<String, Long> definedKeySets = pkg.keySetData.getAliases();
639                     final int dksSize = definedKeySets.size();
640                     for (int i = 0; i < dksSize; i++) {
641                         if (!printedLabel) {
642                             pw.print("      Defined KeySets: ");
643                             printedLabel = true;
644                         } else {
645                             pw.print(", ");
646                         }
647                         pw.print(Long.toString(definedKeySets.valueAt(i)));
648                     }
649                 }
650                 if (printedLabel) {
651                     pw.println("");
652                 }
653                 printedLabel = false;
654                 final long signingKeySet = pkg.keySetData.getProperSigningKeySet();
655                 pw.print("      Signing KeySets: ");
656                 pw.print(Long.toString(signingKeySet));
657                 pw.println("");
658                 if (pkg.keySetData.isUsingUpgradeKeySets()) {
659                     for (long keySetId : pkg.keySetData.getUpgradeKeySets()) {
660                         if (!printedLabel) {
661                             pw.print("      Upgrade KeySets: ");
662                             printedLabel = true;
663                         } else {
664                             pw.print(", ");
665                         }
666                         pw.print(Long.toString(keySetId));
667                     }
668                 }
669                 if (printedLabel) {
670                     pw.println("");
671                 }
672             }
673         }
674     }
675 
writeKeySetManagerServiceLPr(XmlSerializer serializer)676     void writeKeySetManagerServiceLPr(XmlSerializer serializer) throws IOException {
677         serializer.startTag(null, "keyset-settings");
678         serializer.attribute(null, "version", Integer.toString(CURRENT_VERSION));
679         writePublicKeysLPr(serializer);
680         writeKeySetsLPr(serializer);
681         serializer.startTag(null, "lastIssuedKeyId");
682         serializer.attribute(null, "value", Long.toString(lastIssuedKeyId));
683         serializer.endTag(null, "lastIssuedKeyId");
684         serializer.startTag(null, "lastIssuedKeySetId");
685         serializer.attribute(null, "value", Long.toString(lastIssuedKeySetId));
686         serializer.endTag(null, "lastIssuedKeySetId");
687         serializer.endTag(null, "keyset-settings");
688     }
689 
writePublicKeysLPr(XmlSerializer serializer)690     void writePublicKeysLPr(XmlSerializer serializer) throws IOException {
691         serializer.startTag(null, "keys");
692         for (int pKeyIndex = 0; pKeyIndex < mPublicKeys.size(); pKeyIndex++) {
693             long id = mPublicKeys.keyAt(pKeyIndex);
694             PublicKeyHandle pkh = mPublicKeys.valueAt(pKeyIndex);
695             String encodedKey = encodePublicKey(pkh.getKey());
696             serializer.startTag(null, "public-key");
697             serializer.attribute(null, "identifier", Long.toString(id));
698             serializer.attribute(null, "value", encodedKey);
699             serializer.endTag(null, "public-key");
700         }
701         serializer.endTag(null, "keys");
702     }
703 
writeKeySetsLPr(XmlSerializer serializer)704     void writeKeySetsLPr(XmlSerializer 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.attribute(null, "identifier", Long.toString(id));
711             for (long keyId : keys) {
712                 serializer.startTag(null, "key-id");
713                 serializer.attribute(null, "identifier", Long.toString(keyId));
714                 serializer.endTag(null, "key-id");
715             }
716             serializer.endTag(null, "keyset");
717         }
718         serializer.endTag(null, "keysets");
719     }
720 
readKeySetsLPw(XmlPullParser parser, ArrayMap<Long, Integer> keySetRefCounts)721     void readKeySetsLPw(XmlPullParser parser, ArrayMap<Long, Integer> keySetRefCounts)
722             throws XmlPullParserException, IOException {
723         int type;
724         long currentKeySetId = 0;
725         int outerDepth = parser.getDepth();
726         String recordedVersionStr = parser.getAttributeValue(null, "version");
727         if (recordedVersionStr == null) {
728             // The keyset information comes from pre-versioned devices, and
729             // is inaccurate, don't collect any of it.
730             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
731                     && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
732                 continue;
733             }
734             // The KeySet information read previously from packages.xml is invalid.
735             // Destroy it all.
736             for (PackageSetting p : mPackages.values()) {
737                 clearPackageKeySetDataLPw(p);
738             }
739             return;
740         }
741         int recordedVersion = Integer.parseInt(recordedVersionStr);
742         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
743                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
744             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
745                 continue;
746             }
747             final String tagName = parser.getName();
748             if (tagName.equals("keys")) {
749                 readKeysLPw(parser);
750             } else if (tagName.equals("keysets")) {
751                 readKeySetListLPw(parser);
752             } else if (tagName.equals("lastIssuedKeyId")) {
753                 lastIssuedKeyId = Long.parseLong(parser.getAttributeValue(null, "value"));
754             } else if (tagName.equals("lastIssuedKeySetId")) {
755                 lastIssuedKeySetId = Long.parseLong(parser.getAttributeValue(null, "value"));
756             }
757         }
758 
759         addRefCountsFromSavedPackagesLPw(keySetRefCounts);
760     }
761 
readKeysLPw(XmlPullParser parser)762     void readKeysLPw(XmlPullParser parser)
763             throws XmlPullParserException, IOException {
764         int outerDepth = parser.getDepth();
765         int type;
766         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
767                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
768             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
769                 continue;
770             }
771             final String tagName = parser.getName();
772             if (tagName.equals("public-key")) {
773                 readPublicKeyLPw(parser);
774             }
775         }
776     }
777 
readKeySetListLPw(XmlPullParser parser)778     void readKeySetListLPw(XmlPullParser parser)
779             throws XmlPullParserException, IOException {
780         int outerDepth = parser.getDepth();
781         int type;
782         long currentKeySetId = 0;
783         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
784                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
785             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
786                 continue;
787             }
788             final String tagName = parser.getName();
789             if (tagName.equals("keyset")) {
790                 String encodedID = parser.getAttributeValue(null, "identifier");
791                 currentKeySetId = Long.parseLong(encodedID);
792                 int refCount = 0;
793                 mKeySets.put(currentKeySetId, new KeySetHandle(currentKeySetId, refCount));
794                 mKeySetMapping.put(currentKeySetId, new ArraySet<Long>());
795             } else if (tagName.equals("key-id")) {
796                 String encodedID = parser.getAttributeValue(null, "identifier");
797                 long id = Long.parseLong(encodedID);
798                 mKeySetMapping.get(currentKeySetId).add(id);
799             }
800         }
801     }
802 
readPublicKeyLPw(XmlPullParser parser)803     void readPublicKeyLPw(XmlPullParser parser)
804             throws XmlPullParserException {
805         String encodedID = parser.getAttributeValue(null, "identifier");
806         long identifier = Long.parseLong(encodedID);
807         int refCount = 0;
808         String encodedPublicKey = parser.getAttributeValue(null, "value");
809         PublicKey pub = PackageParser.parsePublicKey(encodedPublicKey);
810         if (pub != null) {
811             PublicKeyHandle pkh = new PublicKeyHandle(identifier, refCount, pub);
812             mPublicKeys.put(identifier, pkh);
813         }
814     }
815 
816     /*
817      * Set each KeySet ref count.  Also increment all public keys in each keyset.
818      */
addRefCountsFromSavedPackagesLPw(ArrayMap<Long, Integer> keySetRefCounts)819     private void addRefCountsFromSavedPackagesLPw(ArrayMap<Long, Integer> keySetRefCounts) {
820         final int numRefCounts = keySetRefCounts.size();
821         for (int i = 0; i < numRefCounts; i++) {
822             KeySetHandle ks = mKeySets.get(keySetRefCounts.keyAt(i));
823             if (ks == null) {
824                 /* something went terribly wrong and we have references to a non-existent key-set */
825                 Slog.wtf(TAG, "Encountered non-existent key-set reference when reading settings");
826                 continue;
827             }
828             ks.setRefCountLPw(keySetRefCounts.valueAt(i));
829         }
830 
831         /*
832          * In case something went terribly wrong and we have keysets with no associated packges
833          * that refer to them, record the orphaned keyset ids, and remove them using
834          * decrementKeySetLPw() after all keyset references have been set so that the associtaed
835          * public keys have the appropriate references from all keysets.
836          */
837         ArraySet<Long> orphanedKeySets = new ArraySet<Long>();
838         final int numKeySets = mKeySets.size();
839         for (int i = 0; i < numKeySets; i++) {
840             if (mKeySets.valueAt(i).getRefCountLPr() == 0) {
841                 Slog.wtf(TAG, "Encountered key-set w/out package references when reading settings");
842                 orphanedKeySets.add(mKeySets.keyAt(i));
843             }
844             ArraySet<Long> pubKeys = mKeySetMapping.valueAt(i);
845             final int pkSize = pubKeys.size();
846             for (int j = 0; j < pkSize; j++) {
847                 mPublicKeys.get(pubKeys.valueAt(j)).incrRefCountLPw();
848             }
849         }
850         final int numOrphans = orphanedKeySets.size();
851         for (int i = 0; i < numOrphans; i++) {
852             decrementKeySetLPw(orphanedKeySets.valueAt(i));
853         }
854     }
855 }
856