Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2013 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | package com.android.server.pm; |
| 18 | |
| 19 | import android.content.pm.KeySet; |
| 20 | import android.content.pm.PackageParser; |
| 21 | import android.os.Binder; |
| 22 | import android.util.Base64; |
| 23 | import android.util.Log; |
| 24 | import android.util.LongSparseArray; |
| 25 | |
| 26 | import java.io.IOException; |
| 27 | import java.io.PrintWriter; |
| 28 | import java.security.PublicKey; |
| 29 | import java.util.HashMap; |
| 30 | import java.util.HashSet; |
| 31 | import java.util.Map; |
| 32 | import java.util.Set; |
| 33 | |
| 34 | import org.xmlpull.v1.XmlPullParser; |
| 35 | import org.xmlpull.v1.XmlPullParserException; |
| 36 | import org.xmlpull.v1.XmlSerializer; |
| 37 | |
| 38 | /* |
| 39 | * Manages system-wide KeySet state. |
| 40 | */ |
| 41 | public class KeySetManager { |
| 42 | |
| 43 | static final String TAG = "KeySetManager"; |
| 44 | |
Kenny Root | 9a995f5 | 2013-07-08 09:33:22 -0700 | [diff] [blame] | 45 | /** Sentinel value returned when a {@code KeySet} is not found. */ |
| 46 | public static final long KEYSET_NOT_FOUND = -1; |
| 47 | |
| 48 | /** Sentinel value returned when public key is not found. */ |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 49 | private static final long PUBLIC_KEY_NOT_FOUND = -1; |
| 50 | |
| 51 | private final Object mLockObject = new Object(); |
| 52 | |
| 53 | private final LongSparseArray<KeySet> mKeySets; |
| 54 | |
| 55 | private final LongSparseArray<PublicKey> mPublicKeys; |
| 56 | |
| 57 | private final LongSparseArray<Set<Long>> mKeySetMapping; |
| 58 | |
| 59 | private final Map<String, PackageSetting> mPackages; |
| 60 | |
| 61 | private static long lastIssuedKeySetId = 0; |
| 62 | |
| 63 | private static long lastIssuedKeyId = 0; |
| 64 | |
| 65 | public KeySetManager(Map<String, PackageSetting> packages) { |
| 66 | mKeySets = new LongSparseArray<KeySet>(); |
| 67 | mPublicKeys = new LongSparseArray<PublicKey>(); |
| 68 | mKeySetMapping = new LongSparseArray<Set<Long>>(); |
| 69 | mPackages = packages; |
| 70 | } |
| 71 | |
| 72 | /* |
| 73 | * Determine if a package is signed by the given KeySet. |
| 74 | * |
| 75 | * Returns false if the package was not signed by all the |
| 76 | * keys in the KeySet. |
| 77 | * |
| 78 | * Returns true if the package was signed by at least the |
| 79 | * keys in the given KeySet. |
| 80 | * |
| 81 | * Note that this can return true for multiple KeySets. |
| 82 | */ |
| 83 | public boolean packageIsSignedBy(String packageName, KeySet ks) { |
| 84 | synchronized (mLockObject) { |
| 85 | PackageSetting pkg = mPackages.get(packageName); |
| 86 | if (pkg == null) { |
| 87 | throw new NullPointerException("Invalid package name"); |
| 88 | } |
| 89 | if (pkg.keySetData == null) { |
| 90 | throw new NullPointerException("Package has no KeySet data"); |
| 91 | } |
| 92 | long id = getIdByKeySetLocked(ks); |
| 93 | return pkg.keySetData.packageIsSignedBy(id); |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | /* |
| 98 | * 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 | */ |
| 102 | public void addDefinedKeySetToPackage(String packageName, |
| 103 | Set<PublicKey> keys, String alias) { |
| 104 | if ((packageName == null) || (keys == null) || (alias == null)) { |
Geremy Condra | bf7b1f4 | 2013-06-18 10:38:27 -0700 | [diff] [blame] | 105 | Log.d(TAG, "Got null argument for a defined keyset, ignoring!"); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 106 | return; |
| 107 | } |
| 108 | synchronized (mLockObject) { |
| 109 | KeySet ks = addKeySetLocked(keys); |
| 110 | PackageSetting pkg = mPackages.get(packageName); |
| 111 | if (pkg == null) { |
| 112 | throw new NullPointerException("Unknown package"); |
| 113 | } |
| 114 | long id = getIdByKeySetLocked(ks); |
| 115 | pkg.keySetData.addDefinedKeySet(id, alias); |
| 116 | } |
| 117 | } |
| 118 | |
| 119 | /* |
| 120 | * Similar to the above, this informs the system that the given package |
| 121 | * was signed by the provided KeySet. |
| 122 | */ |
| 123 | public void addSigningKeySetToPackage(String packageName, |
| 124 | Set<PublicKey> signingKeys) { |
| 125 | if ((packageName == null) || (signingKeys == null)) { |
Geremy Condra | bf7b1f4 | 2013-06-18 10:38:27 -0700 | [diff] [blame] | 126 | Log.d(TAG, "Got null argument for a signing keyset, ignoring!"); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 127 | return; |
| 128 | } |
| 129 | synchronized (mLockObject) { |
| 130 | // add the signing KeySet |
| 131 | KeySet ks = addKeySetLocked(signingKeys); |
| 132 | long id = getIdByKeySetLocked(ks); |
| 133 | Set<Long> publicKeyIds = mKeySetMapping.get(id); |
| 134 | if (publicKeyIds == null) { |
| 135 | throw new NullPointerException("Got invalid KeySet id"); |
| 136 | } |
| 137 | |
| 138 | // attach it to the package |
| 139 | PackageSetting pkg = mPackages.get(packageName); |
| 140 | if (pkg == null) { |
| 141 | throw new NullPointerException("No such package!"); |
| 142 | } |
| 143 | pkg.keySetData.addSigningKeySet(id); |
| 144 | |
| 145 | // for each KeySet the package defines which is a subset of |
| 146 | // the one above, add the KeySet id to the package's signing KeySets |
| 147 | for (Long keySetID : pkg.keySetData.getDefinedKeySets()) { |
| 148 | Set<Long> definedKeys = mKeySetMapping.get(keySetID); |
| 149 | if (publicKeyIds.contains(definedKeys)) { |
| 150 | pkg.keySetData.addSigningKeySet(keySetID); |
| 151 | } |
| 152 | } |
| 153 | } |
| 154 | } |
| 155 | |
| 156 | /* |
| 157 | * Fetches the stable identifier associated with the given KeySet. |
| 158 | * |
| 159 | * Returns KEYSET_NOT_FOUND if the KeySet... wasn't found. |
| 160 | */ |
| 161 | public long getIdByKeySet(KeySet ks) { |
| 162 | synchronized (mLockObject) { |
| 163 | return getIdByKeySetLocked(ks); |
| 164 | } |
| 165 | } |
| 166 | |
| 167 | private long getIdByKeySetLocked(KeySet ks) { |
| 168 | for (int keySetIndex = 0; keySetIndex < mKeySets.size(); keySetIndex++) { |
| 169 | KeySet value = mKeySets.valueAt(keySetIndex); |
| 170 | if (ks.equals(value)) { |
| 171 | return mKeySets.keyAt(keySetIndex); |
| 172 | } |
| 173 | } |
| 174 | return KEYSET_NOT_FOUND; |
| 175 | } |
| 176 | |
| 177 | /* |
| 178 | * Fetches the KeySet corresponding to the given stable identifier. |
| 179 | * |
| 180 | * Returns KEYSET_NOT_FOUND if the identifier doesn't identify a KeySet. |
| 181 | */ |
| 182 | public KeySet getKeySetById(long id) { |
| 183 | synchronized (mLockObject) { |
| 184 | return mKeySets.get(id); |
| 185 | } |
| 186 | } |
| 187 | |
| 188 | /* |
| 189 | * Fetches the KeySet that a given package refers to by the provided alias. |
| 190 | * |
| 191 | * If the package isn't known to us, throws an IllegalArgumentException. |
| 192 | * Returns null if the alias isn't known to us. |
| 193 | */ |
| 194 | public KeySet getKeySetByAliasAndPackageName(String packageName, String alias) { |
| 195 | synchronized (mLockObject) { |
| 196 | PackageSetting p = mPackages.get(packageName); |
| 197 | if (p == null) { |
| 198 | throw new NullPointerException("Unknown package"); |
| 199 | } |
| 200 | if (p.keySetData == null) { |
| 201 | throw new IllegalArgumentException("Package has no keySet data"); |
| 202 | } |
| 203 | long keySetId = p.keySetData.getAliases().get(alias); |
| 204 | return mKeySets.get(keySetId); |
| 205 | } |
| 206 | } |
| 207 | |
| 208 | /* |
| 209 | * Fetches all the known KeySets that signed the given package. |
| 210 | * |
| 211 | * If the package is unknown to us, throws an IllegalArgumentException. |
| 212 | */ |
| 213 | public Set<KeySet> getSigningKeySetsByPackageName(String packageName) { |
| 214 | synchronized (mLockObject) { |
| 215 | Set<KeySet> signingKeySets = new HashSet<KeySet>(); |
| 216 | PackageSetting p = mPackages.get(packageName); |
| 217 | if (p == null) { |
| 218 | throw new NullPointerException("Unknown package"); |
| 219 | } |
| 220 | if (p.keySetData == null) { |
| 221 | throw new IllegalArgumentException("Package has no keySet data"); |
| 222 | } |
| 223 | for (long l : p.keySetData.getSigningKeySets()) { |
| 224 | signingKeySets.add(mKeySets.get(l)); |
| 225 | } |
| 226 | return signingKeySets; |
| 227 | } |
| 228 | } |
| 229 | |
| 230 | /* |
| 231 | * Creates a new KeySet corresponding to the given keys. |
| 232 | * |
| 233 | * If the PublicKeys aren't known to the system, this adds them. Otherwise, |
| 234 | * they're deduped. |
| 235 | * |
| 236 | * If the KeySet isn't known to the system, this adds that and creates the |
| 237 | * mapping to the PublicKeys. If it is known, then it's deduped. |
| 238 | * |
| 239 | * Throws if the provided set is null. |
| 240 | */ |
| 241 | private KeySet addKeySetLocked(Set<PublicKey> keys) { |
| 242 | if (keys == null) { |
| 243 | throw new NullPointerException("Provided keys cannot be null"); |
| 244 | } |
| 245 | // add each of the keys in the provided set |
| 246 | Set<Long> addedKeyIds = new HashSet<Long>(keys.size()); |
| 247 | for (PublicKey k : keys) { |
| 248 | long id = addPublicKeyLocked(k); |
| 249 | addedKeyIds.add(id); |
| 250 | } |
| 251 | |
| 252 | // check to see if the resulting keyset is new |
| 253 | long existingKeySetId = getIdFromKeyIdsLocked(addedKeyIds); |
| 254 | if (existingKeySetId != KEYSET_NOT_FOUND) { |
| 255 | return mKeySets.get(existingKeySetId); |
| 256 | } |
| 257 | |
| 258 | // create the KeySet object |
| 259 | KeySet ks = new KeySet(new Binder()); |
| 260 | // get the first unoccupied slot in mKeySets |
| 261 | long id = getFreeKeySetIDLocked(); |
| 262 | // add the KeySet object to it |
| 263 | mKeySets.put(id, ks); |
| 264 | // add the stable key ids to the mapping |
| 265 | mKeySetMapping.put(id, addedKeyIds); |
| 266 | // go home |
| 267 | return ks; |
| 268 | } |
| 269 | |
| 270 | /* |
| 271 | * Adds the given PublicKey to the system, deduping as it goes. |
| 272 | */ |
| 273 | private long addPublicKeyLocked(PublicKey key) { |
| 274 | // check if the public key is new |
| 275 | long existingKeyId = getIdForPublicKeyLocked(key); |
| 276 | if (existingKeyId != PUBLIC_KEY_NOT_FOUND) { |
| 277 | return existingKeyId; |
| 278 | } |
| 279 | // if it's new find the first unoccupied slot in the public keys |
| 280 | long id = getFreePublicKeyIdLocked(); |
| 281 | // add the public key to it |
| 282 | mPublicKeys.put(id, key); |
| 283 | // return the stable identifier |
| 284 | return id; |
| 285 | } |
| 286 | |
| 287 | /* |
| 288 | * Finds the stable identifier for a KeySet based on a set of PublicKey stable IDs. |
| 289 | * |
| 290 | * Returns KEYSET_NOT_FOUND if there isn't one. |
| 291 | */ |
| 292 | private long getIdFromKeyIdsLocked(Set<Long> publicKeyIds) { |
| 293 | for (int keyMapIndex = 0; keyMapIndex < mKeySetMapping.size(); keyMapIndex++) { |
| 294 | Set<Long> value = mKeySetMapping.valueAt(keyMapIndex); |
| 295 | if (value.equals(publicKeyIds)) { |
| 296 | return mKeySetMapping.keyAt(keyMapIndex); |
| 297 | } |
| 298 | } |
| 299 | return KEYSET_NOT_FOUND; |
| 300 | } |
| 301 | |
| 302 | /* |
| 303 | * Finds the stable identifier for a PublicKey or PUBLIC_KEY_NOT_FOUND. |
| 304 | */ |
| 305 | private long getIdForPublicKeyLocked(PublicKey k) { |
| 306 | String encodedPublicKey = new String(k.getEncoded()); |
| 307 | for (int publicKeyIndex = 0; publicKeyIndex < mPublicKeys.size(); publicKeyIndex++) { |
| 308 | PublicKey value = mPublicKeys.valueAt(publicKeyIndex); |
| 309 | String encodedExistingKey = new String(value.getEncoded()); |
| 310 | if (encodedPublicKey.equals(encodedExistingKey)) { |
| 311 | return mPublicKeys.keyAt(publicKeyIndex); |
| 312 | } |
| 313 | } |
| 314 | return PUBLIC_KEY_NOT_FOUND; |
| 315 | } |
| 316 | |
| 317 | /* |
| 318 | * Gets an unused stable identifier for a KeySet. |
| 319 | */ |
| 320 | private long getFreeKeySetIDLocked() { |
| 321 | lastIssuedKeySetId += 1; |
| 322 | return lastIssuedKeySetId; |
| 323 | } |
| 324 | |
| 325 | /* |
| 326 | * Same as above, but for public keys. |
| 327 | */ |
| 328 | private long getFreePublicKeyIdLocked() { |
| 329 | lastIssuedKeyId += 1; |
| 330 | return lastIssuedKeyId; |
| 331 | } |
| 332 | |
| 333 | public void removeAppKeySetData(String packageName) { |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 334 | synchronized (mLockObject) { |
| 335 | // Get the package's known keys and KeySets |
Geremy Condra | cdb5789 | 2013-03-26 16:22:36 -0700 | [diff] [blame] | 336 | Set<Long> deletableKeySets = getKnownKeySetsByPackageNameLocked(packageName); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 337 | Set<Long> deletableKeys = new HashSet<Long>(); |
Geremy Condra | cdb5789 | 2013-03-26 16:22:36 -0700 | [diff] [blame] | 338 | Set<Long> knownKeys = null; |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 339 | for (Long ks : deletableKeySets) { |
Geremy Condra | cdb5789 | 2013-03-26 16:22:36 -0700 | [diff] [blame] | 340 | knownKeys = mKeySetMapping.get(ks); |
| 341 | if (knownKeys != null) { |
| 342 | deletableKeys.addAll(knownKeys); |
| 343 | } |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 344 | } |
| 345 | |
| 346 | // Now remove the keys and KeySets known to any other package |
| 347 | for (String pkgName : mPackages.keySet()) { |
| 348 | if (pkgName.equals(packageName)) { |
| 349 | continue; |
| 350 | } |
Geremy Condra | cdb5789 | 2013-03-26 16:22:36 -0700 | [diff] [blame] | 351 | Set<Long> knownKeySets = getKnownKeySetsByPackageNameLocked(pkgName); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 352 | deletableKeySets.removeAll(knownKeySets); |
Geremy Condra | cdb5789 | 2013-03-26 16:22:36 -0700 | [diff] [blame] | 353 | knownKeys = new HashSet<Long>(); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 354 | for (Long ks : knownKeySets) { |
Geremy Condra | cdb5789 | 2013-03-26 16:22:36 -0700 | [diff] [blame] | 355 | knownKeys = mKeySetMapping.get(ks); |
| 356 | if (knownKeys != null) { |
| 357 | deletableKeys.removeAll(knownKeys); |
| 358 | } |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 359 | } |
| 360 | } |
| 361 | |
| 362 | // The remaining keys and KeySets are not known to any other |
| 363 | // application and so can be safely deleted. |
| 364 | for (Long ks : deletableKeySets) { |
| 365 | mKeySets.delete(ks); |
| 366 | mKeySetMapping.delete(ks); |
| 367 | } |
| 368 | for (Long keyId : deletableKeys) { |
| 369 | mPublicKeys.delete(keyId); |
| 370 | } |
Geremy Condra | cdb5789 | 2013-03-26 16:22:36 -0700 | [diff] [blame] | 371 | |
| 372 | // Now remove them from the KeySets known to each package |
| 373 | for (String pkgName : mPackages.keySet()) { |
Kenny Root | 92179bc | 2013-07-02 11:55:27 -0700 | [diff] [blame] | 374 | PackageSetting p = mPackages.get(pkgName); |
Geremy Condra | cdb5789 | 2013-03-26 16:22:36 -0700 | [diff] [blame] | 375 | for (Long ks : deletableKeySets) { |
| 376 | p.keySetData.removeSigningKeySet(ks); |
| 377 | p.keySetData.removeDefinedKeySet(ks); |
| 378 | } |
| 379 | } |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 380 | } |
| 381 | } |
| 382 | |
Geremy Condra | cdb5789 | 2013-03-26 16:22:36 -0700 | [diff] [blame] | 383 | private Set<Long> getKnownKeySetsByPackageNameLocked(String packageName) { |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 384 | PackageSetting p = mPackages.get(packageName); |
| 385 | if (p == null) { |
| 386 | throw new NullPointerException("Unknown package"); |
| 387 | } |
| 388 | if (p.keySetData == null) { |
| 389 | throw new IllegalArgumentException("Package has no keySet data"); |
| 390 | } |
| 391 | Set<Long> knownKeySets = new HashSet<Long>(); |
Geremy Condra | cdb5789 | 2013-03-26 16:22:36 -0700 | [diff] [blame] | 392 | for (long ks : p.keySetData.getSigningKeySets()) { |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 393 | knownKeySets.add(ks); |
| 394 | } |
Geremy Condra | cdb5789 | 2013-03-26 16:22:36 -0700 | [diff] [blame] | 395 | for (long ks : p.keySetData.getDefinedKeySets()) { |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 396 | knownKeySets.add(ks); |
| 397 | } |
| 398 | return knownKeySets; |
| 399 | } |
| 400 | |
| 401 | public String encodePublicKey(PublicKey k) throws IOException { |
| 402 | return new String(Base64.encode(k.getEncoded(), 0)); |
| 403 | } |
| 404 | |
Dianne Hackborn | cbfd23e | 2013-06-11 14:26:53 -0700 | [diff] [blame] | 405 | public void dump(PrintWriter pw, String packageName, |
| 406 | PackageManagerService.DumpState dumpState) { |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 407 | synchronized (mLockObject) { |
Dianne Hackborn | cbfd23e | 2013-06-11 14:26:53 -0700 | [diff] [blame] | 408 | boolean printedHeader = false; |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 409 | for (Map.Entry<String, PackageSetting> e : mPackages.entrySet()) { |
Dianne Hackborn | cbfd23e | 2013-06-11 14:26:53 -0700 | [diff] [blame] | 410 | String keySetPackage = e.getKey(); |
| 411 | if (packageName != null && !packageName.equals(keySetPackage)) { |
| 412 | continue; |
| 413 | } |
| 414 | if (!printedHeader) { |
| 415 | if (dumpState.onTitlePrinted()) |
| 416 | pw.println(); |
| 417 | pw.println("Key Set Manager:"); |
| 418 | printedHeader = true; |
| 419 | } |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 420 | PackageSetting pkg = e.getValue(); |
Dianne Hackborn | cbfd23e | 2013-06-11 14:26:53 -0700 | [diff] [blame] | 421 | pw.print(" ["); pw.print(keySetPackage); pw.println("]"); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 422 | if (pkg.keySetData != null) { |
Dianne Hackborn | cbfd23e | 2013-06-11 14:26:53 -0700 | [diff] [blame] | 423 | boolean printedLabel = false; |
Ying Wang | fb236b5 | 2013-07-08 10:53:58 -0700 | [diff] [blame] | 424 | for (Map.Entry<String, Long> entry : pkg.keySetData.getAliases().entrySet()) { |
Kenny Root | df0e6ab | 2013-07-03 13:38:31 -0700 | [diff] [blame] | 425 | if (!printedLabel) { |
| 426 | pw.print(" KeySets Aliases: "); |
| 427 | printedLabel = true; |
| 428 | } else { |
| 429 | pw.print(", "); |
| 430 | } |
| 431 | pw.print(entry.getKey()); |
| 432 | pw.print('='); |
| 433 | pw.print(Long.toString(entry.getValue())); |
| 434 | } |
| 435 | if (printedLabel) { |
| 436 | pw.println(""); |
| 437 | } |
| 438 | printedLabel = false; |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 439 | for (long keySetId : pkg.keySetData.getDefinedKeySets()) { |
Dianne Hackborn | cbfd23e | 2013-06-11 14:26:53 -0700 | [diff] [blame] | 440 | if (!printedLabel) { |
| 441 | pw.print(" Defined KeySets: "); |
| 442 | printedLabel = true; |
| 443 | } else { |
| 444 | pw.print(", "); |
| 445 | } |
| 446 | pw.print(Long.toString(keySetId)); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 447 | } |
Dianne Hackborn | cbfd23e | 2013-06-11 14:26:53 -0700 | [diff] [blame] | 448 | if (printedLabel) { |
| 449 | pw.println(""); |
| 450 | } |
| 451 | printedLabel = false; |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 452 | for (long keySetId : pkg.keySetData.getSigningKeySets()) { |
Dianne Hackborn | cbfd23e | 2013-06-11 14:26:53 -0700 | [diff] [blame] | 453 | if (!printedLabel) { |
Kenny Root | df0e6ab | 2013-07-03 13:38:31 -0700 | [diff] [blame] | 454 | pw.print(" Signing KeySets: "); |
Dianne Hackborn | cbfd23e | 2013-06-11 14:26:53 -0700 | [diff] [blame] | 455 | printedLabel = true; |
| 456 | } else { |
| 457 | pw.print(", "); |
| 458 | } |
Kenny Root | df0e6ab | 2013-07-03 13:38:31 -0700 | [diff] [blame] | 459 | pw.print(Long.toString(keySetId)); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 460 | } |
Dianne Hackborn | cbfd23e | 2013-06-11 14:26:53 -0700 | [diff] [blame] | 461 | if (printedLabel) { |
| 462 | pw.println(""); |
| 463 | } |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 464 | } |
| 465 | } |
| 466 | } |
| 467 | } |
| 468 | |
| 469 | void writeKeySetManagerLPr(XmlSerializer serializer) throws IOException { |
| 470 | serializer.startTag(null, "keyset-settings"); |
| 471 | writePublicKeysLPr(serializer); |
| 472 | writeKeySetsLPr(serializer); |
| 473 | serializer.startTag(null, "lastIssuedKeyId"); |
| 474 | serializer.attribute(null, "value", Long.toString(lastIssuedKeyId)); |
| 475 | serializer.endTag(null, "lastIssuedKeyId"); |
| 476 | serializer.startTag(null, "lastIssuedKeySetId"); |
| 477 | serializer.attribute(null, "value", Long.toString(lastIssuedKeySetId)); |
| 478 | serializer.endTag(null, "lastIssuedKeySetId"); |
| 479 | serializer.endTag(null, "keyset-settings"); |
| 480 | } |
| 481 | |
| 482 | void writePublicKeysLPr(XmlSerializer serializer) throws IOException { |
| 483 | serializer.startTag(null, "keys"); |
| 484 | for (int pKeyIndex = 0; pKeyIndex < mPublicKeys.size(); pKeyIndex++) { |
| 485 | long id = mPublicKeys.keyAt(pKeyIndex); |
| 486 | PublicKey key = mPublicKeys.valueAt(pKeyIndex); |
| 487 | String encodedKey = encodePublicKey(key); |
| 488 | serializer.startTag(null, "public-key"); |
| 489 | serializer.attribute(null, "identifier", Long.toString(id)); |
| 490 | serializer.attribute(null, "value", encodedKey); |
| 491 | serializer.endTag(null, "public-key"); |
| 492 | } |
| 493 | serializer.endTag(null, "keys"); |
| 494 | } |
| 495 | |
| 496 | void writeKeySetsLPr(XmlSerializer serializer) throws IOException { |
| 497 | serializer.startTag(null, "keysets"); |
| 498 | for (int keySetIndex = 0; keySetIndex < mKeySetMapping.size(); keySetIndex++) { |
| 499 | long id = mKeySetMapping.keyAt(keySetIndex); |
| 500 | Set<Long> keys = mKeySetMapping.valueAt(keySetIndex); |
| 501 | serializer.startTag(null, "keyset"); |
| 502 | serializer.attribute(null, "identifier", Long.toString(id)); |
| 503 | for (long keyId : keys) { |
| 504 | serializer.startTag(null, "key-id"); |
| 505 | serializer.attribute(null, "identifier", Long.toString(keyId)); |
| 506 | serializer.endTag(null, "key-id"); |
| 507 | } |
| 508 | serializer.endTag(null, "keyset"); |
| 509 | } |
| 510 | serializer.endTag(null, "keysets"); |
| 511 | } |
| 512 | |
| 513 | void readKeySetsLPw(XmlPullParser parser) |
| 514 | throws XmlPullParserException, IOException { |
| 515 | int type; |
| 516 | long currentKeySetId = 0; |
| 517 | while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { |
| 518 | if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { |
| 519 | continue; |
| 520 | } |
| 521 | final String tagName = parser.getName(); |
| 522 | if (tagName.equals("keys")) { |
| 523 | readKeysLPw(parser); |
| 524 | } else if (tagName.equals("keysets")) { |
| 525 | readKeySetListLPw(parser); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 526 | } |
| 527 | } |
| 528 | } |
| 529 | |
| 530 | void readKeysLPw(XmlPullParser parser) |
| 531 | throws XmlPullParserException, IOException { |
| 532 | int outerDepth = parser.getDepth(); |
| 533 | int type; |
| 534 | while ((type = parser.next()) != XmlPullParser.END_DOCUMENT |
| 535 | && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { |
| 536 | if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { |
| 537 | continue; |
| 538 | } |
| 539 | final String tagName = parser.getName(); |
| 540 | if (tagName.equals("public-key")) { |
| 541 | readPublicKeyLPw(parser); |
| 542 | } else if (tagName.equals("lastIssuedKeyId")) { |
| 543 | lastIssuedKeyId = Long.parseLong(parser.getAttributeValue(null, "value")); |
| 544 | } else if (tagName.equals("lastIssuedKeySetId")) { |
| 545 | lastIssuedKeySetId = Long.parseLong(parser.getAttributeValue(null, "value")); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 546 | } |
| 547 | } |
| 548 | } |
| 549 | |
| 550 | void readKeySetListLPw(XmlPullParser parser) |
| 551 | throws XmlPullParserException, IOException { |
| 552 | int outerDepth = parser.getDepth(); |
| 553 | int type; |
| 554 | long currentKeySetId = 0; |
| 555 | while ((type = parser.next()) != XmlPullParser.END_DOCUMENT |
| 556 | && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { |
| 557 | if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { |
| 558 | continue; |
| 559 | } |
| 560 | final String tagName = parser.getName(); |
| 561 | if (tagName.equals("keyset")) { |
| 562 | currentKeySetId = readIdentifierLPw(parser); |
| 563 | mKeySets.put(currentKeySetId, new KeySet(new Binder())); |
| 564 | mKeySetMapping.put(currentKeySetId, new HashSet<Long>()); |
| 565 | } else if (tagName.equals("key-id")) { |
| 566 | long id = readIdentifierLPw(parser); |
| 567 | mKeySetMapping.get(currentKeySetId).add(id); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 568 | } |
| 569 | } |
| 570 | } |
| 571 | |
| 572 | long readIdentifierLPw(XmlPullParser parser) |
| 573 | throws XmlPullParserException { |
| 574 | return Long.parseLong(parser.getAttributeValue(null, "identifier")); |
| 575 | } |
| 576 | |
| 577 | void readPublicKeyLPw(XmlPullParser parser) |
| 578 | throws XmlPullParserException { |
| 579 | String encodedID = parser.getAttributeValue(null, "identifier"); |
| 580 | long identifier = Long.parseLong(encodedID); |
| 581 | String encodedPublicKey = parser.getAttributeValue(null, "value"); |
| 582 | PublicKey pub = PackageParser.parsePublicKey(encodedPublicKey); |
Geremy Condra | a2d8eae | 2013-06-21 16:59:42 -0700 | [diff] [blame] | 583 | if (pub != null) { |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 584 | mPublicKeys.put(identifier, pub); |
| 585 | } |
| 586 | } |
Ying Wang | fb236b5 | 2013-07-08 10:53:58 -0700 | [diff] [blame] | 587 | } |