KeySetManagerService.java revision 6441bc7e5366610771b587a8cb6ff04c2861b7a5
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
17package com.android.server.pm;
18
19import android.content.pm.PackageParser;
20import android.os.Binder;
21import android.util.ArraySet;
22import android.util.Base64;
23import android.util.Slog;
24import android.util.LongSparseArray;
25
26import java.io.IOException;
27import java.io.PrintWriter;
28import java.security.PublicKey;
29import java.util.Map;
30import java.util.Set;
31
32import org.xmlpull.v1.XmlPullParser;
33import org.xmlpull.v1.XmlPullParserException;
34import org.xmlpull.v1.XmlSerializer;
35
36/*
37 * Manages system-wide KeySet state.
38 */
39public class KeySetManagerService {
40
41    static final String TAG = "KeySetManagerService";
42
43    /* original keysets implementation had no versioning info, so this is the first */
44    public static final int FIRST_VERSION = 1;
45
46    public static final int CURRENT_VERSION = FIRST_VERSION;
47
48    /** Sentinel value returned when a {@code KeySet} is not found. */
49    public static final long KEYSET_NOT_FOUND = -1;
50
51    /** Sentinel value returned when public key is not found. */
52    protected static final long PUBLIC_KEY_NOT_FOUND = -1;
53
54    private final LongSparseArray<KeySetHandle> mKeySets;
55
56    private final LongSparseArray<PublicKey> mPublicKeys;
57
58    protected final LongSparseArray<ArraySet<Long>> mKeySetMapping;
59
60    private final Map<String, PackageSetting> mPackages;
61
62    private static long lastIssuedKeySetId = 0;
63
64    private static long lastIssuedKeyId = 0;
65
66    public KeySetManagerService(Map<String, PackageSetting> packages) {
67        mKeySets = new LongSparseArray<KeySetHandle>();
68        mPublicKeys = new LongSparseArray<PublicKey>();
69        mKeySetMapping = new LongSparseArray<ArraySet<Long>>();
70        mPackages = packages;
71    }
72
73    /**
74     * Determine if a package is signed by the given KeySet.
75     *
76     * Returns false if the package was not signed by all the
77     * keys in the KeySet.
78     *
79     * Returns true if the package was signed by at least the
80     * keys in the given KeySet.
81     *
82     * Note that this can return true for multiple KeySets.
83     */
84    public boolean packageIsSignedByLPr(String packageName, KeySetHandle ks) {
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 = getIdByKeySetLPr(ks);
93        if (id == KEYSET_NOT_FOUND) {
94                return false;
95        }
96        return pkg.keySetData.packageIsSignedBy(id);
97    }
98
99    /**
100     * Determine if a package is signed by the given KeySet.
101     *
102     * Returns false if the package was not signed by all the
103     * keys in the KeySet, or if the package was signed by keys
104     * not in the KeySet.
105     *
106     * Note that this can return only for one KeySet.
107     */
108    public boolean packageIsSignedByExactlyLPr(String packageName, KeySetHandle ks) {
109        PackageSetting pkg = mPackages.get(packageName);
110        if (pkg == null) {
111            throw new NullPointerException("Invalid package name");
112        }
113        if (pkg.keySetData == null
114            || pkg.keySetData.getProperSigningKeySet()
115            == PackageKeySetData.KEYSET_UNASSIGNED) {
116            throw new NullPointerException("Package has no KeySet data");
117        }
118        long id = getIdByKeySetLPr(ks);
119        return pkg.keySetData.getProperSigningKeySet() == id;
120    }
121
122    /**
123     * This informs the system that the given package has defined a KeySet
124     * in its manifest that a) contains the given keys and b) is named
125     * alias by that package.
126     */
127    public void addDefinedKeySetToPackageLPw(String packageName,
128            ArraySet<PublicKey> keys, String alias) {
129        if ((packageName == null) || (keys == null) || (alias == null)) {
130            Slog.w(TAG, "Got null argument for a defined keyset, ignoring!");
131            return;
132        }
133        PackageSetting pkg = mPackages.get(packageName);
134        if (pkg == null) {
135            throw new NullPointerException("Unknown package");
136        }
137        // Add to KeySets, then to package
138        KeySetHandle ks = addKeySetLPw(keys);
139        long id = getIdByKeySetLPr(ks);
140        pkg.keySetData.addDefinedKeySet(id, alias);
141    }
142
143    /**
144     * This informs the system that the given package has defined a KeySet
145     * alias in its manifest to be an upgradeKeySet.  This must be called
146     * after all of the defined KeySets have been added.
147     */
148    public void addUpgradeKeySetToPackageLPw(String packageName, String alias) {
149        if ((packageName == null) || (alias == null)) {
150            Slog.w(TAG, "Got null argument for a defined keyset, ignoring!");
151            return;
152        }
153        PackageSetting pkg = mPackages.get(packageName);
154        if (pkg == null) {
155            throw new NullPointerException("Unknown package");
156        }
157        pkg.keySetData.addUpgradeKeySet(alias);
158    }
159
160    /**
161     * Similar to the above, this informs the system that the given package
162     * was signed by the provided KeySet.
163     */
164    public void addSigningKeySetToPackageLPw(String packageName,
165            ArraySet<PublicKey> signingKeys) {
166        if ((packageName == null) || (signingKeys == null)) {
167            Slog.w(TAG, "Got null argument for a signing keyset, ignoring!");
168            return;
169        }
170        // add the signing KeySet
171        KeySetHandle ks = addKeySetLPw(signingKeys);
172        long id = getIdByKeySetLPr(ks);
173        ArraySet<Long> publicKeyIds = mKeySetMapping.get(id);
174        if (publicKeyIds == null) {
175            throw new NullPointerException("Got invalid KeySet id");
176        }
177        // attach it to the package
178        PackageSetting pkg = mPackages.get(packageName);
179        if (pkg == null) {
180            throw new NullPointerException("No such package!");
181        }
182        pkg.keySetData.setProperSigningKeySet(id);
183        // for each KeySet which is a subset of the one above, add the
184        // KeySet id to the package's signing KeySets
185        for (int keySetIndex = 0; keySetIndex < mKeySets.size(); keySetIndex++) {
186            long keySetID = mKeySets.keyAt(keySetIndex);
187            ArraySet<Long> definedKeys = mKeySetMapping.get(keySetID);
188            if (publicKeyIds.containsAll(definedKeys)) {
189                pkg.keySetData.addSigningKeySet(keySetID);
190            }
191        }
192    }
193
194    /**
195     * Fetches the stable identifier associated with the given KeySet. Returns
196     * {@link #KEYSET_NOT_FOUND} if the KeySet... wasn't found.
197     */
198    private long getIdByKeySetLPr(KeySetHandle ks) {
199        for (int keySetIndex = 0; keySetIndex < mKeySets.size(); keySetIndex++) {
200            KeySetHandle value = mKeySets.valueAt(keySetIndex);
201            if (ks.equals(value)) {
202                return mKeySets.keyAt(keySetIndex);
203            }
204        }
205        return KEYSET_NOT_FOUND;
206    }
207
208    /**
209     * Fetches the KeySet corresponding to the given stable identifier.
210     *
211     * Returns {@link #KEYSET_NOT_FOUND} if the identifier doesn't
212     * identify a {@link KeySet}.
213     */
214    public KeySetHandle getKeySetByIdLPr(long id) {
215        return mKeySets.get(id);
216    }
217
218    /**
219     * Fetches the {@link KeySetHandle} that a given package refers to by the
220     * provided alias. Returns null if the package is unknown or does not have a
221     * KeySet corresponding to that alias.
222     */
223    public KeySetHandle getKeySetByAliasAndPackageNameLPr(String packageName, String alias) {
224        PackageSetting p = mPackages.get(packageName);
225        if (p == null || p.keySetData == null) {
226                return null;
227        }
228        Long keySetId = p.keySetData.getAliases().get(alias);
229        if (keySetId == null) {
230            throw new IllegalArgumentException("Unknown KeySet alias: " + alias);
231        }
232        return mKeySets.get(keySetId);
233    }
234
235    /**
236     * Fetches the {@link PublicKey public keys} which belong to the specified
237     * KeySet id.
238     *
239     * Returns {@code null} if the identifier doesn't
240     * identify a {@link KeySetHandle}.
241     */
242    public ArraySet<PublicKey> getPublicKeysFromKeySetLPr(long id) {
243        if(mKeySetMapping.get(id) == null) {
244            return null;
245        }
246        ArraySet<PublicKey> mPubKeys = new ArraySet<PublicKey>();
247        for (long pkId : mKeySetMapping.get(id)) {
248            mPubKeys.add(mPublicKeys.get(pkId));
249        }
250        return mPubKeys;
251    }
252
253    /**
254     * Fetches the proper {@link KeySetHandle KeySet} that signed the given
255     * package.
256     *
257     * @throws IllegalArgumentException if the package has no keyset data.
258     * @throws NullPointerException if the package is unknown.
259     */
260    public KeySetHandle  getSigningKeySetByPackageNameLPr(String packageName) {
261        PackageSetting p = mPackages.get(packageName);
262        if (p == null
263            || p.keySetData == null
264            || p.keySetData.getProperSigningKeySet()
265            == PackageKeySetData.KEYSET_UNASSIGNED) {
266            return null;
267        }
268        return mKeySets.get(p.keySetData.getProperSigningKeySet());
269    }
270
271    /**
272     * Fetches all the known {@link KeySetHandle KeySets} that may upgrade the given
273     * package.
274     *
275     * @throws IllegalArgumentException if the package has no keyset data.
276     * @throws NullPointerException if the package is unknown.
277     */
278    public ArraySet<KeySetHandle> getUpgradeKeySetsByPackageNameLPr(String packageName) {
279        ArraySet<KeySetHandle> upgradeKeySets = new ArraySet<KeySetHandle>();
280        PackageSetting p = mPackages.get(packageName);
281        if (p == null) {
282            throw new NullPointerException("Unknown package");
283        }
284        if (p.keySetData == null) {
285            throw new IllegalArgumentException("Package has no keySet data");
286        }
287        if (p.keySetData.isUsingUpgradeKeySets()) {
288            for (long l : p.keySetData.getUpgradeKeySets()) {
289                upgradeKeySets.add(mKeySets.get(l));
290            }
291        }
292        return upgradeKeySets;
293    }
294
295    /**
296     * Creates a new KeySet corresponding to the given keys.
297     *
298     * If the {@link PublicKey PublicKeys} aren't known to the system, this
299     * adds them. Otherwise, they're deduped.
300     *
301     * If the KeySet isn't known to the system, this adds that and creates the
302     * mapping to the PublicKeys. If it is known, then it's deduped.
303     *
304     * If the KeySet isn't known to the system, this adds it to all appropriate
305     * signingKeySets
306     *
307     * Throws if the provided set is {@code null}.
308     */
309    private KeySetHandle addKeySetLPw(ArraySet<PublicKey> keys) {
310        if (keys == null) {
311            throw new NullPointerException("Provided keys cannot be null");
312        }
313        // add each of the keys in the provided set
314        ArraySet<Long> addedKeyIds = new ArraySet<Long>(keys.size());
315        for (PublicKey k : keys) {
316            long id = addPublicKeyLPw(k);
317            addedKeyIds.add(id);
318        }
319
320        // check to see if the resulting keyset is new
321        long existingKeySetId = getIdFromKeyIdsLPr(addedKeyIds);
322        if (existingKeySetId != KEYSET_NOT_FOUND) {
323            return mKeySets.get(existingKeySetId);
324        }
325
326        // create the KeySet object
327        KeySetHandle ks = new KeySetHandle();
328        // get the first unoccupied slot in mKeySets
329        long id = getFreeKeySetIDLPw();
330        // add the KeySet object to it
331        mKeySets.put(id, ks);
332        // add the stable key ids to the mapping
333        mKeySetMapping.put(id, addedKeyIds);
334        // add this KeySet id to all packages which are signed by it
335        for (String pkgName : mPackages.keySet()) {
336            PackageSetting p = mPackages.get(pkgName);
337            if (p.keySetData != null) {
338                long pProperSigning = p.keySetData.getProperSigningKeySet();
339                if (pProperSigning != PackageKeySetData.KEYSET_UNASSIGNED) {
340                    ArraySet<Long> pSigningKeys = mKeySetMapping.get(pProperSigning);
341                    if (pSigningKeys.containsAll(addedKeyIds)) {
342                        p.keySetData.addSigningKeySet(id);
343                    }
344                }
345            }
346        }
347        // go home
348        return ks;
349    }
350
351    /**
352     * Adds the given PublicKey to the system, deduping as it goes.
353     */
354    private long addPublicKeyLPw(PublicKey key) {
355        // check if the public key is new
356        long existingKeyId = getIdForPublicKeyLPr(key);
357        if (existingKeyId != PUBLIC_KEY_NOT_FOUND) {
358            return existingKeyId;
359        }
360        // if it's new find the first unoccupied slot in the public keys
361        long id = getFreePublicKeyIdLPw();
362        // add the public key to it
363        mPublicKeys.put(id, key);
364        // return the stable identifier
365        return id;
366    }
367
368    /**
369     * Finds the stable identifier for a KeySet based on a set of PublicKey stable IDs.
370     *
371     * Returns KEYSET_NOT_FOUND if there isn't one.
372     */
373    private long getIdFromKeyIdsLPr(Set<Long> publicKeyIds) {
374        for (int keyMapIndex = 0; keyMapIndex < mKeySetMapping.size(); keyMapIndex++) {
375            ArraySet<Long> value = mKeySetMapping.valueAt(keyMapIndex);
376            if (value.equals(publicKeyIds)) {
377                return mKeySetMapping.keyAt(keyMapIndex);
378            }
379        }
380        return KEYSET_NOT_FOUND;
381    }
382
383    /**
384     * Finds the stable identifier for a PublicKey or PUBLIC_KEY_NOT_FOUND.
385     */
386    private long getIdForPublicKeyLPr(PublicKey k) {
387        String encodedPublicKey = new String(k.getEncoded());
388        for (int publicKeyIndex = 0; publicKeyIndex < mPublicKeys.size(); publicKeyIndex++) {
389            PublicKey value = mPublicKeys.valueAt(publicKeyIndex);
390            String encodedExistingKey = new String(value.getEncoded());
391            if (encodedPublicKey.equals(encodedExistingKey)) {
392                return mPublicKeys.keyAt(publicKeyIndex);
393            }
394        }
395        return PUBLIC_KEY_NOT_FOUND;
396    }
397
398    /**
399     * Gets an unused stable identifier for a KeySet.
400     */
401    private long getFreeKeySetIDLPw() {
402        lastIssuedKeySetId += 1;
403        return lastIssuedKeySetId;
404    }
405
406    /**
407     * Same as above, but for public keys.
408     */
409    private long getFreePublicKeyIdLPw() {
410        lastIssuedKeyId += 1;
411        return lastIssuedKeyId;
412    }
413
414    public void removeAppKeySetDataLPw(String packageName) {
415        // Get the package's known keys and KeySets
416        ArraySet<Long> deletableKeySets = getOriginalKeySetsByPackageNameLPr(packageName);
417        ArraySet<Long> deletableKeys = new ArraySet<Long>();
418        ArraySet<Long> knownKeys = null;
419        for (Long ks : deletableKeySets) {
420            knownKeys = mKeySetMapping.get(ks);
421            if (knownKeys != null) {
422                deletableKeys.addAll(knownKeys);
423            }
424        }
425
426        // Now remove the keys and KeySets on which any other package relies
427        for (String pkgName : mPackages.keySet()) {
428            if (pkgName.equals(packageName)) {
429                continue;
430            }
431            ArraySet<Long> knownKeySets = getOriginalKeySetsByPackageNameLPr(pkgName);
432            deletableKeySets.removeAll(knownKeySets);
433            knownKeys = new ArraySet<Long>();
434            for (Long ks : knownKeySets) {
435                knownKeys = mKeySetMapping.get(ks);
436                if (knownKeys != null) {
437                    deletableKeys.removeAll(knownKeys);
438                }
439            }
440        }
441
442        // The remaining keys and KeySets are not relied on by any other
443        // application and so can be safely deleted.
444        for (Long ks : deletableKeySets) {
445            mKeySets.delete(ks);
446            mKeySetMapping.delete(ks);
447        }
448        for (Long keyId : deletableKeys) {
449            mPublicKeys.delete(keyId);
450        }
451
452        // Now remove the deleted KeySets from each package's signingKeySets
453        for (String pkgName : mPackages.keySet()) {
454            PackageSetting p = mPackages.get(pkgName);
455            for (Long ks : deletableKeySets) {
456                p.keySetData.removeSigningKeySet(ks);
457            }
458        }
459        // Finally, remove all KeySets from the original package
460        PackageSetting p = mPackages.get(packageName);
461        clearPackageKeySetDataLPw(p);
462    }
463
464    private void clearPackageKeySetDataLPw(PackageSetting p) {
465        p.keySetData.removeAllSigningKeySets();
466        p.keySetData.removeAllUpgradeKeySets();
467        p.keySetData.removeAllDefinedKeySets();
468        return;
469    }
470
471    private ArraySet<Long> getOriginalKeySetsByPackageNameLPr(String packageName) {
472        PackageSetting p = mPackages.get(packageName);
473        if (p == null) {
474            throw new NullPointerException("Unknown package");
475        }
476        if (p.keySetData == null) {
477            throw new IllegalArgumentException("Package has no keySet data");
478        }
479        ArraySet<Long> knownKeySets = new ArraySet<Long>();
480        knownKeySets.add(p.keySetData.getProperSigningKeySet());
481        if (p.keySetData.isUsingDefinedKeySets()) {
482            for (long ks : p.keySetData.getDefinedKeySets()) {
483                knownKeySets.add(ks);
484            }
485        }
486        return knownKeySets;
487    }
488
489    public String encodePublicKey(PublicKey k) throws IOException {
490        return new String(Base64.encode(k.getEncoded(), 0));
491    }
492
493    public void dumpLPr(PrintWriter pw, String packageName,
494                        PackageManagerService.DumpState dumpState) {
495        boolean printedHeader = false;
496        for (Map.Entry<String, PackageSetting> e : mPackages.entrySet()) {
497            String keySetPackage = e.getKey();
498            if (packageName != null && !packageName.equals(keySetPackage)) {
499                continue;
500            }
501            if (!printedHeader) {
502                if (dumpState.onTitlePrinted())
503                    pw.println();
504                pw.println("Key Set Manager:");
505                printedHeader = true;
506            }
507            PackageSetting pkg = e.getValue();
508            pw.print("  ["); pw.print(keySetPackage); pw.println("]");
509            if (pkg.keySetData != null) {
510                boolean printedLabel = false;
511                for (Map.Entry<String, Long> entry : pkg.keySetData.getAliases().entrySet()) {
512                    if (!printedLabel) {
513                        pw.print("      KeySets Aliases: ");
514                        printedLabel = true;
515                    } else {
516                        pw.print(", ");
517                    }
518                    pw.print(entry.getKey());
519                    pw.print('=');
520                    pw.print(Long.toString(entry.getValue()));
521                }
522                if (printedLabel) {
523                    pw.println("");
524                }
525                printedLabel = false;
526                if (pkg.keySetData.isUsingDefinedKeySets()) {
527                    for (long keySetId : pkg.keySetData.getDefinedKeySets()) {
528                        if (!printedLabel) {
529                            pw.print("      Defined KeySets: ");
530                            printedLabel = true;
531                        } else {
532                            pw.print(", ");
533                        }
534                        pw.print(Long.toString(keySetId));
535                    }
536                }
537                if (printedLabel) {
538                    pw.println("");
539                }
540                printedLabel = false;
541                final long[] signingKeySets = pkg.keySetData.getSigningKeySets();
542                if (signingKeySets != null) {
543                    for (long keySetId : signingKeySets) {
544                        if (!printedLabel) {
545                            pw.print("      Signing KeySets: ");
546                            printedLabel = true;
547                        } else {
548                            pw.print(", ");
549                        }
550                        pw.print(Long.toString(keySetId));
551                    }
552                }
553                if (printedLabel) {
554                    pw.println("");
555                }
556                printedLabel = false;
557                if (pkg.keySetData.isUsingUpgradeKeySets()) {
558                    for (long keySetId : pkg.keySetData.getUpgradeKeySets()) {
559                        if (!printedLabel) {
560                            pw.print("      Upgrade KeySets: ");
561                            printedLabel = true;
562                        } else {
563                            pw.print(", ");
564                        }
565                        pw.print(Long.toString(keySetId));
566                    }
567                }
568                if (printedLabel) {
569                    pw.println("");
570                }
571            }
572        }
573    }
574
575    void writeKeySetManagerServiceLPr(XmlSerializer serializer) throws IOException {
576        serializer.startTag(null, "keyset-settings");
577        serializer.attribute(null, "version", Integer.toString(CURRENT_VERSION));
578        writePublicKeysLPr(serializer);
579        writeKeySetsLPr(serializer);
580        serializer.startTag(null, "lastIssuedKeyId");
581        serializer.attribute(null, "value", Long.toString(lastIssuedKeyId));
582        serializer.endTag(null, "lastIssuedKeyId");
583        serializer.startTag(null, "lastIssuedKeySetId");
584        serializer.attribute(null, "value", Long.toString(lastIssuedKeySetId));
585        serializer.endTag(null, "lastIssuedKeySetId");
586        serializer.endTag(null, "keyset-settings");
587    }
588
589    void writePublicKeysLPr(XmlSerializer serializer) throws IOException {
590        serializer.startTag(null, "keys");
591        for (int pKeyIndex = 0; pKeyIndex < mPublicKeys.size(); pKeyIndex++) {
592            long id = mPublicKeys.keyAt(pKeyIndex);
593            PublicKey key = mPublicKeys.valueAt(pKeyIndex);
594            String encodedKey = encodePublicKey(key);
595            serializer.startTag(null, "public-key");
596            serializer.attribute(null, "identifier", Long.toString(id));
597            serializer.attribute(null, "value", encodedKey);
598            serializer.endTag(null, "public-key");
599        }
600        serializer.endTag(null, "keys");
601    }
602
603    void writeKeySetsLPr(XmlSerializer serializer) throws IOException {
604        serializer.startTag(null, "keysets");
605        for (int keySetIndex = 0; keySetIndex < mKeySetMapping.size(); keySetIndex++) {
606            long id = mKeySetMapping.keyAt(keySetIndex);
607            ArraySet<Long> keys = mKeySetMapping.valueAt(keySetIndex);
608            serializer.startTag(null, "keyset");
609            serializer.attribute(null, "identifier", Long.toString(id));
610            for (long keyId : keys) {
611                serializer.startTag(null, "key-id");
612                serializer.attribute(null, "identifier", Long.toString(keyId));
613                serializer.endTag(null, "key-id");
614            }
615            serializer.endTag(null, "keyset");
616        }
617        serializer.endTag(null, "keysets");
618    }
619
620    void readKeySetsLPw(XmlPullParser parser)
621            throws XmlPullParserException, IOException {
622        int type;
623        long currentKeySetId = 0;
624        int outerDepth = parser.getDepth();
625        String recordedVersion = parser.getAttributeValue(null, "version");
626        if (recordedVersion == null || Integer.parseInt(recordedVersion) != CURRENT_VERSION) {
627            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
628                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
629                // Our version is different than the one which generated the old keyset data.
630                // We don't want any of the old data, but we must advance the parser
631                continue;
632            }
633            // The KeySet information read previously from packages.xml is invalid.
634            // Destroy it all.
635            for (PackageSetting p : mPackages.values()) {
636                clearPackageKeySetDataLPw(p);
637            }
638            return;
639        }
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("keys")) {
647                readKeysLPw(parser);
648            } else if (tagName.equals("keysets")) {
649                readKeySetListLPw(parser);
650            } else if (tagName.equals("lastIssuedKeyId")) {
651                lastIssuedKeyId = Long.parseLong(parser.getAttributeValue(null, "value"));
652            } else if (tagName.equals("lastIssuedKeySetId")) {
653                lastIssuedKeySetId = Long.parseLong(parser.getAttributeValue(null, "value"));
654            }
655        }
656    }
657
658    void readKeysLPw(XmlPullParser parser)
659            throws XmlPullParserException, IOException {
660        int outerDepth = parser.getDepth();
661        int type;
662        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
663                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
664            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
665                continue;
666            }
667            final String tagName = parser.getName();
668            if (tagName.equals("public-key")) {
669                readPublicKeyLPw(parser);
670            }
671        }
672    }
673
674    void readKeySetListLPw(XmlPullParser parser)
675            throws XmlPullParserException, IOException {
676        int outerDepth = parser.getDepth();
677        int type;
678        long currentKeySetId = 0;
679        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
680                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
681            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
682                continue;
683            }
684            final String tagName = parser.getName();
685            if (tagName.equals("keyset")) {
686                currentKeySetId = readIdentifierLPw(parser);
687                mKeySets.put(currentKeySetId, new KeySetHandle());
688                mKeySetMapping.put(currentKeySetId, new ArraySet<Long>());
689            } else if (tagName.equals("key-id")) {
690                long id = readIdentifierLPw(parser);
691                mKeySetMapping.get(currentKeySetId).add(id);
692            }
693        }
694    }
695
696    long readIdentifierLPw(XmlPullParser parser)
697            throws XmlPullParserException {
698        return Long.parseLong(parser.getAttributeValue(null, "identifier"));
699    }
700
701    void readPublicKeyLPw(XmlPullParser parser)
702            throws XmlPullParserException {
703        String encodedID = parser.getAttributeValue(null, "identifier");
704        long identifier = Long.parseLong(encodedID);
705        String encodedPublicKey = parser.getAttributeValue(null, "value");
706        PublicKey pub = PackageParser.parsePublicKey(encodedPublicKey);
707        if (pub != null) {
708            mPublicKeys.put(identifier, pub);
709        }
710    }
711}
712