blob: db3ae9192e96e62baf8174844a01768a815c61df [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
Geremy Condraf1bcca82013-01-07 22:35:24 -080019import android.content.pm.PackageParser;
dcashman8c04fac2015-03-23 11:39:42 -070020import android.util.ArrayMap;
dcashman55b10782014-04-09 14:20:38 -070021import android.util.ArraySet;
Geremy Condraf1bcca82013-01-07 22:35:24 -080022import android.util.Base64;
dcashman55b10782014-04-09 14:20:38 -070023import android.util.Slog;
Geremy Condraf1bcca82013-01-07 22:35:24 -080024import android.util.LongSparseArray;
25
26import java.io.IOException;
27import java.io.PrintWriter;
28import java.security.PublicKey;
Geremy Condraf1bcca82013-01-07 22:35:24 -080029import java.util.Set;
30
31import org.xmlpull.v1.XmlPullParser;
32import org.xmlpull.v1.XmlPullParserException;
33import org.xmlpull.v1.XmlSerializer;
34
35/*
36 * Manages system-wide KeySet state.
37 */
dcashman55b10782014-04-09 14:20:38 -070038public class KeySetManagerService {
Geremy Condraf1bcca82013-01-07 22:35:24 -080039
dcashman55b10782014-04-09 14:20:38 -070040 static final String TAG = "KeySetManagerService";
41
42 /* original keysets implementation had no versioning info, so this is the first */
43 public static final int FIRST_VERSION = 1;
44
45 public static final int CURRENT_VERSION = FIRST_VERSION;
Geremy Condraf1bcca82013-01-07 22:35:24 -080046
Kenny Root9a995f52013-07-08 09:33:22 -070047 /** Sentinel value returned when a {@code KeySet} is not found. */
48 public static final long KEYSET_NOT_FOUND = -1;
49
50 /** Sentinel value returned when public key is not found. */
dcashman55b10782014-04-09 14:20:38 -070051 protected static final long PUBLIC_KEY_NOT_FOUND = -1;
Geremy Condraf1bcca82013-01-07 22:35:24 -080052
dcashman9d2f4412014-06-09 09:27:54 -070053 private final LongSparseArray<KeySetHandle> mKeySets;
Geremy Condraf1bcca82013-01-07 22:35:24 -080054
dcashman8c04fac2015-03-23 11:39:42 -070055 private final LongSparseArray<PublicKeyHandle> mPublicKeys;
Geremy Condraf1bcca82013-01-07 22:35:24 -080056
dcashmand79fdf12014-06-20 15:53:06 -070057 protected final LongSparseArray<ArraySet<Long>> mKeySetMapping;
Geremy Condraf1bcca82013-01-07 22:35:24 -080058
dcashman8c04fac2015-03-23 11:39:42 -070059 private final ArrayMap<String, PackageSetting> mPackages;
Geremy Condraf1bcca82013-01-07 22:35:24 -080060
61 private static long lastIssuedKeySetId = 0;
62
63 private static long lastIssuedKeyId = 0;
64
dcashman8c04fac2015-03-23 11:39:42 -070065 class PublicKeyHandle {
66 private final PublicKey mKey;
67 private final long mId;
68 private int mRefCount;
69
70 public PublicKeyHandle(long id, PublicKey key) {
71 mId = id;
72 mRefCount = 1;
73 mKey = key;
74 }
75
76 /*
77 * Only used when reading state from packages.xml
78 */
79 private PublicKeyHandle(long id, int refCount, PublicKey key) {
80 mId = id;
81 mRefCount = refCount;
82 mKey = key;
83 }
84
85 public long getId() {
86 return mId;
87 }
88
89 public PublicKey getKey() {
90 return mKey;
91 }
92
93 public int getRefCountLPr() {
94 return mRefCount;
95 }
96
97 public void incrRefCountLPw() {
98 mRefCount++;
99 return;
100 }
101 public long decrRefCountLPw() {
102 mRefCount--;
103 return mRefCount;
104 }
105 }
106
107 public KeySetManagerService(ArrayMap<String, PackageSetting> packages) {
dcashman9d2f4412014-06-09 09:27:54 -0700108 mKeySets = new LongSparseArray<KeySetHandle>();
dcashman8c04fac2015-03-23 11:39:42 -0700109 mPublicKeys = new LongSparseArray<PublicKeyHandle>();
dcashmand79fdf12014-06-20 15:53:06 -0700110 mKeySetMapping = new LongSparseArray<ArraySet<Long>>();
Geremy Condraf1bcca82013-01-07 22:35:24 -0800111 mPackages = packages;
112 }
113
Kenny Root2042e9d2013-07-08 09:31:31 -0700114 /**
Geremy Condraf1bcca82013-01-07 22:35:24 -0800115 * Determine if a package is signed by the given KeySet.
116 *
117 * Returns false if the package was not signed by all the
118 * keys in the KeySet.
119 *
120 * Returns true if the package was signed by at least the
121 * keys in the given KeySet.
122 *
123 * Note that this can return true for multiple KeySets.
124 */
dcashman9d2f4412014-06-09 09:27:54 -0700125 public boolean packageIsSignedByLPr(String packageName, KeySetHandle ks) {
dcashmand79fdf12014-06-20 15:53:06 -0700126 PackageSetting pkg = mPackages.get(packageName);
127 if (pkg == null) {
128 throw new NullPointerException("Invalid package name");
Geremy Condraf1bcca82013-01-07 22:35:24 -0800129 }
dcashmand79fdf12014-06-20 15:53:06 -0700130 if (pkg.keySetData == null) {
131 throw new NullPointerException("Package has no KeySet data");
132 }
133 long id = getIdByKeySetLPr(ks);
dcashman9d2f4412014-06-09 09:27:54 -0700134 if (id == KEYSET_NOT_FOUND) {
135 return false;
136 }
dcashman8c04fac2015-03-23 11:39:42 -0700137 ArraySet<Long> pkgKeys = mKeySetMapping.get(pkg.keySetData.getProperSigningKeySet());
138 ArraySet<Long> testKeys = mKeySetMapping.get(id);
139 return pkgKeys.containsAll(testKeys);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800140 }
141
Kenny Root2042e9d2013-07-08 09:31:31 -0700142 /**
dcashman9d2f4412014-06-09 09:27:54 -0700143 * Determine if a package is signed by the given KeySet.
144 *
145 * Returns false if the package was not signed by all the
146 * keys in the KeySet, or if the package was signed by keys
147 * not in the KeySet.
148 *
149 * Note that this can return only for one KeySet.
150 */
151 public boolean packageIsSignedByExactlyLPr(String packageName, KeySetHandle ks) {
152 PackageSetting pkg = mPackages.get(packageName);
153 if (pkg == null) {
154 throw new NullPointerException("Invalid package name");
155 }
156 if (pkg.keySetData == null
157 || pkg.keySetData.getProperSigningKeySet()
158 == PackageKeySetData.KEYSET_UNASSIGNED) {
159 throw new NullPointerException("Package has no KeySet data");
dcashman8c04fac2015-03-23 11:39:42 -0700160 }
dcashman9d2f4412014-06-09 09:27:54 -0700161 long id = getIdByKeySetLPr(ks);
dcashman8c04fac2015-03-23 11:39:42 -0700162 if (id == KEYSET_NOT_FOUND) {
163 return false;
164 }
165 ArraySet<Long> pkgKeys = mKeySetMapping.get(pkg.keySetData.getProperSigningKeySet());
166 ArraySet<Long> testKeys = mKeySetMapping.get(id);
167 return pkgKeys.equals(testKeys);
dcashman9d2f4412014-06-09 09:27:54 -0700168 }
169
170 /**
dcashman8c04fac2015-03-23 11:39:42 -0700171 * Informs the system that the given package was signed by the provided KeySet.
Geremy Condraf1bcca82013-01-07 22:35:24 -0800172 */
dcashmand79fdf12014-06-20 15:53:06 -0700173 public void addSigningKeySetToPackageLPw(String packageName,
dcashman9d2f4412014-06-09 09:27:54 -0700174 ArraySet<PublicKey> signingKeys) {
dcashman8c04fac2015-03-23 11:39:42 -0700175
176 /* check existing keyset for reuse or removal */
dcashmand79fdf12014-06-20 15:53:06 -0700177 PackageSetting pkg = mPackages.get(packageName);
dcashman8c04fac2015-03-23 11:39:42 -0700178 long signingKeySetId = pkg.keySetData.getProperSigningKeySet();
179
180 if (signingKeySetId != PackageKeySetData.KEYSET_UNASSIGNED) {
181 ArraySet<PublicKey> existingKeys = getPublicKeysFromKeySetLPr(signingKeySetId);
182 if (existingKeys.equals(signingKeys)) {
183
184 /* no change in signing keys, leave PackageSetting alone */
185 return;
186 } else {
187
188 /* old keyset no longer valid, remove ref */
189 KeySetHandle ksh = mKeySets.get(signingKeySetId);
190 decrementKeySetLPw(signingKeySetId);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800191 }
192 }
dcashman8c04fac2015-03-23 11:39:42 -0700193
194 /* create and add a new keyset */
195 KeySetHandle ks = addKeySetLPw(signingKeys);
196 long id = ks.getId();
197 pkg.keySetData.setProperSigningKeySet(id);
198 return;
Geremy Condraf1bcca82013-01-07 22:35:24 -0800199 }
200
Kenny Root2042e9d2013-07-08 09:31:31 -0700201 /**
202 * Fetches the stable identifier associated with the given KeySet. Returns
203 * {@link #KEYSET_NOT_FOUND} if the KeySet... wasn't found.
Geremy Condraf1bcca82013-01-07 22:35:24 -0800204 */
dcashman9d2f4412014-06-09 09:27:54 -0700205 private long getIdByKeySetLPr(KeySetHandle ks) {
Geremy Condraf1bcca82013-01-07 22:35:24 -0800206 for (int keySetIndex = 0; keySetIndex < mKeySets.size(); keySetIndex++) {
dcashman9d2f4412014-06-09 09:27:54 -0700207 KeySetHandle value = mKeySets.valueAt(keySetIndex);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800208 if (ks.equals(value)) {
209 return mKeySets.keyAt(keySetIndex);
210 }
211 }
212 return KEYSET_NOT_FOUND;
213 }
214
dcashman8c04fac2015-03-23 11:39:42 -0700215 /*
216 * Inform the system that the given package defines the given KeySets.
217 * Remove any KeySets the package no longer defines.
Geremy Condraf1bcca82013-01-07 22:35:24 -0800218 */
dcashman8c04fac2015-03-23 11:39:42 -0700219 public void addDefinedKeySetsToPackageLPw(String packageName,
220 ArrayMap<String, ArraySet<PublicKey>> definedMapping) {
221 PackageSetting pkg = mPackages.get(packageName);
222 ArrayMap<String, Long> prevDefinedKeySets = pkg.keySetData.getAliases();
223
224 /* add all of the newly defined KeySets */
225 ArrayMap<String, Long> newKeySetAliases = new ArrayMap<String, Long>();
226 final int defMapSize = definedMapping.size();
227 for (int i = 0; i < defMapSize; i++) {
228 String alias = definedMapping.keyAt(i);
229 ArraySet<PublicKey> pubKeys = definedMapping.valueAt(i);
230 if (alias != null && pubKeys != null && pubKeys.size() > 0) {
231 KeySetHandle ks = addKeySetLPw(pubKeys);
232 newKeySetAliases.put(alias, ks.getId());
233 }
234 }
235
236 /* remove each of the old references */
237 final int prevDefSize = prevDefinedKeySets.size();
238 for (int i = 0; i < prevDefSize; i++) {
239 decrementKeySetLPw(prevDefinedKeySets.valueAt(i));
240 }
241 pkg.keySetData.removeAllUpgradeKeySets();
242
243 /* switch to the just-added */
244 pkg.keySetData.setAliases(newKeySetAliases);
245 return;
Geremy Condraf1bcca82013-01-07 22:35:24 -0800246 }
247
Kenny Root2042e9d2013-07-08 09:31:31 -0700248 /**
dcashman8c04fac2015-03-23 11:39:42 -0700249 * This informs the system that the given package has defined a KeySet
250 * alias in its manifest to be an upgradeKeySet. This must be called
251 * after all of the defined KeySets have been added.
252 */
253 public void addUpgradeKeySetsToPackageLPw(String packageName,
254 ArraySet<String> upgradeAliases) {
255 PackageSetting pkg = mPackages.get(packageName);
256 final int uaSize = upgradeAliases.size();
257 for (int i = 0; i < uaSize; i++) {
258 pkg.keySetData.addUpgradeKeySet(upgradeAliases.valueAt(i));
259 }
260 return;
261 }
262
263 /**
264 * Fetched the {@link KeySetHandle} that a given package refers to by the
265 * provided alias. Returns null if the package is unknown or does not have a
dcashman9d2f4412014-06-09 09:27:54 -0700266 * KeySet corresponding to that alias.
Geremy Condraf1bcca82013-01-07 22:35:24 -0800267 */
dcashman9d2f4412014-06-09 09:27:54 -0700268 public KeySetHandle getKeySetByAliasAndPackageNameLPr(String packageName, String alias) {
dcashmand79fdf12014-06-20 15:53:06 -0700269 PackageSetting p = mPackages.get(packageName);
dcashman9d2f4412014-06-09 09:27:54 -0700270 if (p == null || p.keySetData == null) {
dcashman8c04fac2015-03-23 11:39:42 -0700271 return null;
Geremy Condraf1bcca82013-01-07 22:35:24 -0800272 }
dcashman9d2f4412014-06-09 09:27:54 -0700273 Long keySetId = p.keySetData.getAliases().get(alias);
274 if (keySetId == null) {
275 throw new IllegalArgumentException("Unknown KeySet alias: " + alias);
dcashmand79fdf12014-06-20 15:53:06 -0700276 }
dcashmand79fdf12014-06-20 15:53:06 -0700277 return mKeySets.get(keySetId);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800278 }
279
Kenny Root2042e9d2013-07-08 09:31:31 -0700280 /**
dcashman55b10782014-04-09 14:20:38 -0700281 * Fetches the {@link PublicKey public keys} which belong to the specified
282 * KeySet id.
283 *
284 * Returns {@code null} if the identifier doesn't
dcashman9d2f4412014-06-09 09:27:54 -0700285 * identify a {@link KeySetHandle}.
dcashman55b10782014-04-09 14:20:38 -0700286 */
dcashmand79fdf12014-06-20 15:53:06 -0700287 public ArraySet<PublicKey> getPublicKeysFromKeySetLPr(long id) {
288 if(mKeySetMapping.get(id) == null) {
289 return null;
dcashman55b10782014-04-09 14:20:38 -0700290 }
dcashmand79fdf12014-06-20 15:53:06 -0700291 ArraySet<PublicKey> mPubKeys = new ArraySet<PublicKey>();
dcashman8c04fac2015-03-23 11:39:42 -0700292 ArraySet<Long> pkIds = mKeySetMapping.get(id);
293 final int pkSize = pkIds.size();
294 for (int i = 0; i < pkSize; i++) {
295 mPubKeys.add(mPublicKeys.get(pkIds.valueAt(i)).getKey());
dcashmand79fdf12014-06-20 15:53:06 -0700296 }
297 return mPubKeys;
dcashman55b10782014-04-09 14:20:38 -0700298 }
299
300 /**
dcashman9d2f4412014-06-09 09:27:54 -0700301 * Fetches the proper {@link KeySetHandle KeySet} that signed the given
dcashman55b10782014-04-09 14:20:38 -0700302 * package.
303 *
304 * @throws IllegalArgumentException if the package has no keyset data.
dcashman8c04fac2015-03-23 11:39:42 -0700305 * @throws NullPointerException if the packgae is unknown.
Geremy Condraf1bcca82013-01-07 22:35:24 -0800306 */
dcashman9d2f4412014-06-09 09:27:54 -0700307 public KeySetHandle getSigningKeySetByPackageNameLPr(String packageName) {
dcashmand79fdf12014-06-20 15:53:06 -0700308 PackageSetting p = mPackages.get(packageName);
dcashman9d2f4412014-06-09 09:27:54 -0700309 if (p == null
310 || p.keySetData == null
311 || p.keySetData.getProperSigningKeySet()
312 == PackageKeySetData.KEYSET_UNASSIGNED) {
313 return null;
dcashman55b10782014-04-09 14:20:38 -0700314 }
dcashman9d2f4412014-06-09 09:27:54 -0700315 return mKeySets.get(p.keySetData.getProperSigningKeySet());
dcashman55b10782014-04-09 14:20:38 -0700316 }
317
318 /**
Geremy Condraf1bcca82013-01-07 22:35:24 -0800319 * Creates a new KeySet corresponding to the given keys.
320 *
Kenny Root2042e9d2013-07-08 09:31:31 -0700321 * If the {@link PublicKey PublicKeys} aren't known to the system, this
dcashman8c04fac2015-03-23 11:39:42 -0700322 * adds them. Otherwise, they're deduped and the reference count
323 * incremented.
Geremy Condraf1bcca82013-01-07 22:35:24 -0800324 *
325 * If the KeySet isn't known to the system, this adds that and creates the
dcashman8c04fac2015-03-23 11:39:42 -0700326 * mapping to the PublicKeys. If it is known, then it's deduped and the
327 * reference count is incremented.
dcashman55b10782014-04-09 14:20:38 -0700328 *
Kenny Root2042e9d2013-07-08 09:31:31 -0700329 * Throws if the provided set is {@code null}.
Geremy Condraf1bcca82013-01-07 22:35:24 -0800330 */
dcashman9d2f4412014-06-09 09:27:54 -0700331 private KeySetHandle addKeySetLPw(ArraySet<PublicKey> keys) {
dcashman8c04fac2015-03-23 11:39:42 -0700332 if (keys == null || keys.size() == 0) {
333 throw new IllegalArgumentException("Cannot add an empty set of keys!");
Geremy Condraf1bcca82013-01-07 22:35:24 -0800334 }
dcashman8c04fac2015-03-23 11:39:42 -0700335
336 /* add each of the keys in the provided set */
dcashmand79fdf12014-06-20 15:53:06 -0700337 ArraySet<Long> addedKeyIds = new ArraySet<Long>(keys.size());
dcashman8c04fac2015-03-23 11:39:42 -0700338 final int kSize = keys.size();
339 for (int i = 0; i < kSize; i++) {
340 long id = addPublicKeyLPw(keys.valueAt(i));
Geremy Condraf1bcca82013-01-07 22:35:24 -0800341 addedKeyIds.add(id);
342 }
343
dcashman8c04fac2015-03-23 11:39:42 -0700344 /* check to see if the resulting keyset is new */
dcashmand79fdf12014-06-20 15:53:06 -0700345 long existingKeySetId = getIdFromKeyIdsLPr(addedKeyIds);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800346 if (existingKeySetId != KEYSET_NOT_FOUND) {
dcashman8c04fac2015-03-23 11:39:42 -0700347
348 /* public keys were incremented, but we aren't adding a new keyset: undo */
349 for (int i = 0; i < kSize; i++) {
350 decrementPublicKeyLPw(addedKeyIds.valueAt(i));
351 }
352 KeySetHandle ks = mKeySets.get(existingKeySetId);
353 ks.incrRefCountLPw();
354 return ks;
Geremy Condraf1bcca82013-01-07 22:35:24 -0800355 }
356
dcashman8c04fac2015-03-23 11:39:42 -0700357 // get the next keyset id
dcashmand79fdf12014-06-20 15:53:06 -0700358 long id = getFreeKeySetIDLPw();
dcashman8c04fac2015-03-23 11:39:42 -0700359
360 // create the KeySet object and add to mKeySets and mapping
361 KeySetHandle ks = new KeySetHandle(id);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800362 mKeySets.put(id, ks);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800363 mKeySetMapping.put(id, addedKeyIds);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800364 return ks;
365 }
366
dcashman8c04fac2015-03-23 11:39:42 -0700367 /*
368 * Decrements the reference to KeySet represented by the given id. If this
369 * drops to zero, then also decrement the reference to each public key it
370 * contains and remove the KeySet.
371 */
372 private void decrementKeySetLPw(long id) {
373 KeySetHandle ks = mKeySets.get(id);
374 if (ks.decrRefCountLPw() <= 0) {
375 ArraySet<Long> pubKeys = mKeySetMapping.get(id);
376 final int pkSize = pubKeys.size();
377 for (int i = 0; i < pkSize; i++) {
378 decrementPublicKeyLPw(pubKeys.valueAt(i));
379 }
380 mKeySets.delete(id);
381 mKeySetMapping.delete(id);
382 }
383 return;
384 }
385
386 /*
387 * Decrements the reference to PublicKey represented by the given id. If
388 * this drops to zero, then remove it.
389 */
390 private void decrementPublicKeyLPw(long id) {
391 PublicKeyHandle pk = mPublicKeys.get(id);
392 if (pk.decrRefCountLPw() <= 0) {
393 mPublicKeys.delete(id);
394 }
395 return;
396 }
397
Kenny Root2042e9d2013-07-08 09:31:31 -0700398 /**
Geremy Condraf1bcca82013-01-07 22:35:24 -0800399 * Adds the given PublicKey to the system, deduping as it goes.
400 */
dcashmand79fdf12014-06-20 15:53:06 -0700401 private long addPublicKeyLPw(PublicKey key) {
dcashman8c04fac2015-03-23 11:39:42 -0700402 long id = getIdForPublicKeyLPr(key);
403 if (id != PUBLIC_KEY_NOT_FOUND) {
404
405 /* We already know about this key, increment its ref count and ret */
406 mPublicKeys.get(id).incrRefCountLPw();
407 return id;
Geremy Condraf1bcca82013-01-07 22:35:24 -0800408 }
dcashman8c04fac2015-03-23 11:39:42 -0700409
410 /* if it's new find the first unoccupied slot in the public keys */
411 id = getFreePublicKeyIdLPw();
412 mPublicKeys.put(id, new PublicKeyHandle(id, key));
Geremy Condraf1bcca82013-01-07 22:35:24 -0800413 return id;
414 }
415
Kenny Root2042e9d2013-07-08 09:31:31 -0700416 /**
Geremy Condraf1bcca82013-01-07 22:35:24 -0800417 * Finds the stable identifier for a KeySet based on a set of PublicKey stable IDs.
418 *
419 * Returns KEYSET_NOT_FOUND if there isn't one.
420 */
dcashmand79fdf12014-06-20 15:53:06 -0700421 private long getIdFromKeyIdsLPr(Set<Long> publicKeyIds) {
Geremy Condraf1bcca82013-01-07 22:35:24 -0800422 for (int keyMapIndex = 0; keyMapIndex < mKeySetMapping.size(); keyMapIndex++) {
dcashman9d2f4412014-06-09 09:27:54 -0700423 ArraySet<Long> value = mKeySetMapping.valueAt(keyMapIndex);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800424 if (value.equals(publicKeyIds)) {
425 return mKeySetMapping.keyAt(keyMapIndex);
426 }
427 }
428 return KEYSET_NOT_FOUND;
429 }
430
Kenny Root2042e9d2013-07-08 09:31:31 -0700431 /**
Geremy Condraf1bcca82013-01-07 22:35:24 -0800432 * Finds the stable identifier for a PublicKey or PUBLIC_KEY_NOT_FOUND.
433 */
dcashmand79fdf12014-06-20 15:53:06 -0700434 private long getIdForPublicKeyLPr(PublicKey k) {
Geremy Condraf1bcca82013-01-07 22:35:24 -0800435 String encodedPublicKey = new String(k.getEncoded());
436 for (int publicKeyIndex = 0; publicKeyIndex < mPublicKeys.size(); publicKeyIndex++) {
dcashman8c04fac2015-03-23 11:39:42 -0700437 PublicKey value = mPublicKeys.valueAt(publicKeyIndex).getKey();
Geremy Condraf1bcca82013-01-07 22:35:24 -0800438 String encodedExistingKey = new String(value.getEncoded());
439 if (encodedPublicKey.equals(encodedExistingKey)) {
440 return mPublicKeys.keyAt(publicKeyIndex);
441 }
442 }
443 return PUBLIC_KEY_NOT_FOUND;
444 }
445
Kenny Root2042e9d2013-07-08 09:31:31 -0700446 /**
Geremy Condraf1bcca82013-01-07 22:35:24 -0800447 * Gets an unused stable identifier for a KeySet.
448 */
dcashmand79fdf12014-06-20 15:53:06 -0700449 private long getFreeKeySetIDLPw() {
Geremy Condraf1bcca82013-01-07 22:35:24 -0800450 lastIssuedKeySetId += 1;
451 return lastIssuedKeySetId;
452 }
453
Kenny Root2042e9d2013-07-08 09:31:31 -0700454 /**
Geremy Condraf1bcca82013-01-07 22:35:24 -0800455 * Same as above, but for public keys.
456 */
dcashmand79fdf12014-06-20 15:53:06 -0700457 private long getFreePublicKeyIdLPw() {
Geremy Condraf1bcca82013-01-07 22:35:24 -0800458 lastIssuedKeyId += 1;
459 return lastIssuedKeyId;
460 }
461
dcashman8c04fac2015-03-23 11:39:42 -0700462 /*
463 * This package is being removed from the system, so we need to
464 * remove its keyset and public key references, then remove its
465 * keyset data.
466 */
dcashmand79fdf12014-06-20 15:53:06 -0700467 public void removeAppKeySetDataLPw(String packageName) {
dcashman8c04fac2015-03-23 11:39:42 -0700468
469 /* remove refs from common keysets and public keys */
470 PackageSetting pkg = mPackages.get(packageName);
471 long signingKeySetId = pkg.keySetData.getProperSigningKeySet();
472 decrementKeySetLPw(signingKeySetId);
473 ArrayMap<String, Long> definedKeySets = pkg.keySetData.getAliases();
474 for (int i = 0; i < definedKeySets.size(); i++) {
475 decrementKeySetLPw(definedKeySets.valueAt(i));
dcashmand79fdf12014-06-20 15:53:06 -0700476 }
477
dcashman8c04fac2015-03-23 11:39:42 -0700478 /* remove from package */
479 clearPackageKeySetDataLPw(pkg);
dcashman55b10782014-04-09 14:20:38 -0700480 return;
481 }
482
dcashman8c04fac2015-03-23 11:39:42 -0700483 private void clearPackageKeySetDataLPw(PackageSetting pkg) {
484 pkg.keySetData.setProperSigningKeySet(PackageKeySetData.KEYSET_UNASSIGNED);
485 pkg.keySetData.removeAllDefinedKeySets();
486 pkg.keySetData.removeAllUpgradeKeySets();
487 return;
Geremy Condraf1bcca82013-01-07 22:35:24 -0800488 }
489
490 public String encodePublicKey(PublicKey k) throws IOException {
491 return new String(Base64.encode(k.getEncoded(), 0));
492 }
493
dcashmand79fdf12014-06-20 15:53:06 -0700494 public void dumpLPr(PrintWriter pw, String packageName,
495 PackageManagerService.DumpState dumpState) {
496 boolean printedHeader = false;
dcashman8c04fac2015-03-23 11:39:42 -0700497 for (ArrayMap.Entry<String, PackageSetting> e : mPackages.entrySet()) {
dcashmand79fdf12014-06-20 15:53:06 -0700498 String keySetPackage = e.getKey();
499 if (packageName != null && !packageName.equals(keySetPackage)) {
500 continue;
501 }
502 if (!printedHeader) {
503 if (dumpState.onTitlePrinted())
504 pw.println();
505 pw.println("Key Set Manager:");
506 printedHeader = true;
507 }
508 PackageSetting pkg = e.getValue();
509 pw.print(" ["); pw.print(keySetPackage); pw.println("]");
510 if (pkg.keySetData != null) {
511 boolean printedLabel = false;
dcashman8c04fac2015-03-23 11:39:42 -0700512 for (ArrayMap.Entry<String, Long> entry : pkg.keySetData.getAliases().entrySet()) {
dcashmand79fdf12014-06-20 15:53:06 -0700513 if (!printedLabel) {
514 pw.print(" KeySets Aliases: ");
515 printedLabel = true;
516 } else {
517 pw.print(", ");
518 }
519 pw.print(entry.getKey());
520 pw.print('=');
521 pw.print(Long.toString(entry.getValue()));
Dianne Hackborncbfd23e2013-06-11 14:26:53 -0700522 }
dcashmand79fdf12014-06-20 15:53:06 -0700523 if (printedLabel) {
524 pw.println("");
Dianne Hackborncbfd23e2013-06-11 14:26:53 -0700525 }
dcashmand79fdf12014-06-20 15:53:06 -0700526 printedLabel = false;
527 if (pkg.keySetData.isUsingDefinedKeySets()) {
dcashman8c04fac2015-03-23 11:39:42 -0700528 ArrayMap<String, Long> definedKeySets = pkg.keySetData.getAliases();
529 final int dksSize = definedKeySets.size();
530 for (int i = 0; i < dksSize; i++) {
Kenny Rootdf0e6ab2013-07-03 13:38:31 -0700531 if (!printedLabel) {
dcashmand79fdf12014-06-20 15:53:06 -0700532 pw.print(" Defined KeySets: ");
Dianne Hackborncbfd23e2013-06-11 14:26:53 -0700533 printedLabel = true;
534 } else {
535 pw.print(", ");
536 }
dcashman8c04fac2015-03-23 11:39:42 -0700537 pw.print(Long.toString(definedKeySets.valueAt(i)));
Geremy Condraf1bcca82013-01-07 22:35:24 -0800538 }
dcashmand79fdf12014-06-20 15:53:06 -0700539 }
540 if (printedLabel) {
541 pw.println("");
542 }
543 printedLabel = false;
dcashman8c04fac2015-03-23 11:39:42 -0700544 final long signingKeySet = pkg.keySetData.getProperSigningKeySet();
545 pw.print(" Signing KeySets: ");
546 pw.print(Long.toString(signingKeySet));
547 pw.println("");
dcashmand79fdf12014-06-20 15:53:06 -0700548 if (pkg.keySetData.isUsingUpgradeKeySets()) {
549 for (long keySetId : pkg.keySetData.getUpgradeKeySets()) {
550 if (!printedLabel) {
551 pw.print(" Upgrade KeySets: ");
552 printedLabel = true;
553 } else {
554 pw.print(", ");
dcashman55b10782014-04-09 14:20:38 -0700555 }
dcashmand79fdf12014-06-20 15:53:06 -0700556 pw.print(Long.toString(keySetId));
dcashman55b10782014-04-09 14:20:38 -0700557 }
dcashmand79fdf12014-06-20 15:53:06 -0700558 }
559 if (printedLabel) {
560 pw.println("");
Geremy Condraf1bcca82013-01-07 22:35:24 -0800561 }
562 }
563 }
564 }
565
dcashman55b10782014-04-09 14:20:38 -0700566 void writeKeySetManagerServiceLPr(XmlSerializer serializer) throws IOException {
Geremy Condraf1bcca82013-01-07 22:35:24 -0800567 serializer.startTag(null, "keyset-settings");
dcashman55b10782014-04-09 14:20:38 -0700568 serializer.attribute(null, "version", Integer.toString(CURRENT_VERSION));
Geremy Condraf1bcca82013-01-07 22:35:24 -0800569 writePublicKeysLPr(serializer);
570 writeKeySetsLPr(serializer);
571 serializer.startTag(null, "lastIssuedKeyId");
572 serializer.attribute(null, "value", Long.toString(lastIssuedKeyId));
573 serializer.endTag(null, "lastIssuedKeyId");
574 serializer.startTag(null, "lastIssuedKeySetId");
575 serializer.attribute(null, "value", Long.toString(lastIssuedKeySetId));
576 serializer.endTag(null, "lastIssuedKeySetId");
577 serializer.endTag(null, "keyset-settings");
578 }
579
580 void writePublicKeysLPr(XmlSerializer serializer) throws IOException {
581 serializer.startTag(null, "keys");
582 for (int pKeyIndex = 0; pKeyIndex < mPublicKeys.size(); pKeyIndex++) {
583 long id = mPublicKeys.keyAt(pKeyIndex);
dcashman8c04fac2015-03-23 11:39:42 -0700584 PublicKeyHandle pkh = mPublicKeys.valueAt(pKeyIndex);
585 String encodedKey = encodePublicKey(pkh.getKey());
Geremy Condraf1bcca82013-01-07 22:35:24 -0800586 serializer.startTag(null, "public-key");
587 serializer.attribute(null, "identifier", Long.toString(id));
588 serializer.attribute(null, "value", encodedKey);
589 serializer.endTag(null, "public-key");
590 }
591 serializer.endTag(null, "keys");
592 }
593
594 void writeKeySetsLPr(XmlSerializer serializer) throws IOException {
595 serializer.startTag(null, "keysets");
596 for (int keySetIndex = 0; keySetIndex < mKeySetMapping.size(); keySetIndex++) {
597 long id = mKeySetMapping.keyAt(keySetIndex);
dcashman9d2f4412014-06-09 09:27:54 -0700598 ArraySet<Long> keys = mKeySetMapping.valueAt(keySetIndex);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800599 serializer.startTag(null, "keyset");
600 serializer.attribute(null, "identifier", Long.toString(id));
601 for (long keyId : keys) {
602 serializer.startTag(null, "key-id");
603 serializer.attribute(null, "identifier", Long.toString(keyId));
604 serializer.endTag(null, "key-id");
605 }
606 serializer.endTag(null, "keyset");
607 }
608 serializer.endTag(null, "keysets");
609 }
610
dcashman8c04fac2015-03-23 11:39:42 -0700611 void readKeySetsLPw(XmlPullParser parser, ArrayMap<Long, Integer> keySetRefCounts)
Geremy Condraf1bcca82013-01-07 22:35:24 -0800612 throws XmlPullParserException, IOException {
613 int type;
614 long currentKeySetId = 0;
dcashman55b10782014-04-09 14:20:38 -0700615 int outerDepth = parser.getDepth();
dcashman8c04fac2015-03-23 11:39:42 -0700616 String recordedVersionStr = parser.getAttributeValue(null, "version");
617 if (recordedVersionStr == null) {
618 // The keyset information comes from pre-versioned devices, and
619 // is inaccurate, don't collect any of it.
dcashman55b10782014-04-09 14:20:38 -0700620 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
621 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
dcashman55b10782014-04-09 14:20:38 -0700622 continue;
623 }
624 // The KeySet information read previously from packages.xml is invalid.
625 // Destroy it all.
626 for (PackageSetting p : mPackages.values()) {
dcashmand79fdf12014-06-20 15:53:06 -0700627 clearPackageKeySetDataLPw(p);
dcashman55b10782014-04-09 14:20:38 -0700628 }
629 return;
630 }
dcashman8c04fac2015-03-23 11:39:42 -0700631 int recordedVersion = Integer.parseInt(recordedVersionStr);
dcashman55b10782014-04-09 14:20:38 -0700632 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
633 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
Geremy Condraf1bcca82013-01-07 22:35:24 -0800634 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
635 continue;
636 }
637 final String tagName = parser.getName();
638 if (tagName.equals("keys")) {
639 readKeysLPw(parser);
640 } else if (tagName.equals("keysets")) {
641 readKeySetListLPw(parser);
dcashman55b10782014-04-09 14:20:38 -0700642 } else if (tagName.equals("lastIssuedKeyId")) {
643 lastIssuedKeyId = Long.parseLong(parser.getAttributeValue(null, "value"));
644 } else if (tagName.equals("lastIssuedKeySetId")) {
645 lastIssuedKeySetId = Long.parseLong(parser.getAttributeValue(null, "value"));
Geremy Condraf1bcca82013-01-07 22:35:24 -0800646 }
647 }
dcashman8c04fac2015-03-23 11:39:42 -0700648
649 addRefCountsFromSavedPackagesLPw(keySetRefCounts);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800650 }
651
652 void readKeysLPw(XmlPullParser parser)
653 throws XmlPullParserException, IOException {
654 int outerDepth = parser.getDepth();
655 int type;
656 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
657 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
658 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
659 continue;
660 }
661 final String tagName = parser.getName();
662 if (tagName.equals("public-key")) {
663 readPublicKeyLPw(parser);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800664 }
665 }
666 }
667
668 void readKeySetListLPw(XmlPullParser parser)
669 throws XmlPullParserException, IOException {
670 int outerDepth = parser.getDepth();
671 int type;
672 long currentKeySetId = 0;
673 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
674 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
675 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
676 continue;
677 }
678 final String tagName = parser.getName();
679 if (tagName.equals("keyset")) {
dcashman8c04fac2015-03-23 11:39:42 -0700680 String encodedID = parser.getAttributeValue(null, "identifier");
681 currentKeySetId = Long.parseLong(encodedID);
682 int refCount = 0;
683 mKeySets.put(currentKeySetId, new KeySetHandle(currentKeySetId, refCount));
dcashman55b10782014-04-09 14:20:38 -0700684 mKeySetMapping.put(currentKeySetId, new ArraySet<Long>());
Geremy Condraf1bcca82013-01-07 22:35:24 -0800685 } else if (tagName.equals("key-id")) {
dcashman8c04fac2015-03-23 11:39:42 -0700686 String encodedID = parser.getAttributeValue(null, "identifier");
687 long id = Long.parseLong(encodedID);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800688 mKeySetMapping.get(currentKeySetId).add(id);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800689 }
690 }
691 }
692
Geremy Condraf1bcca82013-01-07 22:35:24 -0800693 void readPublicKeyLPw(XmlPullParser parser)
694 throws XmlPullParserException {
695 String encodedID = parser.getAttributeValue(null, "identifier");
696 long identifier = Long.parseLong(encodedID);
dcashman8c04fac2015-03-23 11:39:42 -0700697 int refCount = 0;
Geremy Condraf1bcca82013-01-07 22:35:24 -0800698 String encodedPublicKey = parser.getAttributeValue(null, "value");
699 PublicKey pub = PackageParser.parsePublicKey(encodedPublicKey);
Geremy Condraa2d8eae2013-06-21 16:59:42 -0700700 if (pub != null) {
dcashman8c04fac2015-03-23 11:39:42 -0700701 PublicKeyHandle pkh = new PublicKeyHandle(identifier, refCount, pub);
702 mPublicKeys.put(identifier, pkh);
703 }
704 }
705
706 /*
707 * Set each KeySet ref count. Also increment all public keys in each keyset.
708 */
709 private void addRefCountsFromSavedPackagesLPw(ArrayMap<Long, Integer> keySetRefCounts) {
710 final int numRefCounts = keySetRefCounts.size();
711 for (int i = 0; i < numRefCounts; i++) {
712 KeySetHandle ks = mKeySets.get(keySetRefCounts.keyAt(i));
713 ks.setRefCountLPw(keySetRefCounts.valueAt(i));
714 }
715
716 final int numKeySets = mKeySets.size();
717 for (int i = 0; i < numKeySets; i++) {
718 ArraySet<Long> pubKeys = mKeySetMapping.valueAt(i);
719 final int pkSize = pubKeys.size();
720 for (int j = 0; j < pkSize; j++) {
721 mPublicKeys.get(pubKeys.valueAt(j)).incrRefCountLPw();
722 }
Geremy Condraf1bcca82013-01-07 22:35:24 -0800723 }
724 }
Ying Wangfb236b52013-07-08 10:53:58 -0700725}