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