KeySetManagerService.java revision 405912bce074e9e59a246e2357a108e50dffabf8
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                for (long keySetId : pkg.keySetData.getSigningKeySets()) {
542                    if (!printedLabel) {
543                        pw.print("      Signing KeySets: ");
544                        printedLabel = true;
545                    } else {
546                        pw.print(", ");
547                    }
548                    pw.print(Long.toString(keySetId));
549                }
550                if (printedLabel) {
551                    pw.println("");
552                }
553                printedLabel = false;
554                if (pkg.keySetData.isUsingUpgradeKeySets()) {
555                    for (long keySetId : pkg.keySetData.getUpgradeKeySets()) {
556                        if (!printedLabel) {
557                            pw.print("      Upgrade KeySets: ");
558                            printedLabel = true;
559                        } else {
560                            pw.print(", ");
561                        }
562                        pw.print(Long.toString(keySetId));
563                    }
564                }
565                if (printedLabel) {
566                    pw.println("");
567                }
568            }
569        }
570    }
571
572    void writeKeySetManagerServiceLPr(XmlSerializer serializer) throws IOException {
573        serializer.startTag(null, "keyset-settings");
574        serializer.attribute(null, "version", Integer.toString(CURRENT_VERSION));
575        writePublicKeysLPr(serializer);
576        writeKeySetsLPr(serializer);
577        serializer.startTag(null, "lastIssuedKeyId");
578        serializer.attribute(null, "value", Long.toString(lastIssuedKeyId));
579        serializer.endTag(null, "lastIssuedKeyId");
580        serializer.startTag(null, "lastIssuedKeySetId");
581        serializer.attribute(null, "value", Long.toString(lastIssuedKeySetId));
582        serializer.endTag(null, "lastIssuedKeySetId");
583        serializer.endTag(null, "keyset-settings");
584    }
585
586    void writePublicKeysLPr(XmlSerializer serializer) throws IOException {
587        serializer.startTag(null, "keys");
588        for (int pKeyIndex = 0; pKeyIndex < mPublicKeys.size(); pKeyIndex++) {
589            long id = mPublicKeys.keyAt(pKeyIndex);
590            PublicKey key = mPublicKeys.valueAt(pKeyIndex);
591            String encodedKey = encodePublicKey(key);
592            serializer.startTag(null, "public-key");
593            serializer.attribute(null, "identifier", Long.toString(id));
594            serializer.attribute(null, "value", encodedKey);
595            serializer.endTag(null, "public-key");
596        }
597        serializer.endTag(null, "keys");
598    }
599
600    void writeKeySetsLPr(XmlSerializer serializer) throws IOException {
601        serializer.startTag(null, "keysets");
602        for (int keySetIndex = 0; keySetIndex < mKeySetMapping.size(); keySetIndex++) {
603            long id = mKeySetMapping.keyAt(keySetIndex);
604            ArraySet<Long> keys = mKeySetMapping.valueAt(keySetIndex);
605            serializer.startTag(null, "keyset");
606            serializer.attribute(null, "identifier", Long.toString(id));
607            for (long keyId : keys) {
608                serializer.startTag(null, "key-id");
609                serializer.attribute(null, "identifier", Long.toString(keyId));
610                serializer.endTag(null, "key-id");
611            }
612            serializer.endTag(null, "keyset");
613        }
614        serializer.endTag(null, "keysets");
615    }
616
617    void readKeySetsLPw(XmlPullParser parser)
618            throws XmlPullParserException, IOException {
619        int type;
620        long currentKeySetId = 0;
621        int outerDepth = parser.getDepth();
622        String recordedVersion = parser.getAttributeValue(null, "version");
623        if (recordedVersion == null || Integer.parseInt(recordedVersion) != CURRENT_VERSION) {
624            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
625                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
626                // Our version is different than the one which generated the old keyset data.
627                // We don't want any of the old data, but we must advance the parser
628                continue;
629            }
630            // The KeySet information read previously from packages.xml is invalid.
631            // Destroy it all.
632            for (PackageSetting p : mPackages.values()) {
633                clearPackageKeySetDataLPw(p);
634            }
635            return;
636        }
637        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
638               && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
639            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
640                continue;
641            }
642            final String tagName = parser.getName();
643            if (tagName.equals("keys")) {
644                readKeysLPw(parser);
645            } else if (tagName.equals("keysets")) {
646                readKeySetListLPw(parser);
647            } else if (tagName.equals("lastIssuedKeyId")) {
648                lastIssuedKeyId = Long.parseLong(parser.getAttributeValue(null, "value"));
649            } else if (tagName.equals("lastIssuedKeySetId")) {
650                lastIssuedKeySetId = Long.parseLong(parser.getAttributeValue(null, "value"));
651            }
652        }
653    }
654
655    void readKeysLPw(XmlPullParser parser)
656            throws XmlPullParserException, IOException {
657        int outerDepth = parser.getDepth();
658        int type;
659        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
660                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
661            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
662                continue;
663            }
664            final String tagName = parser.getName();
665            if (tagName.equals("public-key")) {
666                readPublicKeyLPw(parser);
667            }
668        }
669    }
670
671    void readKeySetListLPw(XmlPullParser parser)
672            throws XmlPullParserException, IOException {
673        int outerDepth = parser.getDepth();
674        int type;
675        long currentKeySetId = 0;
676        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
677                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
678            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
679                continue;
680            }
681            final String tagName = parser.getName();
682            if (tagName.equals("keyset")) {
683                currentKeySetId = readIdentifierLPw(parser);
684                mKeySets.put(currentKeySetId, new KeySetHandle());
685                mKeySetMapping.put(currentKeySetId, new ArraySet<Long>());
686            } else if (tagName.equals("key-id")) {
687                long id = readIdentifierLPw(parser);
688                mKeySetMapping.get(currentKeySetId).add(id);
689            }
690        }
691    }
692
693    long readIdentifierLPw(XmlPullParser parser)
694            throws XmlPullParserException {
695        return Long.parseLong(parser.getAttributeValue(null, "identifier"));
696    }
697
698    void readPublicKeyLPw(XmlPullParser parser)
699            throws XmlPullParserException {
700        String encodedID = parser.getAttributeValue(null, "identifier");
701        long identifier = Long.parseLong(encodedID);
702        String encodedPublicKey = parser.getAttributeValue(null, "value");
703        PublicKey pub = PackageParser.parsePublicKey(encodedPublicKey);
704        if (pub != null) {
705            mPublicKeys.put(identifier, pub);
706        }
707    }
708}
709