blob: 49d3c8bccdff52305dd92d011a3aa5dc0cb7e3cb [file] [log] [blame]
Geremy Condraf1bcca82013-01-07 22:35:24 -08001/*
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
17package com.android.server.pm;
18
dcashman87f794f2015-06-03 14:46:47 -070019import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
20
21import com.android.internal.util.Preconditions;
Geremy Condraf1bcca82013-01-07 22:35:24 -080022import android.content.pm.PackageParser;
dcashman8c04fac2015-03-23 11:39:42 -070023import android.util.ArrayMap;
dcashman55b10782014-04-09 14:20:38 -070024import android.util.ArraySet;
Geremy Condraf1bcca82013-01-07 22:35:24 -080025import android.util.Base64;
dcashman55b10782014-04-09 14:20:38 -070026import android.util.Slog;
Geremy Condraf1bcca82013-01-07 22:35:24 -080027import android.util.LongSparseArray;
28
29import java.io.IOException;
30import java.io.PrintWriter;
31import java.security.PublicKey;
Geremy Condraf1bcca82013-01-07 22:35:24 -080032import java.util.Set;
33
34import org.xmlpull.v1.XmlPullParser;
35import org.xmlpull.v1.XmlPullParserException;
36import org.xmlpull.v1.XmlSerializer;
37
38/*
39 * Manages system-wide KeySet state.
40 */
dcashman55b10782014-04-09 14:20:38 -070041public class KeySetManagerService {
Geremy Condraf1bcca82013-01-07 22:35:24 -080042
dcashman55b10782014-04-09 14:20:38 -070043 static final String TAG = "KeySetManagerService";
44
45 /* original keysets implementation had no versioning info, so this is the first */
46 public static final int FIRST_VERSION = 1;
47
48 public static final int CURRENT_VERSION = FIRST_VERSION;
Geremy Condraf1bcca82013-01-07 22:35:24 -080049
Kenny Root9a995f52013-07-08 09:33:22 -070050 /** Sentinel value returned when a {@code KeySet} is not found. */
51 public static final long KEYSET_NOT_FOUND = -1;
52
53 /** Sentinel value returned when public key is not found. */
dcashman55b10782014-04-09 14:20:38 -070054 protected static final long PUBLIC_KEY_NOT_FOUND = -1;
Geremy Condraf1bcca82013-01-07 22:35:24 -080055
dcashman9d2f4412014-06-09 09:27:54 -070056 private final LongSparseArray<KeySetHandle> mKeySets;
Geremy Condraf1bcca82013-01-07 22:35:24 -080057
dcashman8c04fac2015-03-23 11:39:42 -070058 private final LongSparseArray<PublicKeyHandle> mPublicKeys;
Geremy Condraf1bcca82013-01-07 22:35:24 -080059
dcashmand79fdf12014-06-20 15:53:06 -070060 protected final LongSparseArray<ArraySet<Long>> mKeySetMapping;
Geremy Condraf1bcca82013-01-07 22:35:24 -080061
dcashman8c04fac2015-03-23 11:39:42 -070062 private final ArrayMap<String, PackageSetting> mPackages;
Geremy Condraf1bcca82013-01-07 22:35:24 -080063
dcashman79d37cb2015-04-27 10:42:22 -070064 private long lastIssuedKeySetId = 0;
Geremy Condraf1bcca82013-01-07 22:35:24 -080065
dcashman79d37cb2015-04-27 10:42:22 -070066 private long lastIssuedKeyId = 0;
Geremy Condraf1bcca82013-01-07 22:35:24 -080067
dcashman8c04fac2015-03-23 11:39:42 -070068 class PublicKeyHandle {
69 private final PublicKey mKey;
70 private final long mId;
71 private int mRefCount;
72
73 public PublicKeyHandle(long id, PublicKey key) {
74 mId = id;
75 mRefCount = 1;
76 mKey = key;
77 }
78
79 /*
80 * Only used when reading state from packages.xml
81 */
82 private PublicKeyHandle(long id, int refCount, PublicKey key) {
83 mId = id;
84 mRefCount = refCount;
85 mKey = key;
86 }
87
88 public long getId() {
89 return mId;
90 }
91
92 public PublicKey getKey() {
93 return mKey;
94 }
95
96 public int getRefCountLPr() {
97 return mRefCount;
98 }
99
100 public void incrRefCountLPw() {
101 mRefCount++;
102 return;
103 }
dcashman87f794f2015-06-03 14:46:47 -0700104
dcashman8c04fac2015-03-23 11:39:42 -0700105 public long decrRefCountLPw() {
106 mRefCount--;
107 return mRefCount;
108 }
109 }
110
111 public KeySetManagerService(ArrayMap<String, PackageSetting> packages) {
dcashman9d2f4412014-06-09 09:27:54 -0700112 mKeySets = new LongSparseArray<KeySetHandle>();
dcashman8c04fac2015-03-23 11:39:42 -0700113 mPublicKeys = new LongSparseArray<PublicKeyHandle>();
dcashmand79fdf12014-06-20 15:53:06 -0700114 mKeySetMapping = new LongSparseArray<ArraySet<Long>>();
Geremy Condraf1bcca82013-01-07 22:35:24 -0800115 mPackages = packages;
116 }
117
Kenny Root2042e9d2013-07-08 09:31:31 -0700118 /**
Geremy Condraf1bcca82013-01-07 22:35:24 -0800119 * Determine if a package is signed by the given KeySet.
120 *
121 * Returns false if the package was not signed by all the
122 * keys in the KeySet.
123 *
124 * Returns true if the package was signed by at least the
125 * keys in the given KeySet.
126 *
127 * Note that this can return true for multiple KeySets.
128 */
dcashman9d2f4412014-06-09 09:27:54 -0700129 public boolean packageIsSignedByLPr(String packageName, KeySetHandle ks) {
dcashmand79fdf12014-06-20 15:53:06 -0700130 PackageSetting pkg = mPackages.get(packageName);
131 if (pkg == null) {
132 throw new NullPointerException("Invalid package name");
Geremy Condraf1bcca82013-01-07 22:35:24 -0800133 }
dcashmand79fdf12014-06-20 15:53:06 -0700134 if (pkg.keySetData == null) {
135 throw new NullPointerException("Package has no KeySet data");
136 }
137 long id = getIdByKeySetLPr(ks);
dcashman9d2f4412014-06-09 09:27:54 -0700138 if (id == KEYSET_NOT_FOUND) {
139 return false;
140 }
dcashman8c04fac2015-03-23 11:39:42 -0700141 ArraySet<Long> pkgKeys = mKeySetMapping.get(pkg.keySetData.getProperSigningKeySet());
142 ArraySet<Long> testKeys = mKeySetMapping.get(id);
143 return pkgKeys.containsAll(testKeys);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800144 }
145
Kenny Root2042e9d2013-07-08 09:31:31 -0700146 /**
dcashman9d2f4412014-06-09 09:27:54 -0700147 * Determine if a package is signed by the given KeySet.
148 *
149 * Returns false if the package was not signed by all the
150 * keys in the KeySet, or if the package was signed by keys
151 * not in the KeySet.
152 *
153 * Note that this can return only for one KeySet.
154 */
155 public boolean packageIsSignedByExactlyLPr(String packageName, KeySetHandle ks) {
156 PackageSetting pkg = mPackages.get(packageName);
157 if (pkg == null) {
158 throw new NullPointerException("Invalid package name");
159 }
160 if (pkg.keySetData == null
161 || pkg.keySetData.getProperSigningKeySet()
162 == PackageKeySetData.KEYSET_UNASSIGNED) {
163 throw new NullPointerException("Package has no KeySet data");
dcashman8c04fac2015-03-23 11:39:42 -0700164 }
dcashman9d2f4412014-06-09 09:27:54 -0700165 long id = getIdByKeySetLPr(ks);
dcashman8c04fac2015-03-23 11:39:42 -0700166 if (id == KEYSET_NOT_FOUND) {
167 return false;
168 }
169 ArraySet<Long> pkgKeys = mKeySetMapping.get(pkg.keySetData.getProperSigningKeySet());
170 ArraySet<Long> testKeys = mKeySetMapping.get(id);
171 return pkgKeys.equals(testKeys);
dcashman9d2f4412014-06-09 09:27:54 -0700172 }
173
174 /**
dcashman87f794f2015-06-03 14:46:47 -0700175 * addScannedPackageLPw directly modifies the package metadata in pm.Settings
176 * at a point of no-return. We need to make sure that the scanned package does
177 * not contain bad keyset meta-data that could generate an incorrect
178 * PackageSetting. Verify that there is a signing keyset, there are no issues
179 * with null objects, and the upgrade and defined keysets match.
180 *
181 * Returns true if the package can safely be added to the keyset metadata.
182 */
183 public void assertScannedPackageValid(PackageParser.Package pkg)
184 throws PackageManagerException {
185 if (pkg == null || pkg.packageName == null) {
186 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
187 "Passed invalid package to keyset validation.");
188 }
189 ArraySet<PublicKey> signingKeys = pkg.mSigningKeys;
190 if (signingKeys == null || !(signingKeys.size() > 0) || signingKeys.contains(null)) {
191 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
192 "Package has invalid signing-key-set.");
193 }
194 ArrayMap<String, ArraySet<PublicKey>> definedMapping = pkg.mKeySetMapping;
195 if (definedMapping != null) {
196 if (definedMapping.containsKey(null) || definedMapping.containsValue(null)) {
197 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
198 "Package has null defined key set.");
199 }
200 int defMapSize = definedMapping.size();
201 for (int i = 0; i < defMapSize; i++) {
202 if (!(definedMapping.valueAt(i).size() > 0)
203 || definedMapping.valueAt(i).contains(null)) {
204 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
205 "Package has null/no public keys for defined key-sets.");
206 }
207 }
208 }
209 ArraySet<String> upgradeAliases = pkg.mUpgradeKeySets;
210 if (upgradeAliases != null) {
211 if (definedMapping == null || !(definedMapping.keySet().containsAll(upgradeAliases))) {
212 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
213 "Package has upgrade-key-sets without corresponding definitions.");
214 }
215 }
216 }
217
218 public void addScannedPackageLPw(PackageParser.Package pkg) {
219 Preconditions.checkNotNull(pkg, "Attempted to add null pkg to ksms.");
220 Preconditions.checkNotNull(pkg.packageName, "Attempted to add null pkg to ksms.");
221 PackageSetting ps = mPackages.get(pkg.packageName);
222 Preconditions.checkNotNull(ps, "pkg: " + pkg.packageName
223 + "does not have a corresponding entry in mPackages.");
224 addSigningKeySetToPackageLPw(ps, pkg.mSigningKeys);
225 if (pkg.mKeySetMapping != null) {
226 addDefinedKeySetsToPackageLPw(ps, pkg.mKeySetMapping);
227 if (pkg.mUpgradeKeySets != null) {
228 addUpgradeKeySetsToPackageLPw(ps, pkg.mUpgradeKeySets);
229 }
230 }
231 }
232
233 /**
dcashman8c04fac2015-03-23 11:39:42 -0700234 * Informs the system that the given package was signed by the provided KeySet.
Geremy Condraf1bcca82013-01-07 22:35:24 -0800235 */
dcashman87f794f2015-06-03 14:46:47 -0700236 void addSigningKeySetToPackageLPw(PackageSetting pkg,
dcashman9d2f4412014-06-09 09:27:54 -0700237 ArraySet<PublicKey> signingKeys) {
dcashman8c04fac2015-03-23 11:39:42 -0700238
239 /* check existing keyset for reuse or removal */
dcashman8c04fac2015-03-23 11:39:42 -0700240 long signingKeySetId = pkg.keySetData.getProperSigningKeySet();
241
242 if (signingKeySetId != PackageKeySetData.KEYSET_UNASSIGNED) {
243 ArraySet<PublicKey> existingKeys = getPublicKeysFromKeySetLPr(signingKeySetId);
dcashman87f794f2015-06-03 14:46:47 -0700244 if (existingKeys != null && existingKeys.equals(signingKeys)) {
dcashman8c04fac2015-03-23 11:39:42 -0700245
246 /* no change in signing keys, leave PackageSetting alone */
247 return;
248 } else {
249
250 /* old keyset no longer valid, remove ref */
dcashman8c04fac2015-03-23 11:39:42 -0700251 decrementKeySetLPw(signingKeySetId);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800252 }
253 }
dcashman8c04fac2015-03-23 11:39:42 -0700254
255 /* create and add a new keyset */
256 KeySetHandle ks = addKeySetLPw(signingKeys);
257 long id = ks.getId();
258 pkg.keySetData.setProperSigningKeySet(id);
259 return;
Geremy Condraf1bcca82013-01-07 22:35:24 -0800260 }
261
Kenny Root2042e9d2013-07-08 09:31:31 -0700262 /**
263 * Fetches the stable identifier associated with the given KeySet. Returns
264 * {@link #KEYSET_NOT_FOUND} if the KeySet... wasn't found.
Geremy Condraf1bcca82013-01-07 22:35:24 -0800265 */
dcashman9d2f4412014-06-09 09:27:54 -0700266 private long getIdByKeySetLPr(KeySetHandle ks) {
Geremy Condraf1bcca82013-01-07 22:35:24 -0800267 for (int keySetIndex = 0; keySetIndex < mKeySets.size(); keySetIndex++) {
dcashman9d2f4412014-06-09 09:27:54 -0700268 KeySetHandle value = mKeySets.valueAt(keySetIndex);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800269 if (ks.equals(value)) {
270 return mKeySets.keyAt(keySetIndex);
271 }
272 }
273 return KEYSET_NOT_FOUND;
274 }
275
dcashman87f794f2015-06-03 14:46:47 -0700276 /**
dcashman8c04fac2015-03-23 11:39:42 -0700277 * Inform the system that the given package defines the given KeySets.
278 * Remove any KeySets the package no longer defines.
Geremy Condraf1bcca82013-01-07 22:35:24 -0800279 */
dcashman87f794f2015-06-03 14:46:47 -0700280 void addDefinedKeySetsToPackageLPw(PackageSetting pkg,
dcashman8c04fac2015-03-23 11:39:42 -0700281 ArrayMap<String, ArraySet<PublicKey>> definedMapping) {
dcashman8c04fac2015-03-23 11:39:42 -0700282 ArrayMap<String, Long> prevDefinedKeySets = pkg.keySetData.getAliases();
283
284 /* add all of the newly defined KeySets */
285 ArrayMap<String, Long> newKeySetAliases = new ArrayMap<String, Long>();
286 final int defMapSize = definedMapping.size();
287 for (int i = 0; i < defMapSize; i++) {
288 String alias = definedMapping.keyAt(i);
289 ArraySet<PublicKey> pubKeys = definedMapping.valueAt(i);
Thecrazyskull7664bce2017-01-26 08:59:51 -0600290 if (alias != null && pubKeys != null && pubKeys.size() > 0) {
dcashman8c04fac2015-03-23 11:39:42 -0700291 KeySetHandle ks = addKeySetLPw(pubKeys);
292 newKeySetAliases.put(alias, ks.getId());
293 }
294 }
295
296 /* remove each of the old references */
297 final int prevDefSize = prevDefinedKeySets.size();
298 for (int i = 0; i < prevDefSize; i++) {
299 decrementKeySetLPw(prevDefinedKeySets.valueAt(i));
300 }
301 pkg.keySetData.removeAllUpgradeKeySets();
302
303 /* switch to the just-added */
304 pkg.keySetData.setAliases(newKeySetAliases);
305 return;
Geremy Condraf1bcca82013-01-07 22:35:24 -0800306 }
307
Kenny Root2042e9d2013-07-08 09:31:31 -0700308 /**
dcashman8c04fac2015-03-23 11:39:42 -0700309 * This informs the system that the given package has defined a KeySet
310 * alias in its manifest to be an upgradeKeySet. This must be called
311 * after all of the defined KeySets have been added.
312 */
dcashman87f794f2015-06-03 14:46:47 -0700313 void addUpgradeKeySetsToPackageLPw(PackageSetting pkg,
314 ArraySet<String> upgradeAliases) {
dcashman8c04fac2015-03-23 11:39:42 -0700315 final int uaSize = upgradeAliases.size();
316 for (int i = 0; i < uaSize; i++) {
317 pkg.keySetData.addUpgradeKeySet(upgradeAliases.valueAt(i));
318 }
319 return;
320 }
321
322 /**
323 * Fetched the {@link KeySetHandle} that a given package refers to by the
324 * provided alias. Returns null if the package is unknown or does not have a
dcashman9d2f4412014-06-09 09:27:54 -0700325 * KeySet corresponding to that alias.
Geremy Condraf1bcca82013-01-07 22:35:24 -0800326 */
dcashman9d2f4412014-06-09 09:27:54 -0700327 public KeySetHandle getKeySetByAliasAndPackageNameLPr(String packageName, String alias) {
dcashmand79fdf12014-06-20 15:53:06 -0700328 PackageSetting p = mPackages.get(packageName);
dcashman9d2f4412014-06-09 09:27:54 -0700329 if (p == null || p.keySetData == null) {
dcashman8c04fac2015-03-23 11:39:42 -0700330 return null;
Geremy Condraf1bcca82013-01-07 22:35:24 -0800331 }
dcashman9d2f4412014-06-09 09:27:54 -0700332 Long keySetId = p.keySetData.getAliases().get(alias);
333 if (keySetId == null) {
334 throw new IllegalArgumentException("Unknown KeySet alias: " + alias);
dcashmand79fdf12014-06-20 15:53:06 -0700335 }
dcashmand79fdf12014-06-20 15:53:06 -0700336 return mKeySets.get(keySetId);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800337 }
338
dcashman465ef5c2015-06-11 15:22:05 -0700339 /* Checks if an identifier refers to a known keyset */
340 public boolean isIdValidKeySetId(long id) {
341 return mKeySets.get(id) != null;
342 }
343
Kenny Root2042e9d2013-07-08 09:31:31 -0700344 /**
dcashman55b10782014-04-09 14:20:38 -0700345 * Fetches the {@link PublicKey public keys} which belong to the specified
346 * KeySet id.
347 *
348 * Returns {@code null} if the identifier doesn't
dcashman9d2f4412014-06-09 09:27:54 -0700349 * identify a {@link KeySetHandle}.
dcashman55b10782014-04-09 14:20:38 -0700350 */
dcashmand79fdf12014-06-20 15:53:06 -0700351 public ArraySet<PublicKey> getPublicKeysFromKeySetLPr(long id) {
dcashman87f794f2015-06-03 14:46:47 -0700352 ArraySet<Long> pkIds = mKeySetMapping.get(id);
353 if (pkIds == null) {
dcashmand79fdf12014-06-20 15:53:06 -0700354 return null;
dcashman55b10782014-04-09 14:20:38 -0700355 }
dcashmand79fdf12014-06-20 15:53:06 -0700356 ArraySet<PublicKey> mPubKeys = new ArraySet<PublicKey>();
dcashman8c04fac2015-03-23 11:39:42 -0700357 final int pkSize = pkIds.size();
358 for (int i = 0; i < pkSize; i++) {
359 mPubKeys.add(mPublicKeys.get(pkIds.valueAt(i)).getKey());
dcashmand79fdf12014-06-20 15:53:06 -0700360 }
361 return mPubKeys;
dcashman55b10782014-04-09 14:20:38 -0700362 }
363
364 /**
dcashman9d2f4412014-06-09 09:27:54 -0700365 * Fetches the proper {@link KeySetHandle KeySet} that signed the given
dcashman55b10782014-04-09 14:20:38 -0700366 * package.
367 *
368 * @throws IllegalArgumentException if the package has no keyset data.
dcashman8c04fac2015-03-23 11:39:42 -0700369 * @throws NullPointerException if the packgae is unknown.
Geremy Condraf1bcca82013-01-07 22:35:24 -0800370 */
dcashman9d2f4412014-06-09 09:27:54 -0700371 public KeySetHandle getSigningKeySetByPackageNameLPr(String packageName) {
dcashmand79fdf12014-06-20 15:53:06 -0700372 PackageSetting p = mPackages.get(packageName);
dcashman9d2f4412014-06-09 09:27:54 -0700373 if (p == null
374 || p.keySetData == null
375 || p.keySetData.getProperSigningKeySet()
376 == PackageKeySetData.KEYSET_UNASSIGNED) {
377 return null;
dcashman55b10782014-04-09 14:20:38 -0700378 }
dcashman9d2f4412014-06-09 09:27:54 -0700379 return mKeySets.get(p.keySetData.getProperSigningKeySet());
dcashman55b10782014-04-09 14:20:38 -0700380 }
381
382 /**
Geremy Condraf1bcca82013-01-07 22:35:24 -0800383 * Creates a new KeySet corresponding to the given keys.
384 *
Kenny Root2042e9d2013-07-08 09:31:31 -0700385 * If the {@link PublicKey PublicKeys} aren't known to the system, this
dcashman8c04fac2015-03-23 11:39:42 -0700386 * adds them. Otherwise, they're deduped and the reference count
387 * incremented.
Geremy Condraf1bcca82013-01-07 22:35:24 -0800388 *
389 * If the KeySet isn't known to the system, this adds that and creates the
dcashman8c04fac2015-03-23 11:39:42 -0700390 * mapping to the PublicKeys. If it is known, then it's deduped and the
391 * reference count is incremented.
dcashman55b10782014-04-09 14:20:38 -0700392 *
Kenny Root2042e9d2013-07-08 09:31:31 -0700393 * Throws if the provided set is {@code null}.
Geremy Condraf1bcca82013-01-07 22:35:24 -0800394 */
dcashman9d2f4412014-06-09 09:27:54 -0700395 private KeySetHandle addKeySetLPw(ArraySet<PublicKey> keys) {
dcashman8c04fac2015-03-23 11:39:42 -0700396 if (keys == null || keys.size() == 0) {
397 throw new IllegalArgumentException("Cannot add an empty set of keys!");
Geremy Condraf1bcca82013-01-07 22:35:24 -0800398 }
dcashman8c04fac2015-03-23 11:39:42 -0700399
400 /* add each of the keys in the provided set */
dcashmand79fdf12014-06-20 15:53:06 -0700401 ArraySet<Long> addedKeyIds = new ArraySet<Long>(keys.size());
dcashman8c04fac2015-03-23 11:39:42 -0700402 final int kSize = keys.size();
403 for (int i = 0; i < kSize; i++) {
404 long id = addPublicKeyLPw(keys.valueAt(i));
Geremy Condraf1bcca82013-01-07 22:35:24 -0800405 addedKeyIds.add(id);
406 }
407
dcashman8c04fac2015-03-23 11:39:42 -0700408 /* check to see if the resulting keyset is new */
dcashmand79fdf12014-06-20 15:53:06 -0700409 long existingKeySetId = getIdFromKeyIdsLPr(addedKeyIds);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800410 if (existingKeySetId != KEYSET_NOT_FOUND) {
dcashman8c04fac2015-03-23 11:39:42 -0700411
412 /* public keys were incremented, but we aren't adding a new keyset: undo */
413 for (int i = 0; i < kSize; i++) {
414 decrementPublicKeyLPw(addedKeyIds.valueAt(i));
415 }
416 KeySetHandle ks = mKeySets.get(existingKeySetId);
417 ks.incrRefCountLPw();
418 return ks;
Geremy Condraf1bcca82013-01-07 22:35:24 -0800419 }
420
dcashman8c04fac2015-03-23 11:39:42 -0700421 // get the next keyset id
dcashmand79fdf12014-06-20 15:53:06 -0700422 long id = getFreeKeySetIDLPw();
dcashman8c04fac2015-03-23 11:39:42 -0700423
424 // create the KeySet object and add to mKeySets and mapping
425 KeySetHandle ks = new KeySetHandle(id);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800426 mKeySets.put(id, ks);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800427 mKeySetMapping.put(id, addedKeyIds);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800428 return ks;
429 }
430
dcashman8c04fac2015-03-23 11:39:42 -0700431 /*
432 * Decrements the reference to KeySet represented by the given id. If this
433 * drops to zero, then also decrement the reference to each public key it
434 * contains and remove the KeySet.
435 */
436 private void decrementKeySetLPw(long id) {
437 KeySetHandle ks = mKeySets.get(id);
dcashman87f794f2015-06-03 14:46:47 -0700438 if (ks == null) {
439 /* nothing to do */
440 return;
441 }
dcashman8c04fac2015-03-23 11:39:42 -0700442 if (ks.decrRefCountLPw() <= 0) {
443 ArraySet<Long> pubKeys = mKeySetMapping.get(id);
444 final int pkSize = pubKeys.size();
445 for (int i = 0; i < pkSize; i++) {
446 decrementPublicKeyLPw(pubKeys.valueAt(i));
447 }
448 mKeySets.delete(id);
449 mKeySetMapping.delete(id);
450 }
dcashman8c04fac2015-03-23 11:39:42 -0700451 }
452
453 /*
454 * Decrements the reference to PublicKey represented by the given id. If
455 * this drops to zero, then remove it.
456 */
457 private void decrementPublicKeyLPw(long id) {
458 PublicKeyHandle pk = mPublicKeys.get(id);
dcashman87f794f2015-06-03 14:46:47 -0700459 if (pk == null) {
460 /* nothing to do */
461 return;
462 }
dcashman8c04fac2015-03-23 11:39:42 -0700463 if (pk.decrRefCountLPw() <= 0) {
464 mPublicKeys.delete(id);
465 }
dcashman8c04fac2015-03-23 11:39:42 -0700466 }
467
Kenny Root2042e9d2013-07-08 09:31:31 -0700468 /**
Geremy Condraf1bcca82013-01-07 22:35:24 -0800469 * Adds the given PublicKey to the system, deduping as it goes.
470 */
dcashmand79fdf12014-06-20 15:53:06 -0700471 private long addPublicKeyLPw(PublicKey key) {
dcashman87f794f2015-06-03 14:46:47 -0700472 Preconditions.checkNotNull(key, "Cannot add null public key!");
dcashman8c04fac2015-03-23 11:39:42 -0700473 long id = getIdForPublicKeyLPr(key);
474 if (id != PUBLIC_KEY_NOT_FOUND) {
475
476 /* We already know about this key, increment its ref count and ret */
477 mPublicKeys.get(id).incrRefCountLPw();
478 return id;
Geremy Condraf1bcca82013-01-07 22:35:24 -0800479 }
dcashman8c04fac2015-03-23 11:39:42 -0700480
481 /* if it's new find the first unoccupied slot in the public keys */
482 id = getFreePublicKeyIdLPw();
483 mPublicKeys.put(id, new PublicKeyHandle(id, key));
Geremy Condraf1bcca82013-01-07 22:35:24 -0800484 return id;
485 }
486
Kenny Root2042e9d2013-07-08 09:31:31 -0700487 /**
Geremy Condraf1bcca82013-01-07 22:35:24 -0800488 * Finds the stable identifier for a KeySet based on a set of PublicKey stable IDs.
489 *
490 * Returns KEYSET_NOT_FOUND if there isn't one.
491 */
dcashmand79fdf12014-06-20 15:53:06 -0700492 private long getIdFromKeyIdsLPr(Set<Long> publicKeyIds) {
Geremy Condraf1bcca82013-01-07 22:35:24 -0800493 for (int keyMapIndex = 0; keyMapIndex < mKeySetMapping.size(); keyMapIndex++) {
dcashman9d2f4412014-06-09 09:27:54 -0700494 ArraySet<Long> value = mKeySetMapping.valueAt(keyMapIndex);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800495 if (value.equals(publicKeyIds)) {
496 return mKeySetMapping.keyAt(keyMapIndex);
497 }
498 }
499 return KEYSET_NOT_FOUND;
500 }
501
Kenny Root2042e9d2013-07-08 09:31:31 -0700502 /**
Geremy Condraf1bcca82013-01-07 22:35:24 -0800503 * Finds the stable identifier for a PublicKey or PUBLIC_KEY_NOT_FOUND.
504 */
dcashmand79fdf12014-06-20 15:53:06 -0700505 private long getIdForPublicKeyLPr(PublicKey k) {
Geremy Condraf1bcca82013-01-07 22:35:24 -0800506 String encodedPublicKey = new String(k.getEncoded());
507 for (int publicKeyIndex = 0; publicKeyIndex < mPublicKeys.size(); publicKeyIndex++) {
dcashman8c04fac2015-03-23 11:39:42 -0700508 PublicKey value = mPublicKeys.valueAt(publicKeyIndex).getKey();
Geremy Condraf1bcca82013-01-07 22:35:24 -0800509 String encodedExistingKey = new String(value.getEncoded());
510 if (encodedPublicKey.equals(encodedExistingKey)) {
511 return mPublicKeys.keyAt(publicKeyIndex);
512 }
513 }
514 return PUBLIC_KEY_NOT_FOUND;
515 }
516
Kenny Root2042e9d2013-07-08 09:31:31 -0700517 /**
Geremy Condraf1bcca82013-01-07 22:35:24 -0800518 * Gets an unused stable identifier for a KeySet.
519 */
dcashmand79fdf12014-06-20 15:53:06 -0700520 private long getFreeKeySetIDLPw() {
Geremy Condraf1bcca82013-01-07 22:35:24 -0800521 lastIssuedKeySetId += 1;
522 return lastIssuedKeySetId;
523 }
524
Kenny Root2042e9d2013-07-08 09:31:31 -0700525 /**
Geremy Condraf1bcca82013-01-07 22:35:24 -0800526 * Same as above, but for public keys.
527 */
dcashmand79fdf12014-06-20 15:53:06 -0700528 private long getFreePublicKeyIdLPw() {
Geremy Condraf1bcca82013-01-07 22:35:24 -0800529 lastIssuedKeyId += 1;
530 return lastIssuedKeyId;
531 }
532
dcashman8c04fac2015-03-23 11:39:42 -0700533 /*
534 * This package is being removed from the system, so we need to
535 * remove its keyset and public key references, then remove its
536 * keyset data.
537 */
dcashmand79fdf12014-06-20 15:53:06 -0700538 public void removeAppKeySetDataLPw(String packageName) {
dcashman8c04fac2015-03-23 11:39:42 -0700539
540 /* remove refs from common keysets and public keys */
541 PackageSetting pkg = mPackages.get(packageName);
dcashman87f794f2015-06-03 14:46:47 -0700542 Preconditions.checkNotNull(pkg, "pkg name: " + packageName
543 + "does not have a corresponding entry in mPackages.");
dcashman8c04fac2015-03-23 11:39:42 -0700544 long signingKeySetId = pkg.keySetData.getProperSigningKeySet();
545 decrementKeySetLPw(signingKeySetId);
546 ArrayMap<String, Long> definedKeySets = pkg.keySetData.getAliases();
547 for (int i = 0; i < definedKeySets.size(); i++) {
548 decrementKeySetLPw(definedKeySets.valueAt(i));
dcashmand79fdf12014-06-20 15:53:06 -0700549 }
550
dcashman8c04fac2015-03-23 11:39:42 -0700551 /* remove from package */
552 clearPackageKeySetDataLPw(pkg);
dcashman55b10782014-04-09 14:20:38 -0700553 return;
554 }
555
dcashman8c04fac2015-03-23 11:39:42 -0700556 private void clearPackageKeySetDataLPw(PackageSetting pkg) {
557 pkg.keySetData.setProperSigningKeySet(PackageKeySetData.KEYSET_UNASSIGNED);
558 pkg.keySetData.removeAllDefinedKeySets();
559 pkg.keySetData.removeAllUpgradeKeySets();
560 return;
Geremy Condraf1bcca82013-01-07 22:35:24 -0800561 }
562
563 public String encodePublicKey(PublicKey k) throws IOException {
dcashman8a331212015-04-24 10:52:56 -0700564 return new String(Base64.encode(k.getEncoded(), Base64.NO_WRAP));
Geremy Condraf1bcca82013-01-07 22:35:24 -0800565 }
566
dcashmand79fdf12014-06-20 15:53:06 -0700567 public void dumpLPr(PrintWriter pw, String packageName,
568 PackageManagerService.DumpState dumpState) {
569 boolean printedHeader = false;
dcashman8c04fac2015-03-23 11:39:42 -0700570 for (ArrayMap.Entry<String, PackageSetting> e : mPackages.entrySet()) {
dcashmand79fdf12014-06-20 15:53:06 -0700571 String keySetPackage = e.getKey();
572 if (packageName != null && !packageName.equals(keySetPackage)) {
573 continue;
574 }
575 if (!printedHeader) {
576 if (dumpState.onTitlePrinted())
577 pw.println();
578 pw.println("Key Set Manager:");
579 printedHeader = true;
580 }
581 PackageSetting pkg = e.getValue();
582 pw.print(" ["); pw.print(keySetPackage); pw.println("]");
583 if (pkg.keySetData != null) {
584 boolean printedLabel = false;
dcashman8c04fac2015-03-23 11:39:42 -0700585 for (ArrayMap.Entry<String, Long> entry : pkg.keySetData.getAliases().entrySet()) {
dcashmand79fdf12014-06-20 15:53:06 -0700586 if (!printedLabel) {
587 pw.print(" KeySets Aliases: ");
588 printedLabel = true;
589 } else {
590 pw.print(", ");
591 }
592 pw.print(entry.getKey());
593 pw.print('=');
594 pw.print(Long.toString(entry.getValue()));
Dianne Hackborncbfd23e2013-06-11 14:26:53 -0700595 }
dcashmand79fdf12014-06-20 15:53:06 -0700596 if (printedLabel) {
597 pw.println("");
Dianne Hackborncbfd23e2013-06-11 14:26:53 -0700598 }
dcashmand79fdf12014-06-20 15:53:06 -0700599 printedLabel = false;
600 if (pkg.keySetData.isUsingDefinedKeySets()) {
dcashman8c04fac2015-03-23 11:39:42 -0700601 ArrayMap<String, Long> definedKeySets = pkg.keySetData.getAliases();
602 final int dksSize = definedKeySets.size();
603 for (int i = 0; i < dksSize; i++) {
Kenny Rootdf0e6ab2013-07-03 13:38:31 -0700604 if (!printedLabel) {
dcashmand79fdf12014-06-20 15:53:06 -0700605 pw.print(" Defined KeySets: ");
Dianne Hackborncbfd23e2013-06-11 14:26:53 -0700606 printedLabel = true;
607 } else {
608 pw.print(", ");
609 }
dcashman8c04fac2015-03-23 11:39:42 -0700610 pw.print(Long.toString(definedKeySets.valueAt(i)));
Geremy Condraf1bcca82013-01-07 22:35:24 -0800611 }
dcashmand79fdf12014-06-20 15:53:06 -0700612 }
613 if (printedLabel) {
614 pw.println("");
615 }
616 printedLabel = false;
dcashman8c04fac2015-03-23 11:39:42 -0700617 final long signingKeySet = pkg.keySetData.getProperSigningKeySet();
618 pw.print(" Signing KeySets: ");
619 pw.print(Long.toString(signingKeySet));
620 pw.println("");
dcashmand79fdf12014-06-20 15:53:06 -0700621 if (pkg.keySetData.isUsingUpgradeKeySets()) {
622 for (long keySetId : pkg.keySetData.getUpgradeKeySets()) {
623 if (!printedLabel) {
624 pw.print(" Upgrade KeySets: ");
625 printedLabel = true;
626 } else {
627 pw.print(", ");
dcashman55b10782014-04-09 14:20:38 -0700628 }
dcashmand79fdf12014-06-20 15:53:06 -0700629 pw.print(Long.toString(keySetId));
dcashman55b10782014-04-09 14:20:38 -0700630 }
dcashmand79fdf12014-06-20 15:53:06 -0700631 }
632 if (printedLabel) {
633 pw.println("");
Geremy Condraf1bcca82013-01-07 22:35:24 -0800634 }
635 }
636 }
637 }
638
dcashman55b10782014-04-09 14:20:38 -0700639 void writeKeySetManagerServiceLPr(XmlSerializer serializer) throws IOException {
Geremy Condraf1bcca82013-01-07 22:35:24 -0800640 serializer.startTag(null, "keyset-settings");
dcashman55b10782014-04-09 14:20:38 -0700641 serializer.attribute(null, "version", Integer.toString(CURRENT_VERSION));
Geremy Condraf1bcca82013-01-07 22:35:24 -0800642 writePublicKeysLPr(serializer);
643 writeKeySetsLPr(serializer);
644 serializer.startTag(null, "lastIssuedKeyId");
645 serializer.attribute(null, "value", Long.toString(lastIssuedKeyId));
646 serializer.endTag(null, "lastIssuedKeyId");
647 serializer.startTag(null, "lastIssuedKeySetId");
648 serializer.attribute(null, "value", Long.toString(lastIssuedKeySetId));
649 serializer.endTag(null, "lastIssuedKeySetId");
650 serializer.endTag(null, "keyset-settings");
651 }
652
653 void writePublicKeysLPr(XmlSerializer serializer) throws IOException {
654 serializer.startTag(null, "keys");
655 for (int pKeyIndex = 0; pKeyIndex < mPublicKeys.size(); pKeyIndex++) {
656 long id = mPublicKeys.keyAt(pKeyIndex);
dcashman8c04fac2015-03-23 11:39:42 -0700657 PublicKeyHandle pkh = mPublicKeys.valueAt(pKeyIndex);
658 String encodedKey = encodePublicKey(pkh.getKey());
Geremy Condraf1bcca82013-01-07 22:35:24 -0800659 serializer.startTag(null, "public-key");
660 serializer.attribute(null, "identifier", Long.toString(id));
661 serializer.attribute(null, "value", encodedKey);
662 serializer.endTag(null, "public-key");
663 }
664 serializer.endTag(null, "keys");
665 }
666
667 void writeKeySetsLPr(XmlSerializer serializer) throws IOException {
668 serializer.startTag(null, "keysets");
669 for (int keySetIndex = 0; keySetIndex < mKeySetMapping.size(); keySetIndex++) {
670 long id = mKeySetMapping.keyAt(keySetIndex);
dcashman9d2f4412014-06-09 09:27:54 -0700671 ArraySet<Long> keys = mKeySetMapping.valueAt(keySetIndex);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800672 serializer.startTag(null, "keyset");
673 serializer.attribute(null, "identifier", Long.toString(id));
674 for (long keyId : keys) {
675 serializer.startTag(null, "key-id");
676 serializer.attribute(null, "identifier", Long.toString(keyId));
677 serializer.endTag(null, "key-id");
678 }
679 serializer.endTag(null, "keyset");
680 }
681 serializer.endTag(null, "keysets");
682 }
683
dcashman8c04fac2015-03-23 11:39:42 -0700684 void readKeySetsLPw(XmlPullParser parser, ArrayMap<Long, Integer> keySetRefCounts)
Geremy Condraf1bcca82013-01-07 22:35:24 -0800685 throws XmlPullParserException, IOException {
686 int type;
687 long currentKeySetId = 0;
dcashman55b10782014-04-09 14:20:38 -0700688 int outerDepth = parser.getDepth();
dcashman8c04fac2015-03-23 11:39:42 -0700689 String recordedVersionStr = parser.getAttributeValue(null, "version");
690 if (recordedVersionStr == null) {
691 // The keyset information comes from pre-versioned devices, and
692 // is inaccurate, don't collect any of it.
dcashman55b10782014-04-09 14:20:38 -0700693 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
694 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
dcashman55b10782014-04-09 14:20:38 -0700695 continue;
696 }
697 // The KeySet information read previously from packages.xml is invalid.
698 // Destroy it all.
699 for (PackageSetting p : mPackages.values()) {
dcashmand79fdf12014-06-20 15:53:06 -0700700 clearPackageKeySetDataLPw(p);
dcashman55b10782014-04-09 14:20:38 -0700701 }
702 return;
703 }
dcashman8c04fac2015-03-23 11:39:42 -0700704 int recordedVersion = Integer.parseInt(recordedVersionStr);
dcashman55b10782014-04-09 14:20:38 -0700705 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
706 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
Geremy Condraf1bcca82013-01-07 22:35:24 -0800707 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
708 continue;
709 }
710 final String tagName = parser.getName();
711 if (tagName.equals("keys")) {
712 readKeysLPw(parser);
713 } else if (tagName.equals("keysets")) {
714 readKeySetListLPw(parser);
dcashman55b10782014-04-09 14:20:38 -0700715 } else if (tagName.equals("lastIssuedKeyId")) {
716 lastIssuedKeyId = Long.parseLong(parser.getAttributeValue(null, "value"));
717 } else if (tagName.equals("lastIssuedKeySetId")) {
718 lastIssuedKeySetId = Long.parseLong(parser.getAttributeValue(null, "value"));
Geremy Condraf1bcca82013-01-07 22:35:24 -0800719 }
720 }
dcashman8c04fac2015-03-23 11:39:42 -0700721
722 addRefCountsFromSavedPackagesLPw(keySetRefCounts);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800723 }
724
725 void readKeysLPw(XmlPullParser parser)
726 throws XmlPullParserException, IOException {
727 int outerDepth = parser.getDepth();
728 int type;
729 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
730 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
731 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
732 continue;
733 }
734 final String tagName = parser.getName();
735 if (tagName.equals("public-key")) {
736 readPublicKeyLPw(parser);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800737 }
738 }
739 }
740
741 void readKeySetListLPw(XmlPullParser parser)
742 throws XmlPullParserException, IOException {
743 int outerDepth = parser.getDepth();
744 int type;
745 long currentKeySetId = 0;
746 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
747 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
748 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
749 continue;
750 }
751 final String tagName = parser.getName();
752 if (tagName.equals("keyset")) {
dcashman8c04fac2015-03-23 11:39:42 -0700753 String encodedID = parser.getAttributeValue(null, "identifier");
754 currentKeySetId = Long.parseLong(encodedID);
755 int refCount = 0;
756 mKeySets.put(currentKeySetId, new KeySetHandle(currentKeySetId, refCount));
dcashman55b10782014-04-09 14:20:38 -0700757 mKeySetMapping.put(currentKeySetId, new ArraySet<Long>());
Geremy Condraf1bcca82013-01-07 22:35:24 -0800758 } else if (tagName.equals("key-id")) {
dcashman8c04fac2015-03-23 11:39:42 -0700759 String encodedID = parser.getAttributeValue(null, "identifier");
760 long id = Long.parseLong(encodedID);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800761 mKeySetMapping.get(currentKeySetId).add(id);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800762 }
763 }
764 }
765
Geremy Condraf1bcca82013-01-07 22:35:24 -0800766 void readPublicKeyLPw(XmlPullParser parser)
767 throws XmlPullParserException {
768 String encodedID = parser.getAttributeValue(null, "identifier");
769 long identifier = Long.parseLong(encodedID);
dcashman8c04fac2015-03-23 11:39:42 -0700770 int refCount = 0;
Geremy Condraf1bcca82013-01-07 22:35:24 -0800771 String encodedPublicKey = parser.getAttributeValue(null, "value");
772 PublicKey pub = PackageParser.parsePublicKey(encodedPublicKey);
Geremy Condraa2d8eae2013-06-21 16:59:42 -0700773 if (pub != null) {
dcashman8c04fac2015-03-23 11:39:42 -0700774 PublicKeyHandle pkh = new PublicKeyHandle(identifier, refCount, pub);
775 mPublicKeys.put(identifier, pkh);
776 }
777 }
778
779 /*
780 * Set each KeySet ref count. Also increment all public keys in each keyset.
781 */
782 private void addRefCountsFromSavedPackagesLPw(ArrayMap<Long, Integer> keySetRefCounts) {
783 final int numRefCounts = keySetRefCounts.size();
784 for (int i = 0; i < numRefCounts; i++) {
785 KeySetHandle ks = mKeySets.get(keySetRefCounts.keyAt(i));
dcashman87f794f2015-06-03 14:46:47 -0700786 if (ks == null) {
787 /* something went terribly wrong and we have references to a non-existent key-set */
788 Slog.wtf(TAG, "Encountered non-existent key-set reference when reading settings");
789 continue;
790 }
dcashman8c04fac2015-03-23 11:39:42 -0700791 ks.setRefCountLPw(keySetRefCounts.valueAt(i));
792 }
793
dcashman87f794f2015-06-03 14:46:47 -0700794 /*
795 * In case something went terribly wrong and we have keysets with no associated packges
796 * that refer to them, record the orphaned keyset ids, and remove them using
797 * decrementKeySetLPw() after all keyset references have been set so that the associtaed
798 * public keys have the appropriate references from all keysets.
799 */
800 ArraySet<Long> orphanedKeySets = new ArraySet<Long>();
dcashman8c04fac2015-03-23 11:39:42 -0700801 final int numKeySets = mKeySets.size();
802 for (int i = 0; i < numKeySets; i++) {
dcashman87f794f2015-06-03 14:46:47 -0700803 if (mKeySets.valueAt(i).getRefCountLPr() == 0) {
804 Slog.wtf(TAG, "Encountered key-set w/out package references when reading settings");
805 orphanedKeySets.add(mKeySets.keyAt(i));
806 }
dcashman8c04fac2015-03-23 11:39:42 -0700807 ArraySet<Long> pubKeys = mKeySetMapping.valueAt(i);
808 final int pkSize = pubKeys.size();
809 for (int j = 0; j < pkSize; j++) {
810 mPublicKeys.get(pubKeys.valueAt(j)).incrRefCountLPw();
811 }
Geremy Condraf1bcca82013-01-07 22:35:24 -0800812 }
dcashman87f794f2015-06-03 14:46:47 -0700813 final int numOrphans = orphanedKeySets.size();
814 for (int i = 0; i < numOrphans; i++) {
815 decrementKeySetLPw(orphanedKeySets.valueAt(i));
816 }
Geremy Condraf1bcca82013-01-07 22:35:24 -0800817 }
Ying Wangfb236b52013-07-08 10:53:58 -0700818}