blob: c19951fe4accc6ca946288afc2568cc2f4c8c0fe [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
dcashman5de73772014-07-12 13:04:20 -070019import android.content.pm.KeySet;
Geremy Condraf1bcca82013-01-07 22:35:24 -080020import android.content.pm.PackageParser;
21import android.os.Binder;
dcashman55b10782014-04-09 14:20:38 -070022import android.util.ArraySet;
Geremy Condraf1bcca82013-01-07 22:35:24 -080023import android.util.Base64;
dcashman55b10782014-04-09 14:20:38 -070024import android.util.Slog;
Geremy Condraf1bcca82013-01-07 22:35:24 -080025import android.util.LongSparseArray;
26
27import java.io.IOException;
28import java.io.PrintWriter;
29import java.security.PublicKey;
Geremy Condraf1bcca82013-01-07 22:35:24 -080030import java.util.Map;
31import java.util.Set;
32
33import org.xmlpull.v1.XmlPullParser;
34import org.xmlpull.v1.XmlPullParserException;
35import org.xmlpull.v1.XmlSerializer;
36
37/*
38 * Manages system-wide KeySet state.
39 */
dcashman55b10782014-04-09 14:20:38 -070040public class KeySetManagerService {
Geremy Condraf1bcca82013-01-07 22:35:24 -080041
dcashman55b10782014-04-09 14:20:38 -070042 static final String TAG = "KeySetManagerService";
43
44 /* original keysets implementation had no versioning info, so this is the first */
45 public static final int FIRST_VERSION = 1;
46
47 public static final int CURRENT_VERSION = FIRST_VERSION;
Geremy Condraf1bcca82013-01-07 22:35:24 -080048
Kenny Root9a995f52013-07-08 09:33:22 -070049 /** Sentinel value returned when a {@code KeySet} is not found. */
50 public static final long KEYSET_NOT_FOUND = -1;
51
52 /** Sentinel value returned when public key is not found. */
dcashman55b10782014-04-09 14:20:38 -070053 protected static final long PUBLIC_KEY_NOT_FOUND = -1;
Geremy Condraf1bcca82013-01-07 22:35:24 -080054
dcashman5de73772014-07-12 13:04:20 -070055 private final LongSparseArray<KeySet> mKeySets;
Geremy Condraf1bcca82013-01-07 22:35:24 -080056
57 private final LongSparseArray<PublicKey> mPublicKeys;
58
dcashmand79fdf12014-06-20 15:53:06 -070059 protected final LongSparseArray<ArraySet<Long>> mKeySetMapping;
Geremy Condraf1bcca82013-01-07 22:35:24 -080060
61 private final Map<String, PackageSetting> mPackages;
62
63 private static long lastIssuedKeySetId = 0;
64
65 private static long lastIssuedKeyId = 0;
66
dcashman55b10782014-04-09 14:20:38 -070067 public KeySetManagerService(Map<String, PackageSetting> packages) {
dcashman5de73772014-07-12 13:04:20 -070068 mKeySets = new LongSparseArray<KeySet>();
Geremy Condraf1bcca82013-01-07 22:35:24 -080069 mPublicKeys = new LongSparseArray<PublicKey>();
dcashmand79fdf12014-06-20 15:53:06 -070070 mKeySetMapping = new LongSparseArray<ArraySet<Long>>();
Geremy Condraf1bcca82013-01-07 22:35:24 -080071 mPackages = packages;
72 }
73
Kenny Root2042e9d2013-07-08 09:31:31 -070074 /**
Geremy Condraf1bcca82013-01-07 22:35:24 -080075 * Determine if a package is signed by the given KeySet.
76 *
77 * Returns false if the package was not signed by all the
78 * keys in the KeySet.
79 *
80 * Returns true if the package was signed by at least the
81 * keys in the given KeySet.
82 *
83 * Note that this can return true for multiple KeySets.
84 */
dcashman5de73772014-07-12 13:04:20 -070085 public boolean packageIsSignedByLPr(String packageName, KeySet ks) {
dcashmand79fdf12014-06-20 15:53:06 -070086 PackageSetting pkg = mPackages.get(packageName);
87 if (pkg == null) {
88 throw new NullPointerException("Invalid package name");
Geremy Condraf1bcca82013-01-07 22:35:24 -080089 }
dcashmand79fdf12014-06-20 15:53:06 -070090 if (pkg.keySetData == null) {
91 throw new NullPointerException("Package has no KeySet data");
92 }
93 long id = getIdByKeySetLPr(ks);
94 return pkg.keySetData.packageIsSignedBy(id);
Geremy Condraf1bcca82013-01-07 22:35:24 -080095 }
96
Kenny Root2042e9d2013-07-08 09:31:31 -070097 /**
Geremy Condraf1bcca82013-01-07 22:35:24 -080098 * This informs the system that the given package has defined a KeySet
99 * in its manifest that a) contains the given keys and b) is named
100 * alias by that package.
101 */
dcashmand79fdf12014-06-20 15:53:06 -0700102 public void addDefinedKeySetToPackageLPw(String packageName,
dcashman5de73772014-07-12 13:04:20 -0700103 Set<PublicKey> keys, String alias) {
Geremy Condraf1bcca82013-01-07 22:35:24 -0800104 if ((packageName == null) || (keys == null) || (alias == null)) {
dcashman55b10782014-04-09 14:20:38 -0700105 Slog.w(TAG, "Got null argument for a defined keyset, ignoring!");
Geremy Condraf1bcca82013-01-07 22:35:24 -0800106 return;
107 }
dcashmand79fdf12014-06-20 15:53:06 -0700108 PackageSetting pkg = mPackages.get(packageName);
109 if (pkg == null) {
110 throw new NullPointerException("Unknown package");
Geremy Condraf1bcca82013-01-07 22:35:24 -0800111 }
dcashmand79fdf12014-06-20 15:53:06 -0700112 // Add to KeySets, then to package
dcashman5de73772014-07-12 13:04:20 -0700113 KeySet ks = addKeySetLPw(keys);
dcashmand79fdf12014-06-20 15:53:06 -0700114 long id = getIdByKeySetLPr(ks);
115 pkg.keySetData.addDefinedKeySet(id, alias);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800116 }
117
Kenny Root2042e9d2013-07-08 09:31:31 -0700118 /**
dcashman55b10782014-04-09 14:20:38 -0700119 * This informs the system that the given package has defined a KeySet
120 * alias in its manifest to be an upgradeKeySet. This must be called
121 * after all of the defined KeySets have been added.
122 */
dcashmand79fdf12014-06-20 15:53:06 -0700123 public void addUpgradeKeySetToPackageLPw(String packageName, String alias) {
dcashman55b10782014-04-09 14:20:38 -0700124 if ((packageName == null) || (alias == null)) {
125 Slog.w(TAG, "Got null argument for a defined keyset, ignoring!");
126 return;
127 }
dcashmand79fdf12014-06-20 15:53:06 -0700128 PackageSetting pkg = mPackages.get(packageName);
129 if (pkg == null) {
130 throw new NullPointerException("Unknown package");
dcashman55b10782014-04-09 14:20:38 -0700131 }
dcashmand79fdf12014-06-20 15:53:06 -0700132 pkg.keySetData.addUpgradeKeySet(alias);
dcashman55b10782014-04-09 14:20:38 -0700133 }
134
135 /**
Geremy Condraf1bcca82013-01-07 22:35:24 -0800136 * Similar to the above, this informs the system that the given package
137 * was signed by the provided KeySet.
138 */
dcashmand79fdf12014-06-20 15:53:06 -0700139 public void addSigningKeySetToPackageLPw(String packageName,
dcashman5de73772014-07-12 13:04:20 -0700140 Set<PublicKey> signingKeys) {
Geremy Condraf1bcca82013-01-07 22:35:24 -0800141 if ((packageName == null) || (signingKeys == null)) {
dcashman55b10782014-04-09 14:20:38 -0700142 Slog.w(TAG, "Got null argument for a signing keyset, ignoring!");
Geremy Condraf1bcca82013-01-07 22:35:24 -0800143 return;
144 }
dcashmand79fdf12014-06-20 15:53:06 -0700145 // add the signing KeySet
dcashman5de73772014-07-12 13:04:20 -0700146 KeySet ks = addKeySetLPw(signingKeys);
dcashmand79fdf12014-06-20 15:53:06 -0700147 long id = getIdByKeySetLPr(ks);
dcashman5de73772014-07-12 13:04:20 -0700148 Set<Long> publicKeyIds = mKeySetMapping.get(id);
dcashmand79fdf12014-06-20 15:53:06 -0700149 if (publicKeyIds == null) {
150 throw new NullPointerException("Got invalid KeySet id");
151 }
dcashman5de73772014-07-12 13:04:20 -0700152
dcashmand79fdf12014-06-20 15:53:06 -0700153 // attach it to the package
154 PackageSetting pkg = mPackages.get(packageName);
155 if (pkg == null) {
156 throw new NullPointerException("No such package!");
157 }
158 pkg.keySetData.setProperSigningKeySet(id);
159 // for each KeySet which is a subset of the one above, add the
160 // KeySet id to the package's signing KeySets
161 for (int keySetIndex = 0; keySetIndex < mKeySets.size(); keySetIndex++) {
162 long keySetID = mKeySets.keyAt(keySetIndex);
dcashman5de73772014-07-12 13:04:20 -0700163 Set<Long> definedKeys = mKeySetMapping.get(keySetID);
dcashmand79fdf12014-06-20 15:53:06 -0700164 if (publicKeyIds.containsAll(definedKeys)) {
165 pkg.keySetData.addSigningKeySet(keySetID);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800166 }
167 }
168 }
169
Kenny Root2042e9d2013-07-08 09:31:31 -0700170 /**
171 * Fetches the stable identifier associated with the given KeySet. Returns
172 * {@link #KEYSET_NOT_FOUND} if the KeySet... wasn't found.
Geremy Condraf1bcca82013-01-07 22:35:24 -0800173 */
dcashman5de73772014-07-12 13:04:20 -0700174 private long getIdByKeySetLPr(KeySet ks) {
Geremy Condraf1bcca82013-01-07 22:35:24 -0800175 for (int keySetIndex = 0; keySetIndex < mKeySets.size(); keySetIndex++) {
dcashman5de73772014-07-12 13:04:20 -0700176 KeySet value = mKeySets.valueAt(keySetIndex);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800177 if (ks.equals(value)) {
178 return mKeySets.keyAt(keySetIndex);
179 }
180 }
181 return KEYSET_NOT_FOUND;
182 }
183
Kenny Root2042e9d2013-07-08 09:31:31 -0700184 /**
Geremy Condraf1bcca82013-01-07 22:35:24 -0800185 * Fetches the KeySet corresponding to the given stable identifier.
186 *
Kenny Root2042e9d2013-07-08 09:31:31 -0700187 * Returns {@link #KEYSET_NOT_FOUND} if the identifier doesn't
188 * identify a {@link KeySet}.
Geremy Condraf1bcca82013-01-07 22:35:24 -0800189 */
dcashman5de73772014-07-12 13:04:20 -0700190 public KeySet getKeySetByIdLPr(long id) {
dcashmand79fdf12014-06-20 15:53:06 -0700191 return mKeySets.get(id);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800192 }
193
Kenny Root2042e9d2013-07-08 09:31:31 -0700194 /**
dcashman5de73772014-07-12 13:04:20 -0700195 * Fetches the {@link KeySet} that a given package refers to by the provided alias.
196 *
197 * @throws IllegalArgumentException if the package has no keyset data.
198 * @throws NullPointerException if the package is unknown.
Geremy Condraf1bcca82013-01-07 22:35:24 -0800199 */
dcashman5de73772014-07-12 13:04:20 -0700200 public KeySet getKeySetByAliasAndPackageNameLPr(String packageName, String alias) {
dcashmand79fdf12014-06-20 15:53:06 -0700201 PackageSetting p = mPackages.get(packageName);
dcashman5de73772014-07-12 13:04:20 -0700202 if (p == null) {
203 throw new NullPointerException("Unknown package");
Geremy Condraf1bcca82013-01-07 22:35:24 -0800204 }
dcashman5de73772014-07-12 13:04:20 -0700205 if (p.keySetData == null) {
206 throw new IllegalArgumentException("Package has no keySet data");
dcashmand79fdf12014-06-20 15:53:06 -0700207 }
dcashman5de73772014-07-12 13:04:20 -0700208 long keySetId = p.keySetData.getAliases().get(alias);
dcashmand79fdf12014-06-20 15:53:06 -0700209 return mKeySets.get(keySetId);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800210 }
211
Kenny Root2042e9d2013-07-08 09:31:31 -0700212 /**
dcashman55b10782014-04-09 14:20:38 -0700213 * Fetches the {@link PublicKey public keys} which belong to the specified
214 * KeySet id.
215 *
216 * Returns {@code null} if the identifier doesn't
dcashman5de73772014-07-12 13:04:20 -0700217 * identify a {@link KeySet}.
dcashman55b10782014-04-09 14:20:38 -0700218 */
dcashmand79fdf12014-06-20 15:53:06 -0700219 public ArraySet<PublicKey> getPublicKeysFromKeySetLPr(long id) {
220 if(mKeySetMapping.get(id) == null) {
221 return null;
dcashman55b10782014-04-09 14:20:38 -0700222 }
dcashmand79fdf12014-06-20 15:53:06 -0700223 ArraySet<PublicKey> mPubKeys = new ArraySet<PublicKey>();
224 for (long pkId : mKeySetMapping.get(id)) {
225 mPubKeys.add(mPublicKeys.get(pkId));
226 }
227 return mPubKeys;
dcashman55b10782014-04-09 14:20:38 -0700228 }
229
230 /**
dcashman5de73772014-07-12 13:04:20 -0700231 * Fetches all the known {@link KeySet KeySets} that signed the given
dcashman55b10782014-04-09 14:20:38 -0700232 * package.
233 *
234 * @throws IllegalArgumentException if the package has no keyset data.
235 * @throws NullPointerException if the package is unknown.
Geremy Condraf1bcca82013-01-07 22:35:24 -0800236 */
dcashman5de73772014-07-12 13:04:20 -0700237 public Set<KeySet> getSigningKeySetsByPackageNameLPr(String packageName) {
238 Set<KeySet> signingKeySets = new ArraySet<KeySet>();
dcashmand79fdf12014-06-20 15:53:06 -0700239 PackageSetting p = mPackages.get(packageName);
dcashman5de73772014-07-12 13:04:20 -0700240 if (p == null) {
241 throw new NullPointerException("Unknown package");
dcashman55b10782014-04-09 14:20:38 -0700242 }
dcashman5de73772014-07-12 13:04:20 -0700243 if (p.keySetData == null || p.keySetData.getSigningKeySets() == null) {
244 throw new IllegalArgumentException("Package has no keySet data");
245 }
246 for (long l : p.keySetData.getSigningKeySets()) {
247 signingKeySets.add(mKeySets.get(l));
248 }
249 return signingKeySets;
dcashman55b10782014-04-09 14:20:38 -0700250 }
251
252 /**
dcashman5de73772014-07-12 13:04:20 -0700253 * Fetches all the known {@link KeySet KeySets} that may upgrade the given
dcashman55b10782014-04-09 14:20:38 -0700254 * package.
255 *
256 * @throws IllegalArgumentException if the package has no keyset data.
257 * @throws NullPointerException if the package is unknown.
258 */
dcashman5de73772014-07-12 13:04:20 -0700259 public ArraySet<KeySet> getUpgradeKeySetsByPackageNameLPr(String packageName) {
260 ArraySet<KeySet> upgradeKeySets = new ArraySet<KeySet>();
dcashmand79fdf12014-06-20 15:53:06 -0700261 PackageSetting p = mPackages.get(packageName);
262 if (p == null) {
263 throw new NullPointerException("Unknown package");
Geremy Condraf1bcca82013-01-07 22:35:24 -0800264 }
dcashmand79fdf12014-06-20 15:53:06 -0700265 if (p.keySetData == null) {
266 throw new IllegalArgumentException("Package has no keySet data");
267 }
268 if (p.keySetData.isUsingUpgradeKeySets()) {
269 for (long l : p.keySetData.getUpgradeKeySets()) {
270 upgradeKeySets.add(mKeySets.get(l));
271 }
272 }
273 return upgradeKeySets;
Geremy Condraf1bcca82013-01-07 22:35:24 -0800274 }
275
Kenny Root2042e9d2013-07-08 09:31:31 -0700276 /**
Geremy Condraf1bcca82013-01-07 22:35:24 -0800277 * Creates a new KeySet corresponding to the given keys.
278 *
Kenny Root2042e9d2013-07-08 09:31:31 -0700279 * If the {@link PublicKey PublicKeys} aren't known to the system, this
280 * adds them. Otherwise, they're deduped.
Geremy Condraf1bcca82013-01-07 22:35:24 -0800281 *
282 * If the KeySet isn't known to the system, this adds that and creates the
283 * mapping to the PublicKeys. If it is known, then it's deduped.
284 *
dcashman55b10782014-04-09 14:20:38 -0700285 * If the KeySet isn't known to the system, this adds it to all appropriate
286 * signingKeySets
287 *
Kenny Root2042e9d2013-07-08 09:31:31 -0700288 * Throws if the provided set is {@code null}.
Geremy Condraf1bcca82013-01-07 22:35:24 -0800289 */
dcashman5de73772014-07-12 13:04:20 -0700290 private KeySet addKeySetLPw(Set<PublicKey> keys) {
Geremy Condraf1bcca82013-01-07 22:35:24 -0800291 if (keys == null) {
292 throw new NullPointerException("Provided keys cannot be null");
293 }
294 // add each of the keys in the provided set
dcashmand79fdf12014-06-20 15:53:06 -0700295 ArraySet<Long> addedKeyIds = new ArraySet<Long>(keys.size());
Geremy Condraf1bcca82013-01-07 22:35:24 -0800296 for (PublicKey k : keys) {
dcashmand79fdf12014-06-20 15:53:06 -0700297 long id = addPublicKeyLPw(k);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800298 addedKeyIds.add(id);
299 }
300
301 // check to see if the resulting keyset is new
dcashmand79fdf12014-06-20 15:53:06 -0700302 long existingKeySetId = getIdFromKeyIdsLPr(addedKeyIds);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800303 if (existingKeySetId != KEYSET_NOT_FOUND) {
304 return mKeySets.get(existingKeySetId);
305 }
306
307 // create the KeySet object
dcashman5de73772014-07-12 13:04:20 -0700308 KeySet ks = new KeySet(new Binder());
Geremy Condraf1bcca82013-01-07 22:35:24 -0800309 // get the first unoccupied slot in mKeySets
dcashmand79fdf12014-06-20 15:53:06 -0700310 long id = getFreeKeySetIDLPw();
Geremy Condraf1bcca82013-01-07 22:35:24 -0800311 // add the KeySet object to it
312 mKeySets.put(id, ks);
313 // add the stable key ids to the mapping
314 mKeySetMapping.put(id, addedKeyIds);
dcashman55b10782014-04-09 14:20:38 -0700315 // add this KeySet id to all packages which are signed by it
316 for (String pkgName : mPackages.keySet()) {
317 PackageSetting p = mPackages.get(pkgName);
318 if (p.keySetData != null) {
319 long pProperSigning = p.keySetData.getProperSigningKeySet();
320 if (pProperSigning != PackageKeySetData.KEYSET_UNASSIGNED) {
dcashman5de73772014-07-12 13:04:20 -0700321 Set<Long> pSigningKeys = mKeySetMapping.get(pProperSigning);
dcashman55b10782014-04-09 14:20:38 -0700322 if (pSigningKeys.containsAll(addedKeyIds)) {
323 p.keySetData.addSigningKeySet(id);
324 }
325 }
326 }
327 }
Geremy Condraf1bcca82013-01-07 22:35:24 -0800328 // go home
329 return ks;
330 }
331
Kenny Root2042e9d2013-07-08 09:31:31 -0700332 /**
Geremy Condraf1bcca82013-01-07 22:35:24 -0800333 * Adds the given PublicKey to the system, deduping as it goes.
334 */
dcashmand79fdf12014-06-20 15:53:06 -0700335 private long addPublicKeyLPw(PublicKey key) {
Geremy Condraf1bcca82013-01-07 22:35:24 -0800336 // check if the public key is new
dcashmand79fdf12014-06-20 15:53:06 -0700337 long existingKeyId = getIdForPublicKeyLPr(key);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800338 if (existingKeyId != PUBLIC_KEY_NOT_FOUND) {
339 return existingKeyId;
340 }
341 // if it's new find the first unoccupied slot in the public keys
dcashmand79fdf12014-06-20 15:53:06 -0700342 long id = getFreePublicKeyIdLPw();
Geremy Condraf1bcca82013-01-07 22:35:24 -0800343 // add the public key to it
344 mPublicKeys.put(id, key);
345 // return the stable identifier
346 return id;
347 }
348
Kenny Root2042e9d2013-07-08 09:31:31 -0700349 /**
Geremy Condraf1bcca82013-01-07 22:35:24 -0800350 * Finds the stable identifier for a KeySet based on a set of PublicKey stable IDs.
351 *
352 * Returns KEYSET_NOT_FOUND if there isn't one.
353 */
dcashmand79fdf12014-06-20 15:53:06 -0700354 private long getIdFromKeyIdsLPr(Set<Long> publicKeyIds) {
Geremy Condraf1bcca82013-01-07 22:35:24 -0800355 for (int keyMapIndex = 0; keyMapIndex < mKeySetMapping.size(); keyMapIndex++) {
dcashman5de73772014-07-12 13:04:20 -0700356 Set<Long> value = mKeySetMapping.valueAt(keyMapIndex);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800357 if (value.equals(publicKeyIds)) {
358 return mKeySetMapping.keyAt(keyMapIndex);
359 }
360 }
361 return KEYSET_NOT_FOUND;
362 }
363
Kenny Root2042e9d2013-07-08 09:31:31 -0700364 /**
Geremy Condraf1bcca82013-01-07 22:35:24 -0800365 * Finds the stable identifier for a PublicKey or PUBLIC_KEY_NOT_FOUND.
366 */
dcashmand79fdf12014-06-20 15:53:06 -0700367 private long getIdForPublicKeyLPr(PublicKey k) {
Geremy Condraf1bcca82013-01-07 22:35:24 -0800368 String encodedPublicKey = new String(k.getEncoded());
369 for (int publicKeyIndex = 0; publicKeyIndex < mPublicKeys.size(); publicKeyIndex++) {
370 PublicKey value = mPublicKeys.valueAt(publicKeyIndex);
371 String encodedExistingKey = new String(value.getEncoded());
372 if (encodedPublicKey.equals(encodedExistingKey)) {
373 return mPublicKeys.keyAt(publicKeyIndex);
374 }
375 }
376 return PUBLIC_KEY_NOT_FOUND;
377 }
378
Kenny Root2042e9d2013-07-08 09:31:31 -0700379 /**
Geremy Condraf1bcca82013-01-07 22:35:24 -0800380 * Gets an unused stable identifier for a KeySet.
381 */
dcashmand79fdf12014-06-20 15:53:06 -0700382 private long getFreeKeySetIDLPw() {
Geremy Condraf1bcca82013-01-07 22:35:24 -0800383 lastIssuedKeySetId += 1;
384 return lastIssuedKeySetId;
385 }
386
Kenny Root2042e9d2013-07-08 09:31:31 -0700387 /**
Geremy Condraf1bcca82013-01-07 22:35:24 -0800388 * Same as above, but for public keys.
389 */
dcashmand79fdf12014-06-20 15:53:06 -0700390 private long getFreePublicKeyIdLPw() {
Geremy Condraf1bcca82013-01-07 22:35:24 -0800391 lastIssuedKeyId += 1;
392 return lastIssuedKeyId;
393 }
394
dcashmand79fdf12014-06-20 15:53:06 -0700395 public void removeAppKeySetDataLPw(String packageName) {
396 // Get the package's known keys and KeySets
397 ArraySet<Long> deletableKeySets = getOriginalKeySetsByPackageNameLPr(packageName);
398 ArraySet<Long> deletableKeys = new ArraySet<Long>();
399 ArraySet<Long> knownKeys = null;
400 for (Long ks : deletableKeySets) {
401 knownKeys = mKeySetMapping.get(ks);
402 if (knownKeys != null) {
403 deletableKeys.addAll(knownKeys);
404 }
405 }
406
407 // Now remove the keys and KeySets on which any other package relies
408 for (String pkgName : mPackages.keySet()) {
409 if (pkgName.equals(packageName)) {
410 continue;
411 }
412 ArraySet<Long> knownKeySets = getOriginalKeySetsByPackageNameLPr(pkgName);
413 deletableKeySets.removeAll(knownKeySets);
414 knownKeys = new ArraySet<Long>();
415 for (Long ks : knownKeySets) {
Geremy Condracdb57892013-03-26 16:22:36 -0700416 knownKeys = mKeySetMapping.get(ks);
417 if (knownKeys != null) {
dcashmand79fdf12014-06-20 15:53:06 -0700418 deletableKeys.removeAll(knownKeys);
Geremy Condracdb57892013-03-26 16:22:36 -0700419 }
Geremy Condraf1bcca82013-01-07 22:35:24 -0800420 }
Geremy Condraf1bcca82013-01-07 22:35:24 -0800421 }
dcashmand79fdf12014-06-20 15:53:06 -0700422
423 // The remaining keys and KeySets are not relied on by any other
424 // application and so can be safely deleted.
425 for (Long ks : deletableKeySets) {
426 mKeySets.delete(ks);
427 mKeySetMapping.delete(ks);
428 }
429 for (Long keyId : deletableKeys) {
430 mPublicKeys.delete(keyId);
431 }
432
433 // Now remove the deleted KeySets from each package's signingKeySets
434 for (String pkgName : mPackages.keySet()) {
435 PackageSetting p = mPackages.get(pkgName);
436 for (Long ks : deletableKeySets) {
437 p.keySetData.removeSigningKeySet(ks);
438 }
439 }
440 // Finally, remove all KeySets from the original package
441 PackageSetting p = mPackages.get(packageName);
442 clearPackageKeySetDataLPw(p);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800443 }
444
dcashmand79fdf12014-06-20 15:53:06 -0700445 private void clearPackageKeySetDataLPw(PackageSetting p) {
dcashman55b10782014-04-09 14:20:38 -0700446 p.keySetData.removeAllSigningKeySets();
447 p.keySetData.removeAllUpgradeKeySets();
448 p.keySetData.removeAllDefinedKeySets();
449 return;
450 }
451
dcashmand79fdf12014-06-20 15:53:06 -0700452 private ArraySet<Long> getOriginalKeySetsByPackageNameLPr(String packageName) {
Geremy Condraf1bcca82013-01-07 22:35:24 -0800453 PackageSetting p = mPackages.get(packageName);
454 if (p == null) {
455 throw new NullPointerException("Unknown package");
456 }
457 if (p.keySetData == null) {
458 throw new IllegalArgumentException("Package has no keySet data");
459 }
dcashmand79fdf12014-06-20 15:53:06 -0700460 ArraySet<Long> knownKeySets = new ArraySet<Long>();
dcashman55b10782014-04-09 14:20:38 -0700461 knownKeySets.add(p.keySetData.getProperSigningKeySet());
462 if (p.keySetData.isUsingDefinedKeySets()) {
463 for (long ks : p.keySetData.getDefinedKeySets()) {
464 knownKeySets.add(ks);
465 }
Geremy Condraf1bcca82013-01-07 22:35:24 -0800466 }
467 return knownKeySets;
468 }
469
470 public String encodePublicKey(PublicKey k) throws IOException {
471 return new String(Base64.encode(k.getEncoded(), 0));
472 }
473
dcashmand79fdf12014-06-20 15:53:06 -0700474 public void dumpLPr(PrintWriter pw, String packageName,
475 PackageManagerService.DumpState dumpState) {
476 boolean printedHeader = false;
477 for (Map.Entry<String, PackageSetting> e : mPackages.entrySet()) {
478 String keySetPackage = e.getKey();
479 if (packageName != null && !packageName.equals(keySetPackage)) {
480 continue;
481 }
482 if (!printedHeader) {
483 if (dumpState.onTitlePrinted())
484 pw.println();
485 pw.println("Key Set Manager:");
486 printedHeader = true;
487 }
488 PackageSetting pkg = e.getValue();
489 pw.print(" ["); pw.print(keySetPackage); pw.println("]");
490 if (pkg.keySetData != null) {
491 boolean printedLabel = false;
492 for (Map.Entry<String, Long> entry : pkg.keySetData.getAliases().entrySet()) {
493 if (!printedLabel) {
494 pw.print(" KeySets Aliases: ");
495 printedLabel = true;
496 } else {
497 pw.print(", ");
498 }
499 pw.print(entry.getKey());
500 pw.print('=');
501 pw.print(Long.toString(entry.getValue()));
Dianne Hackborncbfd23e2013-06-11 14:26:53 -0700502 }
dcashmand79fdf12014-06-20 15:53:06 -0700503 if (printedLabel) {
504 pw.println("");
Dianne Hackborncbfd23e2013-06-11 14:26:53 -0700505 }
dcashmand79fdf12014-06-20 15:53:06 -0700506 printedLabel = false;
507 if (pkg.keySetData.isUsingDefinedKeySets()) {
508 for (long keySetId : pkg.keySetData.getDefinedKeySets()) {
Kenny Rootdf0e6ab2013-07-03 13:38:31 -0700509 if (!printedLabel) {
dcashmand79fdf12014-06-20 15:53:06 -0700510 pw.print(" Defined KeySets: ");
Dianne Hackborncbfd23e2013-06-11 14:26:53 -0700511 printedLabel = true;
512 } else {
513 pw.print(", ");
514 }
Kenny Rootdf0e6ab2013-07-03 13:38:31 -0700515 pw.print(Long.toString(keySetId));
Geremy Condraf1bcca82013-01-07 22:35:24 -0800516 }
dcashmand79fdf12014-06-20 15:53:06 -0700517 }
518 if (printedLabel) {
519 pw.println("");
520 }
521 printedLabel = false;
522 for (long keySetId : pkg.keySetData.getSigningKeySets()) {
523 if (!printedLabel) {
524 pw.print(" Signing KeySets: ");
525 printedLabel = true;
526 } else {
527 pw.print(", ");
Dianne Hackborncbfd23e2013-06-11 14:26:53 -0700528 }
dcashmand79fdf12014-06-20 15:53:06 -0700529 pw.print(Long.toString(keySetId));
530 }
531 if (printedLabel) {
532 pw.println("");
533 }
534 printedLabel = false;
535 if (pkg.keySetData.isUsingUpgradeKeySets()) {
536 for (long keySetId : pkg.keySetData.getUpgradeKeySets()) {
537 if (!printedLabel) {
538 pw.print(" Upgrade KeySets: ");
539 printedLabel = true;
540 } else {
541 pw.print(", ");
dcashman55b10782014-04-09 14:20:38 -0700542 }
dcashmand79fdf12014-06-20 15:53:06 -0700543 pw.print(Long.toString(keySetId));
dcashman55b10782014-04-09 14:20:38 -0700544 }
dcashmand79fdf12014-06-20 15:53:06 -0700545 }
546 if (printedLabel) {
547 pw.println("");
Geremy Condraf1bcca82013-01-07 22:35:24 -0800548 }
549 }
550 }
551 }
552
dcashman55b10782014-04-09 14:20:38 -0700553 void writeKeySetManagerServiceLPr(XmlSerializer serializer) throws IOException {
Geremy Condraf1bcca82013-01-07 22:35:24 -0800554 serializer.startTag(null, "keyset-settings");
dcashman55b10782014-04-09 14:20:38 -0700555 serializer.attribute(null, "version", Integer.toString(CURRENT_VERSION));
Geremy Condraf1bcca82013-01-07 22:35:24 -0800556 writePublicKeysLPr(serializer);
557 writeKeySetsLPr(serializer);
558 serializer.startTag(null, "lastIssuedKeyId");
559 serializer.attribute(null, "value", Long.toString(lastIssuedKeyId));
560 serializer.endTag(null, "lastIssuedKeyId");
561 serializer.startTag(null, "lastIssuedKeySetId");
562 serializer.attribute(null, "value", Long.toString(lastIssuedKeySetId));
563 serializer.endTag(null, "lastIssuedKeySetId");
564 serializer.endTag(null, "keyset-settings");
565 }
566
567 void writePublicKeysLPr(XmlSerializer serializer) throws IOException {
568 serializer.startTag(null, "keys");
569 for (int pKeyIndex = 0; pKeyIndex < mPublicKeys.size(); pKeyIndex++) {
570 long id = mPublicKeys.keyAt(pKeyIndex);
571 PublicKey key = mPublicKeys.valueAt(pKeyIndex);
572 String encodedKey = encodePublicKey(key);
573 serializer.startTag(null, "public-key");
574 serializer.attribute(null, "identifier", Long.toString(id));
575 serializer.attribute(null, "value", encodedKey);
576 serializer.endTag(null, "public-key");
577 }
578 serializer.endTag(null, "keys");
579 }
580
581 void writeKeySetsLPr(XmlSerializer serializer) throws IOException {
582 serializer.startTag(null, "keysets");
583 for (int keySetIndex = 0; keySetIndex < mKeySetMapping.size(); keySetIndex++) {
584 long id = mKeySetMapping.keyAt(keySetIndex);
dcashman5de73772014-07-12 13:04:20 -0700585 Set<Long> keys = mKeySetMapping.valueAt(keySetIndex);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800586 serializer.startTag(null, "keyset");
587 serializer.attribute(null, "identifier", Long.toString(id));
588 for (long keyId : keys) {
589 serializer.startTag(null, "key-id");
590 serializer.attribute(null, "identifier", Long.toString(keyId));
591 serializer.endTag(null, "key-id");
592 }
593 serializer.endTag(null, "keyset");
594 }
595 serializer.endTag(null, "keysets");
596 }
597
598 void readKeySetsLPw(XmlPullParser parser)
599 throws XmlPullParserException, IOException {
600 int type;
601 long currentKeySetId = 0;
dcashman55b10782014-04-09 14:20:38 -0700602 int outerDepth = parser.getDepth();
603 String recordedVersion = parser.getAttributeValue(null, "version");
604 if (recordedVersion == null || Integer.parseInt(recordedVersion) != CURRENT_VERSION) {
605 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
606 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
607 // Our version is different than the one which generated the old keyset data.
608 // We don't want any of the old data, but we must advance the parser
609 continue;
610 }
611 // The KeySet information read previously from packages.xml is invalid.
612 // Destroy it all.
613 for (PackageSetting p : mPackages.values()) {
dcashmand79fdf12014-06-20 15:53:06 -0700614 clearPackageKeySetDataLPw(p);
dcashman55b10782014-04-09 14:20:38 -0700615 }
616 return;
617 }
618 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
619 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
Geremy Condraf1bcca82013-01-07 22:35:24 -0800620 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
621 continue;
622 }
623 final String tagName = parser.getName();
624 if (tagName.equals("keys")) {
625 readKeysLPw(parser);
626 } else if (tagName.equals("keysets")) {
627 readKeySetListLPw(parser);
dcashman55b10782014-04-09 14:20:38 -0700628 } else if (tagName.equals("lastIssuedKeyId")) {
629 lastIssuedKeyId = Long.parseLong(parser.getAttributeValue(null, "value"));
630 } else if (tagName.equals("lastIssuedKeySetId")) {
631 lastIssuedKeySetId = Long.parseLong(parser.getAttributeValue(null, "value"));
Geremy Condraf1bcca82013-01-07 22:35:24 -0800632 }
633 }
634 }
635
636 void readKeysLPw(XmlPullParser parser)
637 throws XmlPullParserException, IOException {
638 int outerDepth = parser.getDepth();
639 int type;
640 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
641 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
642 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
643 continue;
644 }
645 final String tagName = parser.getName();
646 if (tagName.equals("public-key")) {
647 readPublicKeyLPw(parser);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800648 }
649 }
650 }
651
652 void readKeySetListLPw(XmlPullParser parser)
653 throws XmlPullParserException, IOException {
654 int outerDepth = parser.getDepth();
655 int type;
656 long currentKeySetId = 0;
657 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
658 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
659 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
660 continue;
661 }
662 final String tagName = parser.getName();
663 if (tagName.equals("keyset")) {
664 currentKeySetId = readIdentifierLPw(parser);
dcashman5de73772014-07-12 13:04:20 -0700665 mKeySets.put(currentKeySetId, new KeySet(new Binder()));
dcashman55b10782014-04-09 14:20:38 -0700666 mKeySetMapping.put(currentKeySetId, new ArraySet<Long>());
Geremy Condraf1bcca82013-01-07 22:35:24 -0800667 } else if (tagName.equals("key-id")) {
668 long id = readIdentifierLPw(parser);
669 mKeySetMapping.get(currentKeySetId).add(id);
Geremy Condraf1bcca82013-01-07 22:35:24 -0800670 }
671 }
672 }
673
674 long readIdentifierLPw(XmlPullParser parser)
675 throws XmlPullParserException {
676 return Long.parseLong(parser.getAttributeValue(null, "identifier"));
677 }
678
679 void readPublicKeyLPw(XmlPullParser parser)
680 throws XmlPullParserException {
681 String encodedID = parser.getAttributeValue(null, "identifier");
682 long identifier = Long.parseLong(encodedID);
683 String encodedPublicKey = parser.getAttributeValue(null, "value");
684 PublicKey pub = PackageParser.parsePublicKey(encodedPublicKey);
Geremy Condraa2d8eae2013-06-21 16:59:42 -0700685 if (pub != null) {
Geremy Condraf1bcca82013-01-07 22:35:24 -0800686 mPublicKeys.put(identifier, pub);
687 }
688 }
Ying Wangfb236b52013-07-08 10:53:58 -0700689}