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 | |
dcashman | 5de7377 | 2014-07-12 13:04:20 -0700 | [diff] [blame^] | 19 | import android.content.pm.KeySet; |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 20 | import android.content.pm.PackageParser; |
| 21 | import android.os.Binder; |
dcashman | 55b1078 | 2014-04-09 14:20:38 -0700 | [diff] [blame] | 22 | import android.util.ArraySet; |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 23 | import android.util.Base64; |
dcashman | 55b1078 | 2014-04-09 14:20:38 -0700 | [diff] [blame] | 24 | import android.util.Slog; |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 25 | import android.util.LongSparseArray; |
| 26 | |
| 27 | import java.io.IOException; |
| 28 | import java.io.PrintWriter; |
| 29 | import java.security.PublicKey; |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 30 | import java.util.Map; |
| 31 | import java.util.Set; |
| 32 | |
| 33 | import org.xmlpull.v1.XmlPullParser; |
| 34 | import org.xmlpull.v1.XmlPullParserException; |
| 35 | import org.xmlpull.v1.XmlSerializer; |
| 36 | |
| 37 | /* |
| 38 | * Manages system-wide KeySet state. |
| 39 | */ |
dcashman | 55b1078 | 2014-04-09 14:20:38 -0700 | [diff] [blame] | 40 | public class KeySetManagerService { |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 41 | |
dcashman | 55b1078 | 2014-04-09 14:20:38 -0700 | [diff] [blame] | 42 | 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 Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 48 | |
Kenny Root | 9a995f5 | 2013-07-08 09:33:22 -0700 | [diff] [blame] | 49 | /** 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. */ |
dcashman | 55b1078 | 2014-04-09 14:20:38 -0700 | [diff] [blame] | 53 | protected static final long PUBLIC_KEY_NOT_FOUND = -1; |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 54 | |
dcashman | 5de7377 | 2014-07-12 13:04:20 -0700 | [diff] [blame^] | 55 | private final LongSparseArray<KeySet> mKeySets; |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 56 | |
| 57 | private final LongSparseArray<PublicKey> mPublicKeys; |
| 58 | |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 59 | protected final LongSparseArray<ArraySet<Long>> mKeySetMapping; |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 60 | |
| 61 | private final Map<String, PackageSetting> mPackages; |
| 62 | |
| 63 | private static long lastIssuedKeySetId = 0; |
| 64 | |
| 65 | private static long lastIssuedKeyId = 0; |
| 66 | |
dcashman | 55b1078 | 2014-04-09 14:20:38 -0700 | [diff] [blame] | 67 | public KeySetManagerService(Map<String, PackageSetting> packages) { |
dcashman | 5de7377 | 2014-07-12 13:04:20 -0700 | [diff] [blame^] | 68 | mKeySets = new LongSparseArray<KeySet>(); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 69 | mPublicKeys = new LongSparseArray<PublicKey>(); |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 70 | mKeySetMapping = new LongSparseArray<ArraySet<Long>>(); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 71 | mPackages = packages; |
| 72 | } |
| 73 | |
Kenny Root | 2042e9d | 2013-07-08 09:31:31 -0700 | [diff] [blame] | 74 | /** |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 75 | * 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 | */ |
dcashman | 5de7377 | 2014-07-12 13:04:20 -0700 | [diff] [blame^] | 85 | public boolean packageIsSignedByLPr(String packageName, KeySet ks) { |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 86 | PackageSetting pkg = mPackages.get(packageName); |
| 87 | if (pkg == null) { |
| 88 | throw new NullPointerException("Invalid package name"); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 89 | } |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 90 | 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 Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 95 | } |
| 96 | |
Kenny Root | 2042e9d | 2013-07-08 09:31:31 -0700 | [diff] [blame] | 97 | /** |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 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 | */ |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 102 | public void addDefinedKeySetToPackageLPw(String packageName, |
dcashman | 5de7377 | 2014-07-12 13:04:20 -0700 | [diff] [blame^] | 103 | Set<PublicKey> keys, String alias) { |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 104 | if ((packageName == null) || (keys == null) || (alias == null)) { |
dcashman | 55b1078 | 2014-04-09 14:20:38 -0700 | [diff] [blame] | 105 | Slog.w(TAG, "Got null argument for a defined keyset, ignoring!"); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 106 | return; |
| 107 | } |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 108 | PackageSetting pkg = mPackages.get(packageName); |
| 109 | if (pkg == null) { |
| 110 | throw new NullPointerException("Unknown package"); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 111 | } |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 112 | // Add to KeySets, then to package |
dcashman | 5de7377 | 2014-07-12 13:04:20 -0700 | [diff] [blame^] | 113 | KeySet ks = addKeySetLPw(keys); |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 114 | long id = getIdByKeySetLPr(ks); |
| 115 | pkg.keySetData.addDefinedKeySet(id, alias); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 116 | } |
| 117 | |
Kenny Root | 2042e9d | 2013-07-08 09:31:31 -0700 | [diff] [blame] | 118 | /** |
dcashman | 55b1078 | 2014-04-09 14:20:38 -0700 | [diff] [blame] | 119 | * 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 | */ |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 123 | public void addUpgradeKeySetToPackageLPw(String packageName, String alias) { |
dcashman | 55b1078 | 2014-04-09 14:20:38 -0700 | [diff] [blame] | 124 | if ((packageName == null) || (alias == null)) { |
| 125 | Slog.w(TAG, "Got null argument for a defined keyset, ignoring!"); |
| 126 | return; |
| 127 | } |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 128 | PackageSetting pkg = mPackages.get(packageName); |
| 129 | if (pkg == null) { |
| 130 | throw new NullPointerException("Unknown package"); |
dcashman | 55b1078 | 2014-04-09 14:20:38 -0700 | [diff] [blame] | 131 | } |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 132 | pkg.keySetData.addUpgradeKeySet(alias); |
dcashman | 55b1078 | 2014-04-09 14:20:38 -0700 | [diff] [blame] | 133 | } |
| 134 | |
| 135 | /** |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 136 | * Similar to the above, this informs the system that the given package |
| 137 | * was signed by the provided KeySet. |
| 138 | */ |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 139 | public void addSigningKeySetToPackageLPw(String packageName, |
dcashman | 5de7377 | 2014-07-12 13:04:20 -0700 | [diff] [blame^] | 140 | Set<PublicKey> signingKeys) { |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 141 | if ((packageName == null) || (signingKeys == null)) { |
dcashman | 55b1078 | 2014-04-09 14:20:38 -0700 | [diff] [blame] | 142 | Slog.w(TAG, "Got null argument for a signing keyset, ignoring!"); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 143 | return; |
| 144 | } |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 145 | // add the signing KeySet |
dcashman | 5de7377 | 2014-07-12 13:04:20 -0700 | [diff] [blame^] | 146 | KeySet ks = addKeySetLPw(signingKeys); |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 147 | long id = getIdByKeySetLPr(ks); |
dcashman | 5de7377 | 2014-07-12 13:04:20 -0700 | [diff] [blame^] | 148 | Set<Long> publicKeyIds = mKeySetMapping.get(id); |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 149 | if (publicKeyIds == null) { |
| 150 | throw new NullPointerException("Got invalid KeySet id"); |
| 151 | } |
dcashman | 5de7377 | 2014-07-12 13:04:20 -0700 | [diff] [blame^] | 152 | |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 153 | // 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); |
dcashman | 5de7377 | 2014-07-12 13:04:20 -0700 | [diff] [blame^] | 163 | Set<Long> definedKeys = mKeySetMapping.get(keySetID); |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 164 | if (publicKeyIds.containsAll(definedKeys)) { |
| 165 | pkg.keySetData.addSigningKeySet(keySetID); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 166 | } |
| 167 | } |
| 168 | } |
| 169 | |
Kenny Root | 2042e9d | 2013-07-08 09:31:31 -0700 | [diff] [blame] | 170 | /** |
| 171 | * Fetches the stable identifier associated with the given KeySet. Returns |
| 172 | * {@link #KEYSET_NOT_FOUND} if the KeySet... wasn't found. |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 173 | */ |
dcashman | 5de7377 | 2014-07-12 13:04:20 -0700 | [diff] [blame^] | 174 | private long getIdByKeySetLPr(KeySet ks) { |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 175 | for (int keySetIndex = 0; keySetIndex < mKeySets.size(); keySetIndex++) { |
dcashman | 5de7377 | 2014-07-12 13:04:20 -0700 | [diff] [blame^] | 176 | KeySet value = mKeySets.valueAt(keySetIndex); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 177 | if (ks.equals(value)) { |
| 178 | return mKeySets.keyAt(keySetIndex); |
| 179 | } |
| 180 | } |
| 181 | return KEYSET_NOT_FOUND; |
| 182 | } |
| 183 | |
Kenny Root | 2042e9d | 2013-07-08 09:31:31 -0700 | [diff] [blame] | 184 | /** |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 185 | * Fetches the KeySet corresponding to the given stable identifier. |
| 186 | * |
Kenny Root | 2042e9d | 2013-07-08 09:31:31 -0700 | [diff] [blame] | 187 | * Returns {@link #KEYSET_NOT_FOUND} if the identifier doesn't |
| 188 | * identify a {@link KeySet}. |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 189 | */ |
dcashman | 5de7377 | 2014-07-12 13:04:20 -0700 | [diff] [blame^] | 190 | public KeySet getKeySetByIdLPr(long id) { |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 191 | return mKeySets.get(id); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 192 | } |
| 193 | |
Kenny Root | 2042e9d | 2013-07-08 09:31:31 -0700 | [diff] [blame] | 194 | /** |
dcashman | 5de7377 | 2014-07-12 13:04:20 -0700 | [diff] [blame^] | 195 | * 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 Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 199 | */ |
dcashman | 5de7377 | 2014-07-12 13:04:20 -0700 | [diff] [blame^] | 200 | public KeySet getKeySetByAliasAndPackageNameLPr(String packageName, String alias) { |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 201 | PackageSetting p = mPackages.get(packageName); |
dcashman | 5de7377 | 2014-07-12 13:04:20 -0700 | [diff] [blame^] | 202 | if (p == null) { |
| 203 | throw new NullPointerException("Unknown package"); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 204 | } |
dcashman | 5de7377 | 2014-07-12 13:04:20 -0700 | [diff] [blame^] | 205 | if (p.keySetData == null) { |
| 206 | throw new IllegalArgumentException("Package has no keySet data"); |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 207 | } |
dcashman | 5de7377 | 2014-07-12 13:04:20 -0700 | [diff] [blame^] | 208 | long keySetId = p.keySetData.getAliases().get(alias); |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 209 | return mKeySets.get(keySetId); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 210 | } |
| 211 | |
Kenny Root | 2042e9d | 2013-07-08 09:31:31 -0700 | [diff] [blame] | 212 | /** |
dcashman | 55b1078 | 2014-04-09 14:20:38 -0700 | [diff] [blame] | 213 | * Fetches the {@link PublicKey public keys} which belong to the specified |
| 214 | * KeySet id. |
| 215 | * |
| 216 | * Returns {@code null} if the identifier doesn't |
dcashman | 5de7377 | 2014-07-12 13:04:20 -0700 | [diff] [blame^] | 217 | * identify a {@link KeySet}. |
dcashman | 55b1078 | 2014-04-09 14:20:38 -0700 | [diff] [blame] | 218 | */ |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 219 | public ArraySet<PublicKey> getPublicKeysFromKeySetLPr(long id) { |
| 220 | if(mKeySetMapping.get(id) == null) { |
| 221 | return null; |
dcashman | 55b1078 | 2014-04-09 14:20:38 -0700 | [diff] [blame] | 222 | } |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 223 | ArraySet<PublicKey> mPubKeys = new ArraySet<PublicKey>(); |
| 224 | for (long pkId : mKeySetMapping.get(id)) { |
| 225 | mPubKeys.add(mPublicKeys.get(pkId)); |
| 226 | } |
| 227 | return mPubKeys; |
dcashman | 55b1078 | 2014-04-09 14:20:38 -0700 | [diff] [blame] | 228 | } |
| 229 | |
| 230 | /** |
dcashman | 5de7377 | 2014-07-12 13:04:20 -0700 | [diff] [blame^] | 231 | * Fetches all the known {@link KeySet KeySets} that signed the given |
dcashman | 55b1078 | 2014-04-09 14:20:38 -0700 | [diff] [blame] | 232 | * package. |
| 233 | * |
| 234 | * @throws IllegalArgumentException if the package has no keyset data. |
| 235 | * @throws NullPointerException if the package is unknown. |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 236 | */ |
dcashman | 5de7377 | 2014-07-12 13:04:20 -0700 | [diff] [blame^] | 237 | public Set<KeySet> getSigningKeySetsByPackageNameLPr(String packageName) { |
| 238 | Set<KeySet> signingKeySets = new ArraySet<KeySet>(); |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 239 | PackageSetting p = mPackages.get(packageName); |
dcashman | 5de7377 | 2014-07-12 13:04:20 -0700 | [diff] [blame^] | 240 | if (p == null) { |
| 241 | throw new NullPointerException("Unknown package"); |
dcashman | 55b1078 | 2014-04-09 14:20:38 -0700 | [diff] [blame] | 242 | } |
dcashman | 5de7377 | 2014-07-12 13:04:20 -0700 | [diff] [blame^] | 243 | 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; |
dcashman | 55b1078 | 2014-04-09 14:20:38 -0700 | [diff] [blame] | 250 | } |
| 251 | |
| 252 | /** |
dcashman | 5de7377 | 2014-07-12 13:04:20 -0700 | [diff] [blame^] | 253 | * Fetches all the known {@link KeySet KeySets} that may upgrade the given |
dcashman | 55b1078 | 2014-04-09 14:20:38 -0700 | [diff] [blame] | 254 | * package. |
| 255 | * |
| 256 | * @throws IllegalArgumentException if the package has no keyset data. |
| 257 | * @throws NullPointerException if the package is unknown. |
| 258 | */ |
dcashman | 5de7377 | 2014-07-12 13:04:20 -0700 | [diff] [blame^] | 259 | public ArraySet<KeySet> getUpgradeKeySetsByPackageNameLPr(String packageName) { |
| 260 | ArraySet<KeySet> upgradeKeySets = new ArraySet<KeySet>(); |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 261 | PackageSetting p = mPackages.get(packageName); |
| 262 | if (p == null) { |
| 263 | throw new NullPointerException("Unknown package"); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 264 | } |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 265 | 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 Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 274 | } |
| 275 | |
Kenny Root | 2042e9d | 2013-07-08 09:31:31 -0700 | [diff] [blame] | 276 | /** |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 277 | * Creates a new KeySet corresponding to the given keys. |
| 278 | * |
Kenny Root | 2042e9d | 2013-07-08 09:31:31 -0700 | [diff] [blame] | 279 | * If the {@link PublicKey PublicKeys} aren't known to the system, this |
| 280 | * adds them. Otherwise, they're deduped. |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 281 | * |
| 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 | * |
dcashman | 55b1078 | 2014-04-09 14:20:38 -0700 | [diff] [blame] | 285 | * If the KeySet isn't known to the system, this adds it to all appropriate |
| 286 | * signingKeySets |
| 287 | * |
Kenny Root | 2042e9d | 2013-07-08 09:31:31 -0700 | [diff] [blame] | 288 | * Throws if the provided set is {@code null}. |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 289 | */ |
dcashman | 5de7377 | 2014-07-12 13:04:20 -0700 | [diff] [blame^] | 290 | private KeySet addKeySetLPw(Set<PublicKey> keys) { |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 291 | if (keys == null) { |
| 292 | throw new NullPointerException("Provided keys cannot be null"); |
| 293 | } |
| 294 | // add each of the keys in the provided set |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 295 | ArraySet<Long> addedKeyIds = new ArraySet<Long>(keys.size()); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 296 | for (PublicKey k : keys) { |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 297 | long id = addPublicKeyLPw(k); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 298 | addedKeyIds.add(id); |
| 299 | } |
| 300 | |
| 301 | // check to see if the resulting keyset is new |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 302 | long existingKeySetId = getIdFromKeyIdsLPr(addedKeyIds); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 303 | if (existingKeySetId != KEYSET_NOT_FOUND) { |
| 304 | return mKeySets.get(existingKeySetId); |
| 305 | } |
| 306 | |
| 307 | // create the KeySet object |
dcashman | 5de7377 | 2014-07-12 13:04:20 -0700 | [diff] [blame^] | 308 | KeySet ks = new KeySet(new Binder()); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 309 | // get the first unoccupied slot in mKeySets |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 310 | long id = getFreeKeySetIDLPw(); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 311 | // 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); |
dcashman | 55b1078 | 2014-04-09 14:20:38 -0700 | [diff] [blame] | 315 | // 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) { |
dcashman | 5de7377 | 2014-07-12 13:04:20 -0700 | [diff] [blame^] | 321 | Set<Long> pSigningKeys = mKeySetMapping.get(pProperSigning); |
dcashman | 55b1078 | 2014-04-09 14:20:38 -0700 | [diff] [blame] | 322 | if (pSigningKeys.containsAll(addedKeyIds)) { |
| 323 | p.keySetData.addSigningKeySet(id); |
| 324 | } |
| 325 | } |
| 326 | } |
| 327 | } |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 328 | // go home |
| 329 | return ks; |
| 330 | } |
| 331 | |
Kenny Root | 2042e9d | 2013-07-08 09:31:31 -0700 | [diff] [blame] | 332 | /** |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 333 | * Adds the given PublicKey to the system, deduping as it goes. |
| 334 | */ |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 335 | private long addPublicKeyLPw(PublicKey key) { |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 336 | // check if the public key is new |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 337 | long existingKeyId = getIdForPublicKeyLPr(key); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 338 | if (existingKeyId != PUBLIC_KEY_NOT_FOUND) { |
| 339 | return existingKeyId; |
| 340 | } |
| 341 | // if it's new find the first unoccupied slot in the public keys |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 342 | long id = getFreePublicKeyIdLPw(); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 343 | // add the public key to it |
| 344 | mPublicKeys.put(id, key); |
| 345 | // return the stable identifier |
| 346 | return id; |
| 347 | } |
| 348 | |
Kenny Root | 2042e9d | 2013-07-08 09:31:31 -0700 | [diff] [blame] | 349 | /** |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 350 | * 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 | */ |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 354 | private long getIdFromKeyIdsLPr(Set<Long> publicKeyIds) { |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 355 | for (int keyMapIndex = 0; keyMapIndex < mKeySetMapping.size(); keyMapIndex++) { |
dcashman | 5de7377 | 2014-07-12 13:04:20 -0700 | [diff] [blame^] | 356 | Set<Long> value = mKeySetMapping.valueAt(keyMapIndex); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 357 | if (value.equals(publicKeyIds)) { |
| 358 | return mKeySetMapping.keyAt(keyMapIndex); |
| 359 | } |
| 360 | } |
| 361 | return KEYSET_NOT_FOUND; |
| 362 | } |
| 363 | |
Kenny Root | 2042e9d | 2013-07-08 09:31:31 -0700 | [diff] [blame] | 364 | /** |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 365 | * Finds the stable identifier for a PublicKey or PUBLIC_KEY_NOT_FOUND. |
| 366 | */ |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 367 | private long getIdForPublicKeyLPr(PublicKey k) { |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 368 | 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 Root | 2042e9d | 2013-07-08 09:31:31 -0700 | [diff] [blame] | 379 | /** |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 380 | * Gets an unused stable identifier for a KeySet. |
| 381 | */ |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 382 | private long getFreeKeySetIDLPw() { |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 383 | lastIssuedKeySetId += 1; |
| 384 | return lastIssuedKeySetId; |
| 385 | } |
| 386 | |
Kenny Root | 2042e9d | 2013-07-08 09:31:31 -0700 | [diff] [blame] | 387 | /** |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 388 | * Same as above, but for public keys. |
| 389 | */ |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 390 | private long getFreePublicKeyIdLPw() { |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 391 | lastIssuedKeyId += 1; |
| 392 | return lastIssuedKeyId; |
| 393 | } |
| 394 | |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 395 | 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 Condra | cdb5789 | 2013-03-26 16:22:36 -0700 | [diff] [blame] | 416 | knownKeys = mKeySetMapping.get(ks); |
| 417 | if (knownKeys != null) { |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 418 | deletableKeys.removeAll(knownKeys); |
Geremy Condra | cdb5789 | 2013-03-26 16:22:36 -0700 | [diff] [blame] | 419 | } |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 420 | } |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 421 | } |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 422 | |
| 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 Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 443 | } |
| 444 | |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 445 | private void clearPackageKeySetDataLPw(PackageSetting p) { |
dcashman | 55b1078 | 2014-04-09 14:20:38 -0700 | [diff] [blame] | 446 | p.keySetData.removeAllSigningKeySets(); |
| 447 | p.keySetData.removeAllUpgradeKeySets(); |
| 448 | p.keySetData.removeAllDefinedKeySets(); |
| 449 | return; |
| 450 | } |
| 451 | |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 452 | private ArraySet<Long> getOriginalKeySetsByPackageNameLPr(String packageName) { |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 453 | 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 | } |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 460 | ArraySet<Long> knownKeySets = new ArraySet<Long>(); |
dcashman | 55b1078 | 2014-04-09 14:20:38 -0700 | [diff] [blame] | 461 | knownKeySets.add(p.keySetData.getProperSigningKeySet()); |
| 462 | if (p.keySetData.isUsingDefinedKeySets()) { |
| 463 | for (long ks : p.keySetData.getDefinedKeySets()) { |
| 464 | knownKeySets.add(ks); |
| 465 | } |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 466 | } |
| 467 | return knownKeySets; |
| 468 | } |
| 469 | |
| 470 | public String encodePublicKey(PublicKey k) throws IOException { |
| 471 | return new String(Base64.encode(k.getEncoded(), 0)); |
| 472 | } |
| 473 | |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 474 | 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 Hackborn | cbfd23e | 2013-06-11 14:26:53 -0700 | [diff] [blame] | 502 | } |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 503 | if (printedLabel) { |
| 504 | pw.println(""); |
Dianne Hackborn | cbfd23e | 2013-06-11 14:26:53 -0700 | [diff] [blame] | 505 | } |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 506 | printedLabel = false; |
| 507 | if (pkg.keySetData.isUsingDefinedKeySets()) { |
| 508 | for (long keySetId : pkg.keySetData.getDefinedKeySets()) { |
Kenny Root | df0e6ab | 2013-07-03 13:38:31 -0700 | [diff] [blame] | 509 | if (!printedLabel) { |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 510 | pw.print(" Defined KeySets: "); |
Dianne Hackborn | cbfd23e | 2013-06-11 14:26:53 -0700 | [diff] [blame] | 511 | printedLabel = true; |
| 512 | } else { |
| 513 | pw.print(", "); |
| 514 | } |
Kenny Root | df0e6ab | 2013-07-03 13:38:31 -0700 | [diff] [blame] | 515 | pw.print(Long.toString(keySetId)); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 516 | } |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 517 | } |
| 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 Hackborn | cbfd23e | 2013-06-11 14:26:53 -0700 | [diff] [blame] | 528 | } |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 529 | 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(", "); |
dcashman | 55b1078 | 2014-04-09 14:20:38 -0700 | [diff] [blame] | 542 | } |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 543 | pw.print(Long.toString(keySetId)); |
dcashman | 55b1078 | 2014-04-09 14:20:38 -0700 | [diff] [blame] | 544 | } |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 545 | } |
| 546 | if (printedLabel) { |
| 547 | pw.println(""); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 548 | } |
| 549 | } |
| 550 | } |
| 551 | } |
| 552 | |
dcashman | 55b1078 | 2014-04-09 14:20:38 -0700 | [diff] [blame] | 553 | void writeKeySetManagerServiceLPr(XmlSerializer serializer) throws IOException { |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 554 | serializer.startTag(null, "keyset-settings"); |
dcashman | 55b1078 | 2014-04-09 14:20:38 -0700 | [diff] [blame] | 555 | serializer.attribute(null, "version", Integer.toString(CURRENT_VERSION)); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 556 | 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); |
dcashman | 5de7377 | 2014-07-12 13:04:20 -0700 | [diff] [blame^] | 585 | Set<Long> keys = mKeySetMapping.valueAt(keySetIndex); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 586 | 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; |
dcashman | 55b1078 | 2014-04-09 14:20:38 -0700 | [diff] [blame] | 602 | 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()) { |
dcashman | d79fdf1 | 2014-06-20 15:53:06 -0700 | [diff] [blame] | 614 | clearPackageKeySetDataLPw(p); |
dcashman | 55b1078 | 2014-04-09 14:20:38 -0700 | [diff] [blame] | 615 | } |
| 616 | return; |
| 617 | } |
| 618 | while ((type = parser.next()) != XmlPullParser.END_DOCUMENT |
| 619 | && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 620 | 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); |
dcashman | 55b1078 | 2014-04-09 14:20:38 -0700 | [diff] [blame] | 628 | } 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 Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 632 | } |
| 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 Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 648 | } |
| 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); |
dcashman | 5de7377 | 2014-07-12 13:04:20 -0700 | [diff] [blame^] | 665 | mKeySets.put(currentKeySetId, new KeySet(new Binder())); |
dcashman | 55b1078 | 2014-04-09 14:20:38 -0700 | [diff] [blame] | 666 | mKeySetMapping.put(currentKeySetId, new ArraySet<Long>()); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 667 | } else if (tagName.equals("key-id")) { |
| 668 | long id = readIdentifierLPw(parser); |
| 669 | mKeySetMapping.get(currentKeySetId).add(id); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 670 | } |
| 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 Condra | a2d8eae | 2013-06-21 16:59:42 -0700 | [diff] [blame] | 685 | if (pub != null) { |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 686 | mPublicKeys.put(identifier, pub); |
| 687 | } |
| 688 | } |
Ying Wang | fb236b5 | 2013-07-08 10:53:58 -0700 | [diff] [blame] | 689 | } |